aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/mpic.h14
-rw-r--r--arch/powerpc/sysdev/Makefile2
-rw-r--r--arch/powerpc/sysdev/fsl_mpic_err.c149
-rw-r--r--arch/powerpc/sysdev/mpic.c44
-rw-r--r--arch/powerpc/sysdev/mpic.h22
5 files changed, 229 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index e14d35d572af..c0f9ef90f0b8 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -118,6 +118,9 @@
118#define MPIC_MAX_CPUS 32 118#define MPIC_MAX_CPUS 32
119#define MPIC_MAX_ISU 32 119#define MPIC_MAX_ISU 32
120 120
121#define MPIC_MAX_ERR 32
122#define MPIC_FSL_ERR_INT 16
123
121/* 124/*
122 * Tsi108 implementation of MPIC has many differences from the original one 125 * Tsi108 implementation of MPIC has many differences from the original one
123 */ 126 */
@@ -270,6 +273,7 @@ struct mpic
270 struct irq_chip hc_ipi; 273 struct irq_chip hc_ipi;
271#endif 274#endif
272 struct irq_chip hc_tm; 275 struct irq_chip hc_tm;
276 struct irq_chip hc_err;
273 const char *name; 277 const char *name;
274 /* Flags */ 278 /* Flags */
275 unsigned int flags; 279 unsigned int flags;
@@ -283,6 +287,8 @@ struct mpic
283 /* vector numbers used for internal sources (ipi/timers) */ 287 /* vector numbers used for internal sources (ipi/timers) */
284 unsigned int ipi_vecs[4]; 288 unsigned int ipi_vecs[4];
285 unsigned int timer_vecs[8]; 289 unsigned int timer_vecs[8];
290 /* vector numbers used for FSL MPIC error interrupts */
291 unsigned int err_int_vecs[MPIC_MAX_ERR];
286 292
287 /* Spurious vector to program into unused sources */ 293 /* Spurious vector to program into unused sources */
288 unsigned int spurious_vec; 294 unsigned int spurious_vec;
@@ -306,6 +312,9 @@ struct mpic
306 struct mpic_reg_bank cpuregs[MPIC_MAX_CPUS]; 312 struct mpic_reg_bank cpuregs[MPIC_MAX_CPUS];
307 struct mpic_reg_bank isus[MPIC_MAX_ISU]; 313 struct mpic_reg_bank isus[MPIC_MAX_ISU];
308 314
315 /* ioremap'ed base for error interrupt registers */
316 u32 __iomem *err_regs;
317
309 /* Protected sources */ 318 /* Protected sources */
310 unsigned long *protected; 319 unsigned long *protected;
311 320
@@ -370,6 +379,11 @@ struct mpic
370#define MPIC_NO_RESET 0x00004000 379#define MPIC_NO_RESET 0x00004000
371/* Freescale MPIC (compatible includes "fsl,mpic") */ 380/* Freescale MPIC (compatible includes "fsl,mpic") */
372#define MPIC_FSL 0x00008000 381#define MPIC_FSL 0x00008000
382/* Freescale MPIC supports EIMR (error interrupt mask register).
383 * This flag is set for MPIC version >= 4.1 (version determined
384 * from the BRR1 register).
385*/
386#define MPIC_FSL_HAS_EIMR 0x00010000
373 387
374/* MPIC HW modification ID */ 388/* MPIC HW modification ID */
375#define MPIC_REGSET_MASK 0xf0000000 389#define MPIC_REGSET_MASK 0xf0000000
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 1bd7ecb24620..a57600b3a4e3 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o
15obj-$(CONFIG_PPC_PMI) += pmi.o 15obj-$(CONFIG_PPC_PMI) += pmi.o
16obj-$(CONFIG_U3_DART) += dart_iommu.o 16obj-$(CONFIG_U3_DART) += dart_iommu.o
17obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o 17obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
18obj-$(CONFIG_FSL_SOC) += fsl_soc.o 18obj-$(CONFIG_FSL_SOC) += fsl_soc.o fsl_mpic_err.o
19obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) 19obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
20obj-$(CONFIG_FSL_PMC) += fsl_pmc.o 20obj-$(CONFIG_FSL_PMC) += fsl_pmc.o
21obj-$(CONFIG_FSL_LBC) += fsl_lbc.o 21obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
diff --git a/arch/powerpc/sysdev/fsl_mpic_err.c b/arch/powerpc/sysdev/fsl_mpic_err.c
new file mode 100644
index 000000000000..b83f32562a37
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_mpic_err.c
@@ -0,0 +1,149 @@
1/*
2 * Copyright (C) 2012 Freescale Semiconductor, Inc.
3 *
4 * Author: Varun Sethi <varun.sethi@freescale.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; version 2 of the
9 * License.
10 *
11 */
12
13#include <linux/irq.h>
14#include <linux/smp.h>
15#include <linux/interrupt.h>
16
17#include <asm/io.h>
18#include <asm/irq.h>
19#include <asm/mpic.h>
20
21#include "mpic.h"
22
23#define MPIC_ERR_INT_BASE 0x3900
24#define MPIC_ERR_INT_EISR 0x0000
25#define MPIC_ERR_INT_EIMR 0x0010
26
27static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
28{
29 return in_be32(base + (err_reg >> 2));
30}
31
32static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
33{
34 out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
35}
36
37static void fsl_mpic_mask_err(struct irq_data *d)
38{
39 u32 eimr;
40 struct mpic *mpic = irq_data_get_irq_chip_data(d);
41 unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
42
43 eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
44 eimr |= (1 << (31 - src));
45 mpic_fsl_err_write(mpic->err_regs, eimr);
46}
47
48static void fsl_mpic_unmask_err(struct irq_data *d)
49{
50 u32 eimr;
51 struct mpic *mpic = irq_data_get_irq_chip_data(d);
52 unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
53
54 eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
55 eimr &= ~(1 << (31 - src));
56 mpic_fsl_err_write(mpic->err_regs, eimr);
57}
58
59static struct irq_chip fsl_mpic_err_chip = {
60 .irq_disable = fsl_mpic_mask_err,
61 .irq_mask = fsl_mpic_mask_err,
62 .irq_unmask = fsl_mpic_unmask_err,
63};
64
65int mpic_setup_error_int(struct mpic *mpic, int intvec)
66{
67 int i;
68
69 mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
70 if (!mpic->err_regs) {
71 pr_err("could not map mpic error registers\n");
72 return -ENOMEM;
73 }
74 mpic->hc_err = fsl_mpic_err_chip;
75 mpic->hc_err.name = mpic->name;
76 mpic->flags |= MPIC_FSL_HAS_EIMR;
77 /* allocate interrupt vectors for error interrupts */
78 for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
79 mpic->err_int_vecs[i] = --intvec;
80
81 return 0;
82}
83
84int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw)
85{
86 if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
87 (hw >= mpic->err_int_vecs[0] &&
88 hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
89 WARN_ON(mpic->flags & MPIC_SECONDARY);
90
91 pr_debug("mpic: mapping as Error Interrupt\n");
92 irq_set_chip_data(virq, mpic);
93 irq_set_chip_and_handler(virq, &mpic->hc_err,
94 handle_level_irq);
95 return 1;
96 }
97
98 return 0;
99}
100
101static irqreturn_t fsl_error_int_handler(int irq, void *data)
102{
103 struct mpic *mpic = (struct mpic *) data;
104 u32 eisr, eimr;
105 int errint;
106 unsigned int cascade_irq;
107
108 eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
109 eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
110
111 if (!(eisr & ~eimr))
112 return IRQ_NONE;
113
114 while (eisr) {
115 errint = __builtin_clz(eisr);
116 cascade_irq = irq_linear_revmap(mpic->irqhost,
117 mpic->err_int_vecs[errint]);
118 WARN_ON(cascade_irq == NO_IRQ);
119 if (cascade_irq != NO_IRQ) {
120 generic_handle_irq(cascade_irq);
121 } else {
122 eimr |= 1 << (31 - errint);
123 mpic_fsl_err_write(mpic->err_regs, eimr);
124 }
125 eisr &= ~(1 << (31 - errint));
126 }
127
128 return IRQ_HANDLED;
129}
130
131void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
132{
133 unsigned int virq;
134 int ret;
135
136 virq = irq_create_mapping(mpic->irqhost, irqnum);
137 if (virq == NO_IRQ) {
138 pr_err("Error interrupt setup failed\n");
139 return;
140 }
141
142 /* Mask all error interrupts */
143 mpic_fsl_err_write(mpic->err_regs, ~0);
144
145 ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
146 "mpic-error-int", mpic);
147 if (ret)
148 pr_err("Failed to register error interrupt handler\n");
149}
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 7e32db7e7b0d..9c6e535daad2 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1026,6 +1026,9 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq,
1026 return 0; 1026 return 0;
1027 } 1027 }
1028 1028
1029 if (mpic_map_error_int(mpic, virq, hw))
1030 return 0;
1031
1029 if (hw >= mpic->num_sources) 1032 if (hw >= mpic->num_sources)
1030 return -EINVAL; 1033 return -EINVAL;
1031 1034
@@ -1085,7 +1088,16 @@ static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,
1085 */ 1088 */
1086 switch (intspec[2]) { 1089 switch (intspec[2]) {
1087 case 0: 1090 case 0:
1088 case 1: /* no EISR/EIMR support for now, treat as shared IRQ */ 1091 break;
1092 case 1:
1093 if (!(mpic->flags & MPIC_FSL_HAS_EIMR))
1094 break;
1095
1096 if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs))
1097 return -EINVAL;
1098
1099 *out_hwirq = mpic->err_int_vecs[intspec[3]];
1100
1089 break; 1101 break;
1090 case 2: 1102 case 2:
1091 if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs)) 1103 if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
@@ -1302,6 +1314,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1302 mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); 1314 mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
1303 1315
1304 if (mpic->flags & MPIC_FSL) { 1316 if (mpic->flags & MPIC_FSL) {
1317 u32 brr1, version;
1318 int ret;
1319
1305 /* 1320 /*
1306 * Yes, Freescale really did put global registers in the 1321 * Yes, Freescale really did put global registers in the
1307 * magic per-cpu area -- and they don't even show up in the 1322 * magic per-cpu area -- and they don't even show up in the
@@ -1309,6 +1324,29 @@ struct mpic * __init mpic_alloc(struct device_node *node,
1309 */ 1324 */
1310 mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs, 1325 mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
1311 MPIC_CPU_THISBASE, 0x1000); 1326 MPIC_CPU_THISBASE, 0x1000);
1327
1328 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
1329 MPIC_FSL_BRR1);
1330 version = brr1 & MPIC_FSL_BRR1_VER;
1331
1332 /* Error interrupt mask register (EIMR) is required for
1333 * handling individual device error interrupts. EIMR
1334 * was added in MPIC version 4.1.
1335 *
1336 * Over here we reserve vector number space for error
1337 * interrupt vectors. This space is stolen from the
1338 * global vector number space, as in case of ipis
1339 * and timer interrupts.
1340 *
1341 * Available vector space = intvec_top - 12, where 12
1342 * is the number of vectors which have been consumed by
1343 * ipis and timer interrupts.
1344 */
1345 if (version >= 0x401) {
1346 ret = mpic_setup_error_int(mpic, intvec_top - 12);
1347 if (ret)
1348 return NULL;
1349 }
1312 } 1350 }
1313 1351
1314 /* Reset */ 1352 /* Reset */
@@ -1474,6 +1512,10 @@ void __init mpic_init(struct mpic *mpic)
1474 num_timers = 8; 1512 num_timers = 8;
1475 } 1513 }
1476 1514
1515 /* FSL mpic error interrupt intialization */
1516 if (mpic->flags & MPIC_FSL_HAS_EIMR)
1517 mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);
1518
1477 /* Initialize timers to our reserved vectors and mask them for now */ 1519 /* Initialize timers to our reserved vectors and mask them for now */
1478 for (i = 0; i < num_timers; i++) { 1520 for (i = 0; i < num_timers; i++) {
1479 unsigned int offset = mpic_tm_offset(mpic, i); 1521 unsigned int offset = mpic_tm_offset(mpic, i);
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
index 13f3e8913a93..24bf07a63924 100644
--- a/arch/powerpc/sysdev/mpic.h
+++ b/arch/powerpc/sysdev/mpic.h
@@ -40,4 +40,26 @@ extern int mpic_set_affinity(struct irq_data *d,
40 const struct cpumask *cpumask, bool force); 40 const struct cpumask *cpumask, bool force);
41extern void mpic_reset_core(int cpu); 41extern void mpic_reset_core(int cpu);
42 42
43#ifdef CONFIG_FSL_SOC
44extern int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw);
45extern void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum);
46extern int mpic_setup_error_int(struct mpic *mpic, int intvec);
47#else
48static inline int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t hw)
49{
50 return 0;
51}
52
53
54static inline void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
55{
56 return;
57}
58
59static inline int mpic_setup_error_int(struct mpic *mpic, int intvec)
60{
61 return -1;
62}
63#endif
64
43#endif /* _POWERPC_SYSDEV_MPIC_H */ 65#endif /* _POWERPC_SYSDEV_MPIC_H */