Module Name: src
Committed By: msaitoh
Date: Thu Jun 25 07:53:02 UTC 2020
Modified Files:
src/sys/dev/pci/ixgbe: if_sriov.c ixgbe.c ixgbe.h ixgbe_netbsd.c
ixgbe_osdep.h ixv.c
Log Message:
Reduce ixgbe's busy loop using with workqueue and kpause.
- Use workqueue instead of softint to make some functions sleepable.
- Use new workqueue and enqueue it in ixgbe_local_timer() and
ixgbe_recovery_mode_timer() to make them sleepable.
- Make new ixgbe_delay() and use it. This functions sleeps if the time is
more than equals 1 tick. If it's not, do delay().
To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/pci/ixgbe/if_sriov.c
cvs rdiff -u -r1.232 -r1.233 src/sys/dev/pci/ixgbe/ixgbe.c
cvs rdiff -u -r1.66 -r1.67 src/sys/dev/pci/ixgbe/ixgbe.h
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/pci/ixgbe/ixgbe_netbsd.c
cvs rdiff -u -r1.26 -r1.27 src/sys/dev/pci/ixgbe/ixgbe_osdep.h
cvs rdiff -u -r1.150 -r1.151 src/sys/dev/pci/ixgbe/ixv.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/if_sriov.c
diff -u src/sys/dev/pci/ixgbe/if_sriov.c:1.6 src/sys/dev/pci/ixgbe/if_sriov.c:1.7
--- src/sys/dev/pci/ixgbe/if_sriov.c:1.6 Thu Jun 27 05:55:40 2019
+++ src/sys/dev/pci/ixgbe/if_sriov.c Thu Jun 25 07:53:01 2020
@@ -645,7 +645,6 @@ ixgbe_handle_mbx(void *context, int pend
hw = &adapter->hw;
- IXGBE_CORE_LOCK(adapter);
for (i = 0; i < adapter->num_vfs; i++) {
vf = &adapter->vfs[i];
@@ -660,7 +659,6 @@ ixgbe_handle_mbx(void *context, int pend
ixgbe_process_vf_ack(adapter, vf);
}
}
- IXGBE_CORE_UNLOCK(adapter);
} /* ixgbe_handle_mbx */
int
Index: src/sys/dev/pci/ixgbe/ixgbe.c
diff -u src/sys/dev/pci/ixgbe/ixgbe.c:1.232 src/sys/dev/pci/ixgbe/ixgbe.c:1.233
--- src/sys/dev/pci/ixgbe/ixgbe.c:1.232 Thu Jun 18 09:00:11 2020
+++ src/sys/dev/pci/ixgbe/ixgbe.c Thu Jun 25 07:53:01 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe.c,v 1.232 2020/06/18 09:00:11 msaitoh Exp $ */
+/* $NetBSD: ixgbe.c,v 1.233 2020/06/25 07:53:01 msaitoh Exp $ */
/******************************************************************************
@@ -179,7 +179,7 @@ static void ixgbe_media_status(struct if
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_free_workqueue(struct adapter *);
static void ixgbe_get_slot_info(struct adapter *);
static int ixgbe_allocate_msix(struct adapter *,
const struct pci_attach_args *);
@@ -189,12 +189,14 @@ static int ixgbe_configure_interrupts(st
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 *);
+static void ixgbe_handle_timer(struct work *, void *);
static void ixgbe_recovery_mode_timer(void *);
+static void ixgbe_handle_recovery_mode_timer(struct work *, void *);
static int ixgbe_setup_interface(device_t, struct adapter *);
static void ixgbe_config_gpie(struct adapter *);
static void ixgbe_config_dmac(struct adapter *);
static void ixgbe_config_delay_values(struct adapter *);
+static void ixgbe_schedule_admin_tasklet(struct adapter *);
static void ixgbe_config_link(struct adapter *);
static void ixgbe_check_wol_support(struct adapter *);
static int ixgbe_setup_low_power_mode(struct adapter *);
@@ -262,17 +264,17 @@ static int ixgbe_legacy_irq(void *);
/* The MSI/MSI-X Interrupt handlers */
static int ixgbe_msix_que(void *);
-static int ixgbe_msix_link(void *);
+static int ixgbe_msix_admin(void *);
-/* Software interrupts for deferred work */
+/* Event handlers running on workqueue */
static void ixgbe_handle_que(void *);
static void ixgbe_handle_link(void *);
+static void ixgbe_handle_msf(void *);
static void ixgbe_handle_mod(void *);
static void ixgbe_handle_phy(void *);
-static void ixgbe_handle_msf(struct work *, void *);
-
-/* Workqueue handler for deferred work */
+/* Deferred workqueue handlers */
+static void ixgbe_handle_admin(struct work *, void *);
static void ixgbe_handle_que_work(struct work *, void *);
static const ixgbe_vendor_info_t *ixgbe_lookup(const struct pci_attach_args *);
@@ -783,6 +785,7 @@ ixgbe_attach(device_t parent, device_t d
struct pci_attach_args *pa = aux;
bool unsupported_sfp = false;
const char *str;
+ char wqname[MAXCOMLEN];
char buf[256];
INIT_DEBUGOUT("ixgbe_attach: begin");
@@ -807,11 +810,20 @@ ixgbe_attach(device_t parent, device_t d
aprint_normal(": %s, Version - %s\n",
ixgbe_strings[ent->index], ixgbe_driver_version);
- /* Core Lock Init*/
+ /* Core Lock Init */
IXGBE_CORE_LOCK_INIT(adapter, device_xname(dev));
- /* Set up the timer callout */
+ /* Set up the timer callout and workqueue */
callout_init(&adapter->timer, IXGBE_CALLOUT_FLAGS);
+ snprintf(wqname, sizeof(wqname), "%s-timer", device_xname(dev));
+ error = workqueue_create(&adapter->timer_wq, wqname,
+ ixgbe_handle_timer, adapter, IXGBE_WORKQUEUE_PRI, IPL_NET,
+ IXGBE_TASKLET_WQ_FLAGS);
+ if (error) {
+ aprint_error_dev(dev,
+ "could not create timer workqueue (%d)\n", error);
+ goto err_out;
+ }
/* Determine hardware revision */
id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
@@ -1100,32 +1112,13 @@ ixgbe_attach(device_t parent, device_t d
goto err_late;
/* Tasklets for Link, SFP, Multispeed Fiber and Flow Director */
- adapter->link_si = softint_establish(SOFTINT_NET |IXGBE_SOFTINT_FLAGS,
- ixgbe_handle_link, adapter);
- adapter->mod_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINT_FLAGS,
- ixgbe_handle_mod, adapter);
- adapter->phy_si = softint_establish(SOFTINT_NET | IXGBE_SOFTINT_FLAGS,
- ixgbe_handle_phy, adapter);
- if (adapter->feat_en & IXGBE_FEATURE_FDIR)
- adapter->fdir_si =
- softint_establish(SOFTINT_NET | IXGBE_SOFTINT_FLAGS,
- ixgbe_reinit_fdir, adapter);
- if ((adapter->link_si == NULL) || (adapter->mod_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;
- }
- char wqname[MAXCOMLEN];
- snprintf(wqname, sizeof(wqname), "%s-msf", device_xname(dev));
- error = workqueue_create(&adapter->msf_wq, wqname,
- ixgbe_handle_msf, adapter, IXGBE_WORKQUEUE_PRI, IPL_NET,
+ snprintf(wqname, sizeof(wqname), "%s-admin", device_xname(dev));
+ error = workqueue_create(&adapter->admin_wq, wqname,
+ ixgbe_handle_admin, adapter, IXGBE_WORKQUEUE_PRI, IPL_NET,
IXGBE_TASKLET_WQ_FLAGS);
if (error) {
aprint_error_dev(dev,
- "could not create MSF workqueue (%d)\n", error);
+ "could not create admin workqueue (%d)\n", error);
goto err_out;
}
@@ -1235,6 +1228,14 @@ ixgbe_attach(device_t parent, device_t d
/* Set up the timer callout */
callout_init(&adapter->recovery_mode_timer,
IXGBE_CALLOUT_FLAGS);
+ error = workqueue_create(&adapter->recovery_mode_timer_wq,
+ wqname, ixgbe_handle_recovery_mode_timer, adapter,
+ IXGBE_WORKQUEUE_PRI, IPL_NET, IXGBE_TASKLET_WQ_FLAGS);
+ if (error) {
+ aprint_error_dev(dev, "could not create "
+ "recovery_mode_timer workqueue (%d)\n", error);
+ goto err_out;
+ }
/* Start the task */
callout_reset(&adapter->recovery_mode_timer, hz,
@@ -1252,7 +1253,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_workqueue(adapter);
ixgbe_free_pci_resources(adapter);
if (adapter->mta != NULL)
free(adapter->mta, M_DEVBUF);
@@ -1508,13 +1509,13 @@ ixgbe_is_sfp(struct ixgbe_hw *hw)
} /* ixgbe_is_sfp */
static void
-ixgbe_schedule_msf_tasklet(struct adapter *adapter)
+ixgbe_schedule_admin_tasklet(struct adapter *adapter)
{
if (adapter->schedule_wqs_ok) {
- if (!adapter->msf_pending) {
- adapter->msf_pending = true;
- workqueue_enqueue(adapter->msf_wq,
- &adapter->msf_wc, NULL);
+ if (!adapter->admin_pending) {
+ atomic_or_uint(&adapter->admin_pending, 1);
+ workqueue_enqueue(adapter->admin_wq,
+ &adapter->admin_wc, NULL);
}
}
}
@@ -1527,6 +1528,7 @@ ixgbe_config_link(struct adapter *adapte
{
struct ixgbe_hw *hw = &adapter->hw;
u32 autoneg, err = 0;
+ u32 task_requests = 0;
bool sfp, negotiate = false;
sfp = ixgbe_is_sfp(hw);
@@ -1534,11 +1536,11 @@ ixgbe_config_link(struct adapter *adapte
if (sfp) {
if (hw->phy.multispeed_fiber) {
ixgbe_enable_tx_laser(hw);
- kpreempt_disable();
- ixgbe_schedule_msf_tasklet(adapter);
- kpreempt_enable();
+ task_requests |= IXGBE_REQUEST_TASK_MSF;
}
- softint_schedule(adapter->mod_si);
+ task_requests |= IXGBE_REQUEST_TASK_MOD;
+ atomic_or_32(&adapter->task_requests, task_requests);
+ ixgbe_schedule_admin_tasklet(adapter);
} else {
struct ifmedia *ifm = &adapter->media;
@@ -1766,16 +1768,16 @@ ixgbe_add_hw_stats(struct adapter *adapt
NULL, xname, "Watchdog timeouts");
evcnt_attach_dynamic(&adapter->tso_err, EVCNT_TYPE_MISC,
NULL, xname, "TSO errors");
- evcnt_attach_dynamic(&adapter->link_irq, EVCNT_TYPE_INTR,
- NULL, xname, "Link MSI-X IRQ Handled");
- evcnt_attach_dynamic(&adapter->link_sicount, EVCNT_TYPE_INTR,
- NULL, xname, "Link softint");
- evcnt_attach_dynamic(&adapter->mod_sicount, EVCNT_TYPE_INTR,
- NULL, xname, "module softint");
- evcnt_attach_dynamic(&adapter->msf_sicount, EVCNT_TYPE_INTR,
- NULL, xname, "multimode softint");
- evcnt_attach_dynamic(&adapter->phy_sicount, EVCNT_TYPE_INTR,
- NULL, xname, "external PHY softint");
+ evcnt_attach_dynamic(&adapter->admin_irqev, EVCNT_TYPE_INTR,
+ NULL, xname, "Admin MSI-X IRQ Handled");
+ evcnt_attach_dynamic(&adapter->link_workev, EVCNT_TYPE_INTR,
+ NULL, xname, "Link event");
+ evcnt_attach_dynamic(&adapter->mod_workev, EVCNT_TYPE_INTR,
+ NULL, xname, "SFP+ module event");
+ evcnt_attach_dynamic(&adapter->msf_workev, EVCNT_TYPE_INTR,
+ NULL, xname, "Multispeed event");
+ evcnt_attach_dynamic(&adapter->phy_workev, EVCNT_TYPE_INTR,
+ NULL, xname, "External PHY event");
/* Max number of traffic class is 8 */
KASSERT(IXGBE_DCB_MAX_TRAFFIC_CLASS == 8);
@@ -2072,11 +2074,11 @@ ixgbe_clear_evcnt(struct adapter *adapte
adapter->enomem_tx_dma_setup.ev_count = 0;
adapter->tso_err.ev_count = 0;
adapter->watchdog_events.ev_count = 0;
- adapter->link_irq.ev_count = 0;
- adapter->link_sicount.ev_count = 0;
- adapter->mod_sicount.ev_count = 0;
- adapter->msf_sicount.ev_count = 0;
- adapter->phy_sicount.ev_count = 0;
+ adapter->admin_irqev.ev_count = 0;
+ adapter->link_workev.ev_count = 0;
+ adapter->mod_workev.ev_count = 0;
+ adapter->msf_workev.ev_count = 0;
+ adapter->phy_workev.ev_count = 0;
for (i = 0; i < IXGBE_TC_COUNTER_NUM; i++) {
if (i < __arraycount(stats->mpc)) {
@@ -3047,17 +3049,18 @@ invalid:
} /* ixgbe_media_change */
/************************************************************************
- * ixgbe_msix_link - Link status change ISR (MSI/MSI-X)
+ * ixgbe_msix_admin - Link status change ISR (MSI/MSI-X)
************************************************************************/
static int
-ixgbe_msix_link(void *arg)
+ixgbe_msix_admin(void *arg)
{
struct adapter *adapter = arg;
struct ixgbe_hw *hw = &adapter->hw;
u32 eicr, eicr_mask;
+ u32 task_requests = 0;
s32 retval;
- ++adapter->link_irq.ev_count;
+ ++adapter->admin_irqev.ev_count;
/* Pause other interrupts */
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER);
@@ -3092,21 +3095,21 @@ ixgbe_msix_link(void *arg)
|| ((hw->phy.sfp_type == ixgbe_sfp_type_not_present)
&& (eicr & IXGBE_EICR_LSC))) {
IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask);
- softint_schedule(adapter->mod_si);
+ task_requests |= IXGBE_REQUEST_TASK_MOD;
}
if ((hw->mac.type == ixgbe_mac_82599EB) &&
(eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
IXGBE_WRITE_REG(hw, IXGBE_EICR,
IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
- ixgbe_schedule_msf_tasklet(adapter);
+ task_requests |= IXGBE_REQUEST_TASK_MSF;
}
}
/* Link status change */
if (eicr & IXGBE_EICR_LSC) {
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
- softint_schedule(adapter->link_si);
+ task_requests |= IXGBE_REQUEST_TASK_LSC;
}
if (adapter->hw.mac.type != ixgbe_mac_82598EB) {
@@ -3117,7 +3120,7 @@ ixgbe_msix_link(void *arg)
return 1;
/* Disable the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
- softint_schedule(adapter->fdir_si);
+ task_requests |= IXGBE_REQUEST_TASK_FDIR;
}
if (eicr & IXGBE_EICR_ECC) {
@@ -3157,8 +3160,9 @@ ixgbe_msix_link(void *arg)
/* Check for VF message */
if ((adapter->feat_en & IXGBE_FEATURE_SRIOV) &&
- (eicr & IXGBE_EICR_MAILBOX))
- softint_schedule(adapter->mbx_si);
+ (eicr & IXGBE_EICR_MAILBOX)) {
+ task_requests |= IXGBE_REQUEST_TASK_MBX;
+ }
}
/* Check for fan failure */
@@ -3171,13 +3175,20 @@ ixgbe_msix_link(void *arg)
if ((hw->phy.type == ixgbe_phy_x550em_ext_t) &&
(eicr & IXGBE_EICR_GPI_SDP0_X540)) {
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540);
- softint_schedule(adapter->phy_si);
+ task_requests |= IXGBE_REQUEST_TASK_PHY;
+ }
+
+ if (task_requests != 0) {
+ atomic_or_32(&adapter->task_requests, task_requests);
+ ixgbe_schedule_admin_tasklet(adapter);
+ /* Re-enabling other interrupts is done in the admin task */
+ } else {
+ /* Re-enable other interrupts */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
}
- /* Re-enable other interrupts */
- IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
return 1;
-} /* ixgbe_msix_link */
+} /* ixgbe_msix_admin */
static void
ixgbe_eitr_write(struct adapter *adapter, uint32_t index, uint32_t itr)
@@ -3481,7 +3492,7 @@ map_err:
} /* ixgbe_allocate_pci_resources */
static void
-ixgbe_free_softint(struct adapter *adapter)
+ixgbe_free_workqueue(struct adapter *adapter)
{
struct ix_queue *que = adapter->queues;
struct tx_ring *txr = adapter->tx_rings;
@@ -3502,36 +3513,19 @@ ixgbe_free_softint(struct adapter *adapt
if (adapter->que_wq != NULL)
workqueue_destroy(adapter->que_wq);
- /* 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_wq != NULL) {
- workqueue_destroy(adapter->msf_wq);
- adapter->msf_wq = NULL;
+ if (adapter->admin_wq != NULL) {
+ workqueue_destroy(adapter->admin_wq);
+ adapter->admin_wq = NULL;
+ }
+ if (adapter->timer_wq != NULL) {
+ workqueue_destroy(adapter->timer_wq);
+ adapter->timer_wq = NULL;
+ }
+ if (adapter->recovery_mode_timer_wq != NULL) {
+ workqueue_destroy(adapter->recovery_mode_timer_wq);
+ adapter->recovery_mode_timer_wq = 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_free_workqueue */
/************************************************************************
* ixgbe_detach - Device removal routine
@@ -3585,7 +3579,7 @@ ixgbe_detach(device_t dev, int flags)
ether_ifdetach(adapter->ifp);
- ixgbe_free_softint(adapter);
+ ixgbe_free_workqueue(adapter);
/* let hardware know driver is unloading */
ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
@@ -3619,11 +3613,11 @@ ixgbe_detach(device_t dev, int flags)
evcnt_detach(&adapter->enomem_tx_dma_setup);
evcnt_detach(&adapter->watchdog_events);
evcnt_detach(&adapter->tso_err);
- evcnt_detach(&adapter->link_irq);
- evcnt_detach(&adapter->link_sicount);
- evcnt_detach(&adapter->mod_sicount);
- evcnt_detach(&adapter->msf_sicount);
- evcnt_detach(&adapter->phy_sicount);
+ evcnt_detach(&adapter->admin_irqev);
+ evcnt_detach(&adapter->link_workev);
+ evcnt_detach(&adapter->mod_workev);
+ evcnt_detach(&adapter->msf_workev);
+ evcnt_detach(&adapter->phy_workev);
for (i = 0; i < IXGBE_TC_COUNTER_NUM; i++) {
if (i < __arraycount(stats->mpc)) {
@@ -3975,6 +3969,9 @@ ixgbe_init_locked(struct adapter *adapte
/* Configure RX settings */
ixgbe_initialize_receive_units(adapter);
+ /* Initialize variable holding task enqueue requests interrupts */
+ adapter->task_requests = 0;
+
/* Enable SDP & MSI-X interrupts based on adapter */
ixgbe_config_gpie(adapter);
@@ -4066,6 +4063,7 @@ ixgbe_init_locked(struct adapter *adapte
ixgbe_enable_rx_dma(hw, rxctrl);
callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
+ atomic_and_uint(&adapter->timer_pending, ~1);
if (adapter->feat_en & IXGBE_FEATURE_RECOVERY_MODE)
callout_reset(&adapter->recovery_mode_timer, hz,
ixgbe_recovery_mode_timer, adapter);
@@ -4447,15 +4445,19 @@ ixgbe_local_timer(void *arg)
{
struct adapter *adapter = arg;
- IXGBE_CORE_LOCK(adapter);
- ixgbe_local_timer1(adapter);
- IXGBE_CORE_UNLOCK(adapter);
+ if (adapter->schedule_wqs_ok) {
+ if (!adapter->timer_pending) {
+ atomic_or_uint(&adapter->timer_pending, 1);
+ workqueue_enqueue(adapter->timer_wq,
+ &adapter->timer_wc, NULL);
+ }
+ }
}
static void
-ixgbe_local_timer1(void *arg)
+ixgbe_handle_timer(struct work *wk, void *context)
{
- struct adapter *adapter = arg;
+ struct adapter *adapter = context;
device_t dev = adapter->dev;
struct ix_queue *que = adapter->queues;
u64 queues = 0;
@@ -4463,7 +4465,7 @@ ixgbe_local_timer1(void *arg)
int hung = 0;
int i;
- KASSERT(mutex_owned(&adapter->core_mtx));
+ IXGBE_CORE_LOCK(adapter);
/* Check for pluggable optics */
if (adapter->sfp_probe)
@@ -4547,6 +4549,8 @@ ixgbe_local_timer1(void *arg)
#endif
out:
+ atomic_and_uint(&adapter->timer_pending, ~1);
+ IXGBE_CORE_UNLOCK(adapter);
callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter);
return;
@@ -4555,7 +4559,8 @@ watchdog:
adapter->ifp->if_flags &= ~IFF_RUNNING;
adapter->watchdog_events.ev_count++;
ixgbe_init_locked(adapter);
-} /* ixgbe_local_timer */
+ IXGBE_CORE_UNLOCK(adapter);
+} /* ixgbe_handle_timer */
/************************************************************************
* ixgbe_recovery_mode_timer - Recovery mode timer routine
@@ -4564,6 +4569,18 @@ static void
ixgbe_recovery_mode_timer(void *arg)
{
struct adapter *adapter = arg;
+
+ if (!adapter->recovery_mode_timer_pending) {
+ atomic_or_uint(&adapter->recovery_mode_timer_pending, 1);
+ workqueue_enqueue(adapter->recovery_mode_timer_wq,
+ &adapter->recovery_mode_timer_wc, NULL);
+ }
+}
+
+static void
+ixgbe_handle_recovery_mode_timer(struct work *wk, void *context)
+{
+ struct adapter *adapter = context;
struct ixgbe_hw *hw = &adapter->hw;
IXGBE_CORE_LOCK(adapter);
@@ -4578,10 +4595,11 @@ ixgbe_recovery_mode_timer(void *arg)
} else
atomic_cas_uint(&adapter->recovery_mode, 1, 0);
+ atomic_and_uint(&adapter->recovery_mode_timer_pending, ~1);
callout_reset(&adapter->recovery_mode_timer, hz,
ixgbe_recovery_mode_timer, adapter);
IXGBE_CORE_UNLOCK(adapter);
-} /* ixgbe_recovery_mode_timer */
+} /* ixgbe_handle_recovery_mode_timer */
/************************************************************************
* ixgbe_sfp_probe
@@ -4628,8 +4646,7 @@ ixgbe_handle_mod(void *context)
device_t dev = adapter->dev;
u32 err, cage_full = 0;
- IXGBE_CORE_LOCK(adapter);
- ++adapter->mod_sicount.ev_count;
+ ++adapter->mod_workev.ev_count;
if (adapter->hw.need_crosstalk_fix) {
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
@@ -4679,9 +4696,23 @@ ixgbe_handle_mod(void *context)
goto out;
}
}
- ixgbe_schedule_msf_tasklet(adapter);
+
out:
+ /* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */
+ adapter->phy_layer = ixgbe_get_supported_physical_layer(hw);
+
+ /* Adjust media types shown in ifconfig */
IXGBE_CORE_UNLOCK(adapter);
+ ifmedia_removeall(&adapter->media);
+ ixgbe_add_media_types(adapter);
+ ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
+ IXGBE_CORE_LOCK(adapter);
+
+ atomic_or_32(&adapter->task_requests, IXGBE_REQUEST_TASK_MSF);
+ /*
+ * Don't call ixgbe_schedule_admin_tasklet() because we are on
+ * the workqueue now.
+ */
} /* ixgbe_handle_mod */
@@ -4689,43 +4720,20 @@ out:
* ixgbe_handle_msf - Tasklet for MSF (multispeed fiber) interrupts
************************************************************************/
static void
-ixgbe_handle_msf(struct work *wk, void *context)
+ixgbe_handle_msf(void *context)
{
struct adapter *adapter = context;
- struct ifnet *ifp = adapter->ifp;
struct ixgbe_hw *hw = &adapter->hw;
u32 autoneg;
bool negotiate;
- /*
- * Hold the IFNET_LOCK across this entire call. This will
- * prevent additional changes to adapter->phy_layer
- * and serialize calls to this tasklet. We cannot hold the
- * CORE_LOCK while calling into the ifmedia functions as
- * they may block while allocating memory.
- */
- IFNET_LOCK(ifp);
-
- IXGBE_CORE_LOCK(adapter);
- adapter->msf_pending = false;
- ++adapter->msf_sicount.ev_count;
- /* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */
- adapter->phy_layer = ixgbe_get_supported_physical_layer(hw);
+ ++adapter->msf_workev.ev_count;
autoneg = hw->phy.autoneg_advertised;
if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate);
- else
- negotiate = 0;
if (hw->mac.ops.setup_link)
hw->mac.ops.setup_link(hw, autoneg, TRUE);
- IXGBE_CORE_UNLOCK(adapter);
-
- /* Adjust media types shown in ifconfig */
- ifmedia_removeall(&adapter->media);
- ixgbe_add_media_types(adapter);
- ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO);
- IFNET_UNLOCK(ifp);
} /* ixgbe_handle_msf */
/************************************************************************
@@ -4738,7 +4746,7 @@ ixgbe_handle_phy(void *context)
struct ixgbe_hw *hw = &adapter->hw;
int error;
- ++adapter->phy_sicount.ev_count;
+ ++adapter->phy_workev.ev_count;
error = hw->phy.ops.handle_lasi(hw);
if (error == IXGBE_ERR_OVERTEMP)
device_printf(adapter->dev,
@@ -4750,6 +4758,68 @@ ixgbe_handle_phy(void *context)
} /* ixgbe_handle_phy */
static void
+ixgbe_handle_admin(struct work *wk, void *context)
+{
+ struct adapter *adapter = context;
+ struct ifnet *ifp = adapter->ifp;
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 req;
+
+ /*
+ * Hold the IFNET_LOCK across this entire call. This will
+ * prevent additional changes to adapter->phy_layer
+ * and serialize calls to this tasklet. We cannot hold the
+ * CORE_LOCK while calling into the ifmedia functions as
+ * they call ifmedia_lock() and the lock is CORE_LOCK.
+ */
+ IFNET_LOCK(ifp);
+ IXGBE_CORE_LOCK(adapter);
+ while ((req = adapter->task_requests) != 0) {
+ if ((req & IXGBE_REQUEST_TASK_LSC) != 0) {
+ ixgbe_handle_link(adapter);
+ atomic_and_32(&adapter->task_requests,
+ ~IXGBE_REQUEST_TASK_LSC);
+ }
+ if ((req & IXGBE_REQUEST_TASK_MOD) != 0) {
+ ixgbe_handle_mod(adapter);
+ atomic_and_32(&adapter->task_requests,
+ ~IXGBE_REQUEST_TASK_MOD);
+ }
+ if ((req & IXGBE_REQUEST_TASK_MSF) != 0) {
+ ixgbe_handle_msf(adapter);
+ atomic_and_32(&adapter->task_requests,
+ ~IXGBE_REQUEST_TASK_MSF);
+ }
+ if ((req & IXGBE_REQUEST_TASK_PHY) != 0) {
+ ixgbe_handle_phy(adapter);
+ atomic_and_32(&adapter->task_requests,
+ ~IXGBE_REQUEST_TASK_PHY);
+ }
+ if ((req & IXGBE_REQUEST_TASK_FDIR) != 0) {
+ ixgbe_reinit_fdir(adapter);
+ atomic_and_32(&adapter->task_requests,
+ ~IXGBE_REQUEST_TASK_FDIR);
+ }
+#if 0 /* notyet */
+ if ((req & IXGBE_REQUEST_TASK_MBX) != 0) {
+ ixgbe_handle_mbx(adapter);
+ atomic_and_32(&adapter->task_requests,
+ ~IXGBE_REQUEST_TASK_MBX);
+ }
+#endif
+ }
+ atomic_and_uint(&adapter->admin_pending, ~1);
+ if ((adapter->feat_en & IXGBE_FEATURE_MSIX) != 0) {
+ /* Re-enable other interrupts */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+ } else
+ ixgbe_enable_intr(adapter);
+
+ IXGBE_CORE_UNLOCK(adapter);
+ IFNET_UNLOCK(ifp);
+} /* ixgbe_handle_admin */
+
+static void
ixgbe_ifstop(struct ifnet *ifp, int disable)
{
struct adapter *adapter = ifp->if_softc;
@@ -4758,8 +4828,10 @@ ixgbe_ifstop(struct ifnet *ifp, int disa
ixgbe_stop(adapter);
IXGBE_CORE_UNLOCK(adapter);
- workqueue_wait(adapter->msf_wq, &adapter->msf_wc);
- adapter->msf_pending = false;
+ workqueue_wait(adapter->admin_wq, &adapter->admin_wc);
+ atomic_and_uint(&adapter->admin_pending, ~1);
+ workqueue_wait(adapter->timer_wq, &adapter->timer_wc);
+ atomic_and_uint(&adapter->timer_pending, ~1);
}
/************************************************************************
@@ -5064,7 +5136,9 @@ ixgbe_legacy_irq(void *arg)
struct ifnet *ifp = adapter->ifp;
struct tx_ring *txr = adapter->tx_rings;
bool more = false;
+ bool reenable_intr = true;
u32 eicr, eicr_mask;
+ u32 task_requests = 0;
/* Silicon errata #26 on 82598 */
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
@@ -5110,7 +5184,7 @@ ixgbe_legacy_irq(void *arg)
/* Link status change */
if (eicr & IXGBE_EICR_LSC)
- softint_schedule(adapter->link_si);
+ task_requests |= IXGBE_REQUEST_TASK_LSC;
if (ixgbe_is_sfp(hw)) {
/* Pluggable optics-related interrupt */
@@ -5121,26 +5195,34 @@ ixgbe_legacy_irq(void *arg)
if (eicr & eicr_mask) {
IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask);
- softint_schedule(adapter->mod_si);
+ task_requests |= IXGBE_REQUEST_TASK_MOD;
}
if ((hw->mac.type == ixgbe_mac_82599EB) &&
(eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw))) {
IXGBE_WRITE_REG(hw, IXGBE_EICR,
IXGBE_EICR_GPI_SDP1_BY_MAC(hw));
- ixgbe_schedule_msf_tasklet(adapter);
+ task_requests |= IXGBE_REQUEST_TASK_MSF;
}
}
/* External PHY interrupt */
if ((hw->phy.type == ixgbe_phy_x550em_ext_t) &&
(eicr & IXGBE_EICR_GPI_SDP0_X540))
- softint_schedule(adapter->phy_si);
+ task_requests |= IXGBE_REQUEST_TASK_PHY;
if (more) {
que->req.ev_count++;
ixgbe_sched_handle_que(adapter, que);
- } else
+ reenable_intr = false;
+ }
+ if (task_requests != 0) {
+ atomic_or_32(&adapter->task_requests, task_requests);
+ ixgbe_schedule_admin_tasklet(adapter);
+ reenable_intr = false;
+ }
+
+ if (reenable_intr == true)
ixgbe_enable_intr(adapter);
return 1;
@@ -6741,7 +6823,7 @@ ixgbe_allocate_msix(struct adapter *adap
#endif
/* Set the link handler function */
adapter->osdep.ihs[vector] = pci_intr_establish_xname(pc,
- adapter->osdep.intrs[vector], IPL_NET, ixgbe_msix_link, adapter,
+ adapter->osdep.intrs[vector], IPL_NET, ixgbe_msix_admin, adapter,
intr_xname);
if (adapter->osdep.ihs[vector] == NULL) {
aprint_error_dev(dev, "Failed to register LINK handler\n");
@@ -6761,19 +6843,6 @@ ixgbe_allocate_msix(struct adapter *adap
else
aprint_normal("\n");
- if (adapter->feat_cap & IXGBE_FEATURE_SRIOV) {
- adapter->mbx_si =
- softint_establish(SOFTINT_NET | IXGBE_SOFTINT_FLAGS,
- ixgbe_handle_mbx, 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);
@@ -6782,7 +6851,7 @@ ixgbe_allocate_msix(struct adapter *adap
err_out:
kcpuset_destroy(affinity);
- ixgbe_free_softint(adapter);
+ ixgbe_free_workqueue(adapter);
ixgbe_free_pciintr_resources(adapter);
return (error);
} /* ixgbe_allocate_msix */
@@ -6906,15 +6975,12 @@ ixgbe_handle_link(void *context)
struct adapter *adapter = context;
struct ixgbe_hw *hw = &adapter->hw;
- IXGBE_CORE_LOCK(adapter);
- ++adapter->link_sicount.ev_count;
+ ++adapter->link_workev.ev_count;
ixgbe_check_link(hw, &adapter->link_speed, &adapter->link_up, 0);
ixgbe_update_link_status(adapter);
/* Re-enable link interrupts */
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC);
-
- IXGBE_CORE_UNLOCK(adapter);
} /* ixgbe_handle_link */
#if 0
Index: src/sys/dev/pci/ixgbe/ixgbe.h
diff -u src/sys/dev/pci/ixgbe/ixgbe.h:1.66 src/sys/dev/pci/ixgbe/ixgbe.h:1.67
--- src/sys/dev/pci/ixgbe/ixgbe.h:1.66 Tue Jun 23 05:50:01 2020
+++ src/sys/dev/pci/ixgbe/ixgbe.h Thu Jun 25 07:53:01 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe.h,v 1.66 2020/06/23 05:50:01 msaitoh Exp $ */
+/* $NetBSD: ixgbe.h,v 1.67 2020/06/25 07:53:01 msaitoh Exp $ */
/******************************************************************************
SPDX-License-Identifier: BSD-3-Clause
@@ -475,6 +475,10 @@ struct adapter {
struct ifmedia media;
callout_t timer;
+ struct workqueue *timer_wq;
+ struct work timer_wc;
+ u_int timer_pending;
+
u_short if_flags; /* saved ifp->if_flags */
int ec_capenable; /* saved ec->ec_capenable */
@@ -513,18 +517,15 @@ struct adapter {
/* Support for pluggable optics */
bool sfp_probe;
- void *link_si; /* Link tasklet */
- void *mod_si; /* SFP tasklet */
- struct workqueue *msf_wq; /* Multispeed Fiber */
- struct work msf_wc;
- bool msf_pending;
- void *mbx_si; /* VF -> PF mailbox interrupt */
/* Flow Director */
int fdir_reinit;
- void *fdir_si;
- void *phy_si; /* PHY intr tasklet */
+ /* Admin task */
+ struct workqueue *admin_wq; /* Link, SFP, PHY and FDIR */
+ struct work admin_wc;
+ u_int admin_pending;
+ volatile u32 task_requests;
bool txrx_use_workqueue;
@@ -583,7 +584,10 @@ struct adapter {
/* Firmware error check */
u_int recovery_mode;
- struct callout recovery_mode_timer;
+ callout_t recovery_mode_timer;
+ struct workqueue *recovery_mode_timer_wq;
+ struct work recovery_mode_timer_wc;
+ u_int recovery_mode_timer_pending;
/* Misc stats maintained by the driver */
struct evcnt efbig_tx_dma_setup;
@@ -595,11 +599,11 @@ struct adapter {
struct evcnt enomem_tx_dma_setup;
struct evcnt tso_err;
struct evcnt watchdog_events;
- struct evcnt link_irq;
- struct evcnt link_sicount;
- struct evcnt mod_sicount;
- struct evcnt msf_sicount;
- struct evcnt phy_sicount;
+ struct evcnt admin_irqev;
+ struct evcnt link_workev;
+ struct evcnt mod_workev;
+ struct evcnt msf_workev;
+ struct evcnt phy_workev;
union {
struct ixgbe_hw_stats pf;
@@ -761,9 +765,15 @@ void ixgbe_free_receive_structures(struc
bool ixgbe_txeof(struct tx_ring *);
bool ixgbe_rxeof(struct ix_queue *);
-const struct sysctlnode *ixgbe_sysctl_instance(struct adapter *);
+#define IXGBE_REQUEST_TASK_MOD 0x01
+#define IXGBE_REQUEST_TASK_MSF 0x02
+#define IXGBE_REQUEST_TASK_MBX 0x04
+#define IXGBE_REQUEST_TASK_FDIR 0x08
+#define IXGBE_REQUEST_TASK_PHY 0x10
+#define IXGBE_REQUEST_TASK_LSC 0x20
/* For NetBSD */
+const struct sysctlnode *ixgbe_sysctl_instance(struct adapter *);
void ixgbe_jcl_reinit(struct adapter *, bus_dma_tag_t, struct rx_ring *,
int, size_t);
void ixgbe_jcl_destroy(struct adapter *, struct rx_ring *);
Index: src/sys/dev/pci/ixgbe/ixgbe_netbsd.c
diff -u src/sys/dev/pci/ixgbe/ixgbe_netbsd.c:1.14 src/sys/dev/pci/ixgbe/ixgbe_netbsd.c:1.15
--- src/sys/dev/pci/ixgbe/ixgbe_netbsd.c:1.14 Fri Apr 17 02:21:25 2020
+++ src/sys/dev/pci/ixgbe/ixgbe_netbsd.c Thu Jun 25 07:53:02 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_netbsd.c,v 1.14 2020/04/17 02:21:25 msaitoh Exp $ */
+/* $NetBSD: ixgbe_netbsd.c,v 1.15 2020/06/25 07:53:02 msaitoh Exp $ */
/*
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -305,3 +305,19 @@ atomic_load_acq_uint(volatile u_int *p)
{
return atomic_load_acquire(p);
}
+
+void
+ixgbe_delay(unsigned int us)
+{
+
+ if (__predict_false(cold))
+ delay(us);
+ else if ((us / 1000) >= hztoms(1)) {
+ /*
+ * Wait at least two clock ticks so we know the time has
+ * passed.
+ */
+ kpause("ixgdly", false, mstohz(us / 1000) + 1, NULL);
+ } else
+ delay(us);
+}
Index: src/sys/dev/pci/ixgbe/ixgbe_osdep.h
diff -u src/sys/dev/pci/ixgbe/ixgbe_osdep.h:1.26 src/sys/dev/pci/ixgbe/ixgbe_osdep.h:1.27
--- src/sys/dev/pci/ixgbe/ixgbe_osdep.h:1.26 Thu Jun 11 05:16:22 2020
+++ src/sys/dev/pci/ixgbe/ixgbe_osdep.h Thu Jun 25 07:53:02 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: ixgbe_osdep.h,v 1.26 2020/06/11 05:16:22 msaitoh Exp $ */
+/* $NetBSD: ixgbe_osdep.h,v 1.27 2020/06/25 07:53:02 msaitoh Exp $ */
/******************************************************************************
SPDX-License-Identifier: BSD-3-Clause
@@ -66,9 +66,9 @@ enum {
IXGBE_ERROR_CAUTION,
};
-/* The happy-fun DELAY macro is defined in /usr/src/sys/i386/include/clock.h */
-#define usec_delay(x) DELAY(x)
-#define msec_delay(x) DELAY(1000*(x))
+#define usec_delay(x) ixgbe_delay(x)
+#define msec_delay(x) ixgbe_delay((x) * 1000)
+void ixgbe_delay(unsigned int);
#define DBG 0
#define MSGOUT(S, A, B) printf(S "\n", A, B)
Index: src/sys/dev/pci/ixgbe/ixv.c
diff -u src/sys/dev/pci/ixgbe/ixv.c:1.150 src/sys/dev/pci/ixgbe/ixv.c:1.151
--- src/sys/dev/pci/ixgbe/ixv.c:1.150 Thu Jun 18 09:00:11 2020
+++ src/sys/dev/pci/ixgbe/ixv.c Thu Jun 25 07:53:02 2020
@@ -1,4 +1,4 @@
-/*$NetBSD: ixv.c,v 1.150 2020/06/18 09:00:11 msaitoh Exp $*/
+/*$NetBSD: ixv.c,v 1.151 2020/06/25 07:53:02 msaitoh Exp $*/
/******************************************************************************
@@ -96,13 +96,15 @@ static void ixv_media_status(struct ifne
static int ixv_media_change(struct ifnet *);
static int ixv_allocate_pci_resources(struct adapter *,
const struct pci_attach_args *);
+static void ixv_free_workqueue(struct adapter *);
static int ixv_allocate_msix(struct adapter *,
const struct pci_attach_args *);
static int ixv_configure_interrupts(struct adapter *);
static void ixv_free_pci_resources(struct adapter *);
static void ixv_local_timer(void *);
-static void ixv_local_timer_locked(void *);
+static void ixv_handle_timer(struct work *, void *);
static int ixv_setup_interface(device_t, struct adapter *);
+static void ixv_schedule_admin_tasklet(struct adapter *);
static int ixv_negotiate_api(struct adapter *);
static void ixv_initialize_transmit_units(struct adapter *);
@@ -147,11 +149,11 @@ static int ixv_sysctl_tdh_handler(SYSCTL
static int ixv_msix_que(void *);
static int ixv_msix_mbx(void *);
-/* Deferred interrupt tasklets */
+/* Event handlers running on workqueue */
static void ixv_handle_que(void *);
-static void ixv_handle_link(void *);
-/* Workqueue handler for deferred work */
+/* Deferred workqueue handlers */
+static void ixv_handle_admin(struct work *, void *);
static void ixv_handle_que_work(struct work *, void *);
const struct sysctlnode *ixv_sysctl_instance(struct adapter *);
@@ -228,10 +230,12 @@ TUNABLE_INT("hw.ixv.enable_legacy_tx", &
#define IXGBE_CALLOUT_FLAGS CALLOUT_MPSAFE
#define IXGBE_SOFTINT_FLAGS SOFTINT_MPSAFE
#define IXGBE_WORKQUEUE_FLAGS WQ_PERCPU | WQ_MPSAFE
+#define IXGBE_TASKLET_WQ_FLAGS WQ_MPSAFE
#else
#define IXGBE_CALLOUT_FLAGS 0
#define IXGBE_SOFTINT_FLAGS 0
#define IXGBE_WORKQUEUE_FLAGS WQ_PERCPU
+#define IXGBE_TASKLET_WQ_FLAGS 0
#endif
#define IXGBE_WORKQUEUE_PRI PRI_SOFTNET
@@ -307,6 +311,7 @@ ixv_attach(device_t parent, device_t dev
const struct pci_attach_args *pa = aux;
const char *apivstr;
const char *str;
+ char wqname[MAXCOMLEN];
char buf[256];
INIT_DEBUGOUT("ixv_attach: begin");
@@ -354,8 +359,17 @@ ixv_attach(device_t parent, device_t dev
/* SYSCTL APIs */
ixv_add_device_sysctls(adapter);
- /* Set up the timer callout */
+ /* Set up the timer callout and workqueue */
callout_init(&adapter->timer, IXGBE_CALLOUT_FLAGS);
+ snprintf(wqname, sizeof(wqname), "%s-timer", device_xname(dev));
+ error = workqueue_create(&adapter->timer_wq, wqname,
+ ixv_handle_timer, adapter, IXGBE_WORKQUEUE_PRI, IPL_NET,
+ IXGBE_TASKLET_WQ_FLAGS);
+ if (error) {
+ aprint_error_dev(dev,
+ "could not create timer workqueue (%d)\n", error);
+ goto err_out;
+ }
/* Save off the information about this board */
id = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ID_REG);
@@ -569,7 +583,6 @@ ixv_detach(device_t dev, int flags)
{
struct adapter *adapter = device_private(dev);
struct ixgbe_hw *hw = &adapter->hw;
- struct ix_queue *que = adapter->queues;
struct tx_ring *txr = adapter->tx_rings;
struct rx_ring *rxr = adapter->rx_rings;
struct ixgbevf_hw_stats *stats = &adapter->stats.vf;
@@ -593,23 +606,9 @@ ixv_detach(device_t dev, int flags)
}
#endif
- 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);
- }
- if (adapter->txr_wq != NULL)
- workqueue_destroy(adapter->txr_wq);
- if (adapter->txr_wq_enqueued != NULL)
- percpu_free(adapter->txr_wq_enqueued, sizeof(u_int));
- if (adapter->que_wq != NULL)
- workqueue_destroy(adapter->que_wq);
-
- /* Drain the Mailbox(link) queue */
- softint_disestablish(adapter->link_si);
-
ether_ifdetach(adapter->ifp);
callout_halt(&adapter->timer, NULL);
+ ixv_free_workqueue(adapter);
if (adapter->feat_en & IXGBE_FEATURE_NETMAP)
netmap_detach(adapter->ifp);
@@ -632,7 +631,8 @@ ixv_detach(device_t dev, int flags)
evcnt_detach(&adapter->enomem_tx_dma_setup);
evcnt_detach(&adapter->watchdog_events);
evcnt_detach(&adapter->tso_err);
- evcnt_detach(&adapter->link_irq);
+ evcnt_detach(&adapter->admin_irqev);
+ evcnt_detach(&adapter->link_workev);
txr = adapter->tx_rings;
for (int i = 0; i < adapter->num_queues; i++, rxr++, txr++) {
@@ -759,6 +759,9 @@ ixv_init_locked(struct adapter *adapter)
/* Configure RX settings */
ixv_initialize_receive_units(adapter);
+ /* Initialize variable holding task enqueue requests interrupts */
+ adapter->task_requests = 0;
+
/* Set up VLAN offload and filter */
ixv_setup_vlan_support(adapter);
@@ -784,6 +787,10 @@ ixv_init_locked(struct adapter *adapter)
/* Start watchdog */
callout_reset(&adapter->timer, hz, ixv_local_timer, adapter);
+ atomic_and_uint(&adapter->timer_pending, ~1);
+
+ /* OK to schedule workqueues. */
+ adapter->schedule_wqs_ok = true;
/* And now turn on interrupts */
ixv_enable_intr(adapter);
@@ -951,14 +958,13 @@ ixv_msix_mbx(void *arg)
struct adapter *adapter = arg;
struct ixgbe_hw *hw = &adapter->hw;
- ++adapter->link_irq.ev_count;
+ ++adapter->admin_irqev.ev_count;
/* NetBSD: We use auto-clear, so it's not required to write VTEICR */
/* Link status change */
hw->mac.get_link_status = TRUE;
- softint_schedule(adapter->link_si);
-
- IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, (1 << adapter->vector));
+ atomic_or_32(&adapter->task_requests, IXGBE_REQUEST_TASK_MBX);
+ ixv_schedule_admin_tasklet(adapter);
return 1;
} /* ixv_msix_mbx */
@@ -1053,6 +1059,18 @@ ixv_media_change(struct ifnet *ifp)
return (0);
} /* ixv_media_change */
+static void
+ixv_schedule_admin_tasklet(struct adapter *adapter)
+{
+ if (adapter->schedule_wqs_ok) {
+ if (!adapter->admin_pending) {
+ atomic_or_uint(&adapter->admin_pending, 1);
+ workqueue_enqueue(adapter->admin_wq,
+ &adapter->admin_wc, NULL);
+ }
+ }
+}
+
/************************************************************************
* ixv_negotiate_api
*
@@ -1233,15 +1251,19 @@ ixv_local_timer(void *arg)
{
struct adapter *adapter = arg;
- IXGBE_CORE_LOCK(adapter);
- ixv_local_timer_locked(adapter);
- IXGBE_CORE_UNLOCK(adapter);
+ if (adapter->schedule_wqs_ok) {
+ if (!adapter->timer_pending) {
+ atomic_or_uint(&adapter->timer_pending, 1);
+ workqueue_enqueue(adapter->timer_wq,
+ &adapter->timer_wc, NULL);
+ }
+ }
}
static void
-ixv_local_timer_locked(void *arg)
+ixv_handle_timer(struct work *wk, void *context)
{
- struct adapter *adapter = arg;
+ struct adapter *adapter = context;
device_t dev = adapter->dev;
struct ix_queue *que = adapter->queues;
u64 queues = 0;
@@ -1249,10 +1271,11 @@ ixv_local_timer_locked(void *arg)
int hung = 0;
int i;
- KASSERT(mutex_owned(&adapter->core_mtx));
+ IXGBE_CORE_LOCK(adapter);
if (ixv_check_link(adapter)) {
ixv_init_locked(adapter);
+ IXGBE_CORE_UNLOCK(adapter);
return;
}
@@ -1325,17 +1348,19 @@ ixv_local_timer_locked(void *arg)
}
#endif
+ atomic_and_uint(&adapter->timer_pending, ~1);
+ IXGBE_CORE_UNLOCK(adapter);
callout_reset(&adapter->timer, hz, ixv_local_timer, adapter);
return;
watchdog:
-
device_printf(adapter->dev, "Watchdog timeout -- resetting\n");
adapter->ifp->if_flags &= ~IFF_RUNNING;
adapter->watchdog_events.ev_count++;
ixv_init_locked(adapter);
-} /* ixv_local_timer */
+ IXGBE_CORE_UNLOCK(adapter);
+} /* ixv_handle_timer */
/************************************************************************
* ixv_update_link_status - Update OS on link state
@@ -1416,6 +1441,11 @@ ixv_ifstop(struct ifnet *ifp, int disabl
IXGBE_CORE_LOCK(adapter);
ixv_stop(adapter);
IXGBE_CORE_UNLOCK(adapter);
+
+ workqueue_wait(adapter->admin_wq, &adapter->admin_wc);
+ atomic_and_uint(&adapter->admin_pending, ~1);
+ workqueue_wait(adapter->timer_wq, &adapter->timer_wc);
+ atomic_and_uint(&adapter->timer_pending, ~1);
}
static void
@@ -1440,6 +1470,9 @@ ixv_stop(void *arg)
hw->mac.ops.stop_adapter(hw);
callout_stop(&adapter->timer);
+ /* Don't schedule workqueues. */
+ adapter->schedule_wqs_ok = false;
+
/* reprogram the RAR[0] in case user changed it. */
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
@@ -1500,6 +1533,39 @@ map_err:
return (0);
} /* ixv_allocate_pci_resources */
+static void
+ixv_free_workqueue(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);
+ }
+ if (adapter->txr_wq != NULL)
+ workqueue_destroy(adapter->txr_wq);
+ if (adapter->txr_wq_enqueued != NULL)
+ percpu_free(adapter->txr_wq_enqueued, sizeof(u_int));
+ if (adapter->que_wq != NULL)
+ workqueue_destroy(adapter->que_wq);
+
+ /* Drain the Mailbox(link) queue */
+ if (adapter->admin_wq != NULL) {
+ workqueue_destroy(adapter->admin_wq);
+ adapter->admin_wq = NULL;
+ }
+ if (adapter->timer_wq != NULL) {
+ workqueue_destroy(adapter->timer_wq);
+ adapter->timer_wq = NULL;
+ }
+} /* ixv_free_workqueue */
+
/************************************************************************
* ixv_free_pci_resources
************************************************************************/
@@ -2542,8 +2608,10 @@ ixv_add_stats_sysctls(struct adapter *ad
NULL, xname, "Watchdog timeouts");
evcnt_attach_dynamic(&adapter->tso_err, EVCNT_TYPE_MISC,
NULL, xname, "TSO errors");
- evcnt_attach_dynamic(&adapter->link_irq, EVCNT_TYPE_INTR,
- NULL, xname, "Link MSI-X IRQ Handled");
+ evcnt_attach_dynamic(&adapter->admin_irqev, EVCNT_TYPE_INTR,
+ NULL, xname, "Admin MSI-X IRQ Handled");
+ evcnt_attach_dynamic(&adapter->link_workev, EVCNT_TYPE_INTR,
+ NULL, xname, "Admin event");
for (int i = 0; i < adapter->num_queues; i++, rxr++, txr++) {
snprintf(adapter->queues[i].evnamebuf,
@@ -2712,7 +2780,8 @@ ixv_clear_evcnt(struct adapter *adapter)
adapter->enomem_tx_dma_setup.ev_count = 0;
adapter->watchdog_events.ev_count = 0;
adapter->tso_err.ev_count = 0;
- adapter->link_irq.ev_count = 0;
+ adapter->admin_irqev.ev_count = 0;
+ adapter->link_workev.ev_count = 0;
for (i = 0; i < adapter->num_queues; i++, rxr++, txr++) {
adapter->queues[i].irqs.ev_count = 0;
@@ -2829,8 +2898,10 @@ ixv_print_debug_info(struct adapter *ada
txr->me, (long)txr->no_desc_avail.ev_count);
}
- device_printf(dev, "MBX IRQ Handled: %lu\n",
- (long)adapter->link_irq.ev_count);
+ device_printf(dev, "Admin IRQ Handled: %lu\n",
+ (long)adapter->admin_irqev.ev_count);
+ device_printf(dev, "Admin work Handled: %lu\n",
+ (long)adapter->link_workev.ev_count);
} /* ixv_print_debug_info */
/************************************************************************
@@ -3317,8 +3388,16 @@ ixv_allocate_msix(struct adapter *adapte
aprint_normal("\n");
/* Tasklets for Mailbox */
- adapter->link_si = softint_establish(SOFTINT_NET |IXGBE_SOFTINT_FLAGS,
- ixv_handle_link, adapter);
+ snprintf(wqname, sizeof(wqname), "%s-admin", device_xname(dev));
+ error = workqueue_create(&adapter->admin_wq, wqname,
+ ixv_handle_admin, adapter, IXGBE_WORKQUEUE_PRI, IPL_NET,
+ IXGBE_TASKLET_WQ_FLAGS);
+ if (error) {
+ aprint_error_dev(dev,
+ "could not create admin workqueue (%d)\n", error);
+ goto err_out;
+ }
+
/*
* Due to a broken design QEMU will fail to properly
* enable the guest for MSI-X unless the vectors in
@@ -3336,6 +3415,11 @@ ixv_allocate_msix(struct adapter *adapte
kcpuset_destroy(affinity);
return (0);
+err_out:
+ kcpuset_destroy(affinity);
+ ixv_free_workqueue(adapter);
+ ixv_free_pci_resources(adapter);
+ return (error);
} /* ixv_allocate_msix */
/************************************************************************
@@ -3390,23 +3474,31 @@ ixv_configure_interrupts(struct adapter
/************************************************************************
- * ixv_handle_link - Tasklet handler for MSI-X MBX interrupts
+ * ixv_handle_admin - Tasklet handler for MSI-X MBX interrupts
*
* Done outside of interrupt context since the driver might sleep
************************************************************************/
static void
-ixv_handle_link(void *context)
+ixv_handle_admin(struct work *wk, void *context)
{
struct adapter *adapter = context;
+ struct ixgbe_hw *hw = &adapter->hw;
IXGBE_CORE_LOCK(adapter);
+ ++adapter->link_workev.ev_count;
adapter->hw.mac.ops.check_link(&adapter->hw, &adapter->link_speed,
&adapter->link_up, FALSE);
ixv_update_link_status(adapter);
+ adapter->task_requests = 0;
+ atomic_and_uint(&adapter->admin_pending, ~1);
+
+ /* Re-enable interrupts */
+ IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, (1 << adapter->vector));
+
IXGBE_CORE_UNLOCK(adapter);
-} /* ixv_handle_link */
+} /* ixv_handle_admin */
/************************************************************************
* ixv_check_link - Used in the local timer to poll for link changes