Siyuan,
Some small comments:
1. Please update MnpBuildTxPacket() function's description.
2. Since Mnp Sent the packet asynchronously, MnpSyncSendPacket() function's 
name is improper, the corresponding description also should be updated.

Other parts good to me.

Reviewed-by: Jiaxin Wu <[email protected]>

Thanks.
Jiaxin


-----Original Message-----
From: edk2-devel [mailto:[email protected]] On Behalf Of Fu Siyuan
Sent: Tuesday, January 5, 2016 11:37 AM
To: [email protected]
Cc: Ye, Ting; Wu, Jiaxin
Subject: [edk2] [PATCH v2] MdeModulePkg: Update MNP driver to recycle TX buffer 
asynchronously.

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.

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)
--
2.5.0.windows.1

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to