* Re: [PATCH v1 4/4] iommu/arm-smmu-v3: Process vIOMMU invalidations in batches
From: Nicolin Chen @ 2026-06-15 20:19 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: Will Deacon, Kevin Tian, Robin Murphy, Joerg Roedel, Shuah Khan,
Pranjal Shrivastava, Kees Cook, Yi Liu, Eric Auger,
linux-arm-kernel, iommu, linux-kernel, linux-kselftest
In-Reply-To: <20260615134301.GL1962447@nvidia.com>
On Mon, Jun 15, 2026 at 10:43:01AM -0300, Jason Gunthorpe wrote:
> On Fri, Jun 12, 2026 at 12:11:10PM -0700, Nicolin Chen wrote:
>
> > VMM would have to know which command failed, to flag it in the CONS
> > register, indicating: a) commands prior to the CONS are issued, and
> > b) command pointed by the CONS is illegal.
>
> It is a VMM bug to send a malformed command into the kernel in the
> first place.
OK. I will follow that.
Thanks
Nicolin
^ permalink raw reply
* Re: [PATCH v2 1/5] arm64: Rename page table BSS section to .bss..pgtbl
From: Frank Li @ 2026-06-15 20:09 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-arm-kernel, linux-kernel, will, catalin.marinas,
Ard Biesheuvel, Kevin Brodsky, Mark Brown, Marc Zyngier
In-Reply-To: <20260604151151.150377-8-ardb+git@google.com>
On Thu, Jun 04, 2026 at 05:11:53PM +0200, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Rename the .pgdir.bss section to .bss..pgtbl so that the compiler will
> notice the leading ".bss" and mark it as NOBITS by default (rather than
> PROGBITS, which would take up space in Image binary, forcing all of the
> preceding BSS to be emitted into the image as well). This supersedes the
> NOLOAD linker directive, which achieves the same thing, and can be
> therefore be dropped.
>
> Also, rename .pgdir to .pgtbl to be more generic, as page tables of
> various levels will reside here.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
I met boot failure for i.MX8QXP by this patch
[ 0.823515] Unable to handle kernel paging request at virtual address ffff00000328f000
[ 0.831116] Mem abort info:
[ 0.833886] ESR = 0x0000000096000147
[ 0.837622] EC = 0x25: DABT (current EL), IL = 32 bits
[ 0.842923] SET = 0, FnV = 0
[ 0.845961] EA = 0, S1PTW = 0
[ 0.849088] FSC = 0x07: level 3 translation fault
[ 0.853952] Data abort info:
[ 0.856809] ISV = 0, ISS = 0x00000147, ISS2 = 0x00000000
[ 0.862296] CM = 1, WnR = 1, TnD = 0, TagAccess = 0
[ 0.867330] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 0.872633] swapper pgtable: 4k pages, 48-bit VAs, pgdp=000000008211f000
[ 0.879321] [ffff00000328f000] pgd=0000000000000000, p4d=18000008bffff403, pud=18000008bfffe403, pmd=18000008bffea403, pte=00e800008328ff06
[ 0.891834] Internal error: Oops: 0000000096000147 [#1] SMP
[ 0.897469] Modules linked in:
[ 0.900514] CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 7.1.0-rc1-00016-g63e0b6a5b693 #834 PREEMPT
[ 0.909978] Hardware name: Freescale i.MX8QXP MEK (DT)
[ 0.915104] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 0.922053] pc : dcache_clean_inval_poc+0x24/0x48
[ 0.926742] lr : kvm_arm_init+0xa78/0x1638
[ 0.930828] sp : ffff80008318bd10
[ 0.934127] x29: ffff80008318bd50 x28: 0000000000000000 x27: ffff00000328f000
[ 0.941251] x26: 0000000000002000 x25: ffff80008219e000 x24: 0000000001002222
[ 0.948374] x23: 0000000000000030 x22: ffff800081e850c0 x21: ffff800082b790d0
[ 0.955498] x20: 0000000000000004 x19: ffff8000830a0000 x18: 0000000000000000
[ 0.962622] x17: ffff800082f938b8 x16: ffff800082b8b4e0 x15: ffff800082b8b4b8
[ 0.969746] x14: ffff80008308f0a0 x13: ffff800082b8b490 x12: ffff800082b8b530
[ 0.976869] x11: ffff800082b8b508 x10: ffff80008308f140 x9 : ffff80008308f118
[ 0.983993] x8 : ffff80008308f0f0 x7 : ffff80008308f0c8 x6 : ffff80008308f078
[ 0.991117] x5 : ffff80008308f050 x4 : ffff800082b8b468 x3 : 000000000000003f
[ 0.998240] x2 : 0000000000000040 x1 : ffff000003291000 x0 : ffff00000328f000
[ 1.005367] Call trace:
[ 1.007800] dcache_clean_inval_poc+0x24/0x48 (P)
[ 1.012490] do_one_initcall+0x80/0x1c8
[ 1.016310] kernel_init_freeable+0x208/0x2f0
[ 1.020654] kernel_init+0x24/0x1e0
[ 1.024131] ret_from_fork+0x10/0x20
[ 1.027700] Code: 9ac32042 d1000443 8a230000 d503201f (d50b7e20)
[ 1.033779] ---[ end trace 0000000000000000 ]---
[ 1.038428] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[ 1.046026] SMP: stopping secondary CPUs
[ 1.049943] Kernel Offset: disabled
[ 1.053408] CPU features: 0x00000000,00000008,00040021,0400421b
[ 1.059316] Memory Limit: none
[ 1.062359] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---
Any idea?
Frank
> arch/arm64/include/asm/linkage.h | 2 ++
> arch/arm64/include/asm/mmu.h | 2 --
> arch/arm64/kernel/vmlinux.lds.S | 8 ++++----
> arch/arm64/mm/fixmap.c | 6 +++---
> arch/arm64/mm/kasan_init.c | 2 +-
> 5 files changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm64/include/asm/linkage.h b/arch/arm64/include/asm/linkage.h
> index 40bd17add539..8637f667667c 100644
> --- a/arch/arm64/include/asm/linkage.h
> +++ b/arch/arm64/include/asm/linkage.h
> @@ -43,4 +43,6 @@
> SYM_TYPED_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) \
> bti c ;
>
> +#define __bss_pgtbl __section(".bss..pgtbl") __aligned(PAGE_SIZE)
> +
> #endif
> diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
> index fb95754f2876..5e1211c540ab 100644
> --- a/arch/arm64/include/asm/mmu.h
> +++ b/arch/arm64/include/asm/mmu.h
> @@ -13,8 +13,6 @@
>
> #ifndef __ASSEMBLER__
>
> -#define __pgtbl_bss __section(".pgdir.bss") __aligned(PAGE_SIZE)
> -
> #include <linux/refcount.h>
> #include <asm/cpufeature.h>
>
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index 2b0ebfb30c63..d3ed59abab38 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -352,11 +352,11 @@ SECTIONS
> BSS_SECTION(SBSS_ALIGN, 0, PAGE_SIZE)
> __pi___bss_start = __bss_start;
>
> - /* fixmap BSS starts here - preceding data/BSS is omitted from the linear map */
> - .pgdir.bss (NOLOAD) : ALIGN(PAGE_SIZE) {
> - *(.pgdir.bss)
> + /* page table BSS starts here - preceding data/BSS is omitted from the linear map */
> + .pgtbl : ALIGN(PAGE_SIZE) {
> + *(.bss..pgtbl)
> }
> - ASSERT(ADDR(.pgdir.bss) == __bss_stop, ".pgdir.bss must follow BSS")
> + ASSERT(ADDR(.pgtbl) == __bss_stop, ".pgtbl must follow BSS")
>
> . = ALIGN(PAGE_SIZE);
> __pi_init_pg_dir = .;
> diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
> index 1a3bbd67dd76..f66a0016dd02 100644
> --- a/arch/arm64/mm/fixmap.c
> +++ b/arch/arm64/mm/fixmap.c
> @@ -31,9 +31,9 @@ static_assert(NR_BM_PMD_TABLES == 1);
>
> #define BM_PTE_TABLE_IDX(addr) __BM_TABLE_IDX(addr, PMD_SHIFT)
>
> -static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __pgtbl_bss;
> -static pmd_t bm_pmd[PTRS_PER_PMD] __pgtbl_bss __maybe_unused;
> -static pud_t bm_pud[PTRS_PER_PUD] __pgtbl_bss __maybe_unused;
> +static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __bss_pgtbl;
> +static pmd_t bm_pmd[PTRS_PER_PMD] __bss_pgtbl __maybe_unused;
> +static pud_t bm_pud[PTRS_PER_PUD] __bss_pgtbl __maybe_unused;
>
> static inline pte_t *fixmap_pte(unsigned long addr)
> {
> diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c
> index dbf22cae82ee..3fcad956fdf7 100644
> --- a/arch/arm64/mm/kasan_init.c
> +++ b/arch/arm64/mm/kasan_init.c
> @@ -214,7 +214,7 @@ asmlinkage void __init kasan_early_init(void)
> * shadow pud_t[]/p4d_t[], which could end up getting corrupted
> * when the linear region is mapped.
> */
> - static pte_t tbl[PTRS_PER_PTE] __pgtbl_bss;
> + static pte_t tbl[PTRS_PER_PTE] __bss_pgtbl;
> pgd_t *pgdp = pgd_offset_k(KASAN_SHADOW_START);
>
> set_pgd(pgdp, __pgd(__pa_symbol(tbl) | PGD_TYPE_TABLE));
> --
> 2.54.0.1032.g2f8565e1d1-goog
>
^ permalink raw reply
* [PATCH] iommu/arm-smmu-v3: Declare eats_s1chk and eats_trans as host-endian u64
From: Nicolin Chen @ 2026-06-15 19:45 UTC (permalink / raw)
To: Will Deacon
Cc: Robin Murphy, joro, Jason Gunthorpe, Shuai Xue, linux-arm-kernel,
iommu, linux-kernel
arm_smmu_get_ste_update_safe() declares the eats_s1chk and eats_trans
locals as __le64, but initializes them from FIELD_PREP(), which returns a
host-endian value, and passes them through cpu_to_le64() at the use sites.
Sparse reports the following warnings:
>> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c:1122:38: sparse: sparse: cast from restricted __le64
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c:1124:33: sparse: sparse: cast from restricted __le64
Declare both locals as u64 so the type matches FIELD_PREP() and the
existing cpu_to_le64() at the use sites performs the host-to-little-endian
conversion. No functional change.
Fixes: 7cad80048595 ("iommu/arm-smmu-v3: Mark EATS_TRANS safe when computing the update sequence")
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/all/202606151017.QU0evpH9-lkp@intel.com/
Assisted-by: Claude:claude-opus-4-8
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(-)
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 8ce3e801eda3b..4c0f7b17b1f37 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1240,9 +1240,9 @@ VISIBLE_IF_KUNIT
void arm_smmu_get_ste_update_safe(const __le64 *cur, const __le64 *target,
__le64 *safe_bits)
{
- const __le64 eats_s1chk =
+ const u64 eats_s1chk =
FIELD_PREP(STRTAB_STE_1_EATS, STRTAB_STE_1_EATS_S1CHK);
- const __le64 eats_trans =
+ const u64 eats_trans =
FIELD_PREP(STRTAB_STE_1_EATS, STRTAB_STE_1_EATS_TRANS);
/*
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v8 09/12] iommu/arm-smmu-v3: Implement pm_runtime & system sleep ops
From: Pranjal Shrivastava @ 2026-06-15 19:44 UTC (permalink / raw)
To: Mostafa Saleh
Cc: iommu, Will Deacon, Joerg Roedel, Robin Murphy, Jason Gunthorpe,
Nicolin Chen, Daniel Mentz, Ashish Mhetre, linux-arm-kernel
In-Reply-To: <ajBCazla1VoJX9Ms@google.com>
On Mon, Jun 15, 2026 at 06:20:27PM +0000, Mostafa Saleh wrote:
> On Mon, Jun 01, 2026 at 09:59:06PM +0000, Pranjal Shrivastava wrote:
> > Implement pm_runtime and system sleep ops for arm-smmu-v3.
> >
> > The suspend callback configures the SMMU to abort new transactions,
> > disables the main translation unit and then drains the command queue
> > to ensure completion of any in-flight commands. A software gate
> > (STOP_FLAG) and synchronization barriers are used to quiesce the command
> > submission pipeline and ensure state consistency before power-off.
> >
> > To prevent software metadata flags from leaking into physical registers
> > or polluting the tracking pointer, a newly introduced bitmask
> > (CMDQ_PROD_IDX_MASK) is applied to all register writes and tracking
> > updates.
> >
> > The resume callback restores the MSI configuration and performs a full
> > device reset via `arm_smmu_device_reset` to bring the SMMU back to an
> > operational state. The MSIs are cached during the msi_write and are
> > restored during the resume operation by using the helper. The STOP_FLAG
> > is cleared only after the CMDQ is enabled in hardware.
> >
> > Suggested-by: Daniel Mentz <danielmentz@google.com>
> > Signed-off-by: Pranjal Shrivastava <praan@google.com>
> > ---
> >
[...]
> > + /* Clear any flags from the previous life */
> > + atomic_andnot(CMDQ_PROD_STOP_FLAG, &smmu->cmdq.owner_prod);
> > + atomic_andnot(CMDQ_PROD_STOP_FLAG, &smmu->cmdq.q.llq.atomic.prod);
>
> Should not that be done from the suspend call?
I'm not sure if I understand? We're just clearing the flag here?
We set the flag in suspend to close the gate and clear it in resume
to re-open it. Clearing it at the end of suspend would be wrong as it
would allow new submissions while the SMMU is off..
Additionally, I'll remove the redundant operation on owner_prod (since
it's never set in owner_prod) if that's what you're saying?
>
> > +
> > /* Invalidate any cached configuration */
> > arm_smmu_cmdq_issue_cmd_with_sync(smmu, arm_smmu_make_cmd_cfgi_all());
> >
> > @@ -4898,6 +4939,21 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
> > if (is_kdump_kernel())
> > enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
> >
> > + /*
> > + * While the SMMU was suspended, concurrent CPU threads may have
> > + * updated in-memory structures (such as STEs, CDs, and PTEs).
> > + * Any invalidations corresponding to those updates were safely
> > + * elided because the command queue was stopped (STOP_FLAG == 1).
> > + *
> > + * Since the reset invalidate-all commands above have fully cleared
> > + * the HW TLBs and config caches, the SMMU will fetch these descriptors
> > + * directly from RAM as soon as translation is enabled.
> > + *
> > + * Add a memory barrier to collect all prior RAM writes to ensure the
> > + * SMMU sees a consistent view of memory before translation is enabled.
> > + */
> > + smp_mb();
>
> Should not that be dma_wmb() as this is syncing with the HW?
>
Right.. as discussed with Daniel on the other thread, the dma_wmb()
inside the issue_cmdlist() already ensures that PTE writes have reached
RAM. I'll update the comments to clarify the barrier design here.
The first CFGI_ALL invalidation we issue on resume uses the CMDQ's
standard submission path already includes the necessary dma_wmb().
This ensures that the hardware sees the correct state before we set
SMMUEN=1. I'll update the comment to clarify that we are relying on
this existing synchronization rather than adding a redundant barrier.
> > +
> > /* Enable the SMMU interface */
> > enables |= CR0_SMMUEN;
> > ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
> > @@ -5580,6 +5636,117 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev)
> > arm_smmu_device_disable(smmu);
> > }
> >
> > +static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
> > +{
> > + struct arm_smmu_device *smmu = dev_get_drvdata(dev);
> > + struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
> > + int timeout = ARM_SMMU_SUSPEND_TIMEOUT_US;
> > + u32 enables, target;
> > + int ret;
> > +
> > + /* Abort all transactions before disable to avoid spurious bypass */
> > + arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
> > +
> > + /* Disable the SMMU via CR0.EN and all queues except CMDQ */
> > + enables = CR0_CMDQEN;
> > + ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, ARM_SMMU_CR0ACK);
> > + if (ret) {
> > + dev_err(smmu->dev, "failed to disable SMMU\n");
> > + return ret;
> > + }
> > +
> > + /*
> > + * At this point the SMMU is completely disabled and won't access
> > + * any translation/config structures, even speculative accesses
> > + * aren't performed as per the IHI0070 spec (section 6.3.9.6).
> > + */
> > +
> > + /* Mark the CMDQ to stop and get the target index before the stop */
> > + target = atomic_fetch_or_relaxed(CMDQ_PROD_STOP_FLAG, &cmdq->q.llq.atomic.prod);
>
> As Daniel mentioned, I think this shouldn't be relaxed.
>
Ack. I agree, I mis-read the kdoc about this, I'll fix it.
> > + target &= CMDQ_PROD_IDX_MASK;
> > +
> > +
> > + /* Wait for the last committed owner to reach the hardware */
> > + while ((arm_smmu_cmdq_owner_prod_idx(cmdq) != target) && --timeout)
> > + udelay(1);
>
> I think --timeout has an off-by-one.
>
Good catch, I'll fix this!
Thanks,
Praan
^ permalink raw reply
* Re: [PATCH v6 3/3] PCI: rockchip: drive at 2.5 GT/s, error other speeds
From: Geraldo Nascimento @ 2026-06-15 19:30 UTC (permalink / raw)
To: Shawn Lin, Dragan Simic
Cc: linux-rockchip, Lorenzo Pieralisi, Krzysztof Wilczyński,
Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, linux-pci,
linux-arm-kernel, linux-kernel
In-Reply-To: <4ac5cd7d2271df375ed6307f5c394247721395d9.1781207474.git.geraldogabriel@gmail.com>
Hi,
On Thu, Jun 11, 2026 at 05:04:22PM -0300, Geraldo Nascimento wrote:
> Configure the core to be driven at 2.5 GT/s Link Speed and ignore
> any other speed with a warning. Also drop the 5.0 GT/s Link Speed
> defines from Rockchip PCIe header.
>
> The reason is that Shawn Lin from Rockchip has reiterated that there
> may be danger of "catastrophic failure" in using their PCIe with
> 5.0 GT/s speeds.
>
> While Rockchip has done so informally without issuing a proper errata,
> and the particulars are thus unknown, this may cause data loss or
> worse.
>
> This change is corroborated by RK3399 official datasheet [1], which
> states maximum link speed for this platform is 2.5 GT/s.
>
> [1] https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf
>
> Fixes: 956cd99b35a8 ("PCI: rockchip: Separate common code from RC driver")
> Link: https://lore.kernel.org/all/ffd05070-9879-4468-94e3-b88968b4c21b@rock-chips.com/
> Cc: stable@vger.kernel.org
> Reported-by: Dragan Simic <dsimic@manjaro.org>
> Reported-by: Shawn Lin <shawn.lin@rock-chips.com>
> Signed-off-by: Geraldo Nascimento <geraldogabriel@gmail.com>
> ---
> drivers/pci/controller/pcie-rockchip.c | 16 +++++++++-------
> drivers/pci/controller/pcie-rockchip.h | 3 ---
> 2 files changed, 9 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/pci/controller/pcie-rockchip.c b/drivers/pci/controller/pcie-rockchip.c
> index 0f88da3788054..5a2876d7c8547 100644
> --- a/drivers/pci/controller/pcie-rockchip.c
> +++ b/drivers/pci/controller/pcie-rockchip.c
> @@ -66,8 +66,10 @@ int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip)
> }
>
> rockchip->link_gen = of_pci_get_max_link_speed(node);
> - if (rockchip->link_gen < 0 || rockchip->link_gen > 2)
> - rockchip->link_gen = 2;
> + if (rockchip->link_gen < 0 || rockchip->link_gen >= 2) {
> + rockchip->link_gen = 1;
> + dev_warn(dev, "invalid max-link-speed, limited to 2.5 GT/s\n");
> + }
>
> for (i = 0; i < ROCKCHIP_NUM_PM_RSTS; i++)
> rockchip->pm_rsts[i].id = rockchip_pci_pm_rsts[i];
> @@ -147,12 +149,12 @@ int rockchip_pcie_init_port(struct rockchip_pcie *rockchip)
> goto err_exit_phy;
> }
>
> + /* 5.0 GT/s may cause catastrophic failure for this core */
> if (rockchip->link_gen == 2)
> - rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2,
Sashiko caught unreachable dead code rightfully here. It looks like I
had got it right in v4 and then the fix regressed.
Will address this for v7 after I get more comments.
Thanks,
Geraldo Nascimento
^ permalink raw reply
* [PATCH v1] bus: mvebu-mbus: Fix OF node reference leaks in DT init
From: Yuho Choi @ 2026-06-15 19:12 UTC (permalink / raw)
To: Andrew Lunn, Sebastian Hesselbarth, Gregory Clement
Cc: linux-arm-kernel, linux-kernel, Yuho Choi
mvebu_mbus_dt_init() gets the MBUS node with
of_find_matching_node_and_match() and the controller node with
of_find_node_by_phandle(). Both helpers return nodes with incremented
references, but the function returns without dropping either reference.
Route the error and success paths through common cleanup labels so both
local node references are released once they are no longer needed.
Fixes: 6839cfa82f99 ("bus: mvebu-mbus: Introduce device tree binding")
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
---
drivers/bus/mvebu-mbus.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index dd94145c9b22..61301beeecdc 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -1265,23 +1265,27 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
prop = of_get_property(np, "controller", NULL);
if (!prop) {
pr_err("required 'controller' property missing\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_np;
}
controller = of_find_node_by_phandle(be32_to_cpup(prop));
if (!controller) {
pr_err("could not find an 'mbus-controller' node\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto put_np;
}
if (of_address_to_resource(controller, 0, &mbuswins_res)) {
pr_err("cannot get MBUS register address\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_controller;
}
if (of_address_to_resource(controller, 1, &sdramwins_res)) {
pr_err("cannot get SDRAM register address\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_controller;
}
/*
@@ -1312,9 +1316,15 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
resource_size(&mbusbridge_res),
is_coherent);
if (ret)
- return ret;
+ goto put_controller;
/* Setup statically declared windows in the DT */
- return mbus_dt_setup(&mbus_state, np);
+ ret = mbus_dt_setup(&mbus_state, np);
+
+put_controller:
+ of_node_put(controller);
+put_np:
+ of_node_put(np);
+ return ret;
}
#endif
--
2.43.0
^ permalink raw reply related
* Re: [RFC PATCH] KVM: Ignore MMU notifiers for guest_memfd-only memslots
From: David Hildenbrand @ 2026-06-15 19:07 UTC (permalink / raw)
To: Alexandru Elisei, pbonzini, kvm, linux-kernel, maz, oupton,
suzuki.poulose, kvmarm, linux-arm-kernel, seanjc, mark.rutland
In-Reply-To: <20260615155244.183044-1-alexandru.elisei@arm.com>
On 6/15/26 17:52, Alexandru Elisei wrote:
> For guest_memfd-only memslots (kvm_memslot_is_gmem_only() is true), the
> memory provider for the virtual machine is the guest_memfd file, not the
> userspace mapping. Faults are resolved using the guest_memfd page cache,
> and the permissions for the secondary MMU mapping depends exclusively on
> the memslot (i.e, if the memslot is read-only). How userspace happens to
> have the memory mmaped at fault time, or even if the memory is mapped at
> all into userspace, is not taken into consideration.
>
> guest_memfd memory is not evictable, is not movable and there's no backing
> storage. Once memory is allocated for an offset in guest_memfd file, the
> offset will not change, and that memory is not freed unless userspace
> explicitly punches a hole in the file. As a result, memory reclaim, page
> migration, page aging and dirty page tracking for the userspace mapping
> serve little purpose.
I don't think any of that is relevant for the patch at hand?
The thing is: invalidation (truncation, later migration, for any other reason)
is driven through guest_memfd notifications, not through unrelated page tables.
If we don't lookup pages for the KVM MMU through the page table, then there is
also no need for MMU notifiers. It's all guest_memfd only.
Or am I missing something?
--
Cheers,
David
^ permalink raw reply
* Re: [PATCH] arm64: tlb: Flush walk cache when unsharing PMD tables
From: David Hildenbrand (Arm) @ 2026-06-15 19:00 UTC (permalink / raw)
To: Catalin Marinas, Zeng Heng
Cc: will, akpm, npiggin, aneesh.kumar, peterz, linux-kernel,
wangkefeng.wang, linux-arm-kernel, linux-mm, linux-arch,
Paul Walmsley, Palmer Dabbelt, Albert Ou
In-Reply-To: <ag8fHYL-S26uO0yZ@arm.com>
On 5/21/26 17:05, Catalin Marinas wrote:
> + David H.
>
> On Thu, May 21, 2026 at 03:30:11PM +0800, Zeng Heng wrote:
>> From: Zeng Heng <zengheng4@huawei.com>
>>
>> When huge_pmd_unshare() is called to unshare a PMD table, the
>> tlb_unshare_pmd_ptdesc() function sets tlb->unshared_tables=true
>> but the aarch64 tlb_flush() only checked tlb->freed_tables to
>> determine whether to use TLBF_NONE (vae1is, invalidates walk
>> cache) or TLBF_NOWALKCACHE (vale1is, leaf-only).
>>
>> This caused the stale PMD page table entry to remain in the walk cache
>> after unshare, potentially leading to incorrect page table walks.
>>
>> Fix by including unshared_tables in the check, so that when
>> unsharing tables, TLBF_NONE is used and the walk cache is properly
>> invalidated.
>>
>> Here is the detailed distinction between vae1is and vale1is:
>>
>> | Instruction Combination | Actual Invalidation Scope |
>> | ------------------------ | --------------------------------------------------|
>> | `VAE1IS` + TTL=`0` | All entries at all levels (full invalidation) |
>> | `VAE1IS` + TTL=`2` (L2) | Non-leaf at Level 0/1 + leaf at Level 2 |
>> | `VALE1IS` + TTL=`0` | Leaf entries at all levels (non-leaf not cleared) |
>> | `VALE1IS` + TTL=`2` (L2) | Leaf entry at Level 2 only |
>>
>> Signed-off-by: Zeng Heng <zengheng4@huawei.com>
>
> The fix looks fine but does it need:
I'm late ... just stumbled over this in my inbox while digging though a pile.
>
> Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
> Cc: <stable@vger.kernel.org>
Very likely, yes.
>
>> ---
>> arch/arm64/include/asm/tlb.h | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
>> index 10869d7731b8..751bd57bc3ba 100644
>> --- a/arch/arm64/include/asm/tlb.h
>> +++ b/arch/arm64/include/asm/tlb.h
>> @@ -53,7 +53,8 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
>> static inline void tlb_flush(struct mmu_gather *tlb)
>> {
>> struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
>> - tlbf_t flags = tlb->freed_tables ? TLBF_NONE : TLBF_NOWALKCACHE;
>> + tlbf_t flags = (tlb->freed_tables || tlb->unshared_tables) ?
>> + TLBF_NONE : TLBF_NOWALKCACHE;
>> unsigned long stride = tlb_get_unmap_size(tlb);
>> int tlb_level = tlb_get_level(tlb);
>>
Right, the old code would have effectively called flush_tlb_range() ->
flush_tlb_mm_range() with freed_tables=true.
I recall that being a tricky bit. The commit documents that as:
(1) tlb_remove_table_sync_one() is a NOP on architectures without
CONFIG_MMU_GATHER_RCU_TABLE_FREE.
Here, the assumption is that the previous TLB flush would send an
IPI to all relevant CPUs. Careful: some architectures like x86 only
send IPIs to all relevant CPUs when tlb->freed_tables is set.
The relevant architectures should be selecting
MMU_GATHER_RCU_TABLE_FREE, but x86 might not do that in stable
kernels and it might have been problematic before this patch.
Also, the arch flushing behavior (independent of IPIs) is different
when tlb->freed_tables is set. Do we have to enlighten them to also
take care of tlb->unshared_tables? So far we didn't care, so
hopefully we are fine. Of course, we could be setting
tlb->freed_tables as well, but that might then unnecessarily flush
too much, because the semantics of tlb->freed_tables are a bit
fuzzy.
Turns out I was thinking too much in terms of optimizing IPIs.
Besides arm64 and x86, powerpc and riscv also rely on "tlb->freed_tables"
in tlb_flush(). But only arm64, x86 and riscv support ARCH_WANT_HUGE_PMD_SHARE.
Which makes me wonder whether we also need:
diff --git a/arch/riscv/include/asm/tlb.h b/arch/riscv/include/asm/tlb.h
index 50b63b5c15bd..17c551322b5d 100644
--- a/arch/riscv/include/asm/tlb.h
+++ b/arch/riscv/include/asm/tlb.h
@@ -16,7 +16,8 @@ static void tlb_flush(struct mmu_gather *tlb);
static inline void tlb_flush(struct mmu_gather *tlb)
{
#ifdef CONFIG_MMU
- if (tlb->fullmm || tlb->need_flush_all || tlb->freed_tables)
+ if (tlb->fullmm || tlb->need_flush_all || tlb->freed_tables ||
+ tlb->unshared_tables)
flush_tlb_mm(tlb->mm);
else
flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end,
CCing riscv maintainers.
--
Cheers,
David
^ permalink raw reply related
* [PATCH v1] ARM: mvebu: Fix CPU node reference leak in get_cpu_clk()
From: Yuho Choi @ 2026-06-15 18:59 UTC (permalink / raw)
To: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth, Russell King
Cc: linux-arm-kernel, linux-kernel, Yuho Choi
of_get_cpu_node() returns a reference to the CPU device node.
get_cpu_clk() only needs that node for of_clk_get(), but never drops the
reference after the clock lookup.
Drop the CPU node reference before returning the clock, covering both
the successful lookup and the IS_ERR() path.
Fixes: f6cec7cd0777 ("ARM: mvebu: remove device tree parsing for cpu nodes")
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
---
arch/arm/mach-mvebu/platsmp.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index 18384ea6862c..0f14d7376770 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -42,6 +42,7 @@ static struct clk *get_cpu_clk(int cpu)
if (WARN(!np, "missing cpu node\n"))
return NULL;
cpu_clk = of_clk_get(np, 0);
+ of_node_put(np);
if (WARN_ON(IS_ERR(cpu_clk)))
return NULL;
return cpu_clk;
--
2.43.0
^ permalink raw reply related
* [PATCH v4] ASoC: dt-bindings: mtk-btcvsd-snd: Convert to DT Schema
From: Luca Leonardo Scorcia @ 2026-06-15 18:57 UTC (permalink / raw)
To: linux-mediatek
Cc: Luca Leonardo Scorcia, Liam Girdwood, Mark Brown, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, linux-sound, devicetree, linux-kernel,
linux-arm-kernel
Convert the mtk-btcvsd-snd.txt DT binding to DT Schema format.
Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
---
Changes in v4:
- Removed minItems, maxItems properties from reg node
- Removed the reg-names property
- Adjusted the example
Changes in v3 [3]:
Sorry about the spam. A second round of dt_binding_check + dtbs_check
led me to additional improvements:
- Use reg-names in place of a non-informative description property
- Simplify the reg property in the example
Changes in v2 [2]:
- Fixed issues from make dt_binding_check
- Set myself as maintainer for the binding
Initial version [1].
[1] https://lore.kernel.org/20260420204514.1640995-1-l.scorcia@gmail.com/
[2] https://lore.kernel.org/20260421154619.227039-1-l.scorcia@gmail.com/
[3] https://lore.kernel.org/linux-mediatek/20260421193858.347258-1-l.scorcia@gmail.com/
.../sound/mediatek,mtk-btcvsd-snd.yaml | 59 +++++++++++++++++++
.../bindings/sound/mtk-btcvsd-snd.txt | 24 --------
2 files changed, 59 insertions(+), 24 deletions(-)
create mode 100644 Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
delete mode 100644 Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
diff --git a/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.yaml
new file mode 100644
index 000000000000..1b7451655476
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mediatek,mtk-btcvsd-snd.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/mediatek,mtk-btcvsd-snd.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mediatek ALSA BT SCO CVSD/MSBC
+
+maintainers:
+ - Luca Leonardo Scorcia <l.scorcia@gmail.com>
+
+properties:
+ compatible:
+ const: mediatek,mtk-btcvsd-snd
+
+ reg:
+ items:
+ - description: PKV region
+ - description: SRAM_BANK2 region
+
+ interrupts:
+ items:
+ - description: BT-SCO interrupt
+
+ mediatek,infracfg:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: The phandle of the infracfg controller
+
+ mediatek,offset:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description: Array of register offsets and masks
+ items:
+ - description: infra_misc_offset
+ - description: infra_conn_bt_cvsd_mask
+ - description: cvsd_mcu_read_offset
+ - description: cvsd_mcu_write_offset
+ - description: cvsd_packet_indicator_offset
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - mediatek,infracfg
+ - mediatek,offset
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ mtk-btcvsd-snd@18000000 {
+ compatible = "mediatek,mtk-btcvsd-snd";
+ reg = <0x18000000 0x1000>,
+ <0x18080000 0x8000>;
+ interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
+ mediatek,infracfg = <&infrasys>;
+ mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt b/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
deleted file mode 100644
index 679e44839b48..000000000000
--- a/Documentation/devicetree/bindings/sound/mtk-btcvsd-snd.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-Mediatek ALSA BT SCO CVSD/MSBC Driver
-
-Required properties:
-- compatible = "mediatek,mtk-btcvsd-snd";
-- reg: register location and size of PKV and SRAM_BANK2
-- interrupts: should contain BTSCO interrupt
-- mediatek,infracfg: the phandles of INFRASYS
-- mediatek,offset: Array contains of register offset and mask
- infra_misc_offset,
- infra_conn_bt_cvsd_mask,
- cvsd_mcu_read_offset,
- cvsd_mcu_write_offset,
- cvsd_packet_indicator_offset
-
-Example:
-
- mtk-btcvsd-snd@18000000 {
- compatible = "mediatek,mtk-btcvsd-snd";
- reg=<0 0x18000000 0 0x1000>,
- <0 0x18080000 0 0x8000>;
- interrupts = <GIC_SPI 286 IRQ_TYPE_LEVEL_LOW>;
- mediatek,infracfg = <&infrasys>;
- mediatek,offset = <0xf00 0x800 0xfd0 0xfd4 0xfd8>;
- };
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v11 4/6] dt-bindings: pinctrl: s32g2-siul2: describe GPIO and EIRQ resources
From: Rob Herring (Arm) @ 2026-06-15 18:49 UTC (permalink / raw)
To: Khristine Andreea Barbulescu
Cc: Linus Walleij, Rafael J. Wysocki, Eric Chanudet, Christophe Lizzi,
NXP S32 Linux Team, Larisa Grigore, Vincent Guittot,
Pengutronix Kernel Team, linux-kernel, Alberto Ruiz,
Matthias Brugger, Sascha Hauer, linux-arm-kernel,
Greg Kroah-Hartman, Fabio Estevam, Krzysztof Kozlowski,
Ghennadi Procopciuc, Dong Aisheng, Chester Lin, imx, Lee Jones,
linux-gpio, Enric Balletbo, Shawn Guo, Bartosz Golaszewski,
devicetree, Conor Dooley, Jacky Bai, Srinivas Kandagatla
In-Reply-To: <20260610132116.1998140-5-khristineandreea.barbulescu@oss.nxp.com>
On Wed, 10 Jun 2026 15:21:14 +0200, Khristine Andreea Barbulescu wrote:
> Extend the S32G2 SIUL2 pinctrl binding to describe the GPIO data and
> external interrupt resources present in the same SIUL2 hardware block.
>
> Besides the MSCR and IMCR registers used for pin multiplexing and pad
> configuration, SIUL2 also contains PGPDO and PGPDI registers
> for GPIO data and EIRQ registers for external interrupt control.
>
> Add GPIO controller properties because the SIUL2 block also provides
> GPIO functionality, and gpio-ranges are needed to describe the
> mapping between GPIO lines and pin controller pins.
>
> Document the interrupt controller properties. The SIUL2 block
> contains EIRQ hardware as part of the same register space. IRQ support
> itself will be added in a follow-up patch series.
>
> Update the example accordingly to show the complete SIUL2 register
> layout, including the GPIO data and EIRQ register windows.
>
> Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
> ---
> .../pinctrl/nxp,s32g2-siul2-pinctrl.yaml | 90 +++++++++++++++++--
> 1 file changed, 84 insertions(+), 6 deletions(-)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH v3 1/3] dt-bindings: soc: imx: fsl,imx93-media-blk-ctrl: Allow LVDS Display Bridge child node
From: Rob Herring (Arm) @ 2026-06-15 18:47 UTC (permalink / raw)
To: Liu Ying
Cc: Frank Li, imx, Conor Dooley, linux-arm-kernel, linux-kernel,
Fabio Estevam, devicetree, Marco Felsch, Pengutronix Kernel Team,
Sascha Hauer, Krzysztof Kozlowski, Peng Fan
In-Reply-To: <20260610-imx93-ldb-v3-1-c9b65d742753@nxp.com>
On Wed, 10 Jun 2026 17:26:21 +0800, Liu Ying wrote:
> i.MX93 SoC mediamix blk-ctrl contains one LDB_CTRL register and one LVDS
> register which control video output through a LVDS interface. Allow the
> LVDS Display Bridge(LDB) child node and add the child node to example.
>
> i.MX93 LDB child node(bridge@20) is an addressable node, while i.MX93
> Parallel Display Format Configuration(PDFC) child node(dpi-bridge) is a
> non-addressable node. Mixing the addressable and non-addressable child
> nodes is allowed according to discussion [1].
>
> Link: https://lore.kernel.org/all/n6akxiayi3g6gxcqhreb4iaohmeokoalnqup6h5r2fwdt4zijt@u2wyps55ayqm/ [1]
> Signed-off-by: Liu Ying <victor.liu@nxp.com>
> ---
> .../bindings/soc/imx/fsl,imx93-media-blk-ctrl.yaml | 39 ++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* [PATCH v3 0/2] Input: apple_z2 - bound device-reported packet length and finger count
From: Bryam Vargas via B4 Relay @ 2026-06-15 18:20 UTC (permalink / raw)
To: Sasha Finkelstein, Dmitry Torokhov
Cc: linux-arm-kernel, linux-kernel, Neal Gompa, asahi, Sven Peter,
linux-input, Janne Grunau
The Apple Z2 touch controller is across an SPI bus and its reports are not
trusted: a malicious, malfunctioning or counterfeit controller (or an
interposer on the bus) can put arbitrary values in the report header. Two
such device-supplied fields are used as sizes without being bounded against
the fixed 4000-byte receive buffer, giving the device a heap out-of-bounds
write and a heap out-of-bounds read. This series bounds both.
Patch 1 bounds the 16-bit packet length before the second SPI transfer
(spi_read() into the 4000-byte rx_buf) -- the OOB write.
Patch 2 bounds the device-reported finger count in apple_z2_parse_touches()
-- the OOB read that is then forwarded to userspace as input events.
The two are paired because, as Dmitry noted on v2 of patch 2, the finger
count alone is not enough: msg_len is itself derived from the device length,
so patch 1 is what makes the patch 2 bound meaningful. Patch 1 was posted
standalone first and carries Sasha Finkelstein's Reviewed-by; it is unchanged
here.
This v3 series supersedes the two separate postings:
- packet length (standalone): https://lore.kernel.org/all/20260613-b4-disp-b1926f1a-v1-1-3a277b7c0cfa@proton.me/
- finger count v1: https://lore.kernel.org/all/20260613-b4-disp-f0148c89-v1-1-868a48b2a187@proton.me/
- finger count v2: https://lore.kernel.org/all/20260613-b4-disp-4ebcbd68-v2-1-0161acfbd688@proton.me/
Changes since the v2 finger-count patch (Dmitry Torokhov review,
https://lore.kernel.org/all/ai8U0QiwpBH8qNS3@google.com/):
- Patch 2: instead of clamping the finger count to what the packet holds
(v2 used min_t and reported the fingers that fit), drop the whole packet
when the device claims more fingers than it can hold, with a
dev_warn_ratelimited(), per Dmitry's "I'd drop such packet" suggestion.
A legitimate zero-finger ("all lifted") report (nfingers == 0) is still
passed through to input_mt_sync_frame()/input_sync(), so lifting all
fingers is not lost. (Dropped Joshua Peisach's v2 Reviewed-by, as the
fix shape changed materially from clamp to drop.)
- Patch 2 bound uses the multiplication form
(msg_len < FINGERS_OFFSET + nfingers * sizeof(*fingers)) rather than a
(msg_len - FINGERS_OFFSET) subtraction, so there is no unsigned underflow
when msg_len < FINGERS_OFFSET (which would otherwise re-open the read).
- Patch 1 folded into the series unchanged (Reviewed-by Sasha Finkelstein).
Note on patch 1 (Sasha Finkelstein, on the standalone thread): rejecting an
over-long packet desyncs the SPI datastream and the device then needs a reset
before it operates again. That is the intended outcome for a controller that
is already misbehaving or hostile -- a recoverable desync is preferable to a
~61 KiB heap overflow -- so the reject is kept.
Verification (in-kernel KASAN, CONFIG_KASAN=y kasan.fault=panic, plus userspace
ASan models of the exact parse arithmetic on x86_64 and i386):
Patch 1 (packet length): reported length -> pkt_len 65540:
Arm A (no patch): KASAN slab-out-of-bounds / ASan heap-buffer-overflow WRITE,
both ABIs.
Arm B (patch): rejected, clean. Arm C (benign): clean.
Patch 2 (finger count, drop shape): nfingers 255 in a short packet (msg_len 19):
Arm A (no patch): BUG: KASAN: slab-out-of-bounds, Read of size 2, 1 byte to
the right of the allocated 4000-byte region (cache kmalloc-4k) -> panic;
ASan heap-buffer-overflow READ, both ABIs.
Arm B (patch): packet dropped, zero reads, clean, not synced.
Arm C (benign 3 fingers, msg_len 114): parsed in-bounds, clean, synced.
Arm D (zero-finger all-lifted, nfingers 0, msg_len 19): clean, synced.
Reproducers and full logs available on request.
---
Bryam Vargas (2):
Input: apple_z2 - bound the device-reported packet length
Input: apple_z2 - bound the device-reported finger count
drivers/input/touchscreen/apple_z2.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
---
base-commit: 8e65320d91cdc3b241d4b94855c88459b91abf66
change-id: 20260615-b4-disp-05943ee1-9dc5cce670fe
Best regards,
--
Bryam Vargas <hexlabsecurity@proton.me>
^ permalink raw reply
* [PATCH v3 1/2] Input: apple_z2 - bound the device-reported packet length
From: Bryam Vargas via B4 Relay @ 2026-06-15 18:20 UTC (permalink / raw)
To: Sasha Finkelstein, Dmitry Torokhov
Cc: linux-arm-kernel, linux-kernel, Neal Gompa, asahi, Sven Peter,
linux-input, Janne Grunau
In-Reply-To: <20260615-b4-disp-05943ee1-v3-0-bbfe1b651613@proton.me>
From: Bryam Vargas <hexlabsecurity@proton.me>
apple_z2_read_packet() takes a 16-bit length from the touch controller's
interrupt-data reply (rx_buf[1..2]) and, only rounded down to a multiple of
four, uses it as the size of the second SPI transfer into the fixed-size
rx_buf:
pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
rx_buf is a fixed 4000-byte buffer, but pkt_len is fully controlled by the
device and is never checked against it, so a malicious, malfunctioning or
counterfeit controller (or an interposer on the SPI bus) that reports a
large length makes spi_read() write up to 65540 device-supplied bytes into
the 4000-byte buffer -- a controller-driven heap out-of-bounds write of up
to about 61 KiB. The recently added reply-type check only validates
rx_buf[0], not the length.
Reject any packet whose length exceeds the receive buffer.
Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Sasha Finkelstein <k@chaosmail.tech>
---
drivers/input/touchscreen/apple_z2.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
index 271ababf0ad5..ff9ff97be185 100644
--- a/drivers/input/touchscreen/apple_z2.c
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -22,6 +22,7 @@
#define APPLE_Z2_TOUCH_MOVED 4
#define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB
#define APPLE_Z2_REPLY_INTERRUPT_DATA 0xE1
+#define APPLE_Z2_MAX_PACKET 4000
#define APPLE_Z2_HBPP_CMD_BLOB 0x3001
#define APPLE_Z2_FW_MAGIC 0x5746325A
#define LOAD_COMMAND_INIT_PAYLOAD 0
@@ -147,6 +148,8 @@ static int apple_z2_read_packet(struct apple_z2 *z2)
return 0;
pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
+ if (pkt_len > APPLE_Z2_MAX_PACKET)
+ return -EMSGSIZE;
error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
if (error)
@@ -363,7 +366,7 @@ static int apple_z2_probe(struct spi_device *spi)
if (!z2->tx_buf)
return -ENOMEM;
/* 4096 will end up being rounded up to 8192 due to devres header */
- z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL);
+ z2->rx_buf = devm_kzalloc(dev, APPLE_Z2_MAX_PACKET, GFP_KERNEL);
if (!z2->rx_buf)
return -ENOMEM;
--
2.43.0
^ permalink raw reply related
* [PATCH v3 2/2] Input: apple_z2 - bound the device-reported finger count
From: Bryam Vargas via B4 Relay @ 2026-06-15 18:20 UTC (permalink / raw)
To: Sasha Finkelstein, Dmitry Torokhov
Cc: linux-arm-kernel, linux-kernel, Neal Gompa, asahi, Sven Peter,
linux-input, Janne Grunau
In-Reply-To: <20260615-b4-disp-05943ee1-v3-0-bbfe1b651613@proton.me>
From: Bryam Vargas <hexlabsecurity@proton.me>
apple_z2_parse_touches() takes the finger count from the touch
controller's report and loops over that many fixed-size finger records
without checking the count against the length of the report:
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
for (i = 0; i < nfingers; i++)
/* read fingers[i] ... */
msg points into the fixed 4000-byte rx_buf and nfingers is a single
device-supplied byte, so it can be as large as 255. A malicious,
malfunctioning or counterfeit controller (or an interposer on the SPI
bus) can report a large finger count in a short packet, making the loop
read up to 255 * sizeof(struct apple_z2_finger) bytes starting 24 bytes
into msg -- past the end of the receive buffer. This is a
controller-driven heap out-of-bounds read, and the finger fields that
are read (position, pressure, touch and tool dimensions) are forwarded
to userspace as input events, leaking adjacent kernel memory.
Drop any packet that claims more fingers than it can hold, warning once
per rate-limit interval, rather than reporting a truncated set of
fingers from an inconsistent report. A short zero-finger ("all lifted")
report is still passed through so the lifted state reaches userspace.
The 4000-byte receive buffer holds at most 132 finger records, so this
only ever drops counts that could not have been parsed in bounds.
Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/all/20260613215358.329921F000E9@smtp.kernel.org/
Fixes: 471a92f8a21a ("Input: apple_z2 - add a driver for Apple Z2 touchscreens")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
---
drivers/input/touchscreen/apple_z2.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
index ff9ff97be185..4e2a6967436e 100644
--- a/drivers/input/touchscreen/apple_z2.c
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -93,6 +93,17 @@ static void apple_z2_parse_touches(struct apple_z2 *z2,
return;
nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
+ /*
+ * A malicious or malfunctioning controller can report more fingers
+ * than the packet actually carries; drop the packet rather than read
+ * finger records past the end of the receive buffer.
+ */
+ if (nfingers && msg_len < APPLE_Z2_FINGERS_OFFSET + nfingers * sizeof(*fingers)) {
+ dev_warn_ratelimited(&z2->spidev->dev,
+ "discarding packet: %d fingers exceed packet length\n",
+ nfingers);
+ return;
+ }
for (i = 0; i < nfingers; i++) {
slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger);
if (slot < 0) {
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v8 09/12] iommu/arm-smmu-v3: Implement pm_runtime & system sleep ops
From: Mostafa Saleh @ 2026-06-15 18:20 UTC (permalink / raw)
To: Pranjal Shrivastava
Cc: iommu, Will Deacon, Joerg Roedel, Robin Murphy, Jason Gunthorpe,
Nicolin Chen, Daniel Mentz, Ashish Mhetre, linux-arm-kernel
In-Reply-To: <20260601215909.3958732-10-praan@google.com>
On Mon, Jun 01, 2026 at 09:59:06PM +0000, Pranjal Shrivastava wrote:
> Implement pm_runtime and system sleep ops for arm-smmu-v3.
>
> The suspend callback configures the SMMU to abort new transactions,
> disables the main translation unit and then drains the command queue
> to ensure completion of any in-flight commands. A software gate
> (STOP_FLAG) and synchronization barriers are used to quiesce the command
> submission pipeline and ensure state consistency before power-off.
>
> To prevent software metadata flags from leaking into physical registers
> or polluting the tracking pointer, a newly introduced bitmask
> (CMDQ_PROD_IDX_MASK) is applied to all register writes and tracking
> updates.
>
> The resume callback restores the MSI configuration and performs a full
> device reset via `arm_smmu_device_reset` to bring the SMMU back to an
> operational state. The MSIs are cached during the msi_write and are
> restored during the resume operation by using the helper. The STOP_FLAG
> is cleared only after the CMDQ is enabled in hardware.
>
> Suggested-by: Daniel Mentz <danielmentz@google.com>
> Signed-off-by: Pranjal Shrivastava <praan@google.com>
> ---
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 172 +++++++++++++++++++-
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 18 ++
> 2 files changed, 188 insertions(+), 2 deletions(-)
>
> 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 d31e50b64b50..542de3a3173a 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -28,6 +28,7 @@
> #include <linux/platform_device.h>
> #include <linux/sort.h>
> #include <linux/string_choices.h>
> +#include <linux/pm_runtime.h>
> #include <kunit/visibility.h>
> #include <uapi/linux/iommufd.h>
>
> @@ -110,6 +111,40 @@ static const char * const event_class_str[] = {
> static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master);
> static bool arm_smmu_ats_supported(struct arm_smmu_master *master);
>
> +/* Runtime PM helpers */
> +__maybe_unused static int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
> +{
> + int ret;
> +
> + if (!pm_runtime_enabled(smmu->dev))
> + return 0;
> +
> + ret = pm_runtime_resume_and_get(smmu->dev);
> + if (ret < 0) {
> + dev_err(smmu->dev, "failed to resume device: %d\n", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +__maybe_unused static void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
> +{
> + int ret;
> +
> + if (!pm_runtime_enabled(smmu->dev))
> + return;
> +
> + ret = pm_runtime_put_autosuspend(smmu->dev);
> + if (ret < 0)
> + dev_err(smmu->dev, "failed to suspend device: %d\n", ret);
> +}
> +
> +static inline u32 arm_smmu_cmdq_owner_prod_idx(struct arm_smmu_cmdq *cmdq)
> +{
> + return atomic_read(&cmdq->owner_prod) & CMDQ_PROD_IDX_MASK;
> +}
> +
> static void parse_driver_options(struct arm_smmu_device *smmu)
> {
> int i = 0;
> @@ -789,7 +824,8 @@ int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
> /* b. Stop gathering work by clearing the owned flag */
> prod = atomic_fetch_andnot_relaxed(CMDQ_PROD_OWNED_FLAG,
> &cmdq->q.llq.atomic.prod);
> - prod &= ~CMDQ_PROD_OWNED_FLAG;
> + /* Strip all metadata flags */
> + prod &= CMDQ_PROD_IDX_MASK;
>
> /*
> * c. Wait for any gathered work to be written to the queue.
> @@ -4828,7 +4864,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
>
> /* Command queue */
> writeq_relaxed(smmu->cmdq.q.q_base, smmu->base + ARM_SMMU_CMDQ_BASE);
> - writel_relaxed(smmu->cmdq.q.llq.prod, smmu->base + ARM_SMMU_CMDQ_PROD);
> + writel_relaxed(smmu->cmdq.q.llq.prod & CMDQ_PROD_IDX_MASK,
> + smmu->base + ARM_SMMU_CMDQ_PROD);
> writel_relaxed(smmu->cmdq.q.llq.cons, smmu->base + ARM_SMMU_CMDQ_CONS);
>
> enables = CR0_CMDQEN;
> @@ -4839,6 +4876,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
> return ret;
> }
>
> + /* Clear any flags from the previous life */
> + atomic_andnot(CMDQ_PROD_STOP_FLAG, &smmu->cmdq.owner_prod);
> + atomic_andnot(CMDQ_PROD_STOP_FLAG, &smmu->cmdq.q.llq.atomic.prod);
Should not that be done from the suspend call?
> +
> /* Invalidate any cached configuration */
> arm_smmu_cmdq_issue_cmd_with_sync(smmu, arm_smmu_make_cmd_cfgi_all());
>
> @@ -4898,6 +4939,21 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
> if (is_kdump_kernel())
> enables &= ~(CR0_EVTQEN | CR0_PRIQEN);
>
> + /*
> + * While the SMMU was suspended, concurrent CPU threads may have
> + * updated in-memory structures (such as STEs, CDs, and PTEs).
> + * Any invalidations corresponding to those updates were safely
> + * elided because the command queue was stopped (STOP_FLAG == 1).
> + *
> + * Since the reset invalidate-all commands above have fully cleared
> + * the HW TLBs and config caches, the SMMU will fetch these descriptors
> + * directly from RAM as soon as translation is enabled.
> + *
> + * Add a memory barrier to collect all prior RAM writes to ensure the
> + * SMMU sees a consistent view of memory before translation is enabled.
> + */
> + smp_mb();
Should not that be dma_wmb() as this is syncing with the HW?
> +
> /* Enable the SMMU interface */
> enables |= CR0_SMMUEN;
> ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
> @@ -5580,6 +5636,117 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev)
> arm_smmu_device_disable(smmu);
> }
>
> +static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
> +{
> + struct arm_smmu_device *smmu = dev_get_drvdata(dev);
> + struct arm_smmu_cmdq *cmdq = &smmu->cmdq;
> + int timeout = ARM_SMMU_SUSPEND_TIMEOUT_US;
> + u32 enables, target;
> + int ret;
> +
> + /* Abort all transactions before disable to avoid spurious bypass */
> + arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
> +
> + /* Disable the SMMU via CR0.EN and all queues except CMDQ */
> + enables = CR0_CMDQEN;
> + ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, ARM_SMMU_CR0ACK);
> + if (ret) {
> + dev_err(smmu->dev, "failed to disable SMMU\n");
> + return ret;
> + }
> +
> + /*
> + * At this point the SMMU is completely disabled and won't access
> + * any translation/config structures, even speculative accesses
> + * aren't performed as per the IHI0070 spec (section 6.3.9.6).
> + */
> +
> + /* Mark the CMDQ to stop and get the target index before the stop */
> + target = atomic_fetch_or_relaxed(CMDQ_PROD_STOP_FLAG, &cmdq->q.llq.atomic.prod);
As Daniel mentioned, I think this shouldn't be relaxed.
> + target &= CMDQ_PROD_IDX_MASK;
> +
> +
> + /* Wait for the last committed owner to reach the hardware */
> + while ((arm_smmu_cmdq_owner_prod_idx(cmdq) != target) && --timeout)
> + udelay(1);
I think --timeout has an off-by-one.
Thanks,
Mostafa
^ permalink raw reply
* [PATCH] KVM: arm64: Handle race between interrupt affinity change and LPI disabling
From: Marc Zyngier @ 2026-06-15 18:16 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel, kvm
Cc: Steffen Eiden, Joey Gouly, Suzuki K Poulose, Oliver Upton,
Zenghui Yu, Hyunwoo Kim
Hyunwoo Kim reports some really bad races should the following
situation occur:
- LPI-I is pending in vcpu-B's AP list
- vcpu-A writes to vcpu-B's RD to disable its LPIs
- vcpu-C moves I from B to C
If the last two race nicely enough, vgic_prune_ap_list() can drop
the irq and AP list locks, reacquire them, and in the interval
the irq has been freed. UAF follows.
The fix is two-fold:
- Before dropping the irq and ap_list locks, take a reference on
the irq
- Do not try to handle migration of the pending bit: there is no
expectation that this state is retained, as per the architecture
With that, we're sure that the interrupt is still around, and we
safely remove it from the AP list as it has no target at this
stage (unless another interrupt fires, but that's another story).
Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
Tested-by: Hyunwoo Kim <imv4bel@gmail.com>
Link: https://lore.kernel.org/r/ailsCnyoS82r_QRz@v4bel
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/vgic/vgic.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 5a4768d8cd4f3..70a161383e5a6 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -203,6 +203,7 @@ void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)
list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
if (irq_is_lpi(vcpu->kvm, irq->intid)) {
raw_spin_lock(&irq->irq_lock);
+ irq->pending_latch = false;
list_del(&irq->ap_list);
irq->vcpu = NULL;
raw_spin_unlock(&irq->irq_lock);
@@ -792,7 +793,11 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
continue;
}
- /* This interrupt looks like it has to be migrated. */
+ /*
+ * This interrupt looks like it has to be migrated,
+ * make sure it is kept alive while locks are dropped.
+ */
+ vgic_get_irq_ref(irq);
raw_spin_unlock(&irq->irq_lock);
raw_spin_unlock(&vgic_cpu->ap_list_lock);
@@ -836,6 +841,8 @@ static void vgic_prune_ap_list(struct kvm_vcpu *vcpu)
raw_spin_unlock(&vcpuB->arch.vgic_cpu.ap_list_lock);
raw_spin_unlock(&vcpuA->arch.vgic_cpu.ap_list_lock);
+ deleted_lpis |= vgic_put_irq_norelease(vcpu->kvm, irq);
+
if (target_vcpu_needs_kick) {
kvm_make_request(KVM_REQ_IRQ_PENDING, target_vcpu);
kvm_vcpu_kick(target_vcpu);
--
2.47.3
^ permalink raw reply related
* [PATCH v1] phy: Add USB3 PHY support to Google Tensor SoC USB PHY driver
From: RD Babiera @ 2026-06-15 18:05 UTC (permalink / raw)
To: vkoul, peter.griffin, andre.draszik, tudor.ambarus, p.zabel,
neil.armstrong
Cc: badhri, linux-arm-kernel, linux-samsung-soc, linux-phy,
linux-kernel, RD Babiera
Add USB3 PHY support for the Google Tensor G5 USB PHY driver.
This patch adds functionality for the usb3_core and usb3_tca registers,
usb3 clock, and usb3 reset as defined in
google,lga-usb-phy.yaml.
Refactor the probe sequence to initialize the USB2 and USB3 PHYs, and then
initialize clocks and resets for both PHYs afterwards.
Refactor set_vbus_valid to reduce duplicated code.
Implement USB3 phy_ops for phy_init, phy_exit, and phy_power_on.
Signed-off-by: RD Babiera <rdbabiera@google.com>
---
drivers/phy/phy-google-usb.c | 350 +++++++++++++++++++++++++++++++----
1 file changed, 317 insertions(+), 33 deletions(-)
diff --git a/drivers/phy/phy-google-usb.c b/drivers/phy/phy-google-usb.c
index ab20bc20f19e..a23a9008b521 100644
--- a/drivers/phy/phy-google-usb.c
+++ b/drivers/phy/phy-google-usb.c
@@ -20,6 +20,7 @@
#include <linux/reset.h>
#include <linux/usb/typec_mux.h>
+/* USB_CFG_CSR */
#define USBCS_USB2PHY_CFG19_OFFSET 0x0
#define USBCS_USB2PHY_CFG19_PHY_CFG_PLL_FB_DIV GENMASK(19, 8)
@@ -28,11 +29,41 @@
#define USBCS_USB2PHY_CFG21_REF_FREQ_SEL GENMASK(15, 13)
#define USBCS_USB2PHY_CFG21_PHY_TX_DIG_BYPASS_SEL BIT(19)
+/* USBDP_TOP */
#define USBCS_PHY_CFG1_OFFSET 0x28
+#define USBCS_PHY_CFG1_PHY0_MPLLA_SSC_EN BIT(1)
+#define USBCS_PHY_CFG1_PHY0_SRAM_BYPASS_MODE GENMASK(11, 10)
+#define SRAM_BYPASS_MODE_BYPASS_FIRMWARE BIT(0)
+#define SRAM_BYPASS_MODE_BYPASS_CONTEXT BIT(1)
#define USBCS_PHY_CFG1_SYS_VBUSVALID BIT(17)
+#define USBDP_TOP_CFG_REG_OFFSET 0x44
+#define USBDP_TOP_CFG_REG_PMGT_REF_CLK_REQ_N BIT(0)
+
+#define PHY_POWER_CONFIG_REG1_OFFSET 0x48
+#define PHY_POWER_CONFIG_REG1_PG_MODE_EN BIT(1)
+#define PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG GENMASK(31, 14)
+#define UPCS_PIPE_CONFIG_ISO_CPM BIT(5)
+#define UPCS_PIPE_CONFIG_PG_MODE_STATIC BIT(6)
+#define UPCS_PIPE_CONFIG_LANE_RESET_NO_PG_EXIT BIT(9)
+
+/* USB3_TCA */
+#define TCA_INTR_STS_OFFSET 0x8
+#define TCA_INTR_STS_XA_ACT_EVT BIT(0)
+#define TCA_TCPC_OFFSET 0x14
+#define TCA_TCPC_MUX_CONTROL GENMASK(2, 0)
+#define TCA_TCPC_MUX_CONTROL_USB_ONLY 0x1
+#define TCA_TCPC_CONNECTOR_ORIENTATION BIT(3)
+#define TCA_TCPC_VALID BIT(4)
+#define TCA_PSTATE_0_OFFSET 0x50
+#define TCA_PSTATE_0_UPCS_LANE0_PHYSTATUS BIT(8)
+
+#define GPHY_TCA_DELAY_US 10
+#define GPHY_TCA_TIMEOUT_US 2500000
+
enum google_usb_phy_id {
GOOGLE_USB2_PHY,
+ GOOGLE_USB3_PHY,
GOOGLE_USB_PHY_NUM,
};
@@ -46,11 +77,50 @@ struct google_usb_phy_instance {
struct reset_control_bulk_data *rsts;
};
+struct google_usb_phy_config {
+ const char * const *clk_names;
+ unsigned int num_clks;
+ const char * const *rst_names;
+ unsigned int num_rsts;
+};
+
+static const char * const u2phy_clk_names[] = {
+ "usb2",
+ "usb2_apb",
+};
+static const char * const u3phy_clk_names[] = {
+ "usb3"
+};
+static const char * const u2phy_rst_names[] = {
+ "usb2",
+ "usb2_apb",
+};
+static const char * const u3phy_rst_names[] = {
+ "usb3"
+};
+
+static const struct google_usb_phy_config phy_configs[GOOGLE_USB_PHY_NUM] = {
+ [GOOGLE_USB2_PHY] = {
+ .clk_names = u2phy_clk_names,
+ .num_clks = ARRAY_SIZE(u2phy_clk_names),
+ .rst_names = u2phy_rst_names,
+ .num_rsts = ARRAY_SIZE(u2phy_rst_names),
+ },
+ [GOOGLE_USB3_PHY] = {
+ .clk_names = u3phy_clk_names,
+ .num_clks = ARRAY_SIZE(u3phy_clk_names),
+ .rst_names = u3phy_rst_names,
+ .num_rsts = ARRAY_SIZE(u3phy_rst_names),
+ },
+};
+
struct google_usb_phy {
struct device *dev;
struct regmap *usb_cfg_regmap;
unsigned int usb2_cfg_offset;
void __iomem *usbdp_top_base;
+ void __iomem *usb3_core_base;
+ void __iomem *usb3_tca_base;
struct google_usb_phy_instance *insts;
/*
* Protect phy registers from concurrent access, specifically via
@@ -65,15 +135,79 @@ static void set_vbus_valid(struct google_usb_phy *gphy)
{
u32 reg;
- if (gphy->orientation == TYPEC_ORIENTATION_NONE) {
- reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ if (gphy->orientation == TYPEC_ORIENTATION_NONE)
reg &= ~USBCS_PHY_CFG1_SYS_VBUSVALID;
- writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
- } else {
- reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ else
reg |= USBCS_PHY_CFG1_SYS_VBUSVALID;
- writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
- }
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+}
+
+static void set_sram_bypass(struct google_usb_phy *gphy, u32 bypass)
+{
+ u32 reg;
+
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg &= ~USBCS_PHY_CFG1_PHY0_SRAM_BYPASS_MODE;
+ reg |= FIELD_PREP(USBCS_PHY_CFG1_PHY0_SRAM_BYPASS_MODE, bypass);
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+}
+
+static void set_pmgt_ref_clk_req_n(struct google_usb_phy *gphy, bool resume)
+{
+ u32 reg;
+
+ reg = readl(gphy->usbdp_top_base + USBDP_TOP_CFG_REG_OFFSET);
+ if (resume)
+ reg |= USBDP_TOP_CFG_REG_PMGT_REF_CLK_REQ_N;
+ else
+ reg &= ~USBDP_TOP_CFG_REG_PMGT_REF_CLK_REQ_N;
+ writel(reg, gphy->usbdp_top_base + USBDP_TOP_CFG_REG_OFFSET);
+}
+
+static int wait_tca_xa_ack(struct google_usb_phy *gphy)
+{
+ int ret;
+ u32 reg;
+
+ ret = readl_poll_timeout(gphy->usb3_tca_base + TCA_INTR_STS_OFFSET,
+ reg, !!(reg & TCA_INTR_STS_XA_ACT_EVT),
+ GPHY_TCA_DELAY_US, GPHY_TCA_TIMEOUT_US);
+ if (ret)
+ dev_err(gphy->dev, "tca xa_ack timeout, ret=%d", ret);
+
+ return ret;
+}
+
+static int program_tca_locked(struct google_usb_phy *gphy)
+ __must_hold(&gphy->phy_mutex)
+{
+ int ret;
+ u32 reg;
+
+ reg = readl(gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+ writel(reg, gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+
+ reg = readl(gphy->usb3_tca_base + TCA_TCPC_OFFSET);
+ reg &= ~TCA_TCPC_MUX_CONTROL;
+ reg |= FIELD_PREP(TCA_TCPC_MUX_CONTROL, TCA_TCPC_MUX_CONTROL_USB_ONLY);
+ if (gphy->orientation == TYPEC_ORIENTATION_REVERSE)
+ reg |= TCA_TCPC_CONNECTOR_ORIENTATION;
+ else
+ reg &= ~TCA_TCPC_CONNECTOR_ORIENTATION;
+ reg |= TCA_TCPC_VALID;
+ writel(reg, gphy->usb3_tca_base + TCA_TCPC_OFFSET);
+
+ ret = wait_tca_xa_ack(gphy);
+ dev_dbg(gphy->dev, "TCA switch %s, mux %lu, orientation %s",
+ ret ? "failed" : "success",
+ FIELD_GET(TCA_TCPC_MUX_CONTROL, reg),
+ FIELD_GET(TCA_TCPC_CONNECTOR_ORIENTATION, reg) ? "reverse" : "normal");
+
+ reg = readl(gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+ writel(reg, gphy->usb3_tca_base + TCA_INTR_STS_OFFSET);
+
+ return ret;
}
static int google_usb_set_orientation(struct typec_switch_dev *sw,
@@ -161,6 +295,103 @@ static const struct phy_ops google_usb2_phy_ops = {
.exit = google_usb2_phy_exit,
};
+static int google_usb3_phy_init(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+ int ret = 0;
+ u32 reg;
+
+ dev_dbg(gphy->dev, "initializing usb3 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ reg = readl(gphy->usbdp_top_base + PHY_POWER_CONFIG_REG1_OFFSET);
+ reg |= PHY_POWER_CONFIG_REG1_PG_MODE_EN;
+ reg &= ~PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG;
+ reg |= FIELD_PREP(PHY_POWER_CONFIG_REG1_UPCS_PIPE_CONFIG,
+ (UPCS_PIPE_CONFIG_ISO_CPM |
+ UPCS_PIPE_CONFIG_PG_MODE_STATIC |
+ UPCS_PIPE_CONFIG_LANE_RESET_NO_PG_EXIT));
+ writel(reg, gphy->usbdp_top_base + PHY_POWER_CONFIG_REG1_OFFSET);
+
+ set_vbus_valid(gphy);
+
+ reg = readl(gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+ reg |= USBCS_PHY_CFG1_PHY0_MPLLA_SSC_EN;
+ writel(reg, gphy->usbdp_top_base + USBCS_PHY_CFG1_OFFSET);
+
+ set_sram_bypass(gphy, SRAM_BYPASS_MODE_BYPASS_FIRMWARE |
+ SRAM_BYPASS_MODE_BYPASS_CONTEXT);
+ set_pmgt_ref_clk_req_n(gphy, true);
+
+ ret = clk_bulk_prepare_enable(inst->num_clks, inst->clks);
+ if (ret)
+ return ret;
+
+ ret = reset_control_bulk_deassert(inst->num_rsts, inst->rsts);
+ if (ret)
+ goto disable_clocks;
+
+ ret = readl_poll_timeout(gphy->usb3_tca_base + TCA_PSTATE_0_OFFSET,
+ reg, !(reg & TCA_PSTATE_0_UPCS_LANE0_PHYSTATUS),
+ GPHY_TCA_DELAY_US, GPHY_TCA_TIMEOUT_US);
+ if (ret) {
+ dev_err(gphy->dev, "wait for lane0 phystatus timed out");
+ goto assert_resets;
+ }
+
+ return 0;
+
+assert_resets:
+ reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+disable_clocks:
+ clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+ return ret;
+}
+
+static int google_usb3_phy_exit(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+
+ dev_dbg(gphy->dev, "exiting usb3 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+
+ set_pmgt_ref_clk_req_n(gphy, false);
+ reset_control_bulk_assert(inst->num_rsts, inst->rsts);
+ clk_bulk_disable_unprepare(inst->num_clks, inst->clks);
+
+ return 0;
+}
+
+static int google_usb3_phy_power_on(struct phy *_phy)
+{
+ struct google_usb_phy_instance *inst = phy_get_drvdata(_phy);
+ struct google_usb_phy *gphy = inst->parent;
+ int ret;
+
+ dev_dbg(gphy->dev, "power on usb3 phy\n");
+
+ guard(mutex)(&gphy->phy_mutex);
+ ret = wait_tca_xa_ack(gphy);
+ if (ret) {
+ dev_err(gphy->dev, "PoR->NC transition timeout");
+ return ret;
+ }
+
+ ret = program_tca_locked(gphy);
+
+ return ret;
+}
+
+static const struct phy_ops google_usb3_phy_ops = {
+ .init = google_usb3_phy_init,
+ .exit = google_usb3_phy_exit,
+ .power_on = google_usb3_phy_power_on,
+};
+
static struct phy *google_usb_phy_xlate(struct device *dev,
const struct of_phandle_args *args)
{
@@ -173,14 +404,61 @@ static struct phy *google_usb_phy_xlate(struct device *dev,
return gphy->insts[args->args[0]].phy;
}
+static int google_usb_phy_parse_clocks(struct google_usb_phy *gphy)
+{
+ struct device *dev = gphy->dev;
+ int id, i, ret;
+
+ for (id = 0; id < GOOGLE_USB_PHY_NUM; id++) {
+ const struct google_usb_phy_config *cfg = &phy_configs[id];
+ struct google_usb_phy_instance *inst = &gphy->insts[id];
+
+ inst->num_clks = cfg->num_clks;
+ inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
+ if (!inst->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < inst->num_clks; i++)
+ inst->clks[i].id = cfg->clk_names[i];
+
+ ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get phy%d clks\n", id);
+ }
+
+ return 0;
+}
+
+static int google_usb_phy_parse_resets(struct google_usb_phy *gphy)
+{
+ struct device *dev = gphy->dev;
+ int id, i, ret;
+
+ for (id = 0; id < GOOGLE_USB_PHY_NUM; id++) {
+ const struct google_usb_phy_config *cfg = &phy_configs[id];
+ struct google_usb_phy_instance *inst = &gphy->insts[id];
+
+ inst->num_rsts = cfg->num_rsts;
+ inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
+ if (!inst->rsts)
+ return -ENOMEM;
+
+ for (i = 0; i < inst->num_rsts; i++)
+ inst->rsts[i].id = cfg->rst_names[i];
+ ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get phy%d resets\n", id);
+ }
+
+ return 0;
+}
+
static int google_usb_phy_probe(struct platform_device *pdev)
{
struct typec_switch_desc sw_desc = { };
- struct google_usb_phy_instance *inst;
struct phy_provider *phy_provider;
struct device *dev = &pdev->dev;
struct google_usb_phy *gphy;
- struct phy *phy;
u32 args[1];
int ret;
@@ -212,39 +490,45 @@ static int google_usb_phy_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(gphy->usbdp_top_base),
"invalid usbdp top\n");
+ gphy->usb3_core_base = devm_platform_ioremap_resource_byname(pdev,
+ "usb3_core");
+ if (IS_ERR(gphy->usb3_core_base))
+ return dev_err_probe(dev, PTR_ERR(gphy->usb3_core_base),
+ "invalid usb3 core\n");
+
+ gphy->usb3_tca_base = devm_platform_ioremap_resource_byname(pdev,
+ "usb3_tca");
+ if (IS_ERR(gphy->usb3_tca_base))
+ return dev_err_probe(dev, PTR_ERR(gphy->usb3_tca_base),
+ "invalid usb3 tca\n");
+
gphy->insts = devm_kcalloc(dev, GOOGLE_USB_PHY_NUM, sizeof(*gphy->insts), GFP_KERNEL);
if (!gphy->insts)
return -ENOMEM;
- inst = &gphy->insts[GOOGLE_USB2_PHY];
- inst->parent = gphy;
- inst->index = GOOGLE_USB2_PHY;
- phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
- if (IS_ERR(phy))
- return dev_err_probe(dev, PTR_ERR(phy),
+ gphy->insts[GOOGLE_USB2_PHY].phy = devm_phy_create(dev, NULL, &google_usb2_phy_ops);
+ gphy->insts[GOOGLE_USB2_PHY].index = GOOGLE_USB2_PHY;
+ gphy->insts[GOOGLE_USB2_PHY].parent = gphy;
+ if (IS_ERR(gphy->insts[GOOGLE_USB2_PHY].phy))
+ return dev_err_probe(dev, PTR_ERR(gphy->insts[GOOGLE_USB2_PHY].phy),
"failed to create usb2 phy instance\n");
- inst->phy = phy;
- phy_set_drvdata(phy, inst);
+ phy_set_drvdata(gphy->insts[GOOGLE_USB2_PHY].phy, &gphy->insts[GOOGLE_USB2_PHY]);
- inst->num_clks = 2;
- inst->clks = devm_kcalloc(dev, inst->num_clks, sizeof(*inst->clks), GFP_KERNEL);
- if (!inst->clks)
- return -ENOMEM;
- inst->clks[0].id = "usb2";
- inst->clks[1].id = "usb2_apb";
- ret = devm_clk_bulk_get(dev, inst->num_clks, inst->clks);
+ gphy->insts[GOOGLE_USB3_PHY].phy = devm_phy_create(dev, NULL, &google_usb3_phy_ops);
+ gphy->insts[GOOGLE_USB3_PHY].index = GOOGLE_USB3_PHY;
+ gphy->insts[GOOGLE_USB3_PHY].parent = gphy;
+ if (IS_ERR(gphy->insts[GOOGLE_USB3_PHY].phy))
+ return dev_err_probe(dev, PTR_ERR(gphy->insts[GOOGLE_USB3_PHY].phy),
+ "failed to create usb3 phy instance\n");
+ phy_set_drvdata(gphy->insts[GOOGLE_USB3_PHY].phy, &gphy->insts[GOOGLE_USB3_PHY]);
+
+ ret = google_usb_phy_parse_clocks(gphy);
if (ret)
- return dev_err_probe(dev, ret, "failed to get u2 phy clks\n");
+ return ret;
- inst->num_rsts = 2;
- inst->rsts = devm_kcalloc(dev, inst->num_rsts, sizeof(*inst->rsts), GFP_KERNEL);
- if (!inst->rsts)
- return -ENOMEM;
- inst->rsts[0].id = "usb2";
- inst->rsts[1].id = "usb2_apb";
- ret = devm_reset_control_bulk_get_exclusive(dev, inst->num_rsts, inst->rsts);
+ ret = google_usb_phy_parse_resets(gphy);
if (ret)
- return dev_err_probe(dev, ret, "failed to get u2 phy resets\n");
+ return ret;
phy_provider = devm_of_phy_provider_register(dev, google_usb_phy_xlate);
if (IS_ERR(phy_provider))
base-commit: 2ace2e949979b82f82f12dd76d7c5a6145246ca3
--
2.54.0.1189.g8c84645362-goog
^ permalink raw reply related
* Re: [PATCH 7/7] clk: sunxi-ng: Add Allwinner A733 RTC CCU support
From: Jerome Brunet @ 2026-06-15 17:56 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Junhui Liu, Michael Turquette, Stephen Boyd, Jernej Skrabec,
Samuel Holland, Alexandre Belloni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Maxime Ripard, linux-clk,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-rtc,
devicetree, André Przywara
In-Reply-To: <CAGb2v64euL+QNXiJdTn0JygYLXg0WoguPSprKT4sKGZGVZbwug@mail.gmail.com>
On sam. 28 mars 2026 at 22:41, Chen-Yu Tsai <wens@kernel.org> wrote:
> On Wed, Jan 21, 2026 at 7:04 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
>>
>> Add support for the internal CCU found in the RTC module of the Allwinner
>> A733 SoC. While the basic 16MHz (IOSC) and 32kHz logic remains compatible
>> with older SoCs like the sun6i, the A733 introduces several new features.
>>
>> The A733 RTC CCU supports choosing one of three external crystal
>> frequencies: 19.2MHz, 24MHz, and 26MHz. It features hardware detection
>> logic to automatically identify the frequency used on the board and
>> exports this DCXO signal as the "hosc" clock.
>>
>> Furthermore, the driver implements logic to derive a 32kHz reference
>> from the HOSC. This is achieved through a muxed clock path using fixed
>> pre-dividers to normalize the different crystal frequencies to ~32kHz.
>
> Have you tested whether the actually normalizes the frequency, i.e.
> selects a different divider based on the DCXO frequency? Otherwise
> we're just lying about the frequency.
>
>> This path reuses the same hardware mux registers as the HOSC clock.
>>
>> Additionally, this CCU provides several gate clocks for specific
>> peripherals, including SerDes, HDMI, and UFS. The driver is implemented
>> as an auxiliary driver to be bound to the sun6i-rtc driver.
>>
>> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
>> ---
[...]
>> +};
>> +
>> +static const struct clk_parent_data hosc_parents[] = {
>> + { .fw_name = "osc24M" },
>> + { .fw_name = "osc19M" },
>> + { .fw_name = "osc26M" },
>> + { .fw_name = "osc24M" },
>> +};
>
> As mentioned in my reply to the binding, this is wrong. There is only
> one input.
>
> The most you can do is check the rate of the parent clock against the
> detected one, and _scream_ that the DT is wrong. And maybe override
> the reported frequency.
>
> If you want to do the latter, you could add a new fixed rate gated
> clock type to our library. You would fill in the rate before the
> clocks get registered. I probably wouldn't go that far. We want people
> to have correct hardware descriptions.
>
> Funnily enough Allwinner's BSP actually implements a fixed rate gate
> for the next 24M-to-32k divider clock.
What about implementing the register bellow as a read-only (and
non-cached) divider using the factors provided by Junhui ? That would be
an accurate description of the HW I think.
The oscillator gets set in DT and if the output reported past the
divider is not 32728Hz, you know you've got a problem (bad DT or HW gone
bad)
With a fixed-rate gate, you may actually end up lying about what
actually happen, if the HW does not behave as expected.
Do you prefer a fixed-rate gate still or should I try the RO divider
approach ?
>
>> +
>> +struct ccu_mux hosc_clk = {
>> + .enable = DCXO_CTRL_DCXO_EN,
>> + .mux = _SUNXI_CCU_MUX(14, 2),
>> + .common = {
>> + .reg = DCXO_CTRL_REG,
>> + .hw.init = CLK_HW_INIT_PARENTS_DATA("hosc",
>> + hosc_parents,
>> + &ccu_mux_ro_ops,
>> + 0),
>> + },
>> +};
>
> So this is wrong.
>
>> +
>> +static const struct ccu_mux_fixed_prediv hosc_32k_predivs[] = {
>> + { .index = 0, .div = 732 },
>
> Why is it 732 instead of 750?
>
>> + { .index = 1, .div = 586 },
>> + { .index = 2, .div = 793 },
>> + { .index = 3, .div = 732 },
>> +};
>> +
>> +static struct ccu_mux hosc_32k_mux_clk = {
>> + .enable = DCXO_CTRL_DCXO_EN,
>
^ permalink raw reply
* [GIT PULL] CRC updates for 7.2
From: Eric Biggers @ 2026-06-15 17:48 UTC (permalink / raw)
To: Linus Torvalds
Cc: linux-crypto, linux-arm-kernel, linux-kernel, Ard Biesheuvel,
Christoph Hellwig
The following changes since commit e7ae89a0c97ce2b68b0983cd01eda67cf373517d:
Linux 7.1-rc5 (2026-05-24 13:48:06 -0700)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git tags/crc-for-linus
for you to fetch changes up to cbe44c389ae80362e72696ac08f7c55a83f2a050:
crypto: aegis128 - Use neon-intrinsics.h on ARM too (2026-05-28 13:14:25 -0700)
----------------------------------------------------------------
Accelerate CRC64-NVME for 32-bit ARM by refactoring the arm64 NEON
intrinsics implementation to be shared by 32-bit and 64-bit.
Also apply a similar cleanup to the 32-bit ARM NEON implementation of
xor_gen(), where it now reuses code from the 64-bit implementation.
----------------------------------------------------------------
Ard Biesheuvel (6):
ARM: Add a neon-intrinsics.h header like on arm64
xor/arm: Replace vectorized implementation with arm64's intrinsics
xor/arm64: Use shared NEON intrinsics implementation from 32-bit ARM
lib/crc: Turn NEON intrinsics crc64 implementation into common code
lib/crc: arm: Enable arm64's NEON intrinsics implementation of crc64
crypto: aegis128 - Use neon-intrinsics.h on ARM too
Documentation/arch/arm/kernel_mode_neon.rst | 4 +-
arch/arm/include/asm/neon-intrinsics.h | 60 +++++++++
crypto/Makefile | 10 +-
crypto/aegis128-neon-inner.c | 4 +-
lib/crc/Kconfig | 1 +
lib/crc/Makefile | 9 +-
lib/crc/arm/crc64-neon.h | 34 +++++
lib/crc/arm/crc64.h | 36 +++++
lib/crc/arm64/crc64-neon.h | 21 +++
lib/crc/arm64/crc64.h | 4 +-
lib/crc/{arm64/crc64-neon-inner.c => crc64-neon.c} | 26 +---
lib/raid/xor/Makefile | 13 +-
lib/raid/xor/arm/xor-neon.c | 26 ----
lib/raid/xor/arm/xor-neon.h | 7 +
lib/raid/xor/arm/xor_arch.h | 7 +-
lib/raid/xor/arm64/xor-eor3.c | 146 +++++++++++++++++++++
lib/raid/xor/xor-8regs.c | 2 -
lib/raid/xor/{arm64 => }/xor-neon.c | 143 +-------------------
18 files changed, 338 insertions(+), 215 deletions(-)
create mode 100644 arch/arm/include/asm/neon-intrinsics.h
create mode 100644 lib/crc/arm/crc64-neon.h
create mode 100644 lib/crc/arm/crc64.h
create mode 100644 lib/crc/arm64/crc64-neon.h
rename lib/crc/{arm64/crc64-neon-inner.c => crc64-neon.c} (62%)
delete mode 100644 lib/raid/xor/arm/xor-neon.c
create mode 100644 lib/raid/xor/arm/xor-neon.h
create mode 100644 lib/raid/xor/arm64/xor-eor3.c
rename lib/raid/xor/{arm64 => }/xor-neon.c (56%)
^ permalink raw reply
* Re: [PATCH 1/7] dt-bindings: rtc: sun6i: Add Allwinner A733 support
From: Jerome Brunet @ 2026-06-15 17:46 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Junhui Liu, Michael Turquette, Stephen Boyd, Jernej Skrabec,
Samuel Holland, Alexandre Belloni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Maxime Ripard, linux-clk,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-rtc,
devicetree
In-Reply-To: <CAGb2v67844OPwE6VJ0PAs5LsmCa2h0FvXOBUomZ50dM5tZ0Zow@mail.gmail.com>
On sam. 28 mars 2026 at 20:37, Chen-Yu Tsai <wens@kernel.org> wrote:
> On Wed, Jan 21, 2026 at 7:03 PM Junhui Liu <junhui.liu@pigmoral.tech> wrote:
>>
>> The RTC module in the Allwinner A733 SoC is functionally compatible with
>> the sun6i RTC, but its internal Clock Control Unit (CCU) has significant
>> changes.
>>
>> The A733 supports selecting the oscillator between three frequencies:
>> 19.2MHz, 24MHz, and 26MHz. The RTC CCU relies on hardware to detect
>> which frequency is actually used on the board. By defining all three
>> frequencies as fixed-clocks in the device tree, the driver can identify
>> the hardware-detected frequency and expose it to the rest of the system.
>
> No. The board device tree shall have the exact and correct frequency
> defined in the external crystal device node. The operating system can
> use the hardware-detected frequency to "fix" the in-system representation
> if it is off.
>
>> Additionally, the A733 RTC CCU provides several new DCXO gate clocks for
>> specific modules, including SerDes, HDMI, and UFS.
>>
>> Signed-off-by: Junhui Liu <junhui.liu@pigmoral.tech>
>> ---
>> .../bindings/rtc/allwinner,sun6i-a31-rtc.yaml | 38 ++++++++++++++++++++--
>> include/dt-bindings/clock/sun60i-a733-rtc.h | 16 +++++++++
>> 2 files changed, 52 insertions(+), 2 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
>> index 9df5cdb6f63f..b18431955783 100644
>> --- a/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
>> +++ b/Documentation/devicetree/bindings/rtc/allwinner,sun6i-a31-rtc.yaml
>> @@ -26,6 +26,7 @@ properties:
>> - allwinner,sun50i-h6-rtc
>> - allwinner,sun50i-h616-rtc
>> - allwinner,sun50i-r329-rtc
>> + - allwinner,sun60i-a733-rtc
>> - items:
>> - const: allwinner,sun50i-a64-rtc
>> - const: allwinner,sun8i-h3-rtc
>> @@ -46,11 +47,11 @@ properties:
>>
>> clocks:
>> minItems: 1
>> - maxItems: 4
>> + maxItems: 6
>>
>> clock-names:
>> minItems: 1
>> - maxItems: 4
>> + maxItems: 6
>>
>> clock-output-names:
>> minItems: 1
>> @@ -156,6 +157,38 @@ allOf:
>> - clocks
>> - clock-names
>>
>> + - if:
>> + properties:
>> + compatible:
>> + contains:
>> + const: allwinner,sun60i-a733-rtc
>> +
>> + then:
>> + properties:
>> + clocks:
>> + minItems: 5
>> + items:
>> + - description: Bus clock for register access
>
>> + - description: 19.2 MHz oscillator
>> + - description: 24 MHz oscillator
>> + - description: 26 MHz oscillator
>
> No. There is only one input. As in there is only one set of pins for the
> DCXO. The inputs are the same as on R329 / A523. Just use that list.
>
>> + - description: AHB parent for internal SPI clock
>> + - description: External 32768 Hz oscillator
>> +
>> + clock-names:
>> + minItems: 5
>> + items:
>> + - const: bus
>> + - const: osc19M
>> + - const: osc24M
>> + - const: osc26M
>> + - const: ahb
>> + - const: ext-osc32k
>> +
>> + required:
>> + - clocks
>> + - clock-names
>> +
>> - if:
>> properties:
>> compatible:
>> @@ -164,6 +197,7 @@ allOf:
>> - allwinner,sun8i-r40-rtc
>> - allwinner,sun50i-h616-rtc
>> - allwinner,sun50i-r329-rtc
>> + - allwinner,sun60i-a733-rtc
>>
>> then:
>> properties:
>> diff --git a/include/dt-bindings/clock/sun60i-a733-rtc.h b/include/dt-bindings/clock/sun60i-a733-rtc.h
>> new file mode 100644
>> index 000000000000..8a2b5facad73
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/sun60i-a733-rtc.h
>> @@ -0,0 +1,16 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
>> +
>> +#ifndef _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
>> +#define _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_
>> +
>> +#define CLK_IOSC 0
>> +#define CLK_OSC32K 1
>> +#define CLK_HOSC 2
>
> The DCXO enable control has been present since at least the H6. We just
> never added it, as we would never disable it anyway.
>
> If you compare the RTC clock trees of the A733 and A523, the only addition
> besides the new gates seems to be the LOSC auto selection. But even that
> is just an illusion, as the A523 has the same registers for that.
>
> One could say the A733 RTC is almost backward compatible to the A523, if
> not for the two fastboot registers the A523 has at 0x120 and 0x124.
>
> So I ask that you try to integrate the differences into the existing
> driver and bindings. You can tweak and export internal clks if you
> need.
I'd like to help with that. I think it is doable but I have a question
regarding the binding of the existing driver, more precisely their usage
here:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c?h=v7.1#n370
Clock indexes are supposed to be stable in DT (AFAIK) but with the code
linked the external 32k is at:
* "ext-32k" - so index 3 - if "clock-names" is present
* index 0 if clock names is not present
... but index 0 is supposed to be the bus clock according the binding
doc, whether "clock-names" is there or not :/
So what are those old r329 bindings ? is there a documentation defining
them somewhere ?
Cleaning that part would help with A733 addition in the existing driver
I think
>
>> +#define CLK_RTC_32K 3
>
> AFAICT besides being an internal clock, this is also fed to GPIO for
> debounce? We probably need to expose this on the A523 as well.
>
>
> Thanks
> ChenYu
>
>
>> +#define CLK_OSC32K_FANOUT 4
>> +#define CLK_HOSC_SERDES1 5
>> +#define CLK_HOSC_SERDES0 6
>> +#define CLK_HOSC_HDMI 7
>> +#define CLK_HOSC_UFS 8
>> +
>> +#endif /* _DT_BINDINGS_CLK_SUN60I_A733_RTC_H_ */
>>
>> --
>> 2.52.0
>>
>>
--
Jerome
^ permalink raw reply
* [PATCH v1] ARM: imx: avic: Fix OF node reference leaks
From: Yuho Choi @ 2026-06-15 17:45 UTC (permalink / raw)
To: Frank Li, Sascha Hauer, Russell King, Pengutronix Kernel Team
Cc: Fabio Estevam, linux-arm-kernel, imx, linux-kernel, Yuho Choi
of_find_compatible_node() returns a device node with its reference count
incremented. mxc_init_irq() looks up the i.MX25 CCM node for of_iomap()
and the AVIC node for irq_domain_create_legacy(), but does not release
either temporary reference.
of_iomap() does not consume the node reference, and
irq_domain_create_legacy() takes its own fwnode reference for the domain.
Drop the temporary OF node references after each use.
Fixes: 9b454d16e57d ("ARM: imx: avic: set low-power interrupt mask for imx25")
Fixes: 544496ab5cbd ("ARM: imx: move irq_domain_add_legacy call into avic driver")
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
---
arch/arm/mach-imx/avic.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-imx/avic.c b/arch/arm/mach-imx/avic.c
index 3067c06b4b8e..6873a50bbe2c 100644
--- a/arch/arm/mach-imx/avic.c
+++ b/arch/arm/mach-imx/avic.c
@@ -173,6 +173,7 @@ static void __init mxc_init_irq(void __iomem *irqbase)
np = of_find_compatible_node(NULL, NULL, "fsl,imx25-ccm");
mx25_ccm_base = of_iomap(np, 0);
+ of_node_put(np);
if (mx25_ccm_base) {
/*
@@ -203,6 +204,7 @@ static void __init mxc_init_irq(void __iomem *irqbase)
np = of_find_compatible_node(NULL, NULL, "fsl,avic");
domain = irq_domain_create_legacy(of_fwnode_handle(np), AVIC_NUM_IRQS, irq_base, 0,
&irq_domain_simple_ops, NULL);
+ of_node_put(np);
WARN_ON(!domain);
for (i = 0; i < AVIC_NUM_IRQS / 32; i++, irq_base += 32)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v8 04/12] iommu/tegra241-cmdqv: Restore PROD and CONS after resume
From: Pranjal Shrivastava @ 2026-06-15 17:43 UTC (permalink / raw)
To: Mostafa Saleh
Cc: iommu, Will Deacon, Joerg Roedel, Robin Murphy, Jason Gunthorpe,
Nicolin Chen, Daniel Mentz, Ashish Mhetre, linux-arm-kernel
In-Reply-To: <ajAv7pvRlAgLR7cn@google.com>
On Mon, Jun 15, 2026 at 05:01:34PM +0000, Mostafa Saleh wrote:
> On Mon, Jun 01, 2026 at 09:59:01PM +0000, Pranjal Shrivastava wrote:
> > From: Ashish Mhetre <amhetre@nvidia.com>
> >
> > PROD and CONS indices for vcmdqs are getting set to 0 after resume.
> > Because of this the vcmdq is not consuming commands after resume.
> > Fix this by restoring PROD and CONS indices after resume from
> > saved pointers.
>
> What commands are exisiting at resume? Won't
> tegra241_cmdqv_drain_vintf0_lvcmdqs() drain the queues and make the
> PROD and CONS equal each other anyway?
The SW prod / cons are indeed equal because of the queue drain before
suspend. However, the HW registers in vCMDQ reset to 0 on a power-cycle
Now, if we resume with the software prod/cons at 100/100, since the HW
prod/cons is at 0/0, when the driver then issues a new command and only
updates the PROD register to 101, the HW will see (CONS=0, PROD=101).
The arm-smmu-v3 driver restores these indices correctly in device_reset
but the Tegra VMDQV driver doesn't. Thus, this patch was added to
restore both indices ensuring the HW doesn't de-sync.
This was added after Ashish tested an older version of the series [1]
with Tegra,
Thanks,
Praan
[1] https://lore.kernel.org/all/6afc3e46-489e-4741-96d5-8a2f72a8b431@nvidia.com/
^ permalink raw reply
* Re: [PATCH 1/8] mm: Add ptep_try_set() for lockless empty-slot installs
From: Tejun Heo @ 2026-06-15 17:40 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Will Deacon, David Vernet, Andrea Righi, Changwoo Min,
Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Kumar Kartikeya Dwivedi, Peter Zijlstra,
Catalin Marinas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, Andrew Morton, Mike Rapoport, Emil Tsalapatis,
sched-ext, bpf, x86, linux-arm-kernel, linux-mm, linux-kernel
In-Reply-To: <79338662-e637-412b-84b4-71cef3883b3d@kernel.org>
Hello,
On Mon, Jun 15, 2026 at 07:36:19PM +0200, David Hildenbrand (Arm) wrote:
> On 6/15/26 18:27, Tejun Heo wrote:
> > Hello, David.
> >
> >> Is BPF maybe picking up patches from other subsystems up too early
> >> without waiting for acks?
> >
> > Do you mean the comment cleanup I just sent, or the original
> > ptep_try_set() merge?
>
> I am talking about any patch that touches arch code without an ACK from the
> maintainer.
>
> Maybe arm64 and x86 people are fine with that, but I heard other voices
> recently, thus my question.
I see. I don't know the dynamics here. I'll leave it for bpf folks.
Thanks.
--
tejun
^ permalink raw reply
* Re: [PATCH 1/8] mm: Add ptep_try_set() for lockless empty-slot installs
From: David Hildenbrand (Arm) @ 2026-06-15 17:36 UTC (permalink / raw)
To: Tejun Heo
Cc: Will Deacon, David Vernet, Andrea Righi, Changwoo Min,
Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Martin KaFai Lau, Kumar Kartikeya Dwivedi, Peter Zijlstra,
Catalin Marinas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, Andrew Morton, Mike Rapoport, Emil Tsalapatis,
sched-ext, bpf, x86, linux-arm-kernel, linux-mm, linux-kernel
In-Reply-To: <31d1ac68dc230564301fc1e7dc748a1d@kernel.org>
On 6/15/26 18:27, Tejun Heo wrote:
> Hello, David.
>
>> Is BPF maybe picking up patches from other subsystems up too early
>> without waiting for acks?
>
> Do you mean the comment cleanup I just sent, or the original
> ptep_try_set() merge?
I am talking about any patch that touches arch code without an ACK from the
maintainer.
Maybe arm64 and x86 people are fine with that, but I heard other voices
recently, thus my question.
>
> The original went through several rounds, and you acked the patch that
> introduced both problems (258df8fce42f) before it landed.
I am not an arm64 maintainer although working for the company :)
--
Cheers,
David
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox