Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Feb 2011 01:08:13 +0000 (UTC)
From:      Pyun YongHyeon <yongari@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r218903 - in stable/8/sys: dev/re pci
Message-ID:  <201102210108.p1L18DUG050924@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: yongari
Date: Mon Feb 21 01:08:13 2011
New Revision: 218903
URL: http://svn.freebsd.org/changeset/base/218903

Log:
  MFC r217499:
    Implement initial jumbo frame support for RTL8168/8111 C/D/E PCIe
    GbE controllers. It seems these controllers no longer support
    multi-fragmented RX buffers such that driver have to allocate
    physically contiguous buffers.
  
     o Retire RL_FLAG_NOJUMBO flag and introduce RL_FLAG_JUMBOV2 to
       mark controllers that use new jumbo frame scheme.
     o Configure PCIe max read request size to 4096 for standard frames
       and reduce it to 512 for jumbo frames.
     o TSO/checksum offloading is not supported for jumbo frames on
       these controllers. Reflect it to ioctl handler and driver
       initialization.
     o Remove unused rl_stats_no_timeout in softc.
     o Embed a pointer to structure rl_hwrev into softc to keep track
       of controller MTU limitation and remove rl_hwrev in softc since
       that information is available through a pointer to structure
       rl_hwrev.
  
    Special thanks to Realtek for donating sample hardwares which made
    this possible.
  
    H/W donated by:	Realtek Semiconductor Corp.

Modified:
  stable/8/sys/dev/re/if_re.c
  stable/8/sys/pci/if_rlreg.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/dev/re/if_re.c
==============================================================================
--- stable/8/sys/dev/re/if_re.c	Mon Feb 21 01:05:23 2011	(r218902)
+++ stable/8/sys/dev/re/if_re.c	Mon Feb 21 01:08:13 2011	(r218903)
@@ -189,40 +189,40 @@ static struct rl_type re_devs[] = {
 };
 
 static struct rl_hwrev re_hwrevs[] = {
-	{ RL_HWREV_8139, RL_8139,  "" },
-	{ RL_HWREV_8139A, RL_8139, "A" },
-	{ RL_HWREV_8139AG, RL_8139, "A-G" },
-	{ RL_HWREV_8139B, RL_8139, "B" },
-	{ RL_HWREV_8130, RL_8139, "8130" },
-	{ RL_HWREV_8139C, RL_8139, "C" },
-	{ RL_HWREV_8139D, RL_8139, "8139D/8100B/8100C" },
-	{ RL_HWREV_8139CPLUS, RL_8139CPLUS, "C+"},
-	{ RL_HWREV_8168_SPIN1, RL_8169, "8168"},
-	{ RL_HWREV_8169, RL_8169, "8169"},
-	{ RL_HWREV_8169S, RL_8169, "8169S"},
-	{ RL_HWREV_8110S, RL_8169, "8110S"},
-	{ RL_HWREV_8169_8110SB, RL_8169, "8169SB/8110SB"},
-	{ RL_HWREV_8169_8110SC, RL_8169, "8169SC/8110SC"},
-	{ RL_HWREV_8169_8110SBL, RL_8169, "8169SBL/8110SBL"},
-	{ RL_HWREV_8169_8110SCE, RL_8169, "8169SC/8110SC"},
-	{ RL_HWREV_8100, RL_8139, "8100"},
-	{ RL_HWREV_8101, RL_8139, "8101"},
-	{ RL_HWREV_8100E, RL_8169, "8100E"},
-	{ RL_HWREV_8101E, RL_8169, "8101E"},
-	{ RL_HWREV_8102E, RL_8169, "8102E"},
-	{ RL_HWREV_8102EL, RL_8169, "8102EL"},
-	{ RL_HWREV_8102EL_SPIN1, RL_8169, "8102EL"},
-	{ RL_HWREV_8103E, RL_8169, "8103E"},
-	{ RL_HWREV_8168_SPIN2, RL_8169, "8168"},
-	{ RL_HWREV_8168_SPIN3, RL_8169, "8168"},
-	{ RL_HWREV_8168C, RL_8169, "8168C/8111C"},
-	{ RL_HWREV_8168C_SPIN2, RL_8169, "8168C/8111C"},
-	{ RL_HWREV_8168CP, RL_8169, "8168CP/8111CP"},
-	{ RL_HWREV_8168D, RL_8169, "8168D/8111D"},
-	{ RL_HWREV_8168DP, RL_8169, "8168DP/8111DP"},
-	{ RL_HWREV_8168E, RL_8169, "8168E/8111E"},
-	{ RL_HWREV_8168E_VL, RL_8169, "8168E/8111E-VL"},
-	{ 0, 0, NULL }
+	{ RL_HWREV_8139, RL_8139,  "", RL_MTU },
+	{ RL_HWREV_8139A, RL_8139, "A", RL_MTU },
+	{ RL_HWREV_8139AG, RL_8139, "A-G", RL_MTU },
+	{ RL_HWREV_8139B, RL_8139, "B", RL_MTU },
+	{ RL_HWREV_8130, RL_8139, "8130", RL_MTU },
+	{ RL_HWREV_8139C, RL_8139, "C", RL_MTU },
+	{ RL_HWREV_8139D, RL_8139, "8139D/8100B/8100C", RL_MTU },
+	{ RL_HWREV_8139CPLUS, RL_8139CPLUS, "C+", RL_MTU },
+	{ RL_HWREV_8168_SPIN1, RL_8169, "8168", RL_JUMBO_MTU },
+	{ RL_HWREV_8169, RL_8169, "8169", RL_JUMBO_MTU },
+	{ RL_HWREV_8169S, RL_8169, "8169S", RL_JUMBO_MTU },
+	{ RL_HWREV_8110S, RL_8169, "8110S", RL_JUMBO_MTU },
+	{ RL_HWREV_8169_8110SB, RL_8169, "8169SB/8110SB", RL_JUMBO_MTU },
+	{ RL_HWREV_8169_8110SC, RL_8169, "8169SC/8110SC", RL_JUMBO_MTU },
+	{ RL_HWREV_8169_8110SBL, RL_8169, "8169SBL/8110SBL", RL_JUMBO_MTU },
+	{ RL_HWREV_8169_8110SCE, RL_8169, "8169SC/8110SC", RL_JUMBO_MTU },
+	{ RL_HWREV_8100, RL_8139, "8100", RL_MTU },
+	{ RL_HWREV_8101, RL_8139, "8101", RL_MTU },
+	{ RL_HWREV_8100E, RL_8169, "8100E", RL_MTU },
+	{ RL_HWREV_8101E, RL_8169, "8101E", RL_MTU },
+	{ RL_HWREV_8102E, RL_8169, "8102E", RL_MTU },
+	{ RL_HWREV_8102EL, RL_8169, "8102EL", RL_MTU },
+	{ RL_HWREV_8102EL_SPIN1, RL_8169, "8102EL", RL_MTU },
+	{ RL_HWREV_8103E, RL_8169, "8103E", RL_MTU },
+	{ RL_HWREV_8168_SPIN2, RL_8169, "8168", RL_JUMBO_MTU },
+	{ RL_HWREV_8168_SPIN3, RL_8169, "8168", RL_JUMBO_MTU },
+	{ RL_HWREV_8168C, RL_8169, "8168C/8111C", RL_JUMBO_MTU_6K },
+	{ RL_HWREV_8168C_SPIN2, RL_8169, "8168C/8111C", RL_JUMBO_MTU_6K },
+	{ RL_HWREV_8168CP, RL_8169, "8168CP/8111CP", RL_JUMBO_MTU_6K },
+	{ RL_HWREV_8168D, RL_8169, "8168D/8111D", RL_JUMBO_MTU_9K },
+	{ RL_HWREV_8168DP, RL_8169, "8168DP/8111DP", RL_JUMBO_MTU_9K },
+	{ RL_HWREV_8168E, RL_8169, "8168E/8111E", RL_JUMBO_MTU_9K},
+	{ RL_HWREV_8168E_VL, RL_8169, "8168E/8111E-VL", RL_JUMBO_MTU_6K},
+	{ 0, 0, NULL, 0 }
 };
 
 static int re_probe		(device_t);
@@ -236,7 +236,9 @@ static int re_allocmem		(device_t, struc
 static __inline void re_discard_rxbuf
 				(struct rl_softc *, int);
 static int re_newbuf		(struct rl_softc *, int);
+static int re_jumbo_newbuf	(struct rl_softc *, int);
 static int re_rx_list_init	(struct rl_softc *);
+static int re_jrx_list_init	(struct rl_softc *);
 static int re_tx_list_init	(struct rl_softc *);
 #ifdef RE_FIXUP_RX
 static __inline void re_fixup_rx
@@ -274,6 +276,7 @@ static int re_miibus_readreg	(device_t, 
 static int re_miibus_writereg	(device_t, int, int, int);
 static void re_miibus_statchg	(device_t);
 
+static void re_set_jumbo	(struct rl_softc *, int);
 static void re_set_rxmode		(struct rl_softc *);
 static void re_reset		(struct rl_softc *);
 static void re_setwol		(struct rl_softc *);
@@ -699,7 +702,7 @@ re_reset(struct rl_softc *sc)
 
 	if ((sc->rl_flags & RL_FLAG_MACRESET) != 0)
 		CSR_WRITE_1(sc, 0x82, 1);
-	if (sc->rl_hwrev == RL_HWREV_8169S)
+	if (sc->rl_hwrev->rl_rev == RL_HWREV_8169S)
 		re_gmii_writereg(sc->rl_dev, 1, 0x0b, 0);
 }
 
@@ -991,6 +994,17 @@ re_allocmem(device_t dev, struct rl_soft
 	 * Allocate map for RX mbufs.
 	 */
 
+	if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
+		error = bus_dma_tag_create(sc->rl_parent_tag, sizeof(uint64_t),
+		    0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+		    MJUM9BYTES, 1, MJUM9BYTES, 0, NULL, NULL,
+		    &sc->rl_ldata.rl_jrx_mtag);
+		if (error) {
+			device_printf(dev,
+			    "could not allocate jumbo RX DMA tag\n");
+			return (error);
+		}
+	}
 	error = bus_dma_tag_create(sc->rl_parent_tag, sizeof(uint64_t), 0,
 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
 	    MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, &sc->rl_ldata.rl_rx_mtag);
@@ -1082,6 +1096,24 @@ re_allocmem(device_t dev, struct rl_soft
 
 	/* Create DMA maps for RX buffers */
 
+	if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
+		error = bus_dmamap_create(sc->rl_ldata.rl_jrx_mtag, 0,
+		    &sc->rl_ldata.rl_jrx_sparemap);
+		if (error) {
+			device_printf(dev,
+			    "could not create spare DMA map for jumbo RX\n");
+			return (error);
+		}
+		for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
+			error = bus_dmamap_create(sc->rl_ldata.rl_jrx_mtag, 0,
+			    &sc->rl_ldata.rl_jrx_desc[i].rx_dmamap);
+			if (error) {
+				device_printf(dev,
+				    "could not create DMA map for jumbo RX\n");
+				return (error);
+			}
+		}
+	}
 	error = bus_dmamap_create(sc->rl_ldata.rl_rx_mtag, 0,
 	    &sc->rl_ldata.rl_rx_sparemap);
 	if (error) {
@@ -1197,11 +1229,6 @@ re_attach(device_t dev)
 	msic = 0;
 	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
 		sc->rl_flags |= RL_FLAG_PCIE;
-		if (devid != RT_DEVICEID_8101E) {
-			/* Set PCIe maximum read request size to 2048. */
-			if (pci_get_max_read_req(dev) < 2048)
-				pci_set_max_read_req(dev, 2048);
-		}
 		msic = pci_msi_count(dev);
 		if (bootverbose)
 			device_printf(dev, "MSI count : %d\n", msic);
@@ -1276,7 +1303,7 @@ re_attach(device_t dev)
 	while (hw_rev->rl_desc != NULL) {
 		if (hw_rev->rl_rev == hwrev) {
 			sc->rl_type = hw_rev->rl_type;
-			sc->rl_hwrev = hw_rev->rl_rev;
+			sc->rl_hwrev = hw_rev;
 			break;
 		}
 		hw_rev++;
@@ -1289,26 +1316,23 @@ re_attach(device_t dev)
 
 	switch (hw_rev->rl_rev) {
 	case RL_HWREV_8139CPLUS:
-		sc->rl_flags |= RL_FLAG_NOJUMBO | RL_FLAG_FASTETHER |
-		    RL_FLAG_AUTOPAD;
+		sc->rl_flags |= RL_FLAG_FASTETHER | RL_FLAG_AUTOPAD;
 		break;
 	case RL_HWREV_8100E:
 	case RL_HWREV_8101E:
-		sc->rl_flags |= RL_FLAG_NOJUMBO | RL_FLAG_PHYWAKE |
-		    RL_FLAG_FASTETHER;
+		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_FASTETHER;
 		break;
 	case RL_HWREV_8102E:
 	case RL_HWREV_8102EL:
 	case RL_HWREV_8102EL_SPIN1:
-		sc->rl_flags |= RL_FLAG_NOJUMBO | RL_FLAG_PHYWAKE |
-		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
-		    RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD;
+		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR | RL_FLAG_DESCV2 |
+		    RL_FLAG_MACSTAT | RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP |
+		    RL_FLAG_AUTOPAD;
 		break;
 	case RL_HWREV_8103E:
-		sc->rl_flags |= RL_FLAG_NOJUMBO | RL_FLAG_PHYWAKE |
-		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
-		    RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD |
-		    RL_FLAG_MACSLEEP;
+		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR | RL_FLAG_DESCV2 |
+		    RL_FLAG_MACSTAT | RL_FLAG_FASTETHER | RL_FLAG_CMDSTOP |
+		    RL_FLAG_AUTOPAD | RL_FLAG_MACSLEEP;
 		break;
 	case RL_HWREV_8168_SPIN1:
 	case RL_HWREV_8168_SPIN2:
@@ -1329,28 +1353,17 @@ re_attach(device_t dev)
 	case RL_HWREV_8168DP:
 		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
 		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP |
-		    RL_FLAG_AUTOPAD;
-		/*
-		 * These controllers support jumbo frame but it seems
-		 * that enabling it requires touching additional magic
-		 * registers. Depending on MAC revisions some
-		 * controllers need to disable checksum offload. So
-		 * disable jumbo frame until I have better idea what
-		 * it really requires to make it support.
-		 * RTL8168C/CP : supports up to 6KB jumbo frame.
-		 * RTL8111C/CP : supports up to 9KB jumbo frame.
-		 */
-		sc->rl_flags |= RL_FLAG_NOJUMBO;
+		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2;
 		break;
 	case RL_HWREV_8168E:
 		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PHYWAKE_PM |
 		    RL_FLAG_PAR | RL_FLAG_DESCV2 | RL_FLAG_MACSTAT |
-		    RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD | RL_FLAG_NOJUMBO;
+		    RL_FLAG_CMDSTOP | RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2;
 		break;
 	case RL_HWREV_8168E_VL:
 		sc->rl_flags |= RL_FLAG_PHYWAKE | RL_FLAG_PAR |
 		    RL_FLAG_DESCV2 | RL_FLAG_MACSTAT | RL_FLAG_CMDSTOP |
-		    RL_FLAG_AUTOPAD | RL_FLAG_NOJUMBO;
+		    RL_FLAG_AUTOPAD | RL_FLAG_JUMBOV2;
 		break;
 	case RL_HWREV_8169_8110SB:
 	case RL_HWREV_8169_8110SBL:
@@ -1685,7 +1698,17 @@ re_detach(device_t dev)
 			    sc->rl_ldata.rl_rx_sparemap);
 		bus_dma_tag_destroy(sc->rl_ldata.rl_rx_mtag);
 	}
-
+	if (sc->rl_ldata.rl_jrx_mtag) {
+		for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
+			if (sc->rl_ldata.rl_jrx_desc[i].rx_dmamap)
+				bus_dmamap_destroy(sc->rl_ldata.rl_jrx_mtag,
+				    sc->rl_ldata.rl_jrx_desc[i].rx_dmamap);
+		}
+		if (sc->rl_ldata.rl_jrx_sparemap)
+			bus_dmamap_destroy(sc->rl_ldata.rl_jrx_mtag,
+			    sc->rl_ldata.rl_jrx_sparemap);
+		bus_dma_tag_destroy(sc->rl_ldata.rl_jrx_mtag);
+	}
 	/* Unload and free the stats buffer and map */
 
 	if (sc->rl_ldata.rl_stag) {
@@ -1713,7 +1736,11 @@ re_discard_rxbuf(struct rl_softc *sc, in
 	struct rl_rxdesc	*rxd;
 	uint32_t		cmdstat;
 
-	rxd = &sc->rl_ldata.rl_rx_desc[idx];
+	if (sc->rl_ifp->if_mtu > RL_MTU &&
+	    (sc->rl_flags & RL_FLAG_JUMBOV2) != 0)
+		rxd = &sc->rl_ldata.rl_jrx_desc[idx];
+	else
+		rxd = &sc->rl_ldata.rl_rx_desc[idx];
 	desc = &sc->rl_ldata.rl_rx_list[idx];
 	desc->rl_vlanctl = 0;
 	cmdstat = rxd->rx_size;
@@ -1786,6 +1813,59 @@ re_newbuf(struct rl_softc *sc, int idx)
 	return (0);
 }
 
+static int
+re_jumbo_newbuf(struct rl_softc *sc, int idx)
+{
+	struct mbuf		*m;
+	struct rl_rxdesc	*rxd;
+	bus_dma_segment_t	segs[1];
+	bus_dmamap_t		map;
+	struct rl_desc		*desc;
+	uint32_t		cmdstat;
+	int			error, nsegs;
+
+	m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
+	if (m == NULL)
+		return (ENOBUFS);
+	m->m_len = m->m_pkthdr.len = MJUM9BYTES;
+#ifdef RE_FIXUP_RX
+	m_adj(m, RE_ETHER_ALIGN);
+#endif
+	error = bus_dmamap_load_mbuf_sg(sc->rl_ldata.rl_jrx_mtag,
+	    sc->rl_ldata.rl_jrx_sparemap, m, segs, &nsegs, BUS_DMA_NOWAIT);
+	if (error != 0) {
+		m_freem(m);
+		return (ENOBUFS);
+	}
+	KASSERT(nsegs == 1, ("%s: %d segment returned!", __func__, nsegs));
+
+	rxd = &sc->rl_ldata.rl_jrx_desc[idx];
+	if (rxd->rx_m != NULL) {
+		bus_dmamap_sync(sc->rl_ldata.rl_jrx_mtag, rxd->rx_dmamap,
+		    BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->rl_ldata.rl_jrx_mtag, rxd->rx_dmamap);
+	}
+
+	rxd->rx_m = m;
+	map = rxd->rx_dmamap;
+	rxd->rx_dmamap = sc->rl_ldata.rl_jrx_sparemap;
+	rxd->rx_size = segs[0].ds_len;
+	sc->rl_ldata.rl_jrx_sparemap = map;
+	bus_dmamap_sync(sc->rl_ldata.rl_jrx_mtag, rxd->rx_dmamap,
+	    BUS_DMASYNC_PREREAD);
+
+	desc = &sc->rl_ldata.rl_rx_list[idx];
+	desc->rl_vlanctl = 0;
+	desc->rl_bufaddr_lo = htole32(RL_ADDR_LO(segs[0].ds_addr));
+	desc->rl_bufaddr_hi = htole32(RL_ADDR_HI(segs[0].ds_addr));
+	cmdstat = segs[0].ds_len;
+	if (idx == sc->rl_ldata.rl_rx_desc_cnt - 1)
+		cmdstat |= RL_RDESC_CMD_EOR;
+	desc->rl_cmdstat = htole32(cmdstat | RL_RDESC_CMD_OWN);
+
+	return (0);
+}
+
 #ifdef RE_FIXUP_RX
 static __inline void
 re_fixup_rx(struct mbuf *m)
@@ -1855,6 +1935,29 @@ re_rx_list_init(struct rl_softc *sc)
 	return (0);
 }
 
+static int
+re_jrx_list_init(struct rl_softc *sc)
+{
+	int			error, i;
+
+	bzero(sc->rl_ldata.rl_rx_list,
+	    sc->rl_ldata.rl_rx_desc_cnt * sizeof(struct rl_desc));
+	for (i = 0; i < sc->rl_ldata.rl_rx_desc_cnt; i++) {
+		sc->rl_ldata.rl_jrx_desc[i].rx_m = NULL;
+		if ((error = re_jumbo_newbuf(sc, i)) != 0)
+			return (error);
+	}
+
+	bus_dmamap_sync(sc->rl_ldata.rl_rx_list_tag,
+	    sc->rl_ldata.rl_rx_list_map,
+	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+	sc->rl_ldata.rl_rx_prodidx = 0;
+	sc->rl_head = sc->rl_tail = NULL;
+
+	return (0);
+}
+
 /*
  * RX handler for C+ and 8169. For the gigE chips, we support
  * the reception of jumbo frames that have been fragmented
@@ -1865,14 +1968,18 @@ re_rxeof(struct rl_softc *sc, int *rx_np
 {
 	struct mbuf		*m;
 	struct ifnet		*ifp;
-	int			i, total_len;
+	int			i, rxerr, total_len;
 	struct rl_desc		*cur_rx;
 	u_int32_t		rxstat, rxvlan;
-	int			maxpkt = 16, rx_npkts = 0;
+	int			jumbo, maxpkt = 16, rx_npkts = 0;
 
 	RL_LOCK_ASSERT(sc);
 
 	ifp = sc->rl_ifp;
+	if (ifp->if_mtu > RL_MTU && (sc->rl_flags & RL_FLAG_JUMBOV2) != 0)
+		jumbo = 1;
+	else
+		jumbo = 0;
 
 	/* Invalidate the descriptor memory */
 
@@ -1890,9 +1997,21 @@ re_rxeof(struct rl_softc *sc, int *rx_np
 			break;
 		total_len = rxstat & sc->rl_rxlenmask;
 		rxvlan = le32toh(cur_rx->rl_vlanctl);
-		m = sc->rl_ldata.rl_rx_desc[i].rx_m;
+		if (jumbo != 0)
+			m = sc->rl_ldata.rl_jrx_desc[i].rx_m;
+		else
+			m = sc->rl_ldata.rl_rx_desc[i].rx_m;
 
-		if (!(rxstat & RL_RDESC_STAT_EOF)) {
+		if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 &&
+		    (rxstat & (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) !=
+		    (RL_RDESC_STAT_SOF | RL_RDESC_STAT_EOF)) {
+			/*
+			 * RTL8168C or later controllers do not
+			 * support multi-fragment packet.
+			 */
+			re_discard_rxbuf(sc, i);
+			continue;
+		} else if ((rxstat & RL_RDESC_STAT_EOF) == 0) {
 			if (re_newbuf(sc, i) != 0) {
 				/*
 				 * If this is part of a multi-fragment packet,
@@ -1939,27 +2058,36 @@ re_rxeof(struct rl_softc *sc, int *rx_np
 		 * if total_len > 2^13-1, both _RXERRSUM and _GIANT will be
 		 * set, but if CRC is clear, it will still be a valid frame.
 		 */
-		if (rxstat & RL_RDESC_STAT_RXERRSUM && !(total_len > 8191 &&
-		    (rxstat & RL_RDESC_STAT_ERRS) == RL_RDESC_STAT_GIANT)) {
-			ifp->if_ierrors++;
-			/*
-			 * If this is part of a multi-fragment packet,
-			 * discard all the pieces.
-			 */
-			if (sc->rl_head != NULL) {
-				m_freem(sc->rl_head);
-				sc->rl_head = sc->rl_tail = NULL;
+		if ((rxstat & RL_RDESC_STAT_RXERRSUM) != 0) {
+			rxerr = 1;
+			if ((sc->rl_flags & RL_FLAG_JUMBOV2) == 0 &&
+			    total_len > 8191 &&
+			    (rxstat & RL_RDESC_STAT_ERRS) == RL_RDESC_STAT_GIANT)
+				rxerr = 0;
+			if (rxerr != 0) {
+				ifp->if_ierrors++;
+				/*
+				 * If this is part of a multi-fragment packet,
+				 * discard all the pieces.
+				 */
+				if (sc->rl_head != NULL) {
+					m_freem(sc->rl_head);
+					sc->rl_head = sc->rl_tail = NULL;
+				}
+				re_discard_rxbuf(sc, i);
+				continue;
 			}
-			re_discard_rxbuf(sc, i);
-			continue;
 		}
 
 		/*
 		 * If allocating a replacement mbuf fails,
 		 * reload the current one.
 		 */
-
-		if (re_newbuf(sc, i) != 0) {
+		if (jumbo != 0)
+			rxerr = re_jumbo_newbuf(sc, i);
+		else
+			rxerr = re_newbuf(sc, i);
+		if (rxerr != 0) {
 			ifp->if_iqdrops++;
 			if (sc->rl_head != NULL) {
 				m_freem(sc->rl_head);
@@ -1970,9 +2098,13 @@ re_rxeof(struct rl_softc *sc, int *rx_np
 		}
 
 		if (sc->rl_head != NULL) {
-			m->m_len = total_len % RE_RX_DESC_BUFLEN;
-			if (m->m_len == 0)
-				m->m_len = RE_RX_DESC_BUFLEN;
+			if (jumbo != 0)
+				m->m_len = total_len;
+			else {
+				m->m_len = total_len % RE_RX_DESC_BUFLEN;
+				if (m->m_len == 0)
+					m->m_len = RE_RX_DESC_BUFLEN;
+			}
 			/*
 			 * Special case: if there's 4 bytes or less
 			 * in this buffer, the mbuf can be discarded:
@@ -2589,6 +2721,59 @@ re_start(struct ifnet *ifp)
 }
 
 static void
+re_set_jumbo(struct rl_softc *sc, int jumbo)
+{
+
+	if (sc->rl_hwrev->rl_rev == RL_HWREV_8168E_VL) {
+		pci_set_max_read_req(sc->rl_dev, 4096);
+		return;
+	}
+
+	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG);
+	if (jumbo != 0) {
+		CSR_WRITE_1(sc, RL_CFG3, CSR_READ_1(sc, RL_CFG3) |
+		    RL_CFG3_JUMBO_EN0);
+		switch (sc->rl_hwrev->rl_rev) {
+		case RL_HWREV_8168DP:
+			break;
+		case RL_HWREV_8168E:
+			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) |
+			    0x01);
+			break;
+		default:
+			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) |
+			    RL_CFG4_JUMBO_EN1);
+		}
+	} else {
+		CSR_WRITE_1(sc, RL_CFG3, CSR_READ_1(sc, RL_CFG3) &
+		    ~RL_CFG3_JUMBO_EN0);
+		switch (sc->rl_hwrev->rl_rev) {
+		case RL_HWREV_8168DP:
+			break;
+		case RL_HWREV_8168E:
+			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) &
+			    ~0x01);
+			break;
+		default:
+			CSR_WRITE_1(sc, RL_CFG4, CSR_READ_1(sc, RL_CFG4) &
+			    ~RL_CFG4_JUMBO_EN1);
+		}
+	}
+	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+
+	switch (sc->rl_hwrev->rl_rev) {
+	case RL_HWREV_8168DP:
+		pci_set_max_read_req(sc->rl_dev, 4096);
+		break;
+	default:
+		if (jumbo != 0)
+			pci_set_max_read_req(sc->rl_dev, 512);
+		else
+			pci_set_max_read_req(sc->rl_dev, 4096);
+	}
+}
+
+static void
 re_init(void *xsc)
 {
 	struct rl_softc		*sc = xsc;
@@ -2628,10 +2813,39 @@ re_init_locked(struct rl_softc *sc)
 	/*
 	 * For C+ mode, initialize the RX descriptors and mbufs.
 	 */
-	if (re_rx_list_init(sc) != 0) {
-		device_printf(sc->rl_dev, "no memory for RX buffers\n");
-		re_stop(sc);
-		return;
+	if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
+		if (ifp->if_mtu > RL_MTU) {
+			if (re_jrx_list_init(sc) != 0) {
+				device_printf(sc->rl_dev,
+				    "no memory for jumbo RX buffers\n");
+				re_stop(sc);
+				return;
+			}
+			/* Disable checksum offloading for jumbo frames. */
+			ifp->if_capenable &= ~(IFCAP_HWCSUM | IFCAP_TSO4);
+			ifp->if_hwassist &= ~(RE_CSUM_FEATURES | CSUM_TSO);
+		} else {
+			if (re_rx_list_init(sc) != 0) {
+				device_printf(sc->rl_dev,
+				    "no memory for RX buffers\n");
+				re_stop(sc);
+				return;
+			}
+		}
+		re_set_jumbo(sc, ifp->if_mtu > RL_MTU);
+	} else {
+		if (re_rx_list_init(sc) != 0) {
+			device_printf(sc->rl_dev, "no memory for RX buffers\n");
+			re_stop(sc);
+			return;
+		}
+		if ((sc->rl_flags & RL_FLAG_PCIE) != 0 &&
+		    pci_get_device(sc->rl_dev) != RT_DEVICEID_8101E) {
+			if (ifp->if_mtu > RL_MTU)
+				pci_set_max_read_req(sc->rl_dev, 512);
+			else
+				pci_set_max_read_req(sc->rl_dev, 4096);
+		}
 	}
 	re_tx_list_init(sc);
 
@@ -2652,12 +2866,12 @@ re_init_locked(struct rl_softc *sc)
 	} else
 		cfg |= RL_CPLUSCMD_RXENB | RL_CPLUSCMD_TXENB;
 	CSR_WRITE_2(sc, RL_CPLUS_CMD, cfg);
-	if (sc->rl_hwrev == RL_HWREV_8169_8110SC ||
-	    sc->rl_hwrev == RL_HWREV_8169_8110SCE) {
+	if (sc->rl_hwrev->rl_rev == RL_HWREV_8169_8110SC ||
+	    sc->rl_hwrev->rl_rev == RL_HWREV_8169_8110SCE) {
 		reg = 0x000fff00;
 		if ((CSR_READ_1(sc, RL_CFG2) & RL_CFG2_PCI66MHZ) != 0)
 			reg |= 0x000000ff;
-		if (sc->rl_hwrev == RL_HWREV_8169_8110SCE)
+		if (sc->rl_hwrev->rl_rev == RL_HWREV_8169_8110SCE)
 			reg |= 0x00f00000;
 		CSR_WRITE_4(sc, 0x7c, reg);
 		/* Disable interrupt mitigation. */
@@ -2727,7 +2941,7 @@ re_init_locked(struct rl_softc *sc)
 
 	/* Configure interrupt moderation. */
 	if (sc->rl_type == RL_8169) {
-		switch (sc->rl_hwrev) {
+		switch (sc->rl_hwrev->rl_rev) {
 		case RL_HWREV_8100E:
 		case RL_HWREV_8101E:
 		case RL_HWREV_8102E:
@@ -2790,10 +3004,25 @@ re_init_locked(struct rl_softc *sc)
 	 * size so we can receive jumbo frames.
 	 */
 	if (sc->rl_type == RL_8169) {
-		if ((sc->rl_flags & (RL_FLAG_PCIE | RL_FLAG_NOJUMBO)) ==
-		    (RL_FLAG_PCIE | RL_FLAG_NOJUMBO))
+		if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
+			/*
+			 * For controllers that use new jumbo frame scheme,
+			 * set maximum size of jumbo frame depedning on
+			 * controller revisions.
+			 */
+			if (ifp->if_mtu > RL_MTU)
+				CSR_WRITE_2(sc, RL_MAXRXPKTLEN,
+				    sc->rl_hwrev->rl_max_mtu +
+				    ETHER_VLAN_ENCAP_LEN + ETHER_HDR_LEN +
+				    ETHER_CRC_LEN);
+			else
+				CSR_WRITE_2(sc, RL_MAXRXPKTLEN,
+				    RE_RX_DESC_BUFLEN);
+		} else if ((sc->rl_flags & RL_FLAG_PCIE) != 0 &&
+		    sc->rl_hwrev->rl_max_mtu == RL_MTU) {
+			/* RTL810x has no jumbo frame support. */
 			CSR_WRITE_2(sc, RL_MAXRXPKTLEN, RE_RX_DESC_BUFLEN);
-		else
+		} else
 			CSR_WRITE_2(sc, RL_MAXRXPKTLEN, 16383);
 	}
 
@@ -2860,22 +3089,25 @@ re_ioctl(struct ifnet *ifp, u_long comma
 
 	switch (command) {
 	case SIOCSIFMTU:
-		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > RL_JUMBO_MTU) {
-			error = EINVAL;
-			break;
-		}
-		if ((sc->rl_flags & RL_FLAG_NOJUMBO) != 0 &&
-		    ifr->ifr_mtu > RL_MAX_FRAMELEN) {
+		if (ifr->ifr_mtu < ETHERMIN ||
+		    ifr->ifr_mtu > sc->rl_hwrev->rl_max_mtu) {
 			error = EINVAL;
 			break;
 		}
 		RL_LOCK(sc);
-		if (ifp->if_mtu != ifr->ifr_mtu)
+		if (ifp->if_mtu != ifr->ifr_mtu) {
 			ifp->if_mtu = ifr->ifr_mtu;
-		if (ifp->if_mtu > RL_TSO_MTU &&
-		    (ifp->if_capenable & IFCAP_TSO4) != 0) {
-			ifp->if_capenable &= ~IFCAP_TSO4;
-			ifp->if_hwassist &= ~CSUM_TSO;
+			if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 &&
+			    (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
+				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+				re_init_locked(sc);
+			}
+			if (ifp->if_mtu > RL_TSO_MTU &&
+			    (ifp->if_capenable & IFCAP_TSO4) != 0) {
+				ifp->if_capenable &= ~(IFCAP_TSO4 |
+				    IFCAP_VLAN_HWTSO);
+				ifp->if_hwassist &= ~CSUM_TSO;
+			}
 			VLAN_CAPABILITIES(ifp);
 		}
 		RL_UNLOCK(sc);
@@ -2973,6 +3205,10 @@ re_ioctl(struct ifnet *ifp, u_long comma
 				ifp->if_capenable &= ~IFCAP_VLAN_HWTSO;
 			reinit = 1;
 		}
+		if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0 &&
+		    (mask & (IFCAP_HWCSUM | IFCAP_TSO4 |
+		    IFCAP_VLAN_HWTSO)) != 0)
+				reinit = 1;
 		if ((mask & IFCAP_WOL) != 0 &&
 		    (ifp->if_capabilities & IFCAP_WOL) != 0) {
 			if ((mask & IFCAP_WOL_UCAST) != 0)

Modified: stable/8/sys/pci/if_rlreg.h
==============================================================================
--- stable/8/sys/pci/if_rlreg.h	Mon Feb 21 01:05:23 2011	(r218902)
+++ stable/8/sys/pci/if_rlreg.h	Mon Feb 21 01:08:13 2011	(r218903)
@@ -429,6 +429,7 @@
 #define	RL_CFG3_GRANTSEL	0x80
 #define	RL_CFG3_WOL_MAGIC	0x20
 #define	RL_CFG3_WOL_LINK	0x10
+#define	RL_CFG3_JUMBO_EN0	0x04	/* RTL8168C or later. */
 #define	RL_CFG3_FAST_B2B	0x01
 
 /*
@@ -436,6 +437,7 @@
  */
 #define	RL_CFG4_LWPTN		0x04
 #define	RL_CFG4_LWPME		0x10
+#define	RL_CFG4_JUMBO_EN1	0x02	/* RTL8168C or later. */
 
 /*
  * Config 5 register
@@ -592,6 +594,7 @@ struct rl_hwrev {
 	uint32_t		rl_rev;
 	int			rl_type;
 	char			*rl_desc;
+	int			rl_max_mtu;
 };
 
 struct rl_mii_frame {
@@ -767,6 +770,7 @@ struct rl_stats {
 #define	RL_8139_RX_DESC_CNT	64
 #define	RL_TX_DESC_CNT		RL_8169_TX_DESC_CNT
 #define	RL_RX_DESC_CNT		RL_8169_RX_DESC_CNT
+#define	RL_RX_JUMBO_DESC_CNT	RL_RX_DESC_CNT
 #define	RL_NTXSEGS		32
 
 #define	RL_RING_ALIGN		256
@@ -801,8 +805,13 @@ struct rl_stats {
 
 /* see comment in dev/re/if_re.c */
 #define	RL_JUMBO_FRAMELEN	7440
-#define	RL_JUMBO_MTU		(RL_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
-#define	RL_MAX_FRAMELEN		\
+#define	RL_JUMBO_MTU		\
+	(RL_JUMBO_FRAMELEN-ETHER_VLAN_ENCAP_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define	RL_JUMBO_MTU_6K		\
+	((6 * 1024) - ETHER_VLAN_ENCAP_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
+#define	RL_JUMBO_MTU_9K		\
+	((9 * 1024) - ETHER_VLAN_ENCAP_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
+#define	RL_MTU			\
 	(ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
 
 struct rl_txdesc {
@@ -819,6 +828,7 @@ struct rl_rxdesc {
 struct rl_list_data {
 	struct rl_txdesc	rl_tx_desc[RL_TX_DESC_CNT];
 	struct rl_rxdesc	rl_rx_desc[RL_RX_DESC_CNT];
+	struct rl_rxdesc	rl_jrx_desc[RL_RX_JUMBO_DESC_CNT];
 	int			rl_tx_desc_cnt;
 	int			rl_rx_desc_cnt;
 	int			rl_tx_prodidx;
@@ -827,7 +837,9 @@ struct rl_list_data {
 	int			rl_tx_free;
 	bus_dma_tag_t		rl_tx_mtag;	/* mbuf TX mapping tag */
 	bus_dma_tag_t		rl_rx_mtag;	/* mbuf RX mapping tag */
+	bus_dma_tag_t		rl_jrx_mtag;	/* mbuf RX mapping tag */
 	bus_dmamap_t		rl_rx_sparemap;
+	bus_dmamap_t		rl_jrx_sparemap;
 	bus_dma_tag_t		rl_stag;	/* stats mapping tag */
 	bus_dmamap_t		rl_smap;	/* stats map */
 	struct rl_stats		*rl_stats;
@@ -857,9 +869,9 @@ struct rl_softc {
 	device_t		rl_miibus;
 	bus_dma_tag_t		rl_parent_tag;
 	uint8_t			rl_type;
+	struct rl_hwrev		*rl_hwrev;
 	int			rl_eecmd_read;
 	int			rl_eewidth;
-	uint8_t			rl_stats_no_timeout;
 	int			rl_txthresh;
 	struct rl_chain_data	rl_cdata;
 	struct rl_list_data	rl_ldata;
@@ -868,7 +880,6 @@ struct rl_softc {
 	struct mtx		rl_mtx;
 	struct mbuf		*rl_head;
 	struct mbuf		*rl_tail;
-	uint32_t		rl_hwrev;
 	uint32_t		rl_rxlenmask;
 	int			rl_testmode;
 	int			rl_if_flags;
@@ -890,7 +901,7 @@ struct rl_softc {
 #define	RL_FLAG_AUTOPAD		0x0002
 #define	RL_FLAG_PHYWAKE_PM	0x0004
 #define	RL_FLAG_PHYWAKE		0x0008
-#define	RL_FLAG_NOJUMBO		0x0010
+#define	RL_FLAG_JUMBOV2		0x0010
 #define	RL_FLAG_PAR		0x0020
 #define	RL_FLAG_DESCV2		0x0040
 #define	RL_FLAG_MACSTAT		0x0080



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201102210108.p1L18DUG050924>