They only address a contextual conflict, and pose a risk on their own.
Signed-off-by: Sasha Levin <sashal@kernel.org>
-From 7656e2f87a4d5b925445c4ede4ceae460151c4bc Mon Sep 17 00:00:00 2001
+From 00b383444885ec44bc405dc9c8723a9cf54b09a9 Mon Sep 17 00:00:00 2001
From: Sasha Levin <sashal@kernel.org>
Date: Thu, 10 Feb 2022 09:47:45 -0600
Subject: iommu/amd: Fix I/O page table memory leak
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
-index b1bf4125b0f7..6608d1717574 100644
+index 182c93a43efd..1eddf557636d 100644
--- a/drivers/iommu/amd/io_pgtable.c
+++ b/drivers/iommu/amd/io_pgtable.c
-@@ -492,18 +492,18 @@ static void v1_free_pgtable(struct io_pgtable *iop)
+@@ -519,12 +519,6 @@ static void v1_free_pgtable(struct io_pgtable *iop)
dom = container_of(pgtable, struct protection_domain, iop);
/* Page-table is not visible to IOMMU anymore, so free it */
BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
pgtable->mode > PAGE_MODE_6_LEVEL);
-
- free_sub_pt(pgtable->root, pgtable->mode, &freelist);
+@@ -532,6 +526,12 @@ static void v1_free_pgtable(struct io_pgtable *iop)
+ root = (unsigned long)pgtable->root;
+ freelist = free_sub_pt(root, pgtable->mode, freelist);
+ /* Update data structure */
+ amd_iommu_domain_clr_pt_root(dom);
+ /* Make changes visible to IOMMUs */
+ amd_iommu_domain_update(dom);
+
- put_pages_list(&freelist);
+ free_page_list(freelist);
}
--
+++ /dev/null
-From 3ccd31a933e9a08a64a803d7fda5cb64a48e5229 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 17 Dec 2021 15:30:58 +0000
-Subject: iommu/amd: Simplify pagetable freeing
-
-From: Robin Murphy <robin.murphy@arm.com>
-
-[ Upstream commit 6b3106e9ba2de7320a71291cedcefdcf1195ad58 ]
-
-For reasons unclear, pagetable freeing is an effectively recursive
-method implemented via an elaborate system of templated functions that
-turns out to account for 25% of the object file size. Implementing it
-using regular straightforward recursion makes the code simpler, and
-seems like a good thing to do before we work on it further. As part of
-that, also fix the types to avoid all the needless casting back and
-forth which just gets in the way.
-
-Signed-off-by: Robin Murphy <robin.murphy@arm.com>
-Link: https://lore.kernel.org/r/d3d00c9f3fa0df4756b867072c201e6e82f9ce39.1639753638.git.robin.murphy@arm.com
-Signed-off-by: Joerg Roedel <jroedel@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/iommu/amd/io_pgtable.c | 82 ++++++++++++++--------------------
- 1 file changed, 34 insertions(+), 48 deletions(-)
-
-diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
-index 182c93a43efd..4165e1372b6e 100644
---- a/drivers/iommu/amd/io_pgtable.c
-+++ b/drivers/iommu/amd/io_pgtable.c
-@@ -84,49 +84,45 @@ static void free_page_list(struct page *freelist)
- }
- }
-
--static struct page *free_pt_page(unsigned long pt, struct page *freelist)
-+static struct page *free_pt_page(u64 *pt, struct page *freelist)
- {
-- struct page *p = virt_to_page((void *)pt);
-+ struct page *p = virt_to_page(pt);
-
- p->freelist = freelist;
-
- return p;
- }
-
--#define DEFINE_FREE_PT_FN(LVL, FN) \
--static struct page *free_pt_##LVL (unsigned long __pt, struct page *freelist) \
--{ \
-- unsigned long p; \
-- u64 *pt; \
-- int i; \
-- \
-- pt = (u64 *)__pt; \
-- \
-- for (i = 0; i < 512; ++i) { \
-- /* PTE present? */ \
-- if (!IOMMU_PTE_PRESENT(pt[i])) \
-- continue; \
-- \
-- /* Large PTE? */ \
-- if (PM_PTE_LEVEL(pt[i]) == 0 || \
-- PM_PTE_LEVEL(pt[i]) == 7) \
-- continue; \
-- \
-- p = (unsigned long)IOMMU_PTE_PAGE(pt[i]); \
-- freelist = FN(p, freelist); \
-- } \
-- \
-- return free_pt_page((unsigned long)pt, freelist); \
--}
-+static struct page *free_pt_lvl(u64 *pt, struct page *freelist, int lvl)
-+{
-+ u64 *p;
-+ int i;
-+
-+ for (i = 0; i < 512; ++i) {
-+ /* PTE present? */
-+ if (!IOMMU_PTE_PRESENT(pt[i]))
-+ continue;
-
--DEFINE_FREE_PT_FN(l2, free_pt_page)
--DEFINE_FREE_PT_FN(l3, free_pt_l2)
--DEFINE_FREE_PT_FN(l4, free_pt_l3)
--DEFINE_FREE_PT_FN(l5, free_pt_l4)
--DEFINE_FREE_PT_FN(l6, free_pt_l5)
-+ /* Large PTE? */
-+ if (PM_PTE_LEVEL(pt[i]) == 0 ||
-+ PM_PTE_LEVEL(pt[i]) == 7)
-+ continue;
-
--static struct page *free_sub_pt(unsigned long root, int mode,
-- struct page *freelist)
-+ /*
-+ * Free the next level. No need to look at l1 tables here since
-+ * they can only contain leaf PTEs; just free them directly.
-+ */
-+ p = IOMMU_PTE_PAGE(pt[i]);
-+ if (lvl > 2)
-+ freelist = free_pt_lvl(p, freelist, lvl - 1);
-+ else
-+ freelist = free_pt_page(p, freelist);
-+ }
-+
-+ return free_pt_page(pt, freelist);
-+}
-+
-+static struct page *free_sub_pt(u64 *root, int mode, struct page *freelist)
- {
- switch (mode) {
- case PAGE_MODE_NONE:
-@@ -136,19 +132,11 @@ static struct page *free_sub_pt(unsigned long root, int mode,
- freelist = free_pt_page(root, freelist);
- break;
- case PAGE_MODE_2_LEVEL:
-- freelist = free_pt_l2(root, freelist);
-- break;
- case PAGE_MODE_3_LEVEL:
-- freelist = free_pt_l3(root, freelist);
-- break;
- case PAGE_MODE_4_LEVEL:
-- freelist = free_pt_l4(root, freelist);
-- break;
- case PAGE_MODE_5_LEVEL:
-- freelist = free_pt_l5(root, freelist);
-- break;
- case PAGE_MODE_6_LEVEL:
-- freelist = free_pt_l6(root, freelist);
-+ free_pt_lvl(root, freelist, mode);
- break;
- default:
- BUG();
-@@ -364,7 +352,7 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
-
- static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
- {
-- unsigned long pt;
-+ u64 *pt;
- int mode;
-
- while (cmpxchg64(pte, pteval, 0) != pteval) {
-@@ -375,7 +363,7 @@ static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
- if (!IOMMU_PTE_PRESENT(pteval))
- return freelist;
-
-- pt = (unsigned long)IOMMU_PTE_PAGE(pteval);
-+ pt = IOMMU_PTE_PAGE(pteval);
- mode = IOMMU_PTE_MODE(pteval);
-
- return free_sub_pt(pt, mode, freelist);
-@@ -512,7 +500,6 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- struct amd_io_pgtable *pgtable = container_of(iop, struct amd_io_pgtable, iop);
- struct protection_domain *dom;
- struct page *freelist = NULL;
-- unsigned long root;
-
- if (pgtable->mode == PAGE_MODE_NONE)
- return;
-@@ -529,8 +516,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
- pgtable->mode > PAGE_MODE_6_LEVEL);
-
-- root = (unsigned long)pgtable->root;
-- freelist = free_sub_pt(root, pgtable->mode, freelist);
-+ freelist = free_sub_pt(pgtable->root, pgtable->mode, freelist);
-
- free_page_list(freelist);
- }
---
-2.34.1
-
+++ /dev/null
-From 9b97aa7b7e805cb43fde64554473bfd458dad907 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 17 Dec 2021 15:30:59 +0000
-Subject: iommu/amd: Use put_pages_list
-
-From: Matthew Wilcox (Oracle) <willy@infradead.org>
-
-[ Upstream commit ce00eece6909c266da123fd147172d745a4f14a0 ]
-
-page->freelist is for the use of slab. We already have the ability
-to free a list of pages in the core mm, but it requires the use of a
-list_head and for the pages to be chained together through page->lru.
-Switch the AMD IOMMU code over to using free_pages_list().
-
-Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
-[rm: split from original patch, cosmetic tweaks]
-Signed-off-by: Robin Murphy <robin.murphy@arm.com>
-Link: https://lore.kernel.org/r/73af128f651aaa1f38f69e586c66765a88ad2de0.1639753638.git.robin.murphy@arm.com
-Signed-off-by: Joerg Roedel <jroedel@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/iommu/amd/io_pgtable.c | 50 ++++++++++++----------------------
- 1 file changed, 18 insertions(+), 32 deletions(-)
-
-diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
-index 4165e1372b6e..b1bf4125b0f7 100644
---- a/drivers/iommu/amd/io_pgtable.c
-+++ b/drivers/iommu/amd/io_pgtable.c
-@@ -74,26 +74,14 @@ static u64 *first_pte_l7(u64 *pte, unsigned long *page_size,
- *
- ****************************************************************************/
-
--static void free_page_list(struct page *freelist)
--{
-- while (freelist != NULL) {
-- unsigned long p = (unsigned long)page_address(freelist);
--
-- freelist = freelist->freelist;
-- free_page(p);
-- }
--}
--
--static struct page *free_pt_page(u64 *pt, struct page *freelist)
-+static void free_pt_page(u64 *pt, struct list_head *freelist)
- {
- struct page *p = virt_to_page(pt);
-
-- p->freelist = freelist;
--
-- return p;
-+ list_add_tail(&p->lru, freelist);
- }
-
--static struct page *free_pt_lvl(u64 *pt, struct page *freelist, int lvl)
-+static void free_pt_lvl(u64 *pt, struct list_head *freelist, int lvl)
- {
- u64 *p;
- int i;
-@@ -114,22 +102,22 @@ static struct page *free_pt_lvl(u64 *pt, struct page *freelist, int lvl)
- */
- p = IOMMU_PTE_PAGE(pt[i]);
- if (lvl > 2)
-- freelist = free_pt_lvl(p, freelist, lvl - 1);
-+ free_pt_lvl(p, freelist, lvl - 1);
- else
-- freelist = free_pt_page(p, freelist);
-+ free_pt_page(p, freelist);
- }
-
-- return free_pt_page(pt, freelist);
-+ free_pt_page(pt, freelist);
- }
-
--static struct page *free_sub_pt(u64 *root, int mode, struct page *freelist)
-+static void free_sub_pt(u64 *root, int mode, struct list_head *freelist)
- {
- switch (mode) {
- case PAGE_MODE_NONE:
- case PAGE_MODE_7_LEVEL:
- break;
- case PAGE_MODE_1_LEVEL:
-- freelist = free_pt_page(root, freelist);
-+ free_pt_page(root, freelist);
- break;
- case PAGE_MODE_2_LEVEL:
- case PAGE_MODE_3_LEVEL:
-@@ -141,8 +129,6 @@ static struct page *free_sub_pt(u64 *root, int mode, struct page *freelist)
- default:
- BUG();
- }
--
-- return freelist;
- }
-
- void amd_iommu_domain_set_pgtable(struct protection_domain *domain,
-@@ -350,7 +336,7 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
- return pte;
- }
-
--static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
-+static void free_clear_pte(u64 *pte, u64 pteval, struct list_head *freelist)
- {
- u64 *pt;
- int mode;
-@@ -361,12 +347,12 @@ static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
- }
-
- if (!IOMMU_PTE_PRESENT(pteval))
-- return freelist;
-+ return;
-
- pt = IOMMU_PTE_PAGE(pteval);
- mode = IOMMU_PTE_MODE(pteval);
-
-- return free_sub_pt(pt, mode, freelist);
-+ free_sub_pt(pt, mode, freelist);
- }
-
- /*
-@@ -380,7 +366,7 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
- {
- struct protection_domain *dom = io_pgtable_ops_to_domain(ops);
-- struct page *freelist = NULL;
-+ LIST_HEAD(freelist);
- bool updated = false;
- u64 __pte, *pte;
- int ret, i, count;
-@@ -400,9 +386,9 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
- goto out;
-
- for (i = 0; i < count; ++i)
-- freelist = free_clear_pte(&pte[i], pte[i], freelist);
-+ free_clear_pte(&pte[i], pte[i], &freelist);
-
-- if (freelist != NULL)
-+ if (!list_empty(&freelist))
- updated = true;
-
- if (count > 1) {
-@@ -437,7 +423,7 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
- }
-
- /* Everything flushed out, free pages now */
-- free_page_list(freelist);
-+ put_pages_list(&freelist);
-
- return ret;
- }
-@@ -499,7 +485,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- {
- struct amd_io_pgtable *pgtable = container_of(iop, struct amd_io_pgtable, iop);
- struct protection_domain *dom;
-- struct page *freelist = NULL;
-+ LIST_HEAD(freelist);
-
- if (pgtable->mode == PAGE_MODE_NONE)
- return;
-@@ -516,9 +502,9 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
- pgtable->mode > PAGE_MODE_6_LEVEL);
-
-- freelist = free_sub_pt(pgtable->root, pgtable->mode, freelist);
-+ free_sub_pt(pgtable->root, pgtable->mode, &freelist);
-
-- free_page_list(freelist);
-+ put_pages_list(&freelist);
- }
-
- static struct io_pgtable *v1_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
---
-2.34.1
-
s390-extable-fix-exception-table-sorting.patch
sched-fix-yet-more-sched_fork-races.patch
arm64-dts-juno-remove-gicv2m-dma-range.patch
-iommu-amd-simplify-pagetable-freeing.patch
-iommu-amd-use-put_pages_list.patch
iommu-amd-fix-i-o-page-table-memory-leak.patch
mips-ralink-mt7621-do-memory-detection-on-kseg1.patch
arm-dts-switch-timer-config-to-common-devkit8000-dev.patch
-From 17bba395b5754c254a6fda3a6973b2f35f6e4a46 Mon Sep 17 00:00:00 2001
+From 00b383444885ec44bc405dc9c8723a9cf54b09a9 Mon Sep 17 00:00:00 2001
From: Sasha Levin <sashal@kernel.org>
Date: Thu, 10 Feb 2022 09:47:45 -0600
Subject: iommu/amd: Fix I/O page table memory leak
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
-index b1bf4125b0f7..6608d1717574 100644
+index 182c93a43efd..1eddf557636d 100644
--- a/drivers/iommu/amd/io_pgtable.c
+++ b/drivers/iommu/amd/io_pgtable.c
-@@ -492,18 +492,18 @@ static void v1_free_pgtable(struct io_pgtable *iop)
+@@ -519,12 +519,6 @@ static void v1_free_pgtable(struct io_pgtable *iop)
dom = container_of(pgtable, struct protection_domain, iop);
/* Page-table is not visible to IOMMU anymore, so free it */
BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
pgtable->mode > PAGE_MODE_6_LEVEL);
-
- free_sub_pt(pgtable->root, pgtable->mode, &freelist);
+@@ -532,6 +526,12 @@ static void v1_free_pgtable(struct io_pgtable *iop)
+ root = (unsigned long)pgtable->root;
+ freelist = free_sub_pt(root, pgtable->mode, freelist);
+ /* Update data structure */
+ amd_iommu_domain_clr_pt_root(dom);
+ /* Make changes visible to IOMMUs */
+ amd_iommu_domain_update(dom);
+
- put_pages_list(&freelist);
+ free_page_list(freelist);
}
--
+++ /dev/null
-From da8f8eb5547bbcc236d36afd7cd01f49ad5d2c42 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 17 Dec 2021 15:30:58 +0000
-Subject: iommu/amd: Simplify pagetable freeing
-
-From: Robin Murphy <robin.murphy@arm.com>
-
-[ Upstream commit 6b3106e9ba2de7320a71291cedcefdcf1195ad58 ]
-
-For reasons unclear, pagetable freeing is an effectively recursive
-method implemented via an elaborate system of templated functions that
-turns out to account for 25% of the object file size. Implementing it
-using regular straightforward recursion makes the code simpler, and
-seems like a good thing to do before we work on it further. As part of
-that, also fix the types to avoid all the needless casting back and
-forth which just gets in the way.
-
-Signed-off-by: Robin Murphy <robin.murphy@arm.com>
-Link: https://lore.kernel.org/r/d3d00c9f3fa0df4756b867072c201e6e82f9ce39.1639753638.git.robin.murphy@arm.com
-Signed-off-by: Joerg Roedel <jroedel@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/iommu/amd/io_pgtable.c | 82 ++++++++++++++--------------------
- 1 file changed, 34 insertions(+), 48 deletions(-)
-
-diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
-index 182c93a43efd..4165e1372b6e 100644
---- a/drivers/iommu/amd/io_pgtable.c
-+++ b/drivers/iommu/amd/io_pgtable.c
-@@ -84,49 +84,45 @@ static void free_page_list(struct page *freelist)
- }
- }
-
--static struct page *free_pt_page(unsigned long pt, struct page *freelist)
-+static struct page *free_pt_page(u64 *pt, struct page *freelist)
- {
-- struct page *p = virt_to_page((void *)pt);
-+ struct page *p = virt_to_page(pt);
-
- p->freelist = freelist;
-
- return p;
- }
-
--#define DEFINE_FREE_PT_FN(LVL, FN) \
--static struct page *free_pt_##LVL (unsigned long __pt, struct page *freelist) \
--{ \
-- unsigned long p; \
-- u64 *pt; \
-- int i; \
-- \
-- pt = (u64 *)__pt; \
-- \
-- for (i = 0; i < 512; ++i) { \
-- /* PTE present? */ \
-- if (!IOMMU_PTE_PRESENT(pt[i])) \
-- continue; \
-- \
-- /* Large PTE? */ \
-- if (PM_PTE_LEVEL(pt[i]) == 0 || \
-- PM_PTE_LEVEL(pt[i]) == 7) \
-- continue; \
-- \
-- p = (unsigned long)IOMMU_PTE_PAGE(pt[i]); \
-- freelist = FN(p, freelist); \
-- } \
-- \
-- return free_pt_page((unsigned long)pt, freelist); \
--}
-+static struct page *free_pt_lvl(u64 *pt, struct page *freelist, int lvl)
-+{
-+ u64 *p;
-+ int i;
-+
-+ for (i = 0; i < 512; ++i) {
-+ /* PTE present? */
-+ if (!IOMMU_PTE_PRESENT(pt[i]))
-+ continue;
-
--DEFINE_FREE_PT_FN(l2, free_pt_page)
--DEFINE_FREE_PT_FN(l3, free_pt_l2)
--DEFINE_FREE_PT_FN(l4, free_pt_l3)
--DEFINE_FREE_PT_FN(l5, free_pt_l4)
--DEFINE_FREE_PT_FN(l6, free_pt_l5)
-+ /* Large PTE? */
-+ if (PM_PTE_LEVEL(pt[i]) == 0 ||
-+ PM_PTE_LEVEL(pt[i]) == 7)
-+ continue;
-
--static struct page *free_sub_pt(unsigned long root, int mode,
-- struct page *freelist)
-+ /*
-+ * Free the next level. No need to look at l1 tables here since
-+ * they can only contain leaf PTEs; just free them directly.
-+ */
-+ p = IOMMU_PTE_PAGE(pt[i]);
-+ if (lvl > 2)
-+ freelist = free_pt_lvl(p, freelist, lvl - 1);
-+ else
-+ freelist = free_pt_page(p, freelist);
-+ }
-+
-+ return free_pt_page(pt, freelist);
-+}
-+
-+static struct page *free_sub_pt(u64 *root, int mode, struct page *freelist)
- {
- switch (mode) {
- case PAGE_MODE_NONE:
-@@ -136,19 +132,11 @@ static struct page *free_sub_pt(unsigned long root, int mode,
- freelist = free_pt_page(root, freelist);
- break;
- case PAGE_MODE_2_LEVEL:
-- freelist = free_pt_l2(root, freelist);
-- break;
- case PAGE_MODE_3_LEVEL:
-- freelist = free_pt_l3(root, freelist);
-- break;
- case PAGE_MODE_4_LEVEL:
-- freelist = free_pt_l4(root, freelist);
-- break;
- case PAGE_MODE_5_LEVEL:
-- freelist = free_pt_l5(root, freelist);
-- break;
- case PAGE_MODE_6_LEVEL:
-- freelist = free_pt_l6(root, freelist);
-+ free_pt_lvl(root, freelist, mode);
- break;
- default:
- BUG();
-@@ -364,7 +352,7 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
-
- static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
- {
-- unsigned long pt;
-+ u64 *pt;
- int mode;
-
- while (cmpxchg64(pte, pteval, 0) != pteval) {
-@@ -375,7 +363,7 @@ static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
- if (!IOMMU_PTE_PRESENT(pteval))
- return freelist;
-
-- pt = (unsigned long)IOMMU_PTE_PAGE(pteval);
-+ pt = IOMMU_PTE_PAGE(pteval);
- mode = IOMMU_PTE_MODE(pteval);
-
- return free_sub_pt(pt, mode, freelist);
-@@ -512,7 +500,6 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- struct amd_io_pgtable *pgtable = container_of(iop, struct amd_io_pgtable, iop);
- struct protection_domain *dom;
- struct page *freelist = NULL;
-- unsigned long root;
-
- if (pgtable->mode == PAGE_MODE_NONE)
- return;
-@@ -529,8 +516,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
- pgtable->mode > PAGE_MODE_6_LEVEL);
-
-- root = (unsigned long)pgtable->root;
-- freelist = free_sub_pt(root, pgtable->mode, freelist);
-+ freelist = free_sub_pt(pgtable->root, pgtable->mode, freelist);
-
- free_page_list(freelist);
- }
---
-2.34.1
-
+++ /dev/null
-From 42cf2683550e58b3529f00d834e1a700c8962994 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Fri, 17 Dec 2021 15:30:59 +0000
-Subject: iommu/amd: Use put_pages_list
-
-From: Matthew Wilcox (Oracle) <willy@infradead.org>
-
-[ Upstream commit ce00eece6909c266da123fd147172d745a4f14a0 ]
-
-page->freelist is for the use of slab. We already have the ability
-to free a list of pages in the core mm, but it requires the use of a
-list_head and for the pages to be chained together through page->lru.
-Switch the AMD IOMMU code over to using free_pages_list().
-
-Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
-[rm: split from original patch, cosmetic tweaks]
-Signed-off-by: Robin Murphy <robin.murphy@arm.com>
-Link: https://lore.kernel.org/r/73af128f651aaa1f38f69e586c66765a88ad2de0.1639753638.git.robin.murphy@arm.com
-Signed-off-by: Joerg Roedel <jroedel@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/iommu/amd/io_pgtable.c | 50 ++++++++++++----------------------
- 1 file changed, 18 insertions(+), 32 deletions(-)
-
-diff --git a/drivers/iommu/amd/io_pgtable.c b/drivers/iommu/amd/io_pgtable.c
-index 4165e1372b6e..b1bf4125b0f7 100644
---- a/drivers/iommu/amd/io_pgtable.c
-+++ b/drivers/iommu/amd/io_pgtable.c
-@@ -74,26 +74,14 @@ static u64 *first_pte_l7(u64 *pte, unsigned long *page_size,
- *
- ****************************************************************************/
-
--static void free_page_list(struct page *freelist)
--{
-- while (freelist != NULL) {
-- unsigned long p = (unsigned long)page_address(freelist);
--
-- freelist = freelist->freelist;
-- free_page(p);
-- }
--}
--
--static struct page *free_pt_page(u64 *pt, struct page *freelist)
-+static void free_pt_page(u64 *pt, struct list_head *freelist)
- {
- struct page *p = virt_to_page(pt);
-
-- p->freelist = freelist;
--
-- return p;
-+ list_add_tail(&p->lru, freelist);
- }
-
--static struct page *free_pt_lvl(u64 *pt, struct page *freelist, int lvl)
-+static void free_pt_lvl(u64 *pt, struct list_head *freelist, int lvl)
- {
- u64 *p;
- int i;
-@@ -114,22 +102,22 @@ static struct page *free_pt_lvl(u64 *pt, struct page *freelist, int lvl)
- */
- p = IOMMU_PTE_PAGE(pt[i]);
- if (lvl > 2)
-- freelist = free_pt_lvl(p, freelist, lvl - 1);
-+ free_pt_lvl(p, freelist, lvl - 1);
- else
-- freelist = free_pt_page(p, freelist);
-+ free_pt_page(p, freelist);
- }
-
-- return free_pt_page(pt, freelist);
-+ free_pt_page(pt, freelist);
- }
-
--static struct page *free_sub_pt(u64 *root, int mode, struct page *freelist)
-+static void free_sub_pt(u64 *root, int mode, struct list_head *freelist)
- {
- switch (mode) {
- case PAGE_MODE_NONE:
- case PAGE_MODE_7_LEVEL:
- break;
- case PAGE_MODE_1_LEVEL:
-- freelist = free_pt_page(root, freelist);
-+ free_pt_page(root, freelist);
- break;
- case PAGE_MODE_2_LEVEL:
- case PAGE_MODE_3_LEVEL:
-@@ -141,8 +129,6 @@ static struct page *free_sub_pt(u64 *root, int mode, struct page *freelist)
- default:
- BUG();
- }
--
-- return freelist;
- }
-
- void amd_iommu_domain_set_pgtable(struct protection_domain *domain,
-@@ -350,7 +336,7 @@ static u64 *fetch_pte(struct amd_io_pgtable *pgtable,
- return pte;
- }
-
--static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
-+static void free_clear_pte(u64 *pte, u64 pteval, struct list_head *freelist)
- {
- u64 *pt;
- int mode;
-@@ -361,12 +347,12 @@ static struct page *free_clear_pte(u64 *pte, u64 pteval, struct page *freelist)
- }
-
- if (!IOMMU_PTE_PRESENT(pteval))
-- return freelist;
-+ return;
-
- pt = IOMMU_PTE_PAGE(pteval);
- mode = IOMMU_PTE_MODE(pteval);
-
-- return free_sub_pt(pt, mode, freelist);
-+ free_sub_pt(pt, mode, freelist);
- }
-
- /*
-@@ -380,7 +366,7 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot, gfp_t gfp)
- {
- struct protection_domain *dom = io_pgtable_ops_to_domain(ops);
-- struct page *freelist = NULL;
-+ LIST_HEAD(freelist);
- bool updated = false;
- u64 __pte, *pte;
- int ret, i, count;
-@@ -400,9 +386,9 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
- goto out;
-
- for (i = 0; i < count; ++i)
-- freelist = free_clear_pte(&pte[i], pte[i], freelist);
-+ free_clear_pte(&pte[i], pte[i], &freelist);
-
-- if (freelist != NULL)
-+ if (!list_empty(&freelist))
- updated = true;
-
- if (count > 1) {
-@@ -437,7 +423,7 @@ static int iommu_v1_map_page(struct io_pgtable_ops *ops, unsigned long iova,
- }
-
- /* Everything flushed out, free pages now */
-- free_page_list(freelist);
-+ put_pages_list(&freelist);
-
- return ret;
- }
-@@ -499,7 +485,7 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- {
- struct amd_io_pgtable *pgtable = container_of(iop, struct amd_io_pgtable, iop);
- struct protection_domain *dom;
-- struct page *freelist = NULL;
-+ LIST_HEAD(freelist);
-
- if (pgtable->mode == PAGE_MODE_NONE)
- return;
-@@ -516,9 +502,9 @@ static void v1_free_pgtable(struct io_pgtable *iop)
- BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
- pgtable->mode > PAGE_MODE_6_LEVEL);
-
-- freelist = free_sub_pt(pgtable->root, pgtable->mode, freelist);
-+ free_sub_pt(pgtable->root, pgtable->mode, &freelist);
-
-- free_page_list(freelist);
-+ put_pages_list(&freelist);
- }
-
- static struct io_pgtable *v1_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
---
-2.34.1
-
arm64-dts-juno-remove-gicv2m-dma-range.patch
arm64-dts-rockchip-fix-quartz64-a-ddr-regulator-volt.patch
arm64-dts-imx8mm-fix-vpu-hanging.patch
-iommu-amd-simplify-pagetable-freeing.patch
-iommu-amd-use-put_pages_list.patch
iommu-amd-fix-i-o-page-table-memory-leak.patch
mips-ralink-mt7621-do-memory-detection-on-kseg1.patch
arm-dts-switch-timer-config-to-common-devkit8000-dev.patch