13d0407baSopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * Copyright (c) 2006, Intel Corporation. 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (C) 2006-2008 Intel Corporation 63d0407baSopenharmony_ci * Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> 73d0407baSopenharmony_ci */ 83d0407baSopenharmony_ci 93d0407baSopenharmony_ci#ifndef _IOVA_H_ 103d0407baSopenharmony_ci#define _IOVA_H_ 113d0407baSopenharmony_ci 123d0407baSopenharmony_ci#include <linux/types.h> 133d0407baSopenharmony_ci#include <linux/kernel.h> 143d0407baSopenharmony_ci#include <linux/rbtree.h> 153d0407baSopenharmony_ci#include <linux/atomic.h> 163d0407baSopenharmony_ci#include <linux/dma-mapping.h> 173d0407baSopenharmony_ci 183d0407baSopenharmony_ci/* iova structure */ 193d0407baSopenharmony_cistruct iova { 203d0407baSopenharmony_ci struct rb_node node; 213d0407baSopenharmony_ci unsigned long pfn_hi; /* Highest allocated pfn */ 223d0407baSopenharmony_ci unsigned long pfn_lo; /* Lowest allocated pfn */ 233d0407baSopenharmony_ci}; 243d0407baSopenharmony_ci 253d0407baSopenharmony_cistruct iova_magazine; 263d0407baSopenharmony_cistruct iova_cpu_rcache; 273d0407baSopenharmony_ci 283d0407baSopenharmony_ci#define IOVA_RANGE_CACHE_MAX_SIZE 6 /* log of max cached IOVA range size (in pages) */ 293d0407baSopenharmony_ci#define MAX_GLOBAL_MAGS 32 /* magazines per bin */ 303d0407baSopenharmony_ci 313d0407baSopenharmony_cistruct iova_rcache { 323d0407baSopenharmony_ci spinlock_t lock; 333d0407baSopenharmony_ci unsigned long depot_size; 343d0407baSopenharmony_ci struct iova_magazine *depot[MAX_GLOBAL_MAGS]; 353d0407baSopenharmony_ci struct iova_cpu_rcache __percpu *cpu_rcaches; 363d0407baSopenharmony_ci}; 373d0407baSopenharmony_ci 383d0407baSopenharmony_cistruct iova_domain; 393d0407baSopenharmony_ci 403d0407baSopenharmony_ci/* Call-Back from IOVA code into IOMMU drivers */ 413d0407baSopenharmony_citypedef void (*iova_flush_cb)(struct iova_domain *domain); 423d0407baSopenharmony_ci 433d0407baSopenharmony_ci/* Destructor for per-entry data */ 443d0407baSopenharmony_citypedef void (*iova_entry_dtor)(unsigned long data); 453d0407baSopenharmony_ci 463d0407baSopenharmony_ci/* Number of entries per Flush Queue */ 473d0407baSopenharmony_ci#define IOVA_FQ_SIZE 256 483d0407baSopenharmony_ci 493d0407baSopenharmony_ci/* Timeout (in ms) after which entries are flushed from the Flush-Queue */ 503d0407baSopenharmony_ci#define IOVA_FQ_TIMEOUT 10 513d0407baSopenharmony_ci 523d0407baSopenharmony_ci/* Flush Queue entry for defered flushing */ 533d0407baSopenharmony_cistruct iova_fq_entry { 543d0407baSopenharmony_ci unsigned long iova_pfn; 553d0407baSopenharmony_ci unsigned long pages; 563d0407baSopenharmony_ci unsigned long data; 573d0407baSopenharmony_ci u64 counter; /* Flush counter when this entrie was added */ 583d0407baSopenharmony_ci}; 593d0407baSopenharmony_ci 603d0407baSopenharmony_ci/* Per-CPU Flush Queue structure */ 613d0407baSopenharmony_cistruct iova_fq { 623d0407baSopenharmony_ci struct iova_fq_entry entries[IOVA_FQ_SIZE]; 633d0407baSopenharmony_ci unsigned head, tail; 643d0407baSopenharmony_ci spinlock_t lock; 653d0407baSopenharmony_ci}; 663d0407baSopenharmony_ci 673d0407baSopenharmony_ci/* holds all the iova translations for a domain */ 683d0407baSopenharmony_cistruct iova_domain { 693d0407baSopenharmony_ci spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree */ 703d0407baSopenharmony_ci struct rb_root rbroot; /* iova domain rbtree root */ 713d0407baSopenharmony_ci struct rb_node *cached_node; /* Save last alloced node */ 723d0407baSopenharmony_ci struct rb_node *cached32_node; /* Save last 32-bit alloced node */ 733d0407baSopenharmony_ci unsigned long granule; /* pfn granularity for this domain */ 743d0407baSopenharmony_ci unsigned long start_pfn; /* Lower limit for this domain */ 753d0407baSopenharmony_ci unsigned long dma_32bit_pfn; 763d0407baSopenharmony_ci unsigned long max32_alloc_size; /* Size of last failed allocation */ 773d0407baSopenharmony_ci struct iova_fq __percpu *fq; /* Flush Queue */ 783d0407baSopenharmony_ci 793d0407baSopenharmony_ci atomic64_t fq_flush_start_cnt; /* Number of TLB flushes that 803d0407baSopenharmony_ci have been started */ 813d0407baSopenharmony_ci 823d0407baSopenharmony_ci atomic64_t fq_flush_finish_cnt; /* Number of TLB flushes that 833d0407baSopenharmony_ci have been finished */ 843d0407baSopenharmony_ci 853d0407baSopenharmony_ci struct iova anchor; /* rbtree lookup anchor */ 863d0407baSopenharmony_ci struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE]; /* IOVA range caches */ 873d0407baSopenharmony_ci 883d0407baSopenharmony_ci iova_flush_cb flush_cb; /* Call-Back function to flush IOMMU 893d0407baSopenharmony_ci TLBs */ 903d0407baSopenharmony_ci 913d0407baSopenharmony_ci iova_entry_dtor entry_dtor; /* IOMMU driver specific destructor for 923d0407baSopenharmony_ci iova entry */ 933d0407baSopenharmony_ci 943d0407baSopenharmony_ci struct timer_list fq_timer; /* Timer to regularily empty the 953d0407baSopenharmony_ci flush-queues */ 963d0407baSopenharmony_ci atomic_t fq_timer_on; /* 1 when timer is active, 0 973d0407baSopenharmony_ci when not */ 983d0407baSopenharmony_ci bool best_fit; 993d0407baSopenharmony_ci}; 1003d0407baSopenharmony_ci 1013d0407baSopenharmony_cistatic inline unsigned long iova_size(struct iova *iova) 1023d0407baSopenharmony_ci{ 1033d0407baSopenharmony_ci return iova->pfn_hi - iova->pfn_lo + 1; 1043d0407baSopenharmony_ci} 1053d0407baSopenharmony_ci 1063d0407baSopenharmony_cistatic inline unsigned long iova_shift(struct iova_domain *iovad) 1073d0407baSopenharmony_ci{ 1083d0407baSopenharmony_ci return __ffs(iovad->granule); 1093d0407baSopenharmony_ci} 1103d0407baSopenharmony_ci 1113d0407baSopenharmony_cistatic inline unsigned long iova_mask(struct iova_domain *iovad) 1123d0407baSopenharmony_ci{ 1133d0407baSopenharmony_ci return iovad->granule - 1; 1143d0407baSopenharmony_ci} 1153d0407baSopenharmony_ci 1163d0407baSopenharmony_cistatic inline size_t iova_offset(struct iova_domain *iovad, dma_addr_t iova) 1173d0407baSopenharmony_ci{ 1183d0407baSopenharmony_ci return iova & iova_mask(iovad); 1193d0407baSopenharmony_ci} 1203d0407baSopenharmony_ci 1213d0407baSopenharmony_cistatic inline size_t iova_align(struct iova_domain *iovad, size_t size) 1223d0407baSopenharmony_ci{ 1233d0407baSopenharmony_ci return ALIGN(size, iovad->granule); 1243d0407baSopenharmony_ci} 1253d0407baSopenharmony_ci 1263d0407baSopenharmony_cistatic inline dma_addr_t iova_dma_addr(struct iova_domain *iovad, struct iova *iova) 1273d0407baSopenharmony_ci{ 1283d0407baSopenharmony_ci return (dma_addr_t)iova->pfn_lo << iova_shift(iovad); 1293d0407baSopenharmony_ci} 1303d0407baSopenharmony_ci 1313d0407baSopenharmony_cistatic inline unsigned long iova_pfn(struct iova_domain *iovad, dma_addr_t iova) 1323d0407baSopenharmony_ci{ 1333d0407baSopenharmony_ci return iova >> iova_shift(iovad); 1343d0407baSopenharmony_ci} 1353d0407baSopenharmony_ci 1363d0407baSopenharmony_ci#if IS_ENABLED(CONFIG_IOMMU_IOVA) 1373d0407baSopenharmony_ciint iova_cache_get(void); 1383d0407baSopenharmony_civoid iova_cache_put(void); 1393d0407baSopenharmony_ci 1403d0407baSopenharmony_cistruct iova *alloc_iova_mem(void); 1413d0407baSopenharmony_civoid free_iova_mem(struct iova *iova); 1423d0407baSopenharmony_civoid free_iova(struct iova_domain *iovad, unsigned long pfn); 1433d0407baSopenharmony_civoid __free_iova(struct iova_domain *iovad, struct iova *iova); 1443d0407baSopenharmony_cistruct iova *alloc_iova(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn, bool size_aligned); 1453d0407baSopenharmony_civoid free_iova_fast(struct iova_domain *iovad, unsigned long pfn, unsigned long size); 1463d0407baSopenharmony_civoid queue_iova(struct iova_domain *iovad, unsigned long pfn, unsigned long pages, unsigned long data); 1473d0407baSopenharmony_ciunsigned long alloc_iova_fast(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn, 1483d0407baSopenharmony_ci bool flush_rcache); 1493d0407baSopenharmony_cistruct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, unsigned long pfn_hi); 1503d0407baSopenharmony_civoid copy_reserved_iova(struct iova_domain *from, struct iova_domain *to); 1513d0407baSopenharmony_civoid init_iova_domain(struct iova_domain *iovad, unsigned long granule, unsigned long start_pfn); 1523d0407baSopenharmony_cibool has_iova_flush_queue(struct iova_domain *iovad); 1533d0407baSopenharmony_ciint init_iova_flush_queue(struct iova_domain *iovad, iova_flush_cb flush_cb, iova_entry_dtor entry_dtor); 1543d0407baSopenharmony_cistruct iova *find_iova(struct iova_domain *iovad, unsigned long pfn); 1553d0407baSopenharmony_civoid put_iova_domain(struct iova_domain *iovad); 1563d0407baSopenharmony_cistruct iova *split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, unsigned long pfn_lo, 1573d0407baSopenharmony_ci unsigned long pfn_hi); 1583d0407baSopenharmony_civoid free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad); 1593d0407baSopenharmony_ci#else 1603d0407baSopenharmony_cistatic inline int iova_cache_get(void) 1613d0407baSopenharmony_ci{ 1623d0407baSopenharmony_ci return -ENOTSUPP; 1633d0407baSopenharmony_ci} 1643d0407baSopenharmony_ci 1653d0407baSopenharmony_cistatic inline void iova_cache_put(void) 1663d0407baSopenharmony_ci{ 1673d0407baSopenharmony_ci} 1683d0407baSopenharmony_ci 1693d0407baSopenharmony_cistatic inline struct iova *alloc_iova_mem(void) 1703d0407baSopenharmony_ci{ 1713d0407baSopenharmony_ci return NULL; 1723d0407baSopenharmony_ci} 1733d0407baSopenharmony_ci 1743d0407baSopenharmony_cistatic inline void free_iova_mem(struct iova *iova) 1753d0407baSopenharmony_ci{ 1763d0407baSopenharmony_ci} 1773d0407baSopenharmony_ci 1783d0407baSopenharmony_cistatic inline void free_iova(struct iova_domain *iovad, unsigned long pfn) 1793d0407baSopenharmony_ci{ 1803d0407baSopenharmony_ci} 1813d0407baSopenharmony_ci 1823d0407baSopenharmony_cistatic inline void __free_iova(struct iova_domain *iovad, struct iova *iova) 1833d0407baSopenharmony_ci{ 1843d0407baSopenharmony_ci} 1853d0407baSopenharmony_ci 1863d0407baSopenharmony_cistatic inline struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn, 1873d0407baSopenharmony_ci bool size_aligned) 1883d0407baSopenharmony_ci{ 1893d0407baSopenharmony_ci return NULL; 1903d0407baSopenharmony_ci} 1913d0407baSopenharmony_ci 1923d0407baSopenharmony_cistatic inline void free_iova_fast(struct iova_domain *iovad, unsigned long pfn, unsigned long size) 1933d0407baSopenharmony_ci{ 1943d0407baSopenharmony_ci} 1953d0407baSopenharmony_ci 1963d0407baSopenharmony_cistatic inline void queue_iova(struct iova_domain *iovad, unsigned long pfn, unsigned long pages, unsigned long data) 1973d0407baSopenharmony_ci{ 1983d0407baSopenharmony_ci} 1993d0407baSopenharmony_ci 2003d0407baSopenharmony_cistatic inline unsigned long alloc_iova_fast(struct iova_domain *iovad, unsigned long size, unsigned long limit_pfn, 2013d0407baSopenharmony_ci bool flush_rcache) 2023d0407baSopenharmony_ci{ 2033d0407baSopenharmony_ci return 0; 2043d0407baSopenharmony_ci} 2053d0407baSopenharmony_ci 2063d0407baSopenharmony_cistatic inline struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, unsigned long pfn_hi) 2073d0407baSopenharmony_ci{ 2083d0407baSopenharmony_ci return NULL; 2093d0407baSopenharmony_ci} 2103d0407baSopenharmony_ci 2113d0407baSopenharmony_cistatic inline void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to) 2123d0407baSopenharmony_ci{ 2133d0407baSopenharmony_ci} 2143d0407baSopenharmony_ci 2153d0407baSopenharmony_cistatic inline void init_iova_domain(struct iova_domain *iovad, unsigned long granule, unsigned long start_pfn) 2163d0407baSopenharmony_ci{ 2173d0407baSopenharmony_ci} 2183d0407baSopenharmony_ci 2193d0407baSopenharmony_cistatic inline bool has_iova_flush_queue(struct iova_domain *iovad) 2203d0407baSopenharmony_ci{ 2213d0407baSopenharmony_ci return false; 2223d0407baSopenharmony_ci} 2233d0407baSopenharmony_ci 2243d0407baSopenharmony_cistatic inline int init_iova_flush_queue(struct iova_domain *iovad, iova_flush_cb flush_cb, iova_entry_dtor entry_dtor) 2253d0407baSopenharmony_ci{ 2263d0407baSopenharmony_ci return -ENODEV; 2273d0407baSopenharmony_ci} 2283d0407baSopenharmony_ci 2293d0407baSopenharmony_cistatic inline struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn) 2303d0407baSopenharmony_ci{ 2313d0407baSopenharmony_ci return NULL; 2323d0407baSopenharmony_ci} 2333d0407baSopenharmony_ci 2343d0407baSopenharmony_cistatic inline void put_iova_domain(struct iova_domain *iovad) 2353d0407baSopenharmony_ci{ 2363d0407baSopenharmony_ci} 2373d0407baSopenharmony_ci 2383d0407baSopenharmony_cistatic inline struct iova *split_and_remove_iova(struct iova_domain *iovad, struct iova *iova, unsigned long pfn_lo, 2393d0407baSopenharmony_ci unsigned long pfn_hi) 2403d0407baSopenharmony_ci{ 2413d0407baSopenharmony_ci return NULL; 2423d0407baSopenharmony_ci} 2433d0407baSopenharmony_ci 2443d0407baSopenharmony_cistatic inline void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad) 2453d0407baSopenharmony_ci{ 2463d0407baSopenharmony_ci} 2473d0407baSopenharmony_ci#endif 2483d0407baSopenharmony_ci 2493d0407baSopenharmony_ci#endif 250