* [PATCH v5 2/4] drm/dp: Add helper to validate DP lane counts
From: Damon Ding @ 2026-06-04 8:52 UTC (permalink / raw)
To: hjc, heiko, andy.yan, maarten.lankhorst, mripard, tzimmermann,
airlied, simona, robh, krzk+dt, conor+dt, andrzej.hajda,
neil.armstrong, rfoss
Cc: Laurent.pinchart, jonas, jernej.skrabec, nicolas.frattaroli,
cristian.ciocaltea, sebastian.reichel, dmitry.baryshkov,
luca.ceresoli, dianders, m.szyprowski, dri-devel, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel, Damon Ding
In-Reply-To: <20260604085220.2862986-1-damon.ding@rock-chips.com>
Add a generic helper function drm_dp_lane_count_is_valid() to check
if a DisplayPort lane count is valid. According to the DP specification,
only 1, 2, or 4 lanes are supported.
This helper avoids duplicating DP lane count validation logic across
individual DisplayPort drivers.
Suggested-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
---
include/drm/display/drm_dp_helper.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h
index 8c2d77a032f0..c904cb480d84 100644
--- a/include/drm/display/drm_dp_helper.h
+++ b/include/drm/display/drm_dp_helper.h
@@ -138,6 +138,12 @@ bool drm_dp_as_sdp_supported(struct drm_dp_aux *aux, const u8 dpcd[DP_RECEIVER_C
int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]);
+static inline bool
+drm_dp_lane_count_is_valid(int lane_count)
+{
+ return lane_count == 1 || lane_count == 2 || lane_count == 4;
+}
+
static inline int
drm_dp_max_link_rate(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
{
--
2.34.1
^ permalink raw reply related
* [PATCH v5 4/4] drm/bridge: analogix_dp: Add support for optional data-lanes mapping
From: Damon Ding @ 2026-06-04 8:52 UTC (permalink / raw)
To: hjc, heiko, andy.yan, maarten.lankhorst, mripard, tzimmermann,
airlied, simona, robh, krzk+dt, conor+dt, andrzej.hajda,
neil.armstrong, rfoss
Cc: Laurent.pinchart, jonas, jernej.skrabec, nicolas.frattaroli,
cristian.ciocaltea, sebastian.reichel, dmitry.baryshkov,
luca.ceresoli, dianders, m.szyprowski, dri-devel, devicetree,
linux-arm-kernel, linux-rockchip, linux-kernel, Damon Ding
In-Reply-To: <20260604085220.2862986-1-damon.ding@rock-chips.com>
Parse the optional 'data-lanes' device tree property to support
custom physical lane mapping configuration.
If no valid configuration is found, fall back to the default
lane map (0, 1, 2, 3) automatically and keep the driver running.
Lane mapping is mainly used for below scenarios:
1. Correct PCB lane swap and differential line routing crossover
without hardware changes;
2. Adapt mismatched lane pin definitions between SoC and eDP panel;
3. Support multiple panel hardware variants on the same board
by configuring data-lanes in device tree only.
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Signed-off-by: Damon Ding <damon.ding@rock-chips.com>
---
Changes in v2:
- Add lane mapping application scenarios in commit message.
Changes in v5:
- Add Reviewed-by tag.
---
.../drm/bridge/analogix/analogix_dp_core.c | 56 +++++++++++++++++++
.../drm/bridge/analogix/analogix_dp_core.h | 4 +-
.../gpu/drm/bridge/analogix/analogix_dp_reg.c | 15 +++--
.../gpu/drm/bridge/analogix/analogix_dp_reg.h | 4 ++
4 files changed, 70 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 9300b0db8785..ea525aa3effd 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1234,6 +1234,59 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
.detect = analogix_dp_bridge_detect,
};
+static int analogix_dp_dt_parse_lanes_map(struct analogix_dp_device *dp)
+{
+ struct video_info *video_info = &dp->video_info;
+ struct device_node *endpoint;
+ u32 tmp[LANE_COUNT4];
+ u32 map[LANE_COUNT4] = {0, 1, 2, 3};
+ bool used[LANE_COUNT4] = {false};
+ int num_lanes;
+ int ret, i;
+
+ memcpy(video_info->lane_map, map, sizeof(map));
+
+ num_lanes = drm_of_get_data_lanes_count_ep(dp->dev->of_node, 1, 0, 1,
+ video_info->max_lane_count);
+ if (num_lanes < 0)
+ return -EINVAL;
+
+ endpoint = of_graph_get_endpoint_by_regs(dp->dev->of_node, 1, -1);
+ if (!endpoint)
+ return -EINVAL;
+
+ ret = of_property_read_u32_array(endpoint, "data-lanes", tmp, num_lanes);
+ of_node_put(endpoint);
+ if (ret)
+ return -EINVAL;
+
+ for (i = 0; i < num_lanes; i++) {
+ if (tmp[i] >= LANE_COUNT4) {
+ dev_dbg(dp->dev, "data-lanes[%d] = %u is out of range\n", i, tmp[i]);
+ return -EINVAL;
+ }
+
+ if (used[tmp[i]]) {
+ dev_dbg(dp->dev, "data-lanes[%d] = %u is duplicate\n", i, tmp[i]);
+ return -EINVAL;
+ }
+
+ used[tmp[i]] = true;
+ map[i] = tmp[i];
+ }
+
+ for (i = 0; i < LANE_COUNT4 && num_lanes < LANE_COUNT4; i++) {
+ if (!used[i])
+ map[num_lanes++] = i;
+ }
+
+ dev_dbg(dp->dev, "Using parsed lane map: <%u %u %u %u>\n", map[0], map[1], map[2], map[3]);
+
+ memcpy(video_info->lane_map, map, sizeof(map));
+
+ return 0;
+}
+
static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
{
struct device_node *dp_node = dp->dev->of_node;
@@ -1270,6 +1323,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
break;
}
+ if (analogix_dp_dt_parse_lanes_map(dp))
+ dev_dbg(dp->dev, "No valid data-lanes found, using default lane map\n");
+
return 0;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 94348c4e3623..a75d0fb8f980 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -137,6 +137,8 @@ struct video_info {
int max_link_rate;
enum link_lane_count_type max_lane_count;
+
+ u32 lane_map[LANE_COUNT4];
};
struct link_train {
@@ -175,7 +177,7 @@ struct analogix_dp_device {
/* analogix_dp_reg.c */
void analogix_dp_enable_video_mute(struct analogix_dp_device *dp, bool enable);
void analogix_dp_stop_video(struct analogix_dp_device *dp);
-void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable);
+void analogix_dp_lane_mapping(struct analogix_dp_device *dp);
void analogix_dp_init_analog_param(struct analogix_dp_device *dp);
void analogix_dp_init_interrupt(struct analogix_dp_device *dp);
void analogix_dp_reset(struct analogix_dp_device *dp);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index ea8401293a23..c1344a3f013a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -48,16 +48,15 @@ void analogix_dp_stop_video(struct analogix_dp_device *dp)
writel(reg, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_1);
}
-void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)
+void analogix_dp_lane_mapping(struct analogix_dp_device *dp)
{
+ u32 *lane_map = dp->video_info.lane_map;
u32 reg;
- if (enable)
- reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
- LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
- else
- reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
- LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+ reg = lane_map[0] << LANE0_MAP_SHIFT;
+ reg |= lane_map[1] << LANE1_MAP_SHIFT;
+ reg |= lane_map[2] << LANE2_MAP_SHIFT;
+ reg |= lane_map[3] << LANE3_MAP_SHIFT;
writel(reg, dp->reg_base + ANALOGIX_DP_LANE_MAP);
}
@@ -140,7 +139,7 @@ void analogix_dp_reset(struct analogix_dp_device *dp)
usleep_range(20, 30);
- analogix_dp_lane_swap(dp, 0);
+ analogix_dp_lane_mapping(dp);
writel(0x0, dp->reg_base + ANALOGIX_DP_SYS_CTL_1);
writel(0x40, dp->reg_base + ANALOGIX_DP_SYS_CTL_2);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 12735139046c..ac914e37089b 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -209,6 +209,10 @@
#define LANE0_MAP_LOGIC_LANE_1 (0x1 << 0)
#define LANE0_MAP_LOGIC_LANE_2 (0x2 << 0)
#define LANE0_MAP_LOGIC_LANE_3 (0x3 << 0)
+#define LANE3_MAP_SHIFT (6)
+#define LANE2_MAP_SHIFT (4)
+#define LANE1_MAP_SHIFT (2)
+#define LANE0_MAP_SHIFT (0)
/* ANALOGIX_DP_ANALOG_CTL_1 */
#define TX_TERMINAL_CTRL_50_OHM (0x1 << 4)
--
2.34.1
^ permalink raw reply related
* Re: [PATCH 1/3] arm64/mm: Simplify SWIOTLB setup in arch_mm_preinit()
From: Aneesh Kumar K.V @ 2026-06-04 8:55 UTC (permalink / raw)
To: Mostafa Saleh, linux-arm-kernel, linux-kernel
Cc: akpm, catalin.marinas, will, rppt, maz, Mostafa Saleh
In-Reply-To: <20260603110522.3331819-2-smostafa@google.com>
Mostafa Saleh <smostafa@google.com> writes:
> At the moment, arch_mm_preinit() checks if the system has limited
> addressing or is running under CCA to enable SWIOTLB, only after to
> be forced to true anyway if it was false due to
> CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC being unconditionally true for
> arm64.
>
> Simplify this logic, by making it clear that SWIOTLB is always used
> but its size depends on the address layout of the system.
>
Reviewed-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> arch/arm64/mm/init.c | 11 ++++-------
> 1 file changed, 4 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
> index 97987f850a33..fcc9c05a8fe6 100644
> --- a/arch/arm64/mm/init.c
> +++ b/arch/arm64/mm/init.c
> @@ -336,25 +336,22 @@ void __init arch_setup_zero_pages(void)
> void __init arch_mm_preinit(void)
> {
> unsigned int flags = SWIOTLB_VERBOSE;
> - bool swiotlb = max_pfn > PFN_DOWN(arm64_dma_phys_limit);
> + bool limited_addressing = max_pfn > PFN_DOWN(arm64_dma_phys_limit);
>
> if (is_realm_world()) {
> - swiotlb = true;
> flags |= SWIOTLB_FORCE;
> - }
> -
> - if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) && !swiotlb) {
> + } else if (!limited_addressing) {
> /*
> * If no bouncing needed for ZONE_DMA, reduce the swiotlb
> * buffer for kmalloc() bouncing to 1MB per 1GB of RAM.
> */
> unsigned long size =
> DIV_ROUND_UP(memblock_phys_mem_size(), 1024);
> +
> swiotlb_adjust_size(min(swiotlb_size_or_default(), size));
> - swiotlb = true;
> }
>
> - swiotlb_init(swiotlb, flags);
> + swiotlb_init(true, flags);
>
> /*
> * Check boundaries twice: Some fundamental inconsistencies can be
> --
> 2.54.0.1032.g2f8565e1d1-goog
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: spi: Add for Nuvoton MA35D1 SoC QSPI Controller
From: Conor Dooley @ 2026-06-04 8:55 UTC (permalink / raw)
To: Chi-Wen Weng
Cc: broonie, robh, krzk+dt, conor+dt, linux-arm-kernel, linux-spi,
devicetree, linux-kernel, cwweng
In-Reply-To: <41914879-5fd0-41dd-b097-2be80096e464@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 787 bytes --]
On Thu, Jun 04, 2026 at 03:07:31PM +0800, Chi-Wen Weng wrote:
> Hi Conor,
>
> Thanks for the review.
>
> > Missing commit message for one, but why can't your Nuvoton mail be used
> > here?
>
> I apologize for the missing commit message; I will add a proper description
> in v2.
>
> Regarding the email address, my Nuvoton mail adds a corporate
> confidentiality disclaimer to outgoing
> external mail, so I use my personal address for sending kernel patches.
This prevents you sending with your work email account, but you can still
set your commit author to your Nuvoton address FWIW.
> Conor Dooley 於 2026/6/3 下午 11:24 寫道:
> > On Wed, Jun 03, 2026 at 12:35:50PM +0800, Chi-Wen Weng wrote:
> > > Signed-off-by: Chi-Wen Weng <cwweng.linux@gmail.com>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH 3/3] arm64/coco: Add pKVM as a CC platform
From: Aneesh Kumar K.V @ 2026-06-04 8:59 UTC (permalink / raw)
To: Mostafa Saleh, linux-arm-kernel, linux-kernel
Cc: akpm, catalin.marinas, will, rppt, maz, Mostafa Saleh
In-Reply-To: <20260603110522.3331819-4-smostafa@google.com>
Mostafa Saleh <smostafa@google.com> writes:
> pKVM does support memory encryption, expose that to the rest of
> the kernel through cc_platform_has()
>
> At the moment, all devices inside the guest are emulated which
> requires its memory to be shared back to the host (decrypted), so
> set force_dma_unencrypted() to always return true.
>
> Although, typically pKVM guests rely on restricted-dma-pools to
> bounce traffic, with this change, it is possible to solely rely on
> the default SWIOTLB for that (assuming the appropriate size is set
> from the command line)
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> This change is critical for the ongoing refactoring of the DMA-API[1]
> that will break protected guests under pKVM with this patch. That is
> due to this rework will make the state of the SWIOTLB and restricted
> dma pools depends on the value returned by cc_platform_has()
>
> [1] https://lore.kernel.org/all/20260522042815.370873-1-aneesh.kumar@kernel.org/
> ---
> arch/arm64/include/asm/hypervisor.h | 13 +++++++++++++
> arch/arm64/include/asm/mem_encrypt.h | 3 ++-
> arch/arm64/kernel/rsi.c | 12 ------------
> arch/arm64/mm/init.c | 15 ++++++++++++++-
> drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c | 3 +++
> 5 files changed, 32 insertions(+), 14 deletions(-)
>
> diff --git a/arch/arm64/include/asm/hypervisor.h b/arch/arm64/include/asm/hypervisor.h
> index a12fd897c877..8889a0ba1ec5 100644
> --- a/arch/arm64/include/asm/hypervisor.h
> +++ b/arch/arm64/include/asm/hypervisor.h
> @@ -3,6 +3,9 @@
> #define _ASM_ARM64_HYPERVISOR_H
>
> #include <asm/xen/hypervisor.h>
> +#include <linux/jump_label.h>
> +
> +DECLARE_STATIC_KEY_FALSE(pkvm_guest);
>
> void kvm_init_hyp_services(void);
> bool kvm_arm_hyp_service_available(u32 func_id);
> @@ -10,8 +13,18 @@ void kvm_arm_target_impl_cpu_init(void);
>
> #ifdef CONFIG_ARM_PKVM_GUEST
> void pkvm_init_hyp_services(void);
> +
> +static inline bool is_protected_kvm_guest(void)
> +{
> + return static_branch_unlikely(&pkvm_guest);
> +}
> #else
> static inline void pkvm_init_hyp_services(void) { };
> +
> +static inline bool is_protected_kvm_guest(void)
> +{
> + return false;
> +}
> #endif
>
> static inline void kvm_arch_init_hyp_services(void)
>
...
> diff --git a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
> index d66291def0f4..26fe9c3f22e3 100644
> --- a/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
> +++ b/drivers/virt/coco/pkvm-guest/arm-pkvm-guest.c
> @@ -17,6 +17,7 @@
> #include <asm/hypervisor.h>
>
> static size_t pkvm_granule;
> +DEFINE_STATIC_KEY_FALSE_RO(pkvm_guest);
>
Do we need EXPORT_SYMBOL on this?
>
> static int arm_smccc_do_one_page(u32 func_id, phys_addr_t phys)
> {
> @@ -120,4 +121,6 @@ void pkvm_init_hyp_services(void)
>
> if (kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_MMIO_GUARD))
> arm64_ioremap_prot_hook_register(&mmio_guard_ioremap_hook);
> +
> + static_branch_enable(&pkvm_guest);
> }
> --
> 2.54.0.1032.g2f8565e1d1-goog
-aneesh
^ permalink raw reply
* Re: [PATCH] clk: rockchip: don't COMPILE_TEST builds on M68K
From: Heiko Stuebner @ 2026-06-04 8:59 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: rosenp, linux-arm-kernel, linux-rockchip, linux-clk,
kernel test robot
In-Reply-To: <CAMuHMdUAoUmCNMBVRGgZzSt9SbZqV6SVW2brkvsBKuHrfWHKvw@mail.gmail.com>
Hi Geert,
Am Donnerstag, 4. Juni 2026, 09:56:04 Mitteleuropäische Sommerzeit schrieb Geert Uytterhoeven:
> On Wed, 3 Jun 2026 at 23:37, Heiko Stuebner <heiko@sntech.de> wrote:
> > Rockchip clock drivers use hash-tables with enums as inputs.
> >
> > M68K does interesting things in its __hash_32() implementation, casting
> > that u32 input to an u16 and therefore triggering warnings like:
> >
> > drivers/clk/rockchip/clk-rk3528.c: note: in included file (through include/linux/hash.h, include/linux/slab.h):
> > arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (18720 becomes 8720)
> > arch/m68k/include/asm/hash.h:57:24: sparse: sparse: cast truncates bits from constant value (1e8e8 becomes e8e8)
> >
> > As M68K should never ever need Rockchip clock drivers, simply disable
> > compile-tests for M68K.
> >
> > Fixes: 7edfb7fb58ee ("clk: rockchip: allow COMPILE_TEST builds")
> > Reported-by: kernel test robot <lkp@intel.com>
> > Closes: https://lore.kernel.org/oe-kbuild-all/202605191434.PQkj2Rki-lkp@intel.com/
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
>
> Thanks for your patch!
>
> > --- a/drivers/clk/rockchip/Kconfig
> > +++ b/drivers/clk/rockchip/Kconfig
> > @@ -4,6 +4,7 @@
> > config COMMON_CLK_ROCKCHIP
> > bool "Rockchip clock controller common support"
> > depends on ARCH_ROCKCHIP || COMPILE_TEST
> > + depends on !M68K
> > default ARCH_ROCKCHIP
> > help
> > Say y here to enable common clock controller for Rockchip platforms.
>
> Obviously this is the wrong fix ;-)
>
> I have sent a better one, fixing the issue for every user:
> "[PATCH] m68k: hash: Use lower_16_bits() helper"
> https://lore.kernel.org/b55e9bd0532c0cad519809c86e0a8400060d75a1.1780559561.git.geert@linux-m68k.org
oh nice - fixing the actual problem instead of working around the
issue. I had no clue about m68k and thus no idea of how to test
anything, so went for the easx "fix" :-)
So thanks for looking into that
Heiko
^ permalink raw reply
* Re: [PATCH 1/3] arm64/mm: Simplify SWIOTLB setup in arch_mm_preinit()
From: Aneesh Kumar K.V @ 2026-06-04 9:03 UTC (permalink / raw)
To: Mostafa Saleh, Mike Rapoport
Cc: linux-arm-kernel, linux-kernel, akpm, catalin.marinas, will, maz
In-Reply-To: <aiAojTDO_FcEG8XC@google.com>
Mostafa Saleh <smostafa@google.com> writes:
> Hi Mike,
>
> On Wed, Jun 03, 2026 at 03:27:52PM +0300, Mike Rapoport wrote:
>> Hi,
>>
>> On Wed, Jun 03, 2026 at 11:05:20AM +0000, Mostafa Saleh wrote:
>> > At the moment, arch_mm_preinit() checks if the system has limited
>> > addressing or is running under CCA to enable SWIOTLB, only after to
>> > be forced to true anyway if it was false due to
>> > CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC being unconditionally true for
>> > arm64.
>> >
>> > Simplify this logic, by making it clear that SWIOTLB is always used
>> > but its size depends on the address layout of the system.
>> >
>> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
>> > ---
>> > arch/arm64/mm/init.c | 11 ++++-------
>> > 1 file changed, 4 insertions(+), 7 deletions(-)
>> >
>> > diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>> > index 97987f850a33..fcc9c05a8fe6 100644
>> > --- a/arch/arm64/mm/init.c
>> > +++ b/arch/arm64/mm/init.c
>> > @@ -336,25 +336,22 @@ void __init arch_setup_zero_pages(void)
>> > void __init arch_mm_preinit(void)
>> > {
>> > unsigned int flags = SWIOTLB_VERBOSE;
>> > - bool swiotlb = max_pfn > PFN_DOWN(arm64_dma_phys_limit);
>> > + bool limited_addressing = max_pfn > PFN_DOWN(arm64_dma_phys_limit);
>> >
>> > if (is_realm_world()) {
>> > - swiotlb = true;
>> > flags |= SWIOTLB_FORCE;
>> > - }
>> > -
>> > - if (IS_ENABLED(CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC) && !swiotlb) {
>> > + } else if (!limited_addressing) {
>>
>> Can realm_world() coexist with limited_addressing? Then the size adjustment
>> is still required.
>
> My guess would be no, my understanding is that CCA guests have niche
> hardware.
>
> However, the check for limited_addressing is negated, we adjust the
> SWIOTLB to be smaller if no bouncing is needed.
> So, if this is a realm world, address space layout is irrelevant as we
> keep the original size which is larger.
>
That’s correct. Realm guests need swiotlb to always be enabled, and we
should not reduce the size of the pool.
>
> Otherwise, this alters the current behaviour.
>
>>
>> I'd also make this more explicit:
>>
>> if (max_pfn > PFN_DOWN(arm64_dma_phys_limit))
>
> Sure, I can drop the bool.
>
-aneesh
^ permalink raw reply
* Re: [PATCH] coresight: ultrasoc-smb: Fix OOB write in smb_sync_perf_buffer()
From: Suzuki K Poulose @ 2026-06-04 9:16 UTC (permalink / raw)
To: Mike Leach, James Clark, Leo Yan, Alexander Shishkin, Qi Liu,
Junhao He, Jonathan Cameron, Junrui Luo
Cc: Suzuki K Poulose, coresight, linux-arm-kernel, linux-kernel,
Yuhao Jiang, stable
In-Reply-To: <SYBPR01MB788156B3380A36835DB22290AF102@SYBPR01MB7881.ausprd01.prod.outlook.com>
On Thu, 04 Jun 2026 15:34:25 +0800, Junrui Luo wrote:
> When the SMB sink is used as a perf AUX sink, smb_update_buffer() calls
> smb_sync_perf_buffer() to copy hardware trace data into the perf AUX ring
> buffer pages. It derives pg_idx = head >> PAGE_SHIFT from @head, which is
> handle->head, and indexes dst_pages[pg_idx]. The pg_idx %= nr_pages
> normalization is only applied after the first loop iteration.
>
> This leaves the initial page index underived from the buffer size, which
> can result in an out-of-bounds write past dst_pages[] when head exceeds
> the AUX buffer size.
>
> [...]
Applied, thanks!
[1/1] coresight: ultrasoc-smb: Fix OOB write in smb_sync_perf_buffer()
https://git.kernel.org/coresight/c/98495b5a4d77
Best regards,
--
Suzuki K Poulose <suzuki.poulose@arm.com>
^ permalink raw reply
* Re: [PATCH v7 05/13] coresight: etm4x: exclude ss_status from drvdata->config
From: Suzuki K Poulose @ 2026-06-04 9:15 UTC (permalink / raw)
To: Yeoreum Yun
Cc: coresight, linux-arm-kernel, linux-kernel, mike.leach,
james.clark, alexander.shishkin, leo.yan, jie.gan
In-Reply-To: <ah1yhaZgddq+8fCW@e129823.arm.com>
On 01/06/2026 12:52, Yeoreum Yun wrote:
> Hi Suzuki,
>
>> On 19/05/2026 16:48, Yeoreum Yun wrote:
>>> The purpose of TRCSSCSRn register is to show status of
>>> the corresponding Single-shot Comparator Control and input supports.
>>> That means writable field's purpose for reset or restore from idle status
>>> not for configuration.
>>>
>>> Therefore, exclude ss_status from drvdata->config and move it to drvdata.
>>
>> TRCSSCSRn has two different types of fields.
>>
>> 1. Capability
>> 2. Status
>>
>> Moving the entire register from "config" to a common dangling place looks
>> like shifting the problem to me.
>>
>> Could we do something like :
>>
>> 1. Split the fields to two.
>> a. Store only the capability information in etmv4_caps. Bits[4:0]
>> b. Store the Status bit in drvdata->config , as it is really matters
>> to the session ? Bits[31:30]
>>
>> Add a helper to write/read the TRCSSSRn which would apply/mask the bits from
>> drvdata->etmv4_caps->fields to the Status/Pending
>
> Well. I'm not sure about whether we need to this.
> When I remind of discussion with Leo, The Status and Pending bits should
> be preserved in the *same* session theoretically However, Unitil today
> In case of *perf* it doesn't keep but always cleared at the time of
> resuming session and this behavior haven't reported any issue yet.
>
> TBH, I don't have any idea how perf could utilise those bits except
> the current use case for the sysfs to show the bit via *status* file.
>
> Futhermore, IMHO, config isn't good place for the Status/Pending bits
> since those fields are not *configrable* fields so I think it would be
> better to locate saving information for the status and pending bits on
> drvdata or by defining other fields.
>
> But, until we find some usage of those bits in perf, I think we can
> delay this separation you suggest and it might be better to keep as-is
> for the purpose of showing the status/pending bits when sysfs session is
> finished.
>
> Am I missing something?
Agreed, this can be cleaned up in a separate series.
Suzuki
>
>>
>> Suzuki
>>
>>>
>>> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
>>> ---
>>> .../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
>>> .../hwtracing/coresight/coresight-etm4x-core.c | 16 +++++++++-------
>>> .../hwtracing/coresight/coresight-etm4x-sysfs.c | 10 +++++-----
>>> drivers/hwtracing/coresight/coresight-etm4x.h | 7 ++++++-
>>> 4 files changed, 20 insertions(+), 14 deletions(-)
>>>
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
>>> index e1a59b434505..9b4947d75fde 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
>>> @@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
>>> off_mask = (offset & GENMASK(11, 5));
>>> do {
>>> CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
>>> - CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
>>> CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
>>> } while (0);
>>> } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> index 53fbc4826628..7783c97b53e8 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>>> @@ -95,7 +95,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
>>> const struct etmv4_caps *caps = &drvdata->caps;
>>> return (n < caps->nr_ss_cmp) && caps->nr_pe_cmp &&
>>> - (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
>>> + (drvdata->ss_status[n] & TRCSSCSRn_PC);
>>> }
>>> u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
>>> @@ -571,11 +571,11 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
>>> etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
>>> for (i = 0; i < caps->nr_ss_cmp; i++) {
>>> - /* always clear status bit on restart if using single-shot */
>>> + /* always clear status and pending bits on restart if using single-shot */
>>> if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
>>> - config->ss_status[i] &= ~TRCSSCSRn_STATUS;
>>> + drvdata->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
>>> etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
>>> - etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
>>> + etm4x_relaxed_write32(csa, drvdata->ss_status[i], TRCSSCSRn(i));
>>> if (etm4x_sspcicrn_present(drvdata, i))
>>> etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
>>> }
>>> @@ -772,6 +772,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
>>> /* Clear configuration from previous run */
>>> memset(config, 0, sizeof(struct etmv4_config));
>>> +
>>> if (attr->exclude_kernel)
>>> config->mode = ETM_MODE_EXCL_KERN;
>>> @@ -1064,7 +1065,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
>>> /* read the status of the single shot comparators */
>>> for (i = 0; i < caps->nr_ss_cmp; i++) {
>>> - config->ss_status[i] =
>>> + drvdata->ss_status[i] =
>>> etm4x_relaxed_read32(csa, TRCSSCSRn(i));
>>> }
>>> @@ -1497,8 +1498,9 @@ static void etm4_init_arch_data(void *info)
>>> */
>>> caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
>>> for (i = 0; i < caps->nr_ss_cmp; i++) {
>>> - drvdata->config.ss_status[i] =
>>> - etm4x_relaxed_read32(csa, TRCSSCSRn(i));
>>> + drvdata->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
>>> + drvdata->ss_status[i] &= (TRCSSCSRn_PC | TRCSSCSRn_DV |
>>> + TRCSSCSRn_DA | TRCSSCSRn_INST);
>>> }
>>> /* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
>>> caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
>>> index 7de3c58a47b4..71e95d152ee6 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
>>> @@ -1829,8 +1829,8 @@ static ssize_t sshot_ctrl_store(struct device *dev,
>>> raw_spin_lock(&drvdata->spinlock);
>>> idx = config->ss_idx;
>>> config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
>>> - /* must clear bit 31 in related status register on programming */
>>> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
>>> + /* must clear bit 31 and 30 in related status register on programming */
>>> + drvdata->ss_status[idx] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
>>> raw_spin_unlock(&drvdata->spinlock);
>>> return size;
>>> }
>>> @@ -1844,7 +1844,7 @@ static ssize_t sshot_status_show(struct device *dev,
>>> struct etmv4_config *config = &drvdata->config;
>>> raw_spin_lock(&drvdata->spinlock);
>>> - val = config->ss_status[config->ss_idx];
>>> + val = drvdata->ss_status[config->ss_idx];
>>> raw_spin_unlock(&drvdata->spinlock);
>>> return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
>>> }
>>> @@ -1879,8 +1879,8 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
>>> raw_spin_lock(&drvdata->spinlock);
>>> idx = config->ss_idx;
>>> config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
>>> - /* must clear bit 31 in related status register on programming */
>>> - config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
>>> + /* must clear bit 31 and 30 in related status register on programming */
>>> + drvdata->ss_status[idx] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
>>> raw_spin_unlock(&drvdata->spinlock);
>>> return size;
>>> }
>>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
>>> index 6d4fbae78448..43db1eb6f8cd 100644
>>> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
>>> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
>>> @@ -213,6 +213,7 @@
>>> #define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
>>> #define TRCSSCSRn_STATUS BIT(31)
>>> +#define TRCSSCSRn_PENDING BIT(30)
>>> #define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
>>> #define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
>>> @@ -730,6 +731,9 @@ static inline u32 etm4_res_sel_pair(u8 res_sel_idx)
>>> #define ETM_DEFAULT_ADDR_COMP 0
>>> #define TRCSSCSRn_PC BIT(3)
>>> +#define TRCSSCSRn_DV BIT(2)
>>> +#define TRCSSCSRn_DA BIT(1)
>>> +#define TRCSSCSRn_INST BIT(0)
>>> /* PowerDown Control Register bits */
>>> #define TRCPDCR_PU BIT(3)
>>> @@ -978,7 +982,6 @@ struct etmv4_config {
>>> u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
>>> u8 ss_idx;
>>> u32 ss_ctrl[ETM_MAX_SS_CMP];
>>> - u32 ss_status[ETM_MAX_SS_CMP];
>>> u32 ss_pe_cmp[ETM_MAX_SS_CMP];
>>> u8 addr_idx;
>>> u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
>>> @@ -1073,6 +1076,7 @@ struct etmv4_save_state {
>>> * @config: structure holding configuration parameters.
>>> * @save_state: State to be preserved across power loss
>>> * @paused: Indicates if the trace unit is paused.
>>> + * @ss_status: The status of the corresponding single-shot comparator.
>>> * @arch_features: Bitmap of arch features of etmv4 devices.
>>> */
>>> struct etmv4_drvdata {
>>> @@ -1092,6 +1096,7 @@ struct etmv4_drvdata {
>>> u64 trfcr;
>>> struct etmv4_config config;
>>> struct etmv4_save_state *save_state;
>>> + u32 ss_status[ETM_MAX_SS_CMP];
>>> DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);
>>> };
>>
>
^ permalink raw reply
* Re: [PATCH v6 3/4] firmware: smccc: arm-cca-guest: Bind the TSM provider to an SMCCC device
From: Suzuki K Poulose @ 2026-06-04 9:18 UTC (permalink / raw)
To: Aneesh Kumar K.V (Arm), linux-coco, linux-arm-kernel,
linux-kernel
Cc: Catalin Marinas, Greg KH, Jeremy Linton, Jonathan Cameron,
Lorenzo Pieralisi, Mark Rutland, Sudeep Holla, Will Deacon,
Steven Price
In-Reply-To: <20260527100233.428018-4-aneesh.kumar@kernel.org>
On 27/05/2026 11:02, Aneesh Kumar K.V (Arm) wrote:
> The Arm CCA guest TSM provider currently binds through the arm-cca-dev
> platform device. Like arm-smccc-trng, this device is not an independent
> platform resource; it is a software representation of the RSI firmware
> service discovered through SMCCC.
>
> Move RSI discovery into the SMCCC firmware driver. When the SMCCC conduit
> is SMC and the RSI ABI version check succeeds, create an arm-rsi-dev SMCCC
> device. Convert the Arm CCA guest TSM provider to an SMCCC driver so it
> binds to that discovered RSI service and keeps module autoloading through
> the SMCCC device id table.
>
> Keep the old arm-cca-dev platform-device registration for now. Userspace
> has used that device as a Realm-guest indicator, so removing it is left to
> a follow-up patch that adds a replacement sysfs ABI.
>
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
> arch/arm64/include/asm/rsi.h | 2 +-
> arch/arm64/kernel/rsi.c | 2 +-
> drivers/firmware/smccc/Makefile | 4 ++
> drivers/firmware/smccc/rmm.c | 25 ++++++++
> drivers/firmware/smccc/rmm.h | 17 ++++++
> drivers/firmware/smccc/smccc.c | 8 +++
> drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
> drivers/virt/coco/arm-cca-guest/Makefile | 2 +
> .../{arm-cca-guest.c => arm-cca.c} | 60 +++++++++----------
> 9 files changed, 89 insertions(+), 32 deletions(-)
> create mode 100644 drivers/firmware/smccc/rmm.c
> create mode 100644 drivers/firmware/smccc/rmm.h
> rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (85%)
>
> diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
> index 88b50d660e85..2d2d363aaaee 100644
> --- a/arch/arm64/include/asm/rsi.h
> +++ b/arch/arm64/include/asm/rsi.h
> @@ -10,7 +10,7 @@
> #include <linux/jump_label.h>
> #include <asm/rsi_cmds.h>
>
> -#define RSI_PDEV_NAME "arm-cca-dev"
> +#define RSI_DEV_NAME "arm-rsi-dev"
>
> DECLARE_STATIC_KEY_FALSE(rsi_present);
>
> diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
> index 92160f2e57ff..da440f71bb64 100644
> --- a/arch/arm64/kernel/rsi.c
> +++ b/arch/arm64/kernel/rsi.c
> @@ -161,7 +161,7 @@ void __init arm64_rsi_init(void)
> }
>
> static struct platform_device rsi_dev = {
> - .name = RSI_PDEV_NAME,
> + .name = "arm-cca-dev",
> .id = PLATFORM_DEVID_NONE
> };
>
> diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
> index 40d19144a860..33c850aaff4d 100644
> --- a/drivers/firmware/smccc/Makefile
> +++ b/drivers/firmware/smccc/Makefile
> @@ -2,3 +2,7 @@
> #
> obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
> obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
> +
> +ifeq ($(CONFIG_HAVE_ARM_SMCCC_DISCOVERY),y)
> +obj-$(CONFIG_ARM64) += rmm.o
> +endif
> diff --git a/drivers/firmware/smccc/rmm.c b/drivers/firmware/smccc/rmm.c
> new file mode 100644
> index 000000000000..d572f47e955c
> --- /dev/null
> +++ b/drivers/firmware/smccc/rmm.c
> @@ -0,0 +1,25 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Arm Limited
> + */
> +
> +#include <linux/arm-smccc-bus.h>
> +#include <linux/err.h>
> +#include <linux/printk.h>
> +
> +#include "rmm.h"
> +
> +void __init register_rsi_device(void)
minor nit: Could we rename this global symbol to scope it under rmm ?
perhaps, rmm_register_rsi_device()?
> +{
> + unsigned long ret;
> +
> + if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
> + return;
> +
> + ret = rsi_request_version(RSI_ABI_VERSION, NULL, NULL);
> + if (ret != RSI_SUCCESS)
> + return;
> +
> + if (IS_ERR(arm_smccc_device_register(RSI_DEV_NAME)))
> + pr_err("%s: could not register device\n", RSI_DEV_NAME);
> +}
> diff --git a/drivers/firmware/smccc/rmm.h b/drivers/firmware/smccc/rmm.h
> new file mode 100644
> index 000000000000..627098e2ae1f
> --- /dev/null
> +++ b/drivers/firmware/smccc/rmm.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _SMCCC_RMM_H
> +#define _SMCCC_RMM_H
> +
> +#include <linux/init.h>
> +
> +#ifdef CONFIG_ARM64
> +#include <linux/arm-smccc-bus.h>
> +#include <asm/rsi_cmds.h>
minor nit: Could the header files be moved to rmm.c ?
> +void __init register_rsi_device(void);
> +#else
> +
> +static inline void __init register_rsi_device(void)
> +{
> +}
> +#endif
> +#endif
> diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
> index 6d260354d0f9..888e7f1d6f86 100644
> --- a/drivers/firmware/smccc/smccc.c
> +++ b/drivers/firmware/smccc/smccc.c
> @@ -15,6 +15,8 @@
>
> #include <asm/archrandom.h>
>
> +#include "rmm.h"
> +
> static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
> static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
> static DEFINE_IDA(arm_smccc_bus_id);
> @@ -240,6 +242,12 @@ subsys_initcall(arm_smccc_bus_init);
>
> static int __init smccc_devices_init(void)
> {
> + /*
> + * Register the RMI and RSI devices only when firmware exposes
> + * the required SMCCC function IDs at a supported revision.
> + */
> + register_rsi_device();
nit: We don't have RMI devices yet ? Do we want to make it
rmm_register_devices();
instead ?
> +
> if (smccc_trng_available) {
> struct arm_smccc_device *sdev;
>
> diff --git a/drivers/virt/coco/arm-cca-guest/Kconfig b/drivers/virt/coco/arm-cca-guest/Kconfig
> index 3f0f013f03f1..ad7538750c5a 100644
> --- a/drivers/virt/coco/arm-cca-guest/Kconfig
> +++ b/drivers/virt/coco/arm-cca-guest/Kconfig
> @@ -1,6 +1,7 @@
> config ARM_CCA_GUEST
> tristate "Arm CCA Guest driver"
> depends on ARM64
> + depends on HAVE_ARM_SMCCC_DISCOVERY
> select TSM_REPORTS
> help
> The driver provides userspace interface to request and
> diff --git a/drivers/virt/coco/arm-cca-guest/Makefile b/drivers/virt/coco/arm-cca-guest/Makefile
> index 69eeba08e98a..75a120e24fda 100644
> --- a/drivers/virt/coco/arm-cca-guest/Makefile
> +++ b/drivers/virt/coco/arm-cca-guest/Makefile
> @@ -1,2 +1,4 @@
> # SPDX-License-Identifier: GPL-2.0-only
> obj-$(CONFIG_ARM_CCA_GUEST) += arm-cca-guest.o
> +
> +arm-cca-guest-y += arm-cca.o
> diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca.c
> similarity index 85%
> rename from drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
> rename to drivers/virt/coco/arm-cca-guest/arm-cca.c
> index 66d00b6ceb78..8d5a09bd772a 100644
> --- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
> +++ b/drivers/virt/coco/arm-cca-guest/arm-cca.c
> @@ -4,6 +4,7 @@
> */
>
> #include <linux/arm-smccc.h>
> +#include <linux/arm-smccc-bus.h>
> #include <linux/cc_platform.h>
> #include <linux/kernel.h>
> #include <linux/mod_devicetable.h>
> @@ -182,52 +183,51 @@ static int arm_cca_report_new(struct tsm_report *report, void *data)
> return ret;
> }
>
> -static const struct tsm_report_ops arm_cca_tsm_ops = {
> +static const struct tsm_report_ops arm_cca_tsm_report_ops = {
> .name = KBUILD_MODNAME,
> .report_new = arm_cca_report_new,
> };
>
Would you like to either :
1) Call out renaming the existing cca_tsm to reflect cca_tsm_report
in the commit description ?
OR
2) Split the renaming of the "report" stuff in a follow up patch ?
Rest looks fine by me.
Suzuki
> -/**
> - * arm_cca_guest_init - Register with the Trusted Security Module (TSM)
> - * interface.
> - *
> - * Return:
> - * * %0 - Registered successfully with the TSM interface.
> - * * %-ENODEV - The execution context is not an Arm Realm.
> - * * %-EBUSY - Already registered.
> - */
> -static int __init arm_cca_guest_init(void)
> +static void unregister_cca_tsm_report(void *data)
> +{
> + tsm_report_unregister(&arm_cca_tsm_report_ops);
> +}
> +
> +static int cca_tsm_probe(struct arm_smccc_device *sdev)
> {
> int ret;
>
> if (!is_realm_world())
> return -ENODEV;
>
> - ret = tsm_report_register(&arm_cca_tsm_ops, NULL);
> - if (ret < 0)
> - pr_err("Error %d registering with TSM\n", ret);
> + ret = tsm_report_register(&arm_cca_tsm_report_ops, NULL);
> + if (ret < 0) {
> + dev_err_probe(&sdev->dev, ret, "Error registering with TSM\n");
> + return ret;
> + }
>
> - return ret;
> -}
> -module_init(arm_cca_guest_init);
> + ret = devm_add_action_or_reset(&sdev->dev, unregister_cca_tsm_report,
> + NULL);
> + if (ret < 0) {
> + dev_err_probe(&sdev->dev, ret, "Error registering devm action\n");
> + return ret;
> + }
>
> -/**
> - * arm_cca_guest_exit - unregister with the Trusted Security Module (TSM)
> - * interface.
> - */
> -static void __exit arm_cca_guest_exit(void)
> -{
> - tsm_report_unregister(&arm_cca_tsm_ops);
> + return 0;
> }
> -module_exit(arm_cca_guest_exit);
>
> -/* modalias, so userspace can autoload this module when RSI is available */
> -static const struct platform_device_id arm_cca_match[] __maybe_unused = {
> - { RSI_PDEV_NAME, 0},
> - { }
> +static const struct arm_smccc_device_id cca_tsm_id_table[] = {
> + { .name = RSI_DEV_NAME },
> + {}
> };
> +MODULE_DEVICE_TABLE(arm_smccc, cca_tsm_id_table);
>
> -MODULE_DEVICE_TABLE(platform, arm_cca_match);
> +static struct arm_smccc_driver cca_tsm_driver = {
> + .name = KBUILD_MODNAME,
> + .probe = cca_tsm_probe,
> + .id_table = cca_tsm_id_table,
> +};
> +module_arm_smccc_driver(cca_tsm_driver);
> MODULE_AUTHOR("Sami Mujawar <sami.mujawar@arm.com>");
> MODULE_DESCRIPTION("Arm CCA Guest TSM Driver");
> MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH 3/4] arm64: mte: Disregard the zero page explicitly for manipulating tags
From: Catalin Marinas @ 2026-06-04 9:19 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-arm-kernel, linux-kernel, will, maz, Ard Biesheuvel,
Kevin Brodsky, Mark Brown, David Hildenbrand
In-Reply-To: <20260603160949.3372482-9-ardb+git@google.com>
On Wed, Jun 03, 2026 at 06:09:53PM +0200, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> The zero page is conceptually immutable, and will be moved into .rodata
> to prevent inadvertent corruption.
>
> Prepare the MTE code for this, by ensuring that the zero page is never
> taken into account for tag manipulation, given that those actions will
> no longer be permitted on the read-only alias of .rodata in the linear
> map.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
> arch/arm64/include/asm/mte.h | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h
> index 7f7b97e09996..093b34944aee 100644
> --- a/arch/arm64/include/asm/mte.h
> +++ b/arch/arm64/include/asm/mte.h
> @@ -80,6 +80,11 @@ static inline bool page_mte_tagged(struct page *page)
> */
> static inline bool try_page_mte_tagging(struct page *page)
> {
> + extern struct page *__zero_page;
> +
> + if (page == __zero_page)
> + return false;
Better as is_zero_page()
> +
> VM_WARN_ON_ONCE(folio_test_hugetlb(page_folio(page)));
>
> if (!test_and_set_bit(PG_mte_lock, &page->flags.f))
Some form of this fix should have:
Fixes: f620d66af316 ("arm64: mte: Do not flag the zero page as PG_mte_tagged")
Cc: <stable@vger.kernel.org> # 5.10.x
The current mainline assumption is that mapping the zero page in user
space is always mapped with pte_special() and we skip the MTE tag
zeroing (and PG flag setting). However, the above commit missed the KVM
kvm_s2_fault_map() -> sanitise_mte_tags() path and we don't have a form
of pte_special() for stage 2 mappings.
I'm more inclined to go with a specific test in the KVM path. It matches
the stage 1 where we skip the actual tagging. We could add a
VM_WARN_ONCE in try_page_mte_tagging() to trap future changes.
-------------8<-----------------------
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index d089c107d9b7..445d6cf035c9 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1479,6 +1479,11 @@ static void sanitise_mte_tags(struct kvm *kvm, kvm_pfn_t pfn,
if (!kvm_has_mte(kvm))
return;
+ if (is_zero_pfn(pfn)) {
+ WARN_ON_ONCE(nr_pages != 1);
+ return;
+ }
+
if (folio_test_hugetlb(folio)) {
/* Hugetlb has MTE flags set on head page only */
if (folio_try_hugetlb_mte_tagging(folio)) {
--
Catalin
^ permalink raw reply related
* Re: [PATCH net-next v9 6/6] net: airoha: Support multiple LAN/WAN interfaces for hw MAC address configuration
From: Lorenzo Bianconi @ 2026-06-04 9:20 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Christian Marangi, Benjamin Larsson, linux-arm-kernel,
linux-mediatek, netdev, devicetree, Madhur Agrawal
In-Reply-To: <20260603-airoha-eth-multi-serdes-v9-6-5d476bc2f426@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 7479 bytes --]
On Jun 03, Lorenzo Bianconi wrote:
> The EN7581 and AN7583 SoCs provide registers to configure hardware LAN/WAN
> MAC addresses. These registers are used during FE hw acceleration to
> determine whether received traffic is destined to this host (L3 traffic)
> or should be switched to another device (L2 traffic).
> The SoC hardware design assumes all interfaces configured as LAN (or WAN)
> share the MAC address MSBs, which are programmed into the
> REG_FE_{LAN,WAN}_MAC_H register. The LSBs of 'local' mac addresses can be
> expressed as a range via the REG_FE_MAC_LMIN and REG_FE_MAC_LMAX
> registers. In order to properly accelerate the traffic, FE module requires
> the user to configure the REG_FE_{LAN,WAN}_MAC_H register respecting this
> limitation. Please note a misconfiguration in REG_FE_{LAN,WAN}_MAC_H
> will still allow the user to log into the device for debugging.
> Previously, only a single interface was considered when programming these
> registers. Extend the logic to derive the correct minimum and maximum
> values for REG_FE_MAC_LMIN/REG_FE_MAC_LMAX when two or more interfaces are
> configured as LAN or WAN. Since this functionality was not available
> before this series, no regression is introduced.
Commenting on sashiko's report:
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260603-airoha-eth-multi-serdes-v9-0-5d476bc2f426%40kernel.org
- How does this validation interact with the init path?
In airoha_alloc_gdm_device(), interfaces lacking a DT MAC fall back to
eth_hw_addr_random(), and airoha_dev_init() calls airoha_set_macaddr()
but discards the int return, so a netdev whose initial MAC would fail
the new MSB check still proceeds to register and reaches NETREG_REGISTERED.
- This is done on purpose to not block the device probe and allow the user
to log into the system, and based on the syslog, fix the issue manually.
Regards,
Lorenzo
>
> Tested-by: Madhur Agrawal <madhur.agrawal@airoha.com>
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 77 ++++++++++++++++++++++++++++----
> drivers/net/ethernet/airoha/airoha_eth.h | 2 +-
> drivers/net/ethernet/airoha/airoha_ppe.c | 4 +-
> 3 files changed, 71 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 64ee526da241..8f2608293bb7 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -71,20 +71,76 @@ static void airoha_qdma_irq_disable(struct airoha_irq_bank *irq_bank,
> airoha_qdma_set_irqmask(irq_bank, index, mask, 0);
> }
>
> -static void airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr)
> +static int airoha_set_macaddr(struct airoha_gdm_dev *dev, const u8 *addr)
> {
> + u8 ref_addr[ETH_ALEN] __aligned(2);
> struct airoha_eth *eth = dev->eth;
> - u32 val, reg;
> + u32 reg, val, lmin, lmax;
> + int i;
> +
> + eth_zero_addr(ref_addr);
> + lmin = (addr[3] << 16) | (addr[4] << 8) | addr[5];
> + lmax = lmin;
> +
> + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
> + struct airoha_gdm_port *port = eth->ports[i];
> + int j;
> +
> + if (!port)
> + continue;
> +
> + for (j = 0; j < ARRAY_SIZE(port->devs); j++) {
> + struct airoha_gdm_dev *iter_dev;
> + struct net_device *netdev;
> +
> + iter_dev = port->devs[j];
> + if (!iter_dev || iter_dev == dev)
> + continue;
> +
> + if (airoha_is_lan_gdm_dev(iter_dev) !=
> + airoha_is_lan_gdm_dev(dev))
> + continue;
> +
> + netdev = netdev_from_priv(iter_dev);
> + if (netdev->reg_state != NETREG_REGISTERED)
> + continue;
> +
> + ether_addr_copy(ref_addr, netdev->dev_addr);
> + val = (netdev->dev_addr[3] << 16) |
> + (netdev->dev_addr[4] << 8) | netdev->dev_addr[5];
> + if (val < lmin)
> + lmin = val;
> + if (val > lmax)
> + lmax = val;
> + }
> + }
> +
> + if (!is_zero_ether_addr(ref_addr) && memcmp(ref_addr, addr, 3)) {
> + /* According to the HW design, hw mac address MSBs must be
> + * the same for each net_device with the same LAN/WAN
> + * configuration.
> + */
> + struct net_device *netdev = netdev_from_priv(dev);
> +
> + dev_warn(eth->dev,
> + "%s: wrong mac addr, MSBs must be %02x:%02x:%02x\n",
> + netdev->name, ref_addr[0], ref_addr[1],
> + ref_addr[2]);
> + dev_warn(eth->dev, "FE hw forwarding won't work properly\n");
> +
> + return -EINVAL;
> + }
>
> reg = airoha_is_lan_gdm_dev(dev) ? REG_FE_LAN_MAC_H : REG_FE_WAN_MAC_H;
> val = (addr[0] << 16) | (addr[1] << 8) | addr[2];
> airoha_fe_wr(eth, reg, val);
>
> - val = (addr[3] << 16) | (addr[4] << 8) | addr[5];
> - airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), val);
> - airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), val);
> + airoha_fe_wr(eth, REG_FE_MAC_LMIN(reg), lmin);
> + airoha_fe_wr(eth, REG_FE_MAC_LMAX(reg), lmax);
>
> - airoha_ppe_init_upd_mem(dev);
> + airoha_ppe_init_upd_mem(dev, addr);
> +
> + return 0;
> }
>
> static void airoha_set_gdm_port_fwd_cfg(struct airoha_eth *eth, u32 addr,
> @@ -1826,13 +1882,18 @@ static int airoha_dev_stop(struct net_device *netdev)
> static int airoha_dev_set_macaddr(struct net_device *netdev, void *p)
> {
> struct airoha_gdm_dev *dev = netdev_priv(netdev);
> + struct sockaddr *addr = p;
> int err;
>
> - err = eth_mac_addr(netdev, p);
> + err = eth_prepare_mac_addr_change(netdev, p);
> if (err)
> return err;
>
> - airoha_set_macaddr(dev, netdev->dev_addr);
> + err = airoha_set_macaddr(dev, addr->sa_data);
> + if (err)
> + return err;
> +
> + eth_commit_mac_addr_change(netdev, p);
>
> return 0;
> }
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> index 3e8262f583a7..8f42973f9cf5 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.h
> +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> @@ -683,7 +683,7 @@ void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
> int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, void *type_data);
> int airoha_ppe_init(struct airoha_eth *eth);
> void airoha_ppe_deinit(struct airoha_eth *eth);
> -void airoha_ppe_init_upd_mem(struct airoha_gdm_dev *dev);
> +void airoha_ppe_init_upd_mem(struct airoha_gdm_dev *dev, const u8 *addr);
> u32 airoha_ppe_get_total_num_entries(struct airoha_ppe *ppe);
> struct airoha_foe_entry *airoha_ppe_foe_get_entry(struct airoha_ppe *ppe,
> u32 hash);
> diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
> index f54622904733..91bcc55a6ac6 100644
> --- a/drivers/net/ethernet/airoha/airoha_ppe.c
> +++ b/drivers/net/ethernet/airoha/airoha_ppe.c
> @@ -1487,12 +1487,10 @@ void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
> airoha_ppe_foe_insert_entry(ppe, skb, hash, rx_wlan);
> }
>
> -void airoha_ppe_init_upd_mem(struct airoha_gdm_dev *dev)
> +void airoha_ppe_init_upd_mem(struct airoha_gdm_dev *dev, const u8 *addr)
> {
> - struct net_device *netdev = netdev_from_priv(dev);
> struct airoha_gdm_port *port = dev->port;
> struct airoha_eth *eth = dev->eth;
> - const u8 *addr = netdev->dev_addr;
> u32 val;
>
> val = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5];
>
> --
> 2.54.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v6 3/4] firmware: smccc: arm-cca-guest: Bind the TSM provider to an SMCCC device
From: Sudeep Holla @ 2026-06-04 9:21 UTC (permalink / raw)
To: Aneesh Kumar K.V (Arm)
Cc: linux-coco, linux-arm-kernel, linux-kernel, Catalin Marinas,
Sudeep Holla, Greg KH, Jeremy Linton, Jonathan Cameron,
Lorenzo Pieralisi, Mark Rutland, Will Deacon, Steven Price,
Suzuki K Poulose
In-Reply-To: <20260527100233.428018-4-aneesh.kumar@kernel.org>
On Wed, May 27, 2026 at 03:32:32PM +0530, Aneesh Kumar K.V (Arm) wrote:
> The Arm CCA guest TSM provider currently binds through the arm-cca-dev
> platform device. Like arm-smccc-trng, this device is not an independent
> platform resource; it is a software representation of the RSI firmware
> service discovered through SMCCC.
>
> Move RSI discovery into the SMCCC firmware driver. When the SMCCC conduit
> is SMC and the RSI ABI version check succeeds, create an arm-rsi-dev SMCCC
> device. Convert the Arm CCA guest TSM provider to an SMCCC driver so it
> binds to that discovered RSI service and keeps module autoloading through
> the SMCCC device id table.
>
> Keep the old arm-cca-dev platform-device registration for now. Userspace
> has used that device as a Realm-guest indicator, so removing it is left to
> a follow-up patch that adds a replacement sysfs ABI.
>
> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
> ---
> arch/arm64/include/asm/rsi.h | 2 +-
> arch/arm64/kernel/rsi.c | 2 +-
> drivers/firmware/smccc/Makefile | 4 ++
> drivers/firmware/smccc/rmm.c | 25 ++++++++
> drivers/firmware/smccc/rmm.h | 17 ++++++
> drivers/firmware/smccc/smccc.c | 8 +++
> drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
> drivers/virt/coco/arm-cca-guest/Makefile | 2 +
> .../{arm-cca-guest.c => arm-cca.c} | 60 +++++++++----------
> 9 files changed, 89 insertions(+), 32 deletions(-)
> create mode 100644 drivers/firmware/smccc/rmm.c
> create mode 100644 drivers/firmware/smccc/rmm.h
> rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (85%)
>
> diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
> index 88b50d660e85..2d2d363aaaee 100644
> --- a/arch/arm64/include/asm/rsi.h
> +++ b/arch/arm64/include/asm/rsi.h
> @@ -10,7 +10,7 @@
> #include <linux/jump_label.h>
> #include <asm/rsi_cmds.h>
>
> -#define RSI_PDEV_NAME "arm-cca-dev"
> +#define RSI_DEV_NAME "arm-rsi-dev"
>
> DECLARE_STATIC_KEY_FALSE(rsi_present);
>
> diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
> index 92160f2e57ff..da440f71bb64 100644
> --- a/arch/arm64/kernel/rsi.c
> +++ b/arch/arm64/kernel/rsi.c
> @@ -161,7 +161,7 @@ void __init arm64_rsi_init(void)
> }
>
> static struct platform_device rsi_dev = {
> - .name = RSI_PDEV_NAME,
> + .name = "arm-cca-dev",
> .id = PLATFORM_DEVID_NONE
> };
>
> diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
> index 40d19144a860..33c850aaff4d 100644
> --- a/drivers/firmware/smccc/Makefile
> +++ b/drivers/firmware/smccc/Makefile
> @@ -2,3 +2,7 @@
> #
> obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
> obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
> +
> +ifeq ($(CONFIG_HAVE_ARM_SMCCC_DISCOVERY),y)
> +obj-$(CONFIG_ARM64) += rmm.o
> +endif
> diff --git a/drivers/firmware/smccc/rmm.c b/drivers/firmware/smccc/rmm.c
> new file mode 100644
> index 000000000000..d572f47e955c
> --- /dev/null
> +++ b/drivers/firmware/smccc/rmm.c
> @@ -0,0 +1,25 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Arm Limited
> + */
> +
> +#include <linux/arm-smccc-bus.h>
> +#include <linux/err.h>
> +#include <linux/printk.h>
> +
> +#include "rmm.h"
> +
> +void __init register_rsi_device(void)
> +{
> + unsigned long ret;
> +
> + if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
> + return;
> +
> + ret = rsi_request_version(RSI_ABI_VERSION, NULL, NULL);
> + if (ret != RSI_SUCCESS)
> + return;
> +
> + if (IS_ERR(arm_smccc_device_register(RSI_DEV_NAME)))
> + pr_err("%s: could not register device\n", RSI_DEV_NAME);
> +}
OK, I had something else in my mind when I started looking at 1/4. I didn't
expect each device added on this bus comes up with it's own way to enumerate
it. IMO, it defeats the purpose of building the smccc bus. We may find the
specs for each feature deviated a bit but we can have a generic probe
IMO, let's try that before exploring per feature probe function.
I have a brief sketch of what I think we should aim for(uncompiled/untested)
below. Let me know if that makes sense. I just based it on your bus code.
Regards,
Sudeep
-->8
diff --git c/drivers/firmware/smccc/smccc.c w/drivers/firmware/smccc/smccc.c
index 695c920a8087..450605ddfab6 100644
--- c/drivers/firmware/smccc/smccc.c
+++ w/drivers/firmware/smccc/smccc.c
@@ -9,21 +9,58 @@
#include <linux/init.h>
#include <linux/arm-smccc.h>
#include <linux/kernel.h>
-#include <linux/platform_device.h>
#include <linux/arm-smccc-bus.h>
#include <linux/idr.h>
#include <linux/slab.h>
-#include <asm/archrandom.h>
-
static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
static DEFINE_IDA(arm_smccc_bus_id);
-bool __ro_after_init smccc_trng_available = false;
+struct smccc_device_info {
+ u32 func_id;
+ bool requires_smc;
+ unsigned long min_return;
+ const char *device_name;
+};
+
+bool __ro_after_init smccc_trng_available;
s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED;
s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED;
+static const struct smccc_device_info smccc_devices[] __initconst = {
+ {
+ .func_id = ARM_SMCCC_TRNG_VERSION,
+ .requires_smc = false,
+ .min_return = ARM_SMCCC_TRNG_MIN_VERSION,
+ .device_name = "arm-smccc-trng",
+ },
+};
+
+static bool __init
+smccc_probe_smccc_device(const struct smccc_device_info *smccc_dev)
+{
+ struct arm_smccc_res res;
+ unsigned long ret;
+
+ if (!IS_ENABLED(CONFIG_ARM64))
+ return false;
+
+ if (smccc_conduit == SMCCC_CONDUIT_NONE)
+ return false;
+
+ if (smccc_dev->requires_smc && smccc_conduit != SMCCC_CONDUIT_SMC)
+ return false;
+
+ arm_smccc_1_1_invoke(smccc_dev->func_id, &res);
+ ret = res.a0;
+
+ if ((s32)ret < 0)
+ return false;
+
+ return ret >= smccc_dev->min_return;
+}
+
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
{
struct arm_smccc_res res;
@@ -31,7 +68,7 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
smccc_version = version;
smccc_conduit = conduit;
- smccc_trng_available = smccc_probe_trng();
+ smccc_trng_available = smccc_probe_smccc_device(&smccc_devices[0]);
if ((smccc_version >= ARM_SMCCC_VERSION_1_2) &&
(smccc_conduit != SMCCC_CONDUIT_NONE)) {
@@ -241,14 +278,20 @@ subsys_initcall(arm_smccc_bus_init);
static int __init smccc_devices_init(void)
{
- struct platform_device *pdev;
-
- if (smccc_trng_available) {
- pdev = platform_device_register_simple("smccc_trng", -1,
- NULL, 0);
- if (IS_ERR(pdev))
- pr_err("smccc_trng: could not register device: %ld\n",
- PTR_ERR(pdev));
+ const struct smccc_device_info *smccc_dev;
+ struct arm_smccc_device *sdev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(smccc_devices); i++) {
+ smccc_dev = &smccc_devices[i];
+
+ if (!smccc_probe_smccc_device(smccc_dev))
+ continue;
+
+ sdev = arm_smccc_device_register(smccc_dev->device_name);
+ if (IS_ERR(sdev))
+ pr_err("%s: could not register device: %ld\n",
+ smccc_dev->device_name, PTR_ERR(sdev));
}
return 0;
^ permalink raw reply related
* [PATCH] dma: at_hdmac: Fix use-after-free by proper tasklet cleanup
From: Hongling Zeng @ 2026-06-04 9:23 UTC (permalink / raw)
To: ludovic.desroches, vkoul, Frank.Li, tudor.ambarus, nicolas.ferre
Cc: linux-arm-kernel, dmaengine, linux-kernel, zhongling0719,
Hongling Zeng, sashiko-bot
Current cleanup paths have a use-after-free vulnerability:
- vchan_init() creates tasklets that access at_dma_chan memory
- free_irq() only waits for IRQ handler, NOT tasklets
- atdma is devm-managed and freed after probe/remove
- Running tasklets accessing freed memory → Use-After-Free!
The fix requires careful ordering:
- Disable interrupts FIRST to stop new tasklets from being scheduled
- Then kill tasklets to wait for already-scheduled ones to complete
- Only then free IRQs and other resources
Fixes: ac803b56860f ("dmaengine: at_hdmac: Convert driver to use virt-dma")
Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/all/20260604073945.54B311F00898@smtp.kernel.org/
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
---
drivers/dma/at_hdmac.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index e5b30a57c477..ac45e88e16da 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1940,6 +1940,19 @@ static void at_dma_off(struct at_dma *atdma)
cpu_relax();
}
+static void at_dma_cleanup_channels(struct at_dma *atdma)
+{
+ struct dma_chan *chan, *_chan;
+
+ list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
+ device_node) {
+ /* Disable interrupts */
+ atc_disable_chan_irq(atdma, chan->chan_id);
+ tasklet_kill(&to_at_dma_chan(chan)->vc.task);
+ list_del(&chan->device_node);
+ }
+}
+
static int __init at_dma_probe(struct platform_device *pdev)
{
struct at_dma *atdma;
@@ -2109,6 +2122,7 @@ static int __init at_dma_probe(struct platform_device *pdev)
err_memset_pool_create:
dma_pool_destroy(atdma->lli_pool);
err_desc_pool_create:
+ at_dma_cleanup_channels(atdma);
free_irq(platform_get_irq(pdev, 0), atdma);
err_irq:
clk_disable_unprepare(atdma->clk);
@@ -2125,17 +2139,12 @@ static void at_dma_remove(struct platform_device *pdev)
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&atdma->dma_device);
+ at_dma_cleanup_channels(atdma);
+
dma_pool_destroy(atdma->memset_pool);
dma_pool_destroy(atdma->lli_pool);
free_irq(platform_get_irq(pdev, 0), atdma);
- list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
- device_node) {
- /* Disable interrupts */
- atc_disable_chan_irq(atdma, chan->chan_id);
- list_del(&chan->device_node);
- }
-
clk_disable_unprepare(atdma->clk);
}
--
2.25.1
^ permalink raw reply related
* Re: [PATCH 1/2] dt-bindings: spi: Add for Nuvoton MA35D1 SoC QSPI Controller
From: Chi-Wen Weng @ 2026-06-04 9:25 UTC (permalink / raw)
To: Conor Dooley
Cc: broonie, robh, krzk+dt, conor+dt, linux-arm-kernel, linux-spi,
devicetree, linux-kernel, cwweng
In-Reply-To: <20260604-anthem-jokingly-8d8312ff0c3f@spud>
Hi Conor,
Thanks for the clarification.
I will keep using my personal mail account for sending the patches to
avoid the corporate confidentiality footer, but I will set the commit
author and Signed-off-by to my Nuvoton address in v2.
Best regards,
Chi-Wen
Conor Dooley 於 2026/6/4 下午 04:55 寫道:
> On Thu, Jun 04, 2026 at 03:07:31PM +0800, Chi-Wen Weng wrote:
>> Hi Conor,
>>
>> Thanks for the review.
>>
>>> Missing commit message for one, but why can't your Nuvoton mail be used
>>> here?
>> I apologize for the missing commit message; I will add a proper description
>> in v2.
>>
>> Regarding the email address, my Nuvoton mail adds a corporate
>> confidentiality disclaimer to outgoing
>> external mail, so I use my personal address for sending kernel patches.
> This prevents you sending with your work email account, but you can still
> set your commit author to your Nuvoton address FWIW.
>
>> Conor Dooley 於 2026/6/3 下午 11:24 寫道:
>>> On Wed, Jun 03, 2026 at 12:35:50PM +0800, Chi-Wen Weng wrote:
>>>> Signed-off-by: Chi-Wen Weng <cwweng.linux@gmail.com>
^ permalink raw reply
* [PATCH] KVM: arm64: Fix order of arguments to ktime_get_snapshot_id()
From: Uwe Kleine-König @ 2026-06-04 9:27 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, Thomas Gleixner
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
Catalin Marinas, Will Deacon, Jacob Keller, David Woodhouse,
Vincent Donnefort, linux-arm-kernel, kvmarm, linux-kernel
The first argument to ktime_get_snapshot_id() is the clock ID and the
second output parameter. Fix the caller that reversed the order and thus
fix a compiler error.
Fixes: d09439210441 ("KVM: arm64: Use ktime_get_snapshot_id() to retrieve CLOCK_BOOTTIME")
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
---
arch/arm64/kvm/hyp_trace.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 8574db7491bc..2411b4c32932 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -118,7 +118,7 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
hyp_clock->running = false;
}
- ktime_get_snapshot_id(&snap, CLOCK_BOOTTIME);
+ ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap);
hyp_clock->boot = ktime_to_ns(snap.systime);
hyp_clock->cycles = snap.cycles;
base-commit: d09439210441efbadd8b0aa32c1ddb1eab2f3abd
--
2.47.3
^ permalink raw reply related
* [GIT PULL] Rockchip arm32 fix for the current 7.1-rc
From: Heiko Stuebner @ 2026-06-04 9:27 UTC (permalink / raw)
To: arm; +Cc: soc, linux-rockchip, linux-arm-kernel
Hi SoC maintainers,
please find a below a fix for an issue in the ARCH code for 32bit
Rockchip SoCs, that appeared with 7.1-rc .
Please pull
Thanks
Heiko
The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v7.1-rockchip-arm32fixe
for you to fetch changes up to 6fc5666aa576c6c3bec256fa31d72653210319d5:
ARM: rockchip: keep reset control around (2026-05-26 23:20:39 +0200)
----------------------------------------------------------------
A change in 7.1-rc improved the general handling for reset controllers
using SRCU, but at the same time broke really early users before work-
queues are available.
So adapt the SMP bringup to keep the core-resets around, instead
of aquiring/releasing them on ever SMP action.
----------------------------------------------------------------
Heiko Stuebner (1):
ARM: rockchip: keep reset control around
arch/arm/mach-rockchip/platsmp.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
^ permalink raw reply
* Re: [PATCH 3/4] arm64: mte: Disregard the zero page explicitly for manipulating tags
From: Ard Biesheuvel @ 2026-06-04 9:42 UTC (permalink / raw)
To: Catalin Marinas, Ard Biesheuvel
Cc: linux-arm-kernel, linux-kernel, Will Deacon, maz, Kevin Brodsky,
Mark Brown, David Hildenbrand
In-Reply-To: <aiFDFbeOoxgKigP0@arm.com>
On Thu, 4 Jun 2026, at 11:19, Catalin Marinas wrote:
> On Wed, Jun 03, 2026 at 06:09:53PM +0200, Ard Biesheuvel wrote:
>> From: Ard Biesheuvel <ardb@kernel.org>
>>
>> The zero page is conceptually immutable, and will be moved into .rodata
>> to prevent inadvertent corruption.
>>
>> Prepare the MTE code for this, by ensuring that the zero page is never
>> taken into account for tag manipulation, given that those actions will
>> no longer be permitted on the read-only alias of .rodata in the linear
>> map.
>>
>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>> ---
>> arch/arm64/include/asm/mte.h | 5 +++++
>> 1 file changed, 5 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/mte.h b/arch/arm64/include/asm/mte.h
>> index 7f7b97e09996..093b34944aee 100644
>> --- a/arch/arm64/include/asm/mte.h
>> +++ b/arch/arm64/include/asm/mte.h
>> @@ -80,6 +80,11 @@ static inline bool page_mte_tagged(struct page *page)
>> */
>> static inline bool try_page_mte_tagging(struct page *page)
>> {
>> + extern struct page *__zero_page;
>> +
>> + if (page == __zero_page)
>> + return false;
>
> Better as is_zero_page()
>
True, but I was concerned about #inclusion hell.
>> +
>> VM_WARN_ON_ONCE(folio_test_hugetlb(page_folio(page)));
>>
>> if (!test_and_set_bit(PG_mte_lock, &page->flags.f))
>
> Some form of this fix should have:
>
> Fixes: f620d66af316 ("arm64: mte: Do not flag the zero page as PG_mte_tagged")
> Cc: <stable@vger.kernel.org> # 5.10.x
>
> The current mainline assumption is that mapping the zero page in user
> space is always mapped with pte_special() and we skip the MTE tag
> zeroing (and PG flag setting). However, the above commit missed the KVM
> kvm_s2_fault_map() -> sanitise_mte_tags() path and we don't have a form
> of pte_special() for stage 2 mappings.
>
> I'm more inclined to go with a specific test in the KVM path. It matches
> the stage 1 where we skip the actual tagging. We could add a
> VM_WARN_ONCE in try_page_mte_tagging() to trap future changes.
>
Let's go with that - I'll turn this into a patch for v2
> -------------8<-----------------------
> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
> index d089c107d9b7..445d6cf035c9 100644
> --- a/arch/arm64/kvm/mmu.c
> +++ b/arch/arm64/kvm/mmu.c
> @@ -1479,6 +1479,11 @@ static void sanitise_mte_tags(struct kvm *kvm,
> kvm_pfn_t pfn,
> if (!kvm_has_mte(kvm))
> return;
>
> + if (is_zero_pfn(pfn)) {
> + WARN_ON_ONCE(nr_pages != 1);
> + return;
> + }
> +
> if (folio_test_hugetlb(folio)) {
> /* Hugetlb has MTE flags set on head page only */
> if (folio_try_hugetlb_mte_tagging(folio)) {
>
> --
> Catalin
^ permalink raw reply
* Re: [PATCH] KVM: arm64: Fix order of arguments to ktime_get_snapshot_id()
From: Thomas Gleixner @ 2026-06-04 9:49 UTC (permalink / raw)
To: Uwe Kleine-König, Marc Zyngier, Oliver Upton
Cc: Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
Catalin Marinas, Will Deacon, Jacob Keller, David Woodhouse,
Vincent Donnefort, linux-arm-kernel, kvmarm, linux-kernel
In-Reply-To: <20260604092714.1537457-2-ukleinek@kernel.org>
On Thu, Jun 04 2026 at 11:27, Uwe Kleine-König wrote:
> The first argument to ktime_get_snapshot_id() is the clock ID and the
> second output parameter. Fix the caller that reversed the order and thus
> fix a compiler error.
I've already squashed a fix earlier today
^ permalink raw reply
* [PATCH 1/2] dt-bindings: phy: nuvoton: Add MA35D1 USB2 OTG PHY binding
From: Joey Lu @ 2026-06-04 10:12 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jacky Huang,
Shan-Chun Hung, linux-phy, devicetree, linux-arm-kernel,
linux-kernel, Joey Lu
In-Reply-To: <20260604101220.1092822-1-a0987203069@gmail.com>
Add device tree binding documentation for the Nuvoton MA35D1 USB 2.0
OTG PHY driver (nuvoton,ma35d1-usb2-phy-otg).
PHY index 0 (USB0) is an OTG port whose signals are routed by a hardware
mux to either the DWC2 device controller or the EHCI0/OHCI0 host
controllers depending on the USB ID pin state. PHY index 1 (USB1) is a
dedicated host-only port.
Optional properties allow board-specific resistor calibration trim
(nuvoton,rcalcode) and over-current detect polarity configuration
(nuvoton,oc-active-high).
Signed-off-by: Joey Lu <a0987203069@gmail.com>
---
.../phy/nuvoton,ma35d1-usb2-phy-otg.yaml | 79 +++++++++++++++++++
1 file changed, 79 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/nuvoton,ma35d1-usb2-phy-otg.yaml
diff --git a/Documentation/devicetree/bindings/phy/nuvoton,ma35d1-usb2-phy-otg.yaml b/Documentation/devicetree/bindings/phy/nuvoton,ma35d1-usb2-phy-otg.yaml
new file mode 100644
index 000000000000..19f074565cc6
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/nuvoton,ma35d1-usb2-phy-otg.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/nuvoton,ma35d1-usb2-phy-otg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nuvoton MA35D1 USB 2.0 host PHY
+
+maintainers:
+ - Joey Lu <yclu4@nuvoton.com>
+
+description:
+ USB 2.0 PHY driver for the Nuvoton MA35D1 SoC, used by the EHCI and
+ OHCI host controllers.
+
+ USB0 (PHY index 0) is an OTG port whose physical signals are routed to
+ either the DWC2 device controller or the EHCI0/OHCI0 host controller by
+ a hardware mux that follows the USB ID pin.
+
+ USB1 (PHY index 1) is a dedicated host port with no OTG capability.
+
+properties:
+ compatible:
+ const: nuvoton,ma35d1-usb2-phy-otg
+
+ clocks:
+ maxItems: 1
+
+ nuvoton,sys:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: phandle to the system management syscon.
+ - description: PHY instance index.
+ enum:
+ - 0 # USB0, OTG port (shared with DWC2 gadget controller)
+ - 1 # USB1, host-only port
+ description:
+ A phandle to the syscon node covering the SYS register block, with
+ one argument selecting the PHY instance. Index 0 selects the OTG
+ port PHY (USB0) and index 1 selects the host-only PHY (USB1).
+
+ "#phy-cells":
+ const: 0
+
+ nuvoton,rcalcode:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 15
+ description:
+ Resistor calibration trim code written to the RCALCODE field in
+ USBPMISCR. The 4-bit value adjusts the PHY's internal termination
+ resistance. When absent the hardware reset default is used.
+
+ nuvoton,oc-active-high:
+ type: boolean
+ description:
+ When present, the over-current detect input from the VBUS power
+ switch is treated as active-high. The default (property absent) is
+ active-low. This setting is shared by both USB host ports.
+
+required:
+ - compatible
+ - clocks
+ - nuvoton,sys
+ - "#phy-cells"
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/nuvoton,ma35d1-clk.h>
+
+ usb_hphy0: usb-host-phy {
+ compatible = "nuvoton,ma35d1-usb2-phy-otg";
+ clocks = <&clk HUSBH0_GATE>;
+ nuvoton,sys = <&sys 0>;
+ #phy-cells = <0>;
+ };
--
2.43.0
^ permalink raw reply related
* [PATCH 2/2] phy: nuvoton: Add MA35D1 USB2 OTG PHY driver
From: Joey Lu @ 2026-06-04 10:12 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jacky Huang,
Shan-Chun Hung, linux-phy, devicetree, linux-arm-kernel,
linux-kernel, Joey Lu
In-Reply-To: <20260604101220.1092822-1-a0987203069@gmail.com>
Add a PHY driver for the USB 2.0 PHYs in the Nuvoton MA35D1 SoC,
intended for use with the EHCI and OHCI host controllers.
The MA35D1 SoC has two USB ports:
- USB0: an OTG port shared between a DWC2 gadget controller and
EHCI0/OHCI0 host controllers. A hardware mux automatically routes
the physical USB0 signals to the appropriate controller based on the
USB ID pin state. The DWC2 IP is device-only in hardware,
so host-mode operation on USB0 is handled entirely by EHCI0/OHCI0.
- USB1: a dedicated host-only port served by EHCI1/OHCI1.
The driver implements:
- Power-On Reset sequence with a guard that skips re-initialization if
the PHY is already operational. This protects PHY0 when the DWC2
gadget driver has already run its own init before EHCI0 probes.
- Optional resistor calibration trim via nuvoton,rcalcode.
- Optional over-current detect polarity via nuvoton,oc-active-high.
- For PHY0 only: a USB role switch that exposes the hardware ID pin
state (PWRONOTP[16]).
Signed-off-by: Joey Lu <a0987203069@gmail.com>
---
drivers/phy/nuvoton/Kconfig | 15 ++
drivers/phy/nuvoton/Makefile | 1 +
drivers/phy/nuvoton/phy-ma35d1-otg.c | 264 +++++++++++++++++++++++++++
3 files changed, 280 insertions(+)
create mode 100644 drivers/phy/nuvoton/phy-ma35d1-otg.c
diff --git a/drivers/phy/nuvoton/Kconfig b/drivers/phy/nuvoton/Kconfig
index d02cae2db315..5fdd13f841e7 100644
--- a/drivers/phy/nuvoton/Kconfig
+++ b/drivers/phy/nuvoton/Kconfig
@@ -10,3 +10,18 @@ config PHY_MA35_USB
help
Enable this to support the USB2.0 PHY on the Nuvoton MA35
series SoCs.
+
+config PHY_MA35_USB_OTG
+ tristate "Nuvoton MA35 USB2.0 OTG PHY driver"
+ depends on ARCH_MA35 || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ select MFD_SYSCON
+ select USB_ROLE_SWITCH
+ help
+ Enable this to support the USB2.0 OTG PHY on the Nuvoton MA35
+ series SoCs. This driver handles PHY initialization for the
+ EHCI/OHCI host controllers, including per-PHY power-on reset,
+ resistor calibration trim, and over-current polarity
+ configuration. For the OTG port (PHY0), it also monitors the
+ USB ID pin and registers a USB role switch.
diff --git a/drivers/phy/nuvoton/Makefile b/drivers/phy/nuvoton/Makefile
index 2937e3921898..3ecd76f35d7c 100644
--- a/drivers/phy/nuvoton/Makefile
+++ b/drivers/phy/nuvoton/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_MA35_USB) += phy-ma35d1-usb2.o
+obj-$(CONFIG_PHY_MA35_USB_OTG) += phy-ma35d1-otg.o
diff --git a/drivers/phy/nuvoton/phy-ma35d1-otg.c b/drivers/phy/nuvoton/phy-ma35d1-otg.c
new file mode 100644
index 000000000000..53bc6ddf755e
--- /dev/null
+++ b/drivers/phy/nuvoton/phy-ma35d1-otg.c
@@ -0,0 +1,264 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nuvoton MA35D1 USB 2.0 OTG PHY driver
+ *
+ * PHY0 (USB0) is shared between DWC2 gadget and EHCI0/OHCI0 host
+ * controllers. The hardware mux switches automatically via the USB
+ * ID pin. PHY1 (USB1) is host-only.
+ *
+ * Copyright (C) 2026 Nuvoton Technology Corp.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/usb/role.h>
+
+#define MA35_SYS_PWRONOTP 0x04
+#define PWRONOTP_USBP0ID BIT(16)
+
+#define MA35_SYS_USBPMISCR 0x60
+#define USBPMISCR_PHY_POR(n) BIT(0 + (n) * 16)
+#define USBPMISCR_PHY_SUSPEND(n) BIT(1 + (n) * 16)
+#define USBPMISCR_PHY_COMN(n) BIT(2 + (n) * 16)
+#define USBPMISCR_PHY_HSTCKSTB(n) BIT(8 + (n) * 16)
+#define USBPMISCR_PHY_CK12MSTB(n) BIT(9 + (n) * 16)
+/* Mask for control bits (POR, SUSPEND, COMN) of one PHY */
+#define USBPMISCR_PHY_CTL_MASK(n) (0x7 << ((n) * 16))
+/* Host-mode ready: SUSPEND + HSTCKSTB + CK12MSTB */
+#define USBPMISCR_PHY_HOST_READY(n) (USBPMISCR_PHY_SUSPEND(n) | \
+ USBPMISCR_PHY_HSTCKSTB(n) | \
+ USBPMISCR_PHY_CK12MSTB(n))
+/* RCALCODE: 4-bit resistor trim at bits [15:12] (PHY0) or [31:28] (PHY1) */
+#define USBPMISCR_RCAL_SHIFT(n) (12 + (n) * 16)
+#define USBPMISCR_RCAL_MASK(n) GENMASK(USBPMISCR_RCAL_SHIFT(n) + 3, \
+ USBPMISCR_RCAL_SHIFT(n))
+
+#define MA35_SYS_MISCFCR0 0x70
+/* MISCFCR0[12]: USB host over-current detect polarity (shared, both ports) */
+#define MISCFCR0_UHOVRCURH BIT(12)
+
+struct ma35_otg_phy {
+ struct clk *clk;
+ struct device *dev;
+ struct regmap *sysreg;
+ unsigned int phy_idx;
+ struct usb_role_switch *role_sw;
+ enum usb_role cur_role;
+};
+
+static int ma35_otg_phy_init(struct phy *phy)
+{
+ struct ma35_otg_phy *p = phy_get_drvdata(phy);
+ unsigned int n = p->phy_idx;
+ u32 ready_mask = USBPMISCR_PHY_HOST_READY(n);
+ unsigned int val;
+ int ret;
+
+ regmap_read(p->sysreg, MA35_SYS_USBPMISCR, &val);
+ if ((val & ready_mask) == ready_mask)
+ return 0;
+
+ regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR,
+ USBPMISCR_PHY_CTL_MASK(n),
+ USBPMISCR_PHY_POR(n) | USBPMISCR_PHY_SUSPEND(n));
+ msleep(20);
+
+ regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR,
+ USBPMISCR_PHY_CTL_MASK(n),
+ USBPMISCR_PHY_SUSPEND(n));
+
+ ret = regmap_read_poll_timeout(p->sysreg, MA35_SYS_USBPMISCR, val,
+ (val & ready_mask) == ready_mask,
+ 10, 1000);
+ if (ret) {
+ dev_err(p->dev, "USB PHY%u clock not stable (USBPMISCR=0x%08x)\n",
+ n, val);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ma35_otg_phy_power_on(struct phy *phy)
+{
+ struct ma35_otg_phy *p = phy_get_drvdata(phy);
+
+ return clk_prepare_enable(p->clk);
+}
+
+static int ma35_otg_phy_power_off(struct phy *phy)
+{
+ struct ma35_otg_phy *p = phy_get_drvdata(phy);
+
+ clk_disable_unprepare(p->clk);
+ return 0;
+}
+
+static const struct phy_ops ma35_otg_phy_ops = {
+ .init = ma35_otg_phy_init,
+ .power_on = ma35_otg_phy_power_on,
+ .power_off = ma35_otg_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static enum usb_role ma35_otg_read_id(struct ma35_otg_phy *p)
+{
+ unsigned int val;
+
+ regmap_read(p->sysreg, MA35_SYS_PWRONOTP, &val);
+ return (val & PWRONOTP_USBP0ID) ? USB_ROLE_HOST : USB_ROLE_DEVICE;
+}
+
+static int ma35_otg_role_sw_set(struct usb_role_switch *sw,
+ enum usb_role role)
+{
+ struct ma35_otg_phy *p = usb_role_switch_get_drvdata(sw);
+
+ p->cur_role = role;
+
+ return 0;
+}
+
+static enum usb_role ma35_otg_role_sw_get(struct usb_role_switch *sw)
+{
+ struct ma35_otg_phy *p = usb_role_switch_get_drvdata(sw);
+
+ return ma35_otg_read_id(p);
+}
+
+static int ma35_otg_role_switch_init(struct platform_device *pdev,
+ struct ma35_otg_phy *p)
+{
+ struct usb_role_switch_desc sw_desc = { };
+
+ p->cur_role = ma35_otg_read_id(p);
+
+ sw_desc.set = ma35_otg_role_sw_set;
+ sw_desc.get = ma35_otg_role_sw_get;
+ sw_desc.allow_userspace_control = true;
+ sw_desc.driver_data = p;
+ sw_desc.fwnode = dev_fwnode(&pdev->dev);
+
+ p->role_sw = usb_role_switch_register(&pdev->dev, &sw_desc);
+ if (IS_ERR(p->role_sw))
+ return dev_err_probe(&pdev->dev, PTR_ERR(p->role_sw),
+ "failed to register role switch\n");
+
+ return 0;
+}
+
+static void ma35_otg_role_switch_exit(struct ma35_otg_phy *p)
+{
+ if (!p->role_sw)
+ return;
+
+ usb_role_switch_unregister(p->role_sw);
+ p->role_sw = NULL;
+}
+
+static int ma35_otg_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *provider;
+ struct ma35_otg_phy *p;
+ unsigned int sys_args[1];
+ struct phy *phy;
+ u32 rcalcode;
+ int ret;
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->dev = &pdev->dev;
+ platform_set_drvdata(pdev, p);
+
+ p->sysreg = syscon_regmap_lookup_by_phandle_args(pdev->dev.of_node,
+ "nuvoton,sys",
+ 1, sys_args);
+ if (IS_ERR(p->sysreg))
+ return dev_err_probe(&pdev->dev, PTR_ERR(p->sysreg),
+ "Failed to get SYS regmap\n");
+
+ p->phy_idx = sys_args[0];
+
+ if (p->phy_idx > 1)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "invalid PHY index %u (must be 0 or 1)\n",
+ p->phy_idx);
+
+ p->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(p->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(p->clk),
+ "failed to get PHY clock\n");
+
+ if (!of_property_read_u32(pdev->dev.of_node, "nuvoton,rcalcode",
+ &rcalcode)) {
+ if (rcalcode > 15)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "rcalcode %u out of range (0-15)\n",
+ rcalcode);
+ regmap_update_bits(p->sysreg, MA35_SYS_USBPMISCR,
+ USBPMISCR_RCAL_MASK(p->phy_idx),
+ rcalcode << USBPMISCR_RCAL_SHIFT(p->phy_idx));
+ }
+
+ if (of_property_read_bool(pdev->dev.of_node, "nuvoton,oc-active-high"))
+ regmap_update_bits(p->sysreg, MA35_SYS_MISCFCR0,
+ MISCFCR0_UHOVRCURH, MISCFCR0_UHOVRCURH);
+
+ phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &ma35_otg_phy_ops);
+ if (IS_ERR(phy))
+ return dev_err_probe(&pdev->dev, PTR_ERR(phy),
+ "Failed to create PHY\n");
+
+ phy_set_drvdata(phy, p);
+
+ provider = devm_of_phy_provider_register(&pdev->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(provider))
+ return dev_err_probe(&pdev->dev, PTR_ERR(provider),
+ "Failed to register PHY provider\n");
+
+ if (p->phy_idx == 0) {
+ ret = ma35_otg_role_switch_init(pdev, p);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ma35_otg_phy_remove(struct platform_device *pdev)
+{
+ struct ma35_otg_phy *p = platform_get_drvdata(pdev);
+
+ ma35_otg_role_switch_exit(p);
+}
+
+static const struct of_device_id ma35_otg_phy_of_match[] = {
+ { .compatible = "nuvoton,ma35d1-usb2-phy-otg" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ma35_otg_phy_of_match);
+
+static struct platform_driver ma35_otg_phy_driver = {
+ .probe = ma35_otg_phy_probe,
+ .remove = ma35_otg_phy_remove,
+ .driver = {
+ .name = "ma35d1-usb2-phy-otg",
+ .of_match_table = ma35_otg_phy_of_match,
+ },
+};
+module_platform_driver(ma35_otg_phy_driver);
+
+MODULE_DESCRIPTION("Nuvoton MA35D1 USB 2.0 OTG PHY driver");
+MODULE_AUTHOR("Joey Lu <a0987203069@gmail.com>");
+MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH 0/2] phy: nuvoton: Add MA35D1 USB2 OTG PHY driver
From: Joey Lu @ 2026-06-04 10:12 UTC (permalink / raw)
To: Vinod Koul, Neil Armstrong
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jacky Huang,
Shan-Chun Hung, linux-phy, devicetree, linux-arm-kernel,
linux-kernel, Joey Lu
The Nuvoton MA35D1 SoC has two USB 2.0 ports:
USB0 is an OTG-capable port. Its physical signals are routed by a
hardware mux to either a DWC2 gadget controller or the EHCI0/OHCI0
host controllers, depending on the USB ID pin state. The DWC2 IP is
device-only in hardware, so all host-mode operation on USB0 is
handled by EHCI0/OHCI0.
USB1 is a dedicated host-only port served by EHCI1/OHCI1.
About this driver:
- Runs the PHY Power-On Reset sequence, with a guard that skips
re-initialization if the PHY is already operational.
- Supports optional resistor calibration trim (nuvoton,rcalcode) and
over-current detect polarity configuration (nuvoton,oc-active-high).
- For PHY0 (USB0) only: registers a USB role switch that reads the
hardware ID pin state from PWRONOTP[16] on every query.
Joey Lu (2):
dt-bindings: phy: nuvoton: Add MA35D1 USB2 OTG PHY binding
phy: nuvoton: Add MA35D1 USB2 OTG PHY driver
.../phy/nuvoton,ma35d1-usb2-phy-otg.yaml | 79 ++++++
drivers/phy/nuvoton/Kconfig | 15 +
drivers/phy/nuvoton/Makefile | 1 +
drivers/phy/nuvoton/phy-ma35d1-otg.c | 264 ++++++++++++++++++
4 files changed, 359 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/nuvoton,ma35d1-usb2-phy-otg.yaml
create mode 100644 drivers/phy/nuvoton/phy-ma35d1-otg.c
--
2.43.0
^ permalink raw reply
* Re: [PATCH net] net: airoha: Add NULL check for of_reserved_mem_lookup() in airoha_qdma_init_hfwd_queues()
From: Lorenzo Bianconi @ 2026-06-04 10:18 UTC (permalink / raw)
To: ZhaoJinming
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, horms,
linux-arm-kernel, linux-mediatek, netdev, linux-kernel, stable
In-Reply-To: <20260604070352.2603077-1-zhaojinming@uniontech.com>
[-- Attachment #1: Type: text/plain, Size: 1700 bytes --]
> of_reserved_mem_lookup() may return NULL if the reserved memory region
> referenced by the "memory-region" phandle is not found in the reserved
> memory table (e.g. due to a misconfigured DTS or a removed
> memory-region node). The current code dereferences the returned
> pointer without checking for NULL, leading to a kernel NULL pointer
> dereference at the following lines:
>
> dma_addr = rmem->base; // line 1156
> num_desc = div_u64(rmem->size, buf_size); // line 1160
>
> Add a NULL check after of_reserved_mem_lookup() and return -ENODEV if
> the lookup fails, which is consistent with the existing error handling
> for of_parse_phandle() failure in the same code block.
>
> Fixes: 3a1ce9e3d01b ("net: airoha: Add the capability to allocate hwfd buffers via reserved-memory")
> Cc: stable@vger.kernel.org
> Signed-off-by: ZhaoJinming<zhaojinming@uniontech.com>
Acked-by: Lorenzo Bianconi <lorenzo@kernel.org>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index cecd66251dba..2444d3275a81 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -1153,6 +1153,9 @@ static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma)
>
> rmem = of_reserved_mem_lookup(np);
> of_node_put(np);
> + if (!rmem)
> + return -ENODEV;
> +
> dma_addr = rmem->base;
> /* Compute the number of hw descriptors according to the
> * reserved memory size and the payload buffer size
> --
> 2.25.1
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH v2] dma: at_hdmac: Fix use-after-free by proper tasklet cleanup
From: Hongling Zeng @ 2026-06-04 10:19 UTC (permalink / raw)
To: ludovic.desroches, vkoul, Frank.Li, tudor.ambarus, nicolas.ferre
Cc: linux-arm-kernel, dmaengine, linux-kernel, zhongling0719,
Hongling Zeng, sashiko-bot
Current cleanup paths have a use-after-free vulnerability:
- vchan_init() creates tasklets that access at_dma_chan memory
- free_irq() only waits for IRQ handler, NOT tasklets
- atdma is devm-managed and freed after probe/remove
- Running tasklets accessing freed memory → Use-After-Free!
The fix requires careful ordering:
- free_irq() FIRST to synchronize with running IRQ handlers and prevent
them from scheduling new tasklets
- Then kill tasklets to wait for already-scheduled ones to complete
- Only then free other resources
Fixes: ac803b56860f ("dmaengine: at_hdmac: Convert driver to use virt-dma")
Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/all/20260604073945.54B311F00898@smtp.kernel.org/
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
---
Change in v2:
- Fix NULL pointer dereference in probe error path by checking if channels list is initialized before cleanup
- Fix race condition by calling free_irq() before tasklet_kill() to ensure
IRQ handlers cannot reschedule tasklets after cleanup
---
drivers/dma/at_hdmac.c | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index e5b30a57c477..9048b56b082f 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1940,6 +1940,19 @@ static void at_dma_off(struct at_dma *atdma)
cpu_relax();
}
+static void at_dma_cleanup_channels(struct at_dma *atdma)
+{
+ struct dma_chan *chan, *_chan;
+
+ list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
+ device_node) {
+ /* Disable interrupts */
+ atc_disable_chan_irq(atdma, chan->chan_id);
+ tasklet_kill(&to_at_dma_chan(chan)->vc.task);
+ list_del(&chan->device_node);
+ }
+}
+
static int __init at_dma_probe(struct platform_device *pdev)
{
struct at_dma *atdma;
@@ -2109,6 +2122,8 @@ static int __init at_dma_probe(struct platform_device *pdev)
err_memset_pool_create:
dma_pool_destroy(atdma->lli_pool);
err_desc_pool_create:
+ if (atdma->dma_device.channels.next != NULL)
+ at_dma_cleanup_channels(atdma);
free_irq(platform_get_irq(pdev, 0), atdma);
err_irq:
clk_disable_unprepare(atdma->clk);
@@ -2125,16 +2140,11 @@ static void at_dma_remove(struct platform_device *pdev)
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&atdma->dma_device);
- dma_pool_destroy(atdma->memset_pool);
- dma_pool_destroy(atdma->lli_pool);
free_irq(platform_get_irq(pdev, 0), atdma);
+ at_dma_cleanup_channels(atdma);
- list_for_each_entry_safe(chan, _chan, &atdma->dma_device.channels,
- device_node) {
- /* Disable interrupts */
- atc_disable_chan_irq(atdma, chan->chan_id);
- list_del(&chan->device_node);
- }
+ dma_pool_destroy(atdma->memset_pool);
+ dma_pool_destroy(atdma->lli_pool);
clk_disable_unprepare(atdma->clk);
}
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v6 3/4] firmware: smccc: arm-cca-guest: Bind the TSM provider to an SMCCC device
From: Suzuki K Poulose @ 2026-06-04 10:24 UTC (permalink / raw)
To: Sudeep Holla, Aneesh Kumar K.V (Arm)
Cc: linux-coco, linux-arm-kernel, linux-kernel, Catalin Marinas,
Greg KH, Jeremy Linton, Jonathan Cameron, Lorenzo Pieralisi,
Mark Rutland, Will Deacon, Steven Price
In-Reply-To: <20260603-determined-bumblebee-of-promise-e633d6@sudeepholla>
On 04/06/2026 10:21, Sudeep Holla wrote:
> On Wed, May 27, 2026 at 03:32:32PM +0530, Aneesh Kumar K.V (Arm) wrote:
>> The Arm CCA guest TSM provider currently binds through the arm-cca-dev
>> platform device. Like arm-smccc-trng, this device is not an independent
>> platform resource; it is a software representation of the RSI firmware
>> service discovered through SMCCC.
>>
>> Move RSI discovery into the SMCCC firmware driver. When the SMCCC conduit
>> is SMC and the RSI ABI version check succeeds, create an arm-rsi-dev SMCCC
>> device. Convert the Arm CCA guest TSM provider to an SMCCC driver so it
>> binds to that discovered RSI service and keeps module autoloading through
>> the SMCCC device id table.
>>
>> Keep the old arm-cca-dev platform-device registration for now. Userspace
>> has used that device as a Realm-guest indicator, so removing it is left to
>> a follow-up patch that adds a replacement sysfs ABI.
>>
>> Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
>> ---
>> arch/arm64/include/asm/rsi.h | 2 +-
>> arch/arm64/kernel/rsi.c | 2 +-
>> drivers/firmware/smccc/Makefile | 4 ++
>> drivers/firmware/smccc/rmm.c | 25 ++++++++
>> drivers/firmware/smccc/rmm.h | 17 ++++++
>> drivers/firmware/smccc/smccc.c | 8 +++
>> drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
>> drivers/virt/coco/arm-cca-guest/Makefile | 2 +
>> .../{arm-cca-guest.c => arm-cca.c} | 60 +++++++++----------
>> 9 files changed, 89 insertions(+), 32 deletions(-)
>> create mode 100644 drivers/firmware/smccc/rmm.c
>> create mode 100644 drivers/firmware/smccc/rmm.h
>> rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (85%)
>>
>> diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
>> index 88b50d660e85..2d2d363aaaee 100644
>> --- a/arch/arm64/include/asm/rsi.h
>> +++ b/arch/arm64/include/asm/rsi.h
>> @@ -10,7 +10,7 @@
>> #include <linux/jump_label.h>
>> #include <asm/rsi_cmds.h>
>>
>> -#define RSI_PDEV_NAME "arm-cca-dev"
>> +#define RSI_DEV_NAME "arm-rsi-dev"
>>
>> DECLARE_STATIC_KEY_FALSE(rsi_present);
>>
>> diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
>> index 92160f2e57ff..da440f71bb64 100644
>> --- a/arch/arm64/kernel/rsi.c
>> +++ b/arch/arm64/kernel/rsi.c
>> @@ -161,7 +161,7 @@ void __init arm64_rsi_init(void)
>> }
>>
>> static struct platform_device rsi_dev = {
>> - .name = RSI_PDEV_NAME,
>> + .name = "arm-cca-dev",
>> .id = PLATFORM_DEVID_NONE
>> };
>>
>> diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
>> index 40d19144a860..33c850aaff4d 100644
>> --- a/drivers/firmware/smccc/Makefile
>> +++ b/drivers/firmware/smccc/Makefile
>> @@ -2,3 +2,7 @@
>> #
>> obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
>> obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
>> +
>> +ifeq ($(CONFIG_HAVE_ARM_SMCCC_DISCOVERY),y)
>> +obj-$(CONFIG_ARM64) += rmm.o
>> +endif
>> diff --git a/drivers/firmware/smccc/rmm.c b/drivers/firmware/smccc/rmm.c
>> new file mode 100644
>> index 000000000000..d572f47e955c
>> --- /dev/null
>> +++ b/drivers/firmware/smccc/rmm.c
>> @@ -0,0 +1,25 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (C) 2026 Arm Limited
>> + */
>> +
>> +#include <linux/arm-smccc-bus.h>
>> +#include <linux/err.h>
>> +#include <linux/printk.h>
>> +
>> +#include "rmm.h"
>> +
>> +void __init register_rsi_device(void)
>> +{
>> + unsigned long ret;
>> +
>> + if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
>> + return;
>> +
>> + ret = rsi_request_version(RSI_ABI_VERSION, NULL, NULL);
>> + if (ret != RSI_SUCCESS)
>> + return;
>> +
>> + if (IS_ERR(arm_smccc_device_register(RSI_DEV_NAME)))
>> + pr_err("%s: could not register device\n", RSI_DEV_NAME);
>> +}
>
> OK, I had something else in my mind when I started looking at 1/4. I didn't
> expect each device added on this bus comes up with it's own way to enumerate
> it. IMO, it defeats the purpose of building the smccc bus. We may find the
> specs for each feature deviated a bit but we can have a generic probe
> IMO, let's try that before exploring per feature probe function.
I guess this is ideal, but see below.
>
> I have a brief sketch of what I think we should aim for(uncompiled/untested)
> below. Let me know if that makes sense. I just based it on your bus code.
>
> Regards,
> Sudeep
>
> -->8
>
> diff --git c/drivers/firmware/smccc/smccc.c w/drivers/firmware/smccc/smccc.c
> index 695c920a8087..450605ddfab6 100644
> --- c/drivers/firmware/smccc/smccc.c
> +++ w/drivers/firmware/smccc/smccc.c
> @@ -9,21 +9,58 @@
> #include <linux/init.h>
> #include <linux/arm-smccc.h>
> #include <linux/kernel.h>
> -#include <linux/platform_device.h>
> #include <linux/arm-smccc-bus.h>
> #include <linux/idr.h>
> #include <linux/slab.h>
>
> -#include <asm/archrandom.h>
> -
> static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
> static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
> static DEFINE_IDA(arm_smccc_bus_id);
>
> -bool __ro_after_init smccc_trng_available = false;
> +struct smccc_device_info {
> + u32 func_id;
> + bool requires_smc;
> + unsigned long min_return;
Is this viable for all ? There may be additional restrictions around
the return values and further SMC calls ? Which brings us to call backs
and we kind of have a variant of that here.
Suzuki
> + const char *device_name;
> +};
> +
> +bool __ro_after_init smccc_trng_available;
> s32 __ro_after_init smccc_soc_id_version = SMCCC_RET_NOT_SUPPORTED;
> s32 __ro_after_init smccc_soc_id_revision = SMCCC_RET_NOT_SUPPORTED;
>
> +static const struct smccc_device_info smccc_devices[] __initconst = {
> + {
> + .func_id = ARM_SMCCC_TRNG_VERSION,
> + .requires_smc = false,
> + .min_return = ARM_SMCCC_TRNG_MIN_VERSION,
> + .device_name = "arm-smccc-trng",
> + },
> +};
> +
> +static bool __init
> +smccc_probe_smccc_device(const struct smccc_device_info *smccc_dev)
> +{
> + struct arm_smccc_res res;
> + unsigned long ret;
> +
> + if (!IS_ENABLED(CONFIG_ARM64))
> + return false;
> +
> + if (smccc_conduit == SMCCC_CONDUIT_NONE)
> + return false;
> +
> + if (smccc_dev->requires_smc && smccc_conduit != SMCCC_CONDUIT_SMC)
> + return false;
> +
> + arm_smccc_1_1_invoke(smccc_dev->func_id, &res);
> + ret = res.a0;
> +
> + if ((s32)ret < 0)
> + return false;
> +
> + return ret >= smccc_dev->min_return;
> +}
> +
> void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
> {
> struct arm_smccc_res res;
> @@ -31,7 +68,7 @@ void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
> smccc_version = version;
> smccc_conduit = conduit;
>
> - smccc_trng_available = smccc_probe_trng();
> + smccc_trng_available = smccc_probe_smccc_device(&smccc_devices[0]);
>
> if ((smccc_version >= ARM_SMCCC_VERSION_1_2) &&
> (smccc_conduit != SMCCC_CONDUIT_NONE)) {
> @@ -241,14 +278,20 @@ subsys_initcall(arm_smccc_bus_init);
>
> static int __init smccc_devices_init(void)
> {
> - struct platform_device *pdev;
> -
> - if (smccc_trng_available) {
> - pdev = platform_device_register_simple("smccc_trng", -1,
> - NULL, 0);
> - if (IS_ERR(pdev))
> - pr_err("smccc_trng: could not register device: %ld\n",
> - PTR_ERR(pdev));
> + const struct smccc_device_info *smccc_dev;
> + struct arm_smccc_device *sdev;
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(smccc_devices); i++) {
> + smccc_dev = &smccc_devices[i];
> +
> + if (!smccc_probe_smccc_device(smccc_dev))
> + continue;
> +
> + sdev = arm_smccc_device_register(smccc_dev->device_name);
> + if (IS_ERR(sdev))
> + pr_err("%s: could not register device: %ld\n",
> + smccc_dev->device_name, PTR_ERR(sdev));
> }
>
> return 0;
>
^ 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