Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms
@ 2026-09-23 12:05 George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 01/16] dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically George Moussalem via B4 Relay
                   ` (15 more replies)
  0 siblings, 16 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

Add multiPD support for AHB platforms following the approach for ath12k:
link: https://lore.kernel.org/linux-wireless/20250321-ath12k-ahb-v12-0-bb389ed76ae5@quicinc.com/
link: https://lore.kernel.org/linux-wireless/20260721065038.126046-1-aaradhana.sahu@oss.qualcomm.com/

The IPQ5018 platform is a multiPD platform and the current ath11k driver
supports standalone IPQ5018 WiFi only. However, IPQ5018 boards come with
up to two optional SoC-specific QCN6122 WiFi companion chips for 5G/6G
WiFi.

IPQ5018 implements the multi-PD architecture as follows:

                     +-----------------------------+
                     |     Q6 Remote Processor     |
                     |            RootPD           |
                     +--------------+--------------+
                                    |
                                    |
                                    |
              +---------------------+---------------------+
              |                     |                     |
        +-----v-----+         +-----v-----+         +-----v-----+
        |  UserPD1  |         |  UserPD2  |         |  UserPD3  |
        |  IPQ5018  |         | QCN6122 #1|         | QCN6122 #2|
        |  (Radio)  |         |  (Radio)  |         |  (Radio)  |
        +-----------+         +-----------+         +-----------+

The rootPD is responsible for managing the lifecycle of the UserPD and
shared resources and providing SSR notifiers. There are different
firmware blobs that include either the rootPD and userPD binaries for
IPQ5018-only which auto-spawns the userPD for IPQ5018 WiFi, or for
IPQ5018 and QCN6122 for which the userPDs for each radio must be spawned
by the ath11k driver.

It's worth noting that QCN6122 does not have its own Q6 firmware blobs.
Instead, the firmware segments for QCN6122 are included in the MPD
version of the IPQ5018 firmware blob(s). The QCN6122 M3 firmware does
come separately and is loaded into the Q6 memory carveout of IPQ5018.

In high-level, the path series covers:
- Addition of multiPD IPQ5018 binding definition
- Updates to the ath11k driver to register handle standalone vs multiPD
  remoteproc boot sequence with required notifiers.
- Support for loading M3 firmware files during remoteproc boot sequence
- Ability to set required memory carveouts for Q6, BDF, and M3 firmware
  segments.
- Addition of SCM call to manage power state of the internal IPQ5018
  WiFi radio
- Driver support for resource acquisition and power up/down of userPDs
- Binding definition and AHB driver support for QCN6122

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
George Moussalem (16):
      dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically
      dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018
      wifi: ath11k: Register root PD rproc notifier
      wifi: ath11k: Add support for loading m3 mbn firmware
      wifi: ath11k: Add ability to set BDF and M3 dump memory addresses
      firmware: qcom: scm: Add support for setting internal WiFi power mode
      wifi: ath11k: Register userPD interrupts and SMEM entries
      wifi: ath11k: Power up userPD
      wifi: ath11k: Power down userPD
      dt-bindings: net: wireless: ath11k: Add bindings for QCN6122
      wifi: ath11k: add hw params for QCN6122
      wifi: ath11k: add hal regs for QCN6122
      wifi: ath11k: add hw ring mask for QCN6122
      wifi: ath11k: update hif and pci ops for QCN6122
      wifi: ath11k: define userPDs for QCN6122
      wifi: ath11k: add QCN6122 device support

 .../bindings/net/wireless/qcom,ath11k.yaml         | 569 ++++++++++++++++++++-
 drivers/firmware/qcom/qcom_scm.c                   |  43 ++
 drivers/firmware/qcom/qcom_scm.h                   |   2 +
 drivers/net/wireless/ath/ath11k/ahb.c              | 555 +++++++++++++++++++-
 drivers/net/wireless/ath/ath11k/ahb.h              |  54 +-
 drivers/net/wireless/ath/ath11k/core.c             |  99 +++-
 drivers/net/wireless/ath/ath11k/core.h             |   1 +
 drivers/net/wireless/ath/ath11k/hif.h              |   9 +
 drivers/net/wireless/ath/ath11k/hw.c               | 112 ++++
 drivers/net/wireless/ath/ath11k/hw.h               |  10 +
 drivers/net/wireless/ath/ath11k/pcic.c             |   9 +
 drivers/net/wireless/ath/ath11k/qmi.c              |  70 ++-
 drivers/net/wireless/ath/ath11k/qmi.h              |   3 +-
 include/linux/firmware/qcom/qcom_scm.h             |   1 +
 14 files changed, 1501 insertions(+), 36 deletions(-)
---
base-commit: 10cfa109c880092df32e396647b4afdca9be8350
change-id: 20260910-ipq5018-qcn6122-mpd-46256c31b99e

Best regards,
-- 
George Moussalem <george.moussalem@outlook.com>



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH ath-next 01/16] dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-28 10:45   ` Krzysztof Kozlowski
  2026-09-23 12:05 ` [PATCH ath-next 02/16] dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018 George Moussalem via B4 Relay
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Sort the compatible names in the binding file alphabetically for
legibility and correct ordering.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
index d4aa56e2f823..a846cd704b19 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
@@ -17,10 +17,10 @@ description: |
 properties:
   compatible:
     enum:
-      - qcom,ipq8074-wifi
+      - qcom,ipq5018-wifi
       - qcom,ipq6018-wifi
+      - qcom,ipq8074-wifi
       - qcom,wcn6750-wifi
-      - qcom,ipq5018-wifi
 
   reg:
     maxItems: 1
@@ -108,8 +108,8 @@ allOf:
         compatible:
           contains:
             enum:
-              - qcom,ipq8074-wifi
               - qcom,ipq6018-wifi
+              - qcom,ipq8074-wifi
     then:
       properties:
         interrupts:

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 02/16] dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 01/16] dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-28 10:45   ` Krzysztof Kozlowski
  2026-09-23 12:05 ` [PATCH ath-next 03/16] wifi: ath11k: Register root PD rproc notifier George Moussalem via B4 Relay
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Although support was added for IPQ5018, the bindings are missing, so
let's add them.

WiFi on IPQ5018 boards come in one of the following configurations:
1. IPQ5018 (standalone) + optional 5G/6G WiFi card (such as QCN9074)
2. IPQ5018 (MPD) + one or two 5G/6G QCN6122 WiFi chips where QCN6122
   is an IPQ5018-specific companion chip.

IPQ5018 implements the multi-PD architecture as follows:

                     +-----------------------------+
                     |     Q6 Remote Processor     |
                     |            RootPD           |
                     +--------------+--------------+
                                    |
                                    |
                                    |
              +---------------------+---------------------+
              |                     |                     |
        +-----v-----+         +-----v-----+         +-----v-----+
        |  UserPD1  |         |  UserPD2  |         |  UserPD3  |
        |  IPQ5018  |         | QCN6122 #1|         | QCN6122 #2|
        |  (Radio)  |         |  (Radio)  |         |  (Radio)  |
        +-----------+         +-----------+         +-----------+

The rootPD is responsible for managing the lifecycle of the UserPD and
shared resources and providing SSR notifiers. There are different
firmware blobs that include either the rootPD and userPD binaries for
IPQ5018-only which auto-spawns the userPD for IPQ5018 WiFi, or for
IPQ5018 and QCN6122 for which the userPDs for each radio must be spawned
by the ath11k driver.

SMP2P is used for signaling between the host and the Q6 remote processor
to manage the lifecycle of the userPDs, so add the required interrupts
and smem-states for incoming and outgoing interrupts in the case of the
IPQ5018 + QCN6122 MPD configuration. Otherwise, the SMP2P interrupts and
smem-states are not required for the IPQ5018-only configuration.

In addition, document the memory regions needed for loading the BDF and
M3 firmware as well as for assigning the M3 dump memory block.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 .../bindings/net/wireless/qcom,ath11k.yaml         | 423 ++++++++++++++++++++-
 1 file changed, 410 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
index a846cd704b19..621ad6d4ddad 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
@@ -29,8 +29,13 @@ properties:
     minItems: 32
     maxItems: 52
 
+  interrupts-extended:
+    minItems: 56
+    maxItems: 56
+
   interrupt-names:
-    maxItems: 52
+    minItems: 32
+    maxItems: 56
 
   qcom,rproc:
     $ref: /schemas/types.yaml#/definitions/phandle
@@ -56,11 +61,15 @@ properties:
 
   memory-region:
     minItems: 1
-    maxItems: 2
+    maxItems: 3
     description:
       phandle to a node describing reserved memory (System RAM memory)
       used by ath11k firmware (see bindings/reserved-memory/reserved-memory.txt)
 
+  memory-region-names:
+    minItems: 1
+    maxItems: 3
+
   iommus:
     minItems: 1
     maxItems: 2
@@ -78,20 +87,11 @@ properties:
   qcom,smem-states:
     $ref: /schemas/types.yaml#/definitions/phandle-array
     description: State bits used by the AP to signal the WLAN Q6.
-    items:
-      - description: Signal bits used to enable/disable low power mode
-          on WCN6750 in the case of WoW (Wake on Wireless).
-        items:
-          - description: Phandle to the Shared Memory Point 2 Point device
-              handling the communication with a remote processor
-          - description: Single bit index to toggle in the value sent to
-              the remote processor
-            maximum: 32
+    minItems: 1
+    maxItems: 3
 
   qcom,smem-state-names:
     description: The names of the state bits used for SMP2P output.
-    items:
-      - const: wlan-smp2p-out
 
 required:
   - compatible
@@ -103,6 +103,242 @@ additionalProperties: false
 
 allOf:
   - $ref: ieee80211.yaml#
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,ipq5018-wifi
+    then:
+      properties:
+        interrupts:
+          items:
+            - description: misc-pulse1 interrupt events
+            - description: misc-latch interrupt events
+            - description: sw exception interrupt events
+            - description: watchdog interrupt events
+            - description: interrupt event for ring CE0
+            - description: interrupt event for ring CE1
+            - description: interrupt event for ring CE2
+            - description: interrupt event for ring CE3
+            - description: interrupt event for ring CE4
+            - description: interrupt event for ring CE5
+            - description: interrupt event for ring CE6
+            - description: interrupt event for ring CE7
+            - description: interrupt event for ring CE8
+            - description: interrupt event for ring CE9
+            - description: interrupt event for ring CE10
+            - description: interrupt event for ring CE11
+            - description: interrupt event for ring host2wbm-desc-feed
+            - description: interrupt event for ring host2reo-re-injection
+            - description: interrupt event for ring host2reo-command
+            - description: interrupt event for ring host2rxdma-monitor-ring3
+            - description: interrupt event for ring host2rxdma-monitor-ring2
+            - description: interrupt event for ring host2rxdma-monitor-ring1
+            - description: interrupt event for ring reo2ost-exception
+            - description: interrupt event for ring wbm2host-rx-release
+            - description: interrupt event for ring reo2host-status
+            - description: interrupt event for ring reo2host-destination-ring4
+            - description: interrupt event for ring reo2host-destination-ring3
+            - description: interrupt event for ring reo2host-destination-ring2
+            - description: interrupt event for ring reo2host-destination-ring1
+            - description: interrupt event for ring rxdma2host-monitor-destination-mac3
+            - description: interrupt event for ring rxdma2host-monitor-destination-mac2
+            - description: interrupt event for ring rxdma2host-monitor-destination-mac1
+            - description: interrupt event for ring ppdu-end-interrupts-mac3
+            - description: interrupt event for ring ppdu-end-interrupts-mac2
+            - description: interrupt event for ring ppdu-end-interrupts-mac1
+            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac3
+            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac2
+            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac1
+            - description: interrupt event for ring host2rxdma-host-buf-ring-mac3
+            - description: interrupt event for ring host2rxdma-host-buf-ring-mac2
+            - description: interrupt event for ring host2rxdma-host-buf-ring-mac1
+            - description: interrupt event for ring rxdma2host-destination-ring-mac3
+            - description: interrupt event for ring rxdma2host-destination-ring-mac2
+            - description: interrupt event for ring rxdma2host-destination-ring-mac1
+            - description: interrupt event for ring host2tcl-input-ring4
+            - description: interrupt event for ring host2tcl-input-ring3
+            - description: interrupt event for ring host2tcl-input-ring2
+            - description: interrupt event for ring host2tcl-input-ring1
+            - description: interrupt event for ring wbm2host-tx-completions-ring3
+            - description: interrupt event for ring wbm2host-tx-completions-ring2
+            - description: interrupt event for ring wbm2host-tx-completions-ring1
+            - description: interrupt event for ring tcl2host-status-ring
+        interrupts-extended:
+          items:
+            - description: misc-pulse1 interrupt events
+            - description: misc-latch interrupt events
+            - description: sw exception interrupt events
+            - description: watchdog interrupt events
+            - description: interrupt event for ring CE0
+            - description: interrupt event for ring CE1
+            - description: interrupt event for ring CE2
+            - description: interrupt event for ring CE3
+            - description: interrupt event for ring CE4
+            - description: interrupt event for ring CE5
+            - description: interrupt event for ring CE6
+            - description: interrupt event for ring CE7
+            - description: interrupt event for ring CE8
+            - description: interrupt event for ring CE9
+            - description: interrupt event for ring CE10
+            - description: interrupt event for ring CE11
+            - description: interrupt event for ring host2wbm-desc-feed
+            - description: interrupt event for ring host2reo-re-injection
+            - description: interrupt event for ring host2reo-command
+            - description: interrupt event for ring host2rxdma-monitor-ring3
+            - description: interrupt event for ring host2rxdma-monitor-ring2
+            - description: interrupt event for ring host2rxdma-monitor-ring1
+            - description: interrupt event for ring reo2ost-exception
+            - description: interrupt event for ring wbm2host-rx-release
+            - description: interrupt event for ring reo2host-status
+            - description: interrupt event for ring reo2host-destination-ring4
+            - description: interrupt event for ring reo2host-destination-ring3
+            - description: interrupt event for ring reo2host-destination-ring2
+            - description: interrupt event for ring reo2host-destination-ring1
+            - description: interrupt event for ring rxdma2host-monitor-destination-mac3
+            - description: interrupt event for ring rxdma2host-monitor-destination-mac2
+            - description: interrupt event for ring rxdma2host-monitor-destination-mac1
+            - description: interrupt event for ring ppdu-end-interrupts-mac3
+            - description: interrupt event for ring ppdu-end-interrupts-mac2
+            - description: interrupt event for ring ppdu-end-interrupts-mac1
+            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac3
+            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac2
+            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac1
+            - description: interrupt event for ring host2rxdma-host-buf-ring-mac3
+            - description: interrupt event for ring host2rxdma-host-buf-ring-mac2
+            - description: interrupt event for ring host2rxdma-host-buf-ring-mac1
+            - description: interrupt event for ring rxdma2host-destination-ring-mac3
+            - description: interrupt event for ring rxdma2host-destination-ring-mac2
+            - description: interrupt event for ring rxdma2host-destination-ring-mac1
+            - description: interrupt event for ring host2tcl-input-ring4
+            - description: interrupt event for ring host2tcl-input-ring3
+            - description: interrupt event for ring host2tcl-input-ring2
+            - description: interrupt event for ring host2tcl-input-ring1
+            - description: interrupt event for ring wbm2host-tx-completions-ring3
+            - description: interrupt event for ring wbm2host-tx-completions-ring2
+            - description: interrupt event for ring wbm2host-tx-completions-ring1
+            - description: interrupt event for ring tcl2host-status-ring
+            - description: Q6 firmware user PD fatal interrupt event
+            - description: Q6 firmware user PD ready interrupt event
+            - description: Q6 firmware user PD spawn interrupt event
+            - description: Q6 firmware user PD stop ack interrupt event
+        interrupt-names:
+          minItems: 52
+          items:
+            - const: misc-pulse1
+            - const: misc-latch
+            - const: sw-exception
+            - const: watchdog
+            - const: ce0
+            - const: ce1
+            - const: ce2
+            - const: ce3
+            - const: ce4
+            - const: ce5
+            - const: ce6
+            - const: ce7
+            - const: ce8
+            - const: ce9
+            - const: ce10
+            - const: ce11
+            - const: host2wbm-desc-feed
+            - const: host2reo-re-injection
+            - const: host2reo-command
+            - const: host2rxdma-monitor-ring3
+            - const: host2rxdma-monitor-ring2
+            - const: host2rxdma-monitor-ring1
+            - const: reo2ost-exception
+            - const: wbm2host-rx-release
+            - const: reo2host-status
+            - const: reo2host-destination-ring4
+            - const: reo2host-destination-ring3
+            - const: reo2host-destination-ring2
+            - const: reo2host-destination-ring1
+            - const: rxdma2host-monitor-destination-mac3
+            - const: rxdma2host-monitor-destination-mac2
+            - const: rxdma2host-monitor-destination-mac1
+            - const: ppdu-end-interrupts-mac3
+            - const: ppdu-end-interrupts-mac2
+            - const: ppdu-end-interrupts-mac1
+            - const: rxdma2host-monitor-status-ring-mac3
+            - const: rxdma2host-monitor-status-ring-mac2
+            - const: rxdma2host-monitor-status-ring-mac1
+            - const: host2rxdma-host-buf-ring-mac3
+            - const: host2rxdma-host-buf-ring-mac2
+            - const: host2rxdma-host-buf-ring-mac1
+            - const: rxdma2host-destination-ring-mac3
+            - const: rxdma2host-destination-ring-mac2
+            - const: rxdma2host-destination-ring-mac1
+            - const: host2tcl-input-ring4
+            - const: host2tcl-input-ring3
+            - const: host2tcl-input-ring2
+            - const: host2tcl-input-ring1
+            - const: wbm2host-tx-completions-ring3
+            - const: wbm2host-tx-completions-ring2
+            - const: wbm2host-tx-completions-ring1
+            - const: tcl2host-status-ring
+            - const: fatal
+            - const: ready
+            - const: spawn
+            - const: stop-ack
+        memory-region:
+          items:
+            - description: memory region for Q6 firmware
+            - description: memory region for M3 firmware
+            - description: memory region for M3 dump
+        memory-region-names:
+          items:
+            - const: q6-region
+            - const: m3-region
+            - const: m3-dump
+        qcom,smem-states:
+          items:
+            - description: Signal bit used to shutdown Q6 user PD
+              items:
+                - description: Phandle to the Shared Memory Point 2 Point device
+                - description: Single bit index to toggle in the value sent to the remote processor
+                  maximum: 32
+            - description: Signal bit used to stop Q6 user PD
+              items:
+                - description: Phandle to the Shared Memory Point 2 Point device
+                - description: Single bit index to toggle in the value sent to the remote processor
+                  maximum: 32
+            - description: Signal bit used to spawn Q6 user PD
+              items:
+                - description: Phandle to the Shared Memory Point 2 Point device
+                - description: Single bit index to toggle in the value sent to the remote processor
+                  maximum: 32
+        qcom,smem-state-names:
+          items:
+            - const: shutdown
+            - const: stop
+            - const: spawn
+      allOf:
+        - anyOf:
+            - required:
+                - interrupts
+            - required:
+                - interrupts-extended
+        - if:
+            required:
+              - interrupts-extended
+          then:
+            properties:
+              interrupt-names:
+                minItems: 56
+            required:
+              - interrupts-extended
+              - memory-region
+              - memory-region-names
+              - qcom,smem-states
+              - qcom,smem-state-names
+          else:
+            properties:
+              interrupt-names:
+                minItems: 52
+                maxItems: 52
+
   - if:
       properties:
         compatible:
@@ -265,6 +501,19 @@ allOf:
             - description: interrupt event for ring DP20
             - description: interrupt event for ring DP21
             - description: interrupt event for ring DP22
+        qcom,smem-states:
+          items:
+            - description: Signal bits used to enable/disable low power mode
+                on WCN6750 in the case of WoW (Wake on Wireless).
+              items:
+                - description: Phandle to the Shared Memory Point 2 Point device
+                    handling the communication with a remote processor
+                - description: Single bit index to toggle in the value sent to
+                    the remote processor
+                  maximum: 32
+        qcom,smem-state-names:
+          items:
+            - const: wlan-smp2p-out
 
 examples:
   - |
@@ -464,3 +713,151 @@ examples:
             iommus = <&apps_smmu 0x1c02 0x1>;
         };
     };
+
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    reserved-memory {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        q6_region: q6-region@4b000000 {
+            no-map;
+            reg = <0x0 0x4b000000 0x0 0x1400000>;
+        };
+
+        m3_dump: m3-dump@4d100000 {
+            reg = <0x0 0x4d100000 0x0 0x100000>;
+            no-map;
+        };
+    };
+
+    wifi@c000000 {
+        compatible = "qcom,ipq5018-wifi";
+        reg = <0x0c000000 0x1000000>;
+
+        interrupts-extended = <&intc GIC_SPI 288 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 289 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 290 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 291 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 292 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 293 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 294 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 295 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 297 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 298 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 299 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 300 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 301 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 302 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 303 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 304 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 305 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 306 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 307 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 308 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 309 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 310 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 311 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 334 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 313 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 314 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 315 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 316 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 317 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 318 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 319 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 320 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 321 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 322 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 323 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 324 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 325 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 326 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 327 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 328 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 329 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 330 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 331 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 332 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 333 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 312 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 335 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 336 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 337 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 338 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 339 IRQ_TYPE_EDGE_RISING>,
+                              <&wcss_smp2p_in 8 IRQ_TYPE_NONE>,
+                              <&wcss_smp2p_in 9 IRQ_TYPE_NONE>,
+                              <&wcss_smp2p_in 12 IRQ_TYPE_NONE>,
+                              <&wcss_smp2p_in 11 IRQ_TYPE_NONE>;
+        interrupt-names = "misc-pulse1",
+                          "misc-latch",
+                          "sw-exception",
+                          "watchdog",
+                          "ce0",
+                          "ce1",
+                          "ce2",
+                          "ce3",
+                          "ce4",
+                          "ce5",
+                          "ce6",
+                          "ce7",
+                          "ce8",
+                          "ce9",
+                          "ce10",
+                          "ce11",
+                          "host2wbm-desc-feed",
+                          "host2reo-re-injection",
+                          "host2reo-command",
+                          "host2rxdma-monitor-ring3",
+                          "host2rxdma-monitor-ring2",
+                          "host2rxdma-monitor-ring1",
+                          "reo2ost-exception",
+                          "wbm2host-rx-release",
+                          "reo2host-status",
+                          "reo2host-destination-ring4",
+                          "reo2host-destination-ring3",
+                          "reo2host-destination-ring2",
+                          "reo2host-destination-ring1",
+                          "rxdma2host-monitor-destination-mac3",
+                          "rxdma2host-monitor-destination-mac2",
+                          "rxdma2host-monitor-destination-mac1",
+                          "ppdu-end-interrupts-mac3",
+                          "ppdu-end-interrupts-mac2",
+                          "ppdu-end-interrupts-mac1",
+                          "rxdma2host-monitor-status-ring-mac3",
+                          "rxdma2host-monitor-status-ring-mac2",
+                          "rxdma2host-monitor-status-ring-mac1",
+                          "host2rxdma-host-buf-ring-mac3",
+                          "host2rxdma-host-buf-ring-mac2",
+                          "host2rxdma-host-buf-ring-mac1",
+                          "rxdma2host-destination-ring-mac3",
+                          "rxdma2host-destination-ring-mac2",
+                          "rxdma2host-destination-ring-mac1",
+                          "host2tcl-input-ring4",
+                          "host2tcl-input-ring3",
+                          "host2tcl-input-ring2",
+                          "host2tcl-input-ring1",
+                          "wbm2host-tx-completions-ring3",
+                          "wbm2host-tx-completions-ring2",
+                          "wbm2host-tx-completions-ring1",
+                          "tcl2host-status-ring",
+                          "fatal",
+                          "ready",
+                          "spawn",
+                          "stop-ack";
+
+        qcom,smem-states = <&wcss_smp2p_out 8>,
+                           <&wcss_smp2p_out 9>,
+                           <&wcss_smp2p_out 10>;
+        qcom,smem-state-names = "shutdown",
+                                "stop",
+                                "spawn";
+
+        memory-region = <&q6_region>, <&q6_region>, <&m3_dump>;
+        memory-region-names = "q6-region", "m3-region", "m3-dump";
+
+        qcom,rproc = <&q6v5_wcss>;
+    };

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 03/16] wifi: ath11k: Register root PD rproc notifier
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 01/16] dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 02/16] dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018 George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 04/16] wifi: ath11k: Add support for loading m3 mbn firmware George Moussalem via B4 Relay
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

In preparation for multi-PD support, register the rproc notifier for the
Q6 rootPD to monitor its state about power up/down and crash events.

In non-MPD configurations such as IPQ8074, the rootPD directly provides
WiFi operation.

In a multi-PD configuration, the rootPD provides resources and services
to other one or multiple userPDs that provide WiFi operation.
The rproc driver handles loading and authenticating the firmware image
of the rootPD, while the ath11k driver boots the rootPD and the userPDs.

The root PD must be booted first, so power up the rootPD and wait
for a power-up notification from the notifier callback before powering
up the userPDs. Add global driver-level locking to avoid multiple
threads racing to power up the rootPD.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c | 218 +++++++++++++++++++++++++++++++---
 drivers/net/wireless/ath/ath11k/ahb.h |  17 ++-
 2 files changed, 215 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 27d01411b6e9..86723a2eb3d2 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -44,6 +44,13 @@ MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
 
 #define ATH11K_IRQ_CE0_OFFSET 4
 
+/*
+ * Global Driver-level Locking:
+ *  - ath11k_rproc_info_lock: Protects rproc_info allocation/free
+ */
+static struct ath11k_ahb_rproc_info *g_rproc_info;
+static DEFINE_MUTEX(ath11k_rproc_info_lock);
+
 static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {
 	"misc-pulse1",
 	"misc-latch",
@@ -408,21 +415,12 @@ static void ath11k_ahb_stop(struct ath11k_base *ab)
 
 static int ath11k_ahb_power_up(struct ath11k_base *ab)
 {
-	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
-	int ret;
-
-	ret = rproc_boot(ab_ahb->tgt_rproc);
-	if (ret)
-		ath11k_err(ab, "failed to boot the remote processor Q6\n");
-
-	return ret;
+	return 0;
 }
 
 static void ath11k_ahb_power_down(struct ath11k_base *ab, bool is_suspend)
 {
-	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
-
-	rproc_shutdown(ab_ahb->tgt_rproc);
+	return;
 }
 
 static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)
@@ -832,24 +830,200 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
 	.ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
 };
 
+static int ath11k_ahb_root_pd_state_notifier(struct notifier_block *nb,
+					     const unsigned long event, void *data)
+{
+	struct ath11k_ahb_rproc_info *rproc_info =
+		container_of(nb, struct ath11k_ahb_rproc_info, root_pd_nb);
+
+	if (event == ATH11K_RPROC_AFTER_POWERUP) {
+		ath11k_dbg(NULL, ATH11K_DBG_AHB, "Root PD is UP\n");
+		complete(&rproc_info->rootpd_ready);
+	}
+
+	return 0;
+}
+
+static int ath11k_ahb_register_rproc_notifier(void)
+{
+	int ret;
+
+	lockdep_assert_held(&ath11k_rproc_info_lock);
+
+	if (g_rproc_info->root_pd_notifier)
+		return 0;
+
+	g_rproc_info->root_pd_nb.notifier_call = ath11k_ahb_root_pd_state_notifier;
+
+	g_rproc_info->root_pd_notifier = qcom_register_ssr_notifier(g_rproc_info->tgt_rproc->name,
+								    &g_rproc_info->root_pd_nb);
+	if (IS_ERR(g_rproc_info->root_pd_notifier)) {
+		ret = PTR_ERR(g_rproc_info->root_pd_notifier);
+		g_rproc_info->root_pd_notifier = NULL;
+		return ret;
+	}
+
+	return 0;
+}
+
+static void ath11k_ahb_unregister_rproc_notifier(void)
+{
+	lockdep_assert_held(&ath11k_rproc_info_lock);
+
+	if (!g_rproc_info->root_pd_notifier)
+		return;
+
+	qcom_unregister_ssr_notifier(g_rproc_info->root_pd_notifier,
+				     &g_rproc_info->root_pd_nb);
+	g_rproc_info->root_pd_notifier = NULL;
+}
+
+static struct ath11k_ahb_rproc_info *ath11k_ahb_rproc_info_alloc(struct ath11k_base *ab)
+{
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+	struct ath11k_ahb_rproc_info *rproc_info;
+
+	lockdep_assert_held(&ath11k_rproc_info_lock);
+
+	rproc_info = kzalloc_obj(*rproc_info);
+	if (!rproc_info)
+		return NULL;
+
+	rproc_info->root_pd_booted = false;
+	init_completion(&rproc_info->rootpd_ready);
+	ab_ahb->rproc_info = rproc_info;
+
+	return rproc_info;
+}
+
 static int ath11k_core_get_rproc(struct ath11k_base *ab)
 {
 	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
 	struct device *dev = ab->dev;
 	struct rproc *prproc;
 	phandle rproc_phandle;
+	int ret;
+
+	lockdep_assert_held(&ath11k_rproc_info_lock);
+
+	if (g_rproc_info) {
+		ab_ahb->rproc_info = g_rproc_info;
+		return 0;
+	}
+
+	g_rproc_info = ath11k_ahb_rproc_info_alloc(ab);
+	if (!g_rproc_info)
+		return -ENOMEM;
 
 	if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {
 		ath11k_err(ab, "failed to get q6_rproc handle\n");
-		return -ENOENT;
+		ret = -ENOENT;
+		goto err_free_rproc_info;
 	}
 
 	prproc = rproc_get_by_phandle(rproc_phandle);
-	if (!prproc)
-		return dev_err_probe(&ab->pdev->dev, -EPROBE_DEFER, "failed to get rproc\n");
-	ab_ahb->tgt_rproc = prproc;
+	if (!prproc) {
+		ret = dev_err_probe(dev, -EPROBE_DEFER,
+				    "failed to get rproc\n");
+		goto err_free_rproc_info;
+	}
+	g_rproc_info->tgt_rproc = prproc;
 
 	return 0;
+
+err_free_rproc_info:
+	ab_ahb->rproc_info = NULL;
+	kfree(g_rproc_info);
+	g_rproc_info = NULL;
+	return ret;
+}
+
+static int ath11k_ahb_boot_root_pd(struct ath11k_base *ab)
+{
+	unsigned long time_left;
+	int ret;
+
+	lockdep_assert_held(&ath11k_rproc_info_lock);
+	reinit_completion(&g_rproc_info->rootpd_ready);
+
+	ret = rproc_boot(g_rproc_info->tgt_rproc);
+	if (ret < 0) {
+		ath11k_err(ab, "RootPD boot failed\n");
+		return ret;
+	}
+
+	time_left = wait_for_completion_timeout(&g_rproc_info->rootpd_ready,
+						ATH11K_ROOTPD_READY_TIMEOUT);
+	if (!time_left) {
+		ath11k_err(ab, "RootPD ready wait timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int ath11k_ahb_configure_rproc(struct ath11k_base *ab)
+{
+	int ret;
+
+	mutex_lock(&ath11k_rproc_info_lock);
+
+	ret = ath11k_core_get_rproc(ab);
+	if (ret < 0) {
+		mutex_unlock(&ath11k_rproc_info_lock);
+		return ret;
+	}
+
+	ret = ath11k_ahb_register_rproc_notifier();
+	if (ret < 0) {
+		ret = dev_err_probe(&ab->pdev->dev, ret,
+				    "failed to register rproc notifier\n");
+		goto err_put_rproc;
+	}
+
+	if (g_rproc_info->tgt_rproc->state != RPROC_RUNNING) {
+		ret = ath11k_ahb_boot_root_pd(ab);
+		if (ret) {
+			ath11k_err(ab, "failed to boot the remote processor Q6\n");
+			goto err_unreg_notifier;
+		}
+	}
+	g_rproc_info->root_pd_booted = true;
+
+	mutex_unlock(&ath11k_rproc_info_lock);
+
+	return 0;
+
+err_unreg_notifier:
+	ath11k_ahb_unregister_rproc_notifier();
+
+err_put_rproc:
+	rproc_put(g_rproc_info->tgt_rproc);
+	mutex_unlock(&ath11k_rproc_info_lock);
+	return ret;
+}
+
+static void ath11k_ahb_deconfigure_rproc(struct ath11k_base *ab)
+{
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+	struct ath11k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
+
+	if (!rproc_info || !g_rproc_info)
+		return;
+
+	mutex_lock(&ath11k_rproc_info_lock);
+
+	ath11k_ahb_unregister_rproc_notifier();
+
+	if (g_rproc_info->root_pd_booted &&
+	    g_rproc_info->tgt_rproc->state == RPROC_RUNNING)
+		rproc_shutdown(g_rproc_info->tgt_rproc);
+
+	rproc_put(g_rproc_info->tgt_rproc);
+	kfree(g_rproc_info);
+	g_rproc_info = NULL;
+
+	mutex_unlock(&ath11k_rproc_info_lock);
 }
 
 static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
@@ -1148,6 +1322,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
 	struct ath11k_base *ab;
 	const struct ath11k_hif_ops *hif_ops;
 	const struct ath11k_pci_ops *pci_ops;
+	struct ath11k_ahb *ab_ahb;
 	enum ath11k_hw_rev hw_rev;
 	int ret;
 
@@ -1187,6 +1362,8 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
 	ab->hw_rev = hw_rev;
 	ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
 	platform_set_drvdata(pdev, ab);
+	ab_ahb = ath11k_ahb_priv(ab);
+	ab_ahb->ab = ab;
 
 	ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
 	if (ret) {
@@ -1226,26 +1403,29 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
 
 	ath11k_ahb_init_qmi_ce_config(ab);
 
-	ret = ath11k_core_get_rproc(ab);
+	ret = ath11k_ahb_configure_rproc(ab);
 	if (ret)
 		goto err_ce_free;
 
 	ret = ath11k_core_init(ab);
 	if (ret) {
 		ath11k_err(ab, "failed to init core: %d\n", ret);
-		goto err_ce_free;
+		goto err_rproc_deconfigure;
 	}
 
 	ret = ath11k_ahb_config_irq(ab);
 	if (ret) {
 		ath11k_err(ab, "failed to configure irq: %d\n", ret);
-		goto err_ce_free;
+		goto err_rproc_deconfigure;
 	}
 
 	ath11k_qmi_fwreset_from_cold_boot(ab);
 
 	return 0;
 
+err_rproc_deconfigure:
+	ath11k_ahb_deconfigure_rproc(ab);
+
 err_ce_free:
 	ath11k_ce_free_pipes(ab);
 
@@ -1294,7 +1474,7 @@ static void ath11k_ahb_free_resources(struct ath11k_base *ab)
 	ath11k_ahb_fw_resource_deinit(ab);
 	ath11k_ce_free_pipes(ab);
 	ath11k_ahb_ce_unmap(ab);
-
+	ath11k_ahb_deconfigure_rproc(ab);
 	ath11k_core_free(ab);
 	platform_set_drvdata(pdev, NULL);
 }
diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h
index 8c1eb1e8e6b1..99a361e0091f 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.h
+++ b/drivers/net/wireless/ath/ath11k/ahb.h
@@ -6,6 +6,8 @@
 #ifndef ATH11K_AHB_H
 #define ATH11K_AHB_H
 
+#include <linux/remoteproc/qcom_rproc.h>
+
 #include "core.h"
 
 #define ATH11K_AHB_RECOVERY_TIMEOUT (3 * HZ)
@@ -14,6 +16,9 @@
 #define ATH11K_AHB_SMP2P_SMEM_SEQ_NO		GENMASK(31, 16)
 #define ATH11K_AHB_SMP2P_SMEM_VALUE_MASK	0xFFFFFFFF
 
+#define ATH11K_ROOTPD_READY_TIMEOUT		(5 * HZ)
+#define ATH11K_RPROC_AFTER_POWERUP		QCOM_SSR_AFTER_POWERUP
+
 enum ath11k_ahb_smp2p_msg_id {
 	ATH11K_AHB_POWER_SAVE_ENTER = 1,
 	ATH11K_AHB_POWER_SAVE_EXIT,
@@ -21,8 +26,17 @@ enum ath11k_ahb_smp2p_msg_id {
 
 struct ath11k_base;
 
-struct ath11k_ahb {
+struct ath11k_ahb_rproc_info {
 	struct rproc *tgt_rproc;
+
+	struct completion rootpd_ready;
+	struct notifier_block root_pd_nb;
+	void *root_pd_notifier;
+	bool root_pd_booted;
+};
+
+struct ath11k_ahb {
+	struct ath11k_base *ab;
 	struct {
 		struct device *dev;
 		struct iommu_domain *iommu_domain;
@@ -37,6 +51,7 @@ struct ath11k_ahb {
 		unsigned int smem_bit;
 		struct qcom_smem_state *smem_state;
 	} smp2p_info;
+	struct ath11k_ahb_rproc_info *rproc_info;
 };
 
 static inline struct ath11k_ahb *ath11k_ahb_priv(struct ath11k_base *ab)

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 04/16] wifi: ath11k: Add support for loading m3 mbn firmware
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (2 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 03/16] wifi: ath11k: Register root PD rproc notifier George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 05/16] wifi: ath11k: Add ability to set BDF and M3 dump memory addresses George Moussalem via B4 Relay
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add support for loading m3 firmware in MDT file format which is
different from the m3.bin file format. This is required for several
ath11k wifi chips such as IPQ5018.

The rproc driver is used to load the Q6 firmware binaries / MDT segments
into memory for the root PD and user PDs if present. However, the m3
firmware blob is not. The m3 firmware in MBN (MDT) format is loaded by
ath11k as part of the root PD boot sequence for AHB platform chips.

For chips for which the m3 firmware is outside of the Q6 memory
carveout, obtain the memory region from the device tree and load the m3
firmware into that region. Otherwise, fall back to the Q6 memory region
of the rproc node itself.

Keep track of whether m3 firmware has been loaded in the global
rproc_info struct using a bitmap. In a configuration with multiple
wifi chips of the same hardware revision, the m3 firmware requires to be
loaded only once.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c  | 65 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/ahb.h  |  3 ++
 drivers/net/wireless/ath/ath11k/core.c | 12 ++++++-
 drivers/net/wireless/ath/ath11k/hw.h   |  8 +++++
 drivers/net/wireless/ath/ath11k/qmi.c  |  6 ++--
 5 files changed, 91 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 86723a2eb3d2..9fe2e112dfb8 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -18,6 +18,7 @@
 #include "qmi.h"
 #include <linux/remoteproc.h>
 #include "pcic.h"
+#include <linux/soc/qcom/mdt_loader.h>
 #include <linux/soc/qcom/smem.h>
 #include <linux/soc/qcom/smem_state.h>
 
@@ -890,6 +891,7 @@ static struct ath11k_ahb_rproc_info *ath11k_ahb_rproc_info_alloc(struct ath11k_b
 		return NULL;
 
 	rproc_info->root_pd_booted = false;
+	rproc_info->m3_loaded = 0;
 	init_completion(&rproc_info->rootpd_ready);
 	ab_ahb->rproc_info = rproc_info;
 
@@ -962,6 +964,58 @@ static int ath11k_ahb_boot_root_pd(struct ath11k_base *ab)
 	return 0;
 }
 
+static int ath11k_ahb_load_m3_firmware(struct ath11k_base *ab)
+{
+	char m3_fw_name[ATH11K_FW_NAME_LEN];
+	const struct firmware *m3_fw = NULL;
+	struct device_node *node;
+	struct resource res = {};
+	phys_addr_t mem_phys;
+	void *mem_region;
+	size_t mem_size;
+	int ret;
+
+	ret = of_reserved_mem_region_to_resource_byname(ab->dev->of_node,
+							"m3-region", &res);
+	/* If m3 region isn't found, fall back to the mem region of the rproc */
+	if (ret && ret == -EINVAL) {
+		node = g_rproc_info->tgt_rproc->dev.parent->of_node;
+		ret = of_reserved_mem_region_to_resource(node, 0, &res);
+	}
+	if (ret) {
+		ath11k_err(ab, "Failed to get m3 memory resource: %d\n", ret);
+		return ret;
+	}
+
+	mem_phys = res.start;
+	mem_size = resource_size(&res);
+	mem_region = devm_memremap(ab->dev, mem_phys, mem_size, MEMREMAP_WC);
+
+	snprintf(m3_fw_name, sizeof(m3_fw_name), "%s/%s/%s",
+		 ATH11K_FW_DIR, ab->hw_params.fw.dir, ATH11K_M3_MBN_FILE);
+
+	ret = request_firmware(&m3_fw, m3_fw_name, ab->dev);
+	if (ret < 0) {
+		ath11k_err(ab, "Failed to request firmware: %d\n", ret);
+		return ret;
+	}
+
+	if (!m3_fw->size || m3_fw->size > mem_size) {
+		ath11k_err(ab, "Invalid firmware size\n");
+		release_firmware(m3_fw);
+		return -EINVAL;
+	}
+
+	ret = qcom_mdt_load_no_init(ab->dev, m3_fw, m3_fw_name, mem_region,
+				    mem_phys, mem_size, &mem_phys);
+	if (ret)
+		ath11k_err(ab, "Failed to load MDT segments: %d\n", ret);
+
+	release_firmware(m3_fw);
+
+	return ret;
+}
+
 static int ath11k_ahb_configure_rproc(struct ath11k_base *ab)
 {
 	int ret;
@@ -981,6 +1035,17 @@ static int ath11k_ahb_configure_rproc(struct ath11k_base *ab)
 		goto err_put_rproc;
 	}
 
+	if (ab->hw_params.m3_fw_support &&
+	    ab->hw_params.fw.m3_loader == ath11k_m3_fw_loader_ahb &&
+	    !(g_rproc_info->m3_loaded & BIT(ab->hw_params.hw_rev))) {
+		ret = ath11k_ahb_load_m3_firmware(ab);
+		if (ret) {
+			ath11k_err(ab, "failed to load m3 firmware: %d\n", ret);
+			goto err_unreg_notifier;
+		}
+		g_rproc_info->m3_loaded |= BIT(ab->hw_params.hw_rev);
+	}
+
 	if (g_rproc_info->tgt_rproc->state != RPROC_RUNNING) {
 		ret = ath11k_ahb_boot_root_pd(ab);
 		if (ret) {
diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h
index 99a361e0091f..033d6223494b 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.h
+++ b/drivers/net/wireless/ath/ath11k/ahb.h
@@ -33,6 +33,9 @@ struct ath11k_ahb_rproc_info {
 	struct notifier_block root_pd_nb;
 	void *root_pd_notifier;
 	bool root_pd_booted;
+
+	/* Bitmap of loaded M3 firmwares indexed by hardware revision */
+	u32 m3_loaded;
 };
 
 struct ath11k_ahb {
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index d2ed6a0ea7e3..428f382e74a9 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -46,6 +46,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "IPQ8074/hw2.0",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_ahb,
 		},
 		.max_radios = 3,
 		.bdf_addr = 0x4B0C0000,
@@ -135,6 +136,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "IPQ6018/hw1.0",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_ahb,
 		},
 		.max_radios = 2,
 		.bdf_addr = 0x4ABC0000,
@@ -222,6 +224,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "QCA6390/hw2.0",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_qmi,
 		},
 		.max_radios = 3,
 		.bdf_addr = 0x4B0C0000,
@@ -314,6 +317,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "QCN9074/hw1.0",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_qmi,
 		},
 		.max_radios = 1,
 		.single_pdev_only = false,
@@ -400,6 +404,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "WCN6855/hw2.0",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_qmi,
 		},
 		.max_radios = 3,
 		.bdf_addr = 0x4B0C0000,
@@ -492,6 +497,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "WCN6855/hw2.1",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_qmi,
 		},
 		.max_radios = 3,
 		.bdf_addr = 0x4B0C0000,
@@ -582,6 +588,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "WCN6750/hw1.0",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_qmi,
 		},
 		.max_radios = 1,
 		.bdf_addr = 0x4B0C0000,
@@ -667,6 +674,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "IPQ5018/hw1.0",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_ahb,
 		},
 		.max_radios = MAX_RADIOS_5018,
 		.bdf_addr = 0x4BA00000,
@@ -724,7 +732,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.dbr_debug_support = true,
 		.global_reset = false,
 		.bios_sar_capa = NULL,
-		.m3_fw_support = false,
+		.m3_fw_support = true,
 		.fixed_bdf_addr = true,
 		.fixed_mem_region = true,
 		.static_window_map = false,
@@ -752,6 +760,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "QCA2066/hw2.1",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_qmi,
 		},
 		.max_radios = 3,
 		.bdf_addr = 0x4B0C0000,
@@ -843,6 +852,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 			.dir = "QCA6698AQ/hw2.1",
 			.board_size = 256 * 1024,
 			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_qmi,
 		},
 		.max_radios = 3,
 		.bdf_addr = 0x4B0C0000,
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index 4996536fbd14..5a1100ceb895 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -72,6 +72,7 @@
 #define ATH11k_HW_RATECODE_CCK_SHORT_PREAM_MASK  0x4
 
 #define ATH11K_FW_DIR			"ath11k"
+#define ATH11K_FW_NAME_LEN		35
 
 #define ATH11K_BOARD_MAGIC		"QCA-ATH11K-BOARD"
 #define ATH11K_BOARD_API2_FILE		"board-2.bin"
@@ -79,6 +80,7 @@
 #define ATH11K_DEFAULT_CAL_FILE		"caldata.bin"
 #define ATH11K_AMSS_FILE		"amss.bin"
 #define ATH11K_M3_FILE			"m3.bin"
+#define ATH11K_M3_MBN_FILE		"m3_fw.mbn"
 #define ATH11K_REGDB_FILE_NAME		"regdb.bin"
 
 #define ATH11K_CE_OFFSET(ab)	(ab->mem_ce - ab->mem)
@@ -137,6 +139,11 @@ struct ath11k_hw_hal_params {
 	size_t num_tx_rings;
 };
 
+enum ath11k_m3_fw_loaders {
+	ath11k_m3_fw_loader_ahb,
+	ath11k_m3_fw_loader_qmi,
+};
+
 struct ath11k_hw_params {
 	const char *name;
 	u16 hw_rev;
@@ -147,6 +154,7 @@ struct ath11k_hw_params {
 		const char *dir;
 		size_t board_size;
 		size_t cal_offset;
+		enum ath11k_m3_fw_loaders m3_loader;
 	} fw;
 
 	const struct ath11k_hw_ops *hw_ops;
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index 7dc07339b957..bd81e8d3d5f7 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -1724,7 +1724,8 @@ int ath11k_qmi_host_cap_send(struct ath11k_base *ab)
 	req.bdf_support_valid = 1;
 	req.bdf_support = 1;
 
-	if (ab->hw_params.m3_fw_support) {
+	if (ab->hw_params.m3_fw_support &&
+	    ab->hw_params.fw.m3_loader == ath11k_m3_fw_loader_qmi) {
 		req.m3_support_valid = 1;
 		req.m3_support = 1;
 		req.m3_cache_support_valid = 1;
@@ -2589,7 +2590,8 @@ int ath11k_qmi_wlanfw_m3_info_send(struct ath11k_base *ab)
 	memset(&req, 0, sizeof(req));
 	memset(&resp, 0, sizeof(resp));
 
-	if (ab->hw_params.m3_fw_support) {
+	if (ab->hw_params.m3_fw_support &&
+	    ab->hw_params.fw.m3_loader == ath11k_m3_fw_loader_qmi) {
 		ret = ath11k_qmi_m3_load(ab);
 		if (ret) {
 			ath11k_err(ab, "failed to load m3 firmware: %d", ret);

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 05/16] wifi: ath11k: Add ability to set BDF and M3 dump memory addresses
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (3 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 04/16] wifi: ath11k: Add support for loading m3 mbn firmware George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 06/16] firmware: qcom: scm: Add support for setting internal WiFi power mode George Moussalem via B4 Relay
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

The BDF address is currently hardcoded in the hardware parameters.
However, the BDF address for multi-PD firmware can vary based on the
target and firmware. In addition, setting the M3 dump address is
required for IPQ5018/QCN6122 multi-PD firmware and functioning WiFi
operation.

As such, add the ability to lookup the respective reserved memory
regions defined in the device tree and use those addresses for the BDF
and M3 dump.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/qmi.c | 62 +++++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index bd81e8d3d5f7..771ef9b5304f 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -2037,6 +2037,45 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab)
 	return 0;
 }
 
+static const char *ath11k_qmi_get_mem_reg_name(int mem_type)
+{
+	switch (mem_type) {
+	case HOST_DDR_REGION_TYPE:
+	case BDF_MEM_REGION_TYPE:
+		return "q6-region";
+	case M3_DUMP_REGION_TYPE:
+		return "m3-dump";
+	default:
+		return NULL;
+	}
+}
+
+static int ath11k_qmi_reserved_memory_to_resource(struct ath11k_base *ab,
+						  int mem_type,
+						  struct resource *res)
+{
+	const char *rname;
+	int ret;
+
+	rname = ath11k_qmi_get_mem_reg_name(mem_type);
+	if (!rname) {
+		ath11k_dbg(ab, ATH11K_DBG_QMI,
+			   "invalid memory type %d\n", mem_type);
+		return -EINVAL;
+	}
+
+	ret = of_reserved_mem_region_to_resource_byname(ab->dev->of_node,
+							rname, res);
+	if (ret) {
+		ath11k_dbg(ab, ATH11K_DBG_QMI,
+			   "failed to get reserved memory region for %s\n",
+			   rname);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
 {
 	struct device *dev = ab->dev;
@@ -2073,7 +2112,11 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
 			idx++;
 			break;
 		case BDF_MEM_REGION_TYPE:
-			ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr;
+			ret = ath11k_qmi_reserved_memory_to_resource(ab, BDF_MEM_REGION_TYPE, &res);
+			if (!ret && !(ab->qmi.target_mem[i].size > resource_size(&res)))
+				ab->qmi.target_mem[idx].paddr = res.start;
+			else
+				ab->qmi.target_mem[idx].paddr = ab->hw_params.bdf_addr;
 			ab->qmi.target_mem[idx].iaddr = NULL;
 			ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
 			ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
@@ -2107,6 +2150,16 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab)
 			ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
 			idx++;
 			break;
+		case M3_DUMP_REGION_TYPE:
+			ret = ath11k_qmi_reserved_memory_to_resource(ab, M3_DUMP_REGION_TYPE, &res);
+			if (!ret && !(ab->qmi.target_mem[i].size > resource_size(&res))) {
+				ab->qmi.target_mem[idx].paddr = res.start;
+				ab->qmi.target_mem[idx].iaddr = NULL;
+				ab->qmi.target_mem[idx].size = ab->qmi.target_mem[i].size;
+				ab->qmi.target_mem[idx].type = ab->qmi.target_mem[i].type;
+				idx++;
+			}
+			break;
 		default:
 			ath11k_warn(ab, "qmi ignore invalid mem req type %d\n",
 				    ab->qmi.target_mem[i].type);
@@ -2300,6 +2353,7 @@ static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab,
 {
 	struct qmi_wlanfw_bdf_download_req_msg_v01 *req;
 	struct qmi_wlanfw_bdf_download_resp_msg_v01 resp;
+	struct resource res = {};
 	struct qmi_txn txn;
 	const u8 *temp = data;
 	void __iomem *bdf_addr = NULL;
@@ -2313,7 +2367,11 @@ static int ath11k_qmi_load_file_target_mem(struct ath11k_base *ab,
 	memset(&resp, 0, sizeof(resp));
 
 	if (ab->hw_params.fixed_bdf_addr) {
-		bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size);
+		ret = ath11k_qmi_reserved_memory_to_resource(ab, BDF_MEM_REGION_TYPE, &res);
+		if (!ret && !(ab->hw_params.fw.board_size > resource_size(&res)))
+			bdf_addr = ioremap(res.start, ab->hw_params.fw.board_size);
+		else
+			bdf_addr = ioremap(ab->hw_params.bdf_addr, ab->hw_params.fw.board_size);
 		if (!bdf_addr) {
 			ath11k_warn(ab, "qmi ioremap error for bdf_addr\n");
 			ret = -EIO;

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 06/16] firmware: qcom: scm: Add support for setting internal WiFi power mode
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (4 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 05/16] wifi: ath11k: Add ability to set BDF and M3 dump memory addresses George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 07/16] wifi: ath11k: Register userPD interrupts and SMEM entries George Moussalem via B4 Relay
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add SCM call to power up / down the SoC's internal WiFi radio.
The SoC's internal WiFi radio needs to be powered up/down through a SCM
call when MPD firmware is loaded by the rproc driver. Multi-PD firmware
only loads the root PD and provides services and resources to one or
multiple user PDs which are firmware segments required for each WiFi
radio (for ex. in the case of the MPD firmware for IPQ5018 which
contains the firmware binaries for the SoC's internal WiFi radio and one
or two IPQ5018-specific QCN6122 WiFi companion chips).

For non-MPD firmware, this call is not required.

Not all Trusted Execution Environment (QSEE) images support this call,
so first check if the call is available.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/firmware/qcom/qcom_scm.c       | 43 ++++++++++++++++++++++++++++++++++
 drivers/firmware/qcom/qcom_scm.h       |  2 ++
 include/linux/firmware/qcom/qcom_scm.h |  1 +
 3 files changed, 46 insertions(+)

diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 3eaa4c9ccf3c..8e5f5c235cb7 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -1084,6 +1084,49 @@ static bool qcom_scm_is_pas_available(void)
 	return true;
 }
 
+/**
+ * qcom_scm_pas_set_wifi_power_mode() - Power on/off internal wifi
+ * @peripheral:	peripheral id
+ * @enable:	true to power up, false to power down
+ *
+ * Return 0 on success.
+ */
+int qcom_scm_pas_set_wifi_power_mode(u32 peripheral, bool enable)
+{
+	struct qcom_scm_desc desc = {
+		.svc = QCOM_SCM_SVC_PIL,
+		.cmd = enable ? QCOM_SCM_PIL_PAS_WIFI_PWR_EN :
+		       QCOM_SCM_PIL_PAS_WIFI_PWR_DIS,
+		.arginfo = QCOM_SCM_ARGS(1),
+		.args[0] = peripheral,
+		.owner = ARM_SMCCC_OWNER_SIP,
+	};
+	struct qcom_scm_res res;
+	int ret;
+
+	if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
+					  enable ? QCOM_SCM_PIL_PAS_WIFI_PWR_EN :
+					  QCOM_SCM_PIL_PAS_WIFI_PWR_DIS))
+		return -EOPNOTSUPP;
+
+	ret = qcom_scm_clk_enable();
+	if (ret)
+		return ret;
+
+	ret = qcom_scm_bw_enable();
+	if (ret)
+		goto disable_clk;
+
+	ret = qcom_scm_call(__scm->dev, &desc, &res);
+	qcom_scm_bw_disable();
+
+disable_clk:
+	qcom_scm_clk_disable();
+
+	return ret ? : res.result[0];
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_set_wifi_power_mode);
+
 static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
 {
 	struct qcom_scm_desc desc = {
diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h
index cf90a565fdfb..e1554997ca08 100644
--- a/drivers/firmware/qcom/qcom_scm.h
+++ b/drivers/firmware/qcom/qcom_scm.h
@@ -105,6 +105,8 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev);
 #define QCOM_SCM_PIL_PAS_SHUTDOWN	0x06
 #define QCOM_SCM_PIL_PAS_IS_SUPPORTED	0x07
 #define QCOM_SCM_PIL_PAS_MSS_RESET	0x0a
+#define QCOM_SCM_PIL_PAS_WIFI_PWR_EN	0x17
+#define QCOM_SCM_PIL_PAS_WIFI_PWR_DIS	0x18
 #define QCOM_SCM_PIL_PAS_GET_RSCTABLE	0x21
 
 #define QCOM_SCM_SVC_IO			0x05
diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h
index 5747bd191bf1..9258839ae746 100644
--- a/include/linux/firmware/qcom/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
@@ -93,6 +93,7 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
 						  size_t *output_rt_size);
 
 int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx);
+int qcom_scm_pas_set_wifi_power_mode(u32 peripheral, bool enable);
 
 int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
 int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 07/16] wifi: ath11k: Register userPD interrupts and SMEM entries
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (5 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 06/16] firmware: qcom: scm: Add support for setting internal WiFi power mode George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 08/16] wifi: ath11k: Power up userPD George Moussalem via B4 Relay
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Q6 and the ath11k driver communicate using SMEM and IRQs.

Spawn interrupt is triggered once the userPD thread is spawned.
Ready interrupts denote that the userPD is completely powered up and
ready. Stop-ack is to acknowledge the ath11k driver that userPD has
stopped.

The root PD sets the spawn and stop bits in SMEM upon boot which the
ath11k driver reads to derive the userPD ID.

Set the spawn bit in SMEM to instruct Q6 to spawn a userPD which brings
up the radio. Similarly, the stop bit is set when a userPD needs to be
stopped.

Keep track of the userPDs that have been spawned and stopped in the
global rproc_info structure to determine when the rootPD can be stopped.

Move boot and shutdown of the root PD to probe and remove functions
respectively. This is to ensure that the root PD is booted before any
userPDs are spawned. For non-MPD platforms, the this move has no
functional impact.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c | 176 ++++++++++++++++++++++++++++++++--
 drivers/net/wireless/ath/ath11k/ahb.h |  25 +++++
 2 files changed, 191 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 9fe2e112dfb8..25f9a992a7d2 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -22,6 +22,13 @@
 #include <linux/soc/qcom/smem.h>
 #include <linux/soc/qcom/smem_state.h>
 
+#define ATH11K_UPD_IRQ_WRD_LEN  18
+static const char *const ath11k_userpd_irq[ATH11K_USERPD_MAX_IRQ] = {
+	"spawn",
+	"ready",
+	"stop-ack",
+};
+
 static const struct of_device_id ath11k_ahb_of_match[] = {
 	/* TODO: Should we change the compatible string to something similar
 	 * to one that ath10k uses?
@@ -46,6 +53,15 @@ MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);
 #define ATH11K_IRQ_CE0_OFFSET 4
 
 /*
+ * Multi-UserPD Architecture:
+ *
+ * One Q6 RootPD (managed by separate rproc driver) supports multiple
+ * ath12k UserPDs. Each UserPD represents a WiFi radio instance.
+ *
+ * Lifecycle:
+ *  - RootPD boots when first UserPD probes
+ *  - All UserPDs share RootPD's SSR notifier
+ *
  * Global Driver-level Locking:
  *  - ath11k_rproc_info_lock: Protects rproc_info allocation/free
  */
@@ -831,6 +847,126 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
 	.ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
 };
 
+static int ath11k_ahb_init_userpd(struct ath11k_base *ab, int userpd_id)
+{
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+
+	lockdep_assert_held(&ath11k_rproc_info_lock);
+
+	switch (ab->hw_rev) {
+	case ATH11K_HW_IPQ5018_HW10:
+		if (userpd_id != ATH11K_AHB_USERPD_ID_1)
+			return -EINVAL;
+
+		ab_ahb->userpd_id = userpd_id;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	g_rproc_info->userpd[userpd_id - 1] = ab_ahb;
+	g_rproc_info->num_userpd++;
+
+	return 0;
+}
+
+static irqreturn_t ath11k_userpd_irq_handler(int irq, void *data)
+{
+	struct ath11k_base *ab = data;
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+
+	if (irq == ab_ahb->userpd_irq_num[ATH11K_USERPD_SPAWN_IRQ]) {
+		complete(&ab_ahb->userpd_spawned);
+	} else if (irq == ab_ahb->userpd_irq_num[ATH11K_USERPD_READY_IRQ]) {
+		complete(&ab_ahb->userpd_ready);
+	} else if (irq == ab_ahb->userpd_irq_num[ATH11K_USERPD_STOP_ACK_IRQ])	{
+		complete(&ab_ahb->userpd_stopped);
+	} else {
+		ath11k_err(ab, "Invalid userpd interrupt\n");
+		return IRQ_NONE;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void ath11k_ahb_cleanup_userpd(struct ath11k_base *ab)
+{
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+	struct ath11k_ahb_rproc_info *rproc_info = ab_ahb->rproc_info;
+
+	lockdep_assert_held(&ath11k_rproc_info_lock);
+
+	if (!rproc_info)
+		return;
+
+	if (rproc_info && ab_ahb->userpd_id > 0 &&
+	    ab_ahb->userpd_id < ATH11K_AHB_USERPD_ID_MAX) {
+		rproc_info->userpd[ab_ahb->userpd_id - 1] = NULL;
+		rproc_info->num_userpd--;
+		ab_ahb->rproc_info = NULL;
+	}
+}
+
+static int ath11k_ahb_config_userpd_irq(struct ath11k_base *ab)
+{
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+	char *upd_irq_name;
+	int userpd_id;
+	int i, ret;
+
+	ab_ahb->spawn_state = devm_qcom_smem_state_get(&ab->pdev->dev, "spawn",
+						       &ab_ahb->spawn_bit);
+	if (IS_ERR(ab_ahb->spawn_state))
+		return dev_err_probe(&ab->pdev->dev, PTR_ERR(ab_ahb->spawn_state),
+				     "Failed to acquire spawn state\n");
+
+	ab_ahb->stop_state = devm_qcom_smem_state_get(&ab->pdev->dev, "stop",
+						      &ab_ahb->stop_bit);
+	if (IS_ERR(ab_ahb->stop_state))
+		return dev_err_probe(&ab->pdev->dev, PTR_ERR(ab_ahb->stop_state),
+				     "Failed to acquire stop state\n");
+
+	mutex_lock(&ath11k_rproc_info_lock);
+
+	userpd_id = ab_ahb->spawn_bit / 8;
+	ret = ath11k_ahb_init_userpd(ab, userpd_id);
+	if (ret) {
+		mutex_unlock(&ath11k_rproc_info_lock);
+		return ret;
+	}
+
+	mutex_unlock(&ath11k_rproc_info_lock);
+
+	for (i = 0; i < ATH11K_USERPD_MAX_IRQ; i++) {
+		ab_ahb->userpd_irq_num[i] = platform_get_irq_byname_optional(ab->pdev,
+									     ath11k_userpd_irq[i]);
+		if (ab_ahb->userpd_irq_num[i] < 0)
+			return ab_ahb->userpd_irq_num[i];
+
+		upd_irq_name = devm_kzalloc(&ab->pdev->dev, ATH11K_UPD_IRQ_WRD_LEN,
+					    GFP_KERNEL);
+		if (!upd_irq_name)
+			return -ENOMEM;
+
+		scnprintf(upd_irq_name, ATH11K_UPD_IRQ_WRD_LEN, "UserPD%u-%s",
+			  ab_ahb->userpd_id, ath11k_userpd_irq[i]);
+		ret = devm_request_threaded_irq(&ab->pdev->dev, ab_ahb->userpd_irq_num[i],
+						NULL, ath11k_userpd_irq_handler,
+						IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+						upd_irq_name, ab);
+		if (ret)
+			return dev_err_probe(&ab->pdev->dev, ret,
+					     "Request %s irq failed: %d\n",
+					     ath11k_userpd_irq[i], ret);
+	}
+
+	init_completion(&ab_ahb->userpd_spawned);
+	init_completion(&ab_ahb->userpd_ready);
+	init_completion(&ab_ahb->userpd_stopped);
+
+	return 0;
+}
+
 static int ath11k_ahb_root_pd_state_notifier(struct notifier_block *nb,
 					     const unsigned long event, void *data)
 {
@@ -1032,7 +1168,7 @@ static int ath11k_ahb_configure_rproc(struct ath11k_base *ab)
 	if (ret < 0) {
 		ret = dev_err_probe(&ab->pdev->dev, ret,
 				    "failed to register rproc notifier\n");
-		goto err_put_rproc;
+		goto err_cleanup_userpd;
 	}
 
 	if (ab->hw_params.m3_fw_support &&
@@ -1057,13 +1193,28 @@ static int ath11k_ahb_configure_rproc(struct ath11k_base *ab)
 
 	mutex_unlock(&ath11k_rproc_info_lock);
 
+	/*
+	 * UserPD interrupts are specific to multi-PD configs/firmware only.
+	 * If interrupts aren't found, continue execution for non-MPD platforms.
+	 */
+	ret = ath11k_ahb_config_userpd_irq(ab);
+	if (ret && ret != -EINVAL && ret != -ENXIO)
+		return dev_err_probe(&ab->pdev->dev, ret,
+				     "failed to configure userpd interrupts\n");
+
 	return 0;
 
 err_unreg_notifier:
 	ath11k_ahb_unregister_rproc_notifier();
 
-err_put_rproc:
-	rproc_put(g_rproc_info->tgt_rproc);
+err_cleanup_userpd:
+	ath11k_ahb_cleanup_userpd(ab);
+	if (g_rproc_info && !g_rproc_info->num_userpd) {
+		rproc_put(g_rproc_info->tgt_rproc);
+		kfree(g_rproc_info);
+		g_rproc_info = NULL;
+	}
+
 	mutex_unlock(&ath11k_rproc_info_lock);
 	return ret;
 }
@@ -1078,15 +1229,19 @@ static void ath11k_ahb_deconfigure_rproc(struct ath11k_base *ab)
 
 	mutex_lock(&ath11k_rproc_info_lock);
 
-	ath11k_ahb_unregister_rproc_notifier();
+	ath11k_ahb_cleanup_userpd(ab);
 
-	if (g_rproc_info->root_pd_booted &&
-	    g_rproc_info->tgt_rproc->state == RPROC_RUNNING)
-		rproc_shutdown(g_rproc_info->tgt_rproc);
+	if (!g_rproc_info->num_userpd) {
+		ath11k_ahb_unregister_rproc_notifier();
 
-	rproc_put(g_rproc_info->tgt_rproc);
-	kfree(g_rproc_info);
-	g_rproc_info = NULL;
+		if (g_rproc_info->root_pd_booted &&
+		    g_rproc_info->tgt_rproc->state == RPROC_RUNNING)
+			rproc_shutdown(g_rproc_info->tgt_rproc);
+
+		rproc_put(g_rproc_info->tgt_rproc);
+		kfree(g_rproc_info);
+		g_rproc_info = NULL;
+	}
 
 	mutex_unlock(&ath11k_rproc_info_lock);
 }
@@ -1429,6 +1584,7 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, ab);
 	ab_ahb = ath11k_ahb_priv(ab);
 	ab_ahb->ab = ab;
+	ab_ahb->userpd_id = 0;
 
 	ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
 	if (ret) {
diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h
index 033d6223494b..12e0c4d27a0c 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.h
+++ b/drivers/net/wireless/ath/ath11k/ahb.h
@@ -19,6 +19,11 @@
 #define ATH11K_ROOTPD_READY_TIMEOUT		(5 * HZ)
 #define ATH11K_RPROC_AFTER_POWERUP		QCOM_SSR_AFTER_POWERUP
 
+enum ath11k_ahb_userpd_id {
+	ATH11K_AHB_USERPD_ID_1 = 1,
+	ATH11K_AHB_USERPD_ID_MAX,
+};
+
 enum ath11k_ahb_smp2p_msg_id {
 	ATH11K_AHB_POWER_SAVE_ENTER = 1,
 	ATH11K_AHB_POWER_SAVE_EXIT,
@@ -34,10 +39,20 @@ struct ath11k_ahb_rproc_info {
 	void *root_pd_notifier;
 	bool root_pd_booted;
 
+	u8 num_userpd;
+	struct ath11k_ahb *userpd[ATH11K_AHB_USERPD_ID_MAX];
+
 	/* Bitmap of loaded M3 firmwares indexed by hardware revision */
 	u32 m3_loaded;
 };
 
+enum ath11k_ahb_userpd_irq {
+	ATH11K_USERPD_SPAWN_IRQ,
+	ATH11K_USERPD_READY_IRQ,
+	ATH11K_USERPD_STOP_ACK_IRQ,
+	ATH11K_USERPD_MAX_IRQ,
+};
+
 struct ath11k_ahb {
 	struct ath11k_base *ab;
 	struct {
@@ -55,6 +70,16 @@ struct ath11k_ahb {
 		struct qcom_smem_state *smem_state;
 	} smp2p_info;
 	struct ath11k_ahb_rproc_info *rproc_info;
+
+	struct qcom_smem_state *spawn_state;
+	struct qcom_smem_state *stop_state;
+	struct completion userpd_spawned;
+	struct completion userpd_ready;
+	struct completion userpd_stopped;
+	u32 userpd_id;
+	u32 spawn_bit;
+	u32 stop_bit;
+	int userpd_irq_num[ATH11K_USERPD_MAX_IRQ];
 };
 
 static inline struct ath11k_ahb *ath11k_ahb_priv(struct ath11k_base *ab)

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 08/16] wifi: ath11k: Power up userPD
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (6 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 07/16] wifi: ath11k: Register userPD interrupts and SMEM entries George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 09/16] wifi: ath11k: Power down userPD George Moussalem via B4 Relay
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Set the spawn bit to instruct Q6 to spawn the userPD thread.
Wait for userPD to spawn which is indicated by spawn interrupt. The
ready interrupt is triggered once the userPD is powered up completely.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c | 56 +++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/ahb.h |  7 +++++
 2 files changed, 63 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 25f9a992a7d2..2c41cf585d00 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -11,6 +11,7 @@
 #include <linux/of.h>
 #include <linux/of_reserved_mem.h>
 #include <linux/dma-mapping.h>
+#include <linux/firmware/qcom/qcom_scm.h>
 #include <linux/iommu.h>
 #include "ahb.h"
 #include "debug.h"
@@ -430,8 +431,63 @@ static void ath11k_ahb_stop(struct ath11k_base *ab)
 	ath11k_ce_cleanup_pipes(ab);
 }
 
+static int ath11k_ahb_boot_user_pd(struct ath11k_base *ab)
+{
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+	unsigned long time_left;
+	int ret;
+
+	if (ab->hw_rev == ATH11K_HW_IPQ5018_HW10) {
+		ret = qcom_scm_pas_set_wifi_power_mode(MPD_WCNSS_PAS_ID, true);
+		if (ret) {
+			ath11k_err(ab, "failed to power up wifi: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = qcom_smem_state_update_bits(ab_ahb->spawn_state, BIT(ab_ahb->spawn_bit),
+					  BIT(ab_ahb->spawn_bit));
+	if (ret) {
+		ath11k_err(ab, "Failed to update spawn state %d\n", ret);
+		return ret;
+	}
+
+	time_left = wait_for_completion_timeout(&ab_ahb->userpd_spawned,
+						ATH11K_USERPD_SPAWN_TIMEOUT);
+	if (!time_left) {
+		ath11k_err(ab, "UserPD spawn wait timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	time_left = wait_for_completion_timeout(&ab_ahb->userpd_ready,
+						ATH11K_USERPD_READY_TIMEOUT);
+	if (!time_left) {
+		ath11k_err(ab, "UserPD ready wait timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	qcom_smem_state_update_bits(ab_ahb->spawn_state, BIT(ab_ahb->spawn_bit), 0);
+
+	ath11k_dbg(ab, ATH11K_DBG_AHB, "UserPD%d is now UP\n", ab_ahb->userpd_id);
+
+	return 0;
+}
+
 static int ath11k_ahb_power_up(struct ath11k_base *ab)
 {
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+	int ret;
+
+	if (ab_ahb->userpd_id > 0 &&
+	    ab_ahb->userpd_id < ATH11K_AHB_USERPD_ID_MAX) {
+		ret = ath11k_ahb_boot_user_pd(ab);
+		if (ret) {
+			ath11k_err(ab, "failed to boot userPD%d: %d\n",
+				   ab_ahb->userpd_id, ret);
+			return ret;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h
index 12e0c4d27a0c..0647bdb9ea62 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.h
+++ b/drivers/net/wireless/ath/ath11k/ahb.h
@@ -19,6 +19,13 @@
 #define ATH11K_ROOTPD_READY_TIMEOUT		(5 * HZ)
 #define ATH11K_RPROC_AFTER_POWERUP		QCOM_SSR_AFTER_POWERUP
 
+#define ATH11K_USERPD_SPAWN_TIMEOUT		(5 * HZ)
+#define ATH11K_USERPD_READY_TIMEOUT		(10 * HZ)
+#define ATH11K_USERPD_STOP_TIMEOUT		(5 * HZ)
+#define ATH11K_USERPD_FW_NAME_LEN		35
+
+#define MPD_WCNSS_PAS_ID			0xD
+
 enum ath11k_ahb_userpd_id {
 	ATH11K_AHB_USERPD_ID_1 = 1,
 	ATH11K_AHB_USERPD_ID_MAX,

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 09/16] wifi: ath11k: Power down userPD
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (7 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 08/16] wifi: ath11k: Power up userPD George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 10/16] dt-bindings: net: wireless: ath11k: Add bindings for QCN6122 George Moussalem via B4 Relay
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Set the stop bit in SMEM to stop the userPD. Wait for stop-ack IRQ to
indicate power down completion.

For IPQ5018 wifi specifically, invoke an SCM call to power down the
radio.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 2c41cf585d00..1b9115311bed 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -491,9 +491,32 @@ static int ath11k_ahb_power_up(struct ath11k_base *ab)
 	return 0;
 }
 
+static void ath11k_ahb_stop_user_pd(struct ath11k_base *ab)
+{
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+	unsigned long time_left;
+
+	qcom_smem_state_update_bits(ab_ahb->stop_state, BIT(ab_ahb->stop_bit),
+				    BIT(ab_ahb->stop_bit));
+
+	time_left = wait_for_completion_timeout(&ab_ahb->userpd_stopped,
+						ATH11K_USERPD_STOP_TIMEOUT);
+	if (!time_left)
+		ath11k_warn(ab, "UserPD stop wait timed out\n");
+
+	qcom_smem_state_update_bits(ab_ahb->stop_state, BIT(ab_ahb->stop_bit), 0);
+
+	if (ab->hw_rev == ATH11K_HW_IPQ5018_HW10)
+		qcom_scm_pas_set_wifi_power_mode(MPD_WCNSS_PAS_ID, false);
+}
+
 static void ath11k_ahb_power_down(struct ath11k_base *ab, bool is_suspend)
 {
-	return;
+	struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);
+
+	if (ab_ahb->userpd_id > 0 &&
+	    ab_ahb->userpd_id < ATH11K_AHB_USERPD_ID_MAX)
+		ath11k_ahb_stop_user_pd(ab);
 }
 
 static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 10/16] dt-bindings: net: wireless: ath11k: Add bindings for QCN6122
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (8 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 09/16] wifi: ath11k: Power down userPD George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 11/16] wifi: ath11k: add hw params " George Moussalem via B4 Relay
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add bindings for QCN6122, which is a companion chip to IPQ5018. The
QCN6122 is a 5G/6G WiFi chip that is used in conjunction with the
IPQ5018 SoC in a multi-PD (MPD) configuration.

WiFi on IPQ5018 boards come in one of the following configurations:
1. IPQ5018 (standalone) + optional 5G/6G WiFi card (such as QCN9074)
2. IPQ5018 (MPD) + one or two 5G/6G QCN6122 WiFi chips.

IPQ5018 implements the multi-PD architecture as follows:

                     +-----------------------------+
                     |     Q6 Remote Processor     |
                     |            RootPD           |
                     +--------------+--------------+
                                    |
                                    |
                                    |
              +---------------------+---------------------+
              |                     |                     |
        +-----v-----+         +-----v-----+         +-----v-----+
        |  UserPD1  |         |  UserPD2  |         |  UserPD3  |
        |  IPQ5018  |         | QCN6122 #1|         | QCN6122 #2|
        |  (Radio)  |         |  (Radio)  |         |  (Radio)  |
        +-----------+         +-----------+         +-----------+

The rootPD is responsible for managing the lifecycle of the UserPD and
shared resources and providing SSR notifiers. There are different
firmware blobs that include either the rootPD and userPD binaries for
IPQ5018-only which auto-spawns the userPD for IPQ5018 WiFi, or for
IPQ5018 and QCN6122 for which the userPDs for each radio must be spawned
by the ath11k driver.

SMP2P is used for signaling between the host and the Q6 remote processor
to manage the lifecycle of the userPDs, so add the required interrupts
and smem-states for incoming and outgoing interrupts in the case of the
IPQ5018 + QCN6122 MPD configuration. Otherwise, the SMP2P interrupts and
smem-states are not required for the IPQ5018-only configuration.

In addition, document the memory regions needed for loading the BDF and
M3 firmware as well as for assigning the M3 dump memory block.

It's worth noting that QCN6122 does not have its own Q6 firmware blobs.
Instead, the firmware segments for QCN6122 are included in the IPQ5018
MPD firmware blob(s). In addition, the QCN6122 M3 firmware which does
come separately is loaded into the Q6 memory carveout of IPQ5018, hence
the need for a dedicated "m3-region" reserved memory region.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 .../bindings/net/wireless/qcom,ath11k.yaml         | 144 ++++++++++++++++++++-
 1 file changed, 142 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
index 621ad6d4ddad..10102b5ea8c8 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
@@ -20,6 +20,7 @@ properties:
       - qcom,ipq5018-wifi
       - qcom,ipq6018-wifi
       - qcom,ipq8074-wifi
+      - qcom,qcn6122-wifi
       - qcom,wcn6750-wifi
 
   reg:
@@ -30,11 +31,11 @@ properties:
     maxItems: 52
 
   interrupts-extended:
-    minItems: 56
+    minItems: 17
     maxItems: 56
 
   interrupt-names:
-    minItems: 32
+    minItems: 17
     maxItems: 56
 
   qcom,rproc:
@@ -459,6 +460,93 @@ allOf:
       required:
         - interrupt-names
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - qcom,qcn6122-wifi
+    then:
+      properties:
+        interrupts-extended:
+          items:
+            - description: interrupt event for ring CE1
+            - description: interrupt event for ring CE2
+            - description: interrupt event for ring CE3
+            - description: interrupt event for ring CE4
+            - description: interrupt event for ring CE5
+            - description: interrupt event for ring DP1
+            - description: interrupt event for ring DP2
+            - description: interrupt event for ring DP3
+            - description: interrupt event for ring DP4
+            - description: interrupt event for ring DP5
+            - description: interrupt event for ring DP6
+            - description: interrupt event for ring DP7
+            - description: interrupt event for ring DP8
+            - description: Q6 firmware user PD fatal interrupt event
+            - description: Q6 firmware user PD ready interrupt event
+            - description: Q6 firmware user PD spawn interrupt event
+            - description: Q6 firmware user PD stop ack interrupt event
+        interrupt-names:
+          minItems: 17
+          items:
+            - const: ce1
+            - const: ce2
+            - const: ce3
+            - const: ce4
+            - const: ce5
+            - const: dp1
+            - const: dp2
+            - const: dp3
+            - const: dp4
+            - const: dp5
+            - const: dp6
+            - const: dp7
+            - const: dp8
+            - const: fatal
+            - const: ready
+            - const: spawn
+            - const: stop-ack
+        memory-region:
+          minItems: 1
+          items:
+            - description: memory region for Q6 firmware
+            - description: memory region for M3 firmware
+            - description: memory region for M3 dump
+        memory-region-names:
+          minItems: 1
+          items:
+            - const: q6-region
+            - const: m3-region
+            - const: m3-dump
+        qcom,smem-states:
+          items:
+            - description: Signal bit used to shutdown Q6 user PD
+              items:
+                - description: Phandle to the Shared Memory Point 2 Point device
+                - description: Single bit index to toggle in the value sent to the remote processor
+                  maximum: 32
+            - description: Signal bit used to stop Q6 user PD
+              items:
+                - description: Phandle to the Shared Memory Point 2 Point device
+                - description: Single bit index to toggle in the value sent to the remote processor
+                  maximum: 32
+            - description: Signal bit used to spawn Q6 user PD
+              items:
+                - description: Phandle to the Shared Memory Point 2 Point device
+                - description: Single bit index to toggle in the value sent to the remote processor
+                  maximum: 32
+        qcom,smem-state-names:
+          items:
+            - const: shutdown
+            - const: stop
+            - const: spawn
+      required:
+        - interrupts-extended
+        - interrupt-names
+        - qcom,smem-states
+        - qcom,smem-state-names
+
   - if:
       properties:
         compatible:
@@ -861,3 +949,55 @@ examples:
 
         qcom,rproc = <&q6v5_wcss>;
     };
+
+    wifi1: wifi@b00a040 {
+        reg = <0x0b00a040 0x0>;
+        compatible = "qcom,qcn6122-wifi";
+
+        interrupts-extended = <&intc GIC_SPI 416 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 417 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 418 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 419 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 420 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 421 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 422 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 423 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 424 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 425 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 426 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 427 IRQ_TYPE_EDGE_RISING>,
+                              <&intc GIC_SPI 428 IRQ_TYPE_EDGE_RISING>,
+                              <&wcss_smp2p_in 16 IRQ_TYPE_NONE>,
+                              <&wcss_smp2p_in 17 IRQ_TYPE_NONE>,
+                              <&wcss_smp2p_in 20 IRQ_TYPE_NONE>,
+                              <&wcss_smp2p_in 19 IRQ_TYPE_NONE>;
+        interrupt-names = "ce1",
+                          "ce2",
+                          "ce3",
+                          "ce4",
+                          "ce5",
+                          "dp1",
+                          "dp2",
+                          "dp3",
+                          "dp4",
+                          "dp5",
+                          "dp6",
+                          "dp7",
+                          "dp8",
+                          "fatal",
+                          "ready",
+                          "spawn",
+                          "stop-ack";
+
+        qcom,smem-states = <&wcss_smp2p_out 16>,
+                           <&wcss_smp2p_out 17>,
+                           <&wcss_smp2p_out 18>;
+        qcom,smem-state-names = "shutdown",
+                                "stop",
+                                "spawn";
+
+        memory-region = <&q6_region_qcn6122_1>, <&q6_region_ipq5018>, <&m3_dump_qcn6122_1>;
+        memory-region-names = "q6-region", "m3-region", "m3-dump";
+
+        status = "disabled";
+    };

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 11/16] wifi: ath11k: add hw params for QCN6122
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (9 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 10/16] dt-bindings: net: wireless: ath11k: Add bindings for QCN6122 George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 12/16] wifi: ath11k: add hal regs " George Moussalem via B4 Relay
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add QCN6122 platform support.

QCN6122 is a PCIe based solution that is attached to and enumerated
by the WPSS (Wireless Processor SubSystem) Q6 processor.

Though it is a PCIe device, since it is not attached to APSS processor,
APSS will be unaware of such a decice and hence it is registered to the
APSS processor as a platform AHB device.

As such, QCN6122 is a hybrid bus type device and follows the same
codepath as for WCN6750.

This is a heavily simplified version of below downstream patch:
Link: https://git.codelinaro.org/clo/qsdk/oss/system/feeds/wlan-open/-/blob/NHSS.QSDK.12.4.5.r2/mac80211/patches/232-ath11k-qcn6122-support.patch

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/core.c | 85 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/core.h |  1 +
 drivers/net/wireless/ath/ath11k/qmi.h  |  3 +-
 3 files changed, 88 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 428f382e74a9..0a38db1ee175 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -936,6 +936,91 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.cfr_num_stream_bufs = 255,
 		.cfr_stream_buf_size = 8200,
 	},
+	{
+		.hw_rev = ATH11K_HW_QCN6122_HW10,
+		.name = "qcn6122 hw1.0",
+		.fw = {
+			.dir = "QCN6122/hw1.0",
+			.board_size = 256 * 1024,
+			.cal_offset = 128 * 1024,
+			.m3_loader = ath11k_m3_fw_loader_ahb,
+		},
+		.max_radios = MAX_RADIOS_5018,
+		.bdf_addr = 0x4D200000,
+		.hw_ops = &ipq5018_ops,
+		.internal_sleep_clock = false,
+		.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122,
+		.host_ce_config = ath11k_host_ce_config_qcn9074,
+		.ce_count = CE_CNT_5018,
+		.target_ce_config = ath11k_target_ce_config_wlan_ipq5018,
+		.target_ce_count = TARGET_CE_CNT_5018,
+		.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq5018,
+		.svc_to_ce_map_len = SVC_CE_MAP_LEN_5018,
+		.single_pdev_only = false,
+		.rxdma1_enable = true,
+		.num_rxdma_per_pdev = RXDMA_PER_PDEV_5018,
+		.rx_mac_buf_ring = false,
+		.vdev_start_delay = false,
+		.htt_peer_map_v2 = true,
+
+		.spectral = {
+			.fft_sz = 2,
+			.fft_pad_sz = 0,
+			.summary_pad_sz = 16,
+			.fft_hdr_len = 24,
+			.max_fft_bins = 1024,
+			.fragment_160mhz = false,
+		},
+
+		.interface_modes = BIT(NL80211_IFTYPE_STATION) |
+					BIT(NL80211_IFTYPE_AP) |
+					BIT(NL80211_IFTYPE_MESH_POINT),
+		.supports_monitor = true,
+		.full_monitor_mode = false,
+		.supports_shadow_regs = false,
+		.idle_ps = false,
+		.supports_sta_ps = false,
+		.coldboot_cal_mm = false,
+		.coldboot_cal_ftm = false,
+		.cbcal_restart_fw = true,
+		.fw_mem_mode = 1,
+		.num_vdevs = 16 + 1,
+		.num_peers = 512,
+		.supports_suspend = false,
+		.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
+		.supports_regdb = false,
+		.fix_l1ss = true,
+		.credit_flow = false,
+		.hal_params = &ath11k_hw_hal_params_ipq5018,
+		.supports_dynamic_smps_6ghz = false,
+		.alloc_cacheable_memory = false,
+		.supports_rssi_stats = false,
+		.fw_wmi_diag_event = false,
+		.current_cc_support = false,
+		.dbr_debug_support = true,
+		.global_reset = false,
+		.bios_sar_capa = NULL,
+		.m3_fw_support = true,
+		.fixed_bdf_addr = true,
+		.fixed_mem_region = true,
+		.static_window_map = true,
+		.hybrid_bus_type = true,
+		.fixed_fw_mem = false,
+		.support_off_channel_tx = false,
+		.supports_multi_bssid = false,
+
+		.sram_dump = {},
+
+		.tcl_ring_retry = true,
+		.tx_ring_size = DP_TCL_DATA_RING_SIZE,
+		.smp2p_wow_exit = false,
+		.support_fw_mac_sequence = false,
+		.support_dual_stations = false,
+		.pdev_suspend = false,
+		.cfr_support = false,
+		.cfr_num_stream_bufs = 0,
+		.cfr_stream_buf_size = 0,
+	},
 };
 
 static const struct dmi_system_id ath11k_pm_quirk_table[] = {
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index a0d725923ef2..e92ec95dd384 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -153,6 +153,7 @@ enum ath11k_hw_rev {
 	ATH11K_HW_IPQ5018_HW10,
 	ATH11K_HW_QCA2066_HW21,
 	ATH11K_HW_QCA6698AQ_HW21,
+	ATH11K_HW_QCN6122_HW10,
 };
 
 enum ath11k_firmware_mode {
diff --git a/drivers/net/wireless/ath/ath11k/qmi.h b/drivers/net/wireless/ath/ath11k/qmi.h
index 350816c81ee5..f5442a04f079 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.h
+++ b/drivers/net/wireless/ath/ath11k/qmi.h
@@ -21,10 +21,11 @@
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074	0x02
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9074	0x07
 #define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_WCN6750	0x03
+#define ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122	0x40
 #define ATH11K_QMI_WLANFW_MAX_TIMESTAMP_LEN_V01	32
 #define ATH11K_QMI_RESP_LEN_MAX			8192
 #define ATH11K_QMI_WLANFW_MAX_NUM_MEM_SEG_V01	52
-#define ATH11K_QMI_CALDB_SIZE			0x480000
+#define ATH11K_QMI_CALDB_SIZE			0x500000
 #define ATH11K_QMI_BDF_EXT_STR_LENGTH		0x20
 #define ATH11K_QMI_FW_MEM_REQ_SEGMENT_CNT	5
 

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 12/16] wifi: ath11k: add hal regs for QCN6122
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (10 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 11/16] wifi: ath11k: add hw params " George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 13/16] wifi: ath11k: add hw ring mask " George Moussalem via B4 Relay
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add HAL changes required to support QCN6122. While offsets for QCN6122
are similar to those of WCN6750, QCN6122 does not support shadow regs
and the PCIE PCS/Serdes tuning register offsets do not apply to QCN6122.
So add its own HAL register offsets.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/core.c |  1 +
 drivers/net/wireless/ath/ath11k/hw.c   | 75 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/hw.h   |  1 +
 3 files changed, 77 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index 0a38db1ee175..cf37975fa4cf 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -949,6 +949,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.bdf_addr = 0x4D200000,
 		.hw_ops = &ipq5018_ops,
 		.internal_sleep_clock = false,
+		.regs = &qcn6122_regs,
 		.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122,
 		.host_ce_config = ath11k_host_ce_config_qcn9074,
 		.ce_count = CE_CNT_5018,
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index 93f9a03c48dc..8442fbeb9c58 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -2836,6 +2836,81 @@ const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq5018 = {
 	.num_tx_rings = ARRAY_SIZE(ath11k_hw_tcl2wbm_rbm_map_ipq5018),
 };
 
+const struct ath11k_hw_regs qcn6122_regs = {
+	/* SW2TCL(x) R0 ring configuration address */
+	.hal_tcl1_ring_base_lsb = 0x00000694,
+	.hal_tcl1_ring_base_msb = 0x00000698,
+	.hal_tcl1_ring_id = 0x0000069c,
+	.hal_tcl1_ring_misc = 0x000006a4,
+	.hal_tcl1_ring_tp_addr_lsb = 0x000006b0,
+	.hal_tcl1_ring_tp_addr_msb = 0x000006b4,
+	.hal_tcl1_ring_consumer_int_setup_ix0 = 0x000006c4,
+	.hal_tcl1_ring_consumer_int_setup_ix1 = 0x000006c8,
+	.hal_tcl1_ring_msi1_base_lsb = 0x000006dc,
+	.hal_tcl1_ring_msi1_base_msb = 0x000006e0,
+	.hal_tcl1_ring_msi1_data = 0x000006e4,
+	.hal_tcl2_ring_base_lsb = 0x000006ec,
+	.hal_tcl_ring_base_lsb = 0x0000079c,
+
+	/* TCL STATUS ring address */
+	.hal_tcl_status_ring_base_lsb = 0x000008a4,
+
+	/* REO2SW(x) R0 ring configuration address */
+	.hal_reo1_ring_base_lsb = 0x000001ec,
+	.hal_reo1_ring_base_msb = 0x000001f0,
+	.hal_reo1_ring_id = 0x000001f4,
+	.hal_reo1_ring_misc = 0x000001fc,
+	.hal_reo1_ring_hp_addr_lsb = 0x00000200,
+	.hal_reo1_ring_hp_addr_msb = 0x00000204,
+	.hal_reo1_ring_producer_int_setup = 0x00000210,
+	.hal_reo1_ring_msi1_base_lsb = 0x00000234,
+	.hal_reo1_ring_msi1_base_msb = 0x00000238,
+	.hal_reo1_ring_msi1_data = 0x0000023c,
+	.hal_reo2_ring_base_lsb = 0x00000244,
+	.hal_reo1_aging_thresh_ix_0 = 0x00000564,
+	.hal_reo1_aging_thresh_ix_1 = 0x00000568,
+	.hal_reo1_aging_thresh_ix_2 = 0x0000056c,
+	.hal_reo1_aging_thresh_ix_3 = 0x00000570,
+
+	/* REO2SW(x) R2 ring pointers (head/tail) address */
+	.hal_reo1_ring_hp = 0x00003028,
+	.hal_reo1_ring_tp = 0x0000302c,
+	.hal_reo2_ring_hp = 0x00003030,
+
+	/* REO2TCL R0 ring configuration address */
+	.hal_reo_tcl_ring_base_lsb = 0x000003fc,
+	.hal_reo_tcl_ring_hp = 0x00003058,
+
+	/* SW2REO ring address */
+	.hal_sw2reo_ring_base_lsb = 0x0000013c,
+	.hal_sw2reo_ring_hp = 0x00003018,
+
+	/* REO CMD ring address */
+	.hal_reo_cmd_ring_base_lsb = 0x000000e4,
+	.hal_reo_cmd_ring_hp = 0x00003010,
+
+	/* REO status address */
+	.hal_reo_status_ring_base_lsb = 0x00000504,
+	.hal_reo_status_hp = 0x00003070,
+
+	/* WCSS relative address */
+	.hal_seq_wcss_umac_ce0_src_reg = 0x01b80000,
+	.hal_seq_wcss_umac_ce0_dst_reg = 0x01b81000,
+	.hal_seq_wcss_umac_ce1_src_reg = 0x01b82000,
+	.hal_seq_wcss_umac_ce1_dst_reg = 0x01b83000,
+
+	/* WBM Idle address */
+	.hal_wbm_idle_link_ring_base_lsb = 0x00000874,
+	.hal_wbm_idle_link_ring_misc = 0x00000884,
+
+	/* SW2WBM release address */
+	.hal_wbm_release_ring_base_lsb = 0x000001ec,
+
+	/* WBM2SW release address */
+	.hal_wbm0_release_ring_base_lsb = 0x00000924,
+	.hal_wbm1_release_ring_base_lsb = 0x0000097c,
+};
+
 const struct ath11k_hw_hal_params ath11k_hw_hal_params_ipq8074 = {
 	.rx_buf_rbm = HAL_RX_BUF_RBM_SW3_BM,
 	.tcl2wbm_rbm_map = ath11k_hw_tcl2wbm_rbm_map_ipq8074,
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index 5a1100ceb895..d9646a491808 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -433,6 +433,7 @@ extern const struct ath11k_hw_regs qcn9074_regs;
 extern const struct ath11k_hw_regs wcn6855_regs;
 extern const struct ath11k_hw_regs wcn6750_regs;
 extern const struct ath11k_hw_regs ipq5018_regs;
+extern const struct ath11k_hw_regs qcn6122_regs;
 
 static inline const char *ath11k_bd_ie_type_str(enum ath11k_bd_ie_type type)
 {

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 13/16] wifi: ath11k: add hw ring mask for QCN6122
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (11 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 12/16] wifi: ath11k: add hal regs " George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 14/16] wifi: ath11k: update hif and pci ops " George Moussalem via B4 Relay
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add ring mask for QCN6122 and register them in hw params.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/core.c |  1 +
 drivers/net/wireless/ath/ath11k/hw.c   | 37 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/hw.h   |  1 +
 3 files changed, 39 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index cf37975fa4cf..8fa1171b6bdd 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -948,6 +948,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
 		.max_radios = MAX_RADIOS_5018,
 		.bdf_addr = 0x4D200000,
 		.hw_ops = &ipq5018_ops,
+		.ring_mask = &ath11k_hw_ring_mask_qcn6122,
 		.internal_sleep_clock = false,
 		.regs = &qcn6122_regs,
 		.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN6122,
diff --git a/drivers/net/wireless/ath/ath11k/hw.c b/drivers/net/wireless/ath/ath11k/hw.c
index 8442fbeb9c58..bb375efd50fe 100644
--- a/drivers/net/wireless/ath/ath11k/hw.c
+++ b/drivers/net/wireless/ath/ath11k/hw.c
@@ -2070,6 +2070,43 @@ const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_wcn6750 = {
 	},
 };
 
+const struct ath11k_hw_ring_mask ath11k_hw_ring_mask_qcn6122 = {
+	.tx  = {
+		ATH11K_TX_RING_MASK_0,
+		ATH11K_TX_RING_MASK_1,
+		ATH11K_TX_RING_MASK_2,
+	},
+	.rx_mon_status = {
+		0, 0, 0,
+		ATH11K_RX_MON_STATUS_RING_MASK_0,
+	},
+	.rx = {
+		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, 0, 0, 0, 0, 0, 0, 0,
+		ATH11K_RX_ERR_RING_MASK_0,
+	},
+	.rx_wbm_rel = {
+		0, 0, 0, 0, 0, 0, 0, 0, 0,
+		ATH11K_RX_WBM_REL_RING_MASK_0,
+	},
+	.reo_status = {
+		0, 0, 0,
+		ATH11K_REO_STATUS_RING_MASK_0,
+	},
+	.rxdma2host = {
+		ATH11K_RXDMA2HOST_RING_MASK_0,
+	},
+	.host2rxdma = {
+		ATH11K_HOST2RXDMA_RING_MASK_0,
+	},
+};
+
 /* Target firmware's Copy Engine configuration for IPQ5018 */
 const struct ce_pipe_config ath11k_target_ce_config_wlan_ipq5018[] = {
 	/* CE0: host->target HTC control and raw streams */
diff --git a/drivers/net/wireless/ath/ath11k/hw.h b/drivers/net/wireless/ath/ath11k/hw.h
index d9646a491808..2bcfdae9519b 100644
--- a/drivers/net/wireless/ath/ath11k/hw.h
+++ b/drivers/net/wireless/ath/ath11k/hw.h
@@ -296,6 +296,7 @@ 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_ring_mask ath11k_hw_ring_mask_qcn6122;
 
 extern const struct ce_ie_addr ath11k_ce_ie_addr_ipq8074;
 extern const struct ce_ie_addr ath11k_ce_ie_addr_ipq5018;

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 14/16] wifi: ath11k: update hif and pci ops for QCN6122
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (12 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 13/16] wifi: ath11k: add hw ring mask " George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 15/16] wifi: ath11k: define userPDs " George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 16/16] wifi: ath11k: add QCN6122 device support George Moussalem via B4 Relay
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

Add HIF and PCI ops for QCN6122. QCN6122 by default uses DP window 3.
However, this is configurable, so let's introduce a function to do that and
follow the existing register access code for (hybrid)AHB devices and use
DP window 1.

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c | 34 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath11k/hif.h |  9 +++++++++
 drivers/net/wireless/ath/ath11k/qmi.c |  2 ++
 3 files changed, 45 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 1b9115311bed..03936f574c8d 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -892,6 +892,18 @@ static int ath11k_ahb_hif_resume(struct ath11k_base *ab)
 	return 0;
 }
 
+static void ath11k_ahb_config_static_window_qcn6122(struct ath11k_base *ab)
+{
+	u32 umac_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_SEQ_WCSS_UMAC_OFFSET);
+	u32 ce_window = FIELD_GET(ATH11K_PCI_WINDOW_VALUE_MASK, HAL_CE_WFSS_CE_REG_BASE);
+	u32 window;
+
+	window = (umac_window) | (ce_window << 6);
+
+	iowrite32(ATH11K_PCI_WINDOW_ENABLE_BIT | window,
+		  ab->mem + ATH11K_PCI_WINDOW_REG_ADDRESS);
+}
+
 static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
 	.start = ath11k_ahb_start,
 	.stop = ath11k_ahb_stop,
@@ -907,6 +919,24 @@ static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {
 	.ce_irq_disable = ath11k_ahb_ce_irq_disable_sync,
 };
 
+static const struct ath11k_hif_ops ath11k_ahb_hif_ops_qcn6122 = {
+	.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,
+	.ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq,
+	.ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,
+	.config_static_window = ath11k_ahb_config_static_window_qcn6122,
+};
+
 static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {
 	.start = ath11k_pcic_start,
 	.stop = ath11k_pcic_stop,
@@ -1638,6 +1668,10 @@ static int ath11k_ahb_probe(struct platform_device *pdev)
 		hif_ops = &ath11k_ahb_hif_ops_wcn6750;
 		pci_ops = &ath11k_ahb_pci_ops_wcn6750;
 		break;
+	case ATH11K_HW_QCN6122_HW10:
+		hif_ops = &ath11k_ahb_hif_ops_qcn6122;
+		pci_ops = &ath11k_ahb_pci_ops_wcn6750;
+		break;
 	default:
 		dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev);
 		return -EOPNOTSUPP;
diff --git a/drivers/net/wireless/ath/ath11k/hif.h b/drivers/net/wireless/ath/ath11k/hif.h
index 017fed1b4bd1..2e1a4fedf139 100644
--- a/drivers/net/wireless/ath/ath11k/hif.h
+++ b/drivers/net/wireless/ath/ath11k/hif.h
@@ -32,6 +32,7 @@ struct ath11k_hif_ops {
 	void (*ce_irq_disable)(struct ath11k_base *ab);
 	void (*get_ce_msi_idx)(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx);
 	void (*coredump_download)(struct ath11k_base *ab);
+	void (*config_static_window)(struct ath11k_base *ab);
 };
 
 static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab)
@@ -159,4 +160,12 @@ static inline void ath11k_hif_coredump_download(struct ath11k_base *ab)
 		ab->hif.ops->coredump_download(ab);
 }
 
+static inline void ath11k_hif_config_static_window(struct ath11k_base *ab)
+{
+	if (!ab->hw_params.static_window_map || !ab->hif.ops->config_static_window)
+		return;
+
+	ab->hif.ops->config_static_window(ab);
+}
+
 #endif /* _HIF_H_ */
diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
index 771ef9b5304f..7d77f5c8c609 100644
--- a/drivers/net/wireless/ath/ath11k/qmi.c
+++ b/drivers/net/wireless/ath/ath11k/qmi.c
@@ -2243,6 +2243,8 @@ static int ath11k_qmi_request_device_info(struct ath11k_base *ab)
 	if (!ab->hw_params.ce_remap)
 		ab->mem_ce = ab->mem;
 
+	ath11k_hif_config_static_window(ab);
+
 	return 0;
 out:
 	return ret;

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 15/16] wifi: ath11k: define userPDs for QCN6122
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (13 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 14/16] wifi: ath11k: update hif and pci ops " George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  2026-09-23 12:05 ` [PATCH ath-next 16/16] wifi: ath11k: add QCN6122 device support George Moussalem via B4 Relay
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

The IPQ5018 platform can come with one or two optional QCN6122 wifi
cards. To differentiate the two, the user PD instance number (1 or 2) is
added to the QMI service instance ID so the QCN6122 firmware knows which
radio instance to use and on what PCIe rail it is on.

On IPQ5018/QCN6122 boards, the default mapping is as follows:

          +-> User PD 1 ----> IPQ5018 Internal 2.4G Radio
         /
        /
Root PD +---> User PD 2 ----> QCN6122 5G/6G Radio on PCIe rail 1
        \
         \
          +-> User PD 3 ----> QCN6122 5G/6G Radio on PCIe rail 0

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c | 8 ++++++++
 drivers/net/wireless/ath/ath11k/ahb.h | 2 ++
 2 files changed, 10 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 03936f574c8d..26110c927577 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -969,6 +969,14 @@ static int ath11k_ahb_init_userpd(struct ath11k_base *ab, int userpd_id)
 
 		ab_ahb->userpd_id = userpd_id;
 		break;
+	case ATH11K_HW_QCN6122_HW10:
+		if (userpd_id != ATH11K_AHB_USERPD_ID_2 &&
+		    userpd_id != ATH11K_AHB_USERPD_ID_3)
+			return -EINVAL;
+
+		ab_ahb->userpd_id = userpd_id;
+		ab->qmi.service_ins_id += (ab_ahb->userpd_id - 1);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/drivers/net/wireless/ath/ath11k/ahb.h b/drivers/net/wireless/ath/ath11k/ahb.h
index 0647bdb9ea62..ec89e0e89ca0 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.h
+++ b/drivers/net/wireless/ath/ath11k/ahb.h
@@ -28,6 +28,8 @@
 
 enum ath11k_ahb_userpd_id {
 	ATH11K_AHB_USERPD_ID_1 = 1,
+	ATH11K_AHB_USERPD_ID_2,
+	ATH11K_AHB_USERPD_ID_3,
 	ATH11K_AHB_USERPD_ID_MAX,
 };
 

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH ath-next 16/16] wifi: ath11k: add QCN6122 device support
  2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
                   ` (14 preceding siblings ...)
  2026-09-23 12:05 ` [PATCH ath-next 15/16] wifi: ath11k: define userPDs " George Moussalem via B4 Relay
@ 2026-09-23 12:05 ` George Moussalem via B4 Relay
  15 siblings, 0 replies; 20+ messages in thread
From: George Moussalem via B4 Relay @ 2026-09-23 12:05 UTC (permalink / raw)
  To: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio
  Cc: linux-wireless, devicetree, ath11k, linux-kernel,
	Vignesh Viswanathan, Varadarajan Narayanan, linux-arm-msm,
	George Moussalem

From: George Moussalem <george.moussalem@outlook.com>

QCN6122 is a 2x2 11AX PCIe based chipset, but it is attached to the WPSS
(Wireless Processor SubSystem) Q6 processor, hence it is enumerated
by the Q6 processor. It is registered to the APSS processor as a
platform device (AHB).

Q6 firmware segments for QCN6122 are contained within the multi-PD
version of the shared firmware package for IPQ5018. Each (up to 2)
QCN6122 radio present runs in its own user PD which the ath11k driver
manages to power it up or down.

Also, device information like BAR and its size is not known to the APSS
processor as the chip is enumerated by WPSS Q6. These details are
fetched over QMI.

The QCN6122 chip supports STA, AP, and MESH modes.

Tested on: Linksys MX2000 and GLiNET B3000 wireless access points for
prolonged duration tests spanning multiple days with multiple clients
connected with firmware WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1

Signed-off-by: George Moussalem <george.moussalem@outlook.com>
---
 drivers/net/wireless/ath/ath11k/ahb.c  | 7 +++++++
 drivers/net/wireless/ath/ath11k/pcic.c | 9 +++++++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c
index 26110c927577..51908e779b7c 100644
--- a/drivers/net/wireless/ath/ath11k/ahb.c
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
@@ -46,6 +46,9 @@ static const struct of_device_id ath11k_ahb_of_match[] = {
 	{ .compatible = "qcom,ipq5018-wifi",
 	  .data = (void *)ATH11K_HW_IPQ5018_HW10,
 	},
+	{ .compatible = "qcom,qcn6122-wifi",
+	  .data = (void *)ATH11K_HW_QCN6122_HW10,
+	},
 	{ }
 };
 
@@ -1395,6 +1398,10 @@ static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)
 	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 == -EINVAL)
+		ret = of_property_read_u32_index(ab->dev->of_node,
+						 "interrupts-extended", 2,
+						 &int_prop);
 	if (ret)
 		return ret;
 
diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c
index 2259adc3bbdc..cdcf3df26438 100644
--- a/drivers/net/wireless/ath/ath11k/pcic.c
+++ b/drivers/net/wireless/ath/ath11k/pcic.c
@@ -138,6 +138,15 @@ static const struct ath11k_msi_config ath11k_msi_config[] = {
 		},
 		.hw_rev = ATH11K_HW_QCA6698AQ_HW21,
 	},
+	{
+		.total_vectors = 13,
+		.total_users = 2,
+		.users = (struct ath11k_msi_user[]) {
+			{ .name = "CE", .num_vectors = 5, .base_vector = 0 },
+			{ .name = "DP", .num_vectors = 8, .base_vector = 5 },
+		},
+		.hw_rev = ATH11K_HW_QCN6122_HW10,
+	},
 };
 
 int ath11k_pcic_init_msi_config(struct ath11k_base *ab)

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH ath-next 02/16] dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018
  2026-09-23 12:05 ` [PATCH ath-next 02/16] dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018 George Moussalem via B4 Relay
@ 2026-09-28 10:45   ` Krzysztof Kozlowski
  2026-09-29 10:03     ` George Moussalem
  0 siblings, 1 reply; 20+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-28 10:45 UTC (permalink / raw)
  To: George Moussalem
  Cc: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio, linux-wireless,
	devicetree, ath11k, linux-kernel, Vignesh Viswanathan,
	Varadarajan Narayanan, linux-arm-msm

On Wed, Sep 23, 2026 at 04:05:08PM +0400, George Moussalem wrote:
> Although support was added for IPQ5018, the bindings are missing, so
> let's add them.

So there is no ipq5018 compatible in existing file.

> 
> WiFi on IPQ5018 boards come in one of the following configurations:
> 1. IPQ5018 (standalone) + optional 5G/6G WiFi card (such as QCN9074)
> 2. IPQ5018 (MPD) + one or two 5G/6G QCN6122 WiFi chips where QCN6122
>    is an IPQ5018-specific companion chip.
> 
> IPQ5018 implements the multi-PD architecture as follows:
> 
>                      +-----------------------------+
>                      |     Q6 Remote Processor     |
>                      |            RootPD           |
>                      +--------------+--------------+
>                                     |
>                                     |
>                                     |
>               +---------------------+---------------------+
>               |                     |                     |
>         +-----v-----+         +-----v-----+         +-----v-----+
>         |  UserPD1  |         |  UserPD2  |         |  UserPD3  |
>         |  IPQ5018  |         | QCN6122 #1|         | QCN6122 #2|
>         |  (Radio)  |         |  (Radio)  |         |  (Radio)  |
>         +-----------+         +-----------+         +-----------+
> 
> The rootPD is responsible for managing the lifecycle of the UserPD and
> shared resources and providing SSR notifiers. There are different
> firmware blobs that include either the rootPD and userPD binaries for
> IPQ5018-only which auto-spawns the userPD for IPQ5018 WiFi, or for
> IPQ5018 and QCN6122 for which the userPDs for each radio must be spawned
> by the ath11k driver.
> 
> SMP2P is used for signaling between the host and the Q6 remote processor
> to manage the lifecycle of the userPDs, so add the required interrupts
> and smem-states for incoming and outgoing interrupts in the case of the
> IPQ5018 + QCN6122 MPD configuration. Otherwise, the SMP2P interrupts and
> smem-states are not required for the IPQ5018-only configuration.
> 
> In addition, document the memory regions needed for loading the BDF and
> M3 firmware as well as for assigning the M3 dump memory block.
> 
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---
>  .../bindings/net/wireless/qcom,ath11k.yaml         | 423 ++++++++++++++++++++-
>  1 file changed, 410 insertions(+), 13 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
> index a846cd704b19..621ad6d4ddad 100644
> --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
> +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml

Where is the compatible update?

> @@ -29,8 +29,13 @@ properties:
>      minItems: 32
>      maxItems: 52

56

>  
> +  interrupts-extended:

git grep should tell you - it's not needed. Drop.

> +    minItems: 56
> +    maxItems: 56
> +
>    interrupt-names:
> -    maxItems: 52
> +    minItems: 32
> +    maxItems: 56
>  
>    qcom,rproc:
>      $ref: /schemas/types.yaml#/definitions/phandle
> @@ -56,11 +61,15 @@ properties:
>  
>    memory-region:
>      minItems: 1
> -    maxItems: 2
> +    maxItems: 3
>      description:
>        phandle to a node describing reserved memory (System RAM memory)
>        used by ath11k firmware (see bindings/reserved-memory/reserved-memory.txt)
>  
> +  memory-region-names:
> +    minItems: 1
> +    maxItems: 3

Names would have to be here. But why do you need it in the first place?

> +
>    iommus:
>      minItems: 1
>      maxItems: 2
> @@ -78,20 +87,11 @@ properties:
>    qcom,smem-states:
>      $ref: /schemas/types.yaml#/definitions/phandle-array
>      description: State bits used by the AP to signal the WLAN Q6.
> -    items:
> -      - description: Signal bits used to enable/disable low power mode
> -          on WCN6750 in the case of WoW (Wake on Wireless).
> -        items:
> -          - description: Phandle to the Shared Memory Point 2 Point device
> -              handling the communication with a remote processor
> -          - description: Single bit index to toggle in the value sent to
> -              the remote processor
> -            maximum: 32
> +    minItems: 1
> +    maxItems: 3
>  
>    qcom,smem-state-names:
>      description: The names of the state bits used for SMP2P output.
> -    items:
> -      - const: wlan-smp2p-out

Why isn't all this in qcom,ipq5332-wifi.yaml?

>  
>  required:
>    - compatible
> @@ -103,6 +103,242 @@ additionalProperties: false
>  
>  allOf:
>    - $ref: ieee80211.yaml#
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - qcom,ipq5018-wifi
> +    then:
> +      properties:
> +        interrupts:
> +          items:
> +            - description: misc-pulse1 interrupt events
> +            - description: misc-latch interrupt events
> +            - description: sw exception interrupt events
> +            - description: watchdog interrupt events
> +            - description: interrupt event for ring CE0
> +            - description: interrupt event for ring CE1
> +            - description: interrupt event for ring CE2
> +            - description: interrupt event for ring CE3
> +            - description: interrupt event for ring CE4
> +            - description: interrupt event for ring CE5
> +            - description: interrupt event for ring CE6
> +            - description: interrupt event for ring CE7
> +            - description: interrupt event for ring CE8
> +            - description: interrupt event for ring CE9
> +            - description: interrupt event for ring CE10
> +            - description: interrupt event for ring CE11
> +            - description: interrupt event for ring host2wbm-desc-feed
> +            - description: interrupt event for ring host2reo-re-injection
> +            - description: interrupt event for ring host2reo-command
> +            - description: interrupt event for ring host2rxdma-monitor-ring3
> +            - description: interrupt event for ring host2rxdma-monitor-ring2
> +            - description: interrupt event for ring host2rxdma-monitor-ring1
> +            - description: interrupt event for ring reo2ost-exception
> +            - description: interrupt event for ring wbm2host-rx-release
> +            - description: interrupt event for ring reo2host-status
> +            - description: interrupt event for ring reo2host-destination-ring4
> +            - description: interrupt event for ring reo2host-destination-ring3
> +            - description: interrupt event for ring reo2host-destination-ring2
> +            - description: interrupt event for ring reo2host-destination-ring1
> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac3
> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac2
> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac1
> +            - description: interrupt event for ring ppdu-end-interrupts-mac3
> +            - description: interrupt event for ring ppdu-end-interrupts-mac2
> +            - description: interrupt event for ring ppdu-end-interrupts-mac1
> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac3
> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac2
> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac1
> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac3
> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac2
> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac1
> +            - description: interrupt event for ring rxdma2host-destination-ring-mac3
> +            - description: interrupt event for ring rxdma2host-destination-ring-mac2
> +            - description: interrupt event for ring rxdma2host-destination-ring-mac1
> +            - description: interrupt event for ring host2tcl-input-ring4
> +            - description: interrupt event for ring host2tcl-input-ring3
> +            - description: interrupt event for ring host2tcl-input-ring2
> +            - description: interrupt event for ring host2tcl-input-ring1
> +            - description: interrupt event for ring wbm2host-tx-completions-ring3
> +            - description: interrupt event for ring wbm2host-tx-completions-ring2
> +            - description: interrupt event for ring wbm2host-tx-completions-ring1
> +            - description: interrupt event for ring tcl2host-status-ring
> +        interrupts-extended:
> +          items:
> +            - description: misc-pulse1 interrupt events
> +            - description: misc-latch interrupt events
> +            - description: sw exception interrupt events
> +            - description: watchdog interrupt events
> +            - description: interrupt event for ring CE0
> +            - description: interrupt event for ring CE1
> +            - description: interrupt event for ring CE2
> +            - description: interrupt event for ring CE3
> +            - description: interrupt event for ring CE4
> +            - description: interrupt event for ring CE5
> +            - description: interrupt event for ring CE6
> +            - description: interrupt event for ring CE7
> +            - description: interrupt event for ring CE8
> +            - description: interrupt event for ring CE9
> +            - description: interrupt event for ring CE10
> +            - description: interrupt event for ring CE11
> +            - description: interrupt event for ring host2wbm-desc-feed
> +            - description: interrupt event for ring host2reo-re-injection
> +            - description: interrupt event for ring host2reo-command
> +            - description: interrupt event for ring host2rxdma-monitor-ring3
> +            - description: interrupt event for ring host2rxdma-monitor-ring2
> +            - description: interrupt event for ring host2rxdma-monitor-ring1
> +            - description: interrupt event for ring reo2ost-exception
> +            - description: interrupt event for ring wbm2host-rx-release
> +            - description: interrupt event for ring reo2host-status
> +            - description: interrupt event for ring reo2host-destination-ring4
> +            - description: interrupt event for ring reo2host-destination-ring3
> +            - description: interrupt event for ring reo2host-destination-ring2
> +            - description: interrupt event for ring reo2host-destination-ring1
> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac3
> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac2
> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac1
> +            - description: interrupt event for ring ppdu-end-interrupts-mac3
> +            - description: interrupt event for ring ppdu-end-interrupts-mac2
> +            - description: interrupt event for ring ppdu-end-interrupts-mac1
> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac3
> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac2
> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac1
> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac3
> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac2
> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac1
> +            - description: interrupt event for ring rxdma2host-destination-ring-mac3
> +            - description: interrupt event for ring rxdma2host-destination-ring-mac2
> +            - description: interrupt event for ring rxdma2host-destination-ring-mac1
> +            - description: interrupt event for ring host2tcl-input-ring4
> +            - description: interrupt event for ring host2tcl-input-ring3
> +            - description: interrupt event for ring host2tcl-input-ring2
> +            - description: interrupt event for ring host2tcl-input-ring1
> +            - description: interrupt event for ring wbm2host-tx-completions-ring3
> +            - description: interrupt event for ring wbm2host-tx-completions-ring2
> +            - description: interrupt event for ring wbm2host-tx-completions-ring1
> +            - description: interrupt event for ring tcl2host-status-ring
> +            - description: Q6 firmware user PD fatal interrupt event
> +            - description: Q6 firmware user PD ready interrupt event
> +            - description: Q6 firmware user PD spawn interrupt event
> +            - description: Q6 firmware user PD stop ack interrupt event
> +        interrupt-names:
> +          minItems: 52
> +          items:
> +            - const: misc-pulse1
> +            - const: misc-latch
> +            - const: sw-exception
> +            - const: watchdog
> +            - const: ce0
> +            - const: ce1
> +            - const: ce2
> +            - const: ce3
> +            - const: ce4
> +            - const: ce5
> +            - const: ce6
> +            - const: ce7
> +            - const: ce8
> +            - const: ce9
> +            - const: ce10
> +            - const: ce11
> +            - const: host2wbm-desc-feed
> +            - const: host2reo-re-injection
> +            - const: host2reo-command
> +            - const: host2rxdma-monitor-ring3
> +            - const: host2rxdma-monitor-ring2
> +            - const: host2rxdma-monitor-ring1
> +            - const: reo2ost-exception
> +            - const: wbm2host-rx-release
> +            - const: reo2host-status
> +            - const: reo2host-destination-ring4
> +            - const: reo2host-destination-ring3
> +            - const: reo2host-destination-ring2
> +            - const: reo2host-destination-ring1
> +            - const: rxdma2host-monitor-destination-mac3
> +            - const: rxdma2host-monitor-destination-mac2
> +            - const: rxdma2host-monitor-destination-mac1
> +            - const: ppdu-end-interrupts-mac3
> +            - const: ppdu-end-interrupts-mac2
> +            - const: ppdu-end-interrupts-mac1
> +            - const: rxdma2host-monitor-status-ring-mac3
> +            - const: rxdma2host-monitor-status-ring-mac2
> +            - const: rxdma2host-monitor-status-ring-mac1
> +            - const: host2rxdma-host-buf-ring-mac3
> +            - const: host2rxdma-host-buf-ring-mac2
> +            - const: host2rxdma-host-buf-ring-mac1
> +            - const: rxdma2host-destination-ring-mac3
> +            - const: rxdma2host-destination-ring-mac2
> +            - const: rxdma2host-destination-ring-mac1
> +            - const: host2tcl-input-ring4
> +            - const: host2tcl-input-ring3
> +            - const: host2tcl-input-ring2
> +            - const: host2tcl-input-ring1
> +            - const: wbm2host-tx-completions-ring3
> +            - const: wbm2host-tx-completions-ring2
> +            - const: wbm2host-tx-completions-ring1
> +            - const: tcl2host-status-ring
> +            - const: fatal
> +            - const: ready
> +            - const: spawn
> +            - const: stop-ack
> +        memory-region:
> +          items:
> +            - description: memory region for Q6 firmware
> +            - description: memory region for M3 firmware
> +            - description: memory region for M3 dump
> +        memory-region-names:
> +          items:
> +            - const: q6-region
> +            - const: m3-region
> +            - const: m3-dump
> +        qcom,smem-states:
> +          items:
> +            - description: Signal bit used to shutdown Q6 user PD
> +              items:
> +                - description: Phandle to the Shared Memory Point 2 Point device
> +                - description: Single bit index to toggle in the value sent to the remote processor
> +                  maximum: 32
> +            - description: Signal bit used to stop Q6 user PD
> +              items:
> +                - description: Phandle to the Shared Memory Point 2 Point device
> +                - description: Single bit index to toggle in the value sent to the remote processor
> +                  maximum: 32
> +            - description: Signal bit used to spawn Q6 user PD
> +              items:
> +                - description: Phandle to the Shared Memory Point 2 Point device
> +                - description: Single bit index to toggle in the value sent to the remote processor
> +                  maximum: 32
> +        qcom,smem-state-names:
> +          items:
> +            - const: shutdown
> +            - const: stop
> +            - const: spawn
> +      allOf:
> +        - anyOf:
> +            - required:
> +                - interrupts
> +            - required:
> +                - interrupts-extended
> +        - if:
> +            required:
> +              - interrupts-extended
> +          then:
> +            properties:
> +              interrupt-names:
> +                minItems: 56
> +            required:
> +              - interrupts-extended
> +              - memory-region
> +              - memory-region-names
> +              - qcom,smem-states
> +              - qcom,smem-state-names
> +          else:
> +            properties:
> +              interrupt-names:
> +                minItems: 52
> +                maxItems: 52
> +
>    - if:
>        properties:
>          compatible:
> @@ -265,6 +501,19 @@ allOf:
>              - description: interrupt event for ring DP20
>              - description: interrupt event for ring DP21
>              - description: interrupt event for ring DP22
> +        qcom,smem-states:
> +          items:
> +            - description: Signal bits used to enable/disable low power mode
> +                on WCN6750 in the case of WoW (Wake on Wireless).
> +              items:
> +                - description: Phandle to the Shared Memory Point 2 Point device
> +                    handling the communication with a remote processor
> +                - description: Single bit index to toggle in the value sent to
> +                    the remote processor
> +                  maximum: 32
> +        qcom,smem-state-names:
> +          items:
> +            - const: wlan-smp2p-out
>  
>  examples:
>    - |
> @@ -464,3 +713,151 @@ examples:
>              iommus = <&apps_smmu 0x1c02 0x1>;
>          };
>      };
> +
> +  - |

No, three examples are enough. No need for fourth.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH ath-next 01/16] dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically
  2026-09-23 12:05 ` [PATCH ath-next 01/16] dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically George Moussalem via B4 Relay
@ 2026-09-28 10:45   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 20+ messages in thread
From: Krzysztof Kozlowski @ 2026-09-28 10:45 UTC (permalink / raw)
  To: George Moussalem
  Cc: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio, linux-wireless,
	devicetree, ath11k, linux-kernel, Vignesh Viswanathan,
	Varadarajan Narayanan, linux-arm-msm

On Wed, Sep 23, 2026 at 04:05:07PM +0400, George Moussalem wrote:
> Sort the compatible names in the binding file alphabetically for
> legibility and correct ordering.
> 
> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
> ---

This could be fine, but your next patch suggests qcom,ipq5018-wifi
should be moved out of here.

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH ath-next 02/16] dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018
  2026-09-28 10:45   ` Krzysztof Kozlowski
@ 2026-09-29 10:03     ` George Moussalem
  0 siblings, 0 replies; 20+ messages in thread
From: George Moussalem @ 2026-09-29 10:03 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Johannes Berg, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jeff Johnson, Bjorn Andersson, Konrad Dybcio, linux-wireless,
	devicetree, ath11k, linux-kernel, Vignesh Viswanathan,
	Varadarajan Narayanan, linux-arm-msm

On 9/28/26 14:45, Krzysztof Kozlowski wrote:
> On Wed, Sep 23, 2026 at 04:05:08PM +0400, George Moussalem wrote:
>> Although support was added for IPQ5018, the bindings are missing, so
>> let's add them.
> 
> So there is no ipq5018 compatible in existing file.

The compatible is there, but it's not further specified. But as per your
suggestion, I'll move it entirely to qcom,ipq5332-wifi.yaml.>
>>
>> WiFi on IPQ5018 boards come in one of the following configurations:
>> 1. IPQ5018 (standalone) + optional 5G/6G WiFi card (such as QCN9074)
>> 2. IPQ5018 (MPD) + one or two 5G/6G QCN6122 WiFi chips where QCN6122
>>    is an IPQ5018-specific companion chip.
>>
>> IPQ5018 implements the multi-PD architecture as follows:
>>
>>                      +-----------------------------+
>>                      |     Q6 Remote Processor     |
>>                      |            RootPD           |
>>                      +--------------+--------------+
>>                                     |
>>                                     |
>>                                     |
>>               +---------------------+---------------------+
>>               |                     |                     |
>>         +-----v-----+         +-----v-----+         +-----v-----+
>>         |  UserPD1  |         |  UserPD2  |         |  UserPD3  |
>>         |  IPQ5018  |         | QCN6122 #1|         | QCN6122 #2|
>>         |  (Radio)  |         |  (Radio)  |         |  (Radio)  |
>>         +-----------+         +-----------+         +-----------+
>>
>> The rootPD is responsible for managing the lifecycle of the UserPD and
>> shared resources and providing SSR notifiers. There are different
>> firmware blobs that include either the rootPD and userPD binaries for
>> IPQ5018-only which auto-spawns the userPD for IPQ5018 WiFi, or for
>> IPQ5018 and QCN6122 for which the userPDs for each radio must be spawned
>> by the ath11k driver.
>>
>> SMP2P is used for signaling between the host and the Q6 remote processor
>> to manage the lifecycle of the userPDs, so add the required interrupts
>> and smem-states for incoming and outgoing interrupts in the case of the
>> IPQ5018 + QCN6122 MPD configuration. Otherwise, the SMP2P interrupts and
>> smem-states are not required for the IPQ5018-only configuration.
>>
>> In addition, document the memory regions needed for loading the BDF and
>> M3 firmware as well as for assigning the M3 dump memory block.
>>
>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>> ---
>>  .../bindings/net/wireless/qcom,ath11k.yaml         | 423 ++++++++++++++++++++-
>>  1 file changed, 410 insertions(+), 13 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
>> index a846cd704b19..621ad6d4ddad 100644
>> --- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
>> +++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
> 
> Where is the compatible update?
> 
>> @@ -29,8 +29,13 @@ properties:
>>      minItems: 32
>>      maxItems: 52
> 
> 56
> 
>>  
>> +  interrupts-extended:
> 
> git grep should tell you - it's not needed. Drop.

Noted, thanks!

> 
>> +    minItems: 56
>> +    maxItems: 56
>> +
>>    interrupt-names:
>> -    maxItems: 52
>> +    minItems: 32
>> +    maxItems: 56
>>  
>>    qcom,rproc:
>>      $ref: /schemas/types.yaml#/definitions/phandle
>> @@ -56,11 +61,15 @@ properties:
>>  
>>    memory-region:
>>      minItems: 1
>> -    maxItems: 2
>> +    maxItems: 3
>>      description:
>>        phandle to a node describing reserved memory (System RAM memory)
>>        used by ath11k firmware (see bindings/reserved-memory/reserved-memory.txt)
>>  
>> +  memory-region-names:
>> +    minItems: 1
>> +    maxItems: 3
> 
> Names would have to be here. But why do you need it in the first place?

It's for the ability to override the default hard-coded addresses
defined in the HW params. The memory address/region to load the BDF into
varies per architecture (regular non-MPD vs MPD). The current HW params
define the one for the regular architecture. As with IPQ5332, there's a
need to override that and assign the right memory regions for the BDF
and M3 dump.

Unlike IPQ5018 and IPQ5332, QCN6122 doesn't have its own m3-region to
load its M3 firmware maps to the one of IPQ5018. Hence, the need to
define the m3-region per board.

So for QCN6122, it would look like:
	memory-region = <&q6_region_qcn6122_1>,
			<&q6_region_ipq5018>,
			<&m3_dump_qcn6122_1>;
        memory-region-names = "q6-region",
			      "m3-region",
			      "m3-dump";

> 
>> +
>>    iommus:
>>      minItems: 1
>>      maxItems: 2
>> @@ -78,20 +87,11 @@ properties:
>>    qcom,smem-states:
>>      $ref: /schemas/types.yaml#/definitions/phandle-array
>>      description: State bits used by the AP to signal the WLAN Q6.
>> -    items:
>> -      - description: Signal bits used to enable/disable low power mode
>> -          on WCN6750 in the case of WoW (Wake on Wireless).
>> -        items:
>> -          - description: Phandle to the Shared Memory Point 2 Point device
>> -              handling the communication with a remote processor
>> -          - description: Single bit index to toggle in the value sent to
>> -              the remote processor
>> -            maximum: 32
>> +    minItems: 1
>> +    maxItems: 3
>>  
>>    qcom,smem-state-names:
>>      description: The names of the state bits used for SMP2P output.
>> -    items:
>> -      - const: wlan-smp2p-out
> 
> Why isn't all this in qcom,ipq5332-wifi.yaml?

Will move it there, thanks.

> 
>>  
>>  required:
>>    - compatible
>> @@ -103,6 +103,242 @@ additionalProperties: false
>>  
>>  allOf:
>>    - $ref: ieee80211.yaml#
>> +  - if:
>> +      properties:
>> +        compatible:
>> +          contains:
>> +            enum:
>> +              - qcom,ipq5018-wifi
>> +    then:
>> +      properties:
>> +        interrupts:
>> +          items:
>> +            - description: misc-pulse1 interrupt events
>> +            - description: misc-latch interrupt events
>> +            - description: sw exception interrupt events
>> +            - description: watchdog interrupt events
>> +            - description: interrupt event for ring CE0
>> +            - description: interrupt event for ring CE1
>> +            - description: interrupt event for ring CE2
>> +            - description: interrupt event for ring CE3
>> +            - description: interrupt event for ring CE4
>> +            - description: interrupt event for ring CE5
>> +            - description: interrupt event for ring CE6
>> +            - description: interrupt event for ring CE7
>> +            - description: interrupt event for ring CE8
>> +            - description: interrupt event for ring CE9
>> +            - description: interrupt event for ring CE10
>> +            - description: interrupt event for ring CE11
>> +            - description: interrupt event for ring host2wbm-desc-feed
>> +            - description: interrupt event for ring host2reo-re-injection
>> +            - description: interrupt event for ring host2reo-command
>> +            - description: interrupt event for ring host2rxdma-monitor-ring3
>> +            - description: interrupt event for ring host2rxdma-monitor-ring2
>> +            - description: interrupt event for ring host2rxdma-monitor-ring1
>> +            - description: interrupt event for ring reo2ost-exception
>> +            - description: interrupt event for ring wbm2host-rx-release
>> +            - description: interrupt event for ring reo2host-status
>> +            - description: interrupt event for ring reo2host-destination-ring4
>> +            - description: interrupt event for ring reo2host-destination-ring3
>> +            - description: interrupt event for ring reo2host-destination-ring2
>> +            - description: interrupt event for ring reo2host-destination-ring1
>> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac3
>> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac2
>> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac1
>> +            - description: interrupt event for ring ppdu-end-interrupts-mac3
>> +            - description: interrupt event for ring ppdu-end-interrupts-mac2
>> +            - description: interrupt event for ring ppdu-end-interrupts-mac1
>> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac3
>> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac2
>> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac1
>> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac3
>> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac2
>> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac1
>> +            - description: interrupt event for ring rxdma2host-destination-ring-mac3
>> +            - description: interrupt event for ring rxdma2host-destination-ring-mac2
>> +            - description: interrupt event for ring rxdma2host-destination-ring-mac1
>> +            - description: interrupt event for ring host2tcl-input-ring4
>> +            - description: interrupt event for ring host2tcl-input-ring3
>> +            - description: interrupt event for ring host2tcl-input-ring2
>> +            - description: interrupt event for ring host2tcl-input-ring1
>> +            - description: interrupt event for ring wbm2host-tx-completions-ring3
>> +            - description: interrupt event for ring wbm2host-tx-completions-ring2
>> +            - description: interrupt event for ring wbm2host-tx-completions-ring1
>> +            - description: interrupt event for ring tcl2host-status-ring
>> +        interrupts-extended:
>> +          items:
>> +            - description: misc-pulse1 interrupt events
>> +            - description: misc-latch interrupt events
>> +            - description: sw exception interrupt events
>> +            - description: watchdog interrupt events
>> +            - description: interrupt event for ring CE0
>> +            - description: interrupt event for ring CE1
>> +            - description: interrupt event for ring CE2
>> +            - description: interrupt event for ring CE3
>> +            - description: interrupt event for ring CE4
>> +            - description: interrupt event for ring CE5
>> +            - description: interrupt event for ring CE6
>> +            - description: interrupt event for ring CE7
>> +            - description: interrupt event for ring CE8
>> +            - description: interrupt event for ring CE9
>> +            - description: interrupt event for ring CE10
>> +            - description: interrupt event for ring CE11
>> +            - description: interrupt event for ring host2wbm-desc-feed
>> +            - description: interrupt event for ring host2reo-re-injection
>> +            - description: interrupt event for ring host2reo-command
>> +            - description: interrupt event for ring host2rxdma-monitor-ring3
>> +            - description: interrupt event for ring host2rxdma-monitor-ring2
>> +            - description: interrupt event for ring host2rxdma-monitor-ring1
>> +            - description: interrupt event for ring reo2ost-exception
>> +            - description: interrupt event for ring wbm2host-rx-release
>> +            - description: interrupt event for ring reo2host-status
>> +            - description: interrupt event for ring reo2host-destination-ring4
>> +            - description: interrupt event for ring reo2host-destination-ring3
>> +            - description: interrupt event for ring reo2host-destination-ring2
>> +            - description: interrupt event for ring reo2host-destination-ring1
>> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac3
>> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac2
>> +            - description: interrupt event for ring rxdma2host-monitor-destination-mac1
>> +            - description: interrupt event for ring ppdu-end-interrupts-mac3
>> +            - description: interrupt event for ring ppdu-end-interrupts-mac2
>> +            - description: interrupt event for ring ppdu-end-interrupts-mac1
>> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac3
>> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac2
>> +            - description: interrupt event for ring rxdma2host-monitor-status-ring-mac1
>> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac3
>> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac2
>> +            - description: interrupt event for ring host2rxdma-host-buf-ring-mac1
>> +            - description: interrupt event for ring rxdma2host-destination-ring-mac3
>> +            - description: interrupt event for ring rxdma2host-destination-ring-mac2
>> +            - description: interrupt event for ring rxdma2host-destination-ring-mac1
>> +            - description: interrupt event for ring host2tcl-input-ring4
>> +            - description: interrupt event for ring host2tcl-input-ring3
>> +            - description: interrupt event for ring host2tcl-input-ring2
>> +            - description: interrupt event for ring host2tcl-input-ring1
>> +            - description: interrupt event for ring wbm2host-tx-completions-ring3
>> +            - description: interrupt event for ring wbm2host-tx-completions-ring2
>> +            - description: interrupt event for ring wbm2host-tx-completions-ring1
>> +            - description: interrupt event for ring tcl2host-status-ring
>> +            - description: Q6 firmware user PD fatal interrupt event
>> +            - description: Q6 firmware user PD ready interrupt event
>> +            - description: Q6 firmware user PD spawn interrupt event
>> +            - description: Q6 firmware user PD stop ack interrupt event
>> +        interrupt-names:
>> +          minItems: 52
>> +          items:
>> +            - const: misc-pulse1
>> +            - const: misc-latch
>> +            - const: sw-exception
>> +            - const: watchdog
>> +            - const: ce0
>> +            - const: ce1
>> +            - const: ce2
>> +            - const: ce3
>> +            - const: ce4
>> +            - const: ce5
>> +            - const: ce6
>> +            - const: ce7
>> +            - const: ce8
>> +            - const: ce9
>> +            - const: ce10
>> +            - const: ce11
>> +            - const: host2wbm-desc-feed
>> +            - const: host2reo-re-injection
>> +            - const: host2reo-command
>> +            - const: host2rxdma-monitor-ring3
>> +            - const: host2rxdma-monitor-ring2
>> +            - const: host2rxdma-monitor-ring1
>> +            - const: reo2ost-exception
>> +            - const: wbm2host-rx-release
>> +            - const: reo2host-status
>> +            - const: reo2host-destination-ring4
>> +            - const: reo2host-destination-ring3
>> +            - const: reo2host-destination-ring2
>> +            - const: reo2host-destination-ring1
>> +            - const: rxdma2host-monitor-destination-mac3
>> +            - const: rxdma2host-monitor-destination-mac2
>> +            - const: rxdma2host-monitor-destination-mac1
>> +            - const: ppdu-end-interrupts-mac3
>> +            - const: ppdu-end-interrupts-mac2
>> +            - const: ppdu-end-interrupts-mac1
>> +            - const: rxdma2host-monitor-status-ring-mac3
>> +            - const: rxdma2host-monitor-status-ring-mac2
>> +            - const: rxdma2host-monitor-status-ring-mac1
>> +            - const: host2rxdma-host-buf-ring-mac3
>> +            - const: host2rxdma-host-buf-ring-mac2
>> +            - const: host2rxdma-host-buf-ring-mac1
>> +            - const: rxdma2host-destination-ring-mac3
>> +            - const: rxdma2host-destination-ring-mac2
>> +            - const: rxdma2host-destination-ring-mac1
>> +            - const: host2tcl-input-ring4
>> +            - const: host2tcl-input-ring3
>> +            - const: host2tcl-input-ring2
>> +            - const: host2tcl-input-ring1
>> +            - const: wbm2host-tx-completions-ring3
>> +            - const: wbm2host-tx-completions-ring2
>> +            - const: wbm2host-tx-completions-ring1
>> +            - const: tcl2host-status-ring
>> +            - const: fatal
>> +            - const: ready
>> +            - const: spawn
>> +            - const: stop-ack
>> +        memory-region:
>> +          items:
>> +            - description: memory region for Q6 firmware
>> +            - description: memory region for M3 firmware
>> +            - description: memory region for M3 dump
>> +        memory-region-names:
>> +          items:
>> +            - const: q6-region
>> +            - const: m3-region
>> +            - const: m3-dump
>> +        qcom,smem-states:
>> +          items:
>> +            - description: Signal bit used to shutdown Q6 user PD
>> +              items:
>> +                - description: Phandle to the Shared Memory Point 2 Point device
>> +                - description: Single bit index to toggle in the value sent to the remote processor
>> +                  maximum: 32
>> +            - description: Signal bit used to stop Q6 user PD
>> +              items:
>> +                - description: Phandle to the Shared Memory Point 2 Point device
>> +                - description: Single bit index to toggle in the value sent to the remote processor
>> +                  maximum: 32
>> +            - description: Signal bit used to spawn Q6 user PD
>> +              items:
>> +                - description: Phandle to the Shared Memory Point 2 Point device
>> +                - description: Single bit index to toggle in the value sent to the remote processor
>> +                  maximum: 32
>> +        qcom,smem-state-names:
>> +          items:
>> +            - const: shutdown
>> +            - const: stop
>> +            - const: spawn
>> +      allOf:
>> +        - anyOf:
>> +            - required:
>> +                - interrupts
>> +            - required:
>> +                - interrupts-extended
>> +        - if:
>> +            required:
>> +              - interrupts-extended
>> +          then:
>> +            properties:
>> +              interrupt-names:
>> +                minItems: 56
>> +            required:
>> +              - interrupts-extended
>> +              - memory-region
>> +              - memory-region-names
>> +              - qcom,smem-states
>> +              - qcom,smem-state-names
>> +          else:
>> +            properties:
>> +              interrupt-names:
>> +                minItems: 52
>> +                maxItems: 52
>> +
>>    - if:
>>        properties:
>>          compatible:
>> @@ -265,6 +501,19 @@ allOf:
>>              - description: interrupt event for ring DP20
>>              - description: interrupt event for ring DP21
>>              - description: interrupt event for ring DP22
>> +        qcom,smem-states:
>> +          items:
>> +            - description: Signal bits used to enable/disable low power mode
>> +                on WCN6750 in the case of WoW (Wake on Wireless).
>> +              items:
>> +                - description: Phandle to the Shared Memory Point 2 Point device
>> +                    handling the communication with a remote processor
>> +                - description: Single bit index to toggle in the value sent to
>> +                    the remote processor
>> +                  maximum: 32
>> +        qcom,smem-state-names:
>> +          items:
>> +            - const: wlan-smp2p-out
>>  
>>  examples:
>>    - |
>> @@ -464,3 +713,151 @@ examples:
>>              iommus = <&apps_smmu 0x1c02 0x1>;
>>          };
>>      };
>> +
>> +  - |
> 
> No, three examples are enough. No need for fourth.

Noted, will remove in next version.

> 
> Best regards,
> Krzysztof

Best regards,
George

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-09-29 10:03 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-23 12:05 [PATCH ath-next 00/16] wifi: ath11k: add MultiPD support for AHB platforms George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 01/16] dt-bindings: net: wireless: ath11k: Sort compatible names alphabetically George Moussalem via B4 Relay
2026-09-28 10:45   ` Krzysztof Kozlowski
2026-09-23 12:05 ` [PATCH ath-next 02/16] dt-bindings: net: wireless: ath11k: Add bindings for IPQ5018 George Moussalem via B4 Relay
2026-09-28 10:45   ` Krzysztof Kozlowski
2026-09-29 10:03     ` George Moussalem
2026-09-23 12:05 ` [PATCH ath-next 03/16] wifi: ath11k: Register root PD rproc notifier George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 04/16] wifi: ath11k: Add support for loading m3 mbn firmware George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 05/16] wifi: ath11k: Add ability to set BDF and M3 dump memory addresses George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 06/16] firmware: qcom: scm: Add support for setting internal WiFi power mode George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 07/16] wifi: ath11k: Register userPD interrupts and SMEM entries George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 08/16] wifi: ath11k: Power up userPD George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 09/16] wifi: ath11k: Power down userPD George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 10/16] dt-bindings: net: wireless: ath11k: Add bindings for QCN6122 George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 11/16] wifi: ath11k: add hw params " George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 12/16] wifi: ath11k: add hal regs " George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 13/16] wifi: ath11k: add hw ring mask " George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 14/16] wifi: ath11k: update hif and pci ops " George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 15/16] wifi: ath11k: define userPDs " George Moussalem via B4 Relay
2026-09-23 12:05 ` [PATCH ath-next 16/16] wifi: ath11k: add QCN6122 device support George Moussalem via B4 Relay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox