Loading MAINTAINERS +0 −1 Original line number Original line Diff line number Diff line Loading @@ -1087,7 +1087,6 @@ F: drivers/net/wireless/ath/ath5k/ ATHEROS ATH9K WIRELESS DRIVER ATHEROS ATH9K WIRELESS DRIVER M: "Luis R. Rodriguez" <lrodriguez@atheros.com> M: "Luis R. Rodriguez" <lrodriguez@atheros.com> M: Jouni Malinen <jmalinen@atheros.com> M: Jouni Malinen <jmalinen@atheros.com> M: Sujith Manoharan <Sujith.Manoharan@atheros.com> M: Vasanthakumar Thiagarajan <vasanth@atheros.com> M: Vasanthakumar Thiagarajan <vasanth@atheros.com> M: Senthil Balasubramanian <senthilkumar@atheros.com> M: Senthil Balasubramanian <senthilkumar@atheros.com> L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org Loading drivers/net/wireless/ath/ath9k/ar9002_calib.c +27 −16 Original line number Original line Diff line number Diff line Loading @@ -63,6 +63,7 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah, u8 rxchainmask, u8 rxchainmask, struct ath9k_cal_list *currCal) struct ath9k_cal_list *currCal) { { struct ath9k_hw_cal_data *caldata = ah->caldata; bool iscaldone = false; bool iscaldone = false; if (currCal->calState == CAL_RUNNING) { if (currCal->calState == CAL_RUNNING) { Loading @@ -81,14 +82,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah, } } currCal->calData->calPostProc(ah, numChains); currCal->calData->calPostProc(ah, numChains); ichan->CalValid |= currCal->calData->calType; caldata->CalValid |= currCal->calData->calType; currCal->calState = CAL_DONE; currCal->calState = CAL_DONE; iscaldone = true; iscaldone = true; } else { } else { ar9002_hw_setup_calibration(ah, currCal); ar9002_hw_setup_calibration(ah, currCal); } } } } } else if (!(ichan->CalValid & currCal->calData->calType)) { } else if (!(caldata->CalValid & currCal->calData->calType)) { ath9k_hw_reset_calibration(ah, currCal); ath9k_hw_reset_calibration(ah, currCal); } } Loading Loading @@ -686,8 +687,13 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, { { bool iscaldone = true; bool iscaldone = true; struct ath9k_cal_list *currCal = ah->cal_list_curr; struct ath9k_cal_list *currCal = ah->cal_list_curr; bool nfcal, nfcal_pending = false; if (currCal && nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF); if (ah->caldata) nfcal_pending = ah->caldata->nfcal_pending; if (currCal && !nfcal && (currCal->calState == CAL_RUNNING || (currCal->calState == CAL_RUNNING || currCal->calState == CAL_WAITING)) { currCal->calState == CAL_WAITING)) { iscaldone = ar9002_hw_per_calibration(ah, chan, iscaldone = ar9002_hw_per_calibration(ah, chan, Loading @@ -703,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, } } /* Do NF cal only at longer intervals */ /* Do NF cal only at longer intervals */ if (longcal) { if (longcal || nfcal_pending) { /* Do periodic PAOffset Cal */ /* Do periodic PAOffset Cal */ ar9002_hw_pa_cal(ah, false); ar9002_hw_pa_cal(ah, false); ar9002_hw_olc_temp_compensation(ah); ar9002_hw_olc_temp_compensation(ah); Loading @@ -712,16 +718,18 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, * Get the value from the previous NF cal and update * Get the value from the previous NF cal and update * history buffer. * history buffer. */ */ ath9k_hw_getnf(ah, chan); if (ath9k_hw_getnf(ah, chan)) { /* /* * Load the NF from history buffer of the current channel. * Load the NF from history buffer of the current * NF is slow time-variant, so it is OK to use a historical * channel. * value. * NF is slow time-variant, so it is OK to use a * historical value. */ */ ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_loadnf(ah, ah->curchan); } ath9k_hw_start_nfcal(ah); if (longcal) ath9k_hw_start_nfcal(ah, false); } } return iscaldone; return iscaldone; Loading Loading @@ -869,8 +877,10 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) ar9002_hw_pa_cal(ah, true); ar9002_hw_pa_cal(ah, true); /* Do NF Calibration after DC offset and other calibrations */ /* Do NF Calibration after DC offset and other calibrations */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, ath9k_hw_start_nfcal(ah, true); REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); if (ah->caldata) ah->caldata->nfcal_pending = true; ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; Loading Loading @@ -901,7 +911,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) ath9k_hw_reset_calibration(ah, ah->cal_list_curr); ath9k_hw_reset_calibration(ah, ah->cal_list_curr); } } chan->CalValid = 0; if (ah->caldata) ah->caldata->CalValid = 0; return true; return true; } } Loading drivers/net/wireless/ath/ath9k/ar9003_calib.c +14 −4 Original line number Original line Diff line number Diff line Loading @@ -68,6 +68,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, u8 rxchainmask, u8 rxchainmask, struct ath9k_cal_list *currCal) struct ath9k_cal_list *currCal) { { struct ath9k_hw_cal_data *caldata = ah->caldata; /* Cal is assumed not done until explicitly set below */ /* Cal is assumed not done until explicitly set below */ bool iscaldone = false; bool iscaldone = false; Loading Loading @@ -95,7 +96,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, currCal->calData->calPostProc(ah, numChains); currCal->calData->calPostProc(ah, numChains); /* Calibration has finished. */ /* Calibration has finished. */ ichan->CalValid |= currCal->calData->calType; caldata->CalValid |= currCal->calData->calType; currCal->calState = CAL_DONE; currCal->calState = CAL_DONE; iscaldone = true; iscaldone = true; } else { } else { Loading @@ -106,7 +107,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, ar9003_hw_setup_calibration(ah, currCal); ar9003_hw_setup_calibration(ah, currCal); } } } } } else if (!(ichan->CalValid & currCal->calData->calType)) { } else if (!(caldata->CalValid & currCal->calData->calType)) { /* If current cal is marked invalid in channel, kick it off */ /* If current cal is marked invalid in channel, kick it off */ ath9k_hw_reset_calibration(ah, currCal); ath9k_hw_reset_calibration(ah, currCal); } } Loading Loading @@ -148,6 +149,12 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, /* Do NF cal only at longer intervals */ /* Do NF cal only at longer intervals */ if (longcal) { if (longcal) { /* * Get the value from the previous NF cal and update * history buffer. */ ath9k_hw_getnf(ah, chan); /* /* * Load the NF from history buffer of the current channel. * Load the NF from history buffer of the current channel. * NF is slow time-variant, so it is OK to use a historical * NF is slow time-variant, so it is OK to use a historical Loading @@ -156,7 +163,7 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_loadnf(ah, ah->curchan); /* start NF calibration, without updating BB NF register */ /* start NF calibration, without updating BB NF register */ ath9k_hw_start_nfcal(ah); ath9k_hw_start_nfcal(ah, false); } } return iscaldone; return iscaldone; Loading Loading @@ -762,6 +769,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, /* Revert chainmasks to their original values before NF cal */ /* Revert chainmasks to their original values before NF cal */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ath9k_hw_start_nfcal(ah, true); /* Initialize list pointers */ /* Initialize list pointers */ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; Loading @@ -785,7 +794,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (ah->cal_list_curr) if (ah->cal_list_curr) ath9k_hw_reset_calibration(ah, ah->cal_list_curr); ath9k_hw_reset_calibration(ah, ah->cal_list_curr); chan->CalValid = 0; if (ah->caldata) ah->caldata->CalValid = 0; return true; return true; } } Loading drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +381 −7 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,20 @@ #define LE16(x) __constant_cpu_to_le16(x) #define LE16(x) __constant_cpu_to_le16(x) #define LE32(x) __constant_cpu_to_le32(x) #define LE32(x) __constant_cpu_to_le32(x) /* Local defines to distinguish between extension and control CTL's */ #define EXT_ADDITIVE (0x8000) #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ #define PWRINCR_3_TO_1_CHAIN 9 /* 10*log(3)*2 */ #define PWRINCR_3_TO_2_CHAIN 3 /* floor(10*log(3/2)*2) */ #define PWRINCR_2_TO_1_CHAIN 6 /* 10*log(2)*2 */ #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ static const struct ar9300_eeprom ar9300_default = { static const struct ar9300_eeprom ar9300_default = { .eepromVersion = 2, .eepromVersion = 2, .templateVersion = 2, .templateVersion = 2, Loading Loading @@ -609,6 +623,14 @@ static const struct ar9300_eeprom ar9300_default = { } } }; }; static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) { if (fbin == AR9300_BCHAN_UNUSED) return fbin; return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); } static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) { { return 0; return 0; Loading Loading @@ -1417,9 +1439,9 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) #undef POW_SM #undef POW_SM } } static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq) static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, u8 *targetPowerValT2) { { u8 targetPowerValT2[ar9300RateSize]; /* XXX: hard code for now, need to get from eeprom struct */ /* XXX: hard code for now, need to get from eeprom struct */ u8 ht40PowerIncForPdadc = 0; u8 ht40PowerIncForPdadc = 0; bool is2GHz = false; bool is2GHz = false; Loading Loading @@ -1553,9 +1575,6 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq) "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); i++; i++; } } /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); } } static int ar9003_hw_cal_pier_get(struct ath_hw *ah, static int ar9003_hw_cal_pier_get(struct ath_hw *ah, Loading Loading @@ -1799,14 +1818,369 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) return 0; return 0; } } static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep, int idx, int edge, bool is2GHz) { struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G; struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G; if (is2GHz) return ctl_2g[idx].ctlEdges[edge].tPower; else return ctl_5g[idx].ctlEdges[edge].tPower; } static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep, int idx, unsigned int edge, u16 freq, bool is2GHz) { struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G; struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G; u8 *ctl_freqbin = is2GHz ? &eep->ctl_freqbin_2G[idx][0] : &eep->ctl_freqbin_5G[idx][0]; if (is2GHz) { if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq && ctl_2g[idx].ctlEdges[edge - 1].flag) return ctl_2g[idx].ctlEdges[edge - 1].tPower; } else { if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq && ctl_5g[idx].ctlEdges[edge - 1].flag) return ctl_5g[idx].ctlEdges[edge - 1].tPower; } return AR9300_MAX_RATE_POWER; } /* * Find the maximum conformance test limit for the given channel and CTL info */ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep, u16 freq, int idx, bool is2GHz) { u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER; u8 *ctl_freqbin = is2GHz ? &eep->ctl_freqbin_2G[idx][0] : &eep->ctl_freqbin_5G[idx][0]; u16 num_edges = is2GHz ? AR9300_NUM_BAND_EDGES_2G : AR9300_NUM_BAND_EDGES_5G; unsigned int edge; /* Get the edge power */ for (edge = 0; (edge < num_edges) && (ctl_freqbin[edge] != AR9300_BCHAN_UNUSED); edge++) { /* * If there's an exact channel match or an inband flag set * on the lower channel use the given rdEdgePower */ if (freq == ath9k_hw_fbin2freq(ctl_freqbin[edge], is2GHz)) { twiceMaxEdgePower = ar9003_hw_get_direct_edge_power(eep, idx, edge, is2GHz); break; } else if ((edge > 0) && (freq < ath9k_hw_fbin2freq(ctl_freqbin[edge], is2GHz))) { twiceMaxEdgePower = ar9003_hw_get_indirect_edge_power(eep, idx, edge, freq, is2GHz); /* * Leave loop - no more affecting edges possible in * this monotonic increasing list */ break; } } return twiceMaxEdgePower; } static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, u8 *pPwrArray, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, u16 powerLimit) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep; u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, AR9300_MAX_RATE_POWER }; int i; int16_t twiceLargestAntenna; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; u16 ctlModesFor11a[] = { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; u16 ctlModesFor11g[] = { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 }; u16 numCtlModes, *pCtlMode, ctlMode, freq; struct chan_centers centers; u8 *ctlIndex; u8 ctlNum; u16 twiceMinEdgePower; bool is2ghz = IS_CHAN_2GHZ(chan); ath9k_hw_get_channel_centers(ah, chan, ¢ers); /* Compute TxPower reduction due to Antenna Gain */ if (is2ghz) twiceLargestAntenna = pEepData->modalHeader2G.antennaGain; else twiceLargestAntenna = pEepData->modalHeader5G.antennaGain; twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) - twiceLargestAntenna, 0); /* * scaledPower is the minimum of the user input power level * and the regulatory allowed power level */ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); /* * Reduce scaled Power by number of chains active to get * to per chain tx power level */ switch (ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; break; case 3: scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; break; } scaledPower = max((u16)0, scaledPower); /* * Get target powers from EEPROM - our baseline for TX Power */ if (is2ghz) { /* Setup for CTL modes */ /* CTL_11B, CTL_11G, CTL_2GHT20 */ numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; pCtlMode = ctlModesFor11g; if (IS_CHAN_HT40(chan)) /* All 2G CTL's */ numCtlModes = ARRAY_SIZE(ctlModesFor11g); } else { /* Setup for CTL modes */ /* CTL_11A, CTL_5GHT20 */ numCtlModes = ARRAY_SIZE(ctlModesFor11a) - SUB_NUM_CTL_MODES_AT_5G_40; pCtlMode = ctlModesFor11a; if (IS_CHAN_HT40(chan)) /* All 5G CTL's */ numCtlModes = ARRAY_SIZE(ctlModesFor11a); } /* * For MIMO, need to apply regulatory caps individually across * dynamically running modes: CCK, OFDM, HT20, HT40 * * The outer loop walks through each possible applicable runtime mode. * The inner loop walks through each ctlIndex entry in EEPROM. * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. */ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || (pCtlMode[ctlMode] == CTL_2GHT40); if (isHt40CtlMode) freq = centers.synth_center; else if (pCtlMode[ctlMode] & EXT_ADDITIVE) freq = centers.ext_center; else freq = centers.ctl_center; ath_print(common, ATH_DBG_REGULATORY, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); /* walk through each CTL index stored in EEPROM */ if (is2ghz) { ctlIndex = pEepData->ctlIndex_2G; ctlNum = AR9300_NUM_CTLS_2G; } else { ctlIndex = pEepData->ctlIndex_5G; ctlNum = AR9300_NUM_CTLS_5G; } for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) { ath_print(common, ATH_DBG_REGULATORY, "LOOP-Ctlidx %d: cfgCtl 0x%2.2x " "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " "chan %dn", i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i], chan->channel); /* * compare test group from regulatory * channel list with test mode from pCtlMode * list */ if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == ctlIndex[i]) || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == ((ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { twiceMinEdgePower = ar9003_hw_get_max_edge_power(pEepData, freq, i, is2ghz); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) /* * Find the minimum of all CTL * edge powers that apply to * this channel */ twiceMaxEdgePower = min(twiceMaxEdgePower, twiceMinEdgePower); else { /* specific */ twiceMaxEdgePower = twiceMinEdgePower; break; } } } minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); ath_print(common, ATH_DBG_REGULATORY, "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d " "sP %d minCtlPwr %d\n", ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, scaledPower, minCtlPower); /* Apply ctl mode to correct target power set */ switch (pCtlMode[ctlMode]) { case CTL_11B: for (i = ALL_TARGET_LEGACY_1L_5L; i <= ALL_TARGET_LEGACY_11S; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); break; case CTL_11A: case CTL_11G: for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); break; case CTL_5GHT20: case CTL_2GHT20: for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_21; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); pPwrArray[ALL_TARGET_HT20_22] = (u8)min((u16)pPwrArray[ALL_TARGET_HT20_22], minCtlPower); pPwrArray[ALL_TARGET_HT20_23] = (u8)min((u16)pPwrArray[ALL_TARGET_HT20_23], minCtlPower); break; case CTL_5GHT40: case CTL_2GHT40: for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_23; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); break; default: break; } } /* end ctl mode checking */ } static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, u8 twiceMaxRegulatoryPower, u8 powerLimit) u8 powerLimit) { { ah->txpower_limit = powerLimit; struct ath_common *common = ath9k_hw_common(ah); ar9003_hw_set_target_power_eeprom(ah, chan->channel); u8 targetPowerValT2[ar9300RateSize]; unsigned int i = 0; ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2); ar9003_hw_set_power_per_rate_table(ah, chan, targetPowerValT2, cfgCtl, twiceAntennaReduction, twiceMaxRegulatoryPower, powerLimit); while (i < ar9300RateSize) { ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); i++; ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); i++; ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); i++; ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x\n\n", i, targetPowerValT2[i]); i++; } /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); /* * This is the TX power we send back to driver core, * and it can use to pass to userspace to display our * currently configured TX power setting. * * Since power is rate dependent, use one of the indices * from the AR9300_Rates enum to select an entry from * targetPowerValT2[] to report. Currently returns the * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps * as CCK power is less interesting (?). */ i = ALL_TARGET_LEGACY_6_24; /* legacy */ if (IS_CHAN_HT40(chan)) i = ALL_TARGET_HT40_0_8_16; /* ht40 */ else if (IS_CHAN_HT20(chan)) i = ALL_TARGET_HT20_0_8_16; /* ht20 */ ah->txpower_limit = targetPowerValT2[i]; ar9003_hw_calibration_apply(ah, chan->channel); ar9003_hw_calibration_apply(ah, chan->channel); } } Loading drivers/net/wireless/ath/ath9k/ar9003_paprd.c +9 −8 Original line number Original line Diff line number Diff line Loading @@ -577,10 +577,11 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) } } void ar9003_paprd_populate_single_table(struct ath_hw *ah, void ar9003_paprd_populate_single_table(struct ath_hw *ah, struct ath9k_channel *chan, int chain) struct ath9k_hw_cal_data *caldata, int chain) { { u32 *paprd_table_val = chan->pa_table[chain]; u32 *paprd_table_val = caldata->pa_table[chain]; u32 small_signal_gain = chan->small_signal_gain[chain]; u32 small_signal_gain = caldata->small_signal_gain[chain]; u32 training_power; u32 training_power; u32 reg = 0; u32 reg = 0; int i; int i; Loading Loading @@ -654,17 +655,17 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) } } EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan, int ar9003_paprd_create_curve(struct ath_hw *ah, int chain) struct ath9k_hw_cal_data *caldata, int chain) { { u16 *small_signal_gain = &chan->small_signal_gain[chain]; u16 *small_signal_gain = &caldata->small_signal_gain[chain]; u32 *pa_table = chan->pa_table[chain]; u32 *pa_table = caldata->pa_table[chain]; u32 *data_L, *data_U; u32 *data_L, *data_U; int i, status = 0; int i, status = 0; u32 *buf; u32 *buf; u32 reg; u32 reg; memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain])); memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC); buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC); if (!buf) if (!buf) Loading Loading
MAINTAINERS +0 −1 Original line number Original line Diff line number Diff line Loading @@ -1087,7 +1087,6 @@ F: drivers/net/wireless/ath/ath5k/ ATHEROS ATH9K WIRELESS DRIVER ATHEROS ATH9K WIRELESS DRIVER M: "Luis R. Rodriguez" <lrodriguez@atheros.com> M: "Luis R. Rodriguez" <lrodriguez@atheros.com> M: Jouni Malinen <jmalinen@atheros.com> M: Jouni Malinen <jmalinen@atheros.com> M: Sujith Manoharan <Sujith.Manoharan@atheros.com> M: Vasanthakumar Thiagarajan <vasanth@atheros.com> M: Vasanthakumar Thiagarajan <vasanth@atheros.com> M: Senthil Balasubramanian <senthilkumar@atheros.com> M: Senthil Balasubramanian <senthilkumar@atheros.com> L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org Loading
drivers/net/wireless/ath/ath9k/ar9002_calib.c +27 −16 Original line number Original line Diff line number Diff line Loading @@ -63,6 +63,7 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah, u8 rxchainmask, u8 rxchainmask, struct ath9k_cal_list *currCal) struct ath9k_cal_list *currCal) { { struct ath9k_hw_cal_data *caldata = ah->caldata; bool iscaldone = false; bool iscaldone = false; if (currCal->calState == CAL_RUNNING) { if (currCal->calState == CAL_RUNNING) { Loading @@ -81,14 +82,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah, } } currCal->calData->calPostProc(ah, numChains); currCal->calData->calPostProc(ah, numChains); ichan->CalValid |= currCal->calData->calType; caldata->CalValid |= currCal->calData->calType; currCal->calState = CAL_DONE; currCal->calState = CAL_DONE; iscaldone = true; iscaldone = true; } else { } else { ar9002_hw_setup_calibration(ah, currCal); ar9002_hw_setup_calibration(ah, currCal); } } } } } else if (!(ichan->CalValid & currCal->calData->calType)) { } else if (!(caldata->CalValid & currCal->calData->calType)) { ath9k_hw_reset_calibration(ah, currCal); ath9k_hw_reset_calibration(ah, currCal); } } Loading Loading @@ -686,8 +687,13 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, { { bool iscaldone = true; bool iscaldone = true; struct ath9k_cal_list *currCal = ah->cal_list_curr; struct ath9k_cal_list *currCal = ah->cal_list_curr; bool nfcal, nfcal_pending = false; if (currCal && nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF); if (ah->caldata) nfcal_pending = ah->caldata->nfcal_pending; if (currCal && !nfcal && (currCal->calState == CAL_RUNNING || (currCal->calState == CAL_RUNNING || currCal->calState == CAL_WAITING)) { currCal->calState == CAL_WAITING)) { iscaldone = ar9002_hw_per_calibration(ah, chan, iscaldone = ar9002_hw_per_calibration(ah, chan, Loading @@ -703,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, } } /* Do NF cal only at longer intervals */ /* Do NF cal only at longer intervals */ if (longcal) { if (longcal || nfcal_pending) { /* Do periodic PAOffset Cal */ /* Do periodic PAOffset Cal */ ar9002_hw_pa_cal(ah, false); ar9002_hw_pa_cal(ah, false); ar9002_hw_olc_temp_compensation(ah); ar9002_hw_olc_temp_compensation(ah); Loading @@ -712,16 +718,18 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah, * Get the value from the previous NF cal and update * Get the value from the previous NF cal and update * history buffer. * history buffer. */ */ ath9k_hw_getnf(ah, chan); if (ath9k_hw_getnf(ah, chan)) { /* /* * Load the NF from history buffer of the current channel. * Load the NF from history buffer of the current * NF is slow time-variant, so it is OK to use a historical * channel. * value. * NF is slow time-variant, so it is OK to use a * historical value. */ */ ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_loadnf(ah, ah->curchan); } ath9k_hw_start_nfcal(ah); if (longcal) ath9k_hw_start_nfcal(ah, false); } } return iscaldone; return iscaldone; Loading Loading @@ -869,8 +877,10 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) ar9002_hw_pa_cal(ah, true); ar9002_hw_pa_cal(ah, true); /* Do NF Calibration after DC offset and other calibrations */ /* Do NF Calibration after DC offset and other calibrations */ REG_WRITE(ah, AR_PHY_AGC_CONTROL, ath9k_hw_start_nfcal(ah, true); REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); if (ah->caldata) ah->caldata->nfcal_pending = true; ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; Loading Loading @@ -901,7 +911,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) ath9k_hw_reset_calibration(ah, ah->cal_list_curr); ath9k_hw_reset_calibration(ah, ah->cal_list_curr); } } chan->CalValid = 0; if (ah->caldata) ah->caldata->CalValid = 0; return true; return true; } } Loading
drivers/net/wireless/ath/ath9k/ar9003_calib.c +14 −4 Original line number Original line Diff line number Diff line Loading @@ -68,6 +68,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, u8 rxchainmask, u8 rxchainmask, struct ath9k_cal_list *currCal) struct ath9k_cal_list *currCal) { { struct ath9k_hw_cal_data *caldata = ah->caldata; /* Cal is assumed not done until explicitly set below */ /* Cal is assumed not done until explicitly set below */ bool iscaldone = false; bool iscaldone = false; Loading Loading @@ -95,7 +96,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, currCal->calData->calPostProc(ah, numChains); currCal->calData->calPostProc(ah, numChains); /* Calibration has finished. */ /* Calibration has finished. */ ichan->CalValid |= currCal->calData->calType; caldata->CalValid |= currCal->calData->calType; currCal->calState = CAL_DONE; currCal->calState = CAL_DONE; iscaldone = true; iscaldone = true; } else { } else { Loading @@ -106,7 +107,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah, ar9003_hw_setup_calibration(ah, currCal); ar9003_hw_setup_calibration(ah, currCal); } } } } } else if (!(ichan->CalValid & currCal->calData->calType)) { } else if (!(caldata->CalValid & currCal->calData->calType)) { /* If current cal is marked invalid in channel, kick it off */ /* If current cal is marked invalid in channel, kick it off */ ath9k_hw_reset_calibration(ah, currCal); ath9k_hw_reset_calibration(ah, currCal); } } Loading Loading @@ -148,6 +149,12 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, /* Do NF cal only at longer intervals */ /* Do NF cal only at longer intervals */ if (longcal) { if (longcal) { /* * Get the value from the previous NF cal and update * history buffer. */ ath9k_hw_getnf(ah, chan); /* /* * Load the NF from history buffer of the current channel. * Load the NF from history buffer of the current channel. * NF is slow time-variant, so it is OK to use a historical * NF is slow time-variant, so it is OK to use a historical Loading @@ -156,7 +163,7 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_loadnf(ah, ah->curchan); /* start NF calibration, without updating BB NF register */ /* start NF calibration, without updating BB NF register */ ath9k_hw_start_nfcal(ah); ath9k_hw_start_nfcal(ah, false); } } return iscaldone; return iscaldone; Loading Loading @@ -762,6 +769,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, /* Revert chainmasks to their original values before NF cal */ /* Revert chainmasks to their original values before NF cal */ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ath9k_hw_start_nfcal(ah, true); /* Initialize list pointers */ /* Initialize list pointers */ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; Loading @@ -785,7 +794,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (ah->cal_list_curr) if (ah->cal_list_curr) ath9k_hw_reset_calibration(ah, ah->cal_list_curr); ath9k_hw_reset_calibration(ah, ah->cal_list_curr); chan->CalValid = 0; if (ah->caldata) ah->caldata->CalValid = 0; return true; return true; } } Loading
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +381 −7 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,20 @@ #define LE16(x) __constant_cpu_to_le16(x) #define LE16(x) __constant_cpu_to_le16(x) #define LE32(x) __constant_cpu_to_le32(x) #define LE32(x) __constant_cpu_to_le32(x) /* Local defines to distinguish between extension and control CTL's */ #define EXT_ADDITIVE (0x8000) #define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE) #define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE) #define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE) #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ #define PWRINCR_3_TO_1_CHAIN 9 /* 10*log(3)*2 */ #define PWRINCR_3_TO_2_CHAIN 3 /* floor(10*log(3/2)*2) */ #define PWRINCR_2_TO_1_CHAIN 6 /* 10*log(2)*2 */ #define SUB_NUM_CTL_MODES_AT_5G_40 2 /* excluding HT40, EXT-OFDM */ #define SUB_NUM_CTL_MODES_AT_2G_40 3 /* excluding HT40, EXT-OFDM, EXT-CCK */ static const struct ar9300_eeprom ar9300_default = { static const struct ar9300_eeprom ar9300_default = { .eepromVersion = 2, .eepromVersion = 2, .templateVersion = 2, .templateVersion = 2, Loading Loading @@ -609,6 +623,14 @@ static const struct ar9300_eeprom ar9300_default = { } } }; }; static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) { if (fbin == AR9300_BCHAN_UNUSED) return fbin; return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); } static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah) { { return 0; return 0; Loading Loading @@ -1417,9 +1439,9 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) #undef POW_SM #undef POW_SM } } static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq) static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq, u8 *targetPowerValT2) { { u8 targetPowerValT2[ar9300RateSize]; /* XXX: hard code for now, need to get from eeprom struct */ /* XXX: hard code for now, need to get from eeprom struct */ u8 ht40PowerIncForPdadc = 0; u8 ht40PowerIncForPdadc = 0; bool is2GHz = false; bool is2GHz = false; Loading Loading @@ -1553,9 +1575,6 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq) "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); i++; i++; } } /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); } } static int ar9003_hw_cal_pier_get(struct ath_hw *ah, static int ar9003_hw_cal_pier_get(struct ath_hw *ah, Loading Loading @@ -1799,14 +1818,369 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency) return 0; return 0; } } static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep, int idx, int edge, bool is2GHz) { struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G; struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G; if (is2GHz) return ctl_2g[idx].ctlEdges[edge].tPower; else return ctl_5g[idx].ctlEdges[edge].tPower; } static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep, int idx, unsigned int edge, u16 freq, bool is2GHz) { struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G; struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G; u8 *ctl_freqbin = is2GHz ? &eep->ctl_freqbin_2G[idx][0] : &eep->ctl_freqbin_5G[idx][0]; if (is2GHz) { if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq && ctl_2g[idx].ctlEdges[edge - 1].flag) return ctl_2g[idx].ctlEdges[edge - 1].tPower; } else { if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq && ctl_5g[idx].ctlEdges[edge - 1].flag) return ctl_5g[idx].ctlEdges[edge - 1].tPower; } return AR9300_MAX_RATE_POWER; } /* * Find the maximum conformance test limit for the given channel and CTL info */ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep, u16 freq, int idx, bool is2GHz) { u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER; u8 *ctl_freqbin = is2GHz ? &eep->ctl_freqbin_2G[idx][0] : &eep->ctl_freqbin_5G[idx][0]; u16 num_edges = is2GHz ? AR9300_NUM_BAND_EDGES_2G : AR9300_NUM_BAND_EDGES_5G; unsigned int edge; /* Get the edge power */ for (edge = 0; (edge < num_edges) && (ctl_freqbin[edge] != AR9300_BCHAN_UNUSED); edge++) { /* * If there's an exact channel match or an inband flag set * on the lower channel use the given rdEdgePower */ if (freq == ath9k_hw_fbin2freq(ctl_freqbin[edge], is2GHz)) { twiceMaxEdgePower = ar9003_hw_get_direct_edge_power(eep, idx, edge, is2GHz); break; } else if ((edge > 0) && (freq < ath9k_hw_fbin2freq(ctl_freqbin[edge], is2GHz))) { twiceMaxEdgePower = ar9003_hw_get_indirect_edge_power(eep, idx, edge, freq, is2GHz); /* * Leave loop - no more affecting edges possible in * this monotonic increasing list */ break; } } return twiceMaxEdgePower; } static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, u8 *pPwrArray, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, u16 powerLimit) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep; u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER; static const u16 tpScaleReductionTable[5] = { 0, 3, 6, 9, AR9300_MAX_RATE_POWER }; int i; int16_t twiceLargestAntenna; u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; u16 ctlModesFor11a[] = { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; u16 ctlModesFor11g[] = { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 }; u16 numCtlModes, *pCtlMode, ctlMode, freq; struct chan_centers centers; u8 *ctlIndex; u8 ctlNum; u16 twiceMinEdgePower; bool is2ghz = IS_CHAN_2GHZ(chan); ath9k_hw_get_channel_centers(ah, chan, ¢ers); /* Compute TxPower reduction due to Antenna Gain */ if (is2ghz) twiceLargestAntenna = pEepData->modalHeader2G.antennaGain; else twiceLargestAntenna = pEepData->modalHeader5G.antennaGain; twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) - twiceLargestAntenna, 0); /* * scaledPower is the minimum of the user input power level * and the regulatory allowed power level */ maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { maxRegAllowedPower -= (tpScaleReductionTable[(regulatory->tp_scale)] * 2); } scaledPower = min(powerLimit, maxRegAllowedPower); /* * Reduce scaled Power by number of chains active to get * to per chain tx power level */ switch (ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; case 2: scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; break; case 3: scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; break; } scaledPower = max((u16)0, scaledPower); /* * Get target powers from EEPROM - our baseline for TX Power */ if (is2ghz) { /* Setup for CTL modes */ /* CTL_11B, CTL_11G, CTL_2GHT20 */ numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; pCtlMode = ctlModesFor11g; if (IS_CHAN_HT40(chan)) /* All 2G CTL's */ numCtlModes = ARRAY_SIZE(ctlModesFor11g); } else { /* Setup for CTL modes */ /* CTL_11A, CTL_5GHT20 */ numCtlModes = ARRAY_SIZE(ctlModesFor11a) - SUB_NUM_CTL_MODES_AT_5G_40; pCtlMode = ctlModesFor11a; if (IS_CHAN_HT40(chan)) /* All 5G CTL's */ numCtlModes = ARRAY_SIZE(ctlModesFor11a); } /* * For MIMO, need to apply regulatory caps individually across * dynamically running modes: CCK, OFDM, HT20, HT40 * * The outer loop walks through each possible applicable runtime mode. * The inner loop walks through each ctlIndex entry in EEPROM. * The ctl value is encoded as [7:4] == test group, [3:0] == test mode. */ for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || (pCtlMode[ctlMode] == CTL_2GHT40); if (isHt40CtlMode) freq = centers.synth_center; else if (pCtlMode[ctlMode] & EXT_ADDITIVE) freq = centers.ext_center; else freq = centers.ctl_center; ath_print(common, ATH_DBG_REGULATORY, "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " "EXT_ADDITIVE %d\n", ctlMode, numCtlModes, isHt40CtlMode, (pCtlMode[ctlMode] & EXT_ADDITIVE)); /* walk through each CTL index stored in EEPROM */ if (is2ghz) { ctlIndex = pEepData->ctlIndex_2G; ctlNum = AR9300_NUM_CTLS_2G; } else { ctlIndex = pEepData->ctlIndex_5G; ctlNum = AR9300_NUM_CTLS_5G; } for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) { ath_print(common, ATH_DBG_REGULATORY, "LOOP-Ctlidx %d: cfgCtl 0x%2.2x " "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " "chan %dn", i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i], chan->channel); /* * compare test group from regulatory * channel list with test mode from pCtlMode * list */ if ((((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == ctlIndex[i]) || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == ((ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { twiceMinEdgePower = ar9003_hw_get_max_edge_power(pEepData, freq, i, is2ghz); if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) /* * Find the minimum of all CTL * edge powers that apply to * this channel */ twiceMaxEdgePower = min(twiceMaxEdgePower, twiceMinEdgePower); else { /* specific */ twiceMaxEdgePower = twiceMinEdgePower; break; } } } minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); ath_print(common, ATH_DBG_REGULATORY, "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d " "sP %d minCtlPwr %d\n", ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, scaledPower, minCtlPower); /* Apply ctl mode to correct target power set */ switch (pCtlMode[ctlMode]) { case CTL_11B: for (i = ALL_TARGET_LEGACY_1L_5L; i <= ALL_TARGET_LEGACY_11S; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); break; case CTL_11A: case CTL_11G: for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); break; case CTL_5GHT20: case CTL_2GHT20: for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_21; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); pPwrArray[ALL_TARGET_HT20_22] = (u8)min((u16)pPwrArray[ALL_TARGET_HT20_22], minCtlPower); pPwrArray[ALL_TARGET_HT20_23] = (u8)min((u16)pPwrArray[ALL_TARGET_HT20_23], minCtlPower); break; case CTL_5GHT40: case CTL_2GHT40: for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_23; i++) pPwrArray[i] = (u8)min((u16)pPwrArray[i], minCtlPower); break; default: break; } } /* end ctl mode checking */ } static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, u8 twiceAntennaReduction, u8 twiceMaxRegulatoryPower, u8 twiceMaxRegulatoryPower, u8 powerLimit) u8 powerLimit) { { ah->txpower_limit = powerLimit; struct ath_common *common = ath9k_hw_common(ah); ar9003_hw_set_target_power_eeprom(ah, chan->channel); u8 targetPowerValT2[ar9300RateSize]; unsigned int i = 0; ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2); ar9003_hw_set_power_per_rate_table(ah, chan, targetPowerValT2, cfgCtl, twiceAntennaReduction, twiceMaxRegulatoryPower, powerLimit); while (i < ar9300RateSize) { ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); i++; ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); i++; ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]); i++; ath_print(common, ATH_DBG_EEPROM, "TPC[%02d] 0x%08x\n\n", i, targetPowerValT2[i]); i++; } /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); /* * This is the TX power we send back to driver core, * and it can use to pass to userspace to display our * currently configured TX power setting. * * Since power is rate dependent, use one of the indices * from the AR9300_Rates enum to select an entry from * targetPowerValT2[] to report. Currently returns the * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps * as CCK power is less interesting (?). */ i = ALL_TARGET_LEGACY_6_24; /* legacy */ if (IS_CHAN_HT40(chan)) i = ALL_TARGET_HT40_0_8_16; /* ht40 */ else if (IS_CHAN_HT20(chan)) i = ALL_TARGET_HT20_0_8_16; /* ht20 */ ah->txpower_limit = targetPowerValT2[i]; ar9003_hw_calibration_apply(ah, chan->channel); ar9003_hw_calibration_apply(ah, chan->channel); } } Loading
drivers/net/wireless/ath/ath9k/ar9003_paprd.c +9 −8 Original line number Original line Diff line number Diff line Loading @@ -577,10 +577,11 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain) } } void ar9003_paprd_populate_single_table(struct ath_hw *ah, void ar9003_paprd_populate_single_table(struct ath_hw *ah, struct ath9k_channel *chan, int chain) struct ath9k_hw_cal_data *caldata, int chain) { { u32 *paprd_table_val = chan->pa_table[chain]; u32 *paprd_table_val = caldata->pa_table[chain]; u32 small_signal_gain = chan->small_signal_gain[chain]; u32 small_signal_gain = caldata->small_signal_gain[chain]; u32 training_power; u32 training_power; u32 reg = 0; u32 reg = 0; int i; int i; Loading Loading @@ -654,17 +655,17 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain) } } EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); EXPORT_SYMBOL(ar9003_paprd_setup_gain_table); int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan, int ar9003_paprd_create_curve(struct ath_hw *ah, int chain) struct ath9k_hw_cal_data *caldata, int chain) { { u16 *small_signal_gain = &chan->small_signal_gain[chain]; u16 *small_signal_gain = &caldata->small_signal_gain[chain]; u32 *pa_table = chan->pa_table[chain]; u32 *pa_table = caldata->pa_table[chain]; u32 *data_L, *data_U; u32 *data_L, *data_U; int i, status = 0; int i, status = 0; u32 *buf; u32 *buf; u32 reg; u32 reg; memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain])); memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain])); buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC); buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC); if (!buf) if (!buf) Loading