From 03fcc9bf43b27157fba896cb7d48a7e4ca4d02ee Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Mon, 18 Nov 2013 19:58:53 +0000 Subject: ath9k: merge a few reset / calibration fixes Signed-off-by: Felix Fietkau SVN-Revision: 38854 --- .../kernel/mac80211/patches/300-pending_work.patch | 230 ++++++++++++++++++++- 1 file changed, 227 insertions(+), 3 deletions(-) (limited to 'package/kernel/mac80211/patches/300-pending_work.patch') diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch index b0788e0046..4b0337276d 100644 --- a/package/kernel/mac80211/patches/300-pending_work.patch +++ b/package/kernel/mac80211/patches/300-pending_work.patch @@ -482,7 +482,15 @@ } --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c -@@ -454,7 +454,6 @@ static void ath9k_hw_init_config(struct +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + + #include "hw.h" +@@ -454,7 +455,6 @@ static void ath9k_hw_init_config(struct } ah->config.rx_intr_mitigation = true; @@ -490,6 +498,67 @@ /* * We need this for PCI devices only (Cardbus, PCI, miniPCI) +@@ -1502,8 +1502,9 @@ static bool ath9k_hw_channel_change(stru + int r; + + if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) { +- band_switch = IS_CHAN_5GHZ(ah->curchan) != IS_CHAN_5GHZ(chan); +- mode_diff = (chan->channelFlags != ah->curchan->channelFlags); ++ u32 flags_diff = chan->channelFlags ^ ah->curchan->channelFlags; ++ band_switch = !!(flags_diff & CHANNEL_5GHZ); ++ mode_diff = !!(flags_diff & ~CHANNEL_HT); + } + + for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { +@@ -1815,7 +1816,7 @@ static int ath9k_hw_do_fastcc(struct ath + * If cross-band fcc is not supoprted, bail out if channelFlags differ. + */ + if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) && +- chan->channelFlags != ah->curchan->channelFlags) ++ ((chan->channelFlags ^ ah->curchan->channelFlags) & ~CHANNEL_HT)) + goto fail; + + if (!ath9k_hw_check_alive(ah)) +@@ -1856,10 +1857,12 @@ int ath9k_hw_reset(struct ath_hw *ah, st + struct ath9k_hw_cal_data *caldata, bool fastcc) + { + struct ath_common *common = ath9k_hw_common(ah); ++ struct timespec ts; + u32 saveLedState; + u32 saveDefAntenna; + u32 macStaId1; + u64 tsf = 0; ++ s64 usec = 0; + int r; + bool start_mci_reset = false; + bool save_fullsleep = ah->chip_fullsleep; +@@ -1902,10 +1905,10 @@ int ath9k_hw_reset(struct ath_hw *ah, st + + macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; + +- /* For chips on which RTC reset is done, save TSF before it gets cleared */ +- if (AR_SREV_9100(ah) || +- (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))) +- tsf = ath9k_hw_gettsf64(ah); ++ /* Save TSF before chip reset, a cold reset clears it */ ++ tsf = ath9k_hw_gettsf64(ah); ++ getrawmonotonic(&ts); ++ usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000; + + saveLedState = REG_READ(ah, AR_CFG_LED) & + (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | +@@ -1938,8 +1941,9 @@ int ath9k_hw_reset(struct ath_hw *ah, st + } + + /* Restore TSF */ +- if (tsf) +- ath9k_hw_settsf64(ah, tsf); ++ getrawmonotonic(&ts); ++ usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec; ++ ath9k_hw_settsf64(ah, tsf + usec); + + if (AR_SREV_9280_20_OR_LATER(ah)) + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE); --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -283,7 +283,6 @@ struct ath9k_ops_config { @@ -4417,7 +4486,24 @@ --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c -@@ -701,6 +701,54 @@ static int ar9550_hw_get_modes_txgain_in +@@ -641,11 +641,12 @@ static void ar9003_hw_override_ini(struc + else + ah->enabled_cals &= ~TX_IQ_CAL; + +- if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) +- ah->enabled_cals |= TX_CL_CAL; +- else +- ah->enabled_cals &= ~TX_CL_CAL; + } ++ ++ if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) ++ ah->enabled_cals |= TX_CL_CAL; ++ else ++ ah->enabled_cals &= ~TX_CL_CAL; + } + + static void ar9003_hw_prog_ini(struct ath_hw *ah, +@@ -701,6 +702,54 @@ static int ar9550_hw_get_modes_txgain_in return ret; } @@ -4472,7 +4558,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan) { -@@ -726,6 +774,8 @@ static int ar9003_hw_process_ini(struct +@@ -726,6 +775,8 @@ static int ar9003_hw_process_ini(struct modesIndex); } @@ -4527,3 +4613,141 @@ skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); } } +--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c +@@ -1040,8 +1040,8 @@ static void ar9003_hw_cl_cal_post_proc(s + } + } + +-static bool ar9003_hw_init_cal(struct ath_hw *ah, +- struct ath9k_channel *chan) ++static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, ++ struct ath9k_channel *chan) + { + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_cal_data *caldata = ah->caldata; +@@ -1228,13 +1228,109 @@ skip_tx_iqcal: + return true; + } + ++static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, ++ struct ath9k_channel *chan) ++{ ++ struct ath_common *common = ath9k_hw_common(ah); ++ struct ath9k_hw_cal_data *caldata = ah->caldata; ++ bool txiqcal_done = false; ++ bool is_reusable = true, status = true; ++ bool run_agc_cal = false, sep_iq_cal = false; ++ ++ /* Use chip chainmask only for calibration */ ++ ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask); ++ ++ if (ah->enabled_cals & TX_CL_CAL) { ++ REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); ++ run_agc_cal = true; ++ } ++ ++ if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) ++ goto skip_tx_iqcal; ++ ++ /* Do Tx IQ Calibration */ ++ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, ++ AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, ++ DELPT); ++ ++ /* ++ * For AR9485 or later chips, TxIQ cal runs as part of ++ * AGC calibration. Specifically, AR9550 in SoC chips. ++ */ ++ if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) { ++ txiqcal_done = true; ++ run_agc_cal = true; ++ } else { ++ sep_iq_cal = true; ++ run_agc_cal = true; ++ } ++ ++ /* ++ * In the SoC family, this will run for AR9300, AR9331 and AR9340. ++ */ ++ if (sep_iq_cal) { ++ txiqcal_done = ar9003_hw_tx_iq_cal_run(ah); ++ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); ++ udelay(5); ++ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); ++ } ++ ++skip_tx_iqcal: ++ if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { ++ /* Calibrate the AGC */ ++ REG_WRITE(ah, AR_PHY_AGC_CONTROL, ++ REG_READ(ah, AR_PHY_AGC_CONTROL) | ++ AR_PHY_AGC_CONTROL_CAL); ++ ++ /* Poll for offset calibration complete */ ++ status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, ++ AR_PHY_AGC_CONTROL_CAL, ++ 0, AH_WAIT_TIMEOUT); ++ } ++ ++ if (!status) { ++ ath_dbg(common, CALIBRATE, ++ "offset calibration failed to complete in %d ms; noisy environment?\n", ++ AH_WAIT_TIMEOUT / 1000); ++ return false; ++ } ++ ++ if (txiqcal_done) ++ ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); ++ ++ /* Revert chainmask to runtime parameters */ ++ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ++ ++ /* Initialize list pointers */ ++ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; ++ ++ INIT_CAL(&ah->iq_caldata); ++ INSERT_CAL(ah, &ah->iq_caldata); ++ ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); ++ ++ /* Initialize current pointer to first element in list */ ++ ah->cal_list_curr = ah->cal_list; ++ ++ if (ah->cal_list_curr) ++ ath9k_hw_reset_calibration(ah, ah->cal_list_curr); ++ ++ if (caldata) ++ caldata->CalValid = 0; ++ ++ return true; ++} ++ + void ar9003_hw_attach_calib_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); + struct ath_hw_ops *ops = ath9k_hw_ops(ah); + ++ if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9565(ah)) ++ priv_ops->init_cal = ar9003_hw_init_cal_pcoem; ++ else ++ priv_ops->init_cal = ar9003_hw_init_cal_soc; ++ + priv_ops->init_cal_settings = ar9003_hw_init_cal_settings; +- priv_ops->init_cal = ar9003_hw_init_cal; + priv_ops->setup_calibration = ar9003_hw_setup_calibration; + + ops->calibrate = ar9003_hw_calibrate; +--- a/drivers/net/wireless/ath/ath9k/common.c ++++ b/drivers/net/wireless/ath/ath9k/common.c +@@ -98,10 +98,8 @@ struct ath9k_channel *ath9k_cmn_get_chan + { + struct ieee80211_channel *curchan = chandef->chan; + struct ath9k_channel *channel; +- u8 chan_idx; + +- chan_idx = curchan->hw_value; +- channel = &ah->channels[chan_idx]; ++ channel = &ah->channels[curchan->hw_value]; + ath9k_cmn_update_ichannel(channel, chandef); + + return channel; -- cgit v1.2.3