Module Name: src Committed By: msaitoh Date: Thu Dec 28 06:10:01 UTC 2017
Modified Files: src/sys/dev/pci/ixgbe: ixgbe.c Log Message: Fallback from MSI-X to MSI or INTx if MSI-X setup failed. To generate a diff of this commit: cvs rdiff -u -r1.118 -r1.119 src/sys/dev/pci/ixgbe/ixgbe.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/ixgbe/ixgbe.c diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.118 src/sys/dev/pci/ixgbe/ixgbe.c:1.119 --- src/sys/dev/pci/ixgbe/ixgbe.c:1.118 Thu Dec 21 09:24:45 2017 +++ src/sys/dev/pci/ixgbe/ixgbe.c Thu Dec 28 06:10:01 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ixgbe.c,v 1.118 2017/12/21 09:24:45 msaitoh Exp $ */ +/* $NetBSD: ixgbe.c,v 1.119 2017/12/28 06:10:01 msaitoh Exp $ */ /****************************************************************************** @@ -172,12 +172,14 @@ static void ixgbe_media_status(struc static int ixgbe_media_change(struct ifnet *); static int ixgbe_allocate_pci_resources(struct adapter *, const struct pci_attach_args *); +static void ixgbe_free_softint(struct adapter *); static void ixgbe_get_slot_info(struct adapter *); static int ixgbe_allocate_msix(struct adapter *, const struct pci_attach_args *); static int ixgbe_allocate_legacy(struct adapter *, const struct pci_attach_args *); static int ixgbe_configure_interrupts(struct adapter *); +static void ixgbe_free_pciintr_resources(struct adapter *); static void ixgbe_free_pci_resources(struct adapter *); static void ixgbe_local_timer(void *); static void ixgbe_local_timer1(void *); @@ -1043,13 +1045,54 @@ ixgbe_attach(device_t parent, device_t d hw->eeprom.ops.read(hw, IXGBE_ETRACKID_L, &low); aprint_normal(" ETrackID %08x\n", ((uint32_t)high << 16) | low); - if (adapter->feat_en & IXGBE_FEATURE_MSIX) + if (adapter->feat_en & IXGBE_FEATURE_MSIX) { error = ixgbe_allocate_msix(adapter, pa); - else + if (error) { + /* Free allocated queue structures first */ + ixgbe_free_transmit_structures(adapter); + ixgbe_free_receive_structures(adapter); + free(adapter->queues, M_DEVBUF); + + /* Fallback to legacy interrupt */ + adapter->feat_en &= ~IXGBE_FEATURE_MSIX; + if (adapter->feat_cap & IXGBE_FEATURE_MSI) + adapter->feat_en |= IXGBE_FEATURE_MSI; + adapter->num_queues = 1; + + /* Allocate our TX/RX Queues again */ + if (ixgbe_allocate_queues(adapter)) { + error = ENOMEM; + goto err_out; + } + } + } + if ((adapter->feat_en & IXGBE_FEATURE_MSIX) == 0) error = ixgbe_allocate_legacy(adapter, pa); if (error) goto err_late; + /* Tasklets for Link, SFP, Multispeed Fiber and Flow Director */ + adapter->link_si = softint_establish(SOFTINT_NET |IXGBE_SOFTINFT_FLAGS, + ixgbe_handle_link, adapter); + adapter->mod_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, + ixgbe_handle_mod, adapter); + adapter->msf_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, + ixgbe_handle_msf, adapter); + adapter->phy_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, + ixgbe_handle_phy, adapter); + if (adapter->feat_en & IXGBE_FEATURE_FDIR) + adapter->fdir_si = + softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, + ixgbe_reinit_fdir, adapter); + if ((adapter->link_si == NULL) || (adapter->mod_si == NULL) + || (adapter->msf_si == NULL) || (adapter->phy_si == NULL) + || ((adapter->feat_en & IXGBE_FEATURE_FDIR) + && (adapter->fdir_si == NULL))) { + aprint_error_dev(dev, + "could not establish software interrupts ()\n"); + goto err_out; + } + error = ixgbe_start_hw(hw); switch (error) { case IXGBE_ERR_EEPROM_VERSION: @@ -1158,6 +1201,7 @@ err_out: ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); + ixgbe_free_softint(adapter); ixgbe_free_pci_resources(adapter); if (adapter->mta != NULL) free(adapter->mta, M_DEVBUF); @@ -3113,6 +3157,53 @@ map_err: return (0); } /* ixgbe_allocate_pci_resources */ +static void +ixgbe_free_softint(struct adapter *adapter) +{ + struct ix_queue *que = adapter->queues; + struct tx_ring *txr = adapter->tx_rings; + int i; + + for (i = 0; i < adapter->num_queues; i++, que++, txr++) { + if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) { + if (txr->txr_si != NULL) + softint_disestablish(txr->txr_si); + } + if (que->que_si != NULL) + softint_disestablish(que->que_si); + } + + /* Drain the Link queue */ + if (adapter->link_si != NULL) { + softint_disestablish(adapter->link_si); + adapter->link_si = NULL; + } + if (adapter->mod_si != NULL) { + softint_disestablish(adapter->mod_si); + adapter->mod_si = NULL; + } + if (adapter->msf_si != NULL) { + softint_disestablish(adapter->msf_si); + adapter->msf_si = NULL; + } + if (adapter->phy_si != NULL) { + softint_disestablish(adapter->phy_si); + adapter->phy_si = NULL; + } + if (adapter->feat_en & IXGBE_FEATURE_FDIR) { + if (adapter->fdir_si != NULL) { + softint_disestablish(adapter->fdir_si); + adapter->fdir_si = NULL; + } + } + if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) { + if (adapter->mbx_si != NULL) { + softint_disestablish(adapter->mbx_si); + adapter->mbx_si = NULL; + } + } +} /* ixgbe_free_softint */ + /************************************************************************ * ixgbe_detach - Device removal routine * @@ -3126,7 +3217,6 @@ static int ixgbe_detach(device_t dev, int flags) { struct adapter *adapter = device_private(dev); - struct ix_queue *que = adapter->queues; struct rx_ring *rxr = adapter->rx_rings; struct tx_ring *txr = adapter->tx_rings; struct ixgbe_hw *hw = &adapter->hw; @@ -3164,22 +3254,8 @@ ixgbe_detach(device_t dev, int flags) ixgbe_setup_low_power_mode(adapter); IXGBE_CORE_UNLOCK(adapter); - for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { - if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) - softint_disestablish(txr->txr_si); - softint_disestablish(que->que_si); - } - - /* Drain the Link queue */ - softint_disestablish(adapter->link_si); - softint_disestablish(adapter->mod_si); - softint_disestablish(adapter->msf_si); - if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) - softint_disestablish(adapter->mbx_si); - softint_disestablish(adapter->phy_si); - if (adapter->feat_en & IXGBE_FEATURE_FDIR) - softint_disestablish(adapter->fdir_si); - + ixgbe_free_softint(adapter); + /* let hardware know driver is unloading */ ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; @@ -4546,10 +4622,10 @@ ixgbe_legacy_irq(void *arg) } /* ixgbe_legacy_irq */ /************************************************************************ - * ixgbe_free_pci_resources + * ixgbe_free_pciintr_resources ************************************************************************/ static void -ixgbe_free_pci_resources(struct adapter *adapter) +ixgbe_free_pciintr_resources(struct adapter *adapter) { struct ix_queue *que = adapter->queues; int rid; @@ -4558,9 +4634,11 @@ ixgbe_free_pci_resources(struct adapter * Release all msix queue resources: */ for (int i = 0; i < adapter->num_queues; i++, que++) { - if (que->res != NULL) + if (que->res != NULL) { pci_intr_disestablish(adapter->osdep.pc, adapter->osdep.ihs[i]); + adapter->osdep.ihs[i] = NULL; + } } /* Clean the Legacy or Link interrupt last */ @@ -4575,8 +4653,23 @@ ixgbe_free_pci_resources(struct adapter adapter->osdep.ihs[rid] = NULL; } - pci_intr_release(adapter->osdep.pc, adapter->osdep.intrs, - adapter->osdep.nintrs); + if (adapter->osdep.intrs != NULL) { + pci_intr_release(adapter->osdep.pc, adapter->osdep.intrs, + adapter->osdep.nintrs); + adapter->osdep.intrs = NULL; + } + + return; +} /* ixgbe_free_pciintr_resources */ + +/************************************************************************ + * ixgbe_free_pci_resources + ************************************************************************/ +static void +ixgbe_free_pci_resources(struct adapter *adapter) +{ + + ixgbe_free_pciintr_resources(adapter); if (adapter->osdep.mem_size != 0) { bus_space_unmap(adapter->osdep.mem_bus_space_tag, @@ -5681,12 +5774,12 @@ alloc_retry: adapter->osdep.ihs[0] = pci_intr_establish_xname(adapter->osdep.pc, adapter->osdep.intrs[0], IPL_NET, ixgbe_legacy_irq, que, device_xname(dev)); + intr_type = pci_intr_type(adapter->osdep.pc, adapter->osdep.intrs[0]); if (adapter->osdep.ihs[0] == NULL) { - intr_type = pci_intr_type(adapter->osdep.pc, - adapter->osdep.intrs[0]); aprint_error_dev(dev,"unable to establish %s\n", (intr_type == PCI_INTR_TYPE_MSI) ? "MSI" : "INTx"); pci_intr_release(adapter->osdep.pc, adapter->osdep.intrs, 1); + adapter->osdep.intrs = NULL; switch (intr_type) { case PCI_INTR_TYPE_MSI: /* The next try is for INTx: Disable MSI */ @@ -5704,11 +5797,16 @@ alloc_retry: break; } } + if (intr_type == PCI_INTR_TYPE_INTX) { + adapter->feat_en &= ~IXGBE_FEATURE_MSI; + adapter->feat_en |= IXGBE_FEATURE_LEGACY_IRQ; + } if (adapter->osdep.ihs[0] == NULL) { aprint_error_dev(dev, "couldn't establish interrupt%s%s\n", intrstr ? " at " : "", intrstr ? intrstr : ""); pci_intr_release(adapter->osdep.pc, adapter->osdep.intrs, 1); + adapter->osdep.intrs = NULL; return ENXIO; } aprint_normal_dev(dev, "interrupting at %s\n", intrstr); @@ -5723,29 +5821,8 @@ alloc_retry: que->que_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, ixgbe_handle_que, que); - /* Tasklets for Link, SFP and Multispeed Fiber */ - adapter->link_si = softint_establish(SOFTINT_NET |IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_link, adapter); - adapter->mod_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_mod, adapter); - adapter->msf_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_msf, adapter); - adapter->phy_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_phy, adapter); - - if (adapter->feat_en & IXGBE_FEATURE_FDIR) - adapter->fdir_si = - softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_reinit_fdir, adapter); - - if ((!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX) & - (txr->txr_si == NULL)) || - que->que_si == NULL || - adapter->link_si == NULL || - adapter->mod_si == NULL || - ((adapter->feat_en & IXGBE_FEATURE_FDIR) & - (adapter->fdir_si == NULL)) || - adapter->msf_si == NULL) { + if ((!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX) + & (txr->txr_si == NULL)) || (que->que_si == NULL)) { aprint_error_dev(dev, "could not establish software interrupts\n"); @@ -5825,12 +5902,10 @@ ixgbe_allocate_msix(struct adapter *adap adapter->osdep.intrs[i], IPL_NET, ixgbe_msix_que, que, intr_xname); if (que->res == NULL) { - pci_intr_release(pc, adapter->osdep.intrs, - adapter->osdep.nintrs); aprint_error_dev(dev, "Failed to register QUE handler\n"); - kcpuset_destroy(affinity); - return ENXIO; + error = ENXIO; + goto err_out; } que->msix = vector; adapter->active_queues |= (u64)(1 << que->msix); @@ -5876,16 +5951,25 @@ ixgbe_allocate_msix(struct adapter *adap } aprint_normal("\n"); - if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) + if (!(adapter->feat_en & IXGBE_FEATURE_LEGACY_TX)) { txr->txr_si = softint_establish( SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, ixgbe_deferred_mq_start, txr); + if (txr->txr_si == NULL) { + aprint_error_dev(dev, + "couldn't establish software interrupt\n"); + error = ENXIO; + goto err_out; + } + } que->que_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, ixgbe_handle_que, que); if (que->que_si == NULL) { aprint_error_dev(dev, - "could not establish software interrupt\n"); + "couldn't establish software interrupt\n"); + error = ENXIO; + goto err_out; } } @@ -5906,13 +5990,14 @@ ixgbe_allocate_msix(struct adapter *adap if (adapter->osdep.ihs[vector] == NULL) { adapter->res = NULL; aprint_error_dev(dev, "Failed to register LINK handler\n"); - kcpuset_destroy(affinity); - return (ENXIO); + error = ENXIO; + goto err_out; } /* Round-robin affinity */ kcpuset_zero(affinity); kcpuset_set(affinity, cpu_id % ncpu); - error = interrupt_distribute(adapter->osdep.ihs[vector], affinity,NULL); + error = interrupt_distribute(adapter->osdep.ihs[vector], affinity, + NULL); aprint_normal_dev(dev, "for link, interrupting at %s", intrstr); @@ -5921,27 +6006,30 @@ ixgbe_allocate_msix(struct adapter *adap else aprint_normal("\n"); - /* Tasklets for Link, SFP and Multispeed Fiber */ - adapter->link_si = softint_establish(SOFTINT_NET |IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_link, adapter); - adapter->mod_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_mod, adapter); - adapter->msf_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_msf, adapter); - if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) + if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) { adapter->mbx_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, ixgbe_handle_mbx, adapter); - adapter->phy_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_handle_phy, adapter); - if (adapter->feat_en & IXGBE_FEATURE_FDIR) - adapter->fdir_si = - softint_establish(SOFTINT_NET | IXGBE_SOFTINFT_FLAGS, - ixgbe_reinit_fdir, adapter); + if (adapter->mbx_si == NULL) { + aprint_error_dev(dev, + "could not establish software interrupts\n"); + + error = ENXIO; + goto err_out; + } + } kcpuset_destroy(affinity); + aprint_normal_dev(dev, + "Using MSI-X interrupts with %d vectors\n", vector + 1); return (0); + +err_out: + kcpuset_destroy(affinity); + ixgbe_free_softint(adapter); + ixgbe_free_pciintr_resources(adapter); + return (error); } /* ixgbe_allocate_msix */ /************************************************************************ @@ -6014,8 +6102,6 @@ ixgbe_configure_interrupts(struct adapte msgs, want); goto msi; } - device_printf(dev, - "Using MSI-X interrupts with %d vectors\n", msgs); adapter->num_queues = queues; adapter->feat_en |= IXGBE_FEATURE_MSIX; return (0); @@ -6039,7 +6125,6 @@ msi: if (msgs != 0) { msgs = 1; adapter->feat_en |= IXGBE_FEATURE_MSI; - aprint_normal_dev(dev, "Using an MSI interrupt\n"); return (0); } @@ -6050,7 +6135,6 @@ msi: } adapter->feat_en |= IXGBE_FEATURE_LEGACY_IRQ; - aprint_normal_dev(dev, "Using a Legacy interrupt\n"); return (0); } /* ixgbe_configure_interrupts */