From 1e86b538b294f1f8698eccedd9a4910a276f3394 Mon Sep 17 00:00:00 2001 From: stsp Date: Thu, 8 Feb 2024 11:09:53 +0000 Subject: [PATCH] handle fragmented mbuf DMA segments in the qwx(4) Tx path Fixes qwx0: failed to map Tx buffer: 27 --- sys/dev/ic/qwx.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/sys/dev/ic/qwx.c b/sys/dev/ic/qwx.c index 9e908673ded..b20a2fd3e16 100644 --- a/sys/dev/ic/qwx.c +++ b/sys/dev/ic/qwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: qwx.c,v 1.19 2024/02/08 11:06:50 stsp Exp $ */ +/* $OpenBSD: qwx.c,v 1.20 2024/02/08 11:09:53 stsp Exp $ */ /* * Copyright 2023 Stefan Sperling @@ -22171,12 +22171,27 @@ qwx_dp_tx(struct qwx_softc *sc, struct qwx_vif *arvif, uint8_t pdev_id, #endif ret = bus_dmamap_load_mbuf(sc->sc_dmat, tx_data->map, m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); - if (ret) { + if (ret && ret != EFBIG) { printf("%s: failed to map Tx buffer: %d\n", sc->sc_dev.dv_xname, ret); m_freem(m); return ret; } + if (ret) { + /* Too many DMA segments, linearize mbuf. */ + if (m_defrag(m, M_DONTWAIT)) { + m_freem(m); + return ENOBUFS; + } + ret = bus_dmamap_load_mbuf(sc->sc_dmat, tx_data->map, m, + BUS_DMA_NOWAIT | BUS_DMA_WRITE); + if (ret) { + printf("%s: failed to map Tx buffer: %d\n", + sc->sc_dev.dv_xname, ret); + m_freem(m); + return ret; + } + } ti.paddr = tx_data->map->dm_segs[0].ds_addr; ti.data_len = m->m_pkthdr.len; @@ -22290,11 +22305,26 @@ qwx_mac_mgmt_tx_wmi(struct qwx_softc *sc, struct qwx_vif *arvif, #endif ret = bus_dmamap_load_mbuf(sc->sc_dmat, tx_data->map, m, BUS_DMA_WRITE | BUS_DMA_NOWAIT); - if (ret) { + if (ret && ret != EFBIG) { printf("%s: failed to map mgmt Tx buffer: %d\n", sc->sc_dev.dv_xname, ret); return ret; } + if (ret) { + /* Too many DMA segments, linearize mbuf. */ + if (m_defrag(m, M_DONTWAIT)) { + m_freem(m); + return ENOBUFS; + } + ret = bus_dmamap_load_mbuf(sc->sc_dmat, tx_data->map, m, + BUS_DMA_NOWAIT | BUS_DMA_WRITE); + if (ret) { + printf("%s: failed to map mgmt Tx buffer: %d\n", + sc->sc_dev.dv_xname, ret); + m_freem(m); + return ret; + } + } ret = qwx_wmi_mgmt_send(sc, arvif, pdev_id, buf_id, m, tx_data); if (ret) { -- 2.20.1