linux-acpi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/8] Cache coherency management subsystem
@ 2025-08-20 10:29 Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 1/8] memregion: Drop unused IORES_DESC_* parameter from cpu_cache_invalidate_memregion() Jonathan Cameron
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

Support system level interfaces for cache maintenance as found on some
ARM64 systems. This is needed for correct functionality during various
forms of memory hotplug (e.g. CXL). Typical hardware has MMIO interface
found via ACPI DSDT.

Includes parameter changes to cpu_cache_invalidate_memregion() but no
functional changes for architectures that already support this call.

v3:
  - Squash the layers by moving all the management code into
    lib/cache_maint.c that architectures can opt into via
    GENERIC_CPU_CACHE_MAINTENANCE (Dan).  I added entries to Conor's
    drivers/cache MAINTAINERS entry to include this lib/ code but if
    preferred I can add a separate entry for it.
  - Add a new patch 1 that drops the old IODESC_RES_ parameter as it never
    did anything other than document intent.  With the addition of a
    flushing range, we would have to check the range and resource type
    matched. Simpler to just drop the parameter. (Dan)
  - Minor fixes and renames as per reviews.
  - Even if all else looks good, I fully expect some discussion of the
    naming as I'm not particularly happy with it.
  - Open question on whether is acceptable for the answer to whether
    cpu_cache_invalidate_memregion() is supported to change as drivers
    register (potentially after initial boot).  Could design a firmware
    table solution to this, but will take a while - not sure if it is
    necessary.
  - Switch to a fwctl style allocation function that makes the container
    nature of the allocation explicit.

On current ARM64 systems (and likely other architectures) the
implementation of cache flushing need for actions such as CXL memory
hotplug e.g. cpu_cache_invalidate_memregion(), is performed by system
components outside of the CPU, controlled via either firmware or MMIO
interfaces.

These control units run the necessary coherency protocol operations to
cause the write backs and cache flushes to occur asynchronously. The allow
filtering by PA range to reduce disruption to the system. Systems
supporting this interface must be designed to ensure that, when complete,
all cache lines in the range are in invalid state or clean state
(prefetches may have raced with the invalidation). This must include
memory-side caches and other non architectural caches beyond the Point
of Coherence (ARM terminology) such that writes will reach memory even
after OS programmable address decoders are modified (for CXL this is
any HDM decoders that aren't locked). Software will guarantee that no
writes to these memory ranges race with this operation. Whilst this is
subtly different from write backs must reach the physical memory that
difference probably doesn't matter to those reading this series.

The possible distributed nature of the relevant coherency management
units (e.g. due to interleaving) requires the appropriate commands to be
issued to multiple (potentially heterogeneous) units. To enable this a
registration framework is provided to which drivers may register a set
of callbacks. Upon a request for a cache maintenance operation the
framework iterates over all registered callback sets, calling first a
command to write back and invalidate, and then optionally a command to wait
for completion. Filtering on relevance is left to the individual drivers.

Two drivers are included. This HiSilicon Hydra Home Agent driver which
controls hardware found on some of our relevant server SoCs and,
mostly to show that the approach is general, a driver based on a firmware
interface that was in a public PSCI specification alpha version
(now dropped - don't merge that!)

QEMU emulation code at
http://gitlab.com/jic23/qemu cxl-2025-03-20 

Remaining opens:
- Naming.  All suggestions welcome!
- I don't particularly like defining 'generic' infrastructure with so few
  implementations. If anyone can point me at docs for another one or two,
  or confirm that they think this is fine that would be great!
- I made up the ACPI spec - it's not documented, non official and honestly
  needs work. I would however like to get feedback on whether it is
  something we want to try and get through the ACPI Working group as a much
  improved code first proposal?  The potential justification being to avoid
  the need for lots trivial drivers where maybe a bit of DSDT interpreted
  code does the job better. (Currently I'm not hearing much demand for this
  so will probably drop in a future version).

Thanks to all who engaged in the discussion so far.

Jonathan

Jonathan Cameron (5):
  memregion: Drop unused IORES_DESC_* parameter from
    cpu_cache_invalidate_memregion()
  MAINTAINERS: Add Jonathan Cameron to drivers/cache
  arm64: Select GENERIC_CPU_CACHE_MAINTENANCE and
    ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
  acpi: PoC of Cache control via ACPI0019 and _DSM
  Hack: Pretend we have PSCI 1.2

Yicong Yang (2):
  memregion: Support fine grained invalidate by
    cpu_cache_invalidate_memregion()
  lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION

Yushan Wang (1):
  cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent

 MAINTAINERS                        |   3 +
 arch/arm64/Kconfig                 |   2 +
 arch/x86/mm/pat/set_memory.c       |   2 +-
 drivers/cache/Kconfig              |  22 ++++
 drivers/cache/Makefile             |   3 +
 drivers/cache/acpi_cache_control.c | 153 +++++++++++++++++++++++
 drivers/cache/hisi_soc_hha.c       | 187 +++++++++++++++++++++++++++++
 drivers/cxl/core/region.c          |   5 +-
 drivers/firmware/psci/psci.c       |   2 +
 drivers/nvdimm/region.c            |   2 +-
 drivers/nvdimm/region_devs.c       |   2 +-
 include/linux/cache_coherency.h    |  57 +++++++++
 include/linux/memregion.h          |  10 +-
 lib/Kconfig                        |   3 +
 lib/Makefile                       |   2 +
 lib/cache_maint.c                  | 128 ++++++++++++++++++++
 16 files changed, 575 insertions(+), 8 deletions(-)
 create mode 100644 drivers/cache/acpi_cache_control.c
 create mode 100644 drivers/cache/hisi_soc_hha.c
 create mode 100644 include/linux/cache_coherency.h
 create mode 100644 lib/cache_maint.c

-- 
2.48.1


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v3 1/8] memregion: Drop unused IORES_DESC_* parameter from cpu_cache_invalidate_memregion()
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 2/8] memregion: Support fine grained invalidate by cpu_cache_invalidate_memregion() Jonathan Cameron
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

The res_desc parameter was originally introduced for documentation purposes
and with the idea that with HDM-DB CXL invalidation could be triggered from
the device. That has not come to pass and the continued existence of the
option is confusing when we add a range in the following patch which might
not be a strict subset of the res_desc. So avoid that confusion by dropping
the parameter.

Link: https://lore.kernel.org/linux-mm/686eedb25ed02_24471002e@dwillia2-xfh.jf.intel.com.notmuch/
Suggested-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

---
V3: New patch.
    As Dan calls out in the linked mail, an alternative might be to lookup
    the ranges and enforce the descriptor but his expressed preference
    was for dropping the parameter.
---
 arch/x86/mm/pat/set_memory.c | 2 +-
 drivers/cxl/core/region.c    | 2 +-
 drivers/nvdimm/region.c      | 2 +-
 drivers/nvdimm/region_devs.c | 2 +-
 include/linux/memregion.h    | 7 +++----
 5 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 8834c76f91c9..4019b17fb65e 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -368,7 +368,7 @@ bool cpu_cache_has_invalidate_memregion(void)
 }
 EXPORT_SYMBOL_NS_GPL(cpu_cache_has_invalidate_memregion, "DEVMEM");
 
-int cpu_cache_invalidate_memregion(int res_desc)
+int cpu_cache_invalidate_memregion(void)
 {
 	if (WARN_ON_ONCE(!cpu_cache_has_invalidate_memregion()))
 		return -ENXIO;
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 71cc42d05248..d7fa76810f82 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -228,7 +228,7 @@ static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
 		return -ENXIO;
 	}
 
-	cpu_cache_invalidate_memregion(IORES_DESC_CXL);
+	cpu_cache_invalidate_memregion();
 	return 0;
 }
 
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index 88dc062af5f8..c43506448edf 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -110,7 +110,7 @@ static void nd_region_remove(struct device *dev)
 	 * here is ok.
 	 */
 	if (cpu_cache_has_invalidate_memregion())
-		cpu_cache_invalidate_memregion(IORES_DESC_PERSISTENT_MEMORY);
+		cpu_cache_invalidate_memregion();
 }
 
 static int child_notify(struct device *dev, void *data)
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index de1ee5ebc851..3cdd93d40997 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -90,7 +90,7 @@ static int nd_region_invalidate_memregion(struct nd_region *nd_region)
 		}
 	}
 
-	cpu_cache_invalidate_memregion(IORES_DESC_PERSISTENT_MEMORY);
+	cpu_cache_invalidate_memregion();
 out:
 	for (i = 0; i < nd_region->ndr_mappings; i++) {
 		struct nd_mapping *nd_mapping = &nd_region->mapping[i];
diff --git a/include/linux/memregion.h b/include/linux/memregion.h
index c01321467789..945646bde825 100644
--- a/include/linux/memregion.h
+++ b/include/linux/memregion.h
@@ -26,8 +26,7 @@ static inline void memregion_free(int id)
 
 /**
  * cpu_cache_invalidate_memregion - drop any CPU cached data for
- *     memregions described by @res_desc
- * @res_desc: one of the IORES_DESC_* types
+ *     memregion
  *
  * Perform cache maintenance after a memory event / operation that
  * changes the contents of physical memory in a cache-incoherent manner.
@@ -46,7 +45,7 @@ static inline void memregion_free(int id)
  * the cache maintenance.
  */
 #ifdef CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
-int cpu_cache_invalidate_memregion(int res_desc);
+int cpu_cache_invalidate_memregion(void);
 bool cpu_cache_has_invalidate_memregion(void);
 #else
 static inline bool cpu_cache_has_invalidate_memregion(void)
@@ -54,7 +53,7 @@ static inline bool cpu_cache_has_invalidate_memregion(void)
 	return false;
 }
 
-static inline int cpu_cache_invalidate_memregion(int res_desc)
+static inline int cpu_cache_invalidate_memregion(void)
 {
 	WARN_ON_ONCE("CPU cache invalidation required");
 	return -ENXIO;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 2/8] memregion: Support fine grained invalidate by cpu_cache_invalidate_memregion()
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 1/8] memregion: Drop unused IORES_DESC_* parameter from cpu_cache_invalidate_memregion() Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

From: Yicong Yang <yangyicong@hisilicon.com>

Extend cpu_cache_invalidate_memregion() to support invalidate certain range
of memory by introducing start and length parameters. Control of types of
invalidation is left for when usecases turn up. For now everything is
Clean and Invalidate.

Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Acked-by: Davidlohr Bueso <dave@stgolabs.net>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

---
v3: Rebase on top of previous patch that removed the IO_RESDESC_*
    parameter.
---
 arch/x86/mm/pat/set_memory.c | 2 +-
 drivers/cxl/core/region.c    | 5 ++++-
 drivers/nvdimm/region.c      | 2 +-
 drivers/nvdimm/region_devs.c | 2 +-
 include/linux/memregion.h    | 7 +++++--
 5 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 4019b17fb65e..292c7202faed 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -368,7 +368,7 @@ bool cpu_cache_has_invalidate_memregion(void)
 }
 EXPORT_SYMBOL_NS_GPL(cpu_cache_has_invalidate_memregion, "DEVMEM");
 
-int cpu_cache_invalidate_memregion(void)
+int cpu_cache_invalidate_memregion(phys_addr_t start, size_t len)
 {
 	if (WARN_ON_ONCE(!cpu_cache_has_invalidate_memregion()))
 		return -ENXIO;
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index d7fa76810f82..410e41cef5d3 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -228,7 +228,10 @@ static int cxl_region_invalidate_memregion(struct cxl_region *cxlr)
 		return -ENXIO;
 	}
 
-	cpu_cache_invalidate_memregion();
+	if (!cxlr->params.res)
+		return -ENXIO;
+	cpu_cache_invalidate_memregion(cxlr->params.res->start,
+				       resource_size(cxlr->params.res));
 	return 0;
 }
 
diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c
index c43506448edf..62535d200402 100644
--- a/drivers/nvdimm/region.c
+++ b/drivers/nvdimm/region.c
@@ -110,7 +110,7 @@ static void nd_region_remove(struct device *dev)
 	 * here is ok.
 	 */
 	if (cpu_cache_has_invalidate_memregion())
-		cpu_cache_invalidate_memregion();
+		cpu_cache_invalidate_memregion(0, -1);
 }
 
 static int child_notify(struct device *dev, void *data)
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index 3cdd93d40997..7c1d27c75b73 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -90,7 +90,7 @@ static int nd_region_invalidate_memregion(struct nd_region *nd_region)
 		}
 	}
 
-	cpu_cache_invalidate_memregion();
+	cpu_cache_invalidate_memregion(0, -1);
 out:
 	for (i = 0; i < nd_region->ndr_mappings; i++) {
 		struct nd_mapping *nd_mapping = &nd_region->mapping[i];
diff --git a/include/linux/memregion.h b/include/linux/memregion.h
index 945646bde825..428635562302 100644
--- a/include/linux/memregion.h
+++ b/include/linux/memregion.h
@@ -27,6 +27,9 @@ static inline void memregion_free(int id)
 /**
  * cpu_cache_invalidate_memregion - drop any CPU cached data for
  *     memregion
+ * @start: start physical address of the target memory region.
+ * @len: length of the target memory region. -1 for all the regions of
+ *       the target type.
  *
  * Perform cache maintenance after a memory event / operation that
  * changes the contents of physical memory in a cache-incoherent manner.
@@ -45,7 +48,7 @@ static inline void memregion_free(int id)
  * the cache maintenance.
  */
 #ifdef CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
-int cpu_cache_invalidate_memregion(void);
+int cpu_cache_invalidate_memregion(phys_addr_t start, size_t len);
 bool cpu_cache_has_invalidate_memregion(void);
 #else
 static inline bool cpu_cache_has_invalidate_memregion(void)
@@ -53,7 +56,7 @@ static inline bool cpu_cache_has_invalidate_memregion(void)
 	return false;
 }
 
-static inline int cpu_cache_invalidate_memregion(void)
+static inline int cpu_cache_invalidate_memregion(phys_addr_t start, size_t len)
 {
 	WARN_ON_ONCE("CPU cache invalidation required");
 	return -ENXIO;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 1/8] memregion: Drop unused IORES_DESC_* parameter from cpu_cache_invalidate_memregion() Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 2/8] memregion: Support fine grained invalidate by cpu_cache_invalidate_memregion() Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  2025-08-20 17:44   ` Randy Dunlap
  2025-09-03 16:25   ` Catalin Marinas
  2025-08-20 10:29 ` [PATCH v3 4/8] MAINTAINERS: Add Jonathan Cameron to drivers/cache Jonathan Cameron
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

From: Yicong Yang <yangyicong@hisilicon.com>

ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION provides the mechanism for
invalidating certain memory regions in a cache-incoherent manner. Currently
this is used by NVDIMM and CXL memory drivers in cases where it is
necessary to flush all data from caches by physical address range.

In some architectures these operations are supported by system components
that may become available only later in boot as they are either present
on a discoverable bus, or via a firmware description of an MMIO interface
(e.g. ACPI DSDT). Provide a framework to handle this case.

Architectures can opt in for this support via
CONFIG_GENERIC_CPU_CACHE_MAINTENANCE

Add a registration framework. Each driver provides an ops structure and
the first op is Write Back and Invalidate by PA Range. The driver may
over invalidate.

An optional completion check operation is also provided. If present
that should be called to ensure that the action has finished.

When multiple agents are present in the system each should register with
this framework and the core code will issue the invalidate to all of them
before checking for completion on each. This is done to avoid need for
filtering in the core code which can become complex when interleave,
potentially across different cache coherency hardware is going on, so it
is easier to tell everyone and let those who don't care do nothing.

Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Co-developed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
v3: Squash all the layering from v2 so that the infrastucture is
    always present.
    Suggestions on naming welcome. Note that the hardware I have
    available supports a much richer set of maintenance operations
    than Write Back and Invalidate, so I'd like a name that
    covers all resonable maintenance operations.
    Use an allocation wrapper macro, based on the fwctl one to
    ensure that the first element of the allocated driver structure
    is a struct cache_coherency_device.
    Thanks to all who provided feedback.
---
 include/linux/cache_coherency.h |  57 ++++++++++++++
 lib/Kconfig                     |   3 +
 lib/Makefile                    |   2 +
 lib/cache_maint.c               | 128 ++++++++++++++++++++++++++++++++
 4 files changed, 190 insertions(+)

diff --git a/include/linux/cache_coherency.h b/include/linux/cache_coherency.h
new file mode 100644
index 000000000000..cb195b17b6e6
--- /dev/null
+++ b/include/linux/cache_coherency.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Cache coherency maintenace operation device drivers
+ *
+ * Copyright Huawei 2025
+ */
+#ifndef _LINUX_CACHE_COHERENCY_H_
+#define _LINUX_CACHE_COHERENCY_H_
+
+#include <linux/list.h>
+#include <linux/types.h>
+
+struct cc_inval_params {
+	phys_addr_t addr;
+	size_t size;
+};
+
+struct cache_coherency_device;
+
+struct coherency_ops {
+	int (*wbinv)(struct cache_coherency_device *ccd, struct cc_inval_params *invp);
+	int (*done)(struct cache_coherency_device *ccd);
+};
+
+struct cache_coherency_device {
+	struct list_head node;
+	const struct coherency_ops *ops;
+};
+
+int cache_coherency_device_register(struct cache_coherency_device *ccd);
+void cache_coherency_device_unregister(struct cache_coherency_device *ccd);
+
+struct cache_coherency_device *
+_cache_coherency_device_alloc(const struct coherency_ops *ops, size_t size);
+/**
+ * cache_coherency_device_alloc - Allocate a cache coherency device
+ * @ops: Cache maintenance operations
+ * @drv_struct: structure that contains the struct cache_coherency_device
+ * @member: Name of the struct cache_coherency_device member in @drv_struct.
+ *
+ * This allocates and initializes the cache_coherency_device embedded in the
+ * drv_struct. Upon success the pointer must be freed via
+ * cache_coherency_device_free().
+ *
+ * Returns a 'drv_struct \*' on success, NULL on error.
+ */
+#define cache_coherency_device_alloc(ops, drv_struct, member)	    \
+	({								    \
+		static_assert(__same_type(struct cache_coherency_device,    \
+					  ((drv_struct *)NULL)->member));   \
+		static_assert(offsetof(drv_struct, member) == 0);	    \
+		(drv_struct *)_cache_coherency_device_alloc(ops,	    \
+			sizeof(drv_struct));				    \
+	})
+void cache_coherency_device_free(struct cache_coherency_device *ccd);
+
+#endif
diff --git a/lib/Kconfig b/lib/Kconfig
index c483951b624f..cd8e5844f9bb 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -543,6 +543,9 @@ config MEMREGION
 config ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
 	bool
 
+config GENERIC_CPU_CACHE_MAINTENANCE
+	bool
+
 config ARCH_HAS_MEMREMAP_COMPAT_ALIGN
 	bool
 
diff --git a/lib/Makefile b/lib/Makefile
index 392ff808c9b9..eed20c50f358 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -130,6 +130,8 @@ obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
 obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
 
+obj-$(CONFIG_GENERIC_CPU_CACHE_MAINTENANCE) += cache_maint.o
+
 lib-y += logic_pio.o
 
 lib-$(CONFIG_INDIRECT_IOMEM) += logic_iomem.o
diff --git a/lib/cache_maint.c b/lib/cache_maint.c
new file mode 100644
index 000000000000..05d9c5e99941
--- /dev/null
+++ b/lib/cache_maint.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic support for Memory System Cache Maintenance operations.
+ *
+ * Coherency maintenance drivers register with this simple framework that will
+ * iterate over each registered instance to first kick off invalidation and
+ * then to wait until it is complete.
+ *
+ * If no implementations are registered yet cpu_cache_has_invalidate_memregion()
+ * will return false. If this runs concurrently with unregistration then a
+ * race exists but this is no worse than the case where the device responsible
+ * for a given memory region has not yet registered.
+ */
+#include <linux/cache_coherency.h>
+#include <linux/cleanup.h>
+#include <linux/container_of.h>
+#include <linux/export.h>
+#include <linux/list.h>
+#include <linux/memregion.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+
+static LIST_HEAD(cache_device_list);
+static DECLARE_RWSEM(cache_device_list_lock);
+
+void cache_coherency_device_free(struct cache_coherency_device *ccd)
+{
+	kfree(ccd);
+}
+EXPORT_SYMBOL_GPL(cache_coherency_device_free);
+
+static int cache_inval_one(struct cache_coherency_device *ccd, void *data)
+{
+	if (!ccd->ops)
+		return -EINVAL;
+
+	return ccd->ops->wbinv(ccd, data);
+}
+
+static int cache_inval_done_one(struct cache_coherency_device *ccd)
+{
+	if (!ccd->ops)
+		return -EINVAL;
+
+	if (!ccd->ops->done)
+		return 0;
+
+	return ccd->ops->done(ccd);
+}
+
+static int cache_invalidate_memregion(phys_addr_t addr, size_t size)
+{
+	int ret;
+	struct cache_coherency_device *ccd;
+	struct cc_inval_params params = {
+		.addr = addr,
+		.size = size,
+	};
+
+	guard(rwsem_read)(&cache_device_list_lock);
+	list_for_each_entry(ccd, &cache_device_list, node) {
+		ret = cache_inval_one(ccd, &params);
+		if (ret)
+			return ret;
+	}
+	list_for_each_entry(ccd, &cache_device_list, node) {
+		ret = cache_inval_done_one(ccd);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct cache_coherency_device *
+_cache_coherency_device_alloc(const struct coherency_ops *ops, size_t size)
+{
+	struct cache_coherency_device *ccd;
+
+	if (!ops || !ops->wbinv)
+		return NULL;
+
+	ccd = kzalloc(size, GFP_KERNEL);
+	if (!ccd)
+		return NULL;
+
+	ccd->ops = ops;
+	INIT_LIST_HEAD(&ccd->node);
+
+	return ccd;
+}
+EXPORT_SYMBOL_NS_GPL(_cache_coherency_device_alloc, "CACHE_COHERENCY");
+
+int cache_coherency_device_register(struct cache_coherency_device *ccd)
+{
+	guard(rwsem_write)(&cache_device_list_lock);
+	list_add(&ccd->node, &cache_device_list);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cache_coherency_device_register, "CACHE_COHERENCY");
+
+void cache_coherency_device_unregister(struct cache_coherency_device *ccd)
+{
+	guard(rwsem_write)(&cache_device_list_lock);
+	list_del(&ccd->node);
+}
+EXPORT_SYMBOL_NS_GPL(cache_coherency_device_unregister, "CACHE_COHERENCY");
+
+int cpu_cache_invalidate_memregion(phys_addr_t start, size_t len)
+{
+	return cache_invalidate_memregion(start, len);
+}
+EXPORT_SYMBOL_NS_GPL(cpu_cache_invalidate_memregion, "DEVMEM");
+
+/*
+ * Used for optimization / debug purposes only as removal can race
+ *
+ * Machines that do not support invalidation, e.g. VMs, will not
+ * have any devices to register and so this will always return false.
+ */
+bool cpu_cache_has_invalidate_memregion(void)
+{
+	guard(rwsem_read)(&cache_device_list_lock);
+	return !list_empty(&cache_device_list);
+}
+EXPORT_SYMBOL_NS_GPL(cpu_cache_has_invalidate_memregion, "DEVMEM");
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 4/8] MAINTAINERS: Add Jonathan Cameron to drivers/cache
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
                   ` (2 preceding siblings ...)
  2025-08-20 10:29 ` [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 5/8] arm64: Select GENERIC_CPU_CACHE_MAINTENANCE and ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

Seems unfair to inflict the cache-coherency drivers on Conor with out
also stepping up as a second maintainer for drivers/cache.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
v3: Add lib/cache_maint.c and include/cache_coherency.h
    Conor, do you mind those two being in this entry? Seems silly to spin
    another MAINTAINERS entry for a few 10s of lines of simple code.
---
 MAINTAINERS | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index fe168477caa4..039d10ded9e9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23967,10 +23967,13 @@ F:	drivers/staging/
 
 STANDALONE CACHE CONTROLLER DRIVERS
 M:	Conor Dooley <conor@kernel.org>
+M:	Jonathan Cameron <jonathan.cameron@huawei.com>
 S:	Maintained
 T:	git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
 F:	Documentation/devicetree/bindings/cache/
 F:	drivers/cache
+F:	include/cache_coherency.h
+F:	lib/cache_maint.c
 
 STARFIRE/DURALAN NETWORK DRIVER
 M:	Ion Badulescu <ionut@badula.org>
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 5/8] arm64: Select GENERIC_CPU_CACHE_MAINTENANCE and ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
                   ` (3 preceding siblings ...)
  2025-08-20 10:29 ` [PATCH v3 4/8] MAINTAINERS: Add Jonathan Cameron to drivers/cache Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  2025-09-03 16:25   ` Catalin Marinas
  2025-08-20 10:29 ` [PATCH v3 6/8] cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent Jonathan Cameron
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

Ensure the hooks that the generic cache maintenance framework uses are
available on ARM64 by selecting ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION.

The generic CPU cache maintenance framework provides a way to register
drivers for devices implementing the underlying support for
cpu_cache_has_invalidate_memregion().

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 arch/arm64/Kconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index e9bbfacc35a6..15bf429b3f59 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -21,6 +21,7 @@ config ARM64
 	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
 	select ARCH_HAS_CACHE_LINE_SIZE
 	select ARCH_HAS_CC_PLATFORM
+	select ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DEBUG_VIRTUAL
 	select ARCH_HAS_DEBUG_VM_PGTABLE
@@ -146,6 +147,7 @@ config ARM64
 	select GENERIC_ARCH_TOPOLOGY
 	select GENERIC_CLOCKEVENTS_BROADCAST
 	select GENERIC_CPU_AUTOPROBE
+	select GENERIC_CPU_CACHE_MAINTENANCE
 	select GENERIC_CPU_DEVICES
 	select GENERIC_CPU_VULNERABILITIES
 	select GENERIC_EARLY_IOREMAP
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 6/8] cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
                   ` (4 preceding siblings ...)
  2025-08-20 10:29 ` [PATCH v3 5/8] arm64: Select GENERIC_CPU_CACHE_MAINTENANCE and ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 7/8] acpi: PoC of Cache control via ACPI0019 and _DSM Jonathan Cameron
  2025-08-20 10:29 ` [PATCH v3 8/8] Hack: Pretend we have PSCI 1.2 Jonathan Cameron
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

From: Yushan Wang <wangyushan12@huawei.com>

Hydra Home Agent is a device used to maintain cache coherency. Add support
of explicit cache maintenance operations for it.

Memory resource of HHA conflicts with that of HHA PMU. A workaround is
implemented here by replacing devm_ioremap_resource() to devm_ioremap() to
workaround the resource conflict check.

Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Co-developed-by: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Yushan Wang <wangyushan12@huawei.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/cache/Kconfig        |  15 +++
 drivers/cache/Makefile       |   2 +
 drivers/cache/hisi_soc_hha.c | 187 +++++++++++++++++++++++++++++++++++
 3 files changed, 204 insertions(+)

diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
index db51386c663a..4551b28e14dd 100644
--- a/drivers/cache/Kconfig
+++ b/drivers/cache/Kconfig
@@ -1,6 +1,21 @@
 # SPDX-License-Identifier: GPL-2.0
 menu "Cache Drivers"
 
+if GENERIC_CPU_CACHE_MAINTENANCE
+
+config HISI_SOC_HHA
+	tristate "HiSilicon Hydra Home Agent (HHA) device driver"
+	depends on (ARM64 && ACPI) || COMPILE_TEST
+	help
+	  The Hydra Home Agent (HHA) is responsible for cache coherency
+	  on the SoC. This drivers enables the cache maintenance functions of
+	  the HHA.
+
+	  This driver can be built as a module. If so, the module will be
+	  called hisi_soc_hha.
+
+endif
+
 config AX45MP_L2_CACHE
 	bool "Andes Technology AX45MP L2 Cache controller"
 	depends on RISCV
diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile
index 55c5e851034d..b3362b15d6c1 100644
--- a/drivers/cache/Makefile
+++ b/drivers/cache/Makefile
@@ -3,3 +3,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_HISI_SOC_HHA)		+= hisi_soc_hha.o
diff --git a/drivers/cache/hisi_soc_hha.c b/drivers/cache/hisi_soc_hha.c
new file mode 100644
index 000000000000..9a26a562804e
--- /dev/null
+++ b/drivers/cache/hisi_soc_hha.c
@@ -0,0 +1,187 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for HiSilicon Hydra Home Agent (HHA).
+ *
+ * Copyright (c) 2025 HiSilicon Technologies Co., Ltd.
+ * Author: Yicong Yang <yangyicong@hisilicon.com>
+ *         Yushan Wang <wangyushan12@huawei.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cacheflush.h>
+#include <linux/cache_coherency.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/memregion.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#define HISI_HHA_CTRL		0x5004
+#define   HISI_HHA_CTRL_EN	BIT(0)
+#define   HISI_HHA_CTRL_RANGE	BIT(1)
+#define   HISI_HHA_CTRL_TYPE	GENMASK(3, 2)
+#define HISI_HHA_START_L	0x5008
+#define HISI_HHA_START_H	0x500c
+#define HISI_HHA_LEN_L		0x5010
+#define HISI_HHA_LEN_H		0x5014
+
+/* The maintain operation performs in a 128 Byte granularity */
+#define HISI_HHA_MAINT_ALIGN	128
+
+#define HISI_HHA_POLL_GAP_US		10
+#define HISI_HHA_POLL_TIMEOUT_US	50000
+
+struct hisi_soc_hha {
+	/* Must be first element */
+	struct cache_coherency_device ccd;
+	/* Locks HHA instance to forbid overlapping access. */
+	struct mutex lock;
+	void __iomem *base;
+};
+
+static bool hisi_hha_cache_maintain_wait_finished(struct hisi_soc_hha *soc_hha)
+{
+	u32 val;
+
+	return !readl_poll_timeout_atomic(soc_hha->base + HISI_HHA_CTRL, val,
+					  !(val & HISI_HHA_CTRL_EN),
+					  HISI_HHA_POLL_GAP_US,
+					  HISI_HHA_POLL_TIMEOUT_US);
+}
+
+static int hisi_soc_hha_wbinv(struct cache_coherency_device *ccd, struct cc_inval_params *invp)
+{
+	struct hisi_soc_hha *soc_hha = container_of(ccd, struct hisi_soc_hha, ccd);
+	phys_addr_t top, addr = invp->addr;
+	size_t size = invp->size;
+	u32 reg;
+
+	if (!size)
+		return -EINVAL;
+
+	addr = ALIGN_DOWN(addr, HISI_HHA_MAINT_ALIGN);
+	top = ALIGN(addr + size, HISI_HHA_MAINT_ALIGN);
+	size = top - addr;
+
+	guard(mutex)(&soc_hha->lock);
+
+	if (!hisi_hha_cache_maintain_wait_finished(soc_hha))
+		return -EBUSY;
+
+	/*
+	 * Hardware will search for addresses ranging [addr, addr + size - 1],
+	 * last byte included, and perform maintain in 128 byte granule
+	 * on those cachelines which contain the addresses.
+	 */
+	size -= 1;
+
+	writel(lower_32_bits(addr), soc_hha->base + HISI_HHA_START_L);
+	writel(upper_32_bits(addr), soc_hha->base + HISI_HHA_START_H);
+	writel(lower_32_bits(size), soc_hha->base + HISI_HHA_LEN_L);
+	writel(upper_32_bits(size), soc_hha->base + HISI_HHA_LEN_H);
+
+	reg = FIELD_PREP(HISI_HHA_CTRL_TYPE, 1); /* Clean Invalid */
+	reg |= HISI_HHA_CTRL_RANGE | HISI_HHA_CTRL_EN;
+	writel(reg, soc_hha->base + HISI_HHA_CTRL);
+
+	return 0;
+}
+
+static int hisi_soc_hha_done(struct cache_coherency_device *ccd)
+{
+	struct hisi_soc_hha *soc_hha = container_of(ccd, struct hisi_soc_hha, ccd);
+
+	guard(mutex)(&soc_hha->lock);
+	if (!hisi_hha_cache_maintain_wait_finished(soc_hha))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static const struct coherency_ops hha_ops = {
+	.wbinv = hisi_soc_hha_wbinv,
+	.done = hisi_soc_hha_done,
+};
+
+static int hisi_soc_hha_probe(struct platform_device *pdev)
+{
+	struct hisi_soc_hha *soc_hha;
+	struct resource *mem;
+	int ret;
+
+	soc_hha = cache_coherency_device_alloc(&hha_ops, struct hisi_soc_hha,
+					       ccd);
+	if (!soc_hha)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, soc_hha);
+
+	mutex_init(&soc_hha->lock);
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem)
+		return -ENODEV;
+
+	/*
+	 * HHA cache driver share the same register region with HHA uncore PMU
+	 * driver in hardware's perspective, none of them should reserve the
+	 * resource to itself only.  Here exclusive access verification is
+	 * avoided by calling devm_ioremap instead of devm_ioremap_resource to
+	 * allow both drivers to exist at the same time.
+	 */
+	soc_hha->base = ioremap(mem->start, resource_size(mem));
+	if (IS_ERR_OR_NULL(soc_hha->base)) {
+		ret = dev_err_probe(&pdev->dev, PTR_ERR(soc_hha->base),
+				"failed to remap io memory");
+		goto err_free_ccd;
+	}
+
+	ret = cache_coherency_device_register(&soc_hha->ccd);
+	if (ret)
+		goto err_iounmap;
+
+	return 0;
+
+err_iounmap:
+	iounmap(soc_hha->base);
+err_free_ccd:
+	cache_coherency_device_free(&soc_hha->ccd);
+	return ret;
+}
+
+static void hisi_soc_hha_remove(struct platform_device *pdev)
+{
+	struct hisi_soc_hha *soc_hha = platform_get_drvdata(pdev);
+
+	cache_coherency_device_unregister(&soc_hha->ccd);
+	iounmap(soc_hha->base);
+	cache_coherency_device_free(&soc_hha->ccd);
+}
+
+static const struct acpi_device_id hisi_soc_hha_ids[] = {
+	{ "HISI0511", },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, hisi_soc_hha_ids);
+
+static struct platform_driver hisi_soc_hha_driver = {
+	.driver = {
+		.name = "hisi_soc_hha",
+		.acpi_match_table = hisi_soc_hha_ids,
+	},
+	.probe = hisi_soc_hha_probe,
+	.remove = hisi_soc_hha_remove,
+};
+
+module_platform_driver(hisi_soc_hha_driver);
+
+MODULE_IMPORT_NS("CACHE_COHERENCY");
+MODULE_DESCRIPTION("HiSilicon Hydra Home Agent driver supporting cache maintenance");
+MODULE_AUTHOR("Yicong Yang <yangyicong@hisilicon.com>");
+MODULE_AUTHOR("Yushan Wang <wangyushan12@huawei.com>");
+MODULE_LICENSE("GPL");
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 7/8] acpi: PoC of Cache control via ACPI0019 and _DSM
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
                   ` (5 preceding siblings ...)
  2025-08-20 10:29 ` [PATCH v3 6/8] cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  2025-08-20 17:07   ` Randy Dunlap
  2025-08-20 10:29 ` [PATCH v3 8/8] Hack: Pretend we have PSCI 1.2 Jonathan Cameron
  7 siblings, 1 reply; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

Do not merge. This is the bare outline of what may become an ACPI code
first specification proposal. For that reason it remains an RFC and is
mainly here to show that the framework is flexible enough to be useful
by providing a second driver.

From various discussions, it has become clear that there is some desire not
to end up needing a cache flushing driver for every host that supports the
flush by PA range functionality that is needed for CXL and similar
disagregated memory pools where the host PA mapping to actual memory may
change over time and where various races can occur with prefetchers making
it hard to use CPU instructions to flush all stale data out.

There was once an ARM PSCI specification [1] that defined a firmware
interface to solve this problem. However that meant dropping into a more
privileged mode, or chatting to an external firmware. That was overkill for
those systems that provide a simple MMIO register interface for these
operations (which seems to be the common case). That specification never
made it beyond alpha level.

For the typical class of machine that actually uses these disaggregated
pools, ACPI can potentially provide the same benefits with a great deal
more flexibility. A _DSM in DSDT via operation regions, may be used to do
any of:
1) Make firmware calls
2) Operate a register based state machine.
3) Most other things you might dream of.

This was prototyped against an implementation of the ARM specification in
[1] wrapped up in _DSM magic. That was chosen to give a second (be it
abandoned) example of how this cache control class can be used.

Link: https://developer.arm.com/documentation/den0022/falp1/?lang=en [1]
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/cache/Kconfig              |   7 ++
 drivers/cache/Makefile             |   1 +
 drivers/cache/acpi_cache_control.c | 153 +++++++++++++++++++++++++++++
 3 files changed, 161 insertions(+)

diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
index 4551b28e14dd..158d3819004e 100644
--- a/drivers/cache/Kconfig
+++ b/drivers/cache/Kconfig
@@ -3,6 +3,13 @@ menu "Cache Drivers"
 
 if GENERIC_CPU_CACHE_MAINTENANCE
 
+config ACPI_CACHE_CONTROL
+       tristate "ACPI cache maintenance"
+       depends on ARM64 && ACPI
+       help
+         ACPI0019 device ID in DSDT identifies an interface that may be used
+	 to carry out certain forms of cache flush operation.
+
 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..94c41b018cd5 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_ACPI_CACHE_CONTROL)   	+= acpi_cache_control.o
 obj-$(CONFIG_HISI_SOC_HHA)		+= hisi_soc_hha.o
diff --git a/drivers/cache/acpi_cache_control.c b/drivers/cache/acpi_cache_control.c
new file mode 100644
index 000000000000..8da7fc2e189e
--- /dev/null
+++ b/drivers/cache/acpi_cache_control.c
@@ -0,0 +1,153 @@
+
+#include <linux/acpi.h>
+#include <linux/cache_coherency.h>
+#include <asm/cacheflush.h>
+
+struct acpi_cache_control {
+	struct cache_coherency_device ccd;
+	struct acpi_device *acpi_dev;
+};
+
+static const guid_t testguid =
+	GUID_INIT(0x61FDC7D5, 0x1468, 0x4807,
+		0xB5, 0x65, 0x51, 0x5B, 0xF6, 0xB7, 0x53, 0x19);
+
+static int acpi_cache_control_query(struct acpi_device *device)
+{
+	union acpi_object *out_obj;
+
+	out_obj = acpi_evaluate_dsm(device->handle, &testguid, 1, 1, NULL);//&in_obj);
+	if (out_obj->package.count < 4) {
+		printk("Only partial capabilities received\n");
+		return -EINVAL;
+	}
+	for (int i = 0; i < out_obj->package.count; i++)
+		if (out_obj->package.elements[i].type != 1) {
+			printk("Element %d not integer\n", i);
+			return -EINVAL;
+		}
+	switch (out_obj->package.elements[0].integer.value) {
+	case 0:
+		printk("Supports range\n");
+		break;
+	case 1:
+		printk("Full flush only\n");
+		break;
+	default:
+		printk("unknown op type %llx\n",
+			out_obj->package.elements[0].integer.value);
+		break;
+	}
+
+	printk("Latency is %lld msecs\n",
+		out_obj->package.elements[1].integer.value);
+	printk("Min delay between calls is %lld msecs\n",
+		out_obj->package.elements[2].integer.value);
+
+	if (out_obj->package.elements[3].integer.value & BIT(0))
+		printk("CLEAN_INVALIDATE\n");
+	if (out_obj->package.elements[3].integer.value & BIT(1))
+		printk("CLEAN\n");
+	if (out_obj->package.elements[3].integer.value & BIT(2))
+		printk("INVALIDATE\n");
+	ACPI_FREE(out_obj);
+	return 0;
+}
+
+static int acpi_cache_control_inval(struct acpi_device *device, u64 base, u64 size)
+{
+	union acpi_object *out_obj;
+	union acpi_object in_array[] = {
+		[0].integer = { ACPI_TYPE_INTEGER, base },
+		[1].integer = { ACPI_TYPE_INTEGER, size },
+		[2].integer = { ACPI_TYPE_INTEGER, 0 }, // Clean invalidate
+	};
+	union acpi_object in_obj = {
+		.package = {
+			.type = ACPI_TYPE_PACKAGE,
+			.count = ARRAY_SIZE(in_array),
+			.elements = in_array,
+		},
+	};
+
+	out_obj = acpi_evaluate_dsm(device->handle, &testguid, 1, 2, &in_obj);
+	ACPI_FREE(out_obj);
+	return 0;
+}
+
+static int acpi_cc_wbinv(struct cache_coherency_device *ccd,
+			 struct cc_inval_params *invp)
+{
+	struct acpi_cache_control *acpi_cc =
+		container_of(ccd, struct acpi_cache_control, ccd);
+
+	return acpi_cache_control_inval(acpi_cc->acpi_dev, invp->addr, invp->size);
+}
+
+static int acpi_cc_done(struct cache_coherency_device *ccd)
+{
+	/* Todo */
+	return 0;
+}
+
+static const struct coherency_ops acpi_cc_ops = {
+	.wbinv = acpi_cc_wbinv,
+	.done = acpi_cc_done,
+};
+
+static int acpi_cache_control_add(struct acpi_device *device)
+{
+	struct acpi_cache_control *acpi_cc;
+	int ret;
+
+	ret = acpi_cache_control_query(device);
+	if (ret)
+		return ret;
+
+	acpi_cc = cache_coherency_device_alloc(&acpi_cc_ops,
+					       struct acpi_cache_control, ccd);
+	if (!acpi_cc)
+		return -ENOMEM;
+
+	acpi_cc->acpi_dev = device;
+
+	ret = cache_coherency_device_register(&acpi_cc->ccd);
+	if (ret) {
+		cache_coherency_device_free(&acpi_cc->ccd);
+		return ret;
+	}
+
+	dev_set_drvdata(&device->dev, acpi_cc);
+	return 0;
+}
+
+static void acpi_cache_control_del(struct acpi_device *device)
+{
+	struct acpi_cache_control *acpi_cc = dev_get_drvdata(&device->dev);
+
+	cache_coherency_device_unregister(&acpi_cc->ccd);
+	cache_coherency_device_free(&acpi_cc->ccd);
+}
+
+static const struct acpi_device_id acpi_cache_control_ids[] = {
+	{ "ACPI0019" },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(acpi, acpi_cache_control_ids);
+
+static struct acpi_driver acpi_cache_control_driver = {
+	.name = "acpi_cache_control",
+	.ids = acpi_cache_control_ids,
+	.ops = {
+		.add = acpi_cache_control_add,
+		.remove = acpi_cache_control_del,
+	},
+};
+
+module_acpi_driver(acpi_cache_control_driver);
+
+MODULE_IMPORT_NS("CACHE_COHERENCY");
+MODULE_AUTHOR("Jonathan Cameron <Jonathan.Cameron@huawei.com>");
+MODULE_DESCRIPTION("HACKS HACKS HACKS");
+MODULE_LICENSE("GPL");
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v3 8/8] Hack: Pretend we have PSCI 1.2
  2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
                   ` (6 preceding siblings ...)
  2025-08-20 10:29 ` [PATCH v3 7/8] acpi: PoC of Cache control via ACPI0019 and _DSM Jonathan Cameron
@ 2025-08-20 10:29 ` Jonathan Cameron
  7 siblings, 0 replies; 13+ messages in thread
From: Jonathan Cameron @ 2025-08-20 10:29 UTC (permalink / raw)
  To: Catalin Marinas, james.morse, linux-cxl, linux-arm-kernel,
	linux-acpi, linux-arch, linux-mm, Will Deacon, Dan Williams,
	Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

Need to update QEMU to PSCI 1.2. In meantime lie.
This is just here to aid testing, not for review!

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/firmware/psci/psci.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c
index 38ca190d4a22..804b0d7cda4b 100644
--- a/drivers/firmware/psci/psci.c
+++ b/drivers/firmware/psci/psci.c
@@ -646,6 +646,8 @@ static void __init psci_init_smccc(void)
 		}
 	}
 
+	/* Hack until qemu version stuff updated */
+	arm_smccc_version_init(ARM_SMCCC_VERSION_1_2, psci_conduit);
 	/*
 	 * Conveniently, the SMCCC and PSCI versions are encoded the
 	 * same way. No, this isn't accidental.
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 7/8] acpi: PoC of Cache control via ACPI0019 and _DSM
  2025-08-20 10:29 ` [PATCH v3 7/8] acpi: PoC of Cache control via ACPI0019 and _DSM Jonathan Cameron
@ 2025-08-20 17:07   ` Randy Dunlap
  0 siblings, 0 replies; 13+ messages in thread
From: Randy Dunlap @ 2025-08-20 17:07 UTC (permalink / raw)
  To: Jonathan Cameron, Catalin Marinas, james.morse, linux-cxl,
	linux-arm-kernel, linux-acpi, linux-arch, linux-mm, Will Deacon,
	Dan Williams, Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski

Hi,

On 8/20/25 3:29 AM, Jonathan Cameron wrote:
> diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig
> index 4551b28e14dd..158d3819004e 100644
> --- a/drivers/cache/Kconfig
> +++ b/drivers/cache/Kconfig
> @@ -3,6 +3,13 @@ menu "Cache Drivers"
>  
>  if GENERIC_CPU_CACHE_MAINTENANCE
>  
> +config ACPI_CACHE_CONTROL
> +       tristate "ACPI cache maintenance"
> +       depends on ARM64 && ACPI
> +       help

If there is a v4, please use one tab to indent the 3 lines above.

> +         ACPI0019 device ID in DSDT identifies an interface that may be used

and tab + 2 spaces to indent the 1 line above.

> +	 to carry out certain forms of cache flush operation.

-- 
~Randy


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
  2025-08-20 10:29 ` [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
@ 2025-08-20 17:44   ` Randy Dunlap
  2025-09-03 16:25   ` Catalin Marinas
  1 sibling, 0 replies; 13+ messages in thread
From: Randy Dunlap @ 2025-08-20 17:44 UTC (permalink / raw)
  To: Jonathan Cameron, Catalin Marinas, james.morse, linux-cxl,
	linux-arm-kernel, linux-acpi, linux-arch, linux-mm, Will Deacon,
	Dan Williams, Davidlohr Bueso, H . Peter Anvin, Peter Zijlstra
  Cc: Yicong Yang, linuxarm, Yushan Wang, Lorenzo Pieralisi,
	Mark Rutland, Dave Hansen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, Andy Lutomirski



On 8/20/25 3:29 AM, Jonathan Cameron wrote:
> +struct cache_coherency_device *
> +_cache_coherency_device_alloc(const struct coherency_ops *ops, size_t size);
> +/**
> + * cache_coherency_device_alloc - Allocate a cache coherency device
> + * @ops: Cache maintenance operations
> + * @drv_struct: structure that contains the struct cache_coherency_device
> + * @member: Name of the struct cache_coherency_device member in @drv_struct.
> + *
> + * This allocates and initializes the cache_coherency_device embedded in the
> + * drv_struct. Upon success the pointer must be freed via
> + * cache_coherency_device_free().
> + *
> + * Returns a 'drv_struct \*' on success, NULL on error.

Preferably:

 * Returns: a &drv_struct * on success, %NULL on error.


> + */
> +#define cache_coherency_device_alloc(ops, drv_struct, member)	    \
> +	({								    \
> +		static_assert(__same_type(struct cache_coherency_device,    \
> +					  ((drv_struct *)NULL)->member));   \
> +		static_assert(offsetof(drv_struct, member) == 0);	    \
> +		(drv_struct *)_cache_coherency_device_alloc(ops,	    \
> +			sizeof(drv_struct));				    \
> +	})
> +void cache_coherency_device_free(struct cache_coherency_device *ccd);
> +
> +#endif

-- 
~Randy


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
  2025-08-20 10:29 ` [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
  2025-08-20 17:44   ` Randy Dunlap
@ 2025-09-03 16:25   ` Catalin Marinas
  1 sibling, 0 replies; 13+ messages in thread
From: Catalin Marinas @ 2025-09-03 16:25 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: james.morse, linux-cxl, linux-arm-kernel, linux-acpi, linux-arch,
	linux-mm, Will Deacon, Dan Williams, Davidlohr Bueso,
	H . Peter Anvin, Peter Zijlstra, Yicong Yang, linuxarm,
	Yushan Wang, Lorenzo Pieralisi, Mark Rutland, Dave Hansen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	Andy Lutomirski

On Wed, Aug 20, 2025 at 11:29:45AM +0100, Jonathan Cameron wrote:
> diff --git a/lib/Kconfig b/lib/Kconfig
> index c483951b624f..cd8e5844f9bb 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -543,6 +543,9 @@ config MEMREGION
>  config ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
>  	bool
>  
> +config GENERIC_CPU_CACHE_MAINTENANCE
> +	bool

Nit: you could select ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION here since
the interface is now provided by the generic implementation.

-- 
Catalin

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 5/8] arm64: Select GENERIC_CPU_CACHE_MAINTENANCE and ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION
  2025-08-20 10:29 ` [PATCH v3 5/8] arm64: Select GENERIC_CPU_CACHE_MAINTENANCE and ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
@ 2025-09-03 16:25   ` Catalin Marinas
  0 siblings, 0 replies; 13+ messages in thread
From: Catalin Marinas @ 2025-09-03 16:25 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: james.morse, linux-cxl, linux-arm-kernel, linux-acpi, linux-arch,
	linux-mm, Will Deacon, Dan Williams, Davidlohr Bueso,
	H . Peter Anvin, Peter Zijlstra, Yicong Yang, linuxarm,
	Yushan Wang, Lorenzo Pieralisi, Mark Rutland, Dave Hansen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	Andy Lutomirski

On Wed, Aug 20, 2025 at 11:29:47AM +0100, Jonathan Cameron wrote:
> Ensure the hooks that the generic cache maintenance framework uses are
> available on ARM64 by selecting ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION.
> 
> The generic CPU cache maintenance framework provides a way to register
> drivers for devices implementing the underlying support for
> cpu_cache_has_invalidate_memregion().
> 
> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---
>  arch/arm64/Kconfig | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index e9bbfacc35a6..15bf429b3f59 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -21,6 +21,7 @@ config ARM64
>  	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
>  	select ARCH_HAS_CACHE_LINE_SIZE
>  	select ARCH_HAS_CC_PLATFORM
> +	select ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION

We could drop this if GENERIC_CPU_CACHE_MAINTENANCE selects it.

>  	select ARCH_HAS_CURRENT_STACK_POINTER
>  	select ARCH_HAS_DEBUG_VIRTUAL
>  	select ARCH_HAS_DEBUG_VM_PGTABLE
> @@ -146,6 +147,7 @@ config ARM64
>  	select GENERIC_ARCH_TOPOLOGY
>  	select GENERIC_CLOCKEVENTS_BROADCAST
>  	select GENERIC_CPU_AUTOPROBE
> +	select GENERIC_CPU_CACHE_MAINTENANCE

Either way:

Acked-by: Catalin Marinas <catalin.marinas@arm.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-09-03 16:25 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-20 10:29 [PATCH v3 0/8] Cache coherency management subsystem Jonathan Cameron
2025-08-20 10:29 ` [PATCH v3 1/8] memregion: Drop unused IORES_DESC_* parameter from cpu_cache_invalidate_memregion() Jonathan Cameron
2025-08-20 10:29 ` [PATCH v3 2/8] memregion: Support fine grained invalidate by cpu_cache_invalidate_memregion() Jonathan Cameron
2025-08-20 10:29 ` [PATCH v3 3/8] lib: Support ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
2025-08-20 17:44   ` Randy Dunlap
2025-09-03 16:25   ` Catalin Marinas
2025-08-20 10:29 ` [PATCH v3 4/8] MAINTAINERS: Add Jonathan Cameron to drivers/cache Jonathan Cameron
2025-08-20 10:29 ` [PATCH v3 5/8] arm64: Select GENERIC_CPU_CACHE_MAINTENANCE and ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION Jonathan Cameron
2025-09-03 16:25   ` Catalin Marinas
2025-08-20 10:29 ` [PATCH v3 6/8] cache: Support cache maintenance for HiSilicon SoC Hydra Home Agent Jonathan Cameron
2025-08-20 10:29 ` [PATCH v3 7/8] acpi: PoC of Cache control via ACPI0019 and _DSM Jonathan Cameron
2025-08-20 17:07   ` Randy Dunlap
2025-08-20 10:29 ` [PATCH v3 8/8] Hack: Pretend we have PSCI 1.2 Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).