Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 May 2011 12:06:12 +0000 (UTC)
From:      Bernhard Schmidt <bschmidt@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r221651 - head/sys/dev/iwn
Message-ID:  <201105081206.p48C6CnJ045131@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bschmidt
Date: Sun May  8 12:06:12 2011
New Revision: 221651
URL: http://svn.freebsd.org/changeset/base/221651

Log:
  Add support for TX packet aggregation.

Modified:
  head/sys/dev/iwn/if_iwn.c
  head/sys/dev/iwn/if_iwnreg.h
  head/sys/dev/iwn/if_iwnvar.h

Modified: head/sys/dev/iwn/if_iwn.c
==============================================================================
--- head/sys/dev/iwn/if_iwn.c	Sun May  8 11:58:23 2011	(r221650)
+++ head/sys/dev/iwn/if_iwn.c	Sun May  8 12:06:12 2011	(r221651)
@@ -172,10 +172,8 @@ static void	iwn_rx_phy(struct iwn_softc 
 		    struct iwn_rx_data *);
 static void	iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
 		    struct iwn_rx_data *);
-#if 0	/* HT */
 static void	iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
 		    struct iwn_rx_data *);
-#endif
 static void	iwn5000_rx_calib_results(struct iwn_softc *,
 		    struct iwn_rx_desc *, struct iwn_rx_data *);
 static void	iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *,
@@ -186,6 +184,7 @@ static void	iwn5000_tx_done(struct iwn_s
 		    struct iwn_rx_data *);
 static void	iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int,
 		    uint8_t);
+static void	iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, void *);
 static void	iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
 static void	iwn_notif_intr(struct iwn_softc *);
 static void	iwn_wakeup_intr(struct iwn_softc *);
@@ -255,20 +254,22 @@ static int	iwn_ampdu_rx_start(struct iee
 		    struct ieee80211_rx_ampdu *, int, int, int);
 static void	iwn_ampdu_rx_stop(struct ieee80211_node *,
 		    struct ieee80211_rx_ampdu *);
-#if 0	/* HT */
+static int	iwn_addba_request(struct ieee80211_node *,
+		    struct ieee80211_tx_ampdu *, int, int, int);
+static int	iwn_addba_response(struct ieee80211_node *,
+		    struct ieee80211_tx_ampdu *, int, int, int);
 static int	iwn_ampdu_tx_start(struct ieee80211com *,
 		    struct ieee80211_node *, uint8_t);
-static void	iwn_ampdu_tx_stop(struct ieee80211com *,
-		    struct ieee80211_node *, uint8_t);
+static void	iwn_ampdu_tx_stop(struct ieee80211_node *,
+		    struct ieee80211_tx_ampdu *);
 static void	iwn4965_ampdu_tx_start(struct iwn_softc *,
-		    struct ieee80211_node *, uint8_t, uint16_t);
-static void	iwn4965_ampdu_tx_stop(struct iwn_softc *,
+		    struct ieee80211_node *, int, uint8_t, uint16_t);
+static void	iwn4965_ampdu_tx_stop(struct iwn_softc *, int,
 		    uint8_t, uint16_t);
 static void	iwn5000_ampdu_tx_start(struct iwn_softc *,
-		    struct ieee80211_node *, uint8_t, uint16_t);
-static void	iwn5000_ampdu_tx_stop(struct iwn_softc *,
+		    struct ieee80211_node *, int, uint8_t, uint16_t);
+static void	iwn5000_ampdu_tx_stop(struct iwn_softc *, int,
 		    uint8_t, uint16_t);
-#endif
 static int	iwn5000_query_calibration(struct iwn_softc *);
 static int	iwn5000_send_calibration(struct iwn_softc *);
 static int	iwn5000_send_wimax_coex(struct iwn_softc *);
@@ -657,10 +658,12 @@ iwn_attach(device_t dev)
 	ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
 	sc->sc_ampdu_rx_stop = ic->ic_ampdu_rx_stop;
 	ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop;
-#if 0	/* HT */
-	ic->ic_ampdu_tx_start = iwn_ampdu_tx_start;
-	ic->ic_ampdu_tx_stop = iwn_ampdu_tx_stop;
-#endif
+	sc->sc_addba_request = ic->ic_addba_request;
+	ic->ic_addba_request = iwn_addba_request;
+	sc->sc_addba_response = ic->ic_addba_response;
+	ic->ic_addba_response = iwn_addba_response;
+	sc->sc_addba_stop = ic->ic_addba_stop;
+	ic->ic_addba_stop = iwn_ampdu_tx_stop;
 	ic->ic_newassoc = iwn_newassoc;
 	ic->ic_wme.wme_update = iwn_updateedca;
 	ic->ic_update_mcast = iwn_update_mcast;
@@ -717,11 +720,10 @@ iwn4965_attach(struct iwn_softc *sc, uin
 	ops->set_gains = iwn4965_set_gains;
 	ops->add_node = iwn4965_add_node;
 	ops->tx_done = iwn4965_tx_done;
-#if 0	/* HT */
 	ops->ampdu_tx_start = iwn4965_ampdu_tx_start;
 	ops->ampdu_tx_stop = iwn4965_ampdu_tx_stop;
-#endif
 	sc->ntxqs = IWN4965_NTXQUEUES;
+	sc->firstaggqueue = IWN4965_FIRSTAGGQUEUE;
 	sc->ndmachnls = IWN4965_NDMACHNLS;
 	sc->broadcast_id = IWN4965_ID_BROADCAST;
 	sc->rxonsz = IWN4965_RXONSZ;
@@ -756,11 +758,10 @@ iwn5000_attach(struct iwn_softc *sc, uin
 	ops->set_gains = iwn5000_set_gains;
 	ops->add_node = iwn5000_add_node;
 	ops->tx_done = iwn5000_tx_done;
-#if 0	/* HT */
 	ops->ampdu_tx_start = iwn5000_ampdu_tx_start;
 	ops->ampdu_tx_stop = iwn5000_ampdu_tx_stop;
-#endif
 	sc->ntxqs = IWN5000_NTXQUEUES;
+	sc->firstaggqueue = IWN5000_FIRSTAGGQUEUE;
 	sc->ndmachnls = IWN5000_NDMACHNLS;
 	sc->broadcast_id = IWN5000_ID_BROADCAST;
 	sc->rxonsz = IWN5000_RXONSZ;
@@ -2447,21 +2448,53 @@ iwn_rx_done(struct iwn_softc *sc, struct
 	IWN_LOCK(sc);
 }
 
-#if 0	/* HT */
 /* Process an incoming Compressed BlockAck. */
 static void
 iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
     struct iwn_rx_data *data)
 {
+	struct ifnet *ifp = sc->sc_ifp;
+	struct iwn_node *wn;
+	struct ieee80211_node *ni;
 	struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1);
 	struct iwn_tx_ring *txq;
+	struct ieee80211_tx_ampdu *tap;
+	uint64_t bitmap;
+	uint8_t tid;
+	int ackfailcnt = 0, i, shift;
 
 	bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
 
-	txq = &sc->txq[letoh16(ba->qid)];
-	/* XXX TBD */
+	txq = &sc->txq[le16toh(ba->qid)];
+	tap = sc->qid2tap[le16toh(ba->qid)];
+	tid = WME_AC_TO_TID(tap->txa_ac);
+	ni = tap->txa_ni;
+	wn = (void *)ni;
+
+	if (wn->agg[tid].bitmap == 0)
+		return;
+
+	shift = wn->agg[tid].startidx - ((le16toh(ba->seq) >> 4) & 0xff);
+	if (shift < 0)
+		shift += 0x100;
+
+	if (wn->agg[tid].nframes > (64 - shift))
+		return;
+
+	bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap;
+	for (i = 0; bitmap; i++) {
+		if ((bitmap & 1) == 0) {
+			ifp->if_oerrors++;
+			ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
+			    IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL);
+		} else {
+			ifp->if_opackets++;
+			ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
+			    IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL);
+		}
+		bitmap >>= 1;
+	}
 }
-#endif
 
 /*
  * Process a CALIBRATION_RESULT notification sent by the initialization
@@ -2590,7 +2623,11 @@ iwn4965_tx_done(struct iwn_softc *sc, st
     struct iwn_rx_data *data)
 {
 	struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1);
-	struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
+	struct iwn_tx_ring *ring;
+	int qid;
+
+	qid = desc->qid & 0xf;
+	ring = &sc->txq[qid];
 
 	DPRINTF(sc, IWN_DEBUG_XMIT, "%s: "
 	    "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n",
@@ -2599,7 +2636,13 @@ iwn4965_tx_done(struct iwn_softc *sc, st
 	    le32toh(stat->status));
 
 	bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
-	iwn_tx_done(sc, desc, stat->ackfailcnt, le32toh(stat->status) & 0xff);
+	if (qid >= sc->firstaggqueue) {
+		iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
+		    &stat->status);
+	} else {
+		iwn_tx_done(sc, desc, stat->ackfailcnt,
+		    le32toh(stat->status) & 0xff);
+	}
 }
 
 static void
@@ -2607,7 +2650,11 @@ iwn5000_tx_done(struct iwn_softc *sc, st
     struct iwn_rx_data *data)
 {
 	struct iwn5000_tx_stat *stat = (struct iwn5000_tx_stat *)(desc + 1);
-	struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
+	struct iwn_tx_ring *ring;
+	int qid;
+
+	qid = desc->qid & 0xf;
+	ring = &sc->txq[qid];
 
 	DPRINTF(sc, IWN_DEBUG_XMIT, "%s: "
 	    "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n",
@@ -2621,7 +2668,13 @@ iwn5000_tx_done(struct iwn_softc *sc, st
 #endif
 
 	bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
-	iwn_tx_done(sc, desc, stat->ackfailcnt, le16toh(stat->status) & 0xff);
+	if (qid >= sc->firstaggqueue) {
+		iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
+		    &stat->status);
+	} else {
+		iwn_tx_done(sc, desc, stat->ackfailcnt,
+		    le16toh(stat->status) & 0xff);
+	}
 }
 
 /*
@@ -2722,6 +2775,96 @@ iwn_cmd_done(struct iwn_softc *sc, struc
 	wakeup(&ring->desc[desc->idx]);
 }
 
+static void
+iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
+    void *stat)
+{
+	struct ifnet *ifp = sc->sc_ifp;
+	struct iwn_tx_ring *ring = &sc->txq[qid];
+	struct iwn_tx_data *data;
+	struct mbuf *m;
+	struct iwn_node *wn;
+	struct ieee80211_node *ni;
+	struct ieee80211vap *vap;
+	struct ieee80211_tx_ampdu *tap;
+	uint64_t bitmap;
+	uint32_t *status = stat;
+	uint16_t *aggstatus = stat;
+	uint8_t tid;
+	int bit, i, lastidx, seqno, shift, start;
+
+#ifdef NOT_YET
+	if (nframes == 1) {
+		if ((*status & 0xff) != 1 && (*status & 0xff) != 2)
+			printf("ieee80211_send_bar()\n");
+	}
+#endif
+
+	bitmap = 0;
+	start = idx;
+	for (i = 0; i < nframes; i++) {
+		if (le16toh(aggstatus[i * 2]) & 0xc)
+			continue;
+
+		idx = le16toh(aggstatus[2*i + 1]) & 0xff;
+		bit = idx - start;
+		shift = 0;
+		if (bit >= 64) {
+			shift = 0x100 - idx + start;
+			bit = 0;
+			start = idx;
+		} else if (bit <= -64)
+			bit = 0x100 - start + idx;
+		else if (bit < 0) {
+			shift = start - idx;
+			start = idx;
+			bit = 0;
+		}
+		bitmap = bitmap << shift;
+		bitmap |= 1ULL << bit;
+	}
+	tap = sc->qid2tap[qid];
+	tid = WME_AC_TO_TID(tap->txa_ac);
+	wn = (void *)tap->txa_ni;
+	wn->agg[tid].bitmap = bitmap;
+	wn->agg[tid].startidx = start;
+	wn->agg[tid].nframes = nframes;
+
+	seqno = le32toh(*(status + nframes)) & 0xfff;
+	for (lastidx = (seqno & 0xff); ring->read != lastidx;) {
+		data = &ring->data[ring->read];
+
+		KASSERT(data->ni != NULL, ("no node"));
+
+		/* Unmap and free mbuf. */
+		bus_dmamap_sync(ring->data_dmat, data->map,
+		    BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(ring->data_dmat, data->map);
+		m = data->m, data->m = NULL;
+		ni = data->ni, data->ni = NULL;
+		vap = ni->ni_vap;
+
+		if (m->m_flags & M_TXCB)
+			ieee80211_process_callback(ni, m, 1);
+
+		m_freem(m);
+		ieee80211_free_node(ni);
+
+		ring->queued--;
+		ring->read = (ring->read + 1) % IWN_TX_RING_COUNT;
+	}
+
+	sc->sc_tx_timer = 0;
+	if (ring->queued < IWN_TX_RING_LOMARK) {
+		sc->qfullmsk &= ~(1 << ring->qid);
+		if (sc->qfullmsk == 0 &&
+		    (ifp->if_drv_flags & IFF_DRV_OACTIVE)) {
+			ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+			iwn_start_locked(ifp);
+		}
+	}
+}
+
 /*
  * Process an INT_FH_RX or INT_SW_RX interrupt.
  */
@@ -2766,12 +2909,10 @@ iwn_notif_intr(struct iwn_softc *sc)
 			iwn_rx_done(sc, desc, data);
 			break;
 
-#if 0	/* HT */
 		case IWN_RX_COMPRESSED_BA:
 			/* A Compressed BlockAck has been received. */
 			iwn_rx_compressed_ba(sc, desc, data);
 			break;
-#endif
 
 		case IWN_TX_DONE:
 			/* An 802.11 frame has been transmitted. */
@@ -3151,6 +3292,7 @@ iwn5000_reset_sched(struct iwn_softc *sc
 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;
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ni->ni_ic;
@@ -3186,7 +3328,16 @@ iwn_tx_data(struct iwn_softc *sc, struct
 	}
 	ac = M_WME_GETAC(m);
 
-	ring = &sc->txq[ac];
+	if (IEEE80211_AMPDU_RUNNING(&ni->ni_tx_ampdu[ac])) {
+		struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
+
+		ring = &sc->txq[*(int *)tap->txa_private];
+		*(uint16_t *)wh->i_seq =
+		    htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
+		ni->ni_txseqs[tid]++;
+	} else {
+		ring = &sc->txq[ac];
+	}
 	desc = &ring->desc[ring->cur];
 	data = &ring->data[ring->cur];
 
@@ -3390,10 +3541,8 @@ iwn_tx_data(struct iwn_softc *sc, struct
 	bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map,
 	    BUS_DMASYNC_PREWRITE);
 
-#ifdef notyet
 	/* Update TX scheduler. */
 	ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen);
-#endif
 
 	/* Kick TX ring. */
 	ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT;
@@ -3410,6 +3559,7 @@ 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 ifnet *ifp = sc->sc_ifp;
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211com *ic = ifp->if_l2com;
@@ -3594,10 +3744,8 @@ iwn_tx_data_raw(struct iwn_softc *sc, st
 	bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map,
 	    BUS_DMASYNC_PREWRITE);
 
-#ifdef notyet
 	/* Update TX scheduler. */
 	ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen);
-#endif
 
 	/* Kick TX ring. */
 	ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT;
@@ -3761,6 +3909,7 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd,
 static int
 iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async)
 {
+	struct iwn_ops *ops = &sc->ops;
 	struct iwn_tx_ring *ring = &sc->txq[4];
 	struct iwn_tx_desc *desc;
 	struct iwn_tx_data *data;
@@ -3820,10 +3969,8 @@ iwn_cmd(struct iwn_softc *sc, int code, 
 	bus_dmamap_sync(ring->desc_dma.tag, ring->desc_dma.map,
 	    BUS_DMASYNC_PREWRITE);
 
-#ifdef notyet
 	/* Update TX scheduler. */
 	ops->update_sched(sc, ring->qid, ring->cur, 0, 0);
-#endif
 
 	/* Kick command ring. */
 	ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT;
@@ -3874,7 +4021,7 @@ iwn_set_link_quality(struct iwn_softc *s
 	linkq.id = wn->id;
 	linkq.antmsk_1stream = txant;
 	linkq.antmsk_2stream = IWN_ANT_AB;
-	linkq.ampdu_max = 31;
+	linkq.ampdu_max = 64;
 	linkq.ampdu_threshold = 3;
 	linkq.ampdu_limit = htole16(4000);	/* 4ms */
 
@@ -5391,7 +5538,56 @@ iwn_ampdu_rx_stop(struct ieee80211_node 
 	sc->sc_ampdu_rx_stop(ni, rap);
 }
 
-#if 0 /* HT */
+static int
+iwn_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+    int dialogtoken, int baparamset, int batimeout)
+{
+	struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc;
+	int qid;
+
+	for (qid = sc->firstaggqueue; qid < sc->ntxqs; qid++) {
+		if (sc->qid2tap[qid] == NULL)
+			break;
+	}
+	if (qid == sc->ntxqs) {
+		DPRINTF(sc, IWN_DEBUG_XMIT, "%s: not free aggregation queue\n",
+		    __func__);
+		return 0;
+	}
+	tap->txa_private = malloc(sizeof(int), M_DEVBUF, M_NOWAIT);
+	if (tap->txa_private == NULL) {
+		device_printf(sc->sc_dev,
+		    "%s: failed to alloc TX aggregation structure\n", __func__);
+		return 0;
+	}
+	sc->qid2tap[qid] = tap;
+	*(int *)tap->txa_private = qid;
+	return sc->sc_addba_request(ni, tap, dialogtoken, baparamset,
+	    batimeout);
+}
+
+static int
+iwn_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+    int code, int baparamset, int batimeout)
+{
+	struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc;
+	int qid = *(int *)tap->txa_private;
+	uint8_t tid = WME_AC_TO_TID(tap->txa_ac);
+	int ret;
+
+	if (code == IEEE80211_STATUS_SUCCESS) {
+		ni->ni_txseqs[tid] = tap->txa_start & 0xfff;
+		ret = iwn_ampdu_tx_start(ni->ni_ic, ni, tid);
+		if (ret != 1)
+			return ret;
+	} else {
+		sc->qid2tap[qid] = NULL;
+		free(tap->txa_private, M_DEVBUF);
+		tap->txa_private = NULL;
+	}
+	return sc->sc_addba_response(ni, tap, code, baparamset, batimeout);
+}
+
 /*
  * This function is called by upper layer when an ADDBA response is received
  * from another STA.
@@ -5400,12 +5596,12 @@ static int
 iwn_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
     uint8_t tid)
 {
-	struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid];
-	struct iwn_softc *sc = ic->ic_softc;
+	struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[TID_TO_WME_AC(tid)];
+	struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc;
 	struct iwn_ops *ops = &sc->ops;
 	struct iwn_node *wn = (void *)ni;
 	struct iwn_node_info node;
-	int error;
+	int error, qid;
 
 	/* Enable TX for the specified RA/TID. */
 	wn->disable_tid &= ~(1 << tid);
@@ -5416,35 +5612,44 @@ iwn_ampdu_tx_start(struct ieee80211com *
 	node.disable_tid = htole16(wn->disable_tid);
 	error = ops->add_node(sc, &node, 1);
 	if (error != 0)
-		return error;
+		return 0;
 
 	if ((error = iwn_nic_lock(sc)) != 0)
-		return error;
-	ops->ampdu_tx_start(sc, ni, tid, ba->ba_winstart);
+		return 0;
+	qid = *(int *)tap->txa_private;
+	ops->ampdu_tx_start(sc, ni, qid, tid, tap->txa_start & 0xfff);
 	iwn_nic_unlock(sc);
-	return 0;
+
+	iwn_set_link_quality(sc, ni);
+	return 1;
 }
 
 static void
-iwn_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni,
-    uint8_t tid)
+iwn_ampdu_tx_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
 {
-	struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid];
-	struct iwn_softc *sc = ic->ic_softc;
+	struct iwn_softc *sc = ni->ni_ic->ic_ifp->if_softc;
 	struct iwn_ops *ops = &sc->ops;
+	uint8_t tid = WME_AC_TO_TID(tap->txa_ac);
+	int qid;
+
+	if (tap->txa_private == NULL)
+		return;
 
+	qid = *(int *)tap->txa_private;
 	if (iwn_nic_lock(sc) != 0)
 		return;
-	ops->ampdu_tx_stop(sc, tid, ba->ba_winstart);
+	ops->ampdu_tx_stop(sc, qid, tid, tap->txa_start & 0xfff);
 	iwn_nic_unlock(sc);
+	sc->qid2tap[qid] = NULL;
+	free(tap->txa_private, M_DEVBUF);
+	tap->txa_private = NULL;
 }
 
 static void
 iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni,
-    uint8_t tid, uint16_t ssn)
+    int qid, uint8_t tid, uint16_t ssn)
 {
 	struct iwn_node *wn = (void *)ni;
-	int qid = 7 + tid;
 
 	/* Stop TX scheduler while we're changing its configuration. */
 	iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
@@ -5458,6 +5663,7 @@ iwn4965_ampdu_tx_start(struct iwn_softc 
 	iwn_prph_setbits(sc, IWN4965_SCHED_QCHAIN_SEL, 1 << qid);
 
 	/* Set starting sequence number from the ADDBA request. */
+	sc->txq[qid].cur = sc->txq[qid].read = (ssn & 0xff);
 	IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff));
 	iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn);
 
@@ -5478,10 +5684,8 @@ iwn4965_ampdu_tx_start(struct iwn_softc 
 }
 
 static void
-iwn4965_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn)
+iwn4965_ampdu_tx_stop(struct iwn_softc *sc, int qid, uint8_t tid, uint16_t ssn)
 {
-	int qid = 7 + tid;
-
 	/* Stop TX scheduler while we're changing its configuration. */
 	iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
 	    IWN4965_TXQ_STATUS_CHGACT);
@@ -5500,10 +5704,9 @@ iwn4965_ampdu_tx_stop(struct iwn_softc *
 
 static void
 iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni,
-    uint8_t tid, uint16_t ssn)
+    int qid, uint8_t tid, uint16_t ssn)
 {
 	struct iwn_node *wn = (void *)ni;
-	int qid = 10 + tid;
 
 	/* Stop TX scheduler while we're changing its configuration. */
 	iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
@@ -5520,6 +5723,7 @@ iwn5000_ampdu_tx_start(struct iwn_softc 
 	iwn_prph_setbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid);
 
 	/* Set starting sequence number from the ADDBA request. */
+	sc->txq[qid].cur = sc->txq[qid].read = (ssn & 0xff);
 	IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff));
 	iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn);
 
@@ -5536,10 +5740,8 @@ iwn5000_ampdu_tx_start(struct iwn_softc 
 }
 
 static void
-iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn)
+iwn5000_ampdu_tx_stop(struct iwn_softc *sc, int qid, uint8_t tid, uint16_t ssn)
 {
-	int qid = 10 + tid;
-
 	/* Stop TX scheduler while we're changing its configuration. */
 	iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
 	    IWN5000_TXQ_STATUS_CHGACT);
@@ -5558,7 +5760,6 @@ iwn5000_ampdu_tx_stop(struct iwn_softc *
 	iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
 	    IWN5000_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid]);
 }
-#endif
 
 /*
  * Query calibration tables from the initialization firmware.  We do this

Modified: head/sys/dev/iwn/if_iwnreg.h
==============================================================================
--- head/sys/dev/iwn/if_iwnreg.h	Sun May  8 11:58:23 2011	(r221650)
+++ head/sys/dev/iwn/if_iwnreg.h	Sun May  8 12:06:12 2011	(r221651)
@@ -27,6 +27,9 @@
 #define IWN4965_NTXQUEUES	16
 #define IWN5000_NTXQUEUES	20
 
+#define IWN4965_FIRSTAGGQUEUE	7
+#define IWN5000_FIRSTAGGQUEUE	10
+
 #define IWN4965_NDMACHNLS	7
 #define IWN5000_NDMACHNLS	8
 

Modified: head/sys/dev/iwn/if_iwnvar.h
==============================================================================
--- head/sys/dev/iwn/if_iwnvar.h	Sun May  8 11:58:23 2011	(r221650)
+++ head/sys/dev/iwn/if_iwnvar.h	Sun May  8 12:06:12 2011	(r221651)
@@ -78,6 +78,7 @@ struct iwn_tx_ring {
 	int			qid;
 	int			queued;
 	int			cur;
+	int			read;
 };
 
 struct iwn_softc;
@@ -102,6 +103,11 @@ struct iwn_node {
 	uint16_t			disable_tid;
 	uint8_t				id;
 	uint32_t			ridx[256];
+	struct {
+		uint64_t		bitmap;
+		int			startidx;
+		int			nframes;
+	} agg[IEEE80211_TID_SIZE];
 };
 
 struct iwn_calib_state {
@@ -174,12 +180,10 @@ struct iwn_ops {
 			    int);
 	void		(*tx_done)(struct iwn_softc *, struct iwn_rx_desc *,
 			    struct iwn_rx_data *);
-#if 0	/* HT */
 	void		(*ampdu_tx_start)(struct iwn_softc *,
-			    struct ieee80211_node *, uint8_t, uint16_t);
-	void		(*ampdu_tx_stop)(struct iwn_softc *, uint8_t,
+			    struct ieee80211_node *, int, uint8_t, uint16_t);
+	void		(*ampdu_tx_stop)(struct iwn_softc *, int, uint8_t,
 			    uint16_t);
-#endif
 };
 
 struct iwn_vap {
@@ -215,6 +219,7 @@ struct iwn_softc {
 	const struct iwn_sensitivity_limits
 				*limits;
 	int			ntxqs;
+	int			firstaggqueue;
 	int			ndmachnls;
 	uint8_t			broadcast_id;
 	int			rxonsz;
@@ -306,10 +311,19 @@ struct iwn_softc {
 
 	int			sc_tx_timer;
 
+	struct ieee80211_tx_ampdu *qid2tap[IWN5000_NTXQUEUES];
+
 	int			(*sc_ampdu_rx_start)(struct ieee80211_node *,
 				    struct ieee80211_rx_ampdu *, int, int, int);
 	void			(*sc_ampdu_rx_stop)(struct ieee80211_node *,
 				    struct ieee80211_rx_ampdu *);
+	int			(*sc_addba_request)(struct ieee80211_node *,
+				    struct ieee80211_tx_ampdu *, int, int, int);
+	int			(*sc_addba_response)(struct ieee80211_node *,
+				    struct ieee80211_tx_ampdu *, int, int, int);
+	void			(*sc_addba_stop)(struct ieee80211_node *,
+				    struct ieee80211_tx_ampdu *);
+
 
 	struct iwn_rx_radiotap_header sc_rxtap;
 	struct iwn_tx_radiotap_header sc_txtap;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105081206.p48C6CnJ045131>