From: Srirangan Madhavan <smadhavan@nvidia.com>
To: catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com,
lpieralisi@kernel.org, sudeep.holla@arm.com
Cc: conor@kernel.org, jic23@kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, vsethi@nvidia.com,
jevans@nvidia.com, raghupathyk@nvidia.com, srikars@nvidia.com,
nbenech@nvidia.com, alwilliamson@nvidia.com,
Dan Williams <danwilliams@nvidia.com>,
Srirangan Madhavan <smadhavan@nvidia.com>
Subject: [RFC PATCH 2/2] arm64: mm: add SMCCC-backed cache invalidate provider
Date: Thu, 21 May 2026 07:30:47 +0000 [thread overview]
Message-ID: <20260521073047.320614-3-smadhavan@nvidia.com> (raw)
In-Reply-To: <20260521073047.320614-1-smadhavan@nvidia.com>
Add an arm64 cache maintenance backend that discovers SMCCC cache
clean+invalidate support, queries attributes, handles transient BUSY and
RATE_LIMITED responses with bounded retries, and registers with the generic
cache coherency framework.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
MAINTAINERS | 1 +
arch/arm64/mm/Makefile | 1 +
arch/arm64/mm/cache_maint.c | 180 ++++++++++++++++++++++++++++++++++++
3 files changed, 182 insertions(+)
create mode 100644 arch/arm64/mm/cache_maint.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..33c35f8e6e40 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25383,6 +25383,7 @@ M: Jonathan Cameron <jic23@kernel.org>
S: Maintained
T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
F: Documentation/devicetree/bindings/cache/
+F: arch/arm64/mm/cache_maint.c
F: drivers/cache
F: include/linux/cache_coherency.h
F: lib/cache_maint.c
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index c26489cf96cd..b247dc5dfd45 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_TRANS_TABLE) += trans_pgd-asm.o
obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
obj-$(CONFIG_ARM64_MTE) += mteswap.o
obj-$(CONFIG_ARM64_GCS) += gcs.o
+obj-$(CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION) += cache_maint.o
KASAN_SANITIZE_physaddr.o += n
obj-$(CONFIG_KASAN) += kasan_init.o
diff --git a/arch/arm64/mm/cache_maint.c b/arch/arm64/mm/cache_maint.c
new file mode 100644
index 000000000000..ea7dd30d5dfa
--- /dev/null
+++ b/arch/arm64/mm/cache_maint.c
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 NVIDIA Corporation
+ *
+ * Arm64 cache maintenance provider using SMCCC 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_MAX_DELAY_US 20000
+
+/* DEN0028 v1.7: bit[0] == 1 means implementation flushes all caches globally */
+#define SMCCC_CACHE_ATTR_GLOBAL_OP BIT(0)
+
+struct arm64_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;
+ bool global_op;
+ u64 global_flush_gen;
+};
+
+static struct arm64_smccc_cache *arm64_smccc_cache;
+
+static int smccc_cache_status_to_errno(s32 status)
+{
+ switch (status) {
+ case SMCCC_RET_SUCCESS:
+ return 0;
+ case SMCCC_RET_NOT_SUPPORTED:
+ case SMCCC_RET_NOT_REQUIRED:
+ 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 int smccc_cache_delay_us(const struct arm64_smccc_cache *cache)
+{
+ u64 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_t(u64, delay_us, cache->latency_us);
+
+ if (!delay_us)
+ delay_us = 1000;
+
+ return min_t(u64, delay_us, SMCCC_CACHE_MAX_DELAY_US);
+}
+
+static int arm64_smccc_cache_wbinv(struct cache_coherency_ops_inst *cci,
+ struct cc_inval_params *invp)
+{
+ struct arm64_smccc_cache *cache =
+ container_of(cci, struct arm64_smccc_cache, cci);
+ struct arm_smccc_res res = {};
+ int delay_us = smccc_cache_delay_us(cache);
+ u64 gen = 0;
+ s32 status;
+ int ret;
+ int i;
+
+ if (!invp->size)
+ return -EINVAL;
+
+ if (cache->global_op)
+ gen = READ_ONCE(cache->global_flush_gen);
+
+ guard(mutex)(&cache->lock);
+
+ /*
+ * If firmware reports a global operation type, a successful operation
+ * covers every request that was already waiting behind it. Skip if the
+ * generation advanced while this request was waiting to enter the
+ * serialized firmware call path.
+ */
+ if (cache->global_op && gen != READ_ONCE(cache->global_flush_gen))
+ return 0;
+
+ for (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);
+ status = (s32)res.a0;
+ ret = smccc_cache_status_to_errno(status);
+ if (!ret) {
+ if (cache->global_op) {
+ WRITE_ONCE(cache->global_flush_gen,
+ cache->global_flush_gen + 1);
+ }
+ return 0;
+ }
+
+ if (ret != -EBUSY && ret != -EAGAIN)
+ return ret;
+
+ usleep_range(delay_us, delay_us + 100);
+ }
+
+ return -EBUSY;
+}
+
+static const struct cache_coherency_ops arm64_smccc_cache_ops = {
+ .wbinv = arm64_smccc_cache_wbinv,
+};
+
+static int __init arm64_smccc_cache_init(void)
+{
+ struct arm_smccc_res res = {};
+ s32 status;
+ 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);
+ status = (s32)res.a0;
+ if (status < 0)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES, &res);
+ status = (s32)res.a0;
+ if (status < 0)
+ return -ENODEV;
+
+ arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_CLEAN_INV_MEMREGION_ATTRIBUTES, &res);
+ status = (s32)res.a0;
+ if (status)
+ return -ENODEV;
+
+ arm64_smccc_cache =
+ cache_coherency_ops_instance_alloc(&arm64_smccc_cache_ops,
+ struct arm64_smccc_cache,
+ cci);
+ if (!arm64_smccc_cache)
+ return -ENOMEM;
+
+ mutex_init(&arm64_smccc_cache->lock);
+ arm64_smccc_cache->latency_us = lower_32_bits(res.a2);
+ arm64_smccc_cache->rate_limit = lower_32_bits(res.a3);
+ arm64_smccc_cache->global_op = !!(res.a1 & SMCCC_CACHE_ATTR_GLOBAL_OP);
+
+ ret = cache_coherency_ops_instance_register(&arm64_smccc_cache->cci);
+ if (ret) {
+ cache_coherency_ops_instance_put(&arm64_smccc_cache->cci);
+ arm64_smccc_cache = NULL;
+ return ret;
+ }
+
+ pr_info("SMCCC cache clean+invalidate provider registered\n");
+ return 0;
+}
+arch_initcall(arm64_smccc_cache_init);
--
2.43.0
next prev parent reply other threads:[~2026-05-21 7:31 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-21 7:30 [RFC PATCH 0/2] arm64: add SMCCC cache invalidation backend for memregion users Srirangan Madhavan
2026-05-21 7:30 ` [RFC PATCH 1/2] arm64: smccc: add cache clean/invalidate IDs and return codes Srirangan Madhavan
2026-05-21 7:30 ` Srirangan Madhavan [this message]
2026-05-21 11:18 ` [RFC PATCH 2/2] arm64: mm: add SMCCC-backed cache invalidate provider Jonathan Cameron
2026-05-21 14:12 ` Conor Dooley
2026-05-21 16:35 ` Catalin Marinas
2026-05-21 20:10 ` Dan Williams (nvidia)
2026-05-21 11:28 ` [RFC PATCH 0/2] arm64: add SMCCC cache invalidation backend for memregion users Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260521073047.320614-3-smadhavan@nvidia.com \
--to=smadhavan@nvidia.com \
--cc=alwilliamson@nvidia.com \
--cc=catalin.marinas@arm.com \
--cc=conor@kernel.org \
--cc=danwilliams@nvidia.com \
--cc=jevans@nvidia.com \
--cc=jic23@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mark.rutland@arm.com \
--cc=nbenech@nvidia.com \
--cc=raghupathyk@nvidia.com \
--cc=srikars@nvidia.com \
--cc=sudeep.holla@arm.com \
--cc=vsethi@nvidia.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox