dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

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

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