The branch main has been updated by bz:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=28348caeee6ee98251b0aaa026e8d52b5032e92c

commit 28348caeee6ee98251b0aaa026e8d52b5032e92c
Author:     Bjoern A. Zeeb <[email protected]>
AuthorDate: 2023-05-20 00:36:03 +0000
Commit:     Bjoern A. Zeeb <[email protected]>
CommitDate: 2023-08-21 01:32:46 +0000

    ath11k: update driver from upstream
    
    This is a set of updates of the ath11k driver based on wireless-testing
    (wt-2023-05-11) 711dca0ca3d77414f8f346e564e9c8640147f40d (after v6.4-rc1),
    (wt-2023-06-09) 7bd20e011626ccc3ad53e57873452b1716fcfaaa (after v6.4-rc5),
    (wt-2023-07-24) 62e409149b62a285e89018e49b2e115757fb9022 (after v6.5-rc3),
    (wt-2023-08-06) 2a220a15be657a24868368892e3e2caba2115283 (after v6.5-rc4).
    
    MFC after:      20 days
---
 sys/contrib/dev/athk/ath11k/Makefile            |    3 +-
 sys/contrib/dev/athk/ath11k/ahb.c               |  650 +++++-
 sys/contrib/dev/athk/ath11k/ahb.h               |   25 +
 sys/contrib/dev/athk/ath11k/ce.c                |   12 +-
 sys/contrib/dev/athk/ath11k/ce.h                |   18 +-
 sys/contrib/dev/athk/ath11k/core.c              |  963 ++++++--
 sys/contrib/dev/athk/ath11k/core.h              |  250 +-
 sys/contrib/dev/athk/ath11k/dbring.c            |   31 +-
 sys/contrib/dev/athk/ath11k/debug.c             |    4 +-
 sys/contrib/dev/athk/ath11k/debug.h             |   53 +-
 sys/contrib/dev/athk/ath11k/debugfs.c           |  979 +++++++-
 sys/contrib/dev/athk/ath11k/debugfs.h           |  185 +-
 sys/contrib/dev/athk/ath11k/debugfs_htt_stats.c |  202 +-
 sys/contrib/dev/athk/ath11k/debugfs_htt_stats.h |  159 +-
 sys/contrib/dev/athk/ath11k/debugfs_sta.c       |  107 +
 sys/contrib/dev/athk/ath11k/dp.c                |   32 +-
 sys/contrib/dev/athk/ath11k/dp.h                |   41 +-
 sys/contrib/dev/athk/ath11k/dp_rx.c             |  349 ++-
 sys/contrib/dev/athk/ath11k/dp_tx.c             |  111 +-
 sys/contrib/dev/athk/ath11k/dp_tx.h             |    1 +
 sys/contrib/dev/athk/ath11k/hal.c               |   48 +-
 sys/contrib/dev/athk/ath11k/hal.h               |   45 +-
 sys/contrib/dev/athk/ath11k/hal_desc.h          |    9 +-
 sys/contrib/dev/athk/ath11k/hal_rx.c            |  507 +++-
 sys/contrib/dev/athk/ath11k/hal_rx.h            |  155 +-
 sys/contrib/dev/athk/ath11k/hal_tx.c            |    4 +-
 sys/contrib/dev/athk/ath11k/hal_tx.h            |    2 +
 sys/contrib/dev/athk/ath11k/hif.h               |   11 +
 sys/contrib/dev/athk/ath11k/htc.c               |   50 +-
 sys/contrib/dev/athk/ath11k/hw.c                |  737 +++++-
 sys/contrib/dev/athk/ath11k/hw.h                |   93 +-
 sys/contrib/dev/athk/ath11k/mac.c               | 2159 +++++++++++++----
 sys/contrib/dev/athk/ath11k/mac.h               |   11 +-
 sys/contrib/dev/athk/ath11k/mhi.c               |  310 +--
 sys/contrib/dev/athk/ath11k/mhi.h               |   17 +-
 sys/contrib/dev/athk/ath11k/pci.c               | 1128 +++------
 sys/contrib/dev/athk/ath11k/pci.h               |   28 +-
 sys/contrib/dev/athk/ath11k/pcic.c              |  827 +++++++
 sys/contrib/dev/athk/ath11k/pcic.h              |   54 +
 sys/contrib/dev/athk/ath11k/peer.c              |  404 +++-
 sys/contrib/dev/athk/ath11k/peer.h              |   11 +-
 sys/contrib/dev/athk/ath11k/qmi.c               |  545 ++++-
 sys/contrib/dev/athk/ath11k/qmi.h               |   44 +-
 sys/contrib/dev/athk/ath11k/reg.c               |  137 +-
 sys/contrib/dev/athk/ath11k/reg.h               |    2 +-
 sys/contrib/dev/athk/ath11k/rx_desc.h           |    8 +-
 sys/contrib/dev/athk/ath11k/spectral.c          |   41 +-
 sys/contrib/dev/athk/ath11k/spectral.h          |    1 +
 sys/contrib/dev/athk/ath11k/testmode.c          |  387 ++-
 sys/contrib/dev/athk/ath11k/testmode.h          |    6 +-
 sys/contrib/dev/athk/ath11k/testmode_i.h        |   18 +-
 sys/contrib/dev/athk/ath11k/thermal.c           |    2 +-
 sys/contrib/dev/athk/ath11k/thermal.h           |    2 +-
 sys/contrib/dev/athk/ath11k/trace.h             |   35 +-
 sys/contrib/dev/athk/ath11k/wmi.c               | 2854 +++++++++++++++++++----
 sys/contrib/dev/athk/ath11k/wmi.h               | 1114 ++++++++-
 sys/contrib/dev/athk/ath11k/wow.c               |  805 +++++++
 sys/contrib/dev/athk/ath11k/wow.h               |   45 +
 sys/modules/ath11k/Makefile                     |   10 +-
 59 files changed, 13609 insertions(+), 3232 deletions(-)

diff --git a/sys/contrib/dev/athk/ath11k/Makefile 
b/sys/contrib/dev/athk/ath11k/Makefile
index c1fce4159f1f..cc47e0114595 100644
--- a/sys/contrib/dev/athk/ath11k/Makefile
+++ b/sys/contrib/dev/athk/ath11k/Makefile
@@ -17,13 +17,14 @@ ath11k-y += core.o \
            peer.o \
            dbring.o \
            hw.o \
-           wow.o
+           pcic.o
 
 ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
 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_PM) += wow.o
 
 obj-$(CONFIG_ATH11K_AHB) += ath11k_ahb.o
 ath11k_ahb-y += ahb.o
diff --git a/sys/contrib/dev/athk/ath11k/ahb.c 
b/sys/contrib/dev/athk/ath11k/ahb.c
index f93686d0d25d..ceb3ccbb1827 100644
--- a/sys/contrib/dev/athk/ath11k/ahb.c
+++ b/sys/contrib/dev/athk/ath11k/ahb.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-2023 Qualcomm Innovation Center, Inc. All rights 
reserved.
  */
 
 #include <linux/module.h>
@@ -8,10 +9,16 @@
 #include <linux/of_device.h>
 #include <linux/of.h>
 #include <linux/dma-mapping.h>
+#include <linux/of_address.h>
+#include <linux/iommu.h>
 #include "ahb.h"
 #include "debug.h"
 #include "hif.h"
+#include "qmi.h"
 #include <linux/remoteproc.h>
+#include "pcic.h"
+#include <linux/soc/qcom/smem.h>
+#include <linux/soc/qcom/smem_state.h>
 
 static const struct of_device_id ath11k_ahb_of_match[] = {
        /* TODO: Should we change the compatible string to something similar
@@ -23,18 +30,17 @@ static const struct of_device_id ath11k_ahb_of_match[] = {
        { .compatible = "qcom,ipq6018-wifi",
          .data = (void *)ATH11K_HW_IPQ6018_HW10,
        },
+       { .compatible = "qcom,wcn6750-wifi",
+         .data = (void *)ATH11K_HW_WCN6750_HW10,
+       },
+       { .compatible = "qcom,ipq5018-wifi",
+         .data = (void *)ATH11K_HW_IPQ5018_HW10,
+       },
        { }
 };
 
 MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
 
-static const struct ath11k_bus_params ath11k_ahb_bus_params = {
-       .mhi_support = false,
-       .m3_fw_support = false,
-       .fixed_bdf_addr = true,
-       .fixed_mem_region = true,
-};
-
 #define ATH11K_IRQ_CE0_OFFSET 4
 
 static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
@@ -134,6 +140,61 @@ enum ext_irq_num {
        tcl2host_status_ring,
 };
 
+static int
+ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base *ab, unsigned int vector)
+{
+       return ab->pci.msi.irqs[vector];
+}
+
+static inline u32
+ath11k_ahb_get_window_start_wcn6750(struct ath11k_base *ab, u32 offset)
+{
+       u32 window_start = 0;
+
+       /* If offset lies within DP register range, use 1st window */
+       if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK)
+               window_start = ATH11K_PCI_WINDOW_START;
+       /* If offset lies within CE register range, use 2nd window */
+       else if ((offset ^ HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab)) <
+                ATH11K_PCI_WINDOW_RANGE_MASK)
+               window_start = 2 * ATH11K_PCI_WINDOW_START;
+
+       return window_start;
+}
+
+static void
+ath11k_ahb_window_write32_wcn6750(struct ath11k_base *ab, u32 offset, u32 
value)
+{
+       u32 window_start;
+
+       /* WCN6750 uses static window based register access*/
+       window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
+
+       iowrite32(value, ab->mem + window_start +
+                 (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
+}
+
+static u32 ath11k_ahb_window_read32_wcn6750(struct ath11k_base *ab, u32 offset)
+{
+       u32 window_start;
+       u32 val;
+
+       /* WCN6750 uses static window based register access */
+       window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);
+
+       val = ioread32(ab->mem + window_start +
+                      (offset & ATH11K_PCI_WINDOW_RANGE_MASK));
+       return val;
+}
+
+static const struct ath11k_pci_ops ath11k_ahb_pci_ops_wcn6750 = {
+       .wakeup = NULL,
+       .release = NULL,
+       .get_msi_irq = ath11k_ahb_get_msi_irq_wcn6750,
+       .window_write32 = ath11k_ahb_window_write32_wcn6750,
+       .window_read32 = ath11k_ahb_window_read32_wcn6750,
+};
+
 static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)
 {
        return ioread32(ab->mem + offset);
@@ -210,30 +271,42 @@ static void ath11k_ahb_clearbit32(struct ath11k_base *ab, 
u8 bit, u32 offset)
 static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)
 {
        const struct ce_attr *ce_attr;
+       const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
+       u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
+
+       ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
+       ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
+       ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
 
        ce_attr = &ab->hw_params.host_ce_config[ce_id];
        if (ce_attr->src_nentries)
-               ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
+               ath11k_ahb_setbit32(ab, ce_id, ie1_reg_addr);
 
        if (ce_attr->dest_nentries) {
-               ath11k_ahb_setbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
+               ath11k_ahb_setbit32(ab, ce_id, ie2_reg_addr);
                ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
-                                   CE_HOST_IE_3_ADDRESS);
+                                   ie3_reg_addr);
        }
 }
 
 static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)
 {
        const struct ce_attr *ce_attr;
+       const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;
+       u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;
+
+       ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);
+       ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);
+       ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);
 
        ce_attr = &ab->hw_params.host_ce_config[ce_id];
        if (ce_attr->src_nentries)
-               ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_ADDRESS);
+               ath11k_ahb_clearbit32(ab, ce_id, ie1_reg_addr);
 
        if (ce_attr->dest_nentries) {
-               ath11k_ahb_clearbit32(ab, ce_id, CE_HOST_IE_2_ADDRESS);
+               ath11k_ahb_clearbit32(ab, ce_id, ie2_reg_addr);
                ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,
-                                     CE_HOST_IE_3_ADDRESS);
+                                     ie3_reg_addr);
        }
 }
 
@@ -346,31 +419,6 @@ static void ath11k_ahb_power_down(struct ath11k_base *ab)
        rproc_shutdown(ab_ahb->tgt_rproc);
 }
 
-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)
-               return 0;
-
-       ath11k_dbg(ab, ATH11K_DBG_AHB, "wait for cold boot done\n");
-       timeout = wait_event_timeout(ab->qmi.cold_boot_waitq,
-                                    (ab->qmi.cal_done  == 1),
-                                    ATH11K_COLD_BOOT_FW_RESET_DELAY);
-       if (timeout <= 0) {
-               ath11k_cold_boot_cal = 0;
-               ath11k_warn(ab, "Coldboot Calibration failed timed out\n");
-       }
-
-       /* reset the firmware */
-       ath11k_ahb_power_down(ab);
-       ath11k_ahb_power_up(ab);
-
-       ath11k_dbg(ab, ATH11K_DBG_AHB, "exited from cold boot mode\n");
-       return 0;
-}
-
 static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
 {
        struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
@@ -391,6 +439,8 @@ static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)
 
                for (j = 0; j < irq_grp->num_irq; j++)
                        free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);
+
+               netif_napi_del(&irq_grp->napi);
        }
 }
 
@@ -399,6 +449,9 @@ static void ath11k_ahb_free_irq(struct ath11k_base *ab)
        int irq_idx;
        int i;
 
+       if (ab->hw_params.hybrid_bus_type)
+               return ath11k_pcic_free_irq(ab);
+
        for (i = 0; i < ab->hw_params.ce_count; i++) {
                if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
                        continue;
@@ -466,7 +519,7 @@ static irqreturn_t ath11k_ahb_ext_interrupt_handler(int 
irq, void *arg)
        return IRQ_HANDLED;
 }
 
-static int ath11k_ahb_ext_irq_config(struct ath11k_base *ab)
+static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)
 {
        struct ath11k_hw_params *hw = &ab->hw_params;
        int i, j;
@@ -553,6 +606,9 @@ static int ath11k_ahb_config_irq(struct ath11k_base *ab)
        int irq, irq_idx, i;
        int ret;
 
+       if (ab->hw_params.hybrid_bus_type)
+               return ath11k_pcic_config_irq(ab);
+
        /* Configure CE irqs */
        for (i = 0; i < ab->hw_params.ce_count; i++) {
                struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
@@ -574,7 +630,7 @@ static int ath11k_ahb_config_irq(struct ath11k_base *ab)
        }
 
        /* Configure external interrupts */
-       ret = ath11k_ahb_ext_irq_config(ab);
+       ret = ath11k_ahb_config_ext_irq(ab);
 
        return ret;
 }
@@ -622,11 +678,90 @@ static int ath11k_ahb_map_service_to_pipe(struct 
ath11k_base *ab, u16 service_id
        return 0;
 }
 
-static const struct ath11k_hif_ops ath11k_ahb_hif_ops = {
+static int ath11k_ahb_hif_suspend(struct ath11k_base *ab)
+{
+       struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+       u32 wake_irq;
+       u32 value = 0;
+       int ret;
+
+       if (!device_may_wakeup(ab->dev))
+               return -EPERM;
+
+       wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + 
ATH11K_PCI_CE_WAKE_IRQ];
+
+       ret = enable_irq_wake(wake_irq);
+       if (ret) {
+               ath11k_err(ab, "failed to enable wakeup irq :%d\n", ret);
+               return ret;
+       }
+
+       value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
+                               ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
+       value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_ENTER,
+                                ATH11K_AHB_SMP2P_SMEM_MSG);
+
+       ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
+                                         ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, 
value);
+       if (ret) {
+               ath11k_err(ab, "failed to send smp2p power save enter cmd 
:%d\n", ret);
+               return ret;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_AHB, "device suspended\n");
+
+       return ret;
+}
+
+static int ath11k_ahb_hif_resume(struct ath11k_base *ab)
+{
+       struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+       u32 wake_irq;
+       u32 value = 0;
+       int ret;
+
+       if (!device_may_wakeup(ab->dev))
+               return -EPERM;
+
+       wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + 
ATH11K_PCI_CE_WAKE_IRQ];
+
+       ret = disable_irq_wake(wake_irq);
+       if (ret) {
+               ath11k_err(ab, "failed to disable wakeup irq: %d\n", ret);
+               return ret;
+       }
+
+       reinit_completion(&ab->wow.wakeup_completed);
+
+       value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,
+                               ATH11K_AHB_SMP2P_SMEM_SEQ_NO);
+       value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_EXIT,
+                                ATH11K_AHB_SMP2P_SMEM_MSG);
+
+       ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,
+                                         ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, 
value);
+       if (ret) {
+               ath11k_err(ab, "failed to send smp2p power save enter cmd 
:%d\n", ret);
+               return ret;
+       }
+
+       ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);
+       if (ret == 0) {
+               ath11k_warn(ab, "timed out while waiting for wow wakeup 
completion\n");
+               return -ETIMEDOUT;
+       }
+
+       ath11k_dbg(ab, ATH11K_DBG_AHB, "device resumed\n");
+
+       return 0;
+}
+
+static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
        .start = ath11k_ahb_start,
        .stop = ath11k_ahb_stop,
        .read32 = ath11k_ahb_read32,
        .write32 = ath11k_ahb_write32,
+       .read = NULL,
        .irq_enable = ath11k_ahb_ext_irq_enable,
        .irq_disable = ath11k_ahb_ext_irq_disable,
        .map_service_to_pipe = ath11k_ahb_map_service_to_pipe,
@@ -634,6 +769,25 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops = {
        .power_up = ath11k_ahb_power_up,
 };
 
+static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
+       .start = ath11k_pcic_start,
+       .stop = ath11k_pcic_stop,
+       .read32 = ath11k_pcic_read32,
+       .write32 = ath11k_pcic_write32,
+       .read = NULL,
+       .irq_enable = ath11k_pcic_ext_irq_enable,
+       .irq_disable = ath11k_pcic_ext_irq_disable,
+       .get_msi_address =  ath11k_pcic_get_msi_address,
+       .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,
+       .map_service_to_pipe = ath11k_pcic_map_service_to_pipe,
+       .power_down = ath11k_ahb_power_down,
+       .power_up = ath11k_ahb_power_up,
+       .suspend = ath11k_ahb_hif_suspend,
+       .resume = ath11k_ahb_hif_resume,
+       .ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq,
+       .ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
+};
+
 static int ath11k_core_get_rproc(struct ath11k_base *ab)
 {
        struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
@@ -656,12 +810,284 @@ static int ath11k_core_get_rproc(struct ath11k_base *ab)
        return 0;
 }
 
+static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
+{
+       struct platform_device *pdev = ab->pdev;
+       phys_addr_t msi_addr_pa;
+       dma_addr_t msi_addr_iova;
+       struct resource *res;
+       int int_prop;
+       int ret;
+       int i;
+
+       ret = ath11k_pcic_init_msi_config(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to init msi config: %d\n", ret);
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ath11k_err(ab, "failed to fetch msi_addr\n");
+               return -ENOENT;
+       }
+
+       msi_addr_pa = res->start;
+       msi_addr_iova = dma_map_resource(ab->dev, msi_addr_pa, PAGE_SIZE,
+                                        DMA_FROM_DEVICE, 0);
+       if (dma_mapping_error(ab->dev, msi_addr_iova))
+               return -ENOMEM;
+
+       ab->pci.msi.addr_lo = lower_32_bits(msi_addr_iova);
+       ab->pci.msi.addr_hi = upper_32_bits(msi_addr_iova);
+
+       ret = of_property_read_u32_index(ab->dev->of_node, "interrupts", 1, 
&int_prop);
+       if (ret)
+               return ret;
+
+       ab->pci.msi.ep_base_data = int_prop + 32;
+
+       for (i = 0; i < ab->pci.msi.config->total_vectors; i++) {
+               ret = platform_get_irq(pdev, i);
+               if (ret < 0)
+                       return ret;
+
+               ab->pci.msi.irqs[i] = ret;
+       }
+
+       set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
+
+       return 0;
+}
+
+static int ath11k_ahb_setup_smp2p_handle(struct ath11k_base *ab)
+{
+       struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+
+       if (!ab->hw_params.smp2p_wow_exit)
+               return 0;
+
+       ab_ahb->smp2p_info.smem_state = qcom_smem_state_get(ab->dev, 
"wlan-smp2p-out",
+                                                           
&ab_ahb->smp2p_info.smem_bit);
+       if (IS_ERR(ab_ahb->smp2p_info.smem_state)) {
+               ath11k_err(ab, "failed to fetch smem state: %ld\n",
+                          PTR_ERR(ab_ahb->smp2p_info.smem_state));
+               return PTR_ERR(ab_ahb->smp2p_info.smem_state);
+       }
+
+       return 0;
+}
+
+static void ath11k_ahb_release_smp2p_handle(struct ath11k_base *ab)
+{
+       struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+
+       if (!ab->hw_params.smp2p_wow_exit)
+               return;
+
+       qcom_smem_state_put(ab_ahb->smp2p_info.smem_state);
+}
+
+static int ath11k_ahb_setup_resources(struct ath11k_base *ab)
+{
+       struct platform_device *pdev = ab->pdev;
+       struct resource *mem_res;
+       void __iomem *mem;
+
+       if (ab->hw_params.hybrid_bus_type)
+               return ath11k_ahb_setup_msi_resources(ab);
+
+       mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
+       if (IS_ERR(mem)) {
+               dev_err(&pdev->dev, "ioremap error\n");
+               return PTR_ERR(mem);
+       }
+
+       ab->mem = mem;
+       ab->mem_len = resource_size(mem_res);
+
+       return 0;
+}
+
+static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)
+{
+       struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+       struct device *dev = ab->dev;
+       struct device_node *node;
+       struct resource r;
+       int ret;
+
+       node = of_parse_phandle(dev->of_node, "memory-region", 0);
+       if (!node)
+               return -ENOENT;
+
+       ret = of_address_to_resource(node, 0, &r);
+       of_node_put(node);
+       if (ret) {
+               dev_err(dev, "failed to resolve msa fixed region\n");
+               return ret;
+       }
+
+       ab_ahb->fw.msa_paddr = r.start;
+       ab_ahb->fw.msa_size = resource_size(&r);
+
+       node = of_parse_phandle(dev->of_node, "memory-region", 1);
+       if (!node)
+               return -ENOENT;
+
+       ret = of_address_to_resource(node, 0, &r);
+       of_node_put(node);
+       if (ret) {
+               dev_err(dev, "failed to resolve ce fixed region\n");
+               return ret;
+       }
+
+       ab_ahb->fw.ce_paddr = r.start;
+       ab_ahb->fw.ce_size = resource_size(&r);
+
+       return 0;
+}
+
+static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)
+{
+       struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+       struct device *host_dev = ab->dev;
+       struct platform_device_info info = {0};
+       struct iommu_domain *iommu_dom;
+       struct platform_device *pdev;
+       struct device_node *node;
+       int ret;
+
+       /* Chipsets not requiring MSA need not initialize
+        * MSA resources, return success in such cases.
+        */
+       if (!ab->hw_params.fixed_fw_mem)
+               return 0;
+
+       ret = ath11k_ahb_setup_msa_resources(ab);
+       if (ret) {
+               ath11k_err(ab, "failed to setup msa resources\n");
+               return ret;
+       }
+
+       node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");
+       if (!node) {
+               ab_ahb->fw.use_tz = true;
+               return 0;
+       }
+
+       info.fwnode = &node->fwnode;
+       info.parent = host_dev;
+       info.name = node->name;
+       info.dma_mask = DMA_BIT_MASK(32);
+
+       pdev = platform_device_register_full(&info);
+       if (IS_ERR(pdev)) {
+               of_node_put(node);
+               return PTR_ERR(pdev);
+       }
+
+       ret = of_dma_configure(&pdev->dev, node, true);
+       if (ret) {
+               ath11k_err(ab, "dma configure fail: %d\n", ret);
+               goto err_unregister;
+       }
+
+       ab_ahb->fw.dev = &pdev->dev;
+
+       iommu_dom = iommu_domain_alloc(&platform_bus_type);
+       if (!iommu_dom) {
+               ath11k_err(ab, "failed to allocate iommu domain\n");
+               ret = -ENOMEM;
+               goto err_unregister;
+       }
+
+       ret = iommu_attach_device(iommu_dom, ab_ahb->fw.dev);
+       if (ret) {
+               ath11k_err(ab, "could not attach device: %d\n", ret);
+               goto err_iommu_free;
+       }
+
+       ret = iommu_map(iommu_dom, ab_ahb->fw.msa_paddr,
+                       ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size,
+                       IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
+       if (ret) {
+               ath11k_err(ab, "failed to map firmware region: %d\n", ret);
+               goto err_iommu_detach;
+       }
+
+       ret = iommu_map(iommu_dom, ab_ahb->fw.ce_paddr,
+                       ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size,
+                       IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);
+       if (ret) {
+               ath11k_err(ab, "failed to map firmware CE region: %d\n", ret);
+               goto err_iommu_unmap;
+       }
+
+       ab_ahb->fw.use_tz = false;
+       ab_ahb->fw.iommu_domain = iommu_dom;
+       of_node_put(node);
+
+       return 0;
+
+err_iommu_unmap:
+       iommu_unmap(iommu_dom, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);
+
+err_iommu_detach:
+       iommu_detach_device(iommu_dom, ab_ahb->fw.dev);
+
+err_iommu_free:
+       iommu_domain_free(iommu_dom);
+
+err_unregister:
+       platform_device_unregister(pdev);
+       of_node_put(node);
+
+       return ret;
+}
+
+static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)
+{
+       struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+       struct iommu_domain *iommu;
+       size_t unmapped_size;
+
+       /* Chipsets not requiring MSA would have not initialized
+        * MSA resources, return success in such cases.
+        */
+       if (!ab->hw_params.fixed_fw_mem)
+               return 0;
+
+       if (ab_ahb->fw.use_tz)
+               return 0;
+
+       iommu = ab_ahb->fw.iommu_domain;
+
+       unmapped_size = iommu_unmap(iommu, ab_ahb->fw.msa_paddr, 
ab_ahb->fw.msa_size);
+       if (unmapped_size != ab_ahb->fw.msa_size)
+               ath11k_err(ab, "failed to unmap firmware: %zu\n",
+                          unmapped_size);
+
+       unmapped_size = iommu_unmap(iommu, ab_ahb->fw.ce_paddr, 
ab_ahb->fw.ce_size);
+       if (unmapped_size != ab_ahb->fw.ce_size)
+               ath11k_err(ab, "failed to unmap firmware CE memory: %zu\n",
+                          unmapped_size);
+
+       iommu_detach_device(iommu, ab_ahb->fw.dev);
+       iommu_domain_free(iommu);
+
+       platform_device_unregister(to_platform_device(ab_ahb->fw.dev));
+
+       return 0;
+}
+
 static int ath11k_ahb_probe(struct platform_device *pdev)
 {
        struct ath11k_base *ab;
        const struct of_device_id *of_id;
-       struct resource *mem_res;
-       void __iomem *mem;
+       const struct ath11k_hif_ops *hif_ops;
+       const struct ath11k_pci_ops *pci_ops;
+       enum ath11k_hw_rev hw_rev;
        int ret;
 
        of_id = of_match_device(ath11k_ahb_of_match, &pdev->dev);
@@ -670,10 +1096,22 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
-       if (IS_ERR(mem)) {
-               dev_err(&pdev->dev, "ioremap error\n");
-               return PTR_ERR(mem);
+       hw_rev = (enum ath11k_hw_rev)of_id->data;
+
+       switch (hw_rev) {
+       case ATH11K_HW_IPQ8074:
+       case ATH11K_HW_IPQ6018_HW10:
+       case ATH11K_HW_IPQ5018_HW10:
+               hif_ops = &ath11k_ahb_hif_ops_ipq8074;
+               pci_ops = NULL;
+               break;
+       case ATH11K_HW_WCN6750_HW10:
+               hif_ops = &ath11k_ahb_hif_ops_wcn6750;
+               pci_ops = &ath11k_ahb_pci_ops_wcn6750;
+               break;
+       default:
+               dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev);
+               return -EOPNOTSUPP;
        }
 
        ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
@@ -683,28 +1121,60 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
        }
 
        ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),
-                              ATH11K_BUS_AHB,
-                              &ath11k_ahb_bus_params);
+                              ATH11K_BUS_AHB);
        if (!ab) {
                dev_err(&pdev->dev, "failed to allocate ath11k base\n");
                return -ENOMEM;
        }
 
-       ab->hif.ops = &ath11k_ahb_hif_ops;
+       ab->hif.ops = hif_ops;
        ab->pdev = pdev;
-       ab->hw_rev = (enum ath11k_hw_rev)of_id->data;
-       ab->mem = mem;
-       ab->mem_len = resource_size(mem_res);
+       ab->hw_rev = hw_rev;
+       ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
        platform_set_drvdata(pdev, ab);
 
+       ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
+       if (ret) {
+               ath11k_err(ab, "failed to register PCI ops: %d\n", ret);
+               goto err_core_free;
+       }
+
        ret = ath11k_core_pre_init(ab);
        if (ret)
                goto err_core_free;
 
-       ret = ath11k_hal_srng_init(ab);
+       ret = ath11k_ahb_setup_resources(ab);
        if (ret)
                goto err_core_free;
 
+       ab->mem_ce = ab->mem;
+
+       if (ab->hw_params.ce_remap) {
+               const struct ce_remap *ce_remap = ab->hw_params.ce_remap;
+               /* ce register space is moved out of wcss unlike ipq8074 or 
ipq6018
+                * and the space is not contiguous, hence remapping the CE 
registers
+                * to a new space for accessing them.
+                */
+               ab->mem_ce = ioremap(ce_remap->base, ce_remap->size);
+               if (!ab->mem_ce) {
+                       dev_err(&pdev->dev, "ce ioremap error\n");
+                       ret = -ENOMEM;
+                       goto err_core_free;
+               }
+       }
+
+       ret = ath11k_ahb_fw_resources_init(ab);
+       if (ret)
+               goto err_core_free;
+
+       ret = ath11k_ahb_setup_smp2p_handle(ab);
+       if (ret)
+               goto err_fw_deinit;
+
+       ret = ath11k_hal_srng_init(ab);
+       if (ret)
+               goto err_release_smp2p_handle;
+
        ret = ath11k_ce_alloc_pipes(ab);
        if (ret) {
                ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);
@@ -731,7 +1201,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
                goto err_ce_free;
        }
 
-       ath11k_ahb_fwreset_from_cold_boot(ab);
+       ath11k_qmi_fwreset_from_cold_boot(ab);
 
        return 0;
 
@@ -741,6 +1211,12 @@ err_ce_free:
 err_hal_srng_deinit:
        ath11k_hal_srng_deinit(ab);
 
+err_release_smp2p_handle:
+       ath11k_ahb_release_smp2p_handle(ab);
+
+err_fw_deinit:
+       ath11k_ahb_fw_resource_deinit(ab);
+
 err_core_free:
        ath11k_core_free(ab);
        platform_set_drvdata(pdev, NULL);
@@ -748,20 +1224,10 @@ err_core_free:
        return ret;
 }
 
-static int ath11k_ahb_remove(struct platform_device *pdev)
+static void ath11k_ahb_remove_prepare(struct ath11k_base *ab)
 {
-       struct ath11k_base *ab = platform_get_drvdata(pdev);
        unsigned long left;
 
-       if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
-               ath11k_ahb_power_down(ab);
-               ath11k_debugfs_soc_destroy(ab);
-               ath11k_qmi_deinit_service(ab);
-               goto qmi_fail;
-       }
-
-       reinit_completion(&ab->driver_recovery);
-
        if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {
                left = wait_for_completion_timeout(&ab->driver_recovery,
                                                   ATH11K_AHB_RECOVERY_TIMEOUT);
@@ -771,18 +1237,65 @@ static int ath11k_ahb_remove(struct platform_device 
*pdev)
 
        set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);
        cancel_work_sync(&ab->restart_work);
+       cancel_work_sync(&ab->qmi.event_work);
+}
+
+static void ath11k_ahb_free_resources(struct ath11k_base *ab)
+{
+       struct platform_device *pdev = ab->pdev;
 
-       ath11k_core_deinit(ab);
-qmi_fail:
        ath11k_ahb_free_irq(ab);
        ath11k_hal_srng_deinit(ab);
+       ath11k_ahb_release_smp2p_handle(ab);
+       ath11k_ahb_fw_resource_deinit(ab);
        ath11k_ce_free_pipes(ab);
+
+       if (ab->hw_params.ce_remap)
+               iounmap(ab->mem_ce);
+
        ath11k_core_free(ab);
        platform_set_drvdata(pdev, NULL);
+}
+
+static int ath11k_ahb_remove(struct platform_device *pdev)
+{
+       struct ath11k_base *ab = platform_get_drvdata(pdev);
+
+       if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {
+               ath11k_ahb_power_down(ab);
+               ath11k_debugfs_soc_destroy(ab);
+               ath11k_qmi_deinit_service(ab);
+               goto qmi_fail;
+       }
+
+       ath11k_ahb_remove_prepare(ab);
+       ath11k_core_deinit(ab);
+
+qmi_fail:
+       ath11k_ahb_free_resources(ab);
 
        return 0;
 }
 
+static void ath11k_ahb_shutdown(struct platform_device *pdev)
+{
+       struct ath11k_base *ab = platform_get_drvdata(pdev);
+
+       /* platform shutdown() & remove() are mutually exclusive.
+        * remove() is invoked during rmmod & shutdown() during
+        * system reboot/shutdown.
+        */
+       ath11k_ahb_remove_prepare(ab);
+
+       if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))
+               goto free_resources;
+
+       ath11k_core_deinit(ab);
+
+free_resources:
+       ath11k_ahb_free_resources(ab);
+}
+
 static struct platform_driver ath11k_ahb_driver = {
        .driver         = {
                .name   = "ath11k",
@@ -790,6 +1303,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/sys/contrib/dev/athk/ath11k/ahb.h 
b/sys/contrib/dev/athk/ath11k/ahb.h
index 51e6e4a5f686..415ddfd26654 100644
--- a/sys/contrib/dev/athk/ath11k/ahb.h
+++ b/sys/contrib/dev/athk/ath11k/ahb.h
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
 /*
  * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
  */
 #ifndef ATH11K_AHB_H
 #define ATH11K_AHB_H
@@ -8,10 +9,34 @@
 #include "core.h"
 
 #define ATH11K_AHB_RECOVERY_TIMEOUT (3 * HZ)
+
+#define ATH11K_AHB_SMP2P_SMEM_MSG              GENMASK(15, 0)
+#define ATH11K_AHB_SMP2P_SMEM_SEQ_NO           GENMASK(31, 16)
+#define ATH11K_AHB_SMP2P_SMEM_VALUE_MASK       0xFFFFFFFF
+
*** 25161 LINES SKIPPED ***

Reply via email to