mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
Merge tag 'iommu-updates-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU UPDATES from Joerg Roedel: - KVM PCIe/MSI passthrough support on ARM/ARM64 - introduction of a core representation for individual hardware iommus - support for IOMMU privileged mappings as supported by some ARM IOMMUS - 16-bit SID support for ARM-SMMUv2 - stream table optimization for ARM-SMMUv3 - various fixes and other small improvements * tag 'iommu-updates-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (61 commits) vfio/type1: Fix error return code in vfio_iommu_type1_attach_group() iommu: Remove iommu_register_instance interface iommu/exynos: Make use of iommu_device_register interface iommu/mediatek: Make use of iommu_device_register interface iommu/msm: Make use of iommu_device_register interface iommu/arm-smmu: Make use of the iommu_register interface iommu: Add iommu_device_set_fwnode() interface iommu: Make iommu_device_link/unlink take a struct iommu_device iommu: Add sysfs bindings for struct iommu_device iommu: Introduce new 'struct iommu_device' iommu: Rename struct iommu_device iommu: Rename iommu_get_instance() iommu: Fix static checker warning in iommu_insert_device_resv_regions iommu: Avoid unnecessary assignment of dev->iommu_fwspec iommu/mediatek: Remove bogus 'select' statements iommu/dma: Remove bogus dma_supported() implementation iommu/ipmmu-vmsa: Restrict IOMMU Domain Geometry to 32-bit address space iommu/vt-d: Don't over-free page table directories iommu/vt-d: Tylersburg isoch identity map check is done too late. iommu/vt-d: Fix some macros that are incorrectly specified in intel-iommu ...
This commit is contained in:
@@ -27,6 +27,7 @@ int iommu_dma_init(void);
|
||||
|
||||
/* Domain management interface for IOMMU drivers */
|
||||
int iommu_get_dma_cookie(struct iommu_domain *domain);
|
||||
int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base);
|
||||
void iommu_put_dma_cookie(struct iommu_domain *domain);
|
||||
|
||||
/* Setup call for arch DMA mapping code */
|
||||
@@ -34,7 +35,8 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
|
||||
u64 size, struct device *dev);
|
||||
|
||||
/* General helpers for DMA-API <-> IOMMU-API interaction */
|
||||
int dma_direction_to_prot(enum dma_data_direction dir, bool coherent);
|
||||
int dma_info_to_prot(enum dma_data_direction dir, bool coherent,
|
||||
unsigned long attrs);
|
||||
|
||||
/*
|
||||
* These implement the bulk of the relevant DMA mapping callbacks, but require
|
||||
@@ -65,7 +67,6 @@ dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs);
|
||||
void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs);
|
||||
int iommu_dma_supported(struct device *dev, u64 mask);
|
||||
int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
|
||||
|
||||
/* The DMA API isn't _quite_ the whole story, though... */
|
||||
@@ -86,6 +87,11 @@ static inline int iommu_get_dma_cookie(struct iommu_domain *domain)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void iommu_put_dma_cookie(struct iommu_domain *domain)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -62,6 +62,13 @@
|
||||
*/
|
||||
#define DMA_ATTR_NO_WARN (1UL << 8)
|
||||
|
||||
/*
|
||||
* DMA_ATTR_PRIVILEGED: used to indicate that the buffer is fully
|
||||
* accessible at an elevated privilege level (and ideally inaccessible or
|
||||
* at least read-only at lesser-privileged levels).
|
||||
*/
|
||||
#define DMA_ATTR_PRIVILEGED (1UL << 9)
|
||||
|
||||
/*
|
||||
* A dma_addr_t can hold any valid DMA or bus address for the platform.
|
||||
* It can be given to a device to use as a DMA source or target. A CPU cannot
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/dma_remapping.h>
|
||||
#include <linux/mmu_notifier.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/iommu.h>
|
||||
|
||||
@@ -153,8 +154,8 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
|
||||
#define DMA_TLB_GLOBAL_FLUSH (((u64)1) << 60)
|
||||
#define DMA_TLB_DSI_FLUSH (((u64)2) << 60)
|
||||
#define DMA_TLB_PSI_FLUSH (((u64)3) << 60)
|
||||
#define DMA_TLB_IIRG(type) ((type >> 60) & 7)
|
||||
#define DMA_TLB_IAIG(val) (((val) >> 57) & 7)
|
||||
#define DMA_TLB_IIRG(type) ((type >> 60) & 3)
|
||||
#define DMA_TLB_IAIG(val) (((val) >> 57) & 3)
|
||||
#define DMA_TLB_READ_DRAIN (((u64)1) << 49)
|
||||
#define DMA_TLB_WRITE_DRAIN (((u64)1) << 48)
|
||||
#define DMA_TLB_DID(id) (((u64)((id) & 0xffff)) << 32)
|
||||
@@ -164,9 +165,9 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
|
||||
|
||||
/* INVALID_DESC */
|
||||
#define DMA_CCMD_INVL_GRANU_OFFSET 61
|
||||
#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 3)
|
||||
#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 3)
|
||||
#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 3)
|
||||
#define DMA_ID_TLB_GLOBAL_FLUSH (((u64)1) << 4)
|
||||
#define DMA_ID_TLB_DSI_FLUSH (((u64)2) << 4)
|
||||
#define DMA_ID_TLB_PSI_FLUSH (((u64)3) << 4)
|
||||
#define DMA_ID_TLB_READ_DRAIN (((u64)1) << 7)
|
||||
#define DMA_ID_TLB_WRITE_DRAIN (((u64)1) << 6)
|
||||
#define DMA_ID_TLB_DID(id) (((u64)((id & 0xffff) << 16)))
|
||||
@@ -316,8 +317,8 @@ enum {
|
||||
#define QI_DEV_EIOTLB_SIZE (((u64)1) << 11)
|
||||
#define QI_DEV_EIOTLB_GLOB(g) ((u64)g)
|
||||
#define QI_DEV_EIOTLB_PASID(p) (((u64)p) << 32)
|
||||
#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 32)
|
||||
#define QI_DEV_EIOTLB_QDEP(qd) (((qd) & 0x1f) << 16)
|
||||
#define QI_DEV_EIOTLB_SID(sid) ((u64)((sid) & 0xffff) << 16)
|
||||
#define QI_DEV_EIOTLB_QDEP(qd) ((u64)((qd) & 0x1f) << 4)
|
||||
#define QI_DEV_EIOTLB_MAX_INVS 32
|
||||
|
||||
#define QI_PGRP_IDX(idx) (((u64)(idx)) << 55)
|
||||
@@ -439,7 +440,7 @@ struct intel_iommu {
|
||||
struct irq_domain *ir_domain;
|
||||
struct irq_domain *ir_msi_domain;
|
||||
#endif
|
||||
struct device *iommu_dev; /* IOMMU-sysfs device */
|
||||
struct iommu_device iommu; /* IOMMU core code handle */
|
||||
int node;
|
||||
u32 flags; /* Software defined flags */
|
||||
};
|
||||
|
||||
@@ -31,6 +31,13 @@
|
||||
#define IOMMU_CACHE (1 << 2) /* DMA cache coherency */
|
||||
#define IOMMU_NOEXEC (1 << 3)
|
||||
#define IOMMU_MMIO (1 << 4) /* e.g. things like MSI doorbells */
|
||||
/*
|
||||
* This is to make the IOMMU API setup privileged
|
||||
* mapppings accessible by the master only at higher
|
||||
* privileged execution level and inaccessible at
|
||||
* less privileged levels.
|
||||
*/
|
||||
#define IOMMU_PRIV (1 << 5)
|
||||
|
||||
struct iommu_ops;
|
||||
struct iommu_group;
|
||||
@@ -117,18 +124,25 @@ enum iommu_attr {
|
||||
DOMAIN_ATTR_MAX,
|
||||
};
|
||||
|
||||
/* These are the possible reserved region types */
|
||||
#define IOMMU_RESV_DIRECT (1 << 0)
|
||||
#define IOMMU_RESV_RESERVED (1 << 1)
|
||||
#define IOMMU_RESV_MSI (1 << 2)
|
||||
|
||||
/**
|
||||
* struct iommu_dm_region - descriptor for a direct mapped memory region
|
||||
* struct iommu_resv_region - descriptor for a reserved memory region
|
||||
* @list: Linked list pointers
|
||||
* @start: System physical start address of the region
|
||||
* @length: Length of the region in bytes
|
||||
* @prot: IOMMU Protection flags (READ/WRITE/...)
|
||||
* @type: Type of the reserved region
|
||||
*/
|
||||
struct iommu_dm_region {
|
||||
struct iommu_resv_region {
|
||||
struct list_head list;
|
||||
phys_addr_t start;
|
||||
size_t length;
|
||||
int prot;
|
||||
int type;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
@@ -150,9 +164,9 @@ struct iommu_dm_region {
|
||||
* @device_group: find iommu group for a particular device
|
||||
* @domain_get_attr: Query domain attributes
|
||||
* @domain_set_attr: Change domain attributes
|
||||
* @get_dm_regions: Request list of direct mapping requirements for a device
|
||||
* @put_dm_regions: Free list of direct mapping requirements for a device
|
||||
* @apply_dm_region: Temporary helper call-back for iova reserved ranges
|
||||
* @get_resv_regions: Request list of reserved regions for a device
|
||||
* @put_resv_regions: Free list of reserved regions for a device
|
||||
* @apply_resv_region: Temporary helper call-back for iova reserved ranges
|
||||
* @domain_window_enable: Configure and enable a particular window for a domain
|
||||
* @domain_window_disable: Disable a particular window for a domain
|
||||
* @domain_set_windows: Set the number of windows for a domain
|
||||
@@ -184,11 +198,12 @@ struct iommu_ops {
|
||||
int (*domain_set_attr)(struct iommu_domain *domain,
|
||||
enum iommu_attr attr, void *data);
|
||||
|
||||
/* Request/Free a list of direct mapping requirements for a device */
|
||||
void (*get_dm_regions)(struct device *dev, struct list_head *list);
|
||||
void (*put_dm_regions)(struct device *dev, struct list_head *list);
|
||||
void (*apply_dm_region)(struct device *dev, struct iommu_domain *domain,
|
||||
struct iommu_dm_region *region);
|
||||
/* Request/Free a list of reserved regions for a device */
|
||||
void (*get_resv_regions)(struct device *dev, struct list_head *list);
|
||||
void (*put_resv_regions)(struct device *dev, struct list_head *list);
|
||||
void (*apply_resv_region)(struct device *dev,
|
||||
struct iommu_domain *domain,
|
||||
struct iommu_resv_region *region);
|
||||
|
||||
/* Window handling functions */
|
||||
int (*domain_window_enable)(struct iommu_domain *domain, u32 wnd_nr,
|
||||
@@ -204,6 +219,42 @@ struct iommu_ops {
|
||||
unsigned long pgsize_bitmap;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iommu_device - IOMMU core representation of one IOMMU hardware
|
||||
* instance
|
||||
* @list: Used by the iommu-core to keep a list of registered iommus
|
||||
* @ops: iommu-ops for talking to this iommu
|
||||
* @dev: struct device for sysfs handling
|
||||
*/
|
||||
struct iommu_device {
|
||||
struct list_head list;
|
||||
const struct iommu_ops *ops;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
int iommu_device_register(struct iommu_device *iommu);
|
||||
void iommu_device_unregister(struct iommu_device *iommu);
|
||||
int iommu_device_sysfs_add(struct iommu_device *iommu,
|
||||
struct device *parent,
|
||||
const struct attribute_group **groups,
|
||||
const char *fmt, ...) __printf(4, 5);
|
||||
void iommu_device_sysfs_remove(struct iommu_device *iommu);
|
||||
int iommu_device_link(struct iommu_device *iommu, struct device *link);
|
||||
void iommu_device_unlink(struct iommu_device *iommu, struct device *link);
|
||||
|
||||
static inline void iommu_device_set_ops(struct iommu_device *iommu,
|
||||
const struct iommu_ops *ops)
|
||||
{
|
||||
iommu->ops = ops;
|
||||
}
|
||||
|
||||
static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
iommu->fwnode = fwnode;
|
||||
}
|
||||
|
||||
#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */
|
||||
#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */
|
||||
#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */
|
||||
@@ -233,9 +284,13 @@ extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t io
|
||||
extern void iommu_set_fault_handler(struct iommu_domain *domain,
|
||||
iommu_fault_handler_t handler, void *token);
|
||||
|
||||
extern void iommu_get_dm_regions(struct device *dev, struct list_head *list);
|
||||
extern void iommu_put_dm_regions(struct device *dev, struct list_head *list);
|
||||
extern void iommu_get_resv_regions(struct device *dev, struct list_head *list);
|
||||
extern void iommu_put_resv_regions(struct device *dev, struct list_head *list);
|
||||
extern int iommu_request_dm_for_dev(struct device *dev);
|
||||
extern struct iommu_resv_region *
|
||||
iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot, int type);
|
||||
extern int iommu_get_group_resv_regions(struct iommu_group *group,
|
||||
struct list_head *head);
|
||||
|
||||
extern int iommu_attach_group(struct iommu_domain *domain,
|
||||
struct iommu_group *group);
|
||||
@@ -267,12 +322,6 @@ extern int iommu_domain_get_attr(struct iommu_domain *domain, enum iommu_attr,
|
||||
void *data);
|
||||
extern int iommu_domain_set_attr(struct iommu_domain *domain, enum iommu_attr,
|
||||
void *data);
|
||||
struct device *iommu_device_create(struct device *parent, void *drvdata,
|
||||
const struct attribute_group **groups,
|
||||
const char *fmt, ...) __printf(4, 5);
|
||||
void iommu_device_destroy(struct device *dev);
|
||||
int iommu_device_link(struct device *dev, struct device *link);
|
||||
void iommu_device_unlink(struct device *dev, struct device *link);
|
||||
|
||||
/* Window handling function prototypes */
|
||||
extern int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
|
||||
@@ -352,15 +401,14 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
|
||||
const struct iommu_ops *ops);
|
||||
void iommu_fwspec_free(struct device *dev);
|
||||
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids);
|
||||
void iommu_register_instance(struct fwnode_handle *fwnode,
|
||||
const struct iommu_ops *ops);
|
||||
const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode);
|
||||
const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode);
|
||||
|
||||
#else /* CONFIG_IOMMU_API */
|
||||
|
||||
struct iommu_ops {};
|
||||
struct iommu_group {};
|
||||
struct iommu_fwspec {};
|
||||
struct iommu_device {};
|
||||
|
||||
static inline bool iommu_present(struct bus_type *bus)
|
||||
{
|
||||
@@ -443,16 +491,22 @@ static inline void iommu_set_fault_handler(struct iommu_domain *domain,
|
||||
{
|
||||
}
|
||||
|
||||
static inline void iommu_get_dm_regions(struct device *dev,
|
||||
static inline void iommu_get_resv_regions(struct device *dev,
|
||||
struct list_head *list)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void iommu_put_dm_regions(struct device *dev,
|
||||
static inline void iommu_put_resv_regions(struct device *dev,
|
||||
struct list_head *list)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int iommu_get_group_resv_regions(struct iommu_group *group,
|
||||
struct list_head *head)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int iommu_request_dm_for_dev(struct device *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
@@ -546,15 +600,34 @@ static inline int iommu_domain_set_attr(struct iommu_domain *domain,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline struct device *iommu_device_create(struct device *parent,
|
||||
void *drvdata,
|
||||
const struct attribute_group **groups,
|
||||
const char *fmt, ...)
|
||||
static inline int iommu_device_register(struct iommu_device *iommu)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void iommu_device_destroy(struct device *dev)
|
||||
static inline void iommu_device_set_ops(struct iommu_device *iommu,
|
||||
const struct iommu_ops *ops)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void iommu_device_unregister(struct iommu_device *iommu)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int iommu_device_sysfs_add(struct iommu_device *iommu,
|
||||
struct device *parent,
|
||||
const struct attribute_group **groups,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void iommu_device_sysfs_remove(struct iommu_device *iommu)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -584,13 +657,8 @@ static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void iommu_register_instance(struct fwnode_handle *fwnode,
|
||||
const struct iommu_ops *ops)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode)
|
||||
const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -183,6 +183,12 @@ enum {
|
||||
/* Irq domain is an IPI domain with single virq */
|
||||
IRQ_DOMAIN_FLAG_IPI_SINGLE = (1 << 3),
|
||||
|
||||
/* Irq domain implements MSIs */
|
||||
IRQ_DOMAIN_FLAG_MSI = (1 << 4),
|
||||
|
||||
/* Irq domain implements MSI remapping */
|
||||
IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 5),
|
||||
|
||||
/*
|
||||
* Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
|
||||
* for implementation specific purposes and ignored by the
|
||||
@@ -216,6 +222,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
|
||||
void *host_data);
|
||||
extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
|
||||
enum irq_domain_bus_token bus_token);
|
||||
extern bool irq_domain_check_msi_remap(void);
|
||||
extern void irq_set_default_host(struct irq_domain *host);
|
||||
extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
|
||||
irq_hw_number_t hwirq, int node,
|
||||
@@ -446,6 +453,19 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
|
||||
{
|
||||
return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE;
|
||||
}
|
||||
|
||||
static inline bool irq_domain_is_msi(struct irq_domain *domain)
|
||||
{
|
||||
return domain->flags & IRQ_DOMAIN_FLAG_MSI;
|
||||
}
|
||||
|
||||
static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
|
||||
{
|
||||
return domain->flags & IRQ_DOMAIN_FLAG_MSI_REMAP;
|
||||
}
|
||||
|
||||
extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain);
|
||||
|
||||
#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
|
||||
static inline void irq_domain_activate_irq(struct irq_data *data) { }
|
||||
static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
|
||||
@@ -477,6 +497,22 @@ static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool irq_domain_is_msi(struct irq_domain *domain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
|
||||
|
||||
#else /* CONFIG_IRQ_DOMAIN */
|
||||
|
||||
@@ -31,17 +31,6 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev,
|
||||
|
||||
#endif /* CONFIG_OF_IOMMU */
|
||||
|
||||
static inline void of_iommu_set_ops(struct device_node *np,
|
||||
const struct iommu_ops *ops)
|
||||
{
|
||||
iommu_register_instance(&np->fwnode, ops);
|
||||
}
|
||||
|
||||
static inline const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
|
||||
{
|
||||
return iommu_get_instance(&np->fwnode);
|
||||
}
|
||||
|
||||
extern struct of_device_id __iommu_of_table;
|
||||
|
||||
typedef int (*of_iommu_init_fn)(struct device_node *);
|
||||
|
||||
Reference in New Issue
Block a user