MdeModulePkg: Update MNP driver to recycle TX buffer asynchronously.
authorFu Siyuan <siyuan.fu@intel.com>
Fri, 8 Jan 2016 02:38:34 +0000 (02:38 +0000)
committersfu5 <sfu5@Edk2>
Fri, 8 Jan 2016 02:38:34 +0000 (02:38 +0000)
This patch updates the MNP driver to recycle TX buffer asynchronously, instead
of using a while loop wait after each transmit command.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com>
Reviewed-by: Ye Ting <ting.ye@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19624 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c
MdeModulePkg/Universal/Network/MnpDxe/MnpDriver.h
MdeModulePkg/Universal/Network/MnpDxe/MnpImpl.h
MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c
MdeModulePkg/Universal/Network/MnpDxe/MnpMain.c

index 046d4df..d1a4cb5 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Implementation of Managed Network Protocol private services.\r
 \r
-Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
 of the BSD License which accompanies this distribution.  The full\r
@@ -209,6 +209,208 @@ MnpFreeNbuf (
   gBS->RestoreTPL (OldTpl);\r
 }\r
 \r
+/**\r
+  Add Count of TX buffers to MnpDeviceData->AllTxBufList and MnpDeviceData->FreeTxBufList.\r
+  The length of the buffer is specified by MnpDeviceData->BufferLength.\r
+\r
+  @param[in, out]  MnpDeviceData         Pointer to the MNP_DEVICE_DATA.\r
+  @param[in]       Count                 Number of TX buffers to add.\r
+\r
+  @retval EFI_SUCCESS           The specified amount of TX buffers are allocated.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate a TX buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpAddFreeTxBuf (\r
+  IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
+  IN     UINTN             Count\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  UINT32            Index;\r
+  MNP_TX_BUF_WRAP   *TxBufWrap;\r
+\r
+  NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
+  ASSERT ((Count > 0) && (MnpDeviceData->BufferLength > 0));\r
+\r
+  Status = EFI_SUCCESS;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    TxBufWrap = (MNP_TX_BUF_WRAP*) AllocatePool (sizeof (MNP_TX_BUF_WRAP) + MnpDeviceData->BufferLength - 1);\r
+    if (TxBufWrap == NULL) {\r
+      DEBUG ((EFI_D_ERROR, "MnpAddFreeTxBuf: TxBuf Alloc failed.\n"));\r
+\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+    DEBUG ((EFI_D_INFO, "MnpAddFreeTxBuf: Add TxBufWrap %p, TxBuf %p\n", TxBufWrap, TxBufWrap->TxBuf));\r
+    TxBufWrap->Signature = MNP_TX_BUF_WRAP_SIGNATURE;\r
+    TxBufWrap->InUse     = FALSE;\r
+    InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry);\r
+    InsertTailList (&MnpDeviceData->AllTxBufList, &TxBufWrap->AllEntry);\r
+  }\r
+\r
+  MnpDeviceData->TxBufCount += Index;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Allocate a free TX buffer from MnpDeviceData->FreeTxBufList. If there is none\r
+  in the queue, first try to recycle some from SNP, then try to allocate some and add \r
+  them into the queue, then fetch the NET_BUF from the updated FreeTxBufList.\r
+\r
+  @param[in, out]  MnpDeviceData        Pointer to the MNP_DEVICE_DATA.\r
+\r
+  @return     Pointer to the allocated free NET_BUF structure, if NULL the\r
+              operation is failed.\r
+\r
+**/\r
+UINT8 *\r
+MnpAllocTxBuf (\r
+  IN OUT MNP_DEVICE_DATA   *MnpDeviceData\r
+  )\r
+{\r
+  EFI_TPL           OldTpl;\r
+  UINT8             *TxBuf;\r
+  EFI_STATUS        Status;\r
+  LIST_ENTRY        *Entry;\r
+  MNP_TX_BUF_WRAP   *TxBufWrap;\r
+  \r
+  NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {\r
+    //\r
+    // First try to recycle some TX buffer from SNP\r
+    //\r
+    Status = MnpRecycleTxBuf (MnpDeviceData);\r
+    if (EFI_ERROR (Status)) {\r
+      TxBuf = NULL;\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    //\r
+    // If still no free TX buffer, allocate more.\r
+    //\r
+    if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {\r
+      if ((MnpDeviceData->TxBufCount + MNP_TX_BUFFER_INCREASEMENT) > MNP_MAX_TX_BUFFER_NUM) {\r
+        DEBUG (\r
+          (EFI_D_ERROR,\r
+          "MnpAllocTxBuf: The maximum TxBuf size is reached for MNP driver instance %p.\n",\r
+          MnpDeviceData)\r
+          );\r
+\r
+        TxBuf = NULL;\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Status = MnpAddFreeTxBuf (MnpDeviceData, MNP_TX_BUFFER_INCREASEMENT);\r
+      if (IsListEmpty (&MnpDeviceData->FreeTxBufList)) {\r
+        DEBUG (\r
+          (EFI_D_ERROR,\r
+          "MnpAllocNbuf: Failed to add TxBuf into the FreeTxBufList, %r.\n",\r
+          Status)\r
+          );\r
+\r
+        TxBuf = NULL;\r
+        goto ON_EXIT;\r
+      }\r
+    }\r
+  }\r
+\r
+  ASSERT (!IsListEmpty (&MnpDeviceData->FreeTxBufList));\r
+  Entry = MnpDeviceData->FreeTxBufList.ForwardLink;\r
+  RemoveEntryList (MnpDeviceData->FreeTxBufList.ForwardLink);\r
+  TxBufWrap = NET_LIST_USER_STRUCT_S (Entry, MNP_TX_BUF_WRAP, WrapEntry, MNP_TX_BUF_WRAP_SIGNATURE);\r
+  TxBufWrap->InUse = TRUE;\r
+  TxBuf = TxBufWrap->TxBuf;\r
+\r
+ON_EXIT:\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return TxBuf;\r
+}\r
+\r
+/**\r
+  Try to reclaim the TX buffer into the buffer pool.\r
+\r
+  @param[in, out]  MnpDeviceData         Pointer to the mnp device context data.\r
+  @param[in, out]  TxBuf                 Pointer to the TX buffer to free.\r
+\r
+**/\r
+VOID\r
+MnpFreeTxBuf (\r
+  IN OUT MNP_DEVICE_DATA   *MnpDeviceData,\r
+  IN OUT UINT8             *TxBuf\r
+  )\r
+{\r
+  MNP_TX_BUF_WRAP   *TxBufWrap;\r
+  EFI_TPL           OldTpl;\r
+\r
+  NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
+\r
+  if (TxBuf == NULL) {\r
+    return;\r
+  }\r
+\r
+  TxBufWrap = NET_LIST_USER_STRUCT (TxBuf, MNP_TX_BUF_WRAP, TxBuf);\r
+  if (TxBufWrap->Signature != MNP_TX_BUF_WRAP_SIGNATURE) {\r
+    DEBUG (\r
+      (EFI_D_ERROR,\r
+      "MnpFreeTxBuf: Signature check failed in MnpFreeTxBuf.\n")\r
+      );\r
+    return;\r
+  }\r
+\r
+  if (!TxBufWrap->InUse) {\r
+    DEBUG (\r
+      (EFI_D_WARN,\r
+      "MnpFreeTxBuf: Duplicated recycle report from SNP.\n")\r
+      );\r
+    return;\r
+  }\r
+  \r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  InsertTailList (&MnpDeviceData->FreeTxBufList, &TxBufWrap->WrapEntry);\r
+  TxBufWrap->InUse = FALSE;\r
+  gBS->RestoreTPL (OldTpl);\r
+}\r
+\r
+/**\r
+  Try to recycle all the transmitted buffer address from SNP.\r
+\r
+  @param[in, out]  MnpDeviceData     Pointer to the mnp device context data.\r
+\r
+  @retval EFI_SUCCESS             Successed to recyclethe transmitted buffer address.\r
+  @retval Others                  Failed to recyclethe transmitted buffer address.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpRecycleTxBuf (\r
+  IN OUT MNP_DEVICE_DATA   *MnpDeviceData\r
+  )\r
+{\r
+  UINT8                         *TxBuf;\r
+  EFI_SIMPLE_NETWORK_PROTOCOL   *Snp;\r
+  EFI_STATUS                    Status;\r
+\r
+  Snp = MnpDeviceData->Snp;\r
+  ASSERT (Snp != NULL);\r
+\r
+  do {\r
+    TxBuf = NULL;\r
+    Status = Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (TxBuf != NULL) {\r
+      MnpFreeTxBuf (MnpDeviceData, TxBuf);\r
+    }\r
+  } while (TxBuf != NULL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   Initialize the mnp device context data.\r
@@ -314,13 +516,9 @@ MnpInitializeDeviceData (
   //\r
   // Allocate buffer pool for tx.\r
   //\r
-  MnpDeviceData->TxBuf = AllocatePool (MnpDeviceData->BufferLength);\r
-  if (MnpDeviceData->TxBuf == NULL) {\r
-    DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: AllocatePool failed.\n"));\r
-\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ERROR;\r
-  }\r
+  InitializeListHead (&MnpDeviceData->FreeTxBufList);\r
+  InitializeListHead (&MnpDeviceData->AllTxBufList);\r
+  MnpDeviceData->TxBufCount = 0;\r
 \r
   //\r
   // Create the system poll timer.\r
@@ -370,20 +568,6 @@ MnpInitializeDeviceData (
     goto ERROR;\r
   }\r
 \r
-  //\r
-  // Create the timer for tx timeout check.\r
-  //\r
-  Status = gBS->CreateEvent (\r
-                  EVT_TIMER,\r
-                  TPL_CALLBACK,\r
-                  NULL,\r
-                  NULL,\r
-                  &MnpDeviceData->TxTimeoutEvent\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MnpInitializeDeviceData: CreateEvent for tx timeout event failed.\n"));\r
-  }\r
-\r
 ERROR:\r
   if (EFI_ERROR (Status)) {\r
     //\r
@@ -405,10 +589,6 @@ ERROR:
       gBS->CloseEvent (MnpDeviceData->PollTimer);\r
     }\r
 \r
-    if (MnpDeviceData->TxBuf != NULL) {\r
-      FreePool (MnpDeviceData->TxBuf);\r
-    }\r
-\r
     if (MnpDeviceData->RxNbufCache != NULL) {\r
       MnpFreeNbuf (MnpDeviceData, MnpDeviceData->RxNbufCache);\r
     }\r
@@ -445,6 +625,10 @@ MnpDestroyDeviceData (
   IN     EFI_HANDLE        ImageHandle\r
   )\r
 {\r
+  LIST_ENTRY         *Entry;\r
+  LIST_ENTRY         *NextEntry;\r
+  MNP_TX_BUF_WRAP    *TxBufWrap;\r
+\r
   NET_CHECK_SIGNATURE (MnpDeviceData, MNP_DEVICE_DATA_SIGNATURE);\r
 \r
   //\r
@@ -462,15 +646,21 @@ MnpDestroyDeviceData (
   //\r
   // Close the event.\r
   //\r
-  gBS->CloseEvent (MnpDeviceData->TxTimeoutEvent);\r
   gBS->CloseEvent (MnpDeviceData->TimeoutCheckTimer);\r
   gBS->CloseEvent (MnpDeviceData->MediaDetectTimer);\r
   gBS->CloseEvent (MnpDeviceData->PollTimer);\r
 \r
   //\r
-  // Free the tx buffer.\r
+  // Free the Tx buffer pool.\r
   //\r
-  FreePool (MnpDeviceData->TxBuf);\r
+  NET_LIST_FOR_EACH_SAFE(Entry, NextEntry, &MnpDeviceData->AllTxBufList) {\r
+    TxBufWrap = NET_LIST_USER_STRUCT (Entry, MNP_TX_BUF_WRAP, AllEntry);\r
+    RemoveEntryList (Entry);\r
+    FreePool (TxBufWrap);\r
+    MnpDeviceData->TxBufCount--;\r
+  }\r
+  ASSERT (IsListEmpty (&MnpDeviceData->AllTxBufList));\r
+  ASSERT (MnpDeviceData->TxBufCount == 0);\r
 \r
   //\r
   // Free the RxNbufCache.\r
@@ -957,7 +1147,7 @@ MnpStartSnp (
 /**\r
   Stop the simple network.\r
 \r
-  @param[in]  Snp               Pointer to the simple network protocol.\r
+  @param[in]  MnpDeviceData     Pointer to the MNP_DEVICE_DATA.\r
 \r
   @retval EFI_SUCCESS           The simple network is stopped.\r
   @retval Others                Other errors as indicated.\r
@@ -965,13 +1155,23 @@ MnpStartSnp (
 **/\r
 EFI_STATUS\r
 MnpStopSnp (\r
-  IN EFI_SIMPLE_NETWORK_PROTOCOL     *Snp\r
+  IN  MNP_DEVICE_DATA   *MnpDeviceData\r
   )\r
 {\r
   EFI_STATUS  Status;\r
-\r
+  EFI_SIMPLE_NETWORK_PROTOCOL     *Snp;\r
+  \r
+  Snp = MnpDeviceData->Snp;\r
   ASSERT (Snp != NULL);\r
 \r
+  //\r
+  // Recycle all the transmit buffer from SNP.\r
+  //\r
+  Status = MnpRecycleTxBuf (MnpDeviceData);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   //\r
   // Shut down the simple network.\r
   //\r
@@ -1162,7 +1362,7 @@ MnpStop (
   //\r
   // Stop the simple network.\r
   //\r
-  Status = MnpStopSnp (MnpDeviceData->Snp);\r
+  Status = MnpStopSnp (MnpDeviceData);\r
   return Status;\r
 }\r
 \r
index 35a9b71..126d968 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Declaration of strctures and functions for MnpDxe driver.\r
 \r
-Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
 of the BSD License which accompanies this distribution.  The full\r
@@ -67,7 +67,9 @@ typedef struct {
   LIST_ENTRY                    GroupAddressList;\r
   UINT32                        GroupAddressCount;\r
 \r
-  EFI_EVENT                     TxTimeoutEvent;\r
+  LIST_ENTRY                    FreeTxBufList;\r
+  LIST_ENTRY                    AllTxBufList;\r
+  UINT32                        TxBufCount;\r
 \r
   NET_BUF_QUEUE                 FreeNbufQue;\r
   INTN                          NbufCnt;\r
@@ -90,7 +92,6 @@ typedef struct {
   UINT32                        BufferLength;\r
   UINT32                        PaddingSize;\r
   NET_BUF                       *RxNbufCache;\r
-  UINT8                         *TxBuf;\r
 } MNP_DEVICE_DATA;\r
 \r
 #define MNP_DEVICE_DATA_FROM_THIS(a) \\r
index f94e208..c66be64 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Declaration of structures and functions of MnpDxe driver.\r
 \r
-Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
 of the BSD License which accompanies this distribution.  The full\r
@@ -27,6 +27,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #define MNP_INIT_NET_BUFFER_NUM       512\r
 #define MNP_NET_BUFFER_INCREASEMENT   64\r
 #define MNP_MAX_NET_BUFFER_NUM        65536\r
+#define MNP_TX_BUFFER_INCREASEMENT    64\r
+#define MNP_MAX_TX_BUFFER_NUM         65536\r
 \r
 #define MNP_MAX_RCVD_PACKET_QUE_SIZE  256\r
 \r
@@ -92,6 +94,15 @@ typedef struct {
   UINT64                            TimeoutTick;\r
 } MNP_RXDATA_WRAP;\r
 \r
+#define MNP_TX_BUF_WRAP_SIGNATURE   SIGNATURE_32 ('M', 'T', 'B', 'W')\r
+\r
+typedef struct {\r
+  UINT32                  Signature;\r
+  LIST_ENTRY              WrapEntry;  // Link to FreeTxBufList\r
+  LIST_ENTRY              AllEntry;   // Link to AllTxBufList\r
+  BOOLEAN                 InUse;\r
+  UINT8                   TxBuf[1];\r
+} MNP_TX_BUF_WRAP;\r
 \r
 /**\r
   Initialize the mnp device context data.\r
@@ -342,8 +353,11 @@ MnpIsValidTxToken (
   @param[out]  PktLen              Pointer to a UINT32 variable used to record the packet's\r
                                    length.\r
 \r
+  @retval EFI_SUCCESS           TxPackage is built.\r
+  @retval EFI_OUT_OF_RESOURCES  The deliver fails due to lack of memory resource.\r
+\r
 **/\r
-VOID\r
+EFI_STATUS\r
 MnpBuildTxPacket (\r
   IN     MNP_SERVICE_DATA                    *MnpServiceData,\r
   IN     EFI_MANAGED_NETWORK_TRANSMIT_DATA   *TxData,\r
@@ -352,7 +366,11 @@ MnpBuildTxPacket (
   );\r
 \r
 /**\r
-  Synchronously send out the packet.\r
+  Synchronously send out the packet. \r
+\r
+  This functon places the packet buffer to SNP driver's tansmit queue. The packet\r
+  can be considered successfully sent out once SNP acccetp the packet, while the\r
+  packet buffer recycle is deferred for better performance.\r
 \r
   @param[in]       MnpServiceData      Pointer to the mnp service context data.\r
   @param[in]       Packet              Pointer to the pakcet buffer.\r
@@ -448,6 +466,36 @@ MnpFreeNbuf (
   IN OUT NET_BUF           *Nbuf\r
   );\r
 \r
+/**\r
+  Allocate a free TX buffer from MnpDeviceData->FreeTxBufList. If there is none\r
+  in the queue, first try to recycle some from SNP, then try to allocate some and add \r
+  them into the queue, then fetch the NET_BUF from the updated FreeTxBufList.\r
+\r
+  @param[in, out]  MnpDeviceData        Pointer to the MNP_DEVICE_DATA.\r
+\r
+  @return     Pointer to the allocated free NET_BUF structure, if NULL the\r
+              operation is failed.\r
+\r
+**/\r
+UINT8 *\r
+MnpAllocTxBuf (\r
+  IN OUT MNP_DEVICE_DATA   *MnpDeviceData\r
+  );\r
+\r
+/**\r
+  Try to recycle all the transmitted buffer address from SNP.\r
+\r
+  @param[in, out]  MnpDeviceData     Pointer to the mnp device context data.\r
+\r
+  @retval EFI_SUCCESS             Successed to recyclethe transmitted buffer address.\r
+  @retval Others                  Failed to recyclethe transmitted buffer address.\r
+\r
+**/\r
+EFI_STATUS\r
+MnpRecycleTxBuf (\r
+  IN OUT MNP_DEVICE_DATA   *MnpDeviceData\r
+  );\r
+\r
 /**\r
   Remove the received packets if timeout occurs.\r
 \r
index 7f03b84..1cbfc30 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Implementation of Managed Network Protocol I/O functions.\r
 \r
-Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
 of the BSD License which accompanies this distribution.  The full\r
@@ -102,7 +102,6 @@ MnpIsValidTxToken (
   return TRUE;\r
 }\r
 \r
-\r
 /**\r
   Build the packet to transmit from the TxData passed in.\r
 \r
@@ -113,8 +112,11 @@ MnpIsValidTxToken (
   @param[out]  PktLen              Pointer to a UINT32 variable used to record the packet's\r
                                    length.\r
 \r
+  @retval EFI_SUCCESS           TxPackage is built.\r
+  @retval EFI_OUT_OF_RESOURCES  The deliver fails due to lack of memory resource.\r
+\r
 **/\r
-VOID\r
+EFI_STATUS\r
 MnpBuildTxPacket (\r
   IN     MNP_SERVICE_DATA                    *MnpServiceData,\r
   IN     EFI_MANAGED_NETWORK_TRANSMIT_DATA   *TxData,\r
@@ -125,14 +127,24 @@ MnpBuildTxPacket (
   EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
   UINT8                   *DstPos;\r
   UINT16                  Index;\r
-  MNP_DEVICE_DATA         *MnpDerviceData;\r
-\r
-  MnpDerviceData = MnpServiceData->MnpDeviceData;\r
-\r
+  MNP_DEVICE_DATA         *MnpDeviceData;\r
+  UINT8                   *TxBuf;\r
+  \r
+  MnpDeviceData = MnpServiceData->MnpDeviceData;\r
+  \r
+  TxBuf = MnpAllocTxBuf (MnpDeviceData);\r
+  if (TxBuf == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
   //\r
-  // Reserve space for vlan tag.\r
+  // Reserve space for vlan tag if needed.\r
   //\r
-  *PktBuf = MnpDerviceData->TxBuf + NET_VLAN_TAG_LEN;\r
+  if (MnpServiceData->VlanId != 0) {\r
+    *PktBuf = TxBuf + NET_VLAN_TAG_LEN;\r
+  } else {\r
+    *PktBuf = TxBuf;\r
+  }\r
   \r
   if ((TxData->DestinationAddress == NULL) && (TxData->FragmentCount == 1)) {\r
     CopyMem (\r
@@ -148,7 +160,7 @@ MnpBuildTxPacket (
     // one fragment, copy the data into the packet buffer. Reserve the\r
     // media header space if necessary.\r
     //\r
-    SnpMode = MnpDerviceData->Snp->Mode; \r
+    SnpMode = MnpDeviceData->Snp->Mode; \r
     DstPos  = *PktBuf;\r
     *PktLen = 0;\r
     if (TxData->DestinationAddress != NULL) {\r
@@ -177,11 +189,17 @@ MnpBuildTxPacket (
     //\r
     *PktLen += TxData->DataLength + TxData->HeaderLength;\r
   }\r
+\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 \r
 /**\r
-  Synchronously send out the packet.\r
+  Synchronously send out the packet. \r
+\r
+  This functon places the packet buffer to SNP driver's tansmit queue. The packet\r
+  can be considered successfully sent out once SNP acccetp the packet, while the\r
+  packet buffer recycle is deferred for better performance.\r
 \r
   @param[in]       MnpServiceData      Pointer to the mnp service context data.\r
   @param[in]       Packet              Pointer to the pakcet buffer.\r
@@ -205,14 +223,13 @@ MnpSyncSendPacket (
   EFI_SIMPLE_NETWORK_PROTOCOL       *Snp;\r
   EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;\r
   UINT32                            HeaderSize;\r
-  UINT8                             *TxBuf;\r
   MNP_DEVICE_DATA                   *MnpDeviceData;\r
   UINT16                            ProtocolType;\r
 \r
   MnpDeviceData = MnpServiceData->MnpDeviceData;\r
   Snp           = MnpDeviceData->Snp;\r
   TxData        = Token->Packet.TxData;\r
-\r
+  Token->Status = EFI_SUCCESS;\r
   HeaderSize    = Snp->Mode->MediaHeaderSize - TxData->HeaderLength;\r
 \r
   //\r
@@ -224,19 +241,7 @@ MnpSyncSendPacket (
     // Media not present, skip packet transmit and report EFI_NO_MEDIA\r
     //\r
     DEBUG ((EFI_D_WARN, "MnpSyncSendPacket: No network cable detected.\n"));\r
-    Status = EFI_NO_MEDIA;\r
-    goto SIGNAL_TOKEN;\r
-  }\r
-\r
-  //\r
-  // Start the timeout event.\r
-  //\r
-  Status = gBS->SetTimer (\r
-                  MnpDeviceData->TxTimeoutEvent,\r
-                  TimerRelative,\r
-                  MNP_TX_TIMEOUT_TIME\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
+    Token->Status = EFI_NO_MEDIA;\r
     goto SIGNAL_TOKEN;\r
   }\r
 \r
@@ -250,10 +255,25 @@ MnpSyncSendPacket (
     ProtocolType = TxData->ProtocolType;\r
   }\r
 \r
-  for (;;) {\r
-    //\r
-    // Transmit the packet through SNP.\r
-    //\r
+  //\r
+  // Transmit the packet through SNP.\r
+  //\r
+  Status = Snp->Transmit (\r
+                  Snp,\r
+                  HeaderSize,\r
+                  Length,\r
+                  Packet,\r
+                  TxData->SourceAddress,\r
+                  TxData->DestinationAddress,\r
+                  &ProtocolType\r
+                  );\r
+  if (Status == EFI_NOT_READY) {\r
+    Status = MnpRecycleTxBuf (MnpDeviceData);\r
+    if (EFI_ERROR (Status)) {\r
+      Token->Status = EFI_DEVICE_ERROR;\r
+      goto SIGNAL_TOKEN;\r
+    }\r
+\r
     Status = Snp->Transmit (\r
                     Snp,\r
                     HeaderSize,\r
@@ -262,52 +282,15 @@ MnpSyncSendPacket (
                     TxData->SourceAddress,\r
                     TxData->DestinationAddress,\r
                     &ProtocolType\r
-                    );\r
-    if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
-      Status = EFI_DEVICE_ERROR;\r
-      break;\r
-    }\r
-\r
-    //\r
-    // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
-    // if Status is EFI_NOT_READY, the transmit engine of the network interface is busy.\r
-    // Both need to sync SNP.\r
-    //\r
-    TxBuf = NULL;\r
-    do {\r
-      //\r
-      // Get the recycled transmit buffer status.\r
-      //\r
-      Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);\r
-\r
-      if (!EFI_ERROR (gBS->CheckEvent (MnpDeviceData->TxTimeoutEvent))) {\r
-        Status = EFI_TIMEOUT;\r
-        break;\r
-      }\r
-    } while (TxBuf == NULL);\r
-\r
-    if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
-      break;\r
-    } else {\r
-      //\r
-      // Status is EFI_NOT_READY. Restart the timer event and call Snp->Transmit again.\r
-      //\r
-      gBS->SetTimer (\r
-            MnpDeviceData->TxTimeoutEvent,\r
-            TimerRelative,\r
-            MNP_TX_TIMEOUT_TIME\r
-            );\r
-    }\r
+                    ); \r
+  }\r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    Token->Status = EFI_DEVICE_ERROR;\r
   }\r
-\r
-  //\r
-  // Cancel the timer event.\r
-  //\r
-  gBS->SetTimer (MnpDeviceData->TxTimeoutEvent, TimerCancel, 0);\r
 \r
 SIGNAL_TOKEN:\r
 \r
-  Token->Status = Status;\r
   gBS->SignalEvent (Token->Event);\r
 \r
   //\r
index 4c0f3dd..31c2e3e 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Implementation of Managed Network Protocol public services.\r
 \r
-Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>\r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions\r
 of the BSD License which accompanies this distribution.  The full\r
@@ -552,7 +552,10 @@ MnpTransmit (
   //\r
   // Build the tx packet\r
   //\r
-  MnpBuildTxPacket (MnpServiceData, Token->Packet.TxData, &PktBuf, &PktLen);\r
+  Status = MnpBuildTxPacket (MnpServiceData, Token->Packet.TxData, &PktBuf, &PktLen);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
+  }\r
 \r
   //\r
   //  OK, send the packet synchronously.\r