aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/ath/ath12k/wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath12k/wmi.c')
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c407
1 files changed, 375 insertions, 32 deletions
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 4928e4e91660..0e5bf5ce8d4c 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -62,9 +62,27 @@ struct ath12k_wmi_svc_rdy_ext_parse {
bool dma_ring_cap_done;
};
+struct ath12k_wmi_svc_rdy_ext2_arg {
+ u32 reg_db_version;
+ u32 hw_min_max_tx_power_2ghz;
+ u32 hw_min_max_tx_power_5ghz;
+ u32 chwidth_num_peer_caps;
+ u32 preamble_puncture_bw;
+ u32 max_user_per_ppdu_ofdma;
+ u32 max_user_per_ppdu_mumimo;
+ u32 target_cap_flags;
+ u32 eht_cap_mac_info[WMI_MAX_EHTCAP_MAC_SIZE];
+ u32 max_num_linkview_peers;
+ u32 max_num_msduq_supported_per_tid;
+ u32 default_num_msduq_supported_per_tid;
+};
+
struct ath12k_wmi_svc_rdy_ext2_parse {
+ struct ath12k_wmi_svc_rdy_ext2_arg arg;
struct ath12k_wmi_dma_ring_caps_parse dma_caps_parse;
bool dma_ring_cap_done;
+ bool spectral_bin_scaling_done;
+ bool mac_phy_caps_ext_done;
};
struct ath12k_wmi_rdy_parse {
@@ -134,6 +152,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
.min_len = sizeof(struct wmi_service_available_event) },
[WMI_TAG_PEER_ASSOC_CONF_EVENT] = {
.min_len = sizeof(struct wmi_peer_assoc_conf_event) },
+ [WMI_TAG_RFKILL_EVENT] = {
+ .min_len = sizeof(struct wmi_rfkill_state_change_event) },
[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = {
.min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
[WMI_TAG_HOST_SWFDA_EVENT] = {
@@ -388,22 +408,22 @@ err_pull:
int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,
u32 cmd_id)
{
- struct ath12k_wmi_base *wmi_sc = wmi->wmi_ab;
+ struct ath12k_wmi_base *wmi_ab = wmi->wmi_ab;
int ret = -EOPNOTSUPP;
might_sleep();
- wait_event_timeout(wmi_sc->tx_credits_wq, ({
+ wait_event_timeout(wmi_ab->tx_credits_wq, ({
ret = ath12k_wmi_cmd_send_nowait(wmi, skb, cmd_id);
- if (ret && test_bit(ATH12K_FLAG_CRASH_FLUSH, &wmi_sc->ab->dev_flags))
+ if (ret && test_bit(ATH12K_FLAG_CRASH_FLUSH, &wmi_ab->ab->dev_flags))
ret = -ESHUTDOWN;
(ret != -EAGAIN);
}), WMI_SEND_TIMEOUT_HZ);
if (ret == -EAGAIN)
- ath12k_warn(wmi_sc->ab, "wmi command %d timeout\n", cmd_id);
+ ath12k_warn(wmi_ab->ab, "wmi command %d timeout\n", cmd_id);
return ret;
}
@@ -445,8 +465,10 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
const struct ath12k_wmi_soc_mac_phy_hw_mode_caps_params *hw_caps = svc->hw_caps;
const struct ath12k_wmi_hw_mode_cap_params *wmi_hw_mode_caps = svc->hw_mode_caps;
const struct ath12k_wmi_mac_phy_caps_params *wmi_mac_phy_caps = svc->mac_phy_caps;
+ struct ath12k_base *ab = wmi_handle->wmi_ab->ab;
struct ath12k_band_cap *cap_band;
struct ath12k_pdev_cap *pdev_cap = &pdev->cap;
+ struct ath12k_fw_pdev *fw_pdev;
u32 phy_map;
u32 hw_idx, phy_idx = 0;
int i;
@@ -475,6 +497,12 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle,
pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands);
pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density);
+ fw_pdev = &ab->fw_pdev[ab->fw_pdev_count];
+ fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands);
+ fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id);
+ fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id);
+ ab->fw_pdev_count++;
+
/* Take non-zero tx/rx chainmask. If tx/rx chainmask differs from
* band to band for a single radio, need to see how this should be
* handled.
@@ -699,10 +727,10 @@ static int ath12k_service_ready_event(struct ath12k_base *ab, struct sk_buff *sk
return 0;
}
-struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len)
+struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len)
{
struct sk_buff *skb;
- struct ath12k_base *ab = wmi_sc->ab;
+ struct ath12k_base *ab = wmi_ab->ab;
u32 round_len = roundup(len, 4);
skb = ath12k_htc_alloc_skb(ab, WMI_SKB_HEADROOM + round_len);
@@ -995,6 +1023,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg,
cmd->cac_duration_ms = cpu_to_le32(arg->cac_duration_ms);
cmd->regdomain = cpu_to_le32(arg->regdomain);
cmd->he_ops = cpu_to_le32(arg->he_ops);
+ cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap);
if (!restart) {
if (arg->ssid) {
@@ -1791,6 +1820,7 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
bool hw_crypto_disabled)
{
cmd->peer_flags = 0;
+ cmd->peer_flags_ext = 0;
if (arg->is_wme_set) {
if (arg->qos_flag)
@@ -1805,6 +1835,8 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
cmd->peer_flags |= cpu_to_le32(WMI_PEER_80MHZ);
if (arg->bw_160)
cmd->peer_flags |= cpu_to_le32(WMI_PEER_160MHZ);
+ if (arg->bw_320)
+ cmd->peer_flags |= cpu_to_le32(WMI_PEER_EXT_320MHZ);
/* Typically if STBC is enabled for VHT it should be enabled
* for HT as well
@@ -1832,6 +1864,8 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_REQ);
if (arg->twt_responder)
cmd->peer_flags |= cpu_to_le32(WMI_PEER_TWT_RESP);
+ if (arg->eht_flag)
+ cmd->peer_flags_ext |= cpu_to_le32(WMI_PEER_EXT_EHT);
}
/* Suppress authorization for all AUTH modes that need 4-way handshake
@@ -1876,6 +1910,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
struct wmi_peer_assoc_complete_cmd *cmd;
struct ath12k_wmi_vht_rate_set_params *mcs;
struct ath12k_wmi_he_rate_set_params *he_mcs;
+ struct ath12k_wmi_eht_rate_set_params *eht_mcs;
struct sk_buff *skb;
struct wmi_tlv *tlv;
void *ptr;
@@ -1892,7 +1927,9 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
TLV_HDR_SIZE + (peer_legacy_rates_align * sizeof(u8)) +
TLV_HDR_SIZE + (peer_ht_rates_align * sizeof(u8)) +
sizeof(*mcs) + TLV_HDR_SIZE +
- (sizeof(*he_mcs) * arg->peer_he_mcs_count);
+ (sizeof(*he_mcs) * arg->peer_he_mcs_count) +
+ TLV_HDR_SIZE + (sizeof(*eht_mcs) * arg->peer_eht_mcs_count) +
+ TLV_HDR_SIZE + TLV_HDR_SIZE;
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb)
@@ -1908,6 +1945,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
cmd->peer_new_assoc = cpu_to_le32(arg->peer_new_assoc);
cmd->peer_associd = cpu_to_le32(arg->peer_associd);
+ cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap);
ath12k_wmi_copy_peer_flags(cmd, arg,
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED,
@@ -1939,6 +1977,16 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
cmd->peer_ppet.ppet16_ppet8_ru3_ru0[i] =
cpu_to_le32(arg->peer_ppet.ppet16_ppet8_ru3_ru0[i]);
+ /* Update 11be capabilities */
+ memcpy_and_pad(cmd->peer_eht_cap_mac, sizeof(cmd->peer_eht_cap_mac),
+ arg->peer_eht_cap_mac, sizeof(arg->peer_eht_cap_mac),
+ 0);
+ memcpy_and_pad(cmd->peer_eht_cap_phy, sizeof(cmd->peer_eht_cap_phy),
+ arg->peer_eht_cap_phy, sizeof(arg->peer_eht_cap_phy),
+ 0);
+ memcpy_and_pad(&cmd->peer_eht_ppet, sizeof(cmd->peer_eht_ppet),
+ &arg->peer_eht_ppet, sizeof(arg->peer_eht_ppet), 0);
+
/* Update peer legacy rate information */
ptr += sizeof(*cmd);
@@ -2005,8 +2053,36 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
ptr += sizeof(*he_mcs);
}
+ /* MLO header tag with 0 length */
+ len = 0;
+ tlv = ptr;
+ tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);
+ ptr += TLV_HDR_SIZE;
+
+ /* Loop through the EHT rate set */
+ len = arg->peer_eht_mcs_count * sizeof(*eht_mcs);
+ tlv = ptr;
+ tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);
+ ptr += TLV_HDR_SIZE;
+
+ for (i = 0; i < arg->peer_eht_mcs_count; i++) {
+ eht_mcs = ptr;
+ eht_mcs->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_HE_RATE_SET,
+ sizeof(*eht_mcs));
+
+ eht_mcs->rx_mcs_set = cpu_to_le32(arg->peer_eht_rx_mcs_set[i]);
+ eht_mcs->tx_mcs_set = cpu_to_le32(arg->peer_eht_tx_mcs_set[i]);
+ ptr += sizeof(*eht_mcs);
+ }
+
+ /* ML partner links tag with 0 length */
+ len = 0;
+ tlv = ptr;
+ tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, len);
+ ptr += TLV_HDR_SIZE;
+
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
- "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\n",
+ "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",
cmd->vdev_id, cmd->peer_associd, arg->peer_mac,
cmd->peer_flags, cmd->peer_rate_caps, cmd->peer_caps,
cmd->peer_listen_intval, cmd->peer_ht_caps,
@@ -2016,7 +2092,10 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar,
cmd->peer_he_ops, cmd->peer_he_cap_info_ext,
cmd->peer_he_cap_phy[0], cmd->peer_he_cap_phy[1],
cmd->peer_he_cap_phy[2],
- cmd->peer_bw_rxnss_override);
+ cmd->peer_bw_rxnss_override, cmd->peer_flags_ext,
+ cmd->peer_eht_cap_mac[0], cmd->peer_eht_cap_mac[1],
+ cmd->peer_eht_cap_phy[0], cmd->peer_eht_cap_phy[1],
+ cmd->peer_eht_cap_phy[2]);
ret = ath12k_wmi_cmd_send(wmi, skb, WMI_PEER_ASSOC_CMDID);
if (ret) {
@@ -2162,12 +2241,6 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
if (arg->num_bssid)
len += sizeof(*bssid) * arg->num_bssid;
- len += TLV_HDR_SIZE;
- if (arg->extraie.len)
- extraie_len_with_pad =
- roundup(arg->extraie.len, sizeof(u32));
- len += extraie_len_with_pad;
-
if (arg->num_hint_bssid)
len += TLV_HDR_SIZE +
arg->num_hint_bssid * sizeof(*hint_bssid);
@@ -2176,6 +2249,18 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
len += TLV_HDR_SIZE +
arg->num_hint_s_ssid * sizeof(*s_ssid);
+ len += TLV_HDR_SIZE;
+ if (arg->extraie.len)
+ extraie_len_with_pad =
+ roundup(arg->extraie.len, sizeof(u32));
+ if (extraie_len_with_pad <= (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len)) {
+ len += extraie_len_with_pad;
+ } else {
+ ath12k_warn(ar->ab, "discard large size %d bytes extraie for scan start\n",
+ arg->extraie.len);
+ extraie_len_with_pad = 0;
+ }
+
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb)
return -ENOMEM;
@@ -2265,7 +2350,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len);
ptr += TLV_HDR_SIZE;
- if (arg->extraie.len)
+ if (extraie_len_with_pad)
memcpy(ptr, arg->extraie.ptr,
arg->extraie.len);
@@ -3386,7 +3471,7 @@ int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
int ath12k_wmi_cmd_init(struct ath12k_base *ab)
{
- struct ath12k_wmi_base *wmi_sc = &ab->wmi_ab;
+ struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
struct ath12k_wmi_init_cmd_arg arg = {};
if (test_bit(WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT,
@@ -3395,9 +3480,9 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab)
ab->hw_params->wmi_init(ab, &arg.res_cfg);
- arg.num_mem_chunks = wmi_sc->num_mem_chunks;
- arg.hw_mode_id = wmi_sc->preferred_hw_mode;
- arg.mem_chunks = wmi_sc->mem_chunks;
+ arg.num_mem_chunks = wmi_ab->num_mem_chunks;
+ arg.hw_mode_id = wmi_ab->preferred_hw_mode;
+ arg.mem_chunks = wmi_ab->mem_chunks;
if (ab->hw_params->single_pdev_only)
arg.hw_mode_id = WMI_HOST_HW_MODE_MAX;
@@ -3405,7 +3490,7 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab)
arg.num_band_to_mac = ab->num_radios;
ath12k_fill_band_to_mac_param(ab, arg.band_to_mac);
- return ath12k_init_cmd_send(&wmi_sc->wmi[0], &arg);
+ return ath12k_init_cmd_send(&wmi_ab->wmi[0], &arg);
}
int ath12k_wmi_vdev_spectral_conf(struct ath12k *ar,
@@ -3704,6 +3789,10 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
for (i = 0 ; i < svc_rdy_ext->n_hw_mode_caps; i++) {
hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i];
mode = le32_to_cpu(hw_mode_caps->hw_mode_id);
+
+ if (mode >= WMI_HOST_HW_MODE_MAX)
+ continue;
+
pref = soc->wmi_ab.preferred_hw_mode;
if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) {
@@ -3789,6 +3878,12 @@ static int ath12k_wmi_ext_hal_reg_caps(struct ath12k_base *soc,
ath12k_warn(soc, "failed to extract reg cap %d\n", i);
return ret;
}
+
+ if (reg_cap.phy_id >= MAX_RADIOS) {
+ ath12k_warn(soc, "unexpected phy id %u\n", reg_cap.phy_id);
+ return -EINVAL;
+ }
+
soc->hal_reg_cap[reg_cap.phy_id] = reg_cap;
}
return 0;
@@ -3810,6 +3905,7 @@ static int ath12k_wmi_ext_soc_hal_reg_caps_parse(struct ath12k_base *soc,
soc->num_radios = 0;
phy_id_map = le32_to_cpu(svc_rdy_ext->pref_hw_mode_caps.phy_id_map);
+ soc->fw_pdev_count = 0;
while (phy_id_map && soc->num_radios < MAX_RADIOS) {
ret = ath12k_pull_mac_phy_cap_svc_ready_ext(wmi_handle,
@@ -4037,14 +4133,183 @@ err:
return ret;
}
+static int ath12k_pull_svc_ready_ext2(struct ath12k_wmi_pdev *wmi_handle,
+ const void *ptr,
+ struct ath12k_wmi_svc_rdy_ext2_arg *arg)
+{
+ const struct wmi_service_ready_ext2_event *ev = ptr;
+
+ if (!ev)
+ return -EINVAL;
+
+ arg->reg_db_version = le32_to_cpu(ev->reg_db_version);
+ arg->hw_min_max_tx_power_2ghz = le32_to_cpu(ev->hw_min_max_tx_power_2ghz);
+ arg->hw_min_max_tx_power_5ghz = le32_to_cpu(ev->hw_min_max_tx_power_5ghz);
+ arg->chwidth_num_peer_caps = le32_to_cpu(ev->chwidth_num_peer_caps);
+ arg->preamble_puncture_bw = le32_to_cpu(ev->preamble_puncture_bw);
+ arg->max_user_per_ppdu_ofdma = le32_to_cpu(ev->max_user_per_ppdu_ofdma);
+ arg->max_user_per_ppdu_mumimo = le32_to_cpu(ev->max_user_per_ppdu_mumimo);
+ arg->target_cap_flags = le32_to_cpu(ev->target_cap_flags);
+ return 0;
+}
+
+static void ath12k_wmi_eht_caps_parse(struct ath12k_pdev *pdev, u32 band,
+ const __le32 cap_mac_info[],
+ const __le32 cap_phy_info[],
+ const __le32 supp_mcs[],
+ const struct ath12k_wmi_ppe_threshold_params *ppet,
+ __le32 cap_info_internal)
+{
+ struct ath12k_band_cap *cap_band = &pdev->cap.band[band];
+ u32 support_320mhz;
+ u8 i;
+
+ if (band == NL80211_BAND_6GHZ)
+ support_320mhz = cap_band->eht_cap_phy_info[0] &
+ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
+
+ for (i = 0; i < WMI_MAX_EHTCAP_MAC_SIZE; i++)
+ cap_band->eht_cap_mac_info[i] = le32_to_cpu(cap_mac_info[i]);
+
+ for (i = 0; i < WMI_MAX_EHTCAP_PHY_SIZE; i++)
+ cap_band->eht_cap_phy_info[i] = le32_to_cpu(cap_phy_info[i]);
+
+ if (band == NL80211_BAND_6GHZ)
+ cap_band->eht_cap_phy_info[0] |= support_320mhz;
+
+ cap_band->eht_mcs_20_only = le32_to_cpu(supp_mcs[0]);
+ cap_band->eht_mcs_80 = le32_to_cpu(supp_mcs[1]);
+ if (band != NL80211_BAND_2GHZ) {
+ cap_band->eht_mcs_160 = le32_to_cpu(supp_mcs[2]);
+ cap_band->eht_mcs_320 = le32_to_cpu(supp_mcs[3]);
+ }
+
+ cap_band->eht_ppet.numss_m1 = le32_to_cpu(ppet->numss_m1);
+ cap_band->eht_ppet.ru_bit_mask = le32_to_cpu(ppet->ru_info);
+ for (i = 0; i < WMI_MAX_NUM_SS; i++)
+ cap_band->eht_ppet.ppet16_ppet8_ru3_ru0[i] =
+ le32_to_cpu(ppet->ppet16_ppet8_ru3_ru0[i]);
+
+ cap_band->eht_cap_info_internal = le32_to_cpu(cap_info_internal);
+}
+
+static int
+ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab,
+ const struct ath12k_wmi_caps_ext_params *caps,
+ struct ath12k_pdev *pdev)
+{
+ struct ath12k_band_cap *cap_band;
+ u32 bands, support_320mhz;
+ int i;
+
+ if (ab->hw_params->single_pdev_only) {
+ if (caps->hw_mode_id == WMI_HOST_HW_MODE_SINGLE) {
+ support_320mhz = le32_to_cpu(caps->eht_cap_phy_info_5ghz[0]) &
+ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
+ cap_band = &pdev->cap.band[NL80211_BAND_6GHZ];
+ cap_band->eht_cap_phy_info[0] |= support_320mhz;
+ return 0;
+ }
+
+ for (i = 0; i < ab->fw_pdev_count; i++) {
+ struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i];
+
+ if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) &&
+ fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) {
+ bands = fw_pdev->supported_bands;
+ break;
+ }
+ }
+
+ if (i == ab->fw_pdev_count)
+ return -EINVAL;
+ } else {
+ bands = pdev->cap.supported_bands;
+ }
+
+ if (bands & WMI_HOST_WLAN_2G_CAP) {
+ ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_2GHZ,
+ caps->eht_cap_mac_info_2ghz,
+ caps->eht_cap_phy_info_2ghz,
+ caps->eht_supp_mcs_ext_2ghz,
+ &caps->eht_ppet_2ghz,
+ caps->eht_cap_info_internal);
+ }
+
+ if (bands & WMI_HOST_WLAN_5G_CAP) {
+ ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_5GHZ,
+ caps->eht_cap_mac_info_5ghz,
+ caps->eht_cap_phy_info_5ghz,
+ caps->eht_supp_mcs_ext_5ghz,
+ &caps->eht_ppet_5ghz,
+ caps->eht_cap_info_internal);
+
+ ath12k_wmi_eht_caps_parse(pdev, NL80211_BAND_6GHZ,
+ caps->eht_cap_mac_info_5ghz,
+ caps->eht_cap_phy_info_5ghz,
+ caps->eht_supp_mcs_ext_5ghz,
+ &caps->eht_ppet_5ghz,
+ caps->eht_cap_info_internal);
+ }
+
+ return 0;
+}
+
+static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag,
+ u16 len, const void *ptr,
+ void *data)
+{
+ const struct ath12k_wmi_caps_ext_params *caps = ptr;
+ int i = 0, ret;
+
+ if (tag != WMI_TAG_MAC_PHY_CAPABILITIES_EXT)
+ return -EPROTO;
+
+ if (ab->hw_params->single_pdev_only) {
+ if (ab->wmi_ab.preferred_hw_mode != le32_to_cpu(caps->hw_mode_id) &&
+ caps->hw_mode_id != WMI_HOST_HW_MODE_SINGLE)
+ return 0;
+ } else {
+ for (i = 0; i < ab->num_radios; i++) {
+ if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id))
+ break;
+ }
+
+ if (i == ab->num_radios)
+ return -EINVAL;
+ }
+
+ ret = ath12k_wmi_tlv_mac_phy_caps_ext_parse(ab, caps, &ab->pdevs[i]);
+ if (ret) {
+ ath12k_warn(ab,
+ "failed to parse extended MAC PHY capabilities for pdev %d: %d\n",
+ ret, ab->pdevs[i].pdev_id);
+ return ret;
+ }
+
+ return 0;
+}
+
static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
u16 tag, u16 len,
const void *ptr, void *data)
{
+ struct ath12k_wmi_pdev *wmi_handle = &ab->wmi_ab.wmi[0];
struct ath12k_wmi_svc_rdy_ext2_parse *parse = data;
int ret;
switch (tag) {
+ case WMI_TAG_SERVICE_READY_EXT2_EVENT:
+ ret = ath12k_pull_svc_ready_ext2(wmi_handle, ptr,
+ &parse->arg);
+ if (ret) {
+ ath12k_warn(ab,
+ "failed to extract wmi service ready ext2 parameters: %d\n",
+ ret);
+ return ret;
+ }
+ break;
+
case WMI_TAG_ARRAY_STRUCT:
if (!parse->dma_ring_cap_done) {
ret = ath12k_wmi_dma_ring_caps(ab, len, ptr,
@@ -4053,6 +4318,23 @@ static int ath12k_wmi_svc_rdy_ext2_parse(struct ath12k_base *ab,
return ret;
parse->dma_ring_cap_done = true;
+ } else if (!parse->spectral_bin_scaling_done) {
+ /* TODO: This is a place-holder as WMI tag for
+ * spectral scaling is before
+ * WMI_TAG_MAC_PHY_CAPABILITIES_EXT
+ */
+ parse->spectral_bin_scaling_done = true;
+ } else if (!parse->mac_phy_caps_ext_done) {
+ ret = ath12k_wmi_tlv_iter(ab, ptr, len,
+ ath12k_wmi_tlv_mac_phy_caps_ext,
+ parse);
+ if (ret) {
+ ath12k_warn(ab, "failed to parse extended MAC PHY capabilities WMI TLV: %d\n",
+ ret);
+ return ret;
+ }
+
+ parse->mac_phy_caps_ext_done = true;
}
break;
default:
@@ -4329,10 +4611,11 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
}
ath12k_dbg(ab, ATH12K_DBG_WMI,
- "%s:cc_ext %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
+ "%s:cc_ext %s dfs %d BW: min_2g %d max_2g %d min_5g %d max_5g %d phy_bitmap 0x%x",
__func__, reg_info->alpha2, reg_info->dfs_region,
reg_info->min_bw_2g, reg_info->max_bw_2g,
- reg_info->min_bw_5g, reg_info->max_bw_5g);
+ reg_info->min_bw_5g, reg_info->max_bw_5g,
+ reg_info->phybitmap);
ath12k_dbg(ab, ATH12K_DBG_WMI,
"num_2g_reg_rules %d num_5g_reg_rules %d",
@@ -5139,7 +5422,13 @@ static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
static bool ath12k_reg_is_world_alpha(char *alpha)
{
- return alpha[0] == '0' && alpha[1] == '0';
+ if (alpha[0] == '0' && alpha[1] == '0')
+ return true;
+
+ if (alpha[0] == 'n' && alpha[1] == 'a')
+ return true;
+
+ return false;
}
static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
@@ -5222,7 +5511,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
ar = ab->pdevs[pdev_idx].ar;
kfree(ab->new_regd[pdev_idx]);
ab->new_regd[pdev_idx] = regd;
- ieee80211_queue_work(ar->hw, &ar->regd_update_work);
+ queue_work(ab->workqueue, &ar->regd_update_work);
} else {
/* Multiple events for the same *ar is not expected. But we
* can still clear any previously stored default_regd if we
@@ -5611,8 +5900,9 @@ exit:
rcu_read_unlock();
}
-static struct ath12k *ath12k_get_ar_on_scan_abort(struct ath12k_base *ab,
- u32 vdev_id)
+static struct ath12k *ath12k_get_ar_on_scan_state(struct ath12k_base *ab,
+ u32 vdev_id,
+ enum ath12k_scan_state state)
{
int i;
struct ath12k_pdev *pdev;
@@ -5624,7 +5914,7 @@ static struct ath12k *ath12k_get_ar_on_scan_abort(struct ath12k_base *ab,
ar = pdev->ar;
spin_lock_bh(&ar->data_lock);
- if (ar->scan.state == ATH12K_SCAN_ABORTING &&
+ if (ar->scan.state == state &&
ar->scan.vdev_id == vdev_id) {
spin_unlock_bh(&ar->data_lock);
return ar;
@@ -5654,10 +5944,15 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb)
* aborting scan's vdev id matches this event info.
*/
if (le32_to_cpu(scan_ev.event_type) == WMI_SCAN_EVENT_COMPLETED &&
- le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED)
- ar = ath12k_get_ar_on_scan_abort(ab, le32_to_cpu(scan_ev.vdev_id));
- else
+ le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED) {
+ ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id),
+ ATH12K_SCAN_ABORTING);
+ if (!ar)
+ ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id),
+ ATH12K_SCAN_RUNNING);
+ } else {
ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(scan_ev.vdev_id));
+ }
if (!ar) {
ath12k_warn(ab, "Received scan event for unknown vdev");
@@ -5697,6 +5992,8 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb)
ath12k_wmi_event_scan_start_failed(ar);
break;
case WMI_SCAN_EVENT_DEQUEUED:
+ __ath12k_mac_scan_finish(ar);
+ break;
case WMI_SCAN_EVENT_PREEMPTED:
case WMI_SCAN_EVENT_RESTARTED:
case WMI_SCAN_EVENT_FOREIGN_CHAN_EXIT:
@@ -6218,6 +6515,8 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
ev->detector_id, ev->segment_id, ev->timestamp, ev->is_chirp,
ev->freq_offset, ev->sidx);
+ rcu_read_lock();
+
ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev->pdev_id));
if (!ar) {
@@ -6235,6 +6534,8 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
ieee80211_radar_detected(ar->hw);
exit:
+ rcu_read_unlock();
+
kfree(tb);
}
@@ -6253,11 +6554,16 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,
ath12k_dbg(ab, ATH12K_DBG_WMI,
"pdev temperature ev temp %d pdev_id %d\n", ev.temp, ev.pdev_id);
+ rcu_read_lock();
+
ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev.pdev_id));
if (!ar) {
ath12k_warn(ab, "invalid pdev id in pdev temperature ev %d", ev.pdev_id);
- return;
+ goto exit;
}
+
+exit:
+ rcu_read_unlock();
}
static void ath12k_fils_discovery_event(struct ath12k_base *ab,
@@ -6322,6 +6628,40 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
kfree(tb);
}
+static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
+ struct sk_buff *skb)
+{
+ const struct wmi_rfkill_state_change_event *ev;
+ const void **tb;
+ int ret;
+
+ tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
+ return;
+ }
+
+ ev = tb[WMI_TAG_RFKILL_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return;
+ }
+
+ ath12k_dbg(ab, ATH12K_DBG_MAC,
+ "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
+ le32_to_cpu(ev->gpio_pin_num),
+ le32_to_cpu(ev->int_type),
+ le32_to_cpu(ev->radio_state));
+
+ spin_lock_bh(&ab->base_lock);
+ ab->rfkill_radio_on = (ev->radio_state == cpu_to_le32(WMI_RFKILL_RADIO_STATE_ON));
+ spin_unlock_bh(&ab->base_lock);
+
+ queue_work(ab->workqueue, &ab->rfkill_work);
+ kfree(tb);
+}
+
static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
@@ -6414,6 +6754,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID:
ath12k_probe_resp_tx_status_event(ab, skb);
break;
+ case WMI_RFKILL_STATE_CHANGE_EVENTID:
+ ath12k_rfkill_state_change_event(ab, skb);
+ break;
/* add Unsupported events here */
case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
case WMI_PEER_OPER_MODE_CHANGE_EVENTID: