forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
iommu: introduce generic page table allocation framework
This patch introduces a generic framework for allocating page tables for an IOMMU. There are a number of reasons we want to do this: - It avoids duplication of complex table management code in IOMMU drivers that use the same page table format - It removes any coupling with the CPU table format (and even the architecture!) - It defines an API for IOMMU TLB maintenance Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
- Loading branch information
Showing
4 changed files
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Generic page table allocator for IOMMUs. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
* Copyright (C) 2014 ARM Limited | ||
* | ||
* Author: Will Deacon <will.deacon@arm.com> | ||
*/ | ||
|
||
#include <linux/bug.h> | ||
#include <linux/kernel.h> | ||
#include <linux/types.h> | ||
|
||
#include "io-pgtable.h" | ||
|
||
static const struct io_pgtable_init_fns * | ||
io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = | ||
{ | ||
}; | ||
|
||
struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, | ||
struct io_pgtable_cfg *cfg, | ||
void *cookie) | ||
{ | ||
struct io_pgtable *iop; | ||
const struct io_pgtable_init_fns *fns; | ||
|
||
if (fmt >= IO_PGTABLE_NUM_FMTS) | ||
return NULL; | ||
|
||
fns = io_pgtable_init_table[fmt]; | ||
if (!fns) | ||
return NULL; | ||
|
||
iop = fns->alloc(cfg, cookie); | ||
if (!iop) | ||
return NULL; | ||
|
||
iop->fmt = fmt; | ||
iop->cookie = cookie; | ||
iop->cfg = *cfg; | ||
|
||
return &iop->ops; | ||
} | ||
|
||
/* | ||
* It is the IOMMU driver's responsibility to ensure that the page table | ||
* is no longer accessible to the walker by this point. | ||
*/ | ||
void free_io_pgtable_ops(struct io_pgtable_ops *ops) | ||
{ | ||
struct io_pgtable *iop; | ||
|
||
if (!ops) | ||
return; | ||
|
||
iop = container_of(ops, struct io_pgtable, ops); | ||
iop->cfg.tlb->tlb_flush_all(iop->cookie); | ||
io_pgtable_init_table[iop->fmt]->free(iop); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
#ifndef __IO_PGTABLE_H | ||
#define __IO_PGTABLE_H | ||
|
||
/* | ||
* Public API for use by IOMMU drivers | ||
*/ | ||
enum io_pgtable_fmt { | ||
IO_PGTABLE_NUM_FMTS, | ||
}; | ||
|
||
/** | ||
* struct iommu_gather_ops - IOMMU callbacks for TLB and page table management. | ||
* | ||
* @tlb_flush_all: Synchronously invalidate the entire TLB context. | ||
* @tlb_add_flush: Queue up a TLB invalidation for a virtual address range. | ||
* @tlb_sync: Ensure any queue TLB invalidation has taken effect. | ||
* @flush_pgtable: Ensure page table updates are visible to the IOMMU. | ||
* | ||
* Note that these can all be called in atomic context and must therefore | ||
* not block. | ||
*/ | ||
struct iommu_gather_ops { | ||
void (*tlb_flush_all)(void *cookie); | ||
void (*tlb_add_flush)(unsigned long iova, size_t size, bool leaf, | ||
void *cookie); | ||
void (*tlb_sync)(void *cookie); | ||
void (*flush_pgtable)(void *ptr, size_t size, void *cookie); | ||
}; | ||
|
||
/** | ||
* struct io_pgtable_cfg - Configuration data for a set of page tables. | ||
* | ||
* @quirks: A bitmap of hardware quirks that require some special | ||
* action by the low-level page table allocator. | ||
* @pgsize_bitmap: A bitmap of page sizes supported by this set of page | ||
* tables. | ||
* @ias: Input address (iova) size, in bits. | ||
* @oas: Output address (paddr) size, in bits. | ||
* @tlb: TLB management callbacks for this set of tables. | ||
*/ | ||
struct io_pgtable_cfg { | ||
int quirks; /* IO_PGTABLE_QUIRK_* */ | ||
unsigned long pgsize_bitmap; | ||
unsigned int ias; | ||
unsigned int oas; | ||
const struct iommu_gather_ops *tlb; | ||
|
||
/* Low-level data specific to the table format */ | ||
union { | ||
}; | ||
}; | ||
|
||
/** | ||
* struct io_pgtable_ops - Page table manipulation API for IOMMU drivers. | ||
* | ||
* @map: Map a physically contiguous memory region. | ||
* @unmap: Unmap a physically contiguous memory region. | ||
* @iova_to_phys: Translate iova to physical address. | ||
* | ||
* These functions map directly onto the iommu_ops member functions with | ||
* the same names. | ||
*/ | ||
struct io_pgtable_ops { | ||
int (*map)(struct io_pgtable_ops *ops, unsigned long iova, | ||
phys_addr_t paddr, size_t size, int prot); | ||
int (*unmap)(struct io_pgtable_ops *ops, unsigned long iova, | ||
size_t size); | ||
phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops, | ||
unsigned long iova); | ||
}; | ||
|
||
/** | ||
* alloc_io_pgtable_ops() - Allocate a page table allocator for use by an IOMMU. | ||
* | ||
* @fmt: The page table format. | ||
* @cfg: The page table configuration. This will be modified to represent | ||
* the configuration actually provided by the allocator (e.g. the | ||
* pgsize_bitmap may be restricted). | ||
* @cookie: An opaque token provided by the IOMMU driver and passed back to | ||
* the callback routines in cfg->tlb. | ||
*/ | ||
struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt, | ||
struct io_pgtable_cfg *cfg, | ||
void *cookie); | ||
|
||
/** | ||
* free_io_pgtable_ops() - Free an io_pgtable_ops structure. The caller | ||
* *must* ensure that the page table is no longer | ||
* live, but the TLB can be dirty. | ||
* | ||
* @ops: The ops returned from alloc_io_pgtable_ops. | ||
*/ | ||
void free_io_pgtable_ops(struct io_pgtable_ops *ops); | ||
|
||
|
||
/* | ||
* Internal structures for page table allocator implementations. | ||
*/ | ||
|
||
/** | ||
* struct io_pgtable - Internal structure describing a set of page tables. | ||
* | ||
* @fmt: The page table format. | ||
* @cookie: An opaque token provided by the IOMMU driver and passed back to | ||
* any callback routines. | ||
* @cfg: A copy of the page table configuration. | ||
* @ops: The page table operations in use for this set of page tables. | ||
*/ | ||
struct io_pgtable { | ||
enum io_pgtable_fmt fmt; | ||
void *cookie; | ||
struct io_pgtable_cfg cfg; | ||
struct io_pgtable_ops ops; | ||
}; | ||
|
||
/** | ||
* struct io_pgtable_init_fns - Alloc/free a set of page tables for a | ||
* particular format. | ||
* | ||
* @alloc: Allocate a set of page tables described by cfg. | ||
* @free: Free the page tables associated with iop. | ||
*/ | ||
struct io_pgtable_init_fns { | ||
struct io_pgtable *(*alloc)(struct io_pgtable_cfg *cfg, void *cookie); | ||
void (*free)(struct io_pgtable *iop); | ||
}; | ||
|
||
#endif /* __IO_PGTABLE_H */ |