1/****************************************************************************** 2 * 3 * GPL LICENSE SUMMARY 4 * 5 * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of version 2 of the GNU General Public License as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 19 * USA 20 * 21 * The full GNU General Public License is included in this distribution 22 * in the file called LICENSE.GPL. 23 * 24 * Contact Information: 25 * Intel Linux Wireless <ilw@linux.intel.com> 26 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 27 * 28 *****************************************************************************/ 29 30#include <linux/kernel.h> 31#include <linux/module.h> 32#include <linux/init.h> 33#include <linux/sched.h> 34 35#include "iwl-dev.h" 36#include "iwl-core.h" 37#include "iwl-calib.h" 38#include "iwl-sta.h" 39#include "iwl-io.h" 40#include "iwl-helpers.h" 41#include "iwl-agn-hw.h" 42#include "iwl-agn.h" 43 44void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, 45 struct iwl_rx_mem_buffer *rxb) 46 47{ 48 struct iwl_rx_packet *pkt = rxb_addr(rxb); 49 struct iwl_missed_beacon_notif *missed_beacon; 50 51 missed_beacon = &pkt->u.missed_beacon; 52 if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) > 53 priv->missed_beacon_threshold) { 54 IWL_DEBUG_CALIB(priv, 55 "missed bcn cnsq %d totl %d rcd %d expctd %d\n", 56 le32_to_cpu(missed_beacon->consecutive_missed_beacons), 57 le32_to_cpu(missed_beacon->total_missed_becons), 58 le32_to_cpu(missed_beacon->num_recvd_beacons), 59 le32_to_cpu(missed_beacon->num_expected_beacons)); 60 if (!test_bit(STATUS_SCANNING, &priv->status)) 61 iwl_init_sensitivity(priv); 62 } 63} 64 65/* Calculate noise level, based on measurements during network silence just 66 * before arriving beacon. This measurement can be done only if we know 67 * exactly when to expect beacons, therefore only when we're associated. */ 68static void iwl_rx_calc_noise(struct iwl_priv *priv) 69{ 70 struct statistics_rx_non_phy *rx_info; 71 int num_active_rx = 0; 72 int total_silence = 0; 73 int bcn_silence_a, bcn_silence_b, bcn_silence_c; 74 int last_rx_noise; 75 76 if (priv->cfg->bt_statistics) 77 rx_info = &(priv->_agn.statistics_bt.rx.general.common); 78 else 79 rx_info = &(priv->_agn.statistics.rx.general); 80 bcn_silence_a = 81 le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER; 82 bcn_silence_b = 83 le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER; 84 bcn_silence_c = 85 le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER; 86 87 if (bcn_silence_a) { 88 total_silence += bcn_silence_a; 89 num_active_rx++; 90 } 91 if (bcn_silence_b) { 92 total_silence += bcn_silence_b; 93 num_active_rx++; 94 } 95 if (bcn_silence_c) { 96 total_silence += bcn_silence_c; 97 num_active_rx++; 98 } 99 100 /* Average among active antennas */ 101 if (num_active_rx) 102 last_rx_noise = (total_silence / num_active_rx) - 107; 103 else 104 last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; 105 106 IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n", 107 bcn_silence_a, bcn_silence_b, bcn_silence_c, 108 last_rx_noise); 109} 110 111#ifdef CONFIG_IWLWIFI_DEBUGFS 112static void iwl_accumulative_statistics(struct iwl_priv *priv, 113 __le32 *stats) 114{ 115 int i, size; 116 __le32 *prev_stats; 117 u32 *accum_stats; 118 u32 *delta, *max_delta; 119 struct statistics_general_common *general, *accum_general; 120 struct statistics_tx *tx, *accum_tx; 121 122 if (priv->cfg->bt_statistics) { 123 prev_stats = (__le32 *)&priv->_agn.statistics_bt; 124 accum_stats = (u32 *)&priv->_agn.accum_statistics_bt; 125 size = sizeof(struct iwl_bt_notif_statistics); 126 general = &priv->_agn.statistics_bt.general.common; 127 accum_general = &priv->_agn.accum_statistics_bt.general.common; 128 tx = &priv->_agn.statistics_bt.tx; 129 accum_tx = &priv->_agn.accum_statistics_bt.tx; 130 delta = (u32 *)&priv->_agn.delta_statistics_bt; 131 max_delta = (u32 *)&priv->_agn.max_delta_bt; 132 } else { 133 prev_stats = (__le32 *)&priv->_agn.statistics; 134 accum_stats = (u32 *)&priv->_agn.accum_statistics; 135 size = sizeof(struct iwl_notif_statistics); 136 general = &priv->_agn.statistics.general.common; 137 accum_general = &priv->_agn.accum_statistics.general.common; 138 tx = &priv->_agn.statistics.tx; 139 accum_tx = &priv->_agn.accum_statistics.tx; 140 delta = (u32 *)&priv->_agn.delta_statistics; 141 max_delta = (u32 *)&priv->_agn.max_delta; 142 } 143 for (i = sizeof(__le32); i < size; 144 i += sizeof(__le32), stats++, prev_stats++, delta++, 145 max_delta++, accum_stats++) { 146 if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) { 147 *delta = (le32_to_cpu(*stats) - 148 le32_to_cpu(*prev_stats)); 149 *accum_stats += *delta; 150 if (*delta > *max_delta) 151 *max_delta = *delta; 152 } 153 } 154 155 /* reset accumulative statistics for "no-counter" type statistics */ 156 accum_general->temperature = general->temperature; 157 accum_general->temperature_m = general->temperature_m; 158 accum_general->ttl_timestamp = general->ttl_timestamp; 159 accum_tx->tx_power.ant_a = tx->tx_power.ant_a; 160 accum_tx->tx_power.ant_b = tx->tx_power.ant_b; 161 accum_tx->tx_power.ant_c = tx->tx_power.ant_c; 162} 163#endif 164 165#define REG_RECALIB_PERIOD (60) 166 167/** 168 * iwl_good_plcp_health - checks for plcp error. 169 * 170 * When the plcp error is exceeding the thresholds, reset the radio 171 * to improve the throughput. 172 */ 173bool iwl_good_plcp_health(struct iwl_priv *priv, 174 struct iwl_rx_packet *pkt) 175{ 176 bool rc = true; 177 int combined_plcp_delta; 178 unsigned int plcp_msec; 179 unsigned long plcp_received_jiffies; 180 181 if (priv->cfg->plcp_delta_threshold == 182 IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { 183 IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); 184 return rc; 185 } 186 187 /* 188 * check for plcp_err and trigger radio reset if it exceeds 189 * the plcp error threshold plcp_delta. 190 */ 191 plcp_received_jiffies = jiffies; 192 plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - 193 (long) priv->plcp_jiffies); 194 priv->plcp_jiffies = plcp_received_jiffies; 195 /* 196 * check to make sure plcp_msec is not 0 to prevent division 197 * by zero. 198 */ 199 if (plcp_msec) { 200 struct statistics_rx_phy *ofdm; 201 struct statistics_rx_ht_phy *ofdm_ht; 202 203 if (priv->cfg->bt_statistics) { 204 ofdm = &pkt->u.stats_bt.rx.ofdm; 205 ofdm_ht = &pkt->u.stats_bt.rx.ofdm_ht; 206 combined_plcp_delta = 207 (le32_to_cpu(ofdm->plcp_err) - 208 le32_to_cpu(priv->_agn.statistics_bt. 209 rx.ofdm.plcp_err)) + 210 (le32_to_cpu(ofdm_ht->plcp_err) - 211 le32_to_cpu(priv->_agn.statistics_bt. 212 rx.ofdm_ht.plcp_err)); 213 } else { 214 ofdm = &pkt->u.stats.rx.ofdm; 215 ofdm_ht = &pkt->u.stats.rx.ofdm_ht; 216 combined_plcp_delta = 217 (le32_to_cpu(ofdm->plcp_err) - 218 le32_to_cpu(priv->_agn.statistics. 219 rx.ofdm.plcp_err)) + 220 (le32_to_cpu(ofdm_ht->plcp_err) - 221 le32_to_cpu(priv->_agn.statistics. 222 rx.ofdm_ht.plcp_err)); 223 } 224 225 if ((combined_plcp_delta > 0) && 226 ((combined_plcp_delta * 100) / plcp_msec) > 227 priv->cfg->plcp_delta_threshold) { 228 /* 229 * if plcp_err exceed the threshold, 230 * the following data is printed in csv format: 231 * Text: plcp_err exceeded %d, 232 * Received ofdm.plcp_err, 233 * Current ofdm.plcp_err, 234 * Received ofdm_ht.plcp_err, 235 * Current ofdm_ht.plcp_err, 236 * combined_plcp_delta, 237 * plcp_msec 238 */ 239 IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " 240 "%u, %u, %u, %u, %d, %u mSecs\n", 241 priv->cfg->plcp_delta_threshold, 242 le32_to_cpu(ofdm->plcp_err), 243 le32_to_cpu(ofdm->plcp_err), 244 le32_to_cpu(ofdm_ht->plcp_err), 245 le32_to_cpu(ofdm_ht->plcp_err), 246 combined_plcp_delta, plcp_msec); 247 248 rc = false; 249 } 250 } 251 return rc; 252} 253 254void iwl_rx_statistics(struct iwl_priv *priv, 255 struct iwl_rx_mem_buffer *rxb) 256{ 257 int change; 258 struct iwl_rx_packet *pkt = rxb_addr(rxb); 259 260 if (priv->cfg->bt_statistics) { 261 IWL_DEBUG_RX(priv, 262 "Statistics notification received (%d vs %d).\n", 263 (int)sizeof(struct iwl_bt_notif_statistics), 264 le32_to_cpu(pkt->len_n_flags) & 265 FH_RSCSR_FRAME_SIZE_MSK); 266 267 change = ((priv->_agn.statistics_bt.general.common.temperature != 268 pkt->u.stats_bt.general.common.temperature) || 269 ((priv->_agn.statistics_bt.flag & 270 STATISTICS_REPLY_FLG_HT40_MODE_MSK) != 271 (pkt->u.stats_bt.flag & 272 STATISTICS_REPLY_FLG_HT40_MODE_MSK))); 273#ifdef CONFIG_IWLWIFI_DEBUGFS 274 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); 275#endif 276 277 } else { 278 IWL_DEBUG_RX(priv, 279 "Statistics notification received (%d vs %d).\n", 280 (int)sizeof(struct iwl_notif_statistics), 281 le32_to_cpu(pkt->len_n_flags) & 282 FH_RSCSR_FRAME_SIZE_MSK); 283 284 change = ((priv->_agn.statistics.general.common.temperature != 285 pkt->u.stats.general.common.temperature) || 286 ((priv->_agn.statistics.flag & 287 STATISTICS_REPLY_FLG_HT40_MODE_MSK) != 288 (pkt->u.stats.flag & 289 STATISTICS_REPLY_FLG_HT40_MODE_MSK))); 290#ifdef CONFIG_IWLWIFI_DEBUGFS 291 iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); 292#endif 293 294 } 295 296 iwl_recover_from_statistics(priv, pkt); 297 298 if (priv->cfg->bt_statistics) 299 memcpy(&priv->_agn.statistics_bt, &pkt->u.stats_bt, 300 sizeof(priv->_agn.statistics_bt)); 301 else 302 memcpy(&priv->_agn.statistics, &pkt->u.stats, 303 sizeof(priv->_agn.statistics)); 304 305 set_bit(STATUS_STATISTICS, &priv->status); 306 307 /* Reschedule the statistics timer to occur in 308 * REG_RECALIB_PERIOD seconds to ensure we get a 309 * thermal update even if the uCode doesn't give 310 * us one */ 311 mod_timer(&priv->statistics_periodic, jiffies + 312 msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); 313 314 if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && 315 (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { 316 iwl_rx_calc_noise(priv); 317 queue_work(priv->workqueue, &priv->run_time_calib_work); 318 } 319 if (priv->cfg->ops->lib->temp_ops.temperature && change) 320 priv->cfg->ops->lib->temp_ops.temperature(priv); 321} 322 323void iwl_reply_statistics(struct iwl_priv *priv, 324 struct iwl_rx_mem_buffer *rxb) 325{ 326 struct iwl_rx_packet *pkt = rxb_addr(rxb); 327 328 if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) { 329#ifdef CONFIG_IWLWIFI_DEBUGFS 330 memset(&priv->_agn.accum_statistics, 0, 331 sizeof(struct iwl_notif_statistics)); 332 memset(&priv->_agn.delta_statistics, 0, 333 sizeof(struct iwl_notif_statistics)); 334 memset(&priv->_agn.max_delta, 0, 335 sizeof(struct iwl_notif_statistics)); 336 memset(&priv->_agn.accum_statistics_bt, 0, 337 sizeof(struct iwl_bt_notif_statistics)); 338 memset(&priv->_agn.delta_statistics_bt, 0, 339 sizeof(struct iwl_bt_notif_statistics)); 340 memset(&priv->_agn.max_delta_bt, 0, 341 sizeof(struct iwl_bt_notif_statistics)); 342#endif 343 IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); 344 } 345 iwl_rx_statistics(priv, rxb); 346} 347