Hello:
Some months ago, and with guidance from the members of this forum, I undertook an effort to develop a WDK8 Win7 driver for a 32-bit device that supported scatter-gather DMA from an FPGA board hosting a Xilinx PCIe Endpoint Block (v 1.15). This effort is close to success, but I am running into a problem that I can’t resolve, which occurs somewhere between the driver, the kernel and the firmware on the device. It appears to me that the firmware is writing to an incorrect location in memory, resulting in a blue screen.
The design employs the WdfDmaProfileScatterGather profile to generate a scatter-gather list. The 32-bit physical memory addresses and lengths returned in the scatter gather elements are written into a FIFO on the board, and the firmware writes MWR3 packets targeting these addresses. Firmware has been designed to place addresses and the MWR3 header into register space. Comparison between physical addresses in the scatter-gather list as seen by the driver (via Traceview) and physical addresses written into the MWR3 headers by the firmware indicates consistency. MWR3 header is as expected. However, memory targeted by the host-side test program is not filled by the DMA. Naturally I started with very short transfers (8 bytes), and worked up in size until the machine crashes at transfers of order 0x1000. For what its worth I verified via Traceview that the scatter-gather list is composed of a single element for transfers up to 0x1000 (i.e. page size).
I interpret this crash as a sign that the firmware has targeted an incorrect address.
Briefly, the WDF routines I’m calling are modelled after the widely used PLX9x5x example:
/// EvtDeviceAdd
NTSTATUS status;
PDEVICE_CONTEXT devCtx;
WDF_OBJECT_ATTRIBUTES attributes;
WDF_DMA_ENABLER_CONFIG dmaConfig;
/* code omitted */
devCtx = DeviceGetContext(Device);
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &Device);
if (!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_INFORMATION,
TRACE_TOSC_DRIVER,
“%!FUNC! Error in WdfDeviceCreate”);
}
WdfDeviceSetAlignmentRequirement( Device,
FILE_64_BYTE_ALIGNMENT);
WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig,
(WDF_DMA_PROFILE)(WdfDmaProfileScatterGather) ,
MaxTransferLength );
status = WdfDmaEnablerCreate( Device,
&dmaConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&(devCtx->DMAparms.DMAEnabler));
if (!NT_SUCCESS (status)) {
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_TOSC_DRIVER,
“%!FUNC! WdfDmaEnablerCreate failed: %!STATUS!”,
status);
return status;
}
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TRANSACTION_CONTEXT);
status = WdfDmaTransactionCreate( devCtx->DMAparms.DMAEnabler,
&attributes,
&(devCtx->DMAparms.DMAReadDmaTransaction));
if(!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_TOSC_DRIVER,
“%!FUNC! WdfDmaTransactionCreate A failed: %!STATUS!”,
status);
return status;
}
/// EvtIoRead
WDF_REQUEST_PARAMETERS params;
WDFDEVICE device;
PDEVICE_CONTEXT devCtx;
NTSTATUS status;
/* code omitted */
status = WdfDmaTransactionInitializeUsingRequest(
devCtx->DMAparms.DMAReadDmaTransaction,
Request,
EvtProgramReadDma,
WdfDmaDirectionReadFromDevice );
if(!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_TOSC_QUEUE,
“%!FUNC! failed: WdfDmaTransactionInitializeUsingRequest %!STATUS!”, status);
break;
}
status = WdfDmaTransactionExecute(devCtx->DMAparms_A.DMAReadDmaTransaction,
WDF_NO_CONTEXT);
if(!NT_SUCCESS(status)) {
TraceEvents(TRACE_LEVEL_ERROR,
TRACE_TOSC_QUEUE,
“%!FUNC! failed: WdfDmaTransactionExecute %!STATUS!”,
status);
break;
}