--- /dev/null
+From 323d91d4684d238f6bc3693fed93caf795378fe0 Mon Sep 17 00:00:00 2001
+From: Kalle Valo <quic_kvalo@quicinc.com>
+Date: Thu, 22 Dec 2022 19:15:59 +0200
+Subject: [PATCH] wifi: ath11k: debugfs: fix to work with multiple PCI devices
+
+ath11k fails to load if there are multiple ath11k PCI devices with same name:
+
+ ath11k_pci 0000:01:00.0: Hardware name qcn9074 hw1.0
+ debugfs: Directory 'ath11k' with parent '/' already present!
+ ath11k_pci 0000:01:00.0: failed to create ath11k debugfs
+ ath11k_pci 0000:01:00.0: failed to create soc core: -17
+ ath11k_pci 0000:01:00.0: failed to init core: -17
+ ath11k_pci: probe of 0000:01:00.0 failed with error -17
+
+Fix this by creating a directory for each ath11k device using schema
+<bus>-<devname>, for example "pci-0000:06:00.0". This directory created under
+the top-level ath11k directory, for example /sys/kernel/debug/ath11k.
+
+The reference to the toplevel ath11k directory is not stored anymore within ath11k, instead
+it's retrieved using debugfs_lookup(). If the directory does not exist it will
+be created. After the last directory from the ath11k directory is removed, for
+example when doing rmmod ath11k, the empty ath11k directory is left in place,
+it's a minor cosmetic issue anyway.
+
+Here's an example hierarchy with one WCN6855:
+
+ath11k
+`-- pci-0000:06:00.0
+ |-- mac0
+ | |-- dfs_block_radar_events
+ | |-- dfs_simulate_radar
+ | |-- ext_rx_stats
+ | |-- ext_tx_stats
+ | |-- fw_dbglog_config
+ | |-- fw_stats
+ | | |-- beacon_stats
+ | | |-- pdev_stats
+ | | `-- vdev_stats
+ | |-- htt_stats
+ | |-- htt_stats_reset
+ | |-- htt_stats_type
+ | `-- pktlog_filter
+ |-- simulate_fw_crash
+ `-- soc_dp_stats
+
+I didn't have a test setup where I could connect multiple ath11k devices to the
+same the host, so I have only tested this with one device.
+
+Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.9
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1
+
+Tested-by: Robert Marko <robert.marko@sartura.hr>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/20221220121231.20120-1-kvalo@kernel.org
+---
+ drivers/net/wireless/ath/ath11k/core.h | 1 -
+ drivers/net/wireless/ath/ath11k/debugfs.c | 48 +++++++++++++++++++----
+ 2 files changed, 40 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/core.h
++++ b/drivers/net/wireless/ath/ath11k/core.h
+@@ -912,7 +912,6 @@ struct ath11k_base {
+ enum ath11k_dfs_region dfs_region;
+ #ifdef CPTCFG_ATH11K_DEBUGFS
+ struct dentry *debugfs_soc;
+- struct dentry *debugfs_ath11k;
+ #endif
+ struct ath11k_soc_dp_stats soc_stats;
+
+--- a/drivers/net/wireless/ath/ath11k/debugfs.c
++++ b/drivers/net/wireless/ath/ath11k/debugfs.c
+@@ -976,10 +976,6 @@ int ath11k_debugfs_pdev_create(struct at
+ if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
+ return 0;
+
+- ab->debugfs_soc = debugfs_create_dir(ab->hw_params.name, ab->debugfs_ath11k);
+- if (IS_ERR(ab->debugfs_soc))
+- return PTR_ERR(ab->debugfs_soc);
+-
+ debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
+ &fops_simulate_fw_crash);
+
+@@ -1001,15 +997,51 @@ void ath11k_debugfs_pdev_destroy(struct
+
+ int ath11k_debugfs_soc_create(struct ath11k_base *ab)
+ {
+- ab->debugfs_ath11k = debugfs_create_dir("ath11k", NULL);
++ struct dentry *root;
++ bool dput_needed;
++ char name[64];
++ int ret;
++
++ root = debugfs_lookup("ath11k", NULL);
++ if (!root) {
++ root = debugfs_create_dir("ath11k", NULL);
++ if (IS_ERR_OR_NULL(root))
++ return PTR_ERR(root);
++
++ dput_needed = false;
++ } else {
++ /* a dentry from lookup() needs dput() after we don't use it */
++ dput_needed = true;
++ }
++
++ scnprintf(name, sizeof(name), "%s-%s", ath11k_bus_str(ab->hif.bus),
++ dev_name(ab->dev));
++
++ ab->debugfs_soc = debugfs_create_dir(name, root);
++ if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
++ ret = PTR_ERR(ab->debugfs_soc);
++ goto out;
++ }
++
++ ret = 0;
++
++out:
++ if (dput_needed)
++ dput(root);
+
+- return PTR_ERR_OR_ZERO(ab->debugfs_ath11k);
++ return ret;
+ }
+
+ void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
+ {
+- debugfs_remove_recursive(ab->debugfs_ath11k);
+- ab->debugfs_ath11k = NULL;
++ debugfs_remove_recursive(ab->debugfs_soc);
++ ab->debugfs_soc = NULL;
++
++ /* We are not removing ath11k directory on purpose, even if it
++ * would be empty. This simplifies the directory handling and it's
++ * a minor cosmetic issue to leave an empty ath11k directory to
++ * debugfs.
++ */
+ }
+ EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);
+
--- /dev/null
+From 534a5f99d589cfa6b244b4433c192b6a278a67ff Mon Sep 17 00:00:00 2001
+From: Robert Marko <robimarko@gmail.com>
+Date: Sat, 5 Nov 2022 20:15:40 +0100
+Subject: [PATCH] wifi: ath11k: use unique QRTR instance ID
+
+Currently, trying to use AHB + PCI/MHI cards or multiple PCI/MHI cards
+will cause a clash in the QRTR instance node ID and prevent the driver
+from talking via QMI to the card and thus initializing it with:
+[ 9.836329] ath11k c000000.wifi: host capability request failed: 1 90
+[ 9.842047] ath11k c000000.wifi: failed to send qmi host cap: -22
+
+So, in order to allow for this combination of cards, especially AHB + PCI
+cards like IPQ8074 + QCN9074 (Used by me and tested on) set the desired
+QRTR instance ID offset by calculating a unique one based on PCI domain
+and bus ID-s and writing it to bits 7-0 of BHI_ERRDBG2 MHI register by
+using the SBL state callback that is added as part of the series.
+We also have to make sure that new QRTR offset is added on top of the
+default QRTR instance ID-s that are currently used in the driver.
+
+This finally allows using AHB + PCI or multiple PCI cards on the same
+system.
+
+Since this is not supported on QCA6390 and like, its limited to QCN9074
+which is known to support changing QRTR instance ID.
+
+Before:
+root@OpenWrt:/# qrtr-lookup
+ Service Version Instance Node Port
+ 1054 1 0 7 1 <unknown>
+ 69 1 2 7 3 ATH10k WLAN firmware service
+
+After:
+root@OpenWrt:/# qrtr-lookup
+ Service Version Instance Node Port
+ 1054 1 0 7 1 <unknown>
+ 69 1 2 7 3 ATH10k WLAN firmware service
+ 15 1 0 8 1 Test service
+ 69 1 8 8 2 ATH10k WLAN firmware service
+
+Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1
+
+Signed-off-by: Robert Marko <robimarko@gmail.com>
+---
+ drivers/net/wireless/ath/ath11k/mhi.c | 49 ++++++++++++++++++---------
+ drivers/net/wireless/ath/ath11k/mhi.h | 3 ++
+ drivers/net/wireless/ath/ath11k/pci.c | 9 ++++-
+ 3 files changed, 44 insertions(+), 17 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/mhi.c
++++ b/drivers/net/wireless/ath/ath11k/mhi.c
+@@ -294,6 +294,34 @@ static void ath11k_mhi_op_runtime_put(st
+ {
+ }
+
++static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,
++ void __iomem *addr,
++ u32 *out)
++{
++ *out = readl(addr);
++
++ return 0;
++}
++
++static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,
++ void __iomem *addr,
++ u32 val)
++{
++ writel(val, addr);
++}
++
++static void ath11k_mhi_qrtr_instance_set(struct mhi_controller *mhi_cntrl)
++{
++ struct ath11k_base *ab = dev_get_drvdata(mhi_cntrl->cntrl_dev);
++
++ if (ab->hw_rev == ATH11K_HW_QCN9074_HW10) {
++ ath11k_mhi_op_write_reg(mhi_cntrl,
++ mhi_cntrl->bhi + BHI_ERRDBG2,
++ FIELD_PREP(QRTR_INSTANCE_MASK,
++ ab->qmi.service_ins_id - ab->hw_params.qmi_service_ins_id));
++ }
++}
++
+ static char *ath11k_mhi_op_callback_to_str(enum mhi_callback reason)
+ {
+ switch (reason) {
+@@ -315,6 +343,8 @@ static char *ath11k_mhi_op_callback_to_s
+ return "MHI_CB_FATAL_ERROR";
+ case MHI_CB_BW_REQ:
+ return "MHI_CB_BW_REQ";
++ case MHI_CB_EE_SBL_MODE:
++ return "MHI_CB_EE_SBL_MODE";
+ default:
+ return "UNKNOWN";
+ }
+@@ -336,27 +366,14 @@ static void ath11k_mhi_op_status_cb(stru
+ if (!(test_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags)))
+ queue_work(ab->workqueue_aux, &ab->reset_work);
+ break;
++ case MHI_CB_EE_SBL_MODE:
++ ath11k_mhi_qrtr_instance_set(mhi_cntrl);
++ break;
+ default:
+ break;
+ }
+ }
+
+-static int ath11k_mhi_op_read_reg(struct mhi_controller *mhi_cntrl,
+- void __iomem *addr,
+- u32 *out)
+-{
+- *out = readl(addr);
+-
+- return 0;
+-}
+-
+-static void ath11k_mhi_op_write_reg(struct mhi_controller *mhi_cntrl,
+- void __iomem *addr,
+- u32 val)
+-{
+- writel(val, addr);
+-}
+-
+ static int ath11k_mhi_read_addr_from_dt(struct mhi_controller *mhi_ctrl)
+ {
+ struct device_node *np;
+--- a/drivers/net/wireless/ath/ath11k/mhi.h
++++ b/drivers/net/wireless/ath/ath11k/mhi.h
+@@ -16,6 +16,9 @@
+ #define MHICTRL 0x38
+ #define MHICTRL_RESET_MASK 0x2
+
++#define BHI_ERRDBG2 0x38
++#define QRTR_INSTANCE_MASK GENMASK(7, 0)
++
+ int ath11k_mhi_start(struct ath11k_pci *ar_pci);
+ void ath11k_mhi_stop(struct ath11k_pci *ar_pci);
+ int ath11k_mhi_register(struct ath11k_pci *ar_pci);
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -370,13 +370,20 @@ static void ath11k_pci_sw_reset(struct a
+ static void ath11k_pci_init_qmi_ce_config(struct ath11k_base *ab)
+ {
+ struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;
++ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
++ struct pci_bus *bus = ab_pci->pdev->bus;
+
+ cfg->tgt_ce = ab->hw_params.target_ce_config;
+ cfg->tgt_ce_len = ab->hw_params.target_ce_count;
+
+ cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;
+ cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;
+- ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
++
++ if (ab->hw_rev == ATH11K_HW_QCN9074_HW10) {
++ ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id +
++ (((pci_domain_nr(bus) & 0xF) << 4) | (bus->number & 0xF));
++ } else
++ ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;
+
+ ath11k_ce_get_shadow_config(ab, &cfg->shadow_reg_v2,
+ &cfg->shadow_reg_v2_len);