Skip to content

Commit ccc2121

Browse files
misalehjoergroedel
authored andcommitted
iommu: Add calls for IOMMU_DEBUG_PAGEALLOC
Add calls for the new iommu debug config IOMMU_DEBUG_PAGEALLOC: - iommu_debug_init: Enable the debug mode if configured by the user. - iommu_debug_map: Track iommu pages mapped, using physical address. - iommu_debug_unmap_begin: Track start of iommu unmap operation, with IOVA and size. - iommu_debug_unmap_end: Track the end of unmap operation, passing the actual unmapped size versus the tracked one at unmap_begin. We have to do the unmap_begin/end as once pages are unmapped we lose the information of the physical address. This is racy, but the API is racy by construction as it uses refcounts and doesn't attempt to lock/synchronize with the IOMMU API as that will be costly, meaning that possibility of false negative exists. Reviewed-by: Samiullah Khawaja <skhawaja@google.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Pranjal Shrivastava <praan@google.com> Signed-off-by: Mostafa Saleh <smostafa@google.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent 466ae69 commit ccc2121

4 files changed

Lines changed: 96 additions & 2 deletions

File tree

drivers/iommu/iommu-debug-pagealloc.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
* IOMMU API debug page alloc sanitizer
66
*/
77
#include <linux/atomic.h>
8+
#include <linux/iommu.h>
89
#include <linux/iommu-debug-pagealloc.h>
910
#include <linux/kernel.h>
1011
#include <linux/page_ext.h>
1112

13+
#include "iommu-priv.h"
14+
1215
static bool needed;
16+
DEFINE_STATIC_KEY_FALSE(iommu_debug_initialized);
1317

1418
struct iommu_debug_metadata {
1519
atomic_t ref;
@@ -25,6 +29,30 @@ struct page_ext_operations page_iommu_debug_ops = {
2529
.need = need_iommu_debug,
2630
};
2731

32+
void __iommu_debug_map(struct iommu_domain *domain, phys_addr_t phys, size_t size)
33+
{
34+
}
35+
36+
void __iommu_debug_unmap_begin(struct iommu_domain *domain,
37+
unsigned long iova, size_t size)
38+
{
39+
}
40+
41+
void __iommu_debug_unmap_end(struct iommu_domain *domain,
42+
unsigned long iova, size_t size,
43+
size_t unmapped)
44+
{
45+
}
46+
47+
void iommu_debug_init(void)
48+
{
49+
if (!needed)
50+
return;
51+
52+
pr_info("iommu: Debugging page allocations, expect overhead or disable iommu.debug_pagealloc");
53+
static_branch_enable(&iommu_debug_initialized);
54+
}
55+
2856
static int __init iommu_debug_pagealloc(char *str)
2957
{
3058
return kstrtobool(str, &needed);

drivers/iommu/iommu-priv.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define __LINUX_IOMMU_PRIV_H
66

77
#include <linux/iommu.h>
8+
#include <linux/iommu-debug-pagealloc.h>
89
#include <linux/msi.h>
910

1011
static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)
@@ -65,4 +66,61 @@ static inline int iommufd_sw_msi(struct iommu_domain *domain,
6566
int iommu_replace_device_pasid(struct iommu_domain *domain,
6667
struct device *dev, ioasid_t pasid,
6768
struct iommu_attach_handle *handle);
69+
70+
#ifdef CONFIG_IOMMU_DEBUG_PAGEALLOC
71+
72+
void __iommu_debug_map(struct iommu_domain *domain, phys_addr_t phys,
73+
size_t size);
74+
void __iommu_debug_unmap_begin(struct iommu_domain *domain,
75+
unsigned long iova, size_t size);
76+
void __iommu_debug_unmap_end(struct iommu_domain *domain,
77+
unsigned long iova, size_t size, size_t unmapped);
78+
79+
static inline void iommu_debug_map(struct iommu_domain *domain,
80+
phys_addr_t phys, size_t size)
81+
{
82+
if (static_branch_unlikely(&iommu_debug_initialized))
83+
__iommu_debug_map(domain, phys, size);
84+
}
85+
86+
static inline void iommu_debug_unmap_begin(struct iommu_domain *domain,
87+
unsigned long iova, size_t size)
88+
{
89+
if (static_branch_unlikely(&iommu_debug_initialized))
90+
__iommu_debug_unmap_begin(domain, iova, size);
91+
}
92+
93+
static inline void iommu_debug_unmap_end(struct iommu_domain *domain,
94+
unsigned long iova, size_t size,
95+
size_t unmapped)
96+
{
97+
if (static_branch_unlikely(&iommu_debug_initialized))
98+
__iommu_debug_unmap_end(domain, iova, size, unmapped);
99+
}
100+
101+
void iommu_debug_init(void);
102+
103+
#else
104+
static inline void iommu_debug_map(struct iommu_domain *domain,
105+
phys_addr_t phys, size_t size)
106+
{
107+
}
108+
109+
static inline void iommu_debug_unmap_begin(struct iommu_domain *domain,
110+
unsigned long iova, size_t size)
111+
{
112+
}
113+
114+
static inline void iommu_debug_unmap_end(struct iommu_domain *domain,
115+
unsigned long iova, size_t size,
116+
size_t unmapped)
117+
{
118+
}
119+
120+
static inline void iommu_debug_init(void)
121+
{
122+
}
123+
124+
#endif /* CONFIG_IOMMU_DEBUG_PAGEALLOC */
125+
68126
#endif /* __LINUX_IOMMU_PRIV_H */

drivers/iommu/iommu.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,8 @@ static int __init iommu_subsys_init(void)
237237
if (!nb)
238238
return -ENOMEM;
239239

240+
iommu_debug_init();
241+
240242
for (int i = 0; i < ARRAY_SIZE(iommu_buses); i++) {
241243
nb[i].notifier_call = iommu_bus_notifier;
242244
bus_register_notifier(iommu_buses[i], &nb[i]);
@@ -2629,10 +2631,12 @@ int iommu_map_nosync(struct iommu_domain *domain, unsigned long iova,
26292631
}
26302632

26312633
/* unroll mapping in case something went wrong */
2632-
if (ret)
2634+
if (ret) {
26332635
iommu_unmap(domain, orig_iova, orig_size - size);
2634-
else
2636+
} else {
26352637
trace_map(orig_iova, orig_paddr, orig_size);
2638+
iommu_debug_map(domain, orig_paddr, orig_size);
2639+
}
26362640

26372641
return ret;
26382642
}
@@ -2694,6 +2698,8 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
26942698

26952699
pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size);
26962700

2701+
iommu_debug_unmap_begin(domain, iova, size);
2702+
26972703
/*
26982704
* Keep iterating until we either unmap 'size' bytes (or more)
26992705
* or we hit an area that isn't mapped.
@@ -2714,6 +2720,7 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
27142720
}
27152721

27162722
trace_unmap(orig_iova, size, unmapped);
2723+
iommu_debug_unmap_end(domain, orig_iova, size, unmapped);
27172724
return unmapped;
27182725
}
27192726

include/linux/iommu-debug-pagealloc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define __LINUX_IOMMU_DEBUG_PAGEALLOC_H
1010

1111
#ifdef CONFIG_IOMMU_DEBUG_PAGEALLOC
12+
DECLARE_STATIC_KEY_FALSE(iommu_debug_initialized);
1213

1314
extern struct page_ext_operations page_iommu_debug_ops;
1415

0 commit comments

Comments
 (0)