* [PATCH] wifi: rtw88: usb: fix memory leaks on USB write failures
From: luka.gejak @ 2026-05-01 16:20 UTC (permalink / raw)
To: Ping-Ke Shih, Kalle Valo
Cc: Stanislaw Gruszka, Yan-Hsuan Chuang, Brian Norris, linux-wireless,
linux-kernel, Luka Gejak, stable
From: Luka Gejak <luka.gejak@linux.dev>
When rtw_usb_write_port() fails to submit a USB Request Block (URB)
(e.g., due to device disconnect or ENOMEM), the completion callback is
never executed.
Currently, the driver ignores the return value of rtw_usb_write_port()
in rtw_usb_write_data() and rtw_usb_tx_agg_skb(). Because these
functions rely on the completion callback to free the socket buffers
(skbs) and the transaction control block (txcb), a submission failure
results in:
1. A memory leak of the allocated skb in rtw_usb_write_data().
2. A memory leak of the txcb structure and all aggregated skbs in
rtw_usb_tx_agg_skb().
Fix this by checking the return value of rtw_usb_write_port(). If it
fails, explicitly free the skb in rtw_usb_write_data(), and properly
purge the tx_ack_queue and free the txcb in rtw_usb_tx_agg_skb().
Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver")
Cc: stable@vger.kernel.org
Tested-by: Luka Gejak <luka.gejak@linux.dev>
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
drivers/net/wireless/realtek/rtw88/usb.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index 718940ebba31..d430645a3ef3 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -456,7 +456,13 @@ static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list
tx_desc = (struct rtw_tx_desc *)skb_head->data;
qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL);
- rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb);
+ if (rtw_usb_write_port(rtwdev, qsel, skb_head,
+ rtw_usb_write_port_tx_complete, txcb)) {
+ /* URB submission failed, completion won't run, free the queue */
+ skb_queue_purge(&txcb->tx_ack_queue);
+ kfree(txcb);
+ return false;
+ }
return true;
}
@@ -518,8 +524,10 @@ static int rtw_usb_write_data(struct rtw_dev *rtwdev,
ret = rtw_usb_write_port(rtwdev, qsel, skb,
rtw_usb_write_port_complete, skb);
- if (unlikely(ret))
+ if (unlikely(ret)) {
rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret);
+ dev_kfree_skb_any(skb);
+ }
return ret;
}
--
2.54.0
^ permalink raw reply related
* [PATCH] wireless-regdb: Update regulatory info for Brunei Darussalam (BN) for 2022
From: hfzz7 @ 2026-05-01 16:06 UTC (permalink / raw)
To: linux-wireless; +Cc: wireless-regdb, Hafiz Zafran
In 2022, Authority for Info-communications Technology Industry of Brunei Darussalam (AITI) updates The Brunei Darussalam Radio Spectrum Plan. [1]
* 2400-2483.5 MHz
- 200 mW
* 5150-5350 MHz
- 1000 mW
(For 5250-5.350 MHz, DFS and TPC are required)
* 5470-5725 MHz
- 1000 mW
- DFS
- TPC
* 5725-5850 MHz
- 4000 mW
Also, add regulatory info for WiGig/60 GHz
* 57000-66000 MHz
- 10 W / 10000 mW
Note: According to the Telecommunications (Radio-communication) Regulations, 2013 of the Telecommunications Order, 2001 (S 38/2001), "non-localised use" refers to the operations of specified radio-communication equipment or network at a specific frequency or in any specified frequency within the whole of Brunei Darussalam. [2]
[1] https://aiti.gov.bn/media/planjc1p/bd-radio-spectrum-plan-2019.pdf
[2] https://www.agc.gov.bn/AGC%20Images/LAWS/Gazette_PDF/2013/EN/s086.pdf
Signed-off-by: Hafiz Zafran <hfzz7@duck.com>
---
db.txt | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/db.txt b/db.txt
index 1d17271..8e5cbb5 100644
--- a/db.txt
+++ b/db.txt
@@ -326,11 +326,15 @@ country BM: DFS-FCC
(5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
-country BN: DFS-JP
- (2402 - 2482 @ 40), (20)
- (5170 - 5250 @ 80), (20), AUTO-BW
- (5250 - 5330 @ 80), (20), DFS, AUTO-BW
- (5735 - 5835 @ 80), (20)
+# https://aiti.gov.bn/media/planjc1p/bd-radio-spectrum-plan-2019.pdf
+# Section 7.5, Page 244-251
+country BN: DFS-FCC
+ (2400 - 2483.5 @ 40), (200 mW)
+ (5150 - 5250 @ 80), (1000 mW), AUTO-BW
+ (5250 - 5350 @ 80), (1000 mW), DFS, AUTO-BW
+ (5470 - 5730 @ 160), (1000 mW), DFS
+ (5725 - 5850 @ 80), (4000 mW), AUTO-BW
+ (57000 - 66000 @ 2160), (10000 mW)
country BO: DFS-JP
(2402 - 2482 @ 40), (20)
--
2.51.1
^ permalink raw reply related
* [PATCH] wifi: rtw88: increase TX report timeout to fix race condition
From: luka.gejak @ 2026-05-01 15:04 UTC (permalink / raw)
To: Ping-Ke Shih, Kalle Valo
Cc: Yan-Hsuan Chuang, Brian Norris, Stanislaw Gruszka, linux-wireless,
linux-kernel, Luka Gejak, stable
From: Luka Gejak <luka.gejak@linux.dev>
The driver expects the firmware to report TX status within 500ms.
However, a race condition exists when the hardware is under heavy TX
load and is simultaneously interrupted by background scans or
power-saving state transitions. During these events, the firmware may
go off-channel for longer than 500ms, delaying the TX reports.
When this happens, the purge timer fires prematurely, dropping the
tracking skbs from the queue and spamming the kernel log with:
"failed to get tx report from firmware". Dropping these tracking skbs
prevents the driver from reporting TX status back to mac80211, which
breaks rate control accounting and degrades performance.
Increase RTW_TX_PROBE_TIMEOUT to 2500ms. This timeout is large enough
to comfortably accommodate the duration of full WiFi background scans
and sleep transitions without incorrectly tripping the purge timer,
while still eventually catching true firmware lockups.
Fixes: e3037485c68e ("rtw88: new Realtek 802.11ac driver")
Cc: stable@vger.kernel.org
Tested-by: Luka Gejak <luka.gejak@linux.dev>
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
drivers/net/wireless/realtek/rtw88/tx.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw88/tx.h b/drivers/net/wireless/realtek/rtw88/tx.h
index d34cdeca16f1..95d15e4f5d34 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.h
+++ b/drivers/net/wireless/realtek/rtw88/tx.h
@@ -7,7 +7,7 @@
#define RTK_TX_MAX_AGG_NUM_MASK 0x1f
-#define RTW_TX_PROBE_TIMEOUT msecs_to_jiffies(500)
+#define RTW_TX_PROBE_TIMEOUT msecs_to_jiffies(2500)
struct rtw_tx_desc {
__le32 w0;
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v4 10/15] drm/msm: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-05-01 14:11 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg,
Dmitry Baryshkov
In-Reply-To: <20260429135954.nvr6nyfadsjeymyt@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 07:29:54PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:58PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Switch drm/msm client drivers over to generic PAS TZ APIs. Generic PAS
> > TZ service allows to support multiple TZ implementation backends like QTEE
> > based SCM PAS service, OP-TEE based PAS service and any further future TZ
> > backend service.
> >
> > Acked-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/gpu/drm/msm/Kconfig | 1 +
> > drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 4 ++--
> > drivers/gpu/drm/msm/adreno/adreno_gpu.c | 11 ++++++-----
> > 3 files changed, 9 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gdrivers/gpu/drm/msm/Kconfigpu/drm/msm/Kconfig
> > index 250246f81ea9..09469d56513b 100644
> > --- a/drivers/gpu/drm/msm/Kconfig
> > +++ b/drivers/gpu/drm/msm/Kconfig
> > @@ -21,6 +21,7 @@ config DRM_MSM
> > select SHMEM
> > select TMPFS
> > select QCOM_SCM
>
> do we need this ?
Yeah we do..
>
> > + select QCOM_PAS
> > select QCOM_UBWC_CONFIG
> > select WANT_DEV_COREDUMP
> > select SND_SOC_HDMI_CODEC if SND_SOC
> > diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
> > index 79acae11154a..b556da823897 100644
> > --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
> > +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
> > @@ -5,7 +5,7 @@
> > #include <linux/kernel.h>
> > #include <linux/types.h>
> > #include <linux/cpumask.h>
> > -#include <linux/firmware/qcom/qcom_scm.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/pm_opp.h>
> > #include <linux/nvmem-consumer.h>
> > #include <linux/slab.h>
> > @@ -653,7 +653,7 @@ static int a5xx_zap_shader_resume(struct msm_gpu *gpu)
> > if (adreno_is_a506(adreno_gpu))
> > return 0;
> >
> > - ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID);
> > + ret = qcom_pas_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID);
> > if (ret)
> > DRM_ERROR("%s: zap-shader resume failed: %d\n",
> > gpu->name, ret);
> > diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> > index 66f80f2d12f9..6d68edf0578c 100644
> > --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> > +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
> > @@ -8,6 +8,7 @@
> >
> > #include <linux/ascii85.h>
> > #include <linux/interconnect.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/firmware/qcom/qcom_scm.h>
>
> do we need this ?
>
..needed for qcom_scm_set_gpu_smmu_aperture() API.
> > #include <linux/kernel.h>
> > #include <linux/of_reserved_mem.h>
> > @@ -146,10 +147,10 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
> > goto out;
> >
> > /* Send the image to the secure world */
> > - ret = qcom_scm_pas_auth_and_reset(pasid);
> > + ret = qcom_pas_auth_and_reset(pasid);
> >
> > /*
> > - * If the scm call returns -EOPNOTSUPP we assume that this target
> > + * If the pas call returns -EOPNOTSUPP we assume that this target
> > * doesn't need/support the zap shader so quietly fail
> > */
> > if (ret == -EOPNOTSUPP)
> > @@ -175,9 +176,9 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid)
> > if (!zap_available)
> > return -ENODEV;
> >
> > - /* We need SCM to be able to load the firmware */
> > - if (!qcom_scm_is_available()) {
> > - DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n");
> > + /* We need PAS to be able to load the firmware */
> > + if (!qcom_pas_is_available()) {
> > + DRM_DEV_ERROR(&pdev->dev, "Qcom PAS is not available\n");
> > return -EPROBE_DEFER;
> > }
> >
> > --
> > 2.51.0
> >
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>
Thanks.
-Sumit
^ permalink raw reply
* Re: [PATCH v4 09/15] remoteproc: qcom: Select QCOM_PAS generic service
From: Sumit Garg @ 2026-05-01 14:08 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260429135257.utgighzczrbnl6cp@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 07:22:57PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:57PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Select PAS generic service driver to enable support for multiple PAS
> > backends like OP-TEE in addition to SCM.
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/remoteproc/Kconfig | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
> > index ee54436fea5a..da3c5d9562ea 100644
> > --- a/drivers/remoteproc/Kconfig
> > +++ b/drivers/remoteproc/Kconfig
> > @@ -230,6 +230,7 @@ config QCOM_Q6V5_PAS
> > select QCOM_Q6V5_COMMON
> > select QCOM_RPROC_COMMON
> > select QCOM_SCM
>
> Check do we really need SCM now ?
For WCNSS we don't need, I will drop there but others have SCM memory
assign needs.
> Why not the change for WCNSS, MSS ?
Ack, I will change for them too.
-Sumit
>
> > + select QCOM_PAS
> > help
> > Say y here to support the TrustZone based Peripheral Image Loader for
> > the Qualcomm remote processors. This is commonly used to control
>
>
> > --
> > 2.51.0
> >
>
> --
> -Mukesh Ojha
>
^ permalink raw reply
* Re: [PATCH v4 07/15] soc: qcom: mdtloader: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-05-01 13:59 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260429134208.pqo67sh3jkvsa5ka@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 07:12:08PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:55PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Switch mdtloader client driver over to generic PAS TZ APIs. Generic PAS
> > TZ service allows to support multiple TZ implementation backends like QTEE
> > based SCM PAS service, OP-TEE based PAS service and any further future TZ
> > backend service.
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/soc/qcom/mdt_loader.c | 12 ++++++------
> > include/linux/soc/qcom/mdt_loader.h | 6 +++---
> > 2 files changed, 9 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
> > index c004d444d698..fdde7eda538a 100644
> > --- a/drivers/soc/qcom/mdt_loader.c
> > +++ b/drivers/soc/qcom/mdt_loader.c
> > @@ -13,7 +13,7 @@
> > #include <linux/firmware.h>
> > #include <linux/kernel.h>
> > #include <linux/module.h>
> > -#include <linux/firmware/qcom/qcom_scm.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/sizes.h>
> > #include <linux/slab.h>
> > #include <linux/soc/qcom/mdt_loader.h>
> > @@ -229,7 +229,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
> >
> > static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
> > const char *fw_name, int pas_id, phys_addr_t mem_phys,
> > - struct qcom_scm_pas_context *ctx)
> > + struct qcom_pas_context *ctx)
> > {
> > const struct elf32_phdr *phdrs;
> > const struct elf32_phdr *phdr;
> > @@ -271,7 +271,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
> > goto out;
> > }
> >
> > - ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx);
> > + ret = qcom_pas_init_image(pas_id, metadata, metadata_len, ctx);
> > kfree(metadata);
> > if (ret) {
> > /* Invalid firmware metadata */
> > @@ -280,7 +280,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
> > }
> >
> > if (relocate) {
> > - ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
> > + ret = qcom_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
> > if (ret) {
> > /* Unable to set up relocation */
> > dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
> > @@ -472,7 +472,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
> > * firmware segments (e.g., .bXX files). Authentication of the segments done
> > * by a separate call.
> > *
> > - * The PAS context must be initialized using qcom_scm_pas_context_init()
> > + * The PAS context must be initialized using qcom_pas_context_init()
>
> Should devm_qcom_pas_context_alloc() now
Ack.
>
> > * prior to invoking this function.
> > *
> > * @ctx: Pointer to the PAS (Peripheral Authentication Service) context
> > @@ -483,7 +483,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
> > *
> > * Return: 0 on success or a negative error code on failure.
> > */
> > -int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
> > +int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
> > const char *firmware, void *mem_region, phys_addr_t *reloc_base)
> > {
> > int ret;
> > diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h
> > index 82372e0db0a1..142409555425 100644
> > --- a/include/linux/soc/qcom/mdt_loader.h
> > +++ b/include/linux/soc/qcom/mdt_loader.h
> > @@ -10,7 +10,7 @@
> >
> > struct device;
> > struct firmware;
> > -struct qcom_scm_pas_context;
> > +struct qcom_pas_context;
> >
> > #if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
> >
> > @@ -20,7 +20,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
> > phys_addr_t mem_phys, size_t mem_size,
> > phys_addr_t *reloc_base);
> >
> > -int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
> > +int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
> > const char *firmware, void *mem_region, phys_addr_t *reloc_base);
> >
> > int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
> > @@ -45,7 +45,7 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw,
> > return -ENODEV;
> > }
> >
> > -static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx,
> > +static inline int qcom_mdt_pas_load(struct qcom_pas_context *ctx,
> > const struct firmware *fw, const char *firmware,
> > void *mem_region, phys_addr_t *reloc_base)
> > {
> > --
> > 2.51.0
> >
>
> With above nit
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Thanks.
-Sumit
^ permalink raw reply
* Re: [PATCH v4 06/15] remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-05-01 13:58 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260429133157.lopr6n5vaik36466@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 07:01:57PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:54PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Switch qcom_q6v5_mss client driver over to generic PAS TZ APIs. Generic PAS
> > TZ service allows to support multiple TZ implementation backends like QTEE
> > based SCM PAS service, OP-TEE based PAS service and any further future TZ
> > backend service.
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/remoteproc/qcom_q6v5_mss.c | 5 +++--
> > 1 file changed, 3 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
> > index ae78f5c7c1b6..96888007faa8 100644
> > --- a/drivers/remoteproc/qcom_q6v5_mss.c
> > +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> > @@ -34,6 +34,7 @@
> > #include "qcom_pil_info.h"
> > #include "qcom_q6v5.h"
> >
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/firmware/qcom/qcom_scm.h>
>
> same here., whether it is needed now ?
Ditto, needed for qcom_scm_assign_mem().
>
> >
> > #define MPSS_CRASH_REASON_SMEM 421
> > @@ -1480,7 +1481,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
> > }
> >
> > if (qproc->need_pas_mem_setup) {
> > - ret = qcom_scm_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
> > + ret = qcom_pas_mem_setup(MPSS_PAS_ID, qproc->mpss_phys, qproc->mpss_size);
> > if (ret) {
> > dev_err(qproc->dev,
> > "setting up mpss memory failed: %d\n", ret);
> > @@ -2077,7 +2078,7 @@ static int q6v5_probe(struct platform_device *pdev)
> > if (!desc)
> > return -EINVAL;
> >
> > - if (desc->need_mem_protection && !qcom_scm_is_available())
> > + if (desc->need_mem_protection && !qcom_pas_is_available())
> > return -EPROBE_DEFER;
> >
> > mba_image = desc->hexagon_mba_image;
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Thanks.
-Sumit
^ permalink raw reply
* Re: [PATCH v4 05/15] remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs
From: Sumit Garg @ 2026-05-01 13:57 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260429132512.aki4vqkhpil7awc3@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 06:55:12PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:53PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Switch qcom_q6v5_pas client driver over to generic PAS TZ APIs. Generic PAS
> > TZ service allows to support multiple TZ implementation backends like QTEE
> > based SCM PAS service, OP-TEE based PAS service and any further future TZ
> > backend service.
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/remoteproc/qcom_q6v5_pas.c | 51 +++++++++++++++---------------
> > 1 file changed, 26 insertions(+), 25 deletions(-)
> >
> > diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> > index da27d1d3c9da..847249c28c1b 100644
> > --- a/drivers/remoteproc/qcom_q6v5_pas.c
> > +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> > @@ -20,6 +20,7 @@
> > #include <linux/platform_device.h>
> > #include <linux/pm_domain.h>
> > #include <linux/pm_runtime.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/firmware/qcom/qcom_scm.h>
>
> Can you check do we really need this header ?
Yeah it's needed for qcom_scm_assign_mem() API.
>
> > #include <linux/regulator/consumer.h>
> > #include <linux/remoteproc.h>
> > @@ -118,8 +119,8 @@ struct qcom_pas {
> > struct qcom_rproc_ssr ssr_subdev;
> > struct qcom_sysmon *sysmon;
> >
> > - struct qcom_scm_pas_context *pas_ctx;
> > - struct qcom_scm_pas_context *dtb_pas_ctx;
> > + struct qcom_pas_context *pas_ctx;
> > + struct qcom_pas_context *dtb_pas_ctx;
> > };
> >
> > static void qcom_pas_segment_dump(struct rproc *rproc,
> > @@ -196,7 +197,7 @@ static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas)
> >
> > do {
> > msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS);
> > - ret = qcom_scm_pas_shutdown(pas->pas_id);
> > + ret = qcom_pas_shutdown(pas->pas_id);
> > } while (ret == -EINVAL && --retry_num);
> >
> > return ret;
> > @@ -212,9 +213,9 @@ static int qcom_pas_unprepare(struct rproc *rproc)
> > * auth_and_reset() was successful, but in other cases clean it up
> > * here.
> > */
> > - qcom_scm_pas_metadata_release(pas->pas_ctx);
> > + qcom_pas_metadata_release(pas->pas_ctx);
> > if (pas->dtb_pas_id)
> > - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
> > + qcom_pas_metadata_release(pas->dtb_pas_ctx);
> >
> > return 0;
> > }
> > @@ -228,9 +229,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
> > pas->firmware = fw;
> >
> > if (pas->lite_pas_id)
> > - qcom_scm_pas_shutdown(pas->lite_pas_id);
> > + qcom_pas_shutdown(pas->lite_pas_id);
> > if (pas->lite_dtb_pas_id)
> > - qcom_scm_pas_shutdown(pas->lite_dtb_pas_id);
> > + qcom_pas_shutdown(pas->lite_dtb_pas_id);
> >
> > if (pas->dtb_pas_id) {
> > ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev);
> > @@ -250,7 +251,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
> > return 0;
> >
> > release_dtb_metadata:
> > - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
> > + qcom_pas_metadata_release(pas->dtb_pas_ctx);
> > release_firmware(pas->dtb_firmware);
> >
> > return ret;
> > @@ -310,7 +311,7 @@ static int qcom_pas_start(struct rproc *rproc)
> > if (ret)
> > goto disable_px_supply;
> >
> > - ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
> > + ret = qcom_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
> > if (ret) {
> > dev_err(pas->dev,
> > "failed to authenticate dtb image and release reset\n");
> > @@ -329,7 +330,7 @@ static int qcom_pas_start(struct rproc *rproc)
> > if (ret)
> > goto release_pas_metadata;
> >
> > - ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx);
> > + ret = qcom_pas_prepare_and_auth_reset(pas->pas_ctx);
> > if (ret) {
> > dev_err(pas->dev,
> > "failed to authenticate image and release reset\n");
> > @@ -339,13 +340,13 @@ static int qcom_pas_start(struct rproc *rproc)
> > ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000));
> > if (ret == -ETIMEDOUT) {
> > dev_err(pas->dev, "start timed out\n");
> > - qcom_scm_pas_shutdown(pas->pas_id);
> > + qcom_pas_shutdown(pas->pas_id);
> > goto unmap_carveout;
> > }
> >
> > - qcom_scm_pas_metadata_release(pas->pas_ctx);
> > + qcom_pas_metadata_release(pas->pas_ctx);
> > if (pas->dtb_pas_id)
> > - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
> > + qcom_pas_metadata_release(pas->dtb_pas_ctx);
> >
> > /* firmware is used to pass reference from qcom_pas_start(), drop it now */
> > pas->firmware = NULL;
> > @@ -355,9 +356,9 @@ static int qcom_pas_start(struct rproc *rproc)
> > unmap_carveout:
> > qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size);
> > release_pas_metadata:
> > - qcom_scm_pas_metadata_release(pas->pas_ctx);
> > + qcom_pas_metadata_release(pas->pas_ctx);
> > if (pas->dtb_pas_id)
> > - qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
> > + qcom_pas_metadata_release(pas->dtb_pas_ctx);
> >
> > unmap_dtb_carveout:
> > if (pas->dtb_pas_id)
> > @@ -406,7 +407,7 @@ static int qcom_pas_stop(struct rproc *rproc)
> > if (ret == -ETIMEDOUT)
> > dev_err(pas->dev, "timed out on wait\n");
> >
> > - ret = qcom_scm_pas_shutdown(pas->pas_id);
> > + ret = qcom_pas_shutdown(pas->pas_id);
> > if (ret && pas->decrypt_shutdown)
> > ret = qcom_pas_shutdown_poll_decrypt(pas);
> >
> > @@ -414,7 +415,7 @@ static int qcom_pas_stop(struct rproc *rproc)
> > dev_err(pas->dev, "failed to shutdown: %d\n", ret);
> >
> > if (pas->dtb_pas_id) {
> > - ret = qcom_scm_pas_shutdown(pas->dtb_pas_id);
> > + ret = qcom_pas_shutdown(pas->dtb_pas_id);
> > if (ret)
> > dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
> >
> > @@ -484,11 +485,11 @@ static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *f
> > *
> > * Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources
> > * or not and if it is not having then we pass NULL and zero as input resource
> > - * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table()
> > + * table pointer and size respectively to the argument of qcom_pas_get_rsc_table()
> > * and this is even true for Qualcomm remote processor who does follow remoteproc
> > * framework.
> > */
> > - output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
> > + output_rt = qcom_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
> > ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0;
> > if (ret) {
> > dev_err(pas->dev, "Error in getting resource table: %d\n", ret);
> > @@ -746,7 +747,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
> > if (!desc)
> > return -EINVAL;
> >
> > - if (!qcom_scm_is_available())
> > + if (!qcom_pas_is_available())
> > return -EPROBE_DEFER;
> >
> > fw_name = desc->firmware_name;
> > @@ -838,16 +839,16 @@ static int qcom_pas_probe(struct platform_device *pdev)
> >
> > qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name);
> >
> > - pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id,
> > - pas->mem_phys, pas->mem_size);
> > + pas->pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->pas_id,
> > + pas->mem_phys, pas->mem_size);
> > if (IS_ERR(pas->pas_ctx)) {
> > ret = PTR_ERR(pas->pas_ctx);
> > goto remove_ssr_sysmon;
> > }
> >
> > - pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id,
> > - pas->dtb_mem_phys,
> > - pas->dtb_mem_size);
> > + pas->dtb_pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->dtb_pas_id,
> > + pas->dtb_mem_phys,
> > + pas->dtb_mem_size);
> > if (IS_ERR(pas->dtb_pas_ctx)) {
> > ret = PTR_ERR(pas->dtb_pas_ctx);
> > goto remove_ssr_sysmon;
> > --
> > 2.51.0
> >
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Thanks.
-Sumit
^ permalink raw reply
* Re: [PATCH v4 04/15] firmware: qcom: Add a PAS TEE service
From: Sumit Garg @ 2026-05-01 13:54 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260429132021.xk2xtll545o256oz@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 06:50:21PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:52PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Add support for Peripheral Authentication Service (PAS) driver based
> > on TEE bus with OP-TEE providing the backend PAS service implementation.
> >
> > The TEE PAS service ABI is designed to be extensible with additional API
> > as PTA_QCOM_PAS_CAPABILITIES. This allows to accommodate any future
> > extensions of the PAS service needed while still maintaining backwards
> > compatibility.
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/firmware/qcom/Kconfig | 10 +
> > drivers/firmware/qcom/Makefile | 1 +
> > drivers/firmware/qcom/qcom_pas_tee.c | 479 +++++++++++++++++++++++++++
> > 3 files changed, 490 insertions(+)
> > create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
> >
> > diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
> > index 9a12ae2b639d..300b3a1bd178 100644
> > --- a/drivers/firmware/qcom/Kconfig
> > +++ b/drivers/firmware/qcom/Kconfig
> > @@ -14,6 +14,16 @@ config QCOM_PAS
> > backends plugged in whether it's an SCM implementation or a proper
> > TEE bus based PAS service implementation.
> >
> > +config QCOM_PAS_TEE
> > + tristate
> > + select QCOM_PAS
> > + depends on TEE
> > + depends on !CPU_BIG_ENDIAN
> > + default m if ARCH_QCOM
> > + help
> > + Enable the generic Peripheral Authentication Service (PAS) provided
> > + by the firmware TEE implementation as the backend.
> > +
> > config QCOM_SCM
> > select QCOM_PAS
> > select QCOM_TZMEM
> > diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
> > index dc5ab45f906a..48801d18f37b 100644
> > --- a/drivers/firmware/qcom/Makefile
> > +++ b/drivers/firmware/qcom/Makefile
> > @@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o
> > obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
> > obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
> > obj-$(CONFIG_QCOM_PAS) += qcom_pas.o
> > +obj-$(CONFIG_QCOM_PAS_TEE) += qcom_pas_tee.o
> > diff --git a/drivers/firmware/qcom/qcom_pas_tee.c b/drivers/firmware/qcom/qcom_pas_tee.c
> > new file mode 100644
> > index 000000000000..af73d0a68525
> > --- /dev/null
> > +++ b/drivers/firmware/qcom/qcom_pas_tee.c
> > @@ -0,0 +1,479 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/of.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/slab.h>
> > +#include <linux/tee_drv.h>
> > +#include <linux/uuid.h>
> > +
> > +#include "qcom_pas.h"
> > +
> > +/*
> > + * Peripheral Authentication Service (PAS) supported.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + */
> > +#define TA_QCOM_PAS_IS_SUPPORTED 1
> > +
> > +/*
> > + * PAS capabilities.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + * [out] params[1].value.a: PAS capability flags
> > + */
> > +#define TA_QCOM_PAS_CAPABILITIES 2
> > +
> > +/*
> > + * PAS image initialization.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + * [in] params[1].memref: Loadable firmware metadata
> > + */
> > +#define TA_QCOM_PAS_INIT_IMAGE 3
> > +
> > +/*
> > + * PAS memory setup.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + * [in] params[0].value.b: Relocatable firmware size
> > + * [in] params[1].value.a: 32bit LSB relocatable firmware memory address
> > + * [in] params[1].value.b: 32bit MSB relocatable firmware memory address
> > + */
> > +#define TA_QCOM_PAS_MEM_SETUP 4
> > +
> > +/*
> > + * PAS get resource table.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + * [inout] params[1].memref: Resource table config
> > + */
> > +#define TA_QCOM_PAS_GET_RESOURCE_TABLE 5
> > +
> > +/*
> > + * PAS image authentication and co-processor reset.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + * [in] params[0].value.b: Firmware size
> > + * [in] params[1].value.a: 32bit LSB firmware memory address
> > + * [in] params[1].value.b: 32bit MSB firmware memory address
> > + * [in] params[2].memref: Optional fw memory space shared/lent
> > + */
> > +#define TA_QCOM_PAS_AUTH_AND_RESET 6
> > +
> > +/*
> > + * PAS co-processor set suspend/resume state.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + * [in] params[0].value.b: Co-processor state identifier
> > + */
> > +#define TA_QCOM_PAS_SET_REMOTE_STATE 7
> > +
> > +/*
> > + * PAS co-processor shutdown.
> > + *
> > + * [in] params[0].value.a: Unique 32bit remote processor identifier
> > + */
> > +#define TA_QCOM_PAS_SHUTDOWN 8
> > +
> > +#define TEE_NUM_PARAMS 4
> > +
> > +/**
> > + * struct qcom_pas_tee_private - PAS service private data
> > + * @dev: PAS service device.
> > + * @ctx: TEE context handler.
> > + * @session_id: PAS TA session identifier.
> > + */
> > +struct qcom_pas_tee_private {
> > + struct device *dev;
> > + struct tee_context *ctx;
> > + u32 session_id;
> > +};
> > +
> > +static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id)
> > +{
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > + struct tee_ioctl_invoke_arg inv_arg = {
> > + .func = TA_QCOM_PAS_IS_SUPPORTED,
> > + .session = data->session_id,
> > + .num_params = TEE_NUM_PARAMS
> > + };
> > + struct tee_param param[4] = {
> > + [0] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = pas_id
> > + }
> > + };
> > + int ret;
> > +
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS not supported, pas_id: %d, ret: %d, err: 0x%x\n",
> > + pas_id, ret, inv_arg.ret);
> > + return false;
> > + }
> > +
> > + return true;
> > +}
> > +
> > +static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id,
> > + const void *metadata, size_t size,
> > + struct qcom_pas_context *ctx)
> > +{
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > + struct tee_ioctl_invoke_arg inv_arg = {
> > + .func = TA_QCOM_PAS_INIT_IMAGE,
> > + .session = data->session_id,
> > + .num_params = TEE_NUM_PARAMS
> > + };
> > + struct tee_param param[4] = {
> > + [0] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = pas_id
> > + },
> > + [1] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
> > + }
> > + };
> > + struct tee_shm *mdata_shm;
> > + u8 *mdata_buf = NULL;
> > + int ret;
> > +
> > + mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size);
> > + if (IS_ERR(mdata_shm)) {
> > + dev_err(dev, "mdata_shm allocation failed\n");
> > + return PTR_ERR(mdata_shm);
> > + }
> > +
> > + mdata_buf = tee_shm_get_va(mdata_shm, 0);
> > + if (IS_ERR(mdata_buf)) {
> > + dev_err(dev, "mdata_buf get VA failed\n");
> > + tee_shm_free(mdata_shm);
> > + return PTR_ERR(mdata_buf);
> > + }
> > + memcpy(mdata_buf, metadata, size);
> > +
> > + param[1].u.memref.shm = mdata_shm;
> > + param[1].u.memref.size = size;
> > +
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS init image failed, pas_id: %d, ret: %d, err: 0x%x\n",
> > + pas_id, ret, inv_arg.ret);
> > + tee_shm_free(mdata_shm);
> > + return ret ?: -EINVAL;
> > + }
> > +
> > + if (ctx)
> > + ctx->ptr = (void *)mdata_shm;
> > + else
> > + tee_shm_free(mdata_shm);
> > +
> > + return ret;
> > +}
> > +
> > +static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id,
> > + phys_addr_t addr, phys_addr_t size)
> > +{
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > + struct tee_ioctl_invoke_arg inv_arg = {
> > + .func = TA_QCOM_PAS_MEM_SETUP,
> > + .session = data->session_id,
> > + .num_params = TEE_NUM_PARAMS
> > + };
> > + struct tee_param param[4] = {
> > + [0] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = pas_id,
> > + .u.value.b = size,
> > + },
> > + [1] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = lower_32_bits(addr),
> > + .u.value.b = upper_32_bits(addr),
> > + }
> > + };
> > + int ret;
> > +
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n",
> > + pas_id, ret, inv_arg.ret);
> > + return ret ?: -EINVAL;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T))
> > +
> > +static void *qcom_pas_tee_get_rsc_table(struct device *dev,
> > + struct qcom_pas_context *ctx,
> > + void *input_rt, size_t input_rt_size,
> > + size_t *output_rt_size)
> > +{
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > + struct tee_ioctl_invoke_arg inv_arg = {
> > + .func = TA_QCOM_PAS_GET_RESOURCE_TABLE,
> > + .session = data->session_id,
> > + .num_params = TEE_NUM_PARAMS
> > + };
> > + struct tee_param param[4] = {
> > + [0] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = ctx->pas_id,
> > + },
> > + [1] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
> > + .u.memref.size = input_rt_size,
> > + }
> > + };
> > + void *rt_buf = NULL;
> > + int ret;
> > +
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
> > + ctx->pas_id, ret, inv_arg.ret);
> > + return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
> > + }
> > +
> > + if (param[1].u.memref.size) {
> > + struct tee_shm *rt_shm __free(shm_free) =
> > + tee_shm_alloc_kernel_buf(data->ctx,
> > + param[1].u.memref.size);
> > + void *rt_shm_va;
> > +
> > + if (IS_ERR(rt_shm)) {
> > + dev_err(dev, "rt_shm allocation failed\n");
> > + return rt_shm;
> > + }
> > +
> > + rt_shm_va = tee_shm_get_va(rt_shm, 0);
> > + if (IS_ERR(rt_shm_va)) {
> > + dev_err(dev, "rt_shm get VA failed\n");
> > + return ERR_CAST(rt_shm_va);
> > + }
> > + memcpy(rt_shm_va, input_rt, input_rt_size);
>
> It is very obvious that every existing user will pass NULL as input_rt
> and 0 as input_rt_size.
>
> Are you not getting NULL pointer on this input_rt ? Ok, you may be not
> getting because, input_rt_size == 0.
>
> I hope, your backend implementation checks for this num == 0 and then
> ignore input rt.
rt_shm_va is an INOUT buffer with OP-TEE, if Linux has any RT
information to pass then it can pass in this buffer. For current targets
nothing is provided by Linux and rt_shm_va will only get populated by
OP-TEE with RT information to be consumed by Linux for SMMU
configuration.
The total size of rt_shm_va buffer is sum of input RT and output RT
sizes. This framework is supported by GP TEE APIs to avoid double memory
buffer usage.
>
> > +
> > + param[1].u.memref.shm = rt_shm;
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
> > + ctx->pas_id, ret, inv_arg.ret);
> > + return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
> > + }
> > +
> > + if (param[1].u.memref.size) {
> > + *output_rt_size = param[1].u.memref.size;
> > + rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL);
> > + if (!rt_buf)
> > + return ERR_PTR(-ENOMEM);
> > + }
> > + }
> > +
> > + return rt_buf;
> > +}
> > +
> > +static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id,
> > + phys_addr_t mem_phys, size_t mem_size)
> > +{
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > + struct tee_ioctl_invoke_arg inv_arg = {
> > + .func = TA_QCOM_PAS_AUTH_AND_RESET,
> > + .session = data->session_id,
> > + .num_params = TEE_NUM_PARAMS
> > + };
> > + struct tee_param param[4] = {
> > + [0] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = pas_id,
> > + .u.value.b = mem_size,
> > + },
> > + [1] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = lower_32_bits(mem_phys),
> > + .u.value.b = upper_32_bits(mem_phys),
> > + },
> > + /* Reserved for fw memory space to be shared or lent */
> > + [2] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
> > + }
> > + };
> > + int ret;
> > +
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS auth reset failed, pas_id: %d, ret: %d, err: 0x%x\n",
> > + pas_id, ret, inv_arg.ret);
> > + return ret ?: -EINVAL;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id)
> > +{
> > + return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0);
> > +}
> > +
> > +static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev,
> > + struct qcom_pas_context *ctx)
> > +{
> > + return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys,
> > + ctx->mem_size);
> > +}
> > +
> > +static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state,
> > + u32 pas_id)
> > +{
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > + struct tee_ioctl_invoke_arg inv_arg = {
> > + .func = TA_QCOM_PAS_SET_REMOTE_STATE,
> > + .session = data->session_id,
> > + .num_params = TEE_NUM_PARAMS
> > + };
> > + struct tee_param param[4] = {
> > + [0] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = pas_id,
> > + .u.value.b = state,
> > + }
> > + };
> > + int ret;
> > +
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n",
> > + pas_id, ret, inv_arg.ret);
>
> should be "PAS set remote state failed .."
Ack.
>
> > + return ret ?: -EINVAL;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id)
> > +{
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > + struct tee_ioctl_invoke_arg inv_arg = {
> > + .func = TA_QCOM_PAS_SHUTDOWN,
> > + .session = data->session_id,
> > + .num_params = TEE_NUM_PARAMS
> > + };
> > + struct tee_param param[4] = {
> > + [0] = {
> > + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> > + .u.value.a = pas_id
> > + }
> > + };
> > + int ret;
> > +
> > + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> > + if (ret < 0 || inv_arg.ret != 0) {
> > + dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n",
> > + pas_id, ret, inv_arg.ret);
> > + return ret ?: -EINVAL;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void qcom_pas_tee_metadata_release(struct device *dev,
> > + struct qcom_pas_context *ctx)
> > +{
> > + struct tee_shm *mdata_shm = ctx->ptr;
> > +
> > + tee_shm_free(mdata_shm);
> > +}
> > +
> > +static struct qcom_pas_ops qcom_pas_ops_tee = {
> > + .drv_name = "qcom-pas-tee",
> > + .supported = qcom_pas_tee_supported,
> > + .init_image = qcom_pas_tee_init_image,
> > + .mem_setup = qcom_pas_tee_mem_setup,
> > + .get_rsc_table = qcom_pas_tee_get_rsc_table,
> > + .auth_and_reset = qcom_pas_tee_auth_and_reset,
> > + .prepare_and_auth_reset = qcom_pas_tee_prepare_and_auth_reset,
> > + .set_remote_state = qcom_pas_tee_set_remote_state,
> > + .shutdown = qcom_pas_tee_shutdown,
> > + .metadata_release = qcom_pas_tee_metadata_release,
> > +};
> > +
> > +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
> > +{
> > + return ver->impl_id == TEE_IMPL_ID_OPTEE;
> > +}
> > +
> > +static int qcom_pas_tee_probe(struct tee_client_device *pas_dev)
> > +{
> > + struct device *dev = &pas_dev->dev;
> > + struct qcom_pas_tee_private *data;
> > + struct tee_ioctl_open_session_arg sess_arg = {
> > + .clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL
> > + };
> > + int ret, err = -ENODEV;
>
> Most people prefer one line per variable..
Ack.
>
>
> > +
> > + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> > + if (!data)
> > + return -ENOMEM;
> > +
> > + data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
> > + if (IS_ERR(data->ctx))
> > + return -ENODEV;
> > +
> > + export_uuid(sess_arg.uuid, &pas_dev->id.uuid);
> > + ret = tee_client_open_session(data->ctx, &sess_arg, NULL);
> > + if (ret < 0 || sess_arg.ret != 0) {
> > + dev_err(dev, "tee_client_open_session failed, ret: %d, err: 0x%x\n",
> > + ret, sess_arg.ret);
> > + err = ret ?: -EINVAL;
>
> Only user of goto, we can close the context and return from here and
> 'err' not used.
Ack.
>
> tee_client_close_context(data->ctx);
> return ret ?: -EINVAL;
>
> > + goto out_ctx;
>
>
> > + }
> > +
> > + data->session_id = sess_arg.session;
> > + dev_set_drvdata(dev, data);
> > + qcom_pas_ops_tee.dev = dev;
> > + qcom_pas_ops_register(&qcom_pas_ops_tee);
> > +
> > + return ret;
> > +out_ctx:
> > + tee_client_close_context(data->ctx);
>
> Return after two line does not look nice.
>
> > +
> > + return err;
> > +}
> > +
> > +static void qcom_pas_tee_remove(struct tee_client_device *pas_dev)
> > +{
> > + struct device *dev = &pas_dev->dev;
> > + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> > +
> > + qcom_pas_ops_unregister();
> > + tee_client_close_session(data->ctx, data->session_id);
> > + tee_client_close_context(data->ctx);
> > +}
> > +
> > +static const struct tee_client_device_id qcom_pas_tee_id_table[] = {
> > + {UUID_INIT(0xcff7d191, 0x7ca0, 0x4784,
> > + 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)},
> > + {}
> > +};
> > +MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table);
> > +
> > +static struct tee_client_driver optee_pas_tee_driver = {
> > + .probe = qcom_pas_tee_probe,
> > + .remove = qcom_pas_tee_remove,
> > + .id_table = qcom_pas_tee_id_table,
> > + .driver = {
> > + .name = "qcom-pas-tee",
> > + },
> > +};
> > +
> > +module_tee_client_driver(optee_pas_tee_driver);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Qualcomm PAS TEE driver");
> > --
> > 2.51.0
> >
>
>
> With above change,
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>
Thanks.
-Sumit
^ permalink raw reply
* Re: [PATCH v4 03/15] firmware: qcom_scm: Migrate to generic PAS service
From: Sumit Garg @ 2026-05-01 13:41 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260429104841.l555xd2izoyrqjp4@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 04:18:41PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:51PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > With the availability of generic PAS service, let's add SCM calls as
> > a backend to keep supporting legacy QTEE interfaces. The exported
> > qcom_scm* wrappers will get dropped once all the client drivers get
> > migrated as part of future patches.
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/firmware/qcom/Kconfig | 1 +
> > drivers/firmware/qcom/qcom_scm.c | 335 ++++++++++++++-----------------
> > 2 files changed, 155 insertions(+), 181 deletions(-)
> >
> > diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
> > index 8653639d06db..9a12ae2b639d 100644
> > --- a/drivers/firmware/qcom/Kconfig
> > +++ b/drivers/firmware/qcom/Kconfig
> > @@ -15,6 +15,7 @@ config QCOM_PAS
> > TEE bus based PAS service implementation.
> >
> > config QCOM_SCM
> > + select QCOM_PAS
> > select QCOM_TZMEM
> > tristate
> >
> > diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
> > index 9b06a69d3a6d..d87a962e93da 100644
> > --- a/drivers/firmware/qcom/qcom_scm.c
> > +++ b/drivers/firmware/qcom/qcom_scm.c
> > @@ -13,6 +13,7 @@
> > #include <linux/dma-mapping.h>
> > #include <linux/err.h>
> > #include <linux/export.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/firmware/qcom/qcom_scm.h>
> > #include <linux/firmware/qcom/qcom_tzmem.h>
> > #include <linux/init.h>
> > @@ -33,6 +34,7 @@
> >
> > #include <dt-bindings/interrupt-controller/arm-gic.h>
> >
> > +#include "qcom_pas.h"
> > #include "qcom_scm.h"
> > #include "qcom_tzmem.h"
> >
> > @@ -479,25 +481,6 @@ void qcom_scm_cpu_power_down(u32 flags)
> > }
> > EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down);
> >
> > -int qcom_scm_set_remote_state(u32 state, u32 id)
> > -{
> > - struct qcom_scm_desc desc = {
> > - .svc = QCOM_SCM_SVC_BOOT,
> > - .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
> > - .arginfo = QCOM_SCM_ARGS(2),
> > - .args[0] = state,
> > - .args[1] = id,
> > - .owner = ARM_SMCCC_OWNER_SIP,
> > - };
> > - struct qcom_scm_res res;
> > - int ret;
> > -
> > - ret = qcom_scm_call(__scm->dev, &desc, &res);
> > -
> > - return ret ? : res.result[0];
> > -}
> > -EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
> > -
> > static int qcom_scm_disable_sdi(void)
> > {
> > int ret;
> > @@ -570,26 +553,12 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
> > dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
> > }
> >
> > -/**
> > - * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service
> > - * context for a given peripheral
> > - *
> > - * PAS context is device-resource managed, so the caller does not need
> > - * to worry about freeing the context memory.
> > - *
> > - * @dev: PAS firmware device
> > - * @pas_id: peripheral authentication service id
> > - * @mem_phys: Subsystem reserve memory start address
> > - * @mem_size: Subsystem reserve memory size
> > - *
> > - * Returns: The new PAS context, or ERR_PTR() on failure.
> > - */
> > struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
> > u32 pas_id,
> > phys_addr_t mem_phys,
> > size_t mem_size)
> > {
> > - struct qcom_scm_pas_context *ctx;
> > + struct qcom_pas_context *ctx;
> >
> > ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> > if (!ctx)
> > @@ -600,11 +569,12 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
> > ctx->mem_phys = mem_phys;
> > ctx->mem_size = mem_size;
> >
> > - return ctx;
> > + return (struct qcom_scm_pas_context *)ctx;
> > }
> > EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
> >
> > -static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
> > +static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id,
> > + dma_addr_t mdata_phys,
> > struct qcom_scm_res *res)
> > {
> > struct qcom_scm_desc desc = {
> > @@ -626,7 +596,7 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
> >
> > desc.args[1] = mdata_phys;
> >
> > - ret = qcom_scm_call(__scm->dev, &desc, res);
> > + ret = qcom_scm_call(dev, &desc, res);
> > qcom_scm_bw_disable();
> >
> > disable_clk:
> > @@ -635,7 +605,8 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
> > return ret;
> > }
> >
> > -static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
> > +static int qcom_scm_pas_prep_and_init_image(struct device *dev,
> > + struct qcom_pas_context *ctx,
> > const void *metadata, size_t size)
> > {
> > struct qcom_scm_res res;
> > @@ -650,7 +621,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
> > memcpy(mdata_buf, metadata, size);
> > mdata_phys = qcom_tzmem_to_phys(mdata_buf);
> >
> > - ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res);
> > + ret = __qcom_scm_pas_init_image(dev, ctx->pas_id, mdata_phys, &res);
> > if (ret < 0)
> > qcom_tzmem_free(mdata_buf);
> > else
> > @@ -659,25 +630,9 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
> > return ret ? : res.result[0];
> > }
> >
> > -/**
> > - * qcom_scm_pas_init_image() - Initialize peripheral authentication service
> > - * state machine for a given peripheral, using the
> > - * metadata
> > - * @pas_id: peripheral authentication service id
> > - * @metadata: pointer to memory containing ELF header, program header table
> > - * and optional blob of data used for authenticating the metadata
> > - * and the rest of the firmware
> > - * @size: size of the metadata
> > - * @ctx: optional pas context
> > - *
> > - * Return: 0 on success.
> > - *
> > - * Upon successful return, the PAS metadata context (@ctx) will be used to
> > - * track the metadata allocation, this needs to be released by invoking
> > - * qcom_scm_pas_metadata_release() by the caller.
> > - */
> > -int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> > - struct qcom_scm_pas_context *ctx)
> > +static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id,
> > + const void *metadata, size_t size,
> > + struct qcom_pas_context *ctx)
> > {
> > struct qcom_scm_res res;
> > dma_addr_t mdata_phys;
> > @@ -685,7 +640,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> > int ret;
> >
> > if (ctx && ctx->use_tzmem)
> > - return qcom_scm_pas_prep_and_init_image(ctx, metadata, size);
> > + return qcom_scm_pas_prep_and_init_image(dev, ctx, metadata, size);
> >
> > /*
> > * During the scm call memory protection will be enabled for the meta
> > @@ -699,16 +654,15 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> > * If we pass a buffer that is already part of an SHM Bridge to this
> > * call, it will fail.
> > */
> > - mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
> > - GFP_KERNEL);
> > + mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
> > if (!mdata_buf)
> > return -ENOMEM;
> >
> > memcpy(mdata_buf, metadata, size);
> >
> > - ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res);
> > + ret = __qcom_scm_pas_init_image(dev, pas_id, mdata_phys, &res);
> > if (ret < 0 || !ctx) {
> > - dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
> > + dma_free_coherent(dev, size, mdata_buf, mdata_phys);
> > } else if (ctx) {
> > ctx->ptr = mdata_buf;
> > ctx->phys = mdata_phys;
> > @@ -717,36 +671,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> >
> > return ret ? : res.result[0];
> > }
> > -EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
> >
> > -/**
> > - * qcom_scm_pas_metadata_release() - release metadata context
> > - * @ctx: pas context
> > - */
> > -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
> > +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> > + struct qcom_scm_pas_context *ctx)
> > {
> > - if (!ctx->ptr)
> > - return;
> > + return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size,
> > + (struct qcom_pas_context *)ctx);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
> >
> > +static void __qcom_scm_pas_metadata_release(struct device *dev,
> > + struct qcom_pas_context *ctx)
> > +{
> > if (ctx->use_tzmem)
> > qcom_tzmem_free(ctx->ptr);
> > else
> > - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
> > + dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys);
> >
> > ctx->ptr = NULL;
> > }
> > +
> > +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
> > +{
> > + __qcom_scm_pas_metadata_release(__scm->dev,
> > + (struct qcom_pas_context *)ctx);
> > +}
> > EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
> >
> > -/**
> > - * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
> > - * for firmware loading
> > - * @pas_id: peripheral authentication service id
> > - * @addr: start address of memory area to prepare
> > - * @size: size of the memory area to prepare
> > - *
> > - * Returns 0 on success.
> > - */
> > -int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
> > +static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id,
> > + phys_addr_t addr, phys_addr_t size)
> > {
> > int ret;
> > struct qcom_scm_desc desc = {
> > @@ -768,7 +721,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
> > if (ret)
> > goto disable_clk;
> >
> > - ret = qcom_scm_call(__scm->dev, &desc, &res);
> > + ret = qcom_scm_call(dev, &desc, &res);
> > qcom_scm_bw_disable();
> >
> > disable_clk:
> > @@ -776,9 +729,15 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
> >
> > return ret ? : res.result[0];
> > }
> > +
> > +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
> > +{
> > + return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size);
> > +}
> > EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
> >
> > -static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
> > +static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id,
> > + void *input_rt_tzm,
> > size_t input_rt_size,
> > size_t *output_rt_size)
> > {
> > @@ -813,7 +772,7 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
> > * with output_rt_tzm buffer with res.result[2] size however, It should not
> > * be of unresonable size.
> > */
> > - ret = qcom_scm_call(__scm->dev, &desc, &res);
> > + ret = qcom_scm_call(dev, &desc, &res);
> > if (!ret && res.result[2] > SZ_1G) {
> > ret = -E2BIG;
> > goto free_output_rt;
> > @@ -830,51 +789,11 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
> > return ret ? ERR_PTR(ret) : output_rt_tzm;
> > }
> >
> > -/**
> > - * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
> > - * for a given peripheral.
> > - *
> > - * Qualcomm remote processor may rely on both static and dynamic resources for
> > - * its functionality. Static resources typically refer to memory-mapped addresses
> > - * required by the subsystem and are often embedded within the firmware binary
> > - * and dynamic resources, such as shared memory in DDR etc., are determined at
> > - * runtime during the boot process.
> > - *
> > - * On Qualcomm Technologies devices, it's possible that static resources are not
> > - * embedded in the firmware binary and instead are provided by TrustZone However,
> > - * dynamic resources are always expected to come from TrustZone. This indicates
> > - * that for Qualcomm devices, all resources (static and dynamic) will be provided
> > - * by TrustZone via the SMC call.
> > - *
> > - * If the remote processor firmware binary does contain static resources, they
> > - * should be passed in input_rt. These will be forwarded to TrustZone for
> > - * authentication. TrustZone will then append the dynamic resources and return
> > - * the complete resource table in output_rt_tzm.
> > - *
> > - * If the remote processor firmware binary does not include a resource table,
> > - * the caller of this function should set input_rt as NULL and input_rt_size
> > - * as zero respectively.
> > - *
> > - * More about documentation on resource table data structures can be found in
> > - * include/linux/remoteproc.h
> > - *
> > - * @ctx: PAS context
> > - * @pas_id: peripheral authentication service id
> > - * @input_rt: resource table buffer which is present in firmware binary
> > - * @input_rt_size: size of the resource table present in firmware binary
> > - * @output_rt_size: TrustZone expects caller should pass worst case size for
> > - * the output_rt_tzm.
> > - *
> > - * Return:
> > - * On success, returns a pointer to the allocated buffer containing the final
> > - * resource table and output_rt_size will have actual resource table size from
> > - * TrustZone. The caller is responsible for freeing the buffer. On failure,
> > - * returns ERR_PTR(-errno).
> > - */
> > -struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
> > - void *input_rt,
> > - size_t input_rt_size,
> > - size_t *output_rt_size)
> > +static void *__qcom_scm_pas_get_rsc_table2(struct device *dev,
> > + struct qcom_pas_context *ctx,
> > + void *input_rt,
> > + size_t input_rt_size,
> > + size_t *output_rt_size)
> > {
> > struct resource_table empty_rsc = {};
> > size_t size = SZ_16K;
> > @@ -909,11 +828,12 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
> >
> > memcpy(input_rt_tzm, input_rt, input_rt_size);
> >
> > - output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm,
> > + output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
> > + input_rt_tzm,
> > input_rt_size, &size);
> > if (PTR_ERR(output_rt_tzm) == -EOVERFLOW)
> > /* Try again with the size requested by the TZ */
> > - output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id,
> > + output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
> > input_rt_tzm,
> > input_rt_size,
> > &size);
> > @@ -943,16 +863,20 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
> >
> > return ret ? ERR_PTR(ret) : tbl_ptr;
> > }
> > +
> > +struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
> > + void *input_rt,
> > + size_t input_rt_size,
> > + size_t *output_rt_size)
> > +{
> > + return __qcom_scm_pas_get_rsc_table2(__scm->dev,
> > + (struct qcom_pas_context *)ctx,
> > + input_rt, input_rt_size,
> > + output_rt_size);
> > +}
> > EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
> >
> > -/**
> > - * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
> > - * and reset the remote processor
> > - * @pas_id: peripheral authentication service id
> > - *
> > - * Return 0 on success.
> > - */
> > -int qcom_scm_pas_auth_and_reset(u32 pas_id)
> > +static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id)
> > {
> > int ret;
> > struct qcom_scm_desc desc = {
> > @@ -972,7 +896,7 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
> > if (ret)
> > goto disable_clk;
> >
> > - ret = qcom_scm_call(__scm->dev, &desc, &res);
> > + ret = qcom_scm_call(dev, &desc, &res);
> > qcom_scm_bw_disable();
> >
> > disable_clk:
> > @@ -980,28 +904,15 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
> >
> > return ret ? : res.result[0];
> > }
> > +
> > +int qcom_scm_pas_auth_and_reset(u32 pas_id)
> > +{
> > + return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id);
> > +}
> > EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
> >
> > -/**
> > - * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
> > - * remote processor
> > - *
> > - * @ctx: Context saved during call to qcom_scm_pas_context_init()
> > - *
> > - * This function performs the necessary steps to prepare a PAS subsystem,
> > - * authenticate it using the provided metadata, and initiate a reset sequence.
> > - *
> > - * It should be used when Linux is in control setting up the IOMMU hardware
> > - * for remote subsystem during secure firmware loading processes. The preparation
> > - * step sets up a shmbridge over the firmware memory before TrustZone accesses the
> > - * firmware memory region for authentication. The authentication step verifies
> > - * the integrity and authenticity of the firmware or configuration using secure
> > - * metadata. Finally, the reset step ensures the subsystem starts in a clean and
> > - * sane state.
> > - *
> > - * Return: 0 on success, negative errno on failure.
> > - */
> > -int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
> > +static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
> > + struct qcom_pas_context *ctx)
> > {
> > u64 handle;
> > int ret;
> > @@ -1012,7 +923,7 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
> > * memory region and then invokes a call to TrustZone to authenticate.
> > */
> > if (!ctx->use_tzmem)
> > - return qcom_scm_pas_auth_and_reset(ctx->pas_id);
> > + return __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
> >
> > /*
> > * When Linux runs @ EL2 Linux must create the shmbridge itself and then
> > @@ -1022,20 +933,45 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
> > if (ret)
> > return ret;
> >
> > - ret = qcom_scm_pas_auth_and_reset(ctx->pas_id);
> > + ret = __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
> > qcom_tzmem_shm_bridge_delete(handle);
> >
> > return ret;
> > }
> > +
> > +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
> > +{
> > + return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev,
> > + (struct qcom_pas_context *)ctx);
> > +}
> > EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
> >
> > -/**
> > - * qcom_scm_pas_shutdown() - Shut down the remote processor
> > - * @pas_id: peripheral authentication service id
> > - *
> > - * Returns 0 on success.
> > - */
> > -int qcom_scm_pas_shutdown(u32 pas_id)
> > +static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state,
> > + u32 pas_id)
> > +{
> > + struct qcom_scm_desc desc = {
> > + .svc = QCOM_SCM_SVC_BOOT,
> > + .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
> > + .arginfo = QCOM_SCM_ARGS(2),
> > + .args[0] = state,
> > + .args[1] = pas_id,
> > + .owner = ARM_SMCCC_OWNER_SIP,
> > + };
> > + struct qcom_scm_res res;
> > + int ret;
> > +
> > + ret = qcom_scm_call(dev, &desc, &res);
> > +
> > + return ret ? : res.result[0];
> > +}
> > +
> > +int qcom_scm_set_remote_state(u32 state, u32 id)
>
> s/id/pas_id
Ack.
>
> > +{
> > + return __qcom_scm_pas_set_remote_state(__scm->dev, state, id);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
> > +
> > +static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id)
> > {
> > int ret;
> > struct qcom_scm_desc desc = {
> > @@ -1055,7 +991,7 @@ int qcom_scm_pas_shutdown(u32 pas_id)
> > if (ret)
> > goto disable_clk;
> >
> > - ret = qcom_scm_call(__scm->dev, &desc, &res);
> > + ret = qcom_scm_call(dev, &desc, &res);
> > qcom_scm_bw_disable();
> >
> > disable_clk:
> > @@ -1063,16 +999,14 @@ int qcom_scm_pas_shutdown(u32 pas_id)
> >
> > return ret ? : res.result[0];
> > }
> > +
> > +int qcom_scm_pas_shutdown(u32 pas_id)
> > +{
> > + return __qcom_scm_pas_shutdown(__scm->dev, pas_id);
> > +}
> > EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
> >
> > -/**
> > - * qcom_scm_pas_supported() - Check if the peripheral authentication service is
> > - * available for the given peripherial
> > - * @pas_id: peripheral authentication service id
> > - *
> > - * Returns true if PAS is supported for this peripheral, otherwise false.
> > - */
> > -bool qcom_scm_pas_supported(u32 pas_id)
> > +static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id)
> > {
> > int ret;
> > struct qcom_scm_desc desc = {
> > @@ -1084,16 +1018,49 @@ bool qcom_scm_pas_supported(u32 pas_id)
> > };
> > struct qcom_scm_res res;
> >
> > - if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
> > + if (!__qcom_scm_is_call_available(dev, QCOM_SCM_SVC_PIL,
> > QCOM_SCM_PIL_PAS_IS_SUPPORTED))
> > return false;
> >
> > - ret = qcom_scm_call(__scm->dev, &desc, &res);
> > + ret = qcom_scm_call(dev, &desc, &res);
> >
> > return ret ? false : !!res.result[0];
> > }
> > +
> > +bool qcom_scm_pas_supported(u32 pas_id)
> > +{
> > + return __qcom_scm_pas_supported(__scm->dev, pas_id);
> > +}
> > EXPORT_SYMBOL_GPL(qcom_scm_pas_supported);
> >
> > +static struct qcom_pas_ops qcom_pas_ops_scm = {
> > + .drv_name = "qcom_scm",
> > + .supported = __qcom_scm_pas_supported,
> > + .init_image = __qcom_scm_pas_init_image2,
> > + .mem_setup = __qcom_scm_pas_mem_setup,
> > + .get_rsc_table = __qcom_scm_pas_get_rsc_table2,
> > + .auth_and_reset = __qcom_scm_pas_auth_and_reset,
> > + .prepare_and_auth_reset = __qcom_scm_pas_prepare_and_auth_reset,
> > + .set_remote_state = __qcom_scm_pas_set_remote_state,
> > + .shutdown = __qcom_scm_pas_shutdown,
> > + .metadata_release = __qcom_scm_pas_metadata_release,
> > +};
> > +
> > +/**
> > + * qcom_scm_is_pas_available() - Check if the peripheral authentication service
> > + * is available via SCM or not
> > + *
> > + * Returns true if PAS is available, otherwise false.
> > + */
> > +static bool qcom_scm_is_pas_available(void)
> > +{
> > + if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL,
> > + QCOM_SCM_PIL_PAS_AUTH_AND_RESET))
>
> QCOM_SCM_PIL_PAS_IS_SUPPORTED ?
This SCM call is there to rather check if PAS is supported for a
particular co-processor ID but not the overall SCM PAS functionality.
And this API isn't used by every client driver for status check.
The PAS auth and reset SCM call is surely supported on every QTEE/TZ
implementation, that's why I used it as a reference for checking SCM PAS
support.
-Sumit
>
>
> > + return false;
> > +
> > + return true;
> > +}
> > +
> > static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
> > {
> > struct qcom_scm_desc desc = {
> > @@ -2836,6 +2803,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
> >
> > __get_convention();
> >
> > + if (qcom_scm_is_pas_available()) {
>
> Use qcom_scm_pas_supported() and remove qcom_scm_is_pas_available()..
>
> > + qcom_pas_ops_scm.dev = scm->dev;
> > + qcom_pas_ops_register(&qcom_pas_ops_scm);
> > + }
> > +
> > /*
> > * If "download mode" is requested, from this point on warmboot
> > * will cause the boot stages to enter download mode, unless
> > @@ -2875,6 +2847,7 @@ static void qcom_scm_shutdown(struct platform_device *pdev)
> > {
> > /* Clean shutdown, disable download mode to allow normal restart */
> > qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP);
> > + qcom_pas_ops_unregister();
> > }
> >
> > static const struct of_device_id qcom_scm_dt_match[] = {
> > --
> > 2.51.0
> >
>
> With above changes,
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>
> --
> -Mukesh Ojha
>
^ permalink raw reply
* Re: [PATCH v4 00/15] firmware: qcom: Add OP-TEE PAS service support
From: Sumit Garg @ 2026-05-01 13:34 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260429065926.5iliebd3d2j6bong@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 12:29:26PM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:48PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Qcom platforms has the legacy of using non-standard SCM calls
> > splintered over the various kernel drivers. These SCM calls aren't
> > compliant with the standard SMC calling conventions which is a
> > prerequisite to enable migration to the FF-A specifications from Arm.
> >
> > OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
> > support these non-standard SCM calls. And even for newer architectures
> > using S-EL2 with Hafnium support, QTEE won't be able to support SCM
> > calls either with FF-A requirements coming in. And with both OP-TEE
> > and QTEE drivers well integrated in the TEE subsystem, it makes further
> > sense to reuse the TEE bus client drivers infrastructure.
> >
> > The added benefit of TEE bus infrastructure is that there is support
> > for discoverable/enumerable services. With that client drivers don't
> > have to manually invoke a special SCM call to know the service status.
> >
> > So enable the generic Peripheral Authentication Service (PAS) provided
> > by the firmware. It acts as the common layer with different TZ
> > backends plugged in whether it's an SCM implementation or a proper
> > TEE bus based PAS service implementation.
> >
> > The TEE PAS service ABI is designed to be extensible with additional API
> > as PTA_QCOM_PAS_CAPABILITIES. This allows to accommodate any future
> > extensions of the PAS service needed while still maintaining backwards
> > compatibility.
> >
> > Currently OP-TEE support is being added to provide the backend PAS
> > service implementation which can be found as part of this PR [1].
> > This implementation has been tested on Kodiak/RB3Gen2 board with lemans
> > EVK board being the next target. In addition to that WIN/IPQ targets
> > planning to use OP-TEE will use this service too. Surely the backwards
> > compatibility is maintained and tested for SCM backend.
> >
> > Note that kernel PAS service support while running in EL2 is at parity
> > among OP-TEE vs QTEE. Especially the media (venus/iris) support depends
> > on proper IOMMU support being worked out on the PAS client end.
> >
> > Patch summary:
> > - Patch #1: adds Kodiak EL2 overlay since boot stack with TF-A/OP-TEE
> > only allow UEFI and Linux to boot in EL2.
> > - Patch #2: adds generic PAS service.
> > - Patch #3: migrates SCM backend to generic PAS service.
> > - Patch #4: adds TEE/OP-TEE backend for generic PAS service.
> > - Patch #5-#13: migrates all client drivers to generic PAS service.
> > - Patch #14: drops legacy PAS SCM exported APIs.
>
>
> Gave it a try to test the series on Lemans with Gunyah as well as KVM
> hypervisor and all the remote processor are coming up successfully.
>
> Feel free to carry
>
> Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
>
> for the Series.
>
Thanks for taking time to test this patch-set.
-Sumit
>
> > The patch-set is based on v7.1-rc1 tag and can be found in git tree here
> > [2].
> >
> > Merge strategy:
> >
> > It is expected due to APIs dependency, the entire patch-set to go via
> > the Qcom tree. All other subsystem maintainers, it will be great if I
> > can get acks for the corresponding subsystem patches.
> >
> > [1] https://github.com/OP-TEE/optee_os/pull/7721
> > [2] https://git.kernel.org/pub/scm/linux/kernel/git/sumit.garg/linux.git/log/?h=qcom-pas-v4
> >
> > ---
> > Changes in v4:
> > - Incorporate misc. comments on patch #4.
> > - Picked up an ack for patch #10.
> > - Clarify in cover letter about state of media support.
> >
> > Changes in v3:
> > - Incorporated some style and misc. comments for patch #2, #3 and #4.
> > - Add QCOM_PAS Kconfig dependency for various subsystems.
> > - Switch from pseudo TA to proper TA invoke commands.
> >
> > Changes in v2:
> > - Fixed kernel doc warnings.
> > - Polish commit message and comments for patch #2.
> > - Pass proper PAS ID in set_remote_state API for media firmware drivers.
> > - Added Maintainer entry and dropped MODULE_AUTHOR.
> >
> > Mukesh Ojha (1):
> > arm64: dts: qcom: kodiak: Add EL2 overlay
> >
> > Sumit Garg (14):
> > firmware: qcom: Add a generic PAS service
> > firmware: qcom_scm: Migrate to generic PAS service
> > firmware: qcom: Add a PAS TEE service
> > remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs
> > remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs
> > soc: qcom: mdtloader: Switch to generic PAS TZ APIs
> > remoteproc: qcom_wcnss: Switch to generic PAS TZ APIs
> > remoteproc: qcom: Select QCOM_PAS generic service
> > drm/msm: Switch to generic PAS TZ APIs
> > media: qcom: Switch to generic PAS TZ APIs
> > net: ipa: Switch to generic PAS TZ APIs
> > wifi: ath12k: Switch to generic PAS TZ APIs
> > firmware: qcom_scm: Remove SCM PAS wrappers
> > MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service
> >
> > MAINTAINERS | 9 +
> > arch/arm64/boot/dts/qcom/Makefile | 2 +
> > arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++
> > drivers/firmware/qcom/Kconfig | 19 +
> > drivers/firmware/qcom/Makefile | 2 +
> > drivers/firmware/qcom/qcom_pas.c | 288 +++++++++++
> > drivers/firmware/qcom/qcom_pas.h | 50 ++
> > drivers/firmware/qcom/qcom_pas_tee.c | 479 ++++++++++++++++++
> > drivers/firmware/qcom/qcom_scm.c | 302 ++++-------
> > drivers/gpu/drm/msm/Kconfig | 1 +
> > drivers/gpu/drm/msm/adreno/a5xx_gpu.c | 4 +-
> > drivers/gpu/drm/msm/adreno/adreno_gpu.c | 11 +-
> > drivers/media/platform/qcom/iris/Kconfig | 25 +-
> > .../media/platform/qcom/iris/iris_firmware.c | 9 +-
> > drivers/media/platform/qcom/venus/Kconfig | 1 +
> > drivers/media/platform/qcom/venus/firmware.c | 11 +-
> > drivers/net/ipa/Kconfig | 2 +-
> > drivers/net/ipa/ipa_main.c | 13 +-
> > drivers/net/wireless/ath/ath12k/Kconfig | 2 +-
> > drivers/net/wireless/ath/ath12k/ahb.c | 8 +-
> > drivers/remoteproc/Kconfig | 1 +
> > drivers/remoteproc/qcom_q6v5_mss.c | 5 +-
> > drivers/remoteproc/qcom_q6v5_pas.c | 51 +-
> > drivers/remoteproc/qcom_wcnss.c | 12 +-
> > drivers/soc/qcom/mdt_loader.c | 12 +-
> > include/linux/firmware/qcom/qcom_pas.h | 43 ++
> > include/linux/firmware/qcom/qcom_scm.h | 29 --
> > include/linux/soc/qcom/mdt_loader.h | 6 +-
> > 28 files changed, 1115 insertions(+), 317 deletions(-)
> > create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso
> > create mode 100644 drivers/firmware/qcom/qcom_pas.c
> > create mode 100644 drivers/firmware/qcom/qcom_pas.h
> > create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
> > create mode 100644 include/linux/firmware/qcom/qcom_pas.h
> >
> > --
> > 2.51.0
> >
>
> --
> -Mukesh Ojha
>
^ permalink raw reply
* Re: [PATCH v4 02/15] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-05-01 13:33 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260428211119.megzlvaw23uw3gnn@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 02:41:19AM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:50PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Qcom platforms has the legacy of using non-standard SCM calls
> > splintered over the various kernel drivers. These SCM calls aren't
> > compliant with the standard SMC calling conventions which is a
> > prerequisite to enable migration to the FF-A specifications from Arm.
> >
> > OP-TEE as an alternative trusted OS to Qualcomm TEE (QTEE) can't
> > support these non-standard SCM calls. And even for newer architectures
> > using S-EL2 with Hafnium support, QTEE won't be able to support SCM
> > calls either with FF-A requirements coming in. And with both OP-TEE
> > and QTEE drivers well integrated in the TEE subsystem, it makes further
> > sense to reuse the TEE bus client drivers infrastructure.
> >
> > The added benefit of TEE bus infrastructure is that there is support
> > for discoverable/enumerable services. With that client drivers don't
> > have to manually invoke a special SCM call to know the service status.
> >
> > So enable the generic Peripheral Authentication Service (PAS) provided
> > by the firmware. It acts as the common layer with different TZ
> > backends plugged in whether it's an SCM implementation or a proper
> > TEE bus based PAS service implementation.
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/firmware/qcom/Kconfig | 8 +
> > drivers/firmware/qcom/Makefile | 1 +
> > drivers/firmware/qcom/qcom_pas.c | 288 +++++++++++++++++++++++++
> > drivers/firmware/qcom/qcom_pas.h | 50 +++++
> > include/linux/firmware/qcom/qcom_pas.h | 43 ++++
> > 5 files changed, 390 insertions(+)
> > create mode 100644 drivers/firmware/qcom/qcom_pas.c
> > create mode 100644 drivers/firmware/qcom/qcom_pas.h
> > create mode 100644 include/linux/firmware/qcom/qcom_pas.h
> >
> > diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
> > index b477d54b495a..8653639d06db 100644
> > --- a/drivers/firmware/qcom/Kconfig
> > +++ b/drivers/firmware/qcom/Kconfig
> > @@ -6,6 +6,14 @@
> >
> > menu "Qualcomm firmware drivers"
> >
> > +config QCOM_PAS
> > + tristate
> > + help
> > + Enable the generic Peripheral Authentication Service (PAS) provided
> > + by the firmware. It acts as the common layer with different TZ
> > + backends plugged in whether it's an SCM implementation or a proper
> > + TEE bus based PAS service implementation.
> > +
> > config QCOM_SCM
> > select QCOM_TZMEM
> > tristate
> > diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
> > index 0be40a1abc13..dc5ab45f906a 100644
> > --- a/drivers/firmware/qcom/Makefile
> > +++ b/drivers/firmware/qcom/Makefile
> > @@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
> > obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o
> > obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
> > obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
> > +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o
> > diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c
> > new file mode 100644
> > index 000000000000..caf7fff33e5c
> > --- /dev/null
> > +++ b/drivers/firmware/qcom/qcom_pas.c
> > @@ -0,0 +1,288 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#include <linux/device/devres.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +
> > +#include "qcom_pas.h"
> > +
> > +static struct qcom_pas_ops *ops_ptr;
> > +
> > +/**
> > + * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
> > + * context for a given peripheral
> > + *
> > + * PAS context is device-resource managed, so the caller does not need
> > + * to worry about freeing the context memory.
> > + *
> > + * @dev: PAS firmware device
> > + * @pas_id: peripheral authentication service id
> > + * @mem_phys: Subsystem reserve memory start address
> > + * @mem_size: Subsystem reserve memory size
> > + *
> > + * Return: The new PAS context, or ERR_PTR() on failure.
> > + */
> > +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
> > + u32 pas_id,
> > + phys_addr_t mem_phys,
> > + size_t mem_size)
> > +{
> > + struct qcom_pas_context *ctx;
> > +
> > + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> > + if (!ctx)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + ctx->dev = dev;
> > + ctx->pas_id = pas_id;
> > + ctx->mem_phys = mem_phys;
> > + ctx->mem_size = mem_size;
> > +
> > + return ctx;
> > +}
> > +EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
> > +
> > +/**
> > + * qcom_pas_init_image() - Initialize peripheral authentication service state
> > + * machine for a given peripheral, using the metadata
> > + * @pas_id: peripheral authentication service id
> > + * @metadata: pointer to memory containing ELF header, program header table
> > + * and optional blob of data used for authenticating the metadata
> > + * and the rest of the firmware
> > + * @size: size of the metadata
> > + * @ctx: optional pas context
> > + *
> > + * Return: 0 on success.
> > + *
> > + * Upon successful return, the PAS metadata context (@ctx) will be used to
> > + * track the metadata allocation, this needs to be released by invoking
> > + * qcom_pas_metadata_release() by the caller.
> > + */
> > +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> > + struct qcom_pas_context *ctx)
> > +{
> > + if (!ops_ptr)
> > + return -ENODEV;
> > +
> > + return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_init_image);
> > +
> > +/**
> > + * qcom_pas_metadata_release() - release metadata context
> > + * @ctx: pas context
> > + */
> > +void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
> > +{
> > + if (!ctx || !ctx->ptr || !ops_ptr)
>
> reverse order..
>
> > + return;
> > +
> > + ops_ptr->metadata_release(ops_ptr->dev, ctx);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
> > +
> > +/**
> > + * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
> > + * for firmware loading
> > + * @pas_id: peripheral authentication service id
> > + * @addr: start address of memory area to prepare
> > + * @size: size of the memory area to prepare
> > + *
> > + * Return: 0 on success.
> > + */
> > +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
> > +{
> > + if (!ops_ptr)
> > + return -ENODEV;
> > +
> > + return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
> > +
> > +/**
> > + * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
> > + * for a given peripheral.
> > + *
> > + * Qualcomm remote processor may rely on both static and dynamic resources for
> > + * its functionality. Static resources typically refer to memory-mapped
> > + * addresses required by the subsystem and are often embedded within the
> > + * firmware binary and dynamic resources, such as shared memory in DDR etc.,
> > + * are determined at runtime during the boot process.
> > + *
> > + * On Qualcomm Technologies devices, it's possible that static resources are
> > + * not embedded in the firmware binary and instead are provided by TrustZone.
> > + * However, dynamic resources are always expected to come from TrustZone. This
> > + * indicates that for Qualcomm devices, all resources (static and dynamic) will
> > + * be provided by TrustZone PAS service.
> > + *
> > + * If the remote processor firmware binary does contain static resources, they
> > + * should be passed in input_rt. These will be forwarded to TrustZone for
> > + * authentication. TrustZone will then append the dynamic resources and return
> > + * the complete resource table in output_rt_tzm.
> > + *
> > + * If the remote processor firmware binary does not include a resource table,
> > + * the caller of this function should set input_rt as NULL and input_rt_size
> > + * as zero respectively.
> > + *
> > + * More about documentation on resource table data structures can be found in
> > + * include/linux/remoteproc.h
> > + *
> > + * @ctx: PAS context
> > + * @pas_id: peripheral authentication service id
> > + * @input_rt: resource table buffer which is present in firmware binary
> > + * @input_rt_size: size of the resource table present in firmware binary
> > + * @output_rt_size: TrustZone expects caller should pass worst case size for
> > + * the output_rt_tzm.
> > + *
> > + * Return:
> > + * On success, returns a pointer to the allocated buffer containing the final
> > + * resource table and output_rt_size will have actual resource table size from
> > + * TrustZone. The caller is responsible for freeing the buffer. On failure,
> > + * returns ERR_PTR(-errno).
> > + */
> > +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
> > + void *input_rt,
> > + size_t input_rt_size,
> > + size_t *output_rt_size)
> > +{
> > + if (!ctx)
> > + return ERR_PTR(-EINVAL);
> > + if (!ops_ptr)
> > + return ERR_PTR(-ENODEV);
>
> same as below
>
> > +
> > + return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
> > + input_rt_size, output_rt_size);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
> > +
> > +/**
> > + * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
> > + * and reset the remote processor
> > + * @pas_id: peripheral authentication service id
> > + *
> > + * Return: 0 on success.
> > + */
> > +int qcom_pas_auth_and_reset(u32 pas_id)
> > +{
> > + if (!ops_ptr)
> > + return -ENODEV;
> > +
> > + return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
> > +
> > +/**
> > + * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
> > + * remote processor
> > + *
> > + * @ctx: Context saved during call to qcom_scm_pas_context_init()
> > + *
> > + * This function performs the necessary steps to prepare a PAS subsystem,
> > + * authenticate it using the provided metadata, and initiate a reset sequence.
> > + *
> > + * It should be used when Linux is in control setting up the IOMMU hardware
> > + * for remote subsystem during secure firmware loading processes. The
> > + * preparation step sets up a shmbridge over the firmware memory before
> > + * TrustZone accesses the firmware memory region for authentication. The
> > + * authentication step verifies the integrity and authenticity of the firmware
> > + * or configuration using secure metadata. Finally, the reset step ensures the
> > + * subsystem starts in a clean and sane state.
> > + *
> > + * Return: 0 on success, negative errno on failure.
> > + */
> > +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
> > +{
> > + if (!ctx)
> > + return -EINVAL;
> > + if (!ops_ptr)
> > + return -ENODEV;
>
> They should be checked in reverse order, no point in checking ctx if
> ops_ptr is NULL .,
Ack.
>
> > +
> > + return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
> > +
> > +/**
> > + * qcom_pas_set_remote_state() - Set the remote processor state
> > + * @state: peripheral state
> > + * @pas_id: peripheral authentication service id
> > + *
> > + * Return: 0 on success.
> > + */
> > +int qcom_pas_set_remote_state(u32 state, u32 pas_id)
> > +{
> > + if (!ops_ptr)
> > + return -ENODEV;
> > +
> > + return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
> > +
> > +/**
> > + * qcom_pas_shutdown() - Shut down the remote processor
> > + * @pas_id: peripheral authentication service id
> > + *
> > + * Return: 0 on success.
> > + */
> > +int qcom_pas_shutdown(u32 pas_id)
> > +{
> > + if (!ops_ptr)
> > + return -ENODEV;
> > +
> > + return ops_ptr->shutdown(ops_ptr->dev, pas_id);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
> > +
> > +/**
> > + * qcom_pas_supported() - Check if the peripheral authentication service is
> > + * available for the given peripheral
> > + * @pas_id: peripheral authentication service id
> > + *
> > + * Return: true if PAS is supported for this peripheral, otherwise false.
> > + */
> > +bool qcom_pas_supported(u32 pas_id)
> > +{
> > + if (!ops_ptr)
> > + return false;
> > +
> > + return ops_ptr->supported(ops_ptr->dev, pas_id);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_supported);
> > +
> > +bool qcom_pas_is_available(void)
> > +{
> > + /*
> > + * The barrier for ops_ptr is intended to synchronize the data stores
> > + * for the ops data structure when client drivers are in parallel
> > + * checking for PAS service availability.
> > + *
> > + * Once the PAS backend becomes available, it is allowed for multiple
> > + * threads to enter TZ for parallel bringup of co-processors during
> > + * boot.
> > + */
> > + return !!smp_load_acquire(&ops_ptr);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_is_available);
> > +
> > +void qcom_pas_ops_register(struct qcom_pas_ops *ops)
> > +{
> > + if (!qcom_pas_is_available())
> > + /* Paired with smp_load_acquire() in qcom_pas_is_available() */
> > + smp_store_release(&ops_ptr, ops);
> > + else
> > + pr_err("qcom_pas: ops already registered\n");
>
> pr_err("qcom_pas: ops already registered by %s\n", ops_ptr->drv_name);
>
Ack.
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
> > +
> > +void qcom_pas_ops_unregister(void)
> > +{
> > + /* Paired with smp_load_acquire() in qcom_pas_is_available() */
> > + smp_store_release(&ops_ptr, NULL);
> > +}
> > +EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Qualcomm common TZ PAS driver");
>
> generic ??
Naming is hard but your suggestion sounds more reasonable.
>
> > diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h
> > new file mode 100644
> > index 000000000000..8643e2760602
> > --- /dev/null
> > +++ b/drivers/firmware/qcom/qcom_pas.h
> > @@ -0,0 +1,50 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
> > +
> > +#ifndef __QCOM_PAS_INT_H
> > +#define __QCOM_PAS_INT_H
> > +
> > +struct device;
> > +
> > +/**
> > + * struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops
> > + * @drv_name: PAS driver name.
> > + * @dev: PAS device pointer.
> > + * @supported: Peripheral supported callback.
> > + * @init_image: Peripheral image initialization callback.
> > + * @mem_setup: Peripheral memory setup callback.
> > + * @get_rsc_table: Peripheral get resource table callback.
> > + * @prepare_and_auth_reset: Peripheral prepare firmware authentication and
> > + * reset callback.
> > + * @auth_and_reset: Peripheral firmware authentication and reset
> > + * callback.
> > + * @set_remote_state: Peripheral set remote state callback.
> > + * @shutdown: Peripheral shutdown callback.
> > + * @metadata_release: Image metadata release callback.
> > + */
> > +struct qcom_pas_ops {
> > + const char *drv_name;
> > + struct device *dev;
> > + bool (*supported)(struct device *dev, u32 pas_id);
> > + int (*init_image)(struct device *dev, u32 pas_id, const void *metadata,
> > + size_t size, struct qcom_pas_context *ctx);
> > + int (*mem_setup)(struct device *dev, u32 pas_id, phys_addr_t addr,
> > + phys_addr_t size);
> > + void *(*get_rsc_table)(struct device *dev, struct qcom_pas_context *ctx,
> > + void *input_rt, size_t input_rt_size,
> > + size_t *output_rt_size);
> > + int (*prepare_and_auth_reset)(struct device *dev,
> > + struct qcom_pas_context *ctx);
> > + int (*auth_and_reset)(struct device *dev, u32 pas_id);
> > + int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id);
> > + int (*shutdown)(struct device *dev, u32 pas_id);
> > + void (*metadata_release)(struct device *dev,
> > + struct qcom_pas_context *ctx);
> > +};
> > +
> > +void qcom_pas_ops_register(struct qcom_pas_ops *ops);
> > +void qcom_pas_ops_unregister(void);
> > +
> > +#endif /* __QCOM_PAS_INT_H */
> > diff --git a/include/linux/firmware/qcom/qcom_pas.h b/include/linux/firmware/qcom/qcom_pas.h
> > new file mode 100644
> > index 000000000000..65b1c9564458
> > --- /dev/null
> > +++ b/include/linux/firmware/qcom/qcom_pas.h
> > @@ -0,0 +1,43 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved.
> > + * Copyright (C) 2015 Linaro Ltd.
> > + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
> > + */
>
> Here, you kept the copyright but not in the C file.., from my view, both qcom_pas.c
> and qcom_pas.h are derivative work(>50%) and should carry the original license while
> drivers/firmware/qcom/qcom_pas.h is new work...
I think we discussed this in earlier iteration. The code in the C file
is mostly wrappers which are new but API comments are carried over. If
you insist then I will carry over the copyright.
>
> > +
> > +#ifndef __QCOM_PAS_H
> > +#define __QCOM_PAS_H
> > +
> > +#include <linux/err.h>
> > +#include <linux/types.h>
> > +
> > +struct qcom_pas_context {
> > + struct device *dev;
> > + u32 pas_id;
> > + phys_addr_t mem_phys;
> > + size_t mem_size;
> > + void *ptr;
> > + dma_addr_t phys;
> > + ssize_t size;
> > + bool use_tzmem;
> > +};
> > +
> > +bool qcom_pas_is_available(void);
> > +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
> > + u32 pas_id,
> > + phys_addr_t mem_phys,
> > + size_t mem_size);
> > +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
> > + struct qcom_pas_context *ctx);
> > +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
> > + void *input_rt, size_t input_rt_size,
> > + size_t *output_rt_size);
> > +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size);
> > +int qcom_pas_auth_and_reset(u32 pas_id);
> > +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx);
> > +int qcom_pas_set_remote_state(u32 state, u32 pas_id);
> > +int qcom_pas_shutdown(u32 pas_id);
> > +bool qcom_pas_supported(u32 pas_id);
> > +void qcom_pas_metadata_release(struct qcom_pas_context *ctx);
> > +
> > +#endif /* __QCOM_PAS_H */
> > --
> > 2.51.0
> >
>
> With above change,
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>
Thanks.
-Sumit
^ permalink raw reply
* Re: [PATCH v4 11/15] media: qcom: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-05-01 13:26 UTC (permalink / raw)
To: Mukesh Ojha
Cc: andersson, konradybcio, linux-arm-msm, devicetree, dri-devel,
freedreno, linux-media, netdev, linux-wireless, ath12k,
linux-remoteproc, robh, krzk+dt, conor+dt, robin.clark, sean,
akhilpo, lumag, abhinav.kumar, jesszhan0024, marijn.suijten,
airlied, simona, vikash.garodia, dikshita.agarwal, bod, mchehab,
elder, andrew+netdev, davem, edumazet, kuba, pabeni, jjohnson,
mathieu.poirier, trilokkumar.soni, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260428193714.sg5n3tntww2nuquu@hu-mojha-hyd.qualcomm.com>
On Wed, Apr 29, 2026 at 01:07:14AM +0530, Mukesh Ojha wrote:
> On Mon, Apr 27, 2026 at 03:25:59PM +0530, Sumit Garg wrote:
> > From: Sumit Garg <sumit.garg@oss.qualcomm.com>
> >
> > Switch qcom media client drivers over to generic PAS TZ APIs. Generic PAS
> > TZ service allows to support multiple TZ implementation backends like QTEE
> > based SCM PAS service, OP-TEE based PAS service and any further future TZ
> > backend service.
> >
> > Along with that pass proper PAS ID to set_remote_state API. As per testing
> > the SCM backend just ignores it while OP-TEE makes use of it to for proper
> > book keeping purpose.
>
> When we use 'Along with' or 'while at it', patch is doing two things and
> not one.
Okay, I will split this into 2.
>
> >
> > Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
> > ---
> > drivers/media/platform/qcom/iris/Kconfig | 25 ++++++++++---------
> > .../media/platform/qcom/iris/iris_firmware.c | 9 ++++---
> > drivers/media/platform/qcom/venus/Kconfig | 1 +
> > drivers/media/platform/qcom/venus/firmware.c | 11 ++++----
> > 4 files changed, 25 insertions(+), 21 deletions(-)
> >
> > diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig
> > index 3c803a05305a..f54b759c18aa 100644
> > --- a/drivers/media/platform/qcom/iris/Kconfig
> > +++ b/drivers/media/platform/qcom/iris/Kconfig
> > @@ -1,13 +1,14 @@
> > config VIDEO_QCOM_IRIS
> > - tristate "Qualcomm iris V4L2 decoder driver"
> > - depends on VIDEO_DEV
> > - depends on ARCH_QCOM || COMPILE_TEST
> > - select V4L2_MEM2MEM_DEV
> > - select QCOM_MDT_LOADER if ARCH_QCOM
> > - select QCOM_SCM
> > - select VIDEOBUF2_DMA_CONTIG
> > - help
> > - This is a V4L2 driver for Qualcomm iris video accelerator
> > - hardware. It accelerates decoding operations on various
> > - Qualcomm SoCs.
> > - To compile this driver as a module choose m here.
> > + tristate "Qualcomm iris V4L2 decoder driver"
> > + depends on VIDEO_DEV
> > + depends on ARCH_QCOM || COMPILE_TEST
> > + select V4L2_MEM2MEM_DEV
> > + select QCOM_MDT_LOADER if ARCH_QCOM
> > + select QCOM_SCM
> > + select QCOM_PAS
> > + select VIDEOBUF2_DMA_CONTIG
> > + help
> > + This is a V4L2 driver for Qualcomm iris video accelerator
> > + hardware. It accelerates decoding operations on various
> > + Qualcomm SoCs.
> > + To compile this driver as a module choose m here.
>
> Here, Space replaced by Tabs just for one line.., should be fine.
Yeah, spaces aren't meant here.
>
>
> > diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
> > index 5f408024e967..856fa6a79064 100644
> > --- a/drivers/media/platform/qcom/iris/iris_firmware.c
> > +++ b/drivers/media/platform/qcom/iris/iris_firmware.c
> > @@ -4,6 +4,7 @@
> > */
> >
> > #include <linux/firmware.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/firmware/qcom/qcom_scm.h>
> > #include <linux/of_address.h>
> > #include <linux/of_reserved_mem.h>
> > @@ -79,7 +80,7 @@ int iris_fw_load(struct iris_core *core)
> > return -ENOMEM;
> > }
> >
> > - ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id);
> > + ret = qcom_pas_auth_and_reset(core->iris_platform_data->pas_id);
> > if (ret) {
> > dev_err(core->dev, "auth and reset failed: %d\n", ret);
> > return ret;
> > @@ -93,7 +94,7 @@ int iris_fw_load(struct iris_core *core)
> > cp_config->cp_nonpixel_size);
> > if (ret) {
> > dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret);
> > - qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
> > + qcom_pas_shutdown(core->iris_platform_data->pas_id);
> > return ret;
> > }
> > }
> > @@ -103,10 +104,10 @@ int iris_fw_load(struct iris_core *core)
> >
> > int iris_fw_unload(struct iris_core *core)
> > {
> > - return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
> > + return qcom_pas_shutdown(core->iris_platform_data->pas_id);
> > }
> >
> > int iris_set_hw_state(struct iris_core *core, bool resume)
> > {
> > - return qcom_scm_set_remote_state(resume, 0);
> > + return qcom_pas_set_remote_state(resume, core->irisi_platform_data->pas_id);
>
>
> Should be a separate change for qcom_pas_set_remote_state()
>
> > }
> > diff --git a/drivers/media/platform/qcom/venus/Kconfig b/drivers/media/platform/qcom/venus/Kconfig
> > index ffb731ecd48c..574172724e8f 100644
> > --- a/drivers/media/platform/qcom/venus/Kconfig
> > +++ b/drivers/media/platform/qcom/venus/Kconfig
> > @@ -6,6 +6,7 @@ config VIDEO_QCOM_VENUS
> > select OF_DYNAMIC if ARCH_QCOM
> > select QCOM_MDT_LOADER if ARCH_QCOM
> > select QCOM_SCM
> > + select QCOM_PAS
> > select VIDEOBUF2_DMA_CONTIG
> > select V4L2_MEM2MEM_DEV
> > help
> > diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
> > index 1de7436713ed..3c0727ea137d 100644
> > --- a/drivers/media/platform/qcom/venus/firmware.c
> > +++ b/drivers/media/platform/qcom/venus/firmware.c
> > @@ -12,6 +12,7 @@
> > #include <linux/of_reserved_mem.h>
> > #include <linux/platform_device.h>
> > #include <linux/of_device.h>
> > +#include <linux/firmware/qcom/qcom_pas.h>
> > #include <linux/firmware/qcom/qcom_scm.h>
> > #include <linux/sizes.h>
> > #include <linux/soc/qcom/mdt_loader.h>
> > @@ -58,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume)
> > int ret;
> >
> > if (core->use_tz) {
> > - ret = qcom_scm_set_remote_state(resume, 0);
> > + ret = qcom_pas_set_remote_state(resume, VENUS_PAS_ID);
>
> This too..
>
> > if (resume && ret == -EINVAL)
> > ret = 0;
> > return ret;
> > @@ -218,7 +219,7 @@ int venus_boot(struct venus_core *core)
> > int ret;
> >
> > if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ||
> > - (core->use_tz && !qcom_scm_is_available()))
> > + (core->use_tz && !qcom_pas_is_available()))
> > return -EPROBE_DEFER;
> >
> > ret = of_property_read_string_index(dev->of_node, "firmware-name", 0,
> > @@ -236,7 +237,7 @@ int venus_boot(struct venus_core *core)
> > core->fw.mem_phys = mem_phys;
> >
> > if (core->use_tz)
> > - ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID);
> > + ret = qcom_pas_auth_and_reset(VENUS_PAS_ID);
> > else
> > ret = venus_boot_no_tz(core, mem_phys, mem_size);
> >
> > @@ -259,7 +260,7 @@ int venus_boot(struct venus_core *core)
> > res->cp_nonpixel_start,
> > res->cp_nonpixel_size);
> > if (ret) {
> > - qcom_scm_pas_shutdown(VENUS_PAS_ID);
> > + qcom_pas_shutdown(VENUS_PAS_ID);
> > dev_err(dev, "set virtual address ranges fail (%d)\n",
> > ret);
> > return ret;
> > @@ -274,7 +275,7 @@ int venus_shutdown(struct venus_core *core)
> > int ret;
> >
> > if (core->use_tz)
> > - ret = qcom_scm_pas_shutdown(VENUS_PAS_ID);
> > + ret = qcom_pas_shutdown(VENUS_PAS_ID);
> > else
> > ret = venus_shutdown_no_tz(core);
> >
> > --
> > 2.51.0
>
> with above change
>
> Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
>
Thanks.
-Sumit
^ permalink raw reply
* Re: [PATCH] wifi: carl9170: fix stack-out-of-bounds in carl9170_cmd_callback
From: Christian Lamparter @ 2026-05-01 10:17 UTC (permalink / raw)
To: Deepanshu Kartikey
Cc: linux-wireless, linux-kernel, syzbot+5c1ca6ccaa1215781cac,
tristan, TristanInSec
In-Reply-To: <20260424031711.53104-1-kartikey406@gmail.com>
Hi,
On 4/24/26 5:17 AM, Deepanshu Kartikey wrote:
> carl9170_cmd_callback() does not return after calling
> carl9170_restart() when an invalid command response is detected.
> This causes a fall-through into the memcpy block below, where
> ar->readbuf is written with a device-controlled length (len - 4)
> instead of the expected ar->readlen bytes.
>
> A malicious or fuzzing USB device can send an oversized response
> (e.g. 60 bytes) causing a stack-out-of-bounds write into ar->readbuf,
> as detected by KASAN.
>
> Fix this by adding a return after carl9170_restart() to match the
> original intent stated in the comment ("Do not complete"). Also cap
> the memcpy with min_t() as defense-in-depth to prevent overflow even
> if the control flow changes in future.
>
> The bug has been present since the initial driver submission in 2010.
I've seen this before in a mail from Tristan Madani (CC'd) on the 13th of April 2026.
Unfortunately, he didn't post this to the linux-wireless mailing-list. Instead
he went for the Security Officers <security@kernel.org> , so I can't provide any link to it.
That said, he since changed it because of the notes I had about the driver actually want to process
further so only the memcpy that caused the overflow was modified with the same
"min_t(u32, len - 4, ar->readlen)" instead of "len -4" as the length:
"[PATCH v3 1/3] wifi: carl9170: bound memcpy length in cmd callback to prevent OOB read"
https://lore.kernel.org/linux-wireless/20260421134929.325662-2-tristmd@gmail.com/
So, who should get the credit? Maybe another person will post a patch soon too? Who knows.
Note: if you used any assistents. Please also check out the (new) guide-lines:
https://docs.kernel.org/process/coding-assistants.html and give proper attributions
to the used tools.
> Fixes: a84fab3cbfdc ("carl9170: 802.11 rx/tx processing and usb backend")
> Reported-by: syzbot+5c1ca6ccaa1215781cac@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=5c1ca6ccaa1215781cac
> Tested-by: syzbot+5c1ca6ccaa1215781cac@syzkaller.appspotmail.com
> Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
> ---
> drivers/net/wireless/ath/carl9170/rx.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
> index 6833430130f4..6a5923495a01 100644
> --- a/drivers/net/wireless/ath/carl9170/rx.c
> +++ b/drivers/net/wireless/ath/carl9170/rx.c
> @@ -145,12 +145,14 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
> * and we get a stack trace from there.
> */
> carl9170_restart(ar, CARL9170_RR_INVALID_RSP);
> + return;
It does happen that the driver receives garbage from the device. To remain bug-to-bug compatible with
the rest of the driver should just handle it gracefully. (It's more like the comment above the
carl9170_restart outdated and could be removed. Because carl9170_restart can start an async process that
nukes the whole driver with a full usb_reset which will unbind the device... And if its too far gone it
won't be able to rebind - then it requires the user to either physically unplugged and reinserted the
wifi stick or reboot (only if it helps) or shutdown the machine)
> }
>
> spin_lock(&ar->cmd_lock);
> if (ar->readbuf) {
> if (len >= 4)
> - memcpy(ar->readbuf, buffer + 4, len - 4);
> + memcpy(ar->readbuf, buffer + 4,
> + min_t(u32, len - 4, ar->readlen));
yes.
>
> ar->readbuf = NULL;
> }
Cheers,
Christian
^ permalink raw reply
* Re: [PATCH v2 7/7] arm64: dts: qcom: milos-fairphone-fp6: Enable WiFi
From: Luca Weiss @ 2026-05-01 9:20 UTC (permalink / raw)
To: Konrad Dybcio, Dmitry Baryshkov, Luca Weiss, Jeff Johnson,
Baochen Qiang
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Alexander Koskovich, Liam Girdwood, Mark Brown,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, Johannes Berg, Jeff Johnson,
~postmarketos/upstreaming, phone-devel, linux-arm-msm,
linux-kernel, devicetree, linux-bluetooth, linux-wireless, ath11k
In-Reply-To: <2514523f-a43f-4470-a69b-3d5175d10385@oss.qualcomm.com>
Hi Konrad,
On Tue Apr 7, 2026 at 3:16 PM CEST, Konrad Dybcio wrote:
> On 4/3/26 9:35 PM, Dmitry Baryshkov wrote:
>> On Fri, Apr 03, 2026 at 03:52:53PM +0200, Luca Weiss wrote:
>>> Configure and enable the WiFi node, and add the required pinctrl to
>>> provide the sleep clock from the PMK8550 (PMK7635) to WCN6755.
>>>
>>> Thanks to Alexander Koskovich for helping with the bringup, adding
>>> the missing pinctrl to make the WPSS stop crashing.
>>>
>>> Link: https://lore.kernel.org/linux-arm-msm/DBF7OWAWQ94M.FSCP4DPF8ZJY@fairphone.com/
>>> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
>>> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
>>> ---
>>> arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts | 19 ++++++++++++++++++-
>>> 1 file changed, 18 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>>> index db72418b7195..d8ac495ca7c8 100644
>>> --- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>>> +++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts
>>> @@ -242,7 +242,7 @@ wcn6750-pmu {
>>>
>>> clocks = <&rpmhcc RPMH_RF_CLK1>;
>>>
>>> - pinctrl-0 = <&bluetooth_enable_default>;
>>> + pinctrl-0 = <&bluetooth_enable_default>, <&pmk8550_sleep_clk_default>;
>>> pinctrl-names = "default";
>>>
>>> regulators {
>>> @@ -766,6 +766,17 @@ &pmiv0104_eusb2_repeater {
>>> qcom,tune-usb2-preem = /bits/ 8 <0x6>;
>>> };
>>>
>>> +&pmk8550_gpios {
>>> + pmk8550_sleep_clk_default: sleep-clk-default-state {
>>> + pins = "gpio5";
>>> + function = "func1";
>>> + input-disable;
>>> + output-enable;
>>
>> Hmm, if it's a sleep_clk, should it not be handled via the power
>> sequencer?
>
> If you mean that it may be needed to toggle it with specific timings,
> possibly.. seems that WCN6855 has a "xo-clk" GPIO defined. I requested
> access to some docs that I think should have the answer, hopefully should
> get it soon.
Did you manage to get anything there yet?
Regards
Luca
> Or maybe +Jeff/Baochen could answer faster?
>
> Konrad
^ permalink raw reply
* Re: [PATCH v2] wifi: ath11k: apply existing PM quirk to ThinkPad P14s Gen 5 AMD
From: Kyle Farnung @ 2026-05-01 7:08 UTC (permalink / raw)
To: Baochen Qiang
Cc: Jeff Johnson, Baochen Qiang, Jeff Johnson, linux-wireless, ath11k,
linux-kernel, stable
In-Reply-To: <ba4d194b-6d31-4d8a-a6a6-da116f9f56ac@oss.qualcomm.com>
On Mon, Apr 13, 2026 at 11:43 PM Baochen Qiang
<baochen.qiang@oss.qualcomm.com> wrote:
>
>
>
> On 4/1/2026 11:48 AM, Kyle Farnung wrote:
> > On Tue, Mar 31, 2026 at 7:08 PM Baochen Qiang
> > <baochen.qiang@oss.qualcomm.com> wrote:
> >>
> >>
> >>
> >> On 3/31/2026 2:32 PM, Kyle Farnung via B4 Relay wrote:
> >>> From: Kyle Farnung <kfarnung@gmail.com>
> >>>
> >>> Some ThinkPad P14s Gen 5 AMD systems experience suspend/resume
> >>> reliability issues similar to those reported in [1]. These platforms
> >>
> >> how similar it is? can you describe the issue in details?
> >
> > The issue is that intermittently after suspend my WiFi adapter connects
> > successfully for a few minutes and then drops. It will then keep trying to
> > reconnect in a loop but never succeed. A reboot will fix it, but eventually
> > I found that reloading the module also resolves the issue
> > (modprobe -r ath11k_pci && modprobe ath11k_pci). Based on some searching, I
> > did try adding "ath11k_pci.disable_idle_ps=1" to my kernel arguments. At
> > first it looked like maybe it worked, but then I hit the same problem
> > again. At that point I decided to try building a custom module with the
> > ATH11K_PM_WOW override and so far I'm two days and 10 suspends in without
> > issue.
> >
> > Looking through kernel logs, the issue appears to have started with kernel
> > version 6.17.4. It looks like my Fedora install jumped from 6.16.10 to
> > 6.17.4 on October 22, 2025 and I started seeing the issue two days later.
> >
> > Here are the logs from the most recent occurrence (filtered for brevity):
> >
> > Mar 29 15:26:24 kjfp14sg5 kernel: PM: suspend exit
> > Mar 29 15:26:24 kjfp14sg5 kernel: ath11k_pci 0000:02:00.0: chip_id
> > 0x12 chip_family 0xb board_id 0xff soc_id 0x400c1211
> > Mar 29 15:26:24 kjfp14sg5 kernel: ath11k_pci 0000:02:00.0: fw_version
> > 0x11088c35 fw_build_timestamp 2024-04-17 08:34 fw_build_id
> > WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.41
> > Mar 29 15:26:30 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-REGDOM-CHANGE init=DRIVER type=COUNTRY alpha2=US
> > Mar 29 15:26:30 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-REGDOM-CHANGE init=DRIVER type=COUNTRY alpha2=US
> > Mar 29 15:26:30 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-REGDOM-CHANGE init=DRIVER type=COUNTRY alpha2=US
> > Mar 29 15:26:35 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-CONNECTED - Connection to 68:d7:9a:2a:94:f8 completed [id=0
> > id_str=]
> > Mar 29 15:26:49 kjfp14sg5 wpa_supplicant[2373]: wlp2s0: CTRL-EVENT-BEACON-LOSS
>
> this is the reason to your disconnection
>
> > Mar 29 15:26:55 kjfp14sg5 kernel: ath11k_pci 0000:02:00.0: failed to
> > flush transmit queue, data pkts pending 9
> > Mar 29 15:26:55 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-DISCONNECTED bssid=68:d7:9a:2a:94:f8 reason=4
> > locally_generated=1
> > Mar 29 15:27:00 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-DISCONNECTED bssid=80:2a:a8:98:26:3e reason=6
> > Mar 29 15:27:05 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-DISCONNECTED bssid=74:ac:b9:df:54:36 reason=6
> > Mar 29 15:27:09 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-DISCONNECTED bssid=68:d7:9a:2a:94:f8 reason=2
> > Mar 29 15:27:09 kjfp14sg5 wpa_supplicant[2373]: wlp2s0:
> > CTRL-EVENT-SSID-TEMP-DISABLED id=0 ssid="Batman" auth_failures=1
> > duration=10 reason=CONN_FAILED
>
> and the bssid is disabled so association to this AP won't happen in a period.
>
> Anyway, although it works, using the PM quirk seems not the right fix. As you mentioned it
> seems like a regression starting to show in 6.17.4, can you do regression test to locate
> the issue commit?
It took a bit of trial and error, but I'm reasonably confident that [3] is
the culprit. The issue is pretty sporadic, but I've been able to reproduce
it twice in ~50 sleep/wake cycles on that commit, while the immediate
ancestor has been clean for 17 cycles so far. I'll continue testing and
report back.
The change looks suspicious as it modifies a code path that runs on every
sleep/wake cycle, and the failure appears to be some sort of corrupted
firmware state. In a couple of cases the WiFi firmware crashed outright
(MHI_CB_EE_RDDM) while the issue was occurring.
[3] 79266fd78df1 ("wifi: ath11k: HAL SRNG: don't deinitialize and
re-initialize again")
>
> >
> >>
> >>> were not previously included in the ath11k PM quirk table.
> >>>
> >>> Add DMI matches for product IDs 21ME and 21MF to apply the existing
> >>> ATH11K_PM_WOW override, improving suspend/resume behavior on these
> >>> systems.
> >>>
> >>> Tested on a ThinkPad P14s Gen 5 AMD (21ME) running 6.19.9.
> >>>
> >>> [1] https://bugzilla.kernel.org/show_bug.cgi?id=219196
> >>> [2] https://pcsupport.lenovo.com/us/en/products/laptops-and-netbooks/thinkpad-p-series-laptops/thinkpad-p14s-gen-5-type-21me-21mf/
> >>>
> >>> Fixes: ce8669a27016 ("wifi: ath11k: determine PM policy based on machine model")
> >>> Cc: stable@vger.kernel.org
> >>> Signed-off-by: Kyle Farnung <kfarnung@gmail.com>
> >>> ---
> >>> Changes in v2:
> >>> - Fix missing mailing list recipients (linux-wireless, ath11k, linux-kernel)
> >>> - Link to v1: https://lore.kernel.org/r/20260330-p14s-pm-quirk-v1-1-cf2fa39cc2d5@gmail.com
> >>> ---
> >>> drivers/net/wireless/ath/ath11k/core.c | 14 ++++++++++++++
> >>> 1 file changed, 14 insertions(+)
> >>>
> >>> diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
> >>> index 3f6f4db5b7ee1aba79fd7526e5d59d068e0f4a2e..21d366224e75904feeae6cb9c93d9ef692d127fe 100644
> >>> --- a/drivers/net/wireless/ath/ath11k/core.c
> >>> +++ b/drivers/net/wireless/ath/ath11k/core.c
> >>> @@ -1041,6 +1041,20 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = {
> >>> DMI_MATCH(DMI_PRODUCT_NAME, "21D5"),
> >>> },
> >>> },
> >>> + {
> >>> + .driver_data = (void *)ATH11K_PM_WOW,
> >>> + .matches = { /* P14s G5 AMD #1 */
> >>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> >>> + DMI_MATCH(DMI_PRODUCT_NAME, "21ME"),
> >>> + },
> >>> + },
> >>> + {
> >>> + .driver_data = (void *)ATH11K_PM_WOW,
> >>> + .matches = { /* P14s G5 AMD #2 */
> >>> + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
> >>> + DMI_MATCH(DMI_PRODUCT_NAME, "21MF"),
> >>> + },
> >>> + },
> >>> {}
> >>> };
> >>>
> >>>
> >>> ---
> >>> base-commit: dbd94b9831bc52a1efb7ff3de841ffc3457428ce
> >>> change-id: 20260330-p14s-pm-quirk-0a51ba19235f
> >>>
> >>> Best regards,
> >>
>
^ permalink raw reply
* Re: [PATCH wireless-next v2 05/31] wifi: mm81x: add core.c
From: Lachlan Hodges @ 2026-05-01 5:45 UTC (permalink / raw)
To: johannes, Dan Callaghan, Arien Judge
Cc: ayman.grais, linux-wireless, linux-kernel
In-Reply-To: <20260430045615.334669-6-lachlan.hodges@morsemicro.com>
> +char board_config_file[BCF_SIZE_MAX] = "";
> +module_param_string(bcf, board_config_file, BCF_SIZE_MAX, 0644);
> +MODULE_PARM_DESC(bcf, "BCF filename to load");
Just reviewing the bot results, I see it is not happy about the
mod param, especially since it doesn't really work for multiple
radios so it's not actually a valid approach anyway. After some
discussion we will remove it for now and in the future once we
are in tree add a sysfs entry or something similar.
lachlan
^ permalink raw reply
* Re: RTL8922AE: Severe latency spikes (>200ms) during wifi scan triggers
From: Sivanantham Chinnaiyan @ 2026-05-01 4:55 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <3b9fedf23b39409f8b5979ed36ea02ed@realtek.com>
> It seems like the ping latency without scanning is about 50ms in your
> environment, and currently off-channel time of RTL8922AE is 100ms, so
> roughly it'd be 150ms with scanning.
Got it. Thanks for the clarification.
> What is the problem you are encountering because of long latency?
I encountered disconnects / lags during video calls with the previous
kernel versions. But it seems to be stable from the kernel version
6.19.13 which is what I am currently using. So I wanted to check with
you if this can be reduced.
^ permalink raw reply
* [PATCH ath-next] wifi: ath9k_htc: allocats tx_buf and buf together
From: Rosen Penev @ 2026-05-01 2:33 UTC (permalink / raw)
To: linux-wireless; +Cc: Toke Høiland-Jørgensen, open list
Use a flexible array member to combine allocations. No need to have them
separate as they are always together.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/wireless/ath/ath9k/hif_usb.c | 14 ++------------
drivers/net/wireless/ath/ath9k/hif_usb.h | 2 +-
2 files changed, 3 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 821909b81ea9..8ae4e5d4fa14 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -454,7 +454,6 @@ static void hif_usb_stop(void *hif_handle)
usb_kill_urb(tx_buf->urb);
list_del(&tx_buf->list);
usb_free_urb(tx_buf->urb);
- kfree(tx_buf->buf);
kfree(tx_buf);
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
}
@@ -811,7 +810,6 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
&hif_dev->tx.tx_buf, list) {
list_del(&tx_buf->list);
usb_free_urb(tx_buf->urb);
- kfree(tx_buf->buf);
kfree(tx_buf);
}
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
@@ -828,7 +826,6 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
usb_kill_urb(tx_buf->urb);
list_del(&tx_buf->list);
usb_free_urb(tx_buf->urb);
- kfree(tx_buf->buf);
kfree(tx_buf);
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
}
@@ -849,14 +846,10 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
init_usb_anchor(&hif_dev->mgmt_submitted);
for (i = 0; i < MAX_TX_URB_NUM; i++) {
- tx_buf = kzalloc_obj(*tx_buf);
+ tx_buf = kzalloc_flex(*tx_buf, buf, MAX_TX_BUF_SIZE);
if (!tx_buf)
goto err;
- tx_buf->buf = kzalloc(MAX_TX_BUF_SIZE, GFP_KERNEL);
- if (!tx_buf->buf)
- goto err;
-
tx_buf->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!tx_buf->urb)
goto err;
@@ -871,10 +864,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
return 0;
err:
- if (tx_buf) {
- kfree(tx_buf->buf);
- kfree(tx_buf);
- }
+ kfree(tx_buf);
ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
return -ENOMEM;
}
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index b3e66b0485a5..c28033ee61ce 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -77,13 +77,13 @@ extern int htc_use_dev_fw;
#define HIF_USB_MAX_TXPIPES 4
struct tx_buf {
- u8 *buf;
u16 len;
u16 offset;
struct urb *urb;
struct sk_buff_head skb_queue;
struct hif_device_usb *hif_dev;
struct list_head list;
+ u8 buf[];
};
struct rx_buf {
--
2.54.0
^ permalink raw reply related
* [PATCH] nfc: trf7970a: fix comment typos
From: Miles Krause @ 2026-05-01 0:35 UTC (permalink / raw)
To: Mark Greer, David Heidelberg
Cc: linux-wireless, oe-linux-nfc, linux-kernel, Miles Krause
Fix a few spelling mistakes in comments.
Signed-off-by: Miles Krause <mileskrause5200@gmail.com>
---
drivers/nfc/trf7970a.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 08c27bb438b5..f22e091019de 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -61,15 +61,15 @@
* support that. So, if an abort is received before trf7970a_send_cmd()
* has sent the command to the tag, it simply returns -ECANCELED. If the
* command has already been sent to the tag, then the driver continues
- * normally and recieves the response data (or error) but just before
+ * normally and receives the response data (or error) but just before
* sending the data upstream, it frees the rx_skb and sends -ECANCELED
* upstream instead. If the command failed, that error will be sent
* upstream.
*
- * When recieving data from a tag and the interrupt status register has
+ * When receiving data from a tag and the interrupt status register has
* only the SRX bit set, it means that all of the data has been received
* (once what's in the fifo has been read). However, depending on timing
- * an interrupt status with only the SRX bit set may not be recived. In
+ * an interrupt status with only the SRX bit set may not be received. In
* those cases, the timeout mechanism is used to wait 20 ms in case more
* data arrives. After 20 ms, it is assumed that all of the data has been
* received and the accumulated rx data is sent upstream. The
base-commit: 08d0d3466664000ba0670e0ef0d447f23459e0d4
--
2.54.0
^ permalink raw reply related
* Re: [GIT PULL] wireless-next-2026-04-30
From: patchwork-bot+netdevbpf @ 2026-05-01 0:30 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, linux-wireless
In-Reply-To: <20260430120304.249081-3-johannes@sipsolutions.net>
Hello:
This pull request was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 30 Apr 2026 14:02:12 +0200 you wrote:
> Hi,
>
> Looks like 7.2 is going to be interesting with NAN and UHR
> both getting major work, but for now we have some (relatively)
> minor things - the biggest is the station bandwidth rework,
> which is needed en route to UHR.
>
> [...]
Here is the summary with links:
- [GIT,PULL] wireless-next-2026-04-30
https://git.kernel.org/netdev/net-next/c/6855a52318b3
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH wireless-next] wifi: rt2x00: allocate anchor with rt2x00dev
From: Rosen Penev @ 2026-04-30 23:22 UTC (permalink / raw)
To: linux-wireless; +Cc: Stanislaw Gruszka, open list
Instead of being creative with devm, allocate with rt2x00dev by using a
flexible array member. Simplifies code slightly.
It's worth noting that in 25369b22223d1c56e42a0cd4ac9137349d5a898e , the
proper device was set to the devm call as it seems there was confusion
there.
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
drivers/net/wireless/ralink/rt2x00/rt2x00.h | 3 ++-
drivers/net/wireless/ralink/rt2x00/rt2x00usb.c | 11 +----------
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
index 665887e9b118..7d313e86d3f2 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -1009,11 +1009,12 @@ struct rt2x00_dev {
/* Extra TX headroom required for alignment purposes. */
unsigned int extra_tx_headroom;
- struct usb_anchor *anchor;
unsigned int num_proto_errs;
/* Clock for System On Chip devices. */
struct clk *clk;
+
+ struct usb_anchor anchor[];
};
struct rt2x00_bar_list_entry {
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
index 174d89b0b1d7..47e427ea8622 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00usb.c
@@ -804,7 +804,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
usb_reset_device(usb_dev);
- hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+ hw = ieee80211_alloc_hw(struct_size(rt2x00dev, anchor, 1), ops->hw);
if (!hw) {
rt2x00_probe_err("Failed to allocate hardware\n");
return -ENOMEM;
@@ -826,13 +826,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
if (retval)
goto exit_free_device;
- rt2x00dev->anchor = devm_kmalloc(&usb_intf->dev,
- sizeof(struct usb_anchor),
- GFP_KERNEL);
- if (!rt2x00dev->anchor) {
- retval = -ENOMEM;
- goto exit_free_reg;
- }
init_usb_anchor(rt2x00dev->anchor);
retval = rt2x00lib_probe_dev(rt2x00dev);
@@ -843,8 +836,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
exit_free_anchor:
usb_kill_anchored_urbs(rt2x00dev->anchor);
-
-exit_free_reg:
rt2x00usb_free_reg(rt2x00dev);
exit_free_device:
--
2.54.0
^ permalink raw reply related
* Re: [PATCH ath 0/2] fix leaks in some WMI error path
From: Jeff Johnson @ 2026-04-30 21:54 UTC (permalink / raw)
To: Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <20260424144813.1708214-1-nico.escande@gmail.com>
On 4/24/2026 7:48 AM, Nicolas Escande wrote:
> So this is similar work to what has been posted here [0] for ath12k.
>
> When we use the pattern 'return ath11k_wmi_cmd_send(...)' without
> explicitly checking the return value we fail to free the allocated skb.
>
> This has been split into 2 patches per Jeff's guidance to hopefully
> ease the backporting process.
>
> [0] https://lore.kernel.org/linux-wireless/20260422163258.3013872-1-nico.escande@gmail.com/
>
> Nicolas Escande (2):
> wifi: ath11k: fix leak in error path of some WOW related WMI commands
> wifi: ath11k: fix error path leaks in some WMI calls
>
> drivers/net/wireless/ath/ath11k/wmi.c | 131 ++++++++++++++++++++++----
> 1 file changed, 112 insertions(+), 19 deletions(-)
>
Please repost and include the ath11k list
^ permalink raw reply
* Re: [PATCH ath-next v2 0/5] wifi: ath12k: thermal throttling and cooling device support
From: Jeff Johnson @ 2026-04-30 21:30 UTC (permalink / raw)
To: ath12k, Maharaja Kennadyrajan; +Cc: linux-wireless
In-Reply-To: <20260413153840.1969931-1-maharaja.kennadyrajan@oss.qualcomm.com>
On Mon, 13 Apr 2026 21:08:35 +0530, Maharaja Kennadyrajan wrote:
> Patch 1 handles the firmware stats event so we can track the current
> temperature and throttle level per pdev without spamming logs.
>
> Patch 2 enables thermal throttling at bring-up and programs default level
> tables to firmware via WMI_THERM_THROT_SET_CONF_CMDID; the driver picks
> IPA/XFEM defaults based on the firmware WMI service bitmap, supports 4 or 5
> levels as advertised, and only fills optional fields (pout reduction,
> tx chain mask) when the corresponding WMI service bits are present.
>
> [...]
Applied, thanks!
[1/5] wifi: ath12k: handle thermal throttle stats WMI event
commit: 845b613b57c626ac85fdefd47196acfb3172fd49
[2/5] wifi: ath12k: configure firmware thermal throttling via WMI
commit: 612556eb774f19f0ad64b5f72e890943b95a1339
[3/5] wifi: ath12k: refactor per-radio thermal hwmon setup and cleanup
commit: cd93e8c23ebbd72e9aa799199b14c8433585f747
[4/5] wifi: ath12k: reorder group start/stop for safe thermal sysfs cleanup
commit: 0ab4dc09b7819ddea698fe5a0cc711a64186f12d
[5/5] wifi: ath12k: add thermal cooling device support
commit: e12d2d3983acb150fd987d19ec6a2a530da110df
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-next] wifi: ath12k: unify error handling in some ath12k_wmi_xxx() functions
From: Jeff Johnson @ 2026-04-30 21:30 UTC (permalink / raw)
To: ath12k, Nicolas Escande; +Cc: linux-wireless
In-Reply-To: <20260422163208.3013496-1-nico.escande@gmail.com>
On Wed, 22 Apr 2026 18:32:07 +0200, Nicolas Escande wrote:
> This is purely cosmetic changes that simplifies & standardizes error
> handling for functions that ends with a ath12k_wmi_cmd_send() followed
> by trivial error handling. Saves a few lines of code too.
>
> Compile tested only.
>
>
> [...]
Applied, thanks!
[1/1] wifi: ath12k: unify error handling in some ath12k_wmi_xxx() functions
commit: 31d4f8d427f2b9e423d7e177fb15f934cf0e37dd
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox