Skip to content

Commit 5fb38a6

Browse files
Tvrtko Ursulinpelwell
Tvrtko Ursulin
authored andcommitted
iommu/dma: Add ability to configure NUMA allocation policy for remapped allocations
Add iommu_dma_numa_policy= kernel parameter which can be used to modify the NUMA allocation policy of remapped buffer allocations. Policy is only used for devices which are not associated with a NUMA node. Syntax identical to what tmpfs accepts as it's mpol argument is accepted. Some examples: iommu_dma_numa_policy=interleave iommu_dma_numa_policy=interleave=skip-interleave iommu_dma_numa_policy=bind:0-3,5,7,9-15 iommu_dma_numa_policy=bind=static:1-2 Signed-off-by: Tvrtko Ursulin <[email protected]>
1 parent 845ebf6 commit 5fb38a6

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

drivers/iommu/dma-iommu.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/iova.h>
2222
#include <linux/irq.h>
2323
#include <linux/list_sort.h>
24+
#include <linux/mempolicy.h>
2425
#include <linux/memremap.h>
2526
#include <linux/mm.h>
2627
#include <linux/mutex.h>
@@ -883,11 +884,65 @@ static void __iommu_dma_free_pages(struct page **pages, int count)
883884
kvfree(pages);
884885
}
885886

887+
#if IS_ENABLED(CONFIG_NUMA)
888+
static struct mempolicy iommu_dma_mpol = {
889+
.refcnt = ATOMIC_INIT(1), /* never free it */
890+
.mode = MPOL_LOCAL,
891+
};
892+
893+
static struct mempolicy *dma_iommu_numa_policy(void)
894+
{
895+
return &iommu_dma_mpol;
896+
}
897+
898+
static unsigned short dma_iommu_numa_mode(void)
899+
{
900+
return iommu_dma_mpol.mode;
901+
}
902+
903+
static int __init setup_numapolicy(char *str)
904+
{
905+
struct mempolicy pol = { }, *ppol = &pol;
906+
char buf[128];
907+
int ret;
908+
909+
if (str)
910+
ret = mpol_parse_str(str, &ppol);
911+
else
912+
ret = -EINVAL;
913+
914+
if (!ret) {
915+
iommu_dma_mpol = pol;
916+
mpol_to_str(buf, sizeof(buf), &pol);
917+
pr_info("DMA IOMMU NUMA default policy overridden to '%s'\n", buf);
918+
} else {
919+
pr_warn("Unable to parse dma_iommu_numa_policy=\n");
920+
}
921+
922+
return ret == 0;
923+
}
924+
__setup("iommu_dma_numa_policy=", setup_numapolicy);
925+
#else
926+
static struct mempolicy *dma_iommu_numa_policy(void)
927+
{
928+
return NULL;
929+
}
930+
931+
static unsigned short dma_iommu_numa_mode(void)
932+
{
933+
return MPOL_LOCAL;
934+
}
935+
#endif
886936
static struct page **__iommu_dma_alloc_pages(struct device *dev,
887937
unsigned int count, unsigned long order_mask, gfp_t gfp)
888938
{
889939
struct page **pages;
890940
unsigned int i = 0, nid = dev_to_node(dev);
941+
const bool use_numa = nid == NUMA_NO_NODE &&
942+
dma_iommu_numa_mode() != MPOL_LOCAL;
943+
944+
if (use_numa)
945+
order_mask = 1;
891946

892947
order_mask &= GENMASK(MAX_PAGE_ORDER, 0);
893948
if (!order_mask)
@@ -903,6 +958,7 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev,
903958
while (count) {
904959
struct page *page = NULL;
905960
unsigned int order_size;
961+
nodemask_t *nodemask;
906962

907963
/*
908964
* Higher-order allocations are a convenience rather
@@ -917,6 +973,10 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev,
917973
order_size = 1U << order;
918974
if (order_mask > order_size)
919975
alloc_flags |= __GFP_NORETRY;
976+
if (use_numa)
977+
nodemask = numa_policy_nodemask(gfp,
978+
dma_iommu_numa_policy(),
979+
i, &nid);
920980
page = alloc_pages_node(nid, alloc_flags, order);
921981
if (!page)
922982
continue;

include/linux/mempolicy.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ bool vma_policy_mof(struct vm_area_struct *vma);
135135

136136
extern void numa_default_policy(void);
137137
extern void numa_policy_init(void);
138+
nodemask_t *numa_policy_nodemask(gfp_t gfp, struct mempolicy *pol, pgoff_t ilx,
139+
int *nid);
138140
extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new);
139141
extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
140142

@@ -238,6 +240,14 @@ static inline void numa_policy_init(void)
238240
{
239241
}
240242

243+
static inline nodemask_t *
244+
numa_policy_nodemask(gfp_t gfp, struct mempolicy *pol, pgoff_t ilx, int *nid)
245+
{
246+
*nid = NUMA_NO_NODE;
247+
248+
return NULL;
249+
}
250+
241251
static inline void numa_default_policy(void)
242252
{
243253
}

mm/mempolicy.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,12 @@ static nodemask_t *policy_nodemask(gfp_t gfp, struct mempolicy *pol,
20902090
return nodemask;
20912091
}
20922092

2093+
nodemask_t *numa_policy_nodemask(gfp_t gfp, struct mempolicy *pol, pgoff_t ilx,
2094+
int *nid)
2095+
{
2096+
return policy_nodemask(gfp, pol, ilx, nid);
2097+
}
2098+
20932099
#ifdef CONFIG_HUGETLBFS
20942100
/*
20952101
* huge_node(@vma, @addr, @gfp_flags, @mpol)

0 commit comments

Comments
 (0)