[PATCH v6 3/4] firmware: smccc: arm-cca-guest: Bind the TSM provider to an SMCCC device
Suzuki K Poulose
suzuki.poulose at arm.com
Thu Jun 4 03:24:05 PDT 2026
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 at 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;
>
More information about the linux-arm-kernel
mailing list