aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath11k/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath11k/core.c')
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c141
1 files changed, 136 insertions, 5 deletions
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index ebd6886a8c18..b97c38b9a270 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -7,11 +7,13 @@
#include <linux/slab.h>
#include <linux/remoteproc.h>
#include <linux/firmware.h>
+#include <linux/of.h>
#include "core.h"
#include "dp_tx.h"
#include "dp_rx.h"
#include "debug.h"
#include "hif.h"
+#include "wow.h"
unsigned int ath11k_debug_mask;
EXPORT_SYMBOL(ath11k_debug_mask);
@@ -50,7 +52,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq8074,
.svc_to_ce_map_len = 21,
.single_pdev_only = false,
- .needs_band_to_mac = true,
.rxdma1_enable = true,
.num_rxmda_per_pdev = 1,
.rx_mac_buf_ring = false,
@@ -65,6 +66,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_monitor = true,
.supports_shadow_regs = false,
.idle_ps = false,
+ .cold_boot_calib = true,
+ .supports_suspend = false,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -87,7 +90,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq6018,
.svc_to_ce_map_len = 19,
.single_pdev_only = false,
- .needs_band_to_mac = true,
.rxdma1_enable = true,
.num_rxmda_per_pdev = 1,
.rx_mac_buf_ring = false,
@@ -102,6 +104,8 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_monitor = true,
.supports_shadow_regs = false,
.idle_ps = false,
+ .cold_boot_calib = true,
+ .supports_suspend = false,
},
{
.name = "qca6390 hw2.0",
@@ -124,7 +128,6 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,
.svc_to_ce_map_len = 14,
.single_pdev_only = true,
- .needs_band_to_mac = false,
.rxdma1_enable = false,
.num_rxmda_per_pdev = 2,
.rx_mac_buf_ring = true,
@@ -138,17 +141,130 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_monitor = false,
.supports_shadow_regs = true,
.idle_ps = true,
+ .cold_boot_calib = false,
+ .supports_suspend = true,
},
};
+int ath11k_core_suspend(struct ath11k_base *ab)
+{
+ int ret;
+
+ if (!ab->hw_params.supports_suspend)
+ return -EOPNOTSUPP;
+
+ /* TODO: there can frames in queues so for now add delay as a hack.
+ * Need to implement to handle and remove this delay.
+ */
+ msleep(500);
+
+ ret = ath11k_dp_rx_pktlog_stop(ab, true);
+ if (ret) {
+ ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = ath11k_wow_enable(ab);
+ if (ret) {
+ ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath11k_dp_rx_pktlog_stop(ab, false);
+ if (ret) {
+ ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",
+ ret);
+ return ret;
+ }
+
+ ath11k_ce_stop_shadow_timers(ab);
+ ath11k_dp_stop_shadow_timers(ab);
+
+ ath11k_hif_irq_disable(ab);
+ ath11k_hif_ce_irq_disable(ab);
+
+ ret = ath11k_hif_suspend(ab);
+ if (!ret) {
+ ath11k_warn(ab, "failed to suspend hif: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ath11k_core_suspend);
+
+int ath11k_core_resume(struct ath11k_base *ab)
+{
+ int ret;
+
+ if (!ab->hw_params.supports_suspend)
+ return -EOPNOTSUPP;
+
+ ret = ath11k_hif_resume(ab);
+ if (ret) {
+ ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret);
+ return ret;
+ }
+
+ ath11k_hif_ce_irq_enable(ab);
+ ath11k_hif_irq_enable(ab);
+
+ ret = ath11k_dp_rx_pktlog_start(ab);
+ if (ret) {
+ ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = ath11k_wow_wakeup(ab);
+ if (ret) {
+ ath11k_warn(ab, "failed to wakeup wow during resume: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ath11k_core_resume);
+
+int ath11k_core_check_dt(struct ath11k_base *ab)
+{
+ size_t max_len = sizeof(ab->qmi.target.bdf_ext);
+ const char *variant = NULL;
+ struct device_node *node;
+
+ node = ab->dev->of_node;
+ if (!node)
+ return -ENOENT;
+
+ of_property_read_string(node, "qcom,ath11k-calibration-variant",
+ &variant);
+ if (!variant)
+ return -ENODATA;
+
+ if (strscpy(ab->qmi.target.bdf_ext, variant, max_len) < 0)
+ ath11k_dbg(ab, ATH11K_DBG_BOOT,
+ "bdf variant string is longer than the buffer can accommodate (variant: %s)\n",
+ variant);
+
+ return 0;
+}
+
static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name,
size_t name_len)
{
+ /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
+ char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 };
+
+ if (ab->qmi.target.bdf_ext[0] != '\0')
+ scnprintf(variant, sizeof(variant), ",variant=%s",
+ ab->qmi.target.bdf_ext);
+
scnprintf(name, name_len,
- "bus=%s,qmi-chip-id=%d,qmi-board-id=%d",
+ "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",
ath11k_bus_str(ab->hif.bus),
ab->qmi.target.chip_id,
- ab->qmi.target.board_id);
+ ab->qmi.target.board_id, variant);
ath11k_dbg(ab, ATH11K_DBG_BOOT, "boot using board name '%s'\n", name);
@@ -612,6 +728,15 @@ static int ath11k_core_start(struct ath11k_base *ab,
goto err_reo_cleanup;
}
+ /* put hardware to DBS mode */
+ if (ab->hw_params.single_pdev_only) {
+ ret = ath11k_wmi_set_hw_mode(ab, WMI_HOST_HW_MODE_DBS);
+ if (ret) {
+ ath11k_err(ab, "failed to send dbs mode: %d\n", ret);
+ goto err_hif_stop;
+ }
+ }
+
ret = ath11k_dp_tx_htt_h2t_ver_req_msg(ab);
if (ret) {
ath11k_err(ab, "failed to send htt version request message: %d\n",
@@ -774,8 +899,10 @@ static void ath11k_core_restart(struct work_struct *work)
complete(&ar->scan.started);
complete(&ar->scan.completed);
complete(&ar->peer_assoc_done);
+ complete(&ar->peer_delete_done);
complete(&ar->install_key_done);
complete(&ar->vdev_setup_done);
+ complete(&ar->vdev_delete_done);
complete(&ar->bss_survey_done);
complete(&ar->thermal.wmi_sync);
@@ -923,8 +1050,12 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,
INIT_LIST_HEAD(&ab->peers);
init_waitqueue_head(&ab->peer_mapping_wq);
init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
+ init_waitqueue_head(&ab->qmi.cold_boot_waitq);
INIT_WORK(&ab->restart_work, ath11k_core_restart);
timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);
+ init_completion(&ab->htc_suspend);
+ init_completion(&ab->wow.wakeup_completed);
+
ab->dev = dev;
ab->bus_params = *bus_params;
ab->hif.bus = bus;