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

Reply via email to