In common buffer slave DMA, the device transfers data to or from a contiguous buffer in nonpaged pool, using a system DMA channel. Although originally intended for devices that use the system DMA controller's autoinitialize mode, common buffers can also improve throughput for some types of ISA-based slave devices. Allocating a Common BufferMemory for a common buffer must be physically contiguous and visible in the DMA logical space of a specific device. To guarantee that both these conditions are met, the function AllocateCommonBuffer, a method of the Adapter object, is used. It is described in Table 12.8. The CacheEnabled argument for this function is normally set to FALSE. Using noncached memory for the common buffer eliminates the need to call KeFlushIoBuffers. On some platforms, this can significantly improve the performance of both the driver and the system.
Besides allocating the common buffer, AllocateCommonBuffer also allocates map registers (if required) and sets up a translation for the device, loading map registers as necessary. Thus, the buffer is available for immediate and continuous use. The buffer remains usable until FreeCommonBuffer is explicitly invoked, typically in the handler routine for IRP_MN_ STOP_DEVICE. Using Common Buffer Slave DMA to Maintain ThroughputCommon buffer slave DMA is useful if the driver can't afford to set up mapping registers for each data transfer that it performs. The overhead of setting up mapping registers using MapTransfer can be significant, especially for ISA buses. There is always the possibility that MapTransfer will be forced to copy the transfer buffer into the lowest 16 MB of RAM clearly an expensive proposition. Since common buffers are guaranteed to be accessible by their associated DMA devices, there is never a need to move data from one place to another. For example, drivers of some ISA-based tape drives need to maintain very high throughput if they want to keep the tape streaming. They may not be able to do this if the buffer copy must occur during a call to MapTransfer. To prevent this, the driver can use a ring of common buffers for the actual DMA operation. Other, less time-critical portions of the driver move data between these common buffers and the actual user buffers. Consider the operation of the driver for a hypothetical ISA output device. To maintain a high DMA data rate, it uses a series of common buffers that are shared between the driver's Dispatch and DpcForIsr routines. The Dispatch routine copies user-output data into an available common buffer and attaches the buffer to a queue of pending DMA requests. Once a DMA is in progress, the DpcForIsr removes buffers from the queue and processes them as fast as it can. Figure 12.6 shows the organization of this driver, and the various driver routines are described in the sections that follow. Figure 12.6. Using common buffers to improve I/O throughput.AddDevice ROUTINEBesides creating the device object, this routine should set the DO_ BUFFERED_IO bit in the Flags field. Even though DMA is used for the actual device transfer, the user buffers are initially copied into system space. IRP_MN_START_DEVICE HANDLERBesides the usual responsibilities of initializing the physical device, the handler must now perform the following:
DISPATCH ROUTINEThe Dispatch routine of this driver is somewhat uncommon. The Dispatch routine is responsible for queuing and starting each request. This is what the Dispatch routine does to process an output request:
At this point, the work request for this buffer has been either started or queued. The next phase of the transfer occurs within the Start I/O routine. START I/O ROUTINEIf the device is idle, the Start I/O function is called to start it. It performs the following tasks:
INTERRUPT SERVICE ROUTINEAs with packet-based DMA, the ISR in a common buffer driver for a slave device merely saves hardware status in the Device Extension. It then calls IoRequestDpc to request the DpcForIsr routine. DpcForIsr ROUTINEIn this driver, the DpcForIsr routine sets up each additional work request after the first.
Each completed DMA operation causes another interrupt that brings the driver back through the DpcForIsr routine. This loop continues until all the requests in the work queue have been processed. IRP_MN_STOP_DEVICE HANDLERWhen the device is stopped, the driver should ensure that the device will no longer attempt use of the common buffer. Once the device is quiescent, the Stophandler calls FreeCommonBuffer to release the memory associated with the ring of buffers.
|