Module Name: src Committed By: riastradh Date: Sat Sep 1 22:01:03 UTC 2018
Modified Files: src/sys/dev/ic: bwfm.c bwfmvar.h src/sys/dev/pci: if_bwfm_pci.c src/sys/dev/usb: if_bwfm_usb.c Log Message: bwfm has only one tx descriptor; limit mbuf chains to one segment. PR kern/53287 Can't use m_defrag because it always yields two segments. Discussion on tech-net: https://mail-index.netbsd.org/tech-net/2018/09/01/msg007031.html Diagnosed and tested by maya. To generate a diff of this commit: cvs rdiff -u -r1.12 -r1.13 src/sys/dev/ic/bwfm.c cvs rdiff -u -r1.2 -r1.3 src/sys/dev/ic/bwfmvar.h cvs rdiff -u -r1.1 -r1.2 src/sys/dev/pci/if_bwfm_pci.c cvs rdiff -u -r1.7 -r1.8 src/sys/dev/usb/if_bwfm_usb.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/bwfm.c diff -u src/sys/dev/ic/bwfm.c:1.12 src/sys/dev/ic/bwfm.c:1.13 --- src/sys/dev/ic/bwfm.c:1.12 Tue Jun 26 06:48:00 2018 +++ src/sys/dev/ic/bwfm.c Sat Sep 1 22:01:03 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: bwfm.c,v 1.12 2018/06/26 06:48:00 msaitoh Exp $ */ +/* $NetBSD: bwfm.c,v 1.13 2018/09/01 22:01:03 riastradh Exp $ */ /* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation @@ -337,7 +337,7 @@ bwfm_start(struct ifnet *ifp) continue; } - error = sc->sc_bus_ops->bs_txdata(sc, m); + error = sc->sc_bus_ops->bs_txdata(sc, &m); if (error == ENOBUFS) { IF_PREPEND(&ifp->if_snd, m); ifp->if_flags |= IFF_OACTIVE; Index: src/sys/dev/ic/bwfmvar.h diff -u src/sys/dev/ic/bwfmvar.h:1.2 src/sys/dev/ic/bwfmvar.h:1.3 --- src/sys/dev/ic/bwfmvar.h:1.2 Fri May 11 07:41:11 2018 +++ src/sys/dev/ic/bwfmvar.h Sat Sep 1 22:01:03 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: bwfmvar.h,v 1.2 2018/05/11 07:41:11 maya Exp $ */ +/* $NetBSD: bwfmvar.h,v 1.3 2018/09/01 22:01:03 riastradh Exp $ */ /* $OpenBSD: bwfmvar.h,v 1.1 2017/10/11 17:19:50 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation @@ -93,7 +93,7 @@ struct bwfm_bus_ops { void (*bs_init)(struct bwfm_softc *); void (*bs_stop)(struct bwfm_softc *); int (*bs_txcheck)(struct bwfm_softc *); - int (*bs_txdata)(struct bwfm_softc *, struct mbuf *); + int (*bs_txdata)(struct bwfm_softc *, struct mbuf **); int (*bs_txctl)(struct bwfm_softc *, char *, size_t); int (*bs_rxctl)(struct bwfm_softc *, char *, size_t *); }; Index: src/sys/dev/pci/if_bwfm_pci.c diff -u src/sys/dev/pci/if_bwfm_pci.c:1.1 src/sys/dev/pci/if_bwfm_pci.c:1.2 --- src/sys/dev/pci/if_bwfm_pci.c:1.1 Fri May 11 07:42:22 2018 +++ src/sys/dev/pci/if_bwfm_pci.c Sat Sep 1 22:01:03 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bwfm_pci.c,v 1.1 2018/05/11 07:42:22 maya Exp $ */ +/* $NetBSD: if_bwfm_pci.c,v 1.2 2018/09/01 22:01:03 riastradh Exp $ */ /* $OpenBSD: if_bwfm_pci.c,v 1.18 2018/02/08 05:00:38 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation @@ -225,7 +225,7 @@ void bwfm_pci_dmamem_free(struct bwfm_ int bwfm_pci_pktid_avail(struct bwfm_pci_softc *, struct bwfm_pci_pkts *); int bwfm_pci_pktid_new(struct bwfm_pci_softc *, - struct bwfm_pci_pkts *, struct mbuf *, + struct bwfm_pci_pkts *, struct mbuf **, uint32_t *, paddr_t *); struct mbuf * bwfm_pci_pktid_free(struct bwfm_pci_softc *, struct bwfm_pci_pkts *, uint32_t); @@ -281,7 +281,7 @@ void bwfm_pci_flowring_delete(struct b void bwfm_pci_stop(struct bwfm_softc *); int bwfm_pci_txcheck(struct bwfm_softc *); -int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf *); +int bwfm_pci_txdata(struct bwfm_softc *, struct mbuf **); #ifdef BWFM_DEBUG void bwfm_pci_debug_console(struct bwfm_pci_softc *); @@ -922,7 +922,7 @@ bwfm_pci_pktid_avail(struct bwfm_pci_sof int bwfm_pci_pktid_new(struct bwfm_pci_softc *sc, struct bwfm_pci_pkts *pkts, - struct mbuf *m, uint32_t *pktid, paddr_t *paddr) + struct mbuf **mp, uint32_t *pktid, paddr_t *paddr) { int i, idx; @@ -932,15 +932,32 @@ bwfm_pci_pktid_new(struct bwfm_pci_softc idx = 0; if (pkts->pkts[idx].bb_m == NULL) { if (bus_dmamap_load_mbuf(sc->sc_dmat, - pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) { - if (m_defrag(m, M_DONTWAIT)) - return EFBIG; + pkts->pkts[idx].bb_map, *mp, BUS_DMA_NOWAIT) != 0) { + /* + * Didn't fit. Maybe it has too many + * segments. If it has only one + * segment, fail; otherwise try to + * compact it into a single mbuf + * segment. + */ + if ((*mp)->m_next == NULL) + return ENOBUFS; + struct mbuf *m0 = MCLGETI(NULL, M_DONTWAIT, + NULL, MSGBUF_MAX_PKT_SIZE); + if (m0 == NULL) + return ENOBUFS; + m_copydata(*mp, 0, (*mp)->m_pkthdr.len, + mtod(m0, void *)); + m0->m_pkthdr.len = m0->m_len = + (*mp)->m_pkthdr.len; + m_freem(*mp); + *mp = m0; if (bus_dmamap_load_mbuf(sc->sc_dmat, - pkts->pkts[idx].bb_map, m, BUS_DMA_NOWAIT) != 0) + pkts->pkts[idx].bb_map, *mp, BUS_DMA_NOWAIT) != 0) return EFBIG; } pkts->last = idx; - pkts->pkts[idx].bb_m = m; + pkts->pkts[idx].bb_m = *mp; *pktid = idx; *paddr = pkts->pkts[idx].bb_map->dm_segs[0].ds_addr; return 0; @@ -997,7 +1014,7 @@ bwfm_pci_fill_rx_ioctl_ring(struct bwfm_ break; } m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; - if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { + if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, &m, &pktid, &paddr)) { bwfm_pci_ring_write_cancel(sc, &sc->sc_ctrl_submit, 1); m_freem(m); break; @@ -1037,7 +1054,7 @@ bwfm_pci_fill_rx_buf_ring(struct bwfm_pc break; } m->m_len = m->m_pkthdr.len = MSGBUF_MAX_PKT_SIZE; - if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, m, &pktid, &paddr)) { + if (bwfm_pci_pktid_new(sc, &sc->sc_rx_pkts, &m, &pktid, &paddr)) { bwfm_pci_ring_write_cancel(sc, &sc->sc_rxpost_submit, 1); m_freem(m); break; @@ -1388,7 +1405,7 @@ bwfm_pci_msg_rx(struct bwfm_pci_softc *s if (ring->m != NULL) { m = ring->m; ring->m = NULL; - if (bwfm_pci_txdata(&sc->sc_sc, m)) + if (bwfm_pci_txdata(&sc->sc_sc, &m)) m_freem(ring->m); } ifp->if_flags &= ~IFF_OACTIVE; @@ -1851,7 +1868,7 @@ bwfm_pci_txcheck(struct bwfm_softc *bwfm } int -bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf *m) +bwfm_pci_txdata(struct bwfm_softc *bwfm, struct mbuf **mp) { struct bwfm_pci_softc *sc = (void *)bwfm; struct bwfm_pci_msgring *ring; @@ -1861,7 +1878,7 @@ bwfm_pci_txdata(struct bwfm_softc *bwfm, struct ether_header *eh; int flowid, ret, ac; - flowid = bwfm_pci_flowring_lookup(sc, m); + flowid = bwfm_pci_flowring_lookup(sc, *mp); if (flowid < 0) { /* * We cannot send the packet right now as there is @@ -1872,7 +1889,7 @@ bwfm_pci_txdata(struct bwfm_softc *bwfm, * is created the queue will be restarted and this * mbuf will be transmitted. */ - bwfm_pci_flowring_create(sc, m); + bwfm_pci_flowring_create(sc, *mp); return 0; } @@ -1890,9 +1907,9 @@ bwfm_pci_txdata(struct bwfm_softc *bwfm, return ENOBUFS; /* No QoS for EAPOL frames. */ - eh = mtod(m, struct ether_header *); + eh = mtod(*mp, struct ether_header *); ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ? - M_WME_GETAC(m) : WME_AC_BE; + M_WME_GETAC(*mp) : WME_AC_BE; memset(tx, 0, sizeof(*tx)); tx->msg.msgtype = MSGBUF_TYPE_TX_POST; @@ -1900,9 +1917,9 @@ bwfm_pci_txdata(struct bwfm_softc *bwfm, tx->flags = BWFM_MSGBUF_PKT_FLAGS_FRAME_802_3; tx->flags |= ac << BWFM_MSGBUF_PKT_FLAGS_PRIO_SHIFT; tx->seg_cnt = 1; - memcpy(tx->txhdr, mtod(m, char *), ETHER_HDR_LEN); + memcpy(tx->txhdr, mtod(*mp, char *), ETHER_HDR_LEN); - ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, m, &pktid, &paddr); + ret = bwfm_pci_pktid_new(sc, &sc->sc_tx_pkts, mp, &pktid, &paddr); if (ret) { if (ret == ENOBUFS) { printf("%s: no pktid available for TX\n", @@ -1915,7 +1932,7 @@ bwfm_pci_txdata(struct bwfm_softc *bwfm, paddr += ETHER_HDR_LEN; tx->msg.request_id = htole32(pktid); - tx->data_len = htole16(m->m_len - ETHER_HDR_LEN); + tx->data_len = htole16((*mp)->m_len - ETHER_HDR_LEN); tx->data_buf_addr.high_addr = htole32(paddr >> 32); tx->data_buf_addr.low_addr = htole32(paddr & 0xffffffff); Index: src/sys/dev/usb/if_bwfm_usb.c diff -u src/sys/dev/usb/if_bwfm_usb.c:1.7 src/sys/dev/usb/if_bwfm_usb.c:1.8 --- src/sys/dev/usb/if_bwfm_usb.c:1.7 Sun Aug 12 06:02:38 2018 +++ src/sys/dev/usb/if_bwfm_usb.c Sat Sep 1 22:01:03 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: if_bwfm_usb.c,v 1.7 2018/08/12 06:02:38 rin Exp $ */ +/* $NetBSD: if_bwfm_usb.c,v 1.8 2018/09/01 22:01:03 riastradh Exp $ */ /* $OpenBSD: if_bwfm_usb.c,v 1.2 2017/10/15 14:55:13 patrick Exp $ */ /* * Copyright (c) 2010-2016 Broadcom Corporation @@ -18,7 +18,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_bwfm_usb.c,v 1.7 2018/08/12 06:02:38 rin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_bwfm_usb.c,v 1.8 2018/09/01 22:01:03 riastradh Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -203,7 +203,7 @@ int bwfm_usb_alloc_tx_list(struct bwfm void bwfm_usb_free_tx_list(struct bwfm_usb_softc *); int bwfm_usb_txcheck(struct bwfm_softc *); -int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf *); +int bwfm_usb_txdata(struct bwfm_softc *, struct mbuf **); int bwfm_usb_txctl(struct bwfm_softc *, char *, size_t); int bwfm_usb_rxctl(struct bwfm_softc *, char *, size_t *); @@ -785,9 +785,10 @@ bwfm_usb_txcheck(struct bwfm_softc *bwfm int -bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf *m) +bwfm_usb_txdata(struct bwfm_softc *bwfm, struct mbuf **mp) { struct bwfm_usb_softc *sc = (void *)bwfm; + struct mbuf *m = *mp; struct bwfm_proto_bcdc_hdr *hdr; struct bwfm_usb_tx_data *data; struct ether_header *eh;