Johannes Berg says: ==================== More fixes: - ath12k - avoid busy-waiting - activate correct number of links - iwlwifi - iwldvm regression (lots of warnings) - iwlmld merge damage regression (crash) - fix build with some old gcc versions - carl9170: don't talk to device w/o FW [syzbot] - ath6kl: remove bad FW WARN [syzbot] - ieee80211: use variable-length arrays [syzbot] - mac80211 - remove WARN on delayed beacon update [syzbot] - drop OCB frames with invalid source [syzbot] * tag 'wireless-2025-06-18' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: wifi: iwlwifi: Fix incorrect logic on cmd_ver range checking wifi: iwlwifi: dvm: restore n_no_reclaim_cmds setting wifi: iwlwifi: cfg: Limit cb_size to valid range wifi: iwlwifi: restore missing initialization of async_handlers_list (again) wifi: ath6kl: remove WARN on bad firmware input wifi: carl9170: do not ping device which has failed to load firmware wifi: ath12k: don't wait when there is no vdev started wifi: ath12k: don't use static variables in ath12k_wmi_fw_stats_process() wifi: ath12k: avoid burning CPU while waiting for firmware stats wifi: ath12k: fix documentation on firmware stats wifi: ath12k: don't activate more links than firmware supports wifi: ath12k: update link active in case two links fall on the same MAC wifi: ath12k: support WMI_MLO_LINK_SET_ACTIVE_CMDID command wifi: ath12k: update freq range for each hardware mode wifi: ath12k: parse and save sbs_lower_band_end_freq from WMI_SERVICE_READY_EXT2_EVENTID event wifi: ath12k: parse and save hardware mode info from WMI_SERVICE_READY_EXT_EVENTID event for later use wifi: ath12k: Avoid CPU busy-wait by handling VDEV_STAT and BCN_STAT wifi: mac80211: don't WARN for late channel/color switch wifi: mac80211: drop invalid source address OCB frames wifi: remove zero-length arrays ====================
Unified · Split
| @@ -1216,6 +1216,7 @@ void ath12k_fw_stats_init(struct ath12k *ar) · 1215 unmodified lines | |||
| 1216 | INIT_LIST_HEAD(&ar->fw_stats.pdevs); | 1216 | INIT_LIST_HEAD(&ar->fw_stats.pdevs); |
| 1217 | INIT_LIST_HEAD(&ar->fw_stats.bcn); | 1217 | INIT_LIST_HEAD(&ar->fw_stats.bcn); |
| 1218 | init_completion(&ar->fw_stats_complete); | 1218 | init_completion(&ar->fw_stats_complete); |
| 1219 | init_completion(&ar->fw_stats_done); | ||
| 1219 | } | 1220 | } |
| 1220 | 1221 | ||
| 1221 | void ath12k_fw_stats_free(struct ath12k_fw_stats *stats) | 1222 | void ath12k_fw_stats_free(struct ath12k_fw_stats *stats) |
| @@ -1228,8 +1229,9 @@ void ath12k_fw_stats_free(struct ath12k_fw_stats *stats) · 6 unmodified lines | |||
| 1228 | void ath12k_fw_stats_reset(struct ath12k *ar) | 1229 | void ath12k_fw_stats_reset(struct ath12k *ar) |
| 1229 | { | 1230 | { |
| 1230 | spin_lock_bh(&ar->data_lock); | 1231 | spin_lock_bh(&ar->data_lock); |
| 1231 | ar->fw_stats.fw_stats_done = false; | ||
| 1232 | ath12k_fw_stats_free(&ar->fw_stats); | 1232 | ath12k_fw_stats_free(&ar->fw_stats); |
| 1233 | ar->fw_stats.num_vdev_recvd = 0; | ||
| 1234 | ar->fw_stats.num_bcn_recvd = 0; | ||
| 1233 | spin_unlock_bh(&ar->data_lock); | 1235 | spin_unlock_bh(&ar->data_lock); |
| 1234 | } | 1236 | } |
| 1235 | 1237 | ||
| @@ -601,6 +601,12 @@ struct ath12k_sta { · 600 unmodified lines | |||
| 601 | #define ATH12K_NUM_CHANS 101 | 601 | #define ATH12K_NUM_CHANS 101 |
| 602 | #define ATH12K_MAX_5GHZ_CHAN 173 | 602 | #define ATH12K_MAX_5GHZ_CHAN 173 |
| 603 | 603 | ||
| 604 | static inline bool ath12k_is_2ghz_channel_freq(u32 freq) | ||
| 605 | { | ||
| 606 | return freq >= ATH12K_MIN_2GHZ_FREQ && | ||
| 607 | freq <= ATH12K_MAX_2GHZ_FREQ; | ||
| 608 | } | ||
| 609 | |||
| 604 | enum ath12k_hw_state { | 610 | enum ath12k_hw_state { |
| 605 | ATH12K_HW_STATE_OFF, | 611 | ATH12K_HW_STATE_OFF, |
| 606 | ATH12K_HW_STATE_ON, | 612 | ATH12K_HW_STATE_ON, |
| @@ -626,7 +632,8 @@ struct ath12k_fw_stats { · 19 unmodified lines | |||
| 626 | struct list_head pdevs; | 632 | struct list_head pdevs; |
| 627 | struct list_head vdevs; | 633 | struct list_head vdevs; |
| 628 | struct list_head bcn; | 634 | struct list_head bcn; |
| 629 | bool fw_stats_done; | 635 | u32 num_vdev_recvd; |
| 636 | u32 num_bcn_recvd; | ||
| 630 | }; | 637 | }; |
| 631 | 638 | ||
| 632 | struct ath12k_dbg_htt_stats { | 639 | struct ath12k_dbg_htt_stats { |
| @@ -806,6 +813,7 @@ struct ath12k { · 173 unmodified lines | |||
| 806 | bool regdom_set_by_user; | 813 | bool regdom_set_by_user; |
| 807 | 814 | ||
| 808 | struct completion fw_stats_complete; | 815 | struct completion fw_stats_complete; |
| 816 | struct completion fw_stats_done; | ||
| 809 | 817 | ||
| 810 | struct completion mlo_setup_done; | 818 | struct completion mlo_setup_done; |
| 811 | u32 mlo_setup_status; | 819 | u32 mlo_setup_status; |
| @@ -1251,64 +1251,6 @@ void ath12k_debugfs_soc_destroy(struct ath12k_base *ab) · 1250 unmodified lines | |||
| 1251 | */ | 1251 | */ |
| 1252 | } | 1252 | } |
| 1253 | 1253 | ||
| 1254 | void | ||
| 1255 | ath12k_debugfs_fw_stats_process(struct ath12k *ar, | ||
| 1256 | struct ath12k_fw_stats *stats) | ||
| 1257 | { | ||
| 1258 | struct ath12k_base *ab = ar->ab; | ||
| 1259 | struct ath12k_pdev *pdev; | ||
| 1260 | bool is_end; | ||
| 1261 | static unsigned int num_vdev, num_bcn; | ||
| 1262 | size_t total_vdevs_started = 0; | ||
| 1263 | int i; | ||
| 1264 | |||
| 1265 | if (stats->stats_id == WMI_REQUEST_VDEV_STAT) { | ||
| 1266 | if (list_empty(&stats->vdevs)) { | ||
| 1267 | ath12k_warn(ab, "empty vdev stats"); | ||
| 1268 | return; | ||
| 1269 | } | ||
| 1270 | /* FW sends all the active VDEV stats irrespective of PDEV, | ||
| 1271 | * hence limit until the count of all VDEVs started | ||
| 1272 | */ | ||
| 1273 | rcu_read_lock(); | ||
| 1274 | for (i = 0; i < ab->num_radios; i++) { | ||
| 1275 | pdev = rcu_dereference(ab->pdevs_active[i]); | ||
| 1276 | if (pdev && pdev->ar) | ||
| 1277 | total_vdevs_started += pdev->ar->num_started_vdevs; | ||
| 1278 | } | ||
| 1279 | rcu_read_unlock(); | ||
| 1280 | |||
| 1281 | is_end = ((++num_vdev) == total_vdevs_started); | ||
| 1282 | |||
| 1283 | list_splice_tail_init(&stats->vdevs, | ||
| 1284 | &ar->fw_stats.vdevs); | ||
| 1285 | |||
| 1286 | if (is_end) { | ||
| 1287 | ar->fw_stats.fw_stats_done = true; | ||
| 1288 | num_vdev = 0; | ||
| 1289 | } | ||
| 1290 | return; | ||
| 1291 | } | ||
| 1292 | if (stats->stats_id == WMI_REQUEST_BCN_STAT) { | ||
| 1293 | if (list_empty(&stats->bcn)) { | ||
| 1294 | ath12k_warn(ab, "empty beacon stats"); | ||
| 1295 | return; | ||
| 1296 | } | ||
| 1297 | /* Mark end until we reached the count of all started VDEVs | ||
| 1298 | * within the PDEV | ||
| 1299 | */ | ||
| 1300 | is_end = ((++num_bcn) == ar->num_started_vdevs); | ||
| 1301 | |||
| 1302 | list_splice_tail_init(&stats->bcn, | ||
| 1303 | &ar->fw_stats.bcn); | ||
| 1304 | |||
| 1305 | if (is_end) { | ||
| 1306 | ar->fw_stats.fw_stats_done = true; | ||
| 1307 | num_bcn = 0; | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | } | ||
| 1311 | |||
| 1312 | static int ath12k_open_vdev_stats(struct inode *inode, struct file *file) | 1254 | static int ath12k_open_vdev_stats(struct inode *inode, struct file *file) |
| 1313 | { | 1255 | { |
| 1314 | struct ath12k *ar = inode->i_private; | 1256 | struct ath12k *ar = inode->i_private; |
| @@ -12,8 +12,6 @@ void ath12k_debugfs_soc_create(struct ath12k_base *ab); · 11 unmodified lines | |||
| 12 | void ath12k_debugfs_soc_destroy(struct ath12k_base *ab); | 12 | void ath12k_debugfs_soc_destroy(struct ath12k_base *ab); |
| 13 | void ath12k_debugfs_register(struct ath12k *ar); | 13 | void ath12k_debugfs_register(struct ath12k *ar); |
| 14 | void ath12k_debugfs_unregister(struct ath12k *ar); | 14 | void ath12k_debugfs_unregister(struct ath12k *ar); |
| 15 | void ath12k_debugfs_fw_stats_process(struct ath12k *ar, | ||
| 16 | struct ath12k_fw_stats *stats); | ||
| 17 | void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw, | 15 | void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw, |
| 18 | struct ieee80211_vif *vif); | 16 | struct ieee80211_vif *vif); |
| 19 | void ath12k_debugfs_pdev_create(struct ath12k_base *ab); | 17 | void ath12k_debugfs_pdev_create(struct ath12k_base *ab); |
| @@ -126,11 +124,6 @@ static inline void ath12k_debugfs_unregister(struct ath12k *ar) · 106 unmodified lines | |||
| 126 | { | 124 | { |
| 127 | } | 125 | } |
| 128 | 126 | ||
| 129 | static inline void ath12k_debugfs_fw_stats_process(struct ath12k *ar, | ||
| 130 | struct ath12k_fw_stats *stats) | ||
| 131 | { | ||
| 132 | } | ||
| 133 | |||
| 134 | static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar) | 127 | static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar) |
| 135 | { | 128 | { |
| 136 | return false; | 129 | return false; |
| @@ -4360,7 +4360,7 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 4359 unmodified lines | |||
| 4360 | { | 4360 | { |
| 4361 | struct ath12k_base *ab = ar->ab; | 4361 | struct ath12k_base *ab = ar->ab; |
| 4362 | struct ath12k_hw *ah = ath12k_ar_to_ah(ar); | 4362 | struct ath12k_hw *ah = ath12k_ar_to_ah(ar); |
| 4363 | unsigned long timeout, time_left; | 4363 | unsigned long time_left; |
| 4364 | int ret; | 4364 | int ret; |
| 4365 | 4365 | ||
| 4366 | guard(mutex)(&ah->hw_mutex); | 4366 | guard(mutex)(&ah->hw_mutex); |
| @@ -4368,19 +4368,13 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 1 unmodified line | |||
| 4368 | if (ah->state != ATH12K_HW_STATE_ON) | 4368 | if (ah->state != ATH12K_HW_STATE_ON) |
| 4369 | return -ENETDOWN; | 4369 | return -ENETDOWN; |
| 4370 | 4370 | ||
| 4371 | /* FW stats can get split when exceeding the stats data buffer limit. | ||
| 4372 | * In that case, since there is no end marking for the back-to-back | ||
| 4373 | * received 'update stats' event, we keep a 3 seconds timeout in case, | ||
| 4374 | * fw_stats_done is not marked yet | ||
| 4375 | */ | ||
| 4376 | timeout = jiffies + msecs_to_jiffies(3 * 1000); | ||
| 4377 | ath12k_fw_stats_reset(ar); | 4371 | ath12k_fw_stats_reset(ar); |
| 4378 | 4372 | ||
| 4379 | reinit_completion(&ar->fw_stats_complete); | 4373 | reinit_completion(&ar->fw_stats_complete); |
| 4374 | reinit_completion(&ar->fw_stats_done); | ||
| 4380 | 4375 | ||
| 4381 | ret = ath12k_wmi_send_stats_request_cmd(ar, param->stats_id, | 4376 | ret = ath12k_wmi_send_stats_request_cmd(ar, param->stats_id, |
| 4382 | param->vdev_id, param->pdev_id); | 4377 | param->vdev_id, param->pdev_id); |
| 4383 | |||
| 4384 | if (ret) { | 4378 | if (ret) { |
| 4385 | ath12k_warn(ab, "failed to request fw stats: %d\n", ret); | 4379 | ath12k_warn(ab, "failed to request fw stats: %d\n", ret); |
| 4386 | return ret; | 4380 | return ret; |
| @@ -4391,7 +4385,6 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 4 unmodified lines | |||
| 4391 | param->pdev_id, param->vdev_id, param->stats_id); | 4385 | param->pdev_id, param->vdev_id, param->stats_id); |
| 4392 | 4386 | ||
| 4393 | time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ); | 4387 | time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ); |
| 4394 | |||
| 4395 | if (!time_left) { | 4388 | if (!time_left) { |
| 4396 | ath12k_warn(ab, "time out while waiting for get fw stats\n"); | 4389 | ath12k_warn(ab, "time out while waiting for get fw stats\n"); |
| 4397 | return -ETIMEDOUT; | 4390 | return -ETIMEDOUT; |
| @@ -4400,20 +4393,15 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 2 unmodified lines | |||
| 4400 | /* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back | 4393 | /* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back |
| 4401 | * when stats data buffer limit is reached. fw_stats_complete | 4394 | * when stats data buffer limit is reached. fw_stats_complete |
| 4402 | * is completed once host receives first event from firmware, but | 4395 | * is completed once host receives first event from firmware, but |
| 4403 | * still end might not be marked in the TLV. | 4396 | * still there could be more events following. Below is to wait |
| 4404 | * Below loop is to confirm that firmware completed sending all the event | 4397 | * until firmware completes sending all the events. |
| 4405 | * and fw_stats_done is marked true when end is marked in the TLV. | ||
| 4406 | */ | 4398 | */ |
| 4407 | for (;;) { | 4399 | time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ); |
| 4408 | if (time_after(jiffies, timeout)) | 4400 | if (!time_left) { |
| 4409 | break; | 4401 | ath12k_warn(ab, "time out while waiting for fw stats done\n"); |
| 4410 | spin_lock_bh(&ar->data_lock); | 4402 | return -ETIMEDOUT; |
| 4411 | if (ar->fw_stats.fw_stats_done) { | ||
| 4412 | spin_unlock_bh(&ar->data_lock); | ||
| 4413 | break; | ||
| 4414 | } | ||
| 4415 | spin_unlock_bh(&ar->data_lock); | ||
| 4416 | } | 4403 | } |
| 4404 | |||
| 4417 | return 0; | 4405 | return 0; |
| 4418 | } | 4406 | } |
| 4419 | 4407 | ||
| @@ -5890,6 +5878,327 @@ exit: · 1470 unmodified lines | |||
| 5890 | return ret; | 5878 | return ret; |
| 5891 | } | 5879 | } |
| 5892 | 5880 | ||
| 5881 | static bool ath12k_mac_is_freq_on_mac(struct ath12k_hw_mode_freq_range_arg *freq_range, | ||
| 5882 | u32 freq, u8 mac_id) | ||
| 5883 | { | ||
| 5884 | return (freq >= freq_range[mac_id].low_2ghz_freq && | ||
| 5885 | freq <= freq_range[mac_id].high_2ghz_freq) || | ||
| 5886 | (freq >= freq_range[mac_id].low_5ghz_freq && | ||
| 5887 | freq <= freq_range[mac_id].high_5ghz_freq); | ||
| 5888 | } | ||
| 5889 | |||
| 5890 | static bool | ||
| 5891 | ath12k_mac_2_freq_same_mac_in_freq_range(struct ath12k_base *ab, | ||
| 5892 | struct ath12k_hw_mode_freq_range_arg *freq_range, | ||
| 5893 | u32 freq_link1, u32 freq_link2) | ||
| 5894 | { | ||
| 5895 | u8 i; | ||
| 5896 | |||
| 5897 | for (i = 0; i < MAX_RADIOS; i++) { | ||
| 5898 | if (ath12k_mac_is_freq_on_mac(freq_range, freq_link1, i) && | ||
| 5899 | ath12k_mac_is_freq_on_mac(freq_range, freq_link2, i)) | ||
| 5900 | return true; | ||
| 5901 | } | ||
| 5902 | |||
| 5903 | return false; | ||
| 5904 | } | ||
| 5905 | |||
| 5906 | static bool ath12k_mac_is_hw_dbs_capable(struct ath12k_base *ab) | ||
| 5907 | { | ||
| 5908 | return test_bit(WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT, | ||
| 5909 | ab->wmi_ab.svc_map) && | ||
| 5910 | ab->wmi_ab.hw_mode_info.support_dbs; | ||
| 5911 | } | ||
| 5912 | |||
| 5913 | static bool ath12k_mac_2_freq_same_mac_in_dbs(struct ath12k_base *ab, | ||
| 5914 | u32 freq_link1, u32 freq_link2) | ||
| 5915 | { | ||
| 5916 | struct ath12k_hw_mode_freq_range_arg *freq_range; | ||
| 5917 | |||
| 5918 | if (!ath12k_mac_is_hw_dbs_capable(ab)) | ||
| 5919 | return true; | ||
| 5920 | |||
| 5921 | freq_range = ab->wmi_ab.hw_mode_info.freq_range_caps[ATH12K_HW_MODE_DBS]; | ||
| 5922 | return ath12k_mac_2_freq_same_mac_in_freq_range(ab, freq_range, | ||
| 5923 | freq_link1, freq_link2); | ||
| 5924 | } | ||
| 5925 | |||
| 5926 | static bool ath12k_mac_is_hw_sbs_capable(struct ath12k_base *ab) | ||
| 5927 | { | ||
| 5928 | return test_bit(WMI_TLV_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT, | ||
| 5929 | ab->wmi_ab.svc_map) && | ||
| 5930 | ab->wmi_ab.hw_mode_info.support_sbs; | ||
| 5931 | } | ||
| 5932 | |||
| 5933 | static bool ath12k_mac_2_freq_same_mac_in_sbs(struct ath12k_base *ab, | ||
| 5934 | u32 freq_link1, u32 freq_link2) | ||
| 5935 | { | ||
| 5936 | struct ath12k_hw_mode_info *info = &ab->wmi_ab.hw_mode_info; | ||
| 5937 | struct ath12k_hw_mode_freq_range_arg *sbs_uppr_share; | ||
| 5938 | struct ath12k_hw_mode_freq_range_arg *sbs_low_share; | ||
| 5939 | struct ath12k_hw_mode_freq_range_arg *sbs_range; | ||
| 5940 | |||
| 5941 | if (!ath12k_mac_is_hw_sbs_capable(ab)) | ||
| 5942 | return true; | ||
| 5943 | |||
| 5944 | if (ab->wmi_ab.sbs_lower_band_end_freq) { | ||
| 5945 | sbs_uppr_share = info->freq_range_caps[ATH12K_HW_MODE_SBS_UPPER_SHARE]; | ||
| 5946 | sbs_low_share = info->freq_range_caps[ATH12K_HW_MODE_SBS_LOWER_SHARE]; | ||
| 5947 | |||
| 5948 | return ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_low_share, | ||
| 5949 | freq_link1, freq_link2) || | ||
| 5950 | ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_uppr_share, | ||
| 5951 | freq_link1, freq_link2); | ||
| 5952 | } | ||
| 5953 | |||
| 5954 | sbs_range = info->freq_range_caps[ATH12K_HW_MODE_SBS]; | ||
| 5955 | return ath12k_mac_2_freq_same_mac_in_freq_range(ab, sbs_range, | ||
| 5956 | freq_link1, freq_link2); | ||
| 5957 | } | ||
| 5958 | |||
| 5959 | static bool ath12k_mac_freqs_on_same_mac(struct ath12k_base *ab, | ||
| 5960 | u32 freq_link1, u32 freq_link2) | ||
| 5961 | { | ||
| 5962 | return ath12k_mac_2_freq_same_mac_in_dbs(ab, freq_link1, freq_link2) && | ||
| 5963 | ath12k_mac_2_freq_same_mac_in_sbs(ab, freq_link1, freq_link2); | ||
| 5964 | } | ||
| 5965 | |||
| 5966 | static int ath12k_mac_mlo_sta_set_link_active(struct ath12k_base *ab, | ||
| 5967 | enum wmi_mlo_link_force_reason reason, | ||
| 5968 | enum wmi_mlo_link_force_mode mode, | ||
| 5969 | u8 *mlo_vdev_id_lst, | ||
| 5970 | u8 num_mlo_vdev, | ||
| 5971 | u8 *mlo_inactive_vdev_lst, | ||
| 5972 | u8 num_mlo_inactive_vdev) | ||
| 5973 | { | ||
| 5974 | struct wmi_mlo_link_set_active_arg param = {0}; | ||
| 5975 | u32 entry_idx, entry_offset, vdev_idx; | ||
| 5976 | u8 vdev_id; | ||
| 5977 | |||
| 5978 | param.reason = reason; | ||
| 5979 | param.force_mode = mode; | ||
| 5980 | |||
| 5981 | for (vdev_idx = 0; vdev_idx < num_mlo_vdev; vdev_idx++) { | ||
| 5982 | vdev_id = mlo_vdev_id_lst[vdev_idx]; | ||
| 5983 | entry_idx = vdev_id / 32; | ||
| 5984 | entry_offset = vdev_id % 32; | ||
| 5985 | if (entry_idx >= WMI_MLO_LINK_NUM_SZ) { | ||
| 5986 | ath12k_warn(ab, "Invalid entry_idx %d num_mlo_vdev %d vdev %d", | ||
| 5987 | entry_idx, num_mlo_vdev, vdev_id); | ||
| 5988 | return -EINVAL; | ||
| 5989 | } | ||
| 5990 | param.vdev_bitmap[entry_idx] |= 1 << entry_offset; | ||
| 5991 | /* update entry number if entry index changed */ | ||
| 5992 | if (param.num_vdev_bitmap < entry_idx + 1) | ||
| 5993 | param.num_vdev_bitmap = entry_idx + 1; | ||
| 5994 | } | ||
| 5995 | |||
| 5996 | ath12k_dbg(ab, ATH12K_DBG_MAC, | ||
| 5997 | "num_vdev_bitmap %d vdev_bitmap[0] = 0x%x, vdev_bitmap[1] = 0x%x", | ||
| 5998 | param.num_vdev_bitmap, param.vdev_bitmap[0], param.vdev_bitmap[1]); | ||
| 5999 | |||
| 6000 | if (mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE) { | ||
| 6001 | for (vdev_idx = 0; vdev_idx < num_mlo_inactive_vdev; vdev_idx++) { | ||
| 6002 | vdev_id = mlo_inactive_vdev_lst[vdev_idx]; | ||
| 6003 | entry_idx = vdev_id / 32; | ||
| 6004 | entry_offset = vdev_id % 32; | ||
| 6005 | if (entry_idx >= WMI_MLO_LINK_NUM_SZ) { | ||
| 6006 | ath12k_warn(ab, "Invalid entry_idx %d num_mlo_vdev %d vdev %d", | ||
| 6007 | entry_idx, num_mlo_inactive_vdev, vdev_id); | ||
| 6008 | return -EINVAL; | ||
| 6009 | } | ||
| 6010 | param.inactive_vdev_bitmap[entry_idx] |= 1 << entry_offset; | ||
| 6011 | /* update entry number if entry index changed */ | ||
| 6012 | if (param.num_inactive_vdev_bitmap < entry_idx + 1) | ||
| 6013 | param.num_inactive_vdev_bitmap = entry_idx + 1; | ||
| 6014 | } | ||
| 6015 | |||
| 6016 | ath12k_dbg(ab, ATH12K_DBG_MAC, | ||
| 6017 | "num_vdev_bitmap %d inactive_vdev_bitmap[0] = 0x%x, inactive_vdev_bitmap[1] = 0x%x", | ||
| 6018 | param.num_inactive_vdev_bitmap, | ||
| 6019 | param.inactive_vdev_bitmap[0], | ||
| 6020 | param.inactive_vdev_bitmap[1]); | ||
| 6021 | } | ||
| 6022 | |||
| 6023 | if (mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_LINK_NUM || | ||
| 6024 | mode == WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM) { | ||
| 6025 | param.num_link_entry = 1; | ||
| 6026 | param.link_num[0].num_of_link = num_mlo_vdev - 1; | ||
| 6027 | } | ||
| 6028 | |||
| 6029 | return ath12k_wmi_send_mlo_link_set_active_cmd(ab, ¶m); | ||
| 6030 | } | ||
| 6031 | |||
| 6032 | static int ath12k_mac_mlo_sta_update_link_active(struct ath12k_base *ab, | ||
| 6033 | struct ieee80211_hw *hw, | ||
| 6034 | struct ath12k_vif *ahvif) | ||
| 6035 | { | ||
| 6036 | u8 mlo_vdev_id_lst[IEEE80211_MLD_MAX_NUM_LINKS] = {0}; | ||
| 6037 | u32 mlo_freq_list[IEEE80211_MLD_MAX_NUM_LINKS] = {0}; | ||
| 6038 | unsigned long links = ahvif->links_map; | ||
| 6039 | enum wmi_mlo_link_force_reason reason; | ||
| 6040 | struct ieee80211_chanctx_conf *conf; | ||
| 6041 | enum wmi_mlo_link_force_mode mode; | ||
| 6042 | struct ieee80211_bss_conf *info; | ||
| 6043 | struct ath12k_link_vif *arvif; | ||
| 6044 | u8 num_mlo_vdev = 0; | ||
| 6045 | u8 link_id; | ||
| 6046 | |||
| 6047 | for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 6048 | arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); | ||
| 6049 | /* make sure vdev is created on this device */ | ||
| 6050 | if (!arvif || !arvif->is_created || arvif->ar->ab != ab) | ||
| 6051 | continue; | ||
| 6052 | |||
| 6053 | info = ath12k_mac_get_link_bss_conf(arvif); | ||
| 6054 | conf = wiphy_dereference(hw->wiphy, info->chanctx_conf); | ||
| 6055 | mlo_freq_list[num_mlo_vdev] = conf->def.chan->center_freq; | ||
| 6056 | |||
| 6057 | mlo_vdev_id_lst[num_mlo_vdev] = arvif->vdev_id; | ||
| 6058 | num_mlo_vdev++; | ||
| 6059 | } | ||
| 6060 | |||
| 6061 | /* It is not allowed to activate more links than a single device | ||
| 6062 | * supported. Something goes wrong if we reach here. | ||
| 6063 | */ | ||
| 6064 | if (num_mlo_vdev > ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE) { | ||
| 6065 | WARN_ON_ONCE(1); | ||
| 6066 | return -EINVAL; | ||
| 6067 | } | ||
| 6068 | |||
| 6069 | /* if 2 links are established and both link channels fall on the | ||
| 6070 | * same hardware MAC, send command to firmware to deactivate one | ||
| 6071 | * of them. | ||
| 6072 | */ | ||
| 6073 | if (num_mlo_vdev == 2 && | ||
| 6074 | ath12k_mac_freqs_on_same_mac(ab, mlo_freq_list[0], | ||
| 6075 | mlo_freq_list[1])) { | ||
| 6076 | mode = WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM; | ||
| 6077 | reason = WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT; | ||
| 6078 | return ath12k_mac_mlo_sta_set_link_active(ab, reason, mode, | ||
| 6079 | mlo_vdev_id_lst, num_mlo_vdev, | ||
| 6080 | NULL, 0); | ||
| 6081 | } | ||
| 6082 | |||
| 6083 | return 0; | ||
| 6084 | } | ||
| 6085 | |||
| 6086 | static bool ath12k_mac_are_sbs_chan(struct ath12k_base *ab, u32 freq_1, u32 freq_2) | ||
| 6087 | { | ||
| 6088 | if (!ath12k_mac_is_hw_sbs_capable(ab)) | ||
| 6089 | return false; | ||
| 6090 | |||
| 6091 | if (ath12k_is_2ghz_channel_freq(freq_1) || | ||
| 6092 | ath12k_is_2ghz_channel_freq(freq_2)) | ||
| 6093 | return false; | ||
| 6094 | |||
| 6095 | return !ath12k_mac_2_freq_same_mac_in_sbs(ab, freq_1, freq_2); | ||
| 6096 | } | ||
| 6097 | |||
| 6098 | static bool ath12k_mac_are_dbs_chan(struct ath12k_base *ab, u32 freq_1, u32 freq_2) | ||
| 6099 | { | ||
| 6100 | if (!ath12k_mac_is_hw_dbs_capable(ab)) | ||
| 6101 | return false; | ||
| 6102 | |||
| 6103 | return !ath12k_mac_2_freq_same_mac_in_dbs(ab, freq_1, freq_2); | ||
| 6104 | } | ||
| 6105 | |||
| 6106 | static int ath12k_mac_select_links(struct ath12k_base *ab, | ||
| 6107 | struct ieee80211_vif *vif, | ||
| 6108 | struct ieee80211_hw *hw, | ||
| 6109 | u16 *selected_links) | ||
| 6110 | { | ||
| 6111 | unsigned long useful_links = ieee80211_vif_usable_links(vif); | ||
| 6112 | struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); | ||
| 6113 | u8 num_useful_links = hweight_long(useful_links); | ||
| 6114 | struct ieee80211_chanctx_conf *chanctx; | ||
| 6115 | struct ath12k_link_vif *assoc_arvif; | ||
| 6116 | u32 assoc_link_freq, partner_freq; | ||
| 6117 | u16 sbs_links = 0, dbs_links = 0; | ||
| 6118 | struct ieee80211_bss_conf *info; | ||
| 6119 | struct ieee80211_channel *chan; | ||
| 6120 | struct ieee80211_sta *sta; | ||
| 6121 | struct ath12k_sta *ahsta; | ||
| 6122 | u8 link_id; | ||
| 6123 | |||
| 6124 | /* activate all useful links if less than max supported */ | ||
| 6125 | if (num_useful_links <= ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE) { | ||
| 6126 | *selected_links = useful_links; | ||
| 6127 | return 0; | ||
| 6128 | } | ||
| 6129 | |||
| 6130 | /* only in station mode we can get here, so it's safe | ||
| 6131 | * to use ap_addr | ||
| 6132 | */ | ||
| 6133 | rcu_read_lock(); | ||
| 6134 | sta = ieee80211_find_sta(vif, vif->cfg.ap_addr); | ||
| 6135 | if (!sta) { | ||
| 6136 | rcu_read_unlock(); | ||
| 6137 | ath12k_warn(ab, "failed to find sta with addr %pM\n", vif->cfg.ap_addr); | ||
| 6138 | return -EINVAL; | ||
| 6139 | } | ||
| 6140 | |||
| 6141 | ahsta = ath12k_sta_to_ahsta(sta); | ||
| 6142 | assoc_arvif = wiphy_dereference(hw->wiphy, ahvif->link[ahsta->assoc_link_id]); | ||
| 6143 | info = ath12k_mac_get_link_bss_conf(assoc_arvif); | ||
| 6144 | chanctx = rcu_dereference(info->chanctx_conf); | ||
| 6145 | assoc_link_freq = chanctx->def.chan->center_freq; | ||
| 6146 | rcu_read_unlock(); | ||
| 6147 | ath12k_dbg(ab, ATH12K_DBG_MAC, "assoc link %u freq %u\n", | ||
| 6148 | assoc_arvif->link_id, assoc_link_freq); | ||
| 6149 | |||
| 6150 | /* assoc link is already activated and has to be kept active, | ||
| 6151 | * only need to select a partner link from others. | ||
| 6152 | */ | ||
| 6153 | useful_links &= ~BIT(assoc_arvif->link_id); | ||
| 6154 | for_each_set_bit(link_id, &useful_links, IEEE80211_MLD_MAX_NUM_LINKS) { | ||
| 6155 | info = wiphy_dereference(hw->wiphy, vif->link_conf[link_id]); | ||
| 6156 | if (!info) { | ||
| 6157 | ath12k_warn(ab, "failed to get link info for link: %u\n", | ||
| 6158 | link_id); | ||
| 6159 | return -ENOLINK; | ||
| 6160 | } | ||
| 6161 | |||
| 6162 | chan = info->chanreq.oper.chan; | ||
| 6163 | if (!chan) { | ||
| 6164 | ath12k_warn(ab, "failed to get chan for link: %u\n", link_id); | ||
| 6165 | return -EINVAL; | ||
| 6166 | } | ||
| 6167 | |||
| 6168 | partner_freq = chan->center_freq; | ||
| 6169 | if (ath12k_mac_are_sbs_chan(ab, assoc_link_freq, partner_freq)) { | ||
| 6170 | sbs_links |= BIT(link_id); | ||
| 6171 | ath12k_dbg(ab, ATH12K_DBG_MAC, "new SBS link %u freq %u\n", | ||
| 6172 | link_id, partner_freq); | ||
| 6173 | continue; | ||
| 6174 | } | ||
| 6175 | |||
| 6176 | if (ath12k_mac_are_dbs_chan(ab, assoc_link_freq, partner_freq)) { | ||
| 6177 | dbs_links |= BIT(link_id); | ||
| 6178 | ath12k_dbg(ab, ATH12K_DBG_MAC, "new DBS link %u freq %u\n", | ||
| 6179 | link_id, partner_freq); | ||
| 6180 | continue; | ||
| 6181 | } | ||
| 6182 | |||
| 6183 | ath12k_dbg(ab, ATH12K_DBG_MAC, "non DBS/SBS link %u freq %u\n", | ||
| 6184 | link_id, partner_freq); | ||
| 6185 | } | ||
| 6186 | |||
| 6187 | /* choose the first candidate no matter how many is in the list */ | ||
| 6188 | if (sbs_links) | ||
| 6189 | link_id = __ffs(sbs_links); | ||
| 6190 | else if (dbs_links) | ||
| 6191 | link_id = __ffs(dbs_links); | ||
| 6192 | else | ||
| 6193 | link_id = ffs(useful_links) - 1; | ||
| 6194 | |||
| 6195 | ath12k_dbg(ab, ATH12K_DBG_MAC, "select partner link %u\n", link_id); | ||
| 6196 | |||
| 6197 | *selected_links = BIT(assoc_arvif->link_id) | BIT(link_id); | ||
| 6198 | |||
| 6199 | return 0; | ||
| 6200 | } | ||
| 6201 | |||
| 5893 | static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, | 6202 | static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, |
| 5894 | struct ieee80211_vif *vif, | 6203 | struct ieee80211_vif *vif, |
| 5895 | struct ieee80211_sta *sta, | 6204 | struct ieee80211_sta *sta, |
| @@ -5899,10 +6208,13 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, · 3 unmodified lines | |||
| 5899 | struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); | 6208 | struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); |
| 5900 | struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); | 6209 | struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); |
| 5901 | struct ath12k_hw *ah = ath12k_hw_to_ah(hw); | 6210 | struct ath12k_hw *ah = ath12k_hw_to_ah(hw); |
| 6211 | struct ath12k_base *prev_ab = NULL, *ab; | ||
| 5902 | struct ath12k_link_vif *arvif; | 6212 | struct ath12k_link_vif *arvif; |
| 5903 | struct ath12k_link_sta *arsta; | 6213 | struct ath12k_link_sta *arsta; |
| 5904 | unsigned long valid_links; | 6214 | unsigned long valid_links; |
| 5905 | u8 link_id = 0; | 6215 | u16 selected_links = 0; |
| 6216 | u8 link_id = 0, i; | ||
| 6217 | struct ath12k *ar; | ||
| 5906 | int ret; | 6218 | int ret; |
| 5907 | 6219 | ||
| 5908 | lockdep_assert_wiphy(hw->wiphy); | 6220 | lockdep_assert_wiphy(hw->wiphy); |
| @@ -5972,8 +6284,24 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, · 63 unmodified lines | |||
| 5972 | * about to move to the associated state. | 6284 | * about to move to the associated state. |
| 5973 | */ | 6285 | */ |
| 5974 | if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION && | 6286 | if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION && |
| 5975 | old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) | 6287 | old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { |
| 5976 | ieee80211_set_active_links(vif, ieee80211_vif_usable_links(vif)); | 6288 | /* TODO: for now only do link selection for single device |
| 6289 | * MLO case. Other cases would be handled in the future. | ||
| 6290 | */ | ||
| 6291 | ab = ah->radio[0].ab; | ||
| 6292 | if (ab->ag->num_devices == 1) { | ||
| 6293 | ret = ath12k_mac_select_links(ab, vif, hw, &selected_links); | ||
| 6294 | if (ret) { | ||
| 6295 | ath12k_warn(ab, | ||
| 6296 | "failed to get selected links: %d\n", ret); | ||
| 6297 | goto exit; | ||
| 6298 | } | ||
| 6299 | } else { | ||
| 6300 | selected_links = ieee80211_vif_usable_links(vif); | ||
| 6301 | } | ||
| 6302 | |||
| 6303 | ieee80211_set_active_links(vif, selected_links); | ||
| 6304 | } | ||
| 5977 | 6305 | ||
| 5978 | /* Handle all the other state transitions in generic way */ | 6306 | /* Handle all the other state transitions in generic way */ |
| 5979 | valid_links = ahsta->links_map; | 6307 | valid_links = ahsta->links_map; |
| @@ -5997,6 +6325,24 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, · 17 unmodified lines | |||
| 5997 | } | 6325 | } |
| 5998 | } | 6326 | } |
| 5999 | 6327 | ||
| 6328 | if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION && | ||
| 6329 | old_state == IEEE80211_STA_ASSOC && new_state == IEEE80211_STA_AUTHORIZED) { | ||
| 6330 | for_each_ar(ah, ar, i) { | ||
| 6331 | ab = ar->ab; | ||
| 6332 | if (prev_ab == ab) | ||
| 6333 | continue; | ||
| 6334 | |||
| 6335 | ret = ath12k_mac_mlo_sta_update_link_active(ab, hw, ahvif); | ||
| 6336 | if (ret) { | ||
| 6337 | ath12k_warn(ab, | ||
| 6338 | "failed to update link active state on connect %d\n", | ||
| 6339 | ret); | ||
| 6340 | goto exit; | ||
| 6341 | } | ||
| 6342 | |||
| 6343 | prev_ab = ab; | ||
| 6344 | } | ||
| 6345 | } | ||
| 6000 | /* IEEE80211_STA_NONE -> IEEE80211_STA_NOTEXIST: | 6346 | /* IEEE80211_STA_NONE -> IEEE80211_STA_NOTEXIST: |
| 6001 | * Remove the station from driver (handle ML sta here since that | 6347 | * Remove the station from driver (handle ML sta here since that |
| 6002 | * needs special handling. Normal sta will be handled in generic | 6348 | * needs special handling. Normal sta will be handled in generic |
| @@ -54,6 +54,8 @@ struct ath12k_generic_iter { · 53 unmodified lines | |||
| 54 | #define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS | 54 | #define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS |
| 55 | #define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1) | 55 | #define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1) |
| 56 | 56 | ||
| 57 | #define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2 | ||
| 58 | |||
| 57 | enum ath12k_supported_bw { | 59 | enum ath12k_supported_bw { |
| 58 | ATH12K_BW_20 = 0, | 60 | ATH12K_BW_20 = 0, |
| 59 | ATH12K_BW_40 = 1, | 61 | ATH12K_BW_40 = 1, |
| @@ -91,6 +91,11 @@ struct ath12k_wmi_svc_rdy_ext2_parse { · 90 unmodified lines | |||
| 91 | bool dma_ring_cap_done; | 91 | bool dma_ring_cap_done; |
| 92 | bool spectral_bin_scaling_done; | 92 | bool spectral_bin_scaling_done; |
| 93 | bool mac_phy_caps_ext_done; | 93 | bool mac_phy_caps_ext_done; |
| 94 | bool hal_reg_caps_ext2_done; | ||
| 95 | bool scan_radio_caps_ext2_done; | ||
| 96 | bool twt_caps_done; | ||
| 97 | bool htt_msdu_idx_to_qtype_map_done; | ||
| 98 | bool dbs_or_sbs_cap_ext_done; | ||
| 94 | }; | 99 | }; |
| 95 | 100 | ||
| 96 | struct ath12k_wmi_rdy_parse { | 101 | struct ath12k_wmi_rdy_parse { |
| @@ -4395,6 +4400,7 @@ static int ath12k_wmi_hw_mode_caps_parse(struct ath12k_base *soc, · 4298 unmodified lines | |||
| 4395 | static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, | 4400 | static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, |
| 4396 | u16 len, const void *ptr, void *data) | 4401 | u16 len, const void *ptr, void *data) |
| 4397 | { | 4402 | { |
| 4403 | struct ath12k_svc_ext_info *svc_ext_info = &soc->wmi_ab.svc_ext_info; | ||
| 4398 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; | 4404 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
| 4399 | const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps; | 4405 | const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps; |
| 4400 | enum wmi_host_hw_mode_config_type mode, pref; | 4406 | enum wmi_host_hw_mode_config_type mode, pref; |
| @@ -4427,8 +4433,11 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, · 26 unmodified lines | |||
| 4427 | } | 4433 | } |
| 4428 | } | 4434 | } |
| 4429 | 4435 | ||
| 4430 | ath12k_dbg(soc, ATH12K_DBG_WMI, "preferred_hw_mode:%d\n", | 4436 | svc_ext_info->num_hw_modes = svc_rdy_ext->n_hw_mode_caps; |
| 4431 | soc->wmi_ab.preferred_hw_mode); | 4437 | |
| 4438 | ath12k_dbg(soc, ATH12K_DBG_WMI, "num hw modes %u preferred_hw_mode %d\n", | ||
| 4439 | svc_ext_info->num_hw_modes, soc->wmi_ab.preferred_hw_mode); | ||
| 4440 | |||
| 4432 | if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) | 4441 | if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) |
| 4433 | return -EINVAL; | 4442 | return -EINVAL; |
| 4434 | 4443 | ||
| @@ -4658,6 +4667,65 @@ free_dir_buff: · 223 unmodified lines | |||
| 4658 | return ret; | 4667 | return ret; |
| 4659 | } | 4668 | } |
| 4660 | 4669 | ||
| 4670 | static void | ||
| 4671 | ath12k_wmi_save_mac_phy_info(struct ath12k_base *ab, | ||
| 4672 | const struct ath12k_wmi_mac_phy_caps_params *mac_phy_cap, | ||
| 4673 | struct ath12k_svc_ext_mac_phy_info *mac_phy_info) | ||
| 4674 | { | ||
| 4675 | mac_phy_info->phy_id = __le32_to_cpu(mac_phy_cap->phy_id); | ||
| 4676 | mac_phy_info->supported_bands = __le32_to_cpu(mac_phy_cap->supported_bands); | ||
| 4677 | mac_phy_info->hw_freq_range.low_2ghz_freq = | ||
| 4678 | __le32_to_cpu(mac_phy_cap->low_2ghz_chan_freq); | ||
| 4679 | mac_phy_info->hw_freq_range.high_2ghz_freq = | ||
| 4680 | __le32_to_cpu(mac_phy_cap->high_2ghz_chan_freq); | ||
| 4681 | mac_phy_info->hw_freq_range.low_5ghz_freq = | ||
| 4682 | __le32_to_cpu(mac_phy_cap->low_5ghz_chan_freq); | ||
| 4683 | mac_phy_info->hw_freq_range.high_5ghz_freq = | ||
| 4684 | __le32_to_cpu(mac_phy_cap->high_5ghz_chan_freq); | ||
| 4685 | } | ||
| 4686 | |||
| 4687 | static void | ||
| 4688 | ath12k_wmi_save_all_mac_phy_info(struct ath12k_base *ab, | ||
| 4689 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext) | ||
| 4690 | { | ||
| 4691 | struct ath12k_svc_ext_info *svc_ext_info = &ab->wmi_ab.svc_ext_info; | ||
| 4692 | const struct ath12k_wmi_mac_phy_caps_params *mac_phy_cap; | ||
| 4693 | const struct ath12k_wmi_hw_mode_cap_params *hw_mode_cap; | ||
| 4694 | struct ath12k_svc_ext_mac_phy_info *mac_phy_info; | ||
| 4695 | u32 hw_mode_id, phy_bit_map; | ||
| 4696 | u8 hw_idx; | ||
| 4697 | |||
| 4698 | mac_phy_info = &svc_ext_info->mac_phy_info[0]; | ||
| 4699 | mac_phy_cap = svc_rdy_ext->mac_phy_caps; | ||
| 4700 | |||
| 4701 | for (hw_idx = 0; hw_idx < svc_ext_info->num_hw_modes; hw_idx++) { | ||
| 4702 | hw_mode_cap = &svc_rdy_ext->hw_mode_caps[hw_idx]; | ||
| 4703 | hw_mode_id = __le32_to_cpu(hw_mode_cap->hw_mode_id); | ||
| 4704 | phy_bit_map = __le32_to_cpu(hw_mode_cap->phy_id_map); | ||
| 4705 | |||
| 4706 | while (phy_bit_map) { | ||
| 4707 | ath12k_wmi_save_mac_phy_info(ab, mac_phy_cap, mac_phy_info); | ||
| 4708 | mac_phy_info->hw_mode_config_type = | ||
| 4709 | le32_get_bits(hw_mode_cap->hw_mode_config_type, | ||
| 4710 | WMI_HW_MODE_CAP_CFG_TYPE); | ||
| 4711 | ath12k_dbg(ab, ATH12K_DBG_WMI, | ||
| 4712 | "hw_idx %u hw_mode_id %u hw_mode_config_type %u supported_bands %u phy_id %u 2 GHz [%u - %u] 5 GHz [%u - %u]\n", | ||
| 4713 | hw_idx, hw_mode_id, | ||
| 4714 | mac_phy_info->hw_mode_config_type, | ||
| 4715 | mac_phy_info->supported_bands, mac_phy_info->phy_id, | ||
| 4716 | mac_phy_info->hw_freq_range.low_2ghz_freq, | ||
| 4717 | mac_phy_info->hw_freq_range.high_2ghz_freq, | ||
| 4718 | mac_phy_info->hw_freq_range.low_5ghz_freq, | ||
| 4719 | mac_phy_info->hw_freq_range.high_5ghz_freq); | ||
| 4720 | |||
| 4721 | mac_phy_cap++; | ||
| 4722 | mac_phy_info++; | ||
| 4723 | |||
| 4724 | phy_bit_map >>= 1; | ||
| 4725 | } | ||
| 4726 | } | ||
| 4727 | } | ||
| 4728 | |||
| 4661 | static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab, | 4729 | static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab, |
| 4662 | u16 tag, u16 len, | 4730 | u16 tag, u16 len, |
| 4663 | const void *ptr, void *data) | 4731 | const void *ptr, void *data) |
| @@ -4706,6 +4774,8 @@ static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab, · 42 unmodified lines | |||
| 4706 | return ret; | 4774 | return ret; |
| 4707 | } | 4775 | } |
| 4708 | 4776 | ||
| 4777 | ath12k_wmi_save_all_mac_phy_info(ab, svc_rdy_ext); | ||
| 4778 | |||
| 4709 | svc_rdy_ext->mac_phy_done = true; | 4779 | svc_rdy_ext->mac_phy_done = true; |
| 4710 | } else if (!svc_rdy_ext->ext_hal_reg_done) { | 4780 | } else if (!svc_rdy_ext->ext_hal_reg_done) { |
| 4711 | ret = ath12k_wmi_ext_hal_reg_caps(ab, len, ptr, svc_rdy_ext); | 4781 | ret = ath12k_wmi_ext_hal_reg_caps(ab, len, ptr, svc_rdy_ext); |
| @@ -4922,10 +4992,449 @@ static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, · 210 unmodified lines | |||
| 4922 | return 0; | 4992 | return 0; |
| 4923 | } | 4993 | } |
| 4924 | 4994 | ||
| 4995 | static void | ||
| 4996 | ath12k_wmi_update_freq_info(struct ath12k_base *ab, | ||
| 4997 | struct ath12k_svc_ext_mac_phy_info *mac_cap, | ||
| 4998 | enum ath12k_hw_mode mode, | ||
| 4999 | u32 phy_id) | ||
| 5000 | { | ||
| 5001 | struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info; | ||
| 5002 | struct ath12k_hw_mode_freq_range_arg *mac_range; | ||
| 5003 | |||
| 5004 | mac_range = &hw_mode_info->freq_range_caps[mode][phy_id]; | ||
| 5005 | |||
| 5006 | if (mac_cap->supported_bands & WMI_HOST_WLAN_2GHZ_CAP) { | ||
| 5007 | mac_range->low_2ghz_freq = max_t(u32, | ||
| 5008 | mac_cap->hw_freq_range.low_2ghz_freq, | ||
| 5009 | ATH12K_MIN_2GHZ_FREQ); | ||
| 5010 | mac_range->high_2ghz_freq = mac_cap->hw_freq_range.high_2ghz_freq ? | ||
| 5011 | min_t(u32, | ||
| 5012 | mac_cap->hw_freq_range.high_2ghz_freq, | ||
| 5013 | ATH12K_MAX_2GHZ_FREQ) : | ||
| 5014 | ATH12K_MAX_2GHZ_FREQ; | ||
| 5015 | } | ||
| 5016 | |||
| 5017 | if (mac_cap->supported_bands & WMI_HOST_WLAN_5GHZ_CAP) { | ||
| 5018 | mac_range->low_5ghz_freq = max_t(u32, | ||
| 5019 | mac_cap->hw_freq_range.low_5ghz_freq, | ||
| 5020 | ATH12K_MIN_5GHZ_FREQ); | ||
| 5021 | mac_range->high_5ghz_freq = mac_cap->hw_freq_range.high_5ghz_freq ? | ||
| 5022 | min_t(u32, | ||
| 5023 | mac_cap->hw_freq_range.high_5ghz_freq, | ||
| 5024 | ATH12K_MAX_6GHZ_FREQ) : | ||
| 5025 | ATH12K_MAX_6GHZ_FREQ; | ||
| 5026 | } | ||
| 5027 | } | ||
| 5028 | |||
| 5029 | static bool | ||
| 5030 | ath12k_wmi_all_phy_range_updated(struct ath12k_base *ab, | ||
| 5031 | enum ath12k_hw_mode hwmode) | ||
| 5032 | { | ||
| 5033 | struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info; | ||
| 5034 | struct ath12k_hw_mode_freq_range_arg *mac_range; | ||
| 5035 | u8 phy_id; | ||
| 5036 | |||
| 5037 | for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) { | ||
| 5038 | mac_range = &hw_mode_info->freq_range_caps[hwmode][phy_id]; | ||
| 5039 | /* modify SBS/DBS range only when both phy for DBS are filled */ | ||
| 5040 | if (!mac_range->low_2ghz_freq && !mac_range->low_5ghz_freq) | ||
| 5041 | return false; | ||
| 5042 | } | ||
| 5043 | |||
| 5044 | return true; | ||
| 5045 | } | ||
| 5046 | |||
| 5047 | static void ath12k_wmi_update_dbs_freq_info(struct ath12k_base *ab) | ||
| 5048 | { | ||
| 5049 | struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info; | ||
| 5050 | struct ath12k_hw_mode_freq_range_arg *mac_range; | ||
| 5051 | u8 phy_id; | ||
| 5052 | |||
| 5053 | mac_range = hw_mode_info->freq_range_caps[ATH12K_HW_MODE_DBS]; | ||
| 5054 | /* Reset 5 GHz range for shared mac for DBS */ | ||
| 5055 | for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) { | ||
| 5056 | if (mac_range[phy_id].low_2ghz_freq && | ||
| 5057 | mac_range[phy_id].low_5ghz_freq) { | ||
| 5058 | mac_range[phy_id].low_5ghz_freq = 0; | ||
| 5059 | mac_range[phy_id].high_5ghz_freq = 0; | ||
| 5060 | } | ||
| 5061 | } | ||
| 5062 | } | ||
| 5063 | |||
| 5064 | static u32 | ||
| 5065 | ath12k_wmi_get_highest_5ghz_freq_from_range(struct ath12k_hw_mode_freq_range_arg *range) | ||
| 5066 | { | ||
| 5067 | u32 highest_freq = 0; | ||
| 5068 | u8 phy_id; | ||
| 5069 | |||
| 5070 | for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) { | ||
| 5071 | if (range[phy_id].high_5ghz_freq > highest_freq) | ||
| 5072 | highest_freq = range[phy_id].high_5ghz_freq; | ||
| 5073 | } | ||
| 5074 | |||
| 5075 | return highest_freq ? highest_freq : ATH12K_MAX_6GHZ_FREQ; | ||
| 5076 | } | ||
| 5077 | |||
| 5078 | static u32 | ||
| 5079 | ath12k_wmi_get_lowest_5ghz_freq_from_range(struct ath12k_hw_mode_freq_range_arg *range) | ||
| 5080 | { | ||
| 5081 | u32 lowest_freq = 0; | ||
| 5082 | u8 phy_id; | ||
| 5083 | |||
| 5084 | for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) { | ||
| 5085 | if ((!lowest_freq && range[phy_id].low_5ghz_freq) || | ||
| 5086 | range[phy_id].low_5ghz_freq < lowest_freq) | ||
| 5087 | lowest_freq = range[phy_id].low_5ghz_freq; | ||
| 5088 | } | ||
| 5089 | |||
| 5090 | return lowest_freq ? lowest_freq : ATH12K_MIN_5GHZ_FREQ; | ||
| 5091 | } | ||
| 5092 | |||
| 5093 | static void | ||
| 5094 | ath12k_wmi_fill_upper_share_sbs_freq(struct ath12k_base *ab, | ||
| 5095 | u16 sbs_range_sep, | ||
| 5096 | struct ath12k_hw_mode_freq_range_arg *ref_freq) | ||
| 5097 | { | ||
| 5098 | struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info; | ||
| 5099 | struct ath12k_hw_mode_freq_range_arg *upper_sbs_freq_range; | ||
| 5100 | u8 phy_id; | ||
| 5101 | |||
| 5102 | upper_sbs_freq_range = | ||
| 5103 | hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS_UPPER_SHARE]; | ||
| 5104 | |||
| 5105 | for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) { | ||
| 5106 | upper_sbs_freq_range[phy_id].low_2ghz_freq = | ||
| 5107 | ref_freq[phy_id].low_2ghz_freq; | ||
| 5108 | upper_sbs_freq_range[phy_id].high_2ghz_freq = | ||
| 5109 | ref_freq[phy_id].high_2ghz_freq; | ||
| 5110 | |||
| 5111 | /* update for shared mac */ | ||
| 5112 | if (upper_sbs_freq_range[phy_id].low_2ghz_freq) { | ||
| 5113 | upper_sbs_freq_range[phy_id].low_5ghz_freq = sbs_range_sep + 10; | ||
| 5114 | upper_sbs_freq_range[phy_id].high_5ghz_freq = | ||
| 5115 | ath12k_wmi_get_highest_5ghz_freq_from_range(ref_freq); | ||
| 5116 | } else { | ||
| 5117 | upper_sbs_freq_range[phy_id].low_5ghz_freq = | ||
| 5118 | ath12k_wmi_get_lowest_5ghz_freq_from_range(ref_freq); | ||
| 5119 | upper_sbs_freq_range[phy_id].high_5ghz_freq = sbs_range_sep; | ||
| 5120 | } | ||
| 5121 | } | ||
| 5122 | } | ||
| 5123 | |||
| 5124 | static void | ||
| 5125 | ath12k_wmi_fill_lower_share_sbs_freq(struct ath12k_base *ab, | ||
| 5126 | u16 sbs_range_sep, | ||
| 5127 | struct ath12k_hw_mode_freq_range_arg *ref_freq) | ||
| 5128 | { | ||
| 5129 | struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info; | ||
| 5130 | struct ath12k_hw_mode_freq_range_arg *lower_sbs_freq_range; | ||
| 5131 | u8 phy_id; | ||
| 5132 | |||
| 5133 | lower_sbs_freq_range = | ||
| 5134 | hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS_LOWER_SHARE]; | ||
| 5135 | |||
| 5136 | for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) { | ||
| 5137 | lower_sbs_freq_range[phy_id].low_2ghz_freq = | ||
| 5138 | ref_freq[phy_id].low_2ghz_freq; | ||
| 5139 | lower_sbs_freq_range[phy_id].high_2ghz_freq = | ||
| 5140 | ref_freq[phy_id].high_2ghz_freq; | ||
| 5141 | |||
| 5142 | /* update for shared mac */ | ||
| 5143 | if (lower_sbs_freq_range[phy_id].low_2ghz_freq) { | ||
| 5144 | lower_sbs_freq_range[phy_id].low_5ghz_freq = | ||
| 5145 | ath12k_wmi_get_lowest_5ghz_freq_from_range(ref_freq); | ||
| 5146 | lower_sbs_freq_range[phy_id].high_5ghz_freq = sbs_range_sep; | ||
| 5147 | } else { | ||
| 5148 | lower_sbs_freq_range[phy_id].low_5ghz_freq = sbs_range_sep + 10; | ||
| 5149 | lower_sbs_freq_range[phy_id].high_5ghz_freq = | ||
| 5150 | ath12k_wmi_get_highest_5ghz_freq_from_range(ref_freq); | ||
| 5151 | } | ||
| 5152 | } | ||
| 5153 | } | ||
| 5154 | |||
| 5155 | static const char *ath12k_wmi_hw_mode_to_str(enum ath12k_hw_mode hw_mode) | ||
| 5156 | { | ||
| 5157 | static const char * const mode_str[] = { | ||
| 5158 | [ATH12K_HW_MODE_SMM] = "SMM", | ||
| 5159 | [ATH12K_HW_MODE_DBS] = "DBS", | ||
| 5160 | [ATH12K_HW_MODE_SBS] = "SBS", | ||
| 5161 | [ATH12K_HW_MODE_SBS_UPPER_SHARE] = "SBS_UPPER_SHARE", | ||
| 5162 | [ATH12K_HW_MODE_SBS_LOWER_SHARE] = "SBS_LOWER_SHARE", | ||
| 5163 | }; | ||
| 5164 | |||
| 5165 | if (hw_mode >= ARRAY_SIZE(mode_str)) | ||
| 5166 | return "Unknown"; | ||
| 5167 | |||
| 5168 | return mode_str[hw_mode]; | ||
| 5169 | } | ||
| 5170 | |||
| 5171 | static void | ||
| 5172 | ath12k_wmi_dump_freq_range_per_mac(struct ath12k_base *ab, | ||
| 5173 | struct ath12k_hw_mode_freq_range_arg *freq_range, | ||
| 5174 | enum ath12k_hw_mode hw_mode) | ||
| 5175 | { | ||
| 5176 | u8 i; | ||
| 5177 | |||
| 5178 | for (i = 0; i < MAX_RADIOS; i++) | ||
| 5179 | if (freq_range[i].low_2ghz_freq || freq_range[i].low_5ghz_freq) | ||
| 5180 | ath12k_dbg(ab, ATH12K_DBG_WMI, | ||
| 5181 | "frequency range: %s(%d) mac %d 2 GHz [%d - %d] 5 GHz [%d - %d]", | ||
| 5182 | ath12k_wmi_hw_mode_to_str(hw_mode), | ||
| 5183 | hw_mode, i, | ||
| 5184 | freq_range[i].low_2ghz_freq, | ||
| 5185 | freq_range[i].high_2ghz_freq, | ||
| 5186 | freq_range[i].low_5ghz_freq, | ||
| 5187 | freq_range[i].high_5ghz_freq); | ||
| 5188 | } | ||
| 5189 | |||
| 5190 | static void ath12k_wmi_dump_freq_range(struct ath12k_base *ab) | ||
| 5191 | { | ||
| 5192 | struct ath12k_hw_mode_freq_range_arg *freq_range; | ||
| 5193 | u8 i; | ||
| 5194 | |||
| 5195 | for (i = ATH12K_HW_MODE_SMM; i < ATH12K_HW_MODE_MAX; i++) { | ||
| 5196 | freq_range = ab->wmi_ab.hw_mode_info.freq_range_caps[i]; | ||
| 5197 | ath12k_wmi_dump_freq_range_per_mac(ab, freq_range, i); | ||
| 5198 | } | ||
| 5199 | } | ||
| 5200 | |||
| 5201 | static int ath12k_wmi_modify_sbs_freq(struct ath12k_base *ab, u8 phy_id) | ||
| 5202 | { | ||
| 5203 | struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info; | ||
| 5204 | struct ath12k_hw_mode_freq_range_arg *sbs_mac_range, *shared_mac_range; | ||
| 5205 | struct ath12k_hw_mode_freq_range_arg *non_shared_range; | ||
| 5206 | u8 shared_phy_id; | ||
| 5207 | |||
| 5208 | sbs_mac_range = &hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS][phy_id]; | ||
| 5209 | |||
| 5210 | /* if SBS mac range has both 2.4 and 5 GHz ranges, i.e. shared phy_id | ||
| 5211 | * keep the range as it is in SBS | ||
| 5212 | */ | ||
| 5213 | if (sbs_mac_range->low_2ghz_freq && sbs_mac_range->low_5ghz_freq) | ||
| 5214 | return 0; | ||
| 5215 | |||
| 5216 | if (sbs_mac_range->low_2ghz_freq && !sbs_mac_range->low_5ghz_freq) { | ||
| 5217 | ath12k_err(ab, "Invalid DBS/SBS mode with only 2.4Ghz"); | ||
| 5218 | ath12k_wmi_dump_freq_range_per_mac(ab, sbs_mac_range, ATH12K_HW_MODE_SBS); | ||
| 5219 | return -EINVAL; | ||
| 5220 | } | ||
| 5221 | |||
| 5222 | non_shared_range = sbs_mac_range; | ||
| 5223 | /* if SBS mac range has only 5 GHz then it's the non-shared phy, so | ||
| 5224 | * modify the range as per the shared mac. | ||
| 5225 | */ | ||
| 5226 | shared_phy_id = phy_id ? 0 : 1; | ||
| 5227 | shared_mac_range = | ||
| 5228 | &hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS][shared_phy_id]; | ||
| 5229 | |||
| 5230 | if (shared_mac_range->low_5ghz_freq > non_shared_range->low_5ghz_freq) { | ||
| 5231 | ath12k_dbg(ab, ATH12K_DBG_WMI, "high 5 GHz shared"); | ||
| 5232 | /* If the shared mac lower 5 GHz frequency is greater than | ||
| 5233 | * non-shared mac lower 5 GHz frequency then the shared mac has | ||
| 5234 | * high 5 GHz shared with 2.4 GHz. So non-shared mac's 5 GHz high | ||
| 5235 | * freq should be less than the shared mac's low 5 GHz freq. | ||
| 5236 | */ | ||
| 5237 | if (non_shared_range->high_5ghz_freq >= | ||
| 5238 | shared_mac_range->low_5ghz_freq) | ||
| 5239 | non_shared_range->high_5ghz_freq = | ||
| 5240 | max_t(u32, shared_mac_range->low_5ghz_freq - 10, | ||
| 5241 | non_shared_range->low_5ghz_freq); | ||
| 5242 | } else if (shared_mac_range->high_5ghz_freq < | ||
| 5243 | non_shared_range->high_5ghz_freq) { | ||
| 5244 | ath12k_dbg(ab, ATH12K_DBG_WMI, "low 5 GHz shared"); | ||
| 5245 | /* If the shared mac high 5 GHz frequency is less than | ||
| 5246 | * non-shared mac high 5 GHz frequency then the shared mac has | ||
| 5247 | * low 5 GHz shared with 2.4 GHz. So non-shared mac's 5 GHz low | ||
| 5248 | * freq should be greater than the shared mac's high 5 GHz freq. | ||
| 5249 | */ | ||
| 5250 | if (shared_mac_range->high_5ghz_freq >= | ||
| 5251 | non_shared_range->low_5ghz_freq) | ||
| 5252 | non_shared_range->low_5ghz_freq = | ||
| 5253 | min_t(u32, shared_mac_range->high_5ghz_freq + 10, | ||
| 5254 | non_shared_range->high_5ghz_freq); | ||
| 5255 | } else { | ||
| 5256 | ath12k_warn(ab, "invalid SBS range with all 5 GHz shared"); | ||
| 5257 | return -EINVAL; | ||
| 5258 | } | ||
| 5259 | |||
| 5260 | return 0; | ||
| 5261 | } | ||
| 5262 | |||
| 5263 | static void ath12k_wmi_update_sbs_freq_info(struct ath12k_base *ab) | ||
| 5264 | { | ||
| 5265 | struct ath12k_hw_mode_info *hw_mode_info = &ab->wmi_ab.hw_mode_info; | ||
| 5266 | struct ath12k_hw_mode_freq_range_arg *mac_range; | ||
| 5267 | u16 sbs_range_sep; | ||
| 5268 | u8 phy_id; | ||
| 5269 | int ret; | ||
| 5270 | |||
| 5271 | mac_range = hw_mode_info->freq_range_caps[ATH12K_HW_MODE_SBS]; | ||
| 5272 | |||
| 5273 | /* If sbs_lower_band_end_freq has a value, then the frequency range | ||
| 5274 | * will be split using that value. | ||
| 5275 | */ | ||
| 5276 | sbs_range_sep = ab->wmi_ab.sbs_lower_band_end_freq; | ||
| 5277 | if (sbs_range_sep) { | ||
| 5278 | ath12k_wmi_fill_upper_share_sbs_freq(ab, sbs_range_sep, | ||
| 5279 | mac_range); | ||
| 5280 | ath12k_wmi_fill_lower_share_sbs_freq(ab, sbs_range_sep, | ||
| 5281 | mac_range); | ||
| 5282 | /* Hardware specifies the range boundary with sbs_range_sep, | ||
| 5283 | * (i.e. the boundary between 5 GHz high and 5 GHz low), | ||
| 5284 | * reset the original one to make sure it will not get used. | ||
| 5285 | */ | ||
| 5286 | memset(mac_range, 0, sizeof(*mac_range) * MAX_RADIOS); | ||
| 5287 | return; | ||
| 5288 | } | ||
| 5289 | |||
| 5290 | /* If sbs_lower_band_end_freq is not set that means firmware will send one | ||
| 5291 | * shared mac range and one non-shared mac range. so update that freq. | ||
| 5292 | */ | ||
| 5293 | for (phy_id = 0; phy_id < MAX_RADIOS; phy_id++) { | ||
| 5294 | ret = ath12k_wmi_modify_sbs_freq(ab, phy_id); | ||
| 5295 | if (ret) { | ||
| 5296 | memset(mac_range, 0, sizeof(*mac_range) * MAX_RADIOS); | ||
| 5297 | break; | ||
| 5298 | } | ||
| 5299 | } | ||
| 5300 | } | ||
| 5301 | |||
| 5302 | static void | ||
| 5303 | ath12k_wmi_update_mac_freq_info(struct ath12k_base *ab, | ||
| 5304 | enum wmi_host_hw_mode_config_type hw_config_type, | ||
| 5305 | u32 phy_id, | ||
| 5306 | struct ath12k_svc_ext_mac_phy_info *mac_cap) | ||
| 5307 | { | ||
| 5308 | if (phy_id >= MAX_RADIOS) { | ||
| 5309 | ath12k_err(ab, "mac more than two not supported: %d", phy_id); | ||
| 5310 | return; | ||
| 5311 | } | ||
| 5312 | |||
| 5313 | ath12k_dbg(ab, ATH12K_DBG_WMI, | ||
| 5314 | "hw_mode_cfg %d mac %d band 0x%x SBS cutoff freq %d 2 GHz [%d - %d] 5 GHz [%d - %d]", | ||
| 5315 | hw_config_type, phy_id, mac_cap->supported_bands, | ||
| 5316 | ab->wmi_ab.sbs_lower_band_end_freq, | ||
| 5317 | mac_cap->hw_freq_range.low_2ghz_freq, | ||
| 5318 | mac_cap->hw_freq_range.high_2ghz_freq, | ||
| 5319 | mac_cap->hw_freq_range.low_5ghz_freq, | ||
| 5320 | mac_cap->hw_freq_range.high_5ghz_freq); | ||
| 5321 | |||
| 5322 | switch (hw_config_type) { | ||
| 5323 | case WMI_HOST_HW_MODE_SINGLE: | ||
| 5324 | if (phy_id) { | ||
| 5325 | ath12k_dbg(ab, ATH12K_DBG_WMI, "mac phy 1 is not supported"); | ||
| 5326 | break; | ||
| 5327 | } | ||
| 5328 | ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_SMM, phy_id); | ||
| 5329 | break; | ||
| 5330 | |||
| 5331 | case WMI_HOST_HW_MODE_DBS: | ||
| 5332 | if (!ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_DBS)) | ||
| 5333 | ath12k_wmi_update_freq_info(ab, mac_cap, | ||
| 5334 | ATH12K_HW_MODE_DBS, phy_id); | ||
| 5335 | break; | ||
| 5336 | case WMI_HOST_HW_MODE_DBS_SBS: | ||
| 5337 | case WMI_HOST_HW_MODE_DBS_OR_SBS: | ||
| 5338 | ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_DBS, phy_id); | ||
| 5339 | if (ab->wmi_ab.sbs_lower_band_end_freq || | ||
| 5340 | mac_cap->hw_freq_range.low_5ghz_freq || | ||
| 5341 | mac_cap->hw_freq_range.low_2ghz_freq) | ||
| 5342 | ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_SBS, | ||
| 5343 | phy_id); | ||
| 5344 | |||
| 5345 | if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_DBS)) | ||
| 5346 | ath12k_wmi_update_dbs_freq_info(ab); | ||
| 5347 | if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS)) | ||
| 5348 | ath12k_wmi_update_sbs_freq_info(ab); | ||
| 5349 | break; | ||
| 5350 | case WMI_HOST_HW_MODE_SBS: | ||
| 5351 | case WMI_HOST_HW_MODE_SBS_PASSIVE: | ||
| 5352 | ath12k_wmi_update_freq_info(ab, mac_cap, ATH12K_HW_MODE_SBS, phy_id); | ||
| 5353 | if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS)) | ||
| 5354 | ath12k_wmi_update_sbs_freq_info(ab); | ||
| 5355 | |||
| 5356 | break; | ||
| 5357 | default: | ||
| 5358 | break; | ||
| 5359 | } | ||
| 5360 | } | ||
| 5361 | |||
| 5362 | static bool ath12k_wmi_sbs_range_present(struct ath12k_base *ab) | ||
| 5363 | { | ||
| 5364 | if (ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS) || | ||
| 5365 | (ab->wmi_ab.sbs_lower_band_end_freq && | ||
| 5366 | ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS_LOWER_SHARE) && | ||
| 5367 | ath12k_wmi_all_phy_range_updated(ab, ATH12K_HW_MODE_SBS_UPPER_SHARE))) | ||
| 5368 | return true; | ||
| 5369 | |||
| 5370 | return false; | ||
| 5371 | } | ||
| 5372 | |||
| 5373 | static int ath12k_wmi_update_hw_mode_list(struct ath12k_base *ab) | ||
| 5374 | { | ||
| 5375 | struct ath12k_svc_ext_info *svc_ext_info = &ab->wmi_ab.svc_ext_info; | ||
| 5376 | struct ath12k_hw_mode_info *info = &ab->wmi_ab.hw_mode_info; | ||
| 5377 | enum wmi_host_hw_mode_config_type hw_config_type; | ||
| 5378 | struct ath12k_svc_ext_mac_phy_info *tmp; | ||
| 5379 | bool dbs_mode = false, sbs_mode = false; | ||
| 5380 | u32 i, j = 0; | ||
| 5381 | |||
| 5382 | if (!svc_ext_info->num_hw_modes) { | ||
| 5383 | ath12k_err(ab, "invalid number of hw modes"); | ||
| 5384 | return -EINVAL; | ||
| 5385 | } | ||
| 5386 | |||
| 5387 | ath12k_dbg(ab, ATH12K_DBG_WMI, "updated HW mode list: num modes %d", | ||
| 5388 | svc_ext_info->num_hw_modes); | ||
| 5389 | |||
| 5390 | memset(info->freq_range_caps, 0, sizeof(info->freq_range_caps)); | ||
| 5391 | |||
| 5392 | for (i = 0; i < svc_ext_info->num_hw_modes; i++) { | ||
| 5393 | if (j >= ATH12K_MAX_MAC_PHY_CAP) | ||
| 5394 | return -EINVAL; | ||
| 5395 | |||
| 5396 | /* Update for MAC0 */ | ||
| 5397 | tmp = &svc_ext_info->mac_phy_info[j++]; | ||
| 5398 | hw_config_type = tmp->hw_mode_config_type; | ||
| 5399 | ath12k_wmi_update_mac_freq_info(ab, hw_config_type, tmp->phy_id, tmp); | ||
| 5400 | |||
| 5401 | /* SBS and DBS have dual MAC. Up to 2 MACs are considered. */ | ||
| 5402 | if (hw_config_type == WMI_HOST_HW_MODE_DBS || | ||
| 5403 | hw_config_type == WMI_HOST_HW_MODE_SBS_PASSIVE || | ||
| 5404 | hw_config_type == WMI_HOST_HW_MODE_SBS || | ||
| 5405 | hw_config_type == WMI_HOST_HW_MODE_DBS_OR_SBS) { | ||
| 5406 | if (j >= ATH12K_MAX_MAC_PHY_CAP) | ||
| 5407 | return -EINVAL; | ||
| 5408 | /* Update for MAC1 */ | ||
| 5409 | tmp = &svc_ext_info->mac_phy_info[j++]; | ||
| 5410 | ath12k_wmi_update_mac_freq_info(ab, hw_config_type, | ||
| 5411 | tmp->phy_id, tmp); | ||
| 5412 | |||
| 5413 | if (hw_config_type == WMI_HOST_HW_MODE_DBS || | ||
| 5414 | hw_config_type == WMI_HOST_HW_MODE_DBS_OR_SBS) | ||
| 5415 | dbs_mode = true; | ||
| 5416 | |||
| 5417 | if (ath12k_wmi_sbs_range_present(ab) && | ||
| 5418 | (hw_config_type == WMI_HOST_HW_MODE_SBS_PASSIVE || | ||
| 5419 | hw_config_type == WMI_HOST_HW_MODE_SBS || | ||
| 5420 | hw_config_type == WMI_HOST_HW_MODE_DBS_OR_SBS)) | ||
| 5421 | sbs_mode = true; | ||
| 5422 | } | ||
| 5423 | } | ||
| 5424 | |||
| 5425 | info->support_dbs = dbs_mode; | ||
| 5426 | info->support_sbs = sbs_mode; | ||
| 5427 | |||
| 5428 | ath12k_wmi_dump_freq_range(ab); | ||
| 5429 | |||
| 5430 | return 0; | ||
| 5431 | } | ||
| 5432 | |||
| 4925 | static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, | 5433 | static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, |
| 4926 | u16 tag, u16 len, | 5434 | u16 tag, u16 len, |
| 4927 | const void *ptr, void *data) | 5435 | const void *ptr, void *data) |
| 4928 | { | 5436 | { |
| 5437 | const struct ath12k_wmi_dbs_or_sbs_cap_params *dbs_or_sbs_caps; | ||
| 4929 | struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; | 5438 | struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; |
| 4930 | struct ath12k_wmi_svc_rdy_ext2_parse *parse = data; | 5439 | struct ath12k_wmi_svc_rdy_ext2_parse *parse = data; |
| 4931 | int ret; | 5440 | int ret; |
| @@ -4967,7 +5476,32 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, · 35 unmodified lines | |||
| 4967 | } | 5476 | } |
| 4968 | 5477 | ||
| 4969 | parse->mac_phy_caps_ext_done = true; | 5478 | parse->mac_phy_caps_ext_done = true; |
| 5479 | } else if (!parse->hal_reg_caps_ext2_done) { | ||
| 5480 | parse->hal_reg_caps_ext2_done = true; | ||
| 5481 | } else if (!parse->scan_radio_caps_ext2_done) { | ||
| 5482 | parse->scan_radio_caps_ext2_done = true; | ||
| 5483 | } else if (!parse->twt_caps_done) { | ||
| 5484 | parse->twt_caps_done = true; | ||
| 5485 | } else if (!parse->htt_msdu_idx_to_qtype_map_done) { | ||
| 5486 | parse->htt_msdu_idx_to_qtype_map_done = true; | ||
| 5487 | } else if (!parse->dbs_or_sbs_cap_ext_done) { | ||
| 5488 | dbs_or_sbs_caps = ptr; | ||
| 5489 | ab->wmi_ab.sbs_lower_band_end_freq = | ||
| 5490 | __le32_to_cpu(dbs_or_sbs_caps->sbs_lower_band_end_freq); | ||
| 5491 | |||
| 5492 | ath12k_dbg(ab, ATH12K_DBG_WMI, "sbs_lower_band_end_freq %u\n", | ||
| 5493 | ab->wmi_ab.sbs_lower_band_end_freq); | ||
| 5494 | |||
| 5495 | ret = ath12k_wmi_update_hw_mode_list(ab); | ||
| 5496 | if (ret) { | ||
| 5497 | ath12k_warn(ab, "failed to update hw mode list: %d\n", | ||
| 5498 | ret); | ||
| 5499 | return ret; | ||
| 5500 | } | ||
| 5501 | |||
| 5502 | parse->dbs_or_sbs_cap_ext_done = true; | ||
| 4970 | } | 5503 | } |
| 5504 | |||
| 4971 | break; | 5505 | break; |
| 4972 | default: | 5506 | default: |
| 4973 | break; | 5507 | break; |
| @@ -7626,6 +8160,64 @@ static int ath12k_wmi_pull_fw_stats(struct ath12k_base *ab, struct sk_buff *skb, · 2652 unmodified lines | |||
| 7626 | &parse); | 8160 | &parse); |
| 7627 | } | 8161 | } |
| 7628 | 8162 | ||
| 8163 | static void ath12k_wmi_fw_stats_process(struct ath12k *ar, | ||
| 8164 | struct ath12k_fw_stats *stats) | ||
| 8165 | { | ||
| 8166 | struct ath12k_base *ab = ar->ab; | ||
| 8167 | struct ath12k_pdev *pdev; | ||
| 8168 | bool is_end = true; | ||
| 8169 | size_t total_vdevs_started = 0; | ||
| 8170 | int i; | ||
| 8171 | |||
| 8172 | if (stats->stats_id == WMI_REQUEST_VDEV_STAT) { | ||
| 8173 | if (list_empty(&stats->vdevs)) { | ||
| 8174 | ath12k_warn(ab, "empty vdev stats"); | ||
| 8175 | return; | ||
| 8176 | } | ||
| 8177 | /* FW sends all the active VDEV stats irrespective of PDEV, | ||
| 8178 | * hence limit until the count of all VDEVs started | ||
| 8179 | */ | ||
| 8180 | rcu_read_lock(); | ||
| 8181 | for (i = 0; i < ab->num_radios; i++) { | ||
| 8182 | pdev = rcu_dereference(ab->pdevs_active[i]); | ||
| 8183 | if (pdev && pdev->ar) | ||
| 8184 | total_vdevs_started += pdev->ar->num_started_vdevs; | ||
| 8185 | } | ||
| 8186 | rcu_read_unlock(); | ||
| 8187 | |||
| 8188 | if (total_vdevs_started) | ||
| 8189 | is_end = ((++ar->fw_stats.num_vdev_recvd) == | ||
| 8190 | total_vdevs_started); | ||
| 8191 | |||
| 8192 | list_splice_tail_init(&stats->vdevs, | ||
| 8193 | &ar->fw_stats.vdevs); | ||
| 8194 | |||
| 8195 | if (is_end) | ||
| 8196 | complete(&ar->fw_stats_done); | ||
| 8197 | |||
| 8198 | return; | ||
| 8199 | } | ||
| 8200 | |||
| 8201 | if (stats->stats_id == WMI_REQUEST_BCN_STAT) { | ||
| 8202 | if (list_empty(&stats->bcn)) { | ||
| 8203 | ath12k_warn(ab, "empty beacon stats"); | ||
| 8204 | return; | ||
| 8205 | } | ||
| 8206 | /* Mark end until we reached the count of all started VDEVs | ||
| 8207 | * within the PDEV | ||
| 8208 | */ | ||
| 8209 | if (ar->num_started_vdevs) | ||
| 8210 | is_end = ((++ar->fw_stats.num_bcn_recvd) == | ||
| 8211 | ar->num_started_vdevs); | ||
| 8212 | |||
| 8213 | list_splice_tail_init(&stats->bcn, | ||
| 8214 | &ar->fw_stats.bcn); | ||
| 8215 | |||
| 8216 | if (is_end) | ||
| 8217 | complete(&ar->fw_stats_done); | ||
| 8218 | } | ||
| 8219 | } | ||
| 8220 | |||
| 7629 | static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb) | 8221 | static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb) |
| 7630 | { | 8222 | { |
| 7631 | struct ath12k_fw_stats stats = {}; | 8223 | struct ath12k_fw_stats stats = {}; |
| @@ -7655,19 +8247,15 @@ static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *sk · 23 unmodified lines | |||
| 7655 | 8247 | ||
| 7656 | spin_lock_bh(&ar->data_lock); | 8248 | spin_lock_bh(&ar->data_lock); |
| 7657 | 8249 | ||
| 7658 | /* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via | 8250 | /* Handle WMI_REQUEST_PDEV_STAT status update */ |
| 7659 | * debugfs fw stats. Therefore, processing it separately. | ||
| 7660 | */ | ||
| 7661 | if (stats.stats_id == WMI_REQUEST_PDEV_STAT) { | 8251 | if (stats.stats_id == WMI_REQUEST_PDEV_STAT) { |
| 7662 | list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs); | 8252 | list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs); |
| 7663 | ar->fw_stats.fw_stats_done = true; | 8253 | complete(&ar->fw_stats_done); |
| 7664 | goto complete; | 8254 | goto complete; |
| 7665 | } | 8255 | } |
| 7666 | 8256 | ||
| 7667 | /* WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT are currently requested only | 8257 | /* Handle WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT updates. */ |
| 7668 | * via debugfs fw stats. Hence, processing these in debugfs context. | 8258 | ath12k_wmi_fw_stats_process(ar, &stats); |
| 7669 | */ | ||
| 7670 | ath12k_debugfs_fw_stats_process(ar, &stats); | ||
| 7671 | 8259 | ||
| 7672 | complete: | 8260 | complete: |
| 7673 | complete(&ar->fw_stats_complete); | 8261 | complete(&ar->fw_stats_complete); |
| @@ -9911,3 +10499,224 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar, · 2237 unmodified lines | |||
| 9911 | 10499 | ||
| 9912 | return 0; | 10500 | return 0; |
| 9913 | } | 10501 | } |
| 10502 | |||
| 10503 | static int | ||
| 10504 | ath12k_wmi_fill_disallowed_bmap(struct ath12k_base *ab, | ||
| 10505 | struct wmi_disallowed_mlo_mode_bitmap_params *dislw_bmap, | ||
| 10506 | struct wmi_mlo_link_set_active_arg *arg) | ||
| 10507 | { | ||
| 10508 | struct wmi_ml_disallow_mode_bmap_arg *dislw_bmap_arg; | ||
| 10509 | u8 i; | ||
| 10510 | |||
| 10511 | if (arg->num_disallow_mode_comb > | ||
| 10512 | ARRAY_SIZE(arg->disallow_bmap)) { | ||
| 10513 | ath12k_warn(ab, "invalid num_disallow_mode_comb: %d", | ||
| 10514 | arg->num_disallow_mode_comb); | ||
| 10515 | return -EINVAL; | ||
| 10516 | } | ||
| 10517 | |||
| 10518 | dislw_bmap_arg = &arg->disallow_bmap[0]; | ||
| 10519 | for (i = 0; i < arg->num_disallow_mode_comb; i++) { | ||
| 10520 | dislw_bmap->tlv_header = | ||
| 10521 | ath12k_wmi_tlv_cmd_hdr(0, sizeof(*dislw_bmap)); | ||
| 10522 | dislw_bmap->disallowed_mode_bitmap = | ||
| 10523 | cpu_to_le32(dislw_bmap_arg->disallowed_mode); | ||
| 10524 | dislw_bmap->ieee_link_id_comb = | ||
| 10525 | le32_encode_bits(dislw_bmap_arg->ieee_link_id[0], | ||
| 10526 | WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_1) | | ||
| 10527 | le32_encode_bits(dislw_bmap_arg->ieee_link_id[1], | ||
| 10528 | WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_2) | | ||
| 10529 | le32_encode_bits(dislw_bmap_arg->ieee_link_id[2], | ||
| 10530 | WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_3) | | ||
| 10531 | le32_encode_bits(dislw_bmap_arg->ieee_link_id[3], | ||
| 10532 | WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_4); | ||
| 10533 | |||
| 10534 | ath12k_dbg(ab, ATH12K_DBG_WMI, | ||
| 10535 | "entry %d disallowed_mode %d ieee_link_id_comb 0x%x", | ||
| 10536 | i, dislw_bmap_arg->disallowed_mode, | ||
| 10537 | dislw_bmap_arg->ieee_link_id_comb); | ||
| 10538 | dislw_bmap++; | ||
| 10539 | dislw_bmap_arg++; | ||
| 10540 | } | ||
| 10541 | |||
| 10542 | return 0; | ||
| 10543 | } | ||
| 10544 | |||
| 10545 | int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab, | ||
| 10546 | struct wmi_mlo_link_set_active_arg *arg) | ||
| 10547 | { | ||
| 10548 | struct wmi_disallowed_mlo_mode_bitmap_params *disallowed_mode_bmap; | ||
| 10549 | struct wmi_mlo_set_active_link_number_params *link_num_param; | ||
| 10550 | u32 num_link_num_param = 0, num_vdev_bitmap = 0; | ||
| 10551 | struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab; | ||
| 10552 | struct wmi_mlo_link_set_active_cmd *cmd; | ||
| 10553 | u32 num_inactive_vdev_bitmap = 0; | ||
| 10554 | u32 num_disallow_mode_comb = 0; | ||
| 10555 | struct wmi_tlv *tlv; | ||
| 10556 | struct sk_buff *skb; | ||
| 10557 | __le32 *vdev_bitmap; | ||
| 10558 | void *buf_ptr; | ||
| 10559 | int i, ret; | ||
| 10560 | u32 len; | ||
| 10561 | |||
| 10562 | if (!arg->num_vdev_bitmap && !arg->num_link_entry) { | ||
| 10563 | ath12k_warn(ab, "Invalid num_vdev_bitmap and num_link_entry"); | ||
| 10564 | return -EINVAL; | ||
| 10565 | } | ||
| 10566 | |||
| 10567 | switch (arg->force_mode) { | ||
| 10568 | case WMI_MLO_LINK_FORCE_MODE_ACTIVE_LINK_NUM: | ||
| 10569 | case WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM: | ||
| 10570 | num_link_num_param = arg->num_link_entry; | ||
| 10571 | fallthrough; | ||
| 10572 | case WMI_MLO_LINK_FORCE_MODE_ACTIVE: | ||
| 10573 | case WMI_MLO_LINK_FORCE_MODE_INACTIVE: | ||
| 10574 | case WMI_MLO_LINK_FORCE_MODE_NO_FORCE: | ||
| 10575 | num_vdev_bitmap = arg->num_vdev_bitmap; | ||
| 10576 | break; | ||
| 10577 | case WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE: | ||
| 10578 | num_vdev_bitmap = arg->num_vdev_bitmap; | ||
| 10579 | num_inactive_vdev_bitmap = arg->num_inactive_vdev_bitmap; | ||
| 10580 | break; | ||
| 10581 | default: | ||
| 10582 | ath12k_warn(ab, "Invalid force mode: %u", arg->force_mode); | ||
| 10583 | return -EINVAL; | ||
| 10584 | } | ||
| 10585 | |||
| 10586 | num_disallow_mode_comb = arg->num_disallow_mode_comb; | ||
| 10587 | len = sizeof(*cmd) + | ||
| 10588 | TLV_HDR_SIZE + sizeof(*link_num_param) * num_link_num_param + | ||
| 10589 | TLV_HDR_SIZE + sizeof(*vdev_bitmap) * num_vdev_bitmap + | ||
| 10590 | TLV_HDR_SIZE + TLV_HDR_SIZE + TLV_HDR_SIZE + | ||
| 10591 | TLV_HDR_SIZE + sizeof(*disallowed_mode_bmap) * num_disallow_mode_comb; | ||
| 10592 | if (arg->force_mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE) | ||
| 10593 | len += sizeof(*vdev_bitmap) * num_inactive_vdev_bitmap; | ||
| 10594 | |||
| 10595 | skb = ath12k_wmi_alloc_skb(wmi_ab, len); | ||
| 10596 | if (!skb) | ||
| 10597 | return -ENOMEM; | ||
| 10598 | |||
| 10599 | cmd = (struct wmi_mlo_link_set_active_cmd *)skb->data; | ||
| 10600 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_LINK_SET_ACTIVE_CMD, | ||
| 10601 | sizeof(*cmd)); | ||
| 10602 | cmd->force_mode = cpu_to_le32(arg->force_mode); | ||
| 10603 | cmd->reason = cpu_to_le32(arg->reason); | ||
| 10604 | ath12k_dbg(ab, ATH12K_DBG_WMI, | ||
| 10605 | "mode %d reason %d num_link_num_param %d num_vdev_bitmap %d inactive %d num_disallow_mode_comb %d", | ||
| 10606 | arg->force_mode, arg->reason, num_link_num_param, | ||
| 10607 | num_vdev_bitmap, num_inactive_vdev_bitmap, | ||
| 10608 | num_disallow_mode_comb); | ||
| 10609 | |||
| 10610 | buf_ptr = skb->data + sizeof(*cmd); | ||
| 10611 | tlv = buf_ptr; | ||
| 10612 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, | ||
| 10613 | sizeof(*link_num_param) * num_link_num_param); | ||
| 10614 | buf_ptr += TLV_HDR_SIZE; | ||
| 10615 | |||
| 10616 | if (num_link_num_param) { | ||
| 10617 | cmd->ctrl_flags = | ||
| 10618 | le32_encode_bits(arg->ctrl_flags.dync_force_link_num ? 1 : 0, | ||
| 10619 | CRTL_F_DYNC_FORCE_LINK_NUM); | ||
| 10620 | |||
| 10621 | link_num_param = buf_ptr; | ||
| 10622 | for (i = 0; i < num_link_num_param; i++) { | ||
| 10623 | link_num_param->tlv_header = | ||
| 10624 | ath12k_wmi_tlv_cmd_hdr(0, sizeof(*link_num_param)); | ||
| 10625 | link_num_param->num_of_link = | ||
| 10626 | cpu_to_le32(arg->link_num[i].num_of_link); | ||
| 10627 | link_num_param->vdev_type = | ||
| 10628 | cpu_to_le32(arg->link_num[i].vdev_type); | ||
| 10629 | link_num_param->vdev_subtype = | ||
| 10630 | cpu_to_le32(arg->link_num[i].vdev_subtype); | ||
| 10631 | link_num_param->home_freq = | ||
| 10632 | cpu_to_le32(arg->link_num[i].home_freq); | ||
| 10633 | ath12k_dbg(ab, ATH12K_DBG_WMI, | ||
| 10634 | "entry %d num_of_link %d vdev type %d subtype %d freq %d control_flags %d", | ||
| 10635 | i, arg->link_num[i].num_of_link, | ||
| 10636 | arg->link_num[i].vdev_type, | ||
| 10637 | arg->link_num[i].vdev_subtype, | ||
| 10638 | arg->link_num[i].home_freq, | ||
| 10639 | __le32_to_cpu(cmd->ctrl_flags)); | ||
| 10640 | link_num_param++; | ||
| 10641 | } | ||
| 10642 | |||
| 10643 | buf_ptr += sizeof(*link_num_param) * num_link_num_param; | ||
| 10644 | } | ||
| 10645 | |||
| 10646 | tlv = buf_ptr; | ||
| 10647 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, | ||
| 10648 | sizeof(*vdev_bitmap) * num_vdev_bitmap); | ||
| 10649 | buf_ptr += TLV_HDR_SIZE; | ||
| 10650 | |||
| 10651 | if (num_vdev_bitmap) { | ||
| 10652 | vdev_bitmap = buf_ptr; | ||
| 10653 | for (i = 0; i < num_vdev_bitmap; i++) { | ||
| 10654 | vdev_bitmap[i] = cpu_to_le32(arg->vdev_bitmap[i]); | ||
| 10655 | ath12k_dbg(ab, ATH12K_DBG_WMI, "entry %d vdev_id_bitmap 0x%x", | ||
| 10656 | i, arg->vdev_bitmap[i]); | ||
| 10657 | } | ||
| 10658 | |||
| 10659 | buf_ptr += sizeof(*vdev_bitmap) * num_vdev_bitmap; | ||
| 10660 | } | ||
| 10661 | |||
| 10662 | if (arg->force_mode == WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE) { | ||
| 10663 | tlv = buf_ptr; | ||
| 10664 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, | ||
| 10665 | sizeof(*vdev_bitmap) * | ||
| 10666 | num_inactive_vdev_bitmap); | ||
| 10667 | buf_ptr += TLV_HDR_SIZE; | ||
| 10668 | |||
| 10669 | if (num_inactive_vdev_bitmap) { | ||
| 10670 | vdev_bitmap = buf_ptr; | ||
| 10671 | for (i = 0; i < num_inactive_vdev_bitmap; i++) { | ||
| 10672 | vdev_bitmap[i] = | ||
| 10673 | cpu_to_le32(arg->inactive_vdev_bitmap[i]); | ||
| 10674 | ath12k_dbg(ab, ATH12K_DBG_WMI, | ||
| 10675 | "entry %d inactive_vdev_id_bitmap 0x%x", | ||
| 10676 | i, arg->inactive_vdev_bitmap[i]); | ||
| 10677 | } | ||
| 10678 | |||
| 10679 | buf_ptr += sizeof(*vdev_bitmap) * num_inactive_vdev_bitmap; | ||
| 10680 | } | ||
| 10681 | } else { | ||
| 10682 | /* add empty vdev bitmap2 tlv */ | ||
| 10683 | tlv = buf_ptr; | ||
| 10684 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0); | ||
| 10685 | buf_ptr += TLV_HDR_SIZE; | ||
| 10686 | } | ||
| 10687 | |||
| 10688 | /* add empty ieee_link_id_bitmap tlv */ | ||
| 10689 | tlv = buf_ptr; | ||
| 10690 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0); | ||
| 10691 | buf_ptr += TLV_HDR_SIZE; | ||
| 10692 | |||
| 10693 | /* add empty ieee_link_id_bitmap2 tlv */ | ||
| 10694 | tlv = buf_ptr; | ||
| 10695 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0); | ||
| 10696 | buf_ptr += TLV_HDR_SIZE; | ||
| 10697 | |||
| 10698 | tlv = buf_ptr; | ||
| 10699 | tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, | ||
| 10700 | sizeof(*disallowed_mode_bmap) * | ||
| 10701 | arg->num_disallow_mode_comb); | ||
| 10702 | buf_ptr += TLV_HDR_SIZE; | ||
| 10703 | |||
| 10704 | ret = ath12k_wmi_fill_disallowed_bmap(ab, buf_ptr, arg); | ||
| 10705 | if (ret) | ||
| 10706 | goto free_skb; | ||
| 10707 | |||
| 10708 | ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_MLO_LINK_SET_ACTIVE_CMDID); | ||
| 10709 | if (ret) { | ||
| 10710 | ath12k_warn(ab, | ||
| 10711 | "failed to send WMI_MLO_LINK_SET_ACTIVE_CMDID: %d\n", ret); | ||
| 10712 | goto free_skb; | ||
| 10713 | } | ||
| 10714 | |||
| 10715 | ath12k_dbg(ab, ATH12K_DBG_WMI, "WMI mlo link set active cmd"); | ||
| 10716 | |||
| 10717 | return ret; | ||
| 10718 | |||
| 10719 | free_skb: | ||
| 10720 | dev_kfree_skb(skb); | ||
| 10721 | return ret; | ||
| 10722 | } | ||
| @@ -1974,6 +1974,7 @@ enum wmi_tlv_tag { · 1973 unmodified lines | |||
| 1974 | WMI_TAG_TPC_STATS_CTL_PWR_TABLE_EVENT, | 1974 | WMI_TAG_TPC_STATS_CTL_PWR_TABLE_EVENT, |
| 1975 | WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5, | 1975 | WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5, |
| 1976 | WMI_TAG_VDEV_CH_POWER_INFO, | 1976 | WMI_TAG_VDEV_CH_POWER_INFO, |
| 1977 | WMI_TAG_MLO_LINK_SET_ACTIVE_CMD = 0x3BE, | ||
| 1977 | WMI_TAG_EHT_RATE_SET = 0x3C4, | 1978 | WMI_TAG_EHT_RATE_SET = 0x3C4, |
| 1978 | WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5, | 1979 | WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5, |
| 1979 | WMI_TAG_MLO_TX_SEND_PARAMS, | 1980 | WMI_TAG_MLO_TX_SEND_PARAMS, |
| @@ -2617,6 +2618,8 @@ struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params { · 637 unmodified lines | |||
| 2617 | __le32 num_chainmask_tables; | 2618 | __le32 num_chainmask_tables; |
| 2618 | } __packed; | 2619 | } __packed; |
| 2619 | 2620 | ||
| 2621 | #define WMI_HW_MODE_CAP_CFG_TYPE GENMASK(27, 0) | ||
| 2622 | |||
| 2620 | struct ath12k_wmi_hw_mode_cap_params { | 2623 | struct ath12k_wmi_hw_mode_cap_params { |
| 2621 | __le32 tlv_header; | 2624 | __le32 tlv_header; |
| 2622 | __le32 hw_mode_id; | 2625 | __le32 hw_mode_id; |
| @@ -2666,6 +2669,12 @@ struct ath12k_wmi_mac_phy_caps_params { · 43 unmodified lines | |||
| 2666 | __le32 he_cap_info_2g_ext; | 2669 | __le32 he_cap_info_2g_ext; |
| 2667 | __le32 he_cap_info_5g_ext; | 2670 | __le32 he_cap_info_5g_ext; |
| 2668 | __le32 he_cap_info_internal; | 2671 | __le32 he_cap_info_internal; |
| 2672 | __le32 wireless_modes; | ||
| 2673 | __le32 low_2ghz_chan_freq; | ||
| 2674 | __le32 high_2ghz_chan_freq; | ||
| 2675 | __le32 low_5ghz_chan_freq; | ||
| 2676 | __le32 high_5ghz_chan_freq; | ||
| 2677 | __le32 nss_ratio; | ||
| 2669 | } __packed; | 2678 | } __packed; |
| 2670 | 2679 | ||
| 2671 | struct ath12k_wmi_hal_reg_caps_ext_params { | 2680 | struct ath12k_wmi_hal_reg_caps_ext_params { |
| @@ -2739,6 +2748,11 @@ struct wmi_service_ready_ext2_event { · 67 unmodified lines | |||
| 2739 | __le32 default_num_msduq_supported_per_tid; | 2748 | __le32 default_num_msduq_supported_per_tid; |
| 2740 | } __packed; | 2749 | } __packed; |
| 2741 | 2750 | ||
| 2751 | struct ath12k_wmi_dbs_or_sbs_cap_params { | ||
| 2752 | __le32 hw_mode_id; | ||
| 2753 | __le32 sbs_lower_band_end_freq; | ||
| 2754 | } __packed; | ||
| 2755 | |||
| 2742 | struct ath12k_wmi_caps_ext_params { | 2756 | struct ath12k_wmi_caps_ext_params { |
| 2743 | __le32 hw_mode_id; | 2757 | __le32 hw_mode_id; |
| 2744 | __le32 pdev_and_hw_link_ids; | 2758 | __le32 pdev_and_hw_link_ids; |
| @@ -5049,6 +5063,53 @@ struct ath12k_wmi_pdev { · 2304 unmodified lines | |||
| 5049 | u32 rx_decap_mode; | 5063 | u32 rx_decap_mode; |
| 5050 | }; | 5064 | }; |
| 5051 | 5065 | ||
| 5066 | struct ath12k_hw_mode_freq_range_arg { | ||
| 5067 | u32 low_2ghz_freq; | ||
| 5068 | u32 high_2ghz_freq; | ||
| 5069 | u32 low_5ghz_freq; | ||
| 5070 | u32 high_5ghz_freq; | ||
| 5071 | }; | ||
| 5072 | |||
| 5073 | struct ath12k_svc_ext_mac_phy_info { | ||
| 5074 | enum wmi_host_hw_mode_config_type hw_mode_config_type; | ||
| 5075 | u32 phy_id; | ||
| 5076 | u32 supported_bands; | ||
| 5077 | struct ath12k_hw_mode_freq_range_arg hw_freq_range; | ||
| 5078 | }; | ||
| 5079 | |||
| 5080 | #define ATH12K_MAX_MAC_PHY_CAP 8 | ||
| 5081 | |||
| 5082 | struct ath12k_svc_ext_info { | ||
| 5083 | u32 num_hw_modes; | ||
| 5084 | struct ath12k_svc_ext_mac_phy_info mac_phy_info[ATH12K_MAX_MAC_PHY_CAP]; | ||
| 5085 | }; | ||
| 5086 | |||
| 5087 | /** | ||
| 5088 | * enum ath12k_hw_mode - enum for host mode | ||
| 5089 | * @ATH12K_HW_MODE_SMM: Single mac mode | ||
| 5090 | * @ATH12K_HW_MODE_DBS: DBS mode | ||
| 5091 | * @ATH12K_HW_MODE_SBS: SBS mode with either high share or low share | ||
| 5092 | * @ATH12K_HW_MODE_SBS_UPPER_SHARE: Higher 5 GHz shared with 2.4 GHz | ||
| 5093 | * @ATH12K_HW_MODE_SBS_LOWER_SHARE: Lower 5 GHz shared with 2.4 GHz | ||
| 5094 | * @ATH12K_HW_MODE_MAX: Max, used to indicate invalid mode | ||
| 5095 | */ | ||
| 5096 | enum ath12k_hw_mode { | ||
| 5097 | ATH12K_HW_MODE_SMM, | ||
| 5098 | ATH12K_HW_MODE_DBS, | ||
| 5099 | ATH12K_HW_MODE_SBS, | ||
| 5100 | ATH12K_HW_MODE_SBS_UPPER_SHARE, | ||
| 5101 | ATH12K_HW_MODE_SBS_LOWER_SHARE, | ||
| 5102 | ATH12K_HW_MODE_MAX, | ||
| 5103 | }; | ||
| 5104 | |||
| 5105 | struct ath12k_hw_mode_info { | ||
| 5106 | bool support_dbs:1; | ||
| 5107 | bool support_sbs:1; | ||
| 5108 | |||
| 5109 | struct ath12k_hw_mode_freq_range_arg freq_range_caps[ATH12K_HW_MODE_MAX] | ||
| 5110 | [MAX_RADIOS]; | ||
| 5111 | }; | ||
| 5112 | |||
| 5052 | struct ath12k_wmi_base { | 5113 | struct ath12k_wmi_base { |
| 5053 | struct ath12k_base *ab; | 5114 | struct ath12k_base *ab; |
| 5054 | struct ath12k_wmi_pdev wmi[MAX_RADIOS]; | 5115 | struct ath12k_wmi_pdev wmi[MAX_RADIOS]; |
| @@ -5066,6 +5127,10 @@ struct ath12k_wmi_base { · 11 unmodified lines | |||
| 5066 | enum wmi_host_hw_mode_config_type preferred_hw_mode; | 5127 | enum wmi_host_hw_mode_config_type preferred_hw_mode; |
| 5067 | 5128 | ||
| 5068 | struct ath12k_wmi_target_cap_arg *targ_cap; | 5129 | struct ath12k_wmi_target_cap_arg *targ_cap; |
| 5130 | |||
| 5131 | struct ath12k_svc_ext_info svc_ext_info; | ||
| 5132 | u32 sbs_lower_band_end_freq; | ||
| 5133 | struct ath12k_hw_mode_info hw_mode_info; | ||
| 5069 | }; | 5134 | }; |
| 5070 | 5135 | ||
| 5071 | struct wmi_pdev_set_bios_interface_cmd { | 5136 | struct wmi_pdev_set_bios_interface_cmd { |
| @@ -5997,6 +6062,118 @@ struct wmi_vdev_set_tpc_power_cmd { · 925 unmodified lines | |||
| 5997 | */ | 6062 | */ |
| 5998 | } __packed; | 6063 | } __packed; |
| 5999 | 6064 | ||
| 6065 | #define CRTL_F_DYNC_FORCE_LINK_NUM GENMASK(3, 2) | ||
| 6066 | |||
| 6067 | struct wmi_mlo_link_set_active_cmd { | ||
| 6068 | __le32 tlv_header; | ||
| 6069 | __le32 force_mode; | ||
| 6070 | __le32 reason; | ||
| 6071 | __le32 use_ieee_link_id_bitmap; | ||
| 6072 | struct ath12k_wmi_mac_addr_params ap_mld_mac_addr; | ||
| 6073 | __le32 ctrl_flags; | ||
| 6074 | } __packed; | ||
| 6075 | |||
| 6076 | struct wmi_mlo_set_active_link_number_params { | ||
| 6077 | __le32 tlv_header; | ||
| 6078 | __le32 num_of_link; | ||
| 6079 | __le32 vdev_type; | ||
| 6080 | __le32 vdev_subtype; | ||
| 6081 | __le32 home_freq; | ||
| 6082 | } __packed; | ||
| 6083 | |||
| 6084 | #define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_1 GENMASK(7, 0) | ||
| 6085 | #define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_2 GENMASK(15, 8) | ||
| 6086 | #define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_3 GENMASK(23, 16) | ||
| 6087 | #define WMI_DISALW_MLO_MODE_BMAP_IEEE_LINK_ID_COMB_4 GENMASK(31, 24) | ||
| 6088 | |||
| 6089 | struct wmi_disallowed_mlo_mode_bitmap_params { | ||
| 6090 | __le32 tlv_header; | ||
| 6091 | __le32 disallowed_mode_bitmap; | ||
| 6092 | __le32 ieee_link_id_comb; | ||
| 6093 | } __packed; | ||
| 6094 | |||
| 6095 | enum wmi_mlo_link_force_mode { | ||
| 6096 | WMI_MLO_LINK_FORCE_MODE_ACTIVE = 1, | ||
| 6097 | WMI_MLO_LINK_FORCE_MODE_INACTIVE = 2, | ||
| 6098 | WMI_MLO_LINK_FORCE_MODE_ACTIVE_LINK_NUM = 3, | ||
| 6099 | WMI_MLO_LINK_FORCE_MODE_INACTIVE_LINK_NUM = 4, | ||
| 6100 | WMI_MLO_LINK_FORCE_MODE_NO_FORCE = 5, | ||
| 6101 | WMI_MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE = 6, | ||
| 6102 | WMI_MLO_LINK_FORCE_MODE_NON_FORCE_UPDATE = 7, | ||
| 6103 | }; | ||
| 6104 | |||
| 6105 | enum wmi_mlo_link_force_reason { | ||
| 6106 | WMI_MLO_LINK_FORCE_REASON_NEW_CONNECT = 1, | ||
| 6107 | WMI_MLO_LINK_FORCE_REASON_NEW_DISCONNECT = 2, | ||
| 6108 | WMI_MLO_LINK_FORCE_REASON_LINK_REMOVAL = 3, | ||
| 6109 | WMI_MLO_LINK_FORCE_REASON_TDLS = 4, | ||
| 6110 | WMI_MLO_LINK_FORCE_REASON_REVERT_FAILURE = 5, | ||
| 6111 | WMI_MLO_LINK_FORCE_REASON_LINK_DELETE = 6, | ||
| 6112 | WMI_MLO_LINK_FORCE_REASON_SINGLE_LINK_EMLSR_OP = 7, | ||
| 6113 | }; | ||
| 6114 | |||
| 6115 | struct wmi_mlo_link_num_arg { | ||
| 6116 | u32 num_of_link; | ||
| 6117 | u32 vdev_type; | ||
| 6118 | u32 vdev_subtype; | ||
| 6119 | u32 home_freq; | ||
| 6120 | }; | ||
| 6121 | |||
| 6122 | struct wmi_mlo_control_flags_arg { | ||
| 6123 | bool overwrite_force_active_bitmap; | ||
| 6124 | bool overwrite_force_inactive_bitmap; | ||
| 6125 | bool dync_force_link_num; | ||
| 6126 | bool post_re_evaluate; | ||
| 6127 | u8 post_re_evaluate_loops; | ||
| 6128 | bool dont_reschedule_workqueue; | ||
| 6129 | }; | ||
| 6130 | |||
| 6131 | struct wmi_ml_link_force_cmd_arg { | ||
| 6132 | u8 ap_mld_mac_addr[ETH_ALEN]; | ||
| 6133 | u16 ieee_link_id_bitmap; | ||
| 6134 | u16 ieee_link_id_bitmap2; | ||
| 6135 | u8 link_num; | ||
| 6136 | }; | ||
| 6137 | |||
| 6138 | struct wmi_ml_disallow_mode_bmap_arg { | ||
| 6139 | u32 disallowed_mode; | ||
| 6140 | union { | ||
| 6141 | u32 ieee_link_id_comb; | ||
| 6142 | u8 ieee_link_id[4]; | ||
| 6143 | }; | ||
| 6144 | }; | ||
| 6145 | |||
| 6146 | /* maximum size of link number param array | ||
| 6147 | * for MLO link set active command | ||
| 6148 | */ | ||
| 6149 | #define WMI_MLO_LINK_NUM_SZ 2 | ||
| 6150 | |||
| 6151 | /* maximum size of vdev bitmap array for | ||
| 6152 | * MLO link set active command | ||
| 6153 | */ | ||
| 6154 | #define WMI_MLO_VDEV_BITMAP_SZ 2 | ||
| 6155 | |||
| 6156 | /* Max number of disallowed bitmap combination | ||
| 6157 | * sent to firmware | ||
| 6158 | */ | ||
| 6159 | #define WMI_ML_MAX_DISALLOW_BMAP_COMB 4 | ||
| 6160 | |||
| 6161 | struct wmi_mlo_link_set_active_arg { | ||
| 6162 | enum wmi_mlo_link_force_mode force_mode; | ||
| 6163 | enum wmi_mlo_link_force_reason reason; | ||
| 6164 | u32 num_link_entry; | ||
| 6165 | u32 num_vdev_bitmap; | ||
| 6166 | u32 num_inactive_vdev_bitmap; | ||
| 6167 | struct wmi_mlo_link_num_arg link_num[WMI_MLO_LINK_NUM_SZ]; | ||
| 6168 | u32 vdev_bitmap[WMI_MLO_VDEV_BITMAP_SZ]; | ||
| 6169 | u32 inactive_vdev_bitmap[WMI_MLO_VDEV_BITMAP_SZ]; | ||
| 6170 | struct wmi_mlo_control_flags_arg ctrl_flags; | ||
| 6171 | bool use_ieee_link_id; | ||
| 6172 | struct wmi_ml_link_force_cmd_arg force_cmd; | ||
| 6173 | u32 num_disallow_mode_comb; | ||
| 6174 | struct wmi_ml_disallow_mode_bmap_arg disallow_bmap[WMI_ML_MAX_DISALLOW_BMAP_COMB]; | ||
| 6175 | }; | ||
| 6176 | |||
| 6000 | void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, | 6177 | void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, |
| 6001 | struct ath12k_wmi_resource_config_arg *config); | 6178 | struct ath12k_wmi_resource_config_arg *config); |
| 6002 | void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, | 6179 | void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, |
| @@ -6195,5 +6372,6 @@ bool ath12k_wmi_supports_6ghz_cc_ext(struct ath12k *ar); · 192 unmodified lines | |||
| 6195 | int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar, | 6372 | int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar, |
| 6196 | u32 vdev_id, | 6373 | u32 vdev_id, |
| 6197 | struct ath12k_reg_tpc_power_info *param); | 6374 | struct ath12k_reg_tpc_power_info *param); |
| 6198 | 6375 | int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab, | |
| 6376 | struct wmi_mlo_link_set_active_arg *param); | ||
| 6199 | #endif | 6377 | #endif |
| @@ -87,7 +87,9 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, · 86 unmodified lines | |||
| 87 | * We need to do some backwards compatibility to make this work. | 87 | * We need to do some backwards compatibility to make this work. |
| 88 | */ | 88 | */ |
| 89 | if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) { | 89 | if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) { |
| 90 | WARN_ON(1); | 90 | ath6kl_err("mismatched byte count %d vs. expected %zd\n", |
| 91 | le32_to_cpu(targ_info->byte_count), | ||
| 92 | sizeof(*targ_info)); | ||
| 91 | return -EINVAL; | 93 | return -EINVAL; |
| 92 | } | 94 | } |
| 93 | 95 | ||
| @@ -438,14 +438,21 @@ static void carl9170_usb_rx_complete(struct urb *urb) · 437 unmodified lines | |||
| 438 | 438 | ||
| 439 | if (atomic_read(&ar->rx_anch_urbs) == 0) { | 439 | if (atomic_read(&ar->rx_anch_urbs) == 0) { |
| 440 | /* | 440 | /* |
| 441 | * The system is too slow to cope with | 441 | * At this point, either the system is too slow to |
| 442 | * the enormous workload. We have simply | 442 | * cope with the enormous workload (so we have simply |
| 443 | * run out of active rx urbs and this | 443 | * run out of active rx urbs and this unfortunately |
| 444 | * unfortunately leads to an unpredictable | 444 | * leads to an unpredictable device), or the device |
| 445 | * device. | 445 | * is not fully functional after an unsuccessful |
| 446 | * firmware loading attempts (so it doesn't pass | ||
| 447 | * ieee80211_register_hw() and there is no internal | ||
| 448 | * workqueue at all). | ||
| 446 | */ | 449 | */ |
| 447 | 450 | ||
| 448 | ieee80211_queue_work(ar->hw, &ar->ping_work); | 451 | if (ar->registered) |
| 452 | ieee80211_queue_work(ar->hw, &ar->ping_work); | ||
| 453 | else | ||
| 454 | pr_warn_once("device %s is not registered\n", | ||
| 455 | dev_name(&ar->udev->dev)); | ||
| 449 | } | 456 | } |
| 450 | } else { | 457 | } else { |
| 451 | /* | 458 | /* |
| @@ -1316,6 +1316,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, · 1315 unmodified lines | |||
| 1316 | sizeof(trans->conf.no_reclaim_cmds)); | 1316 | sizeof(trans->conf.no_reclaim_cmds)); |
| 1317 | memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds, | 1317 | memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds, |
| 1318 | sizeof(no_reclaim_cmds)); | 1318 | sizeof(no_reclaim_cmds)); |
| 1319 | trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); | ||
| 1319 | 1320 | ||
| 1320 | switch (iwlwifi_mod_params.amsdu_size) { | 1321 | switch (iwlwifi_mod_params.amsdu_size) { |
| 1321 | case IWL_AMSDU_DEF: | 1322 | case IWL_AMSDU_DEF: |
| @@ -77,6 +77,7 @@ void iwl_construct_mld(struct iwl_mld *mld, struct iwl_trans *trans, · 76 unmodified lines | |||
| 77 | 77 | ||
| 78 | /* Setup async RX handling */ | 78 | /* Setup async RX handling */ |
| 79 | spin_lock_init(&mld->async_handlers_lock); | 79 | spin_lock_init(&mld->async_handlers_lock); |
| 80 | INIT_LIST_HEAD(&mld->async_handlers_list); | ||
| 80 | wiphy_work_init(&mld->async_handlers_wk, | 81 | wiphy_work_init(&mld->async_handlers_wk, |
| 81 | iwl_mld_async_handlers_wk); | 82 | iwl_mld_async_handlers_wk); |
| 82 | 83 | ||
| @@ -34,7 +34,7 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, · 33 unmodified lines | |||
| 34 | WIDE_ID(MAC_CONF_GROUP, | 34 | WIDE_ID(MAC_CONF_GROUP, |
| 35 | MAC_CONFIG_CMD), 0); | 35 | MAC_CONFIG_CMD), 0); |
| 36 | 36 | ||
| 37 | if (WARN_ON(cmd_ver < 1 && cmd_ver > 3)) | 37 | if (WARN_ON(cmd_ver < 1 || cmd_ver > 3)) |
| 38 | return; | 38 | return; |
| 39 | 39 | ||
| 40 | cmd->id_and_color = cpu_to_le32(mvmvif->id); | 40 | cmd->id_and_color = cpu_to_le32(mvmvif->id); |
| @@ -166,7 +166,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, · 165 unmodified lines | |||
| 166 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); | 166 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 167 | struct iwl_context_info *ctxt_info; | 167 | struct iwl_context_info *ctxt_info; |
| 168 | struct iwl_context_info_rbd_cfg *rx_cfg; | 168 | struct iwl_context_info_rbd_cfg *rx_cfg; |
| 169 | u32 control_flags = 0, rb_size; | 169 | u32 control_flags = 0, rb_size, cb_size; |
| 170 | dma_addr_t phys; | 170 | dma_addr_t phys; |
| 171 | int ret; | 171 | int ret; |
| 172 | 172 | ||
| @@ -202,11 +202,12 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, · 29 unmodified lines | |||
| 202 | rb_size = IWL_CTXT_INFO_RB_SIZE_4K; | 202 | rb_size = IWL_CTXT_INFO_RB_SIZE_4K; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | WARN_ON(RX_QUEUE_CB_SIZE(iwl_trans_get_num_rbds(trans)) > 12); | 205 | cb_size = RX_QUEUE_CB_SIZE(iwl_trans_get_num_rbds(trans)); |
| 206 | if (WARN_ON(cb_size > 12)) | ||
| 207 | cb_size = 12; | ||
| 208 | |||
| 206 | control_flags = IWL_CTXT_INFO_TFD_FORMAT_LONG; | 209 | control_flags = IWL_CTXT_INFO_TFD_FORMAT_LONG; |
| 207 | control_flags |= | 210 | control_flags |= u32_encode_bits(cb_size, IWL_CTXT_INFO_RB_CB_SIZE); |
| 208 | u32_encode_bits(RX_QUEUE_CB_SIZE(iwl_trans_get_num_rbds(trans)), | ||
| 209 | IWL_CTXT_INFO_RB_CB_SIZE); | ||
| 210 | control_flags |= u32_encode_bits(rb_size, IWL_CTXT_INFO_RB_SIZE); | 211 | control_flags |= u32_encode_bits(rb_size, IWL_CTXT_INFO_RB_SIZE); |
| 211 | ctxt_info->control.control_flags = cpu_to_le32(control_flags); | 212 | ctxt_info->control.control_flags = cpu_to_le32(control_flags); |
| 212 | 213 | ||
| @@ -1278,7 +1278,7 @@ struct ieee80211_ext { · 1277 unmodified lines | |||
| 1278 | u8 sa[ETH_ALEN]; | 1278 | u8 sa[ETH_ALEN]; |
| 1279 | __le32 timestamp; | 1279 | __le32 timestamp; |
| 1280 | u8 change_seq; | 1280 | u8 change_seq; |
| 1281 | u8 variable[0]; | 1281 | u8 variable[]; |
| 1282 | } __packed s1g_beacon; | 1282 | } __packed s1g_beacon; |
| 1283 | } u; | 1283 | } u; |
| 1284 | } __packed __aligned(2); | 1284 | } __packed __aligned(2); |
| @@ -1536,7 +1536,7 @@ struct ieee80211_mgmt { · 251 unmodified lines | |||
| 1536 | u8 action_code; | 1536 | u8 action_code; |
| 1537 | u8 dialog_token; | 1537 | u8 dialog_token; |
| 1538 | __le16 capability; | 1538 | __le16 capability; |
| 1539 | u8 variable[0]; | 1539 | u8 variable[]; |
| 1540 | } __packed tdls_discover_resp; | 1540 | } __packed tdls_discover_resp; |
| 1541 | struct { | 1541 | struct { |
| 1542 | u8 action_code; | 1542 | u8 action_code; |
| @@ -1721,35 +1721,35 @@ struct ieee80211_tdls_data { · 178 unmodified lines | |||
| 1721 | struct { | 1721 | struct { |
| 1722 | u8 dialog_token; | 1722 | u8 dialog_token; |
| 1723 | __le16 capability; | 1723 | __le16 capability; |
| 1724 | u8 variable[0]; | 1724 | u8 variable[]; |
| 1725 | } __packed setup_req; | 1725 | } __packed setup_req; |
| 1726 | struct { | 1726 | struct { |
| 1727 | __le16 status_code; | 1727 | __le16 status_code; |
| 1728 | u8 dialog_token; | 1728 | u8 dialog_token; |
| 1729 | __le16 capability; | 1729 | __le16 capability; |
| 1730 | u8 variable[0]; | 1730 | u8 variable[]; |
| 1731 | } __packed setup_resp; | 1731 | } __packed setup_resp; |
| 1732 | struct { | 1732 | struct { |
| 1733 | __le16 status_code; | 1733 | __le16 status_code; |
| 1734 | u8 dialog_token; | 1734 | u8 dialog_token; |
| 1735 | u8 variable[0]; | 1735 | u8 variable[]; |
| 1736 | } __packed setup_cfm; | 1736 | } __packed setup_cfm; |
| 1737 | struct { | 1737 | struct { |
| 1738 | __le16 reason_code; | 1738 | __le16 reason_code; |
| 1739 | u8 variable[0]; | 1739 | u8 variable[]; |
| 1740 | } __packed teardown; | 1740 | } __packed teardown; |
| 1741 | struct { | 1741 | struct { |
| 1742 | u8 dialog_token; | 1742 | u8 dialog_token; |
| 1743 | u8 variable[0]; | 1743 | u8 variable[]; |
| 1744 | } __packed discover_req; | 1744 | } __packed discover_req; |
| 1745 | struct { | 1745 | struct { |
| 1746 | u8 target_channel; | 1746 | u8 target_channel; |
| 1747 | u8 oper_class; | 1747 | u8 oper_class; |
| 1748 | u8 variable[0]; | 1748 | u8 variable[]; |
| 1749 | } __packed chan_switch_req; | 1749 | } __packed chan_switch_req; |
| 1750 | struct { | 1750 | struct { |
| 1751 | __le16 status_code; | 1751 | __le16 status_code; |
| 1752 | u8 variable[0]; | 1752 | u8 variable[]; |
| 1753 | } __packed chan_switch_resp; | 1753 | } __packed chan_switch_resp; |
| 1754 | } u; | 1754 | } u; |
| 1755 | } __packed; | 1755 | } __packed; |
| @@ -1,10 +1,11 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* | 2 | /* |
| 3 | * Portions | 3 | * Portions |
| 4 | * Copyright (C) 2022 - 2024 Intel Corporation | 4 | * Copyright (C) 2022 - 2025 Intel Corporation |
| 5 | */ | 5 | */ |
| 6 | #ifndef __MAC80211_DEBUG_H | 6 | #ifndef __MAC80211_DEBUG_H |
| 7 | #define __MAC80211_DEBUG_H | 7 | #define __MAC80211_DEBUG_H |
| 8 | #include <linux/once_lite.h> | ||
| 8 | #include <net/cfg80211.h> | 9 | #include <net/cfg80211.h> |
| 9 | 10 | ||
| 10 | #ifdef CONFIG_MAC80211_OCB_DEBUG | 11 | #ifdef CONFIG_MAC80211_OCB_DEBUG |
| @@ -152,6 +153,8 @@ do { \ · 141 unmodified lines | |||
| 152 | else \ | 153 | else \ |
| 153 | _sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \ | 154 | _sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \ |
| 154 | } while (0) | 155 | } while (0) |
| 156 | #define link_err_once(link, fmt, ...) \ | ||
| 157 | DO_ONCE_LITE(link_err, link, fmt, ##__VA_ARGS__) | ||
| 155 | #define link_id_info(sdata, link_id, fmt, ...) \ | 158 | #define link_id_info(sdata, link_id, fmt, ...) \ |
| 156 | do { \ | 159 | do { \ |
| 157 | if (ieee80211_vif_is_mld(&sdata->vif)) \ | 160 | if (ieee80211_vif_is_mld(&sdata->vif)) \ |
| @@ -4432,6 +4432,10 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) · 4431 unmodified lines | |||
| 4432 | if (!multicast && | 4432 | if (!multicast && |
| 4433 | !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1)) | 4433 | !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1)) |
| 4434 | return false; | 4434 | return false; |
| 4435 | /* reject invalid/our STA address */ | ||
| 4436 | if (!is_valid_ether_addr(hdr->addr2) || | ||
| 4437 | ether_addr_equal(sdata->dev->dev_addr, hdr->addr2)) | ||
| 4438 | return false; | ||
| 4435 | if (!rx->sta) { | 4439 | if (!rx->sta) { |
| 4436 | int rate_idx; | 4440 | int rate_idx; |
| 4437 | if (status->encoding != RX_ENC_LEGACY) | 4441 | if (status->encoding != RX_ENC_LEGACY) |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 5 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
| 6 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | 6 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> |
| 7 | * Copyright 2013-2014 Intel Mobile Communications GmbH | 7 | * Copyright 2013-2014 Intel Mobile Communications GmbH |
| 8 | * Copyright (C) 2018-2024 Intel Corporation | 8 | * Copyright (C) 2018-2025 Intel Corporation |
| 9 | * | 9 | * |
| 10 | * Transmit and frame generation functions. | 10 | * Transmit and frame generation functions. |
| 11 | */ | 11 | */ |
| @@ -5016,12 +5016,25 @@ static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, · 5004 unmodified lines | |||
| 5016 | } | 5016 | } |
| 5017 | } | 5017 | } |
| 5018 | 5018 | ||
| 5019 | static u8 __ieee80211_beacon_update_cntdwn(struct beacon_data *beacon) | 5019 | static u8 __ieee80211_beacon_update_cntdwn(struct ieee80211_link_data *link, |
| 5020 | struct beacon_data *beacon) | ||
| 5020 | { | 5021 | { |
| 5021 | beacon->cntdwn_current_counter--; | 5022 | if (beacon->cntdwn_current_counter == 1) { |
| 5023 | /* | ||
| 5024 | * Channel switch handling is done by a worker thread while | ||
| 5025 | * beacons get pulled from hardware timers. It's therefore | ||
| 5026 | * possible that software threads are slow enough to not be | ||
| 5027 | * able to complete CSA handling in a single beacon interval, | ||
| 5028 | * in which case we get here. There isn't much to do about | ||
| 5029 | * it, other than letting the user know that the AP isn't | ||
| 5030 | * behaving correctly. | ||
| 5031 | */ | ||
| 5032 | link_err_once(link, | ||
| 5033 | "beacon TX faster than countdown (channel/color switch) completion\n"); | ||
| 5034 | return 0; | ||
| 5035 | } | ||
| 5022 | 5036 | ||
| 5023 | /* the counter should never reach 0 */ | 5037 | beacon->cntdwn_current_counter--; |
| 5024 | WARN_ON_ONCE(!beacon->cntdwn_current_counter); | ||
| 5025 | 5038 | ||
| 5026 | return beacon->cntdwn_current_counter; | 5039 | return beacon->cntdwn_current_counter; |
| 5027 | } | 5040 | } |
| @@ -5052,7 +5065,7 @@ u8 ieee80211_beacon_update_cntdwn(struct ieee80211_vif *vif, unsigned int link_i · 24 unmodified lines | |||
| 5052 | if (!beacon) | 5065 | if (!beacon) |
| 5053 | goto unlock; | 5066 | goto unlock; |
| 5054 | 5067 | ||
| 5055 | count = __ieee80211_beacon_update_cntdwn(beacon); | 5068 | count = __ieee80211_beacon_update_cntdwn(link, beacon); |
| 5056 | 5069 | ||
| 5057 | unlock: | 5070 | unlock: |
| 5058 | rcu_read_unlock(); | 5071 | rcu_read_unlock(); |
| @@ -5450,7 +5463,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, · 391 unmodified lines | |||
| 5450 | 5463 | ||
| 5451 | if (beacon->cntdwn_counter_offsets[0]) { | 5464 | if (beacon->cntdwn_counter_offsets[0]) { |
| 5452 | if (!is_template) | 5465 | if (!is_template) |
| 5453 | __ieee80211_beacon_update_cntdwn(beacon); | 5466 | __ieee80211_beacon_update_cntdwn(link, beacon); |
| 5454 | 5467 | ||
| 5455 | ieee80211_set_beacon_cntdwn(sdata, beacon, link); | 5468 | ieee80211_set_beacon_cntdwn(sdata, beacon, link); |
| 5456 | } | 5469 | } |
| @@ -5482,7 +5495,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, · 25 unmodified lines | |||
| 5482 | * for now we leave it consistent with overall | 5495 | * for now we leave it consistent with overall |
| 5483 | * mac80211's behavior. | 5496 | * mac80211's behavior. |
| 5484 | */ | 5497 | */ |
| 5485 | __ieee80211_beacon_update_cntdwn(beacon); | 5498 | __ieee80211_beacon_update_cntdwn(link, beacon); |
| 5486 | 5499 | ||
| 5487 | ieee80211_set_beacon_cntdwn(sdata, beacon, link); | 5500 | ieee80211_set_beacon_cntdwn(sdata, beacon, link); |
| 5488 | } | 5501 | } |