Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 1/2] iommu/arm-smmu-v3: Do not continue in __arm_smmu_domain_inv_range()
From: Pranjal Shrivastava @ 2026-03-24 14:40 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, joro, jgg, linux-arm-kernel, iommu,
	linux-kernel
In-Reply-To: <20260321225041.11090-2-nicolinc@nvidia.com>

On Sat, Mar 21, 2026 at 03:50:40PM -0700, Nicolin Chen wrote:
> The loop in the __arm_smmu_domain_inv_range() is a while loop, not a for
> loop. So, using "continue" is wrong that would fail to move the needle.
> 
> Meanwhile, though the current command is skipped, the batch still has to
> go through arm_smmu_invs_end_batch() to be issued accordingly.
> 
> Thus, use "break" to fix the issue.
> 
> Fixes: 587bb3e56a2c ("iommu/arm-smmu-v3: Add arm_smmu_invs based arm_smmu_domain_inv_range()")
> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 

Reviewed-by: Pranjal Shrivastava <praan@google.com>

Thanks,
Praan


^ permalink raw reply

* Re: [PATCH v4 07/21] mm: have mmap_action_complete() handle the rmap lock and unmap
From: Vlastimil Babka (SUSE) @ 2026-03-24 14:38 UTC (permalink / raw)
  To: Lorenzo Stoakes (Oracle), Andrew Morton
  Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
	Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
	Alexandre Torgue, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
	David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
	Jan Kara, David Hildenbrand, Liam R . Howlett, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jann Horn, Pedro Falcato,
	linux-kernel, linux-doc, linux-hyperv, linux-stm32,
	linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
	target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <8d1ee8ebd3542d006a47e8382fb80cf5b57ecf10.1774045440.git.ljs@kernel.org>

On 3/20/26 23:39, Lorenzo Stoakes (Oracle) wrote:
> Rather than have the callers handle this both the rmap lock release and
> unmapping the VMA on error, handle it within the mmap_action_complete()
> logic where it makes sense to, being careful not to unlock twice.
> 
> This simplifies the logic and makes it harder to make mistake with this,
> while retaining correct behaviour with regard to avoiding deadlocks.
> 
> Also replace the call_action_complete() function with a direct invocation
> of mmap_action_complete() as the abstraction is no longer required.
> 
> Also update the VMA tests to reflect this change.
> 
> Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>

Nice simplification.

Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>



^ permalink raw reply

* Re: [PATCH 05/14] irqchip/gic-v3-its: Prepare shadow structures for KVM host deprivilege
From: Fuad Tabba @ 2026-03-24 14:36 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: alexandru.elisei, kvmarm, linux-arm-kernel, linux-kernel,
	android-kvm, catalin.marinas, dbrazdil, joey.gouly, kees,
	mark.rutland, maz, oupton, perlarsen, qperret, rananta, smostafa,
	suzuki.poulose, tglx, vdonnefort, bgrzesik, will, yuzenghui
In-Reply-To: <ab1jnHvmIeh0PExw@google.com>

Hi Seb,

<snip>

> > You should decouple the synchronous pointer swapping (which must be
> > locked) from the hypervisor notification (which can be done outside
> > the lock). Instead of executing the callback inside the critical
> > section, its_end_deprivilege should:
> > - Lock everything.
> > - Perform the pointer swaps in the host driver structures.
> > - Save the hyp_shadow pointers to a temporary array.
> > - Unlock everything.
>
> I am afraid you can't do that because you can have dropped commands &
> timeouts between these two steps. The driver might put commands in the
> swapped queue and they will timeout.

You're right, that won't work. Simply releasing the lock between the
pointer swap and the hypercall (HVC) isn't safe for two reasons:
- Timeouts (your point): If we swap the pointers to the new shadow
queue and drop the lock, another CPU might immediately try to queue a
command. It will trap to EL2 (cwriter_write), but because the HVC
hasn't finished initializing the hypervisor's internal state
(region->priv), EL2 will
drop the MMIO write. The host will then spin in
its_wait_for_range_completion waiting for the hardware to process a
command it never saw, resulting in a timeout.
- Stage-2 Aborts: Conversely, if we try to run the HVC before swapping
the pointers, the HVC will actively unmap (donate) the original
queue's memory to EL2. If the host is not locked and tries to write to
the old queue during this window, it will trigger a Stage-2 Data Abort
and boom!

We must pause host command submission to the affected ITS while the
HVC is running. That said, I still don't think it's acceptable to do
what you propose in this patch. This holds the raw_spin_lock_irqsave
for way too long, keeping local interrupts disabled while performing
slow hypercalls for the entire system.

I had a bit of a think, and I have two ideas, one is an improvement,
but not a full solution. It's simple though, and it might be enough
for now and I am more confident that it works. The second one is a
better solution I think, assuming it works and I haven't missed
anything :)

Option A: Granular Locking (Per-ITS Lock & HVC)

In this patch its_start_depriviledge effectively locks *all* ITS nodes
in the system simultaneously. Then, its_end_depriviledge calls the HVC
for every single ITS sequentially, while the CPU is still holding all
the locks with interrupts globally disabled. This makes this critical
section very long. Making it shorter is pretty straightforward i
think...

Instead of trying to decouple the pointer swap from the HVC, we can
start by reducing the scope of the lock. We remove the global locking
in its_start_depriviledge. Inside its_end_depriviledge, we process one
ITS at a time:
1. Disable local interrupts and lock one specific ITS
(raw_spin_lock_irqsave(&its->lock)).
2. Perform the pointer swap AND the HVC for this specific ITS.
3. Unlock and re-enable local interrupts (raw_spin_unlock_irqrestore).
4. Move to the next ITS in the list.

This should be simple to implement. It guarantees zero dropped
commands and zero aborts because the swap and HVC remain atomic.
However, the CPU executing the deprivilege still holds a raw spinlock
during a hypercall, but the duration is reduced to a single ITS node
rather than the entire thing.

Option B: Software Quiescence (Driver-Level Pausing)
To make it so that the HVC runs outside of an atomic context (with
local interrupts enabled), maybe we can teach the ITS driver to
voluntarily pause command submission without holding the raw spinlock.

I was thinking that we introduce a new state flag, e.g.,
is_vmm_migrating, to struct its_node. Every ITS command goes through
the BUILD_SINGLE_CMD_FUNC macro. We modify this macro so that if a CPU
tries to send a command and sees this flag is true, it temporarily
drops the lock, re-enables its interrupts, spins (cpu_relax()), and
retries.

The deprivilege sequence per ITS then becomes:
1. Lock: Acquire its->lock.
2. Swap & Pause: Swap the pointers to the shadow queue and set
its->is_vmm_migrating = true.
3. Unlock: Drop its->lock and re-enable interrupts. (Any other CPU
trying to send a command to this ITS will now safely spin and wait).
4. The HVC: Execute the slow hypercall safely outside of atomic context.
5. Resume: Re-acquire its->lock, set its->is_vmm_migrating = false,
and drop the lock. (This wakes up any spinning CPUs, and they
immediately send their commands to the newly registered shadow queue).

The HVC runs safely with local interrupts enabled, guaranteeing that
no commands are dropped or sent to unmapped memory. If a hardware
interrupt fires on another CPU that requires sending an ITS command
exactly while the HVC is running, that CPU will be forced to spin.
However, this is no worse than aquiring locks, where that CPU would
have been spinning waiting for the raw spinlock anyway.

What do you think?

If you like, I could hack something and we could discuss it some more.

Cheers,
/fuad


>
> > - Loop through the temporary array and call the KVM cb to notify EL2.
> >
> > You should probably split this patch into two. The first patch would
> > implement the freeze/unfreeze locking mechanism, and the second would
> > swap the driver's internal memory pointers to the shadow structures,
> > and invoke the KVM callback to lock down the real hardware.
> >
> > Cheers,
> > /fuad
> >
>
> Thanks,
> Sebastian
>
> > > +       if (ret) {
> > > +               its_free_shadow_tables(hyp_shadow);
> > > +               return ret;
> > > +       }
> > > +
> > > +       /* Switch the driver command queue to use the shadow and save the original */
> > > +       its->cmd_write = (its->cmd_write - its->cmd_base) +
> > > +               (struct its_cmd_block *)shadow.cmd_shadow;
> > > +       its->cmd_base = shadow.cmd_shadow;
> > > +
> > > +       /* Shadow the first level of the indirect tables */
> > > +       for (i = 0; i < GITS_BASER_NR_REGS; i++) {
> > > +               baser = shadow.tables[i].val;
> > > +
> > > +               if (!shadow.tables[i].shadow)
> > > +                       continue;
> > > +
> > > +               baser_phys = virt_to_phys(shadow.tables[i].shadow);
> > > +               if (IS_ENABLED(CONFIG_ARM64_64K_PAGES) && (baser_phys >> 48))
> > > +                       baser_phys = GITS_BASER_PHYS_52_to_48(baser_phys);
> > > +
> > > +               its->tables[i].val &= ~GENMASK(47, 12);
> > > +               its->tables[i].val |= baser_phys;
> > > +               its->tables[i].base = shadow.tables[i].shadow;
> > > +       }
> > > +
> > > +       return 0;
> > > +}
> > > +
> > > +int its_end_depriviledge(int ret_pkvm_finalize, unsigned long *flags, its_init_emulate cb)
> > > +{
> > > +       struct its_node *its;
> > > +       int i = 0, ret = 0;
> > > +
> > > +       if (!flags || !cb)
> > > +               return -EINVAL;
> > > +
> > > +       list_for_each_entry(its, &its_nodes, entry) {
> > > +               if (!ret_pkvm_finalize && !ret)
> > > +                       ret = its_switch_to_shadow_locked(its, cb);
> > > +
> > > +               raw_spin_unlock_irqrestore(&its->lock, flags[i++]);
> > > +       }
> > > +
> > > +       kfree(flags);
> > > +       raw_spin_unlock(&its_lock);
> > > +
> > > +       return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(its_end_depriviledge);
> > > +
> > >  static int __init its_probe_one(struct its_node *its)
> > >  {
> > >         u64 baser, tmp;
> > > diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> > > index 0225121f3013..40457a4375d4 100644
> > > --- a/include/linux/irqchip/arm-gic-v3.h
> > > +++ b/include/linux/irqchip/arm-gic-v3.h
> > > @@ -657,6 +657,30 @@ static inline bool gic_enable_sre(void)
> > >         return !!(val & ICC_SRE_EL1_SRE);
> > >  }
> > >
> > > +/*
> > > + * The ITS_BASER structure - contains memory information, cached
> > > + * value of BASER register configuration and ITS page size.
> > > + */
> > > +struct its_baser {
> > > +       void            *base;
> > > +       void            *shadow;
> > > +       u64             val;
> > > +       u32             order;
> > > +       u32             psz;
> > > +};
> > > +
> > > +struct its_shadow_tables {
> > > +       struct its_baser        tables[GITS_BASER_NR_REGS];
> > > +       void                    *cmd_shadow;
> > > +       void                    *cmd_original;
> > > +       size_t                  cmdq_len;
> > > +};
> > > +
> > > +typedef int (*its_init_emulate)(phys_addr_t its_phys_base, struct its_shadow_tables *shadow);
> > > +
> > > +void *its_start_depriviledge(void);
> > > +int its_end_depriviledge(int ret, unsigned long *flags, its_init_emulate cb);
> > > +
> > >  #endif
> > >
> > >  #endif
> > > --
> > > 2.53.0.473.g4a7958ca14-goog
> > >


^ permalink raw reply

* Re: [PATCH] firmware: arm_scmi: clock: Relax check in scmi_clock_protocol_init
From: Cristian Marussi @ 2026-03-24 14:35 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Cristian Marussi, Sudeep Holla, Peng Fan (OSS), Jacky Bai,
	arm-scmi, linux-arm-kernel, linux-kernel, Peng Fan
In-Reply-To: <CAMuHMdVcE439Cyn-TCoioLZXP-YpqObZ0UF8F2NvMCZ41eO6QQ@mail.gmail.com>

On Tue, Mar 24, 2026 at 02:15:36PM +0100, Geert Uytterhoeven wrote:
> Hi Cristian,

Hi Geert,

> 
> On Tue, 24 Mar 2026 at 09:41, Cristian Marussi <cristian.marussi@arm.com> wrote:
> > On Tue, Mar 24, 2026 at 07:49:22AM +0000, Sudeep Holla wrote:
> > > On Tue, Mar 24, 2026 at 02:24:14PM +0800, Peng Fan (OSS) wrote:
> > > > On i.MX95, the SCMI Clock protocol defines several reserved clock IDs that
> > > > are not backed by real clock devices
> > > > (see arch/arm64/boot/dts/freescale/imx95-clock.h).
> > > >
> > > > For these reserved IDs, the SCMI firmware correctly returns NOT_FOUND in
> > > > response to the CLOCK_ATTRIBUTES command. According to the SCMI Clock
> > > > specification, NOT_FOUND is expected when a clock_id does not correspond to
> > > > a valid clock device.
> > > >
> > > > The recent hardening added in scmi_clock_protocol_init() treats any error
> > > > return as fatal, causing SCMI clock probe to fail and preventing i.MX9
> > > > platforms from booting.
> > > >
> > > > Relax the check so that -ENOENT is treated as a non-fatal condition.
> > >
> > > I understand the use-case and the fix here, but still wonder if this
> > > should be treated as quirk or handle it in the core. I am inclined to
> > > latter as reserved SCMI clock/resource ID seems to be trend in its usage
> > > and hard to classify as quirks.
> > >
> > > Cristain, agree or have a different view ?
> >
> > I was just replying...
> >
> > Looking at the spec 3.6.2.5 CLOCK_ATTRIBUTES
> >
> > "This command returns the attributes that are associated with a specific clock. An agent might be allowed access to only
> > a subset of the clocks available in the system. The platform must thus guarantee that clocks that an agent cannot access
> > are not visible to it."
> >
> > ...not sure if this sheds some light or it is ambiguos anyway...I'd say that
> > NOT_FOUND does NOT equate to be invisible...
> >
> > ...BUT at the same time I think that this practice of exposing a non-contiguos
> > set of resources IDs (a set with holes in it) is the a well-known spec-loophole
> > used by many vendors to deploy one single FW image across all of their platforms
> > without having to reconfigure their reosurces IDs ro expose a common set of
> > contiguos IDs like the spec would suggest...
> >
> > Having said that, since we unfortunately left this door open in the
> > implementation, now this loophole has become common practice
> > apparently...
> 
> When I first read that paragraph, I was also confused.
> What does "not visible" mean?
>   - Not present in the clock ID space exposed to that client of
>     the system?
>     Yeah, multiple different sequences of contiguous IDs, depending
>     on client!

Yes that is the most spec-compliant interpretation usually; in general
across all protocols the SCMI server, through customized enumeration
results, should provide a per-agent view of the system: this should help
handling shared or virtualized resources, since the agent always see
only the 'illusion' provided by the server...

...under this assumption if you dont even need a resource at all (not
RW nor RO) you should NOT even be able to see it...this in turn of
course means that in order to expose a contiguous set of IDs you should
be able to properly configure at build time the FW resources on a per
platform basis...

>   - Return failure on CLOCK_ATTRIBUTES?
>     Which is what implementations seem to do.

Yes this is what is done leveraging the gap in the implementation...I am
not sure that the non-contiguous set of IDs is supported if not by
chance as of now :P (especially in other protocols)

> 
> The next step in the fun is when the system actually needs to know the
> clock rate of such a clock...

Well...that seems a bit of wishful thinking ...

...sort of a Schrödinger's clock :P .. it is NOT_FOUND but does have rates ?

Thanks,
Cristian


^ permalink raw reply

* Re: [PATCH rc] iommu/arm-smmu-v3: Drain in-flight fault handlers
From: Will Deacon @ 2026-03-24 14:35 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Lu Baolu, Kevin Tian, Nicolin Chen, robin.murphy, joro, praan,
	mmarrid, kees, Alexander.Grest, smostafa, linux-arm-kernel, iommu,
	linux-kernel, bbiber, skaestle
In-Reply-To: <20260324141716.GB7340@nvidia.com>

On Tue, Mar 24, 2026 at 11:17:16AM -0300, Jason Gunthorpe wrote:
> On Tue, Mar 24, 2026 at 02:04:03PM +0000, Will Deacon wrote:
> > Sorry, that was sloppy terminology on my part. I'm trying to reason about
> > faults that are generated by accesses that were translated with the
> > page-tables of the old domain being reported once we think we are using
> > the new domain.
> 
> It doesn't matter.
> 
> If a concurrent fault is resolving on the old domain and it completes
> after the STE is in the new domain the device will restart and if the
> IOVA is still non-present it will refault. This is normal and fine.
> 
> If it is resolving on the new domain and the new domain has a present
> PTE so the PRI is spurious then the fault handler should NOP it and
> restart the device.

Hmm, I can see that working out if both domains expect faults, but if
I'm switching to a domain without a handler wouldn't I be better off
draining the outstanding faults generated on the old domain first?
Otherwise, won't we see a bunch of noise from the eventq thread as
it dumps unexpected events to the console?

Will


^ permalink raw reply

* [PATCH] arm64: dts: renesas: sparrow-hawk: Reserve first 128 MiB of DRAM
From: Marek Vasut @ 2026-03-24 14:33 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Marek Vasut, stable, Conor Dooley, Geert Uytterhoeven,
	Krzysztof Kozlowski, Magnus Damm, Rob Herring, devicetree,
	linux-kernel, linux-renesas-soc

Mark the first 128 MiB of DRAM as reserved. The first 128 MiB of DRAM
may optionally be used by TFA and other firmware for its own purposes,
and in such case, Linux must not use this memory.

On this platform, U-Boot runs in EL3 and starts TFA BL31 and Linux from
a single combined fitImage. U-Boot has full access to all memory in the
0x40000000..0xbfffffff range, as well memory in the memory banks in the
64-bit address ranges, and therefore U-Boot patches this full complete
view of platform memory layout into the DT that is passed to the next
stage.

The next stage is TFA BL31 and then the Linux kernel. The TFA BL31 does
not modify the DT passed from U-Boot to TFA BL31 and then to Linux with
any new reserved-memory {} node to reserve memory areas used by the TFA
BL31 to prevent the next stage from using those areas, which lets Linux
to use all of the available DRAM as described in the DT that was passed
in by U-Boot, including the areas that are newly utilized by TFA BL31.

In case of high DRAM utilization, for example in case of four instances
of "memtester 3900M" running in parallel, unless the memory used by TFA
BL31 is properly reserved, Linux may use and corrupt the memory used by
TFA BL31, which would often lead to system becoming unresponsive.

Until TFA BL31 can properly fill its own reserved-memory node into the
DT, and to assure older versions of TFA BL31 do not cause problems, add
explicitly reserved-memory {} node which prevents Linux from using the
first 128 MiB of DRAM.

Note that TFA BL31 can be adjusted to use different memory areas, this
newly added reserved-memory {} node follows longer-term practice on the
R-Car SoCs where the first 128 MiB of DRAM is reserved for firmware use.
In case user does modify TFA BL31 to use different memory ranges, they
must either use a future version of TFA BL31 which properly patches a
reserved-memory {} node into the DT, or they must adjust the address
ranges of this reserved-memory {} node accordingly.

Fixes: a719915e76f2 ("arm64: dts: renesas: r8a779g3: Add Retronix R-Car V4H Sparrow Hawk board support")
Cc: stable@vger.kernel.org
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
---
Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Magnus Damm <magnus.damm@gmail.com>
Cc: Rob Herring <robh@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-renesas-soc@vger.kernel.org
---
 arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts
index bcf8270a3ed9a..714fcaf8a846e 100644
--- a/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts
+++ b/arch/arm64/boot/dts/renesas/r8a779g3-sparrow-hawk.dts
@@ -118,6 +118,17 @@ memory@600000000 {
 		reg = <0x6 0x00000000 0x1 0x00000000>;
 	};
 
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		tfa@40000000 {
+			reg = <0x0 0x40000000 0x0 0x8000000>;
+			no-map;
+		};
+	};
+
 	/* Page 27 / DSI to Display */
 	dp-con {
 		compatible = "dp-connector";
-- 
2.53.0



^ permalink raw reply related

* Re: [PATCH] arm64: dts: imx8mp-debix-model-a: Correct PAD settings for pmicirqgrp
From: Frank Li @ 2026-03-24 14:32 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Peng Fan (OSS), Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Marco Felsch, Daniel Scally, devicetree, imx, linux-arm-kernel,
	linux-kernel, Peng Fan, Kieran Bingham, Stefan Klug
In-Reply-To: <20260324093850.GA2351719@killaraus.ideasonboard.com>

On Tue, Mar 24, 2026 at 11:38:50AM +0200, Laurent Pinchart wrote:
> Hi Peng,
>
> Thank you for the patch.
>
> On Tue, Mar 24, 2026 at 11:16:13AM +0800, Peng Fan (OSS) wrote:
> > From: Peng Fan <peng.fan@nxp.com>
> >
> > With commit 5d0efaf47ee90 ("regulator: pca9450: Correct interrupt type"),
> > there is interrupt storm for i.MX8MP DEBIX Model A. Per schematic, there
> > is no on board PULL-UP resistors for GPIO1_IO03, so need to set PAD
> > PUE and PU together to make pull up work properly.
> >
> > Fixes: c86d350aae68e ("arm64: dts: Add device tree for the Debix Model A Board")
> > Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Closes: https://lore.kernel.org/all/20260323105858.GA2185714@killaraus.ideasonboard.com/
> > Signed-off-by: Peng Fan <peng.fan@nxp.com>
>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> Frank, would you be able to handle this as a v7.0 regression fix ?

I just sent out fix pull request for v7.0. Wait for few days for
Dan, Kieran, Stefa's confirm.

Frank

>
> I think the same is needed for imx8mp-debix-som-a.dtsi, but I can't
> confirm it as I don't have the schematics for the SoM, neither do I have
> access to the board.
>
> Dan, Kieran, Stefan, could one of you check if you get an interrupt
> storm from the PMIC on v7.0 ?
>
> > ---
> >  arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts
> > index 9422beee30b29c5a551b08476c80fbff96af3439..df7489587e48ed0c678f11291f6f2b77082ade95 100644
> > --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts
> > +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts
> > @@ -440,7 +440,7 @@ MX8MP_IOMUXC_SAI5_RXC__I2C6_SDA					0x400001c3
> >
> >  	pinctrl_pmic: pmicirqgrp {
> >  		fsl,pins = <
> > -			MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03				0x41
> > +			MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03				0x000001c0
> >  		>;
> >  	};
> >
> >
> > ---
> > base-commit: 09c0f7f1bcdbc3c37a5a760cbec76bf18f278406
> > change-id: 20260324-imx8mp-dts-fix-512530fe4dcd
>
> --
> Regards,
>
> Laurent Pinchart


^ permalink raw reply

* Re: [PATCH v4 06/21] mm/vma: remove superfluous map->hold_file_rmap_lock
From: Vlastimil Babka (SUSE) @ 2026-03-24 14:31 UTC (permalink / raw)
  To: Lorenzo Stoakes (Oracle), Andrew Morton
  Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
	Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
	Alexandre Torgue, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
	David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
	Jan Kara, David Hildenbrand, Liam R . Howlett, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jann Horn, Pedro Falcato,
	linux-kernel, linux-doc, linux-hyperv, linux-stm32,
	linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
	target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <42c3fbb701e361a17193ecda0d2dabcc326288a5.1774045440.git.ljs@kernel.org>

On 3/20/26 23:39, Lorenzo Stoakes (Oracle) wrote:
> We don't need to reference this field, it's confusing as it duplicates
> mmap_action->hide_from_rmap_until_complete, so thread the mmap_action
> through to __mmap_new_vma() instead and use the same field consistently.
> 
> Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>

Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>



^ permalink raw reply

* Re: [PATCH v4 05/21] mm: switch the rmap lock held option off in compat layer
From: Vlastimil Babka (SUSE) @ 2026-03-24 14:26 UTC (permalink / raw)
  To: Lorenzo Stoakes (Oracle), Andrew Morton
  Cc: Jonathan Corbet, Clemens Ladisch, Arnd Bergmann,
	Greg Kroah-Hartman, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
	Dexuan Cui, Long Li, Alexander Shishkin, Maxime Coquelin,
	Alexandre Torgue, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Bodo Stroesser, Martin K . Petersen,
	David Howells, Marc Dionne, Alexander Viro, Christian Brauner,
	Jan Kara, David Hildenbrand, Liam R . Howlett, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jann Horn, Pedro Falcato,
	linux-kernel, linux-doc, linux-hyperv, linux-stm32,
	linux-arm-kernel, linux-mtd, linux-staging, linux-scsi,
	target-devel, linux-afs, linux-fsdevel, linux-mm, Ryan Roberts
In-Reply-To: <dda74230d26a1fcd79a3efab61fa4101dd1cac64.1774045440.git.ljs@kernel.org>

On 3/20/26 23:39, Lorenzo Stoakes (Oracle) wrote:
> In the mmap_prepare compatibility layer, we don't need to hold the rmap
> lock, as we are being called from an .mmap handler.
> 
> The .mmap_prepare hook, when invoked in the VMA logic, is called prior to
> the VMA being instantiated, but the completion hook is called after the VMA
> is linked into the maple tree, meaning rmap walkers can reach it.
> 
> The mmap hook does not link the VMA into the tree, so this cannot happen.
> 
> Therefore it's safe to simply disable this in the mmap_prepare
> compatibility layer.
> 
> Also update VMA tests code to reflect current compatibility layer state.
> 
> Signed-off-by: Lorenzo Stoakes (Oracle) <ljs@kernel.org>

Acked-by: Vlastimil Babka (SUSE) <vbabka@kernel.org>

a typo fix below, Andrew can fix locally?

> ---
>  mm/util.c                       |  6 ++++-
>  tools/testing/vma/include/dup.h | 42 +++++++++++++++++----------------
>  2 files changed, 27 insertions(+), 21 deletions(-)
> 
> diff --git a/mm/util.c b/mm/util.c
> index a2cfa0d77c35..182f0f5cc400 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -1204,6 +1204,7 @@ int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
> 
>  		.action.type = MMAP_NOTHING, /* Default */
>  	};
> +	struct mmap_action *action = &desc.action;
>  	int err;
> 
>  	err = vfs_mmap_prepare(file, &desc);
> @@ -1214,8 +1215,11 @@ int compat_vma_mmap(struct file *file, struct vm_area_struct *vma)
>  	if (err)
>  		return err;
> 
> +	/* being invoked from .mmmap means we don't have to enforce this. */

				.mmap

> +	action->hide_from_rmap_until_complete = false;
> +
>  	set_vma_from_desc(vma, &desc);
> -	err = mmap_action_complete(vma, &desc.action);
> +	err = mmap_action_complete(vma, action);
>  	if (err) {
>  		const size_t len = vma_pages(vma) << PAGE_SHIFT;
> 


^ permalink raw reply

* Re: [PATCH 5/5] pinctrl: sunxi: a523: add missing IRQ bank (plus old DT workaround)
From: Andre Przywara @ 2026-03-24 14:22 UTC (permalink / raw)
  To: wens
  Cc: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Jernej Skrabec, Samuel Holland, Michal Piekos, linux-gpio,
	devicetree, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <CAGb2v648WLXK9KjXcCRKy_mQGMkn8mhxKHSukh-WC4i=sXZGbg@mail.gmail.com>

Hi Chen-Yu,

many thanks for having a look!

On 3/23/26 18:41, Chen-Yu Tsai wrote:
> On Mon, Mar 23, 2026 at 7:02 PM Andre Przywara <andre.przywara@arm.com> wrote:
>>
>> The Allwinner A532 SoC implements 10 GPIO banks, each of which is
>> interrupt capable. However the first bank (PortA) is skipped, so the
>> indicies of those banks range from 1 to 10, not 0 to 9.
>> We described the skipped bank correctly, but missed that for the IRQ
>> banks, where we rely on the IRQ bank index to be aligned with the MMIO
>> register offset, starting at 0x200.
>>
>> Correct that by increasing the number of IRQ banks to 11, to cover both
>> the first skipped one, but also the last one (PortK). This fixes a bug
>> where the interrupt numbers would be off-by-one, due to that
>> mis-enumeration.
>> The big caveat is that now old DTs break the kernel, since they only
>> provide 10 interrupts, and the driver bails out entirely due to the last
>> missing one. So add a workaround for this particular case, where we
>> detect the requirement for 11 banks, but only 10 interrupts provided,
>> and continue with 10 IRQs, albeit emitting a warning about a DT update.
>> This would still be broken in terms of interrupt assignment, but it was
>> broken the whole time before, so it's not a regression.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>   drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c |  2 +-
>>   drivers/pinctrl/sunxi/pinctrl-sunxi.c       | 22 +++++++++++++--------
>>   2 files changed, 15 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c
>> index b6f78f1f30ac..a1d157de53d2 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c
>> @@ -17,7 +17,7 @@ static const u8 a523_nr_bank_pins[SUNXI_PINCTRL_MAX_BANKS] =
>>   /*       PA  PB  PC  PD  PE  PF  PG  PH  PI  PJ  PK */
>>          {  0, 15, 17, 24, 16,  7, 15, 20, 17, 28, 24 };
>>
>> -static const unsigned int a523_irq_bank_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
>> +static const unsigned int a523_irq_bank_map[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
> 
> Actually you don't even need this, since this is a linear mapping.
> 
>  From sunxi_irq_hw_bank_num():
> 
>      if (!desc->irq_bank_map)
>              return bank;
>      else
>              return desc->irq_bank_map[bank];

Yeah, I was wondering about that as well, and there are other cases were 
we wouldn't need the map, espeically in the PRMC pinctrl instances. I 
might add a separate patch for that.

>>   static const u8 a523_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
>>   /*       PA  PB  PC  PD  PE  PF  PG  PH  PI  PJ  PK */
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> index 6a86b7989b25..ffee79397590 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> @@ -19,6 +19,7 @@
>>   #include <linux/irqdomain.h>
>>   #include <linux/of.h>
>>   #include <linux/of_clk.h>
>> +#include <linux/of_irq.h>
>>   #include <linux/platform_device.h>
>>   #include <linux/regulator/consumer.h>
>>   #include <linux/slab.h>
>> @@ -1582,6 +1583,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
>>          struct sunxi_pinctrl *pctl;
>>          struct pinmux_ops *pmxops;
>>          int i, ret, last_pin, pin_idx;
>> +       int num_irq_banks;
>>          struct clk *clk;
>>
>>          pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
>> @@ -1715,16 +1717,20 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
>>                  goto gpiochip_error;
>>          }
>>
>> -       pctl->irq = devm_kcalloc(&pdev->dev,
>> -                                pctl->desc->irq_banks,
>> -                                sizeof(*pctl->irq),
>> -                                GFP_KERNEL);
>> +       num_irq_banks = pctl->desc->irq_banks;
>> +       /* Workaround for old A523 DT, exposing one less interrupt. */
>> +       if (num_irq_banks == 11 && of_irq_count(node) < 11) {
>> +               num_irq_banks = 10;
>> +               pr_warn("Not enough PIO interrupts, please update your DT!\n");
>> +       }
> 
> I would probably make the check universal, and also use dev_warn().
> 
>      num_irq_banks = of_irq_count(node);
>      if (num_irq_banks != pctrl->desc->irq_banks) {
>          dev_warn(&pdev->dev, "Incorrect number of PIO interrupts,
> please update your DT!\n");
>          num_irq_banks = min(num_irq_banks, pctrl->desc->irq_banks);
>      }

Ah, nice one, that's of course much better. But I see that there is 
other code using desc->irq_banks, and if the array allocation is 
different, that will not end well. I will check how we can use 
num_irq_banks there as well.

Thanks!
Andre



> 
> Otherwise,
> 
> Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
> 
> 
>> +       pctl->irq = devm_kcalloc(&pdev->dev, num_irq_banks,
>> +                                sizeof(*pctl->irq), GFP_KERNEL);
>>          if (!pctl->irq) {
>>                  ret = -ENOMEM;
>>                  goto gpiochip_error;
>>          }
>>
>> -       for (i = 0; i < pctl->desc->irq_banks; i++) {
>> +       for (i = 0; i < num_irq_banks; i++) {
>>                  pctl->irq[i] = platform_get_irq(pdev, i);
>>                  if (pctl->irq[i] < 0) {
>>                          ret = pctl->irq[i];
>> @@ -1733,7 +1739,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
>>          }
>>
>>          pctl->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev),
>> -                                               pctl->desc->irq_banks * IRQ_PER_BANK,
>> +                                               num_irq_banks * IRQ_PER_BANK,
>>                                                  &sunxi_pinctrl_irq_domain_ops, pctl);
>>          if (!pctl->domain) {
>>                  dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
>> @@ -1741,7 +1747,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
>>                  goto gpiochip_error;
>>          }
>>
>> -       for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
>> +       for (i = 0; i < (num_irq_banks * IRQ_PER_BANK); i++) {
>>                  int irqno = irq_create_mapping(pctl->domain, i);
>>
>>                  irq_set_lockdep_class(irqno, &sunxi_pinctrl_irq_lock_class,
>> @@ -1751,7 +1757,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
>>                  irq_set_chip_data(irqno, pctl);
>>          }
>>
>> -       for (i = 0; i < pctl->desc->irq_banks; i++) {
>> +       for (i = 0; i < num_irq_banks; i++) {
>>                  /* Mask and clear all IRQs before registering a handler */
>>                  writel(0, pctl->membase +
>>                            sunxi_irq_ctrl_reg_from_bank(pctl->desc, i));
>> --
>> 2.43.0
>>
>>



^ permalink raw reply

* Re: [PATCH RESEND v2] arm64: dts: rockchip: configure hdmirx in Rock 5 ITX
From: Heiko Stuebner @ 2026-03-24 14:18 UTC (permalink / raw)
  To: Pedro Alves
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	linux-arm-kernel, linux-rockchip, linux-kernel, Pedro Alves
In-Reply-To: <20260323-radxa-r5-itx-hdmirx-v2-1-c52501909577@pta2002.com>

Am Montag, 23. März 2026, 10:25:33 Mitteleuropäische Normalzeit schrieb Pedro Alves:
> The Radxa Rock 5 ITX board exposes an HDMI input exactly the same way as
> the Rock 5B, but this was not reflected in its DTS.
> 
> Change the rk3588-rock-5-itx to configure and enable the hdmi_receiver
> and hdmi_receiver_cma nodes.
> 
> The hot-plug detection (HPD) pin keeps the hdmirx_det name rather than
> the hdmirx_hpd name used in other boards since that is what matches the
> official schematics (HDMIIRX_DET_L).
> 
> The configurations were confirmed to be identical on the downstream
> Radxa kernel, and this has been tested to work on a Rock 5 ITX board
> running kernel 6.19.3.
> 
> Signed-off-by: Pedro Alves <pta2002@pta2002.com>
> ---
> Tested with the following commands:
> 
> v4l2-ctl --verbose -d /dev/video4 \
>   --set-fmt-video=width=3840,height=2160,pixelformat='BGR3' \
>   --stream-mmap=4 --stream-skip=3 --stream-count=20 \
>   --stream-to=hdmiin.raw --stream-poll
> 
> ffmpeg -f rawvideo -vcodec rawvideo -s 3840x2160 -r 30 -pix_fmt bgr24 \
>   -i hdmiin.raw output.mp4
> ---
> Changes in v2:
> - Updated dts spacing to match coding style
> - Reverted pin naming to hdmirx_det to match schematics
>   - Didn't end up changing other boards to match. There are quite a few
>     others, so I'll probably send a separate patch for that.
> 
> - Link to v1: https://lore.kernel.org/r/20260304-radxa-r5-itx-hdmirx-v1-1-f77bf1f7ce03@pta2002.com
> ---
>  arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts
> index 172aeabba72a..8e0eead7d223 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5-itx.dts
> @@ -349,6 +349,18 @@ &hdmi1_sound {
>  	status = "okay";
>  };
>  
> +&hdmi_receiver_cma {
> +	status = "okay";
> +};
> +
> +&hdmi_receiver {
> +	pinctrl-0 = <&hdmim1_rx_cec &hdmim1_rx_hpdin &hdmim1_rx_scl &hdmim1_rx_sda &hdmirx_det>;
> +	pinctrl-names = "default";
> +	hpd-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_LOW>;

as said before, please also add a pinctrl setting for this pin.

gpio1_c6 is not part of the main hdmirx set of pins, hence needs an
additional pinctrl entry to configure it as gpio and possibly set any
additional pull settings.

And yes the pinctrl-driver does "implcitly" set the gpio-mode when
a gpio is requested, but our more modern approach is to always have
a real pinctrl entry even for gpios.


Heiko




^ permalink raw reply

* Re: [PATCH] KVM: arm64: Inject UNDEF when host is executing an smc with imm16 != 0
From: Vincent Donnefort @ 2026-03-24 14:18 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: kvmarm, linux-arm-kernel, linux-kernel, android-kvm,
	catalin.marinas, joey.gouly, mark.rutland, maz, oupton,
	suzuki.poulose, tabba, will, yuzenghui
In-Reply-To: <acKbLtb288sABYA4@google.com>

On Tue, Mar 24, 2026 at 02:09:50PM +0000, Vincent Donnefort wrote:
> On Tue, Mar 24, 2026 at 02:06:40PM +0000, Vincent Donnefort wrote:
> > On Tue, Mar 24, 2026 at 01:57:28PM +0000, Sebastian Ene wrote:
> > > The ARM Service Calling Convention (SMCCC) specifies that the function
> > > identifier and parameters should be passed in registers, leaving the
> > > 16-bit immediate field of the SMC instruction un-handled.
> > > Currently, our pKVM handler ignores the immediate value, which could lead
> > > to non-compliant software relying on implementation-defined behavior.
> > > Enforce the host kernel running under pKVM to use an immediate value
> > > of 0 by decoding the ISS from the ESR_EL2 and inject an undefined
> > > instruction exception back to the caller.
> > > 
> > > Signed-off-by: Sebastian Ene <sebastianene@google.com>
> > > ---
> > >  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 7 ++++++-
> > >  1 file changed, 6 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > > index e7790097db93..ff6a90a4a4c7 100644
> > > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > > @@ -756,13 +756,18 @@ static bool handle_host_mte(u64 esr)
> > >  void handle_trap(struct kvm_cpu_context *host_ctxt)
> > >  {
> > >  	u64 esr = read_sysreg_el2(SYS_ESR);
> > > +	u16 imm16;
> > >  
> > >  	switch (ESR_ELx_EC(esr)) {
> > >  	case ESR_ELx_EC_HVC64:
> > >  		handle_host_hcall(host_ctxt);
> > >  		break;
> > >  	case ESR_ELx_EC_SMC64:
> > > -		handle_host_smc(host_ctxt);
> > > +		imm16 = esr & U16_MAX;
> > > +		if (!imm16)
> > 
> > if (ESR_ELx_xVC_IMM_MASK(esr)) ?
> > 
> > Also, I can't find void inject_undef64(void); I think you need a vcpu for that?
> 
> Ah my bad, handle_host_mte() introduced it!
> 
> > 
> > > +			handle_host_smc(host_ctxt);
> > > +		else
> > > +			inject_undef64();

Could it be better to return SMCCC_RET_NOT_SUPPORTED?

> > >  		break;
> > >  	case ESR_ELx_EC_IABT_LOW:
> > >  	case ESR_ELx_EC_DABT_LOW:
> > > -- 
> > > 2.53.0.983.g0bb29b3bc5-goog
> > > 


^ permalink raw reply

* Re: [PATCH rc] iommu/arm-smmu-v3: Drain in-flight fault handlers
From: Jason Gunthorpe @ 2026-03-24 14:17 UTC (permalink / raw)
  To: Will Deacon
  Cc: Lu Baolu, Kevin Tian, Nicolin Chen, robin.murphy, joro, praan,
	mmarrid, kees, Alexander.Grest, smostafa, linux-arm-kernel, iommu,
	linux-kernel, bbiber, skaestle
In-Reply-To: <acKZ0wtfi5R_dHm0@willie-the-truck>

On Tue, Mar 24, 2026 at 02:04:03PM +0000, Will Deacon wrote:
> Sorry, that was sloppy terminology on my part. I'm trying to reason about
> faults that are generated by accesses that were translated with the
> page-tables of the old domain being reported once we think we are using
> the new domain.

It doesn't matter.

If a concurrent fault is resolving on the old domain and it completes
after the STE is in the new domain the device will restart and if the
IOVA is still non-present it will refault. This is normal and fine.

If it is resolving on the new domain and the new domain has a present
PTE so the PRI is spurious then the fault handler should NOP it and
restart the device.

> > The ordering is supposed to be
> >  1) IOMMU HW starts using the new domain
> >  2) iommu_attach_handle_get() returns the new domain
> >  3) IOMMU driver flushes its own IRQs/queues that may be concurrently
> >     calling iommu_attach_handle_get()
> 
> Does that mean we should kick the evtq thread? I'm not sure what this
> means for the priq.

The locking issue is around iommu_attach_handle_get(), so any
thread/irq concurrently calling that has to be fenced. That's it. We
don't have to expedite or synchronize with concurrent PRI at all.

> I don't think we can rely on the IRQ being taken, though, so presumably
> we have to kick the irq thread manually and see what's actually sitting
> in the event queue after the CMD_SYNC?

Er, I thought the iommu_attach_handle_get() was in a threaded irq? If
it is in a WQ then yeah more is needed.

Jason


^ permalink raw reply

* Re: [PATCH v9 2/5] i2c: mux: add support for per channel bus frequency
From: Andy Shevchenko @ 2026-03-24 14:10 UTC (permalink / raw)
  To: Marcus Folkesson
  Cc: Wolfram Sang, Peter Rosin, Michael Hennerich, Bartosz Golaszewski,
	Andi Shyti, Bartosz Golaszewski, linux-i2c, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20260324-i2c-mux-v9-2-5292b0608243@gmail.com>

On Tue, Mar 24, 2026 at 02:54:16PM +0100, Marcus Folkesson wrote:
> There may be several reasons why you may need to use a certain speed
> on an I2C bus. E.g.
> 
> - When several devices are attached to the bus, the speed must be
>   selected according to the slowest device.
> 
> - Electrical conditions may limit the usable speed on the bus for
>   different reasons.
> 
> With an I2C multiplexer, it is possible to group the attached devices
> after their preferred speed by e.g. putting all "slow" devices on a
> separate channel on the multiplexer.
> 
> Consider the following topology:
> 
>                       .----------. 100kHz .--------.
>     .--------. 400kHz |          |--------| dev D1 |
>     |  root  |--+-----| I2C MUX  |        '--------'
>     '--------'  |     |          |--. 400kHz .--------.
>                 |     '----------'  '-------| dev D2 |
>                 |  .--------.               '--------'
>                 '--| dev D3 |
>                    '--------'
> 
> One requirement with this design is that a multiplexer may only use the
> same or lower bus speed as its parent.
> Otherwise, if the multiplexer would have to increase the bus frequency,
> then all siblings (D3 in this case) would run into a clock speed it may
> not support.
> 
> The bus frequency for each channel is set in the devicetree. As the
> i2c-mux bindings import the i2c-controller schema, the clock-frequency
> property is already allowed.
> If no clock-frequency property is set, the channel inherits their parent
> bus speed.

...

> +		of_property_read_u32(child, "clock-frequency", &priv->adap.clock_hz);

Wondering if we may use existing API to get i2c timings from fw description?
i2c_parse_fw_timings() (it might be that it needs to be split for pure fwnode
one and device wrapped).

> +
> +		/* If the mux adapter has no clock-frequency property, inherit from parent */
> +		if (!priv->adap.clock_hz)
> +			priv->adap.clock_hz = parent->clock_hz;
> +
> +		/*
> +		 * Warn if the mux adapter is not parent-locked as
> +		 * this may cause issues for some hardware topologies.
> +		 */
> +		if ((priv->adap.clock_hz < parent->clock_hz) && muxc->mux_locked)
> +			dev_warn(muxc->dev,
> +				 "channel %u is slower than parent on a non parent-locked mux\n",
> +				 chan_id);
> +
> +		/* We don't support mux adapters faster than their parent */
> +		if (priv->adap.clock_hz > parent->clock_hz) {
> +			dev_err(muxc->dev,
> +				"channel (%u) is faster (%u) than parent (%u)\n",
> +				chan_id, priv->adap.clock_hz, parent->clock_hz);
> +
> +			of_node_put(mux_node);
> +			ret = -EINVAL;
> +			goto err_free_priv;
> +		}

-- 
With Best Regards,
Andy Shevchenko




^ permalink raw reply

* Re: [PATCH] KVM: arm64: Inject UNDEF when host is executing an smc with imm16 != 0
From: Vincent Donnefort @ 2026-03-24 14:09 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: kvmarm, linux-arm-kernel, linux-kernel, android-kvm,
	catalin.marinas, joey.gouly, mark.rutland, maz, oupton,
	suzuki.poulose, tabba, will, yuzenghui
In-Reply-To: <acKacAd6aV32624m@google.com>

On Tue, Mar 24, 2026 at 02:06:40PM +0000, Vincent Donnefort wrote:
> On Tue, Mar 24, 2026 at 01:57:28PM +0000, Sebastian Ene wrote:
> > The ARM Service Calling Convention (SMCCC) specifies that the function
> > identifier and parameters should be passed in registers, leaving the
> > 16-bit immediate field of the SMC instruction un-handled.
> > Currently, our pKVM handler ignores the immediate value, which could lead
> > to non-compliant software relying on implementation-defined behavior.
> > Enforce the host kernel running under pKVM to use an immediate value
> > of 0 by decoding the ISS from the ESR_EL2 and inject an undefined
> > instruction exception back to the caller.
> > 
> > Signed-off-by: Sebastian Ene <sebastianene@google.com>
> > ---
> >  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 7 ++++++-
> >  1 file changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > index e7790097db93..ff6a90a4a4c7 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > @@ -756,13 +756,18 @@ static bool handle_host_mte(u64 esr)
> >  void handle_trap(struct kvm_cpu_context *host_ctxt)
> >  {
> >  	u64 esr = read_sysreg_el2(SYS_ESR);
> > +	u16 imm16;
> >  
> >  	switch (ESR_ELx_EC(esr)) {
> >  	case ESR_ELx_EC_HVC64:
> >  		handle_host_hcall(host_ctxt);
> >  		break;
> >  	case ESR_ELx_EC_SMC64:
> > -		handle_host_smc(host_ctxt);
> > +		imm16 = esr & U16_MAX;
> > +		if (!imm16)
> 
> if (ESR_ELx_xVC_IMM_MASK(esr)) ?
> 
> Also, I can't find void inject_undef64(void); I think you need a vcpu for that?

Ah my bad, handle_host_mte() introduced it!

> 
> > +			handle_host_smc(host_ctxt);
> > +		else
> > +			inject_undef64();
> >  		break;
> >  	case ESR_ELx_EC_IABT_LOW:
> >  	case ESR_ELx_EC_DABT_LOW:
> > -- 
> > 2.53.0.983.g0bb29b3bc5-goog
> > 


^ permalink raw reply

* Re: [PATCH] KVM: arm64: Inject UNDEF when host is executing an smc with imm16 != 0
From: Vincent Donnefort @ 2026-03-24 14:06 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: kvmarm, linux-arm-kernel, linux-kernel, android-kvm,
	catalin.marinas, joey.gouly, mark.rutland, maz, oupton,
	suzuki.poulose, tabba, will, yuzenghui
In-Reply-To: <20260324135728.3532400-1-sebastianene@google.com>

On Tue, Mar 24, 2026 at 01:57:28PM +0000, Sebastian Ene wrote:
> The ARM Service Calling Convention (SMCCC) specifies that the function
> identifier and parameters should be passed in registers, leaving the
> 16-bit immediate field of the SMC instruction un-handled.
> Currently, our pKVM handler ignores the immediate value, which could lead
> to non-compliant software relying on implementation-defined behavior.
> Enforce the host kernel running under pKVM to use an immediate value
> of 0 by decoding the ISS from the ESR_EL2 and inject an undefined
> instruction exception back to the caller.
> 
> Signed-off-by: Sebastian Ene <sebastianene@google.com>
> ---
>  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index e7790097db93..ff6a90a4a4c7 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -756,13 +756,18 @@ static bool handle_host_mte(u64 esr)
>  void handle_trap(struct kvm_cpu_context *host_ctxt)
>  {
>  	u64 esr = read_sysreg_el2(SYS_ESR);
> +	u16 imm16;
>  
>  	switch (ESR_ELx_EC(esr)) {
>  	case ESR_ELx_EC_HVC64:
>  		handle_host_hcall(host_ctxt);
>  		break;
>  	case ESR_ELx_EC_SMC64:
> -		handle_host_smc(host_ctxt);
> +		imm16 = esr & U16_MAX;
> +		if (!imm16)

if (ESR_ELx_xVC_IMM_MASK(esr)) ?

Also, I can't find void inject_undef64(void); I think you need a vcpu for that?

> +			handle_host_smc(host_ctxt);
> +		else
> +			inject_undef64();
>  		break;
>  	case ESR_ELx_EC_IABT_LOW:
>  	case ESR_ELx_EC_DABT_LOW:
> -- 
> 2.53.0.983.g0bb29b3bc5-goog
> 


^ permalink raw reply

* Re: [PATCH rc] iommu/arm-smmu-v3: Drain in-flight fault handlers
From: Will Deacon @ 2026-03-24 14:04 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Lu Baolu, Kevin Tian, Nicolin Chen, robin.murphy, joro, praan,
	mmarrid, kees, Alexander.Grest, smostafa, linux-arm-kernel, iommu,
	linux-kernel, bbiber, skaestle
In-Reply-To: <20260312142509.GA1586734@nvidia.com>

On Thu, Mar 12, 2026 at 11:25:09AM -0300, Jason Gunthorpe wrote:
> On Thu, Mar 12, 2026 at 01:51:26PM +0000, Will Deacon wrote:
> > On Fri, Mar 06, 2026 at 04:17:23PM -0800, Nicolin Chen wrote:
> > > From: Malak Marrid <mmarrid@nvidia.com>
> > > 
> > > When a device is switching away from a domain, either through a detach or a
> > > replace operation, it must drain its IOPF queue that only contains the page
> > > requests for the old domain.
> > > 
> > > Currently, the IOPF infrastructure is used by master->stall_enabled. So the
> > > stalled transaction for the old domain should be resumed/terminated. Fix it
> > > properly.
> > > 
> > > Fixes: cfea71aea921 ("iommu/arm-smmu-v3: Put iopf enablement in the domain attach path")
> > > Cc: stable@vger.kernel.org
> > > Co-developed-by: Barak Biber <bbiber@nvidia.com>
> > > Signed-off-by: Barak Biber <bbiber@nvidia.com>
> > > Co-developed-by: Stefan Kaestle <skaestle@nvidia.com>
> > > Signed-off-by: Stefan Kaestle <skaestle@nvidia.com>
> > > Signed-off-by: Malak Marrid <mmarrid@nvidia.com>
> > > Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
> > > ---
> > >  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 11 ++++++++++-
> > >  1 file changed, 10 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > > index 4d00d796f0783..2176ee8bec767 100644
> > > --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > > +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> > > @@ -2843,6 +2843,12 @@ static int arm_smmu_enable_iopf(struct arm_smmu_master *master,
> > >  	if (master->iopf_refcount) {
> > >  		master->iopf_refcount++;
> > >  		master_domain->using_iopf = true;
> > > +		/*
> > > +		 * If the device is already on the IOPF queue (domain replace),
> > > +		 * drain in-flight fault handlers so nothing will hold the old
> > > +		 * domain when the core switches the attach handle.
> > > +		 */
> > > +		iopf_queue_flush_dev(master->dev);
> > 
> > So this drains the iopf workqueue, but don't you still have a race with
> > the hardware generating a fault on the old domain and then that only
> > showing up once you've switched to the new one? What is the actual
> > problem you're trying to solve with this patch?
> 
> HW doesn't generate faults on domains, it calls
> iommu_report_device_fault() which calls find_fault_handler() that
> uses iommu_attach_handle_get() to find the domain. It then shoves the
> domain pointer onto a WQ.

Sorry, that was sloppy terminology on my part. I'm trying to reason about
faults that are generated by accesses that were translated with the
page-tables of the old domain being reported once we think we are using
the new domain.

> The ordering is supposed to be
>  1) IOMMU HW starts using the new domain
>  2) iommu_attach_handle_get() returns the new domain
>  3) IOMMU driver flushes its own IRQs/queues that may be concurrently
>     calling iommu_attach_handle_get()

Does that mean we should kick the evtq thread? I'm not sure what this
means for the priq.

>  4) iopf_queue_flush_dev() to clear the iopf work queue
>  5) domain is freed, no pointers in WQs or other threads
> 
> So the naked iopf_queue_flush_dev() doesn't seem right, I'd expect a
> synchronize_irq() (is that right for threaded IRQs?) too as the
> threaded IRQ is concurrently calling iommu_attach_handle_get().

I don't think we can rely on the IRQ being taken, though, so presumably
we have to kick the irq thread manually and see what's actually sitting
in the event queue after the CMD_SYNC?

Will


^ permalink raw reply

* [PATCH] arm64: dts: ti: k3-am62a7-sk: Add bootph-all tag to vqmmc
From: Judith Mendez @ 2026-03-24 14:02 UTC (permalink / raw)
  To: Judith Mendez, Vignesh Raghavendra
  Cc: Nishanth Menon, Tero Kristo, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-arm-kernel, devicetree, linux-kernel

Add bootph-all property to vqmmc voltage regulator node and its
corresponding pinmux node to make it available during all boot
phases. This allows to run tuning early in SPL stages of boot.

Fixes: 8f023012eb4a ("arm64: dts: ti: k3-am62a: Enable UHS mode support for SD cards")
Cc: stable@vger.kernel.org
Signed-off-by: Judith Mendez <jm@ti.com>
---
 arch/arm64/boot/dts/ti/k3-am62a7-sk.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
index b1a6f10adf26..a085613cf123 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
@@ -154,6 +154,7 @@ vddshv_sdio: regulator-5 {
 		gpios = <&main_gpio0 31 GPIO_ACTIVE_HIGH>;
 		states = <1800000 0x0>,
 			 <3300000 0x1>;
+		bootph-all;
 	};
 
 	leds {
@@ -400,6 +401,7 @@ vddshv_sdio_pins_default: vddshv-sdio-default-pins {
 		pinctrl-single,pins = <
 			AM62AX_IOPAD(0x07c, PIN_OUTPUT, 7) /* (N22) GPMC0_CLK.GPIO0_31 */
 		>;
+		bootph-all;
 	};
 
 	main_ecap0_pins_default: main-ecap0-default-pins {
-- 
2.53.0



^ permalink raw reply related

* Re: [PATCH v5 0/8] PCI: dw-rockchip: add system suspend support
From: Shawn Lin @ 2026-03-24 14:00 UTC (permalink / raw)
  To: Sebastian Reichel, Lorenzo Pieralisi, Krzysztof Wilczyński,
	Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner,
	Philipp Zabel, Jingoo Han, Liam Girdwood, Mark Brown
  Cc: shawn.lin, linux-pci, linux-arm-kernel, linux-rockchip,
	linux-kernel, kernel
In-Reply-To: <20260316-rockchip-pcie-system-suspend-v5-0-5bb5ad37d643@collabora.com>

Hi Sebastian

在 2026/03/17 星期二 3:10, Sebastian Reichel 写道:
> I've recently been working on fixing up at least basic system suspend
> support on the Rockchip RK3576 platform. The last open issue is missing
> support in the PCIe driver. This series is a follow-up for Shawn Lin's
> series with feedback from Niklas Cassel and Manivannan Sadhasivam being
> handled as well as some of my own changes fixing up things I noticed.
> 
> In opposite to Shawn Lin I did not test with different peripherals as my
> main goal is getting basic suspend to ram working in the first place. I
> did notice issues with the Broadcom WLAN card on the RK3576 EVB.
> Suspending that platform without a driver being probed works, but after
> probing brcmfmac suspend is aborted because brcmf_pcie_pm_enter_D3()
> does not work. As far as I can tell the problem is unrelated to the
> Rockchip PCIe driver.

Thanks for the patchset. It doesn't cleanly apply to new -rc now so I
assume it need a rebase. Anyway, I amended this series to apply them
to -rc5 and tested them on several platforms, it works fine.

However, I think patch 7 actually put the host and device into D3cold
unconditionly, with reset the controller,power-off 3v3 and deassert
perst# which doesn't follow NVMe's requirement at least.

Krishna is working on it [1], it would be better to follow the same
patten.

[1] 
https://lore.kernel.org/all/20260217-d3cold-v2-0-89b322864043@oss.qualcomm.com/

> 
> Changes since PATCHv4:
>   * https://lore.kernel.org/r/20251029-rockchip-pcie-system-suspend-v4-0-ce2e1b0692d2@collabora.com
>   * rebase to v7.0-rc1
>   * Add an RFC patch at the end with some bits I found in the Rockchip vendor kernel;
>   * Made some tests on Rock 5B+ (RK3588); with this patch series suspending works
>     when setting pm_test to devices. A full system suspend fails in a later step,
>     but that is independent of PCIe.
> 
> Changes since PATCHv3:
>   * https://lore.kernel.org/linux-pci/1744940759-23823-1-git-send-email-shawn.lin@rock-chips.com/
>   * rename rockchip_pcie_get_ltssm to rockchip_pcie_get_ltssm_status_reg
>     in a separate patch (Niklas Cassel)
>   * rename rockchip_pcie_get_pure_ltssm to rockchip_pcie_get_ltssm_state
>     in a separate patch (Niklas Cassel)
>   * Move devm_phy_get out of phy_init to probe in a separate patch
>     (Manivannan Sadhasivam)
>   * Add helper function for enhanced LTSSM control mode in a separate patch
>     (Niklas Cassel)
>   * Add helper function for controller mode in a separate patch
>     (Niklas Cassel)
>   * Add helper function for DDL indicator in a separate patch
>     (Niklas Cassel)
>   * Move rockchip_pcie_pme_turn_off implementation in a separate patch
>   * Rebase to v6.18-rc3 using new FIELD_PREP_WM16()
>   * Improve readability of PME_TURN_OFF/PME_TO_ACK defines (Manivannan Sadhasivam)
>   * Fix usage of reverse Xmas (Manivannan Sadhasivam)
>   * Assert PERST# before turning off other resources (Manivannan Sadhasivam)
>   * Improve some error messages (Manivannan Sadhasivam)
>   * Rename goto labels as per their purpose (Manivannan Sadhasivam)
>   * Add extra patch for dw_pcie_resume_noirq, since I've seen errors
>     during resume on boards not having anything plugged into their PCIe
>     port
> 
> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> ---
> Sebastian Reichel (8):
>        PCI: dw-rockchip: Restore vpcie3v3 regulator handle
>        PCI: dw-rockchip: Move devm_phy_get out of phy_init
>        PCI: dw-rockchip: Add helper function for enhanced LTSSM control mode
>        PCI: dw-rockchip: Add helper function for controller mode
>        PCI: dw-rockchip: Add helper function for DDL indicator
>        PCI: dw-rockchip: Add pme_turn_off support
>        PCI: dw-rockchip: Add system PM support
>        [RFC] PCI: dw-rockchip: port some suspend code from vendor kernel
> 
>   drivers/pci/controller/dwc/pcie-dw-rockchip.c | 242 ++++++++++++++++++++++----
>   1 file changed, 206 insertions(+), 36 deletions(-)
> ---
> base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
> change-id: 20251028-rockchip-pcie-system-suspend-86cf08a7b229
> 
> Best regards,


^ permalink raw reply

* [PATCH] KVM: arm64: Inject UNDEF when host is executing an smc with imm16 != 0
From: Sebastian Ene @ 2026-03-24 13:57 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel, linux-kernel, android-kvm
  Cc: catalin.marinas, joey.gouly, mark.rutland, maz, oupton,
	sebastianene, suzuki.poulose, tabba, vdonnefort, will, yuzenghui

The ARM Service Calling Convention (SMCCC) specifies that the function
identifier and parameters should be passed in registers, leaving the
16-bit immediate field of the SMC instruction un-handled.
Currently, our pKVM handler ignores the immediate value, which could lead
to non-compliant software relying on implementation-defined behavior.
Enforce the host kernel running under pKVM to use an immediate value
of 0 by decoding the ISS from the ESR_EL2 and inject an undefined
instruction exception back to the caller.

Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index e7790097db93..ff6a90a4a4c7 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -756,13 +756,18 @@ static bool handle_host_mte(u64 esr)
 void handle_trap(struct kvm_cpu_context *host_ctxt)
 {
 	u64 esr = read_sysreg_el2(SYS_ESR);
+	u16 imm16;
 
 	switch (ESR_ELx_EC(esr)) {
 	case ESR_ELx_EC_HVC64:
 		handle_host_hcall(host_ctxt);
 		break;
 	case ESR_ELx_EC_SMC64:
-		handle_host_smc(host_ctxt);
+		imm16 = esr & U16_MAX;
+		if (!imm16)
+			handle_host_smc(host_ctxt);
+		else
+			inject_undef64();
 		break;
 	case ESR_ELx_EC_IABT_LOW:
 	case ESR_ELx_EC_DABT_LOW:
-- 
2.53.0.983.g0bb29b3bc5-goog



^ permalink raw reply related

* [PATCH] ASoC: dt-bindings: rockchip: Convert rockchip-max98090.txt to yaml
From: Fabio Estevam @ 2026-03-24 13:55 UTC (permalink / raw)
  To: broonie
  Cc: heiko, robh, krzk+dt, conor+dt, linux-sound, devicetree,
	linux-rockchip, linux-kernel, linux-arm-kernel, Fabio Estevam

Convert rockchip-max98090.txt to yaml to allow dt-schema validation.

Signed-off-by: Fabio Estevam <festevam@gmail.com>
---
 .../rockchip,rockchip-audio-max98090.yaml     | 59 +++++++++++++++++++
 .../bindings/sound/rockchip-max98090.txt      | 42 -------------
 2 files changed, 59 insertions(+), 42 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.yaml
 delete mode 100644 Documentation/devicetree/bindings/sound/rockchip-max98090.txt

diff --git a/Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.yaml b/Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.yaml
new file mode 100644
index 000000000000..5630652aa4c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rockchip-audio-max98090.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/rockchip,rockchip-audio-max98090.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip audio complex with MAX98090 codec
+
+maintainers:
+  - Fabio Estevam <festevam@gmail.com>
+
+properties:
+  compatible:
+    const: rockchip,rockchip-audio-max98090
+
+  rockchip,model:
+    $ref: /schemas/types.yaml#/definitions/string
+    description: The user-visible name of this sound complex.
+
+  rockchip,i2s-controller:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle to the Rockchip I2S controller.
+
+  rockchip,audio-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle to the MAX98090 audio codec.
+
+  rockchip,headset-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle to the external chip for jack detection.
+
+  rockchip,hdmi-codec:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description: Phandle to the HDMI device for HDMI codec.
+
+required:
+  - compatible
+  - rockchip,model
+  - rockchip,i2s-controller
+
+allOf:
+  - if:
+      required:
+        - rockchip,audio-codec
+    then:
+      required:
+        - rockchip,headset-codec
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    sound {
+        compatible = "rockchip,rockchip-audio-max98090";
+        rockchip,model = "ROCKCHIP-I2S";
+        rockchip,i2s-controller = <&i2s>;
+        rockchip,audio-codec = <&max98090>;
+        rockchip,headset-codec = <&headsetcodec>;
+    };
diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98090.txt b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt
deleted file mode 100644
index e9c58b204399..000000000000
--- a/Documentation/devicetree/bindings/sound/rockchip-max98090.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-ROCKCHIP with MAX98090 CODEC
-
-Required properties:
-- compatible: "rockchip,rockchip-audio-max98090"
-- rockchip,model: The user-visible name of this sound complex
-- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's
-  connected to the CODEC
-
-Optional properties:
-- rockchip,audio-codec: The phandle of the MAX98090 audio codec.
-- rockchip,headset-codec: The phandle of Ext chip for jack detection. This is
-                          required if there is rockchip,audio-codec.
-- rockchip,hdmi-codec: The phandle of HDMI device for HDMI codec.
-
-Example:
-
-/* For max98090-only board. */
-sound {
-	compatible = "rockchip,rockchip-audio-max98090";
-	rockchip,model = "ROCKCHIP-I2S";
-	rockchip,i2s-controller = <&i2s>;
-	rockchip,audio-codec = <&max98090>;
-	rockchip,headset-codec = <&headsetcodec>;
-};
-
-/* For HDMI-only board. */
-sound {
-	compatible = "rockchip,rockchip-audio-max98090";
-	rockchip,model = "ROCKCHIP-I2S";
-	rockchip,i2s-controller = <&i2s>;
-	rockchip,hdmi-codec = <&hdmi>;
-};
-
-/* For max98090 plus HDMI board. */
-sound {
-	compatible = "rockchip,rockchip-audio-max98090";
-	rockchip,model = "ROCKCHIP-I2S";
-	rockchip,i2s-controller = <&i2s>;
-	rockchip,audio-codec = <&max98090>;
-	rockchip,headset-codec = <&headsetcodec>;
-	rockchip,hdmi-codec = <&hdmi>;
-};
-- 
2.43.0



^ permalink raw reply related

* [PATCH v9 5/5] docs: i2c: i2c-topology: add section about bus speed
From: Marcus Folkesson @ 2026-03-24 13:54 UTC (permalink / raw)
  To: Wolfram Sang, Peter Rosin, Michael Hennerich, Bartosz Golaszewski,
	Andi Shyti, Andy Shevchenko, Bartosz Golaszewski
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson
In-Reply-To: <20260324-i2c-mux-v9-0-5292b0608243@gmail.com>

Describe what needs to be consideraed and taken into account
when using different bus speeds for different mux channels.

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 Documentation/i2c/i2c-topology.rst | 178 +++++++++++++++++++++++++++++++++++++
 1 file changed, 178 insertions(+)

diff --git a/Documentation/i2c/i2c-topology.rst b/Documentation/i2c/i2c-topology.rst
index 48fce0f7491b..24df553ca8c7 100644
--- a/Documentation/i2c/i2c-topology.rst
+++ b/Documentation/i2c/i2c-topology.rst
@@ -367,6 +367,184 @@ When D1 or D2 are accessed, accesses to D3 and D4 are locked out while
 accesses to D5 may interleave. When D3 or D4 are accessed, accesses to
 all other devices are locked out.
 
+Bus Speed and I2C Multiplexers
+================================
+
+I2C bus multiplexers allow multiple downstream channels to be exposed
+as separate I2C adapters which also could set their own bus speed.
+
+The multiplexer itself cannot change the bus speed as it use the upstream
+clock and data lines to communicate with the downstream devices. The speed
+is therefore changed in the root adapter resulting in that the whole bus is
+affected.
+
+This increases the complexity of the topology and some considerations must
+be taken into account.
+
+Bus speed
+----------
+
+Downstream channels of an I2C multiplexer can only operate at the same or
+lower bus speed as the upstream bus. This is because the upstream bus may
+have devices that cannot operate at higher speeds and those will be affected
+by the speed change.
+
+The example below illustrates the problem.
+The root adapter is operating at 100kHz. D2 can only operate with 100kHz,
+but D1 can operate at 400kHz. When D1 is selected, the bus speed of the
+root adapter would have to be set to 400kHz, a speed that D2 may not support.
+
+This topology is therefor not allowed: ::
+
+                          .----------. 400kHz .--------.
+        .--------. 100kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |
+                    |     '----------'
+                    |  .--------.
+                    '--| dev D2 |
+                       '--------'
+
+
+This topology is allowed: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D2 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'        |  mux M1  |--. 400kHz .--------.
+                          '----------'  '--------| dev D1 |
+                                                 '--------'
+
+Preferred topology
+-------------------
+
+The preferred topology when using different bus speeds is to have the multiplexer
+connected directly to the root adapter without any devices as siblings.
+By this arrangement, the bus speed can be changed without affecting any other devices
+and many of the caveats are avoided.
+
+Other multiplexers in parallel is still okay as those are locked out during transfers.
+
+This is the preferred topology: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D2 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'        |  mux M1  |--. 400kHz .--------.
+                          '----------'  '--------| dev D1 |
+                                                 '--------'
+
+Locking
+--------
+
+If the multiplexer is mux-locked, transfers to D3 may interleave between the
+select-transfer-deselect to D1 or D2.
+This results in a situation where the bus speed to D3 may be lower than it
+is supposed to be. This is usually not a problem.
+
+This topology is allowed but some transfers to D3 may be at 100kHz: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |--. 400kHz .--------.
+                    |     '----------'  '--------| dev D2 |
+                    |  .--------.                '--------'
+                    '--| dev D3 |
+                       '--------'
+
+Multiple muxes in series
+--------------------------
+
+When multiple muxes are used in series the same rules applies.
+
+Transfers to D3 may interleave between select-transfer-deselect to D1, which
+results that the bus speed to D2 or D3 will be at 100KHz.
+
+Transfers to D2 may interleave between select-transfer-deselect to D1, which
+results in that the bus speed to D1 may be at 400kHz as the transfer to D2
+will set the bus speed to before the transfer to D1 starts.
+
+This is probably a bad topology ::
+
+                     .----------. 400kHz .----------. 100kHz .--------.
+    .--------.400kHz |   mux-   |--------|   mux-   |--------| dev D1 |
+    |  root  |--+----|  locked  | 400kHz |  locked  |        '--------'
+    '--------'  |    |  mux M1  |--.     |  mux M2  |
+                |    '----------'  |     '----------'
+                |  .--------.      |  .--------.
+                '--| dev D3 |      '--| dev D2 |
+                   '--------'         '--------'
+
+Multiple muxes in parallel
+----------------------------
+
+When multiple muxes are used in parallel all access to other muxes are locked out
+so this is not a problem.
+
+If the muxes are mux-locked, access to D3 may still interleave though.
+
+In the example below, D3 may not interleave between select-transfer-deselect for D1
+or D2 as both muxes are parent-locked: ::
+
+
+                   .----------. 100kHz   .--------.
+                   |  parent- |----------| dev D1 |
+                .--|  locked  |          '--------'
+                |  |  mux M1  |
+                |  '----------'
+                |      .----------. 400KHz  .--------.
+    .--------. 400kHz  |  parent- |---------| dev D2 |
+    |  root  |--+------|  locked  |         '--------'
+    '--------'  |      |  mux M2  |
+                |      '----------'
+                |  .--------.
+                '--| dev D3 |
+                   '--------'
+
+Idle state
+-----------
+
+Muxes have an idle state, which is the state the channels are put into when no channel
+is active. The state is typically one of the following:
+
+- All channels are disconnected
+- The last selected channel is left as-is
+- A predefined channel is selected
+
+Muxes that support an idle state where all channels are disconnected are preferred when using
+different bus speeds. Otherwise high bus speeds may "leak" through to devices that
+may not support that higher speed.
+
+Consider the following example: ::
+
+                          .----------. 100kHz .--------.
+        .--------. 400kHz |   mux-   |--------| dev D1 |
+        |  root  |--+-----|  locked  |        '--------'
+        '--------'  |     |  mux M1  |--. 400kHz .--------.
+                    |     '----------'  '--------| dev D2 |
+                    |  .--------.                '--------'
+                    '--| dev D3 |
+                       '--------'
+
+If the idle state of M1 is:
+
+- All channels disconnected: No problem, D1 and D2 are not affected by communication
+  to D3.
+- Last selected channel: Problem if D1 was the last selected channel. High speed
+  communication to D3 will be "leaked" to D1.
+- Predefined channel: Problem if the predefined channel D1. Set predefined channel
+  to D2 as D2 may handle 400kHz.
+
+Supported controllers
+-----------------------
+
+Not all I2C controllers support setting the bus speed dynamically.
+At the time of writing, the following controllers have support:
+
+============================   =============================================
+i2c-davinci                    Supports dynamic bus speed
+============================   =============================================
 
 Mux type of existing device drivers
 ===================================

-- 
2.53.0



^ permalink raw reply related

* [PATCH v9 4/5] i2c: davinci: add support for setting bus frequency
From: Marcus Folkesson @ 2026-03-24 13:54 UTC (permalink / raw)
  To: Wolfram Sang, Peter Rosin, Michael Hennerich, Bartosz Golaszewski,
	Andi Shyti, Andy Shevchenko, Bartosz Golaszewski
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
	Bartosz Golaszewski
In-Reply-To: <20260324-i2c-mux-v9-0-5292b0608243@gmail.com>

Populate adapter with clock_hz and .set_clk_freq() to enable support for
dynamic bus frequency.

Remove bus_freq_hz entirely and only use clock_hz instead.

Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 drivers/i2c/busses/i2c-davinci.c | 35 ++++++++++++++++++++++++++++-------
 1 file changed, 28 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 549fb22cdf4f..d87172408445 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -132,8 +132,6 @@ struct davinci_i2c_dev {
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 #endif
-	/* standard bus frequency */
-	unsigned int		bus_freq_hz;
 	/* Chip has a ICPFUNC register */
 	bool			has_pfunc;
 };
@@ -171,6 +169,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
 	u32 clkh;
 	u32 clkl;
 	u32 input_clock = clk_get_rate(dev->clk);
+	u32 bus_freq_hz = dev->adapter.clock_hz;
 
 	/* NOTE: I2C Clock divider programming info
 	 * As per I2C specs the following formulas provide prescaler
@@ -207,9 +206,9 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
 	if (device_is_compatible(dev->dev, "ti,keystone-i2c"))
 		d = 6;
 
-	clk = (input_clock / (psc + 1)) / (dev->bus_freq_hz);
+	clk = (input_clock / (psc + 1)) / (bus_freq_hz);
 	/* Avoid driving the bus too fast because of rounding errors above */
-	if (input_clock / (psc + 1) / clk > dev->bus_freq_hz)
+	if (input_clock / (psc + 1) / clk > bus_freq_hz)
 		clk++;
 	/*
 	 * According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at
@@ -267,7 +266,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
 		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
 	dev_dbg(dev->dev, "CLKH = %d\n",
 		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
-	dev_dbg(dev->dev, "bus_freq_hz = %dHz\n", dev->bus_freq_hz);
+	dev_dbg(dev->dev, "bus_freq_hz = %dHz\n", dev->adapter.clock_hz);
 
 
 	/* Take the I2C module out of reset: */
@@ -279,6 +278,27 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
 	return 0;
 }
 
+static int davinci_i2c_set_clk(struct i2c_adapter *adap, u32 clock_hz)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+	if (adap->clock_hz == clock_hz)
+		return 0;
+
+	adap->clock_hz = clock_hz;
+
+	/* put I2C into reset */
+	davinci_i2c_reset_ctrl(dev, 0);
+
+	/* compute clock dividers */
+	i2c_davinci_calc_clk_dividers(dev);
+
+	/* Take the I2C module out of reset: */
+	davinci_i2c_reset_ctrl(dev, 1);
+
+	return 0;
+}
+
 /*
  * This routine does i2c bus recovery by using i2c_generic_scl_recovery
  * which is provided by I2C Bus recovery infrastructure.
@@ -755,12 +775,13 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 	dev->dev = &pdev->dev;
 	dev->irq = irq;
 	platform_set_drvdata(pdev, dev);
+	adap = &dev->adapter;
 
 	r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
 	if (r)
 		prop = I2C_MAX_STANDARD_MODE_FREQ;
 
-	dev->bus_freq_hz = prop;
+	adap->clock_hz = prop;
 
 	dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc");
 
@@ -800,7 +821,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 		goto err_unuse_clocks;
 	}
 
-	adap = &dev->adapter;
 	i2c_set_adapdata(adap, dev);
 	adap->owner = THIS_MODULE;
 	adap->class = I2C_CLASS_DEPRECATED;
@@ -809,6 +829,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->timeout = DAVINCI_I2C_TIMEOUT;
 	adap->dev.of_node = dev_of_node(&pdev->dev);
+	adap->set_clk_freq = davinci_i2c_set_clk;
 
 	if (dev->has_pfunc)
 		adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;

-- 
2.53.0



^ permalink raw reply related

* [PATCH v9 3/5] i2c: davinci: calculate bus freq from Hz instead of kHz
From: Marcus Folkesson @ 2026-03-24 13:54 UTC (permalink / raw)
  To: Wolfram Sang, Peter Rosin, Michael Hennerich, Bartosz Golaszewski,
	Andi Shyti, Andy Shevchenko, Bartosz Golaszewski
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson,
	Bartosz Golaszewski
In-Reply-To: <20260324-i2c-mux-v9-0-5292b0608243@gmail.com>

The bus frequency is unnecessarily converted between Hz and kHz in
several places.
This is probably an old legacy from the old times (pre-devicetrees)
when the davinci_i2c_platform_data took the bus_freq in kHz.

Stick to Hz.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 drivers/i2c/busses/i2c-davinci.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index a773ba082321..549fb22cdf4f 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -117,8 +117,6 @@
 /* timeout for pm runtime autosuspend */
 #define DAVINCI_I2C_PM_TIMEOUT	1000	/* ms */
 
-#define DAVINCI_I2C_DEFAULT_BUS_FREQ	100
-
 struct davinci_i2c_dev {
 	struct device           *dev;
 	void __iomem		*base;
@@ -134,8 +132,8 @@ struct davinci_i2c_dev {
 #ifdef CONFIG_CPU_FREQ
 	struct notifier_block	freq_transition;
 #endif
-	/* standard bus frequency (kHz) */
-	unsigned int		bus_freq;
+	/* standard bus frequency */
+	unsigned int		bus_freq_hz;
 	/* Chip has a ICPFUNC register */
 	bool			has_pfunc;
 };
@@ -209,16 +207,16 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
 	if (device_is_compatible(dev->dev, "ti,keystone-i2c"))
 		d = 6;
 
-	clk = ((input_clock / (psc + 1)) / (dev->bus_freq * 1000));
+	clk = (input_clock / (psc + 1)) / (dev->bus_freq_hz);
 	/* Avoid driving the bus too fast because of rounding errors above */
-	if (input_clock / (psc + 1) / clk > dev->bus_freq * 1000)
+	if (input_clock / (psc + 1) / clk > dev->bus_freq_hz)
 		clk++;
 	/*
 	 * According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at
 	 * least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH
 	 * to LOW ratio as 1 to 2 is more safe.
 	 */
-	if (dev->bus_freq > 100)
+	if (bus_freq_hz > I2C_MAX_STANDARD_MODE_FREQ)
 		clkl = (clk << 1) / 3;
 	else
 		clkl = (clk >> 1);
@@ -242,7 +240,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
 	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKH_REG, clkh);
 	davinci_i2c_write_reg(dev, DAVINCI_I2C_CLKL_REG, clkl);
 
-	dev_dbg(dev->dev, "input_clock = %d, CLK = %d\n", input_clock, clk);
+	dev_dbg(dev->dev, "input_clock = %u, CLK = %u\n", input_clock, clk);
 }
 
 /*
@@ -269,7 +267,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
 		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG));
 	dev_dbg(dev->dev, "CLKH = %d\n",
 		davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG));
-	dev_dbg(dev->dev, "bus_freq = %dkHz\n", dev->bus_freq);
+	dev_dbg(dev->dev, "bus_freq_hz = %dHz\n", dev->bus_freq_hz);
 
 
 	/* Take the I2C module out of reset: */
@@ -760,9 +758,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 
 	r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop);
 	if (r)
-		prop = DAVINCI_I2C_DEFAULT_BUS_FREQ;
+		prop = I2C_MAX_STANDARD_MODE_FREQ;
 
-	dev->bus_freq = prop / 1000;
+	dev->bus_freq_hz = prop;
 
 	dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc");
 

-- 
2.53.0



^ permalink raw reply related

* [PATCH v9 2/5] i2c: mux: add support for per channel bus frequency
From: Marcus Folkesson @ 2026-03-24 13:54 UTC (permalink / raw)
  To: Wolfram Sang, Peter Rosin, Michael Hennerich, Bartosz Golaszewski,
	Andi Shyti, Andy Shevchenko, Bartosz Golaszewski
  Cc: linux-i2c, linux-kernel, linux-arm-kernel, Marcus Folkesson
In-Reply-To: <20260324-i2c-mux-v9-0-5292b0608243@gmail.com>

There may be several reasons why you may need to use a certain speed
on an I2C bus. E.g.

- When several devices are attached to the bus, the speed must be
  selected according to the slowest device.

- Electrical conditions may limit the usable speed on the bus for
  different reasons.

With an I2C multiplexer, it is possible to group the attached devices
after their preferred speed by e.g. putting all "slow" devices on a
separate channel on the multiplexer.

Consider the following topology:

                      .----------. 100kHz .--------.
    .--------. 400kHz |          |--------| dev D1 |
    |  root  |--+-----| I2C MUX  |        '--------'
    '--------'  |     |          |--. 400kHz .--------.
                |     '----------'  '-------| dev D2 |
                |  .--------.               '--------'
                '--| dev D3 |
                   '--------'

One requirement with this design is that a multiplexer may only use the
same or lower bus speed as its parent.
Otherwise, if the multiplexer would have to increase the bus frequency,
then all siblings (D3 in this case) would run into a clock speed it may
not support.

The bus frequency for each channel is set in the devicetree. As the
i2c-mux bindings import the i2c-controller schema, the clock-frequency
property is already allowed.
If no clock-frequency property is set, the channel inherits their parent
bus speed.

The following example uses dt bindings to illustrate the topology above:

    i2c {
	clock-frequency = <400000>;

        i2c-mux {
            i2c@0 {
                clock-frequency = <100000>;

                D1 {
                    ...
                };
            };

            i2c@1 {
                D2 {
                  ...
                };
            };
        };

        D3 {
            ...
        }
    };

Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
---
 drivers/i2c/i2c-mux.c | 107 ++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 95 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index d59644e50f14..6b5c9ae1efde 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -36,21 +36,75 @@ struct i2c_mux_priv {
 	u32 chan_id;
 };
 
+static int i2c_mux_select_chan(struct i2c_adapter *adap, u32 chan_id, u32 *oldclock)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	if (priv->adap.clock_hz && priv->adap.clock_hz < parent->clock_hz) {
+		*oldclock = parent->clock_hz;
+
+		if (muxc->mux_locked)
+			ret = i2c_adapter_set_clk_freq(parent, priv->adap.clock_hz);
+		else
+			ret = __i2c_adapter_set_clk_freq(parent, priv->adap.clock_hz);
+
+		dev_dbg(&adap->dev, "Set clock frequency %uHz on %s\n",
+			priv->adap.clock_hz, parent->name);
+
+		if (ret)
+			dev_err(&adap->dev,
+				"Failed to set clock frequency %uHz on adapter %s: %d\n",
+				*oldclock, parent->name, ret);
+	}
+
+	return muxc->select(muxc, priv->chan_id);
+}
+
+static void i2c_mux_deselect_chan(struct i2c_adapter *adap, u32 chan_id, u32 oldclock)
+{
+	struct i2c_mux_priv *priv = adap->algo_data;
+	struct i2c_mux_core *muxc = priv->muxc;
+	struct i2c_adapter *parent = muxc->parent;
+	int ret;
+
+	if (muxc->deselect)
+		muxc->deselect(muxc, priv->chan_id);
+
+	if (oldclock && oldclock != priv->adap.clock_hz) {
+		if (muxc->mux_locked)
+			ret = i2c_adapter_set_clk_freq(parent, oldclock);
+		else
+			ret = __i2c_adapter_set_clk_freq(parent, oldclock);
+
+		dev_dbg(&adap->dev, "Restored clock frequency %uHz on %s\n",
+			oldclock, parent->name);
+
+		if (ret)
+			dev_err(&adap->dev,
+				"Failed to set clock frequency %uHz on adapter %s: %d\n",
+				oldclock, parent->name, ret);
+	}
+}
+
 static int __i2c_mux_master_xfer(struct i2c_adapter *adap,
 				 struct i2c_msg msgs[], int num)
 {
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = __i2c_transfer(parent, msgs, num);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -61,15 +115,16 @@ static int i2c_mux_master_xfer(struct i2c_adapter *adap,
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Switch to the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = i2c_transfer(parent, msgs, num);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -82,16 +137,17 @@ static int __i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = __i2c_smbus_xfer(parent, addr, flags,
 				       read_write, command, size, data);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -104,16 +160,17 @@ static int i2c_mux_smbus_xfer(struct i2c_adapter *adap,
 	struct i2c_mux_priv *priv = adap->algo_data;
 	struct i2c_mux_core *muxc = priv->muxc;
 	struct i2c_adapter *parent = muxc->parent;
+	u32 oldclock = 0;
 	int ret;
 
 	/* Select the right mux port and perform the transfer. */
 
-	ret = muxc->select(muxc, priv->chan_id);
+	ret = i2c_mux_select_chan(adap, priv->chan_id, &oldclock);
 	if (ret >= 0)
 		ret = i2c_smbus_xfer(parent, addr, flags,
 				     read_write, command, size, data);
-	if (muxc->deselect)
-		muxc->deselect(muxc, priv->chan_id);
+
+	i2c_mux_deselect_chan(adap, priv->chan_id, oldclock);
 
 	return ret;
 }
@@ -362,6 +419,32 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
 			}
 		}
 
+		of_property_read_u32(child, "clock-frequency", &priv->adap.clock_hz);
+
+		/* If the mux adapter has no clock-frequency property, inherit from parent */
+		if (!priv->adap.clock_hz)
+			priv->adap.clock_hz = parent->clock_hz;
+
+		/*
+		 * Warn if the mux adapter is not parent-locked as
+		 * this may cause issues for some hardware topologies.
+		 */
+		if ((priv->adap.clock_hz < parent->clock_hz) && muxc->mux_locked)
+			dev_warn(muxc->dev,
+				 "channel %u is slower than parent on a non parent-locked mux\n",
+				 chan_id);
+
+		/* We don't support mux adapters faster than their parent */
+		if (priv->adap.clock_hz > parent->clock_hz) {
+			dev_err(muxc->dev,
+				"channel (%u) is faster (%u) than parent (%u)\n",
+				chan_id, priv->adap.clock_hz, parent->clock_hz);
+
+			of_node_put(mux_node);
+			ret = -EINVAL;
+			goto err_free_priv;
+		}
+
 		priv->adap.dev.of_node = child;
 		of_node_put(mux_node);
 	}

-- 
2.53.0



^ 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