Path: blob/main/sys/contrib/dev/athk/ath12k/wmi.c
106180 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.4*/5#include <linux/skbuff.h>6#include <linux/ctype.h>7#include <net/mac80211.h>8#include <net/cfg80211.h>9#include <linux/completion.h>10#include <linux/if_ether.h>11#include <linux/types.h>12#include <linux/pci.h>13#include <linux/uuid.h>14#include <linux/time.h>15#include <linux/of.h>16#include "core.h"17#include "debug.h"18#include "mac.h"19#include "hw.h"20#include "peer.h"2122struct ath12k_wmi_svc_ready_parse {23bool wmi_svc_bitmap_done;24};2526struct ath12k_wmi_dma_ring_caps_parse {27struct ath12k_wmi_dma_ring_caps_params *dma_ring_caps;28u32 n_dma_ring_caps;29};3031struct ath12k_wmi_service_ext_arg {32u32 default_conc_scan_config_bits;33u32 default_fw_config_bits;34struct ath12k_wmi_ppe_threshold_arg ppet;35u32 he_cap_info;36u32 mpdu_density;37u32 max_bssid_rx_filters;38u32 num_hw_modes;39u32 num_phy;40};4142struct ath12k_wmi_svc_rdy_ext_parse {43struct ath12k_wmi_service_ext_arg arg;44const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps;45const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps;46u32 n_hw_mode_caps;47u32 tot_phy_id;48struct ath12k_wmi_hw_mode_cap_params pref_hw_mode_caps;49struct ath12k_wmi_mac_phy_caps_params *mac_phy_caps;50u32 n_mac_phy_caps;51const struct ath12k_wmi_soc_hal_reg_caps_params *soc_hal_reg_caps;52const struct ath12k_wmi_hal_reg_caps_ext_params *ext_hal_reg_caps;53u32 n_ext_hal_reg_caps;54struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse;55bool hw_mode_done;56bool mac_phy_done;57bool ext_hal_reg_done;58bool mac_phy_chainmask_combo_done;59bool mac_phy_chainmask_cap_done;60bool oem_dma_ring_cap_done;61bool dma_ring_cap_done;62};6364struct ath12k_wmi_svc_rdy_ext2_arg {65u32 reg_db_version;66u32 hw_min_max_tx_power_2ghz;67u32 hw_min_max_tx_power_5ghz;68u32 chwidth_num_peer_caps;69u32 preamble_puncture_bw;70u32 max_user_per_ppdu_ofdma;71u32 max_user_per_ppdu_mumimo;72u32 target_cap_flags;73u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE];74u32 max_num_linkview_peers;75u32 max_num_msduq_supported_per_tid;76u32 default_num_msduq_supported_per_tid;77};7879struct ath12k_wmi_svc_rdy_ext2_parse {80struct ath12k_wmi_svc_rdy_ext2_arg arg;81struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse;82bool dma_ring_cap_done;83bool spectral_bin_scaling_done;84bool mac_phy_caps_ext_done;85};8687struct ath12k_wmi_rdy_parse {88u32 num_extra_mac_addr;89};9091struct ath12k_wmi_dma_buf_release_arg {92struct ath12k_wmi_dma_buf_release_fixed_params fixed;93const struct ath12k_wmi_dma_buf_release_entry_params *buf_entry;94const struct ath12k_wmi_dma_buf_release_meta_data_params *meta_data;95u32 num_buf_entry;96u32 num_meta;97bool buf_entry_done;98bool meta_data_done;99};100101struct ath12k_wmi_tlv_policy {102size_t min_len;103};104105struct wmi_tlv_mgmt_rx_parse {106const struct ath12k_wmi_mgmt_rx_params *fixed;107const u8 *frame_buf;108bool frame_buf_done;109};110111static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {112[WMI_TAG_ARRAY_BYTE] = { .min_len = 0 },113[WMI_TAG_ARRAY_UINT32] = { .min_len = 0 },114[WMI_TAG_SERVICE_READY_EVENT] = {115.min_len = sizeof(struct wmi_service_ready_event) },116[WMI_TAG_SERVICE_READY_EXT_EVENT] = {117.min_len = sizeof(struct wmi_service_ready_ext_event) },118[WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS] = {119.min_len = sizeof(struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params) },120[WMI_TAG_SOC_HAL_REG_CAPABILITIES] = {121.min_len = sizeof(struct ath12k_wmi_soc_hal_reg_caps_params) },122[WMI_TAG_VDEV_START_RESPONSE_EVENT] = {123.min_len = sizeof(struct wmi_vdev_start_resp_event) },124[WMI_TAG_PEER_DELETE_RESP_EVENT] = {125.min_len = sizeof(struct wmi_peer_delete_resp_event) },126[WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT] = {127.min_len = sizeof(struct wmi_bcn_tx_status_event) },128[WMI_TAG_VDEV_STOPPED_EVENT] = {129.min_len = sizeof(struct wmi_vdev_stopped_event) },130[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT] = {131.min_len = sizeof(struct wmi_reg_chan_list_cc_ext_event) },132[WMI_TAG_MGMT_RX_HDR] = {133.min_len = sizeof(struct ath12k_wmi_mgmt_rx_params) },134[WMI_TAG_MGMT_TX_COMPL_EVENT] = {135.min_len = sizeof(struct wmi_mgmt_tx_compl_event) },136[WMI_TAG_SCAN_EVENT] = {137.min_len = sizeof(struct wmi_scan_event) },138[WMI_TAG_PEER_STA_KICKOUT_EVENT] = {139.min_len = sizeof(struct wmi_peer_sta_kickout_event) },140[WMI_TAG_ROAM_EVENT] = {141.min_len = sizeof(struct wmi_roam_event) },142[WMI_TAG_CHAN_INFO_EVENT] = {143.min_len = sizeof(struct wmi_chan_info_event) },144[WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT] = {145.min_len = sizeof(struct wmi_pdev_bss_chan_info_event) },146[WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT] = {147.min_len = sizeof(struct wmi_vdev_install_key_compl_event) },148[WMI_TAG_READY_EVENT] = {149.min_len = sizeof(struct ath12k_wmi_ready_event_min_params) },150[WMI_TAG_SERVICE_AVAILABLE_EVENT] = {151.min_len = sizeof(struct wmi_service_available_event) },152[WMI_TAG_PEER_ASSOC_CONF_EVENT] = {153.min_len = sizeof(struct wmi_peer_assoc_conf_event) },154[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = {155.min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },156[WMI_TAG_HOST_SWFDA_EVENT] = {157.min_len = sizeof(struct wmi_fils_discovery_event) },158[WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT] = {159.min_len = sizeof(struct wmi_probe_resp_tx_status_event) },160[WMI_TAG_VDEV_DELETE_RESP_EVENT] = {161.min_len = sizeof(struct wmi_vdev_delete_resp_event) },162};163164static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)165{166return le32_encode_bits(cmd, WMI_TLV_TAG) |167le32_encode_bits(len, WMI_TLV_LEN);168}169170static __le32 ath12k_wmi_tlv_cmd_hdr(u32 cmd, u32 len)171{172return ath12k_wmi_tlv_hdr(cmd, len - TLV_HDR_SIZE);173}174175void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,176struct ath12k_wmi_resource_config_arg *config)177{178config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS;179180if (ab->num_radios == 2) {181config->num_peers = TARGET_NUM_PEERS(DBS);182config->num_tids = TARGET_NUM_TIDS(DBS);183} else if (ab->num_radios == 3) {184config->num_peers = TARGET_NUM_PEERS(DBS_SBS);185config->num_tids = TARGET_NUM_TIDS(DBS_SBS);186} else {187/* Control should not reach here */188config->num_peers = TARGET_NUM_PEERS(SINGLE);189config->num_tids = TARGET_NUM_TIDS(SINGLE);190}191config->num_offload_peers = TARGET_NUM_OFFLD_PEERS;192config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;193config->num_peer_keys = TARGET_NUM_PEER_KEYS;194config->ast_skid_limit = TARGET_AST_SKID_LIMIT;195config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;196config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;197config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;198config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;199config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;200config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;201202if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))203config->rx_decap_mode = TARGET_DECAP_MODE_RAW;204else205config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;206207config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;208config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;209config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;210config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;211config->num_mcast_groups = TARGET_NUM_MCAST_GROUPS;212config->num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS;213config->mcast2ucast_mode = TARGET_MCAST2UCAST_MODE;214config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;215config->num_wds_entries = TARGET_NUM_WDS_ENTRIES;216config->dma_burst_size = TARGET_DMA_BURST_SIZE;217config->rx_skip_defrag_timeout_dup_detection_check =218TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;219config->vow_config = TARGET_VOW_CONFIG;220config->gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV;221config->num_msdu_desc = TARGET_NUM_MSDU_DESC;222config->beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD;223config->rx_batchmode = TARGET_RX_BATCHMODE;224/* Indicates host supports peer map v3 and unmap v2 support */225config->peer_map_unmap_version = 0x32;226config->twt_ap_pdev_count = ab->num_radios;227config->twt_ap_sta_count = 1000;228}229230void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,231struct ath12k_wmi_resource_config_arg *config)232{233config->num_vdevs = 4;234config->num_peers = 16;235config->num_tids = 32;236237config->num_offload_peers = 3;238config->num_offload_reorder_buffs = 3;239config->num_peer_keys = TARGET_NUM_PEER_KEYS;240config->ast_skid_limit = TARGET_AST_SKID_LIMIT;241config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;242config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;243config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;244config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;245config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;246config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;247config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;248config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;249config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;250config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;251config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;252config->num_mcast_groups = 0;253config->num_mcast_table_elems = 0;254config->mcast2ucast_mode = 0;255config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;256config->num_wds_entries = 0;257config->dma_burst_size = 0;258config->rx_skip_defrag_timeout_dup_detection_check = 0;259config->vow_config = TARGET_VOW_CONFIG;260config->gtk_offload_max_vdev = 2;261config->num_msdu_desc = 0x400;262config->beacon_tx_offload_max_vdev = 2;263config->rx_batchmode = TARGET_RX_BATCHMODE;264265config->peer_map_unmap_version = 0x1;266config->use_pdev_id = 1;267config->max_frag_entries = 0xa;268config->num_tdls_vdevs = 0x1;269config->num_tdls_conn_table_entries = 8;270config->beacon_tx_offload_max_vdev = 0x2;271config->num_multicast_filter_entries = 0x20;272config->num_wow_filters = 0x16;273config->num_keep_alive_pattern = 0;274}275276#define PRIMAP(_hw_mode_) \277[_hw_mode_] = _hw_mode_##_PRI278279static const int ath12k_hw_mode_pri_map[] = {280PRIMAP(WMI_HOST_HW_MODE_SINGLE),281PRIMAP(WMI_HOST_HW_MODE_DBS),282PRIMAP(WMI_HOST_HW_MODE_SBS_PASSIVE),283PRIMAP(WMI_HOST_HW_MODE_SBS),284PRIMAP(WMI_HOST_HW_MODE_DBS_SBS),285PRIMAP(WMI_HOST_HW_MODE_DBS_OR_SBS),286/* keep last */287PRIMAP(WMI_HOST_HW_MODE_MAX),288};289290static int291#if defined(__linux__)292ath12k_wmi_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,293#elif defined(__FreeBSD__)294ath12k_wmi_tlv_iter(struct ath12k_base *ab, const u8 *ptr, size_t len,295#endif296int (*iter)(struct ath12k_base *ab, u16 tag, u16 len,297const void *ptr, void *data),298void *data)299{300#if defined(__linux__)301const void *begin = ptr;302#elif defined(__FreeBSD__)303const u8 *begin = ptr;304#endif305const struct wmi_tlv *tlv;306u16 tlv_tag, tlv_len;307int ret;308309while (len > 0) {310if (len < sizeof(*tlv)) {311ath12k_err(ab, "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",312ptr - begin, len, sizeof(*tlv));313return -EINVAL;314}315316#if defined(__linux__)317tlv = ptr;318#elif defined(__FreeBSD__)319tlv = (const void *)ptr;320#endif321tlv_tag = le32_get_bits(tlv->header, WMI_TLV_TAG);322tlv_len = le32_get_bits(tlv->header, WMI_TLV_LEN);323ptr += sizeof(*tlv);324len -= sizeof(*tlv);325326if (tlv_len > len) {327ath12k_err(ab, "wmi tlv parse failure of tag %u at byte %zd (%zu bytes left, %u expected)\n",328tlv_tag, ptr - begin, len, tlv_len);329return -EINVAL;330}331332if (tlv_tag < ARRAY_SIZE(ath12k_wmi_tlv_policies) &&333ath12k_wmi_tlv_policies[tlv_tag].min_len &&334ath12k_wmi_tlv_policies[tlv_tag].min_len > tlv_len) {335ath12k_err(ab, "wmi tlv parse failure of tag %u at byte %zd (%u bytes is less than min length %zu)\n",336tlv_tag, ptr - begin, tlv_len,337ath12k_wmi_tlv_policies[tlv_tag].min_len);338return -EINVAL;339}340341ret = iter(ab, tlv_tag, tlv_len, ptr, data);342if (ret)343return ret;344345ptr += tlv_len;346len -= tlv_len;347}348349return 0;350}351352static int ath12k_wmi_tlv_iter_parse(struct ath12k_base *ab, u16 tag, u16 len,353const void *ptr, void *data)354{355const void **tb = data;356357if (tag < WMI_TAG_MAX)358tb[tag] = ptr;359360return 0;361}362363static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb,364const void *ptr, size_t len)365{366return ath12k_wmi_tlv_iter(ar, ptr, len, ath12k_wmi_tlv_iter_parse,367(void *)tb);368}369370static const void **371ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr,372size_t len, gfp_t gfp)373{374const void **tb;375int ret;376377tb = kcalloc(WMI_TAG_MAX, sizeof(*tb), gfp);378if (!tb)379return ERR_PTR(-ENOMEM);380381ret = ath12k_wmi_tlv_parse(ab, tb, ptr, len);382if (ret) {383kfree(tb);384return ERR_PTR(ret);385}386387return tb;388}389390static int ath12k_wmi_cmd_send_nowait(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,391u32 cmd_id)392{393struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);394struct ath12k_base *ab = wmi->wmi_ab->ab;395struct wmi_cmd_hdr *cmd_hdr;396int ret;397398if (!skb_push(skb, sizeof(struct wmi_cmd_hdr)))399return -ENOMEM;400401cmd_hdr = (struct wmi_cmd_hdr *)skb->data;402cmd_hdr->cmd_id = le32_encode_bits(cmd_id, WMI_CMD_HDR_CMD_ID);403404memset(skb_cb, 0, sizeof(*skb_cb));405ret = ath12k_htc_send(&ab->htc, wmi->eid, skb);406407if (ret)408goto err_pull;409410return 0;411412err_pull:413skb_pull(skb, sizeof(struct wmi_cmd_hdr));414return ret;415}416417int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,418u32 cmd_id)419{420struct ath12k_wmi_base *wmi_sc = wmi->wmi_ab;421int ret = -EOPNOTSUPP;422423might_sleep();424425wait_event_timeout(wmi_sc->tx_credits_wq, ({426ret = ath12k_wmi_cmd_send_nowait(wmi, skb, cmd_id);427428if (ret && test_bit(ATH12K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags))429ret = -ESHUTDOWN;430431(ret != -EAGAIN);432}), WMI_SEND_TIMEOUT_HZ);433434if (ret == -EAGAIN)435ath12k_warn(wmi_sc->ab, "wmi command %d timeout\n", cmd_id);436437return ret;438}439440static int ath12k_pull_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,441const void *ptr,442struct ath12k_wmi_service_ext_arg *arg)443{444const struct wmi_service_ready_ext_event *ev = ptr;445int i;446447if (!ev)448return -EINVAL;449450/* Move this to host based bitmap */451arg->default_conc_scan_config_bits =452le32_to_cpu(ev->default_conc_scan_config_bits);453arg->default_fw_config_bits = le32_to_cpu(ev->default_fw_config_bits);454arg->he_cap_info = le32_to_cpu(ev->he_cap_info);455arg->mpdu_density = le32_to_cpu(ev->mpdu_density);456arg->max_bssid_rx_filters = le32_to_cpu(ev->max_bssid_rx_filters);457arg->ppet.numss_m1 = le32_to_cpu(ev->ppet.numss_m1);458arg->ppet.ru_bit_mask = le32_to_cpu(ev->ppet.ru_info);459460for (i = 0; i < WMI_MAX_NUM_SS; i++)461arg->ppet.ppet16_ppet8_ru3_ru0[i] =462le32_to_cpu(ev->ppet.ppet16_ppet8_ru3_ru0[i]);463464return 0;465}466467static int468ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,469struct ath12k_wmi_svc_rdy_ext_parse *svc,470u8 hw_mode_id, u8 phy_id,471struct ath12k_pdev *pdev)472{473const struct ath12k_wmi_mac_phy_caps_params *mac_caps;474const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps = svc->hw_caps;475const struct ath12k_wmi_hw_mode_cap_params *wmi_hw_mode_caps = svc->hw_mode_caps;476const struct ath12k_wmi_mac_phy_caps_params *wmi_mac_phy_caps = svc->mac_phy_caps;477struct ath12k_base *ab = wmi_handle->wmi_ab->ab;478struct ath12k_band_cap *cap_band;479struct ath12k_pdev_cap *pdev_cap = &pdev->cap;480struct ath12k_fw_pdev *fw_pdev;481u32 phy_map;482u32 hw_idx, phy_idx = 0;483int i;484485if (!hw_caps || !wmi_hw_mode_caps || !svc->soc_hal_reg_caps)486return -EINVAL;487488for (hw_idx = 0; hw_idx < le32_to_cpu(hw_caps->num_hw_modes); hw_idx++) {489if (hw_mode_id == le32_to_cpu(wmi_hw_mode_caps[hw_idx].hw_mode_id))490break;491492phy_map = le32_to_cpu(wmi_hw_mode_caps[hw_idx].phy_id_map);493phy_idx = fls(phy_map);494}495496if (hw_idx == le32_to_cpu(hw_caps->num_hw_modes))497return -EINVAL;498499phy_idx += phy_id;500if (phy_id >= le32_to_cpu(svc->soc_hal_reg_caps->num_phy))501return -EINVAL;502503mac_caps = wmi_mac_phy_caps + phy_idx;504505pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id);506pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands);507pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density);508509fw_pdev = &ab->fw_pdev[ab->fw_pdev_count];510fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands);511fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id);512fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id);513ab->fw_pdev_count++;514515/* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from516* band to band for a single radio, need to see how this should be517* handled.518*/519if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2G_CAP) {520pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_2g);521pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_2g);522} else if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5G_CAP) {523pdev_cap->vht_cap = le32_to_cpu(mac_caps->vht_cap_info_5g);524pdev_cap->vht_mcs = le32_to_cpu(mac_caps->vht_supp_mcs_5g);525pdev_cap->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g);526pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_5g);527pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_5g);528} else {529return -EINVAL;530}531532/* tx/rx chainmask reported from fw depends on the actual hw chains used,533* For example, for 4x4 capable macphys, first 4 chains can be used for first534* mac and the remaining 4 chains can be used for the second mac or vice-versa.535* In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0536* will be advertised for second mac or vice-versa. Compute the shift value537* for tx/rx chainmask which will be used to advertise supported ht/vht rates to538* mac80211.539*/540pdev_cap->tx_chain_mask_shift =541find_first_bit((unsigned long *)&pdev_cap->tx_chain_mask, 32);542pdev_cap->rx_chain_mask_shift =543find_first_bit((unsigned long *)&pdev_cap->rx_chain_mask, 32);544545if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_2G_CAP) {546cap_band = &pdev_cap->band[NL80211_BAND_2GHZ];547cap_band->phy_id = le32_to_cpu(mac_caps->phy_id);548cap_band->max_bw_supported = le32_to_cpu(mac_caps->max_bw_supported_2g);549cap_band->ht_cap_info = le32_to_cpu(mac_caps->ht_cap_info_2g);550cap_band->he_cap_info[0] = le32_to_cpu(mac_caps->he_cap_info_2g);551cap_band->he_cap_info[1] = le32_to_cpu(mac_caps->he_cap_info_2g_ext);552cap_band->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_2g);553for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++)554cap_band->he_cap_phy_info[i] =555le32_to_cpu(mac_caps->he_cap_phy_info_2g[i]);556557cap_band->he_ppet.numss_m1 = le32_to_cpu(mac_caps->he_ppet2g.numss_m1);558cap_band->he_ppet.ru_bit_mask = le32_to_cpu(mac_caps->he_ppet2g.ru_info);559560for (i = 0; i < WMI_MAX_NUM_SS; i++)561cap_band->he_ppet.ppet16_ppet8_ru3_ru0[i] =562le32_to_cpu(mac_caps->he_ppet2g.ppet16_ppet8_ru3_ru0[i]);563}564565if (le32_to_cpu(mac_caps->supported_bands) & WMI_HOST_WLAN_5G_CAP) {566cap_band = &pdev_cap->band[NL80211_BAND_5GHZ];567cap_band->phy_id = le32_to_cpu(mac_caps->phy_id);568cap_band->max_bw_supported =569le32_to_cpu(mac_caps->max_bw_supported_5g);570cap_band->ht_cap_info = le32_to_cpu(mac_caps->ht_cap_info_5g);571cap_band->he_cap_info[0] = le32_to_cpu(mac_caps->he_cap_info_5g);572cap_band->he_cap_info[1] = le32_to_cpu(mac_caps->he_cap_info_5g_ext);573cap_band->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g);574for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++)575cap_band->he_cap_phy_info[i] =576le32_to_cpu(mac_caps->he_cap_phy_info_5g[i]);577578cap_band->he_ppet.numss_m1 = le32_to_cpu(mac_caps->he_ppet5g.numss_m1);579cap_band->he_ppet.ru_bit_mask = le32_to_cpu(mac_caps->he_ppet5g.ru_info);580581for (i = 0; i < WMI_MAX_NUM_SS; i++)582cap_band->he_ppet.ppet16_ppet8_ru3_ru0[i] =583le32_to_cpu(mac_caps->he_ppet5g.ppet16_ppet8_ru3_ru0[i]);584585cap_band = &pdev_cap->band[NL80211_BAND_6GHZ];586cap_band->max_bw_supported =587le32_to_cpu(mac_caps->max_bw_supported_5g);588cap_band->ht_cap_info = le32_to_cpu(mac_caps->ht_cap_info_5g);589cap_band->he_cap_info[0] = le32_to_cpu(mac_caps->he_cap_info_5g);590cap_band->he_cap_info[1] = le32_to_cpu(mac_caps->he_cap_info_5g_ext);591cap_band->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g);592for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++)593cap_band->he_cap_phy_info[i] =594le32_to_cpu(mac_caps->he_cap_phy_info_5g[i]);595596cap_band->he_ppet.numss_m1 = le32_to_cpu(mac_caps->he_ppet5g.numss_m1);597cap_band->he_ppet.ru_bit_mask = le32_to_cpu(mac_caps->he_ppet5g.ru_info);598599for (i = 0; i < WMI_MAX_NUM_SS; i++)600cap_band->he_ppet.ppet16_ppet8_ru3_ru0[i] =601le32_to_cpu(mac_caps->he_ppet5g.ppet16_ppet8_ru3_ru0[i]);602}603604return 0;605}606607static int608ath12k_pull_reg_cap_svc_rdy_ext(struct ath12k_wmi_pdev *wmi_handle,609const struct ath12k_wmi_soc_hal_reg_caps_params *reg_caps,610const struct ath12k_wmi_hal_reg_caps_ext_params *ext_caps,611u8 phy_idx,612struct ath12k_wmi_hal_reg_capabilities_ext_arg *param)613{614const struct ath12k_wmi_hal_reg_caps_ext_params *ext_reg_cap;615616if (!reg_caps || !ext_caps)617return -EINVAL;618619if (phy_idx >= le32_to_cpu(reg_caps->num_phy))620return -EINVAL;621622ext_reg_cap = &ext_caps[phy_idx];623624param->phy_id = le32_to_cpu(ext_reg_cap->phy_id);625param->eeprom_reg_domain = le32_to_cpu(ext_reg_cap->eeprom_reg_domain);626param->eeprom_reg_domain_ext =627le32_to_cpu(ext_reg_cap->eeprom_reg_domain_ext);628param->regcap1 = le32_to_cpu(ext_reg_cap->regcap1);629param->regcap2 = le32_to_cpu(ext_reg_cap->regcap2);630/* check if param->wireless_mode is needed */631param->low_2ghz_chan = le32_to_cpu(ext_reg_cap->low_2ghz_chan);632param->high_2ghz_chan = le32_to_cpu(ext_reg_cap->high_2ghz_chan);633param->low_5ghz_chan = le32_to_cpu(ext_reg_cap->low_5ghz_chan);634param->high_5ghz_chan = le32_to_cpu(ext_reg_cap->high_5ghz_chan);635636return 0;637}638639static int ath12k_pull_service_ready_tlv(struct ath12k_base *ab,640const void *evt_buf,641struct ath12k_wmi_target_cap_arg *cap)642{643const struct wmi_service_ready_event *ev = evt_buf;644645if (!ev) {646ath12k_err(ab, "%s: failed by NULL param\n",647__func__);648return -EINVAL;649}650651cap->phy_capability = le32_to_cpu(ev->phy_capability);652cap->max_frag_entry = le32_to_cpu(ev->max_frag_entry);653cap->num_rf_chains = le32_to_cpu(ev->num_rf_chains);654cap->ht_cap_info = le32_to_cpu(ev->ht_cap_info);655cap->vht_cap_info = le32_to_cpu(ev->vht_cap_info);656cap->vht_supp_mcs = le32_to_cpu(ev->vht_supp_mcs);657cap->hw_min_tx_power = le32_to_cpu(ev->hw_min_tx_power);658cap->hw_max_tx_power = le32_to_cpu(ev->hw_max_tx_power);659cap->sys_cap_info = le32_to_cpu(ev->sys_cap_info);660cap->min_pkt_size_enable = le32_to_cpu(ev->min_pkt_size_enable);661cap->max_bcn_ie_size = le32_to_cpu(ev->max_bcn_ie_size);662cap->max_num_scan_channels = le32_to_cpu(ev->max_num_scan_channels);663cap->max_supported_macs = le32_to_cpu(ev->max_supported_macs);664cap->wmi_fw_sub_feat_caps = le32_to_cpu(ev->wmi_fw_sub_feat_caps);665cap->txrx_chainmask = le32_to_cpu(ev->txrx_chainmask);666cap->default_dbs_hw_mode_index = le32_to_cpu(ev->default_dbs_hw_mode_index);667cap->num_msdu_desc = le32_to_cpu(ev->num_msdu_desc);668669return 0;670}671672/* Save the wmi_service_bitmap into a linear bitmap. The wmi_services in673* wmi_service ready event are advertised in b0-b3 (LSB 4-bits) of each674* 4-byte word.675*/676static void ath12k_wmi_service_bitmap_copy(struct ath12k_wmi_pdev *wmi,677const u32 *wmi_svc_bm)678{679int i, j;680681for (i = 0, j = 0; i < WMI_SERVICE_BM_SIZE && j < WMI_MAX_SERVICE; i++) {682do {683if (wmi_svc_bm[i] & BIT(j % WMI_SERVICE_BITS_IN_SIZE32))684set_bit(j, wmi->wmi_ab->svc_map);685} while (++j % WMI_SERVICE_BITS_IN_SIZE32);686}687}688689static int ath12k_wmi_svc_rdy_parse(struct ath12k_base *ab, u16 tag, u16 len,690const void *ptr, void *data)691{692struct ath12k_wmi_svc_ready_parse *svc_ready = data;693struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0];694u16 expect_len;695696switch (tag) {697case WMI_TAG_SERVICE_READY_EVENT:698if (ath12k_pull_service_ready_tlv(ab, ptr, &ab->target_caps))699return -EINVAL;700break;701702case WMI_TAG_ARRAY_UINT32:703if (!svc_ready->wmi_svc_bitmap_done) {704expect_len = WMI_SERVICE_BM_SIZE * sizeof(u32);705if (len < expect_len) {706ath12k_warn(ab, "invalid len %d for the tag 0x%x\n",707len, tag);708return -EINVAL;709}710711ath12k_wmi_service_bitmap_copy(wmi_handle, ptr);712713svc_ready->wmi_svc_bitmap_done = true;714}715break;716default:717break;718}719720return 0;721}722723static int ath12k_service_ready_event(struct ath12k_base *ab, struct sk_buff *skb)724{725struct ath12k_wmi_svc_ready_parse svc_ready = { };726int ret;727728ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,729ath12k_wmi_svc_rdy_parse,730&svc_ready);731if (ret) {732ath12k_warn(ab, "failed to parse tlv %d\n", ret);733return ret;734}735736return 0;737}738739struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len)740{741struct sk_buff *skb;742struct ath12k_base *ab = wmi_sc->ab;743u32 round_len = roundup(len, 4);744745skb = ath12k_htc_alloc_skb(ab, WMI_SKB_HEADROOM + round_len);746if (!skb)747return NULL;748749skb_reserve(skb, WMI_SKB_HEADROOM);750if (!IS_ALIGNED((unsigned long)skb->data, 4))751ath12k_warn(ab, "unaligned WMI skb data\n");752753skb_put(skb, round_len);754memset(skb->data, 0, round_len);755756return skb;757}758759int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id,760struct sk_buff *frame)761{762struct ath12k_wmi_pdev *wmi = ar->wmi;763struct wmi_mgmt_send_cmd *cmd;764struct wmi_tlv *frame_tlv;765struct sk_buff *skb;766u32 buf_len;767int ret, len;768769buf_len = min_t(int, frame->len, WMI_MGMT_SEND_DOWNLD_LEN);770771len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4);772773skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);774if (!skb)775return -ENOMEM;776777cmd = (struct wmi_mgmt_send_cmd *)skb->data;778cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MGMT_TX_SEND_CMD,779sizeof(*cmd));780cmd->vdev_id = cpu_to_le32(vdev_id);781cmd->desc_id = cpu_to_le32(buf_id);782cmd->chanfreq = 0;783cmd->paddr_lo = cpu_to_le32(lower_32_bits(ATH12K_SKB_CB(frame)->paddr));784cmd->paddr_hi = cpu_to_le32(upper_32_bits(ATH12K_SKB_CB(frame)->paddr));785cmd->frame_len = cpu_to_le32(frame->len);786cmd->buf_len = cpu_to_le32(buf_len);787cmd->tx_params_valid = 0;788789frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));790frame_tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, buf_len);791792memcpy(frame_tlv->value, frame->data, buf_len);793794ret = ath12k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID);795if (ret) {796ath12k_warn(ar->ab,797"failed to submit WMI_MGMT_TX_SEND_CMDID cmd\n");798dev_kfree_skb(skb);799}800801return ret;802}803804int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr,805struct ath12k_wmi_vdev_create_arg *args)806{807struct ath12k_wmi_pdev *wmi = ar->wmi;808struct wmi_vdev_create_cmd *cmd;809struct sk_buff *skb;810struct ath12k_wmi_vdev_txrx_streams_params *txrx_streams;811struct wmi_tlv *tlv;812int ret, len;813#if defined(__linux__)814void *ptr;815#elif defined(__FreeBSD__)816u8 *ptr;817#endif818819/* It can be optimized my sending tx/rx chain configuration820* only for supported bands instead of always sending it for821* both the bands.822*/823len = sizeof(*cmd) + TLV_HDR_SIZE +824(WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams));825826skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);827if (!skb)828return -ENOMEM;829830cmd = (struct wmi_vdev_create_cmd *)skb->data;831cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_CREATE_CMD,832sizeof(*cmd));833834cmd->vdev_id = cpu_to_le32(args->if_id);835cmd->vdev_type = cpu_to_le32(args->type);836cmd->vdev_subtype = cpu_to_le32(args->subtype);837cmd->num_cfg_txrx_streams = cpu_to_le32(WMI_NUM_SUPPORTED_BAND_MAX);838cmd->pdev_id = cpu_to_le32(args->pdev_id);839cmd->vdev_stats_id = cpu_to_le32(args->if_stats_id);840ether_addr_copy(cmd->vdev_macaddr.addr, macaddr);841842ptr = skb->data + sizeof(*cmd);843len = WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams);844845#if defined(__linux__)846tlv = ptr;847#elif defined(__FreeBSD__)848tlv = (void *)ptr;849#endif850tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);851852ptr += TLV_HDR_SIZE;853#if defined(__linux__)854txrx_streams = ptr;855#elif defined(__FreeBSD__)856txrx_streams = (void *)ptr;857#endif858len = sizeof(*txrx_streams);859txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_TXRX_STREAMS,860len);861txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G;862txrx_streams->supported_tx_streams =863args->chains[NL80211_BAND_2GHZ].tx;864txrx_streams->supported_rx_streams =865args->chains[NL80211_BAND_2GHZ].rx;866867txrx_streams++;868txrx_streams->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_TXRX_STREAMS,869len);870txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G;871txrx_streams->supported_tx_streams =872args->chains[NL80211_BAND_5GHZ].tx;873txrx_streams->supported_rx_streams =874args->chains[NL80211_BAND_5GHZ].rx;875876ath12k_dbg(ar->ab, ATH12K_DBG_WMI,877"WMI vdev create: id %d type %d subtype %d macaddr %pM pdevid %d\n",878args->if_id, args->type, args->subtype,879macaddr, args->pdev_id);880881ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_CREATE_CMDID);882if (ret) {883ath12k_warn(ar->ab,884"failed to submit WMI_VDEV_CREATE_CMDID\n");885dev_kfree_skb(skb);886}887888return ret;889}890891int ath12k_wmi_vdev_delete(struct ath12k *ar, u8 vdev_id)892{893struct ath12k_wmi_pdev *wmi = ar->wmi;894struct wmi_vdev_delete_cmd *cmd;895struct sk_buff *skb;896int ret;897898skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));899if (!skb)900return -ENOMEM;901902cmd = (struct wmi_vdev_delete_cmd *)skb->data;903cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_DELETE_CMD,904sizeof(*cmd));905cmd->vdev_id = cpu_to_le32(vdev_id);906907ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI vdev delete id %d\n", vdev_id);908909ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_DELETE_CMDID);910if (ret) {911ath12k_warn(ar->ab, "failed to submit WMI_VDEV_DELETE_CMDID\n");912dev_kfree_skb(skb);913}914915return ret;916}917918int ath12k_wmi_vdev_stop(struct ath12k *ar, u8 vdev_id)919{920struct ath12k_wmi_pdev *wmi = ar->wmi;921struct wmi_vdev_stop_cmd *cmd;922struct sk_buff *skb;923int ret;924925skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));926if (!skb)927return -ENOMEM;928929cmd = (struct wmi_vdev_stop_cmd *)skb->data;930931cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_STOP_CMD,932sizeof(*cmd));933cmd->vdev_id = cpu_to_le32(vdev_id);934935ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI vdev stop id 0x%x\n", vdev_id);936937ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_STOP_CMDID);938if (ret) {939ath12k_warn(ar->ab, "failed to submit WMI_VDEV_STOP cmd\n");940dev_kfree_skb(skb);941}942943return ret;944}945946int ath12k_wmi_vdev_down(struct ath12k *ar, u8 vdev_id)947{948struct ath12k_wmi_pdev *wmi = ar->wmi;949struct wmi_vdev_down_cmd *cmd;950struct sk_buff *skb;951int ret;952953skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));954if (!skb)955return -ENOMEM;956957cmd = (struct wmi_vdev_down_cmd *)skb->data;958959cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_DOWN_CMD,960sizeof(*cmd));961cmd->vdev_id = cpu_to_le32(vdev_id);962963ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "WMI vdev down id 0x%x\n", vdev_id);964965ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_DOWN_CMDID);966if (ret) {967ath12k_warn(ar->ab, "failed to submit WMI_VDEV_DOWN cmd\n");968dev_kfree_skb(skb);969}970971return ret;972}973974static void ath12k_wmi_put_wmi_channel(struct ath12k_wmi_channel_params *chan,975struct wmi_vdev_start_req_arg *arg)976{977memset(chan, 0, sizeof(*chan));978979chan->mhz = cpu_to_le32(arg->freq);980chan->band_center_freq1 = cpu_to_le32(arg->band_center_freq1);981if (arg->mode == MODE_11AC_VHT80_80)982chan->band_center_freq2 = cpu_to_le32(arg->band_center_freq2);983else984chan->band_center_freq2 = 0;985986chan->info |= le32_encode_bits(arg->mode, WMI_CHAN_INFO_MODE);987if (arg->passive)988chan->info |= cpu_to_le32(WMI_CHAN_INFO_PASSIVE);989if (arg->allow_ibss)990chan->info |= cpu_to_le32(WMI_CHAN_INFO_ADHOC_ALLOWED);991if (arg->allow_ht)992chan->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HT);993if (arg->allow_vht)994chan->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_VHT);995if (arg->allow_he)996chan->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HE);997if (arg->ht40plus)998chan->info |= cpu_to_le32(WMI_CHAN_INFO_HT40_PLUS);999if (arg->chan_radar)1000chan->info |= cpu_to_le32(WMI_CHAN_INFO_DFS);1001if (arg->freq2_radar)1002chan->info |= cpu_to_le32(WMI_CHAN_INFO_DFS_FREQ2);10031004chan->reg_info_1 = le32_encode_bits(arg->max_power,1005WMI_CHAN_REG_INFO1_MAX_PWR) |1006le32_encode_bits(arg->max_reg_power,1007WMI_CHAN_REG_INFO1_MAX_REG_PWR);10081009chan->reg_info_2 = le32_encode_bits(arg->max_antenna_gain,1010WMI_CHAN_REG_INFO2_ANT_MAX) |1011le32_encode_bits(arg->max_power, WMI_CHAN_REG_INFO2_MAX_TX_PWR);1012}10131014int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,1015bool restart)1016{1017struct ath12k_wmi_pdev *wmi = ar->wmi;1018struct wmi_vdev_start_request_cmd *cmd;1019struct sk_buff *skb;1020struct ath12k_wmi_channel_params *chan;1021struct wmi_tlv *tlv;1022#if defined(__linux__)1023void *ptr;1024#elif defined(__FreeBSD__)1025u8 *ptr;1026#endif1027int ret, len;10281029if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))1030return -EINVAL;10311032len = sizeof(*cmd) + sizeof(*chan) + TLV_HDR_SIZE;10331034skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);1035if (!skb)1036return -ENOMEM;10371038cmd = (struct wmi_vdev_start_request_cmd *)skb->data;1039cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_START_REQUEST_CMD,1040sizeof(*cmd));1041cmd->vdev_id = cpu_to_le32(arg->vdev_id);1042cmd->beacon_interval = cpu_to_le32(arg->bcn_intval);1043cmd->bcn_tx_rate = cpu_to_le32(arg->bcn_tx_rate);1044cmd->dtim_period = cpu_to_le32(arg->dtim_period);1045cmd->num_noa_descriptors = cpu_to_le32(arg->num_noa_descriptors);1046cmd->preferred_rx_streams = cpu_to_le32(arg->pref_rx_streams);1047cmd->preferred_tx_streams = cpu_to_le32(arg->pref_tx_streams);1048cmd->cac_duration_ms = cpu_to_le32(arg->cac_duration_ms);1049cmd->regdomain = cpu_to_le32(arg->regdomain);1050cmd->he_ops = cpu_to_le32(arg->he_ops);1051cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap);10521053if (!restart) {1054if (arg->ssid) {1055cmd->ssid.ssid_len = cpu_to_le32(arg->ssid_len);1056memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);1057}1058if (arg->hidden_ssid)1059cmd->flags |= cpu_to_le32(WMI_VDEV_START_HIDDEN_SSID);1060if (arg->pmf_enabled)1061cmd->flags |= cpu_to_le32(WMI_VDEV_START_PMF_ENABLED);1062}10631064cmd->flags |= cpu_to_le32(WMI_VDEV_START_LDPC_RX_ENABLED);10651066ptr = skb->data + sizeof(*cmd);1067#if defined(__linux__)1068chan = ptr;1069#elif defined(__FreeBSD__)1070chan = (void *)ptr;1071#endif10721073ath12k_wmi_put_wmi_channel(chan, arg);10741075chan->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_CHANNEL,1076sizeof(*chan));1077ptr += sizeof(*chan);10781079#if defined(__linux__)1080tlv = ptr;1081#elif defined(__FreeBSD__)1082tlv = (void *)ptr;1083#endif1084tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, 0);10851086/* Note: This is a nested TLV containing:1087* [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv]..1088*/10891090ptr += sizeof(*tlv);10911092ath12k_dbg(ar->ab, ATH12K_DBG_WMI, "vdev %s id 0x%x freq 0x%x mode 0x%x\n",1093restart ? "restart" : "start", arg->vdev_id,1094arg->freq, arg->mode);10951096if (restart)1097ret = ath12k_wmi_cmd_send(wmi, skb,1098WMI_VDEV_RESTART_REQUEST_CMDID);1099else1100ret = ath12k_wmi_cmd_send(wmi, skb,1101WMI_VDEV_START_REQUEST_CMDID);1102if (ret) {1103ath12k_warn(ar->ab, "failed to submit vdev_%s cmd\n",1104restart ? "restart" : "start");1105dev_kfree_skb(skb);1106}11071108return ret;1109}11101111int ath12k_wmi_vdev_up(struct ath12k *ar, u32 vdev_id, u32 aid, const u8 *bssid)1112{1113struct ath12k_wmi_pdev *wmi = ar->wmi;1114struct wmi_vdev_up_cmd *cmd;1115struct sk_buff *skb;1116int ret;11171118skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1119if (!skb)1120return -ENOMEM;11211122cmd = (struct wmi_vdev_up_cmd *)skb->data;11231124cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_UP_CMD,1125sizeof(*cmd));1126cmd->vdev_id = cpu_to_le32(vdev_id);1127cmd->vdev_assoc_id = cpu_to_le32(aid);11281129ether_addr_copy(cmd->vdev_bssid.addr, bssid);11301131ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1132"WMI mgmt vdev up id 0x%x assoc id %d bssid %pM\n",1133vdev_id, aid, bssid);11341135ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_UP_CMDID);1136if (ret) {1137ath12k_warn(ar->ab, "failed to submit WMI_VDEV_UP cmd\n");1138dev_kfree_skb(skb);1139}11401141return ret;1142}11431144int ath12k_wmi_send_peer_create_cmd(struct ath12k *ar,1145struct ath12k_wmi_peer_create_arg *arg)1146{1147struct ath12k_wmi_pdev *wmi = ar->wmi;1148struct wmi_peer_create_cmd *cmd;1149struct sk_buff *skb;1150int ret;11511152skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1153if (!skb)1154return -ENOMEM;11551156cmd = (struct wmi_peer_create_cmd *)skb->data;1157cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PEER_CREATE_CMD,1158sizeof(*cmd));11591160ether_addr_copy(cmd->peer_macaddr.addr, arg->peer_addr);1161cmd->peer_type = cpu_to_le32(arg->peer_type);1162cmd->vdev_id = cpu_to_le32(arg->vdev_id);11631164ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1165"WMI peer create vdev_id %d peer_addr %pM\n",1166arg->vdev_id, arg->peer_addr);11671168ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_CREATE_CMDID);1169if (ret) {1170ath12k_warn(ar->ab, "failed to submit WMI_PEER_CREATE cmd\n");1171dev_kfree_skb(skb);1172}11731174return ret;1175}11761177int ath12k_wmi_send_peer_delete_cmd(struct ath12k *ar,1178const u8 *peer_addr, u8 vdev_id)1179{1180struct ath12k_wmi_pdev *wmi = ar->wmi;1181struct wmi_peer_delete_cmd *cmd;1182struct sk_buff *skb;1183int ret;11841185skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1186if (!skb)1187return -ENOMEM;11881189cmd = (struct wmi_peer_delete_cmd *)skb->data;1190cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PEER_DELETE_CMD,1191sizeof(*cmd));11921193ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);1194cmd->vdev_id = cpu_to_le32(vdev_id);11951196ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1197"WMI peer delete vdev_id %d peer_addr %pM\n",1198vdev_id, peer_addr);11991200ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_DELETE_CMDID);1201if (ret) {1202ath12k_warn(ar->ab, "failed to send WMI_PEER_DELETE cmd\n");1203dev_kfree_skb(skb);1204}12051206return ret;1207}12081209int ath12k_wmi_send_pdev_set_regdomain(struct ath12k *ar,1210struct ath12k_wmi_pdev_set_regdomain_arg *arg)1211{1212struct ath12k_wmi_pdev *wmi = ar->wmi;1213struct wmi_pdev_set_regdomain_cmd *cmd;1214struct sk_buff *skb;1215int ret;12161217skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1218if (!skb)1219return -ENOMEM;12201221cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data;1222cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_REGDOMAIN_CMD,1223sizeof(*cmd));12241225cmd->reg_domain = cpu_to_le32(arg->current_rd_in_use);1226cmd->reg_domain_2g = cpu_to_le32(arg->current_rd_2g);1227cmd->reg_domain_5g = cpu_to_le32(arg->current_rd_5g);1228cmd->conformance_test_limit_2g = cpu_to_le32(arg->ctl_2g);1229cmd->conformance_test_limit_5g = cpu_to_le32(arg->ctl_5g);1230cmd->dfs_domain = cpu_to_le32(arg->dfs_domain);1231cmd->pdev_id = cpu_to_le32(arg->pdev_id);12321233ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1234"WMI pdev regd rd %d rd2g %d rd5g %d domain %d pdev id %d\n",1235arg->current_rd_in_use, arg->current_rd_2g,1236arg->current_rd_5g, arg->dfs_domain, arg->pdev_id);12371238ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_REGDOMAIN_CMDID);1239if (ret) {1240ath12k_warn(ar->ab,1241"failed to send WMI_PDEV_SET_REGDOMAIN cmd\n");1242dev_kfree_skb(skb);1243}12441245return ret;1246}12471248int ath12k_wmi_set_peer_param(struct ath12k *ar, const u8 *peer_addr,1249u32 vdev_id, u32 param_id, u32 param_val)1250{1251struct ath12k_wmi_pdev *wmi = ar->wmi;1252struct wmi_peer_set_param_cmd *cmd;1253struct sk_buff *skb;1254int ret;12551256skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1257if (!skb)1258return -ENOMEM;12591260cmd = (struct wmi_peer_set_param_cmd *)skb->data;1261cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PEER_SET_PARAM_CMD,1262sizeof(*cmd));1263ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);1264cmd->vdev_id = cpu_to_le32(vdev_id);1265cmd->param_id = cpu_to_le32(param_id);1266cmd->param_value = cpu_to_le32(param_val);12671268ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1269"WMI vdev %d peer 0x%pM set param %d value %d\n",1270vdev_id, peer_addr, param_id, param_val);12711272ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_SET_PARAM_CMDID);1273if (ret) {1274ath12k_warn(ar->ab, "failed to send WMI_PEER_SET_PARAM cmd\n");1275dev_kfree_skb(skb);1276}12771278return ret;1279}12801281int ath12k_wmi_send_peer_flush_tids_cmd(struct ath12k *ar,1282u8 peer_addr[ETH_ALEN],1283u32 peer_tid_bitmap,1284u8 vdev_id)1285{1286struct ath12k_wmi_pdev *wmi = ar->wmi;1287struct wmi_peer_flush_tids_cmd *cmd;1288struct sk_buff *skb;1289int ret;12901291skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1292if (!skb)1293return -ENOMEM;12941295cmd = (struct wmi_peer_flush_tids_cmd *)skb->data;1296cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PEER_FLUSH_TIDS_CMD,1297sizeof(*cmd));12981299ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);1300cmd->peer_tid_bitmap = cpu_to_le32(peer_tid_bitmap);1301cmd->vdev_id = cpu_to_le32(vdev_id);13021303ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1304"WMI peer flush vdev_id %d peer_addr %pM tids %08x\n",1305vdev_id, peer_addr, peer_tid_bitmap);13061307ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_FLUSH_TIDS_CMDID);1308if (ret) {1309ath12k_warn(ar->ab,1310"failed to send WMI_PEER_FLUSH_TIDS cmd\n");1311dev_kfree_skb(skb);1312}13131314return ret;1315}13161317int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,1318int vdev_id, const u8 *addr,1319dma_addr_t paddr, u8 tid,1320u8 ba_window_size_valid,1321u32 ba_window_size)1322{1323struct wmi_peer_reorder_queue_setup_cmd *cmd;1324struct sk_buff *skb;1325int ret;13261327skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));1328if (!skb)1329return -ENOMEM;13301331cmd = (struct wmi_peer_reorder_queue_setup_cmd *)skb->data;1332cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_REORDER_QUEUE_SETUP_CMD,1333sizeof(*cmd));13341335ether_addr_copy(cmd->peer_macaddr.addr, addr);1336cmd->vdev_id = cpu_to_le32(vdev_id);1337cmd->tid = cpu_to_le32(tid);1338cmd->queue_ptr_lo = cpu_to_le32(lower_32_bits(paddr));1339cmd->queue_ptr_hi = cpu_to_le32(upper_32_bits(paddr));1340cmd->queue_no = cpu_to_le32(tid);1341cmd->ba_window_size_valid = cpu_to_le32(ba_window_size_valid);1342cmd->ba_window_size = cpu_to_le32(ba_window_size);13431344ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1345"wmi rx reorder queue setup addr %pM vdev_id %d tid %d\n",1346addr, vdev_id, tid);13471348ret = ath12k_wmi_cmd_send(ar->wmi, skb,1349WMI_PEER_REORDER_QUEUE_SETUP_CMDID);1350if (ret) {1351ath12k_warn(ar->ab,1352"failed to send WMI_PEER_REORDER_QUEUE_SETUP\n");1353dev_kfree_skb(skb);1354}13551356return ret;1357}13581359int1360ath12k_wmi_rx_reord_queue_remove(struct ath12k *ar,1361struct ath12k_wmi_rx_reorder_queue_remove_arg *arg)1362{1363struct ath12k_wmi_pdev *wmi = ar->wmi;1364struct wmi_peer_reorder_queue_remove_cmd *cmd;1365struct sk_buff *skb;1366int ret;13671368skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1369if (!skb)1370return -ENOMEM;13711372cmd = (struct wmi_peer_reorder_queue_remove_cmd *)skb->data;1373cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_REORDER_QUEUE_REMOVE_CMD,1374sizeof(*cmd));13751376ether_addr_copy(cmd->peer_macaddr.addr, arg->peer_macaddr);1377cmd->vdev_id = cpu_to_le32(arg->vdev_id);1378cmd->tid_mask = cpu_to_le32(arg->peer_tid_bitmap);13791380ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1381"%s: peer_macaddr %pM vdev_id %d, tid_map %d", __func__,1382arg->peer_macaddr, arg->vdev_id, arg->peer_tid_bitmap);13831384ret = ath12k_wmi_cmd_send(wmi, skb,1385WMI_PEER_REORDER_QUEUE_REMOVE_CMDID);1386if (ret) {1387ath12k_warn(ar->ab,1388"failed to send WMI_PEER_REORDER_QUEUE_REMOVE_CMDID");1389dev_kfree_skb(skb);1390}13911392return ret;1393}13941395int ath12k_wmi_pdev_set_param(struct ath12k *ar, u32 param_id,1396u32 param_value, u8 pdev_id)1397{1398struct ath12k_wmi_pdev *wmi = ar->wmi;1399struct wmi_pdev_set_param_cmd *cmd;1400struct sk_buff *skb;1401int ret;14021403skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1404if (!skb)1405return -ENOMEM;14061407cmd = (struct wmi_pdev_set_param_cmd *)skb->data;1408cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_PARAM_CMD,1409sizeof(*cmd));1410cmd->pdev_id = cpu_to_le32(pdev_id);1411cmd->param_id = cpu_to_le32(param_id);1412cmd->param_value = cpu_to_le32(param_value);14131414ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1415"WMI pdev set param %d pdev id %d value %d\n",1416param_id, pdev_id, param_value);14171418ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PDEV_SET_PARAM_CMDID);1419if (ret) {1420ath12k_warn(ar->ab, "failed to send WMI_PDEV_SET_PARAM cmd\n");1421dev_kfree_skb(skb);1422}14231424return ret;1425}14261427int ath12k_wmi_pdev_set_ps_mode(struct ath12k *ar, int vdev_id, u32 enable)1428{1429struct ath12k_wmi_pdev *wmi = ar->wmi;1430struct wmi_pdev_set_ps_mode_cmd *cmd;1431struct sk_buff *skb;1432int ret;14331434skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1435if (!skb)1436return -ENOMEM;14371438cmd = (struct wmi_pdev_set_ps_mode_cmd *)skb->data;1439cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_STA_POWERSAVE_MODE_CMD,1440sizeof(*cmd));1441cmd->vdev_id = cpu_to_le32(vdev_id);1442cmd->sta_ps_mode = cpu_to_le32(enable);14431444ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1445"WMI vdev set psmode %d vdev id %d\n",1446enable, vdev_id);14471448ret = ath12k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_MODE_CMDID);1449if (ret) {1450ath12k_warn(ar->ab, "failed to send WMI_PDEV_SET_PARAM cmd\n");1451dev_kfree_skb(skb);1452}14531454return ret;1455}14561457int ath12k_wmi_pdev_suspend(struct ath12k *ar, u32 suspend_opt,1458u32 pdev_id)1459{1460struct ath12k_wmi_pdev *wmi = ar->wmi;1461struct wmi_pdev_suspend_cmd *cmd;1462struct sk_buff *skb;1463int ret;14641465skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1466if (!skb)1467return -ENOMEM;14681469cmd = (struct wmi_pdev_suspend_cmd *)skb->data;14701471cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SUSPEND_CMD,1472sizeof(*cmd));14731474cmd->suspend_opt = cpu_to_le32(suspend_opt);1475cmd->pdev_id = cpu_to_le32(pdev_id);14761477ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1478"WMI pdev suspend pdev_id %d\n", pdev_id);14791480ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PDEV_SUSPEND_CMDID);1481if (ret) {1482ath12k_warn(ar->ab, "failed to send WMI_PDEV_SUSPEND cmd\n");1483dev_kfree_skb(skb);1484}14851486return ret;1487}14881489int ath12k_wmi_pdev_resume(struct ath12k *ar, u32 pdev_id)1490{1491struct ath12k_wmi_pdev *wmi = ar->wmi;1492struct wmi_pdev_resume_cmd *cmd;1493struct sk_buff *skb;1494int ret;14951496skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1497if (!skb)1498return -ENOMEM;14991500cmd = (struct wmi_pdev_resume_cmd *)skb->data;15011502cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_RESUME_CMD,1503sizeof(*cmd));1504cmd->pdev_id = cpu_to_le32(pdev_id);15051506ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1507"WMI pdev resume pdev id %d\n", pdev_id);15081509ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PDEV_RESUME_CMDID);1510if (ret) {1511ath12k_warn(ar->ab, "failed to send WMI_PDEV_RESUME cmd\n");1512dev_kfree_skb(skb);1513}15141515return ret;1516}15171518/* TODO FW Support for the cmd is not available yet.1519* Can be tested once the command and corresponding1520* event is implemented in FW1521*/1522int ath12k_wmi_pdev_bss_chan_info_request(struct ath12k *ar,1523enum wmi_bss_chan_info_req_type type)1524{1525struct ath12k_wmi_pdev *wmi = ar->wmi;1526struct wmi_pdev_bss_chan_info_req_cmd *cmd;1527struct sk_buff *skb;1528int ret;15291530skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1531if (!skb)1532return -ENOMEM;15331534cmd = (struct wmi_pdev_bss_chan_info_req_cmd *)skb->data;15351536cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_BSS_CHAN_INFO_REQUEST,1537sizeof(*cmd));1538cmd->req_type = cpu_to_le32(type);15391540ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1541"WMI bss chan info req type %d\n", type);15421543ret = ath12k_wmi_cmd_send(wmi, skb,1544WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID);1545if (ret) {1546ath12k_warn(ar->ab,1547"failed to send WMI_PDEV_BSS_CHAN_INFO_REQUEST cmd\n");1548dev_kfree_skb(skb);1549}15501551return ret;1552}15531554int ath12k_wmi_send_set_ap_ps_param_cmd(struct ath12k *ar, u8 *peer_addr,1555struct ath12k_wmi_ap_ps_arg *arg)1556{1557struct ath12k_wmi_pdev *wmi = ar->wmi;1558struct wmi_ap_ps_peer_cmd *cmd;1559struct sk_buff *skb;1560int ret;15611562skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1563if (!skb)1564return -ENOMEM;15651566cmd = (struct wmi_ap_ps_peer_cmd *)skb->data;1567cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_AP_PS_PEER_CMD,1568sizeof(*cmd));15691570cmd->vdev_id = cpu_to_le32(arg->vdev_id);1571ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);1572cmd->param = cpu_to_le32(arg->param);1573cmd->value = cpu_to_le32(arg->value);15741575ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1576"WMI set ap ps vdev id %d peer %pM param %d value %d\n",1577arg->vdev_id, peer_addr, arg->param, arg->value);15781579ret = ath12k_wmi_cmd_send(wmi, skb, WMI_AP_PS_PEER_PARAM_CMDID);1580if (ret) {1581ath12k_warn(ar->ab,1582"failed to send WMI_AP_PS_PEER_PARAM_CMDID\n");1583dev_kfree_skb(skb);1584}15851586return ret;1587}15881589int ath12k_wmi_set_sta_ps_param(struct ath12k *ar, u32 vdev_id,1590u32 param, u32 param_value)1591{1592struct ath12k_wmi_pdev *wmi = ar->wmi;1593struct wmi_sta_powersave_param_cmd *cmd;1594struct sk_buff *skb;1595int ret;15961597skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1598if (!skb)1599return -ENOMEM;16001601cmd = (struct wmi_sta_powersave_param_cmd *)skb->data;1602cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_STA_POWERSAVE_PARAM_CMD,1603sizeof(*cmd));16041605cmd->vdev_id = cpu_to_le32(vdev_id);1606cmd->param = cpu_to_le32(param);1607cmd->value = cpu_to_le32(param_value);16081609ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1610"WMI set sta ps vdev_id %d param %d value %d\n",1611vdev_id, param, param_value);16121613ret = ath12k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_PARAM_CMDID);1614if (ret) {1615ath12k_warn(ar->ab, "failed to send WMI_STA_POWERSAVE_PARAM_CMDID");1616dev_kfree_skb(skb);1617}16181619return ret;1620}16211622int ath12k_wmi_force_fw_hang_cmd(struct ath12k *ar, u32 type, u32 delay_time_ms)1623{1624struct ath12k_wmi_pdev *wmi = ar->wmi;1625struct wmi_force_fw_hang_cmd *cmd;1626struct sk_buff *skb;1627int ret, len;16281629len = sizeof(*cmd);16301631skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);1632if (!skb)1633return -ENOMEM;16341635cmd = (struct wmi_force_fw_hang_cmd *)skb->data;1636cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_FORCE_FW_HANG_CMD,1637len);16381639cmd->type = cpu_to_le32(type);1640cmd->delay_time_ms = cpu_to_le32(delay_time_ms);16411642ret = ath12k_wmi_cmd_send(wmi, skb, WMI_FORCE_FW_HANG_CMDID);16431644if (ret) {1645ath12k_warn(ar->ab, "Failed to send WMI_FORCE_FW_HANG_CMDID");1646dev_kfree_skb(skb);1647}1648return ret;1649}16501651int ath12k_wmi_vdev_set_param_cmd(struct ath12k *ar, u32 vdev_id,1652u32 param_id, u32 param_value)1653{1654struct ath12k_wmi_pdev *wmi = ar->wmi;1655struct wmi_vdev_set_param_cmd *cmd;1656struct sk_buff *skb;1657int ret;16581659skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1660if (!skb)1661return -ENOMEM;16621663cmd = (struct wmi_vdev_set_param_cmd *)skb->data;1664cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_SET_PARAM_CMD,1665sizeof(*cmd));16661667cmd->vdev_id = cpu_to_le32(vdev_id);1668cmd->param_id = cpu_to_le32(param_id);1669cmd->param_value = cpu_to_le32(param_value);16701671ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1672"WMI vdev id 0x%x set param %d value %d\n",1673vdev_id, param_id, param_value);16741675ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_SET_PARAM_CMDID);1676if (ret) {1677ath12k_warn(ar->ab,1678"failed to send WMI_VDEV_SET_PARAM_CMDID\n");1679dev_kfree_skb(skb);1680}16811682return ret;1683}16841685int ath12k_wmi_send_pdev_temperature_cmd(struct ath12k *ar)1686{1687struct ath12k_wmi_pdev *wmi = ar->wmi;1688struct wmi_get_pdev_temperature_cmd *cmd;1689struct sk_buff *skb;1690int ret;16911692skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1693if (!skb)1694return -ENOMEM;16951696cmd = (struct wmi_get_pdev_temperature_cmd *)skb->data;1697cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_GET_TEMPERATURE_CMD,1698sizeof(*cmd));1699cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);17001701ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1702"WMI pdev get temperature for pdev_id %d\n", ar->pdev->pdev_id);17031704ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PDEV_GET_TEMPERATURE_CMDID);1705if (ret) {1706ath12k_warn(ar->ab, "failed to send WMI_PDEV_GET_TEMPERATURE cmd\n");1707dev_kfree_skb(skb);1708}17091710return ret;1711}17121713int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar,1714u32 vdev_id, u32 bcn_ctrl_op)1715{1716struct ath12k_wmi_pdev *wmi = ar->wmi;1717struct wmi_bcn_offload_ctrl_cmd *cmd;1718struct sk_buff *skb;1719int ret;17201721skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));1722if (!skb)1723return -ENOMEM;17241725cmd = (struct wmi_bcn_offload_ctrl_cmd *)skb->data;1726cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_BCN_OFFLOAD_CTRL_CMD,1727sizeof(*cmd));17281729cmd->vdev_id = cpu_to_le32(vdev_id);1730cmd->bcn_ctrl_op = cpu_to_le32(bcn_ctrl_op);17311732ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1733"WMI bcn ctrl offload vdev id %d ctrl_op %d\n",1734vdev_id, bcn_ctrl_op);17351736ret = ath12k_wmi_cmd_send(wmi, skb, WMI_BCN_OFFLOAD_CTRL_CMDID);1737if (ret) {1738ath12k_warn(ar->ab,1739"failed to send WMI_BCN_OFFLOAD_CTRL_CMDID\n");1740dev_kfree_skb(skb);1741}17421743return ret;1744}17451746int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id,1747struct ieee80211_mutable_offsets *offs,1748struct sk_buff *bcn)1749{1750struct ath12k_wmi_pdev *wmi = ar->wmi;1751struct wmi_bcn_tmpl_cmd *cmd;1752struct ath12k_wmi_bcn_prb_info_params *bcn_prb_info;1753struct wmi_tlv *tlv;1754struct sk_buff *skb;1755#if defined(__linux__)1756void *ptr;1757#elif defined(__FreeBSD__)1758u8 *ptr;1759#endif1760int ret, len;1761size_t aligned_len = roundup(bcn->len, 4);17621763len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len;17641765skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);1766if (!skb)1767return -ENOMEM;17681769cmd = (struct wmi_bcn_tmpl_cmd *)skb->data;1770cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_BCN_TMPL_CMD,1771sizeof(*cmd));1772cmd->vdev_id = cpu_to_le32(vdev_id);1773cmd->tim_ie_offset = cpu_to_le32(offs->tim_offset);1774cmd->csa_switch_count_offset = cpu_to_le32(offs->cntdwn_counter_offs[0]);1775cmd->ext_csa_switch_count_offset = cpu_to_le32(offs->cntdwn_counter_offs[1]);1776cmd->buf_len = cpu_to_le32(bcn->len);17771778ptr = skb->data + sizeof(*cmd);17791780#if defined(__linux__)1781bcn_prb_info = ptr;1782#elif defined(__FreeBSD__)1783bcn_prb_info = (void *)ptr;1784#endif1785len = sizeof(*bcn_prb_info);1786bcn_prb_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_BCN_PRB_INFO,1787len);1788bcn_prb_info->caps = 0;1789bcn_prb_info->erp = 0;17901791ptr += sizeof(*bcn_prb_info);17921793#if defined(__linux__)1794tlv = ptr;1795#elif defined(__FreeBSD__)1796tlv = (void *)ptr;1797#endif1798tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, aligned_len);1799memcpy(tlv->value, bcn->data, bcn->len);18001801ret = ath12k_wmi_cmd_send(wmi, skb, WMI_BCN_TMPL_CMDID);1802if (ret) {1803ath12k_warn(ar->ab, "failed to send WMI_BCN_TMPL_CMDID\n");1804dev_kfree_skb(skb);1805}18061807return ret;1808}18091810int ath12k_wmi_vdev_install_key(struct ath12k *ar,1811struct wmi_vdev_install_key_arg *arg)1812{1813struct ath12k_wmi_pdev *wmi = ar->wmi;1814struct wmi_vdev_install_key_cmd *cmd;1815struct wmi_tlv *tlv;1816struct sk_buff *skb;1817int ret, len, key_len_aligned;18181819/* WMI_TAG_ARRAY_BYTE needs to be aligned with 4, the actual key1820* length is specified in cmd->key_len.1821*/1822key_len_aligned = roundup(arg->key_len, 4);18231824len = sizeof(*cmd) + TLV_HDR_SIZE + key_len_aligned;18251826skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);1827if (!skb)1828return -ENOMEM;18291830cmd = (struct wmi_vdev_install_key_cmd *)skb->data;1831cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_INSTALL_KEY_CMD,1832sizeof(*cmd));1833cmd->vdev_id = cpu_to_le32(arg->vdev_id);1834ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);1835cmd->key_idx = cpu_to_le32(arg->key_idx);1836cmd->key_flags = cpu_to_le32(arg->key_flags);1837cmd->key_cipher = cpu_to_le32(arg->key_cipher);1838cmd->key_len = cpu_to_le32(arg->key_len);1839cmd->key_txmic_len = cpu_to_le32(arg->key_txmic_len);1840cmd->key_rxmic_len = cpu_to_le32(arg->key_rxmic_len);18411842if (arg->key_rsc_counter)1843cmd->key_rsc_counter = cpu_to_le64(arg->key_rsc_counter);18441845tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));1846tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, key_len_aligned);1847memcpy(tlv->value, arg->key_data, arg->key_len);18481849ath12k_dbg(ar->ab, ATH12K_DBG_WMI,1850"WMI vdev install key idx %d cipher %d len %d\n",1851arg->key_idx, arg->key_cipher, arg->key_len);18521853ret = ath12k_wmi_cmd_send(wmi, skb, WMI_VDEV_INSTALL_KEY_CMDID);1854if (ret) {1855ath12k_warn(ar->ab,1856"failed to send WMI_VDEV_INSTALL_KEY cmd\n");1857dev_kfree_skb(skb);1858}18591860return ret;1861}18621863static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,1864struct ath12k_wmi_peer_assoc_arg *arg,1865bool hw_crypto_disabled)1866{1867cmd->peer_flags = 0;1868cmd->peer_flags_ext = 0;18691870if (arg->is_wme_set) {1871if (arg->qos_flag)1872cmd->peer_flags |= cpu_to_le32(WMI_PEER_QOS);1873if (arg->apsd_flag)1874cmd->peer_flags |= cpu_to_le32(WMI_PEER_APSD);1875if (arg->ht_flag)1876cmd->peer_flags |= cpu_to_le32(WMI_PEER_HT);1877if (arg->bw_40)1878cmd->peer_flags |= cpu_to_le32(WMI_PEER_40MHZ);1879if (arg->bw_80)1880cmd->peer_flags |= cpu_to_le32(WMI_PEER_80MHZ);1881if (arg->bw_160)1882cmd->peer_flags |= cpu_to_le32(WMI_PEER_160MHZ);1883if (arg->bw_320)1884cmd->peer_flags |= cpu_to_le32(WMI_PEER_EXT_320MHZ);18851886/* Typically if STBC is enabled for VHT it should be enabled1887* for HT as well1888**/1889if (arg->stbc_flag)1890cmd->peer_flags |= cpu_to_le32(WMI_PEER_STBC);18911892/* Typically if LDPC is enabled for VHT it should be enabled1893* for HT as well1894**/1895if (arg->ldpc_flag)1896cmd->peer_flags |= cpu_to_le32(WMI_PEER_LDPC);18971898if (arg->static_mimops_flag)1899cmd->peer_flags |= cpu_to_le32(WMI_PEER_STATIC_MIMOPS);1900if (arg->dynamic_mimops_flag)1901cmd->peer_flags |= cpu_to_le32(WMI_PEER_DYN_MIMOPS);1902if (arg->spatial_mux_flag)1903cmd->peer_flags |= cpu_to_le32(WMI_PEER_SPATIAL_MUX);1904if (arg->vht_flag)1905cmd->peer_flags |= cpu_to_le32(WMI_PEER_VHT);1906if (arg->he_flag)1907cmd->peer_flags |= cpu_to_le32(WMI_PEER_HE);1908if (arg->twt_requester)1909cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_REQ);1910if (arg->twt_responder)1911cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_RESP);1912if (arg->eht_flag)1913cmd->peer_flags_ext |= cpu_to_le32(WMI_PEER_EXT_EHT);1914}19151916/* Suppress authorization for all AUTH modes that need 4-way handshake1917* (during re-association).1918* Authorization will be done for these modes on key installation.1919*/1920if (arg->auth_flag)1921cmd->peer_flags |= cpu_to_le32(WMI_PEER_AUTH);1922if (arg->need_ptk_4_way) {1923cmd->peer_flags |= cpu_to_le32(WMI_PEER_NEED_PTK_4_WAY);1924if (!hw_crypto_disabled)1925cmd->peer_flags &= cpu_to_le32(~WMI_PEER_AUTH);1926}1927if (arg->need_gtk_2_way)1928cmd->peer_flags |= cpu_to_le32(WMI_PEER_NEED_GTK_2_WAY);1929/* safe mode bypass the 4-way handshake */1930if (arg->safe_mode_enabled)1931cmd->peer_flags &= cpu_to_le32(~(WMI_PEER_NEED_PTK_4_WAY |1932WMI_PEER_NEED_GTK_2_WAY));19331934if (arg->is_pmf_enabled)1935cmd->peer_flags |= cpu_to_le32(WMI_PEER_PMF);19361937/* Disable AMSDU for station transmit, if user configures it */1938/* Disable AMSDU for AP transmit to 11n Stations, if user configures1939* it1940* if (arg->amsdu_disable) Add after FW support1941**/19421943/* Target asserts if node is marked HT and all MCS is set to 0.1944* Mark the node as non-HT if all the mcs rates are disabled through1945* iwpriv1946**/1947if (arg->peer_ht_rates.num_rates == 0)1948cmd->peer_flags &= cpu_to_le32(~WMI_PEER_HT);1949}19501951int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,1952struct ath12k_wmi_peer_assoc_arg *arg)1953{1954struct ath12k_wmi_pdev *wmi = ar->wmi;1955struct wmi_peer_assoc_complete_cmd *cmd;1956struct ath12k_wmi_vht_rate_set_params *mcs;1957struct ath12k_wmi_he_rate_set_params *he_mcs;1958struct ath12k_wmi_eht_rate_set_params *eht_mcs;1959struct sk_buff *skb;1960struct wmi_tlv *tlv;1961#if defined(__linux__)1962void *ptr;1963#elif defined(__FreeBSD__)1964u8 *ptr;1965#endif1966u32 peer_legacy_rates_align;1967u32 peer_ht_rates_align;1968int i, ret, len;19691970peer_legacy_rates_align = roundup(arg->peer_legacy_rates.num_rates,1971sizeof(u32));1972peer_ht_rates_align = roundup(arg->peer_ht_rates.num_rates,1973sizeof(u32));19741975len = sizeof(*cmd) +1976TLV_HDR_SIZE + (peer_legacy_rates_align * sizeof(u8)) +1977TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) +1978sizeof(*mcs) + TLV_HDR_SIZE +1979(sizeof(*he_mcs) * arg->peer_he_mcs_count) +1980TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count) +1981TLV_HDR_SIZE + TLV_HDR_SIZE;19821983skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);1984if (!skb)1985return -ENOMEM;19861987ptr = skb->data;19881989#if defined(__linux__)1990cmd = ptr;1991#elif defined(__FreeBSD__)1992cmd = (void *)ptr;1993#endif1994cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PEER_ASSOC_COMPLETE_CMD,1995sizeof(*cmd));19961997cmd->vdev_id = cpu_to_le32(arg->vdev_id);19981999cmd->peer_new_assoc = cpu_to_le32(arg->peer_new_assoc);2000cmd->peer_associd = cpu_to_le32(arg->peer_associd);2001cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap);20022003ath12k_wmi_copy_peer_flags(cmd, arg,2004test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED,2005&ar->ab->dev_flags));20062007ether_addr_copy(cmd->peer_macaddr.addr, arg->peer_mac);20082009cmd->peer_rate_caps = cpu_to_le32(arg->peer_rate_caps);2010cmd->peer_caps = cpu_to_le32(arg->peer_caps);2011cmd->peer_listen_intval = cpu_to_le32(arg->peer_listen_intval);2012cmd->peer_ht_caps = cpu_to_le32(arg->peer_ht_caps);2013cmd->peer_max_mpdu = cpu_to_le32(arg->peer_max_mpdu);2014cmd->peer_mpdu_density = cpu_to_le32(arg->peer_mpdu_density);2015cmd->peer_vht_caps = cpu_to_le32(arg->peer_vht_caps);2016cmd->peer_phymode = cpu_to_le32(arg->peer_phymode);20172018/* Update 11ax capabilities */2019cmd->peer_he_cap_info = cpu_to_le32(arg->peer_he_cap_macinfo[0]);2020cmd->peer_he_cap_info_ext = cpu_to_le32(arg->peer_he_cap_macinfo[1]);2021cmd->peer_he_cap_info_internal = cpu_to_le32(arg->peer_he_cap_macinfo_internal);2022cmd->peer_he_caps_6ghz = cpu_to_le32(arg->peer_he_caps_6ghz);2023cmd->peer_he_ops = cpu_to_le32(arg->peer_he_ops);2024for (i = 0; i < WMI_MAX_HECAP_PHY_SIZE; i++)2025cmd->peer_he_cap_phy[i] =2026cpu_to_le32(arg->peer_he_cap_phyinfo[i]);2027cmd->peer_ppet.numss_m1 = cpu_to_le32(arg->peer_ppet.numss_m1);2028cmd->peer_ppet.ru_info = cpu_to_le32(arg->peer_ppet.ru_bit_mask);2029for (i = 0; i < WMI_MAX_NUM_SS; i++)2030cmd->peer_ppet.ppet16_ppet8_ru3_ru0[i] =2031cpu_to_le32(arg->peer_ppet.ppet16_ppet8_ru3_ru0[i]);20322033/* Update 11be capabilities */2034memcpy_and_pad(cmd->peer_eht_cap_mac, sizeof(cmd->peer_eht_cap_mac),2035arg->peer_eht_cap_mac, sizeof(arg->peer_eht_cap_mac),20360);2037memcpy_and_pad(cmd->peer_eht_cap_phy, sizeof(cmd->peer_eht_cap_phy),2038arg->peer_eht_cap_phy, sizeof(arg->peer_eht_cap_phy),20390);2040memcpy_and_pad(&cmd->peer_eht_ppet, sizeof(cmd->peer_eht_ppet),2041&arg->peer_eht_ppet, sizeof(arg->peer_eht_ppet), 0);20422043/* Update peer legacy rate information */2044ptr += sizeof(*cmd);20452046#if defined(__linux__)2047tlv = ptr;2048#elif defined(__FreeBSD__)2049tlv = (void *)ptr;2050#endif2051tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, peer_legacy_rates_align);20522053ptr += TLV_HDR_SIZE;20542055cmd->num_peer_legacy_rates = cpu_to_le32(arg->peer_legacy_rates.num_rates);2056memcpy(ptr, arg->peer_legacy_rates.rates,2057arg->peer_legacy_rates.num_rates);20582059/* Update peer HT rate information */2060ptr += peer_legacy_rates_align;20612062#if defined(__linux__)2063tlv = ptr;2064#elif defined(__FreeBSD__)2065tlv = (void *)ptr;2066#endif2067tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, peer_ht_rates_align);2068ptr += TLV_HDR_SIZE;2069cmd->num_peer_ht_rates = cpu_to_le32(arg->peer_ht_rates.num_rates);2070memcpy(ptr, arg->peer_ht_rates.rates,2071arg->peer_ht_rates.num_rates);20722073/* VHT Rates */2074ptr += peer_ht_rates_align;20752076#if defined(__linux__)2077mcs = ptr;2078#elif defined(__FreeBSD__)2079mcs = (void *)ptr;2080#endif20812082mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VHT_RATE_SET,2083sizeof(*mcs));20842085cmd->peer_nss = cpu_to_le32(arg->peer_nss);20862087/* Update bandwidth-NSS mapping */2088cmd->peer_bw_rxnss_override = 0;2089cmd->peer_bw_rxnss_override |= cpu_to_le32(arg->peer_bw_rxnss_override);20902091if (arg->vht_capable) {2092mcs->rx_max_rate = cpu_to_le32(arg->rx_max_rate);2093mcs->rx_mcs_set = cpu_to_le32(arg->rx_mcs_set);2094mcs->tx_max_rate = cpu_to_le32(arg->tx_max_rate);2095mcs->tx_mcs_set = cpu_to_le32(arg->tx_mcs_set);2096}20972098/* HE Rates */2099cmd->peer_he_mcs = cpu_to_le32(arg->peer_he_mcs_count);2100cmd->min_data_rate = cpu_to_le32(arg->min_data_rate);21012102ptr += sizeof(*mcs);21032104len = arg->peer_he_mcs_count * sizeof(*he_mcs);21052106#if defined(__linux__)2107tlv = ptr;2108#elif defined(__FreeBSD__)2109tlv = (void *)ptr;2110#endif2111tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);2112ptr += TLV_HDR_SIZE;21132114/* Loop through the HE rate set */2115for (i = 0; i < arg->peer_he_mcs_count; i++) {2116#if defined(__linux__)2117he_mcs = ptr;2118#elif defined(__FreeBSD__)2119he_mcs = (void *)ptr;2120#endif2121he_mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_HE_RATE_SET,2122sizeof(*he_mcs));21232124he_mcs->rx_mcs_set = cpu_to_le32(arg->peer_he_rx_mcs_set[i]);2125he_mcs->tx_mcs_set = cpu_to_le32(arg->peer_he_tx_mcs_set[i]);2126ptr += sizeof(*he_mcs);2127}21282129/* MLO header tag with 0 length */2130len = 0;2131#if defined(__linux__)2132tlv = ptr;2133#elif defined(__FreeBSD__)2134tlv = (void *)ptr;2135#endif2136tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);2137ptr += TLV_HDR_SIZE;21382139/* Loop through the EHT rate set */2140len = arg->peer_eht_mcs_count * sizeof(*eht_mcs);2141#if defined(__linux__)2142tlv = ptr;2143#elif defined(__FreeBSD__)2144tlv = (void *)ptr;2145#endif2146tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);2147ptr += TLV_HDR_SIZE;21482149for (i = 0; i < arg->peer_eht_mcs_count; i++) {2150#if defined(__linux__)2151eht_mcs = ptr;2152#elif defined(__FreeBSD__)2153eht_mcs = (void *)ptr;2154#endif2155eht_mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_HE_RATE_SET,2156sizeof(*eht_mcs));21572158eht_mcs->rx_mcs_set = cpu_to_le32(arg->peer_eht_rx_mcs_set[i]);2159eht_mcs->tx_mcs_set = cpu_to_le32(arg->peer_eht_tx_mcs_set[i]);2160ptr += sizeof(*eht_mcs);2161}21622163/* ML partner links tag with 0 length */2164len = 0;2165#if defined(__linux__)2166tlv = ptr;2167#elif defined(__FreeBSD__)2168tlv = (void *)ptr;2169#endif2170tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);2171ptr += TLV_HDR_SIZE;21722173ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2174"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",2175cmd->vdev_id, cmd->peer_associd, arg->peer_mac,2176cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps,2177cmd->peer_listen_intval, cmd->peer_ht_caps,2178cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode,2179cmd->peer_mpdu_density,2180cmd->peer_vht_caps, cmd->peer_he_cap_info,2181cmd->peer_he_ops, cmd->peer_he_cap_info_ext,2182cmd->peer_he_cap_phy[0], cmd->peer_he_cap_phy[1],2183cmd->peer_he_cap_phy[2],2184cmd->peer_bw_rxnss_override, cmd->peer_flags_ext,2185cmd->peer_eht_cap_mac[0], cmd->peer_eht_cap_mac[1],2186cmd->peer_eht_cap_phy[0], cmd->peer_eht_cap_phy[1],2187cmd->peer_eht_cap_phy[2]);21882189ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_ASSOC_CMDID);2190if (ret) {2191ath12k_warn(ar->ab,2192"failed to send WMI_PEER_ASSOC_CMDID\n");2193dev_kfree_skb(skb);2194}21952196return ret;2197}21982199void ath12k_wmi_start_scan_init(struct ath12k *ar,2200struct ath12k_wmi_scan_req_arg *arg)2201{2202/* setup commonly used values */2203arg->scan_req_id = 1;2204arg->scan_priority = WMI_SCAN_PRIORITY_LOW;2205arg->dwell_time_active = 50;2206arg->dwell_time_active_2g = 0;2207arg->dwell_time_passive = 150;2208arg->dwell_time_active_6g = 40;2209arg->dwell_time_passive_6g = 30;2210arg->min_rest_time = 50;2211arg->max_rest_time = 500;2212arg->repeat_probe_time = 0;2213arg->probe_spacing_time = 0;2214arg->idle_time = 0;2215arg->max_scan_time = 20000;2216arg->probe_delay = 5;2217arg->notify_scan_events = WMI_SCAN_EVENT_STARTED |2218WMI_SCAN_EVENT_COMPLETED |2219WMI_SCAN_EVENT_BSS_CHANNEL |2220WMI_SCAN_EVENT_FOREIGN_CHAN |2221WMI_SCAN_EVENT_DEQUEUED;2222arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT;2223arg->num_bssid = 1;22242225/* fill bssid_list[0] with 0xff, otherwise bssid and RA will be2226* ZEROs in probe request2227*/2228eth_broadcast_addr(arg->bssid_list[0].addr);2229}22302231static void ath12k_wmi_copy_scan_event_cntrl_flags(struct wmi_start_scan_cmd *cmd,2232struct ath12k_wmi_scan_req_arg *arg)2233{2234/* Scan events subscription */2235if (arg->scan_ev_started)2236cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_STARTED);2237if (arg->scan_ev_completed)2238cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_COMPLETED);2239if (arg->scan_ev_bss_chan)2240cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_BSS_CHANNEL);2241if (arg->scan_ev_foreign_chan)2242cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_FOREIGN_CHAN);2243if (arg->scan_ev_dequeued)2244cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_DEQUEUED);2245if (arg->scan_ev_preempted)2246cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_PREEMPTED);2247if (arg->scan_ev_start_failed)2248cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_START_FAILED);2249if (arg->scan_ev_restarted)2250cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_RESTARTED);2251if (arg->scan_ev_foreign_chn_exit)2252cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT);2253if (arg->scan_ev_suspended)2254cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_SUSPENDED);2255if (arg->scan_ev_resumed)2256cmd->notify_scan_events |= cpu_to_le32(WMI_SCAN_EVENT_RESUMED);22572258/** Set scan control flags */2259cmd->scan_ctrl_flags = 0;2260if (arg->scan_f_passive)2261cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_PASSIVE);2262if (arg->scan_f_strict_passive_pch)2263cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_STRICT_PASSIVE_ON_PCHN);2264if (arg->scan_f_promisc_mode)2265cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FILTER_PROMISCUOS);2266if (arg->scan_f_capture_phy_err)2267cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_CAPTURE_PHY_ERROR);2268if (arg->scan_f_half_rate)2269cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_HALF_RATE_SUPPORT);2270if (arg->scan_f_quarter_rate)2271cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_QUARTER_RATE_SUPPORT);2272if (arg->scan_f_cck_rates)2273cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_CCK_RATES);2274if (arg->scan_f_ofdm_rates)2275cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_OFDM_RATES);2276if (arg->scan_f_chan_stat_evnt)2277cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_CHAN_STAT_EVENT);2278if (arg->scan_f_filter_prb_req)2279cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ);2280if (arg->scan_f_bcast_probe)2281cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_BCAST_PROBE_REQ);2282if (arg->scan_f_offchan_mgmt_tx)2283cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_OFFCHAN_MGMT_TX);2284if (arg->scan_f_offchan_data_tx)2285cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_OFFCHAN_DATA_TX);2286if (arg->scan_f_force_active_dfs_chn)2287cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS);2288if (arg->scan_f_add_tpc_ie_in_probe)2289cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ);2290if (arg->scan_f_add_ds_ie_in_probe)2291cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ);2292if (arg->scan_f_add_spoofed_mac_in_probe)2293cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_ADD_SPOOF_MAC_IN_PROBE_REQ);2294if (arg->scan_f_add_rand_seq_in_probe)2295cmd->scan_ctrl_flags |= cpu_to_le32(WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ);2296if (arg->scan_f_en_ie_whitelist_in_probe)2297cmd->scan_ctrl_flags |=2298cpu_to_le32(WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ);22992300cmd->scan_ctrl_flags |= le32_encode_bits(arg->adaptive_dwell_time_mode,2301WMI_SCAN_DWELL_MODE_MASK);2302}23032304int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,2305struct ath12k_wmi_scan_req_arg *arg)2306{2307struct ath12k_wmi_pdev *wmi = ar->wmi;2308struct wmi_start_scan_cmd *cmd;2309struct ath12k_wmi_ssid_params *ssid = NULL;2310struct ath12k_wmi_mac_addr_params *bssid;2311struct sk_buff *skb;2312struct wmi_tlv *tlv;2313#if defined(__linux__)2314void *ptr;2315#elif defined(__FreeBSD__)2316u8 *ptr;2317#endif2318int i, ret, len;2319u32 *tmp_ptr, extraie_len_with_pad = 0;2320struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;2321struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;23222323len = sizeof(*cmd);23242325len += TLV_HDR_SIZE;2326if (arg->num_chan)2327len += arg->num_chan * sizeof(u32);23282329len += TLV_HDR_SIZE;2330if (arg->num_ssids)2331len += arg->num_ssids * sizeof(*ssid);23322333len += TLV_HDR_SIZE;2334if (arg->num_bssid)2335len += sizeof(*bssid) * arg->num_bssid;23362337len += TLV_HDR_SIZE;2338if (arg->extraie.len)2339extraie_len_with_pad =2340roundup(arg->extraie.len, sizeof(u32));2341len += extraie_len_with_pad;23422343if (arg->num_hint_bssid)2344len += TLV_HDR_SIZE +2345arg->num_hint_bssid * sizeof(*hint_bssid);23462347if (arg->num_hint_s_ssid)2348len += TLV_HDR_SIZE +2349arg->num_hint_s_ssid * sizeof(*s_ssid);23502351skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);2352if (!skb)2353return -ENOMEM;23542355ptr = skb->data;23562357#if defined(__linux__)2358cmd = ptr;2359#elif defined(__FreeBSD__)2360cmd = (void *)ptr;2361#endif2362cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_START_SCAN_CMD,2363sizeof(*cmd));23642365cmd->scan_id = cpu_to_le32(arg->scan_id);2366cmd->scan_req_id = cpu_to_le32(arg->scan_req_id);2367cmd->vdev_id = cpu_to_le32(arg->vdev_id);2368cmd->scan_priority = cpu_to_le32(arg->scan_priority);2369cmd->notify_scan_events = cpu_to_le32(arg->notify_scan_events);23702371ath12k_wmi_copy_scan_event_cntrl_flags(cmd, arg);23722373cmd->dwell_time_active = cpu_to_le32(arg->dwell_time_active);2374cmd->dwell_time_active_2g = cpu_to_le32(arg->dwell_time_active_2g);2375cmd->dwell_time_passive = cpu_to_le32(arg->dwell_time_passive);2376cmd->dwell_time_active_6g = cpu_to_le32(arg->dwell_time_active_6g);2377cmd->dwell_time_passive_6g = cpu_to_le32(arg->dwell_time_passive_6g);2378cmd->min_rest_time = cpu_to_le32(arg->min_rest_time);2379cmd->max_rest_time = cpu_to_le32(arg->max_rest_time);2380cmd->repeat_probe_time = cpu_to_le32(arg->repeat_probe_time);2381cmd->probe_spacing_time = cpu_to_le32(arg->probe_spacing_time);2382cmd->idle_time = cpu_to_le32(arg->idle_time);2383cmd->max_scan_time = cpu_to_le32(arg->max_scan_time);2384cmd->probe_delay = cpu_to_le32(arg->probe_delay);2385cmd->burst_duration = cpu_to_le32(arg->burst_duration);2386cmd->num_chan = cpu_to_le32(arg->num_chan);2387cmd->num_bssid = cpu_to_le32(arg->num_bssid);2388cmd->num_ssids = cpu_to_le32(arg->num_ssids);2389cmd->ie_len = cpu_to_le32(arg->extraie.len);2390cmd->n_probes = cpu_to_le32(arg->n_probes);23912392ptr += sizeof(*cmd);23932394len = arg->num_chan * sizeof(u32);23952396#if defined(__linux__)2397tlv = ptr;2398#elif defined(__FreeBSD__)2399tlv = (void *)ptr;2400#endif2401tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);2402ptr += TLV_HDR_SIZE;2403tmp_ptr = (u32 *)ptr;24042405memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);24062407ptr += len;24082409len = arg->num_ssids * sizeof(*ssid);2410#if defined(__linux__)2411tlv = ptr;2412#elif defined(__FreeBSD__)2413tlv = (void *)ptr;2414#endif2415tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_FIXED_STRUCT, len);24162417ptr += TLV_HDR_SIZE;24182419if (arg->num_ssids) {2420#if defined(__linux__)2421ssid = ptr;2422#elif defined(__FreeBSD__)2423ssid = (void *)ptr;2424#endif2425for (i = 0; i < arg->num_ssids; ++i) {2426ssid->ssid_len = cpu_to_le32(arg->ssid[i].ssid_len);2427memcpy(ssid->ssid, arg->ssid[i].ssid,2428arg->ssid[i].ssid_len);2429ssid++;2430}2431}24322433ptr += (arg->num_ssids * sizeof(*ssid));2434len = arg->num_bssid * sizeof(*bssid);2435#if defined(__linux__)2436tlv = ptr;2437#elif defined(__FreeBSD__)2438tlv = (void *)ptr;2439#endif2440tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_FIXED_STRUCT, len);24412442ptr += TLV_HDR_SIZE;2443#if defined(__linux__)2444bssid = ptr;2445#elif defined(__FreeBSD__)2446bssid = (void *)ptr;2447#endif24482449if (arg->num_bssid) {2450for (i = 0; i < arg->num_bssid; ++i) {2451ether_addr_copy(bssid->addr,2452arg->bssid_list[i].addr);2453bssid++;2454}2455}24562457ptr += arg->num_bssid * sizeof(*bssid);24582459len = extraie_len_with_pad;2460#if defined(__linux__)2461tlv = ptr;2462#elif defined(__FreeBSD__)2463tlv = (void *)ptr;2464#endif2465tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len);2466ptr += TLV_HDR_SIZE;24672468if (arg->extraie.len)2469memcpy(ptr, arg->extraie.ptr,2470arg->extraie.len);24712472ptr += extraie_len_with_pad;24732474if (arg->num_hint_s_ssid) {2475len = arg->num_hint_s_ssid * sizeof(*s_ssid);2476#if defined(__linux__)2477tlv = ptr;2478#elif defined(__FreeBSD__)2479tlv = (void *)ptr;2480#endif2481tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_FIXED_STRUCT, len);2482ptr += TLV_HDR_SIZE;2483#if defined(__linux__)2484s_ssid = ptr;2485#elif defined(__FreeBSD__)2486s_ssid = (void *)ptr;2487#endif2488for (i = 0; i < arg->num_hint_s_ssid; ++i) {2489s_ssid->freq_flags = arg->hint_s_ssid[i].freq_flags;2490s_ssid->short_ssid = arg->hint_s_ssid[i].short_ssid;2491s_ssid++;2492}2493ptr += len;2494}24952496if (arg->num_hint_bssid) {2497len = arg->num_hint_bssid * sizeof(struct ath12k_wmi_hint_bssid_arg);2498#if defined(__linux__)2499tlv = ptr;2500#elif defined(__FreeBSD__)2501tlv = (void *)ptr;2502#endif2503tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_FIXED_STRUCT, len);2504ptr += TLV_HDR_SIZE;2505#if defined(__linux__)2506hint_bssid = ptr;2507#elif defined(__FreeBSD__)2508hint_bssid = (void *)ptr;2509#endif2510for (i = 0; i < arg->num_hint_bssid; ++i) {2511hint_bssid->freq_flags =2512arg->hint_bssid[i].freq_flags;2513ether_addr_copy(&arg->hint_bssid[i].bssid.addr[0],2514&hint_bssid->bssid.addr[0]);2515hint_bssid++;2516}2517}25182519ret = ath12k_wmi_cmd_send(wmi, skb,2520WMI_START_SCAN_CMDID);2521if (ret) {2522ath12k_warn(ar->ab, "failed to send WMI_START_SCAN_CMDID\n");2523dev_kfree_skb(skb);2524}25252526return ret;2527}25282529int ath12k_wmi_send_scan_stop_cmd(struct ath12k *ar,2530struct ath12k_wmi_scan_cancel_arg *arg)2531{2532struct ath12k_wmi_pdev *wmi = ar->wmi;2533struct wmi_stop_scan_cmd *cmd;2534struct sk_buff *skb;2535int ret;25362537skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2538if (!skb)2539return -ENOMEM;25402541cmd = (struct wmi_stop_scan_cmd *)skb->data;25422543cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_STOP_SCAN_CMD,2544sizeof(*cmd));25452546cmd->vdev_id = cpu_to_le32(arg->vdev_id);2547cmd->requestor = cpu_to_le32(arg->requester);2548cmd->scan_id = cpu_to_le32(arg->scan_id);2549cmd->pdev_id = cpu_to_le32(arg->pdev_id);2550/* stop the scan with the corresponding scan_id */2551if (arg->req_type == WLAN_SCAN_CANCEL_PDEV_ALL) {2552/* Cancelling all scans */2553cmd->req_type = cpu_to_le32(WMI_SCAN_STOP_ALL);2554} else if (arg->req_type == WLAN_SCAN_CANCEL_VDEV_ALL) {2555/* Cancelling VAP scans */2556cmd->req_type = cpu_to_le32(WMI_SCAN_STOP_VAP_ALL);2557} else if (arg->req_type == WLAN_SCAN_CANCEL_SINGLE) {2558/* Cancelling specific scan */2559cmd->req_type = WMI_SCAN_STOP_ONE;2560} else {2561ath12k_warn(ar->ab, "invalid scan cancel req_type %d",2562arg->req_type);2563dev_kfree_skb(skb);2564return -EINVAL;2565}25662567ret = ath12k_wmi_cmd_send(wmi, skb,2568WMI_STOP_SCAN_CMDID);2569if (ret) {2570ath12k_warn(ar->ab, "failed to send WMI_STOP_SCAN_CMDID\n");2571dev_kfree_skb(skb);2572}25732574return ret;2575}25762577int ath12k_wmi_send_scan_chan_list_cmd(struct ath12k *ar,2578struct ath12k_wmi_scan_chan_list_arg *arg)2579{2580struct ath12k_wmi_pdev *wmi = ar->wmi;2581struct wmi_scan_chan_list_cmd *cmd;2582struct sk_buff *skb;2583struct ath12k_wmi_channel_params *chan_info;2584struct ath12k_wmi_channel_arg *channel_arg;2585struct wmi_tlv *tlv;2586#if defined(__linux__)2587void *ptr;2588#elif defined(__FreeBSD__)2589u8 *ptr;2590#endif2591int i, ret, len;2592u16 num_send_chans, num_sends = 0, max_chan_limit = 0;2593__le32 *reg1, *reg2;25942595channel_arg = &arg->channel[0];2596while (arg->nallchans) {2597len = sizeof(*cmd) + TLV_HDR_SIZE;2598max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) /2599sizeof(*chan_info);26002601num_send_chans = min(arg->nallchans, max_chan_limit);26022603arg->nallchans -= num_send_chans;2604len += sizeof(*chan_info) * num_send_chans;26052606skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);2607if (!skb)2608return -ENOMEM;26092610cmd = (struct wmi_scan_chan_list_cmd *)skb->data;2611cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SCAN_CHAN_LIST_CMD,2612sizeof(*cmd));2613cmd->pdev_id = cpu_to_le32(arg->pdev_id);2614cmd->num_scan_chans = cpu_to_le32(num_send_chans);2615if (num_sends)2616cmd->flags |= cpu_to_le32(WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG);26172618ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2619"WMI no.of chan = %d len = %d pdev_id = %d num_sends = %d\n",2620num_send_chans, len, cmd->pdev_id, num_sends);26212622ptr = skb->data + sizeof(*cmd);26232624len = sizeof(*chan_info) * num_send_chans;2625#if defined(__linux__)2626tlv = ptr;2627#elif defined(__FreeBSD__)2628tlv = (void *)ptr;2629#endif2630tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ARRAY_STRUCT,2631len);2632ptr += TLV_HDR_SIZE;26332634for (i = 0; i < num_send_chans; ++i) {2635#if defined(__linux__)2636chan_info = ptr;2637#elif defined(__FreeBSD__)2638chan_info = (void *)ptr;2639#endif2640memset(chan_info, 0, sizeof(*chan_info));2641len = sizeof(*chan_info);2642chan_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_CHANNEL,2643len);26442645reg1 = &chan_info->reg_info_1;2646reg2 = &chan_info->reg_info_2;2647chan_info->mhz = cpu_to_le32(channel_arg->mhz);2648chan_info->band_center_freq1 = cpu_to_le32(channel_arg->cfreq1);2649chan_info->band_center_freq2 = cpu_to_le32(channel_arg->cfreq2);26502651if (channel_arg->is_chan_passive)2652chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_PASSIVE);2653if (channel_arg->allow_he)2654chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HE);2655else if (channel_arg->allow_vht)2656chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_VHT);2657else if (channel_arg->allow_ht)2658chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_ALLOW_HT);2659if (channel_arg->half_rate)2660chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_HALF_RATE);2661if (channel_arg->quarter_rate)2662chan_info->info |=2663cpu_to_le32(WMI_CHAN_INFO_QUARTER_RATE);26642665if (channel_arg->psc_channel)2666chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_PSC);26672668if (channel_arg->dfs_set)2669chan_info->info |= cpu_to_le32(WMI_CHAN_INFO_DFS);26702671chan_info->info |= le32_encode_bits(channel_arg->phy_mode,2672WMI_CHAN_INFO_MODE);2673*reg1 |= le32_encode_bits(channel_arg->minpower,2674WMI_CHAN_REG_INFO1_MIN_PWR);2675*reg1 |= le32_encode_bits(channel_arg->maxpower,2676WMI_CHAN_REG_INFO1_MAX_PWR);2677*reg1 |= le32_encode_bits(channel_arg->maxregpower,2678WMI_CHAN_REG_INFO1_MAX_REG_PWR);2679*reg1 |= le32_encode_bits(channel_arg->reg_class_id,2680WMI_CHAN_REG_INFO1_REG_CLS);2681*reg2 |= le32_encode_bits(channel_arg->antennamax,2682WMI_CHAN_REG_INFO2_ANT_MAX);26832684ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2685"WMI chan scan list chan[%d] = %u, chan_info->info %8x\n",2686i, chan_info->mhz, chan_info->info);26872688ptr += sizeof(*chan_info);26892690channel_arg++;2691}26922693ret = ath12k_wmi_cmd_send(wmi, skb, WMI_SCAN_CHAN_LIST_CMDID);2694if (ret) {2695ath12k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n");2696dev_kfree_skb(skb);2697return ret;2698}26992700num_sends++;2701}27022703return 0;2704}27052706int ath12k_wmi_send_wmm_update_cmd(struct ath12k *ar, u32 vdev_id,2707struct wmi_wmm_params_all_arg *param)2708{2709struct ath12k_wmi_pdev *wmi = ar->wmi;2710struct wmi_vdev_set_wmm_params_cmd *cmd;2711struct wmi_wmm_params *wmm_param;2712struct wmi_wmm_params_arg *wmi_wmm_arg;2713struct sk_buff *skb;2714int ret, ac;27152716skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2717if (!skb)2718return -ENOMEM;27192720cmd = (struct wmi_vdev_set_wmm_params_cmd *)skb->data;2721cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_SET_WMM_PARAMS_CMD,2722sizeof(*cmd));27232724cmd->vdev_id = cpu_to_le32(vdev_id);2725cmd->wmm_param_type = 0;27262727for (ac = 0; ac < WME_NUM_AC; ac++) {2728switch (ac) {2729case WME_AC_BE:2730wmi_wmm_arg = ¶m->ac_be;2731break;2732case WME_AC_BK:2733wmi_wmm_arg = ¶m->ac_bk;2734break;2735case WME_AC_VI:2736wmi_wmm_arg = ¶m->ac_vi;2737break;2738case WME_AC_VO:2739wmi_wmm_arg = ¶m->ac_vo;2740break;2741}27422743wmm_param = (struct wmi_wmm_params *)&cmd->wmm_params[ac];2744wmm_param->tlv_header =2745ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_SET_WMM_PARAMS_CMD,2746sizeof(*wmm_param));27472748wmm_param->aifs = cpu_to_le32(wmi_wmm_arg->aifs);2749wmm_param->cwmin = cpu_to_le32(wmi_wmm_arg->cwmin);2750wmm_param->cwmax = cpu_to_le32(wmi_wmm_arg->cwmax);2751wmm_param->txoplimit = cpu_to_le32(wmi_wmm_arg->txop);2752wmm_param->acm = cpu_to_le32(wmi_wmm_arg->acm);2753wmm_param->no_ack = cpu_to_le32(wmi_wmm_arg->no_ack);27542755ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2756"wmi wmm set ac %d aifs %d cwmin %d cwmax %d txop %d acm %d no_ack %d\n",2757ac, wmm_param->aifs, wmm_param->cwmin,2758wmm_param->cwmax, wmm_param->txoplimit,2759wmm_param->acm, wmm_param->no_ack);2760}2761ret = ath12k_wmi_cmd_send(wmi, skb,2762WMI_VDEV_SET_WMM_PARAMS_CMDID);2763if (ret) {2764ath12k_warn(ar->ab,2765"failed to send WMI_VDEV_SET_WMM_PARAMS_CMDID");2766dev_kfree_skb(skb);2767}27682769return ret;2770}27712772int ath12k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath12k *ar,2773u32 pdev_id)2774{2775struct ath12k_wmi_pdev *wmi = ar->wmi;2776struct wmi_dfs_phyerr_offload_cmd *cmd;2777struct sk_buff *skb;2778int ret;27792780skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2781if (!skb)2782return -ENOMEM;27832784cmd = (struct wmi_dfs_phyerr_offload_cmd *)skb->data;2785cmd->tlv_header =2786ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMD,2787sizeof(*cmd));27882789cmd->pdev_id = cpu_to_le32(pdev_id);27902791ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2792"WMI dfs phy err offload enable pdev id %d\n", pdev_id);27932794ret = ath12k_wmi_cmd_send(wmi, skb,2795WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID);2796if (ret) {2797ath12k_warn(ar->ab,2798"failed to send WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE cmd\n");2799dev_kfree_skb(skb);2800}28012802return ret;2803}28042805int ath12k_wmi_delba_send(struct ath12k *ar, u32 vdev_id, const u8 *mac,2806u32 tid, u32 initiator, u32 reason)2807{2808struct ath12k_wmi_pdev *wmi = ar->wmi;2809struct wmi_delba_send_cmd *cmd;2810struct sk_buff *skb;2811int ret;28122813skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2814if (!skb)2815return -ENOMEM;28162817cmd = (struct wmi_delba_send_cmd *)skb->data;2818cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_DELBA_SEND_CMD,2819sizeof(*cmd));2820cmd->vdev_id = cpu_to_le32(vdev_id);2821ether_addr_copy(cmd->peer_macaddr.addr, mac);2822cmd->tid = cpu_to_le32(tid);2823cmd->initiator = cpu_to_le32(initiator);2824cmd->reasoncode = cpu_to_le32(reason);28252826ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2827"wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n",2828vdev_id, mac, tid, initiator, reason);28292830ret = ath12k_wmi_cmd_send(wmi, skb, WMI_DELBA_SEND_CMDID);28312832if (ret) {2833ath12k_warn(ar->ab,2834"failed to send WMI_DELBA_SEND_CMDID cmd\n");2835dev_kfree_skb(skb);2836}28372838return ret;2839}28402841int ath12k_wmi_addba_set_resp(struct ath12k *ar, u32 vdev_id, const u8 *mac,2842u32 tid, u32 status)2843{2844struct ath12k_wmi_pdev *wmi = ar->wmi;2845struct wmi_addba_setresponse_cmd *cmd;2846struct sk_buff *skb;2847int ret;28482849skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2850if (!skb)2851return -ENOMEM;28522853cmd = (struct wmi_addba_setresponse_cmd *)skb->data;2854cmd->tlv_header =2855ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ADDBA_SETRESPONSE_CMD,2856sizeof(*cmd));2857cmd->vdev_id = cpu_to_le32(vdev_id);2858ether_addr_copy(cmd->peer_macaddr.addr, mac);2859cmd->tid = cpu_to_le32(tid);2860cmd->statuscode = cpu_to_le32(status);28612862ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2863"wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n",2864vdev_id, mac, tid, status);28652866ret = ath12k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SET_RESP_CMDID);28672868if (ret) {2869ath12k_warn(ar->ab,2870"failed to send WMI_ADDBA_SET_RESP_CMDID cmd\n");2871dev_kfree_skb(skb);2872}28732874return ret;2875}28762877int ath12k_wmi_addba_send(struct ath12k *ar, u32 vdev_id, const u8 *mac,2878u32 tid, u32 buf_size)2879{2880struct ath12k_wmi_pdev *wmi = ar->wmi;2881struct wmi_addba_send_cmd *cmd;2882struct sk_buff *skb;2883int ret;28842885skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2886if (!skb)2887return -ENOMEM;28882889cmd = (struct wmi_addba_send_cmd *)skb->data;2890cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ADDBA_SEND_CMD,2891sizeof(*cmd));2892cmd->vdev_id = cpu_to_le32(vdev_id);2893ether_addr_copy(cmd->peer_macaddr.addr, mac);2894cmd->tid = cpu_to_le32(tid);2895cmd->buffersize = cpu_to_le32(buf_size);28962897ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2898"wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n",2899vdev_id, mac, tid, buf_size);29002901ret = ath12k_wmi_cmd_send(wmi, skb, WMI_ADDBA_SEND_CMDID);29022903if (ret) {2904ath12k_warn(ar->ab,2905"failed to send WMI_ADDBA_SEND_CMDID cmd\n");2906dev_kfree_skb(skb);2907}29082909return ret;2910}29112912int ath12k_wmi_addba_clear_resp(struct ath12k *ar, u32 vdev_id, const u8 *mac)2913{2914struct ath12k_wmi_pdev *wmi = ar->wmi;2915struct wmi_addba_clear_resp_cmd *cmd;2916struct sk_buff *skb;2917int ret;29182919skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2920if (!skb)2921return -ENOMEM;29222923cmd = (struct wmi_addba_clear_resp_cmd *)skb->data;2924cmd->tlv_header =2925ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ADDBA_CLEAR_RESP_CMD,2926sizeof(*cmd));2927cmd->vdev_id = cpu_to_le32(vdev_id);2928ether_addr_copy(cmd->peer_macaddr.addr, mac);29292930ath12k_dbg(ar->ab, ATH12K_DBG_WMI,2931"wmi addba clear resp vdev_id 0x%X mac_addr %pM\n",2932vdev_id, mac);29332934ret = ath12k_wmi_cmd_send(wmi, skb, WMI_ADDBA_CLEAR_RESP_CMDID);29352936if (ret) {2937ath12k_warn(ar->ab,2938"failed to send WMI_ADDBA_CLEAR_RESP_CMDID cmd\n");2939dev_kfree_skb(skb);2940}29412942return ret;2943}29442945int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,2946struct ath12k_wmi_init_country_arg *arg)2947{2948struct ath12k_wmi_pdev *wmi = ar->wmi;2949struct wmi_init_country_cmd *cmd;2950struct sk_buff *skb;2951int ret;29522953skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));2954if (!skb)2955return -ENOMEM;29562957cmd = (struct wmi_init_country_cmd *)skb->data;2958cmd->tlv_header =2959ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SET_INIT_COUNTRY_CMD,2960sizeof(*cmd));29612962cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);29632964switch (arg->flags) {2965case ALPHA_IS_SET:2966cmd->init_cc_type = WMI_COUNTRY_INFO_TYPE_ALPHA;2967memcpy(&cmd->cc_info.alpha2, arg->cc_info.alpha2, 3);2968break;2969case CC_IS_SET:2970cmd->init_cc_type = cpu_to_le32(WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE);2971cmd->cc_info.country_code =2972cpu_to_le32(arg->cc_info.country_code);2973break;2974case REGDMN_IS_SET:2975cmd->init_cc_type = cpu_to_le32(WMI_COUNTRY_INFO_TYPE_REGDOMAIN);2976cmd->cc_info.regdom_id = cpu_to_le32(arg->cc_info.regdom_id);2977break;2978default:2979ret = -EINVAL;2980goto out;2981}29822983ret = ath12k_wmi_cmd_send(wmi, skb,2984WMI_SET_INIT_COUNTRY_CMDID);29852986out:2987if (ret) {2988ath12k_warn(ar->ab,2989"failed to send WMI_SET_INIT_COUNTRY CMD :%d\n",2990ret);2991dev_kfree_skb(skb);2992}29932994return ret;2995}29962997int2998ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id)2999{3000struct ath12k_wmi_pdev *wmi = ar->wmi;3001struct ath12k_base *ab = wmi->wmi_ab->ab;3002struct wmi_twt_enable_params_cmd *cmd;3003struct sk_buff *skb;3004int ret, len;30053006len = sizeof(*cmd);30073008skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);3009if (!skb)3010return -ENOMEM;30113012cmd = (struct wmi_twt_enable_params_cmd *)skb->data;3013cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_TWT_ENABLE_CMD,3014len);3015cmd->pdev_id = cpu_to_le32(pdev_id);3016cmd->sta_cong_timer_ms = cpu_to_le32(ATH12K_TWT_DEF_STA_CONG_TIMER_MS);3017cmd->default_slot_size = cpu_to_le32(ATH12K_TWT_DEF_DEFAULT_SLOT_SIZE);3018cmd->congestion_thresh_setup =3019cpu_to_le32(ATH12K_TWT_DEF_CONGESTION_THRESH_SETUP);3020cmd->congestion_thresh_teardown =3021cpu_to_le32(ATH12K_TWT_DEF_CONGESTION_THRESH_TEARDOWN);3022cmd->congestion_thresh_critical =3023cpu_to_le32(ATH12K_TWT_DEF_CONGESTION_THRESH_CRITICAL);3024cmd->interference_thresh_teardown =3025cpu_to_le32(ATH12K_TWT_DEF_INTERFERENCE_THRESH_TEARDOWN);3026cmd->interference_thresh_setup =3027cpu_to_le32(ATH12K_TWT_DEF_INTERFERENCE_THRESH_SETUP);3028cmd->min_no_sta_setup = cpu_to_le32(ATH12K_TWT_DEF_MIN_NO_STA_SETUP);3029cmd->min_no_sta_teardown = cpu_to_le32(ATH12K_TWT_DEF_MIN_NO_STA_TEARDOWN);3030cmd->no_of_bcast_mcast_slots =3031cpu_to_le32(ATH12K_TWT_DEF_NO_OF_BCAST_MCAST_SLOTS);3032cmd->min_no_twt_slots = cpu_to_le32(ATH12K_TWT_DEF_MIN_NO_TWT_SLOTS);3033cmd->max_no_sta_twt = cpu_to_le32(ATH12K_TWT_DEF_MAX_NO_STA_TWT);3034cmd->mode_check_interval = cpu_to_le32(ATH12K_TWT_DEF_MODE_CHECK_INTERVAL);3035cmd->add_sta_slot_interval = cpu_to_le32(ATH12K_TWT_DEF_ADD_STA_SLOT_INTERVAL);3036cmd->remove_sta_slot_interval =3037cpu_to_le32(ATH12K_TWT_DEF_REMOVE_STA_SLOT_INTERVAL);3038/* TODO add MBSSID support */3039cmd->mbss_support = 0;30403041ret = ath12k_wmi_cmd_send(wmi, skb,3042WMI_TWT_ENABLE_CMDID);3043if (ret) {3044ath12k_warn(ab, "Failed to send WMI_TWT_ENABLE_CMDID");3045dev_kfree_skb(skb);3046}3047return ret;3048}30493050int3051ath12k_wmi_send_twt_disable_cmd(struct ath12k *ar, u32 pdev_id)3052{3053struct ath12k_wmi_pdev *wmi = ar->wmi;3054struct ath12k_base *ab = wmi->wmi_ab->ab;3055struct wmi_twt_disable_params_cmd *cmd;3056struct sk_buff *skb;3057int ret, len;30583059len = sizeof(*cmd);30603061skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);3062if (!skb)3063return -ENOMEM;30643065cmd = (struct wmi_twt_disable_params_cmd *)skb->data;3066cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_TWT_DISABLE_CMD,3067len);3068cmd->pdev_id = cpu_to_le32(pdev_id);30693070ret = ath12k_wmi_cmd_send(wmi, skb,3071WMI_TWT_DISABLE_CMDID);3072if (ret) {3073ath12k_warn(ab, "Failed to send WMI_TWT_DISABLE_CMDID");3074dev_kfree_skb(skb);3075}3076return ret;3077}30783079int3080ath12k_wmi_send_obss_spr_cmd(struct ath12k *ar, u32 vdev_id,3081struct ieee80211_he_obss_pd *he_obss_pd)3082{3083struct ath12k_wmi_pdev *wmi = ar->wmi;3084struct ath12k_base *ab = wmi->wmi_ab->ab;3085struct wmi_obss_spatial_reuse_params_cmd *cmd;3086struct sk_buff *skb;3087int ret, len;30883089len = sizeof(*cmd);30903091skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);3092if (!skb)3093return -ENOMEM;30943095cmd = (struct wmi_obss_spatial_reuse_params_cmd *)skb->data;3096cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_OBSS_SPATIAL_REUSE_SET_CMD,3097len);3098cmd->vdev_id = cpu_to_le32(vdev_id);3099cmd->enable = cpu_to_le32(he_obss_pd->enable);3100cmd->obss_min = a_cpu_to_sle32(he_obss_pd->min_offset);3101cmd->obss_max = a_cpu_to_sle32(he_obss_pd->max_offset);31023103ret = ath12k_wmi_cmd_send(wmi, skb,3104WMI_PDEV_OBSS_PD_SPATIAL_REUSE_CMDID);3105if (ret) {3106ath12k_warn(ab,3107"Failed to send WMI_PDEV_OBSS_PD_SPATIAL_REUSE_CMDID");3108dev_kfree_skb(skb);3109}3110return ret;3111}31123113int ath12k_wmi_obss_color_cfg_cmd(struct ath12k *ar, u32 vdev_id,3114u8 bss_color, u32 period,3115bool enable)3116{3117struct ath12k_wmi_pdev *wmi = ar->wmi;3118struct ath12k_base *ab = wmi->wmi_ab->ab;3119struct wmi_obss_color_collision_cfg_params_cmd *cmd;3120struct sk_buff *skb;3121int ret, len;31223123len = sizeof(*cmd);31243125skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);3126if (!skb)3127return -ENOMEM;31283129cmd = (struct wmi_obss_color_collision_cfg_params_cmd *)skb->data;3130cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_OBSS_COLOR_COLLISION_DET_CONFIG,3131len);3132cmd->vdev_id = cpu_to_le32(vdev_id);3133cmd->evt_type = enable ? cpu_to_le32(ATH12K_OBSS_COLOR_COLLISION_DETECTION) :3134cpu_to_le32(ATH12K_OBSS_COLOR_COLLISION_DETECTION_DISABLE);3135cmd->current_bss_color = cpu_to_le32(bss_color);3136cmd->detection_period_ms = cpu_to_le32(period);3137cmd->scan_period_ms = cpu_to_le32(ATH12K_BSS_COLOR_COLLISION_SCAN_PERIOD_MS);3138cmd->free_slot_expiry_time_ms = 0;3139cmd->flags = 0;31403141ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3142"wmi_send_obss_color_collision_cfg id %d type %d bss_color %d detect_period %d scan_period %d\n",3143cmd->vdev_id, cmd->evt_type, cmd->current_bss_color,3144cmd->detection_period_ms, cmd->scan_period_ms);31453146ret = ath12k_wmi_cmd_send(wmi, skb,3147WMI_OBSS_COLOR_COLLISION_DET_CONFIG_CMDID);3148if (ret) {3149ath12k_warn(ab, "Failed to send WMI_OBSS_COLOR_COLLISION_DET_CONFIG_CMDID");3150dev_kfree_skb(skb);3151}3152return ret;3153}31543155int ath12k_wmi_send_bss_color_change_enable_cmd(struct ath12k *ar, u32 vdev_id,3156bool enable)3157{3158struct ath12k_wmi_pdev *wmi = ar->wmi;3159struct ath12k_base *ab = wmi->wmi_ab->ab;3160struct wmi_bss_color_change_enable_params_cmd *cmd;3161struct sk_buff *skb;3162int ret, len;31633164len = sizeof(*cmd);31653166skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);3167if (!skb)3168return -ENOMEM;31693170cmd = (struct wmi_bss_color_change_enable_params_cmd *)skb->data;3171cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_BSS_COLOR_CHANGE_ENABLE,3172len);3173cmd->vdev_id = cpu_to_le32(vdev_id);3174cmd->enable = enable ? cpu_to_le32(1) : 0;31753176ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3177"wmi_send_bss_color_change_enable id %d enable %d\n",3178cmd->vdev_id, cmd->enable);31793180ret = ath12k_wmi_cmd_send(wmi, skb,3181WMI_BSS_COLOR_CHANGE_ENABLE_CMDID);3182if (ret) {3183ath12k_warn(ab, "Failed to send WMI_BSS_COLOR_CHANGE_ENABLE_CMDID");3184dev_kfree_skb(skb);3185}3186return ret;3187}31883189int ath12k_wmi_fils_discovery_tmpl(struct ath12k *ar, u32 vdev_id,3190struct sk_buff *tmpl)3191{3192struct wmi_tlv *tlv;3193struct sk_buff *skb;3194void *ptr;3195int ret, len;3196size_t aligned_len;3197struct wmi_fils_discovery_tmpl_cmd *cmd;31983199aligned_len = roundup(tmpl->len, 4);3200len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len;32013202ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3203"WMI vdev %i set FILS discovery template\n", vdev_id);32043205skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len);3206if (!skb)3207return -ENOMEM;32083209cmd = (struct wmi_fils_discovery_tmpl_cmd *)skb->data;3210cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_FILS_DISCOVERY_TMPL_CMD,3211sizeof(*cmd));3212cmd->vdev_id = cpu_to_le32(vdev_id);3213cmd->buf_len = cpu_to_le32(tmpl->len);3214ptr = skb->data + sizeof(*cmd);32153216tlv = ptr;3217tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, aligned_len);3218memcpy(tlv->value, tmpl->data, tmpl->len);32193220ret = ath12k_wmi_cmd_send(ar->wmi, skb, WMI_FILS_DISCOVERY_TMPL_CMDID);3221if (ret) {3222ath12k_warn(ar->ab,3223"WMI vdev %i failed to send FILS discovery template command\n",3224vdev_id);3225dev_kfree_skb(skb);3226}3227return ret;3228}32293230int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,3231struct sk_buff *tmpl)3232{3233struct wmi_probe_tmpl_cmd *cmd;3234struct ath12k_wmi_bcn_prb_info_params *probe_info;3235struct wmi_tlv *tlv;3236struct sk_buff *skb;3237#if defined(__linux__)3238void *ptr;3239#elif defined(__FreeBSD__)3240u8 *ptr;3241#endif3242int ret, len;3243size_t aligned_len = roundup(tmpl->len, 4);32443245ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3246"WMI vdev %i set probe response template\n", vdev_id);32473248len = sizeof(*cmd) + sizeof(*probe_info) + TLV_HDR_SIZE + aligned_len;32493250skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len);3251if (!skb)3252return -ENOMEM;32533254cmd = (struct wmi_probe_tmpl_cmd *)skb->data;3255cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PRB_TMPL_CMD,3256sizeof(*cmd));3257cmd->vdev_id = cpu_to_le32(vdev_id);3258cmd->buf_len = cpu_to_le32(tmpl->len);32593260ptr = skb->data + sizeof(*cmd);32613262#if defined(__linux__)3263probe_info = ptr;3264#elif defined(__FreeBSD__)3265probe_info = (void *)ptr;3266#endif3267len = sizeof(*probe_info);3268probe_info->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_BCN_PRB_INFO,3269len);3270probe_info->caps = 0;3271probe_info->erp = 0;32723273ptr += sizeof(*probe_info);32743275#if defined(__linux__)3276tlv = ptr;3277#elif defined(__FreeBSD__)3278tlv = (void *)ptr;3279#endif3280tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, aligned_len);3281memcpy(tlv->value, tmpl->data, tmpl->len);32823283ret = ath12k_wmi_cmd_send(ar->wmi, skb, WMI_PRB_TMPL_CMDID);3284if (ret) {3285ath12k_warn(ar->ab,3286"WMI vdev %i failed to send probe response template command\n",3287vdev_id);3288dev_kfree_skb(skb);3289}3290return ret;3291}32923293int ath12k_wmi_fils_discovery(struct ath12k *ar, u32 vdev_id, u32 interval,3294bool unsol_bcast_probe_resp_enabled)3295{3296struct sk_buff *skb;3297int ret, len;3298struct wmi_fils_discovery_cmd *cmd;32993300ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3301"WMI vdev %i set %s interval to %u TU\n",3302vdev_id, unsol_bcast_probe_resp_enabled ?3303"unsolicited broadcast probe response" : "FILS discovery",3304interval);33053306len = sizeof(*cmd);3307skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, len);3308if (!skb)3309return -ENOMEM;33103311cmd = (struct wmi_fils_discovery_cmd *)skb->data;3312cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ENABLE_FILS_CMD,3313len);3314cmd->vdev_id = cpu_to_le32(vdev_id);3315cmd->interval = cpu_to_le32(interval);3316cmd->config = cpu_to_le32(unsol_bcast_probe_resp_enabled);33173318ret = ath12k_wmi_cmd_send(ar->wmi, skb, WMI_ENABLE_FILS_CMDID);3319if (ret) {3320ath12k_warn(ar->ab,3321"WMI vdev %i failed to send FILS discovery enable/disable command\n",3322vdev_id);3323dev_kfree_skb(skb);3324}3325return ret;3326}33273328static void3329ath12k_fill_band_to_mac_param(struct ath12k_base *soc,3330struct ath12k_wmi_pdev_band_arg *arg)3331{3332u8 i;3333struct ath12k_wmi_hal_reg_capabilities_ext_arg *hal_reg_cap;3334struct ath12k_pdev *pdev;33353336for (i = 0; i < soc->num_radios; i++) {3337pdev = &soc->pdevs[i];3338hal_reg_cap = &soc->hal_reg_cap[i];3339arg[i].pdev_id = pdev->pdev_id;33403341switch (pdev->cap.supported_bands) {3342case WMI_HOST_WLAN_2G_5G_CAP:3343arg[i].start_freq = hal_reg_cap->low_2ghz_chan;3344arg[i].end_freq = hal_reg_cap->high_5ghz_chan;3345break;3346case WMI_HOST_WLAN_2G_CAP:3347arg[i].start_freq = hal_reg_cap->low_2ghz_chan;3348arg[i].end_freq = hal_reg_cap->high_2ghz_chan;3349break;3350case WMI_HOST_WLAN_5G_CAP:3351arg[i].start_freq = hal_reg_cap->low_5ghz_chan;3352arg[i].end_freq = hal_reg_cap->high_5ghz_chan;3353break;3354default:3355break;3356}3357}3358}33593360static void3361ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cfg,3362struct ath12k_wmi_resource_config_arg *tg_cfg)3363{3364wmi_cfg->num_vdevs = cpu_to_le32(tg_cfg->num_vdevs);3365wmi_cfg->num_peers = cpu_to_le32(tg_cfg->num_peers);3366wmi_cfg->num_offload_peers = cpu_to_le32(tg_cfg->num_offload_peers);3367wmi_cfg->num_offload_reorder_buffs =3368cpu_to_le32(tg_cfg->num_offload_reorder_buffs);3369wmi_cfg->num_peer_keys = cpu_to_le32(tg_cfg->num_peer_keys);3370wmi_cfg->num_tids = cpu_to_le32(tg_cfg->num_tids);3371wmi_cfg->ast_skid_limit = cpu_to_le32(tg_cfg->ast_skid_limit);3372wmi_cfg->tx_chain_mask = cpu_to_le32(tg_cfg->tx_chain_mask);3373wmi_cfg->rx_chain_mask = cpu_to_le32(tg_cfg->rx_chain_mask);3374wmi_cfg->rx_timeout_pri[0] = cpu_to_le32(tg_cfg->rx_timeout_pri[0]);3375wmi_cfg->rx_timeout_pri[1] = cpu_to_le32(tg_cfg->rx_timeout_pri[1]);3376wmi_cfg->rx_timeout_pri[2] = cpu_to_le32(tg_cfg->rx_timeout_pri[2]);3377wmi_cfg->rx_timeout_pri[3] = cpu_to_le32(tg_cfg->rx_timeout_pri[3]);3378wmi_cfg->rx_decap_mode = cpu_to_le32(tg_cfg->rx_decap_mode);3379wmi_cfg->scan_max_pending_req = cpu_to_le32(tg_cfg->scan_max_pending_req);3380wmi_cfg->bmiss_offload_max_vdev = cpu_to_le32(tg_cfg->bmiss_offload_max_vdev);3381wmi_cfg->roam_offload_max_vdev = cpu_to_le32(tg_cfg->roam_offload_max_vdev);3382wmi_cfg->roam_offload_max_ap_profiles =3383cpu_to_le32(tg_cfg->roam_offload_max_ap_profiles);3384wmi_cfg->num_mcast_groups = cpu_to_le32(tg_cfg->num_mcast_groups);3385wmi_cfg->num_mcast_table_elems = cpu_to_le32(tg_cfg->num_mcast_table_elems);3386wmi_cfg->mcast2ucast_mode = cpu_to_le32(tg_cfg->mcast2ucast_mode);3387wmi_cfg->tx_dbg_log_size = cpu_to_le32(tg_cfg->tx_dbg_log_size);3388wmi_cfg->num_wds_entries = cpu_to_le32(tg_cfg->num_wds_entries);3389wmi_cfg->dma_burst_size = cpu_to_le32(tg_cfg->dma_burst_size);3390wmi_cfg->mac_aggr_delim = cpu_to_le32(tg_cfg->mac_aggr_delim);3391wmi_cfg->rx_skip_defrag_timeout_dup_detection_check =3392cpu_to_le32(tg_cfg->rx_skip_defrag_timeout_dup_detection_check);3393wmi_cfg->vow_config = cpu_to_le32(tg_cfg->vow_config);3394wmi_cfg->gtk_offload_max_vdev = cpu_to_le32(tg_cfg->gtk_offload_max_vdev);3395wmi_cfg->num_msdu_desc = cpu_to_le32(tg_cfg->num_msdu_desc);3396wmi_cfg->max_frag_entries = cpu_to_le32(tg_cfg->max_frag_entries);3397wmi_cfg->num_tdls_vdevs = cpu_to_le32(tg_cfg->num_tdls_vdevs);3398wmi_cfg->num_tdls_conn_table_entries =3399cpu_to_le32(tg_cfg->num_tdls_conn_table_entries);3400wmi_cfg->beacon_tx_offload_max_vdev =3401cpu_to_le32(tg_cfg->beacon_tx_offload_max_vdev);3402wmi_cfg->num_multicast_filter_entries =3403cpu_to_le32(tg_cfg->num_multicast_filter_entries);3404wmi_cfg->num_wow_filters = cpu_to_le32(tg_cfg->num_wow_filters);3405wmi_cfg->num_keep_alive_pattern = cpu_to_le32(tg_cfg->num_keep_alive_pattern);3406wmi_cfg->keep_alive_pattern_size = cpu_to_le32(tg_cfg->keep_alive_pattern_size);3407wmi_cfg->max_tdls_concurrent_sleep_sta =3408cpu_to_le32(tg_cfg->max_tdls_concurrent_sleep_sta);3409wmi_cfg->max_tdls_concurrent_buffer_sta =3410cpu_to_le32(tg_cfg->max_tdls_concurrent_buffer_sta);3411wmi_cfg->wmi_send_separate = cpu_to_le32(tg_cfg->wmi_send_separate);3412wmi_cfg->num_ocb_vdevs = cpu_to_le32(tg_cfg->num_ocb_vdevs);3413wmi_cfg->num_ocb_channels = cpu_to_le32(tg_cfg->num_ocb_channels);3414wmi_cfg->num_ocb_schedules = cpu_to_le32(tg_cfg->num_ocb_schedules);3415wmi_cfg->bpf_instruction_size = cpu_to_le32(tg_cfg->bpf_instruction_size);3416wmi_cfg->max_bssid_rx_filters = cpu_to_le32(tg_cfg->max_bssid_rx_filters);3417wmi_cfg->use_pdev_id = cpu_to_le32(tg_cfg->use_pdev_id);3418wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config);3419wmi_cfg->peer_map_unmap_version = cpu_to_le32(tg_cfg->peer_map_unmap_version);3420wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params);3421wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count);3422wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count);3423wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported <<3424WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT);3425}34263427static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi,3428struct ath12k_wmi_init_cmd_arg *arg)3429{3430struct ath12k_base *ab = wmi->wmi_ab->ab;3431struct sk_buff *skb;3432struct wmi_init_cmd *cmd;3433struct ath12k_wmi_resource_config_params *cfg;3434struct ath12k_wmi_pdev_set_hw_mode_cmd *hw_mode;3435struct ath12k_wmi_pdev_band_to_mac_params *band_to_mac;3436struct ath12k_wmi_host_mem_chunk_params *host_mem_chunks;3437struct wmi_tlv *tlv;3438size_t ret, len;3439#if defined(__linux__)3440void *ptr;3441#elif defined(__FreeBSD__)3442u8 *ptr;3443#endif3444u32 hw_mode_len = 0;3445u16 idx;34463447if (arg->hw_mode_id != WMI_HOST_HW_MODE_MAX)3448hw_mode_len = sizeof(*hw_mode) + TLV_HDR_SIZE +3449(arg->num_band_to_mac * sizeof(*band_to_mac));34503451len = sizeof(*cmd) + TLV_HDR_SIZE + sizeof(*cfg) + hw_mode_len +3452(arg->num_mem_chunks ? (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS) : 0);34533454skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);3455if (!skb)3456return -ENOMEM;34573458cmd = (struct wmi_init_cmd *)skb->data;34593460cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_INIT_CMD,3461sizeof(*cmd));34623463ptr = skb->data + sizeof(*cmd);3464#if defined(__linux__)3465cfg = ptr;3466#elif defined(__FreeBSD__)3467cfg = (void *)ptr;3468#endif34693470ath12k_wmi_copy_resource_config(cfg, &arg->res_cfg);34713472cfg->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_RESOURCE_CONFIG,3473sizeof(*cfg));34743475ptr += sizeof(*cfg);3476#if defined(__linux__)3477host_mem_chunks = ptr + TLV_HDR_SIZE;3478#elif defined(__FreeBSD__)3479host_mem_chunks = (void *)(ptr + TLV_HDR_SIZE);3480#endif3481len = sizeof(struct ath12k_wmi_host_mem_chunk_params);34823483for (idx = 0; idx < arg->num_mem_chunks; ++idx) {3484host_mem_chunks[idx].tlv_header =3485ath12k_wmi_tlv_hdr(WMI_TAG_WLAN_HOST_MEMORY_CHUNK,3486len);34873488host_mem_chunks[idx].ptr = cpu_to_le32(arg->mem_chunks[idx].paddr);3489host_mem_chunks[idx].size = cpu_to_le32(arg->mem_chunks[idx].len);3490host_mem_chunks[idx].req_id = cpu_to_le32(arg->mem_chunks[idx].req_id);34913492ath12k_dbg(ab, ATH12K_DBG_WMI,3493#if defined(__linux__)3494"WMI host mem chunk req_id %d paddr 0x%llx len %d\n",3495#elif defined(__FreeBSD__)3496"WMI host mem chunk req_id %d paddr 0x%jx len %d\n",3497#endif3498arg->mem_chunks[idx].req_id,3499#if defined(__linux__)3500(u64)arg->mem_chunks[idx].paddr,3501#elif defined(__FreeBSD__)3502(uintmax_t)arg->mem_chunks[idx].paddr,3503#endif3504arg->mem_chunks[idx].len);3505}3506cmd->num_host_mem_chunks = cpu_to_le32(arg->num_mem_chunks);3507len = sizeof(struct ath12k_wmi_host_mem_chunk_params) * arg->num_mem_chunks;35083509/* num_mem_chunks is zero */3510#if defined(__linux__)3511tlv = ptr;3512#elif defined(__FreeBSD__)3513tlv = (void *)ptr;3514#endif3515tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);3516ptr += TLV_HDR_SIZE + len;35173518if (arg->hw_mode_id != WMI_HOST_HW_MODE_MAX) {3519hw_mode = (struct ath12k_wmi_pdev_set_hw_mode_cmd *)ptr;3520hw_mode->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_HW_MODE_CMD,3521sizeof(*hw_mode));35223523hw_mode->hw_mode_index = cpu_to_le32(arg->hw_mode_id);3524hw_mode->num_band_to_mac = cpu_to_le32(arg->num_band_to_mac);35253526ptr += sizeof(*hw_mode);35273528len = arg->num_band_to_mac * sizeof(*band_to_mac);3529#if defined(__linux__)3530tlv = ptr;3531#elif defined(__FreeBSD__)3532tlv = (void *)ptr;3533#endif3534tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);35353536ptr += TLV_HDR_SIZE;3537len = sizeof(*band_to_mac);35383539for (idx = 0; idx < arg->num_band_to_mac; idx++) {3540band_to_mac = (void *)ptr;35413542band_to_mac->tlv_header =3543ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_BAND_TO_MAC,3544len);3545band_to_mac->pdev_id = cpu_to_le32(arg->band_to_mac[idx].pdev_id);3546band_to_mac->start_freq =3547cpu_to_le32(arg->band_to_mac[idx].start_freq);3548band_to_mac->end_freq =3549cpu_to_le32(arg->band_to_mac[idx].end_freq);3550ptr += sizeof(*band_to_mac);3551}3552}35533554ret = ath12k_wmi_cmd_send(wmi, skb, WMI_INIT_CMDID);3555if (ret) {3556ath12k_warn(ab, "failed to send WMI_INIT_CMDID\n");3557dev_kfree_skb(skb);3558}35593560return ret;3561}35623563int ath12k_wmi_pdev_lro_cfg(struct ath12k *ar,3564int pdev_id)3565{3566struct ath12k_wmi_pdev_lro_config_cmd *cmd;3567struct sk_buff *skb;3568int ret;35693570skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));3571if (!skb)3572return -ENOMEM;35733574cmd = (struct ath12k_wmi_pdev_lro_config_cmd *)skb->data;3575cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_LRO_INFO_CMD,3576sizeof(*cmd));35773578get_random_bytes(cmd->th_4, sizeof(cmd->th_4));3579get_random_bytes(cmd->th_6, sizeof(cmd->th_6));35803581cmd->pdev_id = cpu_to_le32(pdev_id);35823583ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3584"WMI lro cfg cmd pdev_id 0x%x\n", pdev_id);35853586ret = ath12k_wmi_cmd_send(ar->wmi, skb, WMI_LRO_CONFIG_CMDID);3587if (ret) {3588ath12k_warn(ar->ab,3589"failed to send lro cfg req wmi cmd\n");3590goto err;3591}35923593return 0;3594err:3595dev_kfree_skb(skb);3596return ret;3597}35983599int ath12k_wmi_wait_for_service_ready(struct ath12k_base *ab)3600{3601unsigned long time_left;36023603time_left = wait_for_completion_timeout(&ab->wmi_ab.service_ready,3604WMI_SERVICE_READY_TIMEOUT_HZ);3605if (!time_left)3606return -ETIMEDOUT;36073608return 0;3609}36103611int ath12k_wmi_wait_for_unified_ready(struct ath12k_base *ab)3612{3613unsigned long time_left;36143615time_left = wait_for_completion_timeout(&ab->wmi_ab.unified_ready,3616WMI_SERVICE_READY_TIMEOUT_HZ);3617if (!time_left)3618return -ETIMEDOUT;36193620return 0;3621}36223623int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,3624enum wmi_host_hw_mode_config_type mode)3625{3626struct ath12k_wmi_pdev_set_hw_mode_cmd *cmd;3627struct sk_buff *skb;3628struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;3629int len;3630int ret;36313632len = sizeof(*cmd);36333634skb = ath12k_wmi_alloc_skb(wmi_ab, len);3635if (!skb)3636return -ENOMEM;36373638cmd = (struct ath12k_wmi_pdev_set_hw_mode_cmd *)skb->data;36393640cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_HW_MODE_CMD,3641sizeof(*cmd));36423643cmd->pdev_id = WMI_PDEV_ID_SOC;3644cmd->hw_mode_index = cpu_to_le32(mode);36453646ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_HW_MODE_CMDID);3647if (ret) {3648ath12k_warn(ab, "failed to send WMI_PDEV_SET_HW_MODE_CMDID\n");3649dev_kfree_skb(skb);3650}36513652return ret;3653}36543655int ath12k_wmi_cmd_init(struct ath12k_base *ab)3656{3657struct ath12k_wmi_base *wmi_sc = &ab->wmi_ab;3658struct ath12k_wmi_init_cmd_arg arg = {};36593660if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT,3661ab->wmi_ab.svc_map))3662arg.res_cfg.is_reg_cc_ext_event_supported = true;36633664ab->hw_params->wmi_init(ab, &arg.res_cfg);36653666arg.num_mem_chunks = wmi_sc->num_mem_chunks;3667arg.hw_mode_id = wmi_sc->preferred_hw_mode;3668arg.mem_chunks = wmi_sc->mem_chunks;36693670if (ab->hw_params->single_pdev_only)3671arg.hw_mode_id = WMI_HOST_HW_MODE_MAX;36723673arg.num_band_to_mac = ab->num_radios;3674ath12k_fill_band_to_mac_param(ab, arg.band_to_mac);36753676return ath12k_init_cmd_send(&wmi_sc->wmi[0], &arg);3677}36783679int ath12k_wmi_vdev_spectral_conf(struct ath12k *ar,3680struct ath12k_wmi_vdev_spectral_conf_arg *arg)3681{3682struct ath12k_wmi_vdev_spectral_conf_cmd *cmd;3683struct sk_buff *skb;3684int ret;36853686skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));3687if (!skb)3688return -ENOMEM;36893690cmd = (struct ath12k_wmi_vdev_spectral_conf_cmd *)skb->data;3691cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_SPECTRAL_CONFIGURE_CMD,3692sizeof(*cmd));3693cmd->vdev_id = cpu_to_le32(arg->vdev_id);3694cmd->scan_count = cpu_to_le32(arg->scan_count);3695cmd->scan_period = cpu_to_le32(arg->scan_period);3696cmd->scan_priority = cpu_to_le32(arg->scan_priority);3697cmd->scan_fft_size = cpu_to_le32(arg->scan_fft_size);3698cmd->scan_gc_ena = cpu_to_le32(arg->scan_gc_ena);3699cmd->scan_restart_ena = cpu_to_le32(arg->scan_restart_ena);3700cmd->scan_noise_floor_ref = cpu_to_le32(arg->scan_noise_floor_ref);3701cmd->scan_init_delay = cpu_to_le32(arg->scan_init_delay);3702cmd->scan_nb_tone_thr = cpu_to_le32(arg->scan_nb_tone_thr);3703cmd->scan_str_bin_thr = cpu_to_le32(arg->scan_str_bin_thr);3704cmd->scan_wb_rpt_mode = cpu_to_le32(arg->scan_wb_rpt_mode);3705cmd->scan_rssi_rpt_mode = cpu_to_le32(arg->scan_rssi_rpt_mode);3706cmd->scan_rssi_thr = cpu_to_le32(arg->scan_rssi_thr);3707cmd->scan_pwr_format = cpu_to_le32(arg->scan_pwr_format);3708cmd->scan_rpt_mode = cpu_to_le32(arg->scan_rpt_mode);3709cmd->scan_bin_scale = cpu_to_le32(arg->scan_bin_scale);3710cmd->scan_dbm_adj = cpu_to_le32(arg->scan_dbm_adj);3711cmd->scan_chn_mask = cpu_to_le32(arg->scan_chn_mask);37123713ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3714"WMI spectral scan config cmd vdev_id 0x%x\n",3715arg->vdev_id);37163717ret = ath12k_wmi_cmd_send(ar->wmi, skb,3718WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID);3719if (ret) {3720ath12k_warn(ar->ab,3721"failed to send spectral scan config wmi cmd\n");3722goto err;3723}37243725return 0;3726err:3727dev_kfree_skb(skb);3728return ret;3729}37303731int ath12k_wmi_vdev_spectral_enable(struct ath12k *ar, u32 vdev_id,3732u32 trigger, u32 enable)3733{3734struct ath12k_wmi_vdev_spectral_enable_cmd *cmd;3735struct sk_buff *skb;3736int ret;37373738skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));3739if (!skb)3740return -ENOMEM;37413742cmd = (struct ath12k_wmi_vdev_spectral_enable_cmd *)skb->data;3743cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_VDEV_SPECTRAL_ENABLE_CMD,3744sizeof(*cmd));37453746cmd->vdev_id = cpu_to_le32(vdev_id);3747cmd->trigger_cmd = cpu_to_le32(trigger);3748cmd->enable_cmd = cpu_to_le32(enable);37493750ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3751"WMI spectral enable cmd vdev id 0x%x\n",3752vdev_id);37533754ret = ath12k_wmi_cmd_send(ar->wmi, skb,3755WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID);3756if (ret) {3757ath12k_warn(ar->ab,3758"failed to send spectral enable wmi cmd\n");3759goto err;3760}37613762return 0;3763err:3764dev_kfree_skb(skb);3765return ret;3766}37673768int ath12k_wmi_pdev_dma_ring_cfg(struct ath12k *ar,3769struct ath12k_wmi_pdev_dma_ring_cfg_arg *arg)3770{3771struct ath12k_wmi_pdev_dma_ring_cfg_req_cmd *cmd;3772struct sk_buff *skb;3773int ret;37743775skb = ath12k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));3776if (!skb)3777return -ENOMEM;37783779cmd = (struct ath12k_wmi_pdev_dma_ring_cfg_req_cmd *)skb->data;3780cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_DMA_RING_CFG_REQ,3781sizeof(*cmd));37823783cmd->pdev_id = cpu_to_le32(DP_SW2HW_MACID(arg->pdev_id));3784cmd->module_id = cpu_to_le32(arg->module_id);3785cmd->base_paddr_lo = cpu_to_le32(arg->base_paddr_lo);3786cmd->base_paddr_hi = cpu_to_le32(arg->base_paddr_hi);3787cmd->head_idx_paddr_lo = cpu_to_le32(arg->head_idx_paddr_lo);3788cmd->head_idx_paddr_hi = cpu_to_le32(arg->head_idx_paddr_hi);3789cmd->tail_idx_paddr_lo = cpu_to_le32(arg->tail_idx_paddr_lo);3790cmd->tail_idx_paddr_hi = cpu_to_le32(arg->tail_idx_paddr_hi);3791cmd->num_elems = cpu_to_le32(arg->num_elems);3792cmd->buf_size = cpu_to_le32(arg->buf_size);3793cmd->num_resp_per_event = cpu_to_le32(arg->num_resp_per_event);3794cmd->event_timeout_ms = cpu_to_le32(arg->event_timeout_ms);37953796ath12k_dbg(ar->ab, ATH12K_DBG_WMI,3797"WMI DMA ring cfg req cmd pdev_id 0x%x\n",3798arg->pdev_id);37993800ret = ath12k_wmi_cmd_send(ar->wmi, skb,3801WMI_PDEV_DMA_RING_CFG_REQ_CMDID);3802if (ret) {3803ath12k_warn(ar->ab,3804"failed to send dma ring cfg req wmi cmd\n");3805goto err;3806}38073808return 0;3809err:3810dev_kfree_skb(skb);3811return ret;3812}38133814static int ath12k_wmi_dma_buf_entry_parse(struct ath12k_base *soc,3815u16 tag, u16 len,3816const void *ptr, void *data)3817{3818struct ath12k_wmi_dma_buf_release_arg *arg = data;38193820if (tag != WMI_TAG_DMA_BUF_RELEASE_ENTRY)3821return -EPROTO;38223823if (arg->num_buf_entry >= le32_to_cpu(arg->fixed.num_buf_release_entry))3824return -ENOBUFS;38253826arg->num_buf_entry++;3827return 0;3828}38293830static int ath12k_wmi_dma_buf_meta_parse(struct ath12k_base *soc,3831u16 tag, u16 len,3832const void *ptr, void *data)3833{3834struct ath12k_wmi_dma_buf_release_arg *arg = data;38353836if (tag != WMI_TAG_DMA_BUF_RELEASE_SPECTRAL_META_DATA)3837return -EPROTO;38383839if (arg->num_meta >= le32_to_cpu(arg->fixed.num_meta_data_entry))3840return -ENOBUFS;38413842arg->num_meta++;38433844return 0;3845}38463847static int ath12k_wmi_dma_buf_parse(struct ath12k_base *ab,3848u16 tag, u16 len,3849const void *ptr, void *data)3850{3851struct ath12k_wmi_dma_buf_release_arg *arg = data;3852const struct ath12k_wmi_dma_buf_release_fixed_params *fixed;3853u32 pdev_id;3854int ret;38553856switch (tag) {3857case WMI_TAG_DMA_BUF_RELEASE:3858fixed = ptr;3859arg->fixed = *fixed;3860pdev_id = DP_HW2SW_MACID(le32_to_cpu(fixed->pdev_id));3861arg->fixed.pdev_id = cpu_to_le32(pdev_id);3862break;3863case WMI_TAG_ARRAY_STRUCT:3864if (!arg->buf_entry_done) {3865arg->num_buf_entry = 0;3866arg->buf_entry = ptr;38673868ret = ath12k_wmi_tlv_iter(ab, ptr, len,3869ath12k_wmi_dma_buf_entry_parse,3870arg);3871if (ret) {3872ath12k_warn(ab, "failed to parse dma buf entry tlv %d\n",3873ret);3874return ret;3875}38763877arg->buf_entry_done = true;3878} else if (!arg->meta_data_done) {3879arg->num_meta = 0;3880arg->meta_data = ptr;38813882ret = ath12k_wmi_tlv_iter(ab, ptr, len,3883ath12k_wmi_dma_buf_meta_parse,3884arg);3885if (ret) {3886ath12k_warn(ab, "failed to parse dma buf meta tlv %d\n",3887ret);3888return ret;3889}38903891arg->meta_data_done = true;3892}3893break;3894default:3895break;3896}3897return 0;3898}38993900static void ath12k_wmi_pdev_dma_ring_buf_release_event(struct ath12k_base *ab,3901struct sk_buff *skb)3902{3903struct ath12k_wmi_dma_buf_release_arg arg = {};3904struct ath12k_dbring_buf_release_event param;3905int ret;39063907ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,3908ath12k_wmi_dma_buf_parse,3909&arg);3910if (ret) {3911ath12k_warn(ab, "failed to parse dma buf release tlv %d\n", ret);3912return;3913}39143915param.fixed = arg.fixed;3916param.buf_entry = arg.buf_entry;3917param.num_buf_entry = arg.num_buf_entry;3918param.meta_data = arg.meta_data;3919param.num_meta = arg.num_meta;39203921ret = ath12k_dbring_buffer_release_event(ab, ¶m);3922if (ret) {3923ath12k_warn(ab, "failed to handle dma buf release event %d\n", ret);3924return;3925}3926}39273928static int ath12k_wmi_hw_mode_caps_parse(struct ath12k_base *soc,3929u16 tag, u16 len,3930const void *ptr, void *data)3931{3932struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;3933struct ath12k_wmi_hw_mode_cap_params *hw_mode_cap;3934u32 phy_map = 0;39353936if (tag != WMI_TAG_HW_MODE_CAPABILITIES)3937return -EPROTO;39383939if (svc_rdy_ext->n_hw_mode_caps >= svc_rdy_ext->arg.num_hw_modes)3940return -ENOBUFS;39413942hw_mode_cap = container_of(ptr, struct ath12k_wmi_hw_mode_cap_params,3943hw_mode_id);3944svc_rdy_ext->n_hw_mode_caps++;39453946phy_map = le32_to_cpu(hw_mode_cap->phy_id_map);3947svc_rdy_ext->tot_phy_id += fls(phy_map);39483949return 0;3950}39513952static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,3953u16 len, const void *ptr, void *data)3954{3955struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;3956const struct ath12k_wmi_hw_mode_cap_params *hw_mode_caps;3957enum wmi_host_hw_mode_config_type mode, pref;3958u32 i;3959int ret;39603961svc_rdy_ext->n_hw_mode_caps = 0;3962svc_rdy_ext->hw_mode_caps = ptr;39633964ret = ath12k_wmi_tlv_iter(soc, ptr, len,3965ath12k_wmi_hw_mode_caps_parse,3966svc_rdy_ext);3967if (ret) {3968ath12k_warn(soc, "failed to parse tlv %d\n", ret);3969return ret;3970}39713972for (i = 0 ; i < svc_rdy_ext->n_hw_mode_caps; i++) {3973hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i];3974mode = le32_to_cpu(hw_mode_caps->hw_mode_id);39753976if (mode >= WMI_HOST_HW_MODE_MAX)3977continue;39783979pref = soc->wmi_ab.preferred_hw_mode;39803981if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) {3982svc_rdy_ext->pref_hw_mode_caps = *hw_mode_caps;3983soc->wmi_ab.preferred_hw_mode = mode;3984}3985}39863987ath12k_dbg(soc, ATH12K_DBG_WMI, "preferred_hw_mode:%d\n",3988soc->wmi_ab.preferred_hw_mode);3989if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX)3990return -EINVAL;39913992return 0;3993}39943995static int ath12k_wmi_mac_phy_caps_parse(struct ath12k_base *soc,3996u16 tag, u16 len,3997const void *ptr, void *data)3998{3999struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;40004001if (tag != WMI_TAG_MAC_PHY_CAPABILITIES)4002return -EPROTO;40034004if (svc_rdy_ext->n_mac_phy_caps >= svc_rdy_ext->tot_phy_id)4005return -ENOBUFS;40064007len = min_t(u16, len, sizeof(struct ath12k_wmi_mac_phy_caps_params));4008if (!svc_rdy_ext->n_mac_phy_caps) {4009svc_rdy_ext->mac_phy_caps = kzalloc((svc_rdy_ext->tot_phy_id) * len,4010GFP_ATOMIC);4011if (!svc_rdy_ext->mac_phy_caps)4012return -ENOMEM;4013}40144015memcpy(svc_rdy_ext->mac_phy_caps + svc_rdy_ext->n_mac_phy_caps, ptr, len);4016svc_rdy_ext->n_mac_phy_caps++;4017return 0;4018}40194020static int ath12k_wmi_ext_hal_reg_caps_parse(struct ath12k_base *soc,4021u16 tag, u16 len,4022const void *ptr, void *data)4023{4024struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;40254026if (tag != WMI_TAG_HAL_REG_CAPABILITIES_EXT)4027return -EPROTO;40284029if (svc_rdy_ext->n_ext_hal_reg_caps >= svc_rdy_ext->arg.num_phy)4030return -ENOBUFS;40314032svc_rdy_ext->n_ext_hal_reg_caps++;4033return 0;4034}40354036static int ath12k_wmi_ext_hal_reg_caps(struct ath12k_base *soc,4037u16 len, const void *ptr, void *data)4038{4039struct ath12k_wmi_pdev *wmi_handle = &soc->wmi_ab.wmi[0];4040struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;4041struct ath12k_wmi_hal_reg_capabilities_ext_arg reg_cap;4042int ret;4043u32 i;40444045svc_rdy_ext->n_ext_hal_reg_caps = 0;4046svc_rdy_ext->ext_hal_reg_caps = ptr;4047ret = ath12k_wmi_tlv_iter(soc, ptr, len,4048ath12k_wmi_ext_hal_reg_caps_parse,4049svc_rdy_ext);4050if (ret) {4051ath12k_warn(soc, "failed to parse tlv %d\n", ret);4052return ret;4053}40544055for (i = 0; i < svc_rdy_ext->arg.num_phy; i++) {4056ret = ath12k_pull_reg_cap_svc_rdy_ext(wmi_handle,4057svc_rdy_ext->soc_hal_reg_caps,4058svc_rdy_ext->ext_hal_reg_caps, i,4059®_cap);4060if (ret) {4061ath12k_warn(soc, "failed to extract reg cap %d\n", i);4062return ret;4063}4064soc->hal_reg_cap[reg_cap.phy_id] = reg_cap;4065}4066return 0;4067}40684069static int ath12k_wmi_ext_soc_hal_reg_caps_parse(struct ath12k_base *soc,4070u16 len, const void *ptr,4071void *data)4072{4073struct ath12k_wmi_pdev *wmi_handle = &soc->wmi_ab.wmi[0];4074struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;4075u8 hw_mode_id = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.hw_mode_id);4076u32 phy_id_map;4077int pdev_index = 0;4078int ret;40794080svc_rdy_ext->soc_hal_reg_caps = ptr;4081svc_rdy_ext->arg.num_phy = le32_to_cpu(svc_rdy_ext->soc_hal_reg_caps->num_phy);40824083soc->num_radios = 0;4084phy_id_map = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.phy_id_map);4085soc->fw_pdev_count = 0;40864087while (phy_id_map && soc->num_radios < MAX_RADIOS) {4088ret = ath12k_pull_mac_phy_cap_svc_ready_ext(wmi_handle,4089svc_rdy_ext,4090hw_mode_id, soc->num_radios,4091&soc->pdevs[pdev_index]);4092if (ret) {4093ath12k_warn(soc, "failed to extract mac caps, idx :%d\n",4094soc->num_radios);4095return ret;4096}40974098soc->num_radios++;40994100/* For single_pdev_only targets,4101* save mac_phy capability in the same pdev4102*/4103if (soc->hw_params->single_pdev_only)4104pdev_index = 0;4105else4106pdev_index = soc->num_radios;41074108/* TODO: mac_phy_cap prints */4109phy_id_map >>= 1;4110}41114112if (soc->hw_params->single_pdev_only) {4113soc->num_radios = 1;4114soc->pdevs[0].pdev_id = 0;4115}41164117return 0;4118}41194120static int ath12k_wmi_dma_ring_caps_parse(struct ath12k_base *soc,4121u16 tag, u16 len,4122const void *ptr, void *data)4123{4124struct ath12k_wmi_dma_ring_caps_parse *parse = data;41254126if (tag != WMI_TAG_DMA_RING_CAPABILITIES)4127return -EPROTO;41284129parse->n_dma_ring_caps++;4130return 0;4131}41324133static int ath12k_wmi_alloc_dbring_caps(struct ath12k_base *ab,4134u32 num_cap)4135{4136size_t sz;4137void *ptr;41384139sz = num_cap * sizeof(struct ath12k_dbring_cap);4140ptr = kzalloc(sz, GFP_ATOMIC);4141if (!ptr)4142return -ENOMEM;41434144ab->db_caps = ptr;4145ab->num_db_cap = num_cap;41464147return 0;4148}41494150static void ath12k_wmi_free_dbring_caps(struct ath12k_base *ab)4151{4152kfree(ab->db_caps);4153ab->db_caps = NULL;4154}41554156static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab,4157u16 len, const void *ptr, void *data)4158{4159struct ath12k_wmi_dma_ring_caps_parse *dma_caps_parse = data;4160#if defined(__linux__)4161struct ath12k_wmi_dma_ring_caps_params *dma_caps;4162#elif defined(__FreeBSD__)4163const struct ath12k_wmi_dma_ring_caps_params *dma_caps;4164#endif4165struct ath12k_dbring_cap *dir_buff_caps;4166int ret;4167u32 i;41684169dma_caps_parse->n_dma_ring_caps = 0;4170#if defined(__linux__)4171dma_caps = (struct ath12k_wmi_dma_ring_caps_params *)ptr;4172#elif defined(__FreeBSD__)4173dma_caps = (const struct ath12k_wmi_dma_ring_caps_params *)ptr;4174#endif4175ret = ath12k_wmi_tlv_iter(ab, ptr, len,4176ath12k_wmi_dma_ring_caps_parse,4177dma_caps_parse);4178if (ret) {4179ath12k_warn(ab, "failed to parse dma ring caps tlv %d\n", ret);4180return ret;4181}41824183if (!dma_caps_parse->n_dma_ring_caps)4184return 0;41854186if (ab->num_db_cap) {4187ath12k_warn(ab, "Already processed, so ignoring dma ring caps\n");4188return 0;4189}41904191ret = ath12k_wmi_alloc_dbring_caps(ab, dma_caps_parse->n_dma_ring_caps);4192if (ret)4193return ret;41944195dir_buff_caps = ab->db_caps;4196for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) {4197if (le32_to_cpu(dma_caps[i].module_id) >= WMI_DIRECT_BUF_MAX) {4198ath12k_warn(ab, "Invalid module id %d\n",4199le32_to_cpu(dma_caps[i].module_id));4200ret = -EINVAL;4201goto free_dir_buff;4202}42034204dir_buff_caps[i].id = le32_to_cpu(dma_caps[i].module_id);4205dir_buff_caps[i].pdev_id =4206DP_HW2SW_MACID(le32_to_cpu(dma_caps[i].pdev_id));4207dir_buff_caps[i].min_elem = le32_to_cpu(dma_caps[i].min_elem);4208dir_buff_caps[i].min_buf_sz = le32_to_cpu(dma_caps[i].min_buf_sz);4209dir_buff_caps[i].min_buf_align = le32_to_cpu(dma_caps[i].min_buf_align);4210}42114212return 0;42134214free_dir_buff:4215ath12k_wmi_free_dbring_caps(ab);4216return ret;4217}42184219static int ath12k_wmi_svc_rdy_ext_parse(struct ath12k_base *ab,4220u16 tag, u16 len,4221const void *ptr, void *data)4222{4223struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0];4224struct ath12k_wmi_svc_rdy_ext_parse *svc_rdy_ext = data;4225int ret;42264227switch (tag) {4228case WMI_TAG_SERVICE_READY_EXT_EVENT:4229ret = ath12k_pull_svc_ready_ext(wmi_handle, ptr,4230&svc_rdy_ext->arg);4231if (ret) {4232ath12k_warn(ab, "unable to extract ext params\n");4233return ret;4234}4235break;42364237case WMI_TAG_SOC_MAC_PHY_HW_MODE_CAPS:4238svc_rdy_ext->hw_caps = ptr;4239svc_rdy_ext->arg.num_hw_modes =4240le32_to_cpu(svc_rdy_ext->hw_caps->num_hw_modes);4241break;42424243case WMI_TAG_SOC_HAL_REG_CAPABILITIES:4244ret = ath12k_wmi_ext_soc_hal_reg_caps_parse(ab, len, ptr,4245svc_rdy_ext);4246if (ret)4247return ret;4248break;42494250case WMI_TAG_ARRAY_STRUCT:4251if (!svc_rdy_ext->hw_mode_done) {4252ret = ath12k_wmi_hw_mode_caps(ab, len, ptr, svc_rdy_ext);4253if (ret)4254return ret;42554256svc_rdy_ext->hw_mode_done = true;4257} else if (!svc_rdy_ext->mac_phy_done) {4258svc_rdy_ext->n_mac_phy_caps = 0;4259ret = ath12k_wmi_tlv_iter(ab, ptr, len,4260ath12k_wmi_mac_phy_caps_parse,4261svc_rdy_ext);4262if (ret) {4263ath12k_warn(ab, "failed to parse tlv %d\n", ret);4264return ret;4265}42664267svc_rdy_ext->mac_phy_done = true;4268} else if (!svc_rdy_ext->ext_hal_reg_done) {4269ret = ath12k_wmi_ext_hal_reg_caps(ab, len, ptr, svc_rdy_ext);4270if (ret)4271return ret;42724273svc_rdy_ext->ext_hal_reg_done = true;4274} else if (!svc_rdy_ext->mac_phy_chainmask_combo_done) {4275svc_rdy_ext->mac_phy_chainmask_combo_done = true;4276} else if (!svc_rdy_ext->mac_phy_chainmask_cap_done) {4277svc_rdy_ext->mac_phy_chainmask_cap_done = true;4278} else if (!svc_rdy_ext->oem_dma_ring_cap_done) {4279svc_rdy_ext->oem_dma_ring_cap_done = true;4280} else if (!svc_rdy_ext->dma_ring_cap_done) {4281ret = ath12k_wmi_dma_ring_caps(ab, len, ptr,4282&svc_rdy_ext->dma_caps_parse);4283if (ret)4284return ret;42854286svc_rdy_ext->dma_ring_cap_done = true;4287}4288break;42894290default:4291break;4292}4293return 0;4294}42954296static int ath12k_service_ready_ext_event(struct ath12k_base *ab,4297struct sk_buff *skb)4298{4299struct ath12k_wmi_svc_rdy_ext_parse svc_rdy_ext = { };4300int ret;43014302ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,4303ath12k_wmi_svc_rdy_ext_parse,4304&svc_rdy_ext);4305if (ret) {4306ath12k_warn(ab, "failed to parse tlv %d\n", ret);4307goto err;4308}43094310if (!test_bit(WMI_TLV_SERVICE_EXT2_MSG, ab->wmi_ab.svc_map))4311complete(&ab->wmi_ab.service_ready);43124313kfree(svc_rdy_ext.mac_phy_caps);4314return 0;43154316err:4317ath12k_wmi_free_dbring_caps(ab);4318return ret;4319}43204321static int ath12k_pull_svc_ready_ext2(struct ath12k_wmi_pdev *wmi_handle,4322const void *ptr,4323struct ath12k_wmi_svc_rdy_ext2_arg *arg)4324{4325const struct wmi_service_ready_ext2_event *ev = ptr;43264327if (!ev)4328return -EINVAL;43294330arg->reg_db_version = le32_to_cpu(ev->reg_db_version);4331arg->hw_min_max_tx_power_2ghz = le32_to_cpu(ev->hw_min_max_tx_power_2ghz);4332arg->hw_min_max_tx_power_5ghz = le32_to_cpu(ev->hw_min_max_tx_power_5ghz);4333arg->chwidth_num_peer_caps = le32_to_cpu(ev->chwidth_num_peer_caps);4334arg->preamble_puncture_bw = le32_to_cpu(ev->preamble_puncture_bw);4335arg->max_user_per_ppdu_ofdma = le32_to_cpu(ev->max_user_per_ppdu_ofdma);4336arg->max_user_per_ppdu_mumimo = le32_to_cpu(ev->max_user_per_ppdu_mumimo);4337arg->target_cap_flags = le32_to_cpu(ev->target_cap_flags);4338return 0;4339}43404341static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,4342const __le32 cap_mac_info[],4343const __le32 cap_phy_info[],4344const __le32 supp_mcs[],4345const struct ath12k_wmi_ppe_threshold_params *ppet,4346__le32 cap_info_internal)4347{4348struct ath12k_band_cap *cap_band = &pdev->cap.band[band];4349u8 i;43504351for (i = 0; i < WMI_MAX_EHTCAP_MAC_SIZE; i++)4352cap_band->eht_cap_mac_info[i] = le32_to_cpu(cap_mac_info[i]);43534354for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++)4355cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]);43564357cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]);4358cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]);4359if (band != NL80211_BAND_2GHZ) {4360cap_band->eht_mcs_160 = le32_to_cpu(supp_mcs[2]);4361cap_band->eht_mcs_320 = le32_to_cpu(supp_mcs[3]);4362}43634364cap_band->eht_ppet.numss_m1 = le32_to_cpu(ppet->numss_m1);4365cap_band->eht_ppet.ru_bit_mask = le32_to_cpu(ppet->ru_info);4366for (i = 0; i < WMI_MAX_NUM_SS; i++)4367cap_band->eht_ppet.ppet16_ppet8_ru3_ru0[i] =4368le32_to_cpu(ppet->ppet16_ppet8_ru3_ru0[i]);43694370cap_band->eht_cap_info_internal = le32_to_cpu(cap_info_internal);4371}43724373static int4374ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab,4375const struct ath12k_wmi_caps_ext_params *caps,4376struct ath12k_pdev *pdev)4377{4378u32 bands;4379int i;43804381if (ab->hw_params->single_pdev_only) {4382for (i = 0; i < ab->fw_pdev_count; i++) {4383struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i];43844385if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) &&4386fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) {4387bands = fw_pdev->supported_bands;4388break;4389}4390}43914392if (i == ab->fw_pdev_count)4393return -EINVAL;4394} else {4395bands = pdev->cap.supported_bands;4396}43974398if (bands & WMI_HOST_WLAN_2G_CAP) {4399ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_2GHZ,4400caps->eht_cap_mac_info_2ghz,4401caps->eht_cap_phy_info_2ghz,4402caps->eht_supp_mcs_ext_2ghz,4403&caps->eht_ppet_2ghz,4404caps->eht_cap_info_internal);4405}44064407if (bands & WMI_HOST_WLAN_5G_CAP) {4408ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_5GHZ,4409caps->eht_cap_mac_info_5ghz,4410caps->eht_cap_phy_info_5ghz,4411caps->eht_supp_mcs_ext_5ghz,4412&caps->eht_ppet_5ghz,4413caps->eht_cap_info_internal);44144415ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_6GHZ,4416caps->eht_cap_mac_info_5ghz,4417caps->eht_cap_phy_info_5ghz,4418caps->eht_supp_mcs_ext_5ghz,4419&caps->eht_ppet_5ghz,4420caps->eht_cap_info_internal);4421}44224423return 0;4424}44254426static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag,4427u16 len, const void *ptr,4428void *data)4429{4430const struct ath12k_wmi_caps_ext_params *caps = ptr;4431int i = 0, ret;44324433if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT)4434return -EPROTO;44354436if (ab->hw_params->single_pdev_only) {4437if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id))4438return 0;4439} else {4440for (i = 0; i < ab->num_radios; i++) {4441if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id))4442break;4443}44444445if (i == ab->num_radios)4446return -EINVAL;4447}44484449ret = ath12k_wmi_tlv_mac_phy_caps_ext_parse(ab, caps, &ab->pdevs[i]);4450if (ret) {4451ath12k_warn(ab,4452"failed to parse extended MAC PHY capabilities for pdev %d: %d\n",4453ret, ab->pdevs[i].pdev_id);4454return ret;4455}44564457return 0;4458}44594460static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,4461u16 tag, u16 len,4462const void *ptr, void *data)4463{4464struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0];4465struct ath12k_wmi_svc_rdy_ext2_parse *parse = data;4466int ret;44674468switch (tag) {4469case WMI_TAG_SERVICE_READY_EXT2_EVENT:4470ret = ath12k_pull_svc_ready_ext2(wmi_handle, ptr,4471&parse->arg);4472if (ret) {4473ath12k_warn(ab,4474"failed to extract wmi service ready ext2 parameters: %d\n",4475ret);4476return ret;4477}4478break;44794480case WMI_TAG_ARRAY_STRUCT:4481if (!parse->dma_ring_cap_done) {4482ret = ath12k_wmi_dma_ring_caps(ab, len, ptr,4483&parse->dma_caps_parse);4484if (ret)4485return ret;44864487parse->dma_ring_cap_done = true;4488} else if (!parse->spectral_bin_scaling_done) {4489/* TODO: This is a place-holder as WMI tag for4490* spectral scaling is before4491* WMI_TAG_MAC_PHY_CAPABILITIES_EXT4492*/4493parse->spectral_bin_scaling_done = true;4494} else if (!parse->mac_phy_caps_ext_done) {4495ret = ath12k_wmi_tlv_iter(ab, ptr, len,4496ath12k_wmi_tlv_mac_phy_caps_ext,4497parse);4498if (ret) {4499ath12k_warn(ab, "failed to parse extended MAC PHY capabilities WMI TLV: %d\n",4500ret);4501return ret;4502}45034504parse->mac_phy_caps_ext_done = true;4505}4506break;4507default:4508break;4509}45104511return 0;4512}45134514static int ath12k_service_ready_ext2_event(struct ath12k_base *ab,4515struct sk_buff *skb)4516{4517struct ath12k_wmi_svc_rdy_ext2_parse svc_rdy_ext2 = { };4518int ret;45194520ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,4521ath12k_wmi_svc_rdy_ext2_parse,4522&svc_rdy_ext2);4523if (ret) {4524ath12k_warn(ab, "failed to parse ext2 event tlv %d\n", ret);4525goto err;4526}45274528complete(&ab->wmi_ab.service_ready);45294530return 0;45314532err:4533ath12k_wmi_free_dbring_caps(ab);4534return ret;4535}45364537static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buff *skb,4538struct wmi_vdev_start_resp_event *vdev_rsp)4539{4540const void **tb;4541const struct wmi_vdev_start_resp_event *ev;4542int ret;45434544tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);4545if (IS_ERR(tb)) {4546ret = PTR_ERR(tb);4547ath12k_warn(ab, "failed to parse tlv: %d\n", ret);4548return ret;4549}45504551ev = tb[WMI_TAG_VDEV_START_RESPONSE_EVENT];4552if (!ev) {4553ath12k_warn(ab, "failed to fetch vdev start resp ev");4554kfree(tb);4555return -EPROTO;4556}45574558*vdev_rsp = *ev;45594560kfree(tb);4561return 0;4562}45634564static struct ath12k_reg_rule4565*create_ext_reg_rules_from_wmi(u32 num_reg_rules,4566#if defined(__linux__)4567struct ath12k_wmi_reg_rule_ext_params *wmi_reg_rule)4568#elif defined(__FreeBSD__)4569const struct ath12k_wmi_reg_rule_ext_params *wmi_reg_rule)4570#endif4571{4572struct ath12k_reg_rule *reg_rule_ptr;4573u32 count;45744575reg_rule_ptr = kzalloc((num_reg_rules * sizeof(*reg_rule_ptr)),4576GFP_ATOMIC);45774578if (!reg_rule_ptr)4579return NULL;45804581for (count = 0; count < num_reg_rules; count++) {4582reg_rule_ptr[count].start_freq =4583le32_get_bits(wmi_reg_rule[count].freq_info,4584REG_RULE_START_FREQ);4585reg_rule_ptr[count].end_freq =4586le32_get_bits(wmi_reg_rule[count].freq_info,4587REG_RULE_END_FREQ);4588reg_rule_ptr[count].max_bw =4589le32_get_bits(wmi_reg_rule[count].bw_pwr_info,4590REG_RULE_MAX_BW);4591reg_rule_ptr[count].reg_power =4592le32_get_bits(wmi_reg_rule[count].bw_pwr_info,4593REG_RULE_REG_PWR);4594reg_rule_ptr[count].ant_gain =4595le32_get_bits(wmi_reg_rule[count].bw_pwr_info,4596REG_RULE_ANT_GAIN);4597reg_rule_ptr[count].flags =4598le32_get_bits(wmi_reg_rule[count].flag_info,4599REG_RULE_FLAGS);4600reg_rule_ptr[count].psd_flag =4601le32_get_bits(wmi_reg_rule[count].psd_power_info,4602REG_RULE_PSD_INFO);4603reg_rule_ptr[count].psd_eirp =4604le32_get_bits(wmi_reg_rule[count].psd_power_info,4605REG_RULE_PSD_EIRP);4606}46074608return reg_rule_ptr;4609}46104611static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,4612struct sk_buff *skb,4613struct ath12k_reg_info *reg_info)4614{4615const void **tb;4616const struct wmi_reg_chan_list_cc_ext_event *ev;4617#if defined(__linux__)4618struct ath12k_wmi_reg_rule_ext_params *ext_wmi_reg_rule;4619#elif defined(__FreeBSD__)4620const struct ath12k_wmi_reg_rule_ext_params *ext_wmi_reg_rule;4621#endif4622u32 num_2g_reg_rules, num_5g_reg_rules;4623u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];4624u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];4625u32 total_reg_rules = 0;4626int ret, i, j;46274628ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");46294630tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);4631if (IS_ERR(tb)) {4632ret = PTR_ERR(tb);4633ath12k_warn(ab, "failed to parse tlv: %d\n", ret);4634return ret;4635}46364637ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];4638if (!ev) {4639ath12k_warn(ab, "failed to fetch reg chan list ext update ev\n");4640kfree(tb);4641return -EPROTO;4642}46434644reg_info->num_2g_reg_rules = le32_to_cpu(ev->num_2g_reg_rules);4645reg_info->num_5g_reg_rules = le32_to_cpu(ev->num_5g_reg_rules);4646reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP] =4647le32_to_cpu(ev->num_6g_reg_rules_ap_lpi);4648reg_info->num_6g_reg_rules_ap[WMI_REG_STD_POWER_AP] =4649le32_to_cpu(ev->num_6g_reg_rules_ap_sp);4650reg_info->num_6g_reg_rules_ap[WMI_REG_VLP_AP] =4651le32_to_cpu(ev->num_6g_reg_rules_ap_vlp);46524653for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {4654reg_info->num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i] =4655le32_to_cpu(ev->num_6g_reg_rules_cl_lpi[i]);4656reg_info->num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i] =4657le32_to_cpu(ev->num_6g_reg_rules_cl_sp[i]);4658reg_info->num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] =4659le32_to_cpu(ev->num_6g_reg_rules_cl_vlp[i]);4660}46614662num_2g_reg_rules = reg_info->num_2g_reg_rules;4663total_reg_rules += num_2g_reg_rules;4664num_5g_reg_rules = reg_info->num_5g_reg_rules;4665total_reg_rules += num_5g_reg_rules;46664667if (num_2g_reg_rules > MAX_REG_RULES || num_5g_reg_rules > MAX_REG_RULES) {4668ath12k_warn(ab, "Num reg rules for 2G/5G exceeds max limit (num_2g_reg_rules: %d num_5g_reg_rules: %d max_rules: %d)\n",4669num_2g_reg_rules, num_5g_reg_rules, MAX_REG_RULES);4670kfree(tb);4671return -EINVAL;4672}46734674for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {4675num_6g_reg_rules_ap[i] = reg_info->num_6g_reg_rules_ap[i];46764677if (num_6g_reg_rules_ap[i] > MAX_6G_REG_RULES) {4678ath12k_warn(ab, "Num 6G reg rules for AP mode(%d) exceeds max limit (num_6g_reg_rules_ap: %d, max_rules: %d)\n",4679i, num_6g_reg_rules_ap[i], MAX_6G_REG_RULES);4680kfree(tb);4681return -EINVAL;4682}46834684total_reg_rules += num_6g_reg_rules_ap[i];4685}46864687for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {4688num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i] =4689reg_info->num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i];4690total_reg_rules += num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i];46914692num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i] =4693reg_info->num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i];4694total_reg_rules += num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i];46954696num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] =4697reg_info->num_6g_reg_rules_cl[WMI_REG_VLP_AP][i];4698total_reg_rules += num_6g_reg_rules_cl[WMI_REG_VLP_AP][i];46994700if (num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][i] > MAX_6G_REG_RULES ||4701num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][i] > MAX_6G_REG_RULES ||4702num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] > MAX_6G_REG_RULES) {4703ath12k_warn(ab, "Num 6g client reg rules exceeds max limit, for client(type: %d)\n",4704i);4705kfree(tb);4706return -EINVAL;4707}4708}47094710if (!total_reg_rules) {4711ath12k_warn(ab, "No reg rules available\n");4712kfree(tb);4713return -EINVAL;4714}47154716memcpy(reg_info->alpha2, &ev->alpha2, REG_ALPHA2_LEN);47174718/* FIXME: Currently FW includes 6G reg rule also in 5G rule4719* list for country US.4720* Having same 6G reg rule in 5G and 6G rules list causes4721* intersect check to be true, and same rules will be shown4722* multiple times in iw cmd. So added hack below to avoid4723* parsing 6G rule from 5G reg rule list, and this can be4724* removed later, after FW updates to remove 6G reg rule4725* from 5G rules list.4726*/4727if (memcmp(reg_info->alpha2, "US", 2) == 0) {4728reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES;4729num_5g_reg_rules = reg_info->num_5g_reg_rules;4730}47314732reg_info->dfs_region = le32_to_cpu(ev->dfs_region);4733reg_info->phybitmap = le32_to_cpu(ev->phybitmap);4734reg_info->num_phy = le32_to_cpu(ev->num_phy);4735reg_info->phy_id = le32_to_cpu(ev->phy_id);4736reg_info->ctry_code = le32_to_cpu(ev->country_id);4737reg_info->reg_dmn_pair = le32_to_cpu(ev->domain_code);47384739switch (le32_to_cpu(ev->status_code)) {4740case WMI_REG_SET_CC_STATUS_PASS:4741reg_info->status_code = REG_SET_CC_STATUS_PASS;4742break;4743case WMI_REG_CURRENT_ALPHA2_NOT_FOUND:4744reg_info->status_code = REG_CURRENT_ALPHA2_NOT_FOUND;4745break;4746case WMI_REG_INIT_ALPHA2_NOT_FOUND:4747reg_info->status_code = REG_INIT_ALPHA2_NOT_FOUND;4748break;4749case WMI_REG_SET_CC_CHANGE_NOT_ALLOWED:4750reg_info->status_code = REG_SET_CC_CHANGE_NOT_ALLOWED;4751break;4752case WMI_REG_SET_CC_STATUS_NO_MEMORY:4753reg_info->status_code = REG_SET_CC_STATUS_NO_MEMORY;4754break;4755case WMI_REG_SET_CC_STATUS_FAIL:4756reg_info->status_code = REG_SET_CC_STATUS_FAIL;4757break;4758}47594760reg_info->is_ext_reg_event = true;47614762reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g);4763reg_info->max_bw_2g = le32_to_cpu(ev->max_bw_2g);4764reg_info->min_bw_5g = le32_to_cpu(ev->min_bw_5g);4765reg_info->max_bw_5g = le32_to_cpu(ev->max_bw_5g);4766reg_info->min_bw_6g_ap[WMI_REG_INDOOR_AP] = le32_to_cpu(ev->min_bw_6g_ap_lpi);4767reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP] = le32_to_cpu(ev->max_bw_6g_ap_lpi);4768reg_info->min_bw_6g_ap[WMI_REG_STD_POWER_AP] = le32_to_cpu(ev->min_bw_6g_ap_sp);4769reg_info->max_bw_6g_ap[WMI_REG_STD_POWER_AP] = le32_to_cpu(ev->max_bw_6g_ap_sp);4770reg_info->min_bw_6g_ap[WMI_REG_VLP_AP] = le32_to_cpu(ev->min_bw_6g_ap_vlp);4771reg_info->max_bw_6g_ap[WMI_REG_VLP_AP] = le32_to_cpu(ev->max_bw_6g_ap_vlp);47724773for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {4774reg_info->min_bw_6g_client[WMI_REG_INDOOR_AP][i] =4775le32_to_cpu(ev->min_bw_6g_client_lpi[i]);4776reg_info->max_bw_6g_client[WMI_REG_INDOOR_AP][i] =4777le32_to_cpu(ev->max_bw_6g_client_lpi[i]);4778reg_info->min_bw_6g_client[WMI_REG_STD_POWER_AP][i] =4779le32_to_cpu(ev->min_bw_6g_client_sp[i]);4780reg_info->max_bw_6g_client[WMI_REG_STD_POWER_AP][i] =4781le32_to_cpu(ev->max_bw_6g_client_sp[i]);4782reg_info->min_bw_6g_client[WMI_REG_VLP_AP][i] =4783le32_to_cpu(ev->min_bw_6g_client_vlp[i]);4784reg_info->max_bw_6g_client[WMI_REG_VLP_AP][i] =4785le32_to_cpu(ev->max_bw_6g_client_vlp[i]);4786}47874788ath12k_dbg(ab, ATH12K_DBG_WMI,4789"%s:cc_ext %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",4790__func__, reg_info->alpha2, reg_info->dfs_region,4791reg_info->min_bw_2g, reg_info->max_bw_2g,4792reg_info->min_bw_5g, reg_info->max_bw_5g);47934794ath12k_dbg(ab, ATH12K_DBG_WMI,4795"num_2g_reg_rules %d num_5g_reg_rules %d",4796num_2g_reg_rules, num_5g_reg_rules);47974798ath12k_dbg(ab, ATH12K_DBG_WMI,4799"num_6g_reg_rules_ap_lpi: %d num_6g_reg_rules_ap_sp: %d num_6g_reg_rules_ap_vlp: %d",4800num_6g_reg_rules_ap[WMI_REG_INDOOR_AP],4801num_6g_reg_rules_ap[WMI_REG_STD_POWER_AP],4802num_6g_reg_rules_ap[WMI_REG_VLP_AP]);48034804ath12k_dbg(ab, ATH12K_DBG_WMI,4805"6g Regular client: num_6g_reg_rules_lpi: %d num_6g_reg_rules_sp: %d num_6g_reg_rules_vlp: %d",4806num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][WMI_REG_DEFAULT_CLIENT],4807num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][WMI_REG_DEFAULT_CLIENT],4808num_6g_reg_rules_cl[WMI_REG_VLP_AP][WMI_REG_DEFAULT_CLIENT]);48094810ath12k_dbg(ab, ATH12K_DBG_WMI,4811"6g Subordinate client: num_6g_reg_rules_lpi: %d num_6g_reg_rules_sp: %d num_6g_reg_rules_vlp: %d",4812num_6g_reg_rules_cl[WMI_REG_INDOOR_AP][WMI_REG_SUBORDINATE_CLIENT],4813num_6g_reg_rules_cl[WMI_REG_STD_POWER_AP][WMI_REG_SUBORDINATE_CLIENT],4814num_6g_reg_rules_cl[WMI_REG_VLP_AP][WMI_REG_SUBORDINATE_CLIENT]);48154816ext_wmi_reg_rule =4817#if defined(__linux__)4818(struct ath12k_wmi_reg_rule_ext_params *)((u8 *)ev4819#elif defined(__FreeBSD__)4820(const struct ath12k_wmi_reg_rule_ext_params *)((const u8 *)ev4821#endif4822+ sizeof(*ev)4823+ sizeof(struct wmi_tlv));48244825if (num_2g_reg_rules) {4826reg_info->reg_rules_2g_ptr =4827create_ext_reg_rules_from_wmi(num_2g_reg_rules,4828ext_wmi_reg_rule);48294830if (!reg_info->reg_rules_2g_ptr) {4831kfree(tb);4832ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");4833return -ENOMEM;4834}4835}48364837if (num_5g_reg_rules) {4838ext_wmi_reg_rule += num_2g_reg_rules;4839reg_info->reg_rules_5g_ptr =4840create_ext_reg_rules_from_wmi(num_5g_reg_rules,4841ext_wmi_reg_rule);48424843if (!reg_info->reg_rules_5g_ptr) {4844kfree(tb);4845ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");4846return -ENOMEM;4847}4848}48494850ext_wmi_reg_rule += num_5g_reg_rules;48514852for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {4853reg_info->reg_rules_6g_ap_ptr[i] =4854create_ext_reg_rules_from_wmi(num_6g_reg_rules_ap[i],4855ext_wmi_reg_rule);48564857if (!reg_info->reg_rules_6g_ap_ptr[i]) {4858kfree(tb);4859ath12k_warn(ab, "Unable to Allocate memory for 6g ap rules\n");4860return -ENOMEM;4861}48624863ext_wmi_reg_rule += num_6g_reg_rules_ap[i];4864}48654866for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {4867for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {4868reg_info->reg_rules_6g_client_ptr[j][i] =4869create_ext_reg_rules_from_wmi(num_6g_reg_rules_cl[j][i],4870ext_wmi_reg_rule);48714872if (!reg_info->reg_rules_6g_client_ptr[j][i]) {4873kfree(tb);4874ath12k_warn(ab, "Unable to Allocate memory for 6g client rules\n");4875return -ENOMEM;4876}48774878ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i];4879}4880}48814882reg_info->client_type = le32_to_cpu(ev->client_type);4883reg_info->rnr_tpe_usable = ev->rnr_tpe_usable;4884reg_info->unspecified_ap_usable = ev->unspecified_ap_usable;4885reg_info->domain_code_6g_ap[WMI_REG_INDOOR_AP] =4886le32_to_cpu(ev->domain_code_6g_ap_lpi);4887reg_info->domain_code_6g_ap[WMI_REG_STD_POWER_AP] =4888le32_to_cpu(ev->domain_code_6g_ap_sp);4889reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] =4890le32_to_cpu(ev->domain_code_6g_ap_vlp);48914892for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {4893reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] =4894le32_to_cpu(ev->domain_code_6g_client_lpi[i]);4895reg_info->domain_code_6g_client[WMI_REG_STD_POWER_AP][i] =4896le32_to_cpu(ev->domain_code_6g_client_sp[i]);4897reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] =4898le32_to_cpu(ev->domain_code_6g_client_vlp[i]);4899}49004901reg_info->domain_code_6g_super_id = le32_to_cpu(ev->domain_code_6g_super_id);49024903ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",4904reg_info->client_type, reg_info->domain_code_6g_super_id);49054906ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");49074908kfree(tb);4909return 0;4910}49114912static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *skb,4913struct wmi_peer_delete_resp_event *peer_del_resp)4914{4915const void **tb;4916const struct wmi_peer_delete_resp_event *ev;4917int ret;49184919tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);4920if (IS_ERR(tb)) {4921ret = PTR_ERR(tb);4922ath12k_warn(ab, "failed to parse tlv: %d\n", ret);4923return ret;4924}49254926ev = tb[WMI_TAG_PEER_DELETE_RESP_EVENT];4927if (!ev) {4928ath12k_warn(ab, "failed to fetch peer delete resp ev");4929kfree(tb);4930return -EPROTO;4931}49324933memset(peer_del_resp, 0, sizeof(*peer_del_resp));49344935peer_del_resp->vdev_id = ev->vdev_id;4936ether_addr_copy(peer_del_resp->peer_macaddr.addr,4937ev->peer_macaddr.addr);49384939kfree(tb);4940return 0;4941}49424943static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab,4944struct sk_buff *skb,4945u32 *vdev_id)4946{4947const void **tb;4948const struct wmi_vdev_delete_resp_event *ev;4949int ret;49504951tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);4952if (IS_ERR(tb)) {4953ret = PTR_ERR(tb);4954ath12k_warn(ab, "failed to parse tlv: %d\n", ret);4955return ret;4956}49574958ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT];4959if (!ev) {4960ath12k_warn(ab, "failed to fetch vdev delete resp ev");4961kfree(tb);4962return -EPROTO;4963}49644965*vdev_id = le32_to_cpu(ev->vdev_id);49664967kfree(tb);4968return 0;4969}49704971static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, void *evt_buf,4972u32 len, u32 *vdev_id,4973u32 *tx_status)4974{4975const void **tb;4976const struct wmi_bcn_tx_status_event *ev;4977int ret;49784979tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);4980if (IS_ERR(tb)) {4981ret = PTR_ERR(tb);4982ath12k_warn(ab, "failed to parse tlv: %d\n", ret);4983return ret;4984}49854986ev = tb[WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT];4987if (!ev) {4988ath12k_warn(ab, "failed to fetch bcn tx status ev");4989kfree(tb);4990return -EPROTO;4991}49924993*vdev_id = le32_to_cpu(ev->vdev_id);4994*tx_status = le32_to_cpu(ev->tx_status);49954996kfree(tb);4997return 0;4998}49995000static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_buff *skb,5001u32 *vdev_id)5002{5003const void **tb;5004const struct wmi_vdev_stopped_event *ev;5005int ret;50065007tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5008if (IS_ERR(tb)) {5009ret = PTR_ERR(tb);5010ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5011return ret;5012}50135014ev = tb[WMI_TAG_VDEV_STOPPED_EVENT];5015if (!ev) {5016ath12k_warn(ab, "failed to fetch vdev stop ev");5017kfree(tb);5018return -EPROTO;5019}50205021*vdev_id = le32_to_cpu(ev->vdev_id);50225023kfree(tb);5024return 0;5025}50265027static int ath12k_wmi_tlv_mgmt_rx_parse(struct ath12k_base *ab,5028u16 tag, u16 len,5029const void *ptr, void *data)5030{5031struct wmi_tlv_mgmt_rx_parse *parse = data;50325033switch (tag) {5034case WMI_TAG_MGMT_RX_HDR:5035parse->fixed = ptr;5036break;5037case WMI_TAG_ARRAY_BYTE:5038if (!parse->frame_buf_done) {5039parse->frame_buf = ptr;5040parse->frame_buf_done = true;5041}5042break;5043}5044return 0;5045}50465047static int ath12k_pull_mgmt_rx_params_tlv(struct ath12k_base *ab,5048struct sk_buff *skb,5049struct ath12k_wmi_mgmt_rx_arg *hdr)5050{5051struct wmi_tlv_mgmt_rx_parse parse = { };5052const struct ath12k_wmi_mgmt_rx_params *ev;5053const u8 *frame;5054int i, ret;50555056ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,5057ath12k_wmi_tlv_mgmt_rx_parse,5058&parse);5059if (ret) {5060ath12k_warn(ab, "failed to parse mgmt rx tlv %d\n", ret);5061return ret;5062}50635064ev = parse.fixed;5065frame = parse.frame_buf;50665067if (!ev || !frame) {5068ath12k_warn(ab, "failed to fetch mgmt rx hdr");5069return -EPROTO;5070}50715072hdr->pdev_id = le32_to_cpu(ev->pdev_id);5073hdr->chan_freq = le32_to_cpu(ev->chan_freq);5074hdr->channel = le32_to_cpu(ev->channel);5075hdr->snr = le32_to_cpu(ev->snr);5076hdr->rate = le32_to_cpu(ev->rate);5077hdr->phy_mode = le32_to_cpu(ev->phy_mode);5078hdr->buf_len = le32_to_cpu(ev->buf_len);5079hdr->status = le32_to_cpu(ev->status);5080hdr->flags = le32_to_cpu(ev->flags);5081hdr->rssi = a_sle32_to_cpu(ev->rssi);5082hdr->tsf_delta = le32_to_cpu(ev->tsf_delta);50835084for (i = 0; i < ATH_MAX_ANTENNA; i++)5085hdr->rssi_ctl[i] = le32_to_cpu(ev->rssi_ctl[i]);50865087if (skb->len < (frame - skb->data) + hdr->buf_len) {5088ath12k_warn(ab, "invalid length in mgmt rx hdr ev");5089return -EPROTO;5090}50915092/* shift the sk_buff to point to `frame` */5093skb_trim(skb, 0);5094skb_put(skb, frame - skb->data);5095skb_pull(skb, frame - skb->data);5096skb_put(skb, hdr->buf_len);50975098return 0;5099}51005101static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id,5102u32 status)5103{5104struct sk_buff *msdu;5105struct ieee80211_tx_info *info;5106struct ath12k_skb_cb *skb_cb;5107int num_mgmt;51085109spin_lock_bh(&ar->txmgmt_idr_lock);5110msdu = idr_find(&ar->txmgmt_idr, desc_id);51115112if (!msdu) {5113ath12k_warn(ar->ab, "received mgmt tx compl for invalid msdu_id: %d\n",5114desc_id);5115spin_unlock_bh(&ar->txmgmt_idr_lock);5116return -ENOENT;5117}51185119idr_remove(&ar->txmgmt_idr, desc_id);5120spin_unlock_bh(&ar->txmgmt_idr_lock);51215122skb_cb = ATH12K_SKB_CB(msdu);5123dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);51245125info = IEEE80211_SKB_CB(msdu);5126if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status)5127info->flags |= IEEE80211_TX_STAT_ACK;51285129ieee80211_tx_status_irqsafe(ar->hw, msdu);51305131num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx);51325133/* WARN when we received this event without doing any mgmt tx */5134if (num_mgmt < 0)5135WARN_ON_ONCE(1);51365137if (!num_mgmt)5138wake_up(&ar->txmgmt_empty_waitq);51395140return 0;5141}51425143static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,5144struct sk_buff *skb,5145struct wmi_mgmt_tx_compl_event *param)5146{5147const void **tb;5148const struct wmi_mgmt_tx_compl_event *ev;5149int ret;51505151tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5152if (IS_ERR(tb)) {5153ret = PTR_ERR(tb);5154ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5155return ret;5156}51575158ev = tb[WMI_TAG_MGMT_TX_COMPL_EVENT];5159if (!ev) {5160ath12k_warn(ab, "failed to fetch mgmt tx compl ev");5161kfree(tb);5162return -EPROTO;5163}51645165param->pdev_id = ev->pdev_id;5166param->desc_id = ev->desc_id;5167param->status = ev->status;51685169kfree(tb);5170return 0;5171}51725173static void ath12k_wmi_event_scan_started(struct ath12k *ar)5174{5175lockdep_assert_held(&ar->data_lock);51765177switch (ar->scan.state) {5178case ATH12K_SCAN_IDLE:5179case ATH12K_SCAN_RUNNING:5180case ATH12K_SCAN_ABORTING:5181ath12k_warn(ar->ab, "received scan started event in an invalid scan state: %s (%d)\n",5182ath12k_scan_state_str(ar->scan.state),5183ar->scan.state);5184break;5185case ATH12K_SCAN_STARTING:5186ar->scan.state = ATH12K_SCAN_RUNNING;5187complete(&ar->scan.started);5188break;5189}5190}51915192static void ath12k_wmi_event_scan_start_failed(struct ath12k *ar)5193{5194lockdep_assert_held(&ar->data_lock);51955196switch (ar->scan.state) {5197case ATH12K_SCAN_IDLE:5198case ATH12K_SCAN_RUNNING:5199case ATH12K_SCAN_ABORTING:5200ath12k_warn(ar->ab, "received scan start failed event in an invalid scan state: %s (%d)\n",5201ath12k_scan_state_str(ar->scan.state),5202ar->scan.state);5203break;5204case ATH12K_SCAN_STARTING:5205complete(&ar->scan.started);5206__ath12k_mac_scan_finish(ar);5207break;5208}5209}52105211static void ath12k_wmi_event_scan_completed(struct ath12k *ar)5212{5213lockdep_assert_held(&ar->data_lock);52145215switch (ar->scan.state) {5216case ATH12K_SCAN_IDLE:5217case ATH12K_SCAN_STARTING:5218/* One suspected reason scan can be completed while starting is5219* if firmware fails to deliver all scan events to the host,5220* e.g. when transport pipe is full. This has been observed5221* with spectral scan phyerr events starving wmi transport5222* pipe. In such case the "scan completed" event should be (and5223* is) ignored by the host as it may be just firmware's scan5224* state machine recovering.5225*/5226ath12k_warn(ar->ab, "received scan completed event in an invalid scan state: %s (%d)\n",5227ath12k_scan_state_str(ar->scan.state),5228ar->scan.state);5229break;5230case ATH12K_SCAN_RUNNING:5231case ATH12K_SCAN_ABORTING:5232__ath12k_mac_scan_finish(ar);5233break;5234}5235}52365237static void ath12k_wmi_event_scan_bss_chan(struct ath12k *ar)5238{5239lockdep_assert_held(&ar->data_lock);52405241switch (ar->scan.state) {5242case ATH12K_SCAN_IDLE:5243case ATH12K_SCAN_STARTING:5244ath12k_warn(ar->ab, "received scan bss chan event in an invalid scan state: %s (%d)\n",5245ath12k_scan_state_str(ar->scan.state),5246ar->scan.state);5247break;5248case ATH12K_SCAN_RUNNING:5249case ATH12K_SCAN_ABORTING:5250ar->scan_channel = NULL;5251break;5252}5253}52545255static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq)5256{5257lockdep_assert_held(&ar->data_lock);52585259switch (ar->scan.state) {5260case ATH12K_SCAN_IDLE:5261case ATH12K_SCAN_STARTING:5262ath12k_warn(ar->ab, "received scan foreign chan event in an invalid scan state: %s (%d)\n",5263ath12k_scan_state_str(ar->scan.state),5264ar->scan.state);5265break;5266case ATH12K_SCAN_RUNNING:5267case ATH12K_SCAN_ABORTING:5268ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq);5269break;5270}5271}52725273static const char *5274ath12k_wmi_event_scan_type_str(enum wmi_scan_event_type type,5275enum wmi_scan_completion_reason reason)5276{5277switch (type) {5278case WMI_SCAN_EVENT_STARTED:5279return "started";5280case WMI_SCAN_EVENT_COMPLETED:5281switch (reason) {5282case WMI_SCAN_REASON_COMPLETED:5283return "completed";5284case WMI_SCAN_REASON_CANCELLED:5285return "completed [cancelled]";5286case WMI_SCAN_REASON_PREEMPTED:5287return "completed [preempted]";5288case WMI_SCAN_REASON_TIMEDOUT:5289return "completed [timedout]";5290case WMI_SCAN_REASON_INTERNAL_FAILURE:5291return "completed [internal err]";5292case WMI_SCAN_REASON_MAX:5293break;5294}5295return "completed [unknown]";5296case WMI_SCAN_EVENT_BSS_CHANNEL:5297return "bss channel";5298case WMI_SCAN_EVENT_FOREIGN_CHAN:5299return "foreign channel";5300case WMI_SCAN_EVENT_DEQUEUED:5301return "dequeued";5302case WMI_SCAN_EVENT_PREEMPTED:5303return "preempted";5304case WMI_SCAN_EVENT_START_FAILED:5305return "start failed";5306case WMI_SCAN_EVENT_RESTARTED:5307return "restarted";5308case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT:5309return "foreign channel exit";5310default:5311return "unknown";5312}5313}53145315static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,5316struct wmi_scan_event *scan_evt_param)5317{5318const void **tb;5319const struct wmi_scan_event *ev;5320int ret;53215322tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5323if (IS_ERR(tb)) {5324ret = PTR_ERR(tb);5325ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5326return ret;5327}53285329ev = tb[WMI_TAG_SCAN_EVENT];5330if (!ev) {5331ath12k_warn(ab, "failed to fetch scan ev");5332kfree(tb);5333return -EPROTO;5334}53355336scan_evt_param->event_type = ev->event_type;5337scan_evt_param->reason = ev->reason;5338scan_evt_param->channel_freq = ev->channel_freq;5339scan_evt_param->scan_req_id = ev->scan_req_id;5340scan_evt_param->scan_id = ev->scan_id;5341scan_evt_param->vdev_id = ev->vdev_id;5342scan_evt_param->tsf_timestamp = ev->tsf_timestamp;53435344kfree(tb);5345return 0;5346}53475348static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buff *skb,5349struct wmi_peer_sta_kickout_arg *arg)5350{5351const void **tb;5352const struct wmi_peer_sta_kickout_event *ev;5353int ret;53545355tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5356if (IS_ERR(tb)) {5357ret = PTR_ERR(tb);5358ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5359return ret;5360}53615362ev = tb[WMI_TAG_PEER_STA_KICKOUT_EVENT];5363if (!ev) {5364ath12k_warn(ab, "failed to fetch peer sta kickout ev");5365kfree(tb);5366return -EPROTO;5367}53685369arg->mac_addr = ev->peer_macaddr.addr;53705371kfree(tb);5372return 0;5373}53745375static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,5376struct wmi_roam_event *roam_ev)5377{5378const void **tb;5379const struct wmi_roam_event *ev;5380int ret;53815382tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5383if (IS_ERR(tb)) {5384ret = PTR_ERR(tb);5385ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5386return ret;5387}53885389ev = tb[WMI_TAG_ROAM_EVENT];5390if (!ev) {5391ath12k_warn(ab, "failed to fetch roam ev");5392kfree(tb);5393return -EPROTO;5394}53955396roam_ev->vdev_id = ev->vdev_id;5397roam_ev->reason = ev->reason;5398roam_ev->rssi = ev->rssi;53995400kfree(tb);5401return 0;5402}54035404static int freq_to_idx(struct ath12k *ar, int freq)5405{5406struct ieee80211_supported_band *sband;5407int band, ch, idx = 0;54085409for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) {5410if (!ar->mac.sbands[band].channels)5411continue;54125413sband = ar->hw->wiphy->bands[band];5414if (!sband)5415continue;54165417for (ch = 0; ch < sband->n_channels; ch++, idx++)5418if (sband->channels[ch].center_freq == freq)5419goto exit;5420}54215422exit:5423return idx;5424}54255426static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, u8 *evt_buf,5427u32 len, struct wmi_chan_info_event *ch_info_ev)5428{5429const void **tb;5430const struct wmi_chan_info_event *ev;5431int ret;54325433tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);5434if (IS_ERR(tb)) {5435ret = PTR_ERR(tb);5436ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5437return ret;5438}54395440ev = tb[WMI_TAG_CHAN_INFO_EVENT];5441if (!ev) {5442ath12k_warn(ab, "failed to fetch chan info ev");5443kfree(tb);5444return -EPROTO;5445}54465447ch_info_ev->err_code = ev->err_code;5448ch_info_ev->freq = ev->freq;5449ch_info_ev->cmd_flags = ev->cmd_flags;5450ch_info_ev->noise_floor = ev->noise_floor;5451ch_info_ev->rx_clear_count = ev->rx_clear_count;5452ch_info_ev->cycle_count = ev->cycle_count;5453ch_info_ev->chan_tx_pwr_range = ev->chan_tx_pwr_range;5454ch_info_ev->chan_tx_pwr_tp = ev->chan_tx_pwr_tp;5455ch_info_ev->rx_frame_count = ev->rx_frame_count;5456ch_info_ev->tx_frame_cnt = ev->tx_frame_cnt;5457ch_info_ev->mac_clk_mhz = ev->mac_clk_mhz;5458ch_info_ev->vdev_id = ev->vdev_id;54595460kfree(tb);5461return 0;5462}54635464static int5465ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,5466struct wmi_pdev_bss_chan_info_event *bss_ch_info_ev)5467{5468const void **tb;5469const struct wmi_pdev_bss_chan_info_event *ev;5470int ret;54715472tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5473if (IS_ERR(tb)) {5474ret = PTR_ERR(tb);5475ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5476return ret;5477}54785479ev = tb[WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT];5480if (!ev) {5481ath12k_warn(ab, "failed to fetch pdev bss chan info ev");5482kfree(tb);5483return -EPROTO;5484}54855486bss_ch_info_ev->pdev_id = ev->pdev_id;5487bss_ch_info_ev->freq = ev->freq;5488bss_ch_info_ev->noise_floor = ev->noise_floor;5489bss_ch_info_ev->rx_clear_count_low = ev->rx_clear_count_low;5490bss_ch_info_ev->rx_clear_count_high = ev->rx_clear_count_high;5491bss_ch_info_ev->cycle_count_low = ev->cycle_count_low;5492bss_ch_info_ev->cycle_count_high = ev->cycle_count_high;5493bss_ch_info_ev->tx_cycle_count_low = ev->tx_cycle_count_low;5494bss_ch_info_ev->tx_cycle_count_high = ev->tx_cycle_count_high;5495bss_ch_info_ev->rx_cycle_count_low = ev->rx_cycle_count_low;5496bss_ch_info_ev->rx_cycle_count_high = ev->rx_cycle_count_high;5497bss_ch_info_ev->rx_bss_cycle_count_low = ev->rx_bss_cycle_count_low;5498bss_ch_info_ev->rx_bss_cycle_count_high = ev->rx_bss_cycle_count_high;54995500kfree(tb);5501return 0;5502}55035504static int5505ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *skb,5506struct wmi_vdev_install_key_complete_arg *arg)5507{5508const void **tb;5509const struct wmi_vdev_install_key_compl_event *ev;5510int ret;55115512tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5513if (IS_ERR(tb)) {5514ret = PTR_ERR(tb);5515ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5516return ret;5517}55185519ev = tb[WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT];5520if (!ev) {5521ath12k_warn(ab, "failed to fetch vdev install key compl ev");5522kfree(tb);5523return -EPROTO;5524}55255526arg->vdev_id = le32_to_cpu(ev->vdev_id);5527arg->macaddr = ev->peer_macaddr.addr;5528arg->key_idx = le32_to_cpu(ev->key_idx);5529arg->key_flags = le32_to_cpu(ev->key_flags);5530arg->status = le32_to_cpu(ev->status);55315532kfree(tb);5533return 0;5534}55355536static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff *skb,5537struct wmi_peer_assoc_conf_arg *peer_assoc_conf)5538{5539const void **tb;5540const struct wmi_peer_assoc_conf_event *ev;5541int ret;55425543tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);5544if (IS_ERR(tb)) {5545ret = PTR_ERR(tb);5546ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5547return ret;5548}55495550ev = tb[WMI_TAG_PEER_ASSOC_CONF_EVENT];5551if (!ev) {5552ath12k_warn(ab, "failed to fetch peer assoc conf ev");5553kfree(tb);5554return -EPROTO;5555}55565557peer_assoc_conf->vdev_id = le32_to_cpu(ev->vdev_id);5558peer_assoc_conf->macaddr = ev->peer_macaddr.addr;55595560kfree(tb);5561return 0;5562}55635564static int5565ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, u8 *evt_buf,5566u32 len, const struct wmi_pdev_temperature_event *ev)5567{5568const void **tb;5569int ret;55705571tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC);5572if (IS_ERR(tb)) {5573ret = PTR_ERR(tb);5574ath12k_warn(ab, "failed to parse tlv: %d\n", ret);5575return ret;5576}55775578ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT];5579if (!ev) {5580ath12k_warn(ab, "failed to fetch pdev temp ev");5581kfree(tb);5582return -EPROTO;5583}55845585kfree(tb);5586return 0;5587}55885589static void ath12k_wmi_op_ep_tx_credits(struct ath12k_base *ab)5590{5591/* try to send pending beacons first. they take priority */5592wake_up(&ab->wmi_ab.tx_credits_wq);5593}55945595static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,5596struct sk_buff *skb)5597{5598dev_kfree_skb(skb);5599}56005601static bool ath12k_reg_is_world_alpha(char *alpha)5602{5603return alpha[0] == '0' && alpha[1] == '0';5604}56055606static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)5607{5608struct ath12k_reg_info *reg_info = NULL;5609struct ieee80211_regdomain *regd = NULL;5610bool intersect = false;5611int ret = 0, pdev_idx, i, j;5612struct ath12k *ar;56135614reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);5615if (!reg_info) {5616ret = -ENOMEM;5617goto fallback;5618}56195620ret = ath12k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);56215622if (ret) {5623ath12k_warn(ab, "failed to extract regulatory info from received event\n");5624goto fallback;5625}56265627if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {5628/* In case of failure to set the requested ctry,5629* fw retains the current regd. We print a failure info5630* and return from here.5631*/5632ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n");5633goto mem_free;5634}56355636pdev_idx = reg_info->phy_id;56375638if (pdev_idx >= ab->num_radios) {5639/* Process the event for phy0 only if single_pdev_only5640* is true. If pdev_idx is valid but not 0, discard the5641* event. Otherwise, it goes to fallback.5642*/5643if (ab->hw_params->single_pdev_only &&5644pdev_idx < ab->hw_params->num_rxmda_per_pdev)5645goto mem_free;5646else5647goto fallback;5648}56495650/* Avoid multiple overwrites to default regd, during core5651* stop-start after mac registration.5652*/5653if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&5654!memcmp(ab->default_regd[pdev_idx]->alpha2,5655reg_info->alpha2, 2))5656goto mem_free;56575658/* Intersect new rules with default regd if a new country setting was5659* requested, i.e a default regd was already set during initialization5660* and the regd coming from this event has a valid country info.5661*/5662if (ab->default_regd[pdev_idx] &&5663!ath12k_reg_is_world_alpha((char *)5664ab->default_regd[pdev_idx]->alpha2) &&5665!ath12k_reg_is_world_alpha((char *)reg_info->alpha2))5666intersect = true;56675668regd = ath12k_reg_build_regd(ab, reg_info, intersect);5669if (!regd) {5670ath12k_warn(ab, "failed to build regd from reg_info\n");5671goto fallback;5672}56735674spin_lock(&ab->base_lock);5675if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) {5676/* Once mac is registered, ar is valid and all CC events from5677* fw is considered to be received due to user requests5678* currently.5679* Free previously built regd before assigning the newly5680* generated regd to ar. NULL pointer handling will be5681* taken care by kfree itself.5682*/5683ar = ab->pdevs[pdev_idx].ar;5684kfree(ab->new_regd[pdev_idx]);5685ab->new_regd[pdev_idx] = regd;5686queue_work(ab->workqueue, &ar->regd_update_work);5687} else {5688/* Multiple events for the same *ar is not expected. But we5689* can still clear any previously stored default_regd if we5690* are receiving this event for the same radio by mistake.5691* NULL pointer handling will be taken care by kfree itself.5692*/5693kfree(ab->default_regd[pdev_idx]);5694/* This regd would be applied during mac registration */5695ab->default_regd[pdev_idx] = regd;5696}5697ab->dfs_region = reg_info->dfs_region;5698spin_unlock(&ab->base_lock);56995700goto mem_free;57015702fallback:5703/* Fallback to older reg (by sending previous country setting5704* again if fw has succeeded and we failed to process here.5705* The Regdomain should be uniform across driver and fw. Since the5706* FW has processed the command and sent a success status, we expect5707* this function to succeed as well. If it doesn't, CTRY needs to be5708* reverted at the fw and the old SCAN_CHAN_LIST cmd needs to be sent.5709*/5710/* TODO: This is rare, but still should also be handled */5711WARN_ON(1);5712mem_free:5713if (reg_info) {5714kfree(reg_info->reg_rules_2g_ptr);5715kfree(reg_info->reg_rules_5g_ptr);5716if (reg_info->is_ext_reg_event) {5717for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)5718kfree(reg_info->reg_rules_6g_ap_ptr[i]);57195720for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)5721for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++)5722kfree(reg_info->reg_rules_6g_client_ptr[j][i]);5723}5724kfree(reg_info);5725}5726return ret;5727}57285729static int ath12k_wmi_rdy_parse(struct ath12k_base *ab, u16 tag, u16 len,5730const void *ptr, void *data)5731{5732struct ath12k_wmi_rdy_parse *rdy_parse = data;5733struct wmi_ready_event fixed_param;5734#if defined(__linux__)5735struct ath12k_wmi_mac_addr_params *addr_list;5736#elif defined(__FreeBSD__)5737const struct ath12k_wmi_mac_addr_params *addr_list;5738#endif5739struct ath12k_pdev *pdev;5740u32 num_mac_addr;5741int i;57425743switch (tag) {5744case WMI_TAG_READY_EVENT:5745memset(&fixed_param, 0, sizeof(fixed_param));5746#if defined(__linux__)5747memcpy(&fixed_param, (struct wmi_ready_event *)ptr,5748#elif defined(__FreeBSD__)5749memcpy(&fixed_param, (const struct wmi_ready_event *)ptr,5750#endif5751min_t(u16, sizeof(fixed_param), len));5752ab->wlan_init_status = le32_to_cpu(fixed_param.ready_event_min.status);5753rdy_parse->num_extra_mac_addr =5754le32_to_cpu(fixed_param.ready_event_min.num_extra_mac_addr);57555756ether_addr_copy(ab->mac_addr,5757fixed_param.ready_event_min.mac_addr.addr);5758ab->pktlog_defs_checksum = le32_to_cpu(fixed_param.pktlog_defs_checksum);5759ab->wmi_ready = true;5760break;5761case WMI_TAG_ARRAY_FIXED_STRUCT:5762#if defined(__linux__)5763addr_list = (struct ath12k_wmi_mac_addr_params *)ptr;5764#elif defined(__FreeBSD__)5765addr_list = (const struct ath12k_wmi_mac_addr_params *)ptr;5766#endif5767num_mac_addr = rdy_parse->num_extra_mac_addr;57685769if (!(ab->num_radios > 1 && num_mac_addr >= ab->num_radios))5770break;57715772for (i = 0; i < ab->num_radios; i++) {5773pdev = &ab->pdevs[i];5774ether_addr_copy(pdev->mac_addr, addr_list[i].addr);5775}5776ab->pdevs_macaddr_valid = true;5777break;5778default:5779break;5780}57815782return 0;5783}57845785static int ath12k_ready_event(struct ath12k_base *ab, struct sk_buff *skb)5786{5787struct ath12k_wmi_rdy_parse rdy_parse = { };5788int ret;57895790ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,5791ath12k_wmi_rdy_parse, &rdy_parse);5792if (ret) {5793ath12k_warn(ab, "failed to parse tlv %d\n", ret);5794return ret;5795}57965797complete(&ab->wmi_ab.unified_ready);5798return 0;5799}58005801static void ath12k_peer_delete_resp_event(struct ath12k_base *ab, struct sk_buff *skb)5802{5803struct wmi_peer_delete_resp_event peer_del_resp;5804struct ath12k *ar;58055806if (ath12k_pull_peer_del_resp_ev(ab, skb, &peer_del_resp) != 0) {5807ath12k_warn(ab, "failed to extract peer delete resp");5808return;5809}58105811rcu_read_lock();5812ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(peer_del_resp.vdev_id));5813if (!ar) {5814ath12k_warn(ab, "invalid vdev id in peer delete resp ev %d",5815peer_del_resp.vdev_id);5816rcu_read_unlock();5817return;5818}58195820complete(&ar->peer_delete_done);5821rcu_read_unlock();5822ath12k_dbg(ab, ATH12K_DBG_WMI, "peer delete resp for vdev id %d addr %pM\n",5823peer_del_resp.vdev_id, peer_del_resp.peer_macaddr.addr);5824}58255826static void ath12k_vdev_delete_resp_event(struct ath12k_base *ab,5827struct sk_buff *skb)5828{5829struct ath12k *ar;5830u32 vdev_id = 0;58315832if (ath12k_pull_vdev_del_resp_ev(ab, skb, &vdev_id) != 0) {5833ath12k_warn(ab, "failed to extract vdev delete resp");5834return;5835}58365837rcu_read_lock();5838ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);5839if (!ar) {5840ath12k_warn(ab, "invalid vdev id in vdev delete resp ev %d",5841vdev_id);5842rcu_read_unlock();5843return;5844}58455846complete(&ar->vdev_delete_done);58475848rcu_read_unlock();58495850ath12k_dbg(ab, ATH12K_DBG_WMI, "vdev delete resp for vdev id %d\n",5851vdev_id);5852}58535854static const char *ath12k_wmi_vdev_resp_print(u32 vdev_resp_status)5855{5856switch (vdev_resp_status) {5857case WMI_VDEV_START_RESPONSE_INVALID_VDEVID:5858return "invalid vdev id";5859case WMI_VDEV_START_RESPONSE_NOT_SUPPORTED:5860return "not supported";5861case WMI_VDEV_START_RESPONSE_DFS_VIOLATION:5862return "dfs violation";5863case WMI_VDEV_START_RESPONSE_INVALID_REGDOMAIN:5864return "invalid regdomain";5865default:5866return "unknown";5867}5868}58695870static void ath12k_vdev_start_resp_event(struct ath12k_base *ab, struct sk_buff *skb)5871{5872struct wmi_vdev_start_resp_event vdev_start_resp;5873struct ath12k *ar;5874u32 status;58755876if (ath12k_pull_vdev_start_resp_tlv(ab, skb, &vdev_start_resp) != 0) {5877ath12k_warn(ab, "failed to extract vdev start resp");5878return;5879}58805881rcu_read_lock();5882ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(vdev_start_resp.vdev_id));5883if (!ar) {5884ath12k_warn(ab, "invalid vdev id in vdev start resp ev %d",5885vdev_start_resp.vdev_id);5886rcu_read_unlock();5887return;5888}58895890ar->last_wmi_vdev_start_status = 0;58915892status = le32_to_cpu(vdev_start_resp.status);58935894if (WARN_ON_ONCE(status)) {5895ath12k_warn(ab, "vdev start resp error status %d (%s)\n",5896status, ath12k_wmi_vdev_resp_print(status));5897ar->last_wmi_vdev_start_status = status;5898}58995900complete(&ar->vdev_setup_done);59015902rcu_read_unlock();59035904ath12k_dbg(ab, ATH12K_DBG_WMI, "vdev start resp for vdev id %d",5905vdev_start_resp.vdev_id);5906}59075908static void ath12k_bcn_tx_status_event(struct ath12k_base *ab, struct sk_buff *skb)5909{5910u32 vdev_id, tx_status;59115912if (ath12k_pull_bcn_tx_status_ev(ab, skb->data, skb->len,5913&vdev_id, &tx_status) != 0) {5914ath12k_warn(ab, "failed to extract bcn tx status");5915return;5916}5917}59185919static void ath12k_vdev_stopped_event(struct ath12k_base *ab, struct sk_buff *skb)5920{5921struct ath12k *ar;5922u32 vdev_id = 0;59235924if (ath12k_pull_vdev_stopped_param_tlv(ab, skb, &vdev_id) != 0) {5925ath12k_warn(ab, "failed to extract vdev stopped event");5926return;5927}59285929rcu_read_lock();5930ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);5931if (!ar) {5932ath12k_warn(ab, "invalid vdev id in vdev stopped ev %d",5933vdev_id);5934rcu_read_unlock();5935return;5936}59375938complete(&ar->vdev_setup_done);59395940rcu_read_unlock();59415942ath12k_dbg(ab, ATH12K_DBG_WMI, "vdev stopped for vdev id %d", vdev_id);5943}59445945static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)5946{5947struct ath12k_wmi_mgmt_rx_arg rx_ev = {0};5948struct ath12k *ar;5949struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);5950struct ieee80211_hdr *hdr;5951u16 fc;5952struct ieee80211_supported_band *sband;59535954if (ath12k_pull_mgmt_rx_params_tlv(ab, skb, &rx_ev) != 0) {5955ath12k_warn(ab, "failed to extract mgmt rx event");5956dev_kfree_skb(skb);5957return;5958}59595960memset(status, 0, sizeof(*status));59615962ath12k_dbg(ab, ATH12K_DBG_MGMT, "mgmt rx event status %08x\n",5963rx_ev.status);59645965rcu_read_lock();5966ar = ath12k_mac_get_ar_by_pdev_id(ab, rx_ev.pdev_id);59675968if (!ar) {5969ath12k_warn(ab, "invalid pdev_id %d in mgmt_rx_event\n",5970rx_ev.pdev_id);5971dev_kfree_skb(skb);5972goto exit;5973}59745975if ((test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) ||5976(rx_ev.status & (WMI_RX_STATUS_ERR_DECRYPT |5977WMI_RX_STATUS_ERR_KEY_CACHE_MISS |5978WMI_RX_STATUS_ERR_CRC))) {5979dev_kfree_skb(skb);5980goto exit;5981}59825983if (rx_ev.status & WMI_RX_STATUS_ERR_MIC)5984status->flag |= RX_FLAG_MMIC_ERROR;59855986if (rx_ev.chan_freq >= ATH12K_MIN_6G_FREQ) {5987status->band = NL80211_BAND_6GHZ;5988} else if (rx_ev.channel >= 1 && rx_ev.channel <= 14) {5989status->band = NL80211_BAND_2GHZ;5990} else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH12K_MAX_5G_CHAN) {5991status->band = NL80211_BAND_5GHZ;5992} else {5993/* Shouldn't happen unless list of advertised channels to5994* mac80211 has been changed.5995*/5996WARN_ON_ONCE(1);5997dev_kfree_skb(skb);5998goto exit;5999}60006001if (rx_ev.phy_mode == MODE_11B &&6002(status->band == NL80211_BAND_5GHZ || status->band == NL80211_BAND_6GHZ))6003ath12k_dbg(ab, ATH12K_DBG_WMI,6004"wmi mgmt rx 11b (CCK) on 5/6GHz, band = %d\n", status->band);60056006sband = &ar->mac.sbands[status->band];60076008status->freq = ieee80211_channel_to_frequency(rx_ev.channel,6009status->band);6010status->signal = rx_ev.snr + ATH12K_DEFAULT_NOISE_FLOOR;6011status->rate_idx = ath12k_mac_bitrate_to_idx(sband, rx_ev.rate / 100);60126013hdr = (struct ieee80211_hdr *)skb->data;6014fc = le16_to_cpu(hdr->frame_control);60156016/* Firmware is guaranteed to report all essential management frames via6017* WMI while it can deliver some extra via HTT. Since there can be6018* duplicates split the reporting wrt monitor/sniffing.6019*/6020status->flag |= RX_FLAG_SKIP_MONITOR;60216022/* In case of PMF, FW delivers decrypted frames with Protected Bit set6023* including group privacy action frames.6024*/6025if (ieee80211_has_protected(hdr->frame_control)) {6026status->flag |= RX_FLAG_DECRYPTED;60276028if (!ieee80211_is_robust_mgmt_frame(skb)) {6029status->flag |= RX_FLAG_IV_STRIPPED |6030RX_FLAG_MMIC_STRIPPED;6031hdr->frame_control = __cpu_to_le16(fc &6032~IEEE80211_FCTL_PROTECTED);6033}6034}60356036/* TODO: Pending handle beacon implementation6037*if (ieee80211_is_beacon(hdr->frame_control))6038* ath12k_mac_handle_beacon(ar, skb);6039*/60406041ath12k_dbg(ab, ATH12K_DBG_MGMT,6042"event mgmt rx skb %pK len %d ftype %02x stype %02x\n",6043skb, skb->len,6044fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE);60456046ath12k_dbg(ab, ATH12K_DBG_MGMT,6047"event mgmt rx freq %d band %d snr %d, rate_idx %d\n",6048status->freq, status->band, status->signal,6049status->rate_idx);60506051ieee80211_rx_ni(ar->hw, skb);60526053exit:6054rcu_read_unlock();6055}60566057static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *skb)6058{6059struct wmi_mgmt_tx_compl_event tx_compl_param = {0};6060struct ath12k *ar;60616062if (ath12k_pull_mgmt_tx_compl_param_tlv(ab, skb, &tx_compl_param) != 0) {6063ath12k_warn(ab, "failed to extract mgmt tx compl event");6064return;6065}60666067rcu_read_lock();6068ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(tx_compl_param.pdev_id));6069if (!ar) {6070ath12k_warn(ab, "invalid pdev id %d in mgmt_tx_compl_event\n",6071tx_compl_param.pdev_id);6072goto exit;6073}60746075wmi_process_mgmt_tx_comp(ar, le32_to_cpu(tx_compl_param.desc_id),6076le32_to_cpu(tx_compl_param.status));60776078ath12k_dbg(ab, ATH12K_DBG_MGMT,6079"mgmt tx compl ev pdev_id %d, desc_id %d, status %d",6080tx_compl_param.pdev_id, tx_compl_param.desc_id,6081tx_compl_param.status);60826083exit:6084rcu_read_unlock();6085}60866087static struct ath12k *ath12k_get_ar_on_scan_abort(struct ath12k_base *ab,6088u32 vdev_id)6089{6090int i;6091struct ath12k_pdev *pdev;6092struct ath12k *ar;60936094for (i = 0; i < ab->num_radios; i++) {6095pdev = rcu_dereference(ab->pdevs_active[i]);6096if (pdev && pdev->ar) {6097ar = pdev->ar;60986099spin_lock_bh(&ar->data_lock);6100if (ar->scan.state == ATH12K_SCAN_ABORTING &&6101ar->scan.vdev_id == vdev_id) {6102spin_unlock_bh(&ar->data_lock);6103return ar;6104}6105spin_unlock_bh(&ar->data_lock);6106}6107}6108return NULL;6109}61106111static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb)6112{6113struct ath12k *ar;6114struct wmi_scan_event scan_ev = {0};61156116if (ath12k_pull_scan_ev(ab, skb, &scan_ev) != 0) {6117ath12k_warn(ab, "failed to extract scan event");6118return;6119}61206121rcu_read_lock();61226123/* In case the scan was cancelled, ex. during interface teardown,6124* the interface will not be found in active interfaces.6125* Rather, in such scenarios, iterate over the active pdev's to6126* search 'ar' if the corresponding 'ar' scan is ABORTING and the6127* aborting scan's vdev id matches this event info.6128*/6129if (le32_to_cpu(scan_ev.event_type) == WMI_SCAN_EVENT_COMPLETED &&6130le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED)6131ar = ath12k_get_ar_on_scan_abort(ab, le32_to_cpu(scan_ev.vdev_id));6132else6133ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(scan_ev.vdev_id));61346135if (!ar) {6136ath12k_warn(ab, "Received scan event for unknown vdev");6137rcu_read_unlock();6138return;6139}61406141spin_lock_bh(&ar->data_lock);61426143ath12k_dbg(ab, ATH12K_DBG_WMI,6144"scan event %s type %d reason %d freq %d req_id %d scan_id %d vdev_id %d state %s (%d)\n",6145ath12k_wmi_event_scan_type_str(le32_to_cpu(scan_ev.event_type),6146le32_to_cpu(scan_ev.reason)),6147le32_to_cpu(scan_ev.event_type),6148le32_to_cpu(scan_ev.reason),6149le32_to_cpu(scan_ev.channel_freq),6150le32_to_cpu(scan_ev.scan_req_id),6151le32_to_cpu(scan_ev.scan_id),6152le32_to_cpu(scan_ev.vdev_id),6153ath12k_scan_state_str(ar->scan.state), ar->scan.state);61546155switch (le32_to_cpu(scan_ev.event_type)) {6156case WMI_SCAN_EVENT_STARTED:6157ath12k_wmi_event_scan_started(ar);6158break;6159case WMI_SCAN_EVENT_COMPLETED:6160ath12k_wmi_event_scan_completed(ar);6161break;6162case WMI_SCAN_EVENT_BSS_CHANNEL:6163ath12k_wmi_event_scan_bss_chan(ar);6164break;6165case WMI_SCAN_EVENT_FOREIGN_CHAN:6166ath12k_wmi_event_scan_foreign_chan(ar, le32_to_cpu(scan_ev.channel_freq));6167break;6168case WMI_SCAN_EVENT_START_FAILED:6169ath12k_warn(ab, "received scan start failure event\n");6170ath12k_wmi_event_scan_start_failed(ar);6171break;6172case WMI_SCAN_EVENT_DEQUEUED:6173__ath12k_mac_scan_finish(ar);6174break;6175case WMI_SCAN_EVENT_PREEMPTED:6176case WMI_SCAN_EVENT_RESTARTED:6177case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT:6178default:6179break;6180}61816182spin_unlock_bh(&ar->data_lock);61836184rcu_read_unlock();6185}61866187static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff *skb)6188{6189struct wmi_peer_sta_kickout_arg arg = {};6190struct ieee80211_sta *sta;6191struct ath12k_peer *peer;6192struct ath12k *ar;61936194if (ath12k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) {6195ath12k_warn(ab, "failed to extract peer sta kickout event");6196return;6197}61986199rcu_read_lock();62006201spin_lock_bh(&ab->base_lock);62026203peer = ath12k_peer_find_by_addr(ab, arg.mac_addr);62046205if (!peer) {6206ath12k_warn(ab, "peer not found %pM\n",6207arg.mac_addr);6208goto exit;6209}62106211ar = ath12k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);6212if (!ar) {6213ath12k_warn(ab, "invalid vdev id in peer sta kickout ev %d",6214peer->vdev_id);6215goto exit;6216}62176218sta = ieee80211_find_sta_by_ifaddr(ar->hw,6219arg.mac_addr, NULL);6220if (!sta) {6221ath12k_warn(ab, "Spurious quick kickout for STA %pM\n",6222arg.mac_addr);6223goto exit;6224}62256226ath12k_dbg(ab, ATH12K_DBG_WMI, "peer sta kickout event %pM",6227arg.mac_addr);62286229ieee80211_report_low_ack(sta, 10);62306231exit:6232spin_unlock_bh(&ab->base_lock);6233rcu_read_unlock();6234}62356236static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)6237{6238struct wmi_roam_event roam_ev = {};6239struct ath12k *ar;62406241if (ath12k_pull_roam_ev(ab, skb, &roam_ev) != 0) {6242ath12k_warn(ab, "failed to extract roam event");6243return;6244}62456246ath12k_dbg(ab, ATH12K_DBG_WMI,6247"wmi roam event vdev %u reason 0x%08x rssi %d\n",6248roam_ev.vdev_id, roam_ev.reason, roam_ev.rssi);62496250rcu_read_lock();6251ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(roam_ev.vdev_id));6252if (!ar) {6253ath12k_warn(ab, "invalid vdev id in roam ev %d",6254roam_ev.vdev_id);6255rcu_read_unlock();6256return;6257}62586259if (le32_to_cpu(roam_ev.reason) >= WMI_ROAM_REASON_MAX)6260ath12k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n",6261roam_ev.reason, roam_ev.vdev_id);62626263switch (le32_to_cpu(roam_ev.reason)) {6264case WMI_ROAM_REASON_BEACON_MISS:6265/* TODO: Pending beacon miss and connection_loss_work6266* implementation6267* ath12k_mac_handle_beacon_miss(ar, vdev_id);6268*/6269break;6270case WMI_ROAM_REASON_BETTER_AP:6271case WMI_ROAM_REASON_LOW_RSSI:6272case WMI_ROAM_REASON_SUITABLE_AP_FOUND:6273case WMI_ROAM_REASON_HO_FAILED:6274ath12k_warn(ab, "ignoring not implemented roam event reason %d on vdev %i\n",6275roam_ev.reason, roam_ev.vdev_id);6276break;6277}62786279rcu_read_unlock();6280}62816282static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)6283{6284struct wmi_chan_info_event ch_info_ev = {0};6285struct ath12k *ar;6286struct survey_info *survey;6287int idx;6288/* HW channel counters frequency value in hertz */6289u32 cc_freq_hz = ab->cc_freq_hz;62906291if (ath12k_pull_chan_info_ev(ab, skb->data, skb->len, &ch_info_ev) != 0) {6292ath12k_warn(ab, "failed to extract chan info event");6293return;6294}62956296ath12k_dbg(ab, ATH12K_DBG_WMI,6297"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",6298ch_info_ev.vdev_id, ch_info_ev.err_code, ch_info_ev.freq,6299ch_info_ev.cmd_flags, ch_info_ev.noise_floor,6300ch_info_ev.rx_clear_count, ch_info_ev.cycle_count,6301ch_info_ev.mac_clk_mhz);63026303if (le32_to_cpu(ch_info_ev.cmd_flags) == WMI_CHAN_INFO_END_RESP) {6304ath12k_dbg(ab, ATH12K_DBG_WMI, "chan info report completed\n");6305return;6306}63076308rcu_read_lock();6309ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(ch_info_ev.vdev_id));6310if (!ar) {6311ath12k_warn(ab, "invalid vdev id in chan info ev %d",6312ch_info_ev.vdev_id);6313rcu_read_unlock();6314return;6315}6316spin_lock_bh(&ar->data_lock);63176318switch (ar->scan.state) {6319case ATH12K_SCAN_IDLE:6320case ATH12K_SCAN_STARTING:6321ath12k_warn(ab, "received chan info event without a scan request, ignoring\n");6322goto exit;6323case ATH12K_SCAN_RUNNING:6324case ATH12K_SCAN_ABORTING:6325break;6326}63276328idx = freq_to_idx(ar, le32_to_cpu(ch_info_ev.freq));6329if (idx >= ARRAY_SIZE(ar->survey)) {6330ath12k_warn(ab, "chan info: invalid frequency %d (idx %d out of bounds)\n",6331ch_info_ev.freq, idx);6332goto exit;6333}63346335/* If FW provides MAC clock frequency in Mhz, overriding the initialized6336* HW channel counters frequency value6337*/6338if (ch_info_ev.mac_clk_mhz)6339cc_freq_hz = (le32_to_cpu(ch_info_ev.mac_clk_mhz) * 1000);63406341if (ch_info_ev.cmd_flags == WMI_CHAN_INFO_START_RESP) {6342survey = &ar->survey[idx];6343memset(survey, 0, sizeof(*survey));6344survey->noise = le32_to_cpu(ch_info_ev.noise_floor);6345survey->filled = SURVEY_INFO_NOISE_DBM | SURVEY_INFO_TIME |6346SURVEY_INFO_TIME_BUSY;6347survey->time = div_u64(le32_to_cpu(ch_info_ev.cycle_count), cc_freq_hz);6348survey->time_busy = div_u64(le32_to_cpu(ch_info_ev.rx_clear_count),6349cc_freq_hz);6350}6351exit:6352spin_unlock_bh(&ar->data_lock);6353rcu_read_unlock();6354}63556356static void6357ath12k_pdev_bss_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)6358{6359struct wmi_pdev_bss_chan_info_event bss_ch_info_ev = {};6360struct survey_info *survey;6361struct ath12k *ar;6362u32 cc_freq_hz = ab->cc_freq_hz;6363u64 busy, total, tx, rx, rx_bss;6364int idx;63656366if (ath12k_pull_pdev_bss_chan_info_ev(ab, skb, &bss_ch_info_ev) != 0) {6367ath12k_warn(ab, "failed to extract pdev bss chan info event");6368return;6369}63706371busy = (u64)(le32_to_cpu(bss_ch_info_ev.rx_clear_count_high)) << 32 |6372le32_to_cpu(bss_ch_info_ev.rx_clear_count_low);63736374total = (u64)(le32_to_cpu(bss_ch_info_ev.cycle_count_high)) << 32 |6375le32_to_cpu(bss_ch_info_ev.cycle_count_low);63766377tx = (u64)(le32_to_cpu(bss_ch_info_ev.tx_cycle_count_high)) << 32 |6378le32_to_cpu(bss_ch_info_ev.tx_cycle_count_low);63796380rx = (u64)(le32_to_cpu(bss_ch_info_ev.rx_cycle_count_high)) << 32 |6381le32_to_cpu(bss_ch_info_ev.rx_cycle_count_low);63826383rx_bss = (u64)(le32_to_cpu(bss_ch_info_ev.rx_bss_cycle_count_high)) << 32 |6384le32_to_cpu(bss_ch_info_ev.rx_bss_cycle_count_low);63856386ath12k_dbg(ab, ATH12K_DBG_WMI,6387#if defined(__linux__)6388"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",6389bss_ch_info_ev.pdev_id, bss_ch_info_ev.freq,6390bss_ch_info_ev.noise_floor, busy, total,6391tx, rx, rx_bss);6392#elif defined(__FreeBSD__)6393"pdev bss chan info:\n pdev_id: %d freq: %d noise: %d cycle: busy %ju total %ju tx %ju rx %ju rx_bss %ju\n",6394bss_ch_info_ev.pdev_id, bss_ch_info_ev.freq,6395bss_ch_info_ev.noise_floor, (uintmax_t)busy, (uintmax_t)total,6396(uintmax_t)tx, (uintmax_t)rx, (uintmax_t)rx_bss);6397#endif63986399rcu_read_lock();6400ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(bss_ch_info_ev.pdev_id));64016402if (!ar) {6403ath12k_warn(ab, "invalid pdev id %d in bss_chan_info event\n",6404bss_ch_info_ev.pdev_id);6405rcu_read_unlock();6406return;6407}64086409spin_lock_bh(&ar->data_lock);6410idx = freq_to_idx(ar, le32_to_cpu(bss_ch_info_ev.freq));6411if (idx >= ARRAY_SIZE(ar->survey)) {6412ath12k_warn(ab, "bss chan info: invalid frequency %d (idx %d out of bounds)\n",6413bss_ch_info_ev.freq, idx);6414goto exit;6415}64166417survey = &ar->survey[idx];64186419survey->noise = le32_to_cpu(bss_ch_info_ev.noise_floor);6420survey->time = div_u64(total, cc_freq_hz);6421survey->time_busy = div_u64(busy, cc_freq_hz);6422survey->time_rx = div_u64(rx_bss, cc_freq_hz);6423survey->time_tx = div_u64(tx, cc_freq_hz);6424survey->filled |= (SURVEY_INFO_NOISE_DBM |6425SURVEY_INFO_TIME |6426SURVEY_INFO_TIME_BUSY |6427SURVEY_INFO_TIME_RX |6428SURVEY_INFO_TIME_TX);6429exit:6430spin_unlock_bh(&ar->data_lock);6431complete(&ar->bss_survey_done);64326433rcu_read_unlock();6434}64356436static void ath12k_vdev_install_key_compl_event(struct ath12k_base *ab,6437struct sk_buff *skb)6438{6439struct wmi_vdev_install_key_complete_arg install_key_compl = {0};6440struct ath12k *ar;64416442if (ath12k_pull_vdev_install_key_compl_ev(ab, skb, &install_key_compl) != 0) {6443ath12k_warn(ab, "failed to extract install key compl event");6444return;6445}64466447ath12k_dbg(ab, ATH12K_DBG_WMI,6448"vdev install key ev idx %d flags %08x macaddr %pM status %d\n",6449install_key_compl.key_idx, install_key_compl.key_flags,6450install_key_compl.macaddr, install_key_compl.status);64516452rcu_read_lock();6453ar = ath12k_mac_get_ar_by_vdev_id(ab, install_key_compl.vdev_id);6454if (!ar) {6455ath12k_warn(ab, "invalid vdev id in install key compl ev %d",6456install_key_compl.vdev_id);6457rcu_read_unlock();6458return;6459}64606461ar->install_key_status = 0;64626463if (install_key_compl.status != WMI_VDEV_INSTALL_KEY_COMPL_STATUS_SUCCESS) {6464ath12k_warn(ab, "install key failed for %pM status %d\n",6465install_key_compl.macaddr, install_key_compl.status);6466ar->install_key_status = install_key_compl.status;6467}64686469complete(&ar->install_key_done);6470rcu_read_unlock();6471}64726473static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab,6474u16 tag, u16 len,6475const void *ptr,6476void *data)6477{6478const struct wmi_service_available_event *ev;6479#if defined(__linux__)6480u32 *wmi_ext2_service_bitmap;6481#elif defined(__FreeBSD__)6482const u32 *wmi_ext2_service_bitmap;6483#endif6484int i, j;6485u16 expected_len;64866487expected_len = WMI_SERVICE_SEGMENT_BM_SIZE32 * sizeof(u32);6488if (len < expected_len) {6489ath12k_warn(ab, "invalid length %d for the WMI services available tag 0x%x\n",6490len, tag);6491return -EINVAL;6492}64936494switch (tag) {6495case WMI_TAG_SERVICE_AVAILABLE_EVENT:6496#if defined(__linux__)6497ev = (struct wmi_service_available_event *)ptr;6498#elif defined(__FreeBSD__)6499ev = (const struct wmi_service_available_event *)ptr;6500#endif6501for (i = 0, j = WMI_MAX_SERVICE;6502i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT_SERVICE;6503i++) {6504do {6505if (le32_to_cpu(ev->wmi_service_segment_bitmap[i]) &6506BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32))6507set_bit(j, ab->wmi_ab.svc_map);6508} while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32);6509}65106511ath12k_dbg(ab, ATH12K_DBG_WMI,6512"wmi_ext_service_bitmap 0x%x 0x%x 0x%x 0x%x",6513ev->wmi_service_segment_bitmap[0],6514ev->wmi_service_segment_bitmap[1],6515ev->wmi_service_segment_bitmap[2],6516ev->wmi_service_segment_bitmap[3]);6517break;6518case WMI_TAG_ARRAY_UINT32:6519#if defined(__linux__)6520wmi_ext2_service_bitmap = (u32 *)ptr;6521#elif defined(__FreeBSD__)6522wmi_ext2_service_bitmap = (const u32 *)ptr;6523#endif6524for (i = 0, j = WMI_MAX_EXT_SERVICE;6525i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT2_SERVICE;6526i++) {6527do {6528if (wmi_ext2_service_bitmap[i] &6529BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32))6530set_bit(j, ab->wmi_ab.svc_map);6531} while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32);6532}65336534ath12k_dbg(ab, ATH12K_DBG_WMI,6535"wmi_ext2_service_bitmap 0x%04x 0x%04x 0x%04x 0x%04x",6536wmi_ext2_service_bitmap[0], wmi_ext2_service_bitmap[1],6537wmi_ext2_service_bitmap[2], wmi_ext2_service_bitmap[3]);6538break;6539}6540return 0;6541}65426543static int ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff *skb)6544{6545int ret;65466547ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,6548ath12k_wmi_tlv_services_parser,6549NULL);6550return ret;6551}65526553static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff *skb)6554{6555struct wmi_peer_assoc_conf_arg peer_assoc_conf = {0};6556struct ath12k *ar;65576558if (ath12k_pull_peer_assoc_conf_ev(ab, skb, &peer_assoc_conf) != 0) {6559ath12k_warn(ab, "failed to extract peer assoc conf event");6560return;6561}65626563ath12k_dbg(ab, ATH12K_DBG_WMI,6564"peer assoc conf ev vdev id %d macaddr %pM\n",6565peer_assoc_conf.vdev_id, peer_assoc_conf.macaddr);65666567rcu_read_lock();6568ar = ath12k_mac_get_ar_by_vdev_id(ab, peer_assoc_conf.vdev_id);65696570if (!ar) {6571ath12k_warn(ab, "invalid vdev id in peer assoc conf ev %d",6572peer_assoc_conf.vdev_id);6573rcu_read_unlock();6574return;6575}65766577complete(&ar->peer_assoc_done);6578rcu_read_unlock();6579}65806581static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *skb)6582{6583}65846585/* PDEV_CTL_FAILSAFE_CHECK_EVENT is received from FW when the frequency scanned6586* is not part of BDF CTL(Conformance test limits) table entries.6587*/6588static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,6589struct sk_buff *skb)6590{6591const void **tb;6592const struct wmi_pdev_ctl_failsafe_chk_event *ev;6593int ret;65946595tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);6596if (IS_ERR(tb)) {6597ret = PTR_ERR(tb);6598ath12k_warn(ab, "failed to parse tlv: %d\n", ret);6599return;6600}66016602ev = tb[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT];6603if (!ev) {6604ath12k_warn(ab, "failed to fetch pdev ctl failsafe check ev");6605kfree(tb);6606return;6607}66086609ath12k_dbg(ab, ATH12K_DBG_WMI,6610"pdev ctl failsafe check ev status %d\n",6611ev->ctl_failsafe_status);66126613/* If ctl_failsafe_status is set to 1 FW will max out the Transmit power6614* to 10 dBm else the CTL power entry in the BDF would be picked up.6615*/6616if (ev->ctl_failsafe_status != 0)6617ath12k_warn(ab, "pdev ctl failsafe failure status %d",6618ev->ctl_failsafe_status);66196620kfree(tb);6621}66226623static void6624ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,6625const struct ath12k_wmi_pdev_csa_event *ev,6626const u32 *vdev_ids)6627{6628int i;6629struct ath12k_vif *arvif;66306631/* Finish CSA once the switch count becomes NULL */6632if (ev->current_switch_count)6633return;66346635rcu_read_lock();6636for (i = 0; i < le32_to_cpu(ev->num_vdevs); i++) {6637arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_ids[i]);66386639if (!arvif) {6640ath12k_warn(ab, "Recvd csa status for unknown vdev %d",6641vdev_ids[i]);6642continue;6643}66446645if (arvif->is_up && arvif->vif->bss_conf.csa_active)6646ieee80211_csa_finish(arvif->vif);6647}6648rcu_read_unlock();6649}66506651static void6652ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,6653struct sk_buff *skb)6654{6655const void **tb;6656const struct ath12k_wmi_pdev_csa_event *ev;6657const u32 *vdev_ids;6658int ret;66596660tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);6661if (IS_ERR(tb)) {6662ret = PTR_ERR(tb);6663ath12k_warn(ab, "failed to parse tlv: %d\n", ret);6664return;6665}66666667ev = tb[WMI_TAG_PDEV_CSA_SWITCH_COUNT_STATUS_EVENT];6668vdev_ids = tb[WMI_TAG_ARRAY_UINT32];66696670if (!ev || !vdev_ids) {6671ath12k_warn(ab, "failed to fetch pdev csa switch count ev");6672kfree(tb);6673return;6674}66756676ath12k_dbg(ab, ATH12K_DBG_WMI,6677"pdev csa switch count %d for pdev %d, num_vdevs %d",6678ev->current_switch_count, ev->pdev_id,6679ev->num_vdevs);66806681ath12k_wmi_process_csa_switch_count_event(ab, ev, vdev_ids);66826683kfree(tb);6684}66856686static void6687ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff *skb)6688{6689const void **tb;6690const struct ath12k_wmi_pdev_radar_event *ev;6691struct ath12k *ar;6692int ret;66936694tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);6695if (IS_ERR(tb)) {6696ret = PTR_ERR(tb);6697ath12k_warn(ab, "failed to parse tlv: %d\n", ret);6698return;6699}67006701ev = tb[WMI_TAG_PDEV_DFS_RADAR_DETECTION_EVENT];67026703if (!ev) {6704ath12k_warn(ab, "failed to fetch pdev dfs radar detected ev");6705kfree(tb);6706return;6707}67086709ath12k_dbg(ab, ATH12K_DBG_WMI,6710"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",6711ev->pdev_id, ev->detection_mode, ev->chan_freq, ev->chan_width,6712ev->detector_id, ev->segment_id, ev->timestamp, ev->is_chirp,6713ev->freq_offset, ev->sidx);67146715ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev->pdev_id));67166717if (!ar) {6718ath12k_warn(ab, "radar detected in invalid pdev %d\n",6719ev->pdev_id);6720goto exit;6721}67226723ath12k_dbg(ar->ab, ATH12K_DBG_REG, "DFS Radar Detected in pdev %d\n",6724ev->pdev_id);67256726if (ar->dfs_block_radar_events)6727ath12k_info(ab, "DFS Radar detected, but ignored as requested\n");6728else6729ieee80211_radar_detected(ar->hw);67306731exit:6732kfree(tb);6733}67346735static void6736ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,6737struct sk_buff *skb)6738{6739struct ath12k *ar;6740struct wmi_pdev_temperature_event ev = {0};67416742if (ath12k_pull_pdev_temp_ev(ab, skb->data, skb->len, &ev) != 0) {6743ath12k_warn(ab, "failed to extract pdev temperature event");6744return;6745}67466747ath12k_dbg(ab, ATH12K_DBG_WMI,6748"pdev temperature ev temp %d pdev_id %d\n", ev.temp, ev.pdev_id);67496750ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev.pdev_id));6751if (!ar) {6752ath12k_warn(ab, "invalid pdev id in pdev temperature ev %d", ev.pdev_id);6753return;6754}6755}67566757static void ath12k_fils_discovery_event(struct ath12k_base *ab,6758struct sk_buff *skb)6759{6760const void **tb;6761const struct wmi_fils_discovery_event *ev;6762int ret;67636764tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);6765if (IS_ERR(tb)) {6766ret = PTR_ERR(tb);6767ath12k_warn(ab,6768"failed to parse FILS discovery event tlv %d\n",6769ret);6770return;6771}67726773ev = tb[WMI_TAG_HOST_SWFDA_EVENT];6774if (!ev) {6775ath12k_warn(ab, "failed to fetch FILS discovery event\n");6776kfree(tb);6777return;6778}67796780ath12k_warn(ab,6781"FILS discovery frame expected from host for vdev_id: %u, transmission scheduled at %u, next TBTT: %u\n",6782ev->vdev_id, ev->fils_tt, ev->tbtt);67836784kfree(tb);6785}67866787static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,6788struct sk_buff *skb)6789{6790const void **tb;6791const struct wmi_probe_resp_tx_status_event *ev;6792int ret;67936794tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);6795if (IS_ERR(tb)) {6796ret = PTR_ERR(tb);6797ath12k_warn(ab,6798"failed to parse probe response transmission status event tlv: %d\n",6799ret);6800return;6801}68026803ev = tb[WMI_TAG_OFFLOAD_PRB_RSP_TX_STATUS_EVENT];6804if (!ev) {6805ath12k_warn(ab,6806"failed to fetch probe response transmission status event");6807kfree(tb);6808return;6809}68106811if (ev->tx_status)6812ath12k_warn(ab,6813"Probe response transmission failed for vdev_id %u, status %u\n",6814ev->vdev_id, ev->tx_status);68156816kfree(tb);6817}68186819static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)6820{6821struct wmi_cmd_hdr *cmd_hdr;6822enum wmi_tlv_event_id id;68236824cmd_hdr = (struct wmi_cmd_hdr *)skb->data;6825id = le32_get_bits(cmd_hdr->cmd_id, WMI_CMD_HDR_CMD_ID);68266827if (!skb_pull(skb, sizeof(struct wmi_cmd_hdr)))6828goto out;68296830switch (id) {6831/* Process all the WMI events here */6832case WMI_SERVICE_READY_EVENTID:6833ath12k_service_ready_event(ab, skb);6834break;6835case WMI_SERVICE_READY_EXT_EVENTID:6836ath12k_service_ready_ext_event(ab, skb);6837break;6838case WMI_SERVICE_READY_EXT2_EVENTID:6839ath12k_service_ready_ext2_event(ab, skb);6840break;6841case WMI_REG_CHAN_LIST_CC_EXT_EVENTID:6842ath12k_reg_chan_list_event(ab, skb);6843break;6844case WMI_READY_EVENTID:6845ath12k_ready_event(ab, skb);6846break;6847case WMI_PEER_DELETE_RESP_EVENTID:6848ath12k_peer_delete_resp_event(ab, skb);6849break;6850case WMI_VDEV_START_RESP_EVENTID:6851ath12k_vdev_start_resp_event(ab, skb);6852break;6853case WMI_OFFLOAD_BCN_TX_STATUS_EVENTID:6854ath12k_bcn_tx_status_event(ab, skb);6855break;6856case WMI_VDEV_STOPPED_EVENTID:6857ath12k_vdev_stopped_event(ab, skb);6858break;6859case WMI_MGMT_RX_EVENTID:6860ath12k_mgmt_rx_event(ab, skb);6861/* mgmt_rx_event() owns the skb now! */6862return;6863case WMI_MGMT_TX_COMPLETION_EVENTID:6864ath12k_mgmt_tx_compl_event(ab, skb);6865break;6866case WMI_SCAN_EVENTID:6867ath12k_scan_event(ab, skb);6868break;6869case WMI_PEER_STA_KICKOUT_EVENTID:6870ath12k_peer_sta_kickout_event(ab, skb);6871break;6872case WMI_ROAM_EVENTID:6873ath12k_roam_event(ab, skb);6874break;6875case WMI_CHAN_INFO_EVENTID:6876ath12k_chan_info_event(ab, skb);6877break;6878case WMI_PDEV_BSS_CHAN_INFO_EVENTID:6879ath12k_pdev_bss_chan_info_event(ab, skb);6880break;6881case WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID:6882ath12k_vdev_install_key_compl_event(ab, skb);6883break;6884case WMI_SERVICE_AVAILABLE_EVENTID:6885ath12k_service_available_event(ab, skb);6886break;6887case WMI_PEER_ASSOC_CONF_EVENTID:6888ath12k_peer_assoc_conf_event(ab, skb);6889break;6890case WMI_UPDATE_STATS_EVENTID:6891ath12k_update_stats_event(ab, skb);6892break;6893case WMI_PDEV_CTL_FAILSAFE_CHECK_EVENTID:6894ath12k_pdev_ctl_failsafe_check_event(ab, skb);6895break;6896case WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID:6897ath12k_wmi_pdev_csa_switch_count_status_event(ab, skb);6898break;6899case WMI_PDEV_TEMPERATURE_EVENTID:6900ath12k_wmi_pdev_temperature_event(ab, skb);6901break;6902case WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID:6903ath12k_wmi_pdev_dma_ring_buf_release_event(ab, skb);6904break;6905case WMI_HOST_FILS_DISCOVERY_EVENTID:6906ath12k_fils_discovery_event(ab, skb);6907break;6908case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID:6909ath12k_probe_resp_tx_status_event(ab, skb);6910break;6911/* add Unsupported events here */6912case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:6913case WMI_PEER_OPER_MODE_CHANGE_EVENTID:6914case WMI_TWT_ENABLE_EVENTID:6915case WMI_TWT_DISABLE_EVENTID:6916case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID:6917ath12k_dbg(ab, ATH12K_DBG_WMI,6918"ignoring unsupported event 0x%x\n", id);6919break;6920case WMI_PDEV_DFS_RADAR_DETECTION_EVENTID:6921ath12k_wmi_pdev_dfs_radar_detected_event(ab, skb);6922break;6923case WMI_VDEV_DELETE_RESP_EVENTID:6924ath12k_vdev_delete_resp_event(ab, skb);6925break;6926/* TODO: Add remaining events */6927default:6928ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id);6929break;6930}69316932out:6933dev_kfree_skb(skb);6934}69356936static int ath12k_connect_pdev_htc_service(struct ath12k_base *ab,6937u32 pdev_idx)6938{6939int status;6940u32 svc_id[] = { ATH12K_HTC_SVC_ID_WMI_CONTROL,6941ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1,6942ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC2 };6943struct ath12k_htc_svc_conn_req conn_req = {};6944struct ath12k_htc_svc_conn_resp conn_resp = {};69456946/* these fields are the same for all service endpoints */6947conn_req.ep_ops.ep_tx_complete = ath12k_wmi_htc_tx_complete;6948conn_req.ep_ops.ep_rx_complete = ath12k_wmi_op_rx;6949conn_req.ep_ops.ep_tx_credits = ath12k_wmi_op_ep_tx_credits;69506951/* connect to control service */6952conn_req.service_id = svc_id[pdev_idx];69536954status = ath12k_htc_connect_service(&ab->htc, &conn_req, &conn_resp);6955if (status) {6956ath12k_warn(ab, "failed to connect to WMI CONTROL service status: %d\n",6957status);6958return status;6959}69606961ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid;6962ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid;6963ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len;69646965return 0;6966}69676968static int6969ath12k_wmi_send_unit_test_cmd(struct ath12k *ar,6970struct wmi_unit_test_cmd ut_cmd,6971u32 *test_args)6972{6973struct ath12k_wmi_pdev *wmi = ar->wmi;6974struct wmi_unit_test_cmd *cmd;6975struct sk_buff *skb;6976struct wmi_tlv *tlv;6977#if defined(__linux__)6978void *ptr;6979#elif defined(__FreeBSD__)6980u8 *ptr;6981#endif6982u32 *ut_cmd_args;6983int buf_len, arg_len;6984int ret;6985int i;69866987arg_len = sizeof(u32) * le32_to_cpu(ut_cmd.num_args);6988buf_len = sizeof(ut_cmd) + arg_len + TLV_HDR_SIZE;69896990skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, buf_len);6991if (!skb)6992return -ENOMEM;69936994cmd = (struct wmi_unit_test_cmd *)skb->data;6995cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_UNIT_TEST_CMD,6996sizeof(ut_cmd));69976998cmd->vdev_id = ut_cmd.vdev_id;6999cmd->module_id = ut_cmd.module_id;7000cmd->num_args = ut_cmd.num_args;7001cmd->diag_token = ut_cmd.diag_token;70027003ptr = skb->data + sizeof(ut_cmd);70047005#if defined(__linux__)7006tlv = ptr;7007#elif defined(__FreeBSD__)7008tlv = (void *)ptr;7009#endif7010tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, arg_len);70117012ptr += TLV_HDR_SIZE;70137014#if defined(__linux__)7015ut_cmd_args = ptr;7016#elif defined(__FreeBSD__)7017ut_cmd_args = (void *)ptr;7018#endif7019for (i = 0; i < le32_to_cpu(ut_cmd.num_args); i++)7020ut_cmd_args[i] = test_args[i];70217022ath12k_dbg(ar->ab, ATH12K_DBG_WMI,7023"WMI unit test : module %d vdev %d n_args %d token %d\n",7024cmd->module_id, cmd->vdev_id, cmd->num_args,7025cmd->diag_token);70267027ret = ath12k_wmi_cmd_send(wmi, skb, WMI_UNIT_TEST_CMDID);70287029if (ret) {7030ath12k_warn(ar->ab, "failed to send WMI_UNIT_TEST CMD :%d\n",7031ret);7032dev_kfree_skb(skb);7033}70347035return ret;7036}70377038int ath12k_wmi_simulate_radar(struct ath12k *ar)7039{7040struct ath12k_vif *arvif;7041u32 dfs_args[DFS_MAX_TEST_ARGS];7042struct wmi_unit_test_cmd wmi_ut;7043bool arvif_found = false;70447045list_for_each_entry(arvif, &ar->arvifs, list) {7046if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) {7047arvif_found = true;7048break;7049}7050}70517052if (!arvif_found)7053return -EINVAL;70547055dfs_args[DFS_TEST_CMDID] = 0;7056dfs_args[DFS_TEST_PDEV_ID] = ar->pdev->pdev_id;7057/* Currently we could pass segment_id(b0 - b1), chirp(b2)7058* freq offset (b3 - b10) to unit test. For simulation7059* purpose this can be set to 0 which is valid.7060*/7061dfs_args[DFS_TEST_RADAR_PARAM] = 0;70627063wmi_ut.vdev_id = cpu_to_le32(arvif->vdev_id);7064wmi_ut.module_id = cpu_to_le32(DFS_UNIT_TEST_MODULE);7065wmi_ut.num_args = cpu_to_le32(DFS_MAX_TEST_ARGS);7066wmi_ut.diag_token = cpu_to_le32(DFS_UNIT_TEST_TOKEN);70677068ath12k_dbg(ar->ab, ATH12K_DBG_REG, "Triggering Radar Simulation\n");70697070return ath12k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args);7071}70727073int ath12k_wmi_connect(struct ath12k_base *ab)7074{7075u32 i;7076u8 wmi_ep_count;70777078wmi_ep_count = ab->htc.wmi_ep_count;7079if (wmi_ep_count > ab->hw_params->max_radios)7080return -1;70817082for (i = 0; i < wmi_ep_count; i++)7083ath12k_connect_pdev_htc_service(ab, i);70847085return 0;7086}70877088static void ath12k_wmi_pdev_detach(struct ath12k_base *ab, u8 pdev_id)7089{7090if (WARN_ON(pdev_id >= MAX_RADIOS))7091return;70927093/* TODO: Deinit any pdev specific wmi resource */7094}70957096int ath12k_wmi_pdev_attach(struct ath12k_base *ab,7097u8 pdev_id)7098{7099struct ath12k_wmi_pdev *wmi_handle;71007101if (pdev_id >= ab->hw_params->max_radios)7102return -EINVAL;71037104wmi_handle = &ab->wmi_ab.wmi[pdev_id];71057106wmi_handle->wmi_ab = &ab->wmi_ab;71077108ab->wmi_ab.ab = ab;7109/* TODO: Init remaining resource specific to pdev */71107111return 0;7112}71137114int ath12k_wmi_attach(struct ath12k_base *ab)7115{7116int ret;71177118ret = ath12k_wmi_pdev_attach(ab, 0);7119if (ret)7120return ret;71217122ab->wmi_ab.ab = ab;7123ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_MAX;71247125/* It's overwritten when service_ext_ready is handled */7126if (ab->hw_params->single_pdev_only)7127ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_SINGLE;71287129/* TODO: Init remaining wmi soc resources required */7130init_completion(&ab->wmi_ab.service_ready);7131init_completion(&ab->wmi_ab.unified_ready);71327133return 0;7134}71357136void ath12k_wmi_detach(struct ath12k_base *ab)7137{7138int i;71397140/* TODO: Deinit wmi resource specific to SOC as required */71417142for (i = 0; i < ab->htc.wmi_ep_count; i++)7143ath12k_wmi_pdev_detach(ab, i);71447145ath12k_wmi_free_dbring_caps(ab);7146}714771487149