summaryrefslogtreecommitdiffstats
path: root/src/drivers/net/efi/snpnet.c
diff options
context:
space:
mode:
authorMichael Brown2020-06-19 01:18:22 +0200
committerMichael Brown2020-06-19 01:18:22 +0200
commit770a7bd43aa236fe415e0643e2f452e1ad191596 (patch)
treed190c0f4559b8f909c67c7bbe207dafc149faf2d /src/drivers/net/efi/snpnet.c
parent[crypto] Disable MD5 as an OID-identifiable algorithm by default (diff)
downloadipxe-770a7bd43aa236fe415e0643e2f452e1ad191596.tar.gz
ipxe-770a7bd43aa236fe415e0643e2f452e1ad191596.tar.xz
ipxe-770a7bd43aa236fe415e0643e2f452e1ad191596.zip
[snp] Retry initialisation if link is reported as down
Some devices (observed with a Getac RX10 tablet and docking station containing an embedded AX88179 USB NIC) seem to be capable of detecting link state only during the call to Initialize(), and will occasionally erroneously report that the link is down for the first few such calls. Work around these devices by retrying the Initialize() call multiple times, terminating early if a link is detected. The eventual absence of a link is treated as a non-fatal error, since it is entirely possible that the link really is down. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/net/efi/snpnet.c')
-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 536248bc..fb524027 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) */