Merge tag 'iommu-updates-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / iommu / amd_iommu.c
index 830183737b0ffd2001e85b1e444dc3c66723f33a..21d02b0d907c1ada17aa3b1d0e13352cd2e4cbf3 100644 (file)
@@ -46,6 +46,7 @@
 #include "amd_iommu_proto.h"
 #include "amd_iommu_types.h"
 #include "irq_remapping.h"
+#include "pci.h"
 
 #define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28))
 
@@ -263,12 +264,6 @@ static bool check_device(struct device *dev)
        return true;
 }
 
-static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
-{
-       pci_dev_put(*from);
-       *from = to;
-}
-
 static struct pci_bus *find_hosted_bus(struct pci_bus *bus)
 {
        while (!bus->self) {
@@ -701,9 +696,6 @@ retry:
 static void iommu_poll_events(struct amd_iommu *iommu)
 {
        u32 head, tail;
-       unsigned long flags;
-
-       spin_lock_irqsave(&iommu->lock, flags);
 
        head = readl(iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
        tail = readl(iommu->mmio_base + MMIO_EVT_TAIL_OFFSET);
@@ -714,8 +706,6 @@ static void iommu_poll_events(struct amd_iommu *iommu)
        }
 
        writel(head, iommu->mmio_base + MMIO_EVT_HEAD_OFFSET);
-
-       spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
 static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw)
@@ -740,17 +730,11 @@ static void iommu_handle_ppr_entry(struct amd_iommu *iommu, u64 *raw)
 
 static void iommu_poll_ppr_log(struct amd_iommu *iommu)
 {
-       unsigned long flags;
        u32 head, tail;
 
        if (iommu->ppr_log == NULL)
                return;
 
-       /* enable ppr interrupts again */
-       writel(MMIO_STATUS_PPR_INT_MASK, iommu->mmio_base + MMIO_STATUS_OFFSET);
-
-       spin_lock_irqsave(&iommu->lock, flags);
-
        head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
        tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
 
@@ -786,34 +770,50 @@ static void iommu_poll_ppr_log(struct amd_iommu *iommu)
                head = (head + PPR_ENTRY_SIZE) % PPR_LOG_SIZE;
                writel(head, iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
 
-               /*
-                * Release iommu->lock because ppr-handling might need to
-                * re-acquire it
-                */
-               spin_unlock_irqrestore(&iommu->lock, flags);
-
                /* Handle PPR entry */
                iommu_handle_ppr_entry(iommu, entry);
 
-               spin_lock_irqsave(&iommu->lock, flags);
-
                /* Refresh ring-buffer information */
                head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET);
                tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET);
        }
-
-       spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
 irqreturn_t amd_iommu_int_thread(int irq, void *data)
 {
-       struct amd_iommu *iommu;
+       struct amd_iommu *iommu = (struct amd_iommu *) data;
+       u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
 
-       for_each_iommu(iommu) {
-               iommu_poll_events(iommu);
-               iommu_poll_ppr_log(iommu);
-       }
+       while (status & (MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK)) {
+               /* Enable EVT and PPR interrupts again */
+               writel((MMIO_STATUS_EVT_INT_MASK | MMIO_STATUS_PPR_INT_MASK),
+                       iommu->mmio_base + MMIO_STATUS_OFFSET);
 
+               if (status & MMIO_STATUS_EVT_INT_MASK) {
+                       pr_devel("AMD-Vi: Processing IOMMU Event Log\n");
+                       iommu_poll_events(iommu);
+               }
+
+               if (status & MMIO_STATUS_PPR_INT_MASK) {
+                       pr_devel("AMD-Vi: Processing IOMMU PPR Log\n");
+                       iommu_poll_ppr_log(iommu);
+               }
+
+               /*
+                * Hardware bug: ERBT1312
+                * When re-enabling interrupt (by writing 1
+                * to clear the bit), the hardware might also try to set
+                * the interrupt bit in the event status register.
+                * In this scenario, the bit will be set, and disable
+                * subsequent interrupts.
+                *
+                * Workaround: The IOMMU driver should read back the
+                * status register and check if the interrupt bits are cleared.
+                * If not, driver will need to go through the interrupt handler
+                * again and re-clear the bits
+                */
+               status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
+       }
        return IRQ_HANDLED;
 }
 
@@ -2838,24 +2838,6 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
        spin_unlock_irqrestore(&domain->lock, flags);
 }
 
-/*
- * This is a special map_sg function which is used if we should map a
- * device which is not handled by an AMD IOMMU in the system.
- */
-static int map_sg_no_iommu(struct device *dev, struct scatterlist *sglist,
-                          int nelems, int dir)
-{
-       struct scatterlist *s;
-       int i;
-
-       for_each_sg(sglist, s, nelems, i) {
-               s->dma_address = (dma_addr_t)sg_phys(s);
-               s->dma_length  = s->length;
-       }
-
-       return nelems;
-}
-
 /*
  * The exported map_sg function for dma_ops (handles scatter-gather
  * lists).
@@ -2875,9 +2857,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
        INC_STATS_COUNTER(cnt_map_sg);
 
        domain = get_domain(dev);
-       if (PTR_ERR(domain) == -EINVAL)
-               return map_sg_no_iommu(dev, sglist, nelems, dir);
-       else if (IS_ERR(domain))
+       if (IS_ERR(domain))
                return 0;
 
        dma_mask = *dev->dma_mask;
@@ -3410,7 +3390,7 @@ static size_t amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
 }
 
 static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
-                                         unsigned long iova)
+                                         dma_addr_t iova)
 {
        struct protection_domain *domain = dom->priv;
        unsigned long offset_mask;
@@ -3947,6 +3927,9 @@ static struct irq_remap_table *get_irq_table(u16 devid, bool ioapic)
        if (!table)
                goto out;
 
+       /* Initialize table spin-lock */
+       spin_lock_init(&table->lock);
+
        if (ioapic)
                /* Keep the first 32 indexes free for IOAPIC interrupts */
                table->min_index = 32;
@@ -4007,7 +3990,7 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
                        c = 0;
 
                if (c == count) {
-                       struct irq_2_iommu *irte_info;
+                       struct irq_2_irte *irte_info;
 
                        for (; c != 0; --c)
                                table->table[index - c + 1] = IRTE_ALLOCATED;
@@ -4015,9 +3998,9 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
                        index -= count - 1;
 
                        cfg->remapped         = 1;
-                       irte_info             = &cfg->irq_2_iommu;
-                       irte_info->sub_handle = devid;
-                       irte_info->irte_index = index;
+                       irte_info             = &cfg->irq_2_irte;
+                       irte_info->devid      = devid;
+                       irte_info->index      = index;
 
                        goto out;
                }
@@ -4098,7 +4081,7 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
                              struct io_apic_irq_attr *attr)
 {
        struct irq_remap_table *table;
-       struct irq_2_iommu *irte_info;
+       struct irq_2_irte *irte_info;
        struct irq_cfg *cfg;
        union irte irte;
        int ioapic_id;
@@ -4110,7 +4093,7 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
        if (!cfg)
                return -EINVAL;
 
-       irte_info = &cfg->irq_2_iommu;
+       irte_info = &cfg->irq_2_irte;
        ioapic_id = mpc_ioapic_id(attr->ioapic);
        devid     = get_ioapic_devid(ioapic_id);
 
@@ -4125,8 +4108,8 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
 
        /* Setup IRQ remapping info */
        cfg->remapped         = 1;
-       irte_info->sub_handle = devid;
-       irte_info->irte_index = index;
+       irte_info->devid      = devid;
+       irte_info->index      = index;
 
        /* Setup IRTE for IOMMU */
        irte.val                = 0;
@@ -4160,7 +4143,7 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
 static int set_affinity(struct irq_data *data, const struct cpumask *mask,
                        bool force)
 {
-       struct irq_2_iommu *irte_info;
+       struct irq_2_irte *irte_info;
        unsigned int dest, irq;
        struct irq_cfg *cfg;
        union irte irte;
@@ -4171,12 +4154,12 @@ static int set_affinity(struct irq_data *data, const struct cpumask *mask,
 
        cfg       = data->chip_data;
        irq       = data->irq;
-       irte_info = &cfg->irq_2_iommu;
+       irte_info = &cfg->irq_2_irte;
 
        if (!cpumask_intersects(mask, cpu_online_mask))
                return -EINVAL;
 
-       if (get_irte(irte_info->sub_handle, irte_info->irte_index, &irte))
+       if (get_irte(irte_info->devid, irte_info->index, &irte))
                return -EBUSY;
 
        if (assign_irq_vector(irq, cfg, mask))
@@ -4192,7 +4175,7 @@ static int set_affinity(struct irq_data *data, const struct cpumask *mask,
        irte.fields.vector      = cfg->vector;
        irte.fields.destination = dest;
 
-       modify_irte(irte_info->sub_handle, irte_info->irte_index, irte);
+       modify_irte(irte_info->devid, irte_info->index, irte);
 
        if (cfg->move_in_progress)
                send_cleanup_vector(cfg);
@@ -4204,16 +4187,16 @@ static int set_affinity(struct irq_data *data, const struct cpumask *mask,
 
 static int free_irq(int irq)
 {
-       struct irq_2_iommu *irte_info;
+       struct irq_2_irte *irte_info;
        struct irq_cfg *cfg;
 
        cfg = irq_get_chip_data(irq);
        if (!cfg)
                return -EINVAL;
 
-       irte_info = &cfg->irq_2_iommu;
+       irte_info = &cfg->irq_2_irte;
 
-       free_irte(irte_info->sub_handle, irte_info->irte_index);
+       free_irte(irte_info->devid, irte_info->index);
 
        return 0;
 }
@@ -4222,7 +4205,7 @@ static void compose_msi_msg(struct pci_dev *pdev,
                            unsigned int irq, unsigned int dest,
                            struct msi_msg *msg, u8 hpet_id)
 {
-       struct irq_2_iommu *irte_info;
+       struct irq_2_irte *irte_info;
        struct irq_cfg *cfg;
        union irte irte;
 
@@ -4230,7 +4213,7 @@ static void compose_msi_msg(struct pci_dev *pdev,
        if (!cfg)
                return;
 
-       irte_info = &cfg->irq_2_iommu;
+       irte_info = &cfg->irq_2_irte;
 
        irte.val                = 0;
        irte.fields.vector      = cfg->vector;
@@ -4239,11 +4222,11 @@ static void compose_msi_msg(struct pci_dev *pdev,
        irte.fields.dm          = apic->irq_dest_mode;
        irte.fields.valid       = 1;
 
-       modify_irte(irte_info->sub_handle, irte_info->irte_index, irte);
+       modify_irte(irte_info->devid, irte_info->index, irte);
 
        msg->address_hi = MSI_ADDR_BASE_HI;
        msg->address_lo = MSI_ADDR_BASE_LO;
-       msg->data       = irte_info->irte_index;
+       msg->data       = irte_info->index;
 }
 
 static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)
@@ -4268,7 +4251,7 @@ static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)
 static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
                         int index, int offset)
 {
-       struct irq_2_iommu *irte_info;
+       struct irq_2_irte *irte_info;
        struct irq_cfg *cfg;
        u16 devid;
 
@@ -4283,18 +4266,18 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
                return 0;
 
        devid           = get_device_id(&pdev->dev);
-       irte_info       = &cfg->irq_2_iommu;
+       irte_info       = &cfg->irq_2_irte;
 
        cfg->remapped         = 1;
-       irte_info->sub_handle = devid;
-       irte_info->irte_index = index + offset;
+       irte_info->devid      = devid;
+       irte_info->index      = index + offset;
 
        return 0;
 }
 
 static int setup_hpet_msi(unsigned int irq, unsigned int id)
 {
-       struct irq_2_iommu *irte_info;
+       struct irq_2_irte *irte_info;
        struct irq_cfg *cfg;
        int index, devid;
 
@@ -4302,7 +4285,7 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id)
        if (!cfg)
                return -EINVAL;
 
-       irte_info = &cfg->irq_2_iommu;
+       irte_info = &cfg->irq_2_irte;
        devid     = get_hpet_devid(id);
        if (devid < 0)
                return devid;
@@ -4312,8 +4295,8 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id)
                return index;
 
        cfg->remapped         = 1;
-       irte_info->sub_handle = devid;
-       irte_info->irte_index = index;
+       irte_info->devid      = devid;
+       irte_info->index      = index;
 
        return 0;
 }