diff --git a/sys/dev/axgbe/if_axgbe_pci.c b/sys/dev/axgbe/if_axgbe_pci.c --- a/sys/dev/axgbe/if_axgbe_pci.c +++ b/sys/dev/axgbe/if_axgbe_pci.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ MALLOC_DEFINE(M_AXGBE, "axgbe", "axgbe data"); extern struct if_txrx axgbe_txrx; +static int axgbe_sph_enable; /* Function prototypes */ static void *axgbe_register(device_t); @@ -252,16 +254,11 @@ .isc_vendor_info = axgbe_vendor_info_array, .isc_driver_version = XGBE_DRV_VERSION, - .isc_nrxd_min = {XGBE_RX_DESC_CNT_MIN, XGBE_RX_DESC_CNT_MIN}, - .isc_nrxd_default = {XGBE_RX_DESC_CNT_DEFAULT, XGBE_RX_DESC_CNT_DEFAULT}, - .isc_nrxd_max = {XGBE_RX_DESC_CNT_MAX, XGBE_RX_DESC_CNT_MAX}, .isc_ntxd_min = {XGBE_TX_DESC_CNT_MIN}, .isc_ntxd_default = {XGBE_TX_DESC_CNT_DEFAULT}, .isc_ntxd_max = {XGBE_TX_DESC_CNT_MAX}, - .isc_nfl = 2, .isc_ntxqs = 1, - .isc_nrxqs = 2, .isc_flags = IFLIB_TSO_INIT_IP | IFLIB_NEED_SCRATCH | IFLIB_NEED_ZERO_CSUM | IFLIB_NEED_ETHER_PAD, }; @@ -269,6 +266,44 @@ static void * axgbe_register(device_t dev) { + int axgbe_nfl; + int axgbe_nrxqs; + int error, i; + char *value = NULL; + + value = kern_getenv("dev.ax.sph_enable"); + if (value) { + axgbe_sph_enable = strtol(value, NULL, 10); + freeenv(value); + } else { + /* + * No tunable found, generate one with default values + * Note: only a reboot will reveal the new kenv + */ + error = kern_setenv("dev.ax.sph_enable", "1"); + if (error) { + printf("Error setting tunable, using default driver values\n"); + } + axgbe_sph_enable = 1; + } + + if (!axgbe_sph_enable) { + axgbe_nfl = 1; + axgbe_nrxqs = 1; + } else { + axgbe_nfl = 2; + axgbe_nrxqs = 2; + } + + axgbe_sctx_init.isc_nfl = axgbe_nfl; + axgbe_sctx_init.isc_nrxqs = axgbe_nrxqs; + + for (i = 0 ; i < axgbe_nrxqs ; i++) { + axgbe_sctx_init.isc_nrxd_min[i] = XGBE_RX_DESC_CNT_MIN; + axgbe_sctx_init.isc_nrxd_default[i] = XGBE_RX_DESC_CNT_DEFAULT; + axgbe_sctx_init.isc_nrxd_max[i] = XGBE_RX_DESC_CNT_MAX; + } + return (&axgbe_sctx_init); } @@ -1292,6 +1327,9 @@ if_softc_ctx_t scctx = sc->scctx; int i, ret; + /* set split header support based on tunable */ + pdata->sph_enable = axgbe_sph_enable; + /* Initialize ECC timestamps */ pdata->tx_sec_period = ticks; pdata->tx_ded_period = ticks; @@ -1404,6 +1442,8 @@ axgbe_sysctl_init(pdata); + axgbe_pci_init(pdata); + return (0); } /* axgbe_if_attach_post */ @@ -1491,7 +1531,12 @@ struct xgbe_phy_if *phy_if = &pdata->phy_if; struct xgbe_hw_if *hw_if = &pdata->hw_if; int ret = 0; - + + if (!__predict_false((test_bit(XGBE_DOWN, &pdata->dev_state)))) { + axgbe_printf(1, "%s: Starting when XGBE_UP\n", __func__); + return; + } + hw_if->init(pdata); ret = phy_if->phy_start(pdata); @@ -1656,7 +1701,11 @@ MPASS(scctx->isc_nrxqsets > 0); MPASS(scctx->isc_nrxqsets == nrxqsets); - MPASS(nrxqs == 2); + if (!pdata->sph_enable) { + MPASS(nrxqs == 1); + } else { + MPASS(nrxqs == 2); + } axgbe_printf(1, "%s: rxqsets %d/%d rxqs %d\n", __func__, scctx->isc_nrxqsets, nrxqsets, nrxqs); @@ -2258,15 +2307,40 @@ static int axgbe_if_promisc_set(if_ctx_t ctx, int flags) { - struct axgbe_if_softc *sc = iflib_get_softc(ctx); + struct axgbe_if_softc *sc = iflib_get_softc(ctx); + struct xgbe_prv_data *pdata = &sc->pdata; + struct ifnet *ifp = pdata->netdev; - if (XGMAC_IOREAD_BITS(&sc->pdata, MAC_PFR, PR) == 1) - return (0); + axgbe_printf(1, "%s: MAC_PFR 0x%x drv_flags 0x%x if_flags 0x%x\n", + __func__, XGMAC_IOREAD(pdata, MAC_PFR), ifp->if_drv_flags, ifp->if_flags); - XGMAC_IOWRITE_BITS(&sc->pdata, MAC_PFR, PR, 1); - XGMAC_IOWRITE_BITS(&sc->pdata, MAC_PFR, VTFE, 0); + if (ifp->if_flags & IFF_PPROMISC) { - return (0); + axgbe_printf(1, "User requested to enter promisc mode\n"); + + if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PR) == 1) { + axgbe_printf(1, "Already in promisc mode\n"); + return (0); + } + + axgbe_printf(1, "Entering promisc mode\n"); + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PR, 1); + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 0); + } else { + + axgbe_printf(1, "User requested to leave promisc mode\n"); + + if (XGMAC_IOREAD_BITS(pdata, MAC_PFR, PR) == 0) { + axgbe_printf(1, "Already not in promisc mode\n"); + return (0); + } + + axgbe_printf(1, "Leaving promisc mode\n"); + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, PR, 0); + XGMAC_IOWRITE_BITS(pdata, MAC_PFR, VTFE, 1); + } + + return (0); } static uint64_t diff --git a/sys/dev/axgbe/xgbe-dev.c b/sys/dev/axgbe/xgbe-dev.c --- a/sys/dev/axgbe/xgbe-dev.c +++ b/sys/dev/axgbe/xgbe-dev.c @@ -293,12 +293,14 @@ { unsigned int i; + int tso_enabled = (if_getcapenable(pdata->netdev) & IFCAP_TSO); + for (i = 0; i < pdata->channel_count; i++) { if (!pdata->channel[i]->tx_ring) break; - axgbe_printf(0, "Enabling TSO in channel %d\n", i); - XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, TSE, 1); + axgbe_printf(1, "TSO in channel %d %s\n", i, tso_enabled ? "enabled" : "disabled"); + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_TCR, TSE, tso_enabled ? 1 : 0); } } @@ -306,15 +308,33 @@ xgbe_config_sph_mode(struct xgbe_prv_data *pdata) { unsigned int i; + int sph_enable_flag = XGMAC_IOREAD_BITS(pdata, MAC_HWF1R, SPHEN); + + axgbe_printf(1, "sph_enable %d sph feature enabled?: %d\n", + pdata->sph_enable, sph_enable_flag); + + if (pdata->sph_enable && sph_enable_flag) + axgbe_printf(0, "SPH Enabled\n"); for (i = 0; i < pdata->channel_count; i++) { if (!pdata->channel[i]->rx_ring) break; + if (pdata->sph_enable && sph_enable_flag) { + /* Enable split header feature */ + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 1); + } else { + /* Disable split header feature */ + XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 0); + } - XGMAC_DMA_IOWRITE_BITS(pdata->channel[i], DMA_CH_CR, SPH, 1); + /* per-channel confirmation of SPH being disabled/enabled */ + int val = XGMAC_DMA_IOREAD_BITS(pdata->channel[i], DMA_CH_CR, SPH); + axgbe_printf(0, "%s: SPH %s in channel %d\n", __func__, + (val ? "enabled" : "disabled"), i); } - XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE); + if (pdata->sph_enable && sph_enable_flag) + XGMAC_IOWRITE_BITS(pdata, MAC_RCR, HDSMS, XGBE_SPH_HDSMS_SIZE); } static int @@ -953,8 +973,8 @@ { unsigned int pr_mode, am_mode; - pr_mode = ((pdata->netdev->if_drv_flags & IFF_PPROMISC) != 0); - am_mode = ((pdata->netdev->if_drv_flags & IFF_ALLMULTI) != 0); + pr_mode = ((pdata->netdev->if_flags & IFF_PPROMISC) != 0); + am_mode = ((pdata->netdev->if_flags & IFF_ALLMULTI) != 0); xgbe_set_promiscuous_mode(pdata, pr_mode); xgbe_set_all_multicast_mode(pdata, am_mode); @@ -1352,7 +1372,6 @@ if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_NORMAL_DESC3, CTXT)) { /* TODO - Timestamp Context Descriptor */ - XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, CONTEXT, 1); XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, diff --git a/sys/dev/axgbe/xgbe-sysctl.c b/sys/dev/axgbe/xgbe-sysctl.c --- a/sys/dev/axgbe/xgbe-sysctl.c +++ b/sys/dev/axgbe/xgbe-sysctl.c @@ -1614,6 +1614,10 @@ SYSCTL_ADD_UINT(clist, top, OID_AUTO, "axgbe_debug_level", CTLFLAG_RWTUN, &pdata->debug_level, 0, "axgbe log level -- higher is verbose"); + SYSCTL_ADD_UINT(clist, top, OID_AUTO, "sph_enable", + CTLFLAG_RDTUN, &pdata->sph_enable, 1, + "shows the split header feature state (1 - enable, 0 - disable"); + SYSCTL_ADD_PROC(clist, top, OID_AUTO, "xgmac_register", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, pdata, 0, sysctl_xgmac_reg_addr_handler, "IU", diff --git a/sys/dev/axgbe/xgbe-txrx.c b/sys/dev/axgbe/xgbe-txrx.c --- a/sys/dev/axgbe/xgbe-txrx.c +++ b/sys/dev/axgbe/xgbe-txrx.c @@ -379,20 +379,9 @@ axgbe_printf(1, "--> %s: flush txq %d pidx %d cur %d dirty %d\n", __func__, txqid, pidx, ring->cur, ring->dirty); - MPASS(ring->cur == pidx); - if (__predict_false(ring->cur != pidx)) { - axgbe_error("--> %s: cur(%d) ne pidx(%d)\n", __func__, - ring->cur, pidx); - } - - wmb(); - /* Ring Doorbell */ - if (XGMAC_DMA_IOREAD(channel, DMA_CH_TDTR_LO) != - lower_32_bits(rdata->rdata_paddr)) { - XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO, - lower_32_bits(rdata->rdata_paddr)); - } + XGMAC_DMA_IOWRITE(channel, DMA_CH_TDTR_LO, + lower_32_bits(rdata->rdata_paddr)); } static int @@ -466,6 +455,7 @@ unsigned int inte; uint8_t count = iru->iru_count; int i, j; + bool config_intr = false; axgbe_printf(1, "--> %s: rxq %d fl %d pidx %d count %d ring cur %d " "dirty %d\n", __func__, iru->iru_qsidx, iru->iru_flidx, @@ -473,7 +463,7 @@ for (i = iru->iru_pidx, j = 0 ; j < count ; i++, j++) { - if (i == XGBE_RX_DESC_CNT_DEFAULT) + if (i == sc->scctx->isc_nrxd[0]) i = 0; rdata = XGBE_GET_DESC_DATA(ring, i); @@ -485,29 +475,42 @@ "pidx %d\n", __func__, ring->cur, ring->dirty, j, i); } - /* Assuming split header is enabled */ - if (iru->iru_flidx == 0) { + if (pdata->sph_enable) { + if (iru->iru_flidx == 0) { + + /* Fill header/buffer1 address */ + rdesc->desc0 = + cpu_to_le32(lower_32_bits(iru->iru_paddrs[j])); + rdesc->desc1 = + cpu_to_le32(upper_32_bits(iru->iru_paddrs[j])); + } else { + + /* Fill data/buffer2 address */ + rdesc->desc2 = + cpu_to_le32(lower_32_bits(iru->iru_paddrs[j])); + rdesc->desc3 = + cpu_to_le32(upper_32_bits(iru->iru_paddrs[j])); + config_intr = true; + } + } else { /* Fill header/buffer1 address */ - rdesc->desc0 = + rdesc->desc0 = rdesc->desc2 = cpu_to_le32(lower_32_bits(iru->iru_paddrs[j])); - rdesc->desc1 = + rdesc->desc1 = rdesc->desc3 = cpu_to_le32(upper_32_bits(iru->iru_paddrs[j])); - } else { - /* Fill data/buffer2 address */ - rdesc->desc2 = - cpu_to_le32(lower_32_bits(iru->iru_paddrs[j])); - rdesc->desc3 = - cpu_to_le32(upper_32_bits(iru->iru_paddrs[j])); + config_intr = true; + } + + if (config_intr) { if (!rx_usecs && !rx_frames) { /* No coalescing, interrupt for every descriptor */ inte = 1; } else { /* Set interrupt based on Rx frame coalescing setting */ - if (rx_frames && - !(((ring->dirty + 1) &(ring->rdesc_count - 1)) % rx_frames)) + if (rx_frames && !((ring->dirty + 1) % rx_frames)) inte = 1; else inte = 0; @@ -520,6 +523,8 @@ wmb(); ring->dirty = ((ring->dirty + 1) & (ring->rdesc_count - 1)); + + config_intr = false; } } @@ -539,15 +544,16 @@ axgbe_printf(1, "--> %s: rxq %d fl %d pidx %d cur %d dirty %d\n", __func__, qsidx, flidx, pidx, ring->cur, ring->dirty); - if (flidx == 1) { - - rdata = XGBE_GET_DESC_DATA(ring, pidx); + rdata = XGBE_GET_DESC_DATA(ring, pidx); + /* + * update RX descriptor tail pointer in hardware to indicate + * that new buffers are present in the allocated memory region + */ + if (!pdata->sph_enable || flidx == 1) { XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO, lower_32_bits(rdata->rdata_paddr)); } - - wmb(); } static int @@ -560,12 +566,17 @@ struct xgbe_ring_data *rdata; struct xgbe_ring_desc *rdesc; unsigned int cur; - int count; + int count = 0; uint8_t incomplete = 1, context_next = 0, running = 0; axgbe_printf(1, "--> %s: rxq %d idx %d budget %d cur %d dirty %d\n", __func__, qsidx, idx, budget, ring->cur, ring->dirty); + if (__predict_false(test_bit(XGBE_DOWN, &pdata->dev_state))) { + axgbe_printf(0, "%s: Polling when XGBE_DOWN\n", __func__); + return (count); + } + cur = ring->cur; for (count = 0; count <= budget; ) { @@ -609,11 +620,14 @@ xgbe_rx_buf1_len(struct xgbe_prv_data *pdata, struct xgbe_ring_data *rdata, struct xgbe_packet_data *packet) { + unsigned int ret = 0; - /* Always zero if not the first descriptor */ - if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, FIRST)) { - axgbe_printf(1, "%s: Not First\n", __func__); - return (0); + if (pdata->sph_enable) { + /* Always zero if not the first descriptor */ + if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, FIRST)) { + axgbe_printf(1, "%s: Not First\n", __func__); + return (0); + } } /* First descriptor with split header, return header length */ @@ -623,21 +637,33 @@ } /* First descriptor but not the last descriptor and no split header, - * so the full buffer was used + * so the full buffer was used, 256 represents the hardcoded value of + * a max header split defined in the hardware */ if (!XGMAC_GET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, LAST)) { axgbe_printf(1, "%s: Not last %d\n", __func__, pdata->rx_buf_size); - return (256); + if (pdata->sph_enable) { + return (256); + } else { + return (pdata->rx_buf_size); + } } /* First descriptor and last descriptor and no split header, so - * calculate how much of the buffer was used + * calculate how much of the buffer was used, we can return the + * segment length or the remaining bytes of the packet */ axgbe_printf(1, "%s: pkt_len %d buf_size %d\n", __func__, rdata->rx.len, pdata->rx_buf_size); - return (min_t(unsigned int, 256, rdata->rx.len)); + if (pdata->sph_enable) { + ret = min_t(unsigned int, 256, rdata->rx.len); + } else { + ret = rdata->rx.len; + } + + return (ret); } static unsigned int @@ -712,8 +738,10 @@ /* Get the data length in the descriptor buffers */ buf1_len = xgbe_rx_buf1_len(pdata, rdata, packet); len += buf1_len; - buf2_len = xgbe_rx_buf2_len(pdata, rdata, packet, len); - len += buf2_len; + if (pdata->sph_enable) { + buf2_len = xgbe_rx_buf2_len(pdata, rdata, packet, len); + len += buf2_len; + } } else buf1_len = buf2_len = 0; @@ -724,8 +752,10 @@ axgbe_add_frag(pdata, ri, prev_cur, buf1_len, i, 0); i++; - axgbe_add_frag(pdata, ri, prev_cur, buf2_len, i, 1); - i++; + if (pdata->sph_enable) { + axgbe_add_frag(pdata, ri, prev_cur, buf2_len, i, 1); + i++; + } if (!last || context_next) goto read_again; @@ -758,7 +788,7 @@ } if (__predict_false(len == 0)) - axgbe_error("%s: Zero len packet\n", __func__); + axgbe_printf(1, "%s: Discarding Zero len packet\n", __func__); if (__predict_false(len > max_len)) axgbe_error("%s: Big packet %d/%d\n", __func__, len, max_len); diff --git a/sys/dev/axgbe/xgbe.h b/sys/dev/axgbe/xgbe.h --- a/sys/dev/axgbe/xgbe.h +++ b/sys/dev/axgbe/xgbe.h @@ -1296,6 +1296,12 @@ uint64_t rx_coalesce_usecs; unsigned int debug_level; + + /* + * Toggles the split header feature. + * This requires a complete restart. + */ + unsigned int sph_enable; }; struct axgbe_if_softc {