Module Name: src Committed By: knakahara Date: Tue Oct 13 08:36:02 UTC 2015
Modified Files: src/sys/dev/pci: if_wm.c if_wmreg.h Log Message: support RX multiqueue. ok by msaitoh@n.o To generate a diff of this commit: cvs rdiff -u -r1.364 -r1.365 src/sys/dev/pci/if_wm.c cvs rdiff -u -r1.83 -r1.84 src/sys/dev/pci/if_wmreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_wm.c diff -u src/sys/dev/pci/if_wm.c:1.364 src/sys/dev/pci/if_wm.c:1.365 --- src/sys/dev/pci/if_wm.c:1.364 Tue Oct 13 08:33:12 2015 +++ src/sys/dev/pci/if_wm.c Tue Oct 13 08:36:02 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wm.c,v 1.364 2015/10/13 08:33:12 knakahara Exp $ */ +/* $NetBSD: if_wm.c,v 1.365 2015/10/13 08:36:02 knakahara Exp $ */ /* * Copyright (c) 2001, 2002, 2003, 2004 Wasabi Systems, Inc. @@ -83,7 +83,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.364 2015/10/13 08:33:12 knakahara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_wm.c,v 1.365 2015/10/13 08:36:02 knakahara Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -565,6 +565,7 @@ static uint32_t wm_rxpbs_adjust_82580(ui static void wm_reset(struct wm_softc *); static int wm_add_rxbuf(struct wm_rxqueue *, int); static void wm_rxdrain(struct wm_rxqueue *); +static void wm_init_rss(struct wm_softc *); static int wm_init(struct ifnet *); static int wm_init_locked(struct ifnet *); static void wm_stop(struct ifnet *, int); @@ -609,6 +610,7 @@ static void wm_linkintr_serdes(struct wm static void wm_linkintr(struct wm_softc *, uint32_t); static int wm_intr_legacy(void *); #ifdef WM_MSI_MSIX +static void wm_adjust_qnum(struct wm_softc *, int); static int wm_setup_legacy(struct wm_softc *); static int wm_setup_msix(struct wm_softc *); static int wm_txintr_msix(void *); @@ -1623,7 +1625,7 @@ wm_attach(device_t parent, device_t self return; } - /* XXX Currently, Tx, Rx queue are always one. */ +#ifndef WM_MSI_MSIX sc->sc_ntxqueues = 1; sc->sc_nrxqueues = 1; error = wm_alloc_txrx_queues(sc); @@ -1633,7 +1635,6 @@ wm_attach(device_t parent, device_t self return; } -#ifndef WM_MSI_MSIX /* * Map and establish our interrupt. */ @@ -1657,6 +1658,14 @@ wm_attach(device_t parent, device_t self aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); sc->sc_nintrs = 1; #else /* WM_MSI_MSIX */ + wm_adjust_qnum(sc, pci_msix_count(pa->pa_pc, pa->pa_tag)); + error = wm_alloc_txrx_queues(sc); + if (error) { + aprint_error_dev(sc->sc_dev, "cannot allocate queues %d\n", + error); + return; + } + /* Allocation settings */ max_type = PCI_INTR_TYPE_MSIX; counts[PCI_INTR_TYPE_MSIX] = sc->sc_ntxqueues + sc->sc_nrxqueues + 1; @@ -4036,6 +4045,159 @@ wm_rxdrain(struct wm_rxqueue *rxq) } } +/* + * Adjust TX and RX queue numbers which the system actulally uses. + * + * The numbers are affected by below parameters. + * - The nubmer of hardware queues + * - The number of MSI-X vectors (= "nvectors" argument) + * - ncpu + */ +static void +wm_adjust_qnum(struct wm_softc *sc, int nvectors) +{ + int hw_ntxqueues, hw_nrxqueues; + + if (nvectors < 3) { + sc->sc_ntxqueues = 1; + sc->sc_nrxqueues = 1; + return; + } + + switch(sc->sc_type) { + case WM_T_82572: + hw_ntxqueues = 2; + hw_nrxqueues = 2; + break; + case WM_T_82574: + hw_ntxqueues = 2; + hw_nrxqueues = 2; + break; + case WM_T_82575: + hw_ntxqueues = 4; + hw_nrxqueues = 4; + break; + case WM_T_82576: + hw_ntxqueues = 16; + hw_nrxqueues = 16; + break; + case WM_T_82580: + case WM_T_I350: + case WM_T_I354: + hw_ntxqueues = 8; + hw_nrxqueues = 8; + break; + case WM_T_I210: + hw_ntxqueues = 4; + hw_nrxqueues = 4; + break; + case WM_T_I211: + hw_ntxqueues = 2; + hw_nrxqueues = 2; + break; + /* + * As below ethernet controllers does not support MSI-X, + * this driver let them not use multiqueue. + * - WM_T_80003 + * - WM_T_ICH8 + * - WM_T_ICH9 + * - WM_T_ICH10 + * - WM_T_PCH + * - WM_T_PCH2 + * - WM_T_PCH_LPT + */ + default: + hw_ntxqueues = 1; + hw_nrxqueues = 1; + break; + } + + /* + * As queues more then MSI-X vectors cannot improve scaling, we limit + * the number of queues used actually. + * + * XXX + * Currently, we separate TX queue interrupts and RX queue interrupts. + * Howerver, the number of MSI-X vectors of recent controllers (such as + * I354) expects that drivers bundle a TX queue interrupt and a RX + * interrupt to one interrupt. e.g. FreeBSD's igb deals interrupts in + * such a way. + */ + if (nvectors < hw_ntxqueues + hw_nrxqueues + 1) { + sc->sc_ntxqueues = (nvectors - 1) / 2; + sc->sc_nrxqueues = (nvectors - 1) / 2; + } else { + sc->sc_ntxqueues = hw_ntxqueues; + sc->sc_nrxqueues = hw_nrxqueues; + } + + /* + * As queues more then cpus cannot improve scaling, we limit + * the number of queues used actually. + */ + if (ncpu < sc->sc_ntxqueues) + sc->sc_ntxqueues = ncpu; + if (ncpu < sc->sc_nrxqueues) + sc->sc_nrxqueues = ncpu; + + /* XXX Currently, this driver supports RX multiqueue only. */ + sc->sc_ntxqueues = 1; +} + +/* + * Setup registers for RSS. + * + * XXX not yet VMDq support + */ +static void +wm_init_rss(struct wm_softc *sc) +{ + uint32_t mrqc, reta_reg; + int i; + + for (i = 0; i < RETA_NUM_ENTRIES; i++) { + int qid, reta_ent; + + qid = i % sc->sc_nrxqueues; + switch(sc->sc_type) { + case WM_T_82574: + reta_ent = __SHIFTIN(qid, + RETA_ENT_QINDEX_MASK_82574); + break; + case WM_T_82575: + reta_ent = __SHIFTIN(qid, + RETA_ENT_QINDEX1_MASK_82575); + break; + default: + reta_ent = __SHIFTIN(qid, RETA_ENT_QINDEX_MASK); + break; + } + + reta_reg = CSR_READ(sc, WMREG_RETA_Q(i)); + reta_reg &= ~RETA_ENTRY_MASK_Q(i); + reta_reg |= __SHIFTIN(reta_ent, RETA_ENTRY_MASK_Q(i)); + CSR_WRITE(sc, WMREG_RETA_Q(i), reta_reg); + } + + for (i = 0; i < RSSRK_NUM_REGS; i++) + CSR_WRITE(sc, WMREG_RSSRK(i), (uint32_t)random()); + + if (sc->sc_type == WM_T_82574) + mrqc = MRQC_ENABLE_RSS_MQ_82574; + else + mrqc = MRQC_ENABLE_RSS_MQ; + + /* XXXX + * The same as FreeBSD igb. + * Why doesn't use MRQC_RSS_FIELD_IPV6_EX? + */ + mrqc |= (MRQC_RSS_FIELD_IPV4 | MRQC_RSS_FIELD_IPV4_TCP); + mrqc |= (MRQC_RSS_FIELD_IPV6 | MRQC_RSS_FIELD_IPV6_TCP); + mrqc |= (MRQC_RSS_FIELD_IPV4_UDP | MRQC_RSS_FIELD_IPV6_UDP); + mrqc |= (MRQC_RSS_FIELD_IPV6_UDP_EX | MRQC_RSS_FIELD_IPV6_TCP_EX); + + CSR_WRITE(sc, WMREG_MRQC, mrqc); +} #ifdef WM_MSI_MSIX /* @@ -4450,13 +4612,13 @@ wm_init_locked(struct ifnet *ifp) for (i = 0; i < sc->sc_ntxqueues; i++) { struct wm_txqueue *txq = &sc->sc_txq[i]; CSR_WRITE(sc, WMREG_MSIXBM(txq->txq_intr_idx), - txq->txq_id); + EITR_TX_QUEUE(txq->txq_id)); } /* RX */ for (i = 0; i < sc->sc_nrxqueues; i++) { struct wm_rxqueue *rxq = &sc->sc_rxq[i]; CSR_WRITE(sc, WMREG_MSIXBM(rxq->rxq_intr_idx), - rxq->rxq_id); + EITR_RX_QUEUE(rxq->rxq_id)); } /* Link status */ CSR_WRITE(sc, WMREG_MSIXBM(sc->sc_link_intr_idx), @@ -4554,6 +4716,20 @@ wm_init_locked(struct ifnet *ifp) IVAR_MISC_OTHER); CSR_WRITE(sc, WMREG_IVAR_MISC, ivar); } + + if (sc->sc_nrxqueues > 1) { + wm_init_rss(sc); + + /* + ** NOTE: Receive Full-Packet Checksum Offload + ** is mutually exclusive with Multiqueue. However + ** this is not the same as TCP/IP checksums which + ** still work. + */ + reg = CSR_READ(sc, WMREG_RXCSUM); + reg |= RXCSUM_PCSD; + CSR_WRITE(sc, WMREG_RXCSUM, reg); + } } /* Set up the interrupt registers. */ Index: src/sys/dev/pci/if_wmreg.h diff -u src/sys/dev/pci/if_wmreg.h:1.83 src/sys/dev/pci/if_wmreg.h:1.84 --- src/sys/dev/pci/if_wmreg.h:1.83 Tue Oct 13 08:23:31 2015 +++ src/sys/dev/pci/if_wmreg.h Tue Oct 13 08:36:02 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: if_wmreg.h,v 1.83 2015/10/13 08:23:31 knakahara Exp $ */ +/* $NetBSD: if_wmreg.h,v 1.84 2015/10/13 08:36:02 knakahara Exp $ */ /* * Copyright (c) 2001 Wasabi Systems, Inc. @@ -878,6 +878,9 @@ struct livengood_tcpip_ctxdesc { #define RXCSUM_IPOFL (1U << 8) /* IP checksum offload */ #define RXCSUM_TUOFL (1U << 9) /* TCP/UDP checksum offload */ #define RXCSUM_IPV6OFL (1U << 10) /* IPv6 checksum offload */ +#define RXCSUM_CRCOFL (1U << 10) /* SCTP CRC32 checksum offload */ +#define RXCSUM_IPPCSE (1U << 12) /* IP payload checksum enable */ +#define RXCSUM_PCSD (1U << 13) /* packet checksum disabled */ #define WMREG_RLPML 0x5004 /* Rx Long Packet Max Length */ @@ -902,6 +905,56 @@ struct livengood_tcpip_ctxdesc { #define WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup En */ #define WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup En */ +#define WMREG_MRQC 0x5818 /* Multiple Receive Queues Command */ +#define MRQC_DISABLE_RSS 0x00000000 +#define MRQC_ENABLE_RSS_MQ_82574 __BIT(0) /* enable RSS for 82574 */ +#define MRQC_ENABLE_RSS_MQ __BIT(1) /* enable hardware max RSS without VMDq */ +#define MRQC_ENABLE_RSS_VMDQ __BITS(1, 0) /* enable RSS with VMDq */ +#define MRQC_DEFQ_MASK __BITS(5, 3) + /* + * Defines the default queue in non VMDq + * mode according to value of the Multiple Receive + * Queues Enable field. + */ +#define MRQC_DEFQ_NOT_RSS_FLT __SHFTIN(__BIT(1), MRQC_DEFQ_MASK) + /* + * the destination of all packets + * not forwarded by RSS or filters + */ +#define MRQC_DEFQ_NOT_MAC_ETH __SHFTIN(__BITS(1, 0), MRQC_DEFQ_MASK) + /* + * Def_Q field is ignored. Queueing + * decision of all packets not forwarded + * by MAC address and Ether-type filters + * is according to VT_CTL.DEF_PL field. + */ +#define MRQC_DEFQ_IGNORED1 __SHFTIN(__BIT(2), MRQC_DEFQ_MASK) + /* Def_Q field is ignored */ +#define MRQC_DEFQ_IGNORED2 __SHFTIN(__BIT(2)|__BIT(0), MRQC_DEFQ_MASK) + /* Def_Q field is ignored */ +#define MRQC_DEFQ_VMDQ __SHFTIN(__BITS(2, 1), MRQC_DEFQ_MASK) + /* for VMDq mode */ +#define MRQC_RSS_FIELD_IPV4_TCP __BIT(16) +#define MRQC_RSS_FIELD_IPV4 __BIT(17) +#define MRQC_RSS_FIELD_IPV6_TCP_EX __BIT(18) +#define MRQC_RSS_FIELD_IPV6_EX __BIT(19) +#define MRQC_RSS_FIELD_IPV6 __BIT(20) +#define MRQC_RSS_FIELD_IPV6_TCP __BIT(21) +#define MRQC_RSS_FIELD_IPV4_UDP __BIT(22) +#define MRQC_RSS_FIELD_IPV6_UDP __BIT(23) +#define MRQC_RSS_FIELD_IPV6_UDP_EX __BIT(24) + +#define WMREG_RETA_Q(x) (0x5c00 + ((x) >> 2) * 4) /* Redirection Table */ +#define RETA_NUM_ENTRIES 128 +#define RETA_ENTRY_MASK_Q(x) (0x000000ff << (((x) % 4) * 8)) /* Redirection Table */ +#define RETA_ENT_QINDEX_MASK __BITS(3,0) /*queue index for 82580 and newer */ +#define RETA_ENT_QINDEX0_MASK_82575 __BITS(3,2) /*queue index for pool0 */ +#define RETA_ENT_QINDEX1_MASK_82575 __BITS(7,6) /*queue index for pool1 and regular RSS */ +#define RETA_ENT_QINDEX_MASK_82574 __BIT(7) /*queue index for 82574 */ + +#define WMREG_RSSRK(x) (0x5c80 + (x) * 4) /* RSS Random Key Register */ +#define RSSRK_NUM_REGS 10 + #define WMREG_MANC 0x5820 /* Management Control */ #define MANC_SMBUS_EN 0x00000001 #define MANC_ASF_EN 0x00000002