Author: adrian
Date: Sat May  6 06:06:11 2017
New Revision: 317868
URL: https://svnweb.freebsd.org/changeset/base/317868

Log:
  [ar531x] [if_are] Fix if_are behaviour under high load traffic
  
  * use ifqmaxlen
  * handle (inefficiently for now) meeting padding and alignment requirements 
for
    transmit mbufs.
  * change how TX ring handling is done
  
  Submitted by: Hiroki Mori <yamori...@yahoo.co.jp>
  Differential Revision:        https://reviews.freebsd.org/D10557

Modified:
  head/sys/mips/atheros/ar531x/if_are.c
  head/sys/mips/atheros/ar531x/if_arereg.h

Modified: head/sys/mips/atheros/ar531x/if_are.c
==============================================================================
--- head/sys/mips/atheros/ar531x/if_are.c       Sat May  6 06:01:17 2017        
(r317867)
+++ head/sys/mips/atheros/ar531x/if_are.c       Sat May  6 06:06:11 2017        
(r317868)
@@ -302,9 +302,9 @@ are_attach(device_t dev)
        ifp->if_init = are_init;
        sc->are_if_flags = ifp->if_flags;
 
-       /* XXX: add real size */
-       IFQ_SET_MAXLEN(&ifp->if_snd, 9);
-       ifp->if_snd.ifq_maxlen = 9;
+       /* ifqmaxlen is sysctl value in net/if.c */
+       IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
+       ifp->if_snd.ifq_maxlen = ifqmaxlen;
        IFQ_SET_READY(&ifp->if_snd);
 
        /* Tell the upper layer(s) we support long frames. */
@@ -686,19 +686,92 @@ are_encap(struct are_softc *sc, struct m
 {
        struct are_txdesc       *txd;
        struct are_desc         *desc, *prev_desc;
+       struct mbuf             *m;
        bus_dma_segment_t       txsegs[ARE_MAXFRAGS];
        uint32_t                link_addr;
        int                     error, i, nsegs, prod, si, prev_prod;
        int                     txstat;
+       int                     startcount;
+       int                     padlen;
+
+       startcount = sc->are_cdata.are_tx_cnt;
 
        ARE_LOCK_ASSERT(sc);
 
+       /*
+        * Some VIA Rhine wants packet buffers to be longword
+        * aligned, but very often our mbufs aren't. Rather than
+        * waste time trying to decide when to copy and when not
+        * to copy, just do it all the time.
+        */
+       m = m_defrag(*m_head, M_NOWAIT);
+       if (m == NULL) {
+               device_printf(sc->are_dev, "are_encap m_defrag error\n");
+               m_freem(*m_head);
+               *m_head = NULL;
+               return (ENOBUFS);
+       }
+       *m_head = m;
+
+       /*
+        * The Rhine chip doesn't auto-pad, so we have to make
+        * sure to pad short frames out to the minimum frame length
+        * ourselves.
+        */
+       if ((*m_head)->m_pkthdr.len < ARE_MIN_FRAMELEN) {
+               m = *m_head;
+               padlen = ARE_MIN_FRAMELEN - m->m_pkthdr.len;
+               if (M_WRITABLE(m) == 0) {
+                       /* Get a writable copy. */
+                       m = m_dup(*m_head, M_NOWAIT);
+                       m_freem(*m_head);
+                       if (m == NULL) {
+                               device_printf(sc->are_dev, "are_encap m_dup 
error\n");
+                               *m_head = NULL;
+                               return (ENOBUFS);
+                       }
+                       *m_head = m;
+               }
+               if (m->m_next != NULL || M_TRAILINGSPACE(m) < padlen) {
+                       m = m_defrag(m, M_NOWAIT);
+                       if (m == NULL) {
+                               device_printf(sc->are_dev, "are_encap m_defrag 
error\n");
+                               m_freem(*m_head);
+                               *m_head = NULL;
+                               return (ENOBUFS);
+                       }
+               }
+               /*
+                * Manually pad short frames, and zero the pad space
+                * to avoid leaking data.
+                */
+               bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
+               m->m_pkthdr.len += padlen;
+               m->m_len = m->m_pkthdr.len;
+               *m_head = m;
+       }
+
        prod = sc->are_cdata.are_tx_prod;
        txd = &sc->are_cdata.are_txdesc[prod];
-       error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag, 
txd->tx_dmamap,
-           *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+       error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag,
+           txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
        if (error == EFBIG) {
-               panic("EFBIG");
+               device_printf(sc->are_dev, "are_encap EFBIG error\n");
+               m = m_defrag(*m_head, M_NOWAIT);
+               if (m == NULL) {
+                       m_freem(*m_head);
+                       *m_head = NULL;
+                       return (ENOBUFS);
+               }
+               *m_head = m;
+               error = bus_dmamap_load_mbuf_sg(sc->are_cdata.are_tx_tag,
+                   txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+               if (error != 0) {
+                       m_freem(*m_head);
+                       *m_head = NULL;
+                       return (error);
+               }
+
        } else if (error != 0)
                return (error);
        if (nsegs == 0) {
@@ -729,13 +802,12 @@ are_encap(struct are_softc *sc, struct m
        for (i = 0; i < nsegs; i++) {
                desc = &sc->are_rdata.are_tx_ring[prod];
                desc->are_stat = ADSTAT_OWN;
-               desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len) | ADCTL_CH;
-               if (i == 0)
-                       desc->are_devcs |= ADCTL_Tx_FS;
+               desc->are_devcs = ARE_DMASIZE(txsegs[i].ds_len);
                desc->are_addr = txsegs[i].ds_addr;
                /* link with previous descriptor */
-               if (prev_desc)
-                       prev_desc->are_link = ARE_TX_RING_ADDR(sc, prod);
+               /* end of descriptor */
+               if (prod == ARE_TX_RING_CNT - 1)
+                       desc->are_devcs |= ADCTL_ER;
 
                sc->are_cdata.are_tx_cnt++;
                prev_desc = desc;
@@ -761,16 +833,16 @@ are_encap(struct are_softc *sc, struct m
        /* Start transmitting */
        /* Check if new list is queued in NDPTR */
        txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
-       if (txstat == 0 || txstat == 6) {
-               /* Transmit Process Stat is stop or suspended */
-               CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
+       if (startcount == 0 && (txstat == 0 || txstat == 6)) {
+               desc = &sc->are_rdata.are_tx_ring[si];
+               desc->are_devcs |= ADCTL_Tx_FS;
        }
        else {
                link_addr = ARE_TX_RING_ADDR(sc, si);
                /* Get previous descriptor */
                si = (si + ARE_TX_RING_CNT - 1) % ARE_TX_RING_CNT;
                desc = &sc->are_rdata.are_tx_ring[si];
-               desc->are_link = link_addr;
+               desc->are_devcs &= ~(ADCTL_Tx_IC | ADCTL_Tx_LS);
        }
 
        return (0);
@@ -782,6 +854,7 @@ are_start_locked(struct ifnet *ifp)
        struct are_softc                *sc;
        struct mbuf             *m_head;
        int                     enq;
+       int                     txstat;
 
        sc = ifp->if_softc;
 
@@ -816,6 +889,14 @@ are_start_locked(struct ifnet *ifp)
                 */
                ETHER_BPF_MTAP(ifp, m_head);
        }
+
+       if (enq > 0) { 
+               txstat = (CSR_READ_4(sc, CSR_STATUS) >> 20) & 7;
+               if (txstat == 0 || txstat == 6) {
+                       /* Transmit Process Stat is stop or suspended */
+                       CSR_WRITE_4(sc, CSR_TXPOLL, TXPOLL_TPD);
+               }
+       }
 }
 
 static void

Modified: head/sys/mips/atheros/ar531x/if_arereg.h
==============================================================================
--- head/sys/mips/atheros/ar531x/if_arereg.h    Sat May  6 06:01:17 2017        
(r317867)
+++ head/sys/mips/atheros/ar531x/if_arereg.h    Sat May  6 06:06:11 2017        
(r317868)
@@ -44,6 +44,8 @@ struct are_desc {
 #define        ARE_TX_RING_CNT         128
 #define        ARE_TX_RING_SIZE                sizeof(struct are_desc) * 
ARE_TX_RING_CNT
 #define        ARE_RX_RING_SIZE                sizeof(struct are_desc) * 
ARE_RX_RING_CNT
+
+#define        ARE_MIN_FRAMELEN                60
 #define        ARE_RING_ALIGN          sizeof(struct are_desc)
 #define        ARE_RX_ALIGN            sizeof(uint32_t)
 #define        ARE_MAXFRAGS            8
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to