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? ... 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

