From 4fe55239b3baaeb009654b40892f0b697cd85af4 Mon Sep 17 00:00:00 2001 From: Jianqun Xu Date: Mon, 6 Jun 2022 17:51:30 +0800 Subject: [PATCH] iommu/iova: add iova procfs for each dma iommu Tested on RK3588 EVB1: localhost# ls /proc/iova/ av1d-master fdb90000.jpegd fdbb0000.iep fdcb0000.rkisp fdab0000.npu fdba0000.jpege-core fdbd0000.rkvenc-core fdce0000.rkcif fdb50400.vdpu fdba4000.jpege-core fdbe0000.rkvenc-core fdd90000.vop fdb60000.rga fdba8000.jpege-core fdc38100.rkvdec-core rkcif-mipi-lvds fdb70000.rga fdbac000.jpege-core fdc48100.rkvdec-core localhost# cat /proc/iova/fdc38100.rkvdec-core/used 0: [0x00000000ffe00000..0x00000000ffeff000] 1024KiB (4094 - 4095)MiB 1: [0x00000000fff00000..0x00000000fffff000] 1024KiB (4095 - 4096)MiB used: 2 MiB Signed-off-by: Jianqun Xu Change-Id: I102e08243b5a0a4cd173e75e2e25f68f1f5b09b6 --- drivers/iommu/dma-iommu.c | 7 +++++ drivers/iommu/iova.c | 59 +++++++++++++++++++++++++++++++++++++++ include/linux/iova.h | 6 ++++ 3 files changed, 72 insertions(+) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 2591b973a31b..a8678429291f 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -1249,6 +1249,13 @@ void iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size) dev->dma_ops = &iommu_dma_ops; } + if (domain->type == IOMMU_DOMAIN_DMA) { + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; + + init_iova_domain_procfs(iovad, dev_name(dev)); + } + return; out_err: pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n", diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index fe647bb1db8f..7447a0f3f988 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include /* The anchor node sits above the top of the usable address space */ #define IOVA_ANCHOR ~0UL @@ -27,6 +29,63 @@ static void fq_destroy_all_entries(struct iova_domain *iovad); static void fq_flush_timeout(struct timer_list *t); static void iova_dump(struct iova_domain *iovad); +static int iova_used_show(struct seq_file *s, void *v) +{ + struct iova_domain *iovad = s->private; + struct iova *iova, *t; + unsigned long flags, cpu; + unsigned long used_pfn = 0; + int i = 0; + + for_each_online_cpu(cpu) + free_cpu_cached_iovas(cpu, iovad); + free_global_cached_iovas(iovad); + + spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); + rbtree_postorder_for_each_entry_safe(iova, t, &iovad->rbroot, node) { + dma_addr_t start = iova->pfn_lo << iova_shift(iovad); + dma_addr_t end = iova->pfn_hi << iova_shift(iovad); + unsigned long pfn = iova->pfn_hi + 1 - iova->pfn_lo; + + if ((iova->pfn_hi == IOVA_ANCHOR) || (iova->pfn_lo == IOVA_ANCHOR)) + continue; + + seq_printf(s, "%4d: [%pad..%pad] %6luKiB (%4lu - %4lu)MiB\n", + i++, &start, &end, + pfn << (PAGE_SHIFT - 10), + iova->pfn_lo >> (20 - PAGE_SHIFT), + (iova->pfn_hi + 1) >> (20 - PAGE_SHIFT)); + used_pfn += pfn; + } + spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); + seq_printf(s, "used: %lu MiB\n", used_pfn >> (20 - PAGE_SHIFT)); + + return 0; +} + +static struct proc_dir_entry *iova_dir; + +void init_iova_domain_procfs(struct iova_domain *iovad, const char *name) +{ + struct proc_dir_entry *root; + + root = proc_mkdir(name, iova_dir); + if (!root) + return; + + proc_create_single_data("used", 0, root, iova_used_show, iovad); +} +EXPORT_SYMBOL_GPL(init_iova_domain_procfs); + +static int __init iova_procfs_create(void) +{ + if (!iova_dir) + iova_dir = proc_mkdir("iova", NULL); + + return 0; +} +subsys_initcall(iova_procfs_create); + void init_iova_domain(struct iova_domain *iovad, unsigned long granule, unsigned long start_pfn) diff --git a/include/linux/iova.h b/include/linux/iova.h index 5b4e75fe626a..97dc7d74b651 100644 --- a/include/linux/iova.h +++ b/include/linux/iova.h @@ -156,6 +156,7 @@ struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to); void init_iova_domain(struct iova_domain *iovad, unsigned long granule, unsigned long start_pfn); +void init_iova_domain_procfs(struct iova_domain *iovad, const char *name); bool has_iova_flush_queue(struct iova_domain *iovad); int init_iova_flush_queue(struct iova_domain *iovad, iova_flush_cb flush_cb, iova_entry_dtor entry_dtor); @@ -238,6 +239,11 @@ static inline void init_iova_domain(struct iova_domain *iovad, { } +static inline void +init_iova_domain_procfs(struct iova_domain *iovad, const char *name) +{ +} + static inline bool has_iova_flush_queue(struct iova_domain *iovad) { return false;