diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 21:55:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 21:55:10 -0400 |
commit | 5375871d432ae9fc581014ac117b96aaee3cd0c7 (patch) | |
tree | be98e8255b0f927fb920fb532a598b93fa140dbe /arch/powerpc/sysdev/ge | |
parent | b57cb7231b2ce52d3dda14a7b417ae125fb2eb97 (diff) | |
parent | dfbc2d75c1bd47c3186fa91f1655ea2f3825b0ec (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull powerpc merge from Benjamin Herrenschmidt:
"Here's the powerpc batch for this merge window. It is going to be a
bit more nasty than usual as in touching things outside of
arch/powerpc mostly due to the big iSeriesectomy :-) We finally got
rid of the bugger (legacy iSeries support) which was a PITA to
maintain and that nobody really used anymore.
Here are some of the highlights:
- Legacy iSeries is gone. Thanks Stephen ! There's still some bits
and pieces remaining if you do a grep -ir series arch/powerpc but
they are harmless and will be removed in the next few weeks
hopefully.
- The 'fadump' functionality (Firmware Assisted Dump) replaces the
previous (equivalent) "pHyp assisted dump"... it's a rewrite of a
mechanism to get the hypervisor to do crash dumps on pSeries, the
new implementation hopefully being much more reliable. Thanks
Mahesh Salgaonkar.
- The "EEH" code (pSeries PCI error handling & recovery) got a big
spring cleaning, motivated by the need to be able to implement a
new backend for it on top of some new different type of firwmare.
The work isn't complete yet, but a good chunk of the cleanups is
there. Note that this adds a field to struct device_node which is
not very nice and which Grant objects to. I will have a patch soon
that moves that to a powerpc private data structure (hopefully
before rc1) and we'll improve things further later on (hopefully
getting rid of the need for that pointer completely). Thanks Gavin
Shan.
- I dug into our exception & interrupt handling code to improve the
way we do lazy interrupt handling (and make it work properly with
"edge" triggered interrupt sources), and while at it found & fixed
a wagon of issues in those areas, including adding support for page
fault retry & fatal signals on page faults.
- Your usual random batch of small fixes & updates, including a bunch
of new embedded boards, both Freescale and APM based ones, etc..."
I fixed up some conflicts with the generalized irq-domain changes from
Grant Likely, hopefully correctly.
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (141 commits)
powerpc/ps3: Do not adjust the wrapper load address
powerpc: Remove the rest of the legacy iSeries include files
powerpc: Remove the remaining CONFIG_PPC_ISERIES pieces
init: Remove CONFIG_PPC_ISERIES
powerpc: Remove FW_FEATURE ISERIES from arch code
tty/hvc_vio: FW_FEATURE_ISERIES is no longer selectable
powerpc/spufs: Fix double unlocks
powerpc/5200: convert mpc5200 to use of_platform_populate()
powerpc/mpc5200: add options to mpc5200_defconfig
powerpc/mpc52xx: add a4m072 board support
powerpc/mpc5200: update mpc5200_defconfig to fit for charon board
Documentation/powerpc/mpc52xx.txt: Checkpatch cleanup
powerpc/44x: Add additional device support for APM821xx SoC and Bluestone board
powerpc/44x: Add support PCI-E for APM821xx SoC and Bluestone board
MAINTAINERS: Update PowerPC 4xx tree
powerpc/44x: The bug fixed support for APM821xx SoC and Bluestone board
powerpc: document the FSL MPIC message register binding
powerpc: add support for MPIC message register API
powerpc/fsl: Added aliased MSIIR register address to MSI node in dts
powerpc/85xx: mpc8548cds - add 36-bit dts
...
Diffstat (limited to 'arch/powerpc/sysdev/ge')
-rw-r--r-- | arch/powerpc/sysdev/ge/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ge/ge_pic.c | 251 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ge/ge_pic.h | 11 |
3 files changed, 263 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile new file mode 100644 index 000000000000..8731ffcb79b9 --- /dev/null +++ b/arch/powerpc/sysdev/ge/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_GE_FPGA) += ge_pic.o | |||
diff --git a/arch/powerpc/sysdev/ge/ge_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c new file mode 100644 index 000000000000..2bcb78bb3a15 --- /dev/null +++ b/arch/powerpc/sysdev/ge/ge_pic.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * Interrupt handling for GE FPGA based PIC | ||
3 | * | ||
4 | * Author: Martyn Welch <martyn.welch@ge.com> | ||
5 | * | ||
6 | * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc. | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/stddef.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | |||
20 | #include <asm/byteorder.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/prom.h> | ||
23 | #include <asm/irq.h> | ||
24 | |||
25 | #include "ge_pic.h" | ||
26 | |||
27 | #define DEBUG | ||
28 | #undef DEBUG | ||
29 | |||
30 | #ifdef DEBUG | ||
31 | #define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0) | ||
32 | #else | ||
33 | #define DBG(fmt...) do { } while (0) | ||
34 | #endif | ||
35 | |||
36 | #define GEF_PIC_NUM_IRQS 32 | ||
37 | |||
38 | /* Interrupt Controller Interface Registers */ | ||
39 | #define GEF_PIC_INTR_STATUS 0x0000 | ||
40 | |||
41 | #define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu)) | ||
42 | #define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0) | ||
43 | #define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1) | ||
44 | |||
45 | #define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu)) | ||
46 | #define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0) | ||
47 | #define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1) | ||
48 | |||
49 | |||
50 | static DEFINE_RAW_SPINLOCK(gef_pic_lock); | ||
51 | |||
52 | static void __iomem *gef_pic_irq_reg_base; | ||
53 | static struct irq_domain *gef_pic_irq_host; | ||
54 | static int gef_pic_cascade_irq; | ||
55 | |||
56 | /* | ||
57 | * Interrupt Controller Handling | ||
58 | * | ||
59 | * The interrupt controller handles interrupts for most on board interrupts, | ||
60 | * apart from PCI interrupts. For example on SBC610: | ||
61 | * | ||
62 | * 17:31 RO Reserved | ||
63 | * 16 RO PCI Express Doorbell 3 Status | ||
64 | * 15 RO PCI Express Doorbell 2 Status | ||
65 | * 14 RO PCI Express Doorbell 1 Status | ||
66 | * 13 RO PCI Express Doorbell 0 Status | ||
67 | * 12 RO Real Time Clock Interrupt Status | ||
68 | * 11 RO Temperature Interrupt Status | ||
69 | * 10 RO Temperature Critical Interrupt Status | ||
70 | * 9 RO Ethernet PHY1 Interrupt Status | ||
71 | * 8 RO Ethernet PHY3 Interrupt Status | ||
72 | * 7 RO PEX8548 Interrupt Status | ||
73 | * 6 RO Reserved | ||
74 | * 5 RO Watchdog 0 Interrupt Status | ||
75 | * 4 RO Watchdog 1 Interrupt Status | ||
76 | * 3 RO AXIS Message FIFO A Interrupt Status | ||
77 | * 2 RO AXIS Message FIFO B Interrupt Status | ||
78 | * 1 RO AXIS Message FIFO C Interrupt Status | ||
79 | * 0 RO AXIS Message FIFO D Interrupt Status | ||
80 | * | ||
81 | * Interrupts can be forwarded to one of two output lines. Nothing | ||
82 | * clever is done, so if the masks are incorrectly set, a single input | ||
83 | * interrupt could generate interrupts on both output lines! | ||
84 | * | ||
85 | * The dual lines are there to allow the chained interrupts to be easily | ||
86 | * passed into two different cores. We currently do not use this functionality | ||
87 | * in this driver. | ||
88 | * | ||
89 | * Controller can also be configured to generate Machine checks (MCP), again on | ||
90 | * two lines, to be attached to two different cores. It is suggested that these | ||
91 | * should be masked out. | ||
92 | */ | ||
93 | |||
94 | void gef_pic_cascade(unsigned int irq, struct irq_desc *desc) | ||
95 | { | ||
96 | struct irq_chip *chip = irq_desc_get_chip(desc); | ||
97 | unsigned int cascade_irq; | ||
98 | |||
99 | /* | ||
100 | * See if we actually have an interrupt, call generic handling code if | ||
101 | * we do. | ||
102 | */ | ||
103 | cascade_irq = gef_pic_get_irq(); | ||
104 | |||
105 | if (cascade_irq != NO_IRQ) | ||
106 | generic_handle_irq(cascade_irq); | ||
107 | |||
108 | chip->irq_eoi(&desc->irq_data); | ||
109 | } | ||
110 | |||
111 | static void gef_pic_mask(struct irq_data *d) | ||
112 | { | ||
113 | unsigned long flags; | ||
114 | unsigned int hwirq = irqd_to_hwirq(d); | ||
115 | u32 mask; | ||
116 | |||
117 | raw_spin_lock_irqsave(&gef_pic_lock, flags); | ||
118 | mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); | ||
119 | mask &= ~(1 << hwirq); | ||
120 | out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); | ||
121 | raw_spin_unlock_irqrestore(&gef_pic_lock, flags); | ||
122 | } | ||
123 | |||
124 | static void gef_pic_mask_ack(struct irq_data *d) | ||
125 | { | ||
126 | /* Don't think we actually have to do anything to ack an interrupt, | ||
127 | * we just need to clear down the devices interrupt and it will go away | ||
128 | */ | ||
129 | gef_pic_mask(d); | ||
130 | } | ||
131 | |||
132 | static void gef_pic_unmask(struct irq_data *d) | ||
133 | { | ||
134 | unsigned long flags; | ||
135 | unsigned int hwirq = irqd_to_hwirq(d); | ||
136 | u32 mask; | ||
137 | |||
138 | raw_spin_lock_irqsave(&gef_pic_lock, flags); | ||
139 | mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); | ||
140 | mask |= (1 << hwirq); | ||
141 | out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask); | ||
142 | raw_spin_unlock_irqrestore(&gef_pic_lock, flags); | ||
143 | } | ||
144 | |||
145 | static struct irq_chip gef_pic_chip = { | ||
146 | .name = "gefp", | ||
147 | .irq_mask = gef_pic_mask, | ||
148 | .irq_mask_ack = gef_pic_mask_ack, | ||
149 | .irq_unmask = gef_pic_unmask, | ||
150 | }; | ||
151 | |||
152 | |||
153 | /* When an interrupt is being configured, this call allows some flexibilty | ||
154 | * in deciding which irq_chip structure is used | ||
155 | */ | ||
156 | static int gef_pic_host_map(struct irq_domain *h, unsigned int virq, | ||
157 | irq_hw_number_t hwirq) | ||
158 | { | ||
159 | /* All interrupts are LEVEL sensitive */ | ||
160 | irq_set_status_flags(virq, IRQ_LEVEL); | ||
161 | irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int gef_pic_host_xlate(struct irq_domain *h, struct device_node *ct, | ||
167 | const u32 *intspec, unsigned int intsize, | ||
168 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | ||
169 | { | ||
170 | |||
171 | *out_hwirq = intspec[0]; | ||
172 | if (intsize > 1) | ||
173 | *out_flags = intspec[1]; | ||
174 | else | ||
175 | *out_flags = IRQ_TYPE_LEVEL_HIGH; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static const struct irq_domain_ops gef_pic_host_ops = { | ||
181 | .map = gef_pic_host_map, | ||
182 | .xlate = gef_pic_host_xlate, | ||
183 | }; | ||
184 | |||
185 | |||
186 | /* | ||
187 | * Initialisation of PIC, this should be called in BSP | ||
188 | */ | ||
189 | void __init gef_pic_init(struct device_node *np) | ||
190 | { | ||
191 | unsigned long flags; | ||
192 | |||
193 | /* Map the devices registers into memory */ | ||
194 | gef_pic_irq_reg_base = of_iomap(np, 0); | ||
195 | |||
196 | raw_spin_lock_irqsave(&gef_pic_lock, flags); | ||
197 | |||
198 | /* Initialise everything as masked. */ | ||
199 | out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0); | ||
200 | out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0); | ||
201 | |||
202 | out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0); | ||
203 | out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0); | ||
204 | |||
205 | raw_spin_unlock_irqrestore(&gef_pic_lock, flags); | ||
206 | |||
207 | /* Map controller */ | ||
208 | gef_pic_cascade_irq = irq_of_parse_and_map(np, 0); | ||
209 | if (gef_pic_cascade_irq == NO_IRQ) { | ||
210 | printk(KERN_ERR "SBC610: failed to map cascade interrupt"); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | /* Setup an irq_domain structure */ | ||
215 | gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS, | ||
216 | &gef_pic_host_ops, NULL); | ||
217 | if (gef_pic_irq_host == NULL) | ||
218 | return; | ||
219 | |||
220 | /* Chain with parent controller */ | ||
221 | irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade); | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * This is called when we receive an interrupt with apparently comes from this | ||
226 | * chip - check, returning the highest interrupt generated or return NO_IRQ | ||
227 | */ | ||
228 | unsigned int gef_pic_get_irq(void) | ||
229 | { | ||
230 | u32 cause, mask, active; | ||
231 | unsigned int virq = NO_IRQ; | ||
232 | int hwirq; | ||
233 | |||
234 | cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS); | ||
235 | |||
236 | mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0)); | ||
237 | |||
238 | active = cause & mask; | ||
239 | |||
240 | if (active) { | ||
241 | for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) { | ||
242 | if (active & (0x1 << hwirq)) | ||
243 | break; | ||
244 | } | ||
245 | virq = irq_linear_revmap(gef_pic_irq_host, | ||
246 | (irq_hw_number_t)hwirq); | ||
247 | } | ||
248 | |||
249 | return virq; | ||
250 | } | ||
251 | |||
diff --git a/arch/powerpc/sysdev/ge/ge_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h new file mode 100644 index 000000000000..6149916da3f4 --- /dev/null +++ b/arch/powerpc/sysdev/ge/ge_pic.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef __GEF_PIC_H__ | ||
2 | #define __GEF_PIC_H__ | ||
3 | |||
4 | #include <linux/init.h> | ||
5 | |||
6 | void gef_pic_cascade(unsigned int, struct irq_desc *); | ||
7 | unsigned int gef_pic_get_irq(void); | ||
8 | void gef_pic_init(struct device_node *); | ||
9 | |||
10 | #endif /* __GEF_PIC_H__ */ | ||
11 | |||