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;

Reply via email to