git: 640916dc50a6 - stable/15 - igc: Propagate hardware initialization failures

From: Kevin Bowling <kbowling_at_FreeBSD.org>
Date: Sun, 30 Aug 2026 01:37:55 UTC
The branch stable/15 has been updated by kbowling:

URL: https://cgit.FreeBSD.org/src/commit/?id=640916dc50a6fd88eddad312f9e0e21404211f52

commit 640916dc50a6fd88eddad312f9e0e21404211f52
Author:     Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-16 07:56:03 +0000
Commit:     Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-30 01:32:08 +0000

    igc: Propagate hardware initialization failures
    
    The reset helper discards igc_reset_hw and igc_init_hw errors.  Runtime
    initialization then continues programming rings and filters, and iflib
    publishes the interface as running even though the controller did not
    reach a usable state.  Initial attach similarly continues into NVM and
    MAC setup after a failed reset.
    
    Return errors from the reset helper.  Fail attach when the controller
    cannot be reset or initialized, and report runtime failures through
    iflib_init_failed() so iflib leaves the interface stopped.  Also stop
    register accesses and report the error when a stop path reset fails.  A
    later successful initialization completes pending fatal error cleanup
    and re-arms FER.
    
    Cache a requested MAC address before reset, but let init_hw program RAR0
    after reset succeeds.  Let iflib perform its normal attach-post failure
    cleanup instead of releasing the same driver resources from both layers,
    and make queue cleanup idempotent.
    
    Sponsored by:   BBOX.io
    
    (cherry picked from commit c82a015ede8d49aabc8bb253b7597b8db0f42524)
---
 sys/dev/igc/if_igc.c | 62 ++++++++++++++++++++++++++++++++--------------------
 1 file changed, 38 insertions(+), 24 deletions(-)

diff --git a/sys/dev/igc/if_igc.c b/sys/dev/igc/if_igc.c
index eae83a673786..3ea000509c6e 100644
--- a/sys/dev/igc/if_igc.c
+++ b/sys/dev/igc/if_igc.c
@@ -118,7 +118,7 @@ static void	igc_identify_hardware(if_ctx_t);
 static int	igc_allocate_pci_resources(if_ctx_t);
 static void	igc_free_pci_resources(if_ctx_t);
 static void	igc_disable_broken_l1_2(if_ctx_t);
-static void	igc_reset(if_ctx_t);
+static int	igc_reset(if_ctx_t);
 static int	igc_setup_interface(if_ctx_t);
 static int	igc_setup_msix(if_ctx_t);
 
@@ -678,7 +678,12 @@ igc_if_attach_pre(if_ctx_t ctx)
 	** important in reading the nvm and
 	** mac from that.
 	*/
-	igc_reset_hw(hw);
+	error = igc_reset_hw(hw);
+	if (error != IGC_SUCCESS) {
+		device_printf(dev, "Hardware reset failed: %d\n", error);
+		error = EIO;
+		goto err_late;
+	}
 
 	/* Make sure we have a good EEPROM before we read from it */
 	if (igc_validate_nvm_checksum(hw) < 0) {
@@ -746,11 +751,11 @@ igc_if_attach_post(if_ctx_t ctx)
 
 	/* Setup OS specific network interface */
 	error = igc_setup_interface(ctx);
-	if (error != 0) {
-		goto err_late;
-	}
+	if (error != 0)
+		return (error);
 
-	igc_reset(ctx);
+	if (igc_reset(ctx) != IGC_SUCCESS)
+		return (EIO);
 
 	/* Initialize statistics */
 	igc_update_stats_counters(sc);
@@ -763,14 +768,6 @@ igc_if_attach_post(if_ctx_t ctx)
 
 	INIT_DEBUGOUT("igc_if_attach_post: end");
 
-	return (error);
-
-err_late:
-	igc_release_hw_control(sc);
-	igc_free_pci_resources(ctx);
-	igc_if_queues_free(ctx);
-	free(sc->mta, M_DEVBUF);
-
 	return (error);
 }
 
@@ -880,11 +877,11 @@ igc_if_init(if_ctx_t ctx)
 	bcopy(if_getlladdr(ifp), sc->hw.mac.addr,
 	    ETHER_ADDR_LEN);
 
-	/* Put the address into the Receive Address Array */
-	igc_rar_set(&sc->hw, sc->hw.mac.addr, 0);
-
 	/* Initialize the hardware */
-	igc_reset(ctx);
+	if (igc_reset(ctx) != IGC_SUCCESS) {
+		iflib_init_failed(ctx);
+		return;
+	}
 	igc_if_update_admin_status(ctx);
 
 	for (i = 0, tx_que = sc->tx_queues; i < sc->tx_num_queues;
@@ -1621,12 +1618,18 @@ static void
 igc_if_stop(if_ctx_t ctx)
 {
 	struct igc_softc *sc = iflib_get_softc(ctx);
+	s32 error;
 
 	INIT_DEBUGOUT("igc_if_stop: begin");
 
 	igc_led_restore(sc);
 	igc_prepare_fatal_error_reset(sc);
-	igc_reset_hw(&sc->hw);
+	error = igc_reset_hw(&sc->hw);
+	if (error != IGC_SUCCESS) {
+		device_printf(sc->dev, "Hardware reset failed while stopping: "
+		    "%d\n", error);
+		return;
+	}
 	igc_finish_fatal_error_reset(sc);
 	IGC_WRITE_REG(&sc->hw, IGC_WUC, 0);
 }
@@ -2130,7 +2133,7 @@ igc_init_dmac(struct igc_softc *sc, u32 pba)
  *  softc structure.
  *
  **********************************************************************/
-static void
+static int
 igc_reset(if_ctx_t ctx)
 {
 	device_t dev = iflib_get_dev(ctx);
@@ -2138,6 +2141,7 @@ igc_reset(if_ctx_t ctx)
 	struct igc_hw *hw = &sc->hw;
 	u32 rx_buffer_size;
 	u32 pba;
+	s32 error;
 
 	INIT_DEBUGOUT("igc_reset: begin");
 	igc_led_restore(sc);
@@ -2184,14 +2188,21 @@ igc_reset(if_ctx_t ctx)
 	hw->fc.send_xon = true;
 
 	/* Issue a global reset */
-	igc_reset_hw(hw);
+	error = igc_reset_hw(hw);
+	if (error != IGC_SUCCESS) {
+		device_printf(dev, "Hardware reset failed: %d\n", error);
+		return (error);
+	}
 	IGC_WRITE_REG(hw, IGC_WUC, 0);
 
 	/* and a re-init */
-	if (igc_init_hw(hw) < 0) {
-		device_printf(dev, "Hardware Initialization Failed\n");
-		return;
+	error = igc_init_hw(hw);
+	if (error != IGC_SUCCESS) {
+		device_printf(dev, "Hardware initialization failed: %d\n",
+		    error);
+		return (error);
 	}
+	igc_finish_fatal_error_reset(sc);
 
 	/* Setup DMA Coalescing */
 	igc_init_dmac(sc, pba);
@@ -2202,6 +2213,8 @@ igc_reset(if_ctx_t ctx)
 	IGC_WRITE_REG(hw, IGC_VET, ETHERTYPE_VLAN);
 	igc_get_phy_info(hw);
 	igc_check_for_link(hw);
+
+	return (IGC_SUCCESS);
 }
 
 /*
@@ -2468,6 +2481,7 @@ igc_if_queues_free(if_ctx_t ctx)
 
 	if (sc->mta != NULL) {
 		free(sc->mta, M_DEVBUF);
+		sc->mta = NULL;
 	}
 }