aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/phy.c
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-05-30 19:16:45 -0400
commitada47b5fe13d89735805b566185f4885f5a3f750 (patch)
tree644b88f8a71896307d71438e9b3af49126ffb22b /drivers/net/wireless/ath/ath5k/phy.c
parent43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff)
parent3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff)
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/net/wireless/ath/ath5k/phy.c')
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c235
1 files changed, 153 insertions, 82 deletions
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 1a039f2bd732..68e2bccd90d3 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -23,6 +23,7 @@
23#define _ATH5K_PHY 23#define _ATH5K_PHY
24 24
25#include <linux/delay.h> 25#include <linux/delay.h>
26#include <linux/slab.h>
26 27
27#include "ath5k.h" 28#include "ath5k.h"
28#include "reg.h" 29#include "reg.h"
@@ -117,7 +118,7 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
117 118
118/* 119/*
119 * This code is used to optimize rf gain on different environments 120 * This code is used to optimize rf gain on different environments
120 * (temprature mostly) based on feedback from a power detector. 121 * (temperature mostly) based on feedback from a power detector.
121 * 122 *
122 * It's only used on RF5111 and RF5112, later RF chips seem to have 123 * It's only used on RF5111 and RF5112, later RF chips seem to have
123 * auto adjustment on hw -notice they have a much smaller BANK 7 and 124 * auto adjustment on hw -notice they have a much smaller BANK 7 and
@@ -1124,77 +1125,148 @@ ath5k_hw_calibration_poll(struct ath5k_hw *ah)
1124 ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; 1125 ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
1125 AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); 1126 AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
1126 } 1127 }
1128}
1127 1129
1130static int sign_extend(int val, const int nbits)
1131{
1132 int order = BIT(nbits-1);
1133 return (val ^ order) - order;
1128} 1134}
1129 1135
1130/** 1136static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
1131 * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration 1137{
1132 * 1138 s32 val;
1133 * @ah: struct ath5k_hw pointer we are operating on 1139
1134 * @freq: the channel frequency, just used for error logging 1140 val = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
1135 * 1141 return sign_extend(AR5K_REG_MS(val, AR5K_PHY_NF_MINCCA_PWR), 9);
1136 * This function performs a noise floor calibration of the PHY and waits for 1142}
1137 * it to complete. Then the noise floor value is compared to some maximum 1143
1138 * noise floor we consider valid. 1144void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
1139 * 1145{
1140 * Note that this is different from what the madwifi HAL does: it reads the 1146 int i;
1141 * noise floor and afterwards initiates the calibration. Since the noise floor 1147
1142 * calibration can take some time to finish, depending on the current channel 1148 ah->ah_nfcal_hist.index = 0;
1143 * use, that avoids the occasional timeout warnings we are seeing now. 1149 for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++)
1144 * 1150 ah->ah_nfcal_hist.nfval[i] = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
1145 * See the following link for an Atheros patent on noise floor calibration: 1151}
1146 * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ 1152
1147 * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 1153static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
1154{
1155 struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
1156 hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1);
1157 hist->nfval[hist->index] = noise_floor;
1158}
1159
1160static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
1161{
1162 s16 sort[ATH5K_NF_CAL_HIST_MAX];
1163 s16 tmp;
1164 int i, j;
1165
1166 memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
1167 for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
1168 for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
1169 if (sort[j] > sort[j-1]) {
1170 tmp = sort[j];
1171 sort[j] = sort[j-1];
1172 sort[j-1] = tmp;
1173 }
1174 }
1175 }
1176 for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) {
1177 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1178 "cal %d:%d\n", i, sort[i]);
1179 }
1180 return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2];
1181}
1182
1183/*
1184 * When we tell the hardware to perform a noise floor calibration
1185 * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically
1186 * sample-and-hold the minimum noise level seen at the antennas.
1187 * This value is then stored in a ring buffer of recently measured
1188 * noise floor values so we have a moving window of the last few
1189 * samples.
1148 * 1190 *
1149 * XXX: Since during noise floor calibration antennas are detached according to 1191 * The median of the values in the history is then loaded into the
1150 * the patent, we should stop tx queues here. 1192 * hardware for its own use for RSSI and CCA measurements.
1151 */ 1193 */
1152int 1194void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
1153ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
1154{ 1195{
1155 int ret; 1196 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
1156 unsigned int i; 1197 u32 val;
1157 s32 noise_floor; 1198 s16 nf, threshold;
1199 u8 ee_mode;
1158 1200
1159 /* 1201 /* keep last value if calibration hasn't completed */
1160 * Enable noise floor calibration 1202 if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) {
1161 */ 1203 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1162 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, 1204 "NF did not complete in calibration window\n");
1163 AR5K_PHY_AGCCTL_NF);
1164 1205
1165 ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, 1206 return;
1166 AR5K_PHY_AGCCTL_NF, 0, false);
1167 if (ret) {
1168 ATH5K_ERR(ah->ah_sc,
1169 "noise floor calibration timeout (%uMHz)\n", freq);
1170 return -EAGAIN;
1171 } 1207 }
1172 1208
1173 /* Wait until the noise floor is calibrated and read the value */ 1209 switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
1174 for (i = 20; i > 0; i--) { 1210 case CHANNEL_A:
1175 mdelay(1); 1211 case CHANNEL_T:
1176 noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); 1212 case CHANNEL_XR:
1177 noise_floor = AR5K_PHY_NF_RVAL(noise_floor); 1213 ee_mode = AR5K_EEPROM_MODE_11A;
1178 if (noise_floor & AR5K_PHY_NF_ACTIVE) { 1214 break;
1179 noise_floor = AR5K_PHY_NF_AVAL(noise_floor); 1215 case CHANNEL_G:
1180 1216 case CHANNEL_TG:
1181 if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) 1217 ee_mode = AR5K_EEPROM_MODE_11G;
1182 break; 1218 break;
1183 } 1219 default:
1220 case CHANNEL_B:
1221 ee_mode = AR5K_EEPROM_MODE_11B;
1222 break;
1184 } 1223 }
1185 1224
1186 ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1187 "noise floor %d\n", noise_floor);
1188 1225
1189 if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { 1226 /* completed NF calibration, test threshold */
1190 ATH5K_ERR(ah->ah_sc, 1227 nf = ath5k_hw_read_measured_noise_floor(ah);
1191 "noise floor calibration failed (%uMHz)\n", freq); 1228 threshold = ee->ee_noise_floor_thr[ee_mode];
1192 return -EAGAIN; 1229
1230 if (nf > threshold) {
1231 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1232 "noise floor failure detected; "
1233 "read %d, threshold %d\n",
1234 nf, threshold);
1235
1236 nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
1193 } 1237 }
1194 1238
1195 ah->ah_noise_floor = noise_floor; 1239 ath5k_hw_update_nfcal_hist(ah, nf);
1240 nf = ath5k_hw_get_median_noise_floor(ah);
1196 1241
1197 return 0; 1242 /* load noise floor (in .5 dBm) so the hardware will use it */
1243 val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M;
1244 val |= (nf * 2) & AR5K_PHY_NF_M;
1245 ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
1246
1247 AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
1248 ~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE));
1249
1250 ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
1251 0, false);
1252
1253 /*
1254 * Load a high max CCA Power value (-50 dBm in .5 dBm units)
1255 * so that we're not capped by the median we just loaded.
1256 * This will be used as the initial value for the next noise
1257 * floor calibration.
1258 */
1259 val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M);
1260 ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
1261 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
1262 AR5K_PHY_AGCCTL_NF_EN |
1263 AR5K_PHY_AGCCTL_NF_NOUPDATE |
1264 AR5K_PHY_AGCCTL_NF);
1265
1266 ah->ah_noise_floor = nf;
1267
1268 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1269 "noise floor calibrated: %d\n", nf);
1198} 1270}
1199 1271
1200/* 1272/*
@@ -1287,7 +1359,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
1287 return ret; 1359 return ret;
1288 } 1360 }
1289 1361
1290 ath5k_hw_noise_floor_calibration(ah, channel->center_freq); 1362 ath5k_hw_update_noise_floor(ah);
1291 1363
1292 /* 1364 /*
1293 * Re-enable RX/TX and beacons 1365 * Re-enable RX/TX and beacons
@@ -1315,38 +1387,39 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
1315 goto done; 1387 goto done;
1316 1388
1317 /* Calibration has finished, get the results and re-run */ 1389 /* Calibration has finished, get the results and re-run */
1390
1391 /* work around empty results which can apparently happen on 5212 */
1318 for (i = 0; i <= 10; i++) { 1392 for (i = 0; i <= 10; i++) {
1319 iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR); 1393 iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
1320 i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I); 1394 i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
1321 q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q); 1395 q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
1396 ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1397 "iq_corr:%x i_pwr:%x q_pwr:%x", iq_corr, i_pwr, q_pwr);
1398 if (i_pwr && q_pwr)
1399 break;
1322 } 1400 }
1323 1401
1324 i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7; 1402 i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
1325 q_coffd = q_pwr >> 7; 1403 q_coffd = q_pwr >> 7;
1326 1404
1327 /* No correction */ 1405 /* protect against divide by 0 and loss of sign bits */
1328 if (i_coffd == 0 || q_coffd == 0) 1406 if (i_coffd == 0 || q_coffd < 2)
1329 goto done; 1407 goto done;
1330 1408
1331 i_coff = ((-iq_corr) / i_coffd) & 0x3f; 1409 i_coff = (-iq_corr) / i_coffd;
1410 i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
1332 1411
1333 /* Boundary check */ 1412 q_coff = (i_pwr / q_coffd) - 128;
1334 if (i_coff > 31) 1413 q_coff = clamp(q_coff, -16, 15); /* signed 5 bit */
1335 i_coff = 31;
1336 if (i_coff < -32)
1337 i_coff = -32;
1338 1414
1339 q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f; 1415 ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1340 1416 "new I:%d Q:%d (i_coffd:%x q_coffd:%x)",
1341 /* Boundary check */ 1417 i_coff, q_coff, i_coffd, q_coffd);
1342 if (q_coff > 15)
1343 q_coff = 15;
1344 if (q_coff < -16)
1345 q_coff = -16;
1346 1418
1347 /* Commit new I/Q value */ 1419 /* Commit new I/Q values (set enable bit last to match HAL sources) */
1348 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE | 1420 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_I_COFF, i_coff);
1349 ((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S)); 1421 AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_Q_Q_COFF, q_coff);
1422 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE);
1350 1423
1351 /* Re-enable calibration -if we don't we'll commit 1424 /* Re-enable calibration -if we don't we'll commit
1352 * the same values again and again */ 1425 * the same values again and again */
@@ -1360,7 +1433,7 @@ done:
1360 * since noise floor calibration interrupts rx path while I/Q 1433 * since noise floor calibration interrupts rx path while I/Q
1361 * calibration doesn't. We don't need to run noise floor calibration 1434 * calibration doesn't. We don't need to run noise floor calibration
1362 * as often as I/Q calibration.*/ 1435 * as often as I/Q calibration.*/
1363 ath5k_hw_noise_floor_calibration(ah, channel->center_freq); 1436 ath5k_hw_update_noise_floor(ah);
1364 1437
1365 /* Initiate a gain_F calibration */ 1438 /* Initiate a gain_F calibration */
1366 ath5k_hw_request_rfgain_probe(ah); 1439 ath5k_hw_request_rfgain_probe(ah);
@@ -1802,7 +1875,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
1802 break; 1875 break;
1803 case AR5K_ANTMODE_FIXED_A: 1876 case AR5K_ANTMODE_FIXED_A:
1804 def_ant = 1; 1877 def_ant = 1;
1805 tx_ant = 0; 1878 tx_ant = 1;
1806 use_def_for_tx = true; 1879 use_def_for_tx = true;
1807 update_def_on_tx = false; 1880 update_def_on_tx = false;
1808 use_def_for_rts = true; 1881 use_def_for_rts = true;
@@ -1811,7 +1884,7 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
1811 break; 1884 break;
1812 case AR5K_ANTMODE_FIXED_B: 1885 case AR5K_ANTMODE_FIXED_B:
1813 def_ant = 2; 1886 def_ant = 2;
1814 tx_ant = 0; 1887 tx_ant = 2;
1815 use_def_for_tx = true; 1888 use_def_for_tx = true;
1816 update_def_on_tx = false; 1889 update_def_on_tx = false;
1817 use_def_for_rts = true; 1890 use_def_for_rts = true;
@@ -2675,7 +2748,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
2675 /* Fill curves in reverse order 2748 /* Fill curves in reverse order
2676 * from lower power (max gain) 2749 * from lower power (max gain)
2677 * to higher power. Use curve -> idx 2750 * to higher power. Use curve -> idx
2678 * backmaping we did on eeprom init */ 2751 * backmapping we did on eeprom init */
2679 u8 idx = pdg_curve_to_idx[pdg]; 2752 u8 idx = pdg_curve_to_idx[pdg];
2680 2753
2681 /* Grab the needed curves by index */ 2754 /* Grab the needed curves by index */
@@ -2777,7 +2850,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah,
2777 /* Now we have a set of curves for this 2850 /* Now we have a set of curves for this
2778 * channel on tmpL (x range is table_max - table_min 2851 * channel on tmpL (x range is table_max - table_min
2779 * and y values are tmpL[pdg][]) sorted in the same 2852 * and y values are tmpL[pdg][]) sorted in the same
2780 * order as EEPROM (because we've used the backmaping). 2853 * order as EEPROM (because we've used the backmapping).
2781 * So for RF5112 it's from higher power to lower power 2854 * So for RF5112 it's from higher power to lower power
2782 * and for RF2413 it's from lower power to higher power. 2855 * and for RF2413 it's from lower power to higher power.
2783 * For RF5111 we only have one curve. */ 2856 * For RF5111 we only have one curve. */
@@ -2954,8 +3027,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
2954 ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); 3027 ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
2955 return -EINVAL; 3028 return -EINVAL;
2956 } 3029 }
2957 if (txpower == 0)
2958 txpower = AR5K_TUNE_DEFAULT_TXPOWER;
2959 3030
2960 /* Reset TX power values */ 3031 /* Reset TX power values */
2961 memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); 3032 memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));