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 */