Merge git://git.infradead.org/iommu-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Sep 2009 17:06:10 +0000 (10:06 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 23 Sep 2009 17:06:10 +0000 (10:06 -0700)
* git://git.infradead.org/iommu-2.6: (23 commits)
  intel-iommu: Disable PMRs after we enable translation, not before
  intel-iommu: Kill DMAR_BROKEN_GFX_WA option.
  intel-iommu: Fix integer wrap on 32 bit kernels
  intel-iommu: Fix integer overflow in dma_pte_{clear_range,free_pagetable}()
  intel-iommu: Limit DOMAIN_MAX_PFN to fit in an 'unsigned long'
  intel-iommu: Fix kernel hang if interrupt remapping disabled in BIOS
  intel-iommu: Disallow interrupt remapping if not all ioapics covered
  intel-iommu: include linux/dmi.h to use dmi_ routines
  pci/dmar: correct off-by-one error in dmar_fault()
  intel-iommu: Cope with yet another BIOS screwup causing crashes
  intel-iommu: iommu init error path bug fixes
  intel-iommu: Mark functions with __init
  USB: Work around BIOS bugs by quiescing USB controllers earlier
  ia64: IOMMU passthrough mode shouldn't trigger swiotlb init
  intel-iommu: make domain_add_dev_info() call domain_context_mapping()
  intel-iommu: Unify hardware and software passthrough support
  intel-iommu: Cope with broken HP DC7900 BIOS
  iommu=pt is a valid early param
  intel-iommu: double kfree()
  intel-iommu: Kill pointless intel_unmap_single() function
  ...

Fixed up trivial include lines conflict in drivers/pci/intel-iommu.c

1  2 
arch/x86/Kconfig
arch/x86/kernel/pci-swiotlb.c
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c

diff --combined arch/x86/Kconfig
@@@ -24,7 -24,6 +24,7 @@@ config X8
        select HAVE_UNSTABLE_SCHED_CLOCK
        select HAVE_IDE
        select HAVE_OPROFILE
 +      select HAVE_PERF_EVENTS if (!M386 && !M486)
        select HAVE_IOREMAP_PROT
        select HAVE_KPROBES
        select ARCH_WANT_OPTIONAL_GPIOLIB
@@@ -38,7 -37,7 +38,7 @@@
        select HAVE_FUNCTION_GRAPH_FP_TEST
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
 -      select HAVE_FTRACE_SYSCALLS
 +      select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_KVM
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
@@@ -150,10 -149,7 +150,10 @@@ config ARCH_HAS_CACHE_LINE_SIZ
  config HAVE_SETUP_PER_CPU_AREA
        def_bool y
  
 -config HAVE_DYNAMIC_PER_CPU_AREA
 +config NEED_PER_CPU_EMBED_FIRST_CHUNK
 +      def_bool y
 +
 +config NEED_PER_CPU_PAGE_FIRST_CHUNK
        def_bool y
  
  config HAVE_CPUMASK_OF_CPU_MAP
@@@ -182,10 -178,6 +182,10 @@@ config ARCH_SUPPORTS_OPTIMIZED_INLININ
  config ARCH_SUPPORTS_DEBUG_PAGEALLOC
        def_bool y
  
 +config HAVE_INTEL_TXT
 +      def_bool y
 +      depends on EXPERIMENTAL && DMAR && ACPI
 +
  # Use the generic interrupt handling code in kernel/irq/:
  config GENERIC_HARDIRQS
        bool
@@@ -325,7 -317,6 +325,7 @@@ config X86_EXTENDED_PLATFOR
                SGI 320/540 (Visual Workstation)
                Summit/EXA (IBM x440)
                Unisys ES7000 IA32 series
 +              Moorestown MID devices
  
          If you have one of these systems, or if you want to build a
          generic distribution kernel, say Y here - otherwise say N.
@@@ -385,18 -376,6 +385,18 @@@ config X86_ELA
  
          If unsure, choose "PC-compatible" instead.
  
 +config X86_MRST
 +       bool "Moorestown MID platform"
 +      depends on X86_32
 +      depends on X86_EXTENDED_PLATFORM
 +      ---help---
 +        Moorestown is Intel's Low Power Intel Architecture (LPIA) based Moblin
 +        Internet Device(MID) platform. Moorestown consists of two chips:
 +        Lincroft (CPU core, graphics, and memory controller) and Langwell IOH.
 +        Unlike standard x86 PCs, Moorestown does not have many legacy devices
 +        nor standard legacy replacement devices/features. e.g. Moorestown does
 +        not contain i8259, i8254, HPET, legacy BIOS, most of the io ports.
 +
  config X86_RDC321X
        bool "RDC R-321x SoC"
        depends on X86_32
@@@ -606,6 -585,7 +606,6 @@@ config GART_IOMM
        bool "GART IOMMU support" if EMBEDDED
        default y
        select SWIOTLB
 -      select AGP
        depends on X86_64 && PCI
        ---help---
          Support for full DMA access of devices with 32bit memory access only
@@@ -762,6 -742,7 +762,6 @@@ config X86_UP_IOAPI
  config X86_LOCAL_APIC
        def_bool y
        depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC
 -      select HAVE_PERF_COUNTERS if (!M386 && !M486)
  
  config X86_IO_APIC
        def_bool y
@@@ -796,17 -777,41 +796,17 @@@ config X86_REROUTE_FOR_BROKEN_BOOT_IRQ
          increased on these systems.
  
  config X86_MCE
 -      bool "Machine Check Exception"
 +      bool "Machine Check / overheating reporting"
        ---help---
 -        Machine Check Exception support allows the processor to notify the
 -        kernel if it detects a problem (e.g. overheating, component failure).
 +        Machine Check support allows the processor to notify the
 +        kernel if it detects a problem (e.g. overheating, data corruption).
          The action the kernel takes depends on the severity of the problem,
 -        ranging from a warning message on the console, to halting the machine.
 -        Your processor must be a Pentium or newer to support this - check the
 -        flags in /proc/cpuinfo for mce.  Note that some older Pentium systems
 -        have a design flaw which leads to false MCE events - hence MCE is
 -        disabled on all P5 processors, unless explicitly enabled with "mce"
 -        as a boot argument.  Similarly, if MCE is built in and creates a
 -        problem on some new non-standard machine, you can boot with "nomce"
 -        to disable it.  MCE support simply ignores non-MCE processors like
 -        the 386 and 486, so nearly everyone can say Y here.
 -
 -config X86_OLD_MCE
 -      depends on X86_32 && X86_MCE
 -      bool "Use legacy machine check code (will go away)"
 -      default n
 -      select X86_ANCIENT_MCE
 -      ---help---
 -        Use the old i386 machine check code. This is merely intended for
 -        testing in a transition period. Try this if you run into any machine
 -        check related software problems, but report the problem to
 -        linux-kernel.  When in doubt say no.
 -
 -config X86_NEW_MCE
 -      depends on X86_MCE
 -      bool
 -      default y if (!X86_OLD_MCE && X86_32) || X86_64
 +        ranging from warning messages to halting the machine.
  
  config X86_MCE_INTEL
        def_bool y
        prompt "Intel MCE features"
 -      depends on X86_NEW_MCE && X86_LOCAL_APIC
 +      depends on X86_MCE && X86_LOCAL_APIC
        ---help---
           Additional support for intel specific MCE features such as
           the thermal monitor.
  config X86_MCE_AMD
        def_bool y
        prompt "AMD MCE features"
 -      depends on X86_NEW_MCE && X86_LOCAL_APIC
 +      depends on X86_MCE && X86_LOCAL_APIC
        ---help---
           Additional support for AMD specific MCE features such as
           the DRAM Error Threshold.
  
  config X86_ANCIENT_MCE
        def_bool n
 -      depends on X86_32
 +      depends on X86_32 && X86_MCE
        prompt "Support for old Pentium 5 / WinChip machine checks"
        ---help---
          Include support for machine check handling on old Pentium 5 or WinChip
@@@ -834,16 -839,36 +834,16 @@@ config X86_MCE_THRESHOL
        default y
  
  config X86_MCE_INJECT
 -      depends on X86_NEW_MCE
 +      depends on X86_MCE
        tristate "Machine check injector support"
        ---help---
          Provide support for injecting machine checks for testing purposes.
          If you don't know what a machine check is and you don't do kernel
          QA it is safe to say n.
  
 -config X86_MCE_NONFATAL
 -      tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
 -      depends on X86_OLD_MCE
 -      ---help---
 -        Enabling this feature starts a timer that triggers every 5 seconds which
 -        will look at the machine check registers to see if anything happened.
 -        Non-fatal problems automatically get corrected (but still logged).
 -        Disable this if you don't want to see these messages.
 -        Seeing the messages this option prints out may be indicative of dying
 -        or out-of-spec (ie, overclocked) hardware.
 -        This option only does something on certain CPUs.
 -        (AMD Athlon/Duron and Intel Pentium 4)
 -
 -config X86_MCE_P4THERMAL
 -      bool "check for P4 thermal throttling interrupt."
 -      depends on X86_OLD_MCE && X86_MCE && (X86_UP_APIC || SMP)
 -      ---help---
 -        Enabling this feature will cause a message to be printed when the P4
 -        enters thermal throttling.
 -
  config X86_THERMAL_VECTOR
        def_bool y
 -      depends on X86_MCE_P4THERMAL || X86_MCE_INTEL
 +      depends on X86_MCE_INTEL
  
  config VM86
        bool "Enable VM86 support" if EMBEDDED
@@@ -1204,10 -1229,6 +1204,10 @@@ config ARCH_DISCONTIGMEM_DEFAUL
        def_bool y
        depends on NUMA && X86_32
  
 +config ARCH_PROC_KCORE_TEXT
 +      def_bool y
 +      depends on X86_64 && PROC_KCORE
 +
  config ARCH_SPARSEMEM_DEFAULT
        def_bool y
        depends on X86_64
@@@ -1393,10 -1414,6 +1393,10 @@@ config X86_PA
  
          If unsure, say Y.
  
 +config ARCH_USES_PG_UNCACHED
 +      def_bool y
 +      depends on X86_PAT
 +
  config EFI
        bool "EFI runtime service support"
        depends on ACPI
@@@ -1666,8 -1683,6 +1666,8 @@@ source "kernel/power/Kconfig
  
  source "drivers/acpi/Kconfig"
  
 +source "drivers/sfi/Kconfig"
 +
  config X86_APM_BOOT
        bool
        default y
@@@ -1863,7 -1878,7 +1863,7 @@@ config PCI_DIREC
  
  config PCI_MMCONFIG
        def_bool y
 -      depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
 +      depends on X86_32 && PCI && (ACPI || SFI) && (PCI_GOMMCONFIG || PCI_GOANY)
  
  config PCI_OLPC
        def_bool y
@@@ -1901,7 -1916,7 +1901,7 @@@ config DMAR_DEFAULT_O
  config DMAR_BROKEN_GFX_WA
        def_bool n
        prompt "Workaround broken graphics drivers (going away soon)"
-       depends on DMAR
+       depends on DMAR && BROKEN
        ---help---
          Current Graphics drivers tend to use physical address
          for DMA and avoid using DMA APIs. Setting this config
  
  int swiotlb __read_mostly;
  
 -void * __init swiotlb_alloc_boot(size_t size, unsigned long nslabs)
 -{
 -      return alloc_bootmem_low_pages(size);
 -}
 -
 -void *swiotlb_alloc(unsigned order, unsigned long nslabs)
 -{
 -      return (void *)__get_free_pages(GFP_DMA | __GFP_NOWARN, order);
 -}
 -
 -dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
 -{
 -      return paddr;
 -}
 -
 -phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
 -{
 -      return baddr;
 -}
 -
 -int __weak swiotlb_arch_range_needs_mapping(phys_addr_t paddr, size_t size)
 -{
 -      return 0;
 -}
 -
  static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                                        dma_addr_t *dma_handle, gfp_t flags)
  {
@@@ -46,9 -71,8 +46,8 @@@ void __init pci_swiotlb_init(void
  {
        /* don't initialize swiotlb if iommu=off (no_iommu=1) */
  #ifdef CONFIG_X86_64
-       if ((!iommu_detected && !no_iommu && max_pfn > MAX_DMA32_PFN) ||
-               iommu_pass_through)
-              swiotlb = 1;
+       if ((!iommu_detected && !no_iommu && max_pfn > MAX_DMA32_PFN))
+               swiotlb = 1;
  #endif
        if (swiotlb_force)
                swiotlb = 1;
diff --combined drivers/pci/dmar.c
  #include <linux/timer.h>
  #include <linux/irq.h>
  #include <linux/interrupt.h>
 +#include <linux/tboot.h>
 +#include <linux/dmi.h>
  
 -#undef PREFIX
 -#define PREFIX "DMAR:"
 +#define PREFIX "DMAR: "
  
  /* No locks are needed as DMA remapping hardware unit
   * list is constructed at boot time and hotplug of
@@@ -414,12 -413,6 +414,12 @@@ parse_dmar_table(void
         */
        dmar_table_detect();
  
 +      /*
 +       * ACPI tables may not be DMA protected by tboot, so use DMAR copy
 +       * SINIT saved in SinitMleData in TXT heap (which is DMA protected)
 +       */
 +      dmar_tbl = tboot_get_dmar_table(dmar_tbl);
 +
        dmar = (struct acpi_table_dmar *)dmar_tbl;
        if (!dmar)
                return -ENODEV;
@@@ -577,9 -570,6 +577,6 @@@ int __init dmar_table_init(void
                printk(KERN_INFO PREFIX "No ATSR found\n");
  #endif
  
- #ifdef CONFIG_INTR_REMAP
-       parse_ioapics_under_ir();
- #endif
        return 0;
  }
  
@@@ -639,20 -629,31 +636,31 @@@ int alloc_iommu(struct dmar_drhd_unit *
        iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
        iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
  
+       if (iommu->cap == (uint64_t)-1 && iommu->ecap == (uint64_t)-1) {
+               /* Promote an attitude of violence to a BIOS engineer today */
+               WARN(1, "Your BIOS is broken; DMAR reported at address %llx returns all ones!\n"
+                    "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+                    drhd->reg_base_addr,
+                    dmi_get_system_info(DMI_BIOS_VENDOR),
+                    dmi_get_system_info(DMI_BIOS_VERSION),
+                    dmi_get_system_info(DMI_PRODUCT_VERSION));
+               goto err_unmap;
+       }
  #ifdef CONFIG_DMAR
        agaw = iommu_calculate_agaw(iommu);
        if (agaw < 0) {
                printk(KERN_ERR
                       "Cannot get a valid agaw for iommu (seq_id = %d)\n",
                       iommu->seq_id);
-               goto error;
+               goto err_unmap;
        }
        msagaw = iommu_calculate_max_sagaw(iommu);
        if (msagaw < 0) {
                printk(KERN_ERR
                        "Cannot get a valid max agaw for iommu (seq_id = %d)\n",
                        iommu->seq_id);
-               goto error;
+               goto err_unmap;
        }
  #endif
        iommu->agaw = agaw;
        }
  
        ver = readl(iommu->reg + DMAR_VER_REG);
-       pr_debug("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
+       pr_info("IOMMU %llx: ver %d:%d cap %llx ecap %llx\n",
                (unsigned long long)drhd->reg_base_addr,
                DMAR_VER_MAJOR(ver), DMAR_VER_MINOR(ver),
                (unsigned long long)iommu->cap,
  
        drhd->iommu = iommu;
        return 0;
- error:
+  err_unmap:
+       iounmap(iommu->reg);
+  error:
        kfree(iommu);
        return -1;
  }
@@@ -1219,7 -1223,7 +1230,7 @@@ irqreturn_t dmar_fault(int irq, void *d
                                source_id, guest_addr);
  
                fault_index++;
-               if (fault_index > cap_num_fault_regs(iommu->cap))
+               if (fault_index >= cap_num_fault_regs(iommu->cap))
                        fault_index = 0;
                spin_lock_irqsave(&iommu->register_lock, flag);
        }
@@@ -1312,3 -1316,13 +1323,13 @@@ int dmar_reenable_qi(struct intel_iomm
  
        return 0;
  }
+ /*
+  * Check interrupt remapping support in DMAR table description.
+  */
+ int dmar_ir_support(void)
+ {
+       struct acpi_table_dmar *dmar;
+       dmar = (struct acpi_table_dmar *)dmar_tbl;
+       return dmar->flags & 0x1;
+ }
@@@ -37,7 -37,7 +37,8 @@@
  #include <linux/iommu.h>
  #include <linux/intel-iommu.h>
  #include <linux/sysdev.h>
 +#include <linux/tboot.h>
+ #include <linux/dmi.h>
  #include <asm/cacheflush.h>
  #include <asm/iommu.h>
  #include "pci.h"
  
  #define MAX_AGAW_WIDTH 64
  
- #define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
- #define DOMAIN_MAX_PFN(gaw)  ((((u64)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
+ #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)
  
  #define IOVA_PFN(addr)                ((addr) >> PAGE_SHIFT)
  #define DMA_32BIT_PFN         IOVA_PFN(DMA_BIT_MASK(32))
@@@ -252,7 -258,8 +259,8 @@@ static inline int first_pte_in_page(str
   *    2. It maps to each iommu if successful.
   *    3. Each iommu mapps to this domain if successful.
   */
- struct dmar_domain *si_domain;
+ static struct dmar_domain *si_domain;
+ static int hw_pass_through = 1;
  
  /* devices under the same p2p bridge are owned in one domain */
  #define DOMAIN_FLAG_P2P_MULTIPLE_DEVICES (1 << 0)
@@@ -728,7 -735,7 +736,7 @@@ static struct dma_pte *pfn_to_dma_pte(s
                                return NULL;
  
                        domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
-                       pteval = (virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
+                       pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
                        if (cmpxchg64(&pte->val, 0ULL, pteval)) {
                                /* Someone else set it while we were thinking; use theirs. */
                                free_pgtable_page(tmp_page);
@@@ -778,9 -785,10 +786,10 @@@ static void dma_pte_clear_range(struct 
  
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
        BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+       BUG_ON(start_pfn > last_pfn);
  
        /* we don't need lock here; nobody else touches the iova range */
-       while (start_pfn <= last_pfn) {
+       do {
                first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
                if (!pte) {
                        start_pfn = align_to_level(start_pfn + 1, 2);
  
                domain_flush_cache(domain, first_pte,
                                   (void *)pte - (void *)first_pte);
-       }
+       } while (start_pfn && start_pfn <= last_pfn);
  }
  
  /* free page table pages. last level pte should already be cleared */
@@@ -810,6 -819,7 +820,7 @@@ static void dma_pte_free_pagetable(stru
  
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
        BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
+       BUG_ON(start_pfn > last_pfn);
  
        /* We don't need lock here; nobody else touches the iova range */
        level = 2;
                if (tmp + level_size(level) - 1 > last_pfn)
                        return;
  
-               while (tmp + level_size(level) - 1 <= last_pfn) {
+               do {
                        first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
                        if (!pte) {
                                tmp = align_to_level(tmp + 1, level + 1);
                        domain_flush_cache(domain, first_pte,
                                           (void *)pte - (void *)first_pte);
                        
-               }
+               } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
                level++;
        }
        /* free pgd */
@@@ -1158,6 -1168,8 +1169,8 @@@ static int iommu_init_domains(struct in
        pr_debug("Number of Domains supportd <%ld>\n", ndomains);
        nlongs = BITS_TO_LONGS(ndomains);
  
+       spin_lock_init(&iommu->lock);
        /* TBD: there might be 64K domains,
         * consider other allocation for future chip
         */
                        GFP_KERNEL);
        if (!iommu->domains) {
                printk(KERN_ERR "Allocating domain array failed\n");
-               kfree(iommu->domain_ids);
                return -ENOMEM;
        }
  
-       spin_lock_init(&iommu->lock);
        /*
         * if Caching mode is set, then invalid translations are tagged
         * with domainid 0. Hence we need to pre-allocate it.
@@@ -1195,22 -1204,24 +1205,24 @@@ void free_dmar_iommu(struct intel_iomm
        int i;
        unsigned long flags;
  
-       i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
-       for (; i < cap_ndoms(iommu->cap); ) {
-               domain = iommu->domains[i];
-               clear_bit(i, iommu->domain_ids);
+       if ((iommu->domains) && (iommu->domain_ids)) {
+               i = find_first_bit(iommu->domain_ids, cap_ndoms(iommu->cap));
+               for (; i < cap_ndoms(iommu->cap); ) {
+                       domain = iommu->domains[i];
+                       clear_bit(i, iommu->domain_ids);
+                       spin_lock_irqsave(&domain->iommu_lock, flags);
+                       if (--domain->iommu_count == 0) {
+                               if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
+                                       vm_domain_exit(domain);
+                               else
+                                       domain_exit(domain);
+                       }
+                       spin_unlock_irqrestore(&domain->iommu_lock, flags);
  
-               spin_lock_irqsave(&domain->iommu_lock, flags);
-               if (--domain->iommu_count == 0) {
-                       if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
-                               vm_domain_exit(domain);
-                       else
-                               domain_exit(domain);
+                       i = find_next_bit(iommu->domain_ids,
+                               cap_ndoms(iommu->cap), i+1);
                }
-               spin_unlock_irqrestore(&domain->iommu_lock, flags);
-               i = find_next_bit(iommu->domain_ids,
-                       cap_ndoms(iommu->cap), i+1);
        }
  
        if (iommu->gcmd & DMA_GCMD_TE)
@@@ -1310,7 -1321,6 +1322,6 @@@ static void iommu_detach_domain(struct 
  }
  
  static struct iova_domain reserved_iova_list;
- static struct lock_class_key reserved_alloc_key;
  static struct lock_class_key reserved_rbtree_key;
  
  static void dmar_init_reserved_ranges(void)
  
        init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
  
-       lockdep_set_class(&reserved_iova_list.iova_alloc_lock,
-               &reserved_alloc_key);
        lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
                &reserved_rbtree_key);
  
@@@ -1959,14 -1967,35 +1968,35 @@@ static int iommu_prepare_identity_map(s
        struct dmar_domain *domain;
        int ret;
  
-       printk(KERN_INFO
-              "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
-              pci_name(pdev), start, end);
        domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
        if (!domain)
                return -ENOMEM;
  
+       /* For _hardware_ passthrough, don't bother. But for software
+          passthrough, we do it anyway -- it may indicate a memory
+          range which is reserved in E820, so which didn't get set
+          up to start with in si_domain */
+       if (domain == si_domain && hw_pass_through) {
+               printk("Ignoring identity map for HW passthrough device %s [0x%Lx - 0x%Lx]\n",
+                      pci_name(pdev), start, end);
+               return 0;
+       }
+       printk(KERN_INFO
+              "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
+              pci_name(pdev), start, end);
+       
+       if (end >> agaw_to_width(domain->agaw)) {
+               WARN(1, "Your BIOS is broken; RMRR exceeds permitted address width (%d bits)\n"
+                    "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+                    agaw_to_width(domain->agaw),
+                    dmi_get_system_info(DMI_BIOS_VENDOR),
+                    dmi_get_system_info(DMI_BIOS_VERSION),
+                    dmi_get_system_info(DMI_PRODUCT_VERSION));
+               ret = -EIO;
+               goto error;
+       }
        ret = iommu_domain_identity_map(domain, start, end);
        if (ret)
                goto error;
@@@ -2017,23 -2046,6 +2047,6 @@@ static inline void iommu_prepare_isa(vo
  }
  #endif /* !CONFIG_DMAR_FLPY_WA */
  
- /* Initialize each context entry as pass through.*/
- static int __init init_context_pass_through(void)
- {
-       struct pci_dev *pdev = NULL;
-       struct dmar_domain *domain;
-       int ret;
-       for_each_pci_dev(pdev) {
-               domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
-               ret = domain_context_mapping(domain, pdev,
-                                            CONTEXT_TT_PASS_THROUGH);
-               if (ret)
-                       return ret;
-       }
-       return 0;
- }
  static int md_domain_init(struct dmar_domain *domain, int guest_width);
  
  static int __init si_domain_work_fn(unsigned long start_pfn,
  
  }
  
- static int si_domain_init(void)
+ static int __init si_domain_init(int hw)
  {
        struct dmar_drhd_unit *drhd;
        struct intel_iommu *iommu;
  
        si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
  
+       if (hw)
+               return 0;
        for_each_online_node(nid) {
                work_with_active_regions(nid, si_domain_work_fn, &ret);
                if (ret)
@@@ -2101,15 -2116,23 +2117,23 @@@ static int identity_mapping(struct pci_
  }
  
  static int domain_add_dev_info(struct dmar_domain *domain,
-                                 struct pci_dev *pdev)
+                              struct pci_dev *pdev,
+                              int translation)
  {
        struct device_domain_info *info;
        unsigned long flags;
+       int ret;
  
        info = alloc_devinfo_mem();
        if (!info)
                return -ENOMEM;
  
+       ret = domain_context_mapping(domain, pdev, translation);
+       if (ret) {
+               free_devinfo_mem(info);
+               return ret;
+       }
        info->segment = pci_domain_nr(pdev->bus);
        info->bus = pdev->bus->number;
        info->devfn = pdev->devfn;
@@@ -2166,27 -2189,25 +2190,25 @@@ static int iommu_should_identity_map(st
        return 1;
  }
  
- static int iommu_prepare_static_identity_mapping(void)
+ static int __init iommu_prepare_static_identity_mapping(int hw)
  {
        struct pci_dev *pdev = NULL;
        int ret;
  
-       ret = si_domain_init();
+       ret = si_domain_init(hw);
        if (ret)
                return -EFAULT;
  
        for_each_pci_dev(pdev) {
                if (iommu_should_identity_map(pdev, 1)) {
-                       printk(KERN_INFO "IOMMU: identity mapping for device %s\n",
-                              pci_name(pdev));
+                       printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
+                              hw ? "hardware" : "software", pci_name(pdev));
  
-                       ret = domain_context_mapping(si_domain, pdev,
+                       ret = domain_add_dev_info(si_domain, pdev,
+                                                    hw ? CONTEXT_TT_PASS_THROUGH :
                                                     CONTEXT_TT_MULTI_LEVEL);
                        if (ret)
                                return ret;
-                       ret = domain_add_dev_info(si_domain, pdev);
-                       if (ret)
-                               return ret;
                }
        }
  
@@@ -2200,14 -2221,6 +2222,6 @@@ int __init init_dmars(void
        struct pci_dev *pdev;
        struct intel_iommu *iommu;
        int i, ret;
-       int pass_through = 1;
-       /*
-        * In case pass through can not be enabled, iommu tries to use identity
-        * mapping.
-        */
-       if (iommu_pass_through)
-               iommu_identity_mapping = 1;
  
        /*
         * for each drhd
        deferred_flush = kzalloc(g_num_of_iommus *
                sizeof(struct deferred_flush_tables), GFP_KERNEL);
        if (!deferred_flush) {
-               kfree(g_iommus);
                ret = -ENOMEM;
                goto error;
        }
                        goto error;
                }
                if (!ecap_pass_through(iommu->ecap))
-                       pass_through = 0;
+                       hw_pass_through = 0;
        }
-       if (iommu_pass_through)
-               if (!pass_through) {
-                       printk(KERN_INFO
-                              "Pass Through is not supported by hardware.\n");
-                       iommu_pass_through = 0;
-               }
  
        /*
         * Start from the sane iommu hardware state.
                }
        }
  
+       if (iommu_pass_through)
+               iommu_identity_mapping = 1;
+ #ifdef CONFIG_DMAR_BROKEN_GFX_WA
+       else
+               iommu_identity_mapping = 2;
+ #endif
        /*
-        * If pass through is set and enabled, context entries of all pci
-        * devices are intialized by pass through translation type.
+        * If pass through is not set or not enabled, setup context entries for
+        * identity mappings for rmrr, gfx, and isa and may fall back to static
+        * identity mapping if iommu_identity_mapping is set.
         */
-       if (iommu_pass_through) {
-               ret = init_context_pass_through();
+       if (iommu_identity_mapping) {
+               ret = iommu_prepare_static_identity_mapping(hw_pass_through);
                if (ret) {
-                       printk(KERN_ERR "IOMMU: Pass through init failed.\n");
-                       iommu_pass_through = 0;
+                       printk(KERN_CRIT "Failed to setup IOMMU pass-through\n");
+                       goto error;
                }
        }
        /*
-        * If pass through is not set or not enabled, setup context entries for
-        * identity mappings for rmrr, gfx, and isa and may fall back to static
-        * identity mapping if iommu_identity_mapping is set.
+        * For each rmrr
+        *   for each dev attached to rmrr
+        *   do
+        *     locate drhd for dev, alloc domain for dev
+        *     allocate free domain
+        *     allocate page table entries for rmrr
+        *     if context not allocated for bus
+        *           allocate and init context
+        *           set present in root table for this bus
+        *     init context with domain, translation etc
+        *    endfor
+        * endfor
         */
-       if (!iommu_pass_through) {
- #ifdef CONFIG_DMAR_BROKEN_GFX_WA
-               if (!iommu_identity_mapping)
-                       iommu_identity_mapping = 2;
- #endif
-               if (iommu_identity_mapping)
-                       iommu_prepare_static_identity_mapping();
-               /*
-                * For each rmrr
-                *   for each dev attached to rmrr
-                *   do
-                *     locate drhd for dev, alloc domain for dev
-                *     allocate free domain
-                *     allocate page table entries for rmrr
-                *     if context not allocated for bus
-                *           allocate and init context
-                *           set present in root table for this bus
-                *     init context with domain, translation etc
-                *    endfor
-                * endfor
-                */
-               printk(KERN_INFO "IOMMU: Setting RMRR:\n");
-               for_each_rmrr_units(rmrr) {
-                       for (i = 0; i < rmrr->devices_cnt; i++) {
-                               pdev = rmrr->devices[i];
-                               /*
-                                * some BIOS lists non-exist devices in DMAR
-                                * table.
-                                */
-                               if (!pdev)
-                                       continue;
-                               ret = iommu_prepare_rmrr_dev(rmrr, pdev);
-                               if (ret)
-                                       printk(KERN_ERR
-                                "IOMMU: mapping reserved region failed\n");
-                       }
+       printk(KERN_INFO "IOMMU: Setting RMRR:\n");
+       for_each_rmrr_units(rmrr) {
+               for (i = 0; i < rmrr->devices_cnt; i++) {
+                       pdev = rmrr->devices[i];
+                       /*
+                        * some BIOS lists non-exist devices in DMAR
+                        * table.
+                        */
+                       if (!pdev)
+                               continue;
+                       ret = iommu_prepare_rmrr_dev(rmrr, pdev);
+                       if (ret)
+                               printk(KERN_ERR
+                                      "IOMMU: mapping reserved region failed\n");
                }
-               iommu_prepare_isa();
        }
  
+       iommu_prepare_isa();
        /*
         * for each drhd
         *   enable fault log
  
                iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
                iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
-               iommu_disable_protect_mem_regions(iommu);
  
                ret = iommu_enable_translation(iommu);
                if (ret)
                        goto error;
+               iommu_disable_protect_mem_regions(iommu);
        }
  
        return 0;
@@@ -2455,8 -2455,7 +2456,7 @@@ static struct iova *intel_alloc_iova(st
        return iova;
  }
  
- static struct dmar_domain *
- get_valid_domain_for_dev(struct pci_dev *pdev)
+ static struct dmar_domain *__get_valid_domain_for_dev(struct pci_dev *pdev)
  {
        struct dmar_domain *domain;
        int ret;
        return domain;
  }
  
+ static inline struct dmar_domain *get_valid_domain_for_dev(struct pci_dev *dev)
+ {
+       struct device_domain_info *info;
+       /* No lock here, assumes no domain exit in normal case */
+       info = dev->dev.archdata.iommu;
+       if (likely(info))
+               return info->domain;
+       return __get_valid_domain_for_dev(dev);
+ }
  static int iommu_dummy(struct pci_dev *pdev)
  {
        return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
@@@ -2526,10 -2537,10 +2538,10 @@@ static int iommu_no_mapping(struct devi
                 */
                if (iommu_should_identity_map(pdev, 0)) {
                        int ret;
-                       ret = domain_add_dev_info(si_domain, pdev);
-                       if (ret)
-                               return 0;
-                       ret = domain_context_mapping(si_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
+                       ret = domain_add_dev_info(si_domain, pdev,
+                                                 hw_pass_through ?
+                                                 CONTEXT_TT_PASS_THROUGH :
+                                                 CONTEXT_TT_MULTI_LEVEL);
                        if (!ret) {
                                printk(KERN_INFO "64bit %s uses identity mapping\n",
                                       pci_name(pdev));
@@@ -2638,10 -2649,9 +2650,9 @@@ static void flush_unmaps(void
                        unsigned long mask;
                        struct iova *iova = deferred_flush[i].iova[j];
  
-                       mask = (iova->pfn_hi - iova->pfn_lo + 1) << PAGE_SHIFT;
-                       mask = ilog2(mask >> VTD_PAGE_SHIFT);
+                       mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
                        iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
-                                       iova->pfn_lo << PAGE_SHIFT, mask);
+                                       (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
                        __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
                }
                deferred_flush[i].next = 0;
@@@ -2734,12 -2744,6 +2745,6 @@@ static void intel_unmap_page(struct dev
        }
  }
  
- static void intel_unmap_single(struct device *dev, dma_addr_t dev_addr, size_t size,
-                              int dir)
- {
-       intel_unmap_page(dev, dev_addr, size, dir, NULL);
- }
  static void *intel_alloc_coherent(struct device *hwdev, size_t size,
                                  dma_addr_t *dma_handle, gfp_t flags)
  {
@@@ -2772,7 -2776,7 +2777,7 @@@ static void intel_free_coherent(struct 
        size = PAGE_ALIGN(size);
        order = get_order(size);
  
-       intel_unmap_single(hwdev, dma_handle, size, DMA_BIDIRECTIONAL);
+       intel_unmap_page(hwdev, dma_handle, size, DMA_BIDIRECTIONAL, NULL);
        free_pages((unsigned long)vaddr, order);
  }
  
@@@ -2808,11 -2812,18 +2813,18 @@@ static void intel_unmap_sg(struct devic
        /* free page tables */
        dma_pte_free_pagetable(domain, start_pfn, last_pfn);
  
-       iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
-                             (last_pfn - start_pfn + 1));
-       /* free iova */
-       __free_iova(&domain->iovad, iova);
+       if (intel_iommu_strict) {
+               iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+                                     last_pfn - start_pfn + 1);
+               /* free iova */
+               __free_iova(&domain->iovad, iova);
+       } else {
+               add_unmap(domain, iova);
+               /*
+                * queue up the release of the unmap to save the 1/6th of the
+                * cpu used up by the iotlb flush operation...
+                */
+       }
  }
  
  static int intel_nontranslate_map_sg(struct device *hddev,
@@@ -3056,8 -3067,8 +3068,8 @@@ static int init_iommu_hw(void
                                           DMA_CCMD_GLOBAL_INVL);
                iommu->flush.flush_iotlb(iommu, 0, 0, 0,
                                         DMA_TLB_GLOBAL_FLUSH);
-               iommu_disable_protect_mem_regions(iommu);
                iommu_enable_translation(iommu);
+               iommu_disable_protect_mem_regions(iommu);
        }
  
        return 0;
@@@ -3184,28 -3195,18 +3196,28 @@@ static int __init init_iommu_sysfs(void
  int __init intel_iommu_init(void)
  {
        int ret = 0;
 +      int force_on = 0;
  
 -      if (dmar_table_init())
 +      /* VT-d is required for a TXT/tboot launch, so enforce that */
 +      force_on = tboot_force_iommu();
 +
 +      if (dmar_table_init()) {
 +              if (force_on)
 +                      panic("tboot: Failed to initialize DMAR table\n");
                return  -ENODEV;
 +      }
  
 -      if (dmar_dev_scope_init())
 +      if (dmar_dev_scope_init()) {
 +              if (force_on)
 +                      panic("tboot: Failed to initialize DMAR device scope\n");
                return  -ENODEV;
 +      }
  
        /*
         * Check the need for DMA-remapping initialization now.
         * Above initialization will also be used by Interrupt-remapping.
         */
-       if (no_iommu || (swiotlb && !iommu_pass_through) || dmar_disabled)
+       if (no_iommu || swiotlb || dmar_disabled)
                return -ENODEV;
  
        iommu_init_mempool();
  
        ret = init_dmars();
        if (ret) {
 +              if (force_on)
 +                      panic("tboot: Failed to initialize DMARs\n");
                printk(KERN_ERR "IOMMU: dmar init failed\n");
                put_iova_domain(&reserved_iova_list);
                iommu_exit_mempool();
  
        init_timer(&unmap_timer);
        force_iommu = 1;
-       if (!iommu_pass_through) {
-               printk(KERN_INFO
-                      "Multi-level page-table translation for DMAR.\n");
-               dma_ops = &intel_dma_ops;
-       } else
-               printk(KERN_INFO
-                      "DMAR: Pass through translation for DMAR.\n");
+       dma_ops = &intel_dma_ops;
  
        init_iommu_sysfs();
  
@@@ -3517,7 -3509,6 +3522,6 @@@ static int intel_iommu_attach_device(st
        struct intel_iommu *iommu;
        int addr_width;
        u64 end;
-       int ret;
  
        /* normally pdev is not mapped */
        if (unlikely(domain_context_mapped(pdev))) {
                return -EFAULT;
        }
  
-       ret = domain_add_dev_info(dmar_domain, pdev);
-       if (ret)
-               return ret;
-       ret = domain_context_mapping(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
-       return ret;
+       return domain_add_dev_info(dmar_domain, pdev, CONTEXT_TT_MULTI_LEVEL);
  }
  
  static void intel_iommu_detach_device(struct iommu_domain *domain,
@@@ -55,12 -55,15 +55,12 @@@ static struct irq_2_iommu *irq_2_iommu(
        return desc->irq_2_iommu;
  }
  
 -static struct irq_2_iommu *irq_2_iommu_alloc_node(unsigned int irq, int node)
 +static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
  {
        struct irq_desc *desc;
        struct irq_2_iommu *irq_iommu;
  
 -      /*
 -       * alloc irq desc if not allocated already.
 -       */
 -      desc = irq_to_desc_alloc_node(irq, node);
 +      desc = irq_to_desc(irq);
        if (!desc) {
                printk(KERN_INFO "can not get irq_desc for %d\n", irq);
                return NULL;
        irq_iommu = desc->irq_2_iommu;
  
        if (!irq_iommu)
 -              desc->irq_2_iommu = get_one_free_irq_2_iommu(node);
 +              desc->irq_2_iommu = get_one_free_irq_2_iommu(irq_node(irq));
  
        return desc->irq_2_iommu;
  }
  
 -static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
 -{
 -      return irq_2_iommu_alloc_node(irq, cpu_to_node(boot_cpu_id));
 -}
 -
  #else /* !CONFIG_SPARSE_IRQ */
  
  static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
@@@ -603,6 -611,9 +603,9 @@@ int __init intr_remapping_supported(voi
        if (disable_intremap)
                return 0;
  
+       if (!dmar_ir_support())
+               return 0;
        for_each_drhd_unit(drhd) {
                struct intel_iommu *iommu = drhd->iommu;
  
@@@ -618,6 -629,11 +621,11 @@@ int __init enable_intr_remapping(int ei
        struct dmar_drhd_unit *drhd;
        int setup = 0;
  
+       if (parse_ioapics_under_ir() != 1) {
+               printk(KERN_INFO "Not enable interrupt remapping\n");
+               return -1;
+       }
        for_each_drhd_unit(drhd) {
                struct intel_iommu *iommu = drhd->iommu;