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