diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-02-12 12:51:08 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-12 12:51:08 -0500 |
commit | 5171f7a0b79dfbc61a6e12f20f6eef6d7dd5b2a8 (patch) | |
tree | 50e48f8b65bc10fd7b8959735cb599884a161d1b | |
parent | c88d0dc1cc0182358ce1ae6f457dace34539eb12 (diff) | |
parent | 36eed56a8f7e1bd7fb5014ea0e702708e1702f30 (diff) |
Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Conflicts:
drivers/net/wireless/iwlwifi/mvm/mac80211.c
25 files changed, 572 insertions, 303 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 8bce4b0148e0..02c9ebb3b340 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h | |||
@@ -3897,6 +3897,24 @@ struct iwlagn_wowlan_kek_kck_material_cmd { | |||
3897 | __le64 replay_ctr; | 3897 | __le64 replay_ctr; |
3898 | } __packed; | 3898 | } __packed; |
3899 | 3899 | ||
3900 | #define RF_KILL_INDICATOR_FOR_WOWLAN 0x87 | ||
3901 | |||
3902 | /* | ||
3903 | * REPLY_WOWLAN_GET_STATUS = 0xe5 | ||
3904 | */ | ||
3905 | struct iwlagn_wowlan_status { | ||
3906 | __le64 replay_ctr; | ||
3907 | __le32 rekey_status; | ||
3908 | __le32 wakeup_reason; | ||
3909 | u8 pattern_number; | ||
3910 | u8 reserved1; | ||
3911 | __le16 qos_seq_ctr[8]; | ||
3912 | __le16 non_qos_seq_ctr; | ||
3913 | __le16 reserved2; | ||
3914 | union iwlagn_all_tsc_rsc tsc_rsc; | ||
3915 | __le16 reserved3; | ||
3916 | } __packed; | ||
3917 | |||
3900 | /* | 3918 | /* |
3901 | * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) | 3919 | * REPLY_WIPAN_PARAMS = 0xb2 (Commands and Notification) |
3902 | */ | 3920 | */ |
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 0fccf725a2e6..323e4a33fcac 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c | |||
@@ -441,52 +441,154 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, | |||
441 | return ret; | 441 | return ret; |
442 | } | 442 | } |
443 | 443 | ||
444 | struct iwl_resume_data { | ||
445 | struct iwl_priv *priv; | ||
446 | struct iwlagn_wowlan_status *cmd; | ||
447 | bool valid; | ||
448 | }; | ||
449 | |||
450 | static bool iwl_resume_status_fn(struct iwl_notif_wait_data *notif_wait, | ||
451 | struct iwl_rx_packet *pkt, void *data) | ||
452 | { | ||
453 | struct iwl_resume_data *resume_data = data; | ||
454 | struct iwl_priv *priv = resume_data->priv; | ||
455 | u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
456 | |||
457 | if (len - 4 != sizeof(*resume_data->cmd)) { | ||
458 | IWL_ERR(priv, "rx wrong size data\n"); | ||
459 | return true; | ||
460 | } | ||
461 | memcpy(resume_data->cmd, pkt->data, sizeof(*resume_data->cmd)); | ||
462 | resume_data->valid = true; | ||
463 | |||
464 | return true; | ||
465 | } | ||
466 | |||
444 | static int iwlagn_mac_resume(struct ieee80211_hw *hw) | 467 | static int iwlagn_mac_resume(struct ieee80211_hw *hw) |
445 | { | 468 | { |
446 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); | 469 | struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); |
447 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; | 470 | struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; |
448 | struct ieee80211_vif *vif; | 471 | struct ieee80211_vif *vif; |
449 | unsigned long flags; | 472 | u32 base; |
450 | u32 base, status = 0xffffffff; | 473 | int ret; |
451 | int ret = -EIO; | 474 | enum iwl_d3_status d3_status; |
475 | struct error_table_start { | ||
476 | /* cf. struct iwl_error_event_table */ | ||
477 | u32 valid; | ||
478 | u32 error_id; | ||
479 | } err_info; | ||
480 | struct iwl_notification_wait status_wait; | ||
481 | static const u8 status_cmd[] = { | ||
482 | REPLY_WOWLAN_GET_STATUS, | ||
483 | }; | ||
484 | struct iwlagn_wowlan_status status_data = {}; | ||
485 | struct iwl_resume_data resume_data = { | ||
486 | .priv = priv, | ||
487 | .cmd = &status_data, | ||
488 | .valid = false, | ||
489 | }; | ||
490 | struct cfg80211_wowlan_wakeup wakeup = { | ||
491 | .pattern_idx = -1, | ||
492 | }; | ||
493 | #ifdef CONFIG_IWLWIFI_DEBUGFS | ||
494 | const struct fw_img *img; | ||
495 | #endif | ||
452 | 496 | ||
453 | IWL_DEBUG_MAC80211(priv, "enter\n"); | 497 | IWL_DEBUG_MAC80211(priv, "enter\n"); |
454 | mutex_lock(&priv->mutex); | 498 | mutex_lock(&priv->mutex); |
455 | 499 | ||
456 | iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, | 500 | /* we'll clear ctx->vif during iwlagn_prepare_restart() */ |
457 | CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); | 501 | vif = ctx->vif; |
502 | |||
503 | ret = iwl_trans_d3_resume(priv->trans, &d3_status); | ||
504 | if (ret) | ||
505 | goto out_unlock; | ||
506 | |||
507 | if (d3_status != IWL_D3_STATUS_ALIVE) { | ||
508 | IWL_INFO(priv, "Device was reset during suspend\n"); | ||
509 | goto out_unlock; | ||
510 | } | ||
458 | 511 | ||
459 | base = priv->device_pointers.error_event_table; | 512 | base = priv->device_pointers.error_event_table; |
460 | if (iwlagn_hw_valid_rtc_data_addr(base)) { | 513 | if (!iwlagn_hw_valid_rtc_data_addr(base)) { |
461 | if (iwl_trans_grab_nic_access(priv->trans, true, &flags)) { | 514 | IWL_WARN(priv, "Invalid error table during resume!\n"); |
462 | iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, base); | 515 | goto out_unlock; |
463 | status = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); | 516 | } |
464 | iwl_trans_release_nic_access(priv->trans, &flags); | 517 | |
465 | ret = 0; | 518 | iwl_trans_read_mem_bytes(priv->trans, base, |
519 | &err_info, sizeof(err_info)); | ||
520 | |||
521 | if (err_info.valid) { | ||
522 | IWL_INFO(priv, "error table is valid (%d, 0x%x)\n", | ||
523 | err_info.valid, err_info.error_id); | ||
524 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||
525 | wakeup.rfkill_release = true; | ||
526 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||
527 | GFP_KERNEL); | ||
466 | } | 528 | } |
529 | goto out_unlock; | ||
530 | } | ||
467 | 531 | ||
468 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 532 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
469 | if (ret == 0) { | 533 | img = &priv->fw->img[IWL_UCODE_WOWLAN]; |
470 | const struct fw_img *img; | 534 | if (!priv->wowlan_sram) |
471 | 535 | priv->wowlan_sram = | |
472 | img = &(priv->fw->img[IWL_UCODE_WOWLAN]); | 536 | kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len, |
473 | if (!priv->wowlan_sram) { | 537 | GFP_KERNEL); |
474 | priv->wowlan_sram = | 538 | |
475 | kzalloc(img->sec[IWL_UCODE_SECTION_DATA].len, | 539 | if (priv->wowlan_sram) |
476 | GFP_KERNEL); | 540 | iwl_trans_read_mem(priv->trans, 0x800000, |
477 | } | 541 | priv->wowlan_sram, |
542 | img->sec[IWL_UCODE_SECTION_DATA].len / 4); | ||
543 | #endif | ||
478 | 544 | ||
479 | if (priv->wowlan_sram) | 545 | /* |
480 | iwl_trans_read_mem( | 546 | * This is very strange. The GET_STATUS command is sent but the device |
481 | priv->trans, 0x800000, | 547 | * doesn't reply properly, it seems it doesn't close the RBD so one is |
482 | priv->wowlan_sram, | 548 | * always left open ... As a result, we need to send another command |
483 | img->sec[IWL_UCODE_SECTION_DATA].len / 4); | 549 | * and have to reset the driver afterwards. As we need to switch to |
550 | * runtime firmware again that'll happen. | ||
551 | */ | ||
552 | |||
553 | iwl_init_notification_wait(&priv->notif_wait, &status_wait, status_cmd, | ||
554 | ARRAY_SIZE(status_cmd), iwl_resume_status_fn, | ||
555 | &resume_data); | ||
556 | |||
557 | iwl_dvm_send_cmd_pdu(priv, REPLY_WOWLAN_GET_STATUS, CMD_ASYNC, 0, NULL); | ||
558 | iwl_dvm_send_cmd_pdu(priv, REPLY_ECHO, CMD_ASYNC, 0, NULL); | ||
559 | /* an RBD is left open in the firmware now! */ | ||
560 | |||
561 | ret = iwl_wait_notification(&priv->notif_wait, &status_wait, HZ/5); | ||
562 | if (ret) | ||
563 | goto out_unlock; | ||
564 | |||
565 | if (resume_data.valid && priv->contexts[IWL_RXON_CTX_BSS].vif) { | ||
566 | u32 reasons = le32_to_cpu(status_data.wakeup_reason); | ||
567 | struct cfg80211_wowlan_wakeup *wakeup_report; | ||
568 | |||
569 | IWL_INFO(priv, "WoWLAN wakeup reason(s): 0x%.8x\n", reasons); | ||
570 | |||
571 | if (reasons) { | ||
572 | if (reasons & IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET) | ||
573 | wakeup.magic_pkt = true; | ||
574 | if (reasons & IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH) | ||
575 | wakeup.pattern_idx = status_data.pattern_number; | ||
576 | if (reasons & (IWLAGN_WOWLAN_WAKEUP_BEACON_MISS | | ||
577 | IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE)) | ||
578 | wakeup.disconnect = true; | ||
579 | if (reasons & IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL) | ||
580 | wakeup.gtk_rekey_failure = true; | ||
581 | if (reasons & IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ) | ||
582 | wakeup.eap_identity_req = true; | ||
583 | if (reasons & IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE) | ||
584 | wakeup.four_way_handshake = true; | ||
585 | wakeup_report = &wakeup; | ||
586 | } else { | ||
587 | wakeup_report = NULL; | ||
484 | } | 588 | } |
485 | #endif | ||
486 | } | ||
487 | 589 | ||
488 | /* we'll clear ctx->vif during iwlagn_prepare_restart() */ | 590 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); |
489 | vif = ctx->vif; | 591 | } |
490 | 592 | ||
491 | priv->wowlan = false; | 593 | priv->wowlan = false; |
492 | 594 | ||
@@ -496,6 +598,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) | |||
496 | iwl_connection_init_rx_config(priv, ctx); | 598 | iwl_connection_init_rx_config(priv, ctx); |
497 | iwlagn_set_rxon_chain(priv, ctx); | 599 | iwlagn_set_rxon_chain(priv, ctx); |
498 | 600 | ||
601 | out_unlock: | ||
499 | mutex_unlock(&priv->mutex); | 602 | mutex_unlock(&priv->mutex); |
500 | IWL_DEBUG_MAC80211(priv, "leave\n"); | 603 | IWL_DEBUG_MAC80211(priv, "leave\n"); |
501 | 604 | ||
diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index e8d5b90abf5c..a4eed2055fdb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c | |||
@@ -790,7 +790,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
790 | 790 | ||
791 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 791 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
792 | 792 | ||
793 | ieee80211_rx(priv->hw, skb); | 793 | ieee80211_rx_ni(priv->hw, skb); |
794 | } | 794 | } |
795 | 795 | ||
796 | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | 796 | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) |
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 9fabd26997ca..23be948cf162 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c | |||
@@ -1545,10 +1545,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, | |||
1545 | bss_conf->bssid); | 1545 | bss_conf->bssid); |
1546 | } | 1546 | } |
1547 | 1547 | ||
1548 | if (changes & BSS_CHANGED_BEACON && vif->type == NL80211_IFTYPE_ADHOC && | 1548 | if (changes & BSS_CHANGED_BEACON && priv->beacon_ctx == ctx) { |
1549 | priv->beacon_ctx) { | ||
1550 | if (iwlagn_update_beacon(priv, vif)) | 1549 | if (iwlagn_update_beacon(priv, vif)) |
1551 | IWL_ERR(priv, "Error sending IBSS beacon\n"); | 1550 | IWL_ERR(priv, "Error updating beacon\n"); |
1552 | } | 1551 | } |
1553 | 1552 | ||
1554 | mutex_unlock(&priv->mutex); | 1553 | mutex_unlock(&priv->mutex); |
diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index ab768045696b..2d33760a9dc2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c | |||
@@ -77,7 +77,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
77 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", | 77 | IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", |
78 | sta_id); | 78 | sta_id); |
79 | 79 | ||
80 | spin_lock(&priv->sta_lock); | 80 | spin_lock_bh(&priv->sta_lock); |
81 | 81 | ||
82 | switch (add_sta_resp->status) { | 82 | switch (add_sta_resp->status) { |
83 | case ADD_STA_SUCCESS_MSK: | 83 | case ADD_STA_SUCCESS_MSK: |
@@ -119,7 +119,7 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv, | |||
119 | priv->stations[sta_id].sta.mode == | 119 | priv->stations[sta_id].sta.mode == |
120 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", | 120 | STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", |
121 | addsta->sta.addr); | 121 | addsta->sta.addr); |
122 | spin_unlock(&priv->sta_lock); | 122 | spin_unlock_bh(&priv->sta_lock); |
123 | 123 | ||
124 | return ret; | 124 | return ret; |
125 | } | 125 | } |
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index 7b0550d35a91..4ece5ea81b86 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c | |||
@@ -1117,7 +1117,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1117 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> | 1117 | sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> |
1118 | IWLAGN_TX_RES_RA_POS; | 1118 | IWLAGN_TX_RES_RA_POS; |
1119 | 1119 | ||
1120 | spin_lock(&priv->sta_lock); | 1120 | spin_lock_bh(&priv->sta_lock); |
1121 | 1121 | ||
1122 | if (is_agg) | 1122 | if (is_agg) |
1123 | iwl_rx_reply_tx_agg(priv, tx_resp); | 1123 | iwl_rx_reply_tx_agg(priv, tx_resp); |
@@ -1239,11 +1239,11 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, | |||
1239 | le16_to_cpu(tx_resp->seq_ctl)); | 1239 | le16_to_cpu(tx_resp->seq_ctl)); |
1240 | 1240 | ||
1241 | iwl_check_abort_status(priv, tx_resp->frame_count, status); | 1241 | iwl_check_abort_status(priv, tx_resp->frame_count, status); |
1242 | spin_unlock(&priv->sta_lock); | 1242 | spin_unlock_bh(&priv->sta_lock); |
1243 | 1243 | ||
1244 | while (!skb_queue_empty(&skbs)) { | 1244 | while (!skb_queue_empty(&skbs)) { |
1245 | skb = __skb_dequeue(&skbs); | 1245 | skb = __skb_dequeue(&skbs); |
1246 | ieee80211_tx_status(priv->hw, skb); | 1246 | ieee80211_tx_status_ni(priv->hw, skb); |
1247 | } | 1247 | } |
1248 | 1248 | ||
1249 | if (is_offchannel_skb) | 1249 | if (is_offchannel_skb) |
@@ -1290,12 +1290,12 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1290 | tid = ba_resp->tid; | 1290 | tid = ba_resp->tid; |
1291 | agg = &priv->tid_data[sta_id][tid].agg; | 1291 | agg = &priv->tid_data[sta_id][tid].agg; |
1292 | 1292 | ||
1293 | spin_lock(&priv->sta_lock); | 1293 | spin_lock_bh(&priv->sta_lock); |
1294 | 1294 | ||
1295 | if (unlikely(!agg->wait_for_ba)) { | 1295 | if (unlikely(!agg->wait_for_ba)) { |
1296 | if (unlikely(ba_resp->bitmap)) | 1296 | if (unlikely(ba_resp->bitmap)) |
1297 | IWL_ERR(priv, "Received BA when not expected\n"); | 1297 | IWL_ERR(priv, "Received BA when not expected\n"); |
1298 | spin_unlock(&priv->sta_lock); | 1298 | spin_unlock_bh(&priv->sta_lock); |
1299 | return 0; | 1299 | return 0; |
1300 | } | 1300 | } |
1301 | 1301 | ||
@@ -1309,7 +1309,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1309 | IWL_DEBUG_TX_QUEUES(priv, | 1309 | IWL_DEBUG_TX_QUEUES(priv, |
1310 | "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", | 1310 | "Bad queue mapping txq_id=%d, agg_txq[sta:%d,tid:%d]=%d\n", |
1311 | scd_flow, sta_id, tid, agg->txq_id); | 1311 | scd_flow, sta_id, tid, agg->txq_id); |
1312 | spin_unlock(&priv->sta_lock); | 1312 | spin_unlock_bh(&priv->sta_lock); |
1313 | return 0; | 1313 | return 0; |
1314 | } | 1314 | } |
1315 | 1315 | ||
@@ -1378,11 +1378,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1378 | } | 1378 | } |
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | spin_unlock(&priv->sta_lock); | 1381 | spin_unlock_bh(&priv->sta_lock); |
1382 | 1382 | ||
1383 | while (!skb_queue_empty(&reclaimed_skbs)) { | 1383 | while (!skb_queue_empty(&reclaimed_skbs)) { |
1384 | skb = __skb_dequeue(&reclaimed_skbs); | 1384 | skb = __skb_dequeue(&reclaimed_skbs); |
1385 | ieee80211_tx_status(priv->hw, skb); | 1385 | ieee80211_tx_status_ni(priv->hw, skb); |
1386 | } | 1386 | } |
1387 | 1387 | ||
1388 | return 0; | 1388 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index dc792584f401..4a680019e117 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h | |||
@@ -113,13 +113,13 @@ struct iwl_cfg; | |||
113 | * May sleep | 113 | * May sleep |
114 | * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the | 114 | * @rx: Rx notification to the op_mode. rxb is the Rx buffer itself. Cmd is the |
115 | * HCMD the this Rx responds to. | 115 | * HCMD the this Rx responds to. |
116 | * Must be atomic and called with BH disabled. | 116 | * This callback may sleep, it is called from a threaded IRQ handler. |
117 | * @queue_full: notifies that a HW queue is full. | 117 | * @queue_full: notifies that a HW queue is full. |
118 | * Must be atomic and called with BH disabled. | 118 | * Must be atomic and called with BH disabled. |
119 | * @queue_not_full: notifies that a HW queue is not full any more. | 119 | * @queue_not_full: notifies that a HW queue is not full any more. |
120 | * Must be atomic and called with BH disabled. | 120 | * Must be atomic and called with BH disabled. |
121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that | 121 | * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that |
122 | * the radio is killed. Must be atomic. | 122 | * the radio is killed. May sleep. |
123 | * @free_skb: allows the transport layer to free skbs that haven't been | 123 | * @free_skb: allows the transport layer to free skbs that haven't been |
124 | * reclaimed by the op_mode. This can happen when the driver is freed and | 124 | * reclaimed by the op_mode. This can happen when the driver is freed and |
125 | * there are Tx packets pending in the transport layer. | 125 | * there are Tx packets pending in the transport layer. |
@@ -130,8 +130,7 @@ struct iwl_cfg; | |||
130 | * called with BH disabled. | 130 | * called with BH disabled. |
131 | * @nic_config: configure NIC, called before firmware is started. | 131 | * @nic_config: configure NIC, called before firmware is started. |
132 | * May sleep | 132 | * May sleep |
133 | * @wimax_active: invoked when WiMax becomes active. Must be atomic and called | 133 | * @wimax_active: invoked when WiMax becomes active. May sleep |
134 | * with BH disabled. | ||
135 | */ | 134 | */ |
136 | struct iwl_op_mode_ops { | 135 | struct iwl_op_mode_ops { |
137 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, | 136 | struct iwl_op_mode *(*start)(struct iwl_trans *trans, |
@@ -178,6 +177,7 @@ static inline int iwl_op_mode_rx(struct iwl_op_mode *op_mode, | |||
178 | struct iwl_rx_cmd_buffer *rxb, | 177 | struct iwl_rx_cmd_buffer *rxb, |
179 | struct iwl_device_cmd *cmd) | 178 | struct iwl_device_cmd *cmd) |
180 | { | 179 | { |
180 | might_sleep(); | ||
181 | return op_mode->ops->rx(op_mode, rxb, cmd); | 181 | return op_mode->ops->rx(op_mode, rxb, cmd); |
182 | } | 182 | } |
183 | 183 | ||
@@ -196,6 +196,7 @@ static inline void iwl_op_mode_queue_not_full(struct iwl_op_mode *op_mode, | |||
196 | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, | 196 | static inline void iwl_op_mode_hw_rf_kill(struct iwl_op_mode *op_mode, |
197 | bool state) | 197 | bool state) |
198 | { | 198 | { |
199 | might_sleep(); | ||
199 | op_mode->ops->hw_rf_kill(op_mode, state); | 200 | op_mode->ops->hw_rf_kill(op_mode, state); |
200 | } | 201 | } |
201 | 202 | ||
@@ -223,6 +224,7 @@ static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode) | |||
223 | 224 | ||
224 | static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) | 225 | static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) |
225 | { | 226 | { |
227 | might_sleep(); | ||
226 | op_mode->ops->wimax_active(op_mode); | 228 | op_mode->ops->wimax_active(op_mode); |
227 | } | 229 | } |
228 | 230 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0a3d4df5f434..8c7bec6b9a0b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h | |||
@@ -65,6 +65,7 @@ | |||
65 | 65 | ||
66 | #include <linux/ieee80211.h> | 66 | #include <linux/ieee80211.h> |
67 | #include <linux/mm.h> /* for page_address */ | 67 | #include <linux/mm.h> /* for page_address */ |
68 | #include <linux/lockdep.h> | ||
68 | 69 | ||
69 | #include "iwl-debug.h" | 70 | #include "iwl-debug.h" |
70 | #include "iwl-config.h" | 71 | #include "iwl-config.h" |
@@ -526,6 +527,10 @@ struct iwl_trans { | |||
526 | 527 | ||
527 | struct dentry *dbgfs_dir; | 528 | struct dentry *dbgfs_dir; |
528 | 529 | ||
530 | #ifdef CONFIG_LOCKDEP | ||
531 | struct lockdep_map sync_cmd_lockdep_map; | ||
532 | #endif | ||
533 | |||
529 | /* pointer to trans specific struct */ | 534 | /* pointer to trans specific struct */ |
530 | /*Ensure that this pointer will always be aligned to sizeof pointer */ | 535 | /*Ensure that this pointer will always be aligned to sizeof pointer */ |
531 | char trans_specific[0] __aligned(sizeof(void *)); | 536 | char trans_specific[0] __aligned(sizeof(void *)); |
@@ -602,12 +607,22 @@ static inline int iwl_trans_d3_resume(struct iwl_trans *trans, | |||
602 | } | 607 | } |
603 | 608 | ||
604 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, | 609 | static inline int iwl_trans_send_cmd(struct iwl_trans *trans, |
605 | struct iwl_host_cmd *cmd) | 610 | struct iwl_host_cmd *cmd) |
606 | { | 611 | { |
612 | int ret; | ||
613 | |||
607 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, | 614 | WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, |
608 | "%s bad state = %d", __func__, trans->state); | 615 | "%s bad state = %d", __func__, trans->state); |
609 | 616 | ||
610 | return trans->ops->send_cmd(trans, cmd); | 617 | if (!(cmd->flags & CMD_ASYNC)) |
618 | lock_map_acquire_read(&trans->sync_cmd_lockdep_map); | ||
619 | |||
620 | ret = trans->ops->send_cmd(trans, cmd); | ||
621 | |||
622 | if (!(cmd->flags & CMD_ASYNC)) | ||
623 | lock_map_release(&trans->sync_cmd_lockdep_map); | ||
624 | |||
625 | return ret; | ||
611 | } | 626 | } |
612 | 627 | ||
613 | static inline struct iwl_device_cmd * | 628 | static inline struct iwl_device_cmd * |
@@ -791,4 +806,14 @@ iwl_trans_release_nic_access(struct iwl_trans *trans, unsigned long *flags) | |||
791 | int __must_check iwl_pci_register_driver(void); | 806 | int __must_check iwl_pci_register_driver(void); |
792 | void iwl_pci_unregister_driver(void); | 807 | void iwl_pci_unregister_driver(void); |
793 | 808 | ||
809 | static inline void trans_lockdep_init(struct iwl_trans *trans) | ||
810 | { | ||
811 | #ifdef CONFIG_LOCKDEP | ||
812 | static struct lock_class_key __key; | ||
813 | |||
814 | lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map", | ||
815 | &__key, 0); | ||
816 | #endif | ||
817 | } | ||
818 | |||
794 | #endif /* __iwl_trans_h__ */ | 819 | #endif /* __iwl_trans_h__ */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 9a95c374990d..c64d864799cd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c | |||
@@ -97,14 +97,14 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, | |||
97 | struct inet6_ifaddr *ifa; | 97 | struct inet6_ifaddr *ifa; |
98 | int idx = 0; | 98 | int idx = 0; |
99 | 99 | ||
100 | read_lock(&idev->lock); | 100 | read_lock_bh(&idev->lock); |
101 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 101 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
102 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; | 102 | mvmvif->target_ipv6_addrs[idx] = ifa->addr; |
103 | idx++; | 103 | idx++; |
104 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) | 104 | if (idx >= IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS) |
105 | break; | 105 | break; |
106 | } | 106 | } |
107 | read_unlock(&idev->lock); | 107 | read_unlock_bh(&idev->lock); |
108 | 108 | ||
109 | mvmvif->num_target_ipv6_addrs = idx; | 109 | mvmvif->num_target_ipv6_addrs = idx; |
110 | } | 110 | } |
@@ -490,7 +490,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
490 | return -EIO; | 490 | return -EIO; |
491 | } | 491 | } |
492 | 492 | ||
493 | ret = iwl_mvm_sta_add_to_fw(mvm, ap_sta); | 493 | ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false); |
494 | if (ret) | 494 | if (ret) |
495 | return ret; | 495 | return ret; |
496 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); | 496 | rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta); |
@@ -763,6 +763,146 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
763 | return ret; | 763 | return ret; |
764 | } | 764 | } |
765 | 765 | ||
766 | static void iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, | ||
767 | struct ieee80211_vif *vif) | ||
768 | { | ||
769 | u32 base = mvm->error_event_table; | ||
770 | struct error_table_start { | ||
771 | /* cf. struct iwl_error_event_table */ | ||
772 | u32 valid; | ||
773 | u32 error_id; | ||
774 | } err_info; | ||
775 | struct cfg80211_wowlan_wakeup wakeup = { | ||
776 | .pattern_idx = -1, | ||
777 | }; | ||
778 | struct cfg80211_wowlan_wakeup *wakeup_report = &wakeup; | ||
779 | struct iwl_host_cmd cmd = { | ||
780 | .id = WOWLAN_GET_STATUSES, | ||
781 | .flags = CMD_SYNC | CMD_WANT_SKB, | ||
782 | }; | ||
783 | struct iwl_wowlan_status *status; | ||
784 | u32 reasons; | ||
785 | int ret, len; | ||
786 | bool pkt8023 = false; | ||
787 | struct sk_buff *pkt = NULL; | ||
788 | |||
789 | iwl_trans_read_mem_bytes(mvm->trans, base, | ||
790 | &err_info, sizeof(err_info)); | ||
791 | |||
792 | if (err_info.valid) { | ||
793 | IWL_INFO(mvm, "error table is valid (%d)\n", | ||
794 | err_info.valid); | ||
795 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) { | ||
796 | wakeup.rfkill_release = true; | ||
797 | ieee80211_report_wowlan_wakeup(vif, &wakeup, | ||
798 | GFP_KERNEL); | ||
799 | } | ||
800 | return; | ||
801 | } | ||
802 | |||
803 | /* only for tracing for now */ | ||
804 | ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||
805 | if (ret) | ||
806 | IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); | ||
807 | |||
808 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
809 | if (ret) { | ||
810 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||
811 | return; | ||
812 | } | ||
813 | |||
814 | /* RF-kill already asserted again... */ | ||
815 | if (!cmd.resp_pkt) | ||
816 | return; | ||
817 | |||
818 | len = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
819 | if (len - sizeof(struct iwl_cmd_header) < sizeof(*status)) { | ||
820 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
821 | goto out; | ||
822 | } | ||
823 | |||
824 | status = (void *)cmd.resp_pkt->data; | ||
825 | |||
826 | if (len - sizeof(struct iwl_cmd_header) != | ||
827 | sizeof(*status) + le32_to_cpu(status->wake_packet_bufsize)) { | ||
828 | IWL_ERR(mvm, "Invalid WoWLAN status response!\n"); | ||
829 | goto out; | ||
830 | } | ||
831 | |||
832 | reasons = le32_to_cpu(status->wakeup_reasons); | ||
833 | |||
834 | if (reasons == IWL_WOWLAN_WAKEUP_BY_NON_WIRELESS) { | ||
835 | wakeup_report = NULL; | ||
836 | goto report; | ||
837 | } | ||
838 | |||
839 | if (reasons & IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET) { | ||
840 | wakeup.magic_pkt = true; | ||
841 | pkt8023 = true; | ||
842 | } | ||
843 | |||
844 | if (reasons & IWL_WOWLAN_WAKEUP_BY_PATTERN) { | ||
845 | wakeup.pattern_idx = | ||
846 | le16_to_cpu(status->pattern_number); | ||
847 | pkt8023 = true; | ||
848 | } | ||
849 | |||
850 | if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | ||
851 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) | ||
852 | wakeup.disconnect = true; | ||
853 | |||
854 | if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) { | ||
855 | wakeup.gtk_rekey_failure = true; | ||
856 | pkt8023 = true; | ||
857 | } | ||
858 | |||
859 | if (reasons & IWL_WOWLAN_WAKEUP_BY_RFKILL_DEASSERTED) { | ||
860 | wakeup.rfkill_release = true; | ||
861 | pkt8023 = true; | ||
862 | } | ||
863 | |||
864 | if (reasons & IWL_WOWLAN_WAKEUP_BY_EAPOL_REQUEST) { | ||
865 | wakeup.eap_identity_req = true; | ||
866 | pkt8023 = true; | ||
867 | } | ||
868 | |||
869 | if (reasons & IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE) { | ||
870 | wakeup.four_way_handshake = true; | ||
871 | pkt8023 = true; | ||
872 | } | ||
873 | |||
874 | if (status->wake_packet_bufsize) { | ||
875 | u32 pktsize = le32_to_cpu(status->wake_packet_bufsize); | ||
876 | u32 pktlen = le32_to_cpu(status->wake_packet_length); | ||
877 | |||
878 | if (pkt8023) { | ||
879 | pkt = alloc_skb(pktsize, GFP_KERNEL); | ||
880 | if (!pkt) | ||
881 | goto report; | ||
882 | memcpy(skb_put(pkt, pktsize), status->wake_packet, | ||
883 | pktsize); | ||
884 | if (ieee80211_data_to_8023(pkt, vif->addr, vif->type)) | ||
885 | goto report; | ||
886 | wakeup.packet = pkt->data; | ||
887 | wakeup.packet_present_len = pkt->len; | ||
888 | wakeup.packet_len = pkt->len - (pktlen - pktsize); | ||
889 | wakeup.packet_80211 = false; | ||
890 | } else { | ||
891 | wakeup.packet = status->wake_packet; | ||
892 | wakeup.packet_present_len = pktsize; | ||
893 | wakeup.packet_len = pktlen; | ||
894 | wakeup.packet_80211 = true; | ||
895 | } | ||
896 | } | ||
897 | |||
898 | report: | ||
899 | ieee80211_report_wowlan_wakeup(vif, wakeup_report, GFP_KERNEL); | ||
900 | kfree_skb(pkt); | ||
901 | |||
902 | out: | ||
903 | iwl_free_resp(&cmd); | ||
904 | } | ||
905 | |||
766 | int iwl_mvm_resume(struct ieee80211_hw *hw) | 906 | int iwl_mvm_resume(struct ieee80211_hw *hw) |
767 | { | 907 | { |
768 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 908 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
@@ -770,14 +910,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
770 | .mvm = mvm, | 910 | .mvm = mvm, |
771 | }; | 911 | }; |
772 | struct ieee80211_vif *vif = NULL; | 912 | struct ieee80211_vif *vif = NULL; |
773 | u32 base; | ||
774 | int ret; | 913 | int ret; |
775 | enum iwl_d3_status d3_status; | 914 | enum iwl_d3_status d3_status; |
776 | struct error_table_start { | ||
777 | /* cf. struct iwl_error_event_table */ | ||
778 | u32 valid; | ||
779 | u32 error_id; | ||
780 | } err_info; | ||
781 | 915 | ||
782 | mutex_lock(&mvm->mutex); | 916 | mutex_lock(&mvm->mutex); |
783 | 917 | ||
@@ -800,27 +934,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) | |||
800 | goto out_unlock; | 934 | goto out_unlock; |
801 | } | 935 | } |
802 | 936 | ||
803 | base = mvm->error_event_table; | 937 | iwl_mvm_query_wakeup_reasons(mvm, vif); |
804 | |||
805 | iwl_trans_read_mem_bytes(mvm->trans, base, | ||
806 | &err_info, sizeof(err_info)); | ||
807 | |||
808 | if (err_info.valid) { | ||
809 | IWL_INFO(mvm, "error table is valid (%d)\n", | ||
810 | err_info.valid); | ||
811 | if (err_info.error_id == RF_KILL_INDICATOR_FOR_WOWLAN) | ||
812 | IWL_ERR(mvm, "this was due to RF-kill\n"); | ||
813 | goto out_unlock; | ||
814 | } | ||
815 | |||
816 | /* TODO: get status and whatever else ... */ | ||
817 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_GET_STATUSES, CMD_SYNC, 0, NULL); | ||
818 | if (ret) | ||
819 | IWL_ERR(mvm, "failed to query status (%d)\n", ret); | ||
820 | |||
821 | ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, CMD_SYNC, 0, NULL); | ||
822 | if (ret) | ||
823 | IWL_ERR(mvm, "failed to query offloads (%d)\n", ret); | ||
824 | 938 | ||
825 | out_unlock: | 939 | out_unlock: |
826 | mutex_unlock(&mvm->mutex); | 940 | mutex_unlock(&mvm->mutex); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 9fd49db32a32..23eebda848b0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -633,6 +633,9 @@ struct iwl_binding_cmd { | |||
633 | __le32 phy; | 633 | __le32 phy; |
634 | } __packed; /* BINDING_CMD_API_S_VER_1 */ | 634 | } __packed; /* BINDING_CMD_API_S_VER_1 */ |
635 | 635 | ||
636 | /* The maximal number of fragments in the FW's schedule session */ | ||
637 | #define IWL_MVM_MAX_QUOTA 128 | ||
638 | |||
636 | /** | 639 | /** |
637 | * struct iwl_time_quota_data - configuration of time quota per binding | 640 | * struct iwl_time_quota_data - configuration of time quota per binding |
638 | * @id_and_color: ID and color of the relevant Binding | 641 | * @id_and_color: ID and color of the relevant Binding |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 90473c2ba1c7..d3d959db03a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -621,10 +621,6 @@ int iwl_mvm_rx_card_state_notif(struct iwl_mvm *mvm, | |||
621 | (flags & CT_KILL_CARD_DISABLED) ? | 621 | (flags & CT_KILL_CARD_DISABLED) ? |
622 | "Reached" : "Not reached"); | 622 | "Reached" : "Not reached"); |
623 | 623 | ||
624 | if (flags & CARD_DISABLED_MSK) | ||
625 | iwl_write32(mvm->trans, CSR_UCODE_DRV_GP1_SET, | ||
626 | CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); | ||
627 | |||
628 | return 0; | 624 | return 0; |
629 | } | 625 | } |
630 | 626 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index c08a17a3cab9..0854dc338881 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -584,7 +584,11 @@ static void iwl_mvm_mac_ctxt_cmd_fill_sta(struct iwl_mvm *mvm, | |||
584 | struct ieee80211_vif *vif, | 584 | struct ieee80211_vif *vif, |
585 | struct iwl_mac_data_sta *ctxt_sta) | 585 | struct iwl_mac_data_sta *ctxt_sta) |
586 | { | 586 | { |
587 | ctxt_sta->is_assoc = cpu_to_le32(vif->bss_conf.assoc ? 1 : 0); | 587 | /* We need the dtim_period to set the MAC as associated */ |
588 | if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) | ||
589 | ctxt_sta->is_assoc = cpu_to_le32(1); | ||
590 | else | ||
591 | ctxt_sta->is_assoc = cpu_to_le32(0); | ||
588 | 592 | ||
589 | ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); | 593 | ctxt_sta->bi = cpu_to_le32(vif->bss_conf.beacon_int); |
590 | ctxt_sta->bi_reciprocal = | 594 | ctxt_sta->bi_reciprocal = |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index bbb8a5b35662..e27eb9724112 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -474,7 +474,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, | |||
474 | if (mvm->vif_count > 1) { | 474 | if (mvm->vif_count > 1) { |
475 | IWL_DEBUG_MAC80211(mvm, | 475 | IWL_DEBUG_MAC80211(mvm, |
476 | "Disable power on existing interfaces\n"); | 476 | "Disable power on existing interfaces\n"); |
477 | ieee80211_iterate_active_interfaces( | 477 | ieee80211_iterate_active_interfaces_atomic( |
478 | mvm->hw, | 478 | mvm->hw, |
479 | IEEE80211_IFACE_ITER_NORMAL, | 479 | IEEE80211_IFACE_ITER_NORMAL, |
480 | iwl_mvm_pm_disable_iterator, mvm); | 480 | iwl_mvm_pm_disable_iterator, mvm); |
@@ -670,8 +670,6 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
670 | IWL_ERR(mvm, "failed to update quotas\n"); | 670 | IWL_ERR(mvm, "failed to update quotas\n"); |
671 | return; | 671 | return; |
672 | } | 672 | } |
673 | iwl_mvm_remove_time_event(mvm, mvmvif, | ||
674 | &mvmvif->time_event_data); | ||
675 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { | 673 | } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) { |
676 | /* remove AP station now that the MAC is unassoc */ | 674 | /* remove AP station now that the MAC is unassoc */ |
677 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 675 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
@@ -683,6 +681,13 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
683 | if (ret) | 681 | if (ret) |
684 | IWL_ERR(mvm, "failed to update quotas\n"); | 682 | IWL_ERR(mvm, "failed to update quotas\n"); |
685 | } | 683 | } |
684 | } else if (changes & BSS_CHANGED_DTIM_PERIOD) { | ||
685 | /* | ||
686 | * We received a beacon _after_ association so | ||
687 | * remove the session protection. | ||
688 | */ | ||
689 | iwl_mvm_remove_time_event(mvm, mvmvif, | ||
690 | &mvmvif->time_event_data); | ||
686 | } else if (changes & BSS_CHANGED_PS) { | 691 | } else if (changes & BSS_CHANGED_PS) { |
687 | /* | 692 | /* |
688 | * TODO: remove this temporary code. | 693 | * TODO: remove this temporary code. |
@@ -921,8 +926,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, | |||
921 | ret = 0; | 926 | ret = 0; |
922 | } else if (old_state == IEEE80211_STA_AUTH && | 927 | } else if (old_state == IEEE80211_STA_AUTH && |
923 | new_state == IEEE80211_STA_ASSOC) { | 928 | new_state == IEEE80211_STA_ASSOC) { |
924 | iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band); | 929 | ret = iwl_mvm_update_sta(mvm, vif, sta); |
925 | ret = 0; | 930 | if (ret == 0) |
931 | iwl_mvm_rs_rate_init(mvm, sta, | ||
932 | mvmvif->phy_ctxt->channel->band); | ||
926 | } else if (old_state == IEEE80211_STA_ASSOC && | 933 | } else if (old_state == IEEE80211_STA_ASSOC && |
927 | new_state == IEEE80211_STA_AUTHORIZED) { | 934 | new_state == IEEE80211_STA_AUTHORIZED) { |
928 | ret = 0; | 935 | ret = 0; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 983dca3f888a..aa59adf87db3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -536,25 +536,28 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, | |||
536 | 536 | ||
537 | for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { | 537 | for (i = 0; i < ARRAY_SIZE(iwl_mvm_rx_handlers); i++) { |
538 | const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; | 538 | const struct iwl_rx_handlers *rx_h = &iwl_mvm_rx_handlers[i]; |
539 | if (rx_h->cmd_id == pkt->hdr.cmd) { | 539 | struct iwl_async_handler_entry *entry; |
540 | struct iwl_async_handler_entry *entry; | 540 | |
541 | if (!rx_h->async) | 541 | if (rx_h->cmd_id != pkt->hdr.cmd) |
542 | return rx_h->fn(mvm, rxb, cmd); | 542 | continue; |
543 | 543 | ||
544 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 544 | if (!rx_h->async) |
545 | /* we can't do much... */ | 545 | return rx_h->fn(mvm, rxb, cmd); |
546 | if (!entry) | 546 | |
547 | return 0; | 547 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
548 | 548 | /* we can't do much... */ | |
549 | entry->rxb._page = rxb_steal_page(rxb); | 549 | if (!entry) |
550 | entry->rxb._offset = rxb->_offset; | 550 | return 0; |
551 | entry->rxb._rx_page_order = rxb->_rx_page_order; | 551 | |
552 | entry->fn = rx_h->fn; | 552 | entry->rxb._page = rxb_steal_page(rxb); |
553 | spin_lock(&mvm->async_handlers_lock); | 553 | entry->rxb._offset = rxb->_offset; |
554 | list_add_tail(&entry->list, &mvm->async_handlers_list); | 554 | entry->rxb._rx_page_order = rxb->_rx_page_order; |
555 | spin_unlock(&mvm->async_handlers_lock); | 555 | entry->fn = rx_h->fn; |
556 | schedule_work(&mvm->async_handlers_wk); | 556 | spin_lock(&mvm->async_handlers_lock); |
557 | } | 557 | list_add_tail(&entry->list, &mvm->async_handlers_list); |
558 | spin_unlock(&mvm->async_handlers_lock); | ||
559 | schedule_work(&mvm->async_handlers_wk); | ||
560 | break; | ||
558 | } | 561 | } |
559 | 562 | ||
560 | return 0; | 563 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 63628739cf4a..5a92a4978795 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c | |||
@@ -194,7 +194,7 @@ int iwl_mvm_power_disable(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
194 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, | 194 | cmd.id_and_color, iwlmvm_mod_params.power_scheme, |
195 | le16_to_cpu(cmd.flags)); | 195 | le16_to_cpu(cmd.flags)); |
196 | 196 | ||
197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_SYNC, | 197 | return iwl_mvm_send_cmd_pdu(mvm, POWER_TABLE_CMD, CMD_ASYNC, |
198 | sizeof(cmd), &cmd); | 198 | sizeof(cmd), &cmd); |
199 | } | 199 | } |
200 | 200 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 2d4611a563c5..925628468146 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c | |||
@@ -131,7 +131,7 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac, | |||
131 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | 131 | int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) |
132 | { | 132 | { |
133 | struct iwl_time_quota_cmd cmd; | 133 | struct iwl_time_quota_cmd cmd; |
134 | int i, idx, ret; | 134 | int i, idx, ret, num_active_bindings, quota, quota_rem; |
135 | struct iwl_mvm_quota_iterator_data data = { | 135 | struct iwl_mvm_quota_iterator_data data = { |
136 | .n_interfaces = {}, | 136 | .n_interfaces = {}, |
137 | .colors = { -1, -1, -1, -1 }, | 137 | .colors = { -1, -1, -1, -1 }, |
@@ -156,20 +156,39 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, struct ieee80211_vif *newvif) | |||
156 | iwl_mvm_quota_iterator(&data, newvif->addr, newvif); | 156 | iwl_mvm_quota_iterator(&data, newvif->addr, newvif); |
157 | } | 157 | } |
158 | 158 | ||
159 | /* | ||
160 | * The FW's scheduling session consists of | ||
161 | * IWL_MVM_MAX_QUOTA fragments. Divide these fragments | ||
162 | * equally between all the bindings that require quota | ||
163 | */ | ||
164 | num_active_bindings = 0; | ||
165 | for (i = 0; i < MAX_BINDINGS; i++) { | ||
166 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | ||
167 | if (data.n_interfaces[i] > 0) | ||
168 | num_active_bindings++; | ||
169 | } | ||
170 | |||
171 | if (!num_active_bindings) | ||
172 | goto send_cmd; | ||
173 | |||
174 | quota = IWL_MVM_MAX_QUOTA / num_active_bindings; | ||
175 | quota_rem = IWL_MVM_MAX_QUOTA % num_active_bindings; | ||
176 | |||
159 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { | 177 | for (idx = 0, i = 0; i < MAX_BINDINGS; i++) { |
160 | if (data.n_interfaces[i] <= 0) | 178 | if (data.n_interfaces[i] <= 0) |
161 | continue; | 179 | continue; |
162 | 180 | ||
163 | cmd.quotas[idx].id_and_color = | 181 | cmd.quotas[idx].id_and_color = |
164 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); | 182 | cpu_to_le32(FW_CMD_ID_AND_COLOR(i, data.colors[i])); |
165 | cmd.quotas[idx].quota = cpu_to_le32(100); | 183 | cmd.quotas[idx].quota = cpu_to_le32(quota); |
166 | cmd.quotas[idx].max_duration = cpu_to_le32(1000); | 184 | cmd.quotas[idx].max_duration = cpu_to_le32(IWL_MVM_MAX_QUOTA); |
167 | idx++; | 185 | idx++; |
168 | } | 186 | } |
169 | 187 | ||
170 | for (i = idx; i < MAX_BINDINGS; i++) | 188 | /* Give the remainder of the session to the first binding */ |
171 | cmd.quotas[i].id_and_color = cpu_to_le32(FW_CTXT_INVALID); | 189 | le32_add_cpu(&cmd.quotas[0].quota, quota_rem); |
172 | 190 | ||
191 | send_cmd: | ||
173 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, | 192 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_QUOTA_CMD, CMD_SYNC, |
174 | sizeof(cmd), &cmd); | 193 | sizeof(cmd), &cmd); |
175 | if (ret) | 194 | if (ret) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 52da375e5740..3f3ce91ad5c2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c | |||
@@ -121,7 +121,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, | |||
121 | 121 | ||
122 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 122 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
123 | 123 | ||
124 | ieee80211_rx(mvm->hw, skb); | 124 | ieee80211_rx_ni(mvm->hw, skb); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* | 127 | /* |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 69603c3b2b39..a1eb692d7fad 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -81,8 +81,9 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm) | |||
81 | return IWL_MVM_STATION_COUNT; | 81 | return IWL_MVM_STATION_COUNT; |
82 | } | 82 | } |
83 | 83 | ||
84 | /* add a NEW station to fw */ | 84 | /* send station add/update command to firmware */ |
85 | int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) | 85 | int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
86 | bool update) | ||
86 | { | 87 | { |
87 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 88 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; |
88 | struct iwl_mvm_add_sta_cmd add_sta_cmd; | 89 | struct iwl_mvm_add_sta_cmd add_sta_cmd; |
@@ -94,8 +95,11 @@ int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta) | |||
94 | 95 | ||
95 | add_sta_cmd.sta_id = mvm_sta->sta_id; | 96 | add_sta_cmd.sta_id = mvm_sta->sta_id; |
96 | add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); | 97 | add_sta_cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color); |
97 | add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); | 98 | if (!update) { |
98 | memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | 99 | add_sta_cmd.tfd_queue_msk = cpu_to_le32(mvm_sta->tfd_queue_msk); |
100 | memcpy(&add_sta_cmd.addr, sta->addr, ETH_ALEN); | ||
101 | } | ||
102 | add_sta_cmd.add_modify = update ? 1 : 0; | ||
99 | 103 | ||
100 | /* STA_FLG_FAT_EN_MSK ? */ | 104 | /* STA_FLG_FAT_EN_MSK ? */ |
101 | /* STA_FLG_MIMO_EN_MSK ? */ | 105 | /* STA_FLG_MIMO_EN_MSK ? */ |
@@ -181,7 +185,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
181 | /* for HW restart - need to reset the seq_number etc... */ | 185 | /* for HW restart - need to reset the seq_number etc... */ |
182 | memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); | 186 | memset(mvm_sta->tid_data, 0, sizeof(mvm_sta->tid_data)); |
183 | 187 | ||
184 | ret = iwl_mvm_sta_add_to_fw(mvm, sta); | 188 | ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); |
185 | if (ret) | 189 | if (ret) |
186 | return ret; | 190 | return ret; |
187 | 191 | ||
@@ -195,6 +199,13 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm, | |||
195 | return 0; | 199 | return 0; |
196 | } | 200 | } |
197 | 201 | ||
202 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | ||
203 | struct ieee80211_vif *vif, | ||
204 | struct ieee80211_sta *sta) | ||
205 | { | ||
206 | return iwl_mvm_sta_send_to_fw(mvm, sta, true); | ||
207 | } | ||
208 | |||
198 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | 209 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
199 | bool drain) | 210 | bool drain) |
200 | { | 211 | { |
@@ -1116,7 +1127,8 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, | |||
1116 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) | 1127 | if (WARN_ON_ONCE(mvm_sta->vif != vif)) |
1117 | return -EINVAL; | 1128 | return -EINVAL; |
1118 | 1129 | ||
1119 | key_flags = cpu_to_le16(keyconf->keyidx & STA_KEY_FLG_KEYID_MSK); | 1130 | key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) & |
1131 | STA_KEY_FLG_KEYID_MSK); | ||
1120 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); | 1132 | key_flags |= cpu_to_le16(STA_KEY_FLG_NO_ENC | STA_KEY_FLG_WEP_KEY_MAP); |
1121 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); | 1133 | key_flags |= cpu_to_le16(STA_KEY_NOT_VALID); |
1122 | 1134 | ||
@@ -1154,14 +1166,26 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, | |||
1154 | struct ieee80211_sta *sta, u32 iv32, | 1166 | struct ieee80211_sta *sta, u32 iv32, |
1155 | u16 *phase1key) | 1167 | u16 *phase1key) |
1156 | { | 1168 | { |
1157 | struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv; | 1169 | struct iwl_mvm_sta *mvm_sta; |
1158 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); | 1170 | u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta); |
1159 | 1171 | ||
1160 | if (sta_id == IWL_INVALID_STATION) | 1172 | if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION)) |
1161 | return; | 1173 | return; |
1162 | 1174 | ||
1175 | rcu_read_lock(); | ||
1176 | |||
1177 | if (!sta) { | ||
1178 | sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]); | ||
1179 | if (WARN_ON(IS_ERR_OR_NULL(sta))) { | ||
1180 | rcu_read_unlock(); | ||
1181 | return; | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | mvm_sta = (void *)sta->drv_priv; | ||
1163 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, | 1186 | iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, sta_id, |
1164 | iv32, phase1key, CMD_ASYNC); | 1187 | iv32, phase1key, CMD_ASYNC); |
1188 | rcu_read_unlock(); | ||
1165 | } | 1189 | } |
1166 | 1190 | ||
1167 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) | 1191 | void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm, int sta_id) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index 1bf301097984..bdd7c5ed8222 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h | |||
@@ -309,10 +309,14 @@ struct iwl_mvm_int_sta { | |||
309 | u32 tfd_queue_msk; | 309 | u32 tfd_queue_msk; |
310 | }; | 310 | }; |
311 | 311 | ||
312 | int iwl_mvm_sta_add_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta); | 312 | int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, |
313 | bool update); | ||
313 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, | 314 | int iwl_mvm_add_sta(struct iwl_mvm *mvm, |
314 | struct ieee80211_vif *vif, | 315 | struct ieee80211_vif *vif, |
315 | struct ieee80211_sta *sta); | 316 | struct ieee80211_sta *sta); |
317 | int iwl_mvm_update_sta(struct iwl_mvm *mvm, | ||
318 | struct ieee80211_vif *vif, | ||
319 | struct ieee80211_sta *sta); | ||
316 | int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | 320 | int iwl_mvm_rm_sta(struct iwl_mvm *mvm, |
317 | struct ieee80211_vif *vif, | 321 | struct ieee80211_vif *vif, |
318 | struct ieee80211_sta *sta); | 322 | struct ieee80211_sta *sta); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index b9f076f4f17c..c09b71f23759 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c | |||
@@ -76,6 +76,15 @@ | |||
76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) | 76 | #define TU_TO_JIFFIES(_tu) (usecs_to_jiffies((_tu) * 1024)) |
77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) | 77 | #define MSEC_TO_TU(_msec) (_msec*1000/1024) |
78 | 78 | ||
79 | /* For ROC use a TE type which has priority high enough to be scheduled when | ||
80 | * there is a concurrent BSS or GO/AP. Currently, use a TE type that has | ||
81 | * priority similar to the TE priority used for action scans by the FW. | ||
82 | * TODO: This needs to be changed, based on the reason for the ROC, i.e., use | ||
83 | * TE_P2P_DEVICE_DISCOVERABLE for remain on channel without mgmt skb, and use | ||
84 | * TE_P2P_DEVICE_ACTION_SCAN | ||
85 | */ | ||
86 | #define IWL_MVM_ROC_TE_TYPE TE_P2P_DEVICE_ACTION_SCAN | ||
87 | |||
79 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, | 88 | void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, |
80 | struct iwl_mvm_time_event_data *te_data) | 89 | struct iwl_mvm_time_event_data *te_data) |
81 | { | 90 | { |
@@ -175,9 +184,11 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, | |||
175 | */ | 184 | */ |
176 | if (te_data->vif->type == NL80211_IFTYPE_STATION && | 185 | if (te_data->vif->type == NL80211_IFTYPE_STATION && |
177 | (!te_data->vif->bss_conf.assoc || | 186 | (!te_data->vif->bss_conf.assoc || |
178 | !te_data->vif->bss_conf.dtim_period)) | 187 | !te_data->vif->bss_conf.dtim_period)) { |
179 | IWL_ERR(mvm, | 188 | IWL_ERR(mvm, |
180 | "No assocation and the time event is over already...\n"); | 189 | "No assocation and the time event is over already...\n"); |
190 | ieee80211_connection_loss(te_data->vif); | ||
191 | } | ||
181 | 192 | ||
182 | iwl_mvm_te_clear_data(mvm, te_data); | 193 | iwl_mvm_te_clear_data(mvm, te_data); |
183 | } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { | 194 | } else if (le32_to_cpu(notif->action) == TE_NOTIF_HOST_START) { |
@@ -219,57 +230,86 @@ int iwl_mvm_rx_time_event_notif(struct iwl_mvm *mvm, | |||
219 | return 0; | 230 | return 0; |
220 | } | 231 | } |
221 | 232 | ||
222 | static bool iwl_mvm_time_event_notif(struct iwl_notif_wait_data *notif_wait, | 233 | static bool iwl_mvm_time_event_response(struct iwl_notif_wait_data *notif_wait, |
223 | struct iwl_rx_packet *pkt, void *data) | 234 | struct iwl_rx_packet *pkt, void *data) |
224 | { | 235 | { |
225 | struct iwl_mvm *mvm = | 236 | struct iwl_mvm *mvm = |
226 | container_of(notif_wait, struct iwl_mvm, notif_wait); | 237 | container_of(notif_wait, struct iwl_mvm, notif_wait); |
227 | struct iwl_mvm_time_event_data *te_data = data; | 238 | struct iwl_mvm_time_event_data *te_data = data; |
228 | struct ieee80211_vif *vif = te_data->vif; | ||
229 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
230 | struct iwl_time_event_notif *notif; | ||
231 | struct iwl_time_event_resp *resp; | 239 | struct iwl_time_event_resp *resp; |
240 | int resp_len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; | ||
232 | 241 | ||
233 | u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); | 242 | if (WARN_ON(pkt->hdr.cmd != TIME_EVENT_CMD)) |
243 | return true; | ||
234 | 244 | ||
235 | /* until we do something else */ | 245 | if (WARN_ON_ONCE(resp_len != sizeof(pkt->hdr) + sizeof(*resp))) { |
236 | WARN_ON(te_data->id != TE_BSS_STA_AGGRESSIVE_ASSOC); | 246 | IWL_ERR(mvm, "Invalid TIME_EVENT_CMD response\n"); |
247 | return true; | ||
248 | } | ||
237 | 249 | ||
238 | switch (pkt->hdr.cmd) { | 250 | resp = (void *)pkt->data; |
239 | case TIME_EVENT_CMD: | 251 | te_data->uid = le32_to_cpu(resp->unique_id); |
240 | resp = (void *)pkt->data; | 252 | IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n", |
241 | /* TODO: I can't check that since the fw is buggy - it doesn't | 253 | te_data->uid); |
242 | * put the right values when we remove a TE. We can be here | 254 | return true; |
243 | * when we remove a TE because the remove TE command is sent in | 255 | } |
244 | * ASYNC... | ||
245 | * WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); | ||
246 | */ | ||
247 | te_data->uid = le32_to_cpu(resp->unique_id); | ||
248 | IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); | ||
249 | return false; | ||
250 | |||
251 | case TIME_EVENT_NOTIFICATION: | ||
252 | notif = (void *)pkt->data; | ||
253 | WARN_ON(le32_to_cpu(notif->status) != 1); | ||
254 | WARN_ON(mac_id_n_color != le32_to_cpu(notif->id_and_color)); | ||
255 | /* check if this is our Time Event that is starting */ | ||
256 | if (le32_to_cpu(notif->unique_id) != te_data->uid) | ||
257 | return false; | ||
258 | IWL_DEBUG_TE(mvm, "Event %d is starting - time is %d\n", | ||
259 | te_data->uid, le32_to_cpu(notif->timestamp)); | ||
260 | |||
261 | WARN_ONCE(!le32_to_cpu(notif->status), | ||
262 | "Failed to schedule protected session TE\n"); | ||
263 | 256 | ||
264 | te_data->running = true; | 257 | static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm, |
265 | te_data->end_jiffies = jiffies + | 258 | struct ieee80211_vif *vif, |
266 | TU_TO_JIFFIES(te_data->duration); | 259 | struct iwl_mvm_time_event_data *te_data, |
267 | return true; | 260 | struct iwl_time_event_cmd *te_cmd) |
261 | { | ||
262 | static const u8 time_event_response[] = { TIME_EVENT_CMD }; | ||
263 | struct iwl_notification_wait wait_time_event; | ||
264 | int ret; | ||
265 | |||
266 | lockdep_assert_held(&mvm->mutex); | ||
267 | |||
268 | spin_lock_bh(&mvm->time_event_lock); | ||
269 | if (WARN_ON(te_data->id != TE_MAX)) { | ||
270 | spin_unlock_bh(&mvm->time_event_lock); | ||
271 | return -EIO; | ||
272 | } | ||
273 | te_data->vif = vif; | ||
274 | te_data->duration = le32_to_cpu(te_cmd->duration); | ||
275 | te_data->id = le32_to_cpu(te_cmd->id); | ||
276 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
277 | spin_unlock_bh(&mvm->time_event_lock); | ||
278 | |||
279 | /* | ||
280 | * Use a notification wait, which really just processes the | ||
281 | * command response and doesn't wait for anything, in order | ||
282 | * to be able to process the response and get the UID inside | ||
283 | * the RX path. Using CMD_WANT_SKB doesn't work because it | ||
284 | * stores the buffer and then wakes up this thread, by which | ||
285 | * time another notification (that the time event started) | ||
286 | * might already be processed unsuccessfully. | ||
287 | */ | ||
288 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
289 | time_event_response, | ||
290 | ARRAY_SIZE(time_event_response), | ||
291 | iwl_mvm_time_event_response, te_data); | ||
268 | 292 | ||
269 | default: | 293 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, |
270 | WARN_ON(1); | 294 | sizeof(*te_cmd), te_cmd); |
271 | return false; | 295 | if (ret) { |
272 | }; | 296 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); |
297 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
298 | goto out_clear_te; | ||
299 | } | ||
300 | |||
301 | /* No need to wait for anything, so just pass 1 (0 isn't valid) */ | ||
302 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1); | ||
303 | /* should never fail */ | ||
304 | WARN_ON_ONCE(ret); | ||
305 | |||
306 | if (ret) { | ||
307 | out_clear_te: | ||
308 | spin_lock_bh(&mvm->time_event_lock); | ||
309 | iwl_mvm_te_clear_data(mvm, te_data); | ||
310 | spin_unlock_bh(&mvm->time_event_lock); | ||
311 | } | ||
312 | return ret; | ||
273 | } | 313 | } |
274 | 314 | ||
275 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, | 315 | void iwl_mvm_protect_session(struct iwl_mvm *mvm, |
@@ -278,11 +318,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
278 | { | 318 | { |
279 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 319 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
280 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 320 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
281 | static const u8 time_event_notif[] = { TIME_EVENT_CMD, | ||
282 | TIME_EVENT_NOTIFICATION }; | ||
283 | struct iwl_notification_wait wait_time_event; | ||
284 | struct iwl_time_event_cmd time_cmd = {}; | 321 | struct iwl_time_event_cmd time_cmd = {}; |
285 | int ret; | ||
286 | 322 | ||
287 | lockdep_assert_held(&mvm->mutex); | 323 | lockdep_assert_held(&mvm->mutex); |
288 | 324 | ||
@@ -309,12 +345,6 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
309 | iwl_mvm_stop_session_protection(mvm, vif); | 345 | iwl_mvm_stop_session_protection(mvm, vif); |
310 | } | 346 | } |
311 | 347 | ||
312 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
313 | time_event_notif, | ||
314 | ARRAY_SIZE(time_event_notif), | ||
315 | iwl_mvm_time_event_notif, | ||
316 | &mvmvif->time_event_data); | ||
317 | |||
318 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 348 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); |
319 | time_cmd.id_and_color = | 349 | time_cmd.id_and_color = |
320 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 350 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
@@ -322,6 +352,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
322 | 352 | ||
323 | time_cmd.apply_time = | 353 | time_cmd.apply_time = |
324 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); | 354 | cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG)); |
355 | |||
325 | time_cmd.dep_policy = TE_INDEPENDENT; | 356 | time_cmd.dep_policy = TE_INDEPENDENT; |
326 | time_cmd.is_present = cpu_to_le32(1); | 357 | time_cmd.is_present = cpu_to_le32(1); |
327 | time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); | 358 | time_cmd.max_frags = cpu_to_le32(TE_FRAG_NONE); |
@@ -333,33 +364,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, | |||
333 | time_cmd.repeat = cpu_to_le32(1); | 364 | time_cmd.repeat = cpu_to_le32(1); |
334 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 365 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); |
335 | 366 | ||
336 | te_data->vif = vif; | 367 | iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
337 | te_data->duration = duration; | ||
338 | |||
339 | spin_lock_bh(&mvm->time_event_lock); | ||
340 | te_data->id = le32_to_cpu(time_cmd.id); | ||
341 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
342 | spin_unlock_bh(&mvm->time_event_lock); | ||
343 | |||
344 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
345 | sizeof(time_cmd), &time_cmd); | ||
346 | if (ret) { | ||
347 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | ||
348 | goto out_remove_notif; | ||
349 | } | ||
350 | |||
351 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); | ||
352 | if (ret) { | ||
353 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
354 | spin_lock_bh(&mvm->time_event_lock); | ||
355 | iwl_mvm_te_clear_data(mvm, te_data); | ||
356 | spin_unlock_bh(&mvm->time_event_lock); | ||
357 | } | ||
358 | |||
359 | return; | ||
360 | |||
361 | out_remove_notif: | ||
362 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
363 | } | 368 | } |
364 | 369 | ||
365 | /* | 370 | /* |
@@ -424,43 +429,12 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, | |||
424 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); | 429 | iwl_mvm_remove_time_event(mvm, mvmvif, te_data); |
425 | } | 430 | } |
426 | 431 | ||
427 | static bool iwl_mvm_roc_te_notif(struct iwl_notif_wait_data *notif_wait, | ||
428 | struct iwl_rx_packet *pkt, void *data) | ||
429 | { | ||
430 | struct iwl_mvm *mvm = | ||
431 | container_of(notif_wait, struct iwl_mvm, notif_wait); | ||
432 | struct iwl_mvm_time_event_data *te_data = data; | ||
433 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); | ||
434 | struct iwl_time_event_resp *resp; | ||
435 | |||
436 | u32 mac_id_n_color = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); | ||
437 | |||
438 | /* until we do something else */ | ||
439 | WARN_ON(te_data->id != TE_P2P_DEVICE_DISCOVERABLE); | ||
440 | |||
441 | switch (pkt->hdr.cmd) { | ||
442 | case TIME_EVENT_CMD: | ||
443 | resp = (void *)pkt->data; | ||
444 | WARN_ON(mac_id_n_color != le32_to_cpu(resp->id_and_color)); | ||
445 | te_data->uid = le32_to_cpu(resp->unique_id); | ||
446 | IWL_DEBUG_TE(mvm, "Got response - UID = 0x%x\n", te_data->uid); | ||
447 | return true; | ||
448 | |||
449 | default: | ||
450 | WARN_ON(1); | ||
451 | return false; | ||
452 | }; | ||
453 | } | ||
454 | |||
455 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 432 | int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
456 | int duration) | 433 | int duration) |
457 | { | 434 | { |
458 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | 435 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); |
459 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; | 436 | struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data; |
460 | static const u8 roc_te_notif[] = { TIME_EVENT_CMD }; | ||
461 | struct iwl_notification_wait wait_time_event; | ||
462 | struct iwl_time_event_cmd time_cmd = {}; | 437 | struct iwl_time_event_cmd time_cmd = {}; |
463 | int ret; | ||
464 | 438 | ||
465 | lockdep_assert_held(&mvm->mutex); | 439 | lockdep_assert_held(&mvm->mutex); |
466 | if (te_data->running) { | 440 | if (te_data->running) { |
@@ -474,16 +448,10 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
474 | */ | 448 | */ |
475 | flush_work(&mvm->roc_done_wk); | 449 | flush_work(&mvm->roc_done_wk); |
476 | 450 | ||
477 | iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event, | ||
478 | roc_te_notif, | ||
479 | ARRAY_SIZE(roc_te_notif), | ||
480 | iwl_mvm_roc_te_notif, | ||
481 | &mvmvif->time_event_data); | ||
482 | |||
483 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); | 451 | time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_ADD); |
484 | time_cmd.id_and_color = | 452 | time_cmd.id_and_color = |
485 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); | 453 | cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)); |
486 | time_cmd.id = cpu_to_le32(TE_P2P_DEVICE_DISCOVERABLE); | 454 | time_cmd.id = cpu_to_le32(IWL_MVM_ROC_TE_TYPE); |
487 | 455 | ||
488 | time_cmd.apply_time = cpu_to_le32(0); | 456 | time_cmd.apply_time = cpu_to_le32(0); |
489 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); | 457 | time_cmd.dep_policy = cpu_to_le32(TE_INDEPENDENT); |
@@ -492,7 +460,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
492 | time_cmd.interval = cpu_to_le32(1); | 460 | time_cmd.interval = cpu_to_le32(1); |
493 | 461 | ||
494 | /* | 462 | /* |
495 | * TE_P2P_DEVICE_DISCOVERABLE can have lower priority than other events | 463 | * IWL_MVM_ROC_TE_TYPE can have lower priority than other events |
496 | * that are being scheduled by the driver/fw, and thus it might not be | 464 | * that are being scheduled by the driver/fw, and thus it might not be |
497 | * scheduled. To improve the chances of it being scheduled, allow it to | 465 | * scheduled. To improve the chances of it being scheduled, allow it to |
498 | * be fragmented. | 466 | * be fragmented. |
@@ -505,33 +473,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | |||
505 | time_cmd.repeat = cpu_to_le32(1); | 473 | time_cmd.repeat = cpu_to_le32(1); |
506 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); | 474 | time_cmd.notify = cpu_to_le32(TE_NOTIF_HOST_START | TE_NOTIF_HOST_END); |
507 | 475 | ||
508 | /* Push the te data to the tracked te list */ | 476 | return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd); |
509 | te_data->vif = vif; | ||
510 | te_data->duration = MSEC_TO_TU(duration); | ||
511 | |||
512 | spin_lock_bh(&mvm->time_event_lock); | ||
513 | te_data->id = le32_to_cpu(time_cmd.id); | ||
514 | list_add_tail(&te_data->list, &mvm->time_event_list); | ||
515 | spin_unlock_bh(&mvm->time_event_lock); | ||
516 | |||
517 | ret = iwl_mvm_send_cmd_pdu(mvm, TIME_EVENT_CMD, CMD_SYNC, | ||
518 | sizeof(time_cmd), &time_cmd); | ||
519 | if (ret) { | ||
520 | IWL_ERR(mvm, "Couldn't send TIME_EVENT_CMD: %d\n", ret); | ||
521 | goto out_remove_notif; | ||
522 | } | ||
523 | |||
524 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1 * HZ); | ||
525 | if (ret) { | ||
526 | IWL_ERR(mvm, "%s - failed on timeout\n", __func__); | ||
527 | iwl_mvm_te_clear_data(mvm, te_data); | ||
528 | } | ||
529 | |||
530 | return ret; | ||
531 | |||
532 | out_remove_notif: | ||
533 | iwl_remove_notification(&mvm->notif_wait, &wait_time_event); | ||
534 | return ret; | ||
535 | } | 477 | } |
536 | 478 | ||
537 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) | 479 | void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index cada8efe0cca..6b67ce3f679c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c | |||
@@ -620,7 +620,7 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
620 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); | 620 | seq_ctl = le16_to_cpu(hdr->seq_ctrl); |
621 | } | 621 | } |
622 | 622 | ||
623 | ieee80211_tx_status(mvm->hw, skb); | 623 | ieee80211_tx_status_ni(mvm->hw, skb); |
624 | } | 624 | } |
625 | 625 | ||
626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { | 626 | if (txq_id >= IWL_FIRST_AMPDU_QUEUE) { |
@@ -663,12 +663,12 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, | |||
663 | struct iwl_mvm_tid_data *tid_data = | 663 | struct iwl_mvm_tid_data *tid_data = |
664 | &mvmsta->tid_data[tid]; | 664 | &mvmsta->tid_data[tid]; |
665 | 665 | ||
666 | spin_lock(&mvmsta->lock); | 666 | spin_lock_bh(&mvmsta->lock); |
667 | tid_data->next_reclaimed = next_reclaimed; | 667 | tid_data->next_reclaimed = next_reclaimed; |
668 | IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", | 668 | IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", |
669 | next_reclaimed); | 669 | next_reclaimed); |
670 | iwl_mvm_check_ratid_empty(mvm, sta, tid); | 670 | iwl_mvm_check_ratid_empty(mvm, sta, tid); |
671 | spin_unlock(&mvmsta->lock); | 671 | spin_unlock_bh(&mvmsta->lock); |
672 | } | 672 | } |
673 | 673 | ||
674 | #ifdef CONFIG_PM_SLEEP | 674 | #ifdef CONFIG_PM_SLEEP |
@@ -832,7 +832,7 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
832 | return 0; | 832 | return 0; |
833 | } | 833 | } |
834 | 834 | ||
835 | spin_lock(&mvmsta->lock); | 835 | spin_lock_bh(&mvmsta->lock); |
836 | 836 | ||
837 | __skb_queue_head_init(&reclaimed_skbs); | 837 | __skb_queue_head_init(&reclaimed_skbs); |
838 | 838 | ||
@@ -886,13 +886,13 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, | |||
886 | } | 886 | } |
887 | } | 887 | } |
888 | 888 | ||
889 | spin_unlock(&mvmsta->lock); | 889 | spin_unlock_bh(&mvmsta->lock); |
890 | 890 | ||
891 | rcu_read_unlock(); | 891 | rcu_read_unlock(); |
892 | 892 | ||
893 | while (!skb_queue_empty(&reclaimed_skbs)) { | 893 | while (!skb_queue_empty(&reclaimed_skbs)) { |
894 | skb = __skb_dequeue(&reclaimed_skbs); | 894 | skb = __skb_dequeue(&reclaimed_skbs); |
895 | ieee80211_tx_status(mvm->hw, skb); | 895 | ieee80211_tx_status_ni(mvm->hw, skb); |
896 | } | 896 | } |
897 | 897 | ||
898 | return 0; | 898 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 5f6bb4e09d42..aa2a39a637dd 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h | |||
@@ -249,7 +249,6 @@ struct iwl_trans_pcie { | |||
249 | int ict_index; | 249 | int ict_index; |
250 | u32 inta; | 250 | u32 inta; |
251 | bool use_ict; | 251 | bool use_ict; |
252 | struct tasklet_struct irq_tasklet; | ||
253 | struct isr_statistics isr_stats; | 252 | struct isr_statistics isr_stats; |
254 | 253 | ||
255 | spinlock_t irq_lock; | 254 | spinlock_t irq_lock; |
@@ -330,7 +329,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); | |||
330 | * RX | 329 | * RX |
331 | ******************************************************/ | 330 | ******************************************************/ |
332 | int iwl_pcie_rx_init(struct iwl_trans *trans); | 331 | int iwl_pcie_rx_init(struct iwl_trans *trans); |
333 | void iwl_pcie_tasklet(struct iwl_trans *trans); | 332 | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id); |
334 | int iwl_pcie_rx_stop(struct iwl_trans *trans); | 333 | int iwl_pcie_rx_stop(struct iwl_trans *trans); |
335 | void iwl_pcie_rx_free(struct iwl_trans *trans); | 334 | void iwl_pcie_rx_free(struct iwl_trans *trans); |
336 | 335 | ||
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a9ca1d35fa93..b0ae06d2456f 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c | |||
@@ -81,10 +81,10 @@ | |||
81 | * 'processed' and 'read' driver indexes as well) | 81 | * 'processed' and 'read' driver indexes as well) |
82 | * + A received packet is processed and handed to the kernel network stack, | 82 | * + A received packet is processed and handed to the kernel network stack, |
83 | * detached from the iwl->rxq. The driver 'processed' index is updated. | 83 | * detached from the iwl->rxq. The driver 'processed' index is updated. |
84 | * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free | 84 | * + The Host/Firmware iwl->rxq is replenished at irq thread time from the |
85 | * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ | 85 | * rx_free list. If there are no allocated buffers in iwl->rxq->rx_free, |
86 | * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there | 86 | * the READ INDEX is not incremented and iwl->status(RX_STALLED) is set. |
87 | * were enough free buffers and RX_STALLED is set it is cleared. | 87 | * If there were enough free buffers and RX_STALLED is set it is cleared. |
88 | * | 88 | * |
89 | * | 89 | * |
90 | * Driver sequence: | 90 | * Driver sequence: |
@@ -214,9 +214,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) | |||
214 | /* | 214 | /* |
215 | * If the device isn't enabled - not need to try to add buffers... | 215 | * If the device isn't enabled - not need to try to add buffers... |
216 | * This can happen when we stop the device and still have an interrupt | 216 | * This can happen when we stop the device and still have an interrupt |
217 | * pending. We stop the APM before we sync the interrupts / tasklets | 217 | * pending. We stop the APM before we sync the interrupts because we |
218 | * because we have to (see comment there). On the other hand, since | 218 | * have to (see comment there). On the other hand, since the APM is |
219 | * the APM is stopped, we cannot access the HW (in particular not prph). | 219 | * stopped, we cannot access the HW (in particular not prph). |
220 | * So don't try to restock if the APM has been already stopped. | 220 | * So don't try to restock if the APM has been already stopped. |
221 | */ | 221 | */ |
222 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) | 222 | if (!test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) |
@@ -796,11 +796,14 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) | |||
796 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); | 796 | clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status); |
797 | wake_up(&trans_pcie->wait_command_queue); | 797 | wake_up(&trans_pcie->wait_command_queue); |
798 | 798 | ||
799 | local_bh_disable(); | ||
799 | iwl_op_mode_nic_error(trans->op_mode); | 800 | iwl_op_mode_nic_error(trans->op_mode); |
801 | local_bh_enable(); | ||
800 | } | 802 | } |
801 | 803 | ||
802 | void iwl_pcie_tasklet(struct iwl_trans *trans) | 804 | irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) |
803 | { | 805 | { |
806 | struct iwl_trans *trans = dev_id; | ||
804 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 807 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
805 | struct isr_statistics *isr_stats = &trans_pcie->isr_stats; | 808 | struct isr_statistics *isr_stats = &trans_pcie->isr_stats; |
806 | u32 inta = 0; | 809 | u32 inta = 0; |
@@ -811,6 +814,8 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
811 | u32 inta_mask; | 814 | u32 inta_mask; |
812 | #endif | 815 | #endif |
813 | 816 | ||
817 | lock_map_acquire(&trans->sync_cmd_lockdep_map); | ||
818 | |||
814 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); | 819 | spin_lock_irqsave(&trans_pcie->irq_lock, flags); |
815 | 820 | ||
816 | /* Ack/clear/reset pending uCode interrupts. | 821 | /* Ack/clear/reset pending uCode interrupts. |
@@ -855,7 +860,7 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
855 | 860 | ||
856 | handled |= CSR_INT_BIT_HW_ERR; | 861 | handled |= CSR_INT_BIT_HW_ERR; |
857 | 862 | ||
858 | return; | 863 | goto out; |
859 | } | 864 | } |
860 | 865 | ||
861 | #ifdef CONFIG_IWLWIFI_DEBUG | 866 | #ifdef CONFIG_IWLWIFI_DEBUG |
@@ -1005,6 +1010,10 @@ void iwl_pcie_tasklet(struct iwl_trans *trans) | |||
1005 | /* Re-enable RF_KILL if it occurred */ | 1010 | /* Re-enable RF_KILL if it occurred */ |
1006 | else if (handled & CSR_INT_BIT_RF_KILL) | 1011 | else if (handled & CSR_INT_BIT_RF_KILL) |
1007 | iwl_enable_rfkill_int(trans); | 1012 | iwl_enable_rfkill_int(trans); |
1013 | |||
1014 | out: | ||
1015 | lock_map_release(&trans->sync_cmd_lockdep_map); | ||
1016 | return IRQ_HANDLED; | ||
1008 | } | 1017 | } |
1009 | 1018 | ||
1010 | /****************************************************************************** | 1019 | /****************************************************************************** |
@@ -1127,7 +1136,7 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1127 | 1136 | ||
1128 | /* Disable (but don't clear!) interrupts here to avoid | 1137 | /* Disable (but don't clear!) interrupts here to avoid |
1129 | * back-to-back ISRs and sporadic interrupts from our NIC. | 1138 | * back-to-back ISRs and sporadic interrupts from our NIC. |
1130 | * If we have something to service, the tasklet will re-enable ints. | 1139 | * If we have something to service, the irq thread will re-enable ints. |
1131 | * If we *don't* have something, we'll re-enable before leaving here. */ | 1140 | * If we *don't* have something, we'll re-enable before leaving here. */ |
1132 | inta_mask = iwl_read32(trans, CSR_INT_MASK); | 1141 | inta_mask = iwl_read32(trans, CSR_INT_MASK); |
1133 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); | 1142 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); |
@@ -1167,9 +1176,9 @@ static irqreturn_t iwl_pcie_isr(int irq, void *data) | |||
1167 | #endif | 1176 | #endif |
1168 | 1177 | ||
1169 | trans_pcie->inta |= inta; | 1178 | trans_pcie->inta |= inta; |
1170 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 1179 | /* the thread will service interrupts and re-enable them */ |
1171 | if (likely(inta)) | 1180 | if (likely(inta)) |
1172 | tasklet_schedule(&trans_pcie->irq_tasklet); | 1181 | return IRQ_WAKE_THREAD; |
1173 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1182 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && |
1174 | !trans_pcie->inta) | 1183 | !trans_pcie->inta) |
1175 | iwl_enable_interrupts(trans); | 1184 | iwl_enable_interrupts(trans); |
@@ -1277,9 +1286,10 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) | |||
1277 | trans_pcie->inta |= inta; | 1286 | trans_pcie->inta |= inta; |
1278 | 1287 | ||
1279 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ | 1288 | /* iwl_pcie_tasklet() will service interrupts and re-enable them */ |
1280 | if (likely(inta)) | 1289 | if (likely(inta)) { |
1281 | tasklet_schedule(&trans_pcie->irq_tasklet); | 1290 | spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); |
1282 | else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | 1291 | return IRQ_WAKE_THREAD; |
1292 | } else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) && | ||
1283 | !trans_pcie->inta) { | 1293 | !trans_pcie->inta) { |
1284 | /* Allow interrupt if was disabled by this handler and | 1294 | /* Allow interrupt if was disabled by this handler and |
1285 | * no tasklet was schedules, We should not enable interrupt, | 1295 | * no tasklet was schedules, We should not enable interrupt, |
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 56d4f72500bc..17bedc50e753 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c | |||
@@ -760,7 +760,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) | |||
760 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 760 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
761 | 761 | ||
762 | synchronize_irq(trans_pcie->pci_dev->irq); | 762 | synchronize_irq(trans_pcie->pci_dev->irq); |
763 | tasklet_kill(&trans_pcie->irq_tasklet); | ||
764 | 763 | ||
765 | iwl_pcie_tx_free(trans); | 764 | iwl_pcie_tx_free(trans); |
766 | iwl_pcie_rx_free(trans); | 765 | iwl_pcie_rx_free(trans); |
@@ -1480,6 +1479,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1480 | 1479 | ||
1481 | trans->ops = &trans_ops_pcie; | 1480 | trans->ops = &trans_ops_pcie; |
1482 | trans->cfg = cfg; | 1481 | trans->cfg = cfg; |
1482 | trans_lockdep_init(trans); | ||
1483 | trans_pcie->trans = trans; | 1483 | trans_pcie->trans = trans; |
1484 | spin_lock_init(&trans_pcie->irq_lock); | 1484 | spin_lock_init(&trans_pcie->irq_lock); |
1485 | spin_lock_init(&trans_pcie->reg_lock); | 1485 | spin_lock_init(&trans_pcie->reg_lock); |
@@ -1567,15 +1567,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, | |||
1567 | 1567 | ||
1568 | trans_pcie->inta_mask = CSR_INI_SET_MASK; | 1568 | trans_pcie->inta_mask = CSR_INI_SET_MASK; |
1569 | 1569 | ||
1570 | tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) | ||
1571 | iwl_pcie_tasklet, (unsigned long)trans); | ||
1572 | |||
1573 | if (iwl_pcie_alloc_ict(trans)) | 1570 | if (iwl_pcie_alloc_ict(trans)) |
1574 | goto out_free_cmd_pool; | 1571 | goto out_free_cmd_pool; |
1575 | 1572 | ||
1576 | err = request_irq(pdev->irq, iwl_pcie_isr_ict, | 1573 | if (request_threaded_irq(pdev->irq, iwl_pcie_isr_ict, |
1577 | IRQF_SHARED, DRV_NAME, trans); | 1574 | iwl_pcie_irq_handler, |
1578 | if (err) { | 1575 | IRQF_SHARED, DRV_NAME, trans)) { |
1579 | IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); | 1576 | IWL_ERR(trans, "Error allocating IRQ %d\n", pdev->irq); |
1580 | goto out_free_ict; | 1577 | goto out_free_ict; |
1581 | } | 1578 | } |
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 041127ad372a..8e9e3212fe78 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -926,7 +926,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
926 | if (WARN_ON(txq_id == trans_pcie->cmd_queue)) | 926 | if (WARN_ON(txq_id == trans_pcie->cmd_queue)) |
927 | return; | 927 | return; |
928 | 928 | ||
929 | spin_lock(&txq->lock); | 929 | spin_lock_bh(&txq->lock); |
930 | 930 | ||
931 | if (txq->q.read_ptr == tfd_num) | 931 | if (txq->q.read_ptr == tfd_num) |
932 | goto out; | 932 | goto out; |
@@ -970,7 +970,7 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
970 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) | 970 | if (iwl_queue_space(&txq->q) > txq->q.low_mark) |
971 | iwl_wake_queue(trans, txq); | 971 | iwl_wake_queue(trans, txq); |
972 | out: | 972 | out: |
973 | spin_unlock(&txq->lock); | 973 | spin_unlock_bh(&txq->lock); |
974 | } | 974 | } |
975 | 975 | ||
976 | /* | 976 | /* |
@@ -1371,7 +1371,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | |||
1371 | return; | 1371 | return; |
1372 | } | 1372 | } |
1373 | 1373 | ||
1374 | spin_lock(&txq->lock); | 1374 | spin_lock_bh(&txq->lock); |
1375 | 1375 | ||
1376 | cmd_index = get_cmd_index(&txq->q, index); | 1376 | cmd_index = get_cmd_index(&txq->q, index); |
1377 | cmd = txq->entries[cmd_index].cmd; | 1377 | cmd = txq->entries[cmd_index].cmd; |
@@ -1405,7 +1405,7 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, | |||
1405 | 1405 | ||
1406 | meta->flags = 0; | 1406 | meta->flags = 0; |
1407 | 1407 | ||
1408 | spin_unlock(&txq->lock); | 1408 | spin_unlock_bh(&txq->lock); |
1409 | } | 1409 | } |
1410 | 1410 | ||
1411 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) | 1411 | #define HOST_COMPLETE_TIMEOUT (2 * HZ) |