From owner-svn-src-all@freebsd.org Thu Mar 1 06:39:45 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 18FF2F296E8; Thu, 1 Mar 2018 06:39:45 +0000 (UTC) (envelope-from eadler@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id C06E66AF08; Thu, 1 Mar 2018 06:39:44 +0000 (UTC) (envelope-from eadler@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id BB49524DFC; Thu, 1 Mar 2018 06:39:44 +0000 (UTC) (envelope-from eadler@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w216dinc058538; Thu, 1 Mar 2018 06:39:44 GMT (envelope-from eadler@FreeBSD.org) Received: (from eadler@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w216dik6058535; Thu, 1 Mar 2018 06:39:44 GMT (envelope-from eadler@FreeBSD.org) Message-Id: <201803010639.w216dik6058535@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: eadler set sender to eadler@FreeBSD.org using -f From: Eitan Adler Date: Thu, 1 Mar 2018 06:39:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r330208 - stable/11/sys/dev/iwm X-SVN-Group: stable-11 X-SVN-Commit-Author: eadler X-SVN-Commit-Paths: stable/11/sys/dev/iwm X-SVN-Commit-Revision: 330208 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 01 Mar 2018 06:39:45 -0000 Author: eadler Date: Thu Mar 1 06:39:44 2018 New Revision: 330208 URL: https://svnweb.freebsd.org/changeset/base/330208 Log: MFC r318218: [iwm] Process multiple frames per RX buffer. * Factor out iwm_handle_rxb() function from iwm_notif_intr(). * Removing the IWM_FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK flag allows the device to put multiple frames (both command responses and 80211 frames) into a single RX buffer. * Uses m_copym() to split up the receive buffers when multiple 80211 frames are received in one RX buffer. The effect is basically the same as when using m_split(), but we want to keep the original mbuf around when calling iwm_mvm_rx_rx_mpdu() to make error handling a bit easier for now. * Contains a small optimization to avoid the m_copym() when only a single 80211 frame is received in one RX buffer (i.e. matching the existing behaviour). Modified: stable/11/sys/dev/iwm/if_iwm.c stable/11/sys/dev/iwm/if_iwmreg.h stable/11/sys/dev/iwm/if_iwmvar.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/dev/iwm/if_iwm.c ============================================================================== --- stable/11/sys/dev/iwm/if_iwm.c Thu Mar 1 06:39:14 2018 (r330207) +++ stable/11/sys/dev/iwm/if_iwm.c Thu Mar 1 06:39:44 2018 (r330208) @@ -168,6 +168,9 @@ __FBSDID("$FreeBSD$"); #include #include +/* From DragonflyBSD */ +#define mtodoff(m, t, off) ((t)((m)->m_data + (off))) + const uint8_t iwm_nvm_channels[] = { /* 2.4 GHz */ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, @@ -319,16 +322,15 @@ static int iwm_rx_addbuf(struct iwm_softc *, int, int) static int iwm_mvm_get_signal_strength(struct iwm_softc *, struct iwm_rx_phy_info *); static void iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *, - struct iwm_rx_packet *, - struct iwm_rx_data *); + struct iwm_rx_packet *); static int iwm_get_noise(struct iwm_softc *sc, const struct iwm_mvm_statistics_rx_non_phy *); -static void iwm_mvm_rx_rx_mpdu(struct iwm_softc *, struct mbuf *); +static boolean_t iwm_mvm_rx_rx_mpdu(struct iwm_softc *, struct mbuf *, + uint32_t, boolean_t); static int iwm_mvm_rx_tx_cmd_single(struct iwm_softc *, struct iwm_rx_packet *, struct iwm_node *); -static void iwm_mvm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *, - struct iwm_rx_data *); +static void iwm_mvm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *); static void iwm_cmd_done(struct iwm_softc *, struct iwm_rx_packet *); #if 0 static void iwm_update_sched(struct iwm_softc *, int, int, uint8_t, @@ -384,6 +386,7 @@ static const char * static void iwm_nic_error(struct iwm_softc *); static void iwm_nic_umac_error(struct iwm_softc *); #endif +static void iwm_handle_rxb(struct iwm_softc *, struct mbuf *); static void iwm_notif_intr(struct iwm_softc *); static void iwm_intr(void *); static int iwm_attach(device_t); @@ -1431,14 +1434,21 @@ iwm_nic_rx_init(struct iwm_softc *sc) IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG, sc->rxq.stat_dma.paddr >> 4); - /* Enable RX. */ + /* Enable Rx DMA + * XXX 5000 HW isn't supported by the iwm(4) driver. + * IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in + * the credit mechanism in 5000 HW RX FIFO + * Direct rx interrupts to hosts + * Rx buffer size 4 or 8k or 12k + * RB timeout 0x10 + * 256 RBDs + */ IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | /* HW bug */ IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - IWM_FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | - (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) | IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K | + (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) | IWM_RX_QUEUE_SIZE_LOG << IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS); IWM_WRITE_1(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_TIMEOUT_DEF); @@ -3125,13 +3135,11 @@ iwm_mvm_get_signal_strength(struct iwm_softc *sc, stru } static void -iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *sc, - struct iwm_rx_packet *pkt, struct iwm_rx_data *data) +iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt) { struct iwm_rx_phy_info *phy_info = (void *)pkt->data; IWM_DPRINTF(sc, IWM_DEBUG_RECV, "received PHY stats\n"); - bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); memcpy(&sc->sc_last_phy_info, phy_info, sizeof(sc->sc_last_phy_info)); } @@ -3175,8 +3183,9 @@ iwm_get_noise(struct iwm_softc *sc, * * Handles the actual data of the Rx packet from the fw */ -static void -iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m) +static boolean_t +iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, uint32_t offset, + boolean_t stolen) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); @@ -3185,7 +3194,7 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf * struct ieee80211_rx_stats rxs; struct iwm_rx_phy_info *phy_info; struct iwm_rx_mpdu_res_start *rx_res; - struct iwm_rx_packet *pkt = mtod(m, struct iwm_rx_packet *); + struct iwm_rx_packet *pkt = mtodoff(m, struct iwm_rx_packet *, offset); uint32_t len; uint32_t rx_pkt_status; int rssi; @@ -3216,7 +3225,7 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf * rssi = rssi - sc->sc_noise; /* replenish ring for the buffer we're going to feed to the sharks */ - if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0) { + if (!stolen && iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0) { device_printf(sc->sc_dev, "%s: unable to add more buffers\n", __func__); goto fail; @@ -3296,9 +3305,10 @@ iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc, struct mbuf * } IWM_LOCK(sc); - return; + return TRUE; fail: counter_u64_add(ic->ic_ierrors, 1); + return FALSE; } static int @@ -3338,8 +3348,7 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct } static void -iwm_mvm_rx_tx_cmd(struct iwm_softc *sc, - struct iwm_rx_packet *pkt, struct iwm_rx_data *data) +iwm_mvm_rx_tx_cmd(struct iwm_softc *sc, struct iwm_rx_packet *pkt) { struct iwm_cmd_header *cmd_hdr = &pkt->hdr; int idx = cmd_hdr->idx; @@ -3354,8 +3363,6 @@ iwm_mvm_rx_tx_cmd(struct iwm_softc *sc, KASSERT(txd->in != NULL, ("txd without node")); KASSERT(txd->m != NULL, ("txd without mbuf")); - bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD); - sc->sc_tx_timer = 0; status = iwm_mvm_rx_tx_cmd_single(sc, pkt, in); @@ -5358,68 +5365,95 @@ iwm_nic_error(struct iwm_softc *sc) } #endif -#define ADVANCE_RXQ(sc) (sc->rxq.cur = (sc->rxq.cur + 1) % IWM_RX_RING_COUNT); - -/* - * Process an IWM_CSR_INT_BIT_FH_RX or IWM_CSR_INT_BIT_SW_RX interrupt. - * Basic structure from if_iwn - */ static void -iwm_notif_intr(struct iwm_softc *sc) +iwm_handle_rxb(struct iwm_softc *sc, struct mbuf *m) { struct ieee80211com *ic = &sc->sc_ic; - uint16_t hw; + struct iwm_cmd_response *cresp; + struct mbuf *m1; + uint32_t offset = 0; + uint32_t maxoff = IWM_RBUF_SIZE; + uint32_t nextoff; + boolean_t stolen = FALSE; - bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map, - BUS_DMASYNC_POSTREAD); +#define HAVEROOM(a) \ + ((a) + sizeof(uint32_t) + sizeof(struct iwm_cmd_header) < maxoff) - hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff; + while (HAVEROOM(offset)) { + struct iwm_rx_packet *pkt = mtodoff(m, struct iwm_rx_packet *, + offset); + int qid, idx, code, len; - /* - * Process responses - */ - while (sc->rxq.cur != hw) { - struct iwm_rx_ring *ring = &sc->rxq; - struct iwm_rx_data *data = &ring->data[ring->cur]; - struct iwm_rx_packet *pkt; - struct iwm_cmd_response *cresp; - int qid, idx, code; - - bus_dmamap_sync(ring->data_dmat, data->map, - BUS_DMASYNC_POSTREAD); - pkt = mtod(data->m, struct iwm_rx_packet *); - - qid = pkt->hdr.qid & ~0x80; + qid = pkt->hdr.qid; idx = pkt->hdr.idx; code = IWM_WIDE_ID(pkt->hdr.flags, pkt->hdr.code); - IWM_DPRINTF(sc, IWM_DEBUG_INTR, - "rx packet qid=%d idx=%d type=%x %d %d\n", - pkt->hdr.qid & ~0x80, pkt->hdr.idx, code, ring->cur, hw); /* * randomly get these from the firmware, no idea why. * they at least seem harmless, so just ignore them for now */ - if (__predict_false((pkt->hdr.code == 0 && qid == 0 && idx == 0) - || pkt->len_n_flags == htole32(0x55550000))) { - ADVANCE_RXQ(sc); - continue; + if ((pkt->hdr.code == 0 && (qid & ~0x80) == 0 && idx == 0) || + pkt->len_n_flags == htole32(IWM_FH_RSCSR_FRAME_INVALID)) { + break; } + IWM_DPRINTF(sc, IWM_DEBUG_INTR, + "rx packet qid=%d idx=%d type=%x\n", + qid & ~0x80, pkt->hdr.idx, code); + + len = le32toh(pkt->len_n_flags) & IWM_FH_RSCSR_FRAME_SIZE_MSK; + len += sizeof(uint32_t); /* account for status word */ + nextoff = offset + roundup2(len, IWM_FH_RSCSR_FRAME_ALIGN); + iwm_notification_wait_notify(sc->sc_notif_wait, code, pkt); switch (code) { case IWM_REPLY_RX_PHY_CMD: - iwm_mvm_rx_rx_phy_cmd(sc, pkt, data); + iwm_mvm_rx_rx_phy_cmd(sc, pkt); break; - case IWM_REPLY_RX_MPDU_CMD: - iwm_mvm_rx_rx_mpdu(sc, data->m); + case IWM_REPLY_RX_MPDU_CMD: { + /* + * If this is the last frame in the RX buffer, we + * can directly feed the mbuf to the sharks here. + */ + struct iwm_rx_packet *nextpkt = mtodoff(m, + struct iwm_rx_packet *, nextoff); + if (!HAVEROOM(nextoff) || + (nextpkt->hdr.code == 0 && + (nextpkt->hdr.qid & ~0x80) == 0 && + nextpkt->hdr.idx == 0) || + (nextpkt->len_n_flags == + htole32(IWM_FH_RSCSR_FRAME_INVALID))) { + if (iwm_mvm_rx_rx_mpdu(sc, m, offset, stolen)) { + stolen = FALSE; + /* Make sure we abort the loop */ + nextoff = maxoff; + } + break; + } + + /* + * Use m_copym instead of m_split, because that + * makes it easier to keep a valid rx buffer in + * the ring, when iwm_mvm_rx_rx_mpdu() fails. + * + * We need to start m_copym() at offset 0, to get the + * M_PKTHDR flag preserved. + */ + m1 = m_copym(m, 0, M_COPYALL, M_NOWAIT); + if (m1) { + if (iwm_mvm_rx_rx_mpdu(sc, m1, offset, stolen)) + stolen = TRUE; + else + m_freem(m1); + } break; + } case IWM_TX_CMD: - iwm_mvm_rx_tx_cmd(sc, pkt, data); + iwm_mvm_rx_tx_cmd(sc, pkt); break; case IWM_MISSED_BEACONS_NOTIFICATION: { @@ -5480,7 +5514,7 @@ iwm_notif_intr(struct iwm_softc *sc) case IWM_NVM_ACCESS_CMD: case IWM_MCC_UPDATE_CMD: - if (sc->sc_wantresp == ((qid << 16) | idx)) { + if (sc->sc_wantresp == (((qid & ~0x80) << 16) | idx)) { memcpy(sc->sc_cmd_resp, pkt, sizeof(sc->sc_cmd_resp)); } @@ -5540,7 +5574,7 @@ iwm_notif_intr(struct iwm_softc *sc) case IWM_BT_CONFIG: case IWM_REPLY_THERMAL_MNG_BACKOFF: cresp = (void *)pkt->data; - if (sc->sc_wantresp == ((qid << 16) | idx)) { + if (sc->sc_wantresp == (((qid & ~0x80) << 16) | idx)) { memcpy(sc->sc_cmd_resp, pkt, sizeof(*pkt)+sizeof(*cresp)); } @@ -5634,7 +5668,7 @@ iwm_notif_intr(struct iwm_softc *sc) default: device_printf(sc->sc_dev, "frame %d/%d %x UNHANDLED (this should " - "not happen)\n", qid, idx, + "not happen)\n", qid & ~0x80, idx, pkt->len_n_flags); break; } @@ -5653,20 +5687,55 @@ iwm_notif_intr(struct iwm_softc *sc) * uses a slightly different format for pkt->hdr, and "qid" * is actually the upper byte of a two-byte field. */ - if (!(pkt->hdr.qid & (1 << 7))) { + if (!(qid & (1 << 7))) iwm_cmd_done(sc, pkt); - } - ADVANCE_RXQ(sc); + offset = nextoff; } + if (stolen) + m_freem(m); +#undef HAVEROOM +} +/* + * Process an IWM_CSR_INT_BIT_FH_RX or IWM_CSR_INT_BIT_SW_RX interrupt. + * Basic structure from if_iwn + */ +static void +iwm_notif_intr(struct iwm_softc *sc) +{ + uint16_t hw; + + bus_dmamap_sync(sc->rxq.stat_dma.tag, sc->rxq.stat_dma.map, + BUS_DMASYNC_POSTREAD); + + hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff; + /* - * Tell the firmware what we have processed. + * Process responses + */ + while (sc->rxq.cur != hw) { + struct iwm_rx_ring *ring = &sc->rxq; + struct iwm_rx_data *data = &ring->data[ring->cur]; + + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTREAD); + + IWM_DPRINTF(sc, IWM_DEBUG_INTR, + "%s: hw = %d cur = %d\n", __func__, hw, ring->cur); + iwm_handle_rxb(sc, data->m); + + ring->cur = (ring->cur + 1) % IWM_RX_RING_COUNT; + } + + /* + * Tell the firmware that it can reuse the ring entries that + * we have just processed. * Seems like the hardware gets upset unless we align * the write by 8?? */ hw = (hw == 0) ? IWM_RX_RING_COUNT - 1 : hw - 1; - IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, hw & ~7); + IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, rounddown2(hw, 8)); } static void Modified: stable/11/sys/dev/iwm/if_iwmreg.h ============================================================================== --- stable/11/sys/dev/iwm/if_iwmreg.h Thu Mar 1 06:39:14 2018 (r330207) +++ stable/11/sys/dev/iwm/if_iwmreg.h Thu Mar 1 06:39:44 2018 (r330208) @@ -5972,16 +5972,9 @@ struct iwm_dts_measurement_notif_v2 { #define IWM_FRAME_LIMIT 64 /* - * From Linux commit ab02165ccec4c78162501acedeef1a768acdb811: - * As the firmware is slowly running out of command IDs and grouping of - * commands is desirable anyway, the firmware is extending the command - * header from 4 bytes to 8 bytes to introduce a group (in place of the - * former flags field, since that's always 0 on commands and thus can - * be easily used to distinguish between the two). - * * These functions retrieve specific information from the id field in * the iwm_host_cmd struct which contains the command id, the group id, - * and the version of the command. + * and the version of the command and vice versa. */ static inline uint8_t iwm_cmd_opcode(uint32_t cmdid) @@ -5992,7 +5985,7 @@ iwm_cmd_opcode(uint32_t cmdid) static inline uint8_t iwm_cmd_groupid(uint32_t cmdid) { - return ((cmdid & 0Xff00) >> 8); + return ((cmdid & 0xff00) >> 8); } static inline uint8_t @@ -6085,6 +6078,8 @@ struct iwm_rx_packet { } __packed; #define IWM_FH_RSCSR_FRAME_SIZE_MSK 0x00003fff +#define IWM_FH_RSCSR_FRAME_INVALID 0x55550000 +#define IWM_FH_RSCSR_FRAME_ALIGN 0x40 static inline uint32_t iwm_rx_packet_len(const struct iwm_rx_packet *pkt) Modified: stable/11/sys/dev/iwm/if_iwmvar.h ============================================================================== --- stable/11/sys/dev/iwm/if_iwmvar.h Thu Mar 1 06:39:14 2018 (r330207) +++ stable/11/sys/dev/iwm/if_iwmvar.h Thu Mar 1 06:39:44 2018 (r330208) @@ -304,7 +304,6 @@ struct iwm_tx_ring { }; #define IWM_RX_RING_COUNT 256 -#define IWM_RBUF_COUNT (IWM_RX_RING_COUNT + 32) /* Linux driver optionally uses 8k buffer */ #define IWM_RBUF_SIZE 4096