130 lines
4.2 KiB
Diff
130 lines
4.2 KiB
Diff
From 17b226dcf80ce79d02f4f0b08813d8848885b986 Mon Sep 17 00:00:00 2001
|
|
From: Boris Brezillon <boris.brezillon@collabora.com>
|
|
Date: Fri, 24 Nov 2023 15:24:33 +0100
|
|
Subject: [PATCH] iommu: Allow passing custom allocators to pgtable drivers
|
|
|
|
This will be useful for GPU drivers who want to keep page tables in a
|
|
pool so they can:
|
|
|
|
- keep freed page tables in a free pool and speed-up upcoming page
|
|
table allocations
|
|
- batch page table allocation instead of allocating one page at a time
|
|
- pre-reserve pages for page tables needed for map/unmap operations,
|
|
to ensure map/unmap operations don't try to allocate memory in paths
|
|
they're allowed to block or fail
|
|
|
|
It might also be valuable for other aspects of GPU and similar
|
|
use-cases, like fine-grained memory accounting and resource limiting.
|
|
|
|
We will extend the Arm LPAE format to support custom allocators in a
|
|
separate commit.
|
|
|
|
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
|
|
Reviewed-by: Steven Price <steven.price@arm.com>
|
|
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
|
|
Link: https://lore.kernel.org/r/20231124142434.1577550-2-boris.brezillon@collabora.com
|
|
Signed-off-by: Joerg Roedel <jroedel@suse.de>
|
|
---
|
|
drivers/iommu/io-pgtable.c | 23 +++++++++++++++++++++++
|
|
include/linux/io-pgtable.h | 34 ++++++++++++++++++++++++++++++++++
|
|
2 files changed, 57 insertions(+)
|
|
|
|
--- a/drivers/iommu/io-pgtable.c
|
|
+++ b/drivers/iommu/io-pgtable.c
|
|
@@ -34,6 +34,26 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMT
|
|
#endif
|
|
};
|
|
|
|
+static int check_custom_allocator(enum io_pgtable_fmt fmt,
|
|
+ struct io_pgtable_cfg *cfg)
|
|
+{
|
|
+ /* No custom allocator, no need to check the format. */
|
|
+ if (!cfg->alloc && !cfg->free)
|
|
+ return 0;
|
|
+
|
|
+ /* When passing a custom allocator, both the alloc and free
|
|
+ * functions should be provided.
|
|
+ */
|
|
+ if (!cfg->alloc || !cfg->free)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Make sure the format supports custom allocators. */
|
|
+ if (io_pgtable_init_table[fmt]->caps & IO_PGTABLE_CAP_CUSTOM_ALLOCATOR)
|
|
+ return 0;
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
|
|
struct io_pgtable_cfg *cfg,
|
|
void *cookie)
|
|
@@ -44,6 +64,9 @@ struct io_pgtable_ops *alloc_io_pgtable_
|
|
if (fmt >= IO_PGTABLE_NUM_FMTS)
|
|
return NULL;
|
|
|
|
+ if (check_custom_allocator(fmt, cfg))
|
|
+ return NULL;
|
|
+
|
|
fns = io_pgtable_init_table[fmt];
|
|
if (!fns)
|
|
return NULL;
|
|
--- a/include/linux/io-pgtable.h
|
|
+++ b/include/linux/io-pgtable.h
|
|
@@ -100,6 +100,30 @@ struct io_pgtable_cfg {
|
|
const struct iommu_flush_ops *tlb;
|
|
struct device *iommu_dev;
|
|
|
|
+ /**
|
|
+ * @alloc: Custom page allocator.
|
|
+ *
|
|
+ * Optional hook used to allocate page tables. If this function is NULL,
|
|
+ * @free must be NULL too.
|
|
+ *
|
|
+ * Memory returned should be zeroed and suitable for dma_map_single() and
|
|
+ * virt_to_phys().
|
|
+ *
|
|
+ * Not all formats support custom page allocators. Before considering
|
|
+ * passing a non-NULL value, make sure the chosen page format supports
|
|
+ * this feature.
|
|
+ */
|
|
+ void *(*alloc)(void *cookie, size_t size, gfp_t gfp);
|
|
+
|
|
+ /**
|
|
+ * @free: Custom page de-allocator.
|
|
+ *
|
|
+ * Optional hook used to free page tables allocated with the @alloc
|
|
+ * hook. Must be non-NULL if @alloc is not NULL, must be NULL
|
|
+ * otherwise.
|
|
+ */
|
|
+ void (*free)(void *cookie, void *pages, size_t size);
|
|
+
|
|
/* Low-level data specific to the table format */
|
|
union {
|
|
struct {
|
|
@@ -238,15 +262,25 @@ io_pgtable_tlb_add_page(struct io_pgtabl
|
|
}
|
|
|
|
/**
|
|
+ * enum io_pgtable_caps - IO page table backend capabilities.
|
|
+ */
|
|
+enum io_pgtable_caps {
|
|
+ /** @IO_PGTABLE_CAP_CUSTOM_ALLOCATOR: Backend accepts custom page table allocators. */
|
|
+ IO_PGTABLE_CAP_CUSTOM_ALLOCATOR = BIT(0),
|
|
+};
|
|
+
|
|
+/**
|
|
* struct io_pgtable_init_fns - Alloc/free a set of page tables for a
|
|
* particular format.
|
|
*
|
|
* @alloc: Allocate a set of page tables described by cfg.
|
|
* @free: Free the page tables associated with iop.
|
|
+ * @caps: Combination of @io_pgtable_caps flags encoding the backend capabilities.
|
|
*/
|
|
struct io_pgtable_init_fns {
|
|
struct io_pgtable *(*alloc)(struct io_pgtable_cfg *cfg, void *cookie);
|
|
void (*free)(struct io_pgtable *iop);
|
|
+ u32 caps;
|
|
};
|
|
|
|
extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s1_init_fns;
|