aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-rx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c289
1 files changed, 127 insertions, 162 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index e12f11d50b88..db6c90f6affe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -40,89 +40,86 @@
40#include "iwl-agn.h" 40#include "iwl-agn.h"
41#include "iwl-shared.h" 41#include "iwl-shared.h"
42 42
43const char *get_cmd_string(u8 cmd) 43#define IWL_CMD_ENTRY(x) [x] = #x
44{ 44
45 switch (cmd) { 45const char *iwl_dvm_cmd_strings[REPLY_MAX] = {
46 IWL_CMD(REPLY_ALIVE); 46 IWL_CMD_ENTRY(REPLY_ALIVE),
47 IWL_CMD(REPLY_ERROR); 47 IWL_CMD_ENTRY(REPLY_ERROR),
48 IWL_CMD(REPLY_ECHO); 48 IWL_CMD_ENTRY(REPLY_ECHO),
49 IWL_CMD(REPLY_RXON); 49 IWL_CMD_ENTRY(REPLY_RXON),
50 IWL_CMD(REPLY_RXON_ASSOC); 50 IWL_CMD_ENTRY(REPLY_RXON_ASSOC),
51 IWL_CMD(REPLY_QOS_PARAM); 51 IWL_CMD_ENTRY(REPLY_QOS_PARAM),
52 IWL_CMD(REPLY_RXON_TIMING); 52 IWL_CMD_ENTRY(REPLY_RXON_TIMING),
53 IWL_CMD(REPLY_ADD_STA); 53 IWL_CMD_ENTRY(REPLY_ADD_STA),
54 IWL_CMD(REPLY_REMOVE_STA); 54 IWL_CMD_ENTRY(REPLY_REMOVE_STA),
55 IWL_CMD(REPLY_REMOVE_ALL_STA); 55 IWL_CMD_ENTRY(REPLY_REMOVE_ALL_STA),
56 IWL_CMD(REPLY_TXFIFO_FLUSH); 56 IWL_CMD_ENTRY(REPLY_TXFIFO_FLUSH),
57 IWL_CMD(REPLY_WEPKEY); 57 IWL_CMD_ENTRY(REPLY_WEPKEY),
58 IWL_CMD(REPLY_TX); 58 IWL_CMD_ENTRY(REPLY_TX),
59 IWL_CMD(REPLY_LEDS_CMD); 59 IWL_CMD_ENTRY(REPLY_LEDS_CMD),
60 IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); 60 IWL_CMD_ENTRY(REPLY_TX_LINK_QUALITY_CMD),
61 IWL_CMD(COEX_PRIORITY_TABLE_CMD); 61 IWL_CMD_ENTRY(COEX_PRIORITY_TABLE_CMD),
62 IWL_CMD(COEX_MEDIUM_NOTIFICATION); 62 IWL_CMD_ENTRY(COEX_MEDIUM_NOTIFICATION),
63 IWL_CMD(COEX_EVENT_CMD); 63 IWL_CMD_ENTRY(COEX_EVENT_CMD),
64 IWL_CMD(REPLY_QUIET_CMD); 64 IWL_CMD_ENTRY(REPLY_QUIET_CMD),
65 IWL_CMD(REPLY_CHANNEL_SWITCH); 65 IWL_CMD_ENTRY(REPLY_CHANNEL_SWITCH),
66 IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); 66 IWL_CMD_ENTRY(CHANNEL_SWITCH_NOTIFICATION),
67 IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); 67 IWL_CMD_ENTRY(REPLY_SPECTRUM_MEASUREMENT_CMD),
68 IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); 68 IWL_CMD_ENTRY(SPECTRUM_MEASURE_NOTIFICATION),
69 IWL_CMD(POWER_TABLE_CMD); 69 IWL_CMD_ENTRY(POWER_TABLE_CMD),
70 IWL_CMD(PM_SLEEP_NOTIFICATION); 70 IWL_CMD_ENTRY(PM_SLEEP_NOTIFICATION),
71 IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); 71 IWL_CMD_ENTRY(PM_DEBUG_STATISTIC_NOTIFIC),
72 IWL_CMD(REPLY_SCAN_CMD); 72 IWL_CMD_ENTRY(REPLY_SCAN_CMD),
73 IWL_CMD(REPLY_SCAN_ABORT_CMD); 73 IWL_CMD_ENTRY(REPLY_SCAN_ABORT_CMD),
74 IWL_CMD(SCAN_START_NOTIFICATION); 74 IWL_CMD_ENTRY(SCAN_START_NOTIFICATION),
75 IWL_CMD(SCAN_RESULTS_NOTIFICATION); 75 IWL_CMD_ENTRY(SCAN_RESULTS_NOTIFICATION),
76 IWL_CMD(SCAN_COMPLETE_NOTIFICATION); 76 IWL_CMD_ENTRY(SCAN_COMPLETE_NOTIFICATION),
77 IWL_CMD(BEACON_NOTIFICATION); 77 IWL_CMD_ENTRY(BEACON_NOTIFICATION),
78 IWL_CMD(REPLY_TX_BEACON); 78 IWL_CMD_ENTRY(REPLY_TX_BEACON),
79 IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); 79 IWL_CMD_ENTRY(WHO_IS_AWAKE_NOTIFICATION),
80 IWL_CMD(QUIET_NOTIFICATION); 80 IWL_CMD_ENTRY(QUIET_NOTIFICATION),
81 IWL_CMD(REPLY_TX_PWR_TABLE_CMD); 81 IWL_CMD_ENTRY(REPLY_TX_PWR_TABLE_CMD),
82 IWL_CMD(MEASURE_ABORT_NOTIFICATION); 82 IWL_CMD_ENTRY(MEASURE_ABORT_NOTIFICATION),
83 IWL_CMD(REPLY_BT_CONFIG); 83 IWL_CMD_ENTRY(REPLY_BT_CONFIG),
84 IWL_CMD(REPLY_STATISTICS_CMD); 84 IWL_CMD_ENTRY(REPLY_STATISTICS_CMD),
85 IWL_CMD(STATISTICS_NOTIFICATION); 85 IWL_CMD_ENTRY(STATISTICS_NOTIFICATION),
86 IWL_CMD(REPLY_CARD_STATE_CMD); 86 IWL_CMD_ENTRY(REPLY_CARD_STATE_CMD),
87 IWL_CMD(CARD_STATE_NOTIFICATION); 87 IWL_CMD_ENTRY(CARD_STATE_NOTIFICATION),
88 IWL_CMD(MISSED_BEACONS_NOTIFICATION); 88 IWL_CMD_ENTRY(MISSED_BEACONS_NOTIFICATION),
89 IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); 89 IWL_CMD_ENTRY(REPLY_CT_KILL_CONFIG_CMD),
90 IWL_CMD(SENSITIVITY_CMD); 90 IWL_CMD_ENTRY(SENSITIVITY_CMD),
91 IWL_CMD(REPLY_PHY_CALIBRATION_CMD); 91 IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD),
92 IWL_CMD(REPLY_RX_PHY_CMD); 92 IWL_CMD_ENTRY(REPLY_RX_PHY_CMD),
93 IWL_CMD(REPLY_RX_MPDU_CMD); 93 IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD),
94 IWL_CMD(REPLY_RX); 94 IWL_CMD_ENTRY(REPLY_RX),
95 IWL_CMD(REPLY_COMPRESSED_BA); 95 IWL_CMD_ENTRY(REPLY_COMPRESSED_BA),
96 IWL_CMD(CALIBRATION_CFG_CMD); 96 IWL_CMD_ENTRY(CALIBRATION_CFG_CMD),
97 IWL_CMD(CALIBRATION_RES_NOTIFICATION); 97 IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION),
98 IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); 98 IWL_CMD_ENTRY(CALIBRATION_COMPLETE_NOTIFICATION),
99 IWL_CMD(REPLY_TX_POWER_DBM_CMD); 99 IWL_CMD_ENTRY(REPLY_TX_POWER_DBM_CMD),
100 IWL_CMD(TEMPERATURE_NOTIFICATION); 100 IWL_CMD_ENTRY(TEMPERATURE_NOTIFICATION),
101 IWL_CMD(TX_ANT_CONFIGURATION_CMD); 101 IWL_CMD_ENTRY(TX_ANT_CONFIGURATION_CMD),
102 IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF); 102 IWL_CMD_ENTRY(REPLY_BT_COEX_PROFILE_NOTIF),
103 IWL_CMD(REPLY_BT_COEX_PRIO_TABLE); 103 IWL_CMD_ENTRY(REPLY_BT_COEX_PRIO_TABLE),
104 IWL_CMD(REPLY_BT_COEX_PROT_ENV); 104 IWL_CMD_ENTRY(REPLY_BT_COEX_PROT_ENV),
105 IWL_CMD(REPLY_WIPAN_PARAMS); 105 IWL_CMD_ENTRY(REPLY_WIPAN_PARAMS),
106 IWL_CMD(REPLY_WIPAN_RXON); 106 IWL_CMD_ENTRY(REPLY_WIPAN_RXON),
107 IWL_CMD(REPLY_WIPAN_RXON_TIMING); 107 IWL_CMD_ENTRY(REPLY_WIPAN_RXON_TIMING),
108 IWL_CMD(REPLY_WIPAN_RXON_ASSOC); 108 IWL_CMD_ENTRY(REPLY_WIPAN_RXON_ASSOC),
109 IWL_CMD(REPLY_WIPAN_QOS_PARAM); 109 IWL_CMD_ENTRY(REPLY_WIPAN_QOS_PARAM),
110 IWL_CMD(REPLY_WIPAN_WEPKEY); 110 IWL_CMD_ENTRY(REPLY_WIPAN_WEPKEY),
111 IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); 111 IWL_CMD_ENTRY(REPLY_WIPAN_P2P_CHANNEL_SWITCH),
112 IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); 112 IWL_CMD_ENTRY(REPLY_WIPAN_NOA_NOTIFICATION),
113 IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); 113 IWL_CMD_ENTRY(REPLY_WIPAN_DEACTIVATION_COMPLETE),
114 IWL_CMD(REPLY_WOWLAN_PATTERNS); 114 IWL_CMD_ENTRY(REPLY_WOWLAN_PATTERNS),
115 IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER); 115 IWL_CMD_ENTRY(REPLY_WOWLAN_WAKEUP_FILTER),
116 IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS); 116 IWL_CMD_ENTRY(REPLY_WOWLAN_TSC_RSC_PARAMS),
117 IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS); 117 IWL_CMD_ENTRY(REPLY_WOWLAN_TKIP_PARAMS),
118 IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL); 118 IWL_CMD_ENTRY(REPLY_WOWLAN_KEK_KCK_MATERIAL),
119 IWL_CMD(REPLY_WOWLAN_GET_STATUS); 119 IWL_CMD_ENTRY(REPLY_WOWLAN_GET_STATUS),
120 IWL_CMD(REPLY_D3_CONFIG); 120 IWL_CMD_ENTRY(REPLY_D3_CONFIG),
121 default: 121};
122 return "UNKNOWN"; 122#undef IWL_CMD_ENTRY
123
124 }
125}
126 123
127/****************************************************************************** 124/******************************************************************************
128 * 125 *
@@ -137,10 +134,9 @@ static int iwlagn_rx_reply_error(struct iwl_priv *priv,
137 struct iwl_rx_packet *pkt = rxb_addr(rxb); 134 struct iwl_rx_packet *pkt = rxb_addr(rxb);
138 struct iwl_error_resp *err_resp = (void *)pkt->data; 135 struct iwl_error_resp *err_resp = (void *)pkt->data;
139 136
140 IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " 137 IWL_ERR(priv, "Error Reply type 0x%08X cmd REPLY_ERROR (0x%02X) "
141 "seq 0x%04X ser 0x%08X\n", 138 "seq 0x%04X ser 0x%08X\n",
142 le32_to_cpu(err_resp->error_type), 139 le32_to_cpu(err_resp->error_type),
143 get_cmd_string(err_resp->cmd_id),
144 err_resp->cmd_id, 140 err_resp->cmd_id,
145 le16_to_cpu(err_resp->bad_cmd_seq_num), 141 le16_to_cpu(err_resp->bad_cmd_seq_num),
146 le32_to_cpu(err_resp->error_info)); 142 le32_to_cpu(err_resp->error_info));
@@ -216,8 +212,7 @@ static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
216 u32 __maybe_unused len = 212 u32 __maybe_unused len =
217 le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; 213 le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
218 IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " 214 IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
219 "notification for %s:\n", len, 215 "notification for PM_DEBUG_STATISTIC_NOTIFIC:\n", len);
220 get_cmd_string(pkt->hdr.cmd));
221 iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len); 216 iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->data, len);
222 return 0; 217 return 0;
223} 218}
@@ -246,69 +241,6 @@ static int iwlagn_rx_beacon_notif(struct iwl_priv *priv,
246 return 0; 241 return 0;
247} 242}
248 243
249/* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
250#define ACK_CNT_RATIO (50)
251#define BA_TIMEOUT_CNT (5)
252#define BA_TIMEOUT_MAX (16)
253
254/**
255 * iwl_good_ack_health - checks for ACK count ratios, BA timeout retries.
256 *
257 * When the ACK count ratio is low and aggregated BA timeout retries exceeding
258 * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
259 * operation state.
260 */
261static bool iwlagn_good_ack_health(struct iwl_priv *priv,
262 struct statistics_tx *cur)
263{
264 int actual_delta, expected_delta, ba_timeout_delta;
265 struct statistics_tx *old;
266
267 if (priv->agg_tids_count)
268 return true;
269
270 lockdep_assert_held(&priv->statistics.lock);
271
272 old = &priv->statistics.tx;
273
274 actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
275 le32_to_cpu(old->actual_ack_cnt);
276 expected_delta = le32_to_cpu(cur->expected_ack_cnt) -
277 le32_to_cpu(old->expected_ack_cnt);
278
279 /* Values should not be negative, but we do not trust the firmware */
280 if (actual_delta <= 0 || expected_delta <= 0)
281 return true;
282
283 ba_timeout_delta = le32_to_cpu(cur->agg.ba_timeout) -
284 le32_to_cpu(old->agg.ba_timeout);
285
286 if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO &&
287 ba_timeout_delta > BA_TIMEOUT_CNT) {
288 IWL_DEBUG_RADIO(priv,
289 "deltas: actual %d expected %d ba_timeout %d\n",
290 actual_delta, expected_delta, ba_timeout_delta);
291
292#ifdef CONFIG_IWLWIFI_DEBUGFS
293 /*
294 * This is ifdef'ed on DEBUGFS because otherwise the
295 * statistics aren't available. If DEBUGFS is set but
296 * DEBUG is not, these will just compile out.
297 */
298 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
299 priv->delta_stats.tx.rx_detected_cnt);
300 IWL_DEBUG_RADIO(priv,
301 "ack_or_ba_timeout_collision delta %d\n",
302 priv->delta_stats.tx.ack_or_ba_timeout_collision);
303#endif
304
305 if (ba_timeout_delta >= BA_TIMEOUT_MAX)
306 return false;
307 }
308
309 return true;
310}
311
312/** 244/**
313 * iwl_good_plcp_health - checks for plcp error. 245 * iwl_good_plcp_health - checks for plcp error.
314 * 246 *
@@ -347,6 +279,45 @@ static bool iwlagn_good_plcp_health(struct iwl_priv *priv,
347 return true; 279 return true;
348} 280}
349 281
282int iwl_force_rf_reset(struct iwl_priv *priv, bool external)
283{
284 struct iwl_rf_reset *rf_reset;
285
286 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
287 return -EAGAIN;
288
289 if (!iwl_is_any_associated(priv)) {
290 IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
291 return -ENOLINK;
292 }
293
294 rf_reset = &priv->rf_reset;
295 rf_reset->reset_request_count++;
296 if (!external && rf_reset->last_reset_jiffies &&
297 time_after(rf_reset->last_reset_jiffies +
298 IWL_DELAY_NEXT_FORCE_RF_RESET, jiffies)) {
299 IWL_DEBUG_INFO(priv, "RF reset rejected\n");
300 rf_reset->reset_reject_count++;
301 return -EAGAIN;
302 }
303 rf_reset->reset_success_count++;
304 rf_reset->last_reset_jiffies = jiffies;
305
306 /*
307 * There is no easy and better way to force reset the radio,
308 * the only known method is switching channel which will force to
309 * reset and tune the radio.
310 * Use internal short scan (single channel) operation to should
311 * achieve this objective.
312 * Driver should reset the radio when number of consecutive missed
313 * beacon, or any other uCode error condition detected.
314 */
315 IWL_DEBUG_INFO(priv, "perform radio reset.\n");
316 iwl_internal_short_hw_scan(priv);
317 return 0;
318}
319
320
350static void iwlagn_recover_from_statistics(struct iwl_priv *priv, 321static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
351 struct statistics_rx_phy *cur_ofdm, 322 struct statistics_rx_phy *cur_ofdm,
352 struct statistics_rx_ht_phy *cur_ofdm_ht, 323 struct statistics_rx_ht_phy *cur_ofdm_ht,
@@ -368,15 +339,9 @@ static void iwlagn_recover_from_statistics(struct iwl_priv *priv,
368 if (msecs < 99) 339 if (msecs < 99)
369 return; 340 return;
370 341
371 if (iwlagn_mod_params.ack_check && !iwlagn_good_ack_health(priv, tx)) {
372 IWL_ERR(priv, "low ack count detected, restart firmware\n");
373 if (!iwl_force_reset(priv, IWL_FW_RESET, false))
374 return;
375 }
376
377 if (iwlagn_mod_params.plcp_check && 342 if (iwlagn_mod_params.plcp_check &&
378 !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) 343 !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
379 iwl_force_reset(priv, IWL_RF_RESET, false); 344 iwl_force_rf_reset(priv, false);
380} 345}
381 346
382/* Calculate noise level, based on measurements during network silence just 347/* Calculate noise level, based on measurements during network silence just
@@ -589,8 +554,8 @@ static int iwlagn_rx_statistics(struct iwl_priv *priv,
589 iwlagn_rx_calc_noise(priv); 554 iwlagn_rx_calc_noise(priv);
590 queue_work(priv->workqueue, &priv->run_time_calib_work); 555 queue_work(priv->workqueue, &priv->run_time_calib_work);
591 } 556 }
592 if (cfg(priv)->lib->temperature && change) 557 if (priv->lib->temperature && change)
593 cfg(priv)->lib->temperature(priv); 558 priv->lib->temperature(priv);
594 559
595 spin_unlock(&priv->statistics.lock); 560 spin_unlock(&priv->statistics.lock);
596 561
@@ -1182,9 +1147,9 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
1182 err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); 1147 err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
1183 } else { 1148 } else {
1184 /* No handling needed */ 1149 /* No handling needed */
1185 IWL_DEBUG_RX(priv, 1150 IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n",
1186 "No handler needed for %s, 0x%02x\n", 1151 iwl_dvm_get_cmd_string(pkt->hdr.cmd),
1187 get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); 1152 pkt->hdr.cmd);
1188 } 1153 }
1189 } 1154 }
1190 return err; 1155 return err;