Index: sys/net/iflib.c =================================================================== --- sys/net/iflib.c +++ sys/net/iflib.c @@ -163,7 +163,8 @@ if_shared_ctx_t ifc_sctx; struct if_softc_ctx ifc_softc_ctx; - struct mtx ifc_mtx; + struct sx ifc_ctx_sx; + struct mtx ifc_state_mtx; uint16_t ifc_nhwtxqs; uint16_t ifc_nhwrxqs; @@ -318,7 +319,9 @@ #define IFC_INIT_DONE 0x020 #define IFC_PREFETCH 0x040 #define IFC_DO_RESET 0x080 -#define IFC_CHECK_HUNG 0x100 +#define IFC_DO_WATCHDOG 0x100 +#define IFC_CHECK_HUNG 0x200 + #define CSUM_OFFLOAD (CSUM_IP_TSO|CSUM_IP6_TSO|CSUM_IP| \ CSUM_IP_UDP|CSUM_IP_TCP|CSUM_IP_SCTP| \ @@ -535,11 +538,17 @@ #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_INIT(_sc) sx_init(&(_sc)->ifc_ctx_sx, "iflib ctx lock") +#define CTX_LOCK(ctx) sx_xlock(&(ctx)->ifc_ctx_sx) +#define CTX_UNLOCK(ctx) sx_xunlock(&(ctx)->ifc_ctx_sx) +#define CTX_LOCK_DESTROY(ctx) sx_destroy(&(ctx)->ifc_ctx_sx) + + +#define STATE_LOCK_INIT(_sc, _name) mtx_init(&(_sc)->ifc_state_mtx, _name, "iflib state lock", MTX_DEF) +#define STATE_LOCK(ctx) mtx_lock(&(ctx)->ifc_state_mtx) +#define STATE_UNLOCK(ctx) mtx_unlock(&(ctx)->ifc_state_mtx) +#define STATE_LOCK_DESTROY(ctx) mtx_destroy(&(ctx)->ifc_state_mtx) -#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 CALLOUT_LOCK(txq) mtx_lock(&txq->ift_mtx) @@ -2144,18 +2153,14 @@ if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) 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); + hung: 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; + STATE_LOCK(ctx); + if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); + ctx->ifc_flags |= (IFC_DO_WATCHDOG|IFC_DO_RESET); iflib_admin_intr_deferred(ctx); - CTX_UNLOCK(ctx); + STATE_UNLOCK(ctx); } static void @@ -2673,10 +2678,10 @@ return true; return (iflib_rxd_avail(ctx, rxq, *cidxp, 1)); err: - CTX_LOCK(ctx); + STATE_LOCK(ctx); ctx->ifc_flags |= IFC_DO_RESET; iflib_admin_intr_deferred(ctx); - CTX_UNLOCK(ctx); + STATE_UNLOCK(ctx); return (false); } @@ -3719,12 +3724,21 @@ callout_stop(&txq->ift_timer); CALLOUT_UNLOCK(txq); } + if (ctx->ifc_flags & IFC_DO_WATCHDOG) { + ctx->ifc_watchdog_events++; + IFDI_WATCHDOG_RESET(ctx); + STATE_LOCK(ctx); + ctx->ifc_flags &= ~IFC_DO_RESET; + STATE_UNLOCK(ctx); + } 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 (ctx->ifc_flags & IFC_DO_RESET) { + STATE_LOCK(ctx); ctx->ifc_flags &= ~IFC_DO_RESET; + STATE_UNLOCK(ctx); iflib_if_init_locked(ctx); } CTX_UNLOCK(ctx); @@ -3870,15 +3884,15 @@ iflib_txq_t txq = ctx->ifc_txqs; int i; - CTX_LOCK(ctx); + STATE_LOCK(ctx); ctx->ifc_flags |= IFC_QFLUSH; - CTX_UNLOCK(ctx); + STATE_UNLOCK(ctx); for (i = 0; i < NTXQSETS(ctx); i++, txq++) while (!(ifmp_ring_is_idle(txq->ift_br) || ifmp_ring_is_stalled(txq->ift_br))) iflib_txq_check_drain(txq, 0); - CTX_LOCK(ctx); + STATE_LOCK(ctx); ctx->ifc_flags &= ~IFC_QFLUSH; - CTX_UNLOCK(ctx); + STATE_UNLOCK(ctx); if_qflush(ifp); } @@ -3935,14 +3949,18 @@ iflib_stop(ctx); if ((err = IFDI_MTU_SET(ctx, ifr->ifr_mtu)) == 0) { + STATE_LOCK(ctx); if (ifr->ifr_mtu > ctx->ifc_max_fl_buf_size) ctx->ifc_flags |= IFC_MULTISEG; else ctx->ifc_flags &= ~IFC_MULTISEG; + STATE_UNLOCK(ctx); err = if_setmtu(ifp, ifr->ifr_mtu); } iflib_init_locked(ctx); + STATE_LOCK(ctx); if_setdrvflags(ifp, bits); + STATE_UNLOCK(ctx); CTX_UNLOCK(ctx); break; case SIOCSIFFLAGS: @@ -4026,10 +4044,14 @@ bits = if_getdrvflags(ifp); if (bits & IFF_DRV_RUNNING) iflib_stop(ctx); + STATE_LOCK(ctx); if_togglecapenable(ifp, setmask); + STATE_UNLOCK(ctx); if (bits & IFF_DRV_RUNNING) iflib_init_locked(ctx); + STATE_LOCK(ctx); if_setdrvflags(ifp, bits); + STATE_UNLOCK(ctx); CTX_UNLOCK(ctx); } break; @@ -4247,7 +4269,9 @@ } } + CTX_LOCK(ctx); if ((err = IFDI_ATTACH_PRE(ctx)) != 0) { + CTX_UNLOCK(ctx); device_printf(dev, "IFDI_ATTACH_PRE failed %d\n", err); return (err); } @@ -4405,8 +4429,10 @@ if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter); iflib_add_device_sysctl_post(ctx); ctx->ifc_flags |= IFC_INIT_DONE; + CTX_UNLOCK(ctx); return (0); -fail_detach: + fail_detach: + ether_ifdetach(ctx->ifc_ifp); fail_intr_free: if (scctx->isc_intr == IFLIB_INTR_MSIX || scctx->isc_intr == IFLIB_INTR_MSI) @@ -4415,6 +4441,7 @@ /* XXX free queues */ fail: IFDI_DETACH(ctx); + CTX_UNLOCK(ctx); return (err); } @@ -4681,8 +4708,8 @@ _iflib_assert(sctx); - CTX_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev)); - + CTX_LOCK_INIT(ctx); + STATE_LOCK_INIT(ctx, device_get_nameunit(ctx->ifc_dev)); ifp = ctx->ifc_ifp = if_gethandle(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "can not allocate ifnet structure\n"); @@ -5409,8 +5436,8 @@ } void -iflib_config_gtask_init(if_ctx_t ctx, struct grouptask *gtask, gtask_fn_t *fn, - char *name) +iflib_config_gtask_init(void *ctx, struct grouptask *gtask, gtask_fn_t *fn, + const char *name) { GROUPTASK_INIT(gtask, 0, fn, ctx); @@ -5431,9 +5458,11 @@ iflib_txq_t txq = ctx->ifc_txqs; if_setbaudrate(ifp, baudrate); - if (baudrate >= IF_Gbps(10)) + if (baudrate >= IF_Gbps(10)) { + STATE_LOCK(ctx); ctx->ifc_flags |= IFC_PREFETCH; - + STATE_UNLOCK(ctx); + } /* If link down, disable watchdog */ if ((ctx->ifc_link_state == LINK_STATE_UP) && (link_state == LINK_STATE_DOWN)) { for (int i = 0; i < ctx->ifc_softc_ctx.isc_ntxqsets; i++, txq++) @@ -5488,11 +5517,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_ctx_sx); } static int