Index: if_ix.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_ix.c,v retrieving revision 1.166 diff -u -p -r1.166 if_ix.c --- if_ix.c 7 Jun 2020 23:52:05 -0000 1.166 +++ if_ix.c 15 Jun 2020 12:23:34 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ix.c,v 1.166 2020/06/07 23:52:05 dlg Exp $ */ +/* $OpenBSD: if_ix.c,v 1.165 2020/04/24 08:50:23 mpi Exp $ */ /****************************************************************************** @@ -115,7 +115,7 @@ void ixgbe_identify_hardware(struct ix_s int ixgbe_allocate_pci_resources(struct ix_softc *); int ixgbe_allocate_legacy(struct ix_softc *); int ixgbe_allocate_msix(struct ix_softc *); -int ixgbe_setup_msix(struct ix_softc *); +void ixgbe_setup_msix(struct ix_softc *); int ixgbe_allocate_queues(struct ix_softc *); void ixgbe_free_pci_resources(struct ix_softc *); void ixgbe_local_timer(void *); @@ -145,15 +145,11 @@ void ixgbe_rxrefill(void *); int ixgbe_intr(struct ix_softc *sc); void ixgbe_enable_intr(struct ix_softc *); void ixgbe_disable_intr(struct ix_softc *); -void ixgbe_update_stats_counters(struct ix_softc *); int ixgbe_txeof(struct tx_ring *); int ixgbe_rxeof(struct rx_ring *); void ixgbe_rx_checksum(uint32_t, struct mbuf *, uint32_t); void ixgbe_iff(struct ix_softc *); -#ifdef IX_DEBUG -void ixgbe_print_hw_stats(struct ix_softc *); void ixgbe_map_queue_statistics(struct ix_softc *); -#endif void ixgbe_update_link_status(struct ix_softc *); int ixgbe_get_buf(struct rx_ring *, int); int ixgbe_encap(struct tx_ring *, struct mbuf *); @@ -186,6 +182,13 @@ void ixgbe_rearm_queue(struct ix_softc * int ixgbe_link_intr(void *); int ixgbe_queue_intr(void *); +#if NKSTAT > 0 +static void ix_kstats(struct ix_softc *); +static void ix_rxq_kstats(struct ix_softc *, struct rx_ring *); +static void ix_txq_kstats(struct ix_softc *, struct tx_ring *); +static void ix_kstats_tick(void *); +#endif + /********************************************************************* * OpenBSD Device Interface Entry Points *********************************************************************/ @@ -199,7 +202,7 @@ struct cfattach ix_ca = { }; int ixgbe_smart_speed = ixgbe_smart_speed_on; -int ixgbe_enable_msix = 0; +int ixgbe_enable_msix = 1; /********************************************************************* * Device identification routine @@ -246,8 +249,9 @@ ixgbe_attach(struct device *parent, stru rw_init(&sc->sfflock, "ixsff"); - /* Set up the timer callout */ - timeout_set(&sc->timer, ixgbe_local_timer, sc); +#if NKSTAT > 0 + ix_kstats(sc); +#endif /* Determine hardware revision */ ixgbe_identify_hardware(sc); @@ -301,7 +305,7 @@ ixgbe_attach(struct device *parent, stru bcopy(sc->hw.mac.addr, sc->arpcom.ac_enaddr, IXGBE_ETH_LENGTH_OF_ADDRESS); - if (sc->msix > 1) + if (sc->sc_intrmap) error = ixgbe_allocate_msix(sc); else error = ixgbe_allocate_legacy(sc); @@ -319,9 +323,6 @@ ixgbe_attach(struct device *parent, stru /* Setup OS specific network interface */ ixgbe_setup_interface(sc); - /* Initialize statistics */ - ixgbe_update_stats_counters(sc); - /* Get the PCI-E bus info and determine LAN ID */ hw->mac.ops.get_bus_info(hw); @@ -376,7 +377,6 @@ ixgbe_detach(struct device *self, int fl ether_ifdetach(ifp); if_detach(ifp); - timeout_del(&sc->timer); ixgbe_free_pci_resources(sc); ixgbe_free_transmit_structures(sc); @@ -384,6 +384,8 @@ ixgbe_detach(struct device *self, int fl free(sc->mta, M_DEVBUF, IXGBE_ETH_LENGTH_OF_ADDRESS * MAX_NUM_MULTICAST_ADDRESSES); + /* XXX kstat */ + return (0); } @@ -666,7 +668,10 @@ ixgbe_watchdog(struct ifnet * ifp) i, txr->next_to_clean); } ifp->if_flags &= ~IFF_RUNNING; - sc->watchdog_events++; + +#if NKSTAT > 0 + //sc->watchdog_events++; +#endif ixgbe_init(sc); } @@ -795,10 +800,8 @@ ixgbe_init(void *arg) rxctrl |= IXGBE_RXCTRL_RXEN; sc->hw.mac.ops.enable_rx_dma(&sc->hw, rxctrl); - timeout_add_sec(&sc->timer, 1); - /* Set up MSI/X routing */ - if (sc->msix > 1) { + if (sc->sc_intrmap) { ixgbe_configure_ivars(sc); /* Set up auto-mask */ if (sc->hw.mac.type == ixgbe_mac_82598EB) @@ -829,7 +832,7 @@ ixgbe_init(void *arg) itr |= IXGBE_EITR_LLI_MOD | IXGBE_EITR_CNT_WDIS; IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(0), itr); - if (sc->msix > 1) { + if (sc->sc_intrmap) { /* Set moderation on the Link interrupt */ IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(sc->linkvec), IXGBE_LINK_ITR); @@ -857,6 +860,10 @@ ixgbe_init(void *arg) for (i = 0; i < sc->num_queues; i++) ifq_clr_oactive(ifp->if_ifqs[i]); +#if NKSTAT > 0 + ix_kstats_tick(sc); +#endif + splx(s); } @@ -903,7 +910,7 @@ ixgbe_config_gpie(struct ix_softc *sc) gpie |= 0xf << IXGBE_GPIE_LLI_DELAY_SHIFT; } - if (sc->msix > 1) { + if (sc->sc_intrmap) { /* Enable Enhanced MSIX mode */ gpie |= IXGBE_GPIE_MSIX_MODE; gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | @@ -1402,7 +1409,9 @@ ixgbe_encap(struct tx_ring *txr, struct break; /* FALLTHROUGH */ default: - sc->no_tx_dma_setup++; +#if NKSTAT > 0 + //sc->no_tx_dma_setup++; +#endif return (0); } @@ -1445,7 +1454,9 @@ ixgbe_encap(struct tx_ring *txr, struct txr->next_avail_desc = i; - ++txr->tx_packets; +#if NKSTAT > 0 + //++txr->tx_packets; +#endif return (ntxc + j); xmit_fail: @@ -1518,30 +1529,6 @@ ixgbe_mc_array_itr(struct ixgbe_hw *hw, } void -ixgbe_local_timer(void *arg) -{ - struct ix_softc *sc = arg; -#ifdef IX_DEBUG - struct ifnet *ifp = &sc->arpcom.ac_if; -#endif - int s; - - s = splnet(); - - ixgbe_update_stats_counters(sc); - -#ifdef IX_DEBUG - if ((ifp->if_flags & (IFF_RUNNING|IFF_DEBUG)) == - (IFF_RUNNING|IFF_DEBUG)) - ixgbe_print_hw_stats(sc); -#endif - - timeout_add_sec(&sc->timer, 1); - - splx(s); -} - -void ixgbe_update_link_status(struct ix_softc *sc) { struct ifnet *ifp = &sc->arpcom.ac_if; @@ -1595,6 +1582,10 @@ ixgbe_stop(void *arg) /* Tell the stack that the interface is no longer active */ ifp->if_flags &= ~IFF_RUNNING; +#if NKSTAT > 0 + timeout_del(&sc->sc_kstat_tmo); +#endif + INIT_DEBUGOUT("ixgbe_stop: begin\n"); ixgbe_disable_intr(sc); @@ -1606,7 +1597,6 @@ ixgbe_stop(void *arg) /* Turn off the laser */ if (sc->hw.mac.ops.disable_tx_laser) sc->hw.mac.ops.disable_tx_laser(&sc->hw); - timeout_del(&sc->timer); /* reprogram the RAR[0] in case user changed it. */ ixgbe_set_rar(&sc->hw, 0, sc->hw.mac.addr, 0, IXGBE_RAH_AV); @@ -1717,80 +1707,86 @@ ixgbe_allocate_msix(struct ix_softc *sc) { struct ixgbe_osdep *os = &sc->osdep; struct pci_attach_args *pa = &os->os_pa; - int vec, error = 0; - struct ix_queue *que = sc->queues; - const char *intrstr = NULL; - pci_chipset_tag_t pc = pa->pa_pc; + int i = 0, error = 0; + struct ix_queue *que; pci_intr_handle_t ih; - vec = 0; - if (pci_intr_map_msix(pa, vec, &ih)) { - printf(": couldn't map interrupt\n"); - return (ENXIO); - } + for (i = 0, que = sc->queues; i < sc->num_queues; i++, que++) { + if (pci_intr_map_msix(pa, i, &ih)) { + printf("ixgbe_allocate_msix: " + "pci_intr_map_msix vec %d failed\n", i); + error = ENOMEM; + goto fail; + } - que->msix = vec; - snprintf(que->name, sizeof(que->name), "%s:%d", sc->dev.dv_xname, vec); + que->tag = pci_intr_establish_cpuid(pa->pa_pc, ih, + IPL_NET | IPL_MPSAFE, ixgbe_queue_intr, que, que->name, + intrmap_cpu(sc->sc_intrmap, i)); + if (que->tag == NULL) { + printf("ixgbe_allocate_msix: " + "pci_intr_establish vec %d failed\n", i); + error = ENOMEM; + goto fail; + } - intrstr = pci_intr_string(pc, ih); - que->tag = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE, - ixgbe_queue_intr, que, que->name); - if (que->tag == NULL) { - printf(": couldn't establish interrupt"); - if (intrstr != NULL) - printf(" at %s", intrstr); - printf("\n"); - return (ENXIO); + que->msix = i; } /* Now the link status/control last MSI-X vector */ - vec++; - if (pci_intr_map_msix(pa, vec, &ih)) { - printf(": couldn't map link vector\n"); - error = ENXIO; + if (pci_intr_map_msix(pa, i, &ih)) { + printf("ixgbe_allocate_msix: " + "pci_intr_map_msix link vector failed\n"); + error = ENOMEM; goto fail; } - intrstr = pci_intr_string(pc, ih); - sc->tag = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE, + sc->tag = pci_intr_establish(pa->pa_pc, ih, IPL_NET | IPL_MPSAFE, ixgbe_link_intr, sc, sc->dev.dv_xname); if (sc->tag == NULL) { - printf(": couldn't establish interrupt"); - if (intrstr != NULL) - printf(" at %s", intrstr); - printf("\n"); - error = ENXIO; + printf("ixgbe_allocate_msix: " + "pci_intr_establish link vector failed\n"); + error = ENOMEM; goto fail; } - - sc->linkvec = vec; - printf(", %s, %d queue%s", intrstr, vec, (vec > 1) ? "s" : ""); + sc->linkvec = i; + printf(", %s, %d queue%s", pci_intr_string(pa->pa_pc, ih), + i, (i > 1) ? "s" : ""); return (0); fail: - pci_intr_disestablish(pc, que->tag); - que->tag = NULL; + for (que = sc->queues; i > 0; i--, que++) { + if (que->tag == NULL) + continue; + pci_intr_disestablish(pa->pa_pc, que->tag); + que->tag = NULL; + } + return (error); } -int +void ixgbe_setup_msix(struct ix_softc *sc) { struct ixgbe_osdep *os = &sc->osdep; struct pci_attach_args *pa = &os->os_pa; - pci_intr_handle_t dummy; + int nmsix; + unsigned int maxq; if (!ixgbe_enable_msix) - return (0); + return; - /* - * Try a dummy map, maybe this bus doesn't like MSI, this function - * has no side effects. - */ - if (pci_intr_map_msix(pa, 0, &dummy)) - return (0); + nmsix = pci_intr_msix_count(pa->pa_pc, pa->pa_tag); + if (nmsix <= 1) + return; - return (2); /* queue vector + link vector */ + /* give one vector to events */ + nmsix--; + + /* XXX the number of queues is limited to what we can keep stats on */ + maxq = (sc->hw.mac.type == ixgbe_mac_82598EB) ? 8 : 16; + + sc->sc_intrmap = intrmap_create(&sc->dev, nmsix, maxq, 0); + sc->num_queues = intrmap_count(sc->sc_intrmap); } int @@ -1818,7 +1814,7 @@ ixgbe_allocate_pci_resources(struct ix_s sc->hw.back = os; /* Now setup MSI or MSI/X, return us the number of supported vectors. */ - sc->msix = ixgbe_setup_msix(sc); + ixgbe_setup_msix(sc); return (0); } @@ -1902,6 +1898,11 @@ ixgbe_setup_interface(struct ix_softc *s ifiq->ifiq_softc = rxr; rxr->ifiq = ifiq; + +#if NKSTAT > 0 + ix_txq_kstats(sc, txr); + ix_rxq_kstats(sc, rxr); +#endif } sc->max_frame_size = IXGBE_MAX_FRAME_SIZE; @@ -2159,6 +2160,8 @@ ixgbe_allocate_queues(struct ix_softc *s que->sc = sc; que->txr = &sc->tx_rings[i]; que->rxr = &sc->rx_rings[i]; + snprintf(que->name, sizeof(que->name), "%s:%d", + sc->dev.dv_xname, i); } return (0); @@ -2905,10 +2908,8 @@ ixgbe_initialize_receive_units(struct ix rxcsum |= IXGBE_RXCSUM_PCSD; } -#ifdef IX_DEBUG /* Map QPRC/QPRDC/QPTC on a per queue basis */ ixgbe_map_queue_statistics(sc); -#endif /* This is useful for calculating UDP/IP fragment checksums */ if (!(rxcsum & IXGBE_RXCSUM_PCSD)) @@ -3091,7 +3092,9 @@ ixgbe_rxeof(struct rx_ring *rxr) eop = ((staterr & IXGBE_RXD_STAT_EOP) != 0); if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) { - sc->dropped_pkts++; +#if NKSTAT > 0 + //sc->dropped_pkts++; +#endif if (rxbuf->fmp) { m_freem(rxbuf->fmp); @@ -3156,10 +3159,12 @@ ixgbe_rxeof(struct rx_ring *rxr) sendmp = NULL; mp->m_next = nxbuf->buf; } else { /* Sending this frame? */ - rxr->rx_packets++; +#if NKSTAT > 0 + //rxr->rx_packets++; /* capture data for AIM */ - rxr->bytes += sendmp->m_pkthdr.len; - rxr->rx_bytes += sendmp->m_pkthdr.len; + //rxr->bytes += sendmp->m_pkthdr.len; + //rxr->rx_bytes += sendmp->m_pkthdr.len; +#endif ixgbe_rx_checksum(staterr, sendmp, ptype); @@ -3295,7 +3300,7 @@ ixgbe_enable_intr(struct ix_softc *sc) IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); /* With MSI-X we use auto clear */ - if (sc->msix > 1) { + if (sc->sc_intrmap) { mask = IXGBE_EIMS_ENABLE_MASK; /* Don't autoclear Link */ mask &= ~IXGBE_EIMS_OTHER; @@ -3309,7 +3314,7 @@ ixgbe_enable_intr(struct ix_softc *sc) void ixgbe_disable_intr(struct ix_softc *sc) { - if (sc->msix > 1) + if (sc->sc_intrmap) IXGBE_WRITE_REG(&sc->hw, IXGBE_EIAC, 0); if (sc->hw.mac.type == ixgbe_mac_82598EB) { IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, ~0); @@ -3507,164 +3512,378 @@ ixgbe_handle_phy(struct ix_softc *sc) } +#if NKSTAT > 0 +struct ix_kstats { + struct kstat_kv crcerrs; + + struct kstat_kv lxontxc; + struct kstat_kv lxonrxc; + struct kstat_kv lxofftxc; + struct kstat_kv lxoffrxc; + + struct kstat_kv prc64; + struct kstat_kv prc127; + struct kstat_kv prc255; + struct kstat_kv prc511; + struct kstat_kv prc1023; + struct kstat_kv prc1522; + + struct kstat_kv gptc; + struct kstat_kv gorc; + struct kstat_kv gotc; + struct kstat_kv ruc; + struct kstat_kv rfc; + struct kstat_kv roc; + struct kstat_kv rjc; + + struct kstat_kv tor; + struct kstat_kv tpr; + struct kstat_kv tpt; + + struct kstat_kv gprc; + struct kstat_kv bprc; + struct kstat_kv mprc; + + struct kstat_kv ptc64; + struct kstat_kv ptc127; + struct kstat_kv ptc255; + struct kstat_kv ptc511; + struct kstat_kv ptc1023; + struct kstat_kv ptc1522; + + struct kstat_kv mptc; + struct kstat_kv bptc; +}; + +struct ix_rxq_kstats { + struct kstat_kv qprc; + struct kstat_kv qbrc; + struct kstat_kv qprdc; +}; + +struct ix_txq_kstats { + struct kstat_kv qptc; + struct kstat_kv qbtc; +}; + +static int ix_kstats_read(struct kstat *ks); +static int ix_rxq_kstats_read(struct kstat *ks); +static int ix_txq_kstats_read(struct kstat *ks); + +static void +ix_kstats(struct ix_softc *sc) +{ + struct ix_kstats *stats; + struct kstat *ks; + + mtx_init(&sc->sc_kstat_mtx, IPL_SOFTCLOCK); + timeout_set(&sc->sc_kstat_tmo, ix_kstats_tick, sc); + + ks = kstat_create(sc->dev.dv_xname, 0, "ix", 0, + KSTAT_T_KV, 0); + if (ks == NULL) + return; + + stats = malloc(sizeof(*stats), M_DEVBUF, M_WAITOK|M_ZERO); + + kstat_kv_unit_init(&stats->crcerrs, "Rx CRC Errs", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_kv_unit_init(&stats->lxontxc, "Link XON Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->lxonrxc, "Link XON Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->lxofftxc, "Link XOFF Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->lxoffrxc, "Link XOFF Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_kv_unit_init(&stats->prc64, "64B Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->prc127, "65-127B Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->prc255, "128-255B Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->prc511, "256-511B Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->prc1023, "512-1023B Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->prc1522, "1024-MaxB Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_kv_unit_init(&stats->gptc, "Good Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->gorc, "Good Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES); + kstat_kv_unit_init(&stats->gotc, "Good Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES); + + kstat_kv_unit_init(&stats->ruc, "Rx Undersize", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->rfc, "Rx Fragment", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->roc, "Rx Oversize", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->rjc, "Rx Jabber", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_kv_unit_init(&stats->tor, "Total Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES); + kstat_kv_unit_init(&stats->tpr, "Total Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->tpt, "Total Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_kv_unit_init(&stats->gprc, "Good Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->bprc, "Broadcast Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->mprc, "Multicast Rx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_kv_unit_init(&stats->ptc64, "64B Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->ptc127, "65-127B Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->ptc255, "128-255B Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->ptc511, "256-511B Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->ptc1023, "512-1023B Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->ptc1522, "1024-MaxB Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_kv_unit_init(&stats->mptc, "Multicast Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->bptc, "Broadcast Tx", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_set_mutex(ks, &sc->sc_kstat_mtx); + ks->ks_softc = sc; + ks->ks_data = stats; + ks->ks_datalen = sizeof(*stats); + ks->ks_read = ix_kstats_read; + + sc->sc_kstat = ks; + kstat_install(ks); +} + +static void +ix_rxq_kstats(struct ix_softc *sc, struct rx_ring *rxr) +{ + struct ix_rxq_kstats *stats; + struct kstat *ks; + + ks = kstat_create(sc->dev.dv_xname, 0, "ix-rxq", rxr->me, + KSTAT_T_KV, 0); + if (ks == NULL) + return; + + stats = malloc(sizeof(*stats), M_DEVBUF, M_WAITOK|M_ZERO); + + kstat_kv_unit_init(&stats->qprc, "packets", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->qbrc, "bytes", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES); + kstat_kv_unit_init(&stats->qprdc, "qdrops", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + + kstat_set_mutex(ks, &sc->sc_kstat_mtx); + ks->ks_softc = rxr; + ks->ks_data = stats; + ks->ks_datalen = sizeof(*stats); + ks->ks_read = ix_rxq_kstats_read; + + rxr->kstat = ks; + kstat_install(ks); +} + +static void +ix_txq_kstats(struct ix_softc *sc, struct tx_ring *txr) +{ + struct ix_txq_kstats *stats; + struct kstat *ks; + + ks = kstat_create(sc->dev.dv_xname, 0, "ix-txq", txr->me, + KSTAT_T_KV, 0); + if (ks == NULL) + return; + + stats = malloc(sizeof(*stats), M_DEVBUF, M_WAITOK|M_ZERO); + + kstat_kv_unit_init(&stats->qptc, "packets", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS); + kstat_kv_unit_init(&stats->qbtc, "bytes", + KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES); + + kstat_set_mutex(ks, &sc->sc_kstat_mtx); + ks->ks_softc = txr; + ks->ks_data = stats; + ks->ks_datalen = sizeof(*stats); + ks->ks_read = ix_txq_kstats_read; + + txr->kstat = ks; + kstat_install(ks); +} + /********************************************************************** * * Update the board statistics counters. * **********************************************************************/ -void -ixgbe_update_stats_counters(struct ix_softc *sc) + +static void +ix_kstats_tick(void *arg) { - struct ifnet *ifp = &sc->arpcom.ac_if; + struct ix_softc *sc = arg; + int i; + + timeout_add_sec(&sc->sc_kstat_tmo, 1); + + mtx_enter(&sc->sc_kstat_mtx); + ix_kstats_read(sc->sc_kstat); + for (i = 0; i < sc->num_queues; i++) { + ix_rxq_kstats_read(sc->rx_rings[i].kstat); + ix_txq_kstats_read(sc->tx_rings[i].kstat); + } + mtx_leave(&sc->sc_kstat_mtx); +} + +static uint64_t +ix_read36(struct ixgbe_hw *hw, bus_size_t loreg, bus_size_t hireg) +{ + uint64_t lo, hi; + + lo = IXGBE_READ_REG(hw, loreg); + hi = IXGBE_READ_REG(hw, hireg); + + return (((hi & 0xf) << 32) | lo); +} + +static int +ix_kstats_read(struct kstat *ks) +{ + struct ix_kstats *stats = ks->ks_data; + struct ix_softc *sc = ks->ks_softc; struct ixgbe_hw *hw = &sc->hw; - uint64_t crcerrs, rlec, total_missed_rx = 0; -#ifdef IX_DEBUG - uint32_t missed_rx = 0, bprc, lxon, lxoff, total; - int i; -#endif - crcerrs = IXGBE_READ_REG(hw, IXGBE_CRCERRS); - sc->stats.crcerrs += crcerrs; - rlec = IXGBE_READ_REG(hw, IXGBE_RLEC); - sc->stats.rlec += rlec; - -#ifdef IX_DEBUG - for (i = 0; i < 8; i++) { - uint32_t mp; - mp = IXGBE_READ_REG(hw, IXGBE_MPC(i)); - /* missed_rx tallies misses for the gprc workaround */ - missed_rx += mp; - /* global total per queue */ - sc->stats.mpc[i] += mp; - /* running comprehensive total for stats display */ - total_missed_rx += sc->stats.mpc[i]; - if (hw->mac.type == ixgbe_mac_82598EB) - sc->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); - } - - /* Hardware workaround, gprc counts missed packets */ - sc->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); - sc->stats.gprc -= missed_rx; + stats->crcerrs.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_CRCERRS); - if (hw->mac.type != ixgbe_mac_82598EB) { - sc->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + - ((uint64_t)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); - sc->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + - ((uint64_t)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); - sc->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + - ((uint64_t)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); - sc->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); - sc->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); + stats->lxontxc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_LXONTXC); + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + stats->lxonrxc.kv_v.v_u64 += + IXGBE_READ_REG(hw, IXGBE_LXONRXC); + } else { + stats->lxonrxc.kv_v.v_u64 += + IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); + } + stats->lxofftxc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + stats->lxoffrxc.kv_v.v_u64 += + IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); } else { - sc->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); - sc->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); - /* 82598 only has a counter in the high register */ - sc->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); - sc->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); - sc->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH); + stats->lxoffrxc.kv_v.v_u64 += + IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); } - /* - * Workaround: mprc hardware is incorrectly counting - * broadcasts, so for now we subtract those. - */ - bprc = IXGBE_READ_REG(hw, IXGBE_BPRC); - sc->stats.bprc += bprc; - sc->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); - if (hw->mac.type == ixgbe_mac_82598EB) - sc->stats.mprc -= bprc; - - sc->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC); - sc->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); - sc->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); - sc->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); - sc->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); - sc->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); - sc->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); - - lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); - sc->stats.lxontxc += lxon; - lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); - sc->stats.lxofftxc += lxoff; - total = lxon + lxoff; - - sc->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); - sc->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); - sc->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); - sc->stats.gptc -= total; - sc->stats.mptc -= total; - sc->stats.ptc64 -= total; - sc->stats.gotc -= total * ETHER_MIN_LEN; - - sc->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); - sc->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); - sc->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); - sc->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); - sc->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); - sc->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); - sc->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); - sc->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); - sc->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); - sc->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); - for (i = 0; i < 16; i++) { - uint32_t dropped; - - dropped = IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); - sc->stats.qprdc[i] += dropped; - missed_rx += dropped; - sc->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); - sc->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + stats->prc64.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PRC64); + stats->prc127.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PRC127); + stats->prc255.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PRC255); + stats->prc511.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PRC511); + stats->prc1023.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PRC1023); + stats->prc1522.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PRC1522); + + stats->gptc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_GPTC); + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + stats->gorc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_GORCH); + stats->gotc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_GOTCH); + } else { + stats->gorc.kv_v.v_u64 += + ix_read36(hw, IXGBE_GORCL, IXGBE_GORCH); + stats->gotc.kv_v.v_u64 += + ix_read36(hw, IXGBE_GOTCL, IXGBE_GOTCH); } -#endif - /* Fill out the OS statistics structure */ - ifp->if_collisions = 0; - ifp->if_oerrors = sc->watchdog_events; - ifp->if_ierrors = total_missed_rx + crcerrs + rlec; + stats->ruc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_RUC); + stats->rfc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_RFC); + stats->roc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_ROC); + stats->rjc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_RJC); + + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + stats->tor.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_TORH); + } else { + stats->tor.kv_v.v_u64 += + ix_read36(hw, IXGBE_TORL, IXGBE_TORH); + } + stats->tpr.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_TPR); + stats->tpt.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_TPT); + + stats->gprc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_GPRC); + stats->bprc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_BPRC); + stats->mprc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_MPRC); + + stats->ptc64.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PTC64); + stats->ptc127.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PTC127); + stats->ptc255.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PTC255); + stats->ptc511.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PTC511); + stats->ptc1023.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PTC1023); + stats->ptc1522.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_PTC1522); + + stats->mptc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_MPTC); + stats->bptc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_BPTC); + + getnanouptime(&ks->ks_updated); + + return (0); } -#ifdef IX_DEBUG -/********************************************************************** - * - * This routine is called only when ixgbe_display_debug_stats is enabled. - * This routine provides a way to take a look at important statistics - * maintained by the driver and hardware. - * - **********************************************************************/ -void -ixgbe_print_hw_stats(struct ix_softc * sc) +int +ix_rxq_kstats_read(struct kstat *ks) { - struct ifnet *ifp = &sc->arpcom.ac_if; - int i; + struct ix_rxq_kstats *stats = ks->ks_data; + struct rx_ring *rxr = ks->ks_softc; + struct ix_softc *sc = rxr->sc; + struct ixgbe_hw *hw = &sc->hw; + uint32_t i = rxr->me; - printf("%s: missed pkts %llu, rx len errs %llu, crc errs %llu, " - "dropped pkts %lu, watchdog timeouts %ld, " - "XON rx %llu, XON tx %llu, XOFF rx %llu, XOFF tx %llu, " - "total pkts rx %llu, good pkts rx %llu, good pkts tx %llu, " - "tso tx %lu\n", - ifp->if_xname, - (long long)sc->stats.mpc[0], - (long long)sc->stats.roc + (long long)sc->stats.ruc, - (long long)sc->stats.crcerrs, - sc->dropped_pkts, - sc->watchdog_events, - (long long)sc->stats.lxonrxc, - (long long)sc->stats.lxontxc, - (long long)sc->stats.lxoffrxc, - (long long)sc->stats.lxofftxc, - (long long)sc->stats.tpr, - (long long)sc->stats.gprc, - (long long)sc->stats.gptc, - sc->tso_tx); + stats->qprc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + stats->qprdc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + stats->qbrc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_QBRC(i)); + } else { + stats->qprdc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); + stats->qbrc.kv_v.v_u64 += + ix_read36(hw, IXGBE_QBRC_L(i), IXGBE_QBRC_H(i)); + } - printf("%s: per queue statistics\n", ifp->if_xname); - for (i = 0; i < sc->num_queues; i++) { - printf("\tqueue %d: rx pkts %llu, rx drops %llu, " - "tx pkts %llu\n", - i, sc->stats.qprc[i], sc->stats.qprdc[i], - sc->stats.qptc[i]); + getnanouptime(&ks->ks_updated); + + return (0); +} + +int +ix_txq_kstats_read(struct kstat *ks) +{ + struct ix_txq_kstats *stats = ks->ks_data; + struct rx_ring *txr = ks->ks_softc; + struct ix_softc *sc = txr->sc; + struct ixgbe_hw *hw = &sc->hw; + uint32_t i = txr->me; + + stats->qptc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + stats->qbtc.kv_v.v_u64 += IXGBE_READ_REG(hw, IXGBE_QBTC(i)); + } else { + stats->qbtc.kv_v.v_u64 += + ix_read36(hw, IXGBE_QBTC_L(i), IXGBE_QBTC_H(i)); } + + getnanouptime(&ks->ks_updated); + + return (0); } +#endif /* NKVSTAT > 0 */ void ixgbe_map_queue_statistics(struct ix_softc *sc) @@ -3692,4 +3911,3 @@ ixgbe_map_queue_statistics(struct ix_sof IXGBE_WRITE_REG(&sc->hw, IXGBE_TQSM(i), r); } } -#endif Index: if_ix.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_ix.h,v retrieving revision 1.41 diff -u -p -r1.41 if_ix.h --- if_ix.h 7 Jun 2020 23:52:05 -0000 1.41 +++ if_ix.h 15 Jun 2020 12:23:34 -0000 @@ -156,7 +156,6 @@ struct ix_queue { uint32_t eims; /* This queue's EIMS bit */ uint32_t eitr_setting; char name[8]; - pci_intr_handle_t ih; void *tag; struct tx_ring *txr; struct rx_ring *rxr; @@ -182,10 +181,8 @@ struct tx_ring { } queue_status; uint32_t txd_cmd; bus_dma_tag_t txtag; - uint32_t bytes; /* Used for AIM calc */ - uint32_t packets; - /* Soft Stats */ - uint64_t tx_packets; + + struct kstat *kstat; }; @@ -211,15 +208,7 @@ struct rx_ring { struct if_rxring rx_ring; struct ixgbe_rx_buf *rx_buffers; - uint32_t bytes; /* Used for AIM calc */ - uint32_t packets; - - /* Soft stats */ - uint64_t rx_irq; - uint64_t rx_packets; - uint64_t rx_bytes; - uint64_t rx_discarded; - uint64_t rsc_num; + struct kstat *kstat; }; /* Our adapter structure */ @@ -233,12 +222,11 @@ struct ix_softc { void *tag; struct ifmedia media; - struct timeout timer; - int msix; int if_flags; uint16_t num_vlans; uint16_t num_queues; + struct intrmap *sc_intrmap; /* msix */ /* * Shadow VFTA table, this is needed because @@ -288,14 +276,9 @@ struct ix_softc { uint8_t *mta; /* Misc stats maintained by the driver */ - unsigned long dropped_pkts; - unsigned long no_tx_map_avail; - unsigned long no_tx_dma_setup; - unsigned long watchdog_events; - unsigned long tso_tx; - unsigned long link_irq; - - struct ixgbe_hw_stats stats; + struct mutex sc_kstat_mtx; + struct timeout sc_kstat_tmo; + struct kstat *sc_kstat; }; #endif /* _IX_H_ */ Index: ixgbe.h =================================================================== RCS file: /cvs/src/sys/dev/pci/ixgbe.h,v retrieving revision 1.29 diff -u -p -r1.29 ixgbe.h --- ixgbe.h 2 Mar 2020 01:59:01 -0000 1.29 +++ ixgbe.h 15 Jun 2020 12:23:34 -0000 @@ -41,6 +41,7 @@ #include "bpfilter.h" #include "vlan.h" +#include "kstat.h" #include #include @@ -54,6 +55,8 @@ #include #include #include +#include +#include #include #include