* Re: [PATCH 4/6] dt-bindings: net: bluetooth: Document Qualcomm IPQ5018 Bluetooth controller
From: Konrad Dybcio @ 2026-06-26 11:30 UTC (permalink / raw)
To: George Moussalem, Krzysztof Kozlowski
Cc: Jens Axboe, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Johannes Berg, Jeff Johnson, Bartosz Golaszewski,
Marcel Holtmann, Luiz Augusto von Dentz, Balakrishna Godavarthi,
Rocky Liao, Saravana Kannan, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Bjorn Andersson, Konrad Dybcio,
Mathieu Poirier, Philipp Zabel, linux-block, linux-kernel,
linux-mmc, devicetree, linux-wireless, ath10k, linux-arm-msm,
linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <SN7PR19MB673692EBED649CF6DC9833A89DEB2@SN7PR19MB6736.namprd19.prod.outlook.com>
On 6/26/26 1:20 PM, George Moussalem wrote:
> On 6/26/26 14:53, Krzysztof Kozlowski wrote:
>> On Thu, Jun 25, 2026 at 06:10:08PM +0400, George Moussalem wrote:
>>> Document the Qualcomm IPQ5018 Bluetooth controller.
>>>
>>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>>> ---
[...]
>>> + compatible = "qcom,ipq5018-bt";
>>> +
>>> + qcom,ipc = <&apcs_glb 8 23>;
>>> + interrupts = <GIC_SPI 162 IRQ_TYPE_EDGE_RISING>;
>>
>> No firmware to load?
>
> firmware is loaded by the remoteproc in patch 1
>
>>
>> It feels like remoteproc node split is fake. The property qcom,rproc is
>> even more supporting that case. Shouldn't this be simply one device -
>> bluetooth? What sort of two devices do you have exactly? How can I
>> identify them in the hardware?
>
> I wasn't sure how to represent the HW. Should I make this bluetooth node
> a childnode of the rproc? Essentially, this is the transport layer
> (using shared memory space and IPC/interrupt).
>
> Most QCA BT controllers are also childnodes of a serdev/uart node as
> they use serdev for transport.
>
> From what I understand, it's simply BT firmware running on this
> dedicated M0 core in the SoC itself connected to an RF.
Seems like this rhymes with the WPSS remoteproc +ATH1xK_AHB situation
- the Q6 core power sequences and manages the wireless controller,
while Linux gets to drive the device as it would if it were connected
over PCIe/ UART respectively, just with MMIO writes instead.
Konrad
^ permalink raw reply
* Re: [PATCH v2] vhost/net: fix clear_user start address in VHOST_GET_FEATURES_ARRAY
From: Eugenio Perez Martin @ 2026-06-26 11:31 UTC (permalink / raw)
To: rom.wang
Cc: Michael S . Tsirkin, Jason Wang, Paolo Abeni, kvm, virtualization,
netdev, linux-kernel, Yufeng Wang
In-Reply-To: <20260626070438.59149-1-r4o5m6e8o@163.com>
On Fri, Jun 26, 2026 at 9:05 AM rom.wang <r4o5m6e8o@163.com> wrote:
>
> From: Yufeng Wang <wangyufeng@kylinos.cn>
>
> The clear_user() call in VHOST_GET_FEATURES_ARRAY incorrectly starts
> at argp, which is the beginning of the features array, overwriting the
> data just written by copy_to_user(). It should start after the copied
> elements at argp + copied * sizeof(u64) to only zero the trailing
> unused space.
>
> Use size_mul() for both the offset and length calculations so the
> arithmetic stays consistent with the surrounding code and remains
> overflow-safe.
>
> Fixes: 333c515d1896 ("vhost-net: allow configuring extended features")
> Signed-off-by: Yufeng Wang <wangyufeng@kylinos.cn>
>
> ---
> Changes in v2:
> - Use size_mul() for the offset calculation as well, per review feedback.
>
> Link to v1: https://lore.kernel.org/all/20260526080336.61296-1-r4o5m6e8o@163.com/
>
> Note:
> Thank you for your review and suggestions.
>
> I tried to add a switch in tools/virtio/vhost_net_test.c.
> The switch is meant to use VHOST_GET_FEATURES_ARRAY and
> VHOST_SET_FEATURES_ARRAY instead of the legacy versions.
>
> However, when I ran `make virtio` in the tools directory,
> the build failed with an error: missing asm/percpu_types.h.
> I fixed that error, but then another error appeared.
>
> Would it be acceptable to postpone the submission of
> this test case until I have sorted out all the build
> errors?
> ---
> drivers/vhost/net.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
> index 77b59f49bddb..4b963dafa233 100644
> --- a/drivers/vhost/net.c
> +++ b/drivers/vhost/net.c
> @@ -1784,7 +1784,8 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl,
> return -EFAULT;
>
> /* Zero the trailing space provided by user-space, if any */
> - if (clear_user(argp, size_mul(count - copied, sizeof(u64))))
> + if (clear_user(argp + size_mul(copied, sizeof(u64)),
> + size_mul(count - copied, sizeof(u64))))
Acked-by: Eugenio Pérez <eperezma@redhat.com>
Thanks!
> return -EFAULT;
> return 0;
> case VHOST_SET_FEATURES_ARRAY:
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH 2/6] remoteproc: qcom: Add M0 BTSS secure PIL driver
From: George Moussalem @ 2026-06-26 11:32 UTC (permalink / raw)
To: Konrad Dybcio, Jens Axboe, Ulf Hansson, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Johannes Berg, Jeff Johnson,
Bartosz Golaszewski, Marcel Holtmann, Luiz Augusto von Dentz,
Balakrishna Godavarthi, Rocky Liao, Saravana Kannan, Andrew Lunn,
Heiner Kallweit, Russell King, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Bjorn Andersson,
Konrad Dybcio, Mathieu Poirier, Philipp Zabel
Cc: linux-block, linux-kernel, linux-mmc, devicetree, linux-wireless,
ath10k, linux-arm-msm, linux-bluetooth, netdev, linux-remoteproc
In-Reply-To: <38aceb33-b28e-4994-b277-de070b6dae2b@oss.qualcomm.com>
On 6/26/26 15:20, Konrad Dybcio wrote:
> On 6/25/26 4:10 PM, George Moussalem via B4 Relay wrote:
>> From: George Moussalem <george.moussalem@outlook.com>
>>
>> Add support to bring up the M0 core of the bluetooth subsystem found in
>> the IPQ5018 SoC.
>>
>> The signed firmware loaded is authenticated by TrustZone. If successful,
>> the M0 core boots the firmware and the peripheral is taken out of reset
>> using a Secure Channel Manager call to TrustZone.
>>
>> Signed-off-by: George Moussalem <george.moussalem@outlook.com>
>> ---
>
> Can this not fit inside the existing PAS driver?
I've tried but there were two issues with that:
1. a custom way to load the firmware into memory is required because the
loadable segment needs to be offset by the virtual address in the mbn
file (see 0x20250 below). The standard mdt_loader uses the physical
addresses.
readelf -l bt_fw_patch.mbn
Elf file type is EXEC (Executable file)
Entry point 0x20255
There are 3 program headers, starting at offset 52
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
NULL 0x000000 0x00000000 0x00000000 0x00094 0x00000 0
NULL 0x001000 0x0001a000 0x0001a000 0x00088 0x01000 0x1000
LOAD 0x002000 0x00020250 0x00000000 0x06154 0x190f8 RWE 0x4
2. memory needs to be ioremapped using ioremap, not ioremap_wc, else TZ
will complain and throw XPU violations due to strict memory alignment
and non-cache requirements.
>
> Konrad
Cheers,
George
^ permalink raw reply
* Re: [PATCH net v2] net: liquidio: fix BAR resource leak on PF number failure
From: Larysa Zaremba @ 2026-06-26 11:44 UTC (permalink / raw)
To: Haoxiang Li
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, ricardo.farrington,
felix.manlunas, horms, netdev, linux-kernel, stable
In-Reply-To: <20260624064013.2809570-1-haoxiang_li2024@163.com>
On Wed, Jun 24, 2026 at 02:40:13PM +0800, Haoxiang Li wrote:
> If cn23xx_get_pf_num() fails, the function returns without
> unmapping either BAR. Unmap both BARs before returning from
> the error path.
>
> Found by manual code review.
>
> Fixes: 0c45d7fe12c7 ("liquidio: fix use of pf in pass-through mode in a virtual machine")
> Cc: stable@vger.kernel.org
> Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
Reviewed-by: Larysa Zaremba <larysa.zaremba@intel.com>
> ---
> Changes in v2:
> - Modify the commit message.
> - Introduce goto unwind path to do the cleanup. Thanks, Simon!
> ---
> .../cavium/liquidio/cn23xx_pf_device.c | 18 ++++++++++--------
> 1 file changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
> index 75f22f74774c..06b4424e778e 100644
> --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
> +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
> @@ -1163,18 +1163,14 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct)
> if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) {
> dev_err(&oct->pci_dev->dev, "%s CN23XX BAR1 map failed\n",
> __func__);
> - octeon_unmap_pci_barx(oct, 0);
> - return 1;
> + goto err_unmap_bar0;
> }
>
> if (cn23xx_get_pf_num(oct) != 0)
> - return 1;
> + goto err_unmap_bar1;
>
> - if (cn23xx_sriov_config(oct)) {
> - octeon_unmap_pci_barx(oct, 0);
> - octeon_unmap_pci_barx(oct, 1);
> - return 1;
> - }
> + if (cn23xx_sriov_config(oct))
> + goto err_unmap_bar1;
>
> octeon_write_csr64(oct, CN23XX_SLI_MAC_CREDIT_CNT, 0x3F802080802080ULL);
>
> @@ -1205,6 +1201,12 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct)
> oct->coproc_clock_rate = 1000000ULL * cn23xx_coprocessor_clock(oct);
>
> return 0;
> +
> +err_unmap_bar1:
> + octeon_unmap_pci_barx(oct, 1);
> +err_unmap_bar0:
> + octeon_unmap_pci_barx(oct, 0);
> + return 1;
> }
> EXPORT_SYMBOL_GPL(setup_cn23xx_octeon_pf_device);
>
> --
> 2.25.1
>
>
^ permalink raw reply
* Re: [PATCH iwl v3] ice: retry reading NVM if admin queue returns EBUSY
From: Przemek Kitszel @ 2026-06-26 11:46 UTC (permalink / raw)
To: Robert Malz
Cc: Simon Horman, Grzegorz Nitka, anthony.l.nguyen, intel-wired-lan,
netdev
In-Reply-To: <CADcc-bwC4FGQSGyRcnj2ZpGT5+0Q6mjQd-FTCB-mCmmwYrC8Qw@mail.gmail.com>
On 6/26/26 10:15, Robert Malz wrote:
> Hey Przemek,
> I ran some tests and unfortunately, the following sentence from the
> datasheet is true:
> "For specific resources, such as Change Lock (0x0003) and Global Config Lock
> (0x0004), this field is used by software to override the default timeout for the
> operation, and also to specify the timeout used for this operation."
>
> This means we can only change a default timeout for 0x0003 and 0x0004
> but not for 0x0001 (NVM resource).
> Whatever timeout I provide FW defaults to 0xB88
> Input:
> [ 2209.656758] ice 0000:31:00.0: CQ CMD: opcode 0x0008, flags 0x2000,
> datalen 0x0000, retval 0x0000
> [ 2209.656760] ice 0000:31:00.0: cookie (h,l) 0x00000000 0x00000000
> [ 2209.656761] ice 0000:31:00.0: param (0,1) 0x00010001 0x00000BB9
> Output:
> [ 2209.656927] ice 0000:31:00.0: CQ CMD: opcode 0x0008, flags 0x2003,
> datalen 0x0000, retval 0x0000
> [ 2209.656929] ice 0000:31:00.0: cookie (h,l) 0x00000000 0x00000000
> [ 2209.656931] ice 0000:31:00.0: param (0,1) 0x00010001 0x00000BB8
>
> Correct me If I'm wrong, but the only way to properly handle it is to
> ensure the resource is locked and released between every
> ice_acquire_nvm call.
> I'll start working on this.
thank you for checking out!
I agree that simple retries with improved (refactored) locking will be
good solution.
Failure to lock should count as an unsuccessful attempt, with possible
retry after a sleep.
>
> Regards,
> Robert
^ permalink raw reply
* Re: [PATCH net v2] net: ipa: fix SMEM state handle leaks in SMP2P init
From: Larysa Zaremba @ 2026-06-26 11:52 UTC (permalink / raw)
To: Haoxiang Li
Cc: elder, andrew+netdev, davem, edumazet, kuba, pabeni, netdev,
linux-kernel, stable
In-Reply-To: <20260624065955.2822765-1-haoxiang_li2024@163.com>
On Wed, Jun 24, 2026 at 02:59:55PM +0800, Haoxiang Li wrote:
> ipa_smp2p_init() acquires two Qualcomm SMEM state handles with
> qcom_smem_state_get(). However, neither the init error paths
> nor ipa_smp2p_exit() release them.
>
> Release both handles with qcom_smem_state_put() in the init
> error paths and in ipa_smp2p_exit().
>
> Fixes: 530f9216a953 ("soc: qcom: ipa: AP/modem communications")
> Cc: stable@vger.kernel.org
> Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
Reviewed-by: Larysa Zaremba <larysa.zaremba@intel.com>
> ---
> Changes in v2:
> - Use explicit qcom_smem_state_put() calls instead of devm helpers.
> Thanks, Alex! Thanks, Jakub!
> ---
> drivers/net/ipa/ipa_smp2p.c | 30 ++++++++++++++++++++++--------
> 1 file changed, 22 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c
> index 2f0ccdd937cc..331c00ad02c0 100644
> --- a/drivers/net/ipa/ipa_smp2p.c
> +++ b/drivers/net/ipa/ipa_smp2p.c
> @@ -232,19 +232,27 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init)
> &valid_bit);
> if (IS_ERR(valid_state))
> return PTR_ERR(valid_state);
> - if (valid_bit >= 32) /* BITS_PER_U32 */
> - return -EINVAL;
> + if (valid_bit >= 32) { /* BITS_PER_U32 */
> + ret = -EINVAL;
> + goto err_valid_state_put;
> + }
>
> enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled",
> &enabled_bit);
> - if (IS_ERR(enabled_state))
> - return PTR_ERR(enabled_state);
> - if (enabled_bit >= 32) /* BITS_PER_U32 */
> - return -EINVAL;
> + if (IS_ERR(enabled_state)) {
> + ret = PTR_ERR(enabled_state);
> + goto err_valid_state_put;
> + }
> + if (enabled_bit >= 32) { /* BITS_PER_U32 */
> + ret = -EINVAL;
> + goto err_enabled_state_put;
> + }
>
> smp2p = kzalloc_obj(*smp2p);
> - if (!smp2p)
> - return -ENOMEM;
> + if (!smp2p) {
> + ret = -ENOMEM;
> + goto err_enabled_state_put;
> + }
>
> smp2p->ipa = ipa;
>
> @@ -289,6 +297,10 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init)
> ipa->smp2p = NULL;
> mutex_destroy(&smp2p->mutex);
> kfree(smp2p);
> +err_enabled_state_put:
> + qcom_smem_state_put(enabled_state);
> +err_valid_state_put:
> + qcom_smem_state_put(valid_state);
>
> return ret;
> }
> @@ -305,6 +317,8 @@ void ipa_smp2p_exit(struct ipa *ipa)
> ipa_smp2p_power_release(ipa);
> ipa->smp2p = NULL;
> mutex_destroy(&smp2p->mutex);
> + qcom_smem_state_put(smp2p->enabled_state);
> + qcom_smem_state_put(smp2p->valid_state);
> kfree(smp2p);
> }
>
> --
> 2.25.1
>
>
^ permalink raw reply
* Re: [PATCH net v4 1/2] net: phy: sfp: free mii_bus in sfp_i2c_mdiobus_destroy
From: Larysa Zaremba @ 2026-06-26 12:05 UTC (permalink / raw)
To: Petr Wozniak
Cc: Russell King, Andrew Lunn, Heiner Kallweit, Jakub Kicinski,
David S . Miller, Eric Dumazet, Paolo Abeni, netdev, linux-kernel,
linux-phy, Maxime Chevallier, Bjorn Mork, Aleksander Bajkowski,
Marek Behun
In-Reply-To: <20260624084814.20972-2-petr.wozniak@gmail.com>
On Wed, Jun 24, 2026 at 10:48:13AM +0200, Petr Wozniak wrote:
> sfp_i2c_mdiobus_create() allocates the I2C MDIO bus with mdio_i2c_alloc(),
> a plain (non-devm) allocation, and registers it. sfp_i2c_mdiobus_destroy()
> only unregisters the bus and clears sfp->i2c_mii without calling
> mdiobus_free(). As the only reference to the bus is then cleared, the
> struct mii_bus is leaked.
>
> This is hit whenever a copper/RollBall SFP module that instantiated an MDIO
> bus is removed: sfp_sm_main() takes the global teardown path and calls
> sfp_i2c_mdiobus_destroy(). sfp_cleanup(), on driver unbind, frees
> sfp->i2c_mii directly, which is why the leak only triggered on module
> hot-removal and not on unbind.
>
> Free the bus in sfp_i2c_mdiobus_destroy() to match the allocation done in
> sfp_i2c_mdiobus_create().
>
> Fixes: e85b1347ace6 ("net: sfp: create/destroy I2C mdiobus before PHY probe/after PHY release")
> Signed-off-by: Petr Wozniak <petr.wozniak@gmail.com>
> Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Reviewed-by: Larysa Zaremba <larysa.zaremba@intel.com>
> ---
> drivers/net/phy/sfp.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
> index 03bfd8640db9..c4d274ab651e 100644
> --- a/drivers/net/phy/sfp.c
> +++ b/drivers/net/phy/sfp.c
> @@ -963,6 +963,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp)
> static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
> {
> mdiobus_unregister(sfp->i2c_mii);
> + mdiobus_free(sfp->i2c_mii);
> sfp->i2c_mii = NULL;
> }
>
> --
> 2.51.0
>
>
^ permalink raw reply
* Re: [PATCH net 1/7] xsk: fix buffer leak in xsk_drop_skb() for AF_XDP multi-buffer Tx
From: Jason Xing @ 2026-06-26 12:24 UTC (permalink / raw)
To: Larysa Zaremba
Cc: Maciej Fijalkowski, netdev, bpf, magnus.karlsson, stfomichev,
kuba, pabeni, horms, bjorn, Jason Xing
In-Reply-To: <aj5egH5eDwfsY30-@soc-5CG4396X81.clients.intel.com>
On Fri, Jun 26, 2026 at 7:12 PM Larysa Zaremba <larysa.zaremba@intel.com> wrote:
>
> On Tue, Jun 23, 2026 at 03:32:34PM +0200, Maciej Fijalkowski wrote:
> > From: Jason Xing <kernelxing@tencent.com>
> >
> > This patch is inspired by the check[1] from sashiko. It says when
> > overflow happens, the address of cq to be published is invalid.
> > Actually the severer thing is the whole process of publishing the
> > address of cq in this particular case is not right: it should truely
> > publish the address and advance the cached_prod in cq as long as it
> > reads descriptors from txq.
> >
> > The following is the full analysis.
> > xsk_drop_skb() is called in three places, which all discard a partially
> > built multi-buffer skb:
> > 1) xsk_build_skb() -EOVERFLOW error path: packet exceeds MAX_SKB_FRAGS
> > 2) __xsk_generic_xmit() post-loop cleanup: an invalid descriptor in
> > the TX ring prevents the partial packet from completing
> > 3) xsk_release(): socket close while xs->skb holds an incomplete packet
> >
> > In all three cases, the TX descriptors for the already-processed frags
> > have been consumed from the TX ring (xskq_cons_release), and CQ slots
> > have been reserved. However, xsk_drop_skb() calls xsk_consume_skb()
> > which cancels the CQ reservations via xsk_cq_cancel_locked(). Since
> > the buffer addresses never appear in the completion queue, userspace
> > permanently loses track of these buffers.
> >
> > Fix this by letting consume_skb() trigger the existing xsk_destruct_skb
> > destructor, which already submits buffer addresses to the CQ via
> > xsk_cq_submit_addr_locked().
> >
> > Note that cancelling the descriptors back to the TX ring (via
> > xskq_cons_cancel_n) is not a appropriate option because an oversized
> > packet that always exceeds MAX_SKB_FRAGS would be retried indefinitely,
> > which is an obviously deadlock bug in the TX path.
> >
> > Also move the desc->addr assignment in xsk_build_skb() above the
> > overflow check so that the current descriptor's address is recorded
> > before a potential -EOVERFLOW jump to free_err, consistent with the
> > zerocopy path in xsk_build_skb_zerocopy().
> >
> > [1]: https://lore.kernel.org/all/20260425041726.85FB3C2BCB2@smtp.kernel.org/
>
> This change looks good, but overflow case with only 1 descriptor worries me.
I presume you referred to xsk_build_skb_zerocopy()?
> In such cases, once we get to following code, kfree_skb() has already happened:
>
> if (err == -EOVERFLOW) {
> if (xs->skb) {
> /* Drop the packet */
> xsk_inc_num_desc(xs->skb);
> xsk_drop_skb(xs->skb);
> } else {
> xsk_cq_cancel_locked(xs->pool, 1);
> xs->tx->invalid_descs++;
> }
> xskq_cons_release(xs->tx);
> }
>
> kfree_skb() should have resulted in submission of the single fat descriptor to
> xsk_cq_submit_addr_locked() via xsk_destruct_skb(), so far consistent with the
At least, in the NO_LINEAR case, xsk_skb_init_misc() is not called
since the OVERFLOW skips this function, which means kfree_skb()
doesn't invoke xsk_destruct_skb() to publish it in the CQ. So it's
safe to cancel the cq reservation (in xsk_cq_cancel_locked(xs->pool,
1)).
Thanks,
Jason
> multi-descriptor bevaior you are proposing here.
>
> But what happens when we cancel a submitted CQ slot via
> xsk_cq_cancel_locked(xs->pool, 1) in the above code?
>
> >
> > Fixes: cf24f5a5feea ("xsk: add support for AF_XDP multi-buffer on Tx path")
> > Signed-off-by: Jason Xing <kernelxing@tencent.com>
> > ---
> > net/xdp/xsk.c | 13 ++++++++-----
> > 1 file changed, 8 insertions(+), 5 deletions(-)
> >
> > diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
> > index b970f30ea9b9..a7a83dc4546a 100644
> > --- a/net/xdp/xsk.c
> > +++ b/net/xdp/xsk.c
> > @@ -794,8 +794,11 @@ static void xsk_consume_skb(struct sk_buff *skb)
> >
> > static void xsk_drop_skb(struct sk_buff *skb)
> > {
> > - xdp_sk(skb->sk)->tx->invalid_descs += xsk_get_num_desc(skb);
> > - xsk_consume_skb(skb);
> > + struct xdp_sock *xs = xdp_sk(skb->sk);
> > +
> > + xs->tx->invalid_descs += xsk_get_num_desc(skb);
> > + consume_skb(skb);
> > + xs->skb = NULL;
> > }
> >
> > static int xsk_skb_metadata(struct sk_buff *skb, void *buffer,
> > @@ -877,7 +880,7 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,
> > return ERR_PTR(-ENOMEM);
> >
> > /* in case of -EOVERFLOW that could happen below,
> > - * xsk_consume_skb() will release this node as whole skb
> > + * xsk_drop_skb() will release this node as whole skb
> > * would be dropped, which implies freeing all list elements
> > */
> > xsk_addr->addrs[xsk_addr->num_descs] = desc->addr;
> > @@ -969,6 +972,8 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
> > goto free_err;
> > }
> >
> > + xsk_addr->addrs[xsk_addr->num_descs] = desc->addr;
> > +
> > if (unlikely(nr_frags == (MAX_SKB_FRAGS - 1) && xp_mb_desc(desc))) {
> > err = -EOVERFLOW;
> > goto free_err;
> > @@ -986,8 +991,6 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
> >
> > skb_add_rx_frag(skb, nr_frags, page, 0, len, PAGE_SIZE);
> > refcount_add(PAGE_SIZE, &xs->sk.sk_wmem_alloc);
> > -
> > - xsk_addr->addrs[xsk_addr->num_descs] = desc->addr;
> > }
> > }
> >
> > --
> > 2.43.0
> >
> >
^ permalink raw reply
* Re: [PATCH bpf-next v5 0/3] bpf, sockmap: reject a packet-modifying SK_SKB stream parser
From: patchwork-bot+netdevbpf @ 2026-06-26 12:27 UTC (permalink / raw)
To: Sechang Lim
Cc: ast, daniel, andrii, john.fastabend, jakub, eddyz87, edumazet,
kuniyu, pabeni, willemb, davem, kuba, martin.lau, song,
yonghong.song, jolsa, memxor, horms, shuah, jiayuan.chen,
bobby.eshleman, netdev, bpf, linux-kselftest, linux-kernel
In-Reply-To: <20260620024423.4141004-1-rhkrqnwk98@gmail.com>
Hello:
This series was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Sat, 20 Jun 2026 02:44:15 +0000 you wrote:
> A BPF_PROG_TYPE_SK_SKB stream parser runs on strparser's message head,
> which can chain skbs through frag_list. A parser that resizes the skb
> frees the frag_list segments that strparser still tracks through
> skb_nextp, leading to a use-after-free.
>
> A stream parser is only meant to measure the next message, not to modify
> the packet, so reject a packet-modifying parser at attach time.
>
> [...]
Here is the summary with links:
- [bpf-next,v5,1/3] selftests/bpf: don't modify the skb in the strparser parser prog
https://git.kernel.org/bpf/bpf/c/22a0cc10dacb
- [bpf-next,v5,2/3] bpf, sockmap: reject a packet-modifying SK_SKB stream parser
https://git.kernel.org/bpf/bpf/c/31e2f36d3821
- [bpf-next,v5,3/3] selftests/bpf: test rejection of a packet-modifying SK_SKB stream parser
https://git.kernel.org/bpf/bpf/c/05fb34384d20
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH net-next] Documentation: networking: Add a test plan for ethtool pause validation
From: Andrew Lunn @ 2026-06-26 12:39 UTC (permalink / raw)
To: Maxime Chevallier
Cc: Jakub Kicinski, davem, Eric Dumazet, Paolo Abeni, Simon Horman,
Russell King, Heiner Kallweit, Jonathan Corbet, Shuah Khan,
Oleksij Rempel, Vladimir Oltean, Florian Fainelli,
thomas.petazzoni, netdev, linux-kernel, linux-doc
In-Reply-To: <65d26fd2-fbb3-49cd-a9ac-07863d9a8909@bootlin.com>
On Fri, Jun 26, 2026 at 10:33:50AM +0200, Maxime Chevallier wrote:
>
> > Sphinx follows pythons object orientate structure. So you could have a
> > class test_ethtool_pause_advertising, with class documentation. And
> > then methods within the class which are individual tests. The
> > commented out section would then be method documentation.
>
> Good point, so maybe something along these lines :
>
> - A class for the test
> - methods for indivitual tests
> - For readability, I've written what the internal test helper would look
> like (_adv_test), and how a test would look like without the helper in
> adv_rx_on_tx_on().
>
> I'm already diving into coding, but it helps me a bit in the definition of the
> "description" format :)
>
> this is what the class would look like :
I like this :-)
>
>
> @ksft_ethtool_needs_supported_allof([Pause])
> def adv_rx_on_tx_on(cfg, peer) -> None:
Using decorators is a nice idea. Since it is not a C concept, please
give the decorator a good comment explaining what it does. We should
not assume driver developers know python.
> """Advertising test with rx on tx on
>
> - run 'ethtool -A ethX rx on tx on autoneg on'
> - FAIL if the return isn't 0
> - FAIL if ETHTOOL_A_LINKMODES_OURS's advertised values does not contain
> "Pause" or contains "Asym_Pause"
> - FAIL if peer's lp_advertising doesn't contain "Pause" or contains
> "Asym_Pause"
> - Succeed otherwise
> """
> ret = cfg.run('ethtool -A ethX rx on tx on autoneg on')
> ksft_eq(ret, 0)
>
> linkmodes = cfg.get_advertising()
> ksft_in('Pause', linkmodes, "rx on tx on must advertise Pause")
> ksft_not_in('Asym_Pause', linkmodes, "rx on tx on must not advertise Asym_Pause")
>
> remote_linkmodes = peer.get_lp_advertising()
> ksft_in('Pause', linkmodes, "PHY does not advertise Pause")
> ksft_not_in('Asym_Pause', linkmodes, "PHY incorrectly advertises Asym_Pause")
There should be a sleep in here somewhere, to allow the autoneg to
complete.
Andrew
^ permalink raw reply
* Re: [PATCH net-next] Documentation: networking: Add a test plan for ethtool pause validation
From: Maxime Chevallier @ 2026-06-26 12:51 UTC (permalink / raw)
To: Andrew Lunn
Cc: Jakub Kicinski, davem, Eric Dumazet, Paolo Abeni, Simon Horman,
Russell King, Heiner Kallweit, Jonathan Corbet, Shuah Khan,
Oleksij Rempel, Vladimir Oltean, Florian Fainelli,
thomas.petazzoni, netdev, linux-kernel, linux-doc
In-Reply-To: <5b7dbdbc-93fd-4664-abad-0f47855fab55@lunn.ch>
Hi,
On 6/26/26 14:39, Andrew Lunn wrote:
> On Fri, Jun 26, 2026 at 10:33:50AM +0200, Maxime Chevallier wrote:
>>
>>> Sphinx follows pythons object orientate structure. So you could have a
>>> class test_ethtool_pause_advertising, with class documentation. And
>>> then methods within the class which are individual tests. The
>>> commented out section would then be method documentation.
>>
>> Good point, so maybe something along these lines :
>>
>> - A class for the test
>> - methods for indivitual tests
>> - For readability, I've written what the internal test helper would look
>> like (_adv_test), and how a test would look like without the helper in
>> adv_rx_on_tx_on().
>>
>> I'm already diving into coding, but it helps me a bit in the definition of the
>> "description" format :)
>>
>> this is what the class would look like :
>
> I like this :-)
Great :)
>
>>
>>
>> @ksft_ethtool_needs_supported_allof([Pause])
>> def adv_rx_on_tx_on(cfg, peer) -> None:
>
> Using decorators is a nice idea. Since it is not a C concept, please
> give the decorator a good comment explaining what it does. We should
> not assume driver developers know python.
No problem, I'll add that
>
>> """Advertising test with rx on tx on
>>
>> - run 'ethtool -A ethX rx on tx on autoneg on'
>> - FAIL if the return isn't 0
>> - FAIL if ETHTOOL_A_LINKMODES_OURS's advertised values does not contain
>> "Pause" or contains "Asym_Pause"
>> - FAIL if peer's lp_advertising doesn't contain "Pause" or contains
>> "Asym_Pause"
>> - Succeed otherwise
>> """
>> ret = cfg.run('ethtool -A ethX rx on tx on autoneg on')
>> ksft_eq(ret, 0)
>>
>> linkmodes = cfg.get_advertising()
>> ksft_in('Pause', linkmodes, "rx on tx on must advertise Pause")
>> ksft_not_in('Asym_Pause', linkmodes, "rx on tx on must not advertise Asym_Pause")
>>
>> remote_linkmodes = peer.get_lp_advertising()
>> ksft_in('Pause', linkmodes, "PHY does not advertise Pause")
>> ksft_not_in('Asym_Pause', linkmodes, "PHY incorrectly advertises Asym_Pause")
>
> There should be a sleep in here somewhere, to allow the autoneg to
> complete.
Indeed, I think in the end this will be wrapped by some ksft_ethtool_* helper we'll add,
that will also deal with the case where autoneg doesn't succeed and the link stays down.
That's both for error detections, but I also expect there might be cases we'll want to test
that autoneg does not actually succeed.
Good to see we're closing in on a definition, I'll spin V2 based on that format :)
Maxime
^ permalink raw reply
* Re: [PATCH net] net: pse-pd: scope pse_control regulator handle to kref lifetime
From: Simon Horman @ 2026-06-26 12:57 UTC (permalink / raw)
To: Carlo Szelinsky
Cc: Oleksij Rempel, Kory Maincent, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Corey Leavitt, netdev,
linux-kernel
In-Reply-To: <20260624203838.2752376-1-github@szelinsky.de>
On Wed, Jun 24, 2026 at 10:38:38PM +0200, Carlo Szelinsky wrote:
> On Wed, 24 Jun 2026 16:12:51 +0100, Simon Horman wrote:
> > This is an AI-generated review of your patch. The human sending this
> > email has considered the AI review valid, or at least plausible.
> [...]
> > [High]
> > Does this fix the use-after-free completely, or only the regulator-put
> > part of it?
> [...]
> > Would a more complete fix also need pse_controller_unregister() to
> > drain outstanding pse_control references, or have pse_control hold a
> > refcount on pcdev, so that psec cannot outlive pcdev->pi and pcdev?
>
> Thanks, the review is correct. This patch only fixes the regulator
> handle. In the same unbind-while-held case __pse_control_release()
> also reads psec->pcdev->pi[] and psec->pcdev->owner after
> pse_controller_unregister() has freed pcdev->pi, so those are still
> use-after-free reads on their own.
>
> That wider problem is exactly what you describe: the controller does
> not drain its outstanding pse_control references on unregister. It is
> fixed by draining them, which is what the PSE notifier series does --
> PSE_UNREGISTERED drops every phydev->psec before pse_release_pis()
> frees pcdev->pi. This patch is patch 1 of that series (by Corey
> Leavitt); the rest targets net-next and is deferred until it reopens:
>
> https://lore.kernel.org/netdev/20260620112440.1734404-1-github@szelinsky.de/
>
> Jakub suggested sending this one to net on its own since it is a fix,
> so it is here without the notifier patches. My v1 commit message
> overclaimed by saying it makes __pse_control_release() correct
> regardless of the controller's devres state, which is only true for
> the regulator handle. I have reworded it in v2 to scope it to the
> regulator put and to point at the series for the wider lifetime fix.
>
> Does you agree? Another option would be to wait for the entire series.
Thanks for the clarification.
Yes, I agree this is a good approach.
^ permalink raw reply
* Re: [PATCH net v2] net: pse-pd: scope pse_control regulator handle to kref lifetime
From: Simon Horman @ 2026-06-26 12:57 UTC (permalink / raw)
To: Carlo Szelinsky
Cc: Oleksij Rempel, Kory Maincent, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Corey Leavitt,
Heiner Kallweit, Russell King, netdev, linux-kernel
In-Reply-To: <20260624204017.2752934-1-github@szelinsky.de>
On Wed, Jun 24, 2026 at 10:40:16PM +0200, Carlo Szelinsky wrote:
> From: Corey Leavitt <corey@leavitt.info>
>
> __pse_control_release() drops psec->ps via devm_regulator_put(), which
> only succeeds if the devres entry added by the matching
> devm_regulator_get_exclusive() is still present on pcdev->dev at the
> time the pse_control's kref hits zero.
>
> That assumption does not hold when the controller is unbound while a
> pse_control still has consumers: pcdev->dev's devres list is released
> LIFO, so every per-attach regulator-GET devres runs (and
> regulator_put()s the underlying regulator) before
> pse_controller_unregister() itself is invoked. Any later
> pse_control_put() from that unbind path then reads psec->ps as a
> dangling pointer inside devm_regulator_put() and WARNs at
> drivers/regulator/devres.c:232 (devres_release() fails to find the
> already-released match).
>
> The pse_control's consumer handle is logically scoped to the
> pse_control's refcount, not to pcdev->dev's devres lifetime. Switch to
> the plain regulator_get_exclusive() / regulator_put() pair so the
> regulator put in __pse_control_release() no longer depends on the
> controller's devres still being present. No change to the
> regulator-framework-visible refcount or lifetime of the underlying
> regulator: a single get paired with a single put. The existing
> devm_regulator_register() for the per-PI rails is unchanged (those ARE
> correctly scoped to the controller's lifetime).
>
> This addresses only the regulator handle. The same unbind-while-held
> scenario also leaves __pse_control_release() reading psec->pcdev->pi[]
> and psec->pcdev->owner after pse_controller_unregister() has freed
> pcdev->pi, because the controller does not drain its outstanding
> pse_control references on unregister. That wider pse_control vs
> pcdev lifetime problem pre-dates this change and is addressed by the
> PSE controller notifier series, which drains phydev->psec on
> PSE_UNREGISTERED before pcdev->pi is freed.
>
> Link: https://lore.kernel.org/netdev/20260620112440.1734404-1-github@szelinsky.de/
> Fixes: d83e13761d5b ("net: pse-pd: Use regulator framework within PSE framework")
> Signed-off-by: Corey Leavitt <corey@leavitt.info>
> Acked-by: Kory Maincent <kory.maincent@bootlin.com>
> Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
> ---
> This is patch 1 of the "decouple controller lookup from MDIO probe"
> series, reposted on its own for net as Jakub suggested. The rest of the
> series targets net-next and is deferred until it reopens.
>
> Changes in v2:
> - Reword the commit message to scope the fix to the regulator handle.
> As Simon's review pointed out, the same unbind-while-held path also
> reads pcdev->pi[] and pcdev->owner after pse_release_pis(); that wider
> pse_control vs pcdev lifetime issue is fixed by the notifier series,
> not here. No code change.
> Link: https://lore.kernel.org/netdev/20260624151251.1137250-1-horms@kernel.org/
> v1: https://lore.kernel.org/netdev/20260622192839.2508733-1-github@szelinsky.de/
Thanks for the update.
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* Re: [PATCH net v2] nfc: nci: fix uninit-value in nci_core_init_rsp_packet()
From: Simon Horman @ 2026-06-26 13:12 UTC (permalink / raw)
To: Samuel Page
Cc: David Heidelberg, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, oe-linux-nfc, netdev, linux-kernel, stable
In-Reply-To: <20260624224455.999374-1-sam@bynar.io>
On Wed, Jun 24, 2026 at 11:44:55PM +0100, Samuel Page wrote:
> The CORE_INIT_RSP handlers walk the response using length fields taken
> from the packet itself, without checking they stay within skb->len:
>
> - v1 computes
> rsp_2 = skb->data + 6 + rsp_1->num_supported_rf_interfaces;
> from the on-wire (unclamped) interface count and then dereferences
> rsp_2, and memcpy()s the advertised interfaces - both can run past the
> received data;
> - v2 walks supported_rf_interfaces[], advancing the cursor by an
> in-packet rf_extension_cnt with no bound.
>
> A short CORE_INIT_RSP therefore makes the parser read past the packet
> (into the uninitialised tail of the RX skb); the values are stored into
> struct nci_dev and consumed while bringing the device up:
>
> BUG: KMSAN: uninit-value in nci_dev_up+0x10f3/0x1720
> nci_dev_up+0x10f3/0x1720
> nfc_dev_up+0x187/0x380
> nfc_genl_dev_up+0xdc/0x1a0
> genl_rcv_msg+0x5d4/0x9e0
> netlink_rcv_skb+0x28f/0x530
> Uninit was stored to memory at:
> nci_rsp_packet+0x68f/0x2310
> nci_rx_work+0x25f/0x5d0
> Uninit was created at:
> __alloc_skb+0x540/0xd40
> virtual_ncidev_write+0x65/0x210
>
> Validate the response length before parsing or storing the
> variable-length parts, rejecting truncated responses with
> NCI_STATUS_SYNTAX_ERROR. In v1 the check is done before
> num_supported_rf_interfaces is stored into ndev, so a truncated response
> cannot leave ndev->num_supported_rf_interfaces holding the unclamped
> on-wire count, which nci_init_complete_req() would otherwise use as a
> bound for the fixed-size supported_rf_interfaces[] array.
>
> Fixes: 6a2968aaf50c ("NFC: basic NCI protocol implementation")
> Fixes: bcd684aace34 ("net/nfc/nci: Support NCI 2.x initial sequence")
> Cc: stable@vger.kernel.org
> Tested-by: syzbot@syzkaller.appspotmail.com
> Assisted-by: Bynario AI
> Signed-off-by: Samuel Page <sam@bynar.io>
> ---
> v2: validate the response length before storing num_supported_rf_interfaces
> into @ndev. In v1 the unclamped on-wire count was stored first and the
> length check returned early on a truncated response, leaving
> ndev->num_supported_rf_interfaces > NCI_MAX_SUPPORTED_RF_INTERFACES; a
> subsequent CORE_INIT completion then walked it in nci_init_complete_req(),
> which the syzbot CI run on v1 flagged as a UBSAN array-index-out-of-bounds.
> https://ci.syzbot.org/series/2a9a8657-37a3-4dce-8cb5-2035027791dd
> v1: https://lore.kernel.org/all/20260623222402.175798-1-sam@bynar.io
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* Re: [mellanox/mlx5-next RFC 1/1] net/mlx5: RX, Fix refcount warning on frag page release
From: Dragos Tatulea @ 2026-06-26 13:12 UTC (permalink / raw)
To: Nabil S. Alramli, saeedm, tariqt, mbloch
Cc: nalramli, leon, andrew+netdev, davem, edumazet, kuba, pabeni,
netdev, linux-rdma, linux-kernel
In-Reply-To: <20260625174059.2879717-2-dev@nalramli.com>
On 25.06.26 19:40, Nabil S. Alramli wrote:
> Under memory pressure, mlx5 driver has WARNING during fragmented page
> release. This happens because there is a discrepency between what mlx5
> thinks the page fragment counter is vs what the page_pool actually says it
> is.
>
The mlx5 frag counter is not the same as pp_ref_count. The page gets
split into 64 parts during page allocation. The frag counter tracks how
many of those frags have been used.
> The cause of the issue is page allocations on concurrent cpus, which
> increment the non-atomic u16 page counter mlx5e_frag_page.frags, while at
> the same time the page reference counter net_iov.pp_ref_count is atomically
> incremented. That sometimes leads to a difference in the counts and
> therefore triggers the warning in page_pool_unref_netmem:
>
page_pool page allocations must not happen in parallel on different CPUs.
Each queue has its own page_pool and allocation happens within the NAPI of
that queue which sticks to a single CPU. The release path does support
releasing on another CPU (release to ring).
How did you encounter this scenario of having parallel allocations on
different CPUs from the same page_pool?
> ```
> ret = atomic_long_sub_return(nr, pp_ref_count);
> WARN_ON(ret < 0);
> ```
>
> The actual stack trace looks like this:
>
> ```
> WARNING: CPU: 37 PID: 447795 at include/net/page_pool/helpers.h:277 mlx5e_page_release_fragmented.isra.0+0x51/0x60 [mlx5_core]
> Tainted: [S]=CPU_OUT_OF_SPEC, [O]=OOT_MODULE
> Hardware name: *
> RIP: 0010:mlx5e_page_release_fragmented.isra.0+0x51/0x60 [mlx5_core]
> RSP: 0018:ffffc90019814d98 EFLAGS: 00010293
> RAX: 000000000000003f RBX: ffff88c0993d0a10 RCX: ffffea02424592c0
> RDX: 0000000000000001 RSI: ffffea02424592c0 RDI: ffff88c090e20000
> RBP: 000000000000000a R08: 0000000000001409 R09: 0000000000000006
> R10: 0000000000000000 R11: ffff88c095fbc040 R12: 000000000000141f
> R13: 0000000000000009 R14: ffff88c090e20000 R15: 0000000000000001
> FS: 00007f34149fa6c0(0000) GS:ffff89200fa40000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00007ed0265eb000 CR3: 0000005091cbe000 CR4: 0000000000350ef0
> Call Trace:
> <IRQ>
> mlx5e_free_rx_wqes+0x7b/0xa0 [mlx5_core]
> mlx5e_post_rx_wqes+0x1ac/0x5a0 [mlx5_core]
> mlx5e_napi_poll+0x5e5/0x6f0 [mlx5_core]
> __napi_poll+0x2b/0x1a0
> net_rx_action+0x30e/0x370
> ? sched_clock+0x9/0x10
> ? sched_clock_cpu+0xf/0x170
> handle_softirqs+0xe2/0x2a0
> common_interrupt+0x85/0xa0
> </IRQ>
> <TASK>
> asm_common_interrupt+0x26/0x40
> RIP: 0010:page_counter_uncharge+0x34/0x90
> RSP: 0018:ffffc900e728bb00 EFLAGS: 00000213
> RAX: ffff88aff4762000 RBX: ffff88aff4762100 RCX: 0000000000000304
> RDX: 0000000000000001 RSI: 00000000004e9e1a RDI: ffff88aff4762100
> RBP: 0000000000000001 R08: ffff891ea0560048 R09: 00007ffffffff000
> R10: 0000000000001000 R11: ffff891ae8061b00 R12: ffffffffffffffff
> R13: ffff89107fcfd4c0 R14: ffff891ae8061b00 R15: ffff892002fe1400
> uncharge_batch+0x40/0xd0
> ```
>
Can you provide more data on how you reproduced this? This helps to
narrow down the bug. Reproduction steps would be ideal.
> The fix is to use an atomic page fragment counter, so it will always match
> the number of references held in the page_pool.
>
This is not the right fix. The mlx5 page frag counter is not atomic
on purpose because all changes to it happen only within the NAPI
context.
Thanks,
Dragos
^ permalink raw reply
* Re: [PATCH v2 bpf-next 0/2] bpf: bpf_redirect_peer egress redirection
From: patchwork-bot+netdevbpf @ 2026-06-26 13:30 UTC (permalink / raw)
To: Jordan Rife
Cc: bpf, netdev, ast, daniel, andrii, martin.lau, sdf, jiayuan.chen,
paul.chaignon
In-Reply-To: <20260618182035.43811-1-jordan@jrife.io>
Hello:
This series was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:
On Thu, 18 Jun 2026 11:20:31 -0700 you wrote:
> We have several use cases where a pod injects traffic into the datapath
> of another so that the traffic appears to have originated from that
> pod. One such use case is a synthetic flow generator which injects
> synthetic traffic into a pod's datapath to enable dynamic probing and
> debugging. Another is a transparent proxy where connections originating
> from one pod are redirected towards another which proxies that
> connection. The new connection is bound to the IP of the original pod
> using IP_TRANSPARENT and its traffic is injected into that pod's
> datapath and handled as if it had originated there. This can be used for
> mTLS, etc.
>
> [...]
Here is the summary with links:
- [v2,bpf-next,1/2] bpf: Support BPF_F_EGRESS with bpf_redirect_peer
https://git.kernel.org/bpf/bpf-next/c/509ca545d425
- [v2,bpf-next,2/2] selftests/bpf: Add tests for bpf_redirect_peer with BPF_F_EGRESS
https://git.kernel.org/bpf/bpf-next/c/006b9456e9f4
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH v8 00/14] firmware: qcom: Add OP-TEE PAS service support
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
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 and lemans
EVK boards. In addition to that WIN/IPQ targets tested OP-TEE with
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 generic PAS service.
- Patch #2: migrates SCM backend to generic PAS service.
- Patch #3: adds TEE/OP-TEE backend for generic PAS service.
- Patch #4-#12: migrates all client drivers to generic PAS service.
- Patch #13: drops legacy PAS SCM exported APIs.
The patch-set is based on qcom tree tip [2] and can be found in git tree
here [3].
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 (already merged)
[2] https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git/log/?h=for-next
[3] https://git.kernel.org/pub/scm/linux/kernel/git/sumit.garg/linux.git/log/?h=qcom-pas-v8
---
Changes in v8:
- Rebased on mainline tip (no functional changes).
- Now Lemans EVK is also tested to support OP-TEE PAS here:
https://github.com/OP-TEE/optee_os/pull/7845
- Drop Kodiak DT patch as it is carried independently by Mukesh here:
https://lore.kernel.org/lkml/20260624063952.2242702-1-mukesh.ojha@oss.qualcomm.com/
- Regarding Sashiko comments, I have already replied in v6 the ones that
don't apply but in v7 I got the same comments again. Specific context
reasoning which Shashiko ignores:
- ABI contract between Linux and TZ
- No support for multiple concurrent backends
- The TZ backend doesn’t detach during the entire boot cycle
Changes in v7:
- Rebased to qcom tree (for-next branch) tip.
- Merged patch #5 and #7 due to build dependency.
- Disabled modem for kodiak EL2 as it isn't tested yet.
- Fix an issue found out by sashiko-bot for patch #4.
Changes in v6:
- Rebased to v7.1-rc4 tag.
- Patch #14: fixed ret error print.
- Add Kconfig descriptions for PAS symbols such that they are visible
in menuconfig to update.
Changes in v5:
- Incorporated misc. comments from Mukesh.
- Split up patch #11 into 2 to add an independent commit for passing
proper PAS ID to set_remote_state API.
- Picked up tags.
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.
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
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
media: qcom: Pass proper PAS ID to set_remote_state API
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 +
drivers/firmware/qcom/Kconfig | 21 +-
drivers/firmware/qcom/Makefile | 2 +
drivers/firmware/qcom/qcom_pas.c | 291 +++++++++++
drivers/firmware/qcom/qcom_pas.h | 50 ++
drivers/firmware/qcom/qcom_pas_tee.c | 477 ++++++++++++++++++
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 | 27 +-
.../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 | 10 +-
drivers/remoteproc/Kconfig | 4 +-
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 +-
26 files changed, 1084 insertions(+), 321 deletions(-)
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.53.0
^ permalink raw reply
* [PATCH v8 01/14] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg,
Harshal Dev
In-Reply-To: <20260626133440.692849-1-sumit.garg@kernel.org>
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.
Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
Reviewed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Tested-by: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com> # IPQ9650
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 | 291 +++++++++++++++++++++++++
drivers/firmware/qcom/qcom_pas.h | 50 +++++
include/linux/firmware/qcom/qcom_pas.h | 43 ++++
5 files changed, 393 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..9f66cc774508 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -6,6 +6,14 @@
menu "Qualcomm firmware drivers"
+config QCOM_PAS
+ tristate "Qualcomm generic PAS interface driver"
+ 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..bc6c42f2b3c6
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
+ * Copyright (C) 2015 Linaro Ltd.
+ * 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 (!ops_ptr || !ctx || !ctx->ptr)
+ 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 (!ops_ptr)
+ return ERR_PTR(-ENODEV);
+ if (!ctx)
+ return ERR_PTR(-EINVAL);
+
+ 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 devm_qcom_pas_context_alloc()
+ *
+ * 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 (!ops_ptr)
+ return -ENODEV;
+ if (!ctx)
+ return -EINVAL;
+
+ 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 by %s\n",
+ ops_ptr->drv_name);
+}
+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 generic TZ PAS driver");
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.
+ */
+
+#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.53.0
^ permalink raw reply related
* [PATCH v8 02/14] firmware: qcom_scm: Migrate to generic PAS service
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg,
Harshal Dev
In-Reply-To: <20260626133440.692849-1-sumit.garg@kernel.org>
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.
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
Reviewed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Tested-by: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com> # IPQ9650
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/firmware/qcom/Kconfig | 3 +-
drivers/firmware/qcom/qcom_scm.c | 335 ++++++++++++++-----------------
2 files changed, 156 insertions(+), 182 deletions(-)
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index 9f66cc774508..732a0bff7d9f 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -15,8 +15,9 @@ config QCOM_PAS
TEE bus based PAS service implementation.
config QCOM_SCM
+ tristate "Qualcomm PAS SCM interface driver"
+ select QCOM_PAS
select QCOM_TZMEM
- tristate
config QCOM_TZMEM
tristate
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 6b601a4b89db..7933e55803dc 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)
+{
+ 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))
+ return false;
+
+ return true;
+}
+
static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset)
{
struct qcom_scm_desc desc = {
@@ -2837,6 +2804,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
__get_convention();
+ if (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
@@ -2876,6 +2848,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.53.0
^ permalink raw reply related
* [PATCH v8 03/14] firmware: qcom: Add a PAS TEE service
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg,
Harshal Dev
In-Reply-To: <20260626133440.692849-1-sumit.garg@kernel.org>
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.
Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
Reviewed-by: Harshal Dev <harshal.dev@oss.qualcomm.com>
Tested-by: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com> # IPQ9650
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 | 477 +++++++++++++++++++++++++++
3 files changed, 488 insertions(+)
create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index 732a0bff7d9f..b851bcc592be 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 "Qualcomm PAS TEE interface driver"
+ 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
tristate "Qualcomm PAS SCM interface driver"
select QCOM_PAS
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..a2ba3af05a50
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas_tee.c
@@ -0,0 +1,477 @@
+// 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_OR_NULL(rt_shm)) {
+ dev_err(dev, "rt_shm allocation failed\n");
+ rt_shm = NULL;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ 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);
+
+ 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 set remote state 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_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);
+ ctx->ptr = NULL;
+}
+
+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;
+
+ 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);
+ tee_client_close_context(data->ctx);
+ return ret ?: -EINVAL;
+ }
+
+ 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;
+}
+
+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.53.0
^ permalink raw reply related
* [PATCH v8 04/14] remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260626133440.692849-1-sumit.garg@kernel.org>
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.
Since qcom_q6v5_pas depends on MDT loader for PAS firmware loading, it
has to be switched over to generic PAS APIs in this commit to avoid any
build issues.
Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
Tested-by: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com> # IPQ9650
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/remoteproc/qcom_q6v5_pas.c | 51 +++++++++++++++--------------
drivers/soc/qcom/mdt_loader.c | 12 +++----
include/linux/soc/qcom/mdt_loader.h | 6 ++--
3 files changed, 35 insertions(+), 34 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index 808e9609988d..9eb1c4f6c2ab 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>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
@@ -115,8 +116,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,
@@ -193,7 +194,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;
@@ -209,9 +210,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;
}
@@ -225,9 +226,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);
@@ -247,7 +248,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;
@@ -307,7 +308,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");
@@ -326,7 +327,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");
@@ -336,13 +337,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;
@@ -352,9 +353,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)
@@ -403,7 +404,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);
@@ -411,7 +412,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);
@@ -481,11 +482,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);
@@ -743,7 +744,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;
@@ -835,16 +836,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;
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index c004d444d698..137992456b71 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 devm_qcom_pas_context_alloc()
* 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.53.0
^ permalink raw reply related
* [PATCH v8 05/14] remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260626133440.692849-1-sumit.garg@kernel.org>
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.
Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
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>
#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;
--
2.53.0
^ permalink raw reply related
* [PATCH v8 06/14] remoteproc: qcom_wcnss: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260626133440.692849-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Switch qcom_wcnss 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.
Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/remoteproc/qcom_wcnss.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index 4add9037dbd5..0dbdd18ab3dd 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -19,7 +19,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -257,7 +257,7 @@ static int wcnss_start(struct rproc *rproc)
wcnss_indicate_nv_download(wcnss);
wcnss_configure_iris(wcnss);
- ret = qcom_scm_pas_auth_and_reset(WCNSS_PAS_ID);
+ ret = qcom_pas_auth_and_reset(WCNSS_PAS_ID);
if (ret) {
dev_err(wcnss->dev,
"failed to authenticate image and release reset\n");
@@ -269,7 +269,7 @@ static int wcnss_start(struct rproc *rproc)
if (wcnss->ready_irq > 0 && ret == 0) {
/* We have a ready_irq, but it didn't fire in time. */
dev_err(wcnss->dev, "start timed out\n");
- qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ qcom_pas_shutdown(WCNSS_PAS_ID);
ret = -ETIMEDOUT;
goto disable_iris;
}
@@ -311,7 +311,7 @@ static int wcnss_stop(struct rproc *rproc)
0);
}
- ret = qcom_scm_pas_shutdown(WCNSS_PAS_ID);
+ ret = qcom_pas_shutdown(WCNSS_PAS_ID);
if (ret)
dev_err(wcnss->dev, "failed to shutdown: %d\n", ret);
@@ -557,10 +557,10 @@ static int wcnss_probe(struct platform_device *pdev)
data = of_device_get_match_data(&pdev->dev);
- if (!qcom_scm_is_available())
+ if (!qcom_pas_is_available())
return -EPROBE_DEFER;
- if (!qcom_scm_pas_supported(WCNSS_PAS_ID)) {
+ if (!qcom_pas_supported(WCNSS_PAS_ID)) {
dev_err(&pdev->dev, "PAS is not available for WCNSS\n");
return -ENXIO;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v8 07/14] remoteproc: qcom: Select QCOM_PAS generic service
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, pavan.kondeti, jorge.ramirez,
tonyh, vignesh.viswanathan, srinivas.kandagatla, amirreza.zarrabi,
jens.wiklander, op-tee, apurupa, skare, linux-kernel, Sumit Garg
In-Reply-To: <20260626133440.692849-1-sumit.garg@kernel.org>
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.
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
Tested-by: Vignesh Viswanathan <vignesh.viswanathan@oss.qualcomm.com> # IPQ9650
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/remoteproc/Kconfig | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index c521c744e7db..65befdbfa5f7 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -210,6 +210,7 @@ config QCOM_Q6V5_MSS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the Qualcomm self-authenticating modem
subsystem based on Hexagon V5. The TrustZone based system is
@@ -230,6 +231,7 @@ config QCOM_Q6V5_PAS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
+ 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
@@ -282,7 +284,7 @@ config QCOM_WCNSS_PIL
select QCOM_MDT_LOADER
select QCOM_PIL_INFO
select QCOM_RPROC_COMMON
- select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the Peripheral Image Loader for loading WCNSS
firmware and boot the core on e.g. MSM8974, MSM8916. The firmware is
--
2.53.0
^ permalink raw reply related
* [PATCH v8 08/14] drm/msm: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-06-26 13:34 UTC (permalink / raw)
To: andersson
Cc: linux-arm-msm, dri-devel, freedreno, linux-media, netdev,
linux-wireless, ath12k, linux-remoteproc, konradybcio, robh,
krzk+dt, conor+dt, robin.clark, sean, akhilpo, lumag,
abhinav.kumar, jesszhan0024, marijn.suijten, airlied, simona,
vikash.garodia, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, mukesh.ojha, 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: <20260626133440.692849-1-sumit.garg@kernel.org>
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>
Reviewed-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Tested-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com> # Lemans
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/gpu/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
+ 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 2c0bbac43c52..57135acc8e2c 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 c62c45bb0ddb..c36382b23310 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>
#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.53.0
^ permalink raw reply related
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