Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/iommu/intel/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 125 kB image not shown  

Quelle  iommu.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright © 2006-2014 Intel Corporation.
 *
 * Authors: David Woodhouse <dwmw2@infradead.org>,
 *          Ashok Raj <ashok.raj@intel.com>,
 *          Shaohua Li <shaohua.li@intel.com>,
 *          Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>,
 *          Fenghua Yu <fenghua.yu@intel.com>
 *          Joerg Roedel <jroedel@suse.de>
 */


#define pr_fmt(fmt)     "DMAR: " fmt
#define dev_fmt(fmt)    pr_fmt(fmt)

#include <linux/crash_dump.h>
#include <linux/dma-direct.h>
#include <linux/dmi.h>
#include <linux/memory.h>
#include <linux/pci.h>
#include <linux/pci-ats.h>
#include <linux/spinlock.h>
#include <linux/syscore_ops.h>
#include <linux/tboot.h>
#include <uapi/linux/iommufd.h>

#include "iommu.h"
#include "../dma-iommu.h"
#include "../irq_remapping.h"
#include "../iommu-pages.h"
#include "pasid.h"
#include "perfmon.h"

#define ROOT_SIZE  VTD_PAGE_SIZE
#define CONTEXT_SIZE  VTD_PAGE_SIZE

#define IS_GFX_DEVICE(pdev) pci_is_display(pdev)
#define IS_USB_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_SERIAL_USB)
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)

#define IOAPIC_RANGE_START (0xfee00000)
#define IOAPIC_RANGE_END (0xfeefffff)
#define IOVA_START_ADDR  (0x1000)

#define DEFAULT_DOMAIN_ADDRESS_WIDTH 57

#define __DOMAIN_MAX_PFN(gaw)  ((((uint64_t)1) << ((gaw) - VTD_PAGE_SHIFT)) - 1)
#define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << (gaw)) - 1)

/* We limit DOMAIN_MAX_PFN to fit in an unsigned long, and DOMAIN_MAX_ADDR
   to match. That way, we can use 'unsigned long' for PFNs with impunity. */

#define DOMAIN_MAX_PFN(gaw) ((unsigned long) min_t(uint64_t, \
    __DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)

static void __init check_tylersburg_isoch(void);
static int rwbf_quirk;

#define rwbf_required(iommu) (rwbf_quirk || cap_rwbf((iommu)->cap))

/*
 * set to 1 to panic kernel if can't successfully enable VT-d
 * (used when kernel is launched w/ TXT)
 */

static int force_on = 0;
static int intel_iommu_tboot_noforce;
static int no_platform_optin;

#define ROOT_ENTRY_NR (VTD_PAGE_SIZE/sizeof(struct root_entry))

/*
 * Take a root_entry and return the Lower Context Table Pointer (LCTP)
 * if marked present.
 */

static phys_addr_t root_entry_lctp(struct root_entry *re)
{
 if (!(re->lo & 1))
  return 0;

 return re->lo & VTD_PAGE_MASK;
}

/*
 * Take a root_entry and return the Upper Context Table Pointer (UCTP)
 * if marked present.
 */

static phys_addr_t root_entry_uctp(struct root_entry *re)
{
 if (!(re->hi & 1))
  return 0;

 return re->hi & VTD_PAGE_MASK;
}

static int device_rid_cmp_key(const void *key, const struct rb_node *node)
{
 struct device_domain_info *info =
  rb_entry(node, struct device_domain_info, node);
 const u16 *rid_lhs = key;

 if (*rid_lhs < PCI_DEVID(info->bus, info->devfn))
  return -1;

 if (*rid_lhs > PCI_DEVID(info->bus, info->devfn))
  return 1;

 return 0;
}

static int device_rid_cmp(struct rb_node *lhs, const struct rb_node *rhs)
{
 struct device_domain_info *info =
  rb_entry(lhs, struct device_domain_info, node);
 u16 key = PCI_DEVID(info->bus, info->devfn);

 return device_rid_cmp_key(&key, rhs);
}

/*
 * Looks up an IOMMU-probed device using its source ID.
 *
 * Returns the pointer to the device if there is a match. Otherwise,
 * returns NULL.
 *
 * Note that this helper doesn't guarantee that the device won't be
 * released by the iommu subsystem after being returned. The caller
 * should use its own synchronization mechanism to avoid the device
 * being released during its use if its possibly the case.
 */

struct device *device_rbtree_find(struct intel_iommu *iommu, u16 rid)
{
 struct device_domain_info *info = NULL;
 struct rb_node *node;
 unsigned long flags;

 spin_lock_irqsave(&iommu->device_rbtree_lock, flags);
 node = rb_find(&rid, &iommu->device_rbtree, device_rid_cmp_key);
 if (node)
  info = rb_entry(node, struct device_domain_info, node);
 spin_unlock_irqrestore(&iommu->device_rbtree_lock, flags);

 return info ? info->dev : NULL;
}

static int device_rbtree_insert(struct intel_iommu *iommu,
    struct device_domain_info *info)
{
 struct rb_node *curr;
 unsigned long flags;

 spin_lock_irqsave(&iommu->device_rbtree_lock, flags);
 curr = rb_find_add(&info->node, &iommu->device_rbtree, device_rid_cmp);
 spin_unlock_irqrestore(&iommu->device_rbtree_lock, flags);
 if (WARN_ON(curr))
  return -EEXIST;

 return 0;
}

static void device_rbtree_remove(struct device_domain_info *info)
{
 struct intel_iommu *iommu = info->iommu;
 unsigned long flags;

 spin_lock_irqsave(&iommu->device_rbtree_lock, flags);
 rb_erase(&info->node, &iommu->device_rbtree);
 spin_unlock_irqrestore(&iommu->device_rbtree_lock, flags);
}

struct dmar_rmrr_unit {
 struct list_head list;  /* list of rmrr units */
 struct acpi_dmar_header *hdr; /* ACPI header */
 u64 base_address;  /* reserved base address*/
 u64 end_address;  /* reserved end address */
 struct dmar_dev_scope *devices; /* target devices */
 int devices_cnt;  /* target device count */
};

struct dmar_atsr_unit {
 struct list_head list;  /* list of ATSR units */
 struct acpi_dmar_header *hdr; /* ACPI header */
 struct dmar_dev_scope *devices; /* target devices */
 int devices_cnt;  /* target device count */
 u8 include_all:1;  /* include all ports */
};

struct dmar_satc_unit {
 struct list_head list;  /* list of SATC units */
 struct acpi_dmar_header *hdr; /* ACPI header */
 struct dmar_dev_scope *devices; /* target devices */
 struct intel_iommu *iommu; /* the corresponding iommu */
 int devices_cnt;  /* target device count */
 u8 atc_required:1;  /* ATS is required */
};

static LIST_HEAD(dmar_atsr_units);
static LIST_HEAD(dmar_rmrr_units);
static LIST_HEAD(dmar_satc_units);

#define for_each_rmrr_units(rmrr) \
 list_for_each_entry(rmrr, &dmar_rmrr_units, list)

static void intel_iommu_domain_free(struct iommu_domain *domain);

int dmar_disabled = !IS_ENABLED(CONFIG_INTEL_IOMMU_DEFAULT_ON);
int intel_iommu_sm = IS_ENABLED(CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON);

int intel_iommu_enabled = 0;
EXPORT_SYMBOL_GPL(intel_iommu_enabled);

static int intel_iommu_superpage = 1;
static int iommu_identity_mapping;
static int iommu_skip_te_disable;
static int disable_igfx_iommu;

#define IDENTMAP_AZALIA  4

const struct iommu_ops intel_iommu_ops;
static const struct iommu_dirty_ops intel_dirty_ops;

static bool translation_pre_enabled(struct intel_iommu *iommu)
{
 return (iommu->flags & VTD_FLAG_TRANS_PRE_ENABLED);
}

static void clear_translation_pre_enabled(struct intel_iommu *iommu)
{
 iommu->flags &= ~VTD_FLAG_TRANS_PRE_ENABLED;
}

static void init_translation_status(struct intel_iommu *iommu)
{
 u32 gsts;

 gsts = readl(iommu->reg + DMAR_GSTS_REG);
 if (gsts & DMA_GSTS_TES)
  iommu->flags |= VTD_FLAG_TRANS_PRE_ENABLED;
}

static int __init intel_iommu_setup(char *str)
{
 if (!str)
  return -EINVAL;

 while (*str) {
  if (!strncmp(str, "on", 2)) {
   dmar_disabled = 0;
   pr_info("IOMMU enabled\n");
  } else if (!strncmp(str, "off", 3)) {
   dmar_disabled = 1;
   no_platform_optin = 1;
   pr_info("IOMMU disabled\n");
  } else if (!strncmp(str, "igfx_off", 8)) {
   disable_igfx_iommu = 1;
   pr_info("Disable GFX device mapping\n");
  } else if (!strncmp(str, "forcedac", 8)) {
   pr_warn("intel_iommu=forcedac deprecated; use iommu.forcedac instead\n");
   iommu_dma_forcedac = true;
  } else if (!strncmp(str, "strict", 6)) {
   pr_warn("intel_iommu=strict deprecated; use iommu.strict=1 instead\n");
   iommu_set_dma_strict();
  } else if (!strncmp(str, "sp_off", 6)) {
   pr_info("Disable supported super page\n");
   intel_iommu_superpage = 0;
  } else if (!strncmp(str, "sm_on", 5)) {
   pr_info("Enable scalable mode if hardware supports\n");
   intel_iommu_sm = 1;
  } else if (!strncmp(str, "sm_off", 6)) {
   pr_info("Scalable mode is disallowed\n");
   intel_iommu_sm = 0;
  } else if (!strncmp(str, "tboot_noforce", 13)) {
   pr_info("Intel-IOMMU: not forcing on after tboot. This could expose security risk for tboot\n");
   intel_iommu_tboot_noforce = 1;
  } else {
   pr_notice("Unknown option - '%s'\n", str);
  }

  str += strcspn(str, ",");
  while (*str == ',')
   str++;
 }

 return 1;
}
__setup("intel_iommu=", intel_iommu_setup);

static int domain_pfn_supported(struct dmar_domain *domain, unsigned long pfn)
{
 int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;

 return !(addr_width < BITS_PER_LONG && pfn >> addr_width);
}

/*
 * Calculate the Supported Adjusted Guest Address Widths of an IOMMU.
 * Refer to 11.4.2 of the VT-d spec for the encoding of each bit of
 * the returned SAGAW.
 */

static unsigned long __iommu_calculate_sagaw(struct intel_iommu *iommu)
{
 unsigned long fl_sagaw, sl_sagaw;

 fl_sagaw = BIT(2) | (cap_fl5lp_support(iommu->cap) ? BIT(3) : 0);
 sl_sagaw = cap_sagaw(iommu->cap);

 /* Second level only. */
 if (!sm_supported(iommu) || !ecap_flts(iommu->ecap))
  return sl_sagaw;

 /* First level only. */
 if (!ecap_slts(iommu->ecap))
  return fl_sagaw;

 return fl_sagaw & sl_sagaw;
}

static int __iommu_calculate_agaw(struct intel_iommu *iommu, int max_gaw)
{
 unsigned long sagaw;
 int agaw;

 sagaw = __iommu_calculate_sagaw(iommu);
 for (agaw = width_to_agaw(max_gaw); agaw >= 0; agaw--) {
  if (test_bit(agaw, &sagaw))
   break;
 }

 return agaw;
}

/*
 * Calculate max SAGAW for each iommu.
 */

int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
{
 return __iommu_calculate_agaw(iommu, MAX_AGAW_WIDTH);
}

/*
 * calculate agaw for each iommu.
 * "SAGAW" may be different across iommus, use a default agaw, and
 * get a supported less agaw for iommus that don't support the default agaw.
 */

int iommu_calculate_agaw(struct intel_iommu *iommu)
{
 return __iommu_calculate_agaw(iommu, DEFAULT_DOMAIN_ADDRESS_WIDTH);
}

static bool iommu_paging_structure_coherency(struct intel_iommu *iommu)
{
 return sm_supported(iommu) ?
   ecap_smpwc(iommu->ecap) : ecap_coherent(iommu->ecap);
}

/* Return the super pagesize bitmap if supported. */
static unsigned long domain_super_pgsize_bitmap(struct dmar_domain *domain)
{
 unsigned long bitmap = 0;

 /*
 * 1-level super page supports page size of 2MiB, 2-level super page
 * supports page size of both 2MiB and 1GiB.
 */

 if (domain->iommu_superpage == 1)
  bitmap |= SZ_2M;
 else if (domain->iommu_superpage == 2)
  bitmap |= SZ_2M | SZ_1G;

 return bitmap;
}

struct context_entry *iommu_context_addr(struct intel_iommu *iommu, u8 bus,
      u8 devfn, int alloc)
{
 struct root_entry *root = &iommu->root_entry[bus];
 struct context_entry *context;
 u64 *entry;

 /*
 * Except that the caller requested to allocate a new entry,
 * returning a copied context entry makes no sense.
 */

 if (!alloc && context_copied(iommu, bus, devfn))
  return NULL;

 entry = &root->lo;
 if (sm_supported(iommu)) {
  if (devfn >= 0x80) {
   devfn -= 0x80;
   entry = &root->hi;
  }
  devfn *= 2;
 }
 if (*entry & 1)
  context = phys_to_virt(*entry & VTD_PAGE_MASK);
 else {
  unsigned long phy_addr;
  if (!alloc)
   return NULL;

  context = iommu_alloc_pages_node_sz(iommu->node, GFP_ATOMIC,
          SZ_4K);
  if (!context)
   return NULL;

  __iommu_flush_cache(iommu, (void *)context, CONTEXT_SIZE);
  phy_addr = virt_to_phys((void *)context);
  *entry = phy_addr | 1;
  __iommu_flush_cache(iommu, entry, sizeof(*entry));
 }
 return &context[devfn];
}

/**
 * is_downstream_to_pci_bridge - test if a device belongs to the PCI
 *  sub-hierarchy of a candidate PCI-PCI bridge
 * @dev: candidate PCI device belonging to @bridge PCI sub-hierarchy
 * @bridge: the candidate PCI-PCI bridge
 *
 * Return: true if @dev belongs to @bridge PCI sub-hierarchy, else false.
 */

static bool
is_downstream_to_pci_bridge(struct device *dev, struct device *bridge)
{
 struct pci_dev *pdev, *pbridge;

 if (!dev_is_pci(dev) || !dev_is_pci(bridge))
  return false;

 pdev = to_pci_dev(dev);
 pbridge = to_pci_dev(bridge);

 if (pbridge->subordinate &&
     pbridge->subordinate->number <= pdev->bus->number &&
     pbridge->subordinate->busn_res.end >= pdev->bus->number)
  return true;

 return false;
}

static bool quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
{
 struct dmar_drhd_unit *drhd;
 u32 vtbar;
 int rc;

 /* We know that this device on this chipset has its own IOMMU.
 * If we find it under a different IOMMU, then the BIOS is lying
 * to us. Hope that the IOMMU for this device is actually
 * disabled, and it needs no translation...
 */

 rc = pci_bus_read_config_dword(pdev->bus, PCI_DEVFN(0, 0), 0xb0, &vtbar);
 if (rc) {
  /* "can't" happen */
  dev_info(&pdev->dev, "failed to run vt-d quirk\n");
  return false;
 }
 vtbar &= 0xffff0000;

 /* we know that the this iommu should be at offset 0xa000 from vtbar */
 drhd = dmar_find_matched_drhd_unit(pdev);
 if (!drhd || drhd->reg_base_addr - vtbar != 0xa000) {
  pr_warn_once(FW_BUG "BIOS assigned incorrect VT-d unit for Intel(R) QuickData Technology device\n");
  add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
  return true;
 }

 return false;
}

static bool iommu_is_dummy(struct intel_iommu *iommu, struct device *dev)
{
 if (!iommu || iommu->drhd->ignored)
  return true;

 if (dev_is_pci(dev)) {
  struct pci_dev *pdev = to_pci_dev(dev);

  if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
      pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SNB &&
      quirk_ioat_snb_local_iommu(pdev))
   return true;
 }

 return false;
}

static struct intel_iommu *device_lookup_iommu(struct device *dev, u8 *bus, u8 *devfn)
{
 struct dmar_drhd_unit *drhd = NULL;
 struct pci_dev *pdev = NULL;
 struct intel_iommu *iommu;
 struct device *tmp;
 u16 segment = 0;
 int i;

 if (!dev)
  return NULL;

 if (dev_is_pci(dev)) {
  struct pci_dev *pf_pdev;

  pdev = pci_real_dma_dev(to_pci_dev(dev));

  /* VFs aren't listed in scope tables; we need to look up
 * the PF instead to find the IOMMU. */

  pf_pdev = pci_physfn(pdev);
  dev = &pf_pdev->dev;
  segment = pci_domain_nr(pdev->bus);
 } else if (has_acpi_companion(dev))
  dev = &ACPI_COMPANION(dev)->dev;

 rcu_read_lock();
 for_each_iommu(iommu, drhd) {
  if (pdev && segment != drhd->segment)
   continue;

  for_each_active_dev_scope(drhd->devices,
       drhd->devices_cnt, i, tmp) {
   if (tmp == dev) {
    /* For a VF use its original BDF# not that of the PF
 * which we used for the IOMMU lookup. Strictly speaking
 * we could do this for all PCI devices; we only need to
 * get the BDF# from the scope table for ACPI matches. */

    if (pdev && pdev->is_virtfn)
     goto got_pdev;

    if (bus && devfn) {
     *bus = drhd->devices[i].bus;
     *devfn = drhd->devices[i].devfn;
    }
    goto out;
   }

   if (is_downstream_to_pci_bridge(dev, tmp))
    goto got_pdev;
  }

  if (pdev && drhd->include_all) {
got_pdev:
   if (bus && devfn) {
    *bus = pdev->bus->number;
    *devfn = pdev->devfn;
   }
   goto out;
  }
 }
 iommu = NULL;
out:
 if (iommu_is_dummy(iommu, dev))
  iommu = NULL;

 rcu_read_unlock();

 return iommu;
}

static void domain_flush_cache(struct dmar_domain *domain,
          void *addr, int size)
{
 if (!domain->iommu_coherency)
  clflush_cache_range(addr, size);
}

static void free_context_table(struct intel_iommu *iommu)
{
 struct context_entry *context;
 int i;

 if (!iommu->root_entry)
  return;

 for (i = 0; i < ROOT_ENTRY_NR; i++) {
  context = iommu_context_addr(iommu, i, 0, 0);
  if (context)
   iommu_free_pages(context);

  if (!sm_supported(iommu))
   continue;

  context = iommu_context_addr(iommu, i, 0x80, 0);
  if (context)
   iommu_free_pages(context);
 }

 iommu_free_pages(iommu->root_entry);
 iommu->root_entry = NULL;
}

#ifdef CONFIG_DMAR_DEBUG
static void pgtable_walk(struct intel_iommu *iommu, unsigned long pfn,
    u8 bus, u8 devfn, struct dma_pte *parent, int level)
{
 struct dma_pte *pte;
 int offset;

 while (1) {
  offset = pfn_level_offset(pfn, level);
  pte = &parent[offset];

  pr_info("pte level: %d, pte value: 0x%016llx\n", level, pte->val);

  if (!dma_pte_present(pte)) {
   pr_info("page table not present at level %d\n", level - 1);
   break;
  }

  if (level == 1 || dma_pte_superpage(pte))
   break;

  parent = phys_to_virt(dma_pte_addr(pte));
  level--;
 }
}

void dmar_fault_dump_ptes(struct intel_iommu *iommu, u16 source_id,
     unsigned long long addr, u32 pasid)
{
 struct pasid_dir_entry *dir, *pde;
 struct pasid_entry *entries, *pte;
 struct context_entry *ctx_entry;
 struct root_entry *rt_entry;
 int i, dir_index, index, level;
 u8 devfn = source_id & 0xff;
 u8 bus = source_id >> 8;
 struct dma_pte *pgtable;

 pr_info("Dump %s table entries for IOVA 0x%llx\n", iommu->name, addr);

 /* root entry dump */
 if (!iommu->root_entry) {
  pr_info("root table is not present\n");
  return;
 }
 rt_entry = &iommu->root_entry[bus];

 if (sm_supported(iommu))
  pr_info("scalable mode root entry: hi 0x%016llx, low 0x%016llx\n",
   rt_entry->hi, rt_entry->lo);
 else
  pr_info("root entry: 0x%016llx", rt_entry->lo);

 /* context entry dump */
 ctx_entry = iommu_context_addr(iommu, bus, devfn, 0);
 if (!ctx_entry) {
  pr_info("context table is not present\n");
  return;
 }

 pr_info("context entry: hi 0x%016llx, low 0x%016llx\n",
  ctx_entry->hi, ctx_entry->lo);

 /* legacy mode does not require PASID entries */
 if (!sm_supported(iommu)) {
  if (!context_present(ctx_entry)) {
   pr_info("legacy mode page table is not present\n");
   return;
  }
  level = agaw_to_level(ctx_entry->hi & 7);
  pgtable = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);
  goto pgtable_walk;
 }

 if (!context_present(ctx_entry)) {
  pr_info("pasid directory table is not present\n");
  return;
 }

 /* get the pointer to pasid directory entry */
 dir = phys_to_virt(ctx_entry->lo & VTD_PAGE_MASK);

 /* For request-without-pasid, get the pasid from context entry */
 if (intel_iommu_sm && pasid == IOMMU_PASID_INVALID)
  pasid = IOMMU_NO_PASID;

 dir_index = pasid >> PASID_PDE_SHIFT;
 pde = &dir[dir_index];
 pr_info("pasid dir entry: 0x%016llx\n", pde->val);

 /* get the pointer to the pasid table entry */
 entries = get_pasid_table_from_pde(pde);
 if (!entries) {
  pr_info("pasid table is not present\n");
  return;
 }
 index = pasid & PASID_PTE_MASK;
 pte = &entries[index];
 for (i = 0; i < ARRAY_SIZE(pte->val); i++)
  pr_info("pasid table entry[%d]: 0x%016llx\n", i, pte->val[i]);

 if (!pasid_pte_is_present(pte)) {
  pr_info("scalable mode page table is not present\n");
  return;
 }

 if (pasid_pte_get_pgtt(pte) == PASID_ENTRY_PGTT_FL_ONLY) {
  level = pte->val[2] & BIT_ULL(2) ? 5 : 4;
  pgtable = phys_to_virt(pte->val[2] & VTD_PAGE_MASK);
 } else {
  level = agaw_to_level((pte->val[0] >> 2) & 0x7);
  pgtable = phys_to_virt(pte->val[0] & VTD_PAGE_MASK);
 }

pgtable_walk:
 pgtable_walk(iommu, addr >> VTD_PAGE_SHIFT, bus, devfn, pgtable, level);
}
#endif

static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
          unsigned long pfn, int *target_level,
          gfp_t gfp)
{
 struct dma_pte *parent, *pte;
 int level = agaw_to_level(domain->agaw);
 int offset;

 if (!domain_pfn_supported(domain, pfn))
  /* Address beyond IOMMU's addressing capabilities. */
  return NULL;

 parent = domain->pgd;

 while (1) {
  void *tmp_page;

  offset = pfn_level_offset(pfn, level);
  pte = &parent[offset];
  if (!*target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte)))
   break;
  if (level == *target_level)
   break;

  if (!dma_pte_present(pte)) {
   uint64_t pteval, tmp;

   tmp_page = iommu_alloc_pages_node_sz(domain->nid, gfp,
            SZ_4K);

   if (!tmp_page)
    return NULL;

   domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
   pteval = virt_to_phys(tmp_page) | DMA_PTE_READ |
     DMA_PTE_WRITE;
   if (domain->use_first_level)
    pteval |= DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;

   tmp = 0ULL;
   if (!try_cmpxchg64(&pte->val, &tmp, pteval))
    /* Someone else set it while we were thinking; use theirs. */
    iommu_free_pages(tmp_page);
   else
    domain_flush_cache(domain, pte, sizeof(*pte));
  }
  if (level == 1)
   break;

  parent = phys_to_virt(dma_pte_addr(pte));
  level--;
 }

 if (!*target_level)
  *target_level = level;

 return pte;
}

/* return address's pte at specific level */
static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
      unsigned long pfn,
      int level, int *large_page)
{
 struct dma_pte *parent, *pte;
 int total = agaw_to_level(domain->agaw);
 int offset;

 parent = domain->pgd;
 while (level <= total) {
  offset = pfn_level_offset(pfn, total);
  pte = &parent[offset];
  if (level == total)
   return pte;

  if (!dma_pte_present(pte)) {
   *large_page = total;
   break;
  }

  if (dma_pte_superpage(pte)) {
   *large_page = total;
   return pte;
  }

  parent = phys_to_virt(dma_pte_addr(pte));
  total--;
 }
 return NULL;
}

/* clear last level pte, a tlb flush should be followed */
static void dma_pte_clear_range(struct dmar_domain *domain,
    unsigned long start_pfn,
    unsigned long last_pfn)
{
 unsigned int large_page;
 struct dma_pte *first_pte, *pte;

 if (WARN_ON(!domain_pfn_supported(domain, last_pfn)) ||
     WARN_ON(start_pfn > last_pfn))
  return;

 /* we don't need lock here; nobody else touches the iova range */
 do {
  large_page = 1;
  first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
  if (!pte) {
   start_pfn = align_to_level(start_pfn + 1, large_page + 1);
   continue;
  }
  do {
   dma_clear_pte(pte);
   start_pfn += lvl_to_nr_pages(large_page);
   pte++;
  } while (start_pfn <= last_pfn && !first_pte_in_page(pte));

  domain_flush_cache(domain, first_pte,
       (void *)pte - (void *)first_pte);

 } while (start_pfn && start_pfn <= last_pfn);
}

static void dma_pte_free_level(struct dmar_domain *domain, int level,
          int retain_level, struct dma_pte *pte,
          unsigned long pfn, unsigned long start_pfn,
          unsigned long last_pfn)
{
 pfn = max(start_pfn, pfn);
 pte = &pte[pfn_level_offset(pfn, level)];

 do {
  unsigned long level_pfn;
  struct dma_pte *level_pte;

  if (!dma_pte_present(pte) || dma_pte_superpage(pte))
   goto next;

  level_pfn = pfn & level_mask(level);
  level_pte = phys_to_virt(dma_pte_addr(pte));

  if (level > 2) {
   dma_pte_free_level(domain, level - 1, retain_level,
        level_pte, level_pfn, start_pfn,
        last_pfn);
  }

  /*
 * Free the page table if we're below the level we want to
 * retain and the range covers the entire table.
 */

  if (level < retain_level && !(start_pfn > level_pfn ||
        last_pfn < level_pfn + level_size(level) - 1)) {
   dma_clear_pte(pte);
   domain_flush_cache(domain, pte, sizeof(*pte));
   iommu_free_pages(level_pte);
  }
next:
  pfn += level_size(level);
 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
}

/*
 * clear last level (leaf) ptes and free page table pages below the
 * level we wish to keep intact.
 */

static void dma_pte_free_pagetable(struct dmar_domain *domain,
       unsigned long start_pfn,
       unsigned long last_pfn,
       int retain_level)
{
 dma_pte_clear_range(domain, start_pfn, last_pfn);

 /* We don't need lock here; nobody else touches the iova range */
 dma_pte_free_level(domain, agaw_to_level(domain->agaw), retain_level,
      domain->pgd, 0, start_pfn, last_pfn);

 /* free pgd */
 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
  iommu_free_pages(domain->pgd);
  domain->pgd = NULL;
 }
}

/* When a page at a given level is being unlinked from its parent, we don't
   need to *modify* it at all. All we need to do is make a list of all the
   pages which can be freed just as soon as we've flushed the IOTLB and we
   know the hardware page-walk will no longer touch them.
   The 'pte' argument is the *parent* PTE, pointing to the page that is to
   be freed. */

static void dma_pte_list_pagetables(struct dmar_domain *domain,
        int level, struct dma_pte *parent_pte,
        struct iommu_pages_list *freelist)
{
 struct dma_pte *pte = phys_to_virt(dma_pte_addr(parent_pte));

 iommu_pages_list_add(freelist, pte);

 if (level == 1)
  return;

 do {
  if (dma_pte_present(pte) && !dma_pte_superpage(pte))
   dma_pte_list_pagetables(domain, level - 1, pte, freelist);
  pte++;
 } while (!first_pte_in_page(pte));
}

static void dma_pte_clear_level(struct dmar_domain *domain, int level,
    struct dma_pte *pte, unsigned long pfn,
    unsigned long start_pfn, unsigned long last_pfn,
    struct iommu_pages_list *freelist)
{
 struct dma_pte *first_pte = NULL, *last_pte = NULL;

 pfn = max(start_pfn, pfn);
 pte = &pte[pfn_level_offset(pfn, level)];

 do {
  unsigned long level_pfn = pfn & level_mask(level);

  if (!dma_pte_present(pte))
   goto next;

  /* If range covers entire pagetable, free it */
  if (start_pfn <= level_pfn &&
      last_pfn >= level_pfn + level_size(level) - 1) {
   /* These suborbinate page tables are going away entirely. Don't
   bother to clear them; we're just going to *free* them. */

   if (level > 1 && !dma_pte_superpage(pte))
    dma_pte_list_pagetables(domain, level - 1, pte, freelist);

   dma_clear_pte(pte);
   if (!first_pte)
    first_pte = pte;
   last_pte = pte;
  } else if (level > 1) {
   /* Recurse down into a level that isn't *entirely* obsolete */
   dma_pte_clear_level(domain, level - 1,
         phys_to_virt(dma_pte_addr(pte)),
         level_pfn, start_pfn, last_pfn,
         freelist);
  }
next:
  pfn = level_pfn + level_size(level);
 } while (!first_pte_in_page(++pte) && pfn <= last_pfn);

 if (first_pte)
  domain_flush_cache(domain, first_pte,
       (void *)++last_pte - (void *)first_pte);
}

/* We can't just free the pages because the IOMMU may still be walking
   the page tables, and may have cached the intermediate levels. The
   pages can only be freed after the IOTLB flush has been done. */

static void domain_unmap(struct dmar_domain *domain, unsigned long start_pfn,
    unsigned long last_pfn,
    struct iommu_pages_list *freelist)
{
 if (WARN_ON(!domain_pfn_supported(domain, last_pfn)) ||
     WARN_ON(start_pfn > last_pfn))
  return;

 /* we don't need lock here; nobody else touches the iova range */
 dma_pte_clear_level(domain, agaw_to_level(domain->agaw),
       domain->pgd, 0, start_pfn, last_pfn, freelist);

 /* free pgd */
 if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
  iommu_pages_list_add(freelist, domain->pgd);
  domain->pgd = NULL;
 }
}

/* iommu handling */
static int iommu_alloc_root_entry(struct intel_iommu *iommu)
{
 struct root_entry *root;

 root = iommu_alloc_pages_node_sz(iommu->node, GFP_ATOMIC, SZ_4K);
 if (!root) {
  pr_err("Allocating root entry for %s failed\n",
   iommu->name);
  return -ENOMEM;
 }

 __iommu_flush_cache(iommu, root, ROOT_SIZE);
 iommu->root_entry = root;

 return 0;
}

static void iommu_set_root_entry(struct intel_iommu *iommu)
{
 u64 addr;
 u32 sts;
 unsigned long flag;

 addr = virt_to_phys(iommu->root_entry);
 if (sm_supported(iommu))
  addr |= DMA_RTADDR_SMT;

 raw_spin_lock_irqsave(&iommu->register_lock, flag);
 dmar_writeq(iommu->reg + DMAR_RTADDR_REG, addr);

 writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);

 /* Make sure hardware complete it */
 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
        readl, (sts & DMA_GSTS_RTPS), sts);

 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);

 /*
 * Hardware invalidates all DMA remapping hardware translation
 * caches as part of SRTP flow.
 */

 if (cap_esrtps(iommu->cap))
  return;

 iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
 if (sm_supported(iommu))
  qi_flush_pasid_cache(iommu, 0, QI_PC_GLOBAL, 0);
 iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
}

void iommu_flush_write_buffer(struct intel_iommu *iommu)
{
 u32 val;
 unsigned long flag;

 if (!rwbf_quirk && !cap_rwbf(iommu->cap))
  return;

 raw_spin_lock_irqsave(&iommu->register_lock, flag);
 writel(iommu->gcmd | DMA_GCMD_WBF, iommu->reg + DMAR_GCMD_REG);

 /* Make sure hardware complete it */
 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
        readl, (!(val & DMA_GSTS_WBFS)), val);

 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
}

/* return value determine if we need a write buffer flush */
static void __iommu_flush_context(struct intel_iommu *iommu,
      u16 did, u16 source_id, u8 function_mask,
      u64 type)
{
 u64 val = 0;
 unsigned long flag;

 switch (type) {
 case DMA_CCMD_GLOBAL_INVL:
  val = DMA_CCMD_GLOBAL_INVL;
  break;
 case DMA_CCMD_DOMAIN_INVL:
  val = DMA_CCMD_DOMAIN_INVL|DMA_CCMD_DID(did);
  break;
 case DMA_CCMD_DEVICE_INVL:
  val = DMA_CCMD_DEVICE_INVL|DMA_CCMD_DID(did)
   | DMA_CCMD_SID(source_id) | DMA_CCMD_FM(function_mask);
  break;
 default:
  pr_warn("%s: Unexpected context-cache invalidation type 0x%llx\n",
   iommu->name, type);
  return;
 }
 val |= DMA_CCMD_ICC;

 raw_spin_lock_irqsave(&iommu->register_lock, flag);
 dmar_writeq(iommu->reg + DMAR_CCMD_REG, val);

 /* Make sure hardware complete it */
 IOMMU_WAIT_OP(iommu, DMAR_CCMD_REG,
  dmar_readq, (!(val & DMA_CCMD_ICC)), val);

 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
}

void __iommu_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
    unsigned int size_order, u64 type)
{
 int tlb_offset = ecap_iotlb_offset(iommu->ecap);
 u64 val = 0, val_iva = 0;
 unsigned long flag;

 switch (type) {
 case DMA_TLB_GLOBAL_FLUSH:
  /* global flush doesn't need set IVA_REG */
  val = DMA_TLB_GLOBAL_FLUSH|DMA_TLB_IVT;
  break;
 case DMA_TLB_DSI_FLUSH:
  val = DMA_TLB_DSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
  break;
 case DMA_TLB_PSI_FLUSH:
  val = DMA_TLB_PSI_FLUSH|DMA_TLB_IVT|DMA_TLB_DID(did);
  /* IH bit is passed in as part of address */
  val_iva = size_order | addr;
  break;
 default:
  pr_warn("%s: Unexpected iotlb invalidation type 0x%llx\n",
   iommu->name, type);
  return;
 }

 if (cap_write_drain(iommu->cap))
  val |= DMA_TLB_WRITE_DRAIN;

 raw_spin_lock_irqsave(&iommu->register_lock, flag);
 /* Note: Only uses first TLB reg currently */
 if (val_iva)
  dmar_writeq(iommu->reg + tlb_offset, val_iva);
 dmar_writeq(iommu->reg + tlb_offset + 8, val);

 /* Make sure hardware complete it */
 IOMMU_WAIT_OP(iommu, tlb_offset + 8,
  dmar_readq, (!(val & DMA_TLB_IVT)), val);

 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);

 /* check IOTLB invalidation granularity */
 if (DMA_TLB_IAIG(val) == 0)
  pr_err("Flush IOTLB failed\n");
 if (DMA_TLB_IAIG(val) != DMA_TLB_IIRG(type))
  pr_debug("TLB flush request %Lx, actual %Lx\n",
   (unsigned long long)DMA_TLB_IIRG(type),
   (unsigned long long)DMA_TLB_IAIG(val));
}

static struct device_domain_info *
domain_lookup_dev_info(struct dmar_domain *domain,
         struct intel_iommu *iommu, u8 bus, u8 devfn)
{
 struct device_domain_info *info;
 unsigned long flags;

 spin_lock_irqsave(&domain->lock, flags);
 list_for_each_entry(info, &domain->devices, link) {
  if (info->iommu == iommu && info->bus == bus &&
      info->devfn == devfn) {
   spin_unlock_irqrestore(&domain->lock, flags);
   return info;
  }
 }
 spin_unlock_irqrestore(&domain->lock, flags);

 return NULL;
}

/*
 * The extra devTLB flush quirk impacts those QAT devices with PCI device
 * IDs ranging from 0x4940 to 0x4943. It is exempted from risky_device()
 * check because it applies only to the built-in QAT devices and it doesn't
 * grant additional privileges.
 */

#define BUGGY_QAT_DEVID_MASK 0x4940
static bool dev_needs_extra_dtlb_flush(struct pci_dev *pdev)
{
 if (pdev->vendor != PCI_VENDOR_ID_INTEL)
  return false;

 if ((pdev->device & 0xfffc) != BUGGY_QAT_DEVID_MASK)
  return false;

 return true;
}

static void iommu_enable_pci_ats(struct device_domain_info *info)
{
 struct pci_dev *pdev;

 if (!info->ats_supported)
  return;

 pdev = to_pci_dev(info->dev);
 if (!pci_ats_page_aligned(pdev))
  return;

 if (!pci_enable_ats(pdev, VTD_PAGE_SHIFT))
  info->ats_enabled = 1;
}

static void iommu_disable_pci_ats(struct device_domain_info *info)
{
 if (!info->ats_enabled)
  return;

 pci_disable_ats(to_pci_dev(info->dev));
 info->ats_enabled = 0;
}

static void iommu_enable_pci_pri(struct device_domain_info *info)
{
 struct pci_dev *pdev;

 if (!info->ats_enabled || !info->pri_supported)
  return;

 pdev = to_pci_dev(info->dev);
 /* PASID is required in PRG Response Message. */
 if (info->pasid_enabled && !pci_prg_resp_pasid_required(pdev))
  return;

 if (pci_reset_pri(pdev))
  return;

 if (!pci_enable_pri(pdev, PRQ_DEPTH))
  info->pri_enabled = 1;
}

static void iommu_disable_pci_pri(struct device_domain_info *info)
{
 if (!info->pri_enabled)
  return;

 if (WARN_ON(info->iopf_refcount))
  iopf_queue_remove_device(info->iommu->iopf_queue, info->dev);

 pci_disable_pri(to_pci_dev(info->dev));
 info->pri_enabled = 0;
}

static void intel_flush_iotlb_all(struct iommu_domain *domain)
{
 cache_tag_flush_all(to_dmar_domain(domain));
}

static void iommu_disable_protect_mem_regions(struct intel_iommu *iommu)
{
 u32 pmen;
 unsigned long flags;

 if (!cap_plmr(iommu->cap) && !cap_phmr(iommu->cap))
  return;

 raw_spin_lock_irqsave(&iommu->register_lock, flags);
 pmen = readl(iommu->reg + DMAR_PMEN_REG);
 pmen &= ~DMA_PMEN_EPM;
 writel(pmen, iommu->reg + DMAR_PMEN_REG);

 /* wait for the protected region status bit to clear */
 IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG,
  readl, !(pmen & DMA_PMEN_PRS), pmen);

 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
}

static void iommu_enable_translation(struct intel_iommu *iommu)
{
 u32 sts;
 unsigned long flags;

 raw_spin_lock_irqsave(&iommu->register_lock, flags);
 iommu->gcmd |= DMA_GCMD_TE;
 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);

 /* Make sure hardware complete it */
 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
        readl, (sts & DMA_GSTS_TES), sts);

 raw_spin_unlock_irqrestore(&iommu->register_lock, flags);
}

static void iommu_disable_translation(struct intel_iommu *iommu)
{
 u32 sts;
 unsigned long flag;

 if (iommu_skip_te_disable && iommu->drhd->gfx_dedicated &&
     (cap_read_drain(iommu->cap) || cap_write_drain(iommu->cap)))
  return;

 raw_spin_lock_irqsave(&iommu->register_lock, flag);
 iommu->gcmd &= ~DMA_GCMD_TE;
 writel(iommu->gcmd, iommu->reg + DMAR_GCMD_REG);

 /* Make sure hardware complete it */
 IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
        readl, (!(sts & DMA_GSTS_TES)), sts);

 raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
}

static void disable_dmar_iommu(struct intel_iommu *iommu)
{
 /*
 * All iommu domains must have been detached from the devices,
 * hence there should be no domain IDs in use.
 */

 if (WARN_ON(!ida_is_empty(&iommu->domain_ida)))
  return;

 if (iommu->gcmd & DMA_GCMD_TE)
  iommu_disable_translation(iommu);
}

static void free_dmar_iommu(struct intel_iommu *iommu)
{
 if (iommu->copied_tables) {
  bitmap_free(iommu->copied_tables);
  iommu->copied_tables = NULL;
 }

 /* free context mapping */
 free_context_table(iommu);

 if (ecap_prs(iommu->ecap))
  intel_iommu_finish_prq(iommu);
}

/*
 * Check and return whether first level is used by default for
 * DMA translation.
 */

static bool first_level_by_default(struct intel_iommu *iommu)
{
 /* Only SL is available in legacy mode */
 if (!sm_supported(iommu))
  return false;

 /* Only level (either FL or SL) is available, just use it */
 if (ecap_flts(iommu->ecap) ^ ecap_slts(iommu->ecap))
  return ecap_flts(iommu->ecap);

 return true;
}

int domain_attach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
{
 struct iommu_domain_info *info, *curr;
 int num, ret = -ENOSPC;

 if (domain->domain.type == IOMMU_DOMAIN_SVA)
  return 0;

 info = kzalloc(sizeof(*info), GFP_KERNEL);
 if (!info)
  return -ENOMEM;

 guard(mutex)(&iommu->did_lock);
 curr = xa_load(&domain->iommu_array, iommu->seq_id);
 if (curr) {
  curr->refcnt++;
  kfree(info);
  return 0;
 }

 num = ida_alloc_range(&iommu->domain_ida, IDA_START_DID,
         cap_ndoms(iommu->cap) - 1, GFP_KERNEL);
 if (num < 0) {
  pr_err("%s: No free domain ids\n", iommu->name);
  goto err_unlock;
 }

 info->refcnt = 1;
 info->did = num;
 info->iommu = iommu;
 curr = xa_cmpxchg(&domain->iommu_array, iommu->seq_id,
     NULL, info, GFP_KERNEL);
 if (curr) {
  ret = xa_err(curr) ? : -EBUSY;
  goto err_clear;
 }

 return 0;

err_clear:
 ida_free(&iommu->domain_ida, info->did);
err_unlock:
 kfree(info);
 return ret;
}

void domain_detach_iommu(struct dmar_domain *domain, struct intel_iommu *iommu)
{
 struct iommu_domain_info *info;

 if (domain->domain.type == IOMMU_DOMAIN_SVA)
  return;

 guard(mutex)(&iommu->did_lock);
 info = xa_load(&domain->iommu_array, iommu->seq_id);
 if (--info->refcnt == 0) {
  ida_free(&iommu->domain_ida, info->did);
  xa_erase(&domain->iommu_array, iommu->seq_id);
  kfree(info);
 }
}

/*
 * For kdump cases, old valid entries may be cached due to the
 * in-flight DMA and copied pgtable, but there is no unmapping
 * behaviour for them, thus we need an explicit cache flush for
 * the newly-mapped device. For kdump, at this point, the device
 * is supposed to finish reset at its driver probe stage, so no
 * in-flight DMA will exist, and we don't need to worry anymore
 * hereafter.
 */

static void copied_context_tear_down(struct intel_iommu *iommu,
         struct context_entry *context,
         u8 bus, u8 devfn)
{
 u16 did_old;

 if (!context_copied(iommu, bus, devfn))
  return;

 assert_spin_locked(&iommu->lock);

 did_old = context_domain_id(context);
 context_clear_entry(context);

 if (did_old < cap_ndoms(iommu->cap)) {
  iommu->flush.flush_context(iommu, did_old,
        PCI_DEVID(bus, devfn),
        DMA_CCMD_MASK_NOBIT,
        DMA_CCMD_DEVICE_INVL);
  iommu->flush.flush_iotlb(iommu, did_old, 0, 0,
      DMA_TLB_DSI_FLUSH);
 }

 clear_context_copied(iommu, bus, devfn);
}

/*
 * It's a non-present to present mapping. If hardware doesn't cache
 * non-present entry we only need to flush the write-buffer. If the
 * _does_ cache non-present entries, then it does so in the special
 * domain #0, which we have to flush:
 */

static void context_present_cache_flush(struct intel_iommu *iommu, u16 did,
     u8 bus, u8 devfn)
{
 if (cap_caching_mode(iommu->cap)) {
  iommu->flush.flush_context(iommu, 0,
        PCI_DEVID(bus, devfn),
        DMA_CCMD_MASK_NOBIT,
        DMA_CCMD_DEVICE_INVL);
  iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
 } else {
  iommu_flush_write_buffer(iommu);
 }
}

static int domain_context_mapping_one(struct dmar_domain *domain,
          struct intel_iommu *iommu,
          u8 bus, u8 devfn)
{
 struct device_domain_info *info =
   domain_lookup_dev_info(domain, iommu, bus, devfn);
 u16 did = domain_id_iommu(domain, iommu);
 int translation = CONTEXT_TT_MULTI_LEVEL;
 struct dma_pte *pgd = domain->pgd;
 struct context_entry *context;
 int ret;

 if (WARN_ON(!intel_domain_is_ss_paging(domain)))
  return -EINVAL;

 pr_debug("Set context mapping for %02x:%02x.%d\n",
  bus, PCI_SLOT(devfn), PCI_FUNC(devfn));

 spin_lock(&iommu->lock);
 ret = -ENOMEM;
 context = iommu_context_addr(iommu, bus, devfn, 1);
 if (!context)
  goto out_unlock;

 ret = 0;
 if (context_present(context) && !context_copied(iommu, bus, devfn))
  goto out_unlock;

 copied_context_tear_down(iommu, context, bus, devfn);
 context_clear_entry(context);
 context_set_domain_id(context, did);

 if (info && info->ats_supported)
  translation = CONTEXT_TT_DEV_IOTLB;
 else
  translation = CONTEXT_TT_MULTI_LEVEL;

 context_set_address_root(context, virt_to_phys(pgd));
 context_set_address_width(context, domain->agaw);
 context_set_translation_type(context, translation);
 context_set_fault_enable(context);
 context_set_present(context);
 if (!ecap_coherent(iommu->ecap))
  clflush_cache_range(context, sizeof(*context));
 context_present_cache_flush(iommu, did, bus, devfn);
 ret = 0;

out_unlock:
 spin_unlock(&iommu->lock);

 return ret;
}

static int domain_context_mapping_cb(struct pci_dev *pdev,
         u16 alias, void *opaque)
{
 struct device_domain_info *info = dev_iommu_priv_get(&pdev->dev);
 struct intel_iommu *iommu = info->iommu;
 struct dmar_domain *domain = opaque;

 return domain_context_mapping_one(domain, iommu,
       PCI_BUS_NUM(alias), alias & 0xff);
}

static int
domain_context_mapping(struct dmar_domain *domain, struct device *dev)
{
 struct device_domain_info *info = dev_iommu_priv_get(dev);
 struct intel_iommu *iommu = info->iommu;
 u8 bus = info->bus, devfn = info->devfn;
 int ret;

 if (!dev_is_pci(dev))
  return domain_context_mapping_one(domain, iommu, bus, devfn);

 ret = pci_for_each_dma_alias(to_pci_dev(dev),
         domain_context_mapping_cb, domain);
 if (ret)
  return ret;

 iommu_enable_pci_ats(info);

 return 0;
}

/* Return largest possible superpage level for a given mapping */
static int hardware_largepage_caps(struct dmar_domain *domain, unsigned long iov_pfn,
       unsigned long phy_pfn, unsigned long pages)
{
 int support, level = 1;
 unsigned long pfnmerge;

 support = domain->iommu_superpage;

 /* To use a large page, the virtual *and* physical addresses
   must be aligned to 2MiB/1GiB/etc. Lower bits set in either
   of them will mean we have to use smaller pages. So just
   merge them and check both at once. */

 pfnmerge = iov_pfn | phy_pfn;

 while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
  pages >>= VTD_STRIDE_SHIFT;
  if (!pages)
   break;
  pfnmerge >>= VTD_STRIDE_SHIFT;
  level++;
  support--;
 }
 return level;
}

/*
 * Ensure that old small page tables are removed to make room for superpage(s).
 * We're going to add new large pages, so make sure we don't remove their parent
 * tables. The IOTLB/devTLBs should be flushed if any PDE/PTEs are cleared.
 */

static void switch_to_super_page(struct dmar_domain *domain,
     unsigned long start_pfn,
     unsigned long end_pfn, int level)
{
 unsigned long lvl_pages = lvl_to_nr_pages(level);
 struct dma_pte *pte = NULL;

 if (WARN_ON(!IS_ALIGNED(start_pfn, lvl_pages) ||
      !IS_ALIGNED(end_pfn + 1, lvl_pages)))
  return;

 while (start_pfn <= end_pfn) {
  if (!pte)
   pte = pfn_to_dma_pte(domain, start_pfn, &level,
          GFP_ATOMIC);

  if (dma_pte_present(pte)) {
   dma_pte_free_pagetable(domain, start_pfn,
            start_pfn + lvl_pages - 1,
            level + 1);

   cache_tag_flush_range(domain, start_pfn << VTD_PAGE_SHIFT,
           end_pfn << VTD_PAGE_SHIFT, 0);
  }

  pte++;
  start_pfn += lvl_pages;
  if (first_pte_in_page(pte))
   pte = NULL;
 }
}

static int
__domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
   unsigned long phys_pfn, unsigned long nr_pages, int prot,
   gfp_t gfp)
{
 struct dma_pte *first_pte = NULL, *pte = NULL;
 unsigned int largepage_lvl = 0;
 unsigned long lvl_pages = 0;
 phys_addr_t pteval;
 u64 attr;

 if (unlikely(!domain_pfn_supported(domain, iov_pfn + nr_pages - 1)))
  return -EINVAL;

 if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
  return -EINVAL;

 if (!(prot & DMA_PTE_WRITE) && domain->nested_parent) {
  pr_err_ratelimited("Read-only mapping is disallowed on the domain which serves as the parent in a nested configuration, due to HW errata (ERRATA_772415_SPR17)\n");
  return -EINVAL;
 }

 attr = prot & (DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP);
 if (domain->use_first_level) {
  attr |= DMA_FL_PTE_PRESENT | DMA_FL_PTE_US | DMA_FL_PTE_ACCESS;
  if (prot & DMA_PTE_WRITE)
   attr |= DMA_FL_PTE_DIRTY;
 }

 domain->has_mappings = true;

 pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | attr;

 while (nr_pages > 0) {
  uint64_t tmp;

  if (!pte) {
   largepage_lvl = hardware_largepage_caps(domain, iov_pfn,
     phys_pfn, nr_pages);

   pte = pfn_to_dma_pte(domain, iov_pfn, &largepage_lvl,
          gfp);
   if (!pte)
    return -ENOMEM;
   first_pte = pte;

   lvl_pages = lvl_to_nr_pages(largepage_lvl);

   /* It is large page*/
   if (largepage_lvl > 1) {
    unsigned long end_pfn;
    unsigned long pages_to_remove;

    pteval |= DMA_PTE_LARGE_PAGE;
    pages_to_remove = min_t(unsigned long,
       round_down(nr_pages, lvl_pages),
       nr_pte_to_next_page(pte) * lvl_pages);
    end_pfn = iov_pfn + pages_to_remove - 1;
    switch_to_super_page(domain, iov_pfn, end_pfn, largepage_lvl);
   } else {
    pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
   }

  }
  /* We don't need lock here, nobody else
 * touches the iova range
 */

  tmp = 0ULL;
  if (!try_cmpxchg64_local(&pte->val, &tmp, pteval)) {
   static int dumps = 5;
   pr_crit("ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
    iov_pfn, tmp, (unsigned long long)pteval);
   if (dumps) {
    dumps--;
    debug_dma_dump_mappings(NULL);
   }
   WARN_ON(1);
  }

  nr_pages -= lvl_pages;
  iov_pfn += lvl_pages;
  phys_pfn += lvl_pages;
  pteval += lvl_pages * VTD_PAGE_SIZE;

  /* If the next PTE would be the first in a new page, then we
 * need to flush the cache on the entries we've just written.
 * And then we'll need to recalculate 'pte', so clear it and
 * let it get set again in the if (!pte) block above.
 *
 * If we're done (!nr_pages) we need to flush the cache too.
 *
 * Also if we've been setting superpages, we may need to
 * recalculate 'pte' and switch back to smaller pages for the
 * end of the mapping, if the trailing size is not enough to
 * use another superpage (i.e. nr_pages < lvl_pages).
 */

  pte++;
  if (!nr_pages || first_pte_in_page(pte) ||
      (largepage_lvl > 1 && nr_pages < lvl_pages)) {
   domain_flush_cache(domain, first_pte,
        (void *)pte - (void *)first_pte);
   pte = NULL;
  }
 }

 return 0;
}

static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 devfn)
{
 struct intel_iommu *iommu = info->iommu;
 struct context_entry *context;
 u16 did;

 spin_lock(&iommu->lock);
 context = iommu_context_addr(iommu, bus, devfn, 0);
 if (!context) {
  spin_unlock(&iommu->lock);
  return;
 }

 did = context_domain_id(context);
 context_clear_entry(context);
 __iommu_flush_cache(iommu, context, sizeof(*context));
 spin_unlock(&iommu->lock);
 intel_context_flush_no_pasid(info, context, did);
}

int __domain_setup_first_level(struct intel_iommu *iommu, struct device *dev,
          ioasid_t pasid, u16 did, phys_addr_t fsptptr,
          int flags, struct iommu_domain *old)
{
 if (!old)
  return intel_pasid_setup_first_level(iommu, dev, fsptptr, pasid,
           did, flags);
 return intel_pasid_replace_first_level(iommu, dev, fsptptr, pasid, did,
            iommu_domain_did(old, iommu),
            flags);
}

static int domain_setup_second_level(struct intel_iommu *iommu,
         struct dmar_domain *domain,
         struct device *dev, ioasid_t pasid,
         struct iommu_domain *old)
{
 if (!old)
  return intel_pasid_setup_second_level(iommu, domain,
            dev, pasid);
 return intel_pasid_replace_second_level(iommu, domain, dev,
      iommu_domain_did(old, iommu),
      pasid);
}

static int domain_setup_passthrough(struct intel_iommu *iommu,
        struct device *dev, ioasid_t pasid,
        struct iommu_domain *old)
{
 if (!old)
  return intel_pasid_setup_pass_through(iommu, dev, pasid);
 return intel_pasid_replace_pass_through(iommu, dev,
      iommu_domain_did(old, iommu),
      pasid);
}

static int domain_setup_first_level(struct intel_iommu *iommu,
        struct dmar_domain *domain,
        struct device *dev,
        u32 pasid, struct iommu_domain *old)
{
 struct dma_pte *pgd = domain->pgd;
 int level, flags = 0;

 level = agaw_to_level(domain->agaw);
 if (level != 4 && level != 5)
  return -EINVAL;

 if (level == 5)
  flags |= PASID_FLAG_FL5LP;

 if (domain->force_snooping)
  flags |= PASID_FLAG_PAGE_SNOOP;

 return __domain_setup_first_level(iommu, dev, pasid,
       domain_id_iommu(domain, iommu),
       __pa(pgd), flags, old);
}

static int dmar_domain_attach_device(struct dmar_domain *domain,
         struct device *dev)
{
 struct device_domain_info *info = dev_iommu_priv_get(dev);
 struct intel_iommu *iommu = info->iommu;
 unsigned long flags;
 int ret;

 ret = domain_attach_iommu(domain, iommu);
 if (ret)
  return ret;

 info->domain = domain;
 info->domain_attached = true;
 spin_lock_irqsave(&domain->lock, flags);
 list_add(&info->link, &domain->devices);
 spin_unlock_irqrestore(&domain->lock, flags);

 if (dev_is_real_dma_subdevice(dev))
  return 0;

 if (!sm_supported(iommu))
  ret = domain_context_mapping(domain, dev);
 else if (intel_domain_is_fs_paging(domain))
  ret = domain_setup_first_level(iommu, domain, dev,
            IOMMU_NO_PASID, NULL);
 else if (intel_domain_is_ss_paging(domain))
  ret = domain_setup_second_level(iommu, domain, dev,
      IOMMU_NO_PASID, NULL);
 else if (WARN_ON(true))
  ret = -EINVAL;

 if (ret)
  goto out_block_translation;

 ret = cache_tag_assign_domain(domain, dev, IOMMU_NO_PASID);
 if (ret)
  goto out_block_translation;

 return 0;

out_block_translation:
 device_block_translation(dev);
 return ret;
}

/**
 * device_rmrr_is_relaxable - Test whether the RMRR of this device
 * is relaxable (ie. is allowed to be not enforced under some conditions)
 * @dev: device handle
 *
 * We assume that PCI USB devices with RMRRs have them largely
 * for historical reasons and that the RMRR space is not actively used post
 * boot.  This exclusion may change if vendors begin to abuse it.
 *
 * The same exception is made for graphics devices, with the requirement that
 * any use of the RMRR regions will be torn down before assigning the device
 * to a guest.
 *
 * Return: true if the RMRR is relaxable, false otherwise
 */

static bool device_rmrr_is_relaxable(struct device *dev)
{
 struct pci_dev *pdev;

 if (!dev_is_pci(dev))
  return false;

 pdev = to_pci_dev(dev);
 if (IS_USB_DEVICE(pdev) || IS_GFX_DEVICE(pdev))
  return true;
 else
  return false;
}

static int device_def_domain_type(struct device *dev)
{
 struct device_domain_info *info = dev_iommu_priv_get(dev);
 struct intel_iommu *iommu = info->iommu;

 /*
 * Hardware does not support the passthrough translation mode.
 * Always use a dynamaic mapping domain.
 */

 if (!ecap_pass_through(iommu->ecap))
  return IOMMU_DOMAIN_DMA;

 if (dev_is_pci(dev)) {
  struct pci_dev *pdev = to_pci_dev(dev);

  if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
   return IOMMU_DOMAIN_IDENTITY;
 }

 return 0;
}

static void intel_iommu_init_qi(struct intel_iommu *iommu)
{
 /*
 * Start from the sane iommu hardware state.
 * If the queued invalidation is already initialized by us
 * (for example, while enabling interrupt-remapping) then
 * we got the things already rolling from a sane state.
 */

 if (!iommu->qi) {
  /*
 * Clear any previous faults.
 */

  dmar_fault(-1, iommu);
  /*
 * Disable queued invalidation if supported and already enabled
 * before OS handover.
 */

  dmar_disable_qi(iommu);
 }

 if (dmar_enable_qi(iommu)) {
  /*
 * Queued Invalidate not enabled, use Register Based Invalidate
 */

  iommu->flush.flush_context = __iommu_flush_context;
  iommu->flush.flush_iotlb = __iommu_flush_iotlb;
  pr_info("%s: Using Register based invalidation\n",
   iommu->name);
 } else {
  iommu->flush.flush_context = qi_flush_context;
  iommu->flush.flush_iotlb = qi_flush_iotlb;
  pr_info("%s: Using Queued invalidation\n", iommu->name);
 }
}

static int copy_context_table(struct intel_iommu *iommu,
         struct root_entry *old_re,
         struct context_entry **tbl,
         int bus, bool ext)
{
 int tbl_idx, pos = 0, idx, devfn, ret = 0, did;
 struct context_entry *new_ce = NULL, ce;
 struct context_entry *old_ce = NULL;
 struct root_entry re;
 phys_addr_t old_ce_phys;

 tbl_idx = ext ? bus * 2 : bus;
 memcpy(&re, old_re, sizeof(re));

 for (devfn = 0; devfn < 256; devfn++) {
  /* First calculate the correct index */
  idx = (ext ? devfn * 2 : devfn) % 256;

  if (idx == 0) {
   /* First save what we may have and clean up */
   if (new_ce) {
    tbl[tbl_idx] = new_ce;
    __iommu_flush_cache(iommu, new_ce,
          VTD_PAGE_SIZE);
    pos = 1;
   }

   if (old_ce)
    memunmap(old_ce);

   ret = 0;
   if (devfn < 0x80)
    old_ce_phys = root_entry_lctp(&re);
   else
    old_ce_phys = root_entry_uctp(&re);

   if (!old_ce_phys) {
    if (ext && devfn == 0) {
     /* No LCTP, try UCTP */
     devfn = 0x7f;
     continue;
    } else {
     goto out;
    }
   }

   ret = -ENOMEM;
   old_ce = memremap(old_ce_phys, PAGE_SIZE,
     MEMREMAP_WB);
   if (!old_ce)
    goto out;

   new_ce = iommu_alloc_pages_node_sz(iommu->node,
          GFP_KERNEL, SZ_4K);
   if (!new_ce)
    goto out_unmap;

   ret = 0;
  }

  /* Now copy the context entry */
  memcpy(&ce, old_ce + idx, sizeof(ce));

  if (!context_present(&ce))
   continue;

  did = context_domain_id(&ce);
  if (did >= 0 && did < cap_ndoms(iommu->cap))
   ida_alloc_range(&iommu->domain_ida, did, did, GFP_KERNEL);

  set_context_copied(iommu, bus, devfn);
  new_ce[idx] = ce;
 }

 tbl[tbl_idx + pos] = new_ce;

 __iommu_flush_cache(iommu, new_ce, VTD_PAGE_SIZE);

out_unmap:
 memunmap(old_ce);

out:
 return ret;
}

static int copy_translation_tables(struct intel_iommu *iommu)
{
 struct context_entry **ctxt_tbls;
 struct root_entry *old_rt;
 phys_addr_t old_rt_phys;
 int ctxt_table_entries;
 u64 rtaddr_reg;
 int bus, ret;
 bool new_ext, ext;

 rtaddr_reg = dmar_readq(iommu->reg + DMAR_RTADDR_REG);
 ext        = !!(rtaddr_reg & DMA_RTADDR_SMT);
 new_ext    = !!sm_supported(iommu);

 /*
 * The RTT bit can only be changed when translation is disabled,
 * but disabling translation means to open a window for data
 * corruption. So bail out and don't copy anything if we would
 * have to change the bit.
 */

 if (new_ext != ext)
  return -EINVAL;

 iommu->copied_tables = bitmap_zalloc(BIT_ULL(16), GFP_KERNEL);
 if (!iommu->copied_tables)
  return -ENOMEM;

 old_rt_phys = rtaddr_reg & VTD_PAGE_MASK;
 if (!old_rt_phys)
  return -EINVAL;

 old_rt = memremap(old_rt_phys, PAGE_SIZE, MEMREMAP_WB);
 if (!old_rt)
  return -ENOMEM;

 /* This is too big for the stack - allocate it from slab */
 ctxt_table_entries = ext ? 512 : 256;
 ret = -ENOMEM;
 ctxt_tbls = kcalloc(ctxt_table_entries, sizeof(void *), GFP_KERNEL);
 if (!ctxt_tbls)
  goto out_unmap;

 for (bus = 0; bus < 256; bus++) {
  ret = copy_context_table(iommu, &old_rt[bus],
      ctxt_tbls, bus, ext);
  if (ret) {
   pr_err("%s: Failed to copy context table for bus %d\n",
    iommu->name, bus);
   continue;
  }
 }

 spin_lock(&iommu->lock);

 /* Context tables are copied, now write them to the root_entry table */
 for (bus = 0; bus < 256; bus++) {
  int idx = ext ? bus * 2 : bus;
  u64 val;

  if (ctxt_tbls[idx]) {
   val = virt_to_phys(ctxt_tbls[idx]) | 1;
   iommu->root_entry[bus].lo = val;
  }

  if (!ext || !ctxt_tbls[idx + 1])
   continue;

  val = virt_to_phys(ctxt_tbls[idx + 1]) | 1;
  iommu->root_entry[bus].hi = val;
 }

 spin_unlock(&iommu->lock);

 kfree(ctxt_tbls);

 __iommu_flush_cache(iommu, iommu->root_entry, PAGE_SIZE);

 ret = 0;

out_unmap:
 memunmap(old_rt);

 return ret;
}

static int __init init_dmars(void)
{
 struct dmar_drhd_unit *drhd;
 struct intel_iommu *iommu;
 int ret;

 for_each_iommu(iommu, drhd) {
  if (drhd->ignored) {
   iommu_disable_translation(iommu);
   continue;
  }

  /*
 * Find the max pasid size of all IOMMU's in the system.
 * We need to ensure the system pasid table is no bigger
 * than the smallest supported.
 */

  if (pasid_supported(iommu)) {
   u32 temp = 2 << ecap_pss(iommu->ecap);

   intel_pasid_max_id = min_t(u32, temp,
         intel_pasid_max_id);
  }

  intel_iommu_init_qi(iommu);
  init_translation_status(iommu);

  if (translation_pre_enabled(iommu) && !is_kdump_kernel()) {
   iommu_disable_translation(iommu);
   clear_translation_pre_enabled(iommu);
   pr_warn("Translation was enabled for %s but we are not in kdump mode\n",
    iommu->name);
  }

  /*
 * TBD:
 * we could share the same root & context tables
 * among all IOMMU's. Need to Split it later.
 */

  ret = iommu_alloc_root_entry(iommu);
  if (ret)
   goto free_iommu;

  if (translation_pre_enabled(iommu)) {
   pr_info("Translation already enabled - trying to copy translation structures\n");

   ret = copy_translation_tables(iommu);
   if (ret) {
    /*
 * We found the IOMMU with translation
 * enabled - but failed to copy over the
 * old root-entry table. Try to proceed
 * by disabling translation now and
 * allocating a clean root-entry table.
 * This might cause DMAR faults, but
 * probably the dump will still succeed.
 */

    pr_err("Failed to copy translation tables from previous kernel for %s\n",
           iommu->name);
    iommu_disable_translation(iommu);
    clear_translation_pre_enabled(iommu);
   } else {
    pr_info("Copied translation tables from previous kernel for %s\n",
     iommu->name);
   }
  }

  intel_svm_check(iommu);
 }

 /*
 * Now that qi is enabled on all iommus, set the root entry and flush
 * caches. This is required on some Intel X58 chipsets, otherwise the
 * flush_context function will loop forever and the boot hangs.
 */

 for_each_active_iommu(iommu, drhd) {
  iommu_flush_write_buffer(iommu);
  iommu_set_root_entry(iommu);
 }

 check_tylersburg_isoch();

 /*
 * for each drhd
 *   enable fault log
 *   global invalidate context cache
 *   global invalidate iotlb
 *   enable translation
 */

 for_each_iommu(iommu, drhd) {
  if (drhd->ignored) {
   /*
 * we always have to disable PMRs or DMA may fail on
 * this device
 */

   if (force_on)
    iommu_disable_protect_mem_regions(iommu);
   continue;
  }

  iommu_flush_write_buffer(iommu);

  if (ecap_prs(iommu->ecap)) {
   /*
 * Call dmar_alloc_hwirq() with dmar_global_lock held,
 * could cause possible lock race condition.
 */

   up_write(&dmar_global_lock);
   ret = intel_iommu_enable_prq(iommu);
   down_write(&dmar_global_lock);
   if (ret)
    goto free_iommu;
  }

  ret = dmar_set_interrupt(iommu);
  if (ret)
   goto free_iommu;
 }

 return 0;

free_iommu:
 for_each_active_iommu(iommu, drhd) {
  disable_dmar_iommu(iommu);
  free_dmar_iommu(iommu);
 }

 return ret;
}

static void __init init_no_remapping_devices(void)
{
 struct dmar_drhd_unit *drhd;
 struct device *dev;
 int i;

 for_each_drhd_unit(drhd) {
  if (!drhd->include_all) {
   for_each_active_dev_scope(drhd->devices,
        drhd->devices_cnt, i, dev)
    break;
   /* ignore DMAR unit if no devices exist */
   if (i == drhd->devices_cnt)
    drhd->ignored = 1;
  }
 }

 for_each_active_drhd_unit(drhd) {
  if (drhd->include_all)
   continue;

  for_each_active_dev_scope(drhd->devices,
       drhd->devices_cnt, i, dev)
   if (!dev_is_pci(dev) || !IS_GFX_DEVICE(to_pci_dev(dev)))
    break;
  if (i < drhd->devices_cnt)
   continue;

  /* This IOMMU has *only* gfx devices. Either bypass it or
   set the gfx_mapped flag, as appropriate */

  drhd->gfx_dedicated = 1;
  if (disable_igfx_iommu)
   drhd->ignored = 1;
 }
}

#ifdef CONFIG_SUSPEND
static int init_iommu_hw(void)
{
 struct dmar_drhd_unit *drhd;
 struct intel_iommu *iommu = NULL;
 int ret;

 for_each_active_iommu(iommu, drhd) {
  if (iommu->qi) {
   ret = dmar_reenable_qi(iommu);
   if (ret)
    return ret;
  }
 }

 for_each_iommu(iommu, drhd) {
  if (drhd->ignored) {
   /*
 * we always have to disable PMRs or DMA may fail on
 * this device
 */

   if (force_on)
    iommu_disable_protect_mem_regions(iommu);
   continue;
  }

  iommu_flush_write_buffer(iommu);
  iommu_set_root_entry(iommu);
  iommu_enable_translation(iommu);
  iommu_disable_protect_mem_regions(iommu);
 }

 return 0;
}

static void iommu_flush_all(void)
{
 struct dmar_drhd_unit *drhd;
 struct intel_iommu *iommu;

 for_each_active_iommu(iommu, drhd) {
  iommu->flush.flush_context(iommu, 0, 0, 0,
        DMA_CCMD_GLOBAL_INVL);
  iommu->flush.flush_iotlb(iommu, 0, 0, 0,
      DMA_TLB_GLOBAL_FLUSH);
 }
}

static int iommu_suspend(void)
{
 struct dmar_drhd_unit *drhd;
 struct intel_iommu *iommu = NULL;
 unsigned long flag;

 iommu_flush_all();

 for_each_active_iommu(iommu, drhd) {
  iommu_disable_translation(iommu);

  raw_spin_lock_irqsave(&iommu->register_lock, flag);

  iommu->iommu_state[SR_DMAR_FECTL_REG] =
   readl(iommu->reg + DMAR_FECTL_REG);
  iommu->iommu_state[SR_DMAR_FEDATA_REG] =
   readl(iommu->reg + DMAR_FEDATA_REG);
  iommu->iommu_state[SR_DMAR_FEADDR_REG] =
   readl(iommu->reg + DMAR_FEADDR_REG);
  iommu->iommu_state[SR_DMAR_FEUADDR_REG] =
   readl(iommu->reg + DMAR_FEUADDR_REG);

  raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
 return 0;
}

static void iommu_resume(void)
{
 struct dmar_drhd_unit *drhd;
 struct intel_iommu *iommu = NULL;
 unsigned long flag;

 if (init_iommu_hw()) {
  if (force_on)
   panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
  else
   WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
  return;
 }

 for_each_active_iommu(iommu, drhd) {

  raw_spin_lock_irqsave(&iommu->register_lock, flag);

  writel(iommu->iommu_state[SR_DMAR_FECTL_REG],
   iommu->reg + DMAR_FECTL_REG);
  writel(iommu->iommu_state[SR_DMAR_FEDATA_REG],
   iommu->reg + DMAR_FEDATA_REG);
  writel(iommu->iommu_state[SR_DMAR_FEADDR_REG],
   iommu->reg + DMAR_FEADDR_REG);
  writel(iommu->iommu_state[SR_DMAR_FEUADDR_REG],
   iommu->reg + DMAR_FEUADDR_REG);

  raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
}

static struct syscore_ops iommu_syscore_ops = {
 .resume  = iommu_resume,
 .suspend = iommu_suspend,
};

static void __init init_iommu_pm_ops(void)
{
 register_syscore_ops(&iommu_syscore_ops);
}

#else
static inline void init_iommu_pm_ops(void) {}
#endif /* CONFIG_PM */

static int __init rmrr_sanity_check(struct acpi_dmar_reserved_memory *rmrr)
{
 if (!IS_ALIGNED(rmrr->base_address, PAGE_SIZE) ||
     !IS_ALIGNED(rmrr->end_address + 1, PAGE_SIZE) ||
     rmrr->end_address <= rmrr->base_address ||
     arch_rmrr_sanity_check(rmrr))
  return -EINVAL;

 return 0;
}

int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
{
 struct acpi_dmar_reserved_memory *rmrr;
 struct dmar_rmrr_unit *rmrru;

 rmrr = (struct acpi_dmar_reserved_memory *)header;
 if (rmrr_sanity_check(rmrr)) {
  pr_warn(FW_BUG
      "Your BIOS is broken; bad RMRR [%#018Lx-%#018Lx]\n"
      "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
      rmrr->base_address, rmrr->end_address,
      dmi_get_system_info(DMI_BIOS_VENDOR),
      dmi_get_system_info(DMI_BIOS_VERSION),
      dmi_get_system_info(DMI_PRODUCT_VERSION));
  add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
 }

 rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
 if (!rmrru)
  goto out;

 rmrru->hdr = header;

 rmrru->base_address = rmrr->base_address;
 rmrru->end_address = rmrr->end_address;

 rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1),
    ((void *)rmrr) + rmrr->header.length,
    &rmrru->devices_cnt);
 if (rmrru->devices_cnt && rmrru->devices == NULL)
  goto free_rmrru;

 list_add(&rmrru->list, &dmar_rmrr_units);

 return 0;
free_rmrru:
 kfree(rmrru);
out:
 return -ENOMEM;
}

static struct dmar_atsr_unit *dmar_find_atsr(struct acpi_dmar_atsr *atsr)
{
 struct dmar_atsr_unit *atsru;
 struct acpi_dmar_atsr *tmp;

 list_for_each_entry_rcu(atsru, &dmar_atsr_units, list,
    dmar_rcu_check()) {
  tmp = (struct acpi_dmar_atsr *)atsru->hdr;
  if (atsr->segment != tmp->segment)
   continue;
  if (atsr->header.length != tmp->header.length)
   continue;
  if (memcmp(atsr, tmp, atsr->header.length) == 0)
   return atsru;
 }

 return NULL;
}

int dmar_parse_one_atsr(struct acpi_dmar_header *hdr, void *arg)
{
 struct acpi_dmar_atsr *atsr;
 struct dmar_atsr_unit *atsru;

 if (system_state >= SYSTEM_RUNNING && !intel_iommu_enabled)
  return 0;

 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
 atsru = dmar_find_atsr(atsr);
 if (atsru)
  return 0;

 atsru = kzalloc(sizeof(*atsru) + hdr->length, GFP_KERNEL);
 if (!atsru)
  return -ENOMEM;

 /*
 * If memory is allocated from slab by ACPI _DSM method, we need to
 * copy the memory content because the memory buffer will be freed
 * on return.
 */

 atsru->hdr = (void *)(atsru + 1);
 memcpy(atsru->hdr, hdr, hdr->length);
 atsru->include_all = atsr->flags & 0x1;
 if (!atsru->include_all) {
  atsru->devices = dmar_alloc_dev_scope((void *)(atsr + 1),
    (void *)atsr + atsr->header.length,
    &atsru->devices_cnt);
  if (atsru->devices_cnt && atsru->devices == NULL) {
   kfree(atsru);
   return -ENOMEM;
  }
 }

 list_add_rcu(&atsru->list, &dmar_atsr_units);

 return 0;
}

static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
{
 dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
 kfree(atsru);
}

int dmar_release_one_atsr(struct acpi_dmar_header *hdr, void *arg)
{
 struct acpi_dmar_atsr *atsr;
 struct dmar_atsr_unit *atsru;

 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
 atsru = dmar_find_atsr(atsr);
 if (atsru) {
  list_del_rcu(&atsru->list);
  synchronize_rcu();
  intel_iommu_free_atsr(atsru);
 }

 return 0;
}

int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg)
{
 int i;
 struct device *dev;
 struct acpi_dmar_atsr *atsr;
 struct dmar_atsr_unit *atsru;

 atsr = container_of(hdr, struct acpi_dmar_atsr, header);
 atsru = dmar_find_atsr(atsr);
 if (!atsru)
  return 0;

 if (!atsru->include_all && atsru->devices && atsru->devices_cnt) {
  for_each_active_dev_scope(atsru->devices, atsru->devices_cnt,
       i, dev)
   return -EBUSY;
 }

 return 0;
}

static struct dmar_satc_unit *dmar_find_satc(struct acpi_dmar_satc *satc)
{
 struct dmar_satc_unit *satcu;
 struct acpi_dmar_satc *tmp;

 list_for_each_entry_rcu(satcu, &dmar_satc_units, list,
    dmar_rcu_check()) {
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=88 G=91

¤ Dauer der Verarbeitung: 0.21 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.