summaryrefslogtreecommitdiff
path: root/arch/powerpc/sysdev/mpic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r--arch/powerpc/sysdev/mpic.c128
1 files changed, 82 insertions, 46 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index eb7021815e2d..f91c065bed5a 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -147,6 +147,16 @@ static u32 mpic_infos[][MPIC_IDX_END] = {
#endif /* CONFIG_MPIC_WEIRD */
+static inline unsigned int mpic_processor_id(struct mpic *mpic)
+{
+ unsigned int cpu = 0;
+
+ if (mpic->flags & MPIC_PRIMARY)
+ cpu = hard_smp_processor_id();
+
+ return cpu;
+}
+
/*
* Register accessor functions
*/
@@ -210,19 +220,14 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
{
- unsigned int cpu = 0;
+ unsigned int cpu = mpic_processor_id(mpic);
- if (mpic->flags & MPIC_PRIMARY)
- cpu = hard_smp_processor_id();
return _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], reg);
}
static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value)
{
- unsigned int cpu = 0;
-
- if (mpic->flags & MPIC_PRIMARY)
- cpu = hard_smp_processor_id();
+ unsigned int cpu = mpic_processor_id(mpic);
_mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], reg, value);
}
@@ -356,7 +361,7 @@ static inline void mpic_ht_end_irq(struct mpic *mpic, unsigned int source)
}
static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
- unsigned int irqflags)
+ bool level)
{
struct mpic_irq_fixup *fixup = &mpic->fixups[source];
unsigned long flags;
@@ -365,14 +370,14 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
if (fixup->base == NULL)
return;
- DBG("startup_ht_interrupt(0x%x, 0x%x) index: %d\n",
- source, irqflags, fixup->index);
+ DBG("startup_ht_interrupt(0x%x) index: %d\n",
+ source, fixup->index);
raw_spin_lock_irqsave(&mpic->fixup_lock, flags);
/* Enable and configure */
writeb(0x10 + 2 * fixup->index, fixup->base + 2);
tmp = readl(fixup->base + 4);
tmp &= ~(0x23U);
- if (irqflags & IRQ_LEVEL)
+ if (level)
tmp |= 0x22;
writel(tmp, fixup->base + 4);
raw_spin_unlock_irqrestore(&mpic->fixup_lock, flags);
@@ -384,8 +389,7 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
#endif
}
-static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
- unsigned int irqflags)
+static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source)
{
struct mpic_irq_fixup *fixup = &mpic->fixups[source];
unsigned long flags;
@@ -394,7 +398,7 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
if (fixup->base == NULL)
return;
- DBG("shutdown_ht_interrupt(0x%x, 0x%x)\n", source, irqflags);
+ DBG("shutdown_ht_interrupt(0x%x)\n", source);
/* Disable */
raw_spin_lock_irqsave(&mpic->fixup_lock, flags);
@@ -611,7 +615,7 @@ static struct mpic *mpic_find(unsigned int irq)
if (irq < NUM_ISA_INTERRUPTS)
return NULL;
- return get_irq_chip_data(irq);
+ return irq_get_chip_data(irq);
}
/* Determine if the linux irq is an IPI */
@@ -645,7 +649,7 @@ static inline struct mpic * mpic_from_ipi(struct irq_data *d)
/* Get the mpic structure from the irq number */
static inline struct mpic * mpic_from_irq(unsigned int irq)
{
- return get_irq_chip_data(irq);
+ return irq_get_chip_data(irq);
}
/* Get the mpic structure from the irq data */
@@ -733,7 +737,7 @@ static void mpic_unmask_ht_irq(struct irq_data *d)
mpic_unmask_irq(d);
- if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
+ if (irqd_is_level_type(d))
mpic_ht_end_irq(mpic, src);
}
@@ -743,7 +747,7 @@ static unsigned int mpic_startup_ht_irq(struct irq_data *d)
unsigned int src = mpic_irq_to_hw(d->irq);
mpic_unmask_irq(d);
- mpic_startup_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status);
+ mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d));
return 0;
}
@@ -753,7 +757,7 @@ static void mpic_shutdown_ht_irq(struct irq_data *d)
struct mpic *mpic = mpic_from_irq_data(d);
unsigned int src = mpic_irq_to_hw(d->irq);
- mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(d->irq)->status);
+ mpic_shutdown_ht_interrupt(mpic, src);
mpic_mask_irq(d);
}
@@ -770,7 +774,7 @@ static void mpic_end_ht_irq(struct irq_data *d)
* latched another edge interrupt coming in anyway
*/
- if (irq_to_desc(d->irq)->status & IRQ_LEVEL)
+ if (irqd_is_level_type(d))
mpic_ht_end_irq(mpic, src);
mpic_eoi(mpic);
}
@@ -859,7 +863,6 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
struct mpic *mpic = mpic_from_irq_data(d);
unsigned int src = mpic_irq_to_hw(d->irq);
- struct irq_desc *desc = irq_to_desc(d->irq);
unsigned int vecpri, vold, vnew;
DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
@@ -874,10 +877,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
if (flow_type == IRQ_TYPE_NONE)
flow_type = IRQ_TYPE_LEVEL_LOW;
- desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
- desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
- if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
- desc->status |= IRQ_LEVEL;
+ irqd_set_trigger_type(d, flow_type);
if (mpic_is_ht_interrupt(mpic, src))
vecpri = MPIC_VECPRI_POLARITY_POSITIVE |
@@ -892,7 +892,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
if (vold != vnew)
mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vnew);
- return 0;
+ return IRQ_SET_MASK_OK_NOCOPY;;
}
void mpic_set_vector(unsigned int virq, unsigned int vector)
@@ -913,6 +913,20 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
}
+void mpic_set_destination(unsigned int virq, unsigned int cpuid)
+{
+ struct mpic *mpic = mpic_from_irq(virq);
+ unsigned int src = mpic_irq_to_hw(virq);
+
+ DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",
+ mpic, virq, src, cpuid);
+
+ if (src >= mpic->irq_count)
+ return;
+
+ mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
+}
+
static struct irq_chip mpic_irq_chip = {
.irq_mask = mpic_mask_irq,
.irq_unmask = mpic_unmask_irq,
@@ -964,8 +978,8 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
WARN_ON(!(mpic->flags & MPIC_PRIMARY));
DBG("mpic: mapping as IPI\n");
- set_irq_chip_data(virq, mpic);
- set_irq_chip_and_handler(virq, &mpic->hc_ipi,
+ irq_set_chip_data(virq, mpic);
+ irq_set_chip_and_handler(virq, &mpic->hc_ipi,
handle_percpu_irq);
return 0;
}
@@ -987,11 +1001,21 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
DBG("mpic: mapping to irq chip @%p\n", chip);
- set_irq_chip_data(virq, mpic);
- set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq);
+ irq_set_chip_data(virq, mpic);
+ irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq);
/* Set default irq type */
- set_irq_type(virq, IRQ_TYPE_NONE);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+ /* If the MPIC was reset, then all vectors have already been
+ * initialized. Otherwise, a per source lazy initialization
+ * is done here.
+ */
+ if (!mpic_is_ipi(mpic, hw) && (mpic->flags & MPIC_NO_RESET)) {
+ mpic_set_vector(virq, hw);
+ mpic_set_destination(virq, mpic_processor_id(mpic));
+ mpic_irq_set_priority(virq, 8);
+ }
return 0;
}
@@ -1040,6 +1064,11 @@ static struct irq_host_ops mpic_host_ops = {
.xlate = mpic_host_xlate,
};
+static int mpic_reset_prohibited(struct device_node *node)
+{
+ return node && of_get_property(node, "pic-no-reset", NULL);
+}
+
/*
* Exported functions
*/
@@ -1160,7 +1189,15 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
/* Reset */
- if (flags & MPIC_WANTS_RESET) {
+
+ /* When using a device-node, reset requests are only honored if the MPIC
+ * is allowed to reset.
+ */
+ if (mpic_reset_prohibited(node))
+ mpic->flags |= MPIC_NO_RESET;
+
+ if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) {
+ printk(KERN_DEBUG "mpic: Resetting\n");
mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
| MPIC_GREG_GCONF_RESET);
@@ -1320,22 +1357,21 @@ void __init mpic_init(struct mpic *mpic)
mpic_pasemi_msi_init(mpic);
- if (mpic->flags & MPIC_PRIMARY)
- cpu = hard_smp_processor_id();
- else
- cpu = 0;
+ cpu = mpic_processor_id(mpic);
- for (i = 0; i < mpic->num_sources; i++) {
- /* start with vector = source number, and masked */
- u32 vecpri = MPIC_VECPRI_MASK | i |
- (8 << MPIC_VECPRI_PRIORITY_SHIFT);
+ if (!(mpic->flags & MPIC_NO_RESET)) {
+ for (i = 0; i < mpic->num_sources; i++) {
+ /* start with vector = source number, and masked */
+ u32 vecpri = MPIC_VECPRI_MASK | i |
+ (8 << MPIC_VECPRI_PRIORITY_SHIFT);
- /* check if protected */
- if (mpic->protected && test_bit(i, mpic->protected))
- continue;
- /* init hw */
- mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
- mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
+ /* check if protected */
+ if (mpic->protected && test_bit(i, mpic->protected))
+ continue;
+ /* init hw */
+ mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
+ mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION), 1 << cpu);
+ }
}
/* Init spurious vector */