iommu: Introduce new 'struct iommu_device'
This struct represents one hardware iommu in the iommu core code. For now it only has the iommu-ops associated with it, but that will be extended soon. The register/unregister interface is also added, as well as making use of it in the Intel and AMD IOMMU drivers. Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
c09e22d537
commit
b0119e8708
|
@ -112,7 +112,7 @@ static struct timer_list queue_timer;
|
||||||
* Domain for untranslated devices - only allocated
|
* Domain for untranslated devices - only allocated
|
||||||
* if iommu=pt passed on kernel cmd line.
|
* if iommu=pt passed on kernel cmd line.
|
||||||
*/
|
*/
|
||||||
static const struct iommu_ops amd_iommu_ops;
|
const struct iommu_ops amd_iommu_ops;
|
||||||
|
|
||||||
static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
|
static ATOMIC_NOTIFIER_HEAD(ppr_notifier);
|
||||||
int amd_iommu_max_glx_val = -1;
|
int amd_iommu_max_glx_val = -1;
|
||||||
|
@ -3217,7 +3217,7 @@ static void amd_iommu_apply_dm_region(struct device *dev,
|
||||||
WARN_ON_ONCE(reserve_iova(&dma_dom->iovad, start, end) == NULL);
|
WARN_ON_ONCE(reserve_iova(&dma_dom->iovad, start, end) == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct iommu_ops amd_iommu_ops = {
|
const struct iommu_ops amd_iommu_ops = {
|
||||||
.capable = amd_iommu_capable,
|
.capable = amd_iommu_capable,
|
||||||
.domain_alloc = amd_iommu_domain_alloc,
|
.domain_alloc = amd_iommu_domain_alloc,
|
||||||
.domain_free = amd_iommu_domain_free,
|
.domain_free = amd_iommu_domain_free,
|
||||||
|
|
|
@ -94,6 +94,8 @@
|
||||||
* out of it.
|
* out of it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
extern const struct iommu_ops amd_iommu_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* structure describing one IOMMU in the ACPI table. Typically followed by one
|
* structure describing one IOMMU in the ACPI table. Typically followed by one
|
||||||
* or more ivhd_entrys.
|
* or more ivhd_entrys.
|
||||||
|
@ -1639,6 +1641,9 @@ static int iommu_init_pci(struct amd_iommu *iommu)
|
||||||
amd_iommu_groups, "ivhd%d",
|
amd_iommu_groups, "ivhd%d",
|
||||||
iommu->index);
|
iommu->index);
|
||||||
|
|
||||||
|
iommu_device_set_ops(&iommu->iommu, &amd_iommu_ops);
|
||||||
|
iommu_device_register(&iommu->iommu);
|
||||||
|
|
||||||
return pci_enable_device(iommu->dev);
|
return pci_enable_device(iommu->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -538,6 +538,9 @@ struct amd_iommu {
|
||||||
/* IOMMU sysfs device */
|
/* IOMMU sysfs device */
|
||||||
struct device *iommu_dev;
|
struct device *iommu_dev;
|
||||||
|
|
||||||
|
/* Handle for IOMMU core code */
|
||||||
|
struct iommu_device iommu;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't rely on the BIOS to restore all values on reinit, so we
|
* We can't rely on the BIOS to restore all values on reinit, so we
|
||||||
* need to stash them
|
* need to stash them
|
||||||
|
|
|
@ -74,6 +74,8 @@ static unsigned long dmar_seq_ids[BITS_TO_LONGS(DMAR_UNITS_SUPPORTED)];
|
||||||
static int alloc_iommu(struct dmar_drhd_unit *drhd);
|
static int alloc_iommu(struct dmar_drhd_unit *drhd);
|
||||||
static void free_iommu(struct intel_iommu *iommu);
|
static void free_iommu(struct intel_iommu *iommu);
|
||||||
|
|
||||||
|
extern const struct iommu_ops intel_iommu_ops;
|
||||||
|
|
||||||
static void dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
|
static void dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -1084,6 +1086,12 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd)
|
||||||
err = PTR_ERR(iommu->iommu_dev);
|
err = PTR_ERR(iommu->iommu_dev);
|
||||||
goto err_unmap;
|
goto err_unmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops);
|
||||||
|
|
||||||
|
err = iommu_device_register(&iommu->iommu);
|
||||||
|
if (err)
|
||||||
|
goto err_unmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
drhd->iommu = iommu;
|
drhd->iommu = iommu;
|
||||||
|
@ -1102,6 +1110,7 @@ error:
|
||||||
static void free_iommu(struct intel_iommu *iommu)
|
static void free_iommu(struct intel_iommu *iommu)
|
||||||
{
|
{
|
||||||
iommu_device_destroy(iommu->iommu_dev);
|
iommu_device_destroy(iommu->iommu_dev);
|
||||||
|
iommu_device_unregister(&iommu->iommu);
|
||||||
|
|
||||||
if (iommu->irq) {
|
if (iommu->irq) {
|
||||||
if (iommu->pr_irq) {
|
if (iommu->pr_irq) {
|
||||||
|
|
|
@ -547,7 +547,7 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
|
||||||
static DEFINE_SPINLOCK(device_domain_lock);
|
static DEFINE_SPINLOCK(device_domain_lock);
|
||||||
static LIST_HEAD(device_domain_list);
|
static LIST_HEAD(device_domain_list);
|
||||||
|
|
||||||
static const struct iommu_ops intel_iommu_ops;
|
const struct iommu_ops intel_iommu_ops;
|
||||||
|
|
||||||
static bool translation_pre_enabled(struct intel_iommu *iommu)
|
static bool translation_pre_enabled(struct intel_iommu *iommu)
|
||||||
{
|
{
|
||||||
|
@ -5292,7 +5292,7 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_INTEL_IOMMU_SVM */
|
#endif /* CONFIG_INTEL_IOMMU_SVM */
|
||||||
|
|
||||||
static const struct iommu_ops intel_iommu_ops = {
|
const struct iommu_ops intel_iommu_ops = {
|
||||||
.capable = intel_iommu_capable,
|
.capable = intel_iommu_capable,
|
||||||
.domain_alloc = intel_iommu_domain_alloc,
|
.domain_alloc = intel_iommu_domain_alloc,
|
||||||
.domain_free = intel_iommu_domain_free,
|
.domain_free = intel_iommu_domain_free,
|
||||||
|
|
|
@ -77,6 +77,25 @@ struct iommu_group_attribute iommu_group_attr_##_name = \
|
||||||
#define to_iommu_group(_kobj) \
|
#define to_iommu_group(_kobj) \
|
||||||
container_of(_kobj, struct iommu_group, kobj)
|
container_of(_kobj, struct iommu_group, kobj)
|
||||||
|
|
||||||
|
static LIST_HEAD(iommu_device_list);
|
||||||
|
static DEFINE_SPINLOCK(iommu_device_lock);
|
||||||
|
|
||||||
|
int iommu_device_register(struct iommu_device *iommu)
|
||||||
|
{
|
||||||
|
spin_lock(&iommu_device_lock);
|
||||||
|
list_add_tail(&iommu->list, &iommu_device_list);
|
||||||
|
spin_unlock(&iommu_device_lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iommu_device_unregister(struct iommu_device *iommu)
|
||||||
|
{
|
||||||
|
spin_lock(&iommu_device_lock);
|
||||||
|
list_del(&iommu->list);
|
||||||
|
spin_unlock(&iommu_device_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
|
static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
|
||||||
unsigned type);
|
unsigned type);
|
||||||
static int __iommu_attach_device(struct iommu_domain *domain,
|
static int __iommu_attach_device(struct iommu_domain *domain,
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <linux/dma_remapping.h>
|
#include <linux/dma_remapping.h>
|
||||||
#include <linux/mmu_notifier.h>
|
#include <linux/mmu_notifier.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/iommu.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/iommu.h>
|
#include <asm/iommu.h>
|
||||||
|
|
||||||
|
@ -440,6 +441,7 @@ struct intel_iommu {
|
||||||
struct irq_domain *ir_msi_domain;
|
struct irq_domain *ir_msi_domain;
|
||||||
#endif
|
#endif
|
||||||
struct device *iommu_dev; /* IOMMU-sysfs device */
|
struct device *iommu_dev; /* IOMMU-sysfs device */
|
||||||
|
struct iommu_device iommu; /* IOMMU core code handle */
|
||||||
int node;
|
int node;
|
||||||
u32 flags; /* Software defined flags */
|
u32 flags; /* Software defined flags */
|
||||||
};
|
};
|
||||||
|
|
|
@ -204,6 +204,26 @@ struct iommu_ops {
|
||||||
unsigned long pgsize_bitmap;
|
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
|
||||||
|
*/
|
||||||
|
struct iommu_device {
|
||||||
|
struct list_head list;
|
||||||
|
const struct iommu_ops *ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
int iommu_device_register(struct iommu_device *iommu);
|
||||||
|
void iommu_device_unregister(struct iommu_device *iommu);
|
||||||
|
|
||||||
|
static inline void iommu_device_set_ops(struct iommu_device *iommu,
|
||||||
|
const struct iommu_ops *ops)
|
||||||
|
{
|
||||||
|
iommu->ops = ops;
|
||||||
|
}
|
||||||
|
|
||||||
#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */
|
#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */
|
||||||
#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */
|
#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */
|
||||||
#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */
|
#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */
|
||||||
|
@ -361,6 +381,7 @@ const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode);
|
||||||
struct iommu_ops {};
|
struct iommu_ops {};
|
||||||
struct iommu_group {};
|
struct iommu_group {};
|
||||||
struct iommu_fwspec {};
|
struct iommu_fwspec {};
|
||||||
|
struct iommu_device {};
|
||||||
|
|
||||||
static inline bool iommu_present(struct bus_type *bus)
|
static inline bool iommu_present(struct bus_type *bus)
|
||||||
{
|
{
|
||||||
|
@ -558,6 +579,20 @@ static inline void iommu_device_destroy(struct device *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int iommu_device_register(struct iommu_device *iommu)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void iommu_device_set_ops(struct iommu_device *iommu,
|
||||||
|
const struct iommu_ops *ops)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void iommu_device_unregister(struct iommu_device *iommu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline int iommu_device_link(struct device *dev, struct device *link)
|
static inline int iommu_device_link(struct device *dev, struct device *link)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
Loading…
Reference in a new issue