756 lines
22 KiB
C
756 lines
22 KiB
C
|
/*++
|
||
|
Copyright (c) 1992 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
dma.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Jameel Hyder (jameelh) 02-Apr-1998
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode, FSD
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
02-Apr-1998 JameelH Initial version
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include <precomp.h>
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//
|
||
|
// Define the module number for debug code.
|
||
|
//
|
||
|
#define MODULE_NUMBER MODULE_DMA
|
||
|
|
||
|
NDIS_STATUS
|
||
|
NdisMInitializeScatterGatherDma(
|
||
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
||
|
IN BOOLEAN Dma64BitAddresses,
|
||
|
IN ULONG MaximumPhysicalMapping
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Allocates adapter channel for bus mastering devices.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
|
||
|
DEVICE_DESCRIPTION DeviceDescription;
|
||
|
ULONG MapRegisters, SGMapRegsisters;
|
||
|
NDIS_STATUS Status = NDIS_STATUS_NOT_SUPPORTED;
|
||
|
NTSTATUS NtStatus;
|
||
|
ULONG ScatterGatherListSize;
|
||
|
BOOLEAN DereferenceDmaAdapter = FALSE;
|
||
|
BOOLEAN FreeSGListLookasideList = FALSE;
|
||
|
|
||
|
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
||
|
("==>NdisMInitializeScatterGatherDma: Miniport %lx, Dma64BitAddresses %lx, MaximumPhysicalMapping 0x%lx\n",
|
||
|
Miniport, Dma64BitAddresses, MaximumPhysicalMapping));
|
||
|
|
||
|
do
|
||
|
{
|
||
|
if (!MINIPORT_TEST_FLAGS(Miniport, fMINIPORT_IS_NDIS_5 | fMINIPORT_BUS_MASTER))
|
||
|
{
|
||
|
Status = NDIS_STATUS_NOT_SUPPORTED;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (MINIPORT_VERIFY_TEST_FLAG(Miniport, fMINIPORT_VERIFY_FAIL_INIT_SG))
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
NdisZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION));
|
||
|
|
||
|
DeviceDescription.Master = TRUE;
|
||
|
DeviceDescription.ScatterGather = TRUE;
|
||
|
|
||
|
DeviceDescription.BusNumber = Miniport->BusNumber;
|
||
|
DeviceDescription.DmaChannel = 0;
|
||
|
DeviceDescription.InterfaceType = Miniport->AdapterType;
|
||
|
|
||
|
if (Dma64BitAddresses)
|
||
|
{
|
||
|
DeviceDescription.Dma32BitAddresses = FALSE;
|
||
|
DeviceDescription.Dma64BitAddresses = TRUE;
|
||
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_64BITS_DMA);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DeviceDescription.Dma32BitAddresses = TRUE;
|
||
|
DeviceDescription.Dma64BitAddresses = FALSE;
|
||
|
}
|
||
|
|
||
|
if (((MaximumPhysicalMapping * 2 - 2) / PAGE_SIZE) + 2 < Miniport->SGMapRegistersNeeded)
|
||
|
{
|
||
|
DeviceDescription.MaximumLength = (Miniport->SGMapRegistersNeeded - 1) << PAGE_SHIFT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DeviceDescription.MaximumLength = MaximumPhysicalMapping*2;
|
||
|
}
|
||
|
|
||
|
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION2;
|
||
|
|
||
|
//
|
||
|
// Get the adapter object.
|
||
|
//
|
||
|
Miniport->SystemAdapterObject = IoGetDmaAdapter(Miniport->PhysicalDeviceObject,
|
||
|
&DeviceDescription,
|
||
|
&MapRegisters);
|
||
|
|
||
|
|
||
|
if (Miniport->SystemAdapterObject == NULL)
|
||
|
{
|
||
|
NdisWriteErrorLogEntry((NDIS_HANDLE)Miniport,
|
||
|
NDIS_ERROR_CODE_OUT_OF_RESOURCES,
|
||
|
1,
|
||
|
0xFFFFFFFF);
|
||
|
|
||
|
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_ERR,
|
||
|
("NdisMInitializeScatterGatherDma: Miniport %lx, IoGetDmaAdapter failed\n", Miniport));
|
||
|
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
||
|
("NdisMInitializeScatterGatherDma: Miniport %lx, MapRegisters 0x%lx\n", Miniport, MapRegisters));
|
||
|
|
||
|
InterlockedIncrement(&Miniport->DmaAdapterRefCount);
|
||
|
|
||
|
DereferenceDmaAdapter = TRUE;
|
||
|
|
||
|
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
|
||
|
{
|
||
|
Miniport->SendCompleteHandler = ndisMSendCompleteSG;
|
||
|
}
|
||
|
|
||
|
Miniport->SGListLookasideList = (PNPAGED_LOOKASIDE_LIST)ALLOC_FROM_POOL(sizeof(NPAGED_LOOKASIDE_LIST), NDIS_TAG_DMA);
|
||
|
|
||
|
if (Miniport->SGListLookasideList == NULL)
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
FreeSGListLookasideList = TRUE;
|
||
|
|
||
|
NtStatus = Miniport->SystemAdapterObject->DmaOperations->CalculateScatterGatherList(
|
||
|
Miniport->SystemAdapterObject,
|
||
|
NULL,
|
||
|
0,
|
||
|
MapRegisters * PAGE_SIZE,
|
||
|
&ScatterGatherListSize,
|
||
|
&SGMapRegsisters);
|
||
|
|
||
|
ASSERT(NT_SUCCESS(NtStatus));
|
||
|
ASSERT(SGMapRegsisters == MapRegisters);
|
||
|
|
||
|
if (!NT_SUCCESS(NtStatus))
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Miniport->ScatterGatherListSize = ScatterGatherListSize;
|
||
|
|
||
|
ExInitializeNPagedLookasideList(Miniport->SGListLookasideList,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0,
|
||
|
ScatterGatherListSize,
|
||
|
NDIS_TAG_DMA,
|
||
|
0);
|
||
|
|
||
|
Status = NDIS_STATUS_SUCCESS;
|
||
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_SG_LIST);
|
||
|
Miniport->InfoFlags |= NDIS_MINIPORT_SG_LIST;
|
||
|
|
||
|
DereferenceDmaAdapter = FALSE;
|
||
|
FreeSGListLookasideList = FALSE;
|
||
|
|
||
|
}while (FALSE);
|
||
|
|
||
|
|
||
|
if (DereferenceDmaAdapter)
|
||
|
{
|
||
|
ndisDereferenceDmaAdapter(Miniport);
|
||
|
}
|
||
|
|
||
|
if (FreeSGListLookasideList && Miniport->SGListLookasideList)
|
||
|
{
|
||
|
ExDeleteNPagedLookasideList(Miniport->SGListLookasideList);
|
||
|
FREE_POOL(Miniport->SGListLookasideList);
|
||
|
Miniport->SGListLookasideList = NULL;
|
||
|
}
|
||
|
|
||
|
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
||
|
("<==NdisMInitializeScatterGatherDma: Miniport %lx, Status %lx\n", Miniport, Status));
|
||
|
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
FASTCALL
|
||
|
ndisMAllocSGList(
|
||
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
||
|
IN PNDIS_PACKET Packet
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
||
|
PNDIS_BUFFER Buffer;
|
||
|
PVOID pBufferVa;
|
||
|
ULONG PacketLength;
|
||
|
PNDIS_BUFFER pNdisBuffer = NULL;
|
||
|
PVOID SGListBuffer;
|
||
|
KIRQL OldIrql;
|
||
|
|
||
|
NdisQueryPacket(Packet, NULL, NULL, &Buffer, &PacketLength);
|
||
|
|
||
|
pBufferVa = MmGetMdlVirtualAddress(Buffer);
|
||
|
|
||
|
SGListBuffer = ExAllocateFromNPagedLookasideList(Miniport->SGListLookasideList);
|
||
|
|
||
|
//
|
||
|
// Callers of GetScatterGatherList must be at dispatch.
|
||
|
//
|
||
|
RAISE_IRQL_TO_DISPATCH(&OldIrql);
|
||
|
|
||
|
if (SGListBuffer)
|
||
|
{
|
||
|
Packet->Private.Flags = NdisGetPacketFlags(Packet) | NDIS_FLAGS_USES_SG_BUFFER_LIST;
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = SGListBuffer;
|
||
|
|
||
|
Status = Miniport->SystemAdapterObject->DmaOperations->BuildScatterGatherList(
|
||
|
Miniport->SystemAdapterObject,
|
||
|
Miniport->DeviceObject,
|
||
|
Buffer,
|
||
|
pBufferVa,
|
||
|
PacketLength,
|
||
|
ndisMProcessSGList,
|
||
|
Packet,
|
||
|
TRUE,
|
||
|
SGListBuffer,
|
||
|
Miniport->ScatterGatherListSize);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = NULL;
|
||
|
NdisClearPacketFlags(Packet, NDIS_FLAGS_USES_SG_BUFFER_LIST);
|
||
|
ExFreeToNPagedLookasideList(Miniport->SGListLookasideList, SGListBuffer);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
|
||
|
Status = Miniport->SystemAdapterObject->DmaOperations->GetScatterGatherList(
|
||
|
Miniport->SystemAdapterObject,
|
||
|
Miniport->DeviceObject,
|
||
|
Buffer,
|
||
|
pBufferVa,
|
||
|
PacketLength,
|
||
|
ndisMProcessSGList,
|
||
|
Packet,
|
||
|
TRUE);
|
||
|
|
||
|
}
|
||
|
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
PCHAR NewBuffer;
|
||
|
UINT BytesCopied;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Allocate a buffer for the packet.
|
||
|
//
|
||
|
NewBuffer = (PUCHAR)ALLOC_FROM_POOL(PacketLength, NDIS_TAG_DOUBLE_BUFFER_PKT);
|
||
|
if (NULL == NewBuffer)
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate an MDL for the buffer
|
||
|
//
|
||
|
NdisAllocateBuffer(&Status, &pNdisBuffer, NULL, (PVOID)NewBuffer, PacketLength);
|
||
|
if (NDIS_STATUS_SUCCESS != Status)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from.
|
||
|
0, // Offset from beginning of packet.
|
||
|
PacketLength, // Number of bytes to copy.
|
||
|
NewBuffer, // The destination buffer.
|
||
|
&BytesCopied); // The number of bytes copied.
|
||
|
|
||
|
Packet->Private.Flags = NdisGetPacketFlags(Packet) | NDIS_FLAGS_DOUBLE_BUFFERED;
|
||
|
pBufferVa = MmGetMdlVirtualAddress(pNdisBuffer);
|
||
|
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = pNdisBuffer;
|
||
|
|
||
|
RAISE_IRQL_TO_DISPATCH(&OldIrql);
|
||
|
|
||
|
Status = Miniport->SystemAdapterObject->DmaOperations->GetScatterGatherList(
|
||
|
Miniport->SystemAdapterObject,
|
||
|
Miniport->DeviceObject,
|
||
|
pNdisBuffer,
|
||
|
pBufferVa,
|
||
|
PacketLength,
|
||
|
ndisMProcessSGList,
|
||
|
Packet,
|
||
|
TRUE);
|
||
|
|
||
|
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
|
||
|
|
||
|
}while (FALSE);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
||
|
("ndisMAllocSGList: GetScatterGatherList failed %lx\n", Status));
|
||
|
|
||
|
if (pNdisBuffer)
|
||
|
{
|
||
|
NdisFreeBuffer(pNdisBuffer);
|
||
|
}
|
||
|
if (NewBuffer)
|
||
|
{
|
||
|
FREE_POOL(NewBuffer);
|
||
|
}
|
||
|
|
||
|
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = NULL;
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = NULL;
|
||
|
NdisClearPacketFlags(Packet, NDIS_FLAGS_DOUBLE_BUFFERED);
|
||
|
|
||
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
|
||
|
{
|
||
|
PNDIS_STACK_RESERVED NSR;
|
||
|
|
||
|
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
|
||
|
NdisMCoSendComplete(NDIS_STATUS_FAILURE, NSR->VcPtr, Packet);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ndisMSendCompleteX(Miniport, Packet, NDIS_STATUS_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
FASTCALL
|
||
|
ndisMFreeSGList(
|
||
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
||
|
IN PNDIS_PACKET Packet
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PSCATTER_GATHER_LIST pSGL;
|
||
|
PVOID SGListBuffer;
|
||
|
|
||
|
pSGL = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo);
|
||
|
ASSERT(pSGL != NULL);
|
||
|
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = NULL;
|
||
|
|
||
|
ASSERT(CURRENT_IRQL == DISPATCH_LEVEL);
|
||
|
Miniport->SystemAdapterObject->DmaOperations->PutScatterGatherList(Miniport->SystemAdapterObject,
|
||
|
pSGL,
|
||
|
TRUE);
|
||
|
|
||
|
if (NdisGetPacketFlags(Packet) & NDIS_FLAGS_USES_SG_BUFFER_LIST)
|
||
|
{
|
||
|
NdisClearPacketFlags(Packet, NDIS_FLAGS_USES_SG_BUFFER_LIST);
|
||
|
SGListBuffer = NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet);
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = NULL;
|
||
|
ASSERT(SGListBuffer != NULL);
|
||
|
ExFreeToNPagedLookasideList(Miniport->SGListLookasideList, SGListBuffer);
|
||
|
}
|
||
|
else if (NdisGetPacketFlags(Packet) & NDIS_FLAGS_DOUBLE_BUFFERED)
|
||
|
{
|
||
|
PNDIS_BUFFER DoubleBuffer;
|
||
|
PVOID Buffer;
|
||
|
|
||
|
NdisClearPacketFlags(Packet, NDIS_FLAGS_DOUBLE_BUFFERED);
|
||
|
DoubleBuffer = NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet);
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = NULL;
|
||
|
ASSERT(DoubleBuffer != NULL);
|
||
|
Buffer = MmGetMdlVirtualAddress(DoubleBuffer);
|
||
|
NdisFreeBuffer(DoubleBuffer);
|
||
|
FREE_POOL(Buffer);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
ndisMProcessSGList(
|
||
|
IN PDEVICE_OBJECT pDO,
|
||
|
IN PIRP pIrp,
|
||
|
IN PSCATTER_GATHER_LIST pSGL,
|
||
|
IN PVOID Context
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PNDIS_PACKET Packet = (PNDIS_PACKET)Context;
|
||
|
PNDIS_CO_VC_PTR_BLOCK VcPtr;
|
||
|
PNDIS_MINIPORT_BLOCK Miniport;
|
||
|
PNDIS_OPEN_BLOCK Open;
|
||
|
PNDIS_STACK_RESERVED NSR;
|
||
|
|
||
|
ASSERT(CURRENT_IRQL == DISPATCH_LEVEL);
|
||
|
|
||
|
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = pSGL;
|
||
|
|
||
|
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
|
||
|
|
||
|
Open = NSR->Open;
|
||
|
Miniport = Open->MiniportHandle;
|
||
|
|
||
|
//
|
||
|
// Handle Send/SendPacket differently
|
||
|
//
|
||
|
MINIPORT_SET_PACKET_FLAG(Packet, fPACKET_PENDING);
|
||
|
|
||
|
|
||
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
|
||
|
{
|
||
|
VcPtr = NSR->VcPtr;
|
||
|
(*VcPtr->WCoSendPacketsHandler)(VcPtr->MiniportContext,
|
||
|
&Packet,
|
||
|
1);
|
||
|
|
||
|
}
|
||
|
else if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
|
||
|
{
|
||
|
//
|
||
|
// Pass the packet down to the miniport.
|
||
|
//
|
||
|
(Open->WSendPacketsHandler)(Miniport->MiniportAdapterContext,
|
||
|
&Packet,
|
||
|
1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ULONG Flags;
|
||
|
NDIS_STATUS Status;
|
||
|
|
||
|
NdisQuerySendFlags(Packet, &Flags);
|
||
|
Status = (Open->WSendHandler)(Open->MiniportAdapterContext, Packet, Flags);
|
||
|
|
||
|
if (Status != NDIS_STATUS_PENDING)
|
||
|
{
|
||
|
ndisMSendCompleteX(Miniport, Packet, Status);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
FASTCALL
|
||
|
ndisMAllocSGListS(
|
||
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
||
|
IN PNDIS_PACKET Packet
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
Allocate SG list for packets sent on a serialized miniport
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Miniport
|
||
|
Packet
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
|
||
|
PNDIS_BUFFER Buffer;
|
||
|
PVOID pBufferVa;
|
||
|
ULONG PacketLength;
|
||
|
PNDIS_BUFFER pNdisBuffer = NULL;
|
||
|
PVOID SGListBuffer;
|
||
|
KIRQL OldIrql;
|
||
|
|
||
|
NdisQueryPacket(Packet, NULL, NULL, &Buffer, &PacketLength);
|
||
|
|
||
|
pBufferVa = MmGetMdlVirtualAddress(Buffer);
|
||
|
|
||
|
SGListBuffer = ExAllocateFromNPagedLookasideList(Miniport->SGListLookasideList);
|
||
|
|
||
|
//
|
||
|
// Callers of GetScatterGatherList must be at dispatch.
|
||
|
//
|
||
|
RAISE_IRQL_TO_DISPATCH(&OldIrql);
|
||
|
|
||
|
|
||
|
if (SGListBuffer)
|
||
|
{
|
||
|
Packet->Private.Flags = NdisGetPacketFlags(Packet) | NDIS_FLAGS_USES_SG_BUFFER_LIST;
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = SGListBuffer;
|
||
|
|
||
|
Status = Miniport->SystemAdapterObject->DmaOperations->BuildScatterGatherList(
|
||
|
Miniport->SystemAdapterObject,
|
||
|
Miniport->DeviceObject,
|
||
|
Buffer,
|
||
|
pBufferVa,
|
||
|
PacketLength,
|
||
|
ndisMProcessSGListS,
|
||
|
Packet,
|
||
|
TRUE,
|
||
|
SGListBuffer,
|
||
|
Miniport->ScatterGatherListSize);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = NULL;
|
||
|
NdisClearPacketFlags(Packet, NDIS_FLAGS_USES_SG_BUFFER_LIST);
|
||
|
ExFreeToNPagedLookasideList(Miniport->SGListLookasideList, SGListBuffer);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
}
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
Status = Miniport->SystemAdapterObject->DmaOperations->GetScatterGatherList(
|
||
|
Miniport->SystemAdapterObject,
|
||
|
Miniport->DeviceObject,
|
||
|
Buffer,
|
||
|
pBufferVa,
|
||
|
PacketLength,
|
||
|
ndisMProcessSGListS,
|
||
|
Packet,
|
||
|
TRUE);
|
||
|
}
|
||
|
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
PCHAR NewBuffer;
|
||
|
UINT BytesCopied;
|
||
|
|
||
|
//
|
||
|
// probably the packet was too fragmented and we couldn't allocate enough
|
||
|
// map registers. try to double buffer the packet.
|
||
|
//
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Allocate a buffer for the packet.
|
||
|
//
|
||
|
NewBuffer = (PUCHAR)ALLOC_FROM_POOL(PacketLength, NDIS_TAG_DOUBLE_BUFFER_PKT);
|
||
|
if (NULL == NewBuffer)
|
||
|
{
|
||
|
Status = NDIS_STATUS_RESOURCES;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate an MDL for the buffer
|
||
|
//
|
||
|
NdisAllocateBuffer(&Status, &pNdisBuffer, NULL, (PVOID)NewBuffer, PacketLength);
|
||
|
if (NDIS_STATUS_SUCCESS != Status)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ndisMCopyFromPacketToBuffer(Packet, // Packet to copy from.
|
||
|
0, // Offset from beginning of packet.
|
||
|
PacketLength, // Number of bytes to copy.
|
||
|
NewBuffer, // The destination buffer.
|
||
|
&BytesCopied); // The number of bytes copied.
|
||
|
|
||
|
Packet->Private.Flags = NdisGetPacketFlags(Packet) | NDIS_FLAGS_DOUBLE_BUFFERED;
|
||
|
pBufferVa = MmGetMdlVirtualAddress(pNdisBuffer);
|
||
|
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = pNdisBuffer;
|
||
|
|
||
|
RAISE_IRQL_TO_DISPATCH(&OldIrql);
|
||
|
|
||
|
Status = Miniport->SystemAdapterObject->DmaOperations->GetScatterGatherList(
|
||
|
Miniport->SystemAdapterObject,
|
||
|
Miniport->DeviceObject,
|
||
|
pNdisBuffer,
|
||
|
pBufferVa,
|
||
|
PacketLength,
|
||
|
ndisMProcessSGListS,
|
||
|
Packet,
|
||
|
TRUE);
|
||
|
|
||
|
LOWER_IRQL(OldIrql, DISPATCH_LEVEL);
|
||
|
|
||
|
|
||
|
}while (FALSE);
|
||
|
|
||
|
if (!NT_SUCCESS(Status))
|
||
|
{
|
||
|
PNDIS_STACK_RESERVED NSR;
|
||
|
|
||
|
DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
|
||
|
("ndisMAllocSGList: GetScatterGatherList failed %lx\n", Status));
|
||
|
|
||
|
if (pNdisBuffer)
|
||
|
{
|
||
|
NdisFreeBuffer(pNdisBuffer);
|
||
|
}
|
||
|
if (NewBuffer)
|
||
|
{
|
||
|
FREE_POOL(NewBuffer);
|
||
|
}
|
||
|
|
||
|
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = NULL;
|
||
|
NDIS_DOUBLE_BUFFER_INFO_FROM_PACKET(Packet) = NULL;
|
||
|
NdisClearPacketFlags(Packet, NDIS_FLAGS_DOUBLE_BUFFERED);
|
||
|
|
||
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
||
|
//
|
||
|
// complete the send, don't unlink the packet since it was never
|
||
|
// linked to begin with.
|
||
|
//
|
||
|
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
|
||
|
NDISM_COMPLETE_SEND_SG(Miniport, Packet, NSR, Status, TRUE, 0, FALSE);
|
||
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
ndisMProcessSGListS(
|
||
|
IN PDEVICE_OBJECT pDO,
|
||
|
IN PIRP pIrp,
|
||
|
IN PSCATTER_GATHER_LIST pSGL,
|
||
|
IN PVOID Context
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PNDIS_PACKET Packet = (PNDIS_PACKET)Context;
|
||
|
PNDIS_MINIPORT_BLOCK Miniport;
|
||
|
PNDIS_OPEN_BLOCK Open;
|
||
|
PNDIS_STACK_RESERVED NSR;
|
||
|
BOOLEAN LocalLock;
|
||
|
|
||
|
ASSERT(CURRENT_IRQL == DISPATCH_LEVEL);
|
||
|
|
||
|
NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) = pSGL;
|
||
|
|
||
|
NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR);
|
||
|
|
||
|
Open = NSR->Open;
|
||
|
Miniport = Open->MiniportHandle;
|
||
|
|
||
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC (Miniport);
|
||
|
|
||
|
//
|
||
|
// queue the packet
|
||
|
//
|
||
|
LINK_PACKET_SG(Miniport, Packet, NSR);
|
||
|
|
||
|
if (Miniport->FirstPendingPacket == NULL)
|
||
|
{
|
||
|
Miniport->FirstPendingPacket = Packet;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we have the local lock and there is no
|
||
|
// packet pending, then fire off a send.
|
||
|
//
|
||
|
LOCK_MINIPORT(Miniport, LocalLock);
|
||
|
|
||
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL);
|
||
|
if (LocalLock)
|
||
|
{
|
||
|
NDISM_PROCESS_DEFERRED(Miniport);
|
||
|
}
|
||
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
||
|
|
||
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
||
|
|
||
|
}
|
||
|
|