Commit d32932d0 authored by Jiang Liu's avatar Jiang Liu Committed by Thomas Gleixner

x86/irq: Convert IOAPIC to use hierarchical irqdomain interfaces

Convert IOAPIC driver to support and use hierarchical irqdomain
interfaces.  It's a little big, but would break bisecting if we split
it into multiple patches.

Fold in a patch from Andy Shevchenko <andriy.shevchenko@linux.intel.com>
to make it bisectable.
http://lkml.org/lkml/2014/12/10/622Signed-off-by: default avatarJiang Liu <jiang.liu@linux.intel.com>
Tested-by: default avatarJoerg Roedel <jroedel@suse.de>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Sander Eikelenboom <linux@eikelenboom.it>
Cc: David Vrabel <david.vrabel@citrix.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: sfi-devel@simplefirmware.org
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dimitri Sivanich <sivanich@sgi.com>
Cc: Len Brown <len.brown@intel.com>
Cc: Pavel Machek <pavel@ucw.cz>
Cc: Grant Likely <grant.likely@linaro.org>
Cc: Rob Herring <robh@kernel.org>
Cc: David Rientjes <rientjes@google.com>
Cc: David Cohen <david.a.cohen@linux.intel.com>
Link: http://lkml.kernel.org/r/1428905519-23704-38-git-send-email-jiang.liu@linux.intel.comSigned-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 96ed44b2
...@@ -412,11 +412,6 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, ...@@ -412,11 +412,6 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,
trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1; trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1; polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
node = dev ? dev_to_node(dev) : NUMA_NO_NODE; 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;
}
ioapic_set_alloc_attr(&info, node, trigger, polarity); ioapic_set_alloc_attr(&info, node, trigger, polarity);
irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info); irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info);
if (irq < 0) if (irq < 0)
...@@ -442,8 +437,10 @@ static void mp_unregister_gsi(u32 gsi) ...@@ -442,8 +437,10 @@ static void mp_unregister_gsi(u32 gsi)
} }
static struct irq_domain_ops acpi_irqdomain_ops = { static struct irq_domain_ops acpi_irqdomain_ops = {
.map = mp_irqdomain_map, .alloc = mp_irqdomain_alloc,
.unmap = mp_irqdomain_unmap, .free = mp_irqdomain_free,
.activate = mp_irqdomain_activate,
.deactivate = mp_irqdomain_deactivate,
}; };
static int __init static int __init
......
...@@ -142,6 +142,11 @@ u32 mp_pin_to_gsi(int ioapic, int pin) ...@@ -142,6 +142,11 @@ u32 mp_pin_to_gsi(int ioapic, int pin)
return mp_ioapic_gsi_routing(ioapic)->gsi_base + 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 * Initialize all legacy IRQs and all pins on the first IOAPIC
* if we have legacy interrupt controller. Kernel boot option "pirq=" * if we have legacy interrupt controller. Kernel boot option "pirq="
...@@ -152,7 +157,7 @@ static inline int mp_init_irq_at_boot(int ioapic, int irq) ...@@ -152,7 +157,7 @@ static inline int mp_init_irq_at_boot(int ioapic, int irq)
if (!nr_legacy_irqs()) if (!nr_legacy_irqs())
return 0; return 0;
return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs()); return ioapic == 0 || mp_is_legacy_irq(irq);
} }
static inline struct mp_pin_info *mp_pin_info(int ioapic_idx, int pin) static inline struct mp_pin_info *mp_pin_info(int ioapic_idx, int pin)
...@@ -231,7 +236,7 @@ struct irq_pin_list { ...@@ -231,7 +236,7 @@ struct irq_pin_list {
static struct irq_pin_list *alloc_irq_pin_list(int node) static struct irq_pin_list *alloc_irq_pin_list(int node)
{ {
return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node); return kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node);
} }
static void alloc_ioapic_saved_registers(int idx) static void alloc_ioapic_saved_registers(int idx)
...@@ -560,6 +565,17 @@ void native_eoi_ioapic_pin(int apic, int pin, int vector) ...@@ -560,6 +565,17 @@ void native_eoi_ioapic_pin(int apic, int pin, int vector)
} }
} }
void eoi_ioapic_pin(int vector, struct irq_cfg *cfg)
{
unsigned long flags;
struct irq_pin_list *entry;
raw_spin_lock_irqsave(&ioapic_lock, flags);
for_each_irq_pin(entry, cfg->irq_2_pin)
native_eoi_ioapic_pin(entry->apic, entry->pin, vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
}
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;
...@@ -603,9 +619,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) ...@@ -603,9 +619,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
entry.trigger = IOAPIC_LEVEL; entry.trigger = IOAPIC_LEVEL;
ioapic_write_entry(apic, pin, entry); ioapic_write_entry(apic, pin, entry);
} }
raw_spin_lock_irqsave(&ioapic_lock, flags); raw_spin_lock_irqsave(&ioapic_lock, flags);
x86_io_apic_ops.eoi_ioapic_pin(apic, pin, entry.vector); native_eoi_ioapic_pin(apic, pin, entry.vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
...@@ -1023,95 +1038,121 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info) ...@@ -1023,95 +1038,121 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
data->polarity == info->ioapic_polarity; data->polarity == info->ioapic_polarity;
} }
static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin, static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
struct irq_alloc_info *info) struct irq_alloc_info *info)
{ {
bool legacy = false;
int irq = -1; int irq = -1;
int ioapic = mp_irqdomain_ioapic_idx(domain);
int type = ioapics[ioapic].irqdomain_cfg.type; int type = ioapics[ioapic].irqdomain_cfg.type;
switch (type) { switch (type) {
case IOAPIC_DOMAIN_LEGACY: case IOAPIC_DOMAIN_LEGACY:
/* /*
* Dynamically allocate IRQ number for non-ISA IRQs in the first 16 * Dynamically allocate IRQ number for non-ISA IRQs in the first
* GSIs on some weird platforms. * 16 GSIs on some weird platforms.
*/ */
if (gsi < nr_legacy_irqs()) if (!ioapic_initialized || gsi >= nr_legacy_irqs())
irq = irq_create_mapping(domain, pin);
else if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0)
irq = gsi; irq = gsi;
legacy = mp_is_legacy_irq(irq);
break; break;
case IOAPIC_DOMAIN_STRICT: case IOAPIC_DOMAIN_STRICT:
if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0)
irq = gsi; irq = gsi;
break; break;
case IOAPIC_DOMAIN_DYNAMIC: case IOAPIC_DOMAIN_DYNAMIC:
irq = irq_create_mapping(domain, pin);
break; break;
default: default:
WARN(1, "ioapic: unknown irqdomain type %d\n", type); 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) {
struct irq_cfg *cfg = irqd_cfg(irq_data);
if (!mp_check_pin_attr(irq, info))
return -EBUSY;
if (__add_pin_to_irq_node(cfg, 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, static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
unsigned int flags, struct irq_alloc_info *info) unsigned int flags, struct irq_alloc_info *info)
{ {
int irq; int irq;
bool legacy = false;
struct irq_alloc_info tmp;
struct mp_chip_data *data;
struct irq_domain *domain = mp_ioapic_irqdomain(ioapic); struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
struct mp_pin_info *pinfo = mp_pin_info(ioapic, pin);
if (!domain) 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)) { if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) {
irq = mp_irqs[idx].srcbusirq; irq = mp_irqs[idx].srcbusirq;
if (flags & IOAPIC_MAP_ALLOC) { legacy = mp_is_legacy_irq(irq);
if (pinfo->count == 0 && }
mp_irqdomain_map(domain, irq, pin) != 0)
irq = -1;
/* 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) if (irq == 0)
pinfo->count++; irq = -ENOENT;
} }
} else { } else {
irq = irq_find_mapping(domain, pin); ioapic_copy_alloc_attr(&tmp, info, gsi, ioapic, pin);
if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC)) if (legacy)
irq = alloc_irq_from_domain(domain, gsi, pin, info); 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++;
} }
if (flags & IOAPIC_MAP_ALLOC) {
/* special handling for legacy IRQs */
if (irq < nr_legacy_irqs() && pinfo->count == 1 &&
mp_irqdomain_map(domain, irq, pin) != 0)
irq = -1;
if (irq > 0)
pinfo->count++;
else if (pinfo->count == 0)
pinfo->set = 0;
} }
mutex_unlock(&ioapic_mutex); 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) static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags)
...@@ -1166,26 +1207,19 @@ int mp_map_gsi_to_irq(u32 gsi, unsigned int flags, ...@@ -1166,26 +1207,19 @@ int mp_map_gsi_to_irq(u32 gsi, unsigned int flags,
void mp_unmap_irq(int irq) void mp_unmap_irq(int irq)
{ {
struct irq_data *data = irq_get_irq_data(irq); struct irq_data *irq_data = irq_get_irq_data(irq);
struct mp_pin_info *info; struct mp_chip_data *data;
int ioapic, pin;
if (!data || !data->domain) if (!irq_data || !irq_data->domain)
return; return;
ioapic = (int)(long)data->domain->host_data; data = irq_data->chip_data;
pin = (int)data->hwirq; if (!data || data->isa_irq)
info = mp_pin_info(ioapic, pin); return;
mutex_lock(&ioapic_mutex); mutex_lock(&ioapic_mutex);
if (--info->count == 0) { if (--data->count == 0)
info->set = 0; irq_domain_free_irqs(irq, 1);
if (irq < nr_legacy_irqs() &&
ioapics[ioapic].irqdomain_cfg.type == IOAPIC_DOMAIN_LEGACY)
mp_irqdomain_unmap(data->domain, irq);
else
irq_dispose_mapping(irq);
}
mutex_unlock(&ioapic_mutex); mutex_unlock(&ioapic_mutex);
} }
...@@ -1252,7 +1286,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ...@@ -1252,7 +1286,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
} }
EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); 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 #ifdef CONFIG_X86_32
static inline int IO_APIC_irq_trigger(int irq) static inline int IO_APIC_irq_trigger(int irq)
...@@ -1595,7 +1629,7 @@ void __init print_IO_APICs(void) ...@@ -1595,7 +1629,7 @@ void __init print_IO_APICs(void)
struct irq_pin_list *entry; struct irq_pin_list *entry;
chip = irq_get_chip(irq); chip = irq_get_chip(irq);
if (chip != &ioapic_chip) if (chip != &ioapic_chip && chip != &ioapic_ir_chip)
continue; continue;
cfg = irq_cfg(irq); cfg = irq_cfg(irq);
...@@ -2057,12 +2091,12 @@ static inline void ioapic_irqd_unmask(struct irq_data *data, ...@@ -2057,12 +2091,12 @@ static inline void ioapic_irqd_unmask(struct irq_data *data,
} }
#endif #endif
static void ack_ioapic_level(struct irq_data *data) static void ioapic_ack_level(struct irq_data *data)
{ {
struct irq_cfg *cfg = irqd_cfg(data); struct irq_cfg *cfg = irqd_cfg(data);
int i, irq = data->irq;
unsigned long v; unsigned long v;
bool masked; bool masked;
int i;
irq_complete_move(cfg); irq_complete_move(cfg);
masked = ioapic_irqd_mask(data, cfg); masked = ioapic_irqd_mask(data, cfg);
...@@ -2117,22 +2151,70 @@ static void ack_ioapic_level(struct irq_data *data) ...@@ -2117,22 +2151,70 @@ static void ack_ioapic_level(struct irq_data *data)
*/ */
if (!(v & (1 << (i & 0x1f)))) { if (!(v & (1 << (i & 0x1f)))) {
atomic_inc(&irq_mis_count); atomic_inc(&irq_mis_count);
eoi_ioapic_pin(cfg->vector, cfg);
eoi_ioapic_irq(irq, cfg);
} }
ioapic_irqd_unmask(data, cfg, masked); ioapic_irqd_unmask(data, cfg, 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, irqd_cfg(irq_data));
}
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;
unsigned int dest, irq = irq_data->irq;
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;
/* Only the high 8 bits are valid. */
dest = SET_APIC_LOGICAL_ID(cfg->dest_apicid);
__target_IO_APIC_irq(irq, dest, cfg);
}
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return ret;
}
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,
.irq_mask = mask_ioapic_irq, .irq_mask = mask_ioapic_irq,
.irq_unmask = unmask_ioapic_irq, .irq_unmask = unmask_ioapic_irq,
.irq_ack = apic_ack_edge, .irq_ack = irq_chip_ack_parent,
.irq_eoi = ack_ioapic_level, .irq_eoi = ioapic_ack_level,
.irq_set_affinity = native_ioapic_set_affinity, .irq_set_affinity = ioapic_set_affinity,
.irq_retrigger = apic_retrigger_irq, .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, .flags = IRQCHIP_SKIP_SET_WAKE,
}; };
...@@ -2265,6 +2347,24 @@ static int __init disable_timer_pin_setup(char *arg) ...@@ -2265,6 +2347,24 @@ static int __init disable_timer_pin_setup(char *arg)
} }
early_param("disable_timer_pin_1", disable_timer_pin_setup); 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_alloc_info info;
struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
if (domain) {
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 * 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 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
...@@ -2287,7 +2387,6 @@ static inline void __init check_timer(void) ...@@ -2287,7 +2387,6 @@ static inline void __init check_timer(void)
* get/set the timer IRQ vector: * get/set the timer IRQ vector:
*/ */
legacy_pic->mask(0); legacy_pic->mask(0);
assign_irq_vector(0, cfg, apic->target_cpus());
/* /*
* As IRQ0 is to be enabled in the 8259A, the virtual * As IRQ0 is to be enabled in the 8259A, the virtual
...@@ -2328,15 +2427,12 @@ static inline void __init check_timer(void) ...@@ -2328,15 +2427,12 @@ static inline void __init check_timer(void)
} }
if (pin1 != -1) { if (pin1 != -1) {
/* /* Ok, does IRQ0 through the IOAPIC work? */
* Ok, does IRQ0 through the IOAPIC work?
*/
if (no_pin1) { if (no_pin1) {
add_pin_to_irq_node(cfg, node, apic1, pin1); mp_alloc_timer_irq(apic1, pin1);
setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
} else { } 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 * so only need to unmask if it is level-trigger
* do we really have level trigger timer? * do we really have level trigger timer?
*/ */
...@@ -2345,6 +2441,7 @@ static inline void __init check_timer(void) ...@@ -2345,6 +2441,7 @@ static inline void __init check_timer(void)
if (idx != -1 && irq_trigger(idx)) if (idx != -1 && irq_trigger(idx))
unmask_ioapic(cfg); unmask_ioapic(cfg);
} }
irq_domain_activate_irq(irq_get_irq_data(0));
if (timer_irq_works()) { if (timer_irq_works()) {
if (disable_timer_pin_1 > 0) if (disable_timer_pin_1 > 0)
clear_IO_APIC_pin(0, pin1); clear_IO_APIC_pin(0, pin1);
...@@ -2365,7 +2462,7 @@ static inline void __init check_timer(void) ...@@ -2365,7 +2462,7 @@ static inline void __init check_timer(void)
* legacy devices should be connected to IO APIC #0 * legacy devices should be connected to IO APIC #0
*/ */
replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2); replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); irq_domain_activate_irq(irq_get_irq_data(0));
legacy_pic->unmask(0); legacy_pic->unmask(0);
if (timer_irq_works()) { if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
...@@ -2443,6 +2540,8 @@ static inline void __init check_timer(void) ...@@ -2443,6 +2540,8 @@ static inline void __init check_timer(void)
static int mp_irqdomain_create(int ioapic) static int mp_irqdomain_create(int ioapic)
{ {
size_t size; size_t size;
struct irq_alloc_info info;
struct irq_domain *parent;
int hwirqs = mp_ioapic_pin_count(ioapic); int hwirqs = mp_ioapic_pin_count(ioapic);
struct ioapic *ip = &ioapics[ioapic]; struct ioapic *ip = &ioapics[ioapic];
struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg; struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg;
...@@ -2456,9 +2555,18 @@ static int mp_irqdomain_create(int ioapic) ...@@ -2456,9 +2555,18 @@ static int mp_irqdomain_create(int ioapic)
if (cfg->type == IOAPIC_DOMAIN_INVALID) if (cfg->type == IOAPIC_DOMAIN_INVALID)
return 0; 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, ip->irqdomain = irq_domain_add_linear(cfg->dev, hwirqs, cfg->ops,
(void *)(long)ioapic); (void *)(long)ioapic);
if(!ip->irqdomain) { if (ip->irqdomain) {
ip->irqdomain->parent = parent;
} else {
kfree(ip->pin_info); kfree(ip->pin_info);
ip->pin_info = NULL; ip->pin_info = NULL;
return -ENOMEM; return -ENOMEM;
...@@ -3072,7 +3180,6 @@ int mp_unregister_ioapic(u32 gsi_base) ...@@ -3072,7 +3180,6 @@ int mp_unregister_ioapic(u32 gsi_base)
{ {
int ioapic, pin; int ioapic, pin;
int found = 0; int found = 0;
struct mp_pin_info *pin_info;
for_each_ioapic(ioapic) for_each_ioapic(ioapic)
if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) { if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) {
...@@ -3085,13 +3192,19 @@ int mp_unregister_ioapic(u32 gsi_base) ...@@ -3085,13 +3192,19 @@ int mp_unregister_ioapic(u32 gsi_base)
} }
for_each_pin(ioapic, pin) { for_each_pin(ioapic, pin) {
pin_info = mp_pin_info(ioapic, pin); u32 gsi = mp_pin_to_gsi(ioapic, pin);
if (pin_info->count) { 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", pr_warn("pin%d on IOAPIC%d is still in use.\n",
pin, ioapic); pin, ioapic);
return -EBUSY; return -EBUSY;
} }
} }
}
/* Mark entry not present */ /* Mark entry not present */
ioapics[ioapic].nr_registers = 0; ioapics[ioapic].nr_registers = 0;
...@@ -3241,7 +3354,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, ...@@ -3241,7 +3354,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
} }
irq_data->hwirq = info->ioapic_pin; irq_data->hwirq = info->ioapic_pin;
irq_data->chip = &ioapic_chip; irq_data->chip = (domain->parent == x86_vector_domain) ?
&ioapic_chip : &ioapic_ir_chip;
irq_data->chip_data = data; irq_data->chip_data = data;
mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info); mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
......
...@@ -196,38 +196,31 @@ static struct of_ioapic_type of_ioapic_type[] = ...@@ -196,38 +196,31 @@ static struct of_ioapic_type of_ioapic_type[] =
}, },
}; };
static int ioapic_xlate(struct irq_domain *domain, static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
struct device_node *controller, unsigned int nr_irqs, void *arg)
const u32 *intspec, u32 intsize,
irq_hw_number_t *out_hwirq, u32 *out_type)
{ {
struct of_phandle_args *irq_data = (void *)arg;
struct of_ioapic_type *it; 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; return -EINVAL;
if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type))
line = intspec[0];
if (intspec[1] >= ARRAY_SIZE(of_ioapic_type))
return -EINVAL; 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; return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
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;
} }
const struct irq_domain_ops ioapic_irq_domain_ops = { const struct irq_domain_ops ioapic_irq_domain_ops = {
.map = mp_irqdomain_map, .alloc = dt_irqdomain_alloc,
.unmap = mp_irqdomain_unmap, .free = mp_irqdomain_free,
.xlate = ioapic_xlate, .activate = mp_irqdomain_activate,
.deactivate = mp_irqdomain_deactivate,
}; };
static void __init dtb_add_ioapic(struct device_node *dn) static void __init dtb_add_ioapic(struct device_node *dn)
......
...@@ -114,8 +114,10 @@ static void __init MP_bus_info(struct mpc_bus *m) ...@@ -114,8 +114,10 @@ static void __init MP_bus_info(struct mpc_bus *m)
} }
static struct irq_domain_ops mp_ioapic_irqdomain_ops = { static struct irq_domain_ops mp_ioapic_irqdomain_ops = {
.map = mp_irqdomain_map, .alloc = mp_irqdomain_alloc,
.unmap = mp_irqdomain_unmap, .free = mp_irqdomain_free,
.activate = mp_irqdomain_activate,
.deactivate = mp_irqdomain_deactivate,
}; };
static void __init MP_ioapic_info(struct mpc_ioapic *m) static void __init MP_ioapic_info(struct mpc_ioapic *m)
......
...@@ -224,8 +224,6 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev) ...@@ -224,8 +224,6 @@ static int intel_mid_pci_irq_enable(struct pci_dev *dev)
* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to * MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to
* IOAPIC RTE entries, so we just enable RTE for the device. * 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, &info) < 0) if (mp_map_gsi_to_irq(dev->irq, IOAPIC_MAP_ALLOC, &info) < 0)
return -EBUSY; return -EBUSY;
......
...@@ -36,8 +36,7 @@ static int tangier_probe(struct platform_device *pdev) ...@@ -36,8 +36,7 @@ static int tangier_probe(struct platform_device *pdev)
/* IOAPIC builds identity mapping between GSI and IRQ on MID */ /* IOAPIC builds identity mapping between GSI and IRQ on MID */
gsi = pdata->irq; gsi = pdata->irq;
ioapic_set_alloc_attr(&info, cpu_to_node(0), 1, 0); ioapic_set_alloc_attr(&info, cpu_to_node(0), 1, 0);
if (mp_set_gsi_attr(gsi, 1, 0, cpu_to_node(0)) || if (mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info) <= 0) {
mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC, &info) <= 0) {
dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n", dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n",
gsi); gsi);
return -EINVAL; return -EINVAL;
......
...@@ -469,10 +469,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) ...@@ -469,10 +469,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table)
} }
ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 1, polarity); ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 1, polarity);
ret = mp_set_gsi_attr(irq, 1, polarity, NUMA_NO_NODE); ret = mp_map_gsi_to_irq(irq, IOAPIC_MAP_ALLOC, &info);
if (ret == 0)
ret = mp_map_gsi_to_irq(irq, IOAPIC_MAP_ALLOC,
&info);
WARN_ON(ret < 0); WARN_ON(ret < 0);
} }
......
...@@ -72,7 +72,10 @@ static int __init sfi_parse_cpus(struct sfi_table_header *table) ...@@ -72,7 +72,10 @@ static int __init sfi_parse_cpus(struct sfi_table_header *table)
#ifdef CONFIG_X86_IO_APIC #ifdef CONFIG_X86_IO_APIC
static struct irq_domain_ops sfi_ioapic_irqdomain_ops = { static struct irq_domain_ops sfi_ioapic_irqdomain_ops = {
.map = mp_irqdomain_map, .alloc = mp_irqdomain_alloc,
.free = mp_irqdomain_free,
.activate = mp_irqdomain_activate,
.deactivate = mp_irqdomain_deactivate,
}; };
static int __init sfi_parse_ioapic(struct sfi_table_header *table) static int __init sfi_parse_ioapic(struct sfi_table_header *table)
......
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