aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohammed Shafi Shajakhan <mshajakhan@atheros.com>2010-11-23 10:12:27 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-11-30 13:49:13 -0500
commitea066d5a91f2610116dcd27054f749e4f07799d8 (patch)
tree451eb5ad15da0cf8c401dded725fe0f3838beb48
parentdd318575ff0aae91ac4cbcc5b60c184e59267212 (diff)
ath9k: Add support for Adaptive Power Management
This feature is to mitigate the problem of certain 3 stream chips that exceed the PCIe power requirements.An EEPROM flag controls which chips have APM enabled which is basically read from miscellaneous configuration element of the EEPROM header. This workaround will reduce power consumption by using 2 Tx chains for Single and Double stream rates (5 GHz only).All self generated frames (regardless of rate) are sent on 2 chains when this feature is enabled(Chip Limitation). Cc: Paul Shaw <paul.shaw@atheros.com> Signed-off-by: Mohammed Shafi Shajakhan <mshajakhan@atheros.com> Tested-by: Mohammed Shafi Shajakhan <mshajakhan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c23
9 files changed, 45 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 3161a5901a7a..4aecc10cb3a6 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3029,6 +3029,8 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
3029 return le32_to_cpu(pBase->swreg); 3029 return le32_to_cpu(pBase->swreg);
3030 case EEP_PAPRD: 3030 case EEP_PAPRD:
3031 return !!(pBase->featureEnable & BIT(5)); 3031 return !!(pBase->featureEnable & BIT(5));
3032 case EEP_CHAIN_MASK_REDUCE:
3033 return (pBase->miscConfiguration >> 0x3) & 0x1;
3032 default: 3034 default:
3033 return 0; 3035 return 0;
3034 } 3036 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 656d8ce251a7..b34a9e91edd8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -487,7 +487,11 @@ void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
487 break; 487 break;
488 } 488 }
489 489
490 REG_WRITE(ah, AR_SELFGEN_MASK, tx); 490 if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
491 REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
492 else
493 REG_WRITE(ah, AR_SELFGEN_MASK, tx);
494
491 if (tx == 0x5) { 495 if (tx == 0x5) {
492 REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, 496 REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
493 AR_PHY_SWAP_ALT_CHAIN); 497 AR_PHY_SWAP_ALT_CHAIN);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 6f90acc5cca7..efba413561a4 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -544,6 +544,7 @@ struct ath_ant_comb {
544#define SC_OP_BT_PRIORITY_DETECTED BIT(12) 544#define SC_OP_BT_PRIORITY_DETECTED BIT(12)
545#define SC_OP_BT_SCAN BIT(13) 545#define SC_OP_BT_SCAN BIT(13)
546#define SC_OP_ANI_RUN BIT(14) 546#define SC_OP_ANI_RUN BIT(14)
547#define SC_OP_ENABLE_APM BIT(15)
547 548
548/* Powersave flags */ 549/* Powersave flags */
549#define PS_WAIT_FOR_BEACON BIT(0) 550#define PS_WAIT_FOR_BEACON BIT(0)
@@ -695,6 +696,8 @@ static inline void ath_ahb_exit(void) {};
695void ath9k_ps_wakeup(struct ath_softc *sc); 696void ath9k_ps_wakeup(struct ath_softc *sc);
696void ath9k_ps_restore(struct ath_softc *sc); 697void ath9k_ps_restore(struct ath_softc *sc);
697 698
699u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
700
698void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif); 701void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
699int ath9k_wiphy_add(struct ath_softc *sc); 702int ath9k_wiphy_add(struct ath_softc *sc);
700int ath9k_wiphy_del(struct ath_wiphy *aphy); 703int ath9k_wiphy_del(struct ath_wiphy *aphy);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 30724a4e8bb2..47bedd82e9a9 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -103,7 +103,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
103 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); 103 memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
104 series[0].Tries = 1; 104 series[0].Tries = 1;
105 series[0].Rate = rate; 105 series[0].Rate = rate;
106 series[0].ChSel = common->tx_chainmask; 106 series[0].ChSel = ath_txchainmask_reduction(sc,
107 common->tx_chainmask, series[0].Rate);
107 series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; 108 series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
108 ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, 109 ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
109 series, 4, 0); 110 series, 4, 0);
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 3c99830dab0c..7755fb996caa 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -268,6 +268,7 @@ enum eeprom_param {
268 EEP_PAPRD, 268 EEP_PAPRD,
269 EEP_MODAL_VER, 269 EEP_MODAL_VER,
270 EEP_ANT_DIV_CTL1, 270 EEP_ANT_DIV_CTL1,
271 EEP_CHAIN_MASK_REDUCE
271}; 272};
272 273
273enum ar5416_rates { 274enum ar5416_rates {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 883f6cc7b82c..b4396a9578e5 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1974,6 +1974,12 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
1974 if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1)) 1974 if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
1975 pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB; 1975 pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
1976 } 1976 }
1977 if (AR_SREV_9300_20_OR_LATER(ah)) {
1978 if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE))
1979 pCap->hw_caps |= ATH9K_HW_CAP_APM;
1980 }
1981
1982
1977 1983
1978 return 0; 1984 return 0;
1979} 1985}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index cc8f3b9af71f..5fcfa48a45df 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -187,6 +187,7 @@ enum ath9k_hw_caps {
187 ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12), 187 ATH9K_HW_CAP_ANT_DIV_COMB = BIT(12),
188 ATH9K_HW_CAP_2GHZ = BIT(13), 188 ATH9K_HW_CAP_2GHZ = BIT(13),
189 ATH9K_HW_CAP_5GHZ = BIT(14), 189 ATH9K_HW_CAP_5GHZ = BIT(14),
190 ATH9K_HW_CAP_APM = BIT(15),
190}; 191};
191 192
192struct ath9k_hw_capabilities { 193struct ath9k_hw_capabilities {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 50bdb5db23b4..df1bfcfeb734 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -554,9 +554,12 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht)
554static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) 554static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
555{ 555{
556 struct ath_node *an; 556 struct ath_node *an;
557 557 struct ath_hw *ah = sc->sc_ah;
558 an = (struct ath_node *)sta->drv_priv; 558 an = (struct ath_node *)sta->drv_priv;
559 559
560 if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
561 sc->sc_flags |= SC_OP_ENABLE_APM;
562
560 if (sc->sc_flags & SC_OP_TXAGGR) { 563 if (sc->sc_flags & SC_OP_TXAGGR) {
561 ath_tx_node_init(sc, an); 564 ath_tx_node_init(sc, an);
562 an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + 565 an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 177a7b1de322..821d3679c6ff 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1506,6 +1506,18 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
1506 return duration; 1506 return duration;
1507} 1507}
1508 1508
1509u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
1510{
1511 struct ath_hw *ah = sc->sc_ah;
1512 struct ath9k_channel *curchan = ah->curchan;
1513 if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
1514 (curchan->channelFlags & CHANNEL_5GHZ) &&
1515 (chainmask == 0x7) && (rate < 0x90))
1516 return 0x3;
1517 else
1518 return chainmask;
1519}
1520
1509static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) 1521static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
1510{ 1522{
1511 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 1523 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1546,7 +1558,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
1546 1558
1547 rix = rates[i].idx; 1559 rix = rates[i].idx;
1548 series[i].Tries = rates[i].count; 1560 series[i].Tries = rates[i].count;
1549 series[i].ChSel = common->tx_chainmask;
1550 1561
1551 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) || 1562 if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
1552 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) { 1563 (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
@@ -1569,6 +1580,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
1569 if (rates[i].flags & IEEE80211_TX_RC_MCS) { 1580 if (rates[i].flags & IEEE80211_TX_RC_MCS) {
1570 /* MCS rates */ 1581 /* MCS rates */
1571 series[i].Rate = rix | 0x80; 1582 series[i].Rate = rix | 0x80;
1583 series[i].ChSel = ath_txchainmask_reduction(sc,
1584 common->tx_chainmask, series[i].Rate);
1572 series[i].PktDuration = ath_pkt_duration(sc, rix, len, 1585 series[i].PktDuration = ath_pkt_duration(sc, rix, len,
1573 is_40, is_sgi, is_sp); 1586 is_40, is_sgi, is_sp);
1574 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) 1587 if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
@@ -1576,7 +1589,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
1576 continue; 1589 continue;
1577 } 1590 }
1578 1591
1579 /* legcay rates */ 1592 /* legacy rates */
1580 if ((tx_info->band == IEEE80211_BAND_2GHZ) && 1593 if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
1581 !(rate->flags & IEEE80211_RATE_ERP_G)) 1594 !(rate->flags & IEEE80211_RATE_ERP_G))
1582 phy = WLAN_RC_PHY_CCK; 1595 phy = WLAN_RC_PHY_CCK;
@@ -1592,6 +1605,12 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
1592 is_sp = false; 1605 is_sp = false;
1593 } 1606 }
1594 1607
1608 if (bf->bf_state.bfs_paprd)
1609 series[i].ChSel = common->tx_chainmask;
1610 else
1611 series[i].ChSel = ath_txchainmask_reduction(sc,
1612 common->tx_chainmask, series[i].Rate);
1613
1595 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, 1614 series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
1596 phy, rate->bitrate * 100, len, rix, is_sp); 1615 phy, rate->bitrate * 100, len, rix, is_sp);
1597 } 1616 }