aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h13
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c185
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h11
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c17
5 files changed, 148 insertions, 80 deletions
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 647d826bf5fb..6a2a96761111 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -198,6 +198,7 @@
198#define AR5K_TUNE_CWMAX_11B 1023 198#define AR5K_TUNE_CWMAX_11B 1023
199#define AR5K_TUNE_CWMAX_XR 7 199#define AR5K_TUNE_CWMAX_XR 7
200#define AR5K_TUNE_NOISE_FLOOR -72 200#define AR5K_TUNE_NOISE_FLOOR -72
201#define AR5K_TUNE_CCA_MAX_GOOD_VALUE -95
201#define AR5K_TUNE_MAX_TXPOWER 63 202#define AR5K_TUNE_MAX_TXPOWER 63
202#define AR5K_TUNE_DEFAULT_TXPOWER 25 203#define AR5K_TUNE_DEFAULT_TXPOWER 25
203#define AR5K_TUNE_TPC_TXPOWER false 204#define AR5K_TUNE_TPC_TXPOWER false
@@ -1006,6 +1007,14 @@ struct ath5k_capabilities {
1006 } cap_queues; 1007 } cap_queues;
1007}; 1008};
1008 1009
1010/* size of noise floor history (keep it a power of two) */
1011#define ATH5K_NF_CAL_HIST_MAX 8
1012struct ath5k_nfcal_hist
1013{
1014 s16 index; /* current index into nfval */
1015 s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */
1016};
1017
1009 1018
1010/***************************************\ 1019/***************************************\
1011 HARDWARE ABSTRACTION LAYER STRUCTURE 1020 HARDWARE ABSTRACTION LAYER STRUCTURE
@@ -1112,6 +1121,8 @@ struct ath5k_hw {
1112 struct ieee80211_channel r_last_channel; 1121 struct ieee80211_channel r_last_channel;
1113 } ah_radar; 1122 } ah_radar;
1114 1123
1124 struct ath5k_nfcal_hist ah_nfcal_hist;
1125
1115 /* noise floor from last periodic calibration */ 1126 /* noise floor from last periodic calibration */
1116 s32 ah_noise_floor; 1127 s32 ah_noise_floor;
1117 1128
@@ -1274,8 +1285,10 @@ extern int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
1274extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); 1285extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
1275extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); 1286extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
1276/* PHY calibration */ 1287/* PHY calibration */
1288void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
1277extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); 1289extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
1278extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); 1290extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
1291extern s16 ath5k_hw_get_noise_floor(struct ath5k_hw *ah);
1279extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); 1292extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
1280/* Spur mitigation */ 1293/* Spur mitigation */
1281bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, 1294bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index 92995adeb5cd..42284445b75e 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -331,6 +331,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
331 331
332 ath5k_hw_rfgain_opt_init(ah); 332 ath5k_hw_rfgain_opt_init(ah);
333 333
334 ath5k_hw_init_nfcal_hist(ah);
335
334 /* turn on HW LEDs */ 336 /* turn on HW LEDs */
335 ath5k_hw_set_ledstate(ah, AR5K_LED_INIT); 337 ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
336 338
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 1a039f2bd732..895990751d36 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1124,77 +1124,148 @@ ath5k_hw_calibration_poll(struct ath5k_hw *ah)
1124 ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION; 1124 ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
1125 AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); 1125 AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
1126 } 1126 }
1127}
1127 1128
1129static int sign_extend(int val, const int nbits)
1130{
1131 int order = BIT(nbits-1);
1132 return (val ^ order) - order;
1128} 1133}
1129 1134
1130/** 1135static s32 ath5k_hw_read_measured_noise_floor(struct ath5k_hw *ah)
1131 * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration 1136{
1132 * 1137 s32 val;
1133 * @ah: struct ath5k_hw pointer we are operating on 1138
1134 * @freq: the channel frequency, just used for error logging 1139 val = ath5k_hw_reg_read(ah, AR5K_PHY_NF);
1135 * 1140 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 1141}
1137 * it to complete. Then the noise floor value is compared to some maximum 1142
1138 * noise floor we consider valid. 1143void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah)
1139 * 1144{
1140 * Note that this is different from what the madwifi HAL does: it reads the 1145 int i;
1141 * noise floor and afterwards initiates the calibration. Since the noise floor 1146
1142 * calibration can take some time to finish, depending on the current channel 1147 ah->ah_nfcal_hist.index = 0;
1143 * use, that avoids the occasional timeout warnings we are seeing now. 1148 for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++)
1144 * 1149 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: 1150}
1146 * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \ 1151
1147 * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7 1152static void ath5k_hw_update_nfcal_hist(struct ath5k_hw *ah, s16 noise_floor)
1153{
1154 struct ath5k_nfcal_hist *hist = &ah->ah_nfcal_hist;
1155 hist->index = (hist->index + 1) & (ATH5K_NF_CAL_HIST_MAX-1);
1156 hist->nfval[hist->index] = noise_floor;
1157}
1158
1159static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
1160{
1161 s16 sort[ATH5K_NF_CAL_HIST_MAX];
1162 s16 tmp;
1163 int i, j;
1164
1165 memcpy(sort, ah->ah_nfcal_hist.nfval, sizeof(sort));
1166 for (i = 0; i < ATH5K_NF_CAL_HIST_MAX - 1; i++) {
1167 for (j = 1; j < ATH5K_NF_CAL_HIST_MAX - i; j++) {
1168 if (sort[j] > sort[j-1]) {
1169 tmp = sort[j];
1170 sort[j] = sort[j-1];
1171 sort[j-1] = tmp;
1172 }
1173 }
1174 }
1175 for (i = 0; i < ATH5K_NF_CAL_HIST_MAX; i++) {
1176 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1177 "cal %d:%d\n", i, sort[i]);
1178 }
1179 return sort[(ATH5K_NF_CAL_HIST_MAX-1) / 2];
1180}
1181
1182/*
1183 * When we tell the hardware to perform a noise floor calibration
1184 * by setting the AR5K_PHY_AGCCTL_NF bit, it will periodically
1185 * sample-and-hold the minimum noise level seen at the antennas.
1186 * This value is then stored in a ring buffer of recently measured
1187 * noise floor values so we have a moving window of the last few
1188 * samples.
1148 * 1189 *
1149 * XXX: Since during noise floor calibration antennas are detached according to 1190 * The median of the values in the history is then loaded into the
1150 * the patent, we should stop tx queues here. 1191 * hardware for its own use for RSSI and CCA measurements.
1151 */ 1192 */
1152int 1193void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
1153ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
1154{ 1194{
1155 int ret; 1195 struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
1156 unsigned int i; 1196 u32 val;
1157 s32 noise_floor; 1197 s16 nf, threshold;
1198 u8 ee_mode;
1158 1199
1159 /* 1200 /* keep last value if calibration hasn't completed */
1160 * Enable noise floor calibration 1201 if (ath5k_hw_reg_read(ah, AR5K_PHY_AGCCTL) & AR5K_PHY_AGCCTL_NF) {
1161 */ 1202 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1162 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, 1203 "NF did not complete in calibration window\n");
1163 AR5K_PHY_AGCCTL_NF);
1164 1204
1165 ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, 1205 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 } 1206 }
1172 1207
1173 /* Wait until the noise floor is calibrated and read the value */ 1208 switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
1174 for (i = 20; i > 0; i--) { 1209 case CHANNEL_A:
1175 mdelay(1); 1210 case CHANNEL_T:
1176 noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); 1211 case CHANNEL_XR:
1177 noise_floor = AR5K_PHY_NF_RVAL(noise_floor); 1212 ee_mode = AR5K_EEPROM_MODE_11A;
1178 if (noise_floor & AR5K_PHY_NF_ACTIVE) { 1213 break;
1179 noise_floor = AR5K_PHY_NF_AVAL(noise_floor); 1214 case CHANNEL_G:
1180 1215 case CHANNEL_TG:
1181 if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) 1216 ee_mode = AR5K_EEPROM_MODE_11G;
1182 break; 1217 break;
1183 } 1218 default:
1219 case CHANNEL_B:
1220 ee_mode = AR5K_EEPROM_MODE_11B;
1221 break;
1184 } 1222 }
1185 1223
1186 ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1187 "noise floor %d\n", noise_floor);
1188 1224
1189 if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { 1225 /* completed NF calibration, test threshold */
1190 ATH5K_ERR(ah->ah_sc, 1226 nf = ath5k_hw_read_measured_noise_floor(ah);
1191 "noise floor calibration failed (%uMHz)\n", freq); 1227 threshold = ee->ee_noise_floor_thr[ee_mode];
1192 return -EAGAIN; 1228
1229 if (nf > threshold) {
1230 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1231 "noise floor failure detected; "
1232 "read %d, threshold %d\n",
1233 nf, threshold);
1234
1235 nf = AR5K_TUNE_CCA_MAX_GOOD_VALUE;
1193 } 1236 }
1194 1237
1195 ah->ah_noise_floor = noise_floor; 1238 ath5k_hw_update_nfcal_hist(ah, nf);
1239 nf = ath5k_hw_get_median_noise_floor(ah);
1196 1240
1197 return 0; 1241 /* load noise floor (in .5 dBm) so the hardware will use it */
1242 val = ath5k_hw_reg_read(ah, AR5K_PHY_NF) & ~AR5K_PHY_NF_M;
1243 val |= (nf * 2) & AR5K_PHY_NF_M;
1244 ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
1245
1246 AR5K_REG_MASKED_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
1247 ~(AR5K_PHY_AGCCTL_NF_EN | AR5K_PHY_AGCCTL_NF_NOUPDATE));
1248
1249 ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_NF,
1250 0, false);
1251
1252 /*
1253 * Load a high max CCA Power value (-50 dBm in .5 dBm units)
1254 * so that we're not capped by the median we just loaded.
1255 * This will be used as the initial value for the next noise
1256 * floor calibration.
1257 */
1258 val = (val & ~AR5K_PHY_NF_M) | ((-50 * 2) & AR5K_PHY_NF_M);
1259 ath5k_hw_reg_write(ah, val, AR5K_PHY_NF);
1260 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
1261 AR5K_PHY_AGCCTL_NF_EN |
1262 AR5K_PHY_AGCCTL_NF_NOUPDATE |
1263 AR5K_PHY_AGCCTL_NF);
1264
1265 ah->ah_noise_floor = nf;
1266
1267 ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE,
1268 "noise floor calibrated: %d\n", nf);
1198} 1269}
1199 1270
1200/* 1271/*
@@ -1287,7 +1358,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
1287 return ret; 1358 return ret;
1288 } 1359 }
1289 1360
1290 ath5k_hw_noise_floor_calibration(ah, channel->center_freq); 1361 ath5k_hw_update_noise_floor(ah);
1291 1362
1292 /* 1363 /*
1293 * Re-enable RX/TX and beacons 1364 * Re-enable RX/TX and beacons
@@ -1360,7 +1431,7 @@ done:
1360 * since noise floor calibration interrupts rx path while I/Q 1431 * since noise floor calibration interrupts rx path while I/Q
1361 * calibration doesn't. We don't need to run noise floor calibration 1432 * calibration doesn't. We don't need to run noise floor calibration
1362 * as often as I/Q calibration.*/ 1433 * as often as I/Q calibration.*/
1363 ath5k_hw_noise_floor_calibration(ah, channel->center_freq); 1434 ath5k_hw_update_noise_floor(ah);
1364 1435
1365 /* Initiate a gain_F calibration */ 1436 /* Initiate a gain_F calibration */
1366 ath5k_hw_request_rfgain_probe(ah); 1437 ath5k_hw_request_rfgain_probe(ah);
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 64227abe3c20..4cb9c5df9f46 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -2033,17 +2033,14 @@
2033#define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */ 2033#define AR5K_PHY_AGCCTL_NF_NOUPDATE 0x00020000 /* Don't update nf automaticaly */
2034 2034
2035/* 2035/*
2036 * PHY noise floor status register 2036 * PHY noise floor status register (CCA = Clear Channel Assessment)
2037 */ 2037 */
2038#define AR5K_PHY_NF 0x9864 /* Register address */ 2038#define AR5K_PHY_NF 0x9864 /* Register address */
2039#define AR5K_PHY_NF_M 0x000001ff /* Noise floor mask */ 2039#define AR5K_PHY_NF_M 0x000001ff /* Noise floor, written to hardware in 1/2 dBm units */
2040#define AR5K_PHY_NF_ACTIVE 0x00000100 /* Noise floor calibration still active */ 2040#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
2041#define AR5K_PHY_NF_RVAL(_n) (((_n) >> 19) & AR5K_PHY_NF_M)
2042#define AR5K_PHY_NF_AVAL(_n) (-((_n) ^ AR5K_PHY_NF_M) + 1)
2043#define AR5K_PHY_NF_SVAL(_n) (((_n) & AR5K_PHY_NF_M) | (1 << 9))
2044#define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */ 2041#define AR5K_PHY_NF_THRESH62 0x0007f000 /* Thresh62 -check ANI patent- (field) */
2045#define AR5K_PHY_NF_THRESH62_S 12 2042#define AR5K_PHY_NF_THRESH62_S 12
2046#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* ??? */ 2043#define AR5K_PHY_NF_MINCCA_PWR 0x0ff80000 /* Minimum measured noise level, read from hardware in 1 dBm units */
2047#define AR5K_PHY_NF_MINCCA_PWR_S 19 2044#define AR5K_PHY_NF_MINCCA_PWR_S 19
2048 2045
2049/* 2046/*
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 3dab3d856d7b..62954fc77869 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -1293,7 +1293,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
1293 * out and/or noise floor calibration might timeout. 1293 * out and/or noise floor calibration might timeout.
1294 */ 1294 */
1295 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, 1295 AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
1296 AR5K_PHY_AGCCTL_CAL); 1296 AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
1297 1297
1298 /* At the same time start I/Q calibration for QAM constellation 1298 /* At the same time start I/Q calibration for QAM constellation
1299 * -no need for CCK- */ 1299 * -no need for CCK- */
@@ -1314,21 +1314,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
1314 channel->center_freq); 1314 channel->center_freq);
1315 } 1315 }
1316 1316
1317 /*
1318 * If we run NF calibration before AGC, it always times out.
1319 * Binary HAL starts NF and AGC calibration at the same time
1320 * and only waits for AGC to finish. Also if AGC or NF cal.
1321 * times out, reset doesn't fail on binary HAL. I believe
1322 * that's wrong because since rx path is routed to a detector,
1323 * if cal. doesn't finish we won't have RX. Sam's HAL for AR5210/5211
1324 * enables noise floor calibration after offset calibration and if noise
1325 * floor calibration fails, reset fails. I believe that's
1326 * a better approach, we just need to find a polling interval
1327 * that suits best, even if reset continues we need to make
1328 * sure that rx path is ready.
1329 */
1330 ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
1331
1332 /* Restore antenna mode */ 1317 /* Restore antenna mode */
1333 ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode); 1318 ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
1334 1319