diff options
author | Jakub Kicinski <kuba@kernel.org> | 2022-09-30 20:07:30 +0300 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-09-30 20:07:31 +0300 |
commit | 915b96c52763e2988e6368b538b487a7138b8fa4 (patch) | |
tree | 214c1f09160467ac01cf72144e81cceb11b36528 /drivers/net/wireless/ath | |
parent | 6690c2c4c4eaa2a01f1c50ccd35dbe479bba85e3 (diff) | |
parent | 2fc6de5c6924aea5e84d2edaa40ed744f0720844 (diff) | |
download | linux-915b96c52763e2988e6368b538b487a7138b8fa4.tar.xz |
Merge tag 'wireless-next-2022-09-30' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next
Kalle Valo says:
====================
wireless-next patches for v6.1
Few stack changes and lots of driver changes in this round. brcmfmac
has more activity as usual and it gets new hardware support. ath11k
improves WCN6750 support and also other smaller features. And of
course changes all over.
Note: in early September wireless tree was merged to wireless-next to
avoid some conflicts with mac80211 patches, this shouldn't cause any
problems but wanted to mention anyway.
Major changes:
mac80211
- refactoring and preparation for Wi-Fi 7 Multi-Link Operation (MLO)
feature continues
brcmfmac
- support CYW43439 SDIO chipset
- support BCM4378 on Apple platforms
- support CYW89459 PCIe chipset
rtw89
- more work to get rtw8852c supported
- P2P support
- support for enabling and disabling MSDU aggregation via nl80211
mt76
- tx status reporting improvements
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
* tag 'wireless-next-2022-09-30' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (231 commits)
wifi: rtl8xxxu: Improve rtl8xxxu_queue_select
wifi: rtl8xxxu: Fix AIFS written to REG_EDCA_*_PARAM
wifi: rtl8xxxu: gen2: Enable 40 MHz channel width
wifi: rtw89: 8852b: configure DLE mem
wifi: rtw89: check DLE FIFO size with reserved size
wifi: rtw89: mac: correct register of report IMR
wifi: rtw89: pci: set power cut closed for 8852be
wifi: rtw89: pci: add to do PCI auto calibration
wifi: rtw89: 8852b: implement chip_ops::{enable,disable}_bb_rf
wifi: rtw89: add DMA busy checking bits to chip info
wifi: rtw89: mac: define DMA channel mask to avoid unsupported channels
wifi: rtw89: pci: mask out unsupported TX channels
iwlegacy: Replace zero-length arrays with DECLARE_FLEX_ARRAY() helper
ipw2x00: Replace zero-length array with DECLARE_FLEX_ARRAY() helper
wifi: iwlwifi: Track scan_cmd allocation size explicitly
brcmfmac: Remove the call to "dtim_assoc" IOVAR
brcmfmac: increase dcmd maximum buffer size
brcmfmac: Support 89459 pcie
brcmfmac: increase default max WOWL patterns to 16
cw1200: fix incorrect check to determine if no element is found in list
...
====================
Link: https://lore.kernel.org/r/20220930150413.A7984C433D6@smtp.kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/net/wireless/ath')
67 files changed, 1758 insertions, 377 deletions
diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 4481ed375f55..af6546572df2 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -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) { diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index c45c814fd122..59926227bd49 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -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) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index d1ac64026cb3..400f332a7ff0 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -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 */ diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index d70d7d088a2b..f5de8ce8fb45 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -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 */ diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index fe6b6f97a916..2d1634a890dd 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -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}, diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index 240d70515088..437b9759f05d 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -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; diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 39378e3f9b2b..c861e66ef6bc 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -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", diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 367539f2c370..87a3365330ff 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -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: diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 8a075a711b71..e76aab973320 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -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, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a19b0795c86d..bd603feb7953 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -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. */ diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index e52e41a70321..6d32b43a4da6 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -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, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 23381a9db6ae..ec8d5b29bc72 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -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) { @@ -8520,7 +8520,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", sta->addr, changed, sta->deflink.bandwidth, sta->deflink.rx_nss, - sta->smps_mode); + sta->deflink.smps_mode); if (changed & IEEE80211_RC_BW_CHANGED) { bw = WMI_PEER_CHWIDTH_20MHZ; @@ -8554,7 +8554,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, if (changed & IEEE80211_RC_SMPS_CHANGED) { smps = WMI_PEER_SMPS_PS_NONE; - switch (sta->smps_mode) { + switch (sta->deflink.smps_mode) { case IEEE80211_SMPS_AUTOMATIC: case IEEE80211_SMPS_OFF: smps = WMI_PEER_SMPS_PS_NONE; @@ -8567,7 +8567,7 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, break; case IEEE80211_SMPS_NUM_MODES: ath10k_warn(ar, "Invalid smps %d in sta rc update for %pM\n", - sta->smps_mode, sta->addr); + sta->deflink.smps_mode, sta->addr); smps = WMI_PEER_SMPS_PS_NONE; break; } @@ -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, diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index a77cb79a7a54..e56c6a6b1379 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -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. */ diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index cf64898b9447..480cd97ab739 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -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. */ diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c index d7e406916bc8..66cb7a1e628a 100644 --- a/drivers/net/wireless/ath/ath10k/qmi.c +++ b/drivers/net/wireless/ath/ath10k/qmi.c @@ -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. */ diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 6ce2a8b1060d..777e53aa69dc 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -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). diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c index e0e98f9f127e..79e09c7a82b3 100644 --- a/drivers/net/wireless/ath/ath10k/sdio.c +++ b/drivers/net/wireless/ath/ath10k/sdio.c @@ -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. diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c index 36c9a1364253..cefd97323dfe 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.c +++ b/drivers/net/wireless/ath/ath10k/thermal.c @@ -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); diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h index 5fdb020f4da3..1f4de9fbf2b3 100644 --- a/drivers/net/wireless/ath/ath10k/thermal.h +++ b/drivers/net/wireless/ath/ath10k/thermal.h @@ -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; diff --git a/drivers/net/wireless/ath/ath10k/usb.h b/drivers/net/wireless/ath/ath10k/usb.h index 34d683e8fc18..48e066ba8162 100644 --- a/drivers/net/wireless/ath/ath10k/usb.h +++ b/drivers/net/wireless/ath/ath10k/usb.h @@ -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 diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index b39c9b78b32b..dbb48d70f2e9 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -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; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 074d8ba5072a..980d4124fa28 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -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; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 4abd12e78028..6de3cc4640a0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -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; diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index 1be4a25947a3..d34a4d6325b2 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -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) diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h index 58a945411c5b..415ddfd26654 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.h +++ b/drivers/net/wireless/ath/ath11k/ahb.h @@ -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) diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index c14c51f38709..f2da95fd4253 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -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; } diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index c3e9e4f7bc24..b99180bc8172 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -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) diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index afad8f55e433..cf2f52cc4e30 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -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[]; diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 9648e0017393..ccdf3d5ba1ab 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -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; - - 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; - } + int i; - spin_lock_bh(&ar->data_lock); + /* WMI_REQUEST_PDEV_STAT request has been already processed */ - 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_RSSI_PER_CHAIN_STAT) { + ar->fw_stats_done = true; + return; } - 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; } diff --git a/drivers/net/wireless/ath/ath11k/debugfs.h b/drivers/net/wireless/ath/ath11k/debugfs.h index 30c00cb28311..3af0169f6cf2 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.h +++ b/drivers/net/wireless/ath/ath11k/debugfs.h @@ -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) diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h index 5d722b51b125..2b97cbbd28cb 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.h @@ -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; diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index 1b1acbdf837a..9cc4ef28e751 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -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); + } } diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index 8b790ce72e5d..f5156a7fbdd7 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -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) { diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index e9dfa209098b..be9eafc872b3 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -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 diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 2148acf37071..c5a4c34d7749 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -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) && diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index c17a2620aad7..8afbba236935 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -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); diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index bda71ab5a1f2..2fd224480d45 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -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 && diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 110c337ddf33..6a1f78ee6eb6 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -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 { diff --git a/drivers/net/wireless/ath/ath11k/hal_desc.h b/drivers/net/wireless/ath/ath11k/hal_desc.h index 24e72e75a8c7..d895ea878d9f 100644 --- a/drivers/net/wireless/ath/ath11k/hal_desc.h +++ b/drivers/net/wireless/ath/ath11k/hal_desc.h @@ -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. * diff --git a/drivers/net/wireless/ath/ath11k/hal_tx.c b/drivers/net/wireless/ath/ath11k/hal_tx.c index c8929de8ce6c..d1b0e36e04a9 100644 --- a/drivers/net/wireless/ath/ath11k/hal_tx.c +++ b/drivers/net/wireless/ath/ath11k/hal_tx.c @@ -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 = diff --git a/drivers/net/wireless/ath/ath11k/hal_tx.h b/drivers/net/wireless/ath/ath11k/hal_tx.h index 36f4f6f6cbc2..c5e88364afe5 100644 --- a/drivers/net/wireless/ath/ath11k/hal_tx.h +++ b/drivers/net/wireless/ath/ath11k/hal_tx.h @@ -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 */ diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h index e9366f786fbb..659b80d2abd4 100644 --- a/drivers/net/wireless/ath/ath11k/hif.h +++ b/drivers/net/wireless/ath/ath11k/hif.h @@ -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_ */ diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c index 96db85c55585..dbcc0c4035b6 100644 --- a/drivers/net/wireless/ath/ath11k/hw.c +++ b/drivers/net/wireless/ath/ath11k/hw.c @@ -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[] = { diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h index bb5ac940e470..8a3f24862edc 100644 --- a/drivers/net/wireless/ath/ath11k/hw.h +++ b/drivers/net/wireless/ath/ath11k/hw.h @@ -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 diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 7e91e347c9ff..84d956ad4093 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -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); @@ -4701,7 +4707,7 @@ static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", sta->addr, changed, sta->deflink.bandwidth, sta->deflink.rx_nss, - sta->smps_mode); + sta->deflink.smps_mode); spin_lock_bh(&ar->data_lock); @@ -4737,7 +4743,7 @@ static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, if (changed & IEEE80211_RC_SMPS_CHANGED) { smps = WMI_PEER_SMPS_PS_NONE; - switch (sta->smps_mode) { + switch (sta->deflink.smps_mode) { case IEEE80211_SMPS_AUTOMATIC: case IEEE80211_SMPS_OFF: smps = WMI_PEER_SMPS_PS_NONE; @@ -4750,7 +4756,7 @@ static void ath11k_mac_op_sta_rc_update(struct ieee80211_hw *hw, break; default: ath11k_warn(ar->ab, "Invalid smps %d in sta rc update for %pM\n", - sta->smps_mode, sta->addr); + sta->deflink.smps_mode, sta->addr); smps = WMI_PEER_SMPS_PS_NONE; break; } @@ -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; diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index c44df17719f6..86995e8dc913 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -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) diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 5bd34a6273d9..99cf3357c66e 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -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, diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index 825cd884e6cd..380f9d37b644 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -140,55 +140,100 @@ int ath11k_pcic_init_msi_config(struct ath11k_base *ab) } EXPORT_SYMBOL(ath11k_pcic_init_msi_config); +static void __ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value) +{ + if (offset < ATH11K_PCI_WINDOW_START) + iowrite32(value, ab->mem + offset); + else + ab->pci.ops->window_write32(ab, offset, value); +} + void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value) { int ret = 0; + 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); - if (offset < ATH11K_PCI_WINDOW_START) - iowrite32(value, ab->mem + offset); - else - ab->pci.ops->window_write32(ab, offset, value); + __ath11k_pcic_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) + 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); + + 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. */ - 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); - if (offset < ATH11K_PCI_WINDOW_START) - val = ioread32(ab->mem + offset); - else - val = ab->pci.ops->window_read32(ab, offset); + val = __ath11k_pcic_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) + 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); diff --git a/drivers/net/wireless/ath/ath11k/pcic.h b/drivers/net/wireless/ath/ath11k/pcic.h index 0afbb34510db..ac012e88bf6d 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.h +++ b/drivers/net/wireless/ath/ath11k/pcic.h @@ -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 diff --git a/drivers/net/wireless/ath/ath11k/peer.c b/drivers/net/wireless/ath/ath11k/peer.c index 9e22aaf34b88..1ae7af02c364 100644 --- a/drivers/net/wireless/ath/ath11k/peer.c +++ b/drivers/net/wireless/ath/ath11k/peer.c @@ -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); diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 00136601cb7d..51de2208b789 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -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); @@ -3169,6 +3203,22 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work) } 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; default: diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h index c83cf822be81..2ec56a34fa81 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.h +++ b/drivers/net/wireless/ath/ath11k/qmi.h @@ -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 diff --git a/drivers/net/wireless/ath/ath11k/rx_desc.h b/drivers/net/wireless/ath/ath11k/rx_desc.h index 26ecc1bcd9d5..786d5f36f5e5 100644 --- a/drivers/net/wireless/ath/ath11k/rx_desc.h +++ b/drivers/net/wireless/ath/ath11k/rx_desc.h @@ -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 diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index 516a7b4cd180..705868198df4 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -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); diff --git a/drivers/net/wireless/ath/ath11k/spectral.h b/drivers/net/wireless/ath/ath11k/spectral.h index 081744265f2a..96bfa16e18e9 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.h +++ b/drivers/net/wireless/ath/ath11k/spectral.h @@ -35,6 +35,7 @@ struct ath11k_spectral { u16 count; u8 fft_size; bool enabled; + bool is_primary; }; #ifdef CONFIG_ATH11K_SPECTRAL diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c index c96b26f39a25..23ed01bd44f9 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.c +++ b/drivers/net/wireless/ath/ath11k/thermal.c @@ -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); diff --git a/drivers/net/wireless/ath/ath11k/thermal.h b/drivers/net/wireless/ath/ath11k/thermal.h index f9af55f3682d..3e39675ef7f5 100644 --- a/drivers/net/wireless/ath/ath11k/thermal.h +++ b/drivers/net/wireless/ath/ath11k/thermal.h @@ -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; diff --git a/drivers/net/wireless/ath/ath11k/trace.h b/drivers/net/wireless/ath/ath11k/trace.h index 76560587bea0..9535745fe026 100644 --- a/drivers/net/wireless/ath/ath11k/trace.h +++ b/drivers/net/wireless/ath/ath11k/trace.h @@ -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 */ diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 88ee4f9d19da..fad9f8d308a2 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -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); diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 4da248ffa318..8f2c07d70a4a 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -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); diff --git a/drivers/net/wireless/ath/ath11k/wow.c b/drivers/net/wireless/ath/ath11k/wow.c index b3e65cd13d83..1dec23b0699c 100644 --- a/drivers/net/wireless/ath/ath11k/wow.c +++ b/drivers/net/wireless/ath/ath11k/wow.c @@ -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", diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index dc0e5ea25673..090ff0600c81 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -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. */ diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c index 6cf087522157..571062f2e82a 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c @@ -1113,7 +1113,7 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, if (!avp->assoc) return false; - skb = ieee80211_nullfunc_get(sc->hw, vif, false); + skb = ieee80211_nullfunc_get(sc->hw, vif, -1, false); if (!skb) return false; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 096a206f49ed..450ab19b1d4e 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -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: diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index ba16a7f3e23d..ba271a10d4ab 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2160,7 +2160,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, fi->keyix = an->ps_key; else fi->keyix = ATH9K_TXKEYIX_INVALID; - fi->dyn_smps = sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC; + fi->dyn_smps = sta && sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC; fi->keytype = keytype; fi->framelen = framelen; fi->tx_power = txpower; diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h index f1a43fd1d957..d3a9d00e65e1 100644 --- a/drivers/net/wireless/ath/wcn36xx/hal.h +++ b/drivers/net/wireless/ath/wcn36xx/hal.h @@ -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; diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 8da3955995b6..0802ed728824 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -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) |