From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/halalpha/ebsgdma.c | 2307 ++++++++++++++++++++++++++++++++ 1 file changed, 2307 insertions(+) create mode 100644 private/ntos/nthals/halalpha/ebsgdma.c (limited to 'private/ntos/nthals/halalpha/ebsgdma.c') diff --git a/private/ntos/nthals/halalpha/ebsgdma.c b/private/ntos/nthals/halalpha/ebsgdma.c new file mode 100644 index 000000000..e50fe05bb --- /dev/null +++ b/private/ntos/nthals/halalpha/ebsgdma.c @@ -0,0 +1,2307 @@ +/*++ + +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + ebsgdma.c + +Abstract: + + This module contains the hardware dependent routines to support + Io Adapters, Map Registers, and Common buffers for Scatter/Gather + Eisa/Isa bus Alpha AXP systems. The systems supported must include + support for 2 scatter/gather windows. Originally, this module will + support APECS- and LCA-based systems. + +Author: + + Joe Notarangelo 11-Oct-1993 + +Environment: + + Kernel mode + +Revision History: + + Dick Bissen (DEC) 01-Nov-1993 + Forced scatter/gather tables to be aligned with table size + + Joe Notarangelo 24-Nov-1993 + Do not program DMA controllers for ISA masters in IoMapTransfer and + IoFlushAdapterBuffers. Previous code did so if the device was an + Isa device without regard to whether or not it was a master device. + + Joe Notarangelo 02-Feb-1994 + Various bug fixes. Don't adjust mapRegister in IoMapTransfer and + IoFlushAdapterBuffers. Fix alignment adjustment code for Isa + machines. Initialize map registers to zero. Initialize bitmap + for map allocations by calling RtlClearAllBits. Add debugging + prints to fit new module haldebug.c + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + + +// +// There are 2 map register adapters that are created to control access +// to each of the 2 mapping windows that exist for APECS and LCA. +// +// The first adapter (IsaMapAdapter) controls access to the first mapping +// windows which maps 8MB : 16MB-1 in bus space. The window is chosen +// to be as large as possible and must be below 16MB to support ISA +// bus masters and the standard EISA/ISA dma controllers. +// +// The second adapter (MasterMapAdapter) controls access to the second +// mapping windows which maps a large region in bus space that may +// begin above 16MB. This window is used for bus masters that are not +// constrained by the ISA 24-bit limit. +// + +PMAP_REGISTER_ADAPTER HalpIsaMapAdapter = NULL; +PMAP_REGISTER_ADAPTER HalpMasterMapAdapter = NULL; + +// +// Pointer to superpage address memory for map registers. +// + +PTRANSLATION_ENTRY HalpIsaMapRegisterBase = NULL; +PTRANSLATION_ENTRY HalpMasterMapRegisterBase = NULL; + +// +// Control structures for each of the map register windows. +// + +WINDOW_CONTROL_REGISTERS HalpIsaWindowControl; +WINDOW_CONTROL_REGISTERS HalpMasterWindowControl; + + + +// +// Local function prototypes. +// + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ); + +PMAP_REGISTER_ADAPTER +HalpAllocateMapAdapter( + IN PWINDOW_CONTROL_REGISTERS WindowRegisters, + IN HAL_ADAPTER_TYPE AdapterType, + IN PTRANSLATION_ENTRY MapRegisterBase + ); + +PADAPTER_OBJECT +HalpAllocateAdapter( + VOID + ); + +BOOLEAN +HalpAllocateMapRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG NumberOfMapRegisters, + IN BOOLEAN MapAdapterLocked + ); + +BOOLEAN +HalpCreateDmaStructures ( + PLOADER_PARAMETER_BLOCK LoaderBlock + ) + +/*++ + +Routine Description: + + This routine initializes the structures necessary for DMA operations. + Specifically, this routine allocates the physical pages to be used + to contain the scatter/gather entries for all DMA. + +Arguments: + + None. + +Return Value: + + TRUE is returned. + +--*/ + +{ + ULONG Allocated; + ULONG ByteSize; + ULONG MaxPhysicalAddress; + + // + // Initialize the window control structures for each of the 2 + // DMA windows. + // + + INITIALIZE_ISA_DMA_CONTROL( &HalpIsaWindowControl ); + INITIALIZE_MASTER_DMA_CONTROL( &HalpMasterWindowControl ); + + // + // Insure that the maximum address allocated will guarantee that the + // entirety of each allocation can be accessed via the 32-bit superpage. + // + + MaxPhysicalAddress = __1GB - 1; + + // + // Allocate the pages to contain the scatter/gather entries for the + // ISA DMA region (logical address range 8MB: 16MB-1). + // + + ByteSize = ((HalpIsaWindowControl.WindowSize / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY)) + PAGE_SIZE-1; + + // + // Memory allocation for the Isa scatter/gather table will always + // align on a 8K boundry. + // + + Allocated = HalpAllocPhysicalMemory( LoaderBlock, + MaxPhysicalAddress, + ByteSize >> PAGE_SHIFT, + FALSE ); + + ASSERT( Allocated != 0 ); + + HalpIsaMapRegisterBase = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE); + + RtlZeroMemory( HalpIsaMapRegisterBase, + (ByteSize >> PAGE_SHIFT) << PAGE_SHIFT ); + + // + // Allocate the pages to contain the scatter/gather entries for the + // bus master DMA region. Allocation of scatter/gather tables MUST + // be aligned based on the size of the scatter/gather table (16k). + // + + ByteSize = ((HalpMasterWindowControl.WindowSize / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY)) + PAGE_SIZE-1; + + // + // Allocated on an aligned 64k boundry will ensure table alignment + // on a 16K boundry for a 16MB window size. + // + + Allocated = HalpAllocPhysicalMemory( LoaderBlock, + MaxPhysicalAddress, + ByteSize >> PAGE_SHIFT, + TRUE ); + + ASSERT( Allocated != 0 ); + + HalpMasterMapRegisterBase = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE); + + RtlZeroMemory( HalpMasterMapRegisterBase, + (ByteSize >> PAGE_SHIFT) << PAGE_SHIFT ); + + // + // Perform any Eisa/Isa initialization. + // + + HalpEisaInitializeDma(); + + // + // Program the DMA windows to reflect the translations. + // + + INITIALIZE_DMA_WINDOW( &HalpMasterWindowControl, + (PVOID)( (ULONG)HalpMasterMapRegisterBase & + ~KSEG0_BASE ) ); + + INITIALIZE_DMA_WINDOW( &HalpIsaWindowControl, + (PVOID)( (ULONG)HalpIsaMapRegisterBase & + ~KSEG0_BASE ) ); + + return TRUE; +} + +PADAPTER_OBJECT +HalGetAdapter( + IN PDEVICE_DESCRIPTION DeviceDescription, + IN OUT PULONG NumberOfMapRegisters + ) + +/*++ + +Routine Description: + + This function returns the appropriate adapter object for the device defined + in the device description structure. Eisa/Isa bus types and all master + devices are supported for the system. + +Arguments: + + DeviceDescription - Supplies a description of the deivce. + + NumberOfMapRegisters - Returns the maximum number of map registers which + may be allocated by the device driver. + +Return Value: + + A pointer to the requested adapter object or NULL if an adapter could not + be created. + +--*/ + +{ + ULONG MaximumMapRegistersPerChannel; + PADAPTER_OBJECT adapterObject; + PBUS_HANDLER BusHandler; + PPCIPBUSDATA PciBusData; + + // + // Make sure this is the correct version. + // + + if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION1) { + + return(NULL); + + } + + // + // If the device is not a bus master, then it must be an ISA, EISA + // or PCI device on hardware bus 0. PCI devices on hardware busses + // other than 0 cannot support slave DMA devices because the DMAC + // needed to support slave DMA is part of the ISA/EISA bridge, (which + // is located on h/w bus 0). + // + + if( DeviceDescription->Master != TRUE ){ + + // + // This device requires slave DMA h/w support. Determine which + // type of device it is. + // + + switch( DeviceDescription->InterfaceType ){ + + case Isa: + case Eisa: + + // + // The ISA/EISA bridge implements the DMA controller logic + // needed to support slave DMA. + // + + break; + + case PCIBus: + + // + // Get the bus handler for the PCI bus. + // + + BusHandler = HaliHandlerForBus( + PCIBus, + DeviceDescription->BusNumber + ); + + // + // If a bus handler does not exist, then there is a s/w bug + // somewhere. Just return failure. + // + + if( BusHandler == NULL ){ + + return NULL; + + } + + // + // Get a pointer to the PCI private bus data for this bus. + // The h/w bus number is located therein. + // + + PciBusData = (PPCIPBUSDATA)BusHandler->BusData; + + // + // The DMA controller we use to support slave DMA is located + // on the ISA/EISA bridge in h/w bus 0. If this PCI bus is + // not located on h/w bus 0, return failure. + // + + if( PciBusData->HwBusNumber != 0 ){ + + return NULL; + + } + + break; + + default: + + // + // We only support ISA, EISA and PCI slave DMA. + // + + return NULL; + + } + + } + + // + // Create an EISA adapter if this device is an ISA device + // or is not a master device. + // + + if( (DeviceDescription->Master != TRUE) || + (DeviceDescription->InterfaceType == Isa ) ){ + + // + // Allocate the Isa Map Register Adapter if it has not + // already been allocated. + // + + if( HalpIsaMapAdapter == NULL ){ + HalpIsaMapAdapter = HalpAllocateMapAdapter( + &HalpIsaWindowControl, + IsaAdapter, + HalpIsaMapRegisterBase ); + if( HalpIsaMapAdapter == NULL ){ + return NULL; + } + } + + adapterObject = HalpAllocateEisaAdapter( + DeviceDescription, + NumberOfMapRegisters ); + + if( adapterObject == NULL ){ + return NULL; + } + + adapterObject->Type = IsaAdapter; + adapterObject->MapAdapter = HalpIsaMapAdapter; + adapterObject->MapRegisterBase = NULL; + adapterObject->NumberOfMapRegisters = 0; + + } else { + + // + // Allocate the master map register adapter if it has not + // already been allocated. + // + + if( HalpMasterMapAdapter == NULL ){ + HalpMasterMapAdapter = HalpAllocateMapAdapter( + &HalpMasterWindowControl, + BusMasterAdapter, + HalpMasterMapRegisterBase ); + if( HalpMasterMapAdapter == NULL ){ + return NULL; + } + } + + // + // Allocate an adapter for this master device. + // + + adapterObject = HalpAllocateAdapter(); + + if( adapterObject == NULL ){ + return NULL; + } + + // + // Initialize the adapter object. + // + + adapterObject->Type = BusMasterAdapter; + adapterObject->MasterDevice = TRUE; + adapterObject->MapAdapter = HalpMasterMapAdapter; + adapterObject->MapRegisterBase = NULL; + adapterObject->NumberOfMapRegisters = 0; + + // + // Calculate maximum number of map registers for this adapter. + // + + if (NumberOfMapRegisters != NULL) { + + // + // Return number of map registers requested based on the maximum + // transfer length. + // + + *NumberOfMapRegisters = BYTES_TO_PAGES( + DeviceDescription->MaximumLength ) + 1; + + // + // Limit the number of map registers to no more than 1/4 of all + // of the map registers available for this DMA window. + // + + MaximumMapRegistersPerChannel = + (HalpMasterMapAdapter->WindowSize >> PAGE_SHIFT) / 4; + if( *NumberOfMapRegisters > MaximumMapRegistersPerChannel ){ + *NumberOfMapRegisters = MaximumMapRegistersPerChannel; + } + + adapterObject->MapRegistersPerChannel = *NumberOfMapRegisters; + + } else { + + adapterObject->MapRegistersPerChannel = 0; + + } + } + + return(adapterObject); +} + +PMAP_REGISTER_ADAPTER +HalpAllocateMapAdapter( + IN PWINDOW_CONTROL_REGISTERS WindowRegisters, + IN HAL_ADAPTER_TYPE AdapterType, + IN PTRANSLATION_ENTRY MapRegisterBase + ) +/*++ + +Routine Description: + + This routine allocates and initializes the structure for the bus + master map register adapter. + +Arguments: + + WindowRegisters - Supplies a pointer to the software window control + registers that describes the DMA window associated + with this map adapter. + + AdapterType - Supplies the type of the adapter. + + MapRegisterBase - Supplies the starting virtual address of the map + registers for this adapter. + +Return Value: + + Returns the pointer to the allocated and initialized map + adapter if allocation was successful, NULL otherwise. + +--*/ + +{ + ULONG NumberMapRegisters; + ULONG Size; + PMAP_REGISTER_ADAPTER mapAdapter; + + Size = sizeof(MAP_REGISTER_ADAPTER); + + NumberMapRegisters = WindowRegisters->WindowSize / PAGE_SIZE; + + // + // Add size of bitmap. Size of bitmap is the number of bytes required, + // computed by dividing map registers by 8 (>>3) and then rounding up + // to the nearest value divisible by 4. + // + + Size += sizeof(RTL_BITMAP) + (( ((NumberMapRegisters+7) >> 3) + 3) & ~3); + + // + // Allocate the map register adapter. + // + + mapAdapter = ExAllocatePool( NonPagedPool, Size ); + + if( mapAdapter == NULL ){ + return NULL; + } + + // + // Initialize the fields within the map adapter structure. + // + + mapAdapter->Type = AdapterType; + + KeInitializeSpinLock( &mapAdapter->SpinLock ); + InitializeListHead( &mapAdapter->RegisterWaitQueue ); + + mapAdapter->MapRegisterBase = MapRegisterBase; + mapAdapter->NumberOfMapRegisters = NumberMapRegisters; + mapAdapter->MapRegisterAllocation = (PRTL_BITMAP)(mapAdapter + 1); + RtlInitializeBitMap( mapAdapter->MapRegisterAllocation, + (PULONG)((PCHAR)(mapAdapter->MapRegisterAllocation) + + sizeof(RTL_BITMAP)), + NumberMapRegisters ); + RtlClearAllBits( mapAdapter->MapRegisterAllocation ); + + + mapAdapter->WindowBase = WindowRegisters->WindowBase; + mapAdapter->WindowSize = WindowRegisters->WindowSize; + + mapAdapter->WindowControl = WindowRegisters; + + return mapAdapter; +} + +NTSTATUS +HalAllocateAdapterChannel( + IN PADAPTER_OBJECT AdapterObject, + IN PWAIT_CONTEXT_BLOCK Wcb, + IN ULONG NumberOfMapRegisters, + IN PDRIVER_CONTROL ExecutionRoutine + ) +/*++ + +Routine Description: + + This routine allocates the adapter channel specified by the adapter object. + This is accomplished by placing the device object of the driver that wants + to allocate the adapter on the adapter's queue. If the queue is already + "busy", then the adapter has already been allocated, so the device object + is simply placed onto the queue and waits until the adapter becomes free. + + Once the adapter becomes free (or if it already is), then the driver's + execution routine is invoked. + + Also, a number of map registers may be allocated to the driver by specifying + a non-zero value for NumberOfMapRegisters. Then the map register must be + allocated from the master adapter. Once there are a sufficient number of + map registers available, then the execution routine is called and the + base address of the allocated map registers in the adapter is also passed + to the driver's execution routine. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + + Wcb - Supplies a wait context block for saving the allocation parameters. + The DeviceObject, CurrentIrp and DeviceContext should be initalized. + + NumberOfMapRegisters - The number of map registers that are to be allocated + from the channel, if any. + + ExecutionRoutine - The address of the driver's execution routine that is + invoked once the adapter channel (and possibly map registers) have been + allocated. + +Return Value: + + Returns STATUS_SUCESS unless too many map registers are requested. + +Notes: + + Note that this routine MUST be invoked at DISPATCH_LEVEL or above. + +--*/ + +{ + IO_ALLOCATION_ACTION Action; + BOOLEAN Busy = FALSE; + PMAP_REGISTER_ADAPTER MapAdapter; + + // + // Begin by obtaining a pointer to the map register adapter associated + // with this request. + // + + MapAdapter = AdapterObject->MapAdapter; + + DebugPrint( (HALDBG_MAPREG, + "\nHalAllocateAdapter, Adapter=%x, MapA=%x, Maps=%x\n", + AdapterObject, MapAdapter, NumberOfMapRegisters) ); + + // + // Initialize the device object's wait context block in case this device + // must wait before being able to allocate the adapter. + // + + Wcb->DeviceRoutine = ExecutionRoutine; + Wcb->NumberOfMapRegisters = NumberOfMapRegisters; + + // + // Allocate the adapter object for this particular device. If the + // adapter cannot be allocated because it has already been allocated + // to another device, then return to the caller now; otherwise, + // continue. + // + + if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue, + &Wcb->WaitQueueEntry )) { + + // + // The adapter was not busy so it has been allocated. Now check + // to see whether this driver wishes to allocate any map registers. + // If so, then queue the device object to the master adapter queue + // to wait for them to become available. If the driver wants map + // registers, ensure that this adapter has enough total map registers + // to satisfy the request. + // + + AdapterObject->CurrentWcb = Wcb; + AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters; + + if (NumberOfMapRegisters != 0) { + + // + // Validate that the requested number of map registers is + // within the maximum limit. + // + + if (NumberOfMapRegisters > MapAdapter->NumberOfMapRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + Busy = HalpAllocateMapRegisters( AdapterObject, + NumberOfMapRegisters, + FALSE ); + + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (Busy == FALSE) { + + Action = ExecutionRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext + ); + + // + // If the driver wishes to keep the map registers then set the + // number allocated to zero and set the action to deallocate + // object. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + Action = DeallocateObject; + } + + // + // If the driver would like to have the adapter deallocated, + // then deallocate any map registers allocated and then release + // the adapter object. + // + + if (Action == DeallocateObject) { + IoFreeAdapterChannel( AdapterObject ); + } + + } else { + + DebugPrint( (HALDBG_MAPREG, + "No map registers available, Adapter= %x, Maps= %x\n", + AdapterObject, NumberOfMapRegisters) ); + + } + + } else { + + DebugPrint( (HALDBG_MAPREG, + "Device Queue is busy, AdapterObject = %x\n", + AdapterObject) ); + + } + + return(STATUS_SUCCESS); + +} + +BOOLEAN +HalpAllocateMapRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG NumberOfMapRegisters, + IN BOOLEAN MapAdapterLocked + ) +/*++ + +Routine Description: + + Allocate the requested number of contiguous map registers from + the Map adapter. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object for which the + map registers are to be allocated. + + NumberOfMapRegisters - Supplies the number of map registers to allocate. + + MapAdapterLocked - Supplies a boolean which indicates if the map adapter + for the AdapterObject is already locked. + +Return Value: + + The value returned indicates if the map registers are busy. + The value FALSE is returned if the map registers were allocated. + Otherwise, the Adapter is put on the register wait queue for its + associated map adapter and TRUE is returned. + +--*/ +{ + ULONG AllocationMask; + BOOLEAN Busy = FALSE; + ULONG ExtentBegin; + ULONG HintIndex; + KIRQL Irql; + ULONG MapRegisterIndex; + PMAP_REGISTER_ADAPTER mapAdapter; + + // + // Some devices do DMA prefetch. This is bad since it will cause certain + // chipsets to generate a PFN error because a map register has not been + // allocated and validated. To fix this, we'll put in a hack. We'll + // allocate one extra map register and map it to some junk page to avoid + // this nasty problem. + // + + NumberOfMapRegisters += 1; + + // + // Acquire a pointer to the map adapter that contains the map registers + // for the adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + // + // Lock the map register bit map and the adapter queue in the + // master adapter object. + // + + if( MapAdapterLocked == FALSE ){ + KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql ); + } + + MapRegisterIndex = MAXULONG; + + if (IsListEmpty( &mapAdapter->RegisterWaitQueue)) { + + // + // If this is an Isa machine and the requested DMA is for an + // Isa device then we must be careful that the DMA does not cross + // a 64K boundary on the bus. + // + + if( (HalpBusType == MACHINE_TYPE_ISA) && + (mapAdapter->Type == IsaAdapter) ){ + + ASSERT( (NumberOfMapRegisters * PAGE_SIZE) <= __64K ); + + // + // This is an Isa allocation, guarantee that the allocation + // of map registers will not span a 64K boundary. We do this by + // looking for a contiguous allocation of: + // NumberOfMapRegisters * 2 - 1 + // Any allocation of this size will guarantee that: + // (a) The allocation fits before the next 64K boundary or + // (b) The allocation can be made on the next 64K boundary. + // + // N.B. - This algorithm depends on RtlFindClear* to find + // the first available extent of cleared bits. + // + + ExtentBegin = RtlFindClearBits( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters + 7, + 0 ); + + if( ExtentBegin != -1 ){ + + // + // Compute the hint index. If ExtentBegin + NumberOfMaps + // does not cross a 64K boundary then ExtentBegin will be + // the hint index. Otherwise, align the hint to the next + // 64K boundary above ExtentBegin. + // + + AllocationMask = (__64K >> PAGE_SHIFT) - 1; + HintIndex = (ExtentBegin+AllocationMask) & ~AllocationMask; + + MapRegisterIndex = RtlFindClearBitsAndSet( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters, + HintIndex ); + + } + + + } else { + + // + // This allocation is not subject to the Isa 64K restriction. + // + + ExtentBegin = RtlFindClearBits( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters + 7, + 0 ); + + AllocationMask = (__64K >> PAGE_SHIFT) - 1; + + HintIndex = (ExtentBegin + AllocationMask) & ~AllocationMask; + + MapRegisterIndex = RtlFindClearBitsAndSet( + mapAdapter->MapRegisterAllocation, + NumberOfMapRegisters, + HintIndex ); + + } //endif HalpBusType == MACHINE_TYPE_ISA + + } //endif IsListEmpty + + if (MapRegisterIndex == MAXULONG) { + + // + // There were not enough free map registers. Queue this request + // on the map adapter where it will wait until some registers + // are deallocated. + // + + InsertTailList( &mapAdapter->RegisterWaitQueue, + &AdapterObject->AdapterQueue ); + Busy = TRUE; + + } + + // + // Unlock the map adapter (unless locked by the caller). + // + + if( MapAdapterLocked == FALSE ){ + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); + } + + // + // If map registers were allocated, return the index of the first + // map register in the contiguous extent. + // + + if( Busy == FALSE ){ + AdapterObject->MapRegisterBase = + (PVOID) ((PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase + + MapRegisterIndex); + } + + return Busy; + +} + +PADAPTER_OBJECT +HalpAllocateAdapter( + VOID + ) +/*++ + +Routine Description: + + This routine allocates and initializes an adapter object to represent an + adapter or a DMA controller on the system. + +Arguments: + + None. + +Return Value: + + The function value is a pointer to the allocated adapter object. + +--*/ + +{ + + PADAPTER_OBJECT AdapterObject; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG Size; + HANDLE Handle; + NTSTATUS Status; + + // + // Begin by initializing the object attributes structure to be used when + // creating the adapter object. + // + + InitializeObjectAttributes( &ObjectAttributes, + NULL, + OBJ_PERMANENT, + (HANDLE) NULL, + (PSECURITY_DESCRIPTOR) NULL + ); + + Size = sizeof( ADAPTER_OBJECT ); + + // + // Now create the adapter object. + // + + Status = ObCreateObject( KernelMode, + *((POBJECT_TYPE *)IoAdapterObjectType), + &ObjectAttributes, + KernelMode, + (PVOID) NULL, + Size, + 0, + 0, + (PVOID *)&AdapterObject ); + + // + // Reference the object. + // + + if (NT_SUCCESS(Status)) { + + Status = ObReferenceObjectByPointer( + AdapterObject, + FILE_READ_DATA | FILE_WRITE_DATA, + *IoAdapterObjectType, + KernelMode + ); + + } + + // + // If the adapter object was successfully created, then attempt to insert + // it into the the object table. + // + + if (NT_SUCCESS( Status )) { + + Status = ObInsertObject( AdapterObject, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + (PVOID *) NULL, + &Handle ); + + if (NT_SUCCESS( Status )) { + + ZwClose(Handle); + + // + // Initialize the adapter object itself. + // + + AdapterObject->Type = IO_TYPE_ADAPTER; + AdapterObject->Size = (USHORT) Size; + + // + // Initialize the channel wait queue for this + // adapter. + // + + KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue ); + + } else { + + // + // An error was incurred for some reason. Set the return value + // to NULL. + // + + AdapterObject = (PADAPTER_OBJECT) NULL; + } + + } else { + + AdapterObject = (PADAPTER_OBJECT) NULL; + + } + + return AdapterObject; + +} + + + +PVOID +HalAllocateCrashDumpRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN PULONG NumberOfMapRegisters + ) +/*++ + +Routine Description: + + This routine is called during the crash dump disk driver's initialization + to allocate a number map registers permanently. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + NumberOfMapRegisters - Number of map registers requested and updated to + show number actually allocated. + +Return Value: + + Returns a pointer to the allocated map register base. + +--*/ + +{ + ULONG AllocationMask; + PMAP_REGISTER_ADAPTER MapAdapter; + ULONG HintIndex; + ULONG MapRegisterIndex; + ULONG ExtentBegin; + + // + // Begin by obtaining a pointer to the map adapter associated with this + // request. + // + + MapAdapter = AdapterObject->MapAdapter; + + // + // Ensure that this adapter has enough total map registers to satisfy + // the request. + // + + if (*NumberOfMapRegisters > MapAdapter->NumberOfMapRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + return NULL; + } + + MapRegisterIndex = (ULONG)-1; + + // + // If this is an Isa machine and the requested DMA is for an + // Isa device then we must be areful that the DMA does not cross + // a 64K boundary on the bus. + // + + if( (HalpBusType == MACHINE_TYPE_ISA) && + (MapAdapter->Type == IsaAdapter) ){ + + // + // This is an Isa allocation, guarantee that the allocation + // of map registers will not span a 64K boundary. We do this by + // looking for a consiguous allocation of: + // NumberOfMapRegisters * 2 - 1 + // Any allocation of this size will guarantee that: + // (a) The allocation fitst before the next 64K boundary or + // (b) The allocation can be made on the next 64K boundary. + // + // N.B. - This algorithm depends on RtlFindClear* to find + // the first available extent of cleared bits. + // + + ExtentBegin = RtlFindClearBits( + MapAdapter->MapRegisterAllocation, + (*NumberOfMapRegisters * 2) - 1, + 0 ); + if( ExtentBegin != -1){ + + // + // Compute the hint index. If ExtentBegin + NumberOfMaps + // does not cross a 64K boundary then ExtentBegin will be + // the hint index. Otherwise, align the hint to the next + // 64K boundary above ExtentBegin. + // + + AllocationMask = (__64K >> PAGE_SHIFT) - 1; + HintIndex = ExtentBegin; + + if( (ExtentBegin + *NumberOfMapRegisters) > + ((ExtentBegin + AllocationMask) & ~AllocationMask) ){ + + // + // Allocation would have spanned a 64K boundary. + // Round up to next 64K boundary. + // + + HintIndex = (ExtentBegin+AllocationMask) & ~AllocationMask; + + } + + MapRegisterIndex = RtlFindClearBitsAndSet( + MapAdapter->MapRegisterAllocation, + *NumberOfMapRegisters, + HintIndex ); + + } + + } else { + + // + // This allocation is not subject to the Isa 64K restriction. + // + + HintIndex = 0; + + MapRegisterIndex = RtlFindClearBitsAndSet( + MapAdapter->MapRegisterAllocation, + *NumberOfMapRegisters, + 0 ); + + } + + if (MapRegisterIndex == (ULONG)-1) { + + // + // Not enough free map registers were found, so they were busy + // being used by the system when it crashed. Force the appropriate + // number to be "allocated" at the base by simply overjamming the + // bits and return the base map register as the start. + // + + RtlSetBits( + MapAdapter->MapRegisterAllocation, + HintIndex, + *NumberOfMapRegisters + ); + MapRegisterIndex = HintIndex; + + } + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) MapAdapter->MapRegisterBase + MapRegisterIndex); + + return AdapterObject->MapRegisterBase; +} + + + +VOID +IoFreeMapRegisters( + PADAPTER_OBJECT AdapterObject, + PVOID MapRegisterBase, + ULONG NumberOfMapRegisters + ) +/*++ + +Routine Description: + + This routine deallocates the map registers for the adapter. If there are + any queued adapter waiting for an attempt is made to allocate the next + entry. + +Arguments: + + AdapterObject - The adapter object to where the map register should be + returned. + + MapRegisterBase - The map register base of the registers to be deallocated. + + NumberOfMapRegisters - The number of registers to be deallocated. + +Return Value: + + None + +--+*/ + +{ + IO_ALLOCATION_ACTION Action; + BOOLEAN Busy = FALSE; + KIRQL Irql; + LONG MapRegisterIndex; + PLIST_ENTRY Packet; + PWAIT_CONTEXT_BLOCK Wcb; + PMAP_REGISTER_ADAPTER mapAdapter; + + + // + // Deallocate the extra map register that we originally allocated to fix + // the DMA prefetch problem. + // + + NumberOfMapRegisters += 1; + + // + // Begin by getting the address of the map register adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + DebugPrint( (HALDBG_MAPREG, + "IoFreeMapRegisters, Adapter=%x, MapA=%x, Maps=%x\n", + AdapterObject, mapAdapter, NumberOfMapRegisters) ); + + MapRegisterIndex = (PTRANSLATION_ENTRY) MapRegisterBase - + (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase; + + // + // Acquire the map adapter spinlock which locks the adapter queue and the + // bit map for the map registers. + // + + KeAcquireSpinLock(&mapAdapter->SpinLock, &Irql); + + // + // Return the registers to the bit map. + // + + RtlClearBits( mapAdapter->MapRegisterAllocation, + MapRegisterIndex, + NumberOfMapRegisters + ); + + // + // Process any requests waiting for map registers in the adapter queue. + // Requests are processed until a request cannot be satisfied or until + // there are no more requests in the queue. + // + + while(TRUE) { + + if ( IsListEmpty(&mapAdapter->RegisterWaitQueue) ){ + break; + } + + Packet = RemoveHeadList( &mapAdapter->RegisterWaitQueue ); + AdapterObject = CONTAINING_RECORD( Packet, + ADAPTER_OBJECT, + AdapterQueue + ); + DebugPrint( (HALDBG_MAPREG, + "IoFreeMaps, waking Adapter=%x\n", AdapterObject) ); + + Wcb = AdapterObject->CurrentWcb; + + // + // Attempt to allocate the map registers. + // + + Busy = HalpAllocateMapRegisters( AdapterObject, + Wcb->NumberOfMapRegisters, + TRUE ); + + if( Busy == TRUE ){ + DebugPrint( (HALDBG_MAPREG, + "IoFreeMaps, Not enough maps, Adapter=%x, Maps=%x\n", + AdapterObject, Wcb->NumberOfMapRegisters) ); + break; + } + + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); + + // + // Invoke the driver's execution routine now. + // + + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the driver wishes to keep the map registers then set the number + // allocated to zero and set the action to deallocate object. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + Action = DeallocateObject; + } + + // + // If the driver would like to have the adapter deallocated, + // then deallocate any map registers allocated and then release + // the adapter object. + // + + if (Action == DeallocateObject) { + + // + // The map registers are deallocated here rather than in + // IoFreeAdapterChannel. This limits the number of times + // this routine can be called recursively possibly overflowing + // the stack. The worst case occurs if there is a pending + // request for the adapter that uses map registers and whos + // excution routine decallocates the adapter. In that case if + // there are no requests in the map adapter queue, then + // IoFreeMapRegisters will get called again. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + + // + // Deallocate the map registers and clear the count so that + // IoFreeAdapterChannel will not deallocate them again. + // + + KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql ); + + MapRegisterIndex = + (PTRANSLATION_ENTRY)AdapterObject->MapRegisterBase - + (PTRANSLATION_ENTRY)mapAdapter->MapRegisterBase; + + RtlClearBits( mapAdapter->MapRegisterAllocation, + MapRegisterIndex, + AdapterObject->NumberOfMapRegisters + ); + + AdapterObject->NumberOfMapRegisters = 0; + + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); + + } + + IoFreeAdapterChannel( AdapterObject ); + } + + KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql ); + + } + + KeReleaseSpinLock( &mapAdapter->SpinLock, Irql ); +} + +VOID +IoFreeAdapterChannel( + IN PADAPTER_OBJECT AdapterObject + ) + +/*++ + +Routine Description: + + This routine is invoked to deallocate the specified adapter object. + Any map registers that were allocated are also automatically deallocated. + No checks are made to ensure that the adapter is really allocated to + a device object. However, if it is not, then kernel will bugcheck. + + If another device is waiting in the queue to allocate the adapter object + it will be pulled from the queue and its execution routine will be + invoked. + +Arguments: + + AdapterObject - Pointer to the adapter object to be deallocated. + +Return Value: + + None. + +--*/ + +{ + PKDEVICE_QUEUE_ENTRY Packet; + PMAP_REGISTER_ADAPTER mapAdapter; + BOOLEAN Busy = FALSE; + IO_ALLOCATION_ACTION Action; + PWAIT_CONTEXT_BLOCK Wcb; + KIRQL Irql; + LONG MapRegisterNumber; + + // + // Begin by getting the address of the map register adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + DebugPrint( (HALDBG_MAPREG, + "IoFreeChannel, Adapter=%x, MapAdapter=%x\n", + AdapterObject, mapAdapter) ); + + // + // Pull requests of the adapter's device wait queue as long as the + // adapter is free and there are sufficient map registers available. + // + + while( TRUE ){ + + // + // Begin by checking to see whether there are any map registers that + // need to be deallocated. If so, then deallocate them now. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + IoFreeMapRegisters( AdapterObject, + AdapterObject->MapRegisterBase, + AdapterObject->NumberOfMapRegisters + ); + } + + // + // Simply remove the next entry from the adapter's device wait queue. + // If one was successfully removed, allocate any map registers that it + // requires and invoke its execution routine. + // + + Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue ); + if (Packet == NULL) { + + // + // There are no more requests break out of the loop. + // + + break; + } + + Wcb = CONTAINING_RECORD( Packet, + WAIT_CONTEXT_BLOCK, + WaitQueueEntry ); + + AdapterObject->CurrentWcb = Wcb; + AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters; + + DebugPrint( (HALDBG_MAPREG, + "IoFreeChannel, waking for Maps=%x\n", + Wcb->NumberOfMapRegisters) ); + + // + // Check to see whether this driver wishes to allocate any map + // registers. If so, then queue the device object to the master + // adapter queue to wait for them to become available. If the driver + // wants map registers, ensure that this adapter has enough total + // map registers to satisfy the request. + // + + if (Wcb->NumberOfMapRegisters != 0) { + + Busy = HalpAllocateMapRegisters( AdapterObject, + Wcb->NumberOfMapRegisters, + FALSE ); + + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (Busy == FALSE) { + + AdapterObject->CurrentWcb = Wcb; + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the execution routine would like to have the adapter + // deallocated, then release the adapter object. + // + + if (Action == KeepObject) { + + // + // This request wants to keep the channel a while so break + // out of the loop. + // + + break; + } + + // + // If the driver wants to keep the map registers then set the + // number allocated to 0. This keeps the deallocation routine + // from deallocating them. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + } + + } else { + + // + // This request did not get the requested number of map registers so + // out of the loop. + // + + DebugPrint( (HALDBG_MAPREG, + "IoFreeChannel, not enough maps, Adapter=%x, Maps=%x\n", + AdapterObject, Wcb->NumberOfMapRegisters) ); + + break; + } + } +} + +PHYSICAL_ADDRESS +IoMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN OUT PULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine is invoked to set up the map registers in the DMA controller + to allow a transfer to or from a device. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel that has been allocated. + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + MapRegisterBase - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - Supplies the length of the transfer. This determines the + number of map registers that need to be written to map the transfer. + Returns the length of the transfer which was actually mapped. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + +Return Value: + + Returns the logical address to be used by bus masters. + +N.B. - The MapRegisterBase must point to the mapping intended for + the start virtual address of the Mdl. + +--*/ + +{ + ULONG NumberOfPages; + ULONG Offset; + PULONG PageFrameNumber; + ULONG i; + PMAP_REGISTER_ADAPTER mapAdapter; + PTRANSLATION_ENTRY mapRegister; + PHYSICAL_ADDRESS ReturnAddress; + + DebugPrint( (HALDBG_IOMT, + "\nIoMT: CurrentVA = %x, Length = %x, WriteToDevice = %x\n", + CurrentVa, *Length, WriteToDevice ) ); + + // + // Determine the Map Register Adapter. + // + + mapAdapter = NULL; + + if( AdapterObject == NULL ){ + + // + // The caller did not supply the adapter object, we will determine + // the map adapter by matching the MapRegisterBase to the ranges + // allocated for each map adapter. + // + + if( (HalpIsaMapAdapter != NULL) && + (MapRegisterBase >= HalpIsaMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpIsaMapAdapter->MapRegisterBase + + HalpIsaMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpIsaMapAdapter; + + } + + if( (HalpMasterMapAdapter != NULL) && + (MapRegisterBase >= HalpMasterMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpMasterMapAdapter->MapRegisterBase + + HalpMasterMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpMasterMapAdapter; + + } + + } else { + + // + // The adapter object has been provided and will always have + // a pointer to the map adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + } + + ASSERT( mapAdapter != NULL ); + + // + // Begin by determining where in the buffer this portion of the operation + // is taking place. + // + + Offset = BYTE_OFFSET( (PCHAR)CurrentVa - (PCHAR)Mdl->StartVa ); + DebugPrint( (HALDBG_IOMT, "Offset (1) = %x\n", Offset ) ); + + // + // Compute number of pages that this transfer spans. + // + + NumberOfPages = (Offset + *Length + PAGE_SIZE - 1) >> PAGE_SHIFT; + DebugPrint( (HALDBG_IOMT, "NumberOfPages = %x\n", NumberOfPages ) ); + + // + // Compute a pointer to the page frame of the starting page of the transfer. + // + + PageFrameNumber = (PULONG) (Mdl + 1); + PageFrameNumber += ( ((PCHAR) CurrentVa - (PCHAR) Mdl->StartVa) + >> PAGE_SHIFT ); + + // + // Compute a pointer to the map register that maps the starting page of + // the transfer. + // + + mapRegister = MapRegisterBase; + + // + // For each page, establish the mapping in the scatter/gather tables. + // + + for (i = 0; i < NumberOfPages; i++) { + HAL_MAKE_VALID_TRANSLATION( mapRegister, *PageFrameNumber ); + DebugPrint( (HALDBG_IOMT, + "Validate: *PageFrameNumber = %x, mapRegister = %x\n", + *PageFrameNumber, mapRegister ) ); + PageFrameNumber += 1; + mapRegister += 1; + } + + // + // If the operation is a write to device (transfer from memory to device), + // we will validate the extra map register so we don't generate a PFN + // error due to DMA prefetch by some devices. + // + + if (WriteToDevice) { + PageFrameNumber -= 1; + HAL_MAKE_VALID_TRANSLATION( mapRegister, *PageFrameNumber ); + } + + // + // Synchronize the scatter/gather entry writes with any subsequent writes + // to the device. + // + + HalpMb(); //jnfix - create HalpWmb(); + + // + // Invalidate any cached translations in the DMA window. + // + + INVALIDATE_DMA_TRANSLATIONS( mapAdapter->WindowControl ); + + // + // Set the offset to point to the map register plus the offset. + // + + Offset += ((PTRANSLATION_ENTRY) MapRegisterBase - + (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase) << PAGE_SHIFT; + + Offset += (ULONG)mapAdapter->WindowBase; + DebugPrint( (HALDBG_IOMT, "Offset(3) = %x\n", Offset ) ); + + if( (AdapterObject != NULL) && + (AdapterObject->Type == IsaAdapter) && + (AdapterObject->MasterDevice != TRUE) ){ + + // + // Start the EISA DMA controller. + // + + HalpMapEisaTransfer( + AdapterObject, + Offset, + *Length, + WriteToDevice + ); + + } + + ReturnAddress.QuadPart = Offset; + return(ReturnAddress); +} + + +BOOLEAN +IoFlushAdapterBuffers( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) + +/*++ + +Routine Description: + + This routine flushes the DMA adapter object buffers and clears the + enable flag which aborts the dma. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel. + + Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down + buffer to/from which the I/O occured. + + MapRegisterBase - A pointer to the base of the map registers in the adapter + or DMA controller. + + CurrentVa - The current virtual address in the buffer described the the Mdl + where the I/O operation occurred. + + Length - Supplies the length of the transfer. + + WriteToDevice - Supplies a BOOLEAN value that indicates the direction of + the data transfer was to the device. + +Return Value: + + TRUE - If the transfer was successful. + + FALSE - If there was an error in the transfer. + +--*/ + +{ + ULONG NumberOfPages; + ULONG Offset; + BOOLEAN Result; + ULONG i; + PMAP_REGISTER_ADAPTER mapAdapter; + PTRANSLATION_ENTRY mapRegister; + + DebugPrint( (HALDBG_IOMT, + "\nIoFlush: CurrentVA = %x, Length = %x, WriteToDevice = %x\n", + CurrentVa, Length, WriteToDevice ) ); + + // + // Determine the Map Register Adapter. + // + + mapAdapter = NULL; + + if( AdapterObject == NULL ){ + + // + // The caller did not supply the adapter object, we will determine + // the map adapter by matching the MapRegisterBase to the ranges + // allocated for each map adapter. + // + + if( (HalpIsaMapAdapter != NULL) && + (MapRegisterBase >= HalpIsaMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpIsaMapAdapter->MapRegisterBase + + HalpIsaMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpIsaMapAdapter; + + } + + if( (HalpMasterMapAdapter != NULL) && + (MapRegisterBase >= HalpMasterMapAdapter->MapRegisterBase) && + ((PTRANSLATION_ENTRY)MapRegisterBase < + (PTRANSLATION_ENTRY)HalpMasterMapAdapter->MapRegisterBase + + HalpMasterMapAdapter->NumberOfMapRegisters ) ){ + + mapAdapter = HalpMasterMapAdapter; + + } + + } else { + + // + // The adapter object has been provided and will always have + // a pointer to the map adapter. + // + + mapAdapter = AdapterObject->MapAdapter; + + } + + // + // Set the result of the flush to success. + // + + Result = TRUE; + + // + // If this is an Isa compatiable adapter or an adapter that uses + // the ISA/EISA Dma controllers then use the standard routines + // to clear the Dma controller. + // + + if( (AdapterObject != NULL) && + (AdapterObject->Type == IsaAdapter) && + (AdapterObject->MasterDevice != TRUE) ){ + + Result = HalpFlushEisaAdapter( AdapterObject, + Mdl, + MapRegisterBase, + CurrentVa, + Length, + WriteToDevice ); + } + + // + // The Mdl->StartVa must point to a page boundary. + // + + ASSERT( ( (ULONG)Mdl->StartVa & (PAGE_SIZE-1) ) == 0 ); + + // + // Compute the starting offset of the transfer. + // + + Offset = BYTE_OFFSET( (PCHAR)CurrentVa - (PCHAR)Mdl->StartVa ); + + // + // Compute the number of pages that this transfer spanned. + // + + NumberOfPages = (Offset + Length + PAGE_SIZE-1) >> PAGE_SHIFT; + + // + // Compute a pointer to the first translation entry that mapped this + // transfer. + // + + mapRegister = (PTRANSLATION_ENTRY)MapRegisterBase; + + // + // Mark each translation as invalid. + // + + for( i=0; i < NumberOfPages; i++ ){ + HAL_INVALIDATE_TRANSLATION( mapRegister ); + DebugPrint( (HALDBG_IOMT, + "Invalidate mapRegister = %x, PageFrame=%x\n", + mapRegister, (PTRANSLATION_ENTRY)mapRegister->Pfn) ); + mapRegister += 1; + } + + if( WriteToDevice ){ + HAL_INVALIDATE_TRANSLATION( mapRegister ); + } + + // + // Invalidate any cached translations in the DMA window. + // + + INVALIDATE_DMA_TRANSLATIONS( mapAdapter->WindowControl ); + + // + // Synchronize the updated translations with any subsequent device + // accesses. + // Also, synchronize any reads of the newly written DMA data by + // ensuring this processors view of memory is coherent. + // jnfix - actually this second task must be handled by HalFlushIoBuffers + // + + HalpMb(); + + return Result; + +} + +ULONG +HalReadDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +/*++ + +Routine Description: + + This function reads the DMA counter and returns the number of bytes left + to be transfered. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still be be transfered. + +--*/ + +{ + + // + // If this is an Isa compatiable adapter or an adapter that uses + // the ISA/EISA Dma controllers then use the standard routines + // to return the Dma count. + // + + if( AdapterObject->Type == IsaAdapter ){ + + return HalpReadEisaDmaCounter( AdapterObject ); + + } + + return 0; + +} + + +PVOID +HalAllocateCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + OUT PPHYSICAL_ADDRESS LogicalAddress, + IN BOOLEAN CacheEnabled + ) +/*++ + +Routine Description: + + This function allocates the memory for a common buffer and maps so that it + can be accessed by a master device and the CPU. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer to be allocated. + + LogicalAddress - Returns the logical address of the common buffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + Returns the virtual address of the common buffer. If the buffer cannot be + allocated then NULL is returned. + +--*/ + +{ + PVOID virtualAddress; + PVOID mapRegisterBase; + ULONG numberOfMapRegisters; + ULONG mappedLength; + WAIT_CONTEXT_BLOCK wcb; + KEVENT allocationEvent; + NTSTATUS status; + PMDL mdl; + KIRQL irql; + PHYSICAL_ADDRESS MaxPhysicalAddress; + + numberOfMapRegisters = BYTES_TO_PAGES(Length); + + // + // Allocate the actual buffer and limit its physical address + // below 1GB. The 1GB limitation guarantees that the buffer will + // be accessible via 32-bit superpage. + // + + MaxPhysicalAddress.HighPart = 0; + MaxPhysicalAddress.LowPart = __1GB - 1; + virtualAddress = MmAllocateContiguousMemory( Length, MaxPhysicalAddress ); + + if (virtualAddress == NULL) { + + return(virtualAddress); + + } + + // + // Initialize an event. + // + + KeInitializeEvent( &allocationEvent, NotificationEvent, FALSE); + + // + // Initialize the wait context block. Use the device object to indicate + // where the map register base should be stored. + // + + wcb.DeviceObject = &mapRegisterBase; + wcb.CurrentIrp = NULL; + wcb.DeviceContext = &allocationEvent; + + // + // Allocate the adapter and the map registers. + // + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + status = HalAllocateAdapterChannel( + AdapterObject, + &wcb, + numberOfMapRegisters, + HalpAllocationRoutine + ); + + KeLowerIrql(irql); + + if (!NT_SUCCESS(status)) { + + // + // Cleanup and return NULL. + // + + MmFreeContiguousMemory( virtualAddress ); + return(NULL); + + } + + // + // Wait for the map registers to be allocated. + // + + status = KeWaitForSingleObject( + &allocationEvent, + Executive, + KernelMode, + FALSE, + NULL + ); + + if (!NT_SUCCESS(status)) { + + // + // Cleanup and return NULL. + // + + MmFreeContiguousMemory( virtualAddress ); + return(NULL); + + } + + // + // Create an mdl to use with call to I/O map transfer. + // + + mdl = IoAllocateMdl( + virtualAddress, + Length, + FALSE, + FALSE, + NULL + ); + + MmBuildMdlForNonPagedPool(mdl); + + // + // Map the transfer so that the controller can access the memory. + // + + mappedLength = Length; + *LogicalAddress = IoMapTransfer( + NULL, + mdl, + mapRegisterBase, + virtualAddress, + &mappedLength, + TRUE + ); + + IoFreeMdl(mdl); + + if (mappedLength < Length) { + + // + // Cleanup and indicate that the allocation failed. + // + + HalFreeCommonBuffer( + AdapterObject, + Length, + *LogicalAddress, + virtualAddress, + FALSE + ); + + return(NULL); + } + + // + // The allocation completed successfully. + // + + return(virtualAddress); + +} + +VOID +HalFreeCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress, + IN BOOLEAN CacheEnabled + ) +/*++ + +Routine Description: + + This function frees a common buffer and all of the resouces it uses. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + None + +--*/ + +{ + PMAP_REGISTER_ADAPTER mapAdapter; + PTRANSLATION_ENTRY mapRegisterBase; + ULONG mapRegisterIndex; + ULONG numberOfMapRegisters; + + mapAdapter = AdapterObject->MapAdapter; + + // + // Calculate the number of map registers, the map register index and + // the map register base. + // + + numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( VirtualAddress, + Length ); + mapRegisterIndex = (LogicalAddress.LowPart - (ULONG)mapAdapter->WindowBase) + >> PAGE_SHIFT; + + mapRegisterBase = (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase + + mapRegisterIndex; + + // + // Free the map registers. + // + + IoFreeMapRegisters( + AdapterObject, + (PVOID) mapRegisterBase, + numberOfMapRegisters + ); + + // + // Free the memory for the common buffer. + // + + MmFreeContiguousMemory( VirtualAddress ); + + return; + +} + + +BOOLEAN +HalFlushCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress + ) +/*++ + +Routine Description: + + This function is called to flush any hardware adapter buffers when the + driver needs to read data written by an I/O master device to a common + buffer. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + +Return Value: + + Returns TRUE if no errors were detected; otherwise, FALSE is return. + +--*/ + +{ + + return(TRUE); + +} + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This function is called by HalAllocateAdapterChannel when sufficent resources + are available to the driver. This routine saves the MapRegisterBase, + and set the event pointed to by the context parameter. + +Arguments: + + DeviceObject - Supplies a pointer where the map register base should be + stored. + + Irp - Unused. + + MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer. + + Context - Supplies a pointer to an event which is set to indicate the + AdapterObject has been allocated. + +Return Value: + + DeallocateObjectKeepRegisters - Indicates the adapter should be freed + and mapregisters should remain allocated after return. + +--*/ + +{ + + UNREFERENCED_PARAMETER(Irp); + + *((PVOID *) DeviceObject) = MapRegisterBase; + + (VOID) KeSetEvent( (PKEVENT) Context, 0L, FALSE ); + + return(DeallocateObjectKeepRegisters); +} -- cgit v1.2.3