This patch updates the MNP driver to recycle TX buffer asynchronously, instead of using a while loop wait after each transmit command.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Fu Siyuan <siyuan...@intel.com> --- MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c | 177 ++++++++++++++++++---- MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h | 5 +- MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h | 24 ++- MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c | 144 +++++++++--------- MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c | 5 +- 5 files changed, 248 insertions(+), 107 deletions(-) diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c index 046d4df..70be4ac 100644 --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c @@ -209,6 +209,139 @@ MnpFreeNbuf ( gBS->RestoreTPL (OldTpl); } +EFI_STATUS +MnpAddFreeTxBuf ( + IN OUT MNP_DEVICE_DATA *MnpDeviceData, + IN UINTN Count + ) +{ + EFI_STATUS Status; + UINT32 Index; + MNP_TX_BUF_WRAP *TxBufWrap; + + NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE); + ASSERT ((Count > 0) && (MnpDeviceData->BufferLength > 0)); + + Status = EFI_SUCCESS; + for (Index = 0; Index < Count; Index++) { + TxBufWrap = (MNP_TX_BUF_WRAP*) AllocatePool (sizeof (MNP_TX_BUF_WRAP) + MnpDeviceData->BufferLength - 1); + if (TxBufWrap == NULL) { + DEBUG ((EFI_D_ERROR, "MnpAddFreeTxBuf: TxBuf Alloc failed.\n")); + + Status = EFI_OUT_OF_RESOURCES; + break; + } + DEBUG ((EFI_D_INFO, "MnpAddFreeTxBuf: Add TxBufWrap %p, TxBuf %p\n", TxBufWrap, TxBufWrap->TxBuf)); + TxBufWrap->Signature = MNP_TX_BUF_WRAP_SIGNATURE; + TxBufWrap->InUse = FALSE; + InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry); + InsertTailList (&MnpDeviceData->AllTxBufList, &TxBufWrap->AllEntry); + } + + MnpDeviceData->TxBufCount += Index; + return Status; +} + + +UINT8 * +MnpAllocTxBuf ( + IN OUT MNP_DEVICE_DATA *MnpDeviceData + ) +{ + EFI_TPL OldTpl; + UINT8 *TxBuf; + EFI_STATUS Status; + LIST_ENTRY *Entry; + MNP_TX_BUF_WRAP *TxBufWrap; + + NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE); + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + + if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) { + if ((MnpDeviceData->TxBufCount + MNP_TX_BUFFER_INCREASEMENT) > MNP_MAX_TX_BUFFER_NUM) { + DEBUG ( + (EFI_D_ERROR, + "MnpAllocTxBuf: The maximum TxBuf size is reached for MNP driver instance %p.\n", + MnpDeviceData) + ); + + TxBuf = NULL; + goto ON_EXIT; + } + + Status = MnpAddFreeTxBuf (MnpDeviceData, MNP_TX_BUFFER_INCREASEMENT); + if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) { + DEBUG ( + (EFI_D_ERROR, + "MnpAllocNbuf: Failed to add NET_BUFs into the FreeNbufQue, %r.\n", + Status) + ); + + TxBuf = NULL; + goto ON_EXIT; + } + } + + ASSERT (!IsListEmpty (&MnpDeviceData->FreeTxBufList)); + Entry = MnpDeviceData->FreeTxBufList.ForwardLink; + RemoveEntryList (MnpDeviceData->FreeTxBufList.ForwardLink); + //TxBufWrap = NET_LIST_USER_STRUCT_S (Entry, MNP_TX_BUF_WRAP, WrapEntry, MNP_TX_BUF_WRAP_SIGNATURE); + TxBufWrap = NET_LIST_USER_STRUCT (Entry, MNP_TX_BUF_WRAP, WrapEntry); + DEBUG ((EFI_D_INFO, "MnpAllocTxBuf: Allocate TxBufWrap %p, TxBuf %p\n", TxBufWrap, TxBufWrap->TxBuf)); + ASSERT (TxBufWrap->Signature == MNP_TX_BUF_WRAP_SIGNATURE); + TxBufWrap->InUse = TRUE; + TxBuf = TxBufWrap->TxBuf; + +ON_EXIT: + gBS->RestoreTPL (OldTpl); + + //DEBUG ((EFI_D_INFO, "MnpAllocTxBuf: allocate TxBuf %p\n", TxBuf)); + + return TxBuf; +} + + +VOID +MnpFreeTxBuf ( + IN OUT MNP_DEVICE_DATA *MnpDeviceData, + IN OUT UINT8 *TxBuf + ) +{ + MNP_TX_BUF_WRAP *TxBufWrap; + EFI_TPL OldTpl; + + NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE); + + DEBUG ((EFI_D_INFO, "MnpFreeTxBuf: recycle TxBuf %p\n", TxBuf)); + + if (TxBuf == NULL) { + return; + } + + TxBufWrap = NET_LIST_USER_STRUCT (TxBuf, MNP_TX_BUF_WRAP, TxBuf); + if (TxBufWrap->Signature != MNP_TX_BUF_WRAP_SIGNATURE) { + DEBUG ( + (EFI_D_ERROR, + "MnpFreeTxBuf: Signature check failed in MnpFreeTxBuf.\n") + ); + return; + } + + if (!TxBufWrap->InUse) { + DEBUG ( + (EFI_D_WARN, + "MnpFreeTxBuf: Duplicated recycle report from SNP.\n") + ); + return; + } + + OldTpl = gBS->RaiseTPL (TPL_CALLBACK); + InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry); + TxBufWrap->InUse = FALSE; + gBS->RestoreTPL (OldTpl); +} + /** Initialize the mnp device context data. @@ -314,13 +447,9 @@ MnpInitializeDeviceData ( // // Allocate buffer pool for tx. // - MnpDeviceData->TxBuf = AllocatePool (MnpDeviceData->BufferLength); - if (MnpDeviceData->TxBuf == NULL) { - DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: AllocatePool failed.\n")); - - Status = EFI_OUT_OF_RESOURCES; - goto ERROR; - } + InitializeListHead (&MnpDeviceData->FreeTxBufList); + InitializeListHead (&MnpDeviceData->AllTxBufList); + MnpDeviceData->TxBufCount = 0; // // Create the system poll timer. @@ -370,20 +499,6 @@ MnpInitializeDeviceData ( goto ERROR; } - // - // Create the timer for tx timeout check. - // - Status = gBS->CreateEvent ( - EVT_TIMER, - TPL_CALLBACK, - NULL, - NULL, - &MnpDeviceData->TxTimeoutEvent - ); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for tx timeout event failed.\n")); - } - ERROR: if (EFI_ERROR (Status)) { // @@ -405,10 +520,6 @@ ERROR: gBS->CloseEvent (MnpDeviceData->PollTimer); } - if (MnpDeviceData->TxBuf != NULL) { - FreePool (MnpDeviceData->TxBuf); - } - if (MnpDeviceData->RxNbufCache != NULL) { MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache); } @@ -445,6 +556,10 @@ MnpDestroyDeviceData ( IN EFI_HANDLE ImageHandle ) { + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + MNP_TX_BUF_WRAP *TxBufWrap; + NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE); // @@ -462,15 +577,21 @@ MnpDestroyDeviceData ( // // Close the event. // - gBS->CloseEvent (MnpDeviceData->TxTimeoutEvent); gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer); gBS->CloseEvent (MnpDeviceData->MediaDetectTimer); gBS->CloseEvent (MnpDeviceData->PollTimer); // - // Free the tx buffer. + // Free the Tx buffer pool. // - FreePool (MnpDeviceData->TxBuf); + NET_LIST_FOR_EACH_SAFE(Entry, NextEntry, &MnpDeviceData->AllTxBufList) { + TxBufWrap = NET_LIST_USER_STRUCT (Entry, MNP_TX_BUF_WRAP, AllEntry); + RemoveEntryList (Entry); + FreePool (TxBufWrap); + MnpDeviceData->TxBufCount--; + } + ASSERT (IsListEmpty (&MnpDeviceData->AllTxBufList)); + ASSERT (MnpDeviceData->TxBufCount == 0); // // Free the RxNbufCache. diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h b/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h index 35a9b71..ac21e7b 100644 --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h @@ -67,7 +67,9 @@ typedef struct { LIST_ENTRY GroupAddressList; UINT32 GroupAddressCount; - EFI_EVENT TxTimeoutEvent; + LIST_ENTRY FreeTxBufList; + LIST_ENTRY AllTxBufList; + UINT32 TxBufCount; NET_BUF_QUEUE FreeNbufQue; INTN NbufCnt; @@ -90,7 +92,6 @@ typedef struct { UINT32 BufferLength; UINT32 PaddingSize; NET_BUF *RxNbufCache; - UINT8 *TxBuf; } MNP_DEVICE_DATA; #define MNP_DEVICE_DATA_FROM_THIS(a) \ diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h b/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h index f94e208..50ac65d 100644 --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h @@ -27,6 +27,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #define MNP_INIT_NET_BUFFER_NUM 512 #define MNP_NET_BUFFER_INCREASEMENT 64 #define MNP_MAX_NET_BUFFER_NUM 65536 +#define MNP_TX_BUFFER_INCREASEMENT 64 +#define MNP_MAX_TX_BUFFER_NUM 65536 #define MNP_MAX_RCVD_PACKET_QUE_SIZE 256 @@ -92,6 +94,15 @@ typedef struct { UINT64 TimeoutTick; } MNP_RXDATA_WRAP; +#define MNP_TX_BUF_WRAP_SIGNATURE SIGNATURE_32 ('M', 'T', 'B', 'W') + +typedef struct { + UINT32 Signature; + LIST_ENTRY WrapEntry; // Link to FreeTxBufList + LIST_ENTRY AllEntry; // Link to AllTxBufList + BOOLEAN InUse; + UINT8 TxBuf[1]; +} MNP_TX_BUF_WRAP; /** Initialize the mnp device context data. @@ -343,7 +354,7 @@ MnpIsValidTxToken ( length. **/ -VOID +EFI_STATUS MnpBuildTxPacket ( IN MNP_SERVICE_DATA *MnpServiceData, IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData, @@ -448,6 +459,17 @@ MnpFreeNbuf ( IN OUT NET_BUF *Nbuf ); +UINT8 * +MnpAllocTxBuf ( + IN OUT MNP_DEVICE_DATA *MnpDeviceData + ); + +VOID +MnpFreeTxBuf ( + IN OUT MNP_DEVICE_DATA *MnpDeviceData, + IN OUT UINT8 *TxBuf + ); + /** Remove the received packets if timeout occurs. diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c index 7f03b84..1014f9c 100644 --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c @@ -102,6 +102,32 @@ MnpIsValidTxToken ( return TRUE; } +EFI_STATUS +MnpRecycleTxBuf ( + IN OUT MNP_DEVICE_DATA *MnpDeviceData + ) +{ + UINT8 *TxBuf; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + EFI_STATUS Status; + + Snp = MnpDeviceData->Snp; + + do { + TxBuf = NULL; + Status = Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf); + if (EFI_ERROR (Status)) { + return Status; + } + + if (TxBuf != NULL) { + MnpFreeTxBuf (MnpDeviceData, TxBuf); + } + } while (TxBuf != NULL); + + return EFI_SUCCESS; +} + /** Build the packet to transmit from the TxData passed in. @@ -114,7 +140,7 @@ MnpIsValidTxToken ( length. **/ -VOID +EFI_STATUS MnpBuildTxPacket ( IN MNP_SERVICE_DATA *MnpServiceData, IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData, @@ -125,14 +151,33 @@ MnpBuildTxPacket ( EFI_SIMPLE_NETWORK_MODE *SnpMode; UINT8 *DstPos; UINT16 Index; - MNP_DEVICE_DATA *MnpDerviceData; - - MnpDerviceData = MnpServiceData->MnpDeviceData; + MNP_DEVICE_DATA *MnpDeviceData; + UINT8 *TxBuf; + EFI_STATUS Status; + + MnpDeviceData = MnpServiceData->MnpDeviceData; // - // Reserve space for vlan tag. + // Try to recyle some TxBufs before get the TxBuf from the free buffer pool. + // + Status = MnpRecycleTxBuf (MnpDeviceData); + if (EFI_ERROR (Status)) { + return Status; + } + + TxBuf = MnpAllocTxBuf (MnpDeviceData); + if (TxBuf == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Reserve space for vlan tag if needed. // - *PktBuf = MnpDerviceData->TxBuf + NET_VLAN_TAG_LEN; + if (MnpServiceData->VlanId != 0) { + *PktBuf = TxBuf + NET_VLAN_TAG_LEN; + } else { + *PktBuf = TxBuf; + } if ((TxData->DestinationAddress == NULL) && (TxData->FragmentCount == 1)) { CopyMem ( @@ -148,7 +193,7 @@ MnpBuildTxPacket ( // one fragment, copy the data into the packet buffer. Reserve the // media header space if necessary. // - SnpMode = MnpDerviceData->Snp->Mode; + SnpMode = MnpDeviceData->Snp->Mode; DstPos = *PktBuf; *PktLen = 0; if (TxData->DestinationAddress != NULL) { @@ -177,6 +222,8 @@ MnpBuildTxPacket ( // *PktLen += TxData->DataLength + TxData->HeaderLength; } + + return EFI_SUCCESS; } @@ -205,14 +252,13 @@ MnpSyncSendPacket ( EFI_SIMPLE_NETWORK_PROTOCOL *Snp; EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData; UINT32 HeaderSize; - UINT8 *TxBuf; MNP_DEVICE_DATA *MnpDeviceData; UINT16 ProtocolType; MnpDeviceData = MnpServiceData->MnpDeviceData; Snp = MnpDeviceData->Snp; TxData = Token->Packet.TxData; - + Token->Status = EFI_SUCCESS; HeaderSize = Snp->Mode->MediaHeaderSize - TxData->HeaderLength; // @@ -224,19 +270,7 @@ MnpSyncSendPacket ( // Media not present, skip packet transmit and report EFI_NO_MEDIA // DEBUG ((EFI_D_WARN, "MnpSyncSendPacket: No network cable detected.\n")); - Status = EFI_NO_MEDIA; - goto SIGNAL_TOKEN; - } - - // - // Start the timeout event. - // - Status = gBS->SetTimer ( - MnpDeviceData->TxTimeoutEvent, - TimerRelative, - MNP_TX_TIMEOUT_TIME - ); - if (EFI_ERROR (Status)) { + Token->Status = EFI_NO_MEDIA; goto SIGNAL_TOKEN; } @@ -250,64 +284,24 @@ MnpSyncSendPacket ( ProtocolType = TxData->ProtocolType; } - for (;;) { - // - // Transmit the packet through SNP. - // - Status = Snp->Transmit ( - Snp, - HeaderSize, - Length, - Packet, - TxData->SourceAddress, - TxData->DestinationAddress, - &ProtocolType - ); - if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) { - Status = EFI_DEVICE_ERROR; - break; - } - - // - // If Status is EFI_SUCCESS, the packet is put in the transmit queue. - // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy. - // Both need to sync SNP. - // - TxBuf = NULL; - do { - // - // Get the recycled transmit buffer status. - // - Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf); - - if (!EFI_ERROR (gBS->CheckEvent (MnpDeviceData->TxTimeoutEvent))) { - Status = EFI_TIMEOUT; - break; - } - } while (TxBuf == NULL); - - if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) { - break; - } else { - // - // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again. - // - gBS->SetTimer ( - MnpDeviceData->TxTimeoutEvent, - TimerRelative, - MNP_TX_TIMEOUT_TIME - ); - } - } - // - // Cancel the timer event. + // Transmit the packet through SNP. // - gBS->SetTimer (MnpDeviceData->TxTimeoutEvent, TimerCancel, 0); + Status = Snp->Transmit ( + Snp, + HeaderSize, + Length, + Packet, + TxData->SourceAddress, + TxData->DestinationAddress, + &ProtocolType + ); + if (EFI_ERROR (Status)) { + Token->Status = EFI_DEVICE_ERROR; + } SIGNAL_TOKEN: - Token->Status = Status; gBS->SignalEvent (Token->Event); // diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c index 4c0f3dd..195fcae 100644 --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c @@ -552,7 +552,10 @@ MnpTransmit ( // // Build the tx packet // - MnpBuildTxPacket (MnpServiceData, Token->Packet.TxData, &PktBuf, &PktLen); + Status = MnpBuildTxPacket (MnpServiceData, Token->Packet.TxData, &PktBuf, &PktLen); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } // // OK, send the packet synchronously. -- 2.5.0.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel