/* * Drain the transmit queues and reclaim resources. */ static void ath_drain_txq(struct ath_softc *sc) { #ifdef ATH_SUPPORT_HTC u_int16_t i; struct ath_hal *ah = sc->sc_ah; /* drain all host endpoints */ for (i = 0; i < NUM_TX_EP; i++) if (ATH_TXQ_SETUP(sc, i)) ath_tx_drainep(sc, &sc->sc_txep[i]); HTCDrainAllEp(sc->sc_host_htc_handle); /* stop target wireless DMA */ if (!sc->sc_invalid) { for (i = 0; i < NUM_TX_EP; i++) if (ATH_TXQ_SETUP(sc, i)) { u_int32_t hwq_num; hwq_num = adf_os_htonl(sc->sc_txep[i].hwq_num); ath_hal_tx99_tx_stopdma(ah, hwq_num); } } ath_hal_tx99_drain_alltxq(ah); #else /* stop beacon queue. stop and abort all tx qs, flush ath buffer queue */ ath_draintxq(sc, AH_FALSE, 0); /* stop xmit side */ #endif }
static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_buf *bf; struct ath_vif *avp; struct sk_buff *skb; struct ath_txq *cabq; struct ieee80211_tx_info *info; int cabq_depth; ath9k_reset_beacon_status(sc); avp = (void *)vif->drv_priv; cabq = sc->beacon.cabq; if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active) return NULL; /* Release the old beacon first */ bf = avp->av_bcbuf; skb = bf->bf_mpdu; if (skb) { dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); bf->bf_buf_addr = 0; } /* Get a new beacon from mac80211 */ skb = ieee80211_beacon_get(hw, vif); bf->bf_mpdu = skb; if (skb == NULL) return NULL; ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = avp->tsf_adjust; info = IEEE80211_SKB_CB(skb); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { /* * TODO: make sure the seq# gets assigned properly (vs. other * TX frames) */ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, skb->len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; bf->bf_buf_addr = 0; ath_err(common, "dma_mapping_error on beaconing\n"); return NULL; } skb = ieee80211_get_buffered_bc(hw, vif); /* * if the CABQ traffic from previous DTIM is pending and the current * beacon is also a DTIM. * 1) if there is only one vif let the cab traffic continue. * 2) if there are more than one vif and we are using staggered * beacons, then drain the cabq by dropping all the frames in * the cabq so that the current vifs cab traffic can be scheduled. */ spin_lock_bh(&cabq->axq_lock); cabq_depth = cabq->axq_depth; spin_unlock_bh(&cabq->axq_lock); if (skb && cabq_depth) { if (sc->nvifs > 1) { ath_dbg(common, BEACON, "Flushing previous cabq traffic\n"); ath_draintxq(sc, cabq, false); } } ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx); while (skb) { ath_tx_cabq(hw, skb); skb = ieee80211_get_buffered_bc(hw, vif); } return bf; }
void ath_cont_data(struct ath_softc *sc ,int val) { static struct sk_buff *skb = NULL; struct ieee80211_frame *hdr; static struct ieee80211com *ic; static struct ath_buf *bf,*prev,*first; static struct ath_desc *ds; static struct ath_hal *ah; static STAILQ_HEAD(tpc_buf,ath_buf) tmp_q; static int is_inited=0; struct ath_txq *txq; const HAL_RATE_TABLE *rt; u_int8_t *p; u_int32_t flags, txrate, r,i; u_int16_t hdrlen, framelen, dmalen,delay=0; #define MIN(a,b) ((a) < (b) ? (a) : (b)) if(is_inited == 0) { STAILQ_INIT(&tmp_q); is_inited=1; } /* enter CONT_DATA mode */ if (val && skb==NULL) { skb = ath_alloc_skb(4096, 32); if (skb == NULL) goto out; /* build output packet */ hdr = (struct ieee80211_frame *)skb_put(skb, sizeof(*hdr)); IEEE80211_ADDR_COPY(&hdr->i_addr1, test_addr); IEEE80211_ADDR_COPY(&hdr->i_addr2, test_addr); IEEE80211_ADDR_COPY(&hdr->i_addr3, test_addr); hdr->i_dur[0] = 0x0; hdr->i_dur[1] = 0x0; hdr->i_seq[0] = 0x5a; hdr->i_seq[1] = 0x5a; hdr->i_fc[0] = IEEE80211_FC0_TYPE_DATA; hdr->i_fc[1] = 0; hdrlen = sizeof(*hdr); for(r=0; r<2000; ) { p = skb_put(skb, sizeof(PN9Data)); memcpy(p, PN9Data, sizeof(PN9Data)); r += sizeof(PN9Data); } framelen = hdrlen + r + IEEE80211_CRC_LEN; ic = &sc->sc_ic; ah = sc->sc_ah; rt = sc->sc_currates; if (rt==NULL) { printk("no rate table\n"); goto out; } txrate = rt->info[rt->rateCount-1].rateCode; /* send at highest rate */ { int rix; if (sc->sc_txrate==0) sc->sc_txrate = 6000; for(rix=0; rix<rt->rateCount; rix++) { if (rt->info[rix].rateKbps==sc->sc_txrate) { txrate = rt->info[rix].rateCode; printk("txrate set to %dKbps\n", sc->sc_txrate); break; } } } ath_draintxq(sc); prev=first=NULL; /* send 20 frames for the Power Amp to settle down */ for(i=0;i<20;++i) { ATH_TXBUF_LOCK_BH(sc); bf = STAILQ_FIRST(&sc->sc_txbuf); if (bf != NULL) { STAILQ_REMOVE_HEAD(&sc->sc_txbuf,bf_list); } ATH_TXBUF_UNLOCK_BH(sc); if (bf==NULL) { printk("no tx buf\n"); goto out; } if(!i) first=bf; framelen = skb->len + IEEE80211_CRC_LEN; dmalen = skb->len; txq = sc->sc_ac2q[WME_AC_VO]; bf->bf_skbaddr = bus_map_single(sc->sc_bdev, skb->data, framelen, BUS_DMA_TODEVICE); bf->bf_skb = skb; bf->bf_node = 0; flags = HAL_TXDESC_CLRDMASK; ds = bf->bf_desc; if(prev) prev->bf_desc->ds_link = bf->bf_daddr; /* link from prev desc */ ds->ds_data = bf->bf_skbaddr; printk("txpower set to %d\n", sc->sc_txpower); r = ath_hal_setuptxdesc(ah, ds, framelen, hdrlen, HAL_PKT_TYPE_NORMAL, sc->sc_txpower, txrate, /* tx rate */ 15, /* max retries */ HAL_TXKEYIX_INVALID, /* no WEP */ 1, /* select Omni Antenna 0 */ flags, 0, /* rts/cts rate */ 0 /* rts/cts duration */ ); if (r==AH_FALSE) { printk("fail setuptxdesc r(%d)\n", r); goto out; } r = ath_hal_filltxdesc(ah, ds, skb->len, AH_TRUE, AH_TRUE,ds); if (r==AH_FALSE) { printk("fail fill tx desc r(%d)\n", r); goto out; } ath_hal_setupxtxdesc(ah, ds , txrate, 15 /* series 1 */ , txrate, 15 /* series 2 */ , txrate, 15 /* series 3 */ ); /* insert the buffers in to tmp_q */ STAILQ_INSERT_HEAD(&tmp_q,bf,bf_list); #if 0 ATH_TXQ_LOCK_BH(txq); ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); ATH_TXQ_UNLOCK_BH(txq); #endif prev=bf; } ath_hal_intrset(ah, 0); /* disable interrupts */ //sc->sc_imask = HAL_INT_RX | HAL_INT_TX // | HAL_INT_RXEOL | HAL_INT_RXORN // | HAL_INT_FATAL | HAL_INT_GLOBAL; sc->sc_imask = 0; //ath_hal_intrset(ah, sc->sc_imask); bf->bf_desc->ds_link = NULL; r = ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); ath_hal_txstart(ah, txq->axq_qnum); while(ath_hal_txprocdesc(ah,bf->bf_desc) == HAL_EINPROGRESS) { udelay(2000); ++delay; } /* sleep for 20ms */ udelay(20000); printk("took %d msec to transmit the 20 frames \n",2*delay); /* start TX99 mode */ ath_stoprecv(sc); /* stop recv side */ bf->bf_desc->ds_link = first->bf_daddr; /* link to self */ ath_hal_getdiagstate(ah, 19,(void *) sc->sc_prefetch,9,NULL,NULL); ath_hal_getdiagstate(ah, 19, txq->axq_qnum, val,NULL,NULL); ath_hal_txstart(ah, txq->axq_qnum); } /* leave CONT_DATA mode, reset the chip */ if (val==0 && skb) { int j=0; ath_hal_getdiagstate(ah, 19, 0, 0,NULL,NULL); /* insert the buffers back into txbuf list */ ATH_TXBUF_LOCK_BH(sc); bf = STAILQ_FIRST(&tmp_q); while(bf) { bf->bf_skb=NULL; STAILQ_REMOVE_HEAD(&tmp_q,bf_list); STAILQ_INSERT_HEAD(&sc->sc_txbuf,bf,bf_list); bf = STAILQ_FIRST(&tmp_q); ++j; } ATH_TXBUF_UNLOCK_BH(sc); printk("inserted back %d buffers \n",j); ic->ic_reset(ic->ic_dev); skb = NULL; bf = NULL; } if (val==7 && skb) { ath_hal_getdiagstate(ah, 19, ds, 7,NULL,NULL); } out: return; #undef MIN }