1 | // SPDX-License-Identifier: BSD-3-Clause-Clear |
2 | /* |
3 | * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. |
4 | * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. |
5 | */ |
6 | #include <linux/skbuff.h> |
7 | #include <linux/ctype.h> |
8 | #include <net/mac80211.h> |
9 | #include <net/cfg80211.h> |
10 | #include <linux/completion.h> |
11 | #include <linux/if_ether.h> |
12 | #include <linux/types.h> |
13 | #include <linux/pci.h> |
14 | #include <linux/uuid.h> |
15 | #include <linux/time.h> |
16 | #include <linux/of.h> |
17 | #include "core.h" |
18 | #include "debug.h" |
19 | #include "mac.h" |
20 | #include "hw.h" |
21 | #include "peer.h" |
22 | #include "p2p.h" |
23 | |
24 | struct ath12k_wmi_svc_ready_parse { |
25 | bool wmi_svc_bitmap_done; |
26 | }; |
27 | |
28 | struct ath12k_wmi_dma_ring_caps_parse { |
29 | struct ath12k_wmi_dma_ring_caps_params *dma_ring_caps; |
30 | u32 n_dma_ring_caps; |
31 | }; |
32 | |
33 | struct ath12k_wmi_service_ext_arg { |
34 | u32 default_conc_scan_config_bits; |
35 | u32 default_fw_config_bits; |
36 | struct ath12k_wmi_ppe_threshold_arg ppet; |
37 | u32 he_cap_info; |
38 | u32 mpdu_density; |
39 | u32 max_bssid_rx_filters; |
40 | u32 num_hw_modes; |
41 | u32 num_phy; |
42 | }; |
43 | |
44 | struct ath12k_wmi_svc_rdy_ext_parse { |
45 | struct ath12k_wmi_service_ext_arg arg; |
46 | const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps; |
47 | const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps; |
48 | u32 n_hw_mode_caps; |
49 | u32 tot_phy_id; |
50 | struct ath12k_wmi_hw_mode_cap_params pref_hw_mode_caps; |
51 | struct ath12k_wmi_mac_phy_caps_params *mac_phy_caps; |
52 | u32 n_mac_phy_caps; |
53 | const struct ath12k_wmi_soc_hal_reg_caps_params *soc_hal_reg_caps; |
54 | const struct ath12k_wmi_hal_reg_caps_ext_params *ext_hal_reg_caps; |
55 | u32 n_ext_hal_reg_caps; |
56 | struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse; |
57 | bool hw_mode_done; |
58 | bool mac_phy_done; |
59 | bool ext_hal_reg_done; |
60 | bool mac_phy_chainmask_combo_done; |
61 | bool mac_phy_chainmask_cap_done; |
62 | bool oem_dma_ring_cap_done; |
63 | bool dma_ring_cap_done; |
64 | }; |
65 | |
66 | struct ath12k_wmi_svc_rdy_ext2_arg { |
67 | u32 reg_db_version; |
68 | u32 hw_min_max_tx_power_2ghz; |
69 | u32 hw_min_max_tx_power_5ghz; |
70 | u32 chwidth_num_peer_caps; |
71 | u32 preamble_puncture_bw; |
72 | u32 max_user_per_ppdu_ofdma; |
73 | u32 max_user_per_ppdu_mumimo; |
74 | u32 target_cap_flags; |
75 | u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE]; |
76 | u32 max_num_linkview_peers; |
77 | u32 max_num_msduq_supported_per_tid; |
78 | u32 default_num_msduq_supported_per_tid; |
79 | }; |
80 | |
81 | struct ath12k_wmi_svc_rdy_ext2_parse { |
82 | struct ath12k_wmi_svc_rdy_ext2_arg arg; |
83 | struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse; |
84 | bool dma_ring_cap_done; |
85 | bool spectral_bin_scaling_done; |
86 | bool mac_phy_caps_ext_done; |
87 | }; |
88 | |
89 | struct ath12k_wmi_rdy_parse { |
90 | u32 ; |
91 | }; |
92 | |
93 | struct ath12k_wmi_dma_buf_release_arg { |
94 | struct ath12k_wmi_dma_buf_release_fixed_params fixed; |
95 | const struct ath12k_wmi_dma_buf_release_entry_params *buf_entry; |
96 | const struct ath12k_wmi_dma_buf_release_meta_data_params *meta_data; |
97 | u32 num_buf_entry; |
98 | u32 num_meta; |
99 | bool buf_entry_done; |
100 | bool meta_data_done; |
101 | }; |
102 | |
103 | struct ath12k_wmi_tlv_policy { |
104 | size_t min_len; |
105 | }; |
106 | |
107 | struct wmi_tlv_mgmt_rx_parse { |
108 | const struct ath12k_wmi_mgmt_rx_params *fixed; |
109 | const u8 *frame_buf; |
110 | bool frame_buf_done; |
111 | }; |
112 | |
113 | static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { |
114 | [WMI_TAG_ARRAY_BYTE] = { .min_len = 0 }, |
115 | [WMI_TAG_ARRAY_UINT32] = { .min_len = 0 }, |
116 | [WMI_TAG_SERVICE_READY_EVENT] = { |
117 | .min_len = sizeof(struct wmi_service_ready_event) }, |
118 | [WMI_TAG_SERVICE_READY_EXT_EVENT] = { |
119 | .min_len = sizeof(struct wmi_service_ready_ext_event) }, |
120 | [WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS] = { |
121 | .min_len = sizeof(struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params) }, |
122 | [WMI_TAG_SOC_HAL_REG_CAPABILITIES] = { |
123 | .min_len = sizeof(struct ath12k_wmi_soc_hal_reg_caps_params) }, |
124 | [WMI_TAG_VDEV_START_RESPONSE_EVENT] = { |
125 | .min_len = sizeof(struct wmi_vdev_start_resp_event) }, |
126 | [WMI_TAG_PEER_DELETE_RESP_EVENT] = { |
127 | .min_len = sizeof(struct wmi_peer_delete_resp_event) }, |
128 | [WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT] = { |
129 | .min_len = sizeof(struct wmi_bcn_tx_status_event) }, |
130 | [WMI_TAG_VDEV_STOPPED_EVENT] = { |
131 | .min_len = sizeof(struct wmi_vdev_stopped_event) }, |
132 | [WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT] = { |
133 | .min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) }, |
134 | [WMI_TAG_MGMT_RX_HDR] = { |
135 | .min_len = sizeof(struct ath12k_wmi_mgmt_rx_params) }, |
136 | [WMI_TAG_MGMT_TX_COMPL_EVENT] = { |
137 | .min_len = sizeof(struct wmi_mgmt_tx_compl_event) }, |
138 | [WMI_TAG_SCAN_EVENT] = { |
139 | .min_len = sizeof(struct wmi_scan_event) }, |
140 | [WMI_TAG_PEER_STA_KICKOUT_EVENT] = { |
141 | .min_len = sizeof(struct wmi_peer_sta_kickout_event) }, |
142 | [WMI_TAG_ROAM_EVENT] = { |
143 | .min_len = sizeof(struct wmi_roam_event) }, |
144 | [WMI_TAG_CHAN_INFO_EVENT] = { |
145 | .min_len = sizeof(struct wmi_chan_info_event) }, |
146 | [WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT] = { |
147 | .min_len = sizeof(struct wmi_pdev_bss_chan_info_event) }, |
148 | [WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT] = { |
149 | .min_len = sizeof(struct wmi_vdev_install_key_compl_event) }, |
150 | [WMI_TAG_READY_EVENT] = { |
151 | .min_len = sizeof(struct ath12k_wmi_ready_event_min_params) }, |
152 | [WMI_TAG_SERVICE_AVAILABLE_EVENT] = { |
153 | .min_len = sizeof(struct wmi_service_available_event) }, |
154 | [WMI_TAG_PEER_ASSOC_CONF_EVENT] = { |
155 | .min_len = sizeof(struct wmi_peer_assoc_conf_event) }, |
156 | [WMI_TAG_RFKILL_EVENT] = { |
157 | .min_len = sizeof(struct wmi_rfkill_state_change_event) }, |
158 | [WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = { |
159 | .min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) }, |
160 | [WMI_TAG_HOST_SWFDA_EVENT] = { |
161 | .min_len = sizeof(struct wmi_fils_discovery_event) }, |
162 | [WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT] = { |
163 | .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, |
164 | [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { |
165 | .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, |
166 | [WMI_TAG_TWT_ENABLE_COMPLETE_EVENT] = { |
167 | .min_len = sizeof(struct wmi_twt_enable_event) }, |
168 | [WMI_TAG_TWT_DISABLE_COMPLETE_EVENT] = { |
169 | .min_len = sizeof(struct wmi_twt_disable_event) }, |
170 | [WMI_TAG_P2P_NOA_INFO] = { |
171 | .min_len = sizeof(struct ath12k_wmi_p2p_noa_info) }, |
172 | [WMI_TAG_P2P_NOA_EVENT] = { |
173 | .min_len = sizeof(struct wmi_p2p_noa_event) }, |
174 | }; |
175 | |
176 | static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) |
177 | { |
178 | return le32_encode_bits(v: cmd, WMI_TLV_TAG) | |
179 | le32_encode_bits(v: len, WMI_TLV_LEN); |
180 | } |
181 | |
182 | static __le32 ath12k_wmi_tlv_cmd_hdr(u32 cmd, u32 len) |
183 | { |
184 | return ath12k_wmi_tlv_hdr(cmd, len: len - TLV_HDR_SIZE); |
185 | } |
186 | |
187 | void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, |
188 | struct ath12k_wmi_resource_config_arg *config) |
189 | { |
190 | config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; |
191 | config->num_peers = ab->num_radios * |
192 | ath12k_core_get_max_peers_per_radio(ab); |
193 | config->num_tids = ath12k_core_get_max_num_tids(ab); |
194 | config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; |
195 | config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; |
196 | config->num_peer_keys = TARGET_NUM_PEER_KEYS; |
197 | config->ast_skid_limit = TARGET_AST_SKID_LIMIT; |
198 | config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; |
199 | config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; |
200 | config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI; |
201 | config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI; |
202 | config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI; |
203 | config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI; |
204 | |
205 | if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) |
206 | config->rx_decap_mode = TARGET_DECAP_MODE_RAW; |
207 | else |
208 | config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI; |
209 | |
210 | config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS; |
211 | config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV; |
212 | config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV; |
213 | config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES; |
214 | config->num_mcast_groups = TARGET_NUM_MCAST_GROUPS; |
215 | config->num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS; |
216 | config->mcast2ucast_mode = TARGET_MCAST2UCAST_MODE; |
217 | config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE; |
218 | config->num_wds_entries = TARGET_NUM_WDS_ENTRIES; |
219 | config->dma_burst_size = TARGET_DMA_BURST_SIZE; |
220 | config->rx_skip_defrag_timeout_dup_detection_check = |
221 | TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK; |
222 | config->vow_config = TARGET_VOW_CONFIG; |
223 | config->gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV; |
224 | config->num_msdu_desc = TARGET_NUM_MSDU_DESC; |
225 | config->beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD; |
226 | config->rx_batchmode = TARGET_RX_BATCHMODE; |
227 | /* Indicates host supports peer map v3 and unmap v2 support */ |
228 | config->peer_map_unmap_version = 0x32; |
229 | config->twt_ap_pdev_count = ab->num_radios; |
230 | config->twt_ap_sta_count = 1000; |
231 | |
232 | if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) |
233 | config->dp_peer_meta_data_ver = TARGET_RX_PEER_METADATA_VER_V1B; |
234 | } |
235 | |
236 | void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, |
237 | struct ath12k_wmi_resource_config_arg *config) |
238 | { |
239 | config->num_vdevs = 4; |
240 | config->num_peers = 16; |
241 | config->num_tids = 32; |
242 | |
243 | config->num_offload_peers = 3; |
244 | config->num_offload_reorder_buffs = 3; |
245 | config->num_peer_keys = TARGET_NUM_PEER_KEYS; |
246 | config->ast_skid_limit = TARGET_AST_SKID_LIMIT; |
247 | config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; |
248 | config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1; |
249 | config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI; |
250 | config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI; |
251 | config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI; |
252 | config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI; |
253 | config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI; |
254 | config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS; |
255 | config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV; |
256 | config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV; |
257 | config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES; |
258 | config->num_mcast_groups = 0; |
259 | config->num_mcast_table_elems = 0; |
260 | config->mcast2ucast_mode = 0; |
261 | config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE; |
262 | config->num_wds_entries = 0; |
263 | config->dma_burst_size = 0; |
264 | config->rx_skip_defrag_timeout_dup_detection_check = 0; |
265 | config->vow_config = TARGET_VOW_CONFIG; |
266 | config->gtk_offload_max_vdev = 2; |
267 | config->num_msdu_desc = 0x400; |
268 | config->beacon_tx_offload_max_vdev = 2; |
269 | config->rx_batchmode = TARGET_RX_BATCHMODE; |
270 | |
271 | config->peer_map_unmap_version = 0x1; |
272 | config->use_pdev_id = 1; |
273 | config->max_frag_entries = 0xa; |
274 | config->num_tdls_vdevs = 0x1; |
275 | config->num_tdls_conn_table_entries = 8; |
276 | config->beacon_tx_offload_max_vdev = 0x2; |
277 | config->num_multicast_filter_entries = 0x20; |
278 | config->num_wow_filters = 0x16; |
279 | config->num_keep_alive_pattern = 0; |
280 | } |
281 | |
282 | #define PRIMAP(_hw_mode_) \ |
283 | [_hw_mode_] = _hw_mode_##_PRI |
284 | |
285 | static const int ath12k_hw_mode_pri_map[] = { |
286 | PRIMAP(WMI_HOST_HW_MODE_SINGLE), |
287 | PRIMAP(WMI_HOST_HW_MODE_DBS), |
288 | PRIMAP(WMI_HOST_HW_MODE_SBS_PASSIVE), |
289 | PRIMAP(WMI_HOST_HW_MODE_SBS), |
290 | PRIMAP(WMI_HOST_HW_MODE_DBS_SBS), |
291 | PRIMAP(WMI_HOST_HW_MODE_DBS_OR_SBS), |
292 | /* keep last */ |
293 | PRIMAP(WMI_HOST_HW_MODE_MAX), |
294 | }; |
295 | |
296 | static int |
297 | ath12k_wmi_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len, |
298 | int (*iter)(struct ath12k_base *ab, u16 tag, u16 len, |
299 | const void *ptr, void *data), |
300 | void *data) |
301 | { |
302 | const void *begin = ptr; |
303 | const struct wmi_tlv *tlv; |
304 | u16 tlv_tag, tlv_len; |
305 | int ret; |
306 | |
307 | while (len > 0) { |
308 | if (len < sizeof(*tlv)) { |
309 | ath12k_err(ab, fmt: "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n" , |
310 | ptr - begin, len, sizeof(*tlv)); |
311 | return -EINVAL; |
312 | } |
313 | |
314 | tlv = ptr; |
315 | tlv_tag = le32_get_bits(v: tlv->header, WMI_TLV_TAG); |
316 | tlv_len = le32_get_bits(v: tlv->header, WMI_TLV_LEN); |
317 | ptr += sizeof(*tlv); |
318 | len -= sizeof(*tlv); |
319 | |
320 | if (tlv_len > len) { |
321 | ath12k_err(ab, fmt: "wmi tlv parse failure of tag %u at byte %zd (%zu bytes left, %u expected)\n" , |
322 | tlv_tag, ptr - begin, len, tlv_len); |
323 | return -EINVAL; |
324 | } |
325 | |
326 | if (tlv_tag < ARRAY_SIZE(ath12k_wmi_tlv_policies) && |
327 | ath12k_wmi_tlv_policies[tlv_tag].min_len && |
328 | ath12k_wmi_tlv_policies[tlv_tag].min_len > tlv_len) { |
329 | ath12k_err(ab, fmt: "wmi tlv parse failure of tag %u at byte %zd (%u bytes is less than min length %zu)\n" , |
330 | tlv_tag, ptr - begin, tlv_len, |
331 | ath12k_wmi_tlv_policies[tlv_tag].min_len); |
332 | return -EINVAL; |
333 | } |
334 | |
335 | ret = iter(ab, tlv_tag, tlv_len, ptr, data); |
336 | if (ret) |
337 | return ret; |
338 | |
339 | ptr += tlv_len; |
340 | len -= tlv_len; |
341 | } |
342 | |
343 | return 0; |
344 | } |
345 | |
346 | static int ath12k_wmi_tlv_iter_parse(struct ath12k_base *ab, u16 tag, u16 len, |
347 | const void *ptr, void *data) |
348 | { |
349 | const void **tb = data; |
350 | |
351 | if (tag < WMI_TAG_MAX) |
352 | tb[tag] = ptr; |
353 | |
354 | return 0; |
355 | } |
356 | |
357 | static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb, |
358 | const void *ptr, size_t len) |
359 | { |
360 | return ath12k_wmi_tlv_iter(ab: ar, ptr, len, iter: ath12k_wmi_tlv_iter_parse, |
361 | data: (void *)tb); |
362 | } |
363 | |
364 | static const void ** |
365 | ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, |
366 | struct sk_buff *skb, gfp_t gfp) |
367 | { |
368 | const void **tb; |
369 | int ret; |
370 | |
371 | tb = kcalloc(n: WMI_TAG_MAX, size: sizeof(*tb), flags: gfp); |
372 | if (!tb) |
373 | return ERR_PTR(error: -ENOMEM); |
374 | |
375 | ret = ath12k_wmi_tlv_parse(ar: ab, tb, ptr: skb->data, len: skb->len); |
376 | if (ret) { |
377 | kfree(objp: tb); |
378 | return ERR_PTR(error: ret); |
379 | } |
380 | |
381 | return tb; |
382 | } |
383 | |
384 | static int ath12k_wmi_cmd_send_nowait(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, |
385 | u32 cmd_id) |
386 | { |
387 | struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); |
388 | struct ath12k_base *ab = wmi->wmi_ab->ab; |
389 | struct wmi_cmd_hdr *cmd_hdr; |
390 | int ret; |
391 | |
392 | if (!skb_push(skb, len: sizeof(struct wmi_cmd_hdr))) |
393 | return -ENOMEM; |
394 | |
395 | cmd_hdr = (struct wmi_cmd_hdr *)skb->data; |
396 | cmd_hdr->cmd_id = le32_encode_bits(v: cmd_id, WMI_CMD_HDR_CMD_ID); |
397 | |
398 | memset(skb_cb, 0, sizeof(*skb_cb)); |
399 | ret = ath12k_htc_send(htc: &ab->htc, eid: wmi->eid, packet: skb); |
400 | |
401 | if (ret) |
402 | goto err_pull; |
403 | |
404 | return 0; |
405 | |
406 | err_pull: |
407 | skb_pull(skb, len: sizeof(struct wmi_cmd_hdr)); |
408 | return ret; |
409 | } |
410 | |
411 | int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, |
412 | u32 cmd_id) |
413 | { |
414 | struct ath12k_wmi_base *wmi_ab = wmi->wmi_ab; |
415 | int ret = -EOPNOTSUPP; |
416 | |
417 | might_sleep(); |
418 | |
419 | wait_event_timeout(wmi_ab->tx_credits_wq, ({ |
420 | ret = ath12k_wmi_cmd_send_nowait(wmi, skb, cmd_id); |
421 | |
422 | if (ret && test_bit(ATH12K_FLAG_CRASH_FLUSH, &wmi_ab->ab->dev_flags)) |
423 | ret = -ESHUTDOWN; |
424 | |
425 | (ret != -EAGAIN); |
426 | }), WMI_SEND_TIMEOUT_HZ); |
427 | |
428 | if (ret == -EAGAIN) |
429 | ath12k_warn(ab: wmi_ab->ab, fmt: "wmi command %d timeout\n" , cmd_id); |
430 | |
431 | return ret; |
432 | } |
433 | |
434 | static int ath12k_pull_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, |
435 | const void *ptr, |
436 | struct ath12k_wmi_service_ext_arg *arg) |
437 | { |
438 | const struct wmi_service_ready_ext_event *ev = ptr; |
439 | int i; |
440 | |
441 | if (!ev) |
442 | return -EINVAL; |
443 | |
444 | /* Move this to host based bitmap */ |
445 | arg->default_conc_scan_config_bits = |
446 | le32_to_cpu(ev->default_conc_scan_config_bits); |
447 | arg->default_fw_config_bits = le32_to_cpu(ev->default_fw_config_bits); |
448 | arg->he_cap_info = le32_to_cpu(ev->he_cap_info); |
449 | arg->mpdu_density = le32_to_cpu(ev->mpdu_density); |
450 | arg->max_bssid_rx_filters = le32_to_cpu(ev->max_bssid_rx_filters); |
451 | arg->ppet.numss_m1 = le32_to_cpu(ev->ppet.numss_m1); |
452 | arg->ppet.ru_bit_mask = le32_to_cpu(ev->ppet.ru_info); |
453 | |
454 | for (i = 0; i < WMI_MAX_NUM_SS; i++) |
455 | arg->ppet.ppet16_ppet8_ru3_ru0[i] = |
456 | le32_to_cpu(ev->ppet.ppet16_ppet8_ru3_ru0[i]); |
457 | |
458 | return 0; |
459 | } |
460 | |
461 | static int |
462 | ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, |
463 | struct ath12k_wmi_svc_rdy_ext_parse *svc, |
464 | u8 hw_mode_id, u8 phy_id, |
465 | struct ath12k_pdev *pdev) |
466 | { |
467 | const struct ath12k_wmi_mac_phy_caps_params *mac_caps; |
468 | const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps = svc->hw_caps; |
469 | const struct ath12k_wmi_hw_mode_cap_params *wmi_hw_mode_caps = svc->hw_mode_caps; |
470 | const struct ath12k_wmi_mac_phy_caps_params *wmi_mac_phy_caps = svc->mac_phy_caps; |
471 | struct ath12k_base *ab = wmi_handle->wmi_ab->ab; |
472 | struct ath12k_band_cap *cap_band; |
473 | struct ath12k_pdev_cap *pdev_cap = &pdev->cap; |
474 | struct ath12k_fw_pdev *fw_pdev; |
475 | u32 phy_map; |
476 | u32 hw_idx, phy_idx = 0; |
477 | int i; |
478 | |
479 | if (!hw_caps || !wmi_hw_mode_caps || !svc->soc_hal_reg_caps) |
480 | return -EINVAL; |
481 | |
482 | for (hw_idx = 0; hw_idx < le32_to_cpu(hw_caps->num_hw_modes); hw_idx++) { |
483 | if (hw_mode_id == le32_to_cpu(wmi_hw_mode_caps[hw_idx].hw_mode_id)) |
484 | break; |
485 | |
486 | phy_map = le32_to_cpu(wmi_hw_mode_caps[hw_idx].phy_id_map); |
487 | phy_idx = fls(x: phy_map); |
488 | } |
489 | |
490 | if (hw_idx == le32_to_cpu(hw_caps->num_hw_modes)) |
491 | return -EINVAL; |
492 | |
493 | phy_idx += phy_id; |
494 | if (phy_id >= le32_to_cpu(svc->soc_hal_reg_caps->num_phy)) |
495 | return -EINVAL; |
496 | |
497 | mac_caps = wmi_mac_phy_caps + phy_idx; |
498 | |
499 | pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(param: mac_caps); |
500 | pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); |
501 | pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); |
502 | |
503 | fw_pdev = &ab->fw_pdev[ab->fw_pdev_count]; |
504 | fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands); |
505 | fw_pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(param: mac_caps); |
506 | fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id); |
507 | ab->fw_pdev_count++; |
508 | |
509 | /* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from |
510 | * band to band for a single radio, need to see how this should be |
511 | * handled. |
512 | */ |
513 | if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2G_CAP) { |
514 | pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_2g); |
515 | pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_2g); |
516 | } else if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5G_CAP) { |
517 | pdev_cap->vht_cap = le32_to_cpu(mac_caps->vht_cap_info_5g); |
518 | pdev_cap->vht_mcs = le32_to_cpu(mac_caps->vht_supp_mcs_5g); |
519 | pdev_cap->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g); |
520 | pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_5g); |
521 | pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_5g); |
522 | } else { |
523 | return -EINVAL; |
524 | } |
525 | |
526 | /* tx/rx chainmask reported from fw depends on the actual hw chains used, |
527 | * For example, for 4x4 capable macphys, first 4 chains can be used for first |
528 | * mac and the remaining 4 chains can be used for the second mac or vice-versa. |
529 | * In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0 |
530 | * will be advertised for second mac or vice-versa. Compute the shift value |
531 | * for tx/rx chainmask which will be used to advertise supported ht/vht rates to |
532 | * mac80211. |
533 | */ |
534 | pdev_cap->tx_chain_mask_shift = |
535 | find_first_bit(addr: (unsigned long *)&pdev_cap->tx_chain_mask, size: 32); |
536 | pdev_cap->rx_chain_mask_shift = |
537 | find_first_bit(addr: (unsigned long *)&pdev_cap->rx_chain_mask, size: 32); |
538 | |
539 | if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2G_CAP) { |
540 | cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; |
541 | cap_band->phy_id = le32_to_cpu(mac_caps->phy_id); |
542 | cap_band->max_bw_supported = le32_to_cpu(mac_caps->max_bw_supported_2g); |
543 | cap_band->ht_cap_info = le32_to_cpu(mac_caps->ht_cap_info_2g); |
544 | cap_band->he_cap_info[0] = le32_to_cpu(mac_caps->he_cap_info_2g); |
545 | cap_band->he_cap_info[1] = le32_to_cpu(mac_caps->he_cap_info_2g_ext); |
546 | cap_band->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_2g); |
547 | for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++) |
548 | cap_band->he_cap_phy_info[i] = |
549 | le32_to_cpu(mac_caps->he_cap_phy_info_2g[i]); |
550 | |
551 | cap_band->he_ppet.numss_m1 = le32_to_cpu(mac_caps->he_ppet2g.numss_m1); |
552 | cap_band->he_ppet.ru_bit_mask = le32_to_cpu(mac_caps->he_ppet2g.ru_info); |
553 | |
554 | for (i = 0; i < WMI_MAX_NUM_SS; i++) |
555 | cap_band->he_ppet.ppet16_ppet8_ru3_ru0[i] = |
556 | le32_to_cpu(mac_caps->he_ppet2g.ppet16_ppet8_ru3_ru0[i]); |
557 | } |
558 | |
559 | if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5G_CAP) { |
560 | cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; |
561 | cap_band->phy_id = le32_to_cpu(mac_caps->phy_id); |
562 | cap_band->max_bw_supported = |
563 | le32_to_cpu(mac_caps->max_bw_supported_5g); |
564 | cap_band->ht_cap_info = le32_to_cpu(mac_caps->ht_cap_info_5g); |
565 | cap_band->he_cap_info[0] = le32_to_cpu(mac_caps->he_cap_info_5g); |
566 | cap_band->he_cap_info[1] = le32_to_cpu(mac_caps->he_cap_info_5g_ext); |
567 | cap_band->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g); |
568 | for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++) |
569 | cap_band->he_cap_phy_info[i] = |
570 | le32_to_cpu(mac_caps->he_cap_phy_info_5g[i]); |
571 | |
572 | cap_band->he_ppet.numss_m1 = le32_to_cpu(mac_caps->he_ppet5g.numss_m1); |
573 | cap_band->he_ppet.ru_bit_mask = le32_to_cpu(mac_caps->he_ppet5g.ru_info); |
574 | |
575 | for (i = 0; i < WMI_MAX_NUM_SS; i++) |
576 | cap_band->he_ppet.ppet16_ppet8_ru3_ru0[i] = |
577 | le32_to_cpu(mac_caps->he_ppet5g.ppet16_ppet8_ru3_ru0[i]); |
578 | |
579 | cap_band = &pdev_cap->band[NL80211_BAND_6GHZ]; |
580 | cap_band->max_bw_supported = |
581 | le32_to_cpu(mac_caps->max_bw_supported_5g); |
582 | cap_band->ht_cap_info = le32_to_cpu(mac_caps->ht_cap_info_5g); |
583 | cap_band->he_cap_info[0] = le32_to_cpu(mac_caps->he_cap_info_5g); |
584 | cap_band->he_cap_info[1] = le32_to_cpu(mac_caps->he_cap_info_5g_ext); |
585 | cap_band->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g); |
586 | for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++) |
587 | cap_band->he_cap_phy_info[i] = |
588 | le32_to_cpu(mac_caps->he_cap_phy_info_5g[i]); |
589 | |
590 | cap_band->he_ppet.numss_m1 = le32_to_cpu(mac_caps->he_ppet5g.numss_m1); |
591 | cap_band->he_ppet.ru_bit_mask = le32_to_cpu(mac_caps->he_ppet5g.ru_info); |
592 | |
593 | for (i = 0; i < WMI_MAX_NUM_SS; i++) |
594 | cap_band->he_ppet.ppet16_ppet8_ru3_ru0[i] = |
595 | le32_to_cpu(mac_caps->he_ppet5g.ppet16_ppet8_ru3_ru0[i]); |
596 | } |
597 | |
598 | return 0; |
599 | } |
600 | |
601 | static int |
602 | ath12k_pull_reg_cap_svc_rdy_ext(struct ath12k_wmi_pdev *wmi_handle, |
603 | const struct ath12k_wmi_soc_hal_reg_caps_params *reg_caps, |
604 | const struct ath12k_wmi_hal_reg_caps_ext_params *ext_caps, |
605 | u8 phy_idx, |
606 | struct ath12k_wmi_hal_reg_capabilities_ext_arg *param) |
607 | { |
608 | const struct ath12k_wmi_hal_reg_caps_ext_params *ext_reg_cap; |
609 | |
610 | if (!reg_caps || !ext_caps) |
611 | return -EINVAL; |
612 | |
613 | if (phy_idx >= le32_to_cpu(reg_caps->num_phy)) |
614 | return -EINVAL; |
615 | |
616 | ext_reg_cap = &ext_caps[phy_idx]; |
617 | |
618 | param->phy_id = le32_to_cpu(ext_reg_cap->phy_id); |
619 | param->eeprom_reg_domain = le32_to_cpu(ext_reg_cap->eeprom_reg_domain); |
620 | param->eeprom_reg_domain_ext = |
621 | le32_to_cpu(ext_reg_cap->eeprom_reg_domain_ext); |
622 | param->regcap1 = le32_to_cpu(ext_reg_cap->regcap1); |
623 | param->regcap2 = le32_to_cpu(ext_reg_cap->regcap2); |
624 | /* check if param->wireless_mode is needed */ |
625 | param->low_2ghz_chan = le32_to_cpu(ext_reg_cap->low_2ghz_chan); |
626 | param->high_2ghz_chan = le32_to_cpu(ext_reg_cap->high_2ghz_chan); |
627 | param->low_5ghz_chan = le32_to_cpu(ext_reg_cap->low_5ghz_chan); |
628 | param->high_5ghz_chan = le32_to_cpu(ext_reg_cap->high_5ghz_chan); |
629 | |
630 | return 0; |
631 | } |
632 | |
633 | static int ath12k_pull_service_ready_tlv(struct ath12k_base *ab, |
634 | const void *evt_buf, |
635 | struct ath12k_wmi_target_cap_arg *cap) |
636 | { |
637 | const struct wmi_service_ready_event *ev = evt_buf; |
638 | |
639 | if (!ev) { |
640 | ath12k_err(ab, fmt: "%s: failed by NULL param\n" , |
641 | __func__); |
642 | return -EINVAL; |
643 | } |
644 | |
645 | cap->phy_capability = le32_to_cpu(ev->phy_capability); |
646 | cap->max_frag_entry = le32_to_cpu(ev->max_frag_entry); |
647 | cap->num_rf_chains = le32_to_cpu(ev->num_rf_chains); |
648 | cap->ht_cap_info = le32_to_cpu(ev->ht_cap_info); |
649 | cap->vht_cap_info = le32_to_cpu(ev->vht_cap_info); |
650 | cap->vht_supp_mcs = le32_to_cpu(ev->vht_supp_mcs); |
651 | cap->hw_min_tx_power = le32_to_cpu(ev->hw_min_tx_power); |
652 | cap->hw_max_tx_power = le32_to_cpu(ev->hw_max_tx_power); |
653 | cap->sys_cap_info = le32_to_cpu(ev->sys_cap_info); |
654 | cap->min_pkt_size_enable = le32_to_cpu(ev->min_pkt_size_enable); |
655 | cap->max_bcn_ie_size = le32_to_cpu(ev->max_bcn_ie_size); |
656 | cap->max_num_scan_channels = le32_to_cpu(ev->max_num_scan_channels); |
657 | cap->max_supported_macs = le32_to_cpu(ev->max_supported_macs); |
658 | cap->wmi_fw_sub_feat_caps = le32_to_cpu(ev->wmi_fw_sub_feat_caps); |
659 | cap->txrx_chainmask = le32_to_cpu(ev->txrx_chainmask); |
660 | cap->default_dbs_hw_mode_index = le32_to_cpu(ev->default_dbs_hw_mode_index); |
661 | cap->num_msdu_desc = le32_to_cpu(ev->num_msdu_desc); |
662 | |
663 | return 0; |
664 | } |
665 | |
666 | /* Save the wmi_service_bitmap into a linear bitmap. The wmi_services in |
667 | * wmi_service ready event are advertised in b0-b3 (LSB 4-bits) of each |
668 | * 4-byte word. |
669 | */ |
670 | static void ath12k_wmi_service_bitmap_copy(struct ath12k_wmi_pdev *wmi, |
671 | const u32 *wmi_svc_bm) |
672 | { |
673 | int i, j; |
674 | |
675 | for (i = 0, j = 0; i < WMI_SERVICE_BM_SIZE && j < WMI_MAX_SERVICE; i++) { |
676 | do { |
677 | if (wmi_svc_bm[i] & BIT(j % WMI_SERVICE_BITS_IN_SIZE32)) |
678 | set_bit(nr: j, addr: wmi->wmi_ab->svc_map); |
679 | } while (++j % WMI_SERVICE_BITS_IN_SIZE32); |
680 | } |
681 | } |
682 | |
683 | static int ath12k_wmi_svc_rdy_parse(struct ath12k_base *ab, u16 tag, u16 len, |
684 | const void *ptr, void *data) |
685 | { |
686 | struct ath12k_wmi_svc_ready_parse *svc_ready = data; |
687 | struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; |
688 | u16 expect_len; |
689 | |
690 | switch (tag) { |
691 | case WMI_TAG_SERVICE_READY_EVENT: |
692 | if (ath12k_pull_service_ready_tlv(ab, evt_buf: ptr, cap: &ab->target_caps)) |
693 | return -EINVAL; |
694 | break; |
695 | |
696 | case WMI_TAG_ARRAY_UINT32: |
697 | if (!svc_ready->wmi_svc_bitmap_done) { |
698 | expect_len = WMI_SERVICE_BM_SIZE * sizeof(u32); |
699 | if (len < expect_len) { |
700 | ath12k_warn(ab, fmt: "invalid len %d for the tag 0x%x\n" , |
701 | len, tag); |
702 | return -EINVAL; |
703 | } |
704 | |
705 | ath12k_wmi_service_bitmap_copy(wmi: wmi_handle, wmi_svc_bm: ptr); |
706 | |
707 | svc_ready->wmi_svc_bitmap_done = true; |
708 | } |
709 | break; |
710 | default: |
711 | break; |
712 | } |
713 | |
714 | return 0; |
715 | } |
716 | |
717 | static int ath12k_service_ready_event(struct ath12k_base *ab, struct sk_buff *skb) |
718 | { |
719 | struct ath12k_wmi_svc_ready_parse svc_ready = { }; |
720 | int ret; |
721 | |
722 | ret = ath12k_wmi_tlv_iter(ab, ptr: skb->data, len: skb->len, |
723 | iter: ath12k_wmi_svc_rdy_parse, |
724 | data: &svc_ready); |
725 | if (ret) { |
726 | ath12k_warn(ab, fmt: "failed to parse tlv %d\n" , ret); |
727 | return ret; |
728 | } |
729 | |
730 | return 0; |
731 | } |
732 | |
733 | static u32 ath12k_wmi_mgmt_get_freq(struct ath12k *ar, |
734 | struct ieee80211_tx_info *info) |
735 | { |
736 | struct ath12k_base *ab = ar->ab; |
737 | u32 freq = 0; |
738 | |
739 | if (ab->hw_params->single_pdev_only && |
740 | ar->scan.is_roc && |
741 | (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) |
742 | freq = ar->scan.roc_freq; |
743 | |
744 | return freq; |
745 | } |
746 | |
747 | struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len) |
748 | { |
749 | struct sk_buff *skb; |
750 | struct ath12k_base *ab = wmi_ab->ab; |
751 | u32 round_len = roundup(len, 4); |
752 | |
753 | skb = ath12k_htc_alloc_skb(ar: ab, WMI_SKB_HEADROOM + round_len); |
754 | if (!skb) |
755 | return NULL; |
756 | |
757 | skb_reserve(skb, WMI_SKB_HEADROOM); |
758 | if (!IS_ALIGNED((unsigned long)skb->data, 4)) |
759 | ath12k_warn(ab, fmt: "unaligned WMI skb data\n" ); |
760 | |
761 | skb_put(skb, len: round_len); |
762 | memset(skb->data, 0, round_len); |
763 | |
764 | return skb; |
765 | } |
766 | |
767 | int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, |
768 | struct sk_buff *frame) |
769 | { |
770 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
771 | struct wmi_mgmt_send_cmd *cmd; |
772 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb: frame); |
773 | struct wmi_tlv *frame_tlv; |
774 | struct sk_buff *skb; |
775 | u32 buf_len; |
776 | int ret, len; |
777 | |
778 | buf_len = min_t(int, frame->len, WMI_MGMT_SEND_DOWNLD_LEN); |
779 | |
780 | len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4); |
781 | |
782 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
783 | if (!skb) |
784 | return -ENOMEM; |
785 | |
786 | cmd = (struct wmi_mgmt_send_cmd *)skb->data; |
787 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_MGMT_TX_SEND_CMD, |
788 | len: sizeof(*cmd)); |
789 | cmd->vdev_id = cpu_to_le32(vdev_id); |
790 | cmd->desc_id = cpu_to_le32(buf_id); |
791 | cmd->chanfreq = cpu_to_le32(ath12k_wmi_mgmt_get_freq(ar, info)); |
792 | cmd->paddr_lo = cpu_to_le32(lower_32_bits(ATH12K_SKB_CB(frame)->paddr)); |
793 | cmd->paddr_hi = cpu_to_le32(upper_32_bits(ATH12K_SKB_CB(frame)->paddr)); |
794 | cmd->frame_len = cpu_to_le32(frame->len); |
795 | cmd->buf_len = cpu_to_le32(buf_len); |
796 | cmd->tx_params_valid = 0; |
797 | |
798 | frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd)); |
799 | frame_tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len: buf_len); |
800 | |
801 | memcpy(frame_tlv->value, frame->data, buf_len); |
802 | |
803 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_MGMT_TX_SEND_CMDID); |
804 | if (ret) { |
805 | ath12k_warn(ab: ar->ab, |
806 | fmt: "failed to submit WMI_MGMT_TX_SEND_CMDID cmd\n" ); |
807 | dev_kfree_skb(skb); |
808 | } |
809 | |
810 | return ret; |
811 | } |
812 | |
813 | int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr, |
814 | struct ath12k_wmi_vdev_create_arg *args) |
815 | { |
816 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
817 | struct wmi_vdev_create_cmd *cmd; |
818 | struct sk_buff *skb; |
819 | struct ath12k_wmi_vdev_txrx_streams_params *txrx_streams; |
820 | struct wmi_tlv *tlv; |
821 | int ret, len; |
822 | void *ptr; |
823 | |
824 | /* It can be optimized my sending tx/rx chain configuration |
825 | * only for supported bands instead of always sending it for |
826 | * both the bands. |
827 | */ |
828 | len = sizeof(*cmd) + TLV_HDR_SIZE + |
829 | (WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams)); |
830 | |
831 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
832 | if (!skb) |
833 | return -ENOMEM; |
834 | |
835 | cmd = (struct wmi_vdev_create_cmd *)skb->data; |
836 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_CREATE_CMD, |
837 | len: sizeof(*cmd)); |
838 | |
839 | cmd->vdev_id = cpu_to_le32(args->if_id); |
840 | cmd->vdev_type = cpu_to_le32(args->type); |
841 | cmd->vdev_subtype = cpu_to_le32(args->subtype); |
842 | cmd->num_cfg_txrx_streams = cpu_to_le32(WMI_NUM_SUPPORTED_BAND_MAX); |
843 | cmd->pdev_id = cpu_to_le32(args->pdev_id); |
844 | cmd->vdev_stats_id = cpu_to_le32(args->if_stats_id); |
845 | ether_addr_copy(dst: cmd->vdev_macaddr.addr, src: macaddr); |
846 | |
847 | if (args->if_stats_id != ATH12K_INVAL_VDEV_STATS_ID) |
848 | cmd->vdev_stats_id_valid = cpu_to_le32(BIT(0)); |
849 | |
850 | ptr = skb->data + sizeof(*cmd); |
851 | len = WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams); |
852 | |
853 | tlv = ptr; |
854 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len); |
855 | |
856 | ptr += TLV_HDR_SIZE; |
857 | txrx_streams = ptr; |
858 | len = sizeof(*txrx_streams); |
859 | txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_TXRX_STREAMS, |
860 | len); |
861 | txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G; |
862 | txrx_streams->supported_tx_streams = |
863 | args->chains[NL80211_BAND_2GHZ].tx; |
864 | txrx_streams->supported_rx_streams = |
865 | args->chains[NL80211_BAND_2GHZ].rx; |
866 | |
867 | txrx_streams++; |
868 | txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_TXRX_STREAMS, |
869 | len); |
870 | txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G; |
871 | txrx_streams->supported_tx_streams = |
872 | args->chains[NL80211_BAND_5GHZ].tx; |
873 | txrx_streams->supported_rx_streams = |
874 | args->chains[NL80211_BAND_5GHZ].rx; |
875 | |
876 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
877 | "WMI vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n" , |
878 | args->if_id, args->type, args->subtype, |
879 | macaddr, args->pdev_id); |
880 | |
881 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_VDEV_CREATE_CMDID); |
882 | if (ret) { |
883 | ath12k_warn(ab: ar->ab, |
884 | fmt: "failed to submit WMI_VDEV_CREATE_CMDID\n" ); |
885 | dev_kfree_skb(skb); |
886 | } |
887 | |
888 | return ret; |
889 | } |
890 | |
891 | int ath12k_wmi_vdev_delete(struct ath12k *ar, u8 vdev_id) |
892 | { |
893 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
894 | struct wmi_vdev_delete_cmd *cmd; |
895 | struct sk_buff *skb; |
896 | int ret; |
897 | |
898 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
899 | if (!skb) |
900 | return -ENOMEM; |
901 | |
902 | cmd = (struct wmi_vdev_delete_cmd *)skb->data; |
903 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_DELETE_CMD, |
904 | len: sizeof(*cmd)); |
905 | cmd->vdev_id = cpu_to_le32(vdev_id); |
906 | |
907 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI vdev delete id %d\n" , vdev_id); |
908 | |
909 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_VDEV_DELETE_CMDID); |
910 | if (ret) { |
911 | ath12k_warn(ab: ar->ab, fmt: "failed to submit WMI_VDEV_DELETE_CMDID\n" ); |
912 | dev_kfree_skb(skb); |
913 | } |
914 | |
915 | return ret; |
916 | } |
917 | |
918 | int ath12k_wmi_vdev_stop(struct ath12k *ar, u8 vdev_id) |
919 | { |
920 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
921 | struct wmi_vdev_stop_cmd *cmd; |
922 | struct sk_buff *skb; |
923 | int ret; |
924 | |
925 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
926 | if (!skb) |
927 | return -ENOMEM; |
928 | |
929 | cmd = (struct wmi_vdev_stop_cmd *)skb->data; |
930 | |
931 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_STOP_CMD, |
932 | len: sizeof(*cmd)); |
933 | cmd->vdev_id = cpu_to_le32(vdev_id); |
934 | |
935 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI vdev stop id 0x%x\n" , vdev_id); |
936 | |
937 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_VDEV_STOP_CMDID); |
938 | if (ret) { |
939 | ath12k_warn(ab: ar->ab, fmt: "failed to submit WMI_VDEV_STOP cmd\n" ); |
940 | dev_kfree_skb(skb); |
941 | } |
942 | |
943 | return ret; |
944 | } |
945 | |
946 | int ath12k_wmi_vdev_down(struct ath12k *ar, u8 vdev_id) |
947 | { |
948 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
949 | struct wmi_vdev_down_cmd *cmd; |
950 | struct sk_buff *skb; |
951 | int ret; |
952 | |
953 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
954 | if (!skb) |
955 | return -ENOMEM; |
956 | |
957 | cmd = (struct wmi_vdev_down_cmd *)skb->data; |
958 | |
959 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_DOWN_CMD, |
960 | len: sizeof(*cmd)); |
961 | cmd->vdev_id = cpu_to_le32(vdev_id); |
962 | |
963 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI vdev down id 0x%x\n" , vdev_id); |
964 | |
965 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_VDEV_DOWN_CMDID); |
966 | if (ret) { |
967 | ath12k_warn(ab: ar->ab, fmt: "failed to submit WMI_VDEV_DOWN cmd\n" ); |
968 | dev_kfree_skb(skb); |
969 | } |
970 | |
971 | return ret; |
972 | } |
973 | |
974 | static void ath12k_wmi_put_wmi_channel(struct ath12k_wmi_channel_params *chan, |
975 | struct wmi_vdev_start_req_arg *arg) |
976 | { |
977 | memset(chan, 0, sizeof(*chan)); |
978 | |
979 | chan->mhz = cpu_to_le32(arg->freq); |
980 | chan->band_center_freq1 = cpu_to_le32(arg->band_center_freq1); |
981 | if (arg->mode == MODE_11AC_VHT80_80) |
982 | chan->band_center_freq2 = cpu_to_le32(arg->band_center_freq2); |
983 | else |
984 | chan->band_center_freq2 = 0; |
985 | |
986 | chan->info |= le32_encode_bits(v: arg->mode, WMI_CHAN_INFO_MODE); |
987 | if (arg->passive) |
988 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_PASSIVE); |
989 | if (arg->allow_ibss) |
990 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_ADHOC_ALLOWED); |
991 | if (arg->allow_ht) |
992 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HT); |
993 | if (arg->allow_vht) |
994 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_VHT); |
995 | if (arg->allow_he) |
996 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HE); |
997 | if (arg->ht40plus) |
998 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_HT40_PLUS); |
999 | if (arg->chan_radar) |
1000 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_DFS); |
1001 | if (arg->freq2_radar) |
1002 | chan->info |= cpu_to_le32(WMI_CHAN_INFO_DFS_FREQ2); |
1003 | |
1004 | chan->reg_info_1 = le32_encode_bits(v: arg->max_power, |
1005 | WMI_CHAN_REG_INFO1_MAX_PWR) | |
1006 | le32_encode_bits(v: arg->max_reg_power, |
1007 | WMI_CHAN_REG_INFO1_MAX_REG_PWR); |
1008 | |
1009 | chan->reg_info_2 = le32_encode_bits(v: arg->max_antenna_gain, |
1010 | WMI_CHAN_REG_INFO2_ANT_MAX) | |
1011 | le32_encode_bits(v: arg->max_power, WMI_CHAN_REG_INFO2_MAX_TX_PWR); |
1012 | } |
1013 | |
1014 | int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, |
1015 | bool restart) |
1016 | { |
1017 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1018 | struct wmi_vdev_start_request_cmd *cmd; |
1019 | struct sk_buff *skb; |
1020 | struct ath12k_wmi_channel_params *chan; |
1021 | struct wmi_tlv *tlv; |
1022 | void *ptr; |
1023 | int ret, len; |
1024 | |
1025 | if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid))) |
1026 | return -EINVAL; |
1027 | |
1028 | len = sizeof(*cmd) + sizeof(*chan) + TLV_HDR_SIZE; |
1029 | |
1030 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
1031 | if (!skb) |
1032 | return -ENOMEM; |
1033 | |
1034 | cmd = (struct wmi_vdev_start_request_cmd *)skb->data; |
1035 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_START_REQUEST_CMD, |
1036 | len: sizeof(*cmd)); |
1037 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
1038 | cmd->beacon_interval = cpu_to_le32(arg->bcn_intval); |
1039 | cmd->bcn_tx_rate = cpu_to_le32(arg->bcn_tx_rate); |
1040 | cmd->dtim_period = cpu_to_le32(arg->dtim_period); |
1041 | cmd->num_noa_descriptors = cpu_to_le32(arg->num_noa_descriptors); |
1042 | cmd->preferred_rx_streams = cpu_to_le32(arg->pref_rx_streams); |
1043 | cmd->preferred_tx_streams = cpu_to_le32(arg->pref_tx_streams); |
1044 | cmd->cac_duration_ms = cpu_to_le32(arg->cac_duration_ms); |
1045 | cmd->regdomain = cpu_to_le32(arg->regdomain); |
1046 | cmd->he_ops = cpu_to_le32(arg->he_ops); |
1047 | cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); |
1048 | cmd->mbssid_flags = cpu_to_le32(arg->mbssid_flags); |
1049 | |
1050 | if (!restart) { |
1051 | if (arg->ssid) { |
1052 | cmd->ssid.ssid_len = cpu_to_le32(arg->ssid_len); |
1053 | memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len); |
1054 | } |
1055 | if (arg->hidden_ssid) |
1056 | cmd->flags |= cpu_to_le32(WMI_VDEV_START_HIDDEN_SSID); |
1057 | if (arg->pmf_enabled) |
1058 | cmd->flags |= cpu_to_le32(WMI_VDEV_START_PMF_ENABLED); |
1059 | } |
1060 | |
1061 | cmd->flags |= cpu_to_le32(WMI_VDEV_START_LDPC_RX_ENABLED); |
1062 | |
1063 | ptr = skb->data + sizeof(*cmd); |
1064 | chan = ptr; |
1065 | |
1066 | ath12k_wmi_put_wmi_channel(chan, arg); |
1067 | |
1068 | chan->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_CHANNEL, |
1069 | len: sizeof(*chan)); |
1070 | ptr += sizeof(*chan); |
1071 | |
1072 | tlv = ptr; |
1073 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len: 0); |
1074 | |
1075 | /* Note: This is a nested TLV containing: |
1076 | * [wmi_tlv][ath12k_wmi_p2p_noa_descriptor][wmi_tlv].. |
1077 | */ |
1078 | |
1079 | ptr += sizeof(*tlv); |
1080 | |
1081 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %s id 0x%x freq 0x%x mode 0x%x\n" , |
1082 | restart ? "restart" : "start" , arg->vdev_id, |
1083 | arg->freq, arg->mode); |
1084 | |
1085 | if (restart) |
1086 | ret = ath12k_wmi_cmd_send(wmi, skb, |
1087 | cmd_id: WMI_VDEV_RESTART_REQUEST_CMDID); |
1088 | else |
1089 | ret = ath12k_wmi_cmd_send(wmi, skb, |
1090 | cmd_id: WMI_VDEV_START_REQUEST_CMDID); |
1091 | if (ret) { |
1092 | ath12k_warn(ab: ar->ab, fmt: "failed to submit vdev_%s cmd\n" , |
1093 | restart ? "restart" : "start" ); |
1094 | dev_kfree_skb(skb); |
1095 | } |
1096 | |
1097 | return ret; |
1098 | } |
1099 | |
1100 | int ath12k_wmi_vdev_up(struct ath12k *ar, u32 vdev_id, u32 aid, const u8 *bssid) |
1101 | { |
1102 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1103 | struct wmi_vdev_up_cmd *cmd; |
1104 | struct sk_buff *skb; |
1105 | int ret; |
1106 | |
1107 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1108 | if (!skb) |
1109 | return -ENOMEM; |
1110 | |
1111 | cmd = (struct wmi_vdev_up_cmd *)skb->data; |
1112 | |
1113 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_UP_CMD, |
1114 | len: sizeof(*cmd)); |
1115 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1116 | cmd->vdev_assoc_id = cpu_to_le32(aid); |
1117 | |
1118 | ether_addr_copy(dst: cmd->vdev_bssid.addr, src: bssid); |
1119 | |
1120 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1121 | "WMI mgmt vdev up id 0x%x assoc id %d bssid %pM\n" , |
1122 | vdev_id, aid, bssid); |
1123 | |
1124 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_VDEV_UP_CMDID); |
1125 | if (ret) { |
1126 | ath12k_warn(ab: ar->ab, fmt: "failed to submit WMI_VDEV_UP cmd\n" ); |
1127 | dev_kfree_skb(skb); |
1128 | } |
1129 | |
1130 | return ret; |
1131 | } |
1132 | |
1133 | int ath12k_wmi_send_peer_create_cmd(struct ath12k *ar, |
1134 | struct ath12k_wmi_peer_create_arg *arg) |
1135 | { |
1136 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1137 | struct wmi_peer_create_cmd *cmd; |
1138 | struct sk_buff *skb; |
1139 | int ret; |
1140 | |
1141 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1142 | if (!skb) |
1143 | return -ENOMEM; |
1144 | |
1145 | cmd = (struct wmi_peer_create_cmd *)skb->data; |
1146 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PEER_CREATE_CMD, |
1147 | len: sizeof(*cmd)); |
1148 | |
1149 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: arg->peer_addr); |
1150 | cmd->peer_type = cpu_to_le32(arg->peer_type); |
1151 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
1152 | |
1153 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1154 | "WMI peer create vdev_id %d peer_addr %pM\n" , |
1155 | arg->vdev_id, arg->peer_addr); |
1156 | |
1157 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PEER_CREATE_CMDID); |
1158 | if (ret) { |
1159 | ath12k_warn(ab: ar->ab, fmt: "failed to submit WMI_PEER_CREATE cmd\n" ); |
1160 | dev_kfree_skb(skb); |
1161 | } |
1162 | |
1163 | return ret; |
1164 | } |
1165 | |
1166 | int ath12k_wmi_send_peer_delete_cmd(struct ath12k *ar, |
1167 | const u8 *peer_addr, u8 vdev_id) |
1168 | { |
1169 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1170 | struct wmi_peer_delete_cmd *cmd; |
1171 | struct sk_buff *skb; |
1172 | int ret; |
1173 | |
1174 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1175 | if (!skb) |
1176 | return -ENOMEM; |
1177 | |
1178 | cmd = (struct wmi_peer_delete_cmd *)skb->data; |
1179 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PEER_DELETE_CMD, |
1180 | len: sizeof(*cmd)); |
1181 | |
1182 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: peer_addr); |
1183 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1184 | |
1185 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1186 | "WMI peer delete vdev_id %d peer_addr %pM\n" , |
1187 | vdev_id, peer_addr); |
1188 | |
1189 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PEER_DELETE_CMDID); |
1190 | if (ret) { |
1191 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_PEER_DELETE cmd\n" ); |
1192 | dev_kfree_skb(skb); |
1193 | } |
1194 | |
1195 | return ret; |
1196 | } |
1197 | |
1198 | int ath12k_wmi_send_pdev_set_regdomain(struct ath12k *ar, |
1199 | struct ath12k_wmi_pdev_set_regdomain_arg *arg) |
1200 | { |
1201 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1202 | struct wmi_pdev_set_regdomain_cmd *cmd; |
1203 | struct sk_buff *skb; |
1204 | int ret; |
1205 | |
1206 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1207 | if (!skb) |
1208 | return -ENOMEM; |
1209 | |
1210 | cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data; |
1211 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_SET_REGDOMAIN_CMD, |
1212 | len: sizeof(*cmd)); |
1213 | |
1214 | cmd->reg_domain = cpu_to_le32(arg->current_rd_in_use); |
1215 | cmd->reg_domain_2g = cpu_to_le32(arg->current_rd_2g); |
1216 | cmd->reg_domain_5g = cpu_to_le32(arg->current_rd_5g); |
1217 | cmd->conformance_test_limit_2g = cpu_to_le32(arg->ctl_2g); |
1218 | cmd->conformance_test_limit_5g = cpu_to_le32(arg->ctl_5g); |
1219 | cmd->dfs_domain = cpu_to_le32(arg->dfs_domain); |
1220 | cmd->pdev_id = cpu_to_le32(arg->pdev_id); |
1221 | |
1222 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1223 | "WMI pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n" , |
1224 | arg->current_rd_in_use, arg->current_rd_2g, |
1225 | arg->current_rd_5g, arg->dfs_domain, arg->pdev_id); |
1226 | |
1227 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PDEV_SET_REGDOMAIN_CMDID); |
1228 | if (ret) { |
1229 | ath12k_warn(ab: ar->ab, |
1230 | fmt: "failed to send WMI_PDEV_SET_REGDOMAIN cmd\n" ); |
1231 | dev_kfree_skb(skb); |
1232 | } |
1233 | |
1234 | return ret; |
1235 | } |
1236 | |
1237 | int ath12k_wmi_set_peer_param(struct ath12k *ar, const u8 *peer_addr, |
1238 | u32 vdev_id, u32 param_id, u32 param_val) |
1239 | { |
1240 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1241 | struct wmi_peer_set_param_cmd *cmd; |
1242 | struct sk_buff *skb; |
1243 | int ret; |
1244 | |
1245 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1246 | if (!skb) |
1247 | return -ENOMEM; |
1248 | |
1249 | cmd = (struct wmi_peer_set_param_cmd *)skb->data; |
1250 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PEER_SET_PARAM_CMD, |
1251 | len: sizeof(*cmd)); |
1252 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: peer_addr); |
1253 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1254 | cmd->param_id = cpu_to_le32(param_id); |
1255 | cmd->param_value = cpu_to_le32(param_val); |
1256 | |
1257 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1258 | "WMI vdev %d peer 0x%pM set param %d value %d\n" , |
1259 | vdev_id, peer_addr, param_id, param_val); |
1260 | |
1261 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PEER_SET_PARAM_CMDID); |
1262 | if (ret) { |
1263 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_PEER_SET_PARAM cmd\n" ); |
1264 | dev_kfree_skb(skb); |
1265 | } |
1266 | |
1267 | return ret; |
1268 | } |
1269 | |
1270 | int ath12k_wmi_send_peer_flush_tids_cmd(struct ath12k *ar, |
1271 | u8 peer_addr[ETH_ALEN], |
1272 | u32 peer_tid_bitmap, |
1273 | u8 vdev_id) |
1274 | { |
1275 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1276 | struct wmi_peer_flush_tids_cmd *cmd; |
1277 | struct sk_buff *skb; |
1278 | int ret; |
1279 | |
1280 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1281 | if (!skb) |
1282 | return -ENOMEM; |
1283 | |
1284 | cmd = (struct wmi_peer_flush_tids_cmd *)skb->data; |
1285 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PEER_FLUSH_TIDS_CMD, |
1286 | len: sizeof(*cmd)); |
1287 | |
1288 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: peer_addr); |
1289 | cmd->peer_tid_bitmap = cpu_to_le32(peer_tid_bitmap); |
1290 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1291 | |
1292 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1293 | "WMI peer flush vdev_id %d peer_addr %pM tids %08x\n" , |
1294 | vdev_id, peer_addr, peer_tid_bitmap); |
1295 | |
1296 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PEER_FLUSH_TIDS_CMDID); |
1297 | if (ret) { |
1298 | ath12k_warn(ab: ar->ab, |
1299 | fmt: "failed to send WMI_PEER_FLUSH_TIDS cmd\n" ); |
1300 | dev_kfree_skb(skb); |
1301 | } |
1302 | |
1303 | return ret; |
1304 | } |
1305 | |
1306 | int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar, |
1307 | int vdev_id, const u8 *addr, |
1308 | dma_addr_t paddr, u8 tid, |
1309 | u8 ba_window_size_valid, |
1310 | u32 ba_window_size) |
1311 | { |
1312 | struct wmi_peer_reorder_queue_setup_cmd *cmd; |
1313 | struct sk_buff *skb; |
1314 | int ret; |
1315 | |
1316 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len: sizeof(*cmd)); |
1317 | if (!skb) |
1318 | return -ENOMEM; |
1319 | |
1320 | cmd = (struct wmi_peer_reorder_queue_setup_cmd *)skb->data; |
1321 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_REORDER_QUEUE_SETUP_CMD, |
1322 | len: sizeof(*cmd)); |
1323 | |
1324 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: addr); |
1325 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1326 | cmd->tid = cpu_to_le32(tid); |
1327 | cmd->queue_ptr_lo = cpu_to_le32(lower_32_bits(paddr)); |
1328 | cmd->queue_ptr_hi = cpu_to_le32(upper_32_bits(paddr)); |
1329 | cmd->queue_no = cpu_to_le32(tid); |
1330 | cmd->ba_window_size_valid = cpu_to_le32(ba_window_size_valid); |
1331 | cmd->ba_window_size = cpu_to_le32(ba_window_size); |
1332 | |
1333 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1334 | "wmi rx reorder queue setup addr %pM vdev_id %d tid %d\n" , |
1335 | addr, vdev_id, tid); |
1336 | |
1337 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, |
1338 | cmd_id: WMI_PEER_REORDER_QUEUE_SETUP_CMDID); |
1339 | if (ret) { |
1340 | ath12k_warn(ab: ar->ab, |
1341 | fmt: "failed to send WMI_PEER_REORDER_QUEUE_SETUP\n" ); |
1342 | dev_kfree_skb(skb); |
1343 | } |
1344 | |
1345 | return ret; |
1346 | } |
1347 | |
1348 | int |
1349 | ath12k_wmi_rx_reord_queue_remove(struct ath12k *ar, |
1350 | struct ath12k_wmi_rx_reorder_queue_remove_arg *arg) |
1351 | { |
1352 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1353 | struct wmi_peer_reorder_queue_remove_cmd *cmd; |
1354 | struct sk_buff *skb; |
1355 | int ret; |
1356 | |
1357 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1358 | if (!skb) |
1359 | return -ENOMEM; |
1360 | |
1361 | cmd = (struct wmi_peer_reorder_queue_remove_cmd *)skb->data; |
1362 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_REORDER_QUEUE_REMOVE_CMD, |
1363 | len: sizeof(*cmd)); |
1364 | |
1365 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: arg->peer_macaddr); |
1366 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
1367 | cmd->tid_mask = cpu_to_le32(arg->peer_tid_bitmap); |
1368 | |
1369 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1370 | "%s: peer_macaddr %pM vdev_id %d, tid_map %d" , __func__, |
1371 | arg->peer_macaddr, arg->vdev_id, arg->peer_tid_bitmap); |
1372 | |
1373 | ret = ath12k_wmi_cmd_send(wmi, skb, |
1374 | cmd_id: WMI_PEER_REORDER_QUEUE_REMOVE_CMDID); |
1375 | if (ret) { |
1376 | ath12k_warn(ab: ar->ab, |
1377 | fmt: "failed to send WMI_PEER_REORDER_QUEUE_REMOVE_CMDID" ); |
1378 | dev_kfree_skb(skb); |
1379 | } |
1380 | |
1381 | return ret; |
1382 | } |
1383 | |
1384 | int ath12k_wmi_pdev_set_param(struct ath12k *ar, u32 param_id, |
1385 | u32 param_value, u8 pdev_id) |
1386 | { |
1387 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1388 | struct wmi_pdev_set_param_cmd *cmd; |
1389 | struct sk_buff *skb; |
1390 | int ret; |
1391 | |
1392 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1393 | if (!skb) |
1394 | return -ENOMEM; |
1395 | |
1396 | cmd = (struct wmi_pdev_set_param_cmd *)skb->data; |
1397 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_SET_PARAM_CMD, |
1398 | len: sizeof(*cmd)); |
1399 | cmd->pdev_id = cpu_to_le32(pdev_id); |
1400 | cmd->param_id = cpu_to_le32(param_id); |
1401 | cmd->param_value = cpu_to_le32(param_value); |
1402 | |
1403 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1404 | "WMI pdev set param %d pdev id %d value %d\n" , |
1405 | param_id, pdev_id, param_value); |
1406 | |
1407 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PDEV_SET_PARAM_CMDID); |
1408 | if (ret) { |
1409 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_PDEV_SET_PARAM cmd\n" ); |
1410 | dev_kfree_skb(skb); |
1411 | } |
1412 | |
1413 | return ret; |
1414 | } |
1415 | |
1416 | int ath12k_wmi_pdev_set_ps_mode(struct ath12k *ar, int vdev_id, u32 enable) |
1417 | { |
1418 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1419 | struct wmi_pdev_set_ps_mode_cmd *cmd; |
1420 | struct sk_buff *skb; |
1421 | int ret; |
1422 | |
1423 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1424 | if (!skb) |
1425 | return -ENOMEM; |
1426 | |
1427 | cmd = (struct wmi_pdev_set_ps_mode_cmd *)skb->data; |
1428 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_STA_POWERSAVE_MODE_CMD, |
1429 | len: sizeof(*cmd)); |
1430 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1431 | cmd->sta_ps_mode = cpu_to_le32(enable); |
1432 | |
1433 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1434 | "WMI vdev set psmode %d vdev id %d\n" , |
1435 | enable, vdev_id); |
1436 | |
1437 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_STA_POWERSAVE_MODE_CMDID); |
1438 | if (ret) { |
1439 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_PDEV_SET_PARAM cmd\n" ); |
1440 | dev_kfree_skb(skb); |
1441 | } |
1442 | |
1443 | return ret; |
1444 | } |
1445 | |
1446 | int ath12k_wmi_pdev_suspend(struct ath12k *ar, u32 suspend_opt, |
1447 | u32 pdev_id) |
1448 | { |
1449 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1450 | struct wmi_pdev_suspend_cmd *cmd; |
1451 | struct sk_buff *skb; |
1452 | int ret; |
1453 | |
1454 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1455 | if (!skb) |
1456 | return -ENOMEM; |
1457 | |
1458 | cmd = (struct wmi_pdev_suspend_cmd *)skb->data; |
1459 | |
1460 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_SUSPEND_CMD, |
1461 | len: sizeof(*cmd)); |
1462 | |
1463 | cmd->suspend_opt = cpu_to_le32(suspend_opt); |
1464 | cmd->pdev_id = cpu_to_le32(pdev_id); |
1465 | |
1466 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1467 | "WMI pdev suspend pdev_id %d\n" , pdev_id); |
1468 | |
1469 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PDEV_SUSPEND_CMDID); |
1470 | if (ret) { |
1471 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_PDEV_SUSPEND cmd\n" ); |
1472 | dev_kfree_skb(skb); |
1473 | } |
1474 | |
1475 | return ret; |
1476 | } |
1477 | |
1478 | int ath12k_wmi_pdev_resume(struct ath12k *ar, u32 pdev_id) |
1479 | { |
1480 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1481 | struct wmi_pdev_resume_cmd *cmd; |
1482 | struct sk_buff *skb; |
1483 | int ret; |
1484 | |
1485 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1486 | if (!skb) |
1487 | return -ENOMEM; |
1488 | |
1489 | cmd = (struct wmi_pdev_resume_cmd *)skb->data; |
1490 | |
1491 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_RESUME_CMD, |
1492 | len: sizeof(*cmd)); |
1493 | cmd->pdev_id = cpu_to_le32(pdev_id); |
1494 | |
1495 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1496 | "WMI pdev resume pdev id %d\n" , pdev_id); |
1497 | |
1498 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PDEV_RESUME_CMDID); |
1499 | if (ret) { |
1500 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_PDEV_RESUME cmd\n" ); |
1501 | dev_kfree_skb(skb); |
1502 | } |
1503 | |
1504 | return ret; |
1505 | } |
1506 | |
1507 | /* TODO FW Support for the cmd is not available yet. |
1508 | * Can be tested once the command and corresponding |
1509 | * event is implemented in FW |
1510 | */ |
1511 | int ath12k_wmi_pdev_bss_chan_info_request(struct ath12k *ar, |
1512 | enum wmi_bss_chan_info_req_type type) |
1513 | { |
1514 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1515 | struct wmi_pdev_bss_chan_info_req_cmd *cmd; |
1516 | struct sk_buff *skb; |
1517 | int ret; |
1518 | |
1519 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1520 | if (!skb) |
1521 | return -ENOMEM; |
1522 | |
1523 | cmd = (struct wmi_pdev_bss_chan_info_req_cmd *)skb->data; |
1524 | |
1525 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_BSS_CHAN_INFO_REQUEST, |
1526 | len: sizeof(*cmd)); |
1527 | cmd->req_type = cpu_to_le32(type); |
1528 | |
1529 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1530 | "WMI bss chan info req type %d\n" , type); |
1531 | |
1532 | ret = ath12k_wmi_cmd_send(wmi, skb, |
1533 | cmd_id: WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID); |
1534 | if (ret) { |
1535 | ath12k_warn(ab: ar->ab, |
1536 | fmt: "failed to send WMI_PDEV_BSS_CHAN_INFO_REQUEST cmd\n" ); |
1537 | dev_kfree_skb(skb); |
1538 | } |
1539 | |
1540 | return ret; |
1541 | } |
1542 | |
1543 | int ath12k_wmi_send_set_ap_ps_param_cmd(struct ath12k *ar, u8 *peer_addr, |
1544 | struct ath12k_wmi_ap_ps_arg *arg) |
1545 | { |
1546 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1547 | struct wmi_ap_ps_peer_cmd *cmd; |
1548 | struct sk_buff *skb; |
1549 | int ret; |
1550 | |
1551 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1552 | if (!skb) |
1553 | return -ENOMEM; |
1554 | |
1555 | cmd = (struct wmi_ap_ps_peer_cmd *)skb->data; |
1556 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_AP_PS_PEER_CMD, |
1557 | len: sizeof(*cmd)); |
1558 | |
1559 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
1560 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: peer_addr); |
1561 | cmd->param = cpu_to_le32(arg->param); |
1562 | cmd->value = cpu_to_le32(arg->value); |
1563 | |
1564 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1565 | "WMI set ap ps vdev id %d peer %pM param %d value %d\n" , |
1566 | arg->vdev_id, peer_addr, arg->param, arg->value); |
1567 | |
1568 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_AP_PS_PEER_PARAM_CMDID); |
1569 | if (ret) { |
1570 | ath12k_warn(ab: ar->ab, |
1571 | fmt: "failed to send WMI_AP_PS_PEER_PARAM_CMDID\n" ); |
1572 | dev_kfree_skb(skb); |
1573 | } |
1574 | |
1575 | return ret; |
1576 | } |
1577 | |
1578 | int ath12k_wmi_set_sta_ps_param(struct ath12k *ar, u32 vdev_id, |
1579 | u32 param, u32 param_value) |
1580 | { |
1581 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1582 | struct wmi_sta_powersave_param_cmd *cmd; |
1583 | struct sk_buff *skb; |
1584 | int ret; |
1585 | |
1586 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1587 | if (!skb) |
1588 | return -ENOMEM; |
1589 | |
1590 | cmd = (struct wmi_sta_powersave_param_cmd *)skb->data; |
1591 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_STA_POWERSAVE_PARAM_CMD, |
1592 | len: sizeof(*cmd)); |
1593 | |
1594 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1595 | cmd->param = cpu_to_le32(param); |
1596 | cmd->value = cpu_to_le32(param_value); |
1597 | |
1598 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1599 | "WMI set sta ps vdev_id %d param %d value %d\n" , |
1600 | vdev_id, param, param_value); |
1601 | |
1602 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_STA_POWERSAVE_PARAM_CMDID); |
1603 | if (ret) { |
1604 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_STA_POWERSAVE_PARAM_CMDID" ); |
1605 | dev_kfree_skb(skb); |
1606 | } |
1607 | |
1608 | return ret; |
1609 | } |
1610 | |
1611 | int ath12k_wmi_force_fw_hang_cmd(struct ath12k *ar, u32 type, u32 delay_time_ms) |
1612 | { |
1613 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1614 | struct wmi_force_fw_hang_cmd *cmd; |
1615 | struct sk_buff *skb; |
1616 | int ret, len; |
1617 | |
1618 | len = sizeof(*cmd); |
1619 | |
1620 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
1621 | if (!skb) |
1622 | return -ENOMEM; |
1623 | |
1624 | cmd = (struct wmi_force_fw_hang_cmd *)skb->data; |
1625 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_FORCE_FW_HANG_CMD, |
1626 | len); |
1627 | |
1628 | cmd->type = cpu_to_le32(type); |
1629 | cmd->delay_time_ms = cpu_to_le32(delay_time_ms); |
1630 | |
1631 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_FORCE_FW_HANG_CMDID); |
1632 | |
1633 | if (ret) { |
1634 | ath12k_warn(ab: ar->ab, fmt: "Failed to send WMI_FORCE_FW_HANG_CMDID" ); |
1635 | dev_kfree_skb(skb); |
1636 | } |
1637 | return ret; |
1638 | } |
1639 | |
1640 | int ath12k_wmi_vdev_set_param_cmd(struct ath12k *ar, u32 vdev_id, |
1641 | u32 param_id, u32 param_value) |
1642 | { |
1643 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1644 | struct wmi_vdev_set_param_cmd *cmd; |
1645 | struct sk_buff *skb; |
1646 | int ret; |
1647 | |
1648 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1649 | if (!skb) |
1650 | return -ENOMEM; |
1651 | |
1652 | cmd = (struct wmi_vdev_set_param_cmd *)skb->data; |
1653 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_SET_PARAM_CMD, |
1654 | len: sizeof(*cmd)); |
1655 | |
1656 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1657 | cmd->param_id = cpu_to_le32(param_id); |
1658 | cmd->param_value = cpu_to_le32(param_value); |
1659 | |
1660 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1661 | "WMI vdev id 0x%x set param %d value %d\n" , |
1662 | vdev_id, param_id, param_value); |
1663 | |
1664 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_VDEV_SET_PARAM_CMDID); |
1665 | if (ret) { |
1666 | ath12k_warn(ab: ar->ab, |
1667 | fmt: "failed to send WMI_VDEV_SET_PARAM_CMDID\n" ); |
1668 | dev_kfree_skb(skb); |
1669 | } |
1670 | |
1671 | return ret; |
1672 | } |
1673 | |
1674 | int ath12k_wmi_send_pdev_temperature_cmd(struct ath12k *ar) |
1675 | { |
1676 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1677 | struct wmi_get_pdev_temperature_cmd *cmd; |
1678 | struct sk_buff *skb; |
1679 | int ret; |
1680 | |
1681 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1682 | if (!skb) |
1683 | return -ENOMEM; |
1684 | |
1685 | cmd = (struct wmi_get_pdev_temperature_cmd *)skb->data; |
1686 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_GET_TEMPERATURE_CMD, |
1687 | len: sizeof(*cmd)); |
1688 | cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id); |
1689 | |
1690 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1691 | "WMI pdev get temperature for pdev_id %d\n" , ar->pdev->pdev_id); |
1692 | |
1693 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PDEV_GET_TEMPERATURE_CMDID); |
1694 | if (ret) { |
1695 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_PDEV_GET_TEMPERATURE cmd\n" ); |
1696 | dev_kfree_skb(skb); |
1697 | } |
1698 | |
1699 | return ret; |
1700 | } |
1701 | |
1702 | int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar, |
1703 | u32 vdev_id, u32 bcn_ctrl_op) |
1704 | { |
1705 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1706 | struct wmi_bcn_offload_ctrl_cmd *cmd; |
1707 | struct sk_buff *skb; |
1708 | int ret; |
1709 | |
1710 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
1711 | if (!skb) |
1712 | return -ENOMEM; |
1713 | |
1714 | cmd = (struct wmi_bcn_offload_ctrl_cmd *)skb->data; |
1715 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_BCN_OFFLOAD_CTRL_CMD, |
1716 | len: sizeof(*cmd)); |
1717 | |
1718 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1719 | cmd->bcn_ctrl_op = cpu_to_le32(bcn_ctrl_op); |
1720 | |
1721 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1722 | "WMI bcn ctrl offload vdev id %d ctrl_op %d\n" , |
1723 | vdev_id, bcn_ctrl_op); |
1724 | |
1725 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_BCN_OFFLOAD_CTRL_CMDID); |
1726 | if (ret) { |
1727 | ath12k_warn(ab: ar->ab, |
1728 | fmt: "failed to send WMI_BCN_OFFLOAD_CTRL_CMDID\n" ); |
1729 | dev_kfree_skb(skb); |
1730 | } |
1731 | |
1732 | return ret; |
1733 | } |
1734 | |
1735 | int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, |
1736 | const u8 *p2p_ie) |
1737 | { |
1738 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1739 | struct wmi_p2p_go_set_beacon_ie_cmd *cmd; |
1740 | size_t p2p_ie_len, aligned_len; |
1741 | struct wmi_tlv *tlv; |
1742 | struct sk_buff *skb; |
1743 | void *ptr; |
1744 | int ret, len; |
1745 | |
1746 | p2p_ie_len = p2p_ie[1] + 2; |
1747 | aligned_len = roundup(p2p_ie_len, sizeof(u32)); |
1748 | |
1749 | len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; |
1750 | |
1751 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
1752 | if (!skb) |
1753 | return -ENOMEM; |
1754 | |
1755 | ptr = skb->data; |
1756 | cmd = ptr; |
1757 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_P2P_GO_SET_BEACON_IE, |
1758 | len: sizeof(*cmd)); |
1759 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1760 | cmd->ie_buf_len = cpu_to_le32(p2p_ie_len); |
1761 | |
1762 | ptr += sizeof(*cmd); |
1763 | tlv = ptr; |
1764 | tlv->header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_ARRAY_BYTE, |
1765 | len: aligned_len); |
1766 | memcpy(tlv->value, p2p_ie, p2p_ie_len); |
1767 | |
1768 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_P2P_GO_SET_BEACON_IE); |
1769 | if (ret) { |
1770 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_P2P_GO_SET_BEACON_IE\n" ); |
1771 | dev_kfree_skb(skb); |
1772 | } |
1773 | |
1774 | return ret; |
1775 | } |
1776 | |
1777 | int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, |
1778 | struct ieee80211_mutable_offsets *offs, |
1779 | struct sk_buff *bcn) |
1780 | { |
1781 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1782 | struct wmi_bcn_tmpl_cmd *cmd; |
1783 | struct ath12k_wmi_bcn_prb_info_params *bcn_prb_info; |
1784 | struct wmi_tlv *tlv; |
1785 | struct sk_buff *skb; |
1786 | void *ptr; |
1787 | int ret, len; |
1788 | size_t aligned_len = roundup(bcn->len, 4); |
1789 | |
1790 | len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len; |
1791 | |
1792 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
1793 | if (!skb) |
1794 | return -ENOMEM; |
1795 | |
1796 | cmd = (struct wmi_bcn_tmpl_cmd *)skb->data; |
1797 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_BCN_TMPL_CMD, |
1798 | len: sizeof(*cmd)); |
1799 | cmd->vdev_id = cpu_to_le32(vdev_id); |
1800 | cmd->tim_ie_offset = cpu_to_le32(offs->tim_offset); |
1801 | cmd->csa_switch_count_offset = cpu_to_le32(offs->cntdwn_counter_offs[0]); |
1802 | cmd->ext_csa_switch_count_offset = cpu_to_le32(offs->cntdwn_counter_offs[1]); |
1803 | cmd->buf_len = cpu_to_le32(bcn->len); |
1804 | |
1805 | ptr = skb->data + sizeof(*cmd); |
1806 | |
1807 | bcn_prb_info = ptr; |
1808 | len = sizeof(*bcn_prb_info); |
1809 | bcn_prb_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_BCN_PRB_INFO, |
1810 | len); |
1811 | bcn_prb_info->caps = 0; |
1812 | bcn_prb_info->erp = 0; |
1813 | |
1814 | ptr += sizeof(*bcn_prb_info); |
1815 | |
1816 | tlv = ptr; |
1817 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len: aligned_len); |
1818 | memcpy(tlv->value, bcn->data, bcn->len); |
1819 | |
1820 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_BCN_TMPL_CMDID); |
1821 | if (ret) { |
1822 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_BCN_TMPL_CMDID\n" ); |
1823 | dev_kfree_skb(skb); |
1824 | } |
1825 | |
1826 | return ret; |
1827 | } |
1828 | |
1829 | int ath12k_wmi_vdev_install_key(struct ath12k *ar, |
1830 | struct wmi_vdev_install_key_arg *arg) |
1831 | { |
1832 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1833 | struct wmi_vdev_install_key_cmd *cmd; |
1834 | struct wmi_tlv *tlv; |
1835 | struct sk_buff *skb; |
1836 | int ret, len, key_len_aligned; |
1837 | |
1838 | /* WMI_TAG_ARRAY_BYTE needs to be aligned with 4, the actual key |
1839 | * length is specified in cmd->key_len. |
1840 | */ |
1841 | key_len_aligned = roundup(arg->key_len, 4); |
1842 | |
1843 | len = sizeof(*cmd) + TLV_HDR_SIZE + key_len_aligned; |
1844 | |
1845 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
1846 | if (!skb) |
1847 | return -ENOMEM; |
1848 | |
1849 | cmd = (struct wmi_vdev_install_key_cmd *)skb->data; |
1850 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_INSTALL_KEY_CMD, |
1851 | len: sizeof(*cmd)); |
1852 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
1853 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: arg->macaddr); |
1854 | cmd->key_idx = cpu_to_le32(arg->key_idx); |
1855 | cmd->key_flags = cpu_to_le32(arg->key_flags); |
1856 | cmd->key_cipher = cpu_to_le32(arg->key_cipher); |
1857 | cmd->key_len = cpu_to_le32(arg->key_len); |
1858 | cmd->key_txmic_len = cpu_to_le32(arg->key_txmic_len); |
1859 | cmd->key_rxmic_len = cpu_to_le32(arg->key_rxmic_len); |
1860 | |
1861 | if (arg->key_rsc_counter) |
1862 | cmd->key_rsc_counter = cpu_to_le64(arg->key_rsc_counter); |
1863 | |
1864 | tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd)); |
1865 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len: key_len_aligned); |
1866 | memcpy(tlv->value, arg->key_data, arg->key_len); |
1867 | |
1868 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
1869 | "WMI vdev install key idx %d cipher %d len %d\n" , |
1870 | arg->key_idx, arg->key_cipher, arg->key_len); |
1871 | |
1872 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_VDEV_INSTALL_KEY_CMDID); |
1873 | if (ret) { |
1874 | ath12k_warn(ab: ar->ab, |
1875 | fmt: "failed to send WMI_VDEV_INSTALL_KEY cmd\n" ); |
1876 | dev_kfree_skb(skb); |
1877 | } |
1878 | |
1879 | return ret; |
1880 | } |
1881 | |
1882 | static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, |
1883 | struct ath12k_wmi_peer_assoc_arg *arg, |
1884 | bool hw_crypto_disabled) |
1885 | { |
1886 | cmd->peer_flags = 0; |
1887 | cmd->peer_flags_ext = 0; |
1888 | |
1889 | if (arg->is_wme_set) { |
1890 | if (arg->qos_flag) |
1891 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_QOS); |
1892 | if (arg->apsd_flag) |
1893 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_APSD); |
1894 | if (arg->ht_flag) |
1895 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_HT); |
1896 | if (arg->bw_40) |
1897 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_40MHZ); |
1898 | if (arg->bw_80) |
1899 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_80MHZ); |
1900 | if (arg->bw_160) |
1901 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_160MHZ); |
1902 | if (arg->bw_320) |
1903 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_EXT_320MHZ); |
1904 | |
1905 | /* Typically if STBC is enabled for VHT it should be enabled |
1906 | * for HT as well |
1907 | **/ |
1908 | if (arg->stbc_flag) |
1909 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_STBC); |
1910 | |
1911 | /* Typically if LDPC is enabled for VHT it should be enabled |
1912 | * for HT as well |
1913 | **/ |
1914 | if (arg->ldpc_flag) |
1915 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_LDPC); |
1916 | |
1917 | if (arg->static_mimops_flag) |
1918 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_STATIC_MIMOPS); |
1919 | if (arg->dynamic_mimops_flag) |
1920 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_DYN_MIMOPS); |
1921 | if (arg->spatial_mux_flag) |
1922 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_SPATIAL_MUX); |
1923 | if (arg->vht_flag) |
1924 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_VHT); |
1925 | if (arg->he_flag) |
1926 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_HE); |
1927 | if (arg->twt_requester) |
1928 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_REQ); |
1929 | if (arg->twt_responder) |
1930 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_RESP); |
1931 | if (arg->eht_flag) |
1932 | cmd->peer_flags_ext |= cpu_to_le32(WMI_PEER_EXT_EHT); |
1933 | } |
1934 | |
1935 | /* Suppress authorization for all AUTH modes that need 4-way handshake |
1936 | * (during re-association). |
1937 | * Authorization will be done for these modes on key installation. |
1938 | */ |
1939 | if (arg->auth_flag) |
1940 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_AUTH); |
1941 | if (arg->need_ptk_4_way) { |
1942 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_NEED_PTK_4_WAY); |
1943 | if (!hw_crypto_disabled) |
1944 | cmd->peer_flags &= cpu_to_le32(~WMI_PEER_AUTH); |
1945 | } |
1946 | if (arg->need_gtk_2_way) |
1947 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_NEED_GTK_2_WAY); |
1948 | /* safe mode bypass the 4-way handshake */ |
1949 | if (arg->safe_mode_enabled) |
1950 | cmd->peer_flags &= cpu_to_le32(~(WMI_PEER_NEED_PTK_4_WAY | |
1951 | WMI_PEER_NEED_GTK_2_WAY)); |
1952 | |
1953 | if (arg->is_pmf_enabled) |
1954 | cmd->peer_flags |= cpu_to_le32(WMI_PEER_PMF); |
1955 | |
1956 | /* Disable AMSDU for station transmit, if user configures it */ |
1957 | /* Disable AMSDU for AP transmit to 11n Stations, if user configures |
1958 | * it |
1959 | * if (arg->amsdu_disable) Add after FW support |
1960 | **/ |
1961 | |
1962 | /* Target asserts if node is marked HT and all MCS is set to 0. |
1963 | * Mark the node as non-HT if all the mcs rates are disabled through |
1964 | * iwpriv |
1965 | **/ |
1966 | if (arg->peer_ht_rates.num_rates == 0) |
1967 | cmd->peer_flags &= cpu_to_le32(~WMI_PEER_HT); |
1968 | } |
1969 | |
1970 | int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, |
1971 | struct ath12k_wmi_peer_assoc_arg *arg) |
1972 | { |
1973 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
1974 | struct wmi_peer_assoc_complete_cmd *cmd; |
1975 | struct ath12k_wmi_vht_rate_set_params *mcs; |
1976 | struct ath12k_wmi_he_rate_set_params *he_mcs; |
1977 | struct ath12k_wmi_eht_rate_set_params *eht_mcs; |
1978 | struct sk_buff *skb; |
1979 | struct wmi_tlv *tlv; |
1980 | void *ptr; |
1981 | u32 peer_legacy_rates_align; |
1982 | u32 peer_ht_rates_align; |
1983 | int i, ret, len; |
1984 | |
1985 | peer_legacy_rates_align = roundup(arg->peer_legacy_rates.num_rates, |
1986 | sizeof(u32)); |
1987 | peer_ht_rates_align = roundup(arg->peer_ht_rates.num_rates, |
1988 | sizeof(u32)); |
1989 | |
1990 | len = sizeof(*cmd) + |
1991 | TLV_HDR_SIZE + (peer_legacy_rates_align * sizeof(u8)) + |
1992 | TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) + |
1993 | sizeof(*mcs) + TLV_HDR_SIZE + |
1994 | (sizeof(*he_mcs) * arg->peer_he_mcs_count) + |
1995 | TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count) + |
1996 | TLV_HDR_SIZE + TLV_HDR_SIZE; |
1997 | |
1998 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
1999 | if (!skb) |
2000 | return -ENOMEM; |
2001 | |
2002 | ptr = skb->data; |
2003 | |
2004 | cmd = ptr; |
2005 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PEER_ASSOC_COMPLETE_CMD, |
2006 | len: sizeof(*cmd)); |
2007 | |
2008 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
2009 | |
2010 | cmd->peer_new_assoc = cpu_to_le32(arg->peer_new_assoc); |
2011 | cmd->peer_associd = cpu_to_le32(arg->peer_associd); |
2012 | cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); |
2013 | |
2014 | ath12k_wmi_copy_peer_flags(cmd, arg, |
2015 | test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, |
2016 | &ar->ab->dev_flags)); |
2017 | |
2018 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: arg->peer_mac); |
2019 | |
2020 | cmd->peer_rate_caps = cpu_to_le32(arg->peer_rate_caps); |
2021 | cmd->peer_caps = cpu_to_le32(arg->peer_caps); |
2022 | cmd->peer_listen_intval = cpu_to_le32(arg->peer_listen_intval); |
2023 | cmd->peer_ht_caps = cpu_to_le32(arg->peer_ht_caps); |
2024 | cmd->peer_max_mpdu = cpu_to_le32(arg->peer_max_mpdu); |
2025 | cmd->peer_mpdu_density = cpu_to_le32(arg->peer_mpdu_density); |
2026 | cmd->peer_vht_caps = cpu_to_le32(arg->peer_vht_caps); |
2027 | cmd->peer_phymode = cpu_to_le32(arg->peer_phymode); |
2028 | |
2029 | /* Update 11ax capabilities */ |
2030 | cmd->peer_he_cap_info = cpu_to_le32(arg->peer_he_cap_macinfo[0]); |
2031 | cmd->peer_he_cap_info_ext = cpu_to_le32(arg->peer_he_cap_macinfo[1]); |
2032 | cmd->peer_he_cap_info_internal = cpu_to_le32(arg->peer_he_cap_macinfo_internal); |
2033 | cmd->peer_he_caps_6ghz = cpu_to_le32(arg->peer_he_caps_6ghz); |
2034 | cmd->peer_he_ops = cpu_to_le32(arg->peer_he_ops); |
2035 | for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++) |
2036 | cmd->peer_he_cap_phy[i] = |
2037 | cpu_to_le32(arg->peer_he_cap_phyinfo[i]); |
2038 | cmd->peer_ppet.numss_m1 = cpu_to_le32(arg->peer_ppet.numss_m1); |
2039 | cmd->peer_ppet.ru_info = cpu_to_le32(arg->peer_ppet.ru_bit_mask); |
2040 | for (i = 0; i < WMI_MAX_NUM_SS; i++) |
2041 | cmd->peer_ppet.ppet16_ppet8_ru3_ru0[i] = |
2042 | cpu_to_le32(arg->peer_ppet.ppet16_ppet8_ru3_ru0[i]); |
2043 | |
2044 | /* Update 11be capabilities */ |
2045 | memcpy_and_pad(dest: cmd->peer_eht_cap_mac, dest_len: sizeof(cmd->peer_eht_cap_mac), |
2046 | src: arg->peer_eht_cap_mac, count: sizeof(arg->peer_eht_cap_mac), |
2047 | pad: 0); |
2048 | memcpy_and_pad(dest: cmd->peer_eht_cap_phy, dest_len: sizeof(cmd->peer_eht_cap_phy), |
2049 | src: arg->peer_eht_cap_phy, count: sizeof(arg->peer_eht_cap_phy), |
2050 | pad: 0); |
2051 | memcpy_and_pad(dest: &cmd->peer_eht_ppet, dest_len: sizeof(cmd->peer_eht_ppet), |
2052 | src: &arg->peer_eht_ppet, count: sizeof(arg->peer_eht_ppet), pad: 0); |
2053 | |
2054 | /* Update peer legacy rate information */ |
2055 | ptr += sizeof(*cmd); |
2056 | |
2057 | tlv = ptr; |
2058 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len: peer_legacy_rates_align); |
2059 | |
2060 | ptr += TLV_HDR_SIZE; |
2061 | |
2062 | cmd->num_peer_legacy_rates = cpu_to_le32(arg->peer_legacy_rates.num_rates); |
2063 | memcpy(ptr, arg->peer_legacy_rates.rates, |
2064 | arg->peer_legacy_rates.num_rates); |
2065 | |
2066 | /* Update peer HT rate information */ |
2067 | ptr += peer_legacy_rates_align; |
2068 | |
2069 | tlv = ptr; |
2070 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len: peer_ht_rates_align); |
2071 | ptr += TLV_HDR_SIZE; |
2072 | cmd->num_peer_ht_rates = cpu_to_le32(arg->peer_ht_rates.num_rates); |
2073 | memcpy(ptr, arg->peer_ht_rates.rates, |
2074 | arg->peer_ht_rates.num_rates); |
2075 | |
2076 | /* VHT Rates */ |
2077 | ptr += peer_ht_rates_align; |
2078 | |
2079 | mcs = ptr; |
2080 | |
2081 | mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VHT_RATE_SET, |
2082 | len: sizeof(*mcs)); |
2083 | |
2084 | cmd->peer_nss = cpu_to_le32(arg->peer_nss); |
2085 | |
2086 | /* Update bandwidth-NSS mapping */ |
2087 | cmd->peer_bw_rxnss_override = 0; |
2088 | cmd->peer_bw_rxnss_override |= cpu_to_le32(arg->peer_bw_rxnss_override); |
2089 | |
2090 | if (arg->vht_capable) { |
2091 | mcs->rx_max_rate = cpu_to_le32(arg->rx_max_rate); |
2092 | mcs->rx_mcs_set = cpu_to_le32(arg->rx_mcs_set); |
2093 | mcs->tx_max_rate = cpu_to_le32(arg->tx_max_rate); |
2094 | mcs->tx_mcs_set = cpu_to_le32(arg->tx_mcs_set); |
2095 | } |
2096 | |
2097 | /* HE Rates */ |
2098 | cmd->peer_he_mcs = cpu_to_le32(arg->peer_he_mcs_count); |
2099 | cmd->min_data_rate = cpu_to_le32(arg->min_data_rate); |
2100 | |
2101 | ptr += sizeof(*mcs); |
2102 | |
2103 | len = arg->peer_he_mcs_count * sizeof(*he_mcs); |
2104 | |
2105 | tlv = ptr; |
2106 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len); |
2107 | ptr += TLV_HDR_SIZE; |
2108 | |
2109 | /* Loop through the HE rate set */ |
2110 | for (i = 0; i < arg->peer_he_mcs_count; i++) { |
2111 | he_mcs = ptr; |
2112 | he_mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_HE_RATE_SET, |
2113 | len: sizeof(*he_mcs)); |
2114 | |
2115 | he_mcs->rx_mcs_set = cpu_to_le32(arg->peer_he_rx_mcs_set[i]); |
2116 | he_mcs->tx_mcs_set = cpu_to_le32(arg->peer_he_tx_mcs_set[i]); |
2117 | ptr += sizeof(*he_mcs); |
2118 | } |
2119 | |
2120 | /* MLO header tag with 0 length */ |
2121 | len = 0; |
2122 | tlv = ptr; |
2123 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len); |
2124 | ptr += TLV_HDR_SIZE; |
2125 | |
2126 | /* Loop through the EHT rate set */ |
2127 | len = arg->peer_eht_mcs_count * sizeof(*eht_mcs); |
2128 | tlv = ptr; |
2129 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len); |
2130 | ptr += TLV_HDR_SIZE; |
2131 | |
2132 | for (i = 0; i < arg->peer_eht_mcs_count; i++) { |
2133 | eht_mcs = ptr; |
2134 | eht_mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_HE_RATE_SET, |
2135 | len: sizeof(*eht_mcs)); |
2136 | |
2137 | eht_mcs->rx_mcs_set = cpu_to_le32(arg->peer_eht_rx_mcs_set[i]); |
2138 | eht_mcs->tx_mcs_set = cpu_to_le32(arg->peer_eht_tx_mcs_set[i]); |
2139 | ptr += sizeof(*eht_mcs); |
2140 | } |
2141 | |
2142 | /* ML partner links tag with 0 length */ |
2143 | len = 0; |
2144 | tlv = ptr; |
2145 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len); |
2146 | ptr += TLV_HDR_SIZE; |
2147 | |
2148 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2149 | "wmi peer assoc vdev id %d assoc id %d peer mac %pM peer_flags %x rate_caps %x peer_caps %x listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d peer_mpdu_density %d vht_caps %x he cap_info %x he ops %x he cap_info_ext %x he phy %x %x %x peer_bw_rxnss_override %x peer_flags_ext %x eht mac_cap %x %x eht phy_cap %x %x %x\n" , |
2150 | cmd->vdev_id, cmd->peer_associd, arg->peer_mac, |
2151 | cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps, |
2152 | cmd->peer_listen_intval, cmd->peer_ht_caps, |
2153 | cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode, |
2154 | cmd->peer_mpdu_density, |
2155 | cmd->peer_vht_caps, cmd->peer_he_cap_info, |
2156 | cmd->peer_he_ops, cmd->peer_he_cap_info_ext, |
2157 | cmd->peer_he_cap_phy[0], cmd->peer_he_cap_phy[1], |
2158 | cmd->peer_he_cap_phy[2], |
2159 | cmd->peer_bw_rxnss_override, cmd->peer_flags_ext, |
2160 | cmd->peer_eht_cap_mac[0], cmd->peer_eht_cap_mac[1], |
2161 | cmd->peer_eht_cap_phy[0], cmd->peer_eht_cap_phy[1], |
2162 | cmd->peer_eht_cap_phy[2]); |
2163 | |
2164 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_PEER_ASSOC_CMDID); |
2165 | if (ret) { |
2166 | ath12k_warn(ab: ar->ab, |
2167 | fmt: "failed to send WMI_PEER_ASSOC_CMDID\n" ); |
2168 | dev_kfree_skb(skb); |
2169 | } |
2170 | |
2171 | return ret; |
2172 | } |
2173 | |
2174 | void ath12k_wmi_start_scan_init(struct ath12k *ar, |
2175 | struct ath12k_wmi_scan_req_arg *arg) |
2176 | { |
2177 | /* setup commonly used values */ |
2178 | arg->scan_req_id = 1; |
2179 | arg->scan_priority = WMI_SCAN_PRIORITY_LOW; |
2180 | arg->dwell_time_active = 50; |
2181 | arg->dwell_time_active_2g = 0; |
2182 | arg->dwell_time_passive = 150; |
2183 | arg->dwell_time_active_6g = 40; |
2184 | arg->dwell_time_passive_6g = 30; |
2185 | arg->min_rest_time = 50; |
2186 | arg->max_rest_time = 500; |
2187 | arg->repeat_probe_time = 0; |
2188 | arg->probe_spacing_time = 0; |
2189 | arg->idle_time = 0; |
2190 | arg->max_scan_time = 20000; |
2191 | arg->probe_delay = 5; |
2192 | arg->notify_scan_events = WMI_SCAN_EVENT_STARTED | |
2193 | WMI_SCAN_EVENT_COMPLETED | |
2194 | WMI_SCAN_EVENT_BSS_CHANNEL | |
2195 | WMI_SCAN_EVENT_FOREIGN_CHAN | |
2196 | WMI_SCAN_EVENT_DEQUEUED; |
2197 | arg->scan_f_chan_stat_evnt = 1; |
2198 | arg->num_bssid = 1; |
2199 | |
2200 | /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be |
2201 | * ZEROs in probe request |
2202 | */ |
2203 | eth_broadcast_addr(addr: arg->bssid_list[0].addr); |
2204 | } |
2205 | |
2206 | static void ath12k_wmi_copy_scan_event_cntrl_flags(struct wmi_start_scan_cmd *cmd, |
2207 | struct ath12k_wmi_scan_req_arg *arg) |
2208 | { |
2209 | /* Scan events subscription */ |
2210 | if (arg->scan_ev_started) |
2211 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_STARTED); |
2212 | if (arg->scan_ev_completed) |
2213 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_COMPLETED); |
2214 | if (arg->scan_ev_bss_chan) |
2215 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_BSS_CHANNEL); |
2216 | if (arg->scan_ev_foreign_chan) |
2217 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_FOREIGN_CHAN); |
2218 | if (arg->scan_ev_dequeued) |
2219 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_DEQUEUED); |
2220 | if (arg->scan_ev_preempted) |
2221 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_PREEMPTED); |
2222 | if (arg->scan_ev_start_failed) |
2223 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_START_FAILED); |
2224 | if (arg->scan_ev_restarted) |
2225 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_RESTARTED); |
2226 | if (arg->scan_ev_foreign_chn_exit) |
2227 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT); |
2228 | if (arg->scan_ev_suspended) |
2229 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_SUSPENDED); |
2230 | if (arg->scan_ev_resumed) |
2231 | cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_RESUMED); |
2232 | |
2233 | /** Set scan control flags */ |
2234 | cmd->scan_ctrl_flags = 0; |
2235 | if (arg->scan_f_passive) |
2236 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_PASSIVE); |
2237 | if (arg->scan_f_strict_passive_pch) |
2238 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_STRICT_PASSIVE_ON_PCHN); |
2239 | if (arg->scan_f_promisc_mode) |
2240 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FILTER_PROMISCUOS); |
2241 | if (arg->scan_f_capture_phy_err) |
2242 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_CAPTURE_PHY_ERROR); |
2243 | if (arg->scan_f_half_rate) |
2244 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_HALF_RATE_SUPPORT); |
2245 | if (arg->scan_f_quarter_rate) |
2246 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_QUARTER_RATE_SUPPORT); |
2247 | if (arg->scan_f_cck_rates) |
2248 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_CCK_RATES); |
2249 | if (arg->scan_f_ofdm_rates) |
2250 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_OFDM_RATES); |
2251 | if (arg->scan_f_chan_stat_evnt) |
2252 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_CHAN_STAT_EVENT); |
2253 | if (arg->scan_f_filter_prb_req) |
2254 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ); |
2255 | if (arg->scan_f_bcast_probe) |
2256 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_BCAST_PROBE_REQ); |
2257 | if (arg->scan_f_offchan_mgmt_tx) |
2258 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_OFFCHAN_MGMT_TX); |
2259 | if (arg->scan_f_offchan_data_tx) |
2260 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_OFFCHAN_DATA_TX); |
2261 | if (arg->scan_f_force_active_dfs_chn) |
2262 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS); |
2263 | if (arg->scan_f_add_tpc_ie_in_probe) |
2264 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ); |
2265 | if (arg->scan_f_add_ds_ie_in_probe) |
2266 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ); |
2267 | if (arg->scan_f_add_spoofed_mac_in_probe) |
2268 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_SPOOF_MAC_IN_PROBE_REQ); |
2269 | if (arg->scan_f_add_rand_seq_in_probe) |
2270 | cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ); |
2271 | if (arg->scan_f_en_ie_whitelist_in_probe) |
2272 | cmd->scan_ctrl_flags |= |
2273 | cpu_to_le32(WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ); |
2274 | |
2275 | cmd->scan_ctrl_flags |= le32_encode_bits(v: arg->adaptive_dwell_time_mode, |
2276 | WMI_SCAN_DWELL_MODE_MASK); |
2277 | } |
2278 | |
2279 | int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar, |
2280 | struct ath12k_wmi_scan_req_arg *arg) |
2281 | { |
2282 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2283 | struct wmi_start_scan_cmd *cmd; |
2284 | struct ath12k_wmi_ssid_params *ssid = NULL; |
2285 | struct ath12k_wmi_mac_addr_params *bssid; |
2286 | struct sk_buff *skb; |
2287 | struct wmi_tlv *tlv; |
2288 | void *ptr; |
2289 | int i, ret, len; |
2290 | u32 *tmp_ptr, = 0; |
2291 | struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL; |
2292 | struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL; |
2293 | |
2294 | len = sizeof(*cmd); |
2295 | |
2296 | len += TLV_HDR_SIZE; |
2297 | if (arg->num_chan) |
2298 | len += arg->num_chan * sizeof(u32); |
2299 | |
2300 | len += TLV_HDR_SIZE; |
2301 | if (arg->num_ssids) |
2302 | len += arg->num_ssids * sizeof(*ssid); |
2303 | |
2304 | len += TLV_HDR_SIZE; |
2305 | if (arg->num_bssid) |
2306 | len += sizeof(*bssid) * arg->num_bssid; |
2307 | |
2308 | if (arg->num_hint_bssid) |
2309 | len += TLV_HDR_SIZE + |
2310 | arg->num_hint_bssid * sizeof(*hint_bssid); |
2311 | |
2312 | if (arg->num_hint_s_ssid) |
2313 | len += TLV_HDR_SIZE + |
2314 | arg->num_hint_s_ssid * sizeof(*s_ssid); |
2315 | |
2316 | len += TLV_HDR_SIZE; |
2317 | if (arg->extraie.len) |
2318 | extraie_len_with_pad = |
2319 | roundup(arg->extraie.len, sizeof(u32)); |
2320 | if (extraie_len_with_pad <= (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len)) { |
2321 | len += extraie_len_with_pad; |
2322 | } else { |
2323 | ath12k_warn(ab: ar->ab, fmt: "discard large size %d bytes extraie for scan start\n" , |
2324 | arg->extraie.len); |
2325 | extraie_len_with_pad = 0; |
2326 | } |
2327 | |
2328 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
2329 | if (!skb) |
2330 | return -ENOMEM; |
2331 | |
2332 | ptr = skb->data; |
2333 | |
2334 | cmd = ptr; |
2335 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_START_SCAN_CMD, |
2336 | len: sizeof(*cmd)); |
2337 | |
2338 | cmd->scan_id = cpu_to_le32(arg->scan_id); |
2339 | cmd->scan_req_id = cpu_to_le32(arg->scan_req_id); |
2340 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
2341 | cmd->scan_priority = cpu_to_le32(arg->scan_priority); |
2342 | cmd->notify_scan_events = cpu_to_le32(arg->notify_scan_events); |
2343 | |
2344 | ath12k_wmi_copy_scan_event_cntrl_flags(cmd, arg); |
2345 | |
2346 | cmd->dwell_time_active = cpu_to_le32(arg->dwell_time_active); |
2347 | cmd->dwell_time_active_2g = cpu_to_le32(arg->dwell_time_active_2g); |
2348 | cmd->dwell_time_passive = cpu_to_le32(arg->dwell_time_passive); |
2349 | cmd->dwell_time_active_6g = cpu_to_le32(arg->dwell_time_active_6g); |
2350 | cmd->dwell_time_passive_6g = cpu_to_le32(arg->dwell_time_passive_6g); |
2351 | cmd->min_rest_time = cpu_to_le32(arg->min_rest_time); |
2352 | cmd->max_rest_time = cpu_to_le32(arg->max_rest_time); |
2353 | cmd->repeat_probe_time = cpu_to_le32(arg->repeat_probe_time); |
2354 | cmd->probe_spacing_time = cpu_to_le32(arg->probe_spacing_time); |
2355 | cmd->idle_time = cpu_to_le32(arg->idle_time); |
2356 | cmd->max_scan_time = cpu_to_le32(arg->max_scan_time); |
2357 | cmd->probe_delay = cpu_to_le32(arg->probe_delay); |
2358 | cmd->burst_duration = cpu_to_le32(arg->burst_duration); |
2359 | cmd->num_chan = cpu_to_le32(arg->num_chan); |
2360 | cmd->num_bssid = cpu_to_le32(arg->num_bssid); |
2361 | cmd->num_ssids = cpu_to_le32(arg->num_ssids); |
2362 | cmd->ie_len = cpu_to_le32(arg->extraie.len); |
2363 | cmd->n_probes = cpu_to_le32(arg->n_probes); |
2364 | |
2365 | ptr += sizeof(*cmd); |
2366 | |
2367 | len = arg->num_chan * sizeof(u32); |
2368 | |
2369 | tlv = ptr; |
2370 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_UINT32, len); |
2371 | ptr += TLV_HDR_SIZE; |
2372 | tmp_ptr = (u32 *)ptr; |
2373 | |
2374 | memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4); |
2375 | |
2376 | ptr += len; |
2377 | |
2378 | len = arg->num_ssids * sizeof(*ssid); |
2379 | tlv = ptr; |
2380 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_FIXED_STRUCT, len); |
2381 | |
2382 | ptr += TLV_HDR_SIZE; |
2383 | |
2384 | if (arg->num_ssids) { |
2385 | ssid = ptr; |
2386 | for (i = 0; i < arg->num_ssids; ++i) { |
2387 | ssid->ssid_len = cpu_to_le32(arg->ssid[i].ssid_len); |
2388 | memcpy(ssid->ssid, arg->ssid[i].ssid, |
2389 | arg->ssid[i].ssid_len); |
2390 | ssid++; |
2391 | } |
2392 | } |
2393 | |
2394 | ptr += (arg->num_ssids * sizeof(*ssid)); |
2395 | len = arg->num_bssid * sizeof(*bssid); |
2396 | tlv = ptr; |
2397 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_FIXED_STRUCT, len); |
2398 | |
2399 | ptr += TLV_HDR_SIZE; |
2400 | bssid = ptr; |
2401 | |
2402 | if (arg->num_bssid) { |
2403 | for (i = 0; i < arg->num_bssid; ++i) { |
2404 | ether_addr_copy(dst: bssid->addr, |
2405 | src: arg->bssid_list[i].addr); |
2406 | bssid++; |
2407 | } |
2408 | } |
2409 | |
2410 | ptr += arg->num_bssid * sizeof(*bssid); |
2411 | |
2412 | len = extraie_len_with_pad; |
2413 | tlv = ptr; |
2414 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len); |
2415 | ptr += TLV_HDR_SIZE; |
2416 | |
2417 | if (extraie_len_with_pad) |
2418 | memcpy(ptr, arg->extraie.ptr, |
2419 | arg->extraie.len); |
2420 | |
2421 | ptr += extraie_len_with_pad; |
2422 | |
2423 | if (arg->num_hint_s_ssid) { |
2424 | len = arg->num_hint_s_ssid * sizeof(*s_ssid); |
2425 | tlv = ptr; |
2426 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_FIXED_STRUCT, len); |
2427 | ptr += TLV_HDR_SIZE; |
2428 | s_ssid = ptr; |
2429 | for (i = 0; i < arg->num_hint_s_ssid; ++i) { |
2430 | s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags; |
2431 | s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid; |
2432 | s_ssid++; |
2433 | } |
2434 | ptr += len; |
2435 | } |
2436 | |
2437 | if (arg->num_hint_bssid) { |
2438 | len = arg->num_hint_bssid * sizeof(struct ath12k_wmi_hint_bssid_arg); |
2439 | tlv = ptr; |
2440 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_FIXED_STRUCT, len); |
2441 | ptr += TLV_HDR_SIZE; |
2442 | hint_bssid = ptr; |
2443 | for (i = 0; i < arg->num_hint_bssid; ++i) { |
2444 | hint_bssid->freq_flags = |
2445 | arg->hint_bssid[i].freq_flags; |
2446 | ether_addr_copy(dst: &arg->hint_bssid[i].bssid.addr[0], |
2447 | src: &hint_bssid->bssid.addr[0]); |
2448 | hint_bssid++; |
2449 | } |
2450 | } |
2451 | |
2452 | ret = ath12k_wmi_cmd_send(wmi, skb, |
2453 | cmd_id: WMI_START_SCAN_CMDID); |
2454 | if (ret) { |
2455 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_START_SCAN_CMDID\n" ); |
2456 | dev_kfree_skb(skb); |
2457 | } |
2458 | |
2459 | return ret; |
2460 | } |
2461 | |
2462 | int ath12k_wmi_send_scan_stop_cmd(struct ath12k *ar, |
2463 | struct ath12k_wmi_scan_cancel_arg *arg) |
2464 | { |
2465 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2466 | struct wmi_stop_scan_cmd *cmd; |
2467 | struct sk_buff *skb; |
2468 | int ret; |
2469 | |
2470 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2471 | if (!skb) |
2472 | return -ENOMEM; |
2473 | |
2474 | cmd = (struct wmi_stop_scan_cmd *)skb->data; |
2475 | |
2476 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_STOP_SCAN_CMD, |
2477 | len: sizeof(*cmd)); |
2478 | |
2479 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
2480 | cmd->requestor = cpu_to_le32(arg->requester); |
2481 | cmd->scan_id = cpu_to_le32(arg->scan_id); |
2482 | cmd->pdev_id = cpu_to_le32(arg->pdev_id); |
2483 | /* stop the scan with the corresponding scan_id */ |
2484 | if (arg->req_type == WLAN_SCAN_CANCEL_PDEV_ALL) { |
2485 | /* Cancelling all scans */ |
2486 | cmd->req_type = cpu_to_le32(WMI_SCAN_STOP_ALL); |
2487 | } else if (arg->req_type == WLAN_SCAN_CANCEL_VDEV_ALL) { |
2488 | /* Cancelling VAP scans */ |
2489 | cmd->req_type = cpu_to_le32(WMI_SCAN_STOP_VAP_ALL); |
2490 | } else if (arg->req_type == WLAN_SCAN_CANCEL_SINGLE) { |
2491 | /* Cancelling specific scan */ |
2492 | cmd->req_type = WMI_SCAN_STOP_ONE; |
2493 | } else { |
2494 | ath12k_warn(ab: ar->ab, fmt: "invalid scan cancel req_type %d" , |
2495 | arg->req_type); |
2496 | dev_kfree_skb(skb); |
2497 | return -EINVAL; |
2498 | } |
2499 | |
2500 | ret = ath12k_wmi_cmd_send(wmi, skb, |
2501 | cmd_id: WMI_STOP_SCAN_CMDID); |
2502 | if (ret) { |
2503 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_STOP_SCAN_CMDID\n" ); |
2504 | dev_kfree_skb(skb); |
2505 | } |
2506 | |
2507 | return ret; |
2508 | } |
2509 | |
2510 | int ath12k_wmi_send_scan_chan_list_cmd(struct ath12k *ar, |
2511 | struct ath12k_wmi_scan_chan_list_arg *arg) |
2512 | { |
2513 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2514 | struct wmi_scan_chan_list_cmd *cmd; |
2515 | struct sk_buff *skb; |
2516 | struct ath12k_wmi_channel_params *chan_info; |
2517 | struct ath12k_wmi_channel_arg *channel_arg; |
2518 | struct wmi_tlv *tlv; |
2519 | void *ptr; |
2520 | int i, ret, len; |
2521 | u16 num_send_chans, num_sends = 0, max_chan_limit = 0; |
2522 | __le32 *reg1, *reg2; |
2523 | |
2524 | channel_arg = &arg->channel[0]; |
2525 | while (arg->nallchans) { |
2526 | len = sizeof(*cmd) + TLV_HDR_SIZE; |
2527 | max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) / |
2528 | sizeof(*chan_info); |
2529 | |
2530 | num_send_chans = min(arg->nallchans, max_chan_limit); |
2531 | |
2532 | arg->nallchans -= num_send_chans; |
2533 | len += sizeof(*chan_info) * num_send_chans; |
2534 | |
2535 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
2536 | if (!skb) |
2537 | return -ENOMEM; |
2538 | |
2539 | cmd = (struct wmi_scan_chan_list_cmd *)skb->data; |
2540 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_SCAN_CHAN_LIST_CMD, |
2541 | len: sizeof(*cmd)); |
2542 | cmd->pdev_id = cpu_to_le32(arg->pdev_id); |
2543 | cmd->num_scan_chans = cpu_to_le32(num_send_chans); |
2544 | if (num_sends) |
2545 | cmd->flags |= cpu_to_le32(WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG); |
2546 | |
2547 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2548 | "WMI no.of chan = %d len = %d pdev_id = %d num_sends = %d\n" , |
2549 | num_send_chans, len, cmd->pdev_id, num_sends); |
2550 | |
2551 | ptr = skb->data + sizeof(*cmd); |
2552 | |
2553 | len = sizeof(*chan_info) * num_send_chans; |
2554 | tlv = ptr; |
2555 | tlv->header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_ARRAY_STRUCT, |
2556 | len); |
2557 | ptr += TLV_HDR_SIZE; |
2558 | |
2559 | for (i = 0; i < num_send_chans; ++i) { |
2560 | chan_info = ptr; |
2561 | memset(chan_info, 0, sizeof(*chan_info)); |
2562 | len = sizeof(*chan_info); |
2563 | chan_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_CHANNEL, |
2564 | len); |
2565 | |
2566 | reg1 = &chan_info->reg_info_1; |
2567 | reg2 = &chan_info->reg_info_2; |
2568 | chan_info->mhz = cpu_to_le32(channel_arg->mhz); |
2569 | chan_info->band_center_freq1 = cpu_to_le32(channel_arg->cfreq1); |
2570 | chan_info->band_center_freq2 = cpu_to_le32(channel_arg->cfreq2); |
2571 | |
2572 | if (channel_arg->is_chan_passive) |
2573 | chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_PASSIVE); |
2574 | if (channel_arg->allow_he) |
2575 | chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HE); |
2576 | else if (channel_arg->allow_vht) |
2577 | chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_VHT); |
2578 | else if (channel_arg->allow_ht) |
2579 | chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HT); |
2580 | if (channel_arg->half_rate) |
2581 | chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_HALF_RATE); |
2582 | if (channel_arg->quarter_rate) |
2583 | chan_info->info |= |
2584 | cpu_to_le32(WMI_CHAN_INFO_QUARTER_RATE); |
2585 | |
2586 | if (channel_arg->psc_channel) |
2587 | chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_PSC); |
2588 | |
2589 | if (channel_arg->dfs_set) |
2590 | chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_DFS); |
2591 | |
2592 | chan_info->info |= le32_encode_bits(v: channel_arg->phy_mode, |
2593 | WMI_CHAN_INFO_MODE); |
2594 | *reg1 |= le32_encode_bits(v: channel_arg->minpower, |
2595 | WMI_CHAN_REG_INFO1_MIN_PWR); |
2596 | *reg1 |= le32_encode_bits(v: channel_arg->maxpower, |
2597 | WMI_CHAN_REG_INFO1_MAX_PWR); |
2598 | *reg1 |= le32_encode_bits(v: channel_arg->maxregpower, |
2599 | WMI_CHAN_REG_INFO1_MAX_REG_PWR); |
2600 | *reg1 |= le32_encode_bits(v: channel_arg->reg_class_id, |
2601 | WMI_CHAN_REG_INFO1_REG_CLS); |
2602 | *reg2 |= le32_encode_bits(v: channel_arg->antennamax, |
2603 | WMI_CHAN_REG_INFO2_ANT_MAX); |
2604 | |
2605 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2606 | "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n" , |
2607 | i, chan_info->mhz, chan_info->info); |
2608 | |
2609 | ptr += sizeof(*chan_info); |
2610 | |
2611 | channel_arg++; |
2612 | } |
2613 | |
2614 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_SCAN_CHAN_LIST_CMDID); |
2615 | if (ret) { |
2616 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_SCAN_CHAN_LIST cmd\n" ); |
2617 | dev_kfree_skb(skb); |
2618 | return ret; |
2619 | } |
2620 | |
2621 | num_sends++; |
2622 | } |
2623 | |
2624 | return 0; |
2625 | } |
2626 | |
2627 | int ath12k_wmi_send_wmm_update_cmd(struct ath12k *ar, u32 vdev_id, |
2628 | struct wmi_wmm_params_all_arg *param) |
2629 | { |
2630 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2631 | struct wmi_vdev_set_wmm_params_cmd *cmd; |
2632 | struct wmi_wmm_params *wmm_param; |
2633 | struct wmi_wmm_params_arg *wmi_wmm_arg; |
2634 | struct sk_buff *skb; |
2635 | int ret, ac; |
2636 | |
2637 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2638 | if (!skb) |
2639 | return -ENOMEM; |
2640 | |
2641 | cmd = (struct wmi_vdev_set_wmm_params_cmd *)skb->data; |
2642 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_SET_WMM_PARAMS_CMD, |
2643 | len: sizeof(*cmd)); |
2644 | |
2645 | cmd->vdev_id = cpu_to_le32(vdev_id); |
2646 | cmd->wmm_param_type = 0; |
2647 | |
2648 | for (ac = 0; ac < WME_NUM_AC; ac++) { |
2649 | switch (ac) { |
2650 | case WME_AC_BE: |
2651 | wmi_wmm_arg = ¶m->ac_be; |
2652 | break; |
2653 | case WME_AC_BK: |
2654 | wmi_wmm_arg = ¶m->ac_bk; |
2655 | break; |
2656 | case WME_AC_VI: |
2657 | wmi_wmm_arg = ¶m->ac_vi; |
2658 | break; |
2659 | case WME_AC_VO: |
2660 | wmi_wmm_arg = ¶m->ac_vo; |
2661 | break; |
2662 | } |
2663 | |
2664 | wmm_param = (struct wmi_wmm_params *)&cmd->wmm_params[ac]; |
2665 | wmm_param->tlv_header = |
2666 | ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_SET_WMM_PARAMS_CMD, |
2667 | len: sizeof(*wmm_param)); |
2668 | |
2669 | wmm_param->aifs = cpu_to_le32(wmi_wmm_arg->aifs); |
2670 | wmm_param->cwmin = cpu_to_le32(wmi_wmm_arg->cwmin); |
2671 | wmm_param->cwmax = cpu_to_le32(wmi_wmm_arg->cwmax); |
2672 | wmm_param->txoplimit = cpu_to_le32(wmi_wmm_arg->txop); |
2673 | wmm_param->acm = cpu_to_le32(wmi_wmm_arg->acm); |
2674 | wmm_param->no_ack = cpu_to_le32(wmi_wmm_arg->no_ack); |
2675 | |
2676 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2677 | "wmi wmm set ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n" , |
2678 | ac, wmm_param->aifs, wmm_param->cwmin, |
2679 | wmm_param->cwmax, wmm_param->txoplimit, |
2680 | wmm_param->acm, wmm_param->no_ack); |
2681 | } |
2682 | ret = ath12k_wmi_cmd_send(wmi, skb, |
2683 | cmd_id: WMI_VDEV_SET_WMM_PARAMS_CMDID); |
2684 | if (ret) { |
2685 | ath12k_warn(ab: ar->ab, |
2686 | fmt: "failed to send WMI_VDEV_SET_WMM_PARAMS_CMDID" ); |
2687 | dev_kfree_skb(skb); |
2688 | } |
2689 | |
2690 | return ret; |
2691 | } |
2692 | |
2693 | int ath12k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath12k *ar, |
2694 | u32 pdev_id) |
2695 | { |
2696 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2697 | struct wmi_dfs_phyerr_offload_cmd *cmd; |
2698 | struct sk_buff *skb; |
2699 | int ret; |
2700 | |
2701 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2702 | if (!skb) |
2703 | return -ENOMEM; |
2704 | |
2705 | cmd = (struct wmi_dfs_phyerr_offload_cmd *)skb->data; |
2706 | cmd->tlv_header = |
2707 | ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMD, |
2708 | len: sizeof(*cmd)); |
2709 | |
2710 | cmd->pdev_id = cpu_to_le32(pdev_id); |
2711 | |
2712 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2713 | "WMI dfs phy err offload enable pdev id %d\n" , pdev_id); |
2714 | |
2715 | ret = ath12k_wmi_cmd_send(wmi, skb, |
2716 | cmd_id: WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID); |
2717 | if (ret) { |
2718 | ath12k_warn(ab: ar->ab, |
2719 | fmt: "failed to send WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE cmd\n" ); |
2720 | dev_kfree_skb(skb); |
2721 | } |
2722 | |
2723 | return ret; |
2724 | } |
2725 | |
2726 | int ath12k_wmi_delba_send(struct ath12k *ar, u32 vdev_id, const u8 *mac, |
2727 | u32 tid, u32 initiator, u32 reason) |
2728 | { |
2729 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2730 | struct wmi_delba_send_cmd *cmd; |
2731 | struct sk_buff *skb; |
2732 | int ret; |
2733 | |
2734 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2735 | if (!skb) |
2736 | return -ENOMEM; |
2737 | |
2738 | cmd = (struct wmi_delba_send_cmd *)skb->data; |
2739 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_DELBA_SEND_CMD, |
2740 | len: sizeof(*cmd)); |
2741 | cmd->vdev_id = cpu_to_le32(vdev_id); |
2742 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: mac); |
2743 | cmd->tid = cpu_to_le32(tid); |
2744 | cmd->initiator = cpu_to_le32(initiator); |
2745 | cmd->reasoncode = cpu_to_le32(reason); |
2746 | |
2747 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2748 | "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n" , |
2749 | vdev_id, mac, tid, initiator, reason); |
2750 | |
2751 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_DELBA_SEND_CMDID); |
2752 | |
2753 | if (ret) { |
2754 | ath12k_warn(ab: ar->ab, |
2755 | fmt: "failed to send WMI_DELBA_SEND_CMDID cmd\n" ); |
2756 | dev_kfree_skb(skb); |
2757 | } |
2758 | |
2759 | return ret; |
2760 | } |
2761 | |
2762 | int ath12k_wmi_addba_set_resp(struct ath12k *ar, u32 vdev_id, const u8 *mac, |
2763 | u32 tid, u32 status) |
2764 | { |
2765 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2766 | struct wmi_addba_setresponse_cmd *cmd; |
2767 | struct sk_buff *skb; |
2768 | int ret; |
2769 | |
2770 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2771 | if (!skb) |
2772 | return -ENOMEM; |
2773 | |
2774 | cmd = (struct wmi_addba_setresponse_cmd *)skb->data; |
2775 | cmd->tlv_header = |
2776 | ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_ADDBA_SETRESPONSE_CMD, |
2777 | len: sizeof(*cmd)); |
2778 | cmd->vdev_id = cpu_to_le32(vdev_id); |
2779 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: mac); |
2780 | cmd->tid = cpu_to_le32(tid); |
2781 | cmd->statuscode = cpu_to_le32(status); |
2782 | |
2783 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2784 | "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n" , |
2785 | vdev_id, mac, tid, status); |
2786 | |
2787 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_ADDBA_SET_RESP_CMDID); |
2788 | |
2789 | if (ret) { |
2790 | ath12k_warn(ab: ar->ab, |
2791 | fmt: "failed to send WMI_ADDBA_SET_RESP_CMDID cmd\n" ); |
2792 | dev_kfree_skb(skb); |
2793 | } |
2794 | |
2795 | return ret; |
2796 | } |
2797 | |
2798 | int ath12k_wmi_addba_send(struct ath12k *ar, u32 vdev_id, const u8 *mac, |
2799 | u32 tid, u32 buf_size) |
2800 | { |
2801 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2802 | struct wmi_addba_send_cmd *cmd; |
2803 | struct sk_buff *skb; |
2804 | int ret; |
2805 | |
2806 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2807 | if (!skb) |
2808 | return -ENOMEM; |
2809 | |
2810 | cmd = (struct wmi_addba_send_cmd *)skb->data; |
2811 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_ADDBA_SEND_CMD, |
2812 | len: sizeof(*cmd)); |
2813 | cmd->vdev_id = cpu_to_le32(vdev_id); |
2814 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: mac); |
2815 | cmd->tid = cpu_to_le32(tid); |
2816 | cmd->buffersize = cpu_to_le32(buf_size); |
2817 | |
2818 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2819 | "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n" , |
2820 | vdev_id, mac, tid, buf_size); |
2821 | |
2822 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_ADDBA_SEND_CMDID); |
2823 | |
2824 | if (ret) { |
2825 | ath12k_warn(ab: ar->ab, |
2826 | fmt: "failed to send WMI_ADDBA_SEND_CMDID cmd\n" ); |
2827 | dev_kfree_skb(skb); |
2828 | } |
2829 | |
2830 | return ret; |
2831 | } |
2832 | |
2833 | int ath12k_wmi_addba_clear_resp(struct ath12k *ar, u32 vdev_id, const u8 *mac) |
2834 | { |
2835 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2836 | struct wmi_addba_clear_resp_cmd *cmd; |
2837 | struct sk_buff *skb; |
2838 | int ret; |
2839 | |
2840 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2841 | if (!skb) |
2842 | return -ENOMEM; |
2843 | |
2844 | cmd = (struct wmi_addba_clear_resp_cmd *)skb->data; |
2845 | cmd->tlv_header = |
2846 | ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_ADDBA_CLEAR_RESP_CMD, |
2847 | len: sizeof(*cmd)); |
2848 | cmd->vdev_id = cpu_to_le32(vdev_id); |
2849 | ether_addr_copy(dst: cmd->peer_macaddr.addr, src: mac); |
2850 | |
2851 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
2852 | "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n" , |
2853 | vdev_id, mac); |
2854 | |
2855 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_ADDBA_CLEAR_RESP_CMDID); |
2856 | |
2857 | if (ret) { |
2858 | ath12k_warn(ab: ar->ab, |
2859 | fmt: "failed to send WMI_ADDBA_CLEAR_RESP_CMDID cmd\n" ); |
2860 | dev_kfree_skb(skb); |
2861 | } |
2862 | |
2863 | return ret; |
2864 | } |
2865 | |
2866 | int ath12k_wmi_send_init_country_cmd(struct ath12k *ar, |
2867 | struct ath12k_wmi_init_country_arg *arg) |
2868 | { |
2869 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2870 | struct wmi_init_country_cmd *cmd; |
2871 | struct sk_buff *skb; |
2872 | int ret; |
2873 | |
2874 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: sizeof(*cmd)); |
2875 | if (!skb) |
2876 | return -ENOMEM; |
2877 | |
2878 | cmd = (struct wmi_init_country_cmd *)skb->data; |
2879 | cmd->tlv_header = |
2880 | ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_SET_INIT_COUNTRY_CMD, |
2881 | len: sizeof(*cmd)); |
2882 | |
2883 | cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id); |
2884 | |
2885 | switch (arg->flags) { |
2886 | case ALPHA_IS_SET: |
2887 | cmd->init_cc_type = WMI_COUNTRY_INFO_TYPE_ALPHA; |
2888 | memcpy(&cmd->cc_info.alpha2, arg->cc_info.alpha2, 3); |
2889 | break; |
2890 | case CC_IS_SET: |
2891 | cmd->init_cc_type = cpu_to_le32(WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE); |
2892 | cmd->cc_info.country_code = |
2893 | cpu_to_le32(arg->cc_info.country_code); |
2894 | break; |
2895 | case REGDMN_IS_SET: |
2896 | cmd->init_cc_type = cpu_to_le32(WMI_COUNTRY_INFO_TYPE_REGDOMAIN); |
2897 | cmd->cc_info.regdom_id = cpu_to_le32(arg->cc_info.regdom_id); |
2898 | break; |
2899 | default: |
2900 | ret = -EINVAL; |
2901 | goto out; |
2902 | } |
2903 | |
2904 | ret = ath12k_wmi_cmd_send(wmi, skb, |
2905 | cmd_id: WMI_SET_INIT_COUNTRY_CMDID); |
2906 | |
2907 | out: |
2908 | if (ret) { |
2909 | ath12k_warn(ab: ar->ab, |
2910 | fmt: "failed to send WMI_SET_INIT_COUNTRY CMD :%d\n" , |
2911 | ret); |
2912 | dev_kfree_skb(skb); |
2913 | } |
2914 | |
2915 | return ret; |
2916 | } |
2917 | |
2918 | int |
2919 | ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id) |
2920 | { |
2921 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2922 | struct ath12k_base *ab = wmi->wmi_ab->ab; |
2923 | struct wmi_twt_enable_params_cmd *cmd; |
2924 | struct sk_buff *skb; |
2925 | int ret, len; |
2926 | |
2927 | len = sizeof(*cmd); |
2928 | |
2929 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
2930 | if (!skb) |
2931 | return -ENOMEM; |
2932 | |
2933 | cmd = (struct wmi_twt_enable_params_cmd *)skb->data; |
2934 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_TWT_ENABLE_CMD, |
2935 | len); |
2936 | cmd->pdev_id = cpu_to_le32(pdev_id); |
2937 | cmd->sta_cong_timer_ms = cpu_to_le32(ATH12K_TWT_DEF_STA_CONG_TIMER_MS); |
2938 | cmd->default_slot_size = cpu_to_le32(ATH12K_TWT_DEF_DEFAULT_SLOT_SIZE); |
2939 | cmd->congestion_thresh_setup = |
2940 | cpu_to_le32(ATH12K_TWT_DEF_CONGESTION_THRESH_SETUP); |
2941 | cmd->congestion_thresh_teardown = |
2942 | cpu_to_le32(ATH12K_TWT_DEF_CONGESTION_THRESH_TEARDOWN); |
2943 | cmd->congestion_thresh_critical = |
2944 | cpu_to_le32(ATH12K_TWT_DEF_CONGESTION_THRESH_CRITICAL); |
2945 | cmd->interference_thresh_teardown = |
2946 | cpu_to_le32(ATH12K_TWT_DEF_INTERFERENCE_THRESH_TEARDOWN); |
2947 | cmd->interference_thresh_setup = |
2948 | cpu_to_le32(ATH12K_TWT_DEF_INTERFERENCE_THRESH_SETUP); |
2949 | cmd->min_no_sta_setup = cpu_to_le32(ATH12K_TWT_DEF_MIN_NO_STA_SETUP); |
2950 | cmd->min_no_sta_teardown = cpu_to_le32(ATH12K_TWT_DEF_MIN_NO_STA_TEARDOWN); |
2951 | cmd->no_of_bcast_mcast_slots = |
2952 | cpu_to_le32(ATH12K_TWT_DEF_NO_OF_BCAST_MCAST_SLOTS); |
2953 | cmd->min_no_twt_slots = cpu_to_le32(ATH12K_TWT_DEF_MIN_NO_TWT_SLOTS); |
2954 | cmd->max_no_sta_twt = cpu_to_le32(ATH12K_TWT_DEF_MAX_NO_STA_TWT); |
2955 | cmd->mode_check_interval = cpu_to_le32(ATH12K_TWT_DEF_MODE_CHECK_INTERVAL); |
2956 | cmd->add_sta_slot_interval = cpu_to_le32(ATH12K_TWT_DEF_ADD_STA_SLOT_INTERVAL); |
2957 | cmd->remove_sta_slot_interval = |
2958 | cpu_to_le32(ATH12K_TWT_DEF_REMOVE_STA_SLOT_INTERVAL); |
2959 | /* TODO add MBSSID support */ |
2960 | cmd->mbss_support = 0; |
2961 | |
2962 | ret = ath12k_wmi_cmd_send(wmi, skb, |
2963 | cmd_id: WMI_TWT_ENABLE_CMDID); |
2964 | if (ret) { |
2965 | ath12k_warn(ab, fmt: "Failed to send WMI_TWT_ENABLE_CMDID" ); |
2966 | dev_kfree_skb(skb); |
2967 | } |
2968 | return ret; |
2969 | } |
2970 | |
2971 | int |
2972 | ath12k_wmi_send_twt_disable_cmd(struct ath12k *ar, u32 pdev_id) |
2973 | { |
2974 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
2975 | struct ath12k_base *ab = wmi->wmi_ab->ab; |
2976 | struct wmi_twt_disable_params_cmd *cmd; |
2977 | struct sk_buff *skb; |
2978 | int ret, len; |
2979 | |
2980 | len = sizeof(*cmd); |
2981 | |
2982 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
2983 | if (!skb) |
2984 | return -ENOMEM; |
2985 | |
2986 | cmd = (struct wmi_twt_disable_params_cmd *)skb->data; |
2987 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_TWT_DISABLE_CMD, |
2988 | len); |
2989 | cmd->pdev_id = cpu_to_le32(pdev_id); |
2990 | |
2991 | ret = ath12k_wmi_cmd_send(wmi, skb, |
2992 | cmd_id: WMI_TWT_DISABLE_CMDID); |
2993 | if (ret) { |
2994 | ath12k_warn(ab, fmt: "Failed to send WMI_TWT_DISABLE_CMDID" ); |
2995 | dev_kfree_skb(skb); |
2996 | } |
2997 | return ret; |
2998 | } |
2999 | |
3000 | int |
3001 | ath12k_wmi_send_obss_spr_cmd(struct ath12k *ar, u32 vdev_id, |
3002 | struct ieee80211_he_obss_pd *he_obss_pd) |
3003 | { |
3004 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
3005 | struct ath12k_base *ab = wmi->wmi_ab->ab; |
3006 | struct wmi_obss_spatial_reuse_params_cmd *cmd; |
3007 | struct sk_buff *skb; |
3008 | int ret, len; |
3009 | |
3010 | len = sizeof(*cmd); |
3011 | |
3012 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
3013 | if (!skb) |
3014 | return -ENOMEM; |
3015 | |
3016 | cmd = (struct wmi_obss_spatial_reuse_params_cmd *)skb->data; |
3017 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_OBSS_SPATIAL_REUSE_SET_CMD, |
3018 | len); |
3019 | cmd->vdev_id = cpu_to_le32(vdev_id); |
3020 | cmd->enable = cpu_to_le32(he_obss_pd->enable); |
3021 | cmd->obss_min = a_cpu_to_sle32(val: he_obss_pd->min_offset); |
3022 | cmd->obss_max = a_cpu_to_sle32(val: he_obss_pd->max_offset); |
3023 | |
3024 | ret = ath12k_wmi_cmd_send(wmi, skb, |
3025 | cmd_id: WMI_PDEV_OBSS_PD_SPATIAL_REUSE_CMDID); |
3026 | if (ret) { |
3027 | ath12k_warn(ab, |
3028 | fmt: "Failed to send WMI_PDEV_OBSS_PD_SPATIAL_REUSE_CMDID" ); |
3029 | dev_kfree_skb(skb); |
3030 | } |
3031 | return ret; |
3032 | } |
3033 | |
3034 | int ath12k_wmi_obss_color_cfg_cmd(struct ath12k *ar, u32 vdev_id, |
3035 | u8 bss_color, u32 period, |
3036 | bool enable) |
3037 | { |
3038 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
3039 | struct ath12k_base *ab = wmi->wmi_ab->ab; |
3040 | struct wmi_obss_color_collision_cfg_params_cmd *cmd; |
3041 | struct sk_buff *skb; |
3042 | int ret, len; |
3043 | |
3044 | len = sizeof(*cmd); |
3045 | |
3046 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
3047 | if (!skb) |
3048 | return -ENOMEM; |
3049 | |
3050 | cmd = (struct wmi_obss_color_collision_cfg_params_cmd *)skb->data; |
3051 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_OBSS_COLOR_COLLISION_DET_CONFIG, |
3052 | len); |
3053 | cmd->vdev_id = cpu_to_le32(vdev_id); |
3054 | cmd->evt_type = enable ? cpu_to_le32(ATH12K_OBSS_COLOR_COLLISION_DETECTION) : |
3055 | cpu_to_le32(ATH12K_OBSS_COLOR_COLLISION_DETECTION_DISABLE); |
3056 | cmd->current_bss_color = cpu_to_le32(bss_color); |
3057 | cmd->detection_period_ms = cpu_to_le32(period); |
3058 | cmd->scan_period_ms = cpu_to_le32(ATH12K_BSS_COLOR_COLLISION_SCAN_PERIOD_MS); |
3059 | cmd->free_slot_expiry_time_ms = 0; |
3060 | cmd->flags = 0; |
3061 | |
3062 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3063 | "wmi_send_obss_color_collision_cfg id %d type %d bss_color %d detect_period %d scan_period %d\n" , |
3064 | cmd->vdev_id, cmd->evt_type, cmd->current_bss_color, |
3065 | cmd->detection_period_ms, cmd->scan_period_ms); |
3066 | |
3067 | ret = ath12k_wmi_cmd_send(wmi, skb, |
3068 | cmd_id: WMI_OBSS_COLOR_COLLISION_DET_CONFIG_CMDID); |
3069 | if (ret) { |
3070 | ath12k_warn(ab, fmt: "Failed to send WMI_OBSS_COLOR_COLLISION_DET_CONFIG_CMDID" ); |
3071 | dev_kfree_skb(skb); |
3072 | } |
3073 | return ret; |
3074 | } |
3075 | |
3076 | int ath12k_wmi_send_bss_color_change_enable_cmd(struct ath12k *ar, u32 vdev_id, |
3077 | bool enable) |
3078 | { |
3079 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
3080 | struct ath12k_base *ab = wmi->wmi_ab->ab; |
3081 | struct wmi_bss_color_change_enable_params_cmd *cmd; |
3082 | struct sk_buff *skb; |
3083 | int ret, len; |
3084 | |
3085 | len = sizeof(*cmd); |
3086 | |
3087 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
3088 | if (!skb) |
3089 | return -ENOMEM; |
3090 | |
3091 | cmd = (struct wmi_bss_color_change_enable_params_cmd *)skb->data; |
3092 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_BSS_COLOR_CHANGE_ENABLE, |
3093 | len); |
3094 | cmd->vdev_id = cpu_to_le32(vdev_id); |
3095 | cmd->enable = enable ? cpu_to_le32(1) : 0; |
3096 | |
3097 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3098 | "wmi_send_bss_color_change_enable id %d enable %d\n" , |
3099 | cmd->vdev_id, cmd->enable); |
3100 | |
3101 | ret = ath12k_wmi_cmd_send(wmi, skb, |
3102 | cmd_id: WMI_BSS_COLOR_CHANGE_ENABLE_CMDID); |
3103 | if (ret) { |
3104 | ath12k_warn(ab, fmt: "Failed to send WMI_BSS_COLOR_CHANGE_ENABLE_CMDID" ); |
3105 | dev_kfree_skb(skb); |
3106 | } |
3107 | return ret; |
3108 | } |
3109 | |
3110 | int ath12k_wmi_fils_discovery_tmpl(struct ath12k *ar, u32 vdev_id, |
3111 | struct sk_buff *tmpl) |
3112 | { |
3113 | struct wmi_tlv *tlv; |
3114 | struct sk_buff *skb; |
3115 | void *ptr; |
3116 | int ret, len; |
3117 | size_t aligned_len; |
3118 | struct wmi_fils_discovery_tmpl_cmd *cmd; |
3119 | |
3120 | aligned_len = roundup(tmpl->len, 4); |
3121 | len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; |
3122 | |
3123 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3124 | "WMI vdev %i set FILS discovery template\n" , vdev_id); |
3125 | |
3126 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len); |
3127 | if (!skb) |
3128 | return -ENOMEM; |
3129 | |
3130 | cmd = (struct wmi_fils_discovery_tmpl_cmd *)skb->data; |
3131 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_FILS_DISCOVERY_TMPL_CMD, |
3132 | len: sizeof(*cmd)); |
3133 | cmd->vdev_id = cpu_to_le32(vdev_id); |
3134 | cmd->buf_len = cpu_to_le32(tmpl->len); |
3135 | ptr = skb->data + sizeof(*cmd); |
3136 | |
3137 | tlv = ptr; |
3138 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len: aligned_len); |
3139 | memcpy(tlv->value, tmpl->data, tmpl->len); |
3140 | |
3141 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, cmd_id: WMI_FILS_DISCOVERY_TMPL_CMDID); |
3142 | if (ret) { |
3143 | ath12k_warn(ab: ar->ab, |
3144 | fmt: "WMI vdev %i failed to send FILS discovery template command\n" , |
3145 | vdev_id); |
3146 | dev_kfree_skb(skb); |
3147 | } |
3148 | return ret; |
3149 | } |
3150 | |
3151 | int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id, |
3152 | struct sk_buff *tmpl) |
3153 | { |
3154 | struct wmi_probe_tmpl_cmd *cmd; |
3155 | struct ath12k_wmi_bcn_prb_info_params *probe_info; |
3156 | struct wmi_tlv *tlv; |
3157 | struct sk_buff *skb; |
3158 | void *ptr; |
3159 | int ret, len; |
3160 | size_t aligned_len = roundup(tmpl->len, 4); |
3161 | |
3162 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3163 | "WMI vdev %i set probe response template\n" , vdev_id); |
3164 | |
3165 | len = sizeof(*cmd) + sizeof(*probe_info) + TLV_HDR_SIZE + aligned_len; |
3166 | |
3167 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len); |
3168 | if (!skb) |
3169 | return -ENOMEM; |
3170 | |
3171 | cmd = (struct wmi_probe_tmpl_cmd *)skb->data; |
3172 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PRB_TMPL_CMD, |
3173 | len: sizeof(*cmd)); |
3174 | cmd->vdev_id = cpu_to_le32(vdev_id); |
3175 | cmd->buf_len = cpu_to_le32(tmpl->len); |
3176 | |
3177 | ptr = skb->data + sizeof(*cmd); |
3178 | |
3179 | probe_info = ptr; |
3180 | len = sizeof(*probe_info); |
3181 | probe_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_BCN_PRB_INFO, |
3182 | len); |
3183 | probe_info->caps = 0; |
3184 | probe_info->erp = 0; |
3185 | |
3186 | ptr += sizeof(*probe_info); |
3187 | |
3188 | tlv = ptr; |
3189 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_BYTE, len: aligned_len); |
3190 | memcpy(tlv->value, tmpl->data, tmpl->len); |
3191 | |
3192 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, cmd_id: WMI_PRB_TMPL_CMDID); |
3193 | if (ret) { |
3194 | ath12k_warn(ab: ar->ab, |
3195 | fmt: "WMI vdev %i failed to send probe response template command\n" , |
3196 | vdev_id); |
3197 | dev_kfree_skb(skb); |
3198 | } |
3199 | return ret; |
3200 | } |
3201 | |
3202 | int ath12k_wmi_fils_discovery(struct ath12k *ar, u32 vdev_id, u32 interval, |
3203 | bool unsol_bcast_probe_resp_enabled) |
3204 | { |
3205 | struct sk_buff *skb; |
3206 | int ret, len; |
3207 | struct wmi_fils_discovery_cmd *cmd; |
3208 | |
3209 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3210 | "WMI vdev %i set %s interval to %u TU\n" , |
3211 | vdev_id, unsol_bcast_probe_resp_enabled ? |
3212 | "unsolicited broadcast probe response" : "FILS discovery" , |
3213 | interval); |
3214 | |
3215 | len = sizeof(*cmd); |
3216 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len); |
3217 | if (!skb) |
3218 | return -ENOMEM; |
3219 | |
3220 | cmd = (struct wmi_fils_discovery_cmd *)skb->data; |
3221 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_ENABLE_FILS_CMD, |
3222 | len); |
3223 | cmd->vdev_id = cpu_to_le32(vdev_id); |
3224 | cmd->interval = cpu_to_le32(interval); |
3225 | cmd->config = cpu_to_le32(unsol_bcast_probe_resp_enabled); |
3226 | |
3227 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, cmd_id: WMI_ENABLE_FILS_CMDID); |
3228 | if (ret) { |
3229 | ath12k_warn(ab: ar->ab, |
3230 | fmt: "WMI vdev %i failed to send FILS discovery enable/disable command\n" , |
3231 | vdev_id); |
3232 | dev_kfree_skb(skb); |
3233 | } |
3234 | return ret; |
3235 | } |
3236 | |
3237 | static void |
3238 | ath12k_fill_band_to_mac_param(struct ath12k_base *soc, |
3239 | struct ath12k_wmi_pdev_band_arg *arg) |
3240 | { |
3241 | u8 i; |
3242 | struct ath12k_wmi_hal_reg_capabilities_ext_arg *hal_reg_cap; |
3243 | struct ath12k_pdev *pdev; |
3244 | |
3245 | for (i = 0; i < soc->num_radios; i++) { |
3246 | pdev = &soc->pdevs[i]; |
3247 | hal_reg_cap = &soc->hal_reg_cap[i]; |
3248 | arg[i].pdev_id = pdev->pdev_id; |
3249 | |
3250 | switch (pdev->cap.supported_bands) { |
3251 | case WMI_HOST_WLAN_2G_5G_CAP: |
3252 | arg[i].start_freq = hal_reg_cap->low_2ghz_chan; |
3253 | arg[i].end_freq = hal_reg_cap->high_5ghz_chan; |
3254 | break; |
3255 | case WMI_HOST_WLAN_2G_CAP: |
3256 | arg[i].start_freq = hal_reg_cap->low_2ghz_chan; |
3257 | arg[i].end_freq = hal_reg_cap->high_2ghz_chan; |
3258 | break; |
3259 | case WMI_HOST_WLAN_5G_CAP: |
3260 | arg[i].start_freq = hal_reg_cap->low_5ghz_chan; |
3261 | arg[i].end_freq = hal_reg_cap->high_5ghz_chan; |
3262 | break; |
3263 | default: |
3264 | break; |
3265 | } |
3266 | } |
3267 | } |
3268 | |
3269 | static void |
3270 | ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cfg, |
3271 | struct ath12k_wmi_resource_config_arg *tg_cfg) |
3272 | { |
3273 | wmi_cfg->num_vdevs = cpu_to_le32(tg_cfg->num_vdevs); |
3274 | wmi_cfg->num_peers = cpu_to_le32(tg_cfg->num_peers); |
3275 | wmi_cfg->num_offload_peers = cpu_to_le32(tg_cfg->num_offload_peers); |
3276 | wmi_cfg->num_offload_reorder_buffs = |
3277 | cpu_to_le32(tg_cfg->num_offload_reorder_buffs); |
3278 | wmi_cfg->num_peer_keys = cpu_to_le32(tg_cfg->num_peer_keys); |
3279 | wmi_cfg->num_tids = cpu_to_le32(tg_cfg->num_tids); |
3280 | wmi_cfg->ast_skid_limit = cpu_to_le32(tg_cfg->ast_skid_limit); |
3281 | wmi_cfg->tx_chain_mask = cpu_to_le32(tg_cfg->tx_chain_mask); |
3282 | wmi_cfg->rx_chain_mask = cpu_to_le32(tg_cfg->rx_chain_mask); |
3283 | wmi_cfg->rx_timeout_pri[0] = cpu_to_le32(tg_cfg->rx_timeout_pri[0]); |
3284 | wmi_cfg->rx_timeout_pri[1] = cpu_to_le32(tg_cfg->rx_timeout_pri[1]); |
3285 | wmi_cfg->rx_timeout_pri[2] = cpu_to_le32(tg_cfg->rx_timeout_pri[2]); |
3286 | wmi_cfg->rx_timeout_pri[3] = cpu_to_le32(tg_cfg->rx_timeout_pri[3]); |
3287 | wmi_cfg->rx_decap_mode = cpu_to_le32(tg_cfg->rx_decap_mode); |
3288 | wmi_cfg->scan_max_pending_req = cpu_to_le32(tg_cfg->scan_max_pending_req); |
3289 | wmi_cfg->bmiss_offload_max_vdev = cpu_to_le32(tg_cfg->bmiss_offload_max_vdev); |
3290 | wmi_cfg->roam_offload_max_vdev = cpu_to_le32(tg_cfg->roam_offload_max_vdev); |
3291 | wmi_cfg->roam_offload_max_ap_profiles = |
3292 | cpu_to_le32(tg_cfg->roam_offload_max_ap_profiles); |
3293 | wmi_cfg->num_mcast_groups = cpu_to_le32(tg_cfg->num_mcast_groups); |
3294 | wmi_cfg->num_mcast_table_elems = cpu_to_le32(tg_cfg->num_mcast_table_elems); |
3295 | wmi_cfg->mcast2ucast_mode = cpu_to_le32(tg_cfg->mcast2ucast_mode); |
3296 | wmi_cfg->tx_dbg_log_size = cpu_to_le32(tg_cfg->tx_dbg_log_size); |
3297 | wmi_cfg->num_wds_entries = cpu_to_le32(tg_cfg->num_wds_entries); |
3298 | wmi_cfg->dma_burst_size = cpu_to_le32(tg_cfg->dma_burst_size); |
3299 | wmi_cfg->mac_aggr_delim = cpu_to_le32(tg_cfg->mac_aggr_delim); |
3300 | wmi_cfg->rx_skip_defrag_timeout_dup_detection_check = |
3301 | cpu_to_le32(tg_cfg->rx_skip_defrag_timeout_dup_detection_check); |
3302 | wmi_cfg->vow_config = cpu_to_le32(tg_cfg->vow_config); |
3303 | wmi_cfg->gtk_offload_max_vdev = cpu_to_le32(tg_cfg->gtk_offload_max_vdev); |
3304 | wmi_cfg->num_msdu_desc = cpu_to_le32(tg_cfg->num_msdu_desc); |
3305 | wmi_cfg->max_frag_entries = cpu_to_le32(tg_cfg->max_frag_entries); |
3306 | wmi_cfg->num_tdls_vdevs = cpu_to_le32(tg_cfg->num_tdls_vdevs); |
3307 | wmi_cfg->num_tdls_conn_table_entries = |
3308 | cpu_to_le32(tg_cfg->num_tdls_conn_table_entries); |
3309 | wmi_cfg->beacon_tx_offload_max_vdev = |
3310 | cpu_to_le32(tg_cfg->beacon_tx_offload_max_vdev); |
3311 | wmi_cfg->num_multicast_filter_entries = |
3312 | cpu_to_le32(tg_cfg->num_multicast_filter_entries); |
3313 | wmi_cfg->num_wow_filters = cpu_to_le32(tg_cfg->num_wow_filters); |
3314 | wmi_cfg->num_keep_alive_pattern = cpu_to_le32(tg_cfg->num_keep_alive_pattern); |
3315 | wmi_cfg->keep_alive_pattern_size = cpu_to_le32(tg_cfg->keep_alive_pattern_size); |
3316 | wmi_cfg->max_tdls_concurrent_sleep_sta = |
3317 | cpu_to_le32(tg_cfg->max_tdls_concurrent_sleep_sta); |
3318 | wmi_cfg->max_tdls_concurrent_buffer_sta = |
3319 | cpu_to_le32(tg_cfg->max_tdls_concurrent_buffer_sta); |
3320 | wmi_cfg->wmi_send_separate = cpu_to_le32(tg_cfg->wmi_send_separate); |
3321 | wmi_cfg->num_ocb_vdevs = cpu_to_le32(tg_cfg->num_ocb_vdevs); |
3322 | wmi_cfg->num_ocb_channels = cpu_to_le32(tg_cfg->num_ocb_channels); |
3323 | wmi_cfg->num_ocb_schedules = cpu_to_le32(tg_cfg->num_ocb_schedules); |
3324 | wmi_cfg->bpf_instruction_size = cpu_to_le32(tg_cfg->bpf_instruction_size); |
3325 | wmi_cfg->max_bssid_rx_filters = cpu_to_le32(tg_cfg->max_bssid_rx_filters); |
3326 | wmi_cfg->use_pdev_id = cpu_to_le32(tg_cfg->use_pdev_id); |
3327 | wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config); |
3328 | wmi_cfg->peer_map_unmap_version = cpu_to_le32(tg_cfg->peer_map_unmap_version); |
3329 | wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); |
3330 | wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); |
3331 | wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); |
3332 | wmi_cfg->flags2 = le32_encode_bits(v: tg_cfg->dp_peer_meta_data_ver, |
3333 | WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); |
3334 | |
3335 | wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << |
3336 | WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); |
3337 | } |
3338 | |
3339 | static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi, |
3340 | struct ath12k_wmi_init_cmd_arg *arg) |
3341 | { |
3342 | struct ath12k_base *ab = wmi->wmi_ab->ab; |
3343 | struct sk_buff *skb; |
3344 | struct wmi_init_cmd *cmd; |
3345 | struct ath12k_wmi_resource_config_params *cfg; |
3346 | struct ath12k_wmi_pdev_set_hw_mode_cmd *hw_mode; |
3347 | struct ath12k_wmi_pdev_band_to_mac_params *band_to_mac; |
3348 | struct ath12k_wmi_host_mem_chunk_params *host_mem_chunks; |
3349 | struct wmi_tlv *tlv; |
3350 | size_t ret, len; |
3351 | void *ptr; |
3352 | u32 hw_mode_len = 0; |
3353 | u16 idx; |
3354 | |
3355 | if (arg->hw_mode_id != WMI_HOST_HW_MODE_MAX) |
3356 | hw_mode_len = sizeof(*hw_mode) + TLV_HDR_SIZE + |
3357 | (arg->num_band_to_mac * sizeof(*band_to_mac)); |
3358 | |
3359 | len = sizeof(*cmd) + TLV_HDR_SIZE + sizeof(*cfg) + hw_mode_len + |
3360 | (arg->num_mem_chunks ? (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS) : 0); |
3361 | |
3362 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len); |
3363 | if (!skb) |
3364 | return -ENOMEM; |
3365 | |
3366 | cmd = (struct wmi_init_cmd *)skb->data; |
3367 | |
3368 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_INIT_CMD, |
3369 | len: sizeof(*cmd)); |
3370 | |
3371 | ptr = skb->data + sizeof(*cmd); |
3372 | cfg = ptr; |
3373 | |
3374 | ath12k_wmi_copy_resource_config(wmi_cfg: cfg, tg_cfg: &arg->res_cfg); |
3375 | |
3376 | cfg->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_RESOURCE_CONFIG, |
3377 | len: sizeof(*cfg)); |
3378 | |
3379 | ptr += sizeof(*cfg); |
3380 | host_mem_chunks = ptr + TLV_HDR_SIZE; |
3381 | len = sizeof(struct ath12k_wmi_host_mem_chunk_params); |
3382 | |
3383 | for (idx = 0; idx < arg->num_mem_chunks; ++idx) { |
3384 | host_mem_chunks[idx].tlv_header = |
3385 | ath12k_wmi_tlv_hdr(cmd: WMI_TAG_WLAN_HOST_MEMORY_CHUNK, |
3386 | len); |
3387 | |
3388 | host_mem_chunks[idx].ptr = cpu_to_le32(arg->mem_chunks[idx].paddr); |
3389 | host_mem_chunks[idx].size = cpu_to_le32(arg->mem_chunks[idx].len); |
3390 | host_mem_chunks[idx].req_id = cpu_to_le32(arg->mem_chunks[idx].req_id); |
3391 | |
3392 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
3393 | "WMI host mem chunk req_id %d paddr 0x%llx len %d\n" , |
3394 | arg->mem_chunks[idx].req_id, |
3395 | (u64)arg->mem_chunks[idx].paddr, |
3396 | arg->mem_chunks[idx].len); |
3397 | } |
3398 | cmd->num_host_mem_chunks = cpu_to_le32(arg->num_mem_chunks); |
3399 | len = sizeof(struct ath12k_wmi_host_mem_chunk_params) * arg->num_mem_chunks; |
3400 | |
3401 | /* num_mem_chunks is zero */ |
3402 | tlv = ptr; |
3403 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len); |
3404 | ptr += TLV_HDR_SIZE + len; |
3405 | |
3406 | if (arg->hw_mode_id != WMI_HOST_HW_MODE_MAX) { |
3407 | hw_mode = (struct ath12k_wmi_pdev_set_hw_mode_cmd *)ptr; |
3408 | hw_mode->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_SET_HW_MODE_CMD, |
3409 | len: sizeof(*hw_mode)); |
3410 | |
3411 | hw_mode->hw_mode_index = cpu_to_le32(arg->hw_mode_id); |
3412 | hw_mode->num_band_to_mac = cpu_to_le32(arg->num_band_to_mac); |
3413 | |
3414 | ptr += sizeof(*hw_mode); |
3415 | |
3416 | len = arg->num_band_to_mac * sizeof(*band_to_mac); |
3417 | tlv = ptr; |
3418 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_STRUCT, len); |
3419 | |
3420 | ptr += TLV_HDR_SIZE; |
3421 | len = sizeof(*band_to_mac); |
3422 | |
3423 | for (idx = 0; idx < arg->num_band_to_mac; idx++) { |
3424 | band_to_mac = (void *)ptr; |
3425 | |
3426 | band_to_mac->tlv_header = |
3427 | ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_BAND_TO_MAC, |
3428 | len); |
3429 | band_to_mac->pdev_id = cpu_to_le32(arg->band_to_mac[idx].pdev_id); |
3430 | band_to_mac->start_freq = |
3431 | cpu_to_le32(arg->band_to_mac[idx].start_freq); |
3432 | band_to_mac->end_freq = |
3433 | cpu_to_le32(arg->band_to_mac[idx].end_freq); |
3434 | ptr += sizeof(*band_to_mac); |
3435 | } |
3436 | } |
3437 | |
3438 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_INIT_CMDID); |
3439 | if (ret) { |
3440 | ath12k_warn(ab, fmt: "failed to send WMI_INIT_CMDID\n" ); |
3441 | dev_kfree_skb(skb); |
3442 | } |
3443 | |
3444 | return ret; |
3445 | } |
3446 | |
3447 | int ath12k_wmi_pdev_lro_cfg(struct ath12k *ar, |
3448 | int pdev_id) |
3449 | { |
3450 | struct ath12k_wmi_pdev_lro_config_cmd *cmd; |
3451 | struct sk_buff *skb; |
3452 | int ret; |
3453 | |
3454 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len: sizeof(*cmd)); |
3455 | if (!skb) |
3456 | return -ENOMEM; |
3457 | |
3458 | cmd = (struct ath12k_wmi_pdev_lro_config_cmd *)skb->data; |
3459 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_LRO_INFO_CMD, |
3460 | len: sizeof(*cmd)); |
3461 | |
3462 | get_random_bytes(buf: cmd->th_4, len: sizeof(cmd->th_4)); |
3463 | get_random_bytes(buf: cmd->th_6, len: sizeof(cmd->th_6)); |
3464 | |
3465 | cmd->pdev_id = cpu_to_le32(pdev_id); |
3466 | |
3467 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3468 | "WMI lro cfg cmd pdev_id 0x%x\n" , pdev_id); |
3469 | |
3470 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, cmd_id: WMI_LRO_CONFIG_CMDID); |
3471 | if (ret) { |
3472 | ath12k_warn(ab: ar->ab, |
3473 | fmt: "failed to send lro cfg req wmi cmd\n" ); |
3474 | goto err; |
3475 | } |
3476 | |
3477 | return 0; |
3478 | err: |
3479 | dev_kfree_skb(skb); |
3480 | return ret; |
3481 | } |
3482 | |
3483 | int ath12k_wmi_wait_for_service_ready(struct ath12k_base *ab) |
3484 | { |
3485 | unsigned long time_left; |
3486 | |
3487 | time_left = wait_for_completion_timeout(x: &ab->wmi_ab.service_ready, |
3488 | WMI_SERVICE_READY_TIMEOUT_HZ); |
3489 | if (!time_left) |
3490 | return -ETIMEDOUT; |
3491 | |
3492 | return 0; |
3493 | } |
3494 | |
3495 | int ath12k_wmi_wait_for_unified_ready(struct ath12k_base *ab) |
3496 | { |
3497 | unsigned long time_left; |
3498 | |
3499 | time_left = wait_for_completion_timeout(x: &ab->wmi_ab.unified_ready, |
3500 | WMI_SERVICE_READY_TIMEOUT_HZ); |
3501 | if (!time_left) |
3502 | return -ETIMEDOUT; |
3503 | |
3504 | return 0; |
3505 | } |
3506 | |
3507 | int ath12k_wmi_set_hw_mode(struct ath12k_base *ab, |
3508 | enum wmi_host_hw_mode_config_type mode) |
3509 | { |
3510 | struct ath12k_wmi_pdev_set_hw_mode_cmd *cmd; |
3511 | struct sk_buff *skb; |
3512 | struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab; |
3513 | int len; |
3514 | int ret; |
3515 | |
3516 | len = sizeof(*cmd); |
3517 | |
3518 | skb = ath12k_wmi_alloc_skb(wmi_ab, len); |
3519 | if (!skb) |
3520 | return -ENOMEM; |
3521 | |
3522 | cmd = (struct ath12k_wmi_pdev_set_hw_mode_cmd *)skb->data; |
3523 | |
3524 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_PDEV_SET_HW_MODE_CMD, |
3525 | len: sizeof(*cmd)); |
3526 | |
3527 | cmd->pdev_id = WMI_PDEV_ID_SOC; |
3528 | cmd->hw_mode_index = cpu_to_le32(mode); |
3529 | |
3530 | ret = ath12k_wmi_cmd_send(wmi: &wmi_ab->wmi[0], skb, cmd_id: WMI_PDEV_SET_HW_MODE_CMDID); |
3531 | if (ret) { |
3532 | ath12k_warn(ab, fmt: "failed to send WMI_PDEV_SET_HW_MODE_CMDID\n" ); |
3533 | dev_kfree_skb(skb); |
3534 | } |
3535 | |
3536 | return ret; |
3537 | } |
3538 | |
3539 | int ath12k_wmi_cmd_init(struct ath12k_base *ab) |
3540 | { |
3541 | struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab; |
3542 | struct ath12k_wmi_init_cmd_arg arg = {}; |
3543 | |
3544 | if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT, |
3545 | ab->wmi_ab.svc_map)) |
3546 | arg.res_cfg.is_reg_cc_ext_event_supported = true; |
3547 | |
3548 | ab->hw_params->wmi_init(ab, &arg.res_cfg); |
3549 | |
3550 | arg.num_mem_chunks = wmi_ab->num_mem_chunks; |
3551 | arg.hw_mode_id = wmi_ab->preferred_hw_mode; |
3552 | arg.mem_chunks = wmi_ab->mem_chunks; |
3553 | |
3554 | if (ab->hw_params->single_pdev_only) |
3555 | arg.hw_mode_id = WMI_HOST_HW_MODE_MAX; |
3556 | |
3557 | arg.num_band_to_mac = ab->num_radios; |
3558 | ath12k_fill_band_to_mac_param(soc: ab, arg: arg.band_to_mac); |
3559 | |
3560 | return ath12k_init_cmd_send(wmi: &wmi_ab->wmi[0], arg: &arg); |
3561 | } |
3562 | |
3563 | int ath12k_wmi_vdev_spectral_conf(struct ath12k *ar, |
3564 | struct ath12k_wmi_vdev_spectral_conf_arg *arg) |
3565 | { |
3566 | struct ath12k_wmi_vdev_spectral_conf_cmd *cmd; |
3567 | struct sk_buff *skb; |
3568 | int ret; |
3569 | |
3570 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len: sizeof(*cmd)); |
3571 | if (!skb) |
3572 | return -ENOMEM; |
3573 | |
3574 | cmd = (struct ath12k_wmi_vdev_spectral_conf_cmd *)skb->data; |
3575 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_SPECTRAL_CONFIGURE_CMD, |
3576 | len: sizeof(*cmd)); |
3577 | cmd->vdev_id = cpu_to_le32(arg->vdev_id); |
3578 | cmd->scan_count = cpu_to_le32(arg->scan_count); |
3579 | cmd->scan_period = cpu_to_le32(arg->scan_period); |
3580 | cmd->scan_priority = cpu_to_le32(arg->scan_priority); |
3581 | cmd->scan_fft_size = cpu_to_le32(arg->scan_fft_size); |
3582 | cmd->scan_gc_ena = cpu_to_le32(arg->scan_gc_ena); |
3583 | cmd->scan_restart_ena = cpu_to_le32(arg->scan_restart_ena); |
3584 | cmd->scan_noise_floor_ref = cpu_to_le32(arg->scan_noise_floor_ref); |
3585 | cmd->scan_init_delay = cpu_to_le32(arg->scan_init_delay); |
3586 | cmd->scan_nb_tone_thr = cpu_to_le32(arg->scan_nb_tone_thr); |
3587 | cmd->scan_str_bin_thr = cpu_to_le32(arg->scan_str_bin_thr); |
3588 | cmd->scan_wb_rpt_mode = cpu_to_le32(arg->scan_wb_rpt_mode); |
3589 | cmd->scan_rssi_rpt_mode = cpu_to_le32(arg->scan_rssi_rpt_mode); |
3590 | cmd->scan_rssi_thr = cpu_to_le32(arg->scan_rssi_thr); |
3591 | cmd->scan_pwr_format = cpu_to_le32(arg->scan_pwr_format); |
3592 | cmd->scan_rpt_mode = cpu_to_le32(arg->scan_rpt_mode); |
3593 | cmd->scan_bin_scale = cpu_to_le32(arg->scan_bin_scale); |
3594 | cmd->scan_dbm_adj = cpu_to_le32(arg->scan_dbm_adj); |
3595 | cmd->scan_chn_mask = cpu_to_le32(arg->scan_chn_mask); |
3596 | |
3597 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3598 | "WMI spectral scan config cmd vdev_id 0x%x\n" , |
3599 | arg->vdev_id); |
3600 | |
3601 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, |
3602 | cmd_id: WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID); |
3603 | if (ret) { |
3604 | ath12k_warn(ab: ar->ab, |
3605 | fmt: "failed to send spectral scan config wmi cmd\n" ); |
3606 | goto err; |
3607 | } |
3608 | |
3609 | return 0; |
3610 | err: |
3611 | dev_kfree_skb(skb); |
3612 | return ret; |
3613 | } |
3614 | |
3615 | int ath12k_wmi_vdev_spectral_enable(struct ath12k *ar, u32 vdev_id, |
3616 | u32 trigger, u32 enable) |
3617 | { |
3618 | struct ath12k_wmi_vdev_spectral_enable_cmd *cmd; |
3619 | struct sk_buff *skb; |
3620 | int ret; |
3621 | |
3622 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len: sizeof(*cmd)); |
3623 | if (!skb) |
3624 | return -ENOMEM; |
3625 | |
3626 | cmd = (struct ath12k_wmi_vdev_spectral_enable_cmd *)skb->data; |
3627 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_VDEV_SPECTRAL_ENABLE_CMD, |
3628 | len: sizeof(*cmd)); |
3629 | |
3630 | cmd->vdev_id = cpu_to_le32(vdev_id); |
3631 | cmd->trigger_cmd = cpu_to_le32(trigger); |
3632 | cmd->enable_cmd = cpu_to_le32(enable); |
3633 | |
3634 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3635 | "WMI spectral enable cmd vdev id 0x%x\n" , |
3636 | vdev_id); |
3637 | |
3638 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, |
3639 | cmd_id: WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID); |
3640 | if (ret) { |
3641 | ath12k_warn(ab: ar->ab, |
3642 | fmt: "failed to send spectral enable wmi cmd\n" ); |
3643 | goto err; |
3644 | } |
3645 | |
3646 | return 0; |
3647 | err: |
3648 | dev_kfree_skb(skb); |
3649 | return ret; |
3650 | } |
3651 | |
3652 | int ath12k_wmi_pdev_dma_ring_cfg(struct ath12k *ar, |
3653 | struct ath12k_wmi_pdev_dma_ring_cfg_arg *arg) |
3654 | { |
3655 | struct ath12k_wmi_pdev_dma_ring_cfg_req_cmd *cmd; |
3656 | struct sk_buff *skb; |
3657 | int ret; |
3658 | |
3659 | skb = ath12k_wmi_alloc_skb(wmi_ab: ar->wmi->wmi_ab, len: sizeof(*cmd)); |
3660 | if (!skb) |
3661 | return -ENOMEM; |
3662 | |
3663 | cmd = (struct ath12k_wmi_pdev_dma_ring_cfg_req_cmd *)skb->data; |
3664 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_DMA_RING_CFG_REQ, |
3665 | len: sizeof(*cmd)); |
3666 | |
3667 | cmd->pdev_id = cpu_to_le32(DP_SW2HW_MACID(arg->pdev_id)); |
3668 | cmd->module_id = cpu_to_le32(arg->module_id); |
3669 | cmd->base_paddr_lo = cpu_to_le32(arg->base_paddr_lo); |
3670 | cmd->base_paddr_hi = cpu_to_le32(arg->base_paddr_hi); |
3671 | cmd->head_idx_paddr_lo = cpu_to_le32(arg->head_idx_paddr_lo); |
3672 | cmd->head_idx_paddr_hi = cpu_to_le32(arg->head_idx_paddr_hi); |
3673 | cmd->tail_idx_paddr_lo = cpu_to_le32(arg->tail_idx_paddr_lo); |
3674 | cmd->tail_idx_paddr_hi = cpu_to_le32(arg->tail_idx_paddr_hi); |
3675 | cmd->num_elems = cpu_to_le32(arg->num_elems); |
3676 | cmd->buf_size = cpu_to_le32(arg->buf_size); |
3677 | cmd->num_resp_per_event = cpu_to_le32(arg->num_resp_per_event); |
3678 | cmd->event_timeout_ms = cpu_to_le32(arg->event_timeout_ms); |
3679 | |
3680 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
3681 | "WMI DMA ring cfg req cmd pdev_id 0x%x\n" , |
3682 | arg->pdev_id); |
3683 | |
3684 | ret = ath12k_wmi_cmd_send(wmi: ar->wmi, skb, |
3685 | cmd_id: WMI_PDEV_DMA_RING_CFG_REQ_CMDID); |
3686 | if (ret) { |
3687 | ath12k_warn(ab: ar->ab, |
3688 | fmt: "failed to send dma ring cfg req wmi cmd\n" ); |
3689 | goto err; |
3690 | } |
3691 | |
3692 | return 0; |
3693 | err: |
3694 | dev_kfree_skb(skb); |
3695 | return ret; |
3696 | } |
3697 | |
3698 | static int ath12k_wmi_dma_buf_entry_parse(struct ath12k_base *soc, |
3699 | u16 tag, u16 len, |
3700 | const void *ptr, void *data) |
3701 | { |
3702 | struct ath12k_wmi_dma_buf_release_arg *arg = data; |
3703 | |
3704 | if (tag != WMI_TAG_DMA_BUF_RELEASE_ENTRY) |
3705 | return -EPROTO; |
3706 | |
3707 | if (arg->num_buf_entry >= le32_to_cpu(arg->fixed.num_buf_release_entry)) |
3708 | return -ENOBUFS; |
3709 | |
3710 | arg->num_buf_entry++; |
3711 | return 0; |
3712 | } |
3713 | |
3714 | static int ath12k_wmi_dma_buf_meta_parse(struct ath12k_base *soc, |
3715 | u16 tag, u16 len, |
3716 | const void *ptr, void *data) |
3717 | { |
3718 | struct ath12k_wmi_dma_buf_release_arg *arg = data; |
3719 | |
3720 | if (tag != WMI_TAG_DMA_BUF_RELEASE_SPECTRAL_META_DATA) |
3721 | return -EPROTO; |
3722 | |
3723 | if (arg->num_meta >= le32_to_cpu(arg->fixed.num_meta_data_entry)) |
3724 | return -ENOBUFS; |
3725 | |
3726 | arg->num_meta++; |
3727 | |
3728 | return 0; |
3729 | } |
3730 | |
3731 | static int ath12k_wmi_dma_buf_parse(struct ath12k_base *ab, |
3732 | u16 tag, u16 len, |
3733 | const void *ptr, void *data) |
3734 | { |
3735 | struct ath12k_wmi_dma_buf_release_arg *arg = data; |
3736 | const struct ath12k_wmi_dma_buf_release_fixed_params *fixed; |
3737 | u32 pdev_id; |
3738 | int ret; |
3739 | |
3740 | switch (tag) { |
3741 | case WMI_TAG_DMA_BUF_RELEASE: |
3742 | fixed = ptr; |
3743 | arg->fixed = *fixed; |
3744 | pdev_id = DP_HW2SW_MACID(le32_to_cpu(fixed->pdev_id)); |
3745 | arg->fixed.pdev_id = cpu_to_le32(pdev_id); |
3746 | break; |
3747 | case WMI_TAG_ARRAY_STRUCT: |
3748 | if (!arg->buf_entry_done) { |
3749 | arg->num_buf_entry = 0; |
3750 | arg->buf_entry = ptr; |
3751 | |
3752 | ret = ath12k_wmi_tlv_iter(ab, ptr, len, |
3753 | iter: ath12k_wmi_dma_buf_entry_parse, |
3754 | data: arg); |
3755 | if (ret) { |
3756 | ath12k_warn(ab, fmt: "failed to parse dma buf entry tlv %d\n" , |
3757 | ret); |
3758 | return ret; |
3759 | } |
3760 | |
3761 | arg->buf_entry_done = true; |
3762 | } else if (!arg->meta_data_done) { |
3763 | arg->num_meta = 0; |
3764 | arg->meta_data = ptr; |
3765 | |
3766 | ret = ath12k_wmi_tlv_iter(ab, ptr, len, |
3767 | iter: ath12k_wmi_dma_buf_meta_parse, |
3768 | data: arg); |
3769 | if (ret) { |
3770 | ath12k_warn(ab, fmt: "failed to parse dma buf meta tlv %d\n" , |
3771 | ret); |
3772 | return ret; |
3773 | } |
3774 | |
3775 | arg->meta_data_done = true; |
3776 | } |
3777 | break; |
3778 | default: |
3779 | break; |
3780 | } |
3781 | return 0; |
3782 | } |
3783 | |
3784 | static void ath12k_wmi_pdev_dma_ring_buf_release_event(struct ath12k_base *ab, |
3785 | struct sk_buff *skb) |
3786 | { |
3787 | struct ath12k_wmi_dma_buf_release_arg arg = {}; |
3788 | struct ath12k_dbring_buf_release_event param; |
3789 | int ret; |
3790 | |
3791 | ret = ath12k_wmi_tlv_iter(ab, ptr: skb->data, len: skb->len, |
3792 | iter: ath12k_wmi_dma_buf_parse, |
3793 | data: &arg); |
3794 | if (ret) { |
3795 | ath12k_warn(ab, fmt: "failed to parse dma buf release tlv %d\n" , ret); |
3796 | return; |
3797 | } |
3798 | |
3799 | param.fixed = arg.fixed; |
3800 | param.buf_entry = arg.buf_entry; |
3801 | param.num_buf_entry = arg.num_buf_entry; |
3802 | param.meta_data = arg.meta_data; |
3803 | param.num_meta = arg.num_meta; |
3804 | |
3805 | ret = ath12k_dbring_buffer_release_event(ab, ev: ¶m); |
3806 | if (ret) { |
3807 | ath12k_warn(ab, fmt: "failed to handle dma buf release event %d\n" , ret); |
3808 | return; |
3809 | } |
3810 | } |
3811 | |
3812 | static int ath12k_wmi_hw_mode_caps_parse(struct ath12k_base *soc, |
3813 | u16 tag, u16 len, |
3814 | const void *ptr, void *data) |
3815 | { |
3816 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
3817 | struct ath12k_wmi_hw_mode_cap_params *hw_mode_cap; |
3818 | u32 phy_map = 0; |
3819 | |
3820 | if (tag != WMI_TAG_HW_MODE_CAPABILITIES) |
3821 | return -EPROTO; |
3822 | |
3823 | if (svc_rdy_ext->n_hw_mode_caps >= svc_rdy_ext->arg.num_hw_modes) |
3824 | return -ENOBUFS; |
3825 | |
3826 | hw_mode_cap = container_of(ptr, struct ath12k_wmi_hw_mode_cap_params, |
3827 | hw_mode_id); |
3828 | svc_rdy_ext->n_hw_mode_caps++; |
3829 | |
3830 | phy_map = le32_to_cpu(hw_mode_cap->phy_id_map); |
3831 | svc_rdy_ext->tot_phy_id += fls(x: phy_map); |
3832 | |
3833 | return 0; |
3834 | } |
3835 | |
3836 | static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc, |
3837 | u16 len, const void *ptr, void *data) |
3838 | { |
3839 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
3840 | const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps; |
3841 | enum wmi_host_hw_mode_config_type mode, pref; |
3842 | u32 i; |
3843 | int ret; |
3844 | |
3845 | svc_rdy_ext->n_hw_mode_caps = 0; |
3846 | svc_rdy_ext->hw_mode_caps = ptr; |
3847 | |
3848 | ret = ath12k_wmi_tlv_iter(ab: soc, ptr, len, |
3849 | iter: ath12k_wmi_hw_mode_caps_parse, |
3850 | data: svc_rdy_ext); |
3851 | if (ret) { |
3852 | ath12k_warn(ab: soc, fmt: "failed to parse tlv %d\n" , ret); |
3853 | return ret; |
3854 | } |
3855 | |
3856 | for (i = 0 ; i < svc_rdy_ext->n_hw_mode_caps; i++) { |
3857 | hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i]; |
3858 | mode = le32_to_cpu(hw_mode_caps->hw_mode_id); |
3859 | |
3860 | if (mode >= WMI_HOST_HW_MODE_MAX) |
3861 | continue; |
3862 | |
3863 | pref = soc->wmi_ab.preferred_hw_mode; |
3864 | |
3865 | if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) { |
3866 | svc_rdy_ext->pref_hw_mode_caps = *hw_mode_caps; |
3867 | soc->wmi_ab.preferred_hw_mode = mode; |
3868 | } |
3869 | } |
3870 | |
3871 | ath12k_dbg(soc, ATH12K_DBG_WMI, "preferred_hw_mode:%d\n" , |
3872 | soc->wmi_ab.preferred_hw_mode); |
3873 | if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) |
3874 | return -EINVAL; |
3875 | |
3876 | return 0; |
3877 | } |
3878 | |
3879 | static int ath12k_wmi_mac_phy_caps_parse(struct ath12k_base *soc, |
3880 | u16 tag, u16 len, |
3881 | const void *ptr, void *data) |
3882 | { |
3883 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
3884 | |
3885 | if (tag != WMI_TAG_MAC_PHY_CAPABILITIES) |
3886 | return -EPROTO; |
3887 | |
3888 | if (svc_rdy_ext->n_mac_phy_caps >= svc_rdy_ext->tot_phy_id) |
3889 | return -ENOBUFS; |
3890 | |
3891 | len = min_t(u16, len, sizeof(struct ath12k_wmi_mac_phy_caps_params)); |
3892 | if (!svc_rdy_ext->n_mac_phy_caps) { |
3893 | svc_rdy_ext->mac_phy_caps = kzalloc(size: (svc_rdy_ext->tot_phy_id) * len, |
3894 | GFP_ATOMIC); |
3895 | if (!svc_rdy_ext->mac_phy_caps) |
3896 | return -ENOMEM; |
3897 | } |
3898 | |
3899 | memcpy(svc_rdy_ext->mac_phy_caps + svc_rdy_ext->n_mac_phy_caps, ptr, len); |
3900 | svc_rdy_ext->n_mac_phy_caps++; |
3901 | return 0; |
3902 | } |
3903 | |
3904 | static int ath12k_wmi_ext_hal_reg_caps_parse(struct ath12k_base *soc, |
3905 | u16 tag, u16 len, |
3906 | const void *ptr, void *data) |
3907 | { |
3908 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
3909 | |
3910 | if (tag != WMI_TAG_HAL_REG_CAPABILITIES_EXT) |
3911 | return -EPROTO; |
3912 | |
3913 | if (svc_rdy_ext->n_ext_hal_reg_caps >= svc_rdy_ext->arg.num_phy) |
3914 | return -ENOBUFS; |
3915 | |
3916 | svc_rdy_ext->n_ext_hal_reg_caps++; |
3917 | return 0; |
3918 | } |
3919 | |
3920 | static int ath12k_wmi_ext_hal_reg_caps(struct ath12k_base *soc, |
3921 | u16 len, const void *ptr, void *data) |
3922 | { |
3923 | struct ath12k_wmi_pdev *wmi_handle = &soc->wmi_ab.wmi[0]; |
3924 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
3925 | struct ath12k_wmi_hal_reg_capabilities_ext_arg reg_cap; |
3926 | int ret; |
3927 | u32 i; |
3928 | |
3929 | svc_rdy_ext->n_ext_hal_reg_caps = 0; |
3930 | svc_rdy_ext->ext_hal_reg_caps = ptr; |
3931 | ret = ath12k_wmi_tlv_iter(ab: soc, ptr, len, |
3932 | iter: ath12k_wmi_ext_hal_reg_caps_parse, |
3933 | data: svc_rdy_ext); |
3934 | if (ret) { |
3935 | ath12k_warn(ab: soc, fmt: "failed to parse tlv %d\n" , ret); |
3936 | return ret; |
3937 | } |
3938 | |
3939 | for (i = 0; i < svc_rdy_ext->arg.num_phy; i++) { |
3940 | ret = ath12k_pull_reg_cap_svc_rdy_ext(wmi_handle, |
3941 | reg_caps: svc_rdy_ext->soc_hal_reg_caps, |
3942 | ext_caps: svc_rdy_ext->ext_hal_reg_caps, phy_idx: i, |
3943 | param: ®_cap); |
3944 | if (ret) { |
3945 | ath12k_warn(ab: soc, fmt: "failed to extract reg cap %d\n" , i); |
3946 | return ret; |
3947 | } |
3948 | |
3949 | if (reg_cap.phy_id >= MAX_RADIOS) { |
3950 | ath12k_warn(ab: soc, fmt: "unexpected phy id %u\n" , reg_cap.phy_id); |
3951 | return -EINVAL; |
3952 | } |
3953 | |
3954 | soc->hal_reg_cap[reg_cap.phy_id] = reg_cap; |
3955 | } |
3956 | return 0; |
3957 | } |
3958 | |
3959 | static int ath12k_wmi_ext_soc_hal_reg_caps_parse(struct ath12k_base *soc, |
3960 | u16 len, const void *ptr, |
3961 | void *data) |
3962 | { |
3963 | struct ath12k_wmi_pdev *wmi_handle = &soc->wmi_ab.wmi[0]; |
3964 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
3965 | u8 hw_mode_id = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.hw_mode_id); |
3966 | u32 phy_id_map; |
3967 | int pdev_index = 0; |
3968 | int ret; |
3969 | |
3970 | svc_rdy_ext->soc_hal_reg_caps = ptr; |
3971 | svc_rdy_ext->arg.num_phy = le32_to_cpu(svc_rdy_ext->soc_hal_reg_caps->num_phy); |
3972 | |
3973 | soc->num_radios = 0; |
3974 | phy_id_map = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.phy_id_map); |
3975 | soc->fw_pdev_count = 0; |
3976 | |
3977 | while (phy_id_map && soc->num_radios < MAX_RADIOS) { |
3978 | ret = ath12k_pull_mac_phy_cap_svc_ready_ext(wmi_handle, |
3979 | svc: svc_rdy_ext, |
3980 | hw_mode_id, phy_id: soc->num_radios, |
3981 | pdev: &soc->pdevs[pdev_index]); |
3982 | if (ret) { |
3983 | ath12k_warn(ab: soc, fmt: "failed to extract mac caps, idx :%d\n" , |
3984 | soc->num_radios); |
3985 | return ret; |
3986 | } |
3987 | |
3988 | soc->num_radios++; |
3989 | |
3990 | /* For single_pdev_only targets, |
3991 | * save mac_phy capability in the same pdev |
3992 | */ |
3993 | if (soc->hw_params->single_pdev_only) |
3994 | pdev_index = 0; |
3995 | else |
3996 | pdev_index = soc->num_radios; |
3997 | |
3998 | /* TODO: mac_phy_cap prints */ |
3999 | phy_id_map >>= 1; |
4000 | } |
4001 | |
4002 | if (soc->hw_params->single_pdev_only) { |
4003 | soc->num_radios = 1; |
4004 | soc->pdevs[0].pdev_id = 0; |
4005 | } |
4006 | |
4007 | return 0; |
4008 | } |
4009 | |
4010 | static int ath12k_wmi_dma_ring_caps_parse(struct ath12k_base *soc, |
4011 | u16 tag, u16 len, |
4012 | const void *ptr, void *data) |
4013 | { |
4014 | struct ath12k_wmi_dma_ring_caps_parse *parse = data; |
4015 | |
4016 | if (tag != WMI_TAG_DMA_RING_CAPABILITIES) |
4017 | return -EPROTO; |
4018 | |
4019 | parse->n_dma_ring_caps++; |
4020 | return 0; |
4021 | } |
4022 | |
4023 | static int ath12k_wmi_alloc_dbring_caps(struct ath12k_base *ab, |
4024 | u32 num_cap) |
4025 | { |
4026 | size_t sz; |
4027 | void *ptr; |
4028 | |
4029 | sz = num_cap * sizeof(struct ath12k_dbring_cap); |
4030 | ptr = kzalloc(size: sz, GFP_ATOMIC); |
4031 | if (!ptr) |
4032 | return -ENOMEM; |
4033 | |
4034 | ab->db_caps = ptr; |
4035 | ab->num_db_cap = num_cap; |
4036 | |
4037 | return 0; |
4038 | } |
4039 | |
4040 | static void ath12k_wmi_free_dbring_caps(struct ath12k_base *ab) |
4041 | { |
4042 | kfree(objp: ab->db_caps); |
4043 | ab->db_caps = NULL; |
4044 | } |
4045 | |
4046 | static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab, |
4047 | u16 len, const void *ptr, void *data) |
4048 | { |
4049 | struct ath12k_wmi_dma_ring_caps_parse *dma_caps_parse = data; |
4050 | struct ath12k_wmi_dma_ring_caps_params *dma_caps; |
4051 | struct ath12k_dbring_cap *dir_buff_caps; |
4052 | int ret; |
4053 | u32 i; |
4054 | |
4055 | dma_caps_parse->n_dma_ring_caps = 0; |
4056 | dma_caps = (struct ath12k_wmi_dma_ring_caps_params *)ptr; |
4057 | ret = ath12k_wmi_tlv_iter(ab, ptr, len, |
4058 | iter: ath12k_wmi_dma_ring_caps_parse, |
4059 | data: dma_caps_parse); |
4060 | if (ret) { |
4061 | ath12k_warn(ab, fmt: "failed to parse dma ring caps tlv %d\n" , ret); |
4062 | return ret; |
4063 | } |
4064 | |
4065 | if (!dma_caps_parse->n_dma_ring_caps) |
4066 | return 0; |
4067 | |
4068 | if (ab->num_db_cap) { |
4069 | ath12k_warn(ab, fmt: "Already processed, so ignoring dma ring caps\n" ); |
4070 | return 0; |
4071 | } |
4072 | |
4073 | ret = ath12k_wmi_alloc_dbring_caps(ab, num_cap: dma_caps_parse->n_dma_ring_caps); |
4074 | if (ret) |
4075 | return ret; |
4076 | |
4077 | dir_buff_caps = ab->db_caps; |
4078 | for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) { |
4079 | if (le32_to_cpu(dma_caps[i].module_id) >= WMI_DIRECT_BUF_MAX) { |
4080 | ath12k_warn(ab, fmt: "Invalid module id %d\n" , |
4081 | le32_to_cpu(dma_caps[i].module_id)); |
4082 | ret = -EINVAL; |
4083 | goto free_dir_buff; |
4084 | } |
4085 | |
4086 | dir_buff_caps[i].id = le32_to_cpu(dma_caps[i].module_id); |
4087 | dir_buff_caps[i].pdev_id = |
4088 | DP_HW2SW_MACID(le32_to_cpu(dma_caps[i].pdev_id)); |
4089 | dir_buff_caps[i].min_elem = le32_to_cpu(dma_caps[i].min_elem); |
4090 | dir_buff_caps[i].min_buf_sz = le32_to_cpu(dma_caps[i].min_buf_sz); |
4091 | dir_buff_caps[i].min_buf_align = le32_to_cpu(dma_caps[i].min_buf_align); |
4092 | } |
4093 | |
4094 | return 0; |
4095 | |
4096 | free_dir_buff: |
4097 | ath12k_wmi_free_dbring_caps(ab); |
4098 | return ret; |
4099 | } |
4100 | |
4101 | static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab, |
4102 | u16 tag, u16 len, |
4103 | const void *ptr, void *data) |
4104 | { |
4105 | struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; |
4106 | struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data; |
4107 | int ret; |
4108 | |
4109 | switch (tag) { |
4110 | case WMI_TAG_SERVICE_READY_EXT_EVENT: |
4111 | ret = ath12k_pull_svc_ready_ext(wmi_handle, ptr, |
4112 | arg: &svc_rdy_ext->arg); |
4113 | if (ret) { |
4114 | ath12k_warn(ab, fmt: "unable to extract ext params\n" ); |
4115 | return ret; |
4116 | } |
4117 | break; |
4118 | |
4119 | case WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS: |
4120 | svc_rdy_ext->hw_caps = ptr; |
4121 | svc_rdy_ext->arg.num_hw_modes = |
4122 | le32_to_cpu(svc_rdy_ext->hw_caps->num_hw_modes); |
4123 | break; |
4124 | |
4125 | case WMI_TAG_SOC_HAL_REG_CAPABILITIES: |
4126 | ret = ath12k_wmi_ext_soc_hal_reg_caps_parse(soc: ab, len, ptr, |
4127 | data: svc_rdy_ext); |
4128 | if (ret) |
4129 | return ret; |
4130 | break; |
4131 | |
4132 | case WMI_TAG_ARRAY_STRUCT: |
4133 | if (!svc_rdy_ext->hw_mode_done) { |
4134 | ret = ath12k_wmi_hw_mode_caps(soc: ab, len, ptr, data: svc_rdy_ext); |
4135 | if (ret) |
4136 | return ret; |
4137 | |
4138 | svc_rdy_ext->hw_mode_done = true; |
4139 | } else if (!svc_rdy_ext->mac_phy_done) { |
4140 | svc_rdy_ext->n_mac_phy_caps = 0; |
4141 | ret = ath12k_wmi_tlv_iter(ab, ptr, len, |
4142 | iter: ath12k_wmi_mac_phy_caps_parse, |
4143 | data: svc_rdy_ext); |
4144 | if (ret) { |
4145 | ath12k_warn(ab, fmt: "failed to parse tlv %d\n" , ret); |
4146 | return ret; |
4147 | } |
4148 | |
4149 | svc_rdy_ext->mac_phy_done = true; |
4150 | } else if (!svc_rdy_ext->ext_hal_reg_done) { |
4151 | ret = ath12k_wmi_ext_hal_reg_caps(soc: ab, len, ptr, data: svc_rdy_ext); |
4152 | if (ret) |
4153 | return ret; |
4154 | |
4155 | svc_rdy_ext->ext_hal_reg_done = true; |
4156 | } else if (!svc_rdy_ext->mac_phy_chainmask_combo_done) { |
4157 | svc_rdy_ext->mac_phy_chainmask_combo_done = true; |
4158 | } else if (!svc_rdy_ext->mac_phy_chainmask_cap_done) { |
4159 | svc_rdy_ext->mac_phy_chainmask_cap_done = true; |
4160 | } else if (!svc_rdy_ext->oem_dma_ring_cap_done) { |
4161 | svc_rdy_ext->oem_dma_ring_cap_done = true; |
4162 | } else if (!svc_rdy_ext->dma_ring_cap_done) { |
4163 | ret = ath12k_wmi_dma_ring_caps(ab, len, ptr, |
4164 | data: &svc_rdy_ext->dma_caps_parse); |
4165 | if (ret) |
4166 | return ret; |
4167 | |
4168 | svc_rdy_ext->dma_ring_cap_done = true; |
4169 | } |
4170 | break; |
4171 | |
4172 | default: |
4173 | break; |
4174 | } |
4175 | return 0; |
4176 | } |
4177 | |
4178 | static int ath12k_service_ready_ext_event(struct ath12k_base *ab, |
4179 | struct sk_buff *skb) |
4180 | { |
4181 | struct ath12k_wmi_svc_rdy_ext_parse svc_rdy_ext = { }; |
4182 | int ret; |
4183 | |
4184 | ret = ath12k_wmi_tlv_iter(ab, ptr: skb->data, len: skb->len, |
4185 | iter: ath12k_wmi_svc_rdy_ext_parse, |
4186 | data: &svc_rdy_ext); |
4187 | if (ret) { |
4188 | ath12k_warn(ab, fmt: "failed to parse tlv %d\n" , ret); |
4189 | goto err; |
4190 | } |
4191 | |
4192 | if (!test_bit(WMI_TLV_SERVICE_EXT2_MSG, ab->wmi_ab.svc_map)) |
4193 | complete(&ab->wmi_ab.service_ready); |
4194 | |
4195 | kfree(objp: svc_rdy_ext.mac_phy_caps); |
4196 | return 0; |
4197 | |
4198 | err: |
4199 | ath12k_wmi_free_dbring_caps(ab); |
4200 | return ret; |
4201 | } |
4202 | |
4203 | static int ath12k_pull_svc_ready_ext2(struct ath12k_wmi_pdev *wmi_handle, |
4204 | const void *ptr, |
4205 | struct ath12k_wmi_svc_rdy_ext2_arg *arg) |
4206 | { |
4207 | const struct wmi_service_ready_ext2_event *ev = ptr; |
4208 | |
4209 | if (!ev) |
4210 | return -EINVAL; |
4211 | |
4212 | arg->reg_db_version = le32_to_cpu(ev->reg_db_version); |
4213 | arg->hw_min_max_tx_power_2ghz = le32_to_cpu(ev->hw_min_max_tx_power_2ghz); |
4214 | arg->hw_min_max_tx_power_5ghz = le32_to_cpu(ev->hw_min_max_tx_power_5ghz); |
4215 | arg->chwidth_num_peer_caps = le32_to_cpu(ev->chwidth_num_peer_caps); |
4216 | arg->preamble_puncture_bw = le32_to_cpu(ev->preamble_puncture_bw); |
4217 | arg->max_user_per_ppdu_ofdma = le32_to_cpu(ev->max_user_per_ppdu_ofdma); |
4218 | arg->max_user_per_ppdu_mumimo = le32_to_cpu(ev->max_user_per_ppdu_mumimo); |
4219 | arg->target_cap_flags = le32_to_cpu(ev->target_cap_flags); |
4220 | return 0; |
4221 | } |
4222 | |
4223 | static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band, |
4224 | const __le32 cap_mac_info[], |
4225 | const __le32 cap_phy_info[], |
4226 | const __le32 supp_mcs[], |
4227 | const struct ath12k_wmi_ppe_threshold_params *ppet, |
4228 | __le32 cap_info_internal) |
4229 | { |
4230 | struct ath12k_band_cap *cap_band = &pdev->cap.band[band]; |
4231 | u32 support_320mhz; |
4232 | u8 i; |
4233 | |
4234 | if (band == NL80211_BAND_6GHZ) |
4235 | support_320mhz = cap_band->eht_cap_phy_info[0] & |
4236 | IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; |
4237 | |
4238 | for (i = 0; i < WMI_MAX_EHTCAP_MAC_SIZE; i++) |
4239 | cap_band->eht_cap_mac_info[i] = le32_to_cpu(cap_mac_info[i]); |
4240 | |
4241 | for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++) |
4242 | cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]); |
4243 | |
4244 | if (band == NL80211_BAND_6GHZ) |
4245 | cap_band->eht_cap_phy_info[0] |= support_320mhz; |
4246 | |
4247 | cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]); |
4248 | cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]); |
4249 | if (band != NL80211_BAND_2GHZ) { |
4250 | cap_band->eht_mcs_160 = le32_to_cpu(supp_mcs[2]); |
4251 | cap_band->eht_mcs_320 = le32_to_cpu(supp_mcs[3]); |
4252 | } |
4253 | |
4254 | cap_band->eht_ppet.numss_m1 = le32_to_cpu(ppet->numss_m1); |
4255 | cap_band->eht_ppet.ru_bit_mask = le32_to_cpu(ppet->ru_info); |
4256 | for (i = 0; i < WMI_MAX_NUM_SS; i++) |
4257 | cap_band->eht_ppet.ppet16_ppet8_ru3_ru0[i] = |
4258 | le32_to_cpu(ppet->ppet16_ppet8_ru3_ru0[i]); |
4259 | |
4260 | cap_band->eht_cap_info_internal = le32_to_cpu(cap_info_internal); |
4261 | } |
4262 | |
4263 | static int |
4264 | ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, |
4265 | const struct ath12k_wmi_caps_ext_params *caps, |
4266 | struct ath12k_pdev *pdev) |
4267 | { |
4268 | struct ath12k_band_cap *cap_band; |
4269 | u32 bands, support_320mhz; |
4270 | int i; |
4271 | |
4272 | if (ab->hw_params->single_pdev_only) { |
4273 | if (caps->hw_mode_id == WMI_HOST_HW_MODE_SINGLE) { |
4274 | support_320mhz = le32_to_cpu(caps->eht_cap_phy_info_5ghz[0]) & |
4275 | IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; |
4276 | cap_band = &pdev->cap.band[NL80211_BAND_6GHZ]; |
4277 | cap_band->eht_cap_phy_info[0] |= support_320mhz; |
4278 | return 0; |
4279 | } |
4280 | |
4281 | for (i = 0; i < ab->fw_pdev_count; i++) { |
4282 | struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i]; |
4283 | |
4284 | if (fw_pdev->pdev_id == ath12k_wmi_caps_ext_get_pdev_id(param: caps) && |
4285 | fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) { |
4286 | bands = fw_pdev->supported_bands; |
4287 | break; |
4288 | } |
4289 | } |
4290 | |
4291 | if (i == ab->fw_pdev_count) |
4292 | return -EINVAL; |
4293 | } else { |
4294 | bands = pdev->cap.supported_bands; |
4295 | } |
4296 | |
4297 | if (bands & WMI_HOST_WLAN_2G_CAP) { |
4298 | ath12k_wmi_eht_caps_parse(pdev, band: NL80211_BAND_2GHZ, |
4299 | cap_mac_info: caps->eht_cap_mac_info_2ghz, |
4300 | cap_phy_info: caps->eht_cap_phy_info_2ghz, |
4301 | supp_mcs: caps->eht_supp_mcs_ext_2ghz, |
4302 | ppet: &caps->eht_ppet_2ghz, |
4303 | cap_info_internal: caps->eht_cap_info_internal); |
4304 | } |
4305 | |
4306 | if (bands & WMI_HOST_WLAN_5G_CAP) { |
4307 | ath12k_wmi_eht_caps_parse(pdev, band: NL80211_BAND_5GHZ, |
4308 | cap_mac_info: caps->eht_cap_mac_info_5ghz, |
4309 | cap_phy_info: caps->eht_cap_phy_info_5ghz, |
4310 | supp_mcs: caps->eht_supp_mcs_ext_5ghz, |
4311 | ppet: &caps->eht_ppet_5ghz, |
4312 | cap_info_internal: caps->eht_cap_info_internal); |
4313 | |
4314 | ath12k_wmi_eht_caps_parse(pdev, band: NL80211_BAND_6GHZ, |
4315 | cap_mac_info: caps->eht_cap_mac_info_5ghz, |
4316 | cap_phy_info: caps->eht_cap_phy_info_5ghz, |
4317 | supp_mcs: caps->eht_supp_mcs_ext_5ghz, |
4318 | ppet: &caps->eht_ppet_5ghz, |
4319 | cap_info_internal: caps->eht_cap_info_internal); |
4320 | } |
4321 | |
4322 | return 0; |
4323 | } |
4324 | |
4325 | static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, |
4326 | u16 len, const void *ptr, |
4327 | void *data) |
4328 | { |
4329 | const struct ath12k_wmi_caps_ext_params *caps = ptr; |
4330 | int i = 0, ret; |
4331 | |
4332 | if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT) |
4333 | return -EPROTO; |
4334 | |
4335 | if (ab->hw_params->single_pdev_only) { |
4336 | if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id) && |
4337 | caps->hw_mode_id != WMI_HOST_HW_MODE_SINGLE) |
4338 | return 0; |
4339 | } else { |
4340 | for (i = 0; i < ab->num_radios; i++) { |
4341 | if (ab->pdevs[i].pdev_id == |
4342 | ath12k_wmi_caps_ext_get_pdev_id(param: caps)) |
4343 | break; |
4344 | } |
4345 | |
4346 | if (i == ab->num_radios) |
4347 | return -EINVAL; |
4348 | } |
4349 | |
4350 | ret = ath12k_wmi_tlv_mac_phy_caps_ext_parse(ab, caps, pdev: &ab->pdevs[i]); |
4351 | if (ret) { |
4352 | ath12k_warn(ab, |
4353 | fmt: "failed to parse extended MAC PHY capabilities for pdev %d: %d\n" , |
4354 | ret, ab->pdevs[i].pdev_id); |
4355 | return ret; |
4356 | } |
4357 | |
4358 | return 0; |
4359 | } |
4360 | |
4361 | static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab, |
4362 | u16 tag, u16 len, |
4363 | const void *ptr, void *data) |
4364 | { |
4365 | struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0]; |
4366 | struct ath12k_wmi_svc_rdy_ext2_parse *parse = data; |
4367 | int ret; |
4368 | |
4369 | switch (tag) { |
4370 | case WMI_TAG_SERVICE_READY_EXT2_EVENT: |
4371 | ret = ath12k_pull_svc_ready_ext2(wmi_handle, ptr, |
4372 | arg: &parse->arg); |
4373 | if (ret) { |
4374 | ath12k_warn(ab, |
4375 | fmt: "failed to extract wmi service ready ext2 parameters: %d\n" , |
4376 | ret); |
4377 | return ret; |
4378 | } |
4379 | break; |
4380 | |
4381 | case WMI_TAG_ARRAY_STRUCT: |
4382 | if (!parse->dma_ring_cap_done) { |
4383 | ret = ath12k_wmi_dma_ring_caps(ab, len, ptr, |
4384 | data: &parse->dma_caps_parse); |
4385 | if (ret) |
4386 | return ret; |
4387 | |
4388 | parse->dma_ring_cap_done = true; |
4389 | } else if (!parse->spectral_bin_scaling_done) { |
4390 | /* TODO: This is a place-holder as WMI tag for |
4391 | * spectral scaling is before |
4392 | * WMI_TAG_MAC_PHY_CAPABILITIES_EXT |
4393 | */ |
4394 | parse->spectral_bin_scaling_done = true; |
4395 | } else if (!parse->mac_phy_caps_ext_done) { |
4396 | ret = ath12k_wmi_tlv_iter(ab, ptr, len, |
4397 | iter: ath12k_wmi_tlv_mac_phy_caps_ext, |
4398 | data: parse); |
4399 | if (ret) { |
4400 | ath12k_warn(ab, fmt: "failed to parse extended MAC PHY capabilities WMI TLV: %d\n" , |
4401 | ret); |
4402 | return ret; |
4403 | } |
4404 | |
4405 | parse->mac_phy_caps_ext_done = true; |
4406 | } |
4407 | break; |
4408 | default: |
4409 | break; |
4410 | } |
4411 | |
4412 | return 0; |
4413 | } |
4414 | |
4415 | static int ath12k_service_ready_ext2_event(struct ath12k_base *ab, |
4416 | struct sk_buff *skb) |
4417 | { |
4418 | struct ath12k_wmi_svc_rdy_ext2_parse svc_rdy_ext2 = { }; |
4419 | int ret; |
4420 | |
4421 | ret = ath12k_wmi_tlv_iter(ab, ptr: skb->data, len: skb->len, |
4422 | iter: ath12k_wmi_svc_rdy_ext2_parse, |
4423 | data: &svc_rdy_ext2); |
4424 | if (ret) { |
4425 | ath12k_warn(ab, fmt: "failed to parse ext2 event tlv %d\n" , ret); |
4426 | goto err; |
4427 | } |
4428 | |
4429 | complete(&ab->wmi_ab.service_ready); |
4430 | |
4431 | return 0; |
4432 | |
4433 | err: |
4434 | ath12k_wmi_free_dbring_caps(ab); |
4435 | return ret; |
4436 | } |
4437 | |
4438 | static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buff *skb, |
4439 | struct wmi_vdev_start_resp_event *vdev_rsp) |
4440 | { |
4441 | const void **tb; |
4442 | const struct wmi_vdev_start_resp_event *ev; |
4443 | int ret; |
4444 | |
4445 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
4446 | if (IS_ERR(ptr: tb)) { |
4447 | ret = PTR_ERR(ptr: tb); |
4448 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
4449 | return ret; |
4450 | } |
4451 | |
4452 | ev = tb[WMI_TAG_VDEV_START_RESPONSE_EVENT]; |
4453 | if (!ev) { |
4454 | ath12k_warn(ab, fmt: "failed to fetch vdev start resp ev" ); |
4455 | kfree(objp: tb); |
4456 | return -EPROTO; |
4457 | } |
4458 | |
4459 | *vdev_rsp = *ev; |
4460 | |
4461 | kfree(objp: tb); |
4462 | return 0; |
4463 | } |
4464 | |
4465 | static struct ath12k_reg_rule |
4466 | *create_ext_reg_rules_from_wmi(u32 num_reg_rules, |
4467 | struct ath12k_wmi_reg_rule_ext_params *wmi_reg_rule) |
4468 | { |
4469 | struct ath12k_reg_rule *reg_rule_ptr; |
4470 | u32 count; |
4471 | |
4472 | reg_rule_ptr = kzalloc(size: (num_reg_rules * sizeof(*reg_rule_ptr)), |
4473 | GFP_ATOMIC); |
4474 | |
4475 | if (!reg_rule_ptr) |
4476 | return NULL; |
4477 | |
4478 | for (count = 0; count < num_reg_rules; count++) { |
4479 | reg_rule_ptr[count].start_freq = |
4480 | le32_get_bits(v: wmi_reg_rule[count].freq_info, |
4481 | REG_RULE_START_FREQ); |
4482 | reg_rule_ptr[count].end_freq = |
4483 | le32_get_bits(v: wmi_reg_rule[count].freq_info, |
4484 | REG_RULE_END_FREQ); |
4485 | reg_rule_ptr[count].max_bw = |
4486 | le32_get_bits(v: wmi_reg_rule[count].bw_pwr_info, |
4487 | REG_RULE_MAX_BW); |
4488 | reg_rule_ptr[count].reg_power = |
4489 | le32_get_bits(v: wmi_reg_rule[count].bw_pwr_info, |
4490 | REG_RULE_REG_PWR); |
4491 | reg_rule_ptr[count].ant_gain = |
4492 | le32_get_bits(v: wmi_reg_rule[count].bw_pwr_info, |
4493 | REG_RULE_ANT_GAIN); |
4494 | reg_rule_ptr[count].flags = |
4495 | le32_get_bits(v: wmi_reg_rule[count].flag_info, |
4496 | REG_RULE_FLAGS); |
4497 | reg_rule_ptr[count].psd_flag = |
4498 | le32_get_bits(v: wmi_reg_rule[count].psd_power_info, |
4499 | REG_RULE_PSD_INFO); |
4500 | reg_rule_ptr[count].psd_eirp = |
4501 | le32_get_bits(v: wmi_reg_rule[count].psd_power_info, |
4502 | REG_RULE_PSD_EIRP); |
4503 | } |
4504 | |
4505 | return reg_rule_ptr; |
4506 | } |
4507 | |
4508 | static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, |
4509 | struct sk_buff *skb, |
4510 | struct ath12k_reg_info *reg_info) |
4511 | { |
4512 | const void **tb; |
4513 | const struct wmi_reg_chan_list_cc_ext_event *ev; |
4514 | struct ath12k_wmi_reg_rule_ext_params *ext_wmi_reg_rule; |
4515 | u32 num_2g_reg_rules, num_5g_reg_rules; |
4516 | u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE]; |
4517 | u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE]; |
4518 | u32 total_reg_rules = 0; |
4519 | int ret, i, j; |
4520 | |
4521 | ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n" ); |
4522 | |
4523 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
4524 | if (IS_ERR(ptr: tb)) { |
4525 | ret = PTR_ERR(ptr: tb); |
4526 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
4527 | return ret; |
4528 | } |
4529 | |
4530 | ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT]; |
4531 | if (!ev) { |
4532 | ath12k_warn(ab, fmt: "failed to fetch reg chan list ext update ev\n" ); |
4533 | kfree(objp: tb); |
4534 | return -EPROTO; |
4535 | } |
4536 | |
4537 | reg_info->num_2g_reg_rules = le32_to_cpu(ev->num_2g_reg_rules); |
4538 | reg_info->num_5g_reg_rules = le32_to_cpu(ev->num_5g_reg_rules); |
4539 | reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP] = |
4540 | le32_to_cpu(ev->num_6g_reg_rules_ap_lpi); |
4541 | reg_info->num_6g_reg_rules_ap[WMI_REG_STD_POWER_AP] = |
4542 | le32_to_cpu(ev->num_6g_reg_rules_ap_sp); |
4543 | reg_info->num_6g_reg_rules_ap[WMI_REG_VLP_AP] = |
4544 | le32_to_cpu(ev->num_6g_reg_rules_ap_vlp); |
4545 | |
4546 | for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { |
4547 | reg_info->num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i] = |
4548 | le32_to_cpu(ev->num_6g_reg_rules_cl_lpi[i]); |
4549 | reg_info->num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i] = |
4550 | le32_to_cpu(ev->num_6g_reg_rules_cl_sp[i]); |
4551 | reg_info->num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] = |
4552 | le32_to_cpu(ev->num_6g_reg_rules_cl_vlp[i]); |
4553 | } |
4554 | |
4555 | num_2g_reg_rules = reg_info->num_2g_reg_rules; |
4556 | total_reg_rules += num_2g_reg_rules; |
4557 | num_5g_reg_rules = reg_info->num_5g_reg_rules; |
4558 | total_reg_rules += num_5g_reg_rules; |
4559 | |
4560 | if (num_2g_reg_rules > MAX_REG_RULES || num_5g_reg_rules > MAX_REG_RULES) { |
4561 | ath12k_warn(ab, fmt: "Num reg rules for 2G/5G exceeds max limit (num_2g_reg_rules: %d num_5g_reg_rules: %d max_rules: %d)\n" , |
4562 | num_2g_reg_rules, num_5g_reg_rules, MAX_REG_RULES); |
4563 | kfree(objp: tb); |
4564 | return -EINVAL; |
4565 | } |
4566 | |
4567 | for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { |
4568 | num_6g_reg_rules_ap[i] = reg_info->num_6g_reg_rules_ap[i]; |
4569 | |
4570 | if (num_6g_reg_rules_ap[i] > MAX_6G_REG_RULES) { |
4571 | ath12k_warn(ab, fmt: "Num 6G reg rules for AP mode(%d) exceeds max limit (num_6g_reg_rules_ap: %d, max_rules: %d)\n" , |
4572 | i, num_6g_reg_rules_ap[i], MAX_6G_REG_RULES); |
4573 | kfree(objp: tb); |
4574 | return -EINVAL; |
4575 | } |
4576 | |
4577 | total_reg_rules += num_6g_reg_rules_ap[i]; |
4578 | } |
4579 | |
4580 | for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { |
4581 | num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i] = |
4582 | reg_info->num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i]; |
4583 | total_reg_rules += num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i]; |
4584 | |
4585 | num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i] = |
4586 | reg_info->num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i]; |
4587 | total_reg_rules += num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i]; |
4588 | |
4589 | num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] = |
4590 | reg_info->num_6g_reg_rules_cl[WMI_REG_VLP_AP][i]; |
4591 | total_reg_rules += num_6g_reg_rules_cl[WMI_REG_VLP_AP][i]; |
4592 | |
4593 | if (num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i] > MAX_6G_REG_RULES || |
4594 | num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i] > MAX_6G_REG_RULES || |
4595 | num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] > MAX_6G_REG_RULES) { |
4596 | ath12k_warn(ab, fmt: "Num 6g client reg rules exceeds max limit, for client(type: %d)\n" , |
4597 | i); |
4598 | kfree(objp: tb); |
4599 | return -EINVAL; |
4600 | } |
4601 | } |
4602 | |
4603 | if (!total_reg_rules) { |
4604 | ath12k_warn(ab, fmt: "No reg rules available\n" ); |
4605 | kfree(objp: tb); |
4606 | return -EINVAL; |
4607 | } |
4608 | |
4609 | memcpy(reg_info->alpha2, &ev->alpha2, REG_ALPHA2_LEN); |
4610 | |
4611 | /* FIXME: Currently FW includes 6G reg rule also in 5G rule |
4612 | * list for country US. |
4613 | * Having same 6G reg rule in 5G and 6G rules list causes |
4614 | * intersect check to be true, and same rules will be shown |
4615 | * multiple times in iw cmd. So added hack below to avoid |
4616 | * parsing 6G rule from 5G reg rule list, and this can be |
4617 | * removed later, after FW updates to remove 6G reg rule |
4618 | * from 5G rules list. |
4619 | */ |
4620 | if (memcmp(p: reg_info->alpha2, q: "US" , size: 2) == 0) { |
4621 | reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES; |
4622 | num_5g_reg_rules = reg_info->num_5g_reg_rules; |
4623 | } |
4624 | |
4625 | reg_info->dfs_region = le32_to_cpu(ev->dfs_region); |
4626 | reg_info->phybitmap = le32_to_cpu(ev->phybitmap); |
4627 | reg_info->num_phy = le32_to_cpu(ev->num_phy); |
4628 | reg_info->phy_id = le32_to_cpu(ev->phy_id); |
4629 | reg_info->ctry_code = le32_to_cpu(ev->country_id); |
4630 | reg_info->reg_dmn_pair = le32_to_cpu(ev->domain_code); |
4631 | |
4632 | switch (le32_to_cpu(ev->status_code)) { |
4633 | case WMI_REG_SET_CC_STATUS_PASS: |
4634 | reg_info->status_code = REG_SET_CC_STATUS_PASS; |
4635 | break; |
4636 | case WMI_REG_CURRENT_ALPHA2_NOT_FOUND: |
4637 | reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND; |
4638 | break; |
4639 | case WMI_REG_INIT_ALPHA2_NOT_FOUND: |
4640 | reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND; |
4641 | break; |
4642 | case WMI_REG_SET_CC_CHANGE_NOT_ALLOWED: |
4643 | reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED; |
4644 | break; |
4645 | case WMI_REG_SET_CC_STATUS_NO_MEMORY: |
4646 | reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY; |
4647 | break; |
4648 | case WMI_REG_SET_CC_STATUS_FAIL: |
4649 | reg_info->status_code = REG_SET_CC_STATUS_FAIL; |
4650 | break; |
4651 | } |
4652 | |
4653 | reg_info->is_ext_reg_event = true; |
4654 | |
4655 | reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g); |
4656 | reg_info->max_bw_2g = le32_to_cpu(ev->max_bw_2g); |
4657 | reg_info->min_bw_5g = le32_to_cpu(ev->min_bw_5g); |
4658 | reg_info->max_bw_5g = le32_to_cpu(ev->max_bw_5g); |
4659 | reg_info->min_bw_6g_ap[WMI_REG_INDOOR_AP] = le32_to_cpu(ev->min_bw_6g_ap_lpi); |
4660 | reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP] = le32_to_cpu(ev->max_bw_6g_ap_lpi); |
4661 | reg_info->min_bw_6g_ap[WMI_REG_STD_POWER_AP] = le32_to_cpu(ev->min_bw_6g_ap_sp); |
4662 | reg_info->max_bw_6g_ap[WMI_REG_STD_POWER_AP] = le32_to_cpu(ev->max_bw_6g_ap_sp); |
4663 | reg_info->min_bw_6g_ap[WMI_REG_VLP_AP] = le32_to_cpu(ev->min_bw_6g_ap_vlp); |
4664 | reg_info->max_bw_6g_ap[WMI_REG_VLP_AP] = le32_to_cpu(ev->max_bw_6g_ap_vlp); |
4665 | |
4666 | for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { |
4667 | reg_info->min_bw_6g_client[WMI_REG_INDOOR_AP][i] = |
4668 | le32_to_cpu(ev->min_bw_6g_client_lpi[i]); |
4669 | reg_info->max_bw_6g_client[WMI_REG_INDOOR_AP][i] = |
4670 | le32_to_cpu(ev->max_bw_6g_client_lpi[i]); |
4671 | reg_info->min_bw_6g_client[WMI_REG_STD_POWER_AP][i] = |
4672 | le32_to_cpu(ev->min_bw_6g_client_sp[i]); |
4673 | reg_info->max_bw_6g_client[WMI_REG_STD_POWER_AP][i] = |
4674 | le32_to_cpu(ev->max_bw_6g_client_sp[i]); |
4675 | reg_info->min_bw_6g_client[WMI_REG_VLP_AP][i] = |
4676 | le32_to_cpu(ev->min_bw_6g_client_vlp[i]); |
4677 | reg_info->max_bw_6g_client[WMI_REG_VLP_AP][i] = |
4678 | le32_to_cpu(ev->max_bw_6g_client_vlp[i]); |
4679 | } |
4680 | |
4681 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
4682 | "%s:cc_ext %s dfs %d BW: min_2g %d max_2g %d min_5g %d max_5g %d phy_bitmap 0x%x" , |
4683 | __func__, reg_info->alpha2, reg_info->dfs_region, |
4684 | reg_info->min_bw_2g, reg_info->max_bw_2g, |
4685 | reg_info->min_bw_5g, reg_info->max_bw_5g, |
4686 | reg_info->phybitmap); |
4687 | |
4688 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
4689 | "num_2g_reg_rules %d num_5g_reg_rules %d" , |
4690 | num_2g_reg_rules, num_5g_reg_rules); |
4691 | |
4692 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
4693 | "num_6g_reg_rules_ap_lpi: %d num_6g_reg_rules_ap_sp: %d num_6g_reg_rules_ap_vlp: %d" , |
4694 | num_6g_reg_rules_ap[WMI_REG_INDOOR_AP], |
4695 | num_6g_reg_rules_ap[WMI_REG_STD_POWER_AP], |
4696 | num_6g_reg_rules_ap[WMI_REG_VLP_AP]); |
4697 | |
4698 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
4699 | "6g Regular client: num_6g_reg_rules_lpi: %d num_6g_reg_rules_sp: %d num_6g_reg_rules_vlp: %d" , |
4700 | num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][WMI_REG_DEFAULT_CLIENT], |
4701 | num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][WMI_REG_DEFAULT_CLIENT], |
4702 | num_6g_reg_rules_cl[WMI_REG_VLP_AP][WMI_REG_DEFAULT_CLIENT]); |
4703 | |
4704 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
4705 | "6g Subordinate client: num_6g_reg_rules_lpi: %d num_6g_reg_rules_sp: %d num_6g_reg_rules_vlp: %d" , |
4706 | num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][WMI_REG_SUBORDINATE_CLIENT], |
4707 | num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][WMI_REG_SUBORDINATE_CLIENT], |
4708 | num_6g_reg_rules_cl[WMI_REG_VLP_AP][WMI_REG_SUBORDINATE_CLIENT]); |
4709 | |
4710 | ext_wmi_reg_rule = |
4711 | (struct ath12k_wmi_reg_rule_ext_params *)((u8 *)ev |
4712 | + sizeof(*ev) |
4713 | + sizeof(struct wmi_tlv)); |
4714 | |
4715 | if (num_2g_reg_rules) { |
4716 | reg_info->reg_rules_2g_ptr = |
4717 | create_ext_reg_rules_from_wmi(num_reg_rules: num_2g_reg_rules, |
4718 | wmi_reg_rule: ext_wmi_reg_rule); |
4719 | |
4720 | if (!reg_info->reg_rules_2g_ptr) { |
4721 | kfree(objp: tb); |
4722 | ath12k_warn(ab, fmt: "Unable to Allocate memory for 2g rules\n" ); |
4723 | return -ENOMEM; |
4724 | } |
4725 | } |
4726 | |
4727 | if (num_5g_reg_rules) { |
4728 | ext_wmi_reg_rule += num_2g_reg_rules; |
4729 | reg_info->reg_rules_5g_ptr = |
4730 | create_ext_reg_rules_from_wmi(num_reg_rules: num_5g_reg_rules, |
4731 | wmi_reg_rule: ext_wmi_reg_rule); |
4732 | |
4733 | if (!reg_info->reg_rules_5g_ptr) { |
4734 | kfree(objp: tb); |
4735 | ath12k_warn(ab, fmt: "Unable to Allocate memory for 5g rules\n" ); |
4736 | return -ENOMEM; |
4737 | } |
4738 | } |
4739 | |
4740 | ext_wmi_reg_rule += num_5g_reg_rules; |
4741 | |
4742 | for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) { |
4743 | reg_info->reg_rules_6g_ap_ptr[i] = |
4744 | create_ext_reg_rules_from_wmi(num_reg_rules: num_6g_reg_rules_ap[i], |
4745 | wmi_reg_rule: ext_wmi_reg_rule); |
4746 | |
4747 | if (!reg_info->reg_rules_6g_ap_ptr[i]) { |
4748 | kfree(objp: tb); |
4749 | ath12k_warn(ab, fmt: "Unable to Allocate memory for 6g ap rules\n" ); |
4750 | return -ENOMEM; |
4751 | } |
4752 | |
4753 | ext_wmi_reg_rule += num_6g_reg_rules_ap[i]; |
4754 | } |
4755 | |
4756 | for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) { |
4757 | for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { |
4758 | reg_info->reg_rules_6g_client_ptr[j][i] = |
4759 | create_ext_reg_rules_from_wmi(num_reg_rules: num_6g_reg_rules_cl[j][i], |
4760 | wmi_reg_rule: ext_wmi_reg_rule); |
4761 | |
4762 | if (!reg_info->reg_rules_6g_client_ptr[j][i]) { |
4763 | kfree(objp: tb); |
4764 | ath12k_warn(ab, fmt: "Unable to Allocate memory for 6g client rules\n" ); |
4765 | return -ENOMEM; |
4766 | } |
4767 | |
4768 | ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i]; |
4769 | } |
4770 | } |
4771 | |
4772 | reg_info->client_type = le32_to_cpu(ev->client_type); |
4773 | reg_info->rnr_tpe_usable = ev->rnr_tpe_usable; |
4774 | reg_info->unspecified_ap_usable = ev->unspecified_ap_usable; |
4775 | reg_info->domain_code_6g_ap[WMI_REG_INDOOR_AP] = |
4776 | le32_to_cpu(ev->domain_code_6g_ap_lpi); |
4777 | reg_info->domain_code_6g_ap[WMI_REG_STD_POWER_AP] = |
4778 | le32_to_cpu(ev->domain_code_6g_ap_sp); |
4779 | reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] = |
4780 | le32_to_cpu(ev->domain_code_6g_ap_vlp); |
4781 | |
4782 | for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) { |
4783 | reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] = |
4784 | le32_to_cpu(ev->domain_code_6g_client_lpi[i]); |
4785 | reg_info->domain_code_6g_client[WMI_REG_STD_POWER_AP][i] = |
4786 | le32_to_cpu(ev->domain_code_6g_client_sp[i]); |
4787 | reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] = |
4788 | le32_to_cpu(ev->domain_code_6g_client_vlp[i]); |
4789 | } |
4790 | |
4791 | reg_info->domain_code_6g_super_id = le32_to_cpu(ev->domain_code_6g_super_id); |
4792 | |
4793 | ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d" , |
4794 | reg_info->client_type, reg_info->domain_code_6g_super_id); |
4795 | |
4796 | ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n" ); |
4797 | |
4798 | kfree(objp: tb); |
4799 | return 0; |
4800 | } |
4801 | |
4802 | static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *skb, |
4803 | struct wmi_peer_delete_resp_event *peer_del_resp) |
4804 | { |
4805 | const void **tb; |
4806 | const struct wmi_peer_delete_resp_event *ev; |
4807 | int ret; |
4808 | |
4809 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
4810 | if (IS_ERR(ptr: tb)) { |
4811 | ret = PTR_ERR(ptr: tb); |
4812 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
4813 | return ret; |
4814 | } |
4815 | |
4816 | ev = tb[WMI_TAG_PEER_DELETE_RESP_EVENT]; |
4817 | if (!ev) { |
4818 | ath12k_warn(ab, fmt: "failed to fetch peer delete resp ev" ); |
4819 | kfree(objp: tb); |
4820 | return -EPROTO; |
4821 | } |
4822 | |
4823 | memset(peer_del_resp, 0, sizeof(*peer_del_resp)); |
4824 | |
4825 | peer_del_resp->vdev_id = ev->vdev_id; |
4826 | ether_addr_copy(dst: peer_del_resp->peer_macaddr.addr, |
4827 | src: ev->peer_macaddr.addr); |
4828 | |
4829 | kfree(objp: tb); |
4830 | return 0; |
4831 | } |
4832 | |
4833 | static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, |
4834 | struct sk_buff *skb, |
4835 | u32 *vdev_id) |
4836 | { |
4837 | const void **tb; |
4838 | const struct wmi_vdev_delete_resp_event *ev; |
4839 | int ret; |
4840 | |
4841 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
4842 | if (IS_ERR(ptr: tb)) { |
4843 | ret = PTR_ERR(ptr: tb); |
4844 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
4845 | return ret; |
4846 | } |
4847 | |
4848 | ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT]; |
4849 | if (!ev) { |
4850 | ath12k_warn(ab, fmt: "failed to fetch vdev delete resp ev" ); |
4851 | kfree(objp: tb); |
4852 | return -EPROTO; |
4853 | } |
4854 | |
4855 | *vdev_id = le32_to_cpu(ev->vdev_id); |
4856 | |
4857 | kfree(objp: tb); |
4858 | return 0; |
4859 | } |
4860 | |
4861 | static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, |
4862 | struct sk_buff *skb, |
4863 | u32 *vdev_id, u32 *tx_status) |
4864 | { |
4865 | const void **tb; |
4866 | const struct wmi_bcn_tx_status_event *ev; |
4867 | int ret; |
4868 | |
4869 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
4870 | if (IS_ERR(ptr: tb)) { |
4871 | ret = PTR_ERR(ptr: tb); |
4872 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
4873 | return ret; |
4874 | } |
4875 | |
4876 | ev = tb[WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT]; |
4877 | if (!ev) { |
4878 | ath12k_warn(ab, fmt: "failed to fetch bcn tx status ev" ); |
4879 | kfree(objp: tb); |
4880 | return -EPROTO; |
4881 | } |
4882 | |
4883 | *vdev_id = le32_to_cpu(ev->vdev_id); |
4884 | *tx_status = le32_to_cpu(ev->tx_status); |
4885 | |
4886 | kfree(objp: tb); |
4887 | return 0; |
4888 | } |
4889 | |
4890 | static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_buff *skb, |
4891 | u32 *vdev_id) |
4892 | { |
4893 | const void **tb; |
4894 | const struct wmi_vdev_stopped_event *ev; |
4895 | int ret; |
4896 | |
4897 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
4898 | if (IS_ERR(ptr: tb)) { |
4899 | ret = PTR_ERR(ptr: tb); |
4900 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
4901 | return ret; |
4902 | } |
4903 | |
4904 | ev = tb[WMI_TAG_VDEV_STOPPED_EVENT]; |
4905 | if (!ev) { |
4906 | ath12k_warn(ab, fmt: "failed to fetch vdev stop ev" ); |
4907 | kfree(objp: tb); |
4908 | return -EPROTO; |
4909 | } |
4910 | |
4911 | *vdev_id = le32_to_cpu(ev->vdev_id); |
4912 | |
4913 | kfree(objp: tb); |
4914 | return 0; |
4915 | } |
4916 | |
4917 | static int ath12k_wmi_tlv_mgmt_rx_parse(struct ath12k_base *ab, |
4918 | u16 tag, u16 len, |
4919 | const void *ptr, void *data) |
4920 | { |
4921 | struct wmi_tlv_mgmt_rx_parse *parse = data; |
4922 | |
4923 | switch (tag) { |
4924 | case WMI_TAG_MGMT_RX_HDR: |
4925 | parse->fixed = ptr; |
4926 | break; |
4927 | case WMI_TAG_ARRAY_BYTE: |
4928 | if (!parse->frame_buf_done) { |
4929 | parse->frame_buf = ptr; |
4930 | parse->frame_buf_done = true; |
4931 | } |
4932 | break; |
4933 | } |
4934 | return 0; |
4935 | } |
4936 | |
4937 | static int ath12k_pull_mgmt_rx_params_tlv(struct ath12k_base *ab, |
4938 | struct sk_buff *skb, |
4939 | struct ath12k_wmi_mgmt_rx_arg *hdr) |
4940 | { |
4941 | struct wmi_tlv_mgmt_rx_parse parse = { }; |
4942 | const struct ath12k_wmi_mgmt_rx_params *ev; |
4943 | const u8 *frame; |
4944 | int i, ret; |
4945 | |
4946 | ret = ath12k_wmi_tlv_iter(ab, ptr: skb->data, len: skb->len, |
4947 | iter: ath12k_wmi_tlv_mgmt_rx_parse, |
4948 | data: &parse); |
4949 | if (ret) { |
4950 | ath12k_warn(ab, fmt: "failed to parse mgmt rx tlv %d\n" , ret); |
4951 | return ret; |
4952 | } |
4953 | |
4954 | ev = parse.fixed; |
4955 | frame = parse.frame_buf; |
4956 | |
4957 | if (!ev || !frame) { |
4958 | ath12k_warn(ab, fmt: "failed to fetch mgmt rx hdr" ); |
4959 | return -EPROTO; |
4960 | } |
4961 | |
4962 | hdr->pdev_id = le32_to_cpu(ev->pdev_id); |
4963 | hdr->chan_freq = le32_to_cpu(ev->chan_freq); |
4964 | hdr->channel = le32_to_cpu(ev->channel); |
4965 | hdr->snr = le32_to_cpu(ev->snr); |
4966 | hdr->rate = le32_to_cpu(ev->rate); |
4967 | hdr->phy_mode = le32_to_cpu(ev->phy_mode); |
4968 | hdr->buf_len = le32_to_cpu(ev->buf_len); |
4969 | hdr->status = le32_to_cpu(ev->status); |
4970 | hdr->flags = le32_to_cpu(ev->flags); |
4971 | hdr->rssi = a_sle32_to_cpu(val: ev->rssi); |
4972 | hdr->tsf_delta = le32_to_cpu(ev->tsf_delta); |
4973 | |
4974 | for (i = 0; i < ATH_MAX_ANTENNA; i++) |
4975 | hdr->rssi_ctl[i] = le32_to_cpu(ev->rssi_ctl[i]); |
4976 | |
4977 | if (skb->len < (frame - skb->data) + hdr->buf_len) { |
4978 | ath12k_warn(ab, fmt: "invalid length in mgmt rx hdr ev" ); |
4979 | return -EPROTO; |
4980 | } |
4981 | |
4982 | /* shift the sk_buff to point to `frame` */ |
4983 | skb_trim(skb, len: 0); |
4984 | skb_put(skb, len: frame - skb->data); |
4985 | skb_pull(skb, len: frame - skb->data); |
4986 | skb_put(skb, len: hdr->buf_len); |
4987 | |
4988 | return 0; |
4989 | } |
4990 | |
4991 | static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, |
4992 | u32 status) |
4993 | { |
4994 | struct sk_buff *msdu; |
4995 | struct ieee80211_tx_info *info; |
4996 | struct ath12k_skb_cb *skb_cb; |
4997 | int num_mgmt; |
4998 | |
4999 | spin_lock_bh(lock: &ar->txmgmt_idr_lock); |
5000 | msdu = idr_find(&ar->txmgmt_idr, id: desc_id); |
5001 | |
5002 | if (!msdu) { |
5003 | ath12k_warn(ab: ar->ab, fmt: "received mgmt tx compl for invalid msdu_id: %d\n" , |
5004 | desc_id); |
5005 | spin_unlock_bh(lock: &ar->txmgmt_idr_lock); |
5006 | return -ENOENT; |
5007 | } |
5008 | |
5009 | idr_remove(&ar->txmgmt_idr, id: desc_id); |
5010 | spin_unlock_bh(lock: &ar->txmgmt_idr_lock); |
5011 | |
5012 | skb_cb = ATH12K_SKB_CB(skb: msdu); |
5013 | dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); |
5014 | |
5015 | info = IEEE80211_SKB_CB(skb: msdu); |
5016 | if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) |
5017 | info->flags |= IEEE80211_TX_STAT_ACK; |
5018 | |
5019 | ieee80211_tx_status_irqsafe(hw: ath12k_ar_to_hw(ar), skb: msdu); |
5020 | |
5021 | num_mgmt = atomic_dec_if_positive(v: &ar->num_pending_mgmt_tx); |
5022 | |
5023 | /* WARN when we received this event without doing any mgmt tx */ |
5024 | if (num_mgmt < 0) |
5025 | WARN_ON_ONCE(1); |
5026 | |
5027 | if (!num_mgmt) |
5028 | wake_up(&ar->txmgmt_empty_waitq); |
5029 | |
5030 | return 0; |
5031 | } |
5032 | |
5033 | static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, |
5034 | struct sk_buff *skb, |
5035 | struct wmi_mgmt_tx_compl_event *param) |
5036 | { |
5037 | const void **tb; |
5038 | const struct wmi_mgmt_tx_compl_event *ev; |
5039 | int ret; |
5040 | |
5041 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5042 | if (IS_ERR(ptr: tb)) { |
5043 | ret = PTR_ERR(ptr: tb); |
5044 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5045 | return ret; |
5046 | } |
5047 | |
5048 | ev = tb[WMI_TAG_MGMT_TX_COMPL_EVENT]; |
5049 | if (!ev) { |
5050 | ath12k_warn(ab, fmt: "failed to fetch mgmt tx compl ev" ); |
5051 | kfree(objp: tb); |
5052 | return -EPROTO; |
5053 | } |
5054 | |
5055 | param->pdev_id = ev->pdev_id; |
5056 | param->desc_id = ev->desc_id; |
5057 | param->status = ev->status; |
5058 | |
5059 | kfree(objp: tb); |
5060 | return 0; |
5061 | } |
5062 | |
5063 | static void ath12k_wmi_event_scan_started(struct ath12k *ar) |
5064 | { |
5065 | lockdep_assert_held(&ar->data_lock); |
5066 | |
5067 | switch (ar->scan.state) { |
5068 | case ATH12K_SCAN_IDLE: |
5069 | case ATH12K_SCAN_RUNNING: |
5070 | case ATH12K_SCAN_ABORTING: |
5071 | ath12k_warn(ab: ar->ab, fmt: "received scan started event in an invalid scan state: %s (%d)\n" , |
5072 | ath12k_scan_state_str(state: ar->scan.state), |
5073 | ar->scan.state); |
5074 | break; |
5075 | case ATH12K_SCAN_STARTING: |
5076 | ar->scan.state = ATH12K_SCAN_RUNNING; |
5077 | |
5078 | if (ar->scan.is_roc) |
5079 | ieee80211_ready_on_channel(hw: ath12k_ar_to_hw(ar)); |
5080 | |
5081 | complete(&ar->scan.started); |
5082 | break; |
5083 | } |
5084 | } |
5085 | |
5086 | static void ath12k_wmi_event_scan_start_failed(struct ath12k *ar) |
5087 | { |
5088 | lockdep_assert_held(&ar->data_lock); |
5089 | |
5090 | switch (ar->scan.state) { |
5091 | case ATH12K_SCAN_IDLE: |
5092 | case ATH12K_SCAN_RUNNING: |
5093 | case ATH12K_SCAN_ABORTING: |
5094 | ath12k_warn(ab: ar->ab, fmt: "received scan start failed event in an invalid scan state: %s (%d)\n" , |
5095 | ath12k_scan_state_str(state: ar->scan.state), |
5096 | ar->scan.state); |
5097 | break; |
5098 | case ATH12K_SCAN_STARTING: |
5099 | complete(&ar->scan.started); |
5100 | __ath12k_mac_scan_finish(ar); |
5101 | break; |
5102 | } |
5103 | } |
5104 | |
5105 | static void ath12k_wmi_event_scan_completed(struct ath12k *ar) |
5106 | { |
5107 | lockdep_assert_held(&ar->data_lock); |
5108 | |
5109 | switch (ar->scan.state) { |
5110 | case ATH12K_SCAN_IDLE: |
5111 | case ATH12K_SCAN_STARTING: |
5112 | /* One suspected reason scan can be completed while starting is |
5113 | * if firmware fails to deliver all scan events to the host, |
5114 | * e.g. when transport pipe is full. This has been observed |
5115 | * with spectral scan phyerr events starving wmi transport |
5116 | * pipe. In such case the "scan completed" event should be (and |
5117 | * is) ignored by the host as it may be just firmware's scan |
5118 | * state machine recovering. |
5119 | */ |
5120 | ath12k_warn(ab: ar->ab, fmt: "received scan completed event in an invalid scan state: %s (%d)\n" , |
5121 | ath12k_scan_state_str(state: ar->scan.state), |
5122 | ar->scan.state); |
5123 | break; |
5124 | case ATH12K_SCAN_RUNNING: |
5125 | case ATH12K_SCAN_ABORTING: |
5126 | __ath12k_mac_scan_finish(ar); |
5127 | break; |
5128 | } |
5129 | } |
5130 | |
5131 | static void ath12k_wmi_event_scan_bss_chan(struct ath12k *ar) |
5132 | { |
5133 | lockdep_assert_held(&ar->data_lock); |
5134 | |
5135 | switch (ar->scan.state) { |
5136 | case ATH12K_SCAN_IDLE: |
5137 | case ATH12K_SCAN_STARTING: |
5138 | ath12k_warn(ab: ar->ab, fmt: "received scan bss chan event in an invalid scan state: %s (%d)\n" , |
5139 | ath12k_scan_state_str(state: ar->scan.state), |
5140 | ar->scan.state); |
5141 | break; |
5142 | case ATH12K_SCAN_RUNNING: |
5143 | case ATH12K_SCAN_ABORTING: |
5144 | ar->scan_channel = NULL; |
5145 | break; |
5146 | } |
5147 | } |
5148 | |
5149 | static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq) |
5150 | { |
5151 | struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); |
5152 | |
5153 | lockdep_assert_held(&ar->data_lock); |
5154 | |
5155 | switch (ar->scan.state) { |
5156 | case ATH12K_SCAN_IDLE: |
5157 | case ATH12K_SCAN_STARTING: |
5158 | ath12k_warn(ab: ar->ab, fmt: "received scan foreign chan event in an invalid scan state: %s (%d)\n" , |
5159 | ath12k_scan_state_str(state: ar->scan.state), |
5160 | ar->scan.state); |
5161 | break; |
5162 | case ATH12K_SCAN_RUNNING: |
5163 | case ATH12K_SCAN_ABORTING: |
5164 | ar->scan_channel = ieee80211_get_channel(wiphy: hw->wiphy, freq); |
5165 | |
5166 | if (ar->scan.is_roc && ar->scan.roc_freq == freq) |
5167 | complete(&ar->scan.on_channel); |
5168 | |
5169 | break; |
5170 | } |
5171 | } |
5172 | |
5173 | static const char * |
5174 | ath12k_wmi_event_scan_type_str(enum wmi_scan_event_type type, |
5175 | enum wmi_scan_completion_reason reason) |
5176 | { |
5177 | switch (type) { |
5178 | case WMI_SCAN_EVENT_STARTED: |
5179 | return "started" ; |
5180 | case WMI_SCAN_EVENT_COMPLETED: |
5181 | switch (reason) { |
5182 | case WMI_SCAN_REASON_COMPLETED: |
5183 | return "completed" ; |
5184 | case WMI_SCAN_REASON_CANCELLED: |
5185 | return "completed [cancelled]" ; |
5186 | case WMI_SCAN_REASON_PREEMPTED: |
5187 | return "completed [preempted]" ; |
5188 | case WMI_SCAN_REASON_TIMEDOUT: |
5189 | return "completed [timedout]" ; |
5190 | case WMI_SCAN_REASON_INTERNAL_FAILURE: |
5191 | return "completed [internal err]" ; |
5192 | case WMI_SCAN_REASON_MAX: |
5193 | break; |
5194 | } |
5195 | return "completed [unknown]" ; |
5196 | case WMI_SCAN_EVENT_BSS_CHANNEL: |
5197 | return "bss channel" ; |
5198 | case WMI_SCAN_EVENT_FOREIGN_CHAN: |
5199 | return "foreign channel" ; |
5200 | case WMI_SCAN_EVENT_DEQUEUED: |
5201 | return "dequeued" ; |
5202 | case WMI_SCAN_EVENT_PREEMPTED: |
5203 | return "preempted" ; |
5204 | case WMI_SCAN_EVENT_START_FAILED: |
5205 | return "start failed" ; |
5206 | case WMI_SCAN_EVENT_RESTARTED: |
5207 | return "restarted" ; |
5208 | case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT: |
5209 | return "foreign channel exit" ; |
5210 | default: |
5211 | return "unknown" ; |
5212 | } |
5213 | } |
5214 | |
5215 | static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5216 | struct wmi_scan_event *scan_evt_param) |
5217 | { |
5218 | const void **tb; |
5219 | const struct wmi_scan_event *ev; |
5220 | int ret; |
5221 | |
5222 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5223 | if (IS_ERR(ptr: tb)) { |
5224 | ret = PTR_ERR(ptr: tb); |
5225 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5226 | return ret; |
5227 | } |
5228 | |
5229 | ev = tb[WMI_TAG_SCAN_EVENT]; |
5230 | if (!ev) { |
5231 | ath12k_warn(ab, fmt: "failed to fetch scan ev" ); |
5232 | kfree(objp: tb); |
5233 | return -EPROTO; |
5234 | } |
5235 | |
5236 | scan_evt_param->event_type = ev->event_type; |
5237 | scan_evt_param->reason = ev->reason; |
5238 | scan_evt_param->channel_freq = ev->channel_freq; |
5239 | scan_evt_param->scan_req_id = ev->scan_req_id; |
5240 | scan_evt_param->scan_id = ev->scan_id; |
5241 | scan_evt_param->vdev_id = ev->vdev_id; |
5242 | scan_evt_param->tsf_timestamp = ev->tsf_timestamp; |
5243 | |
5244 | kfree(objp: tb); |
5245 | return 0; |
5246 | } |
5247 | |
5248 | static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5249 | struct wmi_peer_sta_kickout_arg *arg) |
5250 | { |
5251 | const void **tb; |
5252 | const struct wmi_peer_sta_kickout_event *ev; |
5253 | int ret; |
5254 | |
5255 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5256 | if (IS_ERR(ptr: tb)) { |
5257 | ret = PTR_ERR(ptr: tb); |
5258 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5259 | return ret; |
5260 | } |
5261 | |
5262 | ev = tb[WMI_TAG_PEER_STA_KICKOUT_EVENT]; |
5263 | if (!ev) { |
5264 | ath12k_warn(ab, fmt: "failed to fetch peer sta kickout ev" ); |
5265 | kfree(objp: tb); |
5266 | return -EPROTO; |
5267 | } |
5268 | |
5269 | arg->mac_addr = ev->peer_macaddr.addr; |
5270 | |
5271 | kfree(objp: tb); |
5272 | return 0; |
5273 | } |
5274 | |
5275 | static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5276 | struct wmi_roam_event *roam_ev) |
5277 | { |
5278 | const void **tb; |
5279 | const struct wmi_roam_event *ev; |
5280 | int ret; |
5281 | |
5282 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5283 | if (IS_ERR(ptr: tb)) { |
5284 | ret = PTR_ERR(ptr: tb); |
5285 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5286 | return ret; |
5287 | } |
5288 | |
5289 | ev = tb[WMI_TAG_ROAM_EVENT]; |
5290 | if (!ev) { |
5291 | ath12k_warn(ab, fmt: "failed to fetch roam ev" ); |
5292 | kfree(objp: tb); |
5293 | return -EPROTO; |
5294 | } |
5295 | |
5296 | roam_ev->vdev_id = ev->vdev_id; |
5297 | roam_ev->reason = ev->reason; |
5298 | roam_ev->rssi = ev->rssi; |
5299 | |
5300 | kfree(objp: tb); |
5301 | return 0; |
5302 | } |
5303 | |
5304 | static int freq_to_idx(struct ath12k *ar, int freq) |
5305 | { |
5306 | struct ieee80211_supported_band *sband; |
5307 | struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); |
5308 | int band, ch, idx = 0; |
5309 | |
5310 | for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { |
5311 | if (!ar->mac.sbands[band].channels) |
5312 | continue; |
5313 | |
5314 | sband = hw->wiphy->bands[band]; |
5315 | if (!sband) |
5316 | continue; |
5317 | |
5318 | for (ch = 0; ch < sband->n_channels; ch++, idx++) |
5319 | if (sband->channels[ch].center_freq == freq) |
5320 | goto exit; |
5321 | } |
5322 | |
5323 | exit: |
5324 | return idx; |
5325 | } |
5326 | |
5327 | static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5328 | struct wmi_chan_info_event *ch_info_ev) |
5329 | { |
5330 | const void **tb; |
5331 | const struct wmi_chan_info_event *ev; |
5332 | int ret; |
5333 | |
5334 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5335 | if (IS_ERR(ptr: tb)) { |
5336 | ret = PTR_ERR(ptr: tb); |
5337 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5338 | return ret; |
5339 | } |
5340 | |
5341 | ev = tb[WMI_TAG_CHAN_INFO_EVENT]; |
5342 | if (!ev) { |
5343 | ath12k_warn(ab, fmt: "failed to fetch chan info ev" ); |
5344 | kfree(objp: tb); |
5345 | return -EPROTO; |
5346 | } |
5347 | |
5348 | ch_info_ev->err_code = ev->err_code; |
5349 | ch_info_ev->freq = ev->freq; |
5350 | ch_info_ev->cmd_flags = ev->cmd_flags; |
5351 | ch_info_ev->noise_floor = ev->noise_floor; |
5352 | ch_info_ev->rx_clear_count = ev->rx_clear_count; |
5353 | ch_info_ev->cycle_count = ev->cycle_count; |
5354 | ch_info_ev->chan_tx_pwr_range = ev->chan_tx_pwr_range; |
5355 | ch_info_ev->chan_tx_pwr_tp = ev->chan_tx_pwr_tp; |
5356 | ch_info_ev->rx_frame_count = ev->rx_frame_count; |
5357 | ch_info_ev->tx_frame_cnt = ev->tx_frame_cnt; |
5358 | ch_info_ev->mac_clk_mhz = ev->mac_clk_mhz; |
5359 | ch_info_ev->vdev_id = ev->vdev_id; |
5360 | |
5361 | kfree(objp: tb); |
5362 | return 0; |
5363 | } |
5364 | |
5365 | static int |
5366 | ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5367 | struct wmi_pdev_bss_chan_info_event *bss_ch_info_ev) |
5368 | { |
5369 | const void **tb; |
5370 | const struct wmi_pdev_bss_chan_info_event *ev; |
5371 | int ret; |
5372 | |
5373 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5374 | if (IS_ERR(ptr: tb)) { |
5375 | ret = PTR_ERR(ptr: tb); |
5376 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5377 | return ret; |
5378 | } |
5379 | |
5380 | ev = tb[WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT]; |
5381 | if (!ev) { |
5382 | ath12k_warn(ab, fmt: "failed to fetch pdev bss chan info ev" ); |
5383 | kfree(objp: tb); |
5384 | return -EPROTO; |
5385 | } |
5386 | |
5387 | bss_ch_info_ev->pdev_id = ev->pdev_id; |
5388 | bss_ch_info_ev->freq = ev->freq; |
5389 | bss_ch_info_ev->noise_floor = ev->noise_floor; |
5390 | bss_ch_info_ev->rx_clear_count_low = ev->rx_clear_count_low; |
5391 | bss_ch_info_ev->rx_clear_count_high = ev->rx_clear_count_high; |
5392 | bss_ch_info_ev->cycle_count_low = ev->cycle_count_low; |
5393 | bss_ch_info_ev->cycle_count_high = ev->cycle_count_high; |
5394 | bss_ch_info_ev->tx_cycle_count_low = ev->tx_cycle_count_low; |
5395 | bss_ch_info_ev->tx_cycle_count_high = ev->tx_cycle_count_high; |
5396 | bss_ch_info_ev->rx_cycle_count_low = ev->rx_cycle_count_low; |
5397 | bss_ch_info_ev->rx_cycle_count_high = ev->rx_cycle_count_high; |
5398 | bss_ch_info_ev->rx_bss_cycle_count_low = ev->rx_bss_cycle_count_low; |
5399 | bss_ch_info_ev->rx_bss_cycle_count_high = ev->rx_bss_cycle_count_high; |
5400 | |
5401 | kfree(objp: tb); |
5402 | return 0; |
5403 | } |
5404 | |
5405 | static int |
5406 | ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5407 | struct wmi_vdev_install_key_complete_arg *arg) |
5408 | { |
5409 | const void **tb; |
5410 | const struct wmi_vdev_install_key_compl_event *ev; |
5411 | int ret; |
5412 | |
5413 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5414 | if (IS_ERR(ptr: tb)) { |
5415 | ret = PTR_ERR(ptr: tb); |
5416 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5417 | return ret; |
5418 | } |
5419 | |
5420 | ev = tb[WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT]; |
5421 | if (!ev) { |
5422 | ath12k_warn(ab, fmt: "failed to fetch vdev install key compl ev" ); |
5423 | kfree(objp: tb); |
5424 | return -EPROTO; |
5425 | } |
5426 | |
5427 | arg->vdev_id = le32_to_cpu(ev->vdev_id); |
5428 | arg->macaddr = ev->peer_macaddr.addr; |
5429 | arg->key_idx = le32_to_cpu(ev->key_idx); |
5430 | arg->key_flags = le32_to_cpu(ev->key_flags); |
5431 | arg->status = le32_to_cpu(ev->status); |
5432 | |
5433 | kfree(objp: tb); |
5434 | return 0; |
5435 | } |
5436 | |
5437 | static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5438 | struct wmi_peer_assoc_conf_arg *peer_assoc_conf) |
5439 | { |
5440 | const void **tb; |
5441 | const struct wmi_peer_assoc_conf_event *ev; |
5442 | int ret; |
5443 | |
5444 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5445 | if (IS_ERR(ptr: tb)) { |
5446 | ret = PTR_ERR(ptr: tb); |
5447 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5448 | return ret; |
5449 | } |
5450 | |
5451 | ev = tb[WMI_TAG_PEER_ASSOC_CONF_EVENT]; |
5452 | if (!ev) { |
5453 | ath12k_warn(ab, fmt: "failed to fetch peer assoc conf ev" ); |
5454 | kfree(objp: tb); |
5455 | return -EPROTO; |
5456 | } |
5457 | |
5458 | peer_assoc_conf->vdev_id = le32_to_cpu(ev->vdev_id); |
5459 | peer_assoc_conf->macaddr = ev->peer_macaddr.addr; |
5460 | |
5461 | kfree(objp: tb); |
5462 | return 0; |
5463 | } |
5464 | |
5465 | static int |
5466 | ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, struct sk_buff *skb, |
5467 | const struct wmi_pdev_temperature_event *ev) |
5468 | { |
5469 | const void **tb; |
5470 | int ret; |
5471 | |
5472 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
5473 | if (IS_ERR(ptr: tb)) { |
5474 | ret = PTR_ERR(ptr: tb); |
5475 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
5476 | return ret; |
5477 | } |
5478 | |
5479 | ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT]; |
5480 | if (!ev) { |
5481 | ath12k_warn(ab, fmt: "failed to fetch pdev temp ev" ); |
5482 | kfree(objp: tb); |
5483 | return -EPROTO; |
5484 | } |
5485 | |
5486 | kfree(objp: tb); |
5487 | return 0; |
5488 | } |
5489 | |
5490 | static void ath12k_wmi_op_ep_tx_credits(struct ath12k_base *ab) |
5491 | { |
5492 | /* try to send pending beacons first. they take priority */ |
5493 | wake_up(&ab->wmi_ab.tx_credits_wq); |
5494 | } |
5495 | |
5496 | static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab, |
5497 | struct sk_buff *skb) |
5498 | { |
5499 | dev_kfree_skb(skb); |
5500 | } |
5501 | |
5502 | static bool ath12k_reg_is_world_alpha(char *alpha) |
5503 | { |
5504 | if (alpha[0] == '0' && alpha[1] == '0') |
5505 | return true; |
5506 | |
5507 | if (alpha[0] == 'n' && alpha[1] == 'a') |
5508 | return true; |
5509 | |
5510 | return false; |
5511 | } |
5512 | |
5513 | static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb) |
5514 | { |
5515 | struct ath12k_reg_info *reg_info = NULL; |
5516 | struct ieee80211_regdomain *regd = NULL; |
5517 | bool intersect = false; |
5518 | int ret = 0, pdev_idx, i, j; |
5519 | struct ath12k *ar; |
5520 | |
5521 | reg_info = kzalloc(size: sizeof(*reg_info), GFP_ATOMIC); |
5522 | if (!reg_info) { |
5523 | ret = -ENOMEM; |
5524 | goto fallback; |
5525 | } |
5526 | |
5527 | ret = ath12k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info); |
5528 | |
5529 | if (ret) { |
5530 | ath12k_warn(ab, fmt: "failed to extract regulatory info from received event\n" ); |
5531 | goto fallback; |
5532 | } |
5533 | |
5534 | if (reg_info->status_code != REG_SET_CC_STATUS_PASS) { |
5535 | /* In case of failure to set the requested ctry, |
5536 | * fw retains the current regd. We print a failure info |
5537 | * and return from here. |
5538 | */ |
5539 | ath12k_warn(ab, fmt: "Failed to set the requested Country regulatory setting\n" ); |
5540 | goto mem_free; |
5541 | } |
5542 | |
5543 | pdev_idx = reg_info->phy_id; |
5544 | |
5545 | if (pdev_idx >= ab->num_radios) { |
5546 | /* Process the event for phy0 only if single_pdev_only |
5547 | * is true. If pdev_idx is valid but not 0, discard the |
5548 | * event. Otherwise, it goes to fallback. |
5549 | */ |
5550 | if (ab->hw_params->single_pdev_only && |
5551 | pdev_idx < ab->hw_params->num_rxmda_per_pdev) |
5552 | goto mem_free; |
5553 | else |
5554 | goto fallback; |
5555 | } |
5556 | |
5557 | /* Avoid multiple overwrites to default regd, during core |
5558 | * stop-start after mac registration. |
5559 | */ |
5560 | if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && |
5561 | !memcmp(p: ab->default_regd[pdev_idx]->alpha2, |
5562 | q: reg_info->alpha2, size: 2)) |
5563 | goto mem_free; |
5564 | |
5565 | /* Intersect new rules with default regd if a new country setting was |
5566 | * requested, i.e a default regd was already set during initialization |
5567 | * and the regd coming from this event has a valid country info. |
5568 | */ |
5569 | if (ab->default_regd[pdev_idx] && |
5570 | !ath12k_reg_is_world_alpha(alpha: (char *) |
5571 | ab->default_regd[pdev_idx]->alpha2) && |
5572 | !ath12k_reg_is_world_alpha(alpha: (char *)reg_info->alpha2)) |
5573 | intersect = true; |
5574 | |
5575 | regd = ath12k_reg_build_regd(ab, reg_info, intersect); |
5576 | if (!regd) { |
5577 | ath12k_warn(ab, fmt: "failed to build regd from reg_info\n" ); |
5578 | goto fallback; |
5579 | } |
5580 | |
5581 | spin_lock(lock: &ab->base_lock); |
5582 | if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) { |
5583 | /* Once mac is registered, ar is valid and all CC events from |
5584 | * fw is considered to be received due to user requests |
5585 | * currently. |
5586 | * Free previously built regd before assigning the newly |
5587 | * generated regd to ar. NULL pointer handling will be |
5588 | * taken care by kfree itself. |
5589 | */ |
5590 | ar = ab->pdevs[pdev_idx].ar; |
5591 | kfree(objp: ab->new_regd[pdev_idx]); |
5592 | ab->new_regd[pdev_idx] = regd; |
5593 | queue_work(wq: ab->workqueue, work: &ar->regd_update_work); |
5594 | } else { |
5595 | /* Multiple events for the same *ar is not expected. But we |
5596 | * can still clear any previously stored default_regd if we |
5597 | * are receiving this event for the same radio by mistake. |
5598 | * NULL pointer handling will be taken care by kfree itself. |
5599 | */ |
5600 | kfree(objp: ab->default_regd[pdev_idx]); |
5601 | /* This regd would be applied during mac registration */ |
5602 | ab->default_regd[pdev_idx] = regd; |
5603 | } |
5604 | ab->dfs_region = reg_info->dfs_region; |
5605 | spin_unlock(lock: &ab->base_lock); |
5606 | |
5607 | goto mem_free; |
5608 | |
5609 | fallback: |
5610 | /* Fallback to older reg (by sending previous country setting |
5611 | * again if fw has succeeded and we failed to process here. |
5612 | * The Regdomain should be uniform across driver and fw. Since the |
5613 | * FW has processed the command and sent a success status, we expect |
5614 | * this function to succeed as well. If it doesn't, CTRY needs to be |
5615 | * reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent. |
5616 | */ |
5617 | /* TODO: This is rare, but still should also be handled */ |
5618 | WARN_ON(1); |
5619 | mem_free: |
5620 | if (reg_info) { |
5621 | kfree(objp: reg_info->reg_rules_2g_ptr); |
5622 | kfree(objp: reg_info->reg_rules_5g_ptr); |
5623 | if (reg_info->is_ext_reg_event) { |
5624 | for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) |
5625 | kfree(objp: reg_info->reg_rules_6g_ap_ptr[i]); |
5626 | |
5627 | for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) |
5628 | for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) |
5629 | kfree(objp: reg_info->reg_rules_6g_client_ptr[j][i]); |
5630 | } |
5631 | kfree(objp: reg_info); |
5632 | } |
5633 | return ret; |
5634 | } |
5635 | |
5636 | static int ath12k_wmi_rdy_parse(struct ath12k_base *ab, u16 tag, u16 len, |
5637 | const void *ptr, void *data) |
5638 | { |
5639 | struct ath12k_wmi_rdy_parse *rdy_parse = data; |
5640 | struct wmi_ready_event fixed_param; |
5641 | struct ath12k_wmi_mac_addr_params *addr_list; |
5642 | struct ath12k_pdev *pdev; |
5643 | u32 num_mac_addr; |
5644 | int i; |
5645 | |
5646 | switch (tag) { |
5647 | case WMI_TAG_READY_EVENT: |
5648 | memset(&fixed_param, 0, sizeof(fixed_param)); |
5649 | memcpy(&fixed_param, (struct wmi_ready_event *)ptr, |
5650 | min_t(u16, sizeof(fixed_param), len)); |
5651 | ab->wlan_init_status = le32_to_cpu(fixed_param.ready_event_min.status); |
5652 | rdy_parse->num_extra_mac_addr = |
5653 | le32_to_cpu(fixed_param.ready_event_min.num_extra_mac_addr); |
5654 | |
5655 | ether_addr_copy(dst: ab->mac_addr, |
5656 | src: fixed_param.ready_event_min.mac_addr.addr); |
5657 | ab->pktlog_defs_checksum = le32_to_cpu(fixed_param.pktlog_defs_checksum); |
5658 | ab->wmi_ready = true; |
5659 | break; |
5660 | case WMI_TAG_ARRAY_FIXED_STRUCT: |
5661 | addr_list = (struct ath12k_wmi_mac_addr_params *)ptr; |
5662 | num_mac_addr = rdy_parse->num_extra_mac_addr; |
5663 | |
5664 | if (!(ab->num_radios > 1 && num_mac_addr >= ab->num_radios)) |
5665 | break; |
5666 | |
5667 | for (i = 0; i < ab->num_radios; i++) { |
5668 | pdev = &ab->pdevs[i]; |
5669 | ether_addr_copy(dst: pdev->mac_addr, src: addr_list[i].addr); |
5670 | } |
5671 | ab->pdevs_macaddr_valid = true; |
5672 | break; |
5673 | default: |
5674 | break; |
5675 | } |
5676 | |
5677 | return 0; |
5678 | } |
5679 | |
5680 | static int ath12k_ready_event(struct ath12k_base *ab, struct sk_buff *skb) |
5681 | { |
5682 | struct ath12k_wmi_rdy_parse rdy_parse = { }; |
5683 | int ret; |
5684 | |
5685 | ret = ath12k_wmi_tlv_iter(ab, ptr: skb->data, len: skb->len, |
5686 | iter: ath12k_wmi_rdy_parse, data: &rdy_parse); |
5687 | if (ret) { |
5688 | ath12k_warn(ab, fmt: "failed to parse tlv %d\n" , ret); |
5689 | return ret; |
5690 | } |
5691 | |
5692 | complete(&ab->wmi_ab.unified_ready); |
5693 | return 0; |
5694 | } |
5695 | |
5696 | static void ath12k_peer_delete_resp_event(struct ath12k_base *ab, struct sk_buff *skb) |
5697 | { |
5698 | struct wmi_peer_delete_resp_event peer_del_resp; |
5699 | struct ath12k *ar; |
5700 | |
5701 | if (ath12k_pull_peer_del_resp_ev(ab, skb, peer_del_resp: &peer_del_resp) != 0) { |
5702 | ath12k_warn(ab, fmt: "failed to extract peer delete resp" ); |
5703 | return; |
5704 | } |
5705 | |
5706 | rcu_read_lock(); |
5707 | ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(peer_del_resp.vdev_id)); |
5708 | if (!ar) { |
5709 | ath12k_warn(ab, fmt: "invalid vdev id in peer delete resp ev %d" , |
5710 | peer_del_resp.vdev_id); |
5711 | rcu_read_unlock(); |
5712 | return; |
5713 | } |
5714 | |
5715 | complete(&ar->peer_delete_done); |
5716 | rcu_read_unlock(); |
5717 | ath12k_dbg(ab, ATH12K_DBG_WMI, "peer delete resp for vdev id %d addr %pM\n" , |
5718 | peer_del_resp.vdev_id, peer_del_resp.peer_macaddr.addr); |
5719 | } |
5720 | |
5721 | static void ath12k_vdev_delete_resp_event(struct ath12k_base *ab, |
5722 | struct sk_buff *skb) |
5723 | { |
5724 | struct ath12k *ar; |
5725 | u32 vdev_id = 0; |
5726 | |
5727 | if (ath12k_pull_vdev_del_resp_ev(ab, skb, vdev_id: &vdev_id) != 0) { |
5728 | ath12k_warn(ab, fmt: "failed to extract vdev delete resp" ); |
5729 | return; |
5730 | } |
5731 | |
5732 | rcu_read_lock(); |
5733 | ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); |
5734 | if (!ar) { |
5735 | ath12k_warn(ab, fmt: "invalid vdev id in vdev delete resp ev %d" , |
5736 | vdev_id); |
5737 | rcu_read_unlock(); |
5738 | return; |
5739 | } |
5740 | |
5741 | complete(&ar->vdev_delete_done); |
5742 | |
5743 | rcu_read_unlock(); |
5744 | |
5745 | ath12k_dbg(ab, ATH12K_DBG_WMI, "vdev delete resp for vdev id %d\n" , |
5746 | vdev_id); |
5747 | } |
5748 | |
5749 | static const char *ath12k_wmi_vdev_resp_print(u32 vdev_resp_status) |
5750 | { |
5751 | switch (vdev_resp_status) { |
5752 | case WMI_VDEV_START_RESPONSE_INVALID_VDEVID: |
5753 | return "invalid vdev id" ; |
5754 | case WMI_VDEV_START_RESPONSE_NOT_SUPPORTED: |
5755 | return "not supported" ; |
5756 | case WMI_VDEV_START_RESPONSE_DFS_VIOLATION: |
5757 | return "dfs violation" ; |
5758 | case WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN: |
5759 | return "invalid regdomain" ; |
5760 | default: |
5761 | return "unknown" ; |
5762 | } |
5763 | } |
5764 | |
5765 | static void ath12k_vdev_start_resp_event(struct ath12k_base *ab, struct sk_buff *skb) |
5766 | { |
5767 | struct wmi_vdev_start_resp_event vdev_start_resp; |
5768 | struct ath12k *ar; |
5769 | u32 status; |
5770 | |
5771 | if (ath12k_pull_vdev_start_resp_tlv(ab, skb, vdev_rsp: &vdev_start_resp) != 0) { |
5772 | ath12k_warn(ab, fmt: "failed to extract vdev start resp" ); |
5773 | return; |
5774 | } |
5775 | |
5776 | rcu_read_lock(); |
5777 | ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(vdev_start_resp.vdev_id)); |
5778 | if (!ar) { |
5779 | ath12k_warn(ab, fmt: "invalid vdev id in vdev start resp ev %d" , |
5780 | vdev_start_resp.vdev_id); |
5781 | rcu_read_unlock(); |
5782 | return; |
5783 | } |
5784 | |
5785 | ar->last_wmi_vdev_start_status = 0; |
5786 | |
5787 | status = le32_to_cpu(vdev_start_resp.status); |
5788 | |
5789 | if (WARN_ON_ONCE(status)) { |
5790 | ath12k_warn(ab, fmt: "vdev start resp error status %d (%s)\n" , |
5791 | status, ath12k_wmi_vdev_resp_print(vdev_resp_status: status)); |
5792 | ar->last_wmi_vdev_start_status = status; |
5793 | } |
5794 | |
5795 | complete(&ar->vdev_setup_done); |
5796 | |
5797 | rcu_read_unlock(); |
5798 | |
5799 | ath12k_dbg(ab, ATH12K_DBG_WMI, "vdev start resp for vdev id %d" , |
5800 | vdev_start_resp.vdev_id); |
5801 | } |
5802 | |
5803 | static void ath12k_bcn_tx_status_event(struct ath12k_base *ab, struct sk_buff *skb) |
5804 | { |
5805 | u32 vdev_id, tx_status; |
5806 | |
5807 | if (ath12k_pull_bcn_tx_status_ev(ab, skb, vdev_id: &vdev_id, tx_status: &tx_status) != 0) { |
5808 | ath12k_warn(ab, fmt: "failed to extract bcn tx status" ); |
5809 | return; |
5810 | } |
5811 | } |
5812 | |
5813 | static void ath12k_vdev_stopped_event(struct ath12k_base *ab, struct sk_buff *skb) |
5814 | { |
5815 | struct ath12k *ar; |
5816 | u32 vdev_id = 0; |
5817 | |
5818 | if (ath12k_pull_vdev_stopped_param_tlv(ab, skb, vdev_id: &vdev_id) != 0) { |
5819 | ath12k_warn(ab, fmt: "failed to extract vdev stopped event" ); |
5820 | return; |
5821 | } |
5822 | |
5823 | rcu_read_lock(); |
5824 | ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); |
5825 | if (!ar) { |
5826 | ath12k_warn(ab, fmt: "invalid vdev id in vdev stopped ev %d" , |
5827 | vdev_id); |
5828 | rcu_read_unlock(); |
5829 | return; |
5830 | } |
5831 | |
5832 | complete(&ar->vdev_setup_done); |
5833 | |
5834 | rcu_read_unlock(); |
5835 | |
5836 | ath12k_dbg(ab, ATH12K_DBG_WMI, "vdev stopped for vdev id %d" , vdev_id); |
5837 | } |
5838 | |
5839 | static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) |
5840 | { |
5841 | struct ath12k_wmi_mgmt_rx_arg rx_ev = {0}; |
5842 | struct ath12k *ar; |
5843 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
5844 | struct ieee80211_hdr *hdr; |
5845 | u16 fc; |
5846 | struct ieee80211_supported_band *sband; |
5847 | |
5848 | if (ath12k_pull_mgmt_rx_params_tlv(ab, skb, hdr: &rx_ev) != 0) { |
5849 | ath12k_warn(ab, fmt: "failed to extract mgmt rx event" ); |
5850 | dev_kfree_skb(skb); |
5851 | return; |
5852 | } |
5853 | |
5854 | memset(status, 0, sizeof(*status)); |
5855 | |
5856 | ath12k_dbg(ab, ATH12K_DBG_MGMT, "mgmt rx event status %08x\n" , |
5857 | rx_ev.status); |
5858 | |
5859 | rcu_read_lock(); |
5860 | ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id: rx_ev.pdev_id); |
5861 | |
5862 | if (!ar) { |
5863 | ath12k_warn(ab, fmt: "invalid pdev_id %d in mgmt_rx_event\n" , |
5864 | rx_ev.pdev_id); |
5865 | dev_kfree_skb(skb); |
5866 | goto exit; |
5867 | } |
5868 | |
5869 | if ((test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) || |
5870 | (rx_ev.status & (WMI_RX_STATUS_ERR_DECRYPT | |
5871 | WMI_RX_STATUS_ERR_KEY_CACHE_MISS | |
5872 | WMI_RX_STATUS_ERR_CRC))) { |
5873 | dev_kfree_skb(skb); |
5874 | goto exit; |
5875 | } |
5876 | |
5877 | if (rx_ev.status & WMI_RX_STATUS_ERR_MIC) |
5878 | status->flag |= RX_FLAG_MMIC_ERROR; |
5879 | |
5880 | if (rx_ev.chan_freq >= ATH12K_MIN_6G_FREQ) { |
5881 | status->band = NL80211_BAND_6GHZ; |
5882 | } else if (rx_ev.channel >= 1 && rx_ev.channel <= 14) { |
5883 | status->band = NL80211_BAND_2GHZ; |
5884 | } else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH12K_MAX_5G_CHAN) { |
5885 | status->band = NL80211_BAND_5GHZ; |
5886 | } else { |
5887 | /* Shouldn't happen unless list of advertised channels to |
5888 | * mac80211 has been changed. |
5889 | */ |
5890 | WARN_ON_ONCE(1); |
5891 | dev_kfree_skb(skb); |
5892 | goto exit; |
5893 | } |
5894 | |
5895 | if (rx_ev.phy_mode == MODE_11B && |
5896 | (status->band == NL80211_BAND_5GHZ || status->band == NL80211_BAND_6GHZ)) |
5897 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
5898 | "wmi mgmt rx 11b (CCK) on 5/6GHz, band = %d\n" , status->band); |
5899 | |
5900 | sband = &ar->mac.sbands[status->band]; |
5901 | |
5902 | status->freq = ieee80211_channel_to_frequency(chan: rx_ev.channel, |
5903 | band: status->band); |
5904 | status->signal = rx_ev.snr + ATH12K_DEFAULT_NOISE_FLOOR; |
5905 | status->rate_idx = ath12k_mac_bitrate_to_idx(sband, bitrate: rx_ev.rate / 100); |
5906 | |
5907 | hdr = (struct ieee80211_hdr *)skb->data; |
5908 | fc = le16_to_cpu(hdr->frame_control); |
5909 | |
5910 | /* Firmware is guaranteed to report all essential management frames via |
5911 | * WMI while it can deliver some extra via HTT. Since there can be |
5912 | * duplicates split the reporting wrt monitor/sniffing. |
5913 | */ |
5914 | status->flag |= RX_FLAG_SKIP_MONITOR; |
5915 | |
5916 | /* In case of PMF, FW delivers decrypted frames with Protected Bit set |
5917 | * including group privacy action frames. |
5918 | */ |
5919 | if (ieee80211_has_protected(fc: hdr->frame_control)) { |
5920 | status->flag |= RX_FLAG_DECRYPTED; |
5921 | |
5922 | if (!ieee80211_is_robust_mgmt_frame(skb)) { |
5923 | status->flag |= RX_FLAG_IV_STRIPPED | |
5924 | RX_FLAG_MMIC_STRIPPED; |
5925 | hdr->frame_control = __cpu_to_le16(fc & |
5926 | ~IEEE80211_FCTL_PROTECTED); |
5927 | } |
5928 | } |
5929 | |
5930 | /* TODO: Pending handle beacon implementation |
5931 | *if (ieee80211_is_beacon(hdr->frame_control)) |
5932 | * ath12k_mac_handle_beacon(ar, skb); |
5933 | */ |
5934 | |
5935 | ath12k_dbg(ab, ATH12K_DBG_MGMT, |
5936 | "event mgmt rx skb %pK len %d ftype %02x stype %02x\n" , |
5937 | skb, skb->len, |
5938 | fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE); |
5939 | |
5940 | ath12k_dbg(ab, ATH12K_DBG_MGMT, |
5941 | "event mgmt rx freq %d band %d snr %d, rate_idx %d\n" , |
5942 | status->freq, status->band, status->signal, |
5943 | status->rate_idx); |
5944 | |
5945 | ieee80211_rx_ni(hw: ath12k_ar_to_hw(ar), skb); |
5946 | |
5947 | exit: |
5948 | rcu_read_unlock(); |
5949 | } |
5950 | |
5951 | static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *skb) |
5952 | { |
5953 | struct wmi_mgmt_tx_compl_event tx_compl_param = {0}; |
5954 | struct ath12k *ar; |
5955 | |
5956 | if (ath12k_pull_mgmt_tx_compl_param_tlv(ab, skb, param: &tx_compl_param) != 0) { |
5957 | ath12k_warn(ab, fmt: "failed to extract mgmt tx compl event" ); |
5958 | return; |
5959 | } |
5960 | |
5961 | rcu_read_lock(); |
5962 | ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(tx_compl_param.pdev_id)); |
5963 | if (!ar) { |
5964 | ath12k_warn(ab, fmt: "invalid pdev id %d in mgmt_tx_compl_event\n" , |
5965 | tx_compl_param.pdev_id); |
5966 | goto exit; |
5967 | } |
5968 | |
5969 | wmi_process_mgmt_tx_comp(ar, le32_to_cpu(tx_compl_param.desc_id), |
5970 | le32_to_cpu(tx_compl_param.status)); |
5971 | |
5972 | ath12k_dbg(ab, ATH12K_DBG_MGMT, |
5973 | "mgmt tx compl ev pdev_id %d, desc_id %d, status %d" , |
5974 | tx_compl_param.pdev_id, tx_compl_param.desc_id, |
5975 | tx_compl_param.status); |
5976 | |
5977 | exit: |
5978 | rcu_read_unlock(); |
5979 | } |
5980 | |
5981 | static struct ath12k *ath12k_get_ar_on_scan_state(struct ath12k_base *ab, |
5982 | u32 vdev_id, |
5983 | enum ath12k_scan_state state) |
5984 | { |
5985 | int i; |
5986 | struct ath12k_pdev *pdev; |
5987 | struct ath12k *ar; |
5988 | |
5989 | for (i = 0; i < ab->num_radios; i++) { |
5990 | pdev = rcu_dereference(ab->pdevs_active[i]); |
5991 | if (pdev && pdev->ar) { |
5992 | ar = pdev->ar; |
5993 | |
5994 | spin_lock_bh(lock: &ar->data_lock); |
5995 | if (ar->scan.state == state && |
5996 | ar->scan.vdev_id == vdev_id) { |
5997 | spin_unlock_bh(lock: &ar->data_lock); |
5998 | return ar; |
5999 | } |
6000 | spin_unlock_bh(lock: &ar->data_lock); |
6001 | } |
6002 | } |
6003 | return NULL; |
6004 | } |
6005 | |
6006 | static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb) |
6007 | { |
6008 | struct ath12k *ar; |
6009 | struct wmi_scan_event scan_ev = {0}; |
6010 | |
6011 | if (ath12k_pull_scan_ev(ab, skb, scan_evt_param: &scan_ev) != 0) { |
6012 | ath12k_warn(ab, fmt: "failed to extract scan event" ); |
6013 | return; |
6014 | } |
6015 | |
6016 | rcu_read_lock(); |
6017 | |
6018 | /* In case the scan was cancelled, ex. during interface teardown, |
6019 | * the interface will not be found in active interfaces. |
6020 | * Rather, in such scenarios, iterate over the active pdev's to |
6021 | * search 'ar' if the corresponding 'ar' scan is ABORTING and the |
6022 | * aborting scan's vdev id matches this event info. |
6023 | */ |
6024 | if (le32_to_cpu(scan_ev.event_type) == WMI_SCAN_EVENT_COMPLETED && |
6025 | le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED) { |
6026 | ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id), |
6027 | state: ATH12K_SCAN_ABORTING); |
6028 | if (!ar) |
6029 | ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id), |
6030 | state: ATH12K_SCAN_RUNNING); |
6031 | } else { |
6032 | ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(scan_ev.vdev_id)); |
6033 | } |
6034 | |
6035 | if (!ar) { |
6036 | ath12k_warn(ab, fmt: "Received scan event for unknown vdev" ); |
6037 | rcu_read_unlock(); |
6038 | return; |
6039 | } |
6040 | |
6041 | spin_lock_bh(lock: &ar->data_lock); |
6042 | |
6043 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6044 | "scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n" , |
6045 | ath12k_wmi_event_scan_type_str(le32_to_cpu(scan_ev.event_type), |
6046 | le32_to_cpu(scan_ev.reason)), |
6047 | le32_to_cpu(scan_ev.event_type), |
6048 | le32_to_cpu(scan_ev.reason), |
6049 | le32_to_cpu(scan_ev.channel_freq), |
6050 | le32_to_cpu(scan_ev.scan_req_id), |
6051 | le32_to_cpu(scan_ev.scan_id), |
6052 | le32_to_cpu(scan_ev.vdev_id), |
6053 | ath12k_scan_state_str(ar->scan.state), ar->scan.state); |
6054 | |
6055 | switch (le32_to_cpu(scan_ev.event_type)) { |
6056 | case WMI_SCAN_EVENT_STARTED: |
6057 | ath12k_wmi_event_scan_started(ar); |
6058 | break; |
6059 | case WMI_SCAN_EVENT_COMPLETED: |
6060 | ath12k_wmi_event_scan_completed(ar); |
6061 | break; |
6062 | case WMI_SCAN_EVENT_BSS_CHANNEL: |
6063 | ath12k_wmi_event_scan_bss_chan(ar); |
6064 | break; |
6065 | case WMI_SCAN_EVENT_FOREIGN_CHAN: |
6066 | ath12k_wmi_event_scan_foreign_chan(ar, le32_to_cpu(scan_ev.channel_freq)); |
6067 | break; |
6068 | case WMI_SCAN_EVENT_START_FAILED: |
6069 | ath12k_warn(ab, fmt: "received scan start failure event\n" ); |
6070 | ath12k_wmi_event_scan_start_failed(ar); |
6071 | break; |
6072 | case WMI_SCAN_EVENT_DEQUEUED: |
6073 | __ath12k_mac_scan_finish(ar); |
6074 | break; |
6075 | case WMI_SCAN_EVENT_PREEMPTED: |
6076 | case WMI_SCAN_EVENT_RESTARTED: |
6077 | case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT: |
6078 | default: |
6079 | break; |
6080 | } |
6081 | |
6082 | spin_unlock_bh(lock: &ar->data_lock); |
6083 | |
6084 | rcu_read_unlock(); |
6085 | } |
6086 | |
6087 | static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff *skb) |
6088 | { |
6089 | struct wmi_peer_sta_kickout_arg arg = {}; |
6090 | struct ieee80211_sta *sta; |
6091 | struct ath12k_peer *peer; |
6092 | struct ath12k *ar; |
6093 | |
6094 | if (ath12k_pull_peer_sta_kickout_ev(ab, skb, arg: &arg) != 0) { |
6095 | ath12k_warn(ab, fmt: "failed to extract peer sta kickout event" ); |
6096 | return; |
6097 | } |
6098 | |
6099 | rcu_read_lock(); |
6100 | |
6101 | spin_lock_bh(lock: &ab->base_lock); |
6102 | |
6103 | peer = ath12k_peer_find_by_addr(ab, addr: arg.mac_addr); |
6104 | |
6105 | if (!peer) { |
6106 | ath12k_warn(ab, fmt: "peer not found %pM\n" , |
6107 | arg.mac_addr); |
6108 | goto exit; |
6109 | } |
6110 | |
6111 | ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id: peer->vdev_id); |
6112 | if (!ar) { |
6113 | ath12k_warn(ab, fmt: "invalid vdev id in peer sta kickout ev %d" , |
6114 | peer->vdev_id); |
6115 | goto exit; |
6116 | } |
6117 | |
6118 | sta = ieee80211_find_sta_by_ifaddr(hw: ath12k_ar_to_hw(ar), |
6119 | addr: arg.mac_addr, NULL); |
6120 | if (!sta) { |
6121 | ath12k_warn(ab, fmt: "Spurious quick kickout for STA %pM\n" , |
6122 | arg.mac_addr); |
6123 | goto exit; |
6124 | } |
6125 | |
6126 | ath12k_dbg(ab, ATH12K_DBG_WMI, "peer sta kickout event %pM" , |
6127 | arg.mac_addr); |
6128 | |
6129 | ieee80211_report_low_ack(sta, num_packets: 10); |
6130 | |
6131 | exit: |
6132 | spin_unlock_bh(lock: &ab->base_lock); |
6133 | rcu_read_unlock(); |
6134 | } |
6135 | |
6136 | static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb) |
6137 | { |
6138 | struct wmi_roam_event roam_ev = {}; |
6139 | struct ath12k *ar; |
6140 | |
6141 | if (ath12k_pull_roam_ev(ab, skb, roam_ev: &roam_ev) != 0) { |
6142 | ath12k_warn(ab, fmt: "failed to extract roam event" ); |
6143 | return; |
6144 | } |
6145 | |
6146 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6147 | "wmi roam event vdev %u reason 0x%08x rssi %d\n" , |
6148 | roam_ev.vdev_id, roam_ev.reason, roam_ev.rssi); |
6149 | |
6150 | rcu_read_lock(); |
6151 | ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(roam_ev.vdev_id)); |
6152 | if (!ar) { |
6153 | ath12k_warn(ab, fmt: "invalid vdev id in roam ev %d" , |
6154 | roam_ev.vdev_id); |
6155 | rcu_read_unlock(); |
6156 | return; |
6157 | } |
6158 | |
6159 | if (le32_to_cpu(roam_ev.reason) >= WMI_ROAM_REASON_MAX) |
6160 | ath12k_warn(ab, fmt: "ignoring unknown roam event reason %d on vdev %i\n" , |
6161 | roam_ev.reason, roam_ev.vdev_id); |
6162 | |
6163 | switch (le32_to_cpu(roam_ev.reason)) { |
6164 | case WMI_ROAM_REASON_BEACON_MISS: |
6165 | /* TODO: Pending beacon miss and connection_loss_work |
6166 | * implementation |
6167 | * ath12k_mac_handle_beacon_miss(ar, vdev_id); |
6168 | */ |
6169 | break; |
6170 | case WMI_ROAM_REASON_BETTER_AP: |
6171 | case WMI_ROAM_REASON_LOW_RSSI: |
6172 | case WMI_ROAM_REASON_SUITABLE_AP_FOUND: |
6173 | case WMI_ROAM_REASON_HO_FAILED: |
6174 | ath12k_warn(ab, fmt: "ignoring not implemented roam event reason %d on vdev %i\n" , |
6175 | roam_ev.reason, roam_ev.vdev_id); |
6176 | break; |
6177 | } |
6178 | |
6179 | rcu_read_unlock(); |
6180 | } |
6181 | |
6182 | static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb) |
6183 | { |
6184 | struct wmi_chan_info_event ch_info_ev = {0}; |
6185 | struct ath12k *ar; |
6186 | struct survey_info *survey; |
6187 | int idx; |
6188 | /* HW channel counters frequency value in hertz */ |
6189 | u32 cc_freq_hz = ab->cc_freq_hz; |
6190 | |
6191 | if (ath12k_pull_chan_info_ev(ab, skb, ch_info_ev: &ch_info_ev) != 0) { |
6192 | ath12k_warn(ab, fmt: "failed to extract chan info event" ); |
6193 | return; |
6194 | } |
6195 | |
6196 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6197 | "chan info vdev_id %d err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d mac_clk_mhz %d\n" , |
6198 | ch_info_ev.vdev_id, ch_info_ev.err_code, ch_info_ev.freq, |
6199 | ch_info_ev.cmd_flags, ch_info_ev.noise_floor, |
6200 | ch_info_ev.rx_clear_count, ch_info_ev.cycle_count, |
6201 | ch_info_ev.mac_clk_mhz); |
6202 | |
6203 | if (le32_to_cpu(ch_info_ev.cmd_flags) == WMI_CHAN_INFO_END_RESP) { |
6204 | ath12k_dbg(ab, ATH12K_DBG_WMI, "chan info report completed\n" ); |
6205 | return; |
6206 | } |
6207 | |
6208 | rcu_read_lock(); |
6209 | ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(ch_info_ev.vdev_id)); |
6210 | if (!ar) { |
6211 | ath12k_warn(ab, fmt: "invalid vdev id in chan info ev %d" , |
6212 | ch_info_ev.vdev_id); |
6213 | rcu_read_unlock(); |
6214 | return; |
6215 | } |
6216 | spin_lock_bh(lock: &ar->data_lock); |
6217 | |
6218 | switch (ar->scan.state) { |
6219 | case ATH12K_SCAN_IDLE: |
6220 | case ATH12K_SCAN_STARTING: |
6221 | ath12k_warn(ab, fmt: "received chan info event without a scan request, ignoring\n" ); |
6222 | goto exit; |
6223 | case ATH12K_SCAN_RUNNING: |
6224 | case ATH12K_SCAN_ABORTING: |
6225 | break; |
6226 | } |
6227 | |
6228 | idx = freq_to_idx(ar, le32_to_cpu(ch_info_ev.freq)); |
6229 | if (idx >= ARRAY_SIZE(ar->survey)) { |
6230 | ath12k_warn(ab, fmt: "chan info: invalid frequency %d (idx %d out of bounds)\n" , |
6231 | ch_info_ev.freq, idx); |
6232 | goto exit; |
6233 | } |
6234 | |
6235 | /* If FW provides MAC clock frequency in Mhz, overriding the initialized |
6236 | * HW channel counters frequency value |
6237 | */ |
6238 | if (ch_info_ev.mac_clk_mhz) |
6239 | cc_freq_hz = (le32_to_cpu(ch_info_ev.mac_clk_mhz) * 1000); |
6240 | |
6241 | if (ch_info_ev.cmd_flags == WMI_CHAN_INFO_START_RESP) { |
6242 | survey = &ar->survey[idx]; |
6243 | memset(survey, 0, sizeof(*survey)); |
6244 | survey->noise = le32_to_cpu(ch_info_ev.noise_floor); |
6245 | survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME | |
6246 | SURVEY_INFO_TIME_BUSY; |
6247 | survey->time = div_u64(le32_to_cpu(ch_info_ev.cycle_count), divisor: cc_freq_hz); |
6248 | survey->time_busy = div_u64(le32_to_cpu(ch_info_ev.rx_clear_count), |
6249 | divisor: cc_freq_hz); |
6250 | } |
6251 | exit: |
6252 | spin_unlock_bh(lock: &ar->data_lock); |
6253 | rcu_read_unlock(); |
6254 | } |
6255 | |
6256 | static void |
6257 | ath12k_pdev_bss_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb) |
6258 | { |
6259 | struct wmi_pdev_bss_chan_info_event bss_ch_info_ev = {}; |
6260 | struct survey_info *survey; |
6261 | struct ath12k *ar; |
6262 | u32 cc_freq_hz = ab->cc_freq_hz; |
6263 | u64 busy, total, tx, rx, rx_bss; |
6264 | int idx; |
6265 | |
6266 | if (ath12k_pull_pdev_bss_chan_info_ev(ab, skb, bss_ch_info_ev: &bss_ch_info_ev) != 0) { |
6267 | ath12k_warn(ab, fmt: "failed to extract pdev bss chan info event" ); |
6268 | return; |
6269 | } |
6270 | |
6271 | busy = (u64)(le32_to_cpu(bss_ch_info_ev.rx_clear_count_high)) << 32 | |
6272 | le32_to_cpu(bss_ch_info_ev.rx_clear_count_low); |
6273 | |
6274 | total = (u64)(le32_to_cpu(bss_ch_info_ev.cycle_count_high)) << 32 | |
6275 | le32_to_cpu(bss_ch_info_ev.cycle_count_low); |
6276 | |
6277 | tx = (u64)(le32_to_cpu(bss_ch_info_ev.tx_cycle_count_high)) << 32 | |
6278 | le32_to_cpu(bss_ch_info_ev.tx_cycle_count_low); |
6279 | |
6280 | rx = (u64)(le32_to_cpu(bss_ch_info_ev.rx_cycle_count_high)) << 32 | |
6281 | le32_to_cpu(bss_ch_info_ev.rx_cycle_count_low); |
6282 | |
6283 | rx_bss = (u64)(le32_to_cpu(bss_ch_info_ev.rx_bss_cycle_count_high)) << 32 | |
6284 | le32_to_cpu(bss_ch_info_ev.rx_bss_cycle_count_low); |
6285 | |
6286 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6287 | "pdev bss chan info:\n pdev_id: %d freq: %d noise: %d cycle: busy %llu total %llu tx %llu rx %llu rx_bss %llu\n" , |
6288 | bss_ch_info_ev.pdev_id, bss_ch_info_ev.freq, |
6289 | bss_ch_info_ev.noise_floor, busy, total, |
6290 | tx, rx, rx_bss); |
6291 | |
6292 | rcu_read_lock(); |
6293 | ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(bss_ch_info_ev.pdev_id)); |
6294 | |
6295 | if (!ar) { |
6296 | ath12k_warn(ab, fmt: "invalid pdev id %d in bss_chan_info event\n" , |
6297 | bss_ch_info_ev.pdev_id); |
6298 | rcu_read_unlock(); |
6299 | return; |
6300 | } |
6301 | |
6302 | spin_lock_bh(lock: &ar->data_lock); |
6303 | idx = freq_to_idx(ar, le32_to_cpu(bss_ch_info_ev.freq)); |
6304 | if (idx >= ARRAY_SIZE(ar->survey)) { |
6305 | ath12k_warn(ab, fmt: "bss chan info: invalid frequency %d (idx %d out of bounds)\n" , |
6306 | bss_ch_info_ev.freq, idx); |
6307 | goto exit; |
6308 | } |
6309 | |
6310 | survey = &ar->survey[idx]; |
6311 | |
6312 | survey->noise = le32_to_cpu(bss_ch_info_ev.noise_floor); |
6313 | survey->time = div_u64(dividend: total, divisor: cc_freq_hz); |
6314 | survey->time_busy = div_u64(dividend: busy, divisor: cc_freq_hz); |
6315 | survey->time_rx = div_u64(dividend: rx_bss, divisor: cc_freq_hz); |
6316 | survey->time_tx = div_u64(dividend: tx, divisor: cc_freq_hz); |
6317 | survey->filled |= (SURVEY_INFO_NOISE_DBM | |
6318 | SURVEY_INFO_TIME | |
6319 | SURVEY_INFO_TIME_BUSY | |
6320 | SURVEY_INFO_TIME_RX | |
6321 | SURVEY_INFO_TIME_TX); |
6322 | exit: |
6323 | spin_unlock_bh(lock: &ar->data_lock); |
6324 | complete(&ar->bss_survey_done); |
6325 | |
6326 | rcu_read_unlock(); |
6327 | } |
6328 | |
6329 | static void ath12k_vdev_install_key_compl_event(struct ath12k_base *ab, |
6330 | struct sk_buff *skb) |
6331 | { |
6332 | struct wmi_vdev_install_key_complete_arg install_key_compl = {0}; |
6333 | struct ath12k *ar; |
6334 | |
6335 | if (ath12k_pull_vdev_install_key_compl_ev(ab, skb, arg: &install_key_compl) != 0) { |
6336 | ath12k_warn(ab, fmt: "failed to extract install key compl event" ); |
6337 | return; |
6338 | } |
6339 | |
6340 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6341 | "vdev install key ev idx %d flags %08x macaddr %pM status %d\n" , |
6342 | install_key_compl.key_idx, install_key_compl.key_flags, |
6343 | install_key_compl.macaddr, install_key_compl.status); |
6344 | |
6345 | rcu_read_lock(); |
6346 | ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id: install_key_compl.vdev_id); |
6347 | if (!ar) { |
6348 | ath12k_warn(ab, fmt: "invalid vdev id in install key compl ev %d" , |
6349 | install_key_compl.vdev_id); |
6350 | rcu_read_unlock(); |
6351 | return; |
6352 | } |
6353 | |
6354 | ar->install_key_status = 0; |
6355 | |
6356 | if (install_key_compl.status != WMI_VDEV_INSTALL_KEY_COMPL_STATUS_SUCCESS) { |
6357 | ath12k_warn(ab, fmt: "install key failed for %pM status %d\n" , |
6358 | install_key_compl.macaddr, install_key_compl.status); |
6359 | ar->install_key_status = install_key_compl.status; |
6360 | } |
6361 | |
6362 | complete(&ar->install_key_done); |
6363 | rcu_read_unlock(); |
6364 | } |
6365 | |
6366 | static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, |
6367 | u16 tag, u16 len, |
6368 | const void *ptr, |
6369 | void *data) |
6370 | { |
6371 | const struct wmi_service_available_event *ev; |
6372 | u32 *wmi_ext2_service_bitmap; |
6373 | int i, j; |
6374 | u16 expected_len; |
6375 | |
6376 | expected_len = WMI_SERVICE_SEGMENT_BM_SIZE32 * sizeof(u32); |
6377 | if (len < expected_len) { |
6378 | ath12k_warn(ab, fmt: "invalid length %d for the WMI services available tag 0x%x\n" , |
6379 | len, tag); |
6380 | return -EINVAL; |
6381 | } |
6382 | |
6383 | switch (tag) { |
6384 | case WMI_TAG_SERVICE_AVAILABLE_EVENT: |
6385 | ev = (struct wmi_service_available_event *)ptr; |
6386 | for (i = 0, j = WMI_MAX_SERVICE; |
6387 | i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT_SERVICE; |
6388 | i++) { |
6389 | do { |
6390 | if (le32_to_cpu(ev->wmi_service_segment_bitmap[i]) & |
6391 | BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) |
6392 | set_bit(nr: j, addr: ab->wmi_ab.svc_map); |
6393 | } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); |
6394 | } |
6395 | |
6396 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6397 | "wmi_ext_service_bitmap 0x%x 0x%x 0x%x 0x%x" , |
6398 | ev->wmi_service_segment_bitmap[0], |
6399 | ev->wmi_service_segment_bitmap[1], |
6400 | ev->wmi_service_segment_bitmap[2], |
6401 | ev->wmi_service_segment_bitmap[3]); |
6402 | break; |
6403 | case WMI_TAG_ARRAY_UINT32: |
6404 | wmi_ext2_service_bitmap = (u32 *)ptr; |
6405 | for (i = 0, j = WMI_MAX_EXT_SERVICE; |
6406 | i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT2_SERVICE; |
6407 | i++) { |
6408 | do { |
6409 | if (wmi_ext2_service_bitmap[i] & |
6410 | BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) |
6411 | set_bit(nr: j, addr: ab->wmi_ab.svc_map); |
6412 | } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); |
6413 | } |
6414 | |
6415 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6416 | "wmi_ext2_service_bitmap 0x%04x 0x%04x 0x%04x 0x%04x" , |
6417 | wmi_ext2_service_bitmap[0], wmi_ext2_service_bitmap[1], |
6418 | wmi_ext2_service_bitmap[2], wmi_ext2_service_bitmap[3]); |
6419 | break; |
6420 | } |
6421 | return 0; |
6422 | } |
6423 | |
6424 | static int ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff *skb) |
6425 | { |
6426 | int ret; |
6427 | |
6428 | ret = ath12k_wmi_tlv_iter(ab, ptr: skb->data, len: skb->len, |
6429 | iter: ath12k_wmi_tlv_services_parser, |
6430 | NULL); |
6431 | return ret; |
6432 | } |
6433 | |
6434 | static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff *skb) |
6435 | { |
6436 | struct wmi_peer_assoc_conf_arg peer_assoc_conf = {0}; |
6437 | struct ath12k *ar; |
6438 | |
6439 | if (ath12k_pull_peer_assoc_conf_ev(ab, skb, peer_assoc_conf: &peer_assoc_conf) != 0) { |
6440 | ath12k_warn(ab, fmt: "failed to extract peer assoc conf event" ); |
6441 | return; |
6442 | } |
6443 | |
6444 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6445 | "peer assoc conf ev vdev id %d macaddr %pM\n" , |
6446 | peer_assoc_conf.vdev_id, peer_assoc_conf.macaddr); |
6447 | |
6448 | rcu_read_lock(); |
6449 | ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id: peer_assoc_conf.vdev_id); |
6450 | |
6451 | if (!ar) { |
6452 | ath12k_warn(ab, fmt: "invalid vdev id in peer assoc conf ev %d" , |
6453 | peer_assoc_conf.vdev_id); |
6454 | rcu_read_unlock(); |
6455 | return; |
6456 | } |
6457 | |
6458 | complete(&ar->peer_assoc_done); |
6459 | rcu_read_unlock(); |
6460 | } |
6461 | |
6462 | static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb) |
6463 | { |
6464 | } |
6465 | |
6466 | /* PDEV_CTL_FAILSAFE_CHECK_EVENT is received from FW when the frequency scanned |
6467 | * is not part of BDF CTL(Conformance test limits) table entries. |
6468 | */ |
6469 | static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab, |
6470 | struct sk_buff *skb) |
6471 | { |
6472 | const void **tb; |
6473 | const struct wmi_pdev_ctl_failsafe_chk_event *ev; |
6474 | int ret; |
6475 | |
6476 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6477 | if (IS_ERR(ptr: tb)) { |
6478 | ret = PTR_ERR(ptr: tb); |
6479 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
6480 | return; |
6481 | } |
6482 | |
6483 | ev = tb[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT]; |
6484 | if (!ev) { |
6485 | ath12k_warn(ab, fmt: "failed to fetch pdev ctl failsafe check ev" ); |
6486 | kfree(objp: tb); |
6487 | return; |
6488 | } |
6489 | |
6490 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6491 | "pdev ctl failsafe check ev status %d\n" , |
6492 | ev->ctl_failsafe_status); |
6493 | |
6494 | /* If ctl_failsafe_status is set to 1 FW will max out the Transmit power |
6495 | * to 10 dBm else the CTL power entry in the BDF would be picked up. |
6496 | */ |
6497 | if (ev->ctl_failsafe_status != 0) |
6498 | ath12k_warn(ab, fmt: "pdev ctl failsafe failure status %d" , |
6499 | ev->ctl_failsafe_status); |
6500 | |
6501 | kfree(objp: tb); |
6502 | } |
6503 | |
6504 | static void |
6505 | ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, |
6506 | const struct ath12k_wmi_pdev_csa_event *ev, |
6507 | const u32 *vdev_ids) |
6508 | { |
6509 | int i; |
6510 | struct ath12k_vif *arvif; |
6511 | |
6512 | /* Finish CSA once the switch count becomes NULL */ |
6513 | if (ev->current_switch_count) |
6514 | return; |
6515 | |
6516 | rcu_read_lock(); |
6517 | for (i = 0; i < le32_to_cpu(ev->num_vdevs); i++) { |
6518 | arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_id: vdev_ids[i]); |
6519 | |
6520 | if (!arvif) { |
6521 | ath12k_warn(ab, fmt: "Recvd csa status for unknown vdev %d" , |
6522 | vdev_ids[i]); |
6523 | continue; |
6524 | } |
6525 | |
6526 | if (arvif->is_up && arvif->vif->bss_conf.csa_active) |
6527 | ieee80211_csa_finish(vif: arvif->vif, link_id: 0); |
6528 | } |
6529 | rcu_read_unlock(); |
6530 | } |
6531 | |
6532 | static void |
6533 | ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab, |
6534 | struct sk_buff *skb) |
6535 | { |
6536 | const void **tb; |
6537 | const struct ath12k_wmi_pdev_csa_event *ev; |
6538 | const u32 *vdev_ids; |
6539 | int ret; |
6540 | |
6541 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6542 | if (IS_ERR(ptr: tb)) { |
6543 | ret = PTR_ERR(ptr: tb); |
6544 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
6545 | return; |
6546 | } |
6547 | |
6548 | ev = tb[WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT]; |
6549 | vdev_ids = tb[WMI_TAG_ARRAY_UINT32]; |
6550 | |
6551 | if (!ev || !vdev_ids) { |
6552 | ath12k_warn(ab, fmt: "failed to fetch pdev csa switch count ev" ); |
6553 | kfree(objp: tb); |
6554 | return; |
6555 | } |
6556 | |
6557 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6558 | "pdev csa switch count %d for pdev %d, num_vdevs %d" , |
6559 | ev->current_switch_count, ev->pdev_id, |
6560 | ev->num_vdevs); |
6561 | |
6562 | ath12k_wmi_process_csa_switch_count_event(ab, ev, vdev_ids); |
6563 | |
6564 | kfree(objp: tb); |
6565 | } |
6566 | |
6567 | static void |
6568 | ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff *skb) |
6569 | { |
6570 | const void **tb; |
6571 | const struct ath12k_wmi_pdev_radar_event *ev; |
6572 | struct ath12k *ar; |
6573 | int ret; |
6574 | |
6575 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6576 | if (IS_ERR(ptr: tb)) { |
6577 | ret = PTR_ERR(ptr: tb); |
6578 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
6579 | return; |
6580 | } |
6581 | |
6582 | ev = tb[WMI_TAG_PDEV_DFS_RADAR_DETECTION_EVENT]; |
6583 | |
6584 | if (!ev) { |
6585 | ath12k_warn(ab, fmt: "failed to fetch pdev dfs radar detected ev" ); |
6586 | kfree(objp: tb); |
6587 | return; |
6588 | } |
6589 | |
6590 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6591 | "pdev dfs radar detected on pdev %d, detection mode %d, chan freq %d, chan_width %d, detector id %d, seg id %d, timestamp %d, chirp %d, freq offset %d, sidx %d" , |
6592 | ev->pdev_id, ev->detection_mode, ev->chan_freq, ev->chan_width, |
6593 | ev->detector_id, ev->segment_id, ev->timestamp, ev->is_chirp, |
6594 | ev->freq_offset, ev->sidx); |
6595 | |
6596 | rcu_read_lock(); |
6597 | |
6598 | ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev->pdev_id)); |
6599 | |
6600 | if (!ar) { |
6601 | ath12k_warn(ab, fmt: "radar detected in invalid pdev %d\n" , |
6602 | ev->pdev_id); |
6603 | goto exit; |
6604 | } |
6605 | |
6606 | ath12k_dbg(ar->ab, ATH12K_DBG_REG, "DFS Radar Detected in pdev %d\n" , |
6607 | ev->pdev_id); |
6608 | |
6609 | if (ar->dfs_block_radar_events) |
6610 | ath12k_info(ab, fmt: "DFS Radar detected, but ignored as requested\n" ); |
6611 | else |
6612 | ieee80211_radar_detected(hw: ath12k_ar_to_hw(ar)); |
6613 | |
6614 | exit: |
6615 | rcu_read_unlock(); |
6616 | |
6617 | kfree(objp: tb); |
6618 | } |
6619 | |
6620 | static void |
6621 | ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, |
6622 | struct sk_buff *skb) |
6623 | { |
6624 | struct ath12k *ar; |
6625 | struct wmi_pdev_temperature_event ev = {0}; |
6626 | |
6627 | if (ath12k_pull_pdev_temp_ev(ab, skb, ev: &ev) != 0) { |
6628 | ath12k_warn(ab, fmt: "failed to extract pdev temperature event" ); |
6629 | return; |
6630 | } |
6631 | |
6632 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6633 | "pdev temperature ev temp %d pdev_id %d\n" , ev.temp, ev.pdev_id); |
6634 | |
6635 | rcu_read_lock(); |
6636 | |
6637 | ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev.pdev_id)); |
6638 | if (!ar) { |
6639 | ath12k_warn(ab, fmt: "invalid pdev id in pdev temperature ev %d" , ev.pdev_id); |
6640 | goto exit; |
6641 | } |
6642 | |
6643 | exit: |
6644 | rcu_read_unlock(); |
6645 | } |
6646 | |
6647 | static void ath12k_fils_discovery_event(struct ath12k_base *ab, |
6648 | struct sk_buff *skb) |
6649 | { |
6650 | const void **tb; |
6651 | const struct wmi_fils_discovery_event *ev; |
6652 | int ret; |
6653 | |
6654 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6655 | if (IS_ERR(ptr: tb)) { |
6656 | ret = PTR_ERR(ptr: tb); |
6657 | ath12k_warn(ab, |
6658 | fmt: "failed to parse FILS discovery event tlv %d\n" , |
6659 | ret); |
6660 | return; |
6661 | } |
6662 | |
6663 | ev = tb[WMI_TAG_HOST_SWFDA_EVENT]; |
6664 | if (!ev) { |
6665 | ath12k_warn(ab, fmt: "failed to fetch FILS discovery event\n" ); |
6666 | kfree(objp: tb); |
6667 | return; |
6668 | } |
6669 | |
6670 | ath12k_warn(ab, |
6671 | fmt: "FILS discovery frame expected from host for vdev_id: %u, transmission scheduled at %u, next TBTT: %u\n" , |
6672 | ev->vdev_id, ev->fils_tt, ev->tbtt); |
6673 | |
6674 | kfree(objp: tb); |
6675 | } |
6676 | |
6677 | static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, |
6678 | struct sk_buff *skb) |
6679 | { |
6680 | const void **tb; |
6681 | const struct wmi_probe_resp_tx_status_event *ev; |
6682 | int ret; |
6683 | |
6684 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6685 | if (IS_ERR(ptr: tb)) { |
6686 | ret = PTR_ERR(ptr: tb); |
6687 | ath12k_warn(ab, |
6688 | fmt: "failed to parse probe response transmission status event tlv: %d\n" , |
6689 | ret); |
6690 | return; |
6691 | } |
6692 | |
6693 | ev = tb[WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT]; |
6694 | if (!ev) { |
6695 | ath12k_warn(ab, |
6696 | fmt: "failed to fetch probe response transmission status event" ); |
6697 | kfree(objp: tb); |
6698 | return; |
6699 | } |
6700 | |
6701 | if (ev->tx_status) |
6702 | ath12k_warn(ab, |
6703 | fmt: "Probe response transmission failed for vdev_id %u, status %u\n" , |
6704 | ev->vdev_id, ev->tx_status); |
6705 | |
6706 | kfree(objp: tb); |
6707 | } |
6708 | |
6709 | static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, |
6710 | struct sk_buff *skb) |
6711 | { |
6712 | const void **tb; |
6713 | const struct wmi_p2p_noa_event *ev; |
6714 | const struct ath12k_wmi_p2p_noa_info *noa; |
6715 | struct ath12k *ar; |
6716 | int ret, vdev_id; |
6717 | |
6718 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6719 | if (IS_ERR(ptr: tb)) { |
6720 | ret = PTR_ERR(ptr: tb); |
6721 | ath12k_warn(ab, fmt: "failed to parse P2P NoA TLV: %d\n" , ret); |
6722 | return ret; |
6723 | } |
6724 | |
6725 | ev = tb[WMI_TAG_P2P_NOA_EVENT]; |
6726 | noa = tb[WMI_TAG_P2P_NOA_INFO]; |
6727 | |
6728 | if (!ev || !noa) { |
6729 | ret = -EPROTO; |
6730 | goto out; |
6731 | } |
6732 | |
6733 | vdev_id = __le32_to_cpu(ev->vdev_id); |
6734 | |
6735 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6736 | "wmi tlv p2p noa vdev_id %i descriptors %u\n" , |
6737 | vdev_id, le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)); |
6738 | |
6739 | rcu_read_lock(); |
6740 | ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); |
6741 | if (!ar) { |
6742 | ath12k_warn(ab, fmt: "invalid vdev id %d in P2P NoA event\n" , |
6743 | vdev_id); |
6744 | ret = -EINVAL; |
6745 | goto unlock; |
6746 | } |
6747 | |
6748 | ath12k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa); |
6749 | |
6750 | ret = 0; |
6751 | |
6752 | unlock: |
6753 | rcu_read_unlock(); |
6754 | out: |
6755 | kfree(objp: tb); |
6756 | return ret; |
6757 | } |
6758 | |
6759 | static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, |
6760 | struct sk_buff *skb) |
6761 | { |
6762 | const struct wmi_rfkill_state_change_event *ev; |
6763 | const void **tb; |
6764 | int ret; |
6765 | |
6766 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6767 | if (IS_ERR(ptr: tb)) { |
6768 | ret = PTR_ERR(ptr: tb); |
6769 | ath12k_warn(ab, fmt: "failed to parse tlv: %d\n" , ret); |
6770 | return; |
6771 | } |
6772 | |
6773 | ev = tb[WMI_TAG_RFKILL_EVENT]; |
6774 | if (!ev) { |
6775 | kfree(objp: tb); |
6776 | return; |
6777 | } |
6778 | |
6779 | ath12k_dbg(ab, ATH12K_DBG_MAC, |
6780 | "wmi tlv rfkill state change gpio %d type %d radio_state %d\n" , |
6781 | le32_to_cpu(ev->gpio_pin_num), |
6782 | le32_to_cpu(ev->int_type), |
6783 | le32_to_cpu(ev->radio_state)); |
6784 | |
6785 | spin_lock_bh(lock: &ab->base_lock); |
6786 | ab->rfkill_radio_on = (ev->radio_state == cpu_to_le32(WMI_RFKILL_RADIO_STATE_ON)); |
6787 | spin_unlock_bh(lock: &ab->base_lock); |
6788 | |
6789 | queue_work(wq: ab->workqueue, work: &ab->rfkill_work); |
6790 | kfree(objp: tb); |
6791 | } |
6792 | |
6793 | static void |
6794 | ath12k_wmi_diag_event(struct ath12k_base *ab, struct sk_buff *skb) |
6795 | { |
6796 | trace_ath12k_wmi_diag(ab, data: skb->data, len: skb->len); |
6797 | } |
6798 | |
6799 | static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab, |
6800 | struct sk_buff *skb) |
6801 | { |
6802 | const void **tb; |
6803 | const struct wmi_twt_enable_event *ev; |
6804 | int ret; |
6805 | |
6806 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6807 | if (IS_ERR(ptr: tb)) { |
6808 | ret = PTR_ERR(ptr: tb); |
6809 | ath12k_warn(ab, fmt: "failed to parse wmi twt enable status event tlv: %d\n" , |
6810 | ret); |
6811 | return; |
6812 | } |
6813 | |
6814 | ev = tb[WMI_TAG_TWT_ENABLE_COMPLETE_EVENT]; |
6815 | if (!ev) { |
6816 | ath12k_warn(ab, fmt: "failed to fetch twt enable wmi event\n" ); |
6817 | goto exit; |
6818 | } |
6819 | |
6820 | ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt enable event pdev id %u status %u\n" , |
6821 | le32_to_cpu(ev->pdev_id), |
6822 | le32_to_cpu(ev->status)); |
6823 | |
6824 | exit: |
6825 | kfree(objp: tb); |
6826 | } |
6827 | |
6828 | static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, |
6829 | struct sk_buff *skb) |
6830 | { |
6831 | const void **tb; |
6832 | const struct wmi_twt_disable_event *ev; |
6833 | int ret; |
6834 | |
6835 | tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); |
6836 | if (IS_ERR(ptr: tb)) { |
6837 | ret = PTR_ERR(ptr: tb); |
6838 | ath12k_warn(ab, fmt: "failed to parse wmi twt disable status event tlv: %d\n" , |
6839 | ret); |
6840 | return; |
6841 | } |
6842 | |
6843 | ev = tb[WMI_TAG_TWT_DISABLE_COMPLETE_EVENT]; |
6844 | if (!ev) { |
6845 | ath12k_warn(ab, fmt: "failed to fetch twt disable wmi event\n" ); |
6846 | goto exit; |
6847 | } |
6848 | |
6849 | ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt disable event pdev id %d status %u\n" , |
6850 | le32_to_cpu(ev->pdev_id), |
6851 | le32_to_cpu(ev->status)); |
6852 | |
6853 | exit: |
6854 | kfree(objp: tb); |
6855 | } |
6856 | |
6857 | static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) |
6858 | { |
6859 | struct wmi_cmd_hdr *cmd_hdr; |
6860 | enum wmi_tlv_event_id id; |
6861 | |
6862 | cmd_hdr = (struct wmi_cmd_hdr *)skb->data; |
6863 | id = le32_get_bits(v: cmd_hdr->cmd_id, WMI_CMD_HDR_CMD_ID); |
6864 | |
6865 | if (!skb_pull(skb, len: sizeof(struct wmi_cmd_hdr))) |
6866 | goto out; |
6867 | |
6868 | switch (id) { |
6869 | /* Process all the WMI events here */ |
6870 | case WMI_SERVICE_READY_EVENTID: |
6871 | ath12k_service_ready_event(ab, skb); |
6872 | break; |
6873 | case WMI_SERVICE_READY_EXT_EVENTID: |
6874 | ath12k_service_ready_ext_event(ab, skb); |
6875 | break; |
6876 | case WMI_SERVICE_READY_EXT2_EVENTID: |
6877 | ath12k_service_ready_ext2_event(ab, skb); |
6878 | break; |
6879 | case WMI_REG_CHAN_LIST_CC_EXT_EVENTID: |
6880 | ath12k_reg_chan_list_event(ab, skb); |
6881 | break; |
6882 | case WMI_READY_EVENTID: |
6883 | ath12k_ready_event(ab, skb); |
6884 | break; |
6885 | case WMI_PEER_DELETE_RESP_EVENTID: |
6886 | ath12k_peer_delete_resp_event(ab, skb); |
6887 | break; |
6888 | case WMI_VDEV_START_RESP_EVENTID: |
6889 | ath12k_vdev_start_resp_event(ab, skb); |
6890 | break; |
6891 | case WMI_OFFLOAD_BCN_TX_STATUS_EVENTID: |
6892 | ath12k_bcn_tx_status_event(ab, skb); |
6893 | break; |
6894 | case WMI_VDEV_STOPPED_EVENTID: |
6895 | ath12k_vdev_stopped_event(ab, skb); |
6896 | break; |
6897 | case WMI_MGMT_RX_EVENTID: |
6898 | ath12k_mgmt_rx_event(ab, skb); |
6899 | /* mgmt_rx_event() owns the skb now! */ |
6900 | return; |
6901 | case WMI_MGMT_TX_COMPLETION_EVENTID: |
6902 | ath12k_mgmt_tx_compl_event(ab, skb); |
6903 | break; |
6904 | case WMI_SCAN_EVENTID: |
6905 | ath12k_scan_event(ab, skb); |
6906 | break; |
6907 | case WMI_PEER_STA_KICKOUT_EVENTID: |
6908 | ath12k_peer_sta_kickout_event(ab, skb); |
6909 | break; |
6910 | case WMI_ROAM_EVENTID: |
6911 | ath12k_roam_event(ab, skb); |
6912 | break; |
6913 | case WMI_CHAN_INFO_EVENTID: |
6914 | ath12k_chan_info_event(ab, skb); |
6915 | break; |
6916 | case WMI_PDEV_BSS_CHAN_INFO_EVENTID: |
6917 | ath12k_pdev_bss_chan_info_event(ab, skb); |
6918 | break; |
6919 | case WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID: |
6920 | ath12k_vdev_install_key_compl_event(ab, skb); |
6921 | break; |
6922 | case WMI_SERVICE_AVAILABLE_EVENTID: |
6923 | ath12k_service_available_event(ab, skb); |
6924 | break; |
6925 | case WMI_PEER_ASSOC_CONF_EVENTID: |
6926 | ath12k_peer_assoc_conf_event(ab, skb); |
6927 | break; |
6928 | case WMI_UPDATE_STATS_EVENTID: |
6929 | ath12k_update_stats_event(ab, skb); |
6930 | break; |
6931 | case WMI_PDEV_CTL_FAILSAFE_CHECK_EVENTID: |
6932 | ath12k_pdev_ctl_failsafe_check_event(ab, skb); |
6933 | break; |
6934 | case WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID: |
6935 | ath12k_wmi_pdev_csa_switch_count_status_event(ab, skb); |
6936 | break; |
6937 | case WMI_PDEV_TEMPERATURE_EVENTID: |
6938 | ath12k_wmi_pdev_temperature_event(ab, skb); |
6939 | break; |
6940 | case WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID: |
6941 | ath12k_wmi_pdev_dma_ring_buf_release_event(ab, skb); |
6942 | break; |
6943 | case WMI_HOST_FILS_DISCOVERY_EVENTID: |
6944 | ath12k_fils_discovery_event(ab, skb); |
6945 | break; |
6946 | case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID: |
6947 | ath12k_probe_resp_tx_status_event(ab, skb); |
6948 | break; |
6949 | case WMI_RFKILL_STATE_CHANGE_EVENTID: |
6950 | ath12k_rfkill_state_change_event(ab, skb); |
6951 | break; |
6952 | case WMI_TWT_ENABLE_EVENTID: |
6953 | ath12k_wmi_twt_enable_event(ab, skb); |
6954 | break; |
6955 | case WMI_TWT_DISABLE_EVENTID: |
6956 | ath12k_wmi_twt_disable_event(ab, skb); |
6957 | break; |
6958 | case WMI_P2P_NOA_EVENTID: |
6959 | ath12k_wmi_p2p_noa_event(ab, skb); |
6960 | break; |
6961 | /* add Unsupported events here */ |
6962 | case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: |
6963 | case WMI_PEER_OPER_MODE_CHANGE_EVENTID: |
6964 | case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: |
6965 | ath12k_dbg(ab, ATH12K_DBG_WMI, |
6966 | "ignoring unsupported event 0x%x\n" , id); |
6967 | break; |
6968 | case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID: |
6969 | ath12k_wmi_pdev_dfs_radar_detected_event(ab, skb); |
6970 | break; |
6971 | case WMI_VDEV_DELETE_RESP_EVENTID: |
6972 | ath12k_vdev_delete_resp_event(ab, skb); |
6973 | break; |
6974 | case WMI_DIAG_EVENTID: |
6975 | ath12k_wmi_diag_event(ab, skb); |
6976 | break; |
6977 | /* TODO: Add remaining events */ |
6978 | default: |
6979 | ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n" , id); |
6980 | break; |
6981 | } |
6982 | |
6983 | out: |
6984 | dev_kfree_skb(skb); |
6985 | } |
6986 | |
6987 | static int ath12k_connect_pdev_htc_service(struct ath12k_base *ab, |
6988 | u32 pdev_idx) |
6989 | { |
6990 | int status; |
6991 | u32 svc_id[] = { ATH12K_HTC_SVC_ID_WMI_CONTROL, |
6992 | ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1, |
6993 | ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2 }; |
6994 | struct ath12k_htc_svc_conn_req conn_req = {}; |
6995 | struct ath12k_htc_svc_conn_resp conn_resp = {}; |
6996 | |
6997 | /* these fields are the same for all service endpoints */ |
6998 | conn_req.ep_ops.ep_tx_complete = ath12k_wmi_htc_tx_complete; |
6999 | conn_req.ep_ops.ep_rx_complete = ath12k_wmi_op_rx; |
7000 | conn_req.ep_ops.ep_tx_credits = ath12k_wmi_op_ep_tx_credits; |
7001 | |
7002 | /* connect to control service */ |
7003 | conn_req.service_id = svc_id[pdev_idx]; |
7004 | |
7005 | status = ath12k_htc_connect_service(htc: &ab->htc, conn_req: &conn_req, conn_resp: &conn_resp); |
7006 | if (status) { |
7007 | ath12k_warn(ab, fmt: "failed to connect to WMI CONTROL service status: %d\n" , |
7008 | status); |
7009 | return status; |
7010 | } |
7011 | |
7012 | ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid; |
7013 | ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid; |
7014 | ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len; |
7015 | |
7016 | return 0; |
7017 | } |
7018 | |
7019 | static int |
7020 | ath12k_wmi_send_unit_test_cmd(struct ath12k *ar, |
7021 | struct wmi_unit_test_cmd ut_cmd, |
7022 | u32 *test_args) |
7023 | { |
7024 | struct ath12k_wmi_pdev *wmi = ar->wmi; |
7025 | struct wmi_unit_test_cmd *cmd; |
7026 | struct sk_buff *skb; |
7027 | struct wmi_tlv *tlv; |
7028 | void *ptr; |
7029 | u32 *ut_cmd_args; |
7030 | int buf_len, arg_len; |
7031 | int ret; |
7032 | int i; |
7033 | |
7034 | arg_len = sizeof(u32) * le32_to_cpu(ut_cmd.num_args); |
7035 | buf_len = sizeof(ut_cmd) + arg_len + TLV_HDR_SIZE; |
7036 | |
7037 | skb = ath12k_wmi_alloc_skb(wmi_ab: wmi->wmi_ab, len: buf_len); |
7038 | if (!skb) |
7039 | return -ENOMEM; |
7040 | |
7041 | cmd = (struct wmi_unit_test_cmd *)skb->data; |
7042 | cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(cmd: WMI_TAG_UNIT_TEST_CMD, |
7043 | len: sizeof(ut_cmd)); |
7044 | |
7045 | cmd->vdev_id = ut_cmd.vdev_id; |
7046 | cmd->module_id = ut_cmd.module_id; |
7047 | cmd->num_args = ut_cmd.num_args; |
7048 | cmd->diag_token = ut_cmd.diag_token; |
7049 | |
7050 | ptr = skb->data + sizeof(ut_cmd); |
7051 | |
7052 | tlv = ptr; |
7053 | tlv->header = ath12k_wmi_tlv_hdr(cmd: WMI_TAG_ARRAY_UINT32, len: arg_len); |
7054 | |
7055 | ptr += TLV_HDR_SIZE; |
7056 | |
7057 | ut_cmd_args = ptr; |
7058 | for (i = 0; i < le32_to_cpu(ut_cmd.num_args); i++) |
7059 | ut_cmd_args[i] = test_args[i]; |
7060 | |
7061 | ath12k_dbg(ar->ab, ATH12K_DBG_WMI, |
7062 | "WMI unit test : module %d vdev %d n_args %d token %d\n" , |
7063 | cmd->module_id, cmd->vdev_id, cmd->num_args, |
7064 | cmd->diag_token); |
7065 | |
7066 | ret = ath12k_wmi_cmd_send(wmi, skb, cmd_id: WMI_UNIT_TEST_CMDID); |
7067 | |
7068 | if (ret) { |
7069 | ath12k_warn(ab: ar->ab, fmt: "failed to send WMI_UNIT_TEST CMD :%d\n" , |
7070 | ret); |
7071 | dev_kfree_skb(skb); |
7072 | } |
7073 | |
7074 | return ret; |
7075 | } |
7076 | |
7077 | int ath12k_wmi_simulate_radar(struct ath12k *ar) |
7078 | { |
7079 | struct ath12k_vif *arvif; |
7080 | u32 dfs_args[DFS_MAX_TEST_ARGS]; |
7081 | struct wmi_unit_test_cmd wmi_ut; |
7082 | bool arvif_found = false; |
7083 | |
7084 | list_for_each_entry(arvif, &ar->arvifs, list) { |
7085 | if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) { |
7086 | arvif_found = true; |
7087 | break; |
7088 | } |
7089 | } |
7090 | |
7091 | if (!arvif_found) |
7092 | return -EINVAL; |
7093 | |
7094 | dfs_args[DFS_TEST_CMDID] = 0; |
7095 | dfs_args[DFS_TEST_PDEV_ID] = ar->pdev->pdev_id; |
7096 | /* Currently we could pass segment_id(b0 - b1), chirp(b2) |
7097 | * freq offset (b3 - b10) to unit test. For simulation |
7098 | * purpose this can be set to 0 which is valid. |
7099 | */ |
7100 | dfs_args[DFS_TEST_RADAR_PARAM] = 0; |
7101 | |
7102 | wmi_ut.vdev_id = cpu_to_le32(arvif->vdev_id); |
7103 | wmi_ut.module_id = cpu_to_le32(DFS_UNIT_TEST_MODULE); |
7104 | wmi_ut.num_args = cpu_to_le32(DFS_MAX_TEST_ARGS); |
7105 | wmi_ut.diag_token = cpu_to_le32(DFS_UNIT_TEST_TOKEN); |
7106 | |
7107 | ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Triggering Radar Simulation\n" ); |
7108 | |
7109 | return ath12k_wmi_send_unit_test_cmd(ar, ut_cmd: wmi_ut, test_args: dfs_args); |
7110 | } |
7111 | |
7112 | int ath12k_wmi_connect(struct ath12k_base *ab) |
7113 | { |
7114 | u32 i; |
7115 | u8 wmi_ep_count; |
7116 | |
7117 | wmi_ep_count = ab->htc.wmi_ep_count; |
7118 | if (wmi_ep_count > ab->hw_params->max_radios) |
7119 | return -1; |
7120 | |
7121 | for (i = 0; i < wmi_ep_count; i++) |
7122 | ath12k_connect_pdev_htc_service(ab, pdev_idx: i); |
7123 | |
7124 | return 0; |
7125 | } |
7126 | |
7127 | static void ath12k_wmi_pdev_detach(struct ath12k_base *ab, u8 pdev_id) |
7128 | { |
7129 | if (WARN_ON(pdev_id >= MAX_RADIOS)) |
7130 | return; |
7131 | |
7132 | /* TODO: Deinit any pdev specific wmi resource */ |
7133 | } |
7134 | |
7135 | int ath12k_wmi_pdev_attach(struct ath12k_base *ab, |
7136 | u8 pdev_id) |
7137 | { |
7138 | struct ath12k_wmi_pdev *wmi_handle; |
7139 | |
7140 | if (pdev_id >= ab->hw_params->max_radios) |
7141 | return -EINVAL; |
7142 | |
7143 | wmi_handle = &ab->wmi_ab.wmi[pdev_id]; |
7144 | |
7145 | wmi_handle->wmi_ab = &ab->wmi_ab; |
7146 | |
7147 | ab->wmi_ab.ab = ab; |
7148 | /* TODO: Init remaining resource specific to pdev */ |
7149 | |
7150 | return 0; |
7151 | } |
7152 | |
7153 | int ath12k_wmi_attach(struct ath12k_base *ab) |
7154 | { |
7155 | int ret; |
7156 | |
7157 | ret = ath12k_wmi_pdev_attach(ab, pdev_id: 0); |
7158 | if (ret) |
7159 | return ret; |
7160 | |
7161 | ab->wmi_ab.ab = ab; |
7162 | ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_MAX; |
7163 | |
7164 | /* It's overwritten when service_ext_ready is handled */ |
7165 | if (ab->hw_params->single_pdev_only) |
7166 | ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_SINGLE; |
7167 | |
7168 | /* TODO: Init remaining wmi soc resources required */ |
7169 | init_completion(x: &ab->wmi_ab.service_ready); |
7170 | init_completion(x: &ab->wmi_ab.unified_ready); |
7171 | |
7172 | return 0; |
7173 | } |
7174 | |
7175 | void ath12k_wmi_detach(struct ath12k_base *ab) |
7176 | { |
7177 | int i; |
7178 | |
7179 | /* TODO: Deinit wmi resource specific to SOC as required */ |
7180 | |
7181 | for (i = 0; i < ab->htc.wmi_ep_count; i++) |
7182 | ath12k_wmi_pdev_detach(ab, pdev_id: i); |
7183 | |
7184 | ath12k_wmi_free_dbring_caps(ab); |
7185 | } |
7186 | |