Blame SOURCES/0163-efinet-open-Simple-Network-Protocol-exclusively.patch

4fe85b
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
4fe85b
From: Andrei Borzenkov <arvidjaar@gmail.com>
4fe85b
Date: Thu, 7 May 2015 20:37:17 +0300
4fe85b
Subject: [PATCH] efinet: open Simple Network Protocol exclusively
4fe85b
4fe85b
EDK2 network stack is based on Managed Network Protocol which is layered
4fe85b
on top of Simple Management Protocol and does background polling. This
4fe85b
polling races with grub for received (and probably trasmitted) packets
4fe85b
which causes either serious slowdown or complete failure to load files.
4fe85b
4fe85b
Open SNP device exclusively.  This destroys all child MNP instances and
4fe85b
stops background polling.
4fe85b
4fe85b
Exclusive open cannot be done when enumerating cards, as it would destroy
4fe85b
PXE information we need to autoconfigure interface; and it cannot be done
4fe85b
during autoconfiguration as we need to do it for non-PXE boot as well. So
4fe85b
move SNP open to card ->open method and add matching ->close to clean up.
4fe85b
4fe85b
Based on patch from Mark Salter <msalter@redhat.com>
4fe85b
4fe85b
Also-By: Mark Salter <msalter@redhat.com>
4fe85b
Closes: 41731
4fe85b
---
4fe85b
 grub-core/net/drivers/efi/efinet.c | 46 ++++++++++++++++++++++++++++++++++++++
4fe85b
 1 file changed, 46 insertions(+)
4fe85b
4fe85b
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
4fe85b
index caa7b50228b..6a1dd1f9dff 100644
4fe85b
--- a/grub-core/net/drivers/efi/efinet.c
4fe85b
+++ b/grub-core/net/drivers/efi/efinet.c
4fe85b
@@ -142,9 +142,55 @@ get_card_packet (struct grub_net_card *dev)
4fe85b
   return nb;
4fe85b
 }
4fe85b
 
4fe85b
+static grub_err_t
4fe85b
+open_card (struct grub_net_card *dev)
4fe85b
+{
4fe85b
+  grub_efi_simple_network_t *net;
4fe85b
+
4fe85b
+  /* Try to reopen SNP exlusively to close any active MNP protocol instance
4fe85b
+     that may compete for packet polling
4fe85b
+   */
4fe85b
+  net = grub_efi_open_protocol (dev->efi_handle, &net_io_guid,
4fe85b
+				GRUB_EFI_OPEN_PROTOCOL_BY_EXCLUSIVE);
4fe85b
+  if (net)
4fe85b
+    {
4fe85b
+      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED
4fe85b
+	  && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS)
4fe85b
+	return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net start failed",
4fe85b
+			   dev->name);
4fe85b
+
4fe85b
+      if (net->mode->state == GRUB_EFI_NETWORK_STOPPED)
4fe85b
+	return grub_error (GRUB_ERR_NET_NO_CARD, "%s: card stopped",
4fe85b
+			   dev->name);
4fe85b
+
4fe85b
+      if (net->mode->state == GRUB_EFI_NETWORK_STARTED
4fe85b
+	  && efi_call_3 (net->initialize, net, 0, 0) != GRUB_EFI_SUCCESS)
4fe85b
+	return grub_error (GRUB_ERR_NET_NO_CARD, "%s: net initialize failed",
4fe85b
+			   dev->name);
4fe85b
+
4fe85b
+      efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
4fe85b
+		  dev->efi_net, &net_io_guid,
4fe85b
+		  grub_efi_image_handle, dev->efi_handle);
4fe85b
+      dev->efi_net = net;
4fe85b
+    }
4fe85b
+
4fe85b
+  /* If it failed we just try to run as best as we can */
4fe85b
+  return GRUB_ERR_NONE;
4fe85b
+}
4fe85b
+
4fe85b
+static void
4fe85b
+close_card (struct grub_net_card *dev)
4fe85b
+{
4fe85b
+  efi_call_4 (grub_efi_system_table->boot_services->close_protocol,
4fe85b
+	      dev->efi_net, &net_io_guid,
4fe85b
+	      grub_efi_image_handle, dev->efi_handle);
4fe85b
+}
4fe85b
+
4fe85b
 static struct grub_net_card_driver efidriver =
4fe85b
   {
4fe85b
     .name = "efinet",
4fe85b
+    .open = open_card,
4fe85b
+    .close = close_card,
4fe85b
     .send = send_card_buffer,
4fe85b
     .recv = get_card_packet
4fe85b
   };