Index: head/sys/dev/iwn/if_iwn.c =================================================================== --- head/sys/dev/iwn/if_iwn.c +++ head/sys/dev/iwn/if_iwn.c @@ -232,6 +232,8 @@ static int iwn_tx_data_raw(struct iwn_softc *, struct mbuf *, struct ieee80211_node *, const struct ieee80211_bpf_params *params); +static int iwn_tx_cmd(struct iwn_softc *, struct mbuf *, + struct ieee80211_node *, struct iwn_tx_ring *); static void iwn_xmit_task(void *arg0, int pending); static int iwn_raw_xmit(struct ieee80211_node *, struct mbuf *, const struct ieee80211_bpf_params *); @@ -4392,32 +4394,25 @@ static int iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - struct iwn_ops *ops = &sc->ops; const struct ieee80211_txparam *tp = ni->ni_txparms; struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; struct iwn_node *wn = (void *)ni; struct iwn_tx_ring *ring; - struct iwn_tx_desc *desc; - struct iwn_tx_data *data; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; - struct mbuf *m1; uint32_t flags; - uint16_t qos; - u_int hdrlen; - bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; + uint16_t seqno, qos; uint8_t tid, type; - int ac, i, totlen, error, pad, nsegs = 0, rate; + int ac, totlen, rate; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); IWN_LOCK_ASSERT(sc); wh = mtod(m, struct ieee80211_frame *); - hdrlen = ieee80211_anyhdrsize(wh); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; /* Select EDCA Access Category and TX ring for this frame. */ @@ -4428,7 +4423,21 @@ qos = 0; tid = 0; } - ac = M_WME_GETAC(m); + + /* Choose a TX rate index. */ + if (type == IEEE80211_FC0_TYPE_MGT || + type == IEEE80211_FC0_TYPE_CTL || + (m->m_flags & M_EAPOL) != 0) + rate = tp->mgmtrate; + else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + rate = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + rate = tp->ucastrate; + else { + /* XXX pass pktlen */ + (void) ieee80211_ratectl_rate(ni, NULL, 0); + rate = ni->ni_txrate; + } /* * XXX TODO: Group addressed frames aren't aggregated and must @@ -4436,12 +4445,13 @@ * assigned from net80211. */ + ac = M_WME_GETAC(m); + seqno = ni->ni_txseqs[tid]; if (m->m_flags & M_AMPDU_MPDU) { - uint16_t seqno; struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; if (!IEEE80211_AMPDU_RUNNING(tap)) { - return EINVAL; + return (EINVAL); } /* @@ -4452,39 +4462,10 @@ * being used! */ ac = *(int *)tap->txa_private; - seqno = ni->ni_txseqs[tid]; *(uint16_t *)wh->i_seq = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); - ring = &sc->txq[ac]; - if ((seqno % 256) != ring->cur) { - device_printf(sc->sc_dev, - "%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n", - __func__, - m, - seqno, - seqno % 256, - ring->cur); - } ni->ni_txseqs[tid]++; } - ring = &sc->txq[ac]; - desc = &ring->desc[ring->cur]; - data = &ring->data[ring->cur]; - - /* Choose a TX rate index. */ - if (type == IEEE80211_FC0_TYPE_MGT || - type == IEEE80211_FC0_TYPE_CTL || - (m->m_flags & M_EAPOL) != 0) - rate = tp->mgmtrate; - else if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; - else { - /* XXX pass pktlen */ - (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; - } /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { @@ -4509,17 +4490,6 @@ ieee80211_radiotap_tx(vap, m); } - /* Prepare TX firmware command. */ - cmd = &ring->cmd[ring->cur]; - cmd->code = IWN_CMD_TX_DATA; - cmd->flags = 0; - cmd->qid = ring->qid; - cmd->idx = ring->cur; - - tx = (struct iwn_cmd_data *)cmd->data; - /* NB: No need to clear tx, all fields are reinitialized here. */ - tx->scratch = 0; /* clear "scratch" area */ - flags = 0; if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { /* Unicast frame, check if an ACK is expected. */ @@ -4562,6 +4532,25 @@ } } + ring = &sc->txq[ac]; + if ((m->m_flags & M_AMPDU_MPDU) != 0 && + (seqno % 256) != ring->cur) { + device_printf(sc->sc_dev, + "%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n", + __func__, + m, + seqno, + seqno % 256, + ring->cur); + } + + /* Prepare TX firmware command. */ + cmd = &ring->cmd[ring->cur]; + tx = (struct iwn_cmd_data *)cmd->data; + + /* NB: No need to clear tx, all fields are reinitialized here. */ + tx->scratch = 0; /* clear "scratch" area */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1) || type != IEEE80211_FC0_TYPE_DATA) tx->id = sc->broadcast_id; @@ -4582,19 +4571,6 @@ } else tx->timeout = htole16(0); - if (hdrlen & 3) { - /* First segment length must be a multiple of 4. */ - flags |= IWN_TX_NEED_PADDING; - pad = 4 - (hdrlen & 3); - } else - pad = 0; - - tx->len = htole16(totlen); - tx->tid = tid; - tx->rts_ntries = 60; - tx->data_ntries = 15; - tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - tx->rate = iwn_rate_to_plcp(sc, ni, rate); if (tx->id == sc->broadcast_id) { /* Group or management frame. */ tx->linkq = 0; @@ -4603,115 +4579,28 @@ flags |= IWN_TX_LINKQ; /* enable MRR */ } - /* Set physical address of "scratch area". */ - tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); - tx->hiaddr = IWN_HIADDR(data->scratch_paddr); - - /* Copy 802.11 header in TX command. */ - memcpy((uint8_t *)(tx + 1), wh, hdrlen); - - /* Trim 802.11 header. */ - m_adj(m, hdrlen); + tx->tid = tid; + tx->rts_ntries = 60; + tx->data_ntries = 15; + tx->lifetime = htole32(IWN_LIFETIME_INFINITE); + tx->rate = iwn_rate_to_plcp(sc, ni, rate); tx->security = 0; tx->flags = htole32(flags); - error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, - &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - if (error != EFBIG) { - device_printf(sc->sc_dev, - "%s: can't map mbuf (error %d)\n", __func__, error); - return error; - } - /* Too many DMA segments, linearize mbuf. */ - m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER - 1); - if (m1 == NULL) { - device_printf(sc->sc_dev, - "%s: could not defrag mbuf\n", __func__); - return ENOBUFS; - } - m = m1; - - error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, - segs, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: can't map mbuf (error %d)\n", __func__, error); - return error; - } - } - - data->m = m; - data->ni = ni; - - DPRINTF(sc, IWN_DEBUG_XMIT, - "%s: qid %d idx %d len %d nsegs %d flags 0x%08x rate 0x%04x plcp 0x%08x\n", - __func__, - ring->qid, - ring->cur, - m->m_pkthdr.len, - nsegs, - flags, - rate, - tx->rate); - - /* Fill TX descriptor. */ - desc->nsegs = 1; - if (m->m_len != 0) - desc->nsegs += nsegs; - /* First DMA segment is used by the TX command. */ - desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr)); - desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) | - (4 + sizeof (*tx) + hdrlen + pad) << 4); - /* Other DMA segments are for data payload. */ - seg = &segs[0]; - for (i = 1; i <= nsegs; i++) { - desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr)); - desc->segs[i].len = htole16(IWN_HIADDR(seg->ds_addr) | - seg->ds_len << 4); - seg++; - } - - bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(ring->cmd_dma.tag, ring->cmd_dma.map, - BUS_DMASYNC_PREWRITE); - bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map, - BUS_DMASYNC_PREWRITE); - - /* Update TX scheduler. */ - if (ring->qid >= sc->firstaggqueue) - ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen); - - /* Kick TX ring. */ - ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT; - IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur); - - /* Mark TX ring as full if we reach a certain threshold. */ - if (++ring->queued > IWN_TX_RING_HIMARK) - sc->qfullmsk |= 1 << ring->qid; - - DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); - - return 0; + return (iwn_tx_cmd(sc, m, ni, ring)); } static int iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { - struct iwn_ops *ops = &sc->ops; struct ieee80211vap *vap = ni->ni_vap; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; struct iwn_tx_ring *ring; - struct iwn_tx_desc *desc; - struct iwn_tx_data *data; - struct mbuf *m1; - bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; uint32_t flags; - u_int hdrlen; - int ac, totlen, error, pad, nsegs = 0, i, rate; + int ac, rate; uint8_t type; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -4719,29 +4608,12 @@ IWN_LOCK_ASSERT(sc); wh = mtod(m, struct ieee80211_frame *); - hdrlen = ieee80211_anyhdrsize(wh); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; ac = params->ibp_pri & 3; - ring = &sc->txq[ac]; - desc = &ring->desc[ring->cur]; - data = &ring->data[ring->cur]; - /* Choose a TX rate. */ rate = params->ibp_rate0; - totlen = m->m_pkthdr.len; - - /* Prepare TX firmware command. */ - cmd = &ring->cmd[ring->cur]; - cmd->code = IWN_CMD_TX_DATA; - cmd->flags = 0; - cmd->qid = ring->qid; - cmd->idx = ring->cur; - - tx = (struct iwn_cmd_data *)cmd->data; - /* NB: No need to clear tx, all fields are reinitialized here. */ - tx->scratch = 0; /* clear "scratch" area */ flags = 0; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) @@ -4762,6 +4634,23 @@ } else flags |= IWN_TX_NEED_CTS | IWN_TX_FULL_TXOP; } + + if (ieee80211_radiotap_active_vap(vap)) { + struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = 0; + tap->wt_rate = rate; + + ieee80211_radiotap_tx(vap, m); + } + + ring = &sc->txq[ac]; + cmd = &ring->cmd[ring->cur]; + + tx = (struct iwn_cmd_data *)cmd->data; + /* NB: No need to clear tx, all fields are reinitialized here. */ + tx->scratch = 0; /* clear "scratch" area */ + if (type == IEEE80211_FC0_TYPE_MGT) { uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; @@ -4777,44 +4666,68 @@ } else tx->timeout = htole16(0); - if (hdrlen & 3) { - /* First segment length must be a multiple of 4. */ - flags |= IWN_TX_NEED_PADDING; - pad = 4 - (hdrlen & 3); - } else - pad = 0; - - if (ieee80211_radiotap_active_vap(vap)) { - struct iwn_tx_radiotap_header *tap = &sc->sc_txtap; - - tap->wt_flags = 0; - tap->wt_rate = rate; - - ieee80211_radiotap_tx(vap, m); - } - - tx->len = htole16(totlen); tx->tid = 0; tx->id = sc->broadcast_id; tx->rts_ntries = params->ibp_try1; tx->data_ntries = params->ibp_try0; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); tx->rate = iwn_rate_to_plcp(sc, ni, rate); + tx->security = 0; + tx->flags = htole32(flags); /* Group or management frame. */ tx->linkq = 0; + return (iwn_tx_cmd(sc, m, ni, ring)); +} + +static int +iwn_tx_cmd(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni, + struct iwn_tx_ring *ring) +{ + struct iwn_ops *ops = &sc->ops; + struct iwn_tx_cmd *cmd; + struct iwn_cmd_data *tx; + struct ieee80211_frame *wh; + struct iwn_tx_desc *desc; + struct iwn_tx_data *data; + bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; + struct mbuf *m1; + u_int hdrlen; + int totlen, error, pad, nsegs = 0, i; + + wh = mtod(m, struct ieee80211_frame *); + hdrlen = ieee80211_anyhdrsize(wh); + totlen = m->m_pkthdr.len; + + desc = &ring->desc[ring->cur]; + data = &ring->data[ring->cur]; + + /* Prepare TX firmware command. */ + cmd = &ring->cmd[ring->cur]; + cmd->code = IWN_CMD_TX_DATA; + cmd->flags = 0; + cmd->qid = ring->qid; + cmd->idx = ring->cur; + + tx = (struct iwn_cmd_data *)cmd->data; + tx->len = htole16(totlen); + /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); tx->hiaddr = IWN_HIADDR(data->scratch_paddr); + if (hdrlen & 3) { + /* First segment length must be a multiple of 4. */ + tx->flags |= htole32(IWN_TX_NEED_PADDING); + pad = 4 - (hdrlen & 3); + } else + pad = 0; /* Copy 802.11 header in TX command. */ memcpy((uint8_t *)(tx + 1), wh, hdrlen); /* Trim 802.11 header. */ m_adj(m, hdrlen); - tx->security = 0; - tx->flags = htole32(flags); error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, &nsegs, BUS_DMA_NOWAIT); @@ -4845,8 +4758,9 @@ data->m = m; data->ni = ni; - DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d\n", - __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs); + DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d " + "plcp %d\n", + __func__, ring->qid, ring->cur, totlen, nsegs, tx->rate); /* Fill TX descriptor. */ desc->nsegs = 1;