* [PATCH v2 3/6] iommu/qcom: Check pm_runtime_resume_and_get() return in probe
From: Mukesh Ojha @ 2026-07-17 14:46 UTC (permalink / raw)
To: Rob Clark, Will Deacon, Joerg Roedel (AMD), Alex Williamson
Cc: Robin Murphy, iommu, linux-arm-msm, linux-arm-kernel,
linux-kernel, Mukesh Ojha, Konrad Dybcio
In-Reply-To: <20260717144608.3216274-1-mukesh.ojha@oss.qualcomm.com>
The SMMU_INTR_SEL_NS register write in qcom_iommu_device_probe() uses
pm_runtime_get_sync() without checking the return value. If runtime
resume fails the subsequent writel_relaxed() would access hardware with
clocks potentially disabled.
Switch to pm_runtime_resume_and_get() which handles the usage-count
cleanup on failure, check the return value, and unwind the already
registered iommu device on error.
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
drivers/iommu/arm/arm-smmu/qcom_iommu.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 71251aecc292..1d04f0a19124 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -861,13 +861,17 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
}
if (qcom_iommu->local_base) {
- pm_runtime_get_sync(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret)
+ goto err_iommu_unregister;
writel_relaxed(0xffffffff, qcom_iommu->local_base + SMMU_INTR_SEL_NS);
pm_runtime_put_sync(dev);
}
return 0;
+err_iommu_unregister:
+ iommu_device_unregister(&qcom_iommu->iommu);
err_sysfs_remove:
iommu_device_sysfs_remove(&qcom_iommu->iommu);
return ret;
--
2.53.0
^ permalink raw reply related
* [PATCH v2 2/6] iommu/qcom: Use devm_pm_runtime_enable() in qcom_iommu_device_probe()
From: Mukesh Ojha @ 2026-07-17 14:46 UTC (permalink / raw)
To: Rob Clark, Will Deacon, Joerg Roedel (AMD), Alex Williamson
Cc: Robin Murphy, iommu, linux-arm-msm, linux-arm-kernel,
linux-kernel, Mukesh Ojha
In-Reply-To: <20260717144608.3216274-1-mukesh.ojha@oss.qualcomm.com>
Switch from pm_runtime_enable() to devm_pm_runtime_enable() so that
the matching pm_runtime_disable() is handled automatically via devres,
both on probe failure and on device removal.
This removes the err_pm_disable error label from the probe function and
the explicit pm_runtime_disable() call from qcom_iommu_device_remove().
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
drivers/iommu/arm/arm-smmu/qcom_iommu.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 09f2ee6be988..71251aecc292 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -836,20 +836,22 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, qcom_iommu);
- pm_runtime_enable(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
/* register context bank devices, which are child nodes: */
ret = devm_of_platform_populate(dev);
if (ret) {
dev_err(dev, "Failed to populate iommu contexts\n");
- goto err_pm_disable;
+ return ret;
}
ret = iommu_device_sysfs_add(&qcom_iommu->iommu, dev, NULL,
dev_name(dev));
if (ret) {
dev_err(dev, "Failed to register iommu in sysfs\n");
- goto err_pm_disable;
+ return ret;
}
ret = iommu_device_register(&qcom_iommu->iommu, &qcom_iommu_ops, dev);
@@ -868,8 +870,6 @@ static int qcom_iommu_device_probe(struct platform_device *pdev)
err_sysfs_remove:
iommu_device_sysfs_remove(&qcom_iommu->iommu);
-err_pm_disable:
- pm_runtime_disable(dev);
return ret;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v2 1/6] iommu/qcom: Fix inverted fault report check in qcom_iommu_fault()
From: Mukesh Ojha @ 2026-07-17 14:46 UTC (permalink / raw)
To: Rob Clark, Will Deacon, Joerg Roedel (AMD), Alex Williamson
Cc: Robin Murphy, iommu, linux-arm-msm, linux-arm-kernel,
linux-kernel, Mukesh Ojha, Konrad Dybcio
In-Reply-To: <20260717144608.3216274-1-mukesh.ojha@oss.qualcomm.com>
report_iommu_fault() returns 0 when a fault handler successfully handles
the fault, and -ENOSYS when no handler is installed. The condition
'!report_iommu_fault()' evaluates to true (printing "Unhandled context
fault") precisely when the fault *was* handled, and stays silent when no
handler is present — the opposite of what is intended.
Remove the '!' so the driver logs unhandled faults correctly.
Fixes: 049541e178d5 ("iommu: qcom: wire up fault handler")
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
---
drivers/iommu/arm/arm-smmu/qcom_iommu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 32efef69e72d..09f2ee6be988 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -200,7 +200,7 @@ static irqreturn_t qcom_iommu_fault(int irq, void *dev)
fsynr = iommu_readl(ctx, ARM_SMMU_CB_FSYNR0);
iova = iommu_readq(ctx, ARM_SMMU_CB_FAR);
- if (!report_iommu_fault(ctx->domain, ctx->dev, iova, 0)) {
+ if (report_iommu_fault(ctx->domain, ctx->dev, iova, 0)) {
dev_err_ratelimited(ctx->dev,
"Unhandled context fault: fsr=0x%x, "
"iova=0x%016llx, fsynr=0x%x, cb=%d\n",
--
2.53.0
^ permalink raw reply related
* [PATCH v2 0/6] iommu/qcom: Misc Fixes
From: Mukesh Ojha @ 2026-07-17 14:46 UTC (permalink / raw)
To: Rob Clark, Will Deacon, Joerg Roedel (AMD), Alex Williamson
Cc: Robin Murphy, iommu, linux-arm-msm, linux-arm-kernel,
linux-kernel, Mukesh Ojha
Series to address fixes in legacy qcom_iommu driver, it is based on top
of https://lore.kernel.org/lkml/20260623071245.1985938-1-haoxiang_li2024@163.com/
Changes in v1: https://lore.kernel.org/lkml/20260623122034.1166295-1-mukesh.ojha@oss.qualcomm.com/
- Used devm_pm_runtime_enable in 2/6 as per comment.
- Dropped 6/8 and 8/8 from the last series.
- Added R-b and fixes tag.
Mukesh Ojha (6):
iommu/qcom: Fix inverted fault report check in qcom_iommu_fault()
iommu/qcom: Use devm_pm_runtime_enable() in qcom_iommu_device_probe()
iommu/qcom: Check pm_runtime_resume_and_get() return in probe
iommu/qcom: Fix pgtbl_ops leak in qcom_iommu_init_domain() error path
iommu/qcom: Publish pgtbl_ops before releasing init_mutex
iommu/qcom: Enable clocks before hardware access in
qcom_iommu_ctx_probe()
drivers/iommu/arm/arm-smmu/qcom_iommu.c | 31 ++++++++++++++++---------
1 file changed, 20 insertions(+), 11 deletions(-)
--
2.53.0
^ permalink raw reply
* Re: [PATCH v1] arm64: cpuinfo: Fix sysfs cleanup on failure
From: 최유호 @ 2026-07-17 14:45 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, Mark Brown, Yicong Yang, Oliver Upton, Zhou Wang,
linux-arm-kernel, linux-kernel
In-Reply-To: <aljL_HSIc2ZhVj07@willie-the-truck>
On Thu, 16 Jul 2026 at 08:18, Will Deacon <will@kernel.org> wrote:
>
> Why is it a good idea to remove the entire group if the merge fails?
> Wouldn't it be more pragmatic to continue with the group that we did
> manage to create? I don't really get why this proposed behaviour is
> better.
You're right. Removing the entire group on an SME merge failure is
unncessary. I'll send a v2 incorporating your suggestion.
Thanks for your time reviewing.
Yuho.
^ permalink raw reply
* [PATCH v5 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
From: André Almeida @ 2026-07-17 14:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Uros Bizjak, Thomas Weißschuh, Liam R. Howlett
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
In-Reply-To: <20260717-tonyk-robust_arm-v5-0-ffd1ad318d17@igalia.com>
Based on the x86 implementation, implement the vDSO function for unlocking
a robust futex correctly.
Commit a2274cc0091e ("x86/vdso: Implement __vdso_futex_robust_try_unlock()")
has the full explanation about why this mechanism is needed.
The unlock assembly sequence for arm64 is:
__vdso_futex_robust_list64_try_unlock:
retry:
ldxr w8, [x0] // Load the value from *futex
cmp w1, w8 // Compare with TID
b.ne __vdso_futex_list64_try_unlock_cs_end
stlxr w3, wzr, [x0] // Try to zero *futex
__vdso_futex_list64_try_unlock_cs_start:
cbnz w3, retry
str xzr, [x2] // After zeroing *futex, zero *op_pending
__vdso_futex_list64_try_unlock_cs_end>:
The decision regarding if the pointer should be cleared or not lies on
checking the w3 register:
return (regs->user_regs[3]) ? NULL : (void __user *)
regs->user_regs.regs[2];
If it's zero, that means that the exclusive store worked and the kernel
should clear op_pending (if userspace didn't managed to) stored at x2.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Notes:
- Only LL/SC for now but I can add LSE later if this looks good
v4:
- Guard makefile for vfutex.o with ifdef
- Moved _start label one instruction above
- Use results register (w3) to check for store success instead of using zero
flag
v3:
- Managed to get pop to always be stored at x2
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/futex_robust.h | 19 +++++++++++++++++++
arch/arm64/kernel/vdso/Makefile | 10 ++++++++++
arch/arm64/kernel/vdso/vfutex.c | 35 +++++++++++++++++++++++++++++++++++
4 files changed, 65 insertions(+)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919..0582172811d9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -221,6 +221,7 @@ config ARM64
select HAVE_RELIABLE_STACKTRACE
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select HAVE_FUNCTION_ARG_ACCESS_API
+ select HAVE_FUTEX_ROBUST_UNLOCK
select MMU_GATHER_RCU_TABLE_FREE
select HAVE_RSEQ
select HAVE_RUST if RUSTC_SUPPORTS_ARM64
diff --git a/arch/arm64/include/asm/futex_robust.h b/arch/arm64/include/asm/futex_robust.h
new file mode 100644
index 000000000000..64f22166756a
--- /dev/null
+++ b/arch/arm64/include/asm/futex_robust.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_FUTEX_ROBUST_H
+#define _ASM_ARM64_FUTEX_ROBUST_H
+
+#include <asm/ptrace.h>
+
+static __always_inline void __user *arm64_futex_robust_unlock_get_pop(struct pt_regs *regs)
+{
+ /*
+ * w3 is stores the result of the stlxr instruction. If it's zero, the then
+ * the ll/sc cmpxchg succeeded and the pending op pointer needs to be cleared.
+ */
+ return (regs->user_regs.regs[3]) ? NULL : (void __user *) regs->user_regs.regs[2];
+}
+
+#define arch_futex_robust_unlock_get_pop(regs) \
+ arm64_futex_robust_unlock_get_pop(regs)
+
+#endif /* _ASM_ARM64_FUTEX_ROBUST_H */
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index 7dec05dd33b7..985346c7a0bb 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -11,6 +11,10 @@ include $(srctree)/lib/vdso/Makefile.include
obj-vdso := vgettimeofday.o note.o sigreturn.o vgetrandom.o vgetrandom-chacha.o
+ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+ obj-vdso += vfutex.o
+endif
+
# Build rules
targets := $(obj-vdso) vdso.so vdso.so.dbg
obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
@@ -45,9 +49,11 @@ CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
+CFLAGS_REMOVE_vfutex.o = $(CC_FLAGS_REMOVE_VDSO)
CFLAGS_vgettimeofday.o = $(CC_FLAGS_ADD_VDSO)
CFLAGS_vgetrandom.o = $(CC_FLAGS_ADD_VDSO)
+CFLAGS_vfutex.o = $(CC_FLAGS_ADD_VDSO)
ifneq ($(c-gettimeofday-y),)
CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
@@ -57,6 +63,10 @@ ifneq ($(c-getrandom-y),)
CFLAGS_vgetrandom.o += -include $(c-getrandom-y)
endif
+ifneq ($(c-futex-y),)
+ CFLAGS_vfutex.o += -include $(c-futex-y)
+endif
+
targets += vdso.lds
CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
diff --git a/arch/arm64/kernel/vdso/vfutex.c b/arch/arm64/kernel/vdso/vfutex.c
new file mode 100644
index 000000000000..4c69d92426fd
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vfutex.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/stringify.h>
+#include <vdso/futex.h>
+
+#define LABEL(name, sz) __stringify(__futex_list##sz##_try_unlock_cs_##name)
+
+#define GLOBLS(sz) ".globl " LABEL(start, sz) ", " LABEL(success, sz) ", " LABEL(end, sz) "\n"
+
+__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
+{
+ register __u64 *pop_reg asm("x2") = pop;
+ register __u32 result_reg asm("w3") = 0;
+ __u32 val;
+
+ asm volatile (
+ GLOBLS(64)
+ " prfm pstl1strm, %[lock] \n"
+ "retry: \n"
+ " ldxr %w[val], %[lock] \n"
+ " cmp %w[tid], %w[val] \n"
+ " bne " LABEL(end, 64)" \n"
+ " stlxr %w[result], wzr, %[lock] \n"
+ LABEL(start, 64)": \n"
+ " cbnz %w[result], retry \n"
+ LABEL(success, 64)": \n"
+ " str xzr, %[pop_reg] \n"
+ LABEL(end, 64)": \n"
+
+ : [val] "=&r" (val), [result] "=&r" (result_reg)
+ : [tid] "r" (tid), [lock] "Q" (*lock), [pop_reg] "Q" (*pop_reg)
+ : "cc", "memory"
+ );
+
+ return val;
+}
--
2.55.0
^ permalink raw reply related
* [PATCH v5 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
From: André Almeida @ 2026-07-17 14:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Uros Bizjak, Thomas Weißschuh, Liam R. Howlett
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
In-Reply-To: <20260717-tonyk-robust_arm-v5-0-ffd1ad318d17@igalia.com>
Based on aarch64 implementation, provide a 32 bit entry point for
this vDSO.
In order to keep compatibility with arm64_futex_robust_unlock_get_pop(),
make sure to store the pop address at r2 and the compare result value
at r3.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
arch/arm64/kernel/vdso.c | 9 +++++++++
arch/arm64/kernel/vdso32/Makefile | 4 ++++
arch/arm64/kernel/vdso32/vdso.lds.S | 9 +++++++++
arch/arm64/kernel/vdso32/vfutex.c | 33 +++++++++++++++++++++++++++++++++
4 files changed, 55 insertions(+)
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index ff43b74e514e..1e62af9158b9 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -71,6 +71,15 @@ static void vdso_futex_robust_unlock_update_ips(enum vdso_abi abi, struct mm_str
futex_set_vdso_cs_range(fd, 0, success, end, false);
}
+
+#ifdef CONFIG_COMPAT_VDSO
+ if (abi == VDSO_ABI_AA32) {
+ success = (uintptr_t) VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_start);
+ end = (uintptr_t) VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_end);
+
+ futex_set_vdso_cs_range(fd, 1, success, end, true);
+ }
+#endif
}
#else
static inline void vdso_futex_robust_unlock_update_ips(enum vdso_abi abi, struct mm_struct *mm) { }
diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
index 4bd60f059f4a..f3190125c68b 100644
--- a/arch/arm64/kernel/vdso32/Makefile
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -97,6 +97,10 @@ munge := ../../../arm/vdso/vdsomunge
hostprogs := $(munge)
c-obj-vdso := note.o
+ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+ c-obj-vdso += vfutex.o
+endif
+
c-obj-vdso-gettimeofday := vgettimeofday.o
ifneq ($(c-gettimeofday-y),)
diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
index c374fb0146f3..46c0123b2684 100644
--- a/arch/arm64/kernel/vdso32/vdso.lds.S
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -87,6 +87,15 @@ VERSION
__vdso_clock_getres;
__vdso_clock_gettime64;
__vdso_clock_getres_time64;
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+ __vdso_futex_robust_list32_try_unlock;
+#endif
local: *;
};
}
+
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+VDSO_futex_list32_try_unlock_cs_success = __futex_list32_try_unlock_cs_success;
+VDSO_futex_list32_try_unlock_cs_start = __futex_list32_try_unlock_cs_start;
+VDSO_futex_list32_try_unlock_cs_end = __futex_list32_try_unlock_cs_end;
+#endif
diff --git a/arch/arm64/kernel/vdso32/vfutex.c b/arch/arm64/kernel/vdso32/vfutex.c
new file mode 100644
index 000000000000..b6ca4b678108
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vfutex.c
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/stringify.h>
+#include <vdso/futex.h>
+
+#define LABEL(name, sz) __stringify(__futex_list##sz##_try_unlock_cs_##name)
+
+#define GLOBLS(sz) ".globl " LABEL(start, sz) ", " LABEL(success, sz) ", " LABEL(end, sz) "\n"
+
+__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
+{
+ register __u32 *pop_reg asm("r2") = pop, result_reg asm("r3") = 0;
+ __u32 val, zero = 0;
+
+ asm volatile (
+ GLOBLS(32)
+ "retry: \n"
+ " ldrex %[val], %[lock] \n"
+ " cmp %[tid], %[val] \n"
+ " bne " LABEL(end, 32)" \n"
+ " strex %[result], %[zero], %[lock] \n"
+ LABEL(start, 32)": \n"
+ " cmp %[result], #0 \n"
+ " bne retry \n"
+ LABEL(success, 32)": \n"
+ " str %[zero], %[pop_reg] \n"
+ LABEL(end, 32)": \n"
+ : [val] "=&r" (val), [result] "=r" (result_reg)
+ : [tid] "r" (tid), [lock] "Q" (*lock), [pop_reg] "Q" (*pop_reg), [zero] "r" (zero)
+ : "cc", "memory"
+ );
+
+ return val;
+}
--
2.55.0
^ permalink raw reply related
* [PATCH v5 3/4] arm64: vdso32: Bring vdso32-offsets.h back
From: André Almeida @ 2026-07-17 14:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Uros Bizjak, Thomas Weißschuh, Liam R. Howlett
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
In-Reply-To: <20260717-tonyk-robust_arm-v5-0-ffd1ad318d17@igalia.com>
Commit c7767f5c43df ("arm64: vdso32: Remove unused vdso32-offsets.h")
removed vdso32-offsets.h because it was empty and therefore useless.
With the introduction of __vdso_futex_robust_try_unlock(), there is the
need to expose offsets again.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
arch/arm64/Makefile | 2 +-
arch/arm64/include/asm/vdso.h | 3 +++
arch/arm64/kernel/vdso32/Makefile | 8 ++++++++
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 6b005c8fef70..265716644193 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -211,7 +211,7 @@ vdso_prepare: prepare0
include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so
ifdef CONFIG_COMPAT_VDSO
$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \
- arch/arm64/kernel/vdso32/vdso.so
+ include/generated/vdso32-offsets.h arch/arm64/kernel/vdso32/vdso.so
endif
endif
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 232b46969088..43a214b93524 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -10,6 +10,9 @@
#ifndef __ASSEMBLER__
#include <generated/vdso-offsets.h>
+#ifdef CONFIG_COMPAT_VDSO
+#include <generated/vdso32-offsets.h>
+#endif
#define VDSO_SYMBOL(base, name) \
({ \
diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
index bea3675fa668..4bd60f059f4a 100644
--- a/arch/arm64/kernel/vdso32/Makefile
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -135,6 +135,14 @@ $(c-obj-vdso-gettimeofday): %.o: %.c FORCE
$(asm-obj-vdso): %.o: %.S FORCE
$(call if_changed_dep,vdsoas)
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+ cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE
+ $(call if_changed,vdsosym)
+
# Actual build commands
quiet_cmd_vdsold_and_vdso_check = LD32 $@
cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check)
--
2.55.0
^ permalink raw reply related
* [PATCH v5 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
From: André Almeida @ 2026-07-17 14:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Uros Bizjak, Thomas Weißschuh, Liam R. Howlett
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
Hi folks,
This is my take on implementing the new vDSO for unlocking a robust futex in
arm64. If you don't know what's that, Thomas wrote a good summary,
including the motivation for this work and the x86 implementation:
https://lore.kernel.org/lkml/878qb89g7b.ffs@tglx/
* Testing
There's one selftest proposed [1] that tests precisely if the task is
interrupted during the critical section, if the kernel will clear op_pending
pointer. I've adapted to arm64 [2] and it works as expected. This test is not
being upstreamed right now because it depends on a better way to expose
vdso.so.dbg [3].
I also used gdb to manually check if the address is cleared when the kernel
interrupts the critical section.
* The patchset
As explained in the Testing section above, we developed a test that puts
breakpoints in the code to test if a user code being interrupted really clears
the op_pending pointer. This test wasn't initially working because of this check
at futex_fixup_robust_unlock():
/*
* Avoid dereferencing current->mm if not returning from interrupt.
* current->rseq.event is going to be used subsequently, so bringing the
* cache line in is not a big deal.
*/
if (!current->rseq.event.user_irq)
return;
rseq.event.user_irq was always false during my tests, and it prevents the fixup
to happen. I figured out that arm64_syscall_enter_from_user_mode() was the
issue because it doesn't set user_irq to true when the task comes from a
syscall. I dropped arm64_syscall_enter_from_user_mode() and replaced with
arm64_enter_from_user_mode() and the test now works fine. I honestly don't know
if this solution is the correct one here, so I would like to hear from the arm64
folks what's the best approach here.
Thanks!
André
[1] https://lore.kernel.org/lkml/20260404093939.7XgeW_54@linutronix.de/
[2] https://lore.kernel.org/lkml/20260529-tonyk-robust_arm-v3-3-a6f02684d4fe@igalia.com/
[3] https://lore.kernel.org/lkml/20260602090536.045586688@kernel.org/
Changes in v5:
- Drop unneeded commit "arm64/entry: Unify user mode handling"
- Replace "_success" with "_start" labels in vdso_futex_robust_unlock_update_ips
- Added "cc" to the asm clobberlist
v4: https://patch.msgid.link/20260705-tonyk-robust_arm-v4-0-e0fd0fa259d3@igalia.com
Changes in v4:
- Added commit "arm64/entry: Unify user mode handling"
- Added missing ifdef FUTEX_ROBUST_UNLOCK guards
- Fixed the position of _start and _success labels in the critical section
- Instead of checking the zero flag, check the result register to decide if the
op_pending needs to be cleared
v3: https://patch.msgid.link/20260529-tonyk-robust_arm-v3-0-a6f02684d4fe@igalia.com
Changes in v3:
- Change asm to always use x2 to store *pop
- Fix clang asm errors
- Moved 32 bit entry point to vdso32/ and use littlearm asm
- Adapted Sebastians test for arm
v2: https://patch.msgid.link/20260424-tonyk-robust_arm-v2-0-db4e46f752cf@igalia.com
Changes in v2:
- s/CONFIG_COMPAT/CONFIG_COMPAT_VDSO (Thomas Weißschuh)
- Fixed linker not finding the symbols (Thomas Weißschuh)
v1: https://patch.msgid.link/20260417-tonyk-robust_arm-v1-0-03aa64e2ff1a@igalia.com
---
André Almeida (4):
arm64: vdso: Prepare for robust futex unlock support
arm64: vdso: Implement __vdso_futex_robust_try_unlock()
arm64: vdso32: Bring vdso32-offsets.h back
arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
arch/arm64/Kconfig | 1 +
arch/arm64/Makefile | 2 +-
arch/arm64/include/asm/futex_robust.h | 19 +++++++++++++++
arch/arm64/include/asm/vdso.h | 3 +++
arch/arm64/kernel/vdso.c | 44 ++++++++++++++++++++++++++++++++++-
arch/arm64/kernel/vdso/Makefile | 10 ++++++++
arch/arm64/kernel/vdso/vdso.lds.S | 9 +++++++
arch/arm64/kernel/vdso/vfutex.c | 35 ++++++++++++++++++++++++++++
arch/arm64/kernel/vdso32/Makefile | 12 ++++++++++
arch/arm64/kernel/vdso32/vdso.lds.S | 9 +++++++
arch/arm64/kernel/vdso32/vfutex.c | 33 ++++++++++++++++++++++++++
11 files changed, 175 insertions(+), 2 deletions(-)
---
base-commit: fce2dfa773ced15f27dd27cd0b482a7473cdcf2a
change-id: 20260416-tonyk-robust_arm-54ff77d2c4e4
Best regards,
--
André Almeida <andrealmeid@igalia.com>
^ permalink raw reply
* [PATCH v5 1/4] arm64: vdso: Prepare for robust futex unlock support
From: André Almeida @ 2026-07-17 14:41 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Carlos O'Donell,
Peter Zijlstra, Florian Weimer, Rich Felker, Torvald Riegel,
Darren Hart, Ingo Molnar, Davidlohr Bueso, Arnd Bergmann,
Uros Bizjak, Thomas Weißschuh, Liam R. Howlett
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
In-Reply-To: <20260717-tonyk-robust_arm-v5-0-ffd1ad318d17@igalia.com>
There will be a VDSO function to unlock non-contended robust futexes in
user space. The unlock sequence is racy vs. clearing the list_pending_op
pointer in the task's robust list head. To plug this race the kernel needs
to know the critical section window so it can clear the pointer when the
task is interrupted within that race window. The window is determined by
labels in the inline assembly.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
v4:
- Guard symbols from vdso.lds.S with ifdef
- drop update_ips() from sigpage remap function
v3:
- Fix adding vdso base addr twice
- Call vdso_futex_robust_unlock_update_ips() on remap as well
v2:
- Fixed linker not finding VDSO symbols
---
arch/arm64/kernel/vdso.c | 35 ++++++++++++++++++++++++++++++++++-
arch/arm64/kernel/vdso/vdso.lds.S | 9 +++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 592dd8668de4..ff43b74e514e 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -11,6 +11,7 @@
#include <linux/clocksource.h>
#include <linux/elf.h>
#include <linux/err.h>
+#include <linux/futex.h>
#include <linux/errno.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
@@ -57,11 +58,41 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
#endif /* CONFIG_COMPAT_VDSO */
};
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+static void vdso_futex_robust_unlock_update_ips(enum vdso_abi abi, struct mm_struct *mm)
+{
+ unsigned long vdso = (unsigned long) mm->context.vdso;
+ struct futex_mm_data *fd = &mm->futex;
+ uintptr_t success, end;
+
+ if (abi == VDSO_ABI_AA64) {
+ success = (uintptr_t) VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_start);
+ end = (uintptr_t) VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_end);
+
+ futex_set_vdso_cs_range(fd, 0, success, end, false);
+ }
+}
+#else
+static inline void vdso_futex_robust_unlock_update_ips(enum vdso_abi abi, struct mm_struct *mm) { }
+#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
+
static int vdso_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma)
{
current->mm->context.vdso = (void *)new_vma->vm_start;
+ vdso_futex_robust_unlock_update_ips(VDSO_ABI_AA64, current->mm);
+
+ return 0;
+}
+
+static int vdso32_mremap(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma)
+{
+ current->mm->context.vdso = (void *)new_vma->vm_start;
+
+ vdso_futex_robust_unlock_update_ips(VDSO_ABI_AA32, current->mm);
+
return 0;
}
@@ -134,6 +165,8 @@ static int __setup_additional_pages(enum vdso_abi abi,
if (IS_ERR(ret))
goto up_fail;
+ vdso_futex_robust_unlock_update_ips(abi, mm);
+
return 0;
up_fail:
@@ -174,7 +207,7 @@ static struct vm_special_mapping aarch32_vdso_maps[] = {
},
[AA32_MAP_VDSO] = {
.name = "[vdso]",
- .mremap = vdso_mremap,
+ .mremap = vdso32_mremap,
},
};
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index 52314be29191..225f59bb81d1 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -104,6 +104,9 @@ VERSION
__kernel_clock_gettime;
__kernel_clock_getres;
__kernel_getrandom;
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+ __vdso_futex_robust_list64_try_unlock;
+#endif
local: *;
};
}
@@ -112,3 +115,9 @@ VERSION
* Make the sigreturn code visible to the kernel.
*/
VDSO_sigtramp = __kernel_rt_sigreturn;
+
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+VDSO_futex_list64_try_unlock_cs_start = __futex_list64_try_unlock_cs_start;
+VDSO_futex_list64_try_unlock_cs_success = __futex_list64_try_unlock_cs_success;
+VDSO_futex_list64_try_unlock_cs_end = __futex_list64_try_unlock_cs_end;
+#endif
--
2.55.0
^ permalink raw reply related
* Re: [RFC PATCH v1 8/8] misc/arm-cla: Add userspace interface
From: Ryan Roberts @ 2026-07-17 14:35 UTC (permalink / raw)
To: Arnd Bergmann, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <404d2c6d-4a18-40c2-9da9-fb030c39536f@app.fastmail.com>
On 17/07/2026 13:54, Arnd Bergmann wrote:
> On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
>> Expose CLA devices through a character device so userspace can enumerate
>> the available hardware and map accelerator register frames.
>>
>> Define version 1 of the CLA UAPI with a GET_PARAM ioctl. Report device
>> topology, CPU affinity, domain membership, mmap offsets, architecture
>> version and attached accelerator masks, together with the IIDR, DEVARCH
>> and REVIDR of each accelerator.
>>
>> CLA registers can only be read from the CPU local to the device, while
>> enumeration may occur on any CPU. Validate the supported CLA
>> architecture version during device setup and cache the CLA and
>> accelerator identification registers for later ioctl queries.
>
> This interface looks very raw at the moment, I expect this will have
> one or more larger redesigns.
Are you referring to the overall UABI or specifically to the ioctl interface
here? I could imagine the ioctl interface evolving before we get this merged
(although it is based on similar patterns used by some DRM and accel drivers -
it's intended to be easily extensible while existing params remain stable).
The aspect where the CLA MMIO is directly mapped into user space is an aspect we
are keen to keep though since it has significant performance implications if we
need to redirect through the kernel.
>
> Most importantly, a single character device to expose an arbitrary
> number of underlying hardware features is an inherently flawed security
> model. If any specific accelerator is ever found to have a
> major vulnerability, that would mean administrators will have to
> disable all of them by default.
Note that we are exposing MMIO per CLA, not per accelerator. So preventing
access to a single CLA would prevent access to all accelerators attached to it.
There is a per-accelerator availability masking control that the kernel can use
to disable access to selected accelerators though, which might help with the
vulnerability example.
The rationale for choosing a single device file was driven by performance: At
domain reassignment time, we need to unmap and invalidate the TLB entries for
all the devices in the domain from the out-going process's address space. By
having all the devices in a single file and all devices within the same domain
adjacent, they can all be mapped to a single VMA, meaning the driver can use a
single call to the existing zap_special_vma_range(), which will result in a
single TLBI-by-range instruction, which is faster than a TLBI-by-va for every
device.
If you think it is important for security to have each CLA exposed by an
independent device file, I'll take another look.
>
>> Support shared read-write mmap of one or more CLA register pages. Create
>> a context for every domain covered by the mapping and resolve faults
>> only while that context owns the domain. Queue unassigned contexts with
>> the domain scheduler, drop mmap_lock while waiting for assignment and
>> retry the fault after the context is woken.
>
> I still need some time to better understand what this means.
I can probably do a better job of explaining this: The kernel keeps a cla_ctx
object which represents a single {file description, mm_struct} context that
wants to use the cla_domain (collection of 1 or more cla_dev). Initially the VMA
is not populated so when user space tries to access, it will fault to the
driver. If the cla_domain is assigned to a different cla_ctx, the faulting
thread is put to sleep until the driver determines that it's the turn of that
cla_ctx to be assigned the domain. At that point the waiting thread(s) are woken
and map the devices from the domain to the VMA and return to user space. The
out-going cla_ctx had it's mappings removed during the reassignment process so
any user space access will now fault and sleep waiting for assignment.
> Does a CPU have multiple concurrently running contexts?
The HW only has a single HW context, hence the timesliced assignment approach
described above (assuming there is more than 1 concurrent user).
> Is a
> user process able to starve the allocation of other processes
> by just requesting a lot of them?
In the current code, a process can theoretically create the same number of
cla_ctx as the number of file descriptors it can open(). It would then need to
mmap and access to get into the queue to be assigned the domain. I see it as
similar to threads; if process A creates 10 threads and process B creates 1
thread, then in the long run (ignoring cgroups et al) you'd expect A to get
10/11th of the CPU time (IIUC?).
Do you think this consitutes a DoS?
>
>> +static long cla_ioctl_get_param(unsigned long arg)
>> +{
>> + struct arm_cla_param __user *uparam = (void __user *)arg;
>> + struct arm_cla_param param;
>> + int accel_id;
>> + int dev_id;
>> + int ret;
>> +
>> + if (copy_from_user(¶m, uparam, sizeof(param)))
>> + return -EFAULT;
>> +
>> + ret = cla_ioctl_validate_param(¶m);
>> + if (ret)
>> + return ret;
>> +
>> + dev_id = dev_nospec(ARM_CLA_PARAM_INDEX_DEV(param.index));
>> + accel_id = accel_nospec(ARM_CLA_PARAM_INDEX_ACCEL(param.index));
>
> Why is the dev_id/accel_id not a property of the device node itself?
As per above, I can go look again at having a device node per CLA device (i.e.
one for each CPU that has a CLA). But it doesn't make sense to have a device
node per accelerator (a CLA can have up to 8 connected accelerators); there is
only a single HW interface.
>
>> + switch (param.param) {
>> + case ARM_CLA_PARAM_UABI_VERSION:
>> + param.value = ARM_CLA_UABI_VERSION;
>> + break;
>
> UABI definitions are not versioned, you have to stay compatible
> indefinitely. If you need something else, add a new command.
Yes agreed; my mistake - this is used for the internal development versions
where the interface has been changing and I forgot to remove it for the RFC.
>
>> + wait_event_interruptible(ctx->waitq,
>> + READ_ONCE(domain->assigned_ctx) == ctx ||
>> + cla_ctx_is_dying(ctx) ||
>> + READ_ONCE(domain->broken));
>
> If you call wait_event_interruptible(), you have to check the return
> code and deal with it being interrupted.
I believe this is already correct - I'm reeturning VM_FAULT_RETRY
unconditionally at this point, which is also the correct return code if we get
interrupted. This unwinds to arm64's do_page_fault() which then notices and
handles the fault:
/* Quick path to respond to signals */
if (fault_signal_pending(fault, regs)) {
if (!user_mode(regs))
goto no_context;
return 0;
}
I believe GUP and other handle_mm_fault() callers have similar logic.
I'll add a comment to make that clear.
>
>> +static const struct file_operations cla_fops = {
>> + .owner = THIS_MODULE,
>> + .mmap = cla_file_mmap,
>> + .unlocked_ioctl = cla_file_ioctl,
>> +#ifdef CONFIG_COMPAT
>> + .compat_ioctl = cla_file_ioctl,
>> +#endif
>
> No need for the #ifdef here. Technically setting .compat_ioctl=compat_ptr_ioctl
> is the correct way here, though that may change in the future now that
> s390 compat mode is gone.
ACK, I'll fix this.
Thanks,
Ryan
>
> Arnd
^ permalink raw reply
* Re: [PATCH] char: mem: keep arch range checks overflow-safe
From: Greg Kroah-Hartman @ 2026-07-17 14:17 UTC (permalink / raw)
To: Yousef Alhouseen
Cc: Arnd Bergmann, Russell King, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz, linux-kernel, linux-arm-kernel,
linux-sh
In-Reply-To: <20260625085800.4505-1-alhouseenyousef@gmail.com>
On Thu, Jun 25, 2026 at 10:58:00AM +0200, Yousef Alhouseen wrote:
> The generic /dev/mem physical range check now avoids validating
> addr + size directly, but ARM and SH provide their own
> valid_phys_addr_range() implementations with the same wrapped-addition
> pattern.
>
> Use subtraction-based upper-bound checks in those overrides as well. Also
> make the ARM mmap pfn check avoid overflowing the pfn plus page-count
> expression.
>
> Suggested-by: Arnd Bergmann <arnd@arndb.de>
> Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
> ---
> arch/arm/mm/mmap.c | 9 +++++++--
> arch/sh/mm/mmap.c | 4 +++-
> 2 files changed, 10 insertions(+), 3 deletions(-)
This should be part of the char/mem patch, right?
thanks,
greg k-h
^ permalink raw reply
* [PATCH] ARM: imx: Fix suspend/resume crash with Clang CFI
From: Yo'av Moshe @ 2026-07-17 14:16 UTC (permalink / raw)
To: Frank Li, Sascha Hauer, Russell King
Cc: Pengutronix Kernel Team, Fabio Estevam, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, imx,
linux-arm-kernel, llvm, stable, linux-kernel, Yo'av Moshe
Relocated suspend code in OCRAM lacks compiler-generated CFI type
signatures. When CONFIG_CFI=y is active, the indirect call to
imx6_suspend_in_ocram_fn triggers a strict CFI violation panic.
Annotate imx6q_suspend_finish with __nocfi to bypass CFI checking
for this specific indirect call.
Cc: stable@vger.kernel.org
Signed-off-by: Yo'av Moshe <linux@yoavmoshe.com>
---
Tested on a Kobo Clara HD (i.MX6SLL SoC) running postmarketOS edge.
Before this patch, suspending the device caused an immediate silent
hang requiring a hard-reboot. With this patch applied, suspend and
resume work successfully.
arch/arm/mach-imx/pm-imx6.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index a671ca498..d9b0c1803 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -360,7 +360,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
return 0;
}
-static int imx6q_suspend_finish(unsigned long val)
+static int __nocfi imx6q_suspend_finish(unsigned long val)
{
if (!imx6_suspend_in_ocram_fn) {
cpu_do_idle();
--
2.55.0
^ permalink raw reply related
* Re: [PATCH 1/3] dt-bindings: mfd: st,stmpe: add deprecated properties
From: Rob Herring (Arm) @ 2026-07-17 13:59 UTC (permalink / raw)
To: Frank.Li
Cc: linux-kernel, Alexandre Torgue, Maxime Coquelin, linux-arm-kernel,
linux-stm32, devicetree, Conor Dooley, Frank Li, Linus Walleij,
imx, Krzysztof Kozlowski, Sascha Hauer, Pengutronix Kernel Team,
Lee Jones, Fabio Estevam
In-Reply-To: <20260708-dts-stmpe-v1-1-1f51d15bb358@nxp.com>
On Wed, 08 Jul 2026 15:48:56 -0400, Frank.Li@oss.nxp.com wrote:
> From: Frank Li <Frank.Li@nxp.com>
>
> Add deprecated properties st,sample-time, st,sample-time, st,mod-12b and
> st,ref-sel. The both driver drivers/mfd/stmpe.c and
> drivers/input/touchscreen/stmpe-ts.c parse these information. Some dts
> put these properties under mfd, but some put these under child node
> sample_ts.
>
> Allow these properties put under sample_ts and mark as deprecated to fix
> below CHECK_DTBS warnings:
> arch/arm/boot/dts/nxp/imx/imx6q-novena.dtb: stmpe811@44 (st,stmpe811): touchscreen: Unevaluated properties are not allowed ('st,adc-freq', 'st,mod-12b', 'st,ref-sel', 'st,sample-time' were unexpected)
> from schema $id: http://devicetree.org/schemas/mfd/st,stmpe.yaml
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> .../devicetree/bindings/mfd/st,stmpe.yaml | 24 ++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: display: imx: Add deprecated property display and display0
From: Rob Herring (Arm) @ 2026-07-17 13:58 UTC (permalink / raw)
To: Frank.Li
Cc: linux-arm-kernel, Alison Wang, vladimir.oltean, Simona Vetter,
Maxime Ripard, imx, Pengutronix Kernel Team, Frank Li,
ioana.ciornei, Krzysztof Kozlowski, Conor Dooley,
Maarten Lankhorst, devicetree, dri-devel, Stefan Agner,
linux-kernel, Thomas Zimmermann, Fabio Estevam, Sascha Hauer,
David Airlie
In-Reply-To: <20260708-ls-dts-display-v1-1-1986b2611895@nxp.com>
On Wed, 08 Jul 2026 15:39:51 -0400, Frank.Li@oss.nxp.com wrote:
> From: Frank Li <Frank.Li@nxp.com>
>
> Add deprecated property display and display0 to allow old platform lx1021a
> (>10 years) to put display timing under dcu node.
>
> Following patch rename display@0 to display0 and mode0 to timing0. Fix
> below CHECK_DTBS warnings:
> arch/arm/boot/dts/nxp/ls/ls1021a-iot.dtb: dcu@2ce0000 (fsl,ls1021a-dcu): 'display', 'display@0' do not match any of the regexes: '^pinctrl-[0-9]+$'
> from schema $id: http://devicetree.org/schemas/display/fsl,ls1021a-dcu.yaml
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> .../bindings/display/fsl,ls1021a-dcu.yaml | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: fsl,fpga-qixis: Add fsl,ls1021aqds-fpga compatible string
From: Rob Herring (Arm) @ 2026-07-17 13:57 UTC (permalink / raw)
To: Frank.Li
Cc: imx, Conor Dooley, linux-arm-kernel, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, vladimir.oltean, Krzysztof Kozlowski,
Fabio Estevam, devicetree, linux-kernel, Ioana Ciornei
In-Reply-To: <20260708-ls-fpga-v1-1-06c8a099b2a5@nxp.com>
On Wed, 08 Jul 2026 14:55:13 -0400, Frank.Li@oss.nxp.com wrote:
> From: Frank Li <Frank.Li@nxp.com>
>
> Add fsl,ls1021aqds-fpga compatible string for ls1021a qds's FPGA on board
> controller chips, which connect CFI interface.
>
> With following patches to fix below CHECK_DTBS warnings:
> arch/arm/boot/dts/nxp/ls/ls1021a-qds.dtb: memory-controller@1530000 (fsl,ifc): board-control@3,0: 'oneOf' conditional failed, one must be fixed:
> 'bank-width', 'device-width' do not match any of the regexes: '^gpio@[0-9a-f]+$', '^mdio-mux@[a-f0-9,]+$', '^pinctrl-[0-9]+$'
> /home/lizhi/source/linux-upstream-pci-ep-arm/arch/arm/boot/dts/nxp/ls/ls1021a-qds.dtb: memory-controller@1530000 (fsl,ifc): board-control@3,0:compatible: 'oneOf' conditional failed, one must be fixed:
> ['simple-mfd'] is too short
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> Documentation/devicetree/bindings/board/fsl,fpga-qixis.yaml | 1 +
> 1 file changed, 1 insertion(+)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply
* Re: [RFC PATCH v1 1/8] misc/arm-cla: Add driver skeleton and documentation
From: Arnd Bergmann @ 2026-07-17 13:49 UTC (permalink / raw)
To: Ryan Roberts, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <20260717104759.123203-2-ryan.roberts@arm.com>
On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
> From: Jean-Philippe Brucker <jpb@kernel.org>
>
> Add the initial Kconfig and build-system plumbing for the Arm Core Local
> Accelerator driver.
>
> Introduce the common driver header and register definitions used by
> later CLA support. The definitions cover the CLA MMIO frame, launch
> response and status fields, standard accelerator registers, launch
> opcodes, error codes and memory translation context state.
>
> Add documentation describing the CLA programming model, its CPU-local
> MMIO access rules, userspace assignment model, domain grouping and
> expected boot state.
I have a few more questions here. Most of the description and
the design decisions make perfect sense to me, but there are
a few things I don't understand from your current document.
> +The CLA supports up to 8 attached accelerators, which are accessed by
> +programming the CLA's MMIO registers. Operations are launched to an
> accelerator
> +and are polled for completion. CLA does not raise interrupts.
> +
> + CPU CLA Accel
> + |--- write DATA[7:0] -->| |
> + |--- write LAUNCH ----->|---- launch ---->|
> + |<--- poll LRESP -------| |
> + | | |
> + |<--- poll STATUS ------|<--- complete ---|
> +
> +Each operation can take a 512-bit payload in the DATA registers. After handling
> +a LAUNCH write, CLA indicates the launch status in the LRESP register. A further
> +operation can only be launched after LRESP indicates completion of the previous
> +launch.
This sounds a lot like st64bv or st64bv0, passing an 8-word payload and returning
a single word per accelerator operation with shared addressing.
Why are there now two interfaces to do the same thing?
Can a user process use st64bv to do the four steps in a
single instruction?
> +Some operations continue to run asynchronously on the accelerator after launch
> +completion. In this case progress is tracked by polling the STATUS register.
> +When the CLA updates the STATUS register, it also raises an event which will
> +wake an in-progress WFE (wait for event) instruction on the local CPU.
The asynchronous interface seems very confusing.
How are page faults from the SVA master resolved during an
asynchronous operation?
Can a CPU start multiple asynchronous operations concurrently?
Do these continue to run if the starting process is scheduled out
and another process also tries to use CLA?
> +Faults during address translation are reported by the accelerator in its
> +registers and in STATUS. While polling for work completion, software fixes up
> +the faults and notifies the accelerator with RESOLVE operations.
I would like to understand the faulting part better. Which instruction
specifically causes the fault, is that the poll STATUS read?
> +Inter-Accelerator Communication
> +-------------------------------
> +
> +On some platforms, multiple accelerators, each attached to a separate CLA within
> +a cluster, are also directly connected to each other via a shared bus to
> +accelerate cooperation between accelerators. The accelerators sharing a bus
> +cannot be isolated from each other. When collaborative operations are launched
> +on each of the participating accelerators, they synchronize over the bus,
> +stalling until all are ready.
Could you give an example what this model might be good for?
Does this mean a user may have to start one operation on each CPU
from a thread of the same process in order to get a result efficiently
across a shared accelerator?
I assume this will become clearer once you can show an example userspace
application that uses this type of accelerator.
> +Intended SW Usage Model
> +=======================
> +
> +CLA is designed for its PL0 MMIO frame to be mapped into user space and for user
> +space to directly launch accelerator operations and poll for completion. It has
> +been observed that for some use cases, the operation execution time is small and
> +a trip through the kernel would consume a significant amount of the CPU budget
> +for preparing the next operation leading to a significant reduction in bandwidth
> +through the accelerator.
Do you have any plans for in-kernel usage of the accelerators?
I would assume that for things like cryptographic features, these
make sense to be exposed to the kernel itself.
> +User space software is expected to create a thread to drive each CLA it is
> +using, and for each thread to be pinned to the CLA's local CPU.
What happens if multiple processes have the same chardev open and
each mmap() that, e.g. after a fork()? Does each process see its
own virtual instance of the accelerator and interact with it through
the same physical MMIO register range but its own process address space,
or do you have to rely on the registers being mapped only into a
single mm_struct to prevent a process from messing with another process
data?
> +Saving and restoring the internal state of the accelerator is an optional
> +feature. Current platforms only support it when the accelerator is idle, so
> +preempting an accelerator causes work cancellation. Software must carefully
> +consider how to balance forward-progress guarantees with preemption
> latency.
I'm not sure I understand this point. Do you mean any async operation
that was started on an accelerator may fail due to preemption, so user
space must be able to restart it?
Arnd
^ permalink raw reply
* Re: [PATCH v6 2/3] pwm: rp1: Add RP1 PWM controller driver
From: Uwe Kleine-König @ 2026-07-17 13:49 UTC (permalink / raw)
To: Andrea della Porta
Cc: linux-pwm, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Florian Fainelli, Broadcom internal kernel review list,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov, mbrugger, Sean Young,
Julian Braha
In-Reply-To: <aln1D3E5QZULZ2U1@apocalypse>
[-- Attachment #1: Type: text/plain, Size: 3351 bytes --]
Hello Andrea,
On Fri, Jul 17, 2026 at 11:25:35AM +0200, Andrea della Porta wrote:
> On 11:18 Thu 16 Jul , Uwe Kleine-König wrote:
> > On Fri, Jul 03, 2026 at 07:05:25PM +0200, Andrea della Porta wrote:
> > > +static int rp1_pwm_round_waveform_tohw(struct pwm_chip *chip,
> > > + struct pwm_device *pwm,
> > > + const struct pwm_waveform *wf,
> > > + void *_wfhw)
> > > +{
> > > + struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
> > > + u64 period_ticks, duty_ticks, offset_ticks;
> > > + struct rp1_pwm_waveform *wfhw = _wfhw;
> > > + u64 clk_rate = rp1->clk_rate;
> > > + int ret = 0;
> > > +
> > > + if (!wf->period_length_ns) {
> > > + wfhw->enabled = false;
> > > + wfhw->inverted_polarity = (pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED);
> >
> > pwm_get_polarity(pwm) looks wrong here for several reasons. 1st the
> > polarity is defined in *wf and should not depend on the current state,
> > 2nd for a disabled hardware the polarity doesn't matter anyhow, and 3rd
> > you should not call pwm API functions from the lowlevel driver (which
> > might interfere with subsystem locking).
>
> Ok, but in this case what the output of the disabled channel should be?
> If it was inverted before the disable, would it make sense to let the output
> be high? Or are we allowed to hard code a polarity value on disable?
Given that not all hardwares can drive the output of a disabled PWM to a
fixed level, a consumer that relies on a fixed inactive level output
must not disable the PWM. So it doesn't matter what you do on
wf->period_length_ns == 0, the only objective is to save power.
> > > + if (!wfhw->inverted_polarity) {
> > > + wf->duty_length_ns = DIV_ROUND_UP_ULL((u64)wfhw->duty_ticks * NSEC_PER_SEC,
> > > + (u32)clk_rate);
> > > + } else {
> > > + if (wfhw->duty_ticks > (u64)wfhw->period_ticks + 1) {
> > > + /* 100% duty cycle case */
> > > + ticks = 0;
> > > + } else {
> > > + ticks = (u64)wfhw->period_ticks + 1 - wfhw->duty_ticks;
> > > + }
> > > + wf->duty_length_ns = DIV_ROUND_UP_ULL(ticks * NSEC_PER_SEC, clk_rate);
> > > + wf->duty_offset_ns = wf->period_length_ns - wf->duty_length_ns;
> >
> > The duty_offset_ns calculation is wrong.
> >
> > Consider clk_rate = 3000000, period_ticks = 8, inverted_polarity = true and
> > duty_ticks = 4.
> >
> > Then you have:
> >
> > .period_length_ns = 2666.6666666666666 ns ~> 2667
> > .duty_length_ns = 1333.3333333333333 ns -> 1334
> > .duty_offset_ns = 1333.3333333333333 ns -> 1334
> >
> > but .period_length_ns - .duty_length_ns is 1333.
> >
> > To get this right, you have to calculate
> >
> > wf->duty_offset_ns = DIV_ROUND_UP_ULL((u64)(wfhw->period_ticks + 1 - ticks) * NSEC_PER_SEC, clk_rate);
>
> So it will end up as 'duty_length_ns + duty_offset_ns >
> period_length_ns', which is timing violation. Is it allowed (or even
> required) in the PWM subsystem?
Not all hardwares support that, but logically it makes sense. The active
phase of the output just crosses the period border. With duty_length_ns
+ duty_offset_ns < period_length_ns (and duty_offset > 0) it's the
inactive phase that crosses the period border, and there is no reason
why the active phase should be more special than the inactive one.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [RFC PATCH v1 0/8] Arm Core Local Accelerator Driver
From: Ryan Roberts @ 2026-07-17 13:42 UTC (permalink / raw)
To: Jason Gunthorpe, Will Deacon
Cc: Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Mark Rutland,
Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet, linux-kernel,
linux-arm-kernel, dri-devel, linux-doc, maz, oupton, hch
In-Reply-To: <20260717133200.GB699082@nvidia.com>
On 17/07/2026 14:32, Jason Gunthorpe wrote:
> On Fri, Jul 17, 2026 at 12:33:17PM +0100, Will Deacon wrote:
>
>> first. So, at the moment, this just looks like a burden to me, especially
>> as it appears to create a brand new, device-specific UAPI for what is
>> ostensibly a form of SVA - something which the community is actively
>> working on already.
>
> Yeah, I think it was a mistake to hardwire the invalidation to the
> CPU. It would fit much better into Linux if the invalidation was
> separate and independently controllable with an option to follow the
> CPU.
Well I'm certainly not going to disagree, but the HW is somewhat fixed at this
point :-|
>
> Then you could use a normal S2 page table through iommufd and not mess
> with kvm. (though the VMID sharing with KVM for a BTM-like scheme was
> never solved upstream)
>
> I also wouldn't expect you to use vfio-mdev, if the devices are
> discovered and known at boot then it should be a normal vfio driver.
OK good feedback - I'm not going to claim to be a VFIO expert (especially not in
front of an actual VFIO expert) - We'll look closer at this and come back if we
have questions (although unlikely over the summer holiday).
Thanks,
Ryan
>
> Jason
^ permalink raw reply
* Re: [RFC PATCH v1 0/8] Arm Core Local Accelerator Driver
From: Jason Gunthorpe @ 2026-07-17 13:32 UTC (permalink / raw)
To: Will Deacon
Cc: Ryan Roberts, Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas,
Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet,
linux-kernel, linux-arm-kernel, dri-devel, linux-doc, maz, oupton,
hch
In-Reply-To: <aloS_T3LQvpHeZUV@willie-the-truck>
On Fri, Jul 17, 2026 at 12:33:17PM +0100, Will Deacon wrote:
> first. So, at the moment, this just looks like a burden to me, especially
> as it appears to create a brand new, device-specific UAPI for what is
> ostensibly a form of SVA - something which the community is actively
> working on already.
Yeah, I think it was a mistake to hardwire the invalidation to the
CPU. It would fit much better into Linux if the invalidation was
separate and independently controllable with an option to follow the
CPU.
Then you could use a normal S2 page table through iommufd and not mess
with kvm. (though the VMID sharing with KVM for a BTM-like scheme was
never solved upstream)
I also wouldn't expect you to use vfio-mdev, if the devices are
discovered and known at boot then it should be a normal vfio driver.
Jason
^ permalink raw reply
* Re: [PATCH 1/3] regulator: core: use system_freezable_wq for init complete work
From: Mark Brown @ 2026-07-17 13:30 UTC (permalink / raw)
To: Joy Zou
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Ye Li, Jacky Bai, Peng Fan, Dong Aisheng, linux-kernel,
devicetree, imx, linux-arm-kernel
In-Reply-To: <20260716-b4-regulator-pf01-v1-1-8c1519d54bd4@oss.nxp.com>
[-- Attachment #1: Type: text/plain, Size: 987 bytes --]
On Thu, Jul 16, 2026 at 11:50:53AM +0800, Joy Zou wrote:
> schedule_delayed_work() uses system_wq, which is non-freezable, allowing
> regulator_init_complete_work to run concurrently with system suspend. This
> work fires ~30s after boot to disable unused regulators via I2C. When it
> races with PM suspend, the I2C adapter may already be suspended, triggering
> a -ESHUTDOWN warning dump.
> [ 33.707233] pc : __i2c_transfer+0x36c/0x3c8
> [ 33.707240] lr : __i2c_transfer+0x36c/0x3c8
> [ 33.707246] sp : ffff80008239ba50
> [ 33.707249] x29: ffff80008239ba50 x28: 0000000000000001 x27: 0000000000000000
Please think hard before including complete backtraces in upstream
reports, they are very large and contain almost no useful information
relative to their size so often obscure the relevant content in your
message. If part of the backtrace is usefully illustrative (it often is
for search engines if nothing else) then it's usually better to pull out
the relevant sections.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 2/3] regulator: pfuze100: add set_suspend_disable for LDO ops
From: Mark Brown @ 2026-07-17 13:22 UTC (permalink / raw)
To: Joy Zou
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Ye Li, Jacky Bai, Peng Fan, Dong Aisheng, linux-kernel,
devicetree, imx, linux-arm-kernel
In-Reply-To: <20260716-b4-regulator-pf01-v1-2-8c1519d54bd4@oss.nxp.com>
[-- Attachment #1: Type: text/plain, Size: 1200 bytes --]
On Thu, Jul 16, 2026 at 11:50:54AM +0800, Joy Zou wrote:
> Add set_suspend_disable callback to pfuze100_ldo_regulator_ops to
> support regulator-off-in-suspend DTS property for VGEN regulators.
> This allows unused LDO regulators to be properly disabled during
> system suspend, reducing power consumption.
> +static int pfuze100_set_suspend_disable(struct regulator_dev *rdev)
This looks to be only used for LDOs but is named like it applies to all
regulators the driver supports.
> +{
> + struct pfuze_chip *pfuze100 = rdev_get_drvdata(rdev);
> + int id = rdev_get_id(rdev);
> +
> + /*
> + * Set VGENxSTBY and clear VGENxLPWR so that the LDO output is
> + * disabled when the PMIC receives a STANDBY event.
> + * EN=1, LPWR=0, STBY=1 results in output Off when STANDBY is asserted.
> + */
> + return regmap_update_bits(pfuze100->regmap,
> + pfuze100->regulator_descs[id].stby_reg,
> + PFUZE100_VGENxSTBY | PFUZE100_VGENxLPWR,
> + PFUZE100_VGENxSTBY);
> +}
This is a fixed bit in the register, but I see other regulators have
_stby_mask configuration. Are you sure that all the LDOs in all the
regulators covered by this driver have this feature with this exact
control bit?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 17/18] arm64: fpsimd: Move SME save/restore inline
From: Mark Rutland @ 2026-07-17 13:22 UTC (permalink / raw)
To: Vladimir Murzin
Cc: linux-arm-kernel, kvmarm, broonie, catalin.marinas, james.morse,
maz, oupton, tabba, will
In-Reply-To: <ahlYC2qgqzNQxggP@J2N7QTR9R3>
On Fri, May 29, 2026 at 10:10:35AM +0100, Mark Rutland wrote:
> On Tue, May 26, 2026 at 05:38:40PM +0100, Mark Rutland wrote:
> > On Tue, May 26, 2026 at 04:28:17PM +0100, Mark Rutland wrote:
> > > On Tue, May 26, 2026 at 03:39:56PM +0100, Vladimir Murzin wrote:
> > > > I suspect you are intentionally not using "Ucj" constrain to limit register allocator,
> > > > if so I'm wondering why?
> > >
> > > Thanks for the suggestion; that was ignorance rather than intent.
> > >
> > > I was not aware of "Ucj" as it doesn't appear on the public GCC
> > > documentation:
> > >
> > > https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
> > >
> > > Looking at the machine description file, that's marked with '@internal',
> > > so IIUC GCC folk don't seem to expect/want people to use it. That said,
> > > LLVM seems to support it.
> > >
> > > I'll go check that all relevant toolchains support this, and poke GCC
> > > folk to see if they're happy to promote that to a public constraint.
> >
> > GCC folk seem happy to make this public, which is great! I'll cross-link
> > a thread here if/when patches appear.
>
> Alex Coplan sent a patch for GCC to make this public:
>
> https://gcc.gnu.org/pipermail/gcc-patches/2026-May/718560.html
Just for posterity, that was merged in GCC commit:
090f3e78a10b5ce14fd80de82d3e8dda8af1cae6 ("aarch64: Make Uc[ij] constraints public")
... which can be found at:
https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=090f3e78a10b5ce14fd80de82d3e8dda8af1cae6
... so we should be able to use that in future once our minimum
supported toolchains are GCC 14.1.0+ and and LLVM 18.1.0+.
Mark.
^ permalink raw reply
* Re: [PATCH] mtd: rawnand: sunxi: add H616 MBUS DMA support
From: Miquel Raynal @ 2026-07-17 13:09 UTC (permalink / raw)
To: James Hilliard
Cc: linux-mtd, linux-sunxi, Richard Weinberger, Vignesh Raghavendra,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Richard Genoud,
Geert Uytterhoeven, linux-arm-kernel, linux-kernel
In-Reply-To: <20260715162444.789303-1-james.hilliard1@gmail.com>
Hi James,
On 15/07/2026 at 10:24:40 -06, James Hilliard <james.hilliard1@gmail.com> wrote:
> The H616 NAND controller uses a descriptor-based internal MBUS DMA
> engine instead of the direct address and count registers used by the
> A23/A33 controller. Since the driver does not support these descriptors,
> it currently attempts to request an external rxtx DMA channel and falls
> back to PIO when none is provided.
>
> Add a single-descriptor backend to the existing ECC page DMA paths.
> Allocate the descriptor coherently, constrain data mappings to the
> controller's 32-bit address range, program the H6-style data block mask,
> and request an interrupt for both command and DMA completion. Keep the
> existing external DMA and legacy MBUS DMA paths unchanged, and fall back
> to PIO if the descriptor cannot be allocated.
>
> Hardware testing on an H616 board with 2 KiB-page SLC NAND
> confirmed that the descriptor path improves sustained read throughput.
I would be nice to show the output of a flash_speed -dc100 /dev/mtdX
before and after.
> Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
> ---
> drivers/mtd/nand/raw/sunxi_nand.c | 110 ++++++++++++++++++++++++++----
> 1 file changed, 95 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c
> index 02647565c8ba..8a136b9fa7cc 100644
> --- a/drivers/mtd/nand/raw/sunxi_nand.c
> +++ b/drivers/mtd/nand/raw/sunxi_nand.c
> @@ -79,6 +79,10 @@
> #define NFC_REG_H6_MDMA_BUF_ADDR 0x0210
> #define NFC_REG_H6_MDMA_CNT 0x0214
>
> +#define NFC_MDMA_DESC_LAST BIT(2)
> +#define NFC_MDMA_DESC_FIRST BIT(3)
> +#define NFC_MDMA_DESC_SIZE_MASK GENMASK(15, 0)
> +
> #define NFC_RAM0_BASE 0x0400
> #define NFC_RAM1_BASE 0x0800
>
> @@ -267,12 +271,19 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
> return container_of(nand, struct sunxi_nand_chip, nand);
> }
>
> +struct sunxi_nfc_mdma_desc {
> + __le32 config;
> + __le32 size;
> + __le32 buf;
> + __le32 next;
> +};
Shouldn't this be declared __packed and possibly even __aligned?
> /*
> * NAND Controller capabilities structure: stores NAND controller capabilities
> * for distinction between compatible strings.
> *
> - * @has_mdma: Use mbus dma mode, otherwise general dma
> - * through MBUS on A23/A33 needs extra configuration.
> + * @has_mdma: Use A23/A33-style MBUS DMA registers
> + * @has_mdma_desc: MBUS DMA uses H6-style descriptors
> * @has_ecc_block_512: If the ECC can handle 512B or only 1024B chunks
> * @has_ecc_clk: If the controller needs an ECC clock.
> * @has_mbus_clk: If the controller needs a mbus clock.
> @@ -304,6 +315,7 @@ static inline struct sunxi_nand_chip *to_sunxi_nand(struct nand_chip *nand)
> */
> struct sunxi_nfc_caps {
> bool has_mdma;
> + bool has_mdma_desc;
> bool has_ecc_block_512;
> bool has_ecc_clk;
> bool has_mbus_clk;
> @@ -346,6 +358,8 @@ struct sunxi_nfc_caps {
> * controller
> * @complete: a completion object used to wait for NAND controller events
> * @dmac: the DMA channel attached to the NAND controller
> + * @mdma_desc: H6-style MBUS DMA descriptor
> + * @mdma_desc_dma: DMA address of @mdma_desc
> * @caps: NAND Controller capabilities
> */
> struct sunxi_nfc {
> @@ -362,6 +376,8 @@ struct sunxi_nfc {
> struct list_head chips;
> struct completion complete;
> struct dma_chan *dmac;
> + struct sunxi_nfc_mdma_desc *mdma_desc;
> + dma_addr_t mdma_desc_dma;
> const struct sunxi_nfc_caps *caps;
> };
>
> @@ -370,6 +386,11 @@ static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_controller *ctrl)
> return container_of(ctrl, struct sunxi_nfc, controller);
> }
>
> +static bool sunxi_nfc_uses_mdma(const struct sunxi_nfc *nfc)
may I suggest sunxi_nfc_use_mdma?
> +{
> + return nfc->caps->has_mdma || nfc->mdma_desc;
I don't get the || there? What are you trying to check exactly?
> +}
> +
> static irqreturn_t sunxi_nfc_interrupt(int irq, void *dev_id)
> {
> struct sunxi_nfc *nfc = dev_id;
> @@ -466,7 +487,9 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
> {
> struct dma_async_tx_descriptor *dmad;
> enum dma_transfer_direction tdir;
> + dma_addr_t buf_dma;
> dma_cookie_t dmat;
> + int len = chunksize * nchunks;
> int ret;
>
> if (ddir == DMA_FROM_DEVICE)
> @@ -474,12 +497,21 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
> else
> tdir = DMA_MEM_TO_DEV;
>
> - sg_init_one(sg, buf, nchunks * chunksize);
> + sg_init_one(sg, buf, len);
> ret = dma_map_sg(nfc->dev, sg, 1, ddir);
> if (!ret)
> return -ENOMEM;
>
> - if (!nfc->caps->has_mdma) {
> + buf_dma = sg_dma_address(sg);
> +
> + if (nfc->mdma_desc &&
> + (len > NFC_MDMA_DESC_SIZE_MASK || !IS_ALIGNED(len, 8) ||
> + !IS_ALIGNED(buf_dma, 4) || upper_32_bits(buf_dma))) {
> + ret = -EINVAL;
> + goto err_unmap_buf;
> + }
> +
> + if (!sunxi_nfc_uses_mdma(nfc)) {
> dmad = dmaengine_prep_slave_sg(nfc->dmac, sg, 1, tdir, DMA_CTRL_ACK);
> if (!dmad) {
> ret = -EINVAL;
> @@ -489,14 +521,30 @@ static int sunxi_nfc_dma_op_prepare(struct sunxi_nfc *nfc, const void *buf,
>
> writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
> nfc->regs + NFC_REG_CTL);
> - writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
> + writel(nfc->mdma_desc ? GENMASK(nchunks - 1, 0) : nchunks,
Very unclear, can this be simplified or at least explained?
> + nfc->regs + NFC_REG_SECTOR_NUM);
> writel(chunksize, nfc->regs + NFC_REG_CNT);
>
> - if (nfc->caps->has_mdma) {
> + if (sunxi_nfc_uses_mdma(nfc))
> writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_DMA_TYPE_NORMAL,
> nfc->regs + NFC_REG_CTL);
> - writel(chunksize * nchunks, nfc->regs + NFC_REG_MDMA_CNT);
> - writel(sg_dma_address(sg), nfc->regs + NFC_REG_MDMA_ADDR);
> +
> + if (nfc->mdma_desc) {
> + struct sunxi_nfc_mdma_desc *desc = nfc->mdma_desc;
> +
> + desc->config = cpu_to_le32(NFC_MDMA_DESC_FIRST |
> + NFC_MDMA_DESC_LAST);
> + desc->size = cpu_to_le32(len);
> + desc->buf = cpu_to_le32(lower_32_bits(buf_dma));
Does lower_32_bits() mean anything here since you already check for the
upper bits before? This check may even be redundant given the fact that
the addressing capability has already been set to 32 bits, so the
dma_map* call would catch this anyway.
> + desc->next = cpu_to_le32(lower_32_bits(nfc->mdma_desc_dma));
Ditto
Plus, the endianness of the controller is little endian, so writel
already does the endianness conversion if need be. cpu_to_le32() here
seems irrelevant.
> +
> + writel(BIT(0), nfc->regs + NFC_REG_H6_MDMA_STA);
BIT(0) should be #define'd
> + dma_wmb();
> + writel(lower_32_bits(nfc->mdma_desc_dma),
> + nfc->regs + NFC_REG_H6_MDMA_DLBA_REG);
> + } else if (nfc->caps->has_mdma) {
> + writel(len, nfc->regs + NFC_REG_MDMA_CNT);
> + writel(buf_dma, nfc->regs + NFC_REG_MDMA_ADDR);
> } else {
> dmat = dmaengine_submit(dmad);
>
> @@ -525,6 +573,14 @@ static void sunxi_nfc_dma_op_cleanup(struct sunxi_nfc *nfc,
> nfc->regs + NFC_REG_CTL);
> }
>
> +static void sunxi_nfc_dma_op_abort(struct sunxi_nfc *nfc)
> +{
> + if (nfc->mdma_desc)
I would prefer to stick to the same condition all the time whether we
are using peripheral dma (MDMA) or not.
> + sunxi_nfc_rst(nfc);
> + else if (!nfc->caps->has_mdma)
Shouldn't this be a "else" here?
> + dmaengine_terminate_all(nfc->dmac);
> +}
> +
> static void sunxi_nfc_select_chip(struct nand_chip *nand, unsigned int cs)
> {
> struct mtd_info *mtd = nand_to_mtd(nand);
> @@ -1202,7 +1258,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct nand_chip *nand, uint8_t *buf
>
> wait = NFC_CMD_INT_FLAG;
>
> - if (nfc->caps->has_mdma)
> + if (sunxi_nfc_uses_mdma(nfc))
> wait |= NFC_DMA_INT_FLAG;
> else
> dma_async_issue_pending(nfc->dmac);
Thanks,
Miquèl
^ permalink raw reply
* [RFC PATCH 2/2] KVM: arm64: Support BBM level 3
From: Mostafa Saleh @ 2026-07-17 13:09 UTC (permalink / raw)
To: linux-kernel, kvmarm, linux-arm-kernel
Cc: maz, oupton, seiden, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will, vdonnefort, tabba, Mostafa Saleh
In-Reply-To: <20260717130901.2239134-1-smostafa@google.com>
If the system supports hardware Break-Before-Make (BBM) level 3, use it
to replace stage-2 PTEs directly instead of falling back to the software
break-before-make sequence.
1) Get a reference count on the containing table for the new PTE.
2) Atomically update the PTE with the new valid descriptor.
3) Invalidate the TLB for the old PTE.
4) Drop the reference count holding the old PTE.
One interesting case, as BBML3 will update the PTE atomically, it
can only know it raced with another core at the point of the cmpxchg
failing, unlike the SW implementation which locks the PTE first.
And as we must issue CMOs to the new mapped page before the update,
that means with BBML3 racing cores will issue redundant CMOs,
to improve this:
- We only use BBML3 if the old PTE was live.
- To reduce the window of the race, an early check is added before
the CMO to exit early, but that does not eliminate the race.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
arch/arm64/kvm/hyp/pgtable.c | 53 +++++++++++++++++++++++++++++++-----
1 file changed, 46 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 127b7f9541b1..69d52308236f 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -838,7 +838,8 @@ static void stage2_clean_old_pte(const struct kvm_pgtable_visit_ctx *ctx,
/**
* stage2_try_break_pte() - Invalidates a pte according to the
* 'break-before-make' requirements of the
- * architecture.
+ * architecture, if BMML3 is supported it
+ * will be used, otherwise fallback to SW.
*
* @ctx: context of the visited pte.
* @mmu: stage-2 mmu
@@ -854,6 +855,18 @@ static bool stage2_try_break_pte(const struct kvm_pgtable_visit_ctx *ctx,
{
kvm_pte_t locked_pte;
+ if (system_supports_bbml3() && kvm_pte_valid(ctx->old)) {
+ kvm_pte_t curr_pte = READ_ONCE(*ctx->ptep);
+
+ /*
+ * All handled in stage2_make_pte(). However exit early if we already
+ * lost the race to avoid extra CMOs.
+ */
+ if (curr_pte != ctx->old)
+ return false;
+ return true;
+ }
+
if (stage2_pte_is_locked(ctx->old)) {
/*
* Should never occur if this walker has exclusive access to the
@@ -873,16 +886,35 @@ static bool stage2_try_break_pte(const struct kvm_pgtable_visit_ctx *ctx,
return true;
}
-static void stage2_make_pte(const struct kvm_pgtable_visit_ctx *ctx, kvm_pte_t new)
+/* Must be paired with stage2_try_break_pte() */
+static bool stage2_make_pte(const struct kvm_pgtable_visit_ctx *ctx, struct kvm_s2_mmu *mmu,
+ kvm_pte_t new)
{
struct kvm_pgtable_mm_ops *mm_ops = ctx->mm_ops;
- WARN_ON(!stage2_pte_is_locked(*ctx->ptep));
-
if (stage2_pte_is_counted(new))
mm_ops->get_page(ctx->ptep);
+ if (system_supports_bbml3() && kvm_pte_valid(ctx->old)) {
+ /*
+ * Barrier is required because stage2_try_set_pte() uses
+ * WRITE_ONCE for non-shared walks, lacking release semantics
+ * used in the software BBM case.
+ */
+ smp_wmb();
+ if (!stage2_try_set_pte(ctx, new)) {
+ if (stage2_pte_is_counted(new))
+ mm_ops->put_page(ctx->ptep);
+ return false;
+ }
+
+ stage2_clean_old_pte(ctx, mmu);
+ return true;
+ }
+
+ WARN_ON(!stage2_pte_is_locked(*ctx->ptep));
smp_store_release(ctx->ptep, new);
+ return true;
}
static bool stage2_unmap_defer_tlb_flush(struct kvm_pgtable *pgt)
@@ -1014,7 +1046,8 @@ static int stage2_map_walker_try_leaf(const struct kvm_pgtable_visit_ctx *ctx,
stage2_pte_executable(new))
mm_ops->icache_inval_pou(kvm_pte_follow(new, mm_ops), granule);
- stage2_make_pte(ctx, new);
+ if (!stage2_make_pte(ctx, data->mmu, new))
+ return -EAGAIN;
return 0;
}
@@ -1069,7 +1102,10 @@ static int stage2_map_walk_leaf(const struct kvm_pgtable_visit_ctx *ctx,
* will be mapped lazily.
*/
new = kvm_init_table_pte(childp, mm_ops);
- stage2_make_pte(ctx, new);
+ if (!stage2_make_pte(ctx, data->mmu, new)) {
+ mm_ops->put_page(childp);
+ return -EAGAIN;
+ }
return 0;
}
@@ -1557,7 +1593,10 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx,
* writes the PTE using smp_store_release().
*/
new = kvm_init_table_pte(childp, mm_ops);
- stage2_make_pte(ctx, new);
+ if (!stage2_make_pte(ctx, mmu, new)) {
+ kvm_pgtable_stage2_free_unlinked(mm_ops, childp, level);
+ return -EAGAIN;
+ }
return 0;
}
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox