- Implement a simple buffer allocation algorithm which backs off the buffer size until all buffer allocations succeed

See issue #6284 for more details.

svn path=/trunk/; revision=53149
This commit is contained in:
Cameron Gutman 2011-08-09 07:30:10 +00:00
parent cd830b727c
commit 6ac78fe2f9
2 changed files with 186 additions and 148 deletions

View file

@ -145,7 +145,7 @@ MiniportHandleInterrupt(
Descriptor->FLAGS |= RD_OWN; Descriptor->FLAGS |= RD_OWN;
Adapter->CurrentReceiveDescriptorIndex++; Adapter->CurrentReceiveDescriptorIndex++;
Adapter->CurrentReceiveDescriptorIndex %= NUMBER_OF_BUFFERS; Adapter->CurrentReceiveDescriptorIndex %= Adapter->BufferCount;
Adapter->Statistics.RcvGoodFrames++; Adapter->Statistics.RcvGoodFrames++;
} }
@ -201,7 +201,7 @@ MiniportHandleInterrupt(
} }
Adapter->CurrentTransmitStartIndex++; Adapter->CurrentTransmitStartIndex++;
Adapter->CurrentTransmitStartIndex %= NUMBER_OF_BUFFERS; Adapter->CurrentTransmitStartIndex %= Adapter->BufferCount;
Adapter->Statistics.XmtGoodFrames++; Adapter->Statistics.XmtGoodFrames++;
} }
@ -297,6 +297,60 @@ MiQueryCard(
return NDIS_STATUS_SUCCESS; return NDIS_STATUS_SUCCESS;
} }
static VOID
MiFreeSharedMemory(
PADAPTER Adapter)
/*
* FUNCTION: Free all allocated shared memory
* ARGUMENTS:
* Adapter: pointer to the miniport's adapter struct
*/
{
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
PhysicalAddress.u.HighPart = 0;
if(Adapter->InitializationBlockVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->InitializationBlockPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
FALSE, Adapter->InitializationBlockVirt, PhysicalAddress);
Adapter->InitializationBlockVirt = NULL;
}
if(Adapter->TransmitDescriptorRingVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitDescriptorRingPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
FALSE, Adapter->TransmitDescriptorRingVirt, PhysicalAddress);
Adapter->TransmitDescriptorRingVirt = NULL;
}
if(Adapter->ReceiveDescriptorRingVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveDescriptorRingPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
FALSE, Adapter->ReceiveDescriptorRingVirt, PhysicalAddress);
Adapter->ReceiveDescriptorRingVirt = NULL;
}
if(Adapter->TransmitBufferPtrVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitBufferPtrPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
TRUE, Adapter->TransmitBufferPtrVirt, PhysicalAddress);
Adapter->TransmitBufferPtrVirt = NULL;
}
if(Adapter->ReceiveBufferPtrVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveBufferPtrPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
TRUE, Adapter->ReceiveBufferPtrVirt, PhysicalAddress);
Adapter->ReceiveBufferPtrVirt = NULL;
}
}
static NDIS_STATUS static NDIS_STATUS
MiAllocateSharedMemory( MiAllocateSharedMemory(
PADAPTER Adapter) PADAPTER Adapter)
@ -313,104 +367,133 @@ MiAllocateSharedMemory(
PRECEIVE_DESCRIPTOR ReceiveDescriptor; PRECEIVE_DESCRIPTOR ReceiveDescriptor;
NDIS_PHYSICAL_ADDRESS PhysicalAddress; NDIS_PHYSICAL_ADDRESS PhysicalAddress;
ULONG i; ULONG i;
ULONG BufferCount = NUMBER_OF_BUFFERS;
ULONG LogBufferCount = LOG_NUMBER_OF_BUFFERS;
/* allocate the initialization block */ while (BufferCount != 0)
Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK); {
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength, /* allocate the initialization block (we have this in the loop so we can use MiFreeSharedMemory) */
FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress); Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK);
if(!Adapter->InitializationBlockVirt) NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
{ FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress);
DPRINT1("insufficient resources\n"); if(!Adapter->InitializationBlockVirt)
{
/* Buffer backoff won't help us here */
DPRINT1("insufficient resources\n");
return NDIS_STATUS_RESOURCES;
}
if(((ULONG)Adapter->InitializationBlockVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress);
/* allocate the transport descriptor ring */
Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress);
if (!Adapter->TransmitDescriptorRingVirt)
{
DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
}
if (((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * BufferCount);
/* allocate the receive descriptor ring */
Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress);
if (!Adapter->ReceiveDescriptorRingVirt)
{
DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
}
if (((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * BufferCount);
/* allocate transmit buffers */
Adapter->TransmitBufferLength = BUFFER_SIZE * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress);
if(!Adapter->TransmitBufferPtrVirt)
{
DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
}
if (((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * BufferCount);
/* allocate receive buffers */
Adapter->ReceiveBufferLength = BUFFER_SIZE * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress);
if(!Adapter->ReceiveBufferPtrVirt)
{
DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
}
if (((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * BufferCount);
break;
}
if (!BufferCount)
{
DPRINT1("Failed to allocate adapter buffers\n");
return NDIS_STATUS_RESOURCES; return NDIS_STATUS_RESOURCES;
} }
if(((ULONG)Adapter->InitializationBlockVirt & 0x00000003) != 0) Adapter->BufferCount = BufferCount;
{ Adapter->LogBufferCount = LogBufferCount;
DPRINT1("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress);
/* allocate the transport descriptor ring */
Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress);
if(!Adapter->TransmitDescriptorRingVirt)
{
DPRINT1("insufficient resources\n");
return NDIS_STATUS_RESOURCES;
}
if(((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS);
/* allocate the receive descriptor ring */
Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress);
if(!Adapter->ReceiveDescriptorRingVirt)
{
DPRINT1("insufficient resources\n");
return NDIS_STATUS_RESOURCES;
}
if(((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS);
/* allocate transmit buffers */
Adapter->TransmitBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress);
if(!Adapter->TransmitBufferPtrVirt)
{
DPRINT1("insufficient resources\n");
return NDIS_STATUS_RESOURCES;
}
if(((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * NUMBER_OF_BUFFERS);
/* allocate receive buffers */
Adapter->ReceiveBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress);
if(!Adapter->ReceiveBufferPtrVirt)
{
DPRINT1("insufficient resources\n");
return NDIS_STATUS_RESOURCES;
}
if(((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
{
DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt);
return NDIS_STATUS_RESOURCES;
}
Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * NUMBER_OF_BUFFERS);
/* initialize tx descriptors */ /* initialize tx descriptors */
TransmitDescriptor = Adapter->TransmitDescriptorRingVirt; TransmitDescriptor = Adapter->TransmitDescriptorRingVirt;
for(i = 0; i < NUMBER_OF_BUFFERS; i++) for(i = 0; i < BufferCount; i++)
{ {
(TransmitDescriptor+i)->TBADR = (ULONG)Adapter->TransmitBufferPtrPhys + i * BUFFER_SIZE; (TransmitDescriptor+i)->TBADR = (ULONG)Adapter->TransmitBufferPtrPhys + i * BUFFER_SIZE;
(TransmitDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */ (TransmitDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */
@ -421,7 +504,7 @@ MiAllocateSharedMemory(
/* initialize rx */ /* initialize rx */
ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt; ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt;
for(i = 0; i < NUMBER_OF_BUFFERS; i++) for(i = 0; i < BufferCount; i++)
{ {
(ReceiveDescriptor+i)->RBADR = (ULONG)Adapter->ReceiveBufferPtrPhys + i * BUFFER_SIZE; (ReceiveDescriptor+i)->RBADR = (ULONG)Adapter->ReceiveBufferPtrPhys + i * BUFFER_SIZE;
(ReceiveDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */ (ReceiveDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */
@ -460,61 +543,12 @@ MiPrepareInitializationBlock(
/* set up receive ring */ /* set up receive ring */
DPRINT("Receive ring physical address: 0x%x\n", Adapter->ReceiveDescriptorRingPhys); DPRINT("Receive ring physical address: 0x%x\n", Adapter->ReceiveDescriptorRingPhys);
Adapter->InitializationBlockVirt->RDRA = (ULONG)Adapter->ReceiveDescriptorRingPhys; Adapter->InitializationBlockVirt->RDRA = (ULONG)Adapter->ReceiveDescriptorRingPhys;
Adapter->InitializationBlockVirt->RLEN = (LOG_NUMBER_OF_BUFFERS << 4) & 0xf0; Adapter->InitializationBlockVirt->RLEN = (Adapter->LogBufferCount << 4) & 0xf0;
/* set up transmit ring */ /* set up transmit ring */
DPRINT("Transmit ring physical address: 0x%x\n", Adapter->TransmitDescriptorRingPhys); DPRINT("Transmit ring physical address: 0x%x\n", Adapter->TransmitDescriptorRingPhys);
Adapter->InitializationBlockVirt->TDRA = (ULONG)Adapter->TransmitDescriptorRingPhys; Adapter->InitializationBlockVirt->TDRA = (ULONG)Adapter->TransmitDescriptorRingPhys;
Adapter->InitializationBlockVirt->TLEN = (LOG_NUMBER_OF_BUFFERS << 4) & 0xf0; Adapter->InitializationBlockVirt->TLEN = (Adapter->LogBufferCount << 4) & 0xf0;
}
static VOID
MiFreeSharedMemory(
PADAPTER Adapter)
/*
* FUNCTION: Free all allocated shared memory
* ARGUMENTS:
* Adapter: pointer to the miniport's adapter struct
*/
{
NDIS_PHYSICAL_ADDRESS PhysicalAddress;
PhysicalAddress.u.HighPart = 0;
if(Adapter->InitializationBlockVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->InitializationBlockPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
FALSE, Adapter->InitializationBlockVirt, PhysicalAddress);
}
if(Adapter->TransmitDescriptorRingVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitDescriptorRingPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
FALSE, Adapter->TransmitDescriptorRingVirt, PhysicalAddress);
}
if(Adapter->ReceiveDescriptorRingVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveDescriptorRingPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
FALSE, Adapter->ReceiveDescriptorRingVirt, PhysicalAddress);
}
if(Adapter->TransmitBufferPtrVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitBufferPtrPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
FALSE, Adapter->TransmitBufferPtrVirt, PhysicalAddress);
}
if(Adapter->ReceiveBufferPtrVirt)
{
PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveBufferPtrPhys;
NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
FALSE, Adapter->ReceiveBufferPtrVirt, PhysicalAddress);
}
} }
static BOOLEAN static BOOLEAN
@ -1136,7 +1170,7 @@ MiniportSend(
/* Check if we have free entry in our circular buffer. */ /* Check if we have free entry in our circular buffer. */
if ((Adapter->CurrentTransmitEndIndex + 1 == if ((Adapter->CurrentTransmitEndIndex + 1 ==
Adapter->CurrentTransmitStartIndex) || Adapter->CurrentTransmitStartIndex) ||
(Adapter->CurrentTransmitEndIndex == NUMBER_OF_BUFFERS - 1 && (Adapter->CurrentTransmitEndIndex == Adapter->BufferCount - 1 &&
Adapter->CurrentTransmitStartIndex == 0)) Adapter->CurrentTransmitStartIndex == 0))
{ {
DPRINT1("No free space in circular buffer\n"); DPRINT1("No free space in circular buffer\n");
@ -1181,7 +1215,7 @@ MiniportSend(
#endif #endif
Adapter->CurrentTransmitEndIndex++; Adapter->CurrentTransmitEndIndex++;
Adapter->CurrentTransmitEndIndex %= NUMBER_OF_BUFFERS; Adapter->CurrentTransmitEndIndex %= Adapter->BufferCount;
Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP; Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP;
Desc->BCNT = 0xf000 | -TotalPacketLength; Desc->BCNT = 0xf000 | -TotalPacketLength;

View file

@ -97,6 +97,10 @@ typedef struct _ADAPTER
PCHAR ReceiveBufferPtrVirt; PCHAR ReceiveBufferPtrVirt;
PCHAR ReceiveBufferPtrPhys; PCHAR ReceiveBufferPtrPhys;
/* buffer count */
ULONG BufferCount;
ULONG LogBufferCount;
ADAPTER_STATS Statistics; ADAPTER_STATS Statistics;
} ADAPTER, *PADAPTER; } ADAPTER, *PADAPTER;