Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for v6.1. Major changes:

ath11k

* cold boot calibration support on WCN6750

* Target Wake Time (TWT) debugfs support for STA interface

* support to connect to a non-transmit MBSSID AP profile

* enable remain-on-channel support on WCN6750

* implement SRAM dump debugfs interface

* enable threaded NAPI on all hardware

* WoW support for WCN6750

* support to provide transmit power from firmware via nl80211

* support to get power save duration for each client

* spectral scan support for 160 MHz

wcn36xx

* add SNR from a received frame as a source of system entropy
This commit is contained in:
Kalle Valo 2022-09-27 09:17:01 +03:00
commit 6cf5e9066d
66 changed files with 1769 additions and 374 deletions

View file

@ -66,6 +66,18 @@ properties:
required:
- iommus
qcom,smem-states:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: State bits used by the AP to signal the WLAN Q6.
items:
- description: Signal bits used to enable/disable low power mode
on WCN6750 in the case of WoW (Wake on Wireless).
qcom,smem-state-names:
description: The names of the state bits used for SMP2P output.
items:
- const: wlan-smp2p-out
required:
- compatible
- reg
@ -448,6 +460,8 @@ examples:
<GIC_SPI 799 IRQ_TYPE_EDGE_RISING>;
qcom,rproc = <&remoteproc_wpss>;
memory-region = <&wlan_fw_mem>, <&wlan_ce_mem>;
qcom,smem-states = <&wlan_smp2p_out 0>;
qcom,smem-state-names = "wlan-smp2p-out";
wifi-firmware {
iommus = <&apps_smmu 0x1c02 0x1>;
};

View file

@ -101,7 +101,7 @@ int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
/* Step 1: Read 4 bytes of the target info and check if it is
* the special sentinal version word or the first word in the
* the special sentinel version word or the first word in the
* version response.
*/
resplen = sizeof(u32);
@ -111,7 +111,7 @@ int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
return ret;
}
/* Some SDIO boards have a special sentinal byte before the real
/* Some SDIO boards have a special sentinel byte before the real
* version response.
*/
if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) {

View file

@ -1323,7 +1323,7 @@ EXPORT_SYMBOL(ath10k_ce_per_engine_service);
/*
* Handler for per-engine interrupts on ALL active CEs.
* This is used in cases where the system is sharing a
* single interrput for all CEs
* single interrupt for all CEs
*/
void ath10k_ce_per_engine_service_any(struct ath10k *ar)

View file

@ -3096,7 +3096,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
* enabled always.
*
* We can still enable BTCOEX if firmware has the support
* eventhough btceox_support value is
* even though btceox_support value is
* ATH10K_DT_BTCOEX_NOT_FOUND
*/

View file

@ -76,7 +76,7 @@
/* The magic used by QCA spec */
#define ATH10K_SMBIOS_BDF_EXT_MAGIC "BDF_"
/* Default Airtime weight multipler (Tuned for multiclient performance) */
/* Default Airtime weight multiplier (Tuned for multiclient performance) */
#define ATH10K_AIRTIME_WEIGHT_MULTIPLIER 4
#define ATH10K_MAX_RETRY_COUNT 30
@ -857,7 +857,7 @@ enum ath10k_dev_flags {
/* Disable HW crypto engine */
ATH10K_FLAG_HW_CRYPTO_DISABLED,
/* Bluetooth coexistance enabled */
/* Bluetooth coexistence enabled */
ATH10K_FLAG_BTCOEX,
/* Per Station statistics service */

View file

@ -531,7 +531,7 @@ static const struct ath10k_mem_section qca6174_hw30_sdio_register_sections[] = {
{0x40000, 0x400A4},
/* SI register is skiped here.
/* SI register is skipped here.
* Because it will cause bus hang
*
* {0x50000, 0x50018},

View file

@ -125,7 +125,7 @@ enum ath10k_mem_region_type {
* To minimize the size of the array, the list must obey the format:
* '{start0,stop0},{start1,stop1},{start2,stop2}....' The values below must
* also obey to 'start0 < stop0 < start1 < stop1 < start2 < ...', otherwise
* we may encouter error in the dump processing.
* we may encounter error in the dump processing.
*/
struct ath10k_mem_section {
u32 start;

View file

@ -1081,7 +1081,7 @@ exit:
* struct available..
*/
/* This generally cooresponds to the debugfs fw_stats file */
/* This generally corresponds to the debugfs fw_stats file */
static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx_pkts_nic",
"tx_bytes_nic",

View file

@ -498,7 +498,7 @@ static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
{
switch (i) {
case ATH10K_AMPDU_SUBFRM_NUM_10:
return "upto 10";
return "up to 10";
case ATH10K_AMPDU_SUBFRM_NUM_20:
return "11-20";
case ATH10K_AMPDU_SUBFRM_NUM_30:

View file

@ -301,12 +301,16 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
ath10k_htt_get_vaddr_ring(htt),
htt->rx_ring.base_paddr);
ath10k_htt_config_paddrs_ring(htt, NULL);
dma_free_coherent(htt->ar->dev,
sizeof(*htt->rx_ring.alloc_idx.vaddr),
htt->rx_ring.alloc_idx.vaddr,
htt->rx_ring.alloc_idx.paddr);
htt->rx_ring.alloc_idx.vaddr = NULL;
kfree(htt->rx_ring.netbufs_ring);
htt->rx_ring.netbufs_ring = NULL;
}
static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
@ -846,8 +850,10 @@ err_dma_idx:
ath10k_htt_get_rx_ring_size(htt),
vaddr_ring,
htt->rx_ring.base_paddr);
ath10k_htt_config_paddrs_ring(htt, NULL);
err_dma_ring:
kfree(htt->rx_ring.netbufs_ring);
htt->rx_ring.netbufs_ring = NULL;
err_netbuf:
return -ENOMEM;
}
@ -2496,7 +2502,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt,
/* I have not yet seen any case where num_mpdu_ranges > 1.
* qcacld does not seem handle that case either, so we introduce the
* same limitiation here as well.
* same limitation here as well.
*/
if (num_mpdu_ranges > 1)
ath10k_warn(ar,

View file

@ -1112,7 +1112,7 @@ int ath10k_htt_tx_fetch_resp(struct ath10k *ar,
int len = 0;
int ret;
/* Response IDs are echo-ed back only for host driver convienence
/* Response IDs are echo-ed back only for host driver convenience
* purposes. They aren't used for anything in the driver yet so use 0.
*/

View file

@ -84,7 +84,7 @@ const struct ath10k_hw_regs qca99x0_regs = {
.ce5_base_address = 0x0004b400,
.ce6_base_address = 0x0004b800,
.ce7_base_address = 0x0004bc00,
/* Note: qca99x0 supports upto 12 Copy Engines. Other than address of
/* Note: qca99x0 supports up to 12 Copy Engines. Other than address of
* CE0 and CE1 no other copy engine is directly referred in the code.
* It is not really necessary to assign address for newly supported
* CEs in this address table.
@ -120,7 +120,7 @@ const struct ath10k_hw_regs qca4019_regs = {
.ce5_base_address = 0x0004b400,
.ce6_base_address = 0x0004b800,
.ce7_base_address = 0x0004bc00,
/* qca4019 supports upto 12 copy engines. Since base address
/* qca4019 supports up to 12 copy engines. Since base address
* of ce8 to ce11 are not directly referred in the code,
* no need have them in separate members in this table.
* Copy Engine Address
@ -924,7 +924,7 @@ static void ath10k_hw_map_target_mem(struct ath10k *ar, u32 msb)
ath10k_hif_write32(ar, address, msb);
}
/* 1. Write to memory region of target, such as IRAM adn DRAM.
/* 1. Write to memory region of target, such as IRAM and DRAM.
* 2. Target address( 0 ~ 00100000 & 0x00400000~0x00500000)
* can be written directly. See ath10k_pci_targ_cpu_to_ce_addr() too.
* 3. In order to access the region other than the above,

View file

@ -4051,7 +4051,7 @@ static int ath10k_mac_tx(struct ath10k *ar,
ath10k_tx_h_seq_no(vif, skb);
break;
case ATH10K_HW_TXRX_ETHERNET:
/* Convert 802.11->802.3 header only if the frame was erlier
/* Convert 802.11->802.3 header only if the frame was earlier
* encapsulated to 802.11 by mac80211. Otherwise pass it as is.
*/
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
@ -8097,7 +8097,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/* TODO: Implement this function properly
* For now it is needed to reply to Probe Requests in IBSS mode.
* Propably we need this information from FW.
* Probably we need this information from FW.
*/
static int ath10k_tx_last_beacon(struct ieee80211_hw *hw)
{
@ -9686,7 +9686,7 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = {
},
};
/* FIXME: This is not thouroughly tested. These combinations may over- or
/* FIXME: This is not thoroughly tested. These combinations may over- or
* underestimate hw/fw capabilities.
*/
static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = {
@ -9926,7 +9926,7 @@ int ath10k_mac_register(struct ath10k *ar)
WLAN_CIPHER_SUITE_BIP_GMAC_128,
WLAN_CIPHER_SUITE_BIP_GMAC_256,
/* Only QCA99x0 and QCA4019 varients support GCMP-128, GCMP-256
/* Only QCA99x0 and QCA4019 variants support GCMP-128, GCMP-256
* and CCMP-256 in hardware.
*/
WLAN_CIPHER_SUITE_GCMP,

View file

@ -1244,7 +1244,7 @@ static void ath10k_pci_process_htt_rx_cb(struct ath10k_ce_pipe *ce_state,
unsigned int nbytes, max_nbytes, nentries;
int orig_len;
/* No need to aquire ce_lock for CE5, since this is the only place CE5
/* No need to acquire ce_lock for CE5, since this is the only place CE5
* is processed other than init and deinit. Before releasing CE5
* buffers, interrupts are disabled. Thus CE5 access is serialized.
*/

View file

@ -81,7 +81,7 @@ struct ath10k_pci_pipe {
/* Handle of underlying Copy Engine */
struct ath10k_ce_pipe *ce_hdl;
/* Our pipe number; facilitiates use of pipe_info ptrs. */
/* Our pipe number; facilitates use of pipe_info ptrs. */
u8 pipe_num;
/* Convenience back pointer to hif_ce_state. */

View file

@ -792,7 +792,7 @@ static void ath10k_qmi_event_server_arrive(struct ath10k_qmi *qmi)
return;
/*
* HACK: sleep for a while inbetween receiving the msa info response
* HACK: sleep for a while between receiving the msa info response
* and the XPU update to prevent SDM845 from crashing due to a security
* violation, when running MPSS.AT.4.0.c2-01184-SDM845_GEN_PACK-1.
*/

View file

@ -448,7 +448,7 @@ struct rx_mpdu_end {
* - 4 bytes for WEP
* - 8 bytes for TKIP, AES
* [padding to 4 bytes]
* c) A-MSDU subframe header (14 bytes) if appliable
* c) A-MSDU subframe header (14 bytes) if applicable
* d) LLC/SNAP (RFC1042, 8 bytes)
*
* In case of A-MSDU only first frame in sequence contains (a) and (b).

View file

@ -1057,7 +1057,7 @@ static int ath10k_sdio_mbox_proc_pending_irqs(struct ath10k *ar,
out:
/* An optimization to bypass reading the IRQ status registers
* unecessarily which can re-wake the target, if upper layers
* unnecessarily which can re-wake the target, if upper layers
* determine that we are in a low-throughput mode, we can rely on
* taking another interrupt rather than re-checking the status
* registers which can re-wake the target.

View file

@ -98,7 +98,7 @@ static ssize_t ath10k_thermal_show_temp(struct device *dev,
temperature = ar->thermal.temperature;
spin_unlock_bh(&ar->data_lock);
/* display in millidegree celcius */
/* display in millidegree celsius */
ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
out:
mutex_unlock(&ar->conf_mutex);

View file

@ -19,7 +19,7 @@ struct ath10k_thermal {
/* protected by conf_mutex */
u32 throttle_state;
u32 quiet_period;
/* temperature value in Celcius degree
/* temperature value in Celsius degree
* protected by data_lock
*/
int temperature;

View file

@ -26,7 +26,7 @@
#define ATH10K_USB_EP_ADDR_APP_DATA_MP_OUT 0x03
#define ATH10K_USB_EP_ADDR_APP_DATA_HP_OUT 0x04
/* diagnostic command defnitions */
/* diagnostic command definitions */
#define ATH10K_USB_CONTROL_REQ_SEND_BMI_CMD 1
#define ATH10K_USB_CONTROL_REQ_RECV_BMI_RESP 2
#define ATH10K_USB_CONTROL_REQ_DIAG_CMD 3

View file

@ -1813,7 +1813,7 @@ struct wmi_tlv_pdev_get_temp_cmd {
struct wmi_tlv_pdev_temperature_event {
__le32 tlv_hdr;
/* temperature value in Celcius degree */
/* temperature value in Celsius degree */
__le32 temperature;
__le32 pdev_id;
} __packed;
@ -2548,7 +2548,7 @@ struct nlo_channel_prediction_cfg {
/* Preconfigured stationary threshold.
* Lesser value means more conservative. Bigger value means more aggressive.
* Maximum is 100 and mininum is 0.
* Maximum is 100 and minimum is 0.
*/
__le32 stationary_threshold;

View file

@ -3555,7 +3555,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
__le32 t;
u32 v, tim_len;
/* When FW reports 0 in tim_len, ensure atleast first byte
/* When FW reports 0 in tim_len, ensure at least first byte
* in tim_bitmap is considered for pvm calculation.
*/
tim_len = tim_info->tim_len ? __le32_to_cpu(tim_info->tim_len) : 1;

View file

@ -3170,7 +3170,7 @@ struct wmi_start_scan_common {
/* dwell time in msec on passive channels */
__le32 dwell_time_passive;
/*
* min time in msec on the BSS channel,only valid if atleast one
* min time in msec on the BSS channel,only valid if at least one
* VDEV is active
*/
__le32 min_rest_time;
@ -3196,7 +3196,7 @@ struct wmi_start_scan_common {
* and bssid_list
*/
__le32 repeat_probe_time;
/* time in msec between 2 consequetive probe requests with in a set. */
/* time in msec between 2 consecutive probe requests with in a set. */
__le32 probe_spacing_time;
/*
* data inactivity time in msec on bss channel that will be used by
@ -4397,7 +4397,7 @@ struct wmi_pdev_stats_tx {
/* wal pdev continuous xretry */
__le32 pdev_cont_xretry;
/* wal pdev continous xretry */
/* wal pdev continuous xretry */
__le32 pdev_tx_timeout;
/* wal pdev resets */
@ -5240,7 +5240,7 @@ enum wmi_vdev_param {
* scheduler.
*/
WMI_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
/* enable/dsiable WDS for this VDEV */
/* enable/disable WDS for this VDEV */
WMI_VDEV_PARAM_WDS,
/* ATIM Window */
WMI_VDEV_PARAM_ATIM_WINDOW,
@ -5372,7 +5372,7 @@ enum wmi_10x_vdev_param {
* scheduler.
*/
WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
/* enable/dsiable WDS for this VDEV */
/* enable/disable WDS for this VDEV */
WMI_10X_VDEV_PARAM_WDS,
/* ATIM Window */
WMI_10X_VDEV_PARAM_ATIM_WINDOW,
@ -5904,7 +5904,7 @@ enum wmi_sta_ps_param_tx_wake_threshold {
enum wmi_sta_ps_param_pspoll_count {
WMI_STA_PS_PSPOLL_COUNT_NO_MAX = 0,
/*
* Values greater than 0 indicate the maximum numer of PS-Poll frames
* Values greater than 0 indicate the maximum number of PS-Poll frames
* FW will send before waking up.
*/
@ -6947,7 +6947,7 @@ struct wmi_echo_ev_arg {
};
struct wmi_pdev_temperature_event {
/* temperature value in Celcius degree */
/* temperature value in Celsius degree */
__le32 temperature;
} __packed;

View file

@ -16,6 +16,8 @@
#include "hif.h"
#include <linux/remoteproc.h>
#include "pcic.h"
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
static const struct of_device_id ath11k_ahb_of_match[] = {
/* TODO: Should we change the compatible string to something similar
@ -359,6 +361,7 @@ static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
if (!irq_grp->napi_enabled) {
dev_set_threaded(&irq_grp->napi_ndev, true);
napi_enable(&irq_grp->napi);
irq_grp->napi_enabled = true;
}
@ -406,7 +409,8 @@ static int ath11k_ahb_fwreset_from_cold_boot(struct ath11k_base *ab)
int timeout;
if (ath11k_cold_boot_cal == 0 || ab->qmi.cal_done ||
ab->hw_params.cold_boot_calib == 0)
ab->hw_params.cold_boot_calib == 0 ||
ab->hw_params.cbcal_restart_fw == 0)
return 0;
ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n");
@ -685,11 +689,90 @@ static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id
return 0;
}
static int ath11k_ahb_hif_suspend(struct ath11k_base *ab)
{
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
u32 wake_irq;
u32 value = 0;
int ret;
if (!device_may_wakeup(ab->dev))
return -EPERM;
wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
ret = enable_irq_wake(wake_irq);
if (ret) {
ath11k_err(ab, "failed to enable wakeup irq :%d\n", ret);
return ret;
}
value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_ENTER,
ATH11K_AHB_SMP2P_SMEM_MSG);
ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
if (ret) {
ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
return ret;
}
ath11k_dbg(ab, ATH11K_DBG_AHB, "ahb device suspended\n");
return ret;
}
static int ath11k_ahb_hif_resume(struct ath11k_base *ab)
{
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
u32 wake_irq;
u32 value = 0;
int ret;
if (!device_may_wakeup(ab->dev))
return -EPERM;
wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];
ret = disable_irq_wake(wake_irq);
if (ret) {
ath11k_err(ab, "failed to disable wakeup irq: %d\n", ret);
return ret;
}
reinit_completion(&ab->wow.wakeup_completed);
value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_EXIT,
ATH11K_AHB_SMP2P_SMEM_MSG);
ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);
if (ret) {
ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);
return ret;
}
ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
if (ret == 0) {
ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");
return -ETIMEDOUT;
}
ath11k_dbg(ab, ATH11K_DBG_AHB, "ahb device resumed\n");
return 0;
}
static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
.start = ath11k_ahb_start,
.stop = ath11k_ahb_stop,
.read32 = ath11k_ahb_read32,
.write32 = ath11k_ahb_write32,
.read = NULL,
.irq_enable = ath11k_ahb_ext_irq_enable,
.irq_disable = ath11k_ahb_ext_irq_disable,
.map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
@ -702,6 +785,7 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
.stop = ath11k_pcic_stop,
.read32 = ath11k_pcic_read32,
.write32 = ath11k_pcic_write32,
.read = NULL,
.irq_enable = ath11k_pcic_ext_irq_enable,
.irq_disable = ath11k_pcic_ext_irq_disable,
.get_msi_address = ath11k_pcic_get_msi_address,
@ -709,6 +793,10 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
.map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
.power_down = ath11k_ahb_power_down,
.power_up = ath11k_ahb_power_up,
.suspend = ath11k_ahb_hif_suspend,
.resume = ath11k_ahb_hif_resume,
.ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq,
.ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
};
static int ath11k_core_get_rproc(struct ath11k_base *ab)
@ -783,6 +871,34 @@ static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
return 0;
}
static int ath11k_ahb_setup_smp2p_handle(struct ath11k_base *ab)
{
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
if (!ab->hw_params.smp2p_wow_exit)
return 0;
ab_ahb->smp2p_info.smem_state = qcom_smem_state_get(ab->dev, "wlan-smp2p-out",
&ab_ahb->smp2p_info.smem_bit);
if (IS_ERR(ab_ahb->smp2p_info.smem_state)) {
ath11k_err(ab, "failed to fetch smem state: %ld\n",
PTR_ERR(ab_ahb->smp2p_info.smem_state));
return PTR_ERR(ab_ahb->smp2p_info.smem_state);
}
return 0;
}
static void ath11k_ahb_release_smp2p_handle(struct ath11k_base *ab)
{
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
if (!ab->hw_params.smp2p_wow_exit)
return;
qcom_smem_state_put(ab_ahb->smp2p_info.smem_state);
}
static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
{
struct platform_device *pdev = ab->pdev;
@ -1038,10 +1154,14 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
if (ret)
goto err_core_free;
ret = ath11k_hal_srng_init(ab);
ret = ath11k_ahb_setup_smp2p_handle(ab);
if (ret)
goto err_fw_deinit;
ret = ath11k_hal_srng_init(ab);
if (ret)
goto err_release_smp2p_handle;
ret = ath11k_ce_alloc_pipes(ab);
if (ret) {
ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
@ -1078,6 +1198,9 @@ err_ce_free:
err_hal_srng_deinit:
ath11k_hal_srng_deinit(ab);
err_release_smp2p_handle:
ath11k_ahb_release_smp2p_handle(ab);
err_fw_deinit:
ath11k_ahb_fw_resource_deinit(ab);
@ -1088,20 +1211,10 @@ err_core_free:
return ret;
}
static int ath11k_ahb_remove(struct platform_device *pdev)
static void ath11k_ahb_remove_prepare(struct ath11k_base *ab)
{
struct ath11k_base *ab = platform_get_drvdata(pdev);
unsigned long left;
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath11k_ahb_power_down(ab);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;
}
reinit_completion(&ab->driver_recovery);
if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
left = wait_for_completion_timeout(&ab->driver_recovery,
ATH11K_AHB_RECOVERY_TIMEOUT);
@ -1111,19 +1224,61 @@ static int ath11k_ahb_remove(struct platform_device *pdev)
set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
cancel_work_sync(&ab->restart_work);
cancel_work_sync(&ab->qmi.event_work);
}
static void ath11k_ahb_free_resources(struct ath11k_base *ab)
{
struct platform_device *pdev = ab->pdev;
ath11k_core_deinit(ab);
qmi_fail:
ath11k_ahb_free_irq(ab);
ath11k_hal_srng_deinit(ab);
ath11k_ahb_release_smp2p_handle(ab);
ath11k_ahb_fw_resource_deinit(ab);
ath11k_ce_free_pipes(ab);
ath11k_core_free(ab);
platform_set_drvdata(pdev, NULL);
}
static int ath11k_ahb_remove(struct platform_device *pdev)
{
struct ath11k_base *ab = platform_get_drvdata(pdev);
if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
ath11k_ahb_power_down(ab);
ath11k_debugfs_soc_destroy(ab);
ath11k_qmi_deinit_service(ab);
goto qmi_fail;
}
ath11k_ahb_remove_prepare(ab);
ath11k_core_deinit(ab);
qmi_fail:
ath11k_ahb_free_resources(ab);
return 0;
}
static void ath11k_ahb_shutdown(struct platform_device *pdev)
{
struct ath11k_base *ab = platform_get_drvdata(pdev);
/* platform shutdown() & remove() are mutually exclusive.
* remove() is invoked during rmmod & shutdown() during
* system reboot/shutdown.
*/
ath11k_ahb_remove_prepare(ab);
if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))
goto free_resources;
ath11k_core_deinit(ab);
free_resources:
ath11k_ahb_free_resources(ab);
}
static struct platform_driver ath11k_ahb_driver = {
.driver = {
.name = "ath11k",
@ -1131,6 +1286,7 @@ static struct platform_driver ath11k_ahb_driver = {
},
.probe = ath11k_ahb_probe,
.remove = ath11k_ahb_remove,
.shutdown = ath11k_ahb_shutdown,
};
static int ath11k_ahb_init(void)

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_AHB_H
#define ATH11K_AHB_H
@ -8,6 +9,16 @@
#include "core.h"
#define ATH11K_AHB_RECOVERY_TIMEOUT (3 * HZ)
#define ATH11K_AHB_SMP2P_SMEM_MSG GENMASK(15, 0)
#define ATH11K_AHB_SMP2P_SMEM_SEQ_NO GENMASK(31, 16)
#define ATH11K_AHB_SMP2P_SMEM_VALUE_MASK 0xFFFFFFFF
enum ath11k_ahb_smp2p_msg_id {
ATH11K_AHB_POWER_SAVE_ENTER = 1,
ATH11K_AHB_POWER_SAVE_EXIT,
};
struct ath11k_base;
struct ath11k_ahb {
@ -21,6 +32,11 @@ struct ath11k_ahb {
u32 ce_size;
bool use_tz;
} fw;
struct {
unsigned short seq_no;
unsigned int smem_bit;
struct qcom_smem_state *smem_state;
} smp2p_info;
};
static inline struct ath11k_ahb *ath11k_ahb_priv(struct ath11k_base *ab)

View file

@ -250,7 +250,7 @@ const struct ce_attr ath11k_host_ce_config_qcn9074[] = {
static bool ath11k_ce_need_shadow_fix(int ce_id)
{
/* only ce4 needs shadow workaroud*/
/* only ce4 needs shadow workaround */
if (ce_id == 4)
return true;
return false;
@ -1042,7 +1042,7 @@ int ath11k_ce_alloc_pipes(struct ath11k_base *ab)
ret = ath11k_ce_alloc_pipe(ab, i);
if (ret) {
/* Free any parial successful allocation */
/* Free any partial successful allocation */
ath11k_ce_free_pipes(ab);
return ret;
}

View file

@ -70,6 +70,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.summary_pad_sz = 0,
.fft_hdr_len = 16,
.max_fft_bins = 512,
.fragment_160mhz = true,
},
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -81,6 +82,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = false,
.supports_sta_ps = false,
.cold_boot_calib = true,
.cbcal_restart_fw = true,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@ -106,6 +108,13 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.hybrid_bus_type = false,
.fixed_fw_mem = false,
.support_off_channel_tx = false,
.supports_multi_bssid = false,
.sram_dump = {},
.tcl_ring_retry = true,
.tx_ring_size = DP_TCL_DATA_RING_SIZE,
.smp2p_wow_exit = false,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@ -141,6 +150,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.summary_pad_sz = 0,
.fft_hdr_len = 16,
.max_fft_bins = 512,
.fragment_160mhz = true,
},
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -152,6 +162,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = false,
.supports_sta_ps = false,
.cold_boot_calib = true,
.cbcal_restart_fw = true,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@ -177,6 +188,13 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.hybrid_bus_type = false,
.fixed_fw_mem = false,
.support_off_channel_tx = false,
.supports_multi_bssid = false,
.sram_dump = {},
.tcl_ring_retry = true,
.tx_ring_size = DP_TCL_DATA_RING_SIZE,
.smp2p_wow_exit = false,
},
{
.name = "qca6390 hw2.0",
@ -212,6 +230,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.summary_pad_sz = 0,
.fft_hdr_len = 0,
.max_fft_bins = 0,
.fragment_160mhz = false,
},
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -222,6 +241,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = true,
.supports_sta_ps = true,
.cold_boot_calib = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@ -247,6 +267,16 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.hybrid_bus_type = false,
.fixed_fw_mem = false,
.support_off_channel_tx = true,
.supports_multi_bssid = true,
.sram_dump = {
.start = 0x01400000,
.end = 0x0171ffff,
},
.tcl_ring_retry = true,
.tx_ring_size = DP_TCL_DATA_RING_SIZE,
.smp2p_wow_exit = false,
},
{
.name = "qcn9074 hw1.0",
@ -281,6 +311,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.summary_pad_sz = 16,
.fft_hdr_len = 24,
.max_fft_bins = 1024,
.fragment_160mhz = false,
},
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -292,6 +323,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = false,
.supports_sta_ps = false,
.cold_boot_calib = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 2,
.num_vdevs = 8,
.num_peers = 128,
@ -317,6 +349,13 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.hybrid_bus_type = false,
.fixed_fw_mem = false,
.support_off_channel_tx = false,
.supports_multi_bssid = false,
.sram_dump = {},
.tcl_ring_retry = true,
.tx_ring_size = DP_TCL_DATA_RING_SIZE,
.smp2p_wow_exit = false,
},
{
.name = "wcn6855 hw2.0",
@ -352,6 +391,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.summary_pad_sz = 0,
.fft_hdr_len = 0,
.max_fft_bins = 0,
.fragment_160mhz = false,
},
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -362,6 +402,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = true,
.supports_sta_ps = true,
.cold_boot_calib = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@ -387,6 +428,16 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.hybrid_bus_type = false,
.fixed_fw_mem = false,
.support_off_channel_tx = true,
.supports_multi_bssid = true,
.sram_dump = {
.start = 0x01400000,
.end = 0x0177ffff,
},
.tcl_ring_retry = true,
.tx_ring_size = DP_TCL_DATA_RING_SIZE,
.smp2p_wow_exit = false,
},
{
.name = "wcn6855 hw2.1",
@ -422,6 +473,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.summary_pad_sz = 0,
.fft_hdr_len = 0,
.max_fft_bins = 0,
.fragment_160mhz = false,
},
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -431,6 +483,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = true,
.supports_sta_ps = true,
.cold_boot_calib = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@ -456,6 +509,16 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.hybrid_bus_type = false,
.fixed_fw_mem = false,
.support_off_channel_tx = true,
.supports_multi_bssid = true,
.sram_dump = {
.start = 0x01400000,
.end = 0x0177ffff,
},
.tcl_ring_retry = true,
.tx_ring_size = DP_TCL_DATA_RING_SIZE,
.smp2p_wow_exit = false,
},
{
.name = "wcn6750 hw1.0",
@ -468,7 +531,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.max_radios = 1,
.bdf_addr = 0x4B0C0000,
.hw_ops = &wcn6750_ops,
.ring_mask = &ath11k_hw_ring_mask_qca6390,
.ring_mask = &ath11k_hw_ring_mask_wcn6750,
.internal_sleep_clock = false,
.regs = &wcn6750_regs,
.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_WCN6750,
@ -491,6 +554,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.summary_pad_sz = 0,
.fft_hdr_len = 0,
.max_fft_bins = 0,
.fragment_160mhz = false,
},
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
@ -499,7 +563,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_shadow_regs = true,
.idle_ps = true,
.supports_sta_ps = true,
.cold_boot_calib = false,
.cold_boot_calib = true,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@ -508,8 +573,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_regdb = true,
.fix_l1ss = false,
.credit_flow = true,
.max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,
.hal_params = &ath11k_hw_hal_params_qca6390,
.max_tx_ring = DP_TCL_NUM_RING_MAX,
.hal_params = &ath11k_hw_hal_params_wcn6750,
.supports_dynamic_smps_6ghz = false,
.alloc_cacheable_memory = false,
.supports_rssi_stats = true,
@ -524,7 +589,14 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.static_window_map = true,
.hybrid_bus_type = true,
.fixed_fw_mem = true,
.support_off_channel_tx = false,
.support_off_channel_tx = true,
.supports_multi_bssid = true,
.sram_dump = {},
.tcl_ring_retry = false,
.tx_ring_size = DP_TCL_DATA_RING_SIZE_WCN6750,
.smp2p_wow_exit = true,
},
};
@ -535,6 +607,52 @@ static inline struct ath11k_pdev *ath11k_core_get_single_pdev(struct ath11k_base
return &ab->pdevs[0];
}
void ath11k_fw_stats_pdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_pdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
void ath11k_fw_stats_vdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_vdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
void ath11k_fw_stats_bcn_free(struct list_head *head)
{
struct ath11k_fw_stats_bcn *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
void ath11k_fw_stats_init(struct ath11k *ar)
{
INIT_LIST_HEAD(&ar->fw_stats.pdevs);
INIT_LIST_HEAD(&ar->fw_stats.vdevs);
INIT_LIST_HEAD(&ar->fw_stats.bcn);
init_completion(&ar->fw_stats_complete);
}
void ath11k_fw_stats_free(struct ath11k_fw_stats *stats)
{
ath11k_fw_stats_pdevs_free(&stats->pdevs);
ath11k_fw_stats_vdevs_free(&stats->vdevs);
ath11k_fw_stats_bcn_free(&stats->bcn);
}
int ath11k_core_suspend(struct ath11k_base *ab)
{
int ret;
@ -1544,7 +1662,7 @@ static void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab)
ar->state_11d = ATH11K_11D_IDLE;
complete(&ar->completed_11d_scan);
complete(&ar->scan.started);
complete(&ar->scan.completed);
complete_all(&ar->scan.completed);
complete(&ar->scan.on_channel);
complete(&ar->peer_assoc_done);
complete(&ar->peer_delete_done);
@ -1563,6 +1681,8 @@ static void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab)
wake_up(&ab->wmi_ab.tx_credits_wq);
wake_up(&ab->peer_mapping_wq);
reinit_completion(&ab->driver_recovery);
}
static void ath11k_core_post_reconfigure_recovery(struct ath11k_base *ab)

View file

@ -498,6 +498,13 @@ struct ath11k_sta {
bool use_4addr_set;
u16 tcl_metadata;
/* Protected with ar->data_lock */
enum ath11k_wmi_peer_ps_state peer_ps_state;
u64 ps_start_time;
u64 ps_start_jiffies;
u64 ps_total_duration;
bool peer_current_ps_valid;
};
#define ATH11K_MIN_5G_FREQ 4150
@ -545,9 +552,6 @@ struct ath11k_debug {
struct dentry *debugfs_pdev;
struct ath11k_dbg_htt_stats htt_stats;
u32 extd_tx_stats;
struct ath11k_fw_stats fw_stats;
struct completion fw_stats_complete;
bool fw_stats_done;
u32 extd_rx_stats;
u32 pktlog_filter;
u32 pktlog_mode;
@ -710,6 +714,13 @@ struct ath11k {
u8 twt_enabled;
bool nlo_enabled;
u8 alpha2[REG_ALPHA2_LEN + 1];
struct ath11k_fw_stats fw_stats;
struct completion fw_stats_complete;
bool fw_stats_done;
/* protected by conf_mutex */
bool ps_state_enable;
bool ps_timekeeper_enable;
};
struct ath11k_band_cap {
@ -887,7 +898,7 @@ struct ath11k_base {
/* Below regd's are protected by ab->data_lock */
/* This is the regd set for every radio
* by the firmware during initializatin
* by the firmware during initialization
*/
struct ieee80211_regdomain *default_regd[MAX_RADIOS];
/* This regd is set during dynamic country setting
@ -1112,6 +1123,12 @@ struct ath11k_fw_stats_bcn {
u32 tx_bcn_outage_cnt;
};
void ath11k_fw_stats_init(struct ath11k *ar);
void ath11k_fw_stats_pdevs_free(struct list_head *head);
void ath11k_fw_stats_vdevs_free(struct list_head *head);
void ath11k_fw_stats_bcn_free(struct list_head *head);
void ath11k_fw_stats_free(struct ath11k_fw_stats *stats);
extern const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq8074[];
extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq8074[];
extern const struct service_to_pipe ath11k_target_service_to_ce_map_wlan_ipq6018[];

View file

@ -14,6 +14,7 @@
#include "dp_tx.h"
#include "debugfs_htt_stats.h"
#include "peer.h"
#include "hif.h"
static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
"REO2SW1_RING",
@ -91,91 +92,35 @@ void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
spin_unlock_bh(&dbr_data->lock);
}
static void ath11k_fw_stats_pdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_pdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath11k_fw_stats_vdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_vdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath11k_fw_stats_bcn_free(struct list_head *head)
{
struct ath11k_fw_stats_bcn *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)
{
spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false;
ath11k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath11k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ar->fw_stats_done = false;
ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
spin_unlock_bh(&ar->data_lock);
}
void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb)
void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats)
{
struct ath11k_fw_stats stats = {};
struct ath11k *ar;
struct ath11k_base *ab = ar->ab;
struct ath11k_pdev *pdev;
bool is_end;
static unsigned int num_vdev, num_bcn;
size_t total_vdevs_started = 0;
int i, ret;
int i;
INIT_LIST_HEAD(&stats.pdevs);
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.bcn);
/* WMI_REQUEST_PDEV_STAT request has been already processed */
ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
if (ret) {
ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
goto free;
if (stats->stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
ar->fw_stats_done = true;
return;
}
rcu_read_lock();
ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
if (!ar) {
rcu_read_unlock();
ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
stats.pdev_id, ret);
goto free;
}
spin_lock_bh(&ar->data_lock);
if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
list_splice_tail_init(&stats.pdevs, &ar->debug.fw_stats.pdevs);
ar->debug.fw_stats_done = true;
goto complete;
}
if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
ar->debug.fw_stats_done = true;
goto complete;
}
if (stats.stats_id == WMI_REQUEST_VDEV_STAT) {
if (list_empty(&stats.vdevs)) {
if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {
if (list_empty(&stats->vdevs)) {
ath11k_warn(ab, "empty vdev stats");
goto complete;
return;
}
/* FW sends all the active VDEV stats irrespective of PDEV,
* hence limit until the count of all VDEVs started
@ -188,43 +133,34 @@ void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb
is_end = ((++num_vdev) == total_vdevs_started);
list_splice_tail_init(&stats.vdevs,
&ar->debug.fw_stats.vdevs);
list_splice_tail_init(&stats->vdevs,
&ar->fw_stats.vdevs);
if (is_end) {
ar->debug.fw_stats_done = true;
ar->fw_stats_done = true;
num_vdev = 0;
}
goto complete;
return;
}
if (stats.stats_id == WMI_REQUEST_BCN_STAT) {
if (list_empty(&stats.bcn)) {
if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
if (list_empty(&stats->bcn)) {
ath11k_warn(ab, "empty bcn stats");
goto complete;
return;
}
/* Mark end until we reached the count of all started VDEVs
* within the PDEV
*/
is_end = ((++num_bcn) == ar->num_started_vdevs);
list_splice_tail_init(&stats.bcn,
&ar->debug.fw_stats.bcn);
list_splice_tail_init(&stats->bcn,
&ar->fw_stats.bcn);
if (is_end) {
ar->debug.fw_stats_done = true;
ar->fw_stats_done = true;
num_bcn = 0;
}
}
complete:
complete(&ar->debug.fw_stats_complete);
rcu_read_unlock();
spin_unlock_bh(&ar->data_lock);
free:
ath11k_fw_stats_pdevs_free(&stats.pdevs);
ath11k_fw_stats_vdevs_free(&stats.vdevs);
ath11k_fw_stats_bcn_free(&stats.bcn);
}
static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
@ -245,7 +181,7 @@ static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
ath11k_debugfs_fw_stats_reset(ar);
reinit_completion(&ar->debug.fw_stats_complete);
reinit_completion(&ar->fw_stats_complete);
ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
@ -255,9 +191,8 @@ static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
return ret;
}
time_left =
wait_for_completion_timeout(&ar->debug.fw_stats_complete,
1 * HZ);
time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);
if (!time_left)
return -ETIMEDOUT;
@ -266,7 +201,7 @@ static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
break;
spin_lock_bh(&ar->data_lock);
if (ar->debug.fw_stats_done) {
if (ar->fw_stats_done) {
spin_unlock_bh(&ar->data_lock);
break;
}
@ -338,8 +273,7 @@ static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
goto err_free;
}
ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
buf);
ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
file->private_data = buf;
@ -410,8 +344,7 @@ static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
goto err_free;
}
ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
buf);
ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
file->private_data = buf;
@ -488,14 +421,13 @@ static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
}
}
ath11k_wmi_fw_stats_fill(ar, &ar->debug.fw_stats, req_param.stats_id,
buf);
ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
/* since beacon stats request is looped for all active VDEVs, saved fw
* stats is not freed for each request until done for all active VDEVs
*/
spin_lock_bh(&ar->data_lock);
ath11k_fw_stats_bcn_free(&ar->debug.fw_stats.bcn);
ath11k_fw_stats_bcn_free(&ar->fw_stats.bcn);
spin_unlock_bh(&ar->data_lock);
file->private_data = buf;
@ -982,6 +914,63 @@ static const struct file_operations fops_fw_dbglog = {
.llseek = default_llseek,
};
static int ath11k_open_sram_dump(struct inode *inode, struct file *file)
{
struct ath11k_base *ab = inode->i_private;
u8 *buf;
u32 start, end;
int ret;
start = ab->hw_params.sram_dump.start;
end = ab->hw_params.sram_dump.end;
buf = vmalloc(end - start + 1);
if (!buf)
return -ENOMEM;
ret = ath11k_hif_read(ab, buf, start, end);
if (ret) {
ath11k_warn(ab, "failed to dump sram: %d\n", ret);
vfree(buf);
return ret;
}
file->private_data = buf;
return 0;
}
static ssize_t ath11k_read_sram_dump(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k_base *ab = file->f_inode->i_private;
const char *buf = file->private_data;
int len;
u32 start, end;
start = ab->hw_params.sram_dump.start;
end = ab->hw_params.sram_dump.end;
len = end - start + 1;
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static int ath11k_release_sram_dump(struct inode *inode, struct file *file)
{
vfree(file->private_data);
file->private_data = NULL;
return 0;
}
static const struct file_operations fops_sram_dump = {
.open = ath11k_open_sram_dump,
.read = ath11k_read_sram_dump,
.release = ath11k_release_sram_dump,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath11k_debugfs_pdev_create(struct ath11k_base *ab)
{
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
@ -997,6 +986,10 @@ int ath11k_debugfs_pdev_create(struct ath11k_base *ab)
debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
&fops_soc_dp_stats);
if (ab->hw_params.sram_dump.start != 0)
debugfs_create_file("sram", 0400, ab->debugfs_soc, ab,
&fops_sram_dump);
return 0;
}
@ -1025,7 +1018,7 @@ void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
ar->debug.debugfs_pdev);
ar->debug.fw_stats.debugfs_fwstats = fwstats_dir;
ar->fw_stats.debugfs_fwstats = fwstats_dir;
/* all stats debugfs files created are under "fw_stats" directory
* created per PDEV
@ -1036,12 +1029,6 @@ void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
&fops_vdev_stats);
debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
&fops_bcn_stats);
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.bcn);
init_completion(&ar->debug.fw_stats_complete);
}
static ssize_t ath11k_write_pktlog_filter(struct file *file,
@ -1382,6 +1369,193 @@ static const struct file_operations fops_dbr_debug = {
.llseek = default_llseek,
};
static ssize_t ath11k_write_ps_timekeeper_enable(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
ssize_t ret;
u8 ps_timekeeper_enable;
if (kstrtou8_from_user(user_buf, count, 0, &ps_timekeeper_enable))
return -EINVAL;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH11K_STATE_ON) {
ret = -ENETDOWN;
goto exit;
}
if (!ar->ps_state_enable) {
ret = -EINVAL;
goto exit;
}
ar->ps_timekeeper_enable = !!ps_timekeeper_enable;
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static ssize_t ath11k_read_ps_timekeeper_enable(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
char buf[32];
int len;
mutex_lock(&ar->conf_mutex);
len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_timekeeper_enable);
mutex_unlock(&ar->conf_mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_ps_timekeeper_enable = {
.read = ath11k_read_ps_timekeeper_enable,
.write = ath11k_write_ps_timekeeper_enable,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static void ath11k_reset_peer_ps_duration(void *data,
struct ieee80211_sta *sta)
{
struct ath11k *ar = data;
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
spin_lock_bh(&ar->data_lock);
arsta->ps_total_duration = 0;
spin_unlock_bh(&ar->data_lock);
}
static ssize_t ath11k_write_reset_ps_duration(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
int ret;
u8 reset_ps_duration;
if (kstrtou8_from_user(user_buf, count, 0, &reset_ps_duration))
return -EINVAL;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH11K_STATE_ON) {
ret = -ENETDOWN;
goto exit;
}
if (!ar->ps_state_enable) {
ret = -EINVAL;
goto exit;
}
ieee80211_iterate_stations_atomic(ar->hw,
ath11k_reset_peer_ps_duration,
ar);
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_reset_ps_duration = {
.write = ath11k_write_reset_ps_duration,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static void ath11k_peer_ps_state_disable(void *data,
struct ieee80211_sta *sta)
{
struct ath11k *ar = data;
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
spin_lock_bh(&ar->data_lock);
arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
arsta->ps_start_time = 0;
arsta->ps_total_duration = 0;
spin_unlock_bh(&ar->data_lock);
}
static ssize_t ath11k_write_ps_state_enable(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
struct ath11k_pdev *pdev = ar->pdev;
int ret;
u32 param;
u8 ps_state_enable;
if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))
return -EINVAL;
mutex_lock(&ar->conf_mutex);
ps_state_enable = !!ps_state_enable;
if (ar->ps_state_enable == ps_state_enable) {
ret = count;
goto exit;
}
param = WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE;
ret = ath11k_wmi_pdev_set_param(ar, param, ps_state_enable, pdev->pdev_id);
if (ret) {
ath11k_warn(ar->ab, "failed to enable ps_state_enable: %d\n",
ret);
goto exit;
}
ar->ps_state_enable = ps_state_enable;
if (!ar->ps_state_enable) {
ar->ps_timekeeper_enable = false;
ieee80211_iterate_stations_atomic(ar->hw,
ath11k_peer_ps_state_disable,
ar);
}
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static ssize_t ath11k_read_ps_state_enable(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
char buf[32];
int len;
mutex_lock(&ar->conf_mutex);
len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_state_enable);
mutex_unlock(&ar->conf_mutex);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_ps_state_enable = {
.read = ath11k_read_ps_state_enable,
.write = ath11k_write_ps_state_enable,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath11k_debugfs_register(struct ath11k *ar)
{
struct ath11k_base *ab = ar->ab;
@ -1428,6 +1602,20 @@ int ath11k_debugfs_register(struct ath11k *ar)
debugfs_create_file("enable_dbr_debug", 0200, ar->debug.debugfs_pdev,
ar, &fops_dbr_debug);
debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_pdev, ar,
&fops_ps_state_enable);
if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
ar->ab->wmi_ab.svc_map)) {
debugfs_create_file("ps_timekeeper_enable", 0600,
ar->debug.debugfs_pdev, ar,
&fops_ps_timekeeper_enable);
debugfs_create_file("reset_ps_duration", 0200,
ar->debug.debugfs_pdev, ar,
&fops_reset_ps_duration);
}
return 0;
}
@ -1456,11 +1644,13 @@ static ssize_t ath11k_write_twt_add_dialog(struct file *file,
{
struct ath11k_vif *arvif = file->private_data;
struct wmi_twt_add_dialog_params params = { 0 };
struct wmi_twt_enable_params twt_params = {0};
struct ath11k *ar = arvif->ar;
u8 buf[128] = {0};
int ret;
if (arvif->ar->twt_enabled == 0) {
ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
if (ar->twt_enabled == 0) {
ath11k_err(ar->ab, "twt support is not enabled\n");
return -EOPNOTSUPP;
}
@ -1490,13 +1680,38 @@ static ssize_t ath11k_write_twt_add_dialog(struct file *file,
if (ret != 16)
return -EINVAL;
/* In the case of station vif, TWT is entirely handled by
* the firmware based on the input parameters in the TWT enable
* WMI command that is sent to the target during assoc.
* For manually testing the TWT feature, we need to first disable
* TWT and send enable command again with TWT input parameter
* sta_cong_timer_ms set to 0.
*/
if (arvif->vif->type == NL80211_IFTYPE_STATION) {
ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
ath11k_wmi_fill_default_twt_params(&twt_params);
twt_params.sta_cong_timer_ms = 0;
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
}
params.vdev_id = arvif->vdev_id;
ret = ath11k_wmi_send_twt_add_dialog_cmd(arvif->ar, &params);
if (ret)
return ret;
goto err_twt_add_dialog;
return count;
err_twt_add_dialog:
if (arvif->vif->type == NL80211_IFTYPE_STATION) {
ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
ath11k_wmi_fill_default_twt_params(&twt_params);
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
}
return ret;
}
static ssize_t ath11k_write_twt_del_dialog(struct file *file,
@ -1505,11 +1720,13 @@ static ssize_t ath11k_write_twt_del_dialog(struct file *file,
{
struct ath11k_vif *arvif = file->private_data;
struct wmi_twt_del_dialog_params params = { 0 };
struct wmi_twt_enable_params twt_params = {0};
struct ath11k *ar = arvif->ar;
u8 buf[64] = {0};
int ret;
if (arvif->ar->twt_enabled == 0) {
ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
if (ar->twt_enabled == 0) {
ath11k_err(ar->ab, "twt support is not enabled\n");
return -EOPNOTSUPP;
}
@ -1535,6 +1752,12 @@ static ssize_t ath11k_write_twt_del_dialog(struct file *file,
if (ret)
return ret;
if (arvif->vif->type == NL80211_IFTYPE_STATION) {
ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
ath11k_wmi_fill_default_twt_params(&twt_params);
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
}
return count;
}
@ -1638,36 +1861,35 @@ static const struct file_operations ath11k_fops_twt_resume_dialog = {
.open = simple_open
};
int ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
void ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
{
if (arvif->vif->type == NL80211_IFTYPE_AP && !arvif->debugfs_twt) {
arvif->debugfs_twt = debugfs_create_dir("twt",
arvif->vif->debugfs_dir);
if (!arvif->debugfs_twt || IS_ERR(arvif->debugfs_twt)) {
ath11k_warn(arvif->ar->ab,
"failed to create directory %p\n",
arvif->debugfs_twt);
arvif->debugfs_twt = NULL;
return -1;
}
struct ath11k_base *ab = arvif->ar->ab;
debugfs_create_file("add_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_add_dialog);
if (arvif->vif->type != NL80211_IFTYPE_AP &&
!(arvif->vif->type == NL80211_IFTYPE_STATION &&
test_bit(WMI_TLV_SERVICE_STA_TWT, ab->wmi_ab.svc_map)))
return;
debugfs_create_file("del_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_del_dialog);
arvif->debugfs_twt = debugfs_create_dir("twt",
arvif->vif->debugfs_dir);
debugfs_create_file("add_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_add_dialog);
debugfs_create_file("pause_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_pause_dialog);
debugfs_create_file("del_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_del_dialog);
debugfs_create_file("resume_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_resume_dialog);
}
return 0;
debugfs_create_file("pause_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_pause_dialog);
debugfs_create_file("resume_dialog", 0200, arvif->debugfs_twt,
arvif, &ath11k_fops_twt_resume_dialog);
}
void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif)
{
if (!arvif->debugfs_twt)
return;
debugfs_remove_recursive(arvif->debugfs_twt);
arvif->debugfs_twt = NULL;
}

View file

@ -269,7 +269,7 @@ int ath11k_debugfs_pdev_create(struct ath11k_base *ab);
void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab);
int ath11k_debugfs_register(struct ath11k *ar);
void ath11k_debugfs_unregister(struct ath11k *ar);
void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb);
void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats);
void ath11k_debugfs_fw_stats_init(struct ath11k *ar);
int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id,
@ -306,7 +306,7 @@ static inline int ath11k_debugfs_rx_filter(struct ath11k *ar)
return ar->debug.rx_filter;
}
int ath11k_debugfs_add_interface(struct ath11k_vif *arvif);
void ath11k_debugfs_add_interface(struct ath11k_vif *arvif);
void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif);
void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
enum wmi_direct_buffer_module id,
@ -341,8 +341,8 @@ static inline void ath11k_debugfs_unregister(struct ath11k *ar)
{
}
static inline void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab,
struct sk_buff *skb)
static inline void ath11k_debugfs_fw_stats_process(struct ath11k *ar,
struct ath11k_fw_stats *stats)
{
}
@ -386,9 +386,8 @@ static inline int ath11k_debugfs_get_fw_stats(struct ath11k *ar,
return 0;
}
static inline int ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
static inline void ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
{
return 0;
}
static inline void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif)

View file

@ -630,7 +630,7 @@ struct htt_tx_hwq_tried_mpdu_cnt_hist_tlv_v {
* completing the burst, we identify the txop used in the burst and
* incr the corresponding bin.
* Each bin represents 1ms & we have 10 bins in this histogram.
* they are deined in FW using the following macros
* they are defined in FW using the following macros
* #define WAL_MAX_TXOP_USED_CNT_HISTOGRAM 10
* #define WAL_TXOP_USED_HISTOGRAM_INTERVAL 1000 ( 1 ms )
*/
@ -1897,7 +1897,7 @@ struct htt_phy_counters_tlv {
u32 phytx_abort_cnt;
/* number of times rx abort initiated by phy */
u32 phyrx_abort_cnt;
/* number of rx defered count initiated by phy */
/* number of rx deferred count initiated by phy */
u32 phyrx_defer_abort_cnt;
/* number of sizing events generated at LSTF */
u32 rx_gain_adj_lstf_event_cnt;

View file

@ -751,6 +751,102 @@ static const struct file_operations fops_htt_peer_stats_reset = {
.llseek = default_llseek,
};
static ssize_t ath11k_dbg_sta_read_peer_ps_state(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_sta *sta = file->private_data;
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
struct ath11k *ar = arsta->arvif->ar;
char buf[20];
int len;
spin_lock_bh(&ar->data_lock);
len = scnprintf(buf, sizeof(buf), "%d\n", arsta->peer_ps_state);
spin_unlock_bh(&ar->data_lock);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_peer_ps_state = {
.open = simple_open,
.read = ath11k_dbg_sta_read_peer_ps_state,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_dbg_sta_read_current_ps_duration(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct ieee80211_sta *sta = file->private_data;
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
struct ath11k *ar = arsta->arvif->ar;
u64 time_since_station_in_power_save;
char buf[20];
int len;
spin_lock_bh(&ar->data_lock);
if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&
arsta->peer_current_ps_valid)
time_since_station_in_power_save = jiffies_to_msecs(jiffies
- arsta->ps_start_jiffies);
else
time_since_station_in_power_save = 0;
len = scnprintf(buf, sizeof(buf), "%llu\n",
time_since_station_in_power_save);
spin_unlock_bh(&ar->data_lock);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_current_ps_duration = {
.open = simple_open,
.read = ath11k_dbg_sta_read_current_ps_duration,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_dbg_sta_read_total_ps_duration(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_sta *sta = file->private_data;
struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
struct ath11k *ar = arsta->arvif->ar;
char buf[20];
u64 power_save_duration;
int len;
spin_lock_bh(&ar->data_lock);
if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON &&
arsta->peer_current_ps_valid)
power_save_duration = jiffies_to_msecs(jiffies
- arsta->ps_start_jiffies)
+ arsta->ps_total_duration;
else
power_save_duration = arsta->ps_total_duration;
len = scnprintf(buf, sizeof(buf), "%llu\n", power_save_duration);
spin_unlock_bh(&ar->data_lock);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_total_ps_duration = {
.open = simple_open,
.read = ath11k_dbg_sta_read_total_ps_duration,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir)
{
@ -778,4 +874,15 @@ void ath11k_debugfs_sta_op_add(struct ieee80211_hw *hw, struct ieee80211_vif *vi
ar->ab->wmi_ab.svc_map))
debugfs_create_file("htt_peer_stats_reset", 0600, dir, sta,
&fops_htt_peer_stats_reset);
debugfs_create_file("peer_ps_state", 0400, dir, sta,
&fops_peer_ps_state);
if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
ar->ab->wmi_ab.svc_map)) {
debugfs_create_file("current_ps_duration", 0440, dir, sta,
&fops_current_ps_duration);
debugfs_create_file("total_ps_duration", 0440, dir, sta,
&fops_total_ps_duration);
}
}

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <crypto/hash.h>
@ -131,13 +132,11 @@ static int ath11k_dp_srng_calculate_msi_group(struct ath11k_base *ab,
switch (type) {
case HAL_WBM2SW_RELEASE:
if (ring_num < 3) {
grp_mask = &ab->hw_params.ring_mask->tx[0];
} else if (ring_num == 3) {
if (ring_num == DP_RX_RELEASE_RING_NUM) {
grp_mask = &ab->hw_params.ring_mask->rx_wbm_rel[0];
ring_num = 0;
} else {
return -ENOENT;
grp_mask = &ab->hw_params.ring_mask->tx[0];
}
break;
case HAL_REO_EXCEPTION:
@ -371,6 +370,7 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
struct ath11k_dp *dp = &ab->dp;
struct hal_srng *srng;
int i, ret;
u8 tcl_num, wbm_num;
ret = ath11k_dp_srng_setup(ab, &dp->wbm_desc_rel_ring,
HAL_SW2WBM_RELEASE, 0, 0,
@ -396,9 +396,12 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
}
for (i = 0; i < ab->hw_params.max_tx_ring; i++) {
tcl_num = ab->hw_params.hal_params->tcl2wbm_rbm_map[i].tcl_ring_num;
wbm_num = ab->hw_params.hal_params->tcl2wbm_rbm_map[i].wbm_ring_num;
ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_data_ring,
HAL_TCL_DATA, i, 0,
DP_TCL_DATA_RING_SIZE);
HAL_TCL_DATA, tcl_num, 0,
ab->hw_params.tx_ring_size);
if (ret) {
ath11k_warn(ab, "failed to set up tcl_data ring (%d) :%d\n",
i, ret);
@ -406,7 +409,7 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
}
ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_comp_ring,
HAL_WBM2SW_RELEASE, i, 0,
HAL_WBM2SW_RELEASE, wbm_num, 0,
DP_TX_COMP_RING_SIZE);
if (ret) {
ath11k_warn(ab, "failed to set up tcl_comp ring (%d) :%d\n",
@ -431,7 +434,7 @@ static int ath11k_dp_srng_common_setup(struct ath11k_base *ab)
}
ret = ath11k_dp_srng_setup(ab, &dp->rx_rel_ring, HAL_WBM2SW_RELEASE,
3, 0, DP_RX_RELEASE_RING_SIZE);
DP_RX_RELEASE_RING_NUM, 0, DP_RX_RELEASE_RING_SIZE);
if (ret) {
ath11k_warn(ab, "failed to set up rx_rel ring :%d\n", ret);
goto err;
@ -774,9 +777,10 @@ int ath11k_dp_service_srng(struct ath11k_base *ab,
int i, j;
int tot_work_done = 0;
if (ab->hw_params.ring_mask->tx[grp_id]) {
i = __fls(ab->hw_params.ring_mask->tx[grp_id]);
ath11k_dp_tx_completion_handler(ab, i);
for (i = 0; i < ab->hw_params.max_tx_ring; i++) {
if (BIT(ab->hw_params.hal_params->tcl2wbm_rbm_map[i].wbm_ring_num) &
ab->hw_params.ring_mask->tx[grp_id])
ath11k_dp_tx_completion_handler(ab, i);
}
if (ab->hw_params.ring_mask->rx_err[grp_id]) {
@ -963,7 +967,7 @@ static void ath11k_dp_update_vdev_search(struct ath11k_vif *arvif)
{
/* When v2_map_support is true:for STA mode, enable address
* search index, tcl uses ast_hash value in the descriptor.
* When v2_map_support is false: for STA mode, dont' enable
* When v2_map_support is false: for STA mode, don't enable
* address search index.
*/
switch (arvif->vdev_type) {

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_DP_H
@ -203,6 +204,7 @@ struct ath11k_pdev_dp {
#define DP_WBM_RELEASE_RING_SIZE 64
#define DP_TCL_DATA_RING_SIZE 512
#define DP_TCL_DATA_RING_SIZE_WCN6750 2048
#define DP_TX_COMP_RING_SIZE 32768
#define DP_TX_IDR_SIZE DP_TX_COMP_RING_SIZE
#define DP_TCL_CMD_RING_SIZE 32
@ -222,6 +224,8 @@ struct ath11k_pdev_dp {
#define DP_RXDMA_MONITOR_DST_RING_SIZE 2048
#define DP_RXDMA_MONITOR_DESC_RING_SIZE 4096
#define DP_RX_RELEASE_RING_NUM 3
#define DP_RX_BUFFER_SIZE 2048
#define DP_RX_BUFFER_SIZE_LITE 1024
#define DP_RX_BUFFER_ALIGN_SIZE 128
@ -299,7 +303,7 @@ struct ath11k_dp {
#define HTT_TX_WBM_COMP_STATUS_OFFSET 8
/* HTT tx completion is overlayed in wbm_release_ring */
/* HTT tx completion is overlaid in wbm_release_ring */
#define HTT_TX_WBM_COMP_INFO0_STATUS GENMASK(12, 9)
#define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON GENMASK(16, 13)
#define HTT_TX_WBM_COMP_INFO0_REINJECT_REASON GENMASK(16, 13)
@ -466,7 +470,7 @@ enum htt_srng_ring_id {
* 3'b010: 4 usec
* 3'b011: 8 usec (default)
* 3'b100: 16 usec
* Others: Reserverd
* Others: Reserved
* b'19 - response_required:
* Host needs HTT_T2H_MSG_TYPE_SRING_SETUP_DONE as response
* b'20:31 - reserved: reserved for future use
@ -993,8 +997,7 @@ struct htt_rx_ring_tlv_filter {
#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END BIT(2)
#define HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING GENMASK(10, 3)
/**
* Enumeration for full monitor mode destination ring select
/* Enumeration for full monitor mode destination ring select
* 0 - REO destination ring select
* 1 - FW destination ring select
* 2 - SW destination ring select
@ -1391,8 +1394,7 @@ struct htt_ppdu_stats_info {
struct list_head list;
};
/**
* @brief target -> host packet log message
/* @brief target -> host packet log message
*
* @details
* The following field definitions describe the format of the packet log
@ -1430,8 +1432,7 @@ struct htt_pktlog_msg {
u8 payload[];
};
/**
* @brief host -> target FW extended statistics retrieve
/* @brief host -> target FW extended statistics retrieve
*
* @details
* The following field definitions describe the format of the HTT host
@ -1566,8 +1567,7 @@ struct htt_ext_stats_cfg_params {
u32 cfg3;
};
/**
* @brief target -> host extended statistics upload
/* @brief target -> host extended statistics upload
*
* @details
* The following field definitions describe the format of the HTT target

View file

@ -2499,7 +2499,7 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap
/* PN for multicast packets are not validate in HW,
* so skip 802.3 rx path
* Also, fast_rx expectes the STA to be authorized, hence
* 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 &&
@ -5197,7 +5197,8 @@ int ath11k_dp_rx_process_mon_status(struct ath11k_base *ab, int mac_id,
if (log_type != ATH11K_PKTLOG_TYPE_INVALID)
trace_ath11k_htt_rxdesc(ar, skb->data, log_type, rx_buf_sz);
memset(ppdu_info, 0, sizeof(struct hal_rx_mon_ppdu_info));
memset(ppdu_info, 0, sizeof(*ppdu_info));
ppdu_info->peer_id = HAL_INVALID_PEERID;
hal_status = ath11k_hal_rx_parse_mon_status(ab, ppdu_info, skb);
if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags) &&

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
@ -93,7 +94,8 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
u8 pool_id;
u8 hal_ring_id;
int ret;
u8 ring_selector = 0, ring_map = 0;
u32 ring_selector = 0;
u8 ring_map = 0;
bool tcl_ring_retry;
if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)))
@ -105,19 +107,13 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
/* Let the default ring selection be based on current processor
* number, where one of the 3 tcl rings are selected based on
* the smp_processor_id(). In case that ring
* is full/busy, we resort to other available rings.
* If all rings are full, we drop the packet.
* //TODO Add throttling logic when all rings are full
*/
ring_selector = smp_processor_id();
ring_selector = ab->hw_params.hw_ops->get_ring_selector(skb);
tcl_ring_sel:
tcl_ring_retry = false;
ti.ring_id = ring_selector % ab->hw_params.max_tx_ring;
ti.rbm_id = ab->hw_params.hal_params->tcl2wbm_rbm_map[ti.ring_id].rbm_id;
ring_map |= BIT(ti.ring_id);
@ -129,7 +125,8 @@ tcl_ring_sel:
spin_unlock_bh(&tx_ring->tx_idr_lock);
if (unlikely(ret < 0)) {
if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1)) {
if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1) ||
!ab->hw_params.tcl_ring_retry) {
atomic_inc(&ab->soc_stats.tx_err.misc_fail);
return -ENOSPC;
}
@ -247,7 +244,7 @@ tcl_ring_sel:
* Restart ring selection if some rings are not checked yet.
*/
if (unlikely(ring_map != (BIT(ab->hw_params.max_tx_ring)) - 1) &&
ab->hw_params.max_tx_ring > 1) {
ab->hw_params.tcl_ring_retry && ab->hw_params.max_tx_ring > 1) {
tcl_ring_retry = true;
ring_selector++;
}
@ -755,7 +752,7 @@ int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid,
return 0;
/* Can this be optimized so that we keep the pending command list only
* for tid delete command to free up the resoruce on the command status
* for tid delete command to free up the resource on the command status
* indication?
*/
dp_cmd = kzalloc(sizeof(*dp_cmd), GFP_ATOMIC);

View file

@ -126,7 +126,7 @@ static const struct hal_srng_config hw_srng_config_template[] = {
},
{ /* WBM2SW_RELEASE */
.start_ring_id = HAL_SRNG_RING_ID_WBM2SW0_RELEASE,
.max_rings = 4,
.max_rings = 5,
.entry_size = sizeof(struct hal_wbm_release_ring) >> 2,
.lmac_ring = false,
.ring_dir = HAL_SRNG_DIR_DST,
@ -1164,7 +1164,7 @@ void ath11k_hal_srng_shadow_update_hp_tp(struct ath11k_base *ab,
{
lockdep_assert_held(&srng->lock);
/* check whether the ring is emptry. Update the shadow
/* check whether the ring is empty. Update the shadow
* HP only when then ring isn't empty.
*/
if (srng->ring_dir == HAL_SRNG_DIR_SRC &&

View file

@ -243,7 +243,7 @@ struct ath11k_base;
#define HAL_WBM0_RELEASE_RING_HP 0x000030c0
#define HAL_WBM1_RELEASE_RING_HP 0x000030c8
/* TCL ring feild mask and offset */
/* TCL ring field mask and offset */
#define HAL_TCL1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8)
#define HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_TCL1_RING_ID_ENTRY_SIZE GENMASK(7, 0)
@ -268,7 +268,7 @@ struct ath11k_base;
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP6 GENMASK(20, 18)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP7 GENMASK(23, 21)
/* REO ring feild mask and offset */
/* REO ring field mask and offset */
#define HAL_REO1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8)
#define HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_REO1_RING_ID_RING_ID GENMASK(15, 8)
@ -389,6 +389,7 @@ enum hal_srng_ring_id {
HAL_SRNG_RING_ID_WBM2SW1_RELEASE,
HAL_SRNG_RING_ID_WBM2SW2_RELEASE,
HAL_SRNG_RING_ID_WBM2SW3_RELEASE,
HAL_SRNG_RING_ID_WBM2SW4_RELEASE,
HAL_SRNG_RING_ID_UMAC_ID_END = 127,
HAL_SRNG_RING_ID_LMAC1_ID_START,
@ -450,13 +451,13 @@ enum hal_ring_type {
/**
* enum hal_reo_cmd_type: Enum for REO command type
* @CMD_GET_QUEUE_STATS: Get REO queue status/stats
* @CMD_FLUSH_QUEUE: Flush all frames in REO queue
* @CMD_FLUSH_CACHE: Flush descriptor entries in the cache
* @CMD_UNBLOCK_CACHE: Unblock a descriptor's address that was blocked
* @HAL_REO_CMD_GET_QUEUE_STATS: Get REO queue status/stats
* @HAL_REO_CMD_FLUSH_QUEUE: Flush all frames in REO queue
* @HAL_REO_CMD_FLUSH_CACHE: Flush descriptor entries in the cache
* @HAL_REO_CMD_UNBLOCK_CACHE: Unblock a descriptor's address that was blocked
* earlier with a 'REO_FLUSH_CACHE' command
* @CMD_FLUSH_TIMEOUT_LIST: Flush buffers/descriptors from timeout list
* @CMD_UPDATE_RX_REO_QUEUE: Update REO queue settings
* @HAL_REO_CMD_FLUSH_TIMEOUT_LIST: Flush buffers/descriptors from timeout list
* @HAL_REO_CMD_UPDATE_RX_QUEUE: Update REO queue settings
*/
enum hal_reo_cmd_type {
HAL_REO_CMD_GET_QUEUE_STATS = 0,
@ -635,7 +636,7 @@ struct hal_srng {
} u;
};
/* Interrupt mitigation - Batch threshold in terms of numer of frames */
/* Interrupt mitigation - Batch threshold in terms of number of frames */
#define HAL_SRNG_INT_BATCH_THRESHOLD_TX 256
#define HAL_SRNG_INT_BATCH_THRESHOLD_RX 128
#define HAL_SRNG_INT_BATCH_THRESHOLD_OTHER 1
@ -678,6 +679,7 @@ enum hal_rx_buf_return_buf_manager {
HAL_RX_BUF_RBM_SW1_BM,
HAL_RX_BUF_RBM_SW2_BM,
HAL_RX_BUF_RBM_SW3_BM,
HAL_RX_BUF_RBM_SW4_BM,
};
#define HAL_SRNG_DESC_LOOP_CNT 0xf0000000
@ -873,8 +875,7 @@ struct hal_reo_status {
} u;
};
/**
* HAL context to be used to access SRNG APIs (currently used by data path
/* HAL context to be used to access SRNG APIs (currently used by data path
* and transport (CE) modules)
*/
struct ath11k_hal {

View file

@ -607,7 +607,7 @@ struct rx_msdu_desc {
*
* msdu_continuation
* When set, this MSDU buffer was not able to hold the entire MSDU.
* The next buffer will therefor contain additional information
* The next buffer will therefore contain additional information
* related to this MSDU.
*
* msdu_length
@ -643,7 +643,7 @@ struct rx_msdu_desc {
*
* da_idx_timeout
* Indicates, an unsuccessful MAC destination address search due
* to the expiration of search timer fot this MSDU.
* to the expiration of search timer for this MSDU.
*/
enum hal_reo_dest_ring_buffer_type {
@ -1678,7 +1678,7 @@ struct hal_wbm_release_ring {
* Producer: SW/TQM/RXDMA/REO/SWITCH
* Consumer: WBM/SW/FW
*
* HTT tx status is overlayed on wbm_release ring on 4-byte words 2, 3, 4 and 5
* HTT tx status is overlaid on wbm_release ring on 4-byte words 2, 3, 4 and 5
* for software based completions.
*
* buf_addr_info
@ -2159,7 +2159,7 @@ struct hal_reo_status_hdr {
* commands.
*
* execution_time (in us)
* The amount of time REO took to excecute the command. Note that
* The amount of time REO took to execute the command. Note that
* this time does not include the duration of the command waiting
* in the command ring, before the execution started.
*

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "hal_desc.h"
@ -44,8 +45,7 @@ void ath11k_hal_tx_cmd_desc_setup(struct ath11k_base *ab, void *cmd,
FIELD_PREP(BUFFER_ADDR_INFO1_ADDR,
((uint64_t)ti->paddr >> HAL_ADDR_MSB_REG_SHIFT));
tcl_cmd->buf_addr_info.info1 |=
FIELD_PREP(BUFFER_ADDR_INFO1_RET_BUF_MGR,
(ti->ring_id + HAL_RX_BUF_RBM_SW0_BM)) |
FIELD_PREP(BUFFER_ADDR_INFO1_RET_BUF_MGR, ti->rbm_id) |
FIELD_PREP(BUFFER_ADDR_INFO1_SW_COOKIE, ti->desc_id);
tcl_cmd->info0 =

View file

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_HAL_TX_H
@ -35,6 +36,7 @@ struct hal_tx_info {
u8 lmac_id;
u8 dscp_tid_tbl_idx;
bool enable_mesh;
u8 rbm_id;
};
/* TODO: Check if the actual desc macros can be used instead */

View file

@ -11,6 +11,7 @@
struct ath11k_hif_ops {
u32 (*read32)(struct ath11k_base *sc, u32 address);
void (*write32)(struct ath11k_base *sc, u32 address, u32 data);
int (*read)(struct ath11k_base *ab, void *buf, u32 start, u32 end);
void (*irq_enable)(struct ath11k_base *sc);
void (*irq_disable)(struct ath11k_base *sc);
int (*start)(struct ath11k_base *sc);
@ -99,6 +100,15 @@ static inline void ath11k_hif_write32(struct ath11k_base *sc, u32 address, u32 d
sc->hif.ops->write32(sc, address, data);
}
static inline int ath11k_hif_read(struct ath11k_base *ab, void *buf,
u32 start, u32 end)
{
if (!ab->hif.ops->read)
return -EOPNOTSUPP;
return ab->hif.ops->read(ab, buf, start, end);
}
static inline int ath11k_hif_map_service_to_pipe(struct ath11k_base *sc, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
{
@ -134,4 +144,5 @@ static inline void ath11k_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
else
*msi_data_idx = ce_id;
}
#endif /* _HIF_H_ */

View file

@ -820,6 +820,30 @@ static bool ath11k_hw_wcn6855_rx_desc_get_ldpc_support(struct hal_rx_desc *desc)
__le32_to_cpu(desc->u.wcn6855.msdu_start.info2));
}
static u32 ath11k_hw_ipq8074_get_tcl_ring_selector(struct sk_buff *skb)
{
/* Let the default ring selection be based on current processor
* number, where one of the 3 tcl rings are selected based on
* the smp_processor_id(). In case that ring
* is full/busy, we resort to other available rings.
* If all rings are full, we drop the packet.
*
* TODO: Add throttling logic when all rings are full
*/
return smp_processor_id();
}
static u32 ath11k_hw_wcn6750_get_tcl_ring_selector(struct sk_buff *skb)
{
/* Select the TCL ring based on the flow hash of the SKB instead
* of CPU ID. Since applications pumping the traffic can be scheduled
* on multiple CPUs, there is a chance that packets of the same flow
* could end on different TCL rings, this could sometimes results in
* an out of order arrival of the packets at the receiver.
*/
return skb_get_hash(skb);
}
const struct ath11k_hw_ops ipq8074_ops = {
.get_hw_mac_from_pdev_id = ath11k_hw_ipq8074_mac_from_pdev_id,
.wmi_init_config = ath11k_init_wmi_config_ipq8074,
@ -857,6 +881,7 @@ const struct ath11k_hw_ops ipq8074_ops = {
.mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
.rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
};
const struct ath11k_hw_ops ipq6018_ops = {
@ -896,6 +921,7 @@ const struct ath11k_hw_ops ipq6018_ops = {
.mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
.rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
};
const struct ath11k_hw_ops qca6390_ops = {
@ -935,6 +961,7 @@ const struct ath11k_hw_ops qca6390_ops = {
.mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
.rx_desc_mac_addr2_valid = ath11k_hw_ipq8074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq8074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
};
const struct ath11k_hw_ops qcn9074_ops = {
@ -974,6 +1001,7 @@ const struct ath11k_hw_ops qcn9074_ops = {
.mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
.rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
};
const struct ath11k_hw_ops wcn6855_ops = {
@ -1013,6 +1041,7 @@ const struct ath11k_hw_ops wcn6855_ops = {
.mpdu_info_get_peerid = ath11k_hw_wcn6855_mpdu_info_get_peerid,
.rx_desc_mac_addr2_valid = ath11k_hw_wcn6855_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_wcn6855_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_ipq8074_get_tcl_ring_selector,
};
const struct ath11k_hw_ops wcn6750_ops = {
@ -1052,11 +1081,14 @@ const struct ath11k_hw_ops wcn6750_ops = {
.mpdu_info_get_peerid = ath11k_hw_ipq8074_mpdu_info_get_peerid,
.rx_desc_mac_addr2_valid = ath11k_hw_ipq9074_rx_desc_mac_addr2_valid,
.rx_desc_mpdu_start_addr2 = ath11k_hw_ipq9074_rx_desc_mpdu_start_addr2,
.get_ring_selector = ath11k_hw_wcn6750_get_tcl_ring_selector,
};
#define ATH11K_TX_RING_MASK_0 0x1
#define ATH11K_TX_RING_MASK_1 0x2
#define ATH11K_TX_RING_MASK_2 0x4
#define ATH11K_TX_RING_MASK_0 BIT(0)
#define ATH11K_TX_RING_MASK_1 BIT(1)
#define ATH11K_TX_RING_MASK_2 BIT(2)
#define ATH11K_TX_RING_MASK_3 BIT(3)
#define ATH11K_TX_RING_MASK_4 BIT(4)
#define ATH11K_RX_RING_MASK_0 0x1
#define ATH11K_RX_RING_MASK_1 0x2
@ -1903,6 +1935,43 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074 = {
},
};
const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_wcn6750 = {
.tx = {
ATH11K_TX_RING_MASK_0,
0,
ATH11K_TX_RING_MASK_2,
0,
ATH11K_TX_RING_MASK_4,
},
.rx_mon_status = {
0, 0, 0, 0, 0, 0,
ATH11K_RX_MON_STATUS_RING_MASK_0,
},
.rx = {
0, 0, 0, 0, 0, 0, 0,
ATH11K_RX_RING_MASK_0,
ATH11K_RX_RING_MASK_1,
ATH11K_RX_RING_MASK_2,
ATH11K_RX_RING_MASK_3,
},
.rx_err = {
0, ATH11K_RX_ERR_RING_MASK_0,
},
.rx_wbm_rel = {
0, ATH11K_RX_WBM_REL_RING_MASK_0,
},
.reo_status = {
0, ATH11K_REO_STATUS_RING_MASK_0,
},
.rxdma2host = {
ATH11K_RXDMA2HOST_RING_MASK_0,
ATH11K_RXDMA2HOST_RING_MASK_1,
ATH11K_RXDMA2HOST_RING_MASK_2,
},
.host2rxdma = {
},
};
const struct ath11k_hw_regs ipq8074_regs = {
/* SW2TCL(x) R0 ring configuration address */
.hal_tcl1_ring_base_lsb = 0x00000510,
@ -2332,12 +2401,55 @@ const struct ath11k_hw_regs wcn6750_regs = {
.hal_reo1_misc_ctl = 0x000005d8,
};
static const struct ath11k_hw_tcl2wbm_rbm_map ath11k_hw_tcl2wbm_rbm_map_ipq8074[] = {
{
.tcl_ring_num = 0,
.wbm_ring_num = 0,
.rbm_id = HAL_RX_BUF_RBM_SW0_BM,
},
{
.tcl_ring_num = 1,
.wbm_ring_num = 1,
.rbm_id = HAL_RX_BUF_RBM_SW1_BM,
},
{
.tcl_ring_num = 2,
.wbm_ring_num = 2,
.rbm_id = HAL_RX_BUF_RBM_SW2_BM,
},
};
static const struct ath11k_hw_tcl2wbm_rbm_map ath11k_hw_tcl2wbm_rbm_map_wcn6750[] = {
{
.tcl_ring_num = 0,
.wbm_ring_num = 0,
.rbm_id = HAL_RX_BUF_RBM_SW0_BM,
},
{
.tcl_ring_num = 1,
.wbm_ring_num = 4,
.rbm_id = HAL_RX_BUF_RBM_SW4_BM,
},
{
.tcl_ring_num = 2,
.wbm_ring_num = 2,
.rbm_id = HAL_RX_BUF_RBM_SW2_BM,
},
};
const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = {
.rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM,
.tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq8074,
};
const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390 = {
.rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM,
.tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq8074,
};
const struct ath11k_hw_hal_params ath11k_hw_hal_params_wcn6750 = {
.rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM,
.tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_wcn6750,
};
static const struct cfg80211_sar_freq_ranges ath11k_hw_sar_freq_ranges_wcn6855[] = {

View file

@ -122,8 +122,15 @@ struct ath11k_hw_ring_mask {
u8 host2rxdma[ATH11K_EXT_IRQ_GRP_NUM_MAX];
};
struct ath11k_hw_tcl2wbm_rbm_map {
u8 tcl_ring_num;
u8 wbm_ring_num;
u8 rbm_id;
};
struct ath11k_hw_hal_params {
enum hal_rx_buf_return_buf_manager rx_buf_rbm;
const struct ath11k_hw_tcl2wbm_rbm_map *tcl2wbm_rbm_map;
};
struct ath11k_hw_params {
@ -166,6 +173,7 @@ struct ath11k_hw_params {
u8 summary_pad_sz;
u8 fft_hdr_len;
u16 max_fft_bins;
bool fragment_160mhz;
} spectral;
u16 interface_modes;
@ -175,6 +183,7 @@ struct ath11k_hw_params {
bool idle_ps;
bool supports_sta_ps;
bool cold_boot_calib;
bool cbcal_restart_fw;
int fw_mem_mode;
u32 num_vdevs;
u32 num_peers;
@ -200,6 +209,16 @@ struct ath11k_hw_params {
bool hybrid_bus_type;
bool fixed_fw_mem;
bool support_off_channel_tx;
bool supports_multi_bssid;
struct {
u32 start;
u32 end;
} sram_dump;
bool tcl_ring_retry;
u32 tx_ring_size;
bool smp2p_wow_exit;
};
struct ath11k_hw_ops {
@ -242,6 +261,7 @@ struct ath11k_hw_ops {
u16 (*mpdu_info_get_peerid)(u8 *tlv_data);
bool (*rx_desc_mac_addr2_valid)(struct hal_rx_desc *desc);
u8* (*rx_desc_mpdu_start_addr2)(struct hal_rx_desc *desc);
u32 (*get_ring_selector)(struct sk_buff *skb);
};
extern const struct ath11k_hw_ops ipq8074_ops;
@ -254,9 +274,11 @@ extern const struct ath11k_hw_ops wcn6750_ops;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_ipq8074;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qca6390;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn9074;
extern const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_wcn6750;
extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074;
extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390;
extern const struct ath11k_hw_hal_params ath11k_hw_hal_params_wcn6750;
static inline
int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw,
@ -397,4 +419,5 @@ static inline const char *ath11k_bd_ie_type_str(enum ath11k_bd_ie_type type)
}
extern const struct cfg80211_sar_capa ath11k_hw_sar_capa_wcn6855;
#endif

View file

@ -3059,7 +3059,7 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar,
return ret;
}
/* Enable all patial BSSID mask for SRG */
/* Enable all partial BSSID mask for SRG */
ret = ath11k_wmi_pdev_srg_obss_bssid_enable_bitmap(ar, bitmap);
if (ret) {
ath11k_warn(ar->ab,
@ -3077,7 +3077,7 @@ static int ath11k_mac_config_obss_pd(struct ath11k *ar,
return ret;
}
/* Enable all patial BSSID mask for non-SRG */
/* Enable all partial BSSID mask for non-SRG */
ret = ath11k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(ar, bitmap);
if (ret) {
ath11k_warn(ar->ab,
@ -3350,10 +3350,15 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
ath11k_recalculate_mgmt_rate(ar, vif, &def);
if (changed & BSS_CHANGED_TWT) {
if (info->twt_requester || info->twt_responder)
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id);
else
struct wmi_twt_enable_params twt_params = {0};
if (info->twt_requester || info->twt_responder) {
ath11k_wmi_fill_default_twt_params(&twt_params);
ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id,
&twt_params);
} else {
ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
}
}
if (changed & BSS_CHANGED_HE_OBSS_PD)
@ -3451,7 +3456,7 @@ void __ath11k_mac_scan_finish(struct ath11k *ar)
ar->scan_channel = NULL;
ar->scan.roc_freq = 0;
cancel_delayed_work(&ar->scan.timeout);
complete(&ar->scan.completed);
complete_all(&ar->scan.completed);
break;
}
}
@ -4524,6 +4529,7 @@ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
new_state == IEEE80211_STA_NONE) {
memset(arsta, 0, sizeof(*arsta));
arsta->arvif = arvif;
arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
INIT_WORK(&arsta->update_wk, ath11k_sta_rc_update_wk);
INIT_WORK(&arsta->set_4addr_wk, ath11k_sta_set_4addr_wk);
@ -4954,6 +4960,8 @@ static int ath11k_mac_set_txbf_conf(struct ath11k_vif *arvif)
if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) {
nsts = vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
if (nsts > (ar->num_rx_chains - 1))
nsts = ar->num_rx_chains - 1;
value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
}
@ -4994,7 +5002,7 @@ static int ath11k_mac_set_txbf_conf(struct ath11k_vif *arvif)
static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
{
bool subfer, subfee;
int sound_dim = 0;
int sound_dim = 0, nsts = 0;
subfer = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE));
subfee = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
@ -5004,6 +5012,11 @@ static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
subfer = false;
}
if (ar->num_rx_chains < 2) {
*vht_cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
subfee = false;
}
/* If SU Beaformer is not set, then disable MU Beamformer Capability */
if (!subfer)
*vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
@ -5016,7 +5029,9 @@ static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
*vht_cap &= ~IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
/* TODO: Need to check invalid STS and Sound_dim values set by FW? */
nsts = (*vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
*vht_cap &= ~IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
/* Enable Sounding Dimension Field only if SU BF is enabled */
if (subfer) {
@ -5028,9 +5043,15 @@ static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
*vht_cap |= sound_dim;
}
/* Use the STS advertised by FW unless SU Beamformee is not supported*/
if (!subfee)
*vht_cap &= ~(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
/* Enable Beamformee STS Field only if SU BF is enabled */
if (subfee) {
if (nsts > (ar->num_rx_chains - 1))
nsts = ar->num_rx_chains - 1;
nsts <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
nsts &= IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
*vht_cap |= nsts;
}
}
static struct ieee80211_sta_vht_cap
@ -6173,6 +6194,13 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
goto err;
}
/* In the case of hardware recovery, debugfs files are
* not deleted since ieee80211_ops.remove_interface() is
* not invoked. In such cases, try to delete the files.
* These will be re-created later.
*/
ath11k_debugfs_remove_interface(arvif);
memset(arvif, 0, sizeof(*arvif));
arvif->ar = ar;
@ -6354,9 +6382,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
}
}
ret = ath11k_debugfs_add_interface(arvif);
if (ret)
goto err_peer_del;
ath11k_debugfs_add_interface(arvif);
mutex_unlock(&ar->conf_mutex);
@ -8421,6 +8447,95 @@ exit:
return ret;
}
static int ath11k_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);
spin_lock_bh(&ar->data_lock);
ar->fw_stats_done = false;
ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
spin_unlock_bh(&ar->data_lock);
reinit_completion(&ar->fw_stats_complete);
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;
return 0;
}
static int ath11k_mac_op_get_txpower(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
int *dbm)
{
struct ath11k *ar = hw->priv;
struct ath11k_base *ab = ar->ab;
struct stats_request_params req_param = {0};
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);
if (ar->state != ATH11K_STATE_ON)
goto err_fallback;
req_param.pdev_id = ar->pdev->pdev_id;
req_param.stats_id = WMI_REQUEST_PDEV_STAT;
ret = ath11k_fw_stats_request(ar, &req_param);
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 const struct ieee80211_ops ath11k_ops = {
.tx = ath11k_mac_op_tx,
.start = ath11k_mac_op_start,
@ -8471,6 +8586,7 @@ static const struct ieee80211_ops ath11k_ops = {
#if IS_ENABLED(CONFIG_IPV6)
.ipv6_addr_change = ath11k_mac_op_ipv6_changed,
#endif
.get_txpower = ath11k_mac_op_get_txpower,
.set_sar_specs = ath11k_mac_op_set_bios_sar_specs,
.remain_on_channel = ath11k_mac_op_remain_on_channel,
@ -8777,6 +8893,11 @@ static int __ath11k_mac_register(struct ath11k *ar)
if (ab->hw_params.single_pdev_only && ar->supports_6ghz)
ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS);
if (ab->hw_params.supports_multi_bssid) {
ieee80211_hw_set(ar->hw, SUPPORTS_MULTI_BSSID);
ieee80211_hw_set(ar->hw, SUPPORTS_ONLY_HE_MULTI_BSSID);
}
ieee80211_hw_set(ar->hw, SIGNAL_DBM);
ieee80211_hw_set(ar->hw, SUPPORTS_PS);
ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
@ -8967,6 +9088,7 @@ int ath11k_mac_register(struct ath11k_base *ab)
struct ath11k_pdev *pdev;
int i;
int ret;
u8 mac_addr[ETH_ALEN] = {0};
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
return 0;
@ -8979,13 +9101,18 @@ int ath11k_mac_register(struct ath11k_base *ab)
if (ret)
return ret;
device_get_mac_address(ab->dev, mac_addr);
for (i = 0; i < ab->num_radios; i++) {
pdev = &ab->pdevs[i];
ar = pdev->ar;
if (ab->pdevs_macaddr_valid) {
ether_addr_copy(ar->mac_addr, pdev->mac_addr);
} else {
ether_addr_copy(ar->mac_addr, ab->mac_addr);
if (is_zero_ether_addr(mac_addr))
ether_addr_copy(ar->mac_addr, ab->mac_addr);
else
ether_addr_copy(ar->mac_addr, mac_addr);
ar->mac_addr[4] += i;
}
@ -9079,6 +9206,8 @@ int ath11k_mac_allocate(struct ath11k_base *ab)
clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);
ar->vdev_id_11d_scan = ATH11K_11D_INVALID_VDEV_ID;
init_completion(&ar->completed_11d_scan);
ath11k_fw_stats_init(ar);
}
return 0;

View file

@ -402,8 +402,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
ret = ath11k_mhi_get_msi(ab_pci);
if (ret) {
ath11k_err(ab, "failed to get msi for mhi\n");
mhi_free_controller(mhi_ctrl);
return ret;
goto free_controller;
}
if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
@ -412,7 +411,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {
ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl);
if (ret < 0)
return ret;
goto free_controller;
} else {
mhi_ctrl->iova_start = 0;
mhi_ctrl->iova_stop = 0xFFFFFFFF;
@ -440,18 +439,22 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci)
default:
ath11k_err(ab, "failed assign mhi_config for unknown hw rev %d\n",
ab->hw_rev);
mhi_free_controller(mhi_ctrl);
return -EINVAL;
ret = -EINVAL;
goto free_controller;
}
ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config);
if (ret) {
ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret);
mhi_free_controller(mhi_ctrl);
return ret;
goto free_controller;
}
return 0;
free_controller:
mhi_free_controller(mhi_ctrl);
ab_pci->mhi_ctrl = NULL;
return ret;
}
void ath11k_mhi_unregister(struct ath11k_pci *ab_pci)

View file

@ -685,6 +685,7 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.stop = ath11k_pcic_stop,
.read32 = ath11k_pcic_read32,
.write32 = ath11k_pcic_write32,
.read = ath11k_pcic_read,
.power_down = ath11k_pci_power_down,
.power_up = ath11k_pci_power_up,
.suspend = ath11k_pci_hif_suspend,

View file

@ -140,55 +140,100 @@ int ath11k_pcic_init_msi_config(struct ath11k_base *ab)
}
EXPORT_SYMBOL(ath11k_pcic_init_msi_config);
void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value)
static void __ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value)
{
int ret = 0;
/* for offset beyond BAR + 4K - 32, may
* need to wakeup the device to access.
*/
if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup)
ret = ab->pci.ops->wakeup(ab);
if (offset < ATH11K_PCI_WINDOW_START)
iowrite32(value, ab->mem + offset);
else
ab->pci.ops->window_write32(ab, offset, value);
if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release &&
!ret)
ab->pci.ops->release(ab);
}
EXPORT_SYMBOL(ath11k_pcic_write32);
u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset)
void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value)
{
int ret = 0;
u32 val;
bool wakeup_required;
/* for offset beyond BAR + 4K - 32, may
* need to wakeup the device to access.
*/
if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup)
wakeup_required = test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF;
if (wakeup_required && ab->pci.ops->wakeup)
ret = ab->pci.ops->wakeup(ab);
__ath11k_pcic_write32(ab, offset, value);
if (wakeup_required && !ret && ab->pci.ops->release)
ab->pci.ops->release(ab);
}
EXPORT_SYMBOL(ath11k_pcic_write32);
static u32 __ath11k_pcic_read32(struct ath11k_base *ab, u32 offset)
{
u32 val;
if (offset < ATH11K_PCI_WINDOW_START)
val = ioread32(ab->mem + offset);
else
val = ab->pci.ops->window_read32(ab, offset);
if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release &&
!ret)
return val;
}
u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset)
{
int ret = 0;
u32 val;
bool wakeup_required;
/* for offset beyond BAR + 4K - 32, may
* need to wakeup the device to access.
*/
wakeup_required = test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF;
if (wakeup_required && ab->pci.ops->wakeup)
ret = ab->pci.ops->wakeup(ab);
val = __ath11k_pcic_read32(ab, offset);
if (wakeup_required && !ret && ab->pci.ops->release)
ab->pci.ops->release(ab);
return val;
}
EXPORT_SYMBOL(ath11k_pcic_read32);
int ath11k_pcic_read(struct ath11k_base *ab, void *buf, u32 start, u32 end)
{
int ret = 0;
bool wakeup_required;
u32 *data = buf;
u32 i;
/* for offset beyond BAR + 4K - 32, may
* need to wakeup the device to access.
*/
wakeup_required = test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
end >= ATH11K_PCI_ACCESS_ALWAYS_OFF;
if (wakeup_required && ab->pci.ops->wakeup) {
ret = ab->pci.ops->wakeup(ab);
if (ret) {
ath11k_warn(ab, "failed to wakeup for read from 0x%x: %d\n",
start, ret);
return ret;
}
}
for (i = start; i < end + 1; i += 4)
*data++ = __ath11k_pcic_read32(ab, i);
if (wakeup_required && ab->pci.ops->release)
ab->pci.ops->release(ab);
return 0;
}
EXPORT_SYMBOL(ath11k_pcic_read);
void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo,
u32 *msi_addr_hi)
{
@ -414,6 +459,7 @@ void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab)
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
if (!irq_grp->napi_enabled) {
dev_set_threaded(&irq_grp->napi_ndev, true);
napi_enable(&irq_grp->napi);
irq_grp->napi_enabled = true;
}
@ -731,3 +777,37 @@ int ath11k_pcic_register_pci_ops(struct ath11k_base *ab,
return 0;
}
EXPORT_SYMBOL(ath11k_pcic_register_pci_ops);
void ath11k_pci_enable_ce_irqs_except_wake_irq(struct ath11k_base *ab)
{
int i;
for (i = 0; i < ab->hw_params.ce_count; i++) {
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR ||
i == ATH11K_PCI_CE_WAKE_IRQ)
continue;
ath11k_pcic_ce_irq_enable(ab, i);
}
}
EXPORT_SYMBOL(ath11k_pci_enable_ce_irqs_except_wake_irq);
void ath11k_pci_disable_ce_irqs_except_wake_irq(struct ath11k_base *ab)
{
int i;
int irq_idx;
struct ath11k_ce_pipe *ce_pipe;
for (i = 0; i < ab->hw_params.ce_count; i++) {
ce_pipe = &ab->ce.ce_pipe[i];
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR ||
i == ATH11K_PCI_CE_WAKE_IRQ)
continue;
disable_irq_nosync(ab->irq_num[irq_idx]);
synchronize_irq(ab->irq_num[irq_idx]);
tasklet_kill(&ce_pipe->intr_tq);
}
}
EXPORT_SYMBOL(ath11k_pci_disable_ce_irqs_except_wake_irq);

View file

@ -12,6 +12,8 @@
#define ATH11K_PCI_IRQ_CE0_OFFSET 3
#define ATH11K_PCI_IRQ_DP_OFFSET 14
#define ATH11K_PCI_CE_WAKE_IRQ 2
#define ATH11K_PCI_WINDOW_ENABLE_BIT 0x40000000
#define ATH11K_PCI_WINDOW_REG_ADDRESS 0x310c
#define ATH11K_PCI_WINDOW_VALUE_MASK GENMASK(24, 19)
@ -45,4 +47,8 @@ void ath11k_pcic_ce_irq_disable_sync(struct ath11k_base *ab);
int ath11k_pcic_init_msi_config(struct ath11k_base *ab);
int ath11k_pcic_register_pci_ops(struct ath11k_base *ab,
const struct ath11k_pci_ops *pci_ops);
int ath11k_pcic_read(struct ath11k_base *ab, void *buf, u32 start, u32 end);
void ath11k_pci_enable_ce_irqs_except_wake_irq(struct ath11k_base *ab);
void ath11k_pci_disable_ce_irqs_except_wake_irq(struct ath11k_base *ab);
#endif

View file

@ -302,6 +302,21 @@ static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr)
spin_lock_bh(&ab->base_lock);
peer = ath11k_peer_find_by_addr(ab, addr);
/* Check if the found peer is what we want to remove.
* While the sta is transitioning to another band we may
* have 2 peer with the same addr assigned to different
* vdev_id. Make sure we are deleting the correct peer.
*/
if (peer && peer->vdev_id == vdev_id)
ath11k_peer_rhash_delete(ab, peer);
/* Fallback to peer list search if the correct peer can't be found.
* Skip the deletion of the peer from the rhash since it has already
* been deleted in peer add.
*/
if (!peer)
peer = ath11k_peer_find(ab, vdev_id, addr);
if (!peer) {
spin_unlock_bh(&ab->base_lock);
mutex_unlock(&ab->tbl_mtx_lock);
@ -312,8 +327,6 @@ static int __ath11k_peer_delete(struct ath11k *ar, u32 vdev_id, const u8 *addr)
return -EINVAL;
}
ath11k_peer_rhash_delete(ab, peer);
spin_unlock_bh(&ab->base_lock);
mutex_unlock(&ab->tbl_mtx_lock);
@ -372,8 +385,17 @@ int ath11k_peer_create(struct ath11k *ar, struct ath11k_vif *arvif,
spin_lock_bh(&ar->ab->base_lock);
peer = ath11k_peer_find_by_addr(ar->ab, param->peer_addr);
if (peer) {
spin_unlock_bh(&ar->ab->base_lock);
return -EINVAL;
if (peer->vdev_id == param->vdev_id) {
spin_unlock_bh(&ar->ab->base_lock);
return -EINVAL;
}
/* Assume sta is transitioning to another band.
* Remove here the peer from rhash.
*/
mutex_lock(&ar->ab->tbl_mtx_lock);
ath11k_peer_rhash_delete(ar->ab, peer);
mutex_unlock(&ar->ab->tbl_mtx_lock);
}
spin_unlock_bh(&ar->ab->base_lock);

View file

@ -1696,6 +1696,13 @@ static struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = {
},
};
static struct qmi_elem_info qmi_wlfw_fw_init_done_ind_msg_v01_ei[] = {
{
.data_type = QMI_EOTI,
.array_type = NO_ARRAY,
},
};
static int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
{
struct qmi_wlanfw_host_cap_req_msg_v01 req;
@ -1872,7 +1879,7 @@ static int ath11k_qmi_respond_fw_mem_request(struct ath11k_base *ab)
/* For QCA6390 by default FW requests a block of ~4M contiguous
* DMA memory, it's hard to allocate from OS. So host returns
* failure to FW and FW will then request mulitple blocks of small
* failure to FW and FW will then request multiple blocks of small
* chunk size memory.
*/
if (!(ab->hw_params.fixed_mem_region ||
@ -3006,6 +3013,12 @@ static void ath11k_qmi_msg_fw_ready_cb(struct qmi_handle *qmi_hdl,
struct ath11k_base *ab = qmi->ab;
ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware ready\n");
if (!ab->qmi.cal_done) {
ab->qmi.cal_done = 1;
wake_up(&ab->qmi.cold_boot_waitq);
}
ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_READY, NULL);
}
@ -3023,6 +3036,19 @@ static void ath11k_qmi_msg_cold_boot_cal_done_cb(struct qmi_handle *qmi_hdl,
ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi cold boot calibration done\n");
}
static void ath11k_qmi_msg_fw_init_done_cb(struct qmi_handle *qmi_hdl,
struct sockaddr_qrtr *sq,
struct qmi_txn *txn,
const void *decoded)
{
struct ath11k_qmi *qmi = container_of(qmi_hdl,
struct ath11k_qmi, handle);
struct ath11k_base *ab = qmi->ab;
ath11k_qmi_driver_event_post(qmi, ATH11K_QMI_EVENT_FW_INIT_DONE, NULL);
ath11k_dbg(ab, ATH11K_DBG_QMI, "qmi firmware init done\n");
}
static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = {
{
.type = QMI_INDICATION,
@ -3053,6 +3079,14 @@ static const struct qmi_msg_handler ath11k_qmi_msg_handlers[] = {
sizeof(struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01),
.fn = ath11k_qmi_msg_cold_boot_cal_done_cb,
},
{
.type = QMI_INDICATION,
.msg_id = QMI_WLFW_FW_INIT_DONE_IND_V01,
.ei = qmi_wlfw_fw_init_done_ind_msg_v01_ei,
.decoded_size =
sizeof(struct qmi_wlfw_fw_init_done_ind_msg_v01),
.fn = ath11k_qmi_msg_fw_init_done_cb,
},
};
static int ath11k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
@ -3145,7 +3179,7 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
}
break;
case ATH11K_QMI_EVENT_FW_READY:
case ATH11K_QMI_EVENT_FW_INIT_DONE:
clear_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
ath11k_hal_dump_srng_stats(ab);
@ -3168,6 +3202,22 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
}
break;
case ATH11K_QMI_EVENT_FW_READY:
/* For targets requiring a FW restart upon cold
* boot completion, there is no need to process
* FW ready; such targets will receive FW init
* done message after FW restart.
*/
if (ab->hw_params.cbcal_restart_fw)
break;
clear_bit(ATH11K_FLAG_CRASH_FLUSH,
&ab->dev_flags);
clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
ath11k_core_qmi_firmware_ready(ab);
set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
break;
case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
break;

View file

@ -31,8 +31,9 @@
#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0021
#define QMI_WLFW_FW_READY_IND_V01 0x0038
#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x003E
#define QMI_WLFW_FW_READY_IND_V01 0x0021
#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038
#define QMI_WLANFW_MAX_DATA_SIZE_V01 6144
#define ATH11K_FIRMWARE_MODE_OFF 4
@ -69,6 +70,7 @@ enum ath11k_qmi_event_type {
ATH11K_QMI_EVENT_FORCE_FW_ASSERT,
ATH11K_QMI_EVENT_POWER_UP,
ATH11K_QMI_EVENT_POWER_DOWN,
ATH11K_QMI_EVENT_FW_INIT_DONE,
ATH11K_QMI_EVENT_MAX,
};
@ -291,6 +293,10 @@ struct qmi_wlanfw_fw_cold_cal_done_ind_msg_v01 {
char placeholder;
};
struct qmi_wlfw_fw_init_done_ind_msg_v01 {
char placeholder;
};
#define QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN 0
#define QMI_WLANFW_CAP_RESP_MSG_V01_MAX_LEN 235
#define QMI_WLANFW_CAP_REQ_V01 0x0024

View file

@ -877,7 +877,7 @@ struct rx_msdu_start_wcn6855 {
*
* l4_offset
* Depending upon mode bit, this field either indicates the
* L4 offset nin bytes from the start of RX_HEADER (only valid
* L4 offset in bytes from the start of RX_HEADER (only valid
* if either ipv4_proto or ipv6_proto is set to 1) or indicates
* the offset in bytes to the start of TCP or UDP header from
* the start of the IP header after decapsulation (Only valid if

View file

@ -30,6 +30,7 @@
#define ATH11K_SPECTRAL_20MHZ 20
#define ATH11K_SPECTRAL_40MHZ 40
#define ATH11K_SPECTRAL_80MHZ 80
#define ATH11K_SPECTRAL_160MHZ 160
#define ATH11K_SPECTRAL_SIGNATURE 0xFA
@ -183,6 +184,8 @@ static int ath11k_spectral_scan_trigger(struct ath11k *ar)
if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED)
return 0;
ar->spectral.is_primary = true;
ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE);
@ -585,6 +588,7 @@ int ath11k_spectral_process_fft(struct ath11k *ar,
u8 chan_width_mhz, bin_sz;
int ret;
u32 check_length;
bool fragment_sample = false;
lockdep_assert_held(&ar->spectral.lock);
@ -639,6 +643,13 @@ int ath11k_spectral_process_fft(struct ath11k *ar,
case ATH11K_SPECTRAL_80MHZ:
fft_sample->chan_width_mhz = chan_width_mhz;
break;
case ATH11K_SPECTRAL_160MHZ:
if (ab->hw_params.spectral.fragment_160mhz) {
chan_width_mhz /= 2;
fragment_sample = true;
}
fft_sample->chan_width_mhz = chan_width_mhz;
break;
default:
ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz);
return -EINVAL;
@ -663,6 +674,17 @@ int ath11k_spectral_process_fft(struct ath11k *ar,
freq = summary->meta.freq2;
fft_sample->freq2 = __cpu_to_be16(freq);
/* If freq2 is available then the spectral scan results are fragmented
* as primary and secondary
*/
if (fragment_sample && freq) {
if (!ar->spectral.is_primary)
fft_sample->freq1 = cpu_to_be16(freq);
/* We have to toggle the is_primary to handle the next report */
ar->spectral.is_primary = !ar->spectral.is_primary;
}
ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins,
ab->hw_params.spectral.fft_sz);

View file

@ -35,6 +35,7 @@ struct ath11k_spectral {
u16 count;
u8 fft_size;
bool enabled;
bool is_primary;
};
#ifdef CONFIG_ATH11K_SPECTRAL

View file

@ -99,7 +99,7 @@ static ssize_t ath11k_thermal_show_temp(struct device *dev,
temperature = ar->thermal.temperature;
spin_unlock_bh(&ar->data_lock);
/* display in millidegree celcius */
/* display in millidegree Celsius */
ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
out:
mutex_unlock(&ar->conf_mutex);

View file

@ -19,7 +19,7 @@ struct ath11k_thermal {
/* protected by conf_mutex */
u32 throttle_state;
/* temperature value in Celcius degree
/* temperature value in Celsius degree
* protected by data_lock
*/
int temperature;

View file

@ -305,6 +305,34 @@ TRACE_EVENT(ath11k_wmi_diag,
)
);
TRACE_EVENT(ath11k_ps_timekeeper,
TP_PROTO(struct ath11k *ar, const void *peer_addr,
u32 peer_ps_timestamp, u8 peer_ps_state),
TP_ARGS(ar, peer_addr, peer_ps_timestamp, peer_ps_state),
TP_STRUCT__entry(__string(device, dev_name(ar->ab->dev))
__string(driver, dev_driver_string(ar->ab->dev))
__dynamic_array(u8, peer_addr, ETH_ALEN)
__field(u8, peer_ps_state)
__field(u32, peer_ps_timestamp)
),
TP_fast_assign(__assign_str(device, dev_name(ar->ab->dev));
__assign_str(driver, dev_driver_string(ar->ab->dev));
memcpy(__get_dynamic_array(peer_addr), peer_addr,
ETH_ALEN);
__entry->peer_ps_state = peer_ps_state;
__entry->peer_ps_timestamp = peer_ps_timestamp;
),
TP_printk("%s %s %u %u",
__get_str(driver),
__get_str(device),
__entry->peer_ps_state,
__entry->peer_ps_timestamp
)
);
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
/* we don't want to use include/trace/events */

View file

@ -416,7 +416,7 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
/* tx/rx chainmask reported from fw depends on the actual hw chains used,
* For example, for 4x4 capable macphys, first 4 chains can be used for first
* mac and the remaing 4 chains can be used for the second mac or vice-versa.
* mac and the remaining 4 chains can be used for the second mac or vice-versa.
* In this case, tx/rx chainmask 0xf will be advertised for first mac and 0xf0
* will be advertised for second mac or vice-versa. Compute the shift value
* for tx/rx chainmask which will be used to advertise supported ht/vht rates to
@ -991,9 +991,13 @@ int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
{
struct ath11k_pdev_wmi *wmi = ar->wmi;
struct wmi_vdev_up_cmd *cmd;
struct ieee80211_bss_conf *bss_conf;
struct ath11k_vif *arvif;
struct sk_buff *skb;
int ret;
arvif = ath11k_mac_get_arvif(ar, vdev_id);
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
if (!skb)
return -ENOMEM;
@ -1007,6 +1011,17 @@ int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
ether_addr_copy(cmd->vdev_bssid.addr, bssid);
if (arvif && arvif->vif->type == NL80211_IFTYPE_STATION) {
bss_conf = &arvif->vif->bss_conf;
if (bss_conf->nontransmitted) {
ether_addr_copy(cmd->trans_bssid.addr,
bss_conf->transmitter_bssid);
cmd->profile_idx = bss_conf->bssid_index;
cmd->profile_num = bss_conf->bssid_indicator;
}
}
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_VDEV_UP_CMDID);
if (ret) {
ath11k_warn(ar->ab, "failed to submit WMI_VDEV_UP cmd\n");
@ -3064,8 +3079,34 @@ int ath11k_wmi_pdev_pktlog_disable(struct ath11k *ar)
return ret;
}
int
ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id)
void ath11k_wmi_fill_default_twt_params(struct wmi_twt_enable_params *twt_params)
{
twt_params->sta_cong_timer_ms = ATH11K_TWT_DEF_STA_CONG_TIMER_MS;
twt_params->default_slot_size = ATH11K_TWT_DEF_DEFAULT_SLOT_SIZE;
twt_params->congestion_thresh_setup = ATH11K_TWT_DEF_CONGESTION_THRESH_SETUP;
twt_params->congestion_thresh_teardown =
ATH11K_TWT_DEF_CONGESTION_THRESH_TEARDOWN;
twt_params->congestion_thresh_critical =
ATH11K_TWT_DEF_CONGESTION_THRESH_CRITICAL;
twt_params->interference_thresh_teardown =
ATH11K_TWT_DEF_INTERFERENCE_THRESH_TEARDOWN;
twt_params->interference_thresh_setup =
ATH11K_TWT_DEF_INTERFERENCE_THRESH_SETUP;
twt_params->min_no_sta_setup = ATH11K_TWT_DEF_MIN_NO_STA_SETUP;
twt_params->min_no_sta_teardown = ATH11K_TWT_DEF_MIN_NO_STA_TEARDOWN;
twt_params->no_of_bcast_mcast_slots = ATH11K_TWT_DEF_NO_OF_BCAST_MCAST_SLOTS;
twt_params->min_no_twt_slots = ATH11K_TWT_DEF_MIN_NO_TWT_SLOTS;
twt_params->max_no_sta_twt = ATH11K_TWT_DEF_MAX_NO_STA_TWT;
twt_params->mode_check_interval = ATH11K_TWT_DEF_MODE_CHECK_INTERVAL;
twt_params->add_sta_slot_interval = ATH11K_TWT_DEF_ADD_STA_SLOT_INTERVAL;
twt_params->remove_sta_slot_interval =
ATH11K_TWT_DEF_REMOVE_STA_SLOT_INTERVAL;
/* TODO add MBSSID support */
twt_params->mbss_support = 0;
}
int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id,
struct wmi_twt_enable_params *params)
{
struct ath11k_pdev_wmi *wmi = ar->wmi;
struct ath11k_base *ab = wmi->wmi_ab->ab;
@ -3083,28 +3124,22 @@ ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id)
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_ENABLE_CMD) |
FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
cmd->pdev_id = pdev_id;
cmd->sta_cong_timer_ms = ATH11K_TWT_DEF_STA_CONG_TIMER_MS;
cmd->default_slot_size = ATH11K_TWT_DEF_DEFAULT_SLOT_SIZE;
cmd->congestion_thresh_setup = ATH11K_TWT_DEF_CONGESTION_THRESH_SETUP;
cmd->congestion_thresh_teardown =
ATH11K_TWT_DEF_CONGESTION_THRESH_TEARDOWN;
cmd->congestion_thresh_critical =
ATH11K_TWT_DEF_CONGESTION_THRESH_CRITICAL;
cmd->interference_thresh_teardown =
ATH11K_TWT_DEF_INTERFERENCE_THRESH_TEARDOWN;
cmd->interference_thresh_setup =
ATH11K_TWT_DEF_INTERFERENCE_THRESH_SETUP;
cmd->min_no_sta_setup = ATH11K_TWT_DEF_MIN_NO_STA_SETUP;
cmd->min_no_sta_teardown = ATH11K_TWT_DEF_MIN_NO_STA_TEARDOWN;
cmd->no_of_bcast_mcast_slots = ATH11K_TWT_DEF_NO_OF_BCAST_MCAST_SLOTS;
cmd->min_no_twt_slots = ATH11K_TWT_DEF_MIN_NO_TWT_SLOTS;
cmd->max_no_sta_twt = ATH11K_TWT_DEF_MAX_NO_STA_TWT;
cmd->mode_check_interval = ATH11K_TWT_DEF_MODE_CHECK_INTERVAL;
cmd->add_sta_slot_interval = ATH11K_TWT_DEF_ADD_STA_SLOT_INTERVAL;
cmd->remove_sta_slot_interval =
ATH11K_TWT_DEF_REMOVE_STA_SLOT_INTERVAL;
/* TODO add MBSSID support */
cmd->mbss_support = 0;
cmd->sta_cong_timer_ms = params->sta_cong_timer_ms;
cmd->default_slot_size = params->default_slot_size;
cmd->congestion_thresh_setup = params->congestion_thresh_setup;
cmd->congestion_thresh_teardown = params->congestion_thresh_teardown;
cmd->congestion_thresh_critical = params->congestion_thresh_critical;
cmd->interference_thresh_teardown = params->interference_thresh_teardown;
cmd->interference_thresh_setup = params->interference_thresh_setup;
cmd->min_no_sta_setup = params->min_no_sta_setup;
cmd->min_no_sta_teardown = params->min_no_sta_teardown;
cmd->no_of_bcast_mcast_slots = params->no_of_bcast_mcast_slots;
cmd->min_no_twt_slots = params->min_no_twt_slots;
cmd->max_no_sta_twt = params->max_no_sta_twt;
cmd->mode_check_interval = params->mode_check_interval;
cmd->add_sta_slot_interval = params->add_sta_slot_interval;
cmd->remove_sta_slot_interval = params->remove_sta_slot_interval;
cmd->mbss_support = params->mbss_support;
ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_ENABLE_CMDID);
if (ret) {
@ -6767,6 +6802,107 @@ static void ath11k_bcn_tx_status_event(struct ath11k_base *ab, struct sk_buff *s
rcu_read_unlock();
}
static void ath11k_wmi_event_peer_sta_ps_state_chg(struct ath11k_base *ab,
struct sk_buff *skb)
{
const struct wmi_peer_sta_ps_state_chg_event *ev;
struct ieee80211_sta *sta;
struct ath11k_peer *peer;
struct ath11k *ar;
struct ath11k_sta *arsta;
const void **tb;
enum ath11k_wmi_peer_ps_state peer_previous_ps_state;
int ret;
tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
if (IS_ERR(tb)) {
ret = PTR_ERR(tb);
ath11k_warn(ab, "failed to parse tlv: %d\n", ret);
return;
}
ev = tb[WMI_TAG_PEER_STA_PS_STATECHANGE_EVENT];
if (!ev) {
ath11k_warn(ab, "failed to fetch sta ps change ev");
kfree(tb);
return;
}
ath11k_dbg(ab, ATH11K_DBG_WMI,
"peer sta ps chnange ev addr %pM state %u sup_bitmap %x ps_valid %u ts %u\n",
ev->peer_macaddr.addr, ev->peer_ps_state,
ev->ps_supported_bitmap, ev->peer_ps_valid,
ev->peer_ps_timestamp);
rcu_read_lock();
spin_lock_bh(&ab->base_lock);
peer = ath11k_peer_find_by_addr(ab, ev->peer_macaddr.addr);
if (!peer) {
spin_unlock_bh(&ab->base_lock);
ath11k_warn(ab, "peer not found %pM\n", ev->peer_macaddr.addr);
goto exit;
}
ar = ath11k_mac_get_ar_by_vdev_id(ab, peer->vdev_id);
if (!ar) {
spin_unlock_bh(&ab->base_lock);
ath11k_warn(ab, "invalid vdev id in peer sta ps state change ev %d",
peer->vdev_id);
goto exit;
}
sta = peer->sta;
spin_unlock_bh(&ab->base_lock);
if (!sta) {
ath11k_warn(ab, "failed to find station entry %pM\n",
ev->peer_macaddr.addr);
goto exit;
}
arsta = (struct ath11k_sta *)sta->drv_priv;
spin_lock_bh(&ar->data_lock);
peer_previous_ps_state = arsta->peer_ps_state;
arsta->peer_ps_state = ev->peer_ps_state;
arsta->peer_current_ps_valid = !!ev->peer_ps_valid;
if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
ar->ab->wmi_ab.svc_map)) {
if (!(ev->ps_supported_bitmap & WMI_PEER_PS_VALID) ||
!(ev->ps_supported_bitmap & WMI_PEER_PS_STATE_TIMESTAMP) ||
!ev->peer_ps_valid)
goto out;
if (arsta->peer_ps_state == WMI_PEER_PS_STATE_ON) {
arsta->ps_start_time = ev->peer_ps_timestamp;
arsta->ps_start_jiffies = jiffies;
} else if (arsta->peer_ps_state == WMI_PEER_PS_STATE_OFF &&
peer_previous_ps_state == WMI_PEER_PS_STATE_ON) {
arsta->ps_total_duration = arsta->ps_total_duration +
(ev->peer_ps_timestamp - arsta->ps_start_time);
}
if (ar->ps_timekeeper_enable)
trace_ath11k_ps_timekeeper(ar, ev->peer_macaddr.addr,
ev->peer_ps_timestamp,
arsta->peer_ps_state);
}
out:
spin_unlock_bh(&ar->data_lock);
exit:
rcu_read_unlock();
kfree(tb);
}
static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *skb)
{
struct ath11k *ar;
@ -7409,7 +7545,53 @@ static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff
static void ath11k_update_stats_event(struct ath11k_base *ab, struct sk_buff *skb)
{
ath11k_debugfs_fw_stats_process(ab, skb);
struct ath11k_fw_stats stats = {};
struct ath11k *ar;
int ret;
INIT_LIST_HEAD(&stats.pdevs);
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.bcn);
ret = ath11k_wmi_pull_fw_stats(ab, skb, &stats);
if (ret) {
ath11k_warn(ab, "failed to pull fw stats: %d\n", ret);
goto free;
}
rcu_read_lock();
ar = ath11k_mac_get_ar_by_pdev_id(ab, stats.pdev_id);
if (!ar) {
rcu_read_unlock();
ath11k_warn(ab, "failed to get ar for pdev_id %d: %d\n",
stats.pdev_id, ret);
goto free;
}
spin_lock_bh(&ar->data_lock);
/* WMI_REQUEST_PDEV_STAT can be requested via .get_txpower mac ops or via
* debugfs fw stats. Therefore, processing it separately.
*/
if (stats.stats_id == WMI_REQUEST_PDEV_STAT) {
list_splice_tail_init(&stats.pdevs, &ar->fw_stats.pdevs);
ar->fw_stats_done = true;
goto complete;
}
/* WMI_REQUEST_VDEV_STAT, WMI_REQUEST_BCN_STAT and WMI_REQUEST_RSSI_PER_CHAIN_STAT
* are currently requested only via debugfs fw stats. Hence, processing these
* in debugfs context
*/
ath11k_debugfs_fw_stats_process(ar, &stats);
complete:
complete(&ar->fw_stats_complete);
rcu_read_unlock();
spin_unlock_bh(&ar->data_lock);
free:
ath11k_fw_stats_free(&stats);
}
/* PDEV_CTL_FAILSAFE_CHECK_EVENT is received from FW when the frequency scanned
@ -7960,6 +8142,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
case WMI_DIAG_EVENTID:
ath11k_wmi_diag_event(ab, skb);
break;
case WMI_PEER_STA_PS_STATECHG_EVENTID:
ath11k_wmi_event_peer_sta_ps_state_chg(ab, skb);
break;
case WMI_GTK_OFFLOAD_STATUS_EVENTID:
ath11k_wmi_gtk_offload_status_event(ab, skb);
break;
@ -8962,12 +9147,13 @@ int ath11k_wmi_sta_keepalive(struct ath11k *ar,
cmd->interval = arg->interval;
cmd->method = arg->method;
arp = (struct wmi_sta_keepalive_arp_resp *)(cmd + 1);
arp->tlv_header = FIELD_PREP(WMI_TLV_TAG,
WMI_TAG_STA_KEEPALIVE_ARP_RESPONSE) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*arp) - TLV_HDR_SIZE);
if (arg->method == WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE ||
arg->method == WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST) {
arp = (struct wmi_sta_keepalive_arp_resp *)(cmd + 1);
arp->tlv_header = FIELD_PREP(WMI_TLV_TAG,
WMI_TAG_STA_KEEPALVE_ARP_RESPONSE) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*arp) - TLV_HDR_SIZE);
arp->src_ip4_addr = arg->src_ip4_addr;
arp->dest_ip4_addr = arg->dest_ip4_addr;
ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr);

View file

@ -17,7 +17,7 @@ struct ath11k_vif;
#define PSOC_HOST_MAX_NUM_SS (8)
/* defines to set Packet extension values whic can be 0 us, 8 usec or 16 usec */
/* defines to set Packet extension values which can be 0 us, 8 usec or 16 usec */
#define MAX_HE_NSS 8
#define MAX_HE_MODULATION 8
#define MAX_HE_RU 4
@ -1214,7 +1214,7 @@ enum wmi_tlv_tag {
WMI_TAG_NS_OFFLOAD_TUPLE,
WMI_TAG_FTM_INTG_CMD,
WMI_TAG_STA_KEEPALIVE_CMD,
WMI_TAG_STA_KEEPALVE_ARP_RESPONSE,
WMI_TAG_STA_KEEPALIVE_ARP_RESPONSE,
WMI_TAG_P2P_SET_VENDOR_IE_DATA_CMD,
WMI_TAG_AP_PS_PEER_CMD,
WMI_TAG_PEER_RATE_RETRY_SCHED_CMD,
@ -2090,6 +2090,7 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213,
WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
WMI_TLV_SERVICE_EXT2_MSG = 220,
WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT = 246,
WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249,
/* The second 128 bits */
@ -4482,7 +4483,7 @@ struct wmi_pdev_radar_ev {
} __packed;
struct wmi_pdev_temperature_event {
/* temperature value in Celcius degree */
/* temperature value in Celsius degree */
s32 temp;
u32 pdev_id;
} __packed;
@ -4708,7 +4709,7 @@ enum wmi_sta_ps_param_tx_wake_threshold {
*/
enum wmi_sta_ps_param_pspoll_count {
WMI_STA_PS_PSPOLL_COUNT_NO_MAX = 0,
/* Values greater than 0 indicate the maximum numer of PS-Poll frames
/* Values greater than 0 indicate the maximum number of PS-Poll frames
* FW will send before waking up.
*/
};
@ -4820,9 +4821,9 @@ enum wmi_rate_preamble {
/**
* enum wmi_rtscts_prot_mode - Enable/Disable RTS/CTS and CTS2Self Protection.
* @WMI_RTS_CTS_DISABLED : RTS/CTS protection is disabled.
* @WMI_USE_RTS_CTS : RTS/CTS Enabled.
* @WMI_USE_CTS2SELF : CTS to self protection Enabled.
* @WMI_RTS_CTS_DISABLED: RTS/CTS protection is disabled.
* @WMI_USE_RTS_CTS: RTS/CTS Enabled.
* @WMI_USE_CTS2SELF: CTS to self protection Enabled.
*/
enum wmi_rtscts_prot_mode {
WMI_RTS_CTS_DISABLED = 0,
@ -4833,13 +4834,13 @@ enum wmi_rtscts_prot_mode {
/**
* enum wmi_rtscts_profile - Selection of RTS CTS profile along with enabling
* protection mode.
* @WMI_RTSCTS_FOR_NO_RATESERIES - Neither of rate-series should use RTS-CTS
* @WMI_RTSCTS_FOR_SECOND_RATESERIES - Only second rate-series will use RTS-CTS
* @WMI_RTSCTS_ACROSS_SW_RETRIES - Only the second rate-series will use RTS-CTS,
* but if there's a sw retry, both the rate
* series will use RTS-CTS.
* @WMI_RTSCTS_ERP - RTS/CTS used for ERP protection for every PPDU.
* @WMI_RTSCTS_FOR_ALL_RATESERIES - Enable RTS-CTS for all rate series.
* @WMI_RTSCTS_FOR_NO_RATESERIES: Neither of rate-series should use RTS-CTS
* @WMI_RTSCTS_FOR_SECOND_RATESERIES: Only second rate-series will use RTS-CTS
* @WMI_RTSCTS_ACROSS_SW_RETRIES: Only the second rate-series will use RTS-CTS,
* but if there's a sw retry, both the rate
* series will use RTS-CTS.
* @WMI_RTSCTS_ERP: RTS/CTS used for ERP protection for every PPDU.
* @WMI_RTSCTS_FOR_ALL_RATESERIES: Enable RTS-CTS for all rate series.
*/
enum wmi_rtscts_profile {
WMI_RTSCTS_FOR_NO_RATESERIES = 0,
@ -4933,6 +4934,25 @@ struct wmi_wmm_params_all_arg {
#define ATH11K_TWT_DEF_ADD_STA_SLOT_INTERVAL 1000
#define ATH11K_TWT_DEF_REMOVE_STA_SLOT_INTERVAL 5000
struct wmi_twt_enable_params {
u32 sta_cong_timer_ms;
u32 mbss_support;
u32 default_slot_size;
u32 congestion_thresh_setup;
u32 congestion_thresh_teardown;
u32 congestion_thresh_critical;
u32 interference_thresh_teardown;
u32 interference_thresh_setup;
u32 min_no_sta_setup;
u32 min_no_sta_teardown;
u32 no_of_bcast_mcast_slots;
u32 min_no_twt_slots;
u32 max_no_sta_twt;
u32 mode_check_interval;
u32 add_sta_slot_interval;
u32 remove_sta_slot_interval;
};
struct wmi_twt_enable_params_cmd {
u32 tlv_header;
u32 pdev_id;
@ -5350,6 +5370,26 @@ struct wmi_debug_log_config_cmd_fixed_param {
#define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
#define WMI_SEND_TIMEOUT_HZ (3 * HZ)
enum ath11k_wmi_peer_ps_state {
WMI_PEER_PS_STATE_OFF,
WMI_PEER_PS_STATE_ON,
WMI_PEER_PS_STATE_DISABLED,
};
enum wmi_peer_ps_supported_bitmap {
/* Used to indicate that power save state change is valid */
WMI_PEER_PS_VALID = 0x1,
WMI_PEER_PS_STATE_TIMESTAMP = 0x2,
};
struct wmi_peer_sta_ps_state_chg_event {
struct wmi_mac_addr peer_macaddr;
u32 peer_ps_state;
u32 ps_supported_bitmap;
u32 peer_ps_valid;
u32 peer_ps_timestamp;
} __packed;
struct ath11k_wmi_base {
struct ath11k_base *ab;
struct ath11k_pdev_wmi wmi[MAX_RADIOS];
@ -6039,7 +6079,9 @@ void ath11k_wmi_fw_stats_fill(struct ath11k *ar,
struct ath11k_fw_stats *fw_stats, u32 stats_id,
char *buf);
int ath11k_wmi_simulate_radar(struct ath11k *ar);
int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id);
void ath11k_wmi_fill_default_twt_params(struct wmi_twt_enable_params *twt_params);
int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id,
struct wmi_twt_enable_params *params);
int ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id);
int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar,
struct wmi_twt_add_dialog_params *params);

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/delay.h>
@ -67,6 +68,13 @@ int ath11k_wow_wakeup(struct ath11k_base *ab)
struct ath11k *ar = ath11k_ab_to_ar(ab, 0);
int ret;
/* In the case of WCN6750, WoW wakeup is done
* by sending SMP2P power save exit message
* to the target processor.
*/
if (ab->hw_params.smp2p_wow_exit)
return 0;
reinit_completion(&ab->wow.wakeup_completed);
ret = ath11k_wmi_wow_host_wakeup_ind(ar);
@ -664,6 +672,12 @@ int ath11k_wow_op_suspend(struct ieee80211_hw *hw,
struct ath11k *ar = hw->priv;
int ret;
ret = ath11k_mac_wait_tx_complete(ar);
if (ret) {
ath11k_warn(ar->ab, "failed to wait tx complete: %d\n", ret);
return ret;
}
mutex_lock(&ar->conf_mutex);
ret = ath11k_dp_rx_pktlog_stop(ar->ab, true);
@ -695,13 +709,6 @@ int ath11k_wow_op_suspend(struct ieee80211_hw *hw,
goto cleanup;
}
ath11k_mac_drain_tx(ar);
ret = ath11k_mac_wait_tx_complete(ar);
if (ret) {
ath11k_warn(ar->ab, "failed to wait tx complete: %d\n", ret);
goto cleanup;
}
ret = ath11k_wow_set_hw_filter(ar);
if (ret) {
ath11k_warn(ar->ab, "failed to set hw filter: %d\n",

View file

@ -1744,7 +1744,7 @@ static void ar9003_hw_spectral_scan_config(struct ath_hw *ah,
REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA);
REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE);
/* on AR93xx and newer, count = 0 will make the the chip send
/* on AR93xx and newer, count = 0 will make the chip send
* spectral samples endlessly. Check if this really was intended,
* and fix otherwise.
*/

View file

@ -710,7 +710,7 @@ struct ath_spec_scan {
/**
* struct ath_hw_ops - callbacks used by hardware code and driver code
*
* This structure contains callbacks designed to to be used internally by
* This structure contains callbacks designed to be used internally by
* hardware code and also by the lower level driver.
*
* @config_pci_powersave:

View file

@ -2677,7 +2677,7 @@ struct ani_global_security_stats {
* management information base (MIB) object is enabled */
u32 rx_wep_unencrypted_frm_cnt;
/* The number of received MSDU packets that that the 802.11 station
/* The number of received MSDU packets that the 802.11 station
* discarded because of MIC failures */
u32 rx_mic_fail_cnt;

View file

@ -16,6 +16,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/random.h>
#include "txrx.h"
static inline int get_rssi0(struct wcn36xx_rx_bd *bd)
@ -278,6 +279,7 @@ static void wcn36xx_update_survey(struct wcn36xx *wcn, int rssi, int snr,
struct ieee80211_supported_band *sband;
int idx;
int i;
u8 snr_sample = snr & 0xff;
idx = 0;
if (band == NL80211_BAND_5GHZ)
@ -297,6 +299,8 @@ static void wcn36xx_update_survey(struct wcn36xx *wcn, int rssi, int snr,
wcn->chan_survey[idx].rssi = rssi;
wcn->chan_survey[idx].snr = snr;
spin_unlock(&wcn->survey_lock);
add_device_randomness(&snr_sample, sizeof(snr_sample));
}
int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)