diff options
author | Stanislaw Gruszka <sgruszka@redhat.com> | 2011-03-04 11:51:49 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-03-04 14:06:50 -0500 |
commit | 466a19a003f3b45a755bc85f967c21da947f9a00 (patch) | |
tree | ca346e832982a54da9751b411322113c35e2d897 /drivers/net/wireless/iwlwifi/iwl-rx.c | |
parent | 9d468d2269b64222a706f52b965998ee64d0b4bf (diff) |
iwlwifi: move rx handlers code to iwl-rx.c
Put generic rx_handlers (except iwlagn_rx_reply_compressed_ba) to
iwl-rx.c . Make functions static and change prefix from iwlagn_ to
iwl_ . Beautify iwl_setup_rx_handlers and do some other minor coding
style changes.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 523 |
1 files changed, 498 insertions, 25 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 566e2d979ce3..8dc129499b90 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -38,7 +38,14 @@ | |||
38 | #include "iwl-io.h" | 38 | #include "iwl-io.h" |
39 | #include "iwl-helpers.h" | 39 | #include "iwl-helpers.h" |
40 | #include "iwl-agn-calib.h" | 40 | #include "iwl-agn-calib.h" |
41 | /************************** RX-FUNCTIONS ****************************/ | 41 | #include "iwl-agn.h" |
42 | |||
43 | /****************************************************************************** | ||
44 | * | ||
45 | * RX path functions | ||
46 | * | ||
47 | ******************************************************************************/ | ||
48 | |||
42 | /* | 49 | /* |
43 | * Rx theory of operation | 50 | * Rx theory of operation |
44 | * | 51 | * |
@@ -211,7 +218,104 @@ err_bd: | |||
211 | return -ENOMEM; | 218 | return -ENOMEM; |
212 | } | 219 | } |
213 | 220 | ||
214 | void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | 221 | /****************************************************************************** |
222 | * | ||
223 | * Generic RX handler implementations | ||
224 | * | ||
225 | ******************************************************************************/ | ||
226 | |||
227 | static void iwl_rx_reply_alive(struct iwl_priv *priv, | ||
228 | struct iwl_rx_mem_buffer *rxb) | ||
229 | { | ||
230 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
231 | struct iwl_alive_resp *palive; | ||
232 | struct delayed_work *pwork; | ||
233 | |||
234 | palive = &pkt->u.alive_frame; | ||
235 | |||
236 | IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision " | ||
237 | "0x%01X 0x%01X\n", | ||
238 | palive->is_valid, palive->ver_type, | ||
239 | palive->ver_subtype); | ||
240 | |||
241 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) { | ||
242 | IWL_DEBUG_INFO(priv, "Initialization Alive received.\n"); | ||
243 | memcpy(&priv->card_alive_init, | ||
244 | &pkt->u.alive_frame, | ||
245 | sizeof(struct iwl_init_alive_resp)); | ||
246 | pwork = &priv->init_alive_start; | ||
247 | } else { | ||
248 | IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); | ||
249 | memcpy(&priv->card_alive, &pkt->u.alive_frame, | ||
250 | sizeof(struct iwl_alive_resp)); | ||
251 | pwork = &priv->alive_start; | ||
252 | } | ||
253 | |||
254 | /* We delay the ALIVE response by 5ms to | ||
255 | * give the HW RF Kill time to activate... */ | ||
256 | if (palive->is_valid == UCODE_VALID_OK) | ||
257 | queue_delayed_work(priv->workqueue, pwork, | ||
258 | msecs_to_jiffies(5)); | ||
259 | else { | ||
260 | IWL_WARN(priv, "%s uCode did not respond OK.\n", | ||
261 | (palive->ver_subtype == INITIALIZE_SUBTYPE) ? | ||
262 | "init" : "runtime"); | ||
263 | /* | ||
264 | * If fail to load init uCode, | ||
265 | * let's try to load the init uCode again. | ||
266 | * We should not get into this situation, but if it | ||
267 | * does happen, we should not move on and loading "runtime" | ||
268 | * without proper calibrate the device. | ||
269 | */ | ||
270 | if (palive->ver_subtype == INITIALIZE_SUBTYPE) | ||
271 | priv->ucode_type = UCODE_NONE; | ||
272 | queue_work(priv->workqueue, &priv->restart); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static void iwl_rx_reply_error(struct iwl_priv *priv, | ||
277 | struct iwl_rx_mem_buffer *rxb) | ||
278 | { | ||
279 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
280 | |||
281 | IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " | ||
282 | "seq 0x%04X ser 0x%08X\n", | ||
283 | le32_to_cpu(pkt->u.err_resp.error_type), | ||
284 | get_cmd_string(pkt->u.err_resp.cmd_id), | ||
285 | pkt->u.err_resp.cmd_id, | ||
286 | le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), | ||
287 | le32_to_cpu(pkt->u.err_resp.error_info)); | ||
288 | } | ||
289 | |||
290 | static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) | ||
291 | { | ||
292 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
293 | struct iwl_csa_notification *csa = &(pkt->u.csa_notif); | ||
294 | /* | ||
295 | * MULTI-FIXME | ||
296 | * See iwl_mac_channel_switch. | ||
297 | */ | ||
298 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | ||
299 | struct iwl_rxon_cmd *rxon = (void *)&ctx->active; | ||
300 | |||
301 | if (priv->switch_rxon.switch_in_progress) { | ||
302 | if (!le32_to_cpu(csa->status) && | ||
303 | (csa->channel == priv->switch_rxon.channel)) { | ||
304 | rxon->channel = csa->channel; | ||
305 | ctx->staging.channel = csa->channel; | ||
306 | IWL_DEBUG_11H(priv, "CSA notif: channel %d\n", | ||
307 | le16_to_cpu(csa->channel)); | ||
308 | iwl_chswitch_done(priv, true); | ||
309 | } else { | ||
310 | IWL_ERR(priv, "CSA notif (fail) : channel %d\n", | ||
311 | le16_to_cpu(csa->channel)); | ||
312 | iwl_chswitch_done(priv, false); | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | |||
318 | static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | ||
215 | struct iwl_rx_mem_buffer *rxb) | 319 | struct iwl_rx_mem_buffer *rxb) |
216 | { | 320 | { |
217 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 321 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
@@ -227,6 +331,52 @@ void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, | |||
227 | priv->measurement_status |= MEASUREMENT_READY; | 331 | priv->measurement_status |= MEASUREMENT_READY; |
228 | } | 332 | } |
229 | 333 | ||
334 | static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, | ||
335 | struct iwl_rx_mem_buffer *rxb) | ||
336 | { | ||
337 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
338 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
339 | struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); | ||
340 | IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", | ||
341 | sleep->pm_sleep_mode, sleep->pm_wakeup_src); | ||
342 | #endif | ||
343 | } | ||
344 | |||
345 | static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, | ||
346 | struct iwl_rx_mem_buffer *rxb) | ||
347 | { | ||
348 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
349 | u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
350 | IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " | ||
351 | "notification for %s:\n", len, | ||
352 | get_cmd_string(pkt->hdr.cmd)); | ||
353 | iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); | ||
354 | } | ||
355 | |||
356 | static void iwl_rx_beacon_notif(struct iwl_priv *priv, | ||
357 | struct iwl_rx_mem_buffer *rxb) | ||
358 | { | ||
359 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
360 | struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw; | ||
361 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
362 | u16 status = le16_to_cpu(beacon->beacon_notify_hdr.status.status); | ||
363 | u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); | ||
364 | |||
365 | IWL_DEBUG_RX(priv, "beacon status %#x, retries:%d ibssmgr:%d " | ||
366 | "tsf:0x%.8x%.8x rate:%d\n", | ||
367 | status & TX_STATUS_MSK, | ||
368 | beacon->beacon_notify_hdr.failure_frame, | ||
369 | le32_to_cpu(beacon->ibss_mgr_status), | ||
370 | le32_to_cpu(beacon->high_tsf), | ||
371 | le32_to_cpu(beacon->low_tsf), rate); | ||
372 | #endif | ||
373 | |||
374 | priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); | ||
375 | |||
376 | if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) | ||
377 | queue_work(priv->workqueue, &priv->beacon_update); | ||
378 | } | ||
379 | |||
230 | /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ | 380 | /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ |
231 | #define ACK_CNT_RATIO (50) | 381 | #define ACK_CNT_RATIO (50) |
232 | #define BA_TIMEOUT_CNT (5) | 382 | #define BA_TIMEOUT_CNT (5) |
@@ -298,7 +448,8 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt | |||
298 | * When the plcp error is exceeding the thresholds, reset the radio | 448 | * When the plcp error is exceeding the thresholds, reset the radio |
299 | * to improve the throughput. | 449 | * to improve the throughput. |
300 | */ | 450 | */ |
301 | static bool iwl_good_plcp_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt) | 451 | static bool iwl_good_plcp_health(struct iwl_priv *priv, |
452 | struct iwl_rx_packet *pkt) | ||
302 | { | 453 | { |
303 | bool rc = true; | 454 | bool rc = true; |
304 | int combined_plcp_delta; | 455 | int combined_plcp_delta; |
@@ -378,7 +529,8 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv, struct iwl_rx_packet *pk | |||
378 | return rc; | 529 | return rc; |
379 | } | 530 | } |
380 | 531 | ||
381 | static void iwl_recover_from_statistics(struct iwl_priv *priv, struct iwl_rx_packet *pkt) | 532 | static void iwl_recover_from_statistics(struct iwl_priv *priv, |
533 | struct iwl_rx_packet *pkt) | ||
382 | { | 534 | { |
383 | const struct iwl_mod_params *mod_params = priv->cfg->mod_params; | 535 | const struct iwl_mod_params *mod_params = priv->cfg->mod_params; |
384 | 536 | ||
@@ -442,7 +594,6 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) | |||
442 | last_rx_noise); | 594 | last_rx_noise); |
443 | } | 595 | } |
444 | 596 | ||
445 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
446 | /* | 597 | /* |
447 | * based on the assumption of all statistics counter are in DWORD | 598 | * based on the assumption of all statistics counter are in DWORD |
448 | * FIXME: This function is for debugging, do not deal with | 599 | * FIXME: This function is for debugging, do not deal with |
@@ -451,6 +602,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv) | |||
451 | static void iwl_accumulative_statistics(struct iwl_priv *priv, | 602 | static void iwl_accumulative_statistics(struct iwl_priv *priv, |
452 | __le32 *stats) | 603 | __le32 *stats) |
453 | { | 604 | { |
605 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
454 | int i, size; | 606 | int i, size; |
455 | __le32 *prev_stats; | 607 | __le32 *prev_stats; |
456 | u32 *accum_stats; | 608 | u32 *accum_stats; |
@@ -498,14 +650,13 @@ static void iwl_accumulative_statistics(struct iwl_priv *priv, | |||
498 | accum_tx->tx_power.ant_a = tx->tx_power.ant_a; | 650 | accum_tx->tx_power.ant_a = tx->tx_power.ant_a; |
499 | accum_tx->tx_power.ant_b = tx->tx_power.ant_b; | 651 | accum_tx->tx_power.ant_b = tx->tx_power.ant_b; |
500 | accum_tx->tx_power.ant_c = tx->tx_power.ant_c; | 652 | accum_tx->tx_power.ant_c = tx->tx_power.ant_c; |
501 | } | ||
502 | #endif | 653 | #endif |
654 | } | ||
503 | 655 | ||
504 | #define REG_RECALIB_PERIOD (60) | 656 | static void iwl_rx_statistics(struct iwl_priv *priv, |
505 | |||
506 | void iwl_rx_statistics(struct iwl_priv *priv, | ||
507 | struct iwl_rx_mem_buffer *rxb) | 657 | struct iwl_rx_mem_buffer *rxb) |
508 | { | 658 | { |
659 | const int reg_recalib_period = 60; | ||
509 | int change; | 660 | int change; |
510 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 661 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
511 | 662 | ||
@@ -522,10 +673,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
522 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != | 673 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != |
523 | (pkt->u.stats_bt.flag & | 674 | (pkt->u.stats_bt.flag & |
524 | STATISTICS_REPLY_FLG_HT40_MODE_MSK))); | 675 | STATISTICS_REPLY_FLG_HT40_MODE_MSK))); |
525 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
526 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); | ||
527 | #endif | ||
528 | 676 | ||
677 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt); | ||
529 | } else { | 678 | } else { |
530 | IWL_DEBUG_RX(priv, | 679 | IWL_DEBUG_RX(priv, |
531 | "Statistics notification received (%d vs %d).\n", | 680 | "Statistics notification received (%d vs %d).\n", |
@@ -539,10 +688,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
539 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != | 688 | STATISTICS_REPLY_FLG_HT40_MODE_MSK) != |
540 | (pkt->u.stats.flag & | 689 | (pkt->u.stats.flag & |
541 | STATISTICS_REPLY_FLG_HT40_MODE_MSK))); | 690 | STATISTICS_REPLY_FLG_HT40_MODE_MSK))); |
542 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
543 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); | ||
544 | #endif | ||
545 | 691 | ||
692 | iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats); | ||
546 | } | 693 | } |
547 | 694 | ||
548 | iwl_recover_from_statistics(priv, pkt); | 695 | iwl_recover_from_statistics(priv, pkt); |
@@ -557,11 +704,11 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
557 | set_bit(STATUS_STATISTICS, &priv->status); | 704 | set_bit(STATUS_STATISTICS, &priv->status); |
558 | 705 | ||
559 | /* Reschedule the statistics timer to occur in | 706 | /* Reschedule the statistics timer to occur in |
560 | * REG_RECALIB_PERIOD seconds to ensure we get a | 707 | * reg_recalib_period seconds to ensure we get a |
561 | * thermal update even if the uCode doesn't give | 708 | * thermal update even if the uCode doesn't give |
562 | * us one */ | 709 | * us one */ |
563 | mod_timer(&priv->statistics_periodic, jiffies + | 710 | mod_timer(&priv->statistics_periodic, jiffies + |
564 | msecs_to_jiffies(REG_RECALIB_PERIOD * 1000)); | 711 | msecs_to_jiffies(reg_recalib_period * 1000)); |
565 | 712 | ||
566 | if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && | 713 | if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && |
567 | (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { | 714 | (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { |
@@ -572,8 +719,8 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
572 | priv->cfg->ops->lib->temp_ops.temperature(priv); | 719 | priv->cfg->ops->lib->temp_ops.temperature(priv); |
573 | } | 720 | } |
574 | 721 | ||
575 | void iwl_reply_statistics(struct iwl_priv *priv, | 722 | static void iwl_rx_reply_statistics(struct iwl_priv *priv, |
576 | struct iwl_rx_mem_buffer *rxb) | 723 | struct iwl_rx_mem_buffer *rxb) |
577 | { | 724 | { |
578 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 725 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
579 | 726 | ||
@@ -597,8 +744,61 @@ void iwl_reply_statistics(struct iwl_priv *priv, | |||
597 | iwl_rx_statistics(priv, rxb); | 744 | iwl_rx_statistics(priv, rxb); |
598 | } | 745 | } |
599 | 746 | ||
600 | void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | 747 | /* Handle notification from uCode that card's power state is changing |
601 | struct iwl_rx_mem_buffer *rxb) | 748 | * due to software, hardware, or critical temperature RFKILL */ |
749 | static void iwl_rx_card_state_notif(struct iwl_priv *priv, | ||
750 | struct iwl_rx_mem_buffer *rxb) | ||
751 | { | ||
752 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
753 | u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); | ||
754 | unsigned long status = priv->status; | ||
755 | |||
756 | IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", | ||
757 | (flags & HW_CARD_DISABLED) ? "Kill" : "On", | ||
758 | (flags & SW_CARD_DISABLED) ? "Kill" : "On", | ||
759 | (flags & CT_CARD_DISABLED) ? | ||
760 | "Reached" : "Not reached"); | ||
761 | |||
762 | if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | | ||
763 | CT_CARD_DISABLED)) { | ||
764 | |||
765 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | ||
766 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | ||
767 | |||
768 | iwl_write_direct32(priv, HBUS_TARG_MBX_C, | ||
769 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); | ||
770 | |||
771 | if (!(flags & RXON_CARD_DISABLED)) { | ||
772 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, | ||
773 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | ||
774 | iwl_write_direct32(priv, HBUS_TARG_MBX_C, | ||
775 | HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); | ||
776 | } | ||
777 | if (flags & CT_CARD_DISABLED) | ||
778 | iwl_tt_enter_ct_kill(priv); | ||
779 | } | ||
780 | if (!(flags & CT_CARD_DISABLED)) | ||
781 | iwl_tt_exit_ct_kill(priv); | ||
782 | |||
783 | if (flags & HW_CARD_DISABLED) | ||
784 | set_bit(STATUS_RF_KILL_HW, &priv->status); | ||
785 | else | ||
786 | clear_bit(STATUS_RF_KILL_HW, &priv->status); | ||
787 | |||
788 | |||
789 | if (!(flags & RXON_CARD_DISABLED)) | ||
790 | iwl_scan_cancel(priv); | ||
791 | |||
792 | if ((test_bit(STATUS_RF_KILL_HW, &status) != | ||
793 | test_bit(STATUS_RF_KILL_HW, &priv->status))) | ||
794 | wiphy_rfkill_set_hw_state(priv->hw->wiphy, | ||
795 | test_bit(STATUS_RF_KILL_HW, &priv->status)); | ||
796 | else | ||
797 | wake_up_interruptible(&priv->wait_command_queue); | ||
798 | } | ||
799 | |||
800 | static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | ||
801 | struct iwl_rx_mem_buffer *rxb) | ||
602 | 802 | ||
603 | { | 803 | { |
604 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 804 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
@@ -618,13 +818,25 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, | |||
618 | } | 818 | } |
619 | } | 819 | } |
620 | 820 | ||
821 | /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). | ||
822 | * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ | ||
823 | static void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | ||
824 | struct iwl_rx_mem_buffer *rxb) | ||
825 | { | ||
826 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
827 | |||
828 | priv->_agn.last_phy_res_valid = true; | ||
829 | memcpy(&priv->_agn.last_phy_res, pkt->u.raw, | ||
830 | sizeof(struct iwl_rx_phy_res)); | ||
831 | } | ||
832 | |||
621 | /* | 833 | /* |
622 | * returns non-zero if packet should be dropped | 834 | * returns non-zero if packet should be dropped |
623 | */ | 835 | */ |
624 | int iwl_set_decrypted_flag(struct iwl_priv *priv, | 836 | static int iwl_set_decrypted_flag(struct iwl_priv *priv, |
625 | struct ieee80211_hdr *hdr, | 837 | struct ieee80211_hdr *hdr, |
626 | u32 decrypt_res, | 838 | u32 decrypt_res, |
627 | struct ieee80211_rx_status *stats) | 839 | struct ieee80211_rx_status *stats) |
628 | { | 840 | { |
629 | u16 fc = le16_to_cpu(hdr->frame_control); | 841 | u16 fc = le16_to_cpu(hdr->frame_control); |
630 | 842 | ||
@@ -669,3 +881,264 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, | |||
669 | } | 881 | } |
670 | return 0; | 882 | return 0; |
671 | } | 883 | } |
884 | |||
885 | static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | ||
886 | struct ieee80211_hdr *hdr, | ||
887 | u16 len, | ||
888 | u32 ampdu_status, | ||
889 | struct iwl_rx_mem_buffer *rxb, | ||
890 | struct ieee80211_rx_status *stats) | ||
891 | { | ||
892 | struct sk_buff *skb; | ||
893 | __le16 fc = hdr->frame_control; | ||
894 | |||
895 | /* We only process data packets if the interface is open */ | ||
896 | if (unlikely(!priv->is_open)) { | ||
897 | IWL_DEBUG_DROP_LIMIT(priv, | ||
898 | "Dropping packet while interface is not open.\n"); | ||
899 | return; | ||
900 | } | ||
901 | |||
902 | /* In case of HW accelerated crypto and bad decryption, drop */ | ||
903 | if (!priv->cfg->mod_params->sw_crypto && | ||
904 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | ||
905 | return; | ||
906 | |||
907 | skb = dev_alloc_skb(128); | ||
908 | if (!skb) { | ||
909 | IWL_ERR(priv, "dev_alloc_skb failed\n"); | ||
910 | return; | ||
911 | } | ||
912 | |||
913 | skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); | ||
914 | |||
915 | iwl_update_stats(priv, false, fc, len); | ||
916 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||
917 | |||
918 | ieee80211_rx(priv->hw, skb); | ||
919 | priv->alloc_rxb_page--; | ||
920 | rxb->page = NULL; | ||
921 | } | ||
922 | |||
923 | static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | ||
924 | { | ||
925 | u32 decrypt_out = 0; | ||
926 | |||
927 | if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == | ||
928 | RX_RES_STATUS_STATION_FOUND) | ||
929 | decrypt_out |= (RX_RES_STATUS_STATION_FOUND | | ||
930 | RX_RES_STATUS_NO_STATION_INFO_MISMATCH); | ||
931 | |||
932 | decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); | ||
933 | |||
934 | /* packet was not encrypted */ | ||
935 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
936 | RX_RES_STATUS_SEC_TYPE_NONE) | ||
937 | return decrypt_out; | ||
938 | |||
939 | /* packet was encrypted with unknown alg */ | ||
940 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
941 | RX_RES_STATUS_SEC_TYPE_ERR) | ||
942 | return decrypt_out; | ||
943 | |||
944 | /* decryption was not done in HW */ | ||
945 | if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != | ||
946 | RX_MPDU_RES_STATUS_DEC_DONE_MSK) | ||
947 | return decrypt_out; | ||
948 | |||
949 | switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
950 | |||
951 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
952 | /* alg is CCM: check MIC only */ | ||
953 | if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) | ||
954 | /* Bad MIC */ | ||
955 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
956 | else | ||
957 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
958 | |||
959 | break; | ||
960 | |||
961 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
962 | if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { | ||
963 | /* Bad TTAK */ | ||
964 | decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; | ||
965 | break; | ||
966 | } | ||
967 | /* fall through if TTAK OK */ | ||
968 | default: | ||
969 | if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) | ||
970 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
971 | else | ||
972 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
973 | break; | ||
974 | } | ||
975 | |||
976 | IWL_DEBUG_RX(priv, "decrypt_in:0x%x decrypt_out = 0x%x\n", | ||
977 | decrypt_in, decrypt_out); | ||
978 | |||
979 | return decrypt_out; | ||
980 | } | ||
981 | |||
982 | /* Called for REPLY_RX (legacy ABG frames), or | ||
983 | * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ | ||
984 | static void iwl_rx_reply_rx(struct iwl_priv *priv, | ||
985 | struct iwl_rx_mem_buffer *rxb) | ||
986 | { | ||
987 | struct ieee80211_hdr *header; | ||
988 | struct ieee80211_rx_status rx_status; | ||
989 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
990 | struct iwl_rx_phy_res *phy_res; | ||
991 | __le32 rx_pkt_status; | ||
992 | struct iwl_rx_mpdu_res_start *amsdu; | ||
993 | u32 len; | ||
994 | u32 ampdu_status; | ||
995 | u32 rate_n_flags; | ||
996 | |||
997 | /** | ||
998 | * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. | ||
999 | * REPLY_RX: physical layer info is in this buffer | ||
1000 | * REPLY_RX_MPDU_CMD: physical layer info was sent in separate | ||
1001 | * command and cached in priv->last_phy_res | ||
1002 | * | ||
1003 | * Here we set up local variables depending on which command is | ||
1004 | * received. | ||
1005 | */ | ||
1006 | if (pkt->hdr.cmd == REPLY_RX) { | ||
1007 | phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; | ||
1008 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) | ||
1009 | + phy_res->cfg_phy_cnt); | ||
1010 | |||
1011 | len = le16_to_cpu(phy_res->byte_count); | ||
1012 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + | ||
1013 | phy_res->cfg_phy_cnt + len); | ||
1014 | ampdu_status = le32_to_cpu(rx_pkt_status); | ||
1015 | } else { | ||
1016 | if (!priv->_agn.last_phy_res_valid) { | ||
1017 | IWL_ERR(priv, "MPDU frame without cached PHY data\n"); | ||
1018 | return; | ||
1019 | } | ||
1020 | phy_res = &priv->_agn.last_phy_res; | ||
1021 | amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw; | ||
1022 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); | ||
1023 | len = le16_to_cpu(amsdu->byte_count); | ||
1024 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); | ||
1025 | ampdu_status = iwl_translate_rx_status(priv, | ||
1026 | le32_to_cpu(rx_pkt_status)); | ||
1027 | } | ||
1028 | |||
1029 | if ((unlikely(phy_res->cfg_phy_cnt > 20))) { | ||
1030 | IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", | ||
1031 | phy_res->cfg_phy_cnt); | ||
1032 | return; | ||
1033 | } | ||
1034 | |||
1035 | if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
1036 | !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
1037 | IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", | ||
1038 | le32_to_cpu(rx_pkt_status)); | ||
1039 | return; | ||
1040 | } | ||
1041 | |||
1042 | /* This will be used in several places later */ | ||
1043 | rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); | ||
1044 | |||
1045 | /* rx_status carries information about the packet to mac80211 */ | ||
1046 | rx_status.mactime = le64_to_cpu(phy_res->timestamp); | ||
1047 | rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
1048 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
1049 | rx_status.freq = | ||
1050 | ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel), | ||
1051 | rx_status.band); | ||
1052 | rx_status.rate_idx = | ||
1053 | iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); | ||
1054 | rx_status.flag = 0; | ||
1055 | |||
1056 | /* TSF isn't reliable. In order to allow smooth user experience, | ||
1057 | * this W/A doesn't propagate it to the mac80211 */ | ||
1058 | /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/ | ||
1059 | |||
1060 | priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); | ||
1061 | |||
1062 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | ||
1063 | rx_status.signal = priv->cfg->ops->utils->calc_rssi(priv, phy_res); | ||
1064 | |||
1065 | iwl_dbg_log_rx_data_frame(priv, len, header); | ||
1066 | IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n", | ||
1067 | rx_status.signal, (unsigned long long)rx_status.mactime); | ||
1068 | |||
1069 | /* | ||
1070 | * "antenna number" | ||
1071 | * | ||
1072 | * It seems that the antenna field in the phy flags value | ||
1073 | * is actually a bit field. This is undefined by radiotap, | ||
1074 | * it wants an actual antenna number but I always get "7" | ||
1075 | * for most legacy frames I receive indicating that the | ||
1076 | * same frame was received on all three RX chains. | ||
1077 | * | ||
1078 | * I think this field should be removed in favor of a | ||
1079 | * new 802.11n radiotap field "RX chains" that is defined | ||
1080 | * as a bitmask. | ||
1081 | */ | ||
1082 | rx_status.antenna = | ||
1083 | (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) | ||
1084 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
1085 | |||
1086 | /* set the preamble flag if appropriate */ | ||
1087 | if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
1088 | rx_status.flag |= RX_FLAG_SHORTPRE; | ||
1089 | |||
1090 | /* Set up the HT phy flags */ | ||
1091 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
1092 | rx_status.flag |= RX_FLAG_HT; | ||
1093 | if (rate_n_flags & RATE_MCS_HT40_MSK) | ||
1094 | rx_status.flag |= RX_FLAG_40MHZ; | ||
1095 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
1096 | rx_status.flag |= RX_FLAG_SHORT_GI; | ||
1097 | |||
1098 | iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, | ||
1099 | rxb, &rx_status); | ||
1100 | } | ||
1101 | |||
1102 | /** | ||
1103 | * iwl_setup_rx_handlers - Initialize Rx handler callbacks | ||
1104 | * | ||
1105 | * Setup the RX handlers for each of the reply types sent from the uCode | ||
1106 | * to the host. | ||
1107 | */ | ||
1108 | void iwl_setup_rx_handlers(struct iwl_priv *priv) | ||
1109 | { | ||
1110 | void (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | ||
1111 | |||
1112 | handlers = priv->rx_handlers; | ||
1113 | |||
1114 | handlers[REPLY_ALIVE] = iwl_rx_reply_alive; | ||
1115 | handlers[REPLY_ERROR] = iwl_rx_reply_error; | ||
1116 | handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; | ||
1117 | handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; | ||
1118 | handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; | ||
1119 | handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; | ||
1120 | handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; | ||
1121 | |||
1122 | /* | ||
1123 | * The same handler is used for both the REPLY to a discrete | ||
1124 | * statistics request from the host as well as for the periodic | ||
1125 | * statistics notifications (after received beacons) from the uCode. | ||
1126 | */ | ||
1127 | handlers[REPLY_STATISTICS_CMD] = iwl_rx_reply_statistics; | ||
1128 | handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; | ||
1129 | |||
1130 | iwl_setup_rx_scan_handlers(priv); | ||
1131 | |||
1132 | handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; | ||
1133 | handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; | ||
1134 | |||
1135 | /* Rx handlers */ | ||
1136 | handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; | ||
1137 | handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; | ||
1138 | |||
1139 | /* block ack */ | ||
1140 | handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; | ||
1141 | |||
1142 | /* Set up hardware specific Rx handlers */ | ||
1143 | priv->cfg->ops->lib->rx_handler_setup(priv); | ||
1144 | } | ||