Index: sys/dev/e1000/e1000_80003es2lan.c =================================================================== --- sys/dev/e1000/e1000_80003es2lan.c +++ sys/dev/e1000/e1000_80003es2lan.c @@ -408,7 +408,7 @@ s32 timeout = 50; DEBUGFUNC("e1000_acquire_swfw_sync_80003es2lan"); - + ASSERT_NO_LOCKS(); while (i < timeout) { if (e1000_get_hw_semaphore_generic(hw)) return -E1000_ERR_SWFW_SYNC; Index: sys/dev/e1000/e1000_82575.c =================================================================== --- sys/dev/e1000/e1000_82575.c +++ sys/dev/e1000/e1000_82575.c @@ -1058,7 +1058,7 @@ s32 i = 0, timeout = 200; DEBUGFUNC("e1000_acquire_swfw_sync_82575"); - + ASSERT_NO_LOCKS(); while (i < timeout) { if (e1000_get_hw_semaphore_generic(hw)) { ret_val = -E1000_ERR_SWFW_SYNC; Index: sys/dev/e1000/e1000_i210.c =================================================================== --- sys/dev/e1000/e1000_i210.c +++ sys/dev/e1000/e1000_i210.c @@ -91,9 +91,11 @@ u32 swmask = mask; u32 fwmask = mask << 16; s32 ret_val = E1000_SUCCESS; + /* Uhh the following line should read 'FIXME: this is a blazing tire fire' */ s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ DEBUGFUNC("e1000_acquire_swfw_sync_i210"); + ASSERT_NO_LOCKS(); while (i < timeout) { if (e1000_get_hw_semaphore_i210(hw)) { Index: sys/dev/e1000/e1000_osdep.h =================================================================== --- sys/dev/e1000/e1000_osdep.h +++ sys/dev/e1000/e1000_osdep.h @@ -216,5 +216,22 @@ bus_space_write_2(((struct e1000_osdep *)(hw)->back)->flash_bus_space_tag, \ ((struct e1000_osdep *)(hw)->back)->flash_bus_space_handle, reg, value) + +#if defined(INVARIANTS) +#include + +#define ASSERT_NO_LOCKS() \ + do { \ + int unknown_locks = curthread->td_locks - mtx_owned(&Giant); \ + if (unknown_locks > 0) { \ + WITNESS_WARN(WARN_GIANTOK|WARN_SLEEPOK|WARN_PANIC, NULL, "unexpected non-sleepable lock"); \ + } \ + MPASS(curthread->td_rw_rlocks == 0); \ + MPASS(curthread->td_lk_slocks == 0); \ + } while (0) +#else +#define ASSERT_NO_LOCKS() +#endif + #endif /* _FREEBSD_OS_H_ */ Index: sys/net/iflib.h =================================================================== --- sys/net/iflib.h +++ sys/net/iflib.h @@ -381,7 +381,7 @@ void iflib_dma_free_multi(iflib_dma_info_t *dmalist, int count); -struct mtx *iflib_ctx_lock_get(if_ctx_t); +struct sx *iflib_ctx_lock_get(if_ctx_t); struct mtx *iflib_qset_lock_get(if_ctx_t, uint16_t); void iflib_led_create(if_ctx_t ctx); Index: sys/net/iflib.c =================================================================== --- sys/net/iflib.c +++ sys/net/iflib.c @@ -51,7 +51,6 @@ #include #include - #include #include #include @@ -157,7 +156,7 @@ if_shared_ctx_t ifc_sctx; struct if_softc_ctx ifc_softc_ctx; - struct mtx ifc_mtx; + struct sx ifc_sx; uint16_t ifc_nhwtxqs; uint16_t ifc_nhwrxqs; @@ -527,12 +526,19 @@ #define CTX_ACTIVE(ctx) ((if_getdrvflags((ctx)->ifc_ifp) & IFF_DRV_RUNNING)) +/* #define CTX_LOCK_INIT(_sc, _name) mtx_init(&(_sc)->ifc_mtx, _name, "iflib ctx lock", MTX_DEF) #define CTX_LOCK(ctx) mtx_lock(&(ctx)->ifc_mtx) #define CTX_UNLOCK(ctx) mtx_unlock(&(ctx)->ifc_mtx) #define CTX_LOCK_DESTROY(ctx) mtx_destroy(&(ctx)->ifc_mtx) +*/ +#define CTX_LOCK_INIT(_sc, _name) sx_init(&(_sc)->ifc_sx, _name) + +#define CTX_LOCK(ctx) sx_xlock(&(ctx)->ifc_sx) +#define CTX_UNLOCK(ctx) sx_xunlock(&(ctx)->ifc_sx) +#define CTX_LOCK_DESTROY(ctx) sx_destroy(&(ctx)->ifc_sx) #define CALLOUT_LOCK(txq) mtx_lock(&txq->ift_mtx) #define CALLOUT_UNLOCK(txq) mtx_unlock(&txq->ift_mtx) @@ -689,7 +695,14 @@ static void iflib_debug_reset(void) {} #endif +typedef void async_gtask_fn_t(if_ctx_t ctx, void *arg); +struct async_task_arg { + async_gtask_fn_t *ata_fn; + if_ctx_t ata_ctx; + void *ata_arg; + struct grouptask *ata_gtask; +}; #define IFLIB_DEBUG 0 @@ -711,6 +724,12 @@ static void _iflib_pre_assert(if_softc_ctx_t scctx); static void iflib_stop(if_ctx_t ctx); static void iflib_if_init_locked(if_ctx_t ctx); +static int async_if_ioctl(if_ctx_t ctx, u_long command, caddr_t data); +static int iflib_config_async_gtask_dispatch(if_ctx_t ctx, async_gtask_fn_t *fn, char *name, void *arg); +static void iflib_admin_reset_deferred(if_ctx_t ctx); + + + #ifndef __NO_STRICT_ALIGNMENT static struct mbuf * iflib_fixup_rx(struct mbuf *m); #endif @@ -1093,13 +1112,12 @@ struct ifnet *ifp = na->ifp; if_ctx_t ctx = ifp->if_softc; - CTX_LOCK(ctx); + /* XXX - do we need synchronization here?*/ if (onoff) { IFDI_INTR_ENABLE(ctx); } else { IFDI_INTR_DISABLE(ctx); } - CTX_UNLOCK(ctx); } @@ -2090,6 +2108,25 @@ } } +/* CONFIG context only */ +static void +iflib_handle_hang(if_ctx_t ctx, void *arg) +{ + iflib_txq_t txq = arg; + + CTX_LOCK(ctx); + if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); + device_printf(ctx->ifc_dev, "TX(%d) desc avail = %d, pidx = %d\n", + txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx); + + IFDI_WATCHDOG_RESET(ctx); + ctx->ifc_watchdog_events++; + + ctx->ifc_flags |= IFC_DO_RESET; + iflib_admin_intr_deferred(ctx); + CTX_UNLOCK(ctx); +} + /* * MI independent logic * @@ -2126,17 +2163,7 @@ callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); return; hung: - CTX_LOCK(ctx); - if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); - device_printf(ctx->ifc_dev, "TX(%d) desc avail = %d, pidx = %d\n", - txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx); - - IFDI_WATCHDOG_RESET(ctx); - ctx->ifc_watchdog_events++; - - ctx->ifc_flags |= IFC_DO_RESET; - iflib_admin_intr_deferred(ctx); - CTX_UNLOCK(ctx); + iflib_config_async_gtask_dispatch(ctx, iflib_handle_hang, "hang handler", txq); } static void @@ -2202,6 +2229,7 @@ txq->ift_timer.c_cpu); } +/* CONFIG context only */ static int iflib_media_change(if_t ifp) { @@ -2215,17 +2243,19 @@ return (err); } +/* CONFIG context only */ static void iflib_media_status(if_t ifp, struct ifmediareq *ifmr) { if_ctx_t ctx = if_getsoftc(ifp); + iflib_admin_intr_deferred(ctx); CTX_LOCK(ctx); - IFDI_UPDATE_ADMIN_STATUS(ctx); IFDI_MEDIA_STATUS(ctx, ifmr); CTX_UNLOCK(ctx); } +/* CONFIG context only */ static void iflib_stop(if_ctx_t ctx) { @@ -2240,9 +2270,7 @@ if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); IFDI_INTR_DISABLE(ctx); - DELAY(1000); IFDI_STOP(ctx); - DELAY(1000); iflib_debug_reset(); /* Wait for current tx queue users to exit to disarm watchdog timer. */ @@ -2581,10 +2609,7 @@ return true; return (iflib_rxd_avail(ctx, rxq, *cidxp, 1)); err: - CTX_LOCK(ctx); - ctx->ifc_flags |= IFC_DO_RESET; - iflib_admin_intr_deferred(ctx); - CTX_UNLOCK(ctx); + iflib_admin_reset_deferred(ctx); return (false); } @@ -3547,19 +3572,16 @@ GROUPTASK_ENQUEUE(&rxq->ifr_task); } +/* CONFIG context only */ static void _task_fn_admin(void *context) { if_ctx_t ctx = context; if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; iflib_txq_t txq; - int i; + int i, running; - if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) { - if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE)) { - return; - } - } + running = !!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING); CTX_LOCK(ctx); for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) { @@ -3567,23 +3589,27 @@ callout_stop(&txq->ift_timer); CALLOUT_UNLOCK(txq); } - IFDI_UPDATE_ADMIN_STATUS(ctx); - for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) - callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); - IFDI_LINK_INTR_ENABLE(ctx); + if (running) { + for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) + callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, + txq, txq->ift_timer.c_cpu); + IFDI_LINK_INTR_ENABLE(ctx); + } if (ctx->ifc_flags & IFC_DO_RESET) { ctx->ifc_flags &= ~IFC_DO_RESET; iflib_if_init_locked(ctx); } CTX_UNLOCK(ctx); - if (LINK_ACTIVE(ctx) == 0) + IFDI_UPDATE_ADMIN_STATUS(ctx); + if (LINK_ACTIVE(ctx) == 0 || !running) return; for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) iflib_txq_check_drain(txq, IFLIB_RESTART_BUDGET); } +/* CONFIG context only */ static void _task_fn_iov(void *context) { @@ -3713,6 +3739,7 @@ return (err); } +/* CONFIG context only */ static void iflib_if_qflush(if_t ifp) { @@ -3796,29 +3823,12 @@ CTX_UNLOCK(ctx); break; case SIOCSIFFLAGS: - CTX_LOCK(ctx); - if (if_getflags(ifp) & IFF_UP) { - if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { - if ((if_getflags(ifp) ^ ctx->ifc_if_flags) & - (IFF_PROMISC | IFF_ALLMULTI)) { - err = IFDI_PROMISC_SET(ctx, if_getflags(ifp)); - } - } else - reinit = 1; - } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { - iflib_stop(ctx); - } - ctx->ifc_if_flags = if_getflags(ifp); - CTX_UNLOCK(ctx); + err = async_if_ioctl(ctx, command, data); break; case SIOCADDMULTI: case SIOCDELMULTI: if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { - CTX_LOCK(ctx); - IFDI_INTR_DISABLE(ctx); - IFDI_MULTI_SET(ctx); - IFDI_INTR_ENABLE(ctx); - CTX_UNLOCK(ctx); + err = async_if_ioctl(ctx, command, data); } break; case SIOCSIFMEDIA: @@ -3912,6 +3922,7 @@ * **********************************************************************/ +/* CONFIG context only */ static void iflib_vlan_register(void *arg, if_t ifp, uint16_t vtag) { @@ -3931,6 +3942,7 @@ CTX_UNLOCK(ctx); } +/* CONFIG context only */ static void iflib_vlan_unregister(void *arg, if_t ifp, uint16_t vtag) { @@ -3950,6 +3962,7 @@ CTX_UNLOCK(ctx); } +/* CONFIG context only */ static void iflib_led_func(void *arg, int onoff) { @@ -4135,6 +4148,7 @@ if (!powerof2(scctx->isc_nrxd[i])) { /* round down instead? */ device_printf(dev, "# rx descriptors must be a power of 2\n"); + err = EINVAL; goto fail; } @@ -5112,6 +5126,22 @@ GROUPTASK_ENQUEUE(&ctx->ifc_admin_task); } +/* CONFIG context only */ +static void +iflib_handle_reset(if_ctx_t ctx, void *arg) +{ + CTX_LOCK(ctx); + ctx->ifc_flags |= IFC_DO_RESET; + iflib_admin_intr_deferred(ctx); + CTX_UNLOCK(ctx); +} + +static void +iflib_admin_reset_deferred(if_ctx_t ctx) +{ + iflib_config_async_gtask_dispatch(ctx, iflib_handle_reset, "reset handler", NULL); +} + void iflib_iov_intr_deferred(if_ctx_t ctx) { @@ -5135,11 +5165,101 @@ taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, -1, name); } +static void +iflib_multi_set(if_ctx_t ctx, void *arg) +{ + CTX_LOCK(ctx); + IFDI_INTR_DISABLE(ctx); + IFDI_MULTI_SET(ctx); + IFDI_INTR_ENABLE(ctx); + CTX_UNLOCK(ctx); +} + +static void +iflib_flags_set(if_ctx_t ctx, void *arg) +{ + int reinit, err; + if_t ifp = ctx->ifc_ifp; + + err = reinit = 0; + CTX_LOCK(ctx); + if (if_getflags(ifp) & IFF_UP) { + if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { + if ((if_getflags(ifp) ^ ctx->ifc_if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) { + err = IFDI_PROMISC_SET(ctx, if_getflags(ifp)); + } + } else + reinit = 1; + } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) { + iflib_stop(ctx); + } + ctx->ifc_if_flags = if_getflags(ifp); + if (reinit) + iflib_if_init_locked(ctx); + CTX_UNLOCK(ctx); + if (err) + log(LOG_WARNING, "IFDI_PROMISC_SET returned %d\n", err); +} + +static void +async_gtask(void *ctx) +{ + struct async_task_arg *at_arg = ctx; + if_ctx_t if_ctx = at_arg->ata_ctx; + void *arg = at_arg->ata_arg; + + at_arg->ata_fn(if_ctx, arg); + taskqgroup_detach(qgroup_if_config_tqg, at_arg->ata_gtask); + free(at_arg->ata_gtask, M_IFLIB); +} + +static int +iflib_config_async_gtask_dispatch(if_ctx_t ctx, async_gtask_fn_t *fn, char *name, void *arg) +{ + struct grouptask *gtask; + struct async_task_arg *at_arg; + + if ((gtask = malloc(sizeof(struct grouptask) + sizeof(struct async_task_arg), M_IFLIB, M_NOWAIT|M_ZERO)) == NULL) + return (ENOMEM); + + at_arg = (struct async_task_arg *)(gtask + 1); + at_arg->ata_fn = fn; + at_arg->ata_ctx = ctx; + at_arg->ata_arg = arg; + at_arg->ata_gtask = gtask; + + GROUPTASK_INIT(gtask, 0, async_gtask, at_arg); + taskqgroup_attach(qgroup_if_config_tqg, gtask, gtask, -1, name); + GROUPTASK_ENQUEUE(gtask); + return (0); +} + +static int +async_if_ioctl(if_ctx_t ctx, u_long command, caddr_t data) +{ + int rc; + + switch (command) { + case SIOCADDMULTI: + case SIOCDELMULTI: + rc = iflib_config_async_gtask_dispatch(ctx, iflib_multi_set, "async_if_multi", NULL); + break; + case SIOCSIFFLAGS: + rc = iflib_config_async_gtask_dispatch(ctx, iflib_flags_set, "async_if_flags", NULL); + break; + default: + panic("unknown command %lx", command); + } + return (rc); +} + + void iflib_config_gtask_deinit(struct grouptask *gtask) { - taskqgroup_detach(qgroup_if_config_tqg, gtask); + taskqgroup_detach(qgroup_if_config_tqg, gtask); } void @@ -5206,11 +5326,11 @@ info, 0, iflib_sysctl_int_delay, "I", description); } -struct mtx * +struct sx * iflib_ctx_lock_get(if_ctx_t ctx) { - return (&ctx->ifc_mtx); + return (&ctx->ifc_sx); } static int