OSDN Git Service

iommu/io-pgtable: Add memory stats debugfs file
authorMitchel Humpherys <mitchelh@codeaurora.org>
Thu, 16 Jul 2015 01:25:07 +0000 (18:25 -0700)
committerDavid Keitel <dkeitel@codeaurora.org>
Tue, 22 Mar 2016 18:13:39 +0000 (11:13 -0700)
It can be useful for debugging to know how much memory is being used for
IOMMU page tables.  Add some dedicated allocation functions and a
debugfs file for this.

Change-Id: Id69b4b1b5df5dcc6c604eec3a12a894b8eab0eb6
Signed-off-by: Mitchel Humpherys <mitchelh@codeaurora.org>
drivers/iommu/io-pgtable-arm.c
drivers/iommu/io-pgtable.c
drivers/iommu/io-pgtable.h

index 4c74530..56c3171 100644 (file)
@@ -249,8 +249,8 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
        /* Grab a pointer to the next level */
        pte = *ptep;
        if (!pte) {
-               cptep = alloc_pages_exact(1UL << data->pg_shift,
-                                        GFP_ATOMIC | __GFP_ZERO);
+               cptep = io_pgtable_alloc_pages_exact(1UL << data->pg_shift,
+                                                    GFP_ATOMIC | __GFP_ZERO);
                if (!cptep)
                        return -ENOMEM;
 
@@ -414,7 +414,7 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
        }
 
        data->iop.cfg.tlb->unprepare_pgtable(data->iop.cookie, start);
-       free_pages_exact(start, table_size);
+       io_pgtable_free_pages_exact(start, table_size);
 }
 
 static void arm_lpae_free_pgtable(struct io_pgtable *iop)
@@ -733,7 +733,8 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
        cfg->arm_lpae_s1_cfg.mair[1] = 0;
 
        /* Looking good; allocate a pgd */
-       data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO);
+       data->pgd = io_pgtable_alloc_pages_exact(data->pgd_size,
+                                                GFP_KERNEL | __GFP_ZERO);
        if (!data->pgd)
                goto out_free_data;
 
@@ -821,7 +822,8 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
        cfg->arm_lpae_s2_cfg.vtcr = reg;
 
        /* Allocate pgd pages */
-       data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO);
+       data->pgd = io_pgtable_alloc_pages_exact(data->pgd_size,
+                                                GFP_KERNEL | __GFP_ZERO);
        if (!data->pgd)
                goto out_free_data;
 
index 6436fe2..881c8a0 100644 (file)
  * Author: Will Deacon <will.deacon@arm.com>
  */
 
+#define pr_fmt(fmt)    "io-pgtable: " fmt
+
 #include <linux/bug.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/iommu.h>
+#include <linux/debugfs.h>
+#include <linux/atomic.h>
 
 #include "io-pgtable.h"
 
@@ -40,6 +45,8 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] =
 #endif
 };
 
+static struct dentry *io_pgtable_top;
+
 struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
                                            struct io_pgtable_cfg *cfg,
                                            void *cookie)
@@ -80,3 +87,44 @@ void free_io_pgtable_ops(struct io_pgtable_ops *ops)
        iop->cfg.tlb->tlb_flush_all(iop->cookie);
        io_pgtable_init_table[iop->fmt]->free(iop);
 }
+
+static atomic_t pages_allocated;
+
+void *io_pgtable_alloc_pages_exact(size_t size, gfp_t gfp_mask)
+{
+       void *ret = alloc_pages_exact(size, gfp_mask);
+
+       if (likely(ret))
+               atomic_add(1 << get_order(size), &pages_allocated);
+       return ret;
+}
+
+void io_pgtable_free_pages_exact(void *virt, size_t size)
+{
+       free_pages_exact(virt, size);
+       atomic_sub(1 << get_order(size), &pages_allocated);
+}
+
+static int io_pgtable_init(void)
+{
+       io_pgtable_top = debugfs_create_dir("io-pgtable", iommu_debugfs_top);
+
+       if (!io_pgtable_top)
+               return -ENODEV;
+
+       if (!debugfs_create_atomic_t("pages", 0600,
+                                    io_pgtable_top, &pages_allocated)) {
+               debugfs_remove_recursive(io_pgtable_top);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void io_pgtable_exit(void)
+{
+       debugfs_remove_recursive(io_pgtable_top);
+}
+
+module_init(io_pgtable_init);
+module_exit(io_pgtable_exit);
index e612b21..2ca3393 100644 (file)
@@ -148,4 +148,24 @@ struct io_pgtable_init_fns {
        void (*free)(struct io_pgtable *iop);
 };
 
+/**
+ * io_pgtable_alloc_pages_exact - allocate an exact number physically-contiguous pages.
+ * @size: the number of bytes to allocate
+ * @gfp_mask: GFP flags for the allocation
+ *
+ * Like alloc_pages_exact(), but with some additional accounting for debug
+ * purposes.
+ */
+void *io_pgtable_alloc_pages_exact(size_t size, gfp_t gfp_mask);
+
+/**
+ * io_pgtable_free_pages_exact - release memory allocated via io_pgtable_alloc_pages_exact()
+ * @virt: the value returned by alloc_pages_exact.
+ * @size: size of allocation, same value as passed to alloc_pages_exact().
+ *
+ * Like free_pages_exact(), but with some additional accounting for debug
+ * purposes.
+ */
+void io_pgtable_free_pages_exact(void *virt, size_t size);
+
 #endif /* __IO_PGTABLE_H */