From a065784620a2b78a2bbd00e066c004644d227ea8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Fri, 8 Apr 2011 15:33:12 -0400 Subject: ath5k: improve pcal error handling for ENOMEM case The ath5k driver does kmalloc allocations for pcal info in a loop. But, if one fails it was simply returning -ENOMEM without freeing already allocated memory. This patch corrects that oversight. Reported-by: Eugene A. Shatokhin Signed-off-by: John W. Linville Reviewed-by: Bob Copeland --- drivers/net/wireless/ath/ath5k/eeprom.c | 129 +++++++++++++++++--------------- 1 file changed, 70 insertions(+), 59 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index b6561f785c6e..fb12027e0346 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100; } +static int +ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *chinfo; + u8 pier, pdg; + + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + chinfo = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { + if (!chinfo[pier].pd_curves) + continue; + + for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { + struct ath5k_pdgain_info *pd = + &chinfo[pier].pd_curves[pdg]; + + if (pd != NULL) { + kfree(pd->pd_step); + kfree(pd->pd_pwr); + } + } + + kfree(chinfo[pier].pd_curves); + } + + return 0; +} + /* Convert RF5111 specific data to generic raw data * used by interpolation code */ static int @@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Only one curve for RF5111 * find out which one and place @@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * (convert power to 0.25dB units @@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Fill pd_curves */ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { @@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; - + goto err_out; /* Fill raw dataset * (all power levels are in 0.25dB units) */ @@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * (all power levels are in 0.25dB units) */ @@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, GFP_KERNEL); if (!chinfo[pier].pd_curves) - return -ENOMEM; + goto err_out; /* Fill pd_curves */ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { @@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, sizeof(u8), GFP_KERNEL); if (!pd->pd_step) - return -ENOMEM; + goto err_out; pd->pd_pwr = kcalloc(pd->pd_points, sizeof(s16), GFP_KERNEL); if (!pd->pd_pwr) - return -ENOMEM; + goto err_out; /* Fill raw dataset * convert all pwr levels to @@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode, } return 0; + +err_out: + ath5k_eeprom_free_pcal_info(ah, mode); + return -ENOMEM; } /* Parse EEPROM data */ @@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) return 0; } -static int -ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode) -{ - struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - struct ath5k_chan_pcal_info *chinfo; - u8 pier, pdg; - - switch (mode) { - case AR5K_EEPROM_MODE_11A: - if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_a; - break; - case AR5K_EEPROM_MODE_11B: - if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_b; - break; - case AR5K_EEPROM_MODE_11G: - if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) - return 0; - chinfo = ee->ee_pwr_cal_g; - break; - default: - return -EINVAL; - } - - for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) { - if (!chinfo[pier].pd_curves) - continue; - - for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) { - struct ath5k_pdgain_info *pd = - &chinfo[pier].pd_curves[pdg]; - - if (pd != NULL) { - kfree(pd->pd_step); - kfree(pd->pd_pwr); - } - } - - kfree(chinfo[pier].pd_curves); - } - - return 0; -} - /* Read conformance test limits used for regulatory control */ static int ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) -- cgit v1.2.3 From 6d7b97b23e114c8fbb825e6721164d228c1af3fc Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 21:37:14 +0200 Subject: ath5k: fix tx status reporting issues During normal operation, minstrel was showing suspicious EWMA probabilities exceeding 100%. It looks like the tx status reporting in ath5k was not properly clearing the rate index for rates which were never attempted. This is caused by uninitialized stale data in the on-stack tx status information, which is reused when more frames are received. To fix this, rely on ts->ts_final_idx to select the last attempted rate, instead of checking whether ts->ts_rate is set. Additionally, the conversion from the driver rate index back to the mac80211 rate index can be dropped, as the mac80211 tx status will still have the original rate index which was used to set up the descriptor. Additionally, one more inaccuracy was fixed - the final rate attempt count only needs to be increased by one if the transmission attempt was successful. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4d7f21ee111c..753662f98f75 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1580,21 +1580,14 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb, info = IEEE80211_SKB_CB(skb); 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 = ts->ts_retry[i]; } - /* count the successful attempt as well */ - info->status.rates[ts->ts_final_idx].count++; + info->status.rates[ts->ts_final_idx + 1].idx = -1; if (unlikely(ts->ts_status)) { sc->stats.ack_fail++; @@ -1609,6 +1602,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++; } /* -- cgit v1.2.3 From a27049e2c926bcf68360532a5ae66e408296ae85 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 23:10:19 +0200 Subject: ath5k: fix short preamble rate duration value Subtract the difference in preamble duration (in usec) from the value returned by ieee80211_generic_frame_duration. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/pcu.c | 31 ++++++++++++------------------- drivers/net/wireless/ath/ath5k/qcu.c | 2 +- 3 files changed, 14 insertions(+), 21 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 8a06dbd39629..996d8afafdb7 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1233,7 +1233,7 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); /* Protocol Control Unit Functions */ /* Helpers */ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, - int len, struct ieee80211_rate *rate); + int len, struct ieee80211_rate *rate, bool shortpre); unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah); unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah); extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode); diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index a702817daf72..e342e470fb05 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -75,7 +75,7 @@ static const unsigned int ack_rates_high[] = * bwmodes. */ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, - int len, struct ieee80211_rate *rate) + int len, struct ieee80211_rate *rate, bool shortpre) { struct ath5k_softc *sc = ah->ah_sc; int sifs, preamble, plcp_bits, sym_time; @@ -84,9 +84,15 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah, /* Fallback */ if (!ah->ah_bwmode) { - dur = ieee80211_generic_frame_duration(sc->hw, - NULL, len, rate); - return le16_to_cpu(dur); + __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw, + NULL, len, rate); + + /* subtract difference between long and short preamble */ + dur = le16_to_cpu(raw_dur); + if (shortpre) + dur -= 96; + + return dur; } bitrate = rate->bitrate; @@ -263,27 +269,14 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah) * actual rate for this rate. See mac80211 tx.c * ieee80211_duration() for a brief description of * what rate we should choose to TX ACKs. */ - tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); + tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); ath5k_hw_reg_write(ah, tx_time, reg); if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)) continue; - /* - * We're not distinguishing short preamble here, - * This is true, all we'll get is a longer value here - * which is not necessarilly bad. We could use - * export ieee80211_frame_duration() but that needs to be - * fixed first to be properly used by mac802111 drivers: - * - * - remove erp stuff and let the routine figure ofdm - * erp rates - * - remove passing argument ieee80211_local as - * drivers don't have access to it - * - move drivers using ieee80211_generic_frame_duration() - * to this - */ + tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true); ath5k_hw_reg_write(ah, tx_time, reg + (AR5K_SET_SHORT_PREAMBLE << 2)); } diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 3343fb9e4940..93abcfacd990 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -550,7 +550,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) else rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; - ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate); + ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false); /* ack_tx_time includes an SIFS already */ eifs = ack_tx_time + sifs + 2 * slot_time; -- cgit v1.2.3 From 488a50176c169eb36544b4f970c8bba68ede30a1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 23:10:20 +0200 Subject: ath5k: fix SIFS time handling ath5k uses 8 usec as a sifs time, extracted from the initvals, whereas the standard requires a sifs time of 10. The difference originates from the fact that the SIFS register has an offset of 2 usec. Fix the SIFS time definition to use the standard value of 10 usec and subtract 2 usecs when writing the SIFS register. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 3 +-- drivers/net/wireless/ath/ath5k/qcu.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 996d8afafdb7..a49aeac378cd 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -224,8 +224,7 @@ /* SIFS */ #define AR5K_INIT_SIFS_TURBO 6 -/* XXX: 8 from initvals 10 from standard */ -#define AR5K_INIT_SIFS_DEFAULT_BG 8 +#define AR5K_INIT_SIFS_DEFAULT_BG 10 #define AR5K_INIT_SIFS_DEFAULT_A 16 #define AR5K_INIT_SIFS_HALF_RATE 32 #define AR5K_INIT_SIFS_QUARTER_RATE 64 diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 93abcfacd990..b18c5021aac3 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -519,7 +519,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) return -EINVAL; sifs = ath5k_hw_get_default_sifs(ah); - sifs_clock = ath5k_hw_htoclock(ah, sifs); + sifs_clock = ath5k_hw_htoclock(ah, sifs - 2); /* EIFS * Txtime of ack at lowest rate + SIFS + DIFS -- cgit v1.2.3 From b1ad1b6febb7772583c98d9a879fbbdb82a726a7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 9 Apr 2011 23:10:21 +0200 Subject: ath5k: fix slot time handling Set the slot time based on the mac80211 short slot vs long slot setting instead of just forcing long slot for all CCK-enabled channels. This slightly improves 802.11g mode performance in in my tests. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/mac80211-ops.c | 9 +++++++++ drivers/net/wireless/ath/ath5k/pcu.c | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index a49aeac378cd..4bb381cae08d 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1057,6 +1057,7 @@ struct ath5k_hw { u8 ah_coverage_class; bool ah_ack_bitrate_high; u8 ah_bwmode; + bool ah_short_slot; /* Antenna Control */ u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 9be29b728b1c..807bd6440169 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -282,6 +282,15 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_BEACON_INT) sc->bintval = bss_conf->beacon_int; + if (changes & BSS_CHANGED_ERP_SLOT) { + int slot_time; + + ah->ah_short_slot = bss_conf->use_short_slot; + slot_time = ath5k_hw_get_default_slottime(ah) + + 3 * ah->ah_coverage_class; + ath5k_hw_set_ifs_intervals(ah, slot_time); + } + if (changes & BSS_CHANGED_ASSOC) { avf->assoc = bss_conf->assoc; if (bss_conf->assoc) diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index e342e470fb05..71b60b7c617e 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -151,9 +151,9 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE; break; case AR5K_BWMODE_DEFAULT: - slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; default: - if (channel->hw_value & CHANNEL_CCK) + slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; + if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot) slot_time = AR5K_INIT_SLOT_TIME_B; break; } -- cgit v1.2.3 From c5e0a88aa2e0f42cdb4c79c977c52f6bc38ec160 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:13 +0200 Subject: ath5k: optimize tx descriptor setup Use local variables to reduce the number of load/store operations on uncached memory. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/desc.c | 38 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 16b44ff7dd3e..0a8a9efaf8b4 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -184,6 +184,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; + u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; @@ -209,7 +210,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, tx_power = AR5K_TUNE_MAX_TXPOWER; /* Clear descriptor */ - memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc)); + memset(&desc->ud.ds_tx5212.tx_stat, 0, + sizeof(desc->ud.ds_tx5212.tx_stat)); /* Setup control descriptor */ @@ -221,7 +223,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; - tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ @@ -232,21 +234,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; - tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; - tx_ctl->tx_control_0 |= - AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | - AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); - tx_ctl->tx_control_1 |= AR5K_REG_SM(type, - AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); - tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); - tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | + AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); + txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); + txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); + txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ - tx_ctl->tx_control_##_c |= \ - AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ + txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); @@ -262,8 +260,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { - tx_ctl->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; - tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, + txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + txctl1 |= AR5K_REG_SM(key_index, AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); } @@ -274,12 +272,16 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; - tx_ctl->tx_control_2 |= rtscts_duration & - AR5K_4W_TX_DESC_CTL2_RTS_DURATION; - tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate, + txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; + txctl3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } + tx_ctl->tx_control_0 = txctl0; + tx_ctl->tx_control_1 = txctl1; + tx_ctl->tx_control_2 = txctl2; + tx_ctl->tx_control_3 = txctl3; + return 0; } -- cgit v1.2.3 From fe12081cb664cd5d412dc56de0585a80484b1331 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:14 +0200 Subject: ath5k: remove ts_rate from ath5k_tx_status It is no longer necessary for preparing mac80211 tx status Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 1 - drivers/net/wireless/ath/ath5k/desc.c | 13 ------------- 2 files changed, 14 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 4bb381cae08d..aa588a0521c1 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -452,7 +452,6 @@ struct ath5k_tx_status { u16 ts_seqnum; u16 ts_tstamp; u8 ts_status; - u8 ts_rate[4]; u8 ts_retry[4]; u8 ts_final_idx; s8 ts_rssi; diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 0a8a9efaf8b4..990a3b421443 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -375,8 +375,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = 1; ts->ts_status = 0; - ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0, - AR5K_2W_TX_DESC_CTL0_XMIT_RATE); ts->ts_retry[0] = ts->ts_longretry; ts->ts_final_idx = 0; @@ -439,32 +437,21 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; switch (ts->ts_final_idx) { case 3: - ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); - ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); ts->ts_longretry += ts->ts_retry[2]; /* fall through */ case 2: - ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); - ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[1]; /* fall through */ case 1: - ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3, - AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); - ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[0]; /* fall through */ case 0: - ts->ts_rate[0] = tx_ctl->tx_control_3 & - AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; break; } -- cgit v1.2.3 From b161b89fb97b30233526d31c5f94397ed94ffea6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:15 +0200 Subject: ath5k: optimize tx status processing Use ACCESS_ONCE to reduce the number of variable reloads on uncached memory Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/desc.c | 37 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 990a3b421443..3758b967029a 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -401,32 +401,38 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; + u32 txstat0, txstat1, txctl2; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_status = &desc->ud.ds_tx5212.tx_stat; + txstat1 = ACCESS_ONCE(tx_status->tx_status_1); + /* No frame has been send or error */ - if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE))) + if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE))) return -EINPROGRESS; + txstat0 = ACCESS_ONCE(tx_status->tx_status_0); + txctl2 = ACCESS_ONCE(tx_ctl->tx_control_2); + /* * Get descriptor status */ - ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_tstamp = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); - ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_shortretry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_longretry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); - ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_seqnum = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_SEQ_NUM); - ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_rssi = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); - ts->ts_antenna = (tx_status->tx_status_1 & + ts->ts_antenna = (txstat1 & AR5K_DESC_TX_STATUS1_XMIT_ANTENNA_5212) ? 2 : 1; ts->ts_status = 0; - ts->ts_final_idx = AR5K_REG_MS(tx_status->tx_status_1, + ts->ts_final_idx = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); /* The longretry counter has the number of un-acked retries @@ -437,17 +443,17 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; switch (ts->ts_final_idx) { case 3: - ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2, + ts->ts_retry[2] = AR5K_REG_MS(txctl2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); ts->ts_longretry += ts->ts_retry[2]; /* fall through */ case 2: - ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2, + ts->ts_retry[1] = AR5K_REG_MS(txctl2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[1]; /* fall through */ case 1: - ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2, + ts->ts_retry[0] = AR5K_REG_MS(txctl2, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); ts->ts_longretry += ts->ts_retry[0]; /* fall through */ @@ -456,15 +462,14 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, } /* TX error */ - if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { - if (tx_status->tx_status_0 & - AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { + if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) ts->ts_status |= AR5K_TXERR_XRETRY; - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) ts->ts_status |= AR5K_TXERR_FIFO; - if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED) ts->ts_status |= AR5K_TXERR_FILT; } -- cgit v1.2.3 From b2fd97d0190a400b49a2f910109a4a492bfea319 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:16 +0200 Subject: ath5k: optimize rx status processing Use ACCESS_ONCE to reduce the number of redundant loads on uncached memory Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/desc.c | 41 +++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 3758b967029a..e366d30ef039 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -603,37 +603,37 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, struct ath5k_rx_status *rs) { struct ath5k_hw_rx_status *rx_status; + u32 rxstat0, rxstat1; rx_status = &desc->ud.ds_rx.rx_stat; + rxstat1 = ACCESS_ONCE(rx_status->rx_status_1); /* No frame received / not ready */ - if (unlikely(!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DONE))) + if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE))) return -EINPROGRESS; memset(rs, 0, sizeof(struct ath5k_rx_status)); + rxstat0 = ACCESS_ONCE(rx_status->rx_status_0); /* * Frame receive status */ - rs->rs_datalen = rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_DATA_LEN; - rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN; + rs->rs_rssi = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL); - rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_rate = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE); - rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0, + rs->rs_antenna = AR5K_REG_MS(rxstat0, AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA); - rs->rs_more = !!(rx_status->rx_status_0 & - AR5K_5212_RX_DESC_STATUS0_MORE); - rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE); + rs->rs_tstamp = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); /* * Key table status */ - if (rx_status->rx_status_1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) - rs->rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID) + rs->rs_keyix = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_KEY_INDEX); else rs->rs_keyix = AR5K_RXKEYIX_INVALID; @@ -641,27 +641,22 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, /* * Receive/descriptor errors */ - if (!(rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) + if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) { + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR) rs->rs_status |= AR5K_RXERR_CRC; - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) { rs->rs_status |= AR5K_RXERR_PHY; - rs->rs_phyerr = AR5K_REG_MS(rx_status->rx_status_1, + rs->rs_phyerr = AR5K_REG_MS(rxstat1, AR5K_5212_RX_DESC_STATUS1_PHY_ERROR_CODE); if (!ah->ah_capabilities.cap_has_phyerr_counters) ath5k_ani_phy_error_report(ah, rs->rs_phyerr); } - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) rs->rs_status |= AR5K_RXERR_DECRYPT; - if (rx_status->rx_status_1 & - AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) + if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR) rs->rs_status |= AR5K_RXERR_MIC; } return 0; -- cgit v1.2.3 From ed8950857f728303a1463ac9267e72c278738bf6 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:17 +0200 Subject: ath5k: remove ts_retry from ath5k_tx_status Reusing the configured retry counts from the skb cb is more efficient than reloading the data from uncached memory. Replace ts_longretry (unused) with ts_final_retry which contains the retry count for the final rate only Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 3 +-- drivers/net/wireless/ath/ath5k/base.c | 11 +++++++++-- drivers/net/wireless/ath/ath5k/desc.c | 34 +++------------------------------- 3 files changed, 13 insertions(+), 35 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index aa588a0521c1..fcaf4ed84ca5 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -452,11 +452,10 @@ struct ath5k_tx_status { u16 ts_seqnum; u16 ts_tstamp; u8 ts_status; - u8 ts_retry[4]; u8 ts_final_idx; + u8 ts_final_retry; s8 ts_rssi; u8 ts_shortretry; - u8 ts_longretry; u8 ts_virtcol; u8 ts_antenna; }; diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 753662f98f75..1a561b89221e 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1573,20 +1573,27 @@ 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 <= ts->ts_final_idx; i++) { + + for (i = 0; i < ts->ts_final_idx; i++) { struct ieee80211_tx_rate *r = &info->status.rates[i]; - r->count = ts->ts_retry[i]; + r->count = tries[i]; } + 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)) { diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index e366d30ef039..0391813befd1 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -366,7 +366,7 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); /*TODO: ts->ts_virtcol + test*/ ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, @@ -375,7 +375,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); ts->ts_antenna = 1; ts->ts_status = 0; - ts->ts_retry[0] = ts->ts_longretry; ts->ts_final_idx = 0; if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { @@ -401,7 +400,7 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; struct ath5k_hw_tx_status *tx_status; - u32 txstat0, txstat1, txctl2; + u32 txstat0, txstat1; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; tx_status = &desc->ud.ds_tx5212.tx_stat; @@ -413,7 +412,6 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, return -EINPROGRESS; txstat0 = ACCESS_ONCE(tx_status->tx_status_0); - txctl2 = ACCESS_ONCE(tx_ctl->tx_control_2); /* * Get descriptor status @@ -422,7 +420,7 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); ts->ts_shortretry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); - ts->ts_longretry = AR5K_REG_MS(txstat0, + ts->ts_final_retry = AR5K_REG_MS(txstat0, AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); ts->ts_seqnum = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_SEQ_NUM); @@ -435,32 +433,6 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, ts->ts_final_idx = AR5K_REG_MS(txstat1, AR5K_DESC_TX_STATUS1_FINAL_TS_IX_5212); - /* The longretry counter has the number of un-acked retries - * for the final rate. To get the total number of retries - * we have to add the retry counters for the other rates - * as well - */ - ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry; - switch (ts->ts_final_idx) { - case 3: - ts->ts_retry[2] = AR5K_REG_MS(txctl2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); - ts->ts_longretry += ts->ts_retry[2]; - /* fall through */ - case 2: - ts->ts_retry[1] = AR5K_REG_MS(txctl2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - ts->ts_longretry += ts->ts_retry[1]; - /* fall through */ - case 1: - ts->ts_retry[0] = AR5K_REG_MS(txctl2, - AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); - ts->ts_longretry += ts->ts_retry[0]; - /* fall through */ - case 0: - break; - } - /* TX error */ if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) { if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) -- cgit v1.2.3 From 5b7916ad8c29da9f30fbf03a8b61862acdba00ce Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:18 +0200 Subject: ath5k: clean up debugfs code The pointers to the debugfs entries do not need to be saved, because they will be recursively removed when the wiphy is unregistered. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/base.c | 1 - drivers/net/wireless/ath/ath5k/debug.c | 65 ++++++++++------------------------ drivers/net/wireless/ath/ath5k/debug.h | 17 --------- 3 files changed, 19 insertions(+), 64 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 1a561b89221e..a799d04e0c8c 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2901,7 +2901,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); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 0230f30e9e9a..0bf7313b8a17 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -888,65 +888,38 @@ static const struct file_operations fops_queue = { void ath5k_debug_init_device(struct ath5k_softc *sc) { - sc->debug.level = ath5k_debug; + struct dentry *phydir; - sc->debug.debugfs_phydir = debugfs_create_dir("ath5k", - sc->hw->wiphy->debugfsdir); + sc->debug.level = ath5k_debug; - sc->debug.debugfs_debug = debugfs_create_file("debug", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_debug); + phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir); + if (!phydir) + return; - sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_registers); + debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc, + &fops_debug); - sc->debug.debugfs_beacon = debugfs_create_file("beacon", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_beacon); + debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers); - sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR, - sc->debug.debugfs_phydir, sc, &fops_reset); + debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc, + &fops_beacon); - sc->debug.debugfs_antenna = debugfs_create_file("antenna", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_antenna); + debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset); - sc->debug.debugfs_misc = debugfs_create_file("misc", - S_IRUSR, - sc->debug.debugfs_phydir, sc, &fops_misc); + debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc, + &fops_antenna); - sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_frameerrors); + debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc); - sc->debug.debugfs_ani = debugfs_create_file("ani", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_ani); + debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc, + &fops_frameerrors); - sc->debug.debugfs_queue = debugfs_create_file("queue", - S_IWUSR | S_IRUSR, - sc->debug.debugfs_phydir, sc, - &fops_queue); -} + debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani); -void -ath5k_debug_finish_device(struct ath5k_softc *sc) -{ - debugfs_remove(sc->debug.debugfs_debug); - debugfs_remove(sc->debug.debugfs_registers); - debugfs_remove(sc->debug.debugfs_beacon); - debugfs_remove(sc->debug.debugfs_reset); - debugfs_remove(sc->debug.debugfs_antenna); - debugfs_remove(sc->debug.debugfs_misc); - debugfs_remove(sc->debug.debugfs_frameerrors); - debugfs_remove(sc->debug.debugfs_ani); - debugfs_remove(sc->debug.debugfs_queue); - debugfs_remove(sc->debug.debugfs_phydir); + debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc, + &fops_queue); } - /* functions used in other places */ void diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h index b0355aef68d3..193dd2d4ea3c 100644 --- a/drivers/net/wireless/ath/ath5k/debug.h +++ b/drivers/net/wireless/ath/ath5k/debug.h @@ -68,17 +68,6 @@ struct ath5k_buf; struct ath5k_dbg_info { unsigned int level; /* debug level */ - /* debugfs entries */ - struct dentry *debugfs_phydir; - struct dentry *debugfs_debug; - struct dentry *debugfs_registers; - struct dentry *debugfs_beacon; - struct dentry *debugfs_reset; - struct dentry *debugfs_antenna; - struct dentry *debugfs_misc; - struct dentry *debugfs_frameerrors; - struct dentry *debugfs_ani; - struct dentry *debugfs_queue; }; /** @@ -140,9 +129,6 @@ enum ath5k_debug_level { void ath5k_debug_init_device(struct ath5k_softc *sc); -void -ath5k_debug_finish_device(struct ath5k_softc *sc); - void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); @@ -166,9 +152,6 @@ ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) static inline void ath5k_debug_init_device(struct ath5k_softc *sc) {} -static inline void -ath5k_debug_finish_device(struct ath5k_softc *sc) {} - static inline void ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} -- cgit v1.2.3 From c266c71a9cbdccb40fb6f4c05d4ddaa6226e5eba Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 10 Apr 2011 18:32:19 +0200 Subject: ath5k: reduce interrupt load caused by rx/tx interrupts While the rx/tx tasklet is pending, new unnecessary interrupts may arrive. Decrease the load by temporarily disabling the interrupts until the tasklet has completed. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 13 ++++++++++ drivers/net/wireless/ath/ath5k/base.c | 45 +++++++++++++++++++++++++++++++--- drivers/net/wireless/ath/ath5k/base.h | 4 +++ 3 files changed, 59 insertions(+), 3 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index fcaf4ed84ca5..e303db7ee6f6 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -872,6 +872,19 @@ enum ath5k_int { AR5K_INT_QTRIG = 0x40000000, /* Non common */ AR5K_INT_GLOBAL = 0x80000000, + AR5K_INT_TX_ALL = AR5K_INT_TXOK + | AR5K_INT_TXDESC + | AR5K_INT_TXERR + | AR5K_INT_TXEOL + | AR5K_INT_TXURN, + + AR5K_INT_RX_ALL = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR + | AR5K_INT_RXNOFRM + | AR5K_INT_RXEOL + | AR5K_INT_RXORN, + AR5K_INT_COMMON = AR5K_INT_RXOK | AR5K_INT_RXDESC | AR5K_INT_RXERR diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index a799d04e0c8c..c7da00454397 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1443,6 +1443,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs) return true; } +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) { @@ -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); } @@ -1693,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); } @@ -2122,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) { @@ -2164,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); @@ -2182,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 */ } @@ -2204,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"); @@ -2575,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); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 978f1f4ac2f3..4c4e36064a3b 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -207,6 +207,10 @@ struct ath5k_softc { enum ath5k_int imask; /* interrupt mask copy */ + spinlock_t irqlock; + bool rx_pending; /* rx tasklet pending */ + bool tx_pending; /* tx tasklet pending */ + u8 lladdr[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; -- cgit v1.2.3 From 8962d87129ec0a820d17ac44cbf3f51010ad8db8 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 13 Apr 2011 08:47:32 -0400 Subject: ath5k: improve comments for optimized tx descriptor setup Comment the use of local variables to reduce the number of load/store operations on uncached memory, in hopes of not losing this optimization accidentally in the future. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/desc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 0391813befd1..dd7cd95c364a 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -184,6 +184,11 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; + + /* + * Use local variables for these to reduce load/store access on + * uncached memory + */ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; @@ -209,7 +214,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, if (tx_power > AR5K_TUNE_MAX_TXPOWER) tx_power = AR5K_TUNE_MAX_TXPOWER; - /* Clear descriptor */ + /* Clear descriptor status area */ memset(&desc->ud.ds_tx5212.tx_stat, 0, sizeof(desc->ud.ds_tx5212.tx_stat)); -- cgit v1.2.3 From 7f94f05b24b47f6b70f2322b26876d0636329dfe Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:42 +0200 Subject: ath5k: disable 5 GHz support if a 2.4 GHz radio is detected On a dual-radio dual-band AR5312 device, the calibration data is shared between the 5 GHz and the 2.4 GHz radio/MAC. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/caps.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index f77e8a703c5c..7dd88e1c3ff8 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -94,6 +94,9 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah) } } + if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112) + __clear_bit(AR5K_MODE_11A, caps->cap_mode); + /* Set number of supported TX queues */ if (ah->ah_version == AR5K_AR5210) caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU; -- cgit v1.2.3 From 0cb9e06b6359bfa82f46c38a0b43e72d90b84081 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:43 +0200 Subject: ath: unshare struct ath_bus_ops between ath5k and ath9k This struct is not used in any common code, and moving it out of the ath header makes it easier to add more driver specific ops. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ath5k.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index e303db7ee6f6..266e548acf78 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1155,6 +1155,12 @@ struct ath5k_hw { struct ath5k_rx_status *); }; +struct ath_bus_ops { + enum ath_bus_type ath_bus_type; + void (*read_cachesize)(struct ath_common *common, int *csz); + bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); +}; + /* * Prototypes */ -- cgit v1.2.3 From fa9bfd61e03e8dbcf110a93b373234d17a732233 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:44 +0200 Subject: ath5k: add a new bus op for reading the mac address On AHB, the calibration data usually does not contain a valid MAC address, the correct MAC address is stored in the board config. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ahb.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath5k/ath5k.h | 2 +- drivers/net/wireless/ath/ath5k/base.c | 2 +- drivers/net/wireless/ath/ath5k/eeprom.c | 29 ----------------------------- drivers/net/wireless/ath/ath5k/pci.c | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 31 deletions(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 82324e98efef..1374e647f4e6 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -18,6 +18,7 @@ #include #include +#include #include #include "ath5k.h" #include "debug.h" @@ -62,10 +63,27 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah) return 0; } +static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + struct ath5k_softc *sc = ah->ah_sc; + struct platform_device *pdev = to_platform_device(sc->dev); + struct ar231x_board_config *bcfg = pdev->dev.platform_data; + u8 *cfg_mac; + + if (to_platform_device(sc->dev)->id == 0) + cfg_mac = bcfg->config->wlan0_mac; + else + cfg_mac = bcfg->config->wlan1_mac; + + memcpy(mac, cfg_mac, ETH_ALEN); + return 0; +} + static const struct ath_bus_ops ath_ahb_bus_ops = { .ath_bus_type = ATH_AHB, .read_cachesize = ath5k_ahb_read_cachesize, .eeprom_read = ath5k_ahb_eeprom_read, + .eeprom_read_mac = ath5k_ahb_eeprom_read_mac, }; /*Initialization*/ diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 266e548acf78..bb50700436fe 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1159,6 +1159,7 @@ struct ath_bus_ops { enum ath_bus_type ath_bus_type; void (*read_cachesize)(struct ath_common *common, int *csz); bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data); + int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac); }; /* @@ -1244,7 +1245,6 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah); /* EEPROM access functions */ int ath5k_eeprom_init(struct ath5k_hw *ah); void ath5k_eeprom_detach(struct ath5k_hw *ah); -int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac); /* Protocol Control Unit Functions */ diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c7da00454397..7583841fc29a 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -2880,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; diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index fb12027e0346..e9263e4c7f3e 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -1732,35 +1732,6 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah) return ret; } -/* - * Read the MAC address from eeprom - */ -int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) -{ - u8 mac_d[ETH_ALEN] = {}; - u32 total, offset; - u16 data; - int octet; - - AR5K_EEPROM_READ(0x20, data); - - for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { - AR5K_EEPROM_READ(offset, data); - - total += data; - mac_d[octet + 1] = data & 0xff; - mac_d[octet] = data >> 8; - octet += 2; - } - - if (!total || total == 3 * 0xffff) - return -EINVAL; - - memcpy(mac, mac_d, ETH_ALEN); - - return 0; -} - /***********************\ * Init/Detach functions * diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 66598a0d1df0..5cc4a2fe47b6 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "../ath.h" #include "ath5k.h" #include "debug.h" @@ -108,11 +109,42 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah) return 0; } +/* + * Read the MAC address from eeprom or platform_data + */ +static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + u8 mac_d[ETH_ALEN] = {}; + u32 total, offset; + u16 data; + int octet; + + AR5K_EEPROM_READ(0x20, data); + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { + AR5K_EEPROM_READ(offset, data); + + total += data; + mac_d[octet + 1] = data & 0xff; + mac_d[octet] = data >> 8; + octet += 2; + } + + if (!total || total == 3 * 0xffff) + return -EINVAL; + + memcpy(mac, mac_d, ETH_ALEN); + + return 0; +} + + /* Common ath_bus_opts structure */ static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath5k_pci_read_cachesize, .eeprom_read = ath5k_pci_eeprom_read, + .eeprom_read_mac = ath5k_pci_eeprom_read_mac, }; /********************\ -- cgit v1.2.3 From 32377b6cf75247cbdd0640efb43bef992efe3b68 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:45 +0200 Subject: ath5k: fix the EEPROM check for hw AES crypto support EEPROM version 5.0 adds a new field for disabling AES support, having an older version means that AES is present. This patch fixes hw AES crypto support on AR5312 boards, which have an older EEPROM version. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/attach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index bc8240560488..326d7c84c912 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -318,7 +318,7 @@ int ath5k_hw_init(struct ath5k_softc *sc) AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); if (srev >= AR5K_SREV_AR5212_V4 && - (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 && + (ee->ee_version < AR5K_EEPROM_VERSION_5_0 || !AR5K_EEPROM_AES_DIS(ee->ee_misc5))) common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM; -- cgit v1.2.3 From 3a9dddea89eb2132ba919fe04cb3b44a3b1e6db7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 13 Apr 2011 21:56:46 +0200 Subject: ath5k: disable 5 GHz support for the dualband PHY chip on dual-radio AR5312 There are two variants of AR5312 dual-band devices, one single-radio and the other one dual-radio. On the dual-radio board, the first MAC only supports 5 GHz, even though it has a dual-band PHY. The 2.4 GHz part of this phy is used in pass-through mode, connecting the second MAC with the second PHY. Disable 2.4 GHz for the first MAC on an AR5312, but only if the board configuration indicates a dual-radio device. Signed-off-by: Felix Fietkau Tested-by: Sedat Dilek Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath5k/ahb.c | 10 ++++++++++ drivers/net/wireless/ath/ath5k/attach.c | 5 +++++ drivers/net/wireless/ath/ath5k/base.h | 3 ++- 3 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/net/wireless/ath/ath5k') diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index 1374e647f4e6..ea9982781559 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -160,6 +160,16 @@ static int ath_ahb_probe(struct platform_device *pdev) else reg |= AR5K_AR5312_ENABLE_WLAN1; __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); + + /* + * On a dual-band AR5312, the multiband radio is only + * used as pass-through. Disable 2 GHz support in the + * driver for it + */ + if (to_platform_device(sc->dev)->id == 0 && + (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) == + (BD_WLAN1|BD_WLAN0)) + __set_bit(ATH_STAT_2G_DISABLED, sc->status); } ret = ath5k_init_softc(sc, &ath_ahb_bus_ops); diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 326d7c84c912..1588401de3c4 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -313,6 +313,11 @@ int ath5k_hw_init(struct ath5k_softc *sc) goto err; } + if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) { + __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode); + __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode); + } + /* Crypto settings */ common->keymax = (sc->ah->ah_version == AR5K_AR5210 ? AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211); diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index 4c4e36064a3b..b294f3305011 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -193,12 +193,13 @@ struct ath5k_softc { dma_addr_t desc_daddr; /* DMA (physical) address */ size_t desc_len; /* size of TX/RX descriptors */ - DECLARE_BITMAP(status, 5); + DECLARE_BITMAP(status, 6); #define ATH_STAT_INVALID 0 /* disable hardware accesses */ #define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ #define ATH_STAT_PROMISC 2 #define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ #define ATH_STAT_STARTED 4 /* opened & irqs enabled */ +#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */ unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ struct ieee80211_channel *curchan; /* current h/w channel */ -- cgit v1.2.3