On 01/07/16 11:32, Gary Lin wrote: > On Wed, Jan 06, 2016 at 01:28:40PM +0100, 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 used dnsmasq to setup a DHCP server for HTTP boot before. > Just 2 more options in my config: > > dhcp-option=60,"HTTPClient" > dhcp-boot="http://192.168.111.1/default.efi" > > Hope this helps.
Stashing this for later, many thanks. Laszlo > > Cheers, > > Gary Lin > >> 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? >> >> ... Anyway I better read "23.7 HTTP Boot" now. >> >> Thanks! >> Laszlo >> >>> >>> Best Regards >>> Siyuan >>> >>> -----Original Message----- >>> From: Laszlo Ersek [mailto:ler...@redhat.com] >>> Sent: Tuesday, January 5, 2016 7:26 PM >>> To: Fu, Siyuan <siyuan...@intel.com> >>> Cc: edk2-de...@ml01.01.org; Ye, Ting <ting...@intel.com>; Wu, Jiaxin >>> <jiaxin...@intel.com> >>> 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 <siyuan...@intel.com> >>>> --- >>>> 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 >> edk2-devel@lists.01.org >> https://lists.01.org/mailman/listinfo/edk2-devel >> > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel