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 | 1216 | INIT_LIST_HEAD(&ar->fw_stats.pdevs); |
| 1217 | 1217 | INIT_LIST_HEAD(&ar->fw_stats.bcn); |
| 1218 | 1218 | init_completion(&ar->fw_stats_complete); |
| 1219 | + init_completion(&ar->fw_stats_done); | |
| 1219 | 1220 | } |
| 1220 | 1221 | |
| 1221 | 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 | 1229 | void ath12k_fw_stats_reset(struct ath12k *ar) |
| 1229 | 1230 | { |
| 1230 | 1231 | spin_lock_bh(&ar->data_lock); |
| 1231 | − ar->fw_stats.fw_stats_done = false; | |
| 1232 | 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 | 1235 | spin_unlock_bh(&ar->data_lock); |
| 1234 | 1236 | } |
| 1235 | 1237 | |
| @@ -601,6 +601,12 @@ struct ath12k_sta { · 600 unmodified lines | ||
| 601 | 601 | #define ATH12K_NUM_CHANS 101 |
| 602 | 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 | 610 | enum ath12k_hw_state { |
| 605 | 611 | ATH12K_HW_STATE_OFF, |
| 606 | 612 | ATH12K_HW_STATE_ON, |
| @@ -626,7 +632,8 @@ struct ath12k_fw_stats { · 19 unmodified lines | ||
| 626 | 632 | struct list_head pdevs; |
| 627 | 633 | struct list_head vdevs; |
| 628 | 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 | 639 | struct ath12k_dbg_htt_stats { |
| @@ -806,6 +813,7 @@ struct ath12k { · 173 unmodified lines | ||
| 806 | 813 | bool regdom_set_by_user; |
| 807 | 814 | |
| 808 | 815 | struct completion fw_stats_complete; |
| 816 | + struct completion fw_stats_done; | |
| 809 | 817 | |
| 810 | 818 | struct completion mlo_setup_done; |
| 811 | 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 | 1254 | static int ath12k_open_vdev_stats(struct inode *inode, struct file *file) |
| 1313 | 1255 | { |
| 1314 | 1256 | struct ath12k *ar = inode->i_private; |
| @@ -12,8 +12,6 @@ void ath12k_debugfs_soc_create(struct ath12k_base *ab); · 11 unmodified lines | ||
| 12 | 12 | void ath12k_debugfs_soc_destroy(struct ath12k_base *ab); |
| 13 | 13 | void ath12k_debugfs_register(struct ath12k *ar); |
| 14 | 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 | 15 | void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw, |
| 18 | 16 | struct ieee80211_vif *vif); |
| 19 | 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 | 127 | static inline bool ath12k_debugfs_is_extd_rx_stats_enabled(struct ath12k *ar) |
| 135 | 128 | { |
| 136 | 129 | return false; |
| @@ -4360,7 +4360,7 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 4359 unmodified lines | ||
| 4360 | 4360 | { |
| 4361 | 4361 | struct ath12k_base *ab = ar->ab; |
| 4362 | 4362 | struct ath12k_hw *ah = ath12k_ar_to_ah(ar); |
| 4363 | − unsigned long timeout, time_left; | |
| 4363 | + unsigned long time_left; | |
| 4364 | 4364 | int ret; |
| 4365 | 4365 | |
| 4366 | 4366 | guard(mutex)(&ah->hw_mutex); |
| @@ -4368,19 +4368,13 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 1 unmodified line | ||
| 4368 | 4368 | if (ah->state != ATH12K_HW_STATE_ON) |
| 4369 | 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 | 4371 | ath12k_fw_stats_reset(ar); |
| 4378 | 4372 | |
| 4379 | 4373 | reinit_completion(&ar->fw_stats_complete); |
| 4374 | + reinit_completion(&ar->fw_stats_done); | |
| 4380 | 4375 | |
| 4381 | 4376 | ret = ath12k_wmi_send_stats_request_cmd(ar, param->stats_id, |
| 4382 | 4377 | param->vdev_id, param->pdev_id); |
| 4383 | − | |
| 4384 | 4378 | if (ret) { |
| 4385 | 4379 | ath12k_warn(ab, "failed to request fw stats: %d\n", ret); |
| 4386 | 4380 | return ret; |
| @@ -4391,7 +4385,6 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 4 unmodified lines | ||
| 4391 | 4385 | param->pdev_id, param->vdev_id, param->stats_id); |
| 4392 | 4386 | |
| 4393 | 4387 | time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ); |
| 4394 | − | |
| 4395 | 4388 | if (!time_left) { |
| 4396 | 4389 | ath12k_warn(ab, "time out while waiting for get fw stats\n"); |
| 4397 | 4390 | return -ETIMEDOUT; |
| @@ -4400,20 +4393,15 @@ int ath12k_mac_get_fw_stats(struct ath12k *ar, · 2 unmodified lines | ||
| 4400 | 4393 | /* Firmware sends WMI_UPDATE_STATS_EVENTID back-to-back |
| 4401 | 4394 | * when stats data buffer limit is reached. fw_stats_complete |
| 4402 | 4395 | * is completed once host receives first event from firmware, but |
| 4403 | − * still end might not be marked in the TLV. | |
| 4404 | − * Below loop is to confirm that firmware completed sending all the event | |
| 4405 | − * and fw_stats_done is marked true when end is marked in the TLV. | |
| 4396 | + * still there could be more events following. Below is to wait | |
| 4397 | + * until firmware completes sending all the events. | |
| 4406 | 4398 | */ |
| 4407 | − for (;;) { | |
| 4408 | − if (time_after(jiffies, timeout)) | |
| 4409 | − break; | |
| 4410 | − spin_lock_bh(&ar->data_lock); | |
| 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); | |
| 4399 | + time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ); | |
| 4400 | + if (!time_left) { | |
| 4401 | + ath12k_warn(ab, "time out while waiting for fw stats done\n"); | |
| 4402 | + return -ETIMEDOUT; | |
| 4416 | 4403 | } |
| 4404 | + | |
| 4417 | 4405 | return 0; |
| 4418 | 4406 | } |
| 4419 | 4407 | |
| @@ -5890,6 +5878,327 @@ exit: · 1470 unmodified lines | ||
| 5890 | 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 | 6202 | static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, |
| 5894 | 6203 | struct ieee80211_vif *vif, |
| 5895 | 6204 | struct ieee80211_sta *sta, |
| @@ -5899,10 +6208,13 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, · 3 unmodified lines | ||
| 5899 | 6208 | struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); |
| 5900 | 6209 | struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); |
| 5901 | 6210 | struct ath12k_hw *ah = ath12k_hw_to_ah(hw); |
| 6211 | + struct ath12k_base *prev_ab = NULL, *ab; | |
| 5902 | 6212 | struct ath12k_link_vif *arvif; |
| 5903 | 6213 | struct ath12k_link_sta *arsta; |
| 5904 | 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 | 6218 | int ret; |
| 5907 | 6219 | |
| 5908 | 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 | 6284 | * about to move to the associated state. |
| 5973 | 6285 | */ |
| 5974 | 6286 | if (ieee80211_vif_is_mld(vif) && vif->type == NL80211_IFTYPE_STATION && |
| 5975 | − old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) | |
| 5976 | − ieee80211_set_active_links(vif, ieee80211_vif_usable_links(vif)); | |
| 6287 | + old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { | |
| 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 | 6306 | /* Handle all the other state transitions in generic way */ |
| 5979 | 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 | 6346 | /* IEEE80211_STA_NONE -> IEEE80211_STA_NOTEXIST: |
| 6001 | 6347 | * Remove the station from driver (handle ML sta here since that |
| 6002 | 6348 | * needs special handling. Normal sta will be handled in generic |
| @@ -54,6 +54,8 @@ struct ath12k_generic_iter { · 53 unmodified lines | ||
| 54 | 54 | #define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS |
| 55 | 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 | 59 | enum ath12k_supported_bw { |
| 58 | 60 | ATH12K_BW_20 = 0, |
| 59 | 61 | ATH12K_BW_40 = 1, |
| @@ -91,6 +91,11 @@ struct ath12k_wmi_svc_rdy_ext2_parse { · 90 unmodified lines | ||
| 91 | 91 | bool dma_ring_cap_done; |
| 92 | 92 | bool spectral_bin_scaling_done; |
| 93 | 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 | 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 | 4400 | static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, |
| 4396 | 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 | 4404 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
| 4399 | 4405 | const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps; |
| 4400 | 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", | |
| 4431 | − soc->wmi_ab.preferred_hw_mode); | |
| 4436 | + svc_ext_info->num_hw_modes = svc_rdy_ext->n_hw_mode_caps; | |
| 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 | 4441 | if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) |
| 4433 | 4442 | return -EINVAL; |
| 4434 | 4443 | |
| @@ -4658,6 +4667,65 @@ free_dir_buff: · 223 unmodified lines | ||
| 4658 | 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 | 4729 | static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab, |
| 4662 | 4730 | u16 tag, u16 len, |
| 4663 | 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 | 4774 | return ret; |
| 4707 | 4775 | } |
| 4708 | 4776 | |
| 4777 | + ath12k_wmi_save_all_mac_phy_info(ab, svc_rdy_ext); | |
| 4778 | + | |
| 4709 | 4779 | svc_rdy_ext->mac_phy_done = true; |
| 4710 | 4780 | } else if (!svc_rdy_ext->ext_hal_reg_done) { |
| 4711 | 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 | 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 | 5433 | static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, |
| 4926 | 5434 | u16 tag, u16 len, |
| 4927 | 5435 | const void *ptr, void *data) |
| 4928 | 5436 | { |
| 5437 | + const struct ath12k_wmi_dbs_or_sbs_cap_params *dbs_or_sbs_caps; | |
| 4929 | 5438 | struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; |
| 4930 | 5439 | struct ath12k_wmi_svc_rdy_ext2_parse *parse = data; |
| 4931 | 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 | 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 | 5505 | break; |
| 4972 | 5506 | default: |
| 4973 | 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 | 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 | 8221 | static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb) |
| 7630 | 8222 | { |
| 7631 | 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 | 8248 | spin_lock_bh(&ar->data_lock); |
| 7657 | 8249 | |
| 7658 | − /* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via | |
| 7659 | − * debugfs fw stats. Therefore, processing it separately. | |
| 7660 | − */ | |
| 8250 | + /* Handle WMI_REQUEST_PDEV_STAT status update */ | |
| 7661 | 8251 | if (stats.stats_id == WMI_REQUEST_PDEV_STAT) { |
| 7662 | 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 | 8254 | goto complete; |
| 7665 | 8255 | } |
| 7666 | 8256 | |
| 7667 | − /* WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT are currently requested only | |
| 7668 | − * via debugfs fw stats. Hence, processing these in debugfs context. | |
| 7669 | − */ | |
| 7670 | − ath12k_debugfs_fw_stats_process(ar, &stats); | |
| 8257 | + /* Handle WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT updates. */ | |
| 8258 | + ath12k_wmi_fw_stats_process(ar, &stats); | |
| 7671 | 8259 | |
| 7672 | 8260 | complete: |
| 7673 | 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 | 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 | 1974 | WMI_TAG_TPC_STATS_CTL_PWR_TABLE_EVENT, |
| 1975 | 1975 | WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5, |
| 1976 | 1976 | WMI_TAG_VDEV_CH_POWER_INFO, |
| 1977 | + WMI_TAG_MLO_LINK_SET_ACTIVE_CMD = 0x3BE, | |
| 1977 | 1978 | WMI_TAG_EHT_RATE_SET = 0x3C4, |
| 1978 | 1979 | WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5, |
| 1979 | 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 | 2618 | __le32 num_chainmask_tables; |
| 2618 | 2619 | } __packed; |
| 2619 | 2620 | |
| 2621 | +#define WMI_HW_MODE_CAP_CFG_TYPE GENMASK(27, 0) | |
| 2622 | + | |
| 2620 | 2623 | struct ath12k_wmi_hw_mode_cap_params { |
| 2621 | 2624 | __le32 tlv_header; |
| 2622 | 2625 | __le32 hw_mode_id; |
| @@ -2666,6 +2669,12 @@ struct ath12k_wmi_mac_phy_caps_params { · 43 unmodified lines | ||
| 2666 | 2669 | __le32 he_cap_info_2g_ext; |
| 2667 | 2670 | __le32 he_cap_info_5g_ext; |
| 2668 | 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 | 2678 | } __packed; |
| 2670 | 2679 | |
| 2671 | 2680 | struct ath12k_wmi_hal_reg_caps_ext_params { |
| @@ -2739,6 +2748,11 @@ struct wmi_service_ready_ext2_event { · 67 unmodified lines | ||
| 2739 | 2748 | __le32 default_num_msduq_supported_per_tid; |
| 2740 | 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 | 2756 | struct ath12k_wmi_caps_ext_params { |
| 2743 | 2757 | __le32 hw_mode_id; |
| 2744 | 2758 | __le32 pdev_and_hw_link_ids; |
| @@ -5049,6 +5063,53 @@ struct ath12k_wmi_pdev { · 2304 unmodified lines | ||
| 5049 | 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 | 5113 | struct ath12k_wmi_base { |
| 5053 | 5114 | struct ath12k_base *ab; |
| 5054 | 5115 | struct ath12k_wmi_pdev wmi[MAX_RADIOS]; |
| @@ -5066,6 +5127,10 @@ struct ath12k_wmi_base { · 11 unmodified lines | ||
| 5066 | 5127 | enum wmi_host_hw_mode_config_type preferred_hw_mode; |
| 5067 | 5128 | |
| 5068 | 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 | 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 | 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 | 6177 | void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, |
| 6001 | 6178 | struct ath12k_wmi_resource_config_arg *config); |
| 6002 | 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 | 6372 | int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar, |
| 6196 | 6373 | u32 vdev_id, |
| 6197 | 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 | 6377 | #endif |
| @@ -87,7 +87,9 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar, · 86 unmodified lines | ||
| 87 | 87 | * We need to do some backwards compatibility to make this work. |
| 88 | 88 | */ |
| 89 | 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 | 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 | 439 | if (atomic_read(&ar->rx_anch_urbs) == 0) { |
| 440 | 440 | /* |
| 441 | − * The system is too slow to cope with | |
| 442 | − * the enormous workload. We have simply | |
| 443 | − * run out of active rx urbs and this | |
| 444 | − * unfortunately leads to an unpredictable | |
| 445 | − * device. | |
| 441 | + * At this point, either the system is too slow to | |
| 442 | + * cope with the enormous workload (so we have simply | |
| 443 | + * run out of active rx urbs and this unfortunately | |
| 444 | + * leads to an unpredictable device), or the 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 | 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 | 1316 | sizeof(trans->conf.no_reclaim_cmds)); |
| 1317 | 1317 | memcpy(trans->conf.no_reclaim_cmds, no_reclaim_cmds, |
| 1318 | 1318 | sizeof(no_reclaim_cmds)); |
| 1319 | + trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); | |
| 1319 | 1320 | |
| 1320 | 1321 | switch (iwlwifi_mod_params.amsdu_size) { |
| 1321 | 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 | 78 | /* Setup async RX handling */ |
| 79 | 79 | spin_lock_init(&mld->async_handlers_lock); |
| 80 | + INIT_LIST_HEAD(&mld->async_handlers_list); | |
| 80 | 81 | wiphy_work_init(&mld->async_handlers_wk, |
| 81 | 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 | 34 | WIDE_ID(MAC_CONF_GROUP, |
| 35 | 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 | 38 | return; |
| 39 | 39 | |
| 40 | 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 | 166 | struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); |
| 167 | 167 | struct iwl_context_info *ctxt_info; |
| 168 | 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 | 170 | dma_addr_t phys; |
| 171 | 171 | int ret; |
| 172 | 172 | |
| @@ -202,11 +202,12 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, · 29 unmodified lines | ||
| 202 | 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 | 209 | control_flags = IWL_CTXT_INFO_TFD_FORMAT_LONG; |
| 207 | − control_flags |= | |
| 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(cb_size, IWL_CTXT_INFO_RB_CB_SIZE); | |
| 210 | 211 | control_flags |= u32_encode_bits(rb_size, IWL_CTXT_INFO_RB_SIZE); |
| 211 | 212 | ctxt_info->control.control_flags = cpu_to_le32(control_flags); |
| 212 | 213 | |
| @@ -1278,7 +1278,7 @@ struct ieee80211_ext { · 1277 unmodified lines | ||
| 1278 | 1278 | u8 sa[ETH_ALEN]; |
| 1279 | 1279 | __le32 timestamp; |
| 1280 | 1280 | u8 change_seq; |
| 1281 | − u8 variable[0]; | |
| 1281 | + u8 variable[]; | |
| 1282 | 1282 | } __packed s1g_beacon; |
| 1283 | 1283 | } u; |
| 1284 | 1284 | } __packed __aligned(2); |
| @@ -1536,7 +1536,7 @@ struct ieee80211_mgmt { · 251 unmodified lines | ||
| 1536 | 1536 | u8 action_code; |
| 1537 | 1537 | u8 dialog_token; |
| 1538 | 1538 | __le16 capability; |
| 1539 | − u8 variable[0]; | |
| 1539 | + u8 variable[]; | |
| 1540 | 1540 | } __packed tdls_discover_resp; |
| 1541 | 1541 | struct { |
| 1542 | 1542 | u8 action_code; |
| @@ -1721,35 +1721,35 @@ struct ieee80211_tdls_data { · 178 unmodified lines | ||
| 1721 | 1721 | struct { |
| 1722 | 1722 | u8 dialog_token; |
| 1723 | 1723 | __le16 capability; |
| 1724 | − u8 variable[0]; | |
| 1724 | + u8 variable[]; | |
| 1725 | 1725 | } __packed setup_req; |
| 1726 | 1726 | struct { |
| 1727 | 1727 | __le16 status_code; |
| 1728 | 1728 | u8 dialog_token; |
| 1729 | 1729 | __le16 capability; |
| 1730 | − u8 variable[0]; | |
| 1730 | + u8 variable[]; | |
| 1731 | 1731 | } __packed setup_resp; |
| 1732 | 1732 | struct { |
| 1733 | 1733 | __le16 status_code; |
| 1734 | 1734 | u8 dialog_token; |
| 1735 | − u8 variable[0]; | |
| 1735 | + u8 variable[]; | |
| 1736 | 1736 | } __packed setup_cfm; |
| 1737 | 1737 | struct { |
| 1738 | 1738 | __le16 reason_code; |
| 1739 | − u8 variable[0]; | |
| 1739 | + u8 variable[]; | |
| 1740 | 1740 | } __packed teardown; |
| 1741 | 1741 | struct { |
| 1742 | 1742 | u8 dialog_token; |
| 1743 | − u8 variable[0]; | |
| 1743 | + u8 variable[]; | |
| 1744 | 1744 | } __packed discover_req; |
| 1745 | 1745 | struct { |
| 1746 | 1746 | u8 target_channel; |
| 1747 | 1747 | u8 oper_class; |
| 1748 | − u8 variable[0]; | |
| 1748 | + u8 variable[]; | |
| 1749 | 1749 | } __packed chan_switch_req; |
| 1750 | 1750 | struct { |
| 1751 | 1751 | __le16 status_code; |
| 1752 | − u8 variable[0]; | |
| 1752 | + u8 variable[]; | |
| 1753 | 1753 | } __packed chan_switch_resp; |
| 1754 | 1754 | } u; |
| 1755 | 1755 | } __packed; |
| @@ -1,10 +1,11 @@ | ||
| 1 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | 2 | /* |
| 3 | 3 | * Portions |
| 4 | − * Copyright (C) 2022 - 2024 Intel Corporation | |
| 4 | + * Copyright (C) 2022 - 2025 Intel Corporation | |
| 5 | 5 | */ |
| 6 | 6 | #ifndef __MAC80211_DEBUG_H |
| 7 | 7 | #define __MAC80211_DEBUG_H |
| 8 | +#include <linux/once_lite.h> | |
| 8 | 9 | #include <net/cfg80211.h> |
| 9 | 10 | |
| 10 | 11 | #ifdef CONFIG_MAC80211_OCB_DEBUG |
| @@ -152,6 +153,8 @@ do { \ · 141 unmodified lines | ||
| 152 | 153 | else \ |
| 153 | 154 | _sdata_err((link)->sdata, fmt, ##__VA_ARGS__); \ |
| 154 | 155 | } while (0) |
| 156 | +#define link_err_once(link, fmt, ...) \ | |
| 157 | + DO_ONCE_LITE(link_err, link, fmt, ##__VA_ARGS__) | |
| 155 | 158 | #define link_id_info(sdata, link_id, fmt, ...) \ |
| 156 | 159 | do { \ |
| 157 | 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 | 4432 | if (!multicast && |
| 4433 | 4433 | !ether_addr_equal(sdata->dev->dev_addr, hdr->addr1)) |
| 4434 | 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 | 4439 | if (!rx->sta) { |
| 4436 | 4440 | int rate_idx; |
| 4437 | 4441 | if (status->encoding != RX_ENC_LEGACY) |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
| 6 | 6 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> |
| 7 | 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 | 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 */ | |
| 5024 | − WARN_ON_ONCE(!beacon->cntdwn_current_counter); | |
| 5037 | + beacon->cntdwn_current_counter--; | |
| 5025 | 5038 | |
| 5026 | 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 | 5065 | if (!beacon) |
| 5053 | 5066 | goto unlock; |
| 5054 | 5067 | |
| 5055 | − count = __ieee80211_beacon_update_cntdwn(beacon); | |
| 5068 | + count = __ieee80211_beacon_update_cntdwn(link, beacon); | |
| 5056 | 5069 | |
| 5057 | 5070 | unlock: |
| 5058 | 5071 | rcu_read_unlock(); |
| @@ -5450,7 +5463,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, · 391 unmodified lines | ||
| 5450 | 5463 | |
| 5451 | 5464 | if (beacon->cntdwn_counter_offsets[0]) { |
| 5452 | 5465 | if (!is_template) |
| 5453 | − __ieee80211_beacon_update_cntdwn(beacon); | |
| 5466 | + __ieee80211_beacon_update_cntdwn(link, beacon); | |
| 5454 | 5467 | |
| 5455 | 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 | 5495 | * for now we leave it consistent with overall |
| 5483 | 5496 | * mac80211's behavior. |
| 5484 | 5497 | */ |
| 5485 | − __ieee80211_beacon_update_cntdwn(beacon); | |
| 5498 | + __ieee80211_beacon_update_cntdwn(link, beacon); | |
| 5486 | 5499 | |
| 5487 | 5500 | ieee80211_set_beacon_cntdwn(sdata, beacon, link); |
| 5488 | 5501 | } |