Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 0/4] arm64: mitigate CVE-2024-7881 in the absence of firmware mitigation
From: Will Deacon @ 2026-04-09 15:13 UTC (permalink / raw)
  To: David Woodhouse
  Cc: catalin.marinas, joey.gouly, kvmarm, linux-arm-kernel,
	mark.rutland, maz, oliver.upton, suzuki.poulose, yuzenghui
In-Reply-To: <3c9c567f7a6e926e8ec24913d564ec55e8f450d2.camel@infradead.org>

On Wed, Apr 08, 2026 at 10:26:10PM +0100, David Woodhouse wrote:
> On Mon, 17 Mar 2025 at 21:26:12 +0000, Will Deacon wrote:
> > I'm really not comfortable with this series and would prefer to see it
> > dropped while we continue the discussion, especially as it's causing
> > minor conflicts with the KVM/arm64 tree in -next.
> > 
> > ...
> > 
> > To be clear: I'm not at all against mitigating this problem and
> > advertising the status of that mitigation. I *am* against quietly
> > handling it like a CPU erratum whilst simultaneously telling userspace
> > that meltdown is not a problem regardless of the mitigation state.
> 
> Was there a conclusion? KVM still isn't even exposing
> SMCCC_ARCH_WORKAROUND_4 to guests...

I didn't see another version, so I think my comments (from a year ago!)
still stand.

Will


^ permalink raw reply

* [GIT PULL] pmdomain fixes for v7.0-rc8
From: Ulf Hansson @ 2026-04-09 15:09 UTC (permalink / raw)
  To: Linus, linux-pm, linux-kernel; +Cc: Ulf Hansson, linux-arm-kernel

Hi Linus,

Here's a pull-request with a couple of pmdomain/firmware fixes intended for
v7.0-rc8. I have also included a patch to update my email in MAINTAINERS and
mailmap. Details about the highlights are as usual found in the signed tag.

Please pull this in!

Kind regards
Ulf Hansson


The following changes since commit 7aaa8047eafd0bd628065b15757d9b48c5f9c07d:

  Linux 7.0-rc6 (2026-03-29 15:40:00 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git tags/pmdomain-v7.0-rc6

for you to fetch changes up to c2812c0cb909211a1d2e7cec862406e32833b9de:

  MAINTAINERS, mailmap: Change Ulf Hansson's email (2026-04-07 14:17:48 +0200)

----------------------------------------------------------------
pmdomain providers:
 - imx: Prevent hang at power down for imx8mp-blk-ctrl

firmware:
 - thead: Fix buffer overflow for TH1520 AON driver

MAINTAINERS, mailmap:
 - Change Ulf Hansson's email

----------------------------------------------------------------
Jacky Bai (1):
      pmdomain: imx8mp-blk-ctrl: Keep the NOC_HDCP clock enabled

Michal Wilczynski (1):
      firmware: thead: Fix buffer overflow and use standard endian macros

Ulf Hansson (1):
      MAINTAINERS, mailmap: Change Ulf Hansson's email

 .mailmap                                        |  2 +
 MAINTAINERS                                     | 14 ++---
 drivers/firmware/thead,th1520-aon.c             |  7 +--
 drivers/pmdomain/imx/imx8mp-blk-ctrl.c          |  8 +--
 include/linux/firmware/thead/thead,th1520-aon.h | 74 -------------------------
 5 files changed, 13 insertions(+), 92 deletions(-)


^ permalink raw reply

* Re: [EXTERNAL] [PATCH 2/3] KVM: arm64: vgic: Allow userspace to set IIDR revision 1
From: David Woodhouse @ 2026-04-09 15:01 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm@vger.kernel.org, shuah@kernel.org, yuzenghui@huawei.com,
	joey.gouly@arm.com, linux-kernel@vger.kernel.org,
	catalin.marinas@arm.com, nathan@kernel.org, pbonzini@redhat.com,
	kvmarm@lists.linux.dev, arnd@arndb.de, kees@kernel.org,
	will@kernel.org, suzuki.poulose@arm.com, oupton@kernel.org,
	rananta@google.com, linux-arm-kernel@lists.infradead.org,
	linux-kselftest@vger.kernel.org, eric.auger@redhat.com
In-Reply-To: <86v7e02qoq.wl-maz@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 2607 bytes --]

On Thu, 2026-04-09 at 14:45 +0100, Marc Zyngier wrote:
> On Wed, 08 Apr 2026 09:39:15 +0100,
> "Woodhouse, David" <dwmw@amazon.co.uk> wrote:
> > 
> > What if the guest boots under a new host kernel and finds the group
> > registers are writable, and then is live migrated to an old host kernel
> > on which they are not?
> 
> That's your problem. KVM/arm64 never supported downgrading.

Again, I don't know why you're saying this. It isn't true, and *can't*
be true if KVM/arm64 is going to be anything more than a toy.

> Not to mention that there is no valid GIC implementation that has RO
> group registers. All you are doing is to inflict a hypervisor bug on
> unsuspecting guests, for no good reason.

It's not about "inflicting a hypervisor bug". It's about preserving the
exact same environment that those millions of guests already *have*
instead of taking the risk of changing things underneath them. And
giving us a *path* to cleanly upgrading for new launches.

> > What about hibernation, if the *boot* kernel in the guest configures
> > the groups, but then transfers control back to the resumed guest kernel
> > which had not?
> 
> A guest that doesn't configures the groups cannot expect anything to
> work. You'd have the exact same problem on bare-metal.
> 
> > 
> > > So what is this *really* fixing?
> > 
> > I look at that question the other way round.
> > 
> > KVM has an established procedure for allowing userspace to control
> > guest-visible changes, using the IIDR. First the host kernel which
> > *supports* the change is rolled out, and only then does the VMM start
> > to enable it for new launches.
> > 
> > Even if we can address the questions above, and even if we can convince
> > ourselves that those are the *only* questions to ask... why not follow
> > the normal, safe, procedure? Especially given that there is already an
> > IIDR value which corresponds to it.
> > 
> > We don't *have* to YOLO it... and I don't want to :)
> 
> That's hardly an argument, is it?

Er... yes, yes really it is an argument. I don't want to randomly
inflict a device model change on *running* guests, and when they resume
from hibernation, when I can preserve the existing behaviour.

It's weird enough that you claim that KVM doesn't support downgrading;
now you seem to be claiming that it doesn't support retaining
compatibility when *upgrading* either!

The ability to set IIDR like this was explicitly *designed* for this
purpose, wasn't it? Why on earth would you object to being able to set
it to KVM_VGIC_IMP_REV_1?




[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]

^ permalink raw reply

* Re: [PATCH v7 7/7] KVM: arm64: Normalize cache configuration
From: David Woodhouse @ 2026-04-09 14:51 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: akihiko.odaki, Gutierrez Cantu, Bernardo, alexandru.elisei,
	alyssa, asahi, broonie, catalin.marinas, james.morse, kvmarm,
	kvmarm, linux-arm-kernel, linux-kernel, marcan, mathieu.poirier,
	oliver.upton, suzuki.poulose, sven, will
In-Reply-To: <86wlyg2r3i.wl-maz@kernel.org>

[-- Attachment #1: Type: text/plain, Size: 3229 bytes --]

On Thu, 2026-04-09 at 14:36 +0100, Marc Zyngier wrote:
> On Thu, 09 Apr 2026 13:25:24 +0100,
> David Woodhouse <dwmw2@infradead.org> wrote:
> > 
> > On Thu, 12 Jan 2023 at 11:38:52 +0900, Akihiko Odaki wrote:
> > > Before this change, the cache configuration of the physical CPU was
> > > exposed to vcpus. This is problematic because the cache configuration a
> > > vcpu sees varies when it migrates between vcpus with different cache
> > > configurations.
> > > 
> > > Fabricate cache configuration from the sanitized value, which holds the
> > > CTR_EL0 value the userspace sees regardless of which physical CPU it
> > > resides on.
> > > 
> > > CLIDR_EL1 and CCSIDR_EL1 are now writable from the userspace so that
> > > the VMM can restore the values saved with the old kernel.
> > 
> > (commit 7af0c2534f4c5)
> > 
> > How does the VMM set the values that the old kernel would have set?
> 
> By reading them at the source?

Yes, but the VMM in EL0 *can't* read the source, can it?

> > Let's say we're deploying a kernel with this change for the first time,
> > and we need to ensure that we provide a consistent environment to
> > guests, which can be live migrated back to an older host.
> 
> We have never guaranteed host downgrade. It almost never works.

Huh? Host downgrade absolutely *does* work; KVM on Arm isn't a toy.
We'd never be able to ship a new kernel if we didn't know we could roll
it *back* if we needed to.

I *know* that you know perfectly well that we actively test host
downgrades prior to every rollout of a new kernel. So I'm a little
confused about what you're trying to say here, Marc.

> > So for new launches, we need to provide the values that the old kernel
> > *would* have provided to the guest. A new launch isn't a migration;
> > there are no "values saved with the old kernel".
> 
> And you can provide these values.

If I know them, sure. But I don't, because:

> > Userspace can't read the CLIDR_EL1 and CCSIDR_EL1 registers directly,
> > and AFAICT not everything we need to reconstitute them is in sysfs. How
> > is this supposed to work?
> > 
> > Shouldn't this change have been made as a capability that the VMM can
> > explicitly opt in or out of? Environments that don't do cross-CPU
> > migration absolutely don't care about, and actively don't *want*, the
> > sanitisation that this commit inflicted on us, surely?
> 
> I don't think a capability buys you anything. You want to expose
> something to the guest? Make it so. You are in the favourable
> situation to completely own the HW and the VMM.

Now that the values are writable, but userspace can't easily see *what*
they would have been in the previous kernel. So having the capability
to ask KVM to set them to those values seems like it might be useful.

> > Am I missing something?
> 
> That you had over 3 years to voice your concern, and did nothing?

I was looking more for technical input about how I might determine the
original values to retain compatibility... but yes, I have given
feedback that merely *reverting* the offending commit in previous
kernel upgrades without actually doing anything to fix it properly
wasn't the best choice.

[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]

^ permalink raw reply

* Re: [PATCH v10 16/20] coresight: Add PM callbacks for sink device
From: Leo Yan @ 2026-04-09 14:49 UTC (permalink / raw)
  To: James Clark
  Cc: Suzuki K Poulose, coresight, linux-arm-kernel, Yeoreum Yun,
	Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
	Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
	Tamas Petz, Thomas Gleixner, Peter Zijlstra, Mike Leach
In-Reply-To: <ffe95710-cd52-484e-821e-a3d92ba17c33@linaro.org>

On Thu, Apr 09, 2026 at 03:30:56PM +0100, James Clark wrote:

[...]

> > > > @@ -1759,16 +1760,36 @@ static int coresight_pm_check(struct
> > > > coresight_path *path)
> > > >       if (source_has_cb)
> > > >           return 1;
> > > > +    sink_has_cb = coresight_ops(sink)->pm_save_disable &&
> > > > +              coresight_ops(sink)->pm_restore_enable;
> > > > +    /*
> > > > +     * It is not permitted that the source has no callbacks
> > > > while the sink
> > > > +     * does, as the sink cannot be disabled without disabling
> > > > the source,
> > > > +     * which may lead to lockups. Alternatively, the ETM driver should
> > > > +     * enable self-hosted PM mode at probe (see etm4_probe()).
> > > > +     */
> > > > +    if (sink_has_cb) {
> > > > +        pr_warn_once("coresight PM failed: source has no PM
> > > > callbacks; "
> > > > +                 "cannot safely control sink\n");
> > > 
> > > This prints out on my Orion board on a fresh boot because of how
> > > pm_save_enable is setup there. Do we really need the configuration
> > > of pm_save_enable for ETE/TRBE if we know that it always needs
> > > saving?

Yeah, I can remove this check and always bind CPU PM ops for ETE.

> > > It also stops warning if I rmmod and modprobe the module after
> > > booting. Seems like pm_save_enable is different depending on how the
> > > module is loaded which doesn't seem right.
> > 
> > Thats because the warning is pr_warn_*once*()
> 
> I don't think so, I tested it with a printf instead of a warn once and also
> tested modprobeing straight after a reboot.

I am a bit surprised that Orion6 hits the CPU idle flow, as I observed
that idle states are not enabled on my board:

  # ls /sys/devices/system/cpu/cpu*/cpuidle
  ls: cannot access '/sys/devices/system/cpu/cpu*/cpuidle': No such file or directory

If you hit only once CPU idle notifier, it is good to add a
dump_stack() in coresight_cpu_pm_notify and print the "cmd" argument,
so we can know the calling coming from where.  I am a bit suspect it
might be a glitch in CPUIdle layer.

Thanks,
Leo


^ permalink raw reply

* Re: [PATCH 7/7] media: rkvdec: Add multicore IOMMU support
From: Detlev Casanova @ 2026-04-09 14:49 UTC (permalink / raw)
  To: Nicolas Dufresne, Mauro Carvalho Chehab, Ezequiel Garcia,
	Heiko Stuebner, Hans Verkuil, Jonas Karlman
  Cc: kernel, linux-media, linux-kernel, linux-rockchip,
	linux-arm-kernel
In-Reply-To: <517dc6e9de0e284b3dc22952d9479616e6c8ec62.camel@collabora.com>

Hi Nicolas,

On 4/9/26 10:19, Nicolas Dufresne wrote:
> Le jeudi 09 avril 2026 à 09:50 -0400, Detlev Casanova a écrit :
>> As each core has its own IOMMU core, buffers must be mapped in each
>> core's IOMMU so that any run() call can use any core without having to
>> remap everything.
>>
>> To do that, we use rockchip iommu domain's iommu devices list.
>> With that, one IOMMU domain can be mapped on multiple devices, meaning
>> that each call to iommu_map() will flush the new mapping on all devices
>> in the list.
>>
>> The IOMMU domain that will have all devices in its list is the first
>> core's default domain.
>>
>> Another domain cannot be used because VB2 allocates buffers through the
>> DMA engine, which uses iommu_get_dma_domain() to find the domain to map
>> buffers through.
>>
>> The IOMMU restore function can still work as before, but needs to be more
>> explicit in what domain to attach the device to.
>> That is because detaching the empty domain will reattach the core's default
>> domain, which is wrong (except for the first "main" core).
>>
>> The RCB temporary buffers are allocated in a dedicated SRAM, each
>> core has its own SRAM, so the mapping for each core's SRAM is added in the
>> global domain.
>>
>> Everything else is mapped through the first core's default domain, making
>> the driver write the mappings on both IOMMU cores.
> Just raising an issue with the patch ordering here. I'm worried in a git bisect,
> the driver will be broken until we apply this last patch. Can we make sure that
> the driver bisects ? (or tell me if I'm wrong)
No, you're right. That's also why I mentioned it in the cover letter. 
This commit is also not too big, so I'll merge the last 3 commits and 
adapt the commit message to keep the information from the 3 (the commit 
messages are why I wanted to keep them separate, but there is no good 
way to keep them that way)

Detlev.
>
>> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
>> ---
>>   .../media/platform/rockchip/rkvdec/rkvdec-rcb.c    | 21 ++++++-------
>>   .../media/platform/rockchip/rkvdec/rkvdec-rcb.h    |  6 ++--
>>   drivers/media/platform/rockchip/rkvdec/rkvdec.c    | 35 +++++++++++++++++-----
>>   drivers/media/platform/rockchip/rkvdec/rkvdec.h    |  2 +-
>>   4 files changed, 44 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
>> index 190fb7438e8c..977e37cf209b 100644
>> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
>> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
>> @@ -57,7 +57,7 @@ bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx)
>>   	return ret;
>>   }
>>   
>> -void rkvdec_free_rcb(struct rkvdec_core *core)
>> +void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core)
>>   {
>>   	struct rkvdec_rcb_config *cfg = core->rcb_config;
>>   	unsigned long virt_addr;
>> @@ -76,12 +76,12 @@ void rkvdec_free_rcb(struct rkvdec_core *core)
>>   		case RKVDEC_ALLOC_SRAM:
>>   			virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
>>   
>> -			if (core->iommu_domain)
>> -				iommu_unmap(core->iommu_domain, virt_addr, rcb_size);
>> +			if (rkvdec->iommu_global_domain)
>> +				iommu_unmap(rkvdec->iommu_global_domain, virt_addr, rcb_size);
>>   			gen_pool_free(core->sram_pool, virt_addr, rcb_size);
>>   			break;
>>   		case RKVDEC_ALLOC_DMA:
>> -			dma_free_coherent(core->dev,
>> +			dma_free_coherent(rkvdec->main_core->dev,
>>   					  rcb_size,
>>   					  cfg->rcb_bufs[i].cpu,
>>   					  cfg->rcb_bufs[i].dma);
>> @@ -97,7 +97,8 @@ void rkvdec_free_rcb(struct rkvdec_core *core)
>>   	core->rcb_config = NULL;
>>   }
>>   
>> -int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>> +int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
>> +			u32 width, u32 height,
>>   			const struct rcb_size_info *size_info,
>>   			size_t rcb_count)
>>   {
>> @@ -132,7 +133,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>>   
>>   		/* Try allocating an SRAM buffer */
>>   		if (core->sram_pool) {
>> -			if (core->iommu_domain)
>> +			if (rkvdec->iommu_global_domain)
>>   				rcb_size = ALIGN(rcb_size, SZ_4K);
>>   
>>   			cpu = gen_pool_dma_zalloc_align(core->sram_pool,
>> @@ -142,11 +143,11 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>>   		}
>>   
>>   		/* If an IOMMU is used, map the SRAM address through it */
>> -		if (cpu && core->iommu_domain) {
>> +		if (cpu && rkvdec->iommu_global_domain) {
>>   			unsigned long virt_addr = (unsigned long)cpu;
>>   			phys_addr_t phys_addr = dma;
>>   
>> -			ret = iommu_map(core->iommu_domain, virt_addr, phys_addr,
>> +			ret = iommu_map(rkvdec->iommu_global_domain, virt_addr, phys_addr,
>>   					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
>>   			if (ret) {
>>   				gen_pool_free(core->sram_pool,
>> @@ -166,7 +167,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>>   ram_fallback:
>>   		/* Fallback to RAM */
>>   		if (!cpu) {
>> -			cpu = dma_alloc_coherent(core->dev,
>> +			cpu = dma_alloc_coherent(rkvdec->main_core->dev,
>>   						 rcb_size,
>>   						 &dma,
>>   						 GFP_KERNEL);
>> @@ -189,7 +190,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>>   	return 0;
>>   
>>   err_alloc:
>> -	rkvdec_free_rcb(core);
>> +	rkvdec_free_rcb(rkvdec, core);
>>   
>>   	return ret;
>>   }
>> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
>> index a12af9b7dc2b..d1149afe7fda 100644
>> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
>> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
>> @@ -8,6 +8,7 @@
>>   
>>   #include <linux/types.h>
>>   
>> +struct rkvdec_dev;
>>   struct rkvdec_ctx;
>>   struct rkvdec_core;
>>   
>> @@ -21,11 +22,12 @@ struct rcb_size_info {
>>   	enum rcb_axis axis;
>>   };
>>   
>> -int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>> +int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
>> +			u32 width, u32 height,
>>   			const struct rcb_size_info *size_info,
>>   			size_t rcb_count);
>>   dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
>>   size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
>>   int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
>>   bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx);
>> -void rkvdec_free_rcb(struct rkvdec_core *core);
>> +void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core);
>> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
>> index c2818f1575ef..2930e9b64906 100644
>> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
>> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
>> @@ -1204,9 +1204,9 @@ static void rkvdec_device_run(void *priv)
>>   	}
>>   
>>   	if (!rkvdec_rcb_buf_validate_size(ctx)) {
>> -		rkvdec_free_rcb(ctx->core);
>> +		rkvdec_free_rcb(ctx->dev, ctx->core);
>>   
>> -		ret = rkvdec_allocate_rcb(ctx->core,
>> +		ret = rkvdec_allocate_rcb(ctx->dev, ctx->core,
>>   					  ctx->decoded_fmt.fmt.pix_mp.width,
>>   					  ctx->decoded_fmt.fmt.pix_mp.height,
>>   					  ctx->dev->variant->rcb_sizes,
>> @@ -1486,6 +1486,7 @@ static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec)
>>   
>>   static void rkvdec_iommu_restore(struct rkvdec_core *core)
>>   {
>> +	int ret;
>>   	if (core->empty_domain) {
>>   		/*
>>   		 * To rewrite mapping into the attached IOMMU core, attach a new empty domain that
>> @@ -1494,8 +1495,14 @@ static void rkvdec_iommu_restore(struct rkvdec_core *core)
>>   		 * This is safely done in this interrupt handler to make sure no memory get mapped
>>   		 * through the IOMMU while the empty domain is attached.
>>   		 */
>> -		iommu_attach_device(core->empty_domain, core->dev);
>> +		iommu_detach_device(core->curr_ctx->dev->iommu_global_domain, core->dev);
>> +		ret = iommu_attach_device(core->empty_domain, core->dev);
>> +		if (ret)
>> +			dev_warn(core->dev, "Cannot attach empty domain: %d\n", ret);
>>   		iommu_detach_device(core->empty_domain, core->dev);
>> +		ret = iommu_attach_device(core->curr_ctx->dev->iommu_global_domain, core->dev);
>> +		if (ret)
>> +			dev_warn(core->dev, "Cannot attach global domain: %d\n", ret);
>>   	}
>>   }
>>   
>> @@ -1858,6 +1865,8 @@ static int rkvdec_probe(struct platform_device *pdev)
>>   
>>   	core = &rkvdec->cores[rkvdec->core_count++];
>>   
>> +	core->id = rkvdec->core_count - 1;
>> +
>>   	platform_set_drvdata(pdev, rkvdec);
>>   	core->dev = &pdev->dev;
>>   	INIT_DELAYED_WORK(&core->watchdog_work, rkvdec_watchdog_func);
>> @@ -1883,12 +1892,24 @@ static int rkvdec_probe(struct platform_device *pdev)
>>   			return PTR_ERR(core->link);
>>   	}
>>   
>> -	core->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
>> -	if (core->iommu_domain) {
>> +	if (iommu_get_domain_for_dev(&pdev->dev)) {
>>   		core->empty_domain = iommu_paging_domain_alloc(core->dev);
>>   
>> -		if (!core->empty_domain)
>> +		if (IS_ERR(core->empty_domain))
>>   			dev_warn(core->dev, "cannot alloc new empty domain\n");
>> +
>> +		if (!rkvdec->iommu_global_domain) {
>> +			rkvdec->iommu_global_domain = iommu_get_domain_for_dev(core->dev);
>> +
>> +			if (IS_ERR(rkvdec->iommu_global_domain)) {
>> +				rkvdec->iommu_global_domain = NULL;
>> +				dev_warn_once(core->dev, "cannot alloc new global domain\n");
>> +			}
>> +		}
>> +
>> +		ret = iommu_attach_device(rkvdec->iommu_global_domain, core->dev);
>> +		if (ret)
>> +			dev_warn(core->dev, "cannot attach global domain to core %d\n", core->id);
>>   	}
>>   
>>   	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
>> @@ -1961,7 +1982,7 @@ static void rkvdec_remove(struct platform_device *pdev)
>>   		if (rkvdec->cores[i].empty_domain)
>>   			iommu_domain_free(rkvdec->cores[i].empty_domain);
>>   
>> -		rkvdec_free_rcb(&rkvdec->cores[i]);
>> +		rkvdec_free_rcb(rkvdec, &rkvdec->cores[i]);
>>   	}
>>   }
>>   
>> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
>> index 4f042a367dc0..ccd766b220c7 100644
>> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
>> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
>> @@ -135,7 +135,6 @@ struct rkvdec_core {
>>   	void __iomem *link;
>>   	struct delayed_work watchdog_work;
>>   	struct gen_pool *sram_pool;
>> -	struct iommu_domain *iommu_domain;
>>   	struct iommu_domain *empty_domain;
>>   	struct rkvdec_rcb_config *rcb_config;
>>   	struct rkvdec_ctx *curr_ctx;
>> @@ -155,6 +154,7 @@ struct rkvdec_dev {
>>   	unsigned int available_core_count;
>>   	spinlock_t cores_lock; /* serializes core list access */
>>   	struct rkvdec_core *main_core;
>> +	struct iommu_domain *iommu_global_domain;
>>   };
>>   
>>   struct rkvdec_ctx {



^ permalink raw reply

* Re: [PATCH v2] nvme-apple: drop invalid put of admin queue reference count
From: Keith Busch @ 2026-04-09 14:47 UTC (permalink / raw)
  To: Fedor Pchelkin
  Cc: Christoph Hellwig, Jens Axboe, Sven Peter, Janne Grunau,
	Neal Gompa, Sagi Grimberg, Hannes Reinecke, Ming Lei,
	Chaitanya Kulkarni, Heyne, Maximilian, asahi, linux-arm-kernel,
	linux-nvme, linux-kernel, lvc-project, stable
In-Reply-To: <20260408141815.375695-1-pchelkin@ispras.ru>

On Wed, Apr 08, 2026 at 05:18:14PM +0300, Fedor Pchelkin wrote:
> Commit 03b3bcd319b3 ("nvme: fix admin request_queue lifetime") moved the
> admin queue reference ->put call into nvme_free_ctrl() - a controller
> device release callback performed for every nvme driver doing
> nvme_init_ctrl().

Thanks, applied to nvme-7.1.


^ permalink raw reply

* Re: [PATCH] mm/arm: pgtable: remove young bit check for pte_valid_user
From: Russell King (Oracle) @ 2026-04-09 14:43 UTC (permalink / raw)
  To: Will Deacon; +Cc: Brian Ruley, Steve Capper, linux-arm-kernel, linux-kernel
In-Reply-To: <adewJetUv6wMiz9o@willie-the-truck>

On Thu, Apr 09, 2026 at 02:56:53PM +0100, Will Deacon wrote:
> On Thu, Apr 09, 2026 at 03:54:45PM +0300, Brian Ruley wrote:
> > Fixes cache desync, which can cause undefined instruction,
> > translation and permission faults under heavy memory use.
> > 
> > This is an old bug introduced in commit 1971188aa196 ("ARM: 7985/1: mm:
> > implement pte_accessible for faulting mappings"), which included a check
> > for the young bit of a PTE. The underlying assumption was that old pages
> > are not cached, therefore, `__sync_icache_dcache' could be skipped
> > entirely.
> > 
> > However, under extreme memory pressure, page migrations happen
> > frequently and the assumption of uncached "old" pages does not hold.
> > Especially for systems that do not have swap, the migrated pages are
> > unequivocally marked old. This presents a problem, as it is possible
> > for the original page to be immediately mapped to another VA that
> > happens to share the same cache index in VIPT I-cache (we found this
> > bug on Cortex-A9). Without cache invalidation, the CPU will see the
> > old mapping whose physical page can now be used for a different
> > purpose, as illustrated below:
> > 
> >                 Core                      Physical Memory
> >   +-------------------------------+     +------------------+
> >   | TLB                           |     |                  |
> >   |  VA_A 0xb6e6f -> pfn_q        |     | pfn_q: code      |
> >   +-------------------------------+     +------------------+
> >   | I-cache                       |
> >   |  set[VA_A bits] | tag=pfn_q   |
> >   +-------------------------------+
> > 
> > migrate (kcompactd):
> >   1. copy pfn_q --> pfn_r
> >   2. free pfn_q
> >   3. pte: VA_a -> pfn_r
> >   4. pte_mkold(pte) --> !young
> >   5. ICIALLUIS skipped (because !young)
> > 
> > pfn_src reused (OOM pressure):
> >   pte: VA_B -> pfn_q (different code)
> > 
> > bug:
> >                 Core                      Physical Memory
> >   +-------------------------------+     +------------------+
> >   | TLB (empty)                   |     | pfn_r: old code  |
> >   +-------------------------------+     | pfn_q: new code  |
> >   | I-cache                       |     +------------------+
> >   |  set[VA_A bits] | tag=pfn_q   |<--- wrong instructions
> >   +-------------------------------+
> 
> (nit: Do you have pfn_r and pfn_q mixed up in the "Physical Memory" box?)

I don't think so. pfn_r contains the code that _was_ in pfn_q before
the migration happened (the migration copied pfn_q to pfn_r).

Then, a short time later, the page for pfn_r is reallocated, with new
code placed into it, and then a new PTE is established for pfn_q -
however, this should be a young PTE (which will be necessary for the
mapping to be visible to userspace), and thus should cause
__sync_icache_dcache() to be called, resulting in __flush_icache_all()
if it is an executable mapping.

If it isn't an executable mapping (because pfn_q isn't code) then we
will skip the __flush_icache_all() for the new mapping.

However, the I-cache for the old PTE that was pfn_r and now is pfn_q
will not be present in the physical page tables. An attempt to execute
code from that mapping should fault, causing the MM to mark that PTE
young, and, as it's executable, it should result in
__flush_icache_all() being called.

Like you, I can't see any issue here.

I think we need to know exactly what happened to the old PTE entry
and the newer PTE entry that was subsequently established on the
lead-up to the undefined instruction exception.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply

* Re: [PATCH v0 06/15] mshv: Implement mshv bridge device for VFIO
From: Stanislav Kinsburskii @ 2026-04-09 14:41 UTC (permalink / raw)
  To: Mukesh R
  Cc: linux-kernel, linux-hyperv, linux-arm-kernel, iommu, linux-pci,
	linux-arch, kys, haiyangz, wei.liu, decui, longli,
	catalin.marinas, will, tglx, mingo, bp, dave.hansen, hpa, joro,
	lpieralisi, kwilczynski, mani, robh, bhelgaas, arnd, nunodasneves,
	mhklinux, romank
In-Reply-To: <c30ede65-46c4-02b1-756a-868f9a265cf1@linux.microsoft.com>

On Tue, Apr 07, 2026 at 10:41:12AM -0700, Mukesh R wrote:
> On 1/20/26 08:09, Stanislav Kinsburskii wrote:
> > On Mon, Jan 19, 2026 at 10:42:21PM -0800, Mukesh R wrote:
> > > From: Mukesh Rathor <mrathor@linux.microsoft.com>
> > > 
> > > Add a new file to implement VFIO-MSHV bridge pseudo device. These
> > > functions are called in the VFIO framework, and credits to kvm/vfio.c
> > > as this file was adapted from it.
> > > 
> > > Original author: Wei Liu <wei.liu@kernel.org>
> > > (Slightly modified from the original version).
> > > 
> > 
> > There is a Linux standard for giving credits when code is adapted from.
> > This doesn't follow that standard. Please fix.
> > 
> > > Signed-off-by: Mukesh Rathor <mrathor@linux.microsoft.com>
> > > ---
> > >   drivers/hv/Makefile    |   3 +-
> > >   drivers/hv/mshv_vfio.c | 210 +++++++++++++++++++++++++++++++++++++++++
> > >   2 files changed, 212 insertions(+), 1 deletion(-)
> > >   create mode 100644 drivers/hv/mshv_vfio.c
> > > 
> > > diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
> > > index a49f93c2d245..eae003c4cb8f 100644
> > > --- a/drivers/hv/Makefile
> > > +++ b/drivers/hv/Makefile
> > > @@ -14,7 +14,8 @@ hv_vmbus-y := vmbus_drv.o \
> > >   hv_vmbus-$(CONFIG_HYPERV_TESTING)	+= hv_debugfs.o
> > >   hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o
> > >   mshv_root-y := mshv_root_main.o mshv_synic.o mshv_eventfd.o mshv_irq.o \
> > > -	       mshv_root_hv_call.o mshv_portid_table.o mshv_regions.o
> > > +	       mshv_root_hv_call.o mshv_portid_table.o mshv_regions.o \
> > > +               mshv_vfio.o
> > >   mshv_vtl-y := mshv_vtl_main.o
> > >   # Code that must be built-in
> > > diff --git a/drivers/hv/mshv_vfio.c b/drivers/hv/mshv_vfio.c
> > > new file mode 100644
> > > index 000000000000..6ea4d99a3bd2
> > > --- /dev/null
> > > +++ b/drivers/hv/mshv_vfio.c
> > > @@ -0,0 +1,210 @@
> > > +// SPDX-License-Identifier: GPL-2.0-only
> > > +/*
> > > + * VFIO-MSHV bridge pseudo device
> > > + *
> > > + * Heavily inspired by the VFIO-KVM bridge pseudo device.
> > > + */
> > > +#include <linux/errno.h>
> > > +#include <linux/file.h>
> > > +#include <linux/list.h>
> > > +#include <linux/module.h>
> > > +#include <linux/mutex.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/vfio.h>
> > > +
> > > +#include "mshv.h"
> > > +#include "mshv_root.h"
> > > +
> > > +struct mshv_vfio_file {
> > > +	struct list_head node;
> > > +	struct file *file;	/* list of struct mshv_vfio_file */
> > > +};
> > > +
> > > +struct mshv_vfio {
> > > +	struct list_head file_list;
> > > +	struct mutex lock;
> > > +};
> > > +
> > > +static bool mshv_vfio_file_is_valid(struct file *file)
> > > +{
> > > +	bool (*fn)(struct file *file);
> > > +	bool ret;
> > > +
> > > +	fn = symbol_get(vfio_file_is_valid);
> > > +	if (!fn)
> > > +		return false;
> > > +
> > > +	ret = fn(file);
> > > +
> > > +	symbol_put(vfio_file_is_valid);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static long mshv_vfio_file_add(struct mshv_device *mshvdev, unsigned int fd)
> > > +{
> > > +	struct mshv_vfio *mshv_vfio = mshvdev->device_private;
> > > +	struct mshv_vfio_file *mvf;
> > > +	struct file *filp;
> > > +	long ret = 0;
> > > +
> > > +	filp = fget(fd);
> > > +	if (!filp)
> > > +		return -EBADF;
> > > +
> > > +	/* Ensure the FD is a vfio FD. */
> > > +	if (!mshv_vfio_file_is_valid(filp)) {
> > > +		ret = -EINVAL;
> > > +		goto out_fput;
> > > +	}
> > > +
> > > +	mutex_lock(&mshv_vfio->lock);
> > > +
> > > +	list_for_each_entry(mvf, &mshv_vfio->file_list, node) {
> > > +		if (mvf->file == filp) {
> > > +			ret = -EEXIST;
> > > +			goto out_unlock;
> > > +		}
> > > +	}
> > > +
> > > +	mvf = kzalloc(sizeof(*mvf), GFP_KERNEL_ACCOUNT);
> > > +	if (!mvf) {
> > > +		ret = -ENOMEM;
> > > +		goto out_unlock;
> > > +	}
> > > +
> > > +	mvf->file = get_file(filp);
> > > +	list_add_tail(&mvf->node, &mshv_vfio->file_list);
> > > +
> > > +out_unlock:
> > > +	mutex_unlock(&mshv_vfio->lock);
> > > +out_fput:
> > > +	fput(filp);
> > > +	return ret;
> > > +}
> > > +
> > > +static long mshv_vfio_file_del(struct mshv_device *mshvdev, unsigned int fd)
> > > +{
> > > +	struct mshv_vfio *mshv_vfio = mshvdev->device_private;
> > > +	struct mshv_vfio_file *mvf;
> > > +	long ret;
> > > +
> > > +	CLASS(fd, f)(fd);
> > > +
> > > +	if (fd_empty(f))
> > > +		return -EBADF;
> > > +
> > > +	ret = -ENOENT;
> > > +	mutex_lock(&mshv_vfio->lock);
> > > +
> > > +	list_for_each_entry(mvf, &mshv_vfio->file_list, node) {
> > > +		if (mvf->file != fd_file(f))
> > > +			continue;
> > > +
> > > +		list_del(&mvf->node);
> > > +		fput(mvf->file);
> > > +		kfree(mvf);
> > > +		ret = 0;
> > > +		break;
> > > +	}
> > > +
> > > +	mutex_unlock(&mshv_vfio->lock);
> > > +	return ret;
> > > +}
> > > +
> > > +static long mshv_vfio_set_file(struct mshv_device *mshvdev, long attr,
> > > +			      void __user *arg)
> > > +{
> > > +	int32_t __user *argp = arg;
> > > +	int32_t fd;
> > > +
> > > +	switch (attr) {
> > > +	case MSHV_DEV_VFIO_FILE_ADD:
> > > +		if (get_user(fd, argp))
> > > +			return -EFAULT;
> > > +		return mshv_vfio_file_add(mshvdev, fd);
> > > +
> > > +	case MSHV_DEV_VFIO_FILE_DEL:
> > > +		if (get_user(fd, argp))
> > > +			return -EFAULT;
> > > +		return mshv_vfio_file_del(mshvdev, fd);
> > > +	}
> > > +
> > > +	return -ENXIO;
> > > +}
> > > +
> > > +static long mshv_vfio_set_attr(struct mshv_device *mshvdev,
> > > +			      struct mshv_device_attr *attr)
> > > +{
> > > +	switch (attr->group) {
> > > +	case MSHV_DEV_VFIO_FILE:
> > > +		return mshv_vfio_set_file(mshvdev, attr->attr,
> > > +					  u64_to_user_ptr(attr->addr));
> > > +	}
> > > +
> > > +	return -ENXIO;
> > > +}
> > > +
> > > +static long mshv_vfio_has_attr(struct mshv_device *mshvdev,
> > > +			      struct mshv_device_attr *attr)
> > > +{
> > > +	switch (attr->group) {
> > > +	case MSHV_DEV_VFIO_FILE:
> > > +		switch (attr->attr) {
> > > +		case MSHV_DEV_VFIO_FILE_ADD:
> > > +		case MSHV_DEV_VFIO_FILE_DEL:
> > > +			return 0;
> > > +		}
> > > +
> > > +		break;
> > > +	}
> > > +
> > > +	return -ENXIO;
> > > +}
> > > +
> > > +static long mshv_vfio_create_device(struct mshv_device *mshvdev, u32 type)
> > > +{
> > > +	struct mshv_device *tmp;
> > > +	struct mshv_vfio *mshv_vfio;
> > > +
> > > +	/* Only one VFIO "device" per VM */
> > > +	hlist_for_each_entry(tmp, &mshvdev->device_pt->pt_devices,
> > > +			     device_ptnode)
> > > +		if (tmp->device_ops == &mshv_vfio_device_ops)
> > > +			return -EBUSY;
> > > +
> > > +	mshv_vfio = kzalloc(sizeof(*mshv_vfio), GFP_KERNEL_ACCOUNT);
> > > +	if (mshv_vfio == NULL)
> > > +		return -ENOMEM;
> > > +
> > > +	INIT_LIST_HEAD(&mshv_vfio->file_list);
> > > +	mutex_init(&mshv_vfio->lock);
> > > +
> > > +	mshvdev->device_private = mshv_vfio;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +/* This is called from mshv_device_fop_release() */
> > > +static void mshv_vfio_release_device(struct mshv_device *mshvdev)
> > > +{
> > > +	struct mshv_vfio *mv = mshvdev->device_private;
> > > +	struct mshv_vfio_file *mvf, *tmp;
> > > +
> > > +	list_for_each_entry_safe(mvf, tmp, &mv->file_list, node) {
> > > +		fput(mvf->file);
> > 
> > This put must be sync as device must be detached from domain before
> > attempting partition destruction.
> 
> Like I said in 6.6 PR, this does not attach or detach devices.
> 

You are mistaken. It absolutely does.

Thanks,
Stanislav

> > This was explicitly mentioned in the patch originated this code.
> > Please fix, add a comment and credits to the commit message.
> 
> That was ".detstroy" hook which is gone.
> 
> Thanks,
> -Mukesh
> 
> 
> > Thanks,
> > Stanislav
> > 
> > 
> > > +		list_del(&mvf->node);
> > > +		kfree(mvf);
> > > +	}
> > > +
> > > +	kfree(mv);
> > > +	kfree(mshvdev);
> > > +}
> > > +
> > > +struct mshv_device_ops mshv_vfio_device_ops = {
> > > +	.device_name = "mshv-vfio",
> > > +	.device_create = mshv_vfio_create_device,
> > > +	.device_release = mshv_vfio_release_device,
> > > +	.device_set_attr = mshv_vfio_set_attr,
> > > +	.device_has_attr = mshv_vfio_has_attr,
> > > +};
> > > -- 
> > > 2.51.2.vfs.0.1
> > > 
> 


^ permalink raw reply

* Re: [PATCH] media: cedrus: skip invalid H.264 reference list entries
From: Nicolas Dufresne @ 2026-04-09 14:39 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: Pengpeng Hou, mripard, mchehab, gregkh, wens, jernej.skrabec,
	samuel, linux-media, linux-staging, linux-arm-kernel, linux-sunxi,
	linux-kernel
In-Reply-To: <ade4Qe4OS04au2Ba@shepard>

[-- Attachment #1: Type: text/plain, Size: 600 bytes --]

Hi,

Le jeudi 09 avril 2026 à 16:31 +0200, Paul Kocialkowski a écrit :
> I think it make sense yes, but it would be good to document it in the uAPI
> document too.

Basically, extend in the M2M decoder spec(s) on the existing documentation:
   
   V4L2_BUF_FLAG_ERROR:
   -
   When this flag is set, the buffer has been dequeued successfully, although
   the data might **have been corrupted**. This is recoverable, streaming may
   continue as normal and the buffer may be reused normally. Drivers set this
   flag when the VIDIOC_DQBUF ioctl is called.
   
   
cheers,
Nicolas

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH v10 16/20] coresight: Add PM callbacks for sink device
From: James Clark @ 2026-04-09 14:31 UTC (permalink / raw)
  To: Suzuki K Poulose, Leo Yan
  Cc: coresight, linux-arm-kernel, Yeoreum Yun, Mark Rutland,
	Will Deacon, Yabin Cui, Keita Morisaki, Yuanfang Zhang,
	Greg Kroah-Hartman, Alexander Shishkin, Tamas Petz,
	Thomas Gleixner, Peter Zijlstra, Mike Leach
In-Reply-To: <ffe95710-cd52-484e-821e-a3d92ba17c33@linaro.org>



On 09/04/2026 3:30 pm, James Clark wrote:
> 
> 
> On 09/04/2026 2:14 pm, Suzuki K Poulose wrote:
>> On 09/04/2026 11:52, James Clark wrote:
>>>
>>>
>>> On 05/04/2026 4:02 pm, Leo Yan wrote:
>>>> Unlike system level sinks, per-CPU sinks may lose power during CPU idle
>>>> states.  Currently, this applies specifically to TRBE.  This commit
>>>> invokes save and restore callbacks for the sink in the CPU PM notifier.
>>>>
>>>> If the sink provides PM callbacks but the source does not, this is
>>>> unsafe because the sink cannot be disabled safely unless the source
>>>> can also be controlled, so veto low power entry to avoid lockups.
>>>>
>>>> Tested-by: James Clark <james.clark@linaro.org>
>>>> Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
>>>> Reviewed-by: James Clark <james.clark@linaro.org>
>>>> Signed-off-by: Leo Yan <leo.yan@arm.com>
>>>> ---
>>>>   drivers/hwtracing/coresight/coresight-core.c | 46 ++++++++++++++++ 
>>>> + + ++++++++--
>>>>   1 file changed, 43 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/ 
>>>> hwtracing/coresight/coresight-core.c
>>>> index 
>>>> c1e8debc76aba7eb5ecf7efe2a3b9b8b3e11b10c..a918bf6398a932de30fe9b4947020cc4c1cfb2f7 100644
>>>> --- a/drivers/hwtracing/coresight/coresight-core.c
>>>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>>>> @@ -1736,14 +1736,15 @@ static void coresight_release_device_list(void)
>>>>   /* Return: 1 if PM is required, 0 if skip, <0 on error */
>>>>   static int coresight_pm_check(struct coresight_path *path)
>>>>   {
>>>> -    struct coresight_device *source;
>>>> -    bool source_has_cb;
>>>> +    struct coresight_device *source, *sink;
>>>> +    bool source_has_cb, sink_has_cb;
>>>>       if (!path)
>>>>           return 0;
>>>>       source = coresight_get_source(path);
>>>> -    if (!source)
>>>> +    sink = coresight_get_sink(path);
>>>> +    if (!source || !sink)
>>>>           return 0;
>>>>       /* Don't save and restore if the source is inactive */
>>>> @@ -1759,16 +1760,36 @@ static int coresight_pm_check(struct 
>>>> coresight_path *path)
>>>>       if (source_has_cb)
>>>>           return 1;
>>>> +    sink_has_cb = coresight_ops(sink)->pm_save_disable &&
>>>> +              coresight_ops(sink)->pm_restore_enable;
>>>> +    /*
>>>> +     * It is not permitted that the source has no callbacks while 
>>>> the sink
>>>> +     * does, as the sink cannot be disabled without disabling the 
>>>> source,
>>>> +     * which may lead to lockups. Alternatively, the ETM driver should
>>>> +     * enable self-hosted PM mode at probe (see etm4_probe()).
>>>> +     */
>>>> +    if (sink_has_cb) {
>>>> +        pr_warn_once("coresight PM failed: source has no PM 
>>>> callbacks; "
>>>> +                 "cannot safely control sink\n");
>>>
>>> This prints out on my Orion board on a fresh boot because of how 
>>> pm_save_enable is setup there. Do we really need the configuration of 
>>> pm_save_enable for ETE/TRBE if we know that it always needs saving?
>>>
>>> It also stops warning if I rmmod and modprobe the module after 
>>> booting. Seems like pm_save_enable is different depending on how the 
>>> module is loaded which doesn't seem right.
>>
>> Thats because the warning is pr_warn_*once*()
>>
>> Suzuki
>>
>>
> 
> I don't think so, I tested it with a printf instead of a warn once and 
> also tested modprobeing straight after a reboot.
> 

I also printed the pointers to the callbacks and they really do change.

>>>
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>>       return 0;
>>>>   }
>>>>   static int coresight_pm_device_save(struct coresight_device *csdev)
>>>>   {
>>>> +    if (!csdev || !coresight_ops(csdev)->pm_save_disable)
>>>> +        return 0;
>>>> +
>>>>       return coresight_ops(csdev)->pm_save_disable(csdev);
>>>>   }
>>>>   static void coresight_pm_device_restore(struct coresight_device 
>>>> *csdev)
>>>>   {
>>>> +    if (!csdev || !coresight_ops(csdev)->pm_restore_enable)
>>>> +        return;
>>>> +
>>>>       coresight_ops(csdev)->pm_restore_enable(csdev);
>>>>   }
>>>> @@ -1787,15 +1808,32 @@ static int coresight_pm_save(struct 
>>>> coresight_path *path)
>>>>       to = list_prev_entry(coresight_path_last_node(path), link);
>>>>       coresight_disable_path_from_to(path, from, to);
>>>> +    ret = coresight_pm_device_save(coresight_get_sink(path));
>>>> +    if (ret)
>>>> +        goto sink_failed;
>>>> +
>>>
>>> The comment directly above this says "Up to the node before sink to 
>>> avoid latency". But then this line goes and saves the sink anyway. So 
>>> I'm not sure what's meant by the comment?
>>>
>>>>       return 0;
>>>> +
>>>> +sink_failed:
>>>> +    if (!coresight_enable_path_from_to(path, 
>>>> coresight_get_mode(source),
>>>> +                       from, to))
>>>> +        coresight_pm_device_restore(source);
>>>> +
>>>> +    pr_err("Failed in coresight PM save on CPU%d: %d\n",
>>>> +           smp_processor_id(), ret);
>>>> +    this_cpu_write(percpu_pm_failed, true);
>>>
>>> Why does only a failing sink set percpu_pm_failed when failing to 
>>> save the source exits early. Sashiko has a similar comment that this 
>>> could result in restoring uninitialised source save data later, but a 
>>> comment in this function about why the flow is like this would be 
>>> helpful.
>>>
>>> We have coresight_disable_path_from_to() which always succeeds and 
>>> doesn't return an error. TRBE is the only sink with a pm_save_disable()
>>> callback, but it always succeeds anyway.
>>>
>>> Would it not be much simpler to require that sink save/restore 
>>> callbacks always succeed and don't return anything? Seems like this 
>>> percpu_pm_failed stuff is extra complexity for a scenario that 
>>> doesn't exist? The only thing that can fail is saving the source but 
>>> it doesn't goto sink_failed when that happens.
>>>
>>> Ideally etm4_cpu_save() wouldn't have a return value either. It would 
>>> be good if we could find away to skip or ignore the timeouts in there 
>>> somehow because that's the only reason it can fail.
>>>
>>>> +    return ret;
>>>>   }
>>>>   static void coresight_pm_restore(struct coresight_path *path)
>>>>   {
>>>>       struct coresight_device *source = coresight_get_source(path);
>>>> +    struct coresight_device *sink = coresight_get_sink(path);
>>>>       struct coresight_node *from, *to;
>>>>       int ret;
>>>> +    coresight_pm_device_restore(sink);
>>>> +
>>>>       from = coresight_path_first_node(path);
>>>>       /* Up to the node before sink to avoid latency */
>>>>       to = list_prev_entry(coresight_path_last_node(path), link);
>>>> @@ -1808,6 +1846,8 @@ static void coresight_pm_restore(struct 
>>>> coresight_path *path)
>>>>       return;
>>>>   path_failed:
>>>> +    coresight_pm_device_save(sink);
>>>> +
>>>>       pr_err("Failed in coresight PM restore on CPU%d: %d\n",
>>>>              smp_processor_id(), ret);
>>>>
>>>
>>
> 



^ permalink raw reply

* Re: [PATCH] media: cedrus: skip invalid H.264 reference list entries
From: Paul Kocialkowski @ 2026-04-09 14:31 UTC (permalink / raw)
  To: Nicolas Dufresne
  Cc: Pengpeng Hou, mripard, mchehab, gregkh, wens, jernej.skrabec,
	samuel, linux-media, linux-staging, linux-arm-kernel, linux-sunxi,
	linux-kernel
In-Reply-To: <4bd5d70a6144f3e8d4356c182f314cf735f1921c.camel@collabora.com>

[-- Attachment #1: Type: text/plain, Size: 6000 bytes --]

Hi Nicolas,

On Thu 09 Apr 26, 10:00, Nicolas Dufresne wrote:
> Le jeudi 09 avril 2026 à 15:33 +0200, Paul Kocialkowski a écrit :
> > Hi,
> > 
> > On Tue 24 Mar 26, 16:08, Pengpeng Hou wrote:
> > > Cedrus consumes H.264 ref_pic_list0/ref_pic_list1 entries from the
> > > stateless slice control and later uses their indices to look up
> > > decode->dpb[] in _cedrus_write_ref_list().
> > > 
> > > Rejecting such controls in cedrus_try_ctrl() would break existing
> > > userspace, since stateless H.264 reference lists may legitimately carry
> > > out-of-range indices for missing references. Instead, guard the actual
> > > DPB lookup in Cedrus and skip entries whose indices do not fit the fixed
> > > V4L2_H264_NUM_DPB_ENTRIES array.
> > 
> > Could you explain why it is legitimate that userspace would pass indices that
> > are not in the dpb list? As far as I remember from the H.264 spec, the L0/L1
> > lists are constructed from active references only and the number of items
> > there
> > should be given by num_ref_idx_l0_active_minus1/num_ref_idx_l1_active_minus1.
> > We can tolerate invalid data beyond these indices, but certainly not as part
> > of the indices that should be valid.
> > 
> > However I agree that cedrus_try_ctrl is maybe not the right place to check it
> > since I'm not sure we are guaranteed that the slice params control will be
> > checked before the new DPB (from the same request) is applied, so we might end
> > up checking against the dpb from the previous decode request.
> > 
> > But I think we should error out and not just skip the invalid reference.
> 
> Its been a long time I haven't looked into this. But what happens here is that
> once you lost a reference, the userspace DPB will hold a gap picture, which as
> no backing storage. Since it has no backing storage, there is no cookie
> (timestamp) associated with it. This gap picture will still make it to the
> reference lists, since the position of the reference in the list is important
> (you cannot just remove an item). It is an established practice in userspace to
> simply fill the void with an invalid index, typically 0xff, which is always
> invalid. Because that's what some userspace do, it became part of our ABI.

Right we definitely need to keep the order of the L0/L1 lists even with missing
references and the question is whether the hardware can deal with it or not.

Our uAPI specification currently doesn't say anything about handling missing
references. I'm generally not very keen on considering that undefined behavior
becomes de-facto uAPI that should never be broken, because there are cases where
it is obviously incorrect and the fact that it didn't fail previously is the
result of a bug in the implementation.

But in this situation I agree we do need a way to indicate that references are
missing and using 0xff sounds like a good plan to me, given that we provide a
uAPI header define with this value and that the doc mentions it.

> Decoders are expected be fault tolerant, though the tolerance level is hardware
> specific, and so failing in the common code would be inappropriate (failing in
> Cedrus could be acceptable, assuming it can't work with missing references,
> which the implementation seems to be fine with).

Okay I agree that we should not fail in common code and tolerate a value to
indicate a missing reference.

What the current proposal is doing (skipping the reference) results in the
SRAM entry for the reference remaining untouched, which will keep its value
from the previous frame. This seems clearly incorrect.

> Hantro G1 notably have a flag to report missing reference to the HW, and it will
> manage concealement internally. G2/RKVDEC don't, and we try and pick the most
> recent frame as a replacement backing storage, which most of the time minimises
> the damages.

It sounds like an approach that could work for cedrus too.

> As future refinement, we need drivers in the long term to properly report the
> damages (perhaps through additional RO request controls). As discussed few years
> ago in the error handling wip for rkvdec, the V4L2 doc specify that any sort of
> damages known to exist in a frame shall results in the ERROR flag being set. We
> can deduce that the error flag with a payload of 0 indicates to userspace to not
> use the frame (which typically happen on hard errors, or errror at entropy
> decode staged) and ERROR flag with a correct payload signal some level of
> corruption, and its left to the application to decide what to do.

I think it make sense yes, but it would be good to document it in the uAPI
document too.

All the best,

Paul

> Nicolas
> 
> > 
> > All the best,
> > 
> > Paul
> > 
> > > 
> > > This keeps the fix local to the driver use site and avoids out-of-bounds
> > > reads from malformed or unsupported reference list entries.
> > > 
> > > Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> > > ---
> > >  drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 3 +++
> > >  1 file changed, 3 insertions(+)
> > > 
> > > diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > > b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > > --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > > +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > > @@ -210,6 +210,9 @@ static void _cedrus_write_ref_list(struct cedrus_ctx
> > > *ctx,
> > >  		u8 dpb_idx;
> > >  
> > >  		dpb_idx = ref_list[i].index;
> > > +		if (dpb_idx >= V4L2_H264_NUM_DPB_ENTRIES)
> > > +			continue;
> > > +
> > >  		dpb = &decode->dpb[dpb_idx];
> > >  
> > >  		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
> > > -- 
> > > 2.50.1
> > > 



-- 
Paul Kocialkowski,

Independent contractor - sys-base - https://www.sys-base.io/
Free software developer - https://www.paulk.fr/

Expert in multimedia, graphics and embedded hardware support with Linux.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH v10 16/20] coresight: Add PM callbacks for sink device
From: James Clark @ 2026-04-09 14:30 UTC (permalink / raw)
  To: Suzuki K Poulose, Leo Yan
  Cc: coresight, linux-arm-kernel, Yeoreum Yun, Mark Rutland,
	Will Deacon, Yabin Cui, Keita Morisaki, Yuanfang Zhang,
	Greg Kroah-Hartman, Alexander Shishkin, Tamas Petz,
	Thomas Gleixner, Peter Zijlstra, Mike Leach
In-Reply-To: <f20b5a00-1d68-48d6-90c8-97dca2e279a4@arm.com>



On 09/04/2026 2:14 pm, Suzuki K Poulose wrote:
> On 09/04/2026 11:52, James Clark wrote:
>>
>>
>> On 05/04/2026 4:02 pm, Leo Yan wrote:
>>> Unlike system level sinks, per-CPU sinks may lose power during CPU idle
>>> states.  Currently, this applies specifically to TRBE.  This commit
>>> invokes save and restore callbacks for the sink in the CPU PM notifier.
>>>
>>> If the sink provides PM callbacks but the source does not, this is
>>> unsafe because the sink cannot be disabled safely unless the source
>>> can also be controlled, so veto low power entry to avoid lockups.
>>>
>>> Tested-by: James Clark <james.clark@linaro.org>
>>> Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
>>> Reviewed-by: James Clark <james.clark@linaro.org>
>>> Signed-off-by: Leo Yan <leo.yan@arm.com>
>>> ---
>>>   drivers/hwtracing/coresight/coresight-core.c | 46 +++++++++++++++++ 
>>> + ++++++++--
>>>   1 file changed, 43 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/ 
>>> hwtracing/coresight/coresight-core.c
>>> index 
>>> c1e8debc76aba7eb5ecf7efe2a3b9b8b3e11b10c..a918bf6398a932de30fe9b4947020cc4c1cfb2f7 100644
>>> --- a/drivers/hwtracing/coresight/coresight-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-core.c
>>> @@ -1736,14 +1736,15 @@ static void coresight_release_device_list(void)
>>>   /* Return: 1 if PM is required, 0 if skip, <0 on error */
>>>   static int coresight_pm_check(struct coresight_path *path)
>>>   {
>>> -    struct coresight_device *source;
>>> -    bool source_has_cb;
>>> +    struct coresight_device *source, *sink;
>>> +    bool source_has_cb, sink_has_cb;
>>>       if (!path)
>>>           return 0;
>>>       source = coresight_get_source(path);
>>> -    if (!source)
>>> +    sink = coresight_get_sink(path);
>>> +    if (!source || !sink)
>>>           return 0;
>>>       /* Don't save and restore if the source is inactive */
>>> @@ -1759,16 +1760,36 @@ static int coresight_pm_check(struct 
>>> coresight_path *path)
>>>       if (source_has_cb)
>>>           return 1;
>>> +    sink_has_cb = coresight_ops(sink)->pm_save_disable &&
>>> +              coresight_ops(sink)->pm_restore_enable;
>>> +    /*
>>> +     * It is not permitted that the source has no callbacks while 
>>> the sink
>>> +     * does, as the sink cannot be disabled without disabling the 
>>> source,
>>> +     * which may lead to lockups. Alternatively, the ETM driver should
>>> +     * enable self-hosted PM mode at probe (see etm4_probe()).
>>> +     */
>>> +    if (sink_has_cb) {
>>> +        pr_warn_once("coresight PM failed: source has no PM 
>>> callbacks; "
>>> +                 "cannot safely control sink\n");
>>
>> This prints out on my Orion board on a fresh boot because of how 
>> pm_save_enable is setup there. Do we really need the configuration of 
>> pm_save_enable for ETE/TRBE if we know that it always needs saving?
>>
>> It also stops warning if I rmmod and modprobe the module after 
>> booting. Seems like pm_save_enable is different depending on how the 
>> module is loaded which doesn't seem right.
> 
> Thats because the warning is pr_warn_*once*()
> 
> Suzuki
> 
> 

I don't think so, I tested it with a printf instead of a warn once and 
also tested modprobeing straight after a reboot.

>>
>>> +        return -EINVAL;
>>> +    }
>>> +
>>>       return 0;
>>>   }
>>>   static int coresight_pm_device_save(struct coresight_device *csdev)
>>>   {
>>> +    if (!csdev || !coresight_ops(csdev)->pm_save_disable)
>>> +        return 0;
>>> +
>>>       return coresight_ops(csdev)->pm_save_disable(csdev);
>>>   }
>>>   static void coresight_pm_device_restore(struct coresight_device 
>>> *csdev)
>>>   {
>>> +    if (!csdev || !coresight_ops(csdev)->pm_restore_enable)
>>> +        return;
>>> +
>>>       coresight_ops(csdev)->pm_restore_enable(csdev);
>>>   }
>>> @@ -1787,15 +1808,32 @@ static int coresight_pm_save(struct 
>>> coresight_path *path)
>>>       to = list_prev_entry(coresight_path_last_node(path), link);
>>>       coresight_disable_path_from_to(path, from, to);
>>> +    ret = coresight_pm_device_save(coresight_get_sink(path));
>>> +    if (ret)
>>> +        goto sink_failed;
>>> +
>>
>> The comment directly above this says "Up to the node before sink to 
>> avoid latency". But then this line goes and saves the sink anyway. So 
>> I'm not sure what's meant by the comment?
>>
>>>       return 0;
>>> +
>>> +sink_failed:
>>> +    if (!coresight_enable_path_from_to(path, 
>>> coresight_get_mode(source),
>>> +                       from, to))
>>> +        coresight_pm_device_restore(source);
>>> +
>>> +    pr_err("Failed in coresight PM save on CPU%d: %d\n",
>>> +           smp_processor_id(), ret);
>>> +    this_cpu_write(percpu_pm_failed, true);
>>
>> Why does only a failing sink set percpu_pm_failed when failing to save 
>> the source exits early. Sashiko has a similar comment that this could 
>> result in restoring uninitialised source save data later, but a 
>> comment in this function about why the flow is like this would be 
>> helpful.
>>
>> We have coresight_disable_path_from_to() which always succeeds and 
>> doesn't return an error. TRBE is the only sink with a pm_save_disable()
>> callback, but it always succeeds anyway.
>>
>> Would it not be much simpler to require that sink save/restore 
>> callbacks always succeed and don't return anything? Seems like this 
>> percpu_pm_failed stuff is extra complexity for a scenario that doesn't 
>> exist? The only thing that can fail is saving the source but it 
>> doesn't goto sink_failed when that happens.
>>
>> Ideally etm4_cpu_save() wouldn't have a return value either. It would 
>> be good if we could find away to skip or ignore the timeouts in there 
>> somehow because that's the only reason it can fail.
>>
>>> +    return ret;
>>>   }
>>>   static void coresight_pm_restore(struct coresight_path *path)
>>>   {
>>>       struct coresight_device *source = coresight_get_source(path);
>>> +    struct coresight_device *sink = coresight_get_sink(path);
>>>       struct coresight_node *from, *to;
>>>       int ret;
>>> +    coresight_pm_device_restore(sink);
>>> +
>>>       from = coresight_path_first_node(path);
>>>       /* Up to the node before sink to avoid latency */
>>>       to = list_prev_entry(coresight_path_last_node(path), link);
>>> @@ -1808,6 +1846,8 @@ static void coresight_pm_restore(struct 
>>> coresight_path *path)
>>>       return;
>>>   path_failed:
>>> +    coresight_pm_device_save(sink);
>>> +
>>>       pr_err("Failed in coresight PM restore on CPU%d: %d\n",
>>>              smp_processor_id(), ret);
>>>
>>
> 



^ permalink raw reply

* Re: [RFC PATCH 1/7] media: v4l2-ctrls: Add V4L2_CID_MEMORY_USAGE control
From: Detlev Casanova @ 2026-04-09 14:29 UTC (permalink / raw)
  To: Nicolas Dufresne, Ming Qian(OSS), Frank Li
  Cc: linux-media, mchehab, hverkuil-cisco, sebastian.fricke, shawnguo,
	s.hauer, kernel, festevam, linux-imx, xiahong.bao, eagle.zhou,
	imx, linux-kernel, linux-arm-kernel
In-Reply-To: <8911674f2f86a4b75e1f44d6e9b66a28f6e74e56.camel@ndufresne.ca>



On 4/8/26 17:11, Nicolas Dufresne wrote:
> Le jeudi 02 avril 2026 à 11:14 +0800, Ming Qian(OSS) a écrit :
>> Hi Nicolas,
>>
>> On 4/1/2026 10:23 AM, Ming Qian(OSS) wrote:
>>> Hi Nicolas,
>>>
>>> On 3/31/2026 10:54 PM, Nicolas Dufresne wrote:
>>>> Le mardi 31 mars 2026 à 10:33 -0400, Frank Li a écrit :
>>>>> On Tue, Mar 31, 2026 at 03:23:11PM +0800, ming.qian@oss.nxp.com wrote:
>>>>>> From: Ming Qian <ming.qian@oss.nxp.com>
>>>>>>
>>>>>> Add a new read-only control V4L2_CID_MEMORY_USAGE that allows
>>>>>> applications to query the total amount of memory currently used
>>>>>> by a device instance.
>>>>>>
>>>>>> This control reports the memory consumption in bytes, including
>>>>>> internal buffers, intermediate processing data, and other
>>>>>> driver-managed allocations. Applications can use this information
>>>>>> for debugging, resource monitoring, or making informed decisions
>>>>>> about buffer allocation strategies.
>>>>>>
>>>>>> Signed-off-by: Ming Qian <ming.qian@oss.nxp.com>
>>>>>> ---
>>>>> Not sure why not export these information by debugfs, or any benefit vs
>>>>> debugfs?
>>>> There is also a on-going proposal that uses fdinfo.
>>>>
>>>> Nicolas
>>>>
>>> Thanks for the reminder about the ongoing fdinfo proposal.
>>>
>>> Just to confirm, you are referring to Detlev’s ongoing fdinfo proposal,
>>> specifically this series:
>>> https://lore.kernel.org/lkml/20260212162328.192217-1-
>>> detlev.casanova@collabora.com/
>>>
>>> I will align my work with it and switch to using fdinfo.
>>> Once the show_fdinfo support from that series is merged, I will prepare
>>> the next revision of my patch accordingly.
>>>
>>> Regards,
>>> Ming
>>>
>> Regarding the discussion about using fdinfo instead of a V4L2 control, I
>> have two questions:
>>
>> 	1. Key consistency in fdinfo
>> 	fdinfo uses key–value pairs, which is flexible, but if multiple
>> 	drivers want to expose the same “memory usage” information,
>> 	they need to agree on a common key name and meaning. Otherwise
>> 	user‑space must handle each driver differently. A V4L2 control
>> 	naturally provides a unified interface without this coordination
>> 	effort.
>>
>>
>> 	2. Lack of notification in fdinfo
>> 	With a control, user‑space can subscribe to control events and
>> 	receive notifications when the memory usage changes. fdinfo does
>> 	not have a built‑in event mechanism, so users must either poll
>> 	or rely on additional eventfd‑like or custom event mechanisms.
>>
>> Do you have any suggestions or existing practices to address these two
>> issues when using fdinfo?
>>
>> Thanks again for your time and comments.
> Added Detlev in CC. You can also refer to his work through:
>
> https://lore.kernel.org/all/20260212162328.192217-1-detlev.casanova@collabora.com/
>
> Nicolas
Hi Ming !

One of the reasons for using fdinfo is that it's already being used in 
the drm subsystem and it is working well.
Of course, in DRM, drivers don't allocate a lot of memory themselves, 
userspace drivers (in mesa) go through the DRM uAPI to allocate buffers, 
making the DRM subsystem aware of all allocated memory.
That lets DRM show memory stats in a standard way for all drm drivers. 
In v4l2, memory allocation is shared between userspace and the driver.
We could have drivers report memory usage through a callback and 
v4l2-core can add the standard field based on that.

For notifications, I don't really see a need for that, most tracing 
tools will use polling (I'm thinking perfetto, but also top-like tools).
We could have a max-mem-usage field if we'd want to make sure we don't 
miss the maximum memory usage between 2 polls.

Finally, I think v4l2 controls should only be used to control, configure 
and exchange data with video devices, not get stat information on what 
the driver is doing.

Detlev.
>
>> Regards,
>> Ming
>>
>>>>> Generanlly document should be first patch, then driver change.
>>>>>
>>>>> Frank
>>>>>
>>>>>>    drivers/media/v4l2-core/v4l2-ctrls-defs.c | 8 ++++++++
>>>>>>    include/uapi/linux/v4l2-controls.h        | 4 +++-
>>>>>>    2 files changed, 11 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/
>>>>>> media/v4l2-core/v4l2-ctrls-defs.c
>>>>>> index 551426c4cd01..053db78ff661 100644
>>>>>> --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
>>>>>> +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
>>>>>> @@ -831,6 +831,7 @@ const char *v4l2_ctrl_get_name(u32 id)
>>>>>>        case V4L2_CID_ALPHA_COMPONENT:        return "Alpha Component";
>>>>>>        case V4L2_CID_COLORFX_CBCR:        return "Color Effects, CbCr";
>>>>>>        case V4L2_CID_COLORFX_RGB:              return "Color Effects,
>>>>>> RGB";
>>>>>> +    case V4L2_CID_MEMORY_USAGE:        return "Memory Usage";
>>>>>>
>>>>>>        /*
>>>>>>         * Codec controls
>>>>>> @@ -1476,6 +1477,13 @@ void v4l2_ctrl_fill(u32 id, const char
>>>>>> **name, enum v4l2_ctrl_type *type,
>>>>>>            *min = 0;
>>>>>>            *max = 0xffff;
>>>>>>            break;
>>>>>> +    case V4L2_CID_MEMORY_USAGE:
>>>>>> +        *type = V4L2_CTRL_TYPE_INTEGER64;
>>>>>> +        *flags |= V4L2_CTRL_FLAG_READ_ONLY;
>>>>>> +        *min = 0;
>>>>>> +        *max = S64_MAX;
>>>>>> +        *step = 1;
>>>>>> +        break;
>>>>>>        case V4L2_CID_FLASH_FAULT:
>>>>>>        case V4L2_CID_JPEG_ACTIVE_MARKER:
>>>>>>        case V4L2_CID_3A_LOCK:
>>>>>> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/
>>>>>> linux/v4l2-controls.h
>>>>>> index 68dd0c4e47b2..02c6f960d38e 100644
>>>>>> --- a/include/uapi/linux/v4l2-controls.h
>>>>>> +++ b/include/uapi/linux/v4l2-controls.h
>>>>>> @@ -110,8 +110,10 @@ enum v4l2_colorfx {
>>>>>>    #define V4L2_CID_COLORFX_CBCR            (V4L2_CID_BASE+42)
>>>>>>    #define V4L2_CID_COLORFX_RGB            (V4L2_CID_BASE+43)
>>>>>>
>>>>>> +#define V4L2_CID_MEMORY_USAGE            (V4L2_CID_BASE+44)
>>>>>> +
>>>>>>    /* last CID + 1 */
>>>>>> -#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+44)
>>>>>> +#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+45)
>>>>>>
>>>>>>    /* USER-class private control IDs */
>>>>>>
>>>>>> -- 
>>>>>> 2.53.0
>>>>>>



^ permalink raw reply

* Re: [PATCH v2 2/4] perf: Fix uninitialized bitfields in perf_clear_branch_entry_bitfields()
From: Leo Yan @ 2026-04-09 14:28 UTC (permalink / raw)
  To: Puranjay Mohan
  Cc: bpf, Puranjay Mohan, Alexei Starovoitov, Andrii Nakryiko,
	Daniel Borkmann, Martin KaFai Lau, Eduard Zingerman,
	Kumar Kartikeya Dwivedi, Will Deacon, Mark Rutland,
	Catalin Marinas, Rob Herring, Breno Leitao, linux-arm-kernel,
	linux-perf-users, kernel-team
In-Reply-To: <20260318171706.2840512-3-puranjay@kernel.org>

On Wed, Mar 18, 2026 at 10:16:56AM -0700, Puranjay Mohan wrote:
> perf_clear_branch_entry_bitfields() zeroes individual bitfields of struct
> perf_branch_entry but misses the new_type (4 bits) and priv (3 bits)
> fields. This means any code path that relies on this function to produce
> a clean entry may expose stale or uninitialised data in these fields to
> userspace.
> 
> The function was introduced by commit bfe4daf850f4 ("perf/core: Add
> perf_clear_branch_entry_bitfields() helper") specifically to "centralize
> the initialization to avoid missing a field in case more are added."
> Unfortunately, the commits that later added new_type and priv to struct
> perf_branch_entry only updated the UAPI header and did not update this
> clearing function.
> 
> Zero new_type and priv alongside the other bitfields.
> 
> Fixes: b190bc4ac9e6 ("perf: Extend branch type classification")
> Fixes: 5402d25aa571 ("perf: Capture branch privilege information")
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> ---
>  include/linux/perf_event.h | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index 48d851fbd8ea..d7f39b7e9cda 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -1481,6 +1481,8 @@ static inline void perf_clear_branch_entry_bitfields(struct perf_branch_entry *b
>  	br->cycles	= 0;
>  	br->type	= 0;
>  	br->spec	= PERF_BR_SPEC_NA;
> +	br->new_type	= 0;
> +	br->priv	= 0;
>  	br->reserved	= 0;
>  }

We already know this does not work well. Instead, we can define a union
for bitfield and use memset to clear it, later we will not bother for
this kind of issue anymore.

  struct perf_branch_entry {
          ...
  
          union {
                  struct {
                          __u64   mispred   :  1, /* target mispredicted */
                                  predicted :  1, /* target predicted */
                                  ...
                                  reserved  : 31;
                  };
                  __u64 bitfields;
          };
  };

static inline void perf_clear_branch_entry_bitfields(struct perf_branch_entry *br)
{
        memset(&br->bitfields, 0, sizeof(br->bitfields));
}

Thanks,
Leo


^ permalink raw reply

* Re: [PATCH RFC net-next 0/4] improve hw flow offload byte accounting
From: Daniel Golle @ 2026-04-09 14:21 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Felix Fietkau, John Crispin, Lorenzo Bianconi, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Matthias Brugger, AngeloGioacchino Del Regno, Simon Horman,
	Florian Westphal, Phil Sutter, netdev, linux-kernel,
	linux-arm-kernel, linux-mediatek, netfilter-devel, coreteam
In-Reply-To: <adevKeasLkEB5zZ4@chamomile>

On Thu, Apr 09, 2026 at 03:52:41PM +0200, Pablo Neira Ayuso wrote:
> On Thu, Apr 09, 2026 at 02:07:22PM +0100, Daniel Golle wrote:
> > Hardware flow counters report raw byte counts whose semantics
> > vary by vendor -- some count ingress L2 frames, others egress
> > L2, others L3. The nf_flow_table framework currently passes
> > these bytes straight to conntrack without conversion, and
> > sub-interfaces (VLAN, PPPoE) that are bypassed by hw offload
> > never see any counter updates at all.
> 
> I see, but that is part of the feature itself? Why pretend that these
> interface are really seeing traffic while they don't. This aspiration
> of trying to do all hardware offload fully transparent (when it is not
> the case, not mentioning semantic changes in how packet handling is
> done compared to the software plane) does not sound convincing to me.

Please explain what you mean by offloading not being fully
transparent. If the MAC hardware offloads VLAN encap/decap, for
example, we also maintain the counters correctly (it just so happens),
just the flow-offloading case results in a weird overall picture:
hardware interface counters keep increasing, encap interfaces (802.1Q,
PPPoE) don't. That makes it confusing and hard to understand what's
happening when only looking at the interface counters (ie. "what is
all that traffic on my physical WAN interface which isn't PPPoE? Can't
be that all of that is the modems management interface, SNMP, ...")

> 
> On top of this, this issue also exists in the software plane: Devices
> that are bypasses do not get their counters bumped.
> 
> Maybe if this is really a requirement, then this should address the
> issue for software too, but is it worth the effort to add
> infrastructure for this purpose?

To me it would feel more correct to see counters increasing also
for offloaded traffic on software interfaces such as PPPoE or VLAN.

I honestly didn't think about the software fastpath, and yes, I think
it should be addressed there too.

> > This series lets drivers declare what their counters represent,
> > so the framework can normalize to L3 for conntrack and
> > propagate per-layer stats to encap sub-interfaces.

This part could also been seen as an independent fix as currently
conntrack stats for the same traffic differ in case of software
offloading (pure L3 bytes) and hardware offloading (L2 ingress bytes
in case of mtk_ppe).


^ permalink raw reply

* Re: [PATCH] mm/arm: pgtable: remove young bit check for pte_valid_user
From: Russell King (Oracle) @ 2026-04-09 14:21 UTC (permalink / raw)
  To: Will Deacon; +Cc: Brian Ruley, Steve Capper, linux-arm-kernel, linux-kernel
In-Reply-To: <adewJetUv6wMiz9o@willie-the-truck>

On Thu, Apr 09, 2026 at 02:56:53PM +0100, Will Deacon wrote:
> On Thu, Apr 09, 2026 at 03:54:45PM +0300, Brian Ruley wrote:
> > Fixes cache desync, which can cause undefined instruction,
> > translation and permission faults under heavy memory use.
> > 
> > This is an old bug introduced in commit 1971188aa196 ("ARM: 7985/1: mm:
> > implement pte_accessible for faulting mappings"), which included a check
> > for the young bit of a PTE. The underlying assumption was that old pages
> > are not cached, therefore, `__sync_icache_dcache' could be skipped
> > entirely.
> > 
> > However, under extreme memory pressure, page migrations happen
> > frequently and the assumption of uncached "old" pages does not hold.
> > Especially for systems that do not have swap, the migrated pages are
> > unequivocally marked old. This presents a problem, as it is possible
> > for the original page to be immediately mapped to another VA that
> > happens to share the same cache index in VIPT I-cache (we found this
> > bug on Cortex-A9). Without cache invalidation, the CPU will see the
> > old mapping whose physical page can now be used for a different
> > purpose, as illustrated below:
> > 
> >                 Core                      Physical Memory
> >   +-------------------------------+     +------------------+
> >   | TLB                           |     |                  |
> >   |  VA_A 0xb6e6f -> pfn_q        |     | pfn_q: code      |
> >   +-------------------------------+     +------------------+
> >   | I-cache                       |
> >   |  set[VA_A bits] | tag=pfn_q   |
> >   +-------------------------------+
> > 
> > migrate (kcompactd):
> >   1. copy pfn_q --> pfn_r
> >   2. free pfn_q
> >   3. pte: VA_a -> pfn_r
> >   4. pte_mkold(pte) --> !young
> >   5. ICIALLUIS skipped (because !young)
> > 
> > pfn_src reused (OOM pressure):
> >   pte: VA_B -> pfn_q (different code)
> > 
> > bug:
> >                 Core                      Physical Memory
> >   +-------------------------------+     +------------------+
> >   | TLB (empty)                   |     | pfn_r: old code  |
> >   +-------------------------------+     | pfn_q: new code  |
> >   | I-cache                       |     +------------------+
> >   |  set[VA_A bits] | tag=pfn_q   |<--- wrong instructions
> >   +-------------------------------+
> 
> (nit: Do you have pfn_r and pfn_q mixed up in the "Physical Memory" box?)
> 
> > This was verified on ba16-based board (i.MX6Quad/Dual, Cortex-A9) by
> > instrumenting the migration code to track recently migrated pages in a
> > ring buffer and then dumping them in the undefined instruction fault
> > handler. The bug can be triggered with `stress-ng':
> > 
> >   stress-ng --vm 4 --vm-bytes 2G --vm-method zero-one --verify
> > 
> > Note that the system we tested on has only 2G of memory, so the test
> > triggered the OOM-killer in our case.
> > 
> > Fixes: 1971188aa196 ("ARM: 7985/1: mm: implement pte_accessible for faulting mappings")
> > Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
> > ---
> >  arch/arm/include/asm/pgtable.h | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
> > index 6fa9acd6a7f5..e3a5b4a9a65f 100644
> > --- a/arch/arm/include/asm/pgtable.h
> > +++ b/arch/arm/include/asm/pgtable.h
> > @@ -185,7 +185,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
> >  #define pte_exec(pte)		(pte_isclear((pte), L_PTE_XN))
> >  
> >  #define pte_valid_user(pte)	\
> > -	(pte_valid(pte) && pte_isset((pte), L_PTE_USER) && pte_young(pte))
> > +	(pte_valid(pte) && pte_isset((pte), L_PTE_USER))
> 
> This patch is from twelve years ago, so please forgive me for having
> forgotten all of the details. However, my recollection is that when using
> the classic/!lpae format (as you will be on Cortex-A9), page aging is
> implemented by using invalid (translation faulting) ptes for 'old'
> mappings.

It is.

> So in the case you describe, we may well elide the I-cache maintenance,
> but won't we also put down an invalid pte?

Correct.

> If we later take a fault
> on that, we should then perform the cache maintenance when installing
> the young entry (via ptep_set_access_flags()).

Correct again.

> The more interesting part
> is probably when the mapping for 'VA_B' is installed to map 'pfn_q' but,
> again, I would've expected the cache maintenance to happen just prior to
> installing the valid (young) mapping.

Also correct - for the new PTE to become accessible in userspace, we
would need to establish a young PTE, which will result in set_ptes()
being called, and that should trigger __flush_icache_all() which will
flush the _entire_ instruction cache, which will remove any stale
entries for the old mapping that is no longer accessible.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply

* Re: [PATCH v2 1/3] arm64: mm: Fix rodata=full block mapping support for realm guests
From: Suzuki K Poulose @ 2026-04-09 14:18 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: Ryan Roberts, Will Deacon, David Hildenbrand (Arm), Dev Jain,
	Yang Shi, Jinjiang Tu, Kevin Brodsky, linux-arm-kernel,
	linux-kernel, stable
In-Reply-To: <d1ecba64-898f-433b-93d4-7a33b9c3f378@arm.com>



On 09/04/2026 10:38, Suzuki K Poulose wrote:
> On 07/04/2026 18:21, Catalin Marinas wrote:
>> On Tue, Apr 07, 2026 at 10:57:35AM +0100, Suzuki K Poulose wrote:
>>> On 02/04/2026 21:43, Catalin Marinas wrote:
>>>> On Mon, Mar 30, 2026 at 05:17:02PM +0100, Ryan Roberts wrote:
>>>>>    int split_kernel_leaf_mapping(unsigned long start, unsigned long 
>>>>> end)
>>>>>    {
>>>>>        int ret;
>>>>> -    /*
>>>>> -     * !BBML2_NOABORT systems should not be trying to change 
>>>>> permissions on
>>>>> -     * anything that is not pte-mapped in the first place. Just 
>>>>> return early
>>>>> -     * and let the permission change code raise a warning if not 
>>>>> already
>>>>> -     * pte-mapped.
>>>>> -     */
>>>>> -    if (!system_supports_bbml2_noabort())
>>>>> -        return 0;
>>>>> -
>>>>>        /*
>>>>>         * If the region is within a pte-mapped area, there is no 
>>>>> need to try to
>>>>>         * split. Additionally, CONFIG_DEBUG_PAGEALLOC and 
>>>>> CONFIG_KFENCE may
>>>>>         * change permissions from atomic context so for those cases 
>>>>> (which are
>>>>>         * always pte-mapped), we must not go any further because 
>>>>> taking the
>>>>> -     * mutex below may sleep.
>>>>> +     * mutex below may sleep. Do not call force_pte_mapping() here 
>>>>> because
>>>>> +     * it could return a confusing result if called from a 
>>>>> secondary cpu
>>>>> +     * prior to finalizing caps. Instead, 
>>>>> linear_map_requires_bbml2 gives us
>>>>> +     * what we need.
>>>>>         */
>>>>> -    if (force_pte_mapping() || is_kfence_address((void *)start))
>>>>> +    if (!linear_map_requires_bbml2 || is_kfence_address((void 
>>>>> *)start))
>>>>>            return 0;
>>>>> +    if (!system_supports_bbml2_noabort()) {
>>>>> +        /*
>>>>> +         * !BBML2_NOABORT systems should not be trying to change
>>>>> +         * permissions on anything that is not pte-mapped in the 
>>>>> first
>>>>> +         * place. Just return early and let the permission change 
>>>>> code
>>>>> +         * raise a warning if not already pte-mapped.
>>>>> +         */
>>>>> +        if (system_capabilities_finalized())
>>>>> +            return 0;
>>>>> +
>>>>> +        /*
>>>>> +         * Boot-time: split_kernel_leaf_mapping_locked() allocates 
>>>>> from
>>>>> +         * page allocator. Can't split until it's available.
>>>>> +         */
>>>>> +        if (WARN_ON(!page_alloc_available))
>>>>> +            return -EBUSY;
>>>>> +
>>>>> +        /*
>>>>> +         * Boot-time: Started secondary cpus but don't know if they
>>>>> +         * support BBML2_NOABORT yet. Can't allow splitting in this
>>>>> +         * window in case they don't.
>>>>> +         */
>>>>> +        if (WARN_ON(num_online_cpus() > 1))
>>>>> +            return -EBUSY;
>>>>> +    }
>>>>
>>>> I think sashiko is over cautions here
>>>> (https://sashiko.dev/#/patchset/20260330161705.3349825-1- 
>>>> ryan.roberts@arm.com)
>>>> but it has a somewhat valid point from the perspective of
>>>> num_online_cpus() semantics. We have have num_online_cpus() == 1 while
>>>> having a secondary CPU just booted and with its MMU enabled. I don't
>>>> think we can have any asynchronous tasks running at that point to
>>>> trigger a spit though. Even async_init() is called after smp_init().
>>>>
>>>> An option may be to attempt cpus_read_trylock() as this lock is 
>>>> taken by
>>>> _cpu_up(). If it fails, return -EBUSY, otherwise check 
>>>> num_online_cpus()
>>>> and unlock (and return -EBUSY if secondaries already started).
>>>>
>>>> Another thing I couldn't get my head around - IIUC is_realm_world()
>>>> won't return true for map_mem() yet (if in a realm).
>>>
>>> That is correct. map_mem() comes from paginig_init(), which gets called
>>> before arm64_rsi_init(). Realm check was delayed until psci_xx_init().
>>> We had a version which parsed the DT for PSCI conduit early enough
>>> to be able to make the SMC calls to detect the Realm. But there
>>> were concerns around it.
>>
>> Ah, yes, I remember.
>>
>> Does it mean that commit 42be24a4178f ("arm64: Enable memory encrypt for
>> Realms") was broken without rodata=full w.r.t. the linear map? Commit
> 
> Apparently, it looks like we missed this when we demoted the RSI
> detection later.
> 
>> a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
>> introduced force_pte_mapping() but it just copied the logic in the
>> existing can_set_direct_map(). Looking at the linear_map_requires_bbml2
>> assignment, we get (!is_realm_world() && is_realm_world()) and it
>> cancels out, no effect on it but we don't get pte mappings either (even
>> if we don't have BBML2).
> 
> Yep, that's right.
>>
>> I think we need at least some safety checks:
>>
>> 1. BBML2_NOABORT support on the boot CPU - continue with the existing
>>     logic (as per Ryan's series)
>>
>> 2. !system_supports_bbml2_noabort() - split in
>>     linear_map_maybe_split_to_ptes(). This does not currently happen
>>     because linear_map_requires_bbml2 may be false in the absence of
>>     rodata=full. Not sure how to fix this without some variable telling
>>     us how the linear map was mapped. The requires_bbml2 flag doesn't
>>
>> 3. Panic in arm64_rsi_init() if !BBML2_NOABORT on the boot CPU _and_ we
>>     have block mappings already. People can avoid it with rodata=full
> 
> It looks like this will be a common case :-(

Having another look, by default, arm64 boots with rodata=full, and users
have to explicitly lower the bar by setting rodata=off or noalias. So
this has been keeping us running ;-).

With rodata=off, I get the following for a Realm boot:

[    0.000000] ------------[ cut here ]------------ 

[    0.000000] WARNING: arch/arm64/mm/pageattr.c:61 at 
pageattr_pmd_entry+0x78/0xe0, CPU#0: swapper/0
[    0.000000] Modules linked in:
[    0.000000] CPU: 0 UID: 0 PID: 0 Comm: swapper Not tainted 7.0.0-rc1+ 
#1889 PREEMPT
[    0.000000] Hardware name: linux,dummy-virt (DT)
[    0.000000] pstate: 800000c5 (Nzcv daIF -PAN -UAO -TCO -DIT -SSBS 
BTYPE=--)
[    0.000000] pc : pageattr_pmd_entry+0x78/0xe0
[    0.000000] lr : walk_pgd_range+0x43c/0x970
[    0.000000] sp : ffff800082343b70
[    0.000000] x29: ffff800082343b70 x28: fff0000019600000 x27: 
fff0000019580000
[    0.000000] x26: ffff800082343c98 x25: fff000001d57ffff x24: 
fff000001fffe000
[    0.000000] x23: ffff8000810ae698 x22: fff000001fffd650 x21: 
fff0000019780000
[    0.000000] x20: fff000001d580000 x19: 0000000000000000 x18: 
0000000000000030
[    0.000000] x17: 0000000000004000 x16: 000000009fffc000 x15: 
0000000000000020
[    0.000000] x14: 0000000000003be4 x13: 0000000000000020 x12: 
0000000000000000
[    0.000000] x11: 0000000000000016 x10: 0000000000000015 x9 : 
0000000000000013
[    0.000000] x8 : 0000000000000015 x7 : 0000000080000000 x6 : 
0000000000000000
[    0.000000] x5 : 0078000099400405 x4 : fff000001fffd650 x3 : 
ffff800082343c98
[    0.000000] x2 : 0000000000080000 x1 : fff0000019580000 x0 : 
0000000000000001
[    0.000000] Call trace:
[    0.000000]  pageattr_pmd_entry+0x78/0xe0 (P)
[    0.000000]  walk_kernel_page_table_range_lockless+0x60/0xa0 

[    0.000000]  update_range_prot+0x80/0x128
[    0.000000]  __set_memory_enc_dec.part.0+0x88/0x258
[    0.000000]  realm_set_memory_decrypted+0x54/0x98
[    0.000000]  set_memory_decrypted+0x38/0x58
[    0.000000]  swiotlb_update_mem_attributes+0x44/0x58
[    0.000000]  mem_init+0x24/0x38
[    0.000000]  mm_core_init+0x94/0x140
[    0.000000]  start_kernel+0x544/0xa18
[    0.000000]  __primary_switched+0x88/0x98
[    0.000000] ---[ end trace 0000000000000000 ]---


Suzuki

> 
>>
>> 4. If (3) is a common case, a better alternative is to rewrite the
>>     linear map sometime after arm64_rsi_init() but before we call
>>     split_kernel_leaf_mapping().
> 
> We will explore this route.
> 
> The other option is to move the RSI detection (and the PSCI probe)
> earlier to be able to make better decisions early on. I will play with
> that a bit too.
> 
> Suzuki
> 
> 
>>
> 



^ permalink raw reply

* Re: [PATCH 7/7] media: rkvdec: Add multicore IOMMU support
From: Nicolas Dufresne @ 2026-04-09 14:19 UTC (permalink / raw)
  To: Detlev Casanova, Mauro Carvalho Chehab, Ezequiel Garcia,
	Heiko Stuebner, Hans Verkuil, Jonas Karlman
  Cc: kernel, linux-media, linux-kernel, linux-rockchip,
	linux-arm-kernel
In-Reply-To: <20260409-rkvdec-multicore-v1-7-62b316abf0f7@collabora.com>

[-- Attachment #1: Type: text/plain, Size: 10653 bytes --]

Le jeudi 09 avril 2026 à 09:50 -0400, Detlev Casanova a écrit :
> As each core has its own IOMMU core, buffers must be mapped in each
> core's IOMMU so that any run() call can use any core without having to
> remap everything.
> 
> To do that, we use rockchip iommu domain's iommu devices list.
> With that, one IOMMU domain can be mapped on multiple devices, meaning
> that each call to iommu_map() will flush the new mapping on all devices
> in the list.
> 
> The IOMMU domain that will have all devices in its list is the first
> core's default domain.
> 
> Another domain cannot be used because VB2 allocates buffers through the
> DMA engine, which uses iommu_get_dma_domain() to find the domain to map
> buffers through.
> 
> The IOMMU restore function can still work as before, but needs to be more
> explicit in what domain to attach the device to.
> That is because detaching the empty domain will reattach the core's default
> domain, which is wrong (except for the first "main" core).
> 
> The RCB temporary buffers are allocated in a dedicated SRAM, each
> core has its own SRAM, so the mapping for each core's SRAM is added in the
> global domain.
> 
> Everything else is mapped through the first core's default domain, making
> the driver write the mappings on both IOMMU cores.

Just raising an issue with the patch ordering here. I'm worried in a git bisect,
the driver will be broken until we apply this last patch. Can we make sure that
the driver bisects ? (or tell me if I'm wrong)

Nicolas

> 
> Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
> ---
>  .../media/platform/rockchip/rkvdec/rkvdec-rcb.c    | 21 ++++++-------
>  .../media/platform/rockchip/rkvdec/rkvdec-rcb.h    |  6 ++--
>  drivers/media/platform/rockchip/rkvdec/rkvdec.c    | 35 +++++++++++++++++-----
>  drivers/media/platform/rockchip/rkvdec/rkvdec.h    |  2 +-
>  4 files changed, 44 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> index 190fb7438e8c..977e37cf209b 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
> @@ -57,7 +57,7 @@ bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx)
>  	return ret;
>  }
>  
> -void rkvdec_free_rcb(struct rkvdec_core *core)
> +void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core)
>  {
>  	struct rkvdec_rcb_config *cfg = core->rcb_config;
>  	unsigned long virt_addr;
> @@ -76,12 +76,12 @@ void rkvdec_free_rcb(struct rkvdec_core *core)
>  		case RKVDEC_ALLOC_SRAM:
>  			virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
>  
> -			if (core->iommu_domain)
> -				iommu_unmap(core->iommu_domain, virt_addr, rcb_size);
> +			if (rkvdec->iommu_global_domain)
> +				iommu_unmap(rkvdec->iommu_global_domain, virt_addr, rcb_size);
>  			gen_pool_free(core->sram_pool, virt_addr, rcb_size);
>  			break;
>  		case RKVDEC_ALLOC_DMA:
> -			dma_free_coherent(core->dev,
> +			dma_free_coherent(rkvdec->main_core->dev,
>  					  rcb_size,
>  					  cfg->rcb_bufs[i].cpu,
>  					  cfg->rcb_bufs[i].dma);
> @@ -97,7 +97,8 @@ void rkvdec_free_rcb(struct rkvdec_core *core)
>  	core->rcb_config = NULL;
>  }
>  
> -int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
> +int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
> +			u32 width, u32 height,
>  			const struct rcb_size_info *size_info,
>  			size_t rcb_count)
>  {
> @@ -132,7 +133,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>  
>  		/* Try allocating an SRAM buffer */
>  		if (core->sram_pool) {
> -			if (core->iommu_domain)
> +			if (rkvdec->iommu_global_domain)
>  				rcb_size = ALIGN(rcb_size, SZ_4K);
>  
>  			cpu = gen_pool_dma_zalloc_align(core->sram_pool,
> @@ -142,11 +143,11 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>  		}
>  
>  		/* If an IOMMU is used, map the SRAM address through it */
> -		if (cpu && core->iommu_domain) {
> +		if (cpu && rkvdec->iommu_global_domain) {
>  			unsigned long virt_addr = (unsigned long)cpu;
>  			phys_addr_t phys_addr = dma;
>  
> -			ret = iommu_map(core->iommu_domain, virt_addr, phys_addr,
> +			ret = iommu_map(rkvdec->iommu_global_domain, virt_addr, phys_addr,
>  					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
>  			if (ret) {
>  				gen_pool_free(core->sram_pool,
> @@ -166,7 +167,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>  ram_fallback:
>  		/* Fallback to RAM */
>  		if (!cpu) {
> -			cpu = dma_alloc_coherent(core->dev,
> +			cpu = dma_alloc_coherent(rkvdec->main_core->dev,
>  						 rcb_size,
>  						 &dma,
>  						 GFP_KERNEL);
> @@ -189,7 +190,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
>  	return 0;
>  
>  err_alloc:
> -	rkvdec_free_rcb(core);
> +	rkvdec_free_rcb(rkvdec, core);
>  
>  	return ret;
>  }
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> index a12af9b7dc2b..d1149afe7fda 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
> @@ -8,6 +8,7 @@
>  
>  #include <linux/types.h>
>  
> +struct rkvdec_dev;
>  struct rkvdec_ctx;
>  struct rkvdec_core;
>  
> @@ -21,11 +22,12 @@ struct rcb_size_info {
>  	enum rcb_axis axis;
>  };
>  
> -int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
> +int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
> +			u32 width, u32 height,
>  			const struct rcb_size_info *size_info,
>  			size_t rcb_count);
>  dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
>  size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
>  int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
>  bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx);
> -void rkvdec_free_rcb(struct rkvdec_core *core);
> +void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core);
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> index c2818f1575ef..2930e9b64906 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
> @@ -1204,9 +1204,9 @@ static void rkvdec_device_run(void *priv)
>  	}
>  
>  	if (!rkvdec_rcb_buf_validate_size(ctx)) {
> -		rkvdec_free_rcb(ctx->core);
> +		rkvdec_free_rcb(ctx->dev, ctx->core);
>  
> -		ret = rkvdec_allocate_rcb(ctx->core,
> +		ret = rkvdec_allocate_rcb(ctx->dev, ctx->core,
>  					  ctx->decoded_fmt.fmt.pix_mp.width,
>  					  ctx->decoded_fmt.fmt.pix_mp.height,
>  					  ctx->dev->variant->rcb_sizes,
> @@ -1486,6 +1486,7 @@ static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec)
>  
>  static void rkvdec_iommu_restore(struct rkvdec_core *core)
>  {
> +	int ret;
>  	if (core->empty_domain) {
>  		/*
>  		 * To rewrite mapping into the attached IOMMU core, attach a new empty domain that
> @@ -1494,8 +1495,14 @@ static void rkvdec_iommu_restore(struct rkvdec_core *core)
>  		 * This is safely done in this interrupt handler to make sure no memory get mapped
>  		 * through the IOMMU while the empty domain is attached.
>  		 */
> -		iommu_attach_device(core->empty_domain, core->dev);
> +		iommu_detach_device(core->curr_ctx->dev->iommu_global_domain, core->dev);
> +		ret = iommu_attach_device(core->empty_domain, core->dev);
> +		if (ret)
> +			dev_warn(core->dev, "Cannot attach empty domain: %d\n", ret);
>  		iommu_detach_device(core->empty_domain, core->dev);
> +		ret = iommu_attach_device(core->curr_ctx->dev->iommu_global_domain, core->dev);
> +		if (ret)
> +			dev_warn(core->dev, "Cannot attach global domain: %d\n", ret);
>  	}
>  }
>  
> @@ -1858,6 +1865,8 @@ static int rkvdec_probe(struct platform_device *pdev)
>  
>  	core = &rkvdec->cores[rkvdec->core_count++];
>  
> +	core->id = rkvdec->core_count - 1;
> +
>  	platform_set_drvdata(pdev, rkvdec);
>  	core->dev = &pdev->dev;
>  	INIT_DELAYED_WORK(&core->watchdog_work, rkvdec_watchdog_func);
> @@ -1883,12 +1892,24 @@ static int rkvdec_probe(struct platform_device *pdev)
>  			return PTR_ERR(core->link);
>  	}
>  
> -	core->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
> -	if (core->iommu_domain) {
> +	if (iommu_get_domain_for_dev(&pdev->dev)) {
>  		core->empty_domain = iommu_paging_domain_alloc(core->dev);
>  
> -		if (!core->empty_domain)
> +		if (IS_ERR(core->empty_domain))
>  			dev_warn(core->dev, "cannot alloc new empty domain\n");
> +
> +		if (!rkvdec->iommu_global_domain) {
> +			rkvdec->iommu_global_domain = iommu_get_domain_for_dev(core->dev);
> +
> +			if (IS_ERR(rkvdec->iommu_global_domain)) {
> +				rkvdec->iommu_global_domain = NULL;
> +				dev_warn_once(core->dev, "cannot alloc new global domain\n");
> +			}
> +		}
> +
> +		ret = iommu_attach_device(rkvdec->iommu_global_domain, core->dev);
> +		if (ret)
> +			dev_warn(core->dev, "cannot attach global domain to core %d\n", core->id);
>  	}
>  
>  	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
> @@ -1961,7 +1982,7 @@ static void rkvdec_remove(struct platform_device *pdev)
>  		if (rkvdec->cores[i].empty_domain)
>  			iommu_domain_free(rkvdec->cores[i].empty_domain);
>  
> -		rkvdec_free_rcb(&rkvdec->cores[i]);
> +		rkvdec_free_rcb(rkvdec, &rkvdec->cores[i]);
>  	}
>  }
>  
> diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> index 4f042a367dc0..ccd766b220c7 100644
> --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
> @@ -135,7 +135,6 @@ struct rkvdec_core {
>  	void __iomem *link;
>  	struct delayed_work watchdog_work;
>  	struct gen_pool *sram_pool;
> -	struct iommu_domain *iommu_domain;
>  	struct iommu_domain *empty_domain;
>  	struct rkvdec_rcb_config *rcb_config;
>  	struct rkvdec_ctx *curr_ctx;
> @@ -155,6 +154,7 @@ struct rkvdec_dev {
>  	unsigned int available_core_count;
>  	spinlock_t cores_lock; /* serializes core list access */
>  	struct rkvdec_core *main_core;
> +	struct iommu_domain *iommu_global_domain;
>  };
>  
>  struct rkvdec_ctx {

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH] mm/arm: pgtable: remove young bit check for pte_valid_user
From: Russell King (Oracle) @ 2026-04-09 14:15 UTC (permalink / raw)
  To: Brian Ruley; +Cc: Steve Capper, Will Deacon, linux-arm-kernel, linux-kernel
In-Reply-To: <20260409125446.981747-1-brian.ruley@gehealthcare.com>

On Thu, Apr 09, 2026 at 03:54:45PM +0300, Brian Ruley wrote:
> Fixes cache desync, which can cause undefined instruction,
> translation and permission faults under heavy memory use.
> 
> This is an old bug introduced in commit 1971188aa196 ("ARM: 7985/1: mm:
> implement pte_accessible for faulting mappings"), which included a check
> for the young bit of a PTE. The underlying assumption was that old pages
> are not cached, therefore, `__sync_icache_dcache' could be skipped
> entirely.
> 
> However, under extreme memory pressure, page migrations happen
> frequently and the assumption of uncached "old" pages does not hold.

The first thing to point out is that PTEs that are marked as "old" are
not mapped into userspace. They need to take a fault to be marked
young, which will involve another call to set_pte(), at which point
pte_valid_user() should return true. Your assumption that this is
about "old" pages being uncached is totally incorrect - there has
never been such an assumption.

> Especially for systems that do not have swap, the migrated pages are
> unequivocally marked old. This presents a problem, as it is possible
> for the original page to be immediately mapped to another VA that
> happens to share the same cache index in VIPT I-cache (we found this
> bug on Cortex-A9). Without cache invalidation, the CPU will see the
> old mapping whose physical page can now be used for a different
> purpose, as illustrated below:



> 
>                 Core                      Physical Memory
>   +-------------------------------+     +------------------+
>   | TLB                           |     |                  |
>   |  VA_A 0xb6e6f -> pfn_q        |     | pfn_q: code      |
>   +-------------------------------+     +------------------+
>   | I-cache                       |
>   |  set[VA_A bits] | tag=pfn_q   |
>   +-------------------------------+
> 
> migrate (kcompactd):
>   1. copy pfn_q --> pfn_r
>   2. free pfn_q
>   3. pte: VA_a -> pfn_r
>   4. pte_mkold(pte) --> !young
>   5. ICIALLUIS skipped (because !young)

At this point, the hardware PTE will be set to zero and the TLB
invalidated. This _should_ mean that any future access should result
in a page permission fault being raised. That will then provoke the
MM to mark the PTE young, which will then result in set_ptes()
being called, and thus __sync_icache_dcache() will be called for
the _neew_ pte (which will be for pfn_r.)

> 
> pfn_src reused (OOM pressure):
>   pte: VA_B -> pfn_q (different code)
> 
> bug:
>                 Core                      Physical Memory
>   +-------------------------------+     +------------------+
>   | TLB (empty)                   |     | pfn_r: old code  |
>   +-------------------------------+     | pfn_q: new code  |
>   | I-cache                       |     +------------------+
>   |  set[VA_A bits] | tag=pfn_q   |<--- wrong instructions
>   +-------------------------------+
> 
> This was verified on ba16-based board (i.MX6Quad/Dual, Cortex-A9) by
> instrumenting the migration code to track recently migrated pages in a
> ring buffer and then dumping them in the undefined instruction fault
> handler. The bug can be triggered with `stress-ng':
> 
>   stress-ng --vm 4 --vm-bytes 2G --vm-method zero-one --verify
> 
> Note that the system we tested on has only 2G of memory, so the test
> triggered the OOM-killer in our case.

So you're saying that stress-ng doesn't reproduce this bug but triggers
the OOM-killer... confused.

Cortex-A9 has been around for a long time - I have systems that still
use Cortex-A9 every day without swap, and they have been rock solid.

If there was a bug like this, I would've expected to see problems, but
I'm not... so, I'm not convinced there's a problem here.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply

* Re: [PATCH v2 1/3] arm64: mm: Fix rodata=full block mapping support for realm guests
From: Catalin Marinas @ 2026-04-09 14:09 UTC (permalink / raw)
  To: Suzuki K Poulose
  Cc: Ryan Roberts, Will Deacon, David Hildenbrand (Arm), Dev Jain,
	Yang Shi, Jinjiang Tu, Kevin Brodsky, linux-arm-kernel,
	linux-kernel, stable
In-Reply-To: <d1ecba64-898f-433b-93d4-7a33b9c3f378@arm.com>

On Thu, Apr 09, 2026 at 10:38:03AM +0100, Suzuki K Poulose wrote:
> On 07/04/2026 18:21, Catalin Marinas wrote:
> > a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
> > introduced force_pte_mapping() but it just copied the logic in the
> > existing can_set_direct_map(). Looking at the linear_map_requires_bbml2
> > assignment, we get (!is_realm_world() && is_realm_world()) and it
> > cancels out, no effect on it but we don't get pte mappings either (even
> > if we don't have BBML2).
> 
> Yep, that's right.
> > 
> > I think we need at least some safety checks:
> > 
> > 1. BBML2_NOABORT support on the boot CPU - continue with the existing
> >     logic (as per Ryan's series)
> > 
> > 2. !system_supports_bbml2_noabort() - split in
> >     linear_map_maybe_split_to_ptes(). This does not currently happen
> >     because linear_map_requires_bbml2 may be false in the absence of
> >     rodata=full. Not sure how to fix this without some variable telling
> >     us how the linear map was mapped. The requires_bbml2 flag doesn't
> > 
> > 3. Panic in arm64_rsi_init() if !BBML2_NOABORT on the boot CPU _and_ we
> >     have block mappings already. People can avoid it with rodata=full
> 
> It looks like this will be a common case :-(
> 
> > 
> > 4. If (3) is a common case, a better alternative is to rewrite the
> >     linear map sometime after arm64_rsi_init() but before we call
> >     split_kernel_leaf_mapping().
> 
> We will explore this route.
> 
> The other option is to move the RSI detection (and the PSCI probe)
> earlier to be able to make better decisions early on. I will play with
> that a bit too.

I thought we could reuse linear_map_split_to_ptes() but this function
assumes that the primary CPU supports BBML2_NOABORT. To do this live,
we'd have to clone the active kernel pgtable hierarchy, switch to it and
then continue with the splitting. kasan_init_shadow() does a bit of this
but not fully as it only cares about the shadow mapping.

Hmm, maybe probing the RSI early is easier ;).

-- 
Catalin


^ permalink raw reply

* Re: [PATCH] media: cedrus: skip invalid H.264 reference list entries
From: Nicolas Dufresne @ 2026-04-09 14:00 UTC (permalink / raw)
  To: Pengpeng Hou, Maxime Ripard
  Cc: Paul Kocialkowski, Mauro Carvalho Chehab, Greg Kroah-Hartman,
	Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, linux-media,
	linux-staging, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <20260409223000.0-cedrus-h264-active-reply-pengpeng@iscas.ac.cn>

[-- Attachment #1: Type: text/plain, Size: 648 bytes --]

Le jeudi 09 avril 2026 à 22:30 +0800, Pengpeng Hou a écrit :
> Hi Paul,
> 
> Thanks, that makes sense.
> 
> I agree Cedrus should not silently skip an invalid index in the active
> portion of ref_pic_list0/ref_pic_list1.
> 
> I'll respin this to keep the check at the Cedrus use site rather than
> cedrus_try_ctrl(), but return -EINVAL when one of the active reference
> entries points past V4L2_H264_NUM_DPB_ENTRIES. Entries beyond
> num_ref_idx_l0_active_minus1 / num_ref_idx_l1_active_minus1 will still
> be ignored as before.

Please, let the discussion continue before respinning.

Nicolas

> 
> Thanks,
> Pengpeng
> 

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH] media: cedrus: skip invalid H.264 reference list entries
From: Nicolas Dufresne @ 2026-04-09 14:00 UTC (permalink / raw)
  To: Paul Kocialkowski, Pengpeng Hou
  Cc: mripard, mchehab, gregkh, wens, jernej.skrabec, samuel,
	linux-media, linux-staging, linux-arm-kernel, linux-sunxi,
	linux-kernel
In-Reply-To: <adeqkmA9VhaPkSAk@shepard>

[-- Attachment #1: Type: text/plain, Size: 4292 bytes --]

Le jeudi 09 avril 2026 à 15:33 +0200, Paul Kocialkowski a écrit :
> Hi,
> 
> On Tue 24 Mar 26, 16:08, Pengpeng Hou wrote:
> > Cedrus consumes H.264 ref_pic_list0/ref_pic_list1 entries from the
> > stateless slice control and later uses their indices to look up
> > decode->dpb[] in _cedrus_write_ref_list().
> > 
> > Rejecting such controls in cedrus_try_ctrl() would break existing
> > userspace, since stateless H.264 reference lists may legitimately carry
> > out-of-range indices for missing references. Instead, guard the actual
> > DPB lookup in Cedrus and skip entries whose indices do not fit the fixed
> > V4L2_H264_NUM_DPB_ENTRIES array.
> 
> Could you explain why it is legitimate that userspace would pass indices that
> are not in the dpb list? As far as I remember from the H.264 spec, the L0/L1
> lists are constructed from active references only and the number of items
> there
> should be given by num_ref_idx_l0_active_minus1/num_ref_idx_l1_active_minus1.
> We can tolerate invalid data beyond these indices, but certainly not as part
> of the indices that should be valid.
> 
> However I agree that cedrus_try_ctrl is maybe not the right place to check it
> since I'm not sure we are guaranteed that the slice params control will be
> checked before the new DPB (from the same request) is applied, so we might end
> up checking against the dpb from the previous decode request.
> 
> But I think we should error out and not just skip the invalid reference.

Its been a long time I haven't looked into this. But what happens here is that
once you lost a reference, the userspace DPB will hold a gap picture, which as
no backing storage. Since it has no backing storage, there is no cookie
(timestamp) associated with it. This gap picture will still make it to the
reference lists, since the position of the reference in the list is important
(you cannot just remove an item). It is an established practice in userspace to
simply fill the void with an invalid index, typically 0xff, which is always
invalid. Because that's what some userspace do, it became part of our ABI.

Decoders are expected be fault tolerant, though the tolerance level is hardware
specific, and so failing in the common code would be inappropriate (failing in
Cedrus could be acceptable, assuming it can't work with missing references,
which the implementation seems to be fine with).

Hantro G1 notably have a flag to report missing reference to the HW, and it will
manage concealement internally. G2/RKVDEC don't, and we try and pick the most
recent frame as a replacement backing storage, which most of the time minimises
the damages.

As future refinement, we need drivers in the long term to properly report the
damages (perhaps through additional RO request controls). As discussed few years
ago in the error handling wip for rkvdec, the V4L2 doc specify that any sort of
damages known to exist in a frame shall results in the ERROR flag being set. We
can deduce that the error flag with a payload of 0 indicates to userspace to not
use the frame (which typically happen on hard errors, or errror at entropy
decode staged) and ERROR flag with a correct payload signal some level of
corruption, and its left to the application to decide what to do.

Nicolas

> 
> All the best,
> 
> Paul
> 
> > 
> > This keeps the fix local to the driver use site and avoids out-of-bounds
> > reads from malformed or unsupported reference list entries.
> > 
> > Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> > ---
> >  drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 3 +++
> >  1 file changed, 3 insertions(+)
> > 
> > diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
> > @@ -210,6 +210,9 @@ static void _cedrus_write_ref_list(struct cedrus_ctx
> > *ctx,
> >  		u8 dpb_idx;
> >  
> >  		dpb_idx = ref_list[i].index;
> > +		if (dpb_idx >= V4L2_H264_NUM_DPB_ENTRIES)
> > +			continue;
> > +
> >  		dpb = &decode->dpb[dpb_idx];
> >  
> >  		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
> > -- 
> > 2.50.1
> > 

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply

* Re: [PATCH] mm/arm: pgtable: remove young bit check for pte_valid_user
From: Will Deacon @ 2026-04-09 13:56 UTC (permalink / raw)
  To: Brian Ruley
  Cc: Russell King, Steve Capper, Russell King, linux-arm-kernel,
	linux-kernel
In-Reply-To: <20260409125446.981747-1-brian.ruley@gehealthcare.com>

On Thu, Apr 09, 2026 at 03:54:45PM +0300, Brian Ruley wrote:
> Fixes cache desync, which can cause undefined instruction,
> translation and permission faults under heavy memory use.
> 
> This is an old bug introduced in commit 1971188aa196 ("ARM: 7985/1: mm:
> implement pte_accessible for faulting mappings"), which included a check
> for the young bit of a PTE. The underlying assumption was that old pages
> are not cached, therefore, `__sync_icache_dcache' could be skipped
> entirely.
> 
> However, under extreme memory pressure, page migrations happen
> frequently and the assumption of uncached "old" pages does not hold.
> Especially for systems that do not have swap, the migrated pages are
> unequivocally marked old. This presents a problem, as it is possible
> for the original page to be immediately mapped to another VA that
> happens to share the same cache index in VIPT I-cache (we found this
> bug on Cortex-A9). Without cache invalidation, the CPU will see the
> old mapping whose physical page can now be used for a different
> purpose, as illustrated below:
> 
>                 Core                      Physical Memory
>   +-------------------------------+     +------------------+
>   | TLB                           |     |                  |
>   |  VA_A 0xb6e6f -> pfn_q        |     | pfn_q: code      |
>   +-------------------------------+     +------------------+
>   | I-cache                       |
>   |  set[VA_A bits] | tag=pfn_q   |
>   +-------------------------------+
> 
> migrate (kcompactd):
>   1. copy pfn_q --> pfn_r
>   2. free pfn_q
>   3. pte: VA_a -> pfn_r
>   4. pte_mkold(pte) --> !young
>   5. ICIALLUIS skipped (because !young)
> 
> pfn_src reused (OOM pressure):
>   pte: VA_B -> pfn_q (different code)
> 
> bug:
>                 Core                      Physical Memory
>   +-------------------------------+     +------------------+
>   | TLB (empty)                   |     | pfn_r: old code  |
>   +-------------------------------+     | pfn_q: new code  |
>   | I-cache                       |     +------------------+
>   |  set[VA_A bits] | tag=pfn_q   |<--- wrong instructions
>   +-------------------------------+

(nit: Do you have pfn_r and pfn_q mixed up in the "Physical Memory" box?)

> This was verified on ba16-based board (i.MX6Quad/Dual, Cortex-A9) by
> instrumenting the migration code to track recently migrated pages in a
> ring buffer and then dumping them in the undefined instruction fault
> handler. The bug can be triggered with `stress-ng':
> 
>   stress-ng --vm 4 --vm-bytes 2G --vm-method zero-one --verify
> 
> Note that the system we tested on has only 2G of memory, so the test
> triggered the OOM-killer in our case.
> 
> Fixes: 1971188aa196 ("ARM: 7985/1: mm: implement pte_accessible for faulting mappings")
> Signed-off-by: Brian Ruley <brian.ruley@gehealthcare.com>
> ---
>  arch/arm/include/asm/pgtable.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
> index 6fa9acd6a7f5..e3a5b4a9a65f 100644
> --- a/arch/arm/include/asm/pgtable.h
> +++ b/arch/arm/include/asm/pgtable.h
> @@ -185,7 +185,7 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
>  #define pte_exec(pte)		(pte_isclear((pte), L_PTE_XN))
>  
>  #define pte_valid_user(pte)	\
> -	(pte_valid(pte) && pte_isset((pte), L_PTE_USER) && pte_young(pte))
> +	(pte_valid(pte) && pte_isset((pte), L_PTE_USER))

This patch is from twelve years ago, so please forgive me for having
forgotten all of the details. However, my recollection is that when using
the classic/!lpae format (as you will be on Cortex-A9), page aging is
implemented by using invalid (translation faulting) ptes for 'old'
mappings.

So in the case you describe, we may well elide the I-cache maintenance,
but won't we also put down an invalid pte? If we later take a fault
on that, we should then perform the cache maintenance when installing
the young entry (via ptep_set_access_flags()). The more interesting part
is probably when the mapping for 'VA_B' is installed to map 'pfn_q' but,
again, I would've expected the cache maintenance to happen just prior to
installing the valid (young) mapping.

Please can you help me to understand the problem better?

Will


^ permalink raw reply

* [PATCH v2] media: cedrus: reject invalid active H.264 ref indices
From: Pengpeng Hou @ 2026-04-09 13:30 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Paul Kocialkowski, Mauro Carvalho Chehab, Greg Kroah-Hartman,
	Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Nicolas Dufresne,
	linux-media, linux-staging, linux-arm-kernel, linux-sunxi,
	linux-kernel, pengpeng
In-Reply-To: <20260324080856.56787-1-pengpeng@iscas.ac.cn>

Cedrus consumes the active ref_pic_list0/ref_pic_list1 entries and uses
their indices to look up decode->dpb[] in _cedrus_write_ref_list().

Those active portions are the first
num_ref_idx_l0_active_minus1 + 1 / num_ref_idx_l1_active_minus1 + 1
entries in the two reference lists.

An out-of-range index in that active portion can therefore read past the
fixed V4L2_H264_NUM_DPB_ENTRIES array.

Checking this in cedrus_try_ctrl() is awkward because the request-local
DPB state may not have been applied yet. Instead, validate the active
entries at the actual Cedrus use site and fail setup with -EINVAL if one
points past decode->dpb[].

Entries beyond the active reference counts remain ignored as before, so
this does not change how Cedrus treats unused tail data in the
reference-list controls.

Fixes: 6eb9b758e307 ("media: cedrus: Add H264 decoding support")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
Changes since v1:
- reject invalid indices in the active reference list entries instead of
  silently skipping them
- keep the validation at the Cedrus use site, but propagate -EINVAL back
  through setup

 drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 32 ++++++++++++++--
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
index 3e2843ef6cce..58c411c580f3 100644
--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
@@ -186,10 +186,10 @@ static int cedrus_write_frame_list(struct cedrus_ctx *ctx,
 
 #define CEDRUS_MAX_REF_IDX	32
 
-static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
-				   struct cedrus_run *run,
-				   const struct v4l2_h264_reference *ref_list,
-				   u8 num_ref, enum cedrus_h264_sram_off sram)
+static int _cedrus_write_ref_list(struct cedrus_ctx *ctx,
+				  struct cedrus_run *run,
+				  const struct v4l2_h264_reference *ref_list,
+				  u8 num_ref, enum cedrus_h264_sram_off sram)
 {
 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
 	struct vb2_queue *cap_q;
@@ -210,6 +210,9 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
 		u8 dpb_idx;
 
 		dpb_idx = ref_list[i].index;
+		if (dpb_idx >= V4L2_H264_NUM_DPB_ENTRIES)
+			return -EINVAL;
+
 		dpb = &decode->dpb[dpb_idx];
 
 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
@@ -229,28 +232,30 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
 
 	size = min_t(size_t, ALIGN(num_ref, 4), sizeof(sram_array));
 	cedrus_h264_write_sram(dev, sram, &sram_array, size);
+
+	return 0;
 }
 
-static void cedrus_write_ref_list0(struct cedrus_ctx *ctx,
-				   struct cedrus_run *run)
+static int cedrus_write_ref_list0(struct cedrus_ctx *ctx,
+				  struct cedrus_run *run)
 {
 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
 
-	_cedrus_write_ref_list(ctx, run,
-			       slice->ref_pic_list0,
-			       slice->num_ref_idx_l0_active_minus1 + 1,
-			       CEDRUS_SRAM_H264_REF_LIST_0);
+	return _cedrus_write_ref_list(ctx, run,
+				      slice->ref_pic_list0,
+				      slice->num_ref_idx_l0_active_minus1 + 1,
+				      CEDRUS_SRAM_H264_REF_LIST_0);
 }
 
-static void cedrus_write_ref_list1(struct cedrus_ctx *ctx,
-				   struct cedrus_run *run)
+static int cedrus_write_ref_list1(struct cedrus_ctx *ctx,
+				  struct cedrus_run *run)
 {
 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
 
-	_cedrus_write_ref_list(ctx, run,
-			       slice->ref_pic_list1,
-			       slice->num_ref_idx_l1_active_minus1 + 1,
-			       CEDRUS_SRAM_H264_REF_LIST_1);
+	return _cedrus_write_ref_list(ctx, run,
+				      slice->ref_pic_list1,
+				      slice->num_ref_idx_l1_active_minus1 + 1,
+				      CEDRUS_SRAM_H264_REF_LIST_1);
 }
 
 static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx,
@@ -338,8 +343,8 @@ static void cedrus_skip_bits(struct cedrus_dev *dev, int num)
 	}
 }
 
-static void cedrus_set_params(struct cedrus_ctx *ctx,
-			      struct cedrus_run *run)
+static int cedrus_set_params(struct cedrus_ctx *ctx,
+			     struct cedrus_run *run)
 {
 	const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params;
 	const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params;
@@ -351,6 +356,7 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
 	size_t slice_bytes = vb2_get_plane_payload(src_buf, 0);
 	unsigned int pic_width_in_mbs;
 	bool mbaff_pic;
+	int ret;
 	u32 reg;
 
 	cedrus_write(dev, VE_H264_VLD_LEN, slice_bytes * 8);
@@ -393,11 +399,17 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
 
 	if ((slice->slice_type == V4L2_H264_SLICE_TYPE_P) ||
 	    (slice->slice_type == V4L2_H264_SLICE_TYPE_SP) ||
-	    (slice->slice_type == V4L2_H264_SLICE_TYPE_B))
-		cedrus_write_ref_list0(ctx, run);
+	    (slice->slice_type == V4L2_H264_SLICE_TYPE_B)) {
+		ret = cedrus_write_ref_list0(ctx, run);
+		if (ret)
+			return ret;
+	}
 
-	if (slice->slice_type == V4L2_H264_SLICE_TYPE_B)
-		cedrus_write_ref_list1(ctx, run);
+	if (slice->slice_type == V4L2_H264_SLICE_TYPE_B) {
+		ret = cedrus_write_ref_list1(ctx, run);
+		if (ret)
+			return ret;
+	}
 
 	// picture parameters
 	reg = 0;
@@ -478,6 +490,8 @@ static void cedrus_set_params(struct cedrus_ctx *ctx,
 		     VE_H264_CTRL_SLICE_DECODE_INT |
 		     VE_H264_CTRL_DECODE_ERR_INT |
 		     VE_H264_CTRL_VLD_DATA_REQ_INT);
+
+	return 0;
 }
 
 static enum cedrus_irq_status
@@ -531,9 +545,7 @@ static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 	if (ret)
 		return ret;
 
-	cedrus_set_params(ctx, run);
-
-	return 0;
+	return cedrus_set_params(ctx, run);
 }
 
 static int cedrus_h264_start(struct cedrus_ctx *ctx)
-- 
2.50.1



^ permalink raw reply related


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