Skip to content

Commit

Permalink
Merge tag 'iommu-updates-v3.18' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/joro/iommu

Pull IOMMU updates from Joerg Roedel:
 "This pull-request includes:

   - change in the IOMMU-API to convert the former iommu_domain_capable
     function to just iommu_capable

   - various fixes in handling RMRR ranges for the VT-d driver (one fix
     requires a device driver core change which was acked by Greg KH)

   - the AMD IOMMU driver now assigns and deassigns complete alias
     groups to fix issues with devices using the wrong PCI request-id

   - MMU-401 support for the ARM SMMU driver

   - multi-master IOMMU group support for the ARM SMMU driver

   - various other small fixes all over the place"

* tag 'iommu-updates-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (41 commits)
  iommu/vt-d: Work around broken RMRR firmware entries
  iommu/vt-d: Store bus information in RMRR PCI device path
  iommu/vt-d: Only remove domain when device is removed
  driver core: Add BUS_NOTIFY_REMOVED_DEVICE event
  iommu/amd: Fix devid mapping for ivrs_ioapic override
  iommu/irq_remapping: Fix the regression of hpet irq remapping
  iommu: Fix bus notifier breakage
  iommu/amd: Split init_iommu_group() from iommu_init_device()
  iommu: Rework iommu_group_get_for_pci_dev()
  iommu: Make of_device_id array const
  amd_iommu: do not dereference a NULL pointer address.
  iommu/omap: Remove omap_iommu unused owner field
  iommu: Remove iommu_domain_has_cap() API function
  IB/usnic: Convert to use new iommu_capable() API function
  vfio: Convert to use new iommu_capable() API function
  kvm: iommu: Convert to use new iommu_capable() API function
  iommu/tegra: Convert to iommu_capable() API function
  iommu/msm: Convert to iommu_capable() API function
  iommu/vt-d: Convert to iommu_capable() API function
  iommu/fsl: Convert to iommu_capable() API function
  ...
  • Loading branch information
Linus Torvalds committed Oct 15, 2014
2 parents c0fa237 + 09b5269 commit 23971bd
Show file tree
Hide file tree
Showing 25 changed files with 461 additions and 356 deletions.
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/iommu/arm,smmu.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ conditions.
"arm,smmu-v1"
"arm,smmu-v2"
"arm,mmu-400"
"arm,mmu-401"
"arm,mmu-500"

depending on the particular implementation and/or the
Expand Down
3 changes: 3 additions & 0 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,9 @@ void device_del(struct device *dev)
*/
if (platform_notify_remove)
platform_notify_remove(dev);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_REMOVED_DEVICE, dev);
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
cleanup_device_parent(dev);
kobject_del(&dev->kobj);
Expand Down
2 changes: 1 addition & 1 deletion drivers/infiniband/hw/usnic/usnic_uiom.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ int usnic_uiom_attach_dev_to_pd(struct usnic_uiom_pd *pd, struct device *dev)
if (err)
goto out_free_dev;

if (!iommu_domain_has_cap(pd->domain, IOMMU_CAP_CACHE_COHERENCY)) {
if (!iommu_capable(dev->bus, IOMMU_CAP_CACHE_COHERENCY)) {
usnic_err("IOMMU of %s does not support cache coherency\n",
dev_name(dev));
err = -EINVAL;
Expand Down
117 changes: 68 additions & 49 deletions drivers/iommu/amd_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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)) {
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

atomic_inc(&alias_data->bind);
}
ret = -EBUSY;
if (head->domain != NULL)
goto out_unlock;

if (dev_data->domain == NULL)
do_attach(dev_data, domain);
/* Attach alias group root */
do_attach(head, 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;

Expand Down Expand Up @@ -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;

Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -3384,28 +3404,27 @@ 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,
.detach_dev = amd_iommu_detach_device,
.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,
};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
21 changes: 15 additions & 6 deletions drivers/iommu/amd_iommu_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu,
set_iommu_for_device(iommu, devid);
}

static int __init add_special_device(u8 type, u8 id, u16 devid, bool cmd_line)
static int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
{
struct devid_map *entry;
struct list_head *list;
Expand All @@ -731,6 +731,8 @@ static int __init add_special_device(u8 type, u8 id, u16 devid, bool cmd_line)
pr_info("AMD-Vi: Command-line override present for %s id %d - ignoring\n",
type == IVHD_SPECIAL_IOAPIC ? "IOAPIC" : "HPET", id);

*devid = entry->devid;

return 0;
}

Expand All @@ -739,7 +741,7 @@ static int __init add_special_device(u8 type, u8 id, u16 devid, bool cmd_line)
return -ENOMEM;

entry->id = id;
entry->devid = devid;
entry->devid = *devid;
entry->cmd_line = cmd_line;

list_add_tail(&entry->list, list);
Expand All @@ -754,7 +756,7 @@ static int __init add_early_maps(void)
for (i = 0; i < early_ioapic_map_size; ++i) {
ret = add_special_device(IVHD_SPECIAL_IOAPIC,
early_ioapic_map[i].id,
early_ioapic_map[i].devid,
&early_ioapic_map[i].devid,
early_ioapic_map[i].cmd_line);
if (ret)
return ret;
Expand All @@ -763,7 +765,7 @@ static int __init add_early_maps(void)
for (i = 0; i < early_hpet_map_size; ++i) {
ret = add_special_device(IVHD_SPECIAL_HPET,
early_hpet_map[i].id,
early_hpet_map[i].devid,
&early_hpet_map[i].devid,
early_hpet_map[i].cmd_line);
if (ret)
return ret;
Expand Down Expand Up @@ -978,10 +980,17 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
PCI_SLOT(devid),
PCI_FUNC(devid));

set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
ret = add_special_device(type, handle, devid, false);
ret = add_special_device(type, handle, &devid, false);
if (ret)
return ret;

/*
* add_special_device might update the devid in case a
* command-line override is present. So call
* set_dev_entry_from_acpi after add_special_device.
*/
set_dev_entry_from_acpi(iommu, devid, e->flags, 0);

break;
}
default:
Expand Down
21 changes: 0 additions & 21 deletions drivers/iommu/amd_iommu_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -417,27 +417,6 @@ struct protection_domain {

};

/*
* 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 iommu_dev_data *alias_data;/* The alias dev_data */
struct protection_domain *domain; /* Domain the device is bound to */
atomic_t bind; /* Domain attach reference count */
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 */
};

/*
* For dynamic growth the aperture size is split into ranges of 128MB of
* DMA address space each. This struct represents one such range.
Expand Down
Loading

0 comments on commit 23971bd

Please sign in to comment.