grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] efinet: send_card_buffer: check for immediate TX completion


From: Martin Wilck
Subject: [PATCH] efinet: send_card_buffer: check for immediate TX completion
Date: Tue, 3 Feb 2015 23:58:18 +0100

We are seeing grub network errors ("couldn't send network packet")
with UEFI PXE over an Emulex CNA. Debugging turned out that the
TX code path was running in a timeout waiting for the "recycle
buffer" to be returned. Time had an influence on this effect:
the menu and all required modules loaded usually fine, but kernel
and initrd (after waiting a few seconds for user input) never did.
We also observed that adding a lot of debug messages to the code
and emitting them over the serial line would aggravate the problem
- the timeouts would now occur earlier in the boot sequence; often
the menu would't be displayed any more.

This made me think that some kind of timeout might have discarded our
"recycle buffers" in this card. Maybe the card would "forget"
the buffers after a while, or the get_status() method was called
by some timer interrupt or what not.

I tried this patch and it actually fixes the problem on this system.
The idea is to check for completion immediately after sending, thereby
avoiding the packet to be discarded.

Please review.
---
 grub-core/net/drivers/efi/efinet.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/grub-core/net/drivers/efi/efinet.c 
b/grub-core/net/drivers/efi/efinet.c
index 2b344d6..8a2b2b8 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -37,11 +37,12 @@ send_card_buffer (struct grub_net_card *dev,
   grub_efi_status_t st;
   grub_efi_simple_network_t *net = dev->efi_net;
   grub_uint64_t limit_time = grub_get_time_ms () + 4000;
+  void *txbuf;
 
   if (dev->txbusy)
     while (1)
       {
-       void *txbuf = NULL;
+       txbuf = NULL;
        st = efi_call_3 (net->get_status, net, 0, &txbuf);
        if (st != GRUB_EFI_SUCCESS)
          return grub_error (GRUB_ERR_IO,
@@ -74,7 +75,18 @@ send_card_buffer (struct grub_net_card *dev,
                   dev->txbuf, NULL, NULL, NULL);
   if (st != GRUB_EFI_SUCCESS)
     return grub_error (GRUB_ERR_IO, N_("couldn't send network packet"));
-  dev->txbusy = 1;
+
+  /* 
+     The card may have sent out the packet immediately - set txbusy
+     to 0 in this case.
+     Cases were observed where checking txbuf at the next call
+     of send_card_buffer() is too late: 0 is returned in txbuf and
+     we run in the GRUB_ERR_TIMEOUT case above.
+     Perhaps a timeout in the FW has discarded the recycle buffer.
+   */
+  st = efi_call_3 (net->get_status, net, 0, &txbuf);
+  dev->txbusy = !(st == GRUB_EFI_SUCCESS && txbuf == dev->txbuf);
+
   return GRUB_ERR_NONE;
 }
 
-- 
1.9.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]