- 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,13 +367,18 @@ 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)
{
/* allocate the initialization block (we have this in the loop so we can use MiFreeSharedMemory) */
Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK); Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK);
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength, NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress); FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress);
if(!Adapter->InitializationBlockVirt) if(!Adapter->InitializationBlockVirt)
{ {
/* Buffer backoff won't help us here */
DPRINT1("insufficient resources\n"); DPRINT1("insufficient resources\n");
return NDIS_STATUS_RESOURCES; return NDIS_STATUS_RESOURCES;
} }
@ -333,84 +392,108 @@ MiAllocateSharedMemory(
Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress); Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress);
/* allocate the transport descriptor ring */ /* allocate the transport descriptor ring */
Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS; Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength, NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress); FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress);
if(!Adapter->TransmitDescriptorRingVirt) if (!Adapter->TransmitDescriptorRingVirt)
{ {
DPRINT1("insufficient resources\n"); DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
return NDIS_STATUS_RESOURCES; BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
} }
if(((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0) if (((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
{ {
DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt); DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt);
return NDIS_STATUS_RESOURCES; return NDIS_STATUS_RESOURCES;
} }
Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress); Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS); RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * BufferCount);
/* allocate the receive descriptor ring */ /* allocate the receive descriptor ring */
Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS; Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength, NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress); FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress);
if(!Adapter->ReceiveDescriptorRingVirt) if (!Adapter->ReceiveDescriptorRingVirt)
{ {
DPRINT1("insufficient resources\n"); DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
return NDIS_STATUS_RESOURCES; BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
} }
if(((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0) if (((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
{ {
DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt); DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt);
return NDIS_STATUS_RESOURCES; return NDIS_STATUS_RESOURCES;
} }
Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress); Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS); RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * BufferCount);
/* allocate transmit buffers */ /* allocate transmit buffers */
Adapter->TransmitBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS; Adapter->TransmitBufferLength = BUFFER_SIZE * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength, NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress); TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress);
if(!Adapter->TransmitBufferPtrVirt) if(!Adapter->TransmitBufferPtrVirt)
{ {
DPRINT1("insufficient resources\n"); DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
return NDIS_STATUS_RESOURCES; BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
} }
if(((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0) if (((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
{ {
DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt); DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt);
return NDIS_STATUS_RESOURCES; return NDIS_STATUS_RESOURCES;
} }
Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress); Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * NUMBER_OF_BUFFERS); RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * BufferCount);
/* allocate receive buffers */ /* allocate receive buffers */
Adapter->ReceiveBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS; Adapter->ReceiveBufferLength = BUFFER_SIZE * BufferCount;
NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength, NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress); TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress);
if(!Adapter->ReceiveBufferPtrVirt) if(!Adapter->ReceiveBufferPtrVirt)
{ {
DPRINT1("insufficient resources\n"); DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
return NDIS_STATUS_RESOURCES; BufferCount = BufferCount >> 1;
LogBufferCount--;
MiFreeSharedMemory(Adapter);
continue;
} }
if(((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0) if (((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
{ {
DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt); DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt);
return NDIS_STATUS_RESOURCES; return NDIS_STATUS_RESOURCES;
} }
Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress); Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * NUMBER_OF_BUFFERS); RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * BufferCount);
break;
}
if (!BufferCount)
{
DPRINT1("Failed to allocate adapter buffers\n");
return NDIS_STATUS_RESOURCES;
}
Adapter->BufferCount = BufferCount;
Adapter->LogBufferCount = LogBufferCount;
/* 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;