]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/MnpDxe/MnpConfig.c
MdeModulePkg: Update MNP driver to recycle TX buffer asynchronously.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpConfig.c
index 046d4dfddccbc24b0f330389d7c16dec5075cb85..d1a4cb5dd2a3103727e833cad59d05e9a9b17a42 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