Changeset a681853 in rtems-libbsd


Ignore:
Timestamp:
Mar 30, 2015, 9:40:24 AM (5 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, afaeccc05a556f6aa25ba044a7e49d6aa634a59e, freebsd-9.3, master
Children:
6b176ce
Parents:
822aa5de
git-author:
Sebastian Huber <sebastian.huber@…> (03/30/15 09:40:24)
git-committer:
Sebastian Huber <sebastian.huber@…> (04/01/15 07:15:30)
Message:

if_dwc: Avoid tx defrag if possible

Drop packets in case of resource shortage.

File:
1 edited

Legend:

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

    r822aa5de ra681853  
    150150#endif /* __rtems__ */
    151151#define TX_DESC_SIZE    (sizeof(struct dwc_hwdesc) * TX_DESC_COUNT)
     152#define TX_MAX_DMA_SEGS 8       /* maximum segs in a tx mbuf dma */
    152153
    153154/*
     
    222223
    223224static inline uint32_t
    224 next_txidx(struct dwc_softc *sc, uint32_t curidx)
    225 {
    226 
    227         return ((curidx + 1) % TX_DESC_COUNT);
     225next_txidx(struct dwc_softc *sc, uint32_t curidx, int inc)
     226{
     227
     228        return ((curidx + (uint32_t)inc) % TX_DESC_COUNT);
    228229}
    229230
     
    239240#endif /* __rtems__ */
    240241
    241 inline static uint32_t
    242 dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr,
    243     uint32_t len)
    244 {
    245         ++sc->txcount;
    246 
    247         sc->txdesc_ring[idx].addr = (uint32_t)(paddr);
    248         sc->txdesc_ring[idx].tdes1 = len;
    249         wmb();
    250 
    251         sc->txdesc_ring[idx].tdes0 = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST
    252             | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT | DDESC_TDES0_OWN;
    253         wmb();
    254 
    255         return (next_txidx(sc, idx));
    256 }
    257 
     242static void
     243dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_dma_segment_t segs[TX_MAX_DMA_SEGS],
     244    int nsegs)
     245{
     246        int i;
     247
     248        sc->txcount += nsegs;
     249
     250        idx = next_txidx(sc, idx, nsegs);
     251        sc->tx_idx_head = idx;
     252
     253        /*
     254         * Fill in the TX descriptors back to front so that OWN bit in first
     255         * descriptor is set last.
     256         */
     257        for (i = nsegs - 1; i >= 0; i--) {
     258                uint32_t tdes0;
     259
     260                idx = next_txidx(sc, idx, -1);
     261
     262                sc->txdesc_ring[idx].addr = segs[i].ds_addr;
     263                sc->txdesc_ring[idx].tdes1 = segs[i].ds_len;
     264                wmb();
     265
     266                tdes0 = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXINT |
     267                    DDESC_TDES0_OWN;
     268
     269                if (i == 0)
     270                        tdes0 |= DDESC_TDES0_TXFIRST;
     271
     272                if (i == nsegs - 1)
     273                        tdes0 |= DDESC_TDES0_TXLAST;
     274
     275                sc->txdesc_ring[idx].tdes0 = tdes0;
     276                wmb();
     277
     278                if (i != 0)
     279                        sc->txbuf_map[idx].mbuf = NULL;
     280        }
     281}
     282
     283#ifdef __rtems__
    258284static int
    259 dwc_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp)
    260 {
    261         struct bus_dma_segment seg;
    262 #ifndef __rtems__
    263         int error, nsegs;
    264 #endif /* __rtems__ */
    265         struct mbuf * m;
    266 
    267         if ((m = m_defrag(*mp, M_NOWAIT)) == NULL)
    268                 return (ENOMEM);
    269         *mp = m;
    270 
     285dwc_get_segs_for_tx(struct mbuf *m, bus_dma_segment_t segs[TX_MAX_DMA_SEGS],
     286    int *nsegs)
     287{
     288        int i = 0;
     289
     290        do {
     291                if (m->m_len > 0) {
     292                        segs[i].ds_addr = mtod(m, bus_addr_t);
     293                        segs[i].ds_len = m->m_len;
     294                        rtems_cache_flush_multiple_data_lines(m->m_data, m->m_len);
     295                        ++i;
     296                }
     297
     298                m = m->m_next;
     299
     300                if (m == NULL) {
     301                        *nsegs = i;
     302
     303                        return (0);
     304                }
     305        } while (i < TX_MAX_DMA_SEGS);
     306
     307        return (EFBIG);
     308}
     309#endif /* __rtems__ */
     310static void
     311dwc_setup_txbuf(struct dwc_softc *sc, struct mbuf *m, int *start_tx)
     312{
     313        bus_dma_segment_t segs[TX_MAX_DMA_SEGS];
     314        int error, nsegs, idx;
     315
     316        idx = sc->tx_idx_head;
    271317#ifndef __rtems__
    272318        error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map,
    273             m, &seg, &nsegs, 0);
     319            m, &seg, &nsegs, BUS_DMA_NOWAIT);
     320
     321#else /* __rtems__ */
     322        error = dwc_get_segs_for_tx(m, segs, &nsegs);
     323#endif /* __rtems__ */
     324        if (error == EFBIG) {
     325                /* Too many segments!  Defrag and try again. */
     326                struct mbuf *m2 = m_defrag(m, M_NOWAIT);
     327
     328                if (m2 == NULL) {
     329                        m_freem(m);
     330                        return;
     331                }
     332                m = m2;
     333#ifndef __rtems__
     334                error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag,
     335                    sc->txbuf_map[idx].map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
     336#else /* __rtems__ */
     337                error = dwc_get_segs_for_tx(m, segs, &nsegs);
     338#endif /* __rtems__ */
     339        }
    274340        if (error != 0) {
    275                 return (ENOMEM);
    276         }
    277 
    278         KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
    279 
     341                /* Give up. */
     342                m_freem(m);
     343                return;
     344        }
     345
     346        sc->txbuf_map[idx].mbuf = m;
     347
     348#ifndef __rtems__
    280349        bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map,
    281350            BUS_DMASYNC_PREWRITE);
    282 #else /* __rtems__ */
    283         rtems_cache_flush_multiple_data_lines(m->m_data, m->m_len);
    284         seg.ds_addr = mtod(m, bus_addr_t);
    285         seg.ds_len = m->m_len;
    286 #endif /* __rtems__ */
    287 
    288         sc->txbuf_map[idx].mbuf = m;
    289 
    290         dwc_setup_txdesc(sc, idx, seg.ds_addr, seg.ds_len);
    291 
    292         return (0);
     351#endif /* __rtems__ */
     352
     353        dwc_setup_txdesc(sc, idx, segs, nsegs);
     354
     355        ETHER_BPF_MTAP(sc->ifp, m);
     356        *start_tx = 1;
    293357}
    294358
     
    298362        struct ifnet *ifp;
    299363        struct mbuf *m;
    300         int enqueued;
     364        int start_tx;
    301365
    302366        DWC_ASSERT_LOCKED(sc);
     
    307371        ifp = sc->ifp;
    308372
    309         enqueued = 0;
     373        start_tx = 0;
    310374
    311375        for (;;) {
    312                 if (sc->txcount == (TX_DESC_COUNT-1)) {
     376                if (sc->txcount >= (TX_DESC_COUNT - 1 - TX_MAX_DMA_SEGS)) {
    313377                        ifp->if_drv_flags |= IFF_DRV_OACTIVE;
    314378                        break;
     
    318382                if (m == NULL)
    319383                        break;
    320                 if (dwc_setup_txbuf(sc, sc->tx_idx_head, &m) != 0) {
    321                         IFQ_DRV_PREPEND(&ifp->if_snd, m);
    322                         break;
    323                 }
    324                 BPF_MTAP(ifp, m);
    325                 sc->tx_idx_head = next_txidx(sc, sc->tx_idx_head);
    326                 ++enqueued;
    327         }
    328 
    329         if (enqueued != 0) {
     384
     385                dwc_setup_txbuf(sc, m, &start_tx);
     386        }
     387
     388        if (start_tx != 0) {
    330389                WRITE4(sc, TRANSMIT_POLL_DEMAND, 0x1);
    331390                sc->tx_watchdog_count = WATCHDOG_TIMEOUT_SECS;
     
    558617dwc_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m)
    559618{
    560         struct bus_dma_segment seg;
     619        bus_dma_segment_t seg;
    561620#ifndef __rtems__
    562621        int error, nsegs;
     
    804863                bmap->mbuf = NULL;
    805864                --sc->txcount;
    806                 sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail);
     865                sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail, 1);
    807866        }
    808867
     
    9701029                sc->txdesc_ring[idx].tdes0 = DDESC_TDES0_TXCHAIN;
    9711030                sc->txdesc_ring[idx].tdes1 = 0;
    972                 nidx = next_txidx(sc, idx);
     1031                nidx = next_txidx(sc, idx, 1);
    9731032#ifndef __rtems__
    9741033                sc->txdesc_ring[idx].addr_next = sc->txdesc_ring_paddr + \
     
    9871046            BUS_SPACE_MAXADDR,          /* highaddr */
    9881047            NULL, NULL,                 /* filter, filterarg */
    989             MCLBYTES, 1,                /* maxsize, nsegments */
     1048            MCLBYTES, TX_MAX_DMA_SEGS,  /* maxsize, nsegments */
    9901049            MCLBYTES,                   /* maxsegsize */
    9911050            0,                          /* flags */
Note: See TracChangeset for help on using the changeset viewer.