2020-08-13 12:04:24 +03:00
|
|
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
2022-04-01 14:53:08 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
|
wifi: ath11k: enable 36 bit mask for stream DMA
Currently 32 bit DMA mask is used, telling kernel to get us an DMA
address under 4GB when mapping a buffer. This results in a very high
CPU overhead in the case where IOMMU is disabled and more than 4GB
system memory is installed. The reason is, with more than 4GB memory
installed, kernel is likely to allocate a buffer whose physical
address is above 4GB. While with IOMMU disabled, kernel has to involve
SWIOTLB to map/unmap that buffer, which consumes lots of CPU cycles.
We did hit an issue caused by the reason mentioned above: in a system
that disables IOMMU and gets 8GB memory installed, a total of 40.5%
CPU usage is observed in throughput test. CPU profiling shows nearly
60% of CPU cycles are consumed by SWIOTLB.
By enabling 36 bit DMA mask, we can bypass SWIOTLB for any buffer
whose physical address is below 64GB. There are two types of DMA mask
within struct device, named dma_mask and coherent_dma_mask. Here we
only enable 36 bit for dma_mask, because firmware crashes if
coherent_dma_mask is also enabled, due to some unknown hardware
limitations. This is acceptable because coherent_dma_mask is used for
mapping a consistent DMA buffer, which generally does not happen in
a hot path.
With this change, the total CPU usage mentioned in above issue drops
to 18.9%.
Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240123015201.28939-1-quic_bqiang@quicinc.com
2024-01-23 09:52:01 +08:00
|
|
|
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
2022-04-01 14:53:08 +03:00
|
|
|
*/
|
2020-08-13 12:04:24 +03:00
|
|
|
|
|
|
|
#include <linux/msi.h>
|
|
|
|
#include <linux/pci.h>
|
2023-10-18 11:37:06 +03:00
|
|
|
#include <linux/firmware.h>
|
2021-12-14 17:39:43 +02:00
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_address.h>
|
|
|
|
#include <linux/ioport.h>
|
2020-08-13 12:04:24 +03:00
|
|
|
|
|
|
|
#include "core.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "mhi.h"
|
2021-02-16 09:16:08 +02:00
|
|
|
#include "pci.h"
|
2022-04-01 14:53:08 +03:00
|
|
|
#include "pcic.h"
|
2020-08-13 12:04:24 +03:00
|
|
|
|
2023-03-29 19:20:38 +03:00
|
|
|
#define MHI_TIMEOUT_DEFAULT_MS 20000
|
2022-02-14 19:53:16 +02:00
|
|
|
#define RDDM_DUMP_SIZE 0x420000
|
2024-01-11 15:14:06 +08:00
|
|
|
#define MHI_CB_INVALID 0xff
|
2020-08-13 12:04:24 +03:00
|
|
|
|
2024-02-23 07:39:31 -08:00
|
|
|
static const struct mhi_channel_config ath11k_mhi_channels_qca6390[] = {
|
2020-08-13 12:04:24 +03:00
|
|
|
{
|
|
|
|
.num = 20,
|
|
|
|
.name = "IPCR",
|
|
|
|
.num_elements = 64,
|
|
|
|
.event_ring = 1,
|
|
|
|
.dir = DMA_TO_DEVICE,
|
|
|
|
.ee_mask = 0x4,
|
|
|
|
.pollcfg = 0,
|
|
|
|
.doorbell = MHI_DB_BRST_DISABLE,
|
|
|
|
.lpm_notify = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
.doorbell_mode_switch = false,
|
|
|
|
.auto_queue = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.num = 21,
|
|
|
|
.name = "IPCR",
|
|
|
|
.num_elements = 64,
|
|
|
|
.event_ring = 1,
|
|
|
|
.dir = DMA_FROM_DEVICE,
|
|
|
|
.ee_mask = 0x4,
|
|
|
|
.pollcfg = 0,
|
|
|
|
.doorbell = MHI_DB_BRST_DISABLE,
|
|
|
|
.lpm_notify = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
.doorbell_mode_switch = false,
|
|
|
|
.auto_queue = true,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2021-02-16 09:16:08 +02:00
|
|
|
static struct mhi_event_config ath11k_mhi_events_qca6390[] = {
|
2020-08-13 12:04:24 +03:00
|
|
|
{
|
|
|
|
.num_elements = 32,
|
|
|
|
.irq_moderation_ms = 0,
|
|
|
|
.irq = 1,
|
|
|
|
.mode = MHI_DB_BRST_DISABLE,
|
|
|
|
.data_type = MHI_ER_CTRL,
|
|
|
|
.hardware_event = false,
|
|
|
|
.client_managed = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.num_elements = 256,
|
|
|
|
.irq_moderation_ms = 1,
|
|
|
|
.irq = 2,
|
|
|
|
.mode = MHI_DB_BRST_DISABLE,
|
|
|
|
.priority = 1,
|
|
|
|
.hardware_event = false,
|
|
|
|
.client_managed = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-02-23 07:39:31 -08:00
|
|
|
static const struct mhi_controller_config ath11k_mhi_config_qca6390 = {
|
2020-08-13 12:04:24 +03:00
|
|
|
.max_channels = 128,
|
|
|
|
.timeout_ms = 2000,
|
|
|
|
.use_bounce_buf = false,
|
wifi: ath11k: decrease MHI channel buffer length to 8KB
Currently buf_len field of ath11k_mhi_config_qca6390 is assigned
with 0, making MHI use a default size, 64KB, to allocate channel
buffers. This is likely to fail in some scenarios where system
memory is highly fragmented and memory compaction or reclaim is
not allowed.
There is a fail report which is caused by it:
kworker/u32:45: page allocation failure: order:4, mode:0x40c00(GFP_NOIO|__GFP_COMP), nodemask=(null),cpuset=/,mems_allowed=0
CPU: 0 PID: 19318 Comm: kworker/u32:45 Not tainted 6.8.0-rc3-1.gae4495f-default #1 openSUSE Tumbleweed (unreleased) 493b6d5b382c603654d7a81fc3c144d59a1dfceb
Workqueue: events_unbound async_run_entry_fn
Call Trace:
<TASK>
dump_stack_lvl+0x47/0x60
warn_alloc+0x13a/0x1b0
? srso_alias_return_thunk+0x5/0xfbef5
? __alloc_pages_direct_compact+0xab/0x210
__alloc_pages_slowpath.constprop.0+0xd3e/0xda0
__alloc_pages+0x32d/0x350
? mhi_prepare_channel+0x127/0x2d0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814]
__kmalloc_large_node+0x72/0x110
__kmalloc+0x37c/0x480
? mhi_map_single_no_bb+0x77/0xf0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814]
? mhi_prepare_channel+0x127/0x2d0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814]
mhi_prepare_channel+0x127/0x2d0 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814]
__mhi_prepare_for_transfer+0x44/0x80 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814]
? __pfx_____mhi_prepare_for_transfer+0x10/0x10 [mhi 40df44e07c05479f7a6e7b90fba9f0e0031a7814]
device_for_each_child+0x5c/0xa0
? __pfx_pci_pm_resume+0x10/0x10
ath11k_core_resume+0x65/0x100 [ath11k a5094e22d7223135c40d93c8f5321cf09fd85e4e]
? srso_alias_return_thunk+0x5/0xfbef5
ath11k_pci_pm_resume+0x32/0x60 [ath11k_pci 830b7bfc3ea80ebef32e563cafe2cb55e9cc73ec]
? srso_alias_return_thunk+0x5/0xfbef5
dpm_run_callback+0x8c/0x1e0
device_resume+0x104/0x340
? __pfx_dpm_watchdog_handler+0x10/0x10
async_resume+0x1d/0x30
async_run_entry_fn+0x32/0x120
process_one_work+0x168/0x330
worker_thread+0x2f5/0x410
? __pfx_worker_thread+0x10/0x10
kthread+0xe8/0x120
? __pfx_kthread+0x10/0x10
ret_from_fork+0x34/0x50
? __pfx_kthread+0x10/0x10
ret_from_fork_asm+0x1b/0x30
</TASK>
Actually those buffers are used only by QMI target -> host communication.
And for WCN6855 and QCA6390, the largest packet size for that is less
than 6KB. So change buf_len field to 8KB, which results in order 1
allocation if page size is 4KB. In this way, we can at least save some
memory, and as well as decrease the possibility of allocation failure
in those scenarios.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Reported-by: Vlastimil Babka <vbabka@suse.cz>
Closes: https://lore.kernel.org/ath11k/96481a45-3547-4d23-ad34-3a8f1d90c1cd@suse.cz/
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240223053111.29170-1-quic_bqiang@quicinc.com
2024-02-23 13:31:11 +08:00
|
|
|
.buf_len = 8192,
|
2021-02-16 09:16:08 +02:00
|
|
|
.num_channels = ARRAY_SIZE(ath11k_mhi_channels_qca6390),
|
|
|
|
.ch_cfg = ath11k_mhi_channels_qca6390,
|
|
|
|
.num_events = ARRAY_SIZE(ath11k_mhi_events_qca6390),
|
|
|
|
.event_cfg = ath11k_mhi_events_qca6390,
|
|
|
|
};
|
|
|
|
|
2024-02-23 07:39:31 -08:00
|
|
|
static const struct mhi_channel_config ath11k_mhi_channels_qcn9074[] = {
|
2021-02-16 09:16:08 +02:00
|
|
|
{
|
|
|
|
.num = 20,
|
|
|
|
.name = "IPCR",
|
|
|
|
.num_elements = 32,
|
|
|
|
.event_ring = 1,
|
|
|
|
.dir = DMA_TO_DEVICE,
|
|
|
|
.ee_mask = 0x14,
|
|
|
|
.pollcfg = 0,
|
|
|
|
.doorbell = MHI_DB_BRST_DISABLE,
|
|
|
|
.lpm_notify = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
.doorbell_mode_switch = false,
|
|
|
|
.auto_queue = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.num = 21,
|
|
|
|
.name = "IPCR",
|
|
|
|
.num_elements = 32,
|
|
|
|
.event_ring = 1,
|
|
|
|
.dir = DMA_FROM_DEVICE,
|
|
|
|
.ee_mask = 0x14,
|
|
|
|
.pollcfg = 0,
|
|
|
|
.doorbell = MHI_DB_BRST_DISABLE,
|
|
|
|
.lpm_notify = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
.doorbell_mode_switch = false,
|
|
|
|
.auto_queue = true,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct mhi_event_config ath11k_mhi_events_qcn9074[] = {
|
|
|
|
{
|
|
|
|
.num_elements = 32,
|
|
|
|
.irq_moderation_ms = 0,
|
|
|
|
.irq = 1,
|
|
|
|
.data_type = MHI_ER_CTRL,
|
|
|
|
.mode = MHI_DB_BRST_DISABLE,
|
|
|
|
.hardware_event = false,
|
|
|
|
.client_managed = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.num_elements = 256,
|
|
|
|
.irq_moderation_ms = 1,
|
|
|
|
.irq = 2,
|
|
|
|
.mode = MHI_DB_BRST_DISABLE,
|
|
|
|
.priority = 1,
|
|
|
|
.hardware_event = false,
|
|
|
|
.client_managed = false,
|
|
|
|
.offload_channel = false,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-02-23 07:39:31 -08:00
|
|
|
static const struct mhi_controller_config ath11k_mhi_config_qcn9074 = {
|
2021-02-16 09:16:08 +02:00
|
|
|
.max_channels = 30,
|
|
|
|
.timeout_ms = 10000,
|
|
|
|
.use_bounce_buf = false,
|
|
|
|
.buf_len = 0,
|
|
|
|
.num_channels = ARRAY_SIZE(ath11k_mhi_channels_qcn9074),
|
|
|
|
.ch_cfg = ath11k_mhi_channels_qcn9074,
|
|
|
|
.num_events = ARRAY_SIZE(ath11k_mhi_events_qcn9074),
|
|
|
|
.event_cfg = ath11k_mhi_events_qcn9074,
|
2020-08-13 12:04:24 +03:00
|
|
|
};
|
|
|
|
|
2020-08-17 13:31:55 +03:00
|
|
|
void ath11k_mhi_set_mhictrl_reset(struct ath11k_base *ab)
|
|
|
|
{
|
|
|
|
u32 val;
|
|
|
|
|
2022-04-01 14:53:08 +03:00
|
|
|
val = ath11k_pcic_read32(ab, MHISTATUS);
|
2020-08-17 13:31:55 +03:00
|
|
|
|
2023-06-09 17:24:34 +03:00
|
|
|
ath11k_dbg(ab, ATH11K_DBG_PCI, "mhistatus 0x%x\n", val);
|
2020-08-17 13:31:55 +03:00
|
|
|
|
2024-03-08 17:09:45 +02:00
|
|
|
/* After SOC_GLOBAL_RESET, MHISTATUS may still have SYSERR bit set
|
|
|
|
* and thus need to set MHICTRL_RESET to clear SYSERR.
|
2020-08-17 13:31:55 +03:00
|
|
|
*/
|
2022-04-01 14:53:08 +03:00
|
|
|
ath11k_pcic_write32(ab, MHICTRL, MHICTRL_RESET_MASK);
|
2020-08-17 13:31:55 +03:00
|
|
|
|
|
|
|
mdelay(10);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ath11k_mhi_reset_txvecdb(struct ath11k_base *ab)
|
|
|
|
{
|
2022-04-01 14:53:08 +03:00
|
|
|
ath11k_pcic_write32(ab, PCIE_TXVECDB, 0);
|
2020-08-17 13:31:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ath11k_mhi_reset_txvecstatus(struct ath11k_base *ab)
|
|
|
|
{
|
2022-04-01 14:53:08 +03:00
|
|
|
ath11k_pcic_write32(ab, PCIE_TXVECSTATUS, 0);
|
2020-08-17 13:31:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ath11k_mhi_reset_rxvecdb(struct ath11k_base *ab)
|
|
|
|
{
|
2022-04-01 14:53:08 +03:00
|
|
|
ath11k_pcic_write32(ab, PCIE_RXVECDB, 0);
|
2020-08-17 13:31:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ath11k_mhi_reset_rxvecstatus(struct ath11k_base *ab)
|
|
|
|
{
|
2022-04-01 14:53:08 +03:00
|
|
|
ath11k_pcic_write32(ab, PCIE_RXVECSTATUS, 0);
|
2020-08-17 13:31:55 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ath11k_mhi_clear_vector(struct ath11k_base *ab)
|
|
|
|
{
|
|
|
|
ath11k_mhi_reset_txvecdb(ab);
|
|
|
|
ath11k_mhi_reset_txvecstatus(ab);
|
|
|
|
ath11k_mhi_reset_rxvecdb(ab);
|
|
|
|
ath11k_mhi_reset_rxvecstatus(ab);
|
|
|
|
}
|
|
|
|
|
2020-08-13 12:04:24 +03:00
|
|
|
static int ath11k_mhi_get_msi(struct ath11k_pci *ab_pci)
|
|
|
|
{
|
|
|
|
struct ath11k_base *ab = ab_pci->ab;
|
|
|
|
u32 user_base_data, base_vector;
|
|
|
|
int ret, num_vectors, i;
|
|
|
|
int *irq;
|
2021-11-19 15:36:26 +02:00
|
|
|
unsigned int msi_data;
|
2020-08-13 12:04:24 +03:00
|
|
|
|
2022-04-01 14:53:08 +03:00
|
|
|
ret = ath11k_pcic_get_user_msi_assignment(ab, "MHI", &num_vectors,
|
2022-04-01 14:53:08 +03:00
|
|
|
&user_base_data, &base_vector);
|
2020-08-13 12:04:24 +03:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2023-06-09 17:24:34 +03:00
|
|
|
ath11k_dbg(ab, ATH11K_DBG_PCI, "num_vectors %d base_vector %d\n",
|
2020-08-13 12:04:24 +03:00
|
|
|
num_vectors, base_vector);
|
|
|
|
|
|
|
|
irq = kcalloc(num_vectors, sizeof(int), GFP_KERNEL);
|
|
|
|
if (!irq)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2021-11-19 15:36:26 +02:00
|
|
|
for (i = 0; i < num_vectors; i++) {
|
|
|
|
msi_data = base_vector;
|
|
|
|
|
2022-04-01 14:53:08 +03:00
|
|
|
if (test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
|
2021-11-19 15:36:26 +02:00
|
|
|
msi_data += i;
|
|
|
|
|
2022-04-01 14:53:08 +03:00
|
|
|
irq[i] = ath11k_pci_get_msi_irq(ab, msi_data);
|
2021-11-19 15:36:26 +02:00
|
|
|
}
|
2020-08-13 12:04:24 +03:00
|
|
|
|
|
|
|
ab_pci->mhi_ctrl->irq = irq;
|
|
|
|
ab_pci->mhi_ctrl->nr_irqs = num_vectors;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ath11k_mhi_op_runtime_get(struct mhi_controller *mhi_cntrl)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ath11k_mhi_op_runtime_put(struct mhi_controller *mhi_cntrl)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
ath11k: add support for device recovery for QCA6390/WCN6855
Currently ath11k has device recovery logic, it is introduced by this
patch "ath11k: Add support for subsystem recovery" which is upstream
by https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=ath11k-bringup&id=3a7b4838b6f6f234239f263ef3dc02e612a083ad.
The patch is for AHB devices such as IPQ8074, it has remote proc module
which is used to download the firmware and boots the processor which
firmware is running on. If firmware crashed, remote proc module will
detect it and download and boot firmware again. Below command will
trigger a firmware crash, and then user can test feature of device
recovery.
Test command:
echo assert > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash
echo assert > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash
Unfortunately, QCA6390 is PCIe bus, it does not have the remote proc
module, it use mhi module to communicate between firmware and ath11k.
So ath11k does not support device recovery for QCA6390 currently.
This patch is to add the extra logic which is different for QCA6390.
When firmware crashed, MHI_CB_EE_RDDM event will be indicate by
firmware and then ath11k_mhi_op_status_cb which is the callback of
mhi_controller will receive the MHI_CB_EE_RDDM event, then ath11k
will start to do recovery process, ath11k_core_reset() calls
ath11k_hif_power_down()/ath11k_hif_power_up(), then the mhi/ath11k
will start to download and boot firmware. There are some logic to
avoid deadloop recovery and two simultaneous recovery operations.
And because it has muti-radios for the soc, so it add some logic
in ath11k_mac_op_reconfig_complete() to make sure all radios has
reconfig complete and then complete the device recovery.
Also it add workqueue_aux, because ab->workqueue is used when receive
ATH11K_QMI_EVENT_FW_READY in recovery process(queue_work(ab->workqueue,
&ab->restart_work)), and ath11k_core_reset will wait for max
ATH11K_RESET_TIMEOUT_HZ for the previous restart_work finished, if
ath11k_core_reset also queued in ab->workqueue, then it will delay
restart_work of previous recovery and lead previous recovery fail.
ath11k recovery success for QCA6390/WCN6855 after apply this patch.
Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220228064606.8981-2-quic_wgong@quicinc.com
2022-02-28 01:46:03 -05:00
|
|
|
static char *ath11k_mhi_op_callback_to_str(enum mhi_callback reason)
|
|
|
|
{
|
|
|
|
switch (reason) {
|
|
|
|
case MHI_CB_IDLE:
|
|
|
|
return "MHI_CB_IDLE";
|
|
|
|
case MHI_CB_PENDING_DATA:
|
|
|
|
return "MHI_CB_PENDING_DATA";
|
|
|
|
case MHI_CB_LPM_ENTER:
|
|
|
|
return "MHI_CB_LPM_ENTER";
|
|
|
|
case MHI_CB_LPM_EXIT:
|
|
|
|
return "MHI_CB_LPM_EXIT";
|
|
|
|
case MHI_CB_EE_RDDM:
|
|
|
|
return "MHI_CB_EE_RDDM";
|
|
|
|
case MHI_CB_EE_MISSION_MODE:
|
|
|
|
return "MHI_CB_EE_MISSION_MODE";
|
|
|
|
case MHI_CB_SYS_ERROR:
|
|
|
|
return "MHI_CB_SYS_ERROR";
|
|
|
|
case MHI_CB_FATAL_ERROR:
|
|
|
|
return "MHI_CB_FATAL_ERROR";
|
|
|
|
case MHI_CB_BW_REQ:
|
|
|
|
return "MHI_CB_BW_REQ";
|
|
|
|
default:
|
|
|
|
return "UNKNOWN";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-13 12:04:24 +03:00
|
|
|
static void ath11k_mhi_op_status_cb(struct mhi_controller *mhi_cntrl,
|
|
|
|
enum mhi_callback cb)
|
|
|
|
{
|
2020-12-10 16:05:19 +02:00
|
|
|
struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);
|
2024-01-11 15:14:06 +08:00
|
|
|
struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
|
2020-12-10 16:05:19 +02:00
|
|
|
|
2023-06-09 17:24:28 +03:00
|
|
|
ath11k_dbg(ab, ATH11K_DBG_BOOT, "notify status reason %s\n",
|
ath11k: add support for device recovery for QCA6390/WCN6855
Currently ath11k has device recovery logic, it is introduced by this
patch "ath11k: Add support for subsystem recovery" which is upstream
by https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=ath11k-bringup&id=3a7b4838b6f6f234239f263ef3dc02e612a083ad.
The patch is for AHB devices such as IPQ8074, it has remote proc module
which is used to download the firmware and boots the processor which
firmware is running on. If firmware crashed, remote proc module will
detect it and download and boot firmware again. Below command will
trigger a firmware crash, and then user can test feature of device
recovery.
Test command:
echo assert > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash
echo assert > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash
Unfortunately, QCA6390 is PCIe bus, it does not have the remote proc
module, it use mhi module to communicate between firmware and ath11k.
So ath11k does not support device recovery for QCA6390 currently.
This patch is to add the extra logic which is different for QCA6390.
When firmware crashed, MHI_CB_EE_RDDM event will be indicate by
firmware and then ath11k_mhi_op_status_cb which is the callback of
mhi_controller will receive the MHI_CB_EE_RDDM event, then ath11k
will start to do recovery process, ath11k_core_reset() calls
ath11k_hif_power_down()/ath11k_hif_power_up(), then the mhi/ath11k
will start to download and boot firmware. There are some logic to
avoid deadloop recovery and two simultaneous recovery operations.
And because it has muti-radios for the soc, so it add some logic
in ath11k_mac_op_reconfig_complete() to make sure all radios has
reconfig complete and then complete the device recovery.
Also it add workqueue_aux, because ab->workqueue is used when receive
ATH11K_QMI_EVENT_FW_READY in recovery process(queue_work(ab->workqueue,
&ab->restart_work)), and ath11k_core_reset will wait for max
ATH11K_RESET_TIMEOUT_HZ for the previous restart_work finished, if
ath11k_core_reset also queued in ab->workqueue, then it will delay
restart_work of previous recovery and lead previous recovery fail.
ath11k recovery success for QCA6390/WCN6855 after apply this patch.
Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220228064606.8981-2-quic_wgong@quicinc.com
2022-02-28 01:46:03 -05:00
|
|
|
ath11k_mhi_op_callback_to_str(cb));
|
|
|
|
|
2020-12-10 16:05:19 +02:00
|
|
|
switch (cb) {
|
|
|
|
case MHI_CB_SYS_ERROR:
|
|
|
|
ath11k_warn(ab, "firmware crashed: MHI_CB_SYS_ERROR\n");
|
|
|
|
break;
|
ath11k: add support for device recovery for QCA6390/WCN6855
Currently ath11k has device recovery logic, it is introduced by this
patch "ath11k: Add support for subsystem recovery" which is upstream
by https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=ath11k-bringup&id=3a7b4838b6f6f234239f263ef3dc02e612a083ad.
The patch is for AHB devices such as IPQ8074, it has remote proc module
which is used to download the firmware and boots the processor which
firmware is running on. If firmware crashed, remote proc module will
detect it and download and boot firmware again. Below command will
trigger a firmware crash, and then user can test feature of device
recovery.
Test command:
echo assert > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash
echo assert > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash
Unfortunately, QCA6390 is PCIe bus, it does not have the remote proc
module, it use mhi module to communicate between firmware and ath11k.
So ath11k does not support device recovery for QCA6390 currently.
This patch is to add the extra logic which is different for QCA6390.
When firmware crashed, MHI_CB_EE_RDDM event will be indicate by
firmware and then ath11k_mhi_op_status_cb which is the callback of
mhi_controller will receive the MHI_CB_EE_RDDM event, then ath11k
will start to do recovery process, ath11k_core_reset() calls
ath11k_hif_power_down()/ath11k_hif_power_up(), then the mhi/ath11k
will start to download and boot firmware. There are some logic to
avoid deadloop recovery and two simultaneous recovery operations.
And because it has muti-radios for the soc, so it add some logic
in ath11k_mac_op_reconfig_complete() to make sure all radios has
reconfig complete and then complete the device recovery.
Also it add workqueue_aux, because ab->workqueue is used when receive
ATH11K_QMI_EVENT_FW_READY in recovery process(queue_work(ab->workqueue,
&ab->restart_work)), and ath11k_core_reset will wait for max
ATH11K_RESET_TIMEOUT_HZ for the previous restart_work finished, if
ath11k_core_reset also queued in ab->workqueue, then it will delay
restart_work of previous recovery and lead previous recovery fail.
ath11k recovery success for QCA6390/WCN6855 after apply this patch.
Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220228064606.8981-2-quic_wgong@quicinc.com
2022-02-28 01:46:03 -05:00
|
|
|
case MHI_CB_EE_RDDM:
|
2023-08-26 08:42:42 +03:00
|
|
|
ath11k_warn(ab, "firmware crashed: MHI_CB_EE_RDDM\n");
|
2024-01-11 15:14:06 +08:00
|
|
|
if (ab_pci->mhi_pre_cb == MHI_CB_EE_RDDM) {
|
|
|
|
ath11k_dbg(ab, ATH11K_DBG_BOOT,
|
|
|
|
"do not queue again for consecutive RDDM event\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
ath11k: add support for device recovery for QCA6390/WCN6855
Currently ath11k has device recovery logic, it is introduced by this
patch "ath11k: Add support for subsystem recovery" which is upstream
by https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=ath11k-bringup&id=3a7b4838b6f6f234239f263ef3dc02e612a083ad.
The patch is for AHB devices such as IPQ8074, it has remote proc module
which is used to download the firmware and boots the processor which
firmware is running on. If firmware crashed, remote proc module will
detect it and download and boot firmware again. Below command will
trigger a firmware crash, and then user can test feature of device
recovery.
Test command:
echo assert > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash
echo assert > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash
Unfortunately, QCA6390 is PCIe bus, it does not have the remote proc
module, it use mhi module to communicate between firmware and ath11k.
So ath11k does not support device recovery for QCA6390 currently.
This patch is to add the extra logic which is different for QCA6390.
When firmware crashed, MHI_CB_EE_RDDM event will be indicate by
firmware and then ath11k_mhi_op_status_cb which is the callback of
mhi_controller will receive the MHI_CB_EE_RDDM event, then ath11k
will start to do recovery process, ath11k_core_reset() calls
ath11k_hif_power_down()/ath11k_hif_power_up(), then the mhi/ath11k
will start to download and boot firmware. There are some logic to
avoid deadloop recovery and two simultaneous recovery operations.
And because it has muti-radios for the soc, so it add some logic
in ath11k_mac_op_reconfig_complete() to make sure all radios has
reconfig complete and then complete the device recovery.
Also it add workqueue_aux, because ab->workqueue is used when receive
ATH11K_QMI_EVENT_FW_READY in recovery process(queue_work(ab->workqueue,
&ab->restart_work)), and ath11k_core_reset will wait for max
ATH11K_RESET_TIMEOUT_HZ for the previous restart_work finished, if
ath11k_core_reset also queued in ab->workqueue, then it will delay
restart_work of previous recovery and lead previous recovery fail.
ath11k recovery success for QCA6390/WCN6855 after apply this patch.
Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220228064606.8981-2-quic_wgong@quicinc.com
2022-02-28 01:46:03 -05:00
|
|
|
if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))
|
|
|
|
queue_work(ab->workqueue_aux, &ab->reset_work);
|
2024-01-11 15:14:06 +08:00
|
|
|
|
ath11k: add support for device recovery for QCA6390/WCN6855
Currently ath11k has device recovery logic, it is introduced by this
patch "ath11k: Add support for subsystem recovery" which is upstream
by https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=ath11k-bringup&id=3a7b4838b6f6f234239f263ef3dc02e612a083ad.
The patch is for AHB devices such as IPQ8074, it has remote proc module
which is used to download the firmware and boots the processor which
firmware is running on. If firmware crashed, remote proc module will
detect it and download and boot firmware again. Below command will
trigger a firmware crash, and then user can test feature of device
recovery.
Test command:
echo assert > /sys/kernel/debug/ath11k/qca6390\ hw2.0/simulate_fw_crash
echo assert > /sys/kernel/debug/ath11k/wcn6855\ hw2.0/simulate_fw_crash
Unfortunately, QCA6390 is PCIe bus, it does not have the remote proc
module, it use mhi module to communicate between firmware and ath11k.
So ath11k does not support device recovery for QCA6390 currently.
This patch is to add the extra logic which is different for QCA6390.
When firmware crashed, MHI_CB_EE_RDDM event will be indicate by
firmware and then ath11k_mhi_op_status_cb which is the callback of
mhi_controller will receive the MHI_CB_EE_RDDM event, then ath11k
will start to do recovery process, ath11k_core_reset() calls
ath11k_hif_power_down()/ath11k_hif_power_up(), then the mhi/ath11k
will start to download and boot firmware. There are some logic to
avoid deadloop recovery and two simultaneous recovery operations.
And because it has muti-radios for the soc, so it add some logic
in ath11k_mac_op_reconfig_complete() to make sure all radios has
reconfig complete and then complete the device recovery.
Also it add workqueue_aux, because ab->workqueue is used when receive
ATH11K_QMI_EVENT_FW_READY in recovery process(queue_work(ab->workqueue,
&ab->restart_work)), and ath11k_core_reset will wait for max
ATH11K_RESET_TIMEOUT_HZ for the previous restart_work finished, if
ath11k_core_reset also queued in ab->workqueue, then it will delay
restart_work of previous recovery and lead previous recovery fail.
ath11k recovery success for QCA6390/WCN6855 after apply this patch.
Tested-on: QCA6390 hw2.0 PCI WLAN.HST.1.0.1-01740-QCAHSTSWPLZ_V2_TO_X86-1
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03003-QCAHSPSWPL_V1_V2_SILICONZ_LITE-2
Signed-off-by: Wen Gong <quic_wgong@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220228064606.8981-2-quic_wgong@quicinc.com
2022-02-28 01:46:03 -05:00
|
|
|
break;
|
2020-12-10 16:05:19 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2024-01-11 15:14:06 +08:00
|
|
|
|
|
|
|
ab_pci->mhi_pre_cb = cb;
|
2020-08-13 12:04:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,
|
|
|
|
void __iomem *addr,
|
|
|
|
u32 *out)
|
|
|
|
{
|
|
|
|
*out = readl(addr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,
|
|
|
|
void __iomem *addr,
|
|
|
|
u32 val)
|
|
|
|
{
|
|
|
|
writel(val, addr);
|
|
|
|
}
|
|
|
|
|
2021-12-14 17:39:43 +02:00
|
|
|
static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl)
|
|
|
|
{
|
|
|
|
struct device_node *np;
|
|
|
|
struct resource res;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
np = of_find_node_by_type(NULL, "memory");
|
|
|
|
if (!np)
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
ret = of_address_to_resource(np, 0, &res);
|
2022-01-10 16:24:13 +02:00
|
|
|
of_node_put(np);
|
2021-12-14 17:39:43 +02:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
mhi_ctrl->iova_start = res.start + 0x1000000;
|
|
|
|
mhi_ctrl->iova_stop = res.end;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-13 12:04:24 +03:00
|
|
|
int ath11k_mhi_register(struct ath11k_pci *ab_pci)
|
|
|
|
{
|
|
|
|
struct ath11k_base *ab = ab_pci->ab;
|
|
|
|
struct mhi_controller *mhi_ctrl;
|
2024-02-23 07:39:31 -08:00
|
|
|
const struct mhi_controller_config *ath11k_mhi_config;
|
2020-08-13 12:04:24 +03:00
|
|
|
int ret;
|
|
|
|
|
2020-11-17 09:33:56 -08:00
|
|
|
mhi_ctrl = mhi_alloc_controller();
|
2020-08-13 12:04:24 +03:00
|
|
|
if (!mhi_ctrl)
|
2020-08-26 14:34:17 +03:00
|
|
|
return -ENOMEM;
|
2020-08-13 12:04:24 +03:00
|
|
|
|
|
|
|
ab_pci->mhi_ctrl = mhi_ctrl;
|
|
|
|
mhi_ctrl->cntrl_dev = ab->dev;
|
|
|
|
mhi_ctrl->regs = ab->mem;
|
2021-08-02 10:42:51 +05:30
|
|
|
mhi_ctrl->reg_len = ab->mem_len;
|
2020-08-13 12:04:24 +03:00
|
|
|
|
2023-10-18 11:37:06 +03:00
|
|
|
if (ab->fw.amss_data && ab->fw.amss_len > 0) {
|
|
|
|
/* use MHI firmware file from firmware-N.bin */
|
|
|
|
mhi_ctrl->fw_data = ab->fw.amss_data;
|
|
|
|
mhi_ctrl->fw_sz = ab->fw.amss_len;
|
|
|
|
} else {
|
|
|
|
/* use the old separate mhi.bin MHI firmware file */
|
|
|
|
ath11k_core_create_firmware_path(ab, ATH11K_AMSS_FILE,
|
|
|
|
ab_pci->amss_path,
|
|
|
|
sizeof(ab_pci->amss_path));
|
|
|
|
mhi_ctrl->fw_image = ab_pci->amss_path;
|
|
|
|
}
|
|
|
|
|
2020-08-13 12:04:24 +03:00
|
|
|
ret = ath11k_mhi_get_msi(ab_pci);
|
|
|
|
if (ret) {
|
|
|
|
ath11k_err(ab, "failed to get msi for mhi\n");
|
2022-09-07 15:37:04 +08:00
|
|
|
goto free_controller;
|
2020-08-13 12:04:24 +03:00
|
|
|
}
|
|
|
|
|
2022-04-01 14:53:08 +03:00
|
|
|
if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
|
2021-11-19 15:36:26 +02:00
|
|
|
mhi_ctrl->irq_flags = IRQF_SHARED | IRQF_NOBALANCING;
|
|
|
|
|
2021-12-14 17:39:43 +02:00
|
|
|
if (test_bit(ATH11K_FLAG_FIXED_MEM_RGN, &ab->dev_flags)) {
|
|
|
|
ret = ath11k_mhi_read_addr_from_dt(mhi_ctrl);
|
|
|
|
if (ret < 0)
|
2022-09-07 15:37:04 +08:00
|
|
|
goto free_controller;
|
2021-12-14 17:39:43 +02:00
|
|
|
} else {
|
|
|
|
mhi_ctrl->iova_start = 0;
|
wifi: ath11k: enable 36 bit mask for stream DMA
Currently 32 bit DMA mask is used, telling kernel to get us an DMA
address under 4GB when mapping a buffer. This results in a very high
CPU overhead in the case where IOMMU is disabled and more than 4GB
system memory is installed. The reason is, with more than 4GB memory
installed, kernel is likely to allocate a buffer whose physical
address is above 4GB. While with IOMMU disabled, kernel has to involve
SWIOTLB to map/unmap that buffer, which consumes lots of CPU cycles.
We did hit an issue caused by the reason mentioned above: in a system
that disables IOMMU and gets 8GB memory installed, a total of 40.5%
CPU usage is observed in throughput test. CPU profiling shows nearly
60% of CPU cycles are consumed by SWIOTLB.
By enabling 36 bit DMA mask, we can bypass SWIOTLB for any buffer
whose physical address is below 64GB. There are two types of DMA mask
within struct device, named dma_mask and coherent_dma_mask. Here we
only enable 36 bit for dma_mask, because firmware crashes if
coherent_dma_mask is also enabled, due to some unknown hardware
limitations. This is acceptable because coherent_dma_mask is used for
mapping a consistent DMA buffer, which generally does not happen in
a hot path.
With this change, the total CPU usage mentioned in above issue drops
to 18.9%.
Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240123015201.28939-1-quic_bqiang@quicinc.com
2024-01-23 09:52:01 +08:00
|
|
|
mhi_ctrl->iova_stop = ab_pci->dma_mask;
|
2021-12-14 17:39:43 +02:00
|
|
|
}
|
|
|
|
|
2022-02-14 19:53:16 +02:00
|
|
|
mhi_ctrl->rddm_size = RDDM_DUMP_SIZE;
|
2020-08-13 12:04:24 +03:00
|
|
|
mhi_ctrl->sbl_size = SZ_512K;
|
|
|
|
mhi_ctrl->seg_len = SZ_512K;
|
|
|
|
mhi_ctrl->fbc_download = true;
|
|
|
|
mhi_ctrl->runtime_get = ath11k_mhi_op_runtime_get;
|
|
|
|
mhi_ctrl->runtime_put = ath11k_mhi_op_runtime_put;
|
|
|
|
mhi_ctrl->status_cb = ath11k_mhi_op_status_cb;
|
|
|
|
mhi_ctrl->read_reg = ath11k_mhi_op_read_reg;
|
|
|
|
mhi_ctrl->write_reg = ath11k_mhi_op_write_reg;
|
|
|
|
|
2021-04-08 10:27:10 +05:30
|
|
|
switch (ab->hw_rev) {
|
|
|
|
case ATH11K_HW_QCN9074_HW10:
|
2021-02-16 09:16:08 +02:00
|
|
|
ath11k_mhi_config = &ath11k_mhi_config_qcn9074;
|
2021-04-08 10:27:10 +05:30
|
|
|
break;
|
|
|
|
case ATH11K_HW_QCA6390_HW20:
|
2021-05-31 17:41:28 +03:00
|
|
|
case ATH11K_HW_WCN6855_HW20:
|
2021-11-29 10:56:12 +08:00
|
|
|
case ATH11K_HW_WCN6855_HW21:
|
2024-01-09 10:13:36 +08:00
|
|
|
case ATH11K_HW_QCA2066_HW21:
|
2021-04-08 10:27:10 +05:30
|
|
|
ath11k_mhi_config = &ath11k_mhi_config_qca6390;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ath11k_err(ab, "failed assign mhi_config for unknown hw rev %d\n",
|
|
|
|
ab->hw_rev);
|
2022-09-07 15:37:04 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto free_controller;
|
2021-04-08 10:27:10 +05:30
|
|
|
}
|
2021-02-16 09:16:08 +02:00
|
|
|
|
2024-01-11 15:14:06 +08:00
|
|
|
ab_pci->mhi_pre_cb = MHI_CB_INVALID;
|
2021-02-16 09:16:08 +02:00
|
|
|
ret = mhi_register_controller(mhi_ctrl, ath11k_mhi_config);
|
2020-08-13 12:04:24 +03:00
|
|
|
if (ret) {
|
|
|
|
ath11k_err(ab, "failed to register to mhi bus, err = %d\n", ret);
|
2022-09-07 15:37:04 +08:00
|
|
|
goto free_controller;
|
2020-08-13 12:04:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2022-09-07 15:37:04 +08:00
|
|
|
|
|
|
|
free_controller:
|
|
|
|
mhi_free_controller(mhi_ctrl);
|
|
|
|
ab_pci->mhi_ctrl = NULL;
|
|
|
|
return ret;
|
2020-08-13 12:04:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void ath11k_mhi_unregister(struct ath11k_pci *ab_pci)
|
|
|
|
{
|
|
|
|
struct mhi_controller *mhi_ctrl = ab_pci->mhi_ctrl;
|
|
|
|
|
|
|
|
mhi_unregister_controller(mhi_ctrl);
|
|
|
|
kfree(mhi_ctrl->irq);
|
2020-11-17 09:33:56 -08:00
|
|
|
mhi_free_controller(mhi_ctrl);
|
2020-08-13 12:04:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int ath11k_mhi_start(struct ath11k_pci *ab_pci)
|
|
|
|
{
|
2022-04-05 11:26:44 +03:00
|
|
|
struct ath11k_base *ab = ab_pci->ab;
|
2020-08-13 12:04:24 +03:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS;
|
|
|
|
|
2022-04-01 20:30:40 +03:00
|
|
|
ret = mhi_prepare_for_power_up(ab_pci->mhi_ctrl);
|
2022-04-05 11:26:44 +03:00
|
|
|
if (ret) {
|
|
|
|
ath11k_warn(ab, "failed to prepare mhi: %d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2020-08-13 12:04:24 +03:00
|
|
|
|
2022-04-01 20:30:40 +03:00
|
|
|
ret = mhi_sync_power_up(ab_pci->mhi_ctrl);
|
2022-04-05 11:26:44 +03:00
|
|
|
if (ret) {
|
|
|
|
ath11k_warn(ab, "failed to power up mhi: %d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2020-08-13 12:04:24 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
wifi: ath11k: support hibernation
Now that all infrastructure is in place and ath11k is fixed to handle all the
corner cases, power down the ath11k firmware during suspend and power it back
up during resume. This fixes the problem when using hibernation with ath11k PCI
devices.
For suspend, two conditions needs to be satisfied:
1. since MHI channel unprepare would be done in late suspend stage,
ath11k needs to get all QMI-dependent things done before that stage.
2. and because unprepare MHI channels requires a working MHI stack,
ath11k is not allowed to call mhi_power_down() until that finishes.
So the original suspend callback is separated into two parts: the first part
handles all QMI-dependent things in suspend callback; while the second part
powers down MHI in suspend_late callback. This is valid because kernel calls
ath11k's suspend callback before all suspend_late callbacks, making the first
condition happy. And because MHI devices are children of ath11k device
(ab->dev), kernel guarantees that ath11k's suspend_late callback is called
after QRTR's suspend_late callback, this satisfies the second condition.
Above analysis also applies to resume process. so the original resume
callback is separated into two parts: the first part powers up MHI stack
in resume_early callback, this guarantees MHI stack is working when
QRTR tries to prepare MHI channels (kernel calls QRTR's resume_early callback
after ath11k's resume_early callback, due to the child-father relationship);
the second part waits for the completion of restart, which won't fail now
since MHI channels are ready for use by QMI.
Another notable change is in power down path, we tell mhi_power_down() to not
to destroy MHI devices, making it possible for QRTR to help unprepare/prepare
MHI channels, and finally get us rid of the probe-defer issue when resume.
Also change related code due to interface changes.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Tested-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240305021320.3367-4-quic_bqiang@quicinc.com
2024-04-08 17:41:50 +03:00
|
|
|
void ath11k_mhi_stop(struct ath11k_pci *ab_pci, bool is_suspend)
|
2020-08-13 12:04:24 +03:00
|
|
|
{
|
wifi: ath11k: support hibernation
Now that all infrastructure is in place and ath11k is fixed to handle all the
corner cases, power down the ath11k firmware during suspend and power it back
up during resume. This fixes the problem when using hibernation with ath11k PCI
devices.
For suspend, two conditions needs to be satisfied:
1. since MHI channel unprepare would be done in late suspend stage,
ath11k needs to get all QMI-dependent things done before that stage.
2. and because unprepare MHI channels requires a working MHI stack,
ath11k is not allowed to call mhi_power_down() until that finishes.
So the original suspend callback is separated into two parts: the first part
handles all QMI-dependent things in suspend callback; while the second part
powers down MHI in suspend_late callback. This is valid because kernel calls
ath11k's suspend callback before all suspend_late callbacks, making the first
condition happy. And because MHI devices are children of ath11k device
(ab->dev), kernel guarantees that ath11k's suspend_late callback is called
after QRTR's suspend_late callback, this satisfies the second condition.
Above analysis also applies to resume process. so the original resume
callback is separated into two parts: the first part powers up MHI stack
in resume_early callback, this guarantees MHI stack is working when
QRTR tries to prepare MHI channels (kernel calls QRTR's resume_early callback
after ath11k's resume_early callback, due to the child-father relationship);
the second part waits for the completion of restart, which won't fail now
since MHI channels are ready for use by QMI.
Another notable change is in power down path, we tell mhi_power_down() to not
to destroy MHI devices, making it possible for QRTR to help unprepare/prepare
MHI channels, and finally get us rid of the probe-defer issue when resume.
Also change related code due to interface changes.
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.30
Tested-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Baochen Qiang <quic_bqiang@quicinc.com>
Acked-by: Jeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240305021320.3367-4-quic_bqiang@quicinc.com
2024-04-08 17:41:50 +03:00
|
|
|
/* During suspend we need to use mhi_power_down_keep_dev()
|
|
|
|
* workaround, otherwise ath11k_core_resume() will timeout
|
|
|
|
* during resume.
|
|
|
|
*/
|
|
|
|
if (is_suspend)
|
|
|
|
mhi_power_down_keep_dev(ab_pci->mhi_ctrl, true);
|
|
|
|
else
|
|
|
|
mhi_power_down(ab_pci->mhi_ctrl, true);
|
|
|
|
|
2022-04-01 20:30:40 +03:00
|
|
|
mhi_unprepare_after_power_down(ab_pci->mhi_ctrl);
|
2020-08-13 12:04:24 +03:00
|
|
|
}
|
|
|
|
|
2022-04-05 11:26:39 +03:00
|
|
|
int ath11k_mhi_suspend(struct ath11k_pci *ab_pci)
|
2020-12-11 19:35:41 +02:00
|
|
|
{
|
2022-04-05 11:26:39 +03:00
|
|
|
struct ath11k_base *ab = ab_pci->ab;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = mhi_pm_suspend(ab_pci->mhi_ctrl);
|
|
|
|
if (ret) {
|
|
|
|
ath11k_warn(ab, "failed to suspend mhi: %d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-12-11 19:35:41 +02:00
|
|
|
}
|
|
|
|
|
2022-04-05 11:26:39 +03:00
|
|
|
int ath11k_mhi_resume(struct ath11k_pci *ab_pci)
|
2020-12-11 19:35:41 +02:00
|
|
|
{
|
2022-04-05 11:26:39 +03:00
|
|
|
struct ath11k_base *ab = ab_pci->ab;
|
|
|
|
int ret;
|
|
|
|
|
2022-04-01 20:30:40 +03:00
|
|
|
/* Do force MHI resume as some devices like QCA6390, WCN6855
|
|
|
|
* are not in M3 state but they are functional. So just ignore
|
|
|
|
* the MHI state while resuming.
|
|
|
|
*/
|
2022-04-05 11:26:39 +03:00
|
|
|
ret = mhi_pm_resume_force(ab_pci->mhi_ctrl);
|
|
|
|
if (ret) {
|
|
|
|
ath11k_warn(ab, "failed to resume mhi: %d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-12-11 19:35:41 +02:00
|
|
|
}
|