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);
} }
......
This diff is collapsed.
...@@ -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