dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

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

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