diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,238 @@ + + + + + +Migration +Tutorial: Direct Memory AddressingTo handle direct memory addressing, you must to make the following +changes to your code. +

If a media driver uses a data transfer mechanism like DMA, +data transfer can be faster if the media driver knows that an address passed +in an I/O request is a physical address. This is known as direct memory addressing.

+ +
Changes to +registration

If the media driver code can handle physical addresses, +it must tell the local media subsystem. This process is called registration. +The media driver calls LocDrv::RegisterDmaDevice() to register +as part of the media +driver initialisation process. The media driver calls RegisterDmaDevice() after +the media driver has registered +with the local media subsystem.

After the call to LocDrv::RegisterDmaDevice(), +the local media subsystem will test if the address in an I/O request is a +physical address or a virtual address. The local media subsystem extracts +the information that the media driver requires. The media driver gets this +information through calls to the functions:

    +
  • TLocDrvRequest::IsPhysicalAddress().

  • +
  • TLocDrvRequest::GetNextPhysicalAddress().

  • +

A TLocDrvRequest object represents an I/O request +and is passed to the media driver.

There are three pieces of information +that the local media subsystem needs from the media driver when the media +driver registers:

    +
  • The minimum number +of bytes that the media device can transfer. For example, the architecture +of some memory card types requires data transfer in blocks of 512 bytes. The +local media subsystem can not support I/O requests for physical addresses +where the length of the data is smaller than this minimum number. This limit +prevents accidental access of the data outside the limits of the request.

  • +
  • The maximum number +of bytes that the media driver can transfer in one burst. This value depends +on the hardware. For eaxample,DMA +Framework has limits that depend on the DMA controller.

  • +
  • The alignment of +memory that the DMA controller requires. For example: a DMA controller +might require 2 byte (word or 16 bit) alignment or 4 byte (double word or +32 bit) alignment. For 2 byte alignment, specify 2; for 4 byte alignment specify +4 etc. The local media subsystem can not support I/O requests for physical +addresses that are not aligned according to this value.

  • +

You get all of this information from the documentation for the platform.

This +example code extends the code shown in the section Media +driver initialisation before the system is initialised. It adds a call +to LocDrv::RegisterDmaDevice(). This call follows registration +of the media driver with the local media subsystem.

DECLARE_STANDARD_EXTENSION() + { + TInt r=KErrNoMemory; + DPrimaryMediaBase* pM=new DPrimaryMediaBase; + if (pM) + {//…Required here for Asynchronous creation (if supported) + pM->iDfcQ = &MyDfcQ; + + // Perform registration here + r = LocDrv::RegisterMediaDevice(MEDIA_DEVICE_TYPE, + MEDIA_DRIVECOUNT, + &IMediaDriveNumbers[0], + pM,MEDIA_NUMMEDIA,KMediaDriveName + ); + if ® != KErrNone) + { + return r; + } + + // Register support for physical addressing. + // + // Note : in practice the values passed to RegisterDmaDevice() would be + // either symbolic constants or functions that return values. If the + // media driver is split into platform independent and platform dependent + // layers, and this code is in the independent layer, then you will need + // functions in the dependent layer to provide these values. + r = LocDrv::RegisterDmaDevice(pM, + 512, // Block Addressing 512 Bytes + 1024, // 1024 Byte address range + 2 ); // 2 Byte alignment + if ® != KErrNone) + { + return r; + } + ... + } + return®); + } +
+
Changes to +request handling

To use physical addreses, you need to make changes +to the code that deals with ERead and EWrite requests +in your implementation of the DMediaDriver::Request() function. This section discusses the issues with ERead requests, +but the principles apply to EWrite requests.

There +are a number of points to consider:

Check if the address is physical

Call TLocDrvRequest::IsPhysicalAddress() to +test if the address passed is a physical address. For example, for a ERead request:

... + // iReadReq points to a TLocDrvRequest object + ... + iMediaStartPos = iReadReq->Pos(); + iTotalLength = I64LOW(iReadReq->Length()); + iDoPhysicalAddress = iReadReq->IsPhysicalAddress(); + if(iDoPhysicalAddress) + { + ..< Physical address memory code >.. + } + else + { + ...< Virtual address memory code >...

Physical address code

If you want to use the physical address, +you need to get the physical address and the length of contiguous memory at +this location. Call TLocDrvRequest::GetNextPhysicalAddress() to +get the physical address and the length of physically contiguous memory. The +length of physically contiguous memory can be smaller than the length supplied +in the read request, because physical memory can be fragmented into a number +of small blocks. If the length is smaller than the length supplied in the +read or write request, you call TLocDrvRequest::GetNextPhysicalAddress() again +to get the address of the next physically contiguous block of memory. You +repeat this operation until the read request is complete. For example, for +a ERead request:

... + // iReadReq points to a TLocDrvRequest object + ... + TPhysAddr physAddr; + TInt physLength; + TInt err = KErrNone; + err = iReadReq->GetNextPhysicalAddress(physAddr, physLength); + if(err == KErrNone) + { + if (physLength < iTotalLength) + { + // Memory is fragmented, note remainder. You will need + // to use this code again using the remainder value. + iRemaining = iTotalLength – physLength; + iTotalLength -= physLength; + } + + // Start data transfer into the current physically + // contiguous block of physical memory. + DoDataTransfer(iMediaStartPos, physLength, physAddr); + ... + } +

If you do not want to deal with fragmented physical memory, +you can use your original code.

Virtual to physical address translation

Your code must not +perform a virtual to physical address translation when it deals with physical +memory. For example:

void DMMCRxDmaHelp::ChannelTransfer(const SDmaPseudoDes& aDes) + { + … + TPhysAddr dest; + + if (iCurrentReq->IsPhysicalAddress()) + dest = (TPhysAddr) aDes.iDest; + else + dest = Epoc::LinearToPhysical(aDes.iDest); + TPlatDma::SetDMARegister(KHoDMA_CDSA(iChno), dest); + … + }

Eliminate inter-process copy

You must change your code to +remove calls to TLocDrvRequest::WriteRemote(). For ERead requests, +data for transfer is already at the physical address. For example:

if (!iCurrentReq->IsPhysicalAddress()) + { + if( (id == DMediaPagingDevice::ERomPageInRequest)|| + (id == DMediaPagingDevice::ECodePageInRequest) ) + { + r = iCurrentReq->WriteToPageHandler((TUint8 *)(& iBufPtr [0]), len, usrOfst); + } + else if(id==DLocalDrive::ERead) + { + r = iCurrentReq->WriteRemote(&iBufPtr,usrOfst); + } + }

The same logic applies to EWrite requests. +You need to remove calls to TLocDrvRequest::ReadRemote().

Test your changes

You are recommended to run regression tests +on your changed code to makes sure that the media driver operates correctly.

+
Issues about +physical addresses

If the media driver can use physical addresses, +you need to be aware of a number of issues.

The address scheme used by the hardware

All media devices +have a minimum number of bytes that they can transfer. For example, the architecture +of some memory card types requires data transfer in blocks of 512 bytes. To +read one byte from this type of media device, the media driver must read a +block of 512 bytes and extract the byte from the block. To write one byte +to a media device, the media driver must read a block of 512 bytes, change +the content of the byte, and write the block to the media device.

Data transfer smaller than the minimum size

If the local +media subsystem receives a request to transfer data with a length smaller +than the minimum transfer size, the local media subsystem does not make a +physical address available to the media driver. A call to TLocDrvRequest::IsPhysicalAddress() returns +false. It is considered unsafe to give access to the physical data surrounding +the requested memory location.

Data transfer not aligned to the media device block boundary

If +the local media subsystem receives a request to transfer data, and the address +on the media device is not aligned to the media device block boundary, +you need to adopt the technique suggested below. The local media subsystem +will make the physical address available to the media driver. A call to TLocDrvRequest::IsPhysicalAddress() returns +true.

Consider the following case. A request has been made to read +1024 bytes from a media device that has a block size of 512 bytes. The 1024 +bytes start at offset +256 on the media device.

+ +

To get the first 256 bytes, you must read the first block of 512 +bytes from the media device. This can corrupt the physical memory passed in +the I/O request. The solution is to read the first block from the media device +into an intermediate buffer. Copy the 256 bytes from that buffer into the +physical memory passed in the I/O request.

To get the last 256 bytes, +you must read the third block of 512 bytes from the media device into the +intermediate buffer. Copy the 256 bytes from that buffer into the correct +position in the physical memory passed in the I/O request.

The middle +512 bytes are aligned on the media device block boundary. The media driver +can read this data into the correct position in the physical memory passed +in the I/O request.

Scatter/Gather DMA controllers

DMA controllers can support +the Scatter/Gather mode of operation. Each request in this mode of operation +consists of a set of smaller requests chained together. This chain of requests +is called the Scatter/Gather list. Each item in the list consists of a physical +address and a length.

Use TLocDrvRequest::GetNextPhysicalAddress() to +help you populate the Scatter/Gather list.

The following code fragment +shows how you do this. The example assumes that the DMA controller supports +a Scatter/Gather list with an unlimited number of entries. In practice, the +number of entries in the list is finite.

TPhysAddr physAddr; + TInt physLength; + TInt err = KErrNone; + + while (iRemaining > 0) + { + err = iCurrentReq->GetNextPhysicalAddress(physAddr, physLength); + if(err != KErrNone) + return err; + + iRemaining -= physLength; + PopulateScatterGatherList(physAddr, physLength); + } + + return DoDataTransfer(pos, length);
+
+MMC Porting +Implementation Tutorial +
\ No newline at end of file