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>
44 files changed:
arch/ia64/include/asm/irq_remapping.h
arch/ia64/kernel/msi_ia64.c
arch/x86/Kconfig
arch/x86/include/asm/hpet.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/irq_remapping.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/irqdomain.h [new file with mode: 0644]
arch/x86/include/asm/msi.h [new file with mode: 0644]
arch/x86/include/asm/pci.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apb_timer.c
arch/x86/kernel/apic/htirq.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/msi.c
arch/x86/kernel/apic/vector.c
arch/x86/kernel/apic/x2apic_phys.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/hpet.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/setup.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/x86_init.c
arch/x86/pci/intel_mid_pci.c
arch/x86/platform/intel-mid/device_libs/platform_wdt.c
arch/x86/platform/intel-mid/intel-mid.c
arch/x86/platform/intel-mid/sfi.c
arch/x86/platform/sfi/sfi.c
arch/x86/platform/uv/uv_irq.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_proto.h
drivers/iommu/amd_iommu_types.h
drivers/iommu/dmar.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/irq_remapping.c
drivers/iommu/irq_remapping.h
drivers/pci/htirq.c
drivers/pci/quirks.c
include/linux/dmar.h
include/linux/htirq.h
include/linux/intel-iommu.h

index e3b3556e2e1bb8d32b67a1b63e4de3e2708af0b8..a8687b1d8906912ab458b9640db72c8655115a3f 100644 (file)
@@ -1,6 +1,4 @@
 #ifndef __IA64_INTR_REMAPPING_H
 #define __IA64_INTR_REMAPPING_H
 #define irq_remapping_enabled 0
-#define dmar_alloc_hwirq       create_irq
-#define dmar_free_hwirq                destroy_irq
 #endif
index 9dd7464f8c1742848011ce1397ef8a79f1e60d4f..d70bf15c690a53227142b6027ce7bb116475ed9d 100644 (file)
@@ -165,7 +165,7 @@ static struct irq_chip dmar_msi_type = {
        .irq_retrigger = ia64_msi_retrigger_irq,
 };
 
-static int
+static void
 msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
 {
        struct irq_cfg *cfg = irq_cfg + irq;
@@ -186,21 +186,29 @@ msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
                MSI_DATA_LEVEL_ASSERT |
                MSI_DATA_DELIVERY_FIXED |
                MSI_DATA_VECTOR(cfg->vector);
-       return 0;
 }
 
-int arch_setup_dmar_msi(unsigned int irq)
+int dmar_alloc_hwirq(int id, int node, void *arg)
 {
-       int ret;
+       int irq;
        struct msi_msg msg;
 
-       ret = msi_compose_msg(NULL, irq, &msg);
-       if (ret < 0)
-               return ret;
-       dmar_msi_write(irq, &msg);
-       irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
-                                     "edge");
-       return 0;
+       irq = create_irq();
+       if (irq > 0) {
+               irq_set_handler_data(irq, arg);
+               irq_set_chip_and_handler_name(irq, &dmar_msi_type,
+                                             handle_edge_irq, "edge");
+               msi_compose_msg(NULL, irq, &msg);
+               dmar_msi_write(irq, &msg);
+       }
+
+       return irq;
+}
+
+void dmar_free_hwirq(int irq)
+{
+       irq_set_handler_data(irq, NULL);
+       destroy_irq(irq);
 }
 #endif /* CONFIG_INTEL_IOMMU */
 
index 226d5696e1d1dd5fe715124710b0f2cd04f8c495..6bbb991d0f3c17396d1a89ec11ba9af5ce708fa2 100644 (file)
@@ -341,7 +341,7 @@ config X86_FEATURE_NAMES
 
 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.
 
@@ -466,7 +466,6 @@ config X86_INTEL_CE
        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
@@ -914,12 +913,12 @@ config X86_UP_IOAPIC
 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 36f7125945e3e241cdf2ac825124fd8d7883e0ba..5fa9fb0f8809902a8e15f6f8fa1d245d379a6a16 100644 (file)
@@ -74,20 +74,16 @@ extern unsigned int hpet_readl(unsigned int a);
 extern void force_hpet_resume(void);
 
 struct irq_data;
+struct hpet_dev;
+struct irq_domain;
+
 extern void hpet_msi_unmask(struct irq_data *data);
 extern void hpet_msi_mask(struct irq_data *data);
-struct hpet_dev;
 extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg);
 extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
-
-#ifdef CONFIG_PCI_MSI
-extern int default_setup_hpet_msi(unsigned int irq, unsigned int id);
-#else
-static inline int default_setup_hpet_msi(unsigned int irq, unsigned int id)
-{
-       return -EINVAL;
-}
-#endif
+extern struct irq_domain *hpet_create_irq_domain(int hpet_id);
+extern int hpet_assign_irq(struct irq_domain *domain,
+                          struct hpet_dev *dev, int dev_num);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
 
index 014c6382ffcea3a3edf6f37ae5b9cb70a2b967ea..9472c9aff26de0a98ebcabdbac801b8ebcd0d8ac 100644 (file)
@@ -60,53 +60,84 @@ extern void trace_call_function_single_interrupt(void);
 #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 {
+                       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 {
-                       struct list_head        irq_2_pin;
+                       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 *);
@@ -116,10 +147,7 @@ static inline void send_cleanup_vector(struct irq_cfg *c) { }
 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) {}
index 2f91685fe1cdb51d937eb20d29c46952d54f298f..6cbf2cfb3f8a02481d1c5c63b99eafb0c29eba35 100644 (file)
@@ -95,9 +95,22 @@ struct IR_IO_APIC_route_entry {
                index           : 15;
 } __attribute__ ((packed));
 
-#define IOAPIC_AUTO     -1
-#define IOAPIC_EDGE     0
-#define IOAPIC_LEVEL    1
+struct irq_alloc_info;
+struct ioapic_domain_cfg;
+
+#define IOAPIC_AUTO                    -1
+#define IOAPIC_EDGE                    0
+#define IOAPIC_LEVEL                   1
+
+#define IOAPIC_MASKED                  1
+#define IOAPIC_UNMASKED                        0
+
+#define IOAPIC_POL_HIGH                        0
+#define IOAPIC_POL_LOW                 1
+
+#define IOAPIC_DEST_MODE_PHYSICAL      0
+#define IOAPIC_DEST_MODE_LOGICAL       1
+
 #define        IOAPIC_MAP_ALLOC                0x1
 #define        IOAPIC_MAP_CHECK                0x2
 
@@ -110,9 +123,6 @@ extern int nr_ioapics;
 
 extern int mpc_ioapic_id(int ioapic);
 extern unsigned int mpc_ioapic_addr(int ioapic);
-extern struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic);
-
-#define MP_MAX_IOAPIC_PIN 127
 
 /* # of MP IRQ source entries */
 extern int mp_irq_entries;
@@ -120,9 +130,6 @@ extern int mp_irq_entries;
 /* MP IRQ source entries */
 extern struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES];
 
-/* Older SiS APIC requires we rewrite the index register */
-extern int sis_apic_bug;
-
 /* 1 if "noapic" boot option passed */
 extern int skip_ioapic_setup;
 
@@ -132,6 +139,8 @@ extern int noioapicquirk;
 /* -1 if "noapic" boot option passed */
 extern int noioapicreroute;
 
+extern u32 gsi_top;
+
 extern unsigned long io_apic_irqs;
 
 #define IO_APIC_IRQ(x) (((x) >= NR_IRQS_LEGACY) || ((1 << (x)) & io_apic_irqs))
@@ -147,13 +156,6 @@ struct irq_cfg;
 extern void ioapic_insert_resources(void);
 extern int arch_early_ioapic_init(void);
 
-extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
-                                    unsigned int, int,
-                                    struct io_apic_irq_attr *);
-extern void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg);
-
-extern void native_eoi_ioapic_pin(int apic, int pin, int vector);
-
 extern int save_ioapic_entries(void);
 extern void mask_ioapic_entries(void);
 extern int restore_ioapic_entries(void);
@@ -161,82 +163,32 @@ extern int restore_ioapic_entries(void);
 extern void setup_ioapic_ids_from_mpc(void);
 extern void setup_ioapic_ids_from_mpc_nocheck(void);
 
-struct io_apic_irq_attr {
-       int ioapic;
-       int ioapic_pin;
-       int trigger;
-       int polarity;
-};
-
-enum ioapic_domain_type {
-       IOAPIC_DOMAIN_INVALID,
-       IOAPIC_DOMAIN_LEGACY,
-       IOAPIC_DOMAIN_STRICT,
-       IOAPIC_DOMAIN_DYNAMIC,
-};
-
-struct device_node;
-struct irq_domain;
-struct irq_domain_ops;
-
-struct ioapic_domain_cfg {
-       enum ioapic_domain_type         type;
-       const struct irq_domain_ops     *ops;
-       struct device_node              *dev;
-};
-
-struct mp_ioapic_gsi{
-       u32 gsi_base;
-       u32 gsi_end;
-};
-extern u32 gsi_top;
-
 extern int mp_find_ioapic(u32 gsi);
 extern int mp_find_ioapic_pin(int ioapic, u32 gsi);
-extern u32 mp_pin_to_gsi(int ioapic, int pin);
-extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags);
+extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags,
+                            struct irq_alloc_info *info);
 extern void mp_unmap_irq(int irq);
 extern int mp_register_ioapic(int id, u32 address, u32 gsi_base,
                              struct ioapic_domain_cfg *cfg);
 extern int mp_unregister_ioapic(u32 gsi_base);
 extern int mp_ioapic_registered(u32 gsi_base);
-extern int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
-                           irq_hw_number_t hwirq);
-extern void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq);
-extern int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node);
-extern void __init pre_init_apic_IRQ0(void);
+
+extern void ioapic_set_alloc_attr(struct irq_alloc_info *info,
+                                 int node, int trigger, int polarity);
 
 extern void mp_save_irq(struct mpc_intsrc *m);
 
 extern void disable_ioapic_support(void);
 
-extern void __init native_io_apic_init_mappings(void);
+extern void __init io_apic_init_mappings(void);
 extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
-extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
-extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
 extern void native_disable_io_apic(void);
-extern void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
-extern void intel_ir_io_apic_print_entries(unsigned int apic, unsigned int nr_entries);
-extern int native_ioapic_set_affinity(struct irq_data *,
-                                     const struct cpumask *,
-                                     bool);
 
 static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
 {
        return x86_io_apic_ops.read(apic, reg);
 }
 
-static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
-{
-       x86_io_apic_ops.write(apic, reg, value);
-}
-static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
-{
-       x86_io_apic_ops.modify(apic, reg, value);
-}
-
-extern void io_apic_eoi(unsigned int apic, unsigned int vector);
-
 extern void setup_IO_APIC(void);
 extern void enable_IO_APIC(void);
 extern void disable_IO_APIC(void);
@@ -253,8 +205,12 @@ static inline int arch_early_ioapic_init(void) { return 0; }
 static inline void print_IO_APICs(void) {}
 #define gsi_top (NR_IRQS_LEGACY)
 static inline int mp_find_ioapic(u32 gsi) { return 0; }
-static inline u32 mp_pin_to_gsi(int ioapic, int pin) { return UINT_MAX; }
-static inline int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) { return gsi; }
+static inline int mp_map_gsi_to_irq(u32 gsi, unsigned int flags,
+                                   struct irq_alloc_info *info)
+{
+       return gsi;
+}
+
 static inline void mp_unmap_irq(int irq) { }
 
 static inline int save_ioapic_entries(void)
@@ -268,17 +224,11 @@ static inline int restore_ioapic_entries(void)
        return -ENOMEM;
 }
 
-static inline void mp_save_irq(struct mpc_intsrc *m) { };
+static inline void mp_save_irq(struct mpc_intsrc *m) { }
 static inline void disable_ioapic_support(void) { }
-#define native_io_apic_init_mappings   NULL
+static inline void io_apic_init_mappings(void) { }
 #define native_io_apic_read            NULL
-#define native_io_apic_write           NULL
-#define native_io_apic_modify          NULL
 #define native_disable_io_apic         NULL
-#define native_io_apic_print_entries   NULL
-#define native_ioapic_set_affinity     NULL
-#define native_setup_ioapic_entry      NULL
-#define native_eoi_ioapic_pin          NULL
 
 static inline void setup_IO_APIC(void) { }
 static inline void enable_IO_APIC(void) { }
index 6224d316c405c444553877845385e2d7b151c161..78974fbc33b47412ff22c6a611d7aee74371b624 100644 (file)
 #ifndef __X86_IRQ_REMAPPING_H
 #define __X86_IRQ_REMAPPING_H
 
+#include <asm/irqdomain.h>
+#include <asm/hw_irq.h>
 #include <asm/io_apic.h>
 
-struct IO_APIC_route_entry;
-struct io_apic_irq_attr;
-struct irq_chip;
 struct msi_msg;
-struct pci_dev;
-struct irq_cfg;
+struct irq_alloc_info;
 
 #ifdef CONFIG_IRQ_REMAP
 
@@ -39,22 +37,21 @@ extern int irq_remapping_enable(void);
 extern void irq_remapping_disable(void);
 extern int irq_remapping_reenable(int);
 extern int irq_remap_enable_fault_handling(void);
-extern int setup_ioapic_remapped_entry(int irq,
-                                      struct IO_APIC_route_entry *entry,
-                                      unsigned int destination,
-                                      int vector,
-                                      struct io_apic_irq_attr *attr);
-extern void free_remapped_irq(int irq);
-extern void compose_remapped_msi_msg(struct pci_dev *pdev,
-                                    unsigned int irq, unsigned int dest,
-                                    struct msi_msg *msg, u8 hpet_id);
-extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int id);
 extern void panic_if_irq_remap(const char *msg);
-extern bool setup_remapped_irq(int irq,
-                              struct irq_cfg *cfg,
-                              struct irq_chip *chip);
 
-void irq_remap_modify_chip_defaults(struct irq_chip *chip);
+extern struct irq_domain *
+irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info);
+extern struct irq_domain *
+irq_remapping_get_irq_domain(struct irq_alloc_info *info);
+
+/* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
+extern struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent);
+
+/* Get parent irqdomain for interrupt remapping irqdomain */
+static inline struct irq_domain *arch_get_ir_parent_domain(void)
+{
+       return x86_vector_domain;
+}
 
 #else  /* CONFIG_IRQ_REMAP */
 
@@ -64,42 +61,22 @@ static inline int irq_remapping_enable(void) { return -ENODEV; }
 static inline void irq_remapping_disable(void) { }
 static inline int irq_remapping_reenable(int eim) { return -ENODEV; }
 static inline int irq_remap_enable_fault_handling(void) { return -ENODEV; }
-static inline int setup_ioapic_remapped_entry(int irq,
-                                             struct IO_APIC_route_entry *entry,
-                                             unsigned int destination,
-                                             int vector,
-                                             struct io_apic_irq_attr *attr)
-{
-       return -ENODEV;
-}
-static inline void free_remapped_irq(int irq) { }
-static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
-                                           unsigned int irq, unsigned int dest,
-                                           struct msi_msg *msg, u8 hpet_id)
-{
-}
-static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
-{
-       return -ENODEV;
-}
 
 static inline void panic_if_irq_remap(const char *msg)
 {
 }
 
-static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+static inline struct irq_domain *
+irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info)
 {
+       return NULL;
 }
 
-static inline bool setup_remapped_irq(int irq,
-                                     struct irq_cfg *cfg,
-                                     struct irq_chip *chip)
+static inline struct irq_domain *
+irq_remapping_get_irq_domain(struct irq_alloc_info *info)
 {
-       return false;
+       return NULL;
 }
-#endif /* CONFIG_IRQ_REMAP */
-
-#define dmar_alloc_hwirq()     irq_alloc_hwirq(-1)
-#define dmar_free_hwirq                irq_free_hwirq
 
+#endif /* CONFIG_IRQ_REMAP */
 #endif /* __X86_IRQ_REMAPPING_H */
index 117db96ad5fbdf3204deb2ad2edb12009501b67e..bf55235d7772522045323e33350f42ed2861ec7a 100644 (file)
@@ -136,18 +136,22 @@ static inline int invalid_vm86_irq(int irq)
  * 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 */
diff --git a/arch/x86/include/asm/irqdomain.h b/arch/x86/include/asm/irqdomain.h
new file mode 100644 (file)
index 0000000..d26075b
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _ASM_IRQDOMAIN_H
+#define _ASM_IRQDOMAIN_H
+
+#include <linux/irqdomain.h>
+#include <asm/hw_irq.h>
+
+#ifdef CONFIG_X86_LOCAL_APIC
+enum {
+       /* Allocate contiguous CPU vectors */
+       X86_IRQ_ALLOC_CONTIGUOUS_VECTORS                = 0x1,
+};
+
+extern struct irq_domain *x86_vector_domain;
+
+extern void init_irq_alloc_info(struct irq_alloc_info *info,
+                               const struct cpumask *mask);
+extern void copy_irq_alloc_info(struct irq_alloc_info *dst,
+                               struct irq_alloc_info *src);
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_X86_IO_APIC
+struct device_node;
+struct irq_data;
+
+enum ioapic_domain_type {
+       IOAPIC_DOMAIN_INVALID,
+       IOAPIC_DOMAIN_LEGACY,
+       IOAPIC_DOMAIN_STRICT,
+       IOAPIC_DOMAIN_DYNAMIC,
+};
+
+struct ioapic_domain_cfg {
+       enum ioapic_domain_type         type;
+       const struct irq_domain_ops     *ops;
+       struct device_node              *dev;
+};
+
+extern const struct irq_domain_ops mp_ioapic_irqdomain_ops;
+
+extern int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nr_irqs, void *arg);
+extern void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nr_irqs);
+extern void mp_irqdomain_activate(struct irq_domain *domain,
+                                 struct irq_data *irq_data);
+extern void mp_irqdomain_deactivate(struct irq_domain *domain,
+                                   struct irq_data *irq_data);
+extern int mp_irqdomain_ioapic_idx(struct irq_domain *domain);
+#endif /* CONFIG_X86_IO_APIC */
+
+#ifdef CONFIG_PCI_MSI
+extern void arch_init_msi_domain(struct irq_domain *domain);
+#else
+static inline void arch_init_msi_domain(struct irq_domain *domain) { }
+#endif
+
+#ifdef CONFIG_HT_IRQ
+extern void arch_init_htirq_domain(struct irq_domain *domain);
+#else
+static inline void arch_init_htirq_domain(struct irq_domain *domain) { }
+#endif
+
+#endif
diff --git a/arch/x86/include/asm/msi.h b/arch/x86/include/asm/msi.h
new file mode 100644 (file)
index 0000000..93724cc
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _ASM_X86_MSI_H
+#define _ASM_X86_MSI_H
+#include <asm/hw_irq.h>
+
+typedef struct irq_alloc_info msi_alloc_info_t;
+
+#endif /* _ASM_X86_MSI_H */
index 4e370a5d81170e4fb4c6fa5d1abaf451c87cf502..d8c80ff32e8cfce6233401637f22fb30988bd76f 100644 (file)
@@ -96,15 +96,10 @@ extern void pci_iommu_alloc(void);
 #ifdef CONFIG_PCI_MSI
 /* implemented in arch/x86/kernel/apic/io_apic. */
 struct msi_desc;
-void native_compose_msi_msg(struct pci_dev *pdev, unsigned int irq,
-                           unsigned int dest, struct msi_msg *msg, u8 hpet_id);
 int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
 void native_teardown_msi_irq(unsigned int irq);
 void native_restore_msi_irqs(struct pci_dev *dev);
-int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
-                 unsigned int irq_base, unsigned int irq_offset);
 #else
-#define native_compose_msi_msg         NULL
 #define native_setup_msi_irqs          NULL
 #define native_teardown_msi_irq                NULL
 #endif
index f58a9c7a3c86658d6094be935fff23b50f785cc5..48d34d28f5a60543bc72471e2a1931fcf13dc04e 100644 (file)
@@ -171,38 +171,17 @@ struct x86_platform_ops {
 };
 
 struct pci_dev;
-struct msi_msg;
 
 struct x86_msi_ops {
        int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
-       void (*compose_msi_msg)(struct pci_dev *dev, unsigned int irq,
-                               unsigned int dest, struct msi_msg *msg,
-                              u8 hpet_id);
        void (*teardown_msi_irq)(unsigned int irq);
        void (*teardown_msi_irqs)(struct pci_dev *dev);
        void (*restore_msi_irqs)(struct pci_dev *dev);
-       int  (*setup_hpet_msi)(unsigned int irq, unsigned int id);
 };
 
-struct IO_APIC_route_entry;
-struct io_apic_irq_attr;
-struct irq_data;
-struct cpumask;
-
 struct x86_io_apic_ops {
-       void            (*init)   (void);
        unsigned int    (*read)   (unsigned int apic, unsigned int reg);
-       void            (*write)  (unsigned int apic, unsigned int reg, unsigned int value);
-       void            (*modify) (unsigned int apic, unsigned int reg, unsigned int value);
        void            (*disable)(void);
-       void            (*print_entries)(unsigned int apic, unsigned int nr_entries);
-       int             (*set_affinity)(struct irq_data *data,
-                                       const struct cpumask *mask,
-                                       bool force);
-       int             (*setup_entry)(int irq, struct IO_APIC_route_entry *entry,
-                                      unsigned int destination, int vector,
-                                      struct io_apic_irq_attr *attr);
-       void            (*eoi_ioapic_pin)(int apic, int pin, int vector);
 };
 
 extern struct x86_init_ops x86_init;
index dbe76a14c3c9909e50ad51ff14e2eefd31cdf101..271293ad89d74678dc1bc504bfe6ed5313de1c91 100644 (file)
 #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,57 +400,13 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
        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;
@@ -663,10 +619,21 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
                                    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
 
@@ -676,8 +643,12 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
 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
 }
@@ -786,7 +757,7 @@ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
        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 6a7c23ff21d3de8ccc906b41bceec57caaea414e..ede92c3364d3277fc3ea378695030eea47ca9fc8 100644 (file)
@@ -171,10 +171,6 @@ static int __init apbt_clockevent_register(void)
 
 static void apbt_setup_irq(struct apbt_dev *adev)
 {
-       /* timer0 irq has been setup early */
-       if (adev->irq == 0)
-               return;
-
        irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
        irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
 }
index 816f36e979ad03c6b052b1ec5c1ca34b6dc566e4..ae50d3454d7874e98f1e71e3402fb786dacb67c7 100644 (file)
@@ -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>
+ *     Add support of hierarchical irqdomain
  *
  * 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/device.h>
 #include <linux/pci.h>
 #include <linux/htirq.h>
+#include <asm/irqdomain.h>
 #include <asm/hw_irq.h>
 #include <asm/apic.h>
 #include <asm/hypertransport.h>
 
+static struct irq_domain *htirq_domain;
+
 /*
  * Hypertransport interrupt support
  */
-static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
-{
-       struct ht_irq_msg msg;
-
-       fetch_ht_irq_msg(irq, &msg);
-
-       msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
-       msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
-
-       msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
-       msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
-
-       write_ht_irq_msg(irq, &msg);
-}
-
 static int
 ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 {
-       struct irq_cfg *cfg = irqd_cfg(data);
-       unsigned int dest;
+       struct irq_data *parent = data->parent_data;
        int ret;
 
-       ret = apic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
-
-       target_ht_irq(data->irq, dest, cfg->vector);
-       return IRQ_SET_MASK_OK_NOCOPY;
+       ret = parent->chip->irq_set_affinity(parent, mask, force);
+       if (ret >= 0) {
+               struct ht_irq_msg msg;
+               struct irq_cfg *cfg = irqd_cfg(data);
+
+               fetch_ht_irq_msg(data->irq, &msg);
+               msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK |
+                                   HT_IRQ_LOW_DEST_ID_MASK);
+               msg.address_lo |= HT_IRQ_LOW_VECTOR(cfg->vector) |
+                                 HT_IRQ_LOW_DEST_ID(cfg->dest_apicid);
+               msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+               msg.address_hi |= HT_IRQ_HIGH_DEST_ID(cfg->dest_apicid);
+               write_ht_irq_msg(data->irq, &msg);
+       }
+
+       return ret;
 }
 
 static struct irq_chip ht_irq_chip = {
        .name                   = "PCI-HT",
        .irq_mask               = mask_ht_irq,
        .irq_unmask             = unmask_ht_irq,
-       .irq_ack                = apic_ack_edge,
+       .irq_ack                = irq_chip_ack_parent,
        .irq_set_affinity       = ht_set_affinity,
-       .irq_retrigger          = apic_retrigger_irq,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
 };
 
-int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+static int htirq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nr_irqs, void *arg)
 {
-       struct irq_cfg *cfg;
-       struct ht_irq_msg msg;
-       unsigned dest;
-       int err;
+       struct ht_irq_cfg *ht_cfg;
+       struct irq_alloc_info *info = arg;
+       struct pci_dev *dev;
+       irq_hw_number_t hwirq;
+       int ret;
 
-       if (disable_apic)
-               return -ENXIO;
+       if (nr_irqs > 1 || !info)
+               return -EINVAL;
 
-       cfg = irq_cfg(irq);
-       err = assign_irq_vector(irq, cfg, apic->target_cpus());
-       if (err)
-               return err;
+       dev = info->ht_dev;
+       hwirq = (info->ht_idx & 0xFF) |
+               PCI_DEVID(dev->bus->number, dev->devfn) << 8 |
+               (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 24;
+       if (irq_find_mapping(domain, hwirq) > 0)
+               return -EEXIST;
 
-       err = apic->cpu_mask_to_apicid_and(cfg->domain,
-                                          apic->target_cpus(), &dest);
-       if (err)
-               return err;
+       ht_cfg = kmalloc(sizeof(*ht_cfg), GFP_KERNEL);
+       if (!ht_cfg)
+               return -ENOMEM;
 
-       msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
+       ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
+       if (ret < 0) {
+               kfree(ht_cfg);
+               return ret;
+       }
+
+       /* Initialize msg to a value that will never match the first write. */
+       ht_cfg->msg.address_lo = 0xffffffff;
+       ht_cfg->msg.address_hi = 0xffffffff;
+       ht_cfg->dev = info->ht_dev;
+       ht_cfg->update = info->ht_update;
+       ht_cfg->pos = info->ht_pos;
+       ht_cfg->idx = 0x10 + (info->ht_idx * 2);
+       irq_domain_set_info(domain, virq, hwirq, &ht_irq_chip, ht_cfg,
+                           handle_edge_irq, ht_cfg, "edge");
+
+       return 0;
+}
+
+static void htirq_domain_free(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nr_irqs)
+{
+       struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+
+       BUG_ON(nr_irqs != 1);
+       kfree(irq_data->chip_data);
+       irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
 
+static void htirq_domain_activate(struct irq_domain *domain,
+                                 struct irq_data *irq_data)
+{
+       struct ht_irq_msg msg;
+       struct irq_cfg *cfg = irqd_cfg(irq_data);
+
+       msg.address_hi = HT_IRQ_HIGH_DEST_ID(cfg->dest_apicid);
        msg.address_lo =
                HT_IRQ_LOW_BASE |
-               HT_IRQ_LOW_DEST_ID(dest) |
+               HT_IRQ_LOW_DEST_ID(cfg->dest_apicid) |
                HT_IRQ_LOW_VECTOR(cfg->vector) |
                ((apic->irq_dest_mode == 0) ?
                        HT_IRQ_LOW_DM_PHYSICAL :
@@ -95,13 +131,56 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
                        HT_IRQ_LOW_MT_FIXED :
                        HT_IRQ_LOW_MT_ARBITRATED) |
                HT_IRQ_LOW_IRQ_MASKED;
+       write_ht_irq_msg(irq_data->irq, &msg);
+}
 
-       write_ht_irq_msg(irq, &msg);
+static void htirq_domain_deactivate(struct irq_domain *domain,
+                                   struct irq_data *irq_data)
+{
+       struct ht_irq_msg msg;
 
-       irq_set_chip_and_handler_name(irq, &ht_irq_chip,
-                                     handle_edge_irq, "edge");
+       memset(&msg, 0, sizeof(msg));
+       write_ht_irq_msg(irq_data->irq, &msg);
+}
 
-       dev_dbg(&dev->dev, "irq %d for HT\n", irq);
+static const struct irq_domain_ops htirq_domain_ops = {
+       .alloc          = htirq_domain_alloc,
+       .free           = htirq_domain_free,
+       .activate       = htirq_domain_activate,
+       .deactivate     = htirq_domain_deactivate,
+};
 
-       return 0;
+void arch_init_htirq_domain(struct irq_domain *parent)
+{
+       if (disable_apic)
+               return;
+
+       htirq_domain = irq_domain_add_tree(NULL, &htirq_domain_ops, NULL);
+       if (!htirq_domain)
+               pr_warn("failed to initialize irqdomain for HTIRQ.\n");
+       else
+               htirq_domain->parent = parent;
+}
+
+int arch_setup_ht_irq(int idx, int pos, struct pci_dev *dev,
+                     ht_irq_update_t *update)
+{
+       struct irq_alloc_info info;
+
+       if (!htirq_domain)
+               return -ENOSYS;
+
+       init_irq_alloc_info(&info, NULL);
+       info.ht_idx = idx;
+       info.ht_pos = pos;
+       info.ht_dev = dev;
+       info.ht_update = update;
+
+       return irq_domain_alloc_irqs(htirq_domain, 1, dev_to_node(&dev->dev),
+                                    &info);
+}
+
+void arch_teardown_ht_irq(unsigned int irq)
+{
+       irq_domain_free_irqs(irq, 1);
 }
index e01e4117188a58bb852cc8ab3547f007c828e810..845dc0df2002472275a39e421502cdb0768c54a1 100644 (file)
  *                                     and Rolf G. Tews
  *                                     for testing these extensively
  *     Paul Diefenbaugh        :       Added full ACPI support
+ *
+ * Historical information which is worth to be preserved:
+ *
+ * - SiS APIC rmw bug:
+ *
+ *     We used to have a workaround for a bug in SiS chips which
+ *     required to rewrite the index register for a read-modify-write
+ *     operation as the chip lost the index information which was
+ *     setup for the read already. We cache the data now, so that
+ *     workaround has been removed.
  */
 
 #include <linux/mm.h>
 #include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/syscore_ops.h>
-#include <linux/irqdomain.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
 #include <linux/jiffies.h>     /* time_after() */
 #include <linux/slab.h>
 #include <linux/bootmem.h>
 
+#include <asm/irqdomain.h>
 #include <asm/idle.h>
 #include <asm/io.h>
 #include <asm/smp.h>
 #define        for_each_ioapic_pin(idx, pin)   \
        for_each_ioapic((idx))          \
                for_each_pin((idx), (pin))
-
 #define for_each_irq_pin(entry, head) \
        list_for_each_entry(entry, &head, list)
 
-/*
- *      Is the SiS APIC rmw bug present ?
- *      -1 = don't know, 0 = no, 1 = yes
- */
-int sis_apic_bug = -1;
-
 static DEFINE_RAW_SPINLOCK(ioapic_lock);
 static DEFINE_MUTEX(ioapic_mutex);
 static unsigned int ioapic_dynirq_base;
 static int ioapic_initialized;
 
-struct mp_pin_info {
+struct irq_pin_list {
+       struct list_head list;
+       int apic, pin;
+};
+
+struct mp_chip_data {
+       struct list_head irq_2_pin;
+       struct IO_APIC_route_entry entry;
        int trigger;
        int polarity;
-       int node;
-       int set;
        u32 count;
+       bool isa_irq;
+};
+
+struct mp_ioapic_gsi {
+       u32 gsi_base;
+       u32 gsi_end;
 };
 
 static struct ioapic {
@@ -101,7 +115,6 @@ static struct ioapic {
        struct mp_ioapic_gsi  gsi_config;
        struct ioapic_domain_cfg irqdomain_cfg;
        struct irq_domain *irqdomain;
-       struct mp_pin_info *pin_info;
        struct resource *iomem_res;
 } ioapics[MAX_IO_APICS];
 
@@ -117,7 +130,7 @@ unsigned int mpc_ioapic_addr(int ioapic_idx)
        return ioapics[ioapic_idx].mp_config.apicaddr;
 }
 
-struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic_idx)
+static inline struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic_idx)
 {
        return &ioapics[ioapic_idx].gsi_config;
 }
@@ -129,11 +142,16 @@ static inline int mp_ioapic_pin_count(int ioapic)
        return gsi_cfg->gsi_end - gsi_cfg->gsi_base + 1;
 }
 
-u32 mp_pin_to_gsi(int ioapic, int pin)
+static inline u32 mp_pin_to_gsi(int ioapic, int pin)
 {
        return mp_ioapic_gsi_routing(ioapic)->gsi_base + pin;
 }
 
+static inline bool mp_is_legacy_irq(int irq)
+{
+       return irq >= 0 && irq < nr_legacy_irqs();
+}
+
 /*
  * Initialize all legacy IRQs and all pins on the first IOAPIC
  * if we have legacy interrupt controller. Kernel boot option "pirq="
@@ -144,12 +162,7 @@ static inline int mp_init_irq_at_boot(int ioapic, int irq)
        if (!nr_legacy_irqs())
                return 0;
 
-       return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs());
-}
-
-static inline struct mp_pin_info *mp_pin_info(int ioapic_idx, int pin)
-{
-       return ioapics[ioapic_idx].pin_info + pin;
+       return ioapic == 0 || mp_is_legacy_irq(irq);
 }
 
 static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic)
@@ -216,16 +229,6 @@ void mp_save_irq(struct mpc_intsrc *m)
                panic("Max # of irq sources exceeded!!\n");
 }
 
-struct irq_pin_list {
-       struct list_head list;
-       int apic, pin;
-};
-
-static struct irq_pin_list *alloc_irq_pin_list(int node)
-{
-       return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node);
-}
-
 static void alloc_ioapic_saved_registers(int idx)
 {
        size_t size;
@@ -247,8 +250,7 @@ static void free_ioapic_saved_registers(int idx)
 
 int __init arch_early_ioapic_init(void)
 {
-       struct irq_cfg *cfg;
-       int i, node = cpu_to_node(0);
+       int i;
 
        if (!nr_legacy_irqs())
                io_apic_irqs = ~0UL;
@@ -256,16 +258,6 @@ int __init arch_early_ioapic_init(void)
        for_each_ioapic(i)
                alloc_ioapic_saved_registers(i);
 
-       /*
-        * For legacy IRQ's, start with assigning irq0 to irq15 to
-        * ISA_IRQ_VECTOR(irq) for all cpu's.
-        */
-       for (i = 0; i < nr_legacy_irqs(); i++) {
-               cfg = alloc_irq_and_cfg_at(i, node);
-               cfg->vector = ISA_IRQ_VECTOR(i);
-               cpumask_setall(cfg->domain);
-       }
-
        return 0;
 }
 
@@ -283,7 +275,7 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
                + (mpc_ioapic_addr(idx) & ~PAGE_MASK);
 }
 
-void io_apic_eoi(unsigned int apic, unsigned int vector)
+static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
 {
        struct io_apic __iomem *io_apic = io_apic_base(apic);
        writel(vector, &io_apic->eoi);
@@ -296,7 +288,8 @@ unsigned int native_io_apic_read(unsigned int apic, unsigned int reg)
        return readl(&io_apic->data);
 }
 
-void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+static void io_apic_write(unsigned int apic, unsigned int reg,
+                         unsigned int value)
 {
        struct io_apic __iomem *io_apic = io_apic_base(apic);
 
@@ -304,21 +297,6 @@ void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int valu
        writel(value, &io_apic->data);
 }
 
-/*
- * Re-write a value: to be used for read-modify-write
- * cycles where the read already set up the index register.
- *
- * Older SiS APIC requires we rewrite the index register
- */
-void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
-{
-       struct io_apic __iomem *io_apic = io_apic_base(apic);
-
-       if (sis_apic_bug)
-               writel(reg, &io_apic->index);
-       writel(value, &io_apic->data);
-}
-
 union entry_union {
        struct { u32 w1, w2; };
        struct IO_APIC_route_entry entry;
@@ -378,7 +356,7 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
 static void ioapic_mask_entry(int apic, int pin)
 {
        unsigned long flags;
-       union entry_union eu = { .entry.mask = 1 };
+       union entry_union eu = { .entry.mask = IOAPIC_MASKED };
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
        io_apic_write(apic, 0x10 + 2*pin, eu.w1);
@@ -391,16 +369,17 @@ static void ioapic_mask_entry(int apic, int pin)
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
+static int __add_pin_to_irq_node(struct mp_chip_data *data,
+                                int node, int apic, int pin)
 {
        struct irq_pin_list *entry;
 
        /* don't allow duplicates */
-       for_each_irq_pin(entry, cfg->irq_2_pin)
+       for_each_irq_pin(entry, data->irq_2_pin)
                if (entry->apic == apic && entry->pin == pin)
                        return 0;
 
-       entry = alloc_irq_pin_list(node);
+       entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node);
        if (!entry) {
                pr_err("can not alloc irq_pin_list (%d,%d,%d)\n",
                       node, apic, pin);
@@ -408,16 +387,16 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi
        }
        entry->apic = apic;
        entry->pin = pin;
+       list_add_tail(&entry->list, &data->irq_2_pin);
 
-       list_add_tail(&entry->list, &cfg->irq_2_pin);
        return 0;
 }
 
-static void __remove_pin_from_irq(struct irq_cfg *cfg, int apic, int pin)
+static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
 {
        struct irq_pin_list *tmp, *entry;
 
-       list_for_each_entry_safe(entry, tmp, &cfg->irq_2_pin, list)
+       list_for_each_entry_safe(entry, tmp, &data->irq_2_pin, list)
                if (entry->apic == apic && entry->pin == pin) {
                        list_del(&entry->list);
                        kfree(entry);
@@ -425,22 +404,23 @@ static void __remove_pin_from_irq(struct irq_cfg *cfg, int apic, int pin)
                }
 }
 
-static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
+static void add_pin_to_irq_node(struct mp_chip_data *data,
+                               int node, int apic, int pin)
 {
-       if (__add_pin_to_irq_node(cfg, node, apic, pin))
+       if (__add_pin_to_irq_node(data, node, apic, pin))
                panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
 }
 
 /*
  * Reroute an IRQ to a different pin.
  */
-static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
+static void __init replace_pin_at_irq_node(struct mp_chip_data *data, int node,
                                           int oldapic, int oldpin,
                                           int newapic, int newpin)
 {
        struct irq_pin_list *entry;
 
-       for_each_irq_pin(entry, cfg->irq_2_pin) {
+       for_each_irq_pin(entry, data->irq_2_pin) {
                if (entry->apic == oldapic && entry->pin == oldpin) {
                        entry->apic = newapic;
                        entry->pin = newpin;
@@ -450,32 +430,26 @@ static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
        }
 
        /* old apic/pin didn't exist, so just add new ones */
-       add_pin_to_irq_node(cfg, node, newapic, newpin);
-}
-
-static void __io_apic_modify_irq(struct irq_pin_list *entry,
-                                int mask_and, int mask_or,
-                                void (*final)(struct irq_pin_list *entry))
-{
-       unsigned int reg, pin;
-
-       pin = entry->pin;
-       reg = io_apic_read(entry->apic, 0x10 + pin * 2);
-       reg &= mask_and;
-       reg |= mask_or;
-       io_apic_modify(entry->apic, 0x10 + pin * 2, reg);
-       if (final)
-               final(entry);
+       add_pin_to_irq_node(data, node, newapic, newpin);
 }
 
-static void io_apic_modify_irq(struct irq_cfg *cfg,
+static void io_apic_modify_irq(struct mp_chip_data *data,
                               int mask_and, int mask_or,
                               void (*final)(struct irq_pin_list *entry))
 {
+       union entry_union eu;
        struct irq_pin_list *entry;
 
-       for_each_irq_pin(entry, cfg->irq_2_pin)
-               __io_apic_modify_irq(entry, mask_and, mask_or, final);
+       eu.entry = data->entry;
+       eu.w1 &= mask_and;
+       eu.w1 |= mask_or;
+       data->entry = eu.entry;
+
+       for_each_irq_pin(entry, data->irq_2_pin) {
+               io_apic_write(entry->apic, 0x10 + 2 * entry->pin, eu.w1);
+               if (final)
+                       final(entry);
+       }
 }
 
 static void io_apic_sync(struct irq_pin_list *entry)
@@ -490,39 +464,31 @@ static void io_apic_sync(struct irq_pin_list *entry)
        readl(&io_apic->data);
 }
 
-static void mask_ioapic(struct irq_cfg *cfg)
+static void mask_ioapic_irq(struct irq_data *irq_data)
 {
+       struct mp_chip_data *data = irq_data->chip_data;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
+       io_apic_modify_irq(data, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void mask_ioapic_irq(struct irq_data *data)
+static void __unmask_ioapic(struct mp_chip_data *data)
 {
-       mask_ioapic(irqd_cfg(data));
+       io_apic_modify_irq(data, ~IO_APIC_REDIR_MASKED, 0, NULL);
 }
 
-static void __unmask_ioapic(struct irq_cfg *cfg)
-{
-       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
-}
-
-static void unmask_ioapic(struct irq_cfg *cfg)
+static void unmask_ioapic_irq(struct irq_data *irq_data)
 {
+       struct mp_chip_data *data = irq_data->chip_data;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       __unmask_ioapic(cfg);
+       __unmask_ioapic(data);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void unmask_ioapic_irq(struct irq_data *data)
-{
-       unmask_ioapic(irqd_cfg(data));
-}
-
 /*
  * IO-APIC versions below 0x20 don't support EOI register.
  * For the record, here is the information about various versions:
@@ -539,7 +505,7 @@ static void unmask_ioapic_irq(struct irq_data *data)
  * Otherwise, we simulate the EOI message manually by changing the trigger
  * mode to edge and then back to level, with RTE being masked during this.
  */
-void native_eoi_ioapic_pin(int apic, int pin, int vector)
+static void __eoi_ioapic_pin(int apic, int pin, int vector)
 {
        if (mpc_ioapic_ver(apic) >= 0x20) {
                io_apic_eoi(apic, vector);
@@ -551,7 +517,7 @@ void native_eoi_ioapic_pin(int apic, int pin, int vector)
                /*
                 * Mask the entry and change the trigger mode to edge.
                 */
-               entry1.mask = 1;
+               entry1.mask = IOAPIC_MASKED;
                entry1.trigger = IOAPIC_EDGE;
 
                __ioapic_write_entry(apic, pin, entry1);
@@ -563,15 +529,14 @@ void native_eoi_ioapic_pin(int apic, int pin, int vector)
        }
 }
 
-void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+void eoi_ioapic_pin(int vector, struct mp_chip_data *data)
 {
-       struct irq_pin_list *entry;
        unsigned long flags;
+       struct irq_pin_list *entry;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       for_each_irq_pin(entry, cfg->irq_2_pin)
-               x86_io_apic_ops.eoi_ioapic_pin(entry->apic, entry->pin,
-                                              cfg->vector);
+       for_each_irq_pin(entry, data->irq_2_pin)
+               __eoi_ioapic_pin(entry->apic, entry->pin, vector);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
@@ -588,8 +553,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
         * Make sure the entry is masked and re-read the contents to check
         * if it is a level triggered pin and if the remote-IRR is set.
         */
-       if (!entry.mask) {
-               entry.mask = 1;
+       if (entry.mask == IOAPIC_UNMASKED) {
+               entry.mask = IOAPIC_MASKED;
                ioapic_write_entry(apic, pin, entry);
                entry = ioapic_read_entry(apic, pin);
        }
@@ -602,13 +567,12 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
                 * doesn't clear the remote-IRR if the trigger mode is not
                 * set to level.
                 */
-               if (!entry.trigger) {
+               if (entry.trigger == IOAPIC_EDGE) {
                        entry.trigger = IOAPIC_LEVEL;
                        ioapic_write_entry(apic, pin, entry);
                }
-
                raw_spin_lock_irqsave(&ioapic_lock, flags);
-               x86_io_apic_ops.eoi_ioapic_pin(apic, pin, entry.vector);
+               __eoi_ioapic_pin(apic, pin, entry.vector);
                raw_spin_unlock_irqrestore(&ioapic_lock, flags);
        }
 
@@ -706,8 +670,8 @@ void mask_ioapic_entries(void)
                        struct IO_APIC_route_entry entry;
 
                        entry = ioapics[apic].saved_registers[pin];
-                       if (!entry.mask) {
-                               entry.mask = 1;
+                       if (entry.mask == IOAPIC_UNMASKED) {
+                               entry.mask = IOAPIC_MASKED;
                                ioapic_write_entry(apic, pin, entry);
                        }
                }
@@ -809,11 +773,11 @@ static int EISA_ELCR(unsigned int irq)
 
 #endif
 
-/* ISA interrupts are always polarity zero edge triggered,
+/* ISA interrupts are always active high edge triggered,
  * when listed as conforming in the MP table. */
 
-#define default_ISA_trigger(idx)       (0)
-#define default_ISA_polarity(idx)      (0)
+#define default_ISA_trigger(idx)       (IOAPIC_EDGE)
+#define default_ISA_polarity(idx)      (IOAPIC_POL_HIGH)
 
 /* EISA interrupts are always polarity zero and can be edge or level
  * trigger depending on the ELCR value.  If an interrupt is listed as
@@ -823,53 +787,55 @@ static int EISA_ELCR(unsigned int irq)
 #define default_EISA_trigger(idx)      (EISA_ELCR(mp_irqs[idx].srcbusirq))
 #define default_EISA_polarity(idx)     default_ISA_polarity(idx)
 
-/* PCI interrupts are always polarity one level triggered,
+/* PCI interrupts are always active low level triggered,
  * when listed as conforming in the MP table. */
 
-#define default_PCI_trigger(idx)       (1)
-#define default_PCI_polarity(idx)      (1)
+#define default_PCI_trigger(idx)       (IOAPIC_LEVEL)
+#define default_PCI_polarity(idx)      (IOAPIC_POL_LOW)
 
 static int irq_polarity(int idx)
 {
        int bus = mp_irqs[idx].srcbus;
-       int polarity;
 
        /*
         * Determine IRQ line polarity (high active or low active):
         */
-       switch (mp_irqs[idx].irqflag & 3)
-       {
-               case 0: /* conforms, ie. bus-type dependent polarity */
-                       if (test_bit(bus, mp_bus_not_pci))
-                               polarity = default_ISA_polarity(idx);
-                       else
-                               polarity = default_PCI_polarity(idx);
-                       break;
-               case 1: /* high active */
-               {
-                       polarity = 0;
-                       break;
-               }
-               case 2: /* reserved */
-               {
-                       pr_warn("broken BIOS!!\n");
-                       polarity = 1;
-                       break;
-               }
-               case 3: /* low active */
-               {
-                       polarity = 1;
-                       break;
-               }
-               default: /* invalid */
-               {
-                       pr_warn("broken BIOS!!\n");
-                       polarity = 1;
-                       break;
-               }
+       switch (mp_irqs[idx].irqflag & 0x03) {
+       case 0:
+               /* conforms to spec, ie. bus-type dependent polarity */
+               if (test_bit(bus, mp_bus_not_pci))
+                       return default_ISA_polarity(idx);
+               else
+                       return default_PCI_polarity(idx);
+       case 1:
+               return IOAPIC_POL_HIGH;
+       case 2:
+               pr_warn("IOAPIC: Invalid polarity: 2, defaulting to low\n");
+       case 3:
+       default: /* Pointless default required due to do gcc stupidity */
+               return IOAPIC_POL_LOW;
+       }
+}
+
+#ifdef CONFIG_EISA
+static int eisa_irq_trigger(int idx, int bus, int trigger)
+{
+       switch (mp_bus_id_to_type[bus]) {
+       case MP_BUS_PCI:
+       case MP_BUS_ISA:
+               return trigger;
+       case MP_BUS_EISA:
+               return default_EISA_trigger(idx);
        }
-       return polarity;
+       pr_warn("IOAPIC: Invalid srcbus: %d defaulting to level\n", bus);
+       return IOAPIC_LEVEL;
 }
+#else
+static inline int eisa_irq_trigger(int idx, int bus, int trigger)
+{
+       return trigger;
+}
+#endif
 
 static int irq_trigger(int idx)
 {
@@ -879,153 +845,227 @@ static int irq_trigger(int idx)
        /*
         * Determine IRQ trigger mode (edge or level sensitive):
         */
-       switch ((mp_irqs[idx].irqflag>>2) & 3)
-       {
-               case 0: /* conforms, ie. bus-type dependent */
-                       if (test_bit(bus, mp_bus_not_pci))
-                               trigger = default_ISA_trigger(idx);
-                       else
-                               trigger = default_PCI_trigger(idx);
-#ifdef CONFIG_EISA
-                       switch (mp_bus_id_to_type[bus]) {
-                               case MP_BUS_ISA: /* ISA pin */
-                               {
-                                       /* set before the switch */
-                                       break;
-                               }
-                               case MP_BUS_EISA: /* EISA pin */
-                               {
-                                       trigger = default_EISA_trigger(idx);
-                                       break;
-                               }
-                               case MP_BUS_PCI: /* PCI pin */
-                               {
-                                       /* set before the switch */
-                                       break;
-                               }
-                               default:
-                               {
-                                       pr_warn("broken BIOS!!\n");
-                                       trigger = 1;
-                                       break;
-                               }
-                       }
+       switch ((mp_irqs[idx].irqflag >> 2) & 0x03) {
+       case 0:
+               /* conforms to spec, ie. bus-type dependent trigger mode */
+               if (test_bit(bus, mp_bus_not_pci))
+                       trigger = default_ISA_trigger(idx);
+               else
+                       trigger = default_PCI_trigger(idx);
+               /* Take EISA into account */
+               return eisa_irq_trigger(idx, bus, trigger);
+       case 1:
+               return IOAPIC_EDGE;
+       case 2:
+               pr_warn("IOAPIC: Invalid trigger mode 2 defaulting to level\n");
+       case 3:
+       default: /* Pointless default required due to do gcc stupidity */
+               return IOAPIC_LEVEL;
+       }
+}
+
+void ioapic_set_alloc_attr(struct irq_alloc_info *info, int node,
+                          int trigger, int polarity)
+{
+       init_irq_alloc_info(info, NULL);
+       info->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
+       info->ioapic_node = node;
+       info->ioapic_trigger = trigger;
+       info->ioapic_polarity = polarity;
+       info->ioapic_valid = 1;
+}
+
+#ifndef CONFIG_ACPI
+int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
 #endif
-                       break;
-               case 1: /* edge */
-               {
-                       trigger = 0;
-                       break;
-               }
-               case 2: /* reserved */
-               {
-                       pr_warn("broken BIOS!!\n");
-                       trigger = 1;
-                       break;
-               }
-               case 3: /* level */
-               {
-                       trigger = 1;
-                       break;
-               }
-               default: /* invalid */
-               {
-                       pr_warn("broken BIOS!!\n");
-                       trigger = 0;
-                       break;
+
+static void ioapic_copy_alloc_attr(struct irq_alloc_info *dst,
+                                  struct irq_alloc_info *src,
+                                  u32 gsi, int ioapic_idx, int pin)
+{
+       int trigger, polarity;
+
+       copy_irq_alloc_info(dst, src);
+       dst->type = X86_IRQ_ALLOC_TYPE_IOAPIC;
+       dst->ioapic_id = mpc_ioapic_id(ioapic_idx);
+       dst->ioapic_pin = pin;
+       dst->ioapic_valid = 1;
+       if (src && src->ioapic_valid) {
+               dst->ioapic_node = src->ioapic_node;
+               dst->ioapic_trigger = src->ioapic_trigger;
+               dst->ioapic_polarity = src->ioapic_polarity;
+       } else {
+               dst->ioapic_node = NUMA_NO_NODE;
+               if (acpi_get_override_irq(gsi, &trigger, &polarity) >= 0) {
+                       dst->ioapic_trigger = trigger;
+                       dst->ioapic_polarity = polarity;
+               } else {
+                       /*
+                        * PCI interrupts are always active low level
+                        * triggered.
+                        */
+                       dst->ioapic_trigger = IOAPIC_LEVEL;
+                       dst->ioapic_polarity = IOAPIC_POL_LOW;
                }
        }
-       return trigger;
 }
 
-static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin)
+static int ioapic_alloc_attr_node(struct irq_alloc_info *info)
+{
+       return (info && info->ioapic_valid) ? info->ioapic_node : NUMA_NO_NODE;
+}
+
+static void mp_register_handler(unsigned int irq, unsigned long trigger)
+{
+       irq_flow_handler_t hdl;
+       bool fasteoi;
+
+       if (trigger) {
+               irq_set_status_flags(irq, IRQ_LEVEL);
+               fasteoi = true;
+       } else {
+               irq_clear_status_flags(irq, IRQ_LEVEL);
+               fasteoi = false;
+       }
+
+       hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
+       __irq_set_handler(irq, hdl, 0, fasteoi ? "fasteoi" : "edge");
+}
+
+static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
 {
+       struct mp_chip_data *data = irq_get_chip_data(irq);
+
+       /*
+        * setup_IO_APIC_irqs() programs all legacy IRQs with default trigger
+        * and polarity attirbutes. So allow the first user to reprogram the
+        * pin with real trigger and polarity attributes.
+        */
+       if (irq < nr_legacy_irqs() && data->count == 1) {
+               if (info->ioapic_trigger != data->trigger)
+                       mp_register_handler(irq, data->trigger);
+               data->entry.trigger = data->trigger = info->ioapic_trigger;
+               data->entry.polarity = data->polarity = info->ioapic_polarity;
+       }
+
+       return data->trigger == info->ioapic_trigger &&
+              data->polarity == info->ioapic_polarity;
+}
+
+static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
+                                struct irq_alloc_info *info)
+{
+       bool legacy = false;
        int irq = -1;
-       int ioapic = (int)(long)domain->host_data;
        int type = ioapics[ioapic].irqdomain_cfg.type;
 
        switch (type) {
        case IOAPIC_DOMAIN_LEGACY:
                /*
-                * Dynamically allocate IRQ number for non-ISA IRQs in the first 16
-                * GSIs on some weird platforms.
+                * Dynamically allocate IRQ number for non-ISA IRQs in the first
+                * 16 GSIs on some weird platforms.
                 */
-               if (gsi < nr_legacy_irqs())
-                       irq = irq_create_mapping(domain, pin);
-               else if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0)
+               if (!ioapic_initialized || gsi >= nr_legacy_irqs())
                        irq = gsi;
+               legacy = mp_is_legacy_irq(irq);
                break;
        case IOAPIC_DOMAIN_STRICT:
-               if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0)
-                       irq = gsi;
+               irq = gsi;
                break;
        case IOAPIC_DOMAIN_DYNAMIC:
-               irq = irq_create_mapping(domain, pin);
                break;
        default:
                WARN(1, "ioapic: unknown irqdomain type %d\n", type);
-               break;
+               return -1;
+       }
+
+       return __irq_domain_alloc_irqs(domain, irq, 1,
+                                      ioapic_alloc_attr_node(info),
+                                      info, legacy);
+}
+
+/*
+ * Need special handling for ISA IRQs because there may be multiple IOAPIC pins
+ * sharing the same ISA IRQ number and irqdomain only supports 1:1 mapping
+ * between IOAPIC pin and IRQ number. A typical IOAPIC has 24 pins, pin 0-15 are
+ * used for legacy IRQs and pin 16-23 are used for PCI IRQs (PIRQ A-H).
+ * When ACPI is disabled, only legacy IRQ numbers (IRQ0-15) are available, and
+ * some BIOSes may use MP Interrupt Source records to override IRQ numbers for
+ * PIRQs instead of reprogramming the interrupt routing logic. Thus there may be
+ * multiple pins sharing the same legacy IRQ number when ACPI is disabled.
+ */
+static int alloc_isa_irq_from_domain(struct irq_domain *domain,
+                                    int irq, int ioapic, int pin,
+                                    struct irq_alloc_info *info)
+{
+       struct mp_chip_data *data;
+       struct irq_data *irq_data = irq_get_irq_data(irq);
+       int node = ioapic_alloc_attr_node(info);
+
+       /*
+        * Legacy ISA IRQ has already been allocated, just add pin to
+        * the pin list assoicated with this IRQ and program the IOAPIC
+        * entry. The IOAPIC entry
+        */
+       if (irq_data && irq_data->parent_data) {
+               if (!mp_check_pin_attr(irq, info))
+                       return -EBUSY;
+               if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic,
+                                         info->ioapic_pin))
+                       return -ENOMEM;
+       } else {
+               irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true);
+               if (irq >= 0) {
+                       irq_data = irq_domain_get_irq_data(domain, irq);
+                       data = irq_data->chip_data;
+                       data->isa_irq = true;
+               }
        }
 
-       return irq > 0 ? irq : -1;
+       return irq;
 }
 
 static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
-                            unsigned int flags)
+                            unsigned int flags, struct irq_alloc_info *info)
 {
        int irq;
+       bool legacy = false;
+       struct irq_alloc_info tmp;
+       struct mp_chip_data *data;
        struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
-       struct mp_pin_info *info = mp_pin_info(ioapic, pin);
 
        if (!domain)
-               return -1;
+               return -ENOSYS;
 
-       mutex_lock(&ioapic_mutex);
-
-       /*
-        * Don't use irqdomain to manage ISA IRQs because there may be
-        * multiple IOAPIC pins sharing the same ISA IRQ number and
-        * irqdomain only supports 1:1 mapping between IOAPIC pin and
-        * IRQ number. A typical IOAPIC has 24 pins, pin 0-15 are used
-        * for legacy IRQs and pin 16-23 are used for PCI IRQs (PIRQ A-H).
-        * When ACPI is disabled, only legacy IRQ numbers (IRQ0-15) are
-        * available, and some BIOSes may use MP Interrupt Source records
-        * to override IRQ numbers for PIRQs instead of reprogramming
-        * the interrupt routing logic. Thus there may be multiple pins
-        * sharing the same legacy IRQ number when ACPI is disabled.
-        */
        if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) {
                irq = mp_irqs[idx].srcbusirq;
-               if (flags & IOAPIC_MAP_ALLOC) {
-                       if (info->count == 0 &&
-                           mp_irqdomain_map(domain, irq, pin) != 0)
-                               irq = -1;
+               legacy = mp_is_legacy_irq(irq);
+       }
 
-                       /* special handling for timer IRQ0 */
+       mutex_lock(&ioapic_mutex);
+       if (!(flags & IOAPIC_MAP_ALLOC)) {
+               if (!legacy) {
+                       irq = irq_find_mapping(domain, pin);
                        if (irq == 0)
-                               info->count++;
+                               irq = -ENOENT;
                }
        } else {
-               irq = irq_find_mapping(domain, pin);
-               if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC))
-                       irq = alloc_irq_from_domain(domain, gsi, pin);
-       }
-
-       if (flags & IOAPIC_MAP_ALLOC) {
-               /* special handling for legacy IRQs */
-               if (irq < nr_legacy_irqs() && info->count == 1 &&
-                   mp_irqdomain_map(domain, irq, pin) != 0)
-                       irq = -1;
-
-               if (irq > 0)
-                       info->count++;
-               else if (info->count == 0)
-                       info->set = 0;
+               ioapic_copy_alloc_attr(&tmp, info, gsi, ioapic, pin);
+               if (legacy)
+                       irq = alloc_isa_irq_from_domain(domain, irq,
+                                                       ioapic, pin, &tmp);
+               else if ((irq = irq_find_mapping(domain, pin)) == 0)
+                       irq = alloc_irq_from_domain(domain, ioapic, gsi, &tmp);
+               else if (!mp_check_pin_attr(irq, &tmp))
+                       irq = -EBUSY;
+               if (irq >= 0) {
+                       data = irq_get_chip_data(irq);
+                       data->count++;
+               }
        }
-
        mutex_unlock(&ioapic_mutex);
 
-       return irq > 0 ? irq : -1;
+       return irq;
 }
 
 static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags)
@@ -1058,10 +1098,10 @@ static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags)
        }
 #endif
 
-       return  mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags);
+       return  mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags, NULL);
 }
 
-int mp_map_gsi_to_irq(u32 gsi, unsigned int flags)
+int mp_map_gsi_to_irq(u32 gsi, unsigned int flags, struct irq_alloc_info *info)
 {
        int ioapic, pin, idx;
 
@@ -1074,31 +1114,24 @@ int mp_map_gsi_to_irq(u32 gsi, unsigned int flags)
        if ((flags & IOAPIC_MAP_CHECK) && idx < 0)
                return -1;
 
-       return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags);
+       return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags, info);
 }
 
 void mp_unmap_irq(int irq)
 {
-       struct irq_data *data = irq_get_irq_data(irq);
-       struct mp_pin_info *info;
-       int ioapic, pin;
+       struct irq_data *irq_data = irq_get_irq_data(irq);
+       struct mp_chip_data *data;
 
-       if (!data || !data->domain)
+       if (!irq_data || !irq_data->domain)
                return;
 
-       ioapic = (int)(long)data->domain->host_data;
-       pin = (int)data->hwirq;
-       info = mp_pin_info(ioapic, pin);
+       data = irq_data->chip_data;
+       if (!data || data->isa_irq)
+               return;
 
        mutex_lock(&ioapic_mutex);
-       if (--info->count == 0) {
-               info->set = 0;
-               if (irq < nr_legacy_irqs() &&
-                   ioapics[ioapic].irqdomain_cfg.type == IOAPIC_DOMAIN_LEGACY)
-                       mp_irqdomain_unmap(data->domain, irq);
-               else
-                       irq_dispose_mapping(irq);
-       }
+       if (--data->count == 0)
+               irq_domain_free_irqs(irq, 1);
        mutex_unlock(&ioapic_mutex);
 }
 
@@ -1165,7 +1198,7 @@ out:
 }
 EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
 
-static struct irq_chip ioapic_chip;
+static struct irq_chip ioapic_chip, ioapic_ir_chip;
 
 #ifdef CONFIG_X86_32
 static inline int IO_APIC_irq_trigger(int irq)
@@ -1189,96 +1222,6 @@ static inline int IO_APIC_irq_trigger(int irq)
 }
 #endif
 
-static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
-                                unsigned long trigger)
-{
-       struct irq_chip *chip = &ioapic_chip;
-       irq_flow_handler_t hdl;
-       bool fasteoi;
-
-       if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-           trigger == IOAPIC_LEVEL) {
-               irq_set_status_flags(irq, IRQ_LEVEL);
-               fasteoi = true;
-       } else {
-               irq_clear_status_flags(irq, IRQ_LEVEL);
-               fasteoi = false;
-       }
-
-       if (setup_remapped_irq(irq, cfg, chip))
-               fasteoi = trigger != 0;
-
-       hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
-       irq_set_chip_and_handler_name(irq, chip, hdl,
-                                     fasteoi ? "fasteoi" : "edge");
-}
-
-int native_setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
-                             unsigned int destination, int vector,
-                             struct io_apic_irq_attr *attr)
-{
-       memset(entry, 0, sizeof(*entry));
-
-       entry->delivery_mode = apic->irq_delivery_mode;
-       entry->dest_mode     = apic->irq_dest_mode;
-       entry->dest          = destination;
-       entry->vector        = vector;
-       entry->mask          = 0;                       /* enable IRQ */
-       entry->trigger       = attr->trigger;
-       entry->polarity      = attr->polarity;
-
-       /*
-        * Mask level triggered irqs.
-        * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
-        */
-       if (attr->trigger)
-               entry->mask = 1;
-
-       return 0;
-}
-
-static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
-                               struct io_apic_irq_attr *attr)
-{
-       struct IO_APIC_route_entry entry;
-       unsigned int dest;
-
-       if (!IO_APIC_IRQ(irq))
-               return;
-
-       if (assign_irq_vector(irq, cfg, apic->target_cpus()))
-               return;
-
-       if (apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus(),
-                                        &dest)) {
-               pr_warn("Failed to obtain apicid for ioapic %d, pin %d\n",
-                       mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
-               clear_irq_vector(irq, cfg);
-
-               return;
-       }
-
-       apic_printk(APIC_VERBOSE,KERN_DEBUG
-                   "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
-                   "IRQ %d Mode:%i Active:%i Dest:%d)\n",
-                   attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin,
-                   cfg->vector, irq, attr->trigger, attr->polarity, dest);
-
-       if (x86_io_apic_ops.setup_entry(irq, &entry, dest, cfg->vector, attr)) {
-               pr_warn("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
-                       mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
-               clear_irq_vector(irq, cfg);
-
-               return;
-       }
-
-       ioapic_register_intr(irq, cfg, attr->trigger);
-       if (irq < nr_legacy_irqs())
-               legacy_pic->mask(irq);
-
-       ioapic_write_entry(attr->ioapic, attr->ioapic_pin, entry);
-}
-
 static void __init setup_IO_APIC_irqs(void)
 {
        unsigned int ioapic, pin;
@@ -1298,106 +1241,41 @@ static void __init setup_IO_APIC_irqs(void)
        }
 }
 
-/*
- * Set up the timer pin, possibly with the 8259A-master behind.
- */
-static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
-                                       unsigned int pin, int vector)
-{
-       struct IO_APIC_route_entry entry;
-       unsigned int dest;
-
-       memset(&entry, 0, sizeof(entry));
-
-       /*
-        * We use logical delivery to get the timer IRQ
-        * to the first CPU.
-        */
-       if (unlikely(apic->cpu_mask_to_apicid_and(apic->target_cpus(),
-                                                 apic->target_cpus(), &dest)))
-               dest = BAD_APICID;
-
-       entry.dest_mode = apic->irq_dest_mode;
-       entry.mask = 0;                 /* don't mask IRQ for edge */
-       entry.dest = dest;
-       entry.delivery_mode = apic->irq_delivery_mode;
-       entry.polarity = 0;
-       entry.trigger = 0;
-       entry.vector = vector;
-
-       /*
-        * The timer IRQ doesn't have to know that behind the
-        * scene we may have a 8259A-master in AEOI mode ...
-        */
-       irq_set_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq,
-                                     "edge");
-
-       /*
-        * Add it to the IO-APIC irq-routing table:
-        */
-       ioapic_write_entry(ioapic_idx, pin, entry);
-}
-
-void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
+void ioapic_zap_locks(void)
 {
-       int i;
-
-       pr_debug(" NR Dst Mask Trig IRR Pol Stat Dmod Deli Vect:\n");
-
-       for (i = 0; i <= nr_entries; i++) {
-               struct IO_APIC_route_entry entry;
-
-               entry = ioapic_read_entry(apic, i);
-
-               pr_debug(" %02x %02X  ", i, entry.dest);
-               pr_cont("%1d    %1d    %1d   %1d   %1d    "
-                       "%1d    %1d    %02X\n",
-                       entry.mask,
-                       entry.trigger,
-                       entry.irr,
-                       entry.polarity,
-                       entry.delivery_status,
-                       entry.dest_mode,
-                       entry.delivery_mode,
-                       entry.vector);
-       }
+       raw_spin_lock_init(&ioapic_lock);
 }
 
-void intel_ir_io_apic_print_entries(unsigned int apic,
-                                   unsigned int nr_entries)
+static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
 {
        int i;
+       char buf[256];
+       struct IO_APIC_route_entry entry;
+       struct IR_IO_APIC_route_entry *ir_entry = (void *)&entry;
 
-       pr_debug(" NR Indx Fmt Mask Trig IRR Pol Stat Indx2 Zero Vect:\n");
-
+       printk(KERN_DEBUG "IOAPIC %d:\n", apic);
        for (i = 0; i <= nr_entries; i++) {
-               struct IR_IO_APIC_route_entry *ir_entry;
-               struct IO_APIC_route_entry entry;
-
                entry = ioapic_read_entry(apic, i);
-
-               ir_entry = (struct IR_IO_APIC_route_entry *)&entry;
-
-               pr_debug(" %02x %04X ", i, ir_entry->index);
-               pr_cont("%1d   %1d    %1d    %1d   %1d   "
-                       "%1d    %1d     %X    %02X\n",
-                       ir_entry->format,
-                       ir_entry->mask,
-                       ir_entry->trigger,
-                       ir_entry->irr,
-                       ir_entry->polarity,
-                       ir_entry->delivery_status,
-                       ir_entry->index2,
-                       ir_entry->zero,
-                       ir_entry->vector);
+               snprintf(buf, sizeof(buf),
+                        " pin%02x, %s, %s, %s, V(%02X), IRR(%1d), S(%1d)",
+                        i,
+                        entry.mask == IOAPIC_MASKED ? "disabled" : "enabled ",
+                        entry.trigger == IOAPIC_LEVEL ? "level" : "edge ",
+                        entry.polarity == IOAPIC_POL_LOW ? "low " : "high",
+                        entry.vector, entry.irr, entry.delivery_status);
+               if (ir_entry->format)
+                       printk(KERN_DEBUG "%s, remapped, I(%04X),  Z(%X)\n",
+                              buf, (ir_entry->index << 15) | ir_entry->index,
+                              ir_entry->zero);
+               else
+                       printk(KERN_DEBUG "%s, %s, D(%02X), M(%1d)\n",
+                              buf,
+                              entry.dest_mode == IOAPIC_DEST_MODE_LOGICAL ?
+                              "logical " : "physical",
+                              entry.dest, entry.delivery_mode);
        }
 }
 
-void ioapic_zap_locks(void)
-{
-       raw_spin_lock_init(&ioapic_lock);
-}
-
 static void __init print_IO_APIC(int ioapic_idx)
 {
        union IO_APIC_reg_00 reg_00;
@@ -1451,16 +1329,13 @@ static void __init print_IO_APIC(int ioapic_idx)
        }
 
        printk(KERN_DEBUG ".... IRQ redirection table:\n");
-
-       x86_io_apic_ops.print_entries(ioapic_idx, reg_01.bits.entries);
+       io_apic_print_entries(ioapic_idx, reg_01.bits.entries);
 }
 
 void __init print_IO_APICs(void)
 {
        int ioapic_idx;
-       struct irq_cfg *cfg;
        unsigned int irq;
-       struct irq_chip *chip;
 
        printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
        for_each_ioapic(ioapic_idx)
@@ -1480,18 +1355,20 @@ void __init print_IO_APICs(void)
        printk(KERN_DEBUG "IRQ to pin mappings:\n");
        for_each_active_irq(irq) {
                struct irq_pin_list *entry;
+               struct irq_chip *chip;
+               struct mp_chip_data *data;
 
                chip = irq_get_chip(irq);
-               if (chip != &ioapic_chip)
+               if (chip != &ioapic_chip && chip != &ioapic_ir_chip)
                        continue;
-
-               cfg = irq_cfg(irq);
-               if (!cfg)
+               data = irq_get_chip_data(irq);
+               if (!data)
                        continue;
-               if (list_empty(&cfg->irq_2_pin))
+               if (list_empty(&data->irq_2_pin))
                        continue;
+
                printk(KERN_DEBUG "IRQ%d ", irq);
-               for_each_irq_pin(entry, cfg->irq_2_pin)
+               for_each_irq_pin(entry, data->irq_2_pin)
                        pr_cont("-> %d:%d", entry->apic, entry->pin);
                pr_cont("\n");
        }
@@ -1564,15 +1441,12 @@ void native_disable_io_apic(void)
                struct IO_APIC_route_entry entry;
 
                memset(&entry, 0, sizeof(entry));
-               entry.mask            = 0; /* Enabled */
-               entry.trigger         = 0; /* Edge */
-               entry.irr             = 0;
-               entry.polarity        = 0; /* High */
-               entry.delivery_status = 0;
-               entry.dest_mode       = 0; /* Physical */
-               entry.delivery_mode   = dest_ExtINT; /* ExtInt */
-               entry.vector          = 0;
-               entry.dest            = read_apic_id();
+               entry.mask              = IOAPIC_UNMASKED;
+               entry.trigger           = IOAPIC_EDGE;
+               entry.polarity          = IOAPIC_POL_HIGH;
+               entry.dest_mode         = IOAPIC_DEST_MODE_PHYSICAL;
+               entry.delivery_mode     = dest_ExtINT;
+               entry.dest              = read_apic_id();
 
                /*
                 * Add it to the IO-APIC irq-routing table:
@@ -1582,7 +1456,6 @@ void native_disable_io_apic(void)
 
        if (cpu_has_apic || apic_from_smp_config())
                disconnect_bsp_APIC(ioapic_i8259.pin != -1);
-
 }
 
 /*
@@ -1792,7 +1665,6 @@ static int __init timer_irq_works(void)
  * This is not complete - we should be able to fake
  * an edge even if it isn't on the 8259A...
  */
-
 static unsigned int startup_ioapic_irq(struct irq_data *data)
 {
        int was_pending = 0, irq = data->irq;
@@ -1804,74 +1676,22 @@ static unsigned int startup_ioapic_irq(struct irq_data *data)
                if (legacy_pic->irq_pending(irq))
                        was_pending = 1;
        }
-       __unmask_ioapic(irqd_cfg(data));
+       __unmask_ioapic(data->chip_data);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return was_pending;
 }
 
-/*
- * Level and edge triggered IO-APIC interrupts need different handling,
- * so we use two separate IRQ descriptors. Edge triggered IRQs can be
- * handled with the level-triggered descriptor, but that one has slightly
- * more overhead. Level-triggered interrupts cannot be handled with the
- * edge-triggered handler, without risking IRQ storms and other ugly
- * races.
- */
-
-static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
-{
-       int apic, pin;
-       struct irq_pin_list *entry;
-       u8 vector = cfg->vector;
-
-       for_each_irq_pin(entry, cfg->irq_2_pin) {
-               unsigned int reg;
-
-               apic = entry->apic;
-               pin = entry->pin;
-
-               io_apic_write(apic, 0x11 + pin*2, dest);
-               reg = io_apic_read(apic, 0x10 + pin*2);
-               reg &= ~IO_APIC_REDIR_VECTOR_MASK;
-               reg |= vector;
-               io_apic_modify(apic, 0x10 + pin*2, reg);
-       }
-}
-
-int native_ioapic_set_affinity(struct irq_data *data,
-                              const struct cpumask *mask,
-                              bool force)
-{
-       unsigned int dest, irq = data->irq;
-       unsigned long flags;
-       int ret;
-
-       if (!config_enabled(CONFIG_SMP))
-               return -EPERM;
-
-       raw_spin_lock_irqsave(&ioapic_lock, flags);
-       ret = apic_set_affinity(data, mask, &dest);
-       if (!ret) {
-               /* Only the high 8 bits are valid. */
-               dest = SET_APIC_LOGICAL_ID(dest);
-               __target_IO_APIC_irq(irq, dest, irqd_cfg(data));
-               ret = IRQ_SET_MASK_OK_NOCOPY;
-       }
-       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-       return ret;
-}
-
 atomic_t irq_mis_count;
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
-static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
+static bool io_apic_level_ack_pending(struct mp_chip_data *data)
 {
        struct irq_pin_list *entry;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       for_each_irq_pin(entry, cfg->irq_2_pin) {
+       for_each_irq_pin(entry, data->irq_2_pin) {
                unsigned int reg;
                int pin;
 
@@ -1888,18 +1708,17 @@ static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
        return false;
 }
 
-static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
+static inline bool ioapic_irqd_mask(struct irq_data *data)
 {
        /* If we are moving the irq we need to mask it */
        if (unlikely(irqd_is_setaffinity_pending(data))) {
-               mask_ioapic(cfg);
+               mask_ioapic_irq(data);
                return true;
        }
        return false;
 }
 
-static inline void ioapic_irqd_unmask(struct irq_data *data,
-                                     struct irq_cfg *cfg, bool masked)
+static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
 {
        if (unlikely(masked)) {
                /* Only migrate the irq if the ack has been received.
@@ -1928,31 +1747,30 @@ static inline void ioapic_irqd_unmask(struct irq_data *data,
                 * accurate and is causing problems then it is a hardware bug
                 * and you can go talk to the chipset vendor about it.
                 */
-               if (!io_apic_level_ack_pending(cfg))
+               if (!io_apic_level_ack_pending(data->chip_data))
                        irq_move_masked_irq(data);
-               unmask_ioapic(cfg);
+               unmask_ioapic_irq(data);
        }
 }
 #else
-static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
+static inline bool ioapic_irqd_mask(struct irq_data *data)
 {
        return false;
 }
-static inline void ioapic_irqd_unmask(struct irq_data *data,
-                                     struct irq_cfg *cfg, bool masked)
+static inline void ioapic_irqd_unmask(struct irq_data *data, bool masked)
 {
 }
 #endif
 
-static void ack_ioapic_level(struct irq_data *data)
+static void ioapic_ack_level(struct irq_data *irq_data)
 {
-       struct irq_cfg *cfg = irqd_cfg(data);
-       int i, irq = data->irq;
+       struct irq_cfg *cfg = irqd_cfg(irq_data);
        unsigned long v;
        bool masked;
+       int i;
 
        irq_complete_move(cfg);
-       masked = ioapic_irqd_mask(data, cfg);
+       masked = ioapic_irqd_mask(irq_data);
 
        /*
         * It appears there is an erratum which affects at least version 0x11
@@ -2004,11 +1822,49 @@ static void ack_ioapic_level(struct irq_data *data)
         */
        if (!(v & (1 << (i & 0x1f)))) {
                atomic_inc(&irq_mis_count);
+               eoi_ioapic_pin(cfg->vector, irq_data->chip_data);
+       }
+
+       ioapic_irqd_unmask(irq_data, masked);
+}
+
+static void ioapic_ir_ack_level(struct irq_data *irq_data)
+{
+       struct mp_chip_data *data = irq_data->chip_data;
+
+       /*
+        * Intr-remapping uses pin number as the virtual vector
+        * in the RTE. Actual vector is programmed in
+        * intr-remapping table entry. Hence for the io-apic
+        * EOI we use the pin number.
+        */
+       ack_APIC_irq();
+       eoi_ioapic_pin(data->entry.vector, data);
+}
 
-               eoi_ioapic_irq(irq, cfg);
+static int ioapic_set_affinity(struct irq_data *irq_data,
+                              const struct cpumask *mask, bool force)
+{
+       struct irq_data *parent = irq_data->parent_data;
+       struct mp_chip_data *data = irq_data->chip_data;
+       struct irq_pin_list *entry;
+       struct irq_cfg *cfg;
+       unsigned long flags;
+       int ret;
+
+       ret = parent->chip->irq_set_affinity(parent, mask, force);
+       raw_spin_lock_irqsave(&ioapic_lock, flags);
+       if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
+               cfg = irqd_cfg(irq_data);
+               data->entry.dest = cfg->dest_apicid;
+               data->entry.vector = cfg->vector;
+               for_each_irq_pin(entry, data->irq_2_pin)
+                       __ioapic_write_entry(entry->apic, entry->pin,
+                                            data->entry);
        }
+       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
-       ioapic_irqd_unmask(data, cfg, masked);
+       return ret;
 }
 
 static struct irq_chip ioapic_chip __read_mostly = {
@@ -2016,10 +1872,20 @@ static struct irq_chip ioapic_chip __read_mostly = {
        .irq_startup            = startup_ioapic_irq,
        .irq_mask               = mask_ioapic_irq,
        .irq_unmask             = unmask_ioapic_irq,
-       .irq_ack                = apic_ack_edge,
-       .irq_eoi                = ack_ioapic_level,
-       .irq_set_affinity       = native_ioapic_set_affinity,
-       .irq_retrigger          = apic_retrigger_irq,
+       .irq_ack                = irq_chip_ack_parent,
+       .irq_eoi                = ioapic_ack_level,
+       .irq_set_affinity       = ioapic_set_affinity,
+       .flags                  = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static struct irq_chip ioapic_ir_chip __read_mostly = {
+       .name                   = "IR-IO-APIC",
+       .irq_startup            = startup_ioapic_irq,
+       .irq_mask               = mask_ioapic_irq,
+       .irq_unmask             = unmask_ioapic_irq,
+       .irq_ack                = irq_chip_ack_parent,
+       .irq_eoi                = ioapic_ir_ack_level,
+       .irq_set_affinity       = ioapic_set_affinity,
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
 };
 
@@ -2113,12 +1979,12 @@ static inline void __init unlock_ExtINT_logic(void)
 
        memset(&entry1, 0, sizeof(entry1));
 
-       entry1.dest_mode = 0;                   /* physical delivery */
-       entry1.mask = 0;                        /* unmask IRQ now */
+       entry1.dest_mode = IOAPIC_DEST_MODE_PHYSICAL;
+       entry1.mask = IOAPIC_UNMASKED;
        entry1.dest = hard_smp_processor_id();
        entry1.delivery_mode = dest_ExtINT;
        entry1.polarity = entry0.polarity;
-       entry1.trigger = 0;
+       entry1.trigger = IOAPIC_EDGE;
        entry1.vector = 0;
 
        ioapic_write_entry(apic, pin, entry1);
@@ -2152,6 +2018,25 @@ static int __init disable_timer_pin_setup(char *arg)
 }
 early_param("disable_timer_pin_1", disable_timer_pin_setup);
 
+static int mp_alloc_timer_irq(int ioapic, int pin)
+{
+       int irq = -1;
+       struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
+
+       if (domain) {
+               struct irq_alloc_info info;
+
+               ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 0, 0);
+               info.ioapic_id = mpc_ioapic_id(ioapic);
+               info.ioapic_pin = pin;
+               mutex_lock(&ioapic_mutex);
+               irq = alloc_isa_irq_from_domain(domain, 0, ioapic, pin, &info);
+               mutex_unlock(&ioapic_mutex);
+       }
+
+       return irq;
+}
+
 /*
  * This code may look a bit paranoid, but it's supposed to cooperate with
  * a wide range of boards and BIOS bugs.  Fortunately only the timer IRQ
@@ -2162,7 +2047,9 @@ early_param("disable_timer_pin_1", disable_timer_pin_setup);
  */
 static inline void __init check_timer(void)
 {
-       struct irq_cfg *cfg = irq_cfg(0);
+       struct irq_data *irq_data = irq_get_irq_data(0);
+       struct mp_chip_data *data = irq_data->chip_data;
+       struct irq_cfg *cfg = irqd_cfg(irq_data);
        int node = cpu_to_node(0);
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
@@ -2174,7 +2061,6 @@ static inline void __init check_timer(void)
         * get/set the timer IRQ vector:
         */
        legacy_pic->mask(0);
-       assign_irq_vector(0, cfg, apic->target_cpus());
 
        /*
         * As IRQ0 is to be enabled in the 8259A, the virtual
@@ -2215,23 +2101,21 @@ static inline void __init check_timer(void)
        }
 
        if (pin1 != -1) {
-               /*
-                * Ok, does IRQ0 through the IOAPIC work?
-                */
+               /* Ok, does IRQ0 through the IOAPIC work? */
                if (no_pin1) {
-                       add_pin_to_irq_node(cfg, node, apic1, pin1);
-                       setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
+                       mp_alloc_timer_irq(apic1, pin1);
                } else {
-                       /* for edge trigger, setup_ioapic_irq already
-                        * leave it unmasked.
+                       /*
+                        * for edge trigger, it's already unmasked,
                         * so only need to unmask if it is level-trigger
                         * do we really have level trigger timer?
                         */
                        int idx;
                        idx = find_irq_entry(apic1, pin1, mp_INT);
                        if (idx != -1 && irq_trigger(idx))
-                               unmask_ioapic(cfg);
+                               unmask_ioapic_irq(irq_get_chip_data(0));
                }
+               irq_domain_activate_irq(irq_data);
                if (timer_irq_works()) {
                        if (disable_timer_pin_1 > 0)
                                clear_IO_APIC_pin(0, pin1);
@@ -2251,8 +2135,8 @@ static inline void __init check_timer(void)
                /*
                 * legacy devices should be connected to IO APIC #0
                 */
-               replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
-               setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
+               replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
+               irq_domain_activate_irq(irq_data);
                legacy_pic->unmask(0);
                if (timer_irq_works()) {
                        apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
@@ -2329,36 +2213,35 @@ out:
 
 static int mp_irqdomain_create(int ioapic)
 {
-       size_t size;
+       struct irq_alloc_info info;
+       struct irq_domain *parent;
        int hwirqs = mp_ioapic_pin_count(ioapic);
        struct ioapic *ip = &ioapics[ioapic];
        struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg;
        struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic);
 
-       size = sizeof(struct mp_pin_info) * mp_ioapic_pin_count(ioapic);
-       ip->pin_info = kzalloc(size, GFP_KERNEL);
-       if (!ip->pin_info)
-               return -ENOMEM;
-
        if (cfg->type == IOAPIC_DOMAIN_INVALID)
                return 0;
 
+       init_irq_alloc_info(&info, NULL);
+       info.type = X86_IRQ_ALLOC_TYPE_IOAPIC;
+       info.ioapic_id = mpc_ioapic_id(ioapic);
+       parent = irq_remapping_get_ir_irq_domain(&info);
+       if (!parent)
+               parent = x86_vector_domain;
+
        ip->irqdomain = irq_domain_add_linear(cfg->dev, hwirqs, cfg->ops,
                                              (void *)(long)ioapic);
-       if(!ip->irqdomain) {
-               kfree(ip->pin_info);
-               ip->pin_info = NULL;
+       if (!ip->irqdomain)
                return -ENOMEM;
-       }
+
+       ip->irqdomain->parent = parent;
 
        if (cfg->type == IOAPIC_DOMAIN_LEGACY ||
            cfg->type == IOAPIC_DOMAIN_STRICT)
                ioapic_dynirq_base = max(ioapic_dynirq_base,
                                         gsi_cfg->gsi_end + 1);
 
-       if (gsi_cfg->gsi_base == 0)
-               irq_set_default_host(ip->irqdomain);
-
        return 0;
 }
 
@@ -2368,8 +2251,6 @@ static void ioapic_destroy_irqdomain(int idx)
                irq_domain_remove(ioapics[idx].irqdomain);
                ioapics[idx].irqdomain = NULL;
        }
-       kfree(ioapics[idx].pin_info);
-       ioapics[idx].pin_info = NULL;
 }
 
 void __init setup_IO_APIC(void)
@@ -2399,20 +2280,6 @@ void __init setup_IO_APIC(void)
        ioapic_initialized = 1;
 }
 
-/*
- *      Called after all the initialization is done. If we didn't find any
- *      APIC bugs then we can allow the modify fast path
- */
-
-static int __init io_apic_bug_finalize(void)
-{
-       if (sis_apic_bug == -1)
-               sis_apic_bug = 0;
-       return 0;
-}
-
-late_initcall(io_apic_bug_finalize);
-
 static void resume_ioapic_id(int ioapic_idx)
 {
        unsigned long flags;
@@ -2451,20 +2318,6 @@ static int __init ioapic_init_ops(void)
 
 device_initcall(ioapic_init_ops);
 
-static int
-io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
-{
-       struct irq_cfg *cfg = alloc_irq_and_cfg_at(irq, node);
-       int ret;
-
-       if (!cfg)
-               return -EINVAL;
-       ret = __add_pin_to_irq_node(cfg, node, attr->ioapic, attr->ioapic_pin);
-       if (!ret)
-               setup_ioapic_irq(irq, cfg, attr);
-       return ret;
-}
-
 static int io_apic_get_redir_entries(int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
@@ -2692,7 +2545,7 @@ void __init setup_ioapic_dest(void)
                else
                        mask = apic->target_cpus();
 
-               x86_io_apic_ops.set_affinity(idata, mask, false);
+               irq_set_affinity(irq, mask);
        }
 
 }
@@ -2737,7 +2590,7 @@ static struct resource * __init ioapic_setup_resources(void)
        return res;
 }
 
-void __init native_io_apic_init_mappings(void)
+void __init io_apic_init_mappings(void)
 {
        unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
        struct resource *ioapic_res;
@@ -2962,7 +2815,6 @@ int mp_unregister_ioapic(u32 gsi_base)
 {
        int ioapic, pin;
        int found = 0;
-       struct mp_pin_info *pin_info;
 
        for_each_ioapic(ioapic)
                if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) {
@@ -2975,11 +2827,17 @@ int mp_unregister_ioapic(u32 gsi_base)
        }
 
        for_each_pin(ioapic, pin) {
-               pin_info = mp_pin_info(ioapic, pin);
-               if (pin_info->count) {
-                       pr_warn("pin%d on IOAPIC%d is still in use.\n",
-                               pin, ioapic);
-                       return -EBUSY;
+               u32 gsi = mp_pin_to_gsi(ioapic, pin);
+               int irq = mp_map_gsi_to_irq(gsi, 0, NULL);
+               struct mp_chip_data *data;
+
+               if (irq >= 0) {
+                       data = irq_get_chip_data(irq);
+                       if (data && data->count) {
+                               pr_warn("pin%d on IOAPIC%d is still in use.\n",
+                                       pin, ioapic);
+                               return -EBUSY;
+                       }
                }
        }
 
@@ -3006,108 +2864,141 @@ int mp_ioapic_registered(u32 gsi_base)
        return 0;
 }
 
-static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
-                                       int ioapic, int ioapic_pin,
-                                       int trigger, int polarity)
+static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data,
+                                 struct irq_alloc_info *info)
 {
-       irq_attr->ioapic        = ioapic;
-       irq_attr->ioapic_pin    = ioapic_pin;
-       irq_attr->trigger       = trigger;
-       irq_attr->polarity      = polarity;
+       if (info && info->ioapic_valid) {
+               data->trigger = info->ioapic_trigger;
+               data->polarity = info->ioapic_polarity;
+       } else if (acpi_get_override_irq(gsi, &data->trigger,
+                                        &data->polarity) < 0) {
+               /* PCI interrupts are always active low level triggered. */
+               data->trigger = IOAPIC_LEVEL;
+               data->polarity = IOAPIC_POL_LOW;
+       }
 }
 
-int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
-                    irq_hw_number_t hwirq)
+static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data,
+                          struct IO_APIC_route_entry *entry)
 {
-       int ioapic = (int)(long)domain->host_data;
-       struct mp_pin_info *info = mp_pin_info(ioapic, hwirq);
-       struct io_apic_irq_attr attr;
+       memset(entry, 0, sizeof(*entry));
+       entry->delivery_mode = apic->irq_delivery_mode;
+       entry->dest_mode     = apic->irq_dest_mode;
+       entry->dest          = cfg->dest_apicid;
+       entry->vector        = cfg->vector;
+       entry->trigger       = data->trigger;
+       entry->polarity      = data->polarity;
+       /*
+        * Mask level triggered irqs. Edge triggered irqs are masked
+        * by the irq core code in case they fire.
+        */
+       if (data->trigger == IOAPIC_LEVEL)
+               entry->mask = IOAPIC_MASKED;
+       else
+               entry->mask = IOAPIC_UNMASKED;
+}
 
-       /* Get default attribute if not set by caller yet */
-       if (!info->set) {
-               u32 gsi = mp_pin_to_gsi(ioapic, hwirq);
+int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+                      unsigned int nr_irqs, void *arg)
+{
+       int ret, ioapic, pin;
+       struct irq_cfg *cfg;
+       struct irq_data *irq_data;
+       struct mp_chip_data *data;
+       struct irq_alloc_info *info = arg;
 
-               if (acpi_get_override_irq(gsi, &info->trigger,
-                                         &info->polarity) < 0) {
-                       /*
-                        * PCI interrupts are always polarity one level
-                        * triggered.
-                        */
-                       info->trigger = 1;
-                       info->polarity = 1;
-               }
-               info->node = NUMA_NO_NODE;
+       if (!info || nr_irqs > 1)
+               return -EINVAL;
+       irq_data = irq_domain_get_irq_data(domain, virq);
+       if (!irq_data)
+               return -EINVAL;
 
-               /*
-                * setup_IO_APIC_irqs() programs all legacy IRQs with default
-                * trigger and polarity attributes. Don't set the flag for that
-                * case so the first legacy IRQ user could reprogram the pin
-                * with real trigger and polarity attributes.
-                */
-               if (virq >= nr_legacy_irqs() || info->count)
-                       info->set = 1;
-       }
-       set_io_apic_irq_attr(&attr, ioapic, hwirq, info->trigger,
-                            info->polarity);
+       ioapic = mp_irqdomain_ioapic_idx(domain);
+       pin = info->ioapic_pin;
+       if (irq_find_mapping(domain, (irq_hw_number_t)pin) > 0)
+               return -EEXIST;
 
-       return io_apic_setup_irq_pin(virq, info->node, &attr);
-}
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
-void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq)
-{
-       struct irq_data *data = irq_get_irq_data(virq);
-       struct irq_cfg *cfg = irq_cfg(virq);
-       int ioapic = (int)(long)domain->host_data;
-       int pin = (int)data->hwirq;
+       info->ioapic_entry = &data->entry;
+       ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
+       if (ret < 0) {
+               kfree(data);
+               return ret;
+       }
+
+       INIT_LIST_HEAD(&data->irq_2_pin);
+       irq_data->hwirq = info->ioapic_pin;
+       irq_data->chip = (domain->parent == x86_vector_domain) ?
+                         &ioapic_chip : &ioapic_ir_chip;
+       irq_data->chip_data = data;
+       mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
+
+       cfg = irqd_cfg(irq_data);
+       add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin);
+       if (info->ioapic_entry)
+               mp_setup_entry(cfg, data, info->ioapic_entry);
+       mp_register_handler(virq, data->trigger);
+       if (virq < nr_legacy_irqs())
+               legacy_pic->mask(virq);
+
+       apic_printk(APIC_VERBOSE, KERN_DEBUG
+                   "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",
+                   ioapic, mpc_ioapic_id(ioapic), pin, cfg->vector,
+                   virq, data->trigger, data->polarity, cfg->dest_apicid);
 
-       ioapic_mask_entry(ioapic, pin);
-       __remove_pin_from_irq(cfg, ioapic, pin);
-       WARN_ON(!list_empty(&cfg->irq_2_pin));
-       arch_teardown_hwirq(virq);
+       return 0;
 }
 
-int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)
+void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
+                      unsigned int nr_irqs)
 {
-       int ret = 0;
-       int ioapic, pin;
-       struct mp_pin_info *info;
+       struct irq_data *irq_data;
+       struct mp_chip_data *data;
 
-       ioapic = mp_find_ioapic(gsi);
-       if (ioapic < 0)
-               return -ENODEV;
-
-       pin = mp_find_ioapic_pin(ioapic, gsi);
-       info = mp_pin_info(ioapic, pin);
-       trigger = trigger ? 1 : 0;
-       polarity = polarity ? 1 : 0;
-
-       mutex_lock(&ioapic_mutex);
-       if (!info->set) {
-               info->trigger = trigger;
-               info->polarity = polarity;
-               info->node = node;
-               info->set = 1;
-       } else if (info->trigger != trigger || info->polarity != polarity) {
-               ret = -EBUSY;
+       BUG_ON(nr_irqs != 1);
+       irq_data = irq_domain_get_irq_data(domain, virq);
+       if (irq_data && irq_data->chip_data) {
+               data = irq_data->chip_data;
+               __remove_pin_from_irq(data, mp_irqdomain_ioapic_idx(domain),
+                                     (int)irq_data->hwirq);
+               WARN_ON(!list_empty(&data->irq_2_pin));
+               kfree(irq_data->chip_data);
        }
-       mutex_unlock(&ioapic_mutex);
-
-       return ret;
+       irq_domain_free_irqs_top(domain, virq, nr_irqs);
 }
 
-/* Enable IOAPIC early just for system timer */
-void __init pre_init_apic_IRQ0(void)
+void mp_irqdomain_activate(struct irq_domain *domain,
+                          struct irq_data *irq_data)
 {
-       struct io_apic_irq_attr attr = { 0, 0, 0, 0 };
+       unsigned long flags;
+       struct irq_pin_list *entry;
+       struct mp_chip_data *data = irq_data->chip_data;
 
-       printk(KERN_INFO "Early APIC setup for system timer0\n");
-#ifndef CONFIG_SMP
-       physid_set_mask_of_physid(boot_cpu_physical_apicid,
-                                        &phys_cpu_present_map);
-#endif
-       setup_local_APIC();
+       raw_spin_lock_irqsave(&ioapic_lock, flags);
+       for_each_irq_pin(entry, data->irq_2_pin)
+               __ioapic_write_entry(entry->apic, entry->pin, data->entry);
+       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+}
 
-       io_apic_setup_irq_pin(0, 0, &attr);
-       irq_set_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq,
-                                     "edge");
+void mp_irqdomain_deactivate(struct irq_domain *domain,
+                            struct irq_data *irq_data)
+{
+       /* It won't be called for IRQ with multiple IOAPIC pins associated */
+       ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain),
+                         (int)irq_data->hwirq);
+}
+
+int mp_irqdomain_ioapic_idx(struct irq_domain *domain)
+{
+       return (int)(long)domain->host_data;
 }
+
+const struct irq_domain_ops mp_ioapic_irqdomain_ops = {
+       .alloc          = mp_irqdomain_alloc,
+       .free           = mp_irqdomain_free,
+       .activate       = mp_irqdomain_activate,
+       .deactivate     = mp_irqdomain_deactivate,
+};
index d6ba2d660dc52f59945825ef80a66821d5a971a5..58fde664e7c017b408587a3436c83438c1b7d6ff 100644 (file)
@@ -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>
+ *     Convert to hierarchical irqdomain
  *
  * 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/dmar.h>
 #include <linux/hpet.h>
 #include <linux/msi.h>
+#include <asm/irqdomain.h>
 #include <asm/msidef.h>
 #include <asm/hpet.h>
 #include <asm/hw_irq.h>
 #include <asm/apic.h>
 #include <asm/irq_remapping.h>
 
-void native_compose_msi_msg(struct pci_dev *pdev,
-                           unsigned int irq, unsigned int dest,
-                           struct msi_msg *msg, u8 hpet_id)
+static struct irq_domain *msi_default_domain;
+
+static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
 {
-       struct irq_cfg *cfg = irq_cfg(irq);
+       struct irq_cfg *cfg = irqd_cfg(data);
 
        msg->address_hi = MSI_ADDR_BASE_HI;
 
        if (x2apic_enabled())
-               msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
+               msg->address_hi |= MSI_ADDR_EXT_DEST_ID(cfg->dest_apicid);
 
        msg->address_lo =
                MSI_ADDR_BASE_LO |
@@ -39,7 +42,7 @@ void native_compose_msi_msg(struct pci_dev *pdev,
                ((apic->irq_delivery_mode != dest_LowestPrio) ?
                        MSI_ADDR_REDIRECTION_CPU :
                        MSI_ADDR_REDIRECTION_LOWPRI) |
-               MSI_ADDR_DEST_ID(dest);
+               MSI_ADDR_DEST_ID(cfg->dest_apicid);
 
        msg->data =
                MSI_DATA_TRIGGER_EDGE |
@@ -50,180 +53,200 @@ void native_compose_msi_msg(struct pci_dev *pdev,
                MSI_DATA_VECTOR(cfg->vector);
 }
 
-static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
-                          struct msi_msg *msg, u8 hpet_id)
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip pci_msi_controller = {
+       .name                   = "PCI-MSI",
+       .irq_unmask             = pci_msi_unmask_irq,
+       .irq_mask               = pci_msi_mask_irq,
+       .irq_ack                = irq_chip_ack_parent,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
+       .irq_compose_msi_msg    = irq_msi_compose_msg,
+       .flags                  = IRQCHIP_SKIP_SET_WAKE,
+};
+
+int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
-       struct irq_cfg *cfg;
-       int err;
-       unsigned dest;
+       struct irq_domain *domain;
+       struct irq_alloc_info info;
 
-       if (disable_apic)
-               return -ENXIO;
+       init_irq_alloc_info(&info, NULL);
+       info.type = X86_IRQ_ALLOC_TYPE_MSI;
+       info.msi_dev = dev;
 
-       cfg = irq_cfg(irq);
-       err = assign_irq_vector(irq, cfg, apic->target_cpus());
-       if (err)
-               return err;
+       domain = irq_remapping_get_irq_domain(&info);
+       if (domain == NULL)
+               domain = msi_default_domain;
+       if (domain == NULL)
+               return -ENOSYS;
 
-       err = apic->cpu_mask_to_apicid_and(cfg->domain,
-                                          apic->target_cpus(), &dest);
-       if (err)
-               return err;
+       return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
+}
 
-       x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
+void native_teardown_msi_irq(unsigned int irq)
+{
+       irq_domain_free_irqs(irq, 1);
+}
 
-       return 0;
+static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
+                                        msi_alloc_info_t *arg)
+{
+       return arg->msi_hwirq;
 }
 
-static int
-msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
+static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
+                          int nvec, msi_alloc_info_t *arg)
 {
-       struct irq_cfg *cfg = irqd_cfg(data);
-       struct msi_msg msg;
-       unsigned int dest;
-       int ret;
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct msi_desc *desc = first_pci_msi_entry(pdev);
+
+       init_irq_alloc_info(arg, NULL);
+       arg->msi_dev = pdev;
+       if (desc->msi_attrib.is_msix) {
+               arg->type = X86_IRQ_ALLOC_TYPE_MSIX;
+       } else {
+               arg->type = X86_IRQ_ALLOC_TYPE_MSI;
+               arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS;
+       }
 
-       ret = apic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
+       return 0;
+}
 
-       __get_cached_msi_msg(data->msi_desc, &msg);
+static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+       arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
+}
+
+static struct msi_domain_ops pci_msi_domain_ops = {
+       .get_hwirq      = pci_msi_get_hwirq,
+       .msi_prepare    = pci_msi_prepare,
+       .set_desc       = pci_msi_set_desc,
+};
 
-       msg.data &= ~MSI_DATA_VECTOR_MASK;
-       msg.data |= MSI_DATA_VECTOR(cfg->vector);
-       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
-       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+static struct msi_domain_info pci_msi_domain_info = {
+       .flags          = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+                         MSI_FLAG_PCI_MSIX,
+       .ops            = &pci_msi_domain_ops,
+       .chip           = &pci_msi_controller,
+       .handler        = handle_edge_irq,
+       .handler_name   = "edge",
+};
 
-       __pci_write_msi_msg(data->msi_desc, &msg);
+void arch_init_msi_domain(struct irq_domain *parent)
+{
+       if (disable_apic)
+               return;
 
-       return IRQ_SET_MASK_OK_NOCOPY;
+       msi_default_domain = pci_msi_create_irq_domain(NULL,
+                                       &pci_msi_domain_info, parent);
+       if (!msi_default_domain)
+               pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n");
 }
 
-/*
- * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI or MSI-X Capability Structure.
- */
-static struct irq_chip msi_chip = {
-       .name                   = "PCI-MSI",
+#ifdef CONFIG_IRQ_REMAP
+static struct irq_chip pci_msi_ir_controller = {
+       .name                   = "IR-PCI-MSI",
        .irq_unmask             = pci_msi_unmask_irq,
        .irq_mask               = pci_msi_mask_irq,
-       .irq_ack                = apic_ack_edge,
-       .irq_set_affinity       = msi_set_affinity,
-       .irq_retrigger          = apic_retrigger_irq,
+       .irq_ack                = irq_chip_ack_parent,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
 };
 
-int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
-                 unsigned int irq_base, unsigned int irq_offset)
-{
-       struct irq_chip *chip = &msi_chip;
-       struct msi_msg msg;
-       unsigned int irq = irq_base + irq_offset;
-       int ret;
-
-       ret = msi_compose_msg(dev, irq, &msg, -1);
-       if (ret < 0)
-               return ret;
-
-       irq_set_msi_desc_off(irq_base, irq_offset, msidesc);
-
-       /*
-        * MSI-X message is written per-IRQ, the offset is always 0.
-        * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
-        */
-       if (!irq_offset)
-               pci_write_msi_msg(irq, &msg);
+static struct msi_domain_info pci_msi_ir_domain_info = {
+       .flags          = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
+                         MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
+       .ops            = &pci_msi_domain_ops,
+       .chip           = &pci_msi_ir_controller,
+       .handler        = handle_edge_irq,
+       .handler_name   = "edge",
+};
 
-       setup_remapped_irq(irq, irq_cfg(irq), chip);
+struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
+{
+       return pci_msi_create_irq_domain(NULL, &pci_msi_ir_domain_info, parent);
+}
+#endif
 
-       irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
+#ifdef CONFIG_DMAR_TABLE
+static void dmar_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
+{
+       dmar_msi_write(data->irq, msg);
+}
 
-       dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq);
+static struct irq_chip dmar_msi_controller = {
+       .name                   = "DMAR-MSI",
+       .irq_unmask             = dmar_msi_unmask,
+       .irq_mask               = dmar_msi_mask,
+       .irq_ack                = irq_chip_ack_parent,
+       .irq_set_affinity       = msi_domain_set_affinity,
+       .irq_retrigger          = irq_chip_retrigger_hierarchy,
+       .irq_compose_msi_msg    = irq_msi_compose_msg,
+       .irq_write_msi_msg      = dmar_msi_write_msg,
+       .flags                  = IRQCHIP_SKIP_SET_WAKE,
+};
 
-       return 0;
+static irq_hw_number_t dmar_msi_get_hwirq(struct msi_domain_info *info,
+                                         msi_alloc_info_t *arg)
+{
+       return arg->dmar_id;
 }
 
-int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+static int dmar_msi_init(struct irq_domain *domain,
+                        struct msi_domain_info *info, unsigned int virq,
+                        irq_hw_number_t hwirq, msi_alloc_info_t *arg)
 {
-       struct msi_desc *msidesc;
-       unsigned int irq;
-       int node, ret;
+       irq_domain_set_info(domain, virq, arg->dmar_id, info->chip, NULL,
+                           handle_edge_irq, arg->dmar_data, "edge");
 
-       /* Multiple MSI vectors only supported with interrupt remapping */
-       if (type == PCI_CAP_ID_MSI && nvec > 1)
-               return 1;
+       return 0;
+}
 
-       node = dev_to_node(&dev->dev);
+static struct msi_domain_ops dmar_msi_domain_ops = {
+       .get_hwirq      = dmar_msi_get_hwirq,
+       .msi_init       = dmar_msi_init,
+};
 
-       list_for_each_entry(msidesc, &dev->msi_list, list) {
-               irq = irq_alloc_hwirq(node);
-               if (!irq)
-                       return -ENOSPC;
+static struct msi_domain_info dmar_msi_domain_info = {
+       .ops            = &dmar_msi_domain_ops,
+       .chip           = &dmar_msi_controller,
+};
 
-               ret = setup_msi_irq(dev, msidesc, irq, 0);
-               if (ret < 0) {
-                       irq_free_hwirq(irq);
-                       return ret;
-               }
+static struct irq_domain *dmar_get_irq_domain(void)
+{
+       static struct irq_domain *dmar_domain;
+       static DEFINE_MUTEX(dmar_lock);
 
-       }
-       return 0;
-}
+       mutex_lock(&dmar_lock);
+       if (dmar_domain == NULL)
+               dmar_domain = msi_create_irq_domain(NULL, &dmar_msi_domain_info,
+                                                   x86_vector_domain);
+       mutex_unlock(&dmar_lock);
 
-void native_teardown_msi_irq(unsigned int irq)
-{
-       irq_free_hwirq(irq);
+       return dmar_domain;
 }
 
-#ifdef CONFIG_DMAR_TABLE
-static int
-dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
-                     bool force)
+int dmar_alloc_hwirq(int id, int node, void *arg)
 {
-       struct irq_cfg *cfg = irqd_cfg(data);
-       unsigned int dest, irq = data->irq;
-       struct msi_msg msg;
-       int ret;
-
-       ret = apic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
+       struct irq_domain *domain = dmar_get_irq_domain();
+       struct irq_alloc_info info;
 
-       dmar_msi_read(irq, &msg);
+       if (!domain)
+               return -1;
 
-       msg.data &= ~MSI_DATA_VECTOR_MASK;
-       msg.data |= MSI_DATA_VECTOR(cfg->vector);
-       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
-       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
-       msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest);
+       init_irq_alloc_info(&info, NULL);
+       info.type = X86_IRQ_ALLOC_TYPE_DMAR;
+       info.dmar_id = id;
+       info.dmar_data = arg;
 
-       dmar_msi_write(irq, &msg);
-
-       return IRQ_SET_MASK_OK_NOCOPY;
+       return irq_domain_alloc_irqs(domain, 1, node, &info);
 }
 
-static struct irq_chip dmar_msi_type = {
-       .name                   = "DMAR_MSI",
-       .irq_unmask             = dmar_msi_unmask,
-       .irq_mask               = dmar_msi_mask,
-       .irq_ack                = apic_ack_edge,
-       .irq_set_affinity       = dmar_msi_set_affinity,
-       .irq_retrigger          = apic_retrigger_irq,
-       .flags                  = IRQCHIP_SKIP_SET_WAKE,
-};
-
-int arch_setup_dmar_msi(unsigned int irq)
+void dmar_free_hwirq(int irq)
 {
-       int ret;
-       struct msi_msg msg;
-
-       ret = msi_compose_msg(NULL, irq, &msg, -1);
-       if (ret < 0)
-               return ret;
-       dmar_msi_write(irq, &msg);
-       irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
-                                     "edge");
-       return 0;
+       irq_domain_free_irqs(irq, 1);
 }
 #endif
 
@@ -231,56 +254,103 @@ int arch_setup_dmar_msi(unsigned int irq)
  * MSI message composition
  */
 #ifdef CONFIG_HPET_TIMER
+static inline int hpet_dev_id(struct irq_domain *domain)
+{
+       struct msi_domain_info *info = msi_get_domain_info(domain);
+
+       return (int)(long)info->data;
+}
 
-static int hpet_msi_set_affinity(struct irq_data *data,
-                                const struct cpumask *mask, bool force)
+static void hpet_msi_write_msg(struct irq_data *data, struct msi_msg *msg)
 {
-       struct irq_cfg *cfg = irqd_cfg(data);
-       struct msi_msg msg;
-       unsigned int dest;
-       int ret;
+       hpet_msi_write(data->handler_data, msg);
+}
 
-       ret = apic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
+static struct irq_chip hpet_msi_controller = {
+       .name = "HPET-MSI",
+       .irq_unmask = hpet_msi_unmask,
+       .irq_mask = hpet_msi_mask,
+       .irq_ack = irq_chip_ack_parent,
+       .irq_set_affinity = msi_domain_set_affinity,
+       .irq_retrigger = irq_chip_retrigger_hierarchy,
+       .irq_compose_msi_msg = irq_msi_compose_msg,
+       .irq_write_msi_msg = hpet_msi_write_msg,
+       .flags = IRQCHIP_SKIP_SET_WAKE,
+};
 
-       hpet_msi_read(data->handler_data, &msg);
+static irq_hw_number_t hpet_msi_get_hwirq(struct msi_domain_info *info,
+                                         msi_alloc_info_t *arg)
+{
+       return arg->hpet_index;
+}
 
-       msg.data &= ~MSI_DATA_VECTOR_MASK;
-       msg.data |= MSI_DATA_VECTOR(cfg->vector);
-       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
-       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+static int hpet_msi_init(struct irq_domain *domain,
+                        struct msi_domain_info *info, unsigned int virq,
+                        irq_hw_number_t hwirq, msi_alloc_info_t *arg)
+{
+       irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
+       irq_domain_set_info(domain, virq, arg->hpet_index, info->chip, NULL,
+                           handle_edge_irq, arg->hpet_data, "edge");
 
-       hpet_msi_write(data->handler_data, &msg);
+       return 0;
+}
 
-       return IRQ_SET_MASK_OK_NOCOPY;
+static void hpet_msi_free(struct irq_domain *domain,
+                         struct msi_domain_info *info, unsigned int virq)
+{
+       irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
 }
 
-static struct irq_chip hpet_msi_type = {
-       .name = "HPET_MSI",
-       .irq_unmask = hpet_msi_unmask,
-       .irq_mask = hpet_msi_mask,
-       .irq_ack = apic_ack_edge,
-       .irq_set_affinity = hpet_msi_set_affinity,
-       .irq_retrigger = apic_retrigger_irq,
-       .flags = IRQCHIP_SKIP_SET_WAKE,
+static struct msi_domain_ops hpet_msi_domain_ops = {
+       .get_hwirq      = hpet_msi_get_hwirq,
+       .msi_init       = hpet_msi_init,
+       .msi_free       = hpet_msi_free,
+};
+
+static struct msi_domain_info hpet_msi_domain_info = {
+       .ops            = &hpet_msi_domain_ops,
+       .chip           = &hpet_msi_controller,
 };
 
-int default_setup_hpet_msi(unsigned int irq, unsigned int id)
+struct irq_domain *hpet_create_irq_domain(int hpet_id)
 {
-       struct irq_chip *chip = &hpet_msi_type;
-       struct msi_msg msg;
-       int ret;
+       struct irq_domain *parent;
+       struct irq_alloc_info info;
+       struct msi_domain_info *domain_info;
+
+       if (x86_vector_domain == NULL)
+               return NULL;
+
+       domain_info = kzalloc(sizeof(*domain_info), GFP_KERNEL);
+       if (!domain_info)
+               return NULL;
+
+       *domain_info = hpet_msi_domain_info;
+       domain_info->data = (void *)(long)hpet_id;
+
+       init_irq_alloc_info(&info, NULL);
+       info.type = X86_IRQ_ALLOC_TYPE_HPET;
+       info.hpet_id = hpet_id;
+       parent = irq_remapping_get_ir_irq_domain(&info);
+       if (parent == NULL)
+               parent = x86_vector_domain;
+       else
+               hpet_msi_controller.name = "IR-HPET-MSI";
+
+       return msi_create_irq_domain(NULL, domain_info, parent);
+}
 
-       ret = msi_compose_msg(NULL, irq, &msg, id);
-       if (ret < 0)
-               return ret;
+int hpet_assign_irq(struct irq_domain *domain, struct hpet_dev *dev,
+                   int dev_num)
+{
+       struct irq_alloc_info info;
 
-       hpet_msi_write(irq_get_handler_data(irq), &msg);
-       irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-       setup_remapped_irq(irq, irq_cfg(irq), chip);
+       init_irq_alloc_info(&info, NULL);
+       info.type = X86_IRQ_ALLOC_TYPE_HPET;
+       info.hpet_data = dev;
+       info.hpet_id = hpet_dev_id(domain);
+       info.hpet_index = dev_num;
 
-       irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
-       return 0;
+       return irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, NULL);
 }
 #endif
index 82d44c314a3f9b7888b8cec42e7c1514e50ae056..2766747e1a3b316d65be99b0d3f6feb4a021a533 100644 (file)
@@ -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)
 {
@@ -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
@@ -114,36 +117,33 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
        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,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;
@@ -174,55 +176,61 @@ 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)
@@ -231,10 +239,102 @@ void clear_irq_vector(int irq, struct irq_cfg *cfg)
                        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;
@@ -258,8 +358,43 @@ int __init arch_probe_nr_irqs(void)
        return nr_legacy_irqs();
 }
 
+#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
+        * 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();
 }
 
@@ -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
@@ -277,13 +412,13 @@ static void __setup_vector_irq(int cpu)
        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 */
@@ -292,8 +427,8 @@ static void __setup_vector_irq(int cpu)
                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);
@@ -319,15 +454,15 @@ void setup_vector_irq(int cpu)
        __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;
@@ -340,57 +475,62 @@ void apic_ack_edge(struct irq_data *data)
        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)
@@ -406,7 +546,7 @@ 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]);
 
@@ -417,8 +557,8 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
                if (!desc)
                        continue;
 
-               cfg = irq_cfg(irq);
-               if (!cfg)
+               data = apic_chip_data(&desc->irq_data);
+               if (!data)
                        continue;
 
                raw_spin_lock(&desc->lock);
@@ -427,10 +567,11 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
                 * 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));
@@ -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)
@@ -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 6fae733e9194893dc761ccd06839df81232c7427..3ffd925655e0d4a8338d401d2793a61a5cb3fd6f 100644 (file)
@@ -21,11 +21,13 @@ early_param("x2apic_phys", set_x2apic_phys_mode);
 
 static bool x2apic_fadt_phys(void)
 {
+#ifdef CONFIG_ACPI
        if ((acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) &&
                (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
                printk(KERN_DEBUG "System requires x2apic physical mode\n");
                return true;
        }
+#endif
        return false;
 }
 
index 6367a780cc8ca891b9513d2e4688717c8d5d3207..5ee771859b6f6e144090efe8f315e0c7707978b3 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/bootmem.h>
 #include <linux/export.h>
 #include <linux/io.h>
-#include <linux/irqdomain.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/of.h>
@@ -17,6 +16,7 @@
 #include <linux/of_pci.h>
 #include <linux/initrd.h>
 
+#include <asm/irqdomain.h>
 #include <asm/hpet.h>
 #include <asm/apic.h>
 #include <asm/pci_x86.h>
@@ -196,38 +196,31 @@ static struct of_ioapic_type of_ioapic_type[] =
        },
 };
 
-static int ioapic_xlate(struct irq_domain *domain,
-                       struct device_node *controller,
-                       const u32 *intspec, u32 intsize,
-                       irq_hw_number_t *out_hwirq, u32 *out_type)
+static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
+                             unsigned int nr_irqs, void *arg)
 {
+       struct of_phandle_args *irq_data = (void *)arg;
        struct of_ioapic_type *it;
-       u32 line, idx, gsi;
+       struct irq_alloc_info tmp;
 
-       if (WARN_ON(intsize < 2))
+       if (WARN_ON(irq_data->args_count < 2))
                return -EINVAL;
-
-       line = intspec[0];
-
-       if (intspec[1] >= ARRAY_SIZE(of_ioapic_type))
+       if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type))
                return -EINVAL;
 
-       it = &of_ioapic_type[intspec[1]];
+       it = &of_ioapic_type[irq_data->args[1]];
+       ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity);
+       tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
+       tmp.ioapic_pin = irq_data->args[0];
 
-       idx = (u32)(long)domain->host_data;
-       gsi = mp_pin_to_gsi(idx, line);
-       if (mp_set_gsi_attr(gsi, it->trigger, it->polarity, cpu_to_node(0)))
-               return -EBUSY;
-
-       *out_hwirq = line;
-       *out_type = it->out_type;
-       return 0;
+       return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
 }
 
-const struct irq_domain_ops ioapic_irq_domain_ops = {
-       .map = mp_irqdomain_map,
-       .unmap = mp_irqdomain_unmap,
-       .xlate = ioapic_xlate,
+static const struct irq_domain_ops ioapic_irq_domain_ops = {
+       .alloc          = dt_irqdomain_alloc,
+       .free           = mp_irqdomain_free,
+       .activate       = mp_irqdomain_activate,
+       .deactivate     = mp_irqdomain_deactivate,
 };
 
 static void __init dtb_add_ioapic(struct device_node *dn)
index 3acbff4716b088ded2e1d237106872d5d1d1a7f0..e2449cf38b06eb43bb9d00752fd320e8748f13c3 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pm.h>
 #include <linux/io.h>
 
+#include <asm/irqdomain.h>
 #include <asm/fixmap.h>
 #include <asm/hpet.h>
 #include <asm/time.h>
@@ -305,8 +306,6 @@ static void hpet_legacy_clockevent_register(void)
        printk(KERN_DEBUG "hpet clockevent registered\n");
 }
 
-static int hpet_setup_msi_irq(unsigned int irq);
-
 static void hpet_set_mode(enum clock_event_mode mode,
                          struct clock_event_device *evt, int timer)
 {
@@ -357,7 +356,7 @@ static void hpet_set_mode(enum clock_event_mode mode,
                        hpet_enable_legacy_int();
                } else {
                        struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
-                       hpet_setup_msi_irq(hdev->irq);
+                       irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
                        disable_irq(hdev->irq);
                        irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
                        enable_irq(hdev->irq);
@@ -423,6 +422,7 @@ static int hpet_legacy_next_event(unsigned long delta,
 
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev *hpet_devs;
+static struct irq_domain *hpet_domain;
 
 void hpet_msi_unmask(struct irq_data *data)
 {
@@ -473,31 +473,6 @@ static int hpet_msi_next_event(unsigned long delta,
        return hpet_next_event(delta, evt, hdev->num);
 }
 
-static int hpet_setup_msi_irq(unsigned int irq)
-{
-       if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
-               irq_free_hwirq(irq);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-static int hpet_assign_irq(struct hpet_dev *dev)
-{
-       unsigned int irq = irq_alloc_hwirq(-1);
-
-       if (!irq)
-               return -EINVAL;
-
-       irq_set_handler_data(irq, dev);
-
-       if (hpet_setup_msi_irq(irq))
-               return -EINVAL;
-
-       dev->irq = irq;
-       return 0;
-}
-
 static irqreturn_t hpet_interrupt_handler(int irq, void *data)
 {
        struct hpet_dev *dev = (struct hpet_dev *)data;
@@ -540,9 +515,6 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
        if (!(hdev->flags & HPET_DEV_VALID))
                return;
 
-       if (hpet_setup_msi_irq(hdev->irq))
-               return;
-
        hdev->cpu = cpu;
        per_cpu(cpu_hpet_dev, cpu) = hdev;
        evt->name = hdev->name;
@@ -574,7 +546,7 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
        unsigned int id;
        unsigned int num_timers;
        unsigned int num_timers_used = 0;
-       int i;
+       int i, irq;
 
        if (hpet_msi_disable)
                return;
@@ -587,6 +559,10 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
        num_timers++; /* Value read out starts from 0 */
        hpet_print_config();
 
+       hpet_domain = hpet_create_irq_domain(hpet_blockid);
+       if (!hpet_domain)
+               return;
+
        hpet_devs = kzalloc(sizeof(struct hpet_dev) * num_timers, GFP_KERNEL);
        if (!hpet_devs)
                return;
@@ -601,15 +577,16 @@ static void hpet_msi_capability_lookup(unsigned int start_timer)
                if (!(cfg & HPET_TN_FSB_CAP))
                        continue;
 
+               irq = hpet_assign_irq(hpet_domain, hdev, hdev->num);
+               if (irq < 0)
+                       continue;
+
+               sprintf(hdev->name, "hpet%d", i);
+               hdev->num = i;
+               hdev->irq = irq;
                hdev->flags = 0;
                if (cfg & HPET_TN_PERIODIC_CAP)
                        hdev->flags |= HPET_DEV_PERI_CAP;
-               hdev->num = i;
-
-               sprintf(hdev->name, "hpet%d", i);
-               if (hpet_assign_irq(hdev))
-                       continue;
-
                hdev->flags |= HPET_DEV_FSB_CAP;
                hdev->flags |= HPET_DEV_VALID;
                num_timers_used++;
@@ -709,10 +686,6 @@ static int hpet_cpuhp_notify(struct notifier_block *n,
 }
 #else
 
-static int hpet_setup_msi_irq(unsigned int irq)
-{
-       return 0;
-}
 static void hpet_msi_capability_lookup(unsigned int start_timer)
 {
        return;
index 2d2a237f2c73698a4dd2819800edd6179239904b..30ca7607cbbbbcae4793aa5c14d8f73bbd784d71 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/pci.h>
-#include <linux/irqdomain.h>
 
+#include <asm/irqdomain.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
@@ -113,11 +113,6 @@ static void __init MP_bus_info(struct mpc_bus *m)
                pr_warn("Unknown bustype %s - ignoring\n", str);
 }
 
-static struct irq_domain_ops mp_ioapic_irqdomain_ops = {
-       .map = mp_irqdomain_map,
-       .unmap = mp_irqdomain_unmap,
-};
-
 static void __init MP_ioapic_info(struct mpc_ioapic *m)
 {
        struct ioapic_domain_cfg cfg = {
index d74ac33290ae3eeef46b923c4556d644b72f0d5a..8d04a7594a036387fa483c8a108523e4849033ae 100644 (file)
@@ -1222,8 +1222,7 @@ void __init setup_arch(char **cmdline_p)
        init_cpu_to_node();
 
        init_apic_mappings();
-       if (x86_io_apic_ops.init)
-               x86_io_apic_ops.init();
+       io_apic_init_mappings();
 
        kvm_guest_init();
 
index 023cccf5a4aefb255f72a3a2673e3a827f453623..51203f60587f847d51eaa33638604a082a864f54 100644 (file)
@@ -555,7 +555,7 @@ wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip)
 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();
@@ -580,22 +580,34 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
        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 ?
@@ -637,20 +649,23 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
                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);
index 234b0722de53522d6d20bd060478ea3e97f8cbb9..3cee10abf01d1515373871918da54f65f6e433c2 100644 (file)
@@ -111,11 +111,9 @@ EXPORT_SYMBOL_GPL(x86_platform);
 #if defined(CONFIG_PCI_MSI)
 struct x86_msi_ops x86_msi = {
        .setup_msi_irqs         = native_setup_msi_irqs,
-       .compose_msi_msg        = native_compose_msi_msg,
        .teardown_msi_irq       = native_teardown_msi_irq,
        .teardown_msi_irqs      = default_teardown_msi_irqs,
        .restore_msi_irqs       = default_restore_msi_irqs,
-       .setup_hpet_msi         = default_setup_hpet_msi,
 };
 
 /* MSI arch specific hooks */
@@ -141,13 +139,6 @@ void arch_restore_msi_irqs(struct pci_dev *dev)
 #endif
 
 struct x86_io_apic_ops x86_io_apic_ops = {
-       .init                   = native_io_apic_init_mappings,
        .read                   = native_io_apic_read,
-       .write                  = native_io_apic_write,
-       .modify                 = native_io_apic_modify,
        .disable                = native_disable_io_apic,
-       .print_entries          = native_io_apic_print_entries,
-       .set_affinity           = native_ioapic_set_affinity,
-       .setup_entry            = native_setup_ioapic_entry,
-       .eoi_ioapic_pin         = native_eoi_ioapic_pin,
 };
index 852aa4c92da027cb07fb64c77c855aaf0877a1da..27062303c88135b5d614455ed372861516903e53 100644 (file)
@@ -208,6 +208,7 @@ static int pci_write(struct pci_bus *bus, unsigned int devfn, int where,
 
 static int intel_mid_pci_irq_enable(struct pci_dev *dev)
 {
+       struct irq_alloc_info info;
        int polarity;
 
        if (dev->irq_managed && dev->irq > 0)
@@ -217,14 +218,13 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
                polarity = 0; /* active high */
        else
                polarity = 1; /* active low */
+       ioapic_set_alloc_attr(&info, dev_to_node(&dev->dev), 1, polarity);
 
        /*
         * MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
         * IOAPIC RTE entries, so we just enable RTE for the device.
         */
-       if (mp_set_gsi_attr(dev->irq, 1, polarity, dev_to_node(&dev->dev)))
-               return -EBUSY;
-       if (mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC) < 0)
+       if (mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC, &info) < 0)
                return -EBUSY;
 
        dev->irq_managed = 1;
index 0b283d4d0ad770d945f407c4921d09ecacb34db4..de734134bc8d2e1733fb831a32cdbfd8fcf80ed5 100644 (file)
@@ -27,6 +27,7 @@ static struct platform_device wdt_dev = {
 static int tangier_probe(struct platform_device *pdev)
 {
        int gsi;
+       struct irq_alloc_info info;
        struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
 
        if (!pdata)
@@ -34,8 +35,8 @@ static int tangier_probe(struct platform_device *pdev)
 
        /* IOAPIC builds identity mapping between GSI and IRQ on MID */
        gsi = pdata->irq;
-       if (mp_set_gsi_attr(gsi, 1, 0, cpu_to_node(0)) ||
-           mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC) <= 0) {
+       ioapic_set_alloc_attr(&info, cpu_to_node(0), 1, 0);
+       if (mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info) <= 0) {
                dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n",
                         gsi);
                return -EINVAL;
index 3005f0c89f2ecfbcc817c7e379c97586d5524e7f..01d54ea766c16539d001da113320c56ee8eac1f8 100644 (file)
@@ -81,26 +81,34 @@ static unsigned long __init intel_mid_calibrate_tsc(void)
        return 0;
 }
 
+static void __init intel_mid_setup_bp_timer(void)
+{
+       apbt_time_init();
+       setup_boot_APIC_clock();
+}
+
 static void __init intel_mid_time_init(void)
 {
        sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
+
        switch (intel_mid_timer_options) {
        case INTEL_MID_TIMER_APBT_ONLY:
                break;
        case INTEL_MID_TIMER_LAPIC_APBT:
-               x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+               /* Use apbt and local apic */
+               x86_init.timers.setup_percpu_clockev = intel_mid_setup_bp_timer;
                x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
-               break;
+               return;
        default:
                if (!boot_cpu_has(X86_FEATURE_ARAT))
                        break;
+               /* Lapic only, no apbt */
                x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
                x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
                return;
        }
-       /* we need at least one APB timer */
-       pre_init_apic_IRQ0();
-       apbt_time_init();
+
+       x86_init.timers.setup_percpu_clockev = apbt_time_init;
 }
 
 static void intel_mid_arch_setup(void)
index c14ad34776c466f3cb18fe4b0a50fe40db8cd3ec..ce992e8cc06526c4e61f1efb1b852e0f41df9ccf 100644 (file)
@@ -95,18 +95,16 @@ int __init sfi_parse_mtmr(struct sfi_table_header *table)
                pr_debug("timer[%d]: paddr = 0x%08x, freq = %dHz, irq = %d\n",
                        totallen, (u32)pentry->phys_addr,
                        pentry->freq_hz, pentry->irq);
-                       if (!pentry->irq)
-                               continue;
-                       mp_irq.type = MP_INTSRC;
-                       mp_irq.irqtype = mp_INT;
-/* triggering mode edge bit 2-3, active high polarity bit 0-1 */
-                       mp_irq.irqflag = 5;
-                       mp_irq.srcbus = MP_BUS_ISA;
-                       mp_irq.srcbusirq = pentry->irq; /* IRQ */
-                       mp_irq.dstapic = MP_APIC_ALL;
-                       mp_irq.dstirq = pentry->irq;
-                       mp_save_irq(&mp_irq);
-                       mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC);
+               mp_irq.type = MP_INTSRC;
+               mp_irq.irqtype = mp_INT;
+               /* triggering mode edge bit 2-3, active high polarity bit 0-1 */
+               mp_irq.irqflag = 5;
+               mp_irq.srcbus = MP_BUS_ISA;
+               mp_irq.srcbusirq = pentry->irq; /* IRQ */
+               mp_irq.dstapic = MP_APIC_ALL;
+               mp_irq.dstirq = pentry->irq;
+               mp_save_irq(&mp_irq);
+               mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC, NULL);
        }
 
        return 0;
@@ -177,7 +175,7 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table)
                mp_irq.dstapic = MP_APIC_ALL;
                mp_irq.dstirq = pentry->irq;
                mp_save_irq(&mp_irq);
-               mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC);
+               mp_map_gsi_to_irq(pentry->irq, IOAPIC_MAP_ALLOC, NULL);
        }
        return 0;
 }
@@ -436,6 +434,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)
        struct devs_id *dev = NULL;
        int num, i, ret;
        int polarity;
+       struct irq_alloc_info info;
 
        sb = (struct sfi_table_simple *)table;
        num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry);
@@ -469,9 +468,8 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)
                                polarity = 1;
                        }
 
-                       ret = mp_set_gsi_attr(irq, 1, polarity, NUMA_NO_NODE);
-                       if (ret == 0)
-                               ret = mp_map_gsi_to_irq(irq, IOAPIC_MAP_ALLOC);
+                       ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 1, polarity);
+                       ret = mp_map_gsi_to_irq(irq, IOAPIC_MAP_ALLOC, &info);
                        WARN_ON(ret < 0);
                }
 
index 2a8a74f3bd76c1338e2378c26bc231cc5adf9bea..6c7111bbd1e92faf169b9b046726f704c260e8d2 100644 (file)
@@ -25,8 +25,8 @@
 #include <linux/init.h>
 #include <linux/sfi.h>
 #include <linux/io.h>
-#include <linux/irqdomain.h>
 
+#include <asm/irqdomain.h>
 #include <asm/io_apic.h>
 #include <asm/mpspec.h>
 #include <asm/setup.h>
@@ -71,9 +71,6 @@ static int __init sfi_parse_cpus(struct sfi_table_header *table)
 #endif /* CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_IO_APIC
-static struct irq_domain_ops sfi_ioapic_irqdomain_ops = {
-       .map = mp_irqdomain_map,
-};
 
 static int __init sfi_parse_ioapic(struct sfi_table_header *table)
 {
@@ -82,7 +79,7 @@ static int __init sfi_parse_ioapic(struct sfi_table_header *table)
        int i, num;
        struct ioapic_domain_cfg cfg = {
                .type = IOAPIC_DOMAIN_STRICT,
-               .ops = &sfi_ioapic_irqdomain_ops,
+               .ops = &mp_ioapic_irqdomain_ops,
        };
 
        sb = (struct sfi_table_simple *)table;
index 0ce67364543242a21fd3d6e2b40f8864623ce668..8570abe68be1feb0b12bb1828a7126d07b94307d 100644 (file)
 #include <linux/slab.h>
 #include <linux/irq.h>
 
+#include <asm/irqdomain.h>
 #include <asm/apic.h>
 #include <asm/uv/uv_irq.h>
 #include <asm/uv/uv_hub.h>
 
 /* MMR offset and pnode of hub sourcing interrupts for a given irq */
-struct uv_irq_2_mmr_pnode{
-       struct rb_node          list;
+struct uv_irq_2_mmr_pnode {
        unsigned long           offset;
        int                     pnode;
-       int                     irq;
 };
 
-static DEFINE_SPINLOCK(uv_irq_lock);
-static struct rb_root          uv_irq_root;
+static void uv_program_mmr(struct irq_cfg *cfg, struct uv_irq_2_mmr_pnode *info)
+{
+       unsigned long mmr_value;
+       struct uv_IO_APIC_route_entry *entry;
+
+       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
+                    sizeof(unsigned long));
+
+       mmr_value = 0;
+       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+       entry->vector           = cfg->vector;
+       entry->delivery_mode    = apic->irq_delivery_mode;
+       entry->dest_mode        = apic->irq_dest_mode;
+       entry->polarity         = 0;
+       entry->trigger          = 0;
+       entry->mask             = 0;
+       entry->dest             = cfg->dest_apicid;
 
-static int uv_set_irq_affinity(struct irq_data *, const struct cpumask *, bool);
+       uv_write_global_mmr64(info->pnode, info->offset, mmr_value);
+}
 
 static void uv_noop(struct irq_data *data) { }
 
@@ -37,6 +52,23 @@ static void uv_ack_apic(struct irq_data *data)
        ack_APIC_irq();
 }
 
+static int
+uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
+                   bool force)
+{
+       struct irq_data *parent = data->parent_data;
+       struct irq_cfg *cfg = irqd_cfg(data);
+       int ret;
+
+       ret = parent->chip->irq_set_affinity(parent, mask, force);
+       if (ret >= 0) {
+               uv_program_mmr(cfg, data->chip_data);
+               send_cleanup_vector(cfg);
+       }
+
+       return ret;
+}
+
 static struct irq_chip uv_irq_chip = {
        .name                   = "UV-CORE",
        .irq_mask               = uv_noop,
@@ -45,189 +77,99 @@ static struct irq_chip uv_irq_chip = {
        .irq_set_affinity       = uv_set_irq_affinity,
 };
 
-/*
- * Add offset and pnode information of the hub sourcing interrupts to the
- * rb tree for a specific irq.
- */
-static int uv_set_irq_2_mmr_info(int irq, unsigned long offset, unsigned blade)
+static int uv_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                          unsigned int nr_irqs, void *arg)
 {
-       struct rb_node **link = &uv_irq_root.rb_node;
-       struct rb_node *parent = NULL;
-       struct uv_irq_2_mmr_pnode *n;
-       struct uv_irq_2_mmr_pnode *e;
-       unsigned long irqflags;
-
-       n = kmalloc_node(sizeof(struct uv_irq_2_mmr_pnode), GFP_KERNEL,
-                               uv_blade_to_memory_nid(blade));
-       if (!n)
+       struct uv_irq_2_mmr_pnode *chip_data;
+       struct irq_alloc_info *info = arg;
+       struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+       int ret;
+
+       if (nr_irqs > 1 || !info || info->type != X86_IRQ_ALLOC_TYPE_UV)
+               return -EINVAL;
+
+       chip_data = kmalloc_node(sizeof(*chip_data), GFP_KERNEL,
+                                irq_data->node);
+       if (!chip_data)
                return -ENOMEM;
 
-       n->irq = irq;
-       n->offset = offset;
-       n->pnode = uv_blade_to_pnode(blade);
-       spin_lock_irqsave(&uv_irq_lock, irqflags);
-       /* Find the right place in the rbtree: */
-       while (*link) {
-               parent = *link;
-               e = rb_entry(parent, struct uv_irq_2_mmr_pnode, list);
-
-               if (unlikely(irq == e->irq)) {
-                       /* irq entry exists */
-                       e->pnode = uv_blade_to_pnode(blade);
-                       e->offset = offset;
-                       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-                       kfree(n);
-                       return 0;
-               }
-
-               if (irq < e->irq)
-                       link = &(*link)->rb_left;
+       ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+       if (ret >= 0) {
+               if (info->uv_limit == UV_AFFINITY_CPU)
+                       irq_set_status_flags(virq, IRQ_NO_BALANCING);
                else
-                       link = &(*link)->rb_right;
+                       irq_set_status_flags(virq, IRQ_MOVE_PCNTXT);
+
+               chip_data->pnode = uv_blade_to_pnode(info->uv_blade);
+               chip_data->offset = info->uv_offset;
+               irq_domain_set_info(domain, virq, virq, &uv_irq_chip, chip_data,
+                                   handle_percpu_irq, NULL, info->uv_name);
+       } else {
+               kfree(chip_data);
        }
 
-       /* Insert the node into the rbtree. */
-       rb_link_node(&n->list, parent, link);
-       rb_insert_color(&n->list, &uv_irq_root);
-
-       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-       return 0;
+       return ret;
 }
 
-/* Retrieve offset and pnode information from the rb tree for a specific irq */
-int uv_irq_2_mmr_info(int irq, unsigned long *offset, int *pnode)
+static void uv_domain_free(struct irq_domain *domain, unsigned int virq,
+                          unsigned int nr_irqs)
 {
-       struct uv_irq_2_mmr_pnode *e;
-       struct rb_node *n;
-       unsigned long irqflags;
-
-       spin_lock_irqsave(&uv_irq_lock, irqflags);
-       n = uv_irq_root.rb_node;
-       while (n) {
-               e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
-
-               if (e->irq == irq) {
-                       *offset = e->offset;
-                       *pnode = e->pnode;
-                       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-                       return 0;
-               }
-
-               if (irq < e->irq)
-                       n = n->rb_left;
-               else
-                       n = n->rb_right;
-       }
-       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-       return -1;
+       struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+
+       BUG_ON(nr_irqs != 1);
+       kfree(irq_data->chip_data);
+       irq_clear_status_flags(virq, IRQ_MOVE_PCNTXT);
+       irq_clear_status_flags(virq, IRQ_NO_BALANCING);
+       irq_domain_free_irqs_top(domain, virq, nr_irqs);
 }
 
 /*
  * Re-target the irq to the specified CPU and enable the specified MMR located
  * on the specified blade to allow the sending of MSIs to the specified CPU.
  */
-static int
-arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
-                      unsigned long mmr_offset, int limit)
+static void uv_domain_activate(struct irq_domain *domain,
+                              struct irq_data *irq_data)
 {
-       const struct cpumask *eligible_cpu = cpumask_of(cpu);
-       struct irq_cfg *cfg = irq_cfg(irq);
-       unsigned long mmr_value;
-       struct uv_IO_APIC_route_entry *entry;
-       int mmr_pnode, err;
-       unsigned int dest;
-
-       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
-                       sizeof(unsigned long));
-
-       err = assign_irq_vector(irq, cfg, eligible_cpu);
-       if (err != 0)
-               return err;
-
-       err = apic->cpu_mask_to_apicid_and(eligible_cpu, eligible_cpu, &dest);
-       if (err != 0)
-               return err;
-
-       if (limit == UV_AFFINITY_CPU)
-               irq_set_status_flags(irq, IRQ_NO_BALANCING);
-       else
-               irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-
-       irq_set_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
-                                     irq_name);
-
-       mmr_value = 0;
-       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-       entry->vector           = cfg->vector;
-       entry->delivery_mode    = apic->irq_delivery_mode;
-       entry->dest_mode        = apic->irq_dest_mode;
-       entry->polarity         = 0;
-       entry->trigger          = 0;
-       entry->mask             = 0;
-       entry->dest             = dest;
-
-       mmr_pnode = uv_blade_to_pnode(mmr_blade);
-       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
-
-       if (cfg->move_in_progress)
-               send_cleanup_vector(cfg);
-
-       return irq;
+       uv_program_mmr(irqd_cfg(irq_data), irq_data->chip_data);
 }
 
 /*
  * Disable the specified MMR located on the specified blade so that MSIs are
  * longer allowed to be sent.
  */
-static void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
+static void uv_domain_deactivate(struct irq_domain *domain,
+                                struct irq_data *irq_data)
 {
        unsigned long mmr_value;
        struct uv_IO_APIC_route_entry *entry;
 
-       BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
-                       sizeof(unsigned long));
-
        mmr_value = 0;
        entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
        entry->mask = 1;
-
-       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+       uv_program_mmr(irqd_cfg(irq_data), irq_data->chip_data);
 }
 
-static int
-uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
-                   bool force)
-{
-       struct irq_cfg *cfg = irqd_cfg(data);
-       unsigned int dest;
-       unsigned long mmr_value, mmr_offset;
-       struct uv_IO_APIC_route_entry *entry;
-       int mmr_pnode;
-
-       if (apic_set_affinity(data, mask, &dest))
-               return -1;
-
-       mmr_value = 0;
-       entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
-
-       entry->vector           = cfg->vector;
-       entry->delivery_mode    = apic->irq_delivery_mode;
-       entry->dest_mode        = apic->irq_dest_mode;
-       entry->polarity         = 0;
-       entry->trigger          = 0;
-       entry->mask             = 0;
-       entry->dest             = dest;
-
-       /* Get previously stored MMR and pnode of hub sourcing interrupts */
-       if (uv_irq_2_mmr_info(data->irq, &mmr_offset, &mmr_pnode))
-               return -1;
-
-       uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+static const struct irq_domain_ops uv_domain_ops = {
+       .alloc          = uv_domain_alloc,
+       .free           = uv_domain_free,
+       .activate       = uv_domain_activate,
+       .deactivate     = uv_domain_deactivate,
+};
 
-       if (cfg->move_in_progress)
-               send_cleanup_vector(cfg);
+static struct irq_domain *uv_get_irq_domain(void)
+{
+       static struct irq_domain *uv_domain;
+       static DEFINE_MUTEX(uv_lock);
+
+       mutex_lock(&uv_lock);
+       if (uv_domain == NULL) {
+               uv_domain = irq_domain_add_tree(NULL, &uv_domain_ops, NULL);
+               if (uv_domain)
+                       uv_domain->parent = x86_vector_domain;
+       }
+       mutex_unlock(&uv_lock);
 
-       return IRQ_SET_MASK_OK_NOCOPY;
+       return uv_domain;
 }
 
 /*
@@ -238,19 +180,21 @@ uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
 int uv_setup_irq(char *irq_name, int cpu, int mmr_blade,
                 unsigned long mmr_offset, int limit)
 {
-       int ret, irq = irq_alloc_hwirq(uv_blade_to_memory_nid(mmr_blade));
+       struct irq_alloc_info info;
+       struct irq_domain *domain = uv_get_irq_domain();
 
-       if (!irq)
-               return -EBUSY;
+       if (!domain)
+               return -ENOMEM;
 
-       ret = arch_enable_uv_irq(irq_name, irq, cpu, mmr_blade, mmr_offset,
-               limit);
-       if (ret == irq)
-               uv_set_irq_2_mmr_info(irq, mmr_offset, mmr_blade);
-       else
-               irq_free_hwirq(irq);
+       init_irq_alloc_info(&info, cpumask_of(cpu));
+       info.type = X86_IRQ_ALLOC_TYPE_UV;
+       info.uv_limit = limit;
+       info.uv_blade = mmr_blade;
+       info.uv_offset = mmr_offset;
+       info.uv_name = irq_name;
 
-       return ret;
+       return irq_domain_alloc_irqs(domain, 1,
+                                    uv_blade_to_memory_nid(mmr_blade), &info);
 }
 EXPORT_SYMBOL_GPL(uv_setup_irq);
 
@@ -263,26 +207,6 @@ EXPORT_SYMBOL_GPL(uv_setup_irq);
  */
 void uv_teardown_irq(unsigned int irq)
 {
-       struct uv_irq_2_mmr_pnode *e;
-       struct rb_node *n;
-       unsigned long irqflags;
-
-       spin_lock_irqsave(&uv_irq_lock, irqflags);
-       n = uv_irq_root.rb_node;
-       while (n) {
-               e = rb_entry(n, struct uv_irq_2_mmr_pnode, list);
-               if (e->irq == irq) {
-                       arch_disable_uv_irq(e->pnode, e->offset);
-                       rb_erase(n, &uv_irq_root);
-                       kfree(e);
-                       break;
-               }
-               if (irq < e->irq)
-                       n = n->rb_left;
-               else
-                       n = n->rb_right;
-       }
-       spin_unlock_irqrestore(&uv_irq_lock, irqflags);
-       irq_free_hwirq(irq);
+       irq_domain_free_irqs(irq, 1);
 }
 EXPORT_SYMBOL_GPL(uv_teardown_irq);
index e43d48956dea239fe6816bdb23f0174754c623ee..cbe8c1f28a95d710143e35f74f6e902eb4037ea9 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/irq.h>
 #include <linux/msi.h>
 #include <linux/dma-contiguous.h>
+#include <linux/irqdomain.h>
 #include <asm/irq_remapping.h>
 #include <asm/io_apic.h>
 #include <asm/apic.h>
@@ -3851,6 +3852,21 @@ union irte {
        } fields;
 };
 
+struct irq_2_irte {
+       u16 devid; /* Device ID for IRTE table */
+       u16 index; /* Index into IRTE table*/
+};
+
+struct amd_ir_data {
+       struct irq_2_irte                       irq_2_irte;
+       union irte                              irte_entry;
+       union {
+               struct msi_msg                  msi_entry;
+       };
+};
+
+static struct irq_chip amd_ir_chip;
+
 #define DTE_IRQ_PHYS_ADDR_MASK (((1ULL << 45)-1) << 6)
 #define DTE_IRQ_REMAP_INTCTL    (2ULL << 60)
 #define DTE_IRQ_TABLE_LEN       (8ULL << 1)
@@ -3944,7 +3960,7 @@ out_unlock:
        return table;
 }
 
-static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
+static int alloc_irq_index(u16 devid, int count)
 {
        struct irq_remap_table *table;
        unsigned long flags;
@@ -3966,18 +3982,10 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
                        c = 0;
 
                if (c == count) {
-                       struct irq_2_irte *irte_info;
-
                        for (; c != 0; --c)
                                table->table[index - c + 1] = IRTE_ALLOCATED;
 
                        index -= count - 1;
-
-                       cfg->remapped         = 1;
-                       irte_info             = &cfg->irq_2_irte;
-                       irte_info->devid      = devid;
-                       irte_info->index      = index;
-
                        goto out;
                }
        }
@@ -3990,22 +3998,6 @@ out:
        return index;
 }
 
-static int get_irte(u16 devid, int index, union irte *irte)
-{
-       struct irq_remap_table *table;
-       unsigned long flags;
-
-       table = get_irq_table(devid, false);
-       if (!table)
-               return -ENOMEM;
-
-       spin_lock_irqsave(&table->lock, flags);
-       irte->val = table->table[index];
-       spin_unlock_irqrestore(&table->lock, flags);
-
-       return 0;
-}
-
 static int modify_irte(u16 devid, int index, union irte irte)
 {
        struct irq_remap_table *table;
@@ -4052,243 +4044,316 @@ static void free_irte(u16 devid, int index)
        iommu_completion_wait(iommu);
 }
 
-static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
-                             unsigned int destination, int vector,
-                             struct io_apic_irq_attr *attr)
+static int get_devid(struct irq_alloc_info *info)
 {
-       struct irq_remap_table *table;
-       struct irq_2_irte *irte_info;
-       struct irq_cfg *cfg;
-       union irte irte;
-       int ioapic_id;
-       int index;
-       int devid;
-       int ret;
-
-       cfg = irq_cfg(irq);
-       if (!cfg)
-               return -EINVAL;
-
-       irte_info = &cfg->irq_2_irte;
-       ioapic_id = mpc_ioapic_id(attr->ioapic);
-       devid     = get_ioapic_devid(ioapic_id);
-
-       if (devid < 0)
-               return devid;
-
-       table = get_irq_table(devid, true);
-       if (table == NULL)
-               return -ENOMEM;
-
-       index = attr->ioapic_pin;
+       int devid = -1;
 
-       /* Setup IRQ remapping info */
-       cfg->remapped         = 1;
-       irte_info->devid      = devid;
-       irte_info->index      = index;
+       switch (info->type) {
+       case X86_IRQ_ALLOC_TYPE_IOAPIC:
+               devid     = get_ioapic_devid(info->ioapic_id);
+               break;
+       case X86_IRQ_ALLOC_TYPE_HPET:
+               devid     = get_hpet_devid(info->hpet_id);
+               break;
+       case X86_IRQ_ALLOC_TYPE_MSI:
+       case X86_IRQ_ALLOC_TYPE_MSIX:
+               devid = get_device_id(&info->msi_dev->dev);
+               break;
+       default:
+               BUG_ON(1);
+               break;
+       }
 
-       /* Setup IRTE for IOMMU */
-       irte.val                = 0;
-       irte.fields.vector      = vector;
-       irte.fields.int_type    = apic->irq_delivery_mode;
-       irte.fields.destination = destination;
-       irte.fields.dm          = apic->irq_dest_mode;
-       irte.fields.valid       = 1;
-
-       ret = modify_irte(devid, index, irte);
-       if (ret)
-               return ret;
+       return devid;
+}
 
-       /* Setup IOAPIC entry */
-       memset(entry, 0, sizeof(*entry));
+static struct irq_domain *get_ir_irq_domain(struct irq_alloc_info *info)
+{
+       struct amd_iommu *iommu;
+       int devid;
 
-       entry->vector        = index;
-       entry->mask          = 0;
-       entry->trigger       = attr->trigger;
-       entry->polarity      = attr->polarity;
+       if (!info)
+               return NULL;
 
-       /*
-        * Mask level triggered irqs.
-        */
-       if (attr->trigger)
-               entry->mask = 1;
+       devid = get_devid(info);
+       if (devid >= 0) {
+               iommu = amd_iommu_rlookup_table[devid];
+               if (iommu)
+                       return iommu->ir_domain;
+       }
 
-       return 0;
+       return NULL;
 }
 
-static int set_affinity(struct irq_data *data, const struct cpumask *mask,
-                       bool force)
+static struct irq_domain *get_irq_domain(struct irq_alloc_info *info)
 {
-       struct irq_2_irte *irte_info;
-       unsigned int dest, irq;
-       struct irq_cfg *cfg;
-       union irte irte;
-       int err;
-
-       if (!config_enabled(CONFIG_SMP))
-               return -1;
-
-       cfg       = irqd_cfg(data);
-       irq       = data->irq;
-       irte_info = &cfg->irq_2_irte;
+       struct amd_iommu *iommu;
+       int devid;
 
-       if (!cpumask_intersects(mask, cpu_online_mask))
-               return -EINVAL;
+       if (!info)
+               return NULL;
 
-       if (get_irte(irte_info->devid, irte_info->index, &irte))
-               return -EBUSY;
+       switch (info->type) {
+       case X86_IRQ_ALLOC_TYPE_MSI:
+       case X86_IRQ_ALLOC_TYPE_MSIX:
+               devid = get_device_id(&info->msi_dev->dev);
+               if (devid >= 0) {
+                       iommu = amd_iommu_rlookup_table[devid];
+                       if (iommu)
+                               return iommu->msi_domain;
+               }
+               break;
+       default:
+               break;
+       }
 
-       if (assign_irq_vector(irq, cfg, mask))
-               return -EBUSY;
+       return NULL;
+}
 
-       err = apic->cpu_mask_to_apicid_and(cfg->domain, mask, &dest);
-       if (err) {
-               if (assign_irq_vector(irq, cfg, data->affinity))
-                       pr_err("AMD-Vi: Failed to recover vector for irq %d\n", irq);
-               return err;
-       }
+struct irq_remap_ops amd_iommu_irq_ops = {
+       .prepare                = amd_iommu_prepare,
+       .enable                 = amd_iommu_enable,
+       .disable                = amd_iommu_disable,
+       .reenable               = amd_iommu_reenable,
+       .enable_faulting        = amd_iommu_enable_faulting,
+       .get_ir_irq_domain      = get_ir_irq_domain,
+       .get_irq_domain         = get_irq_domain,
+};
 
-       irte.fields.vector      = cfg->vector;
-       irte.fields.destination = dest;
+static void irq_remapping_prepare_irte(struct amd_ir_data *data,
+                                      struct irq_cfg *irq_cfg,
+                                      struct irq_alloc_info *info,
+                                      int devid, int index, int sub_handle)
+{
+       struct irq_2_irte *irte_info = &data->irq_2_irte;
+       struct msi_msg *msg = &data->msi_entry;
+       union irte *irte = &data->irte_entry;
+       struct IO_APIC_route_entry *entry;
 
-       modify_irte(irte_info->devid, irte_info->index, irte);
+       data->irq_2_irte.devid = devid;
+       data->irq_2_irte.index = index + sub_handle;
 
-       if (cfg->move_in_progress)
-               send_cleanup_vector(cfg);
+       /* Setup IRTE for IOMMU */
+       irte->val = 0;
+       irte->fields.vector      = irq_cfg->vector;
+       irte->fields.int_type    = apic->irq_delivery_mode;
+       irte->fields.destination = irq_cfg->dest_apicid;
+       irte->fields.dm          = apic->irq_dest_mode;
+       irte->fields.valid       = 1;
+
+       switch (info->type) {
+       case X86_IRQ_ALLOC_TYPE_IOAPIC:
+               /* Setup IOAPIC entry */
+               entry = info->ioapic_entry;
+               info->ioapic_entry = NULL;
+               memset(entry, 0, sizeof(*entry));
+               entry->vector        = index;
+               entry->mask          = 0;
+               entry->trigger       = info->ioapic_trigger;
+               entry->polarity      = info->ioapic_polarity;
+               /* Mask level triggered irqs. */
+               if (info->ioapic_trigger)
+                       entry->mask = 1;
+               break;
 
-       cpumask_copy(data->affinity, mask);
+       case X86_IRQ_ALLOC_TYPE_HPET:
+       case X86_IRQ_ALLOC_TYPE_MSI:
+       case X86_IRQ_ALLOC_TYPE_MSIX:
+               msg->address_hi = MSI_ADDR_BASE_HI;
+               msg->address_lo = MSI_ADDR_BASE_LO;
+               msg->data = irte_info->index;
+               break;
 
-       return 0;
+       default:
+               BUG_ON(1);
+               break;
+       }
 }
 
-static int free_irq(int irq)
+static int irq_remapping_alloc(struct irq_domain *domain, unsigned int virq,
+                              unsigned int nr_irqs, void *arg)
 {
-       struct irq_2_irte *irte_info;
+       struct irq_alloc_info *info = arg;
+       struct irq_data *irq_data;
+       struct amd_ir_data *data;
        struct irq_cfg *cfg;
+       int i, ret, devid;
+       int index = -1;
 
-       cfg = irq_cfg(irq);
-       if (!cfg)
+       if (!info)
+               return -EINVAL;
+       if (nr_irqs > 1 && info->type != X86_IRQ_ALLOC_TYPE_MSI &&
+           info->type != X86_IRQ_ALLOC_TYPE_MSIX)
                return -EINVAL;
 
-       irte_info = &cfg->irq_2_irte;
-
-       free_irte(irte_info->devid, irte_info->index);
+       /*
+        * 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;
 
-       return 0;
-}
+       devid = get_devid(info);
+       if (devid < 0)
+               return -EINVAL;
 
-static void compose_msi_msg(struct pci_dev *pdev,
-                           unsigned int irq, unsigned int dest,
-                           struct msi_msg *msg, u8 hpet_id)
-{
-       struct irq_2_irte *irte_info;
-       struct irq_cfg *cfg;
-       union irte irte;
+       ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+       if (ret < 0)
+               return ret;
 
-       cfg = irq_cfg(irq);
-       if (!cfg)
-               return;
+       ret = -ENOMEM;
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               goto out_free_parent;
 
-       irte_info = &cfg->irq_2_irte;
+       if (info->type == X86_IRQ_ALLOC_TYPE_IOAPIC) {
+               if (get_irq_table(devid, true))
+                       index = info->ioapic_pin;
+               else
+                       ret = -ENOMEM;
+       } else {
+               index = alloc_irq_index(devid, nr_irqs);
+       }
+       if (index < 0) {
+               pr_warn("Failed to allocate IRTE\n");
+               kfree(data);
+               goto out_free_parent;
+       }
 
-       irte.val                = 0;
-       irte.fields.vector      = cfg->vector;
-       irte.fields.int_type    = apic->irq_delivery_mode;
-       irte.fields.destination = dest;
-       irte.fields.dm          = apic->irq_dest_mode;
-       irte.fields.valid       = 1;
+       for (i = 0; i < nr_irqs; i++) {
+               irq_data = irq_domain_get_irq_data(domain, virq + i);
+               cfg = irqd_cfg(irq_data);
+               if (!irq_data || !cfg) {
+                       ret = -EINVAL;
+                       goto out_free_data;
+               }
 
-       modify_irte(irte_info->devid, irte_info->index, irte);
+               if (i > 0) {
+                       data = kzalloc(sizeof(*data), GFP_KERNEL);
+                       if (!data)
+                               goto out_free_data;
+               }
+               irq_data->hwirq = (devid << 16) + i;
+               irq_data->chip_data = data;
+               irq_data->chip = &amd_ir_chip;
+               irq_remapping_prepare_irte(data, cfg, info, devid, index, i);
+               irq_set_status_flags(virq + i, IRQ_MOVE_PCNTXT);
+       }
+       return 0;
 
-       msg->address_hi = MSI_ADDR_BASE_HI;
-       msg->address_lo = MSI_ADDR_BASE_LO;
-       msg->data       = irte_info->index;
+out_free_data:
+       for (i--; i >= 0; i--) {
+               irq_data = irq_domain_get_irq_data(domain, virq + i);
+               if (irq_data)
+                       kfree(irq_data->chip_data);
+       }
+       for (i = 0; i < nr_irqs; i++)
+               free_irte(devid, index + i);
+out_free_parent:
+       irq_domain_free_irqs_common(domain, virq, nr_irqs);
+       return ret;
 }
 
-static int msi_alloc_irq(struct pci_dev *pdev, int irq, int nvec)
+static void irq_remapping_free(struct irq_domain *domain, unsigned int virq,
+                              unsigned int nr_irqs)
 {
-       struct irq_cfg *cfg;
-       int index;
-       u16 devid;
-
-       if (!pdev)
-               return -EINVAL;
+       struct irq_2_irte *irte_info;
+       struct irq_data *irq_data;
+       struct amd_ir_data *data;
+       int i;
 
-       cfg = irq_cfg(irq);
-       if (!cfg)
-               return -EINVAL;
+       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;
+                       irte_info = &data->irq_2_irte;
+                       free_irte(irte_info->devid, irte_info->index);
+                       kfree(data);
+               }
+       }
+       irq_domain_free_irqs_common(domain, virq, nr_irqs);
+}
 
-       devid = get_device_id(&pdev->dev);
-       index = alloc_irq_index(cfg, devid, nvec);
+static void irq_remapping_activate(struct irq_domain *domain,
+                                  struct irq_data *irq_data)
+{
+       struct amd_ir_data *data = irq_data->chip_data;
+       struct irq_2_irte *irte_info = &data->irq_2_irte;
 
-       return index < 0 ? MAX_IRQS_PER_TABLE : index;
+       modify_irte(irte_info->devid, irte_info->index, data->irte_entry);
 }
 
-static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
-                        int index, int offset)
+static void irq_remapping_deactivate(struct irq_domain *domain,
+                                    struct irq_data *irq_data)
 {
-       struct irq_2_irte *irte_info;
-       struct irq_cfg *cfg;
-       u16 devid;
+       struct amd_ir_data *data = irq_data->chip_data;
+       struct irq_2_irte *irte_info = &data->irq_2_irte;
+       union irte entry;
 
-       if (!pdev)
-               return -EINVAL;
+       entry.val = 0;
+       modify_irte(irte_info->devid, irte_info->index, data->irte_entry);
+}
 
-       cfg = irq_cfg(irq);
-       if (!cfg)
-               return -EINVAL;
+static struct irq_domain_ops amd_ir_domain_ops = {
+       .alloc = irq_remapping_alloc,
+       .free = irq_remapping_free,
+       .activate = irq_remapping_activate,
+       .deactivate = irq_remapping_deactivate,
+};
 
-       if (index >= MAX_IRQS_PER_TABLE)
-               return 0;
+static int amd_ir_set_affinity(struct irq_data *data,
+                              const struct cpumask *mask, bool force)
+{
+       struct amd_ir_data *ir_data = data->chip_data;
+       struct irq_2_irte *irte_info = &ir_data->irq_2_irte;
+       struct irq_cfg *cfg = irqd_cfg(data);
+       struct irq_data *parent = data->parent_data;
+       int ret;
 
-       devid           = get_device_id(&pdev->dev);
-       irte_info       = &cfg->irq_2_irte;
+       ret = parent->chip->irq_set_affinity(parent, mask, force);
+       if (ret < 0 || ret == IRQ_SET_MASK_OK_DONE)
+               return ret;
 
-       cfg->remapped         = 1;
-       irte_info->devid      = devid;
-       irte_info->index      = index + offset;
+       /*
+        * Atomically updates the IRTE with the new destination, vector
+        * and flushes the interrupt entry cache.
+        */
+       ir_data->irte_entry.fields.vector = cfg->vector;
+       ir_data->irte_entry.fields.destination = cfg->dest_apicid;
+       modify_irte(irte_info->devid, irte_info->index, ir_data->irte_entry);
 
-       return 0;
+       /*
+        * After this point, all the interrupts will start arriving
+        * at the new destination. So, time to cleanup the previous
+        * vector allocation.
+        */
+       send_cleanup_vector(cfg);
+
+       return IRQ_SET_MASK_OK_DONE;
 }
 
-static int alloc_hpet_msi(unsigned int irq, unsigned int id)
+static void ir_compose_msi_msg(struct irq_data *irq_data, struct msi_msg *msg)
 {
-       struct irq_2_irte *irte_info;
-       struct irq_cfg *cfg;
-       int index, devid;
+       struct amd_ir_data *ir_data = irq_data->chip_data;
 
-       cfg = irq_cfg(irq);
-       if (!cfg)
-               return -EINVAL;
+       *msg = ir_data->msi_entry;
+}
 
-       irte_info = &cfg->irq_2_irte;
-       devid     = get_hpet_devid(id);
-       if (devid < 0)
-               return devid;
+static struct irq_chip amd_ir_chip = {
+       .irq_ack = ir_ack_apic_edge,
+       .irq_set_affinity = amd_ir_set_affinity,
+       .irq_compose_msi_msg = ir_compose_msi_msg,
+};
 
-       index = alloc_irq_index(cfg, devid, 1);
-       if (index < 0)
-               return index;
+int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
+{
+       iommu->ir_domain = irq_domain_add_tree(NULL, &amd_ir_domain_ops, iommu);
+       if (!iommu->ir_domain)
+               return -ENOMEM;
 
-       cfg->remapped         = 1;
-       irte_info->devid      = devid;
-       irte_info->index      = index;
+       iommu->ir_domain->parent = arch_get_ir_parent_domain();
+       iommu->msi_domain = arch_create_msi_irq_domain(iommu->ir_domain);
 
        return 0;
 }
-
-struct irq_remap_ops amd_iommu_irq_ops = {
-       .prepare                = amd_iommu_prepare,
-       .enable                 = amd_iommu_enable,
-       .disable                = amd_iommu_disable,
-       .reenable               = amd_iommu_reenable,
-       .enable_faulting        = amd_iommu_enable_faulting,
-       .setup_ioapic_entry     = setup_ioapic_entry,
-       .set_affinity           = set_affinity,
-       .free_irq               = free_irq,
-       .compose_msi_msg        = compose_msi_msg,
-       .msi_alloc_irq          = msi_alloc_irq,
-       .msi_setup_irq          = msi_setup_irq,
-       .alloc_hpet_msi         = alloc_hpet_msi,
-};
 #endif
index 450ef5001a65ab3bea19e1a9648324eea9951ede..c17df04d7a7fff55763b8eb3a0781b1f8206a683 100644 (file)
@@ -1124,6 +1124,10 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
        if (ret)
                return ret;
 
+       ret = amd_iommu_create_irq_domain(iommu);
+       if (ret)
+               return ret;
+
        /*
         * Make sure IOMMU is not considered to translate itself. The IVRS
         * table tells us so, but this is a lie!
index 72b0fd455e2444cc12a9ee2b678c6b0456c80503..0a21142d3639d0741052be510a84df7f3fe2ef5a 100644 (file)
@@ -62,6 +62,15 @@ extern u8 amd_iommu_pc_get_max_counters(u16 devid);
 extern int amd_iommu_pc_get_set_reg_val(u16 devid, u8 bank, u8 cntr, u8 fxn,
                                    u64 *value, bool is_write);
 
+#ifdef CONFIG_IRQ_REMAP
+extern int amd_iommu_create_irq_domain(struct amd_iommu *iommu);
+#else
+static inline int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
+{
+       return 0;
+}
+#endif
+
 #define PPR_SUCCESS                    0x0
 #define PPR_INVALID                    0x1
 #define PPR_FAILURE                    0xf
index 05030e523771a6ee3befbe890ed45b47a86f8f7f..6533e874c9d77972f0523cfca326830d02e70dd7 100644 (file)
@@ -398,6 +398,7 @@ struct amd_iommu_fault {
 
 
 struct iommu_domain;
+struct irq_domain;
 
 /*
  * This structure contains generic data for  IOMMU protection domains
@@ -579,6 +580,10 @@ struct amd_iommu {
        /* The maximum PC banks and counters/bank (PCSup=1) */
        u8 max_banks;
        u8 max_counters;
+#ifdef CONFIG_IRQ_REMAP
+       struct irq_domain *ir_domain;
+       struct irq_domain *msi_domain;
+#endif
 };
 
 struct devid_map {
index 9847613085e157976707e0d1aa0cc87c3e8b3c68..536f2d8ea41abe502a88628ffc54cc61db6a6ff7 100644 (file)
@@ -1087,8 +1087,8 @@ static void free_iommu(struct intel_iommu *iommu)
 
        if (iommu->irq) {
                free_irq(iommu->irq, iommu);
-               irq_set_handler_data(iommu->irq, NULL);
                dmar_free_hwirq(iommu->irq);
+               iommu->irq = 0;
        }
 
        if (iommu->qi) {
@@ -1642,23 +1642,14 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
        if (iommu->irq)
                return 0;
 
-       irq = dmar_alloc_hwirq();
-       if (irq <= 0) {
+       irq = dmar_alloc_hwirq(iommu->seq_id, iommu->node, iommu);
+       if (irq > 0) {
+               iommu->irq = irq;
+       } else {
                pr_err("IOMMU: no free vectors\n");
                return -EINVAL;
        }
 
-       irq_set_handler_data(irq, iommu);
-       iommu->irq = irq;
-
-       ret = arch_setup_dmar_msi(irq);
-       if (ret) {
-               irq_set_handler_data(irq, NULL);
-               iommu->irq = 0;
-               dmar_free_hwirq(irq);
-               return ret;
-       }
-
        ret = request_irq(irq, dmar_fault, IRQF_NO_THREAD, iommu->name, iommu);
        if (ret)
                pr_err("IOMMU: can't request irq\n");
index 5709ae9c3e771d2f82a1bda2a23d500d8f4faffe..8fad71cc27e79ca2d29ac6e80698294a2d4c3d52 100644 (file)
@@ -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>
@@ -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)
 
@@ -50,43 +66,14 @@ static struct hpet_scope ir_hpet[MAX_HPET_TBS];
  * 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;
@@ -113,7 +100,6 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        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;
@@ -135,47 +121,9 @@ static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
        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;
@@ -242,7 +190,7 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
                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);
@@ -257,29 +205,6 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
        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
  */
@@ -488,7 +413,6 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 
        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);
@@ -502,11 +426,23 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
                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:
@@ -517,6 +453,14 @@ 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);
@@ -702,13 +646,6 @@ static int __init intel_enable_irq_remapping(void)
 
        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;
@@ -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));
 
@@ -966,76 +902,63 @@ static void prepare_irte(struct irte *irte, int vector,
        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.
  *
@@ -1051,170 +974,242 @@ static int intel_setup_ioapic_entry(int irq,
  * 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 390079ee13507747388f635bf67c1c44dfb6c068..fc78b0d41f71c2de813d70ce989c40714d470401 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/msi.h>
 #include <linux/irq.h>
 #include <linux/pci.h>
+#include <linux/irqdomain.h>
 
 #include <asm/hw_irq.h>
 #include <asm/irq_remapping.h>
@@ -24,18 +25,6 @@ int no_x2apic_optout;
 static int disable_irq_remap;
 static struct irq_remap_ops *remap_ops;
 
-static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
-static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
-                                 int index, int sub_handle);
-static int set_remapped_irq_affinity(struct irq_data *data,
-                                    const struct cpumask *mask,
-                                    bool force);
-
-static bool irq_remapped(struct irq_cfg *cfg)
-{
-       return (cfg->remapped == 1);
-}
-
 static void irq_remapping_disable_io_apic(void)
 {
        /*
@@ -49,117 +38,9 @@ static void irq_remapping_disable_io_apic(void)
                disconnect_bsp_APIC(0);
 }
 
-static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
-{
-       int ret, sub_handle, nvec_pow2, index = 0;
-       unsigned int irq;
-       struct msi_desc *msidesc;
-
-       msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
-
-       irq = irq_alloc_hwirqs(nvec, dev_to_node(&dev->dev));
-       if (irq == 0)
-               return -ENOSPC;
-
-       nvec_pow2 = __roundup_pow_of_two(nvec);
-       for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
-               if (!sub_handle) {
-                       index = msi_alloc_remapped_irq(dev, irq, nvec_pow2);
-                       if (index < 0) {
-                               ret = index;
-                               goto error;
-                       }
-               } else {
-                       ret = msi_setup_remapped_irq(dev, irq + sub_handle,
-                                                    index, sub_handle);
-                       if (ret < 0)
-                               goto error;
-               }
-               ret = setup_msi_irq(dev, msidesc, irq, sub_handle);
-               if (ret < 0)
-                       goto error;
-       }
-       return 0;
-
-error:
-       irq_free_hwirqs(irq, nvec);
-
-       /*
-        * Restore altered MSI descriptor fields and prevent just destroyed
-        * IRQs from tearing down again in default_teardown_msi_irqs()
-        */
-       msidesc->irq = 0;
-
-       return ret;
-}
-
-static int do_setup_msix_irqs(struct pci_dev *dev, int nvec)
-{
-       int node, ret, sub_handle, index = 0;
-       struct msi_desc *msidesc;
-       unsigned int irq;
-
-       node            = dev_to_node(&dev->dev);
-       sub_handle      = 0;
-
-       list_for_each_entry(msidesc, &dev->msi_list, list) {
-
-               irq = irq_alloc_hwirq(node);
-               if (irq == 0)
-                       return -1;
-
-               if (sub_handle == 0)
-                       ret = index = msi_alloc_remapped_irq(dev, irq, nvec);
-               else
-                       ret = msi_setup_remapped_irq(dev, irq, index, sub_handle);
-
-               if (ret < 0)
-                       goto error;
-
-               ret = setup_msi_irq(dev, msidesc, irq, 0);
-               if (ret < 0)
-                       goto error;
-
-               sub_handle += 1;
-               irq        += 1;
-       }
-
-       return 0;
-
-error:
-       irq_free_hwirq(irq);
-       return ret;
-}
-
-static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
-                                       int nvec, int type)
-{
-       if (type == PCI_CAP_ID_MSI)
-               return do_setup_msi_irqs(dev, nvec);
-       else
-               return do_setup_msix_irqs(dev, nvec);
-}
-
-static void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
-{
-       /*
-        * Intr-remapping uses pin number as the virtual vector
-        * in the RTE. Actual vector is programmed in
-        * intr-remapping table entry. Hence for the io-apic
-        * EOI we use the pin number.
-        */
-       io_apic_eoi(apic, pin);
-}
-
 static void __init irq_remapping_modify_x86_ops(void)
 {
        x86_io_apic_ops.disable         = irq_remapping_disable_io_apic;
-       x86_io_apic_ops.set_affinity    = set_remapped_irq_affinity;
-       x86_io_apic_ops.setup_entry     = setup_ioapic_remapped_entry;
-       x86_io_apic_ops.eoi_ioapic_pin  = eoi_ioapic_pin_remapped;
-       x86_msi.setup_msi_irqs          = irq_remapping_setup_msi_irqs;
-       x86_msi.setup_hpet_msi          = setup_hpet_msi_remapped;
-       x86_msi.compose_msi_msg         = compose_remapped_msi_msg;
 }
 
 static __init int setup_nointremap(char *str)
@@ -254,113 +135,48 @@ int __init irq_remap_enable_fault_handling(void)
        return remap_ops->enable_faulting();
 }
 
-int setup_ioapic_remapped_entry(int irq,
-                               struct IO_APIC_route_entry *entry,
-                               unsigned int destination, int vector,
-                               struct io_apic_irq_attr *attr)
-{
-       if (!remap_ops->setup_ioapic_entry)
-               return -ENODEV;
-
-       return remap_ops->setup_ioapic_entry(irq, entry, destination,
-                                            vector, attr);
-}
-
-static int set_remapped_irq_affinity(struct irq_data *data,
-                                    const struct cpumask *mask, bool force)
-{
-       if (!config_enabled(CONFIG_SMP) || !remap_ops->set_affinity)
-               return 0;
-
-       return remap_ops->set_affinity(data, mask, force);
-}
-
-void free_remapped_irq(int irq)
-{
-       struct irq_cfg *cfg = irq_cfg(irq);
-
-       if (irq_remapped(cfg) && remap_ops->free_irq)
-               remap_ops->free_irq(irq);
-}
-
-void compose_remapped_msi_msg(struct pci_dev *pdev,
-                             unsigned int irq, unsigned int dest,
-                             struct msi_msg *msg, u8 hpet_id)
-{
-       struct irq_cfg *cfg = irq_cfg(irq);
-
-       if (!irq_remapped(cfg))
-               native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
-       else if (remap_ops->compose_msi_msg)
-               remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
-}
-
-static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
-{
-       if (!remap_ops->msi_alloc_irq)
-               return -ENODEV;
-
-       return remap_ops->msi_alloc_irq(pdev, irq, nvec);
-}
-
-static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
-                                 int index, int sub_handle)
-{
-       if (!remap_ops->msi_setup_irq)
-               return -ENODEV;
-
-       return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
-}
-
-int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
-{
-       int ret;
-
-       if (!remap_ops->alloc_hpet_msi)
-               return -ENODEV;
-
-       ret = remap_ops->alloc_hpet_msi(irq, id);
-       if (ret)
-               return -EINVAL;
-
-       return default_setup_hpet_msi(irq, id);
-}
-
 void panic_if_irq_remap(const char *msg)
 {
        if (irq_remapping_enabled)
                panic(msg);
 }
 
-static void ir_ack_apic_edge(struct irq_data *data)
+void ir_ack_apic_edge(struct irq_data *data)
 {
        ack_APIC_irq();
 }
 
-static void ir_ack_apic_level(struct irq_data *data)
+/**
+ * irq_remapping_get_ir_irq_domain - Get the irqdomain associated with the IOMMU
+ *                                  device serving request @info
+ * @info: interrupt allocation information, used to identify the IOMMU device
+ *
+ * It's used to get parent irqdomain for HPET and IOAPIC irqdomains.
+ * Returns pointer to IRQ domain, or NULL on failure.
+ */
+struct irq_domain *
+irq_remapping_get_ir_irq_domain(struct irq_alloc_info *info)
 {
-       ack_APIC_irq();
-       eoi_ioapic_irq(data->irq, irqd_cfg(data));
-}
+       if (!remap_ops || !remap_ops->get_ir_irq_domain)
+               return NULL;
 
-static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
-{
-       seq_printf(p, " IR-%s", data->chip->name);
+       return remap_ops->get_ir_irq_domain(info);
 }
 
-void irq_remap_modify_chip_defaults(struct irq_chip *chip)
+/**
+ * irq_remapping_get_irq_domain - Get the irqdomain serving the request @info
+ * @info: interrupt allocation information, used to identify the IOMMU device
+ *
+ * There will be one PCI MSI/MSIX irqdomain associated with each interrupt
+ * remapping device, so this interface is used to retrieve the PCI MSI/MSIX
+ * irqdomain serving request @info.
+ * Returns pointer to IRQ domain, or NULL on failure.
+ */
+struct irq_domain *
+irq_remapping_get_irq_domain(struct irq_alloc_info *info)
 {
-       chip->irq_print_chip = ir_print_prefix;
-       chip->irq_ack = ir_ack_apic_edge;
-       chip->irq_eoi = ir_ack_apic_level;
-       chip->irq_set_affinity = x86_io_apic_ops.set_affinity;
-}
+       if (!remap_ops || !remap_ops->get_irq_domain)
+               return NULL;
 
-bool setup_remapped_irq(int irq, struct irq_cfg *cfg, struct irq_chip *chip)
-{
-       if (!irq_remapped(cfg))
-               return false;
-       irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-       irq_remap_modify_chip_defaults(chip);
-       return true;
+       return remap_ops->get_irq_domain(info);
 }
index 7c70cc29ffe6b4d5341587465de8cf3c643a8956..91d5a119956aae96d80dcaaff6c60ada56327ddc 100644 (file)
 
 #ifdef CONFIG_IRQ_REMAP
 
-struct IO_APIC_route_entry;
-struct io_apic_irq_attr;
 struct irq_data;
-struct cpumask;
-struct pci_dev;
 struct msi_msg;
+struct irq_domain;
+struct irq_alloc_info;
 
 extern int irq_remap_broken;
 extern int disable_sourceid_checking;
@@ -52,36 +50,18 @@ struct irq_remap_ops {
        /* Enable fault handling */
        int  (*enable_faulting)(void);
 
-       /* IO-APIC setup routine */
-       int (*setup_ioapic_entry)(int irq, struct IO_APIC_route_entry *,
-                                 unsigned int, int,
-                                 struct io_apic_irq_attr *);
+       /* Get the irqdomain associated the IOMMU device */
+       struct irq_domain *(*get_ir_irq_domain)(struct irq_alloc_info *);
 
-       /* Set the CPU affinity of a remapped interrupt */
-       int (*set_affinity)(struct irq_data *data, const struct cpumask *mask,
-                           bool force);
-
-       /* Free an IRQ */
-       int (*free_irq)(int);
-
-       /* Create MSI msg to use for interrupt remapping */
-       void (*compose_msi_msg)(struct pci_dev *,
-                               unsigned int, unsigned int,
-                               struct msi_msg *, u8);
-
-       /* Allocate remapping resources for MSI */
-       int (*msi_alloc_irq)(struct pci_dev *, int, int);
-
-       /* Setup the remapped MSI irq */
-       int (*msi_setup_irq)(struct pci_dev *, unsigned int, int, int);
-
-       /* Setup interrupt remapping for an HPET MSI */
-       int (*alloc_hpet_msi)(unsigned int, unsigned int);
+       /* Get the MSI irqdomain associated with the IOMMU device */
+       struct irq_domain *(*get_irq_domain)(struct irq_alloc_info *);
 };
 
 extern struct irq_remap_ops intel_irq_remap_ops;
 extern struct irq_remap_ops amd_iommu_irq_ops;
 
+extern void ir_ack_apic_edge(struct irq_data *data);
+
 #else  /* CONFIG_IRQ_REMAP */
 
 #define irq_remapping_enabled 0
index a94dd2c4183a0ddc7ac118b1cfc41a7014d2fc4c..7eb4109a3df4eb6941f6c4c8ee435e7bb98f7747 100644 (file)
  */
 static DEFINE_SPINLOCK(ht_irq_lock);
 
-struct ht_irq_cfg {
-       struct pci_dev *dev;
-        /* Update callback used to cope with buggy hardware */
-       ht_irq_update_t *update;
-       unsigned pos;
-       unsigned idx;
-       struct ht_irq_msg msg;
-};
-
-
 void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
 {
        struct ht_irq_cfg *cfg = irq_get_handler_data(irq);
        unsigned long flags;
+
        spin_lock_irqsave(&ht_irq_lock, flags);
        if (cfg->msg.address_lo != msg->address_lo) {
                pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
@@ -55,6 +46,7 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
 void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
 {
        struct ht_irq_cfg *cfg = irq_get_handler_data(irq);
+
        *msg = cfg->msg;
 }
 
@@ -86,7 +78,6 @@ void unmask_ht_irq(struct irq_data *data)
  */
 int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
 {
-       struct ht_irq_cfg *cfg;
        int max_irq, pos, irq;
        unsigned long flags;
        u32 data;
@@ -105,29 +96,9 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
        if (idx > max_irq)
                return -EINVAL;
 
-       cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
-       if (!cfg)
-               return -ENOMEM;
-
-       cfg->dev = dev;
-       cfg->update = update;
-       cfg->pos = pos;
-       cfg->idx = 0x10 + (idx * 2);
-       /* Initialize msg to a value that will never match the first write. */
-       cfg->msg.address_lo = 0xffffffff;
-       cfg->msg.address_hi = 0xffffffff;
-
-       irq = irq_alloc_hwirq(dev_to_node(&dev->dev));
-       if (!irq) {
-               kfree(cfg);
-               return -EBUSY;
-       }
-       irq_set_handler_data(irq, cfg);
-
-       if (arch_setup_ht_irq(irq, dev) < 0) {
-               ht_destroy_irq(irq);
-               return -EBUSY;
-       }
+       irq = arch_setup_ht_irq(idx, pos, dev, update);
+       if (irq > 0)
+               dev_dbg(&dev->dev, "irq %d for HT\n", irq);
 
        return irq;
 }
@@ -158,13 +129,6 @@ EXPORT_SYMBOL(ht_create_irq);
  */
 void ht_destroy_irq(unsigned int irq)
 {
-       struct ht_irq_cfg *cfg;
-
-       cfg = irq_get_handler_data(irq);
-       irq_set_chip(irq, NULL);
-       irq_set_handler_data(irq, NULL);
-       irq_free_hwirq(irq);
-
-       kfree(cfg);
+       arch_teardown_ht_irq(irq);
 }
 EXPORT_SYMBOL(ht_destroy_irq);
index c6dc1dfd25d55ea9ac536634143eafcf196ce2c2..2890ad7cf7c63f0533811e21e67fea2c4cc25585 100644 (file)
@@ -819,13 +819,6 @@ static void quirk_amd_ioapic(struct pci_dev *dev)
        }
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_VIPER_7410,   quirk_amd_ioapic);
-
-static void quirk_ioapic_rmw(struct pci_dev *dev)
-{
-       if (dev->devfn == 0 && dev->bus->number == 0)
-               sis_apic_bug = 1;
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_ANY_ID,                     quirk_ioapic_rmw);
 #endif /* CONFIG_X86_IO_APIC */
 
 /*
index 30624954dec5a9250c142d2c57d000b991a91710..84737565c1fd959f8bcf8c52faca836db15fe9c2 100644 (file)
@@ -227,6 +227,7 @@ extern void dmar_msi_read(int irq, struct msi_msg *msg);
 extern void dmar_msi_write(int irq, struct msi_msg *msg);
 extern int dmar_set_interrupt(struct intel_iommu *iommu);
 extern irqreturn_t dmar_fault(int irq, void *dev_id);
-extern int arch_setup_dmar_msi(unsigned int irq);
+extern int dmar_alloc_hwirq(int id, int node, void *arg);
+extern void dmar_free_hwirq(int irq);
 
 #endif /* __DMAR_H__ */
index 70a1dbbf209350836f97743363fadfe4f6f95b36..d4a527e58434df73800eed55fbbc6750f5f2d5ee 100644 (file)
@@ -1,24 +1,38 @@
 #ifndef LINUX_HTIRQ_H
 #define LINUX_HTIRQ_H
 
+struct pci_dev;
+struct irq_data;
+
 struct ht_irq_msg {
        u32     address_lo;     /* low 32 bits of the ht irq message */
        u32     address_hi;     /* high 32 bits of the it irq message */
 };
 
+typedef void (ht_irq_update_t)(struct pci_dev *dev, int irq,
+                              struct ht_irq_msg *msg);
+
+struct ht_irq_cfg {
+       struct pci_dev *dev;
+        /* Update callback used to cope with buggy hardware */
+       ht_irq_update_t *update;
+       unsigned pos;
+       unsigned idx;
+       struct ht_irq_msg msg;
+};
+
 /* Helper functions.. */
 void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
 void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
-struct irq_data;
 void mask_ht_irq(struct irq_data *data);
 void unmask_ht_irq(struct irq_data *data);
 
 /* The arch hook for getting things started */
-int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
+int arch_setup_ht_irq(int idx, int pos, struct pci_dev *dev,
+                     ht_irq_update_t *update);
+void arch_teardown_ht_irq(unsigned int irq);
 
 /* For drivers of buggy hardware */
-typedef void (ht_irq_update_t)(struct pci_dev *dev, int irq,
-                              struct ht_irq_msg *msg);
 int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update);
 
 #endif /* LINUX_HTIRQ_H */
index 796ef9645827f000cb76ce4cd8637dc6cfa4db7a..0af9b03e2b1c8cd4a46d99eebe0bbe589f50b864 100644 (file)
@@ -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;
@@ -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;