mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
ath.git patches for v7.2 (PR #2)
For ath12k: - Add thermal throttling and cooling device support - Add support for handling incumbent signal interference in 6 GHz - Add support for channel 177 in the 5 GHz band In addition, a large number of cleanup and minor bug fixing across all supported drivers. -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQ/mtSHzPUi16IfDEksFbugiYzLewUCahXEHAAKCRAsFbugiYzL e4+OAQCK3CILFdb8JbEVgROb/bfAmGWCAkdEBIMxEbGITQSQCAEAsdLEntym8eJA rjCjLNz62Dn5KoQLaV436nCjC+UjWwo= =3Pqg -----END PGP SIGNATURE----- Merge tag 'ath-next-20260526' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath Jeff Johnson says: ================== ath.git patches for v7.2 (PR #2) For ath12k: - Add thermal throttling and cooling device support - Add support for handling incumbent signal interference in 6 GHz - Add support for channel 177 in the 5 GHz band In addition, a large number of cleanup and minor bug fixing across all supported drivers. ================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
commit
6f5dc19f46
|
|
@ -1269,7 +1269,6 @@ struct ath10k {
|
|||
} testmode;
|
||||
|
||||
struct {
|
||||
struct gpio_led wifi_led;
|
||||
struct led_classdev cdev;
|
||||
char label[48];
|
||||
u32 gpio_state_pin;
|
||||
|
|
|
|||
|
|
@ -1353,7 +1353,7 @@ static int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txm
|
|||
msdu_id = res;
|
||||
}
|
||||
|
||||
/* As msdu is freed by mac80211 (in ieee80211_tx_status()) and by
|
||||
/* As msdu is freed by mac80211 (in ieee80211_tx_status_skb()) and by
|
||||
* ath10k (in ath10k_htt_htc_tx_complete()) we have to increase
|
||||
* reference by one to avoid a use-after-free case and a double
|
||||
* free.
|
||||
|
|
|
|||
|
|
@ -19,15 +19,13 @@ static int ath10k_leds_set_brightness_blocking(struct led_classdev *led_cdev,
|
|||
{
|
||||
struct ath10k *ar = container_of(led_cdev, struct ath10k,
|
||||
leds.cdev);
|
||||
struct gpio_led *led = &ar->leds.wifi_led;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON)
|
||||
goto out;
|
||||
|
||||
ar->leds.gpio_state_pin = (brightness != LED_OFF) ^ led->active_low;
|
||||
ath10k_wmi_gpio_output(ar, ar->hw_params.led_pin, ar->leds.gpio_state_pin);
|
||||
ath10k_wmi_gpio_output(ar, ar->hw_params.led_pin, brightness == LED_OFF);
|
||||
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
|
@ -63,13 +61,9 @@ int ath10k_leds_register(struct ath10k *ar)
|
|||
|
||||
snprintf(ar->leds.label, sizeof(ar->leds.label), "ath10k-%s",
|
||||
wiphy_name(ar->hw->wiphy));
|
||||
ar->leds.wifi_led.active_low = 1;
|
||||
ar->leds.wifi_led.name = ar->leds.label;
|
||||
ar->leds.wifi_led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
|
||||
|
||||
ar->leds.cdev.name = ar->leds.label;
|
||||
ar->leds.cdev.brightness_set_blocking = ath10k_leds_set_brightness_blocking;
|
||||
ar->leds.cdev.default_trigger = ar->leds.wifi_led.default_trigger;
|
||||
|
||||
ret = led_classdev_register(wiphy_dev(ar->hw->wiphy), &ar->leds.cdev);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
|
|
@ -1112,7 +1112,7 @@ int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)
|
|||
spin_lock_init(&qmi->event_lock);
|
||||
INIT_WORK(&qmi->event_work, ath10k_qmi_driver_event_work);
|
||||
|
||||
ret = qmi_add_lookup(&qmi->qmi_hdl, WLFW_SERVICE_ID_V01,
|
||||
ret = qmi_add_lookup(&qmi->qmi_hdl, QMI_SERVICE_ID_WLFW,
|
||||
WLFW_SERVICE_VERS_V01, 0);
|
||||
if (ret)
|
||||
goto err_qmi_lookup;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#ifndef WCN3990_QMI_SVC_V01_H
|
||||
#define WCN3990_QMI_SVC_V01_H
|
||||
|
||||
#define WLFW_SERVICE_ID_V01 0x45
|
||||
#define WLFW_SERVICE_VERS_V01 0x01
|
||||
|
||||
#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
config ATH11K
|
||||
tristate "Qualcomm Technologies 802.11ax chipset support"
|
||||
tristate "Qualcomm 802.11ax chipset support"
|
||||
depends on MAC80211 && HAS_DMA
|
||||
select ATH_COMMON
|
||||
select QCOM_QMI_HELPERS
|
||||
|
|
|
|||
|
|
@ -1040,6 +1040,7 @@ void ath11k_dp_free(struct ath11k_base *ab)
|
|||
idr_destroy(&dp->tx_ring[i].txbuf_idr);
|
||||
spin_unlock_bh(&dp->tx_ring[i].tx_idr_lock);
|
||||
kfree(dp->tx_ring[i].tx_status);
|
||||
dp->tx_ring[i].tx_status = NULL;
|
||||
}
|
||||
|
||||
/* Deinit any SOC level resource */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
/*
|
||||
* Copyright (c) 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/msi.h>
|
||||
|
|
@ -282,8 +282,10 @@ static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,
|
|||
break;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ab->base_lock);
|
||||
if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))
|
||||
queue_work(ab->workqueue_aux, &ab->reset_work);
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -1210,6 +1210,14 @@ static void ath11k_pci_shutdown(struct pci_dev *pdev)
|
|||
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
||||
|
||||
ath11k_pci_set_irq_affinity_hint(ab_pci, NULL);
|
||||
|
||||
spin_lock_bh(&ab->base_lock);
|
||||
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
|
||||
spin_unlock_bh(&ab->base_lock);
|
||||
|
||||
cancel_work_sync(&ab->reset_work);
|
||||
cancel_work_sync(&ab->dump_work);
|
||||
|
||||
ath11k_pci_power_down(ab, false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// 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.
|
||||
*/
|
||||
|
||||
|
|
@ -3337,7 +3336,7 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
|
|||
spin_lock_init(&ab->qmi.event_lock);
|
||||
INIT_WORK(&ab->qmi.event_work, ath11k_qmi_driver_event_work);
|
||||
|
||||
ret = qmi_add_lookup(&ab->qmi.handle, ATH11K_QMI_WLFW_SERVICE_ID_V01,
|
||||
ret = qmi_add_lookup(&ab->qmi.handle, QMI_SERVICE_ID_WLFW,
|
||||
ATH11K_QMI_WLFW_SERVICE_VERS_V01,
|
||||
ab->qmi.service_ins_id);
|
||||
if (ret < 0) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#define ATH11K_QMI_MAX_BDF_FILE_NAME_SIZE 64
|
||||
#define ATH11K_QMI_CALDB_ADDRESS 0x4BA00000
|
||||
#define ATH11K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128
|
||||
#define ATH11K_QMI_WLFW_SERVICE_ID_V01 0x45
|
||||
#define ATH11K_QMI_WLFW_SERVICE_VERS_V01 0x01
|
||||
#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01 0x02
|
||||
#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390 0x01
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
config ATH12K
|
||||
tristate "Qualcomm Technologies Wi-Fi 7 support (ath12k)"
|
||||
tristate "Qualcomm Wi-Fi 7 support (ath12k)"
|
||||
depends on MAC80211 && HAS_DMA && PCI
|
||||
select QCOM_QMI_HELPERS
|
||||
select MHI_BUS
|
||||
|
|
@ -15,7 +15,7 @@ config ATH12K
|
|||
If you choose to build a module, it'll be called ath12k.
|
||||
|
||||
config ATH12K_AHB
|
||||
bool "QTI ath12k AHB support"
|
||||
bool "Qualcomm ath12k AHB support"
|
||||
depends on ATH12K && REMOTEPROC
|
||||
select QCOM_MDT_LOADER
|
||||
select QCOM_SCM
|
||||
|
|
@ -33,7 +33,7 @@ config ATH12K_DEBUG
|
|||
you want optimal performance choose N.
|
||||
|
||||
config ATH12K_DEBUGFS
|
||||
bool "QTI ath12k debugfs support"
|
||||
bool "Qualcomm ath12k debugfs support"
|
||||
depends on ATH12K && MAC80211_DEBUGFS
|
||||
help
|
||||
Enable ath12k debugfs support
|
||||
|
|
|
|||
|
|
@ -1006,6 +1006,27 @@ static void ath12k_core_device_cleanup(struct ath12k_base *ab)
|
|||
mutex_unlock(&ab->core_lock);
|
||||
}
|
||||
|
||||
static int ath12k_core_device_setup(struct ath12k_base *ab)
|
||||
{
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&ab->core_lock);
|
||||
|
||||
ret = ath12k_core_pdev_create(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to create pdev core %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath12k_hif_irq_enable(ab);
|
||||
|
||||
ret = ath12k_core_rfkill_config(ab);
|
||||
if (ret && ret != -EOPNOTSUPP)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
|
||||
{
|
||||
struct ath12k_base *ab;
|
||||
|
|
@ -1015,10 +1036,6 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
|
|||
|
||||
clear_bit(ATH12K_GROUP_FLAG_REGISTERED, &ag->flags);
|
||||
|
||||
ath12k_mac_unregister(ag);
|
||||
|
||||
ath12k_mac_mlo_teardown(ag);
|
||||
|
||||
for (i = ag->num_devices - 1; i >= 0; i--) {
|
||||
ab = ag->ab[i];
|
||||
if (!ab)
|
||||
|
|
@ -1029,6 +1046,12 @@ static void ath12k_core_hw_group_stop(struct ath12k_hw_group *ag)
|
|||
ath12k_core_device_cleanup(ab);
|
||||
}
|
||||
|
||||
/* Unregister MAC (drops wiphys) only after per-device cleanup */
|
||||
ath12k_mac_unregister(ag);
|
||||
|
||||
/* Teardown MLO state after MAC unregister for symmetry */
|
||||
ath12k_mac_mlo_teardown(ag);
|
||||
|
||||
ath12k_mac_destroy(ag);
|
||||
}
|
||||
|
||||
|
|
@ -1165,26 +1188,11 @@ static int ath12k_core_hw_group_start(struct ath12k_hw_group *ag)
|
|||
if (!ab)
|
||||
continue;
|
||||
|
||||
mutex_lock(&ab->core_lock);
|
||||
|
||||
set_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags);
|
||||
|
||||
ret = ath12k_core_pdev_create(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to create pdev core %d\n", ret);
|
||||
mutex_unlock(&ab->core_lock);
|
||||
ret = ath12k_core_device_setup(ab);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ath12k_hif_irq_enable(ab);
|
||||
|
||||
ret = ath12k_core_rfkill_config(ab);
|
||||
if (ret && ret != -EOPNOTSUPP) {
|
||||
mutex_unlock(&ab->core_lock);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mutex_unlock(&ab->core_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -542,8 +542,8 @@ struct ath12k_sta {
|
|||
#define ATH12K_MAX_5GHZ_FREQ (ATH12K_5GHZ_MAX_CENTER + ATH12K_HALF_20MHZ_BW)
|
||||
#define ATH12K_MIN_6GHZ_FREQ (ATH12K_6GHZ_MIN_CENTER - ATH12K_HALF_20MHZ_BW)
|
||||
#define ATH12K_MAX_6GHZ_FREQ (ATH12K_6GHZ_MAX_CENTER + ATH12K_HALF_20MHZ_BW)
|
||||
#define ATH12K_NUM_CHANS 101
|
||||
#define ATH12K_MAX_5GHZ_CHAN 173
|
||||
#define ATH12K_NUM_CHANS 102
|
||||
#define ATH12K_MAX_5GHZ_CHAN 177
|
||||
|
||||
static inline bool ath12k_is_2ghz_channel_freq(u32 freq)
|
||||
{
|
||||
|
|
@ -763,6 +763,14 @@ struct ath12k {
|
|||
struct ath12k_pdev_rssi_offsets rssi_info;
|
||||
|
||||
struct ath12k_thermal thermal;
|
||||
|
||||
/* Protected by ar->data_lock */
|
||||
struct ath12k_incumbent_signal_interference {
|
||||
u32 center_freq;
|
||||
enum nl80211_chan_width width;
|
||||
u32 chan_bw_interference_bitmap;
|
||||
bool handling_in_progress;
|
||||
} incumbent_signal_interference;
|
||||
};
|
||||
|
||||
struct ath12k_hw {
|
||||
|
|
|
|||
|
|
@ -1450,6 +1450,44 @@ static const struct file_operations fops_pdev_stats = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t
|
||||
ath12k_write_simulate_incumbent_signal_interference(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath12k *ar = file->private_data;
|
||||
struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
|
||||
struct wiphy *wiphy = ath12k_ar_to_hw(ar)->wiphy;
|
||||
u32 chan_bw_interference_bitmap;
|
||||
int ret;
|
||||
|
||||
if (ah->state != ATH12K_HW_STATE_ON)
|
||||
return -ENETDOWN;
|
||||
|
||||
/*
|
||||
* Bitmap uses the firmware primary-based ordering documented in
|
||||
* ath12k_wmi_transform_interference_bitmap() & intf_map_80.
|
||||
*/
|
||||
if (kstrtou32_from_user(user_buf, count, 0, &chan_bw_interference_bitmap))
|
||||
return -EINVAL;
|
||||
|
||||
wiphy_lock(wiphy);
|
||||
ret = ath12k_wmi_simulate_incumbent_signal_interference(ar, chan_bw_interference_bitmap);
|
||||
if (ret)
|
||||
goto exit;
|
||||
|
||||
ret = count;
|
||||
|
||||
exit:
|
||||
wiphy_unlock(wiphy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_simulate_incumbent_signal_interference = {
|
||||
.write = ath12k_write_simulate_incumbent_signal_interference,
|
||||
.open = simple_open,
|
||||
};
|
||||
|
||||
static
|
||||
void ath12k_debugfs_fw_stats_register(struct ath12k *ar)
|
||||
{
|
||||
|
|
@ -1515,6 +1553,14 @@ void ath12k_debugfs_register(struct ath12k *ar)
|
|||
ar, &fops_tpc_stats_type);
|
||||
init_completion(&ar->debug.tpc_complete);
|
||||
|
||||
if (ar->mac.sbands[NL80211_BAND_6GHZ].channels &&
|
||||
test_bit(WMI_TLV_SERVICE_DCS_INCUMBENT_SIGNAL_INTERFERENCE_SUPPORT,
|
||||
ar->ab->wmi_ab.svc_map)) {
|
||||
debugfs_create_file("simulate_incumbent_signal_interference", 0200,
|
||||
ar->debug.debugfs_pdev, ar,
|
||||
&fops_simulate_incumbent_signal_interference);
|
||||
}
|
||||
|
||||
ath12k_debugfs_htt_stats_register(ar);
|
||||
ath12k_debugfs_fw_stats_register(ar);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
#include "dp_mon.h"
|
||||
#include "debugfs_htt_stats.h"
|
||||
|
||||
#define ATH12K_2GHZ_MIN_CHAN_NUM 1
|
||||
#define ATH12K_2GHZ_MAX_CHAN_NUM 14
|
||||
#define ATH12K_5GHZ_MIN_CHAN_NUM 36
|
||||
#define ATH12K_5GHZ_MAX_CHAN_NUM 177
|
||||
|
||||
static int ath12k_dp_rx_tid_delete_handler(struct ath12k_base *ab,
|
||||
struct ath12k_dp_rx_tid_rxq *rx_tid);
|
||||
|
||||
|
|
@ -1095,7 +1100,8 @@ static void ath12k_get_dot11_hdr_from_rx_desc(struct ath12k_pdev_dp *dp_pdev,
|
|||
static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev,
|
||||
struct sk_buff *msdu,
|
||||
enum hal_encrypt_type enctype,
|
||||
struct hal_rx_desc_data *rx_info)
|
||||
struct hal_rx_desc_data *rx_info,
|
||||
enum ath12k_dp_rx_decap_type decap_type)
|
||||
{
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ethhdr *eth;
|
||||
|
|
@ -1103,12 +1109,24 @@ static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev,
|
|||
u8 sa[ETH_ALEN];
|
||||
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
|
||||
struct ath12k_dp_rx_rfc1042_hdr rfc = {0xaa, 0xaa, 0x03, {0x00, 0x00, 0x00}};
|
||||
struct ath12k_dp_rx_rfc1042_hdr *llc;
|
||||
|
||||
eth = (struct ethhdr *)msdu->data;
|
||||
ether_addr_copy(da, eth->h_dest);
|
||||
ether_addr_copy(sa, eth->h_source);
|
||||
rfc.snap_type = eth->h_proto;
|
||||
skb_pull(msdu, sizeof(*eth));
|
||||
if (decap_type == DP_RX_DECAP_TYPE_8023) {
|
||||
/*
|
||||
* For 802.3 frames, eth->h_proto carries a length field, not
|
||||
* an EtherType. The actual EtherType is in the LLC/SNAP header
|
||||
* that follows the Ethernet header.
|
||||
*/
|
||||
llc = (struct ath12k_dp_rx_rfc1042_hdr *)(msdu->data + sizeof(*eth));
|
||||
rfc.snap_type = llc->snap_type;
|
||||
skb_pull(msdu, sizeof(*eth) + sizeof(*llc));
|
||||
} else {
|
||||
rfc.snap_type = eth->h_proto;
|
||||
skb_pull(msdu, sizeof(*eth));
|
||||
}
|
||||
memcpy(skb_push(msdu, sizeof(rfc)), &rfc,
|
||||
sizeof(rfc));
|
||||
ath12k_get_dot11_hdr_from_rx_desc(dp_pdev, msdu, rxcb, enctype, rx_info);
|
||||
|
|
@ -1126,9 +1144,10 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu
|
|||
bool decrypted,
|
||||
struct hal_rx_desc_data *rx_info)
|
||||
{
|
||||
enum ath12k_dp_rx_decap_type decap_type = rx_info->decap_type;
|
||||
struct ethhdr *ehdr;
|
||||
|
||||
switch (rx_info->decap_type) {
|
||||
switch (decap_type) {
|
||||
case DP_RX_DECAP_TYPE_NATIVE_WIFI:
|
||||
ath12k_dp_rx_h_undecap_nwifi(dp_pdev, msdu, enctype, rx_info);
|
||||
break;
|
||||
|
|
@ -1142,19 +1161,33 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu
|
|||
/* mac80211 allows fast path only for authorized STA */
|
||||
if (ehdr->h_proto == cpu_to_be16(ETH_P_PAE)) {
|
||||
ATH12K_SKB_RXCB(msdu)->is_eapol = true;
|
||||
ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info);
|
||||
ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info,
|
||||
decap_type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* PN for mcast packets will be validated in mac80211;
|
||||
* remove eth header and add 802.11 header.
|
||||
*/
|
||||
if (ATH12K_SKB_RXCB(msdu)->is_mcbc && decrypted)
|
||||
ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info);
|
||||
if (ATH12K_SKB_RXCB(msdu)->is_mcbc && decrypted) {
|
||||
ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info,
|
||||
decap_type);
|
||||
break;
|
||||
}
|
||||
|
||||
rx_info->rx_status->flag |= RX_FLAG_8023;
|
||||
break;
|
||||
case DP_RX_DECAP_TYPE_8023:
|
||||
/* TODO: Handle undecap for these formats */
|
||||
break;
|
||||
/*
|
||||
* Note that ethernet decap format indicates that the decapped
|
||||
* packet is either Ethernet 2 (DIX) or 802.3 (uses SNAP/LLC).
|
||||
*/
|
||||
if (ATH12K_SKB_RXCB(msdu)->is_mcbc && decrypted) {
|
||||
ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info,
|
||||
decap_type);
|
||||
break;
|
||||
}
|
||||
rx_info->rx_status->flag |= RX_FLAG_8023;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_dp_rx_h_undecap);
|
||||
|
|
@ -1289,9 +1322,11 @@ void ath12k_dp_rx_h_ppdu(struct ath12k_pdev_dp *dp_pdev,
|
|||
center_freq <= ATH12K_MAX_6GHZ_FREQ) {
|
||||
rx_status->band = NL80211_BAND_6GHZ;
|
||||
rx_status->freq = center_freq;
|
||||
} else if (channel_num >= 1 && channel_num <= 14) {
|
||||
} else if (channel_num >= ATH12K_2GHZ_MIN_CHAN_NUM &&
|
||||
channel_num <= ATH12K_2GHZ_MAX_CHAN_NUM) {
|
||||
rx_status->band = NL80211_BAND_2GHZ;
|
||||
} else if (channel_num >= 36 && channel_num <= 173) {
|
||||
} else if (channel_num >= ATH12K_5GHZ_MIN_CHAN_NUM &&
|
||||
channel_num <= ATH12K_5GHZ_MAX_CHAN_NUM) {
|
||||
rx_status->band = NL80211_BAND_5GHZ;
|
||||
}
|
||||
|
||||
|
|
@ -1336,9 +1371,7 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
|
|||
struct ath12k_dp_peer *peer;
|
||||
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
|
||||
struct ieee80211_rx_status *status = rx_info->rx_status;
|
||||
u8 decap = rx_info->decap_type;
|
||||
bool is_mcbc = rxcb->is_mcbc;
|
||||
bool is_eapol = rxcb->is_eapol;
|
||||
|
||||
peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
|
||||
|
||||
|
|
@ -1383,15 +1416,6 @@ void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struc
|
|||
|
||||
/* TODO: trace rx packet */
|
||||
|
||||
/* PN for multicast packets are not validate in HW,
|
||||
* so skip 802.3 rx path
|
||||
* Also, fast_rx expects the STA to be authorized, hence
|
||||
* eapol packets are sent in slow path.
|
||||
*/
|
||||
if (decap == DP_RX_DECAP_TYPE_ETHERNET2_DIX && !is_eapol &&
|
||||
!(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED))
|
||||
rx_status->flag |= RX_FLAG_8023;
|
||||
|
||||
ieee80211_rx_napi(ath12k_pdev_dp_to_hw(dp_pdev), pubsta, msdu, napi);
|
||||
}
|
||||
EXPORT_SYMBOL(ath12k_dp_rx_deliver_msdu);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@
|
|||
.max_power = 30, \
|
||||
}
|
||||
|
||||
#define ATH12K_5_9_GHZ_MIN_FREQ 5845
|
||||
#define ATH12K_5_9_GHZ_MAX_FREQ 5885
|
||||
|
||||
static const struct ieee80211_channel ath12k_2ghz_channels[] = {
|
||||
CHAN2G(1, 2412, 0),
|
||||
CHAN2G(2, 2417, 0),
|
||||
|
|
@ -96,6 +99,7 @@ static const struct ieee80211_channel ath12k_5ghz_channels[] = {
|
|||
CHAN5G(165, 5825, 0),
|
||||
CHAN5G(169, 5845, 0),
|
||||
CHAN5G(173, 5865, 0),
|
||||
CHAN5G(177, 5885, 0),
|
||||
};
|
||||
|
||||
static const struct ieee80211_channel ath12k_6ghz_channels[] = {
|
||||
|
|
@ -5615,12 +5619,14 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
|
|||
if (ret)
|
||||
goto exit;
|
||||
|
||||
arg = kzalloc_obj(*arg);
|
||||
arg = kzalloc_flex(*arg, chan_list, n_channels);
|
||||
if (!arg) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
arg->num_chan = n_channels;
|
||||
|
||||
ath12k_wmi_start_scan_init(ar, arg);
|
||||
arg->vdev_id = arvif->vdev_id;
|
||||
arg->scan_id = ATH12K_SCAN_ID;
|
||||
|
|
@ -5642,18 +5648,8 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
|
|||
arg->scan_f_passive = 1;
|
||||
}
|
||||
|
||||
if (n_channels) {
|
||||
arg->num_chan = n_channels;
|
||||
arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list),
|
||||
GFP_KERNEL);
|
||||
if (!arg->chan_list) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < arg->num_chan; i++)
|
||||
arg->chan_list[i] = chan_list[i]->center_freq;
|
||||
}
|
||||
for (i = 0; i < arg->num_chan; i++)
|
||||
arg->chan_list[i] = chan_list[i]->center_freq;
|
||||
|
||||
ret = ath12k_start_scan(ar, arg);
|
||||
if (ret) {
|
||||
|
|
@ -5678,7 +5674,6 @@ static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw,
|
|||
|
||||
exit:
|
||||
if (arg) {
|
||||
kfree(arg->chan_list);
|
||||
kfree(arg->extraie.ptr);
|
||||
kfree(arg);
|
||||
}
|
||||
|
|
@ -9650,6 +9645,10 @@ static int ath12k_mac_start(struct ath12k *ar)
|
|||
ar->allocated_vdev_map = 0;
|
||||
ar->chan_tx_pwr = ATH12K_PDEV_TX_POWER_INVALID;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->incumbent_signal_interference.handling_in_progress = false;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
/* Configure monitor status ring with default rx_filter to get rx status
|
||||
* such as rssi, rx_duration.
|
||||
*/
|
||||
|
|
@ -9677,6 +9676,12 @@ static int ath12k_mac_start(struct ath12k *ar)
|
|||
}
|
||||
}
|
||||
|
||||
ret = ath12k_thermal_throttling_config_default(ar);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to set thermal throttle: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx],
|
||||
&ab->pdevs[ar->pdev_idx]);
|
||||
|
||||
|
|
@ -9857,6 +9862,10 @@ static void ath12k_mac_stop(struct ath12k *ar)
|
|||
synchronize_rcu();
|
||||
|
||||
atomic_set(&ar->num_pending_mgmt_tx, 0);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->incumbent_signal_interference.handling_in_progress = false;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend)
|
||||
|
|
@ -11443,8 +11452,10 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
|
|||
struct ieee80211_vif_chanctx_switch *vifs,
|
||||
int n_vifs)
|
||||
{
|
||||
struct ath12k_incumbent_signal_interference *incumbent;
|
||||
struct ath12k_wmi_vdev_up_params params = {};
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
struct cfg80211_chan_def *chandef;
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct ieee80211_vif *vif;
|
||||
|
|
@ -11556,6 +11567,42 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
|
|||
if (!ath12k_mac_monitor_stop(ar))
|
||||
ath12k_mac_monitor_start(ar);
|
||||
}
|
||||
|
||||
incumbent = &ar->incumbent_signal_interference;
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
if (incumbent->handling_in_progress) {
|
||||
chandef = &vifs[0].new_ctx->def;
|
||||
if (incumbent->chan_bw_interference_bitmap &
|
||||
ATH12K_WMI_DCS_SEG_PRI20) {
|
||||
if (incumbent->center_freq !=
|
||||
chandef->chan->center_freq) {
|
||||
incumbent->chan_bw_interference_bitmap = 0;
|
||||
incumbent->handling_in_progress = false;
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC,
|
||||
"incumbent signal interference chan switch completed\n");
|
||||
} else {
|
||||
ath12k_warn(ab,
|
||||
"incumbent signal interference chan switch not done, freq %u\n",
|
||||
incumbent->center_freq);
|
||||
}
|
||||
} else {
|
||||
if (incumbent->center_freq !=
|
||||
chandef->chan->center_freq ||
|
||||
incumbent->width != chandef->width) {
|
||||
incumbent->chan_bw_interference_bitmap = 0;
|
||||
incumbent->handling_in_progress = false;
|
||||
ath12k_dbg(ab, ATH12K_DBG_MAC,
|
||||
"Bandwidth/channel change due to incumbent signal interference completed\n");
|
||||
} else {
|
||||
ath12k_warn(ab, "Bandwidth/channel change due to incumbent sig intf not done intf_freq %u chan_freq %u intf_width %u chan_width %u\n",
|
||||
incumbent->center_freq,
|
||||
chandef->chan->center_freq,
|
||||
incumbent->width,
|
||||
chandef->width);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -13739,19 +13786,13 @@ int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
|
|||
scan_time_msec = hw->wiphy->max_remain_on_channel_duration * 2;
|
||||
|
||||
struct ath12k_wmi_scan_req_arg *arg __free(kfree) =
|
||||
kzalloc_obj(*arg);
|
||||
kzalloc_flex(*arg, chan_list, 1);
|
||||
if (!arg)
|
||||
return -ENOMEM;
|
||||
|
||||
ath12k_wmi_start_scan_init(ar, arg);
|
||||
arg->num_chan = 1;
|
||||
ath12k_wmi_start_scan_init(ar, arg);
|
||||
|
||||
u32 *chan_list __free(kfree) = kcalloc(arg->num_chan, sizeof(*chan_list),
|
||||
GFP_KERNEL);
|
||||
if (!chan_list)
|
||||
return -ENOMEM;
|
||||
|
||||
arg->chan_list = chan_list;
|
||||
arg->vdev_id = arvif->vdev_id;
|
||||
arg->scan_id = ATH12K_SCAN_ID;
|
||||
arg->chan_list[0] = chan->center_freq;
|
||||
|
|
@ -13904,6 +13945,26 @@ static int ath12k_mac_update_band(struct ath12k *ar,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_mac_update_5_9_ghz_ch_list(struct ath12k *ar,
|
||||
struct ieee80211_supported_band *band)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (test_bit(WMI_TLV_SERVICE_5_9GHZ_SUPPORT,
|
||||
ar->ab->wmi_ab.svc_map))
|
||||
return;
|
||||
|
||||
guard(spinlock_bh)(&ar->ab->base_lock);
|
||||
if (ar->ab->dfs_region != ATH12K_DFS_REG_FCC)
|
||||
return;
|
||||
|
||||
for (i = 0; i < band->n_channels; i++) {
|
||||
if (band->channels[i].center_freq >= ATH12K_5_9_GHZ_MIN_FREQ &&
|
||||
band->channels[i].center_freq <= ATH12K_5_9_GHZ_MAX_FREQ)
|
||||
band->channels[i].flags |= IEEE80211_CHAN_DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
|
||||
u32 supported_bands,
|
||||
struct ieee80211_supported_band *bands[])
|
||||
|
|
@ -14037,6 +14098,8 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar,
|
|||
band->n_bitrates = ath12k_a_rates_size;
|
||||
band->bitrates = ath12k_a_rates;
|
||||
|
||||
ath12k_mac_update_5_9_ghz_ch_list(ar, band);
|
||||
|
||||
if (ab->hw_params->single_pdev_only) {
|
||||
phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5GHZ_CAP);
|
||||
reg_cap = &ab->hal_reg_cap[phy_id];
|
||||
|
|
@ -14465,6 +14528,8 @@ static int ath12k_mac_setup_register(struct ath12k *ar,
|
|||
ar->rssi_info.temp_offset = 0;
|
||||
ar->rssi_info.noise_floor = ar->rssi_info.min_nf_dbm + ar->rssi_info.temp_offset;
|
||||
|
||||
ath12k_thermal_init_configs(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -14817,6 +14882,7 @@ static void ath12k_mac_setup(struct ath12k *ar)
|
|||
init_completion(&ar->completed_11d_scan);
|
||||
init_completion(&ar->regd_update_completed);
|
||||
init_completion(&ar->thermal.wmi_sync);
|
||||
mutex_init(&ar->thermal.lock);
|
||||
|
||||
ar->thermal.temperature = 0;
|
||||
ar->thermal.hwmon_dev = NULL;
|
||||
|
|
|
|||
|
|
@ -1639,7 +1639,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
|
|||
ret = ab_pci->device_family_ops->arch_init(ab);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "PCI arch_init failed %d\n", ret);
|
||||
goto err_pci_msi_free;
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = ath12k_core_init(ab);
|
||||
|
|
|
|||
|
|
@ -4061,7 +4061,7 @@ int ath12k_qmi_init_service(struct ath12k_base *ab)
|
|||
spin_lock_init(&ab->qmi.event_lock);
|
||||
INIT_WORK(&ab->qmi.event_work, ath12k_qmi_driver_event_work);
|
||||
|
||||
ret = qmi_add_lookup(&ab->qmi.handle, ATH12K_QMI_WLFW_SERVICE_ID_V01,
|
||||
ret = qmi_add_lookup(&ab->qmi.handle, QMI_SERVICE_ID_WLFW,
|
||||
ATH12K_QMI_WLFW_SERVICE_VERS_V01,
|
||||
ab->qmi.service_ins_id);
|
||||
if (ret < 0) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
#define ATH12K_QMI_MAX_BDF_FILE_NAME_SIZE 64
|
||||
#define ATH12K_QMI_CALDB_ADDRESS 0x4BA00000
|
||||
#define ATH12K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128
|
||||
#define ATH12K_QMI_WLFW_SERVICE_ID_V01 0x45
|
||||
#define ATH12K_QMI_WLFW_SERVICE_VERS_V01 0x01
|
||||
#define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01 0x02
|
||||
#define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850 0x1
|
||||
|
|
|
|||
|
|
@ -12,6 +12,137 @@
|
|||
#include "core.h"
|
||||
#include "debug.h"
|
||||
|
||||
static const struct ath12k_wmi_tt_level_config_param
|
||||
tt_level_configs[ATH12K_TT_CFG_IDX_MAX][ENHANCED_THERMAL_LEVELS] = {
|
||||
[ATH12K_TT_CFG_IDX_IPA] = {
|
||||
[0] = { .tmplwm = -100, .tmphwm = 115, .dcoffpercent = 0,
|
||||
.pout_reduction_db = 0 },
|
||||
[1] = { .tmplwm = 110, .tmphwm = 120, .dcoffpercent = 0,
|
||||
.pout_reduction_db = 12 },
|
||||
[2] = { .tmplwm = 115, .tmphwm = 125, .dcoffpercent = 50,
|
||||
.pout_reduction_db = 12 },
|
||||
[3] = { .tmplwm = 120, .tmphwm = 130, .dcoffpercent = 90,
|
||||
.pout_reduction_db = 12 },
|
||||
[4] = { .tmplwm = 125, .tmphwm = 130, .dcoffpercent = 100,
|
||||
.pout_reduction_db = 12 },
|
||||
},
|
||||
[ATH12K_TT_CFG_IDX_XFEM] = {
|
||||
[0] = { .tmplwm = -100, .tmphwm = 105, .dcoffpercent = 0,
|
||||
.pout_reduction_db = 0 },
|
||||
[1] = { .tmplwm = 100, .tmphwm = 110, .dcoffpercent = 0,
|
||||
.pout_reduction_db = 0 },
|
||||
[2] = { .tmplwm = 105, .tmphwm = 115, .dcoffpercent = 50,
|
||||
.pout_reduction_db = 0 },
|
||||
[3] = { .tmplwm = 110, .tmphwm = 120, .dcoffpercent = 90,
|
||||
.pout_reduction_db = 0 },
|
||||
[4] = { .tmplwm = 115, .tmphwm = 120, .dcoffpercent = 100,
|
||||
.pout_reduction_db = 0 },
|
||||
},
|
||||
};
|
||||
|
||||
static enum ath12k_thermal_cfg_idx ath12k_thermal_cfg_index(struct ath12k *ar)
|
||||
{
|
||||
if (test_bit(WMI_TLV_SERVICE_IS_TARGET_IPA, ar->ab->wmi_ab.svc_map))
|
||||
return ATH12K_TT_CFG_IDX_IPA;
|
||||
|
||||
return ATH12K_TT_CFG_IDX_XFEM;
|
||||
}
|
||||
|
||||
int ath12k_thermal_throttling_config_default(struct ath12k *ar)
|
||||
{
|
||||
struct ath12k_wmi_thermal_mitigation_arg param = {};
|
||||
int ret;
|
||||
|
||||
if (test_bit(WMI_TLV_SERVICE_THERM_THROT_5_LEVELS, ar->ab->wmi_ab.svc_map))
|
||||
param.num_levels = ENHANCED_THERMAL_LEVELS;
|
||||
else
|
||||
param.num_levels = THERMAL_LEVELS;
|
||||
|
||||
param.levelconf = ar->thermal.tt_level_configs;
|
||||
|
||||
ret = ath12k_wmi_send_thermal_mitigation_cmd(ar, ¶m);
|
||||
if (ret)
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to send thermal mitigation cmd for default config: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath12k_thermal_init_configs(struct ath12k *ar)
|
||||
{
|
||||
enum ath12k_thermal_cfg_idx cfg_idx;
|
||||
|
||||
cfg_idx = ath12k_thermal_cfg_index(ar);
|
||||
ar->thermal.tt_level_configs = &tt_level_configs[cfg_idx][0];
|
||||
}
|
||||
|
||||
static int
|
||||
ath12k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
*state = ATH12K_THERMAL_THROTTLE_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath12k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct ath12k *ar = cdev->devdata;
|
||||
|
||||
mutex_lock(&ar->thermal.lock);
|
||||
*state = ar->thermal.throttle_state;
|
||||
mutex_unlock(&ar->thermal.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath12k_thermal_set_throttling(struct ath12k *ar, u32 throttle_state)
|
||||
{
|
||||
struct ath12k_wmi_thermal_mitigation_arg param = {};
|
||||
struct ath12k_wmi_tt_level_config_param cfg = {};
|
||||
int ret;
|
||||
|
||||
param.num_levels = 1;
|
||||
cfg.dcoffpercent = throttle_state;
|
||||
param.levelconf = &cfg;
|
||||
|
||||
ret = ath12k_wmi_send_thermal_mitigation_cmd(ar, ¶m);
|
||||
if (ret)
|
||||
ath12k_warn(ar->ab, "failed to send thermal mitigation cmd: %d\n",
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
ath12k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long throttle_state)
|
||||
{
|
||||
struct ath12k *ar = cdev->devdata;
|
||||
|
||||
if (throttle_state > ATH12K_THERMAL_THROTTLE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
scoped_guard(mutex, &ar->thermal.lock) {
|
||||
if (ar->thermal.throttle_state == throttle_state)
|
||||
return 0;
|
||||
ar->thermal.throttle_state = throttle_state;
|
||||
}
|
||||
|
||||
if (throttle_state == 0)
|
||||
return ath12k_thermal_throttling_config_default(ar);
|
||||
|
||||
return ath12k_thermal_set_throttling(ar, throttle_state);
|
||||
}
|
||||
|
||||
static const struct thermal_cooling_device_ops ath12k_thermal_ops = {
|
||||
.get_max_state = ath12k_thermal_get_max_throttle_state,
|
||||
.get_cur_state = ath12k_thermal_get_cur_throttle_state,
|
||||
.set_cur_state = ath12k_thermal_set_cur_throttle_state,
|
||||
};
|
||||
|
||||
static ssize_t ath12k_thermal_temp_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
|
@ -66,59 +197,108 @@ static struct attribute *ath12k_hwmon_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(ath12k_hwmon);
|
||||
|
||||
static int ath12k_thermal_setup_radio(struct ath12k_base *ab, int i)
|
||||
{
|
||||
char pdev_name[20];
|
||||
struct ath12k *ar;
|
||||
int ret;
|
||||
|
||||
ar = ab->pdevs[i].ar;
|
||||
if (!ar)
|
||||
return 0;
|
||||
|
||||
ar->thermal.cdev =
|
||||
thermal_cooling_device_register("ath12k_thermal", ar,
|
||||
&ath12k_thermal_ops);
|
||||
if (IS_ERR(ar->thermal.cdev)) {
|
||||
ret = PTR_ERR(ar->thermal.cdev);
|
||||
ar->thermal.cdev = NULL;
|
||||
ath12k_err(ar->ab, "failed to register cooling device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
scnprintf(pdev_name, sizeof(pdev_name), "cooling_device%u",
|
||||
ar->hw_link_id);
|
||||
|
||||
ret = sysfs_create_link(&ar->ah->hw->wiphy->dev.kobj,
|
||||
&ar->thermal.cdev->device.kobj, pdev_name);
|
||||
if (ret) {
|
||||
ath12k_err(ab, "failed to create cooling device symlink: %d\n",
|
||||
ret);
|
||||
goto unregister_cdev;
|
||||
}
|
||||
|
||||
ar->thermal.hwmon_dev =
|
||||
hwmon_device_register_with_groups(&ar->ah->hw->wiphy->dev,
|
||||
"ath12k_hwmon", ar,
|
||||
ath12k_hwmon_groups);
|
||||
if (IS_ERR(ar->thermal.hwmon_dev)) {
|
||||
ret = PTR_ERR(ar->thermal.hwmon_dev);
|
||||
ar->thermal.hwmon_dev = NULL;
|
||||
ath12k_err(ar->ab, "failed to register hwmon device: %d\n",
|
||||
ret);
|
||||
goto remove_sysfs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
remove_sysfs:
|
||||
sysfs_remove_link(&ar->ah->hw->wiphy->dev.kobj, pdev_name);
|
||||
unregister_cdev:
|
||||
thermal_cooling_device_unregister(ar->thermal.cdev);
|
||||
ar->thermal.cdev = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath12k_thermal_cleanup_radio(struct ath12k_base *ab, int i)
|
||||
{
|
||||
char pdev_name[20];
|
||||
struct ath12k *ar;
|
||||
|
||||
ar = ab->pdevs[i].ar;
|
||||
if (!ar)
|
||||
return;
|
||||
|
||||
hwmon_device_unregister(ar->thermal.hwmon_dev);
|
||||
ar->thermal.hwmon_dev = NULL;
|
||||
|
||||
scnprintf(pdev_name, sizeof(pdev_name), "cooling_device%u",
|
||||
ar->hw_link_id);
|
||||
sysfs_remove_link(&ar->ah->hw->wiphy->dev.kobj, pdev_name);
|
||||
|
||||
thermal_cooling_device_unregister(ar->thermal.cdev);
|
||||
ar->thermal.cdev = NULL;
|
||||
}
|
||||
|
||||
int ath12k_thermal_register(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k *ar;
|
||||
int i, j, ret;
|
||||
int i, ret;
|
||||
|
||||
if (!IS_REACHABLE(CONFIG_HWMON))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ab->num_radios; i++) {
|
||||
ar = ab->pdevs[i].ar;
|
||||
if (!ar)
|
||||
continue;
|
||||
|
||||
ar->thermal.hwmon_dev =
|
||||
hwmon_device_register_with_groups(&ar->ah->hw->wiphy->dev,
|
||||
"ath12k_hwmon", ar,
|
||||
ath12k_hwmon_groups);
|
||||
if (IS_ERR(ar->thermal.hwmon_dev)) {
|
||||
ret = PTR_ERR(ar->thermal.hwmon_dev);
|
||||
ar->thermal.hwmon_dev = NULL;
|
||||
ath12k_err(ar->ab, "failed to register hwmon device: %d\n",
|
||||
ret);
|
||||
for (j = i - 1; j >= 0; j--) {
|
||||
ar = ab->pdevs[j].ar;
|
||||
if (!ar)
|
||||
continue;
|
||||
|
||||
hwmon_device_unregister(ar->thermal.hwmon_dev);
|
||||
ar->thermal.hwmon_dev = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
ret = ath12k_thermal_setup_radio(ab, i);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
for (i--; i >= 0; i--)
|
||||
ath12k_thermal_cleanup_radio(ab, i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath12k_thermal_unregister(struct ath12k_base *ab)
|
||||
{
|
||||
struct ath12k *ar;
|
||||
int i;
|
||||
|
||||
if (!IS_REACHABLE(CONFIG_HWMON))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ab->num_radios; i++) {
|
||||
ar = ab->pdevs[i].ar;
|
||||
if (!ar)
|
||||
continue;
|
||||
|
||||
if (ar->thermal.hwmon_dev) {
|
||||
hwmon_device_unregister(ar->thermal.hwmon_dev);
|
||||
ar->thermal.hwmon_dev = NULL;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < ab->num_radios; i++)
|
||||
ath12k_thermal_cleanup_radio(ab, i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,20 +7,41 @@
|
|||
#ifndef _ATH12K_THERMAL_
|
||||
#define _ATH12K_THERMAL_
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define ATH12K_THERMAL_SYNC_TIMEOUT_HZ (5 * HZ)
|
||||
|
||||
#define ATH12K_THERMAL_DEFAULT_DUTY_CYCLE 100
|
||||
#define ATH12K_THERMAL_THROTTLE_MAX 100
|
||||
|
||||
enum ath12k_thermal_cfg_idx {
|
||||
/* Internal Power Amplifier Device */
|
||||
ATH12K_TT_CFG_IDX_IPA,
|
||||
/* External Power Amplifier Device or External Front End Module */
|
||||
ATH12K_TT_CFG_IDX_XFEM,
|
||||
ATH12K_TT_CFG_IDX_MAX,
|
||||
};
|
||||
|
||||
struct ath12k_thermal {
|
||||
struct completion wmi_sync;
|
||||
|
||||
/* temperature value in Celsius degree protected by data_lock. */
|
||||
int temperature;
|
||||
struct device *hwmon_dev;
|
||||
const struct ath12k_wmi_tt_level_config_param *tt_level_configs;
|
||||
struct thermal_cooling_device *cdev;
|
||||
/* Serialize thermal operations and hwmon reads */
|
||||
struct mutex lock;
|
||||
u32 throttle_state;
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_THERMAL)
|
||||
int ath12k_thermal_register(struct ath12k_base *ab);
|
||||
void ath12k_thermal_unregister(struct ath12k_base *ab);
|
||||
void ath12k_thermal_event_temperature(struct ath12k *ar, int temperature);
|
||||
int ath12k_thermal_throttling_config_default(struct ath12k *ar);
|
||||
void ath12k_thermal_init_configs(struct ath12k *ar);
|
||||
int ath12k_thermal_set_throttling(struct ath12k *ar, u32 throttle_state);
|
||||
#else
|
||||
static inline int ath12k_thermal_register(struct ath12k_base *ab)
|
||||
{
|
||||
|
|
@ -36,5 +57,19 @@ static inline void ath12k_thermal_event_temperature(struct ath12k *ar,
|
|||
{
|
||||
}
|
||||
|
||||
static inline int ath12k_thermal_throttling_config_default(struct ath12k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath12k_thermal_init_configs(struct ath12k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ath12k_thermal_set_throttling(struct ath12k *ar,
|
||||
u32 throttle_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* _ATH12K_THERMAL_ */
|
||||
|
|
|
|||
|
|
@ -234,6 +234,68 @@ static const int ath12k_hw_mode_pri_map[] = {
|
|||
PRIMAP(WMI_HOST_HW_MODE_MAX),
|
||||
};
|
||||
|
||||
/*
|
||||
* Interference bitmap transform maps used by
|
||||
* ath12k_wmi_transform_interference_bitmap().
|
||||
*
|
||||
* Firmware reports bitmap bits in a primary-based order where:
|
||||
* - bit 0 is always the primary 20 MHz segment,
|
||||
* - bit 1 is the adjacent 20 MHz in the same 40 MHz block,
|
||||
* - bit 2 is the lower 20 MHz segment of the adjacent 40 MHz segment
|
||||
* - bit 3 is the higher 20 MHz segment of the adjacent 40 MHz segment
|
||||
* - remaining bits continue outward in 80/160/320 MHz groups.
|
||||
*
|
||||
* cfg80211 userspace notification expects absolute frequency order where:
|
||||
* - bit 0 is the lowest-frequency 20 MHz segment in the current chandef,
|
||||
* - bit N increases monotonically toward higher frequency.
|
||||
*
|
||||
* For each bandwidth-specific map:
|
||||
* - row index = primary 20 MHz index in absolute (low->high) order,
|
||||
* - column index = source bit position from firmware bitmap,
|
||||
* - value = destination bit position in absolute order bitmap.
|
||||
*
|
||||
* Example for 80 MHz: if primary index is 2 (third 20 MHz chunk from low
|
||||
* frequency), row intf_map_80[2] = { 2, 3, 0, 1 } means firmware bits {0,1,2,3}
|
||||
* are remapped to destination bits {2,3,0,1} before notifying cfg80211.
|
||||
*/
|
||||
|
||||
static const int intf_map_80[4][4] = {
|
||||
{ 0, 1, 2, 3 },
|
||||
{ 1, 0, 2, 3 },
|
||||
{ 2, 3, 0, 1 },
|
||||
{ 3, 2, 0, 1 }
|
||||
};
|
||||
|
||||
static const int intf_map_160[8][8] = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 1, 0, 2, 3, 4, 5, 6, 7 },
|
||||
{ 2, 3, 0, 1, 4, 5, 6, 7 },
|
||||
{ 3, 2, 0, 1, 4, 5, 6, 7 },
|
||||
{ 4, 5, 6, 7, 0, 1, 2, 3 },
|
||||
{ 5, 4, 6, 7, 0, 1, 2, 3 },
|
||||
{ 6, 7, 4, 5, 0, 1, 2, 3 },
|
||||
{ 7, 6, 4, 5, 0, 1, 2, 3 }
|
||||
};
|
||||
|
||||
static const int intf_map_320[16][16] = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 2, 3, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 3, 2, 0, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 4, 5, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 5, 4, 6, 7, 0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 6, 7, 4, 5, 0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 7, 6, 4, 5, 0, 1, 2, 3, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
{ 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 9, 8, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 10, 11, 8, 9, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 11, 10, 8, 9, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 12, 13, 14, 15, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 13, 12, 14, 15, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 14, 15, 12, 13, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||
{ 15, 14, 12, 13, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7 }
|
||||
};
|
||||
|
||||
static int
|
||||
ath12k_wmi_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,
|
||||
int (*iter)(struct ath12k_base *ab, u16 tag, u16 len,
|
||||
|
|
@ -3380,6 +3442,75 @@ int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ath12k_wmi_send_thermal_mitigation_cmd(struct ath12k *ar,
|
||||
struct ath12k_wmi_thermal_mitigation_arg *arg)
|
||||
{
|
||||
struct ath12k_wmi_therm_throt_level_config_param *lvl_conf;
|
||||
struct ath12k_wmi_therm_throt_config_request_cmd *cmd;
|
||||
struct ath12k_wmi_pdev *wmi = ar->wmi;
|
||||
struct wmi_tlv *tlv;
|
||||
struct sk_buff *skb;
|
||||
int i, ret, len;
|
||||
|
||||
len = sizeof(*cmd) + TLV_HDR_SIZE + (arg->num_levels * sizeof(*lvl_conf));
|
||||
|
||||
skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd = (struct ath12k_wmi_therm_throt_config_request_cmd *)skb->data;
|
||||
cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_THERM_THROT_CONFIG_REQUEST,
|
||||
sizeof(*cmd));
|
||||
cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);
|
||||
cmd->enable = cpu_to_le32(1);
|
||||
cmd->dc = cpu_to_le32(100);
|
||||
cmd->dc_per_event = cpu_to_le32(0xffffffff);
|
||||
cmd->therm_throt_levels = cpu_to_le32(arg->num_levels);
|
||||
|
||||
tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd));
|
||||
tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT,
|
||||
arg->num_levels * sizeof(*lvl_conf));
|
||||
|
||||
lvl_conf = (struct ath12k_wmi_therm_throt_level_config_param *)tlv->value;
|
||||
|
||||
for (i = 0; i < arg->num_levels; i++) {
|
||||
lvl_conf->tlv_header =
|
||||
ath12k_wmi_tlv_cmd_hdr(WMI_TAG_THERM_THROT_LEVEL_CONFIG_INFO,
|
||||
sizeof(*lvl_conf));
|
||||
|
||||
lvl_conf->temp_lwm = a_cpu_to_sle32(arg->levelconf[i].tmplwm);
|
||||
lvl_conf->temp_hwm = a_cpu_to_sle32(arg->levelconf[i].tmphwm);
|
||||
lvl_conf->dc_off_percent = cpu_to_le32(arg->levelconf[i].dcoffpercent);
|
||||
|
||||
if (test_bit(WMI_TLV_SERVICE_THERM_THROT_POUT_REDUCTION,
|
||||
ar->ab->wmi_ab.svc_map))
|
||||
lvl_conf->pout_reduction_25db =
|
||||
cpu_to_le32(arg->levelconf[i].pout_reduction_db);
|
||||
|
||||
if (test_bit(WMI_TLV_SERVICE_THERM_THROT_TX_CHAIN_MASK,
|
||||
ar->ab->wmi_ab.svc_map))
|
||||
lvl_conf->tx_chain_mask = cpu_to_le32(ar->cfg_tx_chainmask);
|
||||
|
||||
lvl_conf->duty_cycle = cpu_to_le32(ATH12K_THERMAL_DEFAULT_DUTY_CYCLE);
|
||||
lvl_conf++;
|
||||
}
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"WMI vdev set thermal throt pdev_id %u enable dc 100 dc_per_event 0xffffffff levels %d\n",
|
||||
ar->pdev->pdev_id, arg->num_levels);
|
||||
|
||||
ret = ath12k_wmi_cmd_send(wmi, skb, WMI_THERM_THROT_SET_CONF_CMDID);
|
||||
if (ret) {
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to send WMI_THERM_THROT_SET_CONF cmd: %d\n",
|
||||
ret);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
|
||||
struct wmi_11d_scan_start_arg *arg)
|
||||
{
|
||||
|
|
@ -4199,12 +4330,9 @@ int ath12k_wmi_pdev_lro_cfg(struct ath12k *ar,
|
|||
if (ret) {
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to send lro cfg req wmi cmd\n");
|
||||
goto err;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -4335,12 +4463,9 @@ int ath12k_wmi_vdev_spectral_conf(struct ath12k *ar,
|
|||
if (ret) {
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to send spectral scan config wmi cmd\n");
|
||||
goto err;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -4372,12 +4497,9 @@ int ath12k_wmi_vdev_spectral_enable(struct ath12k *ar, u32 vdev_id,
|
|||
if (ret) {
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to send spectral enable wmi cmd\n");
|
||||
goto err;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -4418,12 +4540,9 @@ int ath12k_wmi_pdev_dma_ring_cfg(struct ath12k *ar,
|
|||
if (ret) {
|
||||
ath12k_warn(ar->ab,
|
||||
"failed to send dma ring cfg req wmi cmd\n");
|
||||
goto err;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -8540,6 +8659,330 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
|
|||
ev->ctl_failsafe_status);
|
||||
}
|
||||
|
||||
static int
|
||||
ath12k_wmi_incumbent_signal_interference_subtlv_parser(struct ath12k_base *ab,
|
||||
u16 tag, u16 len,
|
||||
const void *ptr,
|
||||
void *data)
|
||||
{
|
||||
const struct ath12k_wmi_incumbent_signal_interference_params *info;
|
||||
struct ath12k_wmi_incumbent_signal_interference_arg *arg = data;
|
||||
|
||||
switch (tag) {
|
||||
case WMI_TAG_DCS_INCUMBENT_SIGNAL_INTERFERENCE_TYPE:
|
||||
if (len < sizeof(*info)) {
|
||||
ath12k_warn(ab,
|
||||
"DCS incumbent signal interference subtlv 0x%x invalid len %u\n",
|
||||
tag, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info = ptr;
|
||||
|
||||
arg->chan_width = le32_to_cpu(info->chan_width);
|
||||
arg->chan_freq = le32_to_cpu(info->chan_freq);
|
||||
arg->center_freq0 = le32_to_cpu(info->center_freq0);
|
||||
arg->center_freq1 = le32_to_cpu(info->center_freq1);
|
||||
arg->chan_bw_interference_bitmap =
|
||||
le32_to_cpu(info->chan_bw_interference_bitmap);
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"incumbent signal interference chan width %u freq %u center_freq0 %u center_freq1 %u bitmap 0x%x\n",
|
||||
arg->chan_width, arg->chan_freq,
|
||||
arg->center_freq0, arg->center_freq1,
|
||||
arg->chan_bw_interference_bitmap);
|
||||
break;
|
||||
default:
|
||||
ath12k_warn(ab, "Received invalid tag 0x%x for WMI DCS interference in subtlvs\n",
|
||||
tag);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath12k_wmi_dcs_interference_event_parser(struct ath12k_base *ab,
|
||||
u16 tag, u16 len,
|
||||
const void *ptr, void *data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
switch (tag) {
|
||||
case WMI_TAG_DCS_INTERFERENCE_EVENT:
|
||||
/* Fixed param should already be processed */
|
||||
break;
|
||||
case WMI_TAG_ARRAY_STRUCT:
|
||||
ret = ath12k_wmi_tlv_iter(ab, ptr, len,
|
||||
ath12k_wmi_incumbent_signal_interference_subtlv_parser,
|
||||
data);
|
||||
break;
|
||||
default:
|
||||
ath12k_warn(ab, "Received invalid tag 0x%x for WMI DCS interference event\n",
|
||||
tag);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
ath12k_wmi_validate_interference_info(struct ath12k *ar,
|
||||
struct ath12k_wmi_incumbent_signal_interference_arg *info)
|
||||
{
|
||||
switch (info->chan_width) {
|
||||
case WMI_CHAN_WIDTH_20:
|
||||
if (info->chan_bw_interference_bitmap > ATH12K_WMI_DCS_SEG_PRI20) {
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"DCS interference event received with wrong chan width bmap 0x%x for 20 MHz",
|
||||
info->chan_bw_interference_bitmap);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case WMI_CHAN_WIDTH_40:
|
||||
if (info->chan_bw_interference_bitmap > (ATH12K_WMI_DCS_SEG_PRI20 |
|
||||
ATH12K_WMI_DCS_SEG_SEC20)) {
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"DCS interference event received with wrong chan width bmap 0x%x for 40 MHz",
|
||||
info->chan_bw_interference_bitmap);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case WMI_CHAN_WIDTH_80:
|
||||
if (info->chan_bw_interference_bitmap > (ATH12K_WMI_DCS_SEG_PRI20 |
|
||||
ATH12K_WMI_DCS_SEG_SEC20 |
|
||||
ATH12K_WMI_DCS_SEG_SEC40)) {
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"DCS interference event received with wrong chan width bmap 0x%x for 80 MHz",
|
||||
info->chan_bw_interference_bitmap);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case WMI_CHAN_WIDTH_160:
|
||||
if (info->chan_bw_interference_bitmap > (ATH12K_WMI_DCS_SEG_PRI20 |
|
||||
ATH12K_WMI_DCS_SEG_SEC20 |
|
||||
ATH12K_WMI_DCS_SEG_SEC40 |
|
||||
ATH12K_WMI_DCS_SEG_SEC80)) {
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"DCS interference event received with wrong chan width bmap 0x%x for 160 MHz",
|
||||
info->chan_bw_interference_bitmap);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case WMI_CHAN_WIDTH_320:
|
||||
if (info->chan_bw_interference_bitmap > (ATH12K_WMI_DCS_SEG_PRI20 |
|
||||
ATH12K_WMI_DCS_SEG_SEC20 |
|
||||
ATH12K_WMI_DCS_SEG_SEC40 |
|
||||
ATH12K_WMI_DCS_SEG_SEC80 |
|
||||
ATH12K_WMI_DCS_SEG_SEC160)) {
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"DCS interference event received with wrong chan width bmap 0x%x for 320 MHz",
|
||||
info->chan_bw_interference_bitmap);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"DCS interference event received with unknown channel width %u",
|
||||
info->chan_width);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32
|
||||
ath12k_wmi_transform_interference_bitmap(int input_bitmap,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
u16 output_bits[ATH12K_MAX_20MHZ_SEGMENTS] = {};
|
||||
u16 input_bits[ATH12K_MAX_20MHZ_SEGMENTS] = {};
|
||||
u32 start_freq, segment_freq;
|
||||
int primary_index = -1;
|
||||
u32 output_bitmap = 0;
|
||||
u16 num_sub_chans;
|
||||
int bandwidth;
|
||||
|
||||
bandwidth = nl80211_chan_width_to_mhz(chandef->width);
|
||||
if (bandwidth < 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Firmware reports bit 0 as primary 20 MHz irrespective of absolute
|
||||
* frequency position. Convert to standardized lowest-to-highest 20 MHz
|
||||
* ordering expected by cfg80211/mac80211 userspace consumers.
|
||||
*/
|
||||
num_sub_chans = bandwidth / 20;
|
||||
start_freq = (chandef->center_freq1 - bandwidth / 2) + 10;
|
||||
|
||||
for (int i = 0; i < ATH12K_MAX_20MHZ_SEGMENTS; i++) {
|
||||
segment_freq = start_freq + (i * 20);
|
||||
if (segment_freq == chandef->chan->center_freq) {
|
||||
primary_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (primary_index == -1)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < ATH12K_MAX_20MHZ_SEGMENTS; ++i)
|
||||
input_bits[i] = BIT(i) & input_bitmap;
|
||||
|
||||
for (int i = 0; i < num_sub_chans; ++i) {
|
||||
int src = i, dst = i;
|
||||
|
||||
switch (bandwidth) {
|
||||
case 40:
|
||||
if (primary_index == 1)
|
||||
dst = 1 - i;
|
||||
break;
|
||||
case 80:
|
||||
dst = intf_map_80[primary_index][i];
|
||||
break;
|
||||
case 160:
|
||||
dst = intf_map_160[primary_index][i];
|
||||
break;
|
||||
case 320:
|
||||
dst = intf_map_320[primary_index][i];
|
||||
break;
|
||||
}
|
||||
output_bits[dst] = input_bits[src];
|
||||
}
|
||||
|
||||
for (int i = 0; i < ATH12K_MAX_20MHZ_SEGMENTS; ++i)
|
||||
output_bitmap |= output_bits[i] ? BIT(i) : 0;
|
||||
|
||||
return output_bitmap;
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_process_incumbent_signal_interference_evt(struct ath12k_base *ab,
|
||||
struct sk_buff *skb,
|
||||
const struct ath12k_wmi_intf_arg *intf_arg)
|
||||
{
|
||||
struct ath12k_wmi_incumbent_signal_interference_arg info = {};
|
||||
struct ath12k_incumbent_signal_interference *incumbent;
|
||||
struct ath12k_mac_get_any_chanctx_conf_arg arg;
|
||||
u32 transformed_intf_bitmap;
|
||||
struct ieee80211_hw *hw;
|
||||
struct ath12k *ar;
|
||||
int ret;
|
||||
|
||||
guard(rcu)();
|
||||
|
||||
ar = ath12k_mac_get_ar_by_pdev_id(ab, intf_arg->pdev_id);
|
||||
if (!ar) {
|
||||
ath12k_warn(ab, "incumbent signal interference detected on invalid pdev %d\n",
|
||||
intf_arg->pdev_id);
|
||||
return;
|
||||
}
|
||||
if (!ar->supports_6ghz) {
|
||||
ath12k_warn(ab, "pdev does not support 6 GHz, dropping DCS interference event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
incumbent = &ar->incumbent_signal_interference;
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
if (incumbent->handling_in_progress) {
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"incumbent signal interference handling ongoing, dropping DCS interference event");
|
||||
return;
|
||||
}
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,
|
||||
ath12k_wmi_dcs_interference_event_parser,
|
||||
&info);
|
||||
if (ret) {
|
||||
ath12k_warn(ab,
|
||||
"failed to parse incumbent signal interference TLV. Error %d\n",
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ath12k_wmi_validate_interference_info(ar, &info)) {
|
||||
ath12k_warn(ab, "invalid DCS incumbent signal interference TLV - Skipping event");
|
||||
return;
|
||||
}
|
||||
|
||||
arg.ar = ar;
|
||||
arg.chanctx_conf = NULL;
|
||||
hw = ath12k_ar_to_hw(ar);
|
||||
ieee80211_iter_chan_contexts_atomic(hw,
|
||||
ath12k_mac_get_any_chanctx_conf_iter,
|
||||
&arg);
|
||||
if (!arg.chanctx_conf) {
|
||||
ath12k_warn(ab, "failed to find valid chanctx_conf in incumbent signal intf detected event\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.chan_freq != arg.chanctx_conf->def.chan->center_freq) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"dcs interference event received with wrong channel %d (ctx freq %d)",
|
||||
info.chan_freq, arg.chanctx_conf->def.chan->center_freq);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
incumbent->center_freq = arg.chanctx_conf->def.chan->center_freq;
|
||||
incumbent->width = arg.chanctx_conf->def.width;
|
||||
incumbent->chan_bw_interference_bitmap = info.chan_bw_interference_bitmap;
|
||||
incumbent->handling_in_progress = true;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
transformed_intf_bitmap =
|
||||
ath12k_wmi_transform_interference_bitmap(info.chan_bw_interference_bitmap,
|
||||
&arg.chanctx_conf->def);
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"incumbent signal interference bitmap 0x%x (transformed 0x%x)\n",
|
||||
info.chan_bw_interference_bitmap, transformed_intf_bitmap);
|
||||
cfg80211_incumbent_signal_notify(hw->wiphy,
|
||||
&arg.chanctx_conf->def,
|
||||
transformed_intf_bitmap,
|
||||
GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_dcs_interference_event(struct ath12k_base *ab,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct ath12k_wmi_dcs_interference_ev_fixed_params *dcs_intf_ev;
|
||||
struct ath12k_wmi_intf_arg dcs_intf_arg;
|
||||
const struct wmi_tlv *tlv;
|
||||
u16 tlv_tag;
|
||||
u8 *ptr;
|
||||
|
||||
if (skb->len < (sizeof(*dcs_intf_ev) + TLV_HDR_SIZE)) {
|
||||
ath12k_warn(ab, "DCS interference event is of incorrect length\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = skb->data;
|
||||
tlv = (struct wmi_tlv *)ptr;
|
||||
tlv_tag = le32_get_bits(tlv->header, WMI_TLV_TAG);
|
||||
ptr += sizeof(*tlv);
|
||||
|
||||
if (tlv_tag != WMI_TAG_DCS_INTERFERENCE_EVENT) {
|
||||
ath12k_warn(ab, "DCS interference event received with wrong tag\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dcs_intf_ev = (struct ath12k_wmi_dcs_interference_ev_fixed_params *)ptr;
|
||||
|
||||
dcs_intf_arg.interference_type =
|
||||
le32_to_cpu(dcs_intf_ev->interference_type);
|
||||
dcs_intf_arg.pdev_id = le32_to_cpu(dcs_intf_ev->pdev_id);
|
||||
|
||||
if (dcs_intf_arg.interference_type ==
|
||||
ATH12K_WMI_DCS_INCUMBENT_SIGNAL_INTERFERENCE) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"incumbent signal interference (Type %u) detected on pdev %u.",
|
||||
dcs_intf_arg.interference_type,
|
||||
dcs_intf_arg.pdev_id);
|
||||
ath12k_wmi_process_incumbent_signal_interference_evt(ab, skb,
|
||||
&dcs_intf_arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab,
|
||||
const struct ath12k_wmi_pdev_csa_event *ev,
|
||||
|
|
@ -8762,6 +9205,42 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,
|
|||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ath12k_wmi_thermal_throt_stats_event(struct ath12k_base *ab,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct wmi_therm_throt_stats_event *ev;
|
||||
struct ath12k *ar;
|
||||
const void **tb;
|
||||
|
||||
tb = ath12k_wmi_tlv_parse(ab, skb);
|
||||
if (IS_ERR(tb)) {
|
||||
ath12k_err(ab, "failed to parse thermal throttling stats tlv: %ld\n",
|
||||
PTR_ERR(tb));
|
||||
return;
|
||||
}
|
||||
|
||||
ev = tb[WMI_TAG_THERM_THROT_STATS_EVENT];
|
||||
if (!ev) {
|
||||
ath12k_err(ab, "failed to fetch thermal throt stats ev\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ar = ath12k_mac_get_ar_by_pdev_id(ab, le32_to_cpu(ev->pdev_id));
|
||||
if (!ar) {
|
||||
ath12k_warn(ab, "received thermal_throt_stats in invalid pdev %u\n",
|
||||
le32_to_cpu(ev->pdev_id));
|
||||
rcu_read_unlock();
|
||||
return;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
ath12k_dbg(ab, ATH12K_DBG_WMI,
|
||||
"thermal stats ev level %u pdev_id %u temp %u throt_levels %u\n",
|
||||
le32_to_cpu(ev->level), le32_to_cpu(ev->pdev_id),
|
||||
le32_to_cpu(ev->temp), le32_to_cpu(ev->therm_throt_levels));
|
||||
}
|
||||
|
||||
static void ath12k_fils_discovery_event(struct ath12k_base *ab,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -9811,6 +10290,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
case WMI_PDEV_TEMPERATURE_EVENTID:
|
||||
ath12k_wmi_pdev_temperature_event(ab, skb);
|
||||
break;
|
||||
case WMI_THERM_THROT_STATS_EVENTID:
|
||||
ath12k_wmi_thermal_throt_stats_event(ab, skb);
|
||||
break;
|
||||
case WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID:
|
||||
ath12k_wmi_pdev_dma_ring_buf_release_event(ab, skb);
|
||||
break;
|
||||
|
|
@ -9865,6 +10347,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
|
|||
case WMI_OBSS_COLOR_COLLISION_DETECTION_EVENTID:
|
||||
ath12k_wmi_obss_color_collision_event(ab, skb);
|
||||
break;
|
||||
case WMI_DCS_INTERFERENCE_EVENTID:
|
||||
ath12k_wmi_dcs_interference_event(ab, skb);
|
||||
break;
|
||||
/* add Unsupported events (rare) here */
|
||||
case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
|
||||
case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
|
||||
|
|
@ -10083,6 +10568,42 @@ int ath12k_wmi_send_tpc_stats_request(struct ath12k *ar,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ath12k_wmi_simulate_incumbent_signal_interference(struct ath12k *ar,
|
||||
u32 chan_bw_interference_bitmap)
|
||||
{
|
||||
struct wmi_unit_test_arg wmi_ut = {};
|
||||
struct ath12k_link_vif *arvif;
|
||||
struct ath12k_vif *ahvif;
|
||||
bool arvif_found = false;
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ahvif = arvif->ahvif;
|
||||
if (arvif->is_started && ahvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
||||
arvif_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arvif_found)
|
||||
return -EINVAL;
|
||||
|
||||
wmi_ut.args[ATH12K_WMI_INCUMBENT_SIGNAL_TEST_INTF] =
|
||||
ATH12K_WMI_UNIT_TEST_INCUMBENT_SIGNAL_INTF_TYPE;
|
||||
wmi_ut.args[ATH12K_WMI_INCUMBENT_SIGNAL_TEST_BITMAP] =
|
||||
chan_bw_interference_bitmap;
|
||||
|
||||
wmi_ut.vdev_id = arvif->vdev_id;
|
||||
wmi_ut.module_id = ATH12K_WMI_INCUMBENT_SIGNAL_UNIT_TEST_MODULE;
|
||||
wmi_ut.num_args = ATH12K_WMI_INCUMBENT_SIGNAL_MAX_TEST_ARGS;
|
||||
wmi_ut.diag_token = ATH12K_WMI_INCUMBENT_SIGNAL_UNIT_TEST_TOKEN;
|
||||
|
||||
ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
|
||||
"Triggering incumbent signal interference simulation, interference bitmap: 0x%x\n",
|
||||
chan_bw_interference_bitmap);
|
||||
|
||||
return ath12k_wmi_send_unit_test_cmd(ar, &wmi_ut);
|
||||
}
|
||||
|
||||
int ath12k_wmi_connect(struct ath12k_base *ab)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -10874,10 +11395,9 @@ int ath12k_wmi_mlo_setup(struct ath12k *ar, struct wmi_mlo_setup_arg *mlo_params
|
|||
ath12k_warn(ar->ab, "failed to submit WMI_MLO_SETUP_CMDID command: %d\n",
|
||||
ret);
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath12k_wmi_mlo_ready(struct ath12k *ar)
|
||||
|
|
@ -10902,10 +11422,9 @@ int ath12k_wmi_mlo_ready(struct ath12k *ar)
|
|||
ath12k_warn(ar->ab, "failed to submit WMI_MLO_READY_CMDID command: %d\n",
|
||||
ret);
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath12k_wmi_mlo_teardown(struct ath12k *ar)
|
||||
|
|
@ -10931,10 +11450,9 @@ int ath12k_wmi_mlo_teardown(struct ath12k *ar)
|
|||
ath12k_warn(ar->ab, "failed to submit WMI MLO teardown command: %d\n",
|
||||
ret);
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ath12k_wmi_supports_6ghz_cc_ext(struct ath12k *ar)
|
||||
|
|
@ -10997,10 +11515,9 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
|
|||
if (ret) {
|
||||
ath12k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n");
|
||||
dev_kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
|||
|
|
@ -870,6 +870,7 @@ enum wmi_tlv_event_id {
|
|||
WMI_READ_DATA_FROM_FLASH_EVENTID,
|
||||
WMI_REPORT_RX_AGGR_FAILURE_EVENTID,
|
||||
WMI_PKGID_EVENTID,
|
||||
WMI_THERM_THROT_STATS_EVENTID,
|
||||
WMI_GPIO_INPUT_EVENTID = WMI_TLV_CMD(WMI_GRP_GPIO),
|
||||
WMI_UPLOADH_EVENTID,
|
||||
WMI_CAPTUREH_EVENTID,
|
||||
|
|
@ -2014,7 +2015,7 @@ enum wmi_tlv_tag {
|
|||
WMI_TAG_VDEV_CH_POWER_INFO,
|
||||
WMI_TAG_MLO_LINK_SET_ACTIVE_CMD = 0x3BE,
|
||||
WMI_TAG_EHT_RATE_SET = 0x3C4,
|
||||
WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5,
|
||||
WMI_TAG_DCS_INCUMBENT_SIGNAL_INTERFERENCE_TYPE = 0x3C5,
|
||||
WMI_TAG_MLO_TX_SEND_PARAMS,
|
||||
WMI_TAG_MLO_PARTNER_LINK_PARAMS,
|
||||
WMI_TAG_MLO_PARTNER_LINK_PARAMS_PEER_ASSOC,
|
||||
|
|
@ -2259,6 +2260,7 @@ enum wmi_tlv_service {
|
|||
WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
|
||||
WMI_TLV_SERVICE_EXT2_MSG = 220,
|
||||
WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT = 244,
|
||||
WMI_TLV_SERVICE_5_9GHZ_SUPPORT = 247,
|
||||
WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249,
|
||||
WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253,
|
||||
|
||||
|
|
@ -2268,11 +2270,17 @@ enum wmi_tlv_service {
|
|||
|
||||
WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
|
||||
|
||||
WMI_TLV_SERVICE_DCS_INCUMBENT_SIGNAL_INTERFERENCE_SUPPORT = 286,
|
||||
|
||||
WMI_TLV_SERVICE_11BE = 289,
|
||||
|
||||
WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361,
|
||||
|
||||
WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365,
|
||||
WMI_TLV_SERVICE_THERM_THROT_POUT_REDUCTION = 410,
|
||||
WMI_TLV_SERVICE_IS_TARGET_IPA = 425,
|
||||
WMI_TLV_SERVICE_THERM_THROT_TX_CHAIN_MASK = 426,
|
||||
WMI_TLV_SERVICE_THERM_THROT_5_LEVELS = 429,
|
||||
WMI_TLV_SERVICE_ETH_OFFLOAD = 461,
|
||||
|
||||
WMI_MAX_EXT2_SERVICE,
|
||||
|
|
@ -3586,7 +3594,6 @@ struct ath12k_wmi_scan_req_arg {
|
|||
u32 num_bssid;
|
||||
u32 num_ssids;
|
||||
u32 n_probes;
|
||||
u32 *chan_list;
|
||||
u32 notify_scan_events;
|
||||
struct cfg80211_ssid ssid[WLAN_SCAN_MAX_NUM_SSID];
|
||||
struct ath12k_wmi_mac_addr_params bssid_list[WLAN_SCAN_MAX_NUM_BSSID];
|
||||
|
|
@ -3595,6 +3602,7 @@ struct ath12k_wmi_scan_req_arg {
|
|||
u32 num_hint_bssid;
|
||||
struct ath12k_wmi_hint_short_ssid_arg hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID];
|
||||
struct ath12k_wmi_hint_bssid_arg hint_bssid[WLAN_SCAN_MAX_HINT_BSSID];
|
||||
u32 chan_list[] __counted_by(num_chan);
|
||||
};
|
||||
|
||||
struct wmi_ssid_arg {
|
||||
|
|
@ -4120,6 +4128,49 @@ enum set_init_cc_flags {
|
|||
ALPHA_IS_SET,
|
||||
};
|
||||
|
||||
struct wmi_therm_throt_stats_event {
|
||||
__le32 pdev_id;
|
||||
__le32 temp;
|
||||
__le32 level;
|
||||
__le32 therm_throt_levels;
|
||||
} __packed;
|
||||
|
||||
#define THERMAL_LEVELS 4
|
||||
#define ENHANCED_THERMAL_LEVELS 5
|
||||
|
||||
struct ath12k_wmi_tt_level_config_param {
|
||||
s32 tmplwm;
|
||||
s32 tmphwm;
|
||||
u32 dcoffpercent;
|
||||
u32 pout_reduction_db;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_therm_throt_config_request_cmd {
|
||||
__le32 tlv_header;
|
||||
__le32 pdev_id;
|
||||
__le32 enable;
|
||||
__le32 dc;
|
||||
/* After how many duty cycles the firmware sends stats to host */
|
||||
__le32 dc_per_event;
|
||||
__le32 therm_throt_levels;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_therm_throt_level_config_param {
|
||||
__le32 tlv_header;
|
||||
a_sle32 temp_lwm;
|
||||
a_sle32 temp_hwm;
|
||||
__le32 dc_off_percent;
|
||||
__le32 prio;
|
||||
__le32 pout_reduction_25db;
|
||||
__le32 tx_chain_mask;
|
||||
__le32 duty_cycle;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_thermal_mitigation_arg {
|
||||
int num_levels;
|
||||
const struct ath12k_wmi_tt_level_config_param *levelconf;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_init_country_arg {
|
||||
union {
|
||||
u16 country_code;
|
||||
|
|
@ -4203,6 +4254,16 @@ enum dfs_test_args_idx {
|
|||
DFS_MAX_TEST_ARGS,
|
||||
};
|
||||
|
||||
#define ATH12K_WMI_INCUMBENT_SIGNAL_UNIT_TEST_MODULE 0x18
|
||||
#define ATH12K_WMI_INCUMBENT_SIGNAL_UNIT_TEST_TOKEN 0
|
||||
#define ATH12K_WMI_UNIT_TEST_INCUMBENT_SIGNAL_INTF_TYPE 1
|
||||
|
||||
enum ath12k_wmi_incumbent_signal_test_args_idx {
|
||||
ATH12K_WMI_INCUMBENT_SIGNAL_TEST_INTF,
|
||||
ATH12K_WMI_INCUMBENT_SIGNAL_TEST_BITMAP,
|
||||
ATH12K_WMI_INCUMBENT_SIGNAL_MAX_TEST_ARGS,
|
||||
};
|
||||
|
||||
/* update if another test command requires more */
|
||||
#define WMI_UNIT_TEST_ARGS_MAX DFS_MAX_TEST_ARGS
|
||||
|
||||
|
|
@ -4487,6 +4548,62 @@ struct ath12k_wmi_pdev_radar_event {
|
|||
a_sle32 sidx;
|
||||
} __packed;
|
||||
|
||||
#define ATH12K_WMI_DCS_INCUMBENT_SIGNAL_INTERFERENCE 0x04
|
||||
|
||||
struct ath12k_wmi_dcs_interference_ev_fixed_params {
|
||||
__le32 interference_type;
|
||||
__le32 pdev_id;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_incumbent_signal_interference_params {
|
||||
__le32 chan_width;
|
||||
__le32 chan_freq;
|
||||
__le32 center_freq0;
|
||||
__le32 center_freq1;
|
||||
__le32 chan_bw_interference_bitmap;
|
||||
} __packed;
|
||||
|
||||
struct ath12k_wmi_incumbent_signal_interference_arg {
|
||||
u32 chan_width;
|
||||
u32 chan_freq;
|
||||
u32 center_freq0;
|
||||
u32 center_freq1;
|
||||
u32 chan_bw_interference_bitmap;
|
||||
};
|
||||
|
||||
struct ath12k_wmi_intf_arg {
|
||||
u32 interference_type;
|
||||
u32 pdev_id;
|
||||
};
|
||||
|
||||
enum ath12k_wmi_dcs_interference_chan_segment {
|
||||
/*
|
||||
* Firmware reports interference bitmap in primary-based order.
|
||||
* Bit 0 is the primary 20 MHz, bit 1 is the adjacent 20 MHz within
|
||||
* the primary 40 MHz. Bits 2-3 cover the secondary 40 MHz, bits 4-7
|
||||
* cover the secondary 80 MHz, and bits 8-15 cover the secondary 160 MHz.
|
||||
*/
|
||||
ATH12K_WMI_DCS_SEG_PRI20 = 0x1,
|
||||
ATH12K_WMI_DCS_SEG_SEC20 = 0x2,
|
||||
ATH12K_WMI_DCS_SEG_SEC40_LOW = 0x4,
|
||||
ATH12K_WMI_DCS_SEG_SEC40_UP = 0x8,
|
||||
ATH12K_WMI_DCS_SEG_SEC40 = 0xC,
|
||||
ATH12K_WMI_DCS_SEG_SEC80_LOW = 0x10,
|
||||
ATH12K_WMI_DCS_SEG_SEC80_LOW_UP = 0x20,
|
||||
ATH12K_WMI_DCS_SEG_SEC80_UP_LOW = 0x40,
|
||||
ATH12K_WMI_DCS_SEG_SEC80_UP = 0x80,
|
||||
ATH12K_WMI_DCS_SEG_SEC80 = 0xF0,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_LOW = 0x0100,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_LOW_UP = 0x0200,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_LOW_UP_UP = 0x0400,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_LOW_UP_UP_UP = 0x0800,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_UP_LOW_LOW_LOW = 0x1000,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_UP_LOW_LOW = 0x2000,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_UP_LOW = 0x4000,
|
||||
ATH12K_WMI_DCS_SEG_SEC160_UP = 0x8000,
|
||||
ATH12K_WMI_DCS_SEG_SEC160 = 0xFF00,
|
||||
};
|
||||
|
||||
struct wmi_pdev_temperature_event {
|
||||
/* temperature value in Celsius degree */
|
||||
a_sle32 temp;
|
||||
|
|
@ -6514,6 +6631,8 @@ __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len);
|
|||
int ath12k_wmi_send_tpc_stats_request(struct ath12k *ar,
|
||||
enum wmi_halphy_ctrl_path_stats_id tpc_stats_type);
|
||||
void ath12k_wmi_free_tpc_stats_mem(struct ath12k *ar);
|
||||
int ath12k_wmi_send_thermal_mitigation_cmd(struct ath12k *ar,
|
||||
struct ath12k_wmi_thermal_mitigation_arg *arg);
|
||||
|
||||
static inline u32
|
||||
ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param)
|
||||
|
|
@ -6576,6 +6695,8 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
|
|||
struct ath12k_reg_tpc_power_info *param);
|
||||
int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab,
|
||||
struct wmi_mlo_link_set_active_arg *param);
|
||||
int ath12k_wmi_simulate_incumbent_signal_interference(struct ath12k *ar,
|
||||
u32 chan_bw_interference_bitmap);
|
||||
int ath12k_wmi_alloc(void);
|
||||
void ath12k_wmi_free(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -80,14 +80,14 @@ static int ar9002_hw_init_mode_regs(struct ath_hw *ah)
|
|||
/* iniAddac needs to be modified for these chips */
|
||||
if (AR_SREV_9160(ah) || !AR_SREV_5416_22_OR_LATER(ah)) {
|
||||
struct ar5416IniArray *addac = &ah->iniAddac;
|
||||
u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns;
|
||||
u32 n = addac->ia_rows * addac->ia_columns;
|
||||
u32 *data;
|
||||
|
||||
data = devm_kzalloc(ah->dev, size, GFP_KERNEL);
|
||||
data = devm_kmemdup_array(ah->dev, addac->ia_array, n, sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(data, addac->ia_array, size);
|
||||
addac->ia_array = data;
|
||||
|
||||
if (!AR_SREV_5416_22_OR_LATER(ah)) {
|
||||
|
|
|
|||
|
|
@ -137,24 +137,6 @@ static void owl_fw_cb(const struct firmware *fw, void *context)
|
|||
release_firmware(fw);
|
||||
}
|
||||
|
||||
static const char *owl_get_eeprom_name(struct pci_dev *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
char *eeprom_name;
|
||||
|
||||
dev_dbg(dev, "using auto-generated eeprom filename\n");
|
||||
|
||||
eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL);
|
||||
if (!eeprom_name)
|
||||
return NULL;
|
||||
|
||||
/* this should match the pattern used in ath9k/init.c */
|
||||
scnprintf(eeprom_name, EEPROM_FILENAME_LEN, "ath9k-eeprom-pci-%s.bin",
|
||||
dev_name(dev));
|
||||
|
||||
return eeprom_name;
|
||||
}
|
||||
|
||||
static void owl_nvmem_work(struct work_struct *work)
|
||||
{
|
||||
struct owl_ctx *ctx = container_of(work, struct owl_ctx, work);
|
||||
|
|
@ -195,8 +177,9 @@ static int owl_nvmem_probe(struct owl_ctx *ctx)
|
|||
static int owl_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
char eeprom_name[EEPROM_FILENAME_LEN];
|
||||
struct device *dev = &pdev->dev;
|
||||
struct owl_ctx *ctx;
|
||||
const char *eeprom_name;
|
||||
int err = 0;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
|
|
@ -215,11 +198,11 @@ static int owl_probe(struct pci_dev *pdev,
|
|||
if (err <= 0)
|
||||
return err;
|
||||
|
||||
eeprom_name = owl_get_eeprom_name(pdev);
|
||||
if (!eeprom_name) {
|
||||
dev_err(&pdev->dev, "no eeprom filename found.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
dev_dbg(dev, "using auto-generated eeprom filename\n");
|
||||
|
||||
/* this should match the pattern used in ath9k/init.c */
|
||||
scnprintf(eeprom_name, sizeof(eeprom_name), "ath9k-eeprom-pci-%s.bin",
|
||||
dev_name(dev));
|
||||
|
||||
err = request_firmware_nowait(THIS_MODULE, true, eeprom_name,
|
||||
&pdev->dev, GFP_KERNEL, ctx, owl_fw_cb);
|
||||
|
|
|
|||
|
|
@ -133,13 +133,11 @@ int ath9k_cmn_init_channels_rates(struct ath_common *common)
|
|||
ATH9K_NUM_CHANNELS);
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) {
|
||||
channels = devm_kzalloc(ah->dev,
|
||||
channels = devm_kmemdup(ah->dev, ath9k_2ghz_chantable,
|
||||
sizeof(ath9k_2ghz_chantable), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(channels, ath9k_2ghz_chantable,
|
||||
sizeof(ath9k_2ghz_chantable));
|
||||
common->sbands[NL80211_BAND_2GHZ].channels = channels;
|
||||
common->sbands[NL80211_BAND_2GHZ].band = NL80211_BAND_2GHZ;
|
||||
common->sbands[NL80211_BAND_2GHZ].n_channels =
|
||||
|
|
@ -150,13 +148,11 @@ int ath9k_cmn_init_channels_rates(struct ath_common *common)
|
|||
}
|
||||
|
||||
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) {
|
||||
channels = devm_kzalloc(ah->dev,
|
||||
channels = devm_kmemdup(ah->dev, ath9k_5ghz_chantable,
|
||||
sizeof(ath9k_5ghz_chantable), GFP_KERNEL);
|
||||
if (!channels)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(channels, ath9k_5ghz_chantable,
|
||||
sizeof(ath9k_5ghz_chantable));
|
||||
common->sbands[NL80211_BAND_5GHZ].channels = channels;
|
||||
common->sbands[NL80211_BAND_5GHZ].band = NL80211_BAND_5GHZ;
|
||||
common->sbands[NL80211_BAND_5GHZ].n_channels =
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
{
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
u8 *ds;
|
||||
int i, bsize, desc_len;
|
||||
int i, desc_len;
|
||||
|
||||
ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n",
|
||||
name, nbuf, ndesc);
|
||||
|
|
@ -339,8 +339,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
if (is_tx) {
|
||||
struct ath_buf *bf;
|
||||
|
||||
bsize = sizeof(struct ath_buf) * nbuf;
|
||||
bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
|
||||
bf = devm_kcalloc(sc->dev, sizeof(*bf), nbuf, GFP_KERNEL);
|
||||
if (!bf)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -370,8 +369,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
|
|||
} else {
|
||||
struct ath_rxbuf *bf;
|
||||
|
||||
bsize = sizeof(struct ath_rxbuf) * nbuf;
|
||||
bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
|
||||
bf = devm_kcalloc(sc->dev, sizeof(struct ath_rxbuf), nbuf, GFP_KERNEL);
|
||||
if (!bf)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -576,7 +574,7 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc)
|
|||
size_t len;
|
||||
int err;
|
||||
|
||||
cell = devm_nvmem_cell_get(sc->dev, "calibration");
|
||||
cell = nvmem_cell_get(sc->dev, "calibration");
|
||||
if (IS_ERR(cell)) {
|
||||
err = PTR_ERR(cell);
|
||||
|
||||
|
|
@ -593,6 +591,7 @@ static int ath9k_nvmem_request_eeprom(struct ath_softc *sc)
|
|||
}
|
||||
|
||||
buf = nvmem_cell_read(cell, &len);
|
||||
nvmem_cell_put(cell);
|
||||
if (IS_ERR(buf))
|
||||
return PTR_ERR(buf);
|
||||
|
||||
|
|
|
|||
|
|
@ -202,7 +202,6 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
|
|||
struct sk_buff *skb;
|
||||
struct ath_rxbuf *bf;
|
||||
int error = 0, i;
|
||||
u32 size;
|
||||
|
||||
ath9k_hw_set_rx_bufsize(ah, common->rx_bufsize -
|
||||
ah->caps.rx_status_len);
|
||||
|
|
@ -212,8 +211,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
|
|||
ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_HP],
|
||||
ah->caps.rx_hp_qdepth);
|
||||
|
||||
size = sizeof(struct ath_rxbuf) * nbufs;
|
||||
bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);
|
||||
bf = devm_kcalloc(sc->dev, sizeof(struct ath_rxbuf), nbufs, GFP_KERNEL);
|
||||
if (!bf)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -1993,7 +1993,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
|||
|
||||
ieee80211_txq_schedule_start(hw, txq->mac80211_qnum);
|
||||
spin_lock_bh(&sc->chan_lock);
|
||||
rcu_read_lock();
|
||||
|
||||
if (sc->cur_chan->stopped)
|
||||
goto out;
|
||||
|
|
@ -2011,7 +2010,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
|||
}
|
||||
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
spin_unlock_bh(&sc->chan_lock);
|
||||
ieee80211_txq_schedule_end(hw, txq->mac80211_qnum);
|
||||
}
|
||||
|
|
@ -2746,6 +2744,11 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (ts.qid >= ATH9K_NUM_TX_QUEUES) {
|
||||
ath_dbg(common, XMIT, "invalid qid %d\n", ts.qid);
|
||||
continue;
|
||||
}
|
||||
|
||||
txq = &sc->tx.txq[ts.qid];
|
||||
|
||||
ath_txq_lock(sc, txq);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user