hi all,

the below diff enables support for jumbo frames on
some newer re(4) devices. i've tested it on 8186D/8111D
and 8186E/8111E chips, which are both able to do 9k
jumbos. it seems to provide a significant speed-up on
simple file transfer tests. most of the important parts
were taken from the freebsd re(4) driver.

feedback welcome, hope this helps someone.

cheers,
jim

Index: re.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/re.c,v
retrieving revision 1.173
diff -u -r1.173 re.c
--- re.c        21 Jan 2015 10:00:42 -0000      1.173
+++ re.c        21 Jan 2015 11:10:31 -0000
@@ -171,6 +171,8 @@
 int    re_ifmedia_upd(struct ifnet *);
 void   re_ifmedia_sts(struct ifnet *, struct ifmediareq *);
 
+void   re_set_jumbo(struct rl_softc *);
+
 void   re_eeprom_putbyte(struct rl_softc *, int);
 void   re_eeprom_getword(struct rl_softc *, int, u_int16_t *);
 void   re_read_eeprom(struct rl_softc *, caddr_t, int, int);
@@ -206,6 +208,10 @@
        CSR_WRITE_1(sc, RL_EECMD,                       \
                CSR_READ_1(sc, RL_EECMD) & ~x)
 
+#define RL_FRAMELEN(mtu)                               \
+       (mtu + ETHER_HDR_LEN + ETHER_CRC_LEN +          \
+               ETHER_VLAN_ENCAP_LEN)
+
 static const struct re_revision {
        u_int32_t               re_chipid;
        const char              *re_name;
@@ -1022,8 +1028,10 @@
 
        /* Create DMA maps for RX buffers */
        for (i = 0; i < RL_RX_DESC_CNT; i++) {
-               error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
-                   0, 0, &sc->rl_ldata.rl_rxsoft[i].rxs_dmamap);
+               error = bus_dmamap_create(sc->sc_dmat,
+                   RL_FRAMELEN(sc->rl_max_mtu), 1,
+                   RL_FRAMELEN(sc->rl_max_mtu), 0, 0,
+                   &sc->rl_ldata.rl_rxsoft[i].rxs_dmamap);
                if (error) {
                        printf("%s: can't create DMA map for RX\n",
                            sc->sc_dev.dv_xname);
@@ -1038,8 +1046,7 @@
        ifp->if_ioctl = re_ioctl;
        ifp->if_start = re_start;
        ifp->if_watchdog = re_watchdog;
-       if ((sc->rl_flags & RL_FLAG_JUMBOV2) == 0)
-               ifp->if_hardmtu = sc->rl_max_mtu;
+       ifp->if_hardmtu = sc->rl_max_mtu;
        IFQ_SET_MAXLEN(&ifp->if_snd, RL_TX_QLEN);
        IFQ_SET_READY(&ifp->if_snd);
 
@@ -1159,7 +1166,7 @@
        u_int32_t       cmdstat;
        int             error, idx;
 
-       m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES);
+       m = MCLGETI(NULL, M_DONTWAIT, NULL, RL_FRAMELEN(sc->rl_max_mtu));
        if (!m)
                return (ENOBUFS);
 
@@ -1168,7 +1175,7 @@
         * alignment so that the frame payload is
         * longword aligned on strict alignment archs.
         */
-       m->m_len = m->m_pkthdr.len = RE_RX_DESC_BUFLEN;
+       m->m_len = m->m_pkthdr.len = RL_FRAMELEN(sc->rl_max_mtu);
        m->m_data += RE_ETHER_ALIGN;
 
        idx = sc->rl_ldata.rl_rx_prodidx;
@@ -1274,7 +1281,7 @@
 {
        struct mbuf     *m;
        struct ifnet    *ifp;
-       int             i, total_len, rx = 0;
+       int             i, total_len, rxerr, rx = 0;
        struct rl_desc  *cur_rx;
        struct rl_rxsoft *rxs;
        u_int32_t       rxstat, rxvlan;
@@ -1306,8 +1313,12 @@
                    BUS_DMASYNC_POSTREAD);
                bus_dmamap_unload(sc->sc_dmat, rxs->rxs_dmamap);
 
-               if (!(rxstat & RL_RDESC_STAT_EOF)) {
-                       m->m_len = RE_RX_DESC_BUFLEN;
+               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)) {
+                       continue;
+               } else if (!(rxstat & RL_RDESC_STAT_EOF)) {
+                       m->m_len = RL_FRAMELEN(sc->rl_max_mtu);
                        if (sc->rl_head == NULL)
                                sc->rl_head = sc->rl_tail = m;
                        else {
@@ -1341,24 +1352,31 @@
                 * 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 (rxstat & RL_RDESC_STAT_RXERRSUM && !(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;
+                               }
+                               continue;
                        }
-                       continue;
                }
 
                if (sc->rl_head != NULL) {
-                       m->m_len = total_len % RE_RX_DESC_BUFLEN;
+                       m->m_len = total_len % RL_FRAMELEN(sc->rl_max_mtu);
                        if (m->m_len == 0)
-                               m->m_len = RE_RX_DESC_BUFLEN;
+                               m->m_len = RL_FRAMELEN(sc->rl_max_mtu);
                        /* 
                         * Special case: if there's 4 bytes or less
                         * in this buffer, the mbuf can be discarded:
@@ -1916,6 +1934,11 @@
            htole32(*(u_int32_t *)(&eaddr.eaddr[0])));
        CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
 
+       if ((sc->rl_flags & RL_FLAG_JUMBOV2) != 0) {
+               ifp->if_capabilities &= ~(IFCAP_CSUM_IPv4);
+               re_set_jumbo(sc);
+       }
+
        /*
         * For C+ mode, initialize the RX descriptors and mbufs.
         */
@@ -1979,7 +2002,7 @@
         * size so we can receive jumbo frames.
         */
        if (sc->sc_hwrev != RL_HWREV_8139CPLUS) {
-               if (sc->rl_flags & RL_FLAG_PCIE)
+               if (sc->rl_flags & RL_FLAG_PCIE && (sc->rl_flags & 
RL_FLAG_JUMBOV2) == 0)
                        CSR_WRITE_2(sc, RL_MAXRXPKTLEN, RE_RX_DESC_BUFLEN);
                else
                        CSR_WRITE_2(sc, RL_MAXRXPKTLEN, 16383);
@@ -2064,7 +2087,7 @@
                break;
        case SIOCGIFRXR:
                error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data,
-                   NULL, MCLBYTES, &sc->rl_ldata.rl_rx_ring);
+                   NULL, RL_FRAMELEN(sc->rl_max_mtu), 
&sc->rl_ldata.rl_rx_ring);
                break;
        default:
                error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
@@ -2282,6 +2305,26 @@
                panic("%s: unknown imtype %d",
                      sc->sc_dev.dv_xname, imtype);
        }
+}
+
+void
+re_set_jumbo(struct rl_softc *sc)
+{
+       CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_WRITECFG);
+       CSR_WRITE_1(sc, RL_CFG3, CSR_READ_1(sc, RL_CFG3) |
+               RL_CFG3_JUMBO_EN0);
+       switch (sc->sc_hwrev) {
+       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);
+               break;
+       }
+       CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
+       
 }
 
 void
Index: rtl81x9reg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtl81x9reg.h,v
retrieving revision 1.90
diff -u -r1.90 rtl81x9reg.h
--- rtl81x9reg.h        20 Jan 2015 04:33:06 -0000      1.90
+++ rtl81x9reg.h        21 Jan 2015 11:10:31 -0000
@@ -442,6 +442,7 @@
 #define RL_CFG3_GRANTSEL       0x80
 #define RL_CFG3_WOL_MAGIC      0x20
 #define RL_CFG3_WOL_LINK       0x10
+#define RL_CFG3_JUMBO_EN0      0x04
 #define RL_CFG3_FAST_B2B       0x01
 
 /*
@@ -449,6 +450,7 @@
  */
 #define RL_CFG4_LWPTN          0x04
 #define RL_CFG4_LWPME          0x10
+#define RL_CFG4_JUMBO_EN1      0x02
 
 /*
  * Config 5 register
@@ -742,8 +744,7 @@
 #define RL_ADDR_LO(y)  ((u_int64_t) (y) & 0xFFFFFFFF)
 #define RL_ADDR_HI(y)  ((u_int64_t) (y) >> 32)
 
-/* see comment in dev/ic/re.c */
-#define RL_JUMBO_FRAMELEN      7440
+#define RL_JUMBO_FRAMELEN      (9 * 1024)      
 #define RL_JUMBO_MTU_4K                \
        ((4 * 1024) - ETHER_HDR_LEN - ETHER_CRC_LEN - ETHER_VLAN_ENCAP_LEN)
 #define RL_JUMBO_MTU_6K                \

Reply via email to