diff -r ebc84c812384 -r 46218c8b8afa Symbian3/PDK/Source/GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita --- a/Symbian3/PDK/Source/GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita Thu Mar 11 15:24:26 2010 +0000 +++ b/Symbian3/PDK/Source/GUID-2380FDDE-5489-5B1C-87BB-1FD882E385D2.dita Thu Mar 11 18:02:22 2010 +0000 @@ -1,240 +1,240 @@ - - - - - -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);
-
- -Register -media driver support for physical addresses - + + + + + +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

  • +
  • Changes to request handling

  • +
  • Issues about physical addresses

  • +
+
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);
+
+ +Register +media driver support for physical addresses +
\ No newline at end of file