]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Universal/Network/MnpDxe/MnpIo.c
MdeModulePkg: Update MNP driver to recycle TX buffer asynchronously.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / MnpDxe / MnpIo.c
index b8f61bf696fe1d82e45b9122202e18ee59da1d67..1cbfc30e5c21128e8c44fb382fe866ce5c44d5aa 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Implementation of Managed Network Protocol I/O functions.\r
 \r
-Copyright (c) 2005 - 2013, 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,19 +127,26 @@ MnpBuildTxPacket (
   EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
   UINT8                   *DstPos;\r
   UINT16                  Index;\r
-  MNP_DEVICE_DATA         *MnpDerviceData;\r
-\r
-  MnpDerviceData = MnpServiceData->MnpDeviceData;\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 if needed.\r
+  //\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
-    //\r
-    // Reserve space for vlan tag,if necessary.\r
-    //\r
-    if (MnpServiceData->VlanId != 0) {\r
-      *PktBuf = MnpDerviceData->TxBuf + NET_VLAN_TAG_LEN;\r
-    } else {\r
-      *PktBuf = MnpDerviceData->TxBuf;\r
-    } \r
-    \r
     CopyMem (\r
         *PktBuf,\r
         TxData->FragmentTable[0].FragmentBuffer,\r
@@ -151,9 +160,8 @@ 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
-    DstPos  = MnpDerviceData->TxBuf;\r
-\r
+    SnpMode = MnpDeviceData->Snp->Mode; \r
+    DstPos  = *PktBuf;\r
     *PktLen = 0;\r
     if (TxData->DestinationAddress != NULL) {\r
       //\r
@@ -177,16 +185,21 @@ MnpBuildTxPacket (
     }\r
 \r
     //\r
-    // Set the buffer pointer and the buffer length.\r
+    // Set the buffer length.\r
     //\r
-    *PktBuf = MnpDerviceData->TxBuf;\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
@@ -210,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
@@ -229,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
@@ -255,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
@@ -267,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