Commit e9b6025b authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'ioapic-cleanups-for-tip' of...

Merge tag 'ioapic-cleanups-for-tip' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu into x86/apic

Pull "x86 IOAPIC code from interrupt remapping details cleanups" from
Joerg Roedel:

 "These patches move all interrupt remapping specific checks out of the
  x86 core code and replaces the respective call-sites with function
  pointers. As a result the interrupt remapping code is better abstraced
  from x86 core interrupt handling code.

  The code was rebased to v3.8-rc4 and tested on systems with AMD-Vi and
  Intel VT-d (both capable of interrupt remapping). The systems were
  tested with IOMMU enabled and with IOMMU disabled. No issues were found."
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 3b4a5058 a1bb20c2
...@@ -80,9 +80,9 @@ extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg); ...@@ -80,9 +80,9 @@ 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); extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
#ifdef CONFIG_PCI_MSI #ifdef CONFIG_PCI_MSI
extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id); extern int default_setup_hpet_msi(unsigned int irq, unsigned int id);
#else #else
static inline int arch_setup_hpet_msi(unsigned int irq, unsigned int id) static inline int default_setup_hpet_msi(unsigned int irq, unsigned int id)
{ {
return -EINVAL; return -EINVAL;
} }
...@@ -111,6 +111,7 @@ extern void hpet_unregister_irq_handler(rtc_irq_handler handler); ...@@ -111,6 +111,7 @@ extern void hpet_unregister_irq_handler(rtc_irq_handler handler);
static inline int hpet_enable(void) { return 0; } static inline int hpet_enable(void) { return 0; }
static inline int is_hpet_enabled(void) { return 0; } static inline int is_hpet_enabled(void) { return 0; }
#define hpet_readl(a) 0 #define hpet_readl(a) 0
#define default_setup_hpet_msi NULL
#endif #endif
#endif /* _ASM_X86_HPET_H */ #endif /* _ASM_X86_HPET_H */
...@@ -101,6 +101,7 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr, ...@@ -101,6 +101,7 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
irq_attr->polarity = polarity; irq_attr->polarity = polarity;
} }
/* Intel specific interrupt remapping information */
struct irq_2_iommu { struct irq_2_iommu {
struct intel_iommu *iommu; struct intel_iommu *iommu;
u16 irte_index; u16 irte_index;
...@@ -108,6 +109,12 @@ struct irq_2_iommu { ...@@ -108,6 +109,12 @@ struct irq_2_iommu {
u8 irte_mask; 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*/
};
/* /*
* This is performance-critical, we want to do it O(1) * This is performance-critical, we want to do it O(1)
* *
...@@ -120,7 +127,11 @@ struct irq_cfg { ...@@ -120,7 +127,11 @@ struct irq_cfg {
u8 vector; u8 vector;
u8 move_in_progress : 1; u8 move_in_progress : 1;
#ifdef CONFIG_IRQ_REMAP #ifdef CONFIG_IRQ_REMAP
struct irq_2_iommu irq_2_iommu; u8 remapped : 1;
union {
struct irq_2_iommu irq_2_iommu;
struct irq_2_irte irq_2_irte;
};
#endif #endif
}; };
......
...@@ -144,11 +144,24 @@ extern int timer_through_8259; ...@@ -144,11 +144,24 @@ extern int timer_through_8259;
(mp_irq_entries && !skip_ioapic_setup && io_apic_irqs) (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs)
struct io_apic_irq_attr; struct io_apic_irq_attr;
struct irq_cfg;
extern int io_apic_set_pci_routing(struct device *dev, int irq, extern int io_apic_set_pci_routing(struct device *dev, int irq,
struct io_apic_irq_attr *irq_attr); struct io_apic_irq_attr *irq_attr);
void setup_IO_APIC_irq_extra(u32 gsi); void setup_IO_APIC_irq_extra(u32 gsi);
extern void ioapic_insert_resources(void); extern void ioapic_insert_resources(void);
extern int native_setup_ioapic_entry(int, struct IO_APIC_route_entry *,
unsigned int, int,
struct io_apic_irq_attr *);
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_compose_msi_msg(struct pci_dev *pdev,
unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id);
extern void native_eoi_ioapic_pin(int apic, int pin, int vector);
int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr); int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
extern int save_ioapic_entries(void); extern int save_ioapic_entries(void);
...@@ -179,6 +192,12 @@ extern void __init native_io_apic_init_mappings(void); ...@@ -179,6 +192,12 @@ extern void __init native_io_apic_init_mappings(void);
extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg); 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_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_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) static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
{ {
...@@ -193,6 +212,9 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned ...@@ -193,6 +212,9 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
{ {
x86_io_apic_ops.modify(apic, reg, value); x86_io_apic_ops.modify(apic, reg, value);
} }
extern void io_apic_eoi(unsigned int apic, unsigned int vector);
#else /* !CONFIG_X86_IO_APIC */ #else /* !CONFIG_X86_IO_APIC */
#define io_apic_assign_pci_irqs 0 #define io_apic_assign_pci_irqs 0
...@@ -223,6 +245,12 @@ static inline void disable_ioapic_support(void) { } ...@@ -223,6 +245,12 @@ static inline void disable_ioapic_support(void) { }
#define native_io_apic_read NULL #define native_io_apic_read NULL
#define native_io_apic_write NULL #define native_io_apic_write NULL
#define native_io_apic_modify 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_compose_msi_msg NULL
#define native_eoi_ioapic_pin NULL
#endif #endif
#endif /* _ASM_X86_IO_APIC_H */ #endif /* _ASM_X86_IO_APIC_H */
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
#ifdef CONFIG_IRQ_REMAP #ifdef CONFIG_IRQ_REMAP
extern int irq_remapping_enabled;
extern void setup_irq_remapping_ops(void); extern void setup_irq_remapping_ops(void);
extern int irq_remapping_supported(void); extern int irq_remapping_supported(void);
extern int irq_remapping_prepare(void); extern int irq_remapping_prepare(void);
...@@ -40,21 +38,19 @@ extern int setup_ioapic_remapped_entry(int irq, ...@@ -40,21 +38,19 @@ extern int setup_ioapic_remapped_entry(int irq,
unsigned int destination, unsigned int destination,
int vector, int vector,
struct io_apic_irq_attr *attr); struct io_apic_irq_attr *attr);
extern int set_remapped_irq_affinity(struct irq_data *data,
const struct cpumask *mask,
bool force);
extern void free_remapped_irq(int irq); extern void free_remapped_irq(int irq);
extern void compose_remapped_msi_msg(struct pci_dev *pdev, extern void compose_remapped_msi_msg(struct pci_dev *pdev,
unsigned int irq, unsigned int dest, unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id); struct msi_msg *msg, u8 hpet_id);
extern int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
extern int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
int index, int sub_handle);
extern int setup_hpet_msi_remapped(unsigned int irq, unsigned int 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);
#else /* CONFIG_IRQ_REMAP */ void irq_remap_modify_chip_defaults(struct irq_chip *chip);
#define irq_remapping_enabled 0 #else /* CONFIG_IRQ_REMAP */
static inline void setup_irq_remapping_ops(void) { } static inline void setup_irq_remapping_ops(void) { }
static inline int irq_remapping_supported(void) { return 0; } static inline int irq_remapping_supported(void) { return 0; }
...@@ -71,30 +67,30 @@ static inline int setup_ioapic_remapped_entry(int irq, ...@@ -71,30 +67,30 @@ static inline int setup_ioapic_remapped_entry(int irq,
{ {
return -ENODEV; return -ENODEV;
} }
static inline int set_remapped_irq_affinity(struct irq_data *data,
const struct cpumask *mask,
bool force)
{
return 0;
}
static inline void free_remapped_irq(int irq) { } static inline void free_remapped_irq(int irq) { }
static inline void compose_remapped_msi_msg(struct pci_dev *pdev, static inline void compose_remapped_msi_msg(struct pci_dev *pdev,
unsigned int irq, unsigned int dest, unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id) struct msi_msg *msg, u8 hpet_id)
{ {
} }
static inline int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
int index, int sub_handle) static inline void panic_if_irq_remap(const char *msg)
{
}
static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
{ {
return -ENODEV;
} }
static inline int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
static inline bool setup_remapped_irq(int irq,
struct irq_cfg *cfg,
struct irq_chip *chip)
{ {
return -ENODEV; return false;
} }
#endif /* CONFIG_IRQ_REMAP */ #endif /* CONFIG_IRQ_REMAP */
......
...@@ -121,9 +121,12 @@ static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq) ...@@ -121,9 +121,12 @@ static inline void x86_restore_msi_irqs(struct pci_dev *dev, int irq)
#define arch_teardown_msi_irq x86_teardown_msi_irq #define arch_teardown_msi_irq x86_teardown_msi_irq
#define arch_restore_msi_irqs x86_restore_msi_irqs #define arch_restore_msi_irqs x86_restore_msi_irqs
/* implemented in arch/x86/kernel/apic/io_apic. */ /* implemented in arch/x86/kernel/apic/io_apic. */
struct msi_desc;
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
void native_teardown_msi_irq(unsigned int irq); void native_teardown_msi_irq(unsigned int irq);
void native_restore_msi_irqs(struct pci_dev *dev, int irq); void native_restore_msi_irqs(struct pci_dev *dev, int irq);
int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
unsigned int irq_base, unsigned int irq_offset);
/* default to the implementation in drivers/lib/msi.c */ /* default to the implementation in drivers/lib/msi.c */
#define HAVE_DEFAULT_MSI_TEARDOWN_IRQS #define HAVE_DEFAULT_MSI_TEARDOWN_IRQS
#define HAVE_DEFAULT_MSI_RESTORE_IRQS #define HAVE_DEFAULT_MSI_RESTORE_IRQS
......
...@@ -181,19 +181,38 @@ struct x86_platform_ops { ...@@ -181,19 +181,38 @@ struct x86_platform_ops {
}; };
struct pci_dev; struct pci_dev;
struct msi_msg;
struct x86_msi_ops { struct x86_msi_ops {
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type); 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_irq)(unsigned int irq);
void (*teardown_msi_irqs)(struct pci_dev *dev); void (*teardown_msi_irqs)(struct pci_dev *dev);
void (*restore_msi_irqs)(struct pci_dev *dev, int irq); void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
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 { struct x86_io_apic_ops {
void (*init) (void); void (*init) (void);
unsigned int (*read) (unsigned int apic, unsigned int reg); unsigned int (*read) (unsigned int apic, unsigned int reg);
void (*write) (unsigned int apic, unsigned int reg, unsigned int value); void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
void (*modify)(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; extern struct x86_init_ops x86_init;
......
...@@ -1477,8 +1477,7 @@ void __init bsp_end_local_APIC_setup(void) ...@@ -1477,8 +1477,7 @@ void __init bsp_end_local_APIC_setup(void)
* Now that local APIC setup is completed for BP, configure the fault * Now that local APIC setup is completed for BP, configure the fault
* handling for interrupt remapping. * handling for interrupt remapping.
*/ */
if (irq_remapping_enabled) irq_remap_enable_fault_handling();
irq_remap_enable_fault_handling();
} }
...@@ -2251,8 +2250,7 @@ static int lapic_suspend(void) ...@@ -2251,8 +2250,7 @@ static int lapic_suspend(void)
local_irq_save(flags); local_irq_save(flags);
disable_local_APIC(); disable_local_APIC();
if (irq_remapping_enabled) irq_remapping_disable();
irq_remapping_disable();
local_irq_restore(flags); local_irq_restore(flags);
return 0; return 0;
...@@ -2268,16 +2266,15 @@ static void lapic_resume(void) ...@@ -2268,16 +2266,15 @@ static void lapic_resume(void)
return; return;
local_irq_save(flags); local_irq_save(flags);
if (irq_remapping_enabled) {
/* /*
* IO-APIC and PIC have their own resume routines. * IO-APIC and PIC have their own resume routines.
* We just mask them here to make sure the interrupt * We just mask them here to make sure the interrupt
* subsystem is completely quiet while we enable x2apic * subsystem is completely quiet while we enable x2apic
* and interrupt-remapping. * and interrupt-remapping.
*/ */
mask_ioapic_entries(); mask_ioapic_entries();
legacy_pic->mask_all(); legacy_pic->mask_all();
}
if (x2apic_mode) if (x2apic_mode)
enable_x2apic(); enable_x2apic();
...@@ -2320,8 +2317,7 @@ static void lapic_resume(void) ...@@ -2320,8 +2317,7 @@ static void lapic_resume(void)
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
apic_read(APIC_ESR); apic_read(APIC_ESR);
if (irq_remapping_enabled) irq_remapping_reenable(x2apic_mode);
irq_remapping_reenable(x2apic_mode);
local_irq_restore(flags); local_irq_restore(flags);
} }
......
...@@ -68,22 +68,6 @@ ...@@ -68,22 +68,6 @@
#define for_each_irq_pin(entry, head) \ #define for_each_irq_pin(entry, head) \
for (entry = head; entry; entry = entry->next) for (entry = head; entry; entry = entry->next)
#ifdef CONFIG_IRQ_REMAP
static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
static inline bool irq_remapped(struct irq_cfg *cfg)
{
return cfg->irq_2_iommu.iommu != NULL;
}
#else
static inline bool irq_remapped(struct irq_cfg *cfg)
{
return false;
}
static inline void irq_remap_modify_chip_defaults(struct irq_chip *chip)
{
}
#endif
/* /*
* Is the SiS APIC rmw bug present ? * Is the SiS APIC rmw bug present ?
* -1 = don't know, 0 = no, 1 = yes * -1 = don't know, 0 = no, 1 = yes
...@@ -326,7 +310,7 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) ...@@ -326,7 +310,7 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
+ (mpc_ioapic_addr(idx) & ~PAGE_MASK); + (mpc_ioapic_addr(idx) & ~PAGE_MASK);
} }
static inline void io_apic_eoi(unsigned int apic, unsigned int vector) void io_apic_eoi(unsigned int apic, unsigned int vector)
{ {
struct io_apic __iomem *io_apic = io_apic_base(apic); struct io_apic __iomem *io_apic = io_apic_base(apic);
writel(vector, &io_apic->eoi); writel(vector, &io_apic->eoi);
...@@ -573,19 +557,10 @@ static void unmask_ioapic_irq(struct irq_data *data) ...@@ -573,19 +557,10 @@ static void unmask_ioapic_irq(struct irq_data *data)
* Otherwise, we simulate the EOI message manually by changing the trigger * 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. * mode to edge and then back to level, with RTE being masked during this.
*/ */
static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg) void native_eoi_ioapic_pin(int apic, int pin, int vector)
{ {
if (mpc_ioapic_ver(apic) >= 0x20) { if (mpc_ioapic_ver(apic) >= 0x20) {
/* io_apic_eoi(apic, 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.
*/
if (cfg && irq_remapped(cfg))
io_apic_eoi(apic, pin);
else
io_apic_eoi(apic, vector);
} else { } else {
struct IO_APIC_route_entry entry, entry1; struct IO_APIC_route_entry entry, entry1;
...@@ -606,14 +581,15 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg) ...@@ -606,14 +581,15 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg)
} }
} }
static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
{ {
struct irq_pin_list *entry; struct irq_pin_list *entry;
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); raw_spin_lock_irqsave(&ioapic_lock, flags);
for_each_irq_pin(entry, cfg->irq_2_pin) for_each_irq_pin(entry, cfg->irq_2_pin)
__eoi_ioapic_pin(entry->apic, entry->pin, cfg->vector, cfg); x86_io_apic_ops.eoi_ioapic_pin(entry->apic, entry->pin,
cfg->vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
...@@ -650,7 +626,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) ...@@ -650,7 +626,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
} }
raw_spin_lock_irqsave(&ioapic_lock, flags); raw_spin_lock_irqsave(&ioapic_lock, flags);
__eoi_ioapic_pin(apic, pin, entry.vector, NULL); x86_io_apic_ops.eoi_ioapic_pin(apic, pin, entry.vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
...@@ -1304,25 +1280,18 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg, ...@@ -1304,25 +1280,18 @@ static void ioapic_register_intr(unsigned int irq, struct irq_cfg *cfg,
fasteoi = false; fasteoi = false;
} }
if (irq_remapped(cfg)) { if (setup_remapped_irq(irq, cfg, chip))
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
irq_remap_modify_chip_defaults(chip);
fasteoi = trigger != 0; fasteoi = trigger != 0;
}
hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq; hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
irq_set_chip_and_handler_name(irq, chip, hdl, irq_set_chip_and_handler_name(irq, chip, hdl,
fasteoi ? "fasteoi" : "edge"); fasteoi ? "fasteoi" : "edge");
} }
static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, int native_setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
unsigned int destination, int vector, unsigned int destination, int vector,
struct io_apic_irq_attr *attr) struct io_apic_irq_attr *attr)
{ {
if (irq_remapping_enabled)
return setup_ioapic_remapped_entry(irq, entry, destination,
vector, attr);
memset(entry, 0, sizeof(*entry)); memset(entry, 0, sizeof(*entry));
entry->delivery_mode = apic->irq_delivery_mode; entry->delivery_mode = apic->irq_delivery_mode;
...@@ -1370,8 +1339,8 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg, ...@@ -1370,8 +1339,8 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin, attr->ioapic, mpc_ioapic_id(attr->ioapic), attr->ioapic_pin,
cfg->vector, irq, attr->trigger, attr->polarity, dest); cfg->vector, irq, attr->trigger, attr->polarity, dest);
if (setup_ioapic_entry(irq, &entry, dest, cfg->vector, attr)) { 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", pr_warn("Failed to setup ioapic entry for ioapic %d, pin %d\n",
mpc_ioapic_id(attr->ioapic), attr->ioapic_pin); mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
__clear_irq_vector(irq, cfg); __clear_irq_vector(irq, cfg);
...@@ -1479,9 +1448,6 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx, ...@@ -1479,9 +1448,6 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
struct IO_APIC_route_entry entry; struct IO_APIC_route_entry entry;
unsigned int dest; unsigned int dest;
if (irq_remapping_enabled)
return;
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
/* /*
...@@ -1513,9 +1479,63 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx, ...@@ -1513,9 +1479,63 @@ static void __init setup_timer_IRQ0_pin(unsigned int ioapic_idx,
ioapic_write_entry(ioapic_idx, pin, entry); ioapic_write_entry(ioapic_idx, pin, entry);
} }
__apicdebuginit(void) print_IO_APIC(int ioapic_idx) void native_io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
{ {
int i; 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);
}
}
void intel_ir_io_apic_print_entries(unsigned int apic,
unsigned int nr_entries)
{
int i;
pr_debug(" NR Indx Fmt Mask Trig IRR Pol Stat Indx2 Zero Vect:\n");
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);
}
}
__apicdebuginit(void) print_IO_APIC(int ioapic_idx)
{
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
union IO_APIC_reg_01 reg_01; union IO_APIC_reg_01 reg_01;
union IO_APIC_reg_02 reg_02; union IO_APIC_reg_02 reg_02;
...@@ -1568,58 +1588,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx) ...@@ -1568,58 +1588,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
printk(KERN_DEBUG ".... IRQ redirection table:\n"); printk(KERN_DEBUG ".... IRQ redirection table:\n");
if (irq_remapping_enabled) { x86_io_apic_ops.print_entries(ioapic_idx, reg_01.bits.entries);
printk(KERN_DEBUG " NR Indx Fmt Mask Trig IRR"
" Pol Stat Indx2 Zero Vect:\n");
} else {
printk(KERN_DEBUG " NR Dst Mask Trig IRR Pol"
" Stat Dmod Deli Vect:\n");
}
for (i = 0; i <= reg_01.bits.entries; i++) {
if (irq_remapping_enabled) {
struct IO_APIC_route_entry entry;
struct IR_IO_APIC_route_entry *ir_entry;
entry = ioapic_read_entry(ioapic_idx, i);
ir_entry = (struct IR_IO_APIC_route_entry *) &entry;
printk(KERN_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
);
} else {
struct IO_APIC_route_entry entry;
entry = ioapic_read_entry(ioapic_idx, i);
printk(KERN_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
);
}
}
} }
__apicdebuginit(void) print_IO_APICs(void) __apicdebuginit(void) print_IO_APICs(void)
...@@ -1921,30 +1890,14 @@ void __init enable_IO_APIC(void) ...@@ -1921,30 +1890,14 @@ void __init enable_IO_APIC(void)
clear_IO_APIC(); clear_IO_APIC();
} }
/* void native_disable_io_apic(void)
* Not an __init, needed by the reboot code
*/
void disable_IO_APIC(void)
{ {
/*
* Clear the IO-APIC before rebooting:
*/
clear_IO_APIC();
if (!legacy_pic->nr_legacy_irqs)
return;
/* /*
* If the i8259 is routed through an IOAPIC * If the i8259 is routed through an IOAPIC
* Put that IOAPIC in virtual wire mode * Put that IOAPIC in virtual wire mode
* so legacy interrupts can be delivered. * so legacy interrupts can be delivered.
*
* With interrupt-remapping, for now we will use virtual wire A mode,
* as virtual wire B is little complex (need to configure both
* IOAPIC RTE as well as interrupt-remapping table entry).
* As this gets called during crash dump, keep this simple for now.
*/ */
if (ioapic_i8259.pin != -1 && !irq_remapping_enabled) { if (ioapic_i8259.pin != -1) {
struct IO_APIC_route_entry entry; struct IO_APIC_route_entry entry;
memset(&entry, 0, sizeof(entry)); memset(&entry, 0, sizeof(entry));
...@@ -1964,12 +1917,25 @@ void disable_IO_APIC(void) ...@@ -1964,12 +1917,25 @@ void disable_IO_APIC(void)
ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
} }
if (cpu_has_apic || apic_from_smp_config())
disconnect_bsp_APIC(ioapic_i8259.pin != -1);
}
/*
* Not an __init, needed by the reboot code
*/
void disable_IO_APIC(void)
{
/* /*
* Use virtual wire A mode when interrupt remapping is enabled. * Clear the IO-APIC before rebooting:
*/ */
if (cpu_has_apic || apic_from_smp_config()) clear_IO_APIC();
disconnect_bsp_APIC(!irq_remapping_enabled &&
ioapic_i8259.pin != -1); if (!legacy_pic->nr_legacy_irqs)
return;
x86_io_apic_ops.disable();
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
...@@ -2322,12 +2288,8 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq ...@@ -2322,12 +2288,8 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
apic = entry->apic; apic = entry->apic;
pin = entry->pin; pin = entry->pin;
/*
* With interrupt-remapping, destination information comes io_apic_write(apic, 0x11 + pin*2, dest);
* from interrupt-remapping table entry.
*/
if (!irq_remapped(cfg))
io_apic_write(apic, 0x11 + pin*2, dest);
reg = io_apic_read(apic, 0x10 + pin*2); reg = io_apic_read(apic, 0x10 + pin*2);
reg &= ~IO_APIC_REDIR_VECTOR_MASK; reg &= ~IO_APIC_REDIR_VECTOR_MASK;
reg |= vector; reg |= vector;
...@@ -2369,9 +2331,10 @@ int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, ...@@ -2369,9 +2331,10 @@ int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
return 0; return 0;
} }
static int
ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask, int native_ioapic_set_affinity(struct irq_data *data,
bool force) const struct cpumask *mask,
bool force)
{ {
unsigned int dest, irq = data->irq; unsigned int dest, irq = data->irq;
unsigned long flags; unsigned long flags;
...@@ -2548,33 +2511,6 @@ static void ack_apic_level(struct irq_data *data) ...@@ -2548,33 +2511,6 @@ static void ack_apic_level(struct irq_data *data)
ioapic_irqd_unmask(data, cfg, masked); ioapic_irqd_unmask(data, cfg, masked);
} }
#ifdef CONFIG_IRQ_REMAP
static void ir_ack_apic_edge(struct irq_data *data)
{
ack_APIC_irq();
}
static void ir_ack_apic_level(struct irq_data *data)
{
ack_APIC_irq();
eoi_ioapic_irq(data->irq, data->chip_data);
}
static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
{
seq_printf(p, " IR-%s", data->chip->name);
}
static void irq_remap_modify_chip_defaults(struct irq_chip *chip)
{
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 = set_remapped_irq_affinity;
}
#endif /* CONFIG_IRQ_REMAP */
static struct irq_chip ioapic_chip __read_mostly = { static struct irq_chip ioapic_chip __read_mostly = {
.name = "IO-APIC", .name = "IO-APIC",
.irq_startup = startup_ioapic_irq, .irq_startup = startup_ioapic_irq,
...@@ -2582,7 +2518,7 @@ static struct irq_chip ioapic_chip __read_mostly = { ...@@ -2582,7 +2518,7 @@ static struct irq_chip ioapic_chip __read_mostly = {
.irq_unmask = unmask_ioapic_irq, .irq_unmask = unmask_ioapic_irq,
.irq_ack = ack_apic_edge, .irq_ack = ack_apic_edge,
.irq_eoi = ack_apic_level, .irq_eoi = ack_apic_level,
.irq_set_affinity = ioapic_set_affinity, .irq_set_affinity = native_ioapic_set_affinity,
.irq_retrigger = ioapic_retrigger_irq, .irq_retrigger = ioapic_retrigger_irq,
}; };
...@@ -2781,8 +2717,7 @@ static inline void __init check_timer(void) ...@@ -2781,8 +2717,7 @@ static inline void __init check_timer(void)
* 8259A. * 8259A.
*/ */
if (pin1 == -1) { if (pin1 == -1) {
if (irq_remapping_enabled) panic_if_irq_remap("BIOS bug: timer not connected to IO-APIC");
panic("BIOS bug: timer not connected to IO-APIC");
pin1 = pin2; pin1 = pin2;
apic1 = apic2; apic1 = apic2;
no_pin1 = 1; no_pin1 = 1;
...@@ -2814,8 +2749,7 @@ static inline void __init check_timer(void) ...@@ -2814,8 +2749,7 @@ static inline void __init check_timer(void)
clear_IO_APIC_pin(0, pin1); clear_IO_APIC_pin(0, pin1);
goto out; goto out;
} }
if (irq_remapping_enabled) panic_if_irq_remap("timer doesn't work through Interrupt-remapped IO-APIC");
panic("timer doesn't work through Interrupt-remapped IO-APIC");
local_irq_disable(); local_irq_disable();
clear_IO_APIC_pin(apic1, pin1); clear_IO_APIC_pin(apic1, pin1);
if (!no_pin1) if (!no_pin1)
...@@ -3058,15 +2992,15 @@ void destroy_irq(unsigned int irq) ...@@ -3058,15 +2992,15 @@ void destroy_irq(unsigned int irq)
irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE); irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE);
if (irq_remapped(cfg)) free_remapped_irq(irq);
free_remapped_irq(irq);
raw_spin_lock_irqsave(&vector_lock, flags); raw_spin_lock_irqsave(&vector_lock, flags);
__clear_irq_vector(irq, cfg); __clear_irq_vector(irq, cfg);
raw_spin_unlock_irqrestore(&vector_lock, flags); raw_spin_unlock_irqrestore(&vector_lock, flags);
free_irq_at(irq, cfg); free_irq_at(irq, cfg);
} }
static inline void destroy_irqs(unsigned int irq, unsigned int count) void destroy_irqs(unsigned int irq, unsigned int count)
{ {
unsigned int i; unsigned int i;
...@@ -3077,37 +3011,16 @@ static inline void destroy_irqs(unsigned int irq, unsigned int count) ...@@ -3077,37 +3011,16 @@ static inline void destroy_irqs(unsigned int irq, unsigned int count)
/* /*
* MSI message composition * MSI message composition
*/ */
#ifdef CONFIG_PCI_MSI void native_compose_msi_msg(struct pci_dev *pdev,
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id) struct msi_msg *msg, u8 hpet_id)
{ {
struct irq_cfg *cfg; struct irq_cfg *cfg = irq_cfg(irq);
int err;
unsigned dest;
if (disable_apic) msg->address_hi = MSI_ADDR_BASE_HI;
return -ENXIO;
cfg = irq_cfg(irq);
err = assign_irq_vector(irq, cfg, apic->target_cpus());
if (err)
return err;
err = apic->cpu_mask_to_apicid_and(cfg->domain,
apic->target_cpus(), &dest);
if (err)
return err;
if (irq_remapped(cfg)) {
compose_remapped_msi_msg(pdev, irq, dest, msg, hpet_id);
return 0;
}
if (x2apic_enabled()) if (x2apic_enabled())
msg->address_hi = MSI_ADDR_BASE_HI | msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
MSI_ADDR_EXT_DEST_ID(dest);
else
msg->address_hi = MSI_ADDR_BASE_HI;
msg->address_lo = msg->address_lo =
MSI_ADDR_BASE_LO | MSI_ADDR_BASE_LO |
...@@ -3126,6 +3039,30 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, ...@@ -3126,6 +3039,30 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
MSI_DATA_DELIVERY_FIXED: MSI_DATA_DELIVERY_FIXED:
MSI_DATA_DELIVERY_LOWPRI) | MSI_DATA_DELIVERY_LOWPRI) |
MSI_DATA_VECTOR(cfg->vector); MSI_DATA_VECTOR(cfg->vector);
}
#ifdef CONFIG_PCI_MSI
static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
struct msi_msg *msg, u8 hpet_id)
{
struct irq_cfg *cfg;
int err;
unsigned dest;
if (disable_apic)
return -ENXIO;
cfg = irq_cfg(irq);
err = assign_irq_vector(irq, cfg, apic->target_cpus());
if (err)
return err;
err = apic->cpu_mask_to_apicid_and(cfg->domain,
apic->target_cpus(), &dest);
if (err)
return err;
x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
return 0; return 0;
} }
...@@ -3165,8 +3102,8 @@ static struct irq_chip msi_chip = { ...@@ -3165,8 +3102,8 @@ static struct irq_chip msi_chip = {
.irq_retrigger = ioapic_retrigger_irq, .irq_retrigger = ioapic_retrigger_irq,
}; };
static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
unsigned int irq_base, unsigned int irq_offset) unsigned int irq_base, unsigned int irq_offset)
{ {
struct irq_chip *chip = &msi_chip; struct irq_chip *chip = &msi_chip;
struct msi_msg msg; struct msi_msg msg;
...@@ -3186,10 +3123,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, ...@@ -3186,10 +3123,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
if (!irq_offset) if (!irq_offset)
write_msi_msg(irq, &msg); write_msi_msg(irq, &msg);
if (irq_remapped(irq_get_chip_data(irq))) { setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
irq_remap_modify_chip_defaults(chip);
}
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
...@@ -3198,44 +3132,28 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, ...@@ -3198,44 +3132,28 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
return 0; return 0;
} }
int setup_msix_irqs(struct pci_dev *dev, int nvec) int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{ {
int node, ret, sub_handle, index = 0;
unsigned int irq, irq_want; unsigned int irq, irq_want;
struct msi_desc *msidesc; struct msi_desc *msidesc;
int node, ret;
/* Multiple MSI vectors only supported with interrupt remapping */
if (type == PCI_CAP_ID_MSI && nvec > 1)
return 1;
node = dev_to_node(&dev->dev); node = dev_to_node(&dev->dev);
irq_want = nr_irqs_gsi; irq_want = nr_irqs_gsi;
sub_handle = 0;
list_for_each_entry(msidesc, &dev->msi_list, list) { list_for_each_entry(msidesc, &dev->msi_list, list) {
irq = create_irq_nr(irq_want, node); irq = create_irq_nr(irq_want, node);
if (irq == 0) if (irq == 0)
return -ENOSPC; return -ENOSPC;
irq_want = irq + 1; irq_want = irq + 1;
if (!irq_remapping_enabled)
goto no_ir;
if (!sub_handle) {
/*
* allocate the consecutive block of IRTE's
* for 'nvec'
*/
index = msi_alloc_remapped_irq(dev, irq, nvec);
if (index < 0) {
ret = index;
goto error;
}
} else {
ret = msi_setup_remapped_irq(dev, irq, index,
sub_handle);
if (ret < 0)
goto error;
}
no_ir:
ret = setup_msi_irq(dev, msidesc, irq, 0); ret = setup_msi_irq(dev, msidesc, irq, 0);
if (ret < 0) if (ret < 0)
goto error; goto error;
sub_handle++;
} }
return 0; return 0;
...@@ -3244,74 +3162,6 @@ int setup_msix_irqs(struct pci_dev *dev, int nvec) ...@@ -3244,74 +3162,6 @@ int setup_msix_irqs(struct pci_dev *dev, int nvec)
return ret; return ret;
} }
int setup_msi_irqs(struct pci_dev *dev, int nvec)
{
int node, ret, sub_handle, index = 0;
unsigned int irq;
struct msi_desc *msidesc;
if (nvec > 1 && !irq_remapping_enabled)
return 1;
nvec = __roundup_pow_of_two(nvec);
WARN_ON(!list_is_singular(&dev->msi_list));
msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
WARN_ON(msidesc->irq);
WARN_ON(msidesc->msi_attrib.multiple);
node = dev_to_node(&dev->dev);
irq = __create_irqs(nr_irqs_gsi, nvec, node);
if (irq == 0)
return -ENOSPC;
if (!irq_remapping_enabled) {
ret = setup_msi_irq(dev, msidesc, irq, 0);
if (ret < 0)
goto error;
return 0;
}
msidesc->msi_attrib.multiple = ilog2(nvec);
for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
if (!sub_handle) {
index = msi_alloc_remapped_irq(dev, irq, nvec);
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:
destroy_irqs(irq, nvec);
/*
* Restore altered MSI descriptor fields and prevent just destroyed
* IRQs from tearing down again in default_teardown_msi_irqs()
*/
msidesc->irq = 0;
msidesc->msi_attrib.multiple = 0;
return ret;
}
int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
if (type == PCI_CAP_ID_MSI)
return setup_msi_irqs(dev, nvec);
return setup_msix_irqs(dev, nvec);
}
void native_teardown_msi_irq(unsigned int irq) void native_teardown_msi_irq(unsigned int irq)
{ {
destroy_irq(irq); destroy_irq(irq);
...@@ -3399,26 +3249,19 @@ static struct irq_chip hpet_msi_type = { ...@@ -3399,26 +3249,19 @@ static struct irq_chip hpet_msi_type = {
.irq_retrigger = ioapic_retrigger_irq, .irq_retrigger = ioapic_retrigger_irq,
}; };
int arch_setup_hpet_msi(unsigned int irq, unsigned int id) int default_setup_hpet_msi(unsigned int irq, unsigned int id)
{ {
struct irq_chip *chip = &hpet_msi_type; struct irq_chip *chip = &hpet_msi_type;
struct msi_msg msg; struct msi_msg msg;
int ret; int ret;
if (irq_remapping_enabled) {
ret = setup_hpet_msi_remapped(irq, id);
if (ret)
return ret;
}
ret = msi_compose_msg(NULL, irq, &msg, id); ret = msi_compose_msg(NULL, irq, &msg, id);
if (ret < 0) if (ret < 0)
return ret; return ret;
hpet_msi_write(irq_get_handler_data(irq), &msg); hpet_msi_write(irq_get_handler_data(irq), &msg);
irq_set_status_flags(irq, IRQ_MOVE_PCNTXT); irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
if (irq_remapped(irq_get_chip_data(irq))) setup_remapped_irq(irq, irq_get_chip_data(irq), chip);
irq_remap_modify_chip_defaults(chip);
irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
return 0; return 0;
...@@ -3784,10 +3627,7 @@ void __init setup_ioapic_dest(void) ...@@ -3784,10 +3627,7 @@ void __init setup_ioapic_dest(void)
else else
mask = apic->target_cpus(); mask = apic->target_cpus();
if (irq_remapping_enabled) x86_io_apic_ops.set_affinity(idata, mask, false);
set_remapped_irq_affinity(idata, mask, false);
else
ioapic_set_affinity(idata, mask, false);
} }
} }
......
...@@ -478,7 +478,7 @@ static int hpet_msi_next_event(unsigned long delta, ...@@ -478,7 +478,7 @@ static int hpet_msi_next_event(unsigned long delta,
static int hpet_setup_msi_irq(unsigned int irq) static int hpet_setup_msi_irq(unsigned int irq)
{ {
if (arch_setup_hpet_msi(irq, hpet_blockid)) { if (x86_msi.setup_hpet_msi(irq, hpet_blockid)) {
destroy_irq(irq); destroy_irq(irq);
return -EINVAL; return -EINVAL;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <asm/time.h> #include <asm/time.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io_apic.h> #include <asm/io_apic.h>
#include <asm/hpet.h>
#include <asm/pat.h> #include <asm/pat.h>
#include <asm/tsc.h> #include <asm/tsc.h>
#include <asm/iommu.h> #include <asm/iommu.h>
...@@ -111,15 +112,22 @@ struct x86_platform_ops x86_platform = { ...@@ -111,15 +112,22 @@ struct x86_platform_ops x86_platform = {
EXPORT_SYMBOL_GPL(x86_platform); EXPORT_SYMBOL_GPL(x86_platform);
struct x86_msi_ops x86_msi = { struct x86_msi_ops x86_msi = {
.setup_msi_irqs = native_setup_msi_irqs, .setup_msi_irqs = native_setup_msi_irqs,
.teardown_msi_irq = native_teardown_msi_irq, .compose_msi_msg = native_compose_msi_msg,
.teardown_msi_irqs = default_teardown_msi_irqs, .teardown_msi_irq = native_teardown_msi_irq,
.restore_msi_irqs = default_restore_msi_irqs, .teardown_msi_irqs = default_teardown_msi_irqs,
.restore_msi_irqs = default_restore_msi_irqs,
.setup_hpet_msi = default_setup_hpet_msi,
}; };
struct x86_io_apic_ops x86_io_apic_ops = { struct x86_io_apic_ops x86_io_apic_ops = {
.init = native_io_apic_init_mappings, .init = native_io_apic_init_mappings,
.read = native_io_apic_read, .read = native_io_apic_read,
.write = native_io_apic_write, .write = native_io_apic_write,
.modify = native_io_apic_modify, .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,
}; };
...@@ -4017,10 +4017,10 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count) ...@@ -4017,10 +4017,10 @@ static int alloc_irq_index(struct irq_cfg *cfg, u16 devid, int count)
index -= count - 1; index -= count - 1;
cfg->remapped = 1;
irte_info = &cfg->irq_2_iommu; irte_info = &cfg->irq_2_iommu;
irte_info->sub_handle = devid; irte_info->sub_handle = devid;
irte_info->irte_index = index; irte_info->irte_index = index;
irte_info->iommu = (void *)cfg;
goto out; goto out;
} }
...@@ -4127,9 +4127,9 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry, ...@@ -4127,9 +4127,9 @@ static int setup_ioapic_entry(int irq, struct IO_APIC_route_entry *entry,
index = attr->ioapic_pin; index = attr->ioapic_pin;
/* Setup IRQ remapping info */ /* Setup IRQ remapping info */
cfg->remapped = 1;
irte_info->sub_handle = devid; irte_info->sub_handle = devid;
irte_info->irte_index = index; irte_info->irte_index = index;
irte_info->iommu = (void *)cfg;
/* Setup IRTE for IOMMU */ /* Setup IRTE for IOMMU */
irte.val = 0; irte.val = 0;
...@@ -4288,9 +4288,9 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq, ...@@ -4288,9 +4288,9 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
devid = get_device_id(&pdev->dev); devid = get_device_id(&pdev->dev);
irte_info = &cfg->irq_2_iommu; irte_info = &cfg->irq_2_iommu;
cfg->remapped = 1;
irte_info->sub_handle = devid; irte_info->sub_handle = devid;
irte_info->irte_index = index + offset; irte_info->irte_index = index + offset;
irte_info->iommu = (void *)cfg;
return 0; return 0;
} }
...@@ -4314,9 +4314,9 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id) ...@@ -4314,9 +4314,9 @@ static int setup_hpet_msi(unsigned int irq, unsigned int id)
if (index < 0) if (index < 0)
return index; return index;
cfg->remapped = 1;
irte_info->sub_handle = devid; irte_info->sub_handle = devid;
irte_info->irte_index = index; irte_info->irte_index = index;
irte_info->iommu = (void *)cfg;
return 0; return 0;
} }
......
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include <asm/irq_remapping.h> #include <asm/irq_remapping.h>
#include <asm/iommu_table.h> #include <asm/iommu_table.h>
#include "irq_remapping.h"
/* No locks are needed as DMA remapping hardware unit /* No locks are needed as DMA remapping hardware unit
* list is constructed at boot time and hotplug of * list is constructed at boot time and hotplug of
* these units are not supported by the architecture. * these units are not supported by the architecture.
......
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/iommu.h> #include <asm/iommu.h>
#include "irq_remapping.h"
#define ROOT_SIZE VTD_PAGE_SIZE #define ROOT_SIZE VTD_PAGE_SIZE
#define CONTEXT_SIZE VTD_PAGE_SIZE #define CONTEXT_SIZE VTD_PAGE_SIZE
......
...@@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) ...@@ -68,6 +68,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
{ {
struct ir_table *table = iommu->ir_table; struct ir_table *table = iommu->ir_table;
struct irq_2_iommu *irq_iommu = irq_2_iommu(irq); struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
struct irq_cfg *cfg = irq_get_chip_data(irq);
u16 index, start_index; u16 index, start_index;
unsigned int mask = 0; unsigned int mask = 0;
unsigned long flags; unsigned long flags;
...@@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) ...@@ -115,6 +116,7 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
for (i = index; i < index + count; i++) for (i = index; i < index + count; i++)
table->base[i].present = 1; table->base[i].present = 1;
cfg->remapped = 1;
irq_iommu->iommu = iommu; irq_iommu->iommu = iommu;
irq_iommu->irte_index = index; irq_iommu->irte_index = index;
irq_iommu->sub_handle = 0; irq_iommu->sub_handle = 0;
...@@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle) ...@@ -155,6 +157,7 @@ static int map_irq_to_irte_handle(int irq, u16 *sub_handle)
static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) 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_2_iommu *irq_iommu = irq_2_iommu(irq);
struct irq_cfg *cfg = irq_get_chip_data(irq);
unsigned long flags; unsigned long flags;
if (!irq_iommu) if (!irq_iommu)
...@@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha ...@@ -162,6 +165,7 @@ static int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subha
raw_spin_lock_irqsave(&irq_2_ir_lock, flags); raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
cfg->remapped = 1;
irq_iommu->iommu = iommu; irq_iommu->iommu = iommu;
irq_iommu->irte_index = index; irq_iommu->irte_index = index;
irq_iommu->sub_handle = subhandle; irq_iommu->sub_handle = subhandle;
...@@ -617,6 +621,14 @@ static int __init intel_enable_irq_remapping(void) ...@@ -617,6 +621,14 @@ static int __init intel_enable_irq_remapping(void)
goto error; goto error;
irq_remapping_enabled = 1; 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"); pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE; return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
......
#include <linux/seq_file.h>
#include <linux/cpumask.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <linux/irq.h>
#include <linux/pci.h>
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/irq_remapping.h> #include <asm/irq_remapping.h>
#include <asm/processor.h>
#include <asm/x86_init.h>
#include <asm/apic.h>
#include "irq_remapping.h" #include "irq_remapping.h"
...@@ -17,6 +24,152 @@ int no_x2apic_optout; ...@@ -17,6 +24,152 @@ int no_x2apic_optout;
static struct irq_remap_ops *remap_ops; 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)
{
/*
* With interrupt-remapping, for now we will use virtual wire A
* mode, as virtual wire B is little complex (need to configure
* both IOAPIC RTE as well as interrupt-remapping table entry).
* As this gets called during crash dump, keep this simple for
* now.
*/
if (cpu_has_apic || apic_from_smp_config())
disconnect_bsp_APIC(0);
}
static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
{
int node, ret, sub_handle, index = 0;
unsigned int irq;
struct msi_desc *msidesc;
nvec = __roundup_pow_of_two(nvec);
WARN_ON(!list_is_singular(&dev->msi_list));
msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
WARN_ON(msidesc->irq);
WARN_ON(msidesc->msi_attrib.multiple);
node = dev_to_node(&dev->dev);
irq = __create_irqs(get_nr_irqs_gsi(), nvec, node);
if (irq == 0)
return -ENOSPC;
msidesc->msi_attrib.multiple = ilog2(nvec);
for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
if (!sub_handle) {
index = msi_alloc_remapped_irq(dev, irq, nvec);
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:
destroy_irqs(irq, nvec);
/*
* Restore altered MSI descriptor fields and prevent just destroyed
* IRQs from tearing down again in default_teardown_msi_irqs()
*/
msidesc->irq = 0;
msidesc->msi_attrib.multiple = 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);
irq = get_nr_irqs_gsi();
sub_handle = 0;
list_for_each_entry(msidesc, &dev->msi_list, list) {
irq = create_irq_nr(irq, 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:
destroy_irq(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);
}
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) static __init int setup_nointremap(char *str)
{ {
disable_irq_remap = 1; disable_irq_remap = 1;
...@@ -79,15 +232,24 @@ int __init irq_remapping_prepare(void) ...@@ -79,15 +232,24 @@ int __init irq_remapping_prepare(void)
int __init irq_remapping_enable(void) int __init irq_remapping_enable(void)
{ {
int ret;
if (!remap_ops || !remap_ops->enable) if (!remap_ops || !remap_ops->enable)
return -ENODEV; return -ENODEV;
return remap_ops->enable(); ret = remap_ops->enable();
if (irq_remapping_enabled)
irq_remapping_modify_x86_ops();
return ret;
} }
void irq_remapping_disable(void) void irq_remapping_disable(void)
{ {
if (!remap_ops || !remap_ops->disable) if (!irq_remapping_enabled ||
!remap_ops ||
!remap_ops->disable)
return; return;
remap_ops->disable(); remap_ops->disable();
...@@ -95,7 +257,9 @@ void irq_remapping_disable(void) ...@@ -95,7 +257,9 @@ void irq_remapping_disable(void)
int irq_remapping_reenable(int mode) int irq_remapping_reenable(int mode)
{ {
if (!remap_ops || !remap_ops->reenable) if (!irq_remapping_enabled ||
!remap_ops ||
!remap_ops->reenable)
return 0; return 0;
return remap_ops->reenable(mode); return remap_ops->reenable(mode);
...@@ -103,6 +267,9 @@ int irq_remapping_reenable(int mode) ...@@ -103,6 +267,9 @@ int irq_remapping_reenable(int mode)
int __init irq_remap_enable_fault_handling(void) int __init irq_remap_enable_fault_handling(void)
{ {
if (!irq_remapping_enabled)
return 0;
if (!remap_ops || !remap_ops->enable_faulting) if (!remap_ops || !remap_ops->enable_faulting)
return -ENODEV; return -ENODEV;
...@@ -133,23 +300,28 @@ int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask, ...@@ -133,23 +300,28 @@ int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
void free_remapped_irq(int irq) void free_remapped_irq(int irq)
{ {
struct irq_cfg *cfg = irq_get_chip_data(irq);
if (!remap_ops || !remap_ops->free_irq) if (!remap_ops || !remap_ops->free_irq)
return; return;
remap_ops->free_irq(irq); if (irq_remapped(cfg))
remap_ops->free_irq(irq);
} }
void compose_remapped_msi_msg(struct pci_dev *pdev, void compose_remapped_msi_msg(struct pci_dev *pdev,
unsigned int irq, unsigned int dest, unsigned int irq, unsigned int dest,
struct msi_msg *msg, u8 hpet_id) struct msi_msg *msg, u8 hpet_id)
{ {
if (!remap_ops || !remap_ops->compose_msi_msg) struct irq_cfg *cfg = irq_get_chip_data(irq);
return;
remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id); if (!irq_remapped(cfg))
native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
else if (remap_ops && remap_ops->compose_msi_msg)
remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
} }
int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
{ {
if (!remap_ops || !remap_ops->msi_alloc_irq) if (!remap_ops || !remap_ops->msi_alloc_irq)
return -ENODEV; return -ENODEV;
...@@ -157,8 +329,8 @@ int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec) ...@@ -157,8 +329,8 @@ int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
return remap_ops->msi_alloc_irq(pdev, irq, nvec); return remap_ops->msi_alloc_irq(pdev, irq, nvec);
} }
int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq, static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
int index, int sub_handle) int index, int sub_handle)
{ {
if (!remap_ops || !remap_ops->msi_setup_irq) if (!remap_ops || !remap_ops->msi_setup_irq)
return -ENODEV; return -ENODEV;
...@@ -173,3 +345,42 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id) ...@@ -173,3 +345,42 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
return remap_ops->setup_hpet_msi(irq, id); return remap_ops->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)
{
ack_APIC_irq();
}
static void ir_ack_apic_level(struct irq_data *data)
{
ack_APIC_irq();
eoi_ioapic_irq(data->irq, data->chip_data);
}
static void ir_print_prefix(struct irq_data *data, struct seq_file *p)
{
seq_printf(p, " IR-%s", data->chip->name);
}
void irq_remap_modify_chip_defaults(struct irq_chip *chip)
{
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;
}
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;
}
...@@ -34,6 +34,7 @@ struct msi_msg; ...@@ -34,6 +34,7 @@ struct msi_msg;
extern int disable_irq_remap; extern int disable_irq_remap;
extern int disable_sourceid_checking; extern int disable_sourceid_checking;
extern int no_x2apic_optout; extern int no_x2apic_optout;
extern int irq_remapping_enabled;
struct irq_remap_ops { struct irq_remap_ops {
/* Check whether Interrupt Remapping is supported */ /* Check whether Interrupt Remapping is supported */
......
...@@ -509,8 +509,11 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq) ...@@ -509,8 +509,11 @@ static inline void irq_set_percpu_devid_flags(unsigned int irq)
/* Handle dynamic irq creation and destruction */ /* Handle dynamic irq creation and destruction */
extern unsigned int create_irq_nr(unsigned int irq_want, int node); extern unsigned int create_irq_nr(unsigned int irq_want, int node);
extern unsigned int __create_irqs(unsigned int from, unsigned int count,
int node);
extern int create_irq(void); extern int create_irq(void);
extern void destroy_irq(unsigned int irq); extern void destroy_irq(unsigned int irq);
extern void destroy_irqs(unsigned int irq, unsigned int count);
/* /*
* Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment