mirror of https://github.com/ipxe/ipxe.git
[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>pull/5/head
parent
8926c233f6
commit
fa3ca017ac
|
@ -19,6 +19,7 @@
|
|||
FILE_LICENCE ( GPL2_OR_LATER );
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pxe.h>
|
||||
#include <realmode.h>
|
||||
#include <pic8259.h>
|
||||
|
@ -34,7 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
#include <undinet.h>
|
||||
#include <pxeparent.h>
|
||||
|
||||
|
||||
/** @file
|
||||
*
|
||||
* UNDI network device driver
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue