svn commit: r302104 - head/sys/dev/iwm

Adrian Chadd adrian at FreeBSD.org
Thu Jun 23 01:13:31 UTC 2016


Author: adrian
Date: Thu Jun 23 01:13:30 2016
New Revision: 302104
URL: https://svnweb.freebsd.org/changeset/base/302104

Log:
  [iwm] Use mbuf for large firmware commands, like OpenBSD does.
  
  We also need to consider the size of large firmware commands in iwm_alloc_tx_ring(),
  in the dma tag creation, when qid == IWM_MVM_CMD_QUEUE. The old code apparently
  only allocated a 2KB (MCLBYTES) sized buffer when it actually expected 4KB.
  
  Submitted by:	Imre Vadasz <imre at vdsz.com>
  Approved by:	re (gjb)
  Differential Revision:	https://reviews.freebsd.org/D6824

Modified:
  head/sys/dev/iwm/if_iwm.c
  head/sys/dev/iwm/if_iwm_util.c

Modified: head/sys/dev/iwm/if_iwm.c
==============================================================================
--- head/sys/dev/iwm/if_iwm.c	Thu Jun 23 01:11:52 2016	(r302103)
+++ head/sys/dev/iwm/if_iwm.c	Thu Jun 23 01:13:30 2016	(r302104)
@@ -956,6 +956,8 @@ iwm_alloc_tx_ring(struct iwm_softc *sc, 
 {
 	bus_addr_t paddr;
 	bus_size_t size;
+	size_t maxsize;
+	int nsegments;
 	int i, error;
 
 	ring->qid = qid;
@@ -988,9 +990,18 @@ iwm_alloc_tx_ring(struct iwm_softc *sc, 
 	}
 	ring->cmd = ring->cmd_dma.vaddr;
 
+	/* FW commands may require more mapped space than packets. */
+	if (qid == IWM_MVM_CMD_QUEUE) {
+		maxsize = IWM_RBUF_SIZE;
+		nsegments = 1;
+	} else {
+		maxsize = MCLBYTES;
+		nsegments = IWM_MAX_SCATTER - 2;
+	}
+
 	error = bus_dma_tag_create(sc->sc_dmat, 1, 0,
-	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES,
-            IWM_MAX_SCATTER - 2, MCLBYTES, 0, NULL, NULL, &ring->data_dmat);
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, maxsize,
+            nsegments, maxsize, 0, NULL, NULL, &ring->data_dmat);
 	if (error != 0) {
 		device_printf(sc->sc_dev, "could not create TX buf DMA tag\n");
 		goto fail;

Modified: head/sys/dev/iwm/if_iwm_util.c
==============================================================================
--- head/sys/dev/iwm/if_iwm_util.c	Thu Jun 23 01:11:52 2016	(r302103)
+++ head/sys/dev/iwm/if_iwm_util.c	Thu Jun 23 01:13:30 2016	(r302104)
@@ -157,19 +157,6 @@ __FBSDID("$FreeBSD$");
 #include <dev/iwm/if_iwm_util.h>
 #include <dev/iwm/if_iwm_pcie_trans.h>
 
-static void
-iwm_dma_map_mem(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
-{
-        if (error != 0)
-                return;
-	KASSERT(nsegs <= 2, ("too many DMA segments, %d should be <= 2",
-	    nsegs));
-	if (nsegs > 1)
-		KASSERT(segs[1].ds_addr == segs[0].ds_addr + segs[0].ds_len,
-		    ("fragmented DMA memory"));
-	*(bus_addr_t *)arg = segs[0].ds_addr;
-}
-
 /*
  * Send a command to the firmware.  We try to implement the Linux
  * driver interface for the routine.
@@ -183,12 +170,15 @@ iwm_send_cmd(struct iwm_softc *sc, struc
 	struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE];
 	struct iwm_tfd *desc;
 	struct iwm_tx_data *data;
-	struct iwm_device_cmd *cmd = NULL;
+	struct iwm_device_cmd *cmd;
+	struct mbuf *m;
+	bus_dma_segment_t seg;
 	bus_addr_t paddr;
 	uint32_t addr_lo;
 	int error = 0, i, paylen, off;
 	int code;
 	int async, wantresp;
+	int nsegs;
 
 	code = hcmd->id;
 	async = hcmd->flags & IWM_CMD_ASYNC;
@@ -231,15 +221,24 @@ iwm_send_cmd(struct iwm_softc *sc, struc
 			error = EINVAL;
 			goto out;
 		}
-		error = bus_dmamem_alloc(ring->data_dmat, (void **)&cmd,
-		    BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &data->map);
-		if (error != 0)
+		m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, IWM_RBUF_SIZE);
+		if (m == NULL) {
+			error = ENOBUFS;
 			goto out;
-		error = bus_dmamap_load(ring->data_dmat, data->map,
-		    cmd, paylen + sizeof(cmd->hdr), iwm_dma_map_mem,
-		    &paddr, BUS_DMA_NOWAIT);
-		if (error != 0)
+		}
+
+		m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
+		error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
+		    data->map, m, &seg, &nsegs, BUS_DMA_NOWAIT);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "%s: can't map mbuf, error %d\n", __func__, error);
+			m_freem(m);
 			goto out;
+		}
+		data->m = m; /* mbuf will be freed in iwm_cmd_done() */
+		cmd = mtod(m, struct iwm_device_cmd *);
+		paddr = seg.ds_addr;
 	} else {
 		cmd = &ring->cmd[ring->cur];
 		paddr = data->cmd_paddr;
@@ -319,8 +318,6 @@ iwm_send_cmd(struct iwm_softc *sc, struc
 		}
 	}
  out:
-	if (cmd && paylen > sizeof(cmd->data))
-		bus_dmamem_free(ring->data_dmat, cmd, data->map);
 	if (wantresp && error != 0) {
 		iwm_free_resp(sc, hcmd);
 	}


More information about the svn-src-all mailing list