diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 73 | 
1 files changed, 57 insertions, 16 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 349a5963931..22047628ccf 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)  }  static void +ath5k_set_current_imask(struct ath5k_softc *sc) +{ +	enum ath5k_int imask = sc->imask; +	unsigned long flags; + +	spin_lock_irqsave(&sc->irqlock, flags); +	if (sc->rx_pending) +		imask &= ~AR5K_INT_RX_ALL; +	if (sc->tx_pending) +		imask &= ~AR5K_INT_TX_ALL; +	ath5k_hw_set_imr(sc->ah, imask); +	spin_unlock_irqrestore(&sc->irqlock, flags); +} + +static void  ath5k_tasklet_rx(unsigned long data)  {  	struct ath5k_rx_status rs = {}; @@ -1506,6 +1521,8 @@ next:  	} while (ath5k_rxbuf_setup(sc, bf) == 0);  unlock:  	spin_unlock(&sc->rxbuflock); +	sc->rx_pending = false; +	ath5k_set_current_imask(sc);  } @@ -1573,28 +1590,28 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,  			 struct ath5k_txq *txq, struct ath5k_tx_status *ts)  {  	struct ieee80211_tx_info *info; +	u8 tries[3];  	int i;  	sc->stats.tx_all_count++;  	sc->stats.tx_bytes_count += skb->len;  	info = IEEE80211_SKB_CB(skb); +	tries[0] = info->status.rates[0].count; +	tries[1] = info->status.rates[1].count; +	tries[2] = info->status.rates[2].count; +  	ieee80211_tx_info_clear_status(info); -	for (i = 0; i < 4; i++) { + +	for (i = 0; i < ts->ts_final_idx; i++) {  		struct ieee80211_tx_rate *r =  			&info->status.rates[i]; -		if (ts->ts_rate[i]) { -			r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]); -			r->count = ts->ts_retry[i]; -		} else { -			r->idx = -1; -			r->count = 0; -		} +		r->count = tries[i];  	} -	/* count the successful attempt as well */ -	info->status.rates[ts->ts_final_idx].count++; +	info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry; +	info->status.rates[ts->ts_final_idx + 1].idx = -1;  	if (unlikely(ts->ts_status)) {  		sc->stats.ack_fail++; @@ -1609,6 +1626,9 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,  	} else {  		info->flags |= IEEE80211_TX_STAT_ACK;  		info->status.ack_signal = ts->ts_rssi; + +		/* count the successful attempt as well */ +		info->status.rates[ts->ts_final_idx].count++;  	}  	/* @@ -1690,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)  	for (i=0; i < AR5K_NUM_TX_QUEUES; i++)  		if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))  			ath5k_tx_processq(sc, &sc->txqs[i]); + +	sc->tx_pending = false; +	ath5k_set_current_imask(sc);  } @@ -2119,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)  	 * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */  } +static void +ath5k_schedule_rx(struct ath5k_softc *sc) +{ +	sc->rx_pending = true; +	tasklet_schedule(&sc->rxtq); +} + +static void +ath5k_schedule_tx(struct ath5k_softc *sc) +{ +	sc->tx_pending = true; +	tasklet_schedule(&sc->txtq); +} +  irqreturn_t  ath5k_intr(int irq, void *dev_id)  { @@ -2161,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)  				ieee80211_queue_work(sc->hw, &sc->reset_work);  			}  			else -				tasklet_schedule(&sc->rxtq); +				ath5k_schedule_rx(sc);  		} else {  			if (status & AR5K_INT_SWBA) {  				tasklet_hi_schedule(&sc->beacontq); @@ -2179,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)  				ath5k_hw_update_tx_triglevel(ah, true);  			}  			if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) -				tasklet_schedule(&sc->rxtq); +				ath5k_schedule_rx(sc);  			if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC  					| AR5K_INT_TXERR | AR5K_INT_TXEOL)) -				tasklet_schedule(&sc->txtq); +				ath5k_schedule_tx(sc);  			if (status & AR5K_INT_BMISS) {  				/* TODO */  			} @@ -2201,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)  	} while (ath5k_hw_is_intr_pending(ah) && --counter > 0); +	if (sc->rx_pending || sc->tx_pending) +		ath5k_set_current_imask(sc); +  	if (unlikely(!counter))  		ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); @@ -2354,7 +2394,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)  	spin_lock_init(&sc->rxbuflock);  	spin_lock_init(&sc->txbuflock);  	spin_lock_init(&sc->block); - +	spin_lock_init(&sc->irqlock);  	/* Setup interrupt handler */  	ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc); @@ -2572,6 +2612,8 @@ done:  static void stop_tasklets(struct ath5k_softc *sc)  { +	sc->rx_pending = false; +	sc->tx_pending = false;  	tasklet_kill(&sc->rxtq);  	tasklet_kill(&sc->txtq);  	tasklet_kill(&sc->calib); @@ -2838,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw)  	INIT_WORK(&sc->reset_work, ath5k_reset_work);  	INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work); -	ret = ath5k_eeprom_read_mac(ah, mac); +	ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);  	if (ret) {  		ATH5K_ERR(sc, "unable to read address from EEPROM\n");  		goto err_queues; @@ -2898,7 +2940,6 @@ ath5k_deinit_softc(struct ath5k_softc *sc)  	 * XXX: ??? detach ath5k_hw ???  	 * Other than that, it's straightforward...  	 */ -	ath5k_debug_finish_device(sc);  	ieee80211_unregister_hw(hw);  	ath5k_desc_free(sc);  	ath5k_txq_release(sc);  |