a DMA PCI Device Driver doesn't work in Vista x64 + more 4GRAM platform!!

  • Thread starter Thread starter Leon Huang
  • Start date Start date
L

Leon Huang

Hi
I writed a BDA driver for a PCI TV card device,I found that my driver can
work well on Vista32/XP32/XPx64 + 4GRAM platform, and work well on Vista x64
+ less than 4G RAM, but can't work on Vista x64 + 4G RAM, this problem make
me confused. I guess that this problem maybe result from the DMA addressing
in Vista x64, or MS change the DMA addressing in Vista x64 after XP
x64,so,the DMA configuration of my driver doesn't compatible with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif
desc.AutoInitialize = FALSE;
desc.MaximumLength = (ULONG) -1;
m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;
m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,
&desc,
&m_MaxMapRegisters);
m_MaxMapRegisters=(TABLE_SIZE)/8;
KdPrint(("DMA MaxMap Cnt=%d\n",m_MaxMapRegisters));
if(!m_pDMAObject)
{
KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
////Allocate DMA Table memory!
for(index=0;index<DMA_INT_CNT;index++)
{
m_DMAPara[index].KsDMA_Table_VA=(PULONG)(m_pDMAObject->DmaOperations)->
AllocateCommonBuffer(m_pDMAObject,
TABLE_SIZE,
&m_DMAPara[index].KsDMA_Table_PA,
FALSE);
if(!m_DMAPara[index].KsDMA_Table_VA)
{
KdPrint(("@@@Allocate DMA%d Table Fail!\n",index));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;
}

can you give me a idea?

thanks

best regards

Leon Huang
 
Leon Huang said:
Hi
I writed a BDA driver for a PCI TV card device,I found that my driver can
work well on Vista32/XP32/XPx64 + 4GRAM platform, and work well on Vista x64
+ less than 4G RAM, but can't work on Vista x64 + 4G RAM, this problem make
me confused. I guess that this problem maybe result from the DMA addressing
in Vista x64, or MS change the DMA addressing in Vista x64 after XP
x64,so,the DMA configuration of my driver doesn't compatible with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif

This code is completely wrong, as the documentation makes clear. The
setting of Dma32BitAddresses and Dma64BitAddresses have ABSOLUTELY NOTHING
to do with the operating system. They are not software-related settings in
any way at all. They should never be wrapped in any #ifdefs.

You are describing YOUR DEVICE here. If your hardware can handle 64-bit
addresses when bus mastering, then you set Dma64BitAddresses to TRUE and
Dma32Bitaddresses to FALSE. If not, you set Dma64BitAddresses to FALSE,
and Dma32BitAddresses to TRUE. It's just that simple. Your hardware
doesn't change based on the operating system, so you will use the same
settings on every system.

My guess is that your device does NOT support 64-bit addressing, but on an
AMD64 system with more that 4G of RAM, you are saying that it does. That's
a recipe for disaster.
 
Hi Tim
Thanks for your reply.
My driver works well under Windows XP x64 operating system and 4G RAM
hardware platform, moreover, it works well under Windows Vista x64 operating
system and less than 4G RAM hardware platform, but can not work under
Windows Vista x64 operating system and 4G RAM hardware platform, the
hardware platform is the same.
In the case of Vista x64 operating system and 4G RAM, the driver succeed
to allocate DMA resource, but it can not receive the DMA interrupt.That is
make me confused.

Regards
 
The first thing that I find odd is that you only support 64 bit addresses if
the system supports them. Why is that? Does your card change to only
supporting 32-bit addressing if it's running on an X86 machine? Do you not
support an x86 machine with > 4GB of memory?

What error are you seeing and where are you seeing it come from?

-p
 
Hi Peter
I remove the #ifdef, as the following

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

The driver can receive the DMA interrupt, but the DMA buffer the driver
received is not the correct data.

The ASIC team analyzed the DMA transfer processing via logic analyzer on
Vista x64 and 4G RAM platform, they proved that the DMA chipsets transferred
correct package by the physical address and length which the driver wrote
into the DMA controller registers.

This modified driver(remove the #ifdef) can work well on Vista x64 and
less than 4G RAM platform, also work well on Windows XP x64 and 4G platform.


It looks as if this problem results from the driver, but I don't know the
difference of DMA transfer between Vista x64 and XP x64.

The following codes are about initializing DMA transfer.

//allocate DMA resource
#define TABLE_SIZE 0x8000

StartDevice()
{
...
...
DEVICE_DESCRIPTION desc;

RtlZeroMemory(&desc, sizeof(DEVICE_DESCRIPTION));

desc.Version = DEVICE_DESCRIPTION_VERSION;

desc.DmaChannel = ((ULONG) ~0);

desc.InterfaceType = PCIBus;

desc.DmaWidth = Width32Bits;

desc.DmaSpeed = Compatible;

desc.ScatterGather = TRUE;

desc.Master = TRUE;

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

desc.AutoInitialize = FALSE;

desc.MaximumLength = (ULONG) -1;

m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;

m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,

&desc,


&m_MaxMapRegisters);

m_MaxMapRegisters=(TABLE_SIZE)/8;

if (m_pDMAObject == NULL)

{

KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

////Allocate DMA Table memory!

For (index = 0; index < DMA_INT_CNT; index++)

{

m_DMAPara[index].KsDMA_Table_VA =
(PULONG)(m_pDMAObject->DmaOperations)->

AllocateCommonBuffer(m_pDMAObject,

TABLE_SIZE,


&m_DMAPara[index].KsDMA_Table_PA,

FALSE);

if(m_DMAPara[index].KsDMA_Table_VA == NULL)

{

KdPrint(("@@@Allocate DMA%d Table
Fail!\n",index));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;

}

..

..

}



NTSTATUS KS_InitDMA ()

{

m_DMAPara[index].KspDMABuf = (PBYTE)ExAllocatePoolWithTag(

NonPagedPool,

m_DMAPara[index].KsdwDMABufSize,

'MpaM');

if(m_DMAPara[index].KspDMABuf == NULL)

{

KdPrint(("@@@KS_InitDMA%d List:Allocate DMA buffer memory
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;;

}

//Allocate an MDL

m_DMAPara[index].KspMDL = IoAllocateMdl(

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

FALSE,

FALSE,

NULL);

if(m_DMAPara[index].KspMDL == NULL)

{

ExFreePool(m_DMAPara[index].KspDMABuf);

m_DMAPara[index].KspDMABuf=NULL;

KdPrint(("@@@KS_InitDMA%d List:Allocate MDL
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;

}

//Build the MDL to describe the memory pages

MmBuildMdlForNonPagedPool(m_DMAPara[index].KspMDL);

//scathergather list

return KS_DmaProgramTransfer(index);

}



NTSTATUS KS_DmaProgramTransfer(int index)

{

NTSTATUS ntStatus=STATUS_SUCCESS;

KIRQL oldIrql;

KdPrint(("KS_DmaProgramTransfer: DMA%d!\n",index));

//KeFlushIoBuffers(m_DMAPara[index].KspMDL, TRUE, TRUE);

//Get ScatterGather resource!

m_KsDmaCallContext.pKSDevice=m_pKSDevice;

m_KsDmaCallContext.index=index;

KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

ntStatus=m_pDMAObject->DmaOperations->GetScatterGatherList(

m_pDMAObject,

m_pKSDevice->FunctionalDeviceObject,

m_DMAPara[index].KspMDL,

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

KS_DmaCallBack,

&m_KsDmaCallContext,

FALSE

);

KdPrint(("GetScatterGatherList Status = 0x%X \n", ntStatus));

//ntStatus = STATUS_INSUFFICIENT_RESOURCES;

KeLowerIrql(oldIrql);

////////////////////////////////////////////

return ntStatus;

}



KS_DmaCallBack()

{

m_DMAPara[index].ScatterGatherList=ScatterGatherList;

ULONG TotalPages=ScatterGatherList->NumberOfElements;

if(TotalPages>m_MaxMapRegisters)

{

TotalPages=m_MaxMapRegisters;

KdPrint(("@@@Error: The DMA buffer PageCnt is too
large>m_MaxMapRegisters!\n"));

}

KdPrint(("TotalPages=%d\n",TotalPages));

for(unsigned long i=0;i<TotalPages;++i)

{

m_DMAPara[index].KsDMA_Table_VA[2*i]=

ScatterGatherList->Elements.Address.LowPart;

m_DMAPara[index].KsDMA_Table_VA[2*i+1]=

(ScatterGatherList->Elements.Length >> 2);

KdPrint(("ScatterGatherList->Elements[%d].Address 0x%X
\n",

i,
ScatterGatherList->Elements.Address.LowPart));

KdPrint(("ScatterGatherList->Elements.Length 0x%X \n",


i, ScatterGatherList->Elements.Length));

}

m_DMAPara[index].KsTotalEntry=TotalPages;

m_DMAPara[index].KsdwCurDMAUsed=0;

}

calling GetScatterGatherList failed, return STATUS_INSUFFICIENT_RESOURCES.

Thanks
Regards

Leon

Peter Wieland said:
The first thing that I find odd is that you only support 64 bit addresses
if the system supports them. Why is that? Does your card change to only
supporting 32-bit addressing if it's running on an X86 machine? Do you
not support an x86 machine with > 4GB of memory?

What error are you seeing and where are you seeing it come from?

-p

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Leon Huang said:
Hi
I writed a BDA driver for a PCI TV card device,I found that my driver
can work well on Vista32/XP32/XPx64 + 4GRAM platform, and work well on
Vista x64 + less than 4G RAM, but can't work on Vista x64 + 4G RAM, this
problem make me confused. I guess that this problem maybe result from the
DMA addressing in Vista x64, or MS change the DMA addressing in Vista x64
after XP x64,so,the DMA configuration of my driver doesn't compatible
with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical
addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif
desc.AutoInitialize = FALSE;
desc.MaximumLength = (ULONG) -1;
m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;
m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,
&desc,
&m_MaxMapRegisters);
m_MaxMapRegisters=(TABLE_SIZE)/8;
KdPrint(("DMA MaxMap Cnt=%d\n",m_MaxMapRegisters));
if(!m_pDMAObject)
{
KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
////Allocate DMA Table memory!
for(index=0;index<DMA_INT_CNT;index++)
{
m_DMAPara[index].KsDMA_Table_VA=(PULONG)(m_pDMAObject->DmaOperations)->
AllocateCommonBuffer(m_pDMAObject,
TABLE_SIZE,
&m_DMAPara[index].KsDMA_Table_PA,
FALSE);
if(!m_DMAPara[index].KsDMA_Table_VA)
{
KdPrint(("@@@Allocate DMA%d Table Fail!\n",index));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;
}

can you give me a idea?

thanks

best regards

Leon Huang
 
There is no such thing as "DMA interrupt".

DMA is one thing, interrupt is another, and the association between them is
only logical and not hardwired in any CPU/motherboard chip, nor coded in
kernel/HAL.

So, look at your interrupt code in the driver and the interrupt logic in
the hardware, DMA is OK.

--
Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
(e-mail address removed)
http://www.storagecraft.com

Leon Huang said:
Hi Peter
I remove the #ifdef, as the following

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

The driver can receive the DMA interrupt, but the DMA buffer the driver
received is not the correct data.

The ASIC team analyzed the DMA transfer processing via logic analyzer on
Vista x64 and 4G RAM platform, they proved that the DMA chipsets transferred
correct package by the physical address and length which the driver wrote
into the DMA controller registers.

This modified driver(remove the #ifdef) can work well on Vista x64 and
less than 4G RAM platform, also work well on Windows XP x64 and 4G platform.


It looks as if this problem results from the driver, but I don't know the
difference of DMA transfer between Vista x64 and XP x64.

The following codes are about initializing DMA transfer.

//allocate DMA resource
#define TABLE_SIZE 0x8000

StartDevice()
{
...
...
DEVICE_DESCRIPTION desc;

RtlZeroMemory(&desc, sizeof(DEVICE_DESCRIPTION));

desc.Version = DEVICE_DESCRIPTION_VERSION;

desc.DmaChannel = ((ULONG) ~0);

desc.InterfaceType = PCIBus;

desc.DmaWidth = Width32Bits;

desc.DmaSpeed = Compatible;

desc.ScatterGather = TRUE;

desc.Master = TRUE;

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

desc.AutoInitialize = FALSE;

desc.MaximumLength = (ULONG) -1;

m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;

m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,

&desc,


&m_MaxMapRegisters);

m_MaxMapRegisters=(TABLE_SIZE)/8;

if (m_pDMAObject == NULL)

{

KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

////Allocate DMA Table memory!

For (index = 0; index < DMA_INT_CNT; index++)

{

m_DMAPara[index].KsDMA_Table_VA =
(PULONG)(m_pDMAObject->DmaOperations)->

AllocateCommonBuffer(m_pDMAObject,

TABLE_SIZE,


&m_DMAPara[index].KsDMA_Table_PA,

FALSE);

if(m_DMAPara[index].KsDMA_Table_VA == NULL)

{

KdPrint(("@@@Allocate DMA%d Table
Fail!\n",index));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;

}

..

..

}



NTSTATUS KS_InitDMA ()

{

m_DMAPara[index].KspDMABuf = (PBYTE)ExAllocatePoolWithTag(

NonPagedPool,

m_DMAPara[index].KsdwDMABufSize,

'MpaM');

if(m_DMAPara[index].KspDMABuf == NULL)

{

KdPrint(("@@@KS_InitDMA%d List:Allocate DMA buffer memory
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;;

}

//Allocate an MDL

m_DMAPara[index].KspMDL = IoAllocateMdl(

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

FALSE,

FALSE,

NULL);

if(m_DMAPara[index].KspMDL == NULL)

{

ExFreePool(m_DMAPara[index].KspDMABuf);

m_DMAPara[index].KspDMABuf=NULL;

KdPrint(("@@@KS_InitDMA%d List:Allocate MDL
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;

}

//Build the MDL to describe the memory pages

MmBuildMdlForNonPagedPool(m_DMAPara[index].KspMDL);

//scathergather list

return KS_DmaProgramTransfer(index);

}



NTSTATUS KS_DmaProgramTransfer(int index)

{

NTSTATUS ntStatus=STATUS_SUCCESS;

KIRQL oldIrql;

KdPrint(("KS_DmaProgramTransfer: DMA%d!\n",index));

//KeFlushIoBuffers(m_DMAPara[index].KspMDL, TRUE, TRUE);

//Get ScatterGather resource!

m_KsDmaCallContext.pKSDevice=m_pKSDevice;

m_KsDmaCallContext.index=index;

KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

ntStatus=m_pDMAObject->DmaOperations->GetScatterGatherList(

m_pDMAObject,

m_pKSDevice->FunctionalDeviceObject,

m_DMAPara[index].KspMDL,

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

KS_DmaCallBack,

&m_KsDmaCallContext,

FALSE

);

KdPrint(("GetScatterGatherList Status = 0x%X \n", ntStatus));

//ntStatus = STATUS_INSUFFICIENT_RESOURCES;

KeLowerIrql(oldIrql);

////////////////////////////////////////////

return ntStatus;

}



KS_DmaCallBack()

{

m_DMAPara[index].ScatterGatherList=ScatterGatherList;

ULONG TotalPages=ScatterGatherList->NumberOfElements;

if(TotalPages>m_MaxMapRegisters)

{

TotalPages=m_MaxMapRegisters;

KdPrint(("@@@Error: The DMA buffer PageCnt is too
large>m_MaxMapRegisters!\n"));

}

KdPrint(("TotalPages=%d\n",TotalPages));

for(unsigned long i=0;i<TotalPages;++i)

{

m_DMAPara[index].KsDMA_Table_VA[2*i]=

ScatterGatherList->Elements.Address.LowPart;

m_DMAPara[index].KsDMA_Table_VA[2*i+1]=

(ScatterGatherList->Elements.Length >> 2);

KdPrint(("ScatterGatherList->Elements[%d].Address 0x%X
\n",

i,
ScatterGatherList->Elements.Address.LowPart));

KdPrint(("ScatterGatherList->Elements.Length 0x%X \n",


i, ScatterGatherList->Elements.Length));

}

m_DMAPara[index].KsTotalEntry=TotalPages;

m_DMAPara[index].KsdwCurDMAUsed=0;

}

calling GetScatterGatherList failed, return STATUS_INSUFFICIENT_RESOURCES.

Thanks
Regards

Leon

Peter Wieland said:
The first thing that I find odd is that you only support 64 bit addresses
if the system supports them. Why is that? Does your card change to only
supporting 32-bit addressing if it's running on an X86 machine? Do you
not support an x86 machine with > 4GB of memory?

What error are you seeing and where are you seeing it come from?

-p

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Leon Huang said:
Hi
I writed a BDA driver for a PCI TV card device,I found that my driver
can work well on Vista32/XP32/XPx64 + 4GRAM platform, and work well on
Vista x64 + less than 4G RAM, but can't work on Vista x64 + 4G RAM, this
problem make me confused. I guess that this problem maybe result from the
DMA addressing in Vista x64, or MS change the DMA addressing in Vista x64
after XP x64,so,the DMA configuration of my driver doesn't compatible
with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical
addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif
desc.AutoInitialize = FALSE;
desc.MaximumLength = (ULONG) -1;
m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;
m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,
&desc,
&m_MaxMapRegisters);
m_MaxMapRegisters=(TABLE_SIZE)/8;
KdPrint(("DMA MaxMap Cnt=%d\n",m_MaxMapRegisters));
if(!m_pDMAObject)
{
KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
////Allocate DMA Table memory!
for(index=0;index<DMA_INT_CNT;index++)
{
m_DMAPara[index].KsDMA_Table_VA=(PULONG)(m_pDMAObject->DmaOperations)->
AllocateCommonBuffer(m_pDMAObject,
TABLE_SIZE,
&m_DMAPara[index].KsDMA_Table_PA,
FALSE);
if(!m_DMAPara[index].KsDMA_Table_VA)
{
KdPrint(("@@@Allocate DMA%d Table Fail!\n",index));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;
}

can you give me a idea?

thanks

best regards

Leon Huang
 
My concern was that I would think your driver should ALWAYS say that it can
do 64-bit DMA since your hardware can apparently handle it.

If you say that you do 32-bit DMA on a 64-bit system then you'll be double
buffering. In that case you won't see the right data for the DMA transfer
show up in KspDMABuf until after you call PutScatterGatherList at the end of
the transfer. Did you wait until after calling PutScatterGatherList (after
the completion of the DMA transfer) before checking to see if you had the
right data?

GetScatterGatherList would return that error if you ask it to map more pages
than the number of map registers you got back from GetDmaAdapter. I notice
you don't bother to check that number until after the GetScatterGatherList
callback ... how many map registers are you getting and how does it compare
to the size of your buffer?

There should not be that significant of a difference between DMA in Server
2003 (or XP 64 bit) and Vista.

--
This posting is provided "AS IS" with no warranties, and confers no rights.


Leon Huang said:
Hi Peter
I remove the #ifdef, as the following

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

The driver can receive the DMA interrupt, but the DMA buffer the driver
received is not the correct data.

The ASIC team analyzed the DMA transfer processing via logic analyzer on
Vista x64 and 4G RAM platform, they proved that the DMA chipsets
transferred correct package by the physical address and length which the
driver wrote into the DMA controller registers.

This modified driver(remove the #ifdef) can work well on Vista x64 and
less than 4G RAM platform, also work well on Windows XP x64 and 4G
platform.


It looks as if this problem results from the driver, but I don't know the
difference of DMA transfer between Vista x64 and XP x64.

The following codes are about initializing DMA transfer.

//allocate DMA resource
#define TABLE_SIZE 0x8000

StartDevice()
{
...
...
DEVICE_DESCRIPTION desc;

RtlZeroMemory(&desc, sizeof(DEVICE_DESCRIPTION));

desc.Version = DEVICE_DESCRIPTION_VERSION;

desc.DmaChannel = ((ULONG) ~0);

desc.InterfaceType = PCIBus;

desc.DmaWidth = Width32Bits;

desc.DmaSpeed = Compatible;

desc.ScatterGather = TRUE;

desc.Master = TRUE;

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

desc.AutoInitialize = FALSE;

desc.MaximumLength = (ULONG) -1;

m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;

m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,

&desc,


&m_MaxMapRegisters);

m_MaxMapRegisters=(TABLE_SIZE)/8;

if (m_pDMAObject == NULL)

{

KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

////Allocate DMA Table memory!

For (index = 0; index < DMA_INT_CNT; index++)

{

m_DMAPara[index].KsDMA_Table_VA =
(PULONG)(m_pDMAObject->DmaOperations)->

AllocateCommonBuffer(m_pDMAObject,

TABLE_SIZE,


&m_DMAPara[index].KsDMA_Table_PA,

FALSE);

if(m_DMAPara[index].KsDMA_Table_VA == NULL)

{

KdPrint(("@@@Allocate DMA%d Table
Fail!\n",index));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;

}

..

..

}



NTSTATUS KS_InitDMA ()

{

m_DMAPara[index].KspDMABuf = (PBYTE)ExAllocatePoolWithTag(

NonPagedPool,

m_DMAPara[index].KsdwDMABufSize,

'MpaM');

if(m_DMAPara[index].KspDMABuf == NULL)

{

KdPrint(("@@@KS_InitDMA%d List:Allocate DMA buffer
memory Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;;

}

//Allocate an MDL

m_DMAPara[index].KspMDL = IoAllocateMdl(

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

FALSE,

FALSE,

NULL);

if(m_DMAPara[index].KspMDL == NULL)

{

ExFreePool(m_DMAPara[index].KspDMABuf);

m_DMAPara[index].KspDMABuf=NULL;

KdPrint(("@@@KS_InitDMA%d List:Allocate MDL
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;

}

//Build the MDL to describe the memory pages

MmBuildMdlForNonPagedPool(m_DMAPara[index].KspMDL);

//scathergather list

return KS_DmaProgramTransfer(index);

}



NTSTATUS KS_DmaProgramTransfer(int index)

{

NTSTATUS ntStatus=STATUS_SUCCESS;

KIRQL oldIrql;

KdPrint(("KS_DmaProgramTransfer: DMA%d!\n",index));

//KeFlushIoBuffers(m_DMAPara[index].KspMDL, TRUE, TRUE);

//Get ScatterGather resource!

m_KsDmaCallContext.pKSDevice=m_pKSDevice;

m_KsDmaCallContext.index=index;

KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

ntStatus=m_pDMAObject->DmaOperations->GetScatterGatherList(

m_pDMAObject,

m_pKSDevice->FunctionalDeviceObject,

m_DMAPara[index].KspMDL,

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

KS_DmaCallBack,

&m_KsDmaCallContext,

FALSE

);

KdPrint(("GetScatterGatherList Status = 0x%X \n", ntStatus));

//ntStatus = STATUS_INSUFFICIENT_RESOURCES;

KeLowerIrql(oldIrql);

////////////////////////////////////////////

return ntStatus;

}



KS_DmaCallBack()

{

m_DMAPara[index].ScatterGatherList=ScatterGatherList;

ULONG TotalPages=ScatterGatherList->NumberOfElements;

if(TotalPages>m_MaxMapRegisters)

{

TotalPages=m_MaxMapRegisters;

KdPrint(("@@@Error: The DMA buffer PageCnt is too
large>m_MaxMapRegisters!\n"));

}

KdPrint(("TotalPages=%d\n",TotalPages));

for(unsigned long i=0;i<TotalPages;++i)

{

m_DMAPara[index].KsDMA_Table_VA[2*i]=

ScatterGatherList->Elements.Address.LowPart;

m_DMAPara[index].KsDMA_Table_VA[2*i+1]=

(ScatterGatherList->Elements.Length >> 2);

KdPrint(("ScatterGatherList->Elements[%d].Address 0x%X
\n",

i,
ScatterGatherList->Elements.Address.LowPart));

KdPrint(("ScatterGatherList->Elements.Length 0x%X
\n",


i, ScatterGatherList->Elements.Length));

}

m_DMAPara[index].KsTotalEntry=TotalPages;

m_DMAPara[index].KsdwCurDMAUsed=0;

}

calling GetScatterGatherList failed, return STATUS_INSUFFICIENT_RESOURCES.

Thanks
Regards

Leon

Peter Wieland said:
The first thing that I find odd is that you only support 64 bit addresses
if the system supports them. Why is that? Does your card change to only
supporting 32-bit addressing if it's running on an X86 machine? Do you
not support an x86 machine with > 4GB of memory?

What error are you seeing and where are you seeing it come from?

-p

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Leon Huang said:
Hi
I writed a BDA driver for a PCI TV card device,I found that my driver
can work well on Vista32/XP32/XPx64 + 4GRAM platform, and work well on
Vista x64 + less than 4G RAM, but can't work on Vista x64 + 4G RAM, this
problem make me confused. I guess that this problem maybe result from
the DMA addressing in Vista x64, or MS change the DMA addressing in
Vista x64 after XP x64,so,the DMA configuration of my driver doesn't
compatible with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical
addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif
desc.AutoInitialize = FALSE;
desc.MaximumLength = (ULONG) -1;
m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;
m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,
&desc,
&m_MaxMapRegisters);
m_MaxMapRegisters=(TABLE_SIZE)/8;
KdPrint(("DMA MaxMap Cnt=%d\n",m_MaxMapRegisters));
if(!m_pDMAObject)
{
KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
////Allocate DMA Table memory!
for(index=0;index<DMA_INT_CNT;index++)
{
m_DMAPara[index].KsDMA_Table_VA=(PULONG)(m_pDMAObject->DmaOperations)->
AllocateCommonBuffer(m_pDMAObject,
TABLE_SIZE,
&m_DMAPara[index].KsDMA_Table_PA,
FALSE);
if(!m_DMAPara[index].KsDMA_Table_VA)
{
KdPrint(("@@@Allocate DMA%d Table Fail!\n",index));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;
}

can you give me a idea?

thanks

best regards

Leon Huang
 
Hi
my PCI DMA device only support 32bit addressing, so, the
Dma64BitAddresses must be FALSE.
On Vista x64 + 4G RAM platform, The DMA call GetScatterGatherList, the
ScatterGatherList->Elements[].Length is
0x1000(4 KB), all elements length are not more than 4 KB, but on Vista x64
+ 3G RAM platform, the ScatterGatherList->Elements[].Length is much large,
and the element is only one. Why is that?
I don't know how to handle double buffer 32bit DMA on Vista x64 OS.

Thanks
Regards
Leon
Peter Wieland said:
My concern was that I would think your driver should ALWAYS say that it
can do 64-bit DMA since your hardware can apparently handle it.

If you say that you do 32-bit DMA on a 64-bit system then you'll be double
buffering. In that case you won't see the right data for the DMA transfer
show up in KspDMABuf until after you call PutScatterGatherList at the end
of the transfer. Did you wait until after calling PutScatterGatherList
(after the completion of the DMA transfer) before checking to see if you
had the right data?

GetScatterGatherList would return that error if you ask it to map more
pages than the number of map registers you got back from GetDmaAdapter. I
notice you don't bother to check that number until after the
GetScatterGatherList callback ... how many map registers are you getting
and how does it compare to the size of your buffer?

There should not be that significant of a difference between DMA in Server
2003 (or XP 64 bit) and Vista.

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Leon Huang said:
Hi Peter
I remove the #ifdef, as the following

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

The driver can receive the DMA interrupt, but the DMA buffer the driver
received is not the correct data.

The ASIC team analyzed the DMA transfer processing via logic analyzer on
Vista x64 and 4G RAM platform, they proved that the DMA chipsets
transferred correct package by the physical address and length which the
driver wrote into the DMA controller registers.

This modified driver(remove the #ifdef) can work well on Vista x64 and
less than 4G RAM platform, also work well on Windows XP x64 and 4G
platform.


It looks as if this problem results from the driver, but I don't know the
difference of DMA transfer between Vista x64 and XP x64.

The following codes are about initializing DMA transfer.

//allocate DMA resource
#define TABLE_SIZE 0x8000

StartDevice()
{
...
...
DEVICE_DESCRIPTION desc;

RtlZeroMemory(&desc, sizeof(DEVICE_DESCRIPTION));

desc.Version = DEVICE_DESCRIPTION_VERSION;

desc.DmaChannel = ((ULONG) ~0);

desc.InterfaceType = PCIBus;

desc.DmaWidth = Width32Bits;

desc.DmaSpeed = Compatible;

desc.ScatterGather = TRUE;

desc.Master = TRUE;

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

desc.AutoInitialize = FALSE;

desc.MaximumLength = (ULONG) -1;

m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;

m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,

&desc,


&m_MaxMapRegisters);

m_MaxMapRegisters=(TABLE_SIZE)/8;

if (m_pDMAObject == NULL)

{

KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

////Allocate DMA Table memory!

For (index = 0; index < DMA_INT_CNT; index++)

{

m_DMAPara[index].KsDMA_Table_VA =
(PULONG)(m_pDMAObject->DmaOperations)->

AllocateCommonBuffer(m_pDMAObject,

TABLE_SIZE,


&m_DMAPara[index].KsDMA_Table_PA,

FALSE);

if(m_DMAPara[index].KsDMA_Table_VA == NULL)

{

KdPrint(("@@@Allocate DMA%d Table
Fail!\n",index));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;

}

..

..

}



NTSTATUS KS_InitDMA ()

{

m_DMAPara[index].KspDMABuf = (PBYTE)ExAllocatePoolWithTag(

NonPagedPool,

m_DMAPara[index].KsdwDMABufSize,

'MpaM');

if(m_DMAPara[index].KspDMABuf == NULL)

{

KdPrint(("@@@KS_InitDMA%d List:Allocate DMA buffer
memory Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;;

}

//Allocate an MDL

m_DMAPara[index].KspMDL = IoAllocateMdl(

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

FALSE,

FALSE,

NULL);

if(m_DMAPara[index].KspMDL == NULL)

{

ExFreePool(m_DMAPara[index].KspDMABuf);

m_DMAPara[index].KspDMABuf=NULL;

KdPrint(("@@@KS_InitDMA%d List:Allocate MDL
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;

}

//Build the MDL to describe the memory pages

MmBuildMdlForNonPagedPool(m_DMAPara[index].KspMDL);

//scathergather list

return KS_DmaProgramTransfer(index);

}



NTSTATUS KS_DmaProgramTransfer(int index)

{

NTSTATUS ntStatus=STATUS_SUCCESS;

KIRQL oldIrql;

KdPrint(("KS_DmaProgramTransfer: DMA%d!\n",index));

//KeFlushIoBuffers(m_DMAPara[index].KspMDL, TRUE, TRUE);

//Get ScatterGather resource!

m_KsDmaCallContext.pKSDevice=m_pKSDevice;

m_KsDmaCallContext.index=index;

KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

ntStatus=m_pDMAObject->DmaOperations->GetScatterGatherList(

m_pDMAObject,

m_pKSDevice->FunctionalDeviceObject,

m_DMAPara[index].KspMDL,

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

KS_DmaCallBack,

&m_KsDmaCallContext,

FALSE

);

KdPrint(("GetScatterGatherList Status = 0x%X \n", ntStatus));

//ntStatus = STATUS_INSUFFICIENT_RESOURCES;

KeLowerIrql(oldIrql);

////////////////////////////////////////////

return ntStatus;

}



KS_DmaCallBack()

{

m_DMAPara[index].ScatterGatherList=ScatterGatherList;

ULONG TotalPages=ScatterGatherList->NumberOfElements;

if(TotalPages>m_MaxMapRegisters)

{

TotalPages=m_MaxMapRegisters;

KdPrint(("@@@Error: The DMA buffer PageCnt is too
large>m_MaxMapRegisters!\n"));

}

KdPrint(("TotalPages=%d\n",TotalPages));

for(unsigned long i=0;i<TotalPages;++i)

{

m_DMAPara[index].KsDMA_Table_VA[2*i]=


ScatterGatherList->Elements.Address.LowPart;

m_DMAPara[index].KsDMA_Table_VA[2*i+1]=

(ScatterGatherList->Elements.Length >> 2);

KdPrint(("ScatterGatherList->Elements[%d].Address 0x%X
\n",

i,
ScatterGatherList->Elements.Address.LowPart));

KdPrint(("ScatterGatherList->Elements.Length 0x%X
\n",


i,
ScatterGatherList->Elements.Length));

}

m_DMAPara[index].KsTotalEntry=TotalPages;

m_DMAPara[index].KsdwCurDMAUsed=0;

}

calling GetScatterGatherList failed, return
STATUS_INSUFFICIENT_RESOURCES.

Thanks
Regards

Leon

Peter Wieland said:
The first thing that I find odd is that you only support 64 bit
addresses if the system supports them. Why is that? Does your card
change to only supporting 32-bit addressing if it's running on an X86
machine? Do you not support an x86 machine with > 4GB of memory?

What error are you seeing and where are you seeing it come from?

-p

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Hi
I writed a BDA driver for a PCI TV card device,I found that my driver
can work well on Vista32/XP32/XPx64 + 4GRAM platform, and work well on
Vista x64 + less than 4G RAM, but can't work on Vista x64 + 4G RAM,
this problem make me confused. I guess that this problem maybe result
from the DMA addressing in Vista x64, or MS change the DMA addressing
in Vista x64 after XP x64,so,the DMA configuration of my driver doesn't
compatible with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical
addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif
desc.AutoInitialize = FALSE;
desc.MaximumLength = (ULONG) -1;
m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;
m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,
&desc,
&m_MaxMapRegisters);
m_MaxMapRegisters=(TABLE_SIZE)/8;
KdPrint(("DMA MaxMap Cnt=%d\n",m_MaxMapRegisters));
if(!m_pDMAObject)
{
KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
////Allocate DMA Table memory!
for(index=0;index<DMA_INT_CNT;index++)
{

m_DMAPara[index].KsDMA_Table_VA=(PULONG)(m_pDMAObject->DmaOperations)->
AllocateCommonBuffer(m_pDMAObject,
TABLE_SIZE,
&m_DMAPara[index].KsDMA_Table_PA,
FALSE);
if(!m_DMAPara[index].KsDMA_Table_VA)
{
KdPrint(("@@@Allocate DMA%d Table Fail!\n",index));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;
}

can you give me a idea?

thanks

best regards

Leon Huang

 
Ah. I assumed way down below that you were setting Dma64BitAddresses
because your device supported them. If your device does not support them
then you should not set that flag. You will have to deal with double
buffering.

You see one large SG entry on the 64-bit OS because the OS is double
buffering your request into a single contiguous buffer. The original buffer
very likely included one or more physical addresses that were not
addressable by your controller.

If the double buffering provided by the OS results in requests that are too
small you could allocate some common buffer and double buffer the requests
yourself. Then you could control how large they were and how many to do at
one time.

Or update your device.

-p

--
This posting is provided "AS IS" with no warranties, and confers no rights.


Leon Huang said:
Hi
my PCI DMA device only support 32bit addressing, so, the
Dma64BitAddresses must be FALSE.
On Vista x64 + 4G RAM platform, The DMA call GetScatterGatherList, the
ScatterGatherList->Elements[].Length is
0x1000(4 KB), all elements length are not more than 4 KB, but on Vista
x64 + 3G RAM platform, the ScatterGatherList->Elements[].Length is much
large, and the element is only one. Why is that?
I don't know how to handle double buffer 32bit DMA on Vista x64 OS.

Thanks
Regards
Leon
Peter Wieland said:
My concern was that I would think your driver should ALWAYS say that it
can do 64-bit DMA since your hardware can apparently handle it.

If you say that you do 32-bit DMA on a 64-bit system then you'll be
double buffering. In that case you won't see the right data for the DMA
transfer show up in KspDMABuf until after you call PutScatterGatherList
at the end of the transfer. Did you wait until after calling
PutScatterGatherList (after the completion of the DMA transfer) before
checking to see if you had the right data?

GetScatterGatherList would return that error if you ask it to map more
pages than the number of map registers you got back from GetDmaAdapter.
I notice you don't bother to check that number until after the
GetScatterGatherList callback ... how many map registers are you getting
and how does it compare to the size of your buffer?

There should not be that significant of a difference between DMA in
Server 2003 (or XP 64 bit) and Vista.

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Leon Huang said:
Hi Peter
I remove the #ifdef, as the following

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

The driver can receive the DMA interrupt, but the DMA buffer the driver
received is not the correct data.

The ASIC team analyzed the DMA transfer processing via logic analyzer on
Vista x64 and 4G RAM platform, they proved that the DMA chipsets
transferred correct package by the physical address and length which the
driver wrote into the DMA controller registers.

This modified driver(remove the #ifdef) can work well on Vista x64
and less than 4G RAM platform, also work well on Windows XP x64 and 4G
platform.


It looks as if this problem results from the driver, but I don't know
the difference of DMA transfer between Vista x64 and XP x64.

The following codes are about initializing DMA transfer.

//allocate DMA resource
#define TABLE_SIZE 0x8000

StartDevice()
{
...
...
DEVICE_DESCRIPTION desc;

RtlZeroMemory(&desc, sizeof(DEVICE_DESCRIPTION));

desc.Version = DEVICE_DESCRIPTION_VERSION;

desc.DmaChannel = ((ULONG) ~0);

desc.InterfaceType = PCIBus;

desc.DmaWidth = Width32Bits;

desc.DmaSpeed = Compatible;

desc.ScatterGather = TRUE;

desc.Master = TRUE;

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

desc.AutoInitialize = FALSE;

desc.MaximumLength = (ULONG) -1;

m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;

m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,

&desc,


&m_MaxMapRegisters);

m_MaxMapRegisters=(TABLE_SIZE)/8;

if (m_pDMAObject == NULL)

{

KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

////Allocate DMA Table memory!

For (index = 0; index < DMA_INT_CNT; index++)

{

m_DMAPara[index].KsDMA_Table_VA =
(PULONG)(m_pDMAObject->DmaOperations)->

AllocateCommonBuffer(m_pDMAObject,

TABLE_SIZE,


&m_DMAPara[index].KsDMA_Table_PA,

FALSE);

if(m_DMAPara[index].KsDMA_Table_VA == NULL)

{

KdPrint(("@@@Allocate DMA%d Table
Fail!\n",index));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;

}

..

..

}



NTSTATUS KS_InitDMA ()

{

m_DMAPara[index].KspDMABuf = (PBYTE)ExAllocatePoolWithTag(

NonPagedPool,

m_DMAPara[index].KsdwDMABufSize,

'MpaM');

if(m_DMAPara[index].KspDMABuf == NULL)

{

KdPrint(("@@@KS_InitDMA%d List:Allocate DMA buffer
memory Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;;

}

//Allocate an MDL

m_DMAPara[index].KspMDL = IoAllocateMdl(

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

FALSE,

FALSE,

NULL);

if(m_DMAPara[index].KspMDL == NULL)

{

ExFreePool(m_DMAPara[index].KspDMABuf);

m_DMAPara[index].KspDMABuf=NULL;

KdPrint(("@@@KS_InitDMA%d List:Allocate MDL
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;

}

//Build the MDL to describe the memory pages

MmBuildMdlForNonPagedPool(m_DMAPara[index].KspMDL);

//scathergather list

return KS_DmaProgramTransfer(index);

}



NTSTATUS KS_DmaProgramTransfer(int index)

{

NTSTATUS ntStatus=STATUS_SUCCESS;

KIRQL oldIrql;

KdPrint(("KS_DmaProgramTransfer: DMA%d!\n",index));

//KeFlushIoBuffers(m_DMAPara[index].KspMDL, TRUE, TRUE);

//Get ScatterGather resource!

m_KsDmaCallContext.pKSDevice=m_pKSDevice;

m_KsDmaCallContext.index=index;

KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

ntStatus=m_pDMAObject->DmaOperations->GetScatterGatherList(

m_pDMAObject,

m_pKSDevice->FunctionalDeviceObject,

m_DMAPara[index].KspMDL,

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

KS_DmaCallBack,

&m_KsDmaCallContext,

FALSE

);

KdPrint(("GetScatterGatherList Status = 0x%X \n", ntStatus));

//ntStatus = STATUS_INSUFFICIENT_RESOURCES;

KeLowerIrql(oldIrql);

////////////////////////////////////////////

return ntStatus;

}



KS_DmaCallBack()

{

m_DMAPara[index].ScatterGatherList=ScatterGatherList;

ULONG TotalPages=ScatterGatherList->NumberOfElements;

if(TotalPages>m_MaxMapRegisters)

{

TotalPages=m_MaxMapRegisters;

KdPrint(("@@@Error: The DMA buffer PageCnt is too
large>m_MaxMapRegisters!\n"));

}

KdPrint(("TotalPages=%d\n",TotalPages));

for(unsigned long i=0;i<TotalPages;++i)

{

m_DMAPara[index].KsDMA_Table_VA[2*i]=


ScatterGatherList->Elements.Address.LowPart;

m_DMAPara[index].KsDMA_Table_VA[2*i+1]=

(ScatterGatherList->Elements.Length >> 2);

KdPrint(("ScatterGatherList->Elements[%d].Address 0x%X
\n",

i,
ScatterGatherList->Elements.Address.LowPart));

KdPrint(("ScatterGatherList->Elements.Length 0x%X
\n",


i,
ScatterGatherList->Elements.Length));

}

m_DMAPara[index].KsTotalEntry=TotalPages;

m_DMAPara[index].KsdwCurDMAUsed=0;

}

calling GetScatterGatherList failed, return
STATUS_INSUFFICIENT_RESOURCES.

Thanks
Regards

Leon

The first thing that I find odd is that you only support 64 bit
addresses if the system supports them. Why is that? Does your card
change to only supporting 32-bit addressing if it's running on an X86
machine? Do you not support an x86 machine with > 4GB of memory?

What error are you seeing and where are you seeing it come from?

-p

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Hi
I writed a BDA driver for a PCI TV card device,I found that my driver
can work well on Vista32/XP32/XPx64 + 4GRAM platform, and work well on
Vista x64 + less than 4G RAM, but can't work on Vista x64 + 4G RAM,
this problem make me confused. I guess that this problem maybe result
from the DMA addressing in Vista x64, or MS change the DMA addressing
in Vista x64 after XP x64,so,the DMA configuration of my driver
doesn't compatible with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical
addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif
desc.AutoInitialize = FALSE;
desc.MaximumLength = (ULONG) -1;
m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;
m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,
&desc,
&m_MaxMapRegisters);
m_MaxMapRegisters=(TABLE_SIZE)/8;
KdPrint(("DMA MaxMap Cnt=%d\n",m_MaxMapRegisters));
if(!m_pDMAObject)
{
KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
////Allocate DMA Table memory!
for(index=0;index<DMA_INT_CNT;index++)
{

m_DMAPara[index].KsDMA_Table_VA=(PULONG)(m_pDMAObject->DmaOperations)->
AllocateCommonBuffer(m_pDMAObject,
TABLE_SIZE,
&m_DMAPara[index].KsDMA_Table_PA,
FALSE);
if(!m_DMAPara[index].KsDMA_Table_VA)
{
KdPrint(("@@@Allocate DMA%d Table Fail!\n",index));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;
}

can you give me a idea?

thanks

best regards

Leon Huang


 
Hi Peter
If the driver call AllocateCommonBuffer to allocate a continuous
physical memory, the driver use this block physical buffer for receiving the
data from DMA device, in this case, the driver work well on Vista x64 + 4G
(or more than) platform. However, the driver doesn't work via scatter/gather
way. I think this may be resulted from that, the DMA device is 32 bits
addressing, the Dma64BitAddresses flag is FALSE, when calling
GetScatterGatherList, the system may allocate physical memory beyond 4G
space, so, the system may use double buffer for supporting it.
if the driver is in Scatter/Gather way, how can make Scatter/Gather
work well on Vista x64 + 4G platform.

Thanks
Regards


Peter Wieland said:
Ah. I assumed way down below that you were setting Dma64BitAddresses
because your device supported them. If your device does not support them
then you should not set that flag. You will have to deal with double
buffering.

You see one large SG entry on the 64-bit OS because the OS is double
buffering your request into a single contiguous buffer. The original
buffer very likely included one or more physical addresses that were not
addressable by your controller.

If the double buffering provided by the OS results in requests that are
too small you could allocate some common buffer and double buffer the
requests yourself. Then you could control how large they were and how
many to do at one time.

Or update your device.

-p

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Leon Huang said:
Hi
my PCI DMA device only support 32bit addressing, so, the
Dma64BitAddresses must be FALSE.
On Vista x64 + 4G RAM platform, The DMA call GetScatterGatherList, the
ScatterGatherList->Elements[].Length is
0x1000(4 KB), all elements length are not more than 4 KB, but on Vista
x64 + 3G RAM platform, the ScatterGatherList->Elements[].Length is much
large, and the element is only one. Why is that?
I don't know how to handle double buffer 32bit DMA on Vista x64 OS.

Thanks
Regards
Leon
Peter Wieland said:
My concern was that I would think your driver should ALWAYS say that it
can do 64-bit DMA since your hardware can apparently handle it.

If you say that you do 32-bit DMA on a 64-bit system then you'll be
double buffering. In that case you won't see the right data for the DMA
transfer show up in KspDMABuf until after you call PutScatterGatherList
at the end of the transfer. Did you wait until after calling
PutScatterGatherList (after the completion of the DMA transfer) before
checking to see if you had the right data?

GetScatterGatherList would return that error if you ask it to map more
pages than the number of map registers you got back from GetDmaAdapter.
I notice you don't bother to check that number until after the
GetScatterGatherList callback ... how many map registers are you getting
and how does it compare to the size of your buffer?

There should not be that significant of a difference between DMA in
Server 2003 (or XP 64 bit) and Vista.

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Hi Peter
I remove the #ifdef, as the following

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

The driver can receive the DMA interrupt, but the DMA buffer the driver
received is not the correct data.

The ASIC team analyzed the DMA transfer processing via logic analyzer
on Vista x64 and 4G RAM platform, they proved that the DMA chipsets
transferred correct package by the physical address and length which
the driver wrote into the DMA controller registers.

This modified driver(remove the #ifdef) can work well on Vista x64
and less than 4G RAM platform, also work well on Windows XP x64 and 4G
platform.


It looks as if this problem results from the driver, but I don't know
the difference of DMA transfer between Vista x64 and XP x64.

The following codes are about initializing DMA transfer.

//allocate DMA resource
#define TABLE_SIZE 0x8000

StartDevice()
{
...
...
DEVICE_DESCRIPTION desc;

RtlZeroMemory(&desc, sizeof(DEVICE_DESCRIPTION));

desc.Version = DEVICE_DESCRIPTION_VERSION;

desc.DmaChannel = ((ULONG) ~0);

desc.InterfaceType = PCIBus;

desc.DmaWidth = Width32Bits;

desc.DmaSpeed = Compatible;

desc.ScatterGather = TRUE;

desc.Master = TRUE;

desc.Dma64BitAddresses = FALSE;

desc.Dma32BitAddresses = TRUE;

desc.AutoInitialize = FALSE;

desc.MaximumLength = (ULONG) -1;

m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;

m_pDMAObject = IoGetDmaAdapter(
pKSDevice->PhysicalDeviceObject,

&desc,


&m_MaxMapRegisters);

m_MaxMapRegisters=(TABLE_SIZE)/8;

if (m_pDMAObject == NULL)

{

KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

////Allocate DMA Table memory!

For (index = 0; index < DMA_INT_CNT; index++)

{

m_DMAPara[index].KsDMA_Table_VA =
(PULONG)(m_pDMAObject->DmaOperations)->

AllocateCommonBuffer(m_pDMAObject,


TABLE_SIZE,


&m_DMAPara[index].KsDMA_Table_PA,

FALSE);

if(m_DMAPara[index].KsDMA_Table_VA == NULL)

{

KdPrint(("@@@Allocate DMA%d Table
Fail!\n",index));

CleanUpResources();

return STATUS_INSUFFICIENT_RESOURCES;

}

m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;

}

..

..

}



NTSTATUS KS_InitDMA ()

{

m_DMAPara[index].KspDMABuf = (PBYTE)ExAllocatePoolWithTag(

NonPagedPool,

m_DMAPara[index].KsdwDMABufSize,

'MpaM');

if(m_DMAPara[index].KspDMABuf == NULL)

{

KdPrint(("@@@KS_InitDMA%d List:Allocate DMA buffer
memory Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;;

}

//Allocate an MDL

m_DMAPara[index].KspMDL = IoAllocateMdl(

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

FALSE,

FALSE,

NULL);

if(m_DMAPara[index].KspMDL == NULL)

{

ExFreePool(m_DMAPara[index].KspDMABuf);

m_DMAPara[index].KspDMABuf=NULL;

KdPrint(("@@@KS_InitDMA%d List:Allocate MDL
Fail!\n",index));

return STATUS_INSUFFICIENT_RESOURCES;

}

//Build the MDL to describe the memory pages

MmBuildMdlForNonPagedPool(m_DMAPara[index].KspMDL);

//scathergather list

return KS_DmaProgramTransfer(index);

}



NTSTATUS KS_DmaProgramTransfer(int index)

{

NTSTATUS ntStatus=STATUS_SUCCESS;

KIRQL oldIrql;

KdPrint(("KS_DmaProgramTransfer: DMA%d!\n",index));

//KeFlushIoBuffers(m_DMAPara[index].KspMDL, TRUE, TRUE);

//Get ScatterGather resource!

m_KsDmaCallContext.pKSDevice=m_pKSDevice;

m_KsDmaCallContext.index=index;

KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

ntStatus=m_pDMAObject->DmaOperations->GetScatterGatherList(

m_pDMAObject,

m_pKSDevice->FunctionalDeviceObject,

m_DMAPara[index].KspMDL,

m_DMAPara[index].KspDMABuf,

m_DMAPara[index].KsdwDMABufSize,

KS_DmaCallBack,

&m_KsDmaCallContext,

FALSE

);

KdPrint(("GetScatterGatherList Status = 0x%X \n", ntStatus));

//ntStatus = STATUS_INSUFFICIENT_RESOURCES;

KeLowerIrql(oldIrql);

////////////////////////////////////////////

return ntStatus;

}



KS_DmaCallBack()

{

m_DMAPara[index].ScatterGatherList=ScatterGatherList;

ULONG TotalPages=ScatterGatherList->NumberOfElements;

if(TotalPages>m_MaxMapRegisters)

{

TotalPages=m_MaxMapRegisters;

KdPrint(("@@@Error: The DMA buffer PageCnt is too
large>m_MaxMapRegisters!\n"));

}

KdPrint(("TotalPages=%d\n",TotalPages));

for(unsigned long i=0;i<TotalPages;++i)

{

m_DMAPara[index].KsDMA_Table_VA[2*i]=


ScatterGatherList->Elements.Address.LowPart;

m_DMAPara[index].KsDMA_Table_VA[2*i+1]=

(ScatterGatherList->Elements.Length >>
2);

KdPrint(("ScatterGatherList->Elements[%d].Address
0x%X \n",

i,
ScatterGatherList->Elements.Address.LowPart));

KdPrint(("ScatterGatherList->Elements.Length 0x%X
\n",


i,
ScatterGatherList->Elements.Length));

}

m_DMAPara[index].KsTotalEntry=TotalPages;

m_DMAPara[index].KsdwCurDMAUsed=0;

}

calling GetScatterGatherList failed, return
STATUS_INSUFFICIENT_RESOURCES.

Thanks
Regards

Leon

The first thing that I find odd is that you only support 64 bit
addresses if the system supports them. Why is that? Does your card
change to only supporting 32-bit addressing if it's running on an X86
machine? Do you not support an x86 machine with > 4GB of memory?

What error are you seeing and where are you seeing it come from?

-p

--
This posting is provided "AS IS" with no warranties, and confers no
rights.


Hi
I writed a BDA driver for a PCI TV card device,I found that my
driver can work well on Vista32/XP32/XPx64 + 4GRAM platform, and work
well on Vista x64 + less than 4G RAM, but can't work on Vista x64 +
4G RAM, this problem make me confused. I guess that this problem
maybe result from the DMA addressing in Vista x64, or MS change the
DMA addressing in Vista x64 after XP x64,so,the DMA configuration of
my driver doesn't compatible with Vista x64.
the following codes is config DMA.

#if defined(_AMD64_)||defined(_IA64_)
if (Mm64BitPhysicalAddress) //if system support 64-bit physical
addressing
{
desc.Dma64BitAddresses = TRUE;
desc.Dma32BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is TRUE \n"));
}
else
{
desc.Dma32BitAddresses = TRUE;
desc.Dma64BitAddresses = FALSE;
KdPrint(("Mm64BitPhysicalAddress is FALSE \n"));
}
#else
desc.Dma64BitAddresses = FALSE;
desc.Dma32BitAddresses = TRUE;
#endif
desc.AutoInitialize = FALSE;
desc.MaximumLength = (ULONG) -1;
m_MaxMapRegisters = (desc.MaximumLength / PAGE_SIZE) + 1;
m_pDMAObject = IoGetDmaAdapter( pKSDevice->PhysicalDeviceObject,
&desc,
&m_MaxMapRegisters);
m_MaxMapRegisters=(TABLE_SIZE)/8;
KdPrint(("DMA MaxMap Cnt=%d\n",m_MaxMapRegisters));
if(!m_pDMAObject)
{
KdPrint(("@@@Couldn't GetDMA adapter resource!\n"));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
////Allocate DMA Table memory!
for(index=0;index<DMA_INT_CNT;index++)
{

m_DMAPara[index].KsDMA_Table_VA=(PULONG)(m_pDMAObject->DmaOperations)->
AllocateCommonBuffer(m_pDMAObject,
TABLE_SIZE,
&m_DMAPara[index].KsDMA_Table_PA,
FALSE);
if(!m_DMAPara[index].KsDMA_Table_VA)
{
KdPrint(("@@@Allocate DMA%d Table Fail!\n",index));
CleanUpResources();
return STATUS_INSUFFICIENT_RESOURCES;
}
m_DMAPara[index].KsdwDMATableSize=TABLE_SIZE;
}

can you give me a idea?

thanks

best regards

Leon Huang

 
Back
Top