diff options
244 files changed, 12283 insertions, 6490 deletions
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 8420689..3510de2 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -159,6 +159,11 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211); /* + * Set default Tx frame to Tx data start delay + */ + txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT; + + /* * 5210 initvals don't include usec settings * so we need to use magic values here for * tx/rx latencies diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 5193ed5..6195639 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -21,11 +21,15 @@ #include <linux/ath9k_platform.h> #include "ath9k.h" -const struct platform_device_id ath9k_platform_id_table[] = { +static const struct platform_device_id ath9k_platform_id_table[] = { { .name = "ath9k", .driver_data = AR5416_AR9100_DEVID, }, + { + .name = "ar934x_wmac", + .driver_data = AR9300_DEVID_AR9340, + }, {}, }; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index 2e31c77..5a1f4f5 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -899,12 +899,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah) * check here default level should not modify INI setting. */ if (use_new_ani(ah)) { - const struct ani_ofdm_level_entry *entry_ofdm; - const struct ani_cck_level_entry *entry_cck; - - entry_ofdm = &ofdm_level_table[ATH9K_ANI_OFDM_DEF_LEVEL]; - entry_cck = &cck_level_table[ATH9K_ANI_CCK_DEF_LEVEL]; - ah->aniperiod = ATH9K_ANI_PERIOD_NEW; ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; } else { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 4a4cd88..f276cb9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -18,13 +18,13 @@ #include "hw-ops.h" #include "ar9003_phy.h" -#define MPASS 3 #define MAX_MEASUREMENT 8 -#define MAX_DIFFERENCE 10 +#define MAX_MAG_DELTA 11 +#define MAX_PHS_DELTA 10 struct coeff { - int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; - int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS]; + int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; + int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT]; int iqc_coeff[2]; }; @@ -185,17 +185,19 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah) /* Accumulate IQ cal measures for active chains */ for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ah->totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ah->totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ah->totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ah->cal_samples, i, ah->totalPowerMeasI[i], - ah->totalPowerMeasQ[i], - ah->totalIqCorrMeas[i]); + if (ah->txchainmask & BIT(i)) { + ah->totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ah->totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ah->totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ah->cal_samples, i, ah->totalPowerMeasI[i], + ah->totalPowerMeasQ[i], + ah->totalIqCorrMeas[i]); + } } } @@ -608,36 +610,48 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah, return true; } -static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg) +static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, + int max_delta) { - int diff[MPASS]; - - diff[0] = abs(mp_coeff[0] - mp_coeff[1]); - diff[1] = abs(mp_coeff[1] - mp_coeff[2]); - diff[2] = abs(mp_coeff[2] - mp_coeff[0]); - - if (diff[0] > MAX_DIFFERENCE && - diff[1] > MAX_DIFFERENCE && - diff[2] > MAX_DIFFERENCE) - return false; + int mp_max = -64, max_idx = 0; + int mp_min = 63, min_idx = 0; + int mp_avg = 0, i, outlier_idx = 0; + + /* find min/max mismatch across all calibrated gains */ + for (i = 0; i < nmeasurement; i++) { + mp_avg += mp_coeff[i]; + if (mp_coeff[i] > mp_max) { + mp_max = mp_coeff[i]; + max_idx = i; + } else if (mp_coeff[i] < mp_min) { + mp_min = mp_coeff[i]; + min_idx = i; + } + } - if (diff[0] <= diff[1] && diff[0] <= diff[2]) - *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2; - else if (diff[1] <= diff[2]) - *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2; - else - *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2; + /* find average (exclude max abs value) */ + for (i = 0; i < nmeasurement; i++) { + if ((abs(mp_coeff[i]) < abs(mp_max)) || + (abs(mp_coeff[i]) < abs(mp_min))) + mp_avg += mp_coeff[i]; + } + mp_avg /= (nmeasurement - 1); - return true; + /* detect outlier */ + if (abs(mp_max - mp_min) > max_delta) { + if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg)) + outlier_idx = max_idx; + else + outlier_idx = min_idx; + } + mp_coeff[outlier_idx] = mp_avg; } static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, u8 num_chains, struct coeff *coeff) { - struct ath_common *common = ath9k_hw_common(ah); int i, im, nmeasurement; - int magnitude, phase; u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff)); @@ -657,37 +671,28 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, /* Load the average of 2 passes */ for (i = 0; i < num_chains; i++) { - if (AR_SREV_9485(ah)) - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0_9485, - AR_PHY_CALIBRATED_GAINS_0); - else - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_CALIBRATED_GAINS_0); + nmeasurement = REG_READ_FIELD(ah, + AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_CALIBRATED_GAINS_0); if (nmeasurement > MAX_MEASUREMENT) nmeasurement = MAX_MEASUREMENT; - for (im = 0; im < nmeasurement; im++) { - /* - * Determine which 2 passes are closest and compute avg - * magnitude - */ - if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im], - &magnitude)) - goto disable_txiqcal; + /* detect outlier only if nmeasurement > 1 */ + if (nmeasurement > 1) { + /* Detect magnitude outlier */ + ar9003_hw_detect_outlier(coeff->mag_coeff[i], + nmeasurement, MAX_MAG_DELTA); - /* - * Determine which 2 passes are closest and compute avg - * phase - */ - if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im], - &phase)) - goto disable_txiqcal; + /* Detect phase outlier */ + ar9003_hw_detect_outlier(coeff->phs_coeff[i], + nmeasurement, MAX_PHS_DELTA); + } + + for (im = 0; im < nmeasurement; im++) { - coeff->iqc_coeff[0] = (magnitude & 0x7f) | - ((phase & 0x7f) << 7); + coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) | + ((coeff->phs_coeff[i][im] & 0x7f) << 7); if ((im % 2) == 0) REG_RMW_FIELD(ah, tx_corr_coeff[im][i], @@ -707,141 +712,37 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, return; -disable_txiqcal: - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, - AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0); - REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, - AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0); - - ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n"); } -static void ar9003_hw_tx_iq_cal(struct ath_hw *ah) +static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); - static const u32 txiqcal_status[AR9300_MAX_CHAINS] = { - AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_TX_IQCAL_STATUS_B1, - AR_PHY_TX_IQCAL_STATUS_B2, - }; - static const u32 chan_info_tab[] = { - AR_PHY_CHAN_INFO_TAB_0, - AR_PHY_CHAN_INFO_TAB_1, - AR_PHY_CHAN_INFO_TAB_2, - }; - struct coeff coeff; - s32 iq_res[6]; - s32 i, j, ip, im, nmeasurement; - u8 nchains = get_streams(common->tx_chainmask); - - for (ip = 0; ip < MPASS; ip++) { - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, - AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, - DELPT); - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, - AR_PHY_TX_IQCAL_START_DO_CAL, - AR_PHY_TX_IQCAL_START_DO_CAL); - - if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, - AR_PHY_TX_IQCAL_START_DO_CAL, - 0, AH_WAIT_TIMEOUT)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Tx IQ Cal not complete.\n"); - goto TX_IQ_CAL_FAILED; - } - - nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0, - AR_PHY_CALIBRATED_GAINS_0); - if (nmeasurement > MAX_MEASUREMENT) - nmeasurement = MAX_MEASUREMENT; - - for (i = 0; i < nchains; i++) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Doing Tx IQ Cal for chain %d.\n", i); - for (im = 0; im < nmeasurement; im++) { - if (REG_READ(ah, txiqcal_status[i]) & - AR_PHY_TX_IQCAL_STATUS_FAILED) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Tx IQ Cal failed for chain %d.\n", i); - goto TX_IQ_CAL_FAILED; - } - - for (j = 0; j < 3; j++) { - u8 idx = 2 * j, - offset = 4 * (3 * im + j); - - REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, - AR_PHY_CHAN_INFO_TAB_S2_READ, - 0); - - /* 32 bits */ - iq_res[idx] = REG_READ(ah, - chan_info_tab[i] + - offset); - - REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, - AR_PHY_CHAN_INFO_TAB_S2_READ, - 1); - - /* 16 bits */ - iq_res[idx+1] = 0xffff & REG_READ(ah, - chan_info_tab[i] + - offset); - - ath_dbg(common, ATH_DBG_CALIBRATE, - "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", - idx, iq_res[idx], idx+1, iq_res[idx+1]); - } - - if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, - coeff.iqc_coeff)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Failed in calculation of IQ correction.\n"); - goto TX_IQ_CAL_FAILED; - } - coeff.mag_coeff[i][im][ip] = - coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im][ip] = - (coeff.iqc_coeff[0] >> 7) & 0x7f; - - if (coeff.mag_coeff[i][im][ip] > 63) - coeff.mag_coeff[i][im][ip] -= 128; - if (coeff.phs_coeff[i][im][ip] > 63) - coeff.phs_coeff[i][im][ip] -= 128; - - } - } - } - - ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff); - - return; - -TX_IQ_CAL_FAILED: - ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); -} - -static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) -{ u8 tx_gain_forced; - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485, - AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE); if (tx_gain_forced) REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); - REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485, - AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1); + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, 1); + + if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START, + AR_PHY_TX_IQCAL_START_DO_CAL, 0, + AH_WAIT_TIMEOUT)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Tx IQ Cal is not completed.\n"); + return false; + } + return true; } static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); const u32 txiqcal_status[AR9300_MAX_CHAINS] = { - AR_PHY_TX_IQCAL_STATUS_B0_9485, + AR_PHY_TX_IQCAL_STATUS_B0, AR_PHY_TX_IQCAL_STATUS_B1, AR_PHY_TX_IQCAL_STATUS_B2, }; @@ -853,7 +754,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) struct coeff coeff; s32 iq_res[6]; u8 num_chains = 0; - int i, ip, im, j; + int i, im, j; int nmeasurement; for (i = 0; i < AR9300_MAX_CHAINS; i++) { @@ -861,71 +762,69 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) num_chains++; } - for (ip = 0; ip < MPASS; ip++) { - for (i = 0; i < num_chains; i++) { - nmeasurement = REG_READ_FIELD(ah, - AR_PHY_TX_IQCAL_STATUS_B0_9485, - AR_PHY_CALIBRATED_GAINS_0); - if (nmeasurement > MAX_MEASUREMENT) - nmeasurement = MAX_MEASUREMENT; + for (i = 0; i < num_chains; i++) { + nmeasurement = REG_READ_FIELD(ah, + AR_PHY_TX_IQCAL_STATUS_B0, + AR_PHY_CALIBRATED_GAINS_0); + if (nmeasurement > MAX_MEASUREMENT) + nmeasurement = MAX_MEASUREMENT; - for (im = 0; im < nmeasurement; im++) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Doing Tx IQ Cal for chain %d.\n", i); + for (im = 0; im < nmeasurement; im++) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Doing Tx IQ Cal for chain %d.\n", i); - if (REG_READ(ah, txiqcal_status[i]) & - AR_PHY_TX_IQCAL_STATUS_FAILED) { - ath_dbg(common, ATH_DBG_CALIBRATE, + if (REG_READ(ah, txiqcal_status[i]) & + AR_PHY_TX_IQCAL_STATUS_FAILED) { + ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed for chain %d.\n", i); - goto tx_iqcal_fail; - } + goto tx_iqcal_fail; + } - for (j = 0; j < 3; j++) { - u32 idx = 2 * j, offset = 4 * (3 * im + j); + for (j = 0; j < 3; j++) { + u32 idx = 2 * j, offset = 4 * (3 * im + j); - REG_RMW_FIELD(ah, + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 0); - /* 32 bits */ - iq_res[idx] = REG_READ(ah, - chan_info_tab[i] + - offset); + /* 32 bits */ + iq_res[idx] = REG_READ(ah, + chan_info_tab[i] + + offset); - REG_RMW_FIELD(ah, + REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 1); - /* 16 bits */ - iq_res[idx + 1] = 0xffff & REG_READ(ah, - chan_info_tab[i] + offset); + /* 16 bits */ + iq_res[idx + 1] = 0xffff & REG_READ(ah, + chan_info_tab[i] + offset); - ath_dbg(common, ATH_DBG_CALIBRATE, - "IQ RES[%d]=0x%x" - "IQ_RES[%d]=0x%x\n", - idx, iq_res[idx], idx + 1, - iq_res[idx + 1]); - } + ath_dbg(common, ATH_DBG_CALIBRATE, + "IQ RES[%d]=0x%x" + "IQ_RES[%d]=0x%x\n", + idx, iq_res[idx], idx + 1, + iq_res[idx + 1]); + } - if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, - coeff.iqc_coeff)) { - ath_dbg(common, ATH_DBG_CALIBRATE, - "Failed in calculation of IQ correction.\n"); - goto tx_iqcal_fail; - } + if (!ar9003_hw_calc_iq_corr(ah, i, iq_res, + coeff.iqc_coeff)) { + ath_dbg(common, ATH_DBG_CALIBRATE, + "Failed in calculation of \ + IQ correction.\n"); + goto tx_iqcal_fail; + } - coeff.mag_coeff[i][im][ip] = - coeff.iqc_coeff[0] & 0x7f; - coeff.phs_coeff[i][im][ip] = - (coeff.iqc_coeff[0] >> 7) & 0x7f; + coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f; + coeff.phs_coeff[i][im] = + (coeff.iqc_coeff[0] >> 7) & 0x7f; - if (coeff.mag_coeff[i][im][ip] > 63) - coeff.mag_coeff[i][im][ip] -= 128; - if (coeff.phs_coeff[i][im][ip] > 63) - coeff.phs_coeff[i][im][ip] -= 128; - } + if (coeff.mag_coeff[i][im] > 63) + coeff.mag_coeff[i][im] -= 128; + if (coeff.phs_coeff[i][im] > 63) + coeff.phs_coeff[i][im] -= 128; } } ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); @@ -940,31 +839,37 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pCap = &ah->caps; int val; + bool txiqcal_done = false; val = REG_READ(ah, AR_ENT_OTP); ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); - if (AR_SREV_9485(ah)) - ar9003_hw_set_chain_masks(ah, 0x1, 0x1); - else if (val & AR_ENT_OTP_CHAIN2_DISABLE) + /* Configure rx/tx chains before running AGC/TxiQ cals */ + if (val & AR_ENT_OTP_CHAIN2_DISABLE) ar9003_hw_set_chain_masks(ah, 0x3, 0x3); else - /* - * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain - * mode before running AGC/TxIQ cals - */ - ar9003_hw_set_chain_masks(ah, 0x7, 0x7); + ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask, + pCap->tx_chainmask); /* Do Tx IQ Calibration */ - if (AR_SREV_9485(ah)) - ar9003_hw_tx_iq_cal_run(ah); - else - ar9003_hw_tx_iq_cal(ah); + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, + AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, + DELPT); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); - udelay(5); - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + /* + * For AR9485 or later chips, TxIQ cal runs as part of + * AGC calibration + */ + if (AR_SREV_9485_OR_LATER(ah)) + txiqcal_done = true; + else { + 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); + } /* Calibrate the AGC */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, @@ -979,7 +884,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, return false; } - if (AR_SREV_9485(ah)) + if (txiqcal_done) ar9003_hw_tx_iq_cal_post_proc(ah); /* Revert chainmasks to their original values before NF cal */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 6eadf97..fb892e5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3217,7 +3217,6 @@ static int ar9300_compress_decision(struct ath_hw *ah, u8 *word, int length, int mdata_size) { struct ath_common *common = ath9k_hw_common(ah); - u8 *dptr; const struct ar9300_eeprom *eep = NULL; switch (code) { @@ -3235,7 +3234,6 @@ static int ar9300_compress_decision(struct ath_hw *ah, break; case _CompressBlock: if (reference == 0) { - dptr = mptr; } else { eep = ar9003_eeprom_struct_find_by_id(reference); if (eep == NULL) { @@ -3448,9 +3446,13 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); else { REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); - REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB, - bias >> 2); - REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1); + if (!AR_SREV_9340(ah)) { + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPABIASLVL_MSB, + bias >> 2); + REG_RMW_FIELD(ah, AR_CH0_THERM, + AR_CH0_THERM_XPASHORT2GND, 1); + } } } @@ -3497,23 +3499,28 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) { + int chain; + static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = { + AR_PHY_SWITCH_CHAIN_0, + AR_PHY_SWITCH_CHAIN_1, + AR_PHY_SWITCH_CHAIN_2, + }; + u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value); value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); - value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value); - - if (!AR_SREV_9485(ah)) { - value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL, - value); - - value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL, - value); + for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { + if ((ah->rxchainmask & BIT(chain)) || + (ah->txchainmask & BIT(chain))) { + value = ar9003_hw_ant_ctrl_chain_get(ah, chain, + is2ghz); + REG_RMW_FIELD(ah, switch_chain_reg[chain], + AR_SWITCH_TABLE_ALL, value); + } } if (AR_SREV_9485(ah)) { @@ -3634,13 +3641,16 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan) /* Test value. if 0 then attenuation is unused. Don't load anything. */ for (i = 0; i < 3; i++) { - value = ar9003_hw_atten_chain_get(ah, i, chan); - REG_RMW_FIELD(ah, ext_atten_reg[i], - AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); - - value = ar9003_hw_atten_chain_get_margin(ah, i, chan); - REG_RMW_FIELD(ah, ext_atten_reg[i], - AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value); + if (ah->txchainmask & BIT(i)) { + value = ar9003_hw_atten_chain_get(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value); + + value = ar9003_hw_atten_chain_get_margin(ah, i, chan); + REG_RMW_FIELD(ah, ext_atten_reg[i], + AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, + value); + } } } @@ -3749,8 +3759,9 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); ar9003_hw_drive_strength_apply(ah); ar9003_hw_atten_apply(ah, chan); - ar9003_hw_internal_regulator_apply(ah); - if (AR_SREV_9485(ah)) + if (!AR_SREV_9340(ah)) + ar9003_hw_internal_regulator_apply(ah); + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) ar9003_hw_apply_tuning_caps(ah); } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index aebaad9..a55eddb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -18,6 +18,7 @@ #include "ar9003_mac.h" #include "ar9003_2p2_initvals.h" #include "ar9485_initvals.h" +#include "ar9340_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -28,7 +29,63 @@ */ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) { - if (AR_SREV_9485_11(ah)) { + if (AR_SREV_9340(ah)) { + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar9340_1p0_mac_core, + ARRAY_SIZE(ar9340_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9340_1p0_mac_postamble, + ARRAY_SIZE(ar9340_1p0_mac_postamble), 5); + + /* bb */ + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9340_1p0_baseband_core, + ARRAY_SIZE(ar9340_1p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9340_1p0_baseband_postamble, + ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9340_1p0_radio_core, + ARRAY_SIZE(ar9340_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9340_1p0_radio_postamble, + ARRAY_SIZE(ar9340_1p0_radio_postamble), 5); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9340_1p0_soc_preamble, + ARRAY_SIZE(ar9340_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9340_1p0_soc_postamble, + ARRAY_SIZE(ar9340_1p0_soc_postamble), 5); + + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_high_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), + 5); + + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9340Modes_fast_clock_1p0, + ARRAY_SIZE(ar9340Modes_fast_clock_1p0), + 3); + + INIT_INI_ARRAY(&ah->iniModesAdditional_40M, + ar9340_1p0_radio_core_40M, + ARRAY_SIZE(ar9340_1p0_radio_core_40M), + 2); + } else if (AR_SREV_9485_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -163,7 +220,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) switch (ar9003_hw_get_tx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), @@ -175,7 +237,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 1: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), @@ -187,7 +254,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 2: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_low_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), @@ -199,7 +271,12 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) 5); break; case 3: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9485Modes_high_power_tx_gain_1_1, ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), @@ -218,7 +295,12 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) switch (ar9003_hw_get_rx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_rx_gain_table_1p0), + 2); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), @@ -230,7 +312,12 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah) 2); break; case 1: - if (AR_SREV_9485_11(ah)) + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 2); + else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 1bc33f5..c83be2d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -86,14 +86,31 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = (freq * 4) / 120; chan_frac = (((freq * 4) % 120) * 0x20000) / 120; channelSel = (channelSel << 17) | chan_frac; + } else if (AR_SREV_9340(ah)) { + if (ah->is_clk_25mhz) { + u32 chan_frac; + + channelSel = (freq * 2) / 75; + chan_frac = (((freq * 2) % 75) * 0x20000) / 75; + channelSel = (channelSel << 17) | chan_frac; + } else + channelSel = CHANSEL_2G(freq) >> 1; } else channelSel = CHANSEL_2G(freq); /* Set to 2G mode */ bMode = 1; } else { - channelSel = CHANSEL_5G(freq); - /* Doubler is ON, so, divide channelSel by 2. */ - channelSel >>= 1; + if (AR_SREV_9340(ah) && ah->is_clk_25mhz) { + u32 chan_frac; + + channelSel = (freq * 2) / 75; + chan_frac = ((freq % 75) * 0x20000) / 75; + channelSel = (channelSel << 17) | chan_frac; + } else { + channelSel = CHANSEL_5G(freq); + /* Doubler is ON, so, divide channelSel by 2. */ + channelSel >>= 1; + } /* Set to 5G mode */ bMode = 0; } @@ -151,7 +168,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, * is out-of-band and can be ignored. */ - if (AR_SREV_9485(ah)) { + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) { spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, IS_CHAN_2GHZ(chan)); if (spur_fbin_ptr[0] == 0) /* No spur */ @@ -176,7 +193,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, for (i = 0; i < max_spur_cnts; i++) { negative = 0; - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i], IS_CHAN_2GHZ(chan)) - synth_freq; else @@ -599,29 +616,25 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); unsigned int regWrites = 0, i; struct ieee80211_channel *channel = chan->chan; - u32 modesIndex, freqIndex; + u32 modesIndex; switch (chan->chanmode) { case CHANNEL_A: case CHANNEL_A_HT20: modesIndex = 1; - freqIndex = 1; break; case CHANNEL_A_HT40PLUS: case CHANNEL_A_HT40MINUS: modesIndex = 2; - freqIndex = 1; break; case CHANNEL_G: case CHANNEL_G_HT20: case CHANNEL_B: modesIndex = 4; - freqIndex = 2; break; case CHANNEL_G_HT40PLUS: case CHANNEL_G_HT40MINUS: modesIndex = 3; - freqIndex = 2; break; default: @@ -646,6 +659,9 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); + if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) + REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); + ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 8bdda2c..2a0d5cb 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -548,15 +548,12 @@ #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) -#define AR_PHY_TX_IQCAL_START_9485 (AR_SM_BASE + 0x3c4) -#define AR_PHY_TX_IQCAL_START_DO_CAL_9485 0x80000000 -#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S 31 -#define AR_PHY_TX_IQCAL_CONTROL_1_9485 (AR_SM_BASE + 0x3c8) -#define AR_PHY_TX_IQCAL_STATUS_B0_9485 (AR_SM_BASE + 0x3f0) - -#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + 0x448) -#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + 0x440) -#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c) +#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3c8 : 0x448) +#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3c4 : 0x440) +#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3f0 : 0x48c) #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ (AR_SREV_9485(ah) ? \ 0x3d0 : 0x450) + ((_i) << 2)) @@ -588,7 +585,7 @@ #define AR_PHY_65NM_CH0_BIAS2 0x160c4 #define AR_PHY_65NM_CH0_BIAS4 0x160cc #define AR_PHY_65NM_CH0_RXTX4 0x1610c -#define AR_PHY_65NM_CH0_THERM (AR_SREV_9485(ah) ? 0x1628c : 0x16290) +#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : 0x1628c) #define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 #define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 @@ -758,10 +755,10 @@ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 #define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004 -#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 -#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 -#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 -#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 +#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 +#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 +#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 +#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0 #define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001 #define AR_PHY_CALIBRATED_GAINS_0 0x3e diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h new file mode 100644 index 0000000..815a8af --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -0,0 +1,1525 @@ +/* + * Copyright (c) 2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_9340_H +#define INITVALS_9340_H + +static const u32 ar9340_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, + {0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, + {0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, +}; + +static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_fast_clock_1p0[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00001030, 0x00000268, 0x000004d0}, + {0x00001070, 0x0000018c, 0x00000318}, + {0x000010b0, 0x00000fd0, 0x00001fa0}, + {0x00008014, 0x044c044c, 0x08980898}, + {0x0000801c, 0x148ec02b, 0x148ec057}, + {0x00008318, 0x000044c0, 0x00008980}, + {0x00009e00, 0x03721821, 0x03721821}, + {0x0000a230, 0x0000000b, 0x00000016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +static const u32 ar9340_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x7f80fff8}, + {0x00016044, 0x03b6d2db}, + {0x00016048, 0x24925266}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x6db6db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f081c}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x00016098, 0xd411eb84}, + {0x0001609c, 0x03e47f32}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160ac, 0xa4646800}, + {0x000160b0, 0x00fe7f46}, + {0x000160b4, 0x92480000}, + {0x000160c0, 0x006db6db}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6de6db6c}, + {0x000160d0, 0xb6da4924}, + {0x00016100, 0x04cb0001}, + {0x00016104, 0xfff80000}, + {0x00016108, 0x00080010}, + {0x0001610c, 0x00000000}, + {0x00016140, 0x50804008}, + {0x00016144, 0x01884080}, + {0x00016148, 0x000080c0}, + {0x00016280, 0x01000015}, + {0x00016284, 0x05530000}, + {0x00016288, 0x00318000}, + {0x0001628c, 0x50000000}, + {0x00016290, 0x4080294f}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x7f80fff8}, + {0x00016444, 0x03b6d2db}, + {0x00016448, 0x24927266}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x6db6db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x04cb0001}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00080010}, + {0x0001650c, 0x00000000}, + {0x00016540, 0x50804008}, + {0x00016544, 0x01884080}, + {0x00016548, 0x000080c0}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, +}; + +static const u32 ar9340_1p0_radio_core_40M[][2] = { + {0x0001609c, 0x02566f3a}, + {0x000160ac, 0xa4647c00}, + {0x000160b0, 0x01885f5a}, +}; + +static const u32 ar9340_1p0_mac_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +}; + +static const u32 ar9340_1p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, +}; + +static const u32 ar9340_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044}, + {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, + {0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, +}; + +static const u32 ar9340_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0xb280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x5f3ca3de}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14750600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x52440bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e3c, 0xcf946222}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009e54, 0x00000000}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a22c, 0x01036a1e}, + {0x0000a234, 0x10000fff}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2dc, 0x00000000}, + {0x0000a2e0, 0x00000000}, + {0x0000a2e4, 0x00000000}, + {0x0000a2e8, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000246}, + {0x0000a3f8, 0x0cdbd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00000000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x04000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00000000}, + {0x0000a610, 0x00000000}, + {0x0000a614, 0x00000000}, + {0x0000a618, 0x00000000}, + {0x0000a61c, 0x00000000}, + {0x0000a620, 0x00000000}, + {0x0000a624, 0x00000000}, + {0x0000a628, 0x00000000}, + {0x0000a62c, 0x00000000}, + {0x0000a630, 0x00000000}, + {0x0000a634, 0x00000000}, + {0x0000a638, 0x00000000}, + {0x0000a63c, 0x00000000}, + {0x0000a640, 0x00000000}, + {0x0000a644, 0x3fad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00000637}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2dc, 0x00000000}, + {0x0000b2e0, 0x00000000}, + {0x0000b2e4, 0x00000000}, + {0x0000b2e8, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, +}; + +static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, + {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, +}; +static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, + {0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, + {0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, + {0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, +}; + + +static const u32 ar9340Common_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, +}; + +static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, + {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, + {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, + {0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402}, + {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640}, + {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, + {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, + {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, + {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, + {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x1c800223, 0x1c800223, 0x11800400, 0x11800400}, + {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402}, + {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266}, + {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266}, +}; + +static const u32 ar9340_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c20}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486200}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081c8, 0x00000000}, + {0x000081cc, 0x00000000}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f424}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e848}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9d400010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x00000007}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0x00ff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x000301ff}, +}; + +static const u32 ar9340Common_wo_xlna_rx_gain_table_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar9340_1p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x000040a4, 0x00a0c1c9}, + {0x00007008, 0x00000000}, + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, +}; + +#endif diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a6b5388..0312aa0 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -423,6 +423,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); #define ATH_PAPRD_TIMEOUT 100 /* msecs */ void ath_hw_check(struct work_struct *work); +void ath_hw_pll_work(struct work_struct *work); void ath_paprd_calibrate(struct work_struct *work); void ath_ani_calibrate(unsigned long data); @@ -453,6 +454,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc); #define ATH_LED_PIN_DEF 1 #define ATH_LED_PIN_9287 8 +#define ATH_LED_PIN_9300 10 #define ATH_LED_PIN_9485 6 #ifdef CONFIG_MAC80211_LEDS diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 24f565b..22cd241 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -781,12 +781,6 @@ void ath_set_beacon(struct ath_softc *sc) break; case NL80211_IFTYPE_STATION: ath_beacon_config_sta(sc, cur_conf); - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; break; default: ath_dbg(common, ATH_DBG_CONFIG, diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index d33bf20..23f15a7 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c @@ -51,6 +51,10 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) .bt_hold_rx_clear = true, }; u32 i; + bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity; + + if (AR_SREV_9300_20_OR_LATER(ah)) + rxclear_polarity = !ath_bt_config.bt_rxclear_polarity; btcoex_hw->bt_coex_mode = (btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) | @@ -59,7 +63,7 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum) SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) | SM(ath_bt_config.bt_mode, AR_BT_MODE) | SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) | - SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | + SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) | SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) | SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) | SM(qnum, AR_BT_QCU_THRESH); @@ -142,6 +146,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, } EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); + static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) { struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; @@ -152,9 +157,22 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah) * enable coex 3-wire */ REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, ah->bt_coex_wlan_weight[0]); + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, ah->bt_coex_wlan_weight[1]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, ah->bt_coex_bt_weight[0]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, ah->bt_coex_bt_weight[1]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, ah->bt_coex_bt_weight[2]); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, ah->bt_coex_bt_weight[3]); + + } else + REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights); + + + if (AR_SREV_9271(ah)) { val = REG_READ(ah, 0x50040); val &= 0xFFFFFEFF; @@ -202,10 +220,86 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) { REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE); - REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); REG_WRITE(ah, AR_BT_COEX_MODE2, 0); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0); + REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, 0); + REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, 0); + } else + REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0); + } ah->btcoex_hw.enabled = false; } EXPORT_SYMBOL(ath9k_hw_btcoex_disable); + +static void ar9003_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type) +{ + ah->bt_coex_bt_weight[0] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[1] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[2] = AR9300_BT_WGHT; + ah->bt_coex_bt_weight[3] = AR9300_BT_WGHT; + + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_ALL_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_ALL_WLAN_WGHT1; + break; + case ATH_BTCOEX_STOMP_LOW: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_LOW_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_LOW_WLAN_WGHT1; + break; + case ATH_BTCOEX_STOMP_NONE: + ah->bt_coex_wlan_weight[0] = AR9300_STOMP_NONE_WLAN_WGHT0; + ah->bt_coex_wlan_weight[1] = AR9300_STOMP_NONE_WLAN_WGHT1; + break; + + default: + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} + +/* + * Configures appropriate weight based on stomp type. + */ +void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type) +{ + if (AR_SREV_9300_20_OR_LATER(ah)) { + ar9003_btcoex_bt_stomp(ah, stomp_type); + return; + } + + switch (stomp_type) { + case ATH_BTCOEX_STOMP_ALL: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_ALL_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_LOW: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_LOW_WLAN_WGHT); + break; + case ATH_BTCOEX_STOMP_NONE: + ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, + AR_STOMP_NONE_WLAN_WGHT); + break; + default: + ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX, + "Invalid Stomptype\n"); + break; + } + + ath9k_hw_btcoex_enable(ah); +} +EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 588dfd4..a9efca8 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h @@ -19,9 +19,13 @@ #include "hw.h" -#define ATH_WLANACTIVE_GPIO 5 -#define ATH_BTACTIVE_GPIO 6 -#define ATH_BTPRIORITY_GPIO 7 +#define ATH_WLANACTIVE_GPIO_9280 5 +#define ATH_BTACTIVE_GPIO_9280 6 +#define ATH_BTPRIORITY_GPIO_9285 7 + +#define ATH_WLANACTIVE_GPIO_9300 5 +#define ATH_BTACTIVE_GPIO_9300 4 +#define ATH_BTPRIORITY_GPIO_9300 8 #define ATH_BTCOEX_DEF_BT_PERIOD 45 #define ATH_BTCOEX_DEF_DUTY_CYCLE 55 @@ -32,6 +36,14 @@ #define ATH_BT_CNT_THRESHOLD 3 #define ATH_BT_CNT_SCAN_THRESHOLD 15 +/* Defines the BT AR_BT_COEX_WGHT used */ +enum ath_stomp_type { + ATH_BTCOEX_NO_STOMP, + ATH_BTCOEX_STOMP_ALL, + ATH_BTCOEX_STOMP_LOW, + ATH_BTCOEX_STOMP_NONE +}; + enum ath_btcoex_scheme { ATH_BTCOEX_CFG_NONE, ATH_BTCOEX_CFG_2WIRE, @@ -57,5 +69,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah, u32 wlan_weight); void ath9k_hw_btcoex_enable(struct ath_hw *ah); void ath9k_hw_btcoex_disable(struct ath_hw *ah); +void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, + enum ath_stomp_type stomp_type); #endif diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 16ba8c6..74535e6 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -158,37 +158,6 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max) } EXPORT_SYMBOL(ath9k_cmn_count_streams); -/* - * Configures appropriate weight based on stomp type. - */ -void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common, - enum ath_stomp_type stomp_type) -{ - struct ath_hw *ah = common->ah; - - switch (stomp_type) { - case ATH_BTCOEX_STOMP_ALL: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_ALL_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_LOW: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_LOW_WLAN_WGHT); - break; - case ATH_BTCOEX_STOMP_NONE: - ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, - AR_STOMP_NONE_WLAN_WGHT); - break; - default: - ath_dbg(common, ATH_DBG_BTCOEX, - "Invalid Stomptype\n"); - break; - } - - ath9k_hw_btcoex_enable(ah); -} -EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp); - void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, u16 new_txpow, u16 *txpower) { diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index b2f7b5f..5124f14 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -50,14 +50,6 @@ #define ATH_EP_RND(x, mul) \ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -/* Defines the BT AR_BT_COEX_WGHT used */ -enum ath_stomp_type { - ATH_BTCOEX_NO_STOMP, - ATH_BTCOEX_STOMP_ALL, - ATH_BTCOEX_STOMP_LOW, - ATH_BTCOEX_STOMP_NONE -}; - int ath9k_cmn_padpos(__le16 frame_control); int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb); void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan, diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 34f191e..bad1a87 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -326,6 +326,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) sc->debug.stats.istats.dtimsync++; if (status & ATH9K_INT_DTIM) sc->debug.stats.istats.dtim++; + if (status & ATH9K_INT_TSFOOR) + sc->debug.stats.istats.tsfoor++; } static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, @@ -380,8 +382,11 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, len += snprintf(buf + len, sizeof(buf) - len, "%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim); len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TSFOOR", sc->debug.stats.istats.tsfoor); + len += snprintf(buf + len, sizeof(buf) - len, "%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total); + if (len > sizeof(buf)) len = sizeof(buf); diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 1f9f8ea..5488a32 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -54,6 +54,9 @@ struct ath_buf; * @dtimsync: DTIM sync lossage * @dtim: RX Beacon with DTIM * @bb_watchdog: Baseband watchdog + * @tsfoor: TSF out of range, indicates that the corrected TSF received + * from a beacon differs from the PCU's internal TSF by more than a + * (programmable) threshold */ struct ath_interrupt_stats { u32 total; @@ -78,6 +81,7 @@ struct ath_interrupt_stats { u32 dtimsync; u32 dtim; u32 bb_watchdog; + u32 tsfoor; }; /** diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index 1357975..b87db47 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -319,10 +319,9 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, u16 numXpdGain, xpdMask; u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0}; u32 reg32, regOffset, regChainOffset, regval; - int16_t modalIdx, diff = 0; + int16_t diff = 0; struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; xpdMask = pEepData->modalHeader.xpdGain; if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >= diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index 995949d..c031854 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -231,6 +231,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) integer = swab32(pModal->antCtrlChain[i]); pModal->antCtrlChain[i] = integer; } + for (i = 0; i < 3; i++) { + word = swab16(pModal->xpaBiasLvlFreq[i]); + pModal->xpaBiasLvlFreq[i] = word; + } for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { word = swab16(pModal->spurChans[i].spurChan); diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 44a0a88..0349b3a 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -46,6 +46,8 @@ void ath_init_leds(struct ath_softc *sc) sc->sc_ah->led_pin = ATH_LED_PIN_9287; else if (AR_SREV_9485(sc->sc_ah)) sc->sc_ah->led_pin = ATH_LED_PIN_9485; + else if (AR_SREV_9300(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9300; else sc->sc_ah->led_pin = ATH_LED_PIN_DEF; } @@ -138,10 +140,10 @@ static void ath_detect_bt_priority(struct ath_softc *sc) static void ath9k_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 timer_next, + u32 trig_timeout, u32 timer_period) { - ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period); + ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period); if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_disable_interrupts(ah); @@ -174,17 +176,17 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; - struct ath_common *common = ath9k_hw_common(ah); u32 timer_period; bool is_btscan; + ath9k_ps_wakeup(sc); ath_detect_bt_priority(sc); is_btscan = sc->sc_flags & SC_OP_BT_SCAN; spin_lock_bh(&btcoex->btcoex_lock); - ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : + ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); @@ -195,11 +197,12 @@ static void ath_btcoex_period_timer(unsigned long data) timer_period = is_btscan ? btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp; - ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0, + ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, timer_period * 10); btcoex->hw_timer_enabled = true; } + ath9k_ps_restore(sc); mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); } @@ -219,14 +222,16 @@ static void ath_btcoex_no_stomp_timer(void *arg) ath_dbg(common, ATH_DBG_BTCOEX, "no stomp timer running\n"); + ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); + ath9k_ps_restore(sc); } int ath_init_btcoex_timer(struct ath_softc *sc) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index f59df48..2bdcdbc 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -17,6 +17,9 @@ #ifndef HTC_USB_H #define HTC_USB_H +#define MAJOR_VERSION_REQ 1 +#define MINOR_VERSION_REQ 2 + #define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB)) #define AR9271_FIRMWARE 0x501000 diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 48a8855..dfc7a98 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -66,8 +66,6 @@ enum htc_opmode { HTC_M_WDS = 2 }; -#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr) - #define ATH9K_HTC_AMPDU 1 #define ATH9K_HTC_NORMAL 2 #define ATH9K_HTC_BEACON 3 @@ -75,7 +73,6 @@ enum htc_opmode { #define ATH9K_HTC_TX_CTSONLY 0x1 #define ATH9K_HTC_TX_RTSCTS 0x2 -#define ATH9K_HTC_TX_USE_MIN_RATE 0x100 struct tx_frame_hdr { u8 data_type; @@ -106,15 +103,14 @@ struct tx_beacon_header { u16 rev; } __packed; +#define MAX_TX_AMPDU_SUBFRAMES_9271 17 +#define MAX_TX_AMPDU_SUBFRAMES_7010 22 + struct ath9k_htc_cap_target { - u32 flags; - u32 flags_ext; - u32 ampdu_limit; + __be32 ampdu_limit; u8 ampdu_subframes; + u8 enable_coex; u8 tx_chainmask; - u8 tx_chainmask_legacy; - u8 rtscts_ratecode; - u8 protmode; u8 pad; } __packed; @@ -175,6 +171,13 @@ struct ath9k_htc_target_rate { struct ath9k_htc_rate rates; }; +struct ath9k_htc_target_rate_mask { + u8 vif_index; + u8 band; + __be32 mask; + u16 pad; +} __packed; + struct ath9k_htc_target_int_stats { __be32 rx; __be32 rxorn; @@ -382,25 +385,6 @@ static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv, #define ATH_LED_PIN_9287 10 #define ATH_LED_PIN_9271 15 #define ATH_LED_PIN_7010 12 -#define ATH_LED_ON_DURATION_IDLE 350 /* in msecs */ -#define ATH_LED_OFF_DURATION_IDLE 250 /* in msecs */ - -enum ath_led_type { - ATH_LED_RADIO, - ATH_LED_ASSOC, - ATH_LED_TX, - ATH_LED_RX -}; - -struct ath_led { - struct ath9k_htc_priv *priv; - struct led_classdev led_cdev; - enum ath_led_type led_type; - struct delayed_work brightness_work; - char name[32]; - bool registered; - int brightness; -}; #define BSTUCK_THRESHOLD 10 @@ -434,14 +418,11 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv); #define OP_INVALID BIT(0) #define OP_SCANNING BIT(1) -#define OP_LED_ASSOCIATED BIT(2) -#define OP_LED_ON BIT(3) -#define OP_ENABLE_BEACON BIT(4) -#define OP_LED_DEINIT BIT(5) -#define OP_BT_PRIORITY_DETECTED BIT(6) -#define OP_BT_SCAN BIT(7) -#define OP_ANI_RUNNING BIT(8) -#define OP_TSF_RESET BIT(9) +#define OP_ENABLE_BEACON BIT(2) +#define OP_BT_PRIORITY_DETECTED BIT(3) +#define OP_BT_SCAN BIT(4) +#define OP_ANI_RUNNING BIT(5) +#define OP_TSF_RESET BIT(6) struct ath9k_htc_priv { struct device *dev; @@ -501,15 +482,13 @@ struct ath9k_htc_priv { bool ps_enabled; bool ps_idle; - struct ath_led radio_led; - struct ath_led assoc_led; - struct ath_led tx_led; - struct ath_led rx_led; - struct delayed_work ath9k_led_blink_work; - int led_on_duration; - int led_off_duration; - int led_on_cnt; - int led_off_cnt; +#ifdef CONFIG_MAC80211_LEDS + enum led_brightness brightness; + bool led_registered; + char led_name[32]; + struct led_classdev led_cdev; + struct work_struct led_work; +#endif int beaconq; int cabq; @@ -551,7 +530,8 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, enum htc_endpoint_id ep_id, bool txok); -int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv); +int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, + u8 enable_coex); void ath9k_htc_station_work(struct work_struct *work); void ath9k_htc_aggr_work(struct work_struct *work); void ath9k_htc_ani_work(struct work_struct *work); @@ -593,9 +573,24 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); void ath9k_htc_radio_enable(struct ieee80211_hw *hw); void ath9k_htc_radio_disable(struct ieee80211_hw *hw); -void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv); + +#ifdef CONFIG_MAC80211_LEDS void ath9k_init_leds(struct ath9k_htc_priv *priv); void ath9k_deinit_leds(struct ath9k_htc_priv *priv); +void ath9k_led_work(struct work_struct *work); +#else +static inline void ath9k_init_leds(struct ath9k_htc_priv *priv) +{ +} + +static inline void ath9k_deinit_leds(struct ath9k_htc_priv *priv) +{ +} + +static inline void ath9k_led_work(struct work_struct *work) +{ +} +#endif int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev, u16 devid, char *product, u32 drv_info); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index a157107..0ded2c6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -74,7 +74,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv, __be32 htc_imask = 0; u64 tsf; int num_beacons, offset, dtim_dec_count, cfp_dec_count; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; memset(&bs, 0, sizeof(bs)); @@ -190,7 +190,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, enum ath9k_int imask = 0; u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; u64 tsf; @@ -246,7 +246,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, enum ath9k_int imask = 0; u32 nexttbtt, intval, tsftu; __be32 htc_imask = 0; - int ret; + int ret __attribute__ ((unused)); u8 cmd_rsp; u64 tsf; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index eca7774..aa48b3ab 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -33,9 +33,15 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf, memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + ath9k_htc_ps_wakeup(priv); + WMI_CMD(WMI_INT_STATS_CMDID); - if (ret) + if (ret) { + ath9k_htc_ps_restore(priv); return -EINVAL; + } + + ath9k_htc_ps_restore(priv); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "RX", @@ -85,9 +91,15 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf, memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + ath9k_htc_ps_wakeup(priv); + WMI_CMD(WMI_TX_STATS_CMDID); - if (ret) + if (ret) { + ath9k_htc_ps_restore(priv); return -EINVAL; + } + + ath9k_htc_ps_restore(priv); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "Xretries", @@ -149,9 +161,15 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf, memset(&cmd_rsp, 0, sizeof(cmd_rsp)); + ath9k_htc_ps_wakeup(priv); + WMI_CMD(WMI_RX_STATS_CMDID); - if (ret) + if (ret) { + ath9k_htc_ps_restore(priv); return -EINVAL; + } + + ath9k_htc_ps_restore(priv); len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n", "NoBuf", @@ -474,6 +492,439 @@ static const struct file_operations fops_debug = { .llseek = default_llseek, }; +static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct base_eep_header *pBase = NULL; + unsigned int len = 0, size = 1500; + ssize_t retval = 0; + char *buf; + + /* + * This can be done since all the 3 EEPROM families have the + * same base header upto a certain point, and we are interested in + * the data only upto that point. + */ + + if (AR_SREV_9271(priv->ah)) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.map4k.baseEepHeader; + else if (priv->ah->hw_version.usbdev == AR9280_USB) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.def.baseEepHeader; + else if (priv->ah->hw_version.usbdev == AR9287_USB) + pBase = (struct base_eep_header *) + &priv->ah->eeprom.map9287.baseEepHeader; + + if (pBase == NULL) { + ath_err(common, "Unknown EEPROM type\n"); + return 0; + } + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Major Version", + pBase->version >> 12); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Minor Version", + pBase->version & 0xFFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Checksum", + pBase->checksum); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "Length", + pBase->length); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "RegDomain1", + pBase->regDmn[0]); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", "RegDomain2", + pBase->regDmn[1]); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "TX Mask", pBase->txMask); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "RX Mask", pBase->rxMask); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Allow 5GHz", + !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Allow 2GHz", + !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 2GHz HT20", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 2GHz HT40", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 5Ghz HT20", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Disable 5Ghz HT40", + !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Big Endian", + !!(pBase->eepMisc & 0x01)); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Major Ver", + (pBase->binBuildNumber >> 24) & 0xFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Minor Ver", + (pBase->binBuildNumber >> 16) & 0xFF); + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "Cal Bin Build", + (pBase->binBuildNumber >> 8) & 0xFF); + + /* + * UB91 specific data. + */ + if (AR_SREV_9271(priv->ah)) { + struct base_eep_header_4k *pBase4k = + &priv->ah->eeprom.map4k.baseEepHeader; + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "TX Gain type", + pBase4k->txGainType); + } + + /* + * UB95 specific data. + */ + if (priv->ah->hw_version.usbdev == AR9287_USB) { + struct base_eep_ar9287_header *pBase9287 = + &priv->ah->eeprom.map9287.baseEepHeader; + + len += snprintf(buf + len, size - len, + "%20s : %10ddB\n", + "Power Table Offset", + pBase9287->pwrTableOffset); + + len += snprintf(buf + len, size - len, + "%20s : %10d\n", + "OpenLoop Power Ctrl", + pBase9287->openLoopPwrCntl); + } + + len += snprintf(buf + len, size - len, + "%20s : %02X:%02X:%02X:%02X:%02X:%02X\n", + "MacAddress", + pBase->macAddr[0], pBase->macAddr[1], pBase->macAddr[2], + pBase->macAddr[3], pBase->macAddr[4], pBase->macAddr[5]); + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; +} + +static const struct file_operations fops_base_eeprom = { + .read = read_file_base_eeprom, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_4k_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, "%20s : %10d\n", \ + _s, (_val)); \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader; + unsigned int len = 0, size = 2048; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("PGA Desired size", pModal->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("O/D Bias Version", pModal->version); + PR_EEP("CCK OutputBias", pModal->ob_0); + PR_EEP("BPSK OutputBias", pModal->ob_1); + PR_EEP("QPSK OutputBias", pModal->ob_2); + PR_EEP("16QAM OutputBias", pModal->ob_3); + PR_EEP("64QAM OutputBias", pModal->ob_4); + PR_EEP("CCK Driver1_Bias", pModal->db1_0); + PR_EEP("BPSK Driver1_Bias", pModal->db1_1); + PR_EEP("QPSK Driver1_Bias", pModal->db1_2); + PR_EEP("16QAM Driver1_Bias", pModal->db1_3); + PR_EEP("64QAM Driver1_Bias", pModal->db1_4); + PR_EEP("CCK Driver2_Bias", pModal->db2_0); + PR_EEP("BPSK Driver2_Bias", pModal->db2_1); + PR_EEP("QPSK Driver2_Bias", pModal->db2_2); + PR_EEP("16QAM Driver2_Bias", pModal->db2_3); + PR_EEP("64QAM Driver2_Bias", pModal->db2_4); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); + PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); + PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1); + PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2); + PR_EEP("TX Diversity", pModal->tx_diversity); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_def_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + if (pBase->opCapFlags & AR5416_OPFLAGS_11G) { \ + pModal = &priv->ah->eeprom.def.modalHeader[1]; \ + len += snprintf(buf + len, size - len, "%20s : %8d%7s", \ + _s, (_val), "|"); \ + } \ + if (pBase->opCapFlags & AR5416_OPFLAGS_11A) { \ + pModal = &priv->ah->eeprom.def.modalHeader[0]; \ + len += snprintf(buf + len, size - len, "%9d\n", \ + (_val)); \ + } \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader; + struct modal_eep_header *pModal = NULL; + unsigned int len = 0, size = 3500; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + len += snprintf(buf + len, size - len, + "%31s %15s\n", "2G", "5G"); + len += snprintf(buf + len, size - len, + "%32s %16s\n", "====", "====\n"); + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); + PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); + PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); + PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); + PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("PGA Desired size", pModal->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]); + PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]); + PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); + PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); + PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); + PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("Chain0 OutputBias", pModal->ob); + PR_EEP("Chain0 DriverBias", pModal->db); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain); + PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); + PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); + PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]); + PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]); + PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]); + PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]); + PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]); + PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]); + PR_EEP("Chain1 OutputBias", pModal->ob_ch1); + PR_EEP("Chain1 DriverBias", pModal->db_ch1); + PR_EEP("LNA Control", pModal->lna_ctl); + PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]); + PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]); + PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_9287_modal_eeprom(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ +#define PR_EEP(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, "%20s : %10d\n", \ + _s, (_val)); \ + } while (0) + + struct ath9k_htc_priv *priv = file->private_data; + struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader; + unsigned int len = 0, size = 3000; + ssize_t retval = 0; + char *buf; + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]); + PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]); + PR_EEP("Ant. Common Control", pModal->antCtrlCommon); + PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]); + PR_EEP("Switch Settle", pModal->switchSettling); + PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]); + PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]); + PR_EEP("ADC Desired size", pModal->adcDesiredSize); + PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff); + PR_EEP("txEndToRxOn", pModal->txEndToRxOn); + PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn); + PR_EEP("CCA Threshold)", pModal->thresh62); + PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]); + PR_EEP("xpdGain", pModal->xpdGain); + PR_EEP("External PD", pModal->xpd); + PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]); + PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]); + PR_EEP("pdGainOverlap", pModal->pdGainOverlap); + PR_EEP("xPA Bias Level", pModal->xpaBiasLvl); + PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart); + PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]); + PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]); + PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]); + PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]); + PR_EEP("HT40 Switch Settle", pModal->swSettleHt40); + PR_EEP("AR92x7 Version", pModal->version); + PR_EEP("DriverBias1", pModal->db1); + PR_EEP("DriverBias2", pModal->db1); + PR_EEP("CCK OutputBias", pModal->ob_cck); + PR_EEP("PSK OutputBias", pModal->ob_psk); + PR_EEP("QAM OutputBias", pModal->ob_qam); + PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off); + + if (len > size) + len = size; + + retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return retval; + +#undef PR_EEP +} + +static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath9k_htc_priv *priv = file->private_data; + + if (AR_SREV_9271(priv->ah)) + return read_4k_modal_eeprom(file, user_buf, count, ppos); + else if (priv->ah->hw_version.usbdev == AR9280_USB) + return read_def_modal_eeprom(file, user_buf, count, ppos); + else if (priv->ah->hw_version.usbdev == AR9287_USB) + return read_9287_modal_eeprom(file, user_buf, count, ppos); + + return 0; +} + +static const struct file_operations fops_modal_eeprom = { + .read = read_file_modal_eeprom, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath9k_htc_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -485,21 +936,25 @@ int ath9k_htc_init_debug(struct ath_hw *ah) return -ENOMEM; debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_tgt_int_stats); + priv, &fops_tgt_int_stats); debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_tgt_tx_stats); + priv, &fops_tgt_tx_stats); debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_tgt_rx_stats); + priv, &fops_tgt_rx_stats); debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_xmit); + priv, &fops_xmit); debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_recv); + priv, &fops_recv); debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_slot); + priv, &fops_slot); debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, - priv, &fops_queue); + priv, &fops_queue); debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, - priv, &fops_debug); + priv, &fops_debug); + debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_base_eeprom); + debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy, + priv, &fops_modal_eeprom); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index dc0b33d..af57fe5 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -65,17 +65,19 @@ static void ath_btcoex_period_work(struct work_struct *work) u32 timer_period; bool is_btscan; int ret; - u8 cmd_rsp, aggr; ath_detect_bt_priority(priv); is_btscan = !!(priv->op_flags & OP_BT_SCAN); - aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED; - - WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr); + ret = ath9k_htc_update_cap_target(priv, + !!(priv->op_flags & OP_BT_PRIORITY_DETECTED)); + if (ret) { + ath_err(common, "Unable to set BTCOEX parameters\n"); + return; + } - ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL : + ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); timer_period = is_btscan ? btcoex->btscan_no_stomp : @@ -103,9 +105,9 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work) "time slice work for bt and wlan\n"); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) - ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW); + ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); } void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv) @@ -152,140 +154,41 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv) /* LED */ /*******/ -static void ath9k_led_blink_work(struct work_struct *work) +#ifdef CONFIG_MAC80211_LEDS +void ath9k_led_work(struct work_struct *work) { - struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv, - ath9k_led_blink_work.work); + struct ath9k_htc_priv *priv = container_of(work, + struct ath9k_htc_priv, + led_work); - if (!(priv->op_flags & OP_LED_ASSOCIATED)) - return; - - if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) || - (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE)) - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); - else - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, - (priv->op_flags & OP_LED_ON) ? 1 : 0); - - ieee80211_queue_delayed_work(priv->hw, - &priv->ath9k_led_blink_work, - (priv->op_flags & OP_LED_ON) ? - msecs_to_jiffies(priv->led_off_duration) : - msecs_to_jiffies(priv->led_on_duration)); - - priv->led_on_duration = priv->led_on_cnt ? - max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) : - ATH_LED_ON_DURATION_IDLE; - priv->led_off_duration = priv->led_off_cnt ? - max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) : - ATH_LED_OFF_DURATION_IDLE; - priv->led_on_cnt = priv->led_off_cnt = 0; - - if (priv->op_flags & OP_LED_ON) - priv->op_flags &= ~OP_LED_ON; - else - priv->op_flags |= OP_LED_ON; -} - -static void ath9k_led_brightness_work(struct work_struct *work) -{ - struct ath_led *led = container_of(work, struct ath_led, - brightness_work.work); - struct ath9k_htc_priv *priv = led->priv; - - switch (led->brightness) { - case LED_OFF: - if (led->led_type == ATH_LED_ASSOC || - led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, - (led->led_type == ATH_LED_RADIO)); - priv->op_flags &= ~OP_LED_ASSOCIATED; - if (led->led_type == ATH_LED_RADIO) - priv->op_flags &= ~OP_LED_ON; - } else { - priv->led_off_cnt++; - } - break; - case LED_FULL: - if (led->led_type == ATH_LED_ASSOC) { - priv->op_flags |= OP_LED_ASSOCIATED; - ieee80211_queue_delayed_work(priv->hw, - &priv->ath9k_led_blink_work, 0); - } else if (led->led_type == ATH_LED_RADIO) { - ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0); - priv->op_flags |= OP_LED_ON; - } else { - priv->led_on_cnt++; - } - break; - default: - break; - } + ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, + (priv->brightness == LED_OFF)); } static void ath9k_led_brightness(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev); - struct ath9k_htc_priv *priv = led->priv; + struct ath9k_htc_priv *priv = container_of(led_cdev, + struct ath9k_htc_priv, + led_cdev); - led->brightness = brightness; - if (!(priv->op_flags & OP_LED_DEINIT)) - ieee80211_queue_delayed_work(priv->hw, - &led->brightness_work, 0); -} - -void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv) -{ - cancel_delayed_work_sync(&priv->radio_led.brightness_work); - cancel_delayed_work_sync(&priv->assoc_led.brightness_work); - cancel_delayed_work_sync(&priv->tx_led.brightness_work); - cancel_delayed_work_sync(&priv->rx_led.brightness_work); -} - -static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led, - char *trigger) -{ - int ret; - - led->priv = priv; - led->led_cdev.name = led->name; - led->led_cdev.default_trigger = trigger; - led->led_cdev.brightness_set = ath9k_led_brightness; - - ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev); - if (ret) - ath_err(ath9k_hw_common(priv->ah), - "Failed to register led:%s", led->name); - else - led->registered = 1; - - INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work); - - return ret; -} - -static void ath9k_unregister_led(struct ath_led *led) -{ - if (led->registered) { - led_classdev_unregister(&led->led_cdev); - led->registered = 0; - } + /* Not locked, but it's just a tiny green light..*/ + priv->brightness = brightness; + ieee80211_queue_work(priv->hw, &priv->led_work); } void ath9k_deinit_leds(struct ath9k_htc_priv *priv) { - priv->op_flags |= OP_LED_DEINIT; - ath9k_unregister_led(&priv->assoc_led); - priv->op_flags &= ~OP_LED_ASSOCIATED; - ath9k_unregister_led(&priv->tx_led); - ath9k_unregister_led(&priv->rx_led); - ath9k_unregister_led(&priv->radio_led); + if (!priv->led_registered) + return; + + ath9k_led_brightness(&priv->led_cdev, LED_OFF); + led_classdev_unregister(&priv->led_cdev); + cancel_work_sync(&priv->led_work); } void ath9k_init_leds(struct ath9k_htc_priv *priv) { - char *trigger; int ret; if (AR_SREV_9287(priv->ah)) @@ -303,48 +206,21 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) /* LED off, active low */ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1); - INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work); - - trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(priv->radio_led.name, sizeof(priv->radio_led.name), - "ath9k-%s::radio", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->radio_led, trigger); - priv->radio_led.led_type = ATH_LED_RADIO; - if (ret) - goto fail; - - trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name), - "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->assoc_led, trigger); - priv->assoc_led.led_type = ATH_LED_ASSOC; - if (ret) - goto fail; - - trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(priv->tx_led.name, sizeof(priv->tx_led.name), - "ath9k-%s::tx", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->tx_led, trigger); - priv->tx_led.led_type = ATH_LED_TX; - if (ret) - goto fail; - - trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(priv->rx_led.name, sizeof(priv->rx_led.name), - "ath9k-%s::rx", wiphy_name(priv->hw->wiphy)); - ret = ath9k_register_led(priv, &priv->rx_led, trigger); - priv->rx_led.led_type = ATH_LED_RX; - if (ret) - goto fail; - - priv->op_flags &= ~OP_LED_DEINIT; + snprintf(priv->led_name, sizeof(priv->led_name), + "ath9k_htc-%s", wiphy_name(priv->hw->wiphy)); + priv->led_cdev.name = priv->led_name; + priv->led_cdev.brightness_set = ath9k_led_brightness; - return; + ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev); + if (ret < 0) + return; -fail: - cancel_delayed_work_sync(&priv->ath9k_led_blink_work); - ath9k_deinit_leds(priv); + INIT_WORK(&priv->led_work, ath9k_led_work); + priv->led_registered = true; + + return; } +#endif /*******************/ /* Rfkill */ diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 06e043b..bfdc8a8 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -117,6 +117,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = { RATE(540, 0x0c, 0), }; +#ifdef CONFIG_MAC80211_LEDS +static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = { + { .throughput = 0 * 1024, .blink_time = 334 }, + { .throughput = 1 * 1024, .blink_time = 260 }, + { .throughput = 5 * 1024, .blink_time = 220 }, + { .throughput = 10 * 1024, .blink_time = 190 }, + { .throughput = 20 * 1024, .blink_time = 170 }, + { .throughput = 50 * 1024, .blink_time = 150 }, + { .throughput = 70 * 1024, .blink_time = 130 }, + { .throughput = 100 * 1024, .blink_time = 110 }, + { .throughput = 200 * 1024, .blink_time = 80 }, + { .throughput = 300 * 1024, .blink_time = 50 }, +}; +#endif + static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv) { int time_left; @@ -243,7 +258,7 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid, */ if (IS_AR7010_DEVICE(drv_info)) - priv->htc->credits = 45; + priv->htc->credits = 48; else priv->htc->credits = 33; @@ -753,6 +768,12 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->queues = 4; hw->channel_change_time = 5000; hw->max_listen_interval = 10; + + if (AR_SREV_9271(priv->ah)) + hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_9271; + else + hw->max_tx_aggregation_subframes = MAX_TX_AMPDU_SUBFRAMES_7010; + hw->vif_data_size = sizeof(struct ath9k_htc_vif); hw->sta_data_size = sizeof(struct ath9k_htc_sta); @@ -802,6 +823,17 @@ static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv) priv->fw_version_major, priv->fw_version_minor); + /* + * Check if the available FW matches the driver's + * required version. + */ + if (priv->fw_version_major != MAJOR_VERSION_REQ || + priv->fw_version_minor != MINOR_VERSION_REQ) { + dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n", + MAJOR_VERSION_REQ, MINOR_VERSION_REQ); + return -EINVAL; + } + return 0; } @@ -846,6 +878,13 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv, if (error != 0) goto err_rx; +#ifdef CONFIG_MAC80211_LEDS + /* must be initialized before ieee80211_register_hw */ + priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw, + IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink, + ARRAY_SIZE(ath9k_htc_tpt_blink)); +#endif + /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 4de3864..5aa104fe 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -332,6 +332,11 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv) memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN); hvif.index = priv->mon_vif_idx; WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + if (ret) { + ath_err(common, "Unable to remove monitor interface at idx: %d\n", + priv->mon_vif_idx); + } + priv->nvifs--; priv->vif_slot &= ~(1 << priv->mon_vif_idx); } @@ -462,6 +467,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, struct ath9k_htc_sta *ista; int ret, sta_idx; u8 cmd_rsp; + u16 maxampdu; if (priv->nstations >= ATH9K_HTC_MAX_STA) return -ENOBUFS; @@ -485,7 +491,15 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv, tsta.sta_index = sta_idx; tsta.vif_index = avp->index; - tsta.maxampdu = cpu_to_be16(0xffff); + + if (!sta) { + tsta.maxampdu = cpu_to_be16(0xffff); + } else { + maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + tsta.maxampdu = cpu_to_be16(maxampdu); + } + if (sta && sta->ht_cap.ht_supported) tsta.flags = cpu_to_be16(ATH_HTC_STA_HT); @@ -558,7 +572,8 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv, return 0; } -int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) +int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, + u8 enable_coex) { struct ath9k_htc_cap_target tcap; int ret; @@ -566,13 +581,9 @@ int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv) memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target)); - /* FIXME: Values are hardcoded */ - tcap.flags = 0x240c40; - tcap.flags_ext = 0x80601000; - tcap.ampdu_limit = 0xffff0000; - tcap.ampdu_subframes = 20; - tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask; - tcap.protmode = 1; + tcap.ampdu_limit = cpu_to_be32(0xffff); + tcap.ampdu_subframes = priv->hw->max_tx_aggregation_subframes; + tcap.enable_coex = enable_coex; tcap.tx_chainmask = priv->ah->caps.tx_chainmask; WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap); @@ -931,7 +942,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath9k_host_rx_init(priv); - ret = ath9k_htc_update_cap_target(priv); + ret = ath9k_htc_update_cap_target(priv, 0); if (ret) ath_dbg(common, ATH_DBG_CONFIG, "Failed to update capability in target\n"); @@ -964,7 +975,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) struct ath9k_htc_priv *priv = hw->priv; struct ath_hw *ah = priv->ah; struct ath_common *common = ath9k_hw_common(ah); - int ret = 0; + int ret __attribute__ ((unused)); u8 cmd_rsp; mutex_lock(&priv->mutex); @@ -992,9 +1003,11 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) /* Cancel all the running timers/work .. */ cancel_work_sync(&priv->fatal_work); cancel_work_sync(&priv->ps_work); - cancel_delayed_work_sync(&priv->ath9k_led_blink_work); + +#ifdef CONFIG_MAC80211_LEDS + cancel_work_sync(&priv->led_work); +#endif ath9k_htc_stop_ani(priv); - ath9k_led_stop_brightness(priv); mutex_lock(&priv->mutex); @@ -1135,6 +1148,10 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, memcpy(&hvif.myaddr, vif->addr, ETH_ALEN); hvif.index = avp->index; WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif); + if (ret) { + ath_err(common, "Unable to remove interface at idx: %d\n", + avp->index); + } priv->nvifs--; priv->vif_slot &= ~(1 << avp->index); @@ -1567,6 +1584,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, int ret = 0; mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); switch (action) { case IEEE80211_AMPDU_RX_START: @@ -1592,6 +1610,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw, ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n"); } + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); return ret; @@ -1642,6 +1661,55 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } +/* + * Currently, this is used only for selecting the minimum rate + * for management frames, rate selection for data frames remain + * unaffected. + */ +static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_common *common = ath9k_hw_common(priv->ah); + struct ath9k_htc_target_rate_mask tmask; + struct ath9k_htc_vif *avp = (void *)vif->drv_priv; + int ret = 0; + u8 cmd_rsp; + + memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask)); + + tmask.vif_index = avp->index; + tmask.band = IEEE80211_BAND_2GHZ; + tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy); + + WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); + if (ret) { + ath_err(common, + "Unable to set 2G rate mask for " + "interface at idx: %d\n", avp->index); + goto out; + } + + tmask.band = IEEE80211_BAND_5GHZ; + tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy); + + WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask); + if (ret) { + ath_err(common, + "Unable to set 5G rate mask for " + "interface at idx: %d\n", avp->index); + goto out; + } + + ath_dbg(common, ATH_DBG_CONFIG, + "Set bitrate masks: 0x%x, 0x%x\n", + mask->control[IEEE80211_BAND_2GHZ].legacy, + mask->control[IEEE80211_BAND_5GHZ].legacy); +out: + return ret; +} + struct ieee80211_ops ath9k_htc_ops = { .tx = ath9k_htc_tx, .start = ath9k_htc_start, @@ -1664,4 +1732,5 @@ struct ieee80211_ops ath9k_htc_ops = { .set_rts_threshold = ath9k_htc_set_rts_threshold, .rfkill_poll = ath9k_htc_rfkill_poll_state, .set_coverage_class = ath9k_htc_set_coverage_class, + .set_bitrate_mask = ath9k_htc_set_bitrate_mask, }; diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 723a3a9..a898dac 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -446,7 +446,6 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, struct ieee80211_tx_info *tx_info; struct ieee80211_tx_rate *rate; struct ieee80211_conf *cur_conf = &priv->hw->conf; - struct ieee80211_supported_band *sband; bool txok; int slot; @@ -461,7 +460,6 @@ static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, tx_info = IEEE80211_SKB_CB(skb); vif = tx_info->control.vif; rate = &tx_info->status.rates[0]; - sband = priv->hw->wiphy->bands[cur_conf->channel->band]; memset(&tx_info->status, 0, sizeof(tx_info->status)); diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index cb9174a..91a5305 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h @@ -83,21 +83,10 @@ struct htc_ep_callbacks { void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id); }; -#define HTC_TX_QUEUE_SIZE 256 - -struct htc_txq { - struct sk_buff *buf[HTC_TX_QUEUE_SIZE]; - u32 txqdepth; - u16 txbuf_cnt; - u16 txq_head; - u16 txq_tail; -}; - struct htc_endpoint { u16 service_id; struct htc_ep_callbacks ep_callbacks; - struct htc_txq htc_txq; u32 max_txqdepth; int max_msglen; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 045abd5..58f3d42 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -247,6 +247,17 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) { u32 val; + switch (ah->hw_version.devid) { + case AR5416_AR9100_DEVID: + ah->hw_version.macVersion = AR_SREV_VERSION_9100; + break; + case AR9300_DEVID_AR9340: + ah->hw_version.macVersion = AR_SREV_VERSION_9340; + val = REG_READ(ah, AR_SREV); + ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); + return; + } + val = REG_READ(ah, AR_SREV) & AR_SREV_ID; if (val == 0xFF) { @@ -462,7 +473,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah) return ecode; } - if (!AR_SREV_9100(ah)) { + if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) { ath9k_hw_ani_setup(ah); ath9k_hw_ani_init(ah); } @@ -484,9 +495,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); int r = 0; - if (ah->hw_version.devid == AR5416_AR9100_DEVID) - ah->hw_version.macVersion = AR_SREV_VERSION_9100; - ath9k_hw_read_revisions(ah); /* @@ -544,6 +552,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) case AR_SREV_VERSION_9271: case AR_SREV_VERSION_9300: case AR_SREV_VERSION_9485: + case AR_SREV_VERSION_9340: break; default: ath_err(common, @@ -552,7 +561,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EOPNOTSUPP; } - if (AR_SREV_9271(ah) || AR_SREV_9100(ah)) + if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah)) ah->is_pciexpress = false; ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); @@ -621,6 +630,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR2427_DEVID_PCIE: case AR9300_DEVID_PCIE: case AR9300_DEVID_AR9485_PCIE: + case AR9300_DEVID_AR9340: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) @@ -663,7 +673,7 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) REGWRITE_BUFFER_FLUSH(ah); } -unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) +u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) { REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); udelay(100); @@ -676,7 +686,6 @@ unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); -#define DPLL3_PHASE_SHIFT_VAL 0x1 static void ath9k_hw_init_pll(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -713,16 +722,48 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2, AR_CH0_BB_DPLL2_PLL_PWD, 0x0); udelay(1000); + } else if (AR_SREV_9340(ah)) { + u32 regval, pll2_divint, pll2_divfrac, refdiv; - REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, - AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); + REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); + udelay(1000); + + REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16); + udelay(100); + + if (ah->is_clk_25mhz) { + pll2_divint = 0x54; + pll2_divfrac = 0x1eb85; + refdiv = 3; + } else { + pll2_divint = 88; + pll2_divfrac = 0; + refdiv = 5; + } + + regval = REG_READ(ah, AR_PHY_PLL_MODE); + regval |= (0x1 << 16); + REG_WRITE(ah, AR_PHY_PLL_MODE, regval); + udelay(100); + + REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) | + (pll2_divint << 18) | pll2_divfrac); + udelay(100); + + regval = REG_READ(ah, AR_PHY_PLL_MODE); + regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | + (0x4 << 26) | (0x18 << 19); + REG_WRITE(ah, AR_PHY_PLL_MODE, regval); + REG_WRITE(ah, AR_PHY_PLL_MODE, + REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + udelay(1000); } pll = ath9k_hw_compute_pll_control(ah, chan); REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) udelay(1000); /* Switch the core clock for ar9271 to 117Mhz */ @@ -734,17 +775,34 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(RTC_PLL_SETTLE_DELAY); REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); + + if (AR_SREV_9340(ah)) { + if (ah->is_clk_25mhz) { + REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); + } else { + REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1); + REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); + REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); + } + udelay(100); + } } static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, enum nl80211_iftype opmode) { + u32 sync_default = AR_INTR_SYNC_DEFAULT; u32 imr_reg = AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; + if (AR_SREV_9340(ah)) + sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; + if (AR_SREV_9300_20_OR_LATER(ah)) { imr_reg |= AR_IMR_RXOK_HP; if (ah->config.rx_intr_mitigation) @@ -775,7 +833,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); } @@ -1487,7 +1545,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); } #ifdef __BIG_ENDIAN - else + else if (AR_SREV_9340(ah)) + REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); + else REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); #endif } @@ -1793,7 +1853,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) struct ath_common *common = ath9k_hw_common(ah); struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; - u16 capField = 0, eeval; + u16 eeval; u8 ant_div_ctl1, tx_chainmask, rx_chainmask; eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); @@ -1804,8 +1864,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) eeval |= AR9285_RDEXT_DEFAULT; regulatory->current_rd_ext = eeval; - capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); - if (ah->opmode != NL80211_IFTYPE_AP && ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { if (regulatory->current_rd == 0x64 || @@ -1898,15 +1956,23 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) else pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) { - btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO; - btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO; - - if (AR_SREV_9285(ah)) { + if (common->btcoex_enabled) { + if (AR_SREV_9300_20_OR_LATER(ah)) { btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; - btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO; - } else { - btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300; + btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300; + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280; + btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280; + + if (AR_SREV_9285(ah)) { + btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE; + btcoex_hw->btpriority_gpio = + ATH_BTPRIORITY_GPIO_9285; + } else { + btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE; + } } } else { btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE; @@ -2359,11 +2425,11 @@ EXPORT_SYMBOL(ath_gen_timer_alloc); void ath9k_hw_gen_timer_start(struct ath_hw *ah, struct ath_gen_timer *timer, - u32 timer_next, + u32 trig_timeout, u32 timer_period) { struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers; - u32 tsf; + u32 tsf, timer_next; BUG_ON(!timer_period); @@ -2371,18 +2437,13 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, tsf = ath9k_hw_gettsf32(ah); + timer_next = tsf + trig_timeout; + ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER, "current tsf %x period %x timer_next %x\n", tsf, timer_period, timer_next); /* - * Pull timer_next forward if the current TSF already passed it - * because of software latency - */ - if (timer_next < tsf) - timer_next = tsf + timer_period; - - /* * Program generic timer registers */ REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr, diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 1018d6c..34ed1bd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -43,6 +43,7 @@ #define AR9287_DEVID_PCI 0x002d #define AR9287_DEVID_PCIE 0x002e #define AR9300_DEVID_PCIE 0x0030 +#define AR9300_DEVID_AR9340 0x0031 #define AR9300_DEVID_AR9485_PCIE 0x0032 #define AR5416_AR9100_DEVID 0x000b @@ -55,6 +56,9 @@ #define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa #define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab +#define AR9300_NUM_BT_WEIGHTS 4 +#define AR9300_NUM_WLAN_WEIGHTS 4 + #define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1) #define ATH_DEFAULT_NOISE_FLOOR -95 @@ -121,7 +125,7 @@ #define AR_GPIO_BIT(_gpio) (1 << (_gpio)) #define BASE_ACTIVATE_DELAY 100 -#define RTC_PLL_SETTLE_DELAY 100 +#define RTC_PLL_SETTLE_DELAY (AR_SREV_9340(ah) ? 1000 : 100) #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 @@ -771,6 +775,8 @@ struct ath_hw { /* Bluetooth coexistance */ struct ath_btcoex_hw btcoex_hw; + u32 bt_coex_bt_weight[AR9300_NUM_BT_WEIGHTS]; + u32 bt_coex_wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; u32 intr_txqs; u8 txchainmask; @@ -799,6 +805,7 @@ struct ath_hw { struct ar5416IniArray iniPcieSerdes; struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniModesAdditional; + struct ar5416IniArray iniModesAdditional_40M; struct ar5416IniArray iniModesRxGain; struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniModes_9271_1_0_only; @@ -845,6 +852,8 @@ struct ath_hw { /* Enterprise mode cap */ u32 ent_mode; + + bool is_clk_25mhz; }; struct ath_bus_ops { @@ -928,7 +937,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); void ath9k_hw_init_global_settings(struct ath_hw *ah); -unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); +u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); void ath9k_hw_set11nmac2040(struct ath_hw *ah); void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 1ac8318..b172d15 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -574,6 +574,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, sc->sc_ah->gpio_mask = pdata->gpio_mask; sc->sc_ah->gpio_val = pdata->gpio_val; sc->sc_ah->led_pin = pdata->led_pin; + ah->is_clk_25mhz = pdata->is_clk_25mhz; } common = ath9k_hw_common(ah); @@ -800,6 +801,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); + INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); sc->last_rssi = ATH_RSSI_DUMMY_MARKER; ath_init_leds(sc); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 1968c67..9cf7a7d 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -812,10 +812,14 @@ EXPORT_SYMBOL(ath9k_hw_disable_interrupts); void ath9k_hw_enable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); + u32 sync_default = AR_INTR_SYNC_DEFAULT; if (!(ah->imask & ATH9K_INT_GLOBAL)) return; + if (AR_SREV_9340(ah)) + sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; + ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { @@ -824,10 +828,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, - AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, - AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default); + REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default); } ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n", REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); @@ -883,6 +885,9 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) mask |= AR_IMR_GENTMR; } + if (ints & ATH9K_INT_GENTIMER) + mask |= AR_IMR_GENTMR; + if (ints & (ATH9K_INT_BMISC)) { mask |= AR_IMR_BCNMISC; if (ints & ATH9K_INT_TIM) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index a8d9009..c3dbf26 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -624,6 +624,43 @@ out: ath9k_ps_restore(sc); } +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) +{ + static int count; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (pll_sqsum >= 0x40000) { + count++; + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_dbg(common, ATH_DBG_RESET, + "Possible RX hang, resetting"); + ath_reset(sc, true); + count = 0; + } + } else + count = 0; +} + +void ath_hw_pll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_pll_work.work); + u32 pll_sqsum; + + if (AR_SREV_9485(sc->sc_ah)) { + + ath9k_ps_wakeup(sc); + pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); + ath9k_ps_restore(sc); + + ath_hw_pll_rx_hang_check(sc, pll_sqsum); + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); + } +} + + void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -1932,6 +1969,12 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) "Bss Info ASSOC %d, bssid: %pM\n", bss_conf->aid, common->curbssid); ath_beacon_config(sc, vif); + /* + * Request a re-configuration of Beacon related timers + * on the receipt of the first Beacon frame (i.e., + * after time sync with the AP). + */ + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; /* Reset rssi stats */ sc->last_rssi = ATH_RSSI_DUMMY_MARKER; sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; @@ -2219,9 +2262,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) int timeout = 200; /* ms */ int i, j; - ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); - cancel_delayed_work_sync(&sc->tx_complete_work); if (drop) @@ -2244,15 +2285,15 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) goto out; } + ath9k_ps_wakeup(sc); if (!ath_drain_all_txq(sc, false)) ath_reset(sc, false); - + ath9k_ps_restore(sc); ieee80211_wake_queues(hw); out: ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); mutex_unlock(&sc->mutex); - ath9k_ps_restore(sc); } static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h index 8e5fe9d..9441bf8 100644 --- a/drivers/net/wireless/ath/ath9k/phy.h +++ b/drivers/net/wireless/ath/ath9k/phy.h @@ -45,4 +45,7 @@ #define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000 #define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20 +#define AR_PHY_PLL_CONTROL 0x16180 +#define AR_PHY_PLL_MODE 0x16184 + #endif diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 1809409..4ccbf2d 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -854,14 +854,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, ath_rc_rate_set_rtscts(sc, rate_table, tx_info); } -static bool ath_rc_update_per(struct ath_softc *sc, +static void ath_rc_update_per(struct ath_softc *sc, const struct ath_rate_table *rate_table, struct ath_rate_priv *ath_rc_priv, struct ieee80211_tx_info *tx_info, int tx_rate, int xretries, int retries, u32 now_msec) { - bool state_change = false; int count, n_bad_frames; u8 last_per; static const u32 nretry_to_per_lookup[10] = { @@ -992,8 +991,6 @@ static bool ath_rc_update_per(struct ath_softc *sc, } } - - return state_change; } static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix, @@ -1017,7 +1014,6 @@ static void ath_rc_update_ht(struct ath_softc *sc, u32 now_msec = jiffies_to_msecs(jiffies); int rate; u8 last_per; - bool state_change = false; const struct ath_rate_table *rate_table = ath_rc_priv->rate_table; int size = ath_rc_priv->rate_table_size; @@ -1027,9 +1023,9 @@ static void ath_rc_update_ht(struct ath_softc *sc, last_per = ath_rc_priv->per[tx_rate]; /* Update PER first */ - state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, - tx_info, tx_rate, xretries, - retries, now_msec); + ath_rc_update_per(sc, rate_table, ath_rc_priv, + tx_info, tx_rate, xretries, + retries, now_msec); /* * If this rate looks bad (high PER) then stop using it for diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index f69dcdf..c5b7cbe 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -1339,7 +1339,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) struct ath_hw_antcomb_conf div_ant_conf; struct ath_ant_comb *antcomb = &sc->ant_comb; int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set; - int curr_main_set, curr_bias; + int curr_main_set; int main_rssi = rs->rs_rssi_ctl0; int alt_rssi = rs->rs_rssi_ctl1; int rx_ant_conf, main_ant_conf; @@ -1393,7 +1393,6 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs) ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf); curr_alt_set = div_ant_conf.alt_lna_conf; curr_main_set = div_ant_conf.main_lna_conf; - curr_bias = div_ant_conf.fast_div_bias; antcomb->count++; @@ -1743,7 +1742,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA)) || - unlikely(ath9k_check_auto_sleep(sc))) + ath9k_check_auto_sleep(sc)) ath_rx_ps(sc, skb); spin_unlock_irqrestore(&sc->sc_pm_lock, flags); diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 6acbf0e..456f3ec 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -693,7 +693,7 @@ #define AR_RC_APB 0x00000002 #define AR_RC_HOSTIF 0x00000100 -#define AR_WA 0x4004 +#define AR_WA (AR_SREV_9340(ah) ? 0x40c4 : 0x4004) #define AR_WA_BIT6 (1 << 6) #define AR_WA_BIT7 (1 << 7) #define AR_WA_BIT23 (1 << 23) @@ -712,7 +712,7 @@ #define AR_PM_STATE 0x4008 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 -#define AR_HOST_TIMEOUT 0x4018 +#define AR_HOST_TIMEOUT (AR_SREV_9340(ah) ? 0x4008 : 0x4018) #define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF #define AR_HOST_TIMEOUT_APB_CNTR_S 0 #define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000 @@ -742,7 +742,8 @@ #define EEPROM_PROTECT_WP_1024_2047 0x8000 #define AR_SREV \ - ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020) + ((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \ + ? 0x400c : 0x4020)) #define AR_SREV_ID \ ((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF) @@ -790,6 +791,7 @@ #define AR_SREV_VERSION_9485 0x240 #define AR_SREV_REVISION_9485_10 0 #define AR_SREV_REVISION_9485_11 1 +#define AR_SREV_VERSION_9340 0x300 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -868,6 +870,11 @@ #define AR_SREV_9485_11(_ah) \ (AR_SREV_9485(_ah) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11)) +#define AR_SREV_9485_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485)) + +#define AR_SREV_9340(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340)) #define AR_SREV_9285E_20(_ah) \ (AR_SREV_9285_12_OR_LATER(_ah) && \ @@ -910,11 +917,11 @@ enum ath_usb_dev { #define AR_INTR_SPURIOUS 0xFFFFFFFF -#define AR_INTR_SYNC_CAUSE_CLR 0x4028 +#define AR_INTR_SYNC_CAUSE (AR_SREV_9340(ah) ? 0x4010 : 0x4028) +#define AR_INTR_SYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4010 : 0x4028) -#define AR_INTR_SYNC_CAUSE 0x4028 -#define AR_INTR_SYNC_ENABLE 0x402c +#define AR_INTR_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4014 : 0x402c) #define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_SYNC_ENABLE_GPIO_S 18 @@ -954,24 +961,24 @@ enum { }; -#define AR_INTR_ASYNC_MASK 0x4030 +#define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030) #define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_MASK_GPIO_S 18 -#define AR_INTR_SYNC_MASK 0x4034 +#define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034) #define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000 #define AR_INTR_SYNC_MASK_GPIO_S 18 -#define AR_INTR_ASYNC_CAUSE_CLR 0x4038 -#define AR_INTR_ASYNC_CAUSE 0x4038 +#define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038) +#define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038) -#define AR_INTR_ASYNC_ENABLE 0x403c +#define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c) #define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000 #define AR_INTR_ASYNC_ENABLE_GPIO_S 18 #define AR_PCIE_SERDES 0x4040 #define AR_PCIE_SERDES2 0x4044 -#define AR_PCIE_PM_CTRL 0x4014 +#define AR_PCIE_PM_CTRL (AR_SREV_9340(ah) ? 0x4004 : 0x4014) #define AR_PCIE_PM_CTRL_ENA 0x00080000 #define AR_NUM_GPIO 14 @@ -982,7 +989,7 @@ enum { #define AR9300_NUM_GPIO 17 #define AR7010_NUM_GPIO 16 -#define AR_GPIO_IN_OUT 0x4048 +#define AR_GPIO_IN_OUT (AR_SREV_9340(ah) ? 0x4028 : 0x4048) #define AR_GPIO_IN_VAL 0x0FFFC000 #define AR_GPIO_IN_VAL_S 14 #define AR928X_GPIO_IN_VAL 0x000FFC00 @@ -996,11 +1003,12 @@ enum { #define AR7010_GPIO_IN_VAL 0x0000FFFF #define AR7010_GPIO_IN_VAL_S 0 -#define AR_GPIO_IN 0x404c +#define AR_GPIO_IN (AR_SREV_9340(ah) ? 0x402c : 0x404c) #define AR9300_GPIO_IN_VAL 0x0001FFFF #define AR9300_GPIO_IN_VAL_S 0 -#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c) +#define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)) #define AR_GPIO_OE_OUT_DRV 0x3 #define AR_GPIO_OE_OUT_DRV_NO 0x0 #define AR_GPIO_OE_OUT_DRV_LOW 0x1 @@ -1022,11 +1030,13 @@ enum { #define AR7010_GPIO_INT_MASK 0x52024 #define AR7010_GPIO_FUNCTION 0x52028 -#define AR_GPIO_INTR_POL (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050) +#define AR_GPIO_INTR_POL (AR_SREV_9340(ah) ? 0x4038 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050)) #define AR_GPIO_INTR_POL_VAL 0x0001FFFF #define AR_GPIO_INTR_POL_VAL_S 0 -#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054) +#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9340(ah) ? 0x403c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)) #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004 #define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2 #define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008 @@ -1044,13 +1054,15 @@ enum { #define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000 #define AR_GPIO_JTAG_DISABLE 0x00020000 -#define AR_GPIO_INPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058) +#define AR_GPIO_INPUT_MUX1 (AR_SREV_9340(ah) ? 0x4040 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)) #define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000 #define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00 #define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8 -#define AR_GPIO_INPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c) +#define AR_GPIO_INPUT_MUX2 (AR_SREV_9340(ah) ? 0x4044 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)) #define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f #define AR_GPIO_INPUT_MUX2_CLK25_S 0 #define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0 @@ -1058,13 +1070,18 @@ enum { #define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00 #define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8 -#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060) -#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064) -#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068) +#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9340(ah) ? 0x4048 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)) +#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9340(ah) ? 0x404c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)) +#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9340(ah) ? 0x4050 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)) -#define AR_INPUT_STATE (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c) +#define AR_INPUT_STATE (AR_SREV_9340(ah) ? 0x4054 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)) -#define AR_EEPROM_STATUS_DATA (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c) +#define AR_EEPROM_STATUS_DATA (AR_SREV_9340(ah) ? 0x40c8 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)) #define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff #define AR_EEPROM_STATUS_DATA_VAL_S 0 #define AR_EEPROM_STATUS_DATA_BUSY 0x00010000 @@ -1072,17 +1089,19 @@ enum { #define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000 #define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000 -#define AR_OBS (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080) +#define AR_OBS (AR_SREV_9340(ah) ? 0x405c : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)) #define AR_GPIO_PDPU (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088) -#define AR_PCIE_MSI (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094) +#define AR_PCIE_MSI (AR_SREV_9340(ah) ? 0x40d8 : \ + (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)) #define AR_PCIE_MSI_ENABLE 0x00000001 -#define AR_INTR_PRIO_SYNC_ENABLE 0x40c4 -#define AR_INTR_PRIO_ASYNC_MASK 0x40c8 -#define AR_INTR_PRIO_SYNC_MASK 0x40cc -#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4 +#define AR_INTR_PRIO_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4088 : 0x40c4) +#define AR_INTR_PRIO_ASYNC_MASK (AR_SREV_9340(ah) ? 0x408c : 0x40c8) +#define AR_INTR_PRIO_SYNC_MASK (AR_SREV_9340(ah) ? 0x4090 : 0x40cc) +#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 #define AR_ENT_OTP_MPSD 0x00800000 @@ -1163,6 +1182,7 @@ enum { #define AR_RTC_PLL_REFDIV_5 0x000000c0 #define AR_RTC_PLL_CLKSEL 0x00000300 #define AR_RTC_PLL_CLKSEL_S 8 +#define AR_RTC_PLL_BYPASS 0x00010000 #define PLL3 0x16188 #define PLL3_DO_MEAS_MASK 0x40000000 @@ -1209,7 +1229,8 @@ enum { /* RTC_DERIVED_* - only for AR9100 */ -#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) +#define AR_RTC_DERIVED_CLK \ + (AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038) #define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe #define AR_RTC_DERIVED_CLK_PERIOD_S 1 @@ -1688,6 +1709,22 @@ enum { #define AR_BTCOEX_WL_WGHT 0xffff0000 #define AR_BTCOEX_WL_WGHT_S 16 +#define AR_BT_COEX_WL_WEIGHTS0 0x8174 +#define AR_BT_COEX_WL_WEIGHTS1 0x81c4 + +#define AR_BT_COEX_BT_WEIGHTS0 0x83ac +#define AR_BT_COEX_BT_WEIGHTS1 0x83b0 +#define AR_BT_COEX_BT_WEIGHTS2 0x83b4 +#define AR_BT_COEX_BT_WEIGHTS3 0x83b8 + +#define AR9300_BT_WGHT 0xcccc4444 +#define AR9300_STOMP_ALL_WLAN_WGHT0 0xfffffff0 +#define AR9300_STOMP_ALL_WLAN_WGHT1 0xfffffff0 +#define AR9300_STOMP_LOW_WLAN_WGHT0 0x88888880 +#define AR9300_STOMP_LOW_WLAN_WGHT1 0x88888880 +#define AR9300_STOMP_NONE_WLAN_WGHT0 0x00000000 +#define AR9300_STOMP_NONE_WLAN_WGHT1 0x00000000 + #define AR_BT_COEX_MODE2 0x817c #define AR_BT_BCN_MISS_THRESH 0x000000ff #define AR_BT_BCN_MISS_THRESH_S 0 diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 8f095ad..f9b1eb4 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -79,8 +79,8 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd) return "WMI_TX_STATS_CMDID"; case WMI_RX_STATS_CMDID: return "WMI_RX_STATS_CMDID"; - case WMI_AGGR_LIMIT_CMD: - return "WMI_AGGR_LIMIT_CMD"; + case WMI_BITRATE_MASK_CMDID: + return "WMI_BITRATE_MASK_CMDID"; } return "Bogus"; diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 02ecb9f..6095eeb 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -111,7 +111,7 @@ enum wmi_cmd_id { WMI_INT_STATS_CMDID, WMI_TX_STATS_CMDID, WMI_RX_STATS_CMDID, - WMI_AGGR_LIMIT_CMD = 0x0026, + WMI_BITRATE_MASK_CMDID, }; enum wmi_event_id { diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index e9e99f7..7b91b2a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2180,28 +2180,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } } -static void ath_hw_pll_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - hw_pll_work.work); - static int count; - - if (AR_SREV_9485(sc->sc_ah)) { - if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) { - count++; - - if (count == 3) { - /* Rx is hung for more than 500ms. Reset it */ - ath_reset(sc, true); - count = 0; - } - } else - count = 0; - - ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); - } -} - static void ath_tx_complete_poll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, @@ -2396,7 +2374,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) } INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work); - INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { error = ath_tx_edma_init(sc); diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 3d4ed58..bb57869 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -448,6 +448,8 @@ struct carl9170_ba_stats { struct carl9170_sta_info { bool ht_sta; + bool sleeping; + atomic_t pending_frames; unsigned int ampdu_max_len; struct carl9170_sta_tid *agg[CARL9170_NUM_TID]; struct carl9170_ba_stats stats[CARL9170_NUM_TID]; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 89fe60a..1638468 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1193,6 +1193,8 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw, struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; unsigned int i; + atomic_set(&sta_info->pending_frames, 0); + if (sta->ht_cap.ht_supported) { if (sta->ht_cap.ampdu_density > 6) { /* @@ -1467,99 +1469,17 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw, enum sta_notify_cmd cmd, struct ieee80211_sta *sta) { - struct ar9170 *ar = hw->priv; struct carl9170_sta_info *sta_info = (void *) sta->drv_priv; - struct sk_buff *skb, *tmp; - struct sk_buff_head free; - int i; switch (cmd) { case STA_NOTIFY_SLEEP: - /* - * Since the peer is no longer listening, we have to return - * as many SKBs as possible back to the mac80211 stack. - * It will deal with the retry procedure, once the peer - * has become available again. - * - * NB: Ideally, the driver should return the all frames in - * the correct, ascending order. However, I think that this - * functionality should be implemented in the stack and not - * here... - */ - - __skb_queue_head_init(&free); - - if (sta->ht_cap.ht_supported) { - rcu_read_lock(); - for (i = 0; i < CARL9170_NUM_TID; i++) { - struct carl9170_sta_tid *tid_info; - - tid_info = rcu_dereference(sta_info->agg[i]); - - if (!tid_info) - continue; - - spin_lock_bh(&ar->tx_ampdu_list_lock); - if (tid_info->state > - CARL9170_TID_STATE_SUSPEND) - tid_info->state = - CARL9170_TID_STATE_SUSPEND; - spin_unlock_bh(&ar->tx_ampdu_list_lock); - - spin_lock_bh(&tid_info->lock); - while ((skb = __skb_dequeue(&tid_info->queue))) - __skb_queue_tail(&free, skb); - spin_unlock_bh(&tid_info->lock); - } - rcu_read_unlock(); - } - - for (i = 0; i < ar->hw->queues; i++) { - spin_lock_bh(&ar->tx_pending[i].lock); - skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) { - struct _carl9170_tx_superframe *super; - struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *info; - - super = (void *) skb->data; - hdr = (void *) super->frame_data; - - if (compare_ether_addr(hdr->addr1, sta->addr)) - continue; - - __skb_unlink(skb, &ar->tx_pending[i]); - - info = IEEE80211_SKB_CB(skb); - if (info->flags & IEEE80211_TX_CTL_AMPDU) - atomic_dec(&ar->tx_ampdu_upload); - - carl9170_tx_status(ar, skb, false); - } - spin_unlock_bh(&ar->tx_pending[i].lock); - } - - while ((skb = __skb_dequeue(&free))) - carl9170_tx_status(ar, skb, false); - + sta_info->sleeping = true; + if (atomic_read(&sta_info->pending_frames)) + ieee80211_sta_block_awake(hw, sta, true); break; case STA_NOTIFY_AWAKE: - if (!sta->ht_cap.ht_supported) - return; - - rcu_read_lock(); - for (i = 0; i < CARL9170_NUM_TID; i++) { - struct carl9170_sta_tid *tid_info; - - tid_info = rcu_dereference(sta_info->agg[i]); - - if (!tid_info) - continue; - - if ((tid_info->state == CARL9170_TID_STATE_SUSPEND)) - tid_info->state = CARL9170_TID_STATE_IDLE; - } - rcu_read_unlock(); + sta_info->sleeping = false; break; } } diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index cb70ed7..bf2eff9 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -104,6 +104,56 @@ static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb) spin_unlock_bh(&ar->tx_stats_lock); } +/* needs rcu_read_lock */ +static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar, + struct sk_buff *skb) +{ + struct _carl9170_tx_superframe *super = (void *) skb->data; + struct ieee80211_hdr *hdr = (void *) super->frame_data; + struct ieee80211_vif *vif; + unsigned int vif_id; + + vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> + CARL9170_TX_SUPER_MISC_VIF_ID_S; + + if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) + return NULL; + + vif = rcu_dereference(ar->vif_priv[vif_id].vif); + if (unlikely(!vif)) + return NULL; + + /* + * Normally we should use wrappers like ieee80211_get_DA to get + * the correct peer ieee80211_sta. + * + * But there is a problem with indirect traffic (broadcasts, or + * data which is designated for other stations) in station mode. + * The frame will be directed to the AP for distribution and not + * to the actual destination. + */ + + return ieee80211_find_sta(vif, hdr->addr1); +} + +static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; + + rcu_read_lock(); + sta = __carl9170_get_tx_sta(ar, skb); + if (unlikely(!sta)) + goto out_rcu; + + sta_info = (struct carl9170_sta_info *) sta->drv_priv; + if (atomic_dec_return(&sta_info->pending_frames) == 0) + ieee80211_sta_block_awake(ar->hw, sta, false); + +out_rcu: + rcu_read_unlock(); +} + static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) { struct ieee80211_tx_info *txinfo; @@ -135,6 +185,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb) } spin_unlock_bh(&ar->tx_stats_lock); + if (atomic_dec_and_test(&ar->tx_total_queued)) complete(&ar->tx_flush); } @@ -329,13 +380,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, { struct _carl9170_tx_superframe *super = (void *) skb->data; struct ieee80211_hdr *hdr = (void *) super->frame_data; - struct ieee80211_tx_info *tx_info; struct carl9170_tx_info *ar_info; - struct carl9170_sta_info *sta_info; struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; struct carl9170_sta_tid *tid_info; - struct ieee80211_vif *vif; - unsigned int vif_id; u8 tid; if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) || @@ -343,30 +391,10 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, (!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR)))) return; - tx_info = IEEE80211_SKB_CB(skb); - ar_info = (void *) tx_info->rate_driver_data; - - vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> - CARL9170_TX_SUPER_MISC_VIF_ID_S; - - if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC)) - return; + ar_info = (void *) txinfo->rate_driver_data; rcu_read_lock(); - vif = rcu_dereference(ar->vif_priv[vif_id].vif); - if (unlikely(!vif)) - goto out_rcu; - - /* - * Normally we should use wrappers like ieee80211_get_DA to get - * the correct peer ieee80211_sta. - * - * But there is a problem with indirect traffic (broadcasts, or - * data which is designated for other stations) in station mode. - * The frame will be directed to the AP for distribution and not - * to the actual destination. - */ - sta = ieee80211_find_sta(vif, hdr->addr1); + sta = __carl9170_get_tx_sta(ar, skb); if (unlikely(!sta)) goto out_rcu; @@ -427,6 +455,7 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, if (txinfo->flags & IEEE80211_TX_CTL_AMPDU) carl9170_tx_status_process_ampdu(ar, skb, txinfo); + carl9170_tx_ps_unblock(ar, skb); carl9170_tx_put_skb(skb); } @@ -540,11 +569,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) struct sk_buff *skb; struct ieee80211_tx_info *txinfo; struct carl9170_tx_info *arinfo; - struct _carl9170_tx_superframe *super; struct ieee80211_sta *sta; - struct ieee80211_vif *vif; - struct ieee80211_hdr *hdr; - unsigned int vif_id; rcu_read_lock(); list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) { @@ -562,20 +587,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar) msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT))) goto unlock; - super = (void *) skb->data; - hdr = (void *) super->frame_data; - - vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >> - CARL9170_TX_SUPER_MISC_VIF_ID_S; - - if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC)) - goto unlock; - - vif = rcu_dereference(ar->vif_priv[vif_id].vif); - if (WARN_ON(!vif)) - goto unlock; - - sta = ieee80211_find_sta(vif, hdr->addr1); + sta = __carl9170_get_tx_sta(ar, skb); if (WARN_ON(!sta)) goto unlock; @@ -1199,15 +1211,6 @@ static struct sk_buff *carl9170_tx_pick_skb(struct ar9170 *ar, arinfo = (void *) info->rate_driver_data; arinfo->timeout = jiffies; - - /* - * increase ref count to "2". - * Ref counting is the easiest way to solve the race between - * the the urb's completion routine: carl9170_tx_callback and - * wlan tx status functions: carl9170_tx_status/janitor. - */ - carl9170_tx_get_skb(skb); - return skb; err_unlock: @@ -1228,6 +1231,36 @@ void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb) __carl9170_tx_process_status(ar, super->s.cookie, q); } +static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *sta; + struct carl9170_sta_info *sta_info; + + rcu_read_lock(); + sta = __carl9170_get_tx_sta(ar, skb); + if (!sta) + goto out_rcu; + + sta_info = (void *) sta->drv_priv; + if (unlikely(sta_info->sleeping)) { + struct ieee80211_tx_info *tx_info; + + rcu_read_unlock(); + + tx_info = IEEE80211_SKB_CB(skb); + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) + atomic_dec(&ar->tx_ampdu_upload); + + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + carl9170_tx_status(ar, skb, false); + return true; + } + +out_rcu: + rcu_read_unlock(); + return false; +} + static void carl9170_tx(struct ar9170 *ar) { struct sk_buff *skb; @@ -1247,6 +1280,9 @@ static void carl9170_tx(struct ar9170 *ar) if (unlikely(!skb)) break; + if (unlikely(carl9170_tx_ps_drop(ar, skb))) + continue; + atomic_inc(&ar->tx_total_pending); q = __carl9170_get_queue(ar, i); @@ -1256,6 +1292,16 @@ static void carl9170_tx(struct ar9170 *ar) */ skb_queue_tail(&ar->tx_status[q], skb); + /* + * increase ref count to "2". + * Ref counting is the easiest way to solve the + * race between the urb's completion routine: + * carl9170_tx_callback + * and wlan tx status functions: + * carl9170_tx_status/janitor. + */ + carl9170_tx_get_skb(skb); + carl9170_usb_tx(ar, skb); schedule_garbagecollector = true; } @@ -1368,6 +1414,11 @@ void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * all ressouces which are associated with the frame. */ + if (sta) { + struct carl9170_sta_info *stai = (void *) sta->drv_priv; + atomic_inc(&stai->pending_frames); + } + if (info->flags & IEEE80211_TX_CTL_AMPDU) { run = carl9170_tx_ampdu_queue(ar, sta, skb); if (run) diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 8a00f9a..6755063 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -2281,6 +2281,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER); save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0); save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1); + save_regs_phy[8] = 0; } else { save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1); save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2); @@ -2289,6 +2290,8 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf, save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER); save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1); save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2); + save_regs_phy[7] = 0; + save_regs_phy[8] = 0; } b43_nphy_rssi_select(dev, 5, type); @@ -3845,8 +3848,8 @@ static int b43_nphy_set_channel(struct b43_wldev *dev, { struct b43_phy *phy = &dev->phy; - const struct b43_nphy_channeltab_entry_rev2 *tabent_r2; - const struct b43_nphy_channeltab_entry_rev3 *tabent_r3; + const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL; + const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL; u8 tmp; diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c index 5a8a3cc..7e5e85a 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c @@ -955,9 +955,6 @@ int iwl4965_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) if (priv->cfg->scan_rx_antennas[band]) rx_ant = priv->cfg->scan_rx_antennas[band]; - if (priv->cfg->scan_tx_antennas[band]) - scan_tx_antennas = priv->cfg->scan_tx_antennas[band]; - priv->scan_tx_ant[band] = iwl4965_toggle_tx_ant(priv, priv->scan_tx_ant[band], scan_tx_antennas); diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index c1511b1..d743373 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -211,10 +211,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) if (!iwl_legacy_is_channel_valid(ch)) continue; - if (iwl_legacy_is_channel_a_band(ch)) - sband = &priv->bands[IEEE80211_BAND_5GHZ]; - else - sband = &priv->bands[IEEE80211_BAND_2GHZ]; + sband = &priv->bands[ch->band]; geo_ch = &sband->channels[sband->n_channels++]; @@ -2117,10 +2114,9 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n", channel->hw_value, changed); - if (unlikely(!priv->cfg->mod_params->disable_hw_scan && - test_bit(STATUS_SCANNING, &priv->status))) { + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { scan_active = 1; - IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); + IWL_DEBUG_MAC80211(priv, "scan active\n"); } if (changed & (IEEE80211_CONF_CHANGE_SMPS | @@ -2433,11 +2429,13 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes); - if (!iwl_legacy_is_alive(priv)) - return; - mutex_lock(&priv->mutex); + if (!iwl_legacy_is_alive(priv)) { + mutex_unlock(&priv->mutex); + return; + } + if (changes & BSS_CHANGED_QOS) { unsigned long flags; @@ -2646,7 +2644,7 @@ unplugged: none: /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_legacy_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index f03b463..bc66c60 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -287,7 +287,6 @@ struct iwl_cfg { struct iwl_base_params *base_params; /* params likely to change within a device family */ u8 scan_rx_antennas[IEEE80211_NUM_BANDS]; - u8 scan_tx_antennas[IEEE80211_NUM_BANDS]; enum iwl_led_mode led_mode; }; diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index 9ee849d..2d87dba 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -134,7 +134,7 @@ struct iwl_queue { * space more than this */ int high_mark; /* high watermark, stop queue if free * space less than this */ -} __packed; +}; /* One for each TFD */ struct iwl_tx_info { @@ -290,6 +290,7 @@ enum { CMD_SIZE_HUGE = (1 << 0), CMD_ASYNC = (1 << 1), CMD_WANT_SKB = (1 << 2), + CMD_MAPPED = (1 << 3), }; #define DEF_CMD_PAYLOAD_SIZE 320 @@ -1076,7 +1077,6 @@ struct iwl_priv { spinlock_t hcmd_lock; /* protect hcmd */ spinlock_t reg_lock; /* protect hw register access */ struct mutex mutex; - struct mutex sync_cmd_mutex; /* enable serialization of sync commands */ /* basic pci-network driver stuff */ struct pci_dev *pci_dev; diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c index 9d721cb..62b4b09 100644 --- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c +++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c @@ -145,6 +145,8 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int cmd_idx; int ret; + lockdep_assert_held(&priv->mutex); + BUG_ON(cmd->flags & CMD_ASYNC); /* A synchronous command can not have a callback set. */ @@ -152,7 +154,6 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", iwl_legacy_get_cmd_string(cmd->id)); - mutex_lock(&priv->sync_cmd_mutex); set_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", @@ -224,7 +225,6 @@ fail: cmd->reply_page = 0; } out: - mutex_unlock(&priv->sync_cmd_mutex); return ret; } EXPORT_SYMBOL(iwl_legacy_send_cmd_sync); diff --git a/drivers/net/wireless/iwlegacy/iwl-helpers.h b/drivers/net/wireless/iwlegacy/iwl-helpers.h index 02132e7..a6effda 100644 --- a/drivers/net/wireless/iwlegacy/iwl-helpers.h +++ b/drivers/net/wireless/iwlegacy/iwl-helpers.h @@ -149,6 +149,12 @@ static inline void iwl_legacy_disable_interrupts(struct iwl_priv *priv) IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); } +static inline void iwl_legacy_enable_rfkill_int(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); + iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); +} + static inline void iwl_legacy_enable_interrupts(struct iwl_priv *priv) { IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c index a227773..4fff995 100644 --- a/drivers/net/wireless/iwlegacy/iwl-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-tx.c @@ -146,33 +146,32 @@ void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv) { struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; struct iwl_queue *q = &txq->q; - bool huge = false; int i; if (q->n_bd == 0) return; while (q->read_ptr != q->write_ptr) { - /* we have no way to tell if it is a huge cmd ATM */ i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0); - if (txq->meta[i].flags & CMD_SIZE_HUGE) - huge = true; - else + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; + } q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd); } - if (huge) { - i = q->n_window; + i = q->n_window; + if (txq->meta[i].flags & CMD_MAPPED) { pci_unmap_single(priv->pci_dev, dma_unmap_addr(&txq->meta[i], mapping), dma_unmap_len(&txq->meta[i], len), PCI_DMA_BIDIRECTIONAL); + txq->meta[i].flags = 0; } } EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap); @@ -467,29 +466,27 @@ int iwl_legacy_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return -EIO; } + spin_lock_irqsave(&priv->hcmd_lock, flags); + if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { - IWL_ERR(priv, "No space in command queue\n"); - IWL_ERR(priv, "Restarting adapter due to queue full\n"); + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + + IWL_ERR(priv, "Restarting adapter due to command queue full\n"); queue_work(priv->workqueue, &priv->restart); return -ENOSPC; } - spin_lock_irqsave(&priv->hcmd_lock, flags); - - /* If this is a huge cmd, mark the huge flag also on the meta.flags - * of the _original_ cmd. This is used for DMA mapping clean up. - */ - if (cmd->flags & CMD_SIZE_HUGE) { - idx = iwl_legacy_get_cmd_index(q, q->write_ptr, 0); - txq->meta[idx].flags = CMD_SIZE_HUGE; - } - idx = iwl_legacy_get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE); out_cmd = txq->cmd[idx]; out_meta = &txq->meta[idx]; + if (WARN_ON(out_meta->flags & CMD_MAPPED)) { + spin_unlock_irqrestore(&priv->hcmd_lock, flags); + return -ENOSPC; + } + memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ - out_meta->flags = cmd->flags; + out_meta->flags = cmd->flags | CMD_MAPPED; if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; if (cmd->flags & CMD_ASYNC) @@ -610,6 +607,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + unsigned long flags; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -623,14 +621,6 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - /* If this is a huge cmd, clear the huge flag on the meta.flags - * of the _original_ cmd. So that iwl_legacy_cmd_queue_free won't unmap - * the DMA buffer for the scan (huge) command. - */ - if (huge) { - cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, 0); - txq->meta[cmd_index].flags = 0; - } cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -647,6 +637,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) } else if (meta->callback) meta->callback(priv, cmd, pkt); + spin_lock_irqsave(&priv->hcmd_lock, flags); + iwl_legacy_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(meta->flags & CMD_ASYNC)) { @@ -655,6 +647,10 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) iwl_legacy_get_cmd_string(cmd->hdr.cmd)); wake_up_interruptible(&priv->wait_command_queue); } + + /* Mark as unmapped */ meta->flags = 0; + + spin_unlock_irqrestore(&priv->hcmd_lock, flags); } EXPORT_SYMBOL(iwl_legacy_tx_cmd_complete); diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index cc7ebce..0ee6be6 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -2748,11 +2748,12 @@ static void iwl3945_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl3945_init_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2761,11 +2762,12 @@ static void iwl3945_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl3945_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2995,10 +2997,12 @@ static void iwl3945_bg_restart(struct work_struct *data) } else { iwl3945_down(priv); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); return; + } - mutex_lock(&priv->mutex); __iwl3945_up(priv); mutex_unlock(&priv->mutex); } @@ -3009,11 +3013,12 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, rx_replenish); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl3945_rx_replenish(priv); +out: mutex_unlock(&priv->mutex); } @@ -3810,7 +3815,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index f887054..f781b7e 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -1069,9 +1069,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) } /* Re-enable all interrupts */ - /* only Re-enable if diabled by irq */ + /* only Re-enable if disabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) iwl_legacy_enable_interrupts(priv); + /* Re-enable RF_KILL if it occurred */ + else if (handled & CSR_INT_BIT_RF_KILL) + iwl_legacy_enable_rfkill_int(priv); #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG if (iwl_legacy_get_debug_level(priv) & (IWL_DL_ISR)) { @@ -2139,7 +2142,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv); static void __iwl4965_down(struct iwl_priv *priv) { unsigned long flags; - int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); + int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); @@ -2401,11 +2404,12 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, init_alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); priv->cfg->ops->lib->init_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2414,11 +2418,12 @@ static void iwl4965_bg_alive_start(struct work_struct *data) struct iwl_priv *priv = container_of(data, struct iwl_priv, alive_start.work); + mutex_lock(&priv->mutex); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; + goto out; - mutex_lock(&priv->mutex); iwl4965_alive_start(priv); +out: mutex_unlock(&priv->mutex); } @@ -2468,10 +2473,12 @@ static void iwl4965_bg_restart(struct work_struct *data) } else { iwl4965_down(priv); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + mutex_unlock(&priv->mutex); return; + } - mutex_lock(&priv->mutex); __iwl4965_up(priv); mutex_unlock(&priv->mutex); } @@ -2624,9 +2631,10 @@ void iwl4965_mac_stop(struct ieee80211_hw *hw) flush_workqueue(priv->workqueue); - /* enable interrupts again in order to receive rfkill changes */ + /* User space software may expect getting rfkill changes + * even if interface is down */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_legacy_enable_interrupts(priv); + iwl_legacy_enable_rfkill_int(priv); IWL_DEBUG_MAC80211(priv, "leave\n"); } @@ -2847,21 +2855,22 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->mutex); + if (iwl_legacy_is_rfkill(priv)) - goto out_exit; + goto out; if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - goto out_exit; + goto out; if (!iwl_legacy_is_associated_ctx(ctx)) - goto out_exit; + goto out; /* channel switch in progress */ if (priv->switch_rxon.switch_in_progress == true) - goto out_exit; + goto out; - mutex_lock(&priv->mutex); if (priv->cfg->ops->lib->set_channel_switch) { ch = channel->hw_value; @@ -2917,7 +2926,6 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw, } out: mutex_unlock(&priv->mutex); -out_exit: if (!priv->switch_rxon.switch_in_progress) ieee80211_chswitch_done(ctx->vif, false); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -3116,7 +3124,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) INIT_LIST_HEAD(&priv->free_frames); mutex_init(&priv->mutex); - mutex_init(&priv->sync_cmd_mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; @@ -3406,14 +3413,14 @@ iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * 8. Enable interrupts and read RFKILL state *********************************************/ - /* enable interrupts if needed: hw bug w/a */ + /* enable rfkill interrupt: hw bug w/a */ pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); } - iwl_legacy_enable_interrupts(priv); + iwl_legacy_enable_rfkill_int(priv); /* If platform's RF_KILL switch is NOT set to KILL */ if (iwl_read32(priv, CSR_GP_CNTRL) & diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index bb6a737..89a41d3 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -14,7 +14,6 @@ iwlagn-objs += iwl-6000.o iwlagn-objs += iwl-1000.o iwlagn-objs += iwl-2000.o -iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index baf8011..3da8cf2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -45,7 +45,6 @@ #include "iwl-agn.h" #include "iwl-helpers.h" #include "iwl-agn-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL1000_UCODE_API_MAX 5 @@ -121,10 +120,10 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = { static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -197,21 +196,11 @@ static struct iwl_lib_ops iwl1000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REGULATORY_BAND_NO_HT40, }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -249,7 +238,6 @@ static struct iwl_ht_params iwl1000_ht_params = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_BLINK @@ -271,7 +259,6 @@ struct iwl_cfg iwl1000_bg_cfg = { .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ .ops = &iwl1000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl1000_base_params, \ .led_mode = IWL_LED_RF_STATE, \ .rx_with_siso_diversity = true diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index e76e02c..bca462c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -46,17 +46,16 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL2030_UCODE_API_MAX 5 #define IWL2000_UCODE_API_MAX 5 -#define IWL200_UCODE_API_MAX 5 +#define IWL105_UCODE_API_MAX 5 /* Lowest firmware API version supported */ #define IWL2030_UCODE_API_MIN 5 #define IWL2000_UCODE_API_MIN 5 -#define IWL200_UCODE_API_MIN 5 +#define IWL105_UCODE_API_MIN 5 #define IWL2030_FW_PRE "iwlwifi-2030-" #define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode" @@ -64,8 +63,8 @@ #define IWL2000_FW_PRE "iwlwifi-2000-" #define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode" -#define IWL200_FW_PRE "iwlwifi-200-" -#define IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode" +#define IWL105_FW_PRE "iwlwifi-105-" +#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode" static void iwl2000_set_ct_threshold(struct iwl_priv *priv) { @@ -128,10 +127,10 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = { static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -280,22 +279,12 @@ static struct iwl_lib_ops iwl2000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REGULATORY_BAND_NO_HT40, }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -312,13 +301,13 @@ static const struct iwl_ops iwl2030_ops = { .utils = &iwlagn_hcmd_utils, }; -static const struct iwl_ops iwl200_ops = { +static const struct iwl_ops iwl105_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_hcmd, .utils = &iwlagn_hcmd_utils, }; -static const struct iwl_ops iwl230_ops = { +static const struct iwl_ops iwl135_ops = { .lib = &iwl2000_lib, .hcmd = &iwlagn_bt_hcmd, .utils = &iwlagn_hcmd_utils, @@ -383,7 +372,6 @@ static struct iwl_bt_params iwl2030_bt_params = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl2000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -409,7 +397,6 @@ struct iwl_cfg iwl2000_2bg_cfg = { .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ .ops = &iwl2030_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ @@ -429,14 +416,13 @@ struct iwl_cfg iwl2030_2bg_cfg = { IWL_DEVICE_2030, }; -#define IWL_DEVICE_200 \ - .fw_name_pre = IWL200_FW_PRE, \ - .ucode_api_max = IWL200_UCODE_API_MAX, \ - .ucode_api_min = IWL200_UCODE_API_MIN, \ +#define IWL_DEVICE_105 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .ops = &iwl200_ops, \ - .mod_params = &iwlagn_mod_params, \ + .ops = &iwl105_ops, \ .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -444,25 +430,24 @@ struct iwl_cfg iwl2030_2bg_cfg = { .adv_pm = true, \ .rx_with_siso_diversity = true \ -struct iwl_cfg iwl200_bg_cfg = { - .name = "200 Series 1x1 BG", - IWL_DEVICE_200, +struct iwl_cfg iwl105_bg_cfg = { + .name = "105 Series 1x1 BG", + IWL_DEVICE_105, }; -struct iwl_cfg iwl200_bgn_cfg = { - .name = "200 Series 1x1 BGN", - IWL_DEVICE_200, +struct iwl_cfg iwl105_bgn_cfg = { + .name = "105 Series 1x1 BGN", + IWL_DEVICE_105, .ht_params = &iwl2000_ht_params, }; -#define IWL_DEVICE_230 \ - .fw_name_pre = IWL200_FW_PRE, \ - .ucode_api_max = IWL200_UCODE_API_MAX, \ - .ucode_api_min = IWL200_UCODE_API_MIN, \ +#define IWL_DEVICE_135 \ + .fw_name_pre = IWL105_FW_PRE, \ + .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_min = IWL105_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ - .ops = &iwl230_ops, \ - .mod_params = &iwlagn_mod_params, \ + .ops = &iwl135_ops, \ .base_params = &iwl2030_base_params, \ .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ @@ -471,17 +456,17 @@ struct iwl_cfg iwl200_bgn_cfg = { .adv_pm = true, \ .rx_with_siso_diversity = true \ -struct iwl_cfg iwl230_bg_cfg = { - .name = "200 Series 1x1 BG/BT", - IWL_DEVICE_230, +struct iwl_cfg iwl135_bg_cfg = { + .name = "105 Series 1x1 BG/BT", + IWL_DEVICE_135, }; -struct iwl_cfg iwl230_bgn_cfg = { - .name = "200 Series 1x1 BGN/BT", - IWL_DEVICE_230, +struct iwl_cfg iwl135_bgn_cfg = { + .name = "105 Series 1x1 BGN/BT", + IWL_DEVICE_135, .ht_params = &iwl2000_ht_params, }; MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX)); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 655afc1..561f2cd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -47,7 +47,6 @@ #include "iwl-agn.h" #include "iwl-agn-hw.h" #include "iwl-5000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL5000_UCODE_API_MAX 5 @@ -165,10 +164,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv) static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -210,10 +209,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -366,21 +365,11 @@ static struct iwl_lib_ops iwl5000_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -413,21 +402,11 @@ static struct iwl_lib_ops iwl5150_lib = { EEPROM_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, }, .temp_ops = { .temperature = iwl5150_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -468,7 +447,6 @@ static struct iwl_ht_params iwl5000_ht_params = { .eeprom_ver = EEPROM_5000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \ .ops = &iwl5000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .led_mode = IWL_LED_BLINK @@ -512,7 +490,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .ops = &iwl5000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl5000_base_params, .ht_params = &iwl5000_ht_params, .led_mode = IWL_LED_BLINK, @@ -526,7 +503,6 @@ struct iwl_cfg iwl5350_agn_cfg = { .eeprom_ver = EEPROM_5050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \ .ops = &iwl5150_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl5000_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 905eb57..6045457 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -46,7 +46,6 @@ #include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-6000-hw.h" -#include "iwl-agn-debugfs.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 @@ -80,7 +79,7 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) static void iwl6050_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } @@ -88,7 +87,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv) static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ - if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6) + if (iwlagn_eeprom_calib_version(priv) >= 6) iwl_set_bit(priv, CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); iwl_set_bit(priv, CSR_GP_DRIVER_REG, @@ -154,10 +153,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) { - if (priv->cfg->mod_params->num_of_queues >= IWL_MIN_NUM_QUEUES && - priv->cfg->mod_params->num_of_queues <= IWLAGN_NUM_QUEUES) + if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES && + iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES) priv->cfg->base_params->num_of_queues = - priv->cfg->mod_params->num_of_queues; + iwlagn_mod_params.num_of_queues; priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; @@ -305,22 +304,12 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -354,22 +343,12 @@ static struct iwl_lib_ops iwl6030_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, - .release_semaphore = iwlcore_eeprom_release_semaphore, - .calib_version = iwlagn_eeprom_calib_version, .query_addr = iwlagn_eeprom_query_addr, .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, }, .temp_ops = { .temperature = iwlagn_temperature, }, - .debugfs_ops = { - .rx_stats_read = iwl_ucode_rx_stats_read, - .tx_stats_read = iwl_ucode_tx_stats_read, - .general_stats_read = iwl_ucode_general_stats_read, - .bt_stats_read = iwl_ucode_bt_stats_read, - .reply_tx_error = iwl_reply_tx_error_read, - }, .txfifo_flush = iwlagn_txfifo_flush, .dev_txfifo_flush = iwlagn_dev_txfifo_flush, }; @@ -482,7 +461,6 @@ static struct iwl_bt_params iwl6000_bt_params = { .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ @@ -511,7 +489,6 @@ struct iwl_cfg iwl6005_2bg_cfg = { .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ .ops = &iwl6030_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_g2_base_params, \ .bt_params = &iwl6000_bt_params, \ .need_dc_calib = true, \ @@ -593,7 +570,6 @@ struct iwl_cfg iwl130_bg_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \ .ops = &iwl6000_ops, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6000_base_params, \ .pa_type = IWL_PA_INTERNAL, \ .led_mode = IWL_LED_BLINK @@ -623,7 +599,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = { .ops = &iwl6050_ops, \ .eeprom_ver = EEPROM_6050_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \ - .mod_params = &iwlagn_mod_params, \ .base_params = &iwl6050_base_params, \ .need_dc_calib = true, \ .led_mode = IWL_LED_BLINK, \ @@ -648,7 +623,6 @@ struct iwl_cfg iwl6150_bgn_cfg = { .eeprom_ver = EEPROM_6150_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION, .ops = &iwl6150_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl6050_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, @@ -664,7 +638,6 @@ struct iwl_cfg iwl6000_3agn_cfg = { .eeprom_ver = EEPROM_6000_EEPROM_VERSION, .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, .ops = &iwl6000_ops, - .mod_params = &iwlagn_mod_params, .base_params = &iwl6000_base_params, .ht_params = &iwl6000_ht_params, .need_dc_calib = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c deleted file mode 100644 index 71a5f31..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c +++ /dev/null @@ -1,1025 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ -#include "iwl-agn.h" -#include "iwl-agn-debugfs.h" - -static const char *fmt_value = " %-30s %10u\n"; -static const char *fmt_hex = " %-30s 0x%02X\n"; -static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; -static const char *fmt_header = - "%-32s current cumulative delta max\n"; - -static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) -{ - int p = 0; - u32 flag; - - flag = le32_to_cpu(priv->statistics.flag); - - p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); - if (flag & UCODE_STATISTICS_CLEAR_MSK) - p += scnprintf(buf + p, bufsz - p, - "\tStatistics have been cleared\n"); - p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", - (flag & UCODE_STATISTICS_FREQUENCY_MSK) - ? "2.4 GHz" : "5.2 GHz"); - p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", - (flag & UCODE_STATISTICS_NARROW_BAND_MSK) - ? "enabled" : "disabled"); - - return p; -} - -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) - { - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_rx_phy) * 40 + - sizeof(struct statistics_rx_non_phy) * 40 + - sizeof(struct statistics_rx_ht_phy) * 40 + 400; - ssize_t ret; - struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; - struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; - struct statistics_rx_non_phy *general, *accum_general; - struct statistics_rx_non_phy *delta_general, *max_general; - struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - ofdm = &priv->statistics.rx_ofdm; - cck = &priv->statistics.rx_cck; - general = &priv->statistics.rx_non_phy; - ht = &priv->statistics.rx_ofdm_ht; - accum_ofdm = &priv->accum_stats.rx_ofdm; - accum_cck = &priv->accum_stats.rx_cck; - accum_general = &priv->accum_stats.rx_non_phy; - accum_ht = &priv->accum_stats.rx_ofdm_ht; - delta_ofdm = &priv->delta_stats.rx_ofdm; - delta_cck = &priv->delta_stats.rx_cck; - delta_general = &priv->delta_stats.rx_non_phy; - delta_ht = &priv->delta_stats.rx_ofdm_ht; - max_ofdm = &priv->max_delta_stats.rx_ofdm; - max_cck = &priv->max_delta_stats.rx_cck; - max_general = &priv->max_delta_stats.rx_non_phy; - max_ht = &priv->max_delta_stats.rx_ofdm_ht; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(ofdm->ina_cnt), - accum_ofdm->ina_cnt, - delta_ofdm->ina_cnt, max_ofdm->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, - delta_ofdm->fina_cnt, max_ofdm->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, - delta_ofdm->plcp_err, max_ofdm->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, - delta_ofdm->crc32_err, max_ofdm->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ofdm->overrun_err), - accum_ofdm->overrun_err, delta_ofdm->overrun_err, - max_ofdm->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ofdm->early_overrun_err), - accum_ofdm->early_overrun_err, - delta_ofdm->early_overrun_err, - max_ofdm->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ofdm->crc32_good), - accum_ofdm->crc32_good, delta_ofdm->crc32_good, - max_ofdm->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(ofdm->false_alarm_cnt), - accum_ofdm->false_alarm_cnt, - delta_ofdm->false_alarm_cnt, - max_ofdm->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(ofdm->fina_sync_err_cnt), - accum_ofdm->fina_sync_err_cnt, - delta_ofdm->fina_sync_err_cnt, - max_ofdm->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(ofdm->sfd_timeout), - accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, - max_ofdm->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(ofdm->fina_timeout), - accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, - max_ofdm->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(ofdm->unresponded_rts), - accum_ofdm->unresponded_rts, - delta_ofdm->unresponded_rts, - max_ofdm->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(ofdm->rxe_frame_limit_overrun), - accum_ofdm->rxe_frame_limit_overrun, - delta_ofdm->rxe_frame_limit_overrun, - max_ofdm->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(ofdm->sent_ack_cnt), - accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, - max_ofdm->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(ofdm->sent_cts_cnt), - accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, - max_ofdm->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(ofdm->sent_ba_rsp_cnt), - accum_ofdm->sent_ba_rsp_cnt, - delta_ofdm->sent_ba_rsp_cnt, - max_ofdm->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(ofdm->dsp_self_kill), - accum_ofdm->dsp_self_kill, - delta_ofdm->dsp_self_kill, - max_ofdm->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ofdm->mh_format_err), - accum_ofdm->mh_format_err, - delta_ofdm->mh_format_err, - max_ofdm->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(ofdm->re_acq_main_rssi_sum), - accum_ofdm->re_acq_main_rssi_sum, - delta_ofdm->re_acq_main_rssi_sum, - max_ofdm->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - CCK:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_cnt:", - le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, - delta_cck->ina_cnt, max_cck->ina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_cnt:", - le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, - delta_cck->fina_cnt, max_cck->fina_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, - delta_cck->plcp_err, max_cck->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, - delta_cck->crc32_err, max_cck->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(cck->overrun_err), - accum_cck->overrun_err, delta_cck->overrun_err, - max_cck->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(cck->early_overrun_err), - accum_cck->early_overrun_err, - delta_cck->early_overrun_err, - max_cck->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, - delta_cck->crc32_good, max_cck->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "false_alarm_cnt:", - le32_to_cpu(cck->false_alarm_cnt), - accum_cck->false_alarm_cnt, - delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_sync_err_cnt:", - le32_to_cpu(cck->fina_sync_err_cnt), - accum_cck->fina_sync_err_cnt, - delta_cck->fina_sync_err_cnt, - max_cck->fina_sync_err_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sfd_timeout:", - le32_to_cpu(cck->sfd_timeout), - accum_cck->sfd_timeout, delta_cck->sfd_timeout, - max_cck->sfd_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "fina_timeout:", - le32_to_cpu(cck->fina_timeout), - accum_cck->fina_timeout, delta_cck->fina_timeout, - max_cck->fina_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unresponded_rts:", - le32_to_cpu(cck->unresponded_rts), - accum_cck->unresponded_rts, delta_cck->unresponded_rts, - max_cck->unresponded_rts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rxe_frame_lmt_ovrun:", - le32_to_cpu(cck->rxe_frame_limit_overrun), - accum_cck->rxe_frame_limit_overrun, - delta_cck->rxe_frame_limit_overrun, - max_cck->rxe_frame_limit_overrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ack_cnt:", - le32_to_cpu(cck->sent_ack_cnt), - accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, - max_cck->sent_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_cts_cnt:", - le32_to_cpu(cck->sent_cts_cnt), - accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, - max_cck->sent_cts_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sent_ba_rsp_cnt:", - le32_to_cpu(cck->sent_ba_rsp_cnt), - accum_cck->sent_ba_rsp_cnt, - delta_cck->sent_ba_rsp_cnt, - max_cck->sent_ba_rsp_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_self_kill:", - le32_to_cpu(cck->dsp_self_kill), - accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, - max_cck->dsp_self_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(cck->mh_format_err), - accum_cck->mh_format_err, delta_cck->mh_format_err, - max_cck->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "re_acq_main_rssi_sum:", - le32_to_cpu(cck->re_acq_main_rssi_sum), - accum_cck->re_acq_main_rssi_sum, - delta_cck->re_acq_main_rssi_sum, - max_cck->re_acq_main_rssi_sum); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - GENERAL:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_cts:", - le32_to_cpu(general->bogus_cts), - accum_general->bogus_cts, delta_general->bogus_cts, - max_general->bogus_cts); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bogus_ack:", - le32_to_cpu(general->bogus_ack), - accum_general->bogus_ack, delta_general->bogus_ack, - max_general->bogus_ack); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_bssid_frames:", - le32_to_cpu(general->non_bssid_frames), - accum_general->non_bssid_frames, - delta_general->non_bssid_frames, - max_general->non_bssid_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "filtered_frames:", - le32_to_cpu(general->filtered_frames), - accum_general->filtered_frames, - delta_general->filtered_frames, - max_general->filtered_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "non_channel_beacons:", - le32_to_cpu(general->non_channel_beacons), - accum_general->non_channel_beacons, - delta_general->non_channel_beacons, - max_general->non_channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_beacons:", - le32_to_cpu(general->channel_beacons), - accum_general->channel_beacons, - delta_general->channel_beacons, - max_general->channel_beacons); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_missed_bcon:", - le32_to_cpu(general->num_missed_bcon), - accum_general->num_missed_bcon, - delta_general->num_missed_bcon, - max_general->num_missed_bcon); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "adc_rx_saturation_time:", - le32_to_cpu(general->adc_rx_saturation_time), - accum_general->adc_rx_saturation_time, - delta_general->adc_rx_saturation_time, - max_general->adc_rx_saturation_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ina_detect_search_tm:", - le32_to_cpu(general->ina_detection_search_time), - accum_general->ina_detection_search_time, - delta_general->ina_detection_search_time, - max_general->ina_detection_search_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_a:", - le32_to_cpu(general->beacon_silence_rssi_a), - accum_general->beacon_silence_rssi_a, - delta_general->beacon_silence_rssi_a, - max_general->beacon_silence_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_b:", - le32_to_cpu(general->beacon_silence_rssi_b), - accum_general->beacon_silence_rssi_b, - delta_general->beacon_silence_rssi_b, - max_general->beacon_silence_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_silence_rssi_c:", - le32_to_cpu(general->beacon_silence_rssi_c), - accum_general->beacon_silence_rssi_c, - delta_general->beacon_silence_rssi_c, - max_general->beacon_silence_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "interference_data_flag:", - le32_to_cpu(general->interference_data_flag), - accum_general->interference_data_flag, - delta_general->interference_data_flag, - max_general->interference_data_flag); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "channel_load:", - le32_to_cpu(general->channel_load), - accum_general->channel_load, - delta_general->channel_load, - max_general->channel_load); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dsp_false_alarms:", - le32_to_cpu(general->dsp_false_alarms), - accum_general->dsp_false_alarms, - delta_general->dsp_false_alarms, - max_general->dsp_false_alarms); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_a:", - le32_to_cpu(general->beacon_rssi_a), - accum_general->beacon_rssi_a, - delta_general->beacon_rssi_a, - max_general->beacon_rssi_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_b:", - le32_to_cpu(general->beacon_rssi_b), - accum_general->beacon_rssi_b, - delta_general->beacon_rssi_b, - max_general->beacon_rssi_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_rssi_c:", - le32_to_cpu(general->beacon_rssi_c), - accum_general->beacon_rssi_c, - delta_general->beacon_rssi_c, - max_general->beacon_rssi_c); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_a:", - le32_to_cpu(general->beacon_energy_a), - accum_general->beacon_energy_a, - delta_general->beacon_energy_a, - max_general->beacon_energy_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_b:", - le32_to_cpu(general->beacon_energy_b), - accum_general->beacon_energy_b, - delta_general->beacon_energy_b, - max_general->beacon_energy_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "beacon_energy_c:", - le32_to_cpu(general->beacon_energy_c), - accum_general->beacon_energy_c, - delta_general->beacon_energy_c, - max_general->beacon_energy_c); - - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Rx - OFDM_HT:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "plcp_err:", - le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, - delta_ht->plcp_err, max_ht->plcp_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "overrun_err:", - le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, - delta_ht->overrun_err, max_ht->overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "early_overrun_err:", - le32_to_cpu(ht->early_overrun_err), - accum_ht->early_overrun_err, - delta_ht->early_overrun_err, - max_ht->early_overrun_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_good:", - le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, - delta_ht->crc32_good, max_ht->crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "crc32_err:", - le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, - delta_ht->crc32_err, max_ht->crc32_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "mh_format_err:", - le32_to_cpu(ht->mh_format_err), - accum_ht->mh_format_err, - delta_ht->mh_format_err, max_ht->mh_format_err); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_crc32_good:", - le32_to_cpu(ht->agg_crc32_good), - accum_ht->agg_crc32_good, - delta_ht->agg_crc32_good, max_ht->agg_crc32_good); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_mpdu_cnt:", - le32_to_cpu(ht->agg_mpdu_cnt), - accum_ht->agg_mpdu_cnt, - delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg_cnt:", - le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, - delta_ht->agg_cnt, max_ht->agg_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "unsupport_mcs:", - le32_to_cpu(ht->unsupport_mcs), - accum_ht->unsupport_mcs, - delta_ht->unsupport_mcs, max_ht->unsupport_mcs); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_tx_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_tx) * 48) + 250; - ssize_t ret; - struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - tx = &priv->statistics.tx; - accum_tx = &priv->accum_stats.tx; - delta_tx = &priv->delta_stats.tx; - max_tx = &priv->max_delta_stats.tx; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_Tx:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "preamble:", - le32_to_cpu(tx->preamble_cnt), - accum_tx->preamble_cnt, - delta_tx->preamble_cnt, max_tx->preamble_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_detected_cnt:", - le32_to_cpu(tx->rx_detected_cnt), - accum_tx->rx_detected_cnt, - delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_defer_cnt:", - le32_to_cpu(tx->bt_prio_defer_cnt), - accum_tx->bt_prio_defer_cnt, - delta_tx->bt_prio_defer_cnt, - max_tx->bt_prio_defer_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "bt_prio_kill_cnt:", - le32_to_cpu(tx->bt_prio_kill_cnt), - accum_tx->bt_prio_kill_cnt, - delta_tx->bt_prio_kill_cnt, - max_tx->bt_prio_kill_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "few_bytes_cnt:", - le32_to_cpu(tx->few_bytes_cnt), - accum_tx->few_bytes_cnt, - delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout:", - le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, - delta_tx->cts_timeout, max_tx->cts_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_timeout:", - le32_to_cpu(tx->ack_timeout), - accum_tx->ack_timeout, - delta_tx->ack_timeout, max_tx->ack_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "expected_ack_cnt:", - le32_to_cpu(tx->expected_ack_cnt), - accum_tx->expected_ack_cnt, - delta_tx->expected_ack_cnt, - max_tx->expected_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "actual_ack_cnt:", - le32_to_cpu(tx->actual_ack_cnt), - accum_tx->actual_ack_cnt, - delta_tx->actual_ack_cnt, - max_tx->actual_ack_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "dump_msdu_cnt:", - le32_to_cpu(tx->dump_msdu_cnt), - accum_tx->dump_msdu_cnt, - delta_tx->dump_msdu_cnt, - max_tx->dump_msdu_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_nxt_frame_mismatch:", - le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), - accum_tx->burst_abort_next_frame_mismatch_cnt, - delta_tx->burst_abort_next_frame_mismatch_cnt, - max_tx->burst_abort_next_frame_mismatch_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "abort_missing_nxt_frame:", - le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), - accum_tx->burst_abort_missing_next_frame_cnt, - delta_tx->burst_abort_missing_next_frame_cnt, - max_tx->burst_abort_missing_next_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "cts_timeout_collision:", - le32_to_cpu(tx->cts_timeout_collision), - accum_tx->cts_timeout_collision, - delta_tx->cts_timeout_collision, - max_tx->cts_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "ack_ba_timeout_collision:", - le32_to_cpu(tx->ack_or_ba_timeout_collision), - accum_tx->ack_or_ba_timeout_collision, - delta_tx->ack_or_ba_timeout_collision, - max_tx->ack_or_ba_timeout_collision); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_timeout:", - le32_to_cpu(tx->agg.ba_timeout), - accum_tx->agg.ba_timeout, - delta_tx->agg.ba_timeout, - max_tx->agg.ba_timeout); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg ba_resched_frames:", - le32_to_cpu(tx->agg.ba_reschedule_frames), - accum_tx->agg.ba_reschedule_frames, - delta_tx->agg.ba_reschedule_frames, - max_tx->agg.ba_reschedule_frames); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg_frame:", - le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), - accum_tx->agg.scd_query_agg_frame_cnt, - delta_tx->agg.scd_query_agg_frame_cnt, - max_tx->agg.scd_query_agg_frame_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_no_agg:", - le32_to_cpu(tx->agg.scd_query_no_agg), - accum_tx->agg.scd_query_no_agg, - delta_tx->agg.scd_query_no_agg, - max_tx->agg.scd_query_no_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_agg:", - le32_to_cpu(tx->agg.scd_query_agg), - accum_tx->agg.scd_query_agg, - delta_tx->agg.scd_query_agg, - max_tx->agg.scd_query_agg); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg scd_query_mismatch:", - le32_to_cpu(tx->agg.scd_query_mismatch), - accum_tx->agg.scd_query_mismatch, - delta_tx->agg.scd_query_mismatch, - max_tx->agg.scd_query_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg frame_not_ready:", - le32_to_cpu(tx->agg.frame_not_ready), - accum_tx->agg.frame_not_ready, - delta_tx->agg.frame_not_ready, - max_tx->agg.frame_not_ready); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg underrun:", - le32_to_cpu(tx->agg.underrun), - accum_tx->agg.underrun, - delta_tx->agg.underrun, max_tx->agg.underrun); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg bt_prio_kill:", - le32_to_cpu(tx->agg.bt_prio_kill), - accum_tx->agg.bt_prio_kill, - delta_tx->agg.bt_prio_kill, - max_tx->agg.bt_prio_kill); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "agg rx_ba_rsp_cnt:", - le32_to_cpu(tx->agg.rx_ba_rsp_cnt), - accum_tx->agg.rx_ba_rsp_cnt, - delta_tx->agg.rx_ba_rsp_cnt, - max_tx->agg.rx_ba_rsp_cnt); - - if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { - pos += scnprintf(buf + pos, bufsz - pos, - "tx power: (1/2 dB step)\n"); - if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna A:", - tx->tx_power.ant_a); - if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna B:", - tx->tx_power.ant_b); - if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) - pos += scnprintf(buf + pos, bufsz - pos, - fmt_hex, "antenna C:", - tx->tx_power.ant_c); - } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - int pos = 0; - char *buf; - int bufsz = sizeof(struct statistics_general) * 10 + 300; - ssize_t ret; - struct statistics_general_common *general, *accum_general; - struct statistics_general_common *delta_general, *max_general; - struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; - struct statistics_div *div, *accum_div, *delta_div, *max_div; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - general = &priv->statistics.common; - dbg = &priv->statistics.common.dbg; - div = &priv->statistics.common.div; - accum_general = &priv->accum_stats.common; - accum_dbg = &priv->accum_stats.common.dbg; - accum_div = &priv->accum_stats.common.div; - delta_general = &priv->delta_stats.common; - max_general = &priv->max_delta_stats.common; - delta_dbg = &priv->delta_stats.common.dbg; - max_dbg = &priv->max_delta_stats.common.dbg; - delta_div = &priv->delta_stats.common.div; - max_div = &priv->max_delta_stats.common.div; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_header, "Statistics_General:"); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature:", - le32_to_cpu(general->temperature)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "temperature_m:", - le32_to_cpu(general->temperature_m)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_value, "ttl_timestamp:", - le32_to_cpu(general->ttl_timestamp)); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_check:", - le32_to_cpu(dbg->burst_check), - accum_dbg->burst_check, - delta_dbg->burst_check, max_dbg->burst_check); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "burst_count:", - le32_to_cpu(dbg->burst_count), - accum_dbg->burst_count, - delta_dbg->burst_count, max_dbg->burst_count); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "wait_for_silence_timeout_count:", - le32_to_cpu(dbg->wait_for_silence_timeout_cnt), - accum_dbg->wait_for_silence_timeout_cnt, - delta_dbg->wait_for_silence_timeout_cnt, - max_dbg->wait_for_silence_timeout_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "sleep_time:", - le32_to_cpu(general->sleep_time), - accum_general->sleep_time, - delta_general->sleep_time, max_general->sleep_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_out:", - le32_to_cpu(general->slots_out), - accum_general->slots_out, - delta_general->slots_out, max_general->slots_out); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "slots_idle:", - le32_to_cpu(general->slots_idle), - accum_general->slots_idle, - delta_general->slots_idle, max_general->slots_idle); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_a:", - le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, - delta_div->tx_on_a, max_div->tx_on_a); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "tx_on_b:", - le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, - delta_div->tx_on_b, max_div->tx_on_b); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "exec_time:", - le32_to_cpu(div->exec_time), accum_div->exec_time, - delta_div->exec_time, max_div->exec_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "probe_time:", - le32_to_cpu(div->probe_time), accum_div->probe_time, - delta_div->probe_time, max_div->probe_time); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "rx_enable_counter:", - le32_to_cpu(general->rx_enable_counter), - accum_general->rx_enable_counter, - delta_general->rx_enable_counter, - max_general->rx_enable_counter); - pos += scnprintf(buf + pos, bufsz - pos, - fmt_table, "num_of_sos_states:", - le32_to_cpu(general->num_of_sos_states), - accum_general->num_of_sos_states, - delta_general->num_of_sos_states, - max_general->num_of_sos_states); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; - ssize_t ret; - struct statistics_bt_activity *bt, *accum_bt; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - if (!priv->bt_enable_flag) - return -EINVAL; - - /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); - ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); - - if (ret) { - IWL_ERR(priv, - "Error sending statistics request: %zd\n", ret); - return -EAGAIN; - } - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - /* - * the statistic information display here is based on - * the last statistics notification from uCode - * might not reflect the current uCode activity - */ - bt = &priv->statistics.bt_activity; - accum_bt = &priv->accum_stats.bt_activity; - - pos += iwl_statistics_flag(priv, buf, bufsz); - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\t\t\tcurrent\t\t\taccumulative\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_req_cnt), - accum_bt->hi_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_tx_denied_cnt), - accum_bt->hi_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_req_cnt), - accum_bt->lo_priority_tx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_tx_denied_cnt), - accum_bt->lo_priority_tx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_req_cnt), - accum_bt->hi_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->hi_priority_rx_denied_cnt), - accum_bt->hi_priority_rx_denied_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_req_cnt), - accum_bt->lo_priority_rx_req_cnt); - pos += scnprintf(buf + pos, bufsz - pos, - "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", - le32_to_cpu(bt->lo_priority_rx_denied_cnt), - accum_bt->lo_priority_rx_denied_cnt); - - pos += scnprintf(buf + pos, bufsz - pos, - "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", - le32_to_cpu(priv->statistics.num_bt_kills), - priv->statistics.accum_num_bt_kills); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -ssize_t iwl_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - int pos = 0; - char *buf; - int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + - (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; - ssize_t ret; - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) { - IWL_ERR(priv, "Can not allocate Buffer\n"); - return -ENOMEM; - } - - pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), - priv->_agn.reply_tx_stats.pp_few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), - priv->_agn.reply_tx_stats.pp_bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), - priv->_agn.reply_tx_stats.pp_quiet_period); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), - priv->_agn.reply_tx_stats.pp_calc_ttak); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), - priv->_agn.reply_tx_stats.int_crossed_retry); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), - priv->_agn.reply_tx_stats.short_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), - priv->_agn.reply_tx_stats.long_limit); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), - priv->_agn.reply_tx_stats.fifo_underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), - priv->_agn.reply_tx_stats.drain_flow); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), - priv->_agn.reply_tx_stats.rfkill_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), - priv->_agn.reply_tx_stats.life_expire); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), - priv->_agn.reply_tx_stats.dest_ps); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), - priv->_agn.reply_tx_stats.host_abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), - priv->_agn.reply_tx_stats.pp_delay); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), - priv->_agn.reply_tx_stats.sta_invalid); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), - priv->_agn.reply_tx_stats.frag_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), - priv->_agn.reply_tx_stats.tid_disable); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), - priv->_agn.reply_tx_stats.fifo_flush); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), - priv->_agn.reply_tx_stats.insuff_cf_poll); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), - priv->_agn.reply_tx_stats.fail_hw_drop); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_tx_fail_reason( - TX_STATUS_FAIL_NO_BEACON_ON_RADAR), - priv->_agn.reply_tx_stats.sta_color_mismatch); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_tx_stats.unknown); - - pos += scnprintf(buf + pos, bufsz - pos, - "\nStatistics_Agg_TX_Error:\n"); - - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), - priv->_agn.reply_agg_tx_stats.underrun); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), - priv->_agn.reply_agg_tx_stats.bt_prio); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), - priv->_agn.reply_agg_tx_stats.few_bytes); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), - priv->_agn.reply_agg_tx_stats.abort); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TTL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_ttl); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_try); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), - priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), - priv->_agn.reply_agg_tx_stats.scd_query); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", - iwl_get_agg_tx_fail_reason( - AGG_TX_STATE_TEST_BAD_CRC32_MSK), - priv->_agn.reply_agg_tx_stats.bad_crc32); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), - priv->_agn.reply_agg_tx_stats.response); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), - priv->_agn.reply_agg_tx_stats.dump_tx); - pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", - iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), - priv->_agn.reply_agg_tx_stats.delay_tx); - pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", - priv->_agn.reply_agg_tx_stats.unknown); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h deleted file mode 100644 index 9a3f329..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h +++ /dev/null @@ -1,70 +0,0 @@ -/****************************************************************************** - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - *****************************************************************************/ - -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-debug.h" - -#ifdef CONFIG_IWLWIFI_DEBUGFS -ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -#else -static ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_ucode_bt_stats_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -static ssize_t iwl_reply_tx_error_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - return 0; -} -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c index 3bcaa10..2ef9448 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c @@ -81,52 +81,13 @@ * ******************************************************************************/ -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) -{ - u16 count; - int ret; - - for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - /* Request semaphore */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - EEPROM_SEM_TIMEOUT); - if (ret >= 0) { - IWL_DEBUG_EEPROM(priv, - "Acquired semaphore after %d tries.\n", - count+1); - return ret; - } - } - - return ret; -} - -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv) -{ - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - -} - int iwl_eeprom_check_version(struct iwl_priv *priv) { u16 eeprom_ver; u16 calib_ver; eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + calib_ver = iwlagn_eeprom_calib_version(priv); if (eeprom_ver < priv->cfg->eeprom_ver || calib_ver < priv->cfg->eeprom_calib_ver) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c index 861cc93..49dd03f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c @@ -37,54 +37,6 @@ #include "iwl-io.h" #include "iwl-agn.h" -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int ret = 0; - struct iwl5000_rxon_assoc_cmd rxon_assoc; - const struct iwl_rxon_cmd *rxon1 = &ctx->staging; - const struct iwl_rxon_cmd *rxon2 = &ctx->active; - - if ((rxon1->flags == rxon2->flags) && - (rxon1->filter_flags == rxon2->filter_flags) && - (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && - (rxon1->ofdm_ht_single_stream_basic_rates == - rxon2->ofdm_ht_single_stream_basic_rates) && - (rxon1->ofdm_ht_dual_stream_basic_rates == - rxon2->ofdm_ht_dual_stream_basic_rates) && - (rxon1->ofdm_ht_triple_stream_basic_rates == - rxon2->ofdm_ht_triple_stream_basic_rates) && - (rxon1->acquisition_data == rxon2->acquisition_data) && - (rxon1->rx_chain == rxon2->rx_chain) && - (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { - IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); - return 0; - } - - rxon_assoc.flags = ctx->staging.flags; - rxon_assoc.filter_flags = ctx->staging.filter_flags; - rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; - rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; - rxon_assoc.reserved1 = 0; - rxon_assoc.reserved2 = 0; - rxon_assoc.reserved3 = 0; - rxon_assoc.ofdm_ht_single_stream_basic_rates = - ctx->staging.ofdm_ht_single_stream_basic_rates; - rxon_assoc.ofdm_ht_dual_stream_basic_rates = - ctx->staging.ofdm_ht_dual_stream_basic_rates; - rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; - rxon_assoc.ofdm_ht_triple_stream_basic_rates = - ctx->staging.ofdm_ht_triple_stream_basic_rates; - rxon_assoc.acquisition_data = ctx->staging.acquisition_data; - - ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, - sizeof(rxon_assoc), &rxon_assoc, NULL); - if (ret) - return ret; - - return ret; -} - int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) { struct iwl_tx_ant_config_cmd tx_ant_cmd = { @@ -364,7 +316,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv) } struct iwl_hcmd_ops iwlagn_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, @@ -373,7 +324,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = { }; struct iwl_hcmd_ops iwlagn_bt_hcmd = { - .rxon_assoc = iwlagn_send_rxon_assoc, .commit_rxon = iwlagn_commit_rxon, .set_rxon_chain = iwlagn_set_rxon_chain, .set_tx_ant = iwlagn_send_tx_ant_config, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index e741128..8e79653 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -483,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv) /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = iwlagn_rx_calib_result; - priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = - iwlagn_rx_calib_complete; priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; /* set up notification wait support */ @@ -667,7 +665,7 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) rb_timeout = RX_RB_TIMEOUT; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; else rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; @@ -1296,9 +1294,17 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) * mean we never reach it, but at the same time work around * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. */ - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_NEVER; + if (priv->new_scan_threshold_behaviour) + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_DISABLED; + else + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_NEVER; band = priv->scan_band; @@ -2256,34 +2262,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) /* notification wait support */ void iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, + u8 cmd, void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt), - u8 cmd) + struct iwl_rx_packet *pkt, + void *data), + void *fn_data) { wait_entry->fn = fn; + wait_entry->fn_data = fn_data; wait_entry->cmd = cmd; wait_entry->triggered = false; + wait_entry->aborted = false; spin_lock_bh(&priv->_agn.notif_wait_lock); list_add(&wait_entry->list, &priv->_agn.notif_waits); spin_unlock_bh(&priv->_agn.notif_wait_lock); } -signed long iwlagn_wait_notification(struct iwl_priv *priv, - struct iwl_notification_wait *wait_entry, - unsigned long timeout) +int iwlagn_wait_notification(struct iwl_priv *priv, + struct iwl_notification_wait *wait_entry, + unsigned long timeout) { int ret; ret = wait_event_timeout(priv->_agn.notif_waitq, - wait_entry->triggered, + wait_entry->triggered || wait_entry->aborted, timeout); spin_lock_bh(&priv->_agn.notif_wait_lock); list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); - return ret; + if (wait_entry->aborted) + return -EIO; + + /* return value is always >= 0 */ + if (ret <= 0) + return -ETIMEDOUT; + return 0; } void iwlagn_remove_notification(struct iwl_priv *priv, @@ -2293,3 +2309,87 @@ void iwlagn_remove_notification(struct iwl_priv *priv, list_del(&wait_entry->list); spin_unlock_bh(&priv->_agn.notif_wait_lock); } + +int iwlagn_start_device(struct iwl_priv *priv) +{ + int ret; + + if (iwl_prepare_card_hw(priv)) { + IWL_WARN(priv, "Exit HW not ready\n"); + return -EIO; + } + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &priv->status); + else + set_bit(STATUS_RF_KILL_HW, &priv->status); + + if (iwl_is_rfkill(priv)) { + wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); + iwl_enable_interrupts(priv); + return -ERFKILL; + } + + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + + ret = iwlagn_hw_nic_init(priv); + if (ret) { + IWL_ERR(priv, "Unable to init nic\n"); + return ret; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(priv); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + return 0; +} + +void iwlagn_stop_device(struct iwl_priv *priv) +{ + unsigned long flags; + + /* stop and reset the on-board processor */ + iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + spin_lock_irqsave(&priv->lock, flags); + iwl_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + iwl_synchronize_irq(priv); + + /* device going down, Stop using ICT table */ + iwl_disable_ict(priv); + + /* + * If a HW restart happens during firmware loading, + * then the firmware loading might call this function + * and later it might be called again due to the + * restart. So don't process again if the device is + * already dead. + */ + if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) { + iwlagn_txq_ctx_stop(priv); + iwlagn_rxq_stop(priv); + + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); + udelay(5); + } + + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* Stop the device, and put it in low power state */ + iwl_apm_stop(priv); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 90e12c1..0238743 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -58,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, u8 old_dev_type = send->dev_type; int ret; - iwlagn_init_notification_wait(priv, &disable_wait, NULL, - REPLY_WIPAN_DEACTIVATION_COMPLETE); + iwlagn_init_notification_wait(priv, &disable_wait, + REPLY_WIPAN_DEACTIVATION_COMPLETE, + NULL, NULL); send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; send->dev_type = RXON_DEV_TYPE_P2P; @@ -72,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); iwlagn_remove_notification(priv, &disable_wait); } else { - signed long wait_res; - - wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ); - if (wait_res == 0) { + ret = iwlagn_wait_notification(priv, &disable_wait, HZ); + if (ret) IWL_ERR(priv, "Timed out waiting for PAN disable\n"); - ret = -EIO; - } } return ret; @@ -124,6 +121,151 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, return iwlagn_send_beacon_cmd(priv); } +static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret = 0; + struct iwl_rxon_assoc_cmd rxon_assoc; + const struct iwl_rxon_cmd *rxon1 = &ctx->staging; + const struct iwl_rxon_cmd *rxon2 = &ctx->active; + + if ((rxon1->flags == rxon2->flags) && + (rxon1->filter_flags == rxon2->filter_flags) && + (rxon1->cck_basic_rates == rxon2->cck_basic_rates) && + (rxon1->ofdm_ht_single_stream_basic_rates == + rxon2->ofdm_ht_single_stream_basic_rates) && + (rxon1->ofdm_ht_dual_stream_basic_rates == + rxon2->ofdm_ht_dual_stream_basic_rates) && + (rxon1->ofdm_ht_triple_stream_basic_rates == + rxon2->ofdm_ht_triple_stream_basic_rates) && + (rxon1->acquisition_data == rxon2->acquisition_data) && + (rxon1->rx_chain == rxon2->rx_chain) && + (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) { + IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n"); + return 0; + } + + rxon_assoc.flags = ctx->staging.flags; + rxon_assoc.filter_flags = ctx->staging.filter_flags; + rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates; + rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates; + rxon_assoc.reserved1 = 0; + rxon_assoc.reserved2 = 0; + rxon_assoc.reserved3 = 0; + rxon_assoc.ofdm_ht_single_stream_basic_rates = + ctx->staging.ofdm_ht_single_stream_basic_rates; + rxon_assoc.ofdm_ht_dual_stream_basic_rates = + ctx->staging.ofdm_ht_dual_stream_basic_rates; + rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain; + rxon_assoc.ofdm_ht_triple_stream_basic_rates = + ctx->staging.ofdm_ht_triple_stream_basic_rates; + rxon_assoc.acquisition_data = ctx->staging.acquisition_data; + + ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd, + sizeof(rxon_assoc), &rxon_assoc, NULL); + if (ret) + return ret; + + return ret; +} + +static int iwlagn_rxon_disconn(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + if (ctx->ctxid == IWL_RXON_CTX_BSS) + ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); + else + ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + if (ret) + return ret; + + /* + * Un-assoc RXON clears the station table and WEP + * keys, so we have to restore those afterwards. + */ + iwl_clear_ucode_stations(priv, ctx); + iwl_restore_stations(priv, ctx); + ret = iwl_restore_default_wep_keys(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); + return ret; + } + + memcpy(active, &ctx->staging, sizeof(*active)); + return 0; +} + +static int iwlagn_rxon_connect(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int ret; + struct iwl_rxon_cmd *active = (void *)&ctx->active; + + /* RXON timing must be before associated RXON */ + ret = iwl_send_rxon_timing(priv, ctx); + if (ret) { + IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); + return ret; + } + /* QoS info may be cleared by previous un-assoc RXON */ + iwlagn_update_qos(priv, ctx); + + /* + * We'll run into this code path when beaconing is + * enabled, but then we also need to send the beacon + * to the device. + */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { + ret = iwlagn_update_beacon(priv, ctx->vif); + if (ret) { + IWL_ERR(priv, + "Error sending required beacon (%d)!\n", + ret); + return ret; + } + } + + priv->start_calib = 0; + /* + * Apply the new configuration. + * + * Associated RXON doesn't clear the station table in uCode, + * so we don't need to restore stations etc. after this. + */ + ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, + sizeof(struct iwl_rxon_cmd), &ctx->staging); + if (ret) { + IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); + return ret; + } + memcpy(active, &ctx->staging, sizeof(*active)); + + iwl_reprogram_ap_sta(priv, ctx); + + /* IBSS beacon needs to be sent after setting assoc */ + if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) + if (iwlagn_update_beacon(priv, ctx->vif)) + IWL_ERR(priv, "Error sending IBSS beacon\n"); + iwl_init_sensitivity(priv); + + /* + * If we issue a new RXON command which required a tune then + * we must send a new TXPOWER command or we won't be able to + * Tx any frames. + * + * It's expected we set power here if channel is changing. + */ + ret = iwl_set_tx_power(priv, priv->tx_power_next, true); + if (ret) { + IWL_ERR(priv, "Error sending TX power (%d)\n", ret); + return ret; + } + return 0; +} + /** * iwlagn_commit_rxon - commit staging_rxon to hardware * @@ -131,6 +273,16 @@ static int iwlagn_update_beacon(struct iwl_priv *priv, * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. + * + * The connect/disconnect flow should be as the following: + * + * 1. make sure send RXON command with association bit unset if not connect + * this should include the channel and the band for the candidate + * to be connected to + * 2. Add Station before RXON association with the AP + * 3. RXON_timing has to send before RXON for connection + * 4. full RXON command - associated bit set + * 5. use RXON_ASSOC command to update any flags changes */ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { @@ -180,6 +332,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; + iwl_print_rx_config_cmd(priv, ctx); ret = iwl_check_rxon_cmd(priv, ctx); if (ret) { IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); @@ -203,14 +356,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv, ctx)) { - ret = iwl_send_rxon_assoc(priv, ctx); + ret = iwlagn_send_rxon_assoc(priv, ctx); if (ret) { IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret); return ret; } memcpy(active, &ctx->staging, sizeof(*active)); - iwl_print_rx_config_cmd(priv, ctx); return 0; } @@ -220,7 +372,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return ret; } - iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto); + iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto); IWL_DEBUG_INFO(priv, "Going to commit RXON\n" @@ -238,92 +390,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * set up filters in the device. */ if ((old_assoc && new_assoc) || !new_assoc) { - if (ctx->ctxid == IWL_RXON_CTX_BSS) - ret = iwlagn_disable_bss(priv, ctx, &ctx->staging); - else - ret = iwlagn_disable_pan(priv, ctx, &ctx->staging); + ret = iwlagn_rxon_disconn(priv, ctx); if (ret) return ret; - - memcpy(active, &ctx->staging, sizeof(*active)); - - /* - * Un-assoc RXON clears the station table and WEP - * keys, so we have to restore those afterwards. - */ - iwl_clear_ucode_stations(priv, ctx); - iwl_restore_stations(priv, ctx); - ret = iwl_restore_default_wep_keys(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret); - return ret; - } - } - - /* RXON timing must be before associated RXON */ - ret = iwl_send_rxon_timing(priv, ctx); - if (ret) { - IWL_ERR(priv, "Failed to send timing (%d)!\n", ret); - return ret; - } - - if (new_assoc) { - /* QoS info may be cleared by previous un-assoc RXON */ - iwlagn_update_qos(priv, ctx); - - /* - * We'll run into this code path when beaconing is - * enabled, but then we also need to send the beacon - * to the device. - */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) { - ret = iwlagn_update_beacon(priv, ctx->vif); - if (ret) { - IWL_ERR(priv, - "Error sending required beacon (%d)!\n", - ret); - return ret; - } - } - - priv->start_calib = 0; - /* - * Apply the new configuration. - * - * Associated RXON doesn't clear the station table in uCode, - * so we don't need to restore stations etc. after this. - */ - ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, - sizeof(struct iwl_rxon_cmd), &ctx->staging); - if (ret) { - IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); - return ret; - } - memcpy(active, &ctx->staging, sizeof(*active)); - - iwl_reprogram_ap_sta(priv, ctx); - - /* IBSS beacon needs to be sent after setting assoc */ - if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC)) - if (iwlagn_update_beacon(priv, ctx->vif)) - IWL_ERR(priv, "Error sending IBSS beacon\n"); } - iwl_print_rx_config_cmd(priv, ctx); - - iwl_init_sensitivity(priv); - - /* - * If we issue a new RXON command which required a tune then we must - * send a new TXPOWER command or we won't be able to Tx any frames. - * - * It's expected we set power here if channel is changing. - */ - ret = iwl_set_tx_power(priv, priv->tx_power_next, true); - if (ret) { - IWL_ERR(priv, "Error sending TX power (%d)\n", ret); - return ret; - } + if (new_assoc) + return iwlagn_rxon_connect(priv, ctx); return 0; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 5c30f6b..c3ae2e4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, } static int iwlagn_load_given_ucode(struct iwl_priv *priv, - struct fw_desc *inst_image, - struct fw_desc *data_image) + struct fw_img *image) { int ret = 0; - ret = iwlagn_load_section(priv, "INST", inst_image, + ret = iwlagn_load_section(priv, "INST", &image->code, IWLAGN_RTC_INST_LOWER_BOUND); if (ret) return ret; - return iwlagn_load_section(priv, "DATA", data_image, + return iwlagn_load_section(priv, "DATA", &image->data, IWLAGN_RTC_DATA_LOWER_BOUND); } -int iwlagn_load_ucode(struct iwl_priv *priv) -{ - int ret = 0; - - /* check whether init ucode should be loaded, or rather runtime ucode */ - if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) { - IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_init, &priv->ucode_init_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Init ucode load complete.\n"); - priv->ucode_type = UCODE_INIT; - } - } else { - IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. " - "Loading runtime ucode...\n"); - ret = iwlagn_load_given_ucode(priv, - &priv->ucode_code, &priv->ucode_data); - if (!ret) { - IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n"); - priv->ucode_type = UCODE_RT; - } - } - - return ret; -} - /* * Calibration */ @@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); } -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_init_alive_start(struct iwl_priv *priv) { - IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n"); - queue_work(priv->workqueue, &priv->restart); -} - -void iwlagn_init_alive_start(struct iwl_priv *priv) -{ - int ret = 0; - - /* initialize uCode was loaded... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv, &priv->ucode_init)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n"); - goto restart; - } - - ret = iwlagn_alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition: %d\n", ret); - goto restart; - } + int ret; if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { @@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv) * no need to close the envlope since we are going * to load the runtime uCode later. */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } - iwlagn_send_calib_cfg(priv); + + ret = iwlagn_send_calib_cfg(priv); + if (ret) + return ret; /** * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ if (priv->cfg->need_temp_offset_calib) - iwlagn_set_temperature_offset_calib(priv); - - return; + return iwlagn_set_temperature_offset_calib(priv); -restart: - /* real restart (first load init_ucode) */ - queue_work(priv->workqueue, &priv->restart); + return 0; } static int iwlagn_send_wimax_coex(struct iwl_priv *priv) @@ -413,19 +362,22 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv) IWL_ERR(priv, "failed to send BT prio tbl command\n"); } -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) { struct iwl_bt_coex_prot_env_cmd env_cmd; + int ret; env_cmd.action = action; env_cmd.type = type; - if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, - sizeof(env_cmd), &env_cmd)) + ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV, + sizeof(env_cmd), &env_cmd); + if (ret) IWL_ERR(priv, "failed to send BT env command\n"); + return ret; } -int iwlagn_alive_notify(struct iwl_priv *priv) +static int iwlagn_alive_notify(struct iwl_priv *priv) { const struct queue_to_fifo_ac *queue_to_fifo; struct iwl_rxon_context *ctx; @@ -604,15 +556,164 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, * iwl_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc) +static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) { - if (!iwlcore_verify_inst_sparse(priv, fw_desc)) { + if (!iwlcore_verify_inst_sparse(priv, &img->code)) { IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n"); return 0; } IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n"); - iwl_print_mismatch_inst(priv, fw_desc); + iwl_print_mismatch_inst(priv, &img->code); return -EIO; } + +struct iwlagn_alive_data { + bool valid; + u8 subtype; +}; + +static void iwlagn_alive_fn(struct iwl_priv *priv, + struct iwl_rx_packet *pkt, + void *data) +{ + struct iwlagn_alive_data *alive_data = data; + struct iwl_alive_resp *palive; + + palive = &pkt->u.alive_frame; + + IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " + "0x%01X 0x%01X\n", + palive->is_valid, palive->ver_type, + palive->ver_subtype); + + priv->device_pointers.error_event_table = + le32_to_cpu(palive->error_event_table_ptr); + priv->device_pointers.log_event_table = + le32_to_cpu(palive->log_event_table_ptr); + + alive_data->subtype = palive->ver_subtype; + alive_data->valid = palive->is_valid == UCODE_VALID_OK; +} + +#define UCODE_ALIVE_TIMEOUT HZ +#define UCODE_CALIB_TIMEOUT (2*HZ) + +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_img *image, + int subtype, int alternate_subtype) +{ + struct iwl_notification_wait alive_wait; + struct iwlagn_alive_data alive_data; + int ret; + enum iwlagn_ucode_subtype old_type; + + ret = iwlagn_start_device(priv); + if (ret) + return ret; + + iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE, + iwlagn_alive_fn, &alive_data); + + old_type = priv->ucode_type; + priv->ucode_type = subtype; + + ret = iwlagn_load_given_ucode(priv, image); + if (ret) { + priv->ucode_type = old_type; + iwlagn_remove_notification(priv, &alive_wait); + return ret; + } + + /* Remove all resets to allow NIC to operate */ + iwl_write32(priv, CSR_RESET, 0); + + /* + * Some things may run in the background now, but we + * just wait for the ALIVE notification here. + */ + ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT); + if (ret) { + priv->ucode_type = old_type; + return ret; + } + + if (!alive_data.valid) { + IWL_ERR(priv, "Loaded ucode is not valid!\n"); + priv->ucode_type = old_type; + return -EIO; + } + + if (alive_data.subtype != subtype && + alive_data.subtype != alternate_subtype) { + IWL_ERR(priv, + "Loaded ucode is not expected type (got %d, expected %d)!\n", + alive_data.subtype, subtype); + priv->ucode_type = old_type; + return -EIO; + } + + ret = iwl_verify_ucode(priv, image); + if (ret) { + priv->ucode_type = old_type; + return ret; + } + + /* delay a bit to give rfkill time to run */ + msleep(5); + + ret = iwlagn_alive_notify(priv); + if (ret) { + IWL_WARN(priv, + "Could not complete ALIVE transition: %d\n", ret); + priv->ucode_type = old_type; + return ret; + } + + return 0; +} + +int iwlagn_run_init_ucode(struct iwl_priv *priv) +{ + struct iwl_notification_wait calib_wait; + int ret; + + lockdep_assert_held(&priv->mutex); + + /* No init ucode required? Curious, but maybe ok */ + if (!priv->ucode_init.code.len) + return 0; + + if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED) + return 0; + + iwlagn_init_notification_wait(priv, &calib_wait, + CALIBRATION_COMPLETE_NOTIFICATION, + NULL, NULL); + + /* Will also start the device */ + ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init, + UCODE_SUBTYPE_INIT, -1); + if (ret) + goto error; + + ret = iwlagn_init_alive_start(priv); + if (ret) + goto error; + + /* + * Some things may run in the background now, but we + * just wait for the calibration complete notification. + */ + ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT); + + goto out; + + error: + iwlagn_remove_notification(priv, &calib_wait); + out: + /* Whatever happened, stop the device */ + iwlagn_stop_device(priv); + return ret; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index cdeb09e..003d524 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -769,7 +769,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) if (w->cmd == pkt->hdr.cmd) { w->triggered = true; if (w->fn) - w->fn(priv, pkt); + w->fn(priv, pkt, w->fn_data); } } spin_unlock(&priv->_agn.notif_wait_lock); @@ -846,14 +846,6 @@ static void iwl_rx_handle(struct iwl_priv *priv) iwlagn_rx_queue_restock(priv); } -/* call this function to flush any scheduled tasklet */ -static inline void iwl_synchronize_irq(struct iwl_priv *priv) -{ - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(priv->pci_dev->irq); - tasklet_kill(&priv->irq_tasklet); -} - /* tasklet for iwlagn interrupt */ static void iwl_irq_tasklet(struct iwl_priv *priv) { @@ -1181,18 +1173,42 @@ static struct attribute_group iwl_attribute_group = { * ******************************************************************************/ -static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc) { - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init); - iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data); + if (desc->v_addr) + dma_free_coherent(&pci_dev->dev, desc->len, + desc->v_addr, desc->p_addr); + desc->v_addr = NULL; + desc->len = 0; } -static void iwl_nic_start(struct iwl_priv *priv) +static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img) { - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); + iwl_free_fw_desc(pci_dev, &img->code); + iwl_free_fw_desc(pci_dev, &img->data); +} + +static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc, + const void *data, size_t len) +{ + if (!len) { + desc->v_addr = NULL; + return -EINVAL; + } + + desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len, + &desc->p_addr, GFP_KERNEL); + if (!desc->v_addr) + return -ENOMEM; + desc->len = len; + memcpy(desc->v_addr, data, len); + return 0; +} + +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +{ + iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt); + iwl_free_fw_img(priv->pci_dev, &priv->ucode_init); } struct iwlagn_ucode_capabilities { @@ -1661,24 +1677,20 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) /* Runtime instructions and 2 copies of data: * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ - priv->ucode_code.len = pieces.inst_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); - - priv->ucode_data.len = pieces.data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); - - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code, + pieces.inst, pieces.inst_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data, + pieces.data, pieces.data_size)) goto err_pci_alloc; /* Initialization instructions and data */ if (pieces.init_size && pieces.init_data_size) { - priv->ucode_init.len = pieces.init_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init); - - priv->ucode_init_data.len = pieces.init_data_size; - iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data); - - if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr) + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code, + pieces.init, pieces.init_size)) + goto err_pci_alloc; + if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data, + pieces.init_data, pieces.init_data_size)) goto err_pci_alloc; } @@ -1704,6 +1716,9 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->cfg->base_params->max_event_log_size; priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr; + priv->new_scan_threshold_behaviour = + !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; @@ -1715,39 +1730,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) else priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - /* Copy images into buffers for card's bus-master reads ... */ - - /* Runtime instructions (first block of data in file) */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", - pieces.inst_size); - memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size); - - IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n", - priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); - - /* - * Runtime data - * NOTE: Copy into backup buffer will be done in iwl_up() - */ - IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", - pieces.data_size); - memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size); - - /* Initialization instructions */ - if (pieces.init_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n", - pieces.init_size); - memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size); - } - - /* Initialization data */ - if (pieces.init_data_size) { - IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n", - pieces.init_data_size); - memcpy(priv->ucode_init_data.v_addr, pieces.init_data, - pieces.init_data_size); - } - /* * figure out the offset of chain noise reset and gain commands * base on the size of standard phy calibration commands table size @@ -1878,9 +1860,10 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) u32 desc, time, count, base, data1; u32 blink1, blink2, ilink1, ilink2; u32 pc, hcmd; + struct iwl_error_event_table table; base = priv->device_pointers.error_event_table; - if (priv->ucode_type == UCODE_INIT) { + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_errlog_ptr; } else { @@ -1891,11 +1874,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Not valid error log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return; } - count = iwl_read_targ_mem(priv, base); + iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); + + count = table.valid; if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERR(priv, "Start IWL Error Log Dump:\n"); @@ -1903,18 +1890,18 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) priv->status, count); } - desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32)); + desc = table.error_id; priv->isr_stats.err_code = desc; - pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32)); - blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32)); + pc = table.pc; + blink1 = table.blink1; + blink2 = table.blink2; + ilink1 = table.ilink1; + ilink2 = table.ilink2; + data1 = table.data1; + data2 = table.data2; + line = table.line; + time = table.tsf_low; + hcmd = table.hcmd; trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line, blink1, blink2, ilink1, ilink2); @@ -1949,7 +1936,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, return pos; base = priv->device_pointers.log_event_table; - if (priv->ucode_type == UCODE_INIT) { + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { if (!base) base = priv->_agn.init_evtlog_ptr; } else { @@ -2062,7 +2049,7 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, size_t bufsz = 0; base = priv->device_pointers.log_event_table; - if (priv->ucode_type == UCODE_INIT) { + if (priv->ucode_type == UCODE_SUBTYPE_INIT) { logsize = priv->_agn.init_evtlog_size; if (!base) base = priv->_agn.init_evtlog_ptr; @@ -2075,7 +2062,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) { IWL_ERR(priv, "Invalid event log pointer 0x%08X for %s uCode\n", - base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT"); + base, + (priv->ucode_type == UCODE_SUBTYPE_INIT) + ? "Init" : "RT"); return -EINVAL; } @@ -2222,30 +2211,14 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) * from protocol/runtime uCode (initialization uCode's * Alive gets handled by iwl_init_alive_start()). */ -static void iwl_alive_start(struct iwl_priv *priv) +static int iwl_alive_start(struct iwl_priv *priv) { int ret = 0; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - - /* Initialize uCode has loaded Runtime uCode ... verify inst image. - * This is a paranoid check, because we would not have gotten the - * "runtime" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv, &priv->ucode_code)) { - /* Runtime instruction load was bad; - * take it all the way back down so we can try again */ - IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n"); - goto restart; - } - - ret = iwlagn_alive_notify(priv); - if (ret) { - IWL_WARN(priv, - "Could not complete ALIVE transition [ntf]: %d\n", ret); - goto restart; - } + iwl_reset_ict(priv); + IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); @@ -2254,7 +2227,7 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl_setup_watchdog(priv); if (iwl_is_rfkill(priv)) - return; + return -ERFKILL; /* download priority table before any calibration request */ if (priv->cfg->bt_params && @@ -2268,10 +2241,14 @@ static void iwl_alive_start(struct iwl_priv *priv) iwlagn_send_prio_tbl(priv); /* FIXME: w/a to force change uCode BT state machine */ - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); - iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, - BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; + ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE, + BT_COEX_PRIO_TBL_EVT_INIT_CALIB2); + if (ret) + return ret; } if (priv->hw_params.calib_rt_cfg) iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); @@ -2313,29 +2290,22 @@ static void iwl_alive_start(struct iwl_priv *priv) set_bit(STATUS_READY, &priv->status); /* Configure the adapter for unassociated operation */ - iwlcore_commit_rxon(priv, ctx); + ret = iwlcore_commit_rxon(priv, ctx); + if (ret) + return ret; /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n"); - wake_up_interruptible(&priv->wait_command_queue); - - iwl_power_update_mode(priv, true); - IWL_DEBUG_INFO(priv, "Updated power mode\n"); - - return; - - restart: - queue_work(priv->workqueue, &priv->restart); + return iwl_power_update_mode(priv, true); } static void iwl_cancel_deferred_work(struct iwl_priv *priv); static void __iwl_down(struct iwl_priv *priv) { - unsigned long flags; int exit_pending; IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n"); @@ -2367,32 +2337,10 @@ static void __iwl_down(struct iwl_priv *priv) if (!exit_pending) clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* stop and reset the on-board processor */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - iwl_synchronize_irq(priv); - if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl_init() then - * clear all bits but the RF Kill bit and return */ - if (!iwl_is_init(priv)) { - priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << - STATUS_RF_KILL_HW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << - STATUS_GEO_CONFIGURED | - test_bit(STATUS_EXIT_PENDING, &priv->status) << - STATUS_EXIT_PENDING; - goto exit; - } - - /* ...otherwise clear out all the status bits but the RF Kill - * bit and continue taking the NIC down. */ + /* Clear out all status bits but a few that are stable across reset */ priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << STATUS_RF_KILL_HW | test_bit(STATUS_GEO_CONFIGURED, &priv->status) << @@ -2402,23 +2350,8 @@ static void __iwl_down(struct iwl_priv *priv) test_bit(STATUS_EXIT_PENDING, &priv->status) << STATUS_EXIT_PENDING; - /* device going down, Stop using ICT table */ - iwl_disable_ict(priv); - - iwlagn_txq_ctx_stop(priv); - iwlagn_rxq_stop(priv); - - /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - udelay(5); - - /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* Stop the device, and put it in low power state */ - iwl_apm_stop(priv); + iwlagn_stop_device(priv); - exit: dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; @@ -2437,9 +2370,10 @@ static void iwl_down(struct iwl_priv *priv) #define HW_READY_TIMEOUT (50) +/* Note: returns poll_bit return value, which is >= 0 if success */ static int iwl_set_hw_ready(struct iwl_priv *priv) { - int ret = 0; + int ret; iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); @@ -2449,25 +2383,21 @@ static int iwl_set_hw_ready(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, HW_READY_TIMEOUT); - if (ret != -ETIMEDOUT) - priv->hw_ready = true; - else - priv->hw_ready = false; - IWL_DEBUG_INFO(priv, "hardware %s\n", - (priv->hw_ready == 1) ? "ready" : "not ready"); + IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : ""); return ret; } -static int iwl_prepare_card_hw(struct iwl_priv *priv) +/* Note: returns standard 0/-ERROR code */ +int iwl_prepare_card_hw(struct iwl_priv *priv) { - int ret = 0; + int ret; IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n"); ret = iwl_set_hw_ready(priv); - if (priv->hw_ready) - return ret; + if (ret >= 0) + return 0; /* If HW is not ready, prepare the conditions to check again */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, @@ -2477,10 +2407,13 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); - /* HW should be ready by now, check again. */ - if (ret != -ETIMEDOUT) - iwl_set_hw_ready(priv); + if (ret < 0) + return ret; + /* HW should be ready by now, check again. */ + ret = iwl_set_hw_ready(priv); + if (ret >= 0) + return 0; return ret; } @@ -2489,9 +2422,10 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv) static int __iwl_up(struct iwl_priv *priv) { struct iwl_rxon_context *ctx; - int i; int ret; + lockdep_assert_held(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); return -EIO; @@ -2505,77 +2439,33 @@ static int __iwl_up(struct iwl_priv *priv) } } - iwl_prepare_card_hw(priv); - - if (!priv->hw_ready) { - IWL_WARN(priv, "Exit HW not ready\n"); - return -EIO; - } - - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); - - if (iwl_is_rfkill(priv)) { - wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); - - iwl_enable_interrupts(priv); - IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n"); - return 0; + ret = iwlagn_run_init_ucode(priv); + if (ret) { + IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); + goto error; } - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - ret = iwlagn_hw_nic_init(priv); + ret = iwlagn_load_ucode_wait_alive(priv, + &priv->ucode_rt, + UCODE_SUBTYPE_REGULAR, + UCODE_SUBTYPE_REGULAR_NEW); if (ret) { - IWL_ERR(priv, "Unable to init nic\n"); - return ret; + IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); + goto error; } - /* make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - /* clear (again), then enable host interrupts */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_enable_interrupts(priv); - - /* really make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - for (i = 0; i < MAX_HW_RESTARTS; i++) { - - /* load bootstrap state machine, - * load bootstrap program into processor's memory, - * prepare to load the "initialize" uCode */ - ret = iwlagn_load_ucode(priv); - - if (ret) { - IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n", - ret); - continue; - } - - /* start card; "initialize" will load runtime ucode */ - iwl_nic_start(priv); - - IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n"); - - return 0; - } + ret = iwl_alive_start(priv); + if (ret) + goto error; + return 0; + error: set_bit(STATUS_EXIT_PENDING, &priv->status); __iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->status); - /* tried to restart and config the device for as long as our - * patience could withstand */ - IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i); - return -EIO; + IWL_ERR(priv, "Unable to initialize device.\n"); + return ret; } @@ -2585,39 +2475,6 @@ static int __iwl_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl_bg_init_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); - - mutex_lock(&priv->mutex); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { - mutex_unlock(&priv->mutex); - return; - } - - iwlagn_init_alive_start(priv); - mutex_unlock(&priv->mutex); -} - -static void iwl_bg_alive_start(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); - - mutex_lock(&priv->mutex); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - goto unlock; - - /* enable dram interrupt */ - iwl_reset_ict(priv); - - iwl_alive_start(priv); -unlock: - mutex_unlock(&priv->mutex); -} - static void iwl_bg_run_time_calib_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2639,6 +2496,42 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) mutex_unlock(&priv->mutex); } +static void iwlagn_prepare_restart(struct iwl_priv *priv) +{ + struct iwl_rxon_context *ctx; + bool bt_full_concurrent; + u8 bt_ci_compliance; + u8 bt_load; + u8 bt_status; + + lockdep_assert_held(&priv->mutex); + + for_each_context(priv, ctx) + ctx->vif = NULL; + priv->is_open = 0; + + /* + * __iwl_down() will clear the BT status variables, + * which is correct, but when we restart we really + * want to keep them so restore them afterwards. + * + * The restart process will later pick them up and + * re-configure the hw when we reconfigure the BT + * command. + */ + bt_full_concurrent = priv->bt_full_concurrent; + bt_ci_compliance = priv->bt_ci_compliance; + bt_load = priv->bt_traffic_load; + bt_status = priv->bt_status; + + __iwl_down(priv); + + priv->bt_full_concurrent = bt_full_concurrent; + priv->bt_ci_compliance = bt_ci_compliance; + priv->bt_traffic_load = bt_load; + priv->bt_status = bt_status; +} + static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); @@ -2647,50 +2540,13 @@ static void iwl_bg_restart(struct work_struct *data) return; if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { - struct iwl_rxon_context *ctx; - bool bt_full_concurrent; - u8 bt_ci_compliance; - u8 bt_load; - u8 bt_status; - mutex_lock(&priv->mutex); - for_each_context(priv, ctx) - ctx->vif = NULL; - priv->is_open = 0; - - /* - * __iwl_down() will clear the BT status variables, - * which is correct, but when we restart we really - * want to keep them so restore them afterwards. - * - * The restart process will later pick them up and - * re-configure the hw when we reconfigure the BT - * command. - */ - bt_full_concurrent = priv->bt_full_concurrent; - bt_ci_compliance = priv->bt_ci_compliance; - bt_load = priv->bt_traffic_load; - bt_status = priv->bt_status; - - __iwl_down(priv); - - priv->bt_full_concurrent = bt_full_concurrent; - priv->bt_ci_compliance = bt_ci_compliance; - priv->bt_traffic_load = bt_load; - priv->bt_status = bt_status; - + iwlagn_prepare_restart(priv); mutex_unlock(&priv->mutex); iwl_cancel_deferred_work(priv); ieee80211_restart_hw(priv->hw); } else { - iwl_down(priv); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - __iwl_up(priv); - mutex_unlock(&priv->mutex); + WARN_ON(1); } } @@ -2801,8 +2657,6 @@ unlock: * *****************************************************************************/ -#define UCODE_READY_TIMEOUT (4 * HZ) - /* * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. @@ -2895,31 +2749,17 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); ret = __iwl_up(priv); mutex_unlock(&priv->mutex); - if (ret) return ret; - if (iwl_is_rfkill(priv)) - goto out; - IWL_DEBUG_INFO(priv, "Start UP work done.\n"); - /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from - * mac80211 will not be run successfully. */ - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - test_bit(STATUS_READY, &priv->status), - UCODE_READY_TIMEOUT); - if (!ret) { - if (!test_bit(STATUS_READY, &priv->status)) { - IWL_ERR(priv, "START_ALIVE timeout after %dms.\n", - jiffies_to_msecs(UCODE_READY_TIMEOUT)); - return -ETIMEDOUT; - } - } + /* Now we should be done, and the READY bit should be set. */ + if (WARN_ON(!test_bit(STATUS_READY, &priv->status))) + ret = -EIO; iwlagn_led_enable(priv); -out: priv->is_open = 1; IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; @@ -2994,7 +2834,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (priv->cfg->mod_params->sw_crypto) { + if (iwlagn_mod_params.sw_crypto) { IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -3506,8 +3346,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done); iwl_setup_scan_deferred_work(priv); @@ -3536,8 +3374,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) if (priv->cfg->ops->lib->cancel_deferred_work) priv->cfg->ops->lib->cancel_deferred_work(priv); - cancel_delayed_work_sync(&priv->init_alive_start); - cancel_delayed_work(&priv->alive_start); cancel_work_sync(&priv->run_time_calib_work); cancel_work_sync(&priv->beacon_update); @@ -3617,12 +3453,6 @@ static int iwl_init_drv(struct iwl_priv *priv) priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF; } - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN; - priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN; - ret = iwl_init_channel_map(priv); if (ret) { IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); @@ -3692,14 +3522,14 @@ static int iwl_set_hw_params(struct iwl_priv *priv) { priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); else priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; - if (priv->cfg->mod_params->disable_11n) + if (iwlagn_mod_params.disable_11n) priv->cfg->sku &= ~IWL_SKU_N; /* Device-specific setup */ @@ -3772,6 +3602,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv = hw->priv; /* At this point both hw and priv are allocated. */ + priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED; + /* * The default context is always valid, * more may be discovered when firmware @@ -3912,8 +3744,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - iwl_prepare_card_hw(priv); - if (!priv->hw_ready) { + if (iwl_prepare_card_hw(priv)) { IWL_WARN(priv, "Failed, HW not ready\n"); goto out_iounmap; } @@ -4069,17 +3900,9 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; - } else { - iwl_down(priv); } - /* - * Make sure device is reset to low power before unloading driver. - * This may be redundant with iwl_down(), but there are paths to - * run iwl_down() without calling apm_ops.stop(), and there are - * paths to avoid running iwl_down() at all before leaving driver. - * This (inexpensive) call *makes sure* device is reset. - */ + /* Reset to low power before unloading driver. */ iwl_apm_stop(priv); iwl_tt_exit(priv); @@ -4306,21 +4129,21 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)}, {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)}, -/* 200 Series */ - {IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)}, - {IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)}, - {IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)}, - -/* 230 Series */ - {IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)}, - {IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)}, - {IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)}, +/* 105 Series */ + {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)}, + +/* 135 Series */ + {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)}, + {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)}, {0} }; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 078a23e..b477336 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -102,10 +102,10 @@ extern struct iwl_cfg iwl2030_2bg_cfg; extern struct iwl_cfg iwl6035_2agn_cfg; extern struct iwl_cfg iwl6035_2abg_cfg; extern struct iwl_cfg iwl6035_2bg_cfg; -extern struct iwl_cfg iwl200_bg_cfg; -extern struct iwl_cfg iwl200_bgn_cfg; -extern struct iwl_cfg iwl230_bg_cfg; -extern struct iwl_cfg iwl230_bgn_cfg; +extern struct iwl_cfg iwl105_bg_cfg; +extern struct iwl_cfg iwl105_bgn_cfg; +extern struct iwl_cfg iwl135_bg_cfg; +extern struct iwl_cfg iwl135_bgn_cfg; extern struct iwl_mod_params iwlagn_mod_params; extern struct iwl_hcmd_ops iwlagn_hcmd; @@ -120,6 +120,19 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv); void iwl_free_isr_ict(struct iwl_priv *priv); irqreturn_t iwl_isr_ict(int irq, void *data); +/* call this function to flush any scheduled tasklet */ +static inline void iwl_synchronize_irq(struct iwl_priv *priv) +{ + /* wait to make sure we flush pending tasklet*/ + synchronize_irq(priv->pci_dev->irq); + tasklet_kill(&priv->irq_tasklet); +} + +int iwl_prepare_card_hw(struct iwl_priv *priv); + +int iwlagn_start_device(struct iwl_priv *priv); +void iwlagn_stop_device(struct iwl_priv *priv); + /* tx queue */ void iwlagn_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index); @@ -145,16 +158,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, u32 changes); /* uCode */ -int iwlagn_load_ucode(struct iwl_priv *priv); void iwlagn_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -void iwlagn_rx_calib_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwlagn_init_alive_start(struct iwl_priv *priv); -int iwlagn_alive_notify(struct iwl_priv *priv); -int iwl_verify_ucode(struct iwl_priv *priv, struct fw_desc *fw_desc); -void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); +int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); +int iwlagn_run_init_ucode(struct iwl_priv *priv); +int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, + struct fw_img *image, + int subtype, int alternate_subtype); /* lib */ void iwl_check_abort_status(struct iwl_priv *priv, @@ -245,8 +256,6 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add); /* hcmd */ -int iwlagn_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); @@ -318,17 +327,17 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) /* eeprom */ void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); -int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); -void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); /* notification wait support */ void __acquires(wait_entry) iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, + u8 cmd, void (*fn)(struct iwl_priv *priv, - struct iwl_rx_packet *pkt), - u8 cmd); -signed long __releases(wait_entry) + struct iwl_rx_packet *pkt, + void *data), + void *fn_data); +int __must_check __releases(wait_entry) iwlagn_wait_notification(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, unsigned long timeout); diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 0edba8a..5fdad65 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -386,7 +386,18 @@ struct iwl_tx_ant_config_cmd { *****************************************************************************/ #define UCODE_VALID_OK cpu_to_le32(0x1) -#define INITIALIZE_SUBTYPE (9) + +enum iwlagn_ucode_subtype { + UCODE_SUBTYPE_REGULAR = 0, + UCODE_SUBTYPE_REGULAR_NEW = 1, + UCODE_SUBTYPE_INIT = 9, + + /* + * Not a valid subtype, the ucode has just a u8, so + * we can use something > 0xff for this value. + */ + UCODE_SUBTYPE_NONE_LOADED = 0x100, +}; /** * REPLY_ALIVE = 0x1 (response only, not a command) @@ -422,49 +433,61 @@ struct iwl_tx_ant_config_cmd { * * 2) error_event_table_ptr indicates base of the error log. This contains * information about any uCode error that occurs. For agn, the format - * of the error log is: - * - * __le32 valid; (nonzero) valid, (0) log is empty - * __le32 error_id; type of error - * __le32 pc; program counter - * __le32 blink1; branch link - * __le32 blink2; branch link - * __le32 ilink1; interrupt link - * __le32 ilink2; interrupt link - * __le32 data1; error-specific data - * __le32 data2; error-specific data - * __le32 line; source code line of error - * __le32 bcon_time; beacon timer - * __le32 tsf_low; network timestamp function timer - * __le32 tsf_hi; network timestamp function timer - * __le32 gp1; GP1 timer register - * __le32 gp2; GP2 timer register - * __le32 gp3; GP3 timer register - * __le32 ucode_ver; uCode version - * __le32 hw_ver; HW Silicon version - * __le32 brd_ver; HW board version - * __le32 log_pc; log program counter - * __le32 frame_ptr; frame pointer - * __le32 stack_ptr; stack pointer - * __le32 hcmd; last host command - * __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag - * __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag - * __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag - * __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag - * __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt - * __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT - * __le32 wait_event; wait event() caller address - * __le32 l2p_control; L2pControlField - * __le32 l2p_duration; L2pDurationField - * __le32 l2p_mhvalid; L2pMhValidBits - * __le32 l2p_addr_match; L2pAddrMatchStat - * __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL) - * __le32 u_timestamp; indicate when the date and time of the compilation - * __le32 reserved; + * of the error log is defined by struct iwl_error_event_table. * * The Linux driver can print both logs to the system log when a uCode error * occurs. */ + +/* + * Note: This structure is read from the device with IO accesses, + * and the reading already does the endian conversion. As it is + * read with u32-sized accesses, any members with a different size + * need to be ordered correctly though! + */ +struct iwl_error_event_table { + u32 valid; /* (nonzero) valid, (0) log is empty */ + u32 error_id; /* type of error */ + u32 pc; /* program counter */ + u32 blink1; /* branch link */ + u32 blink2; /* branch link */ + u32 ilink1; /* interrupt link */ + u32 ilink2; /* interrupt link */ + u32 data1; /* error-specific data */ + u32 data2; /* error-specific data */ + u32 line; /* source code line of error */ + u32 bcon_time; /* beacon timer */ + u32 tsf_low; /* network timestamp function timer */ + u32 tsf_hi; /* network timestamp function timer */ + u32 gp1; /* GP1 timer register */ + u32 gp2; /* GP2 timer register */ + u32 gp3; /* GP3 timer register */ + u32 ucode_ver; /* uCode version */ + u32 hw_ver; /* HW Silicon version */ + u32 brd_ver; /* HW board version */ + u32 log_pc; /* log program counter */ + u32 frame_ptr; /* frame pointer */ + u32 stack_ptr; /* stack pointer */ + u32 hcmd; /* last host command header */ +#if 0 + /* no need to read the remainder, we don't use the values */ + u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */ + u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */ + u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */ + u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */ + u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */ + u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ + u32 wait_event; /* wait event() caller address */ + u32 l2p_control; /* L2pControlField */ + u32 l2p_duration; /* L2pDurationField */ + u32 l2p_mhvalid; /* L2pMhValidBits */ + u32 l2p_addr_match; /* L2pAddrMatchStat */ + u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */ + u32 u_timestamp; /* indicate when the date and time of the compilation */ + u32 flow_handler; /* FH read/write pointers, RX credit */ +#endif +} __packed; + struct iwl_alive_resp { u8 ucode_minor; u8 ucode_major; @@ -638,7 +661,7 @@ struct iwl_rxon_cmd { /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ -struct iwl5000_rxon_assoc_cmd { +struct iwl_rxon_assoc_cmd { __le32 flags; __le32 filter_flags; u8 ofdm_basic_rates; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 885167f..4653dea 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -41,6 +41,7 @@ #include "iwl-power.h" #include "iwl-sta.h" #include "iwl-helpers.h" +#include "iwl-agn.h" /* @@ -94,7 +95,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, max_bit_rate = MAX_BIT_RATE_40_MHZ; } - if (priv->cfg->mod_params->amsdu_size_8K) + if (iwlagn_mod_params.amsdu_size_8K) ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; @@ -135,6 +136,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; + s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN; if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { @@ -208,8 +210,8 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_device_lmt) - priv->tx_power_device_lmt = ch->max_power_avg; + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -222,6 +224,10 @@ int iwlcore_init_geos(struct iwl_priv *priv) geo_ch->flags); } + priv->tx_power_device_lmt = max_tx_power; + priv->tx_power_user_lmt = max_tx_power; + priv->tx_power_next = max_tx_power; + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->cfg->sku & IWL_SKU_A) { IWL_INFO(priv, "Incorrectly detected BG card as ABG. " @@ -410,72 +416,72 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { struct iwl_rxon_cmd *rxon = &ctx->staging; - bool error = false; + u32 errors = 0; if (rxon->flags & RXON_FLG_BAND_24G_MSK) { if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) { IWL_WARN(priv, "check 2.4G: wrong narrow\n"); - error = true; + errors |= BIT(0); } if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) { IWL_WARN(priv, "check 2.4G: wrong radar\n"); - error = true; + errors |= BIT(1); } } else { if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) { IWL_WARN(priv, "check 5.2G: not short slot!\n"); - error = true; + errors |= BIT(2); } if (rxon->flags & RXON_FLG_CCK_MSK) { IWL_WARN(priv, "check 5.2G: CCK!\n"); - error = true; + errors |= BIT(3); } } if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) { IWL_WARN(priv, "mac/bssid mcast!\n"); - error = true; + errors |= BIT(4); } /* make sure basic rates 6Mbps and 1Mbps are supported */ if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 && (rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) { IWL_WARN(priv, "neither 1 nor 6 are basic\n"); - error = true; + errors |= BIT(5); } if (le16_to_cpu(rxon->assoc_id) > 2007) { IWL_WARN(priv, "aid > 2007\n"); - error = true; + errors |= BIT(6); } if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) { IWL_WARN(priv, "CCK and short slot\n"); - error = true; + errors |= BIT(7); } if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) { IWL_WARN(priv, "CCK and auto detect"); - error = true; + errors |= BIT(8); } if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK) { IWL_WARN(priv, "TGg but no auto-detect\n"); - error = true; + errors |= BIT(9); } - if (error) - IWL_WARN(priv, "Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERR(priv, "Invalid RXON\n"); - return -EINVAL; + if (rxon->channel == 0) { + IWL_WARN(priv, "zero channel is invalid\n"); + errors |= BIT(10); } - return 0; + + WARN(errors, "Invalid RXON (%#x), channel %d", + errors, le16_to_cpu(rxon->channel)); + + return errors ? -EINVAL : 0; } /** @@ -867,6 +873,19 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, } #endif +static void iwlagn_abort_notification_waits(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl_notification_wait *wait_entry; + + spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags); + list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list) + wait_entry->aborted = true; + spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags); + + wake_up_all(&priv->_agn.notif_waitq); +} + void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) { unsigned int reload_msec; @@ -878,6 +897,8 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + iwlagn_abort_notification_waits(priv); + /* Keep the restart process from trying to send host * commands by clearing the ready bit */ clear_bit(STATUS_READY, &priv->status); @@ -906,7 +927,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) } if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { - if (priv->cfg->mod_params->restart_fw) { + if (iwlagn_mod_params.restart_fw) { IWL_DEBUG(priv, IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); queue_work(priv->workqueue, &priv->restart); @@ -975,6 +996,8 @@ void iwl_apm_stop(struct iwl_priv *priv) { IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); + clear_bit(STATUS_DEVICE_ENABLED, &priv->status); + /* Stop device's DMA activity */ iwl_apm_stop_master(priv); @@ -1089,6 +1112,8 @@ int iwl_apm_init(struct iwl_priv *priv) iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + set_bit(STATUS_DEVICE_ENABLED, &priv->status); + out: return ret; } @@ -1723,7 +1748,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) * detect failure), then fw_restart module parameter * need to be check before performing firmware reload */ - if (!external && !priv->cfg->mod_params->restart_fw) { + if (!external && !iwlagn_mod_params.restart_fw) { IWL_DEBUG_INFO(priv, "Cancel firmware reload based on " "module parameter setting\n"); break; @@ -1740,6 +1765,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); + struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_context *tmp; u32 interface_modes; int err; @@ -1764,6 +1790,19 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, goto out; } + /* + * Refuse a change that should be done by moving from the PAN + * context to the BSS context instead, if the BSS context is + * available and can support the new interface type. + */ + if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif && + (bss_ctx->interface_modes & BIT(newtype) || + bss_ctx->exclusive_interface_modes & BIT(newtype))) { + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); + err = -EBUSY; + goto out; + } + if (ctx->exclusive_interface_modes & BIT(newtype)) { for_each_context(priv, tmp) { if (ctx == tmp) diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 32a990f..dec98207 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -90,7 +90,6 @@ struct iwl_cmd; #define IWL_CMD(x) case x: return #x struct iwl_hcmd_ops { - int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void (*set_rxon_chain)(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -122,19 +121,6 @@ struct iwl_apm_ops { void (*config)(struct iwl_priv *priv); }; -struct iwl_debugfs_ops { - ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*general_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*bt_stats_read)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); -}; - struct iwl_temp_ops { void (*temperature)(struct iwl_priv *priv); }; @@ -183,7 +169,6 @@ struct iwl_lib_ops { int (*txfifo_flush)(struct iwl_priv *priv, u16 flush_control); void (*dev_txfifo_flush)(struct iwl_priv *priv, u16 flush_control); - struct iwl_debugfs_ops debugfs_ops; }; /* NIC specific ops */ @@ -326,8 +311,6 @@ struct iwl_cfg { u16 eeprom_ver; u16 eeprom_calib_ver; const struct iwl_ops *ops; - /* module based parameters which can be set from modprobe cmd */ - const struct iwl_mod_params *mod_params; /* params not likely to change within a device family */ struct iwl_base_params *base_params; /* params likely to change within a device family */ @@ -592,6 +575,7 @@ void iwlcore_free_geos(struct iwl_priv *priv); #define STATUS_SCAN_HW 15 #define STATUS_POWER_PMI 16 #define STATUS_FW_ERROR 17 +#define STATUS_DEVICE_ENABLED 18 static inline int iwl_is_ready(struct iwl_priv *priv) @@ -644,11 +628,6 @@ void iwl_apm_stop(struct iwl_priv *priv); int iwl_apm_init(struct iwl_priv *priv); int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -static inline int iwl_send_rxon_assoc(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx); -} static inline int iwlcore_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index c272204..0e6a04b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -39,6 +39,7 @@ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" +#include "iwl-agn.h" /* create and remove of files */ #define DEBUGFS_ADD_FILE(name, parent, mode) do { \ @@ -226,10 +227,10 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, /* default is to dump the entire data segment */ if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) { priv->dbgfs_sram_offset = 0x800000; - if (priv->ucode_type == UCODE_INIT) - priv->dbgfs_sram_len = priv->ucode_init_data.len; + if (priv->ucode_type == UCODE_SUBTYPE_INIT) + priv->dbgfs_sram_len = priv->ucode_init.data.len; else - priv->dbgfs_sram_len = priv->ucode_data.len; + priv->dbgfs_sram_len = priv->ucode_rt.data.len; } len = priv->dbgfs_sram_len; @@ -1037,13 +1038,463 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static const char *fmt_value = " %-30s %10u\n"; +static const char *fmt_hex = " %-30s 0x%02X\n"; +static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; +static const char *fmt_header = + "%-32s current cumulative delta max\n"; + +static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz) +{ + int p = 0; + u32 flag; + + flag = le32_to_cpu(priv->statistics.flag); + + p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n", flag); + if (flag & UCODE_STATISTICS_CLEAR_MSK) + p += scnprintf(buf + p, bufsz - p, + "\tStatistics have been cleared\n"); + p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n", + (flag & UCODE_STATISTICS_FREQUENCY_MSK) + ? "2.4 GHz" : "5.2 GHz"); + p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n", + (flag & UCODE_STATISTICS_NARROW_BAND_MSK) + ? "enabled" : "disabled"); + + return p; +} + static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_rx_phy) * 40 + + sizeof(struct statistics_rx_non_phy) * 40 + + sizeof(struct statistics_rx_ht_phy) * 40 + 400; + ssize_t ret; + struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm; + struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck; + struct statistics_rx_non_phy *general, *accum_general; + struct statistics_rx_non_phy *delta_general, *max_general; + struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + ofdm = &priv->statistics.rx_ofdm; + cck = &priv->statistics.rx_cck; + general = &priv->statistics.rx_non_phy; + ht = &priv->statistics.rx_ofdm_ht; + accum_ofdm = &priv->accum_stats.rx_ofdm; + accum_cck = &priv->accum_stats.rx_cck; + accum_general = &priv->accum_stats.rx_non_phy; + accum_ht = &priv->accum_stats.rx_ofdm_ht; + delta_ofdm = &priv->delta_stats.rx_ofdm; + delta_cck = &priv->delta_stats.rx_cck; + delta_general = &priv->delta_stats.rx_non_phy; + delta_ht = &priv->delta_stats.rx_ofdm_ht; + max_ofdm = &priv->max_delta_stats.rx_ofdm; + max_cck = &priv->max_delta_stats.rx_cck; + max_general = &priv->max_delta_stats.rx_non_phy; + max_ht = &priv->max_delta_stats.rx_ofdm_ht; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(ofdm->ina_cnt), + accum_ofdm->ina_cnt, + delta_ofdm->ina_cnt, max_ofdm->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt, + delta_ofdm->fina_cnt, max_ofdm->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err, + delta_ofdm->plcp_err, max_ofdm->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err, + delta_ofdm->crc32_err, max_ofdm->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ofdm->overrun_err), + accum_ofdm->overrun_err, delta_ofdm->overrun_err, + max_ofdm->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ofdm->early_overrun_err), + accum_ofdm->early_overrun_err, + delta_ofdm->early_overrun_err, + max_ofdm->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ofdm->crc32_good), + accum_ofdm->crc32_good, delta_ofdm->crc32_good, + max_ofdm->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(ofdm->false_alarm_cnt), + accum_ofdm->false_alarm_cnt, + delta_ofdm->false_alarm_cnt, + max_ofdm->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(ofdm->fina_sync_err_cnt), + accum_ofdm->fina_sync_err_cnt, + delta_ofdm->fina_sync_err_cnt, + max_ofdm->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(ofdm->sfd_timeout), + accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout, + max_ofdm->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(ofdm->fina_timeout), + accum_ofdm->fina_timeout, delta_ofdm->fina_timeout, + max_ofdm->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(ofdm->unresponded_rts), + accum_ofdm->unresponded_rts, + delta_ofdm->unresponded_rts, + max_ofdm->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(ofdm->rxe_frame_limit_overrun), + accum_ofdm->rxe_frame_limit_overrun, + delta_ofdm->rxe_frame_limit_overrun, + max_ofdm->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(ofdm->sent_ack_cnt), + accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt, + max_ofdm->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(ofdm->sent_cts_cnt), + accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt, + max_ofdm->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(ofdm->sent_ba_rsp_cnt), + accum_ofdm->sent_ba_rsp_cnt, + delta_ofdm->sent_ba_rsp_cnt, + max_ofdm->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(ofdm->dsp_self_kill), + accum_ofdm->dsp_self_kill, + delta_ofdm->dsp_self_kill, + max_ofdm->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ofdm->mh_format_err), + accum_ofdm->mh_format_err, + delta_ofdm->mh_format_err, + max_ofdm->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(ofdm->re_acq_main_rssi_sum), + accum_ofdm->re_acq_main_rssi_sum, + delta_ofdm->re_acq_main_rssi_sum, + max_ofdm->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - CCK:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_cnt:", + le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt, + delta_cck->ina_cnt, max_cck->ina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_cnt:", + le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt, + delta_cck->fina_cnt, max_cck->fina_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(cck->plcp_err), accum_cck->plcp_err, + delta_cck->plcp_err, max_cck->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(cck->crc32_err), accum_cck->crc32_err, + delta_cck->crc32_err, max_cck->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(cck->overrun_err), + accum_cck->overrun_err, delta_cck->overrun_err, + max_cck->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(cck->early_overrun_err), + accum_cck->early_overrun_err, + delta_cck->early_overrun_err, + max_cck->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(cck->crc32_good), accum_cck->crc32_good, + delta_cck->crc32_good, max_cck->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "false_alarm_cnt:", + le32_to_cpu(cck->false_alarm_cnt), + accum_cck->false_alarm_cnt, + delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_sync_err_cnt:", + le32_to_cpu(cck->fina_sync_err_cnt), + accum_cck->fina_sync_err_cnt, + delta_cck->fina_sync_err_cnt, + max_cck->fina_sync_err_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sfd_timeout:", + le32_to_cpu(cck->sfd_timeout), + accum_cck->sfd_timeout, delta_cck->sfd_timeout, + max_cck->sfd_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "fina_timeout:", + le32_to_cpu(cck->fina_timeout), + accum_cck->fina_timeout, delta_cck->fina_timeout, + max_cck->fina_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unresponded_rts:", + le32_to_cpu(cck->unresponded_rts), + accum_cck->unresponded_rts, delta_cck->unresponded_rts, + max_cck->unresponded_rts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rxe_frame_lmt_ovrun:", + le32_to_cpu(cck->rxe_frame_limit_overrun), + accum_cck->rxe_frame_limit_overrun, + delta_cck->rxe_frame_limit_overrun, + max_cck->rxe_frame_limit_overrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ack_cnt:", + le32_to_cpu(cck->sent_ack_cnt), + accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt, + max_cck->sent_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_cts_cnt:", + le32_to_cpu(cck->sent_cts_cnt), + accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt, + max_cck->sent_cts_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sent_ba_rsp_cnt:", + le32_to_cpu(cck->sent_ba_rsp_cnt), + accum_cck->sent_ba_rsp_cnt, + delta_cck->sent_ba_rsp_cnt, + max_cck->sent_ba_rsp_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_self_kill:", + le32_to_cpu(cck->dsp_self_kill), + accum_cck->dsp_self_kill, delta_cck->dsp_self_kill, + max_cck->dsp_self_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(cck->mh_format_err), + accum_cck->mh_format_err, delta_cck->mh_format_err, + max_cck->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "re_acq_main_rssi_sum:", + le32_to_cpu(cck->re_acq_main_rssi_sum), + accum_cck->re_acq_main_rssi_sum, + delta_cck->re_acq_main_rssi_sum, + max_cck->re_acq_main_rssi_sum); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - GENERAL:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_cts:", + le32_to_cpu(general->bogus_cts), + accum_general->bogus_cts, delta_general->bogus_cts, + max_general->bogus_cts); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bogus_ack:", + le32_to_cpu(general->bogus_ack), + accum_general->bogus_ack, delta_general->bogus_ack, + max_general->bogus_ack); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_bssid_frames:", + le32_to_cpu(general->non_bssid_frames), + accum_general->non_bssid_frames, + delta_general->non_bssid_frames, + max_general->non_bssid_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "filtered_frames:", + le32_to_cpu(general->filtered_frames), + accum_general->filtered_frames, + delta_general->filtered_frames, + max_general->filtered_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "non_channel_beacons:", + le32_to_cpu(general->non_channel_beacons), + accum_general->non_channel_beacons, + delta_general->non_channel_beacons, + max_general->non_channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_beacons:", + le32_to_cpu(general->channel_beacons), + accum_general->channel_beacons, + delta_general->channel_beacons, + max_general->channel_beacons); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_missed_bcon:", + le32_to_cpu(general->num_missed_bcon), + accum_general->num_missed_bcon, + delta_general->num_missed_bcon, + max_general->num_missed_bcon); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "adc_rx_saturation_time:", + le32_to_cpu(general->adc_rx_saturation_time), + accum_general->adc_rx_saturation_time, + delta_general->adc_rx_saturation_time, + max_general->adc_rx_saturation_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ina_detect_search_tm:", + le32_to_cpu(general->ina_detection_search_time), + accum_general->ina_detection_search_time, + delta_general->ina_detection_search_time, + max_general->ina_detection_search_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_a:", + le32_to_cpu(general->beacon_silence_rssi_a), + accum_general->beacon_silence_rssi_a, + delta_general->beacon_silence_rssi_a, + max_general->beacon_silence_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_b:", + le32_to_cpu(general->beacon_silence_rssi_b), + accum_general->beacon_silence_rssi_b, + delta_general->beacon_silence_rssi_b, + max_general->beacon_silence_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_silence_rssi_c:", + le32_to_cpu(general->beacon_silence_rssi_c), + accum_general->beacon_silence_rssi_c, + delta_general->beacon_silence_rssi_c, + max_general->beacon_silence_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "interference_data_flag:", + le32_to_cpu(general->interference_data_flag), + accum_general->interference_data_flag, + delta_general->interference_data_flag, + max_general->interference_data_flag); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "channel_load:", + le32_to_cpu(general->channel_load), + accum_general->channel_load, + delta_general->channel_load, + max_general->channel_load); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dsp_false_alarms:", + le32_to_cpu(general->dsp_false_alarms), + accum_general->dsp_false_alarms, + delta_general->dsp_false_alarms, + max_general->dsp_false_alarms); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_a:", + le32_to_cpu(general->beacon_rssi_a), + accum_general->beacon_rssi_a, + delta_general->beacon_rssi_a, + max_general->beacon_rssi_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_b:", + le32_to_cpu(general->beacon_rssi_b), + accum_general->beacon_rssi_b, + delta_general->beacon_rssi_b, + max_general->beacon_rssi_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_rssi_c:", + le32_to_cpu(general->beacon_rssi_c), + accum_general->beacon_rssi_c, + delta_general->beacon_rssi_c, + max_general->beacon_rssi_c); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_a:", + le32_to_cpu(general->beacon_energy_a), + accum_general->beacon_energy_a, + delta_general->beacon_energy_a, + max_general->beacon_energy_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_b:", + le32_to_cpu(general->beacon_energy_b), + accum_general->beacon_energy_b, + delta_general->beacon_energy_b, + max_general->beacon_energy_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "beacon_energy_c:", + le32_to_cpu(general->beacon_energy_c), + accum_general->beacon_energy_c, + delta_general->beacon_energy_c, + max_general->beacon_energy_c); + + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Rx - OFDM_HT:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "plcp_err:", + le32_to_cpu(ht->plcp_err), accum_ht->plcp_err, + delta_ht->plcp_err, max_ht->plcp_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "overrun_err:", + le32_to_cpu(ht->overrun_err), accum_ht->overrun_err, + delta_ht->overrun_err, max_ht->overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "early_overrun_err:", + le32_to_cpu(ht->early_overrun_err), + accum_ht->early_overrun_err, + delta_ht->early_overrun_err, + max_ht->early_overrun_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_good:", + le32_to_cpu(ht->crc32_good), accum_ht->crc32_good, + delta_ht->crc32_good, max_ht->crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "crc32_err:", + le32_to_cpu(ht->crc32_err), accum_ht->crc32_err, + delta_ht->crc32_err, max_ht->crc32_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "mh_format_err:", + le32_to_cpu(ht->mh_format_err), + accum_ht->mh_format_err, + delta_ht->mh_format_err, max_ht->mh_format_err); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_crc32_good:", + le32_to_cpu(ht->agg_crc32_good), + accum_ht->agg_crc32_good, + delta_ht->agg_crc32_good, max_ht->agg_crc32_good); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_mpdu_cnt:", + le32_to_cpu(ht->agg_mpdu_cnt), + accum_ht->agg_mpdu_cnt, + delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg_cnt:", + le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt, + delta_ht->agg_cnt, max_ht->agg_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "unsupport_mcs:", + le32_to_cpu(ht->unsupport_mcs), + accum_ht->unsupport_mcs, + delta_ht->unsupport_mcs, max_ht->unsupport_mcs); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, @@ -1051,8 +1502,190 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_tx) * 48) + 250; + ssize_t ret; + struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + tx = &priv->statistics.tx; + accum_tx = &priv->accum_stats.tx; + delta_tx = &priv->delta_stats.tx; + max_tx = &priv->max_delta_stats.tx; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_Tx:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "preamble:", + le32_to_cpu(tx->preamble_cnt), + accum_tx->preamble_cnt, + delta_tx->preamble_cnt, max_tx->preamble_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_detected_cnt:", + le32_to_cpu(tx->rx_detected_cnt), + accum_tx->rx_detected_cnt, + delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_defer_cnt:", + le32_to_cpu(tx->bt_prio_defer_cnt), + accum_tx->bt_prio_defer_cnt, + delta_tx->bt_prio_defer_cnt, + max_tx->bt_prio_defer_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "bt_prio_kill_cnt:", + le32_to_cpu(tx->bt_prio_kill_cnt), + accum_tx->bt_prio_kill_cnt, + delta_tx->bt_prio_kill_cnt, + max_tx->bt_prio_kill_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "few_bytes_cnt:", + le32_to_cpu(tx->few_bytes_cnt), + accum_tx->few_bytes_cnt, + delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout:", + le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout, + delta_tx->cts_timeout, max_tx->cts_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_timeout:", + le32_to_cpu(tx->ack_timeout), + accum_tx->ack_timeout, + delta_tx->ack_timeout, max_tx->ack_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "expected_ack_cnt:", + le32_to_cpu(tx->expected_ack_cnt), + accum_tx->expected_ack_cnt, + delta_tx->expected_ack_cnt, + max_tx->expected_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "actual_ack_cnt:", + le32_to_cpu(tx->actual_ack_cnt), + accum_tx->actual_ack_cnt, + delta_tx->actual_ack_cnt, + max_tx->actual_ack_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "dump_msdu_cnt:", + le32_to_cpu(tx->dump_msdu_cnt), + accum_tx->dump_msdu_cnt, + delta_tx->dump_msdu_cnt, + max_tx->dump_msdu_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_nxt_frame_mismatch:", + le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt), + accum_tx->burst_abort_next_frame_mismatch_cnt, + delta_tx->burst_abort_next_frame_mismatch_cnt, + max_tx->burst_abort_next_frame_mismatch_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "abort_missing_nxt_frame:", + le32_to_cpu(tx->burst_abort_missing_next_frame_cnt), + accum_tx->burst_abort_missing_next_frame_cnt, + delta_tx->burst_abort_missing_next_frame_cnt, + max_tx->burst_abort_missing_next_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "cts_timeout_collision:", + le32_to_cpu(tx->cts_timeout_collision), + accum_tx->cts_timeout_collision, + delta_tx->cts_timeout_collision, + max_tx->cts_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "ack_ba_timeout_collision:", + le32_to_cpu(tx->ack_or_ba_timeout_collision), + accum_tx->ack_or_ba_timeout_collision, + delta_tx->ack_or_ba_timeout_collision, + max_tx->ack_or_ba_timeout_collision); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_timeout:", + le32_to_cpu(tx->agg.ba_timeout), + accum_tx->agg.ba_timeout, + delta_tx->agg.ba_timeout, + max_tx->agg.ba_timeout); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg ba_resched_frames:", + le32_to_cpu(tx->agg.ba_reschedule_frames), + accum_tx->agg.ba_reschedule_frames, + delta_tx->agg.ba_reschedule_frames, + max_tx->agg.ba_reschedule_frames); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg_frame:", + le32_to_cpu(tx->agg.scd_query_agg_frame_cnt), + accum_tx->agg.scd_query_agg_frame_cnt, + delta_tx->agg.scd_query_agg_frame_cnt, + max_tx->agg.scd_query_agg_frame_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_no_agg:", + le32_to_cpu(tx->agg.scd_query_no_agg), + accum_tx->agg.scd_query_no_agg, + delta_tx->agg.scd_query_no_agg, + max_tx->agg.scd_query_no_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_agg:", + le32_to_cpu(tx->agg.scd_query_agg), + accum_tx->agg.scd_query_agg, + delta_tx->agg.scd_query_agg, + max_tx->agg.scd_query_agg); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg scd_query_mismatch:", + le32_to_cpu(tx->agg.scd_query_mismatch), + accum_tx->agg.scd_query_mismatch, + delta_tx->agg.scd_query_mismatch, + max_tx->agg.scd_query_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg frame_not_ready:", + le32_to_cpu(tx->agg.frame_not_ready), + accum_tx->agg.frame_not_ready, + delta_tx->agg.frame_not_ready, + max_tx->agg.frame_not_ready); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg underrun:", + le32_to_cpu(tx->agg.underrun), + accum_tx->agg.underrun, + delta_tx->agg.underrun, max_tx->agg.underrun); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg bt_prio_kill:", + le32_to_cpu(tx->agg.bt_prio_kill), + accum_tx->agg.bt_prio_kill, + delta_tx->agg.bt_prio_kill, + max_tx->agg.bt_prio_kill); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "agg rx_ba_rsp_cnt:", + le32_to_cpu(tx->agg.rx_ba_rsp_cnt), + accum_tx->agg.rx_ba_rsp_cnt, + delta_tx->agg.rx_ba_rsp_cnt, + max_tx->agg.rx_ba_rsp_cnt); + + if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) { + pos += scnprintf(buf + pos, bufsz - pos, + "tx power: (1/2 dB step)\n"); + if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna A:", + tx->tx_power.ant_a); + if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna B:", + tx->tx_power.ant_b); + if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c) + pos += scnprintf(buf + pos, bufsz - pos, + fmt_hex, "antenna C:", + tx->tx_power.ant_c); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, @@ -1060,8 +1693,347 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; - return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file, - user_buf, count, ppos); + int pos = 0; + char *buf; + int bufsz = sizeof(struct statistics_general) * 10 + 300; + ssize_t ret; + struct statistics_general_common *general, *accum_general; + struct statistics_general_common *delta_general, *max_general; + struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; + struct statistics_div *div, *accum_div, *delta_div, *max_div; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + general = &priv->statistics.common; + dbg = &priv->statistics.common.dbg; + div = &priv->statistics.common.div; + accum_general = &priv->accum_stats.common; + accum_dbg = &priv->accum_stats.common.dbg; + accum_div = &priv->accum_stats.common.div; + delta_general = &priv->delta_stats.common; + max_general = &priv->max_delta_stats.common; + delta_dbg = &priv->delta_stats.common.dbg; + max_dbg = &priv->max_delta_stats.common.dbg; + delta_div = &priv->delta_stats.common.div; + max_div = &priv->max_delta_stats.common.div; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_header, "Statistics_General:"); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature:", + le32_to_cpu(general->temperature)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "temperature_m:", + le32_to_cpu(general->temperature_m)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_value, "ttl_timestamp:", + le32_to_cpu(general->ttl_timestamp)); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_check:", + le32_to_cpu(dbg->burst_check), + accum_dbg->burst_check, + delta_dbg->burst_check, max_dbg->burst_check); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "burst_count:", + le32_to_cpu(dbg->burst_count), + accum_dbg->burst_count, + delta_dbg->burst_count, max_dbg->burst_count); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "wait_for_silence_timeout_count:", + le32_to_cpu(dbg->wait_for_silence_timeout_cnt), + accum_dbg->wait_for_silence_timeout_cnt, + delta_dbg->wait_for_silence_timeout_cnt, + max_dbg->wait_for_silence_timeout_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "sleep_time:", + le32_to_cpu(general->sleep_time), + accum_general->sleep_time, + delta_general->sleep_time, max_general->sleep_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_out:", + le32_to_cpu(general->slots_out), + accum_general->slots_out, + delta_general->slots_out, max_general->slots_out); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "slots_idle:", + le32_to_cpu(general->slots_idle), + accum_general->slots_idle, + delta_general->slots_idle, max_general->slots_idle); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_a:", + le32_to_cpu(div->tx_on_a), accum_div->tx_on_a, + delta_div->tx_on_a, max_div->tx_on_a); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "tx_on_b:", + le32_to_cpu(div->tx_on_b), accum_div->tx_on_b, + delta_div->tx_on_b, max_div->tx_on_b); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "exec_time:", + le32_to_cpu(div->exec_time), accum_div->exec_time, + delta_div->exec_time, max_div->exec_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "probe_time:", + le32_to_cpu(div->probe_time), accum_div->probe_time, + delta_div->probe_time, max_div->probe_time); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "rx_enable_counter:", + le32_to_cpu(general->rx_enable_counter), + accum_general->rx_enable_counter, + delta_general->rx_enable_counter, + max_general->rx_enable_counter); + pos += scnprintf(buf + pos, bufsz - pos, + fmt_table, "num_of_sos_states:", + le32_to_cpu(general->num_of_sos_states), + accum_general->num_of_sos_states, + delta_general->num_of_sos_states, + max_general->num_of_sos_states); + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct statistics_bt_activity) * 24) + 200; + ssize_t ret; + struct statistics_bt_activity *bt, *accum_bt; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + if (!priv->bt_enable_flag) + return -EINVAL; + + /* make request to uCode to retrieve statistics information */ + mutex_lock(&priv->mutex); + ret = iwl_send_statistics_request(priv, CMD_SYNC, false); + mutex_unlock(&priv->mutex); + + if (ret) { + IWL_ERR(priv, + "Error sending statistics request: %zd\n", ret); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + /* + * the statistic information display here is based on + * the last statistics notification from uCode + * might not reflect the current uCode activity + */ + bt = &priv->statistics.bt_activity; + accum_bt = &priv->accum_stats.bt_activity; + + pos += iwl_statistics_flag(priv, buf, bufsz); + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_BT:\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "\t\t\tcurrent\t\t\taccumulative\n"); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_req_cnt), + accum_bt->hi_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_tx_denied_cnt), + accum_bt->hi_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_req_cnt), + accum_bt->lo_priority_tx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_tx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_tx_denied_cnt), + accum_bt->lo_priority_tx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_req_cnt), + accum_bt->hi_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "hi_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->hi_priority_rx_denied_cnt), + accum_bt->hi_priority_rx_denied_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_req_cnt:\t\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_req_cnt), + accum_bt->lo_priority_rx_req_cnt); + pos += scnprintf(buf + pos, bufsz - pos, + "lo_priority_rx_denied_cnt:\t%u\t\t\t%u\n", + le32_to_cpu(bt->lo_priority_rx_denied_cnt), + accum_bt->lo_priority_rx_denied_cnt); + + pos += scnprintf(buf + pos, bufsz - pos, + "(rx)num_bt_kills:\t\t%u\t\t\t%u\n", + le32_to_cpu(priv->statistics.num_bt_kills), + priv->statistics.accum_num_bt_kills); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + int pos = 0; + char *buf; + int bufsz = (sizeof(struct reply_tx_error_statistics) * 24) + + (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; + ssize_t ret; + + if (!iwl_is_alive(priv)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(priv, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n"); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES), + priv->_agn.reply_tx_stats.pp_few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO), + priv->_agn.reply_tx_stats.pp_bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD), + priv->_agn.reply_tx_stats.pp_quiet_period); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK), + priv->_agn.reply_tx_stats.pp_calc_ttak); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY), + priv->_agn.reply_tx_stats.int_crossed_retry); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT), + priv->_agn.reply_tx_stats.short_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT), + priv->_agn.reply_tx_stats.long_limit); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN), + priv->_agn.reply_tx_stats.fifo_underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW), + priv->_agn.reply_tx_stats.drain_flow); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH), + priv->_agn.reply_tx_stats.rfkill_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE), + priv->_agn.reply_tx_stats.life_expire); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS), + priv->_agn.reply_tx_stats.dest_ps); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED), + priv->_agn.reply_tx_stats.host_abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY), + priv->_agn.reply_tx_stats.pp_delay); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID), + priv->_agn.reply_tx_stats.sta_invalid); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED), + priv->_agn.reply_tx_stats.frag_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE), + priv->_agn.reply_tx_stats.tid_disable); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED), + priv->_agn.reply_tx_stats.fifo_flush); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL), + priv->_agn.reply_tx_stats.insuff_cf_poll); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX), + priv->_agn.reply_tx_stats.fail_hw_drop); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_tx_fail_reason( + TX_STATUS_FAIL_NO_BEACON_ON_RADAR), + priv->_agn.reply_tx_stats.sta_color_mismatch); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_tx_stats.unknown); + + pos += scnprintf(buf + pos, bufsz - pos, + "\nStatistics_Agg_TX_Error:\n"); + + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK), + priv->_agn.reply_agg_tx_stats.underrun); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK), + priv->_agn.reply_agg_tx_stats.bt_prio); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK), + priv->_agn.reply_agg_tx_stats.few_bytes); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK), + priv->_agn.reply_agg_tx_stats.abort); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TTL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_ttl); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_try); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK), + priv->_agn.reply_agg_tx_stats.last_sent_bt_kill); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK), + priv->_agn.reply_agg_tx_stats.scd_query); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n", + iwl_get_agg_tx_fail_reason( + AGG_TX_STATE_TEST_BAD_CRC32_MSK), + priv->_agn.reply_agg_tx_stats.bad_crc32); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK), + priv->_agn.reply_agg_tx_stats.response); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK), + priv->_agn.reply_agg_tx_stats.dump_tx); + pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n", + iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK), + priv->_agn.reply_agg_tx_stats.delay_tx); + pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n", + priv->_agn.reply_agg_tx_stats.unknown); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; } static ssize_t iwl_dbgfs_sensitivity_read(struct file *file, @@ -1526,16 +2498,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = (struct iwl_priv *)file->private_data; - - return priv->cfg->ops->lib->debugfs_ops.bt_stats_read(file, - user_buf, count, ppos); -} - static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { @@ -1650,18 +2612,6 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - - if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error) - return priv->cfg->ops->lib->debugfs_ops.reply_tx_error( - file, user_buf, count, ppos); - else - return -ENODATA; -} DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index e84534c..f098eff 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -479,6 +479,10 @@ struct fw_desc { u32 len; /* bytes */ }; +struct fw_img { + struct fw_desc code, data; +}; + /* v1/v2 uCode file layout */ struct iwl_ucode_header { __le32 ver; /* major/minor/API/serial */ @@ -543,12 +547,13 @@ enum iwl_ucode_tlv_type { * enum iwl_ucode_tlv_flag - ucode API flags * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously * was a separate TLV but moved here to save space. - * @IWL_UCODE_TLV_FLAGS_RESERVED_1: reserved + * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, + * treats good CRC threshold as a boolean * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), - IWL_UCODE_TLV_FLAGS_RESERVED_1 = BIT(1), + IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), IWL_UCODE_TLV_FLAGS_MFP = BIT(2), }; @@ -794,12 +799,6 @@ struct iwl_calib_result { size_t buf_len; }; -enum ucode_type { - UCODE_NONE = 0, - UCODE_INIT, - UCODE_RT -}; - /* Sensitivity calib data */ struct iwl_sensitivity_data { u32 auto_corr_ofdm; @@ -1105,10 +1104,12 @@ struct iwl_force_reset { struct iwl_notification_wait { struct list_head list; - void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt); + void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt, + void *data); + void *fn_data; u8 cmd; - bool triggered; + bool triggered, aborted; }; enum iwl_rxon_context_id { @@ -1263,6 +1264,8 @@ struct iwl_priv { /* max number of station keys */ u8 sta_key_max_num; + bool new_scan_threshold_behaviour; + /* EEPROM MAC addresses */ struct mac_address addresses[2]; @@ -1270,11 +1273,10 @@ struct iwl_priv { int fw_index; /* firmware we're trying to load */ u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ - struct fw_desc ucode_code; /* runtime inst */ - struct fw_desc ucode_data; /* runtime data original */ - struct fw_desc ucode_init; /* initialization inst */ - struct fw_desc ucode_init_data; /* initialization data */ - enum ucode_type ucode_type; + struct fw_img ucode_rt; + struct fw_img ucode_init; + + enum iwlagn_ucode_subtype ucode_type; u8 ucode_write_complete; /* the image write is complete */ char firmware_name[25]; @@ -1472,8 +1474,6 @@ struct iwl_priv { struct tasklet_struct irq_tasklet; - struct delayed_work init_alive_start; - struct delayed_work alive_start; struct delayed_work scan_check; /* TX Power */ @@ -1506,7 +1506,6 @@ struct iwl_priv { struct timer_list statistics_periodic; struct timer_list ucode_trace; struct timer_list watchdog; - bool hw_ready; struct iwl_event_log event_log; diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 4027336..c839796 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -142,6 +142,45 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ * ******************************************************************************/ +/* + * The device's EEPROM semaphore prevents conflicts between driver and uCode + * when accessing the EEPROM; each access is a series of pulses to/from the + * EEPROM chip, not a single event, so even reads could conflict if they + * weren't arbitrated by the semaphore. + */ +static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) +{ + u16 count; + int ret; + + for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { + /* Request semaphore */ + iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + + /* See if we got it */ + ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, + EEPROM_SEM_TIMEOUT); + if (ret >= 0) { + IWL_DEBUG_EEPROM(priv, + "Acquired semaphore after %d tries.\n", + count+1); + return ret; + } + } + + return ret; +} + +static void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +{ + iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); + +} + static int iwl_eeprom_verify_signature(struct iwl_priv *priv) { u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; @@ -421,7 +460,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv); + ret = iwl_eeprom_acquire_semaphore(priv); if (ret < 0) { IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n"); ret = -ENOENT; @@ -488,7 +527,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) ret = 0; done: - priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv); + iwl_eeprom_release_semaphore(priv); err: if (ret) @@ -711,13 +750,6 @@ int iwl_init_channel_map(struct iwl_priv *priv) flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - /* Set the tx_power_user_lmt to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->tx_power_user_lmt) - priv->tx_power_user_lmt = - eeprom_ch_info[ch].max_power_avg; - ch_info++; } } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 9ce0525..c960c6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -294,9 +294,6 @@ extern const u8 iwl_eeprom_band_1[14]; struct iwl_eeprom_ops { const u32 regulatory_bands[7]; - int (*acquire_semaphore) (struct iwl_priv *priv); - void (*release_semaphore) (struct iwl_priv *priv); - u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); void (*update_enhanced_txpower) (struct iwl_priv *priv); }; diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 9309ff2..41207a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd) return --index & (n_bd - 1); } -/* TODO: Move fw_desc functions to iwl-pci.ko */ -static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (desc->v_addr) - dma_free_coherent(&pci_dev->dev, desc->len, - desc->v_addr, desc->p_addr); - desc->v_addr = NULL; - desc->len = 0; -} - -static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, - struct fw_desc *desc) -{ - if (!desc->len) { - desc->v_addr = NULL; - return -EINVAL; - } - - desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len, - &desc->p_addr, GFP_KERNEL); - return (desc->v_addr != NULL) ? 0 : -ENOMEM; -} - /* * we have 8 bits used like this: * diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index 5133741..aa4a906 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -73,10 +73,9 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr, return -ETIMEDOUT; } -int iwl_grab_nic_access(struct iwl_priv *priv) +int iwl_grab_nic_access_silent(struct iwl_priv *priv) { int ret; - u32 val; lockdep_assert_held(&priv->reg_lock); @@ -107,9 +106,6 @@ int iwl_grab_nic_access(struct iwl_priv *priv) (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (ret < 0) { - val = iwl_read32(priv, CSR_GP_CNTRL); - IWL_ERR(priv, - "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); return -EIO; } @@ -117,6 +113,18 @@ int iwl_grab_nic_access(struct iwl_priv *priv) return 0; } +int iwl_grab_nic_access(struct iwl_priv *priv) +{ + int ret = iwl_grab_nic_access_silent(priv); + if (ret) { + u32 val = iwl_read32(priv, CSR_GP_CNTRL); + IWL_ERR(priv, + "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); + } + + return ret; +} + void iwl_release_nic_access(struct iwl_priv *priv) { lockdep_assert_held(&priv->reg_lock); @@ -242,20 +250,32 @@ void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) spin_unlock_irqrestore(&priv->reg_lock, flags); } -u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words) { unsigned long flags; - u32 value; + int offs; + u32 *vals = buf; spin_lock_irqsave(&priv->reg_lock, flags); iwl_grab_nic_access(priv); iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); rmb(); - value = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + + for (offs = 0; offs < words; offs++) + vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->reg_lock, flags); +} + +u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +{ + u32 value; + + _iwl_read_targ_mem_words(priv, addr, &value, 1); + return value; } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index ab632ba..869edc5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -62,6 +62,7 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr, int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, int timeout); +int iwl_grab_nic_access_silent(struct iwl_priv *priv); int iwl_grab_nic_access(struct iwl_priv *priv); void iwl_release_nic_access(struct iwl_priv *priv); @@ -76,6 +77,16 @@ void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, u32 bits, u32 mask); void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); +void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, + void *buf, int words); + +#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \ + do { \ + BUILD_BUG_ON((bufsize) % sizeof(u32)); \ + _iwl_read_targ_mem_words(priv, addr, buf, \ + (bufsize) / sizeof(u32));\ + } while (0) + u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index b49819c..0053e9e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -225,55 +225,6 @@ err_bd: * ******************************************************************************/ -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_alive_resp *palive; - struct delayed_work *pwork; - - palive = &pkt->u.alive_frame; - - IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " - "0x%01X 0x%01X\n", - palive->is_valid, palive->ver_type, - palive->ver_subtype); - - priv->device_pointers.log_event_table = - le32_to_cpu(palive->log_event_table_ptr); - priv->device_pointers.error_event_table = - le32_to_cpu(palive->error_event_table_ptr); - - if (palive->ver_subtype == INITIALIZE_SUBTYPE) { - IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); - pwork = &priv->init_alive_start; - } else { - IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); - pwork = &priv->alive_start; - } - - /* We delay the ALIVE response by 5ms to - * give the HW RF Kill time to activate... */ - if (palive->is_valid == UCODE_VALID_OK) - queue_delayed_work(priv->workqueue, pwork, - msecs_to_jiffies(5)); - else { - IWL_WARN(priv, "%s uCode did not respond OK.\n", - (palive->ver_subtype == INITIALIZE_SUBTYPE) ? - "init" : "runtime"); - /* - * If fail to load init uCode, - * let's try to load the init uCode again. - * We should not get into this situation, but if it - * does happen, we should not move on and loading "runtime" - * without proper calibrate the device. - */ - if (palive->ver_subtype == INITIALIZE_SUBTYPE) - priv->ucode_type = UCODE_NONE; - queue_work(priv->workqueue, &priv->restart); - } -} - static void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -482,7 +433,6 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv, struct statistics_tx *tx, unsigned long stamp) { - const struct iwl_mod_params *mod_params = priv->cfg->mod_params; unsigned int msecs; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -498,13 +448,13 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv, if (msecs < 99) return; - if (mod_params->ack_check && !iwl_good_ack_health(priv, tx)) { + if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) { IWL_ERR(priv, "low ack count detected, restart firmware\n"); if (!iwl_force_reset(priv, IWL_FW_RESET, false)) return; } - if (mod_params->plcp_check && + if (iwlagn_mod_params.plcp_check && !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) iwl_force_reset(priv, IWL_RF_RESET, false); } @@ -895,7 +845,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, } /* In case of HW accelerated crypto and bad decryption, drop */ - if (!priv->cfg->mod_params->sw_crypto && + if (!iwlagn_mod_params.sw_crypto && iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; @@ -1125,7 +1075,6 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) handlers = priv->rx_handlers; - handlers[REPLY_ALIVE] = iwl_rx_reply_alive; handlers[REPLY_ERROR] = iwl_rx_reply_error; handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h deleted file mode 100644 index cb80bb4..0000000 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_spectrum_h__ -#define __iwl_spectrum_h__ -enum { /* ieee80211_basic_report.map */ - IEEE80211_BASIC_MAP_BSS = (1 << 0), - IEEE80211_BASIC_MAP_OFDM = (1 << 1), - IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2), - IEEE80211_BASIC_MAP_RADAR = (1 << 3), - IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4), - /* Bits 5-7 are reserved */ - -}; -struct ieee80211_basic_report { - u8 channel; - __le64 start_time; - __le16 duration; - u8 map; -} __packed; - -enum { /* ieee80211_measurement_request.mode */ - /* Bit 0 is reserved */ - IEEE80211_MEASUREMENT_ENABLE = (1 << 1), - IEEE80211_MEASUREMENT_REQUEST = (1 << 2), - IEEE80211_MEASUREMENT_REPORT = (1 << 3), - /* Bits 4-7 are reserved */ -}; - -enum { - IEEE80211_REPORT_BASIC = 0, /* required */ - IEEE80211_REPORT_CCA = 1, /* optional */ - IEEE80211_REPORT_RPI = 2, /* optional */ - /* 3-255 reserved */ -}; - -struct ieee80211_measurement_params { - u8 channel; - __le64 start_time; - __le16 duration; -} __packed; - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __packed; - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[0]; -} __packed; - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __packed; - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 80c3565..52b1b66 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -621,9 +621,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) struct iwl_cmd_meta *meta; struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; unsigned long flags; - void (*callback) (struct iwl_priv *priv, struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt); - /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -637,8 +634,6 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) return; } - spin_lock_irqsave(&priv->hcmd_lock, flags); - cmd_index = get_cmd_index(&txq->q, index, huge); cmd = txq->cmd[cmd_index]; meta = &txq->meta[cmd_index]; @@ -648,13 +643,14 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) dma_unmap_len(meta, len), PCI_DMA_BIDIRECTIONAL); - callback = NULL; /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); rxb->page = NULL; - } else - callback = meta->callback; + } else if (meta->callback) + meta->callback(priv, cmd, pkt); + + spin_lock_irqsave(&priv->hcmd_lock, flags); iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); @@ -669,7 +665,4 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) meta->flags = 0; spin_unlock_irqrestore(&priv->hcmd_lock, flags); - - if (callback) - callback(priv, cmd, pkt); } diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 5caa2ac..486544e 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -122,8 +122,10 @@ static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type) } -/* Various firmware commands need the list of supported rates, but with - the hight-bit set for basic rates */ +/* + * Various firmware commands need the list of supported rates, but with + * the hight-bit set for basic rates + */ static int lbs_add_rates(u8 *rates) { size_t i; @@ -425,7 +427,7 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len) return ie_len + 2; } -/*************************************************************************** +/* * Set Channel */ @@ -452,7 +454,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, -/*************************************************************************** +/* * Scanning */ @@ -538,8 +540,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, goto done; } - /* Validity check: the TLV holds TSF values with 8 bytes each, so - * the size in the TLV must match the nr_sets value */ + /* + * Validity check: the TLV holds TSF values with 8 bytes each, so + * the size in the TLV must match the nr_sets value + */ i = get_unaligned_le16(tsfdesc); tsfdesc += 2; if (i / 8 != scanresp->nr_sets) { @@ -581,8 +585,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, /* To find out the channel, we must parse the IEs */ ie = pos; - /* 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon - interval, capabilities */ + /* + * 6+1+8+2+2: size of BSSID, RSSI, time stamp, beacon + * interval, capabilities + */ ielen = left = len - (6 + 1 + 8 + 2 + 2); while (left >= 2) { u8 id, elen; @@ -790,7 +796,7 @@ static int lbs_cfg_scan(struct wiphy *wiphy, -/*************************************************************************** +/* * Events */ @@ -825,7 +831,7 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event) -/*************************************************************************** +/* * Connect/disconnect */ @@ -950,8 +956,10 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable) * Set WPA/WPA key material */ -/* like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we - * get rid of WEXT, this should go into host.h */ +/* + * like "struct cmd_ds_802_11_key_material", but with cmd_header. Once we + * get rid of WEXT, this should go into host.h + */ struct cmd_key_material { struct cmd_header hdr; @@ -1536,7 +1544,7 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev, } -/*************************************************************************** +/* * Get station */ @@ -1581,7 +1589,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * "Site survey", here just current channel and noise level */ @@ -1614,7 +1622,7 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * Change interface */ @@ -1656,11 +1664,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, -/*************************************************************************** +/* * IBSS (Ad-Hoc) */ -/* The firmware needs the following bits masked out of the beacon-derived +/* + * The firmware needs the following bits masked out of the beacon-derived * capability field when associating/joining to a BSS: * 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused) */ @@ -1999,7 +2008,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -/*************************************************************************** +/* * Initialization */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7e8a658..6a96fc9 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1,7 +1,7 @@ -/** - * This file contains the handling of command. - * It prepares command and sends it to firmware when it is ready. - */ +/* + * This file contains the handling of command. + * It prepares command and sends it to firmware when it is ready. + */ #include <linux/kfifo.h> #include <linux/sched.h> @@ -16,14 +16,14 @@ #define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf))) /** - * @brief Simple callback that copies response back into command + * lbs_cmd_copyback - Simple callback that copies response back into command * - * @param priv A pointer to struct lbs_private structure - * @param extra A pointer to the original command structure for which - * 'resp' is a response - * @param resp A pointer to the command response + * @priv: A pointer to &struct lbs_private structure + * @extra: A pointer to the original command structure for which + * 'resp' is a response + * @resp: A pointer to the command response * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp) @@ -38,15 +38,15 @@ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, EXPORT_SYMBOL_GPL(lbs_cmd_copyback); /** - * @brief Simple callback that ignores the result. Use this if - * you just want to send a command to the hardware, but don't + * lbs_cmd_async_callback - Simple callback that ignores the result. + * Use this if you just want to send a command to the hardware, but don't * care for the result. * - * @param priv ignored - * @param extra ignored - * @param resp ignored + * @priv: ignored + * @extra: ignored + * @resp: ignored * - * @return 0 for success + * returns: 0 for success */ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, struct cmd_header *resp) @@ -56,10 +56,11 @@ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra, /** - * @brief Checks whether a command is allowed in Power Save mode + * is_command_allowed_in_ps - tests if a command is allowed in Power Save mode + * + * @cmd: the command ID * - * @param command the command ID - * @return 1 if allowed, 0 if not allowed + * returns: 1 if allowed, 0 if not allowed */ static u8 is_command_allowed_in_ps(u16 cmd) { @@ -75,11 +76,12 @@ static u8 is_command_allowed_in_ps(u16 cmd) } /** - * @brief Updates the hardware details like MAC address and regulatory region + * lbs_update_hw_spec - Updates the hardware details like MAC address + * and regulatory region * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_update_hw_spec(struct lbs_private *priv) { @@ -217,14 +219,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg); /** - * @brief Sets the Power Save mode + * lbs_set_ps_mode - Sets the Power Save mode * - * @param priv A pointer to struct lbs_private structure - * @param cmd_action The Power Save operation (PS_MODE_ACTION_ENTER_PS or + * @priv: A pointer to &struct lbs_private structure + * @cmd_action: The Power Save operation (PS_MODE_ACTION_ENTER_PS or * PS_MODE_ACTION_EXIT_PS) - * @param block Whether to block on a response or not + * @block: Whether to block on a response or not * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block) { @@ -417,13 +419,13 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep) } /** - * @brief Set an SNMP MIB value + * lbs_set_snmp_mib - Set an SNMP MIB value * - * @param priv A pointer to struct lbs_private structure - * @param oid The OID to set in the firmware - * @param val Value to set the OID to + * @priv: A pointer to &struct lbs_private structure + * @oid: The OID to set in the firmware + * @val: Value to set the OID to * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val) { @@ -467,13 +469,13 @@ out: } /** - * @brief Get an SNMP MIB value + * lbs_get_snmp_mib - Get an SNMP MIB value * - * @param priv A pointer to struct lbs_private structure - * @param oid The OID to retrieve from the firmware - * @param out_val Location for the returned value + * @priv: A pointer to &struct lbs_private structure + * @oid: The OID to retrieve from the firmware + * @out_val: Location for the returned value * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val) { @@ -510,14 +512,14 @@ out: } /** - * @brief Get the min, max, and current TX power + * lbs_get_tx_power - Get the min, max, and current TX power * - * @param priv A pointer to struct lbs_private structure - * @param curlevel Current power level in dBm - * @param minlevel Minimum supported power level in dBm (optional) - * @param maxlevel Maximum supported power level in dBm (optional) + * @priv: A pointer to &struct lbs_private structure + * @curlevel: Current power level in dBm + * @minlevel: Minimum supported power level in dBm (optional) + * @maxlevel: Maximum supported power level in dBm (optional) * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, s16 *maxlevel) @@ -545,12 +547,12 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel, } /** - * @brief Set the TX power + * lbs_set_tx_power - Set the TX power * - * @param priv A pointer to struct lbs_private structure - * @param dbm The desired power level in dBm + * @priv: A pointer to &struct lbs_private structure + * @dbm: The desired power level in dBm * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) { @@ -573,12 +575,13 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm) } /** - * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW) + * lbs_set_monitor_mode - Enable or disable monitor mode + * (only implemented on OLPC usb8388 FW) * - * @param priv A pointer to struct lbs_private structure - * @param enable 1 to enable monitor mode, 0 to disable + * @priv: A pointer to &struct lbs_private structure + * @enable: 1 to enable monitor mode, 0 to disable * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) { @@ -604,11 +607,11 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable) } /** - * @brief Get the radio channel + * lbs_get_channel - Get the radio channel * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return The channel on success, error on failure + * returns: The channel on success, error on failure */ static int lbs_get_channel(struct lbs_private *priv) { @@ -650,12 +653,12 @@ int lbs_update_channel(struct lbs_private *priv) } /** - * @brief Set the radio channel + * lbs_set_channel - Set the radio channel * - * @param priv A pointer to struct lbs_private structure - * @param channel The desired channel, or 0 to clear a locked channel + * @priv: A pointer to &struct lbs_private structure + * @channel: The desired channel, or 0 to clear a locked channel * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_set_channel(struct lbs_private *priv, u8 channel) { @@ -686,12 +689,13 @@ out: } /** - * @brief Get current RSSI and noise floor + * lbs_get_rssi - Get current RSSI and noise floor * - * @param priv A pointer to struct lbs_private structure - * @param rssi On successful return, signal level in mBm + * @priv: A pointer to &struct lbs_private structure + * @rssi: On successful return, signal level in mBm + * @nf: On successful return, Noise floor * - * @return The channel on success, error on failure + * returns: The channel on success, error on failure */ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) { @@ -719,13 +723,14 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) } /** - * @brief Send regulatory and 802.11d domain information to the firmware + * lbs_set_11d_domain_info - Send regulatory and 802.11d domain information + * to the firmware * - * @param priv pointer to struct lbs_private - * @param request cfg80211 regulatory request structure - * @param bands the device's supported bands and channels + * @priv: pointer to &struct lbs_private + * @request: cfg80211 regulatory request structure + * @bands: the device's supported bands and channels * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_set_11d_domain_info(struct lbs_private *priv, struct regulatory_request *request, @@ -842,15 +847,15 @@ int lbs_set_11d_domain_info(struct lbs_private *priv, } /** - * @brief Read a MAC, Baseband, or RF register + * lbs_get_reg - Read a MAC, Baseband, or RF register * - * @param priv pointer to struct lbs_private - * @param cmd register command, one of CMD_MAC_REG_ACCESS, - * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS - * @param offset byte offset of the register to get - * @param value on success, the value of the register at 'offset' + * @priv: pointer to &struct lbs_private + * @reg: register command, one of CMD_MAC_REG_ACCESS, + * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS + * @offset: byte offset of the register to get + * @value: on success, the value of the register at 'offset' * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value) { @@ -886,15 +891,15 @@ out: } /** - * @brief Write a MAC, Baseband, or RF register + * lbs_set_reg - Write a MAC, Baseband, or RF register * - * @param priv pointer to struct lbs_private - * @param cmd register command, one of CMD_MAC_REG_ACCESS, - * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS - * @param offset byte offset of the register to set - * @param value the value to write to the register at 'offset' + * @priv: pointer to &struct lbs_private + * @reg: register command, one of CMD_MAC_REG_ACCESS, + * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS + * @offset: byte offset of the register to set + * @value: the value to write to the register at 'offset' * - * @return 0 on success, error code on failure + * returns: 0 on success, error code on failure */ int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value) { @@ -1023,7 +1028,7 @@ static void lbs_submit_command(struct lbs_private *priv, lbs_deb_leave(LBS_DEB_HOST); } -/** +/* * This function inserts command node to cmdfreeq * after cleans it. Requires priv->driver_lock held. */ @@ -1125,11 +1130,12 @@ void lbs_set_mac_control(struct lbs_private *priv) } /** - * @brief This function allocates the command buffer and link - * it to command free queue. + * lbs_allocate_cmd_buffer - allocates the command buffer and links + * it to command free queue + * + * @priv: A pointer to &struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * returns: 0 for success or -1 on error */ int lbs_allocate_cmd_buffer(struct lbs_private *priv) { @@ -1171,10 +1177,11 @@ done: } /** - * @brief This function frees the command buffer. + * lbs_free_cmd_buffer - free the command buffer * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * + * returns: 0 for success */ int lbs_free_cmd_buffer(struct lbs_private *priv) { @@ -1211,11 +1218,13 @@ done: } /** - * @brief This function gets a free command node if available in - * command free queue. + * lbs_get_free_cmd_node - gets a free command node if available in + * command free queue + * + * @priv: A pointer to &struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL + * returns: A pointer to &cmd_ctrl_node structure on success + * or %NULL on error */ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) { @@ -1245,12 +1254,12 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv) } /** - * @brief This function executes next command in command - * pending queue. It will put firmware back to PS mode - * if applicable. + * lbs_execute_next_command - execute next command in command + * pending queue. Will put firmware back to PS mode if applicable. * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * + * returns: 0 on success or -1 on error */ int lbs_execute_next_command(struct lbs_private *priv) { @@ -1454,12 +1463,12 @@ out: } /** - * @brief This function checks condition and prepares to - * send sleep confirm command to firmware if ok. + * lbs_ps_confirm_sleep - checks condition and prepares to + * send sleep confirm command to firmware if ok + * + * @priv: A pointer to &struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @param psmode Power Saving mode - * @return n/a + * returns: n/a */ void lbs_ps_confirm_sleep(struct lbs_private *priv) { @@ -1499,16 +1508,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) /** - * @brief Configures the transmission power control functionality. + * lbs_set_tpc_cfg - Configures the transmission power control functionality * - * @param priv A pointer to struct lbs_private structure - * @param enable Transmission power control enable - * @param p0 Power level when link quality is good (dBm). - * @param p1 Power level when link quality is fair (dBm). - * @param p2 Power level when link quality is poor (dBm). - * @param usesnr Use Signal to Noise Ratio in TPC + * @priv: A pointer to &struct lbs_private structure + * @enable: Transmission power control enable + * @p0: Power level when link quality is good (dBm). + * @p1: Power level when link quality is fair (dBm). + * @p2: Power level when link quality is poor (dBm). + * @usesnr: Use Signal to Noise Ratio in TPC * - * @return 0 on success + * returns: 0 on success */ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, int8_t p2, int usesnr) @@ -1531,15 +1540,15 @@ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1, } /** - * @brief Configures the power adaptation settings. + * lbs_set_power_adapt_cfg - Configures the power adaptation settings * - * @param priv A pointer to struct lbs_private structure - * @param enable Power adaptation enable - * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm). - * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). - * @param p2 Power level for 48 and 54 Mbps (dBm). + * @priv: A pointer to &struct lbs_private structure + * @enable: Power adaptation enable + * @p0: Power level for 1, 2, 5.5 and 11 Mbps (dBm). + * @p1: Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm). + * @p2: Power level for 48 and 54 Mbps (dBm). * - * @return 0 on Success + * returns: 0 on Success */ int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0, diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 5e95da9..03e5289 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -1,7 +1,7 @@ -/** - * This file contains the handling of command - * responses as well as events generated by firmware. - */ +/* + * This file contains the handling of command + * responses as well as events generated by firmware. + */ #include <linux/slab.h> #include <linux/delay.h> #include <linux/sched.h> @@ -12,12 +12,13 @@ #include "cmd.h" /** - * @brief This function handles disconnect event. it - * reports disconnect to upper layer, clean tx/rx packets, - * reset link state etc. + * lbs_mac_event_disconnected - handles disconnect event. It + * reports disconnect to upper layer, clean tx/rx packets, + * reset link state etc. + * + * @priv: A pointer to struct lbs_private structure * - * @param priv A pointer to struct lbs_private structure - * @return n/a + * returns: n/a */ void lbs_mac_event_disconnected(struct lbs_private *priv) { diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index fbf3b033..851fe7b 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -849,15 +849,14 @@ static struct debug_data items[] = { static int num_of_items = ARRAY_SIZE(items); /** - * @brief proc read function + * lbs_debugfs_read - proc read function * - * @param page pointer to buffer - * @param s read data starting position - * @param off offset - * @param cnt counter - * @param eof end of file flag - * @param data data to output - * @return number of output data + * @file: file to read + * @userbuf: pointer to buffer + * @count: number of bytes to read + * @ppos: read data starting position + * + * returns: amount of data read or negative error code */ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) @@ -897,13 +896,14 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, } /** - * @brief proc write function + * lbs_debugfs_write - proc write function + * + * @f: file pointer + * @buf: pointer to data buffer + * @cnt: data number to write + * @ppos: file position * - * @param f file pointer - * @param buf pointer to data buffer - * @param cnt data number to write - * @param data data to write - * @return number of data + * returns: amount of data written */ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, size_t cnt, loff_t *ppos) @@ -966,11 +966,11 @@ static const struct file_operations lbs_debug_fops = { }; /** - * @brief create debug proc file + * lbs_debug_init - create debug proc file + * + * @priv: pointer to &struct lbs_private * - * @param priv pointer struct lbs_private - * @param dev pointer net_device - * @return N/A + * returns: N/A */ static void lbs_debug_init(struct lbs_private *priv) { diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 2ae752d..da0b05b 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -1,8 +1,8 @@ -/** - * This file contains declaration referring to - * functions defined in other source files - */ +/* + * This file contains declaration referring to + * functions defined in other source files + */ #ifndef _LBS_DECL_H_ #define _LBS_DECL_H_ diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index d00c728..92b5b1f 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -1,7 +1,7 @@ -/** - * This header file contains global constant/enum definitions, - * global variable declaration. - */ +/* + * This header file contains global constant/enum definitions, + * global variable declaration. + */ #ifndef _LBS_DEFS_H_ #define _LBS_DEFS_H_ @@ -123,19 +123,19 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in -/** Buffer Constants */ +/* Buffer Constants */ /* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical -* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas -* driver has more local TxPDs. Each TxPD on the host memory is associated -* with a Tx control node. The driver maintains 8 RxPD descriptors for -* station firmware to store Rx packet information. -* -* Current version of MAC has a 32x6 multicast address buffer. -* -* 802.11b can have up to 14 channels, the driver keeps the -* BSSID(MAC address) of each APs or Ad hoc stations it has sensed. -*/ + * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas + * driver has more local TxPDs. Each TxPD on the host memory is associated + * with a Tx control node. The driver maintains 8 RxPD descriptors for + * station firmware to store Rx packet information. + * + * Current version of MAC has a 32x6 multicast address buffer. + * + * 802.11b can have up to 14 channels, the driver keeps the + * BSSID(MAC address) of each APs or Ad hoc stations it has sensed. + */ #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 #define LBS_NUM_CMD_BUFFERS 10 @@ -166,7 +166,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define WOL_RESULT_NOSPC_ERR 1 #define WOL_RESULT_EEXIST_ERR 2 -/** Misc constants */ +/* Misc constants */ /* This section defines 802.11 specific contants */ #define MRVDRV_MAX_BSS_DESCRIPTS 16 @@ -183,7 +183,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_IE_LENGTH 9 -/* Values used to populate the struct mrvl_mesh_ie. The only time you need this +/* + * Values used to populate the struct mrvl_mesh_ie. The only time you need this * is when enabling the mesh using CMD_MESH_CONFIG. */ #define MARVELL_MESH_IE_TYPE 4 @@ -193,7 +194,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MARVELL_MESH_METRIC_ID 0 #define MARVELL_MESH_CAPABILITY 0 -/** INT status Bit Definition*/ +/* INT status Bit Definition */ #define MRVDRV_TX_DNLD_RDY 0x0001 #define MRVDRV_RX_UPLD_RDY 0x0002 #define MRVDRV_CMD_DNLD_RDY 0x0004 @@ -208,59 +209,63 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define TPC_DEFAULT_P1 10 #define TPC_DEFAULT_P2 13 -/** TxPD status */ +/* TxPD status */ -/* Station firmware use TxPD status field to report final Tx transmit -* result, Bit masks are used to present combined situations. -*/ +/* + * Station firmware use TxPD status field to report final Tx transmit + * result, Bit masks are used to present combined situations. + */ #define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 #define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 -/** Tx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. +/* Tx mesh flag */ +/* + * Currently we are using normal WDS flag as mesh flag. * TODO: change to proper mesh flag when MAC understands it. */ #define TxPD_CONTROL_WDS_FRAME (1<<17) #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME -/** Mesh interface ID */ +/* Mesh interface ID */ #define MESH_IFACE_ID 0x0001 -/** Mesh id should be in bits 14-13-12 */ +/* Mesh id should be in bits 14-13-12 */ #define MESH_IFACE_BIT_OFFSET 0x000c -/** Mesh enable bit in FW capability */ +/* Mesh enable bit in FW capability */ #define MESH_CAPINFO_ENABLE_MASK (1<<16) -/** FW definition from Marvell v4 */ +/* FW definition from Marvell v4 */ #define MRVL_FW_V4 (0x04) -/** FW definition from Marvell v5 */ +/* FW definition from Marvell v5 */ #define MRVL_FW_V5 (0x05) -/** FW definition from Marvell v10 */ +/* FW definition from Marvell v10 */ #define MRVL_FW_V10 (0x0a) -/** FW major revision definition */ +/* FW major revision definition */ #define MRVL_FW_MAJOR_REV(x) ((x)>>24) -/** RxPD status */ +/* RxPD status */ #define MRVDRV_RXPD_STATUS_OK 0x0001 -/** RxPD status - Received packet types */ -/** Rx mesh flag */ -/* Currently we are using normal WDS flag as mesh flag. +/* RxPD status - Received packet types */ +/* Rx mesh flag */ +/* + * Currently we are using normal WDS flag as mesh flag. * TODO: change to proper mesh flag when MAC understands it. */ #define RxPD_CONTROL_WDS_FRAME (0x40) #define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME -/** RSSI-related defines */ -/* RSSI constants are used to implement 802.11 RSSI threshold -* indication. if the Rx packet signal got too weak for 5 consecutive -* times, miniport driver (driver) will report this event to wrapper -*/ +/* RSSI-related defines */ +/* + * RSSI constants are used to implement 802.11 RSSI threshold + * indication. if the Rx packet signal got too weak for 5 consecutive + * times, miniport driver (driver) will report this event to wrapper + */ #define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) -/** RTS/FRAG related defines */ +/* RTS/FRAG related defines */ #define MRVDRV_RTS_MIN_VALUE 0 #define MRVDRV_RTS_MAX_VALUE 2347 #define MRVDRV_FRAG_MIN_VALUE 256 @@ -300,36 +305,36 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MAX_LEDS 8 -/** Global Variable Declaration */ +/* Global Variable Declaration */ extern const char lbs_driver_version[]; extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE]; -/** ENUM definition*/ -/** SNRNF_TYPE */ +/* ENUM definition */ +/* SNRNF_TYPE */ enum SNRNF_TYPE { TYPE_BEACON = 0, TYPE_RXPD, MAX_TYPE_B }; -/** SNRNF_DATA*/ +/* SNRNF_DATA */ enum SNRNF_DATA { TYPE_NOAVG = 0, TYPE_AVG, MAX_TYPE_AVG }; -/** LBS_802_11_POWER_MODE */ +/* LBS_802_11_POWER_MODE */ enum LBS_802_11_POWER_MODE { LBS802_11POWERMODECAM, LBS802_11POWERMODEMAX_PSP, LBS802_11POWERMODEFAST_PSP, - /*not a real mode, defined as an upper bound */ + /* not a real mode, defined as an upper bound */ LBS802_11POWEMODEMAX }; -/** PS_STATE */ +/* PS_STATE */ enum PS_STATE { PS_STATE_FULL_POWER, PS_STATE_AWAKE, @@ -337,7 +342,7 @@ enum PS_STATE { PS_STATE_SLEEP }; -/** DNLD_STATE */ +/* DNLD_STATE */ enum DNLD_STATE { DNLD_RES_RECEIVED, DNLD_DATA_SENT, @@ -345,19 +350,19 @@ enum DNLD_STATE { DNLD_BOOTCMD_SENT, }; -/** LBS_MEDIA_STATE */ +/* LBS_MEDIA_STATE */ enum LBS_MEDIA_STATE { LBS_CONNECTED, LBS_DISCONNECTED }; -/** LBS_802_11_PRIVACY_FILTER */ +/* LBS_802_11_PRIVACY_FILTER */ enum LBS_802_11_PRIVACY_FILTER { LBS802_11PRIVFILTERACCEPTALL, LBS802_11PRIVFILTER8021XWEP }; -/** mv_ms_type */ +/* mv_ms_type */ enum mv_ms_type { MVMS_DAT = 0, MVMS_CMD = 1, @@ -365,14 +370,14 @@ enum mv_ms_type { MVMS_EVENT }; -/** KEY_TYPE_ID */ +/* KEY_TYPE_ID */ enum KEY_TYPE_ID { KEY_TYPE_ID_WEP = 0, KEY_TYPE_ID_TKIP, KEY_TYPE_ID_AES }; -/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ +/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ enum KEY_INFO_WPA { KEY_INFO_WPA_MCAST = 0x01, KEY_INFO_WPA_UNICAST = 0x02, diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index bc461eb..76d018b 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -1,8 +1,8 @@ -/** - * This file contains definitions and data structures specific - * to Marvell 802.11 NIC. It contains the Device Information - * structure struct lbs_private.. - */ +/* + * This file contains definitions and data structures specific + * to Marvell 802.11 NIC. It contains the Device Information + * structure struct lbs_private.. + */ #ifndef _LBS_DEV_H_ #define _LBS_DEV_H_ @@ -12,7 +12,7 @@ #include <linux/kfifo.h> -/** sleep_params */ +/* sleep_params */ struct sleep_params { uint16_t sp_error; uint16_t sp_offset; @@ -23,7 +23,7 @@ struct sleep_params { }; -/** Private structure for the MV device */ +/* Private structure for the MV device */ struct lbs_private { /* Basic networking */ @@ -125,12 +125,12 @@ struct lbs_private { /* Events sent from hardware to driver */ struct kfifo event_fifo; - /** thread to service interrupts */ + /* thread to service interrupts */ struct task_struct *main_thread; wait_queue_head_t waitq; struct workqueue_struct *work_thread; - /** Encryption stuff */ + /* Encryption stuff */ u8 authtype_auto; u8 wep_tx_key; u8 wep_key[4][WLAN_KEY_LEN_WEP104]; @@ -162,7 +162,7 @@ struct lbs_private { s16 txpower_min; s16 txpower_max; - /** Scanning */ + /* Scanning */ struct delayed_work scan_work; int scan_channel; /* Queue of things waiting for scan completion */ diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 50193aa..29dbce4 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -20,7 +20,8 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev, strcpy(info->version, lbs_driver_version); } -/* All 8388 parts have 16KiB EEPROM size at the time of writing. +/* + * All 8388 parts have 16KiB EEPROM size at the time of writing. * In case that changes this needs fixing. */ #define LBS_EEPROM_LEN 16384 diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 6cb6935..2e2dbfa 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -1,7 +1,7 @@ -/** - * This file function prototypes, data structure - * and definitions for all the host/station commands - */ +/* + * This file function prototypes, data structure + * and definitions for all the host/station commands + */ #ifndef _LBS_HOST_H_ #define _LBS_HOST_H_ @@ -13,9 +13,10 @@ #define CMD_OPTION_WAITFORRSP 0x0002 -/** Host command IDs */ +/* Host command IDs */ -/* Return command are almost always the same as the host command, but with +/* + * Return command are almost always the same as the host command, but with * bit 15 set high. There are a few exceptions, though... */ #define CMD_RET(cmd) (0x8000 | cmd) @@ -251,7 +252,7 @@ enum cmd_mesh_config_types { CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */ }; -/** Card Event definition */ +/* Card Event definition */ #define MACREG_INT_CODE_TX_PPA_FREE 0 #define MACREG_INT_CODE_TX_DMA_DONE 1 #define MACREG_INT_CODE_LINK_LOST_W_SCAN 2 @@ -624,12 +625,14 @@ struct cmd_ds_802_11_rf_channel { struct cmd_ds_802_11_rssi { struct cmd_header hdr; - /* request: number of beacons (N) to average the SNR and NF over + /* + * request: number of beacons (N) to average the SNR and NF over * response: SNR of most recent beacon */ __le16 n_or_snr; - /* The following fields are only set in the response. + /* + * The following fields are only set in the response. * In the request these are reserved and should be set to 0. */ __le16 nf; /* most recent beacon noise floor */ @@ -680,14 +683,16 @@ struct cmd_ds_802_11_ps_mode { __le16 action; - /* Interval for keepalive in PS mode: + /* + * Interval for keepalive in PS mode: * 0x0000 = don't change * 0x001E = firmware default * 0xFFFF = disable */ __le16 nullpktinterval; - /* Number of DTIM intervals to wake up for: + /* + * Number of DTIM intervals to wake up for: * 0 = don't change * 1 = firmware default * 5 = max @@ -697,7 +702,8 @@ struct cmd_ds_802_11_ps_mode { __le16 reserved; __le16 locallisteninterval; - /* AdHoc awake period (FW v9+ only): + /* + * AdHoc awake period (FW v9+ only): * 0 = don't change * 1 = always awake (IEEE standard behavior) * 2 - 31 = sleep for (n - 1) periods and awake for 1 period @@ -771,7 +777,8 @@ struct adhoc_bssdesc { __le16 capability; u8 rates[MAX_RATES]; - /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the + /* + * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the * Adhoc join command and will cause a binary layout mismatch with * the firmware */ diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 8712cb2..4dfd48f 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -312,7 +312,8 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r #define CF8385_MANFID 0x02df #define CF8385_CARDID 0x8103 -/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when +/* + * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when * that gets fixed. Currently there's no way to access it from the probe hook. */ static inline u32 get_model(u16 manf_id, u16 card_id) @@ -621,8 +622,10 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) if (remain < count) count = remain; - /* "write the number of bytes to be sent to the I/O Command - * write length register" */ + /* + * "write the number of bytes to be sent to the I/O Command + * write length register" + */ if_cs_write16(card, IF_CS_CMD_LEN, count); /* "write this to I/O Command port register as 16 bit writes */ @@ -631,16 +634,22 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw) &fw->data[sent], count >> 1); - /* "Assert the download over interrupt command in the Host - * status register" */ + /* + * "Assert the download over interrupt command in the Host + * status register" + */ if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND); - /* "Assert the download over interrupt command in the Card - * interrupt case register" */ + /* + * "Assert the download over interrupt command in the Card + * interrupt case register" + */ if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND); - /* "The host polls the Card Status register ... for 50 ms before - declaring a failure */ + /* + * "The host polls the Card Status register ... for 50 ms before + * declaring a failure" + */ ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, IF_CS_BIT_COMMAND); if (ret < 0) { @@ -841,7 +850,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) /* * Most of the libertas cards can do unaligned register access, but some - * weird ones can not. That's especially true for the CF8305 card. + * weird ones cannot. That's especially true for the CF8305 card. */ card->align_regs = 0; @@ -913,8 +922,10 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } - /* Clear any interrupt cause that happened while sending - * firmware/initializing card */ + /* + * Clear any interrupt cause that happened while sending + * firmware/initializing card + */ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); if_cs_enable_ints(card); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 078ef43d9..67de5b3 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -143,8 +143,10 @@ static void spu_transaction_finish(struct if_spi_card *card) card->prev_xfer_time = jiffies; } -/* Write out a byte buffer to an SPI register, - * using a series of 16-bit transfers. */ +/* + * Write out a byte buffer to an SPI register, + * using a series of 16-bit transfers. + */ static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len) { int err = 0; @@ -208,8 +210,10 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len) struct spi_transfer dummy_trans; struct spi_transfer data_trans; - /* You must take an even number of bytes from the SPU, even if you - * don't care about the last one. */ + /* + * You must take an even number of bytes from the SPU, even if you + * don't care about the last one. + */ BUG_ON(len & 0x1); spu_transaction_init(card); @@ -258,8 +262,10 @@ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val) return ret; } -/* Read 32 bits from an SPI register. - * The low 16 bits are read first. */ +/* + * Read 32 bits from an SPI register. + * The low 16 bits are read first. + */ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) { __le32 buf; @@ -271,13 +277,15 @@ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val) return err; } -/* Keep reading 16 bits from an SPI register until you get the correct result. +/* + * Keep reading 16 bits from an SPI register until you get the correct result. * * If mask = 0, the correct result is any non-zero number. * If mask != 0, the correct result is any number where * number & target_mask == target * - * Returns -ETIMEDOUT if a second passes without the correct result. */ + * Returns -ETIMEDOUT if a second passes without the correct result. + */ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, u16 target_mask, u16 target) { @@ -305,8 +313,10 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg, } } -/* Read 16 bits from an SPI register until you receive a specific value. - * Returns -ETIMEDOUT if a 4 tries pass without success. */ +/* + * Read 16 bits from an SPI register until you receive a specific value. + * Returns -ETIMEDOUT if a 4 tries pass without success. + */ static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target) { int err, try; @@ -328,8 +338,10 @@ static int spu_set_interrupt_mode(struct if_spi_card *card, { int err = 0; - /* We can suppress a host interrupt by clearing the appropriate - * bit in the "host interrupt status mask" register */ + /* + * We can suppress a host interrupt by clearing the appropriate + * bit in the "host interrupt status mask" register + */ if (suppress_host_int) { err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0); if (err) @@ -345,10 +357,12 @@ static int spu_set_interrupt_mode(struct if_spi_card *card, return err; } - /* If auto-interrupts are on, the completion of certain transactions + /* + * If auto-interrupts are on, the completion of certain transactions * will trigger an interrupt automatically. If auto-interrupts * are off, we need to set the "Card Interrupt Cause" register to - * trigger a card interrupt. */ + * trigger a card interrupt. + */ if (auto_int) { err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG, IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO | @@ -402,8 +416,10 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes) int err = 0; u32 delay; - /* We have to start up in timed delay mode so that we can safely - * read the Delay Read Register. */ + /* + * We have to start up in timed delay mode so that we can safely + * read the Delay Read Register. + */ card->use_dummy_writes = 0; err = spu_set_bus_mode(card, IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING | @@ -459,8 +475,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, /* Load helper firmware image */ while (bytes_remaining > 0) { - /* Scratch pad 1 should contain the number of bytes we - * want to download to the firmware */ + /* + * Scratch pad 1 should contain the number of bytes we + * want to download to the firmware + */ err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, HELPER_FW_LOAD_CHUNK_SZ); if (err) @@ -472,8 +490,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, if (err) goto out; - /* Feed the data into the command read/write port reg - * in chunks of 64 bytes */ + /* + * Feed the data into the command read/write port reg + * in chunks of 64 bytes + */ memset(temp, 0, sizeof(temp)); memcpy(temp, fw, min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ)); @@ -495,9 +515,11 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, fw += HELPER_FW_LOAD_CHUNK_SZ; } - /* Once the helper / single stage firmware download is complete, + /* + * Once the helper / single stage firmware download is complete, * write 0 to scratch pad 1 and interrupt the - * bootloader. This completes the helper download. */ + * bootloader. This completes the helper download. + */ err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK); if (err) goto out; @@ -517,16 +539,20 @@ out: return err; } -/* Returns the length of the next packet the firmware expects us to send - * Sets crc_err if the previous transfer had a CRC error. */ +/* + * Returns the length of the next packet the firmware expects us to send. + * Sets crc_err if the previous transfer had a CRC error. + */ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card, int *crc_err) { u16 len; int err = 0; - /* wait until the host interrupt status register indicates - * that we are ready to download */ + /* + * wait until the host interrupt status register indicates + * that we are ready to download + */ err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG, IF_SPI_HIST_CMD_DOWNLOAD_RDY, IF_SPI_HIST_CMD_DOWNLOAD_RDY); @@ -587,8 +613,10 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card, goto out; } if (bytes < 0) { - /* If there are no more bytes left, we would normally - * expect to have terminated with len = 0 */ + /* + * If there are no more bytes left, we would normally + * expect to have terminated with len = 0 + */ lbs_pr_err("Firmware load wants more bytes " "than we have to offer.\n"); break; @@ -660,14 +688,18 @@ static int if_spi_c2h_cmd(struct if_spi_card *card) u16 len; u8 i; - /* We need a buffer big enough to handle whatever people send to - * hw_host_to_card */ + /* + * We need a buffer big enough to handle whatever people send to + * hw_host_to_card + */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE); BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE); - /* It's just annoying if the buffer size isn't a multiple of 4, because - * then we might have len < IF_SPI_CMD_BUF_SIZE but - * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */ + /* + * It's just annoying if the buffer size isn't a multiple of 4, because + * then we might have len < IF_SPI_CMD_BUF_SIZE but + * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE + */ BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0); lbs_deb_enter(LBS_DEB_SPI); @@ -838,8 +870,10 @@ static void if_spi_host_to_card_worker(struct work_struct *work) lbs_deb_enter(LBS_DEB_SPI); - /* Read the host interrupt status register to see what we - * can do. */ + /* + * Read the host interrupt status register to see what we + * can do. + */ err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG, &hiStatus); if (err) { @@ -858,12 +892,15 @@ static void if_spi_host_to_card_worker(struct work_struct *work) goto err; } - /* workaround: in PS mode, the card does not set the Command - * Download Ready bit, but it sets TX Download Ready. */ + /* + * workaround: in PS mode, the card does not set the Command + * Download Ready bit, but it sets TX Download Ready. + */ if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY || (card->priv->psstate != PS_STATE_FULL_POWER && (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) { - /* This means two things. First of all, + /* + * This means two things. First of all, * if there was a previous command sent, the card has * successfully received it. * Secondly, it is now ready to download another @@ -871,8 +908,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) */ lbs_host_to_card_done(card->priv); - /* Do we have any command packets from the host to - * send? */ + /* Do we have any command packets from the host to send? */ packet = NULL; spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->cmd_packet_list)) { @@ -886,8 +922,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work) if_spi_h2c(card, packet, MVMS_CMD); } if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { - /* Do we have any data packets from the host to - * send? */ + /* Do we have any data packets from the host to send? */ packet = NULL; spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->data_packet_list)) { @@ -914,7 +949,8 @@ err: * Host to Card * * Called from Libertas to transfer some data to the WLAN device - * We can't sleep here. */ + * We can't sleep here. + */ static int if_spi_host_to_card(struct lbs_private *priv, u8 type, u8 *buf, u16 nb) { @@ -1125,8 +1161,10 @@ static int __devinit if_spi_probe(struct spi_device *spi) if (err) goto free_card; - /* Register our card with libertas. - * This will call alloc_etherdev */ + /* + * Register our card with libertas. + * This will call alloc_etherdev. + */ priv = lbs_add_card(card, &spi->dev); if (!priv) { err = -ENOMEM; @@ -1153,9 +1191,11 @@ static int __devinit if_spi_probe(struct spi_device *spi) goto terminate_workqueue; } - /* Start the card. + /* + * Start the card. * This will call register_netdev, and we'll start - * getting interrupts... */ + * getting interrupts... + */ err = lbs_start_card(priv); if (err) goto release_irq; diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h index d2ac1dc..e450e31 100644 --- a/drivers/net/wireless/libertas/if_spi.h +++ b/drivers/net/wireless/libertas/if_spi.h @@ -86,34 +86,34 @@ #define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff) /***************** IF_SPI_HOST_INT_CTRL_REG *****************/ -/** Host Interrupt Control bit : Wake up */ +/* Host Interrupt Control bit : Wake up */ #define IF_SPI_HICT_WAKE_UP (1<<0) -/** Host Interrupt Control bit : WLAN ready */ +/* Host Interrupt Control bit : WLAN ready */ #define IF_SPI_HICT_WLAN_READY (1<<1) /*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */ /*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */ /*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */ -/** Host Interrupt Control bit : Tx auto download */ +/* Host Interrupt Control bit : Tx auto download */ #define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5) -/** Host Interrupt Control bit : Rx auto upload */ +/* Host Interrupt Control bit : Rx auto upload */ #define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6) -/** Host Interrupt Control bit : Command auto download */ +/* Host Interrupt Control bit : Command auto download */ #define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7) -/** Host Interrupt Control bit : Command auto upload */ +/* Host Interrupt Control bit : Command auto upload */ #define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8) /***************** IF_SPI_CARD_INT_CAUSE_REG *****************/ -/** Card Interrupt Case bit : Tx download over */ +/* Card Interrupt Case bit : Tx download over */ #define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0) -/** Card Interrupt Case bit : Rx upload over */ +/* Card Interrupt Case bit : Rx upload over */ #define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1) -/** Card Interrupt Case bit : Command download over */ +/* Card Interrupt Case bit : Command download over */ #define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2) -/** Card Interrupt Case bit : Host event */ +/* Card Interrupt Case bit : Host event */ #define IF_SPI_CIC_HOST_EVENT (1<<3) -/** Card Interrupt Case bit : Command upload over */ +/* Card Interrupt Case bit : Command upload over */ #define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4) -/** Card Interrupt Case bit : Power down */ +/* Card Interrupt Case bit : Power down */ #define IF_SPI_CIC_POWER_DOWN (1<<5) /***************** IF_SPI_CARD_INT_STATUS_REG *****************/ @@ -138,51 +138,51 @@ #define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_HOST_INT_STATUS_REG *****************/ -/** Host Interrupt Status bit : Tx download ready */ +/* Host Interrupt Status bit : Tx download ready */ #define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0) -/** Host Interrupt Status bit : Rx upload ready */ +/* Host Interrupt Status bit : Rx upload ready */ #define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1) -/** Host Interrupt Status bit : Command download ready */ +/* Host Interrupt Status bit : Command download ready */ #define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2) -/** Host Interrupt Status bit : Card event */ +/* Host Interrupt Status bit : Card event */ #define IF_SPI_HIST_CARD_EVENT (1<<3) -/** Host Interrupt Status bit : Command upload ready */ +/* Host Interrupt Status bit : Command upload ready */ #define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4) -/** Host Interrupt Status bit : I/O write FIFO overflow */ +/* Host Interrupt Status bit : I/O write FIFO overflow */ #define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5) -/** Host Interrupt Status bit : I/O read FIFO underflow */ +/* Host Interrupt Status bit : I/O read FIFO underflow */ #define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6) -/** Host Interrupt Status bit : Data write FIFO overflow */ +/* Host Interrupt Status bit : Data write FIFO overflow */ #define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7) -/** Host Interrupt Status bit : Data read FIFO underflow */ +/* Host Interrupt Status bit : Data read FIFO underflow */ #define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8) -/** Host Interrupt Status bit : Command write FIFO overflow */ +/* Host Interrupt Status bit : Command write FIFO overflow */ #define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9) -/** Host Interrupt Status bit : Command read FIFO underflow */ +/* Host Interrupt Status bit : Command read FIFO underflow */ #define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/ -/** Host Interrupt Status Mask bit : Tx download ready */ +/* Host Interrupt Status Mask bit : Tx download ready */ #define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0) -/** Host Interrupt Status Mask bit : Rx upload ready */ +/* Host Interrupt Status Mask bit : Rx upload ready */ #define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1) -/** Host Interrupt Status Mask bit : Command download ready */ +/* Host Interrupt Status Mask bit : Command download ready */ #define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2) -/** Host Interrupt Status Mask bit : Card event */ +/* Host Interrupt Status Mask bit : Card event */ #define IF_SPI_HISM_CARDEVENT (1<<3) -/** Host Interrupt Status Mask bit : Command upload ready */ +/* Host Interrupt Status Mask bit : Command upload ready */ #define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4) -/** Host Interrupt Status Mask bit : I/O write FIFO overflow */ +/* Host Interrupt Status Mask bit : I/O write FIFO overflow */ #define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5) -/** Host Interrupt Status Mask bit : I/O read FIFO underflow */ +/* Host Interrupt Status Mask bit : I/O read FIFO underflow */ #define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6) -/** Host Interrupt Status Mask bit : Data write FIFO overflow */ +/* Host Interrupt Status Mask bit : Data write FIFO overflow */ #define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7) -/** Host Interrupt Status Mask bit : Data write FIFO underflow */ +/* Host Interrupt Status Mask bit : Data write FIFO underflow */ #define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8) -/** Host Interrupt Status Mask bit : Command write FIFO overflow */ +/* Host Interrupt Status Mask bit : Command write FIFO overflow */ #define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9) -/** Host Interrupt Status Mask bit : Command write FIFO underflow */ +/* Host Interrupt Status Mask bit : Command write FIFO underflow */ #define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10) /***************** IF_SPI_SPU_BUS_MODE_REG *****************/ diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 6524c70..e1e2128f 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -1,6 +1,6 @@ -/** - * This file contains functions used in USB interface module. - */ +/* + * This file contains functions used in USB interface module. + */ #include <linux/delay.h> #include <linux/moduleparam.h> #include <linux/firmware.h> @@ -66,7 +66,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp); /* sysfs hooks */ -/** +/* * Set function to write firmware to device's persistent memory */ static ssize_t if_usb_firmware_set(struct device *dev, @@ -85,7 +85,7 @@ static ssize_t if_usb_firmware_set(struct device *dev, return ret; } -/** +/* * lbs_flash_fw attribute to be exported per ethX interface through sysfs * (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to * the device's persistent memory: @@ -94,7 +94,14 @@ static ssize_t if_usb_firmware_set(struct device *dev, static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); /** - * Set function to write firmware to device's persistent memory + * if_usb_boot2_set - write firmware to device's persistent memory + * + * @dev: target device + * @attr: device attributes + * @buf: firmware buffer to write + * @count: number of bytes to write + * + * returns: number of bytes written or negative error code */ static ssize_t if_usb_boot2_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -112,7 +119,7 @@ static ssize_t if_usb_boot2_set(struct device *dev, return ret; } -/** +/* * lbs_flash_boot2 attribute to be exported per ethX interface through sysfs * (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware * to the device's persistent memory: @@ -121,9 +128,10 @@ static ssize_t if_usb_boot2_set(struct device *dev, static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set); /** - * @brief call back function to handle the status of the URB - * @param urb pointer to urb structure - * @return N/A + * if_usb_write_bulk_callback - callback function to handle the status + * of the URB + * @urb: pointer to &urb structure + * returns: N/A */ static void if_usb_write_bulk_callback(struct urb *urb) { @@ -150,9 +158,9 @@ static void if_usb_write_bulk_callback(struct urb *urb) } /** - * @brief free tx/rx urb, skb and rx buffer - * @param cardp pointer if_usb_card - * @return N/A + * if_usb_free - free tx/rx urb, skb and rx buffer + * @cardp: pointer to &if_usb_card + * returns: N/A */ static void if_usb_free(struct if_usb_card *cardp) { @@ -231,10 +239,10 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv) #endif /** - * @brief sets the configuration values - * @param ifnum interface number - * @param id pointer to usb_device_id - * @return 0 on success, error code on failure + * if_usb_probe - sets the configuration values + * @intf: &usb_interface pointer + * @id: pointer to usb_device_id + * returns: 0 on success, error code on failure */ static int if_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -366,9 +374,9 @@ error: } /** - * @brief free resource and cleanup - * @param intf USB interface structure - * @return N/A + * if_usb_disconnect - free resource and cleanup + * @intf: USB interface structure + * returns: N/A */ static void if_usb_disconnect(struct usb_interface *intf) { @@ -398,9 +406,9 @@ static void if_usb_disconnect(struct usb_interface *intf) } /** - * @brief This function download FW - * @param priv pointer to struct lbs_private - * @return 0 + * if_usb_send_fw_pkt - download FW + * @cardp: pointer to &struct if_usb_card + * returns: 0 */ static int if_usb_send_fw_pkt(struct if_usb_card *cardp) { @@ -486,11 +494,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp) } /** - * @brief This function transfer the data to the device. - * @param priv pointer to struct lbs_private - * @param payload pointer to payload data - * @param nb data length - * @return 0 or -1 + * usb_tx_block - transfer the data to the device + * @cardp: pointer to &struct if_usb_card + * @payload: pointer to payload data + * @nb: data length + * returns: 0 for success or negative error code */ static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) { @@ -727,11 +735,11 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, } /** - * @brief This function reads of the packet into the upload buff, - * wake up the main thread and initialise the Rx callack. + * if_usb_receive - read the packet into the upload buffer, + * wake up the main thread and initialise the Rx callack * - * @param urb pointer to struct urb - * @return N/A + * @urb: pointer to &struct urb + * returns: N/A */ static void if_usb_receive(struct urb *urb) { @@ -802,12 +810,12 @@ rx_exit: } /** - * @brief This function downloads data to FW - * @param priv pointer to struct lbs_private structure - * @param type type of data - * @param buf pointer to data buffer - * @param len number of bytes - * @return 0 or -1 + * if_usb_host_to_card - downloads data to FW + * @priv: pointer to &struct lbs_private structure + * @type: type of data + * @payload: pointer to data buffer + * @nb: number of bytes + * returns: 0 for success or negative error code */ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, uint8_t *payload, uint16_t nb) @@ -831,10 +839,11 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, } /** - * @brief This function issues Boot command to the Boot2 code - * @param ivalue 1:Boot from FW by USB-Download - * 2:Boot from FW in EEPROM - * @return 0 + * if_usb_issue_boot_command - issues Boot command to the Boot2 code + * @cardp: pointer to &if_usb_card + * @ivalue: 1:Boot from FW by USB-Download + * 2:Boot from FW in EEPROM + * returns: 0 for success or negative error code */ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) { @@ -853,11 +862,11 @@ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) /** - * @brief This function checks the validity of Boot2/FW image. + * check_fwfile_format - check the validity of Boot2/FW image * - * @param data pointer to image - * len image length - * @return 0 or -1 + * @data: pointer to image + * @totlen: image length + * returns: 0 (good) or 1 (failure) */ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) { @@ -901,13 +910,13 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen) /** -* @brief This function programs the firmware subject to cmd +* if_usb_prog_firmware - programs the firmware subject to cmd * -* @param cardp the if_usb_card descriptor -* fwname firmware or boot2 image file name -* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, -* or BOOT_CMD_UPDATE_BOOT2. -* @return 0 or error code +* @cardp: the if_usb_card descriptor +* @fwname: firmware or boot2 image file name +* @cmd: either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW, +* or BOOT_CMD_UPDATE_BOOT2. +* returns: 0 or error code */ static int if_usb_prog_firmware(struct if_usb_card *cardp, const char *fwname, int cmd) diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index d819e7e..6e42eac 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -6,9 +6,9 @@ struct lbs_private; -/** - * This file contains definition for USB interface. - */ +/* + * This file contains definition for USB interface. + */ #define CMD_TYPE_REQUEST 0xF00DFACE #define CMD_TYPE_DATA 0xBEADC0DE #define CMD_TYPE_INDICATION 0xBEEFFACE @@ -40,7 +40,7 @@ struct bootcmdresp uint8_t pad[2]; }; -/** USB card description structure*/ +/* USB card description structure*/ struct if_usb_card { struct usb_device *udev; uint32_t model; /* MODEL_* */ @@ -77,7 +77,7 @@ struct if_usb_card { __le16 boot2_version; }; -/** fwheader */ +/* fwheader */ struct fwheader { __le32 dnldcmd; __le32 baseaddr; @@ -86,14 +86,14 @@ struct fwheader { }; #define FW_MAX_DATA_BLK_SIZE 600 -/** FWData */ +/* FWData */ struct fwdata { struct fwheader hdr; __le32 seqnum; uint8_t data[0]; }; -/** fwsyncheader */ +/* fwsyncheader */ struct fwsyncheader { __le32 cmd; __le32 seqnum; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index ca8149c..ed57cf8 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1,8 +1,8 @@ -/** - * This file contains the major functions in WLAN - * driver. It includes init, exit, open, close and main - * thread etc.. - */ +/* + * This file contains the major functions in WLAN + * driver. It includes init, exit, open, close and main + * thread etc.. + */ #include <linux/moduleparam.h> #include <linux/delay.h> @@ -35,18 +35,20 @@ EXPORT_SYMBOL_GPL(lbs_debug); module_param_named(libertas_debug, lbs_debug, int, 0644); -/* This global structure is used to send the confirm_sleep command as - * fast as possible down to the firmware. */ +/* + * This global structure is used to send the confirm_sleep command as + * fast as possible down to the firmware. + */ struct cmd_confirm_sleep confirm_sleep; -/** +/* * the table to keep region code */ u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; -/** +/* * FW rate table. FW refers to rates by their index in this table, not by the * rate value itself. Values of 0x00 are * reserved positions. @@ -57,10 +59,10 @@ static u8 fw_data_rates[MAX_RATES] = }; /** - * @brief use index to get the data rate + * lbs_fw_index_to_data_rate - use index to get the data rate * - * @param idx The index of data rate - * @return data rate or 0 + * @idx: The index of data rate + * returns: data rate or 0 */ u32 lbs_fw_index_to_data_rate(u8 idx) { @@ -70,10 +72,10 @@ u32 lbs_fw_index_to_data_rate(u8 idx) } /** - * @brief use rate to get the index + * lbs_data_rate_to_fw_index - use rate to get the index * - * @param rate data rate - * @return index or 0 + * @rate: data rate + * returns: index or 0 */ u8 lbs_data_rate_to_fw_index(u32 rate) { @@ -91,10 +93,10 @@ u8 lbs_data_rate_to_fw_index(u32 rate) /** - * @brief This function opens the ethX interface + * lbs_dev_open - open the ethX interface * - * @param dev A pointer to net_device structure - * @return 0 or -EBUSY if monitor mode active + * @dev: A pointer to &net_device structure + * returns: 0 or -EBUSY if monitor mode active */ static int lbs_dev_open(struct net_device *dev) { @@ -120,10 +122,10 @@ static int lbs_dev_open(struct net_device *dev) } /** - * @brief This function closes the ethX interface + * lbs_eth_stop - close the ethX interface * - * @param dev A pointer to net_device structure - * @return 0 + * @dev: A pointer to &net_device structure + * returns: 0 */ static int lbs_eth_stop(struct net_device *dev) { @@ -336,12 +338,12 @@ void lbs_set_multicast_list(struct net_device *dev) } /** - * @brief This function handles the major jobs in the LBS driver. + * lbs_thread - handles the major jobs in the LBS driver. * It handles all events generated by firmware, RX data received * from firmware and TX data sent from kernel. * - * @param data A pointer to lbs_thread structure - * @return 0 + * @data: A pointer to &lbs_thread structure + * returns: 0 */ static int lbs_thread(void *data) { @@ -540,11 +542,11 @@ static int lbs_thread(void *data) } /** - * @brief This function gets the HW spec from the firmware and sets - * some basic parameters. + * lbs_setup_firmware - gets the HW spec from the firmware and sets + * some basic parameters * - * @param priv A pointer to struct lbs_private structure - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private structure + * returns: 0 or -1 */ static int lbs_setup_firmware(struct lbs_private *priv) { @@ -630,8 +632,10 @@ int lbs_resume(struct lbs_private *priv) EXPORT_SYMBOL_GPL(lbs_resume); /** - * This function handles the timeout of command sending. - * It will re-send the same command again. + * lbs_cmd_timeout_handler - handles the timeout of command sending. + * It will re-send the same command again. + * + * @data: &struct lbs_private pointer */ static void lbs_cmd_timeout_handler(unsigned long data) { @@ -655,8 +659,10 @@ out: } /** - * This function put the device back to deep sleep mode when timer expires - * and no activity (command, event, data etc.) is detected. + * auto_deepsleep_timer_fn - put the device back to deep sleep mode when + * timer expires and no activity (command, event, data etc.) is detected. + * @data: &struct lbs_private pointer + * returns: N/A */ static void auto_deepsleep_timer_fn(unsigned long data) { @@ -792,11 +798,12 @@ static const struct net_device_ops lbs_netdev_ops = { }; /** - * @brief This function adds the card. it will probe the + * lbs_add_card - adds the card. It will probe the * card, allocate the lbs_priv and initialize the device. * - * @param card A pointer to card - * @return A pointer to struct lbs_private structure + * @card: A pointer to card + * @dmdev: A pointer to &struct device + * returns: A pointer to &struct lbs_private structure */ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) { @@ -1057,19 +1064,19 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) EXPORT_SYMBOL_GPL(lbs_notify_command_response); /** - * @brief Retrieves two-stage firmware + * lbs_get_firmware - Retrieves two-stage firmware * - * @param dev A pointer to device structure - * @param user_helper User-defined helper firmware file - * @param user_mainfw User-defined main firmware file - * @param card_model Bus-specific card model ID used to filter firmware table - * elements - * @param fw_table Table of firmware file names and device model numbers - * terminated by an entry with a NULL helper name - * @param helper On success, the helper firmware; caller must free - * @param mainfw On success, the main firmware; caller must free + * @dev: A pointer to &device structure + * @user_helper: User-defined helper firmware file + * @user_mainfw: User-defined main firmware file + * @card_model: Bus-specific card model ID used to filter firmware table + * elements + * @fw_table: Table of firmware file names and device model numbers + * terminated by an entry with a NULL helper name + * @helper: On success, the helper firmware; caller must free + * @mainfw: On success, the main firmware; caller must free * - * @return 0 on success, non-zero on failure + * returns: 0 on success, non-zero on failure */ int lbs_get_firmware(struct device *dev, const char *user_helper, const char *user_mainfw, u32 card_model, diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 9d097b9..a0804d1 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -16,12 +16,15 @@ * Mesh sysfs support */ -/** +/* * Attributes exported through sysfs */ /** - * @brief Get function for sysfs attribute anycast_mask + * lbs_anycast_get - Get function for sysfs attribute anycast_mask + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_anycast_get(struct device *dev, struct device_attribute *attr, char * buf) @@ -40,7 +43,11 @@ static ssize_t lbs_anycast_get(struct device *dev, } /** - * @brief Set function for sysfs attribute anycast_mask + * lbs_anycast_set - Set function for sysfs attribute anycast_mask + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_anycast_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) @@ -62,7 +69,10 @@ static ssize_t lbs_anycast_set(struct device *dev, } /** - * @brief Get function for sysfs attribute prb_rsp_limit + * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_prb_rsp_limit_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -85,7 +95,11 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev, } /** - * @brief Set function for sysfs attribute prb_rsp_limit + * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -114,7 +128,10 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev, } /** - * Get function for sysfs attribute mesh + * lbs_mesh_get - Get function for sysfs attribute mesh + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t lbs_mesh_get(struct device *dev, struct device_attribute *attr, char * buf) @@ -124,7 +141,11 @@ static ssize_t lbs_mesh_get(struct device *dev, } /** - * Set function for sysfs attribute mesh + * lbs_mesh_set - Set function for sysfs attribute mesh + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) @@ -151,19 +172,19 @@ static ssize_t lbs_mesh_set(struct device *dev, return count; } -/** +/* * lbs_mesh attribute to be exported per ethX interface * through sysfs (/sys/class/net/ethX/lbs_mesh) */ static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); -/** +/* * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask) */ static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); -/** +/* * prb_rsp_limit attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/prb_rsp_limit) */ @@ -274,10 +295,10 @@ int lbs_deinit_mesh(struct lbs_private *priv) /** - * @brief This function closes the mshX interface + * lbs_mesh_stop - close the mshX interface * - * @param dev A pointer to net_device structure - * @return 0 + * @dev: A pointer to &net_device structure + * returns: 0 */ static int lbs_mesh_stop(struct net_device *dev) { @@ -301,10 +322,10 @@ static int lbs_mesh_stop(struct net_device *dev) } /** - * @brief This function opens the mshX interface + * lbs_mesh_dev_open - open the mshX interface * - * @param dev A pointer to net_device structure - * @return 0 or -EBUSY if monitor mode active + * @dev: A pointer to &net_device structure + * returns: 0 or -EBUSY if monitor mode active */ static int lbs_mesh_dev_open(struct net_device *dev) { @@ -342,10 +363,10 @@ static const struct net_device_ops mesh_netdev_ops = { }; /** - * @brief This function adds mshX interface + * lbs_add_mesh - add mshX interface * - * @param priv A pointer to the struct lbs_private structure - * @return 0 if successful, -X otherwise + * @priv: A pointer to the &struct lbs_private structure + * returns: 0 if successful, -X otherwise */ int lbs_add_mesh(struct lbs_private *priv) { @@ -456,13 +477,13 @@ void lbs_mesh_set_txpd(struct lbs_private *priv, */ /** - * @brief Add or delete Mesh Blinding Table entries + * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries * - * @param priv A pointer to struct lbs_private structure - * @param add TRUE to add the entry, FALSE to delete it - * @param addr1 Destination address to blind or unblind + * @priv: A pointer to &struct lbs_private structure + * @add: TRUE to add the entry, FALSE to delete it + * @addr1: Destination address to blind or unblind * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) { @@ -493,11 +514,11 @@ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1) } /** - * @brief Reset/clear the mesh blinding table + * lbs_mesh_bt_reset - Reset/clear the mesh blinding table * - * @param priv A pointer to struct lbs_private structure + * @priv: A pointer to &struct lbs_private structure * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_reset(struct lbs_private *priv) { @@ -517,17 +538,18 @@ int lbs_mesh_bt_reset(struct lbs_private *priv) } /** - * @brief Gets the inverted status of the mesh blinding table + * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh + * blinding table * - * Normally the firmware "blinds" or ignores traffic from mesh nodes in the - * table, but an inverted table allows *only* traffic from nodes listed in - * the table. + * Normally the firmware "blinds" or ignores traffic from mesh nodes in the + * table, but an inverted table allows *only* traffic from nodes listed in + * the table. * - * @param priv A pointer to struct lbs_private structure - * @param invert On success, TRUE if the blinding table is inverted, - * FALSE if it is not inverted + * @priv: A pointer to &struct lbs_private structure + * @inverted: On success, TRUE if the blinding table is inverted, + * FALSE if it is not inverted * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) { @@ -551,18 +573,19 @@ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted) } /** - * @brief Sets the inverted status of the mesh blinding table + * lbs_mesh_bt_set_inverted - Sets the inverted status of the mesh + * blinding table * - * Normally the firmware "blinds" or ignores traffic from mesh nodes in the - * table, but an inverted table allows *only* traffic from nodes listed in - * the table. + * Normally the firmware "blinds" or ignores traffic from mesh nodes in the + * table, but an inverted table allows *only* traffic from nodes listed in + * the table. * - * @param priv A pointer to struct lbs_private structure - * @param invert TRUE to invert the blinding table (only traffic from - * listed nodes allowed), FALSE to return it - * to normal state (listed nodes ignored) + * @priv: A pointer to &struct lbs_private structure + * @inverted: TRUE to invert the blinding table (only traffic from + * listed nodes allowed), FALSE to return it + * to normal state (listed nodes ignored) * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted) { @@ -583,13 +606,13 @@ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted) } /** - * @brief List an entry in the mesh blinding table + * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table * - * @param priv A pointer to struct lbs_private structure - * @param id The ID of the entry to list - * @param addr1 MAC address associated with the table entry + * @priv: A pointer to &struct lbs_private structure + * @id: The ID of the entry to list + * @addr1: MAC address associated with the table entry * - * @return 0 on success, error on failure + * returns: 0 on success, error on failure */ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) { @@ -614,14 +637,14 @@ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1) } /** - * @brief Access the mesh forwarding table + * lbs_cmd_fwt_access - Access the mesh forwarding table * - * @param priv A pointer to struct lbs_private structure - * @param cmd_action The forwarding table action to perform - * @param cmd The pre-filled FWT_ACCESS command + * @priv: A pointer to &struct lbs_private structure + * @cmd_action: The forwarding table action to perform + * @cmd: The pre-filled FWT_ACCESS command * - * @return 0 on success and 'cmd' will be filled with the - * firmware's response + * returns: 0 on success and 'cmd' will be filled with the + * firmware's response */ int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action, struct cmd_ds_fwt_access *cmd) @@ -774,7 +797,10 @@ static int mesh_get_default_parameters(struct device *dev, } /** - * @brief Get function for sysfs attribute bootflag + * bootflag_get - Get function for sysfs attribute bootflag + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t bootflag_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -791,7 +817,11 @@ static ssize_t bootflag_get(struct device *dev, } /** - * @brief Set function for sysfs attribute bootflag + * bootflag_set - Set function for sysfs attribute bootflag + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -817,7 +847,10 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute boottime + * boottime_get - Get function for sysfs attribute boottime + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t boottime_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -834,7 +867,11 @@ static ssize_t boottime_get(struct device *dev, } /** - * @brief Set function for sysfs attribute boottime + * boottime_set - Set function for sysfs attribute boottime + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t boottime_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -869,7 +906,10 @@ static ssize_t boottime_set(struct device *dev, } /** - * @brief Get function for sysfs attribute channel + * channel_get - Get function for sysfs attribute channel + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t channel_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -886,7 +926,11 @@ static ssize_t channel_get(struct device *dev, } /** - * @brief Set function for sysfs attribute channel + * channel_set - Set function for sysfs attribute channel + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -912,7 +956,10 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute mesh_id + * mesh_id_get - Get function for sysfs attribute mesh_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -938,7 +985,11 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, } /** - * @brief Set function for sysfs attribute mesh_id + * mesh_id_set - Set function for sysfs attribute mesh_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -980,7 +1031,10 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute protocol_id + * protocol_id_get - Get function for sysfs attribute protocol_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t protocol_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -997,7 +1051,11 @@ static ssize_t protocol_id_get(struct device *dev, } /** - * @brief Set function for sysfs attribute protocol_id + * protocol_id_set - Set function for sysfs attribute protocol_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t protocol_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1034,7 +1092,10 @@ static ssize_t protocol_id_set(struct device *dev, } /** - * @brief Get function for sysfs attribute metric_id + * metric_id_get - Get function for sysfs attribute metric_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t metric_id_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -1051,7 +1112,11 @@ static ssize_t metric_id_get(struct device *dev, } /** - * @brief Set function for sysfs attribute metric_id + * metric_id_set - Set function for sysfs attribute metric_id + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1088,7 +1153,10 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, } /** - * @brief Get function for sysfs attribute capability + * capability_get - Get function for sysfs attribute capability + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer where data will be returned */ static ssize_t capability_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -1105,7 +1173,11 @@ static ssize_t capability_get(struct device *dev, } /** - * @brief Set function for sysfs attribute capability + * capability_set - Set function for sysfs attribute capability + * @dev: the &struct device + * @attr: device attributes + * @buf: buffer that contains new attribute value + * @count: size of buffer */ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index afb2e8d..ee95c73 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -1,6 +1,6 @@ -/** - * Contains all definitions needed for the Libertas' MESH implementation. - */ +/* + * Contains all definitions needed for the Libertas' MESH implementation. + */ #ifndef _LBS_MESH_H_ #define _LBS_MESH_H_ diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index a2b1df2..a3f4b55 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -1,6 +1,6 @@ -/** - * This file contains the handling of RX in wlan driver. - */ +/* + * This file contains the handling of RX in wlan driver. + */ #include <linux/etherdevice.h> #include <linux/slab.h> #include <linux/types.h> @@ -40,12 +40,12 @@ static int process_rxed_802_11_packet(struct lbs_private *priv, struct sk_buff *skb); /** - * @brief This function processes received packet and forwards it - * to kernel/upper layer + * lbs_process_rxed_packet - processes received packet and forwards it + * to kernel/upper layer * - * @param priv A pointer to struct lbs_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private + * @skb: A pointer to skb which includes the received packet + * returns: 0 or -1 */ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) { @@ -156,11 +156,11 @@ done: EXPORT_SYMBOL_GPL(lbs_process_rxed_packet); /** - * @brief This function converts Tx/Rx rates from the Marvell WLAN format - * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) + * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format + * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) * - * @param rate Input rate - * @return Output Rate (0 if invalid) + * @rate: Input rate + * returns: Output Rate (0 if invalid) */ static u8 convert_mv_rate_to_radiotap(u8 rate) { @@ -196,12 +196,12 @@ static u8 convert_mv_rate_to_radiotap(u8 rate) } /** - * @brief This function processes a received 802.11 packet and forwards it - * to kernel/upper layer + * process_rxed_802_11_packet - processes a received 802.11 packet and forwards + * it to kernel/upper layer * - * @param priv A pointer to struct lbs_private - * @param skb A pointer to skb which includes the received packet - * @return 0 or -1 + * @priv: A pointer to &struct lbs_private + * @skb: A pointer to skb which includes the received packet + * returns: 0 or -1 */ static int process_rxed_802_11_packet(struct lbs_private *priv, struct sk_buff *skb) diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index 8000ca6..bbb95f8 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -1,6 +1,6 @@ -/** - * This file contains the handling of TX in wlan driver. - */ +/* + * This file contains the handling of TX in wlan driver. + */ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/sched.h> @@ -13,11 +13,11 @@ #include "dev.h" /** - * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE - * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) + * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE + * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) * - * @param rate Input rate - * @return Output Rate (0 if invalid) + * @rate: Input rate + * returns: Output Rate (0 if invalid) */ static u32 convert_radiotap_rate_to_mv(u8 rate) { @@ -51,12 +51,12 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) } /** - * @brief This function checks the conditions and sends packet to IF - * layer if everything is ok. + * lbs_hard_start_xmit - checks the conditions and sends packet to IF + * layer if everything is ok * - * @param priv A pointer to struct lbs_private structure - * @param skb A pointer to skb which includes TX packet - * @return 0 or -1 + * @skb: A pointer to skb which includes TX packet + * @dev: A pointer to the &struct net_device + * returns: 0 or -1 */ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -168,13 +168,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } /** - * @brief This function sends to the host the last transmitted packet, - * filling the radiotap headers with transmission information. + * lbs_send_tx_feedback - sends to the host the last transmitted packet, + * filling the radiotap headers with transmission information. * - * @param priv A pointer to struct lbs_private structure - * @param status A 32 bit value containing transmission status. + * @priv: A pointer to &struct lbs_private structure + * @try_count: A 32-bit value containing transmission retry status. * - * @returns void + * returns: void */ void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count) { diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index 462fbb4..cf1d9b0 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -1,6 +1,6 @@ -/** - * This header file contains definition for global types - */ +/* + * This header file contains definition for global types + */ #ifndef _LBS_TYPES_H_ #define _LBS_TYPES_H_ @@ -54,7 +54,7 @@ union ieee_phy_param_set { struct ieee_ie_ds_param_set ds; } __packed; -/** TLV type ID definition */ +/* TLV type ID definition */ #define PROPRIETARY_TLV_BASE_ID 0x0100 /* Terminating TLV type */ @@ -96,7 +96,7 @@ union ieee_phy_param_set { #define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37) #define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291) -/** TLV related data structures*/ +/* TLV related data structures */ struct mrvl_ie_header { __le16 type; __le16 len; @@ -177,7 +177,7 @@ struct mrvl_ie_auth_type { __le16 auth; } __packed; -/** Local Power capability */ +/* Local Power capability */ struct mrvl_ie_power_capability { struct mrvl_ie_header header; s8 minpower; @@ -235,9 +235,11 @@ struct mrvl_ie_ledbhv { struct led_bhv ledbhv[1]; } __packed; -/* Meant to be packed as the value member of a struct ieee80211_info_element. +/* + * Meant to be packed as the value member of a struct ieee80211_info_element. * Note that the len member of the ieee80211_info_element varies depending on - * the mesh_id_len */ + * the mesh_id_len + */ struct mrvl_meshie_val { uint8_t oui[3]; uint8_t type; diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c index e22d761..1d294cf 100644 --- a/drivers/net/wireless/mwifiex/11n.c +++ b/drivers/net/wireless/mwifiex/11n.c @@ -29,95 +29,38 @@ * Fills HT capability information field, AMPDU Parameters field, HT extended * capability field, and supported MCS set fields. * - * Only the following HT capability information fields are used, all other - * fields are always turned off. + * HT capability information field, AMPDU Parameters field, supported MCS set + * fields are retrieved from cfg80211 stack * - * Bit 1 : Supported channel width (0: 20MHz, 1: Both 20 and 40 MHz) - * Bit 4 : Greenfield support (0: Not supported, 1: Supported) - * Bit 5 : Short GI for 20 MHz support (0: Not supported, 1: Supported) - * Bit 6 : Short GI for 40 MHz support (0: Not supported, 1: Supported) - * Bit 7 : Tx STBC (0: Not supported, 1: Supported) - * Bit 8-9 : Rx STBC (0: Not supported, X: Support for up to X spatial streams) - * Bit 10 : Delayed BA support (0: Not supported, 1: Supported) - * Bit 11 : Maximum AMSDU length (0: 3839 octets, 1: 7935 octets) - * Bit 14 : 40-Mhz intolerant support (0: Not supported, 1: Supported) - * - * In addition, the following AMPDU Parameters are set - - * - Maximum AMPDU length exponent (set to 3) - * - Minimum AMPDU start spacing (set to 0 - No restrictions) - * - * MCS is set for 1x1, with MSC32 for infra mode or ad-hoc mode with 40 MHz - * support. - * - * RD responder bit to set to clear in the extended capability header. + * RD responder bit to set to clear in the extended capability header. */ void -mwifiex_fill_cap_info(struct mwifiex_private *priv, +mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type, struct mwifiex_ie_types_htcap *ht_cap) { - struct mwifiex_adapter *adapter = priv->adapter; - u8 *mcs; - int rx_mcs_supp; - uint16_t ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info); uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info); + struct ieee80211_supported_band *sband = + priv->wdev->wiphy->bands[radio_type]; - /* Convert dev_cap to IEEE80211_HT_CAP */ - if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - else - ht_cap_info &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - - if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_SGI_20; - else - ht_cap_info &= ~IEEE80211_HT_CAP_SGI_20; - - if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_SGI_40; - else - ht_cap_info &= ~IEEE80211_HT_CAP_SGI_40; - - if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_TX_STBC; - else - ht_cap_info &= ~IEEE80211_HT_CAP_TX_STBC; - - if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; - else - ht_cap_info &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - if (ISSUPP_GREENFIELD(adapter->hw_dot_11n_dev_cap)) - ht_cap_info |= IEEE80211_HT_CAP_GRN_FLD; - else - ht_cap_info &= ~IEEE80211_HT_CAP_GRN_FLD; - - ht_cap_info &= ~IEEE80211_HT_CAP_MAX_AMSDU; - ht_cap_info |= IEEE80211_HT_CAP_SM_PS; + ht_cap->ht_cap.ampdu_params_info = + (sband->ht_cap.ampdu_factor & + IEEE80211_HT_AMPDU_PARM_FACTOR)| + ((sband->ht_cap.ampdu_density << + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) & + IEEE80211_HT_AMPDU_PARM_DENSITY); - ht_cap->ht_cap.ampdu_params_info |= IEEE80211_HT_AMPDU_PARM_FACTOR; - ht_cap->ht_cap.ampdu_params_info &= ~IEEE80211_HT_AMPDU_PARM_DENSITY; - - rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); - - mcs = (u8 *)&ht_cap->ht_cap.mcs; - - /* Set MCS for 1x1 */ - memset(mcs, 0xff, rx_mcs_supp); - - /* Clear all the other values */ - memset(&mcs[rx_mcs_supp], 0, - sizeof(struct ieee80211_mcs_info) - rx_mcs_supp); + memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs, + sizeof(sband->ht_cap.mcs)); if (priv->bss_mode == NL80211_IFTYPE_STATION || - (ht_cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask); /* Clear RD responder bit */ ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER; - ht_cap->ht_cap.cap_info = cpu_to_le16(ht_cap_info); + ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap); ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap); } @@ -391,10 +334,15 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, struct mwifiex_ie_types_2040bssco *bss_co_2040; struct mwifiex_ie_types_extcap *ext_cap; int ret_len = 0; + struct ieee80211_supported_band *sband; + u8 radio_type; if (!buffer || !*buffer) return ret_len; + radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); + sband = priv->wdev->wiphy->bands[radio_type]; + if (bss_desc->bcn_ht_cap) { ht_cap = (struct mwifiex_ie_types_htcap *) *buffer; memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); @@ -406,7 +354,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, sizeof(struct ieee_types_header), le16_to_cpu(ht_cap->header.len)); - mwifiex_fill_cap_info(priv, ht_cap); + mwifiex_fill_cap_info(priv, radio_type, ht_cap); *buffer += sizeof(struct mwifiex_ie_types_htcap); ret_len += sizeof(struct mwifiex_ie_types_htcap); @@ -428,8 +376,8 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, sizeof(struct ieee_types_header), le16_to_cpu(ht_info->header.len)); - if (!ISSUPP_CHANWIDTH40 - (priv->adapter->hw_dot_11n_dev_cap)) + if (!(sband->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) ht_info->ht_info.ht_param &= ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY | IEEE80211_HT_PARAM_CHA_SEC_OFFSET); @@ -451,7 +399,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, chan_list->chan_scan_param[0].radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); - if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) + if ((sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && (bss_desc->bcn_ht_info->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) SET_SECONDARYCHAN(chan_list->chan_scan_param[0]. diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h index 02602ff..a4390a1 100644 --- a/drivers/net/wireless/mwifiex/11n.h +++ b/drivers/net/wireless/mwifiex/11n.h @@ -38,7 +38,7 @@ int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, u8 **buffer); void mwifiex_cfg_tx_buf(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); -void mwifiex_fill_cap_info(struct mwifiex_private *, +void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type, struct mwifiex_ie_types_htcap *); int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv, u16 action, int *htcap_cfg); diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b99ae26..98009e2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1150,9 +1150,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, * * The following default values are set - * - HT Supported = True - * - Maximum AMPDU length factor = 0x3 - * - Minimum AMPDU spacing = 0x6 - * - HT Capabilities map = IEEE80211_HT_CAP_SUP_WIDTH_20_40 (0x0002) + * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K + * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE + * - HT Capabilities supported by firmware * - MCS information, Rx mask = 0xff * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01) */ @@ -1166,13 +1166,41 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, struct mwifiex_adapter *adapter = priv->adapter; ht_info->ht_supported = true; - ht_info->ampdu_factor = 0x3; - ht_info->ampdu_density = 0x6; + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE; memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40; - rx_mcs_supp = GET_RXMCSSUPP(priv->adapter->hw_dev_mcs_support); + /* Fill HT capability information */ + if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20; + + if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + else + ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40; + + if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT; + else + ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + + if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap)) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + else + ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC; + + ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->cap |= IEEE80211_HT_CAP_SM_PS; + + rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support); /* Set MCS for 1x1 */ memset(mcs, 0xff, rx_mcs_supp); /* Clear all the other values */ @@ -1235,20 +1263,23 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, wdev->wiphy->max_scan_ssids = 10; wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + mwifiex_setup_ht_caps( + &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv); + + if (priv->adapter->config_bands & BAND_A) { + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + mwifiex_setup_ht_caps( + &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv); + } else { + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + } /* Initialize cipher suits */ wdev->wiphy->cipher_suites = mwifiex_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - /* Initialize parameters for 2GHz band */ - - mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, - priv); - mwifiex_setup_ht_caps(&wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, - priv); - memcpy(wdev->wiphy->perm_addr, mac, 6); wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 23d2d0b..85fca5e 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -100,7 +100,7 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, struct mwifiex_bssdescriptor *bss_desc) { struct mwifiex_ie_types_tsf_timestamp tsf_tlv; - long long tsf_val; + __le64 tsf_val; /* Null Checks */ if (buffer == NULL) @@ -116,6 +116,8 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); *buffer += sizeof(tsf_tlv.header); + /* TSF at the time when beacon/probe_response was received */ + tsf_val = cpu_to_le64(bss_desc->network_tsf); memcpy(*buffer, &tsf_val, sizeof(tsf_val)); *buffer += sizeof(tsf_val); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 1b50303..5043fcd 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -280,7 +280,7 @@ struct mwifiex_bssdescriptor { * BAND_A(0X04): 'a' band */ u16 bss_band; - long long network_tsf; + u64 network_tsf; u8 time_stamp[8]; union ieee_types_phy_param_set phy_param_set; union ieee_types_ss_param_set ss_param_set; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 68d905d..31a5295 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1007,7 +1007,9 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); ht_cap->header.len = cpu_to_le16(sizeof(struct ieee80211_ht_cap)); - mwifiex_fill_cap_info(priv, ht_cap); + radio_type = + mwifiex_band_to_radio_type(priv->adapter->config_bands); + mwifiex_fill_cap_info(priv, radio_type, ht_cap); tlv_pos += sizeof(struct mwifiex_ie_types_htcap); } @@ -2988,32 +2990,28 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) struct mwifiex_bssdescriptor *curr_bss = &priv->curr_bss_params.bss_descriptor; - /* save the beacon buffer if it is not saved or updated */ - if ((priv->curr_bcn_buf == NULL) || - (priv->curr_bcn_size != curr_bss->beacon_buf_size) || - (memcmp(priv->curr_bcn_buf, curr_bss->beacon_buf, - curr_bss->beacon_buf_size))) { - - kfree(priv->curr_bcn_buf); - priv->curr_bcn_buf = NULL; + if (!curr_bss->beacon_buf_size) + return; + /* allocate beacon buffer at 1st time; or if it's size has changed */ + if (!priv->curr_bcn_buf || + priv->curr_bcn_size != curr_bss->beacon_buf_size) { priv->curr_bcn_size = curr_bss->beacon_buf_size; - if (!priv->curr_bcn_size) - return; + kfree(priv->curr_bcn_buf); priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, GFP_KERNEL); if (!priv->curr_bcn_buf) { dev_err(priv->adapter->dev, "failed to alloc curr_bcn_buf\n"); - } else { - memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, - curr_bss->beacon_buf_size); - dev_dbg(priv->adapter->dev, - "info: current beacon saved %d\n", - priv->curr_bcn_size); + return; } } + + memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, + curr_bss->beacon_buf_size); + dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", + priv->curr_bcn_size); } /* diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 28ebaec..9f5ecef 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -74,6 +74,14 @@ MODULE_PARM_DESC(ap_mode_default, #define MWL8K_A2H_INT_RX_READY (1 << 1) #define MWL8K_A2H_INT_TX_DONE (1 << 0) +/* HW micro second timer register + * located at offset 0xA600. This + * will be used to timestamp tx + * packets. + */ + +#define MWL8K_HW_TIMER_REGISTER 0x0000a600 + #define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \ MWL8K_A2H_INT_CHNL_SWITCHED | \ MWL8K_A2H_INT_QUEUE_EMPTY | \ @@ -773,8 +781,10 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos) skb_pull(skb, sizeof(*tr) - hdrlen); } +#define REDUCED_TX_HEADROOM 8 + static void -mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) +mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad) { struct ieee80211_hdr *wh; int hdrlen; @@ -790,6 +800,22 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) wh = (struct ieee80211_hdr *)skb->data; hdrlen = ieee80211_hdrlen(wh->frame_control); + + /* + * Check if skb_resize is required because of + * tx_headroom adjustment. + */ + if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts) + + REDUCED_TX_HEADROOM))) { + if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) { + + wiphy_err(priv->hw->wiphy, + "Failed to reallocate TX buffer\n"); + return; + } + skb->truesize += REDUCED_TX_HEADROOM; + } + reqd_hdrlen = sizeof(*tr); if (hdrlen != reqd_hdrlen) @@ -812,7 +838,8 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad) tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad); } -static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) +static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv, + struct sk_buff *skb) { struct ieee80211_hdr *wh; struct ieee80211_tx_info *tx_info; @@ -853,7 +880,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb) break; } } - mwl8k_add_dma_header(skb, data_pad); + mwl8k_add_dma_header(priv, skb, data_pad); } /* @@ -1554,24 +1581,11 @@ static int mwl8k_tid_queue_mapping(u8 tid) /* The firmware will fill in the rate information * for each packet that gets queued in the hardware - * in this structure + * and these macros will interpret that info. */ -struct rateinfo { - __le16 format:1; - __le16 short_gi:1; - __le16 band_width:1; - __le16 rate_id_mcs:6; - __le16 adv_coding:2; - __le16 antenna:2; - __le16 act_sub_chan:2; - __le16 preamble_type:1; - __le16 power_id:4; - __le16 antenna2:1; - __le16 reserved:1; - __le16 tx_bf_frame:1; - __le16 green_field:1; -} __packed; +#define RI_FORMAT(a) (a & 0x0001) +#define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3) static int mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) @@ -1592,7 +1606,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) struct ieee80211_sta *sta; struct mwl8k_sta *sta_info = NULL; u16 rate_info; - struct rateinfo *rate; struct ieee80211_hdr *wh; tx = txq->head; @@ -1635,14 +1648,13 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) sta_info = MWL8K_STA(sta); BUG_ON(sta_info == NULL); rate_info = le16_to_cpu(tx_desc->rate_info); - rate = (struct rateinfo *)&rate_info; /* If rate is < 6.5 Mpbs for an ht station * do not form an ampdu. If the station is a * legacy station (format = 0), do not form an * ampdu */ - if (rate->rate_id_mcs < 1 || - rate->format == 0) { + if (RI_RATE_ID_MCS(rate_info) < 1 || + RI_FORMAT(rate_info) == 0) { sta_info->is_ampdu_allowed = false; } else { sta_info->is_ampdu_allowed = true; @@ -1666,10 +1678,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) processed++; } - if (index < MWL8K_TX_WMM_QUEUES && processed && priv->radio_on && - !mutex_is_locked(&priv->fw_mutex)) - ieee80211_wake_queue(hw, index); - return processed; } @@ -1814,6 +1822,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) u8 tid = 0; struct mwl8k_ampdu_stream *stream = NULL; bool start_ba_session = false; + bool mgmtframe = false; struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; wh = (struct ieee80211_hdr *)skb->data; @@ -1822,10 +1831,13 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) else qos = 0; + if (ieee80211_is_mgmt(wh->frame_control)) + mgmtframe = true; + if (priv->ap_fw) - mwl8k_encapsulate_tx_frame(skb); + mwl8k_encapsulate_tx_frame(priv, skb); else - mwl8k_add_dma_header(skb, 0); + mwl8k_add_dma_header(priv, skb, 0); wh = &((struct mwl8k_dma_data *)skb->data)->wh; @@ -1951,14 +1963,26 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) txq = priv->txq + index; - if (index >= MWL8K_TX_WMM_QUEUES && txq->len >= MWL8K_TX_DESCS) { - /* This is the case in which the tx packet is destined for an - * AMPDU queue and that AMPDU queue is full. Because we don't - * start and stop the AMPDU queues, we must drop these packets. - */ - dev_kfree_skb(skb); - spin_unlock_bh(&priv->tx_lock); - return; + /* Mgmt frames that go out frequently are probe + * responses. Other mgmt frames got out relatively + * infrequently. Hence reserve 2 buffers so that + * other mgmt frames do not get dropped due to an + * already queued probe response in one of the + * reserved buffers. + */ + + if (txq->len >= MWL8K_TX_DESCS - 2) { + if (mgmtframe == false || + txq->len == MWL8K_TX_DESCS) { + if (start_ba_session) { + spin_lock(&priv->stream_lock); + mwl8k_remove_stream(hw, stream); + spin_unlock(&priv->stream_lock); + } + spin_unlock_bh(&priv->tx_lock); + dev_kfree_skb(skb); + return; + } } BUG_ON(txq->skb[txq->tail] != NULL); @@ -1975,6 +1999,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id; else tx->peer_id = 0; + + if (priv->ap_fw) + tx->timestamp = cpu_to_le32(ioread32(priv->regs + + MWL8K_HW_TIMER_REGISTER)); + wmb(); tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus); @@ -1985,9 +2014,6 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb) if (txq->tail == MWL8K_TX_DESCS) txq->tail = 0; - if (txq->head == txq->tail && index < MWL8K_TX_WMM_QUEUES) - ieee80211_stop_queue(hw, index); - mwl8k_tx_start(priv); spin_unlock_bh(&priv->tx_lock); @@ -2482,7 +2508,8 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw) cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT | MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP | - MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON); + MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON | + MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY); cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS); cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS); @@ -5466,6 +5493,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) hw->extra_tx_headroom = sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts); + hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0; + hw->channel_change_time = 10; hw->queues = MWL8K_TX_WMM_QUEUES; diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 13d750d..54cc0bb 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -491,7 +491,7 @@ static int p54_parse_rssical(struct ieee80211_hw *dev, struct pda_rssi_cal_entry *cal = (void *) &data[offset]; for (i = 0; i < entries; i++) { - u16 freq; + u16 freq = 0; switch (i) { case IEEE80211_BAND_2GHZ: freq = 2437; diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index 2fab7d2..b6a061c 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -727,3 +727,34 @@ int p54_fetch_statistics(struct p54_common *priv) p54_tx(priv, skb); return 0; } + +int p54_set_groupfilter(struct p54_common *priv) +{ + struct p54_group_address_table *grp; + struct sk_buff *skb; + bool on = false; + + skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp), + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp)); + + on = !(priv->filter_flags & FIF_ALLMULTI) && + (priv->mc_maclist_num > 0 && + priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM); + + if (on) { + grp->filter_enable = cpu_to_le16(1); + grp->num_address = cpu_to_le16(priv->mc_maclist_num); + memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list)); + } else { + grp->filter_enable = cpu_to_le16(0); + grp->num_address = cpu_to_le16(0); + memset(grp->mac_list, 0, sizeof(grp->mac_list)); + } + + p54_tx(priv, skb); + return 0; +} diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h index eb581ab..3d8d622 100644 --- a/drivers/net/wireless/p54/lmac.h +++ b/drivers/net/wireless/p54/lmac.h @@ -540,6 +540,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set); int p54_setup_mac(struct p54_common *priv); int p54_set_ps(struct p54_common *priv); int p54_fetch_statistics(struct p54_common *priv); +int p54_set_groupfilter(struct p54_common *priv); /* e/v DCF setup */ int p54_set_edcf(struct p54_common *priv); diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index a946991..a5a6d9e 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -308,6 +308,31 @@ out: return ret; } +static u64 p54_prepare_multicast(struct ieee80211_hw *dev, + struct netdev_hw_addr_list *mc_list) +{ + struct p54_common *priv = dev->priv; + struct netdev_hw_addr *ha; + int i; + + BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) != + ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list)); + /* + * The first entry is reserved for the global broadcast MAC. + * Otherwise the firmware will drop it and ARP will no longer work. + */ + i = 1; + priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN); + i++; + if (i >= ARRAY_SIZE(priv->mc_maclist)) + break; + } + + return 1; /* update */ +} + static void p54_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -316,12 +341,16 @@ static void p54_configure_filter(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; *total_flags &= FIF_PROMISC_IN_BSS | + FIF_ALLMULTI | FIF_OTHER_BSS; priv->filter_flags = *total_flags; if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) p54_setup_mac(priv); + + if (changed_flags & FIF_ALLMULTI || multicast) + p54_set_groupfilter(priv); } static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, @@ -591,6 +620,7 @@ static const struct ieee80211_ops p54_ops = { .config = p54_config, .flush = p54_flush, .bss_info_changed = p54_bss_info_changed, + .prepare_multicast = p54_prepare_multicast, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -660,6 +690,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) init_completion(&priv->beacon_comp); INIT_DELAYED_WORK(&priv->work, p54_work); + memset(&priv->mc_maclist[0], ~0, ETH_ALEN); return dev; } EXPORT_SYMBOL_GPL(p54_init_common); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 50730fc..799d05e 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -211,8 +211,10 @@ struct p54_common { /* BBP/MAC state */ u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; + u8 mc_maclist[4][ETH_ALEN]; u16 wakeup_timer; unsigned int filter_flags; + int mc_maclist_num; int mode; u32 tsf_low32, tsf_high32; u32 basic_rate_mask; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index b21f8123..15237c2 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1797,6 +1797,7 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags); } __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 5cd096e..790afd3 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1640,7 +1640,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, struct channel_info *info) { u8 rfcsr; - u16 eeprom; rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); @@ -1670,11 +1669,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); if (rf->channel <= 14) { int idx = rf->channel-1; - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) { /* r55/r59 value array of channel 1~14 */ static const char r55_bt_rev[] = {0x83, 0x83, @@ -2917,8 +2915,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) ant = (div_mode == 3) ? 1 : 0; /* check if this is a Bluetooth combo card */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) { + if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) { u32 reg; rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); @@ -3727,16 +3724,8 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) } /* - * Read frequency offset and RF programming sequence. - */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); - rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); - - /* - * Read external LNA informations. + * Determine external LNA informations. */ - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom); - if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G)) __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags); if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G)) @@ -3749,6 +3738,18 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags); /* + * Detect if this device has Bluetooth co-existence. + */ + if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) + __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags); + + /* + * Read frequency offset and RF programming sequence. + */ + rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom); + rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET); + + /* * Store led settings, for correct led behaviour. */ #ifdef CONFIG_RT2X00_LIB_LEDS @@ -3756,7 +3757,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); - rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg); + rt2x00dev->led_mcu_reg = eeprom; #endif /* CONFIG_RT2X00_LIB_LEDS */ /* diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 08d3947..cc4a54f 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -302,8 +302,8 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, /* * Write firmware to device. */ - rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, - data, len); + rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, + data, len); rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000); rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 0d4e8fa..0eb44cf 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -114,12 +114,12 @@ static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev) return false; } -static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, +static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, int urb_status, u32 tx_status) { if (urb_status) { WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status); - return; + return false; } /* try to read all TX_STA_FIFO entries before scheduling txdone_work */ @@ -129,13 +129,14 @@ static void rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev, "drop tx status report.\n"); queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } else - rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO, - rt2800usb_tx_sta_fifo_read_completed); + return true; } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) { queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } else if (rt2800usb_txstatus_pending(rt2x00dev)) { - mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); } + + return false; } static void rt2800usb_tx_dma_done(struct queue_entry *entry) @@ -493,7 +494,7 @@ static void rt2800usb_work_txdone(struct work_struct *work) * also delayed -> use a timer to retrieve it. */ if (rt2800usb_txstatus_pending(rt2x00dev)) - mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(20)); + mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2)); } /* @@ -633,6 +634,7 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags); __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); setup_timer(&rt2x00dev->txstatus_timer, rt2800usb_tx_sta_fifo_timeout, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 9d1a158..c446db6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -662,6 +662,7 @@ enum rt2x00_state_flags { * Driver configuration */ CONFIG_CHANNEL_HT40, + CONFIG_POWERSAVING, }; /* @@ -681,6 +682,7 @@ enum rt2x00_capability_flags { REQUIRE_TASKLET_CONTEXT, REQUIRE_SW_SEQNO, REQUIRE_HT_TX_DESC, + REQUIRE_PS_AUTOWAKE, /* * Capabilities @@ -697,6 +699,7 @@ enum rt2x00_capability_flags { CAPABILITY_EXTERNAL_LNA_A, CAPABILITY_EXTERNAL_LNA_BG, CAPABILITY_DOUBLE_ANTENNA, + CAPABILITY_BT_COEXIST, }; /* @@ -874,10 +877,20 @@ struct rt2x00_dev { u8 calibration[2]; /* + * Association id. + */ + u16 aid; + + /* * Beacon interval. */ u16 beacon_int; + /** + * Timestamp of last received beacon + */ + unsigned long last_beacon; + /* * Low level statistics which will have * to be kept up to date while device is running. @@ -906,6 +919,11 @@ struct rt2x00_dev { struct work_struct txdone_work; /* + * Powersaving work + */ + struct delayed_work autowakeup_work; + + /* * Data queue arrays for RX, TX, Beacon and ATIM. */ unsigned int data_queues; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index f787264..555180d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -100,6 +100,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.basic_rates = bss_conf->basic_rates; erp.beacon_int = bss_conf->beacon_int; + /* Update the AID, this is needed for dynamic PS support */ + rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; + rt2x00dev->last_beacon = bss_conf->timestamp; + /* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int; @@ -204,6 +208,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, { struct rt2x00lib_conf libconf; u16 hw_value; + u16 autowake_timeout; + u16 beacon_int; + u16 beacon_diff; memset(&libconf, 0, sizeof(libconf)); @@ -227,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, sizeof(libconf.channel)); } + if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) + cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); + /* * Start configuration. */ @@ -239,6 +250,26 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00link_reset_tuner(rt2x00dev, false); + if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && + (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && + (conf->flags & IEEE80211_CONF_PS)) { + beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; + beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int); + + if (beacon_diff > beacon_int) + beacon_diff = 0; + + autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; + queue_delayed_work(rt2x00dev->workqueue, + &rt2x00dev->autowakeup_work, + autowake_timeout - 15); + } + + if (conf->flags & IEEE80211_CONF_PS) + set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); + else + clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); + rt2x00dev->curr_band = conf->channel->band; rt2x00dev->curr_freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level; diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 7776d9f..2eb5196 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -141,6 +141,16 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) rt2x00dev); } +static void rt2x00lib_autowakeup(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, autowakeup_work.work); + + if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) + ERROR(rt2x00dev, "Device failed to wakeup.\n"); + clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); +} + /* * Interrupt context handlers. */ @@ -416,6 +426,77 @@ void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status) } EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo); +static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + + return NULL; +} + +static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb, + struct rxdone_entry_desc *rxdesc) +{ + struct ieee80211_hdr *hdr = (void *) skb->data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool cam; + + /* If this is not a beacon, or if mac80211 has no powersaving + * configured, or if the device is already in powersaving mode + * we can exit now. */ + if (likely(!ieee80211_is_beacon(hdr->frame_control) || + !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* min. beacon length + FCS_LEN */ + if (skb->len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (!(rxdesc->dev_flags & RXDONE_MY_BSS) || + !rt2x00dev->aid) + return; + + rt2x00dev->last_beacon = jiffies; + + tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + cam |= (tim_ie->bitmap_ctrl & 0x01); + + if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, + IEEE80211_CONF_CHANGE_PS); +} + static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, struct rxdone_entry_desc *rxdesc) { @@ -531,6 +612,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry) rxdesc.flags |= RX_FLAG_HT; /* + * Check if this is a beacon, and more frames have been + * buffered while we were in powersaving mode. + */ + rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc); + + /* * Update extra components */ rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc); @@ -1017,6 +1104,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) } INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); + INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); /* * Let the driver probe the device to detect the capabilities. diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index cb208d5..39e1052 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -170,19 +170,22 @@ struct rt2x00_async_read_data { __le32 reg; struct usb_ctrlrequest cr; struct rt2x00_dev *rt2x00dev; - void (*callback)(struct rt2x00_dev *,int,u32); + bool (*callback)(struct rt2x00_dev *, int, u32); }; static void rt2x00usb_register_read_async_cb(struct urb *urb) { struct rt2x00_async_read_data *rd = urb->context; - rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg)); - kfree(urb->context); + if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) { + if (usb_submit_urb(urb, GFP_ATOMIC) < 0) + kfree(rd); + } else + kfree(rd); } void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - void (*callback)(struct rt2x00_dev*,int,u32)) + bool (*callback)(struct rt2x00_dev*, int, u32)) { struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); struct urb *urb; diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 64be34f..323ca7b 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -349,10 +349,12 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, * be called from atomic context. The callback will be called * when the URB completes. Otherwise the function is similar * to rt2x00usb_register_read(). + * When the callback function returns false, the memory will be cleaned up, + * when it returns true, the urb will be fired again. */ void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev, const unsigned int offset, - void (*callback)(struct rt2x00_dev*,int,u32)); + bool (*callback)(struct rt2x00_dev*, int, u32)); /* * Radio handlers diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index a6ce7d6..ad20953 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2209,6 +2209,7 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) if (!modparam_nohwcrypt) __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags); __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags); + __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags); /* * Set the rssi offset. diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index b259f80..ccb6da3 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -50,8 +50,9 @@ *3) functions called by core.c *4) wq & timer callback functions *5) frame process functions - *6) sysfs functions - *7) ... + *6) IOT functions + *7) sysfs functions + *8) ... */ /********************************************************* @@ -59,7 +60,7 @@ * mac80211 init functions * *********************************************************/ -static struct ieee80211_channel rtl_channeltable[] = { +static struct ieee80211_channel rtl_channeltable_2g[] = { {.center_freq = 2412, .hw_value = 1,}, {.center_freq = 2417, .hw_value = 2,}, {.center_freq = 2422, .hw_value = 3,}, @@ -76,7 +77,34 @@ static struct ieee80211_channel rtl_channeltable[] = { {.center_freq = 2484, .hw_value = 14,}, }; -static struct ieee80211_rate rtl_ratetable[] = { +static struct ieee80211_channel rtl_channeltable_5g[] = { + {.center_freq = 5180, .hw_value = 36,}, + {.center_freq = 5200, .hw_value = 40,}, + {.center_freq = 5220, .hw_value = 44,}, + {.center_freq = 5240, .hw_value = 48,}, + {.center_freq = 5260, .hw_value = 52,}, + {.center_freq = 5280, .hw_value = 56,}, + {.center_freq = 5300, .hw_value = 60,}, + {.center_freq = 5320, .hw_value = 64,}, + {.center_freq = 5500, .hw_value = 100,}, + {.center_freq = 5520, .hw_value = 104,}, + {.center_freq = 5540, .hw_value = 108,}, + {.center_freq = 5560, .hw_value = 112,}, + {.center_freq = 5580, .hw_value = 116,}, + {.center_freq = 5600, .hw_value = 120,}, + {.center_freq = 5620, .hw_value = 124,}, + {.center_freq = 5640, .hw_value = 128,}, + {.center_freq = 5660, .hw_value = 132,}, + {.center_freq = 5680, .hw_value = 136,}, + {.center_freq = 5700, .hw_value = 140,}, + {.center_freq = 5745, .hw_value = 149,}, + {.center_freq = 5765, .hw_value = 153,}, + {.center_freq = 5785, .hw_value = 157,}, + {.center_freq = 5805, .hw_value = 161,}, + {.center_freq = 5825, .hw_value = 165,}, +}; + +static struct ieee80211_rate rtl_ratetable_2g[] = { {.bitrate = 10, .hw_value = 0x00,}, {.bitrate = 20, .hw_value = 0x01,}, {.bitrate = 55, .hw_value = 0x02,}, @@ -91,18 +119,57 @@ static struct ieee80211_rate rtl_ratetable[] = { {.bitrate = 540, .hw_value = 0x0b,}, }; +static struct ieee80211_rate rtl_ratetable_5g[] = { + {.bitrate = 60, .hw_value = 0x04,}, + {.bitrate = 90, .hw_value = 0x05,}, + {.bitrate = 120, .hw_value = 0x06,}, + {.bitrate = 180, .hw_value = 0x07,}, + {.bitrate = 240, .hw_value = 0x08,}, + {.bitrate = 360, .hw_value = 0x09,}, + {.bitrate = 480, .hw_value = 0x0a,}, + {.bitrate = 540, .hw_value = 0x0b,}, +}; + static const struct ieee80211_supported_band rtl_band_2ghz = { .band = IEEE80211_BAND_2GHZ, - .channels = rtl_channeltable, - .n_channels = ARRAY_SIZE(rtl_channeltable), + .channels = rtl_channeltable_2g, + .n_channels = ARRAY_SIZE(rtl_channeltable_2g), + + .bitrates = rtl_ratetable_2g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g), + + .ht_cap = {0}, +}; + +static struct ieee80211_supported_band rtl_band_5ghz = { + .band = IEEE80211_BAND_5GHZ, + + .channels = rtl_channeltable_5g, + .n_channels = ARRAY_SIZE(rtl_channeltable_5g), - .bitrates = rtl_ratetable, - .n_bitrates = ARRAY_SIZE(rtl_ratetable), + .bitrates = rtl_ratetable_5g, + .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g), .ht_cap = {0}, }; +static const u8 tid_to_ac[] = { + 2, /* IEEE80211_AC_BE */ + 3, /* IEEE80211_AC_BK */ + 3, /* IEEE80211_AC_BK */ + 2, /* IEEE80211_AC_BE */ + 1, /* IEEE80211_AC_VI */ + 1, /* IEEE80211_AC_VI */ + 0, /* IEEE80211_AC_VO */ + 0, /* IEEE80211_AC_VO */ +}; + +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid) +{ + return tid_to_ac[tid]; +} + static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, struct ieee80211_sta_ht_cap *ht_cap) { @@ -115,6 +182,9 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU; + if (rtlpriv->rtlhal.disable_amsdu_8k) + ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU; + /* *Maximum length of AMPDU that the STA can receive. *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets) @@ -159,37 +229,99 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw, static void _rtl_init_mac80211(struct ieee80211_hw *hw) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct ieee80211_supported_band *sband; - /* <1> use mac->bands as mem for hw->wiphy->bands */ - sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); - /* - * <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] - * to default value(1T1R) - */ - memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, - sizeof(struct ieee80211_supported_band)); + if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset == + BAND_ON_BOTH) { + /* 1: 2.4 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); - /* <3> init ht cap base on ant_num */ - _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); - /* <4> set mac->sband to wiphy->sband */ - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + + /* 2: 5 G bands */ + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), + &rtl_band_2ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + /* <1> use mac->bands as mem for hw->wiphy->bands */ + sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]); + + /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ] + * to default value(1T1R) */ + memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), + &rtl_band_5ghz, + sizeof(struct ieee80211_supported_band)); + + /* <3> init ht cap base on ant_num */ + _rtl_init_hw_ht_capab(hw, &sband->ht_cap); + + /* <4> set mac->sband to wiphy->sband */ + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband; + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, + ("Err BAND %d\n", + rtlhal->current_bandtype)); + } + } /* <5> set hw caps */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/ - /*IEEE80211_HW_SUPPORTS_PS | */ - /*IEEE80211_HW_PS_NULLFUNC_STACK | */ - /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + IEEE80211_HW_BEACON_FILTER | + IEEE80211_HW_AMPDU_AGGREGATION | IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; + /* swlps or hwlps has been set in diff chip in init_sw_vars */ + if (rtlpriv->psc.swctrl_lps) + hw->flags |= IEEE80211_HW_SUPPORTS_PS | + IEEE80211_HW_PS_NULLFUNC_STACK | + /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */ + 0; + hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->rts_threshold = 2347; @@ -199,9 +331,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) /* TODO: Correct this value for our hw */ /* TODO: define these hard code value */ hw->channel_change_time = 100; - hw->max_listen_interval = 5; + hw->max_listen_interval = 10; hw->max_rate_tries = 4; /* hw->max_rates = 1; */ + hw->sta_data_size = sizeof(struct rtl_sta_info); /* <6> mac address */ if (is_valid_ether_addr(rtlefuse->dev_addr)) { @@ -230,6 +363,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) (void *)rtl_watchdog_wq_callback); INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, (void *)rtl_ips_nic_off_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_work, + (void *)rtl_swlps_wq_callback); + INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq, + (void *)rtl_swlps_rfon_wq_callback); } @@ -241,6 +378,8 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw) cancel_delayed_work(&rtlpriv->works.watchdog_wq); cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); } void rtl_init_rfkill(struct ieee80211_hw *hw) @@ -310,6 +449,8 @@ int rtl_init_core(struct ieee80211_hw *hw) spin_lock_init(&rtlpriv->locks.rf_ps_lock); spin_lock_init(&rtlpriv->locks.rf_lock); spin_lock_init(&rtlpriv->locks.lps_lock); + spin_lock_init(&rtlpriv->locks.waitq_lock); + spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock); rtlmac->link_state = MAC80211_NOLINK; @@ -329,12 +470,6 @@ void rtl_init_rx_config(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER, - (u8 *) (&mac->rx_mgt_filter)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER, - (u8 *) (&mac->rx_ctrl_filter)); - rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER, - (u8 *) (&mac->rx_data_filter)); } /********************************************************* @@ -361,28 +496,40 @@ static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw, } static void _rtl_query_shortgi(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc, struct ieee80211_tx_info *info) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); u8 rate_flag = info->control.rates[0].flags; - + u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0; tcb_desc->use_shortgi = false; - if (!mac->ht_enable) + if (sta == NULL) return; - if (!mac->sgi_40 && !mac->sgi_20) + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + + if (!(sta->ht_cap.ht_supported)) + return; + + if (!sgi_40 && !sgi_20) return; - if ((mac->bw_40 == true) && mac->sgi_40) + if (mac->opmode == NL80211_IFTYPE_STATION) + bw_40 = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + if ((bw_40 == true) && sgi_40) tcb_desc->use_shortgi = true; - else if ((mac->bw_40 == false) && mac->sgi_20) + else if ((bw_40 == false) && sgi_20) tcb_desc->use_shortgi = true; if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI)) tcb_desc->use_shortgi = false; - } static void _rtl_query_protection_mode(struct ieee80211_hw *hw, @@ -410,19 +557,25 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw, tcb_desc->rts_enable = true; tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M]; } - } static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u8 ratr_index = 7; + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + ratr_index = sta_entry->ratr_index; + } if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) { - if (mac->opmode == NL80211_IFTYPE_STATION) + if (mac->opmode == NL80211_IFTYPE_STATION) { tcb_desc->ratr_index = 0; - else if (mac->opmode == NL80211_IFTYPE_ADHOC) { + } else if (mac->opmode == NL80211_IFTYPE_ADHOC) { if (tcb_desc->multicast || tcb_desc->broadcast) { tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M]; @@ -430,36 +583,61 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, } else { /* TODO */ } + tcb_desc->ratr_index = ratr_index; + } else if (mac->opmode == NL80211_IFTYPE_AP) { + tcb_desc->ratr_index = ratr_index; } } if (rtlpriv->dm.useramask) { - /* TODO adhoc and station handled differently in the future */ - tcb_desc->mac_id = 0; - - if ((mac->mode == WIRELESS_MODE_N_24G) || - (mac->mode == WIRELESS_MODE_N_5G)) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; - } else if (mac->mode & WIRELESS_MODE_G) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; - } else if (mac->mode & WIRELESS_MODE_B) { - tcb_desc->ratr_index = RATR_INX_WIRELESS_B; + /* TODO we will differentiate adhoc and station futrue */ + if (mac->opmode == NL80211_IFTYPE_STATION) { + tcb_desc->mac_id = 0; + + if (mac->mode == WIRELESS_MODE_N_24G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB; + else if (mac->mode == WIRELESS_MODE_N_5G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_NG; + else if (mac->mode & WIRELESS_MODE_G) + tcb_desc->ratr_index = RATR_INX_WIRELESS_GB; + else if (mac->mode & WIRELESS_MODE_B) + tcb_desc->ratr_index = RATR_INX_WIRELESS_B; + else if (mac->mode & WIRELESS_MODE_A) + tcb_desc->ratr_index = RATR_INX_WIRELESS_G; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (NULL != sta) { + if (sta->aid > 0) + tcb_desc->mac_id = sta->aid + 1; + else + tcb_desc->mac_id = 1; + } else { + tcb_desc->mac_id = 0; + } } } } static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); tcb_desc->packet_bw = false; - - if (!mac->bw_40 || !mac->ht_enable) + if (!sta) return; - + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (!(sta->ht_cap.ht_supported) || + !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + return; + } else if (mac->opmode == NL80211_IFTYPE_STATION) { + if (!mac->bw_40 || !(sta->ht_cap.ht_supported)) + return; + } if (tcb_desc->multicast || tcb_desc->broadcast) return; @@ -486,22 +664,21 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw) void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw)); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct ieee80211_rate *txrate; __le16 fc = hdr->frame_control; - memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + txrate = ieee80211_get_tx_rate(hw, info); + tcb_desc->hw_rate = txrate->hw_value; if (ieee80211_is_data(fc)) { - txrate = ieee80211_get_tx_rate(hw, info); - tcb_desc->hw_rate = txrate->hw_value; - /* - *we set data rate RTL_RC_CCK_RATE1M + *we set data rate INX 0 *in rtl_rc.c if skb is special data or *mgt which need low data rate. */ @@ -510,12 +687,11 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *So tcb_desc->hw_rate is just used for *special data and mgt frames */ - if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) { + if (info->control.rates[0].idx == 0 && + ieee80211_is_nullfunc(fc)) { tcb_desc->use_driver_rate = true; - tcb_desc->ratr_index = 7; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; - tcb_desc->hw_rate = - rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; tcb_desc->disable_ratefallback = 1; } else { /* @@ -525,7 +701,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *and N rate will all be controlled by FW *when tcb_desc->use_driver_rate = false */ - if (rtlmac->ht_enable) { + if (sta && (sta->ht_cap.ht_supported)) { tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw); } else { if (rtlmac->mode == WIRELESS_MODE_B) { @@ -543,43 +719,25 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr))) tcb_desc->broadcast = 1; - _rtl_txrate_selectmode(hw, tcb_desc); - _rtl_query_bandwidth_mode(hw, tcb_desc); + _rtl_txrate_selectmode(hw, sta, tcb_desc); + _rtl_query_bandwidth_mode(hw, sta, tcb_desc); _rtl_qurey_shortpreamble_mode(hw, tcb_desc, info); - _rtl_query_shortgi(hw, tcb_desc, info); + _rtl_query_shortgi(hw, sta, tcb_desc, info); _rtl_query_protection_mode(hw, tcb_desc, info); } else { tcb_desc->use_driver_rate = true; - tcb_desc->ratr_index = 7; + tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; tcb_desc->disable_ratefallback = 1; tcb_desc->mac_id = 0; - - tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + tcb_desc->packet_bw = false; } } EXPORT_SYMBOL(rtl_get_tcb_desc); -bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb) -{ - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); - __le16 fc = hdr->frame_control; - - if (ieee80211_is_auth(fc)) { - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); - rtl_ips_nic_on(hw); - - mac->link_state = MAC80211_LINKING; - } - - return true; -} - bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) { struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); struct rtl_priv *rtlpriv = rtl_priv(hw); __le16 fc = hdr->frame_control; u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN)); @@ -624,9 +782,8 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - __le16 fc = hdr->frame_control; + __le16 fc = rtl_get_fc(skb); u16 ether_type; u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb); const struct iphdr *ip; @@ -634,12 +791,11 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) if (!ieee80211_is_data(fc)) return false; - if (ieee80211_is_nullfunc(fc)) - return true; ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len + SNAP_SIZE + PROTOC_TYPE_SIZE); ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE); + /* ether_type = ntohs(ether_type); */ if (ETH_P_IP == ether_type) { if (IPPROTO_UDP == ip->protocol) { @@ -696,61 +852,92 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx) * functions called by core.c * *********************************************************/ -int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn) +int rtl_tx_agg_start(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_tid_data *tid_data; struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; - RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, - ("on ra = %pM tid = %d\n", ra, tid)); + if (sta == NULL) + return -EINVAL; if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; - if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Start AGG when state is not RTL_AGG_OFF !\n")); + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + if (!sta_entry) return -ENXIO; - } - - tid_data = &mac->tids[tid]; - *ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data = &sta_entry->tids[tid]; RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, - ("HW queue is empty tid:%d\n", tid)); - tid_data->agg.agg_state = RTL_AGG_ON; + ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid, + tid_data->seq_number)); + + *ssn = tid_data->seq_number; + tid_data->agg.agg_state = RTL_AGG_START; - ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid); + ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); return 0; } -int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid) +int rtl_tx_agg_stop(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) { - int ssn = -1; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; - if (!ra) { + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); return -EINVAL; } + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); + if (unlikely(tid >= MAX_TID_COUNT)) return -EINVAL; - if (mac->tids[tid].agg.agg_state != RTL_AGG_ON) - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Stopping AGG while state not ON or starting\n")); + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP; + + ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid); + + return 0; +} + +int rtl_tx_agg_oper(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u16 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_tid_data *tid_data; + struct rtl_sta_info *sta_entry = NULL; + + if (sta == NULL) + return -EINVAL; + + if (!sta->addr) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n")); + return -EINVAL; + } - tid_data = &mac->tids[tid]; - ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, + ("on ra = %pM tid = %d\n", sta->addr, tid)); - mac->tids[tid].agg.agg_state = RTL_AGG_OFF; + if (unlikely(tid >= MAX_TID_COUNT)) + return -EINVAL; - ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid); + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + tid_data = &sta_entry->tids[tid]; + sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL; return 0; } @@ -769,18 +956,16 @@ void rtl_watchdog_wq_callback(void *data) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - bool busytraffic = false; bool higher_busytraffic = false; bool higher_busyrxtraffic = false; - bool higher_busytxtraffic = false; - - u8 idx = 0; + u8 idx, tid; u32 rx_cnt_inp4eriod = 0; u32 tx_cnt_inp4eriod = 0; u32 aver_rx_cnt_inperiod = 0; u32 aver_tx_cnt_inperiod = 0; - + u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0}; + u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0}; bool enter_ps = false; if (is_hal_stop(rtlhal)) @@ -794,9 +979,6 @@ void rtl_watchdog_wq_callback(void *data) mac->cnt_after_linked = 0; } - /* <2> DM */ - rtlpriv->cfg->ops->dm_watchdog(hw); - /* *<3> to check if traffic busy, if * busytraffic we don't change channel @@ -835,8 +1017,27 @@ void rtl_watchdog_wq_callback(void *data) /* Extremely high Rx data. */ if (aver_rx_cnt_inperiod > 5000) higher_busyrxtraffic = true; + } + + /* check every tid's tx traffic */ + for (tid = 0; tid <= 7; tid++) { + for (idx = 0; idx <= 2; idx++) + rtlpriv->link_info.tidtx_in4period[tid][idx] = + rtlpriv->link_info.tidtx_in4period[tid] + [idx + 1]; + rtlpriv->link_info.tidtx_in4period[tid][3] = + rtlpriv->link_info.tidtx_inperiod[tid]; + + for (idx = 0; idx <= 3; idx++) + tidtx_inp4eriod[tid] += + rtlpriv->link_info.tidtx_in4period[tid][idx]; + aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4; + if (aver_tidtx_inperiod[tid] > 5000) + rtlpriv->link_info.higher_busytxtraffic[tid] = + true; else - higher_busytxtraffic = false; + rtlpriv->link_info.higher_busytxtraffic[tid] = + false; } if (((rtlpriv->link_info.num_rx_inperiod + @@ -855,11 +1056,15 @@ void rtl_watchdog_wq_callback(void *data) rtlpriv->link_info.num_rx_inperiod = 0; rtlpriv->link_info.num_tx_inperiod = 0; + for (tid = 0; tid <= 7; tid++) + rtlpriv->link_info.tidtx_inperiod[tid] = 0; rtlpriv->link_info.busytraffic = busytraffic; rtlpriv->link_info.higher_busytraffic = higher_busytraffic; rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic; + /* <3> DM */ + rtlpriv->cfg->ops->dm_watchdog(hw); } void rtl_watch_dog_timer_callback(unsigned long data) @@ -876,6 +1081,268 @@ void rtl_watch_dog_timer_callback(unsigned long data) /********************************************************* * + * frame process functions + * + *********************************************************/ +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return NULL; + + if (pos[0] == ie) + return pos; + + pos += 2 + pos[1]; + } + return NULL; +} + +/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */ +/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */ +static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw, + enum ieee80211_smps_mode smps, u8 *da, u8 *bssid) +{ + struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); + struct sk_buff *skb; + struct ieee80211_mgmt *action_frame; + + /* 27 = header + category + action + smps mode */ + skb = dev_alloc_skb(27 + hw->extra_tx_headroom); + if (!skb) + return NULL; + + skb_reserve(skb, hw->extra_tx_headroom); + action_frame = (void *)skb_put(skb, 27); + memset(action_frame, 0, 27); + memcpy(action_frame->da, da, ETH_ALEN); + memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN); + memcpy(action_frame->bssid, bssid, ETH_ALEN); + action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_ACTION); + action_frame->u.action.category = WLAN_CATEGORY_HT; + action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS; + switch (smps) { + case IEEE80211_SMPS_AUTOMATIC:/* 0 */ + case IEEE80211_SMPS_NUM_MODES:/* 4 */ + WARN_ON(1); + case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */ + break; + case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */ + break; + case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/ + action_frame->u.action.u.ht_smps.smps_control = + WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */ + break; + } + + return skb; +} + +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + enum ieee80211_smps_mode smps) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + if (rtlpriv->mac80211.act_scanning) + goto err_free; + + if (!sta) + goto err_free; + + if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) + goto err_free; + + if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) + goto err_free; + + /* this is a type = mgmt * stype = action frame */ + if (skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct rtl_sta_info *sta_entry = + (struct rtl_sta_info *) sta->drv_priv; + sta_entry->mimo_ps = smps; + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + + info->control.rates[0].idx = 0; + info->control.sta = sta; + info->band = hw->conf.channel->band; + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + } +err_free: + return 0; +} + +/********************************************************* + * + * IOT functions + * + *********************************************************/ +static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw, + struct octet_string vendor_ie) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool matched = false; + static u8 athcap_1[] = { 0x00, 0x03, 0x7F }; + static u8 athcap_2[] = { 0x00, 0x13, 0x74 }; + static u8 broadcap_1[] = { 0x00, 0x10, 0x18 }; + static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 }; + static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 }; + static u8 racap[] = { 0x00, 0x0c, 0x43 }; + static u8 ciscocap[] = { 0x00, 0x40, 0x96 }; + static u8 marvcap[] = { 0x00, 0x50, 0x43 }; + + if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 || + memcmp(vendor_ie.octet, athcap_2, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_ATH; + matched = true; + } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_2, 3) == 0 || + memcmp(vendor_ie.octet, broadcap_3, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_BROAD; + matched = true; + } else if (memcmp(vendor_ie.octet, racap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_RAL; + matched = true; + } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_CISCO; + matched = true; + } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) { + rtlpriv->mac80211.vendor = PEER_MARV; + matched = true; + } + + return matched; +} + +static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data, + unsigned int len) +{ + struct ieee80211_mgmt *mgmt = (void *)data; + struct octet_string vendor_ie; + u8 *pos, *end; + + pos = (u8 *)mgmt->u.beacon.variable; + end = data + len; + while (pos < end) { + if (pos[0] == 221) { + vendor_ie.length = pos[1]; + vendor_ie.octet = &pos[2]; + if (rtl_chk_vendor_ouisub(hw, vendor_ie)) + return true; + } + + if (pos + 2 + pos[1] > end) + return false; + + pos += 2 + pos[1]; + } + return false; +} + +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *)data; + u32 vendor = PEER_UNKNOWN; + + static u8 ap3_1[3] = { 0x00, 0x14, 0xbf }; + static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 }; + static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e }; + static u8 ap4_1[3] = { 0x00, 0x90, 0xcc }; + static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e }; + static u8 ap4_3[3] = { 0x00, 0x18, 0x02 }; + static u8 ap4_4[3] = { 0x00, 0x17, 0x3f }; + static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf }; + static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 }; + static u8 ap5_2[3] = { 0x00, 0x21, 0x91 }; + static u8 ap5_3[3] = { 0x00, 0x24, 0x01 }; + static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 }; + static u8 ap5_5[3] = { 0x00, 0x17, 0x9A }; + static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 }; + static u8 ap6_1[3] = { 0x00, 0x17, 0x94 }; + static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 }; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (mac->link_state == MAC80211_NOLINK) { + mac->vendor = PEER_UNKNOWN; + return; + } + + if (mac->cnt_after_linked > 2) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + if (rtl_find_221_ie(hw, data, len)) + vendor = mac->vendor; + + if ((memcmp(mac->bssid, ap5_1, 3) == 0) || + (memcmp(mac->bssid, ap5_2, 3) == 0) || + (memcmp(mac->bssid, ap5_3, 3) == 0) || + (memcmp(mac->bssid, ap5_4, 3) == 0) || + (memcmp(mac->bssid, ap5_5, 3) == 0) || + (memcmp(mac->bssid, ap5_6, 3) == 0) || + vendor == PEER_ATH) { + vendor = PEER_ATH; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ath find\n")); + } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) || + (memcmp(mac->bssid, ap4_5, 3) == 0) || + (memcmp(mac->bssid, ap4_1, 3) == 0) || + (memcmp(mac->bssid, ap4_2, 3) == 0) || + (memcmp(mac->bssid, ap4_3, 3) == 0) || + vendor == PEER_RAL) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ral findn\n")); + vendor = PEER_RAL; + } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || + vendor == PEER_CISCO) { + vendor = PEER_CISCO; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>cisco find\n")); + } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) || + (memcmp(mac->bssid, ap3_2, 3) == 0) || + (memcmp(mac->bssid, ap3_3, 3) == 0) || + vendor == PEER_BROAD) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>broad find\n")); + vendor = PEER_BROAD; + } else if (memcmp(mac->bssid, ap7_1, 3) == 0 || + vendor == PEER_MARV) { + vendor = PEER_MARV; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>marv find\n")); + } + + mac->vendor = vendor; +} + +/********************************************************* + * * sysfs functions * *********************************************************/ @@ -941,12 +1408,13 @@ static int __init rtl_core_module_init(void) if (rtl_rate_control_register()) printk(KERN_ERR "rtlwifi: Unable to register rtl_rc," "use default RC !!\n"); + return 0; } static void __exit rtl_core_module_exit(void) { - /*RC*/ + /*RC*/ rtl_rate_control_unregister(); } diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 0430453..a91f3ee 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -24,13 +24,26 @@ * Hsinchu 300, Taiwan. * * Larry Finger <Larry.Finger@lwfinger.net> + * *****************************************************************************/ #ifndef __RTL_BASE_H__ #define __RTL_BASE_H__ +enum ap_peer { + PEER_UNKNOWN = 0, + PEER_RTL = 1, + PEER_RTL_92SE = 2, + PEER_BROAD = 3, + PEER_RAL = 4, + PEER_ATH = 5, + PEER_CISCO = 6, + PEER_MARV = 7, + PEER_AIRGO = 9, + PEER_MAX = 10, +} ; + #define RTL_DUMMY_OFFSET 0 -#define RTL_RX_DESC_SIZE 24 #define RTL_DUMMY_UNIT 8 #define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT) #define RTL_TX_DESC_SIZE 32 @@ -53,6 +66,14 @@ #define FRAME_OFFSET_SEQUENCE 22 #define FRAME_OFFSET_ADDRESS4 24 +#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \ + WRITEEF2BYTE(_hdr, _val) +#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \ + WRITEEF1BYTE(_hdr, _val) +#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val) +#define SET_80211_HDR_TO_DS(_hdr, _val) \ + SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val) #define SET_80211_PS_POLL_AID(_hdr, _val) \ (*(u16 *)((u8 *)(_hdr) + 2) = le16_to_cpu(_val)) @@ -64,11 +85,27 @@ #define SET_80211_HDR_DURATION(_hdr, _val) \ (*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val)) #define SET_80211_HDR_ADDRESS1(_hdr, _val) \ - memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val)) #define SET_80211_HDR_ADDRESS2(_hdr, _val) \ - memcpy((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val)) #define SET_80211_HDR_ADDRESS3(_hdr, _val) \ - memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val), ETH_ALEN) + CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val)) +#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \ + WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val) + +#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val) +#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \ + WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val) +#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val) +#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \ + READEF2BYTE(((u8 *)(__phdr)) + 34) +#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val) +#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \ + SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \ + (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val)))) int rtl_init_core(struct ieee80211_hw *hw); void rtl_deinit_core(struct ieee80211_hw *hw); @@ -80,18 +117,27 @@ void rtl_watch_dog_timer_callback(unsigned long data); void rtl_deinit_deferred_work(struct ieee80211_hw *hw); bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); -bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb); u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx); void rtl_watch_dog_timer_callback(unsigned long data); -int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, +int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u16 tid, u16 *ssn); -int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid); +int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); +int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta, + u16 tid); void rtl_watchdog_wq_callback(void *data); void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc); +int rtl_send_smps_action(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 *da, u8 *bssid, + enum ieee80211_smps_mode smps); +u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); +void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); +u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); extern struct attribute_group rtl_attribute_group; #endif diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c index 52c9c13..7295af0 100644 --- a/drivers/net/wireless/rtlwifi/cam.c +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -23,6 +23,8 @@ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * + * Larry Finger <Larry.Finger@lwfinger.net> + * *****************************************************************************/ #include "wifi.h" @@ -49,7 +51,7 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, u32 target_content = 0; u8 entry_i; - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("key_cont_128:\n %x:%x:%x:%x:%x:%x\n", key_cont_128[0], key_cont_128[1], key_cont_128[2], key_cont_128[3], @@ -68,15 +70,13 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], target_command); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): " - "WRITE %x: %x\n", + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE %x: %x\n", rtlpriv->cfg->maps[WCAMI], target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The Key ID is %d\n", entry_no)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): " - "WRITE %x: %x\n", + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE %x: %x\n", rtlpriv->cfg->maps[RWCAM], target_command)); } else if (entry_i == 1) { @@ -91,12 +91,10 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM], target_command); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A4: %x\n", - target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A0: %x\n", - target_command)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A4: %x\n", target_content)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A0: %x\n", target_command)); } else { @@ -113,16 +111,14 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no, target_command); udelay(100); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A4: %x\n", - target_content)); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("rtl_cam_program_entry(): WRITE A0: %x\n", - target_command)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A4: %x\n", target_content)); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + ("WRITE A0: %x\n", target_command)); } } - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("after set key, usconfig:%x\n", us_config)); } @@ -289,3 +285,71 @@ void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index) } EXPORT_SYMBOL(rtl_cam_empty_entry); + +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4; + u8 entry_idx = 0; + u8 i, *addr; + + if (NULL == sta_addr) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is NULL.\n")); + return TOTAL_CAM_ENTRY; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + if (memcmp(addr, sta_addr, ETH_ALEN) == 0) + return i; + } + /* Get a free CAM entry. */ + for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) { + if ((bitmap & BIT(0)) == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n", + rtlpriv->sec.hwsec_cam_bitmap, entry_idx)); + rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx; + memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx], + sta_addr, ETH_ALEN); + return entry_idx; + } + bitmap = bitmap >> 1; + } + return TOTAL_CAM_ENTRY; +} +EXPORT_SYMBOL(rtl_cam_get_free_entry); + +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 bitmap; + u8 i, *addr; + + if (NULL == sta_addr) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is NULL.\n")); + } + + if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\ + sta_addr[4]|sta_addr[5]) == 0) { + RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG, + ("sta_addr is 00:00:00:00:00:00.\n")); + return; + } + /* Does STA already exist? */ + for (i = 4; i < TOTAL_CAM_ENTRY; i++) { + addr = rtlpriv->sec.hwsec_cam_sta_addr[i]; + bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i; + if (((bitmap & BIT(0)) == BIT(0)) && + (memcmp(addr, sta_addr, ETH_ALEN) == 0)) { + /* Remove from HW Security CAM */ + memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); + rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); + printk(KERN_INFO "&&&&&&&&&del entry %d\n", i); + } + } + return; +} +EXPORT_SYMBOL(rtl_cam_del_entry); diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h index dd82f05..c62da4e 100644 --- a/drivers/net/wireless/rtlwifi/cam.h +++ b/drivers/net/wireless/rtlwifi/cam.h @@ -23,12 +23,13 @@ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park, * Hsinchu 300, Taiwan. * + * Larry Finger <Larry.Finger@lwfinger.net> + * *****************************************************************************/ #ifndef __RTL_CAM_H_ #define __RTL_CAM_H_ -#define TOTAL_CAM_ENTRY 32 #define CAM_CONTENT_COUNT 8 #define CFG_DEFAULT_KEY BIT(5) @@ -49,5 +50,7 @@ int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index); void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index); void rtl_cam_reset_sec_info(struct ieee80211_hw *hw); +u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr); +void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr); #endif diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 8fed3c6..fc89cd8 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -24,6 +24,7 @@ * Hsinchu 300, Taiwan. * * Larry Finger <Larry.Finger@lwfinger.net> + * *****************************************************************************/ #include "wifi.h" @@ -70,6 +71,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw) mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; /*reset sec info */ rtl_cam_reset_sec_info(hw); @@ -85,6 +87,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON)) goto err_free; @@ -92,8 +96,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status)) goto err_free; - - rtlpriv->intf_ops->adapter_tx(hw, skb); + if (!rtlpriv->intf_ops->waitq_insert(hw, skb)) + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); return; @@ -134,10 +138,26 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw, mac->link_state = MAC80211_LINKED; rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); + break; case NL80211_IFTYPE_AP: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("NL80211_IFTYPE_AP\n")); + + mac->link_state = MAC80211_LINKED; + rtlpriv->cfg->ops->set_bcn_reg(hw); + if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) + mac->basic_rates = 0xfff; + else + mac->basic_rates = 0xff0; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, + (u8 *) (&mac->basic_rates)); break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -184,13 +204,12 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw, mac->vif = NULL; mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); + mac->vendor = PEER_UNKNOWN; mac->opmode = NL80211_IFTYPE_UNSPECIFIED; rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); - mutex_unlock(&rtlpriv->locks.conf_mutex); } - static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -222,10 +241,25 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /*For LPS */ if (changed & IEEE80211_CONF_CHANGE_PS) { - if (conf->flags & IEEE80211_CONF_PS) - rtl_lps_enter(hw); - else - rtl_lps_leave(hw); + cancel_delayed_work(&rtlpriv->works.ps_work); + cancel_delayed_work(&rtlpriv->works.ps_rfon_wq); + if (conf->flags & IEEE80211_CONF_PS) { + rtlpriv->psc.sw_ps_enabled = true; + /* sleep here is must, or we may recv the beacon and + * cause mac80211 into wrong ps state, this will cause + * power save nullfunc send fail, and further cause + * pkt loss, So sleep must quickly but not immediatly + * because that will cause nullfunc send by mac80211 + * fail, and cause pkt loss, we have tested that 5mA + * is worked very well */ + if (!rtlpriv->psc.multi_buffered) + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, + MSECS(5)); + } else { + rtl_swlps_rf_awake(hw); + rtlpriv->psc.sw_ps_enabled = false; + } } if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) { @@ -257,7 +291,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) case NL80211_CHAN_NO_HT: /* SC */ mac->cur_40_prime_sc = - PRIME_CHNL_OFFSET_DONT_CARE; + PRIME_CHNL_OFFSET_DONT_CARE; rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20; mac->bw_40 = false; break; @@ -265,7 +299,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER; rtlphy->current_chan_bw = - HT_CHANNEL_WIDTH_20_40; + HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ @@ -276,7 +310,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* SC */ mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER; rtlphy->current_chan_bw = - HT_CHANNEL_WIDTH_20_40; + HT_CHANNEL_WIDTH_20_40; mac->bw_40 = true; /*wide channel */ @@ -286,16 +320,29 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) default: mac->bw_40 = false; RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("switch case not processed\n")); + ("switch case not processed\n")); break; } if (wide_chan <= 0) wide_chan = 1; + + /* In scanning, before we go offchannel we may send a ps=1 null + * to AP, and then we may send a ps = 0 null to AP quickly, but + * first null may have caused AP to put lots of packet to hw tx + * buffer. These packets must be tx'd before we go off channel + * so we must delay more time to let AP flush these packets + * before going offchannel, or dis-association or delete BA will + * happen by AP + */ + if (rtlpriv->mac80211.offchan_deley) { + rtlpriv->mac80211.offchan_deley = false; + mdelay(50); + } rtlphy->current_channel = wide_chan; - rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->switch_channel(hw); + rtlpriv->cfg->ops->set_channel_access(hw); rtlpriv->cfg->ops->set_bw_mode(hw, hw->conf.channel_type); } @@ -343,27 +390,28 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, } } - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - /* - *TODO: BIT(5) is probe response BIT(8) is beacon - *TODO: Use define for BIT(5) and BIT(8) - */ - if (*new_flags & FIF_BCN_PRBRESP_PROMISC) - mac->rx_mgt_filter |= (BIT(5) | BIT(8)); - else - mac->rx_mgt_filter &= ~(BIT(5) | BIT(8)); + /* if ssid not set to hw don't check bssid + * here just used for linked scanning, & linked + * and nolink check bssid is set in set network_type */ + if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) && + (mac->link_state >= MAC80211_LINKED)) { + if (mac->opmode != NL80211_IFTYPE_AP) { + if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { + rtlpriv->cfg->ops->set_chk_bssid(hw, false); + } else { + rtlpriv->cfg->ops->set_chk_bssid(hw, true); + } + } } if (changed_flags & FIF_CONTROL) { if (*new_flags & FIF_CONTROL) { mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF]; - mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("Enable receive control frame.\n")); } else { mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF]; - mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("Disable receive control frame.\n")); } @@ -380,14 +428,54 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw, ("Disable receive other BSS's frame.\n")); } } - - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf)); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER, - (u8 *) (&mac->rx_mgt_filter)); - rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER, - (u8 *) (&mac->rx_ctrl_filter)); } +static int rtl_op_sta_add(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry; + + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + sta_entry->wireless_mode = WIRELESS_MODE_G; + if (sta->supp_rates[0] <= 0xf) + sta_entry->wireless_mode = WIRELESS_MODE_B; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + } else if (rtlhal->current_bandtype == BAND_ON_5G) { + sta_entry->wireless_mode = WIRELESS_MODE_A; + if (sta->ht_cap.ht_supported == true) + sta_entry->wireless_mode = WIRELESS_MODE_N_24G; + } + + /* I found some times mac80211 give wrong supp_rates for adhoc*/ + if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC) + sta_entry->wireless_mode = WIRELESS_MODE_G; + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("Add sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); + } + return 0; +} +static int rtl_op_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_sta_info *sta_entry; + if (sta) { + RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, + ("Remove sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr))); + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = 0; + sta_entry->ratr_index = 0; + } + return 0; +} static int _rtl_get_hal_qnum(u16 queue) { int qnum; @@ -444,19 +532,18 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct ieee80211_sta *sta = NULL; mutex_lock(&rtlpriv->locks.conf_mutex); - if ((vif->type == NL80211_IFTYPE_ADHOC) || (vif->type == NL80211_IFTYPE_AP) || (vif->type == NL80211_IFTYPE_MESH_POINT)) { - if ((changed & BSS_CHANGED_BEACON) || (changed & BSS_CHANGED_BEACON_ENABLED && bss_conf->enable_beacon)) { - if (mac->beacon_enabled == 0) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_BEACON_ENABLED\n")); @@ -468,8 +555,13 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, rtlpriv->cfg->maps [RTL_IBSS_INT_MASKS], 0); + + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); } - } else { + } + if ((changed & BSS_CHANGED_BEACON_ENABLED && + !bss_conf->enable_beacon)) { if (mac->beacon_enabled == 1) { RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("ADHOC DISABLE BEACON\n")); @@ -480,7 +572,6 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, [RTL_IBSS_INT_MASKS]); } } - if (changed & BSS_CHANGED_BEACON_INT) { RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE, ("BSS_CHANGED_BEACON_INT\n")); @@ -492,11 +583,25 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, /*TODO: reference to enum ieee80211_bss_change */ if (changed & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { + /* we should reset all sec info & cam + * before set cam after linked, we should not + * reset in disassoc, that will cause tkip->wep + * fail because some flag will be wrong */ + /* reset sec info */ + rtl_cam_reset_sec_info(hw); + /* reset cam to fix wep fail issue + * when change from wpa to wep */ + rtl_cam_reset_all_entry(hw); + mac->link_state = MAC80211_LINKED; mac->cnt_after_linked = 0; mac->assoc_id = bss_conf->aid; memcpy(mac->bssid, bss_conf->bssid, 6); + if (rtlpriv->cfg->ops->linked_set_reg) + rtlpriv->cfg->ops->linked_set_reg(hw); + if (mac->opmode == NL80211_IFTYPE_STATION && sta) + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0); RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_ASSOC\n")); } else { @@ -505,9 +610,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, mac->link_state = MAC80211_NOLINK; memset(mac->bssid, 0, 6); - - /* reset sec info */ - rtl_cam_reset_sec_info(hw); + mac->vendor = PEER_UNKNOWN; RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, ("BSS_CHANGED_UN_ASSOC\n")); @@ -544,14 +647,10 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_HT) { - struct ieee80211_sta *sta = NULL; - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("BSS_CHANGED_HT\n")); - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); - + sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); if (sta) { if (sta->ht_cap.ampdu_density > mac->current_ampdu_density) @@ -573,9 +672,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BSSID) { - struct ieee80211_sta *sta = NULL; u32 basic_rates; - u8 i; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID, (u8 *) bss_conf->bssid); @@ -583,96 +680,65 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG, (MAC_FMT "\n", MAC_ARG(bss_conf->bssid))); + mac->vendor = PEER_UNKNOWN; memcpy(mac->bssid, bss_conf->bssid, 6); - if (is_valid_ether_addr(bss_conf->bssid)) { - switch (vif->type) { - case NL80211_IFTYPE_UNSPECIFIED: - break; - case NL80211_IFTYPE_ADHOC: - break; - case NL80211_IFTYPE_STATION: - break; - case NL80211_IFTYPE_AP: - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("switch case not process\n")); - break; - } - rtlpriv->cfg->ops->set_network_type(hw, vif->type); - } else - rtlpriv->cfg->ops->set_network_type(hw, - NL80211_IFTYPE_UNSPECIFIED); - - memset(mac->mcs, 0, 16); - mac->ht_enable = false; - mac->sgi_40 = false; - mac->sgi_20 = false; - - if (!bss_conf->use_short_slot) - mac->mode = WIRELESS_MODE_B; - else - mac->mode = WIRELESS_MODE_G; + rtlpriv->cfg->ops->set_network_type(hw, vif->type); rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); + sta = get_sta(hw, vif, (u8 *)bss_conf->bssid); + if (!sta) { + rcu_read_unlock(); + goto out; + } - if (sta) { - if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_5G) { + mac->mode = WIRELESS_MODE_A; + } else { + if (sta->supp_rates[0] <= 0xf) + mac->mode = WIRELESS_MODE_B; + else + mac->mode = WIRELESS_MODE_G; + } + + if (sta->ht_cap.ht_supported) { + if (rtlhal->current_bandtype == BAND_ON_2_4G) mac->mode = WIRELESS_MODE_N_24G; - mac->ht_enable = true; - } + else + mac->mode = WIRELESS_MODE_N_5G; + } - if (mac->ht_enable) { - u16 ht_cap = sta->ht_cap.cap; - memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16); - - for (i = 0; i < 16; i++) - RT_TRACE(rtlpriv, COMP_MAC80211, - DBG_LOUD, ("%x ", - mac->mcs[i])); - RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, - ("\n")); - - if (ht_cap & IEEE80211_HT_CAP_SGI_40) - mac->sgi_40 = true; - - if (ht_cap & IEEE80211_HT_CAP_SGI_20) - mac->sgi_20 = true; - - /* - * for cisco 1252 bw20 it's wrong - * if (ht_cap & - * IEEE80211_HT_CAP_SUP_WIDTH_20_40) { - * mac->bw_40 = true; - * } - */ - } + /* just station need it, because ibss & ap mode will + * set in sta_add, and will be NULL here */ + if (mac->opmode == NL80211_IFTYPE_STATION) { + struct rtl_sta_info *sta_entry; + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + sta_entry->wireless_mode = mac->mode; + } + + if (sta->ht_cap.ht_supported) { + mac->ht_enable = true; + + /* + * for cisco 1252 bw20 it's wrong + * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) { + * mac->bw_40 = true; + * } + * */ } - rcu_read_unlock(); - /*mac80211 just give us CCK rates any time - *So we add G rate in basic rates when - not in B mode*/ if (changed & BSS_CHANGED_BASIC_RATES) { - if (mac->mode == WIRELESS_MODE_B) - basic_rates = bss_conf->basic_rates | 0x00f; + /* for 5G must << RATE_6M_INDEX=4, + * because 5G have no cck rate*/ + if (rtlhal->current_bandtype == BAND_ON_5G) + basic_rates = sta->supp_rates[1] << 4; else - basic_rates = bss_conf->basic_rates | 0xff0; - - if (!vif) - goto out; + basic_rates = sta->supp_rates[0]; mac->basic_rates = basic_rates; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE, (u8 *) (&basic_rates)); - - if (rtlpriv->dm.useramask) - rtlpriv->cfg->ops->update_rate_mask(hw, 0); - else - rtlpriv->cfg->ops->update_rate_table(hw); - } + rcu_read_unlock(); } /* @@ -758,16 +824,17 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_START: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_START: TID:%d\n", tid)); - return rtl_tx_agg_start(hw, sta->addr, tid, ssn); + return rtl_tx_agg_start(hw, sta, tid, ssn); break; case IEEE80211_AMPDU_TX_STOP: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid)); - return rtl_tx_agg_stop(hw, sta->addr, tid); + return rtl_tx_agg_stop(hw, sta, tid); break; case IEEE80211_AMPDU_TX_OPERATIONAL: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, ("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid)); + rtl_tx_agg_oper(hw, sta, tid); break; case IEEE80211_AMPDU_RX_START: RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE, @@ -797,8 +864,12 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw) if (mac->link_state == MAC80211_LINKED) { rtl_lps_leave(hw); mac->link_state = MAC80211_LINKED_SCANNING; - } else + } else { rtl_ips_nic_on(hw); + } + + /* Dual mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY); rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP); @@ -810,22 +881,19 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n")); - - rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); mac->act_scanning = false; + /* Dual mac */ + rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false; + if (mac->link_state == MAC80211_LINKED_SCANNING) { mac->link_state = MAC80211_LINKED; - - /* fix fwlps issue */ - rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); - - if (rtlpriv->dm.useramask) - rtlpriv->cfg->ops->update_rate_mask(hw, 0); - else - rtlpriv->cfg->ops->update_rate_table(hw); - + if (mac->opmode == NL80211_IFTYPE_STATION) { + /* fix fwlps issue */ + rtlpriv->cfg->ops->set_network_type(hw, mac->opmode); + } } + rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE); } static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, @@ -856,49 +924,73 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, rtl_ips_nic_on(hw); mutex_lock(&rtlpriv->locks.conf_mutex); /* <1> get encryption alg */ + switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: key_type = WEP40_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n")); - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_WEP104: RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP104\n")); key_type = WEP104_ENCRYPTION; - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_TKIP: key_type = TKIP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n")); - if (mac->opmode == NL80211_IFTYPE_ADHOC) - rtlpriv->sec.use_defaultkey = true; break; case WLAN_CIPHER_SUITE_CCMP: key_type = AESCCMP_ENCRYPTION; RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n")); - if (mac->opmode == NL80211_IFTYPE_ADHOC) - rtlpriv->sec.use_defaultkey = true; break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("alg_err:%x!!!!:\n", key->cipher)); goto out_unlock; } + if (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION || + mac->opmode == NL80211_IFTYPE_ADHOC) + rtlpriv->sec.use_defaultkey = true; + /* <2> get key_idx */ key_idx = (u8) (key->keyidx); if (key_idx > 3) goto out_unlock; /* <3> if pairwise key enable_hw_sec */ group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE); - if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || - rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { - if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION && - (key_type == WEP40_ENCRYPTION || - key_type == WEP104_ENCRYPTION)) - wep_only = true; - rtlpriv->sec.pairwise_enc_algorithm = key_type; - rtlpriv->cfg->ops->enable_hw_sec(hw); + + /* wep always be group key, but there are two conditions: + * 1) wep only: is just for wep enc, in this condition + * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION + * will be true & enable_hw_sec will be set when wep + * ke setting. + * 2) wep(group) + AES(pairwise): some AP like cisco + * may use it, in this condition enable_hw_sec will not + * be set when wep key setting */ + /* we must reset sec_info after lingked before set key, + * or some flag will be wrong*/ + if (mac->opmode == NL80211_IFTYPE_AP) { + if (!group_key || key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION) { + if (group_key) + wep_only = true; + rtlpriv->cfg->ops->enable_hw_sec(hw); + } + } else { + if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) || + rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) { + if (rtlpriv->sec.pairwise_enc_algorithm == + NO_ENCRYPTION && + (key_type == WEP40_ENCRYPTION || + key_type == WEP104_ENCRYPTION)) + wep_only = true; + rtlpriv->sec.pairwise_enc_algorithm = key_type; + RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1" + " TKIP:2 AES:4 WEP104:5)\n", key_type)); + rtlpriv->cfg->ops->enable_hw_sec(hw); + } } /* <4> set key based on cmd */ switch (cmd) { @@ -930,6 +1022,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (!sta) { RT_ASSERT(false, ("pairwise key withnot" "mac_addr\n")); + err = -EOPNOTSUPP; goto out_unlock; } @@ -957,6 +1050,10 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("disable key delete one entry\n")); /*set local buf about wep key. */ + if (mac->opmode == NL80211_IFTYPE_AP) { + if (sta) + rtl_cam_del_entry(hw, sta->addr); + } memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen); rtlpriv->sec.key_len[key_idx] = 0; memcpy(mac_addr, zero_addr, ETH_ALEN); @@ -1009,6 +1106,18 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) mutex_unlock(&rtlpriv->locks.conf_mutex); } +/* this function is called by mac80211 to flush tx buffer + * before switch channle or power save, or tx buffer packet + * maybe send after offchannel or rf sleep, this may cause + * dis-association by AP */ +static void rtl_op_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->intf_ops->flush) + rtlpriv->intf_ops->flush(hw, drop); +} + const struct ieee80211_ops rtl_ops = { .start = rtl_op_start, .stop = rtl_op_stop, @@ -1017,6 +1126,8 @@ const struct ieee80211_ops rtl_ops = { .remove_interface = rtl_op_remove_interface, .config = rtl_op_config, .configure_filter = rtl_op_configure_filter, + .sta_add = rtl_op_sta_add, + .sta_remove = rtl_op_sta_remove, .set_key = rtl_op_set_key, .conf_tx = rtl_op_conf_tx, .bss_info_changed = rtl_op_bss_info_changed, @@ -1028,4 +1139,5 @@ const struct ieee80211_ops rtl_ops = { .sw_scan_start = rtl_op_sw_scan_start, .sw_scan_complete = rtl_op_sw_scan_complete, .rfkill_poll = rtl_op_rfkill_poll, + .flush = rtl_op_flush, }; diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h index 0ef31c3c..4b247db 100644 --- a/drivers/net/wireless/rtlwifi/core.h +++ b/drivers/net/wireless/rtlwifi/core.h @@ -24,6 +24,7 @@ * Hsinchu 300, Taiwan. * * Larry Finger <Larry.Finger@lwfinger.net> + * *****************************************************************************/ #ifndef __RTL_CORE_H__ diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 5d73c0f..510d42e 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -52,8 +52,6 @@ static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = { {11, 0, 0, 28} }; -static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, - u8 *pbuf); static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset, u8 *value); static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset, @@ -79,7 +77,7 @@ static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata, u8 *targetdata); static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, u16 efuse_addr, u8 word_en, u8 *data); -static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, +static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate); static u16 efuse_get_current_size(struct ieee80211_hw *hw); static u8 efuse_calculate_word_cnts(u8 word_en); @@ -115,8 +113,10 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) u8 bytetemp; u8 temp; u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; - if (address < EFUSE_REAL_CONTENT_LEN) { + if (address < efuse_len) { temp = address & 0xFF; rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1, temp); @@ -158,11 +158,13 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) u8 bytetemp; u8 temp; u32 k = 0; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("Addr=%x Data =%x\n", address, value)); - if (address < EFUSE_REAL_CONTENT_LEN) { + if (address < efuse_len) { rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value); temp = address & 0xFF; @@ -198,7 +200,7 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) } -static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) +void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 value32; @@ -233,24 +235,28 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - u8 efuse_tbl[EFUSE_MAP_LEN]; + u8 efuse_tbl[HWSET_MAX_SIZE]; u8 rtemp8[1]; u16 efuse_addr = 0; u8 offset, wren; u16 i; u16 j; + const u16 efuse_max_section = + rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP]; + const u32 efuse_len = + rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE]; u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT]; u16 efuse_utilized = 0; u8 efuse_usage; - if ((_offset + _size_byte) > EFUSE_MAP_LEN) { + if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) { RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("read_efuse(): Invalid offset(%#x) with read " "bytes(%#x)!!\n", _offset, _size_byte)); return; } - for (i = 0; i < EFUSE_MAX_SECTION; i++) + for (i = 0; i < efuse_max_section; i++) for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) efuse_word[i][j] = 0xFFFF; @@ -262,10 +268,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) efuse_addr++; } - while ((*rtemp8 != 0xFF) && (efuse_addr < EFUSE_REAL_CONTENT_LEN)) { + while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) { offset = ((*rtemp8 >> 4) & 0x0f); - if (offset < EFUSE_MAX_SECTION) { + if (offset < efuse_max_section) { wren = (*rtemp8 & 0x0f); RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, ("offset-%d Worden=%x\n", offset, wren)); @@ -281,7 +287,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) efuse_utilized++; efuse_word[offset][i] = (*rtemp8 & 0xff); - if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) + if (efuse_addr >= efuse_len) break; RTPRINT(rtlpriv, FEEPROM, @@ -294,7 +300,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) efuse_word[offset][i] |= (((u16)*rtemp8 << 8) & 0xff00); - if (efuse_addr >= EFUSE_REAL_CONTENT_LEN) + if (efuse_addr >= efuse_len) break; } @@ -305,13 +311,13 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL, ("Addr=%d\n", efuse_addr)); read_efuse_byte(hw, efuse_addr, rtemp8); - if (*rtemp8 != 0xFF && (efuse_addr < 512)) { + if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) { efuse_utilized++; efuse_addr++; } } - for (i = 0; i < EFUSE_MAX_SECTION; i++) { + for (i = 0; i < efuse_max_section; i++) { for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) { efuse_tbl[(i * 8) + (j * 2)] = (efuse_word[i][j] & 0xff); @@ -324,7 +330,7 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf) pbuf[i] = efuse_tbl[_offset + i]; rtlefuse->efuse_usedbytes = efuse_utilized; - efuse_usage = (u8)((efuse_utilized * 100) / EFUSE_REAL_CONTENT_LEN); + efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len); rtlefuse->efuse_usedpercentage = efuse_usage; rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES, (u8 *)&efuse_utilized); @@ -478,9 +484,10 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); - if (rtlefuse->autoload_failflag == true) { - memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128); - } else + if (rtlefuse->autoload_failflag == true) + memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, + rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); + else efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], @@ -632,8 +639,9 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse) { + struct rtl_priv *rtlpriv = rtl_priv(hw); efuse_power_switch(hw, false, true); - read_efuse(hw, 0, 128, efuse); + read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse); efuse_power_switch(hw, false, false); } @@ -641,7 +649,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, u8 efuse_data, u8 offset, u8 *tmpdata, u8 *readstate) { - bool bdataempty = true; + bool dataempty = true; u8 hoffset; u8 tmpidx; u8 hworden; @@ -657,13 +665,13 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, &efuse_data)) { tmpdata[tmpidx] = efuse_data; if (efuse_data != 0xff) - bdataempty = true; + dataempty = true; } } - if (bdataempty == true) + if (dataempty == true) { *readstate = PG_STATE_DATA; - else { + } else { *efuse_addr = *efuse_addr + (word_cnts * 2) + 1; *readstate = PG_STATE_HEADER; } @@ -677,9 +685,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) { u8 readstate = PG_STATE_HEADER; - bool continual = true; - u8 efuse_data, word_cnts = 0; u16 efuse_addr = 0; u8 tmpdata[8]; @@ -795,19 +801,20 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr, tmp_word_en &= (~BIT(1)); if ((target_pkt->word_en & BIT(2)) ^ - (match_word_en & BIT(2))) + (match_word_en & BIT(2))) tmp_word_en &= (~BIT(2)); if ((target_pkt->word_en & BIT(3)) ^ - (match_word_en & BIT(3))) + (match_word_en & BIT(3))) tmp_word_en &= (~BIT(3)); if ((tmp_word_en & 0x0F) != 0x0F) { *efuse_addr = efuse_get_current_size(hw); target_pkt->offset = offset; target_pkt->word_en = tmp_word_en; - } else + } else { *continual = false; + } *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { @@ -842,9 +849,9 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, efuse_one_byte_write(hw, *efuse_addr, pg_header); efuse_one_byte_read(hw, *efuse_addr, &tmp_header); - if (tmp_header == pg_header) + if (tmp_header == pg_header) { *write_state = PG_STATE_DATA; - else if (tmp_header == 0xFF) { + } else if (tmp_header == 0xFF) { *write_state = PG_STATE_HEADER; *repeat_times += 1; if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) { @@ -871,11 +878,13 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, reorg_worden, originaldata); *efuse_addr = efuse_get_current_size(hw); - } else + } else { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; - } else + } + } else { *efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1; + } *write_state = PG_STATE_HEADER; *repeat_times += 1; @@ -1069,10 +1078,12 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 tempval; u16 tmpV16; - if (pwrstate) { + if (pwrstate && (rtlhal->hw_type != + HARDWARE_TYPE_RTL8192SE)) { tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL]); if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) { @@ -1105,13 +1116,22 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) tempval = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); - tempval &= 0x0F; - tempval |= (VOLTAGE_V25 << 4); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) { + tempval &= 0x0F; + tempval |= (VOLTAGE_V25 << 4); + } + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, (tempval | 0x80)); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x03); + } + } else { if (write) { tempval = rtl_read_byte(rtlpriv, @@ -1122,6 +1142,11 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate) (tempval & 0x7F)); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK], + 0x02); + } + } } diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h index 47774dd..164daba 100644 --- a/drivers/net/wireless/rtlwifi/efuse.h +++ b/drivers/net/wireless/rtlwifi/efuse.h @@ -30,9 +30,10 @@ #ifndef __RTL_EFUSE_H_ #define __RTL_EFUSE_H_ +#define EFUSE_IC_ID_OFFSET 506 + #define EFUSE_REAL_CONTENT_LEN 512 #define EFUSE_MAP_LEN 128 -#define EFUSE_MAX_SECTION 16 #define EFUSE_MAX_WORD_UNIT 4 #define EFUSE_INIT_MAP 0 @@ -52,6 +53,7 @@ #define _PRE_EXECUTE_READ_CMD_ #define EFUSE_REPEAT_THRESHOLD_ 3 +#define EFUSE_ERROE_HANDLE 1 struct efuse_map { u8 offset; @@ -103,6 +105,7 @@ struct efuse_priv { u8 tx_power_g[14]; }; +extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf); extern void efuse_initialize(struct ieee80211_hw *hw); extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address); extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index c3dd4cc..3550c9f 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -32,6 +32,7 @@ #include "pci.h" #include "base.h" #include "ps.h" +#include "efuse.h" static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { INTEL_VENDOR_ID, @@ -40,6 +41,31 @@ static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { SIS_VENDOR_ID }; +static const u8 ac_to_hwq[] = { + VO_QUEUE, + VI_QUEUE, + BE_QUEUE, + BK_QUEUE +}; + +static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + __le16 fc = rtl_get_fc(skb); + u8 queue_index = skb_get_queue_mapping(skb); + + if (unlikely(ieee80211_is_beacon(fc))) + return BEACON_QUEUE; + if (ieee80211_is_mgmt(fc)) + return MGNT_QUEUE; + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + if (ieee80211_is_nullfunc(fc)) + return HIGH_QUEUE; + + return ac_to_hwq[queue_index]; +} + /* Update PCI dependent default settings*/ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) { @@ -48,6 +74,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; + u8 init_aspm; ppsc->reg_rfps_level = 0; ppsc->support_aspm = 0; @@ -113,25 +140,45 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw) /*Set HW definition to determine if it supports ASPM. */ switch (rtlpci->const_support_pciaspm) { - case 0: - /*Not support ASPM. */ - ppsc->support_aspm = false; - break; - case 1: - /*Support ASPM. */ - ppsc->support_aspm = true; - ppsc->support_backdoor = true; - break; + case 0:{ + /*Not support ASPM. */ + bool support_aspm = false; + ppsc->support_aspm = support_aspm; + break; + } + case 1:{ + /*Support ASPM. */ + bool support_aspm = true; + bool support_backdoor = true; + ppsc->support_aspm = support_aspm; + + /*if (priv->oem_id == RT_CID_TOSHIBA && + !priv->ndis_adapter.amd_l1_patch) + support_backdoor = false; */ + + ppsc->support_backdoor = support_backdoor; + + break; + } case 2: /*ASPM value set by chipset. */ - if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) - ppsc->support_aspm = true; + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) { + bool support_aspm = true; + ppsc->support_aspm = support_aspm; + } break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case not process\n")); break; } + + /* toshiba aspm issue, toshiba will set aspm selfly + * so we should not set aspm in driver */ + pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm); + if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE && + init_aspm == 0x43) + ppsc->support_aspm = false; } static bool _rtl_pci_platform_switch_device_pci_aspm( @@ -139,8 +186,11 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + + if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) + value |= 0x40; - value |= 0x40; pci_write_config_byte(rtlpci->pdev, 0x80, value); return false; @@ -150,11 +200,13 @@ static bool _rtl_pci_platform_switch_device_pci_aspm( static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - u8 buffer; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - buffer = value; pci_write_config_byte(rtlpci->pdev, 0x81, value); + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) + udelay(100); + return true; } @@ -175,6 +227,9 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) u16 aspmlevel = 0; u8 tmp_u1b = 0; + if (!ppsc->support_aspm) + return; + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ("PCI(Bridge) UNKNOWN.\n")); @@ -228,6 +283,9 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) u8 u_pcibridge_aspmsetting; u8 u_device_aspmsetting; + if (!ppsc->support_aspm) + return; + if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) { RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, ("PCI(Bridge) UNKNOWN.\n")); @@ -272,7 +330,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0); RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ); } - udelay(200); + udelay(100); } static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) @@ -309,13 +367,13 @@ static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; u8 linkctrl_reg; - u8 num4bBytes; + u8 num4bbytes; - num4bBytes = (capabilityoffset + 0x10) / 4; + num4bbytes = (capabilityoffset + 0x10) / 4; /*Read Link Control Register */ rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bBytes << 2)); + pcicfg_addrport + (num4bbytes << 2)); rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; @@ -348,7 +406,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x70f, tmp); } -static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw) +static void rtl_pci_init_aspm(struct ieee80211_hw *hw) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -362,52 +420,6 @@ static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw) } -static void rtl_pci_init_aspm(struct ieee80211_hw *hw) -{ - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - - /*close ASPM for AMD defaultly */ - rtlpci->const_amdpci_aspm = 0; - - /* - * ASPM PS mode. - * 0 - Disable ASPM, - * 1 - Enable ASPM without Clock Req, - * 2 - Enable ASPM with Clock Req, - * 3 - Always Enable ASPM with Clock Req, - * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 - * */ - rtlpci->const_pci_aspm = 3; - - /*Setting for PCI-E device */ - rtlpci->const_devicepci_aspm_setting = 0x03; - - /*Setting for PCI-E bridge */ - rtlpci->const_hostpci_aspm_setting = 0x02; - - /* - * In Hw/Sw Radio Off situation. - * 0 - Default, - * 1 - From ASPM setting without low Mac Pwr, - * 2 - From ASPM setting with low Mac Pwr, - * 3 - Bus D3 - * set default to RTL8192CE:0 RTL8192SE:2 - */ - rtlpci->const_hwsw_rfoff_d3 = 0; - - /* - * This setting works for those device with - * backdoor ASPM setting such as EPHY setting. - * 0 - Not support ASPM, - * 1 - Support ASPM, - * 2 - According to chipset. - */ - rtlpci->const_support_pciaspm = 1; - - _rtl_pci_initialize_adapter_common(hw); -} - static void _rtl_pci_io_handler_init(struct device *dev, struct ieee80211_hw *hw) { @@ -429,6 +441,90 @@ static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw) { } +static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw, + struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + u8 additionlen = FCS_LEN; + struct sk_buff *next_skb; + + /* here open is 4, wep/tkip is 8, aes is 12*/ + if (info->control.hw_key) + additionlen += info->control.hw_key->icv_len; + + /* The most skb num is 6 */ + tcb_desc->empkt_num = 0; + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) { + struct ieee80211_tx_info *next_info; + + next_info = IEEE80211_SKB_CB(next_skb); + if (next_info->flags & IEEE80211_TX_CTL_AMPDU) { + tcb_desc->empkt_len[tcb_desc->empkt_num] = + next_skb->len + additionlen; + tcb_desc->empkt_num++; + } else { + break; + } + + if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid], + next_skb)) + break; + + if (tcb_desc->empkt_num >= 5) + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + return true; +} + +/* just for early mode now */ +static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct sk_buff *skb = NULL; + struct ieee80211_tx_info *info = NULL; + int tid; /* should be int */ + + if (!rtlpriv->rtlhal.earlymode_enable) + return; + + /* we juse use em for BE/BK/VI/VO */ + for (tid = 7; tid >= 0; tid--) { + u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)]; + struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; + while (!mac->act_scanning && + rtlpriv->psc.rfpwr_state == ERFON) { + struct rtl_tcb_desc tcb_desc; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + if (!skb_queue_empty(&mac->skb_waitq[tid]) && + (ring->entries - skb_queue_len(&ring->queue) > 5)) { + skb = skb_dequeue(&mac->skb_waitq[tid]); + } else { + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + break; + } + spin_unlock_bh(&rtlpriv->locks.waitq_lock); + + /* Some macaddr can't do early mode. like + * multicast/broadcast/no_qos data */ + info = IEEE80211_SKB_CB(skb); + if (info->flags & IEEE80211_TX_CTL_AMPDU) + _rtl_update_earlymode_info(hw, skb, + &tcb_desc, tid); + + rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc); + } + } +} + + static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -440,6 +536,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) struct rtl_tx_desc *entry = &ring->desc[ring->idx]; struct sk_buff *skb; struct ieee80211_tx_info *info; + __le16 fc; + u8 tid; u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true, HW_DESC_OWN); @@ -460,6 +558,10 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) HW_DESC_TXBUFF_ADDR), skb->len, PCI_DMA_TODEVICE); + /* remove early mode header */ + if (rtlpriv->rtlhal.earlymode_enable) + skb_pull(skb, EM_HDR_LEN); + RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE, ("new ring->idx:%d, " "free: skb_queue_len:%d, free: seq:%x\n", @@ -467,6 +569,30 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb_queue_len(&ring->queue), *(u16 *) (skb->data + 22))); + if (prio == TXCMD_QUEUE) { + dev_kfree_skb(skb); + goto tx_status_ok; + + } + + /* for sw LPS, just after NULL skb send out, we can + * sure AP kown we are sleeped, our we should not let + * rf to sleep*/ + fc = rtl_get_fc(skb); + if (ieee80211_is_nullfunc(fc)) { + if (ieee80211_has_pm(fc)) { + rtlpriv->mac80211.offchan_deley = true; + rtlpriv->psc.state_inap = 1; + } else { + rtlpriv->psc.state_inap = 0; + } + } + + /* update tid tx pkt num */ + tid = rtl_get_tid(skb); + if (tid <= 7) + rtlpriv->link_info.tidtx_inperiod[tid]++; + info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); @@ -489,7 +615,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) skb_get_queue_mapping (skb)); } - +tx_status_ok: skb = NULL; } @@ -561,23 +687,21 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) *skb_trim(skb, skb->len - 4); */ - hdr = (struct ieee80211_hdr *)(skb->data); - fc = hdr->frame_control; + hdr = rtl_get_hdr(skb); + fc = rtl_get_fc(skb); - if (!stats.crc) { + if (!stats.crc || !stats.hwerror) { memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); - if (is_broadcast_ether_addr(hdr->addr1)) + if (is_broadcast_ether_addr(hdr->addr1)) { ;/*TODO*/ - else { - if (is_multicast_ether_addr(hdr->addr1)) - ;/*TODO*/ - else { - unicast = true; - rtlpriv->stats.rxbytesunicast += - skb->len; - } + } else if (is_multicast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else { + unicast = true; + rtlpriv->stats.rxbytesunicast += + skb->len; } rtl_is_special_data(hw, skb, false); @@ -591,28 +715,38 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) num_rx_inperiod++; } - if (unlikely(!rtl_action_proc(hw, skb, - false))) { + /* for sw lps */ + rtl_swlps_beacon(hw, (void *)skb->data, + skb->len); + rtl_recognize_peer(hw, (void *)skb->data, + skb->len); + if ((rtlpriv->mac80211.opmode == + NL80211_IFTYPE_AP) && + (rtlpriv->rtlhal.current_bandtype == + BAND_ON_2_4G) && + (ieee80211_is_beacon(fc) || + ieee80211_is_probe_resp(fc))) { dev_kfree_skb_any(skb); } else { - struct sk_buff *uskb = NULL; - u8 *pdata; - uskb = dev_alloc_skb(skb->len + 128); - if (!uskb) { - RT_TRACE(rtlpriv, - (COMP_INTR | COMP_RECV), - DBG_EMERG, - ("can't alloc rx skb\n")); - goto done; + if (unlikely(!rtl_action_proc(hw, skb, + false))) { + dev_kfree_skb_any(skb); + } else { + struct sk_buff *uskb = NULL; + u8 *pdata; + uskb = dev_alloc_skb(skb->len + + 128); + memcpy(IEEE80211_SKB_RXCB(uskb), + &rx_status, + sizeof(rx_status)); + pdata = (u8 *)skb_put(uskb, + skb->len); + memcpy(pdata, skb->data, + skb->len); + dev_kfree_skb_any(skb); + + ieee80211_rx_irqsafe(hw, uskb); } - memcpy(IEEE80211_SKB_RXCB(uskb), - &rx_status, - sizeof(rx_status)); - pdata = (u8 *)skb_put(uskb, skb->len); - memcpy(pdata, skb->data, skb->len); - dev_kfree_skb_any(skb); - - ieee80211_rx_irqsafe(hw, uskb); } } else { dev_kfree_skb_any(skb); @@ -627,7 +761,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) new_skb = dev_alloc_skb(rtlpci->rxbuffersize); if (unlikely(!new_skb)) { RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), - DBG_EMERG, + DBG_DMESG, ("can't alloc skb for rx\n")); goto done; } @@ -645,7 +779,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) } done: - bufferaddress = (u32)(*((dma_addr_t *) skb->cb)); + bufferaddress = (*((dma_addr_t *)skb->cb)); tmp_one = 1; rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, HW_DESC_RXBUFF_ADDR, @@ -674,6 +808,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) struct ieee80211_hw *hw = dev_id; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); unsigned long flags; u32 inta = 0; u32 intb = 0; @@ -760,23 +895,36 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) _rtl_pci_tx_isr(hw, VO_QUEUE); } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) { + if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) { + rtlpriv->link_info.num_tx_inperiod++; + + RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, + ("CMD TX OK interrupt!\n")); + _rtl_pci_tx_isr(hw, TXCMD_QUEUE); + } + } + /*<2> Rx related */ if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) { RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx descriptor unavailable!\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n")); - tasklet_schedule(&rtlpriv->works.irq_tasklet); + _rtl_pci_rx_interrupt(hw); } + if (rtlpriv->rtlhal.earlymode_enable) + tasklet_schedule(&rtlpriv->works.irq_tasklet); + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); return IRQ_HANDLED; @@ -787,7 +935,7 @@ done: static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) { - _rtl_pci_rx_interrupt(hw); + _rtl_pci_tx_chk_waitq(hw); } static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) @@ -795,14 +943,15 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE]; + struct rtl8192_tx_ring *ring = NULL; struct ieee80211_hdr *hdr = NULL; struct ieee80211_tx_info *info = NULL; struct sk_buff *pskb = NULL; struct rtl_tx_desc *pdesc = NULL; - unsigned int queue_index; + struct rtl_tcb_desc tcb_desc; u8 temp_one = 1; + memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc)); ring = &rtlpci->tx_ring[BEACON_QUEUE]; pskb = __skb_dequeue(&ring->queue); if (pskb) @@ -812,14 +961,11 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) pskb = ieee80211_beacon_get(hw, mac->vif); if (pskb == NULL) return; - hdr = (struct ieee80211_hdr *)(pskb->data); + hdr = rtl_get_hdr(pskb); info = IEEE80211_SKB_CB(pskb); - - queue_index = BEACON_QUEUE; - pdesc = &ring->desc[0]; rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, pskb, queue_index); + info, pskb, BEACON_QUEUE, &tcb_desc); __skb_queue_tail(&ring->queue, pskb); @@ -861,7 +1007,6 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); rtlpci->up_first_time = true; rtlpci->being_init_adapter = false; @@ -869,31 +1014,20 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, rtlhal->hw = hw; rtlpci->pdev = pdev; - ppsc->inactiveps = false; - ppsc->leisure_ps = true; - ppsc->fwctrl_lps = true; - ppsc->reg_fwctrl_lps = 3; - ppsc->reg_max_lps_awakeintvl = 5; - - if (ppsc->reg_fwctrl_lps == 1) - ppsc->fwctrl_psmode = FW_PS_MIN_MODE; - else if (ppsc->reg_fwctrl_lps == 2) - ppsc->fwctrl_psmode = FW_PS_MAX_MODE; - else if (ppsc->reg_fwctrl_lps == 3) - ppsc->fwctrl_psmode = FW_PS_DTIM_MODE; - /*Tx/Rx related var */ _rtl_pci_init_trx_var(hw); - /*IBSS*/ mac->beacon_interval = 100; + /*IBSS*/ mac->beacon_interval = 100; - /*AMPDU*/ mac->min_space_cfg = 0; + /*AMPDU*/ + mac->min_space_cfg = 0; mac->max_mss_density = 0; /*set sane AMPDU defaults */ mac->current_ampdu_density = 7; mac->current_ampdu_factor = 3; - /*QOS*/ rtlpci->acm_method = eAcmWay2_SW; + /*QOS*/ + rtlpci->acm_method = eAcmWay2_SW; /*task */ tasklet_init(&rtlpriv->works.irq_tasklet, @@ -934,7 +1068,8 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, ("queue:%d, ring_addr:%p\n", prio, ring)); for (i = 0; i < entries; i++) { - nextdescaddress = (u32) dma + ((i + 1) % entries) * + nextdescaddress = (u32) dma + + ((i + 1) % entries) * sizeof(*ring); rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]), @@ -999,7 +1134,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); - bufferaddress = (u32)(*((dma_addr_t *)skb->cb)); + bufferaddress = (*((dma_addr_t *)skb->cb)); rtlpriv->cfg->ops->set_desc((u8 *)entry, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); @@ -1182,72 +1317,73 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) return 0; } -static unsigned int _rtl_mac_to_hwqueue(__le16 fc, - unsigned int mac80211_queue_index) +static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw, + struct sk_buff *skb) { - unsigned int hw_queue_index; - - if (unlikely(ieee80211_is_beacon(fc))) { - hw_queue_index = BEACON_QUEUE; - goto out; - } - - if (ieee80211_is_mgmt(fc)) { - hw_queue_index = MGNT_QUEUE; - goto out; - } - - switch (mac80211_queue_index) { - case 0: - hw_queue_index = VO_QUEUE; - break; - case 1: - hw_queue_index = VI_QUEUE; - break; - case 2: - hw_queue_index = BE_QUEUE;; - break; - case 3: - hw_queue_index = BK_QUEUE; - break; - default: - hw_queue_index = BE_QUEUE; - RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n", - mac80211_queue_index)); - break; - } + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; + struct rtl_sta_info *sta_entry = NULL; + u8 tid = rtl_get_tid(skb); + + if (!sta) + return false; + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + + if (!rtlpriv->rtlhal.earlymode_enable) + return false; + if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL) + return false; + if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE) + return false; + if (tid > 7) + return false; + + /* maybe every tid should be checked */ + if (!rtlpriv->link_info.higher_busytxtraffic[tid]) + return false; + + spin_lock_bh(&rtlpriv->locks.waitq_lock); + skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb); + spin_unlock_bh(&rtlpriv->locks.waitq_lock); -out: - return hw_queue_index; + return true; } -static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta = info->control.sta; struct rtl8192_tx_ring *ring; struct rtl_tx_desc *pdesc; u8 idx; - unsigned int queue_index, hw_queue; + u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb); unsigned long flags; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); - __le16 fc = hdr->frame_control; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); u8 *pda_addr = hdr->addr1; struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); /*ssn */ - u8 *qc = NULL; u8 tid = 0; u16 seq_number = 0; u8 own; u8 temp_one = 1; - if (ieee80211_is_mgmt(fc)) - rtl_tx_mgmt_proc(hw, skb); - rtl_action_proc(hw, skb, true); + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); + rtl_ips_nic_on(hw); + } + + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } - queue_index = skb_get_queue_mapping(skb); - hw_queue = _rtl_mac_to_hwqueue(fc, queue_index); + rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; @@ -1257,7 +1393,6 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) rtlpriv->stats.txbytesunicast += skb->len; spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - ring = &rtlpci->tx_ring[hw_queue]; if (hw_queue != BEACON_QUEUE) idx = (ring->idx + skb_queue_len(&ring->queue)) % @@ -1280,43 +1415,30 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return skb->len; } - /* - *if(ieee80211_is_nullfunc(fc)) { - * spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - * return 1; - *} - */ - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - - seq_number = mac->tids[tid].seq_number; - seq_number &= IEEE80211_SCTL_SEQ; - /* - *hdr->seq_ctrl = hdr->seq_ctrl & - *cpu_to_le16(IEEE80211_SCTL_FRAG); - *hdr->seq_ctrl |= cpu_to_le16(seq_number); - */ - - seq_number += 1; + tid = rtl_get_tid(skb); + if (sta) { + sta_entry = (struct rtl_sta_info *)sta->drv_priv; + seq_number = (le16_to_cpu(hdr->seq_ctrl) & + IEEE80211_SCTL_SEQ) >> 4; + seq_number += 1; + + if (!ieee80211_has_morefrags(hdr->frame_control)) + sta_entry->tids[tid].seq_number = seq_number; + } } if (ieee80211_is_data(fc)) rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); - rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc, - info, skb, hw_queue); + rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, + info, skb, hw_queue, ptcb_desc); __skb_queue_tail(&ring->queue, skb); - rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true, HW_DESC_OWN, (u8 *)&temp_one); - if (!ieee80211_has_morefrags(hdr->frame_control)) { - if (qc) - mac->tids[tid].seq_number = seq_number; - } if ((ring->entries - skb_queue_len(&ring->queue)) < 2 && hw_queue != BEACON_QUEUE) { @@ -1338,6 +1460,35 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return 0; } +static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u16 i = 0; + int queue_id; + struct rtl8192_tx_ring *ring; + + for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) { + u32 queue_len; + ring = &pcipriv->dev.tx_ring[queue_id]; + queue_len = skb_queue_len(&ring->queue); + if (queue_len == 0 || queue_id == BEACON_QUEUE || + queue_id == TXCMD_QUEUE) { + queue_id--; + continue; + } else { + msleep(20); + i++; + } + + /* we just wait 1s for all queues */ + if (rtlpriv->psc.rfpwr_state == ERFOFF || + is_hal_stop(rtlhal) || i >= 200) + return; + } +} + static void rtl_pci_deinit(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1456,11 +1607,13 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, struct pci_dev *bridge_pdev = pdev->bus->self; u16 venderid; u16 deviceid; + u8 revisionid; u16 irqline; u8 tmp; venderid = pdev->vendor; deviceid = pdev->device; + pci_read_config_byte(pdev, 0x8, &revisionid); pci_read_config_word(pdev, 0x3C, &irqline); if (deviceid == RTL_PCI_8192_DID || @@ -1471,7 +1624,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, deviceid == RTL_PCI_8173_DID || deviceid == RTL_PCI_8172_DID || deviceid == RTL_PCI_8171_DID) { - switch (pdev->revision) { + switch (revisionid) { case RTL_PCI_REVISION_ID_8192PCIE: RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("8192 PCI-E is found - " @@ -1500,6 +1653,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("8192C PCI-E is found - " "vid/did=%x/%x\n", venderid, deviceid)); + } else if (deviceid == RTL_PCI_8192DE_DID || + deviceid == RTL_PCI_8192DE_DID2) { + rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE; + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, + ("8192D PCI-E is found - " + "vid/did=%x/%x\n", venderid, deviceid)); } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("Err: Unknown device -" @@ -1508,6 +1667,25 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE; } + if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) { + if (revisionid == 0 || revisionid == 1) { + if (revisionid == 0) { + RT_TRACE(rtlpriv, COMP_INIT, + DBG_LOUD, ("Find 92DE MAC0.\n")); + rtlhal->interfaceindex = 0; + } else if (revisionid == 1) { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Find 92DE MAC1.\n")); + rtlhal->interfaceindex = 1; + } + } else { + RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + ("Unknown device - " + "VendorID/DeviceID=%x/%x, Revision=%x\n", + venderid, deviceid, revisionid)); + rtlhal->interfaceindex = 0; + } + } /*find bus info */ pcipriv->ndis_adapter.busnumber = pdev->bus->number; pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn); @@ -1533,12 +1711,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, PCI_SLOT(bridge_pdev->devfn); pcipriv->ndis_adapter.pcibridge_funcnum = PCI_FUNC(bridge_pdev->devfn); - pcipriv->ndis_adapter.pcibridge_pciehdr_offset = - pci_pcie_cap(bridge_pdev); pcipriv->ndis_adapter.pcicfg_addrport = (pcipriv->ndis_adapter.pcibridge_busnum << 16) | (pcipriv->ndis_adapter.pcibridge_devnum << 11) | (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); + pcipriv->ndis_adapter.pcibridge_pciehdr_offset = + pci_pcie_cap(bridge_pdev); pcipriv->ndis_adapter.num4bytes = (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4; @@ -1621,6 +1799,11 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pcipriv = (void *)rtlpriv->priv; pcipriv->dev.pdev = pdev; + /* init cfg & intf_ops */ + rtlpriv->rtlhal.interface = INTF_PCI; + rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); + rtlpriv->intf_ops = &rtl_pci_ops; + /* *init dbgp flags before all *other functions, because we will @@ -1638,13 +1821,14 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, return err; } - pmem_start = pci_resource_start(pdev, 2); - pmem_len = pci_resource_len(pdev, 2); - pmem_flags = pci_resource_flags(pdev, 2); + pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id); + pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id); + pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id); /*shared mem start */ rtlpriv->io.pci_mem_start = - (unsigned long)pci_iomap(pdev, 2, pmem_len); + (unsigned long)pci_iomap(pdev, + rtlpriv->cfg->bar_id, pmem_len); if (rtlpriv->io.pci_mem_start == 0) { RT_ASSERT(false, ("Can't map PCI mem\n")); goto fail2; @@ -1663,11 +1847,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x04, 0x06); pci_write_config_byte(pdev, 0x04, 0x07); - /* init cfg & intf_ops */ - rtlpriv->rtlhal.interface = INTF_PCI; - rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data); - rtlpriv->intf_ops = &rtl_pci_ops; - /* find adapter */ _rtl_pci_find_adapter(pdev, hw); @@ -1785,8 +1964,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev) rtl_pci_deinit(hw); rtl_deinit_core(hw); - if (rtlpriv->cfg->ops->deinit_sw_leds) - rtlpriv->cfg->ops->deinit_sw_leds(hw); _rtl_pci_io_handler_release(hw); rtlpriv->cfg->ops->deinit_sw_vars(hw); @@ -1801,6 +1978,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev) } pci_disable_device(pdev); + + rtl_pci_disable_aspm(hw); + pci_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); @@ -1824,10 +2004,15 @@ no need to call hw_disable here. ****************************************/ int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state) { + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtlpriv->cfg->ops->hw_suspend(hw); + rtl_deinit_rfkill(hw); + pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); - return 0; } EXPORT_SYMBOL(rtl_pci_suspend); @@ -1835,6 +2020,8 @@ EXPORT_SYMBOL(rtl_pci_suspend); int rtl_pci_resume(struct pci_dev *pdev) { int ret; + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtl_priv *rtlpriv = rtl_priv(hw); pci_set_power_state(pdev, PCI_D0); ret = pci_enable_device(pdev); @@ -1845,15 +2032,20 @@ int rtl_pci_resume(struct pci_dev *pdev) pci_restore_state(pdev); + rtlpriv->cfg->ops->hw_resume(hw); + rtl_init_rfkill(hw); return 0; } EXPORT_SYMBOL(rtl_pci_resume); struct rtl_intf_ops rtl_pci_ops = { + .read_efuse_byte = read_efuse_byte, .adapter_start = rtl_pci_start, .adapter_stop = rtl_pci_stop, .adapter_tx = rtl_pci_tx, + .flush = rtl_pci_flush, .reset_trx_ring = rtl_pci_reset_trx_ring, + .waitq_insert = rtl_pci_tx_chk_waitq_insert, .disable_aspm = rtl_pci_disable_aspm, .enable_aspm = rtl_pci_enable_aspm, diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index 12747b9..671b1f5 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -102,8 +102,8 @@ #define RTL_PCI_8191CE_DID 0x8177 /*8192ce */ #define RTL_PCI_8188CE_DID 0x8176 /*8192ce */ #define RTL_PCI_8192CU_DID 0x8191 /*8192ce */ -#define RTL_PCI_8192DE_DID 0x092D /*8192ce */ -#define RTL_PCI_8192DU_DID 0x092D /*8192ce */ +#define RTL_PCI_8192DE_DID 0x8193 /*8192de */ +#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/ /*8192 support 16 pages of IO registers*/ #define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000 @@ -129,6 +129,11 @@ enum pci_bridge_vendor { PCI_BRIDGE_VENDOR_MAX, }; +struct rtl_pci_capabilities_header { + u8 capability_id; + u8 next; +}; + struct rtl_rx_desc { u32 dword[8]; } __packed; @@ -161,7 +166,9 @@ struct rtl_pci { bool driver_is_goingto_unload; bool up_first_time; + bool first_init; bool being_init_adapter; + bool init_ready; bool irq_enabled; /*Tx */ @@ -197,6 +204,9 @@ struct rtl_pci { /*QOS & EDCA */ enum acm_method acm_method; + + u16 shortretry_limit; + u16 longretry_limit; }; struct mp_adapter { @@ -227,6 +237,7 @@ struct rtl_pci_priv { struct rtl_pci dev; struct mp_adapter ndis_adapter; struct rtl_led_ctl ledctl; + struct bt_coexist_info bt_coexist; }; #define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv)) diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index c8395fb..2bb7119 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -36,7 +36,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - bool init_status = true; /*<1> reset trx ring */ if (rtlhal->interface == INTF_PCI) @@ -49,7 +48,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) /*<2> Enable Adapter */ rtlpriv->cfg->ops->hw_init(hw); RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); - /*init_status = false; */ /*<3> Enable Interrupt */ rtlpriv->cfg->ops->enable_interrupt(hw); @@ -57,7 +55,7 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw) /*<enable timer> */ rtl_watch_dog_timer_callback((unsigned long)hw); - return init_status; + return true; } EXPORT_SYMBOL(rtl_ps_enable_nic); @@ -192,12 +190,13 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) ppsc->swrf_processing = true; - if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) { + if (ppsc->inactive_pwrstate == ERFOFF && + rtlhal->interface == INTF_PCI) { if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && rtlhal->interface == INTF_PCI) { rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } } @@ -206,9 +205,10 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw) if (ppsc->inactive_pwrstate == ERFOFF && rtlhal->interface == INTF_PCI) { - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } } @@ -232,6 +232,9 @@ void rtl_ips_nic_off_wq_callback(void *data) return; } + if (mac->link_state > MAC80211_NOLINK) + return; + if (is_hal_stop(rtlhal)) return; @@ -283,10 +286,14 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw) void rtl_ips_nic_on(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); enum rf_pwrstate rtstate; unsigned long flags; + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags); if (ppsc->inactiveps) { @@ -369,8 +376,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode) * mode and set RPWM to turn RF on. */ - if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) && - ppsc->report_linked) { + if ((ppsc->fwctrl_lps) && ppsc->report_linked) { bool fw_current_inps; if (ppsc->dot11_psmode == EACTIVE) { RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, @@ -424,7 +430,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); unsigned long flag; - if (!(ppsc->fwctrl_lps && ppsc->leisure_ps)) + if (!ppsc->fwctrl_lps) return; if (rtlpriv->sec.being_setkey) @@ -445,17 +451,16 @@ void rtl_lps_enter(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->leisure_ps) { - /* Idle for a while if we connect to AP a while ago. */ - if (mac->cnt_after_linked >= 2) { - if (ppsc->dot11_psmode == EACTIVE) { - RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + /* Idle for a while if we connect to AP a while ago. */ + if (mac->cnt_after_linked >= 2) { + if (ppsc->dot11_psmode == EACTIVE) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("Enter 802.11 power save mode...\n")); - rtl_lps_set_psmode(hw, EAUTOPS); - } + rtl_lps_set_psmode(hw, EAUTOPS); } } + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } @@ -469,17 +474,17 @@ void rtl_lps_leave(struct ieee80211_hw *hw) spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); - if (ppsc->fwctrl_lps && ppsc->leisure_ps) { + if (ppsc->fwctrl_lps) { if (ppsc->dot11_psmode != EACTIVE) { /*FIX ME */ rtlpriv->cfg->ops->enable_interrupt(hw); if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && - RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) && rtlhal->interface == INTF_PCI) { rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, @@ -490,3 +495,214 @@ void rtl_lps_leave(struct ieee80211_hw *hw) } spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); } + +/* For sw LPS*/ +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct ieee80211_hdr *hdr = (void *) data; + struct ieee80211_tim_ie *tim_ie; + u8 *tim; + u8 tim_len; + bool u_buffed; + bool m_buffed; + + if (mac->opmode != NL80211_IFTYPE_STATION) + return; + + if (!rtlpriv->psc.swctrl_lps) + return; + + if (rtlpriv->mac80211.link_state != MAC80211_LINKED) + return; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if (rtlpriv->psc.fwctrl_lps) + return; + + if (likely(!(hw->conf.flags & IEEE80211_CONF_PS))) + return; + + /* check if this really is a beacon */ + if (!ieee80211_is_beacon(hdr->frame_control)) + return; + + /* min. beacon length + FCS_LEN */ + if (len <= 40 + FCS_LEN) + return; + + /* and only beacons from the associated BSSID, please */ + if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid)) + return; + + rtlpriv->psc.last_beacon = jiffies; + + tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM); + if (!tim) + return; + + if (tim[1] < sizeof(*tim_ie)) + return; + + tim_len = tim[1]; + tim_ie = (struct ieee80211_tim_ie *) &tim[2]; + + if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period)) + rtlpriv->psc.dtim_counter = tim_ie->dtim_count; + + /* Check whenever the PHY can be turned off again. */ + + /* 1. What about buffered unicast traffic for our AID? */ + u_buffed = ieee80211_check_tim(tim_ie, tim_len, + rtlpriv->mac80211.assoc_id); + + /* 2. Maybe the AP wants to send multicast/broadcast data? */ + m_buffed = tim_ie->bitmap_ctrl & 0x01; + rtlpriv->psc.multi_buffered = m_buffed; + + /* unicast will process by mac80211 through + * set ~IEEE80211_CONF_PS, So we just check + * multicast frames here */ + if (!m_buffed) { + /* back to low-power land. and delay is + * prevent null power save frame tx fail */ + queue_delayed_work(rtlpriv->works.rtl_wq, + &rtlpriv->works.ps_work, MSECS(5)); + } else { + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, " + "m_buffered: %x\n", u_buffed, m_buffed)); + } +} + +void rtl_swlps_rf_awake(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + unsigned long flag; + + if (!rtlpriv->psc.swctrl_lps) + return; + if (mac->link_state != MAC80211_LINKED) + return; + + if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM && + RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->disable_aspm(hw); + RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); +} + +void rtl_swlps_rfon_wq_callback(void *data) +{ + struct rtl_works *rtlworks = + container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq); + struct ieee80211_hw *hw = rtlworks->hw; + + rtl_swlps_rf_awake(hw); +} + +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + unsigned long flag; + u8 sleep_intv; + + if (!rtlpriv->psc.sw_ps_enabled) + return; + + if ((rtlpriv->sec.being_setkey) || + (mac->opmode == NL80211_IFTYPE_ADHOC)) + return; + + /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */ + if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5)) + return; + + if (rtlpriv->link_info.busytraffic) + return; + + spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); + if (rtlpriv->psc.rfchange_inprogress) { + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + return; + } + spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); + + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag); + rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag); + + if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && + !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { + rtlpriv->intf_ops->enable_aspm(hw); + RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); + } + + /* here is power save alg, when this beacon is DTIM + * we will set sleep time to dtim_period * n; + * when this beacon is not DTIM, we will set sleep + * time to sleep_intv = rtlpriv->psc.dtim_counter or + * MAX_SW_LPS_SLEEP_INTV(default set to 5) */ + + if (rtlpriv->psc.dtim_counter == 0) { + if (hw->conf.ps_dtim_period == 1) + sleep_intv = hw->conf.ps_dtim_period * 2; + else + sleep_intv = hw->conf.ps_dtim_period; + } else { + sleep_intv = rtlpriv->psc.dtim_counter; + } + + if (sleep_intv > MAX_SW_LPS_SLEEP_INTV) + sleep_intv = MAX_SW_LPS_SLEEP_INTV; + + /* this print should always be dtim_conter = 0 & + * sleep = dtim_period, that meaons, we should + * awake before every dtim */ + RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, + ("dtim_counter:%x will sleep :%d" + " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv)); + + /* we tested that 40ms is enough for sw & hw sw delay */ + queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq, + MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40)); +} + + +void rtl_swlps_wq_callback(void *data) +{ + struct rtl_works *rtlworks = container_of_dwork_rtl(data, + struct rtl_works, + ps_work); + struct ieee80211_hw *hw = rtlworks->hw; + struct rtl_priv *rtlpriv = rtl_priv(hw); + bool ps = false; + + ps = (hw->conf.flags & IEEE80211_CONF_PS); + + /* we can sleep after ps null send ok */ + if (rtlpriv->psc.state_inap) { + rtl_swlps_rf_sleep(hw); + + if (rtlpriv->psc.state && !ps) { + rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies - + rtlpriv->psc.last_action); + } + + if (ps) + rtlpriv->psc.last_slept = jiffies; + + rtlpriv->psc.last_action = jiffies; + rtlpriv->psc.state = ps; + } +} diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h index ae56da8..e3bf898 100644 --- a/drivers/net/wireless/rtlwifi/ps.h +++ b/drivers/net/wireless/rtlwifi/ps.h @@ -30,6 +30,8 @@ #ifndef __REALTEK_RTL_PCI_PS_H__ #define __REALTEK_RTL_PCI_PS_H__ +#define MAX_SW_LPS_SLEEP_INTV 5 + bool rtl_ps_set_rf_state(struct ieee80211_hw *hw, enum rf_pwrstate state_toset, u32 changesource, bool protect_or_not); @@ -40,4 +42,11 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw); void rtl_ips_nic_off_wq_callback(void *data); void rtl_lps_enter(struct ieee80211_hw *hw); void rtl_lps_leave(struct ieee80211_hw *hw); + +void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len); +void rtl_swlps_wq_callback(void *data); +void rtl_swlps_rfon_wq_callback(void *data); +void rtl_swlps_rf_awake(struct ieee80211_hw *hw); +void rtl_swlps_rf_sleep(struct ieee80211_hw *hw); + #endif diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c index 9163410..30da68a 100644 --- a/drivers/net/wireless/rtlwifi/rc.c +++ b/drivers/net/wireless/rtlwifi/rc.c @@ -38,17 +38,14 @@ *CCK11M or OFDM_54M based on wireless mode. */ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, struct sk_buff *skb, bool not_data) { struct rtl_mac *rtlmac = rtl_mac(rtlpriv); - - /* - *mgt use 1M, although we have check it - *before this function use rate_control_send_low, - *we still check it here - */ - if (not_data) - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + struct rtl_hal *rtlhal = rtl_hal(rtlpriv); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_sta_info *sta_entry = NULL; + u8 wireless_mode = 0; /* *this rate is no use for true rate, firmware @@ -57,35 +54,78 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv, *2.in rtl_get_tcb_desc when we check rate is * 1M we will not use FW rate but user rate. */ - if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) { - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M]; + if (rtlmac->opmode == NL80211_IFTYPE_AP || + rtlmac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) { + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wireless_mode = sta_entry->wireless_mode; + } else { + return 0; + } + } else { + wireless_mode = rtlmac->mode; + } + + if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) || + not_data) { + return 0; } else { - if (rtlmac->mode == WIRELESS_MODE_B) - return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]; - else - return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M]; + if (rtlhal->current_bandtype == BAND_ON_2_4G) { + if (wireless_mode == WIRELESS_MODE_B) { + return B_MODE_MAX_RIX; + } else if (wireless_mode == WIRELESS_MODE_G) { + return G_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } else { + if (wireless_mode == WIRELESS_MODE_A) { + return A_MODE_MAX_RIX; + } else { + if (get_rf_type(rtlphy) != RF_2T2R) + return N_MODE_MCS7_RIX; + else + return N_MODE_MCS15_RIX; + } + } } } static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv, + struct ieee80211_sta *sta, struct ieee80211_tx_rate *rate, struct ieee80211_tx_rate_control *txrc, - u8 tries, u8 rix, int rtsctsenable, + u8 tries, char rix, int rtsctsenable, bool not_data) { struct rtl_mac *mac = rtl_mac(rtlpriv); + u8 sgi_20 = 0, sgi_40 = 0; + if (sta) { + sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20; + sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; + } rate->count = tries; - rate->idx = (rix > 0x2) ? rix : 0x2; + rate->idx = rix >= 0x00 ? rix : 0x00; if (!not_data) { if (txrc->short_preamble) rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE; - if (mac->bw_40) - rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (mac->sgi_20 || mac->sgi_40) + if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta && (sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } else { + if (mac->bw_40) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + } + if (sgi_20 || sgi_40) rate->flags |= IEEE80211_TX_RC_SHORT_GI; - if (mac->ht_enable) + if (sta && sta->ht_cap.ht_supported) rate->flags |= IEEE80211_TX_RC_MCS; } } @@ -97,39 +137,39 @@ static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta, struct sk_buff *skb = txrc->skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *rates = tx_info->control.rates; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc = hdr->frame_control; + __le16 fc = rtl_get_fc(skb); u8 try_per_rate, i, rix; bool not_data = !ieee80211_is_data(fc); if (rate_control_send_low(sta, priv_sta, txrc)) return; - rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data); - + rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data); try_per_rate = 1; - _rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc, + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc, try_per_rate, rix, 1, not_data); if (!not_data) { for (i = 1; i < 4; i++) - _rtl_rc_rate_set_series(rtlpriv, &rates[i], + _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i], txrc, i, (rix - i), 1, not_data); } } -static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid) +static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, + struct rtl_sta_info *sta_entry, u16 tid) { struct rtl_mac *mac = rtl_mac(rtlpriv); if (mac->act_scanning) return false; - if (mac->cnt_after_linked < 3) + if (mac->opmode == NL80211_IFTYPE_STATION && + mac->cnt_after_linked < 3) return false; - if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF) + if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP) return true; return false; @@ -143,11 +183,9 @@ static void rtl_tx_status(void *ppriv, { struct rtl_priv *rtlpriv = ppriv; struct rtl_mac *mac = rtl_mac(rtlpriv); - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); + struct rtl_sta_info *sta_entry; if (!priv_sta || !ieee80211_is_data(fc)) return; @@ -159,17 +197,21 @@ static void rtl_tx_status(void *ppriv, || is_broadcast_ether_addr(ieee80211_get_DA(hdr))) return; - /* Check if aggregation has to be enabled for this tid */ - if (conf_is_ht(&mac->hw->conf) && - !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { - if (ieee80211_is_data_qos(fc)) { - u8 *qc, tid; - - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - - if (_rtl_tx_aggr_check(rtlpriv, tid)) - ieee80211_start_tx_ba_session(sta, tid, 5000); + if (sta) { + /* Check if aggregation has to be enabled for this tid */ + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + if ((sta->ht_cap.ht_supported == true) && + !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { + if (ieee80211_is_data_qos(fc)) { + u8 tid = rtl_get_tid(skb); + if (_rtl_tx_aggr_check(rtlpriv, sta_entry, + tid)) { + sta_entry->tids[tid].agg.agg_state = + RTL_AGG_PROGRESS; + ieee80211_start_tx_ba_session(sta, + tid, 5000); + } + } } } } @@ -178,43 +220,6 @@ static void rtl_rate_init(void *ppriv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { - struct rtl_priv *rtlpriv = ppriv; - struct rtl_mac *mac = rtl_mac(rtlpriv); - u8 is_ht = conf_is_ht(&mac->hw->conf); - - if ((mac->opmode == NL80211_IFTYPE_STATION) || - (mac->opmode == NL80211_IFTYPE_MESH_POINT) || - (mac->opmode == NL80211_IFTYPE_ADHOC)) { - - switch (sband->band) { - case IEEE80211_BAND_2GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_G; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - case IEEE80211_BAND_5GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_A; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("Invalid band\n")); - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - } - - RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG, - ("Choosing rate table index: %d\n", - rtlpriv->rate_priv->cur_ratetab_idx)); - - } - } static void rtl_rate_update(void *ppriv, @@ -223,49 +228,6 @@ static void rtl_rate_update(void *ppriv, u32 changed, enum nl80211_channel_type oper_chan_type) { - struct rtl_priv *rtlpriv = ppriv; - struct rtl_mac *mac = rtl_mac(rtlpriv); - struct rtl_hal *rtlhal = rtl_hal(rtlpriv); - bool oper_cw40 = false, oper_sgi40; - bool local_cw40 = mac->bw_40; - bool local_sgi40 = mac->sgi_40; - u8 is_ht = conf_is_ht(&mac->hw->conf); - - if (changed & IEEE80211_RC_HT_CHANGED) { - if (mac->opmode != NL80211_IFTYPE_STATION) - return; - - if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || - rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) - oper_cw40 = true; - - oper_sgi40 = mac->sgi_40; - - if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { - switch (sband->band) { - case IEEE80211_BAND_2GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_G; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - case IEEE80211_BAND_5GHZ: - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_A; - if (is_ht) - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("Invalid band\n")); - rtlpriv->rate_priv->cur_ratetab_idx = - RATR_INX_WIRELESS_NGB; - break; - } - } - } } static void *rtl_rate_alloc(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h index b4667c0..4afa2c2 100644 --- a/drivers/net/wireless/rtlwifi/rc.h +++ b/drivers/net/wireless/rtlwifi/rc.h @@ -30,8 +30,15 @@ #ifndef __RTL_RC_H__ #define __RTL_RC_H__ +#define B_MODE_MAX_RIX 3 +#define G_MODE_MAX_RIX 11 +#define A_MODE_MAX_RIX 7 + +/* in mac80211 mcs0-mcs15 is idx0-idx15*/ +#define N_MODE_MCS7_RIX 7 +#define N_MODE_MCS15_RIX 15 + struct rtl_rate_priv { - u8 cur_ratetab_idx; u8 ht_cap; }; diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index d26f957..8f6718f 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -66,31 +66,83 @@ static struct country_code_to_enum_rd allCountries[] = { NL80211_RRF_PASSIVE_SCAN | \ NL80211_RRF_NO_OFDM) +/* 5G chan 36 - chan 64*/ +#define RTL819x_5GHZ_5150_5350 \ + REG_RULE(5150-10, 5350+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 100 - chan 165*/ +#define RTL819x_5GHZ_5470_5850 \ + REG_RULE(5470-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +/* 5G chan 149 - chan 165*/ +#define RTL819x_5GHZ_5725_5850 \ + REG_RULE(5725-10, 5850+10, 40, 0, 30, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +#define RTL819x_5GHZ_ALL \ + (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850) + static const struct ieee80211_regdomain rtl_regdom_11 = { .n_reg_rules = 1, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - } + } +}; + +static const struct ieee80211_regdomain rtl_regdom_12_13 = { + .n_reg_rules = 2, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + } }; -static const struct ieee80211_regdomain rtl_regdom_global = { +static const struct ieee80211_regdomain rtl_regdom_no_midband = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - RTL819x_2GHZ_CH12_13, - RTL819x_2GHZ_CH14, - } + RTL819x_5GHZ_5150_5350, + RTL819x_5GHZ_5725_5850, + } }; -static const struct ieee80211_regdomain rtl_regdom_world = { - .n_reg_rules = 2, +static const struct ieee80211_regdomain rtl_regdom_60_64 = { + .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { RTL819x_2GHZ_CH01_11, - RTL819x_2GHZ_CH12_13, - } + RTL819x_2GHZ_CH12_13, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14_60_64 = { + .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + RTL819x_5GHZ_5725_5850, + } +}; + +static const struct ieee80211_regdomain rtl_regdom_14 = { + .n_reg_rules = 3, + .alpha2 = "99", + .reg_rules = { + RTL819x_2GHZ_CH01_11, + RTL819x_2GHZ_CH12_13, + RTL819x_2GHZ_CH14, + } }; static bool _rtl_is_radar_freq(u16 center_freq) @@ -162,6 +214,8 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, u32 bandwidth = 0; int r; + if (!wiphy->bands[IEEE80211_BAND_2GHZ]) + return; sband = wiphy->bands[IEEE80211_BAND_2GHZ]; /* @@ -292,25 +346,26 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select( { switch (reg->country_code) { case COUNTRY_CODE_FCC: + return &rtl_regdom_no_midband; case COUNTRY_CODE_IC: return &rtl_regdom_11; case COUNTRY_CODE_ETSI: + case COUNTRY_CODE_TELEC_NETGEAR: + return &rtl_regdom_60_64; case COUNTRY_CODE_SPAIN: case COUNTRY_CODE_FRANCE: case COUNTRY_CODE_ISRAEL: - case COUNTRY_CODE_TELEC_NETGEAR: - return &rtl_regdom_world; + case COUNTRY_CODE_WORLD_WIDE_13: + return &rtl_regdom_12_13; case COUNTRY_CODE_MKK: case COUNTRY_CODE_MKK1: case COUNTRY_CODE_TELEC: case COUNTRY_CODE_MIC: - return &rtl_regdom_global; + return &rtl_regdom_14_60_64; case COUNTRY_CODE_GLOBAL_DOMAIN: - return &rtl_regdom_global; - case COUNTRY_CODE_WORLD_WIDE_13: - return &rtl_regdom_world; + return &rtl_regdom_14; default: - return &rtl_regdom_world; + return &rtl_regdom_no_midband; } } @@ -323,9 +378,11 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg, const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY; wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS; + regd = _rtl_regdomain_select(reg); wiphy_apply_custom_regulatory(wiphy, regd); _rtl_reg_apply_radar_flags(wiphy); @@ -355,8 +412,8 @@ int rtl_regd_init(struct ieee80211_hw *hw, if (wiphy == NULL || &rtlpriv->regd == NULL) return -EINVAL; - /* force the channel plan to world wide 13 */ - rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; + /* init country_code from efuse channel plan */ + rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan; RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE, (KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n", @@ -373,8 +430,8 @@ int rtl_regd_init(struct ieee80211_hw *hw, country = _rtl_regd_find_country(rtlpriv->regd.country_code); if (country) { - rtlpriv->regd.alpha2[0] = country->isoName[0]; - rtlpriv->regd.alpha2[1] = country->isoName[1]; + rtlpriv->regd.alpha2[0] = country->iso_name[0]; + rtlpriv->regd.alpha2[1] = country->iso_name[1]; } else { rtlpriv->regd.alpha2[0] = '0'; rtlpriv->regd.alpha2[1] = '0'; diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h index 4cdbc4a..d231189 100644 --- a/drivers/net/wireless/rtlwifi/regd.h +++ b/drivers/net/wireless/rtlwifi/regd.h @@ -32,7 +32,7 @@ struct country_code_to_enum_rd { u16 countrycode; - const char *isoName; + const char *iso_name; }; enum country_code_type_t { diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c index c228b9e..9718382 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c @@ -28,10 +28,26 @@ *****************************************************************************/ #include "dm_common.h" +#include "phy_common.h" +#include "../pci.h" +#include "../base.h" struct dig_t dm_digtable; static struct ps_t dm_pstable; +#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1) +#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1) +#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1) +#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1) +#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1) + +#define RTLPRIV (struct rtl_priv *) +#define GET_UNDECORATED_AVERAGE_RSSI(_priv) \ + ((RTLPRIV(_priv))->mac80211.opmode == \ + NL80211_IFTYPE_ADHOC) ? \ + ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \ + ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb) + static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = { 0x7f8001fe, 0x788001e2, @@ -304,7 +320,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw) static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) { - static u8 binitialized; /* initialized to false */ + static u8 initialized; /* initialized to false */ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; @@ -315,11 +331,11 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw) if ((multi_sta == false) || (dm_digtable.cursta_connectctate != DIG_STA_DISCONNECT)) { - binitialized = false; + initialized = false; dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX; return; - } else if (binitialized == false) { - binitialized = true; + } else if (initialized == false) { + initialized = true; dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0; dm_digtable.cur_igvalue = 0x20; rtl92c_dm_write_dig(hw); @@ -461,10 +477,7 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw) if (mac->act_scanning == true) return; - if ((mac->link_state > MAC80211_NOLINK) && - (mac->link_state < MAC80211_LINKED)) - dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT; - else if (mac->link_state >= MAC80211_LINKED) + if (mac->link_state >= MAC80211_LINKED) dm_digtable.cursta_connectctate = DIG_STA_CONNECT; else dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT; @@ -562,23 +575,42 @@ EXPORT_SYMBOL(rtl92c_dm_init_edca_turbo); static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + static u64 last_txok_cnt; static u64 last_rxok_cnt; - u64 cur_txok_cnt; - u64 cur_rxok_cnt; + static u32 last_bt_edca_ul; + static u32 last_bt_edca_dl; + u64 cur_txok_cnt = 0; + u64 cur_rxok_cnt = 0; u32 edca_be_ul = 0x5ea42b; u32 edca_be_dl = 0x5ea42b; + bool bt_change_edca = false; - if (mac->opmode == NL80211_IFTYPE_ADHOC) - goto dm_checkedcaturbo_exit; + if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) || + (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) { + rtlpriv->dm.current_turbo_edca = false; + last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl; + } + + if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul; + bt_change_edca = true; + } + + if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) { + edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl; + bt_change_edca = true; + } if (mac->link_state != MAC80211_LINKED) { rtlpriv->dm.current_turbo_edca = false; return; } - if (!mac->ht_enable) { /*FIX MERGE */ + if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) { if (!(edca_be_ul & 0xffff0000)) edca_be_ul |= 0x005e0000; @@ -586,10 +618,12 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) edca_be_dl |= 0x005e0000; } - if ((!rtlpriv->dm.is_any_nonbepkts) && - (!rtlpriv->dm.disable_framebursting)) { + if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) && + (!rtlpriv->dm.disable_framebursting))) { + cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt; cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt; + if (cur_rxok_cnt > 4 * cur_txok_cnt) { if (!rtlpriv->dm.is_cur_rdlstate || !rtlpriv->dm.current_turbo_edca) { @@ -618,7 +652,6 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw) } } -dm_checkedcaturbo_exit: rtlpriv->dm.is_any_nonbepkts = false; last_txok_cnt = rtlpriv->stats.txbytesunicast; last_rxok_cnt = rtlpriv->stats.rxbytesunicast; @@ -633,14 +666,14 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 thermalvalue, delta, delta_lck, delta_iqk; long ele_a, ele_d, temp_cck, val_x, value32; - long val_y, ele_c; + long val_y, ele_c = 0; u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0; int i; bool is2t = IS_92C_SERIAL(rtlhal->version); u8 txpwr_level[2] = {0, 0}; u8 ofdm_min_index = 6, rf; - rtlpriv->dm.txpower_trackingInit = true; + rtlpriv->dm.txpower_trackinginit = true; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("rtl92c_dm_txpower_tracking_callback_thermalmeter\n")); @@ -683,7 +716,6 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw for (i = 0; i < OFDM_TABLE_LENGTH; i++) { if (ele_d == (ofdmswing_table[i] & MASKOFDM_D)) { - ofdm_index_old[1] = (u8) i; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1062,7 +1094,7 @@ static void rtl92c_dm_initialize_txpower_tracking_thermalmeter( struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->dm.txpower_tracking = true; - rtlpriv->dm.txpower_trackingInit = false; + rtlpriv->dm.txpower_trackinginit = false; RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, ("pMgntInfo->txpower_tracking = %d\n", @@ -1132,6 +1164,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rate_adaptive *p_ra = &(rtlpriv->ra); u32 low_rssithresh_for_ra, high_rssithresh_for_ra; + struct ieee80211_sta *sta = NULL; if (is_hal_stop(rtlhal)) { RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, @@ -1145,8 +1178,8 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) return; } - if (mac->link_state == MAC80211_LINKED) { - + if (mac->link_state == MAC80211_LINKED && + mac->opmode == NL80211_IFTYPE_STATION) { switch (p_ra->pre_ratr_state) { case DM_RATR_STA_HIGH: high_rssithresh_for_ra = 50; @@ -1185,10 +1218,13 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw) ("PreState = %d, CurState = %d\n", p_ra->pre_ratr_state, p_ra->ratr_state)); - rtlpriv->cfg->ops->update_rate_mask(hw, + rcu_read_lock(); + sta = ieee80211_find_sta(mac->vif, mac->bssid); + rtlpriv->cfg->ops->update_rate_tbl(hw, sta, p_ra->ratr_state); p_ra->pre_ratr_state = p_ra->ratr_state; + rcu_read_unlock(); } } } @@ -1202,51 +1238,6 @@ static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw) dm_pstable.rssi_val_min = 0; } -static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - - if (dm_pstable.rssi_val_min != 0) { - if (dm_pstable.pre_ccastate == CCA_2R) { - if (dm_pstable.rssi_val_min >= 35) - dm_pstable.cur_ccasate = CCA_1R; - else - dm_pstable.cur_ccasate = CCA_2R; - } else { - if (dm_pstable.rssi_val_min <= 30) - dm_pstable.cur_ccasate = CCA_2R; - else - dm_pstable.cur_ccasate = CCA_1R; - } - } else { - dm_pstable.cur_ccasate = CCA_MAX; - } - - if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) { - if (dm_pstable.cur_ccasate == CCA_1R) { - if (get_rf_type(rtlphy) == RF_2T2R) { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, - MASKBYTE0, 0x13); - rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20); - } else { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, - MASKBYTE0, 0x23); - rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c); - } - } else { - rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, - 0x33); - rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63); - } - dm_pstable.pre_ccastate = dm_pstable.cur_ccasate; - } - - RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n", - (dm_pstable.cur_ccasate == - 0) ? "1RCCA" : "2RCCA")); -} - void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal) { static u8 initialize; @@ -1352,7 +1343,9 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw) } if (IS_92C_SERIAL(rtlhal->version)) - rtl92c_dm_1r_cca(hw); + ;/* rtl92c_dm_1r_cca(hw); */ + else + rtl92c_dm_rf_saving(hw, false); } void rtl92c_dm_init(struct ieee80211_hw *hw) @@ -1369,6 +1362,84 @@ void rtl92c_dm_init(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_dm_init); +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); + long undecorated_smoothed_pwdb; + + if (!rtlpriv->dm.dynamic_txpower_enable) + return; + + if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if ((mac->link_state < MAC80211_LINKED) && + (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Not connected to any\n")); + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + + rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL; + return; + } + + if (mac->link_state >= MAC80211_LINKED) { + if (mac->opmode == NL80211_IFTYPE_ADHOC) { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Client PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.undecorated_smoothed_pwdb; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("STA Default Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + } else { + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("AP Ext Port PWDB = 0x%lx\n", + undecorated_smoothed_pwdb)); + } + + if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n")); + } else if ((undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) && + (undecorated_smoothed_pwdb >= + TX_POWER_NEAR_FIELD_THRESH_LVL1)) { + + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n")); + } else if (undecorated_smoothed_pwdb < + (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) { + rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL; + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("TXHIGHPWRLEVEL_NORMAL\n")); + } + + if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) { + RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, + ("PHY_SetTxPowerLevel8192S() Channel = %d\n", + rtlphy->current_channel)); + rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel); + } + + rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl; +} + void rtl92c_dm_watchdog(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1388,11 +1459,321 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw) rtl92c_dm_dig(hw); rtl92c_dm_false_alarm_counter_statistics(hw); rtl92c_dm_dynamic_bb_powersaving(hw); - rtlpriv->cfg->ops->dm_dynamic_txpower(hw); + rtl92c_dm_dynamic_txpower(hw); rtl92c_dm_check_txpower_tracking(hw); rtl92c_dm_refresh_rate_adaptive_mask(hw); + rtl92c_dm_bt_coexist(hw); rtl92c_dm_check_edca_turbo(hw); - } } EXPORT_SYMBOL(rtl92c_dm_watchdog); + +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + long undecorated_smoothed_pwdb; + u8 curr_bt_rssi_state = 0x00; + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + undecorated_smoothed_pwdb = + GET_UNDECORATED_AVERAGE_RSSI(rtlpriv); + } else { + if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0) + undecorated_smoothed_pwdb = 100; + else + undecorated_smoothed_pwdb = + rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; + } + + /* Check RSSI to determine HighPower/NormalPower state for + * BT coexistence. */ + if (undecorated_smoothed_pwdb >= 67) + curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER); + else if (undecorated_smoothed_pwdb < 62) + curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER; + + /* Check RSSI to determine AMPDU setting for BT coexistence. */ + if (undecorated_smoothed_pwdb >= 40) + curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF); + else if (undecorated_smoothed_pwdb <= 32) + curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF; + + /* Marked RSSI state. It will be used to determine BT coexistence + * setting later. */ + if (undecorated_smoothed_pwdb < 35) + curr_bt_rssi_state |= BT_RSSI_STATE_SPECIAL_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW); + + /* Set Tx Power according to BT status. */ + if (undecorated_smoothed_pwdb >= 30) + curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW; + else if (undecorated_smoothed_pwdb < 25) + curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW); + + /* Check BT state related to BT_Idle in B/G mode. */ + if (undecorated_smoothed_pwdb < 15) + curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW; + else + curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW); + + if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) { + rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state; + return true; + } else { + return false; + } +} +EXPORT_SYMBOL(rtl92c_bt_rssi_state_change); + +static bool rtl92c_bt_state_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u32 polling, ratio_tx, ratio_pri; + u32 bt_tx, bt_pri; + u8 bt_state; + u8 cur_service_type; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) + return false; + + bt_state = rtl_read_byte(rtlpriv, 0x4fd); + bt_tx = rtl_read_dword(rtlpriv, 0x488); + bt_tx = bt_tx & 0x00ffffff; + bt_pri = rtl_read_dword(rtlpriv, 0x48c); + bt_pri = bt_pri & 0x00ffffff; + polling = rtl_read_dword(rtlpriv, 0x490); + + if (bt_tx == 0xffffffff && bt_pri == 0xffffffff && + polling == 0xffffffff && bt_state == 0xff) + return false; + + bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1); + if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) { + rtlpcipriv->bt_coexist.bt_cur_state = bt_state; + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + BIT_OFFSET_LEN_MASK_32(2, 1); + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + } + return true; + } + + ratio_tx = bt_tx * 1000 / polling; + ratio_pri = bt_pri * 1000 / polling; + rtlpcipriv->bt_coexist.ratio_tx = ratio_tx; + rtlpcipriv->bt_coexist.ratio_pri = ratio_pri; + + if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) { + + if ((ratio_tx < 30) && (ratio_pri < 30)) + cur_service_type = BT_IDLE; + else if ((ratio_pri > 110) && (ratio_pri < 250)) + cur_service_type = BT_SCO; + else if ((ratio_tx >= 200) && (ratio_pri >= 200)) + cur_service_type = BT_BUSY; + else if ((ratio_tx >= 350) && (ratio_tx < 500)) + cur_service_type = BT_OTHERBUSY; + else if (ratio_tx >= 500) + cur_service_type = BT_PAN; + else + cur_service_type = BT_OTHER_ACTION; + + if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) { + rtlpcipriv->bt_coexist.bt_service = cur_service_type; + bt_state = bt_state | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + + /* Add interrupt migration when bt is not ini + * idle state (no traffic). */ + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtl_write_word(rtlpriv, 0x504, 0x0ccc); + rtl_write_byte(rtlpriv, 0x506, 0x54); + rtl_write_byte(rtlpriv, 0x507, 0x54); + } else { + rtl_write_byte(rtlpriv, 0x506, 0x00); + rtl_write_byte(rtlpriv, 0x507, 0x00); + } + + rtl_write_byte(rtlpriv, 0x4fd, bt_state); + return true; + } + } + + return false; + +} + +static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + static bool media_connect; + + if (rtlpriv->mac80211.link_state < MAC80211_LINKED) { + media_connect = false; + } else { + if (!media_connect) { + media_connect = true; + return true; + } + media_connect = true; + } + + return false; +} + +static void rtl92c_bt_set_normal(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f; + } else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) { + if (rtlpcipriv->bt_coexist.ratio_tx > 160) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f; + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b; + } + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) && + (rtlpriv->mac80211.mode == WIRELESS_MODE_G || + (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_BG_EDCA_LOW)) { + rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b; + rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b; + } +} + +static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + + /* Only enable HW BT coexist when BT in "Busy" state. */ + if (rtlpriv->mac80211.vendor == PEER_CISCO && + rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else { + if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if ((rtlpcipriv->bt_coexist.bt_service == + BT_OTHER_ACTION) && (rtlpriv->mac80211.mode < + WIRELESS_MODE_N_24G) && + (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_SPECIAL_LOW)) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + } else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + } + } + + if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100); + else + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0); + + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_NORMAL_POWER) { + rtl92c_bt_set_normal(hw); + } else { + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } + + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, + 0x1e, + 0xf0, 0xf); + } else { + rtlpriv->cfg->ops->set_rfreg(hw, + RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + } + + if (!rtlpriv->dm.dynamic_txpower_enable) { + if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) { + if (rtlpcipriv->bt_coexist.bt_rssi_state & + BT_RSSI_STATE_TXPOWER_LOW) { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT2; + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_BT1; + } + } else { + rtlpriv->dm.dynamic_txhighpower_lvl = + TXHIGHPWRLEVEL_NORMAL; + } + rtl92c_phy_set_txpower_level(hw, + rtlpriv->phy.current_channel); + } +} + +static void rtl92c_check_bt_change(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + if (rtlpcipriv->bt_coexist.bt_cur_state) { + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl92c_bt_ant_isolation(hw); + } else { + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00); + rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0, + rtlpcipriv->bt_coexist.bt_rfreg_origin_1e); + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + } +} + +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + bool wifi_connect_change; + bool bt_state_change; + bool rssi_state_change; + + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + + wifi_connect_change = rtl92c_bt_wifi_connect_change(hw); + bt_state_change = rtl92c_bt_state_change(hw); + rssi_state_change = rtl92c_bt_rssi_state_change(hw); + + if (wifi_connect_change || bt_state_change || rssi_state_change) + rtl92c_check_bt_change(hw); + } +} +EXPORT_SYMBOL(rtl92c_dm_bt_coexist); diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h index b9cbb0a..b9736d3 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h @@ -200,5 +200,7 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery); +void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index bc9d241..50303e1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -223,29 +223,15 @@ int rtl92c_download_fw(struct ieee80211_hw *hw) u8 *pfwdata; u32 fwsize; enum version_8192c version = rtlhal->version; - const struct firmware *firmware; printk(KERN_INFO "rtl8192c: Loading firmware file %s\n", rtlpriv->cfg->fw_name); - if (request_firmware(&firmware, rtlpriv->cfg->fw_name, - rtlpriv->io.dev)) { - printk(KERN_ERR "rtl8192c: Firmware loading failed\n"); + if (!rtlhal->pfirmware) return 1; - } - - if (firmware->size > 0x4000) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("Firmware is too big!\n")); - release_firmware(firmware); - return 1; - } - - memcpy(rtlhal->pfirmware, firmware->data, firmware->size); - fwsize = firmware->size; - release_firmware(firmware); pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware; pfwdata = (u8 *) rtlhal->pfirmware; + fwsize = rtlhal->fwsize; if (IS_FW_HEADER_EXIST(pfwheader)) { RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG, @@ -553,6 +539,39 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode) } EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd); +static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, + struct sk_buff *skb) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + struct rtl8192_tx_ring *ring; + struct rtl_tx_desc *pdesc; + u8 own; + unsigned long flags; + struct sk_buff *pskb = NULL; + + ring = &rtlpci->tx_ring[BEACON_QUEUE]; + + pskb = __skb_dequeue(&ring->queue); + if (pskb) + kfree_skb(pskb); + + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); + + pdesc = &ring->desc[0]; + own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); + + rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); + + __skb_queue_tail(&ring->queue, skb); + + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); + + rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); + + return true; +} + #define BEACON_PG 0 /*->1*/ #define PSPOLL_PG 2 #define NULL_PG 3 @@ -670,7 +689,7 @@ static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) +void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -679,12 +698,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) u32 totalpacketlen; bool rtstatus; u8 u1RsvdPageLoc[3] = {0}; - bool b_dlok = false; + bool dlok = false; u8 *beacon; - u8 *p_pspoll; + u8 *pspoll; u8 *nullfunc; - u8 *p_probersp; + u8 *probersp; /*--------------------------------------------------------- (1) beacon ---------------------------------------------------------*/ @@ -695,10 +714,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) /*------------------------------------------------------- (2) ps-poll --------------------------------------------------------*/ - p_pspoll = &reserved_page_packet[PSPOLL_PG * 128]; - SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000)); - SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid); - SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr); + pspoll = &reserved_page_packet[PSPOLL_PG * 128]; + SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000)); + SET_80211_PS_POLL_BSSID(pspoll, mac->bssid); + SET_80211_PS_POLL_TA(pspoll, mac->mac_addr); SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG); @@ -715,10 +734,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) /*--------------------------------------------------------- (4) probe response ----------------------------------------------------------*/ - p_probersp = &reserved_page_packet[PROBERSP_PG * 128]; - SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid); - SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr); - SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid); + probersp = &reserved_page_packet[PROBERSP_PG * 128]; + SET_80211_HDR_ADDRESS1(probersp, mac->bssid); + SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr); + SET_80211_HDR_ADDRESS3(probersp, mac->bssid); SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG); @@ -736,12 +755,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) memcpy((u8 *) skb_put(skb, totalpacketlen), &reserved_page_packet, totalpacketlen); - rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb); + rtstatus = _rtl92c_cmd_send_packet(hw, skb); if (rtstatus) - b_dlok = true; + dlok = true; - if (b_dlok) { + if (dlok) { RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("Set RSVD page location to Fw.\n")); RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG, diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h index 3db33bd..3d5823c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h @@ -27,8 +27,8 @@ * *****************************************************************************/ -#ifndef __RTL92C__FW__H__ -#define __RTL92C__FW__H__ +#ifndef __RTL92C__FW__COMMON__H__ +#define __RTL92C__FW__COMMON__H__ #define FW_8192C_SIZE 0x3000 #define FW_8192C_START_ADDRESS 0x1000 diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c index a702282..c5424ca 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c @@ -78,27 +78,29 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)," " data(%#x)\n", regaddr, bitmask, data)); + } EXPORT_SYMBOL(rtl92c_phy_set_bb_reg); u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset) + enum radio_path rfpath, u32 offset) { RT_ASSERT(false, ("deprecated!\n")); return 0; + } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read); void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, - u32 data) + enum radio_path rfpath, u32 offset, + u32 data) { RT_ASSERT(false, ("deprecated!\n")); } EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write); u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset) + enum radio_path rfpath, u32 offset) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -149,8 +151,8 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read); void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 offset, - u32 data) + enum radio_path rfpath, u32 offset, + u32 data) { u32 data_and_addr; u32 newoffset; @@ -197,6 +199,7 @@ static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw) rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2); rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2); } + bool rtl92c_phy_rf_config(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -241,13 +244,14 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw) rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, 0x200)); + return true; } EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile); void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, - u32 data) + u32 regaddr, u32 bitmask, + u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -317,61 +321,48 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, } if (regaddr == RTXAGC_B_RATE54_24) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9])); } - if (regaddr == RTXAGC_B_CCK1_55_MCS32) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14])); } - if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15])); } - if (regaddr == RTXAGC_B_MCS03_MCS00) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10])); } - if (regaddr == RTXAGC_B_MCS07_MCS04) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11])); } - if (regaddr == RTXAGC_B_MCS11_MCS08) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n", rtlphy->pwrgroup_cnt, rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12])); } - if (regaddr == RTXAGC_B_MCS15_MCS12) { rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data; - RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n", rtlphy->pwrgroup_cnt, @@ -583,6 +574,7 @@ static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw, rtlphy->cur_cck_txpwridx = cckpowerlevel[0]; rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0]; + } void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel) @@ -611,7 +603,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); u8 idx; u8 rf_path; - u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_B, power_indbm); @@ -639,11 +630,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm) } EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm); -void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval) -{ -} -EXPORT_SYMBOL(rtl92c_phy_set_beacon_hw_reg); - u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, long power_indbm) @@ -741,9 +727,9 @@ void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, if (rtlphy->set_bwmode_inprogress) return; rtlphy->set_bwmode_inprogress = true; - if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) - rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw); - else { + if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) { + rtlphy->set_bwmode_inprogress = false; + } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("FALSE driver sleep or unload\n")); rtlphy->set_bwmode_inprogress = false; @@ -773,8 +759,9 @@ void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw) mdelay(delay); else continue; - } else + } else { rtlphy->sw_chnl_inprogress = false; + } break; } while (true); RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); @@ -811,9 +798,32 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw) } EXPORT_SYMBOL(rtl92c_phy_sw_chnl); -static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, - u8 channel, u8 *stage, u8 *step, - u32 *delay) +static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, + u32 cmdtableidx, u32 cmdtablesz, + enum swchnlcmd_id cmdid, + u32 para1, u32 para2, u32 msdelay) +{ + struct swchnlcmd *pcmd; + + if (cmdtable == NULL) { + RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); + return false; + } + + if (cmdtableidx >= cmdtablesz) + return false; + + pcmd = cmdtable + cmdtableidx; + pcmd->cmdid = cmdid; + pcmd->para1 = para1; + pcmd->para2 = para2; + pcmd->msdelay = msdelay; + return true; +} + +bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -917,29 +927,6 @@ static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, return false; } -static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, - u32 para1, u32 para2, u32 msdelay) -{ - struct swchnlcmd *pcmd; - - if (cmdtable == NULL) { - RT_ASSERT(false, ("cmdtable cannot be NULL.\n")); - return false; - } - - if (cmdtableidx >= cmdtablesz) - return false; - - pcmd = cmdtable + cmdtableidx; - pcmd->cmdid = cmdid; - pcmd->para1 = para1; - pcmd->para2 = para2; - pcmd->msdelay = msdelay; - return true; -} - bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath) { return true; @@ -1002,13 +989,13 @@ static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw) reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD); reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD); reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD); + if (!(reg_eac & BIT(31)) && (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) && (((reg_ebc & 0x03FF0000) >> 16) != 0x42)) result |= 0x01; else return result; - if (!(reg_eac & BIT(30)) && (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) && (((reg_ecc & 0x03FF0000) >> 16) != 0x36)) @@ -1023,9 +1010,9 @@ static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, u32 oldval_0, x, tx0_a, reg; long y, tx0_c; - if (final_candidate == 0xFF) + if (final_candidate == 0xFF) { return; - else if (iqk_ok) { + } else if (iqk_ok) { oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE, MASKDWORD) >> 22) & 0x3FF; x = result[final_candidate][0]; @@ -1063,9 +1050,9 @@ static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw, u32 oldval_1, x, tx1_a, reg; long y, tx1_c; - if (final_candidate == 0xFF) + if (final_candidate == 0xFF) { return; - else if (iqk_ok) { + } else if (iqk_ok) { oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE, MASKDWORD) >> 22) & 0x3FF; x = result[final_candidate][4]; @@ -1282,6 +1269,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, RFPGA0_XA_HSSIPARAMETER1, BIT(8)); } + if (!rtlphy->rfpi_enable) _rtl92c_phy_pi_mode_switch(hw, true); if (t == 0) { @@ -1317,9 +1305,10 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, 0x3FF0000) >> 16; break; } else if (i == (retrycount - 1) && patha_ok == 0x01) + result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) & 0x3FF0000) >> - 16; + 16; result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16; @@ -1375,8 +1364,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta, bool is2t) { - /* This routine is deliberately dummied out for later fixes */ -#if 0 +#if 0 /* This routine is deliberately dummied out for later fixes */ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); @@ -1434,7 +1422,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x04db25a4, 0x0b1b25a4 }; - u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; + const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c }; u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 }; @@ -1463,13 +1451,15 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x00050006 }; - const u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; + u32 apk_result[PATH_NUM][APK_BB_REG_NUM]; long bb_offset, delta_v, delta_offset; if (!is2t) pathbound = 1; + return; + for (index = 0; index < PATH_NUM; index++) { apk_offset[index] = apk_normal_offset[index]; apk_value[index] = apk_normal_value[index]; @@ -1730,8 +1720,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, 0x08)); } - - rtlphy->apk_done = true; + rtlphy->b_apk_done = true; #endif } @@ -1758,6 +1747,7 @@ static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1); } + } #undef IQK_ADDA_REG_NUM diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h index 53ffb09..9a264c0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h +++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h @@ -27,8 +27,8 @@ * *****************************************************************************/ -#ifndef __RTL92C_PHY_H__ -#define __RTL92C_PHY_H__ +#ifndef __RTL92C_PHY_COMMON_H__ +#define __RTL92C_PHY_COMMON_H__ #define MAX_PRECMD_CNT 16 #define MAX_RFDEPENDCMD_CNT 16 @@ -39,6 +39,7 @@ #define RT_CANNOT_IO(hw) false #define HIGHPOWER_RADIOA_ARRAYLEN 22 +#define IQK_ADDA_REG_NUM 16 #define MAX_TOLERANCE 5 #define IQK_DELAY_TIME 1 @@ -56,6 +57,7 @@ #define IQK_ADDA_REG_NUM 16 #define IQK_MAC_REG_NUM 4 +#define IQK_DELAY_TIME 1 #define RF90_PATH_MAX 2 #define CT_OFFSET_MAC_ADDR 0X16 @@ -77,6 +79,7 @@ #define RTL92C_MAX_PATH_NUM 2 #define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + enum swchnlcmd_id { CMDID_END, CMDID_SET_TXPOWEROWER_LEVEL, @@ -184,45 +187,41 @@ struct tx_power_struct { u32 mcs_original_offset[4][16]; }; -extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, - u32 bitmask, u32 data); -extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel); -extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); -extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm); -extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); -extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); -extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, enum nl80211_channel_type ch_type); -extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); -extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); -extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); -extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state); void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw); void rtl92c_phy_set_io(struct ieee80211_hw *hw); @@ -235,12 +234,25 @@ u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw, enum wireless_mode wirelessmode, long power_indbm); void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); -static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable, - u32 cmdtableidx, u32 cmdtablesz, - enum swchnlcmd_id cmdid, u32 para1, - u32 para2, u32 msdelay); -static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, - u8 channel, u8 *stage, u8 *step, - u32 *delay); +void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, + u8 channel, u8 *stage, u8 *step, + u32 *delay); +u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw); +u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset); +void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 offset, + u32 data); +bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); +void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, + u32 regaddr, u32 bitmask, + u32 data); +bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 2f577c8..35ff7df 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h @@ -121,19 +121,6 @@ #define CHIP_92C 0x01 #define CHIP_88C 0x00 -/* Add vendor information into chip version definition. - * Add UMC B-Cut and RTL8723 chip info definition. - * - * BIT 7 Reserved - * BIT 6 UMC BCut - * BIT 5 Manufacturer(TSMC/UMC) - * BIT 4 TEST/NORMAL - * BIT 3 8723 Version - * BIT 2 8723? - * BIT 1 1T2R? - * BIT 0 88C/92C -*/ - enum version_8192c { VERSION_A_CHIP_92C = 0x01, VERSION_A_CHIP_88C = 0x00, @@ -280,20 +267,6 @@ struct h2c_cmd_8192c { u8 *p_cmdbuffer; }; -static inline u8 _rtl92c_get_chnl_group(u8 chnl) -{ - u8 group = 0; - - if (chnl < 3) - group = 0; - else if (chnl < 9) - group = 1; - else - group = 2; - - return group; -} - /* NOTE: reference to rtl8192c_rates struct */ static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT, u8 desc_rate, bool first_ampdu) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c index 7d76504..2df33e5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c @@ -29,10 +29,12 @@ #include "../wifi.h" #include "../base.h" +#include "../pci.h" #include "reg.h" #include "def.h" #include "phy.h" #include "dm.h" +#include "../rtl8192c/fw_common.h" void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h index 36302eb..07dd955 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h @@ -192,6 +192,7 @@ void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw); void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw); void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw); void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal); +void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw); void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index 05477f4..4a56138 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -30,12 +30,14 @@ #include "../wifi.h" #include "../efuse.h" #include "../base.h" +#include "../regd.h" #include "../cam.h" #include "../ps.h" #include "../pci.h" #include "reg.h" #include "def.h" #include "phy.h" +#include "../rtl8192c/fw_common.h" #include "dm.h" #include "led.h" #include "hw.h" @@ -137,15 +139,6 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } - case HW_VAR_MGT_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0); - break; - case HW_VAR_CTRL_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1); - break; - case HW_VAR_DATA_FILTER: - *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2); - break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case not process\n")); @@ -156,6 +149,7 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -178,7 +172,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) rate_cfg |= 0x01; rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff); rtl_write_byte(rtlpriv, REG_RRSR + 1, - (rate_cfg >> 8)&0xff); + (rate_cfg >> 8) & 0xff); while (rate_cfg > 0x1) { rate_cfg = (rate_cfg >> 1); rate_index++; @@ -276,13 +270,19 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } case HW_VAR_AMPDU_FACTOR:{ - u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 }; + u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9}; + u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97}; u8 factor_toset; u8 *p_regtoset = NULL; u8 index = 0; - p_regtoset = regtoset_normal; + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == + BT_CSR_BC4)) + p_regtoset = regtoset_bt; + else + p_regtoset = regtoset_normal; factor_toset = *((u8 *) val); if (factor_toset <= 3) { @@ -317,45 +317,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } case HW_VAR_AC_PARAM:{ u8 e_aci = *((u8 *) val); - u32 u4b_ac_param; - u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min); - u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max); - u16 tx_op = le16_to_cpu(mac->ac[e_aci].tx_op); - - u4b_ac_param = (u32) mac->ac[e_aci].aifs; - u4b_ac_param |= ((u32)cw_min - & 0xF) << AC_PARAM_ECW_MIN_OFFSET; - u4b_ac_param |= ((u32)cw_max & - 0xF) << AC_PARAM_ECW_MAX_OFFSET; - u4b_ac_param |= (u32)tx_op << AC_PARAM_TXOP_OFFSET; - - RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD, - ("queue:%x, ac_param:%x\n", e_aci, - u4b_ac_param)); - - switch (e_aci) { - case AC1_BK: - rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, - u4b_ac_param); - break; - case AC0_BE: - rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, - u4b_ac_param); - break; - case AC2_VI: - rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, - u4b_ac_param); - break; - case AC3_VO: - rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, - u4b_ac_param); - break; - default: - RT_ASSERT(false, - ("SetHwReg8185(): invalid aci: %d !\n", - e_aci)); - break; - } + rtl92c_dm_init_edca_turbo(hw); if (rtlpci->acm_method != eAcmWay2_SW) rtlpriv->cfg->ops->set_hw_reg(hw, @@ -526,9 +488,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) case HW_VAR_CORRECT_TSF:{ u8 btype_ibss = ((u8 *) (val))[0]; - /*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? - 1 : 0;*/ - if (btype_ibss == true) _rtl92ce_stop_tx_beacon(hw); @@ -537,7 +496,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) rtl_write_dword(rtlpriv, REG_TSFTR, (u32) (mac->tsf & 0xffffffff)); rtl_write_dword(rtlpriv, REG_TSFTR + 4, - (u32) ((mac->tsf >> 32)&0xffffffff)); + (u32) ((mac->tsf >> 32) & 0xffffffff)); _rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0); @@ -547,15 +506,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) break; } - case HW_VAR_MGT_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val); - break; - case HW_VAR_CTRL_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val); - break; - case HW_VAR_DATA_FILTER: - rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val); - break; default: RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case " "not process\n")); @@ -679,12 +629,12 @@ static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw) rtl92ce_sw_led_on(hw, pLed0); else rtl92ce_sw_led_off(hw, pLed0); - } static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); @@ -693,9 +643,22 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) u16 retry; rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 value32; + value32 = rtl_read_dword(rtlpriv, REG_APS_FSMCO); + value32 |= (SOP_ABG | SOP_AMB | XOP_BTCK); + rtl_write_dword(rtlpriv, REG_APS_FSMCO, value32); + } rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b); rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u32 u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + + u4b_tmp &= (~0x00024800); + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } + bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0); udelay(2); @@ -726,6 +689,11 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82); udelay(2); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2) & 0xfd; + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, bytetmp); + } + rtl_write_word(rtlpriv, REG_CR, 0x2ff); if (_rtl92ce_llt_table_init(hw) == false) @@ -793,6 +761,7 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) { struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); u8 reg_bw_opmode; u32 reg_ratr, reg_prsr; @@ -824,7 +793,11 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504); - rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431); + else + rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841); rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2); @@ -840,11 +813,20 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_PIFS, 0x1C); rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16); - rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); - - rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402); + } else { + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020); + } - rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666); + else + rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666); rtl_write_byte(rtlpriv, REG_ACKTO, 0x40); @@ -948,8 +930,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) } rtlhal->last_hmeboxnum = 0; - rtl92ce_phy_mac_config(hw); - rtl92ce_phy_bb_config(hw); + rtl92c_phy_mac_config(hw); + rtl92c_phy_bb_config(hw); rtlphy->rf_mode = RF_OP_BY_SW_3WIRE; rtl92c_phy_rf_config(hw); rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0, @@ -962,15 +944,20 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw) _rtl92ce_hw_configure(hw); rtl_cam_reset_all_entry(hw); rtl92ce_enable_hw_security_config(hw); + ppsc->rfpwr_state = ERFON; + rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr); _rtl92ce_enable_aspm_back_door(hw); rtlpriv->intf_ops->enable_aspm(hw); + + rtl8192ce_bt_hw_init(hw); + if (ppsc->rfpwr_state == ERFON) { rtl92c_phy_set_rfpath_switch(hw, 1); - if (iqk_initialized) + if (iqk_initialized) { rtl92c_phy_iq_calibrate(hw, true); - else { + } else { rtl92c_phy_iq_calibrate(hw, false); iqk_initialized = true; } @@ -1128,75 +1115,62 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw, return 0; } -static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw, - enum nl80211_iftype type) +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR); - u8 filterout_non_associated_bssid = false; - switch (type) { - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_STATION: - filterout_non_associated_bssid = true; - break; - case NL80211_IFTYPE_UNSPECIFIED: - case NL80211_IFTYPE_AP: - default: - break; - } + if (rtlpriv->psc.rfpwr_state != ERFON) + return; - if (filterout_non_associated_bssid == true) { + if (check_bssid == true) { reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (®_rcr)); _rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4)); - } else if (filterout_non_associated_bssid == false) { + } else if (check_bssid == false) { reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN)); _rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0); rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (®_rcr)); } + } int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type) { + struct rtl_priv *rtlpriv = rtl_priv(hw); + if (_rtl92ce_set_media_status(hw, type)) return -EOPNOTSUPP; - _rtl92ce_set_check_bssid(hw, type); + + if (rtlpriv->mac80211.link_state == MAC80211_LINKED) { + if (type != NL80211_IFTYPE_AP) + rtl92ce_set_check_bssid(hw, true); + } else { + rtl92ce_set_check_bssid(hw, false); + } + return 0; } +/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */ void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci) { struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 u4b_ac_param; - u16 cw_min = le16_to_cpu(mac->ac[aci].cw_min); - u16 cw_max = le16_to_cpu(mac->ac[aci].cw_max); - u16 tx_op = le16_to_cpu(mac->ac[aci].tx_op); - rtl92c_dm_init_edca_turbo(hw); - u4b_ac_param = (u32) mac->ac[aci].aifs; - u4b_ac_param |= (u32) ((cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET); - u4b_ac_param |= (u32) ((cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET); - u4b_ac_param |= (u32) (tx_op << AC_PARAM_TXOP_OFFSET); - RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG, - ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n", - aci, u4b_ac_param, mac->ac[aci].aifs, cw_min, - cw_max, tx_op)); switch (aci) { case AC1_BK: - rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f); break; case AC0_BE: - rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); + /* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */ break; case AC2_VI: - rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322); break; case AC3_VO: - rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param); + rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222); break; default: RT_ASSERT(false, ("invalid aci: %d !\n", aci)); @@ -1227,8 +1201,10 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw) static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); u8 u1b_tmp; + u32 u4b_tmp; rtlpriv->intf_ops->enable_aspm(hw); rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); @@ -1243,13 +1219,27 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00); rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000); u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL); - rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | - (u1b_tmp << 8)); + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8))) { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00F30000 | + (u1b_tmp << 8)); + } else { + rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 | + (u1b_tmp << 8)); + } rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790); rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080); rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80); rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23); - rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + if (rtlpcipriv->bt_coexist.bt_coexistence) { + u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL); + u4b_tmp |= 0x03824800; + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp); + } else { + rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e); + } + rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e); rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10); } @@ -1327,6 +1317,7 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD, ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr)); + if (add_msr) rtlpci->irq_mask[0] |= add_msr; if (rm_msr) @@ -1582,7 +1573,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) ("RTL819X Not boot from eeprom, check it !!")); } - RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"), + RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"), hwinfo, HWSET_MAX_SIZE); eeprom_id = *((u16 *)&hwinfo[0]); @@ -1610,6 +1601,10 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) rtlefuse->autoload_failflag, hwinfo); + rtl8192ce_read_bt_coexist_info_from_hwpg(hw, + rtlefuse->autoload_failflag, + hwinfo); + rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN]; rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION]; rtlefuse->txpwr_fromeprom = true; @@ -1618,6 +1613,9 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw) RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid)); + /* set channel paln to world wide 13 */ + rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13; + if (rtlhal->oem_id == RT_CID_DEFAULT) { switch (rtlefuse->eeprom_oemid) { case EEPROM_CID_DEFAULT: @@ -1701,30 +1699,36 @@ void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw) } else { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n")); } - _rtl92ce_hal_customized_behavior(hw); } -void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) +static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - - u32 ratr_value = (u32) mac->basic_rates; - u8 *mcsrate = mac->mcs; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + u32 ratr_value; u8 ratr_index = 0; u8 nmode = mac->ht_enable; - u8 mimo_ps = 1; + u8 mimo_ps = IEEE80211_SMPS_OFF; u16 shortgi_rate; u32 tmp_ratr_value; u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; enum wireless_mode wirelessmode = mac->mode; - ratr_value |= ((*(u16 *) (mcsrate))) << 12; - + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_value = sta->supp_rates[1] << 4; + else + ratr_value = sta->supp_rates[0]; + ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: if (ratr_value & 0x0000000c) @@ -1738,7 +1742,7 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) case WIRELESS_MODE_N_24G: case WIRELESS_MODE_N_5G: nmode = 1; - if (mimo_ps == 0) { + if (mimo_ps == IEEE80211_SMPS_STATIC) { ratr_value &= 0x0007F005; } else { u32 ratr_mask; @@ -1761,10 +1765,19 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) break; } - ratr_value &= 0x0FFFFFFF; + if ((rtlpcipriv->bt_coexist.bt_coexistence) && + (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) && + (rtlpcipriv->bt_coexist.bt_cur_state) && + (rtlpcipriv->bt_coexist.bt_ant_isolation) && + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) || + (rtlpcipriv->bt_coexist.bt_service == BT_BUSY))) + ratr_value &= 0x0fffcfc0; + else + ratr_value &= 0x0FFFFFFF; - if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || (!curtxbw_40mhz && - curshortgi_20mhz))) { + if (nmode && ((curtxbw_40mhz && + curshortgi_40mhz) || (!curtxbw_40mhz && + curshortgi_20mhz))) { ratr_value |= 0x10000000; tmp_ratr_value = (ratr_value >> 12); @@ -1784,24 +1797,42 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw) ("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0))); } -void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) +static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u32 ratr_bitmap = (u32) mac->basic_rates; - u8 *p_mcsrate = mac->mcs; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + struct rtl_sta_info *sta_entry = NULL; + u32 ratr_bitmap; u8 ratr_index; - u8 curtxbw_40mhz = mac->bw_40; - u8 curshortgi_40mhz = mac->sgi_40; - u8 curshortgi_20mhz = mac->sgi_20; - enum wireless_mode wirelessmode = mac->mode; + u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ? 1 : 0; + u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? + 1 : 0; + u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ? + 1 : 0; + enum wireless_mode wirelessmode = 0; bool shortgi = false; u8 rate_mask[5]; u8 macid = 0; - u8 mimops = 1; - - ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12); + u8 mimo_ps = IEEE80211_SMPS_OFF; + + sta_entry = (struct rtl_sta_info *) sta->drv_priv; + wirelessmode = sta_entry->wireless_mode; + if (mac->opmode == NL80211_IFTYPE_STATION) + curtxbw_40mhz = mac->bw_40; + else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) + macid = sta->aid + 1; + + if (rtlhal->current_bandtype == BAND_ON_5G) + ratr_bitmap = sta->supp_rates[1] << 4; + else + ratr_bitmap = sta->supp_rates[0]; + ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 | + sta->ht_cap.mcs.rx_mask[0] << 12); switch (wirelessmode) { case WIRELESS_MODE_B: ratr_index = RATR_INX_WIRELESS_B; @@ -1828,7 +1859,7 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) case WIRELESS_MODE_N_5G: ratr_index = RATR_INX_WIRELESS_NGB; - if (mimops == 0) { + if (mimo_ps == IEEE80211_SMPS_STATIC) { if (rssi_level == 1) ratr_bitmap &= 0x00070000; else if (rssi_level == 2) @@ -1892,8 +1923,8 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) } RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("ratr_bitmap :%x\n", ratr_bitmap)); - *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) | - (ratr_index << 28); + *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) | + (ratr_index << 28)); rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80; RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, " "ratr_val:%x, %x:%x:%x:%x:%x\n", @@ -1902,6 +1933,20 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level) rate_mask[2], rate_mask[3], rate_mask[4])); rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask); + + if (macid != 0) + sta_entry->ratr_index = ratr_index; +} + +void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + + if (rtlpriv->dm.useramask) + rtl92ce_update_hal_rate_mask(hw, sta, rssi_level); + else + rtl92ce_update_hal_rate_table(hw, sta); } void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) @@ -1919,7 +1964,7 @@ void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer); } -bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) +bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); @@ -1929,7 +1974,7 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) bool actuallyset = false; unsigned long flag; - if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter)) + if (rtlpci->being_init_adapter) return false; if (ppsc->swrf_processing) @@ -1946,12 +1991,6 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) cur_rfstate = ppsc->rfpwr_state; - if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { - rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv, REG_MAC_PINMUX_CFG)&~(BIT(3))); @@ -1976,38 +2015,13 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) } if (actuallyset) { - if (e_rfpowerstate_toset == ERFON) { - if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) && - RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) { - rtlpriv->intf_ops->disable_aspm(hw); - RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - } - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ppsc->rfchange_inprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); - - if (e_rfpowerstate_toset == ERFOFF) { - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { - rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - } - - } else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) { + } else { if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC); - if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) { - rtlpriv->intf_ops->enable_aspm(hw); - RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM); - } - - spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); - ppsc->rfchange_inprogress = false; - spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); - } else { spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag); ppsc->rfchange_inprogress = false; spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag); @@ -2086,15 +2100,31 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, macaddr = cam_const_broad; entry_id = key_index; } else { + if (mac->opmode == NL80211_IFTYPE_AP) { + entry_id = rtl_cam_get_free_entry(hw, + p_macaddr); + if (entry_id >= TOTAL_CAM_ENTRY) { + RT_TRACE(rtlpriv, COMP_SEC, + DBG_EMERG, + ("Can not find free hw" + " security cam entry\n")); + return; + } + } else { + entry_id = CAM_PAIRWISE_KEY_POSITION; + } + key_index = PAIRWISE_KEYIDX; - entry_id = CAM_PAIRWISE_KEY_POSITION; is_pairwise = true; } } if (rtlpriv->sec.key_len[key_index] == 0) { RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, - ("delete one entry\n")); + ("delete one entry, entry_id is %d\n", + entry_id)); + if (mac->opmode == NL80211_IFTYPE_AP) + rtl_cam_del_entry(hw, p_macaddr); rtl_cam_delete_one_entry(hw, p_macaddr, entry_id); } else { RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, @@ -2146,3 +2176,132 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, } } } + +static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + rtlpcipriv->bt_coexist.bt_coexistence = + rtlpcipriv->bt_coexist.eeprom_bt_coexist; + rtlpcipriv->bt_coexist.bt_ant_num = + rtlpcipriv->bt_coexist.eeprom_bt_ant_num; + rtlpcipriv->bt_coexist.bt_coexist_type = + rtlpcipriv->bt_coexist.eeprom_bt_type; + + if (rtlpcipriv->bt_coexist.reg_bt_iso == 2) + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation; + else + rtlpcipriv->bt_coexist.bt_ant_isolation = + rtlpcipriv->bt_coexist.reg_bt_iso; + + rtlpcipriv->bt_coexist.bt_radio_shared_type = + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared; + + if (rtlpcipriv->bt_coexist.bt_coexistence) { + + if (rtlpcipriv->bt_coexist.reg_bt_sco == 1) + rtlpcipriv->bt_coexist.bt_service = BT_OTHER_ACTION; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 2) + rtlpcipriv->bt_coexist.bt_service = BT_SCO; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 4) + rtlpcipriv->bt_coexist.bt_service = BT_BUSY; + else if (rtlpcipriv->bt_coexist.reg_bt_sco == 5) + rtlpcipriv->bt_coexist.bt_service = BT_OTHERBUSY; + else + rtlpcipriv->bt_coexist.bt_service = BT_IDLE; + + rtlpcipriv->bt_coexist.bt_edca_ul = 0; + rtlpcipriv->bt_coexist.bt_edca_dl = 0; + rtlpcipriv->bt_coexist.bt_rssi_state = 0xff; + } +} + +void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool auto_load_fail, u8 *hwinfo) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + u8 value; + + if (!auto_load_fail) { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = + ((hwinfo[RF_OPTION1] & 0xe0) >> 5); + value = hwinfo[RF_OPTION4]; + rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1); + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = + ((value & 0x10) >> 4); + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = + ((value & 0x20) >> 5); + } else { + rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0; + rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE; + rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2; + rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0; + rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED; + } + + rtl8192ce_bt_var_init(hw); +} + +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw) +{ + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + /* 0:Low, 1:High, 2:From Efuse. */ + rtlpcipriv->bt_coexist.reg_bt_iso = 2; + /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 3; + /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */ + rtlpcipriv->bt_coexist.reg_bt_sco = 0; +} + + +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); + struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw); + + u8 u1_tmp; + + if (rtlpcipriv->bt_coexist.bt_coexistence && + ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) || + rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8)) { + + if (rtlpcipriv->bt_coexist.bt_ant_isolation) + rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0); + + u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) & + BIT_OFFSET_LEN_MASK_32(0, 1); + u1_tmp = u1_tmp | + ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ? + 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) | + ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ? + 0 : BIT_OFFSET_LEN_MASK_32(2, 1)); + rtl_write_byte(rtlpriv, 0x4fd, u1_tmp); + + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040); + rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010); + + /* Config to 1T1R. */ + if (rtlphy->rf_type == RF_1T1R) { + u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp); + + u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE); + u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1)); + rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp); + } + } +} + +void rtl92ce_suspend(struct ieee80211_hw *hw) +{ +} + +void rtl92ce_resume(struct ieee80211_hw *hw) +{ +} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h index a3dfdb6..07dbe3e 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h @@ -30,7 +30,18 @@ #ifndef __RTL92CE_HW_H__ #define __RTL92CE_HW_H__ -#define H2C_RA_MASK 6 +static inline u8 _rtl92c_get_chnl_group(u8 chnl) +{ + u8 group; + + if (chnl < 3) + group = 0; + else if (chnl < 9) + group = 1; + else + group = 2; + return group; +} void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw); @@ -41,28 +52,27 @@ void rtl92ce_card_disable(struct ieee80211_hw *hw); void rtl92ce_enable_interrupt(struct ieee80211_hw *hw); void rtl92ce_disable_interrupt(struct ieee80211_hw *hw); int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type); +void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci); void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw); void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw); void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr); void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); -void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw); -void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); +void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid); void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw); void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all); -bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); -void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished); -void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); -void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus); -int rtl92c_download_fw(struct ieee80211_hw *hw); -void rtl92c_firmware_selfreset(struct ieee80211_hw *hw); -void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw, - u8 element_id, u32 cmd_len, u8 *p_cmdbuffer); -bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw); + +void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo); +void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw); +void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw); +void rtl92ce_suspend(struct ieee80211_hw *hw); +void rtl92ce_resume(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c index d21b934..9dd1ed7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c @@ -106,12 +106,11 @@ void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled) void rtl92ce_init_sw_leds(struct ieee80211_hw *hw) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); - _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0); _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1); } -void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, +static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); @@ -146,7 +145,7 @@ void rtl92ce_led_control(struct ieee80211_hw *hw, ledaction == LED_CTL_POWER_ON)) { return; } - RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n", + RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d.\n", ledaction)); _rtl92ce_sw_led_control(hw, ledaction); } diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h index 94332b3..7dfccea 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h @@ -34,7 +34,5 @@ void rtl92ce_init_sw_leds(struct ieee80211_hw *hw); void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled); void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction); -void _rtl92ce_sw_led_control(struct ieee80211_hw *hw, - enum led_ctl_mode ledaction); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index d0541e8..73ae8a4 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -38,7 +38,9 @@ #include "dm.h" #include "table.h" -u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); + +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -73,9 +75,47 @@ u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, return readback_value; } +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + bool is92c = IS_92C_SERIAL(rtlhal->version); + bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw); + + if (is92c) + rtl_write_byte(rtlpriv, 0x14, 0x71); + return rtstatus; +} + +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw) +{ + bool rtstatus = true; + struct rtl_priv *rtlpriv = rtl_priv(hw); + u16 regval; + u32 regvaldw; + u8 reg_hwparafile = 1; + + _rtl92c_phy_init_bb_rf_register_definition(hw); + regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, + regval | BIT(13) | BIT(0) | BIT(1)); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); + rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); + rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, + FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | + FEN_BB_GLB_RSTn | FEN_BBRSTB); + rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); + regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); + rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); + if (reg_hwparafile == 1) + rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); + return rtstatus; +} + void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, - u32 regaddr, u32 bitmask, u32 data) + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -121,45 +161,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, bitmask, data, rfpath)); } -bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - bool is92c = IS_92C_SERIAL(rtlhal->version); - bool rtstatus = _rtl92ce_phy_config_mac_with_headerfile(hw); - - if (is92c) - rtl_write_byte(rtlpriv, 0x14, 0x71); - return rtstatus; -} - -bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw) -{ - bool rtstatus = true; - struct rtl_priv *rtlpriv = rtl_priv(hw); - u16 regval; - u32 regvaldw; - u8 reg_hwparafile = 1; - - _rtl92c_phy_init_bb_rf_register_definition(hw); - regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); - rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, - regval | BIT(13) | BIT(0) | BIT(1)); - rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83); - rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb); - rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB); - rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, - FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE | - FEN_BB_GLB_RSTn | FEN_BBRSTB); - rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80); - regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0); - rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23)); - if (reg_hwparafile == 1) - rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw); - return rtstatus; -} - -bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) +static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 i; @@ -177,7 +179,7 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) } bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { int i; u32 *phy_regarray_table; @@ -236,7 +238,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { struct rtl_priv *rtlpriv = rtl_priv(hw); int i; @@ -274,7 +276,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, return true; } -bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, +bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath) { @@ -364,74 +366,6 @@ bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, return true; } -void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - struct rtl_phy *rtlphy = &(rtlpriv->phy); - struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - u8 reg_bw_opmode; - u8 reg_prsr_rsc; - - RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, - ("Switch to %s bandwidth\n", - rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ? - "20MHz" : "40MHz")) - - if (is_hal_stop(rtlhal)) - return; - - reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE); - reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2); - - switch (rtlphy->current_chan_bw) { - case HT_CHANNEL_WIDTH_20: - reg_bw_opmode |= BW_OPMODE_20MHZ; - rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); - break; - - case HT_CHANNEL_WIDTH_20_40: - reg_bw_opmode &= ~BW_OPMODE_20MHZ; - rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode); - - reg_prsr_rsc = - (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5); - rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc); - break; - - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); - break; - } - - switch (rtlphy->current_chan_bw) { - case HT_CHANNEL_WIDTH_20: - rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0); - rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0); - rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1); - break; - case HT_CHANNEL_WIDTH_20_40: - rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1); - rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1); - rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND, - (mac->cur_40_prime_sc >> 1)); - rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc); - rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0); - rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)), - (mac->cur_40_prime_sc == - HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1); - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, - ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw)); - break; - } - rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw); - rtlphy->set_bwmode_inprogress = false; - RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n")); -} - void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) { u8 tmpreg; @@ -477,6 +411,36 @@ void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) } } +static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw) +{ + u32 u4b_tmp; + u8 delay = 5; + struct rtl_priv *rtlpriv = rtl_priv(hw); + + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + while (u4b_tmp != 0 && delay > 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0); + rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00); + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40); + u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK); + delay--; + } + if (delay == 0) { + rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3); + rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00); + RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE, + ("Switch RF timeout !!!.\n")); + return; + } + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2); + rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22); +} + static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { @@ -523,33 +487,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, break; } case ERFOFF:{ - for (queue_id = 0, i = 0; - queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { - ring = &pcipriv->dev.tx_ring[queue_id]; - if (skb_queue_len(&ring->queue) == 0 || - queue_id == BEACON_QUEUE) { - queue_id++; - continue; - } else { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("eRf Off/Sleep: %d times " - "TcbBusyQueue[%d] " - "=%d before doze!\n", (i + 1), - queue_id, - skb_queue_len(&ring->queue))); - udelay(10); - i++; - } - if (i >= MAX_DOZE_WAITING_TIMES_9x) { - RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, - ("\nERFOFF: %d times " - "TcbBusyQueue[%d] = %d !\n", - MAX_DOZE_WAITING_TIMES_9x, - queue_id, - skb_queue_len(&ring->queue))); - break; - } - } if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) { RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG, ("IPS Set eRf nic disable\n")); @@ -581,6 +518,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, "TcbBusyQueue[%d] =%d before " "doze!\n", (i + 1), queue_id, skb_queue_len(&ring->queue))); + udelay(10); i++; } @@ -599,7 +537,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies))); ppsc->last_sleep_jiffies = jiffies; - _rtl92c_phy_set_rf_sleep(hw); + _rtl92ce_phy_set_rf_sleep(hw); break; } default: @@ -614,10 +552,11 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, return bresult; } -bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); + bool bresult = false; if (rfpwr_state == ppsc->rfpwr_state) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h index a37267e..ad58085 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h @@ -39,6 +39,7 @@ #define RT_CANNOT_IO(hw) false #define HIGHPOWER_RADIOA_ARRAYLEN 22 +#define IQK_ADDA_REG_NUM 16 #define MAX_TOLERANCE 5 #define IQK_DELAY_TIME 1 @@ -56,6 +57,8 @@ #define IQK_ADDA_REG_NUM 16 #define IQK_MAC_REG_NUM 4 +#define IQK_DELAY_TIME 1 + #define RF90_PATH_MAX 2 #define CT_OFFSET_MAC_ADDR 0X16 @@ -76,7 +79,7 @@ #define CT_OFFSET_CUSTOMER_ID 0x7F #define RTL92C_MAX_PATH_NUM 2 -#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255 + enum swchnlcmd_id { CMDID_END, CMDID_SET_TXPOWEROWER_LEVEL, @@ -184,43 +187,44 @@ struct tx_power_struct { u32 mcs_original_offset[4][16]; }; -extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, +bool rtl92c_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask); -extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, +void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask, u32 data); -extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, +u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask); extern void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, - u32 bitmask, u32 data); -extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); + enum radio_path rfpath, u32 regaddr, + u32 bitmask, u32 data); +bool rtl92c_phy_mac_config(struct ieee80211_hw *hw); bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); -extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, +bool rtl92c_phy_rf_config(struct ieee80211_hw *hw); +bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); -extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, +void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw); +void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel); -extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); -extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, +void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel); +bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm); -extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, +void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation); -extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw); -extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, +void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw, enum nl80211_channel_type ch_type); -extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); -extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); -extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); -extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, +void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw); +u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw); +void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery); +void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval); void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta); void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw); +void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain); bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); -extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, +bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype); bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, @@ -237,9 +241,6 @@ u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask); void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); -void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw, - u32 regaddr, u32 bitmask, - u32 data); void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw, enum radio_path rfpath, u32 offset, u32 data); @@ -250,5 +251,11 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw); bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw); void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw); +bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); +bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h index b0868a6..598cecc 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h @@ -72,6 +72,7 @@ #define REG_GPIO_IO_SEL_2 0x0062 /* RTL8723 WIFI/BT/GPS Multi-Function control source. */ #define REG_MULTI_FUNC_CTRL 0x0068 + #define REG_MCUFWDL 0x0080 #define REG_HMEBOX_EXT_0 0x0088 @@ -542,7 +543,7 @@ #define IMR_OCPINT BIT(1) #define IMR_WLANOFF BIT(0) -#define HWSET_MAX_SIZE 128 +#define EFUSE_REAL_CONTENT_LEN 512 #define EEPROM_DEFAULT_TSSI 0x0 #define EEPROM_DEFAULT_TXPOWERDIFF 0x0 @@ -656,6 +657,7 @@ #define STOPBE BIT(1) #define STOPBK BIT(0) +#define RCR_APPFCS BIT(31) #define RCR_APP_FCS BIT(31) #define RCR_APP_MIC BIT(30) #define RCR_APP_ICV BIT(29) @@ -688,6 +690,7 @@ #define REG_USB_INFO 0xFE17 #define REG_USB_SPECIAL_OPTION 0xFE55 + #define REG_USB_DMA_AGG_TO 0xFE5B #define REG_USB_AGG_TO 0xFE5C #define REG_USB_AGG_TH 0xFE5D @@ -775,7 +778,6 @@ #define BOOT_FROM_EEPROM BIT(4) #define EEPROM_EN BIT(5) -#define EEPROMSEL BOOT_FROM_EEPROM #define AFE_BGEN BIT(0) #define AFE_MBEN BIT(1) @@ -901,28 +903,7 @@ #define BD_PKG_SEL BIT(25) #define BD_HCI_SEL BIT(26) #define TYPE_ID BIT(27) - -/* REG_GPIO_OUTSTS (For RTL8723 only) */ -#define EFS_HCI_SEL (BIT(0)|BIT(1)) -#define PAD_HCI_SEL (BIT(2)|BIT(3)) -#define HCI_SEL (BIT(4)|BIT(5)) -#define PKG_SEL_HCI BIT(6) -#define FEN_GPS BIT(7) -#define FEN_BT BIT(8) -#define FEN_WL BIT(9) -#define FEN_PCI BIT(10) -#define FEN_USB BIT(11) -#define BTRF_HWPDN_N BIT(12) -#define WLRF_HWPDN_N BIT(13) -#define PDN_BT_N BIT(14) -#define PDN_GPS_N BIT(15) -#define BT_CTL_HWPDN BIT(16) -#define GPS_CTL_HWPDN BIT(17) -#define PPHY_SUSB BIT(20) -#define UPHY_SUSB BIT(21) -#define PCI_SUSEN BIT(22) -#define USB_SUSEN BIT(23) -#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) +#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28)) #define CHIP_VER_RTL_MASK 0xF000 #define CHIP_VER_RTL_SHIFT 12 @@ -1077,6 +1058,7 @@ #define _RARF_RC8(x) (((x) & 0x1F) << 24) #define AC_PARAM_TXOP_OFFSET 16 +#define AC_PARAM_TXOP_LIMIT_OFFSET 16 #define AC_PARAM_ECW_MAX_OFFSET 12 #define AC_PARAM_ECW_MIN_OFFSET 8 #define AC_PARAM_AIFS_OFFSET 0 @@ -1221,33 +1203,11 @@ #define EPROM_CMD_CONFIG 0x3 #define EPROM_CMD_LOAD 1 -#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE +#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE -#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) - -/* REG_MULTI_FUNC_CTRL(For RTL8723 Only) */ -/* Enable GPIO[9] as WiFi HW PDn source */ #define WL_HWPDN_EN BIT(0) -/* WiFi HW PDn polarity control */ -#define WL_HWPDN_SL BIT(1) -/* WiFi function enable */ -#define WL_FUNC_EN BIT(2) -/* Enable GPIO[9] as WiFi RF HW PDn source */ -#define WL_HWROF_EN BIT(3) -/* Enable GPIO[11] as BT HW PDn source */ -#define BT_HWPDN_EN BIT(16) -/* BT HW PDn polarity control */ -#define BT_HWPDN_SL BIT(17) -/* BT function enable */ -#define BT_FUNC_EN BIT(18) -/* Enable GPIO[11] as BT/GPS RF HW PDn source */ -#define BT_HWROF_EN BIT(19) -/* Enable GPIO[10] as GPS HW PDn source */ -#define GPS_HWPDN_EN BIT(20) -/* GPS HW PDn polarity control */ -#define GPS_HWPDN_SL BIT(21) -/* GPS function enable */ -#define GPS_FUNC_EN BIT(22) + +#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2) #define RPMAC_RESET 0x100 #define RPMAC_TXSTART 0x104 diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c index e301b12..90d0f2c 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c @@ -34,9 +34,9 @@ #include "rf.h" #include "dm.h" -static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw); +static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw); -void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) +void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -62,7 +62,7 @@ void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) } void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel) + u8 *ppowerlevel) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -128,8 +128,7 @@ void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, tmpval = tx_agc[RF90_PATH_A] >> 8; - if (mac->mode == WIRELESS_MODE_B) - tmpval = tmpval & 0xff00ffff; + tmpval = tmpval & 0xff00ffff; rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval); @@ -440,16 +439,17 @@ bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw) else rtlphy->num_total_rfpath = 2; - return _rtl92c_phy_rf6052_config_parafile(hw); + return _rtl92ce_phy_rf6052_config_parafile(hw); + } -static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) +static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); u32 u4_regvalue = 0; u8 rfpath; - bool rtstatus; + bool rtstatus = true; struct bb_reg_def *pphyreg; for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) { @@ -484,12 +484,12 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw) switch (rfpath) { case RF90_PATH_A: - rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, - (enum radio_path) rfpath); + rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); break; case RF90_PATH_B: - rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw, - (enum radio_path) rfpath); + rtstatus = rtl92c_phy_config_rf_with_headerfile(hw, + (enum radio_path)rfpath); break; case RF90_PATH_C: break; diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h index 3aa520c..39ff036 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h @@ -34,14 +34,11 @@ #define RF6052_MAX_REG 0x3F #define RF6052_MAX_PATH 2 -extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, - u8 bandwidth); -extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel); -extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel); -bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); -bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, - enum radio_path rfpath); - +extern void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, + u8 bandwidth); +extern void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +extern void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); +extern bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index f4e2f3d..390bbb5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -42,10 +42,58 @@ #include "trx.h" #include "led.h" +static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw) +{ + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + + /*close ASPM for AMD defaultly */ + rtlpci->const_amdpci_aspm = 0; + + /* + * ASPM PS mode. + * 0 - Disable ASPM, + * 1 - Enable ASPM without Clock Req, + * 2 - Enable ASPM with Clock Req, + * 3 - Alwyas Enable ASPM with Clock Req, + * 4 - Always Enable ASPM without Clock Req. + * set defult to RTL8192CE:3 RTL8192E:2 + * */ + rtlpci->const_pci_aspm = 3; + + /*Setting for PCI-E device */ + rtlpci->const_devicepci_aspm_setting = 0x03; + + /*Setting for PCI-E bridge */ + rtlpci->const_hostpci_aspm_setting = 0x02; + + /* + * In Hw/Sw Radio Off situation. + * 0 - Default, + * 1 - From ASPM setting without low Mac Pwr, + * 2 - From ASPM setting with low Mac Pwr, + * 3 - Bus D3 + * set default to RTL8192CE:0 RTL8192SE:2 + */ + rtlpci->const_hwsw_rfoff_d3 = 0; + + /* + * This setting works for those device with + * backdoor ASPM setting such as EPHY setting. + * 0 - Not support ASPM, + * 1 - Support ASPM, + * 2 - According to chipset. + */ + rtlpci->const_support_pciaspm = 1; +} + int rtl92c_init_sw_vars(struct ieee80211_hw *hw) { + int err; struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); + const struct firmware *firmware; + + rtl8192ce_bt_reg_init(hw); rtlpriv->dm.dm_initialgain_enable = 1; rtlpriv->dm.dm_flag = 0; @@ -53,7 +101,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.thermalvalue = 0; rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13); - rtlpci->receive_config = (RCR_APP_FCS | + /* compatible 5G band 88ce just 2.4G band & smsp */ + rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G; + rtlpriv->rtlhal.bandset = BAND_ON_2_4G; + rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY; + + rtlpci->receive_config = (RCR_APPFCS | RCR_AMF | RCR_ADF | RCR_APP_MIC | @@ -76,13 +129,49 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0); - rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000); + /* for LPS & IPS */ + rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; + rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; + rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + rtlpriv->psc.reg_fwctrl_lps = 3; + rtlpriv->psc.reg_max_lps_awakeintvl = 5; + /* for ASPM, you can close aspm through + * set const_support_pciaspm = 0 */ + rtl92c_init_aspm_vars(hw); + + if (rtlpriv->psc.reg_fwctrl_lps == 1) + rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 2) + rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE; + else if (rtlpriv->psc.reg_fwctrl_lps == 3) + rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE; + + /* for firmware buf */ + rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); if (!rtlpriv->rtlhal.pfirmware) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Can't alloc buffer for fw.\n")); return 1; } + /* request fw */ + err = request_firmware(&firmware, rtlpriv->cfg->fw_name, + rtlpriv->io.dev); + if (err) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Failed to request firmware!\n")); + return 1; + } + if (firmware->size > 0x4000) { + RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, + ("Firmware is too big!\n")); + release_firmware(firmware); + return 1; + } + memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size); + rtlpriv->rtlhal.fwsize = firmware->size; + release_firmware(firmware); + return 0; } @@ -103,17 +192,19 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .interrupt_recognized = rtl92ce_interrupt_recognized, .hw_init = rtl92ce_hw_init, .hw_disable = rtl92ce_card_disable, + .hw_suspend = rtl92ce_suspend, + .hw_resume = rtl92ce_resume, .enable_interrupt = rtl92ce_enable_interrupt, .disable_interrupt = rtl92ce_disable_interrupt, .set_network_type = rtl92ce_set_network_type, + .set_chk_bssid = rtl92ce_set_check_bssid, .set_qos = rtl92ce_set_qos, .set_bcn_reg = rtl92ce_set_beacon_related_registers, .set_bcn_intv = rtl92ce_set_beacon_interval, .update_interrupt_mask = rtl92ce_update_interrupt_mask, .get_hw_reg = rtl92ce_get_hw_reg, .set_hw_reg = rtl92ce_set_hw_reg, - .update_rate_table = rtl92ce_update_hal_rate_table, - .update_rate_mask = rtl92ce_update_hal_rate_mask, + .update_rate_tbl = rtl92ce_update_hal_rate_tbl, .fill_tx_desc = rtl92ce_tx_fill_desc, .fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc, .query_rx_desc = rtl92ce_rx_query_desc, @@ -123,7 +214,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .switch_channel = rtl92c_phy_sw_chnl, .dm_watchdog = rtl92c_dm_watchdog, .scan_operation_backup = rtl92c_phy_scan_operation_backup, - .set_rf_power_state = rtl92ce_phy_set_rf_power_state, + .set_rf_power_state = rtl92c_phy_set_rf_power_state, .led_control = rtl92ce_led_control, .set_desc = rtl92ce_set_desc, .get_desc = rtl92ce_get_desc, @@ -133,24 +224,27 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = { .init_sw_leds = rtl92ce_init_sw_leds, .get_bbreg = rtl92c_phy_query_bb_reg, .set_bbreg = rtl92c_phy_set_bb_reg, - .get_rfreg = rtl92ce_phy_query_rf_reg, .set_rfreg = rtl92ce_phy_set_rf_reg, - .cmd_send_packet = _rtl92c_cmd_send_packet, + .get_rfreg = rtl92c_phy_query_rf_reg, .phy_rf6052_config = rtl92ce_phy_rf6052_config, .phy_rf6052_set_cck_txpower = rtl92ce_phy_rf6052_set_cck_txpower, .phy_rf6052_set_ofdm_txpower = rtl92ce_phy_rf6052_set_ofdm_txpower, .config_bb_with_headerfile = _rtl92ce_phy_config_bb_with_headerfile, .config_bb_with_pgheaderfile = _rtl92ce_phy_config_bb_with_pgheaderfile, .phy_lc_calibrate = _rtl92ce_phy_lc_calibrate, - .phy_set_bw_mode_callback = rtl92ce_phy_set_bw_mode_callback, .dm_dynamic_txpower = rtl92ce_dm_dynamic_txpower, }; static struct rtl_mod_params rtl92ce_mod_params = { - .sw_crypto = 0, + .sw_crypto = false, + .inactiveps = true, + .swctrl_lps = false, + .fwctrl_lps = true, }; static struct rtl_hal_cfg rtl92ce_hal_cfg = { + .bar_id = 2, + .write_readback = true, .name = "rtl92c_pci", .fw_name = "rtlwifi/rtl8192cfw.bin", .ops = &rtl8192ce_hal_ops, @@ -174,6 +268,8 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN, .maps[EFUSE_ANA8M] = EFUSE_ANA8M, .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE, + .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, + .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, .maps[RWCAM] = REG_CAMCMD, .maps[WCAMI] = REG_CAMWRITE, @@ -238,7 +334,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, }; -static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = { +DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = { {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)}, {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)}, @@ -256,7 +352,13 @@ MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin"); module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444); +module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444); +module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444); +module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444); MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); +MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); +MODULE_PARM_DESC(fwlps, "using linked fw control power save " + "(default 1 is open)\n"); static struct pci_driver rtl92ce_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h index 36e6576..b7dc326 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h @@ -33,19 +33,9 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw); void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw); void rtl92c_init_var_map(struct ieee80211_hw *hw); -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, - struct sk_buff *skb); -void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel); -void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel); bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype); + u8 configtype); bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype); -void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); -u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, u32 bitmask); -void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw); + u8 configtype); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index aa2b581..54b2bd5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -36,42 +36,16 @@ #include "trx.h" #include "led.h" -static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(__le16 fc, - unsigned int - skb_queue) +static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) { - enum rtl_desc_qsel qsel; + __le16 fc = rtl_get_fc(skb); - if (unlikely(ieee80211_is_beacon(fc))) { - qsel = QSLT_BEACON; - return qsel; - } - - if (ieee80211_is_mgmt(fc)) { - qsel = QSLT_MGNT; - return qsel; - } + if (unlikely(ieee80211_is_beacon(fc))) + return QSLT_BEACON; + if (ieee80211_is_mgmt(fc)) + return QSLT_MGNT; - switch (skb_queue) { - case VO_QUEUE: - qsel = QSLT_VO; - break; - case VI_QUEUE: - qsel = QSLT_VI; - break; - case BE_QUEUE: - qsel = QSLT_BE; - break; - case BK_QUEUE: - qsel = QSLT_BK; - break; - default: - qsel = QSLT_BE; - RT_ASSERT(false, ("BE queue, skb_queue:%d," - " set qsel = 0x%X\n", skb_queue, QSLT_BE)); - break; - } - return qsel; + return skb->priority; } static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) @@ -255,6 +229,7 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, u8 evm, pwdb_all, rf_rx_num = 0; u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; + bool in_powersavemode = false; bool is_cck_rate; is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); @@ -270,9 +245,13 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, u8 report, cck_highpwr; cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; - cck_highpwr = (u8) rtl_get_bbreg(hw, - RFPGA0_XA_HSSIPARAMETER2, - BIT(9)); + if (!in_powersavemode) + cck_highpwr = (u8) rtl_get_bbreg(hw, + RFPGA0_XA_HSSIPARAMETER2, + BIT(9)); + else + cck_highpwr = false; + if (!cck_highpwr) { u8 cck_agc_rpt = cck_buf->cck_agc_rpt; report = cck_buf->cck_agc_rpt & 0xc0; @@ -398,6 +377,7 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) { + rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX; last_rssi = @@ -424,10 +404,6 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw, if (!pstats->is_cck && pstats->packet_toself) { for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { - - if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath)) - continue; - if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) { rtlpriv->stats.rx_rssi_percentage[rfpath] = pstats->rx_mimo_signalstrength[rfpath]; @@ -723,7 +699,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index) + u8 hw_queue, struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -732,16 +708,9 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, bool defaultadapter = true; struct ieee80211_sta *sta; u8 *pdesc = (u8 *) pdesc_tx; - struct rtl_tcb_desc tcb_desc; - u8 *qc = ieee80211_get_qos_ctl(hdr); - u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; __le16 fc = hdr->frame_control; - u8 rate_flag = info->control.rates[0].flags; - - enum rtl_desc_qsel fw_qsel = - _rtl92ce_map_hwqueue_to_fwqueue(fc, queue_index); - + u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue); bool firstseg = ((hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0); @@ -751,56 +720,68 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + u8 bw_40 = 0; + + rcu_read_lock(); + sta = get_sta(hw, mac->vif, mac->bssid); + if (mac->opmode == NL80211_IFTYPE_STATION) { + bw_40 = mac->bw_40; + } else if (mac->opmode == NL80211_IFTYPE_AP || + mac->opmode == NL80211_IFTYPE_ADHOC) { + if (sta) + bw_40 = sta->ht_cap.cap & + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c)); + if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) { + firstseg = true; + lastseg = true; + } if (firstseg) { SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); - SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate); + SET_TX_DESC_TX_RATE(pdesc, tcb_desc->hw_rate); - if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); - if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && - info->flags & IEEE80211_TX_CTL_AMPDU) { + if (info->flags & IEEE80211_TX_CTL_AMPDU) { SET_TX_DESC_AGG_BREAK(pdesc, 1); SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14); } SET_TX_DESC_SEQ(pdesc, seq_number); - SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.rts_enable && - !tcb_desc. + SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc->rts_enable && + !tcb_desc-> cts_enable) ? 1 : 0)); SET_TX_DESC_HW_RTS_ENABLE(pdesc, - ((tcb_desc.rts_enable - || tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); + ((tcb_desc->rts_enable + || tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate); + SET_TX_DESC_RTS_RATE(pdesc, tcb_desc->rts_rate); SET_TX_DESC_RTS_BW(pdesc, 0); - SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc); + SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? - (tcb_desc.rts_use_shortpreamble ? 1 : 0) - : (tcb_desc.rts_use_shortgi ? 1 : 0))); + ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); - if (mac->bw_40) { - if (tcb_desc.packet_bw) { + if (bw_40) { + if (tcb_desc->packet_bw) { SET_TX_DESC_DATA_BW(pdesc, 1); SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3); } else { SET_TX_DESC_DATA_BW(pdesc, 0); - - if (rate_flag & IEEE80211_TX_RC_DUP_DATA) { - SET_TX_DESC_TX_SUB_CARRIER(pdesc, - mac->cur_40_prime_sc); - } + SET_TX_DESC_TX_SUB_CARRIER(pdesc, + mac->cur_40_prime_sc); } } else { SET_TX_DESC_DATA_BW(pdesc, 0); @@ -810,13 +791,10 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_LINIP(pdesc, 0); SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len); - rcu_read_lock(); - sta = ieee80211_find_sta(mac->vif, mac->bssid); if (sta) { u8 ampdu_density = sta->ht_cap.ampdu_density; SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density); } - rcu_read_unlock(); if (info->control.hw_key) { struct ieee80211_key_conf *keyconf = @@ -844,7 +822,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F); SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF); SET_TX_DESC_DISABLE_FB(pdesc, 0); - SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0); + SET_TX_DESC_USE_RATE(pdesc, tcb_desc->use_driver_rate ? 1 : 0); if (ieee80211_is_data_qos(fc)) { if (mac->rdg_en) { @@ -855,24 +833,24 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, } } } + rcu_read_unlock(); SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0)); SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0)); SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); if (rtlpriv->dm.useramask) { - SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index); - SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id); + SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->mac_id); } else { - SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index); - SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index); + SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(pdesc, tcb_desc->ratr_index); } - if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && - ppsc->fwctrl_lps) { + if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { SET_TX_DESC_HWSEQ_EN(pdesc, 1); SET_TX_DESC_PKT_ID(pdesc, 8); @@ -923,7 +901,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len)); - SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping)); + SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping); SET_TX_DESC_RATE_ID(pdesc, 7); SET_TX_DESC_MACID(pdesc, 0); @@ -1021,7 +999,7 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name) return ret; } -void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue) { struct rtl_priv *rtlpriv = rtl_priv(hw); if (hw_queue == BEACON_QUEUE) { @@ -1032,35 +1010,3 @@ void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue) } } -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, - struct sk_buff *skb) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); - struct rtl8192_tx_ring *ring; - struct rtl_tx_desc *pdesc; - u8 own; - unsigned long flags; - struct sk_buff *pskb = NULL; - - ring = &rtlpci->tx_ring[BEACON_QUEUE]; - - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); - - pskb = __skb_dequeue(&ring->queue); - if (pskb) - kfree_skb(pskb); - - pdesc = &ring->desc[0]; - own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN); - - rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb); - - __skb_queue_tail(&ring->queue, skb); - - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - - rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE); - - return true; -} diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index b0b0b13..0f11771 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -724,17 +724,16 @@ struct rx_desc_92c { void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc, struct ieee80211_tx_info *info, - struct sk_buff *skb, unsigned int qsel); + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, struct ieee80211_rx_status *rx_status, u8 *pdesc, struct sk_buff *skb); void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val); u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name); -void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue); +void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue); void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool b_firstseg, bool b_lastseg, struct sk_buff *skb); -bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb); - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index e43be25..52e2af5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -39,6 +39,7 @@ #include "mac.h" #include "dm.h" #include "hw.h" +#include "../rtl8192ce/hw.h" #include "trx.h" #include "led.h" #include "table.h" @@ -605,10 +606,10 @@ void rtl92cu_read_eeprom_info(struct ieee80211_hw *hw) if (!IS_NORMAL_CHIP(rtlhal->version)) return; tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR); - rtlefuse->epromtype = (tmp_u1b & EEPROMSEL) ? + rtlefuse->epromtype = (tmp_u1b & BOOT_FROM_EEPROM) ? EEPROM_93C46 : EEPROM_BOOT_EFUSE; RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from %s\n", - (tmp_u1b & EEPROMSEL) ? "EERROM" : "EFUSE")); + (tmp_u1b & BOOT_FROM_EEPROM) ? "EERROM" : "EFUSE")); rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true; RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload %s\n", (tmp_u1b & EEPROM_EN) ? "OK!!" : "ERR!!")); @@ -977,7 +978,7 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); - mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APP_FCS | + mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS | RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL | RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32); rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf); @@ -2182,7 +2183,9 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val) } } -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw) +void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h index 62af555..32f85cb 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h @@ -98,13 +98,14 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw, u32 add_msr, u32 rm_msr); void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val); -void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw); +void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, + u8 rssi_level); void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level); void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw); bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid); void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid); -u8 _rtl92c_get_chnl_group(u8 chnl); int rtl92c_download_fw(struct ieee80211_hw *hw); void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode); void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 4e020e6..9a3d023 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -38,7 +38,7 @@ #include "table.h" u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, u32 regaddr, u32 bitmask) + enum radio_path rfpath, u32 regaddr, u32 bitmask) { struct rtl_priv *rtlpriv = rtl_priv(hw); u32 original_value, readback_value, bitshift; @@ -64,8 +64,8 @@ u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, } void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, - enum radio_path rfpath, - u32 regaddr, u32 bitmask, u32 data) + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -163,7 +163,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw) } bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { int i; u32 *phy_regarray_table; @@ -223,7 +223,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, } bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, - u8 configtype) + u8 configtype) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -459,7 +459,7 @@ void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t) } } -bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, +static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, enum rf_pwrstate rfpwr_state) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -595,7 +595,7 @@ bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, } bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, - enum rf_pwrstate rfpwr_state) + enum rf_pwrstate rfpwr_state) { struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); bool bresult = false; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h index 0629955..ff81a61 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h @@ -34,3 +34,17 @@ bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath); void rtl92c_phy_set_io(struct ieee80211_hw *hw); bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw); bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw); +u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, u32 regaddr, u32 bitmask); +void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw, + enum radio_path rfpath, + u32 regaddr, u32 bitmask, u32 data); +bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw); +bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw, + u8 configtype); +void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t); +bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw, + u8 configtype); +void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw); +bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, + enum rf_pwrstate rfpwr_state); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c index 1c79c22..c7576ec 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -62,7 +62,7 @@ void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth) } void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel) + u8 *ppowerlevel) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); @@ -389,7 +389,7 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw, } void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, - u8 *ppowerlevel, u8 channel) + u8 *ppowerlevel, u8 channel) { u32 writeVal[2], powerBase0[2], powerBase1[2]; u8 index = 0; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h index 86c2728..500a209 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h @@ -43,5 +43,9 @@ extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw); bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw, enum radio_path rfpath); +void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel); +void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw, + u8 *ppowerlevel, u8 channel); #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 71244a3..bee7c14 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -94,7 +94,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { .update_interrupt_mask = rtl92cu_update_interrupt_mask, .get_hw_reg = rtl92cu_get_hw_reg, .set_hw_reg = rtl92cu_set_hw_reg, - .update_rate_table = rtl92cu_update_hal_rate_table, + .update_rate_tbl = rtl92cu_update_hal_rate_table, .update_rate_mask = rtl92cu_update_hal_rate_mask, .fill_tx_desc = rtl92cu_tx_fill_desc, .fill_fake_txdesc = rtl92cu_fill_fake_txdesc, diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 3f0cb81..79c98f6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -498,14 +498,14 @@ static void _rtl_tx_desc_checksum(u8 *txdesc) void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index) + u8 queue_index, + struct rtl_tcb_desc *tcb_desc) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); bool defaultadapter = true; - struct ieee80211_sta *sta; - struct rtl_tcb_desc tcb_desc; + struct ieee80211_sta *sta = info->control.sta = info->control.sta; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; @@ -517,15 +517,15 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, u8 *txdesc; seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; - rtl_get_tcb_desc(hw, info, skb, &tcb_desc); + rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc); txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE); memset(txdesc, 0, RTL_TX_HEADER_SIZE); SET_TX_DESC_PKT_SIZE(txdesc, pktlen); SET_TX_DESC_LINIP(txdesc, 0); SET_TX_DESC_PKT_OFFSET(txdesc, RTL_DUMMY_OFFSET); SET_TX_DESC_OFFSET(txdesc, RTL_TX_HEADER_SIZE); - SET_TX_DESC_TX_RATE(txdesc, tcb_desc.hw_rate); - if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble) + SET_TX_DESC_TX_RATE(txdesc, tcb_desc->hw_rate); + if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(txdesc, 1); if (mac->tids[tid].agg.agg_state == RTL_AGG_ON && info->flags & IEEE80211_TX_CTL_AMPDU) { @@ -535,21 +535,21 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_AGG_BREAK(txdesc, 1); } SET_TX_DESC_SEQ(txdesc, seq_number); - SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable && - !tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable || - tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc.cts_enable) ? 1 : 0)); - SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc.rts_stbc) ? 1 : 0)); - SET_TX_DESC_RTS_RATE(txdesc, tcb_desc.rts_rate); + SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable && + !tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable || + tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc->cts_enable) ? 1 : 0)); + SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc->rts_stbc) ? 1 : 0)); + SET_TX_DESC_RTS_RATE(txdesc, tcb_desc->rts_rate); SET_TX_DESC_RTS_BW(txdesc, 0); - SET_TX_DESC_RTS_SC(txdesc, tcb_desc.rts_sc); + SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(txdesc, - ((tcb_desc.rts_rate <= DESC92C_RATE54M) ? - (tcb_desc.rts_use_shortpreamble ? 1 : 0) - : (tcb_desc.rts_use_shortgi ? 1 : 0))); + ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + (tcb_desc->rts_use_shortpreamble ? 1 : 0) + : (tcb_desc->rts_use_shortgi ? 1 : 0))); if (mac->bw_40) { - if (tcb_desc.packet_bw) { + if (tcb_desc->packet_bw) { SET_TX_DESC_DATA_BW(txdesc, 1); SET_TX_DESC_DATA_SC(txdesc, 3); } else { @@ -590,7 +590,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_DATA_RATE_FB_LIMIT(txdesc, 0x1F); SET_TX_DESC_RTS_RATE_FB_LIMIT(txdesc, 0xF); SET_TX_DESC_DISABLE_FB(txdesc, 0); - SET_TX_DESC_USE_RATE(txdesc, tcb_desc.use_driver_rate ? 1 : 0); + SET_TX_DESC_USE_RATE(txdesc, tcb_desc->use_driver_rate ? 1 : 0); if (ieee80211_is_data_qos(fc)) { if (mac->rdg_en) { RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, @@ -600,11 +600,11 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, } } if (rtlpriv->dm.useramask) { - SET_TX_DESC_RATE_ID(txdesc, tcb_desc.ratr_index); - SET_TX_DESC_MACID(txdesc, tcb_desc.mac_id); + SET_TX_DESC_RATE_ID(txdesc, tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->mac_id); } else { - SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc.ratr_index); - SET_TX_DESC_MACID(txdesc, tcb_desc.ratr_index); + SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc->ratr_index); + SET_TX_DESC_MACID(txdesc, tcb_desc->ratr_index); } if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps && ppsc->fwctrl_lps) { @@ -656,7 +656,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; - memset(pdesc, 0, RTL_TX_HEADER_SIZE); + memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); if (firstseg) SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h index b396d46..53de5f6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h @@ -37,6 +37,8 @@ #define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */ #define RX_DRV_INFO_SIZE_UNIT 8 +#define RTL_AGG_ON 1 + enum usb_rx_agg_mode { USB_RX_AGG_DISABLE, USB_RX_AGG_DMA, @@ -419,7 +421,8 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *, void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, struct sk_buff *skb, - unsigned int queue_index); + u8 queue_index, + struct rtl_tcb_desc *tcb_desc); void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, u32 buffer_len, bool bIsPsPoll); void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index f5d8573..a9367eb 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -852,6 +852,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rtl_tx_desc *pdesc = NULL; + struct rtl_tcb_desc tcb_desc; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); __le16 fc = hdr->frame_control; u8 *pda_addr = hdr->addr1; @@ -860,8 +861,17 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, u8 tid = 0; u16 seq_number = 0; - if (ieee80211_is_mgmt(fc)) - rtl_tx_mgmt_proc(hw, skb); + if (ieee80211_is_auth(fc)) { + RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n")); + rtl_ips_nic_on(hw); + } + + if (rtlpriv->psc.sw_ps_enabled) { + if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) && + !ieee80211_has_pm(fc)) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + } + rtl_action_proc(hw, skb, true); if (is_multicast_ether_addr(pda_addr)) rtlpriv->stats.txbytesmulticast += skb->len; @@ -878,7 +888,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, seq_number <<= 4; } rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb, - hw_queue); + hw_queue, &tcb_desc); if (!ieee80211_has_morefrags(hdr->frame_control)) { if (qc) mac->tids[tid].seq_number = seq_number; @@ -887,7 +897,8 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb, rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX); } -static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *dummy) { struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h index abadfe9..d2a63fb 100644 --- a/drivers/net/wireless/rtlwifi/usb.h +++ b/drivers/net/wireless/rtlwifi/usb.h @@ -31,6 +31,8 @@ #include <linux/usb.h> #include <linux/skbuff.h> +#define RTL_RX_DESC_SIZE 24 + #define RTL_USB_DEVICE(vend, prod, cfg) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ .idVendor = (vend), \ diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 2713efe..693395e 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -68,6 +68,8 @@ #define QBSS_LOAD_SIZE 5 #define MAX_WMMELE_LENGTH 64 +#define TOTAL_CAM_ENTRY 32 + /*slot time for 11g. */ #define RTL_SLOT_TIME_9 9 #define RTL_SLOT_TIME_20 20 @@ -94,8 +96,10 @@ #define CHANNEL_GROUP_MAX_5G 9 #define CHANNEL_MAX_NUMBER_2G 14 #define AVG_THERMAL_NUM 8 +#define MAX_TID_COUNT 9 /* for early mode */ +#define FCS_LEN 4 #define EM_HDR_LEN 8 enum intf_type { INTF_PCI = 0, @@ -159,6 +163,8 @@ enum hardware_type { (IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal)) #define IS_HARDWARE_TYPE_8723(rtlhal) \ (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal)) +#define IS_HARDWARE_TYPE_8723U(rtlhal) \ + (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, @@ -297,6 +303,9 @@ enum hw_variables { HW_VAR_DATA_FILTER, }; +#define HWSET_MAX_SIZE 128 +#define EFUSE_MAX_SECTION 16 + enum _RT_MEDIA_STATUS { RT_MEDIA_DISCONNECT = 0, RT_MEDIA_CONNECT = 1 @@ -843,6 +852,7 @@ struct rtl_phy { bool apk_done; u32 reg_rf3c[2]; /* pathA / pathB */ + /* bfsync */ u8 framesync; u32 framesync_c34; @@ -852,6 +862,10 @@ struct rtl_phy { }; #define MAX_TID_COUNT 9 +#define RTL_AGG_STOP 0 +#define RTL_AGG_PROGRESS 1 +#define RTL_AGG_START 2 +#define RTL_AGG_OPERATIONAL 3 #define RTL_AGG_OFF 0 #define RTL_AGG_ON 1 #define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2 @@ -871,6 +885,13 @@ struct rtl_tid_data { struct rtl_ht_agg agg; }; +struct rtl_sta_info { + u8 ratr_index; + u8 wireless_mode; + u8 mimo_ps; + struct rtl_tid_data tids[MAX_TID_COUNT]; +} __packed; + struct rtl_priv; struct rtl_io { struct device *dev; @@ -894,6 +915,7 @@ struct rtl_io { u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len, u8 *pdata); + }; struct rtl_mac { @@ -916,6 +938,8 @@ struct rtl_mac { int n_channels; int n_bitrates; + bool offchan_deley; + /*filters */ u32 rx_conf; u16 rx_mgt_filter; @@ -1032,7 +1056,9 @@ struct rtl_security { enum rt_enc_alg pairwise_enc_algorithm; /*Encryption Algorithm for Brocast/Multicast */ enum rt_enc_alg group_enc_algorithm; - + /*Cam Entry Bitmap */ + u32 hwsec_cam_bitmap; + u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN]; /*local Key buffer, indx 0 is for pairwise key 1-4 is for agoup key. */ u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN]; @@ -1053,7 +1079,7 @@ struct rtl_dm { bool current_turbo_edca; bool is_any_nonbepkts; /*out dm */ bool is_cur_rdlstate; - bool txpower_trackingInit; + bool txpower_trackinginit; bool disable_framebursting; bool cck_inch14; bool txpower_tracking; @@ -1079,7 +1105,6 @@ struct rtl_dm { bool disable_tx_int; char ofdm_index[2]; char cck_index; - u8 power_index_backup[6]; }; #define EFUSE_MAX_LOGICAL_SIZE 256 @@ -1175,6 +1200,7 @@ struct rtl_ps_ctl { * otherwise Offset[560h] = 0x00. * */ bool support_aspm; + bool support_backdoor; /*for LPS */ @@ -1201,7 +1227,6 @@ struct rtl_ps_ctl { /*just for PCIE ASPM */ u8 const_amdpci_aspm; - bool pwrdown_mode; enum rf_pwrstate inactive_pwrstate; @@ -1282,6 +1307,10 @@ struct rt_link_detect { bool busytraffic; bool higher_busytraffic; bool higher_busyrxtraffic; + + u32 tidtx_in4period[MAX_TID_COUNT][4]; + u32 tidtx_inperiod[MAX_TID_COUNT]; + bool higher_busytxtraffic[MAX_TID_COUNT]; }; struct rtl_tcb_desc { @@ -1344,13 +1373,15 @@ struct rtl_hal_ops { u32 add_msr, u32 rm_msr); void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val); - void (*update_rate_table) (struct ieee80211_hw *hw); + void (*update_rate_tbl) (struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 rssi_level); void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level); void (*fill_tx_desc) (struct ieee80211_hw *hw, struct ieee80211_hdr *hdr, u8 *pdesc_tx, struct ieee80211_tx_info *info, - struct sk_buff *skb, unsigned int queue_index); - void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 * pDesc, + struct sk_buff *skb, u8 hw_queue, + struct rtl_tcb_desc *ptcb_desc); + void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc, u32 buffer_len, bool bIsPsPoll); void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc, bool firstseg, bool lastseg, @@ -1370,10 +1401,10 @@ struct rtl_hal_ops { enum led_ctl_mode ledaction); void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val); u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name); - void (*tx_polling) (struct ieee80211_hw *hw, unsigned int hw_queue); + void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue); void (*enable_hw_sec) (struct ieee80211_hw *hw); void (*set_key) (struct ieee80211_hw *hw, u32 key_index, - u8 *p_macaddr, bool is_group, u8 enc_algo, + u8 *macaddr, bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all); void (*init_sw_leds) (struct ieee80211_hw *hw); void (*deinit_sw_leds) (struct ieee80211_hw *hw); @@ -1384,6 +1415,7 @@ struct rtl_hal_ops { u32 regaddr, u32 bitmask); void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath, u32 regaddr, u32 bitmask, u32 data); + void (*linked_set_reg) (struct ieee80211_hw *hw); bool (*phy_rf6052_config) (struct ieee80211_hw *hw); void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw, u8 *powerlevel); @@ -1404,7 +1436,9 @@ struct rtl_intf_ops { int (*adapter_start) (struct ieee80211_hw *hw); void (*adapter_stop) (struct ieee80211_hw *hw); - int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb); + int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb, + struct rtl_tcb_desc *ptcb_desc); + void (*flush)(struct ieee80211_hw *hw, bool drop); int (*reset_trx_ring) (struct ieee80211_hw *hw); bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1418,6 +1452,15 @@ struct rtl_intf_ops { struct rtl_mod_params { /* default: 0 = using hardware encryption */ int sw_crypto; + + /* default: 1 = using no linked power save */ + bool inactiveps; + + /* default: 1 = using linked sw power save */ + bool swctrl_lps; + + /* default: 1 = using linked fw power save */ + bool fwctrl_lps; }; struct rtl_hal_usbint_cfg { @@ -1445,6 +1488,7 @@ struct rtl_hal_usbint_cfg { struct rtl_hal_cfg { u8 bar_id; + bool write_readback; char *name; char *fw_name; struct rtl_hal_ops *ops; @@ -1469,7 +1513,6 @@ struct rtl_locks { spinlock_t rf_lock; spinlock_t lps_lock; spinlock_t waitq_lock; - spinlock_t tx_urb_lock; /*Dual mac*/ spinlock_t cck_and_rw_pagea_lock; @@ -1653,13 +1696,23 @@ struct bt_coexist_info { #define EF4BYTE(_val) \ (le32_to_cpu(_val)) +/* Read data from memory */ +#define READEF1BYTE(_ptr) \ + EF1BYTE(*((u8 *)(_ptr))) /* Read le16 data from memory and convert to host ordering */ #define READEF2BYTE(_ptr) \ EF2BYTE(*((u16 *)(_ptr))) +#define READEF4BYTE(_ptr) \ + EF4BYTE(*((u32 *)(_ptr))) +/* Write data to memory */ +#define WRITEEF1BYTE(_ptr, _val) \ + (*((u8 *)(_ptr))) = EF1BYTE(_val) /* Write le16 data to memory in host ordering */ #define WRITEEF2BYTE(_ptr, _val) \ (*((u16 *)(_ptr))) = EF2BYTE(_val) +#define WRITEEF4BYTE(_ptr, _val) \ + (*((u16 *)(_ptr))) = EF2BYTE(_val) /* Create a bit mask * Examples: @@ -1698,6 +1751,25 @@ struct bt_coexist_info { #define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ (EF1BYTE(*((u8 *)(__pstart)))) +/*Description: +Translate subfield (continuous bits in little-endian) of 4-byte +value to host byte ordering.*/ +#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_32(__bitlen) \ + ) +#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_16(__bitlen) \ + ) +#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ + ( \ + (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ + BIT_LEN_MASK_8(__bitlen) \ + ) + /* Description: * Mask subfield (continuous bits in little-endian) of 4-byte value * and return the result in 4-byte value in host byte ordering. @@ -1721,6 +1793,18 @@ struct bt_coexist_info { /* Description: * Set subfield of little-endian 4-byte value to specified value. */ +#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u32 *)(__pstart)) = EF4BYTE \ + ( \ + LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \ + ); +#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \ + *((u16 *)(__pstart)) = EF2BYTE \ + ( \ + LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \ + ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \ + ); #define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \ *((u8 *)(__pstart)) = EF1BYTE \ ( \ @@ -1728,12 +1812,16 @@ struct bt_coexist_info { ((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \ ); +#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ + (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) + /**************************************** mem access macro define end ****************************************/ #define byte(x, n) ((x >> (8 * n)) & 0xff) +#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC) #define RTL_WATCH_DOG_TIME 2000 #define MSECS(t) msecs_to_jiffies(t) #define WLAN_FC_GET_VERS(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_VERS) @@ -1768,6 +1856,15 @@ struct bt_coexist_info { #define container_of_dwork_rtl(x, y, z) \ container_of(container_of(x, struct delayed_work, work), y, z) +#define FILL_OCTET_STRING(_os, _octet, _len) \ + (_os).octet = (u8 *)(_octet); \ + (_os).length = (_len); + +#define CP_MACADDR(des, src) \ + ((des)[0] = (src)[0], (des)[1] = (src)[1],\ + (des)[2] = (src)[2], (des)[3] = (src)[3],\ + (des)[4] = (src)[4], (des)[5] = (src)[5]) + static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) { return rtlpriv->io.read8_sync(rtlpriv, addr); @@ -1786,17 +1883,26 @@ static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) { rtlpriv->io.write8_async(rtlpriv, addr, val8); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read8_sync(rtlpriv, addr); } static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) { rtlpriv->io.write16_async(rtlpriv, addr, val16); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read16_sync(rtlpriv, addr); } static inline void rtl_write_dword(struct rtl_priv *rtlpriv, u32 addr, u32 val32) { rtlpriv->io.write32_async(rtlpriv, addr, val32); + + if (rtlpriv->cfg->write_readback) + rtlpriv->io.read32_sync(rtlpriv, addr); } static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, @@ -1855,4 +1961,31 @@ static inline u8 get_rf_type(struct rtl_phy *rtlphy) return rtlphy->rf_type; } +static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb) +{ + return (struct ieee80211_hdr *)(skb->data); +} + +static inline __le16 rtl_get_fc(struct sk_buff *skb) +{ + return rtl_get_hdr(skb)->frame_control; +} + +static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr) +{ + return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK; +} + +static inline u16 rtl_get_tid(struct sk_buff *skb) +{ + return rtl_get_tid_h(rtl_get_hdr(skb)); +} + +static inline struct ieee80211_sta *get_sta(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u8 *bssid) +{ + return ieee80211_find_sta(vif, bssid); +} + #endif diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 692ebff..35ce7b0 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -3,7 +3,7 @@ menuconfig WL12XX_MENU depends on MAC80211 && EXPERIMENTAL ---help--- This will enable TI wl12xx driver support for the following chips: - wl1271 and wl1273. + wl1271, wl1273, wl1281 and wl1283. The drivers make use of the mac80211 stack. config WL12XX diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index a3db755..a5c9c0a 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -965,10 +965,13 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) } /* memory config */ - mem_conf->num_stations = wl->conf.mem.num_stations; - mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; - mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; - mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; + /* FIXME: for now we always use mem_wl127x for AP, because it + * doesn't support dynamic memory and we don't have the + * optimal values for wl128x without dynamic memory yet */ + mem_conf->num_stations = wl->conf.mem_wl127x.num_stations; + mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num; + mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num; + mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles; mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, @@ -986,6 +989,7 @@ out: int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) { struct wl1271_acx_sta_config_memory *mem_conf; + struct conf_memory_settings *mem; int ret; wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); @@ -996,16 +1000,21 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) goto out; } + if (wl->chip.id == CHIP_ID_1283_PG20) + mem = &wl->conf.mem_wl128x; + else + mem = &wl->conf.mem_wl127x; + /* memory config */ - mem_conf->num_stations = wl->conf.mem.num_stations; - mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num; - mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num; - mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles; + mem_conf->num_stations = mem->num_stations; + mem_conf->rx_mem_block_num = mem->rx_block_num; + mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; + mem_conf->num_ssid_profiles = mem->ssid_profiles; mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); - mem_conf->dyn_mem_enable = wl->conf.mem.dynamic_memory; - mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks; - mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks; - mem_conf->tx_min = wl->conf.mem.tx_min; + mem_conf->dyn_mem_enable = mem->dynamic_memory; + mem_conf->tx_free_req = mem->min_req_tx_blocks; + mem_conf->rx_free_req = mem->min_req_rx_blocks; + mem_conf->tx_min = mem->tx_min; ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, sizeof(*mem_conf)); @@ -1019,6 +1028,32 @@ out: return ret; } +int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap) +{ + struct wl1271_acx_host_config_bitmap *bitmap_conf; + int ret; + + bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL); + if (!bitmap_conf) { + ret = -ENOMEM; + goto out; + } + + bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap); + + ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP, + bitmap_conf, sizeof(*bitmap_conf)); + if (ret < 0) { + wl1271_warning("wl1271 bitmap config opt failed: %d", ret); + goto out; + } + +out: + kfree(bitmap_conf); + + return ret; +} + int wl1271_acx_init_mem_config(struct wl1271 *wl) { int ret; @@ -1489,22 +1524,46 @@ out: return ret; } -int wl1271_acx_max_tx_retry(struct wl1271 *wl) +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) { - struct wl1271_acx_max_tx_retry *acx = NULL; + struct wl1271_acx_ap_max_tx_retry *acx = NULL; int ret; - wl1271_debug(DEBUG_ACX, "acx max tx retry"); + wl1271_debug(DEBUG_ACX, "acx ap max tx retry"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) return -ENOMEM; - acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries); + acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); if (ret < 0) { - wl1271_warning("acx max tx retry failed: %d", ret); + wl1271_warning("acx ap max tx retry failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl) +{ + struct wl1271_acx_sta_max_tx_retry *acx = NULL; + int ret; + + wl1271_debug(DEBUG_ACX, "acx sta max tx retry"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->max_tx_retry = wl->conf.tx.max_tx_retries; + + ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx sta max tx retry failed: %d", ret); goto out; } diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index dd19b01..942908c 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -939,6 +939,16 @@ struct wl1271_acx_keep_alive_config { u8 padding; } __packed; +#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) +#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1) +#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3) + +struct wl1271_acx_host_config_bitmap { + struct acx_header header; + + __le32 host_cfg_bitmap; +} __packed; + enum { WL1271_ACX_TRIG_TYPE_LEVEL = 0, WL1271_ACX_TRIG_TYPE_EDGE, @@ -1135,7 +1145,7 @@ struct wl1271_acx_fw_tsf_information { u8 padding[3]; } __packed; -struct wl1271_acx_max_tx_retry { +struct wl1271_acx_ap_max_tx_retry { struct acx_header header; /* @@ -1146,6 +1156,13 @@ struct wl1271_acx_max_tx_retry { u8 padding_1[2]; } __packed; +struct wl1271_acx_sta_max_tx_retry { + struct acx_header header; + + u8 max_tx_retry; + u8 padding_1[3]; +} __packed; + struct wl1271_acx_config_ps { struct acx_header header; @@ -1275,6 +1292,7 @@ int wl1271_acx_tx_config_options(struct wl1271 *wl); int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); int wl1271_acx_sta_mem_cfg(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl); +int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); int wl1271_acx_smart_reflex(struct wl1271 *wl); int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); @@ -1296,7 +1314,8 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl, int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, bool enable); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); -int wl1271_acx_max_tx_retry(struct wl1271 *wl); +int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); +int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 6934dffd..d263ebb 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -22,6 +22,7 @@ */ #include <linux/slab.h> +#include <linux/wl12xx.h> #include "acx.h" #include "reg.h" @@ -243,33 +244,57 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) if (wl->nvs == NULL) return -ENODEV; - /* - * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band - * configurations) can be removed when those NVS files stop floating - * around. - */ - if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || - wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { - /* for now 11a is unsupported in AP mode */ - if (wl->bss_type != BSS_TYPE_AP_BSS && - wl->nvs->general_params.dual_mode_select) - wl->enable_11a = true; - } + if (wl->chip.id == CHIP_ID_1283_PG20) { + struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; + + if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) { + if (nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } else { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, + sizeof(struct wl128x_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } - if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && - (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || - wl->enable_11a)) { - wl1271_error("nvs size is not as expected: %zu != %zu", - wl->nvs_len, sizeof(struct wl1271_nvs_file)); - kfree(wl->nvs); - wl->nvs = NULL; - wl->nvs_len = 0; - return -EILSEQ; - } + /* only the first part of the NVS needs to be uploaded */ + nvs_len = sizeof(nvs->nvs); + nvs_ptr = (u8 *)nvs->nvs; + + } else { + struct wl1271_nvs_file *nvs = + (struct wl1271_nvs_file *)wl->nvs; + /* + * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz + * band configurations) can be removed when those NVS files stop + * floating around. + */ + if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || + wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { + /* for now 11a is unsupported in AP mode */ + if (wl->bss_type != BSS_TYPE_AP_BSS && + nvs->general_params.dual_mode_select) + wl->enable_11a = true; + } - /* only the first part of the NVS needs to be uploaded */ - nvs_len = sizeof(wl->nvs->nvs); - nvs_ptr = (u8 *)wl->nvs->nvs; + if (wl->nvs_len != sizeof(struct wl1271_nvs_file) && + (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE || + wl->enable_11a)) { + wl1271_error("nvs size is not as expected: %zu != %zu", + wl->nvs_len, sizeof(struct wl1271_nvs_file)); + kfree(wl->nvs); + wl->nvs = NULL; + wl->nvs_len = 0; + return -EILSEQ; + } + + /* only the first part of the NVS needs to be uploaded */ + nvs_len = sizeof(nvs->nvs); + nvs_ptr = (u8 *) nvs->nvs; + } /* update current MAC address to NVS */ nvs_ptr[11] = wl->mac_addr[0]; @@ -319,10 +344,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) /* * We've reached the first zero length, the first NVS table * is located at an aligned offset which is at least 7 bytes further. + * NOTE: The wl->nvs->nvs element must be first, in order to + * simplify the casting, we assume it is at the beginning of + * the wl->nvs structure. */ - nvs_ptr = (u8 *)wl->nvs->nvs + - ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4); - nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs; + nvs_ptr = (u8 *)wl->nvs + + ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); + nvs_len -= nvs_ptr - (u8 *)wl->nvs; /* Now we must set the partition correctly */ wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -450,10 +478,14 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | - SOFT_GEMINI_SENSE_EVENT_ID; + SOFT_GEMINI_SENSE_EVENT_ID | + MAX_TX_RETRY_EVENT_ID; if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID; + wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID | + INACTIVE_STA_EVENT_ID; + else + wl->event_mask |= DUMMY_PACKET_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { @@ -493,24 +525,159 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; } -/* uploads NVS and firmware */ -int wl1271_load_firmware(struct wl1271 *wl) +static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) { - int ret = 0; - u32 tmp, clk, pause; + u16 spare_reg; + + /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ + spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); + if (spare_reg == 0xFFFF) + return -EFAULT; + spare_reg |= (BIT(3) | BIT(5) | BIT(6)); + wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); + + /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ + wl1271_top_reg_write(wl, SYS_CLK_CFG_REG, + WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); + + /* Delay execution for 15msec, to let the HW settle */ + mdelay(15); + + return 0; +} + +static bool wl128x_is_tcxo_valid(struct wl1271 *wl) +{ + u16 tcxo_detection; + + tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG); + if (tcxo_detection & TCXO_DET_FAILED) + return false; + + return true; +} + +static bool wl128x_is_fref_valid(struct wl1271 *wl) +{ + u16 fref_detection; + + fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG); + if (fref_detection & FREF_CLK_DETECT_FAIL) + return false; + + return true; +} + +static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) +{ + wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); + wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); + wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); + + return 0; +} + +static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) +{ + u16 spare_reg; + u16 pll_config; + u8 input_freq; + + /* Mask bits [3:1] in the sys_clk_cfg register */ + spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG); + if (spare_reg == 0xFFFF) + return -EFAULT; + spare_reg |= BIT(2); + wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg); + + /* Handle special cases of the TCXO clock */ + if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || + wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6) + return wl128x_manually_configure_mcs_pll(wl); + + /* Set the input frequency according to the selected clock source */ + input_freq = (clk & 1) + 1; + + pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG); + if (pll_config == 0xFFFF) + return -EFAULT; + pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); + pll_config |= MCS_PLL_ENABLE_HP; + wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); + + return 0; +} + +/* + * WL128x has two clocks input - TCXO and FREF. + * TCXO is the main clock of the device, while FREF is used to sync + * between the GPS and the cellular modem. + * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used + * as the WLAN/BT main clock. + */ +static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) +{ + u16 sys_clk_cfg; + + /* For XTAL-only modes, FREF will be used after switching from TCXO */ + if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL || + wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) { + if (!wl128x_switch_tcxo_to_fref(wl)) + return -EINVAL; + goto fref_clk; + } + + /* Query the HW, to determine which clock source we should use */ + sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG); + if (sys_clk_cfg == 0xFFFF) + return -EINVAL; + if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) + goto fref_clk; + + /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */ + if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 || + wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) { + if (!wl128x_switch_tcxo_to_fref(wl)) + return -EINVAL; + goto fref_clk; + } + + /* TCXO clock is selected */ + if (!wl128x_is_tcxo_valid(wl)) + return -EINVAL; + *selected_clock = wl->tcxo_clock; + goto config_mcs_pll; + +fref_clk: + /* FREF clock is selected */ + if (!wl128x_is_fref_valid(wl)) + return -EINVAL; + *selected_clock = wl->ref_clock; + +config_mcs_pll: + return wl128x_configure_mcs_pll(wl, *selected_clock); +} + +static int wl127x_boot_clk(struct wl1271 *wl) +{ + u32 pause; + u32 clk; wl1271_boot_hw_version(wl); - if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4) + if (wl->ref_clock == CONF_REF_CLK_19_2_E || + wl->ref_clock == CONF_REF_CLK_38_4_E || + wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL) /* ref clk: 19.2/38.4/38.4-XTAL */ clk = 0x3; - else if (wl->ref_clock == 1 || wl->ref_clock == 3) + else if (wl->ref_clock == CONF_REF_CLK_26_E || + wl->ref_clock == CONF_REF_CLK_52_E) /* ref clk: 26/52 */ clk = 0x5; else return -EINVAL; - if (wl->ref_clock != 0) { + if (wl->ref_clock != CONF_REF_CLK_19_2_E) { u16 val; /* Set clock type (open drain) */ val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE); @@ -540,6 +707,26 @@ int wl1271_load_firmware(struct wl1271 *wl) pause |= WU_COUNTER_PAUSE_VAL; wl1271_write32(wl, WU_COUNTER_PAUSE, pause); + return 0; +} + +/* uploads NVS and firmware */ +int wl1271_load_firmware(struct wl1271 *wl) +{ + int ret = 0; + u32 tmp, clk; + int selected_clock = -1; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + ret = wl128x_boot_clk(wl, &selected_clock); + if (ret < 0) + goto out; + } else { + ret = wl127x_boot_clk(wl); + if (ret < 0) + goto out; + } + /* Continue the ELP wake up sequence */ wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); udelay(500); @@ -555,7 +742,12 @@ int wl1271_load_firmware(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); - clk |= (wl->ref_clock << 1) << 4; + if (wl->chip.id == CHIP_ID_1283_PG20) { + clk |= ((selected_clock & 0x3) << 1) << 4; + } else { + clk |= (wl->ref_clock << 1) << 4; + } + wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -585,16 +777,12 @@ int wl1271_load_firmware(struct wl1271 *wl) /* 6. read the EEPROM parameters */ tmp = wl1271_read32(wl, SCR_PAD2); - ret = wl1271_boot_write_irq_polarity(wl); - if (ret < 0) - goto out; - - wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, - WL1271_ACX_ALL_EVENTS_VECTOR); - /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ + if (wl->chip.id == CHIP_ID_1283_PG20) + wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds); + ret = wl1271_boot_upload_firmware(wl); if (ret < 0) goto out; @@ -618,6 +806,13 @@ int wl1271_boot(struct wl1271 *wl) if (ret < 0) goto out; + ret = wl1271_boot_write_irq_polarity(wl); + if (ret < 0) + goto out; + + wl1271_write32(wl, ACX_REG_INTERRUPT_MASK, + WL1271_ACX_ALL_EVENTS_VECTOR); + /* Enable firmware interrupts now */ wl1271_boot_enable_interrupts(wl); diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index 17229b8..e8f8255 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -74,4 +74,56 @@ struct wl1271_static_data { #define FREF_CLK_POLARITY_BITS 0xfffff8ff #define CLK_REQ_OUTN_SEL 0x700 +/* PLL configuration algorithm for wl128x */ +#define SYS_CLK_CFG_REG 0x2200 +/* Bit[0] - 0-TCXO, 1-FREF */ +#define MCS_PLL_CLK_SEL_FREF BIT(0) +/* Bit[3:2] - 01-TCXO, 10-FREF */ +#define WL_CLK_REQ_TYPE_FREF BIT(3) +#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2)) +/* Bit[4] - 0-TCXO, 1-FREF */ +#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4) + +#define TCXO_ILOAD_INT_REG 0x2264 +#define TCXO_CLK_DETECT_REG 0x2266 + +#define TCXO_DET_FAILED BIT(4) + +#define FREF_ILOAD_INT_REG 0x2084 +#define FREF_CLK_DETECT_REG 0x2086 +#define FREF_CLK_DETECT_FAIL BIT(4) + +/* Use this reg for masking during driver access */ +#define WL_SPARE_REG 0x2320 +#define WL_SPARE_VAL BIT(2) +/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */ +#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3)) + +#define PLL_LOCK_COUNTERS_REG 0xD8C +#define PLL_LOCK_COUNTERS_COEX 0x0F +#define PLL_LOCK_COUNTERS_MCS 0xF0 +#define MCS_PLL_OVERRIDE_REG 0xD90 +#define MCS_PLL_CONFIG_REG 0xD92 +#define MCS_SEL_IN_FREQ_MASK 0x0070 +#define MCS_SEL_IN_FREQ_SHIFT 4 +#define MCS_PLL_CONFIG_REG_VAL 0x73 +#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1)) + +#define MCS_PLL_M_REG 0xD94 +#define MCS_PLL_N_REG 0xD96 +#define MCS_PLL_M_REG_VAL 0xC8 +#define MCS_PLL_N_REG_VAL 0x07 + +#define SDIO_IO_DS 0xd14 + +/* SDIO/wSPI DS configuration values */ +enum { + HCI_IO_DS_8MA = 0, + HCI_IO_DS_4MA = 1, /* default */ + HCI_IO_DS_6MA = 2, + HCI_IO_DS_2MA = 3, +}; + +/* end PLL configuration algorithm for wl128x */ + #endif diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 9632433..69d24f3 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -110,7 +110,47 @@ out: int wl1271_cmd_general_parms(struct wl1271 *wl) { struct wl1271_general_parms_cmd *gen_parms; - struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + struct wl1271_ini_general_params *gp = + &((struct wl1271_nvs_file *)wl->nvs)->general_params; + bool answer = false; + int ret; + + if (!wl->nvs) + return -ENODEV; + + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); + if (!gen_parms) + return -ENOMEM; + + gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM; + + memcpy(&gen_parms->general_params, gp, sizeof(*gp)); + + if (gp->tx_bip_fem_auto_detect) + answer = true; + + ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); + if (ret < 0) { + wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); + goto out; + } + + gp->tx_bip_fem_manufacturer = + gen_parms->general_params.tx_bip_fem_manufacturer; + + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", + answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + +out: + kfree(gen_parms); + return ret; +} + +int wl128x_cmd_general_parms(struct wl1271 *wl) +{ + struct wl128x_general_parms_cmd *gen_parms; + struct wl128x_ini_general_params *gp = + &((struct wl128x_nvs_file *)wl->nvs)->general_params; bool answer = false; int ret; @@ -147,8 +187,9 @@ out: int wl1271_cmd_radio_parms(struct wl1271 *wl) { + struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; struct wl1271_radio_parms_cmd *radio_parms; - struct wl1271_ini_general_params *gp = &wl->nvs->general_params; + struct wl1271_ini_general_params *gp = &nvs->general_params; int ret; if (!wl->nvs) @@ -161,18 +202,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; /* 2.4GHz parameters */ - memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2, + memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl1271_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, - &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_2)); /* 5GHz parameters */ memcpy(&radio_parms->static_params_5, - &wl->nvs->stat_radio_params_5, + &nvs->stat_radio_params_5, sizeof(struct wl1271_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, - &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, sizeof(struct wl1271_ini_fem_params_5)); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", @@ -186,6 +227,50 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) return ret; } +int wl128x_cmd_radio_parms(struct wl1271 *wl) +{ + struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; + struct wl128x_radio_parms_cmd *radio_parms; + struct wl128x_ini_general_params *gp = &nvs->general_params; + int ret; + + if (!wl->nvs) + return -ENODEV; + + radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL); + if (!radio_parms) + return -ENOMEM; + + radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + + /* 2.4GHz parameters */ + memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, + sizeof(struct wl128x_ini_band_params_2)); + memcpy(&radio_parms->dyn_params_2, + &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl128x_ini_fem_params_2)); + + /* 5GHz parameters */ + memcpy(&radio_parms->static_params_5, + &nvs->stat_radio_params_5, + sizeof(struct wl128x_ini_band_params_5)); + memcpy(&radio_parms->dyn_params_5, + &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + sizeof(struct wl128x_ini_fem_params_5)); + + radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; + + wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", + radio_parms, sizeof(*radio_parms)); + + ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0); + if (ret < 0) + wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed"); + + kfree(radio_parms); + return ret; +} + int wl1271_cmd_ext_radio_parms(struct wl1271 *wl) { struct wl1271_ext_radio_parms_cmd *ext_radio_parms; @@ -985,7 +1070,7 @@ int wl1271_cmd_start_bss(struct wl1271 *wl) memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); - cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC); + cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); cmd->bss_index = WL1271_AP_BSS_INDEX; cmd->global_hlid = WL1271_AP_GLOBAL_HLID; cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 54c12e7..5cac95d 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -32,7 +32,9 @@ struct acx_header; int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, size_t res_len); int wl1271_cmd_general_parms(struct wl1271 *wl); +int wl128x_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); +int wl128x_cmd_radio_parms(struct wl1271 *wl); int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); @@ -415,6 +417,21 @@ struct wl1271_general_parms_cmd { u8 padding[3]; } __packed; +struct wl128x_general_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + struct wl128x_ini_general_params general_params; + + u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 sr_sen_n_p; + u8 sr_sen_n_p_gain; + u8 sr_sen_nrn; + u8 sr_sen_prn; + u8 padding[3]; +} __packed; + struct wl1271_radio_parms_cmd { struct wl1271_cmd_header header; @@ -431,6 +448,23 @@ struct wl1271_radio_parms_cmd { u8 padding3[2]; } __packed; +struct wl128x_radio_parms_cmd { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + /* Static radio parameters */ + struct wl128x_ini_band_params_2 static_params_2; + struct wl128x_ini_band_params_5 static_params_5; + + u8 fem_vendor_and_options; + + /* Dynamic radio parameters */ + struct wl128x_ini_fem_params_2 dyn_params_2; + u8 padding2; + struct wl128x_ini_fem_params_5 dyn_params_5; +} __packed; + struct wl1271_ext_radio_parms_cmd { struct wl1271_cmd_header header; diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 8a83238..e3de915 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -683,10 +683,18 @@ struct conf_tx_settings { struct conf_tx_rate_class ap_bcst_conf; /* - * AP-mode - allow this number of TX retries to a station before an + * Allow this number of TX retries to a connected station/AP before an * event is triggered from FW. + * In AP-mode the hlids of unreachable stations are given in the + * "sta_tx_retry_exceeded" member in the event mailbox. */ - u16 ap_max_tx_retries; + u8 max_tx_retries; + + /* + * AP-mode - after this number of seconds a connected station is + * considered inactive. + */ + u16 ap_aging_period; /* * Configuration for TID parameters. @@ -1004,7 +1012,9 @@ enum { CONF_REF_CLK_19_2_E, CONF_REF_CLK_26_E, CONF_REF_CLK_38_4_E, - CONF_REF_CLK_52_E + CONF_REF_CLK_52_E, + CONF_REF_CLK_38_4_M_XTAL, + CONF_REF_CLK_26_M_XTAL, }; enum single_dual_band_enum { @@ -1018,15 +1028,6 @@ enum single_dual_band_enum { #define CONF_NUMBER_OF_CHANNELS_2_4 14 #define CONF_NUMBER_OF_CHANNELS_5 35 -struct conf_radio_parms { - /* - * FEM parameter set to use - * - * Range: 0 or 1 - */ - u8 fem; -}; - struct conf_itrim_settings { /* enable dco itrim */ u8 enable; @@ -1202,7 +1203,9 @@ struct conf_drv_settings { struct conf_scan_settings scan; struct conf_rf_settings rf; struct conf_ht_setting ht; - struct conf_memory_settings mem; + struct conf_memory_settings mem_wl127x; + struct conf_memory_settings mem_wl128x; + u8 hci_io_ds; }; #endif diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 8e75b09..70ab198 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -267,7 +267,7 @@ static ssize_t gpio_power_write(struct file *file, } buf[len] = '\0'; - ret = strict_strtoul(buf, 0, &value); + ret = kstrtoul(buf, 0, &value); if (ret < 0) { wl1271_warning("illegal value in gpio_power"); return -EINVAL; diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 1b170c5..d7be3ae 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -33,6 +33,7 @@ void wl1271_pspoll_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, pspoll_work); @@ -55,8 +56,13 @@ void wl1271_pspoll_work(struct work_struct *work) * delivery failure occurred, and no-one changed state since, so * we should go back to powersave. */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true); + wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); }; @@ -129,11 +135,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, /* enable beacon early termination */ ret = wl1271_acx_bet_enable(wl, true); - if (ret < 0) - break; - - /* go to extremely low power mode */ - wl1271_ps_elp_sleep(wl); break; default: break; @@ -173,6 +174,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) u32 vector; bool beacon_loss = false; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); + bool disconnect_sta = false; + unsigned long sta_bitmap = 0; wl1271_event_mbox_dump(mbox); @@ -228,9 +231,60 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_rssi_trigger(wl, mbox); } + if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { + wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); + if (wl->vif) + wl1271_tx_dummy_packet(wl); + } + + /* + * "TX retries exceeded" has a different meaning according to mode. + * In AP mode the offending station is disconnected. In STA mode we + * report connection loss. + */ + if (vector & MAX_TX_RETRY_EVENT_ID) { + wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID"); + if (is_ap) { + sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded); + disconnect_sta = true; + } else { + beacon_loss = true; + } + } + + if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) { + wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID"); + sta_bitmap |= le16_to_cpu(mbox->sta_aging_status); + disconnect_sta = true; + } + if (wl->vif && beacon_loss) ieee80211_connection_loss(wl->vif); + if (is_ap && disconnect_sta) { + u32 num_packets = wl->conf.tx.max_tx_retries; + struct ieee80211_sta *sta; + const u8 *addr; + int h; + + for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS); + h < AP_MAX_LINKS; + h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) { + if (!wl1271_is_active_sta(wl, h)) + continue; + + addr = wl->links[h].addr; + + rcu_read_lock(); + sta = ieee80211_find_sta(wl->vif, addr); + if (sta) { + wl1271_debug(DEBUG_EVENT, "remove sta %d", h); + ieee80211_report_low_ack(sta, num_packets); + } + rcu_read_unlock(); + } + } + return 0; } diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index 0e80886..7ae5a08 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -58,10 +58,16 @@ enum { CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), - ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20), - STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */ + MAX_TX_RETRY_EVENT_ID = BIT(20), + /* STA: dummy paket for dynamic mem blocks */ + DUMMY_PACKET_EVENT_ID = BIT(21), + /* AP: STA remove complete */ + STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), + /* STA: SG prediction */ SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), + /* AP: Inactive STA */ + INACTIVE_STA_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), DBG_EVENT_ID = BIT(26), @@ -116,7 +122,11 @@ struct event_mailbox { /* AP FW only */ u8 hlid_removed; + + /* a bitmap of hlids for stations that have been inactive too long */ __le16 sta_aging_status; + + /* a bitmap of hlids for stations which didn't respond to TX */ __le16 sta_tx_retry_exceeded; u8 reserved_5[24]; @@ -127,4 +137,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl); int wl1271_event_handle(struct wl1271 *wl, u8 mbox); void wl1271_pspoll_work(struct work_struct *work); +/* Functions from main.c */ +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid); + #endif diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h index c330a25..1420c84 100644 --- a/drivers/net/wireless/wl12xx/ini.h +++ b/drivers/net/wireless/wl12xx/ini.h @@ -41,6 +41,28 @@ struct wl1271_ini_general_params { u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; } __packed; +#define WL128X_INI_MAX_SETTINGS_PARAM 4 + +struct wl128x_ini_general_params { + u8 ref_clock; + u8 settling_time; + u8 clk_valid_on_wakeup; + u8 tcxo_ref_clock; + u8 tcxo_settling_time; + u8 tcxo_valid_on_wakeup; + u8 tcxo_ldo_voltage; + u8 xtal_itrim_val; + u8 platform_conf; + u8 dual_mode_select; + u8 tx_bip_fem_auto_detect; + u8 tx_bip_fem_manufacturer; + u8 general_settings[WL128X_INI_MAX_SETTINGS_PARAM]; + u8 sr_state; + u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM]; + u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM]; +} __packed; + #define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15 struct wl1271_ini_band_params_2 { @@ -49,9 +71,16 @@ struct wl1271_ini_band_params_2 { u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; } __packed; -#define WL1271_INI_RATE_GROUP_COUNT 6 #define WL1271_INI_CHANNEL_COUNT_2 14 +struct wl128x_ini_band_params_2 { + u8 rx_trace_insertion_loss; + u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2]; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + +#define WL1271_INI_RATE_GROUP_COUNT 6 + struct wl1271_ini_fem_params_2 { __le16 tx_bip_ref_pd_voltage; u8 tx_bip_ref_power; @@ -68,6 +97,28 @@ struct wl1271_ini_fem_params_2 { u8 normal_to_degraded_high_thr; } __packed; +#define WL128X_INI_RATE_GROUP_COUNT 7 +/* low and high temperatures */ +#define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2 + +struct wl128x_ini_fem_params_2 { + __le16 tx_bip_ref_pd_voltage; + u8 tx_bip_ref_power; + u8 tx_bip_ref_offset; + u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1]; + u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2]; + u8 tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES]; + u8 rx_fem_insertion_loss; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; + #define WL1271_INI_CHANNEL_COUNT_5 35 #define WL1271_INI_SUB_BAND_COUNT_5 7 @@ -77,6 +128,12 @@ struct wl1271_ini_band_params_5 { u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; } __packed; +struct wl128x_ini_band_params_5 { + u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_5]; + u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE]; +} __packed; + struct wl1271_ini_fem_params_5 { __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; @@ -92,6 +149,23 @@ struct wl1271_ini_fem_params_5 { u8 normal_to_degraded_high_thr; } __packed; +struct wl128x_ini_fem_params_5 { + __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5]; + u8 tx_per_rate_pwr_limits_normal[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5]; + u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT]; + u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5]; + u8 tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 * + WL128X_INI_PD_VS_TEMPERATURE_RANGES]; + u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5]; + u8 degraded_low_to_normal_thr; + u8 normal_to_degraded_high_thr; +} __packed; /* NVS data structure */ #define WL1271_INI_NVS_SECTION_SIZE 468 @@ -100,7 +174,7 @@ struct wl1271_ini_fem_params_5 { #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 struct wl1271_nvs_file { - /* NVS section */ + /* NVS section - must be first! */ u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; /* INI section */ @@ -120,4 +194,24 @@ struct wl1271_nvs_file { } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; } __packed; +struct wl128x_nvs_file { + /* NVS section - must be first! */ + u8 nvs[WL1271_INI_NVS_SECTION_SIZE]; + + /* INI section */ + struct wl128x_ini_general_params general_params; + u8 fem_vendor_and_options; + struct wl128x_ini_band_params_2 stat_radio_params_2; + u8 padding2; + struct { + struct wl128x_ini_fem_params_2 params; + u8 padding; + } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; + struct wl128x_ini_band_params_5 stat_radio_params_5; + u8 padding3; + struct { + struct wl128x_ini_fem_params_5 params; + u8 padding; + } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; +} __packed; #endif diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 6072fe4..ab3b1e2 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -31,6 +31,7 @@ #include "cmd.h" #include "reg.h" #include "tx.h" +#include "io.h" int wl1271_sta_init_templates_config(struct wl1271 *wl) { @@ -321,9 +322,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) { int ret; - ret = wl1271_cmd_ext_radio_parms(wl); - if (ret < 0) - return ret; + if (wl->chip.id != CHIP_ID_1283_PG20) { + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + } /* PS config */ ret = wl1271_acx_config_ps(wl); @@ -372,6 +375,10 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; + ret = wl1271_acx_sta_max_tx_retry(wl); + if (ret < 0) + return ret; + ret = wl1271_acx_sta_mem_cfg(wl); if (ret < 0) return ret; @@ -438,7 +445,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_max_tx_retry(wl); + ret = wl1271_acx_ap_max_tx_retry(wl); if (ret < 0) return ret; @@ -504,6 +511,27 @@ static int wl1271_set_ba_policies(struct wl1271 *wl) return ret; } +int wl1271_chip_specific_init(struct wl1271 *wl) +{ + int ret = 0; + + if (wl->chip.id == CHIP_ID_1283_PG20) { + u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; + + if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) + /* Enable SDIO padding */ + host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; + + /* Must be before wl1271_acx_init_mem_config() */ + ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); + if (ret < 0) + goto out; + } +out: + return ret; +} + + int wl1271_hw_init(struct wl1271 *wl) { struct conf_tx_ac_category *conf_ac; @@ -511,11 +539,22 @@ int wl1271_hw_init(struct wl1271 *wl) int ret, i; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); - ret = wl1271_cmd_general_parms(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_general_parms(wl); + else + ret = wl1271_cmd_general_parms(wl); + if (ret < 0) + return ret; + + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_radio_parms(wl); + else + ret = wl1271_cmd_radio_parms(wl); if (ret < 0) return ret; - ret = wl1271_cmd_radio_parms(wl); + /* Chip-specific init */ + ret = wl1271_chip_specific_init(wl); if (ret < 0) return ret; diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h index 3a8bd3f..4975270 100644 --- a/drivers/net/wireless/wl12xx/init.h +++ b/drivers/net/wireless/wl12xx/init.h @@ -31,6 +31,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl); int wl1271_init_phy_config(struct wl1271 *wl); int wl1271_init_pta(struct wl1271 *wl); int wl1271_init_energy_detection(struct wl1271 *wl); +int wl1271_chip_specific_init(struct wl1271 *wl); int wl1271_hw_init(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c index d557f73..da5c1ad 100644 --- a/drivers/net/wireless/wl12xx/io.c +++ b/drivers/net/wireless/wl12xx/io.c @@ -29,6 +29,7 @@ #include "wl12xx.h" #include "wl12xx_80211.h" #include "io.h" +#include "tx.h" #define OCP_CMD_LOOP 32 @@ -43,6 +44,16 @@ #define OCP_STATUS_REQ_FAILED 0x20000 #define OCP_STATUS_RESP_ERROR 0x30000 +bool wl1271_set_block_size(struct wl1271 *wl) +{ + if (wl->if_ops->set_block_size) { + wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE); + return true; + } + + return false; +} + void wl1271_disable_interrupts(struct wl1271 *wl) { wl->if_ops->disable_irq(wl); diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index 00c771e..beed621 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -169,5 +169,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl); struct ieee80211_hw *wl1271_alloc_hw(void); int wl1271_free_hw(struct wl1271 *wl); irqreturn_t wl1271_irq(int irq, void *data); +bool wl1271_set_block_size(struct wl1271 *wl); +int wl1271_tx_dummy_packet(struct wl1271 *wl); +void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index 8b3c8d1..0c69e95 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -30,6 +30,7 @@ #include <linux/vmalloc.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/wl12xx.h> #include "wl12xx.h" #include "wl12xx_80211.h" @@ -54,7 +55,7 @@ static struct conf_drv_settings default_conf = { [CONF_SG_BT_PER_THRESHOLD] = 7500, [CONF_SG_HV3_MAX_OVERRIDE] = 0, [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, - [CONF_SG_BT_LOAD_RATIO] = 50, + [CONF_SG_BT_LOAD_RATIO] = 200, [CONF_SG_AUTO_PS_MODE] = 1, [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, @@ -191,7 +192,8 @@ static struct conf_drv_settings default_conf = { .long_retry_limit = 10, .aflags = 0, }, - .ap_max_tx_retries = 100, + .max_tx_retries = 100, + .ap_aging_period = 300, .tid_conf_count = 4, .tid_conf = { [CONF_TX_AC_BE] = { @@ -254,7 +256,7 @@ static struct conf_drv_settings default_conf = { .ps_poll_threshold = 10, .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, - .bet_max_consecutive = 10, + .bet_max_consecutive = 50, .psm_entry_retries = 5, .psm_exit_retries = 255, .psm_entry_nullfunc_retries = 3, @@ -298,7 +300,7 @@ static struct conf_drv_settings default_conf = { .tx_ba_win_size = 64, .inactivity_timeout = 10000, }, - .mem = { + .mem_wl127x = { .num_stations = 1, .ssid_profiles = 1, .rx_block_num = 70, @@ -307,7 +309,18 @@ static struct conf_drv_settings default_conf = { .min_req_tx_blocks = 100, .min_req_rx_blocks = 22, .tx_min = 27, - } + }, + .mem_wl128x = { + .num_stations = 1, + .ssid_profiles = 1, + .rx_block_num = 40, + .tx_min_block_num = 40, + .dynamic_memory = 1, + .min_req_tx_blocks = 45, + .min_req_rx_blocks = 22, + .tx_min = 27, + }, + .hci_io_ds = HCI_IO_DS_6MA, }; static void __wl1271_op_remove_interface(struct wl1271 *wl); @@ -329,6 +342,7 @@ static struct platform_device wl1271_device = { }, }; +static DEFINE_MUTEX(wl_list_mutex); static LIST_HEAD(wl_list); static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, @@ -359,10 +373,12 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what, return NOTIFY_DONE; wl_temp = hw->priv; + mutex_lock(&wl_list_mutex); list_for_each_entry(wl, &wl_list, list) { if (wl == wl_temp) break; } + mutex_unlock(&wl_list_mutex); if (wl != wl_temp) return NOTIFY_DONE; @@ -438,15 +454,30 @@ static int wl1271_plt_init(struct wl1271 *wl) struct conf_tx_tid *conf_tid; int ret, i; - ret = wl1271_cmd_general_parms(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_general_parms(wl); + else + ret = wl1271_cmd_general_parms(wl); if (ret < 0) return ret; - ret = wl1271_cmd_radio_parms(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = wl128x_cmd_radio_parms(wl); + else + ret = wl1271_cmd_radio_parms(wl); + if (ret < 0) + return ret; + + if (wl->chip.id != CHIP_ID_1283_PG20) { + ret = wl1271_cmd_ext_radio_parms(wl); + if (ret < 0) + return ret; + } if (ret < 0) return ret; - ret = wl1271_cmd_ext_radio_parms(wl); + /* Chip-specific initializations */ + ret = wl1271_chip_specific_init(wl); if (ret < 0) return ret; @@ -593,15 +624,17 @@ static void wl1271_fw_status(struct wl1271 *wl, { struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; - u32 total = 0; + u32 old_tx_blk_count = wl->tx_blocks_available; + u32 freed_blocks = 0; int i; - if (wl->bss_type == BSS_TYPE_AP_BSS) + if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(struct wl1271_fw_ap_status), false); - else + } else { wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(struct wl1271_fw_sta_status), false); + } wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", @@ -612,22 +645,37 @@ static void wl1271_fw_status(struct wl1271 *wl, /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - u32 cnt = le32_to_cpu(status->tx_released_blks[i]) - - wl->tx_blocks_freed[i]; + freed_blocks += le32_to_cpu(status->tx_released_blks[i]) - + wl->tx_blocks_freed[i]; wl->tx_blocks_freed[i] = le32_to_cpu(status->tx_released_blks[i]); - wl->tx_blocks_available += cnt; - total += cnt; } - /* if more blocks are available now, tx work can be scheduled */ - if (total) - clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + wl->tx_allocated_blocks -= freed_blocks; - /* for AP update num of allocated TX blocks per link and ps status */ - if (wl->bss_type == BSS_TYPE_AP_BSS) + if (wl->bss_type == BSS_TYPE_AP_BSS) { + /* Update num of allocated TX blocks per link and ps status */ wl1271_irq_update_links_status(wl, &full_status->ap); + wl->tx_blocks_available += freed_blocks; + } else { + int avail = full_status->sta.tx_total - wl->tx_allocated_blocks; + + /* + * The FW might change the total number of TX memblocks before + * we get a notification about blocks being released. Thus, the + * available blocks calculation might yield a temporary result + * which is lower than the actual available blocks. Keeping in + * mind that only blocks that were allocated can be moved from + * TX to RX, tx_blocks_available should never decrease here. + */ + wl->tx_blocks_available = max((int)wl->tx_blocks_available, + avail); + } + + /* if more blocks are available now, tx work can be scheduled */ + if (wl->tx_blocks_available > old_tx_blk_count) + clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); /* update the host-chipset time offset */ getnstimeofday(&ts); @@ -674,6 +722,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie) set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); cancel_work_sync(&wl->tx_work); + /* + * In case edge triggered interrupt must be used, we cannot iterate + * more than once without introducing race conditions with the hardirq. + */ + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + loopcount = 1; + mutex_lock(&wl->mutex); wl1271_debug(DEBUG_IRQ, "IRQ work"); @@ -785,11 +840,17 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) switch (wl->bss_type) { case BSS_TYPE_AP_BSS: - fw_name = WL1271_AP_FW_NAME; + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_AP_FW_NAME; + else + fw_name = WL127X_AP_FW_NAME; break; case BSS_TYPE_IBSS: case BSS_TYPE_STA_BSS: - fw_name = WL1271_FW_NAME; + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_FW_NAME; + else + fw_name = WL1271_FW_NAME; break; default: wl1271_error("no compatible firmware for bss_type %d", @@ -838,14 +899,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get nvs file: %d", ret); return ret; } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -954,6 +1015,17 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) if (ret < 0) goto out; break; + case CHIP_ID_1283_PG20: + wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)", + wl->chip.id); + + ret = wl1271_setup(wl); + if (ret < 0) + goto out; + if (wl1271_set_block_size(wl)) + wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT; + break; + case CHIP_ID_1283_PG10: default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; @@ -978,6 +1050,24 @@ out: return ret; } +static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl) +{ + unsigned int quirks = 0; + unsigned int *fw_ver = wl->chip.fw_ver; + + /* Only for wl127x */ + if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && + /* Check STA version */ + (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || + /* Check AP version */ + ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && + (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) + quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; + + return quirks; +} + int wl1271_plt_start(struct wl1271 *wl) { int retries = WL1271_BOOT_RETRIES; @@ -1013,6 +1103,9 @@ int wl1271_plt_start(struct wl1271 *wl) wl->state = WL1271_STATE_PLT; wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver_str); + + /* Check if any quirks are needed with older fw versions */ + wl->quirks |= wl1271_get_fw_ver_quirks(wl); goto out; irq_disable: @@ -1040,7 +1133,7 @@ out: return ret; } -int __wl1271_plt_stop(struct wl1271 *wl) +static int __wl1271_plt_stop(struct wl1271 *wl) { int ret = 0; @@ -1124,6 +1217,69 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) spin_unlock_irqrestore(&wl->wl_lock, flags); } +int wl1271_tx_dummy_packet(struct wl1271 *wl) +{ + unsigned long flags; + + spin_lock_irqsave(&wl->wl_lock, flags); + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + wl->tx_queue_count++; + spin_unlock_irqrestore(&wl->wl_lock, flags); + + /* The FW is low on RX memory blocks, so send the dummy packet asap */ + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) + wl1271_tx_work_locked(wl); + + /* + * If the FW TX is busy, TX work will be scheduled by the threaded + * interrupt handler function + */ + return 0; +} + +/* + * The size of the dummy packet should be at least 1400 bytes. However, in + * order to minimize the number of bus transactions, aligning it to 512 bytes + * boundaries could be beneficial, performance wise + */ +#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512)) + +static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) +{ + struct sk_buff *skb; + struct ieee80211_hdr_3addr *hdr; + unsigned int dummy_packet_size; + + dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE - + sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr); + + skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE); + if (!skb) { + wl1271_warning("Failed to allocate a dummy packet skb"); + return NULL; + } + + skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr)); + + hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS); + + memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size); + + /* Dummy packets require the TID to be management */ + skb->priority = WL1271_TID_MGMT; + + /* Initialize all fields that might be used */ + skb->queue_mapping = 0; + memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info)); + + return skb; +} + + static struct notifier_block wl1271_dev_notifier = { .notifier_call = wl1271_dev_notify, }; @@ -1174,6 +1330,16 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } + /* + * in some very corner case HW recovery scenarios its possible to + * get here before __wl1271_op_remove_interface is complete, so + * opt out if that is the case. + */ + if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) { + ret = -EBUSY; + goto out; + } + switch (vif->type) { case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; @@ -1242,6 +1408,7 @@ power_off: wl->vif = vif; wl->state = WL1271_STATE_ON; + set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags); wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str); /* update hw/fw version info in wiphy struct */ @@ -1249,6 +1416,9 @@ power_off: strncpy(wiphy->fw_version, wl->chip.fw_ver_str, sizeof(wiphy->fw_version)); + /* Check if any quirks are needed with older fw versions */ + wl->quirks |= wl1271_get_fw_ver_quirks(wl); + /* * Now we know if 11a is supported (info from the NVS), so disable * 11a channels if not supported @@ -1262,8 +1432,10 @@ power_off: out: mutex_unlock(&wl->mutex); + mutex_lock(&wl_list_mutex); if (!ret) list_add(&wl->list, &wl_list); + mutex_unlock(&wl_list_mutex); return ret; } @@ -1274,11 +1446,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); + /* because of hardware recovery, we may get here twice */ + if (wl->state != WL1271_STATE_ON) + return; + wl1271_info("down"); + mutex_lock(&wl_list_mutex); list_del(&wl->list); - - WARN_ON(wl->state != WL1271_STATE_ON); + mutex_unlock(&wl_list_mutex); /* enable dyn ps just in case (if left on due to fw crash etc) */ if (wl->bss_type == BSS_TYPE_STA_BSS) @@ -1286,12 +1462,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) if (wl->scan.state != WL1271_SCAN_STATE_IDLE) { wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, true); } + /* + * this must be before the cancel_work calls below, so that the work + * functions don't perform further work. + */ wl->state = WL1271_STATE_OFF; mutex_unlock(&wl->mutex); @@ -1321,6 +1500,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; + wl->tx_allocated_blocks = 0; wl->tx_results_count = 0; wl->tx_packets_count = 0; wl->tx_security_last_seq = 0; @@ -1328,7 +1508,6 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->time_offset = 0; wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; - wl->flags = 0; wl->vif = NULL; wl->filters = 0; wl1271_free_ap_keys(wl); @@ -1336,6 +1515,13 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl) wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; + /* + * this is performed after the cancel_work calls and the associated + * mutex_lock, so that wl1271_op_add_interface does not accidentally + * get executed before all these vars have been reset. + */ + wl->flags = 0; + for (i = 0; i < NUM_TX_QUEUES; i++) wl->tx_blocks_freed[i] = 0; @@ -1368,7 +1554,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, cancel_work_sync(&wl->recovery_work); } -static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) +void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) { wl1271_set_default_filters(wl); @@ -1431,10 +1617,10 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) * One of the side effects of the JOIN command is that is clears * WPA/WPA2 keys from the chipset. Performing a JOIN while associated * to a WPA/WPA2 access point will therefore kill the data-path. - * Currently there is no supported scenario for JOIN during - * association - if it becomes a supported scenario, the WPA/WPA2 keys - * must be handled somehow. - * + * Currently the only valid scenario for JOIN during association + * is on roaming, in which case we will also be given new keys. + * Keep the below message for now, unless it starts bothering + * users who really like to roam a lot :) */ if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) wl1271_info("JOIN while associated."); @@ -1490,7 +1676,7 @@ static int wl1271_unjoin(struct wl1271 *wl) clear_bit(WL1271_FLAG_JOINED, &wl->flags); memset(wl->bssid, 0, ETH_ALEN); - /* stop filterting packets based on bssid */ + /* stop filtering packets based on bssid */ wl1271_configure_filters(wl, FIF_OTHER_BSS); out: @@ -1569,7 +1755,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&wl->mutex); if (unlikely(wl->state == WL1271_STATE_OFF)) { - ret = -EAGAIN; + /* we support configuring the channel and band while off */ + if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) { + wl->band = conf->channel->band; + wl->channel = channel; + } + goto out; } @@ -2650,32 +2841,31 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY; conf_tid->apsd_conf[0] = 0; conf_tid->apsd_conf[1] = 0; - } else { - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out; + goto out; + } - /* - * the txop is confed in units of 32us by the mac80211, - * we need us - */ - ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), - params->cw_min, params->cw_max, - params->aifs, params->txop << 5); - if (ret < 0) - goto out_sleep; + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; - ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), - CONF_CHANNEL_TYPE_EDCF, - wl1271_tx_get_queue(queue), - ps_scheme, CONF_ACK_POLICY_LEGACY, - 0, 0); - if (ret < 0) - goto out_sleep; + /* + * the txop is confed in units of 32us by the mac80211, + * we need us + */ + ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue), + params->cw_min, params->cw_max, + params->aifs, params->txop << 5); + if (ret < 0) + goto out_sleep; + + ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue), + CONF_CHANNEL_TYPE_EDCF, + wl1271_tx_get_queue(queue), + ps_scheme, CONF_ACK_POLICY_LEGACY, + 0, 0); out_sleep: - wl1271_ps_elp_sleep(wl); - } + wl1271_ps_elp_sleep(wl); out: mutex_unlock(&wl->mutex); @@ -2764,6 +2954,12 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); } +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) +{ + int id = hlid - WL1271_AP_STA_HLID_START; + return test_bit(id, wl->ap_hlid_map); +} + static int wl1271_op_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -2847,10 +3043,11 @@ out: return ret; } -int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum ieee80211_ampdu_mlme_action action, - struct ieee80211_sta *sta, u16 tid, u16 *ssn, - u8 buf_size) +static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum ieee80211_ampdu_mlme_action action, + struct ieee80211_sta *sta, u16 tid, u16 *ssn, + u8 buf_size) { struct wl1271 *wl = hw->priv; int ret; @@ -3003,7 +3200,8 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { #ifdef CONFIG_WL12XX_HT #define WL12XX_HT_CAP { \ - .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \ + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ .ht_supported = true, \ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \ .ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \ @@ -3207,8 +3405,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, unsigned long res; int ret; - ret = strict_strtoul(buf, 10, &res); - + ret = kstrtoul(buf, 10, &res); if (ret < 0) { wl1271_warning("incorrect value written to bt_coex_mode"); return count; @@ -3273,7 +3470,11 @@ int wl1271_register_hw(struct wl1271 *wl) ret = wl1271_fetch_nvs(wl); if (ret == 0) { - u8 *nvs_ptr = (u8 *)wl->nvs->nvs; + /* NOTE: The wl->nvs->nvs element must be first, in + * order to simplify the casting, we assume it is at + * the beginning of the wl->nvs structure. + */ + u8 *nvs_ptr = (u8 *)wl->nvs; wl->mac_addr[0] = nvs_ptr[11]; wl->mac_addr[1] = nvs_ptr[10]; @@ -3341,7 +3542,6 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_HAS_RATE_CONTROL | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_SUPPORTS_CQM_RSSI | - IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_AP_LINK_PS; wl->hw->wiphy->cipher_suites = cipher_suites; @@ -3358,6 +3558,10 @@ int wl1271_init_ieee80211(struct wl1271 *wl) wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - sizeof(struct ieee80211_header); + /* make sure all our channels fit in the scanned_ch bitmask */ + BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + + ARRAY_SIZE(wl1271_channels_5ghz) > + WL1271_MAX_CHANNELS); /* * We keep local copies of the band structs because we need to * modify them on a per-device basis. @@ -3458,6 +3662,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; wl->quirks = 0; + wl->platform_quirks = 0; memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) @@ -3478,11 +3683,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void) goto err_hw; } + wl->dummy_packet = wl12xx_alloc_dummy_packet(wl); + if (!wl->dummy_packet) { + ret = -ENOMEM; + goto err_aggr; + } + /* Register platform device */ ret = platform_device_register(wl->plat_dev); if (ret) { wl1271_error("couldn't register platform device"); - goto err_aggr; + goto err_dummy_packet; } dev_set_drvdata(&wl->plat_dev->dev, wl); @@ -3508,6 +3719,9 @@ err_bt_coex_state: err_platform: platform_device_unregister(wl->plat_dev); +err_dummy_packet: + dev_kfree_skb(wl->dummy_packet); + err_aggr: free_pages((unsigned long)wl->aggr_buf, order); @@ -3527,6 +3741,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw); int wl1271_free_hw(struct wl1271 *wl) { platform_device_unregister(wl->plat_dev); + dev_kfree_skb(wl->dummy_packet); free_pages((unsigned long)wl->aggr_buf, get_order(WL1271_AGGR_BUFFER_SIZE)); kfree(wl->plat_dev); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 971f13e..b8deada 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -149,9 +149,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode, case STATION_ACTIVE_MODE: default: wl1271_debug(DEBUG_PSM, "leaving psm"); - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - return ret; /* disable beacon early termination */ ret = wl1271_acx_bet_enable(wl, false); diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index 9909607..440a4ee 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -207,6 +207,8 @@ #define CHIP_ID_1271_PG10 (0x4030101) #define CHIP_ID_1271_PG20 (0x4030111) +#define CHIP_ID_1283_PG10 (0x05030101) +#define CHIP_ID_1283_PG20 (0x05030111) #define ENABLE (REGISTERS_BASE + 0x5450) @@ -452,24 +454,11 @@ #define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200 #define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400 -/* - * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile - * for platforms using active high interrupt level - */ -#ifdef USE_ACTIVE_HIGH #define HI_CFG_DEF_VAL \ (HI_CFG_UART_ENABLE | \ HI_CFG_RST232_ENABLE | \ HI_CFG_CLOCK_REQ_SELECT | \ HI_CFG_HOST_INT_ENABLE) -#else -#define HI_CFG_DEF_VAL \ - (HI_CFG_UART_ENABLE | \ - HI_CFG_RST232_ENABLE | \ - HI_CFG_CLOCK_REQ_SELECT | \ - HI_CFG_HOST_INT_ENABLE) - -#endif #define REF_FREQ_19_2 0 #define REF_FREQ_26_0 1 diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 919b59f..2a58149 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -48,18 +48,14 @@ static void wl1271_rx_status(struct wl1271 *wl, struct ieee80211_rx_status *status, u8 beacon) { - enum ieee80211_band desc_band; - memset(status, 0, sizeof(struct ieee80211_rx_status)); - status->band = wl->band; - if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG) - desc_band = IEEE80211_BAND_2GHZ; + status->band = IEEE80211_BAND_2GHZ; else - desc_band = IEEE80211_BAND_5GHZ; + status->band = IEEE80211_BAND_5GHZ; - status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band); + status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); #ifdef CONFIG_WL12XX_HT /* 11n support */ @@ -76,7 +72,8 @@ static void wl1271_rx_status(struct wl1271 *wl, */ wl->noise = desc->rssi - (desc->snr >> 1); - status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band); + status->freq = ieee80211_channel_to_frequency(desc->channel, + status->band); if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) { status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; @@ -163,18 +160,25 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) break; } - /* - * Choose the block we want to read - * For aggregated packets, only the first memory block should - * be retrieved. The FW takes care of the rest. - */ - mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter); - wl->rx_mem_pool_addr.addr = (mem_block << 8) + - le32_to_cpu(wl_mem_map->packet_memory_pool_start); - wl->rx_mem_pool_addr.addr_extra = - wl->rx_mem_pool_addr.addr + 4; - wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, - sizeof(wl->rx_mem_pool_addr), false); + if (wl->chip.id != CHIP_ID_1283_PG20) { + /* + * Choose the block we want to read + * For aggregated packets, only the first memory block + * should be retrieved. The FW takes care of the rest. + */ + mem_block = wl1271_rx_get_mem_block(status, + drv_rx_counter); + + wl->rx_mem_pool_addr.addr = (mem_block << 8) + + le32_to_cpu(wl_mem_map->packet_memory_pool_start); + + wl->rx_mem_pool_addr.addr_extra = + wl->rx_mem_pool_addr.addr + 4; + + wl1271_write(wl, WL1271_SLV_REG_DATA, + &wl->rx_mem_pool_addr, + sizeof(wl->rx_mem_pool_addr), false); + } /* Read all available packets at once */ wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 420653a..5d0544c 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -48,8 +48,7 @@ void wl1271_scan_complete_work(struct work_struct *work) goto out; wl->scan.state = WL1271_SCAN_STATE_IDLE; - kfree(wl->scan.scanned_ch); - wl->scan.scanned_ch = NULL; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; ieee80211_scan_completed(wl->hw, false); @@ -87,7 +86,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, flags = req->channels[i]->flags; - if (!wl->scan.scanned_ch[i] && + if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && (req->channels[i]->band == band)) { @@ -124,7 +123,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, memset(&channels[j].bssid_msb, 0xff, 2); /* Mark the channels we already used */ - wl->scan.scanned_ch[i] = true; + set_bit(i, wl->scan.scanned_ch); j++; } @@ -291,6 +290,12 @@ void wl1271_scan_stm(struct wl1271 *wl) int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, struct cfg80211_scan_request *req) { + /* + * cfg80211 should guarantee that we don't get more channels + * than what we have registered. + */ + BUG_ON(req->n_channels > WL1271_MAX_CHANNELS); + if (wl->scan.state != WL1271_SCAN_STATE_IDLE) return -EBUSY; @@ -304,10 +309,8 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len, } wl->scan.req = req; + memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); - wl->scan.scanned_ch = kcalloc(req->n_channels, - sizeof(*wl->scan.scanned_ch), - GFP_KERNEL); /* we assume failure so that timeout scenarios are handled correctly */ wl->scan.failed = true; ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work, diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index b1c7d03..bcd4ad7 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -51,6 +51,13 @@ static const struct sdio_device_id wl1271_devices[] = { }; MODULE_DEVICE_TABLE(sdio, wl1271_devices); +static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz) +{ + sdio_claim_host(wl->if_priv); + sdio_set_block_size(wl->if_priv, blksz); + sdio_release_host(wl->if_priv); +} + static inline struct sdio_func *wl_to_func(struct wl1271 *wl) { return wl->if_priv; @@ -203,7 +210,8 @@ static struct wl1271_if_operations sdio_ops = { .power = wl1271_sdio_set_power, .dev = wl1271_sdio_wl_to_dev, .enable_irq = wl1271_sdio_enable_interrupts, - .disable_irq = wl1271_sdio_disable_interrupts + .disable_irq = wl1271_sdio_disable_interrupts, + .set_block_size = wl1271_sdio_set_block_size, }; static int __devinit wl1271_probe(struct sdio_func *func, @@ -212,6 +220,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, struct ieee80211_hw *hw; const struct wl12xx_platform_data *wlan_data; struct wl1271 *wl; + unsigned long irqflags; int ret; /* We are only able to handle the wlan function */ @@ -230,6 +239,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); @@ -239,9 +251,16 @@ static int __devinit wl1271_probe(struct sdio_func *func, wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; + wl->tcxo_clock = wlan_data->board_tcxo_clock; + wl->platform_quirks = wlan_data->platform_quirks; + + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); @@ -343,4 +362,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_FIRMWARE(WL1271_FW_NAME); -MODULE_FIRMWARE(WL1271_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME); +MODULE_FIRMWARE(WL127X_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index 9fcbd3d..f289153 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl)); + if (wl->chip.id == CHIP_ID_1283_PG20) + ret = request_firmware(&fw, WL128X_FW_NAME, + wl1271_wl_to_dev(wl)); + else + ret = request_firmware(&fw, WL1271_FW_NAME, + wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get firmware: %d", ret); @@ -227,14 +232,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) const struct firmware *fw; int ret; - ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl)); + ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { wl1271_error("could not get nvs file: %d", ret); return ret; } - wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL); + wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); @@ -288,6 +293,11 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_notice("chip id 0x%x (1271 PG20)", wl->chip.id); break; + case CHIP_ID_1283_PG20: + wl1271_notice("chip id 0x%x (1283 PG20)", + wl->chip.id); + break; + case CHIP_ID_1283_PG10: default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); return -ENODEV; @@ -407,6 +417,9 @@ static int __devinit wl1271_probe(struct sdio_func *func, /* Grab access to FN0 for ELP reg. */ func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + /* Use block mode for transferring over one block size of data */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; + wlan_data = wl12xx_get_platform_data(); if (IS_ERR(wlan_data)) { ret = PTR_ERR(wlan_data); @@ -416,6 +429,7 @@ static int __devinit wl1271_probe(struct sdio_func *func, wl->irq = wlan_data->irq; wl->ref_clock = wlan_data->board_ref_clock; + wl->tcxo_clock = wlan_data->board_tcxo_clock; sdio_set_drvdata(func, wl_test); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index ffc745b..51662bb 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -355,7 +355,8 @@ static struct wl1271_if_operations spi_ops = { .power = wl1271_spi_set_power, .dev = wl1271_spi_wl_to_dev, .enable_irq = wl1271_spi_enable_interrupts, - .disable_irq = wl1271_spi_disable_interrupts + .disable_irq = wl1271_spi_disable_interrupts, + .set_block_size = NULL, }; static int __devinit wl1271_probe(struct spi_device *spi) @@ -363,6 +364,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) struct wl12xx_platform_data *pdata; struct ieee80211_hw *hw; struct wl1271 *wl; + unsigned long irqflags; int ret; pdata = spi->dev.platform_data; @@ -400,6 +402,13 @@ static int __devinit wl1271_probe(struct spi_device *spi) } wl->ref_clock = pdata->board_ref_clock; + wl->tcxo_clock = pdata->board_tcxo_clock; + wl->platform_quirks = pdata->platform_quirks; + + if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) + irqflags = IRQF_TRIGGER_RISING; + else + irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; wl->irq = spi->irq; if (wl->irq < 0) { @@ -409,7 +418,7 @@ static int __devinit wl1271_probe(struct spi_device *spi) } ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + irqflags, DRIVER_NAME, wl); if (ret < 0) { wl1271_error("request_irq() failed: %d", ret); @@ -490,5 +499,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); MODULE_FIRMWARE(WL1271_FW_NAME); -MODULE_FIRMWARE(WL1271_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_FW_NAME); +MODULE_FIRMWARE(WL127X_AP_FW_NAME); +MODULE_FIRMWARE(WL128X_AP_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index 6ec06a4..da351d7 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -27,6 +27,7 @@ #include "wl12xx.h" #include "acx.h" +#include "reg.h" #define WL1271_TM_MAX_DATA_LENGTH 1024 @@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) kfree(wl->nvs); - if (len != sizeof(struct wl1271_nvs_file)) + if ((wl->chip.id == CHIP_ID_1283_PG20) && + (len != sizeof(struct wl128x_nvs_file))) + return -EINVAL; + else if (len != sizeof(struct wl1271_nvs_file)) return -EINVAL; wl->nvs = kzalloc(len, GFP_KERNEL); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 5e9ef7d..7a3339f 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -70,6 +70,28 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id) } } +static int wl1271_tx_update_filters(struct wl1271 *wl, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + + hdr = (struct ieee80211_hdr *)(skb->data + + sizeof(struct wl1271_tx_hw_descr)); + + /* + * stop bssid-based filtering before transmitting authentication + * requests. this way the hw will never drop authentication + * responses coming from BSSIDs it isn't familiar with (e.g. on + * roaming) + */ + if (!ieee80211_is_auth(hdr->frame_control)) + return 0; + + wl1271_configure_filters(wl, FIF_OTHER_BSS); + + return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); +} + static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, struct sk_buff *skb) { @@ -127,13 +149,29 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb) } } +static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, + unsigned int packet_length) +{ + if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) + return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); + else + return ALIGN(packet_length, WL1271_TX_ALIGN_TO); +} + static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 buf_offset, u8 hlid) { struct wl1271_tx_hw_descr *desc; u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; + u32 len; u32 total_blocks; int id, ret = -EBUSY; + u32 spare_blocks; + + if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) + spare_blocks = 2; + else + spare_blocks = 1; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -145,17 +183,27 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, /* approximate the number of blocks required for this packet in the firmware */ - total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; - total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; + len = wl12xx_calc_packet_alignment(wl, total_len); + + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + + spare_blocks; + if (total_blocks <= wl->tx_blocks_available) { desc = (struct wl1271_tx_hw_descr *)skb_push( skb, total_len - skb->len); - desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; - desc->total_mem_blocks = total_blocks; + /* HW descriptor fields change between wl127x and wl128x */ + if (wl->chip.id == CHIP_ID_1283_PG20) { + desc->wl128x_mem.total_mem_blocks = total_blocks; + } else { + desc->wl127x_mem.extra_blocks = spare_blocks; + desc->wl127x_mem.total_mem_blocks = total_blocks; + } + desc->id = id; wl->tx_blocks_available -= total_blocks; + wl->tx_allocated_blocks += total_blocks; if (wl->bss_type == BSS_TYPE_AP_BSS) wl->links[hlid].allocated_blks += total_blocks; @@ -172,13 +220,18 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return ret; } +static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +{ + return wl->dummy_packet == skb; +} + static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control, u8 hlid) { struct timespec ts; struct wl1271_tx_hw_descr *desc; - int pad, ac, rate_idx; + int aligned_len, ac, rate_idx; s64 hosttime; u16 tx_attr; @@ -202,12 +255,25 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); - /* configure the tx attributes */ - tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; - - /* queue (we use same identifiers for tid's and ac's */ + /* queue */ ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - desc->tid = ac; + desc->tid = skb->priority; + + if (wl12xx_is_dummy_packet(wl, skb)) { + /* + * FW expects the dummy packet to have an invalid session id - + * any session id that is different than the one set in the join + */ + tx_attr = ((~wl->session_counter) << + TX_HW_ATTR_OFST_SESSION_COUNTER) & + TX_HW_ATTR_SESSION_COUNTER; + + tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; + } else { + /* configure the tx attributes */ + tx_attr = + wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; + } if (wl->bss_type != BSS_TYPE_AP_BSS) { desc->aid = hlid; @@ -237,20 +303,37 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; desc->reserved = 0; - /* align the length (and store in terms of words) */ - pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); - desc->length = cpu_to_le16(pad >> 2); + aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); - /* calculate number of padding bytes */ - pad = pad - skb->len; - tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; + if (wl->chip.id == CHIP_ID_1283_PG20) { + desc->wl128x_mem.extra_bytes = aligned_len - skb->len; + desc->length = cpu_to_le16(aligned_len >> 2); - desc->tx_attr = cpu_to_le16(tx_attr); + wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " + "tx_attr: 0x%x len: %d life: %d mem: %d", + desc->hlid, tx_attr, + le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), + desc->wl128x_mem.total_mem_blocks); + } else { + int pad; + + /* Store the aligned length in terms of words */ + desc->length = cpu_to_le16(aligned_len >> 2); + + /* calculate number of padding bytes */ + pad = aligned_len - skb->len; + tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; - wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " - "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, - le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), - le16_to_cpu(desc->life_time), desc->total_mem_blocks); + wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " + "tx_attr: 0x%x len: %d life: %d mem: %d", pad, + desc->hlid, tx_attr, + le16_to_cpu(desc->length), + le16_to_cpu(desc->life_time), + desc->wl127x_mem.total_mem_blocks); + } + + desc->tx_attr = cpu_to_le16(tx_attr); } /* caller must hold wl->mutex */ @@ -300,19 +383,29 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_regulate_link(wl, hlid); + } else { + wl1271_tx_update_filters(wl, skb); } wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); /* - * The length of each packet is stored in terms of words. Thus, we must - * pad the skb data to make sure its length is aligned. - * The number of padding bytes is computed and set in wl1271_tx_fill_hdr + * The length of each packet is stored in terms of + * words. Thus, we must pad the skb data to make sure its + * length is aligned. The number of padding bytes is computed + * and set in wl1271_tx_fill_hdr. + * In special cases, we want to align to a specific block size + * (eg. for wl128x with SDIO we align to 256). */ - total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); + total_len = wl12xx_calc_packet_alignment(wl, skb->len); + memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); + /* Revert side effects in the dummy packet skb, so it can be reused */ + if (wl12xx_is_dummy_packet(wl, skb)) + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + return total_len; } @@ -425,10 +518,23 @@ out: static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) { + unsigned long flags; + struct sk_buff *skb = NULL; + if (wl->bss_type == BSS_TYPE_AP_BSS) - return wl1271_ap_skb_dequeue(wl); + skb = wl1271_ap_skb_dequeue(wl); + else + skb = wl1271_sta_skb_dequeue(wl); + + if (!skb && + test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { + skb = wl->dummy_packet; + spin_lock_irqsave(&wl->wl_lock, flags); + wl->tx_queue_count--; + spin_unlock_irqrestore(&wl->wl_lock, flags); + } - return wl1271_sta_skb_dequeue(wl); + return skb; } static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) @@ -436,7 +542,9 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) unsigned long flags; int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - if (wl->bss_type == BSS_TYPE_AP_BSS) { + if (wl12xx_is_dummy_packet(wl, skb)) { + set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); + } else if (wl->bss_type == BSS_TYPE_AP_BSS) { u8 hlid = wl1271_tx_get_hlid(skb); skb_queue_head(&wl->links[hlid].tx_queue[q], skb); @@ -454,22 +562,14 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) void wl1271_tx_work_locked(struct wl1271 *wl) { struct sk_buff *skb; - bool woken_up = false; u32 buf_offset = 0; bool sent_packets = false; int ret; if (unlikely(wl->state == WL1271_STATE_OFF)) - goto out; + return; while ((skb = wl1271_skb_dequeue(wl))) { - if (!woken_up) { - ret = wl1271_ps_elp_wakeup(wl); - if (ret < 0) - goto out_ack; - woken_up = true; - } - ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); if (ret == -EAGAIN) { /* @@ -516,18 +616,22 @@ out_ack: wl1271_handle_tx_low_watermark(wl); } - -out: - if (woken_up) - wl1271_ps_elp_sleep(wl); } void wl1271_tx_work(struct work_struct *work) { struct wl1271 *wl = container_of(work, struct wl1271, tx_work); + int ret; mutex_lock(&wl->mutex); + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + wl1271_tx_work_locked(wl); + + wl1271_ps_elp_wakeup(wl); +out: mutex_unlock(&wl->mutex); } @@ -549,6 +653,11 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, skb = wl->tx_frames[id]; info = IEEE80211_SKB_CB(skb); + if (wl12xx_is_dummy_packet(wl, skb)) { + wl1271_free_tx_id(wl, id); + return; + } + /* update the TX status info */ if (result->status == TX_SUCCESS) { if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) @@ -678,10 +787,13 @@ void wl1271_tx_reset(struct wl1271 *wl) while ((skb = skb_dequeue(&wl->tx_queue[i]))) { wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, skb); + + if (!wl12xx_is_dummy_packet(wl, skb)) { + info = IEEE80211_SKB_CB(skb); + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + ieee80211_tx_status(wl->hw, skb); + } } } } @@ -702,21 +814,27 @@ void wl1271_tx_reset(struct wl1271 *wl) wl1271_free_tx_id(wl, i); wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); - /* Remove private headers before passing the skb to mac80211 */ - info = IEEE80211_SKB_CB(skb); - skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); - if (info->control.hw_key && - info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, - hdrlen); - skb_pull(skb, WL1271_TKIP_IV_SPACE); - } + if (!wl12xx_is_dummy_packet(wl, skb)) { + /* + * Remove private headers before passing the skb to + * mac80211 + */ + info = IEEE80211_SKB_CB(skb); + skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); + if (info->control.hw_key && + info->control.hw_key->cipher == + WLAN_CIPHER_SUITE_TKIP) { + int hdrlen = ieee80211_get_hdrlen_from_skb(skb); + memmove(skb->data + WL1271_TKIP_IV_SPACE, + skb->data, hdrlen); + skb_pull(skb, WL1271_TKIP_IV_SPACE); + } - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; - ieee80211_tx_status(wl->hw, skb); + ieee80211_tx_status(wl->hw, skb); + } } } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 02f07fa..fc7835c 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -25,7 +25,6 @@ #ifndef __TX_H__ #define __TX_H__ -#define TX_HW_BLOCK_SPARE 2 #define TX_HW_BLOCK_SIZE 252 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 @@ -41,6 +40,7 @@ BIT(8) | BIT(9)) #define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11)) #define TX_HW_ATTR_TX_CMPLT_REQ BIT(12) +#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13) #define TX_HW_ATTR_OFST_SAVE_RETRIES 0 #define TX_HW_ATTR_OFST_HEADER_PAD 1 @@ -55,20 +55,60 @@ #define WL1271_TX_ALIGN_TO 4 #define WL1271_TKIP_IV_SPACE 4 +/* Used for management frames and dummy packets */ +#define WL1271_TID_MGMT 7 + +struct wl127x_tx_mem { + /* + * Number of extra memory blocks to allocate for this packet + * in addition to the number of blocks derived from the packet + * length. + */ + u8 extra_blocks; + /* + * Total number of memory blocks allocated by the host for + * this packet. Must be equal or greater than the actual + * blocks number allocated by HW. + */ + u8 total_mem_blocks; +} __packed; + +struct wl128x_tx_mem { + /* + * Total number of memory blocks allocated by the host for + * this packet. + */ + u8 total_mem_blocks; + /* + * Number of extra bytes, at the end of the frame. the host + * uses this padding to complete each frame to integer number + * of SDIO blocks. + */ + u8 extra_bytes; +} __packed; + +/* + * On wl128x based devices, when TX packets are aggregated, each packet + * size must be aligned to the SDIO block size. The maximum block size + * is bounded by the type of the padded bytes field that is sent to the + * FW. Currently the type is u8, so the maximum block size is 256 bytes. + */ +#define WL12XX_BUS_BLOCK_SIZE min(512u, \ + (1u << (8 * sizeof(((struct wl128x_tx_mem *) 0)->extra_bytes)))) + struct wl1271_tx_hw_descr { /* Length of packet in words, including descriptor+header+data */ __le16 length; - /* Number of extra memory blocks to allocate for this packet in - addition to the number of blocks derived from the packet length */ - u8 extra_mem_blocks; - /* Total number of memory blocks allocated by the host for this packet. - Must be equal or greater than the actual blocks number allocated by - HW!! */ - u8 total_mem_blocks; + union { + struct wl127x_tx_mem wl127x_mem; + struct wl128x_tx_mem wl128x_mem; + } __packed; /* Device time (in us) when the packet arrived to the driver */ __le32 start_time; - /* Max delay in TUs until transmission. The last device time the - packet can be transmitted is: startTime+(1024*LifeTime) */ + /* + * Max delay in TUs until transmission. The last device time the + * packet can be transmitted is: start_time + (1024 * life_time) + */ __le16 life_time; /* Bitwise fields - see TX_ATTR... definitions above. */ __le16 tx_attr; diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 86be83e..7c521af 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -131,9 +131,16 @@ extern u32 wl12xx_debug_level; #define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin" -#define WL1271_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" +#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin" +#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" +#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin" -#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.bin" +/* + * wl127x and wl128x are using the same NVS file name. However, the + * ini parameters between them are different. The driver validates + * the correct NVS size in wl1271_boot_upload_nvs(). + */ +#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin" #define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff)) #define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff)) @@ -165,7 +172,6 @@ extern u32 wl12xx_debug_level; #define WL1271_PS_STA_MAX_BLOCKS (2 * 9) #define WL1271_AP_BSS_INDEX 0 -#define WL1271_AP_DEF_INACTIV_SEC 300 #define WL1271_AP_DEF_BEACON_EXP 20 #define ACX_TX_DESCRIPTORS 32 @@ -200,13 +206,29 @@ struct wl1271_partition_set { struct wl1271; -#define WL12XX_NUM_FW_VER 5 +enum { + FW_VER_CHIP, + FW_VER_IF_TYPE, + FW_VER_MAJOR, + FW_VER_SUBTYPE, + FW_VER_MINOR, + + NUM_FW_VER +}; + +#define FW_VER_CHIP_WL127X 6 +#define FW_VER_CHIP_WL128X 7 + +#define FW_VER_IF_TYPE_STA 1 +#define FW_VER_IF_TYPE_AP 2 + +#define FW_VER_MINOR_1_SPARE_STA_MIN 58 +#define FW_VER_MINOR_1_SPARE_AP_MIN 47 -/* FIXME: I'm not sure about this structure name */ struct wl1271_chip { u32 id; char fw_ver_str[ETHTOOL_BUSINFO_LEN]; - unsigned int fw_ver[WL12XX_NUM_FW_VER]; + unsigned int fw_ver[NUM_FW_VER]; }; struct wl1271_stats { @@ -261,6 +283,8 @@ struct wl1271_fw_sta_status { u8 tx_total; u8 reserved1; __le16 reserved2; + /* Total structure size is 68 bytes */ + u32 padding; } __packed; struct wl1271_fw_full_status { @@ -277,9 +301,10 @@ struct wl1271_rx_mem_pool_addr { u32 addr_extra; }; +#define WL1271_MAX_CHANNELS 64 struct wl1271_scan { struct cfg80211_scan_request *req; - bool *scanned_ch; + unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; bool failed; u8 state; u8 ssid[IW_ESSID_MAX_SIZE+1]; @@ -297,6 +322,7 @@ struct wl1271_if_operations { struct device* (*dev)(struct wl1271 *wl); void (*enable_irq)(struct wl1271 *wl); void (*disable_irq)(struct wl1271 *wl); + void (*set_block_size) (struct wl1271 *wl, unsigned int blksz); }; #define MAX_NUM_KEYS 14 @@ -327,7 +353,9 @@ enum wl12xx_flags { WL1271_FLAG_PSPOLL_FAILURE, WL1271_FLAG_STA_STATE_SENT, WL1271_FLAG_FW_TX_BUSY, - WL1271_FLAG_AP_STARTED + WL1271_FLAG_AP_STARTED, + WL1271_FLAG_IF_INITIALIZED, + WL1271_FLAG_DUMMY_PACKET_PENDING, }; struct wl1271_link { @@ -371,7 +399,7 @@ struct wl1271 { u8 *fw; size_t fw_len; u8 fw_bss_type; - struct wl1271_nvs_file *nvs; + void *nvs; size_t nvs_len; s8 hw_pg_ver; @@ -389,6 +417,7 @@ struct wl1271 { /* Accounting for allocated / available TX blocks on HW */ u32 tx_blocks_freed[NUM_TX_QUEUES]; u32 tx_blocks_available; + u32 tx_allocated_blocks; u32 tx_results_count; /* Transmitted TX packets counter for chipset interface */ @@ -430,6 +459,9 @@ struct wl1271 { /* Intermediate buffer, used for packet aggregation */ u8 *aggr_buf; + /* Reusable dummy packet template */ + struct sk_buff *dummy_packet; + /* Network stack work */ struct work_struct netstack_work; @@ -527,6 +559,8 @@ struct wl1271 { bool ba_support; u8 ba_rx_bitmap; + int tcxo_clock; + /* * AP-mode - links indexed by HLID. The global and broadcast links * are always active. @@ -544,6 +578,9 @@ struct wl1271 { /* Quirks of specific hardware revisions */ unsigned int quirks; + + /* Platform limitations */ + unsigned int platform_quirks; }; struct wl1271_station { @@ -576,6 +613,15 @@ int wl1271_plt_stop(struct wl1271 *wl); /* Quirks */ /* Each RX/TX transaction requires an end-of-transaction transfer */ -#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) +#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) + +/* + * Older firmwares use 2 spare TX blocks + * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47) + */ +#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) + +/* WL128X requires aggregated packets to be aligned to the SDIO block size */ +#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) #endif diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 7c031fd..06d15b6 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c @@ -46,40 +46,66 @@ void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc, if (!ccdev) return; bus = ccdev->bus; + + /* We support SLOW only on 6..9 */ + if (ccdev->id.revision >= 10 && mode == SSB_CLKMODE_SLOW) + mode = SSB_CLKMODE_DYNAMIC; + + if (cc->capabilities & SSB_CHIPCO_CAP_PMU) + return; /* PMU controls clockmode, separated function needed */ + SSB_WARN_ON(ccdev->id.revision >= 20); + /* chipcommon cores prior to rev6 don't support dynamic clock control */ if (ccdev->id.revision < 6) return; - /* chipcommon cores rev10 are a whole new ball game */ + + /* ChipCommon cores rev10+ need testing */ if (ccdev->id.revision >= 10) return; + if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL)) return; switch (mode) { - case SSB_CLKMODE_SLOW: + case SSB_CLKMODE_SLOW: /* For revs 6..9 only */ tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW; chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); break; case SSB_CLKMODE_FAST: - ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ - tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; - tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; - chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + if (ccdev->id.revision < 10) { + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */ + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + } else { + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) | + SSB_CHIPCO_SYSCLKCTL_FORCEHT)); + /* udelay(150); TODO: not available in early init */ + } break; case SSB_CLKMODE_DYNAMIC: - tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; - tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; - if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) - tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; - chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); - - /* for dynamic control, we have to release our xtal_pu "force on" */ - if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) - ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + if (ccdev->id.revision < 10) { + tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL); + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL; + tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != + SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL) + tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL; + chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp); + + /* For dynamic control, we have to release our xtal_pu + * "force on" */ + if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL) + ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0); + } else { + chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL, + (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) & + ~SSB_CHIPCO_SYSCLKCTL_FORCEHT)); + } break; default: SSB_WARN_ON(1); @@ -260,6 +286,12 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) if (cc->dev->id.revision >= 11) cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); + + if (cc->dev->id.revision >= 20) { + chipco_write32(cc, SSB_CHIPCO_GPIOPULLUP, 0); + chipco_write32(cc, SSB_CHIPCO_GPIOPULLDOWN, 0); + } + ssb_pmu_init(cc); chipco_powercontrol_init(cc); ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 5732bb2..305ade7 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -423,6 +423,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc) switch (bus->chip_id) { case 0x4312: + min_msk = 0xCBB; + break; case 0x4322: /* We keep the default settings: * min_msk = 0xCBB diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 1ba9f0e..8fde122 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -21,6 +21,8 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address); static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device, u8 address, u16 data); +static void ssb_commit_settings(struct ssb_bus *bus); + static inline u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset) { @@ -412,6 +414,16 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc) * Workarounds. **************************************************/ +static void ssb_pcicore_fix_sprom_core_index(struct ssb_pcicore *pc) +{ + u16 tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(0)); + if (((tmp & 0xF000) >> 12) != pc->dev->core_index) { + tmp &= ~0xF000; + tmp |= (pc->dev->core_index << 12); + pcicore_write16(pc, SSB_PCICORE_SPROM(0), tmp); + } +} + static u8 ssb_pcicore_polarity_workaround(struct ssb_pcicore *pc) { return (ssb_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80; @@ -430,6 +442,76 @@ static void ssb_pcicore_serdes_workaround(struct ssb_pcicore *pc) ssb_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000); } +static void ssb_pcicore_pci_setup_workarounds(struct ssb_pcicore *pc) +{ + struct ssb_device *pdev = pc->dev; + struct ssb_bus *bus = pdev->bus; + u32 tmp; + + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_PREF; + tmp |= SSB_PCICORE_SBTOPCI_BURST; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + + if (pdev->id.revision < 5) { + tmp = ssb_read32(pdev, SSB_IMCFGLO); + tmp &= ~SSB_IMCFGLO_SERTO; + tmp |= 2; + tmp &= ~SSB_IMCFGLO_REQTO; + tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; + ssb_write32(pdev, SSB_IMCFGLO, tmp); + ssb_commit_settings(bus); + } else if (pdev->id.revision >= 11) { + tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); + tmp |= SSB_PCICORE_SBTOPCI_MRM; + pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); + } +} + +static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) +{ + u32 tmp; + u8 rev = pc->dev->id.revision; + + if (rev == 0 || rev == 1) { + /* TLP Workaround register. */ + tmp = ssb_pcie_read(pc, 0x4); + tmp |= 0x8; + ssb_pcie_write(pc, 0x4, tmp); + } + if (rev == 1) { + /* DLLP Link Control register. */ + tmp = ssb_pcie_read(pc, 0x100); + tmp |= 0x40; + ssb_pcie_write(pc, 0x100, tmp); + } + + if (rev == 0) { + const u8 serdes_rx_device = 0x1F; + + ssb_pcie_mdio_write(pc, serdes_rx_device, + 2 /* Timer */, 0x8128); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 6 /* CDR */, 0x0100); + ssb_pcie_mdio_write(pc, serdes_rx_device, + 7 /* CDR BW */, 0x1466); + } else if (rev == 3 || rev == 4 || rev == 5) { + /* TODO: DLLP Power Management Threshold */ + ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + } else if (rev == 7) { + /* TODO: No PLL down */ + } + + if (rev >= 6) { + /* Miscellaneous Configuration Fixup */ + tmp = pcicore_read16(pc, SSB_PCICORE_SPROM(5)); + if (!(tmp & 0x8000)) + pcicore_write16(pc, SSB_PCICORE_SPROM(5), + tmp | 0x8000); + } +} + /************************************************** * Generic and Clientmode operation code. **************************************************/ @@ -449,6 +531,8 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!ssb_device_is_enabled(dev)) ssb_device_enable(dev, 0); + ssb_pcicore_fix_sprom_core_index(pc); + #ifdef CONFIG_SSB_PCICORE_HOSTMODE pc->hostmode = pcicore_is_in_hostmode(pc); if (pc->hostmode) @@ -457,7 +541,10 @@ void ssb_pcicore_init(struct ssb_pcicore *pc) if (!pc->hostmode) ssb_pcicore_init_clientmode(pc); + /* Additional always once-executed workarounds */ ssb_pcicore_serdes_workaround(pc); + /* TODO: ASPM */ + /* TODO: Clock Request Update */ } static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address) @@ -522,7 +609,7 @@ static u16 ssb_pcie_mdio_read(struct ssb_pcicore *pc, u8 device, u8 address) pcicore_write32(pc, mdio_data, v); /* Wait for the device to complete the transaction */ udelay(10); - for (i = 0; i < 200; i++) { + for (i = 0; i < max_retries; i++) { v = pcicore_read32(pc, mdio_control); if (v & 0x100 /* Trans complete */) { udelay(10); @@ -646,48 +733,10 @@ int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc, if (pc->setup_done) goto out; if (pdev->id.coreid == SSB_DEV_PCI) { - tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); - tmp |= SSB_PCICORE_SBTOPCI_PREF; - tmp |= SSB_PCICORE_SBTOPCI_BURST; - pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); - - if (pdev->id.revision < 5) { - tmp = ssb_read32(pdev, SSB_IMCFGLO); - tmp &= ~SSB_IMCFGLO_SERTO; - tmp |= 2; - tmp &= ~SSB_IMCFGLO_REQTO; - tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT; - ssb_write32(pdev, SSB_IMCFGLO, tmp); - ssb_commit_settings(bus); - } else if (pdev->id.revision >= 11) { - tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2); - tmp |= SSB_PCICORE_SBTOPCI_MRM; - pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp); - } + ssb_pcicore_pci_setup_workarounds(pc); } else { WARN_ON(pdev->id.coreid != SSB_DEV_PCIE); - //TODO: Better make defines for all these magic PCIE values. - if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) { - /* TLP Workaround register. */ - tmp = ssb_pcie_read(pc, 0x4); - tmp |= 0x8; - ssb_pcie_write(pc, 0x4, tmp); - } - if (pdev->id.revision == 0) { - const u8 serdes_rx_device = 0x1F; - - ssb_pcie_mdio_write(pc, serdes_rx_device, - 2 /* Timer */, 0x8128); - ssb_pcie_mdio_write(pc, serdes_rx_device, - 6 /* CDR */, 0x0100); - ssb_pcie_mdio_write(pc, serdes_rx_device, - 7 /* CDR BW */, 0x1466); - } else if (pdev->id.revision == 1) { - /* DLLP Link Control register. */ - tmp = ssb_pcie_read(pc, 0x100); - tmp |= 0x40; - ssb_pcie_write(pc, 0x100, tmp); - } + ssb_pcicore_pcie_setup_workarounds(pc); } pc->setup_done = 1; out: diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index e05ba6e..ad3da93 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1117,23 +1117,22 @@ static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) { u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV; - /* The REJECT bit changed position in TMSLOW between - * Backplane revisions. */ + /* The REJECT bit seems to be different for Backplane rev 2.3 */ switch (rev) { case SSB_IDLOW_SSBREV_22: - return SSB_TMSLOW_REJECT_22; + case SSB_IDLOW_SSBREV_24: + case SSB_IDLOW_SSBREV_26: + return SSB_TMSLOW_REJECT; case SSB_IDLOW_SSBREV_23: return SSB_TMSLOW_REJECT_23; - case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */ - case SSB_IDLOW_SSBREV_25: /* same here */ - case SSB_IDLOW_SSBREV_26: /* same here */ + case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */ case SSB_IDLOW_SSBREV_27: /* same here */ - return SSB_TMSLOW_REJECT_23; /* this is a guess */ + return SSB_TMSLOW_REJECT; /* this is a guess */ default: printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); WARN_ON(1); } - return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); + return (SSB_TMSLOW_REJECT | SSB_TMSLOW_REJECT_23); } int ssb_device_is_enabled(struct ssb_device *dev) @@ -1309,20 +1308,20 @@ EXPORT_SYMBOL(ssb_bus_may_powerdown); int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl) { - struct ssb_chipcommon *cc; int err; enum ssb_clkmode mode; err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); if (err) goto error; - cc = &bus->chipco; - mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; - ssb_chipco_set_clockmode(cc, mode); #ifdef CONFIG_SSB_DEBUG bus->powered_up = 1; #endif + + mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST; + ssb_chipco_set_clockmode(&bus->chipco, mode); + return 0; error: ssb_printk(KERN_ERR PFX "Bus powerup failed\n"); diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index 020387a..60a7c49 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -28,6 +28,8 @@ struct ath9k_platform_data { int led_pin; u32 gpio_mask; u32 gpio_val; + + bool is_clk_25mhz; }; #endif /* _LINUX_ATH9K_PLATFORM_H */ diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index 2cdf249..a08d693 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h @@ -123,6 +123,8 @@ #define SSB_CHIPCO_FLASHDATA 0x0048 #define SSB_CHIPCO_BCAST_ADDR 0x0050 #define SSB_CHIPCO_BCAST_DATA 0x0054 +#define SSB_CHIPCO_GPIOPULLUP 0x0058 /* Rev >= 20 only */ +#define SSB_CHIPCO_GPIOPULLDOWN 0x005C /* Rev >= 20 only */ #define SSB_CHIPCO_GPIOIN 0x0060 #define SSB_CHIPCO_GPIOOUT 0x0064 #define SSB_CHIPCO_GPIOOUTEN 0x0068 @@ -131,6 +133,9 @@ #define SSB_CHIPCO_GPIOIRQ 0x0074 #define SSB_CHIPCO_WATCHDOG 0x0080 #define SSB_CHIPCO_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */ +#define SSB_CHIPCO_GPIOTIMER_OFFTIME 0x0000FFFF +#define SSB_CHIPCO_GPIOTIMER_OFFTIME_SHIFT 0 +#define SSB_CHIPCO_GPIOTIMER_ONTIME 0xFFFF0000 #define SSB_CHIPCO_GPIOTIMER_ONTIME_SHIFT 16 #define SSB_CHIPCO_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */ #define SSB_CHIPCO_CLOCK_N 0x0090 @@ -189,8 +194,10 @@ #define SSB_CHIPCO_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ #define SSB_CHIPCO_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ #define SSB_CHIPCO_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ -#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00010000 /* HT available */ -#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00020000 /* APL available */ +#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00010000 /* ALP available */ +#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00020000 /* HT available */ +#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */ +#define SSB_CHIPCO_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */ #define SSB_CHIPCO_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ #define SSB_CHIPCO_UART0_DATA 0x0300 #define SSB_CHIPCO_UART0_IMR 0x0304 diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 402955a..efbf459 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -97,7 +97,7 @@ #define SSB_INTVEC_ENET1 0x00000040 /* Enable interrupts for enet 1 */ #define SSB_TMSLOW 0x0F98 /* SB Target State Low */ #define SSB_TMSLOW_RESET 0x00000001 /* Reset */ -#define SSB_TMSLOW_REJECT_22 0x00000002 /* Reject (Backplane rev 2.2) */ +#define SSB_TMSLOW_REJECT 0x00000002 /* Reject (Standard Backplane) */ #define SSB_TMSLOW_REJECT_23 0x00000004 /* Reject (Backplane rev 2.3) */ #define SSB_TMSLOW_CLOCK 0x00010000 /* Clock Enable */ #define SSB_TMSLOW_FGC 0x00020000 /* Force Gated Clocks On */ diff --git a/include/linux/wl12xx.h b/include/linux/wl12xx.h index bebb8ef..4b69739 100644 --- a/include/linux/wl12xx.h +++ b/include/linux/wl12xx.h @@ -24,12 +24,26 @@ #ifndef _LINUX_WL12XX_H #define _LINUX_WL12XX_H -/* The board reference clock values */ +/* Reference clock values */ enum { - WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ - WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ - WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ - WL12XX_REFCLOCK_54 = 3, /* 54 MHz */ + WL12XX_REFCLOCK_19 = 0, /* 19.2 MHz */ + WL12XX_REFCLOCK_26 = 1, /* 26 MHz */ + WL12XX_REFCLOCK_38 = 2, /* 38.4 MHz */ + WL12XX_REFCLOCK_52 = 3, /* 52 MHz */ + WL12XX_REFCLOCK_38_XTAL = 4, /* 38.4 MHz, XTAL */ + WL12XX_REFCLOCK_26_XTAL = 5, /* 26 MHz, XTAL */ +}; + +/* TCXO clock values */ +enum { + WL12XX_TCXOCLOCK_19_2 = 0, /* 19.2MHz */ + WL12XX_TCXOCLOCK_26 = 1, /* 26 MHz */ + WL12XX_TCXOCLOCK_38_4 = 2, /* 38.4MHz */ + WL12XX_TCXOCLOCK_52 = 3, /* 52 MHz */ + WL12XX_TCXOCLOCK_16_368 = 4, /* 16.368 MHz */ + WL12XX_TCXOCLOCK_32_736 = 5, /* 32.736 MHz */ + WL12XX_TCXOCLOCK_16_8 = 6, /* 16.8 MHz */ + WL12XX_TCXOCLOCK_33_6 = 7, /* 33.6 MHz */ }; struct wl12xx_platform_data { @@ -38,8 +52,13 @@ struct wl12xx_platform_data { int irq; bool use_eeprom; int board_ref_clock; + int board_tcxo_clock; + unsigned long platform_quirks; }; +/* Platform does not support level trigger interrupts */ +#define WL12XX_PLATFORM_QUIRK_EDGE_IRQ BIT(0) + #ifdef CONFIG_WL12XX_PLATFORM_DATA int wl12xx_set_platform_data(const struct wl12xx_platform_data *data); diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 499b7b7..0c20227 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -246,6 +246,15 @@ enum { #define HCI_AT_GENERAL_BONDING 0x04 #define HCI_AT_GENERAL_BONDING_MITM 0x05 +/* Link Key types */ +#define HCI_LK_COMBINATION 0x00 +#define HCI_LK_LOCAL_UNIT 0x01 +#define HCI_LK_REMOTE_UNIT 0x02 +#define HCI_LK_DEBUG_COMBINATION 0x03 +#define HCI_LK_UNAUTH_COMBINATION 0x04 +#define HCI_LK_AUTH_COMBINATION 0x05 +#define HCI_LK_CHANGED_COMBINATION 0x06 + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4093133..14cc324 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -126,6 +126,8 @@ struct hci_dev { __u16 sniff_min_interval; __u16 sniff_max_interval; + unsigned int auto_accept_delay; + unsigned long quirks; atomic_t cmd_cnt; @@ -226,6 +228,7 @@ struct hci_conn { __u16 pkt_type; __u16 link_policy; __u32 link_mode; + __u8 key_type; __u8 auth_type; __u8 sec_level; __u8 pending_sec_level; @@ -245,6 +248,7 @@ struct hci_conn { struct timer_list disc_timer; struct timer_list idle_timer; + struct timer_list auto_accept_timer; struct work_struct work_add; struct work_struct work_del; @@ -511,8 +515,8 @@ int hci_uuids_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 *key, u8 type, u8 pin_len); +int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remote_oob_data_clear(struct hci_dev *hdev); @@ -771,15 +775,16 @@ int mgmt_index_removed(u16 index); int mgmt_powered(u16 index, u8 powered); int mgmt_discoverable(u16 index, u8 discoverable); int mgmt_connectable(u16 index, u8 connectable); -int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type); +int mgmt_new_key(u16 index, struct link_key *key, u8 persistent); int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnect_failed(u16 index); int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status); -int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr); +int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure); int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); -int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value); +int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, + u8 confirm_hint); int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status); @@ -790,6 +795,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, u8 *eir); int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name); +int mgmt_discovering(u16 index, u8 discovering); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7a215a7..c34b1c1 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -284,6 +284,25 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + + struct l2cap_conn *conn; + + __le16 psm; + __u16 dcid; + __u16 scid; + + __u16 imtu; + __u16 omtu; + __u16 flush_to; + __u8 mode; + + __le16 sport; + + __u8 sec_level; + __u8 role_switch; + __u8 force_reliable; + __u8 flushable; + __u8 ident; __u8 conf_req[64]; @@ -291,6 +310,15 @@ struct l2cap_chan { __u8 num_conf_req; __u8 num_conf_rsp; + __u8 fcs; + + __u8 tx_win; + __u8 max_tx; + __u16 retrans_timeout; + __u16 monitor_timeout; + __u16 mps; + + __u8 conf_state; __u16 conn_state; __u8 next_tx_seq; @@ -360,32 +388,6 @@ struct l2cap_conn { struct l2cap_pinfo { struct bt_sock bt; - __le16 psm; - __u16 dcid; - __u16 scid; - - __u16 imtu; - __u16 omtu; - __u16 flush_to; - __u8 mode; - - __u8 fcs; - __u8 sec_level; - __u8 role_switch; - __u8 force_reliable; - __u8 flushable; - - __u8 conf_state; - - __u8 tx_win; - __u8 max_tx; - __u16 retrans_timeout; - __u16 monitor_timeout; - __u16 mps; - - __le16 sport; - - struct l2cap_conn *conn; struct l2cap_chan *chan; }; @@ -439,21 +441,20 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) extern int disable_ertm; -extern const struct proto_ops l2cap_sock_ops; extern struct bt_sock_list l2cap_sk_list; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); -void __l2cap_connect_rsp_defer(struct sock *sk); +void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); int __l2cap_wait_ack(struct sock *sk); -struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); -struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); -struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); +struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); +struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); +struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); -void l2cap_do_send(struct sock *sk, struct sk_buff *skb); +void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); @@ -465,7 +466,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); +struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); -int l2cap_do_connect(struct sock *sk); +void l2cap_chan_free(struct l2cap_chan *chan); +int l2cap_chan_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 6b6ff92..4899286 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data { bdaddr_t bdaddr; } __packed; +#define MGMT_OP_START_DISCOVERY 0x001B + +#define MGMT_OP_STOP_DISCOVERY 0x001C + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; @@ -226,8 +230,8 @@ struct mgmt_ev_controller_error { #define MGMT_EV_NEW_KEY 0x000A struct mgmt_ev_new_key { + __u8 store_hint; struct mgmt_key_info key; - __u8 old_key_type; } __packed; #define MGMT_EV_CONNECTED 0x000B @@ -249,11 +253,13 @@ struct mgmt_ev_connect_failed { #define MGMT_EV_PIN_CODE_REQUEST 0x000E struct mgmt_ev_pin_code_request { bdaddr_t bdaddr; + __u8 secure; } __packed; #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F struct mgmt_ev_user_confirm_request { bdaddr_t bdaddr; + __u8 confirm_hint; __le32 value; } __packed; @@ -281,3 +287,5 @@ struct mgmt_ev_remote_name { bdaddr_t bdaddr; __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; + +#define MGMT_EV_DISCOVERING 0x0014 diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d23dd6c..db4b6b9 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1822,6 +1822,10 @@ enum ieee80211_ampdu_mlme_action { * * @tx_frames_pending: Check if there is any pending frame in the hardware * queues before entering power save. + * + * @set_bitrate_mask: Set a mask of rates to be used for rate control selection + * when transmitting a frame. Currently only legacy rates are handled. + * The callback can sleep. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); @@ -1910,6 +1914,8 @@ struct ieee80211_ops { void (*get_ringparam)(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); bool (*tx_frames_pending)(struct ieee80211_hw *hw); + int (*set_bitrate_mask)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask); }; /** @@ -2292,6 +2298,17 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb); /** + * ieee80211_report_low_ack - report non-responding station + * + * When operating in AP-mode, call this function to report a non-responding + * connected STA. + * + * @sta: the non-responding connected sta + * @num_packets: number of packets sent to @sta without a response + */ +void ieee80211_report_low_ack(struct ieee80211_sta *sta, u32 num_packets); + +/** * ieee80211_beacon_get_tim - beacon generation function * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from the add_interface callback. diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index cce99b0..c5b11af 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst); - session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); + session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu, + l2cap_pi(sock->sk)->chan->imtu); BT_DBG("mtu %d", session->mtu); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7a6f56b..7f5ad8a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg) hci_conn_enter_sniff_mode(conn); } +static void hci_conn_auto_accept(unsigned long arg) +{ + struct hci_conn *conn = (void *) arg; + struct hci_dev *hdev = conn->hdev; + + hci_dev_lock(hdev); + + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), + &conn->dst); + + hci_dev_unlock(hdev); +} + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *conn; @@ -287,6 +300,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->auth_type = HCI_AT_GENERAL_BONDING; conn->io_capability = hdev->io_capability; conn->remote_auth = 0xff; + conn->key_type = 0xff; conn->power_save = 1; conn->disc_timeout = HCI_DISCONN_TIMEOUT; @@ -311,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); + setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, + (unsigned long) conn); atomic_set(&conn->refcnt, 0); @@ -341,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn) del_timer(&conn->disc_timer); + del_timer(&conn->auto_accept_timer); + if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; if (sco) @@ -535,32 +553,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) return 0; } +/* Encrypt the the link */ +static void hci_conn_encrypt(struct hci_conn *conn) +{ + BT_DBG("conn %p", conn); + + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + struct hci_cp_set_conn_encrypt cp; + cp.handle = cpu_to_le16(conn->handle); + cp.encrypt = 0x01; + hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), + &cp); + } +} + /* Enable security */ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) { BT_DBG("conn %p", conn); + /* For sdp we don't need the link key. */ if (sec_level == BT_SECURITY_SDP) return 1; + /* For non 2.1 devices and low security level we don't need the link + key. */ if (sec_level == BT_SECURITY_LOW && (!conn->ssp_mode || !conn->hdev->ssp_mode)) return 1; - if (conn->link_mode & HCI_LM_ENCRYPT) - return hci_conn_auth(conn, sec_level, auth_type); - + /* For other security levels we need the link key. */ + if (!(conn->link_mode & HCI_LM_AUTH)) + goto auth; + + /* An authenticated combination key has sufficient security for any + security level. */ + if (conn->key_type == HCI_LK_AUTH_COMBINATION) + goto encrypt; + + /* An unauthenticated combination key has sufficient security for + security level 1 and 2. */ + if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && + (sec_level == BT_SECURITY_MEDIUM || + sec_level == BT_SECURITY_LOW)) + goto encrypt; + + /* A combination key has always sufficient security for the security + levels 1 or 2. High security level requires the combination key + is generated using maximum PIN code length (16). + For pre 2.1 units. */ + if (conn->key_type == HCI_LK_COMBINATION && + (sec_level != BT_SECURITY_HIGH || + conn->pin_length == 16)) + goto encrypt; + +auth: if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return 0; - if (hci_conn_auth(conn, sec_level, auth_type)) { - struct hci_cp_set_conn_encrypt cp; - cp.handle = cpu_to_le16(conn->handle); - cp.encrypt = 1; - hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, - sizeof(cp), &cp); - } + hci_conn_auth(conn, sec_level, auth_type); + return 0; + +encrypt: + if (conn->link_mode & HCI_LM_ENCRYPT) + return 1; + hci_conn_encrypt(conn); return 0; } EXPORT_SYMBOL(hci_conn_security); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e057d12..815269b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1020,18 +1020,54 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return NULL; } -int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 *val, u8 type, u8 pin_len) +static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, + u8 key_type, u8 old_key_type) +{ + /* Legacy key */ + if (key_type < 0x03) + return 1; + + /* Debug keys are insecure so don't store them persistently */ + if (key_type == HCI_LK_DEBUG_COMBINATION) + return 0; + + /* Changed combination key and there's no previous one */ + if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff) + return 0; + + /* Security mode 3 case */ + if (!conn) + return 1; + + /* Neither local nor remote side had no-bonding as requirement */ + if (conn->auth_type > 0x01 && conn->remote_auth > 0x01) + return 1; + + /* Local side had dedicated bonding as requirement */ + if (conn->auth_type == 0x02 || conn->auth_type == 0x03) + return 1; + + /* Remote side had dedicated bonding as requirement */ + if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) + return 1; + + /* If none of the above criteria match, then don't store the key + * persistently */ + return 0; +} + +int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; - u8 old_key_type; + u8 old_key_type, persistent; old_key = hci_find_link_key(hdev, bdaddr); if (old_key) { old_key_type = old_key->type; key = old_key; } else { - old_key_type = 0xff; + old_key_type = conn ? conn->key_type : 0xff; key = kzalloc(sizeof(*key), GFP_ATOMIC); if (!key) return -ENOMEM; @@ -1040,16 +1076,37 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); + /* Some buggy controller combinations generate a changed + * combination key for legacy pairing even when there's no + * previous key */ + if (type == HCI_LK_CHANGED_COMBINATION && + (!conn || conn->remote_auth == 0xff) && + old_key_type == 0xff) { + type = HCI_LK_COMBINATION; + if (conn) + conn->key_type = type; + } + bacpy(&key->bdaddr, bdaddr); memcpy(key->val, val, 16); - key->type = type; key->pin_len = pin_len; - if (new_key) - mgmt_new_key(hdev->id, key, old_key_type); - - if (type == 0x06) + if (type == HCI_LK_CHANGED_COMBINATION) key->type = old_key_type; + else + key->type = type; + + if (!new_key) + return 0; + + persistent = hci_persistent_key(hdev, conn, type, old_key_type); + + mgmt_new_key(hdev->id, key, persistent); + + if (!persistent) { + list_del(&key->list); + kfree(key); + } return 0; } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cb25628..d5aa97e 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); @@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_conn_check_pending(hdev); } @@ -841,10 +845,14 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) if (status) { hci_req_complete(hdev, HCI_OP_INQUIRY, status); - hci_conn_check_pending(hdev); - } else - set_bit(HCI_INQUIRY, &hdev->flags); + return; + } + + if (test_bit(HCI_MGMT, &hdev->flags) && + !test_and_set_bit(HCI_INQUIRY, + &hdev->flags)) + mgmt_discovering(hdev->id, 1); } static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) @@ -1013,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); - if (conn && hci_outgoing_auth_needed(hdev, conn)) { + if (!conn) + goto unlock; + + if (!hci_outgoing_auth_needed(hdev, conn)) + goto unlock; + + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } +unlock: hci_dev_unlock(hdev); } @@ -1208,7 +1223,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s status %d", hdev->name, status); - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_req_complete(hdev, HCI_OP_INQUIRY, status); @@ -1228,6 +1245,12 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); + if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_discovering(hdev->id, 1); + } + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; @@ -1443,7 +1466,6 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s conn->sec_level = conn->pending_sec_level; } else { mgmt_auth_failed(hdev->id, &conn->dst, ev->status); - conn->sec_level = BT_SECURITY_LOW; } clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); @@ -1501,12 +1523,19 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - if (conn && hci_outgoing_auth_needed(hdev, conn)) { + if (!conn) + goto unlock; + + if (!hci_outgoing_auth_needed(hdev, conn)) + goto unlock; + + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } +unlock: hci_dev_unlock(hdev); } @@ -2006,9 +2035,16 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff if (!test_bit(HCI_PAIRABLE, &hdev->flags)) hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); + else if (test_bit(HCI_MGMT, &hdev->flags)) { + u8 secure; - if (test_bit(HCI_MGMT, &hdev->flags)) - mgmt_pin_code_request(hdev->id, &ev->bdaddr); + if (conn->pending_sec_level == BT_SECURITY_HIGH) + secure = 1; + else + secure = 0; + + mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); + } hci_dev_unlock(hdev); } @@ -2037,17 +2073,30 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s found key type %u for %s", hdev->name, key->type, batostr(&ev->bdaddr)); - if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) { + if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && + key->type == HCI_LK_DEBUG_COMBINATION) { BT_DBG("%s ignoring debug key", hdev->name); goto not_found; } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (conn) { + if (key->type == HCI_LK_UNAUTH_COMBINATION && + conn->auth_type != 0xff && + (conn->auth_type & 0x01)) { + BT_DBG("%s ignoring unauthenticated key", hdev->name); + goto not_found; + } - if (key->type == 0x04 && conn && conn->auth_type != 0xff && - (conn->auth_type & 0x01)) { - BT_DBG("%s ignoring unauthenticated key", hdev->name); - goto not_found; + if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 && + conn->pending_sec_level == BT_SECURITY_HIGH) { + BT_DBG("%s ignoring key unauthenticated for high \ + security", hdev->name); + goto not_found; + } + + conn->key_type = key->type; + conn->pin_length = key->pin_len; } bacpy(&cp.bdaddr, &ev->bdaddr); @@ -2079,11 +2128,15 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; pin_len = conn->pin_length; + + if (ev->key_type != HCI_LK_CHANGED_COMBINATION) + conn->key_type = ev->key_type; + hci_conn_put(conn); } if (test_bit(HCI_LINK_KEYS, &hdev->flags)) - hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key, + hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, ev->key_type, pin_len); hci_dev_unlock(hdev); @@ -2158,6 +2211,12 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct hci_dev_lock(hdev); + if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_discovering(hdev->id, 1); + } + if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) { struct inquiry_info_with_rssi_and_pscan_mode *info; info = (void *) (skb->data + 1); @@ -2320,6 +2379,12 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct if (!num_rsp) return; + if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) { + + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_discovering(hdev->id, 1); + } + hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { @@ -2353,7 +2418,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn) /* If remote requests no-bonding follow that lead */ if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01) - return 0x00; + return conn->remote_auth | (conn->auth_type & 0x01); return conn->auth_type; } @@ -2382,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &ev->bdaddr); cp.capability = conn->io_capability; - cp.authentication = hci_get_auth_req(conn); + conn->auth_type = hci_get_auth_req(conn); + cp.authentication = conn->auth_type; if ((conn->out == 0x01 || conn->remote_oob == 0x01) && hci_find_remote_oob_data(hdev, &conn->dst)) @@ -2396,7 +2462,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff struct hci_cp_io_capability_neg_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); - cp.reason = 0x16; /* Pairing not allowed */ + cp.reason = 0x18; /* Pairing not allowed */ hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY, sizeof(cp), &cp); @@ -2431,14 +2497,67 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_user_confirm_req *ev = (void *) skb->data; + int loc_mitm, rem_mitm, confirm_hint = 0; + struct hci_conn *conn; BT_DBG("%s", hdev->name); hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) - mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); + if (!test_bit(HCI_MGMT, &hdev->flags)) + goto unlock; + + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (!conn) + goto unlock; + + loc_mitm = (conn->auth_type & 0x01); + rem_mitm = (conn->remote_auth & 0x01); + + /* If we require MITM but the remote device can't provide that + * (it has NoInputNoOutput) then reject the confirmation + * request. The only exception is when we're dedicated bonding + * initiators (connect_cfm_cb set) since then we always have the MITM + * bit set. */ + if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) { + BT_DBG("Rejecting request: remote device can't provide MITM"); + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); + goto unlock; + } + + /* If no side requires MITM protection; auto-accept */ + if ((!loc_mitm || conn->remote_cap == 0x03) && + (!rem_mitm || conn->io_capability == 0x03)) { + /* If we're not the initiators request authorization to + * proceed from user space (mgmt_user_confirm with + * confirm_hint set to 1). */ + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + BT_DBG("Confirming auto-accept as acceptor"); + confirm_hint = 1; + goto confirm; + } + + BT_DBG("Auto-accept of user confirmation with %ums delay", + hdev->auto_accept_delay); + + if (hdev->auto_accept_delay > 0) { + int delay = msecs_to_jiffies(hdev->auto_accept_delay); + mod_timer(&conn->auto_accept_timer, jiffies + delay); + goto unlock; + } + + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); + goto unlock; + } + +confirm: + mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey, + confirm_hint); + +unlock: hci_dev_unlock(hdev); } diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 8775933..a6c3aa8 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -511,6 +511,35 @@ static const struct file_operations uuids_fops = { .release = single_release, }; +static int auto_accept_delay_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock_bh(hdev); + + hdev->auto_accept_delay = val; + + hci_dev_unlock_bh(hdev); + + return 0; +} + +static int auto_accept_delay_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock_bh(hdev); + + *val = hdev->auto_accept_delay; + + hci_dev_unlock_bh(hdev); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, + auto_accept_delay_set, "%llu\n"); + int hci_register_sysfs(struct hci_dev *hdev) { struct device *dev = &hdev->dev; @@ -545,6 +574,8 @@ int hci_register_sysfs(struct hci_dev *hdev) debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); + debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev, + &auto_accept_delay_fops); return 0; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index ae6ebc6..c405a95 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -979,8 +979,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); - session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); - session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); + session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu, + l2cap_pi(ctrl_sock->sk)->chan->imtu); + session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu, + l2cap_pi(intr_sock->sk)->chan->imtu); BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index fd3c1f3..a378acc 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -80,8 +80,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->dcid == cid) + if (c->dcid == cid) return c; } return NULL; @@ -93,8 +92,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->scid == cid) + if (c->scid == cid) return c; } return NULL; @@ -149,7 +147,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) +struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) { struct l2cap_chan *chan; @@ -162,38 +160,43 @@ static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) return chan; } +void l2cap_chan_free(struct l2cap_chan *chan) +{ + kfree(chan); +} + static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { struct sock *sk = chan->sk; BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, - l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + chan->psm, chan->dcid); conn->disc_reason = 0x13; - l2cap_pi(sk)->conn = conn; + chan->conn = conn; if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { if (conn->hcon->type == LE_LINK) { /* LE connection */ - l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU; - l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA; - l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; + chan->omtu = L2CAP_LE_DEFAULT_MTU; + chan->scid = L2CAP_CID_LE_DATA; + chan->dcid = L2CAP_CID_LE_DATA; } else { /* Alloc CID for connection-oriented socket */ - l2cap_pi(sk)->scid = l2cap_alloc_cid(conn); - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->scid = l2cap_alloc_cid(conn); + chan->omtu = L2CAP_DEFAULT_MTU; } } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ - l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; - l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->scid = L2CAP_CID_CONN_LESS; + chan->dcid = L2CAP_CID_CONN_LESS; + chan->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ - l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; - l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->scid = L2CAP_CID_SIGNALING; + chan->dcid = L2CAP_CID_SIGNALING; + chan->omtu = L2CAP_DEFAULT_MTU; } sock_hold(sk); @@ -206,7 +209,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) void l2cap_chan_del(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sock *parent = bt_sk(sk)->parent; l2cap_sock_clear_timer(sk); @@ -220,7 +223,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) write_unlock_bh(&conn->chan_lock); __sock_put(sk); - l2cap_pi(sk)->conn = NULL; + chan->conn = NULL; hci_conn_put(conn->hcon); } @@ -236,13 +239,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE && - l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE)) - goto free; + if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE && + chan->conf_state & L2CAP_CONF_INPUT_DONE)) + return; skb_queue_purge(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + if (chan->mode == L2CAP_MODE_ERTM) { struct srej_list *l, *tmp; del_timer(&chan->retrans_timer); @@ -257,15 +260,14 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) kfree(l); } } - -free: - kfree(chan); } -static inline u8 l2cap_get_auth_type(struct sock *sk) +static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; + if (sk->sk_type == SOCK_RAW) { - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_HIGH: return HCI_AT_DEDICATED_BONDING_MITM; case BT_SECURITY_MEDIUM: @@ -273,16 +275,16 @@ static inline u8 l2cap_get_auth_type(struct sock *sk) default: return HCI_AT_NO_BONDING; } - } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) - l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + } else if (chan->psm == cpu_to_le16(0x0001)) { + if (chan->sec_level == BT_SECURITY_LOW) + chan->sec_level = BT_SECURITY_SDP; - if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + if (chan->sec_level == BT_SECURITY_HIGH) return HCI_AT_NO_BONDING_MITM; else return HCI_AT_NO_BONDING; } else { - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_HIGH: return HCI_AT_GENERAL_BONDING_MITM; case BT_SECURITY_MEDIUM: @@ -294,15 +296,14 @@ static inline u8 l2cap_get_auth_type(struct sock *sk) } /* Service level security */ -static inline int l2cap_check_security(struct sock *sk) +static inline int l2cap_check_security(struct l2cap_chan *chan) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; __u8 auth_type; - auth_type = l2cap_get_auth_type(sk); + auth_type = l2cap_get_auth_type(chan); - return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level, - auth_type); + return hci_conn_security(conn->hcon, chan->sec_level, auth_type); } u8 l2cap_get_ident(struct l2cap_conn *conn) @@ -350,7 +351,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) struct sk_buff *skb; struct l2cap_hdr *lh; struct l2cap_pinfo *pi = l2cap_pi(chan->sk); - struct l2cap_conn *conn = pi->conn; + struct l2cap_conn *conn = chan->conn; struct sock *sk = (struct sock *)pi; int count, hlen = L2CAP_HDR_SIZE + 2; u8 flags; @@ -358,7 +359,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) if (sk->sk_state != BT_CONNECTED) return; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) hlen += 2; BT_DBG("chan %p, control 0x%2.2x", chan, control); @@ -382,10 +383,10 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(pi->dcid); + lh->cid = cpu_to_le16(chan->dcid); put_unaligned_le16(control, skb_put(skb, 2)); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { u16 fcs = crc16(0, (u8 *)lh, count - 2); put_unaligned_le16(fcs, skb_put(skb, 2)); } @@ -395,7 +396,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) else flags = ACL_START; - hci_send_acl(pi->conn->hcon, skb, flags); + hci_send_acl(chan->conn->hcon, skb, flags); } static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) @@ -411,27 +412,27 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) l2cap_send_sframe(chan, control); } -static inline int __l2cap_no_conn_pending(struct sock *sk) +static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) { - return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND); + return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND); } static void l2cap_do_start(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; - if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) { + if (l2cap_check_security(chan) && + __l2cap_no_conn_pending(chan)) { struct l2cap_conn_req req; - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); @@ -477,14 +478,14 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in sk = chan->sk; - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + if (chan->mode == L2CAP_MODE_ERTM) { del_timer(&chan->retrans_timer); del_timer(&chan->monitor_timer); del_timer(&chan->ack_timer); } - req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.dcid = cpu_to_le16(chan->dcid); + req.scid = cpu_to_le16(chan->scid); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); @@ -515,15 +516,15 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (sk->sk_state == BT_CONNECT) { struct l2cap_conn_req req; - if (!l2cap_check_security(sk) || - !__l2cap_no_conn_pending(sk)) { + if (!l2cap_check_security(chan) || + !__l2cap_no_conn_pending(chan)) { bh_unlock_sock(sk); continue; } - if (!l2cap_mode_supported(l2cap_pi(sk)->mode, + if (!l2cap_mode_supported(chan->mode, conn->feat_mask) - && l2cap_pi(sk)->conf_state & + && chan->conf_state & L2CAP_CONF_STATE2_DEVICE) { /* __l2cap_sock_close() calls list_del(chan) * so release the lock */ @@ -534,11 +535,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) continue; } - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); @@ -546,10 +547,10 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } else if (sk->sk_state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; char buf[128]; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); - if (l2cap_check_security(sk)) { + if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); @@ -569,13 +570,13 @@ static void l2cap_conn_start(struct l2cap_conn *conn) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT || + if (chan->conf_state & L2CAP_CONF_REQ_SENT || rsp.result != L2CAP_CR_SUCCESS) { bh_unlock_sock(sk); continue; } - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -598,10 +599,12 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (state && sk->sk_state != state) continue; - if (l2cap_pi(sk)->scid == cid) { + if (chan->scid == cid) { /* Exact match. */ if (!bacmp(&bt_sk(sk)->src, src)) break; @@ -648,6 +651,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) goto clean; } + l2cap_pi(sk)->chan = chan; + write_lock_bh(&conn->chan_lock); hci_conn_hold(conn->hcon); @@ -661,8 +666,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) __l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - l2cap_sock_set_timer(sk, sk->sk_sndtimeo); sk->sk_state = BT_CONNECTED; @@ -722,7 +725,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; - if (l2cap_pi(sk)->force_reliable) + if (chan->force_reliable) sk->sk_err = err; } @@ -828,10 +831,12 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (state && sk->sk_state != state) continue; - if (l2cap_pi(sk)->psm == psm) { + if (chan->psm == psm) { /* Exact match. */ if (!bacmp(&bt_sk(sk)->src, src)) break; @@ -847,19 +852,19 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) return node ? sk : sk1; } -int l2cap_do_connect(struct sock *sk) +int l2cap_chan_connect(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *dst = &bt_sk(sk)->dst; struct l2cap_conn *conn; - struct l2cap_chan *chan; struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; int err; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - l2cap_pi(sk)->psm); + chan->psm); hdev = hci_get_route(dst, src); if (!hdev) @@ -867,14 +872,14 @@ int l2cap_do_connect(struct sock *sk) hci_dev_lock_bh(hdev); - auth_type = l2cap_get_auth_type(sk); + auth_type = l2cap_get_auth_type(chan); - if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) + if (chan->dcid == L2CAP_CID_LE_DATA) hcon = hci_connect(hdev, LE_LINK, dst, - l2cap_pi(sk)->sec_level, auth_type); + chan->sec_level, auth_type); else hcon = hci_connect(hdev, ACL_LINK, dst, - l2cap_pi(sk)->sec_level, auth_type); + chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); @@ -888,20 +893,11 @@ int l2cap_do_connect(struct sock *sk) goto done; } - chan = l2cap_chan_alloc(sk); - if (!chan) { - hci_conn_put(hcon); - err = -ENOMEM; - goto done; - } - /* Update source addr of the socket */ bacpy(src, conn->src); l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -909,7 +905,7 @@ int l2cap_do_connect(struct sock *sk) if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { l2cap_sock_clear_timer(sk); - if (l2cap_check_security(sk)) + if (l2cap_check_security(chan)) sk->sk_state = BT_CONNECTED; } else l2cap_do_start(chan); @@ -925,12 +921,13 @@ done: int __l2cap_wait_ack(struct sock *sk) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; DECLARE_WAITQUEUE(wait, current); int err = 0; int timeo = HZ/5; add_wait_queue(sk_sleep(sk), &wait); - while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + while ((chan->unacked_frames > 0 && chan->conn)) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) @@ -963,7 +960,7 @@ static void l2cap_monitor_timeout(unsigned long arg) bh_lock_sock(sk); if (chan->retry_count >= chan->remote_max_tx) { - l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); bh_unlock_sock(sk); return; } @@ -1011,15 +1008,14 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) del_timer(&chan->retrans_timer); } -void l2cap_do_send(struct sock *sk, struct sk_buff *skb) +void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) { - struct l2cap_pinfo *pi = l2cap_pi(sk); - struct hci_conn *hcon = pi->conn->hcon; + struct hci_conn *hcon = chan->conn->hcon; u16 flags; - BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); + BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len); - if (!pi->flushable && lmp_no_flush_capable(hcon->hdev)) + if (!chan->flushable && lmp_no_flush_capable(hcon->hdev)) flags = ACL_START_NO_FLUSH; else flags = ACL_START; @@ -1029,9 +1025,7 @@ void l2cap_do_send(struct sock *sk, struct sk_buff *skb) void l2cap_streaming_send(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; struct sk_buff *skb; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; while ((skb = skb_dequeue(&chan->tx_q))) { @@ -1039,12 +1033,12 @@ void l2cap_streaming_send(struct l2cap_chan *chan) control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)skb->data, skb->len - 2); put_unaligned_le16(fcs, skb->data + skb->len - 2); } - l2cap_do_send(sk, skb); + l2cap_do_send(chan, skb); chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; } @@ -1052,8 +1046,6 @@ void l2cap_streaming_send(struct l2cap_chan *chan) static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; u16 control, fcs; @@ -1072,7 +1064,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); return; } @@ -1091,19 +1083,18 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2); put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } - l2cap_do_send(sk, tx_skb); + l2cap_do_send(chan, tx_skb); } int l2cap_ertm_send(struct l2cap_chan *chan) { struct sk_buff *skb, *tx_skb; struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; int nsent = 0; @@ -1114,7 +1105,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); break; } @@ -1134,12 +1125,12 @@ int l2cap_ertm_send(struct l2cap_chan *chan) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2); put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); } - l2cap_do_send(sk, tx_skb); + l2cap_do_send(chan, tx_skb); __mod_retrans_timer(); @@ -1210,7 +1201,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; struct sk_buff **frag; int err, sent = 0; @@ -1240,9 +1231,10 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in return sent; } -struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len) +struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; struct l2cap_hdr *lh; @@ -1257,9 +1249,9 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2)); + put_unaligned_le16(chan->psm, skb_put(skb, 2)); err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); if (unlikely(err < 0)) { @@ -1269,9 +1261,10 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s return skb; } -struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len) +struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE; struct l2cap_hdr *lh; @@ -1286,7 +1279,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); @@ -1297,9 +1290,10 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size return skb; } -struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) +struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct sock *sk = chan->sk; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; struct l2cap_hdr *lh; @@ -1312,7 +1306,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz if (sdulen) hlen += 2; - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) hlen += 2; count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1323,7 +1317,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); put_unaligned_le16(control, skb_put(skb, 2)); if (sdulen) @@ -1335,7 +1329,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz return ERR_PTR(err); } - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) put_unaligned_le16(0, skb_put(skb, 2)); bt_cb(skb)->retries = 0; @@ -1344,7 +1338,6 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { - struct sock *sk = chan->sk; struct sk_buff *skb; struct sk_buff_head sar_queue; u16 control; @@ -1352,7 +1345,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; - skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len); + skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1371,7 +1364,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le buflen = len; } - skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0); + skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); if (IS_ERR(skb)) { skb_queue_purge(&sar_queue); return PTR_ERR(skb); @@ -1391,10 +1384,11 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le static void l2cap_chan_ready(struct sock *sk) { struct sock *parent = bt_sk(sk)->parent; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sk %p, parent %p", sk, parent); - l2cap_pi(sk)->conf_state = 0; + chan->conf_state = 0; l2cap_sock_clear_timer(sk); if (!parent) { @@ -1615,9 +1609,8 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_req *req = data; - struct l2cap_conf_rfc rfc = { .mode = pi->mode }; + struct l2cap_conf_rfc rfc = { .mode = chan->mode }; void *ptr = req->data; BT_DBG("chan %p", chan); @@ -1625,26 +1618,26 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) if (chan->num_conf_req || chan->num_conf_rsp) goto done; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE) + if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE) break; /* fall through */ default: - pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask); break; } done: - if (pi->imtu != L2CAP_DEFAULT_MTU) - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + if (chan->imtu != L2CAP_DEFAULT_MTU) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: - if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) && - !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && + !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) break; rfc.mode = L2CAP_MODE_BASIC; @@ -1660,24 +1653,24 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; - rfc.txwin_size = pi->tx_win; - rfc.max_transmit = pi->max_tx; + rfc.txwin_size = chan->tx_win; + rfc.max_transmit = chan->max_tx; rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); - if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) break; - if (pi->fcs == L2CAP_FCS_NONE || - pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { - pi->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + if (chan->fcs == L2CAP_FCS_NONE || + chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; @@ -1688,24 +1681,24 @@ done: rfc.retrans_timeout = 0; rfc.monitor_timeout = 0; rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE); - if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) break; - if (pi->fcs == L2CAP_FCS_NONE || - pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { - pi->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + if (chan->fcs == L2CAP_FCS_NONE || + chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; } - req->dcid = cpu_to_le16(pi->dcid); + req->dcid = cpu_to_le16(chan->dcid); req->flags = cpu_to_le16(0); return ptr - data; @@ -1713,7 +1706,6 @@ done: static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; void *req = chan->conf_req; @@ -1738,7 +1730,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) break; case L2CAP_CONF_FLUSH_TO: - pi->flush_to = val; + chan->flush_to = val; break; case L2CAP_CONF_QOS: @@ -1751,7 +1743,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) case L2CAP_CONF_FCS: if (val == L2CAP_FCS_NONE) - pi->conf_state |= L2CAP_CONF_NO_FCS_RECV; + chan->conf_state |= L2CAP_CONF_NO_FCS_RECV; break; @@ -1768,25 +1760,25 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) if (chan->num_conf_rsp || chan->num_conf_req > 1) goto done; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) { - pi->mode = l2cap_select_mode(rfc.mode, - pi->conn->feat_mask); + if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { + chan->mode = l2cap_select_mode(rfc.mode, + chan->conn->feat_mask); break; } - if (pi->mode != rfc.mode) + if (chan->mode != rfc.mode) return -ECONNREFUSED; break; } done: - if (pi->mode != rfc.mode) { + if (chan->mode != rfc.mode) { result = L2CAP_CONF_UNACCEPT; - rfc.mode = pi->mode; + rfc.mode = chan->mode; if (chan->num_conf_rsp == 1) return -ECONNREFUSED; @@ -1803,23 +1795,23 @@ done: if (mtu < L2CAP_DEFAULT_MIN_MTU) result = L2CAP_CONF_UNACCEPT; else { - pi->omtu = mtu; - pi->conf_state |= L2CAP_CONF_MTU_DONE; + chan->omtu = mtu; + chan->conf_state |= L2CAP_CONF_MTU_DONE; } - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu); switch (rfc.mode) { case L2CAP_MODE_BASIC: - pi->fcs = L2CAP_FCS_NONE; - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->fcs = L2CAP_FCS_NONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; break; case L2CAP_MODE_ERTM: chan->remote_tx_win = rfc.txwin_size; chan->remote_max_tx = rfc.max_transmit; - if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); @@ -1828,7 +1820,7 @@ done: rfc.monitor_timeout = le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1836,12 +1828,12 @@ done: break; case L2CAP_MODE_STREAMING: - if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1852,29 +1844,28 @@ done: result = L2CAP_CONF_UNACCEPT; memset(&rfc, 0, sizeof(rfc)); - rfc.mode = pi->mode; + rfc.mode = chan->mode; } if (result == L2CAP_CONF_SUCCESS) - pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; + chan->conf_state |= L2CAP_CONF_OUTPUT_DONE; } - rsp->scid = cpu_to_le16(pi->dcid); + rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(0x0000); return ptr - data; } -static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, u16 *result) +static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result) { - struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; void *ptr = req->data; int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; - BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data); + BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); @@ -1883,27 +1874,27 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, case L2CAP_CONF_MTU: if (val < L2CAP_DEFAULT_MIN_MTU) { *result = L2CAP_CONF_UNACCEPT; - pi->imtu = L2CAP_DEFAULT_MIN_MTU; + chan->imtu = L2CAP_DEFAULT_MIN_MTU; } else - pi->imtu = val; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + chan->imtu = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); break; case L2CAP_CONF_FLUSH_TO: - pi->flush_to = val; + chan->flush_to = val; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, - 2, pi->flush_to); + 2, chan->flush_to); break; case L2CAP_CONF_RFC: if (olen == sizeof(rfc)) memcpy(&rfc, (void *)val, olen); - if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) && - rfc.mode != pi->mode) + if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) && + rfc.mode != chan->mode) return -ECONNREFUSED; - pi->fcs = 0; + chan->fcs = 0; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1911,78 +1902,74 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, } } - if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode) + if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode) return -ECONNREFUSED; - pi->mode = rfc.mode; + chan->mode = rfc.mode; if (*result == L2CAP_CONF_SUCCESS) { switch (rfc.mode) { case L2CAP_MODE_ERTM: - pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); - pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); + chan->mps = le16_to_cpu(rfc.max_pdu_size); break; case L2CAP_MODE_STREAMING: - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); } } - req->dcid = cpu_to_le16(pi->dcid); + req->dcid = cpu_to_le16(chan->dcid); req->flags = cpu_to_le16(0x0000); return ptr - data; } -static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) +static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags) { struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); - rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(flags); return ptr - data; } -void __l2cap_connect_rsp_defer(struct sock *sk) +void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) { struct l2cap_conn_rsp rsp; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_conn *conn = chan->conn; u8 buf[128]; - sk->sk_state = BT_CONFIG; - - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + if (chan->conf_state & L2CAP_CONF_REQ_SENT) return; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; } -static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) +static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) { - struct l2cap_pinfo *pi = l2cap_pi(sk); int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; - BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); + BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); - if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) + if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING)) return; while (len >= L2CAP_CONF_OPT_SIZE) { @@ -1999,12 +1986,12 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) done: switch (rfc.mode) { case L2CAP_MODE_ERTM: - pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); - pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); + chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); + chan->mps = le16_to_cpu(rfc.max_pdu_size); break; case L2CAP_MODE_STREAMING: - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); } } @@ -2076,6 +2063,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } + l2cap_pi(sk)->chan = chan; + write_lock_bh(&conn->chan_lock); /* Check if we already have channel with that dcid */ @@ -2091,23 +2080,21 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_sock_init(sk, parent); bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - l2cap_pi(sk)->psm = psm; - l2cap_pi(sk)->dcid = scid; + chan->psm = psm; + chan->dcid = scid; bt_accept_enqueue(parent, sk); __l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - - dcid = l2cap_pi(sk)->scid; + dcid = chan->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); chan->ident = cmd->ident; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { - if (l2cap_check_security(sk)) { + if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { sk->sk_state = BT_CONNECT2; result = L2CAP_CR_PEND; @@ -2155,10 +2142,10 @@ sendresp: L2CAP_INFO_REQ, sizeof(info), &info); } - if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && + if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) && result == L2CAP_CR_SUCCESS) { u8 buf[128]; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2198,13 +2185,13 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd case L2CAP_CR_SUCCESS: sk->sk_state = BT_CONFIG; chan->ident = 0; - l2cap_pi(sk)->dcid = dcid; - l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; + chan->dcid = dcid; + chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + if (chan->conf_state & L2CAP_CONF_REQ_SENT) break; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, req), req); @@ -2212,7 +2199,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; case L2CAP_CR_PEND: - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; break; default: @@ -2232,15 +2219,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd return 0; } -static inline void set_default_fcs(struct l2cap_pinfo *pi) +static inline void set_default_fcs(struct l2cap_chan *chan) { + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); + /* FCS is enabled only in ERTM or streaming mode, if one or both * sides request it. */ - if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) - pi->fcs = L2CAP_FCS_NONE; - else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV)) - pi->fcs = L2CAP_FCS_CRC16; + if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) + chan->fcs = L2CAP_FCS_NONE; + else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) + chan->fcs = L2CAP_FCS_CRC16; } static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -2276,7 +2265,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr len = cmd_len - sizeof(*req); if (chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, - l2cap_build_conf_rsp(sk, rsp, + l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_REJECT, flags), rsp); goto unlock; } @@ -2288,7 +2277,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (flags & 0x0001) { /* Incomplete config. Send empty response. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, - l2cap_build_conf_rsp(sk, rsp, + l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_SUCCESS, 0x0001), rsp); goto unlock; } @@ -2306,27 +2295,27 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reset config buffer. */ chan->conf_len = 0; - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE)) + if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE)) goto unlock; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { - set_default_fcs(l2cap_pi(sk)); + if (chan->conf_state & L2CAP_CONF_INPUT_DONE) { + set_default_fcs(chan); sk->sk_state = BT_CONNECTED; chan->next_tx_seq = 0; chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); l2cap_chan_ready(sk); goto unlock; } - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { + if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) { u8 buf[64]; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2360,7 +2349,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr switch (result) { case L2CAP_CONF_SUCCESS: - l2cap_conf_rfc_get(sk, rsp->data, len); + l2cap_conf_rfc_get(chan, rsp->data, len); break; case L2CAP_CONF_UNACCEPT: @@ -2374,8 +2363,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* throw out any old stored conf requests */ result = L2CAP_CONF_SUCCESS; - len = l2cap_parse_conf_rsp(sk, rsp->data, - len, req, &result); + len = l2cap_parse_conf_rsp(chan, rsp->data, len, + req, &result); if (len < 0) { l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; @@ -2399,16 +2388,16 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (flags & 0x01) goto done; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; + chan->conf_state |= L2CAP_CONF_INPUT_DONE; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { - set_default_fcs(l2cap_pi(sk)); + if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) { + set_default_fcs(chan); sk->sk_state = BT_CONNECTED; chan->next_tx_seq = 0; chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); l2cap_chan_ready(sk); @@ -2438,8 +2427,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk = chan->sk; - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(chan->scid); + rsp.scid = cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); sk->sk_shutdown = SHUTDOWN_MASK; @@ -2774,12 +2763,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, kfree_skb(skb); } -static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) +static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb) { u16 our_fcs, rcv_fcs; int hdr_size = L2CAP_HDR_SIZE + 2; - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { skb_trim(skb, skb->len - 2); rcv_fcs = get_unaligned_le16(skb->data + skb->len); our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); @@ -2860,7 +2849,6 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err; @@ -2881,7 +2869,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk chan->sdu_len = get_unaligned_le16(skb->data); - if (chan->sdu_len > pi->imtu) + if (chan->sdu_len > chan->imtu) goto disconnect; chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); @@ -2924,7 +2912,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > chan->imtu) goto drop; if (chan->partial_sdu_len != chan->sdu_len) @@ -2961,7 +2949,7 @@ drop: chan->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); kfree_skb(skb); return 0; } @@ -3022,7 +3010,7 @@ static void l2cap_busy_work(struct work_struct *work) if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY); + l2cap_send_disconn_req(chan->conn, chan, EBUSY); break; } @@ -3092,7 +3080,6 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err = -EINVAL; @@ -3123,7 +3110,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf chan->sdu_len = get_unaligned_le16(skb->data); skb_pull(skb, 2); - if (chan->sdu_len > pi->imtu) { + if (chan->sdu_len > chan->imtu) { err = -EMSGSIZE; break; } @@ -3164,7 +3151,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf chan->conn_state &= ~L2CAP_CONN_SAR_SDU; chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > chan->imtu) goto drop; if (chan->partial_sdu_len == chan->sdu_len) { @@ -3241,12 +3228,11 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; int tx_seq_offset, expected_tx_seq_offset; - int num_to_ack = (pi->tx_win/6) + 1; + int num_to_ack = (chan->tx_win/6) + 1; int err = 0; BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len, @@ -3271,8 +3257,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont tx_seq_offset += 64; /* invalid tx_seq */ - if (tx_seq_offset >= pi->tx_win) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + if (tx_seq_offset >= chan->tx_win) { + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3539,7 +3525,6 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) { struct l2cap_chan *chan = l2cap_pi(sk)->chan; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control; u8 req_seq; int len, next_tx_seq_offset, req_seq_offset; @@ -3553,17 +3538,17 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) * Receiver will miss it and start proper recovery * procedures and ask retransmission. */ - if (l2cap_check_fcs(pi, skb)) + if (l2cap_check_fcs(chan, skb)) goto drop; if (__is_sar_start(control) && __is_iframe(control)) len -= 2; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > pi->mps) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + if (len > chan->mps) { + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3579,13 +3564,13 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) /* check for invalid req-seq */ if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } if (__is_iframe(control)) { if (len < 0) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3593,7 +3578,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) } else { if (len != 0) { BT_ERR("%d", len); - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3630,14 +3615,14 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (sk->sk_state != BT_CONNECTED) goto drop; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: /* If socket recv buffers overflows we drop data here * which is *bad* because L2CAP has to be reliable. * But we don't have any other choice. L2CAP doesn't * provide flow control mechanism. */ - if (pi->imtu < skb->len) + if (chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3659,16 +3644,16 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk skb_pull(skb, 2); len = skb->len; - if (l2cap_check_fcs(pi, skb)) + if (l2cap_check_fcs(chan, skb)) goto drop; if (__is_sar_start(control)) len -= 2; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > pi->mps || len < 0 || __is_sframe(control)) + if (len > chan->mps || len < 0 || __is_sframe(control)) goto drop; tx_seq = __get_txseq(control); @@ -3683,7 +3668,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto done; default: - BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode); + BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode); break; } @@ -3712,7 +3697,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) goto drop; - if (l2cap_pi(sk)->imtu < skb->len) + if (l2cap_pi(sk)->chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3742,7 +3727,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) goto drop; - if (l2cap_pi(sk)->imtu < skb->len) + if (l2cap_pi(sk)->chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3812,17 +3797,19 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) /* Find listening sockets and check their link_mode */ read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (sk->sk_state != BT_LISTEN) continue; if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { lm1 |= HCI_LM_ACCEPT; - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) lm1 |= HCI_LM_MASTER; exact++; } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm2 |= HCI_LM_ACCEPT; - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) lm2 |= HCI_LM_MASTER; } } @@ -3874,19 +3861,21 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) return 0; } -static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) +static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) { + struct sock *sk = chan->sk; + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) return; if (encrypt == 0x00) { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) { + if (chan->sec_level == BT_SECURITY_MEDIUM) { l2cap_sock_clear_timer(sk); l2cap_sock_set_timer(sk, HZ * 5); - } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + } else if (chan->sec_level == BT_SECURITY_HIGH) __l2cap_sock_close(sk, ECONNREFUSED); } else { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) + if (chan->sec_level == BT_SECURITY_MEDIUM) l2cap_sock_clear_timer(sk); } } @@ -3908,14 +3897,14 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_lock_sock(sk); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { + if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) { bh_unlock_sock(sk); continue; } if (!status && (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)) { - l2cap_check_encryption(sk, encrypt); + l2cap_check_encryption(chan, encrypt); bh_unlock_sock(sk); continue; } @@ -3923,11 +3912,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (sk->sk_state == BT_CONNECT) { if (!status) { struct l2cap_conn_req req; - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); @@ -3948,8 +3937,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) result = L2CAP_CR_SEC_BLOCK; } - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, @@ -4021,10 +4010,10 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl if (chan && chan->sk) { struct sock *sk = chan->sk; - if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { + if (chan->imtu < len - L2CAP_HDR_SIZE) { BT_ERR("Frame exceeding recv MTU (len %d, " "MTU %d)", len, - l2cap_pi(sk)->imtu); + chan->imtu); bh_unlock_sock(sk); l2cap_conn_unreliable(conn, ECOMM); goto drop; @@ -4084,14 +4073,15 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) sk_for_each(sk, node, &l2cap_sk_list.head) { struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = pi->chan; seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, __le16_to_cpu(pi->psm), - pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->sec_level, - pi->mode); + sk->sk_state, __le16_to_cpu(chan->psm), + chan->scid, chan->dcid, + chan->imtu, chan->omtu, chan->sec_level, + chan->mode); } read_unlock_bh(&l2cap_sk_list.lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 47394a1..7c4a9ae 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -30,6 +30,8 @@ #include <net/bluetooth/hci_core.h> #include <net/bluetooth/l2cap.h> +static const struct proto_ops l2cap_sock_ops; + /* ---- L2CAP timers ---- */ static void l2cap_sock_timeout(unsigned long arg) { @@ -51,7 +53,7 @@ static void l2cap_sock_timeout(unsigned long arg) if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) reason = ECONNREFUSED; else if (sk->sk_state == BT_CONNECT && - l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) + l2cap_pi(sk)->chan->sec_level != BT_SECURITY_SDP) reason = ECONNREFUSED; else reason = ETIMEDOUT; @@ -80,9 +82,13 @@ static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) { struct sock *sk; struct hlist_node *node; - sk_for_each(sk, node, &l2cap_sk_list.head) - if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) goto found; + } + sk = NULL; found: return sk; @@ -91,6 +97,7 @@ found: static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sockaddr_l2 la; int len, err = 0; @@ -136,17 +143,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } else { /* Save source address */ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); - l2cap_pi(sk)->psm = la.l2_psm; - l2cap_pi(sk)->sport = la.l2_psm; + chan->psm = la.l2_psm; + chan->sport = la.l2_psm; sk->sk_state = BT_BOUND; if (__le16_to_cpu(la.l2_psm) == 0x0001 || __le16_to_cpu(la.l2_psm) == 0x0003) - l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + chan->sec_level = BT_SECURITY_SDP; } if (la.l2_cid) - l2cap_pi(sk)->scid = la.l2_cid; + chan->scid = la.l2_cid; write_unlock_bh(&l2cap_sk_list.lock); @@ -158,6 +165,7 @@ done: static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sockaddr_l2 la; int len, err = 0; @@ -182,7 +190,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al goto done; } - switch (l2cap_pi(sk)->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: @@ -226,10 +234,10 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al /* Set destination address and psm */ bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); - l2cap_pi(sk)->psm = la.l2_psm; - l2cap_pi(sk)->dcid = la.l2_cid; + chan->psm = la.l2_psm; + chan->dcid = la.l2_cid; - err = l2cap_do_connect(sk); + err = l2cap_chan_connect(l2cap_pi(sk)->chan); if (err) goto done; @@ -244,6 +252,7 @@ done: static int l2cap_sock_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; int err = 0; BT_DBG("sk %p backlog %d", sk, backlog); @@ -256,7 +265,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - switch (l2cap_pi(sk)->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: @@ -269,7 +278,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) { + if (!chan->psm && !chan->scid) { bdaddr_t *src = &bt_sk(sk)->src; u16 psm; @@ -279,8 +288,8 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) for (psm = 0x1001; psm < 0x1100; psm += 2) if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { - l2cap_pi(sk)->psm = cpu_to_le16(psm); - l2cap_pi(sk)->sport = cpu_to_le16(psm); + chan->psm = cpu_to_le16(psm); + chan->sport = cpu_to_le16(psm); err = 0; break; } @@ -360,6 +369,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l { struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sock %p, sk %p", sock, sk); @@ -367,13 +377,13 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l *len = sizeof(struct sockaddr_l2); if (peer) { - la->l2_psm = l2cap_pi(sk)->psm; + la->l2_psm = chan->psm; bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); - la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); + la->l2_cid = cpu_to_le16(chan->dcid); } else { - la->l2_psm = l2cap_pi(sk)->sport; + la->l2_psm = chan->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); - la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); + la->l2_cid = cpu_to_le16(chan->scid); } return 0; @@ -382,6 +392,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_options opts; struct l2cap_conninfo cinfo; int len, err = 0; @@ -397,13 +408,13 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us switch (optname) { case L2CAP_OPTIONS: memset(&opts, 0, sizeof(opts)); - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = l2cap_pi(sk)->mode; - opts.fcs = l2cap_pi(sk)->fcs; - opts.max_tx = l2cap_pi(sk)->max_tx; - opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + opts.imtu = chan->imtu; + opts.omtu = chan->omtu; + opts.flush_to = chan->flush_to; + opts.mode = chan->mode; + opts.fcs = chan->fcs; + opts.max_tx = chan->max_tx; + opts.txwin_size = (__u16)chan->tx_win; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) @@ -412,7 +423,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; case L2CAP_LM: - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_LOW: opt = L2CAP_LM_AUTH; break; @@ -428,10 +439,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; } - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) opt |= L2CAP_LM_MASTER; - if (l2cap_pi(sk)->force_reliable) + if (chan->force_reliable) opt |= L2CAP_LM_RELIABLE; if (put_user(opt, (u32 __user *) optval)) @@ -446,8 +457,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; } - cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; - memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3); + cinfo.hci_handle = chan->conn->hcon->handle; + memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) @@ -467,6 +478,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct bt_security sec; int len, err = 0; @@ -491,7 +503,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; } - sec.level = l2cap_pi(sk)->sec_level; + sec.level = chan->sec_level; len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) @@ -511,7 +523,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; case BT_FLUSHABLE: - if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval)) + if (put_user(chan->flushable, (u32 __user *) optval)) err = -EFAULT; break; @@ -528,6 +540,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_options opts; int len, err = 0; u32 opt; @@ -543,13 +556,13 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = l2cap_pi(sk)->mode; - opts.fcs = l2cap_pi(sk)->fcs; - opts.max_tx = l2cap_pi(sk)->max_tx; - opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + opts.imtu = chan->imtu; + opts.omtu = chan->omtu; + opts.flush_to = chan->flush_to; + opts.mode = chan->mode; + opts.fcs = chan->fcs; + opts.max_tx = chan->max_tx; + opts.txwin_size = (__u16)chan->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { @@ -562,10 +575,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - l2cap_pi(sk)->mode = opts.mode; - switch (l2cap_pi(sk)->mode) { + chan->mode = opts.mode; + switch (chan->mode) { case L2CAP_MODE_BASIC: - l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; + chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -577,11 +590,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - l2cap_pi(sk)->imtu = opts.imtu; - l2cap_pi(sk)->omtu = opts.omtu; - l2cap_pi(sk)->fcs = opts.fcs; - l2cap_pi(sk)->max_tx = opts.max_tx; - l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; + chan->imtu = opts.imtu; + chan->omtu = opts.omtu; + chan->fcs = opts.fcs; + chan->max_tx = opts.max_tx; + chan->tx_win = (__u8)opts.txwin_size; break; case L2CAP_LM: @@ -591,14 +604,14 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us } if (opt & L2CAP_LM_AUTH) - l2cap_pi(sk)->sec_level = BT_SECURITY_LOW; + chan->sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) - l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM; + chan->sec_level = BT_SECURITY_MEDIUM; if (opt & L2CAP_LM_SECURE) - l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH; + chan->sec_level = BT_SECURITY_HIGH; - l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); - l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); + chan->role_switch = (opt & L2CAP_LM_MASTER); + chan->force_reliable = (opt & L2CAP_LM_RELIABLE); break; default: @@ -613,6 +626,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct bt_security sec; int len, err = 0; u32 opt; @@ -649,7 +663,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - l2cap_pi(sk)->sec_level = sec.level; + chan->sec_level = sec.level; break; case BT_DEFER_SETUP: @@ -678,7 +692,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch } if (opt == BT_FLUSHABLE_OFF) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; /* proceed further only when we have l2cap_conn and No Flush support in the LM */ if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) { @@ -687,7 +701,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch } } - l2cap_pi(sk)->flushable = opt; + chan->flushable = opt; break; default: @@ -702,7 +716,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sk_buff *skb; u16 control; int err; @@ -725,76 +739,77 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms /* Connectionless channel */ if (sk->sk_type == SOCK_DGRAM) { - skb = l2cap_create_connless_pdu(sk, msg, len); + skb = l2cap_create_connless_pdu(chan, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { - l2cap_do_send(sk, skb); + l2cap_do_send(chan, skb); err = len; } goto done; } - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: /* Check outgoing MTU */ - if (len > pi->omtu) { + if (len > chan->omtu) { err = -EMSGSIZE; goto done; } /* Create a basic PDU */ - skb = l2cap_create_basic_pdu(sk, msg, len); + skb = l2cap_create_basic_pdu(chan, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; } - l2cap_do_send(sk, skb); + l2cap_do_send(chan, skb); err = len; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Entire SDU fits into one PDU */ - if (len <= pi->chan->remote_mps) { + if (len <= chan->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; - skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); + skb = l2cap_create_iframe_pdu(chan, msg, len, control, + 0); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; } - __skb_queue_tail(&pi->chan->tx_q, skb); + __skb_queue_tail(&chan->tx_q, skb); - if (pi->chan->tx_send_head == NULL) - pi->chan->tx_send_head = skb; + if (chan->tx_send_head == NULL) + chan->tx_send_head = skb; } else { /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(pi->chan, msg, len); + err = l2cap_sar_segment_sdu(chan, msg, len); if (err < 0) goto done; } - if (pi->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(pi->chan); + if (chan->mode == L2CAP_MODE_STREAMING) { + l2cap_streaming_send(chan); err = len; break; } - if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->chan->conn_state & L2CAP_CONN_WAIT_F)) { + if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (chan->conn_state & L2CAP_CONN_WAIT_F)) { err = len; break; } - err = l2cap_ertm_send(pi->chan); + err = l2cap_ertm_send(chan); if (err >= 0) err = len; break; default: - BT_DBG("bad state %1.1x", pi->mode); + BT_DBG("bad state %1.1x", chan->mode); err = -EBADFD; } @@ -810,7 +825,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { - __l2cap_connect_rsp_defer(sk); + sk->sk_state = BT_CONFIG; + + __l2cap_connect_rsp_defer(l2cap_pi(sk)->chan); release_sock(sk); return 0; } @@ -834,6 +851,8 @@ void l2cap_sock_kill(struct sock *sk) BT_DBG("sk %p state %d", sk, sk->sk_state); /* Kill poor orphan */ + + l2cap_chan_free(l2cap_pi(sk)->chan); bt_sock_unlink(&l2cap_sk_list, sk); sock_set_flag(sk, SOCK_DEAD); sock_put(sk); @@ -865,8 +884,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) void __l2cap_sock_close(struct sock *sk, int reason) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_conn *conn = chan->conn; BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); @@ -898,8 +917,8 @@ void __l2cap_sock_close(struct sock *sk, int reason) else result = L2CAP_CR_BAD_PSM; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, @@ -923,6 +942,7 @@ void __l2cap_sock_close(struct sock *sk, int reason) static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -932,7 +952,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) lock_sock(sk); if (!sk->sk_shutdown) { - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) err = __l2cap_wait_ack(sk); sk->sk_shutdown = SHUTDOWN_MASK; @@ -979,44 +999,47 @@ static void l2cap_sock_destruct(struct sock *sk) void l2cap_sock_init(struct sock *sk, struct sock *parent) { struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = pi->chan; BT_DBG("sk %p", sk); if (parent) { + struct l2cap_chan *pchan = l2cap_pi(parent)->chan; + sk->sk_type = parent->sk_type; bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; - pi->imtu = l2cap_pi(parent)->imtu; - pi->omtu = l2cap_pi(parent)->omtu; - pi->conf_state = l2cap_pi(parent)->conf_state; - pi->mode = l2cap_pi(parent)->mode; - pi->fcs = l2cap_pi(parent)->fcs; - pi->max_tx = l2cap_pi(parent)->max_tx; - pi->tx_win = l2cap_pi(parent)->tx_win; - pi->sec_level = l2cap_pi(parent)->sec_level; - pi->role_switch = l2cap_pi(parent)->role_switch; - pi->force_reliable = l2cap_pi(parent)->force_reliable; - pi->flushable = l2cap_pi(parent)->flushable; + chan->imtu = pchan->imtu; + chan->omtu = pchan->omtu; + chan->conf_state = pchan->conf_state; + chan->mode = pchan->mode; + chan->fcs = pchan->fcs; + chan->max_tx = pchan->max_tx; + chan->tx_win = pchan->tx_win; + chan->sec_level = pchan->sec_level; + chan->role_switch = pchan->role_switch; + chan->force_reliable = pchan->force_reliable; + chan->flushable = pchan->flushable; } else { - pi->imtu = L2CAP_DEFAULT_MTU; - pi->omtu = 0; + chan->imtu = L2CAP_DEFAULT_MTU; + chan->omtu = 0; if (!disable_ertm && sk->sk_type == SOCK_STREAM) { - pi->mode = L2CAP_MODE_ERTM; - pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + chan->mode = L2CAP_MODE_ERTM; + chan->conf_state |= L2CAP_CONF_STATE2_DEVICE; } else { - pi->mode = L2CAP_MODE_BASIC; + chan->mode = L2CAP_MODE_BASIC; } - pi->max_tx = L2CAP_DEFAULT_MAX_TX; - pi->fcs = L2CAP_FCS_CRC16; - pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; - pi->sec_level = BT_SECURITY_LOW; - pi->role_switch = 0; - pi->force_reliable = 0; - pi->flushable = BT_FLUSHABLE_OFF; + chan->max_tx = L2CAP_DEFAULT_MAX_TX; + chan->fcs = L2CAP_FCS_CRC16; + chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->sec_level = BT_SECURITY_LOW; + chan->role_switch = 0; + chan->force_reliable = 0; + chan->flushable = BT_FLUSHABLE_OFF; } /* Default config options */ - pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; + chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; } static struct proto l2cap_proto = { @@ -1054,6 +1077,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; + struct l2cap_chan *chan; BT_DBG("sock %p", sock); @@ -1072,11 +1096,19 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, if (!sk) return -ENOMEM; + chan = l2cap_chan_alloc(sk); + if (!chan) { + l2cap_sock_kill(sk); + return -ENOMEM; + } + + l2cap_pi(sk)->chan = chan; + l2cap_sock_init(sk, NULL); return 0; } -const struct proto_ops l2cap_sock_ops = { +static const struct proto_ops l2cap_sock_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .release = l2cap_sock_release, diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c304688..2481d25 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -945,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) for (i = 0; i < key_count; i++) { struct mgmt_key_info *key = &cp->keys[i]; - hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type, + hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, key->pin_len); } @@ -1569,6 +1569,75 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return err; } +static int start_discovery(struct sock *sk, u16 index) +{ + u8 lap[3] = { 0x33, 0x8b, 0x9e }; + struct hci_cp_inquiry cp; + struct pending_cmd *cmd; + struct hci_dev *hdev; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memset(&cp, 0, sizeof(cp)); + memcpy(&cp.lap, lap, 3); + cp.length = 0x08; + cp.num_rsp = 0x00; + + err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + +static int stop_discovery(struct sock *sk, u16 index) +{ + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1677,7 +1746,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), len); break; - + case MGMT_OP_START_DISCOVERY: + err = start_discovery(sk, index); + break; + case MGMT_OP_STOP_DISCOVERY: + err = stop_discovery(sk, index); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1784,17 +1858,17 @@ int mgmt_connectable(u16 index, u8 connectable) return ret; } -int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) +int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) { struct mgmt_ev_new_key ev; memset(&ev, 0, sizeof(ev)); + ev.store_hint = persistent; bacpy(&ev.key.bdaddr, &key->bdaddr); ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; - ev.old_key_type = old_key_type; return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); } @@ -1868,11 +1942,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status) return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); } -int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr) +int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure) { struct mgmt_ev_pin_code_request ev; bacpy(&ev.bdaddr, bdaddr); + ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev), NULL); @@ -1920,13 +1995,15 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status) return err; } -int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value) +int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, + u8 confirm_hint) { struct mgmt_ev_user_confirm_request ev; BT_DBG("hci%u", index); bacpy(&ev.bdaddr, bdaddr); + ev.confirm_hint = confirm_hint; put_unaligned_le32(value, &ev.value); return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev), @@ -2075,3 +2152,9 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); } + +int mgmt_discovering(u16 index, u8 discovering) +{ + return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, + sizeof(discovering), NULL); +} diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index c997393..121a5c1 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -232,6 +232,8 @@ static int rfcomm_l2sock_create(struct socket **sock) static inline int rfcomm_check_security(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + __u8 auth_type; switch (d->sec_level) { @@ -246,8 +248,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d) break; } - return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level, - auth_type); + return hci_conn_security(conn->hcon, d->sec_level, auth_type); } static void rfcomm_session_timeout(unsigned long arg) @@ -710,10 +711,10 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, /* Set L2CAP options */ sk = sock->sk; lock_sock(sk); - l2cap_pi(sk)->imtu = l2cap_mtu; - l2cap_pi(sk)->sec_level = sec_level; + l2cap_pi(sk)->chan->imtu = l2cap_mtu; + l2cap_pi(sk)->chan->sec_level = sec_level; if (l2cap_ertm) - l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; + l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM; release_sock(sk); s = rfcomm_session_add(sock, BT_BOUND); @@ -1241,6 +1242,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) void rfcomm_dlc_accept(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; BT_DBG("dlc %p", d); @@ -1254,7 +1256,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d) rfcomm_dlc_unlock(d); if (d->role_switch) - hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00); + hci_conn_switch_role(conn->hcon, 0x00); rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); } @@ -1890,7 +1892,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) /* We should adjust MTU on incoming sessions. * L2CAP MTU minus UIH header and FCS. */ - s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5; + s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu, + l2cap_pi(nsock->sk)->chan->imtu) - 5; rfcomm_schedule(); } else @@ -1909,7 +1912,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s) /* We can adjust MTU on outgoing sessions. * L2CAP MTU minus UIH header and FCS. */ - s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; + s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5; rfcomm_send_sabm(s, 0); break; @@ -1992,7 +1995,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) /* Set L2CAP options */ sk = sock->sk; lock_sock(sk); - l2cap_pi(sk)->imtu = l2cap_mtu; + l2cap_pi(sk)->chan->imtu = l2cap_mtu; release_sock(sk); /* Start listening on the socket */ diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 66cc1f0..386cfaf 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -743,6 +743,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u struct sock *sk = sock->sk; struct sock *l2cap_sk; struct rfcomm_conninfo cinfo; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; int len, err = 0; u32 opt; @@ -787,8 +788,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk; - cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle; - memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3); + cinfo.hci_handle = conn->hcon->handle; + memcpy(cinfo.dev_class, conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index 4bd6ef0..b9b595c 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -54,13 +54,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *cdata, u8 *mic) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad; + u8 *pos, *cpos, *b, *s_0, *e, *b_0; b = scratch; s_0 = scratch + AES_BLOCK_LEN; e = scratch + 2 * AES_BLOCK_LEN; b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; @@ -94,13 +93,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch, u8 *cdata, size_t data_len, u8 *mic, u8 *data) { int i, j, last_len, num_blocks; - u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad; + u8 *pos, *cpos, *b, *s_0, *a, *b_0; b = scratch; s_0 = scratch + AES_BLOCK_LEN; a = scratch + 2 * AES_BLOCK_LEN; b_0 = scratch + 3 * AES_BLOCK_LEN; - aad = scratch + 4 * AES_BLOCK_LEN; num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); last_len = data_len % AES_BLOCK_LEN; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a9ddaf6..12d52ce 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1633,16 +1633,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i; - - /* - * This _could_ be supported by providing a hook for - * drivers for this function, but at this point it - * doesn't seem worth bothering. - */ - if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) - return -EOPNOTSUPP; + int i, ret; + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { + ret = drv_set_bitrate_mask(local, sdata, mask); + if (ret) + return ret; + } for (i = 0; i < IEEE80211_NUM_BANDS; i++) sdata->rc_rateidx_mask[i] = mask->control[i].legacy; diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 00a0685..2ddb56e 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -565,4 +565,22 @@ static inline bool drv_tx_frames_pending(struct ieee80211_local *local) return ret; } + +static inline int drv_set_bitrate_mask(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + const struct cfg80211_bitrate_mask *mask) +{ + int ret = -EOPNOTSUPP; + + might_sleep(); + + trace_drv_set_bitrate_mask(local, sdata, mask); + if (local->ops->set_bitrate_mask) + ret = local->ops->set_bitrate_mask(&local->hw, + &sdata->vif, mask); + trace_drv_return_int(local, ret); + + return ret; +} + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index c8c934d..191e834 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h @@ -989,6 +989,33 @@ DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait, TP_ARGS(local) ); +TRACE_EVENT(drv_set_bitrate_mask, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + const struct cfg80211_bitrate_mask *mask), + + TP_ARGS(local, sdata, mask), + + TP_STRUCT__entry( + LOCAL_ENTRY + VIF_ENTRY + __field(u32, legacy_2g) + __field(u32, legacy_5g) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + VIF_ASSIGN; + __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy; + __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy; + ), + + TP_printk( + LOCAL_PR_FMT VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x", + LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g + ) +); + /* * Tracing for API calls that drivers call. */ diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 1488396..b81860c 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -40,7 +40,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, size_t len) { - u16 auth_alg, auth_transaction, status_code; + u16 auth_alg, auth_transaction; lockdep_assert_held(&sdata->u.ibss.mtx); @@ -49,7 +49,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - status_code = le16_to_cpu(mgmt->u.auth.status_code); /* * IEEE 802.11 standard does not require authentication in IBSS @@ -527,8 +526,6 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband; u8 bssid[ETH_ALEN]; u16 capability; int i; @@ -551,8 +548,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", sdata->name, bssid); - sband = local->hw.wiphy->bands[ifibss->channel->band]; - capability = WLAN_CAPABILITY_IBSS; if (ifibss->privacy) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a778499..027c046 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -766,6 +766,9 @@ struct ieee80211_local { int tx_headroom; /* required headroom for hardware/radiotap */ + /* count for keys needing tailroom space allocation */ + int crypto_tx_tailroom_needed_cnt; + /* Tasklet and skb queue to process calls from IRQ mode. All frames * added to skb_queue will be processed, but frames in * skb_queue_unreliable may be dropped if the total length of these diff --git a/net/mac80211/key.c b/net/mac80211/key.c index af3c564..b510721 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -101,6 +101,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!ret) { key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) + key->local->crypto_tx_tailroom_needed_cnt--; + return 0; } @@ -156,6 +161,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, sta ? sta->addr : bcast_addr, ret); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + + if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || + (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))) + key->local->crypto_tx_tailroom_needed_cnt++; } void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) @@ -388,8 +397,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key) ieee80211_aes_key_free(key->u.ccmp.tfm); if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC) ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm); - if (key->local) + if (key->local) { ieee80211_debugfs_key_remove(key); + key->local->crypto_tx_tailroom_needed_cnt--; + } kfree(key); } @@ -451,6 +462,8 @@ int ieee80211_key_link(struct ieee80211_key *key, ieee80211_debugfs_key_add(key); + key->local->crypto_tx_tailroom_needed_cnt++; + ret = ieee80211_key_enable_hw_accel(key); mutex_unlock(&sdata->local->key_mtx); @@ -492,8 +505,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) mutex_lock(&sdata->local->key_mtx); - list_for_each_entry(key, &sdata->key_list, list) + sdata->local->crypto_tx_tailroom_needed_cnt = 0; + + list_for_each_entry(key, &sdata->key_list, list) { + sdata->local->crypto_tx_tailroom_needed_cnt++; ieee80211_key_enable_hw_accel(key); + } mutex_unlock(&sdata->local->key_mtx); } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 0ab2a8d..6187766 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -33,12 +33,6 @@ #include "cfg.h" #include "debugfs.h" - -static bool ieee80211_disable_40mhz_24ghz; -module_param(ieee80211_disable_40mhz_24ghz, bool, 0644); -MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz, - "Disable 40MHz support in the 2.4GHz band"); - static struct lock_class_key ieee80211_rx_skb_queue_class; void ieee80211_configure_filter(struct ieee80211_local *local) @@ -728,18 +722,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } channels += sband->n_channels; - /* - * Since ieee80211_disable_40mhz_24ghz is global, we can - * modify the sband's ht data even if the driver uses a - * global structure for that. - */ - if (ieee80211_disable_40mhz_24ghz && - band == IEEE80211_BAND_2GHZ && - sband->ht_cap.ht_supported) { - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; - sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; - } - if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 1120797..c1299e2 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -613,12 +613,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status; - struct ieee80211_if_mesh *ifmsh; struct ieee80211_mgmt *mgmt; u16 stype; - ifmsh = &sdata->u.mesh; - rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 5bf64d7..e57f2e7 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -633,7 +633,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, struct mesh_path *mpath; u8 ttl; u8 *ta, *target_addr; - u8 target_flags; u32 target_sn; u16 target_rcode; @@ -644,7 +643,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, return; } ttl--; - target_flags = PERR_IE_TARGET_FLAGS(perr_elem); target_addr = PERR_IE_TARGET_ADDR(perr_elem); target_sn = PERR_IE_TARGET_SN(perr_elem); target_rcode = PERR_IE_TARGET_RCODE(perr_elem); @@ -675,12 +673,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_path *mpath; - u8 *ta; u8 ttl, flags, hopcount; u8 *orig_addr; u32 orig_sn, metric; - ta = mgmt->sa; ttl = rann->rann_ttl; if (ttl <= 1) { ifmsh->mshstats.dropped_frames_ttl++; diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index e373551..0424617 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) ieee80211_scan_cancel(local); + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { + set_sta_flags(sta, WLAN_STA_BLOCK_BA); + ieee80211_sta_tear_down_BA_sessions(sta, true); + } + mutex_unlock(&local->sta_mtx); + } + ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); /* flush out all packets */ synchronize_net(); + drv_flush(local, false); + local->quiescing = true; /* make quiescing visible to timers everywhere */ mb(); @@ -43,11 +54,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) /* tear down aggregation sessions and remove STAs */ mutex_lock(&local->sta_mtx); list_for_each_entry(sta, &local->sta_list, list) { - if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { - set_sta_flags(sta, WLAN_STA_BLOCK_BA); - ieee80211_sta_tear_down_BA_sessions(sta, true); - } - if (sta->uploaded) { sdata = sta->sdata; if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a864890..13a6697 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -652,7 +652,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, set_release_timer: mod_timer(&tid_agg_rx->reorder_timer, - tid_agg_rx->reorder_time[j] + + tid_agg_rx->reorder_time[j] + 1 + HT_RX_REORDER_BUF_TIMEOUT); } else { del_timer(&tid_agg_rx->reorder_timer); @@ -2368,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_QUEUED; } -static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr, - struct ieee80211_rx_data *rx) -{ - int keyidx; - unsigned int hdrlen; - - hdrlen = ieee80211_hdrlen(hdr->frame_control); - if (rx->skb->len >= hdrlen + 4) - keyidx = rx->skb->data[hdrlen + 3] >> 6; - else - keyidx = -1; - - if (!rx->sta) { - /* - * Some hardware seem to generate incorrect Michael MIC - * reports; ignore them to avoid triggering countermeasures. - */ - return; - } - - if (!ieee80211_has_protected(hdr->frame_control)) - return; - - if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) { - /* - * APs with pairwise keys should never receive Michael MIC - * errors for non-zero keyidx because these are reserved for - * group keys and only the AP is sending real multicast - * frames in the BSS. - */ - return; - } - - if (!ieee80211_is_data(hdr->frame_control) && - !ieee80211_is_auth(hdr->frame_control)) - return; - - mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL, - GFP_ATOMIC); -} - /* TODO: use IEEE80211_RX_FRAGMENTED */ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct ieee80211_rate *rate) @@ -2752,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, if (!prepares) return false; - if (status->flag & RX_FLAG_MMIC_ERROR) { - if (status->rx_flags & IEEE80211_RX_RA_MATCH) - ieee80211_rx_michael_mic_report(hdr, rx); - return false; - } - if (!consume) { skb = skb_copy(skb, GFP_ATOMIC); if (!skb) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a03d8a3..d9e6e81 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -587,7 +587,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; - struct ieee80211_sub_if_data *sdata; if (skb_queue_empty(&sta->ps_tx_buf)) return false; @@ -604,7 +603,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (!skb) break; - sdata = sta->sdata; local->total_ps_buffered--; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 3ed3c83..1658efa 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -446,3 +446,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_tx_status); + +void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets) +{ + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); + cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr, + num_packets, GFP_ATOMIC); +} +EXPORT_SYMBOL(ieee80211_report_low_ack); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 17b10be..e3e3aa1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1036,14 +1036,11 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct ieee80211_radiotap_iterator iterator; struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_supported_band *sband; bool hw_frag; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, NULL); - sband = tx->local->hw.wiphy->bands[tx->channel->band]; - info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; tx->flags &= ~IEEE80211_TX_FRAGMENTED; @@ -1442,11 +1439,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, struct ieee80211_tx_data tx; ieee80211_tx_result res_prepare; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - u16 queue; bool result = true; - queue = skb_get_queue_mapping(skb); - if (unlikely(skb->len < 10)) { dev_kfree_skb(skb); return true; @@ -1482,12 +1476,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local, { int tail_need = 0; - /* - * This could be optimised, devices that do full hardware - * crypto (including TKIP MMIC) need no tailroom... But we - * have no drivers for such devices currently. - */ - if (may_encrypt) { + if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) { tail_need = IEEE80211_ENCRYPT_TAILROOM; tail_need -= skb_tailroom(skb); tail_need = max_t(int, tail_need, 0); @@ -2485,7 +2474,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, { struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb = NULL; - struct sta_info *sta; struct ieee80211_tx_data tx; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; @@ -2527,7 +2515,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, info = IEEE80211_SKB_CB(skb); - sta = tx.sta; tx.flags |= IEEE80211_TX_PS_BUFFERED; tx.channel = local->hw.conf.channel; info->band = tx.channel->band; diff --git a/net/mac80211/work.c b/net/mac80211/work.c index e73c8ca..a94b312 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -198,9 +198,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, qos_info; - const u8 *ies; size_t offset = 0, noffset; - int i, len, count, rates_len, supp_rates_len; + int i, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_supported_band *sband; u32 rates = 0; @@ -285,7 +284,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, } /* SSID */ - ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); + pos = skb_put(skb, 2 + wk->assoc.ssid_len); *pos++ = WLAN_EID_SSID; *pos++ = wk->assoc.ssid_len; memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); @@ -295,7 +294,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, if (supp_rates_len > 8) supp_rates_len = 8; - len = sband->n_bitrates; pos = skb_put(skb, supp_rates_len + 2); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = supp_rates_len; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index f1765de..9dc3b5f 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -87,42 +87,76 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - /* No way to verify the MIC if the hardware stripped it */ - if (status->flag & RX_FLAG_MMIC_STRIPPED) + /* + * it makes no sense to check for MIC errors on anything other + * than data frames. + */ + if (!ieee80211_is_data_present(hdr->frame_control)) + return RX_CONTINUE; + + /* + * No way to verify the MIC if the hardware stripped it or + * the IV with the key index. In this case we have solely rely + * on the driver to set RX_FLAG_MMIC_ERROR in the event of a + * MIC failure report. + */ + if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) { + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + + if (!(status->flag & RX_FLAG_IV_STRIPPED)) + goto update_iv; + return RX_CONTINUE; + } + /* + * Some hardware seems to generate Michael MIC failure reports; even + * though, the frame was not encrypted with TKIP and therefore has no + * MIC. Ignore the flag them to avoid triggering countermeasures. + */ if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP || - !ieee80211_has_protected(hdr->frame_control) || - !ieee80211_is_data_present(hdr->frame_control)) + !(status->flag & RX_FLAG_DECRYPTED)) return RX_CONTINUE; + if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) { + /* + * APs with pairwise keys should never receive Michael MIC + * errors for non-zero keyidx because these are reserved for + * group keys and only the AP is sending real multicast + * frames in the BSS. ( + */ + return RX_DROP_UNUSABLE; + } + + if (status->flag & RX_FLAG_MMIC_ERROR) + goto mic_fail; + hdrlen = ieee80211_hdrlen(hdr->frame_control); if (skb->len < hdrlen + MICHAEL_MIC_LEN) return RX_DROP_UNUSABLE; data = skb->data + hdrlen; data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; - key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; michael_mic(key, hdr, data, data_len, mic); - if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) { - if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) - return RX_DROP_UNUSABLE; - - mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, - (void *) skb->data, NULL, - GFP_ATOMIC); - return RX_DROP_UNUSABLE; - } + if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) + goto mic_fail; /* remove Michael MIC from payload */ skb_trim(skb, skb->len - MICHAEL_MIC_LEN); +update_iv: /* update IV in key information to be able to detect replays */ rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32; rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16; return RX_CONTINUE; + +mic_fail: + mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx, + (void *) skb->data, NULL, GFP_ATOMIC); + return RX_DROP_UNUSABLE; } diff --git a/net/wireless/core.c b/net/wireless/core.c index fe01de2..bbf1fa1 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -46,6 +46,11 @@ static struct dentry *ieee80211_debugfs_dir; /* for the cleanup, scan and event works */ struct workqueue_struct *cfg80211_wq; +static bool cfg80211_disable_40mhz_24ghz; +module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); +MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, + "Disable 40MHz support in the 2.4GHz band"); + /* requires cfg80211_mutex to be held! */ struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) { @@ -451,6 +456,18 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; /* + * Since cfg80211_disable_40mhz_24ghz is global, we can + * modify the sband's ht data even if the driver uses a + * global structure for that. + */ + if (cfg80211_disable_40mhz_24ghz && + band == IEEE80211_BAND_2GHZ && + sband->ht_cap.ht_supported) { + sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; + } + + /* * Since we use a u32 for rate bitmaps in * ieee80211_get_response_rate, we cannot * have more than 32 legacy rates. diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 58d6995..1613080 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1455,7 +1455,8 @@ static void reg_process_hint(struct regulatory_request *reg_request) * We only time out user hints, given that they should be the only * source of bogus requests. */ - if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER) + if (r != -EALREADY && + reg_request->initiator == NL80211_REGDOM_SET_BY_USER) schedule_delayed_work(®_timeout, msecs_to_jiffies(3142)); } |