#include <linux/bootmem.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
+#include <linux/slab.h>
#include <asm/ptrace.h>
#include <asm/signal.h>
static struct mpic *mpics;
static struct mpic *mpic_primary;
-static DEFINE_SPINLOCK(mpic_lock);
+static DEFINE_RAW_SPINLOCK(mpic_lock);
#ifdef CONFIG_PPC32 /* XXX for now */
#ifdef CONFIG_IRQ_ALL_CPUS
MPIC_CPU_WHOAMI,
MPIC_CPU_INTACK,
MPIC_CPU_EOI,
+ MPIC_CPU_MCACK,
MPIC_IRQ_BASE,
MPIC_IRQ_STRIDE,
TSI108_CPU_WHOAMI,
TSI108_CPU_INTACK,
TSI108_CPU_EOI,
+ TSI108_CPU_MCACK,
TSI108_IRQ_BASE,
TSI108_IRQ_STRIDE,
switch(type) {
#ifdef CONFIG_PPC_DCR
case mpic_access_dcr:
- return dcr_write(rb->dhost, reg, value);
+ dcr_write(rb->dhost, reg, value);
+ break;
#endif
case mpic_access_mmio_be:
- return out_be32(rb->base + (reg >> 2), value);
+ out_be32(rb->base + (reg >> 2), value);
+ break;
case mpic_access_mmio_le:
default:
- return out_le32(rb->base + (reg >> 2), value);
+ out_le32(rb->base + (reg >> 2), value);
+ break;
}
}
{
unsigned int isu = src_no >> mpic->isu_shift;
unsigned int idx = src_no & mpic->isu_mask;
+ unsigned int val;
+ val = _mpic_read(mpic->reg_type, &mpic->isus[isu],
+ reg + (idx * MPIC_INFO(IRQ_STRIDE)));
#ifdef CONFIG_MPIC_BROKEN_REGREAD
if (reg == 0)
- return mpic->isu_reg0_shadow[idx];
- else
+ val = (val & (MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY)) |
+ mpic->isu_reg0_shadow[src_no];
#endif
- return _mpic_read(mpic->reg_type, &mpic->isus[isu],
- reg + (idx * MPIC_INFO(IRQ_STRIDE)));
+ return val;
}
static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
#ifdef CONFIG_MPIC_BROKEN_REGREAD
if (reg == 0)
- mpic->isu_reg0_shadow[idx] = value;
+ mpic->isu_reg0_shadow[src_no] =
+ value & ~(MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY);
#endif
}
*/
-static void _mpic_map_mmio(struct mpic *mpic, unsigned long phys_addr,
+static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr,
struct mpic_reg_bank *rb, unsigned int offset,
unsigned int size)
{
}
#ifdef CONFIG_PPC_DCR
-static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb,
+static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node,
+ struct mpic_reg_bank *rb,
unsigned int offset, unsigned int size)
{
const u32 *dbasep;
- dbasep = of_get_property(mpic->irqhost->of_node, "dcr-reg", NULL);
+ dbasep = of_get_property(node, "dcr-reg", NULL);
- rb->dhost = dcr_map(mpic->irqhost->of_node, *dbasep + offset, size);
+ rb->dhost = dcr_map(node, *dbasep + offset, size);
BUG_ON(!DCR_MAP_OK(rb->dhost));
}
-static inline void mpic_map(struct mpic *mpic, unsigned long phys_addr,
- struct mpic_reg_bank *rb, unsigned int offset,
- unsigned int size)
+static inline void mpic_map(struct mpic *mpic, struct device_node *node,
+ phys_addr_t phys_addr, struct mpic_reg_bank *rb,
+ unsigned int offset, unsigned int size)
{
if (mpic->flags & MPIC_USES_DCR)
- _mpic_map_dcr(mpic, rb, offset, size);
+ _mpic_map_dcr(mpic, node, rb, offset, size);
else
_mpic_map_mmio(mpic, phys_addr, rb, offset, size);
}
#else /* CONFIG_PPC_DCR */
-#define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s)
+#define mpic_map(m,n,p,b,o,s) _mpic_map_mmio(m,p,b,o,s)
#endif /* !CONFIG_PPC_DCR */
unsigned int mask = 1U << (fixup->index & 0x1f);
writel(mask, fixup->applebase + soff);
} else {
- spin_lock(&mpic->fixup_lock);
+ raw_spin_lock(&mpic->fixup_lock);
writeb(0x11 + 2 * fixup->index, fixup->base + 2);
writel(fixup->data, fixup->base + 4);
- spin_unlock(&mpic->fixup_lock);
+ raw_spin_unlock(&mpic->fixup_lock);
}
}
DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n",
source, irqflags, fixup->index);
- spin_lock_irqsave(&mpic->fixup_lock, flags);
+ raw_spin_lock_irqsave(&mpic->fixup_lock, flags);
/* Enable and configure */
writeb(0x10 + 2 * fixup->index, fixup->base + 2);
tmp = readl(fixup->base + 4);
if (irqflags & IRQ_LEVEL)
tmp |= 0x22;
writel(tmp, fixup->base + 4);
- spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+ raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags);
#ifdef CONFIG_PM
/* use the lowest bit inverted to the actual HW,
DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags);
/* Disable */
- spin_lock_irqsave(&mpic->fixup_lock, flags);
+ raw_spin_lock_irqsave(&mpic->fixup_lock, flags);
writeb(0x10 + 2 * fixup->index, fixup->base + 2);
tmp = readl(fixup->base + 4);
tmp |= 1;
writel(tmp, fixup->base + 4);
- spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+ raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags);
#ifdef CONFIG_PM
/* use the lowest bit inverted to the actual HW,
addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32);
}
- printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%lx\n",
+ printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%llx\n",
PCI_SLOT(devfn), PCI_FUNC(devfn),
flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr);
printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n");
/* Allocate fixups array */
- mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup));
+ mpic->fixups = kzalloc(128 * sizeof(*mpic->fixups), GFP_KERNEL);
BUG_ON(mpic->fixups == NULL);
- memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup));
/* Init spinlock */
- spin_lock_init(&mpic->fixup_lock);
+ raw_spin_lock_init(&mpic->fixup_lock);
/* Map U3 config space. We assume all IO-APICs are on the primary bus
* so we only need to map 64kB.
#endif /* CONFIG_MPIC_U3_HT_IRQS */
+#ifdef CONFIG_SMP
+static int irq_choose_cpu(const cpumask_t *mask)
+{
+ int cpuid;
+
+ if (cpumask_equal(mask, cpu_all_mask)) {
+ static int irq_rover;
+ static DEFINE_RAW_SPINLOCK(irq_rover_lock);
+ unsigned long flags;
+
+ /* Round-robin distribution... */
+ do_round_robin:
+ raw_spin_lock_irqsave(&irq_rover_lock, flags);
+
+ while (!cpu_online(irq_rover)) {
+ if (++irq_rover >= NR_CPUS)
+ irq_rover = 0;
+ }
+ cpuid = irq_rover;
+ do {
+ if (++irq_rover >= NR_CPUS)
+ irq_rover = 0;
+ } while (!cpu_online(irq_rover));
+
+ raw_spin_unlock_irqrestore(&irq_rover_lock, flags);
+ } else {
+ cpuid = cpumask_first_and(mask, cpu_online_mask);
+ if (cpuid >= nr_cpu_ids)
+ goto do_round_robin;
+ }
+
+ return get_hard_smp_processor_id(cpuid);
+}
+#else
+static int irq_choose_cpu(const cpumask_t *mask)
+{
+ return hard_smp_processor_id();
+}
+#endif
#define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
/* Find an mpic associated with a given linux interrupt */
-static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi)
+static struct mpic *mpic_find(unsigned int irq)
{
- unsigned int src = mpic_irq_to_hw(irq);
- struct mpic *mpic;
-
if (irq < NUM_ISA_INTERRUPTS)
return NULL;
- mpic = irq_desc[irq].chip_data;
+ return irq_to_desc(irq)->chip_data;
+}
- if (is_ipi)
- *is_ipi = (src >= mpic->ipi_vecs[0] &&
- src <= mpic->ipi_vecs[3]);
+/* Determine if the linux irq is an IPI */
+static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq)
+{
+ unsigned int src = mpic_irq_to_hw(irq);
- return mpic;
+ return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]);
}
+
/* Convert a cpu mask from logical to physical cpu numbers. */
static inline u32 mpic_physmask(u32 cpumask)
{
/* Get the mpic structure from the IPI number */
static inline struct mpic * mpic_from_ipi(unsigned int ipi)
{
- return irq_desc[ipi].chip_data;
+ return irq_to_desc(ipi)->chip_data;
}
#endif
/* Get the mpic structure from the irq number */
static inline struct mpic * mpic_from_irq(unsigned int irq)
{
- return irq_desc[irq].chip_data;
+ return irq_to_desc(irq)->chip_data;
}
/* Send an EOI */
(void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI));
}
-#ifdef CONFIG_SMP
-static irqreturn_t mpic_ipi_action(int irq, void *dev_id)
-{
- struct mpic *mpic;
-
- mpic = mpic_find(irq, NULL);
- smp_message_recv(mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]);
-
- return IRQ_HANDLED;
-}
-#endif /* CONFIG_SMP */
-
/*
* Linux descriptor level callbacks
*/
mpic_unmask_irq(irq);
- if (irq_desc[irq].status & IRQ_LEVEL)
+ if (irq_to_desc(irq)->status & IRQ_LEVEL)
mpic_ht_end_irq(mpic, src);
}
unsigned int src = mpic_irq_to_hw(irq);
mpic_unmask_irq(irq);
- mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status);
+ mpic_startup_ht_interrupt(mpic, src, irq_to_desc(irq)->status);
return 0;
}
struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(irq);
- mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status);
+ mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(irq)->status);
mpic_mask_irq(irq);
}
* latched another edge interrupt coming in anyway
*/
- if (irq_desc[irq].status & IRQ_LEVEL)
+ if (irq_to_desc(irq)->status & IRQ_LEVEL)
mpic_ht_end_irq(mpic, src);
mpic_eoi(mpic);
}
#endif /* CONFIG_SMP */
-void mpic_set_affinity(unsigned int irq, cpumask_t cpumask)
+int mpic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
{
struct mpic *mpic = mpic_from_irq(irq);
unsigned int src = mpic_irq_to_hw(irq);
- cpumask_t tmp;
+ if (mpic->flags & MPIC_SINGLE_DEST_CPU) {
+ int cpuid = irq_choose_cpu(cpumask);
- cpus_and(tmp, cpumask, cpu_online_map);
+ mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
+ } else {
+ cpumask_t tmp;
+
+ cpumask_and(&tmp, cpumask, cpu_online_mask);
- mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
- mpic_physmask(cpus_addr(tmp)[0]));
+ mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
+ mpic_physmask(cpus_addr(tmp)[0]));
+ }
+
+ return 0;
}
static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
{
struct mpic *mpic = mpic_from_irq(virq);
unsigned int src = mpic_irq_to_hw(virq);
- struct irq_desc *desc = get_irq_desc(virq);
+ struct irq_desc *desc = irq_to_desc(virq);
unsigned int vecpri, vold, vnew;
DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
return 0;
}
+void mpic_set_vector(unsigned int virq, unsigned int vector)
+{
+ struct mpic *mpic = mpic_from_irq(virq);
+ unsigned int src = mpic_irq_to_hw(virq);
+ unsigned int vecpri;
+
+ DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
+ mpic, virq, src, vector);
+
+ if (src >= mpic->irq_count)
+ return;
+
+ vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
+ vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK);
+ vecpri |= vector;
+ mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+}
+
static struct irq_chip mpic_irq_chip = {
.mask = mpic_mask_irq,
.unmask = mpic_unmask_irq,
}
static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
- u32 *intspec, unsigned int intsize,
+ const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
const char *name)
{
struct mpic *mpic;
- u32 reg;
+ u32 greg_feature;
const char *vers;
int i;
int intvec_top;
u64 paddr = phys_addr;
- mpic = alloc_bootmem(sizeof(struct mpic));
+ mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);
if (mpic == NULL)
return NULL;
-
- memset(mpic, 0, sizeof(struct mpic));
- mpic->name = name;
- mpic->irqhost = irq_alloc_host(of_node_get(node), IRQ_HOST_MAP_LINEAR,
- isu_size, &mpic_host_ops,
- flags & MPIC_LARGE_VECTORS ? 2048 : 256);
- if (mpic->irqhost == NULL) {
- of_node_put(node);
- return NULL;
- }
+ mpic->name = name;
- mpic->irqhost->host_data = mpic;
mpic->hc_irq = mpic_irq_chip;
- mpic->hc_irq.typename = name;
+ mpic->hc_irq.name = name;
if (flags & MPIC_PRIMARY)
mpic->hc_irq.set_affinity = mpic_set_affinity;
#ifdef CONFIG_MPIC_U3_HT_IRQS
mpic->hc_ht_irq = mpic_irq_ht_chip;
- mpic->hc_ht_irq.typename = name;
+ mpic->hc_ht_irq.name = name;
if (flags & MPIC_PRIMARY)
mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
#endif /* CONFIG_MPIC_U3_HT_IRQS */
#ifdef CONFIG_SMP
mpic->hc_ipi = mpic_ipi_chip;
- mpic->hc_ipi.typename = name;
+ mpic->hc_ipi.name = name;
#endif /* CONFIG_SMP */
mpic->flags = flags;
/* Look for protected sources */
if (node) {
- unsigned int psize, bits, mapsize;
+ int psize;
+ unsigned int bits, mapsize;
const u32 *psrc =
of_get_property(node, "protected-sources", &psize);
if (psrc) {
psize /= 4;
bits = intvec_top + 1;
mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long);
- mpic->protected = alloc_bootmem(mapsize);
+ mpic->protected = kzalloc(mapsize, GFP_KERNEL);
BUG_ON(mpic->protected == NULL);
- memset(mpic->protected, 0, mapsize);
for (i = 0; i < psize; i++) {
if (psrc[i] > intvec_top)
continue;
* in, try to obtain one
*/
if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) {
- const u32 *reg;
- reg = of_get_property(node, "reg", NULL);
+ const u32 *reg = of_get_property(node, "reg", NULL);
BUG_ON(reg == NULL);
paddr = of_translate_address(node, reg);
BUG_ON(paddr == OF_BAD_ADDR);
}
/* Map the global registers */
- mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
- mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
+ mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
+ mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
/* Reset */
if (flags & MPIC_WANTS_RESET) {
mb();
}
+ /* CoreInt */
+ if (flags & MPIC_ENABLE_COREINT)
+ mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
+ mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
+ | MPIC_GREG_GCONF_COREINT);
+
+ if (flags & MPIC_ENABLE_MCK)
+ mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
+ mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
+ | MPIC_GREG_GCONF_MCK);
+
/* Read feature register, calculate num CPUs and, for non-ISU
* MPICs, num sources as well. On ISU MPICs, sources are counted
* as ISUs are added
*/
- reg = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
- mpic->num_cpus = ((reg & MPIC_GREG_FEATURE_LAST_CPU_MASK)
+ greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
+ mpic->num_cpus = ((greg_feature & MPIC_GREG_FEATURE_LAST_CPU_MASK)
>> MPIC_GREG_FEATURE_LAST_CPU_SHIFT) + 1;
- if (isu_size == 0)
- mpic->num_sources = ((reg & MPIC_GREG_FEATURE_LAST_SRC_MASK)
- >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
+ if (isu_size == 0) {
+ if (flags & MPIC_BROKEN_FRR_NIRQS)
+ mpic->num_sources = mpic->irq_count;
+ else
+ mpic->num_sources =
+ ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
+ >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
+ }
/* Map the per-CPU registers */
for (i = 0; i < mpic->num_cpus; i++) {
- mpic_map(mpic, paddr, &mpic->cpuregs[i],
+ mpic_map(mpic, node, paddr, &mpic->cpuregs[i],
MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE),
0x1000);
}
/* Initialize main ISU if none provided */
if (mpic->isu_size == 0) {
mpic->isu_size = mpic->num_sources;
- mpic_map(mpic, paddr, &mpic->isus[0],
+ mpic_map(mpic, node, paddr, &mpic->isus[0],
MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
}
mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
mpic->isu_mask = (1 << mpic->isu_shift) - 1;
+ mpic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR,
+ isu_size ? isu_size : mpic->num_sources,
+ &mpic_host_ops,
+ flags & MPIC_LARGE_VECTORS ? 2048 : 256);
+ if (mpic->irqhost == NULL)
+ return NULL;
+
+ mpic->irqhost->host_data = mpic;
+
/* Display version */
- switch (reg & MPIC_GREG_FEATURE_VERSION_MASK) {
+ switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) {
case 1:
vers = "1.0";
break;
BUG_ON(isu_num >= MPIC_MAX_ISU);
- mpic_map(mpic, paddr, &mpic->isus[isu_num], 0,
+ mpic_map(mpic, mpic->irqhost->of_node,
+ paddr, &mpic->isus[isu_num], 0,
MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+
if ((isu_first + mpic->isu_size) > mpic->num_sources)
mpic->num_sources = isu_first + mpic->isu_size;
}
void __init mpic_init(struct mpic *mpic)
{
int i;
+ int cpu;
BUG_ON(mpic->num_sources == 0);
mpic_u3msi_init(mpic);
}
+ mpic_pasemi_msi_init(mpic);
+
+ if (mpic->flags & MPIC_PRIMARY)
+ cpu = hard_smp_processor_id();
+ else
+ cpu = 0;
+
for (i = 0; i < mpic->num_sources; i++) {
/* start with vector = source number, and masked */
u32 vecpri = MPIC_VECPRI_MASK | i |
continue;
/* init hw */
mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
- mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
- 1 << hard_smp_processor_id());
+ mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
}
/* Init spurious vector */
mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
| MPIC_GREG_GCONF_8259_PTHROU_DIS);
+ if (mpic->flags & MPIC_NO_BIAS)
+ mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
+ mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
+ | MPIC_GREG_GCONF_NO_BIAS);
+
/* Set current processor priority to 0 */
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
#ifdef CONFIG_PM
/* allocate memory to save mpic state */
- mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save));
+ mpic->save_data = kmalloc(mpic->num_sources * sizeof(*mpic->save_data),
+ GFP_KERNEL);
BUG_ON(mpic->save_data == NULL);
#endif
}
unsigned long flags;
u32 v;
- spin_lock_irqsave(&mpic_lock, flags);
+ raw_spin_lock_irqsave(&mpic_lock, flags);
v = mpic_read(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1);
if (enable)
v |= MPIC_GREG_GLOBAL_CONF_1_SIE;
else
v &= ~MPIC_GREG_GLOBAL_CONF_1_SIE;
mpic_write(mpic->gregs, MPIC_GREG_GLOBAL_CONF_1, v);
- spin_unlock_irqrestore(&mpic_lock, flags);
+ raw_spin_unlock_irqrestore(&mpic_lock, flags);
}
void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
{
- int is_ipi;
- struct mpic *mpic = mpic_find(irq, &is_ipi);
+ struct mpic *mpic = mpic_find(irq);
unsigned int src = mpic_irq_to_hw(irq);
unsigned long flags;
u32 reg;
- spin_lock_irqsave(&mpic_lock, flags);
- if (is_ipi) {
+ if (!mpic)
+ return;
+
+ raw_spin_lock_irqsave(&mpic_lock, flags);
+ if (mpic_is_ipi(mpic, irq)) {
reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) &
~MPIC_VECPRI_PRIORITY_MASK;
mpic_ipi_write(src - mpic->ipi_vecs[0],
mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI),
reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
}
- spin_unlock_irqrestore(&mpic_lock, flags);
-}
-
-unsigned int mpic_irq_get_priority(unsigned int irq)
-{
- int is_ipi;
- struct mpic *mpic = mpic_find(irq, &is_ipi);
- unsigned int src = mpic_irq_to_hw(irq);
- unsigned long flags;
- u32 reg;
-
- spin_lock_irqsave(&mpic_lock, flags);
- if (is_ipi)
- reg = mpic_ipi_read(src = mpic->ipi_vecs[0]);
- else
- reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
- spin_unlock_irqrestore(&mpic_lock, flags);
- return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT;
+ raw_spin_unlock_irqrestore(&mpic_lock, flags);
}
void mpic_setup_this_cpu(void)
DBG("%s: setup_this_cpu(%d)\n", mpic->name, hard_smp_processor_id());
- spin_lock_irqsave(&mpic_lock, flags);
+ raw_spin_lock_irqsave(&mpic_lock, flags);
/* let the mpic know we want intrs. default affinity is 0xffffffff
* until changed via /proc. That's how it's done on x86. If we want
/* Set current processor priority to 0 */
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
- spin_unlock_irqrestore(&mpic_lock, flags);
+ raw_spin_unlock_irqrestore(&mpic_lock, flags);
#endif /* CONFIG_SMP */
}
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio);
}
-/*
- * XXX: someone who knows mpic should check this.
- * do we need to eoi the ipi including for kexec cpu here (see xics comments)?
- * or can we reset the mpic in the new kernel?
- */
void mpic_teardown_this_cpu(int secondary)
{
struct mpic *mpic = mpic_primary;
BUG_ON(mpic == NULL);
DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id());
- spin_lock_irqsave(&mpic_lock, flags);
+ raw_spin_lock_irqsave(&mpic_lock, flags);
/* let the mpic know we don't want intrs. */
for (i = 0; i < mpic->num_sources ; i++)
/* Set current processor priority to max */
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
+ /* We need to EOI the IPI since not all platforms reset the MPIC
+ * on boot and new interrupts wouldn't get delivered otherwise.
+ */
+ mpic_eoi(mpic);
- spin_unlock_irqrestore(&mpic_lock, flags);
+ raw_spin_unlock_irqrestore(&mpic_lock, flags);
}
mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
}
-unsigned int mpic_get_one_irq(struct mpic *mpic)
+static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg)
{
u32 src;
- src = mpic_cpu_read(MPIC_INFO(CPU_INTACK)) & MPIC_INFO(VECPRI_VECTOR_MASK);
+ src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK);
#ifdef DEBUG_LOW
- DBG("%s: get_one_irq(): %d\n", mpic->name, src);
+ DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src);
#endif
if (unlikely(src == mpic->spurious_vec)) {
if (mpic->flags & MPIC_SPV_EOI)
return irq_linear_revmap(mpic->irqhost, src);
}
+unsigned int mpic_get_one_irq(struct mpic *mpic)
+{
+ return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK));
+}
+
unsigned int mpic_get_irq(void)
{
struct mpic *mpic = mpic_primary;
return mpic_get_one_irq(mpic);
}
+unsigned int mpic_get_coreint_irq(void)
+{
+#ifdef CONFIG_BOOKE
+ struct mpic *mpic = mpic_primary;
+ u32 src;
+
+ BUG_ON(mpic == NULL);
+
+ src = mfspr(SPRN_EPR);
+
+ if (unlikely(src == mpic->spurious_vec)) {
+ if (mpic->flags & MPIC_SPV_EOI)
+ mpic_eoi(mpic);
+ return NO_IRQ;
+ }
+ if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING "%s: Got protected source %d !\n",
+ mpic->name, (int)src);
+ return NO_IRQ;
+ }
+
+ return irq_linear_revmap(mpic->irqhost, src);
+#else
+ return NO_IRQ;
+#endif
+}
+
+unsigned int mpic_get_mcirq(void)
+{
+ struct mpic *mpic = mpic_primary;
+
+ BUG_ON(mpic == NULL);
+
+ return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK));
+}
#ifdef CONFIG_SMP
void mpic_request_ipis(void)
{
struct mpic *mpic = mpic_primary;
- int i, err;
- static char *ipi_names[] = {
- "IPI0 (call function)",
- "IPI1 (reschedule)",
- "IPI2 (unused)",
- "IPI3 (debugger break)",
- };
+ int i;
BUG_ON(mpic == NULL);
- printk(KERN_INFO "mpic: requesting IPIs ... \n");
+ printk(KERN_INFO "mpic: requesting IPIs...\n");
for (i = 0; i < 4; i++) {
unsigned int vipi = irq_create_mapping(mpic->irqhost,
mpic->ipi_vecs[0] + i);
if (vipi == NO_IRQ) {
- printk(KERN_ERR "Failed to map IPI %d\n", i);
- break;
- }
- err = request_irq(vipi, mpic_ipi_action,
- IRQF_DISABLED|IRQF_PERCPU,
- ipi_names[i], mpic);
- if (err) {
- printk(KERN_ERR "Request of irq %d for IPI %d failed\n",
- vipi, i);
- break;
+ printk(KERN_ERR "Failed to map %s\n", smp_ipi_name[i]);
+ continue;
}
+ smp_request_message_ipi(vipi, i);
}
}