diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath11k')
| -rw-r--r-- | drivers/net/wireless/ath/ath11k/hal.h | 38 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath11k/mac.c | 455 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath11k/pci.c | 20 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath11k/pci.h | 18 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath11k/qmi.c | 2 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath11k/wmi.c | 20 | ||||
| -rw-r--r-- | drivers/net/wireless/ath/ath11k/wmi.h | 18 |
7 files changed, 380 insertions, 191 deletions
diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 839095af9267..82603a389bb9 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_HAL_H @@ -43,14 +43,14 @@ struct ath11k_base; #define HAL_SEQ_WCSS_UMAC_OFFSET 0x00a00000 #define HAL_SEQ_WCSS_UMAC_REO_REG 0x00a38000 #define HAL_SEQ_WCSS_UMAC_TCL_REG 0x00a44000 -#define HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(x) \ - (ab->hw_params.regs->hal_seq_wcss_umac_ce0_src_reg) -#define HAL_SEQ_WCSS_UMAC_CE0_DST_REG(x) \ - (ab->hw_params.regs->hal_seq_wcss_umac_ce0_dst_reg) -#define HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(x) \ - (ab->hw_params.regs->hal_seq_wcss_umac_ce1_src_reg) -#define HAL_SEQ_WCSS_UMAC_CE1_DST_REG(x) \ - (ab->hw_params.regs->hal_seq_wcss_umac_ce1_dst_reg) +#define HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab) \ + ((ab)->hw_params.regs->hal_seq_wcss_umac_ce0_src_reg) +#define HAL_SEQ_WCSS_UMAC_CE0_DST_REG(ab) \ + ((ab)->hw_params.regs->hal_seq_wcss_umac_ce0_dst_reg) +#define HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(ab) \ + ((ab)->hw_params.regs->hal_seq_wcss_umac_ce1_src_reg) +#define HAL_SEQ_WCSS_UMAC_CE1_DST_REG(ab) \ + ((ab)->hw_params.regs->hal_seq_wcss_umac_ce1_dst_reg) #define HAL_SEQ_WCSS_UMAC_WBM_REG 0x00a34000 #define HAL_CE_WFSS_CE_REG_BASE 0x01b80000 @@ -209,10 +209,10 @@ struct ath11k_base; #define HAL_REO_STATUS_HP(ab) ab->hw_params.regs->hal_reo_status_hp /* WBM Idle R0 address */ -#define HAL_WBM_IDLE_LINK_RING_BASE_LSB(x) \ - (ab->hw_params.regs->hal_wbm_idle_link_ring_base_lsb) -#define HAL_WBM_IDLE_LINK_RING_MISC_ADDR(x) \ - (ab->hw_params.regs->hal_wbm_idle_link_ring_misc) +#define HAL_WBM_IDLE_LINK_RING_BASE_LSB(ab) \ + ((ab)->hw_params.regs->hal_wbm_idle_link_ring_base_lsb) +#define HAL_WBM_IDLE_LINK_RING_MISC_ADDR(ab) \ + ((ab)->hw_params.regs->hal_wbm_idle_link_ring_misc) #define HAL_WBM_R0_IDLE_LIST_CONTROL_ADDR 0x00000048 #define HAL_WBM_R0_IDLE_LIST_SIZE_ADDR 0x0000004c #define HAL_WBM_SCATTERED_RING_BASE_LSB 0x00000058 @@ -227,17 +227,17 @@ struct ath11k_base; #define HAL_WBM_IDLE_LINK_RING_HP 0x000030b0 /* SW2WBM R0 release address */ -#define HAL_WBM_RELEASE_RING_BASE_LSB(x) \ - (ab->hw_params.regs->hal_wbm_release_ring_base_lsb) +#define HAL_WBM_RELEASE_RING_BASE_LSB(ab) \ + ((ab)->hw_params.regs->hal_wbm_release_ring_base_lsb) /* SW2WBM R2 release address */ #define HAL_WBM_RELEASE_RING_HP 0x00003018 /* WBM2SW R0 release address */ -#define HAL_WBM0_RELEASE_RING_BASE_LSB(x) \ - (ab->hw_params.regs->hal_wbm0_release_ring_base_lsb) -#define HAL_WBM1_RELEASE_RING_BASE_LSB(x) \ - (ab->hw_params.regs->hal_wbm1_release_ring_base_lsb) +#define HAL_WBM0_RELEASE_RING_BASE_LSB(ab) \ + ((ab)->hw_params.regs->hal_wbm0_release_ring_base_lsb) +#define HAL_WBM1_RELEASE_RING_BASE_LSB(ab) \ + ((ab)->hw_params.regs->hal_wbm1_release_ring_base_lsb) /* WBM2SW R2 release address */ #define HAL_WBM0_RELEASE_RING_HP 0x000030c0 diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 0e41b5a91d66..3276fe443502 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -2235,9 +2235,9 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar, arg->peer_nss = min(sta->deflink.rx_nss, max_nss); arg->rx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.rx_highest); arg->rx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map); + arg->rx_mcs_set = ath11k_peer_assoc_h_vht_limit(arg->rx_mcs_set, vht_mcs_mask); arg->tx_max_rate = __le16_to_cpu(vht_cap->vht_mcs.tx_highest); - arg->tx_mcs_set = ath11k_peer_assoc_h_vht_limit( - __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask); + arg->tx_mcs_set = __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map); /* In IPQ8074 platform, VHT mcs rate 10 and 11 is enabled by default. * VHT mcs rate 10 and 11 is not supported in 11ac standard. @@ -2522,10 +2522,10 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, he_tx_mcs = v; } v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); + v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); - v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; arg->peer_he_mcs_count++; @@ -2535,10 +2535,10 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar, default: v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); + v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); - v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; arg->peer_he_mcs_count++; @@ -4028,6 +4028,150 @@ static int ath11k_start_scan(struct ath11k *ar, return 0; } +static void ath11k_mac_fw_stats_reset(struct ath11k *ar) +{ + spin_lock_bh(&ar->data_lock); + ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs); + ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs); + ar->fw_stats.num_vdev_recvd = 0; + ar->fw_stats.num_bcn_recvd = 0; + spin_unlock_bh(&ar->data_lock); +} + +int ath11k_mac_fw_stats_request(struct ath11k *ar, + struct stats_request_params *req_param) +{ + struct ath11k_base *ab = ar->ab; + unsigned long time_left; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + ath11k_mac_fw_stats_reset(ar); + + reinit_completion(&ar->fw_stats_complete); + reinit_completion(&ar->fw_stats_done); + + ret = ath11k_wmi_send_stats_request_cmd(ar, req_param); + + if (ret) { + ath11k_warn(ab, "could not request fw stats (%d)\n", + ret); + return ret; + } + + time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ); + if (!time_left) + return -ETIMEDOUT; + + /* FW stats can get split when exceeding the stats data buffer limit. + * In that case, since there is no end marking for the back-to-back + * received 'update stats' event, we keep a 3 seconds timeout in case, + * fw_stats_done is not marked yet + */ + time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ); + if (!time_left) + return -ETIMEDOUT; + + return 0; +} + +static int ath11k_mac_get_fw_stats(struct ath11k *ar, u32 pdev_id, + u32 vdev_id, u32 stats_id) +{ + struct ath11k_base *ab = ar->ab; + struct stats_request_params req_param; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + if (ar->state != ATH11K_STATE_ON) + return -ENETDOWN; + + req_param.pdev_id = pdev_id; + req_param.vdev_id = vdev_id; + req_param.stats_id = stats_id; + + ret = ath11k_mac_fw_stats_request(ar, &req_param); + if (ret) + ath11k_warn(ab, "failed to request fw stats: %d\n", ret); + + ath11k_dbg(ab, ATH11K_DBG_WMI, + "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n", + pdev_id, vdev_id, stats_id); + + return ret; +} + +static int ath11k_mac_handle_get_txpower(struct ath11k *ar, + struct ieee80211_vif *vif, + int *dbm) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_fw_stats_pdev *pdev; + int ret; + + /* Final Tx power is minimum of Target Power, CTL power, Regulatory + * Power, PSD EIRP Power. We just know the Regulatory power from the + * regulatory rules obtained. FW knows all these power and sets the min + * of these. Hence, we request the FW pdev stats in which FW reports + * the minimum of all vdev's channel Tx power. + */ + lockdep_assert_held(&ar->conf_mutex); + + /* Firmware doesn't provide Tx power during CAC hence no need to fetch + * the stats. + */ + if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) + return -EAGAIN; + + ret = ath11k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0, + WMI_REQUEST_PDEV_STAT); + if (ret) { + ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret); + goto err_fallback; + } + + spin_lock_bh(&ar->data_lock); + pdev = list_first_entry_or_null(&ar->fw_stats.pdevs, + struct ath11k_fw_stats_pdev, list); + if (!pdev) { + spin_unlock_bh(&ar->data_lock); + goto err_fallback; + } + + /* tx power is set as 2 units per dBm in FW. */ + *dbm = pdev->chan_tx_power / 2; + + spin_unlock_bh(&ar->data_lock); + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "txpower from firmware %d, reported %d dBm\n", + pdev->chan_tx_power, *dbm); + return 0; + +err_fallback: + /* We didn't get txpower from FW. Hence, relying on vif->bss_conf.txpower */ + *dbm = vif->bss_conf.txpower; + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "txpower from firmware NaN, reported %d dBm\n", + *dbm); + return 0; +} + +static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id, + int *dbm) +{ + struct ath11k *ar = hw->priv; + int ret; + + mutex_lock(&ar->conf_mutex); + ret = ath11k_mac_handle_get_txpower(ar, vif, dbm); + mutex_unlock(&ar->conf_mutex); + + return ret; +} + static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) @@ -6107,6 +6251,159 @@ static void ath11k_mgmt_over_wmi_tx_purge(struct ath11k *ar) ath11k_mgmt_over_wmi_tx_drop(ar, skb); } +static int ath11k_mac_mgmt_action_frame_fill_elem_data(struct ath11k_vif *arvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u8 category, *buf, iv_len, action_code, dialog_token; + int cur_tx_power, max_tx_power; + struct ath11k *ar = arvif->ar; + struct cfg80211_chan_def def; + struct ath11k_skb_cb *skb_cb; + struct ieee80211_mgmt *mgmt; + unsigned int remaining_len; + bool has_protected; + + lockdep_assert_held(&ar->conf_mutex); + + /* make sure category field is present */ + if (skb->len < IEEE80211_MIN_ACTION_SIZE) + return -EINVAL; + + remaining_len = skb->len - IEEE80211_MIN_ACTION_SIZE; + has_protected = ieee80211_has_protected(hdr->frame_control); + + /* In case of SW crypto and hdr protected (PMF), packet will already be encrypted, + * we can't put in data in this case + */ + if (test_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && + has_protected) + return 0; + + mgmt = (struct ieee80211_mgmt *)hdr; + buf = (u8 *)&mgmt->u.action; + + /* FCTL_PROTECTED frame might have extra space added for HDR_LEN. Offset that + * many bytes if it is there + */ + if (has_protected) { + skb_cb = ATH11K_SKB_CB(skb); + + switch (skb_cb->cipher) { + /* Cipher suite having flag %IEEE80211_KEY_FLAG_GENERATE_IV_MGMT set in + * key needs to be processed. See ath11k_install_key() + */ + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + iv_len = IEEE80211_CCMP_HDR_LEN; + break; + case WLAN_CIPHER_SUITE_TKIP: + iv_len = 0; + break; + default: + return -EINVAL; + } + + if (remaining_len < iv_len) + return -EINVAL; + + buf += iv_len; + remaining_len -= iv_len; + } + + category = *buf++; + /* category code is already taken care in %IEEE80211_MIN_ACTION_SIZE hence + * no need to adjust remaining_len + */ + + switch (category) { + case WLAN_CATEGORY_RADIO_MEASUREMENT: + /* need action code and dialog token */ + if (remaining_len < 2) + return -EINVAL; + + /* Packet Format: + * Action Code | Dialog Token | Variable Len (based on Action Code) + */ + action_code = *buf++; + dialog_token = *buf++; + remaining_len -= 2; + + if (ath11k_mac_vif_chan(arvif->vif, &def)) + return -ENOENT; + + cur_tx_power = arvif->vif->bss_conf.txpower; + max_tx_power = min(def.chan->max_reg_power, (int)ar->max_tx_power / 2); + ath11k_mac_handle_get_txpower(ar, arvif->vif, &cur_tx_power); + + switch (action_code) { + case WLAN_RM_ACTION_LINK_MEASUREMENT_REQUEST: + /* need variable fields to be present in len */ + if (remaining_len < 2) + return -EINVAL; + + /* Variable length format as defined in IEEE 802.11-2024, + * Figure 9-1187-Link Measurement Request frame Action field + * format. + * Transmit Power | Max Tx Power + * We fill both of these. + */ + *buf++ = cur_tx_power; + *buf = max_tx_power; + + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "RRM: Link Measurement Req dialog_token %u cur_tx_power %d max_tx_power %d\n", + dialog_token, cur_tx_power, max_tx_power); + break; + case WLAN_RM_ACTION_LINK_MEASUREMENT_REPORT: + /* need variable fields to be present in len */ + if (remaining_len < 3) + return -EINVAL; + + /* Variable length format as defined in IEEE 802.11-2024, + * Figure 9-1188-Link Measurement Report frame Action field format + * TPC Report | Variable Fields + * + * TPC Report Format: + * Element ID | Len | Tx Power | Link Margin + * + * We fill Tx power in the TPC Report (2nd index) + */ + buf[2] = cur_tx_power; + + /* TODO: At present, Link margin data is not present so can't + * really fill it now. Once it is available, it can be added + * here + */ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "RRM: Link Measurement Report dialog_token %u cur_tx_power %d\n", + dialog_token, cur_tx_power); + break; + default: + return -EINVAL; + } + break; + default: + /* nothing to fill */ + return 0; + } + + return 0; +} + +static int ath11k_mac_mgmt_frame_fill_elem_data(struct ath11k_vif *arvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_is_action(hdr->frame_control)) + return 0; + + return ath11k_mac_mgmt_action_frame_fill_elem_data(arvif, skb); +} + static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) { struct ath11k *ar = container_of(work, struct ath11k, wmi_mgmt_tx_work); @@ -6126,6 +6423,19 @@ static void ath11k_mgmt_over_wmi_tx_work(struct work_struct *work) arvif = ath11k_vif_to_arvif(skb_cb->vif); mutex_lock(&ar->conf_mutex); if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { + /* Fill in the data which is required to be filled by the driver + * For example: Max Tx power in Link Measurement Request/Report + */ + ret = ath11k_mac_mgmt_frame_fill_elem_data(arvif, skb); + if (ret) { + /* If we couldn't fill the data due to any reason, + * let's not discard transmitting the packet. + */ + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "Failed to fill the required data for the mgmt packet err %d\n", + ret); + } + ret = ath11k_mac_mgmt_tx_wmi(ar, arvif, skb); if (ret) { ath11k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", @@ -9079,81 +9389,6 @@ static void ath11k_mac_put_chain_rssi(struct station_info *sinfo, } } -static void ath11k_mac_fw_stats_reset(struct ath11k *ar) -{ - spin_lock_bh(&ar->data_lock); - ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs); - ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs); - ar->fw_stats.num_vdev_recvd = 0; - ar->fw_stats.num_bcn_recvd = 0; - spin_unlock_bh(&ar->data_lock); -} - -int ath11k_mac_fw_stats_request(struct ath11k *ar, - struct stats_request_params *req_param) -{ - struct ath11k_base *ab = ar->ab; - unsigned long time_left; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - ath11k_mac_fw_stats_reset(ar); - - reinit_completion(&ar->fw_stats_complete); - reinit_completion(&ar->fw_stats_done); - - ret = ath11k_wmi_send_stats_request_cmd(ar, req_param); - - if (ret) { - ath11k_warn(ab, "could not request fw stats (%d)\n", - ret); - return ret; - } - - time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ); - if (!time_left) - return -ETIMEDOUT; - - /* FW stats can get split when exceeding the stats data buffer limit. - * In that case, since there is no end marking for the back-to-back - * received 'update stats' event, we keep a 3 seconds timeout in case, - * fw_stats_done is not marked yet - */ - time_left = wait_for_completion_timeout(&ar->fw_stats_done, 3 * HZ); - if (!time_left) - return -ETIMEDOUT; - - return 0; -} - -static int ath11k_mac_get_fw_stats(struct ath11k *ar, u32 pdev_id, - u32 vdev_id, u32 stats_id) -{ - struct ath11k_base *ab = ar->ab; - struct stats_request_params req_param; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - if (ar->state != ATH11K_STATE_ON) - return -ENETDOWN; - - req_param.pdev_id = pdev_id; - req_param.vdev_id = vdev_id; - req_param.stats_id = stats_id; - - ret = ath11k_mac_fw_stats_request(ar, &req_param); - if (ret) - ath11k_warn(ab, "failed to request fw stats: %d\n", ret); - - ath11k_dbg(ab, ATH11K_DBG_WMI, - "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n", - pdev_id, vdev_id, stats_id); - - return ret; -} - static void ath11k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -9539,66 +9774,6 @@ exit: return ret; } -static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - unsigned int link_id, - int *dbm) -{ - struct ath11k *ar = hw->priv; - struct ath11k_base *ab = ar->ab; - struct ath11k_fw_stats_pdev *pdev; - int ret; - - /* Final Tx power is minimum of Target Power, CTL power, Regulatory - * Power, PSD EIRP Power. We just know the Regulatory power from the - * regulatory rules obtained. FW knows all these power and sets the min - * of these. Hence, we request the FW pdev stats in which FW reports - * the minimum of all vdev's channel Tx power. - */ - mutex_lock(&ar->conf_mutex); - - /* Firmware doesn't provide Tx power during CAC hence no need to fetch - * the stats. - */ - if (test_bit(ATH11K_CAC_RUNNING, &ar->dev_flags)) { - mutex_unlock(&ar->conf_mutex); - return -EAGAIN; - } - - ret = ath11k_mac_get_fw_stats(ar, ar->pdev->pdev_id, 0, - WMI_REQUEST_PDEV_STAT); - if (ret) { - ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret); - goto err_fallback; - } - - spin_lock_bh(&ar->data_lock); - pdev = list_first_entry_or_null(&ar->fw_stats.pdevs, - struct ath11k_fw_stats_pdev, list); - if (!pdev) { - spin_unlock_bh(&ar->data_lock); - goto err_fallback; - } - - /* tx power is set as 2 units per dBm in FW. */ - *dbm = pdev->chan_tx_power / 2; - - spin_unlock_bh(&ar->data_lock); - mutex_unlock(&ar->conf_mutex); - - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "txpower from firmware %d, reported %d dBm\n", - pdev->chan_tx_power, *dbm); - return 0; - -err_fallback: - mutex_unlock(&ar->conf_mutex); - /* We didn't get txpower from FW. Hence, relying on vif->bss_conf.txpower */ - *dbm = vif->bss_conf.txpower; - ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "txpower from firmware NaN, reported %d dBm\n", - *dbm); - return 0; -} - static int ath11k_mac_station_add(struct ath11k *ar, struct ieee80211_vif *vif, struct ieee80211_sta *sta) @@ -10368,6 +10543,8 @@ static int __ath11k_mac_register(struct ath11k *ar) ar->hw->wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; + ar->hw->wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION; + ar->max_num_stations = TARGET_NUM_STATIONS(ab); ar->max_num_peers = TARGET_NUM_PEERS_PDEV(ab); diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index d8655badd96d..7114eca8810d 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/module.h> @@ -177,6 +177,19 @@ static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci) ab_pci->ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); } +static void ath11k_pci_restore_window(struct ath11k_base *ab) +{ + struct ath11k_pci *ab_pci = ath11k_pci_priv(ab); + + spin_lock_bh(&ab_pci->window_lock); + + iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | ab_pci->register_window, + ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); + ioread32(ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS); + + spin_unlock_bh(&ab_pci->window_lock); +} + static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) { u32 val, delay; @@ -201,6 +214,11 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab) val = ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET); if (val == 0xffffffff) ath11k_warn(ab, "link down error during global reset\n"); + + /* Restore window register as its content is cleared during + * hardware global reset, such that it aligns with host cache. + */ + ath11k_pci_restore_window(ab); } static void ath11k_pci_clear_dbg_registers(struct ath11k_base *ab) diff --git a/drivers/net/wireless/ath/ath11k/pci.h b/drivers/net/wireless/ath/ath11k/pci.h index c33c7865145c..1e3005a4b64c 100644 --- a/drivers/net/wireless/ath/ath11k/pci.h +++ b/drivers/net/wireless/ath/ath11k/pci.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _ATH11K_PCI_H #define _ATH11K_PCI_H @@ -35,18 +35,18 @@ #define PCIE_SMLH_REQ_RST_LINK_DOWN 0x2 #define PCIE_INT_CLEAR_ALL 0xffffffff -#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(x) \ - (ab->hw_params.regs->pcie_qserdes_sysclk_en_sel) +#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab) \ + ((ab)->hw_params.regs->pcie_qserdes_sysclk_en_sel) #define PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL 0x10 #define PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK 0xffffffff -#define PCIE_PCS_OSC_DTCT_CONFIG1_REG(x) \ - (ab->hw_params.regs->pcie_pcs_osc_dtct_config_base) +#define PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab) \ + ((ab)->hw_params.regs->pcie_pcs_osc_dtct_config_base) #define PCIE_PCS_OSC_DTCT_CONFIG1_VAL 0x02 -#define PCIE_PCS_OSC_DTCT_CONFIG2_REG(x) \ - (ab->hw_params.regs->pcie_pcs_osc_dtct_config_base + 0x4) +#define PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab) \ + ((ab)->hw_params.regs->pcie_pcs_osc_dtct_config_base + 0x4) #define PCIE_PCS_OSC_DTCT_CONFIG2_VAL 0x52 -#define PCIE_PCS_OSC_DTCT_CONFIG4_REG(x) \ - (ab->hw_params.regs->pcie_pcs_osc_dtct_config_base + 0xc) +#define PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab) \ + ((ab)->hw_params.regs->pcie_pcs_osc_dtct_config_base + 0xc) #define PCIE_PCS_OSC_DTCT_CONFIG4_VAL 0xff #define PCIE_PCS_OSC_DTCT_CONFIG_MSK 0x000000ff diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index aea56c38bf8f..ff6a97e328b8 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -3177,7 +3177,7 @@ static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl, sq->sq_node = service->node; sq->sq_port = service->port; - ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)sq, + ret = kernel_connect(qmi_hdl->sock, (struct sockaddr_unsized *)sq, sizeof(*sq), 0); if (ret) { ath11k_warn(ab, "failed to connect to qmi remote service: %d\n", ret); diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index e3b444333dee..110035dae8a6 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/skbuff.h> #include <linux/ctype.h> @@ -2061,10 +2061,13 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, cmd->peer_bw_rxnss_override |= param->peer_bw_rxnss_override; if (param->vht_capable) { - mcs->rx_max_rate = param->rx_max_rate; - mcs->rx_mcs_set = param->rx_mcs_set; - mcs->tx_max_rate = param->tx_max_rate; - mcs->tx_mcs_set = param->tx_mcs_set; + /* firmware interprets mcs->tx_mcs_set field as peer's + * RX capability + */ + mcs->tx_max_rate = param->rx_max_rate; + mcs->tx_mcs_set = param->rx_mcs_set; + mcs->rx_max_rate = param->tx_max_rate; + mcs->rx_mcs_set = param->tx_mcs_set; } /* HE Rates */ @@ -2088,8 +2091,11 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, FIELD_PREP(WMI_TLV_LEN, sizeof(*he_mcs) - TLV_HDR_SIZE); - he_mcs->rx_mcs_set = param->peer_he_tx_mcs_set[i]; - he_mcs->tx_mcs_set = param->peer_he_rx_mcs_set[i]; + /* firmware interprets mcs->rx_mcs_set field as peer's + * RX capability + */ + he_mcs->rx_mcs_set = param->peer_he_rx_mcs_set[i]; + he_mcs->tx_mcs_set = param->peer_he_tx_mcs_set[i]; ptr += sizeof(*he_mcs); } diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 9fcffaa2f383..0f0de24a3840 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH11K_WMI_H @@ -3463,20 +3463,6 @@ struct scan_cancel_param { u32 pdev_id; }; -struct wmi_bcn_send_from_host_cmd { - u32 tlv_header; - u32 vdev_id; - u32 data_len; - union { - u32 frag_ptr; - u32 frag_ptr_lo; - }; - u32 frame_ctrl; - u32 dtim_flag; - u32 bcn_antenna; - u32 frag_ptr_hi; -}; - #define WMI_CHAN_INFO_MODE GENMASK(5, 0) #define WMI_CHAN_INFO_HT40_PLUS BIT(6) #define WMI_CHAN_INFO_PASSIVE BIT(7) @@ -4133,8 +4119,10 @@ struct wmi_rate_set { struct wmi_vht_rate_set { u32 tlv_header; u32 rx_max_rate; + /* MCS at which the peer can transmit */ u32 rx_mcs_set; u32 tx_max_rate; + /* MCS at which the peer can receive */ u32 tx_mcs_set; u32 tx_max_mcs_nss; } __packed; |
