Merge branches 'dma-debug/next', 'amd-iommu/command-cleanups', 'amd-iommu/ats' and...
Joerg Roedel [Tue, 10 May 2011 08:25:23 +0000 (10:25 +0200)]
Conflicts:
arch/x86/include/asm/amd_iommu_types.h
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c

1  2  3  4 
arch/x86/include/asm/amd_iommu_types.h
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
drivers/pci/intel-iommu.c

    /* command specific defines */
    #define CMD_COMPL_WAIT          0x01
    #define CMD_INV_DEV_ENTRY       0x02
-- -#define CMD_INV_IOMMU_PAGES     0x03
++ +#define CMD_INV_IOMMU_PAGES 0x03
++ +#define CMD_INV_IOTLB_PAGES 0x04
+++ #define CMD_INV_ALL         0x08
    
    #define CMD_COMPL_WAIT_STORE_MASK   0x01
    #define CMD_COMPL_WAIT_INT_MASK             0x02
@@@@@ -383,31 -383,31 -382,122 -381,97 +382,128 @@@@@ irqreturn_t amd_iommu_int_handler(int i
     *
     ****************************************************************************/
    
--  /*
--   * Writes the command to the IOMMUs command buffer and informs the
--   * hardware about the new command. Must be called with iommu->lock held.
--   */
--  static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
++  static int wait_on_sem(volatile u64 *sem)
++  {
++      int i = 0;
++  
++      while (*sem == 0 && i < LOOP_TIMEOUT) {
++              udelay(1);
++              i += 1;
++      }
++  
++      if (i == LOOP_TIMEOUT) {
++              pr_alert("AMD-Vi: Completion-Wait loop timed out\n");
++              return -EIO;
++      }
++  
++      return 0;
++  }
++  
++  static void copy_cmd_to_buffer(struct amd_iommu *iommu,
++                             struct iommu_cmd *cmd,
++                             u32 tail)
    {
--      u32 tail, head;
        u8 *target;
    
--      WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
--      tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
        target = iommu->cmd_buf + tail;
--      memcpy_toio(target, cmd, sizeof(*cmd));
--      tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
--      head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
--      if (tail == head)
--              return -ENOMEM;
++      tail   = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
++  
++      /* Copy command to buffer */
++      memcpy(target, cmd, sizeof(*cmd));
++  
++      /* Tell the IOMMU about it */
        writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
++  }
    
--      return 0;
++  static void build_completion_wait(struct iommu_cmd *cmd, u64 address)
++  {
++      WARN_ON(address & 0x7ULL);
++  
++      memset(cmd, 0, sizeof(*cmd));
++      cmd->data[0] = lower_32_bits(__pa(address)) | CMD_COMPL_WAIT_STORE_MASK;
++      cmd->data[1] = upper_32_bits(__pa(address));
++      cmd->data[2] = 1;
++      CMD_SET_TYPE(cmd, CMD_COMPL_WAIT);
++  }
++  
++  static void build_inv_dte(struct iommu_cmd *cmd, u16 devid)
++  {
++      memset(cmd, 0, sizeof(*cmd));
++      cmd->data[0] = devid;
++      CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY);
++  }
++  
++  static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
++                                size_t size, u16 domid, int pde)
++  {
++      u64 pages;
++      int s;
++  
++      pages = iommu_num_pages(address, size, PAGE_SIZE);
++      s     = 0;
++  
++      if (pages > 1) {
++              /*
++               * If we have to flush more than one page, flush all
++               * TLB entries for this domain
++               */
++              address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
++              s = 1;
++      }
++  
++      address &= PAGE_MASK;
++  
++      memset(cmd, 0, sizeof(*cmd));
++      cmd->data[1] |= domid;
++      cmd->data[2]  = lower_32_bits(address);
++      cmd->data[3]  = upper_32_bits(address);
++      CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
++      if (s) /* size bit - we flush more than one 4kb page */
++              cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
++      if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
++              cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
++  }
++  
++ +static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep,
++ +                              u64 address, size_t size)
++ +{
++ +    u64 pages;
++ +    int s;
++ +
++ +    pages = iommu_num_pages(address, size, PAGE_SIZE);
++ +    s     = 0;
++ +
++ +    if (pages > 1) {
++ +            /*
++ +             * If we have to flush more than one page, flush all
++ +             * TLB entries for this domain
++ +             */
++ +            address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
++ +            s = 1;
++ +    }
++ +
++ +    address &= PAGE_MASK;
++ +
++ +    memset(cmd, 0, sizeof(*cmd));
++ +    cmd->data[0]  = devid;
++ +    cmd->data[0] |= (qdep & 0xff) << 24;
++ +    cmd->data[1]  = devid;
++ +    cmd->data[2]  = lower_32_bits(address);
++ +    cmd->data[3]  = upper_32_bits(address);
++ +    CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES);
++ +    if (s)
++ +            cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
++ +}
++ +
+++ static void build_inv_all(struct iommu_cmd *cmd)
+++ {
+++     memset(cmd, 0, sizeof(*cmd));
+++     CMD_SET_TYPE(cmd, CMD_INV_ALL);
  + }
  + 
    /*
--   * General queuing function for commands. Takes iommu->lock and calls
--   * __iommu_queue_command().
++   * Writes the command to the IOMMUs command buffer and informs the
++   * hardware about the new command.
     */
    static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
    {
     * This function queues a completion wait command into the command
     * buffer of an IOMMU
     */
--  static int __iommu_completion_wait(struct amd_iommu *iommu)
++  static int iommu_completion_wait(struct amd_iommu *iommu)
    {
        struct iommu_cmd cmd;
++      volatile u64 sem = 0;
++      int ret;
    
--       memset(&cmd, 0, sizeof(cmd));
--       cmd.data[0] = CMD_COMPL_WAIT_INT_MASK;
--       CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT);
++      if (!iommu->need_sync)
++              return 0;
++  
++      build_completion_wait(&cmd, (u64)&sem);
++  
++      ret = iommu_queue_command(iommu, &cmd);
++      if (ret)
++              return ret;
    
--       return __iommu_queue_command(iommu, &cmd);
++      return wait_on_sem(&sem);
    }
    
--  /*
--   * This function is called whenever we need to ensure that the IOMMU has
--   * completed execution of all commands we sent. It sends a
--   * COMPLETION_WAIT command and waits for it to finish. The IOMMU informs
--   * us about that by writing a value to a physical address we pass with
--   * the command.
--   */
--  static int iommu_completion_wait(struct amd_iommu *iommu)
++  static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid)
    {
--      int ret = 0;
--      unsigned long flags;
++      struct iommu_cmd cmd;
    
--      spin_lock_irqsave(&iommu->lock, flags);
++      build_inv_dte(&cmd, devid);
    
--      if (!iommu->need_sync)
--              goto out;
++      return iommu_queue_command(iommu, &cmd);
++  }
    
--      ret = __iommu_completion_wait(iommu);
++  static void iommu_flush_dte_all(struct amd_iommu *iommu)
++  {
++      u32 devid;
    
--      iommu->need_sync = false;
++      for (devid = 0; devid <= 0xffff; ++devid)
++              iommu_flush_dte(iommu, devid);
    
--      if (ret)
--              goto out;
--  
--      __iommu_wait_for_completion(iommu);
++      iommu_completion_wait(iommu);
++  }
    
--  out:
--      spin_unlock_irqrestore(&iommu->lock, flags);
++  /*
++   * This function uses heavy locking and may disable irqs for some time. But
++   * this is no issue because it is only called during resume.
++   */
++  static void iommu_flush_tlb_all(struct amd_iommu *iommu)
++  {
++      u32 dom_id;
    
--      if (iommu->reset_in_progress)
--              reset_iommu_command_buffer(iommu);
++      for (dom_id = 0; dom_id <= 0xffff; ++dom_id) {
++              struct iommu_cmd cmd;
++              build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
++                                    dom_id, 1);
++              iommu_queue_command(iommu, &cmd);
++      }
    
--      return 0;
++      iommu_completion_wait(iommu);
    }
    
--  static void iommu_flush_complete(struct protection_domain *domain)
+++ static void iommu_flush_all(struct amd_iommu *iommu)
  + {
--      int i;
+++     struct iommu_cmd cmd;
  + 
--      for (i = 0; i < amd_iommus_present; ++i) {
--              if (!domain->dev_iommu[i])
--                      continue;
+++     build_inv_all(&cmd);
  + 
--              /*
--               * Devices of this domain are behind this IOMMU
--               * We need to wait for completion of all commands.
--               */
--              iommu_completion_wait(amd_iommus[i]);
+++     iommu_queue_command(iommu, &cmd);
+++     iommu_completion_wait(iommu);
+++ }
+++ 
++  void iommu_flush_all_caches(struct amd_iommu *iommu)
++  {
  -     iommu_flush_dte_all(iommu);
  -     iommu_flush_tlb_all(iommu);
+++     if (iommu_feature(iommu, FEATURE_IA)) {
+++             iommu_flush_all(iommu);
+++     } else {
+++             iommu_flush_dte_all(iommu);
+++             iommu_flush_tlb_all(iommu);
  +     }
    }
    
    /*
--   * Command send function for invalidating a device table entry
++ + * Command send function for flushing on-device TLB
   + */
--  static int iommu_flush_device(struct device *dev)
++ +static int device_flush_iotlb(struct device *dev, u64 address, size_t size)
   +{
++ +    struct pci_dev *pdev = to_pci_dev(dev);
   +    struct amd_iommu *iommu;
   +    struct iommu_cmd cmd;
   +    u16 devid;
++ +    int qdep;
   +
++ +    qdep  = pci_ats_queue_depth(pdev);
   +    devid = get_device_id(dev);
   +    iommu = amd_iommu_rlookup_table[devid];
   +
--      /* Build command */
--      memset(&cmd, 0, sizeof(cmd));
--      CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY);
--      cmd.data[0] = devid;
++ +    build_inv_iotlb_pages(&cmd, devid, qdep, address, size);
   +
   +    return iommu_queue_command(iommu, &cmd);
   +}
   +
--  static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
--                                        u16 domid, int pde, int s)
--  {
--      memset(cmd, 0, sizeof(*cmd));
--      address &= PAGE_MASK;
--      CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
--      cmd->data[1] |= domid;
--      cmd->data[2] = lower_32_bits(address);
--      cmd->data[3] = upper_32_bits(address);
--      if (s) /* size bit - we flush more than one 4kb page */
--              cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
--      if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
--              cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
--  }
--  
   +/*
--   * Generic command send function for invalidaing TLB entries
++   * Command send function for invalidating a device table entry
     */
--  static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu,
--              u64 address, u16 domid, int pde, int s)
++  static int device_flush_dte(struct device *dev)
    {
--      struct iommu_cmd cmd;
++      struct amd_iommu *iommu;
++ +    struct pci_dev *pdev;
++      u16 devid;
   +    int ret;
    
--      __iommu_build_inv_iommu_pages(&cmd, address, domid, pde, s);
++ +    pdev  = to_pci_dev(dev);
++      devid = get_device_id(dev);
++      iommu = amd_iommu_rlookup_table[devid];
    
--      ret = iommu_queue_command(iommu, &cmd);
   -    return iommu_flush_dte(iommu, devid);
++ +    ret = iommu_flush_dte(iommu, devid);
++ +    if (ret)
++ +            return ret;
++ +
++ +    if (pci_ats_enabled(pdev))
++ +            ret = device_flush_iotlb(dev, 0, ~0UL);
   +
   +    return ret;
    }
    
    /*
     * It invalidates a single PTE if the range to flush is within a single
     * page. Otherwise it flushes the whole TLB of the IOMMU.
     */
--  static void __iommu_flush_pages(struct protection_domain *domain,
--                              u64 address, size_t size, int pde)
++  static void __domain_flush_pages(struct protection_domain *domain,
++                               u64 address, size_t size, int pde)
    {
--      int s = 0, i;
--      unsigned long pages = iommu_num_pages(address, size, PAGE_SIZE);
--  
--      address &= PAGE_MASK;
--  
--      if (pages > 1) {
--              /*
--               * If we have to flush more than one page, flush all
--               * TLB entries for this domain
--               */
--              address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
--              s = 1;
--      }
++ +    struct iommu_dev_data *dev_data;
++      struct iommu_cmd cmd;
++      int ret = 0, i;
    
++      build_inv_iommu_pages(&cmd, address, size, domain->id, pde);
    
        for (i = 0; i < amd_iommus_present; ++i) {
                if (!domain->dev_iommu[i])
                 * Devices of this domain are behind this IOMMU
                 * We need a TLB flush
                 */
--              iommu_queue_inv_iommu_pages(amd_iommus[i], address,
--                                          domain->id, pde, s);
++              ret |= iommu_queue_command(amd_iommus[i], &cmd);
        }
    
--      return;
++ +    list_for_each_entry(dev_data, &domain->dev_list, list) {
++ +            struct pci_dev *pdev = to_pci_dev(dev_data->dev);
++ +
++ +            if (!pci_ats_enabled(pdev))
++ +                    continue;
++ +
++ +            ret |= device_flush_iotlb(dev_data->dev, address, size);
++ +    }
++ +
++      WARN_ON(ret);
    }
    
--  static void iommu_flush_pages(struct protection_domain *domain,
--                           u64 address, size_t size)
++  static void domain_flush_pages(struct protection_domain *domain,
++                             u64 address, size_t size)
    {
--      __iommu_flush_pages(domain, address, size, 0);
++      __domain_flush_pages(domain, address, size, 0);
    }
    
    /* Flush the whole IO/TLB for a given protection domain */
@@@@@ -667,6 -667,6 -674,9 -687,12 +688,15 @@@@@ static void __init init_iommu_from_pci(
                                        MMIO_GET_LD(range));
        iommu->evt_msi_num = MMIO_MSI_NUM(misc);
    
++ +    if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
++ +            amd_iommu_iotlb_sup = false;
++ +
+++     /* read extended feature bits */
+++     low  = readl(iommu->mmio_base + MMIO_EXT_FEATURES);
+++     high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4);
+++ 
+++     iommu->features = ((u64)high << 32) | low;
+++ 
        if (!is_rd890_iommu(iommu->dev))
                return;
    
Simple merge