Adding Josh On 01/06/16 13:28, Laszlo Ersek wrote: > On 01/06/16 01:55, Fu, Siyuan wrote: >> Hi, Laszlo >> >> You suggestion make sense, I will separate the patch into 2 commits >> when check in it. > > Thanks. > >> For the second question, this patch only make the TX buffer recycle >> asynchronously and it's handled internal the MNP driver itself. For >> the MNP's consumer point of view the function behaves exactly same as >> before. > > Right. > >> But this patch also depends on a correctly implementation of >> the UNDI GetStatus command, which should return the recycled TX >> buffer address in it, and we are planning to update the SCT test case >> to cover this point. > > In your environment, you probably have a > > [UNDI] -> [SnpDxe] -> [MnpDxe] -> [...] > > driver / protocol chain. The one that I have in mind however is > > [NIC specific SNP driver] -> [MnpDxe] -> [...] > > This is what I could test (without any UNDI dependency), if I only knew > what to use for the "[...]" part. > >> In our test environment, this patch could improve about 20% download >> speed of the HTTP boot. This result could be different on other >> platform and NIC, but I think the user should be able to see the >> better download performance. > > That's great, thanks! > > I've never tried HTTP boot before. I found some hints at > <http://ipxe.org/appnote/uefihttp>, but I don't use "ISC dhcpd" -- in my > (virtual) environment, DHCP is provided by "dnsmasq", and that is in > turn configured by libvirtd. > > Based on the docs <http://libvirt.org/formatnetwork.html>, I don't think > it is currently possible to set up HTTP netboot with libvirtd. > > I guess I could set up an independent DHCP server or config, but maybe > there's a simpler way. In the UEFI shell, the TFTP command enables the > user to download a file with TFTP. This seems to be implemented in > ShellPkg/Library/UefiShellTftpCommandLib. > > Is there a similar shell command for HTTP perhaps?
I just noticed that the most recent release of BITS provides a standalone HTTP client! http://biosbits.org/news/bits-2070/ Josh, a couple of points: - edk2 doesn't provide EFI_IP4_CONFIG_PROTOCOL any longer; it provides EFI_IP4_CONFIG2_PROTOCOL. I haven't tested this new release of BITS just yet, but I know this caused problems for a few consumers of edk2. - OVMF *should* provide EFI_DNS4_SERVICE_BINDING_PROTOCOL: if you build it with -D HTTP_BOOT_ENABLE, then "NetworkPkg/DnsDxe/DnsDxe.inf" gets included, and that INF file says: [Protocols] gEfiDns4ServiceBindingProtocolGuid ## BY_START Are you using Gerd's RPMs? Gerd, can you please add -D HTTP_BOOT_ENABLE to the OVMF (IA32 / X64) build commands edk2.git.spec? Thanks! Laszlo > > ... Anyway I better read "23.7 HTTP Boot" now. > > Thanks! > Laszlo > >> >> Best Regards >> Siyuan >> >> -----Original Message----- >> From: Laszlo Ersek [mailto:[email protected]] >> Sent: Tuesday, January 5, 2016 7:26 PM >> To: Fu, Siyuan <[email protected]> >> Cc: [email protected]; Ye, Ting <[email protected]>; Wu, Jiaxin >> <[email protected]> >> Subject: Re: [edk2] [PATCH v2] MdeModulePkg: Update MNP driver to recycle TX >> buffer asynchronously. >> >> On 01/05/16 04:37, Fu Siyuan wrote: >>> This patch updates the MNP driver to recycle TX buffer asynchronously, >>> instead of using a while loop wait after each transmit command. >>> This patch also fixes a bug in SNP.GetStatus() interface to support >>> the MNP update. The UNDI driver may return multiple transmitted >>> buffers in a single GetStatus command, while SNP.GetStatus could only >>> return one pointer each time, the rest of them are lost. This patch >>> fixes this issue by store these recycled pointer in a temporary buffer in >>> SNP driver. >> >> (1) Would it be possible to separate these two changes? For example, would >> the following work? >> >> - The first patch updates only SnpDxe. >> >> Since the SnpDxe changes should only affect SnpDxe internals -- the >> buffering of recycled UNDI TX buffers is internal to SNP, and not visible to >> MNP --, patching only SnpDxe in the first step should not break MNP. >> >> - The second patch updates only MnpDxe; implementing the asynchronous >> recycling. This would be supported by SnpDxe with the first patch applied. >> >> (2) Is there a good way to test the asynchronism? Like an easily available >> UEFI application, or a UEFI shell command? >> >> I think this MNP change is good idea. Is it also observable for an >> interactive user (e.g., better transfer speed with the TFTP command, or >> something similar)? >> >> Thanks! >> Laszlo >> >> >>> >>> Contributed-under: TianoCore Contribution Agreement 1.0 >>> Signed-off-by: Fu Siyuan <[email protected]> >>> --- >>> MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c | 266 >>> ++++++++++++++++++--- >>> MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h | 7 +- >>> MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h | 45 +++- >>> MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c | 118 ++++----- >>> MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c | 7 +- >>> MdeModulePkg/Universal/Network/SnpDxe/Get_status.c | 73 ++++-- >>> MdeModulePkg/Universal/Network/SnpDxe/Snp.c | 16 +- >>> MdeModulePkg/Universal/Network/SnpDxe/Snp.h | 18 +- >>> 8 files changed, 421 insertions(+), 129 deletions(-) >>> >>> diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c >>> b/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c >>> index 046d4df..d1a4cb5 100644 >>> --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c >>> +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c >>> @@ -1,7 +1,7 @@ >>> /** @file >>> Implementation of Managed Network Protocol private services. >>> >>> -Copyright (c) 2005 - 2012, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2005 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full @@ -209,6 +209,208 @@ >>> MnpFreeNbuf ( >>> gBS->RestoreTPL (OldTpl); >>> } >>> >>> +/** >>> + Add Count of TX buffers to MnpDeviceData->AllTxBufList and >>> MnpDeviceData->FreeTxBufList. >>> + The length of the buffer is specified by MnpDeviceData->BufferLength. >>> + >>> + @param[in, out] MnpDeviceData Pointer to the MNP_DEVICE_DATA. >>> + @param[in] Count Number of TX buffers to add. >>> + >>> + @retval EFI_SUCCESS The specified amount of TX buffers are >>> allocated. >>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate a TX buffer. >>> + >>> +**/ >>> +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; >>> +} >>> + >>> +/** >>> + Allocate a free TX buffer from MnpDeviceData->FreeTxBufList. If >>> +there is none >>> + in the queue, first try to recycle some from SNP, then try to >>> +allocate some and add >>> + them into the queue, then fetch the NET_BUF from the updated >>> FreeTxBufList. >>> + >>> + @param[in, out] MnpDeviceData Pointer to the MNP_DEVICE_DATA. >>> + >>> + @return Pointer to the allocated free NET_BUF structure, if NULL the >>> + operation is failed. >>> + >>> +**/ >>> +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)) { >>> + // >>> + // First try to recycle some TX buffer from SNP >>> + // >>> + Status = MnpRecycleTxBuf (MnpDeviceData); >>> + if (EFI_ERROR (Status)) { >>> + TxBuf = NULL; >>> + goto ON_EXIT; >>> + } >>> + >>> + // >>> + // If still no free TX buffer, allocate more. >>> + // >>> + 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 TxBuf into the FreeTxBufList, >>> %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->InUse = TRUE; >>> + TxBuf = TxBufWrap->TxBuf; >>> + >>> +ON_EXIT: >>> + gBS->RestoreTPL (OldTpl); >>> + >>> + return TxBuf; >>> +} >>> + >>> +/** >>> + Try to reclaim the TX buffer into the buffer pool. >>> + >>> + @param[in, out] MnpDeviceData Pointer to the mnp device context >>> data. >>> + @param[in, out] TxBuf Pointer to the TX buffer to free. >>> + >>> +**/ >>> +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); >>> + >>> + 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); >>> +} >>> + >>> +/** >>> + Try to recycle all the transmitted buffer address from SNP. >>> + >>> + @param[in, out] MnpDeviceData Pointer to the mnp device context >>> data. >>> + >>> + @retval EFI_SUCCESS Successed to recyclethe transmitted >>> buffer address. >>> + @retval Others Failed to recyclethe transmitted buffer >>> address. >>> + >>> +**/ >>> +EFI_STATUS >>> +MnpRecycleTxBuf ( >>> + IN OUT MNP_DEVICE_DATA *MnpDeviceData >>> + ) >>> +{ >>> + UINT8 *TxBuf; >>> + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; >>> + EFI_STATUS Status; >>> + >>> + Snp = MnpDeviceData->Snp; >>> + ASSERT (Snp != NULL); >>> + >>> + 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; >>> +} >>> >>> /** >>> Initialize the mnp device context data. >>> @@ -314,13 +516,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 +568,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 +589,6 @@ ERROR: >>> gBS->CloseEvent (MnpDeviceData->PollTimer); >>> } >>> >>> - if (MnpDeviceData->TxBuf != NULL) { >>> - FreePool (MnpDeviceData->TxBuf); >>> - } >>> - >>> if (MnpDeviceData->RxNbufCache != NULL) { >>> MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache); >>> } >>> @@ -445,6 +625,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 +646,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. >>> @@ -957,7 +1147,7 @@ MnpStartSnp ( >>> /** >>> Stop the simple network. >>> >>> - @param[in] Snp Pointer to the simple network protocol. >>> + @param[in] MnpDeviceData Pointer to the MNP_DEVICE_DATA. >>> >>> @retval EFI_SUCCESS The simple network is stopped. >>> @retval Others Other errors as indicated. >>> @@ -965,14 +1155,24 @@ MnpStartSnp ( >>> **/ >>> EFI_STATUS >>> MnpStopSnp ( >>> - IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp >>> + IN MNP_DEVICE_DATA *MnpDeviceData >>> ) >>> { >>> EFI_STATUS Status; >>> - >>> + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; >>> + >>> + Snp = MnpDeviceData->Snp; >>> ASSERT (Snp != NULL); >>> >>> // >>> + // Recycle all the transmit buffer from SNP. >>> + // >>> + Status = MnpRecycleTxBuf (MnpDeviceData); if (EFI_ERROR (Status)) >>> + { >>> + return Status; >>> + } >>> + >>> + // >>> // Shut down the simple network. >>> // >>> Status = Snp->Shutdown (Snp); >>> @@ -1162,7 +1362,7 @@ MnpStop ( >>> // >>> // Stop the simple network. >>> // >>> - Status = MnpStopSnp (MnpDeviceData->Snp); >>> + Status = MnpStopSnp (MnpDeviceData); >>> return Status; >>> } >>> >>> diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h >>> b/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h >>> index 35a9b71..126d968 100644 >>> --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h >>> +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h >>> @@ -1,7 +1,7 @@ >>> /** @file >>> Declaration of strctures and functions for MnpDxe driver. >>> >>> -Copyright (c) 2005 - 2012, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2005 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full @@ -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..dd9ad32 100644 >>> --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h >>> +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h >>> @@ -1,7 +1,7 @@ >>> /** @file >>> Declaration of structures and functions of MnpDxe driver. >>> >>> -Copyright (c) 2005 - 2010, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2005 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full @@ -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, >>> @@ -449,6 +460,36 @@ MnpFreeNbuf ( >>> ); >>> >>> /** >>> + Allocate a free TX buffer from MnpDeviceData->FreeTxBufList. If >>> + there is none in the queue, first try to recycle some from SNP, >>> + then try to allocate some and add them into the queue, then fetch the >>> NET_BUF from the updated FreeTxBufList. >>> + >>> + @param[in, out] MnpDeviceData Pointer to the MNP_DEVICE_DATA. >>> + >>> + @return Pointer to the allocated free NET_BUF structure, if NULL the >>> + operation is failed. >>> + >>> +**/ >>> +UINT8 * >>> +MnpAllocTxBuf ( >>> + IN OUT MNP_DEVICE_DATA *MnpDeviceData >>> + ); >>> + >>> +/** >>> + Try to recycle all the transmitted buffer address from SNP. >>> + >>> + @param[in, out] MnpDeviceData Pointer to the mnp device context >>> data. >>> + >>> + @retval EFI_SUCCESS Successed to recyclethe transmitted >>> buffer address. >>> + @retval Others Failed to recyclethe transmitted buffer >>> address. >>> + >>> +**/ >>> +EFI_STATUS >>> +MnpRecycleTxBuf ( >>> + IN OUT MNP_DEVICE_DATA *MnpDeviceData >>> + ); >>> + >>> +/** >>> Remove the received packets if timeout occurs. >>> >>> @param[in] Event The event this notify function registered to. >>> diff --git a/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c >>> b/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c >>> index 7f03b84..45ba1b9 100644 >>> --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c >>> +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c >>> @@ -1,7 +1,7 @@ >>> /** @file >>> Implementation of Managed Network Protocol I/O functions. >>> >>> -Copyright (c) 2005 - 2014, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2005 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full @@ -102,7 +102,6 @@ >>> MnpIsValidTxToken ( >>> return TRUE; >>> } >>> >>> - >>> /** >>> Build the packet to transmit from the TxData passed in. >>> >>> @@ -114,7 +113,7 @@ MnpIsValidTxToken ( >>> length. >>> >>> **/ >>> -VOID >>> +EFI_STATUS >>> MnpBuildTxPacket ( >>> IN MNP_SERVICE_DATA *MnpServiceData, >>> IN EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData, >>> @@ -125,14 +124,24 @@ MnpBuildTxPacket ( >>> EFI_SIMPLE_NETWORK_MODE *SnpMode; >>> UINT8 *DstPos; >>> UINT16 Index; >>> - MNP_DEVICE_DATA *MnpDerviceData; >>> - >>> - MnpDerviceData = MnpServiceData->MnpDeviceData; >>> - >>> + MNP_DEVICE_DATA *MnpDeviceData; >>> + UINT8 *TxBuf; >>> + >>> + MnpDeviceData = MnpServiceData->MnpDeviceData; >>> + >>> + TxBuf = MnpAllocTxBuf (MnpDeviceData); if (TxBuf == NULL) { >>> + return EFI_OUT_OF_RESOURCES; >>> + } >>> + >>> // >>> - // Reserve space for vlan tag. >>> + // 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 +157,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 +186,8 @@ >>> MnpBuildTxPacket ( >>> // >>> *PktLen += TxData->DataLength + TxData->HeaderLength; >>> } >>> + >>> + return EFI_SUCCESS; >>> } >>> >>> >>> @@ -205,14 +216,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 +234,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,10 +248,25 @@ MnpSyncSendPacket ( >>> ProtocolType = TxData->ProtocolType; >>> } >>> >>> - for (;;) { >>> - // >>> - // Transmit the packet through SNP. >>> - // >>> + // >>> + // Transmit the packet through SNP. >>> + // >>> + Status = Snp->Transmit ( >>> + Snp, >>> + HeaderSize, >>> + Length, >>> + Packet, >>> + TxData->SourceAddress, >>> + TxData->DestinationAddress, >>> + &ProtocolType >>> + ); >>> + if (Status == EFI_NOT_READY) { >>> + Status = MnpRecycleTxBuf (MnpDeviceData); >>> + if (EFI_ERROR (Status)) { >>> + Token->Status = EFI_DEVICE_ERROR; >>> + goto SIGNAL_TOKEN; >>> + } >>> + >>> Status = Snp->Transmit ( >>> Snp, >>> HeaderSize, >>> @@ -262,52 +275,15 @@ MnpSyncSendPacket ( >>> 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 >>> - ); >>> - } >>> + ); >>> + } >>> + >>> + if (EFI_ERROR (Status)) { >>> + Token->Status = EFI_DEVICE_ERROR; >>> } >>> - >>> - // >>> - // Cancel the timer event. >>> - // >>> - gBS->SetTimer (MnpDeviceData->TxTimeoutEvent, TimerCancel, 0); >>> >>> 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..31c2e3e 100644 >>> --- a/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c >>> +++ b/MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c >>> @@ -1,7 +1,7 @@ >>> /** @file >>> Implementation of Managed Network Protocol public services. >>> >>> -Copyright (c) 2005 - 2010, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2005 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full @@ -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. >>> diff --git a/MdeModulePkg/Universal/Network/SnpDxe/Get_status.c >>> b/MdeModulePkg/Universal/Network/SnpDxe/Get_status.c >>> index 0532976..8f2ab9b 100644 >>> --- a/MdeModulePkg/Universal/Network/SnpDxe/Get_status.c >>> +++ b/MdeModulePkg/Universal/Network/SnpDxe/Get_status.c >>> @@ -2,7 +2,7 @@ >>> Implementation of reading the current interrupt status and recycled >>> transmit >>> buffer status from a network interface. >>> >>> -Copyright (c) 2004 - 2010, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2004 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full text of the license may be >>> found at @@ -16,15 +16,15 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY >>> KIND, EITHER EXPRESS OR IMPLIED. >>> #include "Snp.h" >>> >>> /** >>> - Call undi to get the status of the interrupts, get the list of >>> transmit >>> - buffers that completed transmitting. >>> + Call undi to get the status of the interrupts, get the list of >>> + recycled transmit buffers that completed transmitting. The recycled >>> + transmit buffer address will be saved into Snp->RecycledTxBuf. >>> >>> @param Snp Pointer to snp driver structure. >>> @param InterruptStatusPtr A non null pointer to contain the >>> interrupt >>> status. >>> - @param TransmitBufferListPtrs A non null pointer to contain the list of >>> - pointers of previous transmitted buffers >>> whose >>> - transmission was completed asynchrnously. >>> + @param GetTransmittedBuf Set to TRUE to retrieve the recycled >>> transmit >>> + buffer address. >>> >>> @retval EFI_SUCCESS The status of the network interface was >>> retrieved. >>> @retval EFI_DEVICE_ERROR The command could not be sent to the network >>> @@ -35,19 +35,23 @@ EFI_STATUS >>> PxeGetStatus ( >>> SNP_DRIVER *Snp, >>> UINT32 *InterruptStatusPtr, >>> - VOID **TransmitBufferListPtr >>> + BOOLEAN GetTransmittedBuf >>> ) >>> { >>> PXE_DB_GET_STATUS *Db; >>> UINT16 InterruptFlags; >>> + UINT32 Index; >>> + UINT64 *Tmp; >>> >>> + Tmp = NULL; >>> Db = Snp->Db; >>> Snp->Cdb.OpCode = PXE_OPCODE_GET_STATUS; >>> >>> Snp->Cdb.OpFlags = 0; >>> >>> - if (TransmitBufferListPtr != NULL) { >>> + if (GetTransmittedBuf) { >>> Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS; >>> + ZeroMem (Db->TxBuffer, sizeof (Db->TxBuffer)); >>> } >>> >>> if (InterruptStatusPtr != NULL) { >>> @@ -116,13 +120,34 @@ PxeGetStatus ( >>> >>> } >>> >>> - if (TransmitBufferListPtr != NULL) { >>> - *TransmitBufferListPtr = >>> - ( >>> - ((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) >>> != 0) || >>> - ((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY) >>> != 0) >>> - ) ? 0 : (VOID *) (UINTN) Db->TxBuffer[0]; >>> - >>> + if (GetTransmittedBuf) { >>> + if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) >>> == 0) { >>> + // >>> + // UNDI has written some transmitted buffer addresses into the DB. >>> Store them into Snp->RecycledTxBuf. >>> + // >>> + for (Index = 0; Index < MAX_XMIT_BUFFERS; Index++) { >>> + if (Db->TxBuffer[Index] != 0) { >>> + if (Snp->RecycledTxBufCount == Snp->MaxRecycledTxBuf) { >>> + // >>> + // Snp->RecycledTxBuf is full, reallocate a new one. >>> + // >>> + if ((Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= >>> SNP_MAX_TX_BUFFER_NUM) { >>> + return EFI_DEVICE_ERROR; >>> + } >>> + Tmp = AllocatePool (sizeof (UINT64) * (Snp->MaxRecycledTxBuf + >>> SNP_TX_BUFFER_INCREASEMENT)); >>> + if (Tmp == NULL) { >>> + return EFI_DEVICE_ERROR; >>> + } >>> + CopyMem (Tmp, Snp->RecycledTxBuf, sizeof (UINT64) * >>> Snp->RecycledTxBufCount); >>> + FreePool (Snp->RecycledTxBuf); >>> + Snp->RecycledTxBuf = Tmp; >>> + Snp->MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT; >>> + } >>> + Snp->RecycledTxBuf[Snp->RecycledTxBufCount] = >>> Db->TxBuffer[Index]; >>> + Snp->RecycledTxBufCount++; >>> + } >>> + } >>> + } >>> } >>> >>> // >>> @@ -216,7 +241,23 @@ SnpUndi32GetStatus ( >>> goto ON_EXIT; >>> } >>> >>> - Status = PxeGetStatus (Snp, InterruptStatus, TxBuf); >>> + if (Snp->RecycledTxBufCount == 0 && TxBuf != NULL) { >>> + Status = PxeGetStatus (Snp, InterruptStatus, TRUE); } else { >>> + Status = PxeGetStatus (Snp, InterruptStatus, FALSE); } >>> + >>> + if (TxBuf != NULL) { >>> + // >>> + // Get a recycled buf from Snp->RecycledTxBuf >>> + // >>> + if (Snp->RecycledTxBufCount == 0) { >>> + *TxBuf = NULL; >>> + } else { >>> + Snp->RecycledTxBufCount--; >>> + *TxBuf = (VOID *) (UINTN) >>> Snp->RecycledTxBuf[Snp->RecycledTxBufCount]; >>> + } >>> + } >>> >>> ON_EXIT: >>> gBS->RestoreTPL (OldTpl); >>> diff --git a/MdeModulePkg/Universal/Network/SnpDxe/Snp.c >>> b/MdeModulePkg/Universal/Network/SnpDxe/Snp.c >>> index db5b626..5ff294f 100644 >>> --- a/MdeModulePkg/Universal/Network/SnpDxe/Snp.c >>> +++ b/MdeModulePkg/Universal/Network/SnpDxe/Snp.c >>> @@ -1,7 +1,7 @@ >>> /** @file >>> Implementation of driver entry point and driver binding protocol. >>> >>> -Copyright (c) 2004 - 2015, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2004 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full text of the license may be >>> found at @@ -403,6 +403,14 @@ SimpleNetworkDriverStart ( >>> >>> Snp->TxRxBufferSize = 0; >>> Snp->TxRxBuffer = NULL; >>> + >>> + Snp->RecycledTxBuf = AllocatePool (sizeof (UINT64) * >>> + SNP_TX_BUFFER_INCREASEMENT); if (Snp->RecycledTxBuf == NULL) { >>> + Status = EFI_OUT_OF_RESOURCES; >>> + goto Error_DeleteSNP; >>> + } >>> + Snp->MaxRecycledTxBuf = SNP_TX_BUFFER_INCREASEMENT; >>> + Snp->RecycledTxBufCount = 0; >>> >>> if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) >>> { >>> Snp->IfNum = Nii->IfNum; >>> @@ -678,6 +686,10 @@ SimpleNetworkDriverStart ( >>> >>> Error_DeleteSNP: >>> >>> + if (Snp->RecycledTxBuf != NULL) { >>> + FreePool (Snp->RecycledTxBuf); >>> + } >>> + >>> PciIo->FreeBuffer ( >>> PciIo, >>> SNP_MEM_PAGES (sizeof (SNP_DRIVER)), @@ -790,6 +802,8 @@ >>> SimpleNetworkDriverStop ( >>> PxeShutdown (Snp); >>> PxeStop (Snp); >>> >>> + FreePool (Snp->RecycledTxBuf); >>> + >>> PciIo = Snp->PciIo; >>> PciIo->FreeBuffer ( >>> PciIo, >>> diff --git a/MdeModulePkg/Universal/Network/SnpDxe/Snp.h >>> b/MdeModulePkg/Universal/Network/SnpDxe/Snp.h >>> index f1d0ab3..67f65ff 100644 >>> --- a/MdeModulePkg/Universal/Network/SnpDxe/Snp.h >>> +++ b/MdeModulePkg/Universal/Network/SnpDxe/Snp.h >>> @@ -1,7 +1,7 @@ >>> /** @file >>> Declaration of strctures and functions for SnpDxe driver. >>> >>> -Copyright (c) 2004 - 2014, Intel Corporation. All rights >>> reserved.<BR> >>> +Copyright (c) 2004 - 2016, Intel Corporation. All rights >>> +reserved.<BR> >>> This program and the accompanying materials are licensed and made >>> available under the terms and conditions of the BSD License which >>> accompanies this distribution. The full text of the license may be >>> found at @@ -49,6 +49,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY >>> KIND, EITHER EXPRESS OR IMPLIED. >>> #define PCI_BAR_MEM_MODE 0x00000000 >>> #define PCI_BAR_MEM_64BIT 0x00000004 >>> >>> +#define SNP_TX_BUFFER_INCREASEMENT MAX_XMIT_BUFFERS >>> +#define SNP_MAX_TX_BUFFER_NUM 65536 >>> + >>> typedef >>> EFI_STATUS >>> (EFIAPI *ISSUE_UNDI32_COMMAND) ( >>> @@ -130,6 +133,19 @@ typedef struct { >>> // i.e. PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED >>> // >>> BOOLEAN MediaStatusSupported; >>> + >>> + // >>> + // Array of the recycled transmit buffer address from UNDI. >>> + // >>> + UINT64 *RecycledTxBuf; >>> + // >>> + // The maximum number of recycled buffer pointers in RecycledTxBuf. >>> + // >>> + UINT32 MaxRecycledTxBuf; >>> + // >>> + // Current number of recycled buffer pointers in RecycledTxBuf. >>> + // >>> + UINT32 RecycledTxBufCount; >>> } SNP_DRIVER; >>> >>> #define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) CR (a, SNP_DRIVER, Snp, >>> SNP_DRIVER_SIGNATURE) >>> >> > > _______________________________________________ > edk2-devel mailing list > [email protected] > https://lists.01.org/mailman/listinfo/edk2-devel > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

