162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation 462306a36Sopenharmony_ci * Rewrite, cleanup: 562306a36Sopenharmony_ci * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _ASM_IOMMU_H 962306a36Sopenharmony_ci#define _ASM_IOMMU_H 1062306a36Sopenharmony_ci#ifdef __KERNEL__ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/compiler.h> 1362306a36Sopenharmony_ci#include <linux/spinlock.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 1662306a36Sopenharmony_ci#include <linux/bitops.h> 1762306a36Sopenharmony_ci#include <asm/machdep.h> 1862306a36Sopenharmony_ci#include <asm/types.h> 1962306a36Sopenharmony_ci#include <asm/pci-bridge.h> 2062306a36Sopenharmony_ci#include <asm/asm-const.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define IOMMU_PAGE_SHIFT_4K 12 2362306a36Sopenharmony_ci#define IOMMU_PAGE_SIZE_4K (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K) 2462306a36Sopenharmony_ci#define IOMMU_PAGE_MASK_4K (~((1 << IOMMU_PAGE_SHIFT_4K) - 1)) 2562306a36Sopenharmony_ci#define IOMMU_PAGE_ALIGN_4K(addr) ALIGN(addr, IOMMU_PAGE_SIZE_4K) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define IOMMU_PAGE_SIZE(tblptr) (ASM_CONST(1) << (tblptr)->it_page_shift) 2862306a36Sopenharmony_ci#define IOMMU_PAGE_MASK(tblptr) (~((1 << (tblptr)->it_page_shift) - 1)) 2962306a36Sopenharmony_ci#define IOMMU_PAGE_ALIGN(addr, tblptr) ALIGN(addr, IOMMU_PAGE_SIZE(tblptr)) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define DIRECT64_PROPNAME "linux,direct64-ddr-window-info" 3262306a36Sopenharmony_ci#define DMA64_PROPNAME "linux,dma64-ddr-window-info" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Boot time flags */ 3562306a36Sopenharmony_ciextern int iommu_is_off; 3662306a36Sopenharmony_ciextern int iommu_force_on; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistruct iommu_table_ops { 3962306a36Sopenharmony_ci /* 4062306a36Sopenharmony_ci * When called with direction==DMA_NONE, it is equal to clear(). 4162306a36Sopenharmony_ci * uaddr is a linear map address. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci int (*set)(struct iommu_table *tbl, 4462306a36Sopenharmony_ci long index, long npages, 4562306a36Sopenharmony_ci unsigned long uaddr, 4662306a36Sopenharmony_ci enum dma_data_direction direction, 4762306a36Sopenharmony_ci unsigned long attrs); 4862306a36Sopenharmony_ci#ifdef CONFIG_IOMMU_API 4962306a36Sopenharmony_ci /* 5062306a36Sopenharmony_ci * Exchanges existing TCE with new TCE plus direction bits; 5162306a36Sopenharmony_ci * returns old TCE and DMA direction mask. 5262306a36Sopenharmony_ci * @tce is a physical address. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci int (*xchg_no_kill)(struct iommu_table *tbl, 5562306a36Sopenharmony_ci long index, 5662306a36Sopenharmony_ci unsigned long *hpa, 5762306a36Sopenharmony_ci enum dma_data_direction *direction); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci void (*tce_kill)(struct iommu_table *tbl, 6062306a36Sopenharmony_ci unsigned long index, 6162306a36Sopenharmony_ci unsigned long pages); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci __be64 *(*useraddrptr)(struct iommu_table *tbl, long index, bool alloc); 6462306a36Sopenharmony_ci#endif 6562306a36Sopenharmony_ci void (*clear)(struct iommu_table *tbl, 6662306a36Sopenharmony_ci long index, long npages); 6762306a36Sopenharmony_ci /* get() returns a physical address */ 6862306a36Sopenharmony_ci unsigned long (*get)(struct iommu_table *tbl, long index); 6962306a36Sopenharmony_ci void (*flush)(struct iommu_table *tbl); 7062306a36Sopenharmony_ci void (*free)(struct iommu_table *tbl); 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* These are used by VIO */ 7462306a36Sopenharmony_ciextern struct iommu_table_ops iommu_table_lpar_multi_ops; 7562306a36Sopenharmony_ciextern struct iommu_table_ops iommu_table_pseries_ops; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * IOMAP_MAX_ORDER defines the largest contiguous block 7962306a36Sopenharmony_ci * of dma space we can get. IOMAP_MAX_ORDER = 13 8062306a36Sopenharmony_ci * allows up to 2**12 pages (4096 * 4096) = 16 MB 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci#define IOMAP_MAX_ORDER 13 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define IOMMU_POOL_HASHBITS 2 8562306a36Sopenharmony_ci#define IOMMU_NR_POOLS (1 << IOMMU_POOL_HASHBITS) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistruct iommu_pool { 8862306a36Sopenharmony_ci unsigned long start; 8962306a36Sopenharmony_ci unsigned long end; 9062306a36Sopenharmony_ci unsigned long hint; 9162306a36Sopenharmony_ci spinlock_t lock; 9262306a36Sopenharmony_ci} ____cacheline_aligned_in_smp; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct iommu_table { 9562306a36Sopenharmony_ci unsigned long it_busno; /* Bus number this table belongs to */ 9662306a36Sopenharmony_ci unsigned long it_size; /* Size of iommu table in entries */ 9762306a36Sopenharmony_ci unsigned long it_indirect_levels; 9862306a36Sopenharmony_ci unsigned long it_level_size; 9962306a36Sopenharmony_ci unsigned long it_allocated_size; 10062306a36Sopenharmony_ci unsigned long it_offset; /* Offset into global table */ 10162306a36Sopenharmony_ci unsigned long it_base; /* mapped address of tce table */ 10262306a36Sopenharmony_ci unsigned long it_index; /* which iommu table this is */ 10362306a36Sopenharmony_ci unsigned long it_type; /* type: PCI or Virtual Bus */ 10462306a36Sopenharmony_ci unsigned long it_blocksize; /* Entries in each block (cacheline) */ 10562306a36Sopenharmony_ci unsigned long poolsize; 10662306a36Sopenharmony_ci unsigned long nr_pools; 10762306a36Sopenharmony_ci struct iommu_pool large_pool; 10862306a36Sopenharmony_ci struct iommu_pool pools[IOMMU_NR_POOLS]; 10962306a36Sopenharmony_ci unsigned long *it_map; /* A simple allocation bitmap for now */ 11062306a36Sopenharmony_ci unsigned long it_page_shift;/* table iommu page size */ 11162306a36Sopenharmony_ci struct list_head it_group_list;/* List of iommu_table_group_link */ 11262306a36Sopenharmony_ci __be64 *it_userspace; /* userspace view of the table */ 11362306a36Sopenharmony_ci struct iommu_table_ops *it_ops; 11462306a36Sopenharmony_ci struct kref it_kref; 11562306a36Sopenharmony_ci int it_nid; 11662306a36Sopenharmony_ci unsigned long it_reserved_start; /* Start of not-DMA-able (MMIO) area */ 11762306a36Sopenharmony_ci unsigned long it_reserved_end; 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define IOMMU_TABLE_USERSPACE_ENTRY_RO(tbl, entry) \ 12162306a36Sopenharmony_ci ((tbl)->it_ops->useraddrptr((tbl), (entry), false)) 12262306a36Sopenharmony_ci#define IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry) \ 12362306a36Sopenharmony_ci ((tbl)->it_ops->useraddrptr((tbl), (entry), true)) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* Pure 2^n version of get_order */ 12662306a36Sopenharmony_cistatic inline __attribute_const__ 12762306a36Sopenharmony_ciint get_iommu_order(unsigned long size, struct iommu_table *tbl) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci return __ilog2((size - 1) >> tbl->it_page_shift) + 1; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistruct scatterlist; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#ifdef CONFIG_PPC64 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic inline void set_iommu_table_base(struct device *dev, 13862306a36Sopenharmony_ci struct iommu_table *base) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci dev->archdata.iommu_table_base = base; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic inline void *get_iommu_table_base(struct device *dev) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci return dev->archdata.iommu_table_base; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ciextern int dma_iommu_dma_supported(struct device *dev, u64 mask); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciextern struct iommu_table *iommu_tce_table_get(struct iommu_table *tbl); 15162306a36Sopenharmony_ciextern int iommu_tce_table_put(struct iommu_table *tbl); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* Initializes an iommu_table based in values set in the passed-in 15462306a36Sopenharmony_ci * structure 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ciextern struct iommu_table *iommu_init_table(struct iommu_table *tbl, 15762306a36Sopenharmony_ci int nid, unsigned long res_start, unsigned long res_end); 15862306a36Sopenharmony_cibool iommu_table_in_use(struct iommu_table *tbl); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define IOMMU_TABLE_GROUP_MAX_TABLES 2 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistruct iommu_table_group; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistruct iommu_table_group_ops { 16562306a36Sopenharmony_ci unsigned long (*get_table_size)( 16662306a36Sopenharmony_ci __u32 page_shift, 16762306a36Sopenharmony_ci __u64 window_size, 16862306a36Sopenharmony_ci __u32 levels); 16962306a36Sopenharmony_ci long (*create_table)(struct iommu_table_group *table_group, 17062306a36Sopenharmony_ci int num, 17162306a36Sopenharmony_ci __u32 page_shift, 17262306a36Sopenharmony_ci __u64 window_size, 17362306a36Sopenharmony_ci __u32 levels, 17462306a36Sopenharmony_ci struct iommu_table **ptbl); 17562306a36Sopenharmony_ci long (*set_window)(struct iommu_table_group *table_group, 17662306a36Sopenharmony_ci int num, 17762306a36Sopenharmony_ci struct iommu_table *tblnew); 17862306a36Sopenharmony_ci long (*unset_window)(struct iommu_table_group *table_group, 17962306a36Sopenharmony_ci int num); 18062306a36Sopenharmony_ci /* Switch ownership from platform code to external user (e.g. VFIO) */ 18162306a36Sopenharmony_ci long (*take_ownership)(struct iommu_table_group *table_group); 18262306a36Sopenharmony_ci /* Switch ownership from external user (e.g. VFIO) back to core */ 18362306a36Sopenharmony_ci void (*release_ownership)(struct iommu_table_group *table_group); 18462306a36Sopenharmony_ci}; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistruct iommu_table_group_link { 18762306a36Sopenharmony_ci struct list_head next; 18862306a36Sopenharmony_ci struct rcu_head rcu; 18962306a36Sopenharmony_ci struct iommu_table_group *table_group; 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistruct iommu_table_group { 19362306a36Sopenharmony_ci /* IOMMU properties */ 19462306a36Sopenharmony_ci __u32 tce32_start; 19562306a36Sopenharmony_ci __u32 tce32_size; 19662306a36Sopenharmony_ci __u64 pgsizes; /* Bitmap of supported page sizes */ 19762306a36Sopenharmony_ci __u32 max_dynamic_windows_supported; 19862306a36Sopenharmony_ci __u32 max_levels; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci struct iommu_group *group; 20162306a36Sopenharmony_ci struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES]; 20262306a36Sopenharmony_ci struct iommu_table_group_ops *ops; 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#ifdef CONFIG_IOMMU_API 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ciextern void iommu_register_group(struct iommu_table_group *table_group, 20862306a36Sopenharmony_ci int pci_domain_number, unsigned long pe_num); 20962306a36Sopenharmony_ciextern int iommu_add_device(struct iommu_table_group *table_group, 21062306a36Sopenharmony_ci struct device *dev); 21162306a36Sopenharmony_ciextern long iommu_tce_xchg(struct mm_struct *mm, struct iommu_table *tbl, 21262306a36Sopenharmony_ci unsigned long entry, unsigned long *hpa, 21362306a36Sopenharmony_ci enum dma_data_direction *direction); 21462306a36Sopenharmony_ciextern long iommu_tce_xchg_no_kill(struct mm_struct *mm, 21562306a36Sopenharmony_ci struct iommu_table *tbl, 21662306a36Sopenharmony_ci unsigned long entry, unsigned long *hpa, 21762306a36Sopenharmony_ci enum dma_data_direction *direction); 21862306a36Sopenharmony_ciextern void iommu_tce_kill(struct iommu_table *tbl, 21962306a36Sopenharmony_ci unsigned long entry, unsigned long pages); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ciextern struct iommu_table_group_ops spapr_tce_table_group_ops; 22262306a36Sopenharmony_ci#else 22362306a36Sopenharmony_cistatic inline void iommu_register_group(struct iommu_table_group *table_group, 22462306a36Sopenharmony_ci int pci_domain_number, 22562306a36Sopenharmony_ci unsigned long pe_num) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic inline int iommu_add_device(struct iommu_table_group *table_group, 23062306a36Sopenharmony_ci struct device *dev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci#endif /* !CONFIG_IOMMU_API */ 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ciu64 dma_iommu_get_required_mask(struct device *dev); 23762306a36Sopenharmony_ci#else 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic inline void *get_iommu_table_base(struct device *dev) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return NULL; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic inline int dma_iommu_dma_supported(struct device *dev, u64 mask) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ciextern int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl, 25262306a36Sopenharmony_ci struct scatterlist *sglist, int nelems, 25362306a36Sopenharmony_ci unsigned long mask, 25462306a36Sopenharmony_ci enum dma_data_direction direction, 25562306a36Sopenharmony_ci unsigned long attrs); 25662306a36Sopenharmony_ciextern void ppc_iommu_unmap_sg(struct iommu_table *tbl, 25762306a36Sopenharmony_ci struct scatterlist *sglist, 25862306a36Sopenharmony_ci int nelems, 25962306a36Sopenharmony_ci enum dma_data_direction direction, 26062306a36Sopenharmony_ci unsigned long attrs); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ciextern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, 26362306a36Sopenharmony_ci size_t size, dma_addr_t *dma_handle, 26462306a36Sopenharmony_ci unsigned long mask, gfp_t flag, int node); 26562306a36Sopenharmony_ciextern void iommu_free_coherent(struct iommu_table *tbl, size_t size, 26662306a36Sopenharmony_ci void *vaddr, dma_addr_t dma_handle); 26762306a36Sopenharmony_ciextern dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl, 26862306a36Sopenharmony_ci struct page *page, unsigned long offset, 26962306a36Sopenharmony_ci size_t size, unsigned long mask, 27062306a36Sopenharmony_ci enum dma_data_direction direction, 27162306a36Sopenharmony_ci unsigned long attrs); 27262306a36Sopenharmony_ciextern void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle, 27362306a36Sopenharmony_ci size_t size, enum dma_data_direction direction, 27462306a36Sopenharmony_ci unsigned long attrs); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_civoid __init iommu_init_early_pSeries(void); 27762306a36Sopenharmony_ciextern void iommu_init_early_dart(struct pci_controller_ops *controller_ops); 27862306a36Sopenharmony_ciextern void iommu_init_early_pasemi(void); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci#if defined(CONFIG_PPC64) && defined(CONFIG_PM) 28162306a36Sopenharmony_cistatic inline void iommu_restore(void) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci if (ppc_md.iommu_restore) 28462306a36Sopenharmony_ci ppc_md.iommu_restore(); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci#endif 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* The API to support IOMMU operations for VFIO */ 28962306a36Sopenharmony_ciextern int iommu_tce_check_ioba(unsigned long page_shift, 29062306a36Sopenharmony_ci unsigned long offset, unsigned long size, 29162306a36Sopenharmony_ci unsigned long ioba, unsigned long npages); 29262306a36Sopenharmony_ciextern int iommu_tce_check_gpa(unsigned long page_shift, 29362306a36Sopenharmony_ci unsigned long gpa); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci#define iommu_tce_clear_param_check(tbl, ioba, tce_value, npages) \ 29662306a36Sopenharmony_ci (iommu_tce_check_ioba((tbl)->it_page_shift, \ 29762306a36Sopenharmony_ci (tbl)->it_offset, (tbl)->it_size, \ 29862306a36Sopenharmony_ci (ioba), (npages)) || (tce_value)) 29962306a36Sopenharmony_ci#define iommu_tce_put_param_check(tbl, ioba, gpa) \ 30062306a36Sopenharmony_ci (iommu_tce_check_ioba((tbl)->it_page_shift, \ 30162306a36Sopenharmony_ci (tbl)->it_offset, (tbl)->it_size, \ 30262306a36Sopenharmony_ci (ioba), 1) || \ 30362306a36Sopenharmony_ci iommu_tce_check_gpa((tbl)->it_page_shift, (gpa))) 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciextern void iommu_flush_tce(struct iommu_table *tbl); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciextern enum dma_data_direction iommu_tce_direction(unsigned long tce); 30862306a36Sopenharmony_ciextern unsigned long iommu_direction_to_tce_perm(enum dma_data_direction dir); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci#ifdef CONFIG_PPC_CELL_NATIVE 31162306a36Sopenharmony_ciextern bool iommu_fixed_is_weak; 31262306a36Sopenharmony_ci#else 31362306a36Sopenharmony_ci#define iommu_fixed_is_weak false 31462306a36Sopenharmony_ci#endif 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ciextern const struct dma_map_ops dma_iommu_ops; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci#endif /* __KERNEL__ */ 31962306a36Sopenharmony_ci#endif /* _ASM_IOMMU_H */ 320