Merge branches 'arm/exynos', 'arm/omap', 'arm/smmu', 'x86/vt-d', 'x86/amd' and 'core' into next
Conflicts: drivers/iommu/arm-smmu.c
This commit is contained in:
@@ -87,6 +87,27 @@ int amd_iommu_max_glx_val = -1;
|
||||
|
||||
static struct dma_map_ops amd_iommu_dma_ops;
|
||||
|
||||
/*
|
||||
* This struct contains device specific data for the IOMMU
|
||||
*/
|
||||
struct iommu_dev_data {
|
||||
struct list_head list; /* For domain->dev_list */
|
||||
struct list_head dev_data_list; /* For global dev_data_list */
|
||||
struct list_head alias_list; /* Link alias-groups together */
|
||||
struct iommu_dev_data *alias_data;/* The alias dev_data */
|
||||
struct protection_domain *domain; /* Domain the device is bound to */
|
||||
u16 devid; /* PCI Device ID */
|
||||
bool iommu_v2; /* Device can make use of IOMMUv2 */
|
||||
bool passthrough; /* Default for device is pt_domain */
|
||||
struct {
|
||||
bool enabled;
|
||||
int qdep;
|
||||
} ats; /* ATS state */
|
||||
bool pri_tlp; /* PASID TLB required for
|
||||
PPR completions */
|
||||
u32 errata; /* Bitmap for errata to apply */
|
||||
};
|
||||
|
||||
/*
|
||||
* general struct to manage commands send to an IOMMU
|
||||
*/
|
||||
@@ -114,8 +135,9 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid)
|
||||
if (!dev_data)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&dev_data->alias_list);
|
||||
|
||||
dev_data->devid = devid;
|
||||
atomic_set(&dev_data->bind, 0);
|
||||
|
||||
spin_lock_irqsave(&dev_data_list_lock, flags);
|
||||
list_add_tail(&dev_data->dev_data_list, &dev_data_list);
|
||||
@@ -260,17 +282,13 @@ static bool check_device(struct device *dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int init_iommu_group(struct device *dev)
|
||||
static void init_iommu_group(struct device *dev)
|
||||
{
|
||||
struct iommu_group *group;
|
||||
|
||||
group = iommu_group_get_for_dev(dev);
|
||||
|
||||
if (IS_ERR(group))
|
||||
return PTR_ERR(group);
|
||||
|
||||
iommu_group_put(group);
|
||||
return 0;
|
||||
if (!IS_ERR(group))
|
||||
iommu_group_put(group);
|
||||
}
|
||||
|
||||
static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
|
||||
@@ -340,7 +358,6 @@ static int iommu_init_device(struct device *dev)
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct iommu_dev_data *dev_data;
|
||||
u16 alias;
|
||||
int ret;
|
||||
|
||||
if (dev->archdata.iommu)
|
||||
return 0;
|
||||
@@ -362,12 +379,9 @@ static int iommu_init_device(struct device *dev)
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
dev_data->alias_data = alias_data;
|
||||
}
|
||||
|
||||
ret = init_iommu_group(dev);
|
||||
if (ret) {
|
||||
free_dev_data(dev_data);
|
||||
return ret;
|
||||
/* Add device to the alias_list */
|
||||
list_add(&dev_data->alias_list, &alias_data->alias_list);
|
||||
}
|
||||
|
||||
if (pci_iommuv2_capable(pdev)) {
|
||||
@@ -455,6 +469,15 @@ int __init amd_iommu_init_devices(void)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize IOMMU groups only after iommu_init_device() has
|
||||
* had a chance to populate any IVRS defined aliases.
|
||||
*/
|
||||
for_each_pci_dev(pdev) {
|
||||
if (check_device(&pdev->dev))
|
||||
init_iommu_group(&pdev->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
@@ -1368,6 +1391,9 @@ static int iommu_map_page(struct protection_domain *dom,
|
||||
count = PAGE_SIZE_PTE_COUNT(page_size);
|
||||
pte = alloc_pte(dom, bus_addr, page_size, NULL, GFP_KERNEL);
|
||||
|
||||
if (!pte)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
if (IOMMU_PTE_PRESENT(pte[i]))
|
||||
return -EBUSY;
|
||||
@@ -2122,35 +2148,29 @@ static void do_detach(struct iommu_dev_data *dev_data)
|
||||
static int __attach_device(struct iommu_dev_data *dev_data,
|
||||
struct protection_domain *domain)
|
||||
{
|
||||
struct iommu_dev_data *head, *entry;
|
||||
int ret;
|
||||
|
||||
/* lock domain */
|
||||
spin_lock(&domain->lock);
|
||||
|
||||
if (dev_data->alias_data != NULL) {
|
||||
struct iommu_dev_data *alias_data = dev_data->alias_data;
|
||||
head = dev_data;
|
||||
|
||||
/* Some sanity checks */
|
||||
ret = -EBUSY;
|
||||
if (alias_data->domain != NULL &&
|
||||
alias_data->domain != domain)
|
||||
goto out_unlock;
|
||||
if (head->alias_data != NULL)
|
||||
head = head->alias_data;
|
||||
|
||||
if (dev_data->domain != NULL &&
|
||||
dev_data->domain != domain)
|
||||
goto out_unlock;
|
||||
/* Now we have the root of the alias group, if any */
|
||||
|
||||
/* Do real assignment */
|
||||
if (alias_data->domain == NULL)
|
||||
do_attach(alias_data, domain);
|
||||
ret = -EBUSY;
|
||||
if (head->domain != NULL)
|
||||
goto out_unlock;
|
||||
|
||||
atomic_inc(&alias_data->bind);
|
||||
}
|
||||
/* Attach alias group root */
|
||||
do_attach(head, domain);
|
||||
|
||||
if (dev_data->domain == NULL)
|
||||
do_attach(dev_data, domain);
|
||||
|
||||
atomic_inc(&dev_data->bind);
|
||||
/* Attach other devices in the alias group */
|
||||
list_for_each_entry(entry, &head->alias_list, alias_list)
|
||||
do_attach(entry, domain);
|
||||
|
||||
ret = 0;
|
||||
|
||||
@@ -2298,6 +2318,7 @@ static int attach_device(struct device *dev,
|
||||
*/
|
||||
static void __detach_device(struct iommu_dev_data *dev_data)
|
||||
{
|
||||
struct iommu_dev_data *head, *entry;
|
||||
struct protection_domain *domain;
|
||||
unsigned long flags;
|
||||
|
||||
@@ -2307,15 +2328,14 @@ static void __detach_device(struct iommu_dev_data *dev_data)
|
||||
|
||||
spin_lock_irqsave(&domain->lock, flags);
|
||||
|
||||
if (dev_data->alias_data != NULL) {
|
||||
struct iommu_dev_data *alias_data = dev_data->alias_data;
|
||||
head = dev_data;
|
||||
if (head->alias_data != NULL)
|
||||
head = head->alias_data;
|
||||
|
||||
if (atomic_dec_and_test(&alias_data->bind))
|
||||
do_detach(alias_data);
|
||||
}
|
||||
list_for_each_entry(entry, &head->alias_list, alias_list)
|
||||
do_detach(entry);
|
||||
|
||||
if (atomic_dec_and_test(&dev_data->bind))
|
||||
do_detach(dev_data);
|
||||
do_detach(head);
|
||||
|
||||
spin_unlock_irqrestore(&domain->lock, flags);
|
||||
|
||||
@@ -2415,6 +2435,7 @@ static int device_change_notifier(struct notifier_block *nb,
|
||||
case BUS_NOTIFY_ADD_DEVICE:
|
||||
|
||||
iommu_init_device(dev);
|
||||
init_iommu_group(dev);
|
||||
|
||||
/*
|
||||
* dev_data is still NULL and
|
||||
@@ -3158,7 +3179,6 @@ static void cleanup_domain(struct protection_domain *domain)
|
||||
entry = list_first_entry(&domain->dev_list,
|
||||
struct iommu_dev_data, list);
|
||||
__detach_device(entry);
|
||||
atomic_set(&entry->bind, 0);
|
||||
}
|
||||
|
||||
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
|
||||
@@ -3384,20 +3404,20 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
|
||||
return paddr;
|
||||
}
|
||||
|
||||
static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
|
||||
unsigned long cap)
|
||||
static bool amd_iommu_capable(enum iommu_cap cap)
|
||||
{
|
||||
switch (cap) {
|
||||
case IOMMU_CAP_CACHE_COHERENCY:
|
||||
return 1;
|
||||
return true;
|
||||
case IOMMU_CAP_INTR_REMAP:
|
||||
return irq_remapping_enabled;
|
||||
return (irq_remapping_enabled == 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct iommu_ops amd_iommu_ops = {
|
||||
.capable = amd_iommu_capable,
|
||||
.domain_init = amd_iommu_domain_init,
|
||||
.domain_destroy = amd_iommu_domain_destroy,
|
||||
.attach_dev = amd_iommu_attach_device,
|
||||
@@ -3405,7 +3425,6 @@ static const struct iommu_ops amd_iommu_ops = {
|
||||
.map = amd_iommu_map,
|
||||
.unmap = amd_iommu_unmap,
|
||||
.iova_to_phys = amd_iommu_iova_to_phys,
|
||||
.domain_has_cap = amd_iommu_domain_has_cap,
|
||||
.pgsize_bitmap = AMD_IOMMU_PGSIZES,
|
||||
};
|
||||
|
||||
@@ -4235,7 +4254,7 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_hpet_msi(unsigned int irq, unsigned int id)
|
||||
static int alloc_hpet_msi(unsigned int irq, unsigned int id)
|
||||
{
|
||||
struct irq_2_irte *irte_info;
|
||||
struct irq_cfg *cfg;
|
||||
@@ -4274,6 +4293,6 @@ struct irq_remap_ops amd_iommu_irq_ops = {
|
||||
.compose_msi_msg = compose_msi_msg,
|
||||
.msi_alloc_irq = msi_alloc_irq,
|
||||
.msi_setup_irq = msi_setup_irq,
|
||||
.setup_hpet_msi = setup_hpet_msi,
|
||||
.alloc_hpet_msi = alloc_hpet_msi,
|
||||
};
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user