Skip to content

Commit

Permalink
[undi] Retry PXENV_UNDI_INITIALIZE multiple times
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Dec 8, 2011
1 parent 8926c23 commit fa3ca01
Showing 1 changed file with 30 additions and 8 deletions.
38 changes: 30 additions & 8 deletions src/arch/i386/drivers/net/undinet.c
Expand Up @@ -19,6 +19,7 @@
FILE_LICENCE ( GPL2_OR_LATER );

#include <string.h>
#include <unistd.h>
#include <pxe.h>
#include <realmode.h>
#include <pic8259.h>
Expand All @@ -34,7 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <undinet.h>
#include <pxeparent.h>


/** @file
*
* UNDI network device driver
Expand Down Expand Up @@ -63,6 +63,12 @@ struct undi_nic {

/** @} */

/** Maximum number of times to retry PXENV_UNDI_INITIALIZE */
#define UNDI_INITIALIZE_RETRY_MAX 10

/** Delay between retries of PXENV_UNDI_INITIALIZE */
#define UNDI_INITIALIZE_RETRY_DELAY_MS 200

static void undinet_close ( struct net_device *netdev );

/** Address of UNDI entry point */
Expand Down Expand Up @@ -482,12 +488,13 @@ int undinet_probe ( struct undi_device *undi ) {
struct undi_nic *undinic;
struct s_PXENV_START_UNDI start_undi;
struct s_PXENV_UNDI_STARTUP undi_startup;
struct s_PXENV_UNDI_INITIALIZE undi_initialize;
struct s_PXENV_UNDI_INITIALIZE undi_init;
struct s_PXENV_UNDI_GET_INFORMATION undi_info;
struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface;
struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
struct s_PXENV_UNDI_CLEANUP undi_cleanup;
struct s_PXENV_STOP_UNDI stop_undi;
unsigned int retry;
int rc;

/* Allocate net device */
Expand Down Expand Up @@ -524,12 +531,27 @@ int undinet_probe ( struct undi_device *undi ) {
&undi_startup,
sizeof ( undi_startup ) ) ) != 0 )
goto err_undi_startup;
memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
if ( ( rc = pxeparent_call ( undinet_entry,
PXENV_UNDI_INITIALIZE,
&undi_initialize,
sizeof ( undi_initialize ))) != 0 )
goto err_undi_initialize;
/* On some PXE stacks, PXENV_UNDI_INITIALIZE may fail
* due to a transient condition (e.g. media test
* failing because the link has only just come out of
* reset). We may therefore need to retry this call
* several times.
*/
for ( retry = 0 ; ; ) {
memset ( &undi_init, 0, sizeof ( undi_init ) );
if ( ( rc = pxeparent_call ( undinet_entry,
PXENV_UNDI_INITIALIZE,
&undi_init,
sizeof ( undi_init ))) ==0)
break;
if ( ++retry > UNDI_INITIALIZE_RETRY_MAX )
goto err_undi_initialize;
DBGC ( undinic, "UNDINIC %p retrying "
"PXENV_UNDI_INITIALIZE (retry %d)\n",
undinic, retry );
/* Delay to allow link to settle if necessary */
mdelay ( UNDI_INITIALIZE_RETRY_DELAY_MS );
}
}
undi->flags |= UNDI_FL_INITIALIZED;

Expand Down

0 comments on commit fa3ca01

Please sign in to comment.