iommu/amd: Use helpers to access irq_cfg data structure associated with IRQ
[cascardo/linux.git] / drivers / iommu / amd_iommu.c
index ecb0109..d65f766 100644 (file)
@@ -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);
-
-               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;
 
@@ -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,28 +3404,28 @@ 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,
+       .map_sg = default_iommu_map_sg,
        .iova_to_phys = amd_iommu_iova_to_phys,
-       .domain_has_cap = amd_iommu_domain_has_cap,
        .pgsize_bitmap  = AMD_IOMMU_PGSIZES,
 };
 
@@ -4049,7 +4069,7 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
        int devid;
        int ret;
 
-       cfg = irq_get_chip_data(irq);
+       cfg = irq_cfg(irq);
        if (!cfg)
                return -EINVAL;
 
@@ -4112,7 +4132,7 @@ static int set_affinity(struct irq_data *data, const struct cpumask *mask,
        if (!config_enabled(CONFIG_SMP))
                return -1;
 
-       cfg       = data->chip_data;
+       cfg       = irqd_cfg(data);
        irq       = data->irq;
        irte_info = &cfg->irq_2_irte;
 
@@ -4150,7 +4170,7 @@ static int free_irq(int irq)
        struct irq_2_irte *irte_info;
        struct irq_cfg *cfg;
 
-       cfg = irq_get_chip_data(irq);
+       cfg = irq_cfg(irq);
        if (!cfg)
                return -EINVAL;
 
@@ -4169,7 +4189,7 @@ static void compose_msi_msg(struct pci_dev *pdev,
        struct irq_cfg *cfg;
        union irte irte;
 
-       cfg = irq_get_chip_data(irq);
+       cfg = irq_cfg(irq);
        if (!cfg)
                return;
 
@@ -4198,7 +4218,7 @@ static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)
        if (!pdev)
                return -EINVAL;
 
-       cfg = irq_get_chip_data(irq);
+       cfg = irq_cfg(irq);
        if (!cfg)
                return -EINVAL;
 
@@ -4218,7 +4238,7 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
        if (!pdev)
                return -EINVAL;
 
-       cfg = irq_get_chip_data(irq);
+       cfg = irq_cfg(irq);
        if (!cfg)
                return -EINVAL;
 
@@ -4235,13 +4255,13 @@ 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;
        int index, devid;
 
-       cfg = irq_get_chip_data(irq);
+       cfg = irq_cfg(irq);
        if (!cfg)
                return -EINVAL;
 
@@ -4274,6 +4294,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