* [PATCH v1 1/2] arm64: smccc: add cache clean/invalidate IDs and return codes
2026-06-02 8:21 [PATCH v1 0/2] Add SMCCC cache clean/invalidate provider Srirangan Madhavan
@ 2026-06-02 8:21 ` Srirangan Madhavan
2026-06-02 14:49 ` Jonathan Cameron
2026-06-02 8:21 ` [PATCH v1 2/2] cache: add SMCCC-backed cache invalidate provider Srirangan Madhavan
1 sibling, 1 reply; 5+ messages in thread
From: Srirangan Madhavan @ 2026-06-02 8:21 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Conor Dooley,
Jonathan Cameron
Cc: Catalin Marinas, Will Deacon, Dan Williams, Thierry Reding,
Jonathan Hunter, linux-arm-kernel, linux-kernel, linux-tegra,
Srirangan Madhavan
Define SMCCC Arch function IDs for CLEAN_INV_MEMREGION and its ATTRIBUTES
call, and add RATE_LIMITED/BUSY return codes from DEN0028 for callers that
need transient error handling.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia•com>
---
include/linux/arm-smccc.h | 21 +++++++++++++++++++--
tools/include/linux/arm-smccc.h | 21 +++++++++++++++++++--
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 50b47eba7d01..8cba040e0816 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -105,6 +105,22 @@
ARM_SMCCC_SMC_32, \
0, 0x3fff)
+/*
+ * DEN0028 v1.7 defines these cache maintenance functions as SMC64
+ * because they carry 64-bit memory range arguments.
+ */
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x5)
+
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x6)
+
#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
@@ -294,13 +310,14 @@
0x53)
/*
- * Return codes defined in ARM DEN 0070A
- * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
+ * Return codes defined by Arm SMCCC (DEN0028 v1.7).
*/
#define SMCCC_RET_SUCCESS 0
#define SMCCC_RET_NOT_SUPPORTED -1
#define SMCCC_RET_NOT_REQUIRED -2
#define SMCCC_RET_INVALID_PARAMETER -3
+#define SMCCC_RET_RATE_LIMITED -4
+#define SMCCC_RET_BUSY -5
#ifndef __ASSEMBLY__
diff --git a/tools/include/linux/arm-smccc.h b/tools/include/linux/arm-smccc.h
index 63ce9bebccd3..ae5637b3240f 100644
--- a/tools/include/linux/arm-smccc.h
+++ b/tools/include/linux/arm-smccc.h
@@ -96,6 +96,22 @@
ARM_SMCCC_SMC_32, \
0, 0x3fff)
+/*
+ * DEN0028 v1.7 defines these cache maintenance functions as SMC64
+ * because they carry 64-bit memory range arguments.
+ */
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x5)
+
+#define ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_ARCH, \
+ 0x6)
+
#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
@@ -182,12 +198,13 @@
0x53)
/*
- * Return codes defined in ARM DEN 0070A
- * ARM DEN 0070A is now merged/consolidated into ARM DEN 0028 C
+ * Return codes defined by Arm SMCCC (DEN0028 v1.7).
*/
#define SMCCC_RET_SUCCESS 0
#define SMCCC_RET_NOT_SUPPORTED -1
#define SMCCC_RET_NOT_REQUIRED -2
#define SMCCC_RET_INVALID_PARAMETER -3
+#define SMCCC_RET_RATE_LIMITED -4
+#define SMCCC_RET_BUSY -5
#endif /*__LINUX_ARM_SMCCC_H*/
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v1 1/2] arm64: smccc: add cache clean/invalidate IDs and return codes
2026-06-02 8:21 ` [PATCH v1 1/2] arm64: smccc: add cache clean/invalidate IDs and return codes Srirangan Madhavan
@ 2026-06-02 14:49 ` Jonathan Cameron
0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Cameron @ 2026-06-02 14:49 UTC (permalink / raw)
To: Srirangan Madhavan
Cc: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Conor Dooley,
Catalin Marinas, Will Deacon, Dan Williams, Thierry Reding,
Jonathan Hunter, linux-arm-kernel, linux-kernel, linux-tegra
On Tue, 2 Jun 2026 08:21:44 +0000
Srirangan Madhavan <smadhavan@nvidia•com> wrote:
> Define SMCCC Arch function IDs for CLEAN_INV_MEMREGION and its ATTRIBUTES
> call, and add RATE_LIMITED/BUSY return codes from DEN0028 for callers that
> need transient error handling.
>
> Signed-off-by: Srirangan Madhavan <smadhavan@nvidia•com>
Reviewed-by: Jonathan Cameron <jic23@kernel•org>
I assume beta spec is enough to merge this? Probably just need
someone from Arm to confirm. Last time we had this feature and it got
ripped out it only made it to an alpha spec (which is not enough!)
Jonathan
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 2/2] cache: add SMCCC-backed cache invalidate provider
2026-06-02 8:21 [PATCH v1 0/2] Add SMCCC cache clean/invalidate provider Srirangan Madhavan
2026-06-02 8:21 ` [PATCH v1 1/2] arm64: smccc: add cache clean/invalidate IDs and return codes Srirangan Madhavan
@ 2026-06-02 8:21 ` Srirangan Madhavan
2026-06-02 15:03 ` Jonathan Cameron
1 sibling, 1 reply; 5+ messages in thread
From: Srirangan Madhavan @ 2026-06-02 8:21 UTC (permalink / raw)
To: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Conor Dooley,
Jonathan Cameron
Cc: Catalin Marinas, Will Deacon, Dan Williams, Thierry Reding,
Jonathan Hunter, linux-arm-kernel, linux-kernel, linux-tegra,
Srirangan Madhavan
Add a cache maintenance provider for the Arm SMCCC cache clean+invalidate
interface.
The provider discovers SMCCC support and attributes at init time,
serializes firmware calls, handles transient BUSY and RATE_LIMITED
responses with bounded retries, and registers with the generic cache
coherency framework used by memregion callers.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia•com>
---
drivers/cache/Kconfig | 11 +++
drivers/cache/Makefile | 1 +
drivers/cache/arm_smccc_cache.c | 160 ++++++++++++++++++++++++++++++++
3 files changed, 172 insertions(+)
create mode 100644 drivers/cache/arm_smccc_cache.c
diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
index 1518449d47b5..5d7ef3d15979 100644
--- a/drivers/cache/Kconfig
+++ b/drivers/cache/Kconfig
@@ -42,6 +42,17 @@ menuconfig CACHEMAINT_FOR_HOTPLUG
if CACHEMAINT_FOR_HOTPLUG
+config ARM_SMCCC_CACHE
+ bool "Arm SMCCC cache maintenance provider"
+ depends on ARM64 && HAVE_ARM_SMCCC_DISCOVERY
+ help
+ Enable support for the Arm SMCCC cache clean+invalidate
+ interface as a provider for memory hotplug-like cache
+ maintenance operations.
+ The provider registers only when firmware advertises the
+ SMCCC calls and attributes, so systems without firmware support
+ continue without a registered provider.
+
config HISI_SOC_HHA
tristate "HiSilicon Hydra Home Agent (HHA) device driver"
depends on (ARM64 && ACPI) || COMPILE_TEST
diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
index b3362b15d6c1..6d91085aafe4 100644
--- a/drivers/cache/Makefile
+++ b/drivers/cache/Makefile
@@ -4,4 +4,5 @@ obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o
obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
obj-$(CONFIG_STARFIVE_STARLINK_CACHE) += starfive_starlink_cache.o
+obj-$(CONFIG_ARM_SMCCC_CACHE) += arm_smccc_cache.o
obj-$(CONFIG_HISI_SOC_HHA) += hisi_soc_hha.o
diff --git a/drivers/cache/arm_smccc_cache.c b/drivers/cache/arm_smccc_cache.c
new file mode 100644
index 000000000000..ff6bca91a1a1
--- /dev/null
+++ b/drivers/cache/arm_smccc_cache.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 NVIDIA Corporation
+ *
+ * Arm SMCCC cache maintenance provider using cache clean+invalidate calls.
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/cache_coherency.h>
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/nmi.h>
+
+#define SMCCC_CACHE_MAX_RETRIES 5
+#define SMCCC_CACHE_DEFAULT_DELAY_US 1000UL
+#define SMCCC_CACHE_MAX_DELAY_US 20000UL
+
+struct smccc_cache {
+ /* Must be first member */
+ struct cache_coherency_ops_inst cci;
+ struct mutex lock; /* Serializes SMCCC cache maintenance calls. */
+ u32 latency_us;
+ u32 rate_limit;
+};
+
+static int smccc_cache_status_to_errno(s32 status)
+{
+ switch (status) {
+ case SMCCC_RET_SUCCESS:
+ return 0;
+ case SMCCC_RET_NOT_SUPPORTED:
+ return -EOPNOTSUPP;
+ case SMCCC_RET_INVALID_PARAMETER:
+ return -EINVAL;
+ case SMCCC_RET_RATE_LIMITED:
+ return -EAGAIN;
+ case SMCCC_RET_BUSY:
+ return -EBUSY;
+ default:
+ return -EIO;
+ }
+}
+
+static unsigned long smccc_cache_delay_us(const struct smccc_cache *cache)
+{
+ unsigned long delay_us = 0;
+
+ if (cache->rate_limit)
+ delay_us = DIV_ROUND_UP_ULL(USEC_PER_SEC, cache->rate_limit);
+
+ if (cache->latency_us)
+ delay_us = max(delay_us, (unsigned long)cache->latency_us);
+
+ /*
+ * Firmware may advertise neither a rate limit nor a latency hint; use
+ * a small bounded backoff instead of retrying in a tight loop.
+ */
+ if (!delay_us)
+ delay_us = SMCCC_CACHE_DEFAULT_DELAY_US;
+
+ return min(delay_us, SMCCC_CACHE_MAX_DELAY_US);
+}
+
+static int smccc_cache_wbinv(struct cache_coherency_ops_inst *cci,
+ struct cc_inval_params *invp)
+{
+ struct smccc_cache *cache = container_of(cci, struct smccc_cache, cci);
+ struct arm_smccc_res res = {};
+ unsigned long delay_us = smccc_cache_delay_us(cache);
+ int ret;
+
+ if (!invp->size)
+ return -EINVAL;
+
+ /*
+ * Serialize the full retry sequence. With the default bounds, a caller
+ * may hold the mutex across up to four 20ms backoff sleeps.
+ */
+ guard(mutex)(&cache->lock);
+
+ for (unsigned int i = 0; i < SMCCC_CACHE_MAX_RETRIES; i++) {
+ /* Long firmware operations can trigger watchdog checks. */
+ touch_nmi_watchdog();
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION,
+ invp->addr, invp->size, 0UL, &res);
+
+ ret = smccc_cache_status_to_errno((s32)res.a0);
+ if (!ret)
+ return 0;
+
+ if (ret != -EBUSY && ret != -EAGAIN)
+ return ret;
+
+ if (i + 1 == SMCCC_CACHE_MAX_RETRIES)
+ break;
+
+ fsleep(delay_us);
+ }
+
+ return -EBUSY;
+}
+
+static const struct cache_coherency_ops smccc_cache_ops = {
+ .wbinv = smccc_cache_wbinv,
+};
+
+static int __init smccc_cache_init(void)
+{
+ struct smccc_cache *cache;
+ struct arm_smccc_res res = {};
+ int ret;
+
+ if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_1)
+ return -ENODEV;
+
+ if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION, &res);
+ if ((s32)res.a0 < 0)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES,
+ &res);
+ if ((s32)res.a0 < 0)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES,
+ &res);
+ if ((s32)res.a0)
+ return -ENODEV;
+
+ cache = cache_coherency_ops_instance_alloc(&smccc_cache_ops,
+ struct smccc_cache, cci);
+ if (!cache)
+ return -ENOMEM;
+
+ mutex_init(&cache->lock);
+ cache->latency_us = lower_32_bits(res.a2);
+ cache->rate_limit = lower_32_bits(res.a3);
+
+ ret = cache_coherency_ops_instance_register(&cache->cci);
+ if (ret) {
+ mutex_destroy(&cache->lock);
+ cache_coherency_ops_instance_put(&cache->cci);
+ return ret;
+ }
+
+ pr_info("SMCCC cache clean+invalidate provider registered\n");
+
+ return 0;
+}
+arch_initcall(smccc_cache_init);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v1 2/2] cache: add SMCCC-backed cache invalidate provider
2026-06-02 8:21 ` [PATCH v1 2/2] cache: add SMCCC-backed cache invalidate provider Srirangan Madhavan
@ 2026-06-02 15:03 ` Jonathan Cameron
0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Cameron @ 2026-06-02 15:03 UTC (permalink / raw)
To: Srirangan Madhavan
Cc: Mark Rutland, Lorenzo Pieralisi, Sudeep Holla, Conor Dooley,
Catalin Marinas, Will Deacon, Dan Williams, Thierry Reding,
Jonathan Hunter, linux-arm-kernel, linux-kernel, linux-tegra
On Tue, 2 Jun 2026 08:21:45 +0000
Srirangan Madhavan <smadhavan@nvidia•com> wrote:
> Add a cache maintenance provider for the Arm SMCCC cache clean+invalidate
> interface.
>
> The provider discovers SMCCC support and attributes at init time,
> serializes firmware calls, handles transient BUSY and RATE_LIMITED
> responses with bounded retries, and registers with the generic cache
> coherency framework used by memregion callers.
>
> Signed-off-by: Srirangan Madhavan <smadhavan@nvidia•com>
3 things inline.
With the loop style updated to either drop that optimization of
eliding of the last sleep or use a while (1) loop and the kconfig
modified to not imply there are _no_ registered providers.
Reviewed-by: Jonathan Cameron <jic23@kernel•org>
The comment in Makefile isn't really about this patch, just something
I noticed whilst wondering why it wasn't ordered.
> ---
> drivers/cache/Kconfig | 11 +++
> drivers/cache/Makefile | 1 +
> drivers/cache/arm_smccc_cache.c | 160 ++++++++++++++++++++++++++++++++
> 3 files changed, 172 insertions(+)
> create mode 100644 drivers/cache/arm_smccc_cache.c
>
> diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
> index 1518449d47b5..5d7ef3d15979 100644
> --- a/drivers/cache/Kconfig
> +++ b/drivers/cache/Kconfig
> @@ -42,6 +42,17 @@ menuconfig CACHEMAINT_FOR_HOTPLUG
>
> if CACHEMAINT_FOR_HOTPLUG
>
> +config ARM_SMCCC_CACHE
> + bool "Arm SMCCC cache maintenance provider"
> + depends on ARM64 && HAVE_ARM_SMCCC_DISCOVERY
> + help
> + Enable support for the Arm SMCCC cache clean+invalidate
> + interface as a provider for memory hotplug-like cache
> + maintenance operations.
> + The provider registers only when firmware advertises the
> + SMCCC calls and attributes, so systems without firmware support
> + continue without a registered provider.
"without this registered provider". or "without registering a provider."
We need to be careful that we don't give the impressions this is the only
option for Arm64 systems that do SMCCC and need a cache maintenance
provider. The HiSilcon systems that use HISI_SOC_HHA meet all those
conditions - except that they don't use this service.
> +
> config HISI_SOC_HHA
> tristate "HiSilicon Hydra Home Agent (HHA) device driver"
> depends on (ARM64 && ACPI) || COMPILE_TEST
> diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
> index b3362b15d6c1..6d91085aafe4 100644
> --- a/drivers/cache/Makefile
> +++ b/drivers/cache/Makefile
> @@ -4,4 +4,5 @@ obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o
> obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
> obj-$(CONFIG_STARFIVE_STARLINK_CACHE) += starfive_starlink_cache.o
>
Maybe we should add a comment here
# Depend on CACHEMAINT_FOR_HOTPLUG
or something like that to avoid them being 'sorted' into the group above
at somepoint in future.
> +obj-$(CONFIG_ARM_SMCCC_CACHE) += arm_smccc_cache.o
> obj-$(CONFIG_HISI_SOC_HHA) += hisi_soc_hha.o
> diff --git a/drivers/cache/arm_smccc_cache.c b/drivers/cache/arm_smccc_cache.c
> new file mode 100644
> index 000000000000..ff6bca91a1a1
> --- /dev/null
> +++ b/drivers/cache/arm_smccc_cache.c
> @@ -0,0 +1,160 @@
> + static int smccc_cache_wbinv(struct cache_coherency_ops_inst *cci,
> + struct cc_inval_params *invp)
> +{
> + struct smccc_cache *cache = container_of(cci, struct smccc_cache, cci);
> + struct arm_smccc_res res = {};
> + unsigned long delay_us = smccc_cache_delay_us(cache);
> + int ret;
> +
> + if (!invp->size)
> + return -EINVAL;
> +
> + /*
> + * Serialize the full retry sequence. With the default bounds, a caller
> + * may hold the mutex across up to four 20ms backoff sleeps.
> + */
> + guard(mutex)(&cache->lock);
> +
> + for (unsigned int i = 0; i < SMCCC_CACHE_MAX_RETRIES; i++) {
> + /* Long firmware operations can trigger watchdog checks. */
> + touch_nmi_watchdog();
> +
> + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION,
> + invp->addr, invp->size, 0UL, &res);
> +
> + ret = smccc_cache_status_to_errno((s32)res.a0);
> + if (!ret)
> + return 0;
> +
> + if (ret != -EBUSY && ret != -EAGAIN)
> + return ret;
> +
> + if (i + 1 == SMCCC_CACHE_MAX_RETRIES)
> + break;
The for loop bound makes little sense if you are going to do
this. Use a while loop. Or don't worry about optimising out the final
sleep as we never expect to hit this.
> +
> + fsleep(delay_us);
> + }
> +
> + return -EBUSY;
> +}
^ permalink raw reply [flat|nested] 5+ messages in thread