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

Reply via email to