This is a follow-on series for WCN6750 adding several
features, fixes and throughput enhancements.
Manikanta Pubbisetty (8):
ath11k: Enable low power mode when WLAN is not active
ath11k: Register shutdown handler for WCN6750
ath11k: Cold boot calibration support on WCN6750
ath11k: Cap NSS of HE peer to radio supported NSS
ath11k: Enable threaded NAPI on WCN6750
ath11k: Increase TCL data ring size
ath11k: Add multi TX ring support for WCN6750
ath11k: Add Coredump support of MSA region for WCN6750
---
Note: This series is dependent on another series adding
support for WCN6750 in ATH11K.
https://patchwork.kernel.org/project/linux-wireless/list/?series=605793
drivers/net/wireless/ath/ath11k/Kconfig | 1 +
drivers/net/wireless/ath/ath11k/Makefile | 1 +
drivers/net/wireless/ath/ath11k/ahb.c | 126 +++++++++++++++++++++-
drivers/net/wireless/ath/ath11k/ahb.h | 8 +-
drivers/net/wireless/ath/ath11k/core.c | 168 ++++++++++++++++++++++++-----
drivers/net/wireless/ath/ath11k/core.h | 5 +-
drivers/net/wireless/ath/ath11k/coredump.c | 87 +++++++++++++++
drivers/net/wireless/ath/ath11k/coredump.h | 71 ++++++++++++
drivers/net/wireless/ath/ath11k/dp.c | 23 ++--
drivers/net/wireless/ath/ath11k/dp.h | 5 +-
drivers/net/wireless/ath/ath11k/dp_tx.c | 14 +--
drivers/net/wireless/ath/ath11k/hal.c | 4 +-
drivers/net/wireless/ath/ath11k/hal.h | 4 +-
drivers/net/wireless/ath/ath11k/hal_tx.c | 4 +-
drivers/net/wireless/ath/ath11k/hal_tx.h | 2 +
drivers/net/wireless/ath/ath11k/hw.c | 113 ++++++++++++++++++-
drivers/net/wireless/ath/ath11k/hw.h | 17 ++-
drivers/net/wireless/ath/ath11k/mac.c | 28 ++++-
drivers/net/wireless/ath/ath11k/pci_cmn.c | 4 +-
drivers/net/wireless/ath/ath11k/qmi.c | 47 +++++++-
drivers/net/wireless/ath/ath11k/qmi.h | 12 ++-
drivers/net/wireless/ath/ath11k/thermal.c | 12 +++
22 files changed, 685 insertions(+), 71 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath11k/coredump.c
create mode 100644 drivers/net/wireless/ath/ath11k/coredump.h
--
2.7.4
When the system shuts down, SMMU driver will be stopped
and will not assist in IOVA translation. SMMU driver expects
all of its consumers to shutdown before shutting down itself.
WCN6750 being one of the consumer should not perform DMA
activity after SMMU shutdown which will otherwise result
in a SMMU fault.
SMMU driver will call the shutdown() callback of all its
consumer devices and the consumers shall stop further DMA
activity after the invocation of their respective shutdown()
callback.
Register the shutdown() callback to the platform core for WCN6750.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/ahb.c | 36 ++++++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath11k/qmi.c | 3 +--
2 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 7cb13a0..97ee8c4 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@@ -1069,6 +1069,7 @@ 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);
ath11k_core_deinit(ab);
qmi_fail:
@@ -1082,6 +1083,38 @@ static int ath11k_ahb_remove(struct platform_device *pdev)
return 0;
}
+static void ath11k_ahb_shutdown(struct platform_device *pdev)
+{
+ struct ath11k_base *ab = platform_get_drvdata(pdev);
+ unsigned long left;
+
+ 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);
+ if (!left)
+ ath11k_warn(ab, "failed to receive recovery response completion\n");
+ }
+
+ set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
+ cancel_work_sync(&ab->restart_work);
+ cancel_work_sync(&ab->qmi.event_work);
+
+ if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))
+ goto free_resources;
+
+ ath11k_core_deinit(ab);
+
+free_resources:
+ ath11k_ahb_free_irq(ab);
+ ath11k_hal_srng_deinit(ab);
+ ath11k_ahb_fw_resource_deinit(ab);
+ ath11k_ce_free_pipes(ab);
+ ath11k_core_free(ab);
+ platform_set_drvdata(pdev, NULL);
+}
+
static struct platform_driver ath11k_ahb_driver = {
.driver = {
.name = "ath11k",
@@ -1089,6 +1122,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/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index 4745ff9..f50c273 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/elf.h>
@@ -3185,7 +3185,6 @@ int ath11k_qmi_init_service(struct ath11k_base *ab)
void ath11k_qmi_deinit_service(struct ath11k_base *ab)
{
qmi_handle_release(&ab->qmi.handle);
- cancel_work_sync(&ab->qmi.event_work);
destroy_workqueue(ab->qmi.event_wq);
ath11k_qmi_m3_free(ab);
ath11k_qmi_free_target_mem_chunk(ab);
--
2.7.4
Add cold boot calibration support on WCN6750. Unlike other
chipsets where firmware (FW) is restarted after cold boot
caliration is completed, it is recommended not to restart
the firmware for WCN6750.
Also, QMI message IDs for some of the QMI messages were incorrectly
defined in the original implementation, these has to be corrected
for enabling cold boot support on WCN6750. These corrections are
applicable for all chipsets and will not impact them.
QMI message flow for WCN6750 with cold boot support:
FW_INIT_DONE to HOST -> CALIBRATION Mode to FW -> CAL_DONE to Host ->
FW_READY to Host -> MODE_ON to FW
QMI message flow for other chipsets with cold boot support:
FW_INIT_DONE to Host -> CALIBRATION Mode to FW -> CAL_DONE to Host ->
Trigger FW restart -> FW_INIT_DONE to HOST -> MODE_ON to FW
QMI message flow for chipsets without cold boot support:
FW_INIT_DONE to Host -> MODE_ON to FW
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/ahb.c | 3 ++-
drivers/net/wireless/ath/ath11k/core.c | 9 ++++++-
drivers/net/wireless/ath/ath11k/hw.h | 1 +
drivers/net/wireless/ath/ath11k/qmi.c | 44 +++++++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath11k/qmi.h | 12 +++++++---
5 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 97ee8c4..4301f62 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -378,7 +378,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.cold_boot_fw_restart == 0)
return 0;
ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n");
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index acb8861..643f655 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -83,6 +83,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = false,
.supports_sta_ps = false,
.cold_boot_calib = true,
+ .cold_boot_fw_restart = true,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@@ -147,6 +148,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = false,
.supports_sta_ps = false,
.cold_boot_calib = true,
+ .cold_boot_fw_restart = true,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@@ -210,6 +212,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = true,
.supports_sta_ps = true,
.cold_boot_calib = false,
+ .cold_boot_fw_restart = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@@ -273,6 +276,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = false,
.supports_sta_ps = false,
.cold_boot_calib = false,
+ .cold_boot_fw_restart = false,
.fw_mem_mode = 2,
.num_vdevs = 8,
.num_peers = 128,
@@ -336,6 +340,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = true,
.supports_sta_ps = true,
.cold_boot_calib = false,
+ .cold_boot_fw_restart = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@@ -398,6 +403,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.idle_ps = true,
.supports_sta_ps = true,
.cold_boot_calib = false,
+ .cold_boot_fw_restart = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
@@ -459,7 +465,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,
+ .cold_boot_fw_restart = false,
.fw_mem_mode = 0,
.num_vdevs = 16 + 1,
.num_peers = 512,
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index a38745e..ed4b72b 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -193,6 +193,7 @@ struct ath11k_hw_params {
bool supports_rssi_stats;
bool fw_wmi_diag_event;
bool non_wow_suspend;
+ bool cold_boot_fw_restart;
};
struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index f50c273..1f9b751d 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -1693,6 +1693,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;
@@ -2999,6 +3006,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,
@@ -3029,6 +3049,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,
@@ -3111,7 +3139,7 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
if (ret < 0)
set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
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);
@@ -3131,6 +3159,20 @@ 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.cold_boot_fw_restart) {
+ 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 593d81ed..f3cea7d 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef 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,
};
@@ -289,6 +291,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
--
2.7.4
Cap NSS of HE peer to radio supported NSS during assoc, this
is needed as the WCN6750 FW expects peer NSS to be <= radio
supported NSS, this will fix the FW assert because of peer
NSS being greater than max NSS supported by the radio.
Since we are capping the NSS to the NSS that radio supports,
this change should not impact other supported hardware.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/mac.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index 2402405..55cdee9 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -2274,6 +2274,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
max_nss = i + 1;
}
arg->peer_nss = min(sta->rx_nss, max_nss);
+ arg->peer_nss = min_t(u32, arg->peer_nss, ar->num_rx_chains);
if (arg->peer_phymode == MODE_11AX_HE160 ||
arg->peer_phymode == MODE_11AX_HE80_80) {
--
2.7.4
Enable threaded NAPI on WCN6750; Unlike traditional NAPI
poll which runs in softirq context and on the core which
scheduled the NAPI, threaded NAPI makes use of kernel threads
which are under direct control of the scheduler and helps
in balancing the NAPI processing load across multiple CPUs,
this helps in improving throughput.
In the case of WCN6750, enabling threaded NAPI has improved
160Mhz RX throughput by nearly 400Mbps.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/ahb.c | 2 ++
drivers/net/wireless/ath/ath11k/core.c | 7 +++++++
drivers/net/wireless/ath/ath11k/hw.h | 1 +
drivers/net/wireless/ath/ath11k/pci_cmn.c | 4 +++-
4 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 4301f62..fd3bb43 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -331,6 +331,8 @@ 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) {
+ if (ab->hw_params.threaded_napi)
+ dev_set_threaded(&irq_grp->napi_ndev, true);
napi_enable(&irq_grp->napi);
irq_grp->napi_enabled = true;
}
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 643f655..161bddf 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -99,6 +99,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_rssi_stats = false,
.fw_wmi_diag_event = false,
.non_wow_suspend = false,
+ .threaded_napi = false,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -164,6 +165,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_rssi_stats = false,
.fw_wmi_diag_event = false,
.non_wow_suspend = false,
+ .threaded_napi = false,
},
{
.name = "qca6390 hw2.0",
@@ -228,6 +230,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_rssi_stats = true,
.fw_wmi_diag_event = true,
.non_wow_suspend = false,
+ .threaded_napi = false,
},
{
.name = "qcn9074 hw1.0",
@@ -292,6 +295,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_rssi_stats = false,
.fw_wmi_diag_event = false,
.non_wow_suspend = false,
+ .threaded_napi = false,
},
{
.name = "wcn6855 hw2.0",
@@ -356,6 +360,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_rssi_stats = true,
.fw_wmi_diag_event = true,
.non_wow_suspend = false,
+ .threaded_napi = false,
},
{
.name = "wcn6855 hw2.1",
@@ -419,6 +424,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_rssi_stats = true,
.fw_wmi_diag_event = true,
.non_wow_suspend = false,
+ .threaded_napi = false,
},
{
.name = "wcn6750 hw1.0",
@@ -482,6 +488,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_rssi_stats = true,
.fw_wmi_diag_event = false,
.non_wow_suspend = true,
+ .threaded_napi = true,
},
};
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index ed4b72b..d33b9b7 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -194,6 +194,7 @@ struct ath11k_hw_params {
bool fw_wmi_diag_event;
bool non_wow_suspend;
bool cold_boot_fw_restart;
+ bool threaded_napi;
};
struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/pci_cmn.c b/drivers/net/wireless/ath/ath11k/pci_cmn.c
index 047fcd7..6550f7c 100644
--- a/drivers/net/wireless/ath/ath11k/pci_cmn.c
+++ b/drivers/net/wireless/ath/ath11k/pci_cmn.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "core.h"
@@ -425,6 +425,8 @@ void ath11k_pci_ext_irq_enable(struct ath11k_base *ab)
struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
if (!irq_grp->napi_enabled) {
+ if (ab->hw_params.threaded_napi)
+ dev_set_threaded(&irq_grp->napi_ndev, true);
napi_enable(&irq_grp->napi);
irq_grp->napi_enabled = true;
}
--
2.7.4
In the context of WCN6750, MSA is a 12MB reserved memory region
entirely used by WCN6750 firmware for it's operation. This memory
carries useful information required to debug firmware/hardware
issues. Therefore add coredump support to dump MSA region during
FW assert for WCN6750.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/Kconfig | 1 +
drivers/net/wireless/ath/ath11k/Makefile | 1 +
drivers/net/wireless/ath/ath11k/ahb.c | 85 ++++++++++++++++++++++++++++-
drivers/net/wireless/ath/ath11k/ahb.h | 8 ++-
drivers/net/wireless/ath/ath11k/coredump.c | 87 ++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath11k/coredump.h | 71 ++++++++++++++++++++++++
6 files changed, 251 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/wireless/ath/ath11k/coredump.c
create mode 100644 drivers/net/wireless/ath/ath11k/coredump.h
diff --git a/drivers/net/wireless/ath/ath11k/Kconfig b/drivers/net/wireless/ath/ath11k/Kconfig
index ad5cc6c..96074f5 100644
--- a/drivers/net/wireless/ath/ath11k/Kconfig
+++ b/drivers/net/wireless/ath/ath11k/Kconfig
@@ -5,6 +5,7 @@ config ATH11K
depends on CRYPTO_MICHAEL_MIC
select ATH_COMMON
select QCOM_QMI_HELPERS
+ select WANT_DEV_COREDUMP
help
This module adds support for Qualcomm Technologies 802.11ax family of
chipsets.
diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile
index e3ea6a2..ec3c394 100644
--- a/drivers/net/wireless/ath/ath11k/Makefile
+++ b/drivers/net/wireless/ath/ath11k/Makefile
@@ -24,6 +24,7 @@ ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath11k-$(CONFIG_ATH11K_TRACING) += trace.o
ath11k-$(CONFIG_THERMAL) += thermal.o
ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o
+ath11k-$(CONFIG_DEV_COREDUMP) += coredump.o
obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o
ath11k_ahb-y += ahb.o pci_cmn.o
diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index fd3bb43..83b1da8 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -15,7 +15,9 @@
#include "debug.h"
#include "hif.h"
#include <linux/remoteproc.h>
+#include <linux/remoteproc/qcom_rproc.h>
#include "pci_cmn.h"
+#include "coredump.h"
static const struct of_device_id ath11k_ahb_of_match[] = {
/* TODO: Should we change the compatible string to something similar
@@ -777,6 +779,74 @@ static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
return 0;
}
+static void ath11k_ahb_coredump_msa(struct ath11k_base *ab)
+{
+ struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+ struct ath11k_msa_dump msa_data;
+
+ msa_data.paddr = ab_ahb->fw.msa_paddr;
+ msa_data.vaddr = ab_ahb->fw.msa_vaddr;
+ msa_data.size = ab_ahb->fw.msa_size;
+
+ ath11k_coredump_msa(ab, &msa_data);
+}
+
+static int ath11k_ahb_ssr_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct ath11k_ahb *ab_ahb = container_of(nb, struct ath11k_ahb, nb);
+ struct ath11k_base *ab = ab_ahb->ab;
+ struct qcom_ssr_notify_data *notify_data = data;
+
+ switch (action) {
+ case QCOM_SSR_BEFORE_POWERUP:
+ break;
+ case QCOM_SSR_AFTER_POWERUP:
+ break;
+ case QCOM_SSR_BEFORE_SHUTDOWN:
+ if (notify_data->crashed)
+ ath11k_ahb_coredump_msa(ab);
+ break;
+ case QCOM_SSR_AFTER_SHUTDOWN:
+ break;
+ default:
+ ath11k_err(ab, "received unrecognized event %lu\n", action);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int ath11k_ahb_register_ssr_notifier(struct ath11k_base *ab)
+{
+ struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+ void *notifier;
+ int ret;
+
+ ab_ahb->nb.notifier_call = ath11k_ahb_ssr_notifier;
+
+ notifier = qcom_register_ssr_notifier("wpss", &ab_ahb->nb);
+ if (IS_ERR(notifier)) {
+ ret = PTR_ERR(notifier);
+ ath11k_err(ab, "failed to initialize SSR notifier: %d\n", ret);
+ return ret;
+ }
+
+ ab_ahb->notifier = notifier;
+
+ return 0;
+}
+
+static void ath11k_ahb_unregister_ssr_notifier(struct ath11k_base *ab)
+{
+ struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+ int ret;
+
+ ret = qcom_unregister_ssr_notifier(ab_ahb->notifier, &ab_ahb->nb);
+ if (ret)
+ ath11k_err(ab, "error %d unregistering notifier\n", ret);
+}
+
static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
{
struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
@@ -798,6 +868,14 @@ static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
ab_ahb->fw.msa_paddr = r.start;
ab_ahb->fw.msa_size = resource_size(&r);
+ ab_ahb->fw.msa_vaddr = devm_memremap(dev, ab_ahb->fw.msa_paddr,
+ ab_ahb->fw.msa_size,
+ MEMREMAP_WT);
+ if (IS_ERR(ab_ahb->fw.msa_vaddr)) {
+ dev_err(dev, "failed to map memory region: %pa\n",
+ &r.start);
+ return PTR_ERR(ab_ahb->fw.msa_vaddr);
+ }
node = of_parse_phandle(dev->of_node, "memory-region", 1);
if (!node)
@@ -813,7 +891,7 @@ static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
ab_ahb->fw.ce_paddr = r.start;
ab_ahb->fw.ce_size = resource_size(&r);
- return 0;
+ return ath11k_ahb_register_ssr_notifier(ab);
}
static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
@@ -917,6 +995,8 @@ static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)
if (ab_ahb->fw.use_tz)
return 0;
+ ath11k_ahb_unregister_ssr_notifier(ab);
+
iommu = ab_ahb->fw.iommu_domain;
unmapped_size = iommu_unmap(iommu, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
@@ -940,6 +1020,7 @@ static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)
static int ath11k_ahb_probe(struct platform_device *pdev)
{
struct ath11k_base *ab;
+ struct ath11k_ahb *ab_ahb;
const struct of_device_id *of_id;
const struct ath11k_bus_params *bus_params;
const struct ath11k_hif_ops *hif_ops;
@@ -986,6 +1067,8 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
ab->pdev = pdev;
ab->hw_rev = hw_rev;
platform_set_drvdata(pdev, ab);
+ ab_ahb = ath11k_ahb_priv(ab);
+ ab_ahb->ab = ab;
ret = ath11k_ahb_setup_resources(ab);
if (ret)
diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h
index 4c7872d..efb72eb 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.h
+++ b/drivers/net/wireless/ath/ath11k/ahb.h
@@ -1,11 +1,12 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_AHB_H
#define ATH11K_AHB_H
+#include <linux/notifier.h>
#include "core.h"
#define ATH11K_AHB_RECOVERY_TIMEOUT (3 * HZ)
@@ -13,15 +14,20 @@ struct ath11k_base;
struct ath11k_ahb {
struct rproc *tgt_rproc;
+ struct ath11k_base *ab;
struct {
struct device *dev;
struct iommu_domain *iommu_domain;
dma_addr_t msa_paddr;
u32 msa_size;
+ void *msa_vaddr;
dma_addr_t ce_paddr;
u32 ce_size;
bool use_tz;
} fw;
+
+ struct notifier_block nb;
+ void *notifier;
};
static inline struct ath11k_ahb *ath11k_ahb_priv(struct ath11k_base *ab)
diff --git a/drivers/net/wireless/ath/ath11k/coredump.c b/drivers/net/wireless/ath/ath11k/coredump.c
new file mode 100644
index 0000000..247ac26
--- /dev/null
+++ b/drivers/net/wireless/ath/ath11k/coredump.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/devcoredump.h>
+#include <linux/dma-direction.h>
+#include <linux/mm.h>
+#include <linux/uuid.h>
+#include <linux/time.h>
+#include "core.h"
+#include "coredump.h"
+#include "debug.h"
+
+static void ath11k_coredump_update_hdr(struct ath11k_base *ab,
+ struct ath11k_dump_file_data *file_data,
+ size_t header_size)
+{
+ struct timespec64 timestamp;
+
+ strscpy(file_data->df_magic, "ATH11K-FW-DUMP",
+ sizeof(file_data->df_magic));
+ file_data->len = cpu_to_le32(header_size);
+ file_data->version = cpu_to_le32(ATH11K_FW_CRASH_DUMP_VERSION);
+ guid_gen(&file_data->guid);
+ ktime_get_real_ts64(×tamp);
+ file_data->tv_sec = cpu_to_le64(timestamp.tv_sec);
+ file_data->tv_nsec = cpu_to_le64(timestamp.tv_nsec);
+}
+
+void ath11k_coredump_msa(struct ath11k_base *ab,
+ struct ath11k_msa_dump *msa_data)
+{
+ struct ath11k_dump_segment *segment;
+ struct ath11k_dump_file_data *file_data;
+ size_t header_size;
+ int ret;
+ u8 *buf, *dump;
+
+ segment = vzalloc(sizeof(*segment));
+ if (!segment)
+ return;
+
+ header_size = sizeof(struct ath11k_dump_file_data);
+ header_size += sizeof(*segment);
+ header_size = PAGE_ALIGN(header_size);
+ buf = vzalloc(header_size);
+ if (!buf) {
+ vfree(segment);
+ return;
+ }
+
+ file_data = (struct ath11k_dump_file_data *)buf;
+
+ ath11k_coredump_update_hdr(ab, file_data, header_size);
+
+ file_data->num_seg = cpu_to_le32(1);
+ file_data->seg_size = cpu_to_le32(sizeof(*segment));
+
+ /* copy segment details to file */
+ buf += offsetof(struct ath11k_dump_file_data, seg);
+ file_data->seg = (struct ath11k_dump_segment *)buf;
+
+ segment->addr = msa_data->paddr;
+ segment->vaddr = msa_data->vaddr;
+ segment->len = msa_data->size;
+ segment->type = ATH11K_FW_MSA_DUMP_DATA;
+
+ memcpy(file_data->seg, segment, sizeof(*segment));
+
+ dump = vzalloc(header_size + segment->len);
+ if (!dump) {
+ ret = -ENOMEM;
+ ath11k_err(ab, "failed to allocate memory for msa dump %d\n", ret);
+ goto err_alloc_fail;
+ }
+
+ memcpy(dump, (void *)file_data, header_size);
+ memcpy(dump + header_size, segment->vaddr, segment->len);
+
+ dev_coredumpv(ab->dev, dump, header_size + segment->len,
+ GFP_KERNEL);
+err_alloc_fail:
+ vfree(file_data);
+ vfree(segment);
+}
+EXPORT_SYMBOL(ath11k_coredump_msa);
diff --git a/drivers/net/wireless/ath/ath11k/coredump.h b/drivers/net/wireless/ath/ath11k/coredump.h
new file mode 100644
index 0000000..ad7ecf2
--- /dev/null
+++ b/drivers/net/wireless/ath/ath11k/coredump.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear
+ *
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _COREDUMP_H_
+#define _COREDUMP_H_
+
+#define ATH11K_FW_CRASH_DUMP_VERSION 1
+
+enum ath11k_fw_crash_dump_type {
+ ATH11K_FW_MSA_DUMP_DATA,
+ ATH11K_FW_CRASH_DUMP_MAX,
+};
+
+struct ath11k_dump_segment {
+ unsigned long addr;
+ u32 *vaddr;
+ unsigned int len;
+ unsigned int type;
+};
+
+struct ath11k_dump_file_data {
+ /* "ATH11K-FW-DUMP" */
+ char df_magic[16];
+ __le32 len;
+ /* file dump version */
+ __le32 version;
+ /* pci device id */
+ __le32 chip_id;
+ guid_t guid;
+ /* time-of-day stamp */
+ __le64 tv_sec;
+ /* time-of-day stamp, nano-seconds */
+ __le64 tv_nsec;
+ /* room for growth w/out changing binary format */
+ u8 unused[8];
+ /* number of segments */
+ __le32 num_seg;
+ /* ath11k_dump_segment struct size */
+ __le32 seg_size;
+
+ struct ath11k_dump_segment *seg;
+ /* struct ath11k_dump_segment + more */
+
+ u8 data[];
+} __packed;
+
+struct ath11k_coredump_state {
+ struct ath11k_dump_file_data *header;
+ struct ath11k_dump_segment *segments;
+ u32 num_seg;
+};
+
+struct ath11k_msa_dump {
+ u64 paddr;
+ u32 *vaddr;
+ u64 size;
+};
+
+#ifdef CONFIG_DEV_COREDUMP
+void ath11k_coredump_msa(struct ath11k_base *ab,
+ struct ath11k_msa_dump *msa_data);
+#else
+static inline void
+ath11k_coredump_msa(struct ath11k_base *ab,
+ struct ath11k_msa_dump *msa_data)
+{
+}
+#endif /* CONFIG_DEV_COREDUMP */
+#endif /* _COREDUMP_H_ */
--
2.7.4
Currently in the case of WCN6750, only one TCL ring is
enabled for TX, all TX activity happens only on one ring,
this is limiting the TX throughput in 160Mhz case, enabling
mutliple TCL rings on WCN6750 has shown an improvement of
nearly 300 Mbps in the case of TCP TX, therefore add the
support of multi TX ring for WCN6750.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/core.c | 11 ++-
drivers/net/wireless/ath/ath11k/dp.c | 23 ++++---
drivers/net/wireless/ath/ath11k/dp.h | 2 +
drivers/net/wireless/ath/ath11k/dp_tx.c | 14 ++--
drivers/net/wireless/ath/ath11k/hal.c | 4 +-
drivers/net/wireless/ath/ath11k/hal.h | 4 +-
drivers/net/wireless/ath/ath11k/hal_tx.c | 4 +-
drivers/net/wireless/ath/ath11k/hal_tx.h | 2 +
drivers/net/wireless/ath/ath11k/hw.c | 113 +++++++++++++++++++++++++++++--
drivers/net/wireless/ath/ath11k/hw.h | 12 ++++
10 files changed, 160 insertions(+), 29 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 161bddf..fa507a27 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -100,6 +100,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_wmi_diag_event = false,
.non_wow_suspend = false,
.threaded_napi = false,
+ .tcl_wbm_map = ath11k_hw_tcl_wbm_ring_map_ipq8074,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -166,6 +167,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_wmi_diag_event = false,
.non_wow_suspend = false,
.threaded_napi = false,
+ .tcl_wbm_map = ath11k_hw_tcl_wbm_ring_map_ipq8074,
},
{
.name = "qca6390 hw2.0",
@@ -231,6 +233,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_wmi_diag_event = true,
.non_wow_suspend = false,
.threaded_napi = false,
+ .tcl_wbm_map = ath11k_hw_tcl_wbm_ring_map_ipq8074,
},
{
.name = "qcn9074 hw1.0",
@@ -296,6 +299,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_wmi_diag_event = false,
.non_wow_suspend = false,
.threaded_napi = false,
+ .tcl_wbm_map = ath11k_hw_tcl_wbm_ring_map_ipq8074,
},
{
.name = "wcn6855 hw2.0",
@@ -361,6 +365,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_wmi_diag_event = true,
.non_wow_suspend = false,
.threaded_napi = false,
+ .tcl_wbm_map = ath11k_hw_tcl_wbm_ring_map_ipq8074,
},
{
.name = "wcn6855 hw2.1",
@@ -425,6 +430,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_wmi_diag_event = true,
.non_wow_suspend = false,
.threaded_napi = false,
+ .tcl_wbm_map = ath11k_hw_tcl_wbm_ring_map_ipq8074,
},
{
.name = "wcn6750 hw1.0",
@@ -437,7 +443,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,
@@ -481,7 +487,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_regdb = true,
.fix_l1ss = true,
.credit_flow = true,
- .max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,
+ .max_tx_ring = DP_TCL_NUM_RING_MAX,
.hal_params = &ath11k_hw_hal_params_qca6390,
.supports_dynamic_smps_6ghz = false,
.alloc_cacheable_memory = false,
@@ -489,6 +495,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_wmi_diag_event = false,
.non_wow_suspend = true,
.threaded_napi = true,
+ .tcl_wbm_map = ath11k_hw_tcl_wbm_ring_map_wcn6750,
},
};
diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c
index 8b790ce..c44b081 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,8 +396,11 @@ 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.tcl_wbm_map[i].tcl_ring_num;
+ wbm_num = ab->hw_params.tcl_wbm_map[i].wbm_ring_num;
+
ret = ath11k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_data_ring,
- HAL_TCL_DATA, i, 0,
+ HAL_TCL_DATA, tcl_num, 0,
DP_TCL_DATA_RING_SIZE);
if (ret) {
ath11k_warn(ab, "failed to set up tcl_data ring (%d) :%d\n",
@@ -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,8 +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]);
+ for (i = 0; i < ab->hw_params.max_tx_ring; i++) {
+ if (!(BIT(ab->hw_params.tcl_wbm_map[i].wbm_ring_num) &
+ ab->hw_params.ring_mask->tx[grp_id]))
+ continue;
ath11k_dp_tx_completion_handler(ab, i);
}
diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
index 9a30367..946510f 100644
--- a/drivers/net/wireless/ath/ath11k/dp.h
+++ b/drivers/net/wireless/ath/ath11k/dp.h
@@ -220,6 +220,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
diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c
index 91d6244..770bdc5 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.tcl_wbm_map[ti.ring_id].rbm_id;
ring_map |= BIT(ti.ring_id);
diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c
index 9a6340d..92038c5 100644
--- a/drivers/net/wireless/ath/ath11k/hal.c
+++ b/drivers/net/wireless/ath/ath11k/hal.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/dma-mapping.h>
#include "hal_tx.h"
@@ -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,
diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h
index 347d456..f1b6336 100644
--- a/drivers/net/wireless/ath/ath11k/hal.h
+++ b/drivers/net/wireless/ath/ath11k/hal.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_HAL_H
@@ -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,
@@ -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
diff --git a/drivers/net/wireless/ath/ath11k/hal_tx.c b/drivers/net/wireless/ath/ath11k/hal_tx.c
index c8929de..d1b0e36 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 36f4f6f..c5e8836 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/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index c19f9101..4d3c433 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/types.h>
@@ -814,6 +814,30 @@ static u16 ath11k_hw_wcn6855_mpdu_info_get_peerid(u8 *tlv_data)
return peer_id;
}
+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,
+ * 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,
@@ -851,6 +875,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 = {
@@ -890,6 +915,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 = {
@@ -929,6 +955,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 = {
@@ -968,6 +995,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 = {
@@ -1006,6 +1034,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 = {
@@ -1044,11 +1073,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
@@ -1895,6 +1927,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,
@@ -2318,3 +2387,39 @@ const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = {
const struct ath11k_hw_hal_params ath11k_hw_hal_params_qca6390 = {
.rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM,
};
+
+const struct ath11k_hw_tcl_wbm_ring_map ath11k_hw_tcl_wbm_ring_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,
+ },
+};
+
+const struct ath11k_hw_tcl_wbm_ring_map ath11k_hw_tcl_wbm_ring_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,
+ },
+};
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index d33b9b7..f7c6ad5 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -126,6 +126,12 @@ struct ath11k_hw_hal_params {
enum hal_rx_buf_return_buf_manager rx_buf_rbm;
};
+struct ath11k_hw_tcl_wbm_ring_map {
+ u8 tcl_ring_num;
+ u8 wbm_ring_num;
+ u8 rbm_id;
+};
+
struct ath11k_hw_params {
const char *name;
u16 hw_rev;
@@ -195,6 +201,7 @@ struct ath11k_hw_params {
bool non_wow_suspend;
bool cold_boot_fw_restart;
bool threaded_napi;
+ const struct ath11k_hw_tcl_wbm_ring_map *tcl_wbm_map;
};
struct ath11k_hw_ops {
@@ -237,6 +244,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;
@@ -249,10 +257,14 @@ 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_tcl_wbm_ring_map ath11k_hw_tcl_wbm_ring_map_ipq8074[];
+extern const struct ath11k_hw_tcl_wbm_ring_map ath11k_hw_tcl_wbm_ring_map_wcn6750[];
+
static inline
int ath11k_hw_get_mac_from_pdev_id(struct ath11k_hw_params *hw,
int pdev_idx)
--
2.7.4
Increase TCL data ring size from 512 to 2048, this is
needed to meet 160Mhz TX throughput on WCN6750.
As the ring size is increased, there will be a slight
increase in memory used but should not impact the
functioning of any hardware.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/dp.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h
index 409d6cc..9a30367 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
@@ -199,7 +200,7 @@ struct ath11k_pdev_dp {
#define DP_IDLE_SCATTER_BUFS_MAX 16
#define DP_WBM_RELEASE_RING_SIZE 64
-#define DP_TCL_DATA_RING_SIZE 512
+#define DP_TCL_DATA_RING_SIZE 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
--
2.7.4
Currently, WLAN chip is powered once during driver probe and
is kept ON (powered) always even when WLAN is not active;
keeping the chip powered ON all the time will consume extra
power which is not desirable on a battery operated device.
Same is the case with non-WoW suspend, chip will not be put
into low power mode when the system is suspended resulting
in higher battery drain.
As per the recommendation, sending a PDEV suspend WMI command
followed by a QMI MODE OFF command will cease all WLAN activity
and put the device in low power mode. Put the chip in low power
mode when there are no active WLAN interfaces and during non-WoW
suspend to conserve power.
The logic is being applied only for WCN6750 not impacting other
supported chips.
Tested-on: WCN6750 hw1.0 AHB WLAN.MSL.1.0.1-00573-QCAMSLSWPLZ-1
Signed-off-by: Manikanta Pubbisetty <[email protected]>
---
drivers/net/wireless/ath/ath11k/core.c | 141 ++++++++++++++++++++++++------
drivers/net/wireless/ath/ath11k/core.h | 5 +-
drivers/net/wireless/ath/ath11k/hw.h | 3 +-
drivers/net/wireless/ath/ath11k/mac.c | 27 +++++-
drivers/net/wireless/ath/ath11k/thermal.c | 12 +++
5 files changed, 159 insertions(+), 29 deletions(-)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 86373d6..acb8861 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/module.h>
@@ -97,6 +97,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.alloc_cacheable_memory = true,
.supports_rssi_stats = false,
.fw_wmi_diag_event = false,
+ .non_wow_suspend = false,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -160,6 +161,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.alloc_cacheable_memory = true,
.supports_rssi_stats = false,
.fw_wmi_diag_event = false,
+ .non_wow_suspend = false,
},
{
.name = "qca6390 hw2.0",
@@ -222,6 +224,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.alloc_cacheable_memory = false,
.supports_rssi_stats = true,
.fw_wmi_diag_event = true,
+ .non_wow_suspend = false,
},
{
.name = "qcn9074 hw1.0",
@@ -284,6 +287,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.alloc_cacheable_memory = true,
.supports_rssi_stats = false,
.fw_wmi_diag_event = false,
+ .non_wow_suspend = false,
},
{
.name = "wcn6855 hw2.0",
@@ -346,6 +350,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.alloc_cacheable_memory = false,
.supports_rssi_stats = true,
.fw_wmi_diag_event = true,
+ .non_wow_suspend = false,
},
{
.name = "wcn6855 hw2.1",
@@ -407,6 +412,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.alloc_cacheable_memory = false,
.supports_rssi_stats = true,
.fw_wmi_diag_event = true,
+ .non_wow_suspend = false,
},
{
.name = "wcn6750 hw1.0",
@@ -468,6 +474,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.alloc_cacheable_memory = false,
.supports_rssi_stats = true,
.fw_wmi_diag_event = false,
+ .non_wow_suspend = true,
},
};
@@ -931,7 +938,6 @@ static int ath11k_core_soc_create(struct ath11k_base *ab)
static void ath11k_core_soc_destroy(struct ath11k_base *ab)
{
ath11k_debugfs_soc_destroy(ab);
- ath11k_dp_free(ab);
ath11k_reg_free(ab);
ath11k_qmi_deinit_service(ab);
}
@@ -987,11 +993,10 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab)
static void ath11k_core_pdev_destroy(struct ath11k_base *ab)
{
- ath11k_spectral_deinit(ab);
ath11k_thermal_unregister(ab);
ath11k_mac_unregister(ab);
- ath11k_hif_irq_disable(ab);
- ath11k_dp_pdev_free(ab);
+ if (!test_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags))
+ ath11k_core_stop_device(ab);
ath11k_debugfs_pdev_destroy(ab);
}
@@ -1205,6 +1210,9 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
mutex_unlock(&ab->core_lock);
+ if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
+ ath11k_core_stop_device(ab);
+
return 0;
err_core_stop:
@@ -1221,10 +1229,7 @@ int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)
static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
{
- int ret;
-
mutex_lock(&ab->core_lock);
- ath11k_thermal_unregister(ab);
ath11k_hif_irq_disable(ab);
ath11k_dp_pdev_free(ab);
ath11k_spectral_deinit(ab);
@@ -1234,27 +1239,11 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
mutex_unlock(&ab->core_lock);
ath11k_dp_free(ab);
- ath11k_hal_srng_deinit(ab);
+ set_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags);
ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1;
- ret = ath11k_hal_srng_init(ab);
- if (ret)
- return ret;
-
- clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
-
- ret = ath11k_core_qmi_firmware_ready(ab);
- if (ret)
- goto err_hal_srng_deinit;
-
- clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
-
return 0;
-
-err_hal_srng_deinit:
- ath11k_hal_srng_deinit(ab);
- return ret;
}
void ath11k_core_halt(struct ath11k *ar)
@@ -1465,7 +1454,6 @@ void ath11k_core_deinit(struct ath11k_base *ab)
mutex_lock(&ab->core_lock);
ath11k_core_pdev_destroy(ab);
- ath11k_core_stop(ab);
mutex_unlock(&ab->core_lock);
@@ -1527,5 +1515,106 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
}
EXPORT_SYMBOL(ath11k_core_alloc);
+static int ath11k_core_suspend_target(struct ath11k_base *ab, u32 suspend_opt)
+{
+ struct ath11k *ar;
+ struct ath11k_pdev *pdev;
+ unsigned long time_left;
+ int ret;
+ int i;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = &ab->pdevs[i];
+ ar = pdev->ar;
+
+ reinit_completion(&ab->htc_suspend);
+
+ ret = ath11k_wmi_pdev_suspend(ar, suspend_opt, pdev->pdev_id);
+ if (ret) {
+ ath11k_warn(ab, "could not suspend target (%d)\n", ret);
+ return ret;
+ }
+
+ time_left = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ);
+
+ if (!time_left) {
+ ath11k_warn(ab, "suspend timed out - target pause event never came\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+void ath11k_core_stop_device(struct ath11k_base *ab)
+{
+ if (!ab->hw_params.non_wow_suspend &&
+ !test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags))
+ return;
+
+ ath11k_core_suspend_target(ab, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);
+
+ ath11k_hif_irq_disable(ab);
+ ath11k_core_stop(ab);
+ ath11k_spectral_deinit(ab);
+ ath11k_dp_pdev_free(ab);
+ ath11k_dp_free(ab);
+
+ set_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags);
+}
+
+int ath11k_core_start_device(struct ath11k_base *ab)
+{
+ int i;
+ int ret;
+ struct ath11k_pdev *pdev;
+ struct ath11k *ar;
+
+ if (!ab->hw_params.non_wow_suspend &&
+ !test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags))
+ return 0;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = &ab->pdevs[i];
+ ar = pdev->ar;
+ if (!ar)
+ continue;
+
+ if (ar->state == ATH11K_STATE_ON)
+ break;
+ }
+
+ if (i == ab->num_radios ||
+ test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
+ if (!test_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags))
+ return -EAGAIN;
+
+ ath11k_hal_srng_deinit(ab);
+
+ ret = ath11k_hal_srng_init(ab);
+ if (ret) {
+ ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
+ return ret;
+ }
+
+ clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);
+
+ ret = ath11k_core_qmi_firmware_ready(ab);
+ if (ret) {
+ ath11k_err(ab, "failed to init core: %d\n", ret);
+ goto err_hal_srng_deinit;
+ }
+
+ clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
+ clear_bit(ATH11K_FLAG_DEVICE_STOPPED, &ab->dev_flags);
+ }
+
+ return 0;
+
+err_hal_srng_deinit:
+ ath11k_hal_srng_deinit(ab);
+ return ret;
+}
+
MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 76f5aef..758f271 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_CORE_H
@@ -208,6 +208,7 @@ enum ath11k_dev_flags {
ATH11K_FLAG_FIXED_MEM_RGN,
ATH11K_FLAG_DEVICE_INIT_DONE,
ATH11K_FLAG_MULTI_MSI_VECTORS,
+ ATH11K_FLAG_DEVICE_STOPPED,
};
enum ath11k_monitor_flags {
@@ -1025,6 +1026,8 @@ int ath11k_core_check_dt(struct ath11k_base *ath11k);
void ath11k_core_halt(struct ath11k *ar);
int ath11k_core_resume(struct ath11k_base *ab);
int ath11k_core_suspend(struct ath11k_base *ab);
+void ath11k_core_stop_device(struct ath11k_base *ab);
+int ath11k_core_start_device(struct ath11k_base *ab);
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
const char *filename);
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index a220c9a..a38745e 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef ATH11K_HW_H
@@ -192,6 +192,7 @@ struct ath11k_hw_params {
bool alloc_cacheable_memory;
bool supports_rssi_stats;
bool fw_wmi_diag_event;
+ bool non_wow_suspend;
};
struct ath11k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index ac6a192..2402405 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <net/mac80211.h>
@@ -5726,6 +5726,14 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw)
int ret;
ath11k_mac_drain_tx(ar);
+
+ ret = ath11k_core_start_device(ab);
+ if (ret) {
+ if (ret != -EAGAIN)
+ ath11k_err(ab, "failed to start device : %d\n", ret);
+ return ret;
+ }
+
mutex_lock(&ar->conf_mutex);
switch (ar->state) {
@@ -5847,8 +5855,11 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw)
static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
{
struct ath11k *ar = hw->priv;
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_pdev *pdev;
struct htt_ppdu_stats_info *ppdu_stats, *tmp;
int ret;
+ int i;
ath11k_mac_drain_tx(ar);
@@ -5879,6 +5890,20 @@ static void ath11k_mac_op_stop(struct ieee80211_hw *hw)
synchronize_rcu();
atomic_set(&ar->num_pending_mgmt_tx, 0);
+
+ for (i = 0; i < ab->num_radios; i++) {
+ pdev = &ab->pdevs[i];
+ ar = pdev->ar;
+ if (!ar || ar->state == ATH11K_STATE_OFF)
+ continue;
+ break;
+ }
+
+ /* All PDEVs on the SoC are down, time to power down
+ * the device.
+ */
+ if (i == ab->num_radios)
+ ath11k_core_stop_device(ab);
}
static void
diff --git a/drivers/net/wireless/ath/ath11k/thermal.c b/drivers/net/wireless/ath/ath11k/thermal.c
index c96b26f..acb3b45 100644
--- a/drivers/net/wireless/ath/ath11k/thermal.c
+++ b/drivers/net/wireless/ath/ath11k/thermal.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/device.h>
@@ -69,6 +70,11 @@ static ssize_t ath11k_thermal_show_temp(struct device *dev,
mutex_lock(&ar->conf_mutex);
+ if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) {
+ ret = -ESHUTDOWN;
+ goto out;
+ }
+
/* Can't get temperature when the card is off */
if (ar->state != ATH11K_STATE_ON) {
ret = -ENETDOWN;
@@ -131,6 +137,9 @@ int ath11k_thermal_set_throttling(struct ath11k *ar, u32 throttle_state)
lockdep_assert_held(&ar->conf_mutex);
+ if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
+ return 0;
+
if (ar->state != ATH11K_STATE_ON)
return 0;
@@ -162,6 +171,9 @@ int ath11k_thermal_register(struct ath11k_base *sc)
struct ath11k_pdev *pdev;
int i, ret;
+ if (test_bit(ATH11K_FLAG_REGISTERED, &sc->dev_flags))
+ return 0;
+
for (i = 0; i < sc->num_radios; i++) {
pdev = &sc->pdevs[i];
ar = pdev->ar;
--
2.7.4