Browse Source

[undi] Retry PXENV_UNDI_INITIALIZE multiple times

On at least one PXE stack (Realtek r8169), PXENV_UNDI_INITIALIZE has
been observed to fail intermittently due to a media test failure (PXE
error 0x00000061).  Retrying the call to PXENV_UNDI_INITIALIZE
succeeds, and the NIC is then usable.

It is worth noting that this particular Realtek PXE stack is already
known to be unreliable: for example, it repeatably fails its own
boot-time media test after every warm reboot.

Fix by attempting PXENV_UNDI_INITIALIZE multiple times, with a short
delay between each attempt to allow the link to settle.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
fa3ca017ac
1 changed files with 30 additions and 8 deletions
  1. 30
    8
      src/arch/i386/drivers/net/undinet.c

+ 30
- 8
src/arch/i386/drivers/net/undinet.c View File

@@ -19,6 +19,7 @@
19 19
 FILE_LICENCE ( GPL2_OR_LATER );
20 20
 
21 21
 #include <string.h>
22
+#include <unistd.h>
22 23
 #include <pxe.h>
23 24
 #include <realmode.h>
24 25
 #include <pic8259.h>
@@ -34,7 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
34 35
 #include <undinet.h>
35 36
 #include <pxeparent.h>
36 37
 
37
-
38 38
 /** @file
39 39
  *
40 40
  * UNDI network device driver
@@ -63,6 +63,12 @@ struct undi_nic {
63 63
 
64 64
 /** @} */
65 65
 
66
+/** Maximum number of times to retry PXENV_UNDI_INITIALIZE */
67
+#define UNDI_INITIALIZE_RETRY_MAX 10
68
+
69
+/** Delay between retries of PXENV_UNDI_INITIALIZE */
70
+#define UNDI_INITIALIZE_RETRY_DELAY_MS 200
71
+
66 72
 static void undinet_close ( struct net_device *netdev );
67 73
 
68 74
 /** Address of UNDI entry point */
@@ -482,12 +488,13 @@ int undinet_probe ( struct undi_device *undi ) {
482 488
 	struct undi_nic *undinic;
483 489
 	struct s_PXENV_START_UNDI start_undi;
484 490
 	struct s_PXENV_UNDI_STARTUP undi_startup;
485
-	struct s_PXENV_UNDI_INITIALIZE undi_initialize;
491
+	struct s_PXENV_UNDI_INITIALIZE undi_init;
486 492
 	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
487 493
 	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
488 494
 	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
489 495
 	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
490 496
 	struct s_PXENV_STOP_UNDI stop_undi;
497
+	unsigned int retry;
491 498
 	int rc;
492 499
 
493 500
 	/* Allocate net device */
@@ -524,12 +531,27 @@ int undinet_probe ( struct undi_device *undi ) {
524 531
 					     &undi_startup,
525 532
 					     sizeof ( undi_startup ) ) ) != 0 )
526 533
 			goto err_undi_startup;
527
-		memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
528
-		if ( ( rc = pxeparent_call ( undinet_entry,
529
-					     PXENV_UNDI_INITIALIZE,
530
-					     &undi_initialize,
531
-					     sizeof ( undi_initialize ))) != 0 )
532
-			goto err_undi_initialize;
534
+		/* On some PXE stacks, PXENV_UNDI_INITIALIZE may fail
535
+		 * due to a transient condition (e.g. media test
536
+		 * failing because the link has only just come out of
537
+		 * reset).  We may therefore need to retry this call
538
+		 * several times.
539
+		 */
540
+		for ( retry = 0 ; ; ) {
541
+			memset ( &undi_init, 0, sizeof ( undi_init ) );
542
+			if ( ( rc = pxeparent_call ( undinet_entry,
543
+						     PXENV_UNDI_INITIALIZE,
544
+						     &undi_init,
545
+						     sizeof ( undi_init ))) ==0)
546
+				break;
547
+			if ( ++retry > UNDI_INITIALIZE_RETRY_MAX )
548
+				goto err_undi_initialize;
549
+			DBGC ( undinic, "UNDINIC %p retrying "
550
+			       "PXENV_UNDI_INITIALIZE (retry %d)\n",
551
+			       undinic, retry );
552
+			/* Delay to allow link to settle if necessary */
553
+			mdelay ( UNDI_INITIALIZE_RETRY_DELAY_MS );
554
+		}
533 555
 	}
534 556
 	undi->flags |= UNDI_FL_INITIALIZED;
535 557
 

Loading…
Cancel
Save