aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/mac80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac80211.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c383
1 files changed, 288 insertions, 95 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 2eb6ebee4467..0d6a8b768a68 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -211,7 +211,9 @@ void iwl_mvm_ref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
211 return; 211 return;
212 212
213 IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type); 213 IWL_DEBUG_RPM(mvm, "Take mvm reference - type %d\n", ref_type);
214 WARN_ON(test_and_set_bit(ref_type, mvm->ref_bitmap)); 214 spin_lock_bh(&mvm->refs_lock);
215 mvm->refs[ref_type]++;
216 spin_unlock_bh(&mvm->refs_lock);
215 iwl_trans_ref(mvm->trans); 217 iwl_trans_ref(mvm->trans);
216} 218}
217 219
@@ -221,29 +223,35 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
221 return; 223 return;
222 224
223 IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type); 225 IWL_DEBUG_RPM(mvm, "Leave mvm reference - type %d\n", ref_type);
224 WARN_ON(!test_and_clear_bit(ref_type, mvm->ref_bitmap)); 226 spin_lock_bh(&mvm->refs_lock);
227 WARN_ON(!mvm->refs[ref_type]--);
228 spin_unlock_bh(&mvm->refs_lock);
225 iwl_trans_unref(mvm->trans); 229 iwl_trans_unref(mvm->trans);
226} 230}
227 231
228static void 232static void iwl_mvm_unref_all_except(struct iwl_mvm *mvm,
229iwl_mvm_unref_all_except(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref) 233 enum iwl_mvm_ref_type except_ref)
230{ 234{
231 int i; 235 int i, j;
232 236
233 if (!iwl_mvm_is_d0i3_supported(mvm)) 237 if (!iwl_mvm_is_d0i3_supported(mvm))
234 return; 238 return;
235 239
236 for_each_set_bit(i, mvm->ref_bitmap, IWL_MVM_REF_COUNT) { 240 spin_lock_bh(&mvm->refs_lock);
237 if (ref == i) 241 for (i = 0; i < IWL_MVM_REF_COUNT; i++) {
242 if (except_ref == i || !mvm->refs[i])
238 continue; 243 continue;
239 244
240 IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d\n", i); 245 IWL_DEBUG_RPM(mvm, "Cleanup: remove mvm ref type %d (%d)\n",
241 clear_bit(i, mvm->ref_bitmap); 246 i, mvm->refs[i]);
242 iwl_trans_unref(mvm->trans); 247 for (j = 0; j < mvm->refs[i]; j++)
248 iwl_trans_unref(mvm->trans);
249 mvm->refs[i] = 0;
243 } 250 }
251 spin_unlock_bh(&mvm->refs_lock);
244} 252}
245 253
246static int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type) 254int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type)
247{ 255{
248 iwl_mvm_ref(mvm, ref_type); 256 iwl_mvm_ref(mvm, ref_type);
249 257
@@ -321,13 +329,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
321 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; 329 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
322 } 330 }
323 331
324 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT &&
325 !iwlwifi_mod_params.uapsd_disable) {
326 hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
327 hw->uapsd_queues = IWL_UAPSD_AC_INFO;
328 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
329 }
330
331 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) 332 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
332 hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; 333 hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
333 334
@@ -660,6 +661,7 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
660 spin_unlock_bh(&mvm->time_event_lock); 661 spin_unlock_bh(&mvm->time_event_lock);
661 662
662 mvmvif->phy_ctxt = NULL; 663 mvmvif->phy_ctxt = NULL;
664 memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));
663} 665}
664 666
665#ifdef CONFIG_IWLWIFI_DEBUGFS 667#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -668,11 +670,11 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
668 struct iwl_fw_error_dump_file *dump_file; 670 struct iwl_fw_error_dump_file *dump_file;
669 struct iwl_fw_error_dump_data *dump_data; 671 struct iwl_fw_error_dump_data *dump_data;
670 struct iwl_fw_error_dump_info *dump_info; 672 struct iwl_fw_error_dump_info *dump_info;
673 struct iwl_mvm_dump_ptrs *fw_error_dump;
671 const struct fw_img *img; 674 const struct fw_img *img;
672 u32 sram_len, sram_ofs; 675 u32 sram_len, sram_ofs;
673 u32 file_len, rxf_len; 676 u32 file_len, rxf_len;
674 unsigned long flags; 677 unsigned long flags;
675 u32 trans_len;
676 int reg_val; 678 int reg_val;
677 679
678 lockdep_assert_held(&mvm->mutex); 680 lockdep_assert_held(&mvm->mutex);
@@ -680,6 +682,10 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
680 if (mvm->fw_error_dump) 682 if (mvm->fw_error_dump)
681 return; 683 return;
682 684
685 fw_error_dump = kzalloc(sizeof(*mvm->fw_error_dump), GFP_KERNEL);
686 if (!fw_error_dump)
687 return;
688
683 img = &mvm->fw->img[mvm->cur_ucode]; 689 img = &mvm->fw->img[mvm->cur_ucode];
684 sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; 690 sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
685 sram_len = img->sec[IWL_UCODE_SECTION_DATA].len; 691 sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
@@ -697,18 +703,15 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
697 rxf_len + 703 rxf_len +
698 sizeof(*dump_info); 704 sizeof(*dump_info);
699 705
700 trans_len = iwl_trans_dump_data(mvm->trans, NULL, 0);
701 if (trans_len)
702 file_len += trans_len;
703
704 dump_file = vzalloc(file_len); 706 dump_file = vzalloc(file_len);
705 if (!dump_file) 707 if (!dump_file) {
708 kfree(fw_error_dump);
706 return; 709 return;
710 }
707 711
708 mvm->fw_error_dump = dump_file; 712 fw_error_dump->op_mode_ptr = dump_file;
709 713
710 dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER); 714 dump_file->barker = cpu_to_le32(IWL_FW_ERROR_DUMP_BARKER);
711 dump_file->file_len = cpu_to_le32(file_len);
712 dump_data = (void *)dump_file->data; 715 dump_data = (void *)dump_file->data;
713 716
714 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO); 717 dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_DEV_FW_INFO);
@@ -749,14 +752,12 @@ static void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
749 iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data, 752 iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data,
750 sram_len); 753 sram_len);
751 754
752 if (trans_len) { 755 fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans);
753 void *buf = iwl_fw_error_next_data(dump_data); 756 fw_error_dump->op_mode_len = file_len;
754 u32 real_trans_len = iwl_trans_dump_data(mvm->trans, buf, 757 if (fw_error_dump->trans_ptr)
755 trans_len); 758 file_len += fw_error_dump->trans_ptr->len;
756 dump_data = (void *)((u8 *)buf + real_trans_len); 759 dump_file->file_len = cpu_to_le32(file_len);
757 dump_file->file_len = 760 mvm->fw_error_dump = fw_error_dump;
758 cpu_to_le32(file_len - trans_len + real_trans_len);
759 }
760} 761}
761#endif 762#endif
762 763
@@ -788,6 +789,12 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
788 iwl_mvm_reset_phy_ctxts(mvm); 789 iwl_mvm_reset_phy_ctxts(mvm);
789 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); 790 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
790 memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); 791 memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
792 memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
793 memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
794 memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
795 memset(&mvm->last_bt_ci_cmd_old, 0, sizeof(mvm->last_bt_ci_cmd_old));
796 memset(&mvm->bt_ack_kill_msk, 0, sizeof(mvm->bt_ack_kill_msk));
797 memset(&mvm->bt_cts_kill_msk, 0, sizeof(mvm->bt_cts_kill_msk));
791 798
792 ieee80211_wake_queues(mvm->hw); 799 ieee80211_wake_queues(mvm->hw);
793 800
@@ -1399,6 +1406,28 @@ static inline int iwl_mvm_configure_bcast_filter(struct iwl_mvm *mvm,
1399} 1406}
1400#endif 1407#endif
1401 1408
1409static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
1410{
1411 struct ieee80211_sta *sta;
1412 struct iwl_mvm_sta *mvmsta;
1413 int i;
1414
1415 lockdep_assert_held(&mvm->mutex);
1416
1417 for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
1418 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
1419 lockdep_is_held(&mvm->mutex));
1420 if (!sta || IS_ERR(sta) || !sta->tdls)
1421 continue;
1422
1423 mvmsta = iwl_mvm_sta_from_mac80211(sta);
1424 ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
1425 NL80211_TDLS_TEARDOWN,
1426 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
1427 GFP_KERNEL);
1428 }
1429}
1430
1402static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, 1431static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
1403 struct ieee80211_vif *vif, 1432 struct ieee80211_vif *vif,
1404 struct ieee80211_bss_conf *bss_conf, 1433 struct ieee80211_bss_conf *bss_conf,
@@ -1494,14 +1523,18 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
1494 */ 1523 */
1495 iwl_mvm_remove_time_event(mvm, mvmvif, 1524 iwl_mvm_remove_time_event(mvm, mvmvif,
1496 &mvmvif->time_event_data); 1525 &mvmvif->time_event_data);
1497 iwl_mvm_sf_update(mvm, vif, false);
1498 WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
1499 } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | 1526 } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS |
1500 BSS_CHANGED_QOS)) { 1527 BSS_CHANGED_QOS)) {
1501 ret = iwl_mvm_power_update_mac(mvm); 1528 ret = iwl_mvm_power_update_mac(mvm);
1502 if (ret) 1529 if (ret)
1503 IWL_ERR(mvm, "failed to update power mode\n"); 1530 IWL_ERR(mvm, "failed to update power mode\n");
1504 } 1531 }
1532
1533 if (changes & BSS_CHANGED_BEACON_INFO) {
1534 iwl_mvm_sf_update(mvm, vif, false);
1535 WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
1536 }
1537
1505 if (changes & BSS_CHANGED_TXPOWER) { 1538 if (changes & BSS_CHANGED_TXPOWER) {
1506 IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n", 1539 IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d\n",
1507 bss_conf->txpower); 1540 bss_conf->txpower);
@@ -1533,6 +1566,14 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
1533 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1566 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1534 int ret; 1567 int ret;
1535 1568
1569 /*
1570 * iwl_mvm_mac_ctxt_add() might read directly from the device
1571 * (the system time), so make sure it is available.
1572 */
1573 ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_START_AP);
1574 if (ret)
1575 return ret;
1576
1536 mutex_lock(&mvm->mutex); 1577 mutex_lock(&mvm->mutex);
1537 1578
1538 /* Send the beacon template */ 1579 /* Send the beacon template */
@@ -1581,6 +1622,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
1581 1622
1582 iwl_mvm_bt_coex_vif_change(mvm); 1623 iwl_mvm_bt_coex_vif_change(mvm);
1583 1624
1625 /* we don't support TDLS during DCM */
1626 if (iwl_mvm_phy_ctx_count(mvm) > 1)
1627 iwl_mvm_teardown_tdls_peers(mvm);
1628
1584 mutex_unlock(&mvm->mutex); 1629 mutex_unlock(&mvm->mutex);
1585 return 0; 1630 return 0;
1586 1631
@@ -1594,6 +1639,7 @@ out_remove:
1594 iwl_mvm_mac_ctxt_remove(mvm, vif); 1639 iwl_mvm_mac_ctxt_remove(mvm, vif);
1595out_unlock: 1640out_unlock:
1596 mutex_unlock(&mvm->mutex); 1641 mutex_unlock(&mvm->mutex);
1642 iwl_mvm_unref(mvm, IWL_MVM_REF_START_AP);
1597 return ret; 1643 return ret;
1598} 1644}
1599 1645
@@ -1671,6 +1717,14 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
1671{ 1717{
1672 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1718 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1673 1719
1720 /*
1721 * iwl_mvm_bss_info_changed_station() might call
1722 * iwl_mvm_protect_session(), which reads directly from
1723 * the device (the system time), so make sure it is available.
1724 */
1725 if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_BSS_CHANGED))
1726 return;
1727
1674 mutex_lock(&mvm->mutex); 1728 mutex_lock(&mvm->mutex);
1675 1729
1676 if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) 1730 if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
@@ -1690,8 +1744,50 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
1690 } 1744 }
1691 1745
1692 mutex_unlock(&mvm->mutex); 1746 mutex_unlock(&mvm->mutex);
1747 iwl_mvm_unref(mvm, IWL_MVM_REF_BSS_CHANGED);
1693} 1748}
1694 1749
1750static int iwl_mvm_cancel_scan_wait_notif(struct iwl_mvm *mvm,
1751 enum iwl_scan_status scan_type)
1752{
1753 int ret;
1754 bool wait_for_handlers = false;
1755
1756 mutex_lock(&mvm->mutex);
1757
1758 if (mvm->scan_status != scan_type) {
1759 ret = 0;
1760 /* make sure there are no pending notifications */
1761 wait_for_handlers = true;
1762 goto out;
1763 }
1764
1765 switch (scan_type) {
1766 case IWL_MVM_SCAN_SCHED:
1767 ret = iwl_mvm_scan_offload_stop(mvm, true);
1768 break;
1769 case IWL_MVM_SCAN_OS:
1770 ret = iwl_mvm_cancel_scan(mvm);
1771 break;
1772 case IWL_MVM_SCAN_NONE:
1773 default:
1774 WARN_ON_ONCE(1);
1775 ret = -EINVAL;
1776 break;
1777 }
1778 if (ret)
1779 goto out;
1780
1781 wait_for_handlers = true;
1782out:
1783 mutex_unlock(&mvm->mutex);
1784
1785 /* make sure we consume the completion notification */
1786 if (wait_for_handlers)
1787 iwl_mvm_wait_for_async_handlers(mvm);
1788
1789 return ret;
1790}
1695static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, 1791static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
1696 struct ieee80211_vif *vif, 1792 struct ieee80211_vif *vif,
1697 struct ieee80211_scan_request *hw_req) 1793 struct ieee80211_scan_request *hw_req)
@@ -1704,19 +1800,13 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
1704 req->n_channels > mvm->fw->ucode_capa.n_scan_channels) 1800 req->n_channels > mvm->fw->ucode_capa.n_scan_channels)
1705 return -EINVAL; 1801 return -EINVAL;
1706 1802
1803 ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED);
1804 if (ret)
1805 return ret;
1806
1707 mutex_lock(&mvm->mutex); 1807 mutex_lock(&mvm->mutex);
1708 1808
1709 switch (mvm->scan_status) { 1809 if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
1710 case IWL_MVM_SCAN_SCHED:
1711 ret = iwl_mvm_scan_offload_stop(mvm, true);
1712 if (ret) {
1713 ret = -EBUSY;
1714 goto out;
1715 }
1716 break;
1717 case IWL_MVM_SCAN_NONE:
1718 break;
1719 default:
1720 ret = -EBUSY; 1810 ret = -EBUSY;
1721 goto out; 1811 goto out;
1722 } 1812 }
@@ -1732,8 +1822,6 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
1732 iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); 1822 iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
1733out: 1823out:
1734 mutex_unlock(&mvm->mutex); 1824 mutex_unlock(&mvm->mutex);
1735 /* make sure to flush the Rx handler before the next scan arrives */
1736 iwl_mvm_wait_for_async_handlers(mvm);
1737 return ret; 1825 return ret;
1738} 1826}
1739 1827
@@ -1885,28 +1973,6 @@ static void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm,
1885 iwl_mvm_power_update_mac(mvm); 1973 iwl_mvm_power_update_mac(mvm);
1886} 1974}
1887 1975
1888static void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)
1889{
1890 struct ieee80211_sta *sta;
1891 struct iwl_mvm_sta *mvmsta;
1892 int i;
1893
1894 lockdep_assert_held(&mvm->mutex);
1895
1896 for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
1897 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
1898 lockdep_is_held(&mvm->mutex));
1899 if (!sta || IS_ERR(sta) || !sta->tdls)
1900 continue;
1901
1902 mvmsta = iwl_mvm_sta_from_mac80211(sta);
1903 ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,
1904 NL80211_TDLS_TEARDOWN,
1905 WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,
1906 GFP_KERNEL);
1907 }
1908}
1909
1910static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw, 1976static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
1911 struct ieee80211_vif *vif, 1977 struct ieee80211_vif *vif,
1912 struct ieee80211_sta *sta, 1978 struct ieee80211_sta *sta,
@@ -2065,10 +2131,19 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
2065 if (WARN_ON_ONCE(vif->bss_conf.assoc)) 2131 if (WARN_ON_ONCE(vif->bss_conf.assoc))
2066 return; 2132 return;
2067 2133
2134 /*
2135 * iwl_mvm_protect_session() reads directly from the device
2136 * (the system time), so make sure it is available.
2137 */
2138 if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PREPARE_TX))
2139 return;
2140
2068 mutex_lock(&mvm->mutex); 2141 mutex_lock(&mvm->mutex);
2069 /* Try really hard to protect the session and hear a beacon */ 2142 /* Try really hard to protect the session and hear a beacon */
2070 iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500); 2143 iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
2071 mutex_unlock(&mvm->mutex); 2144 mutex_unlock(&mvm->mutex);
2145
2146 iwl_mvm_unref(mvm, IWL_MVM_REF_PREPARE_TX);
2072} 2147}
2073 2148
2074static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw, 2149static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
@@ -2077,10 +2152,19 @@ static void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
2077 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 2152 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2078 u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int; 2153 u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;
2079 2154
2155 /*
2156 * iwl_mvm_protect_session() reads directly from the device
2157 * (the system time), so make sure it is available.
2158 */
2159 if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PROTECT_TDLS))
2160 return;
2161
2080 mutex_lock(&mvm->mutex); 2162 mutex_lock(&mvm->mutex);
2081 /* Protect the session to hear the TDLS setup response on the channel */ 2163 /* Protect the session to hear the TDLS setup response on the channel */
2082 iwl_mvm_protect_session(mvm, vif, duration, duration, 100); 2164 iwl_mvm_protect_session(mvm, vif, duration, duration, 100);
2083 mutex_unlock(&mvm->mutex); 2165 mutex_unlock(&mvm->mutex);
2166
2167 iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_TDLS);
2084} 2168}
2085 2169
2086static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, 2170static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
@@ -2091,6 +2175,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
2091 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 2175 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2092 int ret; 2176 int ret;
2093 2177
2178 ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS);
2179 if (ret)
2180 return ret;
2181
2094 mutex_lock(&mvm->mutex); 2182 mutex_lock(&mvm->mutex);
2095 2183
2096 if (!iwl_mvm_is_idle(mvm)) { 2184 if (!iwl_mvm_is_idle(mvm)) {
@@ -2098,26 +2186,7 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
2098 goto out; 2186 goto out;
2099 } 2187 }
2100 2188
2101 switch (mvm->scan_status) { 2189 if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
2102 case IWL_MVM_SCAN_OS:
2103 IWL_DEBUG_SCAN(mvm, "Stopping previous scan for sched_scan\n");
2104 ret = iwl_mvm_cancel_scan(mvm);
2105 if (ret) {
2106 ret = -EBUSY;
2107 goto out;
2108 }
2109
2110 /*
2111 * iwl_mvm_rx_scan_complete() will be called soon but will
2112 * not reset the scan status as it won't be IWL_MVM_SCAN_OS
2113 * any more since we queue the next scan immediately (below).
2114 * We make sure it is called before the next scan starts by
2115 * flushing the async-handlers work.
2116 */
2117 break;
2118 case IWL_MVM_SCAN_NONE:
2119 break;
2120 default:
2121 ret = -EBUSY; 2190 ret = -EBUSY;
2122 goto out; 2191 goto out;
2123 } 2192 }
@@ -2145,8 +2214,6 @@ err:
2145 mvm->scan_status = IWL_MVM_SCAN_NONE; 2214 mvm->scan_status = IWL_MVM_SCAN_NONE;
2146out: 2215out:
2147 mutex_unlock(&mvm->mutex); 2216 mutex_unlock(&mvm->mutex);
2148 /* make sure to flush the Rx handler before the next scan arrives */
2149 iwl_mvm_wait_for_async_handlers(mvm);
2150 return ret; 2217 return ret;
2151} 2218}
2152 2219
@@ -2266,6 +2333,119 @@ static void iwl_mvm_mac_update_tkip_key(struct ieee80211_hw *hw,
2266} 2333}
2267 2334
2268 2335
2336static bool iwl_mvm_rx_aux_roc(struct iwl_notif_wait_data *notif_wait,
2337 struct iwl_rx_packet *pkt, void *data)
2338{
2339 struct iwl_mvm *mvm =
2340 container_of(notif_wait, struct iwl_mvm, notif_wait);
2341 struct iwl_hs20_roc_res *resp;
2342 int resp_len = iwl_rx_packet_payload_len(pkt);
2343 struct iwl_mvm_time_event_data *te_data = data;
2344
2345 if (WARN_ON(pkt->hdr.cmd != HOT_SPOT_CMD))
2346 return true;
2347
2348 if (WARN_ON_ONCE(resp_len != sizeof(*resp))) {
2349 IWL_ERR(mvm, "Invalid HOT_SPOT_CMD response\n");
2350 return true;
2351 }
2352
2353 resp = (void *)pkt->data;
2354
2355 IWL_DEBUG_TE(mvm,
2356 "Aux ROC: Recieved response from ucode: status=%d uid=%d\n",
2357 resp->status, resp->event_unique_id);
2358
2359 te_data->uid = le32_to_cpu(resp->event_unique_id);
2360 IWL_DEBUG_TE(mvm, "TIME_EVENT_CMD response - UID = 0x%x\n",
2361 te_data->uid);
2362
2363 spin_lock_bh(&mvm->time_event_lock);
2364 list_add_tail(&te_data->list, &mvm->aux_roc_te_list);
2365 spin_unlock_bh(&mvm->time_event_lock);
2366
2367 return true;
2368}
2369
2370#define AUX_ROC_MAX_DELAY_ON_CHANNEL 5000
2371static int iwl_mvm_send_aux_roc_cmd(struct iwl_mvm *mvm,
2372 struct ieee80211_channel *channel,
2373 struct ieee80211_vif *vif,
2374 int duration)
2375{
2376 int res, time_reg = DEVICE_SYSTEM_TIME_REG;
2377 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
2378 struct iwl_mvm_time_event_data *te_data = &mvmvif->hs_time_event_data;
2379 static const u8 time_event_response[] = { HOT_SPOT_CMD };
2380 struct iwl_notification_wait wait_time_event;
2381 struct iwl_hs20_roc_req aux_roc_req = {
2382 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
2383 .id_and_color =
2384 cpu_to_le32(FW_CMD_ID_AND_COLOR(MAC_INDEX_AUX, 0)),
2385 .sta_id_and_color = cpu_to_le32(mvm->aux_sta.sta_id),
2386 /* Set the channel info data */
2387 .channel_info.band = (channel->band == IEEE80211_BAND_2GHZ) ?
2388 PHY_BAND_24 : PHY_BAND_5,
2389 .channel_info.channel = channel->hw_value,
2390 .channel_info.width = PHY_VHT_CHANNEL_MODE20,
2391 /* Set the time and duration */
2392 .apply_time = cpu_to_le32(iwl_read_prph(mvm->trans, time_reg)),
2393 .apply_time_max_delay =
2394 cpu_to_le32(MSEC_TO_TU(AUX_ROC_MAX_DELAY_ON_CHANNEL)),
2395 .duration = cpu_to_le32(MSEC_TO_TU(duration)),
2396 };
2397
2398 /* Set the node address */
2399 memcpy(aux_roc_req.node_addr, vif->addr, ETH_ALEN);
2400
2401 te_data->vif = vif;
2402 te_data->duration = duration;
2403 te_data->id = HOT_SPOT_CMD;
2404
2405 lockdep_assert_held(&mvm->mutex);
2406
2407 spin_lock_bh(&mvm->time_event_lock);
2408 list_add_tail(&te_data->list, &mvm->time_event_list);
2409 spin_unlock_bh(&mvm->time_event_lock);
2410
2411 /*
2412 * Use a notification wait, which really just processes the
2413 * command response and doesn't wait for anything, in order
2414 * to be able to process the response and get the UID inside
2415 * the RX path. Using CMD_WANT_SKB doesn't work because it
2416 * stores the buffer and then wakes up this thread, by which
2417 * time another notification (that the time event started)
2418 * might already be processed unsuccessfully.
2419 */
2420 iwl_init_notification_wait(&mvm->notif_wait, &wait_time_event,
2421 time_event_response,
2422 ARRAY_SIZE(time_event_response),
2423 iwl_mvm_rx_aux_roc, te_data);
2424
2425 res = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0, sizeof(aux_roc_req),
2426 &aux_roc_req);
2427
2428 if (res) {
2429 IWL_ERR(mvm, "Couldn't send HOT_SPOT_CMD: %d\n", res);
2430 iwl_remove_notification(&mvm->notif_wait, &wait_time_event);
2431 goto out_clear_te;
2432 }
2433
2434 /* No need to wait for anything, so just pass 1 (0 isn't valid) */
2435 res = iwl_wait_notification(&mvm->notif_wait, &wait_time_event, 1);
2436 /* should never fail */
2437 WARN_ON_ONCE(res);
2438
2439 if (res) {
2440 out_clear_te:
2441 spin_lock_bh(&mvm->time_event_lock);
2442 iwl_mvm_te_clear_data(mvm, te_data);
2443 spin_unlock_bh(&mvm->time_event_lock);
2444 }
2445
2446 return res;
2447}
2448
2269static int iwl_mvm_roc(struct ieee80211_hw *hw, 2449static int iwl_mvm_roc(struct ieee80211_hw *hw,
2270 struct ieee80211_vif *vif, 2450 struct ieee80211_vif *vif,
2271 struct ieee80211_channel *channel, 2451 struct ieee80211_channel *channel,
@@ -2281,8 +2461,17 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
2281 IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, 2461 IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value,
2282 duration, type); 2462 duration, type);
2283 2463
2284 if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { 2464 switch (vif->type) {
2285 IWL_ERR(mvm, "vif isn't a P2P_DEVICE: %d\n", vif->type); 2465 case NL80211_IFTYPE_STATION:
2466 /* Use aux roc framework (HS20) */
2467 ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
2468 vif, duration);
2469 return ret;
2470 case NL80211_IFTYPE_P2P_DEVICE:
2471 /* handle below */
2472 break;
2473 default:
2474 IWL_ERR(mvm, "vif isn't P2P_DEVICE: %d\n", vif->type);
2286 return -EINVAL; 2475 return -EINVAL;
2287 } 2476 }
2288 2477
@@ -2661,6 +2850,10 @@ static int iwl_mvm_switch_vif_chanctx(struct ieee80211_hw *hw,
2661 goto out_remove; 2850 goto out_remove;
2662 } 2851 }
2663 2852
2853 /* we don't support TDLS during DCM - can be caused by channel switch */
2854 if (iwl_mvm_phy_ctx_count(mvm) > 1)
2855 iwl_mvm_teardown_tdls_peers(mvm);
2856
2664 goto out; 2857 goto out;
2665 2858
2666out_remove: 2859out_remove: