* [PATCH v3 3/3] ARM/arm64: defconfig: Drop redundant Qualcomm interconnect entries
From: Krzysztof Kozlowski @ 2026-07-20 19:03 UTC (permalink / raw)
To: Georgi Djakov, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-pm, linux-kernel, linux-arm-kernel,
Krzysztof Kozlowski
In-Reply-To: <20260720-interconnect-qcom-clean-arm64-v3-0-942e8ee7ebda@oss.qualcomm.com>
Drop all drivers from defconfig which have defaults in Kconfig.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
arch/arm/configs/qcom_defconfig | 3 ---
arch/arm64/configs/defconfig | 31 -------------------------------
2 files changed, 34 deletions(-)
diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index df0a0ce5b097..630e31c036a9 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -272,9 +272,6 @@ CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y
CONFIG_PHY_QCOM_USB_HSIC=y
CONFIG_NVMEM_QCOM_QFPROM=y
CONFIG_INTERCONNECT=y
-CONFIG_INTERCONNECT_QCOM=y
-CONFIG_INTERCONNECT_QCOM_MSM8974=m
-CONFIG_INTERCONNECT_QCOM_SDX55=m
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT4_FS=y
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 91a3b2cd10b3..b11040fa9cfd 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1863,37 +1863,6 @@ CONFIG_INTERCONNECT_IMX8MM=m
CONFIG_INTERCONNECT_IMX8MN=m
CONFIG_INTERCONNECT_IMX8MQ=m
CONFIG_INTERCONNECT_IMX8MP=y
-CONFIG_INTERCONNECT_QCOM=y
-CONFIG_INTERCONNECT_QCOM_ELIZA=y
-CONFIG_INTERCONNECT_QCOM_GLYMUR=y
-CONFIG_INTERCONNECT_QCOM_KAANAPALI=y
-CONFIG_INTERCONNECT_QCOM_MSM8916=m
-CONFIG_INTERCONNECT_QCOM_MSM8953=y
-CONFIG_INTERCONNECT_QCOM_MSM8996=y
-CONFIG_INTERCONNECT_QCOM_OSM_L3=m
-CONFIG_INTERCONNECT_QCOM_QCM2290=y
-CONFIG_INTERCONNECT_QCOM_QCS404=m
-CONFIG_INTERCONNECT_QCOM_QCS615=y
-CONFIG_INTERCONNECT_QCOM_QCS8300=y
-CONFIG_INTERCONNECT_QCOM_QDU1000=y
-CONFIG_INTERCONNECT_QCOM_SA8775P=y
-CONFIG_INTERCONNECT_QCOM_SC7180=y
-CONFIG_INTERCONNECT_QCOM_SC7280=y
-CONFIG_INTERCONNECT_QCOM_SC8180X=y
-CONFIG_INTERCONNECT_QCOM_SC8280XP=y
-CONFIG_INTERCONNECT_QCOM_SDM845=y
-CONFIG_INTERCONNECT_QCOM_SDX75=y
-CONFIG_INTERCONNECT_QCOM_SM6115=y
-CONFIG_INTERCONNECT_QCOM_SM6350=y
-CONFIG_INTERCONNECT_QCOM_MILOS=y
-CONFIG_INTERCONNECT_QCOM_SM8150=y
-CONFIG_INTERCONNECT_QCOM_SM8250=y
-CONFIG_INTERCONNECT_QCOM_SM8350=y
-CONFIG_INTERCONNECT_QCOM_SM8450=y
-CONFIG_INTERCONNECT_QCOM_SM8550=y
-CONFIG_INTERCONNECT_QCOM_SM8650=y
-CONFIG_INTERCONNECT_QCOM_SM8750=y
-CONFIG_INTERCONNECT_QCOM_X1E80100=y
CONFIG_COUNTER=m
CONFIG_RZ_MTU3_CNT=m
CONFIG_STM32_TIMER_CNT=m
--
2.53.0
^ permalink raw reply related
* [PATCH v3 2/3] interconnect: qcom: Add missing depends to Hawi, Maili, Nord and Shikra
From: Krzysztof Kozlowski @ 2026-07-20 19:03 UTC (permalink / raw)
To: Georgi Djakov, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-pm, linux-kernel, linux-arm-kernel,
Krzysztof Kozlowski
In-Reply-To: <20260720-interconnect-qcom-clean-arm64-v3-0-942e8ee7ebda@oss.qualcomm.com>
Hawi, Maili, Nord and Shikra were added in parallel or after
commit 5b696f065843 ("interconnect: qcom: Restrict drivers per
ARM/ARM64"), thus they missed the update restricting them per
architecture (with the same rationale).
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/interconnect/qcom/Kconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index dd8774d84321..6bc2038de28a 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -34,6 +34,7 @@ config INTERCONNECT_QCOM_GLYMUR
config INTERCONNECT_QCOM_HAWI
tristate "Qualcomm HAWI interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
default ARCH_QCOM
@@ -55,6 +56,7 @@ config INTERCONNECT_QCOM_KAANAPALI
config INTERCONNECT_QCOM_MAILI
tristate "Qualcomm MAILI interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
default ARCH_QCOM
@@ -146,6 +148,7 @@ config INTERCONNECT_QCOM_MSM8996
config INTERCONNECT_QCOM_NORD
tristate "Qualcomm Nord interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
+ depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
default ARCH_QCOM
@@ -370,6 +373,7 @@ config INTERCONNECT_QCOM_SHIKRA
tristate "Qualcomm SHIKRA interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
+ depends on ARM64 || COMPILE_TEST
default ARCH_QCOM
select INTERCONNECT_QCOM_SMD_RPM
help
--
2.53.0
^ permalink raw reply related
* [PATCH v3 1/3] interconnect: qcom: Make important drivers default
From: Krzysztof Kozlowski @ 2026-07-20 19:03 UTC (permalink / raw)
To: Georgi Djakov, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-pm, linux-kernel, linux-arm-kernel,
Krzysztof Kozlowski
In-Reply-To: <20260720-interconnect-qcom-clean-arm64-v3-0-942e8ee7ebda@oss.qualcomm.com>
The interconnect drivers for Qualcomm SoC Network-on-Chip are covering a
basic or fundamental SoC feature: bandwidth management between internal
SoC blocks. SoC can boot without these, but power management or
performance will be affected. These drivers do not represent any sort
of buses visible to the board designers/configurators, thus they should
be always enabled, regardless how SoC is used in the final board.
Kernel configuration should not ask users choice of drivers when that
choice is obvious and known to the developers that answer should be
'yes' or 'module'.
Switch all almost Qualcomm interconnect drivers to a default 'yes' for
ARCH_QCOM. This has impact:
1. arm64 defconfig:
a. Enable as built-in INTERCONNECT_QCOM_HAWI, INTERCONNECT_QCOM_NORD,
INTERCONNECT_QCOM_SDM660, INTERCONNECT_QCOM_SDM670,
INTERCONNECT_QCOM_SM7150 and INTERCONNECT_QCOM_SAR2130P, which
were not selected before but should be, because these platforms
need them anyway for proper functioning.
b. Switch to built-in from a module INTERCONNECT_QCOM_QCS404 and
INTERCONNECT_QCOM_MSM8916, which as modules would not make the
platform bootable in most cases, and INTERCONNECT_QCOM_OSM_L3,
which when module might slow down boot considerably by having
caches running at slow speed.
2. arm qcom_defconfig: Switch to built-in from a module
INTERCONNECT_QCOM_RPMH, INTERCONNECT_QCOM_SMD_RPM,
INTERCONNECT_QCOM_BCM_VOTER, INTERCONNECT_QCOM_MSM8974,
INTERCONNECT_QCOM_SDX55, which as modules would not make the
platform bootable in most cases.
3. arm multi_v7 defconfig: Enable drivers necessary to boot
ARM 32-bit platforms, which are already enabled on qcom_defconfig:
a. Enable as built-in INTERCONNECT_QCOM_MSM8974.
b. Enable as modules (other dependencies prevent from built-in)
INTERCONNECT_QCOM_RPMH, INTERCONNECT_QCOM_BCM_VOTER and
INTERCONNECT_QCOM_SDX55.
4. COMPILE_TEST builds: Enable by default all drivers for arm or arm64
builds, whenever ARCH_QCOM is selected. This has impact on build
time and feels logical, because if one selects ARCH_QCOM then
probably by default wants to build test it entirely. Kernels with
COMPILE_TEST are not supposed to be used for booting.
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
drivers/interconnect/qcom/Kconfig | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
index e4806bd7929c..dd8774d84321 100644
--- a/drivers/interconnect/qcom/Kconfig
+++ b/drivers/interconnect/qcom/Kconfig
@@ -2,6 +2,7 @@
config INTERCONNECT_QCOM
tristate "Qualcomm Network-on-Chip interconnect drivers"
depends on ARCH_QCOM
+ default ARCH_QCOM
help
Support for Qualcomm's Network-on-Chip interconnect hardware.
@@ -14,6 +15,7 @@ config INTERCONNECT_QCOM_ELIZA
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on Eliza-based
platforms.
@@ -24,6 +26,7 @@ config INTERCONNECT_QCOM_GLYMUR
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on glymur-based
platforms.
@@ -33,6 +36,7 @@ config INTERCONNECT_QCOM_HAWI
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on hawi-based
platforms.
@@ -43,6 +47,7 @@ config INTERCONNECT_QCOM_KAANAPALI
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on kaanapali-based
platforms.
@@ -72,6 +77,7 @@ config INTERCONNECT_QCOM_MSM8916
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM if ARM64
help
This is a driver for the Qualcomm Network-on-Chip on msm8916-based
platforms.
@@ -100,6 +106,7 @@ config INTERCONNECT_QCOM_MSM8953
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on msm8953-based
platforms.
@@ -110,6 +117,7 @@ config INTERCONNECT_QCOM_MSM8974
depends on QCOM_SMD_RPM
depends on ARM || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on msm8974-based
platforms.
@@ -130,6 +138,7 @@ config INTERCONNECT_QCOM_MSM8996
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on msm8996-based
platforms.
@@ -139,6 +148,7 @@ config INTERCONNECT_QCOM_NORD
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on Nord-based
platforms. The topology consists of several NoCs controlled by
@@ -149,6 +159,7 @@ config INTERCONNECT_QCOM_OSM_L3
tristate "Qualcomm OSM L3 interconnect driver"
depends on INTERCONNECT_QCOM || COMPILE_TEST
depends on ARM64 || COMPILE_TEST
+ default ARCH_QCOM
help
Say y here to support the Operating State Manager (OSM) interconnect
driver which controls the scaling of L3 caches on Qualcomm SoCs.
@@ -159,6 +170,7 @@ config INTERCONNECT_QCOM_QCM2290
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on qcm2290-based
platforms.
@@ -169,6 +181,7 @@ config INTERCONNECT_QCOM_QCS404
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on qcs404-based
platforms.
@@ -179,6 +192,7 @@ config INTERCONNECT_QCOM_QCS615
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on qcs615-based
platforms.
@@ -189,6 +203,7 @@ config INTERCONNECT_QCOM_QCS8300
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on QCS8300-based platforms. The interconnect provider collects and
@@ -201,6 +216,7 @@ config INTERCONNECT_QCOM_QDU1000
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on QDU1000-based
and QRU1000-based platforms.
@@ -225,6 +241,7 @@ config INTERCONNECT_QCOM_SA8775P
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sa8775p-based
platforms.
@@ -235,6 +252,7 @@ config INTERCONNECT_QCOM_SAR2130P
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on SAR2130P-based
platforms.
@@ -245,6 +263,7 @@ config INTERCONNECT_QCOM_SC7180
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sc7180-based
platforms.
@@ -255,6 +274,7 @@ config INTERCONNECT_QCOM_SC7280
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sc7280-based
platforms.
@@ -265,6 +285,7 @@ config INTERCONNECT_QCOM_SC8180X
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sc8180x-based
platforms.
@@ -275,6 +296,7 @@ config INTERCONNECT_QCOM_SC8280XP
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on SC8280XP-based
platforms.
@@ -285,6 +307,7 @@ config INTERCONNECT_QCOM_SDM660
depends on ARM64 || COMPILE_TEST
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sdm660-based
platforms.
@@ -295,6 +318,7 @@ config INTERCONNECT_QCOM_SDM670
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sdm670-based
platforms.
@@ -305,6 +329,7 @@ config INTERCONNECT_QCOM_SDM845
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sdm845-based
platforms.
@@ -315,6 +340,7 @@ config INTERCONNECT_QCOM_SDX55
depends on ARM || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sdx55-based
platforms.
@@ -335,6 +361,7 @@ config INTERCONNECT_QCOM_SDX75
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sdx75-based
platforms.
@@ -355,6 +382,7 @@ config INTERCONNECT_QCOM_SM6115
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sm6115-based
platforms.
@@ -365,6 +393,7 @@ config INTERCONNECT_QCOM_SM6350
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sm6350-based
platforms.
@@ -375,6 +404,7 @@ config INTERCONNECT_QCOM_SM7150
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sm7150-based
platforms.
@@ -385,6 +415,7 @@ config INTERCONNECT_QCOM_MILOS
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on Milos-based
platforms.
@@ -395,6 +426,7 @@ config INTERCONNECT_QCOM_SM8150
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sm8150-based
platforms.
@@ -405,6 +437,7 @@ config INTERCONNECT_QCOM_SM8250
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on sm8250-based
platforms.
@@ -415,6 +448,7 @@ config INTERCONNECT_QCOM_SM8350
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on SM8350-based
platforms.
@@ -425,6 +459,7 @@ config INTERCONNECT_QCOM_SM8450
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on SM8450-based
platforms.
@@ -435,6 +470,7 @@ config INTERCONNECT_QCOM_SM8550
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on SM8550-based
platforms.
@@ -445,6 +481,7 @@ config INTERCONNECT_QCOM_SM8650
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on SM8650-based
platforms.
@@ -455,6 +492,7 @@ config INTERCONNECT_QCOM_SM8750
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on SM8750-based
platforms.
@@ -465,6 +503,7 @@ config INTERCONNECT_QCOM_X1E80100
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
+ default ARCH_QCOM
help
This is a driver for the Qualcomm Network-on-Chip on X1E80100-based
platforms.
--
2.53.0
^ permalink raw reply related
* [PATCH v3 0/3] interconnect: qcom: Some defconfig/defaults cleanups and improvements
From: Krzysztof Kozlowski @ 2026-07-20 19:03 UTC (permalink / raw)
To: Georgi Djakov, Bjorn Andersson, Konrad Dybcio
Cc: linux-arm-msm, linux-pm, linux-kernel, linux-arm-kernel,
Krzysztof Kozlowski
Merging:
1. First two patches via interconnect tree.
2. Defconfig a release later via qcom soc tree (dependency to avoid
surprises).
Changes in v3:
- Update also Nord and Hawi
- Split defconfig to separate patch #3.
- Add new patch #2 for arm64 dependency for Hawi, Nord, Shikra and Maili.
- Link to v2: https://patch.msgid.link/20260515-interconnect-qcom-clean-arm64-v2-0-adeebc73596d@oss.qualcomm.com
Changes in v2:
- Patch #3: Switch to built-in for everything, with explanation in
commit msg.
- Tags
- Link to v1: https://patch.msgid.link/20260428-interconnect-qcom-clean-arm64-v1-0-e6bc3f7832db@oss.qualcomm.com
Similarly to clocks and pinctrl, interconnects should not be a user
visible choice.
Best regards,
Krzysztof
---
Krzysztof Kozlowski (3):
interconnect: qcom: Make important drivers default
interconnect: qcom: Add missing depends to Hawi, Maili, Nord and Shikra
ARM/arm64: defconfig: Drop redundant Qualcomm interconnect entries
arch/arm/configs/qcom_defconfig | 3 ---
arch/arm64/configs/defconfig | 31 ----------------------------
drivers/interconnect/qcom/Kconfig | 43 +++++++++++++++++++++++++++++++++++++++
3 files changed, 43 insertions(+), 34 deletions(-)
---
base-commit: 96ff9ad7f53e233e69f87f882b331bfddd903469
change-id: 20260428-interconnect-qcom-clean-arm64-aecdaa1e531b
Best regards,
--
Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH] KVM: arm64: Stop the hyp trace clock worker on disable
From: Vincent Donnefort @ 2026-07-20 19:02 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, linux-arm-kernel, kvmarm, will, joey.gouly, seiden,
suzuki.poulose, yuzenghui, linux-kernel, tabba
In-Reply-To: <al5wo9x7oUGzlbTo@google.com>
On Mon, Jul 20, 2026 at 08:01:55PM +0100, Vincent Donnefort wrote:
> On Mon, Jul 20, 2026 at 07:48:50PM +0100, Fuad Tabba wrote:
> > When disabling, hyp_trace_clock_enable() cancels the clock work but then
> > falls through into the enable path, which re-schedules it and marks the
> > clock running again, so the worker never stops. Return once the work is
> > cancelled.
> >
> > Fixes: b22888917fa41 ("KVM: arm64: Sync boot clock with the nVHE/pKVM hyp")
> > Reported-by: Sashiko <sashiko-bot@kernel.org>
> > Closes: https://lore.kernel.org/all/20260720172923.E4F161F000E9@smtp.kernel.org/
> > Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
>
> Done here already https://lore.kernel.org/all/alczBmnItMwq8xj4@google.com/
sorry I meant here:
https://lore.kernel.org/all/20260715105100.3178255-1-vdonnefort@google.com/
>
> > ---
> > arch/arm64/kvm/hyp_trace.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
> > index 2411b4c32932c..27367843fd211 100644
> > --- a/arch/arm64/kvm/hyp_trace.c
> > +++ b/arch/arm64/kvm/hyp_trace.c
> > @@ -116,6 +116,7 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
> > if (!enable) {
> > cancel_delayed_work_sync(&hyp_clock->work);
> > hyp_clock->running = false;
> > + return;
> > }
> >
> > ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap);
> >
> > base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
> > --
> > 2.39.5
> >
^ permalink raw reply
* Re: [PATCH] KVM: arm64: Stop the hyp trace clock worker on disable
From: Vincent Donnefort @ 2026-07-20 19:01 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, linux-arm-kernel, kvmarm, will, joey.gouly, seiden,
suzuki.poulose, yuzenghui, linux-kernel, tabba
In-Reply-To: <20260720184850.1826630-1-fuad.tabba@linux.dev>
On Mon, Jul 20, 2026 at 07:48:50PM +0100, Fuad Tabba wrote:
> When disabling, hyp_trace_clock_enable() cancels the clock work but then
> falls through into the enable path, which re-schedules it and marks the
> clock running again, so the worker never stops. Return once the work is
> cancelled.
>
> Fixes: b22888917fa41 ("KVM: arm64: Sync boot clock with the nVHE/pKVM hyp")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260720172923.E4F161F000E9@smtp.kernel.org/
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
Done here already https://lore.kernel.org/all/alczBmnItMwq8xj4@google.com/
> ---
> arch/arm64/kvm/hyp_trace.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
> index 2411b4c32932c..27367843fd211 100644
> --- a/arch/arm64/kvm/hyp_trace.c
> +++ b/arch/arm64/kvm/hyp_trace.c
> @@ -116,6 +116,7 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
> if (!enable) {
> cancel_delayed_work_sync(&hyp_clock->work);
> hyp_clock->running = false;
> + return;
> }
>
> ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap);
>
> base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
> --
> 2.39.5
>
^ permalink raw reply
* [PATCH] KVM: arm64: Stop the hyp trace clock worker on disable
From: Fuad Tabba @ 2026-07-20 18:48 UTC (permalink / raw)
To: maz, oupton, linux-arm-kernel, kvmarm
Cc: vdonnefort, will, joey.gouly, seiden, suzuki.poulose, yuzenghui,
linux-kernel, tabba
When disabling, hyp_trace_clock_enable() cancels the clock work but then
falls through into the enable path, which re-schedules it and marks the
clock running again, so the worker never stops. Return once the work is
cancelled.
Fixes: b22888917fa41 ("KVM: arm64: Sync boot clock with the nVHE/pKVM hyp")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260720172923.E4F161F000E9@smtp.kernel.org/
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/hyp_trace.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 2411b4c32932c..27367843fd211 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -116,6 +116,7 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
if (!enable) {
cancel_delayed_work_sync(&hyp_clock->work);
hyp_clock->running = false;
+ return;
}
ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap);
base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
--
2.39.5
^ permalink raw reply related
* Re: [PATCH v5 0/4] Some Minor fixes and cleanups to irqchip/gic-v3-its
From: Thomas Gleixner @ 2026-07-20 18:46 UTC (permalink / raw)
To: Kemeng Shi, maz, jason, lpieralisi, radu
Cc: linux-arm-kernel, linux-kernel, Kemeng Shi
In-Reply-To: <20260720071215.50705-1-shikemeng@huaweicloud.com>
On Mon, Jul 20 2026 at 15:12, Kemeng Shi wrote:
>
> Kemeng Shi (4):
> irqchip/gic-v3-its: Fix memleak in its_probe_one()
> irqchip/gic-v3-its: Fix its node leak in gic_acpi_parse_madt_its()
Why are you resending already merged patches? You got an email
notification about it, no?
^ permalink raw reply
* Re: [PATCH v1 01/11] tracing: Include linux/types.h in trace_remote_event.h
From: Steven Rostedt @ 2026-07-20 18:32 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, linux-arm-kernel, kvmarm, catalin.marinas, will,
mhiramat, alexandru.elisei, vdonnefort, joey.gouly, seiden,
suzuki.poulose, yuzenghui, qperret, ardb, linux-kernel,
linux-trace-kernel, tabba
In-Reply-To: <20260720161343.1367007-2-fuad.tabba@linux.dev>
On Mon, 20 Jul 2026 17:13:33 +0100
Fuad Tabba <fuad.tabba@linux.dev> wrote:
> diff --git a/include/linux/trace_remote_event.h b/include/linux/trace_remote_event.h
> index c8ae1e1f5e721..e4cc2d4497bcf 100644
> --- a/include/linux/trace_remote_event.h
> +++ b/include/linux/trace_remote_event.h
> @@ -3,6 +3,8 @@
> #ifndef _LINUX_TRACE_REMOTE_EVENTS_H
> #define _LINUX_TRACE_REMOTE_EVENTS_H
>
> +#include <linux/types.h>
> +
> struct trace_remote;
> struct trace_event_fields;
> struct trace_seq;
I don't know if this is correct or not, but here's my ack so others can
decide and take it through their trees.
Acked-by: Steven Rostedt <rostedt@goodmis.org.
-- Steve
^ permalink raw reply
* Re: [PATCH 7/8] net: mv643xx: use platform_device_set_fwnode()
From: Andrew Lunn @ 2026-07-20 18:28 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Bartosz Golaszewski, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Madhavan Srinivasan, Michael Ellerman,
Nicholas Piggin, Christophe Leroy (CS GROUP), Andi Shyti,
Joerg Roedel (AMD), Will Deacon, Robin Murphy, Andy Shevchenko,
Doug Berger, Florian Fainelli,
Broadcom internal kernel review list, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Lee Jones, Sebastian Hesselbarth,
Srinivas Kandagatla, driver-core, linuxppc-dev, linux-kernel,
linux-i2c, iommu, netdev, linux-pm, imx, linux-arm-kernel, mfd,
linux-arm-msm, linux-sound
In-Reply-To: <CAMRc=Mduv_KiB42d4AZddTrFSHmKogd2wh6vBDXomW6ssdfq9A@mail.gmail.com>
On Mon, Jul 20, 2026 at 06:01:37PM +0200, Bartosz Golaszewski wrote:
> On Mon, 20 Jul 2026 16:43:40 +0200, Andrew Lunn <andrew@lunn.ch> said:
> > On Mon, Jul 20, 2026 at 11:24:54AM +0200, Bartosz Golaszewski wrote:
> >> Prefer the higher-level platform_device_set_fwnode() over the
> >> OF-specific platform_device_set_of_node() for dynamically allocated
> >> platform devices.
> >>
> >> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> >> ---
> >> drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +-
> >> 1 file changed, 1 insertion(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
> >> index 9caa1e47c174c9d7a161b7f2e2ee12a829b813d4..2f2d6cce8d852b9ec3ab42678a04a7915d1f00cc 100644
> >> --- a/drivers/net/ethernet/marvell/mv643xx_eth.c
> >> +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
> >> @@ -2780,7 +2780,7 @@ static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
> >> goto put_err;
> >> }
> >> ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> >> - platform_device_set_of_node(ppdev, pnp);
> >> + platform_device_set_fwnode(ppdev, of_fwnode_handle(pnp));
> >
> > This is definitely an OF only driver. There are no other calls to
> > fwnode functions in this driver, so this is the wrong thing to do.
> >
> > Sorry, NACK.
> >
>
> I'm not going to die on this hill but drivers are OF-only until they're not.
> For example, Qualcomm is now working on a hybrid ACPI-OF approach for
> laptops[1] and we may end up needing to start converting drivers to fwnode
> after all.
>
> There's no real benefit to sticking to OF-specific APIs unless you need to
> iterate over all properties of a node or use some other functionality not
> available in fwnode. The overhead is minimal and it's never a hot path.
There is a lot of benefit to sticking to OF specific APIs, because
within the kernel OF is well maintained, has active maintainers, there
are tools to validate bindings, etc. ACPI is a Wild West, each driver
is a snow flake, there is no review, no binding documentation, no
validation tools etc.
I hope you allow plenty of time to convert any networking drivers,
where Linux is driving the hardware, to ACPI. Your first stop will be
the UEFI forum making a proposal for MDIO busses, because that
currently is not part of ACPI. You will then need to spend time
understanding the DT bindings, and figuring out which properties are
deprecated so need to stay OF only, and which can be converted to dual
OF/ACPI. I've seen too many naive attempts which blindly convert
everything, copying all the past errors in the DT binding into the
brand new ACPI binding. That will get NACKed.
OF != ACPI
Andrew
^ permalink raw reply
* [PATCH v3 11/17] KVM: arm64: Filter out non-kernel addresses in kern_hyp_va
From: Vincent Donnefort @ 2026-07-20 17:15 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel
Cc: joey.gouly, seiden, suzuki.poulose, yuzenghui, catalin.marinas,
will, kernel-team, tabba, qperret, Vincent Donnefort, Fuad Tabba
In-Reply-To: <20260720171513.1415357-1-vdonnefort@google.com>
kern_hyp_va() is idempotent for the hypervisor linear space. This is
handy for nVHE hypervisor callers handling kvm_vcpu or kvm_arch
pointers. Those pointers can originate from the hypervisor space (when
protected mode is enabled, we don't trust the kernel and the hypervisor
uses its own copy) or from the kernel space (we do trust the kernel in
"non-protected" nVHE).
This idempotence does not hold for addresses within the hypervisor
private range, like the ones you get from the pKVM heap allocator
(hyp_alloc()). To resolve this, filter out non-kernel addresses based on
PAGE_OFFSET.
Leave the assembly version untouched as it has no current users.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6eae7e7e2a68..d60e5f2de10c 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -126,6 +126,9 @@ static __always_inline unsigned long __kern_hyp_va(unsigned long v)
* replace the instructions with `nop`s.
*/
#ifndef __KVM_VHE_HYPERVISOR__
+ if (!is_ttbr1_addr(v))
+ return v;
+
asm volatile(ALTERNATIVE_CB("and %0, %0, #1\n" /* mask with va_mask */
"ror %0, %0, #1\n" /* rotate to the first tag bit */
"add %0, %0, #0\n" /* insert the low 12 bits of the tag */
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related
* Re: [PATCH 6/8] arm64: dts: freescale: imx8mm-verdin: Add Toradex OV5640 CSI Cameras
From: Frank Li @ 2026-07-20 18:16 UTC (permalink / raw)
To: Ernest Van Hoecke
Cc: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Francesco Dolcini,
imx, linux-arm-kernel, devicetree, linux-kernel,
Ernest Van Hoecke
In-Reply-To: <20260713-v1-verdin-imx8mm-dtbos-v1-6-4acd63db4504@toradex.com>
On Mon, Jul 13, 2026 at 05:06:27PM +0200, Ernest Van Hoecke wrote:
> From: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
>
> Add device tree overlays for the Toradex OV5640 CSI Camera on Verdin CSI_1.
>
> The default overlay describes the current CSI Camera Set 5MP OV5640 with a
> 27 MHz on-board oscillator. Add a separate 24 MHz overlay for the legacy
> camera module.
>
> Link: https://developer.toradex.com/hardware/accessories/cameras/csi-camera-module-5mp-ov5640-arducam
> Link: https://www.toradex.com/accessories/csi-camera-ov5640
> Link: https://developer.toradex.com/hardware/legacy-products/other/csi-camera-module-5mp-ov5640/
> Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@toradex.com>
> ---
> arch/arm64/boot/dts/freescale/Makefile | 6 ++
> .../dts/freescale/imx8mm-verdin-ov5640-24mhz.dtso | 17 +++++
> .../boot/dts/freescale/imx8mm-verdin-ov5640.dtsi | 78 ++++++++++++++++++++++
> .../boot/dts/freescale/imx8mm-verdin-ov5640.dtso | 18 +++++
> 4 files changed, 119 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index c465aa19e526..ed3d678e7c5e 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -189,6 +189,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-mallow.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia-dsi-to-hdmi.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-zinnia.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-ov5640-24mhz.dtbo
> +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-ov5640.dtbo
Need not add dtbo here,
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-ov5640-24mhz.dtb can
auto dtbo build dtbo.
check other dtbo.
Frank
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-panel-cap-touch-10inch-dsi.dtbo
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-panel-cap-touch-7inch-dsi.dtbo
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia-dsi-to-hdmi.dtb
> @@ -197,6 +199,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-hdmi.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-nau8822-btl.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-ov5640-24mhz.dtb
> +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-ov5640.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev-panel-cap-touch-7inch-dsi.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-ivy.dtb
> @@ -217,6 +221,8 @@ imx8mm-verdin-wifi-dev-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-ver
> imx8mm-verdin-wifi-dev-dsi-to-lvds-panel-cap-touch-10inch-dtbs := imx8mm-verdin-wifi-dev.dtb \
> imx8mm-verdin-dsi-to-lvds-panel-cap-touch-10inch.dtbo
> imx8mm-verdin-wifi-dev-nau8822-btl-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-dev-nau8822-btl.dtbo
> +imx8mm-verdin-wifi-dev-ov5640-24mhz-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-ov5640-24mhz.dtbo
> +imx8mm-verdin-wifi-dev-ov5640-dtbs := imx8mm-verdin-wifi-dev.dtb imx8mm-verdin-ov5640.dtbo
> imx8mm-verdin-wifi-dev-panel-cap-touch-7inch-dsi-dtbs := imx8mm-verdin-wifi-dev.dtb \
> imx8mm-verdin-panel-cap-touch-7inch-dsi.dtbo
> imx8mm-verdin-wifi-yavia-dsi-to-hdmi-dtbs := imx8mm-verdin-wifi-yavia.dtb imx8mm-verdin-dsi-to-hdmi.dtbo
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640-24mhz.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640-24mhz.dtso
> new file mode 100644
> index 000000000000..f479b709c151
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640-24mhz.dtso
> @@ -0,0 +1,17 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
> +/*
> + * Copyright (c) Toradex
> + *
> + * Toradex CSI Camera Module 5MP OV5640 on Verdin CSI_1.
> + *
> + * https://developer.toradex.com/hardware/legacy-products/other/csi-camera-module-5mp-ov5640/
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include "imx8mm-verdin-ov5640.dtsi"
> +
> +&clock_camera {
> + clock-frequency = <24000000>;
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640.dtsi
> new file mode 100644
> index 000000000000..0632bdb1b679
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640.dtsi
> @@ -0,0 +1,78 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
> +/*
> + * Copyright (c) Toradex
> + *
> + * Common device tree include for Toradex OV5640 CSI camera on Verdin CSI_1.
> + */
> +
> +#include <dt-bindings/gpio/gpio.h>
> +
> +&{/} {
> + clock_camera: clock-camera {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + };
> +
> + regulator_camera: regulator-camera {
> + compatible = "regulator-fixed";
> + /* Verdin GPIO_8_CSI (SODIMM 222) - CSI_1_PWR_EN */
> + gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
> + enable-active-high;
> + regulator-name = "V_CSI";
> + startup-delay-us = <5000>;
> + };
> +};
> +
> +&csi {
> + status = "okay";
> +};
> +
> +/* Verdin I2C_4_CSI */
> +&i2c3 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + status = "okay";
> +
> + camera@3c {
> + compatible = "ovti,ov5640";
> + reg = <0x3c>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_gpio5>, <&pinctrl_gpio6>;
> + clocks = <&clock_camera>;
> + clock-names = "xclk";
> + AVDD-supply = <®ulator_camera>;
> + DOVDD-supply = <®ulator_camera>;
> + DVDD-supply = <®ulator_camera>;
> + /* Verdin GPIO_6_CSI (SODIMM 218) - CSI_1_PWDN */
> + powerdown-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
> + /* Verdin GPIO_5_CSI (SODIMM 216) - CSI_1_RESET# */
> + reset-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
> +
> + port {
> + ov5640_to_mipi_csi2: endpoint {
> + clock-lanes = <0>;
> + data-lanes = <1 2>;
> + remote-endpoint = <&imx8mm_mipi_csi_in>;
> + };
> + };
> + };
> +};
> +
> +&mipi_csi {
> + status = "okay";
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port@0 {
> + reg = <0>;
> +
> + imx8mm_mipi_csi_in: endpoint {
> + data-lanes = <1 2>;
> + remote-endpoint = <&ov5640_to_mipi_csi2>;
> + };
> + };
> + };
> +};
> diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640.dtso b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640.dtso
> new file mode 100644
> index 000000000000..d56234913b61
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-ov5640.dtso
> @@ -0,0 +1,18 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
> +/*
> + * Copyright (c) Toradex
> + *
> + * Toradex CSI Camera Set 5MP OV5640 on Verdin CSI_1.
> + *
> + * https://developer.toradex.com/hardware/accessories/cameras/csi-camera-module-5mp-ov5640-arducam
> + * https://www.toradex.com/accessories/csi-camera-ov5640
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include "imx8mm-verdin-ov5640.dtsi"
> +
> +&clock_camera {
> + clock-frequency = <27000000>;
> +};
>
> --
> 2.43.0
>
^ permalink raw reply
* [PATCH v3 09/17] KVM: arm64: Add selftests for the pKVM heap allocator
From: Vincent Donnefort @ 2026-07-20 17:15 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel
Cc: joey.gouly, seiden, suzuki.poulose, yuzenghui, catalin.marinas,
will, kernel-team, tabba, qperret, Vincent Donnefort, Fuad Tabba
In-Reply-To: <20260720171513.1415357-1-vdonnefort@google.com>
Introduce a comprehensive runtime selftest for the pKVM hypervisor heap
allocator, executed during init when CONFIG_NVHE_EL2_DEBUG is enabled.
The selftest runs entirely at EL2 and exercises allocator's core
mechanisms:
* over-sized allocations
* basic allocation and alignment
* chunk recycling, splitting, merging
* memory reclaiming
* memory topup
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 0c3126179704..08466f608d1f 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -92,6 +92,7 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___pkvm_hyp_topup,
__KVM_HOST_SMCCC_FUNC___pkvm_hyp_reclaim,
__KVM_HOST_SMCCC_FUNC___pkvm_hyp_reclaimable,
+ __KVM_HOST_SMCCC_FUNC___pkvm_hyp_alloc_selftest,
MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY),
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 99daa985856f..73c8881e14ec 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -19,8 +19,10 @@
enum pkvm_topup_id {
PKVM_TOPUP_HYP_ALLOC,
+ PKVM_TOPUP_HYP_ALLOC_SELFTEST,
};
+void pkvm_selftests(void);
int pkvm_init_host_vm(struct kvm *kvm, unsigned long type);
int pkvm_create_hyp_vm(struct kvm *kvm);
bool pkvm_hyp_vm_is_created(struct kvm *kvm);
@@ -206,6 +208,7 @@ struct pkvm_mapping {
enum pkvm_hyp_req_type {
PKVM_HYP_NO_REQ = 0,
PKVM_HYP_REQ_HYP_ALLOC,
+ PKVM_HYP_REQ_HYP_ALLOC_SELFTEST,
__PKVM_HYP_REQ_TYPE_MAX,
};
@@ -233,6 +236,7 @@ static inline size_t pkvm_hyp_req_arg_size(u8 type)
case PKVM_HYP_NO_REQ:
return 0;
case PKVM_HYP_REQ_HYP_ALLOC:
+ case PKVM_HYP_REQ_HYP_ALLOC_SELFTEST:
return sizeof(req->mem);
default:
WARN_ON(1);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 50adfff75be8..750862705a70 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -2883,6 +2883,8 @@ static int __init init_hyp_mode(void)
kvm_err("Failed to init hyp memory protection\n");
goto out_err;
}
+
+ pkvm_selftests();
}
return 0;
diff --git a/arch/arm64/kvm/hyp/include/nvhe/alloc.h b/arch/arm64/kvm/hyp/include/nvhe/alloc.h
index 8f87a63f8946..329250dad6f6 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/alloc.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/alloc.h
@@ -14,4 +14,11 @@ int hyp_alloc_init(size_t size);
int hyp_alloc_topup(struct kvm_hyp_memcache *host_mc);
unsigned long hyp_alloc_reclaimable(void);
void hyp_alloc_reclaim(struct kvm_hyp_memcache *host_mc, unsigned long target);
+
+#ifdef CONFIG_NVHE_EL2_DEBUG
+int hyp_allocator_selftest(void);
+u32 hyp_alloc_selftest_topup_needed(void);
+int hyp_alloc_selftest_topup(struct kvm_hyp_memcache *host_mc);
+void hyp_alloc_selftest_reclaim(struct kvm_hyp_memcache *host_mc, unsigned long target);
+#endif
#endif
diff --git a/arch/arm64/kvm/hyp/nvhe/alloc.c b/arch/arm64/kvm/hyp/nvhe/alloc.c
index 32c923d83f78..49d7560ad150 100644
--- a/arch/arm64/kvm/hyp/nvhe/alloc.c
+++ b/arch/arm64/kvm/hyp/nvhe/alloc.c
@@ -1013,9 +1013,17 @@ int hyp_alloc_errno(void)
return hyp_allocator_errno(&hyp_allocator);
}
+static int selftest_init(void);
+
int hyp_alloc_init(size_t size)
{
- return hyp_allocator_init(&hyp_allocator, size);
+ int ret;
+
+ ret = hyp_allocator_init(&hyp_allocator, size);
+ if (ret)
+ return ret;
+
+ return selftest_init();
}
void hyp_alloc_reclaim(struct kvm_hyp_memcache *mc, unsigned long target)
@@ -1037,3 +1045,179 @@ u32 hyp_alloc_topup_needed(void)
{
return hyp_allocator_topup_needed(&hyp_allocator);
}
+
+#ifdef CONFIG_NVHE_EL2_DEBUG
+#define SELFTEST_MAX_PAGES 6
+#define SELFTEST_MAX_SIZE (PAGE_SIZE * SELFTEST_MAX_PAGES)
+
+static DEFINE_PER_CPU(int, __selftest_errno);
+static DEFINE_PER_CPU(u32, __selftest_topup_needed);
+
+static struct hyp_allocator selftest_allocator = {
+ .errno = &__selftest_errno,
+ .topup_needed = &__selftest_topup_needed,
+ .lock = __HYP_SPIN_LOCK_UNLOCKED,
+};
+
+int hyp_alloc_selftest_topup(struct kvm_hyp_memcache *host_mc)
+{
+ return hyp_allocator_topup(&selftest_allocator, host_mc);
+}
+
+void hyp_alloc_selftest_reclaim(struct kvm_hyp_memcache *host_mc, unsigned long target)
+{
+ hyp_allocator_reclaim(&selftest_allocator, host_mc, target);
+}
+
+u32 hyp_alloc_selftest_topup_needed(void)
+{
+ return hyp_allocator_topup_needed(&selftest_allocator);
+}
+
+static int selftest_init(void)
+{
+ return hyp_allocator_init(&selftest_allocator, SELFTEST_MAX_SIZE);
+}
+
+static void *selftest_alloc(size_t size)
+{
+ return hyp_allocator_alloc(&selftest_allocator, size);
+}
+
+static void selftest_free(void *addr)
+{
+ hyp_allocator_free(&selftest_allocator, addr);
+}
+
+static int selftest_errno(void)
+{
+ return hyp_allocator_errno(&selftest_allocator);
+}
+
+int hyp_allocator_selftest(void)
+{
+ struct hyp_allocator *allocator = &selftest_allocator;
+ static DEFINE_HYP_SPINLOCK(selftest_lock);
+ struct kvm_hyp_memcache host_mc = { };
+ void *addr1, *addr2, *addr3, *addr4;
+ int ret;
+
+ guard(hyp_spinlock)(&selftest_lock);
+
+ if (allocator->mc.nr_pages < SELFTEST_MAX_PAGES) {
+ *this_cpu_ptr(allocator->topup_needed) = SELFTEST_MAX_PAGES -
+ allocator->mc.nr_pages;
+ return -ENOMEM;
+ }
+
+ selftest_alloc(SELFTEST_MAX_SIZE);
+ if (selftest_errno() != -E2BIG)
+ return -EINVAL;
+
+ selftest_alloc(SIZE_MAX);
+ if (selftest_errno() != -E2BIG)
+ return -EINVAL;
+
+ /* Test first chunk */
+ addr1 = selftest_alloc(0);
+ if (!addr1 || addr1 != (void *)allocator->start + chunk_hdr_size())
+ return -EINVAL;
+
+ /* Test second contiguous chunk with unaligned size */
+ addr2 = selftest_alloc(MIN_ALLOC_SIZE + 1);
+ if (!addr2)
+ return -EINVAL;
+ addr3 = selftest_alloc(0);
+ if (!addr3 ||
+ addr3 != addr2 + (2 * MIN_ALLOC_SIZE) + chunk_hdr_size())
+ return -EINVAL;
+
+ selftest_free(addr3);
+
+ /* Test chunk recycling */
+ selftest_free(addr1);
+ if (addr1 != selftest_alloc(0))
+ return -EINVAL;
+
+ /* Test chunk forward merging */
+ addr3 = selftest_alloc(0);
+ selftest_free(addr2);
+ selftest_free(addr1);
+ if (addr1 != selftest_alloc(MIN_ALLOC_SIZE * 2))
+ return -EINVAL;
+
+ selftest_free(addr1);
+
+ /* Test chunk splitting */
+ if (addr1 != selftest_alloc(0))
+ return -EINVAL;
+ if (addr2 != selftest_alloc(0))
+ return -EINVAL;
+
+ /* Test chunk backward merging */
+ selftest_free(addr1);
+ selftest_free(addr2);
+ if (addr1 != selftest_alloc(MIN_ALLOC_SIZE * 2))
+ return -EINVAL;
+
+ selftest_free(addr1);
+
+ /* Test chunk 3-way merging */
+ addr1 = selftest_alloc(0);
+ addr2 = selftest_alloc(0);
+ addr4 = selftest_alloc(0);
+ selftest_free(addr1);
+ selftest_free(addr3);
+ selftest_free(addr2);
+ if (addr1 != selftest_alloc(MIN_ALLOC_SIZE * 3))
+ return -EINVAL;
+
+ selftest_free(addr4);
+ selftest_free(addr1);
+
+ /* Test reclaiming */
+ if (addr1 != selftest_alloc(0))
+ return -EINVAL;
+ if (addr2 != selftest_alloc(PAGE_SIZE * 2))
+ return -EINVAL;
+ addr3 = selftest_alloc(0);
+ addr4 = selftest_alloc(PAGE_SIZE);
+
+ /* Test reclaiming the last chunk of the list */
+ selftest_free(addr4);
+ hyp_allocator_reclaim(allocator, &host_mc, SELFTEST_MAX_PAGES);
+ if (host_mc.nr_pages != SELFTEST_MAX_PAGES - 3)
+ return -EINVAL;
+
+ /* Test punching a hole in the middle of a free chunk ... */
+ selftest_free(addr2);
+ hyp_allocator_reclaim(allocator, &host_mc, SELFTEST_MAX_PAGES);
+ if (host_mc.nr_pages != SELFTEST_MAX_PAGES - 2)
+ return -EINVAL;
+
+ if (selftest_alloc(PAGE_SIZE))
+ return -EINVAL;
+ if (selftest_errno() != -ENOMEM)
+ return -EINVAL;
+
+ /* ... and to refill this hole */
+ ret = hyp_allocator_topup(allocator, &host_mc);
+ if (ret)
+ return ret;
+ /* Chunk at addr2 was made smaller by the reclaim */
+ if (addr2 != selftest_alloc(PAGE_SIZE))
+ return -EINVAL;
+
+ /* Test reclaiming the entire allocator from the host */
+ selftest_free(addr3);
+ selftest_free(addr2);
+ selftest_free(addr1);
+ if (addr1 != selftest_alloc(SELFTEST_MAX_PAGES * PAGE_SIZE - chunk_hdr_size()))
+ return -EINVAL;
+ selftest_free(addr1);
+
+ return 0;
+}
+#else
+static int selftest_init(void) { return 0; }
+#endif
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 346365e76ef2..d99c9b1b0c82 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -633,6 +633,28 @@ static void handle___pkvm_finalize_teardown_vm(struct kvm_cpu_context *host_ctxt
cpu_reg(host_ctxt, 1) = __pkvm_finalize_teardown_vm(handle);
}
+#ifdef CONFIG_NVHE_EL2_DEBUG
+static void handle___pkvm_hyp_alloc_selftest(struct kvm_cpu_context *host_ctxt)
+{
+ struct pkvm_hyp_req req = { .type = PKVM_HYP_NO_REQ };
+ int ret;
+
+ ret = hyp_allocator_selftest();
+ if (ret == -ENOMEM) {
+ req.type = PKVM_HYP_REQ_HYP_ALLOC_SELFTEST;
+ req.mem.nr_pages = hyp_alloc_selftest_topup_needed();
+ }
+
+ cpu_reg(host_ctxt, 1) = ret;
+ pkvm_hyp_req_to_smccc(host_ctxt, &req);
+}
+#else
+static void handle___pkvm_hyp_alloc_selftest(struct kvm_cpu_context *host_ctxt)
+{
+ cpu_reg(host_ctxt, 1) = -EPERM;
+}
+#endif
+
static void handle___pkvm_hyp_topup(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(enum pkvm_topup_id, id, host_ctxt, 1);
@@ -648,6 +670,11 @@ static void handle___pkvm_hyp_topup(struct kvm_cpu_context *host_ctxt)
case PKVM_TOPUP_HYP_ALLOC:
ret = hyp_alloc_topup(&host_mc);
break;
+#ifdef CONFIG_NVHE_EL2_DEBUG
+ case PKVM_TOPUP_HYP_ALLOC_SELFTEST:
+ ret = hyp_alloc_selftest_topup(&host_mc);
+ break;
+#endif
default:
ret = -EINVAL;
}
@@ -668,6 +695,11 @@ static void handle___pkvm_hyp_reclaim(struct kvm_cpu_context *host_ctxt)
case PKVM_TOPUP_HYP_ALLOC:
hyp_alloc_reclaim(&host_mc, target);
break;
+#ifdef CONFIG_NVHE_EL2_DEBUG
+ case PKVM_TOPUP_HYP_ALLOC_SELFTEST:
+ hyp_alloc_selftest_reclaim(&host_mc, target);
+ break;
+#endif
default:
ret = -EINVAL;
}
@@ -804,6 +836,7 @@ static const hcall_t host_hcall[] = {
HANDLE_FUNC(__pkvm_hyp_topup),
HANDLE_FUNC(__pkvm_hyp_reclaim),
HANDLE_FUNC(__pkvm_hyp_reclaimable),
+ HANDLE_FUNC(__pkvm_hyp_alloc_selftest),
HANDLE_FUNC(__pkvm_host_share_hyp),
HANDLE_FUNC(__pkvm_host_unshare_hyp),
diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
index a82e773a1c2d..d28422f5c3d6 100644
--- a/arch/arm64/kvm/pkvm.c
+++ b/arch/arm64/kvm/pkvm.c
@@ -326,6 +326,22 @@ static int __init pkvm_drop_host_privileges(void)
return ret;
}
+void __init pkvm_selftests(void)
+{
+#ifdef CONFIG_NVHE_EL2_DEBUG
+ int ret = pkvm_call_hyp_req(__pkvm_hyp_alloc_selftest);
+ unsigned long reclaimed;
+
+ reclaimed = pkvm_hyp_reclaim(PKVM_TOPUP_HYP_ALLOC_SELFTEST, ULONG_MAX);
+
+ /* On failure, not all the pages may be reclaimable */
+ if (!ret)
+ WARN_ON(reclaimed != 6 /* SELFTEST_MAX_PAGES */);
+ else
+ kvm_err("pKVM hyp allocator selftest failed (%d)\n", ret);
+#endif
+}
+
static int __init finalize_pkvm(void)
{
int ret;
@@ -652,6 +668,9 @@ static int pkvm_handle_hyp_req(struct pkvm_hyp_req *req)
case PKVM_HYP_REQ_HYP_ALLOC:
ret = pkvm_hyp_topup(PKVM_TOPUP_HYP_ALLOC, req->mem.nr_pages);
break;
+ case PKVM_HYP_REQ_HYP_ALLOC_SELFTEST:
+ ret = pkvm_hyp_topup(PKVM_TOPUP_HYP_ALLOC_SELFTEST, req->mem.nr_pages);
+ break;
}
trace_kvm_handle_pkvm_hyp_req(req, ret);
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related
* Re: [PATCH net-next] net: stmmac: Simplify ioctl handling
From: Andrew Lunn @ 2026-07-20 18:12 UTC (permalink / raw)
To: Vadim Fedorenko
Cc: Maxime Chevallier, Andrew Lunn, Jakub Kicinski, davem,
Eric Dumazet, Paolo Abeni, Simon Horman, Maxime Coquelin,
Alexandre Torgue, Russell King, thomas.petazzoni,
Alexis Lothoré, netdev, linux-kernel, linux-arm-kernel,
linux-stm32
In-Reply-To: <6ac12388-60de-45aa-a8d0-62fcfaf7bea2@linux.dev>
On Mon, Jul 20, 2026 at 04:17:32PM +0100, Vadim Fedorenko wrote:
> On 19.07.2026 17:13, Andrew Lunn wrote:
> > > Looking at this, I'm wondering if we can't just get rid of SIOCSHWTSTAMP
> > > handling in phy_mii_ioctl(). Looks like we can ?
> >
> > I'm not sure about that. We need Richards input.
> >
> > The code in phy_mii_ioctl() allows the MAC to be bypassed, it goes
> > straight to a PHY based stamper. It could be the MAC has no idea the
> > PHY has this capability, so it has not implemented the .ndo?
> >
> > It might be we need to hoist the code from phy_mii_ioctl() into
> > dev_{sg}et_hwtstamp()?
>
> Hi Andrew!
>
> I think I've converted all phy drivers while removing support for
> SIOCSHWTSTAMP/SIOCGHWTSTAMP from netdev ioctl. I believe it's impossible right
> now to reach SIOCSHWTSTAMP path of phy_mii_ioctl via ioctl on net device.
Lets look at this, using a random example:
drivers/net/ethernet/marvell/mv643xx_eth.c
mv643xx_eth_netdev_ops has nothing about time stamping. However it
does have a mv643xx_eth_ioctl. Which calls phy_mii_ioctl().
Lets say this Marvell MAC driver was paired with a
nxp-c45-tja11xx. nxp_c45_probe() does:
priv->mii_ts.rxtstamp = nxp_c45_rxtstamp;
priv->mii_ts.txtstamp = nxp_c45_txtstamp;
priv->mii_ts.hwtstamp_set = nxp_c45_hwtstamp_set;
priv->mii_ts.hwtstamp_get = nxp_c45_hwtstamp_get;
priv->mii_ts.ts_info = nxp_c45_ts_info;
phydev->mii_ts = &priv->mii_ts;
So it looks like in phy_mii_ioctl(), the conditions:
case SIOCSHWTSTAMP:
if (phydev->mii_ts && phydev->mii_ts->hwtstamp_set) {
are fulfilled, and
ret = phydev->mii_ts->hwtstamp_set(phydev->mii_ts,
&kernel_cfg,
&extack);
will happen.
Now, this combination of MAC and PHY is very unlikely but it proves
the point. As far as i remember, Richard added this code for the
dp83640 PHY device, but i don't remember what MAC driver it was paired
with. He wanted to make PHY support just work without the MAC driver
even caring.
Andrew
^ permalink raw reply
* [PATCH v6 1/4] arm64: vdso: Prepare for robust futex unlock support
From: André Almeida @ 2026-07-20 16:03 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
André Almeida
In-Reply-To: <20260720-tonyk-robust_arm-v6-0-7e68c122047e@igalia.com>
To solve the robust futex's list_pending_op clearing race condition,
prepare for implement __vdso_futex_robust_try_unlock() for arm64 with the
following steps:
- Create a helper function that sets the struct futex_mm_data with the
VDSO's labels addresses. The robust futex fixup mechanism needs to
compare the current instruction pointer to the VDSO instructions range.
- Split vdso_mremap() in vdso_mremap() and aarch32_mremap(), this allows
the VDSO to be setup correctly regarding the instructions addresses for
both ABIs when a mremap happens.
- Implement arch_futex_robust_unlock_get_pop() for arm64, checking for r2
and r3 registers values for the fixup function. The role of this registers
is explained in the commit that implement the assembly portion of the VDSO.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
v6:
- Restructured this commit. Move the arch bits away, kept just the
generic/helper functions.
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/include/asm/futex_robust.h | 19 +++++++++++++++++++
arch/arm64/kernel/vdso.c | 27 ++++++++++++++++++++++++++-
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/futex_robust.h b/arch/arm64/include/asm/futex_robust.h
new file mode 100644
index 000000000000..4ff783bb2dc3
--- /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 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.c b/arch/arm64/kernel/vdso.c
index 592dd8668de4..3ef331b5b240 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,6 +58,22 @@ static struct vdso_abi_info vdso_info[] __ro_after_init = {
#endif /* CONFIG_COMPAT_VDSO */
};
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
+ void *endp)
+{
+ unsigned long start = (unsigned long) startp;
+ unsigned long end = (unsigned long) endp;
+ struct futex_mm_data *fd = &mm->futex;
+
+ futex_set_vdso_cs_range(fd, is_32bit ? 1 : 0, start, end, is_32bit);
+}
+
+#else
+static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit, void *startp,
+ void *endp)
+#endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
+
static int vdso_mremap(const struct vm_special_mapping *sm,
struct vm_area_struct *new_vma)
{
@@ -162,6 +179,14 @@ static int aarch32_sigpage_mremap(const struct vm_special_mapping *sm,
return 0;
}
+static int aarch32_mremap(const struct vm_special_mapping *sm,
+ struct vm_area_struct *new_vma)
+{
+ current->mm->context.vdso = (void *)new_vma->vm_start;
+
+ return 0;
+}
+
static struct vm_special_mapping aarch32_vdso_maps[] = {
[AA32_MAP_VECTORS] = {
.name = "[vectors]", /* ABI */
@@ -174,7 +199,7 @@ static struct vm_special_mapping aarch32_vdso_maps[] = {
},
[AA32_MAP_VDSO] = {
.name = "[vdso]",
- .mremap = vdso_mremap,
+ .mremap = aarch32_mremap,
},
};
--
2.55.0
^ permalink raw reply related
* [PATCH v3 04/17] KVM: arm64: Add a heap allocator for the pKVM hyp
From: Vincent Donnefort @ 2026-07-20 17:15 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel
Cc: joey.gouly, seiden, suzuki.poulose, yuzenghui, catalin.marinas,
will, kernel-team, tabba, qperret, Vincent Donnefort
In-Reply-To: <20260720171513.1415357-1-vdonnefort@google.com>
Currently, memory used by the hypervisor comes from donations that are
embedded within HVCs. e.g. __pkvm_init_vm()'s hyp_vm.
This is cumbersome: the host needs to know the size of those
struct, the memory must be page-aligned and physically contiguous which
may be difficult to satisfy when host memory is highly fragmented.
Create a heap allocator to manage VA-contiguous memory. This allocator
grows upward, recycles unused chunks of memory and provides a simple API
to allocate and free:
hyp_alloc(size), hyp_free(addr)
This heap allocator also manages the underlying physical memory,
allowing the host to top up the allocator's pool and reclaim memory.
hyp_alloc_topup(), hyp_alloc_reclaim().
Pages remain mapped in the allocator's VA-space as long as they are not
reclaimed.
When the allocator runs out of memory, hyp_alloc() fails and
hyp_alloc_errno() returns -ENOMEM to signal that a top-up is required.
Additionally, harden the allocator with a fast hash of the chunks
meta-data. This intends to detect accidental corruptions and makes the
allocator slightly more robust to potential attacks.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/arch/arm64/kvm/hyp/include/nvhe/alloc.h b/arch/arm64/kvm/hyp/include/nvhe/alloc.h
new file mode 100644
index 000000000000..8f87a63f8946
--- /dev/null
+++ b/arch/arm64/kvm/hyp/include/nvhe/alloc.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __KVM_NVHE_ALLOC__
+#define __KVM_NVHE_ALLOC__
+#include <linux/types.h>
+
+#include <asm/kvm_host.h>
+
+void *hyp_alloc(size_t size);
+int hyp_alloc_errno(void);
+u32 hyp_alloc_topup_needed(void);
+void hyp_free(void *addr);
+
+int hyp_alloc_init(size_t size);
+int hyp_alloc_topup(struct kvm_hyp_memcache *host_mc);
+unsigned long hyp_alloc_reclaimable(void);
+void hyp_alloc_reclaim(struct kvm_hyp_memcache *host_mc, unsigned long target);
+#endif
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index f57450ebcb49..985fe3343f4c 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -23,7 +23,7 @@ lib-objs := $(addprefix ../../../lib/, $(lib-objs))
CFLAGS_switch.nvhe.o += -Wno-override-init
hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o \
- hyp-main.o hyp-smp.o psci-relay.o early_alloc.o page_alloc.o \
+ hyp-main.o hyp-smp.o psci-relay.o alloc.o early_alloc.o page_alloc.o \
cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o ffa.o
hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
../hyp-entry.o ../exception.o ../pgtable.o ../vgic-v5-sr.o
diff --git a/arch/arm64/kvm/hyp/nvhe/alloc.c b/arch/arm64/kvm/hyp/nvhe/alloc.c
new file mode 100644
index 000000000000..32c923d83f78
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/alloc.c
@@ -0,0 +1,1039 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Google LLC
+ * Author: Vincent Donnefort <vdonnefort@google.com>
+ *
+ * This heap allocator manages a reserved VA space range, dynamically mapping
+ * and unmapping physical pages on-demand to minimise the pKVM hypervisor
+ * footprint. As memory is reclaimed and relinquished to the host, unmapped
+ * holes are introduced within the VA space. To prevent orphans mapped regions,
+ * neighboring unused chunks cannot be merged if they are separated by an
+ * unmapped region.
+ *
+ */
+
+#include <nvhe/alloc.h>
+#include <nvhe/mem_protect.h>
+#include <nvhe/mm.h>
+#include <nvhe/spinlock.h>
+
+#include <linux/build_bug.h>
+#include <linux/hash.h>
+
+/*
+ * A minimum of 16 bytes allows us to comply with the alignment requirement for
+ * FPSIMD registers that are part of struct pkvm_hyp_vcpu.
+ *
+ * It also must be a power of two.
+ */
+#define MIN_ALLOC_SIZE 16UL
+
+/**
+ * struct chunk_hdr - Chunk header
+ * @next: offset from this chunk header to the next one.
+ * @prev: offset from this chunk header to the previous one.
+ * @__unmapped: Internal field containing the offset to the unmapped page
+ * boundary, multiplexed with the allocation state flag.
+ * @hash: Hash computed over the chunk header.
+ */
+struct chunk_hdr {
+ u32 next;
+ u32 prev;
+#define USED_BIT_MASK 1U
+ u32 __unmapped;
+ u32 hash;
+ char data[];
+} __aligned(MIN_ALLOC_SIZE);
+
+/**
+ * struct hyp_allocator - Heap allocator
+ * @start: Start in the allocator's reserved virtual address range.
+ * @end: End in the allocator's reserved virtual address range.
+ * @last_used: Pointer to the end of the last used chunk. This is
+ * necessary for the last chunk in the list as the
+ * allocated size of a chunk is derived from the next one.
+ * @first_unmapped: Pointer to the first unmapped page in the
+ * allocator's range. This is only necessary and
+ * updated when no chunk is in the list.
+ * @head: Head of the chunk list.
+ * @tail: Tail of the chunk list.
+ * @mc: Memcache containing pre-allocated pages for mapping.
+ * @lock: Spinlock protecting the allocator state.
+ * @errno: Per-CPU error code for allocation failures.
+ * @topup_needed: Per-CPU page counter needed to top-up the memcache.
+ */
+struct hyp_allocator {
+ void *start;
+ void *end;
+ void *last_used;
+ void *first_unmapped;
+ struct chunk_hdr *head;
+ struct chunk_hdr *tail;
+ struct kvm_hyp_memcache mc;
+ hyp_spinlock_t lock;
+ int __percpu *errno;
+ u32 __percpu *topup_needed;
+};
+
+static u32 chunk_hash_compute(const struct chunk_hdr *chunk)
+{
+ u32 hash = 0;
+
+ BUILD_BUG_ON(sizeof(*chunk) != 16);
+
+ hash ^= hash_64(*(const u64 *)chunk, 32);
+ hash ^= hash_32(chunk->__unmapped, 32);
+ return hash;
+}
+
+static void chunk_set_hash(struct chunk_hdr *chunk)
+{
+ if (chunk)
+ chunk->hash = chunk_hash_compute(chunk);
+}
+
+static void chunk_check_hash(const struct chunk_hdr *chunk)
+{
+ if (chunk)
+ WARN_ON(chunk->hash != chunk_hash_compute(chunk));
+}
+
+static bool chunk_is_used(const struct chunk_hdr *chunk)
+{
+ return !!(chunk->__unmapped & USED_BIT_MASK);
+}
+
+static void chunk_set_used(struct chunk_hdr *chunk)
+{
+ chunk->__unmapped |= USED_BIT_MASK;
+}
+
+static void chunk_set_unused(struct chunk_hdr *chunk)
+{
+ chunk->__unmapped &= ~USED_BIT_MASK;
+}
+
+static void *chunk_unmapped(const struct chunk_hdr *chunk)
+{
+ u32 offset = chunk->__unmapped & ~USED_BIT_MASK;
+
+ if (!offset)
+ return NULL;
+
+ return (void *)chunk + offset;
+}
+
+static void __chunk_set_unmapped(struct chunk_hdr *chunk, u32 unmapped)
+{
+ chunk->__unmapped = unmapped | (chunk_is_used(chunk) ? USED_BIT_MASK : 0);
+}
+
+static void chunk_set_unmapped(struct chunk_hdr *chunk, void *unmapped)
+{
+ WARN_ON(!PAGE_ALIGNED(unmapped));
+
+ if (unmapped) {
+ WARN_ON((void *)chunk > unmapped);
+ __chunk_set_unmapped(chunk, unmapped - (void *)chunk);
+ } else {
+ __chunk_set_unmapped(chunk, 0);
+ }
+}
+
+static void *chunk_data(const struct chunk_hdr *chunk)
+{
+ return (void *)&chunk->data;
+}
+
+static struct chunk_hdr *__chunk_next(const struct chunk_hdr *chunk)
+{
+ if (!chunk->next)
+ return NULL;
+
+ return (struct chunk_hdr *)((void *)chunk + chunk->next);
+}
+
+static struct chunk_hdr *__chunk_prev(const struct chunk_hdr *chunk)
+{
+ if (!chunk->prev)
+ return NULL;
+
+ return (struct chunk_hdr *)((void *)chunk - chunk->prev);
+}
+
+static void chunk_set_next(struct chunk_hdr *chunk, struct chunk_hdr *next)
+{
+ if (!chunk)
+ return;
+
+ if (next) {
+ WARN_ON(chunk > next);
+ chunk->next = (void *)next - (void *)chunk;
+ } else {
+ chunk->next = 0;
+ }
+}
+
+static void chunk_set_prev(struct chunk_hdr *chunk, struct chunk_hdr *prev)
+{
+ if (!chunk)
+ return;
+
+ if (prev) {
+ WARN_ON(chunk < prev);
+ chunk->prev = (void *)chunk - (void *)prev;
+ } else {
+ chunk->prev = 0;
+ }
+}
+
+static struct chunk_hdr *chunk_get_next(const struct chunk_hdr *chunk)
+{
+ struct chunk_hdr *next = __chunk_next(chunk);
+
+ chunk_check_hash(next);
+ return next;
+}
+
+static struct chunk_hdr *chunk_get_prev(const struct chunk_hdr *chunk)
+{
+ struct chunk_hdr *prev = __chunk_prev(chunk);
+
+ chunk_check_hash(prev);
+ return prev;
+}
+
+static struct chunk_hdr *chunk_get(struct chunk_hdr *chunk)
+{
+ chunk_check_hash(chunk);
+ return chunk;
+}
+
+#define chunk_hdr_size() \
+ offsetof(struct chunk_hdr, data)
+
+#define chunk_min_size() \
+ (chunk_hdr_size() + MIN_ALLOC_SIZE)
+
+static size_t chunk_data_size(const struct chunk_hdr *chunk, struct hyp_allocator *allocator)
+{
+ struct chunk_hdr *next = chunk_get_next(chunk);
+ void *end;
+
+ if (next)
+ end = (void *)next;
+ else
+ end = allocator->end;
+
+ return end - chunk_data(chunk);
+}
+
+static size_t chunk_mapped_data_size(const struct chunk_hdr *chunk, struct hyp_allocator *allocator)
+{
+ void *unmapped = chunk_unmapped(chunk);
+
+ if (!unmapped)
+ return chunk_data_size(chunk, allocator);
+
+ return unmapped - chunk_data(chunk);
+}
+
+static size_t chunk_used_size(const struct chunk_hdr *chunk, struct hyp_allocator *allocator)
+{
+ struct chunk_hdr *next = chunk_get_next(chunk);
+
+ if (!chunk_is_used(chunk))
+ return 0;
+
+ if (next)
+ return chunk_mapped_data_size(chunk, allocator);
+
+ return allocator->last_used - chunk_data(chunk);
+}
+
+static void chunk_list_insert(struct chunk_hdr *chunk, struct chunk_hdr *prev)
+{
+ struct chunk_hdr *next = NULL;
+
+ WARN_ON(!chunk);
+
+ if (prev) {
+ next = chunk_get_next(prev);
+ chunk_set_next(prev, chunk);
+ chunk_set_hash(prev);
+ }
+
+ if (next) {
+ chunk_set_prev(next, chunk);
+ chunk_set_hash(next);
+ }
+
+ chunk_set_next(chunk, next);
+ chunk_set_prev(chunk, prev);
+}
+
+static void chunk_list_del(struct chunk_hdr *chunk)
+{
+ struct chunk_hdr *prev, *next;
+
+ WARN_ON(!chunk);
+
+ prev = chunk_get_prev(chunk);
+ next = chunk_get_next(chunk);
+
+ if (prev) {
+ chunk_set_next(prev, next);
+ chunk_set_hash(prev);
+ }
+
+ if (next) {
+ chunk_set_prev(next, prev);
+ chunk_set_hash(next);
+ }
+}
+
+/*
+ * Return a fixup start address for chunk creation. It makes sure the chunk
+ * header doesn't cross any page boundary and that it leaves enough space at the
+ * start of page. This is intended to prevent orphan mapped regions during chunk
+ * memory reclaim
+ */
+static void *chunk_start(void *start)
+{
+ void *page = PTR_ALIGN(start, PAGE_SIZE);
+
+ if (page - start < chunk_hdr_size())
+ return page;
+
+ page = PTR_ALIGN_DOWN(start, PAGE_SIZE);
+ if (start - page < chunk_min_size())
+ return page + chunk_min_size();
+
+ return start;
+}
+
+static void hyp_allocator_set_errno(struct hyp_allocator *allocator, int errno)
+{
+ *this_cpu_ptr(allocator->errno) = errno;
+}
+
+static int hyp_allocator_errno(struct hyp_allocator *allocator)
+{
+ int *errno = this_cpu_ptr(allocator->errno);
+ int ret = *errno;
+
+ *errno = 0;
+
+ return ret;
+}
+
+static int hyp_allocator_map(struct hyp_allocator *allocator, struct chunk_hdr *chunk,
+ struct chunk_hdr *next,
+ void *addr, void *end)
+{
+ void *unmapped = chunk ? chunk_unmapped(chunk) : allocator->first_unmapped;
+ void *unmapped_end = next ?: allocator->end;
+
+ /*
+ * hyp_allocator_can_create_chunk() already validates addr/end
+ * belong to the chunk.
+ */
+ WARN_ON(end <= addr);
+
+ /* The chunk does not span an unmapped region */
+ if (!unmapped)
+ return 0;
+
+ while (unmapped < end) {
+ void *page = pop_hyp_memcache(&allocator->mc, hyp_phys_to_virt);
+ int ret;
+
+ if (!page) {
+ end = PTR_ALIGN(end, PAGE_SIZE);
+ *this_cpu_ptr(allocator->topup_needed) =
+ (unsigned long)(end - unmapped) >> PAGE_SHIFT;
+ return -ENOMEM;
+ }
+
+ ret = pkvm_map_private_va_range(unmapped, hyp_virt_to_phys(page), PAGE_SIZE);
+ if (ret) {
+ push_hyp_memcache(&allocator->mc, page, hyp_virt_to_phys);
+ return ret;
+ }
+
+ unmapped += PAGE_SIZE;
+
+ /*
+ * Reset the unmap field if we've reached the next chunk or the
+ * allocator boundary. Chunks are always installed to cover a
+ * mapped region followed by an unmapped one. Therefore, we
+ * expect next to be PAGE_ALIGNED.
+ */
+ WARN_ON(!PAGE_ALIGNED(unmapped_end));
+ if (unmapped == unmapped_end)
+ unmapped = 0;
+
+ if (chunk) {
+ chunk_set_unmapped(chunk, unmapped);
+ chunk_set_hash(chunk);
+ } else {
+ allocator->first_unmapped = unmapped;
+ }
+
+ if (!unmapped)
+ break;
+ }
+
+ return 0;
+}
+
+static void hyp_allocator_unmap(struct hyp_allocator *allocator, struct chunk_hdr *chunk,
+ void *addr, void *end)
+{
+ void *unmap = addr;
+
+ /*
+ * hyp_allocator_chunk_reclaimable() already computes valid addr/end, no
+ * need to check them again
+ */
+ WARN_ON(end <= addr);
+
+ while (unmap < end) {
+ phys_addr_t pa = pkvm_private_va_range_pa((void *)unmap);
+ void *page = hyp_phys_to_virt(pa);
+
+ push_hyp_memcache(&allocator->mc, page, hyp_virt_to_phys);
+ unmap += PAGE_SIZE;
+ }
+
+ pkvm_remove_mappings(addr, end);
+
+ if (chunk) {
+ chunk_set_unmapped(chunk, addr);
+ chunk_set_hash(chunk);
+ } else {
+ allocator->first_unmapped = addr;
+ }
+}
+
+static bool hyp_allocator_can_create_chunk(struct hyp_allocator *allocator,
+ const struct chunk_hdr *prev,
+ const struct chunk_hdr *next,
+ void *addr, void *end)
+{
+ void *page, *unmapped;
+
+ if (addr < allocator->start || end > allocator->end)
+ return false;
+
+ /* First chunk created must be installed at allocator->start */
+ if (!prev)
+ return addr == allocator->start;
+
+ /* Must not overwrite the next chunk */
+ if (next && end > (void *)next)
+ return false;
+
+ /* Must not overwrite the previous chunk */
+ if (addr < (chunk_data(prev) + chunk_used_size(prev, allocator)))
+ return false;
+
+ /* Header must not cross page boundaries */
+ page = PTR_ALIGN(addr, PAGE_SIZE);
+ if (page != addr && (page - addr) < chunk_hdr_size())
+ return false;
+
+ /* Must leave a minimum distance from a page-start to maximise reclaim */
+ page = PTR_ALIGN_DOWN(addr, PAGE_SIZE);
+ if (page != addr && (addr - page) < chunk_min_size())
+ return false;
+
+ unmapped = chunk_unmapped(prev);
+ if (!unmapped)
+ return true;
+
+ /* Must never create an orphan mapped region */
+ if (addr > unmapped)
+ return false;
+
+ return true;
+}
+
+/*
+ * Tries to create a new chunk in the allocator whose header starts at @addr and
+ * whose data finishes at @end.
+ */
+static struct chunk_hdr *hyp_allocator_create_chunk(struct hyp_allocator *allocator,
+ struct chunk_hdr *prev, void *addr,
+ void *end, bool used)
+{
+ struct chunk_hdr *next, *chunk = addr;
+ void *unmapped;
+ int ret;
+
+ if (end > allocator->end)
+ return ERR_PTR(-E2BIG);
+
+ next = prev ? chunk_get_next(prev) : NULL;
+ if (!hyp_allocator_can_create_chunk(allocator, prev, next, addr, end))
+ return ERR_PTR(-EINVAL);
+
+ ret = hyp_allocator_map(allocator, prev, next, addr, end);
+ if (ret)
+ return ERR_PTR(ret);
+
+ memset(chunk, 0, sizeof(*chunk));
+ if (used)
+ chunk_set_used(chunk);
+ else
+ chunk_set_unused(chunk);
+
+ /* First chunk, first allocation */
+ if (!prev) {
+ chunk_set_unmapped(chunk, allocator->first_unmapped);
+ chunk_list_insert(chunk, NULL);
+ chunk_set_hash(chunk);
+
+ allocator->last_used = end;
+ allocator->head = allocator->tail = chunk;
+ return chunk;
+ }
+
+ /* Last chunk in the list */
+ if (!next) {
+ allocator->last_used = end;
+ allocator->tail = chunk;
+ }
+
+ /* Inherit prev's unmapped region */
+ unmapped = chunk_unmapped(prev);
+ chunk_set_unmapped(chunk, unmapped);
+ chunk_list_insert(chunk, prev);
+ chunk_set_hash(chunk);
+
+ chunk_set_unmapped(prev, 0);
+ chunk_set_hash(prev);
+
+ return chunk;
+}
+
+static bool hyp_allocator_can_destroy_chunk(struct hyp_allocator *allocator,
+ const struct chunk_hdr *prev,
+ const struct chunk_hdr *next,
+ const struct chunk_hdr *chunk)
+{
+ if (chunk_is_used(chunk))
+ return false;
+
+ /* Last chunk in the allocator */
+ if (!prev)
+ return true;
+
+ /* Can't merge down unless we are the last one in the list */
+ if (next && chunk_is_used(prev))
+ return false;
+
+ /* Must never create an orphan mapped region */
+ if (chunk_unmapped(prev))
+ return false;
+
+ return true;
+}
+
+static int hyp_allocator_destroy_chunk(struct hyp_allocator *allocator,
+ struct chunk_hdr *prev,
+ struct chunk_hdr *chunk)
+{
+ struct chunk_hdr *next;
+
+ next = prev ? chunk_get_next(chunk) : NULL;
+ if (!hyp_allocator_can_destroy_chunk(allocator, prev, next, chunk))
+ return -EINVAL;
+
+ /* Last chunk in the allocator */
+ if (!prev) {
+ allocator->first_unmapped = chunk_unmapped(chunk);
+ allocator->head = allocator->tail = NULL;
+ return 0;
+ }
+
+ /* Last chunk in the list */
+ if (!next) {
+ allocator->last_used = chunk;
+ allocator->tail = prev;
+ }
+
+ chunk_set_unmapped(prev, chunk_unmapped(chunk));
+ chunk_set_hash(prev);
+ chunk_list_del(chunk);
+
+ return 0;
+}
+
+/*
+ * Return the best unused chunk for recycling, that is the smallest chunk
+ * fitting the allocation which needs to use the least unmapped region.
+ */
+static struct chunk_hdr *hyp_allocator_find_efficient_chunk(struct hyp_allocator *allocator,
+ size_t size)
+{
+ struct chunk_hdr *chunk, *best_chunk = NULL;
+ size_t best_data_size = SIZE_MAX;
+ size_t best_missing = SIZE_MAX;
+
+ chunk = allocator->head;
+ while (chunk) {
+ size_t missing, mapped, data_size;
+
+ if (chunk_is_used(chunk))
+ goto next;
+
+ data_size = chunk_data_size(chunk, allocator);
+ if (data_size < size)
+ goto next;
+
+ mapped = chunk_mapped_data_size(chunk, allocator);
+ missing = (size > mapped) ? DIV_ROUND_UP(size - mapped, PAGE_SIZE) : 0;
+ if (missing > best_missing)
+ goto next;
+
+ if (missing == best_missing && data_size >= best_data_size)
+ goto next;
+
+ best_missing = missing;
+ best_data_size = data_size;
+ best_chunk = chunk;
+
+next:
+ chunk = chunk_get_next(chunk);
+ }
+
+ return best_chunk;
+}
+
+static struct chunk_hdr *hyp_allocator_reuse_chunk(struct hyp_allocator *allocator,
+ struct chunk_hdr *chunk, size_t size)
+{
+ struct chunk_hdr *next = chunk_get_next(chunk);
+ void *start, *end, *split, *split_end;
+ int ret;
+
+ start = chunk_data(chunk);
+ end = start + size;
+
+ /* Last chunk in the list, no need to split */
+ if (!next) {
+ split = split_end = NULL;
+ allocator->last_used = chunk_data(chunk) + size;
+ } else {
+ split = chunk_start(end);
+ split_end = split + chunk_min_size();
+
+ if (!hyp_allocator_can_create_chunk(allocator, chunk, next, split, split_end))
+ split = split_end = NULL;
+ }
+
+ /* Batch the mapping of the reused chunk and the split */
+ ret = hyp_allocator_map(allocator, chunk, next, chunk_data(chunk), split ? split_end : end);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (split)
+ WARN_ON(IS_ERR_OR_NULL(
+ hyp_allocator_create_chunk(allocator, chunk, split, split_end, false)));
+
+ chunk_set_used(chunk);
+ chunk_set_hash(chunk);
+
+ return chunk;
+}
+
+static struct chunk_hdr *hyp_allocator_alloc_chunk(struct hyp_allocator *allocator, size_t size)
+{
+ struct chunk_hdr *chunk;
+ void *start, *end;
+
+ /* First allocation */
+ if (!allocator->head) {
+ start = allocator->start;
+ end = start + chunk_hdr_size() + size;
+ return hyp_allocator_create_chunk(allocator, NULL, start, end, true);
+ }
+
+ chunk = hyp_allocator_find_efficient_chunk(allocator, size);
+
+ /* Nothing found, create a new chunk at the end in the list */
+ if (!chunk) {
+ start = chunk_start(chunk_data(allocator->tail) +
+ chunk_used_size(allocator->tail, allocator));
+ end = start + chunk_hdr_size() + size;
+ return hyp_allocator_create_chunk(allocator, allocator->tail, start, end, true);
+ }
+
+ return hyp_allocator_reuse_chunk(allocator, chunk, size);
+}
+
+static void *hyp_allocator_alloc(struct hyp_allocator *allocator, size_t size)
+{
+ struct chunk_hdr *chunk;
+
+ size = max(size, MIN_ALLOC_SIZE);
+
+ /* Ensure we do not overflow ALIGN(MIN_ALLOC_SIZE) */
+ if (size > U32_MAX) {
+ hyp_allocator_set_errno(allocator, -E2BIG);
+ return NULL;
+ }
+
+ size = ALIGN(size, MIN_ALLOC_SIZE);
+ if (size > (allocator->end - allocator->start - chunk_hdr_size())) {
+ hyp_allocator_set_errno(allocator, -E2BIG);
+ return NULL;
+ }
+
+ scoped_guard(hyp_spinlock, &allocator->lock) {
+ chunk = hyp_allocator_alloc_chunk(allocator, size);
+ if (IS_ERR_OR_NULL(chunk)) {
+ hyp_allocator_set_errno(allocator,
+ IS_ERR(chunk) ? PTR_ERR(chunk) : -EINVAL);
+ return NULL;
+ }
+ }
+
+ memset(chunk_data(chunk), 0, size);
+ return chunk_data(chunk);
+}
+
+static void hyp_allocator_free(struct hyp_allocator *allocator, void *data)
+{
+ struct chunk_hdr *chunk, *next, *prev;
+
+ if (!data)
+ return;
+
+ WARN_ON(!IS_ALIGNED((unsigned long)data, MIN_ALLOC_SIZE));
+ WARN_ON(data >= allocator->end || data < allocator->start + chunk_hdr_size());
+
+ guard(hyp_spinlock)(&allocator->lock);
+
+ chunk = chunk_get(container_of(data, struct chunk_hdr, data));
+ WARN_ON(!chunk_is_used(chunk));
+ chunk_set_unused(chunk);
+ chunk_set_hash(chunk);
+
+ next = chunk_get_next(chunk);
+ if (next)
+ hyp_allocator_destroy_chunk(allocator, chunk, next);
+
+ prev = chunk_get_prev(chunk);
+ if (prev)
+ hyp_allocator_destroy_chunk(allocator, prev, chunk);
+}
+
+static unsigned long hyp_allocator_chunk_reclaimable(struct hyp_allocator *allocator,
+ const struct chunk_hdr *chunk,
+ u64 *__addr, u64 *__end)
+{
+ struct chunk_hdr *next;
+ void *addr, *end;
+
+ /* Last chunk in the allocator */
+ if (chunk == allocator->head && chunk == allocator->tail && !chunk_is_used(chunk)) {
+ addr = (void *)chunk;
+ end = chunk_unmapped(chunk);
+ if (!end)
+ end = allocator->end;
+ goto end;
+ }
+
+ next = chunk_get_next(chunk);
+
+ /* Last chunk in the list we can reclaim, even if used */
+ if (!next) {
+ addr = chunk_data(chunk) + chunk_used_size(chunk, allocator);
+ addr = PTR_ALIGN(addr, PAGE_SIZE);
+ end = chunk_unmapped(chunk);
+ if (!end)
+ end = allocator->end;
+ goto end;
+ }
+
+ if (chunk_is_used(chunk))
+ return 0;
+
+ addr = PTR_ALIGN(chunk_data(chunk), PAGE_SIZE);
+ end = chunk_unmapped(chunk);
+ if (!end)
+ end = PTR_ALIGN_DOWN(next, PAGE_SIZE);
+
+end:
+ if (addr >= end)
+ return 0;
+
+ if (__end)
+ *__end = (u64)end;
+ if (__addr)
+ *__addr = (u64)addr;
+
+ return (end - addr) >> PAGE_SHIFT;
+}
+
+static void hyp_allocator_reclaim_chunk(struct hyp_allocator *allocator, struct chunk_hdr *chunk,
+ void *addr, void *end)
+{
+ struct chunk_hdr *next;
+
+ WARN_ON(end <= addr);
+
+ /* We are about to destroy the last chunk in the allocator */
+ if (addr == allocator->start) {
+ allocator->tail = allocator->head = chunk = NULL;
+ goto unmap;
+ }
+
+ next = chunk_get_next(chunk);
+
+ /*
+ * Split the reclaimed chunk at the next page boundary,
+ * this ensures no orphan mapped region is created. Splitting at the page boundary is always
+ * possible because chunks always leave a minimum distance to the page start.
+ *
+ * +--------------+
+ * |______________|
+ * |______________|<- Next chunk
+ * |_ _ _ __ _ _ _|
+ * | |<- Page-aligned split
+ * +--------------+
+ * +--------------+
+ * | |
+ * | |<- Page reclaimed
+ * | |
+ * | |
+ * +--------------+
+ * +--------------+
+ * | |
+ * |______________|
+ * |______________|<- Chunk to split
+ * | |
+ * +--------------+
+ */
+ if (next && !chunk_unmapped(chunk) && next != end)
+ WARN_ON(IS_ERR_OR_NULL(hyp_allocator_create_chunk(allocator, chunk, end, next,
+ false)));
+unmap:
+ hyp_allocator_unmap(allocator, chunk, addr, end);
+}
+
+/*
+ * Return the best reclaimable chunk which is the highest chunk in the list
+ * with the biggest reclaimable region.
+ */
+static struct chunk_hdr *hyp_allocator_find_reclaimable_chunk(struct hyp_allocator *allocator,
+ u64 *addr, u64 *end)
+{
+ struct chunk_hdr *chunk, *best_chunk = NULL;
+ unsigned long best_reclaimable = 0;
+
+ chunk = allocator->head;
+ while (chunk) {
+ u64 __addr, __end;
+ unsigned long reclaimable = hyp_allocator_chunk_reclaimable(allocator, chunk,
+ &__addr, &__end);
+
+ /* Favour the top biggest chunks */
+ if (reclaimable && reclaimable >= best_reclaimable) {
+ best_reclaimable = reclaimable;
+ best_chunk = chunk;
+ *addr = __addr;
+ *end = __end;
+ }
+
+ chunk = chunk_get_next(chunk);
+ }
+
+ return best_chunk;
+}
+
+static unsigned long hyp_allocator_drain_memcache(struct hyp_allocator *allocator,
+ struct kvm_hyp_memcache *host_mc,
+ unsigned long target)
+{
+ struct kvm_hyp_memcache *mc = &allocator->mc;
+ unsigned long drained = 0;
+
+ while (target && mc->nr_pages) {
+ void *page = pop_hyp_memcache(mc, hyp_phys_to_virt);
+
+ memset(page, 0, PAGE_SIZE);
+ kvm_flush_dcache_to_poc(page, PAGE_SIZE);
+ push_hyp_memcache(host_mc, page, hyp_virt_to_phys);
+ WARN_ON(__pkvm_hyp_donate_host(hyp_virt_to_pfn(page), 1));
+
+ target--;
+ drained++;
+ }
+
+ return drained;
+}
+
+static void hyp_allocator_reclaim(struct hyp_allocator *allocator, struct kvm_hyp_memcache *host_mc,
+ unsigned long target)
+{
+ if (!target)
+ return;
+
+ guard(hyp_spinlock)(&allocator->lock);
+
+ target -= hyp_allocator_drain_memcache(allocator, host_mc, target);
+ if (!target)
+ return;
+
+ do {
+ unsigned long reclaimable;
+ struct chunk_hdr *chunk;
+ u64 addr, end;
+
+ chunk = hyp_allocator_find_reclaimable_chunk(allocator, &addr, &end);
+ if (!chunk)
+ break;
+
+ reclaimable = min((end - addr) >> PAGE_SHIFT, target);
+ addr = end - (reclaimable << PAGE_SHIFT);
+ hyp_allocator_reclaim_chunk(allocator, chunk, (void *)addr, (void *)end);
+
+ target -= reclaimable;
+ } while (target);
+
+ hyp_allocator_drain_memcache(allocator, host_mc, ULONG_MAX);
+}
+
+static unsigned long hyp_allocator_reclaimable(struct hyp_allocator *allocator)
+{
+ unsigned long reclaimable = 0;
+ struct chunk_hdr *chunk;
+
+ guard(hyp_spinlock)(&allocator->lock);
+
+ chunk = allocator->head;
+ while (chunk) {
+ reclaimable += hyp_allocator_chunk_reclaimable(allocator, chunk, NULL, NULL);
+ chunk = chunk_get_next(chunk);
+ }
+
+ return reclaimable;
+}
+
+static int hyp_allocator_topup(struct hyp_allocator *allocator,
+ struct kvm_hyp_memcache *host_mc)
+{
+ struct kvm_hyp_memcache *alloc_mc = &allocator->mc;
+
+ guard(hyp_spinlock)(&allocator->lock);
+ return refill_memcache(alloc_mc, host_mc->nr_pages + alloc_mc->nr_pages, host_mc);
+}
+
+static u32 hyp_allocator_topup_needed(struct hyp_allocator *allocator)
+{
+ u32 *topup_needed = this_cpu_ptr(allocator->topup_needed);
+ u32 ret = *topup_needed;
+
+ *topup_needed = 0;
+
+ return ret;
+}
+
+static int hyp_allocator_init(struct hyp_allocator *allocator, size_t size)
+{
+ unsigned long start;
+ int ret;
+
+ size = PAGE_ALIGN(size);
+
+ /* constrained by chunk_hdr u32 types */
+ if (size > U32_MAX || !size)
+ return -EINVAL;
+
+ ret = pkvm_alloc_private_va_range(size, &start);
+ if (ret)
+ return ret;
+
+ allocator->first_unmapped = allocator->start = (void *)start;
+ allocator->end = allocator->start + size;
+ hyp_spin_lock_init(&allocator->lock);
+
+ return 0;
+}
+
+static DEFINE_PER_CPU(int, __hyp_allocator_errno);
+static DEFINE_PER_CPU(u32, __hyp_allocator_topup_needed);
+
+static struct hyp_allocator hyp_allocator = {
+ .errno = &__hyp_allocator_errno,
+ .topup_needed = &__hyp_allocator_topup_needed,
+};
+
+/**
+ * hyp_alloc() - Allocate memory from the heap allocator
+ *
+ * @size: Allocation size in bytes.
+ *
+ * Callers must ensure they do not hold pkvm_pgd_lock to avoid deadlocks,
+ * as the allocator may modify the hyp stage-1 page-table.
+ *
+ * Return: A pointer to the allocated memory on success, else NULL.
+ */
+void *hyp_alloc(size_t size)
+{
+ return hyp_allocator_alloc(&hyp_allocator, size);
+}
+
+/**
+ * hyp_free() - Free memory allocated with hyp_alloc()
+ *
+ * @data: Address returned by the original hyp_alloc().
+ *
+ * The use of any other address than one returned by hyp_alloc() will cause a
+ * hypervisor panic.
+ */
+void hyp_free(void *data)
+{
+ hyp_allocator_free(&hyp_allocator, data);
+}
+
+/**
+ * hyp_alloc_errno() - Read the errno on allocation error
+ *
+ * Get the return code from an allocation failure.
+ *
+ * Return: -ENOMEM if the allocator needs a refill from the host, -E2BIG if
+ * there is no VA space left else 0.
+ */
+int hyp_alloc_errno(void)
+{
+ return hyp_allocator_errno(&hyp_allocator);
+}
+
+int hyp_alloc_init(size_t size)
+{
+ return hyp_allocator_init(&hyp_allocator, size);
+}
+
+void hyp_alloc_reclaim(struct kvm_hyp_memcache *mc, unsigned long target)
+{
+ hyp_allocator_reclaim(&hyp_allocator, mc, target);
+}
+
+unsigned long hyp_alloc_reclaimable(void)
+{
+ return hyp_allocator_reclaimable(&hyp_allocator);
+}
+
+int hyp_alloc_topup(struct kvm_hyp_memcache *host_mc)
+{
+ return hyp_allocator_topup(&hyp_allocator, host_mc);
+}
+
+u32 hyp_alloc_topup_needed(void)
+{
+ return hyp_allocator_topup_needed(&hyp_allocator);
+}
diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c
index 75b00c323310..9fd3dcde3557 100644
--- a/arch/arm64/kvm/hyp/nvhe/setup.c
+++ b/arch/arm64/kvm/hyp/nvhe/setup.c
@@ -10,6 +10,7 @@
#include <asm/kvm_pgtable.h>
#include <asm/kvm_pkvm.h>
+#include <nvhe/alloc.h>
#include <nvhe/early_alloc.h>
#include <nvhe/ffa.h>
#include <nvhe/gfp.h>
@@ -363,6 +364,11 @@ int __pkvm_init(phys_addr_t phys, unsigned long size, unsigned long *per_cpu_bas
if (ret)
return ret;
+ /* Arbitrary size, unmapped at boot and only consume VA-space */
+ ret = hyp_alloc_init(SZ_128M);
+ if (ret)
+ return ret;
+
update_nvhe_init_params();
/* Jump in the idmap page to switch to the new page-tables */
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related
* Re: [PATCH v3 1/5] drm/bridge: Implement generic USB Type-C DP HPD bridge
From: Sebastian Reichel @ 2026-07-20 17:59 UTC (permalink / raw)
To: Chaoyi Chen
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Luca Ceresoli, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter,
Sandy Huang, Heiko Stübner, Andy Yan, Vinod Koul,
Chaoyi Chen, Nicolas Frattaroli, linux-kernel, dri-devel,
linux-arm-kernel, linux-rockchip, linux-phy
In-Reply-To: <alpeAqKo72pwOEnX@venus>
[-- Attachment #1: Type: text/plain, Size: 3102 bytes --]
Hi,
On Fri, Jul 17, 2026 at 07:19:29PM +0200, Sebastian Reichel wrote:
> On Fri, Jul 17, 2026 at 03:23:19PM +0800, Chaoyi Chen wrote:
> > From: Chaoyi Chen <chaoyi.chen@rock-chips.com>
> >
> > The HPD function of Type-C DP is implemented through
> > drm_connector_oob_hotplug_event(). For embedded DP, it is required
> > that the DRM connector fwnode corresponds to the Type-C port fwnode.
> >
> > To describe the relationship between the DP controller and the Type-C
> > port device, we usually using drm_bridge to build a bridge chain.
> >
> > Now several USB-C controller drivers have already implemented the DP
> > HPD bridge function provided by aux-hpd-bridge.c, it will build a DP
> > HPD bridge on USB-C connector port device.
> >
> > But this requires the USB-C controller driver to manually register the
> > HPD bridge. If the driver does not implement this feature, the bridge
> > will not be create.
> >
> > So this patch implements a generic DP HPD bridge based on
> > aux-hpd-bridge.c. It will monitor Type-C bus events, and when a
> > Type-C port device containing the DP svid is registered, it will
> > create an HPD bridge for it without the need for the USB-C controller
> > driver to implement it.
> >
> > Signed-off-by: Chaoyi Chen <chaoyi.chen@rock-chips.com>
> > Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> > Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > ---
>
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> Tested-by: Sebastian Reichel <sebastian.reichel@collabora.com> # ArmSom Sige5
>
> I gave this a test together with the RK3588/RK3576 USB-C DP AltMode
> patches I'm working on. As the fusb302 does a manual registration
> for the DRM bridge in its probe function, the bridge is registered
> twice:
>
> root@sige5 # cat /sys/kernel/debug/dri/bridges
> ...
> bridge[1]: drm_aux_hpd_bridge_funcs
> refcount: 4
> type: [10] DP
> OF: /soc/i2c@2ac50000/typec-portc@22/connector:usb-c-connector
> ops: [0x4] hpd
> bridge[2]: drm_aux_hpd_bridge_funcs
> refcount: 2
> type: [10] DP
> OF: /soc/i2c@2ac50000/typec-portc@22/connector:usb-c-connector
> ops: [0x4] hpd
> ...
>
> Apparently the USB-C DP AltMode keeps working, so this just wastes
> a few CPU cycles and some memory. So this can land and then we can
> remove the manual code from the driver as a follow-up step. I also
> gave that a try and things keep working. I won't send the fusb302
> patch for now to ensure its not applied before this patch lands.
The above test was done with a kernel having all config options
built-in (i.e. no modules). Using arm64 defconfig one ends up with
CONFIG_DRM_AUX_HPD_TYPEC_BRIDGE=m
But the resulting 'aux-hpd-typec-dp-bridge' module is not loaded
automatically resulting in missing bridge registration. Running
'modprobe aux-hpd-typec-dp-bridge' manually in the booted system
does not work either as the TypeC controller has already been
registered and no new BUS_NOTIFY_ADD_DEVICE is generated.
Greetings,
-- Sebastian
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH 2/2] arm64: dts: allwinner: a523: Add SPDIF to x96qpro+ device
From: Per Larsson @ 2026-07-20 17:42 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
moderated list:ARM/Allwinner sunXi SoC support,
open list:ARM/Allwinner sunXi SoC support, open list
Cc: Per Larsson
In-Reply-To: <20260720174253.7686-1-per@palvencia.se>
The X96QPro+ TV box uses the PH7 pin for its SPDIF output
Add the relevant bits to the dts now that the dtsi knows about the pin
Signed-off-by: Per Larsson <per@palvencia.se>
---
.../dts/allwinner/sun55i-h728-x96qpro+.dts | 24 +++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts b/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts
index a96927fbdadd..b172985583f8 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts
@@ -44,6 +44,24 @@ reg_vcc3v3: vcc3v3 {
vin-supply = <®_vcc5v>;
regulator-always-on;
};
+
+ sound-spdif {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "spdif-out";
+
+ simple-audio-card,cpu {
+ sound-dai = <&spdif>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&spdif_out>;
+ };
+ };
+
+ spdif_out: spdif-out {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
+ };
};
&ehci0 {
@@ -275,6 +293,12 @@ &r_pio {
vcc-pm-supply = <®_aldo3>;
};
+&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spdif_out_ph_pin>;
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pb_pins>;
--
2.48.1
^ permalink raw reply related
* [PATCH 1/2] arm64: dts: allwinner: a523: Add missing SPDIF pin
From: Per Larsson @ 2026-07-20 17:42 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
moderated list:ARM/Allwinner sunXi SoC support,
open list:ARM/Allwinner sunXi SoC support, open list
Cc: Per Larsson
When spdif support was added for the Allwinner A523 family of SoCs, only
two of the three possible pins were added to the dtsi, since the third
would clash with the first ethernet port (emac0)
However, some devices don't use emac0 and instead use emac1 for the only
available ethernet port, leaving the pin free to use for spdif.
Add the missing pin to the dtsi so such devices can (later) use it
Signed-off-by: Per Larsson <per@palvencia.se>
---
arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
index ca6a16807049..7370e8ed24ec 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
@@ -216,6 +216,13 @@ spdif_out_pb_pin: spdif-pb-pin {
allwinner,pinmux = <2>;
};
+ /omit-if-no-ref/
+ spdif_out_ph_pin: spdif-ph-pin {
+ pins = "PH7";
+ function = "spdif";
+ allwinner,pinmux = <4>;
+ };
+
/omit-if-no-ref/
spdif_out_pi_pin: spdif-pi-pin {
pins = "PI10";
--
2.48.1
^ permalink raw reply related
* Re: [PATCH v2 5/6] media: nxp: imx8-isi: Correct color map between V4L2 and ISI
From: Laurent Pinchart @ 2026-07-20 17:40 UTC (permalink / raw)
To: Guoniu Zhou
Cc: Mauro Carvalho Chehab, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Christian Hemp,
Stefan Riedmueller, Jacopo Mondi, Loic Poulain,
Bryan O'Donoghue, Dong Aisheng, Guoniu Zhou, linux-media, imx,
linux-arm-kernel, linux-kernel, stable
In-Reply-To: <20260720-isi-v2-5-45845bc5d4fa@oss.nxp.com>
Hi Guoniu,
On Mon, Jul 20, 2026 at 11:34:07AM +0800, Guoniu Zhou wrote:
> Fix the ISI input format for the color map V4L2_PIX_FMT_XBGR32 in
> memory-to-memory mode.
>
> Fixes: cf21f328fcaf ("media: nxp: Add i.MX8 ISI driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
Tentatively,
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
I'm running a build to test this change.
> ---
> Changes in v2:
> - Reword commit description for clarity (Frank Li)
> ---
> drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
> index 5eb448f4c26f..05b51b98344b 100644
> --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
> +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
> @@ -151,7 +151,7 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = {
> .fourcc = V4L2_PIX_FMT_XBGR32,
> .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT
> | MXC_ISI_VIDEO_M2M_CAP,
> - .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8,
> + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XRGB8,
> .isi_out_format = CHNL_IMG_CTRL_FORMAT_XRGB888,
> .mem_planes = 1,
> .color_planes = 1,
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH RESEND v4 net-next 13/14] net: enetc: use alloc_etherdev_mqs() to create netdev for VF driver
From: Joe Damato @ 2026-07-20 17:36 UTC (permalink / raw)
To: wei.fang
Cc: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier, imx, netdev, linux-kernel, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <20260720014317.1059359-14-wei.fang@oss.nxp.com>
On Mon, Jul 20, 2026 at 09:43:15AM +0800, wei.fang@oss.nxp.com wrote:
> From: Wei Fang <wei.fang@nxp.com>
>
> The VF driver uses alloc_etherdev_mq() with ENETC_MAX_NUM_TXQS as the
> queue count, which forces the TX and RX queue counts to be equal and
> uses a compile-time constant rather than the actual hardware capability.
>
> After enetc_get_si_caps() is called, si->num_tx_rings and
> si->num_rx_rings reflect the actual number of rings assigned to the VF
> by the PF. For the ENETC VF on LS1028A and the upcoming i.MX95/94, their
> SoCs have no more than 6 CPUs, and the number of TX/RX rings allocated
> to the VF is less than 8.
>
> Therefore, switch to alloc_etherdev_mqs() so that the TX and RX queue
> counts are set independently, each capped at ENETC_MAX_NUM_TXQS, based
> on the actual number of rings assigned to the VF by the PF.
>
> Note that if future SoCs have more than 6 CPUs and more than 6 RX rings
> allocated to VFs, the size of the int_vector array in struct
> enetc_ndev_priv will need to be modified. Similarly, if more than 8 TX
> rings are allocated to each int_vector, ENETC_MAX_NUM_TXQS will also
> need to be modified.
>
> Signed-off-by: Wei Fang <wei.fang@nxp.com>
> ---
> drivers/net/ethernet/freescale/enetc/enetc_vf.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/freescale/enetc/enetc_vf.c b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> index 9cdb0a4d6baf..7dcb4a0246f5 100644
> --- a/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> +++ b/drivers/net/ethernet/freescale/enetc/enetc_vf.c
> @@ -317,7 +317,14 @@ static int enetc_vf_probe(struct pci_dev *pdev,
>
> enetc_get_si_caps(si);
>
> - ndev = alloc_etherdev_mq(sizeof(*priv), ENETC_MAX_NUM_TXQS);
> + /* Currently, the supported SoCs have a max of 6 CPUs and the VFs
> + * have less than 6 RX/TX rings. So no issues for these supported
> + * SoCs, but for future SoCs which have more CPUs or more TX/RX
> + * rings, all the related logic needs to be improved.
> + */
> + ndev = alloc_etherdev_mqs(sizeof(*priv),
> + min(si->num_tx_rings, ENETC_MAX_NUM_TXQS),
> + min(si->num_rx_rings, ENETC_MAX_NUM_TXQS));
Code looks right, but looks almost like a typo. I guess it would read nicer if
ENETC_MAX_NUM_RXQS existed?
That said:
Reviewed-by: Joe Damato <joe@dama.to>
^ permalink raw reply
* [PATCH v3 07/17] KVM: arm64: Add PKVM_HYP_REQ_HYP_ALLOC request
From: Vincent Donnefort @ 2026-07-20 17:15 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel
Cc: joey.gouly, seiden, suzuki.poulose, yuzenghui, catalin.marinas,
will, kernel-team, tabba, qperret, Vincent Donnefort
In-Reply-To: <20260720171513.1415357-1-vdonnefort@google.com>
Introduce a new pkvm_hyp_request type asking the host to top up the pKVM
heap allocator.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 043495f7fc78..b77acfd7d1c8 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -89,6 +89,7 @@ enum __kvm_host_smccc_func {
__KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
+ __KVM_HOST_SMCCC_FUNC___pkvm_hyp_topup,
MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY),
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 6c2497047f8d..99daa985856f 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -17,6 +17,10 @@
#define HYP_MEMBLOCK_REGIONS 128
+enum pkvm_topup_id {
+ PKVM_TOPUP_HYP_ALLOC,
+};
+
int pkvm_init_host_vm(struct kvm *kvm, unsigned long type);
int pkvm_create_hyp_vm(struct kvm *kvm);
bool pkvm_hyp_vm_is_created(struct kvm *kvm);
@@ -201,6 +205,7 @@ struct pkvm_mapping {
enum pkvm_hyp_req_type {
PKVM_HYP_NO_REQ = 0,
+ PKVM_HYP_REQ_HYP_ALLOC,
__PKVM_HYP_REQ_TYPE_MAX,
};
@@ -222,9 +227,13 @@ struct pkvm_hyp_req {
static inline size_t pkvm_hyp_req_arg_size(u8 type)
{
+ struct pkvm_hyp_req *req;
+
switch (type) {
case PKVM_HYP_NO_REQ:
return 0;
+ case PKVM_HYP_REQ_HYP_ALLOC:
+ return sizeof(req->mem);
default:
WARN_ON(1);
}
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index d3c69de698f4..439b91fc8aec 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -15,6 +15,7 @@
#include <asm/kvm_hypevents.h>
#include <asm/kvm_mmu.h>
+#include <nvhe/alloc.h>
#include <nvhe/ffa.h>
#include <nvhe/mem_protect.h>
#include <nvhe/mm.h>
@@ -632,6 +633,30 @@ static void handle___pkvm_finalize_teardown_vm(struct kvm_cpu_context *host_ctxt
cpu_reg(host_ctxt, 1) = __pkvm_finalize_teardown_vm(handle);
}
+static void handle___pkvm_hyp_topup(struct kvm_cpu_context *host_ctxt)
+{
+ DECLARE_REG(enum pkvm_topup_id, id, host_ctxt, 1);
+ DECLARE_REG(phys_addr_t, head, host_ctxt, 2);
+ DECLARE_REG(unsigned long, nr_pages, host_ctxt, 3);
+ struct kvm_hyp_memcache host_mc = {
+ .head = head,
+ .nr_pages = nr_pages,
+ };
+ int ret;
+
+ switch (id) {
+ case PKVM_TOPUP_HYP_ALLOC:
+ ret = hyp_alloc_topup(&host_mc);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ cpu_reg(host_ctxt, 1) = ret;
+ cpu_reg(host_ctxt, 2) = host_mc.head;
+ cpu_reg(host_ctxt, 3) = host_mc.nr_pages;
+}
+
static void handle___tracing_load(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(unsigned long, desc_hva, host_ctxt, 1);
@@ -740,6 +765,7 @@ static const hcall_t host_hcall[] = {
HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
HANDLE_FUNC(__vgic_v5_save_apr),
HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
+ HANDLE_FUNC(__pkvm_hyp_topup),
HANDLE_FUNC(__pkvm_host_share_hyp),
HANDLE_FUNC(__pkvm_host_unshare_hyp),
diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
index a626978dc91f..d26e7435d34d 100644
--- a/arch/arm64/kvm/pkvm.c
+++ b/arch/arm64/kvm/pkvm.c
@@ -88,6 +88,33 @@ void __init kvm_hyp_reserve(void)
hyp_mem_base);
}
+static int pkvm_hyp_topup(enum pkvm_topup_id id, unsigned long nr_pages)
+{
+ struct kvm_hyp_memcache mc;
+ struct arm_smccc_res res;
+ int ret;
+
+ init_hyp_memcache(&mc);
+ ret = topup_hyp_memcache(&mc, nr_pages);
+ if (ret)
+ goto err;
+
+ arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(__pkvm_hyp_topup), id, mc.head,
+ mc.nr_pages, &res);
+ if (WARN_ON_ONCE(res.a0 != SMCCC_RET_SUCCESS)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = res.a1;
+ mc.head = res.a2;
+ mc.nr_pages = res.a3;
+
+err:
+ free_hyp_memcache(&mc);
+ return ret;
+}
+
static void __pkvm_destroy_hyp_vm(struct kvm *kvm)
{
if (pkvm_hyp_vm_is_created(kvm)) {
@@ -599,6 +626,9 @@ static int pkvm_handle_hyp_req(struct pkvm_hyp_req *req)
int ret = -EINVAL;
switch (req->type) {
+ case PKVM_HYP_REQ_HYP_ALLOC:
+ ret = pkvm_hyp_topup(PKVM_TOPUP_HYP_ALLOC, req->mem.nr_pages);
+ break;
}
trace_kvm_handle_pkvm_hyp_req(req, ret);
diff --git a/arch/arm64/kvm/trace_pkvm.h b/arch/arm64/kvm/trace_pkvm.h
index 3966c111e3ad..493225e3282d 100644
--- a/arch/arm64/kvm/trace_pkvm.h
+++ b/arch/arm64/kvm/trace_pkvm.h
@@ -9,9 +9,11 @@
#define TRACE_SYSTEM kvm
TRACE_DEFINE_ENUM(PKVM_HYP_NO_REQ);
+TRACE_DEFINE_ENUM(PKVM_HYP_REQ_HYP_ALLOC);
-#define PKVM_HYP_REQ_TYPES \
- { PKVM_HYP_NO_REQ, "NO_REQ" }
+#define PKVM_HYP_REQ_TYPES \
+ { PKVM_HYP_NO_REQ, "NO_REQ" }, \
+ { PKVM_HYP_REQ_HYP_ALLOC, "HYP_ALLOC" }
TRACE_EVENT(kvm_handle_pkvm_hyp_req,
TP_PROTO(struct pkvm_hyp_req *req, int ret),
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related
* [PATCH v3 06/17] KVM: arm64: Add pkvm_hyp_req infrastructure
From: Vincent Donnefort @ 2026-07-20 17:15 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel
Cc: joey.gouly, seiden, suzuki.poulose, yuzenghui, catalin.marinas,
will, kernel-team, tabba, qperret, Vincent Donnefort, Fuad Tabba
In-Reply-To: <20260720171513.1415357-1-vdonnefort@google.com>
Introduce a struct pkvm_hyp_req to enable the pKVM hypervisor to request
resources from the host.
Provide serialisation helpers to transport these requests via SMCCC
registers (starting from a2):
pkvm_hyp_req_to_smccc() to encode into the SMCCC args.
smccc_to_pkvm_hyp_req() to decode them.
When the hypervisor raises a request, the host must handle it and retry
the HVC. To automate this sequence, introduce the pkvm_call_hyp_req()
macro. This intercepts pending requests, invokes the handler and retries
the HVC.
Additionally, introduce a trace event to track the handling of these
requests.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index 74fedd9c5ff0..6c2497047f8d 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -199,6 +199,95 @@ struct pkvm_mapping {
u64 __subtree_last; /* Internal member for interval tree */
};
+enum pkvm_hyp_req_type {
+ PKVM_HYP_NO_REQ = 0,
+ __PKVM_HYP_REQ_TYPE_MAX,
+};
+
+#define PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX \
+ (sizeof(struct arm_smccc_res) - offsetof(struct arm_smccc_res, a2) - 1)
+
+struct pkvm_hyp_req {
+ u8 type;
+ union {
+ struct {
+ u32 nr_pages;
+ } mem;
+ struct {
+ /* Helper for SMCCC encoding/decoding */
+ u8 args[PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX];
+ } args;
+ };
+};
+
+static inline size_t pkvm_hyp_req_arg_size(u8 type)
+{
+ switch (type) {
+ case PKVM_HYP_NO_REQ:
+ return 0;
+ default:
+ WARN_ON(1);
+ }
+
+ return 0;
+}
+
+/* Encode the pending pkvm_hyp_req type into the SMCCC args */
+static inline void
+pkvm_hyp_req_to_smccc(struct kvm_cpu_context *host_ctxt, struct pkvm_hyp_req *req)
+{
+ u8 *dst, type = req->type;
+ size_t size;
+
+ if (type == PKVM_HYP_NO_REQ || type >= __PKVM_HYP_REQ_TYPE_MAX) {
+ host_ctxt->regs.regs[2] = 0;
+ return;
+ }
+
+ size = pkvm_hyp_req_arg_size(type);
+ if (WARN_ON(size > PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX))
+ return;
+
+ dst = (u8 *)&host_ctxt->regs.regs[2];
+ *dst = type;
+
+ memcpy(dst + 1, &req->args, size);
+}
+
+/* Return true if a pkvm_hyp_req has been decoded from the SMCCC args */
+static inline bool smccc_to_pkvm_hyp_req(struct pkvm_hyp_req *req, struct arm_smccc_res *res)
+{
+ u8 *src = (u8 *)res + offsetof(struct arm_smccc_res, a2);
+ u8 type = *src;
+
+ if (type == PKVM_HYP_NO_REQ || type >= __PKVM_HYP_REQ_TYPE_MAX)
+ return false;
+
+ req->type = type;
+ memcpy(&req->args, src + 1, pkvm_hyp_req_arg_size(type));
+
+ return true;
+}
+
+int __pkvm_handle_smccc_req(struct arm_smccc_res *res);
+
+#define pkvm_call_hyp_req(f, ...) \
+({ \
+ struct arm_smccc_res __res; \
+ int __ret; \
+ do { \
+ __ret = -1; \
+ arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f), ##__VA_ARGS__, &__res); \
+ if (WARN_ON(__res.a0 != SMCCC_RET_SUCCESS)) \
+ break; \
+ __ret = __res.a1; \
+ if (!__ret) \
+ break; \
+ __ret = __pkvm_handle_smccc_req(&__res); \
+ } while (!__ret); \
+ __ret; \
+})
+
int pkvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu,
struct kvm_pgtable_mm_ops *mm_ops);
void pkvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
index d2681da0b629..a626978dc91f 100644
--- a/arch/arm64/kvm/pkvm.c
+++ b/arch/arm64/kvm/pkvm.c
@@ -16,6 +16,9 @@
#include "hyp_constants.h"
+#define CREATE_TRACE_POINTS
+#include "trace_pkvm.h"
+
DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
static struct memblock_region *hyp_memory = kvm_nvhe_sym(hyp_memory);
@@ -590,3 +593,25 @@ bool pkvm_force_reclaim_guest_page(phys_addr_t phys)
return !ret || ret == -EAGAIN;
}
+
+static int pkvm_handle_hyp_req(struct pkvm_hyp_req *req)
+{
+ int ret = -EINVAL;
+
+ switch (req->type) {
+ }
+
+ trace_kvm_handle_pkvm_hyp_req(req, ret);
+
+ return ret;
+}
+
+int __pkvm_handle_smccc_req(struct arm_smccc_res *res)
+{
+ struct pkvm_hyp_req req;
+
+ if (smccc_to_pkvm_hyp_req(&req, res))
+ return pkvm_handle_hyp_req(&req);
+
+ return res->a1;
+}
diff --git a/arch/arm64/kvm/trace_pkvm.h b/arch/arm64/kvm/trace_pkvm.h
new file mode 100644
index 000000000000..3966c111e3ad
--- /dev/null
+++ b/arch/arm64/kvm/trace_pkvm.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#if !defined(_TRACE_PKVM_ARM64_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PKVM_ARM64_KVM_H
+
+#include <linux/tracepoint.h>
+#include <asm/kvm_pkvm.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+
+TRACE_DEFINE_ENUM(PKVM_HYP_NO_REQ);
+
+#define PKVM_HYP_REQ_TYPES \
+ { PKVM_HYP_NO_REQ, "NO_REQ" }
+
+TRACE_EVENT(kvm_handle_pkvm_hyp_req,
+ TP_PROTO(struct pkvm_hyp_req *req, int ret),
+ TP_ARGS(req, ret),
+
+ TP_STRUCT__entry(
+ __field(u8, type)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ __entry->type = req->type;
+ __entry->ret = ret;
+ ),
+
+ TP_printk("type: %s ret: %d",
+ __print_symbolic(__entry->type, PKVM_HYP_REQ_TYPES),
+ __entry->ret)
+);
+
+#endif /* _TRACE_PKVM_ARM64_KVM_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace_pkvm
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
--
2.55.0.229.g6434b31f56-goog
^ permalink raw reply related
* Re: [PATCH] remoteproc: Remove redundant dev_err()/dev_err_probe()
From: Mathieu Poirier @ 2026-07-20 17:33 UTC (permalink / raw)
To: Pan Chuang
Cc: Bjorn Andersson, Paul Cercueil, Matthias Brugger,
AngeloGioacchino Del Regno, Maxime Coquelin, Alexandre Torgue,
open list:REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM, open list,
open list:INGENIC JZ47xx SoCs,
moderated list:ARM/Mediatek SoC support,
moderated list:ARM/Mediatek SoC support,
open list:ARM/QUALCOMM MAILING LIST,
moderated list:ARM/STM32 ARCHITECTURE
In-Reply-To: <20260717065224.600593-1-panchuang@vivo.com>
On Fri, Jul 17, 2026 at 02:52:23PM +0800, Pan Chuang wrote:
> Since commit 55b48e23f5c4 ("genirq/devres: Add error handling in
> devm_request_*_irq()"), devm_request_irq() and devm_request_threaded_irq()
> automatically log detailed error messages on failure. Remove the
> now-redundant driver-specific dev_err() and dev_err_probe() calls.
>
> Signed-off-by: Pan Chuang <panchuang@vivo.com>
> ---
> drivers/remoteproc/da8xx_remoteproc.c | 2 +-
> drivers/remoteproc/ingenic_rproc.c | 4 +---
> drivers/remoteproc/keystone_remoteproc.c | 4 ++--
> drivers/remoteproc/mtk_scp.c | 4 +---
> drivers/remoteproc/qcom_q6v5.c | 20 +++++---------------
> drivers/remoteproc/qcom_sysmon.c | 2 --
> drivers/remoteproc/qcom_wcnss.c | 4 +---
> drivers/remoteproc/stm32_rproc.c | 3 +--
> 8 files changed, 12 insertions(+), 31 deletions(-)
>
Applied.
Thanks,
Mathieu
> diff --git a/drivers/remoteproc/da8xx_remoteproc.c b/drivers/remoteproc/da8xx_remoteproc.c
> index 23fca7176539..006fa7b56727 100644
> --- a/drivers/remoteproc/da8xx_remoteproc.c
> +++ b/drivers/remoteproc/da8xx_remoteproc.c
> @@ -298,7 +298,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
> handle_event, 0, "da8xx-remoteproc",
> rproc);
> if (ret)
> - return dev_err_probe(dev, ret, "devm_request_threaded_irq error\n");
> + return ret;
>
> /*
> * rproc_add() can end up enabling the DSP's clk with the DSP
> diff --git a/drivers/remoteproc/ingenic_rproc.c b/drivers/remoteproc/ingenic_rproc.c
> index 1b78d8ddeacf..252519f48964 100644
> --- a/drivers/remoteproc/ingenic_rproc.c
> +++ b/drivers/remoteproc/ingenic_rproc.c
> @@ -219,10 +219,8 @@ static int ingenic_rproc_probe(struct platform_device *pdev)
>
> ret = devm_request_irq(dev, vpu->irq, vpu_interrupt, IRQF_NO_AUTOEN,
> "VPU", rproc);
> - if (ret < 0) {
> - dev_err(dev, "Failed to request IRQ\n");
> + if (ret < 0)
> return ret;
> - }
>
> ret = devm_rproc_add(dev, rproc);
> if (ret) {
> diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
> index 83763d640c4e..407d6034f748 100644
> --- a/drivers/remoteproc/keystone_remoteproc.c
> +++ b/drivers/remoteproc/keystone_remoteproc.c
> @@ -411,7 +411,7 @@ static int keystone_rproc_probe(struct platform_device *pdev)
> ret = devm_request_irq(dev, ksproc->irq_ring, keystone_rproc_vring_interrupt,
> IRQF_NO_AUTOEN, dev_name(dev), ksproc);
> if (ret)
> - return dev_err_probe(dev, ret, "failed to request vring interrupt\n");
> + return ret;
>
> ksproc->irq_fault = platform_get_irq_byname(pdev, "exception");
> if (ksproc->irq_fault < 0)
> @@ -419,7 +419,7 @@ static int keystone_rproc_probe(struct platform_device *pdev)
> ret = devm_request_irq(dev, ksproc->irq_fault, keystone_rproc_exception_interrupt,
> IRQF_NO_AUTOEN, dev_name(dev), ksproc);
> if (ret)
> - return dev_err_probe(dev, ret, "failed to enable exception interrupt\n");
> + return ret;
>
> ksproc->kick_gpio = devm_gpiod_get(dev, "kick", GPIOD_ASIS);
> ret = PTR_ERR_OR_ZERO(ksproc->kick_gpio);
> diff --git a/drivers/remoteproc/mtk_scp.c b/drivers/remoteproc/mtk_scp.c
> index 436656bdfa8b..9751acc2bf83 100644
> --- a/drivers/remoteproc/mtk_scp.c
> +++ b/drivers/remoteproc/mtk_scp.c
> @@ -1246,10 +1246,8 @@ static struct mtk_scp *scp_rproc_init(struct platform_device *pdev,
> scp_irq_handler, IRQF_ONESHOT,
> pdev->name, scp);
>
> - if (ret) {
> - dev_err(dev, "failed to request irq\n");
> + if (ret)
> goto remove_subdev;
> - }
>
> return scp;
>
> diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
> index 0206a4a19254..1075ef4027b7 100644
> --- a/drivers/remoteproc/qcom_q6v5.c
> +++ b/drivers/remoteproc/qcom_q6v5.c
> @@ -302,10 +302,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
> NULL, q6v5_wdog_interrupt,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> "q6v5 wdog", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
> if (q6v5->fatal_irq < 0)
> @@ -315,10 +313,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
> NULL, q6v5_fatal_interrupt,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> "q6v5 fatal", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
> if (q6v5->ready_irq < 0)
> @@ -328,10 +324,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
> NULL, q6v5_ready_interrupt,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> "q6v5 ready", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
> if (q6v5->handover_irq < 0)
> @@ -342,10 +336,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT |
> IRQF_NO_AUTOEN,
> "q6v5 handover", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire handover IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack");
> if (q6v5->stop_irq < 0)
> @@ -355,10 +347,8 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
> NULL, q6v5_stop_interrupt,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> "q6v5 stop", q6v5);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n");
> + if (ret)
> return ret;
> - }
>
> q6v5->state = devm_qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
> if (IS_ERR(q6v5->state)) {
> diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
> index a0830a48b1f4..61e1038328e8 100644
> --- a/drivers/remoteproc/qcom_sysmon.c
> +++ b/drivers/remoteproc/qcom_sysmon.c
> @@ -662,8 +662,6 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> "q6v5 shutdown-ack", sysmon);
> if (ret) {
> - dev_err(sysmon->dev,
> - "failed to acquire shutdown-ack IRQ\n");
> kfree(sysmon);
> return ERR_PTR(ret);
> }
> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> index 3392c9380202..e9a00efe97f6 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -521,10 +521,8 @@ static int wcnss_request_irq(struct qcom_wcnss *wcnss,
> NULL, thread_fn,
> IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> "wcnss", wcnss);
> - if (ret) {
> - dev_err(&pdev->dev, "request %s IRQ failed\n", name);
> + if (ret)
> return ret;
> - }
>
> /* Return the IRQ number if the IRQ was successfully acquired */
> return irq_number;
> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> index 0e5d64fbe52c..1fe4cdc0a13a 100644
> --- a/drivers/remoteproc/stm32_rproc.c
> +++ b/drivers/remoteproc/stm32_rproc.c
> @@ -682,8 +682,7 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
> err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0,
> dev_name(dev), pdev);
> if (err)
> - return dev_err_probe(dev, err,
> - "failed to request wdg irq\n");
> + return err;
>
> ddata->wdg_irq = irq;
>
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v2 2/6] media: nxp: imx8-isi: Add stream ID validation for crossbar routing
From: Laurent Pinchart @ 2026-07-20 17:32 UTC (permalink / raw)
To: Frank Li
Cc: Guoniu Zhou, Mauro Carvalho Chehab, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Christian Hemp,
Stefan Riedmueller, Jacopo Mondi, Loic Poulain,
Bryan O'Donoghue, Dong Aisheng, Guoniu Zhou, linux-media, imx,
linux-arm-kernel, linux-kernel
In-Reply-To: <al46mfiUE5lr8rRF@SMW015318>
On Mon, Jul 20, 2026 at 10:11:21AM -0500, Frank Li wrote:
> On Mon, Jul 20, 2026 at 11:34:04AM +0800, Guoniu Zhou wrote:
> > Add validation to enforce hardware constraints that were previously
> > missing in the crossbar routing configuration:
> >
> > - SOURCE stream must be 0 (ISI pipes are hardcoded to stream 0)
> >
> > This check complements the existing memory input validation and ensures
> > that all routing configurations respect hardware limitations.
> >
> > Signed-off-by: Guoniu Zhou <guoniu.zhou@oss.nxp.com>
> > ---
> > Changes in v2:
> > - New patch split from v1 1/5: adds stream ID validation on top of
> > for_each_active_route() fix (Frank Li)
> > - Remove incorrect sink_stream validation
> > ---
> > drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c | 14 +++++++++++++-
> > 1 file changed, 13 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
> > index 84871bceb31d..328d08a278ea 100644
> > --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
> > +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
> > @@ -106,8 +106,20 @@ static int __mxc_isi_crossbar_set_routing(struct v4l2_subdev *sd,
> > if (ret)
> > return ret;
> >
> > - /* The memory input can be routed to the first pipeline only. */
> > + /*
> > + * Validate routes against hardware constraints:
> > + * - SOURCE stream must be 0 (pipes are hardcoded to stream 0)
> > + * - Memory input can only route to the first pipeline
> > + */
> > for_each_active_route(routing, route) {
> > + if (route->source_stream != 0) {
> > + dev_dbg(xbar->isi->dev,
>
> it is one error, should be dev_err()?
As this is an error that can be triggered by userspace, we prefer
dev_dbg() to avoid giving unpriviledge userspace a way to flood the
kernel log.
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > + "route to pipe %u must use source_stream=0, got %u\n",
> > + route->source_pad - xbar->num_sinks,
> > + route->source_stream);
> > + return -ENXIO;
> > + }
> > +
> > if (route->sink_pad == xbar->num_sinks - 1 &&
> > route->source_pad != xbar->num_sinks) {
> > dev_dbg(xbar->isi->dev,
--
Regards,
Laurent Pinchart
^ 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