#endif
#include <linux/bootmem.h>
#include <linux/dmar.h>
+#include <linux/hpet.h>
#include <asm/idle.h>
#include <asm/io.h>
#include <asm/hypertransport.h>
#include <asm/setup.h>
#include <asm/irq_remapping.h>
+#include <asm/hpet.h>
+#include <asm/uv/uv_hub.h>
+#include <asm/uv/uv_irq.h>
#include <mach_ipi.h>
#include <mach_apic.h>
}
early_param("noapic", parse_noapic);
-struct irq_cfg;
struct irq_pin_list;
struct irq_cfg {
unsigned int irq;
-#ifdef CONFIG_HAVE_SPARSE_IRQ
- struct irq_cfg *next;
-#endif
struct irq_pin_list *irq_2_pin;
cpumask_t domain;
cpumask_t old_domain;
};
/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
-static struct irq_cfg irq_cfg_legacy[] __initdata = {
+static struct irq_cfg irq_cfgx[NR_IRQS] = {
[0] = { .irq = 0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, },
[1] = { .irq = 1, .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, },
[2] = { .irq = 2, .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, },
[15] = { .irq = 15, .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
};
-static struct irq_cfg irq_cfg_init = { .irq = -1U, };
-
-static void init_one_irq_cfg(struct irq_cfg *cfg)
-{
- memcpy(cfg, &irq_cfg_init, sizeof(struct irq_cfg));
-}
-
-static struct irq_cfg *irq_cfgx;
-
-/*
- * Protect the irq_cfgx_free freelist:
- */
-static DEFINE_SPINLOCK(irq_cfg_lock);
-
-#ifdef CONFIG_HAVE_SPARSE_IRQ
-static struct irq_cfg *irq_cfgx_free;
-#endif
-static void __init init_work(void *data)
-{
- struct dyn_array *da = data;
- struct irq_cfg *cfg;
- int legacy_count;
- int i;
-
- cfg = *da->name;
-
- memcpy(cfg, irq_cfg_legacy, sizeof(irq_cfg_legacy));
-
- legacy_count = ARRAY_SIZE(irq_cfg_legacy);
- for (i = legacy_count; i < *da->nr; i++)
- init_one_irq_cfg(&cfg[i]);
-
-#ifdef CONFIG_HAVE_SPARSE_IRQ
- for (i = 1; i < *da->nr; i++)
- cfg[i-1].next = &cfg[i];
-
- irq_cfgx_free = &irq_cfgx[legacy_count];
- irq_cfgx[legacy_count - 1].next = NULL;
-#endif
-}
-
-#ifdef CONFIG_HAVE_SPARSE_IRQ
-/* need to be biger than size of irq_cfg_legacy */
-static int nr_irq_cfg = 32;
-
-static int __init parse_nr_irq_cfg(char *arg)
-{
- if (arg) {
- nr_irq_cfg = simple_strtoul(arg, NULL, 0);
- if (nr_irq_cfg < 32)
- nr_irq_cfg = 32;
- }
- return 0;
-}
-
-early_param("nr_irq_cfg", parse_nr_irq_cfg);
-
-#define for_each_irq_cfg(irqX, cfg) \
- for (cfg = irq_cfgx, irqX = cfg->irq; cfg; cfg = cfg->next, irqX = cfg ? cfg->irq : -1U)
-
-
-DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irq_cfg, PAGE_SIZE, init_work);
+#define for_each_irq_cfg(irq, cfg) \
+ for (irq = 0, cfg = irq_cfgx; irq < nr_irqs; irq++, cfg++)
static struct irq_cfg *irq_cfg(unsigned int irq)
{
- struct irq_cfg *cfg;
-
- cfg = irq_cfgx;
- while (cfg) {
- if (cfg->irq == irq)
- return cfg;
-
- cfg = cfg->next;
- }
-
- return NULL;
+ return irq < nr_irqs ? irq_cfgx + irq : NULL;
}
static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
{
- struct irq_cfg *cfg, *cfg_pri;
- unsigned long flags;
- int count = 0;
- int i;
-
- cfg_pri = cfg = irq_cfgx;
- while (cfg) {
- if (cfg->irq == irq)
- return cfg;
-
- cfg_pri = cfg;
- cfg = cfg->next;
- count++;
- }
-
- spin_lock_irqsave(&irq_cfg_lock, flags);
- if (!irq_cfgx_free) {
- unsigned long phys;
- unsigned long total_bytes;
- /*
- * we run out of pre-allocate ones, allocate more
- */
- printk(KERN_DEBUG "try to get more irq_cfg %d\n", nr_irq_cfg);
-
- total_bytes = sizeof(struct irq_cfg) * nr_irq_cfg;
- if (after_bootmem)
- cfg = kzalloc(total_bytes, GFP_ATOMIC);
- else
- cfg = __alloc_bootmem_nopanic(total_bytes, PAGE_SIZE, 0);
-
- if (!cfg)
- panic("please boot with nr_irq_cfg= %d\n", count * 2);
-
- phys = __pa(cfg);
- printk(KERN_DEBUG "irq_irq ==> [%#lx - %#lx]\n", phys, phys + total_bytes);
-
- for (i = 0; i < nr_irq_cfg; i++)
- init_one_irq_cfg(&cfg[i]);
-
- for (i = 1; i < nr_irq_cfg; i++)
- cfg[i-1].next = &cfg[i];
-
- irq_cfgx_free = cfg;
- }
-
- cfg = irq_cfgx_free;
- irq_cfgx_free = irq_cfgx_free->next;
- cfg->next = NULL;
- if (cfg_pri)
- cfg_pri->next = cfg;
- else
- irq_cfgx = cfg;
- cfg->irq = irq;
-
- spin_unlock_irqrestore(&irq_cfg_lock, flags);
-
- printk(KERN_DEBUG "found new irq_cfg for irq %d\n", cfg->irq);
-#ifdef CONFIG_HAVE_SPARSE_IRQ_DEBUG
- {
- /* dump the results */
- struct irq_cfg *cfg;
- unsigned long phys;
- unsigned long bytes = sizeof(struct irq_cfg);
-
- printk(KERN_DEBUG "=========================== %d\n", irq);
- printk(KERN_DEBUG "irq_cfg dump after get that for %d\n", irq);
- for_each_irq_cfg(cfg) {
- phys = __pa(cfg);
- printk(KERN_DEBUG "irq_cfg %d ==> [%#lx - %#lx]\n", cfg->irq, phys, phys + bytes);
- }
- printk(KERN_DEBUG "===========================\n");
- }
-#endif
- return cfg;
+ return irq_cfg(irq);
}
-#else
-
-#define for_each_irq_cfg(irq, cfg) \
- for (irq = 0, cfg = &irq_cfgx[irq]; irq < nr_irqs; irq++, cfg = &irq_cfgx[irq])
-
-DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irqs, PAGE_SIZE, init_work);
-struct irq_cfg *irq_cfg(unsigned int irq)
-{
- if (irq < nr_irqs)
- return &irq_cfgx[irq];
-
- return NULL;
-}
-struct irq_cfg *irq_cfg_alloc(unsigned int irq)
-{
- return irq_cfg(irq);
-}
+/*
+ * Rough estimation of how many shared IRQs there are, can be changed
+ * anytime.
+ */
+#define MAX_PLUS_SHARED_IRQS NR_IRQS
+#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
-#endif
/*
* This is performance-critical, we want to do it O(1)
*
struct irq_pin_list *next;
};
-static struct irq_pin_list *irq_2_pin_head;
-/* fill one page ? */
-static int nr_irq_2_pin = 0x100;
+static struct irq_pin_list irq_2_pin_head[PIN_MAP_SIZE];
static struct irq_pin_list *irq_2_pin_ptr;
-static void __init irq_2_pin_init_work(void *data)
+
+static void __init irq_2_pin_init(void)
{
- struct dyn_array *da = data;
- struct irq_pin_list *pin;
+ struct irq_pin_list *pin = irq_2_pin_head;
int i;
- pin = *da->name;
-
- for (i = 1; i < *da->nr; i++)
+ for (i = 1; i < PIN_MAP_SIZE; i++)
pin[i-1].next = &pin[i];
irq_2_pin_ptr = &pin[0];
}
-DEFINE_DYN_ARRAY(irq_2_pin_head, sizeof(struct irq_pin_list), nr_irq_2_pin, PAGE_SIZE, irq_2_pin_init_work);
static struct irq_pin_list *get_one_free_irq_2_pin(void)
{
- struct irq_pin_list *pin;
- int i;
-
- pin = irq_2_pin_ptr;
-
- if (pin) {
- irq_2_pin_ptr = pin->next;
- pin->next = NULL;
- return pin;
- }
-
- /*
- * we run out of pre-allocate ones, allocate more
- */
- printk(KERN_DEBUG "try to get more irq_2_pin %d\n", nr_irq_2_pin);
-
- if (after_bootmem)
- pin = kzalloc(sizeof(struct irq_pin_list)*nr_irq_2_pin,
- GFP_ATOMIC);
- else
- pin = __alloc_bootmem_nopanic(sizeof(struct irq_pin_list) *
- nr_irq_2_pin, PAGE_SIZE, 0);
+ struct irq_pin_list *pin = irq_2_pin_ptr;
if (!pin)
panic("can not get more irq_2_pin\n");
- for (i = 1; i < nr_irq_2_pin; i++)
- pin[i-1].next = &pin[i];
-
irq_2_pin_ptr = pin->next;
pin->next = NULL;
-
return pin;
}
static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
{
struct io_apic __iomem *io_apic = io_apic_base(apic);
- if (sis_apic_bug)
- writel(reg, &io_apic->index);
+
+ if (sis_apic_bug)
+ writel(reg, &io_apic->index);
writel(value, &io_apic->data);
}
cfg->irq_2_pin = entry;
entry->apic = apic;
entry->pin = pin;
- printk(KERN_DEBUG " 0 add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin);
return;
}
entry = entry->next;
entry->apic = apic;
entry->pin = pin;
- printk(KERN_DEBUG " x add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin);
}
/*
add_pin_to_irq(irq, newapic, newpin);
}
-#define __DO_ACTION(R, ACTION_ENABLE, ACTION_DISABLE, FINAL) \
- \
-{ \
- int pin; \
- struct irq_cfg *cfg; \
- struct irq_pin_list *entry; \
- \
- cfg = irq_cfg(irq); \
- entry = cfg->irq_2_pin; \
- for (;;) { \
- unsigned int reg; \
- if (!entry) \
- break; \
- pin = entry->pin; \
- reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \
- reg ACTION_DISABLE; \
- reg ACTION_ENABLE; \
- io_apic_modify(entry->apic, 0x10 + R + pin*2, reg); \
- FINAL; \
- if (!entry->next) \
- break; \
- entry = entry->next; \
- } \
-}
-
-#define DO_ACTION(name,R, ACTION_ENABLE, ACTION_DISABLE, FINAL) \
- \
- static void name##_IO_APIC_irq (unsigned int irq) \
- __DO_ACTION(R, ACTION_ENABLE, ACTION_DISABLE, FINAL)
-
-/* mask = 0 */
-DO_ACTION(__unmask, 0, |= 0, &= ~IO_APIC_REDIR_MASKED, )
+static inline void io_apic_modify_irq(unsigned int irq,
+ int mask_and, int mask_or,
+ void (*final)(struct irq_pin_list *entry))
+{
+ int pin;
+ struct irq_cfg *cfg;
+ struct irq_pin_list *entry;
+
+ cfg = irq_cfg(irq);
+ for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) {
+ unsigned int reg;
+ pin = entry->pin;
+ reg = io_apic_read(entry->apic, 0x10 + pin * 2);
+ reg &= mask_and;
+ reg |= mask_or;
+ io_apic_modify(entry->apic, 0x10 + pin * 2, reg);
+ if (final)
+ final(entry);
+ }
+}
+
+static void __unmask_IO_APIC_irq(unsigned int irq)
+{
+ io_apic_modify_irq(irq, ~IO_APIC_REDIR_MASKED, 0, NULL);
+}
#ifdef CONFIG_X86_64
-/*
- * Synchronize the IO-APIC and the CPU by doing
- * a dummy read from the IO-APIC
- */
-static inline void io_apic_sync(unsigned int apic)
+void io_apic_sync(struct irq_pin_list *entry)
{
- struct io_apic __iomem *io_apic = io_apic_base(apic);
+ /*
+ * Synchronize the IO-APIC and the CPU by doing
+ * a dummy read from the IO-APIC
+ */
+ struct io_apic __iomem *io_apic;
+ io_apic = io_apic_base(entry->apic);
readl(&io_apic->data);
}
-/* mask = 1 */
-DO_ACTION(__mask, 0, |= IO_APIC_REDIR_MASKED, &= ~0, io_apic_sync(entry->apic))
-
-#else
-
-/* mask = 1 */
-DO_ACTION(__mask, 0, |= IO_APIC_REDIR_MASKED, &= ~0, )
-
-/* mask = 1, trigger = 0 */
-DO_ACTION(__mask_and_edge, 0, |= IO_APIC_REDIR_MASKED, &= ~IO_APIC_REDIR_LEVEL_TRIGGER, )
+static void __mask_IO_APIC_irq(unsigned int irq)
+{
+ io_apic_modify_irq(irq, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
+}
+#else /* CONFIG_X86_32 */
+static void __mask_IO_APIC_irq(unsigned int irq)
+{
+ io_apic_modify_irq(irq, ~0, IO_APIC_REDIR_MASKED, NULL);
+}
-/* mask = 0, trigger = 1 */
-DO_ACTION(__unmask_and_level, 0, |= IO_APIC_REDIR_LEVEL_TRIGGER, &= ~IO_APIC_REDIR_MASKED, )
+static void __mask_and_edge_IO_APIC_irq(unsigned int irq)
+{
+ io_apic_modify_irq(irq, ~IO_APIC_REDIR_LEVEL_TRIGGER,
+ IO_APIC_REDIR_MASKED, NULL);
+}
-#endif
+static void __unmask_and_level_IO_APIC_irq(unsigned int irq)
+{
+ io_apic_modify_irq(irq, ~IO_APIC_REDIR_MASKED,
+ IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
+}
+#endif /* CONFIG_X86_32 */
static void mask_IO_APIC_irq (unsigned int irq)
{
kzalloc(sizeof(struct IO_APIC_route_entry) *
nr_ioapic_registers[apic], GFP_KERNEL);
if (!early_ioapic_entries[apic])
- return -ENOMEM;
+ goto nomem;
}
for (apic = 0; apic < nr_ioapics; apic++)
ioapic_write_entry(apic, pin, entry);
}
}
+
return 0;
+
+nomem:
+ while (apic >= 0)
+ kfree(early_ioapic_entries[apic--]);
+ memset(early_ioapic_entries, 0,
+ ARRAY_SIZE(early_ioapic_entries));
+
+ return -ENOMEM;
}
void restore_IO_APIC_setup(void)
{
int apic, pin;
- for (apic = 0; apic < nr_ioapics; apic++)
+ for (apic = 0; apic < nr_ioapics; apic++) {
+ if (!early_ioapic_entries[apic])
+ break;
for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
ioapic_write_entry(apic, pin,
early_ioapic_entries[apic][pin]);
+ kfree(early_ioapic_entries[apic]);
+ early_ioapic_entries[apic] = NULL;
+ }
}
void reinit_intr_remapped_IO_APIC(int intr_remapping)
while (i < apic)
irq += nr_ioapic_registers[i++];
irq += pin;
- /*
+ /*
* For MPS mode, so far only needed by ES7000 platform
*/
- if (ioapic_renumber_irq)
- irq = ioapic_renumber_irq(apic, irq);
+ if (ioapic_renumber_irq)
+ irq = ioapic_renumber_irq(apic, irq);
}
#ifdef CONFIG_X86_32
#ifdef CONFIG_X86_32
static inline int IO_APIC_irq_trigger(int irq)
{
- int apic, idx, pin;
+ int apic, idx, pin;
- for (apic = 0; apic < nr_ioapics; apic++) {
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
- idx = find_irq_entry(apic, pin, mp_INT);
- if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin)))
- return irq_trigger(idx);
- }
- }
- /*
+ for (apic = 0; apic < nr_ioapics; apic++) {
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ idx = find_irq_entry(apic, pin, mp_INT);
+ if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin)))
+ return irq_trigger(idx);
+ }
+ }
+ /*
* nonexistent IRQs are edge default
*/
- return 0;
+ return 0;
}
#else
static inline int IO_APIC_irq_trigger(int irq)
{
struct irq_desc *desc;
- /* first time to use this irq_desc */
- if (irq < 16)
- desc = irq_to_desc(irq);
- else
- desc = irq_to_desc_alloc(irq);
+ desc = irq_to_desc(irq);
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL)
static void __init setup_IO_APIC_irqs(void)
{
- int apic, pin, idx, irq, first_notcon = 1;
+ int apic, pin, idx, irq;
+ int notcon = 0;
apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
for (apic = 0; apic < nr_ioapics; apic++) {
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
-
- idx = find_irq_entry(apic,pin,mp_INT);
- if (idx == -1) {
- if (first_notcon) {
- apic_printk(APIC_VERBOSE, KERN_DEBUG " IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mp_apicid, pin);
- first_notcon = 0;
- } else
- apic_printk(APIC_VERBOSE, ", %d-%d", mp_ioapics[apic].mp_apicid, pin);
- continue;
- }
- if (!first_notcon) {
- apic_printk(APIC_VERBOSE, " not connected.\n");
- first_notcon = 1;
- }
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+
+ idx = find_irq_entry(apic, pin, mp_INT);
+ if (idx == -1) {
+ if (!notcon) {
+ notcon = 1;
+ apic_printk(APIC_VERBOSE,
+ KERN_DEBUG " %d-%d",
+ mp_ioapics[apic].mp_apicid,
+ pin);
+ } else
+ apic_printk(APIC_VERBOSE, " %d-%d",
+ mp_ioapics[apic].mp_apicid,
+ pin);
+ continue;
+ }
+ if (notcon) {
+ apic_printk(APIC_VERBOSE,
+ " (apicid-pin) not connected\n");
+ notcon = 0;
+ }
- irq = pin_2_irq(idx, apic, pin);
+ irq = pin_2_irq(idx, apic, pin);
#ifdef CONFIG_X86_32
- if (multi_timer_check(apic, irq))
- continue;
+ if (multi_timer_check(apic, irq))
+ continue;
#endif
- add_pin_to_irq(irq, apic, pin);
+ add_pin_to_irq(irq, apic, pin);
- setup_IO_APIC_irq(apic, pin, irq,
- irq_trigger(idx), irq_polarity(idx));
- }
+ setup_IO_APIC_irq(apic, pin, irq,
+ irq_trigger(idx), irq_polarity(idx));
+ }
}
- if (!first_notcon)
- apic_printk(APIC_VERBOSE, " not connected.\n");
+ if (notcon)
+ apic_printk(APIC_VERBOSE,
+ " (apicid-pin) not connected\n");
}
/*
reg_01.raw = io_apic_read(apic, 1);
if (reg_01.bits.version >= 0x10)
reg_02.raw = io_apic_read(apic, 2);
- if (reg_01.bits.version >= 0x20)
- reg_03.raw = io_apic_read(apic, 3);
+ if (reg_01.bits.version >= 0x20)
+ reg_03.raw = io_apic_read(apic, 3);
spin_unlock_irqrestore(&ioapic_lock, flags);
printk("\n");
#else
static int ioapic_retrigger_irq(unsigned int irq)
{
- send_IPI_self(irq_cfg(irq)->vector);
+ send_IPI_self(irq_cfg(irq)->vector);
- return 1;
+ return 1;
}
#endif
if (io_apic_level_ack_pending(irq)) {
/*
- * Interrupt in progress. Migrating irq now will change the
+ * Interrupt in progress. Migrating irq now will change the
* vector information in the IO-APIC RTE and that will confuse
* the EOI broadcast performed by cpu.
* So, delay the irq migration to the next instance.
ack_APIC_irq();
}
-#ifdef CONFIG_X86_32
atomic_t irq_mis_count;
-#endif
static void ack_apic_level(unsigned int irq)
{
}
static struct irq_chip ioapic_chip __read_mostly = {
- .name = "IO-APIC",
- .startup = startup_ioapic_irq,
- .mask = mask_IO_APIC_irq,
- .unmask = unmask_IO_APIC_irq,
- .ack = ack_apic_edge,
- .eoi = ack_apic_level,
+ .name = "IO-APIC",
+ .startup = startup_ioapic_irq,
+ .mask = mask_IO_APIC_irq,
+ .unmask = unmask_IO_APIC_irq,
+ .ack = ack_apic_edge,
+ .eoi = ack_apic_level,
#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity_irq,
+ .set_affinity = set_ioapic_affinity_irq,
#endif
.retrigger = ioapic_retrigger_irq,
};
#ifdef CONFIG_INTR_REMAP
static struct irq_chip ir_ioapic_chip __read_mostly = {
- .name = "IR-IO-APIC",
- .startup = startup_ioapic_irq,
- .mask = mask_IO_APIC_irq,
- .unmask = unmask_IO_APIC_irq,
- .ack = ack_x2apic_edge,
- .eoi = ack_x2apic_level,
+ .name = "IR-IO-APIC",
+ .startup = startup_ioapic_irq,
+ .mask = mask_IO_APIC_irq,
+ .unmask = unmask_IO_APIC_irq,
+ .ack = ack_x2apic_edge,
+ .eoi = ack_x2apic_level,
#ifdef CONFIG_SMP
- .set_affinity = set_ir_ioapic_affinity_irq,
+ .set_affinity = set_ir_ioapic_affinity_irq,
#endif
.retrigger = ioapic_retrigger_irq,
};
local_irq_save(flags);
- ver = apic_read(APIC_LVR);
- ver = GET_APIC_VERSION(ver);
+ ver = apic_read(APIC_LVR);
+ ver = GET_APIC_VERSION(ver);
/*
* get/set the timer IRQ vector:
io_apic_irqs = ~PIC_IRQS;
apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n");
- /*
+ /*
* Set up IO-APIC IRQ routing.
*/
#ifdef CONFIG_X86_32
- if (!acpi_ioapic)
- setup_ioapic_ids_from_mpc();
+ if (!acpi_ioapic)
+ setup_ioapic_ids_from_mpc();
#endif
sync_Arb_IDs();
setup_IO_APIC_irqs();
static int __init io_apic_bug_finalize(void)
{
- if (sis_apic_bug == -1)
- sis_apic_bug = 0;
- return 0;
+ if (sis_apic_bug == -1)
+ sis_apic_bug = 0;
+ return 0;
}
late_initcall(io_apic_bug_finalize);
unsigned long flags;
struct irq_cfg *cfg_new;
-#ifndef CONFIG_HAVE_SPARSE_IRQ
irq_want = nr_irqs - 1;
-#endif
irq = 0;
spin_lock_irqsave(&vector_lock, flags);
if (index < 0) {
printk(KERN_ERR
"Unable to allocate %d IRTE for PCI %s\n", nvec,
- pci_name(dev));
+ pci_name(dev));
return -ENOSPC;
}
return index;
#endif
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
+ dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI/MSI-X\n", irq);
+
return 0;
}
}
#endif
+#ifdef CONFIG_HPET_TIMER
+
+#ifdef CONFIG_SMP
+static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
+{
+ struct irq_cfg *cfg;
+ struct irq_desc *desc;
+ struct msi_msg msg;
+ unsigned int dest;
+ cpumask_t tmp;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ return;
+
+ if (assign_irq_vector(irq, mask))
+ return;
+
+ cfg = irq_cfg(irq);
+ cpus_and(tmp, cfg->domain, mask);
+ dest = cpu_mask_to_apicid(tmp);
+
+ hpet_msi_read(irq, &msg);
+
+ msg.data &= ~MSI_DATA_VECTOR_MASK;
+ msg.data |= MSI_DATA_VECTOR(cfg->vector);
+ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+ hpet_msi_write(irq, &msg);
+ desc = irq_to_desc(irq);
+ desc->affinity = mask;
+}
+#endif /* CONFIG_SMP */
+
+struct irq_chip hpet_msi_type = {
+ .name = "HPET_MSI",
+ .unmask = hpet_msi_unmask,
+ .mask = hpet_msi_mask,
+ .ack = ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = hpet_msi_set_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_hpet_msi(unsigned int irq)
+{
+ int ret;
+ struct msi_msg msg;
+
+ ret = msi_compose_msg(NULL, irq, &msg);
+ if (ret < 0)
+ return ret;
+
+ hpet_msi_write(irq, &msg);
+ set_irq_chip_and_handler_name(irq, &hpet_msi_type, handle_edge_irq,
+ "edge");
+
+ return 0;
+}
+#endif
+
#endif /* CONFIG_PCI_MSI */
/*
* Hypertransport interrupt support
set_irq_chip_and_handler_name(irq, &ht_irq_chip,
handle_edge_irq, "edge");
+
+ dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
}
return err;
}
#endif /* CONFIG_HT_IRQ */
+#ifdef CONFIG_X86_64
+/*
+ * Re-target the irq to the specified CPU and enable the specified MMR located
+ * on the specified blade to allow the sending of MSIs to the specified CPU.
+ */
+int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
+ unsigned long mmr_offset)
+{
+ const cpumask_t *eligible_cpu = get_cpu_mask(cpu);
+ struct irq_cfg *cfg;
+ int mmr_pnode;
+ unsigned long mmr_value;
+ struct uv_IO_APIC_route_entry *entry;
+ unsigned long flags;
+ int err;
+
+ err = assign_irq_vector(irq, *eligible_cpu);
+ if (err != 0)
+ return err;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
+ irq_name);
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ cfg = irq_cfg(irq);
+
+ mmr_value = 0;
+ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+ BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
+
+ entry->vector = cfg->vector;
+ entry->delivery_mode = INT_DELIVERY_MODE;
+ entry->dest_mode = INT_DEST_MODE;
+ entry->polarity = 0;
+ entry->trigger = 0;
+ entry->mask = 0;
+ entry->dest = cpu_mask_to_apicid(*eligible_cpu);
+
+ mmr_pnode = uv_blade_to_pnode(mmr_blade);
+ uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+
+ return irq;
+}
+
+/*
+ * Disable the specified MMR located on the specified blade so that MSIs are
+ * longer allowed to be sent.
+ */
+void arch_disable_uv_irq(int mmr_blade, unsigned long mmr_offset)
+{
+ unsigned long mmr_value;
+ struct uv_IO_APIC_route_entry *entry;
+ int mmr_pnode;
+
+ mmr_value = 0;
+ entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
+ BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
+
+ entry->mask = 1;
+
+ mmr_pnode = uv_blade_to_pnode(mmr_blade);
+ uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
+}
+#endif /* CONFIG_X86_64 */
+
int __init io_apic_get_redir_entries (int ioapic)
{
union IO_APIC_reg_01 reg_01;
/* something wrong ? */
if (nr < nr_min)
nr = nr_min;
+ if (WARN_ON(nr > NR_IRQS))
+ nr = NR_IRQS;
return nr;
}
void __init ioapic_init_mappings(void)
{
unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
- int i;
struct resource *ioapic_res;
+ int i;
+ irq_2_pin_init();
ioapic_res = ioapic_setup_resources();
for (i = 0; i < nr_ioapics; i++) {
if (smp_found_config) {
ioapic_phys = mp_ioapics[i].mp_apicaddr;
#ifdef CONFIG_X86_32
- if (!ioapic_phys) {
- printk(KERN_ERR
- "WARNING: bogus zero IO-APIC "
- "address found in MPTABLE, "
- "disabling IO/APIC support!\n");
- smp_found_config = 0;
- skip_ioapic_setup = 1;
- goto fake_ioapic_page;
- }
+ if (!ioapic_phys) {
+ printk(KERN_ERR
+ "WARNING: bogus zero IO-APIC "
+ "address found in MPTABLE, "
+ "disabling IO/APIC support!\n");
+ smp_found_config = 0;
+ skip_ioapic_setup = 1;
+ goto fake_ioapic_page;
+ }
#endif
} else {
#ifdef CONFIG_X86_32