From: Srirangan Madhavan <smadhavan@nvidia.com>
To: mark.rutland@arm.com, lpieralisi@kernel.org,
sudeep.holla@kernel.org, conor@kernel.org, jic23@kernel.org
Cc: catalin.marinas@arm.com, will@kernel.org, treding@nvidia.com,
jonathanh@nvidia.com, bence.csokas@arm.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
Srirangan Madhavan <smadhavan@nvidia.com>
Subject: [PATCH v3 2/2] cache: add SMCCC-backed cache invalidate provider
Date: Thu, 10 Sep 2026 08:21:42 +0000 [thread overview]
Message-ID: <20260910082142.1522865-3-smadhavan@nvidia.com> (raw)
In-Reply-To: <20260910082142.1522865-1-smadhavan@nvidia.com>
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>
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/cache/Kconfig | 11 +++
drivers/cache/Makefile | 2 +
drivers/cache/arm_smccc_cache.c | 149 ++++++++++++++++++++++++++++++++
3 files changed, 162 insertions(+)
create mode 100644 drivers/cache/arm_smccc_cache.c
diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
index 1518449d47b5..57fd1823dec5 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 this 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..55736a032d6f 100644
--- a/drivers/cache/Makefile
+++ b/drivers/cache/Makefile
@@ -4,4 +4,6 @@ obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o
obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
obj-$(CONFIG_STARFIVE_STARLINK_CACHE) += starfive_starlink_cache.o
+# Providers below depend on CACHEMAINT_FOR_HOTPLUG.
+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..1cfa8f8809d0
--- /dev/null
+++ b/drivers/cache/arm_smccc_cache.c
@@ -0,0 +1,149 @@
+// 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. */
+ u64 rate_limit;
+ u32 latency_us;
+};
+
+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);
+ unsigned long delay_us = smccc_cache_delay_us(cache);
+ struct arm_smccc_res res = {};
+ 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 five 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;
+
+ fsleep(delay_us);
+ }
+
+ return ret;
+}
+
+static const struct cache_coherency_ops smccc_cache_ops = {
+ .wbinv = smccc_cache_wbinv,
+};
+
+static int __init smccc_cache_init(void)
+{
+ struct arm_smccc_res res = {};
+ struct smccc_cache *cache;
+ 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_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 = 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;
+ }
+
+ return 0;
+}
+arch_initcall(smccc_cache_init);
--
2.43.0
next prev parent reply other threads:[~2026-09-10 8:22 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-10 8:21 [PATCH v3 0/2] Add SMCCC cache clean/invalidate provider Srirangan Madhavan
2026-09-10 8:21 ` [PATCH v3 1/2] arm64: smccc: add cache clean/invalidate IDs and return codes Srirangan Madhavan
2026-09-10 8:21 ` Srirangan Madhavan [this message]
2026-09-10 18:52 ` [PATCH v3 2/2] cache: add SMCCC-backed cache invalidate provider Jonathan Cameron
2026-09-12 11:05 ` Conor Dooley
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=20260910082142.1522865-3-smadhavan@nvidia.com \
--to=smadhavan@nvidia.com \
--cc=bence.csokas@arm.com \
--cc=catalin.marinas@arm.com \
--cc=conor@kernel.org \
--cc=jic23@kernel.org \
--cc=jonathanh@nvidia.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mark.rutland@arm.com \
--cc=sudeep.holla@kernel.org \
--cc=treding@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.