mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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:
commit
6cf5e9066d
66 changed files with 1769 additions and 374 deletions
|
@ -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>;
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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, ¶ms);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ struct ath11k_spectral {
|
|||
u16 count;
|
||||
u8 fft_size;
|
||||
bool enabled;
|
||||
bool is_primary;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH11K_SPECTRAL
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Reference in a new issue