Fixes to get slave DMA working again, as well as more architectural changes

that bring us closer to the Windows 2000 DMA model.

adapter.c: significantly re-worked and heavily commented
hal.h: more additions to ADAPTER_OBJECT; more pending
dma.c: added initialization of ADAPTER_OBJECT
ndis/io.c: minor DMA changes and addition of fixmes

svn path=/trunk/; revision=6411
This commit is contained in:
Vizzini 2003-10-23 09:03:51 +00:00
parent 47be3186ac
commit 3c640340fe
4 changed files with 194 additions and 85 deletions

View file

@ -363,9 +363,8 @@ NdisMAllocateMapRegisters(
Description.Version = DEVICE_DESCRIPTION_VERSION;
Description.Master = TRUE; /* implied by calling this function */
Description.ScatterGather = TRUE; /* All BM DMA are S/G (ms seems to do this) */
Description.ScatterGather = TRUE; /* XXX UNTRUE: All BM DMA are S/G (ms seems to do this) */
Description.Dma32BitAddresses = DmaSize;
Description.Dma64BitAddresses = 0; /* FIXME figure this out based on input */
Description.BusNumber = Adapter->BusNumber;
Description.InterfaceType = Adapter->BusType;
Description.DmaChannel = DmaChannel;
@ -373,6 +372,7 @@ NdisMAllocateMapRegisters(
if(Adapter->NdisMiniportBlock.AdapterType == Isa)
{
/* system dma */
if(DmaChannel < 4)
Description.DmaWidth = Width8Bits;
else
@ -382,7 +382,6 @@ NdisMAllocateMapRegisters(
}
else if(Adapter->NdisMiniportBlock.AdapterType == PCIBus)
{
/* Width and Speed are automatically determined on PCI */
if(DmaSize == NDIS_DMA_64BITS)
Description.Dma64BitAddresses = TRUE;
else
@ -394,12 +393,6 @@ NdisMAllocateMapRegisters(
ASSERT(0);
}
Description.Reserved1 = 0; /* Must Be Zero (ref DDK) */
Description.DemandMode = 0; /* unused due to bus master */
Description.AutoInitialize = 0; /* unused due to bus master */
Description.IgnoreCount = 0; /* unused due to bus master */
Description.DmaPort = 0; /* unused due to bus type */
AvailableMapRegisters = MapRegistersRequired;
AdapterObject = HalGetAdapter(&Description, &AvailableMapRegisters);

View file

@ -1,4 +1,4 @@
/* $Id: adapter.c,v 1.6 2003/10/20 06:03:28 vizzini Exp $
/* $Id: adapter.c,v 1.7 2003/10/23 09:03:51 vizzini Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -22,6 +22,7 @@
/* NOTE: IoAllocateAdapterChannel in NTOSKRNL.EXE */
NTSTATUS STDCALL
HalAllocateAdapterChannel(PADAPTER_OBJECT AdapterObject,
PWAIT_CONTEXT_BLOCK WaitContextBlock,
@ -39,76 +40,77 @@ HalAllocateAdapterChannel(PADAPTER_OBJECT AdapterObject,
* STATUS_SUCCESS in all other cases, including if the callbacak had
* to be queued for later delivery
* NOTES:
* - Map registers don't exist on X86 so we can just call the callback
* with a map register base of 0
* - the ADAPTER_OBJECT struct is undocumented; please make copious
* notes here if anything is changed or improved since there is
* no other documentation for this routine or its data structures
* - The original implementation of this function allocated a contiguous
* physical buffer the size of NumberOfMapRegisters * PAGE_SIZE, which
* is unnecessary and very expensive (contiguous memory is rare). It
* also leaked in some circumstances (drivers allocate and sometimes
* don't free map registers)
* notes in hal.h if anything is changed or improved since there is
* no other documentation for this data structure
* BUGS:
* - This routine should check whether or not map registers are needed
* (rather than assuming they're not) and allocate them on platforms
* that support them.
* - it's possible that some of this code is in the wrong place
* - there are many unhandled cases
*/
{
#if 0
KIRQL OldIrql;
PVOID Buffer;
int ret;
LARGE_INTEGER MaxAddress;
IO_ALLOCATION_ACTION Retval;
/* set up the wait context block in case we can't run right away */
WaitContextBlock->DeviceRoutine = ExecutionRoutine;
WaitContextBlock->NumberOfMapRegisters = NumberOfMapRegisters;
/* returns true if queued, else returns false and sets the queue to busy */
if(KeInsertDeviceQueue(&AdapterObject->DeviceQueue, (PKDEVICE_QUEUE_ENTRY)WaitContextBlock))
return STATUS_SUCCESS;
/* 24-bit max address due to 16-bit dma controllers */
MaxAddress.QuadPart = 0x1000000;
/* why 64K alignment? */
Buffer = MmAllocateContiguousAlignedMemory( NumberOfMapRegisters * PAGE_SIZE,
MaxAddress,
0x10000 );
if( !Buffer )
/*
* X86 lacks map registers, so for now, we allocate a contiguous
* block of physical memory <16MB and copy all DMA buffers into
* that. This can be optimized.
*/
AdapterObject->MapRegisterBase = MmAllocateContiguousAlignedMemory(
NumberOfMapRegisters * PAGE_SIZE, MaxAddress, 0x10000 );
if(!AdapterObject->MapRegisterBase)
return STATUS_INSUFFICIENT_RESOURCES;
KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
if( AdapterObject->Inuse )
{
// someone is already using it, we need to wait
// create a wait block, and add it to the chain
UNIMPLEMENTED;
}
else {
AdapterObject->Inuse = TRUE;
KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
ret = ExecutionRoutine( DeviceObject,
NULL,
Buffer,
WaitContextBlock->DriverContext );
KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
if( ret == DeallocateObject )
{
MmFreeContiguousMemory( Buffer );
AdapterObject->Inuse = FALSE;
}
else AdapterObject->Buffer = Buffer;
}
KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
#endif
AdapterObject->MapRegisterBase = 0;
AdapterObject->AllocatedMapRegisters = 0;
AdapterObject->AllocatedMapRegisters = NumberOfMapRegisters;
IO_ALLOCATION_ACTION Retval = ExecutionRoutine(WaitContextBlock->DeviceObject,
WaitContextBlock->CurrentIrp, 0, WaitContextBlock->DeviceContext);
/* call the client's AdapterControl callback with its map registers and context */
Retval = ExecutionRoutine(WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
if(Retval == DeallocateObject)
IoFreeAdapterChannel(AdapterObject);
/*
* KeepObject: don't free any resources; the ADAPTER_OBJECT is still in use
* and the caller will call IoFreeAdapterChannel later
*
* DeallocateObject: Deallocate the map registers and release the ADAPTER_OBJECT
* so someone else can use it
*
* DeallocateObjectKeepRegisters: release the ADAPTER_OBJECT but hang on to
* the map registers. The client will later call IoFreeMapRegisters.
*
* NOTE - IoFreeAdapterChannel runs the queue, so it must be called
* unless the adapter object is not to be freed.
*/
if( Retval == DeallocateObject )
IoFreeAdapterChannel(AdapterObject);
else if(Retval == DeallocateObjectKeepRegisters)
AdapterObject->AllocatedMapRegisters = 0;
{
/* don't free the allocated map registers - this is what IoFreeAdapterChannel checks */
AdapterObject->AllocatedMapRegisters = 0;
IoFreeAdapterChannel(AdapterObject);
}
/*
* if we don't call IoFreeAdapterChannel, the next device won't get de-queued,
* which is what we want.
*/
return STATUS_SUCCESS;
}
BOOLEAN STDCALL
IoFlushAdapterBuffers (PADAPTER_OBJECT AdapterObject,
PMDL Mdl,
@ -116,44 +118,124 @@ IoFlushAdapterBuffers (PADAPTER_OBJECT AdapterObject,
PVOID CurrentVa,
ULONG Length,
BOOLEAN WriteToDevice)
/*
* FUNCTION: flush any data remaining in the dma controller's memory into the host memory
* ARGUMENTS:
* AdapterObject: the adapter object to flush
* Mdl: original MDL to flush data into
* MapRegisterBase: map register base that was just used by IoMapTransfer, etc
* CurrentVa: offset into Mdl to be flushed into, same as was passed to IoMapTransfer
* Length: length of the buffer to be flushed into
* WriteToDevice: True if it's a write, False if it's a read
* RETURNS:
* TRUE in all cases
* NOTES:
* - This copies data from the map register-backed buffer to the user's target buffer.
* Data is not in the user buffer until this is called.
* - This is only meaningful on a read operation. Return immediately for a write.
*/
{
// if this was a read from device, copy data back to caller buffer, otherwise, do nothing
if( !WriteToDevice )
memcpy( (PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) + (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )), MapRegisterBase, Length );
/* FIXME we don't have ASSERT */
//ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
/* this can happen if the card supports scatter/gather */
if(!MapRegisterBase)
return TRUE;
if(WriteToDevice)
return TRUE;
memcpy(
(PVOID)((DWORD)MmGetSystemAddressForMdl( Mdl ) + (DWORD)CurrentVa - (DWORD)MmGetMdlVirtualAddress( Mdl )),
MapRegisterBase, Length );
return TRUE;
}
VOID STDCALL
IoFreeAdapterChannel (PADAPTER_OBJECT AdapterObject)
/*
* FUNCTION: frees DMA resources allocated by IoAllocateAdapterChannel
* ARGUMENTS:
* AdapterObject: Adapter object with resources to free
* NOTES:
* - This function releases the DMA adapter and optionally the map registers
* - After releasing the adapter, it checks the adapter's queue and runs
* each queued device object in series until the queue is empty
* - This is the only way the device queue is emptied.
*/
{
KIRQL OldIrql;
KeAcquireSpinLock( &AdapterObject->SpinLock, &OldIrql );
if( AdapterObject->Inuse == FALSE )
LARGE_INTEGER MaxAddress;
PWAIT_CONTEXT_BLOCK WaitContextBlock;
IO_ALLOCATION_ACTION Retval;
while(1)
{
DbgPrint( "Attempting to IoFreeAdapterChannel on a channel not in use\n" );
KEBUGCHECK(0);
/* To keep map registers, call here with the following set to 0 */
if(AdapterObject->AllocatedMapRegisters)
IoFreeMapRegisters(AdapterObject, AdapterObject->MapRegisterBase, AdapterObject->AllocatedMapRegisters);
if(!(WaitContextBlock = (PWAIT_CONTEXT_BLOCK)KeRemoveDeviceQueue(&AdapterObject->DeviceQueue)))
break;
/*
* the following should really be done elsewhere since this
* function really can't return an error code. FIXME.
*/
/* 24-bit max address due to 16-bit dma controllers */
MaxAddress.QuadPart = 0x1000000;
AdapterObject->MapRegisterBase = MmAllocateContiguousAlignedMemory(
WaitContextBlock->NumberOfMapRegisters * PAGE_SIZE, MaxAddress, 0x10000 );
if(!AdapterObject->MapRegisterBase)
return;
/* call the adapter control routine */
Retval = ((PDRIVER_CONTROL)WaitContextBlock->DeviceRoutine)(WaitContextBlock->DeviceObject, WaitContextBlock->CurrentIrp,
AdapterObject->MapRegisterBase, WaitContextBlock->DeviceContext);
if(Retval == KeepObject)
{
/* we're done until the caller manually calls IoFreeAdapterChannel */
break;
}
else if(Retval == DeallocateObjectKeepRegisters)
{
/* hide the map registers so they aren't deallocated next time around */
AdapterObject->AllocatedMapRegisters = 0;
}
}
AdapterObject->Inuse = FALSE;
if( AdapterObject->Buffer )
{
MmFreeContiguousMemory( AdapterObject->Buffer );
AdapterObject->Buffer = 0;
}
KeReleaseSpinLock( &AdapterObject->SpinLock, OldIrql );
}
VOID STDCALL
IoFreeMapRegisters (PADAPTER_OBJECT AdapterObject,
PVOID MapRegisterBase,
ULONG NumberOfMapRegisters)
/*
* FUNCTION: free map registers reserved by the system for a DMA
* ARGUMENTS:
* AdapterObject: dma adapter to free map registers on
* MapRegisterBase: hadle to map registers to free
* NumberOfRegisters: number of map registers to be freed
* NOTES:
* - XXX real windows has a funky interdependence between IoFreeMapRegisters
* and IoFreeAdapterChannel
* BUGS:
* - needs to be improved to use a real map register implementation
*/
{
UNIMPLEMENTED;
if( AdapterObject->AllocatedMapRegisters )
{
MmFreeContiguousMemory(AdapterObject->MapRegisterBase);
AdapterObject->MapRegisterBase = 0;
}
}
PHYSICAL_ADDRESS STDCALL
IoMapTransfer (PADAPTER_OBJECT AdapterObject,
PMDL Mdl,
@ -161,6 +243,24 @@ IoMapTransfer (PADAPTER_OBJECT AdapterObject,
PVOID CurrentVa,
PULONG Length,
BOOLEAN WriteToDevice)
/*
* FUNCTION: map a dma for transfer and do the dma if it's a slave
* ARGUMENTS:
* AdapterObject: adapter object to do the dma on
* Mdl: locked-down user buffer to DMA in to or out of
* MapRegisterBase: handle to map registers to use for this dma
* CurrentVa: index into Mdl to transfer into/out of
* Length: length of transfer in/out
* WriteToDevice: TRUE if it's an output dma, FALSE otherwise
* RETURNS:
* If a busmaster: A logical address that can be used to program a dma controller
* Otherwise: nothing meaningful
* NOTES:
* - This function does a copyover to contiguous memory <16MB
* - If it's a slave transfer, this function actually performs it.
* BUGS:
* - If the controller supports scatter/gather, the copyover should not happen
*/
{
PHYSICAL_ADDRESS Address;
// program up the dma controller, and return

View file

@ -1,4 +1,4 @@
/* $Id: dma.c,v 1.7 2003/09/11 11:45:28 ekohl Exp $
/* $Id: dma.c,v 1.8 2003/10/23 09:03:51 vizzini Exp $
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
@ -16,6 +16,9 @@
#include <internal/debug.h>
#include <hal.h>
/* XXX This initialization is out of date - ADAPTER_OBJECT has changed */
/* NOTE: The following initializations have to be kept in synch with ADAPTER_OBJECT in hal.h */
/* FIXME: we need the 16-bit dma channels */
ADAPTER_OBJECT IsaSlaveAdapterObjects[] = {
{ Isa, FALSE, 0, (PVOID)0x87, (PVOID)0x1, (PVOID)0x0, 0, NULL },
{ Isa, FALSE, 1, (PVOID)0x83, (PVOID)0x3, (PVOID)0x2, 0, NULL },
@ -25,6 +28,8 @@ ADAPTER_OBJECT IsaSlaveAdapterObjects[] = {
ADAPTER_OBJECT PciBusMasterAdapterObjects[] = {
{ PCIBus, TRUE, 0, (PVOID)0, (PVOID)0, (PVOID)0x0, 0, NULL } };
/* Global flag to tell whether or not the adapter's device queue should be initialized (first call only) */
BOOLEAN AdaptersInitialized = FALSE;
/* FUNCTIONS *****************************************************************/
@ -112,6 +117,17 @@ HalGetAdapter (PDEVICE_DESCRIPTION DeviceDescription,
* Figure out what to do with the commented-out cases
*/
{
/* TODO: find a better home for this */
if(!AdaptersInitialized)
{
KeInitializeDeviceQueue(&PciBusMasterAdapterObjects[0].DeviceQueue);
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[0].DeviceQueue);
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[1].DeviceQueue);
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[2].DeviceQueue);
KeInitializeDeviceQueue(&IsaSlaveAdapterObjects[3].DeviceQueue);
AdaptersInitialized = TRUE;
}
/* Validate parameters in device description, and return a pointer to
the adapter object for the requested dma channel */
if( DeviceDescription->Version != DEVICE_DESCRIPTION_VERSION )

View file

@ -57,8 +57,8 @@ struct _ADAPTER_OBJECT {
PVOID MapRegisterBase;
ULONG AllocatedMapRegisters;
PWAIT_CONTEXT_BLOCK WaitContextBlock;
PKDEVICE_QUEUE DeviceQueue;
BOOLEAN UsesPhysicalMapRegisters;
KDEVICE_QUEUE DeviceQueue;
BOOLEAN ScatterGather;
};
/* sysinfo.c */