* [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 [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 [flat|nested] 5+ messages in thread