Index: adapter.h =================================================================== --- adapter.h (revision 225414) +++ adapter.h (working copy) @@ -533,7 +532,9 @@ char fw_version[32]; struct adapter_params params; struct t4_virt_res vres; + struct tp_err_stats err_stats; + struct callout tick; struct sysctl_ctx_list ctx; /* from first_port_up to last_port_down */ struct sysctl_oid *oid_fwq; struct sysctl_oid *oid_ctrlq; Index: t4_main.c =================================================================== --- t4_main.c (revision 225414) +++ t4_main.c (working copy) @@ -327,6 +318,7 @@ static void reg_block_dump(struct adapter *, uint8_t *, unsigned int, unsigned int); static void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); +static void t4_tick(void *); static void cxgbe_tick(void *); static int t4_sysctls(struct adapter *); static int cxgbe_sysctls(struct port_info *); @@ -427,6 +419,7 @@ device_get_nameunit(dev)); mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); sx_init(&sc->userq_lock, "userq"); + callout_init_mtx(&sc->tick, &sc->sc_lock, 0); rc = map_bars(sc); if (rc != 0) @@ -725,6 +718,8 @@ #endif t4_set_desc(sc); + callout_reset(&sc->tick, hz, t4_tick, sc); + done: if (rc != 0) t4_detach(dev); @@ -756,6 +751,7 @@ if (sc->cdev) destroy_dev(sc->cdev); + callout_drain(&sc->tick); bus_generic_detach(dev); for (i = 0; i < MAX_NPORTS; i++) { pi = sc->port[i]; @@ -838,7 +834,7 @@ pi->ifp = ifp; ifp->if_softc = pi; - callout_init(&pi->tick, CALLOUT_MPSAFE); + callout_init_mtx(&pi->tick, &pi->pi_lock, 0); pi->tq = taskqueue_create("cxgbe_taskq", M_NOWAIT, taskqueue_thread_enqueue, &pi->tq); if (pi->tq == NULL) { @@ -903,6 +899,7 @@ if (rc != 0) device_printf(dev, "port uninit failed: %d.\n", rc); + callout_drain(&pi->tick); taskqueue_free(pi->tq); ifmedia_removeall(&pi->media); @@ -2101,7 +2098,6 @@ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); callout_stop(&pi->tick); PORT_UNLOCK(pi); - callout_drain(&pi->tick); /* * Stop and then free the queues' resources, including the queues @@ -2520,6 +2516,18 @@ } static void +t4_tick(void *arg) +{ + struct adapter *sc = arg; + struct tp_err_stats *st = &sc->err_stats; + + ADAPTER_LOCK_ASSERT_OWNED(sc); + t4_tp_get_err_stats(sc, st); + + callout_schedule(&sc->tick, hz); +} + +static void cxgbe_tick(void *arg) { struct port_info *pi = arg; @@ -2528,11 +2536,8 @@ int i, drops; struct port_stats *s = &pi->stats; - PORT_LOCK(pi); - if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { - PORT_UNLOCK(pi); - return; /* without scheduling another callout */ - } + PORT_LOCK_ASSERT_OWNED(pi); + KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, ("interface down")); t4_get_port_stats(pi->adapter, pi->tx_chan, s); @@ -2555,7 +2560,6 @@ s->rx_fcs_err + s->rx_len_err; callout_schedule(&pi->tick, hz); - PORT_UNLOCK(pi); } static int @@ -2566,6 +2570,10 @@ struct sysctl_oid_list *children; ctx = device_get_sysctl_ctx(sc->dev); + + /* + * dev.t4nex.X. + */ oid = device_get_sysctl_tree(sc->dev); children = SYSCTL_CHILDREN(oid); @@ -2598,6 +2606,23 @@ sysctl_devlog, "A", "device log"); #endif + /* + * dev.t4nex.X.stats. + */ + oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, + NULL, "adapter statistics"); + children = SYSCTL_CHILDREN(oid); + + /* We get these from err_stats and they may be stale by up to 1s */ + SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cong_drops0", CTLFLAG_RD, + &sc->err_stats.tnlCongDrops[0], 0, "channel 0 congestion drops"); + SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cong_drops1", CTLFLAG_RD, + &sc->err_stats.tnlCongDrops[1], 0, "channel 1 congestion drops"); + SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cong_drops2", CTLFLAG_RD, + &sc->err_stats.tnlCongDrops[2], 0, "channel 2 congestion drops"); + SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cong_drops3", CTLFLAG_RD, + &sc->err_stats.tnlCongDrops[3], 0, "channel 3 congestion drops"); + return (0); } @@ -2775,7 +2800,7 @@ SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ &pi->stats.name, desc) - /* We get these from port_stats and they may be stale by upto 1s */ + /* We get these from port_stats and they may be stale by up to 1s */ SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, "# drops due to buffer-group 0 overflows"); SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1,