Merge tag 'iommu-updates-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/joro...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Oct 2016 19:52:41 +0000 (12:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Oct 2016 19:52:41 +0000 (12:52 -0700)
Pull IOMMU updates from Joerg Roedel:

 - support for interrupt virtualization in the AMD IOMMU driver. These
   patches were shared with the KVM tree and are already merged through
   that tree.

 - generic DT-binding support for the ARM-SMMU driver. With this the
   driver now makes use of the generic DMA-API code. This also required
   some changes outside of the IOMMU code, but these are acked by the
   respective maintainers.

 - more cleanups and fixes all over the place.

* tag 'iommu-updates-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (40 commits)
  iommu/amd: No need to wait iommu completion if no dte irq entry change
  iommu/amd: Free domain id when free a domain of struct dma_ops_domain
  iommu/amd: Use standard bitmap operation to set bitmap
  iommu/amd: Clean up the cmpxchg64 invocation
  iommu/io-pgtable-arm: Check for v7s-incapable systems
  iommu/dma: Avoid PCI host bridge windows
  iommu/dma: Add support for mapping MSIs
  iommu/arm-smmu: Set domain geometry
  iommu/arm-smmu: Wire up generic configuration support
  Docs: dt: document ARM SMMU generic binding usage
  iommu/arm-smmu: Convert to iommu_fwspec
  iommu/arm-smmu: Intelligent SMR allocation
  iommu/arm-smmu: Add a stream map entry iterator
  iommu/arm-smmu: Streamline SMMU data lookups
  iommu/arm-smmu: Refactor mmu-masters handling
  iommu/arm-smmu: Keep track of S2CR state
  iommu/arm-smmu: Consolidate stream map entry state
  iommu/arm-smmu: Handle stream IDs more dynamically
  iommu/arm-smmu: Set PRIVCFG in stage 1 STEs
  iommu/arm-smmu: Support non-PCI devices with SMMUv3
  ...

1  2 
arch/arm64/mm/dma-mapping.c
drivers/iommu/amd_iommu.c
drivers/irqchip/irq-gic-v3-its.c

@@@ -20,7 -20,6 +20,7 @@@
  #include <linux/gfp.h>
  #include <linux/acpi.h>
  #include <linux/bootmem.h>
 +#include <linux/cache.h>
  #include <linux/export.h>
  #include <linux/slab.h>
  #include <linux/genalloc.h>
@@@ -31,7 -30,7 +31,7 @@@
  
  #include <asm/cacheflush.h>
  
 -static int swiotlb __read_mostly;
 +static int swiotlb __ro_after_init;
  
  static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot,
                                 bool coherent)
@@@ -169,7 -168,7 +169,7 @@@ static void *__dma_alloc(struct device 
                return ptr;
  
        /* remove any dirty cache lines on the kernel alias */
 -      __dma_flush_range(ptr, ptr + size);
 +      __dma_flush_area(ptr, size);
  
        /* create a coherent mapping */
        page = virt_to_page(ptr);
@@@ -388,7 -387,7 +388,7 @@@ static int __init atomic_pool_init(void
                void *page_addr = page_address(page);
  
                memset(page_addr, 0, atomic_pool_size);
 -              __dma_flush_range(page_addr, page_addr + atomic_pool_size);
 +              __dma_flush_area(page_addr, atomic_pool_size);
  
                atomic_pool = gen_pool_create(PAGE_SHIFT, -1);
                if (!atomic_pool)
@@@ -549,7 -548,7 +549,7 @@@ fs_initcall(dma_debug_do_init)
  /* Thankfully, all cache ops are by VA so we can ignore phys here */
  static void flush_page(struct device *dev, const void *virt, phys_addr_t phys)
  {
 -      __dma_flush_range(virt, virt + PAGE_SIZE);
 +      __dma_flush_area(virt, PAGE_SIZE);
  }
  
  static void *__iommu_alloc_attrs(struct device *dev, size_t size,
@@@ -828,7 -827,7 +828,7 @@@ static bool do_iommu_attach(struct devi
         * then the IOMMU core will have already configured a group for this
         * device, and allocated the default domain for that group.
         */
-       if (!domain || iommu_dma_init_domain(domain, dma_base, size)) {
+       if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
                pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
                        dev_name(dev));
                return false;
@@@ -103,7 -103,7 +103,7 @@@ struct flush_queue 
        struct flush_queue_entry *entries;
  };
  
- DEFINE_PER_CPU(struct flush_queue, flush_queue);
static DEFINE_PER_CPU(struct flush_queue, flush_queue);
  
  static atomic_t queue_timer_on;
  static struct timer_list queue_timer;
@@@ -1008,13 -1008,15 +1008,13 @@@ static void build_inv_irt(struct iommu_
   * Writes the command to the IOMMUs command buffer and informs the
   * hardware about the new command.
   */
 -static int iommu_queue_command_sync(struct amd_iommu *iommu,
 -                                  struct iommu_cmd *cmd,
 -                                  bool sync)
 +static int __iommu_queue_command_sync(struct amd_iommu *iommu,
 +                                    struct iommu_cmd *cmd,
 +                                    bool sync)
  {
        u32 left, tail, head, next_tail;
 -      unsigned long flags;
  
  again:
 -      spin_lock_irqsave(&iommu->lock, flags);
  
        head      = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
        tail      = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
  
        if (left <= 2) {
                struct iommu_cmd sync_cmd;
 -              volatile u64 sem = 0;
                int ret;
  
 -              build_completion_wait(&sync_cmd, (u64)&sem);
 -              copy_cmd_to_buffer(iommu, &sync_cmd, tail);
 +              iommu->cmd_sem = 0;
  
 -              spin_unlock_irqrestore(&iommu->lock, flags);
 +              build_completion_wait(&sync_cmd, (u64)&iommu->cmd_sem);
 +              copy_cmd_to_buffer(iommu, &sync_cmd, tail);
  
 -              if ((ret = wait_on_sem(&sem)) != 0)
 +              if ((ret = wait_on_sem(&iommu->cmd_sem)) != 0)
                        return ret;
  
                goto again;
        /* We need to sync now to make sure all commands are processed */
        iommu->need_sync = sync;
  
 +      return 0;
 +}
 +
 +static int iommu_queue_command_sync(struct amd_iommu *iommu,
 +                                  struct iommu_cmd *cmd,
 +                                  bool sync)
 +{
 +      unsigned long flags;
 +      int ret;
 +
 +      spin_lock_irqsave(&iommu->lock, flags);
 +      ret = __iommu_queue_command_sync(iommu, cmd, sync);
        spin_unlock_irqrestore(&iommu->lock, flags);
  
 -      return 0;
 +      return ret;
  }
  
  static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
  static int iommu_completion_wait(struct amd_iommu *iommu)
  {
        struct iommu_cmd cmd;
 -      volatile u64 sem = 0;
 +      unsigned long flags;
        int ret;
  
        if (!iommu->need_sync)
                return 0;
  
 -      build_completion_wait(&cmd, (u64)&sem);
  
 -      ret = iommu_queue_command_sync(iommu, &cmd, false);
 +      build_completion_wait(&cmd, (u64)&iommu->cmd_sem);
 +
 +      spin_lock_irqsave(&iommu->lock, flags);
 +
 +      iommu->cmd_sem = 0;
 +
 +      ret = __iommu_queue_command_sync(iommu, &cmd, false);
        if (ret)
 -              return ret;
 +              goto out_unlock;
 +
 +      ret = wait_on_sem(&iommu->cmd_sem);
 +
 +out_unlock:
 +      spin_unlock_irqrestore(&iommu->lock, flags);
  
 -      return wait_on_sem(&sem);
 +      return ret;
  }
  
  static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid)
@@@ -1361,7 -1342,8 +1361,8 @@@ static u64 *alloc_pte(struct protection
  
                        __npte = PM_LEVEL_PDE(level, virt_to_phys(page));
  
-                       if (cmpxchg64(pte, __pte, __npte)) {
+                       /* pte could have been changed somewhere. */
+                       if (cmpxchg64(pte, __pte, __npte) != __pte) {
                                free_page((unsigned long)page);
                                continue;
                        }
@@@ -1741,6 -1723,9 +1742,9 @@@ static void dma_ops_domain_free(struct 
  
        free_pagetable(&dom->domain);
  
+       if (dom->domain.id)
+               domain_id_free(dom->domain.id);
        kfree(dom);
  }
  
@@@ -3649,7 -3634,7 +3653,7 @@@ static struct irq_remap_table *get_irq_
  
        table = irq_lookup_table[devid];
        if (table)
-               goto out;
+               goto out_unlock;
  
        alias = amd_iommu_alias_table[devid];
        table = irq_lookup_table[alias];
        /* Nothing there yet, allocate new irq remapping table */
        table = kzalloc(sizeof(*table), GFP_ATOMIC);
        if (!table)
-               goto out;
+               goto out_unlock;
  
        /* Initialize table spin-lock */
        spin_lock_init(&table->lock);
        if (!table->table) {
                kfree(table);
                table = NULL;
-               goto out;
+               goto out_unlock;
        }
  
        if (!AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir))
@@@ -4153,6 -4138,7 +4157,7 @@@ static int irq_remapping_alloc(struct i
        }
        if (index < 0) {
                pr_warn("Failed to allocate IRTE\n");
+               ret = index;
                goto out_free_parent;
        }
  
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  
 +#include <linux/acpi.h>
  #include <linux/bitmap.h>
  #include <linux/cpu.h>
  #include <linux/delay.h>
+ #include <linux/dma-iommu.h>
  #include <linux/interrupt.h>
 +#include <linux/irqdomain.h>
 +#include <linux/acpi_iort.h>
  #include <linux/log2.h>
  #include <linux/mm.h>
  #include <linux/msi.h>
@@@ -78,7 -76,7 +79,7 @@@ struct its_node 
        raw_spinlock_t          lock;
        struct list_head        entry;
        void __iomem            *base;
 -      unsigned long           phys_base;
 +      phys_addr_t             phys_base;
        struct its_cmd_block    *cmd_base;
        struct its_cmd_block    *cmd_write;
        struct its_baser        tables[GITS_BASER_NR_REGS];
@@@ -118,7 -116,6 +119,7 @@@ struct its_device 
  static LIST_HEAD(its_nodes);
  static DEFINE_SPINLOCK(its_lock);
  static struct rdists *gic_rdists;
 +static struct irq_domain *its_parent;
  
  #define gic_data_rdist()              (raw_cpu_ptr(gic_rdists->rdist))
  #define gic_data_rdist_rd_base()      (gic_data_rdist()->rd_base)
@@@ -659,6 -656,8 +660,8 @@@ static void its_irq_compose_msi_msg(str
        msg->address_lo         = addr & ((1UL << 32) - 1);
        msg->address_hi         = addr >> 32;
        msg->data               = its_get_event_id(d);
+       iommu_dma_map_msi_msg(d->irq, msg);
  }
  
  static struct irq_chip its_irq_chip = {
@@@ -1441,11 -1440,6 +1444,11 @@@ static int its_irq_gic_domain_alloc(str
                fwspec.param[0] = GIC_IRQ_TYPE_LPI;
                fwspec.param[1] = hwirq;
                fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
 +      } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
 +              fwspec.fwnode = domain->parent->fwnode;
 +              fwspec.param_count = 2;
 +              fwspec.param[0] = hwirq;
 +              fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
        } else {
                return -EINVAL;
        }
@@@ -1623,59 -1617,44 +1626,59 @@@ static void its_enable_quirks(struct it
        gic_enable_quirks(iidr, its_quirks, its);
  }
  
 -static int __init its_probe(struct device_node *node,
 -                          struct irq_domain *parent)
 +static int its_init_domain(struct fwnode_handle *handle, struct its_node *its)
 +{
 +      struct irq_domain *inner_domain;
 +      struct msi_domain_info *info;
 +
 +      info = kzalloc(sizeof(*info), GFP_KERNEL);
 +      if (!info)
 +              return -ENOMEM;
 +
 +      inner_domain = irq_domain_create_tree(handle, &its_domain_ops, its);
 +      if (!inner_domain) {
 +              kfree(info);
 +              return -ENOMEM;
 +      }
 +
 +      inner_domain->parent = its_parent;
 +      inner_domain->bus_token = DOMAIN_BUS_NEXUS;
 +      info->ops = &its_msi_domain_ops;
 +      info->data = its;
 +      inner_domain->host_data = info;
 +
 +      return 0;
 +}
 +
 +static int __init its_probe_one(struct resource *res,
 +                              struct fwnode_handle *handle, int numa_node)
  {
 -      struct resource res;
        struct its_node *its;
        void __iomem *its_base;
 -      struct irq_domain *inner_domain;
        u32 val;
        u64 baser, tmp;
        int err;
  
 -      err = of_address_to_resource(node, 0, &res);
 -      if (err) {
 -              pr_warn("%s: no regs?\n", node->full_name);
 -              return -ENXIO;
 -      }
 -
 -      its_base = ioremap(res.start, resource_size(&res));
 +      its_base = ioremap(res->start, resource_size(res));
        if (!its_base) {
 -              pr_warn("%s: unable to map registers\n", node->full_name);
 +              pr_warn("ITS@%pa: Unable to map ITS registers\n", &res->start);
                return -ENOMEM;
        }
  
        val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
        if (val != 0x30 && val != 0x40) {
 -              pr_warn("%s: no ITS detected, giving up\n", node->full_name);
 +              pr_warn("ITS@%pa: No ITS detected, giving up\n", &res->start);
                err = -ENODEV;
                goto out_unmap;
        }
  
        err = its_force_quiescent(its_base);
        if (err) {
 -              pr_warn("%s: failed to quiesce, giving up\n",
 -                      node->full_name);
 +              pr_warn("ITS@%pa: Failed to quiesce, giving up\n", &res->start);
                goto out_unmap;
        }
  
 -      pr_info("ITS: %s\n", node->full_name);
 +      pr_info("ITS %pR\n", res);
  
        its = kzalloc(sizeof(*its), GFP_KERNEL);
        if (!its) {
        INIT_LIST_HEAD(&its->entry);
        INIT_LIST_HEAD(&its->its_device_list);
        its->base = its_base;
 -      its->phys_base = res.start;
 +      its->phys_base = res->start;
        its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
 -      its->numa_node = of_node_to_nid(node);
 +      its->numa_node = numa_node;
  
        its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
        if (!its->cmd_base) {
        writeq_relaxed(0, its->base + GITS_CWRITER);
        writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR);
  
 -      if (of_property_read_bool(node, "msi-controller")) {
 -              struct msi_domain_info *info;
 -
 -              info = kzalloc(sizeof(*info), GFP_KERNEL);
 -              if (!info) {
 -                      err = -ENOMEM;
 -                      goto out_free_tables;
 -              }
 -
 -              inner_domain = irq_domain_add_tree(node, &its_domain_ops, its);
 -              if (!inner_domain) {
 -                      err = -ENOMEM;
 -                      kfree(info);
 -                      goto out_free_tables;
 -              }
 -
 -              inner_domain->parent = parent;
 -              inner_domain->bus_token = DOMAIN_BUS_NEXUS;
 -              info->ops = &its_msi_domain_ops;
 -              info->data = its;
 -              inner_domain->host_data = info;
 -      }
 +      err = its_init_domain(handle, its);
 +      if (err)
 +              goto out_free_tables;
  
        spin_lock(&its_lock);
        list_add(&its->entry, &its_nodes);
@@@ -1754,7 -1752,7 +1757,7 @@@ out_free_its
        kfree(its);
  out_unmap:
        iounmap(its_base);
 -      pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
 +      pr_err("ITS@%pa: failed probing (%d)\n", &res->start, err);
        return err;
  }
  
@@@ -1782,92 -1780,16 +1785,92 @@@ static struct of_device_id its_device_i
        {},
  };
  
 -int __init its_init(struct device_node *node, struct rdists *rdists,
 -           struct irq_domain *parent_domain)
 +static int __init its_of_probe(struct device_node *node)
  {
        struct device_node *np;
 +      struct resource res;
  
        for (np = of_find_matching_node(node, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
 -              its_probe(np, parent_domain);
 +              if (!of_property_read_bool(np, "msi-controller")) {
 +                      pr_warn("%s: no msi-controller property, ITS ignored\n",
 +                              np->full_name);
 +                      continue;
 +              }
 +
 +              if (of_address_to_resource(np, 0, &res)) {
 +                      pr_warn("%s: no regs?\n", np->full_name);
 +                      continue;
 +              }
 +
 +              its_probe_one(&res, &np->fwnode, of_node_to_nid(np));
 +      }
 +      return 0;
 +}
 +
 +#ifdef CONFIG_ACPI
 +
 +#define ACPI_GICV3_ITS_MEM_SIZE (SZ_128K)
 +
 +static int __init gic_acpi_parse_madt_its(struct acpi_subtable_header *header,
 +                                        const unsigned long end)
 +{
 +      struct acpi_madt_generic_translator *its_entry;
 +      struct fwnode_handle *dom_handle;
 +      struct resource res;
 +      int err;
 +
 +      its_entry = (struct acpi_madt_generic_translator *)header;
 +      memset(&res, 0, sizeof(res));
 +      res.start = its_entry->base_address;
 +      res.end = its_entry->base_address + ACPI_GICV3_ITS_MEM_SIZE - 1;
 +      res.flags = IORESOURCE_MEM;
 +
 +      dom_handle = irq_domain_alloc_fwnode((void *)its_entry->base_address);
 +      if (!dom_handle) {
 +              pr_err("ITS@%pa: Unable to allocate GICv3 ITS domain token\n",
 +                     &res.start);
 +              return -ENOMEM;
        }
  
 +      err = iort_register_domain_token(its_entry->translation_id, dom_handle);
 +      if (err) {
 +              pr_err("ITS@%pa: Unable to register GICv3 ITS domain token (ITS ID %d) to IORT\n",
 +                     &res.start, its_entry->translation_id);
 +              goto dom_err;
 +      }
 +
 +      err = its_probe_one(&res, dom_handle, NUMA_NO_NODE);
 +      if (!err)
 +              return 0;
 +
 +      iort_deregister_domain_token(its_entry->translation_id);
 +dom_err:
 +      irq_domain_free_fwnode(dom_handle);
 +      return err;
 +}
 +
 +static void __init its_acpi_probe(void)
 +{
 +      acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
 +                            gic_acpi_parse_madt_its, 0);
 +}
 +#else
 +static void __init its_acpi_probe(void) { }
 +#endif
 +
 +int __init its_init(struct fwnode_handle *handle, struct rdists *rdists,
 +                  struct irq_domain *parent_domain)
 +{
 +      struct device_node *of_node;
 +
 +      its_parent = parent_domain;
 +      of_node = to_of_node(handle);
 +      if (of_node)
 +              its_of_probe(of_node);
 +      else
 +              its_acpi_probe();
 +
        if (list_empty(&its_nodes)) {
                pr_warn("ITS: No ITS available, not enabling LPIs\n");
                return -ENXIO;