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 13 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
 FILE_LICENCE ( GPL2_OR_LATER );
19
 FILE_LICENCE ( GPL2_OR_LATER );
20
 
20
 
21
 #include <string.h>
21
 #include <string.h>
22
+#include <unistd.h>
22
 #include <pxe.h>
23
 #include <pxe.h>
23
 #include <realmode.h>
24
 #include <realmode.h>
24
 #include <pic8259.h>
25
 #include <pic8259.h>
34
 #include <undinet.h>
35
 #include <undinet.h>
35
 #include <pxeparent.h>
36
 #include <pxeparent.h>
36
 
37
 
37
-
38
 /** @file
38
 /** @file
39
  *
39
  *
40
  * UNDI network device driver
40
  * UNDI network device driver
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
 static void undinet_close ( struct net_device *netdev );
72
 static void undinet_close ( struct net_device *netdev );
67
 
73
 
68
 /** Address of UNDI entry point */
74
 /** Address of UNDI entry point */
482
 	struct undi_nic *undinic;
488
 	struct undi_nic *undinic;
483
 	struct s_PXENV_START_UNDI start_undi;
489
 	struct s_PXENV_START_UNDI start_undi;
484
 	struct s_PXENV_UNDI_STARTUP undi_startup;
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
 	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
492
 	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
487
 	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
493
 	struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
488
 	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
494
 	struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
489
 	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
495
 	struct s_PXENV_UNDI_CLEANUP undi_cleanup;
490
 	struct s_PXENV_STOP_UNDI stop_undi;
496
 	struct s_PXENV_STOP_UNDI stop_undi;
497
+	unsigned int retry;
491
 	int rc;
498
 	int rc;
492
 
499
 
493
 	/* Allocate net device */
500
 	/* Allocate net device */
524
 					     &undi_startup,
531
 					     &undi_startup,
525
 					     sizeof ( undi_startup ) ) ) != 0 )
532
 					     sizeof ( undi_startup ) ) ) != 0 )
526
 			goto err_undi_startup;
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
 	undi->flags |= UNDI_FL_INITIALIZED;
556
 	undi->flags |= UNDI_FL_INITIALIZED;
535
 
557
 

Loading…
Cancel
Save