Add support for jumbo frames.
authorvisa <visa@openbsd.org>
Thu, 4 Aug 2016 13:10:31 +0000 (13:10 +0000)
committervisa <visa@openbsd.org>
Thu, 4 Aug 2016 13:10:31 +0000 (13:10 +0000)
sys/arch/octeon/dev/cn30xxgmx.c
sys/arch/octeon/dev/if_cnmac.c
sys/arch/octeon/dev/if_cnmacvar.h

index cb8c66c..ba4beb2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cn30xxgmx.c,v 1.25 2016/06/22 13:09:35 visa Exp $     */
+/*     $OpenBSD: cn30xxgmx.c,v 1.26 2016/08/04 13:10:31 visa Exp $     */
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -571,13 +571,12 @@ int
 cn30xxgmx_rx_frm_ctl_enable(struct cn30xxgmx_port_softc *sc,
     uint64_t rx_frm_ctl)
 {
-       /*
-        * XXX Jumbo-frame Workarounds
-        *     Current implementation of cnmac is required to
-        *     configure GMX0_RX0_JABBER[CNT] as follows:
-        *      RX0_FRM_MAX(1536) <= GMX0_RX0_JABBER <= 1536(0x600)
-        */
-       _GMX_PORT_WR8(sc, GMX0_RX0_JABBER, GMX_FRM_MAX_SIZ);
+       struct ifnet *ifp = &sc->sc_port_ac->ac_if;
+       unsigned int maxlen;
+
+       maxlen = roundup(ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
+           ETHER_VLAN_ENCAP_LEN, 8);
+       _GMX_PORT_WR8(sc, GMX0_RX0_JABBER, maxlen);
 
        return cn30xxgmx_rx_frm_ctl_xable(sc, rx_frm_ctl, 1);
 }
index 74a6649..66544ca 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_cnmac.c,v 1.54 2016/07/30 09:45:09 visa Exp $      */
+/*     $OpenBSD: if_cnmac.c,v 1.55 2016/08/04 13:10:31 visa Exp $      */
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -310,6 +310,7 @@ octeon_eth_attach(struct device *parent, struct device *self, void *aux)
        ifp->if_ioctl = octeon_eth_ioctl;
        ifp->if_start = octeon_eth_start;
        ifp->if_watchdog = octeon_eth_watchdog;
+       ifp->if_hardmtu = OCTEON_ETH_MAX_MTU;
        IFQ_SET_MAXLEN(&ifp->if_snd, max(GATHER_QUEUE_SIZE, IFQ_MAXLEN));
 
        ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_TCPv4 |
@@ -627,17 +628,25 @@ int
 octeon_eth_buf_free_work(struct octeon_eth_softc *sc, uint64_t *work)
 {
        paddr_t addr, pktbuf;
-       unsigned int back;
-
-       if (ISSET(work[2], PIP_WQE_WORD2_IP_BUFS)) {
-               addr = work[3] & PIP_WQE_WORD3_ADDR, CCA_CACHED;
-               back = (work[3] & PIP_WQE_WORD3_BACK) >>
+       uint64_t word3;
+       unsigned int back, nbufs;
+
+       nbufs = (work[2] & PIP_WQE_WORD2_IP_BUFS) >>
+           PIP_WQE_WORD2_IP_BUFS_SHIFT;
+       word3 = work[3];
+       while (nbufs-- > 0) {
+               addr = word3 & PIP_WQE_WORD3_ADDR, CCA_CACHED;
+               back = (word3 & PIP_WQE_WORD3_BACK) >>
                    PIP_WQE_WORD3_BACK_SHIFT;
                pktbuf = (addr & ~(CACHE_LINE_SIZE - 1)) -
                    back * CACHE_LINE_SIZE;
 
                cn30xxfpa_store(pktbuf, OCTEON_POOL_NO_PKT,
                    OCTEON_POOL_SIZE_PKT / CACHE_LINE_SIZE);
+
+               if (nbufs > 0)
+                       memcpy(&word3, (void *)PHYS_TO_XKPHYS(addr -
+                           sizeof(word3), CCA_CACHED), sizeof(word3));
        }
 
        cn30xxfpa_buf_put_paddr(octeon_eth_fb_wqe, XKPHYS_TO_PHYS(work));
@@ -1153,36 +1162,67 @@ int
 octeon_eth_recv_mbuf(struct octeon_eth_softc *sc, uint64_t *work,
     struct mbuf **rm, int *nmbuf)
 {
-       struct mbuf *m, **pm;
+       struct mbuf *m, *m0, *mprev, **pm;
        paddr_t addr, pktbuf;
        uint64_t word1 = work[1];
        uint64_t word2 = work[2];
        uint64_t word3 = work[3];
-       unsigned int back;
+       unsigned int back, i, nbufs;
+       unsigned int left, total, size;
 
        cn30xxfpa_buf_put_paddr(octeon_eth_fb_wqe, XKPHYS_TO_PHYS(work));
 
-       if ((word2 >> PIP_WQE_WORD2_IP_BUFS_SHIFT) != 1)
-               panic("%s: expected one buffer, got %llu", __func__,
-                   word2 >> PIP_WQE_WORD2_IP_BUFS_SHIFT);
-
-       addr = word3 & PIP_WQE_WORD3_ADDR;
-       back = (word3 & PIP_WQE_WORD3_BACK) >> PIP_WQE_WORD3_BACK_SHIFT;
-       pktbuf = (addr & ~(CACHE_LINE_SIZE - 1)) - back * CACHE_LINE_SIZE;
-       pm = (struct mbuf **)PHYS_TO_XKPHYS(pktbuf, CCA_CACHED) - 1;
-       m = *pm;
-       *pm = NULL;
-       if ((paddr_t)m->m_pkthdr.ph_cookie != pktbuf)
-               panic("%s: packet pool is corrupted, mbuf cookie %p != "
-                   "pktbuf %p", __func__, m->m_pkthdr.ph_cookie,
-                   (void *)pktbuf);
-
-       m->m_pkthdr.ph_cookie = NULL;
-       m->m_data += addr - pktbuf;
-       m->m_len = m->m_pkthdr.len = (word1 & PIP_WQE_WORD1_LEN) >> 48;
+       nbufs = (word2 & PIP_WQE_WORD2_IP_BUFS) >> PIP_WQE_WORD2_IP_BUFS_SHIFT;
+       if (nbufs == 0)
+               panic("%s: dynamic short packet", __func__);
 
-       *rm = m;
-       *nmbuf = 1;
+       m0 = mprev = NULL;
+       total = left = (word1 & PIP_WQE_WORD1_LEN) >> 48;
+       for (i = 0; i < nbufs; i++) {
+               addr = word3 & PIP_WQE_WORD3_ADDR;
+               back = (word3 & PIP_WQE_WORD3_BACK) >> PIP_WQE_WORD3_BACK_SHIFT;
+               pktbuf = (addr & ~(CACHE_LINE_SIZE - 1)) -
+                   back * CACHE_LINE_SIZE;
+               pm = (struct mbuf **)PHYS_TO_XKPHYS(pktbuf, CCA_CACHED) - 1;
+               m = *pm;
+               *pm = NULL;
+               if ((paddr_t)m->m_pkthdr.ph_cookie != pktbuf)
+                       panic("%s: packet pool is corrupted, mbuf cookie %p != "
+                           "pktbuf %p", __func__, m->m_pkthdr.ph_cookie,
+                           (void *)pktbuf);
+
+               /*
+                * Because of a hardware bug in some Octeon models the size
+                * field of word3 can be wrong. However, the hardware uses
+                * all space in a buffer before moving to the next one so
+                * it is possible to derive the size of this data segment
+                * from the size of packet data buffers.
+                */
+               size = OCTEON_POOL_SIZE_PKT - (addr - pktbuf);
+               if (size > left)
+                       size = left;
+
+               m->m_pkthdr.ph_cookie = NULL;
+               m->m_data += addr - pktbuf;
+               m->m_len = size;
+               left -= size;
+
+               if (m0 == NULL)
+                       m0 = m;
+               else {
+                       m->m_flags &= ~M_PKTHDR;
+                       mprev->m_next = m;
+               }
+               mprev = m;
+
+               if (i + 1 < nbufs)
+                       memcpy(&word3, (void *)PHYS_TO_XKPHYS(addr -
+                           sizeof(word3), CCA_CACHED), sizeof(word3));
+       }
+
+       m0->m_pkthdr.len = total;
+       *rm = m0;
+       *nmbuf = nbufs;
 
        return 0;
 }
index ccdc40d..322a4b4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_cnmacvar.h,v 1.13 2016/07/30 09:45:09 visa Exp $   */
+/*     $OpenBSD: if_cnmacvar.h,v 1.14 2016/08/04 13:10:31 visa Exp $   */
 
 /*
  * Copyright (c) 2007 Internet Initiative Japan, Inc.
@@ -34,6 +34,8 @@
 #define FREE_QUEUE_SIZE                GATHER_QUEUE_SIZE
 #define RECV_QUEUE_SIZE                (GATHER_QUEUE_SIZE * 2)
 
+#define OCTEON_ETH_MAX_MTU             12288
+
 /* Number of mbufs per port to keep in the packet pool */
 #define OCTEON_ETH_MBUFS_PER_PORT      256