Changeset 5deeb69 in rtems-libbsd


Ignore:
Timestamp:
Mar 27, 2015, 1:16:40 PM (5 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
afaeccc05a556f6aa25ba044a7e49d6aa634a59e, master
Children:
b99c023
Parents:
d9ff828
git-author:
Sebastian Huber <sebastian.huber@…> (03/27/15 13:16:40)
git-committer:
Sebastian Huber <sebastian.huber@…> (01/10/17 08:53:33)
Message:

if_dwc: Avoid tx defrag if possible

Drop packets in case of resource shortage.

Location:
freebsd/sys/dev/dwc
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • freebsd/sys/dev/dwc/if_dwc.c

    rd9ff828 r5deeb69  
    158158
    159159static inline uint32_t
    160 next_txidx(struct dwc_softc *sc, uint32_t curidx)
    161 {
    162 
    163         return ((curidx + 1) % TX_DESC_COUNT);
     160next_txidx(struct dwc_softc *sc, uint32_t curidx, int inc)
     161{
     162
     163        return ((curidx + (uint32_t)inc) % TX_DESC_COUNT);
    164164}
    165165
     
    173173}
    174174
    175 inline static uint32_t
    176 dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr,
    177     uint32_t len)
    178 {
    179         uint32_t flags;
    180 
    181         ++sc->txcount;
    182 
    183         sc->txdesc_ring[idx].addr = (uint32_t)(paddr);
    184         if (sc->mactype == DWC_GMAC_ALT_DESC) {
    185                 flags = DDESC_CNTL_TXCHAIN | DDESC_CNTL_TXFIRST
    186                     | DDESC_CNTL_TXLAST | DDESC_CNTL_TXINT;
    187                 sc->txdesc_ring[idx].tdes0 = 0;
    188                 sc->txdesc_ring[idx].tdes1 = flags | len;
    189         } else {
    190                 flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST
    191                     | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT;
    192                 sc->txdesc_ring[idx].tdes0 = flags;
    193                 sc->txdesc_ring[idx].tdes1 = len;
    194         }
    195         wmb();
    196 
    197         sc->txdesc_ring[idx].tdes0 = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST
    198             | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT | DDESC_TDES0_OWN;
    199         wmb();
    200 
    201         return (next_txidx(sc, idx));
    202 }
    203 
    204 static int
    205 dwc_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp)
    206 {
    207         struct bus_dma_segment seg;
    208         int error, nsegs;
    209         struct mbuf * m;
    210 
    211         if ((m = m_defrag(*mp, M_NOWAIT)) == NULL)
    212                 return (ENOMEM);
    213         *mp = m;
    214 
     175static void
     176dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_dma_segment_t segs[TX_MAX_DMA_SEGS],
     177    int nsegs)
     178{
     179        int i;
     180
     181        sc->txcount += nsegs;
     182
     183        idx = next_txidx(sc, idx, nsegs);
     184        sc->tx_idx_head = idx;
     185
     186        /*
     187         * Fill in the TX descriptors back to front so that OWN bit in first
     188         * descriptor is set last.
     189         */
     190        for (i = nsegs - 1; i >= 0; i--) {
     191                uint32_t flags;
     192                uint32_t len;
     193
     194                idx = next_txidx(sc, idx, -1);
     195
     196                sc->txdesc_ring[idx].addr = segs[i].ds_addr;
     197                len = segs[i].ds_len;
     198
     199                if (sc->mactype == DWC_GMAC_ALT_DESC) {
     200                        flags = DDESC_CNTL_TXCHAIN | DDESC_CNTL_TXINT;
     201
     202                        if (i == 0)
     203                                flags |= DDESC_CNTL_TXFIRST;
     204
     205                        if (i == nsegs - 1)
     206                                flags |= DDESC_CNTL_TXLAST;
     207
     208                        sc->txdesc_ring[idx].tdes0 = 0;
     209                        sc->txdesc_ring[idx].tdes1 = flags | len;
     210                } else {
     211                        flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXINT |
     212                            DDESC_TDES0_OWN;
     213
     214                        if (i == 0)
     215                                flags |= DDESC_TDES0_TXFIRST;
     216
     217                        if (i == nsegs - 1)
     218                                flags |= DDESC_TDES0_TXLAST;
     219
     220                        sc->txdesc_ring[idx].tdes1 = len;
     221                        wmb();
     222                        sc->txdesc_ring[idx].tdes0 = flags;
     223                }
     224
     225                wmb();
     226
     227                if (i != 0)
     228                        sc->txbuf_map[idx].mbuf = NULL;
     229        }
     230}
     231
     232static void
     233dwc_setup_txbuf(struct dwc_softc *sc, struct mbuf *m, int *start_tx)
     234{
     235        bus_dma_segment_t segs[TX_MAX_DMA_SEGS];
     236        int error, nsegs, idx;
     237
     238        idx = sc->tx_idx_head;
    215239        error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map,
    216             m, &seg, &nsegs, 0);
     240            m, &seg, &nsegs, BUS_DMA_NOWAIT);
     241
     242        if (error == EFBIG) {
     243                /* Too many segments!  Defrag and try again. */
     244                struct mbuf *m2 = m_defrag(m, M_NOWAIT);
     245
     246                if (m2 == NULL) {
     247                        m_freem(m);
     248                        return;
     249                }
     250                m = m2;
     251                error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag,
     252                    sc->txbuf_map[idx].map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
     253        }
    217254        if (error != 0) {
    218                 return (ENOMEM);
    219         }
    220 
    221         KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
     255                /* Give up. */
     256                m_freem(m);
     257                return;
     258        }
     259
     260        sc->txbuf_map[idx].mbuf = m;
    222261
    223262        bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map,
    224263            BUS_DMASYNC_PREWRITE);
    225264
    226         sc->txbuf_map[idx].mbuf = m;
    227 
    228         dwc_setup_txdesc(sc, idx, seg.ds_addr, seg.ds_len);
    229 
    230         return (0);
     265        dwc_setup_txdesc(sc, idx, segs, nsegs);
     266
     267        ETHER_BPF_MTAP(sc->ifp, m);
     268        *start_tx = 1;
    231269}
    232270
     
    236274        struct ifnet *ifp;
    237275        struct mbuf *m;
    238         int enqueued;
     276        int start_tx;
    239277
    240278        DWC_ASSERT_LOCKED(sc);
     
    245283        ifp = sc->ifp;
    246284
    247         enqueued = 0;
     285        start_tx = 0;
    248286
    249287        for (;;) {
    250                 if (sc->txcount == (TX_DESC_COUNT-1)) {
     288                if (sc->txcount >= (TX_DESC_COUNT - 1 - TX_MAX_DMA_SEGS)) {
    251289                        ifp->if_drv_flags |= IFF_DRV_OACTIVE;
    252290                        break;
     
    256294                if (m == NULL)
    257295                        break;
    258                 if (dwc_setup_txbuf(sc, sc->tx_idx_head, &m) != 0) {
    259                         IFQ_DRV_PREPEND(&ifp->if_snd, m);
    260                         break;
    261                 }
    262                 BPF_MTAP(ifp, m);
    263                 sc->tx_idx_head = next_txidx(sc, sc->tx_idx_head);
    264                 ++enqueued;
    265         }
    266 
    267         if (enqueued != 0) {
     296
     297                dwc_setup_txbuf(sc, m, &start_tx);
     298        }
     299
     300        if (start_tx != 0) {
    268301                WRITE4(sc, TRANSMIT_POLL_DEMAND, 0x1);
    269302                sc->tx_watchdog_count = WATCHDOG_TIMEOUT_SECS;
     
    476509dwc_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m)
    477510{
    478         struct bus_dma_segment seg;
     511        bus_dma_segment_t seg;
    479512        int error, nsegs;
    480513
     
    718751                bmap->mbuf = NULL;
    719752                --sc->txcount;
    720                 sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail);
     753                sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail, 1);
    721754        }
    722755
     
    877910                        sc->txdesc_ring[idx].tdes1 = 0;
    878911                }
    879                 nidx = next_txidx(sc, idx);
     912                nidx = next_txidx(sc, idx, 1);
    880913                sc->txdesc_ring[idx].addr_next = sc->txdesc_ring_paddr +
    881914                    (nidx * sizeof(struct dwc_hwdesc));
     
    888921            BUS_SPACE_MAXADDR,          /* highaddr */
    889922            NULL, NULL,                 /* filter, filterarg */
    890             MCLBYTES, 1,                /* maxsize, nsegments */
     923            MCLBYTES, TX_MAX_DMA_SEGS,  /* maxsize, nsegments */
    891924            MCLBYTES,                   /* maxsegsize */
    892925            0,                          /* flags */
  • freebsd/sys/dev/dwc/if_dwcvar.h

    rd9ff828 r5deeb69  
    5050#define TX_DESC_COUNT   1024
    5151#define TX_DESC_SIZE    (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT)
     52#define TX_MAX_DMA_SEGS 8       /* maximum segs in a tx mbuf dma */
    5253
    5354struct dwc_bufmap {
Note: See TracChangeset for help on using the changeset viewer.