Hi all,
I have encountered another puzzling problem in writing a driver. The basic idea of my driver was to synchronize use of a DMA engine using WorkItems and spinlocks. I am relying on the FIFO like behavior of WorkItems while using the spinlock to make sure that only the current work item will have access to the DMA engine.
I perform the following steps:
-
Created a SpinLock object that is kept in my device extension.
-
ISR occurs->DPC called-> DPC creates a WorkItem and executes it for each service request
* The DPC also uses events to tell currently executing WOrkItems that a DMA operation has completed -
The WorkItem will try and obtain the spinlock in the device context
* All other subsequent workitems should wait for the lock until it is release.
* The DMA Workitem will wait for notification that the DMA completed.
* When the DMA operation is completed the workItem will release the spinlock and delete itself. -
The next WorkItem should be able to get the spinlock and go on its merry way.
The problem I am seeing is that each WorkItem that is created seems to be able to obtain the spinlock as soon as it tries and kills the synchronization I thought I had. I have so far assumed that I am always dealing the one and only Device context each time I obtained the context but now I am staring to question this. Could I not be using “my” device context somehow?
What could be wrong?
Here is the general code snippets----
NTSTATUS
ddcInitializeDMA(
IN PDEVICE_EXTENSION devExt
)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_DMA_ENABLER_CONFIG dmaConfig;
WDF_OBJECT_ATTRIBUTES attributes;
int i=0;
PAGED_CODE();
…
//Initialize DMA Lock
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = devExt->Device;
status = WdfSpinLockCreate(&attributes,&devExt->DmaLock);
if(!NT_SUCCESS(status)){
KdPrint(( “e2mapci : ddcInitializeDeviceExtension : WdfSpinLockCreate : DmaLock failed!”));
}
…
//
// Initialize MTI DMA Event
//
KeInitializeEvent(&devExt -> MtiDMAEvent, NotificationEvent, FALSE);
return status;
}
NTSTATUS
ddcInitializeDMA(
IN PDEVICE_EXTENSION devExt
)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_DMA_ENABLER_CONFIG dmaConfig;
WDF_OBJECT_ATTRIBUTES attributes;
int i=0;
PAGED_CODE();
…
//Initialize DMA Lock
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = devExt->Device;
status = WdfSpinLockCreate(&attributes,&devExt->DmaLock);
if(!NT_SUCCESS(status)){
KdPrint(( “e2mapci : ddcInitializeDeviceExtension : WdfSpinLockCreate : DmaLock failed!”));
}
…
//
// Initialize MTI DMA Event
//
KeInitializeEvent(&devExt -> MtiDMAEvent, NotificationEvent, FALSE);
return status;
}
VOID
ddcEvtInterruptDpc(
IN WDFINTERRUPT Interrupt,
IN WDFDEVICE Device
)
–*/
{
NTSTATUS status= STATUS_SUCCESS;
…
devExt = ddcGetDeviceContext(Device);
…
//
// Evaluate MSR
//
// read improvements iterrupt status
ISR1 = ddcReadReg32(ISRReg);
if(ISR1)
{
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(
&attributes,
MTI_DATA_WORKITEM_CONTEXT
);
attributes.ParentObject = Device;
WDF_WORKITEM_CONFIG_INIT(
&workitemConfig,
ddcDMAWorkItem
);
workitemConfig.AutomaticSerialization = FALSE;
status = WdfWorkItemCreate(
&workitemConfig,
&attributes,
&DMAWorkItem
);
if (!NT_SUCCESS(status)) {
KdPrint((“Failed to create workitem %x\n”, status));
return;
}
//get context
MTIWorkitemContext = GetMTIDataWorkItemContext(DMAWorkItem);
//set device in workitem context
MTIWorkitemContext->Device = Device;
//
// Execute this work item.
//
WdfWorkItemEnqueue(DMAWorkItem);
}
}
…
return;
}
VOID
ddcDMAWorkItem(
IN WDFWORKITEM WorkItem
)
{
PMTI_DATA_WORKITEM_CONTEXT pItemContext;
NTSTATUS status= STATUS_SUCCESS;
PDEVICE_EXTENSION devExt;
…
KdPrint((“ddcDMAWorkItem: called!\n”));
// get work item
pItemContext = GetMTIDataWorkItemContext(WorkItem);
devExt = ddcGetDeviceContext(pItemContext->Device);
// acquire DMA spinlock
KdPrint((“ddcDMAWorkItem: waiting for spinlock!\n”));
WdfSpinLockAcquire(devExt->DmaLock);
KdPrint((“ddcDMAWorkItem: acquired spinlock!\n”));
// send out DMA
//
// Create a new DmaTransaction.
//
…
//
// Initialize this new DmaTransaction.
//
…
// preform DMA
…
//wait for signal event to sgnal transaction complete process buffer & release spinlock
KeWaitForSingleObject(&devExt -> MtiDMAEvent, Executive, KernelMode, FALSE,NULL);
KdPrint((“ddcDMAWorkItem: Received DMA event!\n”));
//
…
// release SpinLock
WdfSpinLockRelease(devExt->DmaLock);
KdPrint((“ddcDMAWorkItem: released spinlock!\n”));
// delete work item
WdfObjectDelete(WorkItem);
return;
}