Commit 13f43d7c authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Joerg Roedel
Browse files

iommu/pages: Formalize the freelist API



We want to get rid of struct page references outside the internal
allocator implementation. The free list has the driver open code something
like:

   list_add_tail(&virt_to_page(ptr)->lru, freelist);

Move the above into a small inline and make the freelist into a wrapper
type 'struct iommu_pages_list' so that the compiler can help check all the
conversion.

This struct has also proven helpful in some future ideas to convert to a
singly linked list to get an extra pointer in the struct page, and to
signal that the pages should be freed with RCU.

Use a temporary _Generic so we don't need to rename the free function as
the patches progress.

Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Tested-by: default avatarAlejandro Jimenez <alejandro.j.jimenez@oracle.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/8-v4-c8663abbb606+3f7-iommu_pages_jgg@nvidia.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent f5af4a4f
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -67,18 +67,25 @@ void iommu_free_pages(void *virt)
EXPORT_SYMBOL_GPL(iommu_free_pages);

/**
 * iommu_put_pages_list - free a list of pages.
 * @head: the head of the lru list to be freed.
 * iommu_put_pages_list_new - free a list of pages.
 * @list: The list of pages to be freed
 *
 * Frees a list of pages allocated by iommu_alloc_pages_node().
 */
void iommu_put_pages_list(struct list_head *head)
void iommu_put_pages_list_new(struct iommu_pages_list *list)
{
	while (!list_empty(head)) {
		struct page *p = list_entry(head->prev, struct page, lru);
	struct page *p, *tmp;

		list_del(&p->lru);
	list_for_each_entry_safe(p, tmp, &list->pages, lru)
		__iommu_free_page(p);
}
EXPORT_SYMBOL_GPL(iommu_put_pages_list_new);

void iommu_put_pages_list_old(struct list_head *head)
{
	struct page *p, *tmp;

	list_for_each_entry_safe(p, tmp, head, lru)
		__iommu_free_page(p);
}
EXPORT_SYMBOL_GPL(iommu_put_pages_list);
EXPORT_SYMBOL_GPL(iommu_put_pages_list_old);
+42 −3
Original line number Diff line number Diff line
@@ -7,12 +7,51 @@
#ifndef __IOMMU_PAGES_H
#define __IOMMU_PAGES_H

#include <linux/types.h>
#include <linux/topology.h>
#include <linux/iommu.h>

void *iommu_alloc_pages_node(int nid, gfp_t gfp, unsigned int order);
void iommu_free_pages(void *virt);
void iommu_put_pages_list(struct list_head *head);
void iommu_put_pages_list_new(struct iommu_pages_list *list);
void iommu_put_pages_list_old(struct list_head *head);

#define iommu_put_pages_list(head)                                   \
	_Generic(head,                                               \
		struct iommu_pages_list *: iommu_put_pages_list_new, \
		struct list_head *: iommu_put_pages_list_old)(head)

/**
 * iommu_pages_list_add - add the page to a iommu_pages_list
 * @list: List to add the page to
 * @virt: Address returned from iommu_alloc_pages_node()
 */
static inline void iommu_pages_list_add(struct iommu_pages_list *list,
					void *virt)
{
	list_add_tail(&virt_to_page(virt)->lru, &list->pages);
}

/**
 * iommu_pages_list_splice - Put all the pages in list from into list to
 * @from: Source list of pages
 * @to: Destination list of pages
 *
 * from must be re-initialized after calling this function if it is to be
 * used again.
 */
static inline void iommu_pages_list_splice(struct iommu_pages_list *from,
					   struct iommu_pages_list *to)
{
	list_splice(&from->pages, &to->pages);
}

/**
 * iommu_pages_list_empty - True if the list is empty
 * @list: List to check
 */
static inline bool iommu_pages_list_empty(struct iommu_pages_list *list)
{
	return list_empty(&list->pages);
}

/**
 * iommu_alloc_pages - allocate a zeroed page of a given order
+12 −0
Original line number Diff line number Diff line
@@ -341,6 +341,18 @@ typedef unsigned int ioasid_t;
/* Read but do not clear any dirty bits */
#define IOMMU_DIRTY_NO_CLEAR (1 << 0)

/*
 * Pages allocated through iommu_alloc_pages_node() can be placed on this list
 * using iommu_pages_list_add(). Note: ONLY pages from iommu_alloc_pages_node()
 * can be used this way!
 */
struct iommu_pages_list {
	struct list_head pages;
};

#define IOMMU_PAGES_LIST_INIT(name) \
	((struct iommu_pages_list){ .pages = LIST_HEAD_INIT(name.pages) })

#ifdef CONFIG_IOMMU_API

/**