* MAINTAINERS: Add self for the DEC LANCE network driver
From: Maciej W. Rozycki @ 2026-04-27 10:23 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, linux-kernel
Like with the rest of DECstation and TURBOchannel hardware I have been
handling the DEC LANCE network driver for some 25 years now anyway.
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
linux-maintainers-declance.diff
Index: linux-macro/MAINTAINERS
===================================================================
--- linux-macro.orig/MAINTAINERS
+++ linux-macro/MAINTAINERS
@@ -6986,6 +6986,12 @@ T: git git://git.kernel.org/pub/scm/linu
F: include/linux/debugobjects.h
F: lib/debugobjects.c
+DEC LANCE NETWORK DRIVER
+M: "Maciej W. Rozycki" <macro@orcam.me.uk>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/amd/declance.c
+
DECSTATION PLATFORM SUPPORT
M: "Maciej W. Rozycki" <macro@orcam.me.uk>
L: linux-mips@vger.kernel.org
^ permalink raw reply
* MAINTAINERS: Add self for the 3c509 network driver
From: Maciej W. Rozycki @ 2026-04-27 10:23 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, linux-kernel
It appears there's a need for a maintainer for the 3Com EtherLink III
family of Ethernet network adapters. There is documentation available
and the driver is very mature so the task ought to be of little hassle,
so I think I should be able to squeeze in any issues to be addressed.
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
linux-maintainers-3c509.diff
Index: linux-macro/MAINTAINERS
===================================================================
--- linux-macro.orig/MAINTAINERS
+++ linux-macro/MAINTAINERS
@@ -67,6 +67,12 @@ Maintainers List
first. When adding to this list, please keep the entries in
alphabetical order.
+3C509 NETWORK DRIVER
+M: "Maciej W. Rozycki" <macro@orcam.me.uk>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/3com/3c509.c
+
3C59X NETWORK DRIVER
M: Steffen Klassert <klassert@kernel.org>
L: netdev@vger.kernel.org
^ permalink raw reply
* Re: [PATCH v2 bpf 1/1] xskmap: reject TX-only AF_XDP sockets
From: bot+bpf-ci @ 2026-04-27 10:23 UTC (permalink / raw)
To: linpu5433, kerneljasonxing, magnus.karlsson, maciej.fijalkowski,
netdev, bpf
Cc: sdf, davem, edumazet, kuba, pabeni, horms, ast, daniel, hawk,
john.fastabend, bjorn, linux-kernel, tanyuan98, yifanwucs, ast,
andrii, daniel, martin.lau, eddyz87, yonghong.song, clm,
ihor.solodrai
In-Reply-To: <2b156bc4277a9e891f3399935416701d1f9efd7c.1777276241.git.linpu5433@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1740 bytes --]
> commit 6df1a89cfba973e50ce1bcafe9ffe818f3de7c06
> Author: Linpu Yu <linpu5433@gmail.com>
>
> xskmap: reject TX-only AF_XDP sockets
>
> XSKMAP entries are used as redirect targets for incoming XDP frames.
> A TX-only AF_XDP socket lacks an Rx ring and cannot handle redirected
> traffic, but xsk_map_update_elem() currently allows such sockets to
> be inserted into the map.
>
> Redirecting packets to such a socket on the veth generic-XDP path
> causes a kernel crash in xsk_generic_rcv().
>
> Reject TX-only sockets during XSKMAP updates to avoid the crash.
> They remain fully operational for pure Tx purposes outside XSKMAP.
>
> Fixes: fbfc504a24f5 ("bpf: introduce new bpf AF_XDP map type BPF_MAP_TYPE_XSKMAP")
^^^^
Is this the correct commit to fix? The original commit fbfc504a24f5
introduced xskmap WITH a check (xsk_is_setup_for_bpf_map) that prevented
TX-only sockets from being inserted. It looks like commit 968be23ceaca
("xsk: Fix possible segfault at xskmap entry insertion") later removed
this check, which allowed TX-only sockets without Rx rings to be
inserted into the map, causing the kernel crash.
Should the Fixes tag reference 968be23ceaca instead?
> Reported-by: Juefei Pu <tomapufckgml@gmail.com>
> Reported-by: Yuan Tan <yuantan098@gmail.com>
> Reported-by: Xin Liu <bird@lzu.edu.cn>
> Signed-off-by: Yifan Wu <yifanwucs@gmail.com>
> Signed-off-by: Linpu Yu <linpu5433@gmail.com>
[ ... ]
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/24988517198
^ permalink raw reply
* Re: [Intel-wired-lan] [PATCH v2] ice: wait for reset completion in ice_resume()
From: Paul Menzel @ 2026-04-27 10:13 UTC (permalink / raw)
To: Aaron Ma
Cc: Tony Nguyen, Przemek Kitszel, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, netdev, linux-kernel,
Akeem G Abodunrin, Jesse Brandeburg, intel-wired-lan, Kohei Enju
In-Reply-To: <20260424030345.1140665-1-aaron.ma@canonical.com>
Dear Aaron,
Thank you for your patch.
Am 24.04.26 um 05:03 schrieb Aaron Ma via Intel-wired-lan:
> ice_resume() schedules an asynchronous PF reset and returns
> immediately. The reset runs later in ice_service_task(). If
> userspace tries to bring up the net device before the reset
> finishes, ice_open() fails with -EBUSY:
>
> ice_resume()
> ice_schedule_reset() # sets ICE_PFR_REQ, returns
> ...
> ice_open()
> ice_is_reset_in_progress() # ICE_PFR_REQ still set, -EBUSY
> ...
> ice_service_task()
> ice_do_reset()
> ice_rebuild() # clears ICE_PFR_REQ, too late
>
> Reproduced on E800 series NICs during suspend/resume with irdma
> enabled, where the aux device probe widens the race window.
Please document, how you reproduced it, and also paste possible messages
by Linux or NetworkManager, so that people can easily search for the commit.
> Wait for the reset to complete before returning from ice_resume().
Please mention the delay length in the commit message.
> Fixes: 769c500dcc1e ("ice: Add advanced power mgmt for WoL")
> Cc: stable@vger.kernel.org
> Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
> ---
> v2: reword comment to clarify best-effort semantics (Kohei Enju)
>
> drivers/net/ethernet/intel/ice/ice_main.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> index 5f92377d4dfc2..a81eb21ea87c1 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -5635,6 +5635,15 @@ static int ice_resume(struct device *dev)
> /* Restart the service task */
> mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
>
> + /* Best-effort wait for the scheduled reset to finish so that the
> + * device is operational before returning. Without this, userspace
> + * (e.g. NetworkManager) may try to open the net device while the
> + * asynchronous reset is still in progress, hitting -EBUSY.
> + */
> + ret = ice_wait_for_reset(pf, 10 * HZ);
Why not pass a delay in micro/milliseconds?
> + if (ret)
> + dev_err(dev, "Wait for reset failed during resume: %d\n", ret);
Mention the delay?
> +
> return 0;
> }
>
Kind regards,
Paul
^ permalink raw reply
* Re: [PATCH v4 net 10/10] octeontx2-af: npc: cn20k: Reject missing default-rule MCAM indices
From: Ratheesh Kannoth @ 2026-04-27 10:13 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Suman Ghosh
In-Reply-To: <20260427063213.3937451-11-rkannoth@marvell.com>
On 2026-04-27 at 12:02:13, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> When cn20k default L2 rules are not installed,
> npc_cn20k_dft_rules_idx_get() leaves broadcast, multicast,
> promiscuous, and unicast slots at USHRT_MAX.
> npc_get_nixlf_mcam_index() previously returned that sentinel as a
> diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> index 5d349d131fdb..9e6c79d6fadf 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
[ ... ]
>> @@ -3897,6 +4006,14 @@ int rvu_mbox_handler_npc_read_base_steer_rule(struct rvu *rvu,
>> /* Read the default ucast entry if there is no pkt steering rule */
>> index = npc_get_nixlf_mcam_index(mcam, pcifunc, nixlf,
>> NIXLF_UCAST_ENTRY);
>> + if (index < 0) {
>> + mutex_unlock(&mcam->lock);
>> + dev_err(rvu->dev,
>> + "%s: Error to get ucast entry for pcifunc=%#x\n",
>> + __func__, pcifunc);
>> + goto out;
>> + }
>> +
>Should this path set rc before jumping to out?
>Looking at the surrounding function, rc is initialized to 0 and the out
>label simply returns rc:
> int index, blkaddr, nixlf, rc = 0;
> ...
> out:
> return rc;
>The adjacent nix_get_nixlf() failure path assigns rc before the goto,
>and other error paths in this file use return NPC_MCAM_INVALID_REQ.
>On this new error path rc stays 0, npc_read_mcam_entry() is skipped, and
>the handler returns success with rsp->entry left zero-filled. Would the
>requester be unable to distinguish this failure from a legitimate reply?
>Would assigning rc = NPC_MCAM_INVALID_REQ (or another negative errno)
>before goto out be more appropriate here?
>> read_entry:
>> /* Read the mcam entry */
>> npc_read_mcam_entry(rvu, mcam, blkaddr, index, &rsp->entry, &intf,
pw-bot: changes-requested
ACK. will set rc for this error path.
^ permalink raw reply
* [PATCH net v3] ipv6: Implement limits on extension header parsing
From: Daniel Borkmann @ 2026-04-27 10:13 UTC (permalink / raw)
To: kuba
Cc: edumazet, dsahern, tom, willemdebruijn.kernel, idosch,
justin.iurman, pabeni, netdev
ipv6_{skip_exthdr,find_hdr}() and ip6_{tnl_parse_tlv_enc_lim,
protocol_deliver_rcu}() iterate over IPv6 extension headers until they
find a non-extension-header protocol or run out of packet data. The
loops have no iteration counter, relying solely on the packet length
to bound them. For a crafted packet with 8-byte extension headers
filling a 64KB jumbogram, this means a worst case of up to ~8k
iterations with a skb_header_pointer call each. ipv6_skip_exthdr(),
for example, is used where it parses the inner quoted packet inside
an incoming ICMPv6 error:
- icmpv6_rcv
- checksum validation
- case ICMPV6_DEST_UNREACH
- icmpv6_notify
- pskb_may_pull() <- pull inner IPv6 header
- ipv6_skip_exthdr() <- iterates here
- pskb_may_pull()
- ipprot->err_handler() <- sk lookup
The per-iteration cost of ipv6_skip_exthdr itself is generally
light, but skb_header_pointer becomes more costly on reassembled
packets: the first ~1232 bytes of the inner packet are in the skb's
linear area, but the remaining ~63KB are in the frag_list where
skb_copy_bits is needed to read data.
Add a configurable limit via a new sysctl net.ipv6.max_ext_hdrs_number
(default 8, minimum 1). All four extension header walking functions
are bound by this limit. The sysctl is in line with commit 47d3d7ac656a
("ipv6: Implement limits on Hop-by-Hop and Destination options").
As documented, init_net is used to derive max_ext_hdrs_number to
be consistent given a net cannot always reliably be retrieved.
Note that the check in ip6_protocol_deliver_rcu() happens right
before the goto resubmit, such that we don't have to have a test
for ipv6_ext_hdr() in the fast-path.
There's an ongoing IETF draft-iurman-6man-eh-occurrences to enforce
IPv6 extension headers ordering and occurrence. The latter also
discusses security implications. As per RFC8200 section 4.1, the
occurrence rules for extension headers provide a practical upper
bound, thus 8 was used as the default.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
v2->v3:
- Adding IP6SKB_HOPBYHOP coverage (Justin)
- I left the limit at 8 w/ sysctl, still feels the better
option to me if we can keep the worst-case more tightened
v1->v2:
- Set the default to 8 (Justin)
- Update IETF references (Justin)
- Add core path coverage as well (Justin)
Documentation/networking/ip-sysctl.rst | 7 +++++++
include/net/dropreason-core.h | 6 ++++++
include/net/ipv6.h | 2 ++
include/net/netns/ipv6.h | 1 +
net/ipv6/af_inet6.c | 1 +
net/ipv6/exthdrs_core.c | 11 +++++++++++
net/ipv6/ip6_input.c | 6 ++++++
net/ipv6/ip6_tunnel.c | 5 +++++
net/ipv6/sysctl_net_ipv6.c | 8 ++++++++
9 files changed, 47 insertions(+)
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index 2e3a746fcc6d..f7412f4049d1 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -2537,6 +2537,13 @@ max_hbh_length - INTEGER
Default: INT_MAX (unlimited)
+max_ext_hdrs_number - INTEGER
+ Maximum number of IPv6 extension headers allowed in a packet.
+ Limits how many extension headers will be traversed. The value
+ is read from the initial netns.
+
+ Default: 8
+
skip_notify_on_dev_down - BOOLEAN
Controls whether an RTM_DELROUTE message is generated for routes
removed when a device is taken down or deleted. IPv4 does not
diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index e0ca3904ff8e..1fd91e59b84e 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -99,6 +99,7 @@
FN(FRAG_TOO_FAR) \
FN(TCP_MINTTL) \
FN(IPV6_BAD_EXTHDR) \
+ FN(IPV6_TOO_MANY_EXTHDRS) \
FN(IPV6_NDISC_FRAG) \
FN(IPV6_NDISC_HOP_LIMIT) \
FN(IPV6_NDISC_BAD_CODE) \
@@ -494,6 +495,11 @@ enum skb_drop_reason {
SKB_DROP_REASON_TCP_MINTTL,
/** @SKB_DROP_REASON_IPV6_BAD_EXTHDR: Bad IPv6 extension header. */
SKB_DROP_REASON_IPV6_BAD_EXTHDR,
+ /**
+ * @SKB_DROP_REASON_IPV6_TOO_MANY_EXTHDRS: Number of IPv6 extension
+ * headers in the packet exceeds net.ipv6.max_ext_hdrs_number.
+ */
+ SKB_DROP_REASON_IPV6_TOO_MANY_EXTHDRS,
/** @SKB_DROP_REASON_IPV6_NDISC_FRAG: invalid frag (suppress_frag_ndisc). */
SKB_DROP_REASON_IPV6_NDISC_FRAG,
/** @SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT: invalid hop limit. */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index d042afe7a245..c540b750726e 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -90,6 +90,8 @@ struct ip_tunnel_info;
#define IP6_DEFAULT_MAX_DST_OPTS_LEN INT_MAX /* No limit */
#define IP6_DEFAULT_MAX_HBH_OPTS_LEN INT_MAX /* No limit */
+#define IP6_DEFAULT_MAX_EXT_HDRS_CNT 8
+
/*
* Addr type
*
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 499e4288170f..2cea457bddb4 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -54,6 +54,7 @@ struct netns_sysctl_ipv6 {
int max_hbh_opts_cnt;
int max_dst_opts_len;
int max_hbh_opts_len;
+ int max_ext_hdrs_cnt;
int seg6_flowlabel;
u32 ioam6_id;
u64 ioam6_id_wide;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 0a88b376141d..19424c3f2dfc 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -945,6 +945,7 @@ static int __net_init inet6_net_init(struct net *net)
net->ipv6.sysctl.flowlabel_state_ranges = 0;
net->ipv6.sysctl.max_dst_opts_cnt = IP6_DEFAULT_MAX_DST_OPTS_CNT;
net->ipv6.sysctl.max_hbh_opts_cnt = IP6_DEFAULT_MAX_HBH_OPTS_CNT;
+ net->ipv6.sysctl.max_ext_hdrs_cnt = IP6_DEFAULT_MAX_EXT_HDRS_CNT;
net->ipv6.sysctl.max_dst_opts_len = IP6_DEFAULT_MAX_DST_OPTS_LEN;
net->ipv6.sysctl.max_hbh_opts_len = IP6_DEFAULT_MAX_HBH_OPTS_LEN;
net->ipv6.sysctl.fib_notify_on_flag_change = 0;
diff --git a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
index 49e31e4ae7b7..9df892e7f7fb 100644
--- a/net/ipv6/exthdrs_core.c
+++ b/net/ipv6/exthdrs_core.c
@@ -4,6 +4,8 @@
* not configured or static.
*/
#include <linux/export.h>
+
+#include <net/net_namespace.h>
#include <net/ipv6.h>
/*
@@ -72,7 +74,9 @@ EXPORT_SYMBOL(ipv6_ext_hdr);
int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
__be16 *frag_offp)
{
+ int exthdr_max = READ_ONCE(init_net.ipv6.sysctl.max_ext_hdrs_cnt);
u8 nexthdr = *nexthdrp;
+ int exthdr_cnt = 0;
*frag_offp = 0;
@@ -82,6 +86,8 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
if (nexthdr == NEXTHDR_NONE)
return -1;
+ if (unlikely(exthdr_cnt++ >= exthdr_max))
+ return -1;
hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
if (!hp)
return -1;
@@ -188,8 +194,10 @@ EXPORT_SYMBOL_GPL(ipv6_find_tlv);
int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
int target, unsigned short *fragoff, int *flags)
{
+ int exthdr_max = READ_ONCE(init_net.ipv6.sysctl.max_ext_hdrs_cnt);
unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr);
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
+ int exthdr_cnt = 0;
bool found;
if (fragoff)
@@ -216,6 +224,9 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
return -ENOENT;
}
+ if (unlikely(exthdr_cnt++ >= exthdr_max))
+ return -EBADMSG;
+
hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
if (!hp)
return -EBADMSG;
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 967b07aeb683..79fa33573e53 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -403,6 +403,8 @@ INDIRECT_CALLABLE_DECLARE(int tcp_v6_rcv(struct sk_buff *));
void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
bool have_final)
{
+ int exthdr_max = READ_ONCE(init_net.ipv6.sysctl.max_ext_hdrs_cnt);
+ int exthdr_cnt = IP6CB(skb)->flags & IP6SKB_HOPBYHOP ? 1 : 0;
const struct inet6_protocol *ipprot;
struct inet6_dev *idev;
unsigned int nhoff;
@@ -487,6 +489,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
nexthdr = ret;
goto resubmit_final;
} else {
+ if (unlikely(exthdr_cnt++ >= exthdr_max)) {
+ SKB_DR_SET(reason, IPV6_TOO_MANY_EXTHDRS);
+ goto discard;
+ }
goto resubmit;
}
} else if (ret == 0) {
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index c468c83af0f2..4546a60942ab 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -395,15 +395,20 @@ ip6_tnl_dev_uninit(struct net_device *dev)
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
{
+ int exthdr_max = READ_ONCE(init_net.ipv6.sysctl.max_ext_hdrs_cnt);
const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
unsigned int nhoff = raw - skb->data;
unsigned int off = nhoff + sizeof(*ipv6h);
u8 nexthdr = ipv6h->nexthdr;
+ int exthdr_cnt = 0;
while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
struct ipv6_opt_hdr *hdr;
u16 optlen;
+ if (unlikely(exthdr_cnt++ >= exthdr_max))
+ break;
+
if (!pskb_may_pull(skb, off + sizeof(*hdr)))
break;
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index d2cd33e2698d..93f865545a7c 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -135,6 +135,14 @@ static struct ctl_table ipv6_table_template[] = {
.extra1 = SYSCTL_ZERO,
.extra2 = &flowlabel_reflect_max,
},
+ {
+ .procname = "max_ext_hdrs_number",
+ .data = &init_net.ipv6.sysctl.max_ext_hdrs_cnt,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = SYSCTL_ONE,
+ },
{
.procname = "max_dst_opts_number",
.data = &init_net.ipv6.sysctl.max_dst_opts_cnt,
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v4 net 09/10] octeontx2-af: npc: cn20k: Tear down default MCAM rules explicitly on free
From: Ratheesh Kannoth @ 2026-04-27 10:09 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev
In-Reply-To: <20260427063213.3937451-10-rkannoth@marvell.com>
On 2026-04-27 at 12:02:12, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_cn20k_dft_rules_free() used the NPC MCAM mbox "free all" path, which
> does not match how cn20k tracks default-rule MCAM slots indexes.
>
> Resolve the default-rule indices, then for each valid slot clear the
> bitmap entry, drop the PF/VF map, disable the MCAM line, clear the
> target function, and npc_cn20k_idx_free(). Remove any
> matching software mcam_rules nodes. On hard failure from idx_free, WARN
> and stop so the box stays up for analysis.
>
> In npc_mcam_free_all_entries(), prefetch the same default-rule indices
> and, on cn20k, skip bitmap clear and idx_free when the scanned entry is
> one of those reserved defaults (they are released by
> npc_cn20k_dft_rules_free). Still disable the entry and tear down counter
> mapping for every matching index.
>
> Fixes: 09d3b7a1403f ("octeontx2-af: npc: cn20k: Allocate default MCAM indexes")
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
>> free_rules:
>> + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
>> + if (blkaddr < 0)
>> + return;
>> + for (int i = 0; i < 4; i++) {
>> + if (ptr[i] == USHRT_MAX)
>> + continue;
>>
>> - free_req.hdr.pcifunc = pcifunc;
>> - free_req.all = 1;
>> - rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
>> - if (rc)
>> - dev_err(rvu->dev,
>> - "%s: Error deleting default entries (pcifunc=%#x\n",
>> - __func__, pcifunc);
>> + mutex_lock(&mcam->lock);
>> + npc_mcam_clear_bit(mcam, ptr[i]);
>> + mcam->entry2pfvf_map[ptr[i]] = NPC_MCAM_INVALID_MAP;
>> + npc_cn20k_enable_mcam_entry(rvu, blkaddr, ptr[i], false);
>> + mcam->entry2target_pffunc[ptr[i]] = 0x0;
>> + mutex_unlock(&mcam->lock);
>> +
>> + rc = npc_cn20k_idx_free(rvu, &ptr[i], 1);
>> + if (rc) {
>> + /* Non recoverable error. Let us WARN and return. Keep system alive to
>> + * enable debugging
>> + */
>> + WARN(1, "%s Error deleting default entries (pcifunc=%#x) mcam_idx=%u\n",
>> + __func__, pcifunc, ptr[i]);
>> + return;
>When npc_cn20k_idx_free() fails on some ptr[i], this path WARNs and
>returns from inside the per-entry loop. At that point, the earlier
>block in npc_cn20k_dft_rules_free() has already xa_erase()d the
>xa_pf2dfl_rmap entries for all four default rule IDs for this pcifunc,
>so npc_cn20k_dft_rules_idx_get() on a retry would return -ESRCH and
>could not reclaim anything.
>Given that, could the remaining ptr[i+1..3] entries leak on this path?
>Their bitmap bits stay cleared only if they were processed before the
>failure, but any entries after i still have their bitmap slot allocated,
>entry2pfvf_map still referencing pcifunc, MCAM line still enabled,
>entry2target_pffunc still set, and the cn20k idx allocator still holding
>the slots.
No. This is a non recoverable error and no way we can recover and proceed. So this warning
and returning would enable the user to debug the system.
>> + }
>> + }
>> +
>> + mutex_lock(&mcam->lock);
>> + list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
>> + for (int i = 0; i < 4; i++) {
>> + if (ptr[i] != rule->entry)
>> + continue;
>> +
>> + list_del(&rule->list);
>> + kfree(rule);
>> + break;
>> + }
>> + }
>> + mutex_unlock(&mcam->lock);
>> }
>On the same error path, the list_for_each_entry_safe() walk over
>mcam->mcam_rules below is skipped entirely because of the early return,
>so rvu_npc_mcam_rule nodes for all four default indices (including the
>ones that were successfully torn down before the failure) stay on the
>list.
>The commit message says:
> Resolve the default-rule indices, then for each valid slot clear the
> bitmap entry, drop the PF/VF map, disable the MCAM line, clear the
> target function, and npc_cn20k_idx_free(). Remove any
> matching software mcam_rules nodes. On hard failure from idx_free, WARN
> and stop so the box stays up for analysis.
>Is the "Remove any matching software mcam_rules nodes" step intended to
>also be skipped whenever idx_free() fails? If not, would it make sense
>to move the mcam_rules cleanup ahead of the per-entry loop, or continue
>the loop best-effort and WARN once at the end, so the software list and
>the already-torn-down slots do not silently diverge on the error path?
No. mcam list will show more information in debugfs. I dont think, freeing 4 entries (in default entries)
would save us anything. So better to keep this way.
^ permalink raw reply
* Re: [PATCH v4 net 05/10] octeontx2-af: npc: cn20k: Clear MCAM entries by index and key width
From: Ratheesh Kannoth @ 2026-04-27 10:01 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Suman Ghosh
In-Reply-To: <20260427063213.3937451-6-rkannoth@marvell.com>
On 2026-04-27 at 12:02:08, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> Replace the old four-argument CN20K MCAM clear with a per-bank static
> helper and npc_cn20k_clear_mcam_entry() that takes a logical MCAM index,
> resolves the key width via npc_mcam_idx_2_key_type(), and clears either
> one bank (X2) or every bank (X4).
> Call it from npc_clear_mcam_entry() on cn20k and log when key-type lookup
> fails. Use the per-bank helper from npc_cn20k_config_mcam_entry() for
> pre-program clears.
> For loopback VFs, use the promisc MCAM index as ucast_idx when copying
> RSS action for promisc, matching cn20k default-rule layout.
>
> Cc: Suman Ghosh <sumang@marvell.com>
> Fixes: 6d1e70282f76 ("octeontx2-af: npc: cn20k: Use common APIs")
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
>> @@ -755,9 +762,15 @@ void rvu_npc_install_promisc_entry(struct rvu *rvu, u16 pcifunc,
>>
>> /* If the corresponding PF's ucast action is RSS,
>> * use the same action for promisc also
>> + * Please note that for lbk(s) "index" and "ucast_idx"
>> + * will be same.
>> */
>> - ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
>> - nixlf, NIXLF_UCAST_ENTRY);
>> + if (is_lbk_vf(rvu, pcifunc))
>> + ucast_idx = index;
>> + else
>> + ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
>> + nixlf, NIXLF_UCAST_ENTRY);
>> +
>The commit subject and the Fixes: tag reference a cn20k-only change,
>and the comment added above says the new layout matches cn20k
>default-rules, but is_lbk_vf() is silicon-agnostic:
> static inline bool is_lbk_vf(struct rvu *rvu, u16 pcifunc)
> {
> return (!(pcifunc & ~RVU_PFVF_FUNC_MASK) &&
> (rvu->vf_devid == RVU_LBK_VF_DEVID));
> }
>Is it intentional that this branch fires on cn10k and otx2 LBK VFs as
>well?
>Previously, for any LBK VF, ucast_idx was obtained from
>npc_get_nixlf_mcam_index(..., NIXLF_UCAST_ENTRY), which on non-cn20k
>falls through to npc_get_ucast_mcam_index() and returns the ucast
>slot. After this patch ucast_idx becomes the promisc slot for all
>LBK VFs.
>The subsequent is_mcam_entry_enabled(ucast_idx) and
>npc_get_mcam_action(ucast_idx) now read a different MCAM entry on
>non-cn20k silicon, which can change whether an RSS action is
>inherited for the LBK VF promisc rule.
>Should this hunk be gated by is_cn20k(rvu->pdev), or is the
>behavioural change on cn10k/otx2 LBK VFs intended and worth calling
>out in the commit message?
This is intentional change.
^ permalink raw reply
* Re: [PATCH net 1/3] netconsole: return count instead of strnlen(buf, count) from store callbacks
From: Breno Leitao @ 2026-04-27 10:00 UTC (permalink / raw)
To: Simon Horman
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Keiichi Kii, Satyam Sharma, Andrew Morton,
Matthew Wood, asantostc, gustavold, netdev, linux-kernel,
kernel-team
In-Reply-To: <20260426084640.GN900403@horms.kernel.org>
Hello Simon,
On Sun, Apr 26, 2026 at 09:46:40AM +0100, Simon Horman wrote:
> On Thu, Apr 23, 2026 at 02:41:15AM -0700, Breno Leitao wrote:
> > Several configfs store callbacks in netconsole end with:
> >
> > ret = strnlen(buf, count);
> >
> > This under-reports the number of bytes consumed when the input
> > contains an embedded NUL within count, telling the VFS that fewer
> > bytes were written than userspace actually handed in. A conformant
> > partial-write loop would then retry the trailing bytes against a
> > callback that has already accepted them.
> >
> > Every other configfs driver in the tree returns count directly from
> > its store callbacks once parsing has succeeded, including
> > drivers/nvme/target/configfs.c, drivers/gpio/gpio-sim.c,
> > drivers/most/configfs.c, drivers/block/null_blk/main.c,
> > drivers/pci/endpoint/pci-ep-cfs.c, and the rest of the configfs
> > users. netconsole was the outlier (along with
> > drivers/infiniband/core/cma_configfs.c, which has the same latent
> > issue).
> >
> > Align netconsole with the rest of the configfs ecosystem: return
> > count once the parser/validator has accepted the input. The numeric
> > and boolean parsers (kstrtobool, kstrtou16, mac_pton,
> > netpoll_parse_ip_addr) have already validated the meaningful prefix;
> > any trailing bytes are padding and should simply be reported as
> > consumed.
> >
> > Fixes: 0bcc1816188e ("[NET] netconsole: Support dynamic reconfiguration using configfs")
> > Signed-off-by: Breno Leitao <leitao@debian.org>
>
> Reviewed-by: Simon Horman <horms@kernel.org>
>
> FTR: Sashiko has provided an AI generated review of this patch.
> Like it's review of patch 3/3 - which I forwarded separately -
> it flags that trim_newline() may perform an OOB access
> if passed an empty string. But this is not correct because
> trim_newline() correctly handles this case.
You're absolutely right. This has been addressed in the patch that recently
landed in Linus' tree.
It appears Sashiko ran its analysis on a tree predating that fix.
https://github.com/torvalds/linux/commit/7079c8c13f2d33992bc846240517d88f4ab07781
Thanks for the review,
--breno
^ permalink raw reply
* [PATCH v4 15/15] MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service
From: Sumit Garg @ 2026-04-27 9:56 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Add Sumit Garg as the maintainer for the Qualcomm generic Peripheral
Authentication Service (PAS) as well as the PAS TEE backend driver.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..6d3fc5145f0a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22007,6 +22007,15 @@ F: Documentation/devicetree/bindings/media/*qcom*
F: drivers/media/platform/qcom
F: include/dt-bindings/media/*qcom*
+QUALCOMM PAS TZ SERVICE
+M: Sumit Garg <sumit.garg@oss.qualcomm.com>
+L: linux-arm-msm@vger.kernel.org
+S: Maintained
+F: drivers/firmware/qcom/qcom_pas.c
+F: drivers/firmware/qcom/qcom_pas.h
+F: drivers/firmware/qcom/qcom_pas_tee.c
+F: include/linux/firmware/qcom/qcom_pas.h
+
QUALCOMM SMB CHARGER DRIVER
M: Casey Connolly <casey.connolly@linaro.org>
L: linux-arm-msm@vger.kernel.org
--
2.51.0
^ permalink raw reply related
* [PATCH v4 14/15] firmware: qcom_scm: Remove SCM PAS wrappers
From: Sumit Garg @ 2026-04-27 9:56 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Now since all the Qcom SCM client drivers have been migrated over to
generic PAS TZ service, let's drop the exported SCM PAS wrappers.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/firmware/qcom/qcom_scm.c | 143 +++++--------------------
include/linux/firmware/qcom/qcom_scm.h | 29 -----
2 files changed, 29 insertions(+), 143 deletions(-)
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index d87a962e93da..2493b200696b 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -553,26 +553,6 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
}
-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_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 (struct qcom_scm_pas_context *)ctx;
-}
-EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
-
static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id,
dma_addr_t mdata_phys,
struct qcom_scm_res *res)
@@ -630,9 +610,9 @@ static int qcom_scm_pas_prep_and_init_image(struct device *dev,
return ret ? : res.result[0];
}
-static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id,
- const void *metadata, size_t size,
- struct qcom_pas_context *ctx)
+static int qcom_scm_pas_init_image(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;
@@ -672,16 +652,8 @@ static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id,
return ret ? : res.result[0];
}
-int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
- struct qcom_scm_pas_context *ctx)
-{
- 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)
+static void qcom_scm_pas_metadata_release(struct device *dev,
+ struct qcom_pas_context *ctx)
{
if (ctx->use_tzmem)
qcom_tzmem_free(ctx->ptr);
@@ -691,15 +663,8 @@ static void __qcom_scm_pas_metadata_release(struct device *dev,
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);
-
-static int __qcom_scm_pas_mem_setup(struct device *dev, 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 = {
@@ -730,12 +695,6 @@ static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id,
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(struct device *dev, u32 pas_id,
void *input_rt_tzm,
size_t input_rt_size,
@@ -789,11 +748,10 @@ static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id,
return ret ? ERR_PTR(ret) : output_rt_tzm;
}
-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)
+static void *qcom_scm_pas_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 resource_table empty_rsc = {};
size_t size = SZ_16K;
@@ -864,19 +822,7 @@ static void *__qcom_scm_pas_get_rsc_table2(struct device *dev,
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);
-
-static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id)
+static int qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -905,14 +851,8 @@ static int __qcom_scm_pas_auth_and_reset(struct device *dev, 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);
-
-static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
- struct qcom_pas_context *ctx)
+static int qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
+ struct qcom_pas_context *ctx)
{
u64 handle;
int ret;
@@ -923,7 +863,7 @@ static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
* memory region and then invokes a call to TrustZone to authenticate.
*/
if (!ctx->use_tzmem)
- return __qcom_scm_pas_auth_and_reset(dev, 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
@@ -933,21 +873,14 @@ static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
if (ret)
return ret;
- ret = __qcom_scm_pas_auth_and_reset(dev, 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);
-
-static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state,
- 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,
@@ -965,13 +898,7 @@ static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state,
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)
+static int qcom_scm_pas_shutdown(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -1000,13 +927,7 @@ static int __qcom_scm_pas_shutdown(struct device *dev, 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);
-
-static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id)
+static bool qcom_scm_pas_supported(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -1027,23 +948,17 @@ static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id)
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,
+ .supported = qcom_scm_pas_supported,
+ .init_image = qcom_scm_pas_init_image,
+ .mem_setup = qcom_scm_pas_mem_setup,
+ .get_rsc_table = qcom_scm_pas_get_rsc_table,
+ .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,
};
/**
diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h
index 5747bd191bf1..a0a6bc0229c4 100644
--- a/include/linux/firmware/qcom/qcom_scm.h
+++ b/include/linux/firmware/qcom/qcom_scm.h
@@ -64,35 +64,6 @@ bool qcom_scm_is_available(void);
int qcom_scm_set_cold_boot_addr(void *entry);
int qcom_scm_set_warm_boot_addr(void *entry);
void qcom_scm_cpu_power_down(u32 flags);
-int qcom_scm_set_remote_state(u32 state, u32 id);
-
-struct qcom_scm_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;
-};
-
-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);
-int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
- struct qcom_scm_pas_context *ctx);
-void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx);
-int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size);
-int qcom_scm_pas_auth_and_reset(u32 pas_id);
-int qcom_scm_pas_shutdown(u32 pas_id);
-bool qcom_scm_pas_supported(u32 pas_id);
-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);
-
-int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx);
int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
--
2.51.0
^ permalink raw reply related
* [PATCH v4 13/15] wifi: ath12k: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:56 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Switch ath12k 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.
Acked-by: Jeff Johnson <jjohnson@kernel.org>
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/Kconfig | 2 +-
drivers/net/wireless/ath/ath12k/ahb.c | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig
index d39c075758bd..2b8b87931330 100644
--- a/drivers/net/wireless/ath/ath12k/Kconfig
+++ b/drivers/net/wireless/ath/ath12k/Kconfig
@@ -18,7 +18,7 @@ config ATH12K_AHB
bool "QTI ath12k AHB support"
depends on ATH12K && REMOTEPROC
select QCOM_MDT_LOADER
- select QCOM_SCM
+ select QCOM_PAS
help
Enable support for Ath12k AHB bus chipsets, example IPQ5332.
diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c
index 2dcf0a52e4c1..c5ba91e6f95e 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/ahb.c
@@ -5,7 +5,7 @@
*/
#include <linux/dma-mapping.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -420,7 +420,7 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab)
if (ab_ahb->scm_auth_enabled) {
/* Authenticate FW image using peripheral ID */
- ret = qcom_scm_pas_auth_and_reset(pasid);
+ ret = qcom_pas_auth_and_reset(pasid);
if (ret) {
ath12k_err(ab, "failed to boot the remote processor %d\n", ret);
goto err_fw2;
@@ -485,9 +485,9 @@ static void ath12k_ahb_power_down(struct ath12k_base *ab, bool is_suspend)
pasid = (u32_encode_bits(ab_ahb->userpd_id, ATH12K_USERPD_ID_MASK)) |
ATH12K_AHB_UPD_SWID;
/* Release the firmware */
- ret = qcom_scm_pas_shutdown(pasid);
+ ret = qcom_pas_shutdown(pasid);
if (ret)
- ath12k_err(ab, "scm pas shutdown failed for userPD%d\n",
+ ath12k_err(ab, "pas shutdown failed for userPD%d: %d\n",
ab_ahb->userpd_id);
}
}
--
2.51.0
^ permalink raw reply related
* [PATCH v4 12/15] net: ipa: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:56 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Switch ipa client driver over to generic PAS TZ APIs. Generic PAS TZ
service allows to support multiple TZ implementation backends like QTEE
based SCM PAS service, OP-TEE based PAS service and any further future TZ
backend service.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/net/ipa/Kconfig | 2 +-
drivers/net/ipa/ipa_main.c | 13 ++++++++-----
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ipa/Kconfig b/drivers/net/ipa/Kconfig
index 01d219d3760c..a9aff1b7977d 100644
--- a/drivers/net/ipa/Kconfig
+++ b/drivers/net/ipa/Kconfig
@@ -6,7 +6,7 @@ config QCOM_IPA
depends on QCOM_RPROC_COMMON || (QCOM_RPROC_COMMON=n && COMPILE_TEST)
depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
select QCOM_MDT_LOADER
- select QCOM_SCM
+ select QCOM_PAS
select QCOM_QMI_HELPERS
help
Choose Y or M here to include support for the Qualcomm
diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c
index 788dd99af2a4..3cd9e44680e9 100644
--- a/drivers/net/ipa/ipa_main.c
+++ b/drivers/net/ipa/ipa_main.c
@@ -14,7 +14,7 @@
#include <linux/pm_runtime.h>
#include <linux/types.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/soc/qcom/mdt_loader.h>
#include "ipa.h"
@@ -624,10 +624,13 @@ static int ipa_firmware_load(struct device *dev)
}
ret = qcom_mdt_load(dev, fw, path, IPA_PAS_ID, virt, phys, size, NULL);
- if (ret)
+ if (ret) {
dev_err(dev, "error %d loading \"%s\"\n", ret, path);
- else if ((ret = qcom_scm_pas_auth_and_reset(IPA_PAS_ID)))
- dev_err(dev, "error %d authenticating \"%s\"\n", ret, path);
+ } else {
+ ret = qcom_pas_auth_and_reset(IPA_PAS_ID);
+ if (ret)
+ dev_err(dev, "error %d authenticating \"%s\"\n", ret, path);
+ }
memunmap(virt);
out_release_firmware:
@@ -758,7 +761,7 @@ static enum ipa_firmware_loader ipa_firmware_loader(struct device *dev)
return IPA_LOADER_INVALID;
out_self:
/* We need Trust Zone to load firmware; make sure it's available */
- if (qcom_scm_is_available())
+ if (qcom_pas_is_available())
return IPA_LOADER_SELF;
return IPA_LOADER_DEFER;
--
2.51.0
^ permalink raw reply related
* [PATCH v4 11/15] media: qcom: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Switch qcom media client drivers over to generic PAS TZ APIs. Generic PAS
TZ service allows to support multiple TZ implementation backends like QTEE
based SCM PAS service, OP-TEE based PAS service and any further future TZ
backend service.
Along with that pass proper PAS ID to set_remote_state API. As per testing
the SCM backend just ignores it while OP-TEE makes use of it to for proper
book keeping purpose.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/media/platform/qcom/iris/Kconfig | 25 ++++++++++---------
.../media/platform/qcom/iris/iris_firmware.c | 9 ++++---
drivers/media/platform/qcom/venus/Kconfig | 1 +
drivers/media/platform/qcom/venus/firmware.c | 11 ++++----
4 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig
index 3c803a05305a..f54b759c18aa 100644
--- a/drivers/media/platform/qcom/iris/Kconfig
+++ b/drivers/media/platform/qcom/iris/Kconfig
@@ -1,13 +1,14 @@
config VIDEO_QCOM_IRIS
- tristate "Qualcomm iris V4L2 decoder driver"
- depends on VIDEO_DEV
- depends on ARCH_QCOM || COMPILE_TEST
- select V4L2_MEM2MEM_DEV
- select QCOM_MDT_LOADER if ARCH_QCOM
- select QCOM_SCM
- select VIDEOBUF2_DMA_CONTIG
- help
- This is a V4L2 driver for Qualcomm iris video accelerator
- hardware. It accelerates decoding operations on various
- Qualcomm SoCs.
- To compile this driver as a module choose m here.
+ tristate "Qualcomm iris V4L2 decoder driver"
+ depends on VIDEO_DEV
+ depends on ARCH_QCOM || COMPILE_TEST
+ select V4L2_MEM2MEM_DEV
+ select QCOM_MDT_LOADER if ARCH_QCOM
+ select QCOM_SCM
+ select QCOM_PAS
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ This is a V4L2 driver for Qualcomm iris video accelerator
+ hardware. It accelerates decoding operations on various
+ Qualcomm SoCs.
+ To compile this driver as a module choose m here.
diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c
index 5f408024e967..856fa6a79064 100644
--- a/drivers/media/platform/qcom/iris/iris_firmware.c
+++ b/drivers/media/platform/qcom/iris/iris_firmware.c
@@ -4,6 +4,7 @@
*/
#include <linux/firmware.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
@@ -79,7 +80,7 @@ int iris_fw_load(struct iris_core *core)
return -ENOMEM;
}
- ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id);
+ ret = qcom_pas_auth_and_reset(core->iris_platform_data->pas_id);
if (ret) {
dev_err(core->dev, "auth and reset failed: %d\n", ret);
return ret;
@@ -93,7 +94,7 @@ int iris_fw_load(struct iris_core *core)
cp_config->cp_nonpixel_size);
if (ret) {
dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret);
- qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
+ qcom_pas_shutdown(core->iris_platform_data->pas_id);
return ret;
}
}
@@ -103,10 +104,10 @@ int iris_fw_load(struct iris_core *core)
int iris_fw_unload(struct iris_core *core)
{
- return qcom_scm_pas_shutdown(core->iris_platform_data->pas_id);
+ return qcom_pas_shutdown(core->iris_platform_data->pas_id);
}
int iris_set_hw_state(struct iris_core *core, bool resume)
{
- return qcom_scm_set_remote_state(resume, 0);
+ return qcom_pas_set_remote_state(resume, core->iris_platform_data->pas_id);
}
diff --git a/drivers/media/platform/qcom/venus/Kconfig b/drivers/media/platform/qcom/venus/Kconfig
index ffb731ecd48c..574172724e8f 100644
--- a/drivers/media/platform/qcom/venus/Kconfig
+++ b/drivers/media/platform/qcom/venus/Kconfig
@@ -6,6 +6,7 @@ config VIDEO_QCOM_VENUS
select OF_DYNAMIC if ARCH_QCOM
select QCOM_MDT_LOADER if ARCH_QCOM
select QCOM_SCM
+ select QCOM_PAS
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
help
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 1de7436713ed..3c0727ea137d 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -12,6 +12,7 @@
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -58,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume)
int ret;
if (core->use_tz) {
- ret = qcom_scm_set_remote_state(resume, 0);
+ ret = qcom_pas_set_remote_state(resume, VENUS_PAS_ID);
if (resume && ret == -EINVAL)
ret = 0;
return ret;
@@ -218,7 +219,7 @@ int venus_boot(struct venus_core *core)
int ret;
if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ||
- (core->use_tz && !qcom_scm_is_available()))
+ (core->use_tz && !qcom_pas_is_available()))
return -EPROBE_DEFER;
ret = of_property_read_string_index(dev->of_node, "firmware-name", 0,
@@ -236,7 +237,7 @@ int venus_boot(struct venus_core *core)
core->fw.mem_phys = mem_phys;
if (core->use_tz)
- ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID);
+ ret = qcom_pas_auth_and_reset(VENUS_PAS_ID);
else
ret = venus_boot_no_tz(core, mem_phys, mem_size);
@@ -259,7 +260,7 @@ int venus_boot(struct venus_core *core)
res->cp_nonpixel_start,
res->cp_nonpixel_size);
if (ret) {
- qcom_scm_pas_shutdown(VENUS_PAS_ID);
+ qcom_pas_shutdown(VENUS_PAS_ID);
dev_err(dev, "set virtual address ranges fail (%d)\n",
ret);
return ret;
@@ -274,7 +275,7 @@ int venus_shutdown(struct venus_core *core)
int ret;
if (core->use_tz)
- ret = qcom_scm_pas_shutdown(VENUS_PAS_ID);
+ ret = qcom_pas_shutdown(VENUS_PAS_ID);
else
ret = venus_shutdown_no_tz(core);
--
2.51.0
^ permalink raw reply related
* [PATCH v4 10/15] drm/msm: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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>
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 79acae11154a..b556da823897 100644
--- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c
@@ -5,7 +5,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/cpumask.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/pm_opp.h>
#include <linux/nvmem-consumer.h>
#include <linux/slab.h>
@@ -653,7 +653,7 @@ static int a5xx_zap_shader_resume(struct msm_gpu *gpu)
if (adreno_is_a506(adreno_gpu))
return 0;
- ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID);
+ ret = qcom_pas_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID);
if (ret)
DRM_ERROR("%s: zap-shader resume failed: %d\n",
gpu->name, ret);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
index 66f80f2d12f9..6d68edf0578c 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -8,6 +8,7 @@
#include <linux/ascii85.h>
#include <linux/interconnect.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/kernel.h>
#include <linux/of_reserved_mem.h>
@@ -146,10 +147,10 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname,
goto out;
/* Send the image to the secure world */
- ret = qcom_scm_pas_auth_and_reset(pasid);
+ ret = qcom_pas_auth_and_reset(pasid);
/*
- * If the scm call returns -EOPNOTSUPP we assume that this target
+ * If the pas call returns -EOPNOTSUPP we assume that this target
* doesn't need/support the zap shader so quietly fail
*/
if (ret == -EOPNOTSUPP)
@@ -175,9 +176,9 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid)
if (!zap_available)
return -ENODEV;
- /* We need SCM to be able to load the firmware */
- if (!qcom_scm_is_available()) {
- DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n");
+ /* We need PAS to be able to load the firmware */
+ if (!qcom_pas_is_available()) {
+ DRM_DEV_ERROR(&pdev->dev, "Qcom PAS is not available\n");
return -EPROBE_DEFER;
}
--
2.51.0
^ permalink raw reply related
* [PATCH v4 09/15] remoteproc: qcom: Select QCOM_PAS generic service
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/remoteproc/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index ee54436fea5a..da3c5d9562ea 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -230,6 +230,7 @@ config QCOM_Q6V5_PAS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
+ select QCOM_PAS
help
Say y here to support the TrustZone based Peripheral Image Loader for
the Qualcomm remote processors. This is commonly used to control
--
2.51.0
^ permalink raw reply related
* [PATCH v4 08/15] remoteproc: qcom_wcnss: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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.
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.51.0
^ permalink raw reply related
* [PATCH v4 07/15] soc: qcom: mdtloader: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Sumit Garg <sumit.garg@oss.qualcomm.com>
Switch mdtloader client driver over to generic PAS TZ APIs. Generic PAS
TZ service allows to support multiple TZ implementation backends like QTEE
based SCM PAS service, OP-TEE based PAS service and any further future TZ
backend service.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/soc/qcom/mdt_loader.c | 12 ++++++------
include/linux/soc/qcom/mdt_loader.h | 6 +++---
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index c004d444d698..fdde7eda538a 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -13,7 +13,7 @@
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/firmware/qcom/qcom_scm.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/mdt_loader.h>
@@ -229,7 +229,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, phys_addr_t mem_phys,
- struct qcom_scm_pas_context *ctx)
+ struct qcom_pas_context *ctx)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
@@ -271,7 +271,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
goto out;
}
- ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx);
+ ret = qcom_pas_init_image(pas_id, metadata, metadata_len, ctx);
kfree(metadata);
if (ret) {
/* Invalid firmware metadata */
@@ -280,7 +280,7 @@ static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
}
if (relocate) {
- ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
+ ret = qcom_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
if (ret) {
/* Unable to set up relocation */
dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
@@ -472,7 +472,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
* firmware segments (e.g., .bXX files). Authentication of the segments done
* by a separate call.
*
- * The PAS context must be initialized using qcom_scm_pas_context_init()
+ * The PAS context must be initialized using qcom_pas_context_init()
* prior to invoking this function.
*
* @ctx: Pointer to the PAS (Peripheral Authentication Service) context
@@ -483,7 +483,7 @@ EXPORT_SYMBOL_GPL(qcom_mdt_load);
*
* Return: 0 on success or a negative error code on failure.
*/
-int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
+int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
const char *firmware, void *mem_region, phys_addr_t *reloc_base)
{
int ret;
diff --git a/include/linux/soc/qcom/mdt_loader.h b/include/linux/soc/qcom/mdt_loader.h
index 82372e0db0a1..142409555425 100644
--- a/include/linux/soc/qcom/mdt_loader.h
+++ b/include/linux/soc/qcom/mdt_loader.h
@@ -10,7 +10,7 @@
struct device;
struct firmware;
-struct qcom_scm_pas_context;
+struct qcom_pas_context;
#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
@@ -20,7 +20,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base);
-int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw,
+int qcom_mdt_pas_load(struct qcom_pas_context *ctx, const struct firmware *fw,
const char *firmware, void *mem_region, phys_addr_t *reloc_base);
int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
@@ -45,7 +45,7 @@ static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw,
return -ENODEV;
}
-static inline int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx,
+static inline int qcom_mdt_pas_load(struct qcom_pas_context *ctx,
const struct firmware *fw, const char *firmware,
void *mem_region, phys_addr_t *reloc_base)
{
--
2.51.0
^ permalink raw reply related
* [PATCH v4 06/15] remoteproc: qcom_q6v5_mss: Switch to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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.
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.51.0
^ permalink raw reply related
* [PATCH v4 05/15] remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/remoteproc/qcom_q6v5_pas.c | 51 +++++++++++++++---------------
1 file changed, 26 insertions(+), 25 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index da27d1d3c9da..847249c28c1b 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc.h>
@@ -118,8 +119,8 @@ struct qcom_pas {
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
- struct qcom_scm_pas_context *pas_ctx;
- struct qcom_scm_pas_context *dtb_pas_ctx;
+ struct qcom_pas_context *pas_ctx;
+ struct qcom_pas_context *dtb_pas_ctx;
};
static void qcom_pas_segment_dump(struct rproc *rproc,
@@ -196,7 +197,7 @@ static int qcom_pas_shutdown_poll_decrypt(struct qcom_pas *pas)
do {
msleep(QCOM_PAS_DECRYPT_SHUTDOWN_DELAY_MS);
- ret = qcom_scm_pas_shutdown(pas->pas_id);
+ ret = qcom_pas_shutdown(pas->pas_id);
} while (ret == -EINVAL && --retry_num);
return ret;
@@ -212,9 +213,9 @@ static int qcom_pas_unprepare(struct rproc *rproc)
* auth_and_reset() was successful, but in other cases clean it up
* here.
*/
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
return 0;
}
@@ -228,9 +229,9 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
pas->firmware = fw;
if (pas->lite_pas_id)
- qcom_scm_pas_shutdown(pas->lite_pas_id);
+ qcom_pas_shutdown(pas->lite_pas_id);
if (pas->lite_dtb_pas_id)
- qcom_scm_pas_shutdown(pas->lite_dtb_pas_id);
+ qcom_pas_shutdown(pas->lite_dtb_pas_id);
if (pas->dtb_pas_id) {
ret = request_firmware(&pas->dtb_firmware, pas->dtb_firmware_name, pas->dev);
@@ -250,7 +251,7 @@ static int qcom_pas_load(struct rproc *rproc, const struct firmware *fw)
return 0;
release_dtb_metadata:
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
release_firmware(pas->dtb_firmware);
return ret;
@@ -310,7 +311,7 @@ static int qcom_pas_start(struct rproc *rproc)
if (ret)
goto disable_px_supply;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
+ ret = qcom_pas_prepare_and_auth_reset(pas->dtb_pas_ctx);
if (ret) {
dev_err(pas->dev,
"failed to authenticate dtb image and release reset\n");
@@ -329,7 +330,7 @@ static int qcom_pas_start(struct rproc *rproc)
if (ret)
goto release_pas_metadata;
- ret = qcom_scm_pas_prepare_and_auth_reset(pas->pas_ctx);
+ ret = qcom_pas_prepare_and_auth_reset(pas->pas_ctx);
if (ret) {
dev_err(pas->dev,
"failed to authenticate image and release reset\n");
@@ -339,13 +340,13 @@ static int qcom_pas_start(struct rproc *rproc)
ret = qcom_q6v5_wait_for_start(&pas->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) {
dev_err(pas->dev, "start timed out\n");
- qcom_scm_pas_shutdown(pas->pas_id);
+ qcom_pas_shutdown(pas->pas_id);
goto unmap_carveout;
}
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
/* firmware is used to pass reference from qcom_pas_start(), drop it now */
pas->firmware = NULL;
@@ -355,9 +356,9 @@ static int qcom_pas_start(struct rproc *rproc)
unmap_carveout:
qcom_pas_unmap_carveout(rproc, pas->mem_phys, pas->mem_size);
release_pas_metadata:
- qcom_scm_pas_metadata_release(pas->pas_ctx);
+ qcom_pas_metadata_release(pas->pas_ctx);
if (pas->dtb_pas_id)
- qcom_scm_pas_metadata_release(pas->dtb_pas_ctx);
+ qcom_pas_metadata_release(pas->dtb_pas_ctx);
unmap_dtb_carveout:
if (pas->dtb_pas_id)
@@ -406,7 +407,7 @@ static int qcom_pas_stop(struct rproc *rproc)
if (ret == -ETIMEDOUT)
dev_err(pas->dev, "timed out on wait\n");
- ret = qcom_scm_pas_shutdown(pas->pas_id);
+ ret = qcom_pas_shutdown(pas->pas_id);
if (ret && pas->decrypt_shutdown)
ret = qcom_pas_shutdown_poll_decrypt(pas);
@@ -414,7 +415,7 @@ static int qcom_pas_stop(struct rproc *rproc)
dev_err(pas->dev, "failed to shutdown: %d\n", ret);
if (pas->dtb_pas_id) {
- ret = qcom_scm_pas_shutdown(pas->dtb_pas_id);
+ ret = qcom_pas_shutdown(pas->dtb_pas_id);
if (ret)
dev_err(pas->dev, "failed to shutdown dtb: %d\n", ret);
@@ -484,11 +485,11 @@ static int qcom_pas_parse_firmware(struct rproc *rproc, const struct firmware *f
*
* Here, we call rproc_elf_load_rsc_table() to check firmware binary has resources
* or not and if it is not having then we pass NULL and zero as input resource
- * table pointer and size respectively to the argument of qcom_scm_pas_get_rsc_table()
+ * table pointer and size respectively to the argument of qcom_pas_get_rsc_table()
* and this is even true for Qualcomm remote processor who does follow remoteproc
* framework.
*/
- output_rt = qcom_scm_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
+ output_rt = qcom_pas_get_rsc_table(pas->pas_ctx, table, table_sz, &output_rt_size);
ret = IS_ERR(output_rt) ? PTR_ERR(output_rt) : 0;
if (ret) {
dev_err(pas->dev, "Error in getting resource table: %d\n", ret);
@@ -746,7 +747,7 @@ static int qcom_pas_probe(struct platform_device *pdev)
if (!desc)
return -EINVAL;
- if (!qcom_scm_is_available())
+ if (!qcom_pas_is_available())
return -EPROBE_DEFER;
fw_name = desc->firmware_name;
@@ -838,16 +839,16 @@ static int qcom_pas_probe(struct platform_device *pdev)
qcom_add_ssr_subdev(rproc, &pas->ssr_subdev, desc->ssr_name);
- pas->pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->pas_id,
- pas->mem_phys, pas->mem_size);
+ pas->pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->pas_id,
+ pas->mem_phys, pas->mem_size);
if (IS_ERR(pas->pas_ctx)) {
ret = PTR_ERR(pas->pas_ctx);
goto remove_ssr_sysmon;
}
- pas->dtb_pas_ctx = devm_qcom_scm_pas_context_alloc(pas->dev, pas->dtb_pas_id,
- pas->dtb_mem_phys,
- pas->dtb_mem_size);
+ pas->dtb_pas_ctx = devm_qcom_pas_context_alloc(pas->dev, pas->dtb_pas_id,
+ pas->dtb_mem_phys,
+ pas->dtb_mem_size);
if (IS_ERR(pas->dtb_pas_ctx)) {
ret = PTR_ERR(pas->dtb_pas_ctx);
goto remove_ssr_sysmon;
--
2.51.0
^ permalink raw reply related
* [PATCH v4 04/15] firmware: qcom: Add a PAS TEE service
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/firmware/qcom/Kconfig | 10 +
drivers/firmware/qcom/Makefile | 1 +
drivers/firmware/qcom/qcom_pas_tee.c | 479 +++++++++++++++++++++++++++
3 files changed, 490 insertions(+)
create mode 100644 drivers/firmware/qcom/qcom_pas_tee.c
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index 9a12ae2b639d..300b3a1bd178 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -14,6 +14,16 @@ config QCOM_PAS
backends plugged in whether it's an SCM implementation or a proper
TEE bus based PAS service implementation.
+config QCOM_PAS_TEE
+ tristate
+ select QCOM_PAS
+ depends on TEE
+ depends on !CPU_BIG_ENDIAN
+ default m if ARCH_QCOM
+ help
+ Enable the generic Peripheral Authentication Service (PAS) provided
+ by the firmware TEE implementation as the backend.
+
config QCOM_SCM
select QCOM_PAS
select QCOM_TZMEM
diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
index dc5ab45f906a..48801d18f37b 100644
--- a/drivers/firmware/qcom/Makefile
+++ b/drivers/firmware/qcom/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
obj-$(CONFIG_QCOM_PAS) += qcom_pas.o
+obj-$(CONFIG_QCOM_PAS_TEE) += qcom_pas_tee.o
diff --git a/drivers/firmware/qcom/qcom_pas_tee.c b/drivers/firmware/qcom/qcom_pas_tee.c
new file mode 100644
index 000000000000..af73d0a68525
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas_tee.c
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/firmware/qcom/qcom_pas.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+#include <linux/uuid.h>
+
+#include "qcom_pas.h"
+
+/*
+ * Peripheral Authentication Service (PAS) supported.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ */
+#define TA_QCOM_PAS_IS_SUPPORTED 1
+
+/*
+ * PAS capabilities.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [out] params[1].value.a: PAS capability flags
+ */
+#define TA_QCOM_PAS_CAPABILITIES 2
+
+/*
+ * PAS image initialization.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[1].memref: Loadable firmware metadata
+ */
+#define TA_QCOM_PAS_INIT_IMAGE 3
+
+/*
+ * PAS memory setup.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[0].value.b: Relocatable firmware size
+ * [in] params[1].value.a: 32bit LSB relocatable firmware memory address
+ * [in] params[1].value.b: 32bit MSB relocatable firmware memory address
+ */
+#define TA_QCOM_PAS_MEM_SETUP 4
+
+/*
+ * PAS get resource table.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [inout] params[1].memref: Resource table config
+ */
+#define TA_QCOM_PAS_GET_RESOURCE_TABLE 5
+
+/*
+ * PAS image authentication and co-processor reset.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[0].value.b: Firmware size
+ * [in] params[1].value.a: 32bit LSB firmware memory address
+ * [in] params[1].value.b: 32bit MSB firmware memory address
+ * [in] params[2].memref: Optional fw memory space shared/lent
+ */
+#define TA_QCOM_PAS_AUTH_AND_RESET 6
+
+/*
+ * PAS co-processor set suspend/resume state.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ * [in] params[0].value.b: Co-processor state identifier
+ */
+#define TA_QCOM_PAS_SET_REMOTE_STATE 7
+
+/*
+ * PAS co-processor shutdown.
+ *
+ * [in] params[0].value.a: Unique 32bit remote processor identifier
+ */
+#define TA_QCOM_PAS_SHUTDOWN 8
+
+#define TEE_NUM_PARAMS 4
+
+/**
+ * struct qcom_pas_tee_private - PAS service private data
+ * @dev: PAS service device.
+ * @ctx: TEE context handler.
+ * @session_id: PAS TA session identifier.
+ */
+struct qcom_pas_tee_private {
+ struct device *dev;
+ struct tee_context *ctx;
+ u32 session_id;
+};
+
+static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_IS_SUPPORTED,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS not supported, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return false;
+ }
+
+ return true;
+}
+
+static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id,
+ const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_INIT_IMAGE,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+ }
+ };
+ struct tee_shm *mdata_shm;
+ u8 *mdata_buf = NULL;
+ int ret;
+
+ mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size);
+ if (IS_ERR(mdata_shm)) {
+ dev_err(dev, "mdata_shm allocation failed\n");
+ return PTR_ERR(mdata_shm);
+ }
+
+ mdata_buf = tee_shm_get_va(mdata_shm, 0);
+ if (IS_ERR(mdata_buf)) {
+ dev_err(dev, "mdata_buf get VA failed\n");
+ tee_shm_free(mdata_shm);
+ return PTR_ERR(mdata_buf);
+ }
+ memcpy(mdata_buf, metadata, size);
+
+ param[1].u.memref.shm = mdata_shm;
+ param[1].u.memref.size = size;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS init image failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ tee_shm_free(mdata_shm);
+ return ret ?: -EINVAL;
+ }
+
+ if (ctx)
+ ctx->ptr = (void *)mdata_shm;
+ else
+ tee_shm_free(mdata_shm);
+
+ return ret;
+}
+
+static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id,
+ phys_addr_t addr, phys_addr_t size)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_MEM_SETUP,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id,
+ .u.value.b = size,
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = lower_32_bits(addr),
+ .u.value.b = upper_32_bits(addr),
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T))
+
+static void *qcom_pas_tee_get_rsc_table(struct device *dev,
+ struct qcom_pas_context *ctx,
+ void *input_rt, size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_GET_RESOURCE_TABLE,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = ctx->pas_id,
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
+ .u.memref.size = input_rt_size,
+ }
+ };
+ void *rt_buf = NULL;
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ ctx->pas_id, ret, inv_arg.ret);
+ return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
+ }
+
+ if (param[1].u.memref.size) {
+ struct tee_shm *rt_shm __free(shm_free) =
+ tee_shm_alloc_kernel_buf(data->ctx,
+ param[1].u.memref.size);
+ void *rt_shm_va;
+
+ if (IS_ERR(rt_shm)) {
+ dev_err(dev, "rt_shm allocation failed\n");
+ return rt_shm;
+ }
+
+ rt_shm_va = tee_shm_get_va(rt_shm, 0);
+ if (IS_ERR(rt_shm_va)) {
+ dev_err(dev, "rt_shm get VA failed\n");
+ return ERR_CAST(rt_shm_va);
+ }
+ memcpy(rt_shm_va, input_rt, input_rt_size);
+
+ param[1].u.memref.shm = rt_shm;
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ ctx->pas_id, ret, inv_arg.ret);
+ return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
+ }
+
+ if (param[1].u.memref.size) {
+ *output_rt_size = param[1].u.memref.size;
+ rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL);
+ if (!rt_buf)
+ return ERR_PTR(-ENOMEM);
+ }
+ }
+
+ return rt_buf;
+}
+
+static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id,
+ phys_addr_t mem_phys, size_t mem_size)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_AUTH_AND_RESET,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id,
+ .u.value.b = mem_size,
+ },
+ [1] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = lower_32_bits(mem_phys),
+ .u.value.b = upper_32_bits(mem_phys),
+ },
+ /* Reserved for fw memory space to be shared or lent */
+ [2] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS auth reset failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id)
+{
+ return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0);
+}
+
+static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev,
+ struct qcom_pas_context *ctx)
+{
+ return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys,
+ ctx->mem_size);
+}
+
+static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state,
+ u32 pas_id)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_SET_REMOTE_STATE,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id,
+ .u.value.b = state,
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id)
+{
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+ struct tee_ioctl_invoke_arg inv_arg = {
+ .func = TA_QCOM_PAS_SHUTDOWN,
+ .session = data->session_id,
+ .num_params = TEE_NUM_PARAMS
+ };
+ struct tee_param param[4] = {
+ [0] = {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = pas_id
+ }
+ };
+ int ret;
+
+ ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
+ if (ret < 0 || inv_arg.ret != 0) {
+ dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n",
+ pas_id, ret, inv_arg.ret);
+ return ret ?: -EINVAL;
+ }
+
+ return ret;
+}
+
+static void qcom_pas_tee_metadata_release(struct device *dev,
+ struct qcom_pas_context *ctx)
+{
+ struct tee_shm *mdata_shm = ctx->ptr;
+
+ tee_shm_free(mdata_shm);
+}
+
+static struct qcom_pas_ops qcom_pas_ops_tee = {
+ .drv_name = "qcom-pas-tee",
+ .supported = qcom_pas_tee_supported,
+ .init_image = qcom_pas_tee_init_image,
+ .mem_setup = qcom_pas_tee_mem_setup,
+ .get_rsc_table = qcom_pas_tee_get_rsc_table,
+ .auth_and_reset = qcom_pas_tee_auth_and_reset,
+ .prepare_and_auth_reset = qcom_pas_tee_prepare_and_auth_reset,
+ .set_remote_state = qcom_pas_tee_set_remote_state,
+ .shutdown = qcom_pas_tee_shutdown,
+ .metadata_release = qcom_pas_tee_metadata_release,
+};
+
+static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
+{
+ return ver->impl_id == TEE_IMPL_ID_OPTEE;
+}
+
+static int qcom_pas_tee_probe(struct tee_client_device *pas_dev)
+{
+ struct device *dev = &pas_dev->dev;
+ struct qcom_pas_tee_private *data;
+ struct tee_ioctl_open_session_arg sess_arg = {
+ .clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL
+ };
+ int ret, err = -ENODEV;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL);
+ if (IS_ERR(data->ctx))
+ return -ENODEV;
+
+ export_uuid(sess_arg.uuid, &pas_dev->id.uuid);
+ ret = tee_client_open_session(data->ctx, &sess_arg, NULL);
+ if (ret < 0 || sess_arg.ret != 0) {
+ dev_err(dev, "tee_client_open_session failed, ret: %d, err: 0x%x\n",
+ ret, sess_arg.ret);
+ err = ret ?: -EINVAL;
+ goto out_ctx;
+ }
+
+ data->session_id = sess_arg.session;
+ dev_set_drvdata(dev, data);
+ qcom_pas_ops_tee.dev = dev;
+ qcom_pas_ops_register(&qcom_pas_ops_tee);
+
+ return ret;
+out_ctx:
+ tee_client_close_context(data->ctx);
+
+ return err;
+}
+
+static void qcom_pas_tee_remove(struct tee_client_device *pas_dev)
+{
+ struct device *dev = &pas_dev->dev;
+ struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
+
+ qcom_pas_ops_unregister();
+ tee_client_close_session(data->ctx, data->session_id);
+ tee_client_close_context(data->ctx);
+}
+
+static const struct tee_client_device_id qcom_pas_tee_id_table[] = {
+ {UUID_INIT(0xcff7d191, 0x7ca0, 0x4784,
+ 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)},
+ {}
+};
+MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table);
+
+static struct tee_client_driver optee_pas_tee_driver = {
+ .probe = qcom_pas_tee_probe,
+ .remove = qcom_pas_tee_remove,
+ .id_table = qcom_pas_tee_id_table,
+ .driver = {
+ .name = "qcom-pas-tee",
+ },
+};
+
+module_tee_client_driver(optee_pas_tee_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm PAS TEE driver");
--
2.51.0
^ permalink raw reply related
* [PATCH v4 03/15] firmware: qcom_scm: Migrate to generic PAS service
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/firmware/qcom/Kconfig | 1 +
drivers/firmware/qcom/qcom_scm.c | 335 ++++++++++++++-----------------
2 files changed, 155 insertions(+), 181 deletions(-)
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index 8653639d06db..9a12ae2b639d 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -15,6 +15,7 @@ config QCOM_PAS
TEE bus based PAS service implementation.
config QCOM_SCM
+ select QCOM_PAS
select QCOM_TZMEM
tristate
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 9b06a69d3a6d..d87a962e93da 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/firmware/qcom/qcom_pas.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/firmware/qcom/qcom_tzmem.h>
#include <linux/init.h>
@@ -33,6 +34,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "qcom_pas.h"
#include "qcom_scm.h"
#include "qcom_tzmem.h"
@@ -479,25 +481,6 @@ void qcom_scm_cpu_power_down(u32 flags)
}
EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down);
-int qcom_scm_set_remote_state(u32 state, u32 id)
-{
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_BOOT,
- .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
- .arginfo = QCOM_SCM_ARGS(2),
- .args[0] = state,
- .args[1] = id,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- struct qcom_scm_res res;
- int ret;
-
- ret = qcom_scm_call(__scm->dev, &desc, &res);
-
- return ret ? : res.result[0];
-}
-EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
-
static int qcom_scm_disable_sdi(void)
{
int ret;
@@ -570,26 +553,12 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
dev_err(__scm->dev, "failed to set download mode: %d\n", ret);
}
-/**
- * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service
- * context for a given peripheral
- *
- * PAS context is device-resource managed, so the caller does not need
- * to worry about freeing the context memory.
- *
- * @dev: PAS firmware device
- * @pas_id: peripheral authentication service id
- * @mem_phys: Subsystem reserve memory start address
- * @mem_size: Subsystem reserve memory size
- *
- * Returns: The new PAS context, or ERR_PTR() on failure.
- */
struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
u32 pas_id,
phys_addr_t mem_phys,
size_t mem_size)
{
- struct qcom_scm_pas_context *ctx;
+ struct qcom_pas_context *ctx;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -600,11 +569,12 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
ctx->mem_phys = mem_phys;
ctx->mem_size = mem_size;
- return ctx;
+ return (struct qcom_scm_pas_context *)ctx;
}
EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
-static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
+static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id,
+ dma_addr_t mdata_phys,
struct qcom_scm_res *res)
{
struct qcom_scm_desc desc = {
@@ -626,7 +596,7 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
desc.args[1] = mdata_phys;
- ret = qcom_scm_call(__scm->dev, &desc, res);
+ ret = qcom_scm_call(dev, &desc, res);
qcom_scm_bw_disable();
disable_clk:
@@ -635,7 +605,8 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
return ret;
}
-static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
+static int qcom_scm_pas_prep_and_init_image(struct device *dev,
+ struct qcom_pas_context *ctx,
const void *metadata, size_t size)
{
struct qcom_scm_res res;
@@ -650,7 +621,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
memcpy(mdata_buf, metadata, size);
mdata_phys = qcom_tzmem_to_phys(mdata_buf);
- ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res);
+ ret = __qcom_scm_pas_init_image(dev, ctx->pas_id, mdata_phys, &res);
if (ret < 0)
qcom_tzmem_free(mdata_buf);
else
@@ -659,25 +630,9 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
return ret ? : res.result[0];
}
-/**
- * qcom_scm_pas_init_image() - Initialize peripheral authentication service
- * state machine for a given peripheral, using the
- * metadata
- * @pas_id: peripheral authentication service id
- * @metadata: pointer to memory containing ELF header, program header table
- * and optional blob of data used for authenticating the metadata
- * and the rest of the firmware
- * @size: size of the metadata
- * @ctx: optional pas context
- *
- * Return: 0 on success.
- *
- * Upon successful return, the PAS metadata context (@ctx) will be used to
- * track the metadata allocation, this needs to be released by invoking
- * qcom_scm_pas_metadata_release() by the caller.
- */
-int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
- struct qcom_scm_pas_context *ctx)
+static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id,
+ const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
{
struct qcom_scm_res res;
dma_addr_t mdata_phys;
@@ -685,7 +640,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
int ret;
if (ctx && ctx->use_tzmem)
- return qcom_scm_pas_prep_and_init_image(ctx, metadata, size);
+ return qcom_scm_pas_prep_and_init_image(dev, ctx, metadata, size);
/*
* During the scm call memory protection will be enabled for the meta
@@ -699,16 +654,15 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
* If we pass a buffer that is already part of an SHM Bridge to this
* call, it will fail.
*/
- mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys,
- GFP_KERNEL);
+ mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL);
if (!mdata_buf)
return -ENOMEM;
memcpy(mdata_buf, metadata, size);
- ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res);
+ ret = __qcom_scm_pas_init_image(dev, pas_id, mdata_phys, &res);
if (ret < 0 || !ctx) {
- dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
+ dma_free_coherent(dev, size, mdata_buf, mdata_phys);
} else if (ctx) {
ctx->ptr = mdata_buf;
ctx->phys = mdata_phys;
@@ -717,36 +671,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
return ret ? : res.result[0];
}
-EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
-/**
- * qcom_scm_pas_metadata_release() - release metadata context
- * @ctx: pas context
- */
-void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
+int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_scm_pas_context *ctx)
{
- if (!ctx->ptr)
- return;
+ return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size,
+ (struct qcom_pas_context *)ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
+static void __qcom_scm_pas_metadata_release(struct device *dev,
+ struct qcom_pas_context *ctx)
+{
if (ctx->use_tzmem)
qcom_tzmem_free(ctx->ptr);
else
- dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
+ dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys);
ctx->ptr = NULL;
}
+
+void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
+{
+ __qcom_scm_pas_metadata_release(__scm->dev,
+ (struct qcom_pas_context *)ctx);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
-/**
- * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
- * for firmware loading
- * @pas_id: peripheral authentication service id
- * @addr: start address of memory area to prepare
- * @size: size of the memory area to prepare
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id,
+ phys_addr_t addr, phys_addr_t size)
{
int ret;
struct qcom_scm_desc desc = {
@@ -768,7 +721,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -776,9 +729,15 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+{
+ return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
-static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
+static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id,
+ void *input_rt_tzm,
size_t input_rt_size,
size_t *output_rt_size)
{
@@ -813,7 +772,7 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
* with output_rt_tzm buffer with res.result[2] size however, It should not
* be of unresonable size.
*/
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
if (!ret && res.result[2] > SZ_1G) {
ret = -E2BIG;
goto free_output_rt;
@@ -830,51 +789,11 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
return ret ? ERR_PTR(ret) : output_rt_tzm;
}
-/**
- * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
- * for a given peripheral.
- *
- * Qualcomm remote processor may rely on both static and dynamic resources for
- * its functionality. Static resources typically refer to memory-mapped addresses
- * required by the subsystem and are often embedded within the firmware binary
- * and dynamic resources, such as shared memory in DDR etc., are determined at
- * runtime during the boot process.
- *
- * On Qualcomm Technologies devices, it's possible that static resources are not
- * embedded in the firmware binary and instead are provided by TrustZone However,
- * dynamic resources are always expected to come from TrustZone. This indicates
- * that for Qualcomm devices, all resources (static and dynamic) will be provided
- * by TrustZone via the SMC call.
- *
- * If the remote processor firmware binary does contain static resources, they
- * should be passed in input_rt. These will be forwarded to TrustZone for
- * authentication. TrustZone will then append the dynamic resources and return
- * the complete resource table in output_rt_tzm.
- *
- * If the remote processor firmware binary does not include a resource table,
- * the caller of this function should set input_rt as NULL and input_rt_size
- * as zero respectively.
- *
- * More about documentation on resource table data structures can be found in
- * include/linux/remoteproc.h
- *
- * @ctx: PAS context
- * @pas_id: peripheral authentication service id
- * @input_rt: resource table buffer which is present in firmware binary
- * @input_rt_size: size of the resource table present in firmware binary
- * @output_rt_size: TrustZone expects caller should pass worst case size for
- * the output_rt_tzm.
- *
- * Return:
- * On success, returns a pointer to the allocated buffer containing the final
- * resource table and output_rt_size will have actual resource table size from
- * TrustZone. The caller is responsible for freeing the buffer. On failure,
- * returns ERR_PTR(-errno).
- */
-struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
- void *input_rt,
- size_t input_rt_size,
- size_t *output_rt_size)
+static void *__qcom_scm_pas_get_rsc_table2(struct device *dev,
+ struct qcom_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
{
struct resource_table empty_rsc = {};
size_t size = SZ_16K;
@@ -909,11 +828,12 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
memcpy(input_rt_tzm, input_rt, input_rt_size);
- output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm,
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
+ input_rt_tzm,
input_rt_size, &size);
if (PTR_ERR(output_rt_tzm) == -EOVERFLOW)
/* Try again with the size requested by the TZ */
- output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id,
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id,
input_rt_tzm,
input_rt_size,
&size);
@@ -943,16 +863,20 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c
return ret ? ERR_PTR(ret) : tbl_ptr;
}
+
+struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ return __qcom_scm_pas_get_rsc_table2(__scm->dev,
+ (struct qcom_pas_context *)ctx,
+ input_rt, input_rt_size,
+ output_rt_size);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
-/**
- * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
- * and reset the remote processor
- * @pas_id: peripheral authentication service id
- *
- * Return 0 on success.
- */
-int qcom_scm_pas_auth_and_reset(u32 pas_id)
+static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
@@ -972,7 +896,7 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
if (ret)
goto disable_clk;
- ret = qcom_scm_call(__scm->dev, &desc, &res);
+ ret = qcom_scm_call(dev, &desc, &res);
qcom_scm_bw_disable();
disable_clk:
@@ -980,28 +904,15 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id)
return ret ? : res.result[0];
}
+
+int qcom_scm_pas_auth_and_reset(u32 pas_id)
+{
+ return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
-/**
- * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
- * remote processor
- *
- * @ctx: Context saved during call to qcom_scm_pas_context_init()
- *
- * This function performs the necessary steps to prepare a PAS subsystem,
- * authenticate it using the provided metadata, and initiate a reset sequence.
- *
- * It should be used when Linux is in control setting up the IOMMU hardware
- * for remote subsystem during secure firmware loading processes. The preparation
- * step sets up a shmbridge over the firmware memory before TrustZone accesses the
- * firmware memory region for authentication. The authentication step verifies
- * the integrity and authenticity of the firmware or configuration using secure
- * metadata. Finally, the reset step ensures the subsystem starts in a clean and
- * sane state.
- *
- * Return: 0 on success, negative errno on failure.
- */
-int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
+static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev,
+ struct qcom_pas_context *ctx)
{
u64 handle;
int ret;
@@ -1012,7 +923,7 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
* memory region and then invokes a call to TrustZone to authenticate.
*/
if (!ctx->use_tzmem)
- return qcom_scm_pas_auth_and_reset(ctx->pas_id);
+ return __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
/*
* When Linux runs @ EL2 Linux must create the shmbridge itself and then
@@ -1022,20 +933,45 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
if (ret)
return ret;
- ret = qcom_scm_pas_auth_and_reset(ctx->pas_id);
+ ret = __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id);
qcom_tzmem_shm_bridge_delete(handle);
return ret;
}
+
+int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
+{
+ return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev,
+ (struct qcom_pas_context *)ctx);
+}
EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
-/**
- * qcom_scm_pas_shutdown() - Shut down the remote processor
- * @pas_id: peripheral authentication service id
- *
- * Returns 0 on success.
- */
-int qcom_scm_pas_shutdown(u32 pas_id)
+static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state,
+ u32 pas_id)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_BOOT,
+ .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE,
+ .arginfo = QCOM_SCM_ARGS(2),
+ .args[0] = state,
+ .args[1] = pas_id,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ struct qcom_scm_res res;
+ int ret;
+
+ ret = qcom_scm_call(dev, &desc, &res);
+
+ return ret ? : res.result[0];
+}
+
+int qcom_scm_set_remote_state(u32 state, u32 id)
+{
+ 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 = {
@@ -2836,6 +2803,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
@@ -2875,6 +2847,7 @@ static void qcom_scm_shutdown(struct platform_device *pdev)
{
/* Clean shutdown, disable download mode to allow normal restart */
qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP);
+ qcom_pas_ops_unregister();
}
static const struct of_device_id qcom_scm_dt_match[] = {
--
2.51.0
^ permalink raw reply related
* [PATCH v4 02/15] firmware: qcom: Add a generic PAS service
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-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.
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
drivers/firmware/qcom/Kconfig | 8 +
drivers/firmware/qcom/Makefile | 1 +
drivers/firmware/qcom/qcom_pas.c | 288 +++++++++++++++++++++++++
drivers/firmware/qcom/qcom_pas.h | 50 +++++
include/linux/firmware/qcom/qcom_pas.h | 43 ++++
5 files changed, 390 insertions(+)
create mode 100644 drivers/firmware/qcom/qcom_pas.c
create mode 100644 drivers/firmware/qcom/qcom_pas.h
create mode 100644 include/linux/firmware/qcom/qcom_pas.h
diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig
index b477d54b495a..8653639d06db 100644
--- a/drivers/firmware/qcom/Kconfig
+++ b/drivers/firmware/qcom/Kconfig
@@ -6,6 +6,14 @@
menu "Qualcomm firmware drivers"
+config QCOM_PAS
+ tristate
+ help
+ Enable the generic Peripheral Authentication Service (PAS) provided
+ by the firmware. It acts as the common layer with different TZ
+ backends plugged in whether it's an SCM implementation or a proper
+ TEE bus based PAS service implementation.
+
config QCOM_SCM
select QCOM_TZMEM
tristate
diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile
index 0be40a1abc13..dc5ab45f906a 100644
--- a/drivers/firmware/qcom/Makefile
+++ b/drivers/firmware/qcom/Makefile
@@ -8,3 +8,4 @@ qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
+obj-$(CONFIG_QCOM_PAS) += qcom_pas.o
diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c
new file mode 100644
index 000000000000..caf7fff33e5c
--- /dev/null
+++ b/drivers/firmware/qcom/qcom_pas.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/device/devres.h>
+#include <linux/firmware/qcom/qcom_pas.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "qcom_pas.h"
+
+static struct qcom_pas_ops *ops_ptr;
+
+/**
+ * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service
+ * context for a given peripheral
+ *
+ * PAS context is device-resource managed, so the caller does not need
+ * to worry about freeing the context memory.
+ *
+ * @dev: PAS firmware device
+ * @pas_id: peripheral authentication service id
+ * @mem_phys: Subsystem reserve memory start address
+ * @mem_size: Subsystem reserve memory size
+ *
+ * Return: The new PAS context, or ERR_PTR() on failure.
+ */
+struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev,
+ u32 pas_id,
+ phys_addr_t mem_phys,
+ size_t mem_size)
+{
+ struct qcom_pas_context *ctx;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->dev = dev;
+ ctx->pas_id = pas_id;
+ ctx->mem_phys = mem_phys;
+ ctx->mem_size = mem_size;
+
+ return ctx;
+}
+EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc);
+
+/**
+ * qcom_pas_init_image() - Initialize peripheral authentication service state
+ * machine for a given peripheral, using the metadata
+ * @pas_id: peripheral authentication service id
+ * @metadata: pointer to memory containing ELF header, program header table
+ * and optional blob of data used for authenticating the metadata
+ * and the rest of the firmware
+ * @size: size of the metadata
+ * @ctx: optional pas context
+ *
+ * Return: 0 on success.
+ *
+ * Upon successful return, the PAS metadata context (@ctx) will be used to
+ * track the metadata allocation, this needs to be released by invoking
+ * qcom_pas_metadata_release() by the caller.
+ */
+int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_pas_context *ctx)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_init_image);
+
+/**
+ * qcom_pas_metadata_release() - release metadata context
+ * @ctx: pas context
+ */
+void qcom_pas_metadata_release(struct qcom_pas_context *ctx)
+{
+ if (!ctx || !ctx->ptr || !ops_ptr)
+ return;
+
+ ops_ptr->metadata_release(ops_ptr->dev, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_metadata_release);
+
+/**
+ * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral
+ * for firmware loading
+ * @pas_id: peripheral authentication service id
+ * @addr: start address of memory area to prepare
+ * @size: size of the memory area to prepare
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_mem_setup);
+
+/**
+ * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
+ * for a given peripheral.
+ *
+ * Qualcomm remote processor may rely on both static and dynamic resources for
+ * its functionality. Static resources typically refer to memory-mapped
+ * addresses required by the subsystem and are often embedded within the
+ * firmware binary and dynamic resources, such as shared memory in DDR etc.,
+ * are determined at runtime during the boot process.
+ *
+ * On Qualcomm Technologies devices, it's possible that static resources are
+ * not embedded in the firmware binary and instead are provided by TrustZone.
+ * However, dynamic resources are always expected to come from TrustZone. This
+ * indicates that for Qualcomm devices, all resources (static and dynamic) will
+ * be provided by TrustZone PAS service.
+ *
+ * If the remote processor firmware binary does contain static resources, they
+ * should be passed in input_rt. These will be forwarded to TrustZone for
+ * authentication. TrustZone will then append the dynamic resources and return
+ * the complete resource table in output_rt_tzm.
+ *
+ * If the remote processor firmware binary does not include a resource table,
+ * the caller of this function should set input_rt as NULL and input_rt_size
+ * as zero respectively.
+ *
+ * More about documentation on resource table data structures can be found in
+ * include/linux/remoteproc.h
+ *
+ * @ctx: PAS context
+ * @pas_id: peripheral authentication service id
+ * @input_rt: resource table buffer which is present in firmware binary
+ * @input_rt_size: size of the resource table present in firmware binary
+ * @output_rt_size: TrustZone expects caller should pass worst case size for
+ * the output_rt_tzm.
+ *
+ * Return:
+ * On success, returns a pointer to the allocated buffer containing the final
+ * resource table and output_rt_size will have actual resource table size from
+ * TrustZone. The caller is responsible for freeing the buffer. On failure,
+ * returns ERR_PTR(-errno).
+ */
+struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ if (!ctx)
+ return ERR_PTR(-EINVAL);
+ if (!ops_ptr)
+ return ERR_PTR(-ENODEV);
+
+ return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt,
+ input_rt_size, output_rt_size);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table);
+
+/**
+ * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware
+ * and reset the remote processor
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_auth_and_reset(u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset);
+
+/**
+ * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
+ * remote processor
+ *
+ * @ctx: Context saved during call to qcom_scm_pas_context_init()
+ *
+ * This function performs the necessary steps to prepare a PAS subsystem,
+ * authenticate it using the provided metadata, and initiate a reset sequence.
+ *
+ * It should be used when Linux is in control setting up the IOMMU hardware
+ * for remote subsystem during secure firmware loading processes. The
+ * preparation step sets up a shmbridge over the firmware memory before
+ * TrustZone accesses the firmware memory region for authentication. The
+ * authentication step verifies the integrity and authenticity of the firmware
+ * or configuration using secure metadata. Finally, the reset step ensures the
+ * subsystem starts in a clean and sane state.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx)
+{
+ if (!ctx)
+ return -EINVAL;
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset);
+
+/**
+ * qcom_pas_set_remote_state() - Set the remote processor state
+ * @state: peripheral state
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_set_remote_state(u32 state, u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state);
+
+/**
+ * qcom_pas_shutdown() - Shut down the remote processor
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: 0 on success.
+ */
+int qcom_pas_shutdown(u32 pas_id)
+{
+ if (!ops_ptr)
+ return -ENODEV;
+
+ return ops_ptr->shutdown(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_shutdown);
+
+/**
+ * qcom_pas_supported() - Check if the peripheral authentication service is
+ * available for the given peripheral
+ * @pas_id: peripheral authentication service id
+ *
+ * Return: true if PAS is supported for this peripheral, otherwise false.
+ */
+bool qcom_pas_supported(u32 pas_id)
+{
+ if (!ops_ptr)
+ return false;
+
+ return ops_ptr->supported(ops_ptr->dev, pas_id);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_supported);
+
+bool qcom_pas_is_available(void)
+{
+ /*
+ * The barrier for ops_ptr is intended to synchronize the data stores
+ * for the ops data structure when client drivers are in parallel
+ * checking for PAS service availability.
+ *
+ * Once the PAS backend becomes available, it is allowed for multiple
+ * threads to enter TZ for parallel bringup of co-processors during
+ * boot.
+ */
+ return !!smp_load_acquire(&ops_ptr);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_is_available);
+
+void qcom_pas_ops_register(struct qcom_pas_ops *ops)
+{
+ if (!qcom_pas_is_available())
+ /* Paired with smp_load_acquire() in qcom_pas_is_available() */
+ smp_store_release(&ops_ptr, ops);
+ else
+ pr_err("qcom_pas: ops already registered\n");
+}
+EXPORT_SYMBOL_GPL(qcom_pas_ops_register);
+
+void qcom_pas_ops_unregister(void)
+{
+ /* Paired with smp_load_acquire() in qcom_pas_is_available() */
+ smp_store_release(&ops_ptr, NULL);
+}
+EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Qualcomm common TZ PAS driver");
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.51.0
^ permalink raw reply related
* Re: [PATCH v4 net 03/10] octeontx2-af: npc: cn20k: Propagate errors in defrag MCAM alloc rollback
From: Ratheesh Kannoth @ 2026-04-27 9:56 UTC (permalink / raw)
To: netdev, linux-kernel
Cc: sgoutham, davem, edumazet, kuba, pabeni, andrew+netdev,
Dan Carpenter, Simon Horman
In-Reply-To: <20260427063213.3937451-4-rkannoth@marvell.com>
On 2026-04-27 at 12:02:06, Ratheesh Kannoth (rkannoth@marvell.com) wrote:
> npc_defrag_alloc_free_slots() allocates MCAM indexes in up to two passes
> on bank0 then bank1. On failure it rolls back by freeing entries already
> placed in save[].
>
> __npc_subbank_alloc() can return a negative errno while only part of the
> indexes are valid. The rollback loop used rc for
> npc_mcam_idx_2_subbank_idx() as well, so a successful lookup stored zero
> in rc and a later __npc_subbank_free() failure could still end with
> return 0 when the allocation path had also left rc at zero
> (for example shortfall after zero return values from the alloc helpers).
>
> Jump to the rollback path immediately when either __npc_subbank_alloc()
> call fails, preserving its errno. If both calls succeed but the total
> allocated count is still less than cnt, set rc to -ENOSPC before rollback.
> Use a separate err variable for npc_mcam_idx_2_subbank_idx() so a
> successful lookup no longer clears a non-zero rc from the allocation
> phase.
>
>> @@ -3533,13 +3535,14 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
>> __func__, cnt, alloc_cnt1, alloc_cnt2);
>> goto fail_free_alloc;
>> }
>> +
>> return 0;
>>
>> fail_free_alloc:
>> for (i = 0; i < alloc_cnt1 + alloc_cnt2; i++) {
>> - rc = npc_mcam_idx_2_subbank_idx(rvu, save[i],
>> - &sb, &sb_off);
>> - if (rc) {
>> + err = npc_mcam_idx_2_subbank_idx(rvu, save[i],
>> + &sb, &sb_off);
>> + if (err) {
>> dev_err(rvu->dev,
>> "%s: Error to find subbank for mcam idx=%u\n",
>> __func__, save[i]);
>Does the diff implement what the commit message describes?
>The commit message states:
> Jump to the rollback path immediately when either __npc_subbank_alloc()
> call fails, preserving its errno. If both calls succeed but the total
> allocated count is still less than cnt, set rc to -ENOSPC before
> rollback.
>Looking at npc_defrag_alloc_free_slots() after the patch applies, there
>is no early jump after the first __npc_subbank_alloc() call, and no
>assignment of rc = -ENOSPC before the goto:
ACK.
pw-bot: changes-requested
>> @@ -3533,13 +3535,14 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu,
>> __func__, cnt, alloc_cnt1, alloc_cnt2);
>> goto fail_free_alloc;
>> }
>> +
>> return 0;
>>
>> fail_free_alloc:
>> for (i = 0; i < alloc_cnt1 + alloc_cnt2; i++) {
>> - rc = npc_mcam_idx_2_subbank_idx(rvu, save[i],
>> - &sb, &sb_off);
>> - if (rc) {
>> + err = npc_mcam_idx_2_subbank_idx(rvu, save[i],
>> + &sb, &sb_off);
>> + if (err) {
>> dev_err(rvu->dev,
>> "%s: Error to find subbank for mcam idx=%u\n",
>> __func__, save[i]);
>Does the diff implement what the commit message describes?
>The commit message states:
> Jump to the rollback path immediately when either __npc_subbank_alloc()
> call fails, preserving its errno. If both calls succeed but the total
> allocated count is still less than cnt, set rc to -ENOSPC before
> rollback.
>Looking at npc_defrag_alloc_free_slots() after the patch applies, there
>is no early jump after the first __npc_subbank_alloc() call, and no
>assignment of rc = -ENOSPC before the goto:
ACK.
^ permalink raw reply
* [PATCH v4 01/15] arm64: dts: qcom: kodiak: Add EL2 overlay
From: Sumit Garg @ 2026-04-27 9:55 UTC (permalink / raw)
To: andersson, konradybcio
Cc: linux-arm-msm, devicetree, dri-devel, freedreno, linux-media,
netdev, linux-wireless, ath12k, linux-remoteproc, robh, krzk+dt,
conor+dt, robin.clark, sean, akhilpo, lumag, abhinav.kumar,
jesszhan0024, marijn.suijten, airlied, simona, vikash.garodia,
dikshita.agarwal, bod, mchehab, elder, andrew+netdev, davem,
edumazet, kuba, pabeni, jjohnson, mathieu.poirier,
trilokkumar.soni, 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: <20260427095603.1157963-1-sumit.garg@kernel.org>
From: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
All the existing variants Kodiak boards are using Gunyah hypervisor
which means that, so far, Linux-based OS could only boot in EL1 on those
devices. However, it is possible for us to boot Linux at EL2 on these
devices [1].
When running under Gunyah, the remote processor firmware IOMMU
streams are controlled by Gunyah. However, without Gunyah, the IOMMU is
managed by the consumer of this DeviceTree. Therefore, describe the
firmware streams for each remote processor.
Add a EL2-specific DT overlay and apply it to Kodiak IOT variant
devices to create -el2.dtb for each of them alongside "normal" dtb.
[1]
https://docs.qualcomm.com/bundle/publicresource/topics/80-70020-4/boot-developer-touchpoints.html#uefi
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
[SG: watchdog fixup]
Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/Makefile | 2 ++
arch/arm64/boot/dts/qcom/kodiak-el2.dtso | 35 ++++++++++++++++++++++++
2 files changed, 37 insertions(+)
create mode 100644 arch/arm64/boot/dts/qcom/kodiak-el2.dtso
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 4ba8e7306419..28123cdc9de2 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -170,6 +170,8 @@ qcs615-ride-el2-dtbs := qcs615-ride.dtb talos-el2.dtbo
dtb-$(CONFIG_ARCH_QCOM) += qcs615-ride-el2.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-radxa-dragon-q6a.dtb
dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb
+qcs6490-rb3gen2-el2-dtbs := qcs6490-rb3gen2.dtb kodiak-el2.dtbo
+dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2-el2.dtb
qcs6490-rb3gen2-vision-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-vision-mezzanine.dtbo
qcs6490-rb3gen2-industrial-mezzanine-dtbs := qcs6490-rb3gen2.dtb qcs6490-rb3gen2-industrial-mezzanine.dtbo
diff --git a/arch/arm64/boot/dts/qcom/kodiak-el2.dtso b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso
new file mode 100644
index 000000000000..0b3a69a0d765
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/kodiak-el2.dtso
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ *
+ * Kodiak specific modifications required to boot in EL2.
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+&gpu_zap_shader {
+ status = "disabled";
+};
+
+&remoteproc_adsp {
+ iommus = <&apps_smmu 0x1800 0x0>;
+};
+
+&remoteproc_cdsp {
+ iommus = <&apps_smmu 0x11a0 0x0400>;
+};
+
+&remoteproc_wpss {
+ iommus = <&apps_smmu 0x1c03 0x1>,
+ <&apps_smmu 0x1c83 0x1>;
+};
+
+&venus {
+ status = "disabled";
+};
+
+&watchdog {
+ status = "okay";
+};
--
2.51.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