Merge branch 'x86/asm' into x86/apic, to resolve a conflict
authorIngo Molnar <mingo@kernel.org>
Mon, 11 May 2015 14:05:09 +0000 (16:05 +0200)
committerIngo Molnar <mingo@kernel.org>
Mon, 11 May 2015 14:05:09 +0000 (16:05 +0200)
Conflicts:
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/vector.c

Signed-off-by: Ingo Molnar <mingo@kernel.org>
1  2 
arch/x86/Kconfig
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/irq_vectors.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/smpboot.c
drivers/iommu/intel_irq_remapping.c
include/linux/intel-iommu.h

diff --combined arch/x86/Kconfig
index 3c17c04ce5a7ee696c31eddcb8bd739c343ae1b2,226d5696e1d1dd5fe715124710b0f2cd04f8c495..6bbb991d0f3c17396d1a89ec11ba9af5ce708fa2
@@@ -22,6 -22,7 +22,7 @@@ config X86_6
  ### Arch settings
  config X86
        def_bool y
+       select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI
        select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
        select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select ARCH_HAS_FAST_MULTIPLIER
@@@ -340,7 -341,7 +341,7 @@@ config X86_FEATURE_NAME
  
  config X86_X2APIC
        bool "Support x2apic"
 -      depends on X86_LOCAL_APIC && X86_64 && IRQ_REMAP
 +      depends on X86_LOCAL_APIC && X86_64 && (IRQ_REMAP || HYPERVISOR_GUEST)
        ---help---
          This enables x2apic support on CPUs that have this feature.
  
@@@ -465,6 -466,7 +466,6 @@@ config X86_INTEL_C
        select X86_REBOOTFIXUPS
        select OF
        select OF_EARLY_FLATTREE
 -      select IRQ_DOMAIN
        ---help---
          Select for the Intel CE media processor (CE4100) SOC.
          This option compiles in support for the CE4100 SOC for settop
@@@ -912,12 -914,12 +913,12 @@@ config X86_UP_IOAPI
  config X86_LOCAL_APIC
        def_bool y
        depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
 -      select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ
 +      select IRQ_DOMAIN_HIERARCHY
 +      select PCI_MSI_IRQ_DOMAIN if PCI_MSI
  
  config X86_IO_APIC
        def_bool y
        depends on X86_LOCAL_APIC || X86_UP_IOAPIC
 -      select IRQ_DOMAIN
  
  config X86_REROUTE_FOR_BROKEN_BOOT_IRQS
        bool "Reroute for broken boot IRQs"
index 1f88e719fa78c7565a0d8041d2a040f300859575,014c6382ffcea3a3edf6f37ae5b9cb70a2b967ea..9472c9aff26de0a98ebcabdbac801b8ebcd0d8ac
@@@ -36,40 -36,6 +36,6 @@@ extern asmlinkage void spurious_interru
  extern asmlinkage void thermal_interrupt(void);
  extern asmlinkage void reschedule_interrupt(void);
  
- extern asmlinkage void invalidate_interrupt(void);
- extern asmlinkage void invalidate_interrupt0(void);
- extern asmlinkage void invalidate_interrupt1(void);
- extern asmlinkage void invalidate_interrupt2(void);
- extern asmlinkage void invalidate_interrupt3(void);
- extern asmlinkage void invalidate_interrupt4(void);
- extern asmlinkage void invalidate_interrupt5(void);
- extern asmlinkage void invalidate_interrupt6(void);
- extern asmlinkage void invalidate_interrupt7(void);
- extern asmlinkage void invalidate_interrupt8(void);
- extern asmlinkage void invalidate_interrupt9(void);
- extern asmlinkage void invalidate_interrupt10(void);
- extern asmlinkage void invalidate_interrupt11(void);
- extern asmlinkage void invalidate_interrupt12(void);
- extern asmlinkage void invalidate_interrupt13(void);
- extern asmlinkage void invalidate_interrupt14(void);
- extern asmlinkage void invalidate_interrupt15(void);
- extern asmlinkage void invalidate_interrupt16(void);
- extern asmlinkage void invalidate_interrupt17(void);
- extern asmlinkage void invalidate_interrupt18(void);
- extern asmlinkage void invalidate_interrupt19(void);
- extern asmlinkage void invalidate_interrupt20(void);
- extern asmlinkage void invalidate_interrupt21(void);
- extern asmlinkage void invalidate_interrupt22(void);
- extern asmlinkage void invalidate_interrupt23(void);
- extern asmlinkage void invalidate_interrupt24(void);
- extern asmlinkage void invalidate_interrupt25(void);
- extern asmlinkage void invalidate_interrupt26(void);
- extern asmlinkage void invalidate_interrupt27(void);
- extern asmlinkage void invalidate_interrupt28(void);
- extern asmlinkage void invalidate_interrupt29(void);
- extern asmlinkage void invalidate_interrupt30(void);
- extern asmlinkage void invalidate_interrupt31(void);
  extern asmlinkage void irq_move_cleanup_interrupt(void);
  extern asmlinkage void reboot_interrupt(void);
  extern asmlinkage void threshold_interrupt(void);
@@@ -94,84 -60,53 +60,84 @@@ extern void trace_call_function_single_
  #define trace_kvm_posted_intr_ipi kvm_posted_intr_ipi
  #endif /* CONFIG_TRACING */
  
 -#ifdef CONFIG_IRQ_REMAP
 -/* Intel specific interrupt remapping information */
 -struct irq_2_iommu {
 -      struct intel_iommu *iommu;
 -      u16 irte_index;
 -      u16 sub_handle;
 -      u8  irte_mask;
 -};
 -
 -/* AMD specific interrupt remapping information */
 -struct irq_2_irte {
 -      u16 devid; /* Device ID for IRTE table */
 -      u16 index; /* Index into IRTE table*/
 -};
 -#endif        /* CONFIG_IRQ_REMAP */
 -
  #ifdef        CONFIG_X86_LOCAL_APIC
  struct irq_data;
 +struct pci_dev;
 +struct msi_desc;
 +
 +enum irq_alloc_type {
 +      X86_IRQ_ALLOC_TYPE_IOAPIC = 1,
 +      X86_IRQ_ALLOC_TYPE_HPET,
 +      X86_IRQ_ALLOC_TYPE_MSI,
 +      X86_IRQ_ALLOC_TYPE_MSIX,
 +      X86_IRQ_ALLOC_TYPE_DMAR,
 +      X86_IRQ_ALLOC_TYPE_UV,
 +};
  
 -struct irq_cfg {
 -      cpumask_var_t           domain;
 -      cpumask_var_t           old_domain;
 -      u8                      vector;
 -      u8                      move_in_progress : 1;
 -#ifdef CONFIG_IRQ_REMAP
 -      u8                      remapped : 1;
 +struct irq_alloc_info {
 +      enum irq_alloc_type     type;
 +      u32                     flags;
 +      const struct cpumask    *mask;  /* CPU mask for vector allocation */
        union {
 -              struct irq_2_iommu irq_2_iommu;
 -              struct irq_2_irte  irq_2_irte;
 -      };
 +              int             unused;
 +#ifdef        CONFIG_HPET_TIMER
 +              struct {
 +                      int             hpet_id;
 +                      int             hpet_index;
 +                      void            *hpet_data;
 +              };
  #endif
 -      union {
 -#ifdef CONFIG_X86_IO_APIC
 +#ifdef        CONFIG_PCI_MSI
 +              struct {
 +                      struct pci_dev  *msi_dev;
 +                      irq_hw_number_t msi_hwirq;
 +              };
 +#endif
 +#ifdef        CONFIG_X86_IO_APIC
                struct {
 -                      struct list_head        irq_2_pin;
 +                      int             ioapic_id;
 +                      int             ioapic_pin;
 +                      int             ioapic_node;
 +                      u32             ioapic_trigger : 1;
 +                      u32             ioapic_polarity : 1;
 +                      u32             ioapic_valid : 1;
 +                      struct IO_APIC_route_entry *ioapic_entry;
 +              };
 +#endif
 +#ifdef        CONFIG_DMAR_TABLE
 +              struct {
 +                      int             dmar_id;
 +                      void            *dmar_data;
 +              };
 +#endif
 +#ifdef        CONFIG_HT_IRQ
 +              struct {
 +                      int             ht_pos;
 +                      int             ht_idx;
 +                      struct pci_dev  *ht_dev;
 +                      void            *ht_update;
 +              };
 +#endif
 +#ifdef        CONFIG_X86_UV
 +              struct {
 +                      int             uv_limit;
 +                      int             uv_blade;
 +                      unsigned long   uv_offset;
 +                      char            *uv_name;
                };
  #endif
        };
  };
  
 +struct irq_cfg {
 +      unsigned int            dest_apicid;
 +      u8                      vector;
 +};
 +
  extern struct irq_cfg *irq_cfg(unsigned int irq);
  extern struct irq_cfg *irqd_cfg(struct irq_data *irq_data);
 -extern struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node);
  extern void lock_vector_lock(void);
  extern void unlock_vector_lock(void);
 -extern int assign_irq_vector(int, struct irq_cfg *, const struct cpumask *);
 -extern void clear_irq_vector(int irq, struct irq_cfg *cfg);
  extern void setup_vector_irq(int cpu);
  #ifdef CONFIG_SMP
  extern void send_cleanup_vector(struct irq_cfg *);
@@@ -181,7 -116,10 +147,7 @@@ static inline void send_cleanup_vector(
  static inline void irq_complete_move(struct irq_cfg *c) { }
  #endif
  
 -extern int apic_retrigger_irq(struct irq_data *data);
  extern void apic_ack_edge(struct irq_data *data);
 -extern int apic_set_affinity(struct irq_data *data, const struct cpumask *mask,
 -                           unsigned int *dest_id);
  #else /*  CONFIG_X86_LOCAL_APIC */
  static inline void lock_vector_lock(void) {}
  static inline void unlock_vector_lock(void) {}
@@@ -206,7 -144,6 +172,6 @@@ extern asmlinkage void smp_irq_move_cle
  extern __visible void smp_reschedule_interrupt(struct pt_regs *);
  extern __visible void smp_call_function_interrupt(struct pt_regs *);
  extern __visible void smp_call_function_single_interrupt(struct pt_regs *);
- extern __visible void smp_invalidate_interrupt(struct pt_regs *);
  #endif
  
  extern char irq_entries_start[];
index b26cb124a4f1cf7bc55fe350c25a8debcee82a44,117db96ad5fbdf3204deb2ad2edb12009501b67e..bf55235d7772522045323e33350f42ed2861ec7a
  #define IRQ_MOVE_CLEANUP_VECTOR               FIRST_EXTERNAL_VECTOR
  
  #define IA32_SYSCALL_VECTOR           0x80
- #ifdef CONFIG_X86_32
- # define SYSCALL_VECTOR                       0x80
- #endif
  
  /*
   * Vectors 0x30-0x3f are used for ISA interrupts.
   *   round up to the next 16-vector boundary
   */
- #define IRQ0_VECTOR                   ((FIRST_EXTERNAL_VECTOR + 16) & ~15)
- #define IRQ1_VECTOR                   (IRQ0_VECTOR +  1)
- #define IRQ2_VECTOR                   (IRQ0_VECTOR +  2)
- #define IRQ3_VECTOR                   (IRQ0_VECTOR +  3)
- #define IRQ4_VECTOR                   (IRQ0_VECTOR +  4)
- #define IRQ5_VECTOR                   (IRQ0_VECTOR +  5)
- #define IRQ6_VECTOR                   (IRQ0_VECTOR +  6)
- #define IRQ7_VECTOR                   (IRQ0_VECTOR +  7)
- #define IRQ8_VECTOR                   (IRQ0_VECTOR +  8)
- #define IRQ9_VECTOR                   (IRQ0_VECTOR +  9)
- #define IRQ10_VECTOR                  (IRQ0_VECTOR + 10)
- #define IRQ11_VECTOR                  (IRQ0_VECTOR + 11)
- #define IRQ12_VECTOR                  (IRQ0_VECTOR + 12)
- #define IRQ13_VECTOR                  (IRQ0_VECTOR + 13)
- #define IRQ14_VECTOR                  (IRQ0_VECTOR + 14)
- #define IRQ15_VECTOR                  (IRQ0_VECTOR + 15)
+ #define ISA_IRQ_VECTOR(irq)           (((FIRST_EXTERNAL_VECTOR + 16) & ~15) + irq)
  
  /*
   * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
@@@ -155,22 -136,18 +136,22 @@@ static inline int invalid_vm86_irq(int 
   * static arrays.
   */
  
 -#define NR_IRQS_LEGACY                          16
 +#define NR_IRQS_LEGACY                        16
  
 -#define IO_APIC_VECTOR_LIMIT          ( 32 * MAX_IO_APICS )
 +#define CPU_VECTOR_LIMIT              (64 * NR_CPUS)
 +#define IO_APIC_VECTOR_LIMIT          (32 * MAX_IO_APICS)
  
 -#ifdef CONFIG_X86_IO_APIC
 -# define CPU_VECTOR_LIMIT             (64 * NR_CPUS)
 -# define NR_IRQS                                      \
 +#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_PCI_MSI)
 +#define NR_IRQS                                               \
        (CPU_VECTOR_LIMIT > IO_APIC_VECTOR_LIMIT ?      \
                (NR_VECTORS + CPU_VECTOR_LIMIT)  :      \
                (NR_VECTORS + IO_APIC_VECTOR_LIMIT))
 -#else /* !CONFIG_X86_IO_APIC: */
 -# define NR_IRQS                      NR_IRQS_LEGACY
 +#elif defined(CONFIG_X86_IO_APIC)
 +#define       NR_IRQS                         (NR_VECTORS + IO_APIC_VECTOR_LIMIT)
 +#elif defined(CONFIG_PCI_MSI)
 +#define NR_IRQS                               (NR_VECTORS + CPU_VECTOR_LIMIT)
 +#else
 +#define NR_IRQS                               NR_IRQS_LEGACY
  #endif
  
  #endif /* _ASM_X86_IRQ_VECTORS_H */
index cb9f6f12246b797a870419001ae2323d69070797,dbe76a14c3c9909e50ad51ff14e2eefd31cdf101..271293ad89d74678dc1bc504bfe6ed5313de1c91
  #include <linux/module.h>
  #include <linux/dmi.h>
  #include <linux/irq.h>
 -#include <linux/irqdomain.h>
  #include <linux/slab.h>
  #include <linux/bootmem.h>
  #include <linux/ioport.h>
  #include <linux/pci.h>
  
 +#include <asm/irqdomain.h>
  #include <asm/pci_x86.h>
  #include <asm/pgtable.h>
  #include <asm/io_apic.h>
@@@ -400,13 -400,57 +400,13 @@@ static int mp_config_acpi_gsi(struct de
        return 0;
  }
  
 -static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,
 -                         int polarity)
 -{
 -      int irq, node;
 -
 -      if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
 -              return gsi;
 -
 -      trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
 -      polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
 -      node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
 -      if (mp_set_gsi_attr(gsi, trigger, polarity, node)) {
 -              pr_warn("Failed to set pin attr for GSI%d\n", gsi);
 -              return -1;
 -      }
 -
 -      irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC);
 -      if (irq < 0)
 -              return irq;
 -
 -      /* Don't set up the ACPI SCI because it's already set up */
 -      if (enable_update_mptable && acpi_gbl_FADT.sci_interrupt != gsi)
 -              mp_config_acpi_gsi(dev, gsi, trigger, polarity);
 -
 -      return irq;
 -}
 -
 -static void mp_unregister_gsi(u32 gsi)
 -{
 -      int irq;
 -
 -      if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
 -              return;
 -
 -      irq = mp_map_gsi_to_irq(gsi, 0);
 -      if (irq > 0)
 -              mp_unmap_irq(irq);
 -}
 -
 -static struct irq_domain_ops acpi_irqdomain_ops = {
 -      .map = mp_irqdomain_map,
 -      .unmap = mp_irqdomain_unmap,
 -};
 -
  static int __init
  acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
  {
        struct acpi_madt_io_apic *ioapic = NULL;
        struct ioapic_domain_cfg cfg = {
                .type = IOAPIC_DOMAIN_DYNAMIC,
 -              .ops = &acpi_irqdomain_ops,
 +              .ops = &mp_ioapic_irqdomain_ops,
        };
  
        ioapic = (struct acpi_madt_io_apic *)header;
@@@ -619,21 -663,10 +619,21 @@@ static int acpi_register_gsi_ioapic(str
                                    int trigger, int polarity)
  {
        int irq = gsi;
 -
  #ifdef CONFIG_X86_IO_APIC
 +      int node;
 +      struct irq_alloc_info info;
 +
 +      node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
 +      trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
 +      polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
 +      ioapic_set_alloc_attr(&info, node, trigger, polarity);
 +
        mutex_lock(&acpi_ioapic_lock);
 -      irq = mp_register_gsi(dev, gsi, trigger, polarity);
 +      irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info);
 +      /* Don't set up the ACPI SCI because it's already set up */
 +      if (irq >= 0 && enable_update_mptable &&
 +          acpi_gbl_FADT.sci_interrupt != gsi)
 +              mp_config_acpi_gsi(dev, gsi, trigger, polarity);
        mutex_unlock(&acpi_ioapic_lock);
  #endif
  
  static void acpi_unregister_gsi_ioapic(u32 gsi)
  {
  #ifdef CONFIG_X86_IO_APIC
 +      int irq;
 +
        mutex_lock(&acpi_ioapic_lock);
 -      mp_unregister_gsi(gsi);
 +      irq = mp_map_gsi_to_irq(gsi, 0, NULL);
 +      if (irq > 0)
 +              mp_unmap_irq(irq);
        mutex_unlock(&acpi_ioapic_lock);
  #endif
  }
@@@ -728,7 -757,7 +728,7 @@@ static int _acpi_map_lsapic(acpi_handl
  }
  
  /* wrapper to silence section mismatch warning */
- int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu)
+ int __ref acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu)
  {
        return _acpi_map_lsapic(handle, physid, pcpu);
  }
@@@ -757,7 -786,7 +757,7 @@@ int acpi_register_ioapic(acpi_handle ha
        u64 addr;
        struct ioapic_domain_cfg cfg = {
                .type = IOAPIC_DOMAIN_DYNAMIC,
 -              .ops = &acpi_irqdomain_ops,
 +              .ops = &mp_ioapic_irqdomain_ops,
        };
  
        ioapic_id = acpi_get_ioapic_id(handle, gsi_base, &addr);
index 426496862be0765c7af89673fa37d8c3f7d0983a,82d44c314a3f9b7888b8cec42e7c1514e50ae056..2766747e1a3b316d65be99b0d3f6feb4a021a533
@@@ -3,8 -3,6 +3,8 @@@
   *
   * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
   *    Moved from arch/x86/kernel/apic/io_apic.c.
 + * Jiang Liu <jiang.liu@linux.intel.com>
 + *    Enable support of hierarchical irqdomains
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
  #include <linux/interrupt.h>
  #include <linux/init.h>
  #include <linux/compiler.h>
 -#include <linux/irqdomain.h>
  #include <linux/slab.h>
 +#include <asm/irqdomain.h>
  #include <asm/hw_irq.h>
  #include <asm/apic.h>
  #include <asm/i8259.h>
  #include <asm/desc.h>
  #include <asm/irq_remapping.h>
  
 +struct apic_chip_data {
 +      struct irq_cfg          cfg;
 +      cpumask_var_t           domain;
 +      cpumask_var_t           old_domain;
 +      u8                      move_in_progress : 1;
 +};
 +
 +struct irq_domain *x86_vector_domain;
  static DEFINE_RAW_SPINLOCK(vector_lock);
 +static cpumask_var_t vector_cpumask;
 +static struct irq_chip lapic_controller;
 +#ifdef        CONFIG_X86_IO_APIC
 +static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
 +#endif
  
  void lock_vector_lock(void)
  {
@@@ -49,59 -34,71 +49,59 @@@ void unlock_vector_lock(void
        raw_spin_unlock(&vector_lock);
  }
  
 -struct irq_cfg *irq_cfg(unsigned int irq)
 +static struct apic_chip_data *apic_chip_data(struct irq_data *irq_data)
  {
 -      return irq_get_chip_data(irq);
 +      if (!irq_data)
 +              return NULL;
 +
 +      while (irq_data->parent_data)
 +              irq_data = irq_data->parent_data;
 +
 +      return irq_data->chip_data;
  }
  
  struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
  {
 -      return irq_data->chip_data;
 +      struct apic_chip_data *data = apic_chip_data(irq_data);
 +
 +      return data ? &data->cfg : NULL;
 +}
 +
 +struct irq_cfg *irq_cfg(unsigned int irq)
 +{
 +      return irqd_cfg(irq_get_irq_data(irq));
  }
  
 -static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
 +static struct apic_chip_data *alloc_apic_chip_data(int node)
  {
 -      struct irq_cfg *cfg;
 +      struct apic_chip_data *data;
  
 -      cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
 -      if (!cfg)
 +      data = kzalloc_node(sizeof(*data), GFP_KERNEL, node);
 +      if (!data)
                return NULL;
 -      if (!zalloc_cpumask_var_node(&cfg->domain, GFP_KERNEL, node))
 -              goto out_cfg;
 -      if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
 +      if (!zalloc_cpumask_var_node(&data->domain, GFP_KERNEL, node))
 +              goto out_data;
 +      if (!zalloc_cpumask_var_node(&data->old_domain, GFP_KERNEL, node))
                goto out_domain;
 -#ifdef        CONFIG_X86_IO_APIC
 -      INIT_LIST_HEAD(&cfg->irq_2_pin);
 -#endif
 -      return cfg;
 +      return data;
  out_domain:
 -      free_cpumask_var(cfg->domain);
 -out_cfg:
 -      kfree(cfg);
 +      free_cpumask_var(data->domain);
 +out_data:
 +      kfree(data);
        return NULL;
  }
  
 -struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
 +static void free_apic_chip_data(struct apic_chip_data *data)
  {
 -      int res = irq_alloc_desc_at(at, node);
 -      struct irq_cfg *cfg;
 -
 -      if (res < 0) {
 -              if (res != -EEXIST)
 -                      return NULL;
 -              cfg = irq_cfg(at);
 -              if (cfg)
 -                      return cfg;
 +      if (data) {
 +              free_cpumask_var(data->domain);
 +              free_cpumask_var(data->old_domain);
 +              kfree(data);
        }
 -
 -      cfg = alloc_irq_cfg(at, node);
 -      if (cfg)
 -              irq_set_chip_data(at, cfg);
 -      else
 -              irq_free_desc(at);
 -      return cfg;
  }
  
 -static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
 -{
 -      if (!cfg)
 -              return;
 -      irq_set_chip_data(at, NULL);
 -      free_cpumask_var(cfg->domain);
 -      free_cpumask_var(cfg->old_domain);
 -      kfree(cfg);
 -}
 -
 -static int
 -__assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
 +static int __assign_irq_vector(int irq, struct apic_chip_data *d,
 +                             const struct cpumask *mask)
  {
        /*
         * NOTE! The local APIC isn't very good at handling
        static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
        static int current_offset = VECTOR_OFFSET_START % 16;
        int cpu, err;
 -      cpumask_var_t tmp_mask;
  
 -      if (cfg->move_in_progress)
 +      if (d->move_in_progress)
                return -EBUSY;
  
 -      if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
 -              return -ENOMEM;
 -
        /* Only try and allocate irqs on cpus that are present */
        err = -ENOSPC;
 -      cpumask_clear(cfg->old_domain);
 +      cpumask_clear(d->old_domain);
        cpu = cpumask_first_and(mask, cpu_online_mask);
        while (cpu < nr_cpu_ids) {
                int new_cpu, vector, offset;
  
 -              apic->vector_allocation_domain(cpu, tmp_mask, mask);
 +              apic->vector_allocation_domain(cpu, vector_cpumask, mask);
  
 -              if (cpumask_subset(tmp_mask, cfg->domain)) {
 +              if (cpumask_subset(vector_cpumask, d->domain)) {
                        err = 0;
 -                      if (cpumask_equal(tmp_mask, cfg->domain))
 +                      if (cpumask_equal(vector_cpumask, d->domain))
                                break;
                        /*
                         * New cpumask using the vector is a proper subset of
                         * the current in use mask. So cleanup the vector
                         * allocation for the members that are not used anymore.
                         */
 -                      cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask);
 -                      cfg->move_in_progress =
 -                         cpumask_intersects(cfg->old_domain, cpu_online_mask);
 -                      cpumask_and(cfg->domain, cfg->domain, tmp_mask);
 +                      cpumask_andnot(d->old_domain, d->domain,
 +                                     vector_cpumask);
 +                      d->move_in_progress =
 +                         cpumask_intersects(d->old_domain, cpu_online_mask);
 +                      cpumask_and(d->domain, d->domain, vector_cpumask);
                        break;
                }
  
@@@ -157,18 -157,16 +157,18 @@@ next
                }
  
                if (unlikely(current_vector == vector)) {
 -                      cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
 -                      cpumask_andnot(tmp_mask, mask, cfg->old_domain);
 -                      cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
 +                      cpumask_or(d->old_domain, d->old_domain,
 +                                 vector_cpumask);
 +                      cpumask_andnot(vector_cpumask, mask, d->old_domain);
 +                      cpu = cpumask_first_and(vector_cpumask,
 +                                              cpu_online_mask);
                        continue;
                }
  
                if (test_bit(vector, used_vectors))
                        goto next;
  
 -              for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) {
 +              for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask) {
                        if (per_cpu(vector_irq, new_cpu)[vector] >
                            VECTOR_UNDEFINED)
                                goto next;
                /* Found one! */
                current_vector = vector;
                current_offset = offset;
 -              if (cfg->vector) {
 -                      cpumask_copy(cfg->old_domain, cfg->domain);
 -                      cfg->move_in_progress =
 -                         cpumask_intersects(cfg->old_domain, cpu_online_mask);
 +              if (d->cfg.vector) {
 +                      cpumask_copy(d->old_domain, d->domain);
 +                      d->move_in_progress =
 +                         cpumask_intersects(d->old_domain, cpu_online_mask);
                }
 -              for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
 +              for_each_cpu_and(new_cpu, vector_cpumask, cpu_online_mask)
                        per_cpu(vector_irq, new_cpu)[vector] = irq;
 -              cfg->vector = vector;
 -              cpumask_copy(cfg->domain, tmp_mask);
 +              d->cfg.vector = vector;
 +              cpumask_copy(d->domain, vector_cpumask);
                err = 0;
                break;
        }
 -      free_cpumask_var(tmp_mask);
 +
 +      if (!err) {
 +              /* cache destination APIC IDs into cfg->dest_apicid */
 +              err = apic->cpu_mask_to_apicid_and(mask, d->domain,
 +                                                 &d->cfg.dest_apicid);
 +      }
  
        return err;
  }
  
 -int assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
 +static int assign_irq_vector(int irq, struct apic_chip_data *data,
 +                           const struct cpumask *mask)
  {
        int err;
        unsigned long flags;
  
        raw_spin_lock_irqsave(&vector_lock, flags);
 -      err = __assign_irq_vector(irq, cfg, mask);
 +      err = __assign_irq_vector(irq, data, mask);
        raw_spin_unlock_irqrestore(&vector_lock, flags);
        return err;
  }
  
 -void clear_irq_vector(int irq, struct irq_cfg *cfg)
 +static void clear_irq_vector(int irq, struct apic_chip_data *data)
  {
        int cpu, vector;
        unsigned long flags;
  
        raw_spin_lock_irqsave(&vector_lock, flags);
 -      BUG_ON(!cfg->vector);
 +      BUG_ON(!data->cfg.vector);
  
 -      vector = cfg->vector;
 -      for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
 +      vector = data->cfg.vector;
 +      for_each_cpu_and(cpu, data->domain, cpu_online_mask)
                per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
  
 -      cfg->vector = 0;
 -      cpumask_clear(cfg->domain);
 +      data->cfg.vector = 0;
 +      cpumask_clear(data->domain);
  
 -      if (likely(!cfg->move_in_progress)) {
 +      if (likely(!data->move_in_progress)) {
                raw_spin_unlock_irqrestore(&vector_lock, flags);
                return;
        }
  
 -      for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
 +      for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
                for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
                     vector++) {
                        if (per_cpu(vector_irq, cpu)[vector] != irq)
                        break;
                }
        }
 -      cfg->move_in_progress = 0;
 +      data->move_in_progress = 0;
        raw_spin_unlock_irqrestore(&vector_lock, flags);
  }
  
 +void init_irq_alloc_info(struct irq_alloc_info *info,
 +                       const struct cpumask *mask)
 +{
 +      memset(info, 0, sizeof(*info));
 +      info->mask = mask;
 +}
 +
 +void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src)
 +{
 +      if (src)
 +              *dst = *src;
 +      else
 +              memset(dst, 0, sizeof(*dst));
 +}
 +
 +static inline const struct cpumask *
 +irq_alloc_info_get_mask(struct irq_alloc_info *info)
 +{
 +      return (!info || !info->mask) ? apic->target_cpus() : info->mask;
 +}
 +
 +static void x86_vector_free_irqs(struct irq_domain *domain,
 +                               unsigned int virq, unsigned int nr_irqs)
 +{
 +      struct irq_data *irq_data;
 +      int i;
 +
 +      for (i = 0; i < nr_irqs; i++) {
 +              irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
 +              if (irq_data && irq_data->chip_data) {
 +                      clear_irq_vector(virq + i, irq_data->chip_data);
 +                      free_apic_chip_data(irq_data->chip_data);
 +#ifdef        CONFIG_X86_IO_APIC
 +                      if (virq + i < nr_legacy_irqs())
 +                              legacy_irq_data[virq + i] = NULL;
 +#endif
 +                      irq_domain_reset_irq_data(irq_data);
 +              }
 +      }
 +}
 +
 +static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
 +                               unsigned int nr_irqs, void *arg)
 +{
 +      struct irq_alloc_info *info = arg;
 +      struct apic_chip_data *data;
 +      const struct cpumask *mask;
 +      struct irq_data *irq_data;
 +      int i, err;
 +
 +      if (disable_apic)
 +              return -ENXIO;
 +
 +      /* Currently vector allocator can't guarantee contiguous allocations */
 +      if ((info->flags & X86_IRQ_ALLOC_CONTIGUOUS_VECTORS) && nr_irqs > 1)
 +              return -ENOSYS;
 +
 +      mask = irq_alloc_info_get_mask(info);
 +      for (i = 0; i < nr_irqs; i++) {
 +              irq_data = irq_domain_get_irq_data(domain, virq + i);
 +              BUG_ON(!irq_data);
 +#ifdef        CONFIG_X86_IO_APIC
 +              if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
 +                      data = legacy_irq_data[virq + i];
 +              else
 +#endif
 +                      data = alloc_apic_chip_data(irq_data->node);
 +              if (!data) {
 +                      err = -ENOMEM;
 +                      goto error;
 +              }
 +
 +              irq_data->chip = &lapic_controller;
 +              irq_data->chip_data = data;
 +              irq_data->hwirq = virq + i;
 +              err = assign_irq_vector(virq, data, mask);
 +              if (err)
 +                      goto error;
 +      }
 +
 +      return 0;
 +
 +error:
 +      x86_vector_free_irqs(domain, virq, i + 1);
 +      return err;
 +}
 +
 +static const struct irq_domain_ops x86_vector_domain_ops = {
 +      .alloc  = x86_vector_alloc_irqs,
 +      .free   = x86_vector_free_irqs,
 +};
 +
  int __init arch_probe_nr_irqs(void)
  {
        int nr;
        return nr_legacy_irqs();
  }
  
-        * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
 +#ifdef        CONFIG_X86_IO_APIC
 +static void init_legacy_irqs(void)
 +{
 +      int i, node = cpu_to_node(0);
 +      struct apic_chip_data *data;
 +
 +      /*
 +       * For legacy IRQ's, start with assigning irq0 to irq15 to
-               /*
-                * For legacy IRQ's, start with assigning irq0 to irq15 to
-                * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
-                */
-               data->cfg.vector = IRQ0_VECTOR + i;
++       * ISA_IRQ_VECTOR(i) for all cpu's.
 +       */
 +      for (i = 0; i < nr_legacy_irqs(); i++) {
 +              data = legacy_irq_data[i] = alloc_apic_chip_data(node);
 +              BUG_ON(!data);
++
++              data->cfg.vector = ISA_IRQ_VECTOR(i);
 +              cpumask_setall(data->domain);
 +              irq_set_chip_data(i, data);
 +      }
 +}
 +#else
 +static void init_legacy_irqs(void) { }
 +#endif
 +
  int __init arch_early_irq_init(void)
  {
 +      init_legacy_irqs();
 +
 +      x86_vector_domain = irq_domain_add_tree(NULL, &x86_vector_domain_ops,
 +                                              NULL);
 +      BUG_ON(x86_vector_domain == NULL);
 +      irq_set_default_host(x86_vector_domain);
 +
 +      arch_init_msi_domain(x86_vector_domain);
 +      arch_init_htirq_domain(x86_vector_domain);
 +
 +      BUG_ON(!alloc_cpumask_var(&vector_cpumask, GFP_KERNEL));
 +
        return arch_early_ioapic_init();
  }
  
@@@ -405,7 -267,7 +402,7 @@@ static void __setup_vector_irq(int cpu
  {
        /* Initialize vector_irq on a new cpu */
        int irq, vector;
 -      struct irq_cfg *cfg;
 +      struct apic_chip_data *data;
  
        /*
         * vector_lock will make sure that we don't run into irq vector
        raw_spin_lock(&vector_lock);
        /* Mark the inuse vectors */
        for_each_active_irq(irq) {
 -              cfg = irq_cfg(irq);
 -              if (!cfg)
 +              data = apic_chip_data(irq_get_irq_data(irq));
 +              if (!data)
                        continue;
  
 -              if (!cpumask_test_cpu(cpu, cfg->domain))
 +              if (!cpumask_test_cpu(cpu, data->domain))
                        continue;
 -              vector = cfg->vector;
 +              vector = data->cfg.vector;
                per_cpu(vector_irq, cpu)[vector] = irq;
        }
        /* Mark the free vectors */
                if (irq <= VECTOR_UNDEFINED)
                        continue;
  
 -              cfg = irq_cfg(irq);
 -              if (!cpumask_test_cpu(cpu, cfg->domain))
 +              data = apic_chip_data(irq_get_irq_data(irq));
 +              if (!cpumask_test_cpu(cpu, data->domain))
                        per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
        }
        raw_spin_unlock(&vector_lock);
@@@ -452,20 -314,20 +449,20 @@@ void setup_vector_irq(int cpu
         * legacy vector to irq mapping:
         */
        for (irq = 0; irq < nr_legacy_irqs(); irq++)
-               per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq;
+               per_cpu(vector_irq, cpu)[ISA_IRQ_VECTOR(irq)] = irq;
  
        __setup_vector_irq(cpu);
  }
  
 -int apic_retrigger_irq(struct irq_data *data)
 +static int apic_retrigger_irq(struct irq_data *irq_data)
  {
 -      struct irq_cfg *cfg = irqd_cfg(data);
 +      struct apic_chip_data *data = apic_chip_data(irq_data);
        unsigned long flags;
        int cpu;
  
        raw_spin_lock_irqsave(&vector_lock, flags);
 -      cpu = cpumask_first_and(cfg->domain, cpu_online_mask);
 -      apic->send_IPI_mask(cpumask_of(cpu), cfg->vector);
 +      cpu = cpumask_first_and(data->domain, cpu_online_mask);
 +      apic->send_IPI_mask(cpumask_of(cpu), data->cfg.vector);
        raw_spin_unlock_irqrestore(&vector_lock, flags);
  
        return 1;
@@@ -478,62 -340,57 +475,62 @@@ void apic_ack_edge(struct irq_data *dat
        ack_APIC_irq();
  }
  
 -/*
 - * Either sets data->affinity to a valid value, and returns
 - * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
 - * leaves data->affinity untouched.
 - */
 -int apic_set_affinity(struct irq_data *data, const struct cpumask *mask,
 -                    unsigned int *dest_id)
 +static int apic_set_affinity(struct irq_data *irq_data,
 +                           const struct cpumask *dest, bool force)
  {
 -      struct irq_cfg *cfg = irqd_cfg(data);
 -      unsigned int irq = data->irq;
 -      int err;
 +      struct apic_chip_data *data = irq_data->chip_data;
 +      int err, irq = irq_data->irq;
  
        if (!config_enabled(CONFIG_SMP))
                return -EPERM;
  
 -      if (!cpumask_intersects(mask, cpu_online_mask))
 +      if (!cpumask_intersects(dest, cpu_online_mask))
                return -EINVAL;
  
 -      err = assign_irq_vector(irq, cfg, mask);
 -      if (err)
 -              return err;
 -
 -      err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id);
 +      err = assign_irq_vector(irq, data, dest);
        if (err) {
 -              if (assign_irq_vector(irq, cfg, data->affinity))
 +              struct irq_data *top = irq_get_irq_data(irq);
 +
 +              if (assign_irq_vector(irq, data, top->affinity))
                        pr_err("Failed to recover vector for irq %d\n", irq);
                return err;
        }
  
 -      cpumask_copy(data->affinity, mask);
 -
 -      return 0;
 +      return IRQ_SET_MASK_OK;
  }
  
 +static struct irq_chip lapic_controller = {
 +      .irq_ack                = apic_ack_edge,
 +      .irq_set_affinity       = apic_set_affinity,
 +      .irq_retrigger          = apic_retrigger_irq,
 +};
 +
  #ifdef CONFIG_SMP
 -void send_cleanup_vector(struct irq_cfg *cfg)
 +static void __send_cleanup_vector(struct apic_chip_data *data)
  {
        cpumask_var_t cleanup_mask;
  
        if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
                unsigned int i;
  
 -              for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
 +              for_each_cpu_and(i, data->old_domain, cpu_online_mask)
                        apic->send_IPI_mask(cpumask_of(i),
                                            IRQ_MOVE_CLEANUP_VECTOR);
        } else {
 -              cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
 +              cpumask_and(cleanup_mask, data->old_domain, cpu_online_mask);
                apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
                free_cpumask_var(cleanup_mask);
        }
 -      cfg->move_in_progress = 0;
 +      data->move_in_progress = 0;
 +}
 +
 +void send_cleanup_vector(struct irq_cfg *cfg)
 +{
 +      struct apic_chip_data *data;
 +
 +      data = container_of(cfg, struct apic_chip_data, cfg);
 +      if (data->move_in_progress)
 +              __send_cleanup_vector(data);
  }
  
  asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
                int irq;
                unsigned int irr;
                struct irq_desc *desc;
 -              struct irq_cfg *cfg;
 +              struct apic_chip_data *data;
  
                irq = __this_cpu_read(vector_irq[vector]);
  
                if (!desc)
                        continue;
  
 -              cfg = irq_cfg(irq);
 -              if (!cfg)
 +              data = apic_chip_data(&desc->irq_data);
 +              if (!data)
                        continue;
  
                raw_spin_lock(&desc->lock);
                 * Check if the irq migration is in progress. If so, we
                 * haven't received the cleanup request yet for this irq.
                 */
 -              if (cfg->move_in_progress)
 +              if (data->move_in_progress)
                        goto unlock;
  
 -              if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
 +              if (vector == data->cfg.vector &&
 +                  cpumask_test_cpu(me, data->domain))
                        goto unlock;
  
                irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
@@@ -600,15 -456,14 +597,15 @@@ unlock
  static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
  {
        unsigned me;
 +      struct apic_chip_data *data;
  
 -      if (likely(!cfg->move_in_progress))
 +      data = container_of(cfg, struct apic_chip_data, cfg);
 +      if (likely(!data->move_in_progress))
                return;
  
        me = smp_processor_id();
 -
 -      if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
 -              send_cleanup_vector(cfg);
 +      if (vector == data->cfg.vector && cpumask_test_cpu(me, data->domain))
 +              __send_cleanup_vector(data);
  }
  
  void irq_complete_move(struct irq_cfg *cfg)
@@@ -620,11 -475,46 +617,11 @@@ void irq_force_complete_move(int irq
  {
        struct irq_cfg *cfg = irq_cfg(irq);
  
 -      if (!cfg)
 -              return;
 -
 -      __irq_complete_move(cfg, cfg->vector);
 +      if (cfg)
 +              __irq_complete_move(cfg, cfg->vector);
  }
  #endif
  
 -/*
 - * Dynamic irq allocate and deallocation. Should be replaced by irq domains!
 - */
 -int arch_setup_hwirq(unsigned int irq, int node)
 -{
 -      struct irq_cfg *cfg;
 -      unsigned long flags;
 -      int ret;
 -
 -      cfg = alloc_irq_cfg(irq, node);
 -      if (!cfg)
 -              return -ENOMEM;
 -
 -      raw_spin_lock_irqsave(&vector_lock, flags);
 -      ret = __assign_irq_vector(irq, cfg, apic->target_cpus());
 -      raw_spin_unlock_irqrestore(&vector_lock, flags);
 -
 -      if (!ret)
 -              irq_set_chip_data(irq, cfg);
 -      else
 -              free_irq_cfg(irq, cfg);
 -      return ret;
 -}
 -
 -void arch_teardown_hwirq(unsigned int irq)
 -{
 -      struct irq_cfg *cfg = irq_cfg(irq);
 -
 -      free_remapped_irq(irq);
 -      clear_irq_vector(irq, cfg);
 -      free_irq_cfg(irq, cfg);
 -}
 -
  static void __init print_APIC_field(int base)
  {
        int i;
index 63b46414c80c78ab5845b58e46cd2ca0bd437e67,023cccf5a4aefb255f72a3a2673e3a827f453623..51203f60587f847d51eaa33638604a082a864f54
@@@ -555,7 -555,7 +555,7 @@@ wakeup_secondary_cpu_via_nmi(int apicid
  static int
  wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
  {
 -      unsigned long send_status, accept_status = 0;
 +      unsigned long send_status = 0, accept_status = 0;
        int maxlvt, num_starts, j;
  
        maxlvt = lapic_get_maxlvt();
        apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT,
                       phys_apicid);
  
 -      pr_debug("Waiting for send to finish...\n");
 -      send_status = safe_apic_wait_icr_idle();
 +      if (!cpu_has_x2apic) {
 +              pr_debug("Waiting for send to finish...\n");
 +              send_status = safe_apic_wait_icr_idle();
  
 -      mdelay(10);
 +              mdelay(10);
  
 -      pr_debug("Deasserting INIT\n");
 +              pr_debug("Deasserting INIT\n");
  
 -      /* Target chip */
 -      /* Send IPI */
 -      apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
 +              /* Target chip */
 +              /* Send IPI */
 +              apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid);
  
 -      pr_debug("Waiting for send to finish...\n");
 -      send_status = safe_apic_wait_icr_idle();
 +              pr_debug("Waiting for send to finish...\n");
 +              send_status = safe_apic_wait_icr_idle();
  
 -      mb();
 -      atomic_set(&init_deasserted, 1);
 +              mb();
 +              atomic_set(&init_deasserted, 1);
 +      } else if (tboot_enabled()) {
 +              /*
 +               * With tboot AP is actually spinning in a mini-guest before
 +               * receiving INIT. Upon receiving INIT ipi, AP need time to
 +               * VMExit, update VMCS to tracking SIPIs and VMResume.
 +               *
 +               * While AP is in root mode handling the INIT the CPU will drop
 +               * any SIPIs
 +               */
 +              udelay(10);
 +      }
  
        /*
         * Should we send STARTUP IPIs ?
                apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12),
                               phys_apicid);
  
 -              /*
 -               * Give the other CPU some time to accept the IPI.
 -               */
 -              udelay(300);
 +              if (!cpu_has_x2apic) {
 +                      /*
 +                       * Give the other CPU some time to accept the IPI.
 +                       */
 +                      udelay(300);
  
 -              pr_debug("Startup point 1\n");
 +                      pr_debug("Startup point 1\n");
  
 -              pr_debug("Waiting for send to finish...\n");
 -              send_status = safe_apic_wait_icr_idle();
 +                      pr_debug("Waiting for send to finish...\n");
 +                      send_status = safe_apic_wait_icr_idle();
 +
 +                      /*
 +                       * Give the other CPU some time to accept the IPI.
 +                       */
 +                      udelay(200);
 +              }
  
 -              /*
 -               * Give the other CPU some time to accept the IPI.
 -               */
 -              udelay(200);
                if (maxlvt > 3)         /* Due to the Pentium erratum 3AP.  */
                        apic_write(APIC_ESR, 0);
                accept_status = (apic_read(APIC_ESR) & 0xEF);
@@@ -807,8 -792,6 +807,6 @@@ void common_cpu_up(unsigned int cpu, st
        clear_tsk_thread_flag(idle, TIF_FORK);
        initial_gs = per_cpu_offset(cpu);
  #endif
-       per_cpu(kernel_stack, cpu) =
-               (unsigned long)task_stack_page(idle) + THREAD_SIZE;
  }
  
  /*
index 7ecc6b3180ba8b1b9aa5e065ddc42851a5cc5dbd,5709ae9c3e771d2f82a1bda2a23d500d8f4faffe..8fad71cc27e79ca2d29ac6e80698294a2d4c3d52
@@@ -8,7 -8,6 +8,7 @@@
  #include <linux/irq.h>
  #include <linux/intel-iommu.h>
  #include <linux/acpi.h>
 +#include <linux/irqdomain.h>
  #include <asm/io_apic.h>
  #include <asm/smp.h>
  #include <asm/cpu.h>
@@@ -32,21 -31,6 +32,21 @@@ struct hpet_scope 
        unsigned int devfn;
  };
  
 +struct irq_2_iommu {
 +      struct intel_iommu *iommu;
 +      u16 irte_index;
 +      u16 sub_handle;
 +      u8  irte_mask;
 +};
 +
 +struct intel_ir_data {
 +      struct irq_2_iommu                      irq_2_iommu;
 +      struct irte                             irte_entry;
 +      union {
 +              struct msi_msg                  msi_entry;
 +      };
 +};
 +
  #define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
  #define IRTE_DEST(dest) ((eim_mode) ? dest : dest << 8)
  
@@@ -66,14 -50,43 +66,14 @@@ static struct hpet_scope ir_hpet[MAX_HP
   * the dmar_global_lock.
   */
  static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
 +static struct irq_domain_ops intel_ir_domain_ops;
  
  static int __init parse_ioapics_under_ir(void);
  
 -static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 -{
 -      struct irq_cfg *cfg = irq_cfg(irq);
 -      return cfg ? &cfg->irq_2_iommu : NULL;
 -}
 -
 -static int get_irte(int irq, struct irte *entry)
 -{
 -      struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
 -      unsigned long flags;
 -      int index;
 -
 -      if (!entry || !irq_iommu)
 -              return -1;
 -
 -      raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
 -
 -      if (unlikely(!irq_iommu->iommu)) {
 -              raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 -              return -1;
 -      }
 -
 -      index = irq_iommu->irte_index + irq_iommu->sub_handle;
 -      *entry = *(irq_iommu->iommu->ir_table->base + index);
 -
 -      raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 -      return 0;
 -}
 -
 -static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
 +static int alloc_irte(struct intel_iommu *iommu, int irq,
 +                    struct irq_2_iommu *irq_iommu, u16 count)
  {
        struct ir_table *table = iommu->ir_table;
 -      struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
 -      struct irq_cfg *cfg = irq_cfg(irq);
        unsigned int mask = 0;
        unsigned long flags;
        int index;
        if (index < 0) {
                pr_warn("IR%d: can't allocate an IRTE\n", iommu->seq_id);
        } else {
 -              cfg->remapped = 1;
                irq_iommu->iommu = iommu;
                irq_iommu->irte_index =  index;
                irq_iommu->sub_handle = 0;
@@@ -121,9 -135,47 +121,9 @@@ static int qi_flush_iec(struct intel_io
        return qi_submit_sync(&desc, iommu);
  }
  
 -static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
 +static int modify_irte(struct irq_2_iommu *irq_iommu,
 +                     struct irte *irte_modified)
  {
 -      struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
 -      unsigned long flags;
 -      int index;
 -
 -      if (!irq_iommu)
 -              return -1;
 -
 -      raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
 -      *sub_handle = irq_iommu->sub_handle;
 -      index = irq_iommu->irte_index;
 -      raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 -      return index;
 -}
 -
 -static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
 -{
 -      struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
 -      struct irq_cfg *cfg = irq_cfg(irq);
 -      unsigned long flags;
 -
 -      if (!irq_iommu)
 -              return -1;
 -
 -      raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
 -
 -      cfg->remapped = 1;
 -      irq_iommu->iommu = iommu;
 -      irq_iommu->irte_index = index;
 -      irq_iommu->sub_handle = subhandle;
 -      irq_iommu->irte_mask = 0;
 -
 -      raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 -
 -      return 0;
 -}
 -
 -static int modify_irte(int irq, struct irte *irte_modified)
 -{
 -      struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        struct intel_iommu *iommu;
        unsigned long flags;
        struct irte *irte;
@@@ -190,7 -242,7 +190,7 @@@ static int clear_entries(struct irq_2_i
                return 0;
  
        iommu = irq_iommu->iommu;
 -      index = irq_iommu->irte_index + irq_iommu->sub_handle;
 +      index = irq_iommu->irte_index;
  
        start = iommu->ir_table->base + index;
        end = start + (1 << irq_iommu->irte_mask);
        return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
  }
  
 -static int free_irte(int irq)
 -{
 -      struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
 -      unsigned long flags;
 -      int rc;
 -
 -      if (!irq_iommu)
 -              return -1;
 -
 -      raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
 -
 -      rc = clear_entries(irq_iommu);
 -
 -      irq_iommu->iommu = NULL;
 -      irq_iommu->irte_index = 0;
 -      irq_iommu->sub_handle = 0;
 -      irq_iommu->irte_mask = 0;
 -
 -      raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 -
 -      return rc;
 -}
 -
  /*
   * source validation type
   */
@@@ -413,6 -488,7 +413,6 @@@ static int intel_setup_irq_remapping(st
  
        pages = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO,
                                 INTR_REMAP_PAGE_ORDER);
 -
        if (!pages) {
                pr_err("IR%d: failed to allocate pages of order %d\n",
                       iommu->seq_id, INTR_REMAP_PAGE_ORDER);
                goto out_free_pages;
        }
  
 +      iommu->ir_domain = irq_domain_add_hierarchy(arch_get_ir_parent_domain(),
 +                                                  0, INTR_REMAP_TABLE_ENTRIES,
 +                                                  NULL, &intel_ir_domain_ops,
 +                                                  iommu);
 +      if (!iommu->ir_domain) {
 +              pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
 +              goto out_free_bitmap;
 +      }
 +      iommu->ir_msi_domain = arch_create_msi_irq_domain(iommu->ir_domain);
 +
        ir_table->base = page_address(pages);
        ir_table->bitmap = bitmap;
        iommu->ir_table = ir_table;
        return 0;
  
 +out_free_bitmap:
 +      kfree(bitmap);
  out_free_pages:
        __free_pages(pages, INTR_REMAP_PAGE_ORDER);
  out_free_table:
  static void intel_teardown_irq_remapping(struct intel_iommu *iommu)
  {
        if (iommu && iommu->ir_table) {
 +              if (iommu->ir_msi_domain) {
 +                      irq_domain_remove(iommu->ir_msi_domain);
 +                      iommu->ir_msi_domain = NULL;
 +              }
 +              if (iommu->ir_domain) {
 +                      irq_domain_remove(iommu->ir_domain);
 +                      iommu->ir_domain = NULL;
 +              }
                free_pages((unsigned long)iommu->ir_table->base,
                           INTR_REMAP_PAGE_ORDER);
                kfree(iommu->ir_table->bitmap);
@@@ -581,10 -637,7 +581,7 @@@ static int __init intel_enable_irq_rema
        if (x2apic_supported()) {
                eim = !dmar_x2apic_optout();
                if (!eim)
-                       printk(KERN_WARNING
-                               "Your BIOS is broken and requested that x2apic be disabled.\n"
-                               "This will slightly decrease performance.\n"
-                               "Use 'intremap=no_x2apic_optout' to override BIOS request.\n");
+                       pr_info("x2apic is disabled because BIOS sets x2apic opt out bit. You can use 'intremap=no_x2apic_optout' to override the BIOS setting.\n");
        }
  
        for_each_iommu(iommu, drhd) {
  
        irq_remapping_enabled = 1;
  
 -      /*
 -       * VT-d has a different layout for IO-APIC entries when
 -       * interrupt remapping is enabled. So it needs a special routine
 -       * to print IO-APIC entries for debugging purposes too.
 -       */
 -      x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries;
 -
        pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
  
        return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
@@@ -885,7 -945,8 +882,7 @@@ error
        return -1;
  }
  
 -static void prepare_irte(struct irte *irte, int vector,
 -                       unsigned int dest)
 +static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
  {
        memset(irte, 0, sizeof(*irte));
  
        irte->redir_hint = 1;
  }
  
 -static int intel_setup_ioapic_entry(int irq,
 -                                  struct IO_APIC_route_entry *route_entry,
 -                                  unsigned int destination, int vector,
 -                                  struct io_apic_irq_attr *attr)
 +static struct irq_domain *intel_get_ir_irq_domain(struct irq_alloc_info *info)
  {
 -      int ioapic_id = mpc_ioapic_id(attr->ioapic);
 -      struct intel_iommu *iommu;
 -      struct IR_IO_APIC_route_entry *entry;
 -      struct irte irte;
 -      int index;
 -
 -      down_read(&dmar_global_lock);
 -      iommu = map_ioapic_to_ir(ioapic_id);
 -      if (!iommu) {
 -              pr_warn("No mapping iommu for ioapic %d\n", ioapic_id);
 -              index = -ENODEV;
 -      } else {
 -              index = alloc_irte(iommu, irq, 1);
 -              if (index < 0) {
 -                      pr_warn("Failed to allocate IRTE for ioapic %d\n",
 -                              ioapic_id);
 -                      index = -ENOMEM;
 -              }
 -      }
 -      up_read(&dmar_global_lock);
 -      if (index < 0)
 -              return index;
 -
 -      prepare_irte(&irte, vector, destination);
 +      struct intel_iommu *iommu = NULL;
  
 -      /* Set source-id of interrupt request */
 -      set_ioapic_sid(&irte, ioapic_id);
 +      if (!info)
 +              return NULL;
  
 -      modify_irte(irq, &irte);
 +      switch (info->type) {
 +      case X86_IRQ_ALLOC_TYPE_IOAPIC:
 +              iommu = map_ioapic_to_ir(info->ioapic_id);
 +              break;
 +      case X86_IRQ_ALLOC_TYPE_HPET:
 +              iommu = map_hpet_to_ir(info->hpet_id);
 +              break;
 +      case X86_IRQ_ALLOC_TYPE_MSI:
 +      case X86_IRQ_ALLOC_TYPE_MSIX:
 +              iommu = map_dev_to_ir(info->msi_dev);
 +              break;
 +      default:
 +              BUG_ON(1);
 +              break;
 +      }
  
 -      apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: "
 -              "Set IRTE entry (P:%d FPD:%d Dst_Mode:%d "
 -              "Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X "
 -              "Avail:%X Vector:%02X Dest:%08X "
 -              "SID:%04X SQ:%X SVT:%X)\n",
 -              attr->ioapic, irte.present, irte.fpd, irte.dst_mode,
 -              irte.redir_hint, irte.trigger_mode, irte.dlvry_mode,
 -              irte.avail, irte.vector, irte.dest_id,
 -              irte.sid, irte.sq, irte.svt);
 +      return iommu ? iommu->ir_domain : NULL;
 +}
  
 -      entry = (struct IR_IO_APIC_route_entry *)route_entry;
 -      memset(entry, 0, sizeof(*entry));
 +static struct irq_domain *intel_get_irq_domain(struct irq_alloc_info *info)
 +{
 +      struct intel_iommu *iommu;
  
 -      entry->index2   = (index >> 15) & 0x1;
 -      entry->zero     = 0;
 -      entry->format   = 1;
 -      entry->index    = (index & 0x7fff);
 -      /*
 -       * IO-APIC RTE will be configured with virtual vector.
 -       * irq handler will do the explicit EOI to the io-apic.
 -       */
 -      entry->vector   = attr->ioapic_pin;
 -      entry->mask     = 0;                    /* enable IRQ */
 -      entry->trigger  = attr->trigger;
 -      entry->polarity = attr->polarity;
 +      if (!info)
 +              return NULL;
  
 -      /* Mask level triggered irqs.
 -       * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
 -       */
 -      if (attr->trigger)
 -              entry->mask = 1;
 +      switch (info->type) {
 +      case X86_IRQ_ALLOC_TYPE_MSI:
 +      case X86_IRQ_ALLOC_TYPE_MSIX:
 +              iommu = map_dev_to_ir(info->msi_dev);
 +              if (iommu)
 +                      return iommu->ir_msi_domain;
 +              break;
 +      default:
 +              break;
 +      }
  
 -      return 0;
 +      return NULL;
  }
  
 +struct irq_remap_ops intel_irq_remap_ops = {
 +      .prepare                = intel_prepare_irq_remapping,
 +      .enable                 = intel_enable_irq_remapping,
 +      .disable                = disable_irq_remapping,
 +      .reenable               = reenable_irq_remapping,
 +      .enable_faulting        = enable_drhd_fault_handling,
 +      .get_ir_irq_domain      = intel_get_ir_irq_domain,
 +      .get_irq_domain         = intel_get_irq_domain,
 +};
 +
  /*
   * Migrate the IO-APIC irq in the presence of intr-remapping.
   *
   * is used to migrate MSI irq's in the presence of interrupt-remapping.
   */
  static int
 -intel_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
 -                        bool force)
 +intel_ir_set_affinity(struct irq_data *data, const struct cpumask *mask,
 +                    bool force)
  {
 +      struct intel_ir_data *ir_data = data->chip_data;
 +      struct irte *irte = &ir_data->irte_entry;
        struct irq_cfg *cfg = irqd_cfg(data);
 -      unsigned int dest, irq = data->irq;
 -      struct irte irte;
 -      int err;
 -
 -      if (!config_enabled(CONFIG_SMP))
 -              return -EINVAL;
 -
 -      if (!cpumask_intersects(mask, cpu_online_mask))
 -              return -EINVAL;
 -
 -      if (get_irte(irq, &irte))
 -              return -EBUSY;
 -
 -      err = assign_irq_vector(irq, cfg, mask);
 -      if (err)
 -              return err;
 -
 -      err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest);
 -      if (err) {
 -              if (assign_irq_vector(irq, cfg, data->affinity))
 -                      pr_err("Failed to recover vector for irq %d\n", irq);
 -              return err;
 -      }
 +      struct irq_data *parent = data->parent_data;
 +      int ret;
  
 -      irte.vector = cfg->vector;
 -      irte.dest_id = IRTE_DEST(dest);
 +      ret = parent->chip->irq_set_affinity(parent, mask, force);
 +      if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
 +              return ret;
  
        /*
         * Atomically updates the IRTE with the new destination, vector
         * and flushes the interrupt entry cache.
         */
 -      modify_irte(irq, &irte);
 +      irte->vector = cfg->vector;
 +      irte->dest_id = IRTE_DEST(cfg->dest_apicid);
 +      modify_irte(&ir_data->irq_2_iommu, irte);
  
        /*
         * After this point, all the interrupts will start arriving
         * at the new destination. So, time to cleanup the previous
         * vector allocation.
         */
 -      if (cfg->move_in_progress)
 -              send_cleanup_vector(cfg);
 +      send_cleanup_vector(cfg);
  
 -      cpumask_copy(data->affinity, mask);
 -      return 0;
 +      return IRQ_SET_MASK_OK_DONE;
  }
  
 -static void intel_compose_msi_msg(struct pci_dev *pdev,
 -                                unsigned int irq, unsigned int dest,
 -                                struct msi_msg *msg, u8 hpet_id)
 +static void intel_ir_compose_msi_msg(struct irq_data *irq_data,
 +                                   struct msi_msg *msg)
  {
 -      struct irq_cfg *cfg;
 -      struct irte irte;
 -      u16 sub_handle = 0;
 -      int ir_index;
 -
 -      cfg = irq_cfg(irq);
 +      struct intel_ir_data *ir_data = irq_data->chip_data;
  
 -      ir_index = map_irq_to_irte_handle(irq, &sub_handle);
 -      BUG_ON(ir_index == -1);
 -
 -      prepare_irte(&irte, cfg->vector, dest);
 -
 -      /* Set source-id of interrupt request */
 -      if (pdev)
 -              set_msi_sid(&irte, pdev);
 -      else
 -              set_hpet_sid(&irte, hpet_id);
 +      *msg = ir_data->msi_entry;
 +}
  
 -      modify_irte(irq, &irte);
 +static struct irq_chip intel_ir_chip = {
 +      .irq_ack = ir_ack_apic_edge,
 +      .irq_set_affinity = intel_ir_set_affinity,
 +      .irq_compose_msi_msg = intel_ir_compose_msi_msg,
 +};
  
 -      msg->address_hi = MSI_ADDR_BASE_HI;
 -      msg->data = sub_handle;
 -      msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
 -                        MSI_ADDR_IR_SHV |
 -                        MSI_ADDR_IR_INDEX1(ir_index) |
 -                        MSI_ADDR_IR_INDEX2(ir_index);
 +static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
 +                                           struct irq_cfg *irq_cfg,
 +                                           struct irq_alloc_info *info,
 +                                           int index, int sub_handle)
 +{
 +      struct IR_IO_APIC_route_entry *entry;
 +      struct irte *irte = &data->irte_entry;
 +      struct msi_msg *msg = &data->msi_entry;
 +
 +      prepare_irte(irte, irq_cfg->vector, irq_cfg->dest_apicid);
 +      switch (info->type) {
 +      case X86_IRQ_ALLOC_TYPE_IOAPIC:
 +              /* Set source-id of interrupt request */
 +              set_ioapic_sid(irte, info->ioapic_id);
 +              apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: Set IRTE entry (P:%d FPD:%d Dst_Mode:%d Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X Avail:%X Vector:%02X Dest:%08X SID:%04X SQ:%X SVT:%X)\n",
 +                      info->ioapic_id, irte->present, irte->fpd,
 +                      irte->dst_mode, irte->redir_hint,
 +                      irte->trigger_mode, irte->dlvry_mode,
 +                      irte->avail, irte->vector, irte->dest_id,
 +                      irte->sid, irte->sq, irte->svt);
 +
 +              entry = (struct IR_IO_APIC_route_entry *)info->ioapic_entry;
 +              info->ioapic_entry = NULL;
 +              memset(entry, 0, sizeof(*entry));
 +              entry->index2   = (index >> 15) & 0x1;
 +              entry->zero     = 0;
 +              entry->format   = 1;
 +              entry->index    = (index & 0x7fff);
 +              /*
 +               * IO-APIC RTE will be configured with virtual vector.
 +               * irq handler will do the explicit EOI to the io-apic.
 +               */
 +              entry->vector   = info->ioapic_pin;
 +              entry->mask     = 0;                    /* enable IRQ */
 +              entry->trigger  = info->ioapic_trigger;
 +              entry->polarity = info->ioapic_polarity;
 +              if (info->ioapic_trigger)
 +                      entry->mask = 1; /* Mask level triggered irqs. */
 +              break;
 +
 +      case X86_IRQ_ALLOC_TYPE_HPET:
 +      case X86_IRQ_ALLOC_TYPE_MSI:
 +      case X86_IRQ_ALLOC_TYPE_MSIX:
 +              if (info->type == X86_IRQ_ALLOC_TYPE_HPET)
 +                      set_hpet_sid(irte, info->hpet_id);
 +              else
 +                      set_msi_sid(irte, info->msi_dev);
 +
 +              msg->address_hi = MSI_ADDR_BASE_HI;
 +              msg->data = sub_handle;
 +              msg->address_lo = MSI_ADDR_BASE_LO | MSI_ADDR_IR_EXT_INT |
 +                                MSI_ADDR_IR_SHV |
 +                                MSI_ADDR_IR_INDEX1(index) |
 +                                MSI_ADDR_IR_INDEX2(index);
 +              break;
 +
 +      default:
 +              BUG_ON(1);
 +              break;
 +      }
  }
  
 -/*
 - * Map the PCI dev to the corresponding remapping hardware unit
 - * and allocate 'nvec' consecutive interrupt-remapping table entries
 - * in it.
 - */
 -static int intel_msi_alloc_irq(struct pci_dev *dev, int irq, int nvec)
 +static void intel_free_irq_resources(struct irq_domain *domain,
 +                                   unsigned int virq, unsigned int nr_irqs)
  {
 -      struct intel_iommu *iommu;
 -      int index;
 +      struct irq_data *irq_data;
 +      struct intel_ir_data *data;
 +      struct irq_2_iommu *irq_iommu;
 +      unsigned long flags;
 +      int i;
  
 -      down_read(&dmar_global_lock);
 -      iommu = map_dev_to_ir(dev);
 -      if (!iommu) {
 -              printk(KERN_ERR
 -                     "Unable to map PCI %s to iommu\n", pci_name(dev));
 -              index = -ENOENT;
 -      } else {
 -              index = alloc_irte(iommu, irq, nvec);
 -              if (index < 0) {
 -                      printk(KERN_ERR
 -                             "Unable to allocate %d IRTE for PCI %s\n",
 -                             nvec, pci_name(dev));
 -                      index = -ENOSPC;
 +      for (i = 0; i < nr_irqs; i++) {
 +              irq_data = irq_domain_get_irq_data(domain, virq  + i);
 +              if (irq_data && irq_data->chip_data) {
 +                      data = irq_data->chip_data;
 +                      irq_iommu = &data->irq_2_iommu;
 +                      raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
 +                      clear_entries(irq_iommu);
 +                      raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 +                      irq_domain_reset_irq_data(irq_data);
 +                      kfree(data);
                }
        }
 -      up_read(&dmar_global_lock);
 -
 -      return index;
  }
  
 -static int intel_msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
 -                             int index, int sub_handle)
 +static int intel_irq_remapping_alloc(struct irq_domain *domain,
 +                                   unsigned int virq, unsigned int nr_irqs,
 +                                   void *arg)
  {
 -      struct intel_iommu *iommu;
 -      int ret = -ENOENT;
 +      struct intel_iommu *iommu = domain->host_data;
 +      struct irq_alloc_info *info = arg;
 +      struct intel_ir_data *data, *ird;
 +      struct irq_data *irq_data;
 +      struct irq_cfg *irq_cfg;
 +      int i, ret, index;
 +
 +      if (!info || !iommu)
 +              return -EINVAL;
 +      if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_MSI &&
 +          info->type != X86_IRQ_ALLOC_TYPE_MSIX)
 +              return -EINVAL;
 +
 +      /*
 +       * With IRQ remapping enabled, don't need contiguous CPU vectors
 +       * to support multiple MSI interrupts.
 +       */
 +      if (info->type == X86_IRQ_ALLOC_TYPE_MSI)
 +              info->flags &= ~X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
 +
 +      ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
 +      if (ret < 0)
 +              return ret;
 +
 +      ret = -ENOMEM;
 +      data = kzalloc(sizeof(*data), GFP_KERNEL);
 +      if (!data)
 +              goto out_free_parent;
  
        down_read(&dmar_global_lock);
 -      iommu = map_dev_to_ir(pdev);
 -      if (iommu) {
 -              /*
 -               * setup the mapping between the irq and the IRTE
 -               * base index, the sub_handle pointing to the
 -               * appropriate interrupt remap table entry.
 -               */
 -              set_irte_irq(irq, iommu, index, sub_handle);
 -              ret = 0;
 -      }
 +      index = alloc_irte(iommu, virq, &data->irq_2_iommu, nr_irqs);
        up_read(&dmar_global_lock);
 +      if (index < 0) {
 +              pr_warn("Failed to allocate IRTE\n");
 +              kfree(data);
 +              goto out_free_parent;
 +      }
  
 +      for (i = 0; i < nr_irqs; i++) {
 +              irq_data = irq_domain_get_irq_data(domain, virq + i);
 +              irq_cfg = irqd_cfg(irq_data);
 +              if (!irq_data || !irq_cfg) {
 +                      ret = -EINVAL;
 +                      goto out_free_data;
 +              }
 +
 +              if (i > 0) {
 +                      ird = kzalloc(sizeof(*ird), GFP_KERNEL);
 +                      if (!ird)
 +                              goto out_free_data;
 +                      /* Initialize the common data */
 +                      ird->irq_2_iommu = data->irq_2_iommu;
 +                      ird->irq_2_iommu.sub_handle = i;
 +              } else {
 +                      ird = data;
 +              }
 +
 +              irq_data->hwirq = (index << 16) + i;
 +              irq_data->chip_data = ird;
 +              irq_data->chip = &intel_ir_chip;
 +              intel_irq_remapping_prepare_irte(ird, irq_cfg, info, index, i);
 +              irq_set_status_flags(virq + i, IRQ_MOVE_PCNTXT);
 +      }
 +      return 0;
 +
 +out_free_data:
 +      intel_free_irq_resources(domain, virq, i);
 +out_free_parent:
 +      irq_domain_free_irqs_common(domain, virq, nr_irqs);
        return ret;
  }
  
 -static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
 +static void intel_irq_remapping_free(struct irq_domain *domain,
 +                                   unsigned int virq, unsigned int nr_irqs)
  {
 -      int ret = -1;
 -      struct intel_iommu *iommu;
 -      int index;
 +      intel_free_irq_resources(domain, virq, nr_irqs);
 +      irq_domain_free_irqs_common(domain, virq, nr_irqs);
 +}
  
 -      down_read(&dmar_global_lock);
 -      iommu = map_hpet_to_ir(id);
 -      if (iommu) {
 -              index = alloc_irte(iommu, irq, 1);
 -              if (index >= 0)
 -                      ret = 0;
 -      }
 -      up_read(&dmar_global_lock);
 +static void intel_irq_remapping_activate(struct irq_domain *domain,
 +                                       struct irq_data *irq_data)
 +{
 +      struct intel_ir_data *data = irq_data->chip_data;
  
 -      return ret;
 +      modify_irte(&data->irq_2_iommu, &data->irte_entry);
  }
  
 -struct irq_remap_ops intel_irq_remap_ops = {
 -      .prepare                = intel_prepare_irq_remapping,
 -      .enable                 = intel_enable_irq_remapping,
 -      .disable                = disable_irq_remapping,
 -      .reenable               = reenable_irq_remapping,
 -      .enable_faulting        = enable_drhd_fault_handling,
 -      .setup_ioapic_entry     = intel_setup_ioapic_entry,
 -      .set_affinity           = intel_ioapic_set_affinity,
 -      .free_irq               = free_irte,
 -      .compose_msi_msg        = intel_compose_msi_msg,
 -      .msi_alloc_irq          = intel_msi_alloc_irq,
 -      .msi_setup_irq          = intel_msi_setup_irq,
 -      .alloc_hpet_msi         = intel_alloc_hpet_msi,
 +static void intel_irq_remapping_deactivate(struct irq_domain *domain,
 +                                         struct irq_data *irq_data)
 +{
 +      struct intel_ir_data *data = irq_data->chip_data;
 +      struct irte entry;
 +
 +      memset(&entry, 0, sizeof(entry));
 +      modify_irte(&data->irq_2_iommu, &entry);
 +}
 +
 +static struct irq_domain_ops intel_ir_domain_ops = {
 +      .alloc = intel_irq_remapping_alloc,
 +      .free = intel_irq_remapping_free,
 +      .activate = intel_irq_remapping_activate,
 +      .deactivate = intel_irq_remapping_deactivate,
  };
  
  /*
index ecaf3a93784527cb6ee93c2b3f20f3fd9c66c520,796ef9645827f000cb76ce4cd8637dc6cfa4db7a..0af9b03e2b1c8cd4a46d99eebe0bbe589f50b864
@@@ -115,10 -115,19 +115,19 @@@ static inline void dmar_writeq(void __i
   * Extended Capability Register
   */
  
- #define ecap_niotlb_iunits(e) ((((e) >> 24) & 0xff) + 1)
+ #define ecap_pss(e)           ((e >> 35) & 0x1f)
+ #define ecap_eafs(e)          ((e >> 34) & 0x1)
+ #define ecap_nwfs(e)          ((e >> 33) & 0x1)
+ #define ecap_srs(e)           ((e >> 31) & 0x1)
+ #define ecap_ers(e)           ((e >> 30) & 0x1)
+ #define ecap_prs(e)           ((e >> 29) & 0x1)
+ #define ecap_pasid(e)         ((e >> 28) & 0x1)
+ #define ecap_dis(e)           ((e >> 27) & 0x1)
+ #define ecap_nest(e)          ((e >> 26) & 0x1)
+ #define ecap_mts(e)           ((e >> 25) & 0x1)
+ #define ecap_ecs(e)           ((e >> 24) & 0x1)
  #define ecap_iotlb_offset(e)  ((((e) >> 8) & 0x3ff) * 16)
- #define ecap_max_iotlb_offset(e) \
-       (ecap_iotlb_offset(e) + ecap_niotlb_iunits(e) * 16)
+ #define ecap_max_iotlb_offset(e) (ecap_iotlb_offset(e) + 16)
  #define ecap_coherent(e)      ((e) & 0x1)
  #define ecap_qis(e)           ((e) & 0x2)
  #define ecap_pass_through(e)  ((e >> 6) & 0x1)
  #define DMA_GSTS_IRES (((u32)1) << 25)
  #define DMA_GSTS_CFIS (((u32)1) << 23)
  
+ /* DMA_RTADDR_REG */
+ #define DMA_RTADDR_RTT (((u64)1) << 11)
  /* CCMD_REG */
  #define DMA_CCMD_ICC (((u64)1) << 63)
  #define DMA_CCMD_GLOBAL_INVL (((u64)1) << 61)
@@@ -286,8 -298,6 +298,8 @@@ struct q_inval 
  
  #define INTR_REMAP_TABLE_ENTRIES      65536
  
 +struct irq_domain;
 +
  struct ir_table {
        struct irte *base;
        unsigned long *bitmap;
@@@ -337,8 -347,6 +349,8 @@@ struct intel_iommu 
  
  #ifdef CONFIG_IRQ_REMAP
        struct ir_table *ir_table;      /* Interrupt remapping info */
 +      struct irq_domain *ir_domain;
 +      struct irq_domain *ir_msi_domain;
  #endif
        struct device   *iommu_dev; /* IOMMU-sysfs device */
        int             node;