diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/base.c')
| -rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 297 | 
1 files changed, 228 insertions, 69 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 8dce0077b02..93005f1d326 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -50,6 +50,7 @@  #include <linux/pci.h>  #include <linux/ethtool.h>  #include <linux/uaccess.h> +#include <linux/slab.h>  #include <net/ieee80211_radiotap.h> @@ -58,8 +59,8 @@  #include "base.h"  #include "reg.h"  #include "debug.h" +#include "ani.h" -static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */  static int modparam_nohwcrypt;  module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);  MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); @@ -198,7 +199,7 @@ static void __devexit	ath5k_pci_remove(struct pci_dev *pdev);  static int		ath5k_pci_suspend(struct device *dev);  static int		ath5k_pci_resume(struct device *dev); -SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume); +static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);  #define ATH5K_PM_OPS	(&ath5k_pm_ops)  #else  #define ATH5K_PM_OPS	NULL @@ -230,7 +231,7 @@ static void ath5k_remove_interface(struct ieee80211_hw *hw,  		struct ieee80211_vif *vif);  static int ath5k_config(struct ieee80211_hw *hw, u32 changed);  static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, -				   int mc_count, struct dev_addr_list *mc_list); +				   struct netdev_hw_addr_list *mc_list);  static void ath5k_configure_filter(struct ieee80211_hw *hw,  		unsigned int changed_flags,  		unsigned int *new_flags, @@ -307,7 +308,7 @@ static int 	ath5k_rxbuf_setup(struct ath5k_softc *sc,  				struct ath5k_buf *bf);  static int 	ath5k_txbuf_setup(struct ath5k_softc *sc,  				struct ath5k_buf *bf, -				struct ath5k_txq *txq); +				struct ath5k_txq *txq, int padsize);  static inline void ath5k_txbuf_free(struct ath5k_softc *sc,  				struct ath5k_buf *bf)  { @@ -364,6 +365,7 @@ static void 	ath5k_beacon_send(struct ath5k_softc *sc);  static void 	ath5k_beacon_config(struct ath5k_softc *sc);  static void	ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);  static void	ath5k_tasklet_beacon(unsigned long data); +static void	ath5k_tasklet_ani(unsigned long data);  static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)  { @@ -829,6 +831,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)  	tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);  	tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);  	tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); +	tasklet_init(&sc->ani_tasklet, ath5k_tasklet_ani, (unsigned long)sc);  	ret = ath5k_eeprom_read_mac(ah, mac);  	if (ret) { @@ -1137,8 +1140,6 @@ ath5k_mode_setup(struct ath5k_softc *sc)  	struct ath5k_hw *ah = sc->ah;  	u32 rfilt; -	ah->ah_op_mode = sc->opmode; -  	/* configure rx filter */  	rfilt = sc->filter_flags;  	ath5k_hw_set_rx_filter(ah, rfilt); @@ -1147,8 +1148,9 @@ ath5k_mode_setup(struct ath5k_softc *sc)  		ath5k_hw_set_bssid_mask(ah, sc->bssidmask);  	/* configure operational mode */ -	ath5k_hw_set_opmode(ah); +	ath5k_hw_set_opmode(ah, sc->opmode); +	ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "mode setup opmode %d\n", sc->opmode);  	ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt);  } @@ -1271,7 +1273,7 @@ static enum ath5k_pkt_type get_hw_packet_type(struct sk_buff *skb)  static int  ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, -		  struct ath5k_txq *txq) +		  struct ath5k_txq *txq, int padsize)  {  	struct ath5k_hw *ah = sc->ah;  	struct ath5k_desc *ds = bf->desc; @@ -1323,7 +1325,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,  			sc->vif, pktlen, info));  	}  	ret = ah->ah_setup_tx_desc(ah, ds, pktlen, -		ieee80211_get_hdrlen_from_skb(skb), +		ieee80211_get_hdrlen_from_skb(skb), padsize,  		get_hw_packet_type(skb),  		(sc->power_level * 2),  		hw_rate, @@ -1635,7 +1637,6 @@ ath5k_txq_cleanup(struct ath5k_softc *sc)  					sc->txqs[i].link);  			}  	} -	ieee80211_wake_queues(sc->hw); /* XXX move to callers */  	for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)  		if (sc->txqs[i].setup) @@ -1806,6 +1807,86 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,  }  static void +ath5k_update_beacon_rssi(struct ath5k_softc *sc, struct sk_buff *skb, int rssi) +{ +	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; +	struct ath5k_hw *ah = sc->ah; +	struct ath_common *common = ath5k_hw_common(ah); + +	/* only beacons from our BSSID */ +	if (!ieee80211_is_beacon(mgmt->frame_control) || +	    memcmp(mgmt->bssid, common->curbssid, ETH_ALEN) != 0) +		return; + +	ah->ah_beacon_rssi_avg = ath5k_moving_average(ah->ah_beacon_rssi_avg, +						      rssi); + +	/* in IBSS mode we should keep RSSI statistics per neighbour */ +	/* le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS */ +} + +/* + * Compute padding position. skb must contains an IEEE 802.11 frame + */ +static int ath5k_common_padpos(struct sk_buff *skb) +{ +	struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data; +	__le16 frame_control = hdr->frame_control; +	int padpos = 24; + +	if (ieee80211_has_a4(frame_control)) { +		padpos += ETH_ALEN; +	} +	if (ieee80211_is_data_qos(frame_control)) { +		padpos += IEEE80211_QOS_CTL_LEN; +	} + +	return padpos; +} + +/* + * This function expects a 802.11 frame and returns the number of + * bytes added, or -1 if we don't have enought header room. + */ + +static int ath5k_add_padding(struct sk_buff *skb) +{ +	int padpos = ath5k_common_padpos(skb); +	int padsize = padpos & 3; + +	if (padsize && skb->len>padpos) { + +		if (skb_headroom(skb) < padsize) +			return -1; + +		skb_push(skb, padsize); +		memmove(skb->data, skb->data+padsize, padpos); +		return padsize; +	} + +	return 0; +} + +/* + * This function expects a 802.11 frame and returns the number of + * bytes removed + */ + +static int ath5k_remove_padding(struct sk_buff *skb) +{ +	int padpos = ath5k_common_padpos(skb); +	int padsize = padpos & 3; + +	if (padsize && skb->len>=padpos+padsize) { +		memmove(skb->data + padsize, skb->data, padpos); +		skb_pull(skb, padsize); +		return padsize; +	} + +	return 0; +} + +static void  ath5k_tasklet_rx(unsigned long data)  {  	struct ieee80211_rx_status *rxs; @@ -1818,8 +1899,6 @@ ath5k_tasklet_rx(unsigned long data)  	struct ath5k_buf *bf;  	struct ath5k_desc *ds;  	int ret; -	int hdrlen; -	int padsize;  	int rx_flag;  	spin_lock(&sc->rxbuflock); @@ -1844,18 +1923,30 @@ ath5k_tasklet_rx(unsigned long data)  			break;  		else if (unlikely(ret)) {  			ATH5K_ERR(sc, "error in processing rx descriptor\n"); +			sc->stats.rxerr_proc++;  			spin_unlock(&sc->rxbuflock);  			return;  		} +		sc->stats.rx_all_count++; +  		if (unlikely(rs.rs_more)) {  			ATH5K_WARN(sc, "unsupported jumbo\n"); +			sc->stats.rxerr_jumbo++;  			goto next;  		}  		if (unlikely(rs.rs_status)) { -			if (rs.rs_status & AR5K_RXERR_PHY) +			if (rs.rs_status & AR5K_RXERR_CRC) +				sc->stats.rxerr_crc++; +			if (rs.rs_status & AR5K_RXERR_FIFO) +				sc->stats.rxerr_fifo++; +			if (rs.rs_status & AR5K_RXERR_PHY) { +				sc->stats.rxerr_phy++; +				if (rs.rs_phyerr > 0 && rs.rs_phyerr < 32) +					sc->stats.rxerr_phy_code[rs.rs_phyerr]++;  				goto next; +			}  			if (rs.rs_status & AR5K_RXERR_DECRYPT) {  				/*  				 * Decrypt error.  If the error occurred @@ -1867,12 +1958,14 @@ ath5k_tasklet_rx(unsigned long data)  				 *  				 * XXX do key cache faulting  				 */ +				sc->stats.rxerr_decrypt++;  				if (rs.rs_keyix == AR5K_RXKEYIX_INVALID &&  				    !(rs.rs_status & AR5K_RXERR_CRC))  					goto accept;  			}  			if (rs.rs_status & AR5K_RXERR_MIC) {  				rx_flag |= RX_FLAG_MMIC_ERROR; +				sc->stats.rxerr_mic++;  				goto accept;  			} @@ -1904,12 +1997,8 @@ accept:  		 * bytes and we can optimize this a bit. In addition, we must  		 * not try to remove padding from short control frames that do  		 * not have payload. */ -		hdrlen = ieee80211_get_hdrlen_from_skb(skb); -		padsize = ath5k_pad_size(hdrlen); -		if (padsize) { -			memmove(skb->data + padsize, skb->data, hdrlen); -			skb_pull(skb, padsize); -		} +		ath5k_remove_padding(skb); +  		rxs = IEEE80211_SKB_RXCB(skb);  		/* @@ -1942,6 +2031,12 @@ accept:  		rxs->signal = rxs->noise + rs.rs_rssi;  		rxs->antenna = rs.rs_antenna; + +		if (rs.rs_antenna > 0 && rs.rs_antenna < 5) +			sc->stats.antenna_rx[rs.rs_antenna]++; +		else +			sc->stats.antenna_rx[0]++; /* invalid */ +  		rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate);  		rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); @@ -1951,6 +2046,8 @@ accept:  		ath5k_debug_dump_skb(sc, skb, "RX  ", 0); +		ath5k_update_beacon_rssi(sc, skb, rs.rs_rssi); +  		/* check beacons in IBSS mode */  		if (sc->opmode == NL80211_IFTYPE_ADHOC)  			ath5k_check_ibss_tsf(sc, skb, rxs); @@ -1987,6 +2084,17 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)  	list_for_each_entry_safe(bf, bf0, &txq->q, list) {  		ds = bf->desc; +		/* +		 * It's possible that the hardware can say the buffer is +		 * completed when it hasn't yet loaded the ds_link from +		 * host memory and moved on.  If there are more TX +		 * descriptors in the queue, wait for TXDP to change +		 * before processing this one. +		 */ +		if (ath5k_hw_get_txdp(sc->ah, txq->qnum) == bf->daddr && +		    !list_is_last(&bf->list, &txq->q)) +			break; +  		ret = sc->ah->ah_proc_tx_desc(sc->ah, ds, &ts);  		if (unlikely(ret == -EINPROGRESS))  			break; @@ -1996,6 +2104,7 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)  			break;  		} +		sc->stats.tx_all_count++;  		skb = bf->skb;  		info = IEEE80211_SKB_CB(skb);  		bf->skb = NULL; @@ -2021,14 +2130,31 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)  		info->status.rates[ts.ts_final_idx].count++;  		if (unlikely(ts.ts_status)) { -			sc->ll_stats.dot11ACKFailureCount++; -			if (ts.ts_status & AR5K_TXERR_FILT) +			sc->stats.ack_fail++; +			if (ts.ts_status & AR5K_TXERR_FILT) {  				info->flags |= IEEE80211_TX_STAT_TX_FILTERED; +				sc->stats.txerr_filt++; +			} +			if (ts.ts_status & AR5K_TXERR_XRETRY) +				sc->stats.txerr_retry++; +			if (ts.ts_status & AR5K_TXERR_FIFO) +				sc->stats.txerr_fifo++;  		} else {  			info->flags |= IEEE80211_TX_STAT_ACK;  			info->status.ack_signal = ts.ts_rssi;  		} +		/* +		 * Remove MAC header padding before giving the frame +		 * back to mac80211. +		 */ +		ath5k_remove_padding(skb); + +		if (ts.ts_antenna > 0 && ts.ts_antenna < 5) +			sc->stats.antenna_tx[ts.ts_antenna]++; +		else +			sc->stats.antenna_tx[0]++; /* invalid */ +  		ieee80211_tx_status(sc->hw, skb);  		spin_lock(&sc->txbuflock); @@ -2072,6 +2198,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)  	int ret = 0;  	u8 antenna;  	u32 flags; +	const int padsize = 0;  	bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,  			PCI_DMA_TODEVICE); @@ -2119,7 +2246,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)  	 * from tx power (value is in dB units already) */  	ds->ds_data = bf->skbaddr;  	ret = ah->ah_setup_tx_desc(ah, ds, skb->len, -			ieee80211_get_hdrlen_from_skb(skb), +			ieee80211_get_hdrlen_from_skb(skb), padsize,  			AR5K_PKT_TYPE_BEACON, (sc->power_level * 2),  			ieee80211_get_tx_rate(sc->hw, info)->hw_value,  			1, AR5K_TXKEYIX_INVALID, @@ -2406,9 +2533,6 @@ ath5k_init(struct ath5k_softc *sc)  	 */  	ath5k_stop_locked(sc); -	/* Set PHY calibration interval */ -	ah->ah_cal_intval = ath5k_calinterval; -  	/*  	 * The basic interface to setting the hardware in a good  	 * state is ``reset''.  On return the hardware is known to @@ -2420,7 +2544,8 @@ ath5k_init(struct ath5k_softc *sc)  	sc->curband = &sc->sbands[sc->curchan->band];  	sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |  		AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | -		AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI; +		AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; +  	ret = ath5k_reset(sc, NULL);  	if (ret)  		goto done; @@ -2434,8 +2559,7 @@ ath5k_init(struct ath5k_softc *sc)  	for (i = 0; i < AR5K_KEYTABLE_SIZE; i++)  		ath5k_hw_reset_key(ah, i); -	/* Set ack to be sent at low bit-rates */ -	ath5k_hw_set_ack_bitrate_high(ah, false); +	ath5k_hw_set_ack_bitrate_high(ah, true);  	ret = 0;  done:  	mmiowb(); @@ -2532,12 +2656,33 @@ ath5k_stop_hw(struct ath5k_softc *sc)  	tasklet_kill(&sc->restq);  	tasklet_kill(&sc->calib);  	tasklet_kill(&sc->beacontq); +	tasklet_kill(&sc->ani_tasklet);  	ath5k_rfkill_hw_stop(sc->ah);  	return ret;  } +static void +ath5k_intr_calibration_poll(struct ath5k_hw *ah) +{ +	if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && +	    !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { +		/* run ANI only when full calibration is not active */ +		ah->ah_cal_next_ani = jiffies + +			msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); +		tasklet_schedule(&ah->ah_sc->ani_tasklet); + +	} else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { +		ah->ah_cal_next_full = jiffies + +			msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); +		tasklet_schedule(&ah->ah_sc->calib); +	} +	/* we could use SWI to generate enough interrupts to meet our +	 * calibration interval requirements, if necessary: +	 * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */ +} +  static irqreturn_t  ath5k_intr(int irq, void *dev_id)  { @@ -2561,7 +2706,20 @@ ath5k_intr(int irq, void *dev_id)  			 */  			tasklet_schedule(&sc->restq);  		} else if (unlikely(status & AR5K_INT_RXORN)) { -			tasklet_schedule(&sc->restq); +			/* +			 * Receive buffers are full. Either the bus is busy or +			 * the CPU is not fast enough to process all received +			 * frames. +			 * Older chipsets need a reset to come out of this +			 * condition, but we treat it as RX for newer chips. +			 * We don't know exactly which versions need a reset - +			 * this guess is copied from the HAL. +			 */ +			sc->stats.rxorn_intr++; +			if (ah->ah_mac_srev < AR5K_SREV_AR5212) +				tasklet_schedule(&sc->restq); +			else +				tasklet_schedule(&sc->rxtq);  		} else {  			if (status & AR5K_INT_SWBA) {  				tasklet_hi_schedule(&sc->beacontq); @@ -2586,15 +2744,10 @@ ath5k_intr(int irq, void *dev_id)  			if (status & AR5K_INT_BMISS) {  				/* TODO */  			} -			if (status & AR5K_INT_SWI) { -				tasklet_schedule(&sc->calib); -			}  			if (status & AR5K_INT_MIB) { -				/* -				 * These stats are also used for ANI i think -				 * so how about updating them more often ? -				 */ -				ath5k_hw_update_mib_counters(ah, &sc->ll_stats); +				sc->stats.mib_intr++; +				ath5k_hw_update_mib_counters(ah); +				ath5k_ani_mib_intr(ah);  			}  			if (status & AR5K_INT_GPIO)  				tasklet_schedule(&sc->rf_kill.toggleq); @@ -2605,7 +2758,7 @@ ath5k_intr(int irq, void *dev_id)  	if (unlikely(!counter))  		ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); -	ath5k_hw_calibration_poll(ah); +	ath5k_intr_calibration_poll(ah);  	return IRQ_HANDLED;  } @@ -2629,8 +2782,7 @@ ath5k_tasklet_calibrate(unsigned long data)  	struct ath5k_hw *ah = sc->ah;  	/* Only full calibration for now */ -	if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION) -		return; +	ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;  	/* Stop queues so that calibration  	 * doesn't interfere with tx */ @@ -2646,18 +2798,29 @@ ath5k_tasklet_calibrate(unsigned long data)  		 * to load new gain values.  		 */  		ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); -		ath5k_reset_wake(sc); +		ath5k_reset(sc, sc->curchan);  	}  	if (ath5k_hw_phy_calibrate(ah, sc->curchan))  		ATH5K_ERR(sc, "calibration of channel %u failed\n",  			ieee80211_frequency_to_channel(  				sc->curchan->center_freq)); -	ah->ah_swi_mask = 0; -  	/* Wake queues */  	ieee80211_wake_queues(sc->hw); +	ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL; +} + + +static void +ath5k_tasklet_ani(unsigned long data) +{ +	struct ath5k_softc *sc = (void *)data; +	struct ath5k_hw *ah = sc->ah; + +	ah->ah_cal_mask |= AR5K_CALIBRATION_ANI; +	ath5k_ani_calibration(ah); +	ah->ah_cal_mask &= ~AR5K_CALIBRATION_ANI;  } @@ -2679,7 +2842,6 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,  	struct ath5k_softc *sc = hw->priv;  	struct ath5k_buf *bf;  	unsigned long flags; -	int hdrlen;  	int padsize;  	ath5k_debug_dump_skb(sc, skb, "TX  ", 1); @@ -2691,17 +2853,11 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,  	 * the hardware expects the header padded to 4 byte boundaries  	 * if this is not the case we add the padding after the header  	 */ -	hdrlen = ieee80211_get_hdrlen_from_skb(skb); -	padsize = ath5k_pad_size(hdrlen); -	if (padsize) { - -		if (skb_headroom(skb) < padsize) { -			ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" -				  " headroom to pad %d\n", hdrlen, padsize); -			goto drop_packet; -		} -		skb_push(skb, padsize); -		memmove(skb->data, skb->data+padsize, hdrlen); +	padsize = ath5k_add_padding(skb); +	if (padsize < 0) { +		ATH5K_ERR(sc, "tx hdrlen not %%4: not enough" +			  " headroom to pad"); +		goto drop_packet;  	}  	spin_lock_irqsave(&sc->txbuflock, flags); @@ -2720,7 +2876,7 @@ static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,  	bf->skb = skb; -	if (ath5k_txbuf_setup(sc, bf, txq)) { +	if (ath5k_txbuf_setup(sc, bf, txq, padsize)) {  		bf->skb = NULL;  		spin_lock_irqsave(&sc->txbuflock, flags);  		list_add_tail(&bf->list, &sc->txbuf); @@ -2767,6 +2923,8 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)  		goto err;  	} +	ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode); +  	/*  	 * Change channels and update the h/w rate map if we're switching;  	 * e.g. 11a to 11b/g. @@ -2835,6 +2993,8 @@ static int ath5k_add_interface(struct ieee80211_hw *hw,  		goto end;  	} +	ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "add interface mode %d\n", sc->opmode); +  	ath5k_hw_set_lladdr(sc->ah, vif->addr);  	ath5k_mode_setup(sc); @@ -2905,7 +3065,7 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)  	 * then we must allow the user to set how many tx antennas we  	 * have available  	 */ -	ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT); +	ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);  unlock:  	mutex_unlock(&sc->lock); @@ -2913,22 +3073,20 @@ unlock:  }  static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, -				   int mc_count, struct dev_addr_list *mclist) +				   struct netdev_hw_addr_list *mc_list)  {  	u32 mfilt[2], val; -	int i;  	u8 pos; +	struct netdev_hw_addr *ha;  	mfilt[0] = 0;  	mfilt[1] = 1; -	for (i = 0; i < mc_count; i++) { -		if (!mclist) -			break; +	netdev_hw_addr_list_for_each(ha, mc_list) {  		/* calculate XOR of eight 6-bit values */ -		val = get_unaligned_le32(mclist->dmi_addr + 0); +		val = get_unaligned_le32(ha->addr + 0);  		pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; -		val = get_unaligned_le32(mclist->dmi_addr + 3); +		val = get_unaligned_le32(ha->addr + 3);  		pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;  		pos &= 0x3f;  		mfilt[pos / 32] |= (1 << (pos % 32)); @@ -2936,8 +3094,7 @@ static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw,  		* but not sure, needs testing, if we do use this we'd  		* neet to inform below to not reset the mcast */  		/* ath5k_hw_set_mcast_filterindex(ah, -		 *      mclist->dmi_addr[5]); */ -		mclist = mclist->next; +		 *      ha->addr[5]); */  	}  	return ((u64)(mfilt[1]) << 32) | mfilt[0]; @@ -3123,12 +3280,14 @@ ath5k_get_stats(struct ieee80211_hw *hw,  		struct ieee80211_low_level_stats *stats)  {  	struct ath5k_softc *sc = hw->priv; -	struct ath5k_hw *ah = sc->ah;  	/* Force update */ -	ath5k_hw_update_mib_counters(ah, &sc->ll_stats); +	ath5k_hw_update_mib_counters(sc->ah); -	memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); +	stats->dot11ACKFailureCount = sc->stats.ack_fail; +	stats->dot11RTSFailureCount = sc->stats.rts_fail; +	stats->dot11RTSSuccessCount = sc->stats.rts_ok; +	stats->dot11FCSErrorCount = sc->stats.fcs_error;  	return 0;  }  |