mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: Nicolin Chen <nicolinc@nvidia.com> Tested-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/8-v4-c8663abbb606+3f7-iommu_pages_jgg@nvidia.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
f5af4a4f7c
commit
13f43d7cf3
3 changed files with 69 additions and 11 deletions
|
@ -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);
|
||||
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_old);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue