aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/drivers/net/efi/snpnet.c56
1 files changed, 49 insertions, 7 deletions
diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c
index 536248bca..fb5240277 100644
--- a/src/drivers/net/efi/snpnet.c
+++ b/src/drivers/net/efi/snpnet.c
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/netdevice.h>
#include <ipxe/ethernet.h>
#include <ipxe/vsprintf.h>
+#include <ipxe/timer.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/SimpleNetwork.h>
#include <ipxe/efi/efi_driver.h>
@@ -64,6 +65,12 @@ struct snp_nic {
/** Maximum number of received packets per poll */
#define SNP_RX_QUOTA 4
+/** Maximum initialisation retry count */
+#define SNP_INITIALIZE_RETRY_MAX 10
+
+/** Delay between each initialisation retry */
+#define SNP_INITIALIZE_RETRY_DELAY_MS 10
+
/**
* Format SNP MAC address (for debugging)
*
@@ -335,7 +342,9 @@ static int snpnet_rx_filters ( struct net_device *netdev ) {
static int snpnet_open ( struct net_device *netdev ) {
struct snp_nic *snp = netdev->priv;
EFI_MAC_ADDRESS *mac = ( ( void * ) netdev->ll_addr );
+ EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode;
EFI_STATUS efirc;
+ unsigned int retry;
int rc;
/* Try setting MAC address (before initialising) */
@@ -346,13 +355,46 @@ static int snpnet_open ( struct net_device *netdev ) {
/* Ignore error */
}
- /* Initialise NIC */
- if ( ( efirc = snp->snp->Initialize ( snp->snp, 0, 0 ) ) != 0 ) {
- rc = -EEFI ( efirc );
- snpnet_dump_mode ( netdev );
- DBGC ( snp, "SNP %s could not initialise: %s\n",
- netdev->name, strerror ( rc ) );
- return rc;
+ /* Initialise NIC, retrying multiple times if link stays down */
+ for ( retry = 0 ; ; ) {
+
+ /* Initialise NIC */
+ if ( ( efirc = snp->snp->Initialize ( snp->snp,
+ 0, 0 ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ snpnet_dump_mode ( netdev );
+ DBGC ( snp, "SNP %s could not initialise: %s\n",
+ netdev->name, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Stop if we have link up (or no link detection capability) */
+ if ( ( ! mode->MediaPresentSupported ) || mode->MediaPresent )
+ break;
+
+ /* Stop if we have exceeded our retry count. This is
+ * not a failure; it is plausible that we genuinely do
+ * not have link up.
+ */
+ if ( ++retry >= SNP_INITIALIZE_RETRY_MAX )
+ break;
+ DBGC ( snp, "SNP %s retrying initialisation (retry %d)\n",
+ netdev->name, retry );
+
+ /* Delay to allow time for link to establish */
+ mdelay ( SNP_INITIALIZE_RETRY_DELAY_MS );
+
+ /* Shut down and retry; this is sometimes necessary in
+ * order to persuade the underlying SNP driver to
+ * actually update the link state.
+ */
+ if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ snpnet_dump_mode ( netdev );
+ DBGC ( snp, "SNP %s could not shut down: %s\n",
+ netdev->name, strerror ( rc ) );
+ return rc;
+ }
}
/* Try setting MAC address (after initialising) */