[PATCH v1 2/2] cache: add SMCCC-backed cache invalidate provider
Jonathan Cameron
jic23 at kernel.org
Tue Jun 2 08:03:20 PDT 2026
On Tue, 2 Jun 2026 08:21:45 +0000
Srirangan Madhavan <smadhavan at 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 at 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 at 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;
> +}
More information about the linux-arm-kernel
mailing list