Adaptation/GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita
changeset 15 307f4279f433
equal deleted inserted replaced
14:578be2adaf3e 15:307f4279f433
       
     1 <?xml version="1.0" encoding="utf-8"?>
       
     2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
       
     3 <!-- This component and the accompanying materials are made available under the terms of the License 
       
     4 "Eclipse Public License v1.0" which accompanies this distribution, 
       
     5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
       
     6 <!-- Initial Contributors:
       
     7     Nokia Corporation - initial contribution.
       
     8 Contributors: 
       
     9 -->
       
    10 <!DOCTYPE concept
       
    11   PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
       
    12 <concept id="GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2" xml:lang="en"><title>Migration
       
    13 Tutorial: Direct Memory Addressing</title><shortdesc>To handle direct memory addressing, you must to make the following
       
    14 changes to your code. </shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
       
    15 <p>If a media driver uses a data transfer mechanism like <xref href="GUID-E5576D91-BC5C-588E-BF90-5A1E3C445133.dita">DMA</xref>,
       
    16 data transfer can be faster if the media driver knows that an address passed
       
    17 in an I/O request is a physical address. This is known as direct memory addressing. </p>
       
    18 <ul>
       
    19 <li id="GUID-E2C6E9D0-0150-529C-953E-32DFDEA68E77"><p> <xref href="GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita#GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2/GUID-621EB44F-25BB-5B71-BF74-ED0304B7B591">Changes to registration</xref>  </p> </li>
       
    20 <li id="GUID-62701989-76A6-52D5-A713-226343BED4EE"><p> <xref href="GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita#GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2/GUID-49992CF9-404A-585C-8770-E9034434A344">Changes to request handling</xref>  </p> </li>
       
    21 <li id="GUID-79FF128E-98B3-5613-B02A-08A81FC5B82D"><p> <xref href="GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita#GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2/GUID-5F4A392F-0EAF-5E69-B902-D987B8FFD610">Issues about physical addresses</xref>  </p> </li>
       
    22 </ul>
       
    23 <section id="GUID-621EB44F-25BB-5B71-BF74-ED0304B7B591"><title>Changes to
       
    24 registration</title> <p>If the media driver code can handle physical addresses,
       
    25 it must tell the local media subsystem. This process is called registration.
       
    26 The media driver calls <xref href="GUID-9E60E8D9-619E-3A76-BAC8-93A60D62C7DF.dita#GUID-9E60E8D9-619E-3A76-BAC8-93A60D62C7DF/GUID-57B3380F-3CA6-3FF4-9D79-05B718E0743A"><apiname>LocDrv::RegisterDmaDevice()</apiname></xref> to register
       
    27 as part of the <xref href="GUID-A70A01D2-467E-5BA8-A01D-6182558F3F52.dita">media
       
    28 driver initialisation</xref> process. The media driver calls <codeph>RegisterDmaDevice()</codeph> after
       
    29 the media driver has <xref href="GUID-A70A01D2-467E-5BA8-A01D-6182558F3F52.dita#GUID-A70A01D2-467E-5BA8-A01D-6182558F3F52/GUID-4A8DEEAB-32C4-5431-8226-5623E2BD9098">registered
       
    30 with the local media subsystem</xref>. </p> <p>After the call to <xref href="GUID-9E60E8D9-619E-3A76-BAC8-93A60D62C7DF.dita#GUID-9E60E8D9-619E-3A76-BAC8-93A60D62C7DF/GUID-57B3380F-3CA6-3FF4-9D79-05B718E0743A"><apiname>LocDrv::RegisterDmaDevice()</apiname></xref>,
       
    31 the local media subsystem will test if the address in an I/O request is a
       
    32 physical address or a virtual address. The local media subsystem extracts
       
    33 the information that the media driver requires. The media driver gets this
       
    34 information through calls to the functions: </p> <ul>
       
    35 <li id="GUID-93AEF5CB-CB70-5369-BC33-9F2B51903FFE"><p> <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-DD6773B4-9EF5-322F-B53D-29174DF3B3BF"><apiname>TLocDrvRequest::IsPhysicalAddress()</apiname></xref>. </p> </li>
       
    36 <li id="GUID-33328F10-BE3D-5ADA-8FFE-5E19764E43F1"><p> <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-9879145B-D996-327E-87F6-3B8337A86A56"><apiname>TLocDrvRequest::GetNextPhysicalAddress()</apiname></xref>. </p> </li>
       
    37 </ul> <p>A <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita"><apiname>TLocDrvRequest</apiname></xref> object represents an I/O request
       
    38 and is passed to the media driver. </p> <p>There are three pieces of information
       
    39 that the local media subsystem needs from the media driver when the media
       
    40 driver registers: </p> <ul>
       
    41 <li id="GUID-7A889D6A-52E0-5FBB-BC2F-A1E10A0F0D4D"><p>The <i>minimum number
       
    42 of bytes</i> that the media device can transfer. For example, the architecture
       
    43 of some memory card types requires data transfer in blocks of 512 bytes. The
       
    44 local media subsystem can not support I/O requests for physical addresses
       
    45 where the length of the data is smaller than this minimum number. This limit
       
    46 prevents accidental access of the data outside the limits of the request. </p> </li>
       
    47 <li id="GUID-C778CC22-699B-5B01-B217-C6567CBE01E3"><p>The <i>maximum number
       
    48 of bytes</i> that the media driver can transfer in one burst. This value depends
       
    49 on the hardware. For eaxample,<xref href="GUID-0D2F811C-81C3-526F-8EA4-98E50261BF4B.dita">DMA
       
    50 Framework</xref> has limits that depend on the DMA controller. </p> </li>
       
    51 <li id="GUID-49B448A8-B8ED-5EF6-9AB2-BA43FD6ED34F"><p>The <i>alignment of
       
    52 memory</i> that the DMA controller requires. For example: a DMA controller
       
    53 might require 2 byte (word or 16 bit) alignment or 4 byte (double word or
       
    54 32 bit) alignment. For 2 byte alignment, specify 2; for 4 byte alignment specify
       
    55 4 etc. The local media subsystem can not support I/O requests for physical
       
    56 addresses that are not aligned according to this value. </p> </li>
       
    57 </ul> <p>You get all of this information from the documentation for the platform. </p> <p>This
       
    58 example code extends the code shown in the section <xref href="GUID-A70A01D2-467E-5BA8-A01D-6182558F3F52.dita">Media
       
    59 driver initialisation before the system is initialised</xref>. It adds a call
       
    60 to <xref href="GUID-9E60E8D9-619E-3A76-BAC8-93A60D62C7DF.dita#GUID-9E60E8D9-619E-3A76-BAC8-93A60D62C7DF/GUID-57B3380F-3CA6-3FF4-9D79-05B718E0743A"><apiname>LocDrv::RegisterDmaDevice()</apiname></xref>. This call follows registration
       
    61 of the media driver with the local media subsystem. </p> <codeblock id="GUID-A56AFE4C-729A-57DA-B232-60A29CE7F735" xml:space="preserve">DECLARE_STANDARD_EXTENSION()
       
    62     {
       
    63     TInt r=KErrNoMemory;
       
    64     DPrimaryMediaBase* pM=new DPrimaryMediaBase;
       
    65     if (pM)
       
    66         {//…Required here for Asynchronous creation (if supported)
       
    67         pM-&gt;iDfcQ = &amp;MyDfcQ;
       
    68  
       
    69         // Perform registration here
       
    70         r = LocDrv::RegisterMediaDevice(MEDIA_DEVICE_TYPE,
       
    71                                         MEDIA_DRIVECOUNT,
       
    72                                         &amp;IMediaDriveNumbers[0],
       
    73                                         pM,MEDIA_NUMMEDIA,KMediaDriveName
       
    74                                        );
       
    75         if ® != KErrNone)
       
    76             {
       
    77             return r;
       
    78             }
       
    79        
       
    80         // Register support for physical addressing.
       
    81         //
       
    82         // Note : in practice the values passed to RegisterDmaDevice() would be
       
    83         // either symbolic constants or functions that return values. If the 
       
    84         // media driver is split into platform independent and platform dependent
       
    85         // layers, and this code is in the independent layer, then you will need 
       
    86         // functions in the dependent layer to provide these values.
       
    87         r = LocDrv::RegisterDmaDevice(pM,
       
    88                                                     512,  // Block Addressing 512 Bytes
       
    89                                                     1024, // 1024 Byte address range
       
    90                                                     2 );  // 2 Byte alignment
       
    91         if ® != KErrNone)
       
    92             {
       
    93             return r;
       
    94             }
       
    95         ...
       
    96         }
       
    97     return®);
       
    98     }
       
    99       </codeblock> </section>
       
   100 <section id="GUID-49992CF9-404A-585C-8770-E9034434A344"><title> Changes to
       
   101 request handling</title> <p>To use physical addreses, you need to make changes
       
   102 to the code that deals with <codeph>ERead</codeph> and <codeph>EWrite</codeph> requests
       
   103 in your implementation of the <xref href="GUID-EBF025DB-1552-5E99-8C07-09932DB60552.dita#GUID-EBF025DB-1552-5E99-8C07-09932DB60552/GUID-EC193360-31C2-5012-8ED2-19F1C48C8FC5">DMediaDriver::Request()</xref> function. This section discusses the issues with <codeph>ERead</codeph> requests,
       
   104 but the principles apply to <codeph>EWrite</codeph> requests. </p> <p>There
       
   105 are a number of points to consider: </p> <p><b>Check if the address is physical </b> </p> <p>Call <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-DD6773B4-9EF5-322F-B53D-29174DF3B3BF"><apiname>TLocDrvRequest::IsPhysicalAddress()</apiname></xref> to
       
   106 test if the address passed is a physical address. For example, for a <codeph>ERead</codeph> request: </p> <codeblock id="GUID-90F1EE30-DAE5-5DE5-B42E-9EF48EB12509" xml:space="preserve">...
       
   107    // iReadReq points to a TLocDrvRequest object
       
   108    ...
       
   109    iMediaStartPos = iReadReq-&gt;Pos();
       
   110    iTotalLength   = I64LOW(iReadReq-&gt;Length()); 
       
   111    iDoPhysicalAddress = iReadReq-&gt;IsPhysicalAddress();
       
   112    if(iDoPhysicalAddress)
       
   113       {
       
   114       ..&lt; Physical address memory code &gt;..
       
   115       }
       
   116    else
       
   117       {
       
   118       ...&lt; Virtual address memory code &gt;...</codeblock> <p><b>Physical address code </b> </p> <p>If you want to use the physical address,
       
   119 you need to get the physical address and the length of contiguous memory at
       
   120 this location. Call <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-9879145B-D996-327E-87F6-3B8337A86A56"><apiname>TLocDrvRequest::GetNextPhysicalAddress()</apiname></xref> to
       
   121 get the physical address and the length of physically contiguous memory. The
       
   122 length of physically contiguous memory can be smaller than the length supplied
       
   123 in the read request, because physical memory can be fragmented into a number
       
   124 of small blocks. If the length is smaller than the length supplied in the
       
   125 read or write request, you call <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-9879145B-D996-327E-87F6-3B8337A86A56"><apiname>TLocDrvRequest::GetNextPhysicalAddress()</apiname></xref> again
       
   126 to get the address of the next physically contiguous block of memory. You
       
   127 repeat this operation until the read request is complete. For example, for
       
   128 a <codeph>ERead</codeph> request: </p> <codeblock id="GUID-2311A626-38BF-582F-B310-8E30D73AA1A7" xml:space="preserve">...
       
   129    // iReadReq points to a TLocDrvRequest object
       
   130    ...
       
   131    TPhysAddr physAddr; 
       
   132    TInt physLength;
       
   133    TInt err = KErrNone;                
       
   134    err = iReadReq-&gt;GetNextPhysicalAddress(physAddr, physLength);
       
   135    if(err == KErrNone)
       
   136       {                       
       
   137       if (physLength &lt; iTotalLength)
       
   138          {
       
   139          // Memory is fragmented, note remainder. You will need 
       
   140          // to use this code again using the remainder value.
       
   141          iRemaining    = iTotalLength – physLength;
       
   142          iTotalLength -= physLength;
       
   143          }
       
   144       
       
   145       // Start data transfer into the current physically
       
   146       // contiguous block of physical memory.
       
   147       DoDataTransfer(iMediaStartPos, physLength, physAddr);
       
   148       ...
       
   149       }
       
   150 </codeblock> <p>If you do not want to deal with fragmented physical memory,
       
   151 you can use your original code. </p> <p><b>Virtual to physical address translation </b> </p> <p>Your code must not
       
   152 perform a virtual to physical address translation when it deals with physical
       
   153 memory. For example: </p> <codeblock id="GUID-4377A0D5-8E41-59AF-B26E-C468ABAFCF47" xml:space="preserve">void DMMCRxDmaHelp::ChannelTransfer(const SDmaPseudoDes&amp; aDes)
       
   154       {
       
   155
       
   156       TPhysAddr dest;
       
   157 
       
   158       if (iCurrentReq-&gt;IsPhysicalAddress())
       
   159          dest = (TPhysAddr) aDes.iDest;
       
   160       else
       
   161          dest = Epoc::LinearToPhysical(aDes.iDest);
       
   162       TPlatDma::SetDMARegister(KHoDMA_CDSA(iChno), dest);
       
   163
       
   164       }</codeblock> <p><b>Eliminate inter-process copy </b> </p> <p>You must change your code to
       
   165 remove calls to <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-842F91FF-C780-3E2A-8860-8F34815452FC"><apiname>TLocDrvRequest::WriteRemote()</apiname></xref>. For <codeph>ERead</codeph> requests,
       
   166 data for transfer is already at the physical address. For example: </p> <codeblock id="GUID-1B14C66A-476C-5E3F-B0D7-502B54324D74" xml:space="preserve">if (!iCurrentReq-&gt;IsPhysicalAddress())
       
   167       {
       
   168       if( (id == DMediaPagingDevice::ERomPageInRequest)||
       
   169           (id == DMediaPagingDevice::ECodePageInRequest) )
       
   170          {
       
   171          r = iCurrentReq-&gt;WriteToPageHandler((TUint8 *)(&amp; iBufPtr [0]), len, usrOfst);
       
   172          }
       
   173       else if(id==DLocalDrive::ERead)
       
   174          {
       
   175          r = iCurrentReq-&gt;WriteRemote(&amp;iBufPtr,usrOfst);
       
   176          }
       
   177       }</codeblock> <p>The same logic applies to <codeph>EWrite</codeph> requests.
       
   178 You need to remove calls to <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-96B80631-AD1C-35E8-8613-0A630BD7D9E9"><apiname>TLocDrvRequest::ReadRemote()</apiname></xref>. </p> <p><b>Test your changes </b> </p> <p>You are recommended to run regression tests
       
   179 on your changed code to makes sure that the media driver operates correctly. </p> </section>
       
   180 <section id="GUID-5F4A392F-0EAF-5E69-B902-D987B8FFD610"><title>Issues about
       
   181 physical addresses</title> <p>If the media driver can use physical addresses,
       
   182 you need to be aware of a number of issues. </p> <p><b>The address scheme used by the hardware </b> </p> <p>All media devices
       
   183 have a minimum number of bytes that they can transfer. For example, the architecture
       
   184 of some memory card types requires data transfer in blocks of 512 bytes. To
       
   185 read one byte from this type of media device, the media driver must read a
       
   186 block of 512 bytes and extract the byte from the block. To write one byte
       
   187 to a media device, the media driver must read a block of 512 bytes, change
       
   188 the content of the byte, and write the block to the media device. </p> <p><b>Data transfer smaller than the minimum size </b> </p> <p>If the local
       
   189 media subsystem receives a request to transfer data with a length smaller
       
   190 than the minimum transfer size, the local media subsystem does not make a
       
   191 physical address available to the media driver. A call to <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-DD6773B4-9EF5-322F-B53D-29174DF3B3BF"><apiname>TLocDrvRequest::IsPhysicalAddress()</apiname></xref> returns
       
   192 false. It is considered unsafe to give access to the physical data surrounding
       
   193 the requested memory location. </p> <p><b>Data transfer not aligned to the media device block boundary </b> </p> <p>If
       
   194 the local media subsystem receives a request to transfer data, and the address
       
   195 on the media device is <i>not aligned</i> to the media device block boundary,
       
   196 you need to adopt the technique suggested below. The local media subsystem
       
   197 will make the physical address available to the media driver. A call to <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-DD6773B4-9EF5-322F-B53D-29174DF3B3BF"><apiname>TLocDrvRequest::IsPhysicalAddress()</apiname></xref> returns
       
   198 true. </p> <p>Consider the following case. A request has been made to read
       
   199 1024 bytes from a media device that has a block size of 512 bytes. The 1024
       
   200 bytes start at offset +256 on the media device. </p> <fig id="GUID-2689C022-180B-51EF-A02D-E63ACA832EB2">
       
   201 <image href="GUID-647ADEDA-AB5A-548F-93C3-D099EAE6A030_d0e17089_href.png" placement="inline"/>
       
   202 </fig> <p>To get the first 256 bytes, you must read the first block of 512
       
   203 bytes from the media device. This can corrupt the physical memory passed in
       
   204 the I/O request. The solution is to read the first block from the media device
       
   205 into an intermediate buffer. Copy the 256 bytes from that buffer into the
       
   206 physical memory passed in the I/O request. </p> <p>To get the last 256 bytes,
       
   207 you must read the third block of 512 bytes from the media device into the
       
   208 intermediate buffer. Copy the 256 bytes from that buffer into the correct
       
   209 position in the physical memory passed in the I/O request. </p> <p>The middle
       
   210 512 bytes are aligned on the media device block boundary. The media driver
       
   211 can read this data into the correct position in the physical memory passed
       
   212 in the I/O request. </p> <p><b>Scatter/Gather DMA controllers </b> </p> <p>DMA controllers can support
       
   213 the Scatter/Gather mode of operation. Each request in this mode of operation
       
   214 consists of a set of smaller requests chained together. This chain of requests
       
   215 is called the Scatter/Gather list. Each item in the list consists of a physical
       
   216 address and a length. </p> <p>Use <xref href="GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C.dita#GUID-D84A9903-AE0F-3F54-8833-E8956A88E26C/GUID-9879145B-D996-327E-87F6-3B8337A86A56"><apiname>TLocDrvRequest::GetNextPhysicalAddress()</apiname></xref> to
       
   217 help you populate the Scatter/Gather list. </p> <p>The following code fragment
       
   218 shows how you do this. The example assumes that the DMA controller supports
       
   219 a Scatter/Gather list with an unlimited number of entries. In practice, the
       
   220 number of entries in the list is finite. </p> <codeblock id="GUID-EC3A441C-080F-5EB8-B0E8-E658F80687D4" xml:space="preserve">TPhysAddr physAddr; 
       
   221    TInt physLength;
       
   222    TInt err = KErrNone;
       
   223 
       
   224    while (iRemaining &gt; 0)
       
   225       {
       
   226       err = iCurrentReq-&gt;GetNextPhysicalAddress(physAddr, physLength);
       
   227       if(err != KErrNone)
       
   228          return err;
       
   229 
       
   230       iRemaining -= physLength;
       
   231       PopulateScatterGatherList(physAddr, physLength);
       
   232       }                            
       
   233 
       
   234    return DoDataTransfer(pos, length);</codeblock> </section>
       
   235 </conbody><related-links>
       
   236 <link href="GUID-86082C0C-B0EE-5E7C-85B4-4A509066012F.dita"><linktext>MMC Porting
       
   237 Implementation Tutorial</linktext></link>
       
   238 </related-links></concept>