mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
ath11k: reduce diff to upstream Atheros/QCA's ath11k driver
It seems that over the time of merging and only partly working on making it compile again a few mis-merges happened. Reduce diff to the v6.19 upstream version so that we only have additions to the driver (usually guarded by #ifdef __FreeBSD__). Sponsored by: The FreeBSD Foundation MFC after: 3 days
This commit is contained in:
1 parent
03ba27c194
commit
3c4eef5d83
7 files changed
+415
-194
No files matched your search
@@ -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
|
||||
|
||||
+316
-139
@@ -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);
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -209,6 +209,19 @@ static inline void ath11k_pci_select_static_window(struct ath11k_pci *ab_pci)
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -233,6 +246,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)
|
||||
@@ -1269,9 +1287,39 @@ static __maybe_unused int ath11k_pci_pm_resume(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ath11k_pci_pm_ops,
|
||||
ath11k_pci_pm_suspend,
|
||||
ath11k_pci_pm_resume);
|
||||
static __maybe_unused int ath11k_pci_pm_suspend_late(struct device *dev)
|
||||
{
|
||||
struct ath11k_base *ab = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = ath11k_core_suspend_late(ab);
|
||||
if (ret)
|
||||
ath11k_warn(ab, "failed to late suspend core: %d\n", ret);
|
||||
|
||||
/* Similar to ath11k_pci_pm_suspend(), we return success here
|
||||
* even error happens, to allow system suspend/hibernation survive.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int ath11k_pci_pm_resume_early(struct device *dev)
|
||||
{
|
||||
struct ath11k_base *ab = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = ath11k_core_resume_early(ab);
|
||||
if (ret)
|
||||
ath11k_warn(ab, "failed to early resume core: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops __maybe_unused ath11k_pci_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend,
|
||||
ath11k_pci_pm_resume)
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(ath11k_pci_pm_suspend_late,
|
||||
ath11k_pci_pm_resume_early)
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct pci_driver ath11k_pci_driver = {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -3219,7 +3219,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);
|
||||
|
||||
@@ -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>
|
||||
@@ -1903,6 +1903,8 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id,
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "cmd bcn tmpl");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2172,10 +2174,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 */
|
||||
@@ -2207,8 +2212,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -3466,20 +3466,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)
|
||||
@@ -4136,8 +4122,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;
|
||||
|
||||
Reference in new issue
Block a user