diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-09-29 01:00:29 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-10-04 00:52:08 -0400 |
commit | 2e194583125bfea94d1ceaa6a32e891643befa7d (patch) | |
tree | edcd8ee247c244727cc828582591fea26c7cd83b | |
parent | f3c87a8999c28f2948ebd407574f7e9fb5c577b2 (diff) |
[POWERPC] Cell interrupt rework
This patch reworks the cell iic interrupt handling so that:
- Node ID is back in the interrupt number (only one IRQ host is created
for all nodes). This allows interrupts from sources on another node to
be routed non-locally. This will allow possibly one day to fix maxcpus=1
or 2 and still get interrupts from devices on BE 1. (A bit more fixing
is needed for that) and it will allow us to implement actual affinity
control of external interrupts.
- Added handling of the IO exceptions interrupts (badly named, but I
re-used the name initially used by STI). Those are the interrupts
exposed by IIC_ISR and IIC_IRR, such as the IOC translation exception,
performance monitor, etc... Those get their special numbers in the IRQ
number space and are internally implemented as a cascade on unit 0xe,
class 1 of each node.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 235 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.h | 97 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spider-pic.c | 9 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spu_base.c | 19 |
4 files changed, 238 insertions, 122 deletions
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 6b57a47c5d37..6cc59e0b4582 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -21,6 +21,12 @@ | |||
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | * | ||
25 | * TODO: | ||
26 | * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers | ||
27 | * vs node numbers in the setup code | ||
28 | * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from | ||
29 | * a non-active node to the active node) | ||
24 | */ | 30 | */ |
25 | 31 | ||
26 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
@@ -44,24 +50,25 @@ struct iic { | |||
44 | u8 target_id; | 50 | u8 target_id; |
45 | u8 eoi_stack[16]; | 51 | u8 eoi_stack[16]; |
46 | int eoi_ptr; | 52 | int eoi_ptr; |
47 | struct irq_host *host; | 53 | struct device_node *node; |
48 | }; | 54 | }; |
49 | 55 | ||
50 | static DEFINE_PER_CPU(struct iic, iic); | 56 | static DEFINE_PER_CPU(struct iic, iic); |
51 | #define IIC_NODE_COUNT 2 | 57 | #define IIC_NODE_COUNT 2 |
52 | static struct irq_host *iic_hosts[IIC_NODE_COUNT]; | 58 | static struct irq_host *iic_host; |
53 | 59 | ||
54 | /* Convert between "pending" bits and hw irq number */ | 60 | /* Convert between "pending" bits and hw irq number */ |
55 | static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) | 61 | static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) |
56 | { | 62 | { |
57 | unsigned char unit = bits.source & 0xf; | 63 | unsigned char unit = bits.source & 0xf; |
64 | unsigned char node = bits.source >> 4; | ||
65 | unsigned char class = bits.class & 3; | ||
58 | 66 | ||
67 | /* Decode IPIs */ | ||
59 | if (bits.flags & CBE_IIC_IRQ_IPI) | 68 | if (bits.flags & CBE_IIC_IRQ_IPI) |
60 | return IIC_IRQ_IPI0 | (bits.prio >> 4); | 69 | return IIC_IRQ_TYPE_IPI | (bits.prio >> 4); |
61 | else if (bits.class <= 3) | ||
62 | return (bits.class << 4) | unit; | ||
63 | else | 70 | else |
64 | return IIC_IRQ_INVALID; | 71 | return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit; |
65 | } | 72 | } |
66 | 73 | ||
67 | static void iic_mask(unsigned int irq) | 74 | static void iic_mask(unsigned int irq) |
@@ -86,21 +93,70 @@ static struct irq_chip iic_chip = { | |||
86 | .eoi = iic_eoi, | 93 | .eoi = iic_eoi, |
87 | }; | 94 | }; |
88 | 95 | ||
96 | |||
97 | static void iic_ioexc_eoi(unsigned int irq) | ||
98 | { | ||
99 | } | ||
100 | |||
101 | static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc, | ||
102 | struct pt_regs *regs) | ||
103 | { | ||
104 | struct cbe_iic_regs *node_iic = desc->handler_data; | ||
105 | unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC; | ||
106 | unsigned long bits, ack; | ||
107 | int cascade; | ||
108 | |||
109 | for (;;) { | ||
110 | bits = in_be64(&node_iic->iic_is); | ||
111 | if (bits == 0) | ||
112 | break; | ||
113 | /* pre-ack edge interrupts */ | ||
114 | ack = bits & IIC_ISR_EDGE_MASK; | ||
115 | if (ack) | ||
116 | out_be64(&node_iic->iic_is, ack); | ||
117 | /* handle them */ | ||
118 | for (cascade = 63; cascade >= 0; cascade--) | ||
119 | if (bits & (0x8000000000000000UL >> cascade)) { | ||
120 | unsigned int cirq = | ||
121 | irq_linear_revmap(iic_host, | ||
122 | base | cascade); | ||
123 | if (cirq != NO_IRQ) | ||
124 | generic_handle_irq(cirq, regs); | ||
125 | } | ||
126 | /* post-ack level interrupts */ | ||
127 | ack = bits & ~IIC_ISR_EDGE_MASK; | ||
128 | if (ack) | ||
129 | out_be64(&node_iic->iic_is, ack); | ||
130 | } | ||
131 | desc->chip->eoi(irq); | ||
132 | } | ||
133 | |||
134 | |||
135 | static struct irq_chip iic_ioexc_chip = { | ||
136 | .typename = " CELL-IOEX", | ||
137 | .mask = iic_mask, | ||
138 | .unmask = iic_unmask, | ||
139 | .eoi = iic_ioexc_eoi, | ||
140 | }; | ||
141 | |||
89 | /* Get an IRQ number from the pending state register of the IIC */ | 142 | /* Get an IRQ number from the pending state register of the IIC */ |
90 | static unsigned int iic_get_irq(struct pt_regs *regs) | 143 | static unsigned int iic_get_irq(struct pt_regs *regs) |
91 | { | 144 | { |
92 | struct cbe_iic_pending_bits pending; | 145 | struct cbe_iic_pending_bits pending; |
93 | struct iic *iic; | 146 | struct iic *iic; |
147 | unsigned int virq; | ||
94 | 148 | ||
95 | iic = &__get_cpu_var(iic); | 149 | iic = &__get_cpu_var(iic); |
96 | *(unsigned long *) &pending = | 150 | *(unsigned long *) &pending = |
97 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); | 151 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); |
152 | if (!(pending.flags & CBE_IIC_IRQ_VALID)) | ||
153 | return NO_IRQ; | ||
154 | virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending)); | ||
155 | if (virq == NO_IRQ) | ||
156 | return NO_IRQ; | ||
98 | iic->eoi_stack[++iic->eoi_ptr] = pending.prio; | 157 | iic->eoi_stack[++iic->eoi_ptr] = pending.prio; |
99 | BUG_ON(iic->eoi_ptr > 15); | 158 | BUG_ON(iic->eoi_ptr > 15); |
100 | if (pending.flags & CBE_IIC_IRQ_VALID) | 159 | return virq; |
101 | return irq_linear_revmap(iic->host, | ||
102 | iic_pending_to_hwnum(pending)); | ||
103 | return NO_IRQ; | ||
104 | } | 160 | } |
105 | 161 | ||
106 | #ifdef CONFIG_SMP | 162 | #ifdef CONFIG_SMP |
@@ -108,12 +164,7 @@ static unsigned int iic_get_irq(struct pt_regs *regs) | |||
108 | /* Use the highest interrupt priorities for IPI */ | 164 | /* Use the highest interrupt priorities for IPI */ |
109 | static inline int iic_ipi_to_irq(int ipi) | 165 | static inline int iic_ipi_to_irq(int ipi) |
110 | { | 166 | { |
111 | return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi; | 167 | return IIC_IRQ_TYPE_IPI + 0xf - ipi; |
112 | } | ||
113 | |||
114 | static inline int iic_irq_to_ipi(int irq) | ||
115 | { | ||
116 | return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0); | ||
117 | } | 168 | } |
118 | 169 | ||
119 | void iic_setup_cpu(void) | 170 | void iic_setup_cpu(void) |
@@ -123,7 +174,7 @@ void iic_setup_cpu(void) | |||
123 | 174 | ||
124 | void iic_cause_IPI(int cpu, int mesg) | 175 | void iic_cause_IPI(int cpu, int mesg) |
125 | { | 176 | { |
126 | out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4); | 177 | out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4); |
127 | } | 178 | } |
128 | 179 | ||
129 | u8 iic_get_target_id(int cpu) | 180 | u8 iic_get_target_id(int cpu) |
@@ -134,9 +185,7 @@ EXPORT_SYMBOL_GPL(iic_get_target_id); | |||
134 | 185 | ||
135 | struct irq_host *iic_get_irq_host(int node) | 186 | struct irq_host *iic_get_irq_host(int node) |
136 | { | 187 | { |
137 | if (node < 0 || node >= IIC_NODE_COUNT) | 188 | return iic_host; |
138 | return NULL; | ||
139 | return iic_hosts[node]; | ||
140 | } | 189 | } |
141 | EXPORT_SYMBOL_GPL(iic_get_irq_host); | 190 | EXPORT_SYMBOL_GPL(iic_get_irq_host); |
142 | 191 | ||
@@ -149,34 +198,20 @@ static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | |||
149 | 198 | ||
150 | return IRQ_HANDLED; | 199 | return IRQ_HANDLED; |
151 | } | 200 | } |
152 | |||
153 | static void iic_request_ipi(int ipi, const char *name) | 201 | static void iic_request_ipi(int ipi, const char *name) |
154 | { | 202 | { |
155 | int node, virq; | 203 | int virq; |
156 | 204 | ||
157 | for (node = 0; node < IIC_NODE_COUNT; node++) { | 205 | virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi)); |
158 | char *rname; | 206 | if (virq == NO_IRQ) { |
159 | if (iic_hosts[node] == NULL) | 207 | printk(KERN_ERR |
160 | continue; | 208 | "iic: failed to map IPI %s\n", name); |
161 | virq = irq_create_mapping(iic_hosts[node], | 209 | return; |
162 | iic_ipi_to_irq(ipi)); | ||
163 | if (virq == NO_IRQ) { | ||
164 | printk(KERN_ERR | ||
165 | "iic: failed to map IPI %s on node %d\n", | ||
166 | name, node); | ||
167 | continue; | ||
168 | } | ||
169 | rname = kzalloc(strlen(name) + 16, GFP_KERNEL); | ||
170 | if (rname) | ||
171 | sprintf(rname, "%s node %d", name, node); | ||
172 | else | ||
173 | rname = (char *)name; | ||
174 | if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, | ||
175 | rname, (void *)(long)ipi)) | ||
176 | printk(KERN_ERR | ||
177 | "iic: failed to request IPI %s on node %d\n", | ||
178 | name, node); | ||
179 | } | 210 | } |
211 | if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name, | ||
212 | (void *)(long)ipi)) | ||
213 | printk(KERN_ERR | ||
214 | "iic: failed to request IPI %s\n", name); | ||
180 | } | 215 | } |
181 | 216 | ||
182 | void iic_request_IPIs(void) | 217 | void iic_request_IPIs(void) |
@@ -193,16 +228,24 @@ void iic_request_IPIs(void) | |||
193 | 228 | ||
194 | static int iic_host_match(struct irq_host *h, struct device_node *node) | 229 | static int iic_host_match(struct irq_host *h, struct device_node *node) |
195 | { | 230 | { |
196 | return h->host_data != NULL && node == h->host_data; | 231 | return device_is_compatible(node, |
232 | "IBM,CBEA-Internal-Interrupt-Controller"); | ||
197 | } | 233 | } |
198 | 234 | ||
199 | static int iic_host_map(struct irq_host *h, unsigned int virq, | 235 | static int iic_host_map(struct irq_host *h, unsigned int virq, |
200 | irq_hw_number_t hw) | 236 | irq_hw_number_t hw) |
201 | { | 237 | { |
202 | if (hw < IIC_IRQ_IPI0) | 238 | switch (hw & IIC_IRQ_TYPE_MASK) { |
203 | set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq); | 239 | case IIC_IRQ_TYPE_IPI: |
204 | else | ||
205 | set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq); | 240 | set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq); |
241 | break; | ||
242 | case IIC_IRQ_TYPE_IOEXC: | ||
243 | set_irq_chip_and_handler(virq, &iic_ioexc_chip, | ||
244 | handle_fasteoi_irq); | ||
245 | break; | ||
246 | default: | ||
247 | set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq); | ||
248 | } | ||
206 | return 0; | 249 | return 0; |
207 | } | 250 | } |
208 | 251 | ||
@@ -211,11 +254,39 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct, | |||
211 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 254 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
212 | 255 | ||
213 | { | 256 | { |
214 | /* Currently, we don't translate anything. That needs to be fixed as | 257 | unsigned int node, ext, unit, class; |
215 | * we get better defined device-trees. iic interrupts have to be | 258 | const u32 *val; |
216 | * explicitely mapped by whoever needs them | 259 | |
217 | */ | 260 | if (!device_is_compatible(ct, |
218 | return -ENODEV; | 261 | "IBM,CBEA-Internal-Interrupt-Controller")) |
262 | return -ENODEV; | ||
263 | if (intsize != 1) | ||
264 | return -ENODEV; | ||
265 | val = get_property(ct, "#interrupt-cells", NULL); | ||
266 | if (val == NULL || *val != 1) | ||
267 | return -ENODEV; | ||
268 | |||
269 | node = intspec[0] >> 24; | ||
270 | ext = (intspec[0] >> 16) & 0xff; | ||
271 | class = (intspec[0] >> 8) & 0xff; | ||
272 | unit = intspec[0] & 0xff; | ||
273 | |||
274 | /* Check if node is in supported range */ | ||
275 | if (node > 1) | ||
276 | return -EINVAL; | ||
277 | |||
278 | /* Build up interrupt number, special case for IO exceptions */ | ||
279 | *out_hwirq = (node << IIC_IRQ_NODE_SHIFT); | ||
280 | if (unit == IIC_UNIT_IIC && class == 1) | ||
281 | *out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext; | ||
282 | else | ||
283 | *out_hwirq |= IIC_IRQ_TYPE_NORMAL | | ||
284 | (class << IIC_IRQ_CLASS_SHIFT) | unit; | ||
285 | |||
286 | /* Dummy flags, ignored by iic code */ | ||
287 | *out_flags = IRQ_TYPE_EDGE_RISING; | ||
288 | |||
289 | return 0; | ||
219 | } | 290 | } |
220 | 291 | ||
221 | static struct irq_host_ops iic_host_ops = { | 292 | static struct irq_host_ops iic_host_ops = { |
@@ -225,7 +296,7 @@ static struct irq_host_ops iic_host_ops = { | |||
225 | }; | 296 | }; |
226 | 297 | ||
227 | static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, | 298 | static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, |
228 | struct irq_host *host) | 299 | struct device_node *node) |
229 | { | 300 | { |
230 | /* XXX FIXME: should locate the linux CPU number from the HW cpu | 301 | /* XXX FIXME: should locate the linux CPU number from the HW cpu |
231 | * number properly. We are lucky for now | 302 | * number properly. We are lucky for now |
@@ -237,19 +308,19 @@ static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, | |||
237 | 308 | ||
238 | iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe); | 309 | iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe); |
239 | iic->eoi_stack[0] = 0xff; | 310 | iic->eoi_stack[0] = 0xff; |
240 | iic->host = host; | 311 | iic->node = of_node_get(node); |
241 | out_be64(&iic->regs->prio, 0); | 312 | out_be64(&iic->regs->prio, 0); |
242 | 313 | ||
243 | printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n", | 314 | printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n", |
244 | hw_cpu, addr, iic->regs, iic->target_id); | 315 | hw_cpu, iic->target_id, node->full_name); |
245 | } | 316 | } |
246 | 317 | ||
247 | static int __init setup_iic(void) | 318 | static int __init setup_iic(void) |
248 | { | 319 | { |
249 | struct device_node *dn; | 320 | struct device_node *dn; |
250 | struct resource r0, r1; | 321 | struct resource r0, r1; |
251 | struct irq_host *host; | 322 | unsigned int node, cascade, found = 0; |
252 | int found = 0; | 323 | struct cbe_iic_regs *node_iic; |
253 | const u32 *np; | 324 | const u32 *np; |
254 | 325 | ||
255 | for (dn = NULL; | 326 | for (dn = NULL; |
@@ -269,19 +340,33 @@ static int __init setup_iic(void) | |||
269 | of_node_put(dn); | 340 | of_node_put(dn); |
270 | return -ENODEV; | 341 | return -ENODEV; |
271 | } | 342 | } |
272 | host = NULL; | 343 | found++; |
273 | if (found < IIC_NODE_COUNT) { | 344 | init_one_iic(np[0], r0.start, dn); |
274 | host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, | 345 | init_one_iic(np[1], r1.start, dn); |
275 | IIC_SOURCE_COUNT, | 346 | |
276 | &iic_host_ops, | 347 | /* Setup cascade for IO exceptions. XXX cleanup tricks to get |
277 | IIC_IRQ_INVALID); | 348 | * node vs CPU etc... |
278 | iic_hosts[found] = host; | 349 | * Note that we configure the IIC_IRR here with a hard coded |
279 | BUG_ON(iic_hosts[found] == NULL); | 350 | * priority of 1. We might want to improve that later. |
280 | iic_hosts[found]->host_data = of_node_get(dn); | 351 | */ |
281 | found++; | 352 | node = np[0] >> 1; |
282 | } | 353 | node_iic = cbe_get_cpu_iic_regs(np[0]); |
283 | init_one_iic(np[0], r0.start, host); | 354 | cascade = node << IIC_IRQ_NODE_SHIFT; |
284 | init_one_iic(np[1], r1.start, host); | 355 | cascade |= 1 << IIC_IRQ_CLASS_SHIFT; |
356 | cascade |= IIC_UNIT_IIC; | ||
357 | cascade = irq_create_mapping(iic_host, cascade); | ||
358 | if (cascade == NO_IRQ) | ||
359 | continue; | ||
360 | set_irq_data(cascade, node_iic); | ||
361 | set_irq_chained_handler(cascade , iic_ioexc_cascade); | ||
362 | out_be64(&node_iic->iic_ir, | ||
363 | (1 << 12) /* priority */ | | ||
364 | (node << 4) /* dest node */ | | ||
365 | IIC_UNIT_THREAD_0 /* route them to thread 0 */); | ||
366 | /* Flush pending (make sure it triggers if there is | ||
367 | * anything pending | ||
368 | */ | ||
369 | out_be64(&node_iic->iic_is, 0xfffffffffffffffful); | ||
285 | } | 370 | } |
286 | 371 | ||
287 | if (found) | 372 | if (found) |
@@ -292,6 +377,12 @@ static int __init setup_iic(void) | |||
292 | 377 | ||
293 | void __init iic_init_IRQ(void) | 378 | void __init iic_init_IRQ(void) |
294 | { | 379 | { |
380 | /* Setup an irq host data structure */ | ||
381 | iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, | ||
382 | &iic_host_ops, IIC_IRQ_INVALID); | ||
383 | BUG_ON(iic_host == NULL); | ||
384 | irq_set_default_host(iic_host); | ||
385 | |||
295 | /* Discover and initialize iics */ | 386 | /* Discover and initialize iics */ |
296 | if (setup_iic() < 0) | 387 | if (setup_iic() < 0) |
297 | panic("IIC: Failed to initialize !\n"); | 388 | panic("IIC: Failed to initialize !\n"); |
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h index 5560a92ec3ab..9ba1d3c17b4b 100644 --- a/arch/powerpc/platforms/cell/interrupt.h +++ b/arch/powerpc/platforms/cell/interrupt.h | |||
@@ -2,48 +2,76 @@ | |||
2 | #define ASM_CELL_PIC_H | 2 | #define ASM_CELL_PIC_H |
3 | #ifdef __KERNEL__ | 3 | #ifdef __KERNEL__ |
4 | /* | 4 | /* |
5 | * Mapping of IIC pending bits into per-node | 5 | * Mapping of IIC pending bits into per-node interrupt numbers. |
6 | * interrupt numbers. | ||
7 | * | 6 | * |
8 | * IRQ FF CC SS PP FF CC SS PP Description | 7 | * Interrupt numbers are in the range 0...0x1ff where the top bit |
8 | * (0x100) represent the source node. Only 2 nodes are supported with | ||
9 | * the current code though it's trivial to extend that if necessary using | ||
10 | * higher level bits | ||
9 | * | 11 | * |
10 | * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge | 12 | * The bottom 8 bits are split into 2 type bits and 6 data bits that |
11 | * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge | 13 | * depend on the type: |
12 | * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0 | ||
13 | * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1 | ||
14 | * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2 | ||
15 | * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI | ||
16 | * | 14 | * |
17 | * F flags | 15 | * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source |
18 | * C class | 16 | * 01 (0x40 | data) : IO exception. data is the exception number as |
19 | * S source | 17 | * defined by bit numbers in IIC_SR |
20 | * P Priority | 18 | * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority) |
21 | * + node number | 19 | * and node is always 0 (IPIs are per-cpu, their source is |
22 | * * don't care | 20 | * not relevant) |
21 | * 11 (0xc0 | data) : reserved | ||
23 | * | 22 | * |
24 | * A node consists of a Cell Broadband Engine and an optional | 23 | * In addition, interrupt number 0x80000000 is defined as always invalid |
25 | * south bridge device providing a maximum of 64 IRQs. | 24 | * (that is the node field is expected to never extend to move than 23 bits) |
26 | * The south bridge may be connected to either IOIF0 | ||
27 | * or IOIF1. | ||
28 | * Each SPE is represented as three IRQ lines, one per | ||
29 | * interrupt class. | ||
30 | * 16 IRQ numbers are reserved for inter processor | ||
31 | * interruptions, although these are only used in the | ||
32 | * range of the first node. | ||
33 | * | 25 | * |
34 | * This scheme needs 128 IRQ numbers per BIF node ID, | ||
35 | * which means that with the total of 512 lines | ||
36 | * available, we can have a maximum of four nodes. | ||
37 | */ | 26 | */ |
38 | 27 | ||
39 | enum { | 28 | enum { |
40 | IIC_IRQ_INVALID = 0xff, | 29 | IIC_IRQ_INVALID = 0x80000000u, |
41 | IIC_IRQ_MAX = 0x3f, | 30 | IIC_IRQ_NODE_MASK = 0x100, |
42 | IIC_IRQ_EXT_IOIF0 = 0x20, | 31 | IIC_IRQ_NODE_SHIFT = 8, |
43 | IIC_IRQ_EXT_IOIF1 = 0x2b, | 32 | IIC_IRQ_MAX = 0x1ff, |
44 | IIC_IRQ_IPI0 = 0x40, | 33 | IIC_IRQ_TYPE_MASK = 0xc0, |
45 | IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */ | 34 | IIC_IRQ_TYPE_NORMAL = 0x00, |
46 | IIC_SOURCE_COUNT = 0x50, | 35 | IIC_IRQ_TYPE_IOEXC = 0x40, |
36 | IIC_IRQ_TYPE_IPI = 0x80, | ||
37 | IIC_IRQ_CLASS_SHIFT = 4, | ||
38 | IIC_IRQ_CLASS_0 = 0x00, | ||
39 | IIC_IRQ_CLASS_1 = 0x10, | ||
40 | IIC_IRQ_CLASS_2 = 0x20, | ||
41 | IIC_SOURCE_COUNT = 0x200, | ||
42 | |||
43 | /* Here are defined the various source/dest units. Avoid using those | ||
44 | * definitions if you can, they are mostly here for reference | ||
45 | */ | ||
46 | IIC_UNIT_SPU_0 = 0x4, | ||
47 | IIC_UNIT_SPU_1 = 0x7, | ||
48 | IIC_UNIT_SPU_2 = 0x3, | ||
49 | IIC_UNIT_SPU_3 = 0x8, | ||
50 | IIC_UNIT_SPU_4 = 0x2, | ||
51 | IIC_UNIT_SPU_5 = 0x9, | ||
52 | IIC_UNIT_SPU_6 = 0x1, | ||
53 | IIC_UNIT_SPU_7 = 0xa, | ||
54 | IIC_UNIT_IOC_0 = 0x0, | ||
55 | IIC_UNIT_IOC_1 = 0xb, | ||
56 | IIC_UNIT_THREAD_0 = 0xe, /* target only */ | ||
57 | IIC_UNIT_THREAD_1 = 0xf, /* target only */ | ||
58 | IIC_UNIT_IIC = 0xe, /* source only (IO exceptions) */ | ||
59 | |||
60 | /* Base numbers for the external interrupts */ | ||
61 | IIC_IRQ_EXT_IOIF0 = | ||
62 | IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0, | ||
63 | IIC_IRQ_EXT_IOIF1 = | ||
64 | IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1, | ||
65 | |||
66 | /* Base numbers for the IIC_ISR interrupts */ | ||
67 | IIC_IRQ_IOEX_TMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63, | ||
68 | IIC_IRQ_IOEX_PMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62, | ||
69 | IIC_IRQ_IOEX_ATI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61, | ||
70 | IIC_IRQ_IOEX_MATBFI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60, | ||
71 | IIC_IRQ_IOEX_ELDI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59, | ||
72 | |||
73 | /* Which bits in IIC_ISR are edge sensitive */ | ||
74 | IIC_ISR_EDGE_MASK = 0x4ul, | ||
47 | }; | 75 | }; |
48 | 76 | ||
49 | extern void iic_init_IRQ(void); | 77 | extern void iic_init_IRQ(void); |
@@ -52,7 +80,6 @@ extern void iic_request_IPIs(void); | |||
52 | extern void iic_setup_cpu(void); | 80 | extern void iic_setup_cpu(void); |
53 | 81 | ||
54 | extern u8 iic_get_target_id(int cpu); | 82 | extern u8 iic_get_target_id(int cpu); |
55 | extern struct irq_host *iic_get_irq_host(int node); | ||
56 | 83 | ||
57 | extern void spider_init_IRQ(void); | 84 | extern void spider_init_IRQ(void); |
58 | 85 | ||
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 742a03282b44..608b1ebc56b2 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c | |||
@@ -243,7 +243,6 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) | |||
243 | const u32 *imap, *tmp; | 243 | const u32 *imap, *tmp; |
244 | int imaplen, intsize, unit; | 244 | int imaplen, intsize, unit; |
245 | struct device_node *iic; | 245 | struct device_node *iic; |
246 | struct irq_host *iic_host; | ||
247 | 246 | ||
248 | #if 0 /* Enable that when we have a way to retreive the node as well */ | 247 | #if 0 /* Enable that when we have a way to retreive the node as well */ |
249 | /* First, we check wether we have a real "interrupts" in the device | 248 | /* First, we check wether we have a real "interrupts" in the device |
@@ -289,11 +288,11 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) | |||
289 | * the iic host from the iic OF node, but that way I'm still compatible | 288 | * the iic host from the iic OF node, but that way I'm still compatible |
290 | * with really really old old firmwares for which we don't have a node | 289 | * with really really old old firmwares for which we don't have a node |
291 | */ | 290 | */ |
292 | iic_host = iic_get_irq_host(pic->node_id); | ||
293 | if (iic_host == NULL) | ||
294 | return NO_IRQ; | ||
295 | /* Manufacture an IIC interrupt number of class 2 */ | 291 | /* Manufacture an IIC interrupt number of class 2 */ |
296 | virq = irq_create_mapping(iic_host, 0x20 | unit); | 292 | virq = irq_create_mapping(NULL, |
293 | (pic->node_id << IIC_IRQ_NODE_SHIFT) | | ||
294 | (2 << IIC_IRQ_CLASS_SHIFT) | | ||
295 | unit); | ||
297 | if (virq == NO_IRQ) | 296 | if (virq == NO_IRQ) |
298 | printk(KERN_ERR "spider_pic: failed to map cascade !"); | 297 | printk(KERN_ERR "spider_pic: failed to map cascade !"); |
299 | return virq; | 298 | return virq; |
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 0f5c8ebc7fc3..f78680346e5f 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -568,24 +568,23 @@ static void spu_unmap(struct spu *spu) | |||
568 | /* This function shall be abstracted for HV platforms */ | 568 | /* This function shall be abstracted for HV platforms */ |
569 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) | 569 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) |
570 | { | 570 | { |
571 | struct irq_host *host; | ||
572 | unsigned int isrc; | 571 | unsigned int isrc; |
573 | const u32 *tmp; | 572 | const u32 *tmp; |
574 | 573 | ||
575 | host = iic_get_irq_host(spu->node); | 574 | /* Get the interrupt source unit from the device-tree */ |
576 | if (host == NULL) | ||
577 | return -ENODEV; | ||
578 | |||
579 | /* Get the interrupt source from the device-tree */ | ||
580 | tmp = get_property(np, "isrc", NULL); | 575 | tmp = get_property(np, "isrc", NULL); |
581 | if (!tmp) | 576 | if (!tmp) |
582 | return -ENODEV; | 577 | return -ENODEV; |
583 | spu->isrc = isrc = tmp[0]; | 578 | isrc = tmp[0]; |
579 | |||
580 | /* Add the node number */ | ||
581 | isrc |= spu->node << IIC_IRQ_NODE_SHIFT; | ||
582 | spu->isrc = isrc; | ||
584 | 583 | ||
585 | /* Now map interrupts of all 3 classes */ | 584 | /* Now map interrupts of all 3 classes */ |
586 | spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc); | 585 | spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); |
587 | spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc); | 586 | spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); |
588 | spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc); | 587 | spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); |
589 | 588 | ||
590 | /* Right now, we only fail if class 2 failed */ | 589 | /* Right now, we only fail if class 2 failed */ |
591 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; | 590 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; |