* Re: [PATCH RFC bpf-next 1/8] kasan: expose generic kasan helpers
From: Alexei Starovoitov @ 2026-04-14 19:16 UTC (permalink / raw)
To: Alexis Lothoré
Cc: Andrey Konovalov, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman,
Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, David S. Miller, David Ahern, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, X86 ML, H. Peter Anvin,
Shuah Khan, Maxime Coquelin, Alexandre Torgue, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Vincenzo Frascino,
Andrew Morton, ebpf, Bastien Curutchet, Thomas Petazzoni,
Xu Kuohai, bpf, LKML, Network Development,
open list:KERNEL SELFTEST FRAMEWORK, linux-stm32,
linux-arm-kernel, kasan-dev, linux-mm
In-Reply-To: <DHT3JV7GTOBL.29205LGGNEDSH@bootlin.com>
On Tue, Apr 14, 2026 at 11:41 AM Alexis Lothoré
<alexis.lothore@bootlin.com> wrote:
>
> On Tue Apr 14, 2026 at 4:36 PM CEST, Alexei Starovoitov wrote:
> > On Tue, Apr 14, 2026 at 6:13 AM Alexis Lothoré
> > <alexis.lothore@bootlin.com> wrote:
> >>
> >> Hi Andrey, thanks for the prompt review !
> >>
> >> On Tue Apr 14, 2026 at 12:19 AM CEST, Andrey Konovalov wrote:
> >> > On Mon, Apr 13, 2026 at 8:29 PM Alexis Lothoré (eBPF Foundation)
> >> > <alexis.lothore@bootlin.com> wrote:
> >> >>
> >>
> >> [...]
> >>
> >> >> +#ifdef CONFIG_KASAN_GENERIC
> >> >> +void __asan_load1(void *p);
> >> >> +void __asan_store1(void *p);
> >> >> +void __asan_load2(void *p);
> >> >> +void __asan_store2(void *p);
> >> >> +void __asan_load4(void *p);
> >> >> +void __asan_store4(void *p);
> >> >> +void __asan_load8(void *p);
> >> >> +void __asan_store8(void *p);
> >> >> +void __asan_load16(void *p);
> >> >> +void __asan_store16(void *p);
> >> >> +#endif /* CONFIG_KASAN_GENERIC */
> >> >
> >> > This looks ugly, let's not do this unless it's really required.
> >> >
> >> > You can just use kasan_check_read/write() instead - these are public
> >> > wrappers around the same shadow memory checking functions. And they
> >> > also work with the SW_TAGS mode, in case the BPF would want to use
> >> > that mode at some point. (For HW_TAGS, we only have kasan_check_byte()
> >> > that checks a single byte, but it can be extended in the future if
> >> > required to be used by BPF.)
> >>
> >> ACK, I'll try to use those kasan_check_read and kasan_check_write rather
> >> than __asan_{load,store}X.
> >
> > No. The performance penalty will be too high.
>
> Since we are mentioning it, I did not consider yet any performance
> comparision/benchmarking (and I am not really familiar with usual bpf
> performance validation practices for new bpf features). Is there any
> existing test I should take a look at for this ? Maybe some specific
> benches in tools/testing/selftests/bpf/bench ?
So far everything in bpf/bench/ measures bpf infra like
maps, kprobes, tracepoints, etc.
We don't have benchmarks for bpf programs.
So we don't know how well JITs are generating code
and how much inlining done by the verifier, JITs actually helps.
Puranjay is working on creating a SPECint like set of benchmarks.
For this kasan work we should make the best decisions from
performance point of view, like not wasting unnecessary call
and not saving unnecessary registers. btw in the other patch
I think you can skip saving of r10 and r11.
But we cannot quantify yet that avoiding extra call gives us N%.
You can micro-benchmark, of course, but gotta be careful
interpreting the results. It might be too easy to get into
thinking that JIT must inline __asan_load() for the sake of performance.
^ permalink raw reply
* Re: [PATCH RFC bpf-next 1/8] kasan: expose generic kasan helpers
From: Alexis Lothoré @ 2026-04-14 18:41 UTC (permalink / raw)
To: Alexei Starovoitov, Alexis Lothoré
Cc: Andrey Konovalov, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman,
Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, David S. Miller, David Ahern, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, X86 ML, H. Peter Anvin,
Shuah Khan, Maxime Coquelin, Alexandre Torgue, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Vincenzo Frascino,
Andrew Morton, ebpf, Bastien Curutchet, Thomas Petazzoni,
Xu Kuohai, bpf, LKML, Network Development,
open list:KERNEL SELFTEST FRAMEWORK, linux-stm32,
linux-arm-kernel, kasan-dev, linux-mm
In-Reply-To: <CAADnVQLJ=fJ7t1i2+_RYqU1gqYqiLP9Zrwo4vdZsgzjK_yzJTQ@mail.gmail.com>
On Tue Apr 14, 2026 at 4:36 PM CEST, Alexei Starovoitov wrote:
> On Tue, Apr 14, 2026 at 6:13 AM Alexis Lothoré
> <alexis.lothore@bootlin.com> wrote:
>>
>> Hi Andrey, thanks for the prompt review !
>>
>> On Tue Apr 14, 2026 at 12:19 AM CEST, Andrey Konovalov wrote:
>> > On Mon, Apr 13, 2026 at 8:29 PM Alexis Lothoré (eBPF Foundation)
>> > <alexis.lothore@bootlin.com> wrote:
>> >>
>>
>> [...]
>>
>> >> +#ifdef CONFIG_KASAN_GENERIC
>> >> +void __asan_load1(void *p);
>> >> +void __asan_store1(void *p);
>> >> +void __asan_load2(void *p);
>> >> +void __asan_store2(void *p);
>> >> +void __asan_load4(void *p);
>> >> +void __asan_store4(void *p);
>> >> +void __asan_load8(void *p);
>> >> +void __asan_store8(void *p);
>> >> +void __asan_load16(void *p);
>> >> +void __asan_store16(void *p);
>> >> +#endif /* CONFIG_KASAN_GENERIC */
>> >
>> > This looks ugly, let's not do this unless it's really required.
>> >
>> > You can just use kasan_check_read/write() instead - these are public
>> > wrappers around the same shadow memory checking functions. And they
>> > also work with the SW_TAGS mode, in case the BPF would want to use
>> > that mode at some point. (For HW_TAGS, we only have kasan_check_byte()
>> > that checks a single byte, but it can be extended in the future if
>> > required to be used by BPF.)
>>
>> ACK, I'll try to use those kasan_check_read and kasan_check_write rather
>> than __asan_{load,store}X.
>
> No. The performance penalty will be too high.
Since we are mentioning it, I did not consider yet any performance
comparision/benchmarking (and I am not really familiar with usual bpf
performance validation practices for new bpf features). Is there any
existing test I should take a look at for this ? Maybe some specific
benches in tools/testing/selftests/bpf/bench ?
> hw_tags won't work without corresponding JIT work.
> I see no point sacrificing performance for aesthetics.
> __asan_load/storeX is what compilers emit.
> In that sense JIT is a compiler it should emit exactly the same.
--
Alexis Lothoré, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH v2 3/3] iio: adc: xilinx-ams: refactor alarm mapping to table-driven approach
From: Andy Shevchenko @ 2026-04-14 18:40 UTC (permalink / raw)
To: Guilherme Ivo Bozi
Cc: Salih Erim, Conall O'Griofa, Jonathan Cameron, Michal Simek,
David Lechner, Nuno Sá, Andy Shevchenko, linux-iio,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260414103316.18455-4-guilherme.bozi@usp.br>
On Tue, Apr 14, 2026 at 07:29:19AM -0300, Guilherme Ivo Bozi wrote:
> Replace multiple open-coded switch statements that map between
> scan_index, alarm bits, and register offsets with a centralized
> table-driven approach.
>
> Introduce a struct-based alarm_map to describe the relationship
> between scan indices and alarm offsets, and add a helper to
> translate scan_index to event IDs. This removes duplicated logic
> across ams_get_alarm_offset(), ams_event_to_channel(), and
> ams_get_alarm_mask().
>
> The new approach improves maintainability, reduces code size,
> and makes it easier to extend or modify alarm mappings in the
> future, while preserving existing behavior.
...
> +static const struct ams_alarm_map alarm_map[] = {
> + [AMS_ALARM_BIT_TEMP] = { AMS_SEQ_TEMP, AMS_ALARM_TEMP },
> + [AMS_ALARM_BIT_SUPPLY1] = { AMS_SEQ_SUPPLY1, AMS_ALARM_SUPPLY1 },
> + [AMS_ALARM_BIT_SUPPLY2] = { AMS_SEQ_SUPPLY2, AMS_ALARM_SUPPLY2 },
> + [AMS_ALARM_BIT_SUPPLY3] = { AMS_SEQ_SUPPLY3, AMS_ALARM_SUPPLY3 },
> + [AMS_ALARM_BIT_SUPPLY4] = { AMS_SEQ_SUPPLY4, AMS_ALARM_SUPPLY4 },
> + [AMS_ALARM_BIT_SUPPLY5] = { AMS_SEQ_SUPPLY5, AMS_ALARM_SUPPLY5 },
> + [AMS_ALARM_BIT_SUPPLY6] = { AMS_SEQ_SUPPLY6, AMS_ALARM_SUPPLY6 },
> + [AMS_ALARM_BIT_RESERVED] = { 0, AMS_ALARM_NONE },
> + [AMS_ALARM_BIT_SUPPLY7] = { AMS_SEQ_SUPPLY7, AMS_ALARM_SUPPLY7 },
> + [AMS_ALARM_BIT_SUPPLY8] = { AMS_SEQ_SUPPLY8, AMS_ALARM_SUPPLY8 },
> + [AMS_ALARM_BIT_SUPPLY9] = { AMS_SEQ_SUPPLY9, AMS_ALARM_SUPPLY9 },
> + [AMS_ALARM_BIT_SUPPLY10] = { AMS_SEQ_SUPPLY10, AMS_ALARM_SUPPLY10 },
> + [AMS_ALARM_BIT_VCCAMS] = { AMS_SEQ_VCCAMS, AMS_ALARM_VCCAMS },
> + [AMS_ALARM_BIT_TEMP_REMOTE] = { AMS_SEQ_TEMP_REMOTE, AMS_ALARM_TEMP_REMOTE }
Haven't noticed before, please leave a trailing comma here as it is not
semantically a terminator entry.
> +};
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v2 1/3] iio: adc: xilinx-ams: fix out-of-bounds channel lookup in event handling
From: Andy Shevchenko @ 2026-04-14 18:37 UTC (permalink / raw)
To: Guilherme Ivo Bozi
Cc: Salih Erim, Conall O'Griofa, Jonathan Cameron, Michal Simek,
David Lechner, Nuno Sá, Andy Shevchenko, linux-iio,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260414103316.18455-2-guilherme.bozi@usp.br>
On Tue, Apr 14, 2026 at 07:29:17AM -0300, Guilherme Ivo Bozi wrote:
> ams_event_to_channel() may return a pointer past the end of
> dev->channels when no matching scan_index is found. This can lead
> to invalid memory access in ams_handle_event().
>
> Add a bounds check in ams_event_to_channel() and return NULL when
> no channel is found. Also guard the caller to safely handle this
> case.
...
> + if (i >= dev->num_channels)
The '==' is clearer. Otherwise, please justify the '>' part.
> + return NULL;
...
TBH I do not see how this code is not a dead code. But for the sake of
robustness it might be added. I leave it up to the maintainer.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* [PATCH v2 2/3] drm/exynos: remove bridge when component_add fails
From: Osama Abdelkader @ 2026-04-14 17:54 UTC (permalink / raw)
To: luca.ceresoli, Inki Dae, Seung-Woo Kim, Kyungmin Park,
David Airlie, Simona Vetter, Krzysztof Kozlowski, Alim Akhtar,
dri-devel, linux-arm-kernel, linux-samsung-soc, linux-kernel
Cc: Osama Abdelkader
In-Reply-To: <20260414175417.144625-1-osama.abdelkader@gmail.com>
Use devm_drm_bridge_add() so the bridge is released if probe fails after
registration, and drop the manual drm_bridge_remove() in remove().
Check the return value of devm_drm_bridge_add().
v2: devm_drm_bridge_add instead of drm_bridge_add + goto remove_bridge
Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
---
drivers/gpu/drm/exynos/exynos_drm_mic.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c
index 29a8366513fa..e68c954ec3e6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_mic.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c
@@ -423,7 +423,9 @@ static int exynos_mic_probe(struct platform_device *pdev)
mic->bridge.of_node = dev->of_node;
- drm_bridge_add(&mic->bridge);
+ ret = devm_drm_bridge_add(dev, &mic->bridge);
+ if (ret)
+ goto err;
pm_runtime_enable(dev);
@@ -443,12 +445,8 @@ static int exynos_mic_probe(struct platform_device *pdev)
static void exynos_mic_remove(struct platform_device *pdev)
{
- struct exynos_mic *mic = platform_get_drvdata(pdev);
-
component_del(&pdev->dev, &exynos_mic_component_ops);
pm_runtime_disable(&pdev->dev);
-
- drm_bridge_remove(&mic->bridge);
}
static const struct of_device_id exynos_mic_of_match[] = {
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config
From: Yeoreum Yun @ 2026-04-14 16:59 UTC (permalink / raw)
To: Leo Yan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
In-Reply-To: <20260414160441.GF356832@e132581.arm.com>
Hi Leo,
> On Mon, Apr 13, 2026 at 03:19:55PM +0100, Yeoreum Yun wrote:
> > The purpose of TRCSSCSRn register is to show status of
> > the corresponding Single-shot Comparator Control and input supports.
> > That means writable field's purpose for reset or restore from idle status
> > not for configuration.
> >
> > Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
> > This includes remove TRCSSCRn from configurable item and
> > remove saving in etm4_disable_hw().
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> > ---
> > .../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
> > .../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
> > .../coresight/coresight-etm4x-sysfs.c | 7 ++-----
> > drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++-
> > 4 files changed, 10 insertions(+), 20 deletions(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> > index c302072b293a..d14d7c8a23e5 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> > @@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
> > off_mask = (offset & GENMASK(11, 5));
> > do {
> > CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
> > - CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
> > CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
> > } while (0);
> > } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > index 6443f3717b37..8ebfd3924143 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > @@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
> > const struct etmv4_caps *caps = &drvdata->caps;
> >
> > return (n < caps->nr_ss_cmp) && caps->nr_pe &&
> > - (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
> > + (caps->ss_status[n] & TRCSSCSRn_PC);
>
> Nitpick: The naming 'ss_status' is a bit confused for capability.
> Could we rename 'ss_status' to 'ss_comparator' or a simple one
> 'ss_cmp' ?
Okay.
>
> > }
> >
> > u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
> > @@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> > etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
> >
> > for (i = 0; i < caps->nr_ss_cmp; i++) {
> > - /* always clear status bit on restart if using single-shot */
> > - if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> > - config->ss_status[i] &= ~TRCSSCSRn_STATUS;
> > etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
> > - etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
> > + /* always clear status and pending bits on restart if using single-shot */
> > + etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
>
> It is a bit weird to use caps to write a register. A smooth way is to
> clear STATUS and PENDING bits based on the read back value:
>
> val = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> val &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
> etm4x_relaxed_write32(csa, val, TRCSSCSRn(i));
TBH, this is what I want to avoid. anyway Why do we need to
read again TRCSSCSR<n>? I think it's enough to write caps->ss_cmp
for clear purpose or
since the cap->ss_cmp will be all RO fields, It seems to better
to write "0" in here without reading TRCSSSR again.
>
> > if (etm4x_sspcicrn_present(drvdata, i))
> > etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
> > }
> > @@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
> >
> > etm4_disable_trace_unit(drvdata);
> >
> > - /* read the status of the single shot comparators */
> > - for (i = 0; i < caps->nr_ss_cmp; i++) {
> > - config->ss_status[i] =
> > - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> > - }
> > -
> > /* read back the current counter values */
> > for (i = 0; i < caps->nr_cntr; i++) {
> > config->cntr_val[i] =
> > @@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
> > */
> > caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
> > for (i = 0; i < caps->nr_ss_cmp; i++) {
> > - drvdata->config.ss_status[i] =
> > - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> > + caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> > + caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
>
> For init cap, we can use explict way:
>
> caps->ss_cmp &= (TRCSSCSRn_PC | TRCSSCSRn_DV |
> TRCSSCSRn_DA | TRCSSCSRn_INST);
Okay.
>
> > }
> > /* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
> > caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > index 50408215d1ac..dd62f01674cf 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> > @@ -1827,8 +1827,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
> > raw_spin_lock(&drvdata->spinlock);
> > idx = config->ss_idx;
> > config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
> > - /* must clear bit 31 in related status register on programming */
> > - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> > raw_spin_unlock(&drvdata->spinlock);
> > return size;
> > }
> > @@ -1839,10 +1837,11 @@ static ssize_t sshot_status_show(struct device *dev,
> > {
> > unsigned long val;
> > struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> > + const struct etmv4_caps *caps = &drvdata->caps;
> > struct etmv4_config *config = &drvdata->config;
> >
> > raw_spin_lock(&drvdata->spinlock);
> > - val = config->ss_status[config->ss_idx];
> > + val = caps->ss_status[config->ss_idx];
>
> I think cap->ss_cmp is a good refactoring, but for legacy reason, I am
> just wandering if we still need config->ss_status so that it can record
> the lastest status (mainly for STATUS bit and PENDING bit).
>
> Otherwise, this Sysfs interface can only provide capability rather
> than status value.
The legacy *totally* isn't understandable.
Since config->ss_status is *updated* at "disable" -- end of sysfs session,
STATUS and PENDING bit doesn't have any meaning in here
and while running a session config->ss_status isn't updated all
So, I don't believe there was any user who care about this bit via
sysfs interface.
Therefore, I think we can refactor with caps->ss_cmp. let's drop the
useless and meaningless information.
>
> Thanks,
> Leo
>
> > raw_spin_unlock(&drvdata->spinlock);
> > return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> > }
> > @@ -1877,8 +1876,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
> > raw_spin_lock(&drvdata->spinlock);
> > idx = config->ss_idx;
> > config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
> > - /* must clear bit 31 in related status register on programming */
> > - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> > raw_spin_unlock(&drvdata->spinlock);
> > return size;
> > }
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> > index 8168676f2945..8864cfb76bad 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> > @@ -213,6 +213,7 @@
> > #define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
> >
> > #define TRCSSCSRn_STATUS BIT(31)
> > +#define TRCSSCSRn_PENDING BIT(30)
> > #define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
> >
> > #define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
> > @@ -861,6 +862,7 @@ enum etm_impdef_type {
> > * @lpoverride: If the implementation can support low-power state over.
> > * @skip_power_up: Indicates if an implementation can skip powering up
> > * the trace unit.
> > + * @ss_status: The status of the corresponding single-shot comparator.
> > */
> > struct etmv4_caps {
> > u8 nr_pe;
> > @@ -899,6 +901,7 @@ struct etmv4_caps {
> > bool atbtrig : 1;
> > bool lpoverride : 1;
> > bool skip_power_up : 1;
> > + u32 ss_status[ETM_MAX_SS_CMP];
> > };
> >
> > /**
> > @@ -977,7 +980,6 @@ struct etmv4_config {
> > u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
> > u8 ss_idx;
> > u32 ss_ctrl[ETM_MAX_SS_CMP];
> > - u32 ss_status[ETM_MAX_SS_CMP];
> > u32 ss_pe_cmp[ETM_MAX_SS_CMP];
> > u8 addr_idx;
> > u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
> > --
> > LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
> >
--
Sincerely,
Yeoreum Yun
^ permalink raw reply
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
From: Yeoreum Yun @ 2026-04-14 16:50 UTC (permalink / raw)
To: Leo Yan
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
In-Reply-To: <20260414163221.GG356832@e132581.arm.com>
Hi,
> On Mon, Apr 13, 2026 at 03:19:56PM +0100, Yeoreum Yun wrote:
> > If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
> > the trace ID may be leaked because it is not released.
> >
> > To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
> > fails in cscfg_csdev_enable_active_config().
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> > ---
> > drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
> > 1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > index 8ebfd3924143..1bc9f13e33f7 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> > cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> > if (cfg_hash) {
> > ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> > - if (ret)
> > + if (ret) {
> > + etm4_release_trace_id(drvdata);
>
> I am not familiar with the trace ID, seems to me, it just allocate a ID
> for each tracer from the ID map and then always use this cached ID for
> the tracers.
>
> If so, even an ID is reserved for failures, and the ID map is big enough
> for each CPU, we don't need to worry memory leak or ID used out issue ?
>
Agree. Practically, this is not a big issue and I don't think
because of this new id couldn't be allocated in 128
although the one id is occupied by cpu while source is disabled.
However, in theory, this could lead to an ID leak,
so it would be better to release it in error cases.
[...]
--
Sincerely,
Yeoreum Yun
^ permalink raw reply
* Re: [GIT PULL] Kbuild and Kconfig changes for v7.1
From: pr-tracker-bot @ 2026-04-14 16:46 UTC (permalink / raw)
To: Nicolas Schier
Cc: Linus Torvalds, Alexander Coffin, Ard Biesheuvel, Arnd Bergmann,
Bill Wendling, David Howells, Dodji Seketeli, H. Peter Anvin,
Helge Deller, John Moon, Jonathan Corbet, Josh Poimboeuf,
Justin Stitt, Kees Cook, Masahiro Yamada, Nathan Chancellor,
Nick Desaulniers, Shuah Khan, Song Liu, Thomas Weißschuh,
Yonghong Song, kernel-team, linux-arm-kernel, linux-efi,
linux-hexagon, linux-kbuild, linux-kernel, linux-parisc,
linux-s390, linuxppc-dev, llvm, loongarch
In-Reply-To: <adu-ZyIv47FnsVLI@levanger>
The pull request you sent on Sun, 12 Apr 2026 17:46:47 +0200:
> ssh://git@gitolite.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git tags/kbuild-7.1-1
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/5d0d3623303775d750e122a2542d1a26c8573d38
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* Re: [RFC PATCH] arm64: mm: support set_memory_encrypted/decrypted for vmalloc addresses
From: Catalin Marinas @ 2026-04-14 16:46 UTC (permalink / raw)
To: Kameron Carr
Cc: will, suzuki.poulose, steven.price, ryan.roberts, dev.jain, yang,
shijie, kevin.brodsky, linux-arm-kernel, linux-kernel
In-Reply-To: <001301dcc932$21cb6d80$65624880$@linux.microsoft.com>
On Fri, Apr 10, 2026 at 02:36:42PM -0700, Kameron Carr wrote:
> On Friday, April 10, 2026 4:06 AM, Catalin Marinas wrote:
> > Could you give more details about the user of set_memory_decrypted() on
> > vmalloc()'ed addresses? I think this came up in the past and I wondered
> > whether something like GFP_DECRYPTED would be simpler to implement (even
> > posted a hack but without vmalloc() support). If it is known upfront
> > that the memory will be decrypted, it's easier/cheaper to do this on the
> > page allocation time to change the linear map and just use
> > pgprot_decrypted() for vmap(). No need to rewrite the page table after
> > mapping the pages.
[...]
> In this use case, whether to decrypt the memory can always be known at
> time of allocation, so a solution like GFP_DECRYPTED is an option.
>
> I think I found the hack you mentioned
> (https://lore.kernel.org/linux-arm-kernel/ZmNJdSxSz-sYpVgI@arm.com/). The
> feedback in Michael Kelley's reply covers the key considerations well.
Yes, that's the thread. It started originally as a GICv3 need
(eventually we went for genpool).
> He likely had netvsc's use of vmalloc in mind when he made the point
> "GFP_DECRYPTED should work for the three memory allocation interfaces and
> their variants: alloc_pages(), kmalloc(), and vmalloc()." His other
> points already cover the concerns I had in mind around handling errors
> from set_memory_decrypted()/encrypted(), etc.
>
> What is the current status of your proposed GFP_DECRYPTED implementation?
> Is this something you are actively working on?
Not really. But I've been looking at it again and I think it adds more
problems than it solves. A GFP flag would be passed down to
kmem_cache_alloc() and confuse the slab management if some pages are
encrypted, others not for the same kmem_cache (SLAB_NO_MERGE wouldn't
help). I wonder whether something like SLAB_DECRYPTED would work better
for this if we really need it (not aware of any user though).
Anyway, let's ignore slab for now and look at vmalloc(). I can see
hv_ringbuffer_init() using an explicit vmap(pgprot_decrypted()). While
you could do this, it might be better to just add a VM_DECRYPTED flag
and a few wrappers like vmalloc_decrypted(). It would call
set_memory_decrypted() for the allocated pages and use
pgprot_decrypted() for vmap. On vfree(), it will have to set the pages
back to encrypted. It should be fairly mechanical to do (or a 5 min job
for an LLM ;)).
--
Catalin
^ permalink raw reply
* Re: [GIT PULL] arm64: dts: ti: k3: Late DT update for v7.1
From: Krzysztof Kozlowski @ 2026-04-14 16:44 UTC (permalink / raw)
To: Vignesh Raghavendra
Cc: SoC, arm, SoC list, linux-arm-kernel, linux-kernel, Tero Kristo,
Nishanth, Menon
In-Reply-To: <6e294d61-9779-41ef-83f8-29f46fd98700@ti.com>
On Sun, Apr 12, 2026 at 12:52:51PM +0530, Vignesh Raghavendra wrote:
> Hi ARM SoC Maintainers,
>
> This contains a single patch that updates r5f remoteproc DT nodes, warranted by recent
> binding update merged via remoteproc tree.
>
> The following changes since commit 47c806de9e9cf171d197f2f0df86df7f2bd1aa56:
>
> arm64: dts: ti: k3-pinctrl: sort shift values numerically (2026-03-27 19:55:06 +0530)
>
> are available in the Git repository at:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git tags/ti-k3-dt-for-v7.1-part2
>
> for you to fetch changes up to abe76f9f47d59ff80eb2fc59482aa76bbf6fd13a:
>
> arm64: dts: ti: k3: Use memory-region-names for r5f (2026-04-09 17:05:28 +0530)
>
> ----------------------------------------------------------------
> TI K3 device tree updates for v7.1 part2
>
> Late addition:
> - Use memory-region-names for r5f across K3 SoCs
>
Thanks, applied
Best regards,
Krzysztof
^ permalink raw reply
* Re: [GIT PULL] ARM: mvebu: dt64 for v7.1 (#1)
From: Krzysztof Kozlowski @ 2026-04-14 16:40 UTC (permalink / raw)
To: Gregory CLEMENT
Cc: Arnd Bergmann, arm, soc, Andrew Lunn, Sebastian Hesselbarth,
linux-arm-kernel
In-Reply-To: <87cy072bho.fsf@BLaptop.bootlin.com>
On Fri, Apr 10, 2026 at 03:25:39PM +0200, Gregory CLEMENT wrote:
> Hi,
>
> Here is the first pull request for dt64 for mvebu for v7.1.
>
> Gregory
>
> The following changes since commit 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f:
>
> Linux 7.0-rc1 (2026-02-22 13:18:59 -0800)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu.git tags/mvebu-dt64-7.1-1
>
> for you to fetch changes up to 00e6d608fe80b0f68c325cb46862f78e9a8ec768:
>
> arm64: dts: marvell: armada-37xx: swap PHYs' order in USB3 controller node (2026-04-09 10:14:40 +0200)
>
> ----------------------------------------------------------------
> mvebu dt64 for 7.1 (part 1)
This was sent just 2 days before merge window open, thus I applied it as
late branch.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v4 3/9] coresight: etm4x: fix leaked trace id
From: Leo Yan @ 2026-04-14 16:32 UTC (permalink / raw)
To: Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
In-Reply-To: <20260413142003.3549310-4-yeoreum.yun@arm.com>
On Mon, Apr 13, 2026 at 03:19:56PM +0100, Yeoreum Yun wrote:
> If etm4_enable_sysfs() fails in cscfg_csdev_enable_active_config(),
> the trace ID may be leaked because it is not released.
>
> To address this, call etm4_release_trace_id() when etm4_enable_sysfs()
> fails in cscfg_csdev_enable_active_config().
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 8ebfd3924143..1bc9f13e33f7 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -918,8 +918,10 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
> cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> if (cfg_hash) {
> ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> - if (ret)
> + if (ret) {
> + etm4_release_trace_id(drvdata);
I am not familiar with the trace ID, seems to me, it just allocate a ID
for each tracer from the ID map and then always use this cached ID for
the tracers.
If so, even an ID is reserved for failures, and the ID map is big enough
for each CPU, we don't need to worry memory leak or ID used out issue ?
Thanks,
Leo
> return ret;
> + }
> }
>
> raw_spin_lock(&drvdata->spinlock);
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
^ permalink raw reply
* Re: [PATCH RFC] ACPI: processor: idle: Do not propagate acpi_processor_ffh_lpi_probe() -ENODEV
From: Breno Leitao @ 2026-04-14 16:31 UTC (permalink / raw)
To: Sudeep Holla
Cc: lihuisong (C), Rafael J. Wysocki, Len Brown, lpieralisi,
catalin.marinas, will, Rafael J. Wysocki, linux-acpi,
linux-kernel, pjaroszynski, guohanjun, linux-arm-kernel, rmikey,
kernel-team
In-Reply-To: <20260414-excellent-hidden-dodo-5bb98e@sudeepholla>
Hello Sudeep,
On Tue, Apr 14, 2026 at 03:10:03PM +0100, Sudeep Holla wrote:
> On Tue, Apr 14, 2026 at 06:14:19AM -0700, Breno Leitao wrote:
> > Hello Sudeep,
> >
> > On Tue, Apr 14, 2026 at 01:25:53PM +0100, Sudeep Holla wrote:
> > > So while I understand that the kernel did not report an error previously, that
> > > does not mean the _LPI table is merely moot on this platform when it contains
> > > only a WFI state.
> >
> > Can you clarify whether datacenter ARM systems are expected to expose
> > deeper idle states beyond WFI in their _LPI tables?
> >
>
> Of course any system that prefers to save power when its idling must have
> these _LPI deeper idle states.
>
> > Backing up, I'm observing 72 pr_err() messages during boot on these
> > hosts and trying to determine whether this indicates a firmware issue or
> > if the kernel needs adjustment.
>
> I consider this a firmware issue, but not a fatal one. What matters more is
> the behavior after those errors are reported.
I understand. While I'm not a hardware or firmware vendor myself, I can
see how they might consider power management features _optional_ for certain
server configurations.
> If you force success, either through your change or through the PSCI approach
> suggested by lihuisong, then in practice you are only enabling a cpuidle
> driver with a single usable state: WFI. That is not inherently wrong, but it
> also does not provide much benefit.
Given that this isn't a critical error, would it make sense to downgrade
the pr_err() to pr_debug()? is it a reasonable compromise. I just want
to avoid these pr_err() all accross the board, affecting kernel health
metrics in large fleets.
My proposal:
commit c98007f9e10fe229672d29c3844c96705cecaed5
Author: Breno Leitao <leitao@debian.org>
Date: Tue Apr 14 05:28:28 2026 -0700
ACPI: processor: idle: Downgrade FFH LPI probe failure message to pr_debug()
The "Invalid FFH LPI data" message is printed at pr_err() level for every
CPU when acpi_processor_ffh_lpi_probe() fails. On platforms where the FFH
probe legitimately returns an error (e.g., no deep idle states beyond
WFI), this floods the kernel log with per-CPU error messages that are not
actionable.
Downgrade to pr_debug() since this is a diagnostic message, not a
critical error.
Signed-off-by: Breno Leitao <leitao@debian.org>
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index ee5facccbe10c..ab93a2c10a9ad 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1259,7 +1259,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
if (pr->flags.has_lpi) {
ret = acpi_processor_ffh_lpi_probe(pr->id);
if (ret)
- pr_err("CPU%u: Invalid FFH LPI data\n", pr->id);
+ pr_debug("CPU%u: Invalid FFH LPI data\n", pr->id);
}
return ret;
^ permalink raw reply related
* Re: [PATCH] ASoC: pxa2xx-ac97: fix error handling for reset GPIO descriptor
From: Mark Brown @ 2026-04-13 17:02 UTC (permalink / raw)
To: Daniel Mack, Haojian Zhuang, Robert Jarzmik, Jaroslav Kysela,
Takashi Iwai, Peng Fan (OSS)
Cc: linux-arm-kernel, linux-sound, linux-kernel, Peng Fan,
kernel test robot, Dan Carpenter
In-Reply-To: <20260413-ac97-v1-1-b44b9e084307@nxp.com>
On Mon, 13 Apr 2026 18:52:43 +0800, Peng Fan (OSS) wrote:
> ASoC: pxa2xx-ac97: fix error handling for reset GPIO descriptor
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.1
Thanks!
[1/1] ASoC: pxa2xx-ac97: fix error handling for reset GPIO descriptor
https://git.kernel.org/broonie/sound/c/54a032d3e62f
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply
* Re: [PATCH v8 1/4] dt-bindings: backlight: Add max25014 support
From: Daniel Thompson @ 2026-04-14 16:25 UTC (permalink / raw)
To: maudspierings
Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Liam Girdwood, Mark Brown, Frank Li, dri-devel, linux-leds,
devicetree, linux-kernel, linux-fbdev, imx, linux-arm-kernel
In-Reply-To: <20260407-max25014-v8-1-14eac7ed673a@gocontroll.com>
On Tue, Apr 07, 2026 at 04:41:42PM +0200, Maud Spierings via B4 Relay wrote:
> From: Maud Spierings <maudspierings@gocontroll.com>
>
> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> with integrated boost controller.
>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
Reviewed-by: Daniel Thompson (RISCstar) <danielt@kernel.org>
Daniel.
^ permalink raw reply
* Re: [PATCH RFC v2 01/11] ASoC: meson: gx: add gx-formatter and gx-interface
From: Mark Brown @ 2026-04-14 16:21 UTC (permalink / raw)
To: Valerio Setti
Cc: Jerome Brunet, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Neil Armstrong, Kevin Hilman, Martin Blumenstingl, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-kernel, linux-sound,
linux-arm-kernel, linux-amlogic, devicetree
In-Reply-To: <20260411-audin-rfc-v2-1-4c8a6ec5fcab@baylibre.com>
[-- Attachment #1: Type: text/plain, Size: 704 bytes --]
On Sat, Apr 11, 2026 at 04:57:26PM +0200, Valerio Setti wrote:
> These files are the basic block which allow to shape I2S in GX devices
> the same as the AXG ones: the DAI backend only controls the interface
> (i.e. clocks and pins) whereas a formatter takes care of properly
> formatting the data.
> +int gx_formatter_probe(struct platform_device *pdev)
> +{
> +
> + return snd_soc_register_component(dev, drv->component_drv, NULL, 0);
> +}
> +EXPORT_SYMBOL_GPL(gx_formatter_probe);
The other allocations in this are devm_ but the component is registered
without using devm. Not using devm also means that all the users need
remove() functions to unregister the component, there isn't one for
AUDIN.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH RFC v2 02/11] ASoC: meson: aiu-encoder-i2s: use gx_iface and gx_stream structures
From: Mark Brown @ 2026-04-14 16:13 UTC (permalink / raw)
To: Valerio Setti
Cc: Jerome Brunet, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Neil Armstrong, Kevin Hilman, Martin Blumenstingl, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-kernel, linux-sound,
linux-arm-kernel, linux-amlogic, devicetree
In-Reply-To: <20260411-audin-rfc-v2-2-4c8a6ec5fcab@baylibre.com>
[-- Attachment #1: Type: text/plain, Size: 1601 bytes --]
On Sat, Apr 11, 2026 at 04:57:27PM +0200, Valerio Setti wrote:
> @@ -200,13 +200,17 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
> - aiu_encoder_i2s_divider_enable(component, true);
> + ret = gx_stream_set_cont_clocks(ts, iface->fmt);
> + if (ret)
> + dev_err(dai->dev, "failed to apply continuous clock setting\n");
> +
> + aiu_encoder_i2s_divider_enable(component, 1);
If we're checking the error here we should probably return it as well.
Including the error code in the log message is also generally helpful.
> @@ -214,16 +218,20 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
> static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
> struct snd_soc_dai *dai)
> {
> + struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
> struct snd_soc_component *component = dai->component;
>
> - aiu_encoder_i2s_divider_enable(component, false);
> -
> - return 0;
> + /* This is the last substream open and that is going to be closed. */
> + if (snd_soc_dai_active(dai) <= 1)
> + aiu_encoder_i2s_divider_enable(component, 0);
> + return gx_stream_set_cont_clocks(ts, 0);
> }
Note that we only hw_free() if we preprared, but we enable in
hw_params().
> @@ -284,6 +295,8 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
> if (ret)
> dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
>
> + aiu->i2s.iface.mclk_rate = freq;
> +
> return ret;
> }
This means we store the new rate even if the set above failed.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v3 0/8] unwind, arm64: add sframe unwinder for kernel
From: Jens Remus @ 2026-04-14 16:10 UTC (permalink / raw)
To: Dylan Hatch, Roman Gushchin, Weinan Liu, Will Deacon,
Josh Poimboeuf, Indu Bhagat, Peter Zijlstra, Steven Rostedt,
Catalin Marinas, Jiri Kosina
Cc: Mark Rutland, Prasanna Kumar T S M, Puranjay Mohan, Song Liu,
joe.lawrence, linux-toolchains, linux-kernel, live-patching,
linux-arm-kernel
In-Reply-To: <20260406185000.1378082-1-dylanbhatch@google.com>
On 4/6/2026 8:49 PM, Dylan Hatch wrote:
> Dylan Hatch (7):
> sframe: Allow kernelspace sframe sections.
> arm64, unwind: build kernel with sframe V3 info
> sframe: Provide PC lookup for vmlinux .sframe section.
> sframe: Allow unsorted FDEs.
> arm64/module, sframe: Add sframe support for modules.
> sframe: Introduce in-kernel SFRAME_VALIDATION.
> unwind: arm64: Use sframe to unwind interrupt frames.
Nit: Trailing dot in commit subjects seems unusual. Remove?
> Weinan Liu (1):
> arm64: entry: add unwind info for various kernel entries
Regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
jremus@de.ibm.com / jremus@linux.ibm.com
IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/
^ permalink raw reply
* [PATCH] KVM: arm64: pkvm: Adopt MARKER() to define host hypercall ranges
From: Marc Zyngier @ 2026-04-14 16:05 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Will Deacon, Vincent Donnefort, Fuad Tabba, Joey Gouly,
Suzuki K Poulose, Oliver Upton, Zenghui Yu
The EL2 code defines ranges of host hypercalls that are either
enabled at boot-time only, used by [nh]VHE KVM, or reserved to pKVM.
The way these ranges are delineated is error prone, as the enum symbols
defining the limits are expressed in terms of actual function symbols.
This means that should a new function be added, special care must be
taken to also update the limit symbol.
Improve this by reusing the mechanism introduced for the vcpu_sysreg
enum, which uses a MARKER() macro and some extra trickery to make
the limit symbol standalone. Crucially, the limit symbol has the
same value as the *following* symbol.
The handle_host_hcall() function is then updated to make use of
the new limit definitions and get rid of the brittle default
upper limit. This allows for some more strict checks at build
time, and the removal of an comparison at run time.
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/include/asm/kvm_asm.h | 12 ++++++++++--
arch/arm64/include/asm/kvm_host.h | 3 ---
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 10 +++++-----
3 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 37414440cee7f..fa033be6141ad 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -50,6 +50,9 @@
#include <linux/mm.h>
+#define MARKER(m) \
+ m, __after_##m = m - 1
+
enum __kvm_host_smccc_func {
/* Hypercalls that are unavailable once pKVM has finalised. */
/* __KVM_HOST_SMCCC_FUNC___kvm_hyp_init */
@@ -59,8 +62,10 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs,
__KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs,
__KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
+
+ MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM),
+
__KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
- __KVM_HOST_SMCCC_FUNC_MIN_PKVM = __KVM_HOST_SMCCC_FUNC___pkvm_prot_finalize,
/* Hypercalls that are always available and common to [nh]VHE/pKVM. */
__KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
@@ -76,7 +81,8 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
- __KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM = __KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
+
+ MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY),
/* Hypercalls that are available only when pKVM has finalised. */
__KVM_HOST_SMCCC_FUNC___pkvm_host_share_hyp,
@@ -108,6 +114,8 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___tracing_reset,
__KVM_HOST_SMCCC_FUNC___tracing_enable_event,
__KVM_HOST_SMCCC_FUNC___tracing_write_event,
+
+ MARKER(__KVM_HOST_SMCCC_FUNC_MAX)
};
#define DECLARE_KVM_VHE_SYM(sym) extern char sym[]
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 851f6171751c0..44211e86f5ebd 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -450,9 +450,6 @@ struct kvm_vcpu_fault_info {
r = __VNCR_START__ + ((VNCR_ ## r) / 8), \
__after_##r = __MAX__(__before_##r - 1, r)
-#define MARKER(m) \
- m, __after_##m = m - 1
-
enum vcpu_sysreg {
__INVALID_SYSREG__, /* 0 is reserved as an invalid value */
MPIDR_EL1, /* MultiProcessor Affinity Register */
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 73f2e0221e703..9e44c05cf780e 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -748,9 +748,11 @@ static const hcall_t host_hcall[] = {
static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(unsigned long, id, host_ctxt, 0);
- unsigned long hcall_min = 0, hcall_max = -1;
+ unsigned long hcall_min = 0, hcall_max = __KVM_HOST_SMCCC_FUNC_MAX;
hcall_t hfn;
+ BUILD_BUG_ON(ARRAY_SIZE(host_hcall) != __KVM_HOST_SMCCC_FUNC_MAX);
+
/*
* If pKVM has been initialised then reject any calls to the
* early "privileged" hypercalls. Note that we cannot reject
@@ -763,16 +765,14 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
if (static_branch_unlikely(&kvm_protected_mode_initialized)) {
hcall_min = __KVM_HOST_SMCCC_FUNC_MIN_PKVM;
} else {
- hcall_max = __KVM_HOST_SMCCC_FUNC_MAX_NO_PKVM;
+ hcall_max = __KVM_HOST_SMCCC_FUNC_PKVM_ONLY;
}
id &= ~ARM_SMCCC_CALL_HINTS;
id -= KVM_HOST_SMCCC_ID(0);
- if (unlikely(id < hcall_min || id > hcall_max ||
- id >= ARRAY_SIZE(host_hcall))) {
+ if (unlikely(id < hcall_min || id >= hcall_max))
goto inval;
- }
hfn = host_hcall[id];
if (unlikely(!hfn))
--
2.47.3
^ permalink raw reply related
* Re: [PATCH v4 2/9] coresight: etm4x: exclude ss_status from drvdata->config
From: Leo Yan @ 2026-04-14 16:04 UTC (permalink / raw)
To: Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, suzuki.poulose,
mike.leach, james.clark, alexander.shishkin, jie.gan
In-Reply-To: <20260413142003.3549310-3-yeoreum.yun@arm.com>
On Mon, Apr 13, 2026 at 03:19:55PM +0100, Yeoreum Yun wrote:
> The purpose of TRCSSCSRn register is to show status of
> the corresponding Single-shot Comparator Control and input supports.
> That means writable field's purpose for reset or restore from idle status
> not for configuration.
>
> Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
> This includes remove TRCSSCRn from configurable item and
> remove saving in etm4_disable_hw().
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> .../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
> .../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
> .../coresight/coresight-etm4x-sysfs.c | 7 ++-----
> drivers/hwtracing/coresight/coresight-etm4x.h | 4 +++-
> 4 files changed, 10 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index c302072b293a..d14d7c8a23e5 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
> off_mask = (offset & GENMASK(11, 5));
> do {
> CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
> - CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
> CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
> } while (0);
> } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 6443f3717b37..8ebfd3924143 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
> const struct etmv4_caps *caps = &drvdata->caps;
>
> return (n < caps->nr_ss_cmp) && caps->nr_pe &&
> - (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
> + (caps->ss_status[n] & TRCSSCSRn_PC);
Nitpick: The naming 'ss_status' is a bit confused for capability.
Could we rename 'ss_status' to 'ss_comparator' or a simple one
'ss_cmp' ?
> }
>
> u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
> @@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
>
> for (i = 0; i < caps->nr_ss_cmp; i++) {
> - /* always clear status bit on restart if using single-shot */
> - if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
> - config->ss_status[i] &= ~TRCSSCSRn_STATUS;
> etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
> - etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
> + /* always clear status and pending bits on restart if using single-shot */
> + etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
It is a bit weird to use caps to write a register. A smooth way is to
clear STATUS and PENDING bits based on the read back value:
val = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
val &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
etm4x_relaxed_write32(csa, val, TRCSSCSRn(i));
> if (etm4x_sspcicrn_present(drvdata, i))
> etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
> }
> @@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
>
> etm4_disable_trace_unit(drvdata);
>
> - /* read the status of the single shot comparators */
> - for (i = 0; i < caps->nr_ss_cmp; i++) {
> - config->ss_status[i] =
> - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> - }
> -
> /* read back the current counter values */
> for (i = 0; i < caps->nr_cntr; i++) {
> config->cntr_val[i] =
> @@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
> */
> caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
> for (i = 0; i < caps->nr_ss_cmp; i++) {
> - drvdata->config.ss_status[i] =
> - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> + caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
> + caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
For init cap, we can use explict way:
caps->ss_cmp &= (TRCSSCSRn_PC | TRCSSCSRn_DV |
TRCSSCSRn_DA | TRCSSCSRn_INST);
> }
> /* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
> caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> index 50408215d1ac..dd62f01674cf 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
> @@ -1827,8 +1827,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
> raw_spin_lock(&drvdata->spinlock);
> idx = config->ss_idx;
> config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
> - /* must clear bit 31 in related status register on programming */
> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> raw_spin_unlock(&drvdata->spinlock);
> return size;
> }
> @@ -1839,10 +1837,11 @@ static ssize_t sshot_status_show(struct device *dev,
> {
> unsigned long val;
> struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
> + const struct etmv4_caps *caps = &drvdata->caps;
> struct etmv4_config *config = &drvdata->config;
>
> raw_spin_lock(&drvdata->spinlock);
> - val = config->ss_status[config->ss_idx];
> + val = caps->ss_status[config->ss_idx];
I think cap->ss_cmp is a good refactoring, but for legacy reason, I am
just wandering if we still need config->ss_status so that it can record
the lastest status (mainly for STATUS bit and PENDING bit).
Otherwise, this Sysfs interface can only provide capability rather
than status value.
Thanks,
Leo
> raw_spin_unlock(&drvdata->spinlock);
> return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
> }
> @@ -1877,8 +1876,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
> raw_spin_lock(&drvdata->spinlock);
> idx = config->ss_idx;
> config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
> - /* must clear bit 31 in related status register on programming */
> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
> raw_spin_unlock(&drvdata->spinlock);
> return size;
> }
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 8168676f2945..8864cfb76bad 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -213,6 +213,7 @@
> #define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
>
> #define TRCSSCSRn_STATUS BIT(31)
> +#define TRCSSCSRn_PENDING BIT(30)
> #define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
>
> #define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
> @@ -861,6 +862,7 @@ enum etm_impdef_type {
> * @lpoverride: If the implementation can support low-power state over.
> * @skip_power_up: Indicates if an implementation can skip powering up
> * the trace unit.
> + * @ss_status: The status of the corresponding single-shot comparator.
> */
> struct etmv4_caps {
> u8 nr_pe;
> @@ -899,6 +901,7 @@ struct etmv4_caps {
> bool atbtrig : 1;
> bool lpoverride : 1;
> bool skip_power_up : 1;
> + u32 ss_status[ETM_MAX_SS_CMP];
> };
>
> /**
> @@ -977,7 +980,6 @@ struct etmv4_config {
> u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
> u8 ss_idx;
> u32 ss_ctrl[ETM_MAX_SS_CMP];
> - u32 ss_status[ETM_MAX_SS_CMP];
> u32 ss_pe_cmp[ETM_MAX_SS_CMP];
> u8 addr_idx;
> u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
^ permalink raw reply
* Re: [PATCH RFC bpf-next 1/8] kasan: expose generic kasan helpers
From: Alexei Starovoitov @ 2026-04-14 15:58 UTC (permalink / raw)
To: Andrey Konovalov
Cc: Alexis Lothoré, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman,
Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, David S. Miller, David Ahern, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, X86 ML, H. Peter Anvin,
Shuah Khan, Maxime Coquelin, Alexandre Torgue, Andrey Ryabinin,
Alexander Potapenko, Dmitry Vyukov, Vincenzo Frascino,
Andrew Morton, ebpf, Bastien Curutchet, Thomas Petazzoni,
Xu Kuohai, bpf, LKML, Network Development,
open list:KERNEL SELFTEST FRAMEWORK, linux-stm32,
linux-arm-kernel, kasan-dev, linux-mm
In-Reply-To: <CA+fCnZd31GzdpEqR8VhfK4JtUKyyRMgbBoAbeGACJgm7WvB6Vw@mail.gmail.com>
On Tue, Apr 14, 2026 at 8:10 AM Andrey Konovalov <andreyknvl@gmail.com> wrote:
>
> On Tue, Apr 14, 2026 at 4:36 PM Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > > ACK, I'll try to use those kasan_check_read and kasan_check_write rather
> > > than __asan_{load,store}X.
> >
> > No. The performance penalty will be too high.
>
> With using __asan_load/storeX(), it will be one function call to get
> to check_region_inline(): __asan_load/storeX->check_region_inline.
>
> With kasan_check_read/write(), right now, it would be two function
> calls: __kasan_check_read->kasan_check_range->check_region_inline.
>
> I doubt an extra function call would make a difference in terms of
> performance: the shadow checking itself is also expensive.
>
> But if the second call is a concern, we can move kasan_check_range()
> and lower-level functions into mm/kasan/generic.h and include it into
> shadow.c, and then it will be just one function call.
>
> To improve performance further, the JIT compiler could emit inlined
> shadow checking instructions, same as the C compiler does with
> KASAN_INLINE=y.
>
> > hw_tags won't work without corresponding JIT work.
>
> You probably meant SW_TAGS here.
>
> HW_TAGS will likely just work without any JIT changes (even the
> kasan_check_byte() thing I mentioned should not be required), assuming
> JIT'ed BPF code just accesses kernel-returned pointers as is.
>
> > I see no point sacrificing performance for aesthetics.
>
> With the change I suggested above, there would be no performance
> difference. And the code stays cleaner.
>
> > __asan_load/storeX is what compilers emit.
>
> For Generic mode. For SW_TAGS, the function names are different.
> Keeping this detail within the KASAN code is cleaner.
I think we're talking past each other.
We're not interested in KASAN_SW_TAGS or KASAN_HW_TAGS.
We're not going to modify arm64 JIT at all.
This is purely KASAN_GENRIC and only on x86-64.
JIT will emit exactly what compilers emit for generic
which is __asan_load/store. This is as stable ABI as it can get
and we don't want to deviate from it.
The goal here is to find bugs in the verifier.
If something got past it, that shouldn't have,
kasan generic on x86-64 is enough.
^ permalink raw reply
* RE: [PATCH 06/11] Drivers: hv: Make sint vector architecture neutral in MSHV_VTL
From: Michael Kelley @ 2026-04-14 15:34 UTC (permalink / raw)
To: Naman Jain, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Catalin Marinas, Will Deacon,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, H . Peter Anvin, Arnd Bergmann, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Cc: Marc Zyngier, Timothy Hayes, Lorenzo Pieralisi, mrigendrachaubey,
ssengar@linux.microsoft.com, linux-hyperv@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-riscv@lists.infradead.org
In-Reply-To: <3264b2e6-f6fb-41b1-97da-22b5249c1839@linux.microsoft.com>
From: Naman Jain <namjain@linux.microsoft.com> Sent: Monday, April 13, 2026 9:52 AM
> >>>
> >>> Sashiko AI raised an interesting question about the startup timing --
> >>> whether the vmbus_platform_driver_probe() is guaranteed to have
> >>> set vmbus_interrupt before the VTL functions below run and use it.
> >>> What causes the mshv_vtl.ko module to be loaded, and hence run
> >>> mshv_vtl_init()?
> >>
> >> There is no race condition here. The init ordering guarantees that
> >> vmbus_interrupt is always set before mshv_vtl_synic_enable_regs()
> >> reads it.
> >>
> >> The call chain for setting vmbus_interrupt:
> >>
> >> subsys_initcall(hv_acpi_init) [level 4]
> >> -> platform_driver_register(&vmbus_platform_driver) and so on.
> >>
> >>
> >> The call chain for reading vmbus_interrupt:
> >>
> >> module_init(mshv_vtl_init) [level 6]
> >> -> hv_vtl_setup_synic()
> >> -> cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, ..., mshv_vtl_alloc_context, ...)
> >> -> mshv_vtl_alloc_context()
> >> -> mshv_vtl_synic_enable_regs()
> >> -> sint.vector = vmbus_interrupt
> >>
> >> do_initcalls() processes sections in order 0 through 7, so
> >> hv_acpi_init() (level 4) is guaranteed to complete before
> >> mshv_vtl_init() (level 6) runs.
> >>
> >
> > I think the situation is more complex than what you describe, depending
> > on whether the VMBus driver and/or MSHV_VTL are built as modules vs.
> > being built-in to the kernel image. In include/linux/module.h, see the
> > comment for module_init() and how subsys_initcall() is mapped
> > to module_init() when built as a module.
> >
> > If both are built-in, then what you describe is correct. But if either or
> > both are modules, then the respective init functions (hv_acpi_init
> > and mshv_vtl_init) get called at the time the module is loaded, and
> > not by do_initcalls(). I think hv_vmbus.ko gets loaded when an attempt
> > is first made to access a disk, but I would need to look more closely to
> > be sure. I don't have any understanding of what causes mshv_vtl.ko
> > to be loaded. And what is the ordering if MSHV_VTL is built-in while
> > VMBus is built as a module, or vice versa?
> >
> > Michael
> >
>
> Based on this, I still feel that this race is not possible.
>
> hv_vmbus mshv_vtl
> y y -> different initcall levels, no issues
> y m -> use without initialization is not possible
> m y -> config dependencies take care of this, and mshv_vtl
> is forced to compile as a module in this case.
> m m -> config and symbol dependencies should take care of
> it. mshv_vtl has symbol and config dependencies on hv_vmbus, and it
> won't allow loading mshv_vtl if hv_vmbus module is not loaded.
>
> Relevant code here: kernel/module/main.c
>
Makes sense. I'm convinced! :-)
Michael
^ permalink raw reply
* [PATCH v22 5/7] remoteproc: Add TEE support
From: Arnaud Pouliquen @ 2026-04-14 15:29 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
Add a remoteproc TEE (Trusted Execution Environment) driver that will be
probed by the TEE bus. If the associated Trusted application is supported
on the secure part, this driver offers a client interface to load firmware
by the secure part.
This firmware could be authenticated by the secure trusted application.
A specificity of the implementation is that the firmware has to be
authenticated and optionally decrypted to access the resource table.
Consequently, the boot sequence is:
1) rproc_parse_fw --> rproc_tee_parse_fw
remoteproc TEE:
- Requests the TEE application to authenticate and load the firmware
in the remote processor memories.
- Requests the TEE application for the address of the resource table.
- Creates a copy of the resource table stored in rproc->cached_table.
2) rproc_load_segments --> rproc_tee_load_fw
remoteproc TEE:
- Requests the TEE application to load the firmware. Nothing is done
at the TEE application as the firmware is already loaded.
- In case of recovery, the TEE application has to reload the firmware.
3) rproc_tee_get_loaded_rsc_table
remoteproc TEE requests the TEE application for the address of the
resource table.
4) rproc_start --> rproc_tee_start
- Requests the TEE application to start the remote processor.
The shutdown sequence is:
5) rproc_stop --> rproc_tee_stop
- Requests the TEE application to stop the remote processor.
6) rproc_tee_release_fw
This function is used to request the TEE application to perform actions
to return to the initial state on stop or on error during the boot
sequence.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
Version 22 updates:
- Revert to version 19, as the st,stm32-rproc-tee compatible has been
rejected. As a consequence, we cannot have a rproc_stm32-tee.c driver
and must reuse the rproc_stm32.c driver.
- Protect rproc_to_trproc() with lockdep_assert_held().
Version 21 updates:
- introduce uuid_to_str() to compute the compatible from the TEE UUID
- update rproc_tee_register() to provide phandle referenced in the
remoteproc driver client.
- use device_link_add() to link the remoteproc driver client.
Version 20 updates:
- rework probe. the remoteproc-tee now probe the remoteproc devices
defined in device tree as child.
- creation of rproc-service-80a4c275-0a47-4905-8285-1486a9771a08 compatible
- use of of_find_compatible_node() to find node in DT
- use of of_platform_populate() to probe remoteproc devices
- remove device_link_add() as now managed by of_platform_populate)
- add "auto_boot" parameter in rproc_tee_register()
- rename TA_RPROC_FW_CMD_* TEE CMD in TA_RPROC_CMD_* command
- use of DEFINE_MUTEX
Version 19 updates:
- rework/fix function headers
- use memremap instead of ioremap for the resource table.
- realign comments to 80 chars limit, with few exceptions for readability
- replace spinlock by mutex and and protect APIs from concurrent access
- add support of 64-bit address in rproc_tee_get_loaded_rsc_table()
- update copyright year
Version 18 updates
Fix warning:
warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
---
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/remoteproc_tee.c | 789 ++++++++++++++++++++++++++++
include/linux/remoteproc_tee.h | 98 ++++
4 files changed, 898 insertions(+)
create mode 100644 drivers/remoteproc/remoteproc_tee.c
create mode 100644 include/linux/remoteproc_tee.h
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index ee54436fea5a..87d69f200590 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -23,6 +23,16 @@ config REMOTEPROC_CDEV
It's safe to say N if you don't want to use this interface.
+config REMOTEPROC_TEE
+ bool "Remoteproc support by a TEE application"
+ depends on OPTEE
+ help
+ Support a remote processor that is managed by an application running in a Trusted
+ Execution Environment (TEE). This application is responsible for loading the remote
+ processor firmware image and managing its lifecycle.
+
+ It's safe to say N if the remote processor is not managed by a TEE.
+
config IMX_REMOTEPROC
tristate "i.MX remoteproc support"
depends on ARCH_MXC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 1c7598b8475d..a1a5201982d4 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -11,6 +11,7 @@ remoteproc-y += remoteproc_sysfs.o
remoteproc-y += remoteproc_virtio.o
remoteproc-y += remoteproc_elf_loader.o
obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o
+obj-$(CONFIG_REMOTEPROC_TEE) += remoteproc_tee.o
obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
obj-$(CONFIG_IMX_DSP_REMOTEPROC) += imx_dsp_rproc.o
obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o
diff --git a/drivers/remoteproc/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
new file mode 100644
index 000000000000..b4e01ad84010
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_tee.c
@@ -0,0 +1,789 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) STMicroelectronics 2025
+ * Author: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/mutex.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+
+#include "remoteproc_internal.h"
+
+#define MAX_TEE_PARAM_ARRAY_MEMBER 4
+
+/*
+ * Authentication and load of the firmware image in the remote processor
+ * memories by the TEE. After this step the firmware is installed in destination
+ * memories, which can then be locked to prevent access by Linux.
+ *
+ * [in] params[0].value.a: remote processor identifier
+ * [in] params[1].memref: buffer containing a temporary copy of the signed
+ * image to load.
+ */
+#define TA_RPROC_CMD_LOAD_FW 1
+
+/*
+ * Start the remote processor by the TEE
+ *
+ * [in] params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_START 2
+
+/*
+ * Stop the remote processor by the TEE
+ *
+ * [in] params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_STOP 3
+
+/*
+ * Return the address of the resource table, or 0 if not found.
+ *
+ * [in] params[0].value.a: remote processor identifier
+ * [out] params[1].value.a: 32bit LSB resource table memory address
+ * [out] params[1].value.b: 32bit MSB resource table memory address
+ * [out] params[2].value.a: 32bit LSB resource table memory size
+ * [out] params[2].value.b: 32bit MSB resource table memory size
+ */
+#define TA_RPROC_CMD_GET_RSC_TABLE 4
+
+/*
+ * Release remote processor firmware images and associated resources.
+ * This command should be used in case an error occurs between the loading of
+ * the firmware images (TA_RPROC_CMD_LOAD_FW) and the starting of the remote
+ * processor (TA_RPROC_CMD_START) or after stopping the remote processor
+ * to release associated resources (TA_RPROC_CMD_STOP).
+ *
+ * [in] params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_RELEASE_FW 6
+
+/**
+ * struct rproc_tee_context - Global TEE backend context
+ * @rproc_list: List of registered TEE-backed remoteprocs
+ * @tee_ctx: TEE context handle
+ * @dev: TEE client device
+ */
+struct rproc_tee_context {
+ struct list_head rproc_list;
+ struct tee_context *tee_ctx;
+ struct device *dev;
+};
+
+/**
+ * struct rproc_tee - TEE remoteproc structure
+ * @node: Reference in global list
+ * @rproc: Remoteproc reference
+ * @rproc_id: remote processor identifier
+ * @session_id: TEE session identifier
+ */
+struct rproc_tee {
+ struct list_head node;
+ struct rproc *rproc;
+ u32 rproc_id;
+ u32 session_id;
+};
+
+static struct rproc_tee_context rproc_tee_ctx;
+static DEFINE_MUTEX(ctx_lock); /* Protects concurrent manipulations of the rproc_tee_ctx*/
+
+static struct rproc_tee *rproc_to_trproc(struct rproc *rproc)
+{
+ struct rproc_tee *trproc;
+
+ lockdep_assert_held(&ctx_lock);
+
+ list_for_each_entry(trproc, &rproc_tee_ctx.rproc_list, node) {
+ if (trproc->rproc == rproc)
+ return trproc;
+ }
+
+ return NULL;
+}
+
+static void rproc_tee_prepare_args(struct rproc_tee *trproc, int cmd,
+ struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param,
+ unsigned int num_params)
+{
+ memset(arg, 0, sizeof(*arg));
+ memset(param, 0, MAX_TEE_PARAM_ARRAY_MEMBER * sizeof(*param));
+
+ arg->func = cmd;
+ arg->session = trproc->session_id;
+ arg->num_params = num_params + 1;
+
+ param[0] = (struct tee_param) {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = trproc->rproc_id,
+ };
+}
+
+static int rproc_tee_sanity_check(struct device_node *tee_np)
+{
+ /* Backend not probed yet */
+ if (!rproc_tee_ctx.dev || !rproc_tee_ctx.dev->of_node)
+ return -EPROBE_DEFER;
+
+ /* DT error: phandle points to different node than the backend we use */
+ if (tee_np != rproc_tee_ctx.dev->of_node)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * rproc_tee_release_fw() - Release the firmware for a TEE-based remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_RELEASE_FW TEE client function to
+ * release the firmware. It should only be called when the remoteproc state is
+ * RPROC_OFFLINE or RPROC_DETACHED. The function requests the TEE remoteproc
+ * application to release the firmware loaded by rproc_tee_load_fw().
+ * The request is ignored if the rproc state is RPROC_DETACHED as the remote
+ * processor is still running.
+ */
+void rproc_tee_release_fw(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return;
+
+ if (!rproc_tee_ctx.dev)
+ goto out;
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc)
+ goto out;
+
+ /*
+ * If the remote processor state is RPROC_DETACHED, just ignore the
+ * request, as the remote processor is still running.
+ */
+ if (rproc->state == RPROC_DETACHED)
+ goto out;
+
+ if (rproc->state != RPROC_OFFLINE) {
+ dev_err(rproc_tee_ctx.dev, "unexpected rproc state: %d\n", rproc->state);
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_RELEASE_FW, &arg, param, 0);
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_RELEASE_FW invoke failed TEE err: %#x, ret:%d\n",
+ arg.ret, ret);
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+}
+EXPORT_SYMBOL_GPL(rproc_tee_release_fw);
+
+/**
+ * rproc_tee_load_fw() - Load firmware from TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function invokes the TA_RPROC_CMD_LOAD_FW TEE client function to load
+ * the firmware. It registers the fw->data as a shared memory region with the
+ * TEE, and request the TEE to load the firmware. This function can be called
+ * twice during the remote processor boot, a first by rproc_tee_parse_fw() to
+ * parse the resource table , and a second time by rproc_tee_load_fw().
+ * The TEE application should ignores the command if the firmware
+ * is already loaded by rproc_tee_parse_fw().
+ *
+ * Return: 0 on success, or an error code on failure
+ */
+int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_shm *fw_shm;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fw_shm = tee_shm_register_kernel_buf(rproc_tee_ctx.tee_ctx, (void *)fw->data, fw->size);
+ if (IS_ERR(fw_shm)) {
+ ret = PTR_ERR(fw_shm);
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_LOAD_FW, &arg, param, 1);
+
+ /* Provide the address of the firmware image */
+ param[1] = (struct tee_param) {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+ .u.memref = {
+ .shm = fw_shm,
+ .size = fw->size,
+ .shm_offs = 0,
+ },
+ };
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_LOAD_FW invoke failed TEE err: %#x, ret:%d\n",
+ arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+
+ tee_shm_free(fw_shm);
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_load_fw);
+
+static int rproc_tee_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
+ size_t *table_sz)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_GET_RSC_TABLE, &arg, param, 2);
+
+ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+ param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_GET_RSC_TABLE invoke failed TEE err: %#x, ret:%d\n",
+ arg.ret, ret);
+ ret = -EIO;
+ goto out;
+ }
+
+ *table_sz = param[2].u.value.a;
+ if (sizeof(phys_addr_t) == sizeof(u64))
+ *table_sz |= param[2].u.value.b << 32;
+
+ if (*table_sz) {
+ *rsc_pa = param[1].u.value.a;
+ if (sizeof(phys_addr_t) == sizeof(u64))
+ *rsc_pa |= param[1].u.value.b << 32;
+ } else {
+ *rsc_pa = 0;
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+
+/**
+ * rproc_tee_parse_fw() - Get the resource table from TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function retrieves the loaded resource table and creates a cached_table
+ * copy. Since the firmware image is signed and potentially encrypted, the
+ * firmware must be loaded first to access the loaded resource table.
+ *
+ * Return: 0 on success, or an error code on failure
+ */
+int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ phys_addr_t rsc_table;
+ void *rsc_va;
+ size_t table_sz;
+ int ret;
+
+ if (!rproc)
+ return -EINVAL;
+
+ /* We need first to Load the firmware, to be able to get the resource table. */
+ ret = rproc_tee_load_fw(rproc, fw);
+ if (ret)
+ return ret;
+
+ ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+ if (ret)
+ goto release_fw;
+
+ /* A missing resource table is valid for some firmware images. */
+ if (!table_sz) {
+ rproc->table_ptr = NULL;
+ rproc->table_sz = 0;
+ return 0;
+ }
+
+ /*
+ * We assume here that the memory mapping is the same between the TEE
+ * and Linux kernel contexts. Else a new TEE remoteproc service could be
+ * needed to get a copy of the resource table.
+ */
+ rsc_va = memremap(rsc_table, table_sz, MEMREMAP_WC);
+ if (!rsc_va) {
+ dev_err(rproc_tee_ctx.dev, "Unable to map memory region: %pa+%zx\n",
+ &rsc_table, table_sz);
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ /*
+ * Create a copy of the resource table to have the same behavior as the
+ * ELF loader. This cached table will be used by the remoteproc core
+ * after the remoteproc stops to free resources and for crash recovery
+ * to reapply the settings.
+ * The cached table will be freed by the remoteproc core.
+ */
+ rproc->cached_table = kmemdup(rsc_va, table_sz, GFP_KERNEL);
+ memunmap(rsc_va);
+
+ if (!rproc->cached_table) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ rproc->table_ptr = rproc->cached_table;
+ rproc->table_sz = table_sz;
+
+ return 0;
+
+release_fw:
+ rproc_tee_release_fw(rproc);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_parse_fw);
+
+/**
+ * rproc_tee_find_loaded_rsc_table() - Find the loaded resource table loaded by
+ * the TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function retrieves the physical address and size of the resource table
+ * loaded by the TEE application.
+ *
+ * Return: pointer to the resource table if found, or NULL if not found or size
+ * is 0
+ */
+struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
+ const struct firmware *fw)
+{
+ phys_addr_t rsc_table;
+ size_t table_sz;
+ int ret;
+
+ ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+ if (ret)
+ return NULL;
+
+ rproc->table_sz = table_sz;
+ if (!table_sz)
+ return NULL;
+
+ /*
+ * At this step the memory area that contains the resource table should
+ * have been registered by the remote proc platform driver and allocated
+ * by rproc_alloc_registered_carveouts().
+ */
+ return rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
+}
+EXPORT_SYMBOL_GPL(rproc_tee_find_loaded_rsc_table);
+
+/**
+ * rproc_tee_start() - Request the TEE application to start the remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_START command to start the remote
+ * processor.
+ *
+ * Return: Returns 0 on success, -EINVAL or -EIO on failure
+ */
+int rproc_tee_start(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_START, &arg, param, 0);
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_START invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_start);
+
+/**
+ * rproc_tee_stop() - Request the TEE application to start the remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_STOP command to stop the remote
+ * processor.
+ *
+ * Return: Returns 0 on success, -EINVAL or -EIO on failure
+ */
+int rproc_tee_stop(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_STOP, &arg, param, 0);
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_STOP invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_stop);
+
+/**
+ * rproc_tee_register() - Register a remote processor controlled by the TEE application
+ * @dev: client rproc device
+ * @rproc: out pointer to the struct rproc representing the remote processor
+ * @tee_phandle: backend phandle args (np + 1 cell: rproc_id)
+ *
+ * The phandle must point to the same DT node that rproc_tee_probe() attached
+ * to the TEE client device.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int rproc_tee_register(struct device *dev, struct rproc *rproc,
+ const struct of_phandle_args *tee_phandle)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ unsigned int rproc_id;
+ struct device_node *tee_np;
+ struct tee_ioctl_open_session_arg sess_arg;
+ struct tee_client_device *tee_device;
+ struct device_link *link;
+ struct rproc_tee *trproc;
+ int ret;
+
+ if (!tee_phandle || !tee_phandle->np || tee_phandle->args_count < 1)
+ return -EINVAL;
+
+ rproc_id = tee_phandle->args[0];
+ tee_np = tee_phandle->np;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ ret = rproc_tee_sanity_check(tee_np);
+ if (ret)
+ goto out;
+
+ trproc = kzalloc_obj(*trproc);
+ if (!trproc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ tee_device = to_tee_client_device(rproc_tee_ctx.dev);
+ memset(&sess_arg, 0, sizeof(sess_arg));
+ memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
+
+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+ sess_arg.num_params = 1;
+
+ param[0] = (struct tee_param) {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = rproc_id,
+ };
+
+ ret = tee_client_open_session(rproc_tee_ctx.tee_ctx, &sess_arg, param);
+ if (ret < 0 || sess_arg.ret != 0) {
+ dev_err(dev, "tee_client_open_session failed, err: %#x\n",
+ sess_arg.ret);
+ ret = -EINVAL;
+ goto free_trproc;
+ }
+
+ trproc->rproc_id = rproc_id;
+ trproc->session_id = sess_arg.session;
+
+ ret = rproc_add(rproc);
+ if (ret)
+ goto close_tee;
+
+ trproc->rproc = rproc;
+ /* Create device link between the rproc device and the TEE device */
+ link = device_link_add(dev, rproc_tee_ctx.dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!link) {
+ ret = -ENOMEM;
+ goto del_rproc;
+ }
+
+ list_add_rcu(&trproc->node, &rproc_tee_ctx.rproc_list);
+
+ mutex_unlock(&ctx_lock);
+
+ return 0;
+
+del_rproc:
+ rproc_del(rproc);
+close_tee:
+ if (tee_client_close_session(rproc_tee_ctx.tee_ctx, trproc->session_id))
+ dev_err(rproc_tee_ctx.dev,
+ "tee_client_close_session failed\n");
+free_trproc:
+ kfree(trproc);
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_register);
+
+/**
+ * rproc_tee_unregister - Unregister a remote processor controlled by the TEE
+ * application.
+ * @dev: Pointer to client rproc device
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function unregisters a remote processor previously registered by the
+ * rproc_tee_register() function.
+ *
+ * Return: Returns 0 on success, or an error code on failure
+ */
+int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
+{
+ struct rproc_tee *trproc;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ /*
+ * Unlock ctx_lock before calling rproc_del(),
+ * they may call into rproc core and take other locks to stop the
+ * remote processor, if it is running.
+ */
+ mutex_unlock(&ctx_lock);
+
+ rproc_del(rproc);
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ ret = tee_client_close_session(rproc_tee_ctx.tee_ctx,
+ trproc->session_id);
+ if (ret < 0)
+ dev_err(rproc_tee_ctx.dev,
+ "tee_client_close_session failed, err: %#x\n", ret);
+
+ list_del(&trproc->node);
+ kfree(trproc);
+
+out_unlock:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_unregister);
+
+static int rproc_tee_ctx_match(struct tee_ioctl_version_data *ver,
+ const void *data)
+{
+ /* Today we support only OP-TEE; could be extended to other TEEs */
+ return ver->impl_id == TEE_IMPL_ID_OPTEE;
+}
+
+static const struct tee_client_device_id rproc_tee_id_table[] = {
+ {UUID_INIT(0x80a4c275, 0x0a47, 0x4905, 0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(tee, rproc_tee_id_table);
+
+static void uuid_to_str(const struct tee_client_device_id *id, char *uuid_str)
+{
+ snprintf(uuid_str, UUID_STRING_LEN + 1,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ id->uuid.b[0], id->uuid.b[1], id->uuid.b[2], id->uuid.b[3],
+ id->uuid.b[4], id->uuid.b[5], id->uuid.b[6], id->uuid.b[7],
+ id->uuid.b[8], id->uuid.b[9], id->uuid.b[10], id->uuid.b[11],
+ id->uuid.b[12], id->uuid.b[13], id->uuid.b[14], id->uuid.b[15]);
+}
+
+static int rproc_tee_probe(struct tee_client_device *tee_dev)
+{
+ struct device *dev = &tee_dev->dev;
+ struct tee_context *tee_ctx;
+ struct device_node *np;
+ char uuid_str[UUID_STRING_LEN + 1];
+ int ret;
+
+ uuid_to_str(&rproc_tee_id_table[0], uuid_str);
+ np = of_find_compatible_node(NULL, NULL, uuid_str);
+ if (!np) {
+ dev_err(dev, "Device node not found for UUID: %s\n", uuid_str);
+ return -ENODEV;
+ }
+
+ /* Open context with TEE driver */
+ tee_ctx = tee_client_open_context(NULL, rproc_tee_ctx_match, NULL, NULL);
+ if (IS_ERR(tee_ctx)) {
+ ret = PTR_ERR(tee_ctx);
+ goto put_node;
+ }
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ goto close_ctx;
+
+ INIT_LIST_HEAD(&rproc_tee_ctx.rproc_list);
+
+ ret = device_add_of_node(dev, np);
+
+ if (ret) {
+ mutex_unlock(&ctx_lock);
+ goto close_ctx;
+ }
+ rproc_tee_ctx.dev = dev;
+ rproc_tee_ctx.tee_ctx = tee_ctx;
+
+ mutex_unlock(&ctx_lock);
+ of_node_put(np);
+
+ return 0;
+
+close_ctx:
+ tee_client_close_context(tee_ctx);
+put_node:
+ of_node_put(np);
+ return ret;
+}
+
+static void rproc_tee_remove(struct tee_client_device *tee_dev)
+{
+ struct device *dev = &tee_dev->dev;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return;
+
+ rproc_tee_ctx.dev = NULL;
+ mutex_unlock(&ctx_lock);
+ device_remove_of_node(dev);
+
+ tee_client_close_context(rproc_tee_ctx.tee_ctx);
+ rproc_tee_ctx.tee_ctx = NULL;
+}
+
+static struct tee_client_driver rproc_tee_fw_driver = {
+ .id_table = rproc_tee_id_table,
+ .probe = rproc_tee_probe,
+ .remove = rproc_tee_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ },
+};
+
+module_tee_client_driver(rproc_tee_fw_driver);
+
+MODULE_DESCRIPTION("remote processor TEE module");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/remoteproc_tee.h b/include/linux/remoteproc_tee.h
new file mode 100644
index 000000000000..8cf805f3b65e
--- /dev/null
+++ b/include/linux/remoteproc_tee.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright(c) 2025 STMicroelectronics
+ */
+
+#ifndef REMOTEPROC_TEE_H
+#define REMOTEPROC_TEE_H
+
+#include <linux/tee_drv.h>
+#include <linux/firmware.h>
+#include <linux/remoteproc.h>
+
+#if IS_ENABLED(CONFIG_REMOTEPROC_TEE)
+
+int rproc_tee_register(struct device *dev, struct rproc *rproc,
+ const struct of_phandle_args *tee_phandle);
+int rproc_tee_unregister(struct device *dev, struct rproc *rproc);
+int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw);
+int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw);
+void rproc_tee_release_fw(struct rproc *rproc);
+struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
+ const struct firmware *fw);
+int rproc_tee_start(struct rproc *rproc);
+int rproc_tee_stop(struct rproc *rproc);
+int rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa, size_t size, u64 *da);
+#else
+
+static inline int rproc_tee_register(struct device *dev, struct rproc *rproc,
+ const struct of_phandle_args *tee_phandle)
+{
+ return -ENODEV;
+}
+
+static inline int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_start(struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_stop(struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa,
+ size_t size, u64 *da)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return -EINVAL;
+}
+
+static inline void rproc_tee_release_fw(struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+}
+
+static inline struct resource_table *
+rproc_tee_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return NULL;
+}
+#endif /* CONFIG_REMOTEPROC_TEE */
+#endif /* REMOTEPROC_TEE_H */
--
2.43.0
^ permalink raw reply related
* [PATCH v22 7/7] remoteproc: stm32: add OP-TEE backend support
From: Arnaud Pouliquen @ 2026-04-14 15:29 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
Integrate OP-TEE-controlled firmware loading into stm32_rproc
adding support for the st,rproc-tee devicetree property.
When st,rproc-tee is present, the driver:
- parses the backend phandle + ID from DT and validates it
- uses the remoteproc_tee operation set and registration path
- keeps reset/holdboot handling only for the non-TEE case
- uses a TEE-specific flow.
Notice that the attach/detach is not yet supported and should be part
of a separate patchset.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
V21 updates:
- reapply the V19 patch as the stm32_rproc-tee driver can no more
be used.
- update v19 patch to support the st,rproc-tee phandle.
- rework the commit message.
---
drivers/remoteproc/stm32_rproc.c | 167 +++++++++++++++++++++++--------
1 file changed, 123 insertions(+), 44 deletions(-)
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 4bcd6a784935..61d89f3a78b1 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -18,6 +18,7 @@
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -89,6 +90,7 @@ struct stm32_rproc {
struct stm32_rproc_mem *rmems;
struct stm32_mbox mb[MBOX_NB_MBX];
struct workqueue_struct *workqueue;
+ struct of_phandle_args tee_phandle;
bool hold_boot_smc;
void __iomem *rsc_va;
};
@@ -255,6 +257,19 @@ static int stm32_rproc_release(struct rproc *rproc)
return 0;
}
+static int stm32_rproc_tee_stop(struct rproc *rproc)
+{
+ int err;
+
+ stm32_rproc_request_shutdown(rproc);
+
+ err = rproc_tee_stop(rproc);
+ if (err)
+ return err;
+
+ return stm32_rproc_release(rproc);
+}
+
static int stm32_rproc_prepare(struct rproc *rproc)
{
struct device *dev = rproc->dev.parent;
@@ -683,6 +698,17 @@ static const struct rproc_ops st_rproc_ops = {
.get_boot_addr = rproc_elf_get_boot_addr,
};
+static const struct rproc_ops st_rproc_tee_ops = {
+ .prepare = stm32_rproc_prepare,
+ .start = rproc_tee_start,
+ .stop = stm32_rproc_tee_stop,
+ .kick = stm32_rproc_kick,
+ .load = rproc_tee_load_fw,
+ .parse_fw = rproc_tee_parse_fw,
+ .find_loaded_rsc_table = rproc_tee_find_loaded_rsc_table,
+ .release_fw = rproc_tee_release_fw,
+};
+
static const struct of_device_id stm32_rproc_match[] = {
{ .compatible = "st,stm32mp1-m4" },
{},
@@ -716,6 +742,7 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ struct of_phandle_args tee_phandle;
struct stm32_syscon tz;
unsigned int tzen;
int err, irq;
@@ -741,51 +768,69 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
dev_info(dev, "wdg irq registered\n");
}
- ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
- if (!ddata->rst) {
- /* Try legacy fallback method: get it by index */
- ddata->rst = devm_reset_control_get_by_index(dev, 0);
+ if (of_find_property(np, "st,rproc-tee", NULL)) {
+ err = of_parse_phandle_with_fixed_args(np, "st,rproc-tee",
+ 1, 0, &tee_phandle);
+ if (err)
+ return dev_err_probe(dev, err,
+ "failed to parse st,rproc-tee\n");
+
+ if (!IS_ENABLED(CONFIG_REMOTEPROC_TEE)) {
+ of_node_put(tee_phandle.np);
+ return dev_err_probe(dev, -ENODEV,
+ "st,rproc-tee requires REMOTEPROC_TEE support\n");
+ }
+
+ ddata->tee_phandle = tee_phandle;
}
- if (IS_ERR(ddata->rst))
- return dev_err_probe(dev, PTR_ERR(ddata->rst),
- "failed to get mcu_reset\n");
- /*
- * Three ways to manage the hold boot
- * - using SCMI: the hold boot is managed as a reset
- * The DT "reset-mames" property should be defined with 2 items:
- * reset-names = "mcu_rst", "hold_boot";
- * - using SMC call (deprecated): use SMC reset interface
- * The DT "reset-mames" property is optional, "st,syscfg-tz" is required
- * - default(no SCMI, no SMC): the hold boot is managed as a syscon register
- * The DT "reset-mames" property is optional, "st,syscfg-holdboot" is required
- */
+ if (!ddata->tee_phandle.np) {
+ ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
+ if (!ddata->rst) {
+ /* Try legacy fallback method: get it by index */
+ ddata->rst = devm_reset_control_get_by_index(dev, 0);
+ }
+ if (IS_ERR(ddata->rst))
+ return dev_err_probe(dev, PTR_ERR(ddata->rst),
+ "failed to get mcu_reset\n");
- ddata->hold_boot_rst = devm_reset_control_get_optional(dev, "hold_boot");
- if (IS_ERR(ddata->hold_boot_rst))
- return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst),
- "failed to get hold_boot reset\n");
+ /*
+ * Three ways to manage the hold boot
+ * - using SCMI: the hold boot is managed as a reset
+ * The DT "reset-mames" property should be defined with 2 items:
+ * reset-names = "mcu_rst", "hold_boot";
+ * - using SMC call (deprecated): use SMC reset interface
+ * The DT "reset-mames" property is optional, "st,syscfg-tz" is required
+ * - default(no SCMI, no SMC): the hold boot is managed as a syscon register
+ * The DT "reset-mames" property is optional, "st,syscfg-holdboot" is required
+ */
- if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) {
- /* Manage the MCU_BOOT using SMC call */
- err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
- if (!err) {
- err = regmap_read(tz.map, tz.reg, &tzen);
- if (err) {
- dev_err(dev, "failed to read tzen\n");
- return err;
+ ddata->hold_boot_rst = devm_reset_control_get_optional(dev, "hold_boot");
+ if (IS_ERR(ddata->hold_boot_rst))
+ return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst),
+ "failed to get hold_boot reset\n");
+
+ if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) {
+ /* Manage the MCU_BOOT using SMC call */
+ err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
+ if (!err) {
+ err = regmap_read(tz.map, tz.reg, &tzen);
+ if (err) {
+ dev_err(dev, "failed to read tzen\n");
+ return err;
+ }
+ ddata->hold_boot_smc = tzen & tz.mask;
}
- ddata->hold_boot_smc = tzen & tz.mask;
}
- }
- if (!ddata->hold_boot_rst && !ddata->hold_boot_smc) {
- /* Default: hold boot manage it through the syscon controller */
- err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
- &ddata->hold_boot);
- if (err) {
- dev_err(dev, "failed to get hold boot\n");
- return err;
+ if (!ddata->hold_boot_rst && !ddata->hold_boot_smc) {
+ /* Default: hold boot manage it through the syscon controller */
+ err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
+ &ddata->hold_boot);
+ if (err) {
+ dev_err(dev, "failed to get hold boot\n");
+ return err;
+ }
}
}
@@ -857,18 +902,31 @@ static int stm32_rproc_probe(struct platform_device *pdev)
if (ret < 0 && ret != -EINVAL)
return ret;
- rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, fw_name, sizeof(*ddata));
+ if (of_find_property(np, "st,rproc-tee", NULL))
+ rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, fw_name,
+ sizeof(*ddata));
+ else
+ rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, fw_name,
+ sizeof(*ddata));
+
if (!rproc)
return -ENOMEM;
ddata = rproc->priv;
-
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
ret = stm32_rproc_parse_dt(pdev, ddata, &rproc->auto_boot);
if (ret)
goto free_rproc;
+ if (ddata->tee_phandle.np &&
+ !of_device_is_available(ddata->tee_phandle.np)) {
+ of_node_put(ddata->tee_phandle.np);
+ ddata->tee_phandle.np = NULL;
+ ret = -EPROBE_DEFER;
+ goto free_rproc;
+ }
+
ret = stm32_rproc_of_memory_translations(pdev, ddata);
if (ret)
goto free_rproc;
@@ -877,8 +935,14 @@ static int stm32_rproc_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
- if (state == M4_STATE_CRUN)
+ if (state == M4_STATE_CRUN) {
+ if (ddata->tee_phandle.np) {
+ dev_err(dev, "TEE support not yet compatible with attached state\n");
+ ret = -EINVAL;
+ goto free_rproc;
+ }
rproc->state = RPROC_DETACHED;
+ }
rproc->has_iommu = false;
ddata->workqueue = create_workqueue(dev_name(dev));
@@ -894,10 +958,12 @@ static int stm32_rproc_probe(struct platform_device *pdev)
if (ret)
goto free_wkq;
- ret = rproc_add(rproc);
+ if (ddata->tee_phandle.np)
+ ret = rproc_tee_register(dev, rproc, &ddata->tee_phandle);
+ else
+ ret = rproc_add(rproc);
if (ret)
goto free_mb;
-
return 0;
free_mb:
@@ -911,6 +977,11 @@ static int stm32_rproc_probe(struct platform_device *pdev)
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
}
+ if (ddata->tee_phandle.np) {
+ of_node_put(ddata->tee_phandle.np);
+ ddata->tee_phandle.np = NULL;
+ }
+
return ret;
}
@@ -919,11 +990,11 @@ static void stm32_rproc_remove(struct platform_device *pdev)
struct rproc *rproc = platform_get_drvdata(pdev);
struct stm32_rproc *ddata = rproc->priv;
struct device *dev = &pdev->dev;
+ struct device_node *tee_np = ddata->tee_phandle.np;
if (atomic_read(&rproc->power) > 0)
rproc_shutdown(rproc);
- rproc_del(rproc);
stm32_rproc_free_mbox(rproc);
destroy_workqueue(ddata->workqueue);
@@ -931,6 +1002,14 @@ static void stm32_rproc_remove(struct platform_device *pdev)
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
}
+
+ if (tee_np) {
+ ddata->tee_phandle.np = NULL;
+ rproc_tee_unregister(dev, rproc);
+ of_node_put(tee_np);
+ } else {
+ rproc_del(rproc);
+ }
}
static int stm32_rproc_suspend(struct device *dev)
--
2.43.0
^ permalink raw reply related
* [PATCH v22 1/7] dt-bindings: firmware: Add TEE remoteproc service binding
From: Arnaud Pouliquen @ 2026-04-14 15:28 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
Add a device tree binding for the TEE-based remote processor control
service implemented as an OP-TEE Trusted Application identified by
UUID 80a4c275-0a47-4905-8285-1486a9771a08.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
v21 updates:
- rename compatible to exactly match with the TEE UUID
- the remoteproc device driver is no more declared as a child,
but use phandle as done for the SCMI.
- remove linaro,optee-tz bindings update are now useless.
---
.../bindings/remoteproc/remoteproc-tee.yaml | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
diff --git a/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
new file mode 100644
index 000000000000..498a7e590905
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/remoteproc-tee.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TEE Remote Processor Control Service (UUID 80a4c275-0a47-4905-8285-1486a9771a08)
+
+maintainers:
+ - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
+
+description:
+ Node describing a TEE-based remote processor control service implemented as
+ a Trusted Application identified by UUID 80a4c275-0a47-4905-8285-1486a9771a08.
+
+ This binding is intended to define the interface for remoteproc services
+ implemented as TAs running in a TEE, and is used by the a remoteproc driver
+ to bind to such a service and control a remote processor through it.
+
+properties:
+ compatible:
+ const: 80a4c275-0a47-4905-8285-1486a9771a08
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ firmware {
+ tee_rproc: optee-rproc {
+ compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
+ };
+ };
+...
--
2.43.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