diff mbox series

[RFC,v3,19/35] arm64: mte: Discover tag storage memory

Message ID 20240125164256.4147-20-alexandru.elisei@arm.com (mailing list archive)
State New, archived
Headers show
Series Add support for arm64 MTE dynamic tag storage reuse | expand

Commit Message

Alexandru Elisei Jan. 25, 2024, 4:42 p.m. UTC
Allow the kernel to get the base address, size, block size and associated
memory node for tag storage from the device tree blob.

A tag storage region represents the smallest contiguous memory region that
holds all the tags for the associated contiguous memory region which can be
tagged. For example, for a 32GB contiguous tagged memory the corresponding
tag storage region is exactly 1GB of contiguous memory, not two adjacent
512M of tag storage memory, nor one 2GB tag storage region.

Tag storage is described as reserved memory; future patches will teach the
kernel how to make use of it for data (non-tagged) allocations.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
---

Changes since rfc v2:

* Reworked from rfc v2 patch #11 ("arm64: mte: Reserve tag storage memory").
* Added device tree schema (Rob Herring)
* Tag storage memory is now described in the "reserved-memory" node (Rob
Herring).

 .../reserved-memory/arm,mte-tag-storage.yaml  |  78 +++++++++
 arch/arm64/Kconfig                            |  12 ++
 arch/arm64/include/asm/mte_tag_storage.h      |  16 ++
 arch/arm64/kernel/Makefile                    |   1 +
 arch/arm64/kernel/mte_tag_storage.c           | 158 ++++++++++++++++++
 arch/arm64/mm/init.c                          |   3 +
 6 files changed, 268 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/reserved-memory/arm,mte-tag-storage.yaml
 create mode 100644 arch/arm64/include/asm/mte_tag_storage.h
 create mode 100644 arch/arm64/kernel/mte_tag_storage.c

Comments

Krzysztof Kozlowski Jan. 26, 2024, 8:50 a.m. UTC | #1
On 25/01/2024 17:42, Alexandru Elisei wrote:
> Allow the kernel to get the base address, size, block size and associated
> memory node for tag storage from the device tree blob.
> 

Please use scripts/get_maintainers.pl to get a list of necessary people
and lists to CC. It might happen, that command when run on an older
kernel, gives you outdated entries. Therefore please be sure you base
your patches on recent Linux kernel.

Tools like b4 or scripts_getmaintainer.pl provide you proper list of
people, so fix your workflow. Tools might also fail if you work on some
ancient tree (don't, use mainline), work on fork of kernel (don't, use
mainline) or you ignore some maintainers (really don't). Just use b4 and
all the problems go away.

You missed at least devicetree list (maybe more), so this won't be
tested by automated tooling. Performing review on untested code might be
a waste of time, thus I will skip this patch entirely till you follow
the process allowing the patch to be tested.

Please kindly resend and include all necessary To/Cc entries.


> A tag storage region represents the smallest contiguous memory region that
> holds all the tags for the associated contiguous memory region which can be
> tagged. For example, for a 32GB contiguous tagged memory the corresponding
> tag storage region is exactly 1GB of contiguous memory, not two adjacent
> 512M of tag storage memory, nor one 2GB tag storage region.
> 
> Tag storage is described as reserved memory; future patches will teach the
> kernel how to make use of it for data (non-tagged) allocations.
> 
> Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
> ---
> 
> Changes since rfc v2:
> 
> * Reworked from rfc v2 patch #11 ("arm64: mte: Reserve tag storage memory").
> * Added device tree schema (Rob Herring)
> * Tag storage memory is now described in the "reserved-memory" node (Rob
> Herring).
> 
>  .../reserved-memory/arm,mte-tag-storage.yaml  |  78 +++++++++

Please run scripts/checkpatch.pl and fix reported warnings. Some
warnings can be ignored, but the code here looks like it needs a fix.
Feel free to get in touch if the warning is not clear.


Best regards,
Krzysztof
Alexandru Elisei Jan. 26, 2024, 5:01 p.m. UTC | #2
Hi Krzysztof,

On Fri, Jan 26, 2024 at 09:50:58AM +0100, Krzysztof Kozlowski wrote:
> On 25/01/2024 17:42, Alexandru Elisei wrote:
> > Allow the kernel to get the base address, size, block size and associated
> > memory node for tag storage from the device tree blob.
> > 
> 
> Please use scripts/get_maintainers.pl to get a list of necessary people
> and lists to CC. It might happen, that command when run on an older
> kernel, gives you outdated entries. Therefore please be sure you base
> your patches on recent Linux kernel.
> 
> Tools like b4 or scripts_getmaintainer.pl provide you proper list of
> people, so fix your workflow. Tools might also fail if you work on some
> ancient tree (don't, use mainline), work on fork of kernel (don't, use
> mainline) or you ignore some maintainers (really don't). Just use b4 and
> all the problems go away.
> 
> You missed at least devicetree list (maybe more), so this won't be
> tested by automated tooling. Performing review on untested code might be
> a waste of time, thus I will skip this patch entirely till you follow
> the process allowing the patch to be tested.
> 
> Please kindly resend and include all necessary To/Cc entries.

My mistake, the previous iteration of the series didn't include a
devicetree binding and I forgot to update the To/Cc list. Thank you for the
heads-up, hopefully you can have a look after I resend the series.

> 
> 
> > A tag storage region represents the smallest contiguous memory region that
> > holds all the tags for the associated contiguous memory region which can be
> > tagged. For example, for a 32GB contiguous tagged memory the corresponding
> > tag storage region is exactly 1GB of contiguous memory, not two adjacent
> > 512M of tag storage memory, nor one 2GB tag storage region.
> > 
> > Tag storage is described as reserved memory; future patches will teach the
> > kernel how to make use of it for data (non-tagged) allocations.
> > 
> > Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
> > ---
> > 
> > Changes since rfc v2:
> > 
> > * Reworked from rfc v2 patch #11 ("arm64: mte: Reserve tag storage memory").
> > * Added device tree schema (Rob Herring)
> > * Tag storage memory is now described in the "reserved-memory" node (Rob
> > Herring).
> > 
> >  .../reserved-memory/arm,mte-tag-storage.yaml  |  78 +++++++++
> 
> Please run scripts/checkpatch.pl and fix reported warnings. Some
> warnings can be ignored, but the code here looks like it needs a fix.
> Feel free to get in touch if the warning is not clear.

Thank you for pointing it out, I'll move the binding to a separate patch.

Alex
diff mbox series

Patch

diff --git a/Documentation/devicetree/bindings/reserved-memory/arm,mte-tag-storage.yaml b/Documentation/devicetree/bindings/reserved-memory/arm,mte-tag-storage.yaml
new file mode 100644
index 000000000000..a99aaa1e8b6e
--- /dev/null
+++ b/Documentation/devicetree/bindings/reserved-memory/arm,mte-tag-storage.yaml
@@ -0,0 +1,78 @@ 
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/reserved-memory/arm,mte-tag-storage.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Tag storage memory for Memory Tagging Extension
+
+description: |
+  Description of the tag storage memory region that Linux can use to store
+  data when the associated memory is not tagged.
+
+  The reserved memory described by the node must also be described by a
+  standalone 'memory' node.
+
+maintainers:
+  - Alexandru Elisei <alexandru.elisei@arm.com>
+
+allOf:
+  - $ref: reserved-memory.yaml
+
+properties:
+  compatible:
+    const: arm,mte-tag-storage
+
+  reg:
+    description: |
+      Specifies the memory region that MTE uses for tag storage. The size of the
+      region must be equal to the size needed to store all the tags for the
+      associated tagged memory.
+
+  block-size:
+    description: |
+      Specifies the minimum multiple of 4K bytes of tag storage where all the
+      tags stored in the block correspond to a contiguous memory region. This
+      is needed for platforms where the memory controller interleaves tag
+      writes to memory.
+
+      For example, if the memory controller interleaves tag writes for 256KB
+      of contiguous memory across 8K of tag storage (2-way interleave), then
+      the correct value for 'block-size' is 0x2000.
+
+      This value is a hardware property, independent of the selected kernel page
+      size.
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  tagged-memory:
+    description: |
+      Specifies the memory node, as a phandle, for which all the tags are
+      stored in the tag storage region.
+
+      The memory node must describe one contiguous memory region (i.e, the
+      'ranges' property of the memory node must have exactly one entry).
+    $ref: /schemas/types.yaml#/definitions/phandle
+
+unevaluatedProperties: false
+
+required:
+  - compatible
+  - reg
+  - block-size
+  - tagged-memory
+  - reusable
+
+examples:
+  - |
+    reserved-memory {
+      #address-cells = <2>;
+      #size-cells = <2>;
+
+      tags0: tag-storage@8f8000000 {
+        compatible = "arm,mte-tag-storage";
+        reg = <0x08 0xf8000000 0x00 0x4000000>;
+        block-size = <0x1000>;
+        tagged-memory = <&memory0>;
+        reusable;
+      };
+    };
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index aa7c1d435139..92d97930b56e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2082,6 +2082,18 @@  config ARM64_MTE
 
 	  Documentation/arch/arm64/memory-tagging-extension.rst.
 
+if ARM64_MTE
+config ARM64_MTE_TAG_STORAGE
+	bool
+	help
+	  Adds support for dynamic management of the memory used by the hardware
+	  for storing MTE tags. This memory, unlike normal memory, cannot be
+	  tagged. When it is used to store tags for another memory location it
+	  cannot be used for any type of allocation.
+
+	  If unsure, say N
+endif # ARM64_MTE
+
 endmenu # "ARMv8.5 architectural features"
 
 menu "ARMv8.7 architectural features"
diff --git a/arch/arm64/include/asm/mte_tag_storage.h b/arch/arm64/include/asm/mte_tag_storage.h
new file mode 100644
index 000000000000..3c2cd29e053e
--- /dev/null
+++ b/arch/arm64/include/asm/mte_tag_storage.h
@@ -0,0 +1,16 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 ARM Ltd.
+ */
+#ifndef __ASM_MTE_TAG_STORAGE_H
+#define __ASM_MTE_TAG_STORAGE_H
+
+#ifdef CONFIG_ARM64_MTE_TAG_STORAGE
+void mte_init_tag_storage(void);
+#else
+static inline void mte_init_tag_storage(void)
+{
+}
+#endif /* CONFIG_ARM64_MTE_TAG_STORAGE */
+
+#endif /* __ASM_MTE_TAG_STORAGE_H  */
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index e5d03a7039b4..89c28b538908 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -70,6 +70,7 @@  obj-$(CONFIG_CRASH_CORE)		+= crash_core.o
 obj-$(CONFIG_ARM_SDE_INTERFACE)		+= sdei.o
 obj-$(CONFIG_ARM64_PTR_AUTH)		+= pointer_auth.o
 obj-$(CONFIG_ARM64_MTE)			+= mte.o
+obj-$(CONFIG_ARM64_MTE_TAG_STORAGE)	+= mte_tag_storage.o
 obj-y					+= vdso-wrap.o
 obj-$(CONFIG_COMPAT_VDSO)		+= vdso32-wrap.o
 obj-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS)	+= patch-scs.o
diff --git a/arch/arm64/kernel/mte_tag_storage.c b/arch/arm64/kernel/mte_tag_storage.c
new file mode 100644
index 000000000000..2f32265d8ad8
--- /dev/null
+++ b/arch/arm64/kernel/mte_tag_storage.c
@@ -0,0 +1,158 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Support for dynamic tag storage.
+ *
+ * Copyright (C) 2023 ARM Ltd.
+ */
+
+#include <linux/memblock.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/range.h>
+#include <linux/string.h>
+#include <linux/xarray.h>
+
+#include <asm/mte_tag_storage.h>
+
+struct tag_region {
+	struct range mem_range;	/* Memory associated with the tag storage, in PFNs. */
+	struct range tag_range;	/* Tag storage memory, in PFNs. */
+	u32 block_size_pages;	/* Tag block size, in pages. */
+	phandle mem_phandle;	/* phandle for the associated memory node. */
+};
+
+#define MAX_TAG_REGIONS	32
+
+static struct tag_region tag_regions[MAX_TAG_REGIONS];
+static int num_tag_regions;
+
+static u32 __init get_block_size_pages(u32 block_size_bytes)
+{
+	u32 a = PAGE_SIZE;
+	u32 b = block_size_bytes;
+	u32 r;
+
+	/* Find greatest common divisor using the Euclidian algorithm. */
+	do {
+		r = a % b;
+		a = b;
+		b = r;
+	} while (b != 0);
+
+	return PHYS_PFN(PAGE_SIZE * block_size_bytes / a);
+}
+
+int __init tag_storage_probe(struct reserved_mem *rmem)
+{
+	struct tag_region *region;
+	u32 block_size_bytes;
+	int ret;
+
+	if (num_tag_regions == MAX_TAG_REGIONS) {
+		pr_err("Exceeded maximum number of tag storage regions");
+		goto out_err;
+	}
+
+	region = &tag_regions[num_tag_regions];
+	region->tag_range.start = PHYS_PFN(rmem->base);
+	region->tag_range.end = PHYS_PFN(rmem->base + rmem->size - 1);
+
+	ret = of_flat_read_u32(rmem->fdt_node, "block-size", &block_size_bytes);
+	if (ret || block_size_bytes == 0) {
+		pr_err("Invalid or missing 'block-size' property");
+		goto out_err;
+	}
+
+	region->block_size_pages = get_block_size_pages(block_size_bytes);
+	if (range_len(&region->tag_range) % region->block_size_pages != 0) {
+		pr_err("Tag storage region size 0x%llx pages is not a multiple of block size 0x%x pages",
+		       range_len(&region->tag_range), region->block_size_pages);
+		goto out_err;
+	}
+
+	ret = of_flat_read_u32(rmem->fdt_node, "tagged-memory", &region->mem_phandle);
+	if (ret) {
+		pr_err("Invalid or missing 'tagged-memory' property");
+		goto out_err;
+	}
+
+	num_tag_regions++;
+	return 0;
+
+out_err:
+	num_tag_regions = 0;
+	return -EINVAL;
+}
+RESERVEDMEM_OF_DECLARE(tag_storage, "arm,mte-tag-storage", tag_storage_probe);
+
+static int __init mte_find_tagged_memory_regions(void)
+{
+	struct device_node *mem_dev;
+	struct tag_region *region;
+	struct range *mem_range;
+	const __be32 *reg;
+	u64 addr, size;
+	int i;
+
+	for (i = 0; i < num_tag_regions; i++) {
+		region = &tag_regions[i];
+		mem_range = &region->mem_range;
+
+		mem_dev = of_find_node_by_phandle(region->mem_phandle);
+		if (!mem_dev) {
+			pr_err("Cannot find tagged memory node");
+			goto out;
+		}
+
+		reg = of_get_property(mem_dev, "reg", NULL);
+		if (!reg) {
+			pr_err("Invalid tagged memory node");
+			goto out_put_mem;
+		}
+
+		addr = of_translate_address(mem_dev, reg);
+		if (addr == OF_BAD_ADDR) {
+			pr_err("Invalid memory address");
+			goto out_put_mem;
+		}
+
+		size = of_read_number(reg + of_n_addr_cells(mem_dev), of_n_size_cells(mem_dev));
+		if (!size) {
+			pr_err("Invalid memory size");
+			goto out_put_mem;
+		}
+
+		mem_range->start = PHYS_PFN(addr);
+		mem_range->end = PHYS_PFN(addr + size - 1);
+
+		of_node_put(mem_dev);
+	}
+
+	return 0;
+
+out_put_mem:
+	of_node_put(mem_dev);
+out:
+	return -EINVAL;
+}
+
+void __init mte_init_tag_storage(void)
+{
+	int ret;
+
+	if (num_tag_regions == 0)
+		return;
+
+	ret = mte_find_tagged_memory_regions();
+	if (ret)
+		goto out_disabled;
+
+	return;
+
+out_disabled:
+	num_tag_regions = 0;
+	pr_info("MTE tag storage region management disabled");
+}
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 74c1db8ce271..2ccc0c294a13 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -39,6 +39,7 @@ 
 #include <asm/kernel-pgtable.h>
 #include <asm/kvm_host.h>
 #include <asm/memory.h>
+#include <asm/mte_tag_storage.h>
 #include <asm/numa.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
@@ -386,6 +387,8 @@  void __init mem_init(void)
 	/* this will put all unused low memory onto the freelists */
 	memblock_free_all();
 
+	mte_init_tag_storage();
+
 	/*
 	 * Check boundaries twice: Some fundamental inconsistencies can be
 	 * detected at build time already.