aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/cell/spider-pic.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-03 07:36:01 -0400
committerPaul Mackerras <paulus@samba.org>2006-07-03 07:36:01 -0400
commit0ebfff1491ef85d41ddf9c633834838be144f69f (patch)
tree5b469a6d61a9fcfbf94e7b6d411e544dbdec8dec /arch/powerpc/platforms/cell/spider-pic.c
parentf63e115fb50db39706b955b81e3375ef6bab2268 (diff)
[POWERPC] Add new interrupt mapping core and change platforms to use it
This adds the new irq remapper core and removes the old one. Because there are some fundamental conflicts with the old code, like the value of NO_IRQ which I'm now setting to 0 (as per discussions with Linus), etc..., this commit also changes the relevant platform and driver code over to use the new remapper (so as not to cause difficulties later in bisecting). This patch removes the old pre-parsing of the open firmware interrupt tree along with all the bogus assumptions it made to try to renumber interrupts according to the platform. This is all to be handled by the new code now. For the pSeries XICS interrupt controller, a single remapper host is created for the whole machine regardless of how many interrupt presentation and source controllers are found, and it's set to match any device node that isn't a 8259. That works fine on pSeries and avoids having to deal with some of the complexities of split source controllers vs. presentation controllers in the pSeries device trees. The powerpc i8259 PIC driver now always requests the legacy interrupt range. It also has the feature of being able to match any device node (including NULL) if passed no device node as an input. That will help porting over platforms with broken device-trees like Pegasos who don't have a proper interrupt tree. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/cell/spider-pic.c')
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c341
1 files changed, 246 insertions, 95 deletions
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 98425acb6cda..ae7ef88f1a37 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -22,6 +22,7 @@
22 22
23#include <linux/interrupt.h> 23#include <linux/interrupt.h>
24#include <linux/irq.h> 24#include <linux/irq.h>
25#include <linux/ioport.h>
25 26
26#include <asm/pgtable.h> 27#include <asm/pgtable.h>
27#include <asm/prom.h> 28#include <asm/prom.h>
@@ -56,58 +57,67 @@ enum {
56 REISWAITEN = 0x508, /* Reissue Wait Control*/ 57 REISWAITEN = 0x508, /* Reissue Wait Control*/
57}; 58};
58 59
59static void __iomem *spider_pics[4]; 60#define SPIDER_CHIP_COUNT 4
61#define SPIDER_SRC_COUNT 64
62#define SPIDER_IRQ_INVALID 63
60 63
61static void __iomem *spider_get_pic(int irq) 64struct spider_pic {
62{ 65 struct irq_host *host;
63 int node = irq / IIC_NODE_STRIDE; 66 struct device_node *of_node;
64 irq %= IIC_NODE_STRIDE; 67 void __iomem *regs;
65 68 unsigned int node_id;
66 if (irq >= IIC_EXT_OFFSET && 69};
67 irq < IIC_EXT_OFFSET + IIC_NUM_EXT && 70static struct spider_pic spider_pics[SPIDER_CHIP_COUNT];
68 spider_pics)
69 return spider_pics[node];
70 return NULL;
71}
72 71
73static int spider_get_nr(unsigned int irq) 72static struct spider_pic *spider_virq_to_pic(unsigned int virq)
74{ 73{
75 return (irq % IIC_NODE_STRIDE) - IIC_EXT_OFFSET; 74 return irq_map[virq].host->host_data;
76} 75}
77 76
78static void __iomem *spider_get_irq_config(int irq) 77static void __iomem *spider_get_irq_config(struct spider_pic *pic,
78 unsigned int src)
79{ 79{
80 void __iomem *pic; 80 return pic->regs + TIR_CFGA + 8 * src;
81 pic = spider_get_pic(irq);
82 return pic + TIR_CFGA + 8 * spider_get_nr(irq);
83} 81}
84 82
85static void spider_unmask_irq(unsigned int irq) 83static void spider_unmask_irq(unsigned int virq)
86{ 84{
87 int nodeid = (irq / IIC_NODE_STRIDE) * 0x10; 85 struct spider_pic *pic = spider_virq_to_pic(virq);
88 void __iomem *cfg = spider_get_irq_config(irq); 86 void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
89 irq = spider_get_nr(irq);
90 87
91 /* FIXME: Most of that is configuration and has nothing to do with enabling/disable, 88 /* We use no locking as we should be covered by the descriptor lock
92 * besides, it's also partially bogus. 89 * for access to invidual source configuration registers
93 */ 90 */
94 out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid); 91 out_be32(cfg, in_be32(cfg) | 0x30000000u);
95 out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
96} 92}
97 93
98static void spider_mask_irq(unsigned int irq) 94static void spider_mask_irq(unsigned int virq)
99{ 95{
100 void __iomem *cfg = spider_get_irq_config(irq); 96 struct spider_pic *pic = spider_virq_to_pic(virq);
101 irq = spider_get_nr(irq); 97 void __iomem *cfg = spider_get_irq_config(pic, irq_map[virq].hwirq);
102 98
99 /* We use no locking as we should be covered by the descriptor lock
100 * for access to invidual source configuration registers
101 */
103 out_be32(cfg, in_be32(cfg) & ~0x30000000u); 102 out_be32(cfg, in_be32(cfg) & ~0x30000000u);
104} 103}
105 104
106static void spider_ack_irq(unsigned int irq) 105static void spider_ack_irq(unsigned int virq)
107{ 106{
108 /* Should reset edge detection logic but we don't configure any edge interrupt 107 struct spider_pic *pic = spider_virq_to_pic(virq);
109 * at the moment. 108 unsigned int src = irq_map[virq].hwirq;
109
110 /* Reset edge detection logic if necessary
110 */ 111 */
112 if (get_irq_desc(virq)->status & IRQ_LEVEL)
113 return;
114
115 /* Only interrupts 47 to 50 can be set to edge */
116 if (src < 47 || src > 50)
117 return;
118
119 /* Perform the clear of the edge logic */
120 out_be32(pic->regs + TIR_EDC, 0x100 | (src & 0xf));
111} 121}
112 122
113static struct irq_chip spider_pic = { 123static struct irq_chip spider_pic = {
@@ -117,102 +127,243 @@ static struct irq_chip spider_pic = {
117 .ack = spider_ack_irq, 127 .ack = spider_ack_irq,
118}; 128};
119 129
120static int spider_get_irq(int node) 130static int spider_host_match(struct irq_host *h, struct device_node *node)
131{
132 struct spider_pic *pic = h->host_data;
133 return node == pic->of_node;
134}
135
136static int spider_host_map(struct irq_host *h, unsigned int virq,
137 irq_hw_number_t hw, unsigned int flags)
121{ 138{
122 unsigned long cs; 139 unsigned int sense = flags & IRQ_TYPE_SENSE_MASK;
123 void __iomem *regs = spider_pics[node]; 140 struct spider_pic *pic = h->host_data;
141 void __iomem *cfg = spider_get_irq_config(pic, hw);
142 int level = 0;
143 u32 ic;
144
145 /* Note that only level high is supported for most interrupts */
146 if (sense != IRQ_TYPE_NONE && sense != IRQ_TYPE_LEVEL_HIGH &&
147 (hw < 47 || hw > 50))
148 return -EINVAL;
149
150 /* Decode sense type */
151 switch(sense) {
152 case IRQ_TYPE_EDGE_RISING:
153 ic = 0x3;
154 break;
155 case IRQ_TYPE_EDGE_FALLING:
156 ic = 0x2;
157 break;
158 case IRQ_TYPE_LEVEL_LOW:
159 ic = 0x0;
160 level = 1;
161 break;
162 case IRQ_TYPE_LEVEL_HIGH:
163 case IRQ_TYPE_NONE:
164 ic = 0x1;
165 level = 1;
166 break;
167 default:
168 return -EINVAL;
169 }
124 170
125 cs = in_be32(regs + TIR_CS) >> 24; 171 /* Configure the source. One gross hack that was there before and
172 * that I've kept around is the priority to the BE which I set to
173 * be the same as the interrupt source number. I don't know wether
174 * that's supposed to make any kind of sense however, we'll have to
175 * decide that, but for now, I'm not changing the behaviour.
176 */
177 out_be32(cfg, (ic << 24) | (0x7 << 16) | (pic->node_id << 4) | 0xe);
178 out_be32(cfg + 4, (0x2 << 16) | (hw & 0xff));
126 179
127 if (cs == 63) 180 if (level)
128 return -1; 181 get_irq_desc(virq)->status |= IRQ_LEVEL;
129 else 182 set_irq_chip_and_handler(virq, &spider_pic, handle_level_irq);
130 return cs; 183 return 0;
184}
185
186static int spider_host_xlate(struct irq_host *h, struct device_node *ct,
187 u32 *intspec, unsigned int intsize,
188 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
189
190{
191 /* Spider interrupts have 2 cells, first is the interrupt source,
192 * second, well, I don't know for sure yet ... We mask the top bits
193 * because old device-trees encode a node number in there
194 */
195 *out_hwirq = intspec[0] & 0x3f;
196 *out_flags = IRQ_TYPE_LEVEL_HIGH;
197 return 0;
131} 198}
132 199
200static struct irq_host_ops spider_host_ops = {
201 .match = spider_host_match,
202 .map = spider_host_map,
203 .xlate = spider_host_xlate,
204};
205
133static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc, 206static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
134 struct pt_regs *regs) 207 struct pt_regs *regs)
135{ 208{
136 int node = (int)(long)desc->handler_data; 209 struct spider_pic *pic = desc->handler_data;
137 int cascade_irq; 210 unsigned int cs, virq;
138 211
139 cascade_irq = spider_get_irq(node); 212 cs = in_be32(pic->regs + TIR_CS) >> 24;
140 generic_handle_irq(cascade_irq, regs); 213 if (cs == SPIDER_IRQ_INVALID)
214 virq = NO_IRQ;
215 else
216 virq = irq_linear_revmap(pic->host, cs);
217 if (virq != NO_IRQ)
218 generic_handle_irq(virq, regs);
141 desc->chip->eoi(irq); 219 desc->chip->eoi(irq);
142} 220}
143 221
144/* hardcoded part to be compatible with older firmware */ 222/* For hooking up the cascace we have a problem. Our device-tree is
223 * crap and we don't know on which BE iic interrupt we are hooked on at
224 * least not the "standard" way. We can reconstitute it based on two
225 * informations though: which BE node we are connected to and wether
226 * we are connected to IOIF0 or IOIF1. Right now, we really only care
227 * about the IBM cell blade and we know that its firmware gives us an
228 * interrupt-map property which is pretty strange.
229 */
230static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
231{
232 unsigned int virq;
233 u32 *imap, *tmp;
234 int imaplen, intsize, unit;
235 struct device_node *iic;
236 struct irq_host *iic_host;
237
238#if 0 /* Enable that when we have a way to retreive the node as well */
239 /* First, we check wether we have a real "interrupts" in the device
240 * tree in case the device-tree is ever fixed
241 */
242 struct of_irq oirq;
243 if (of_irq_map_one(pic->of_node, 0, &oirq) == 0) {
244 virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
245 oirq.size);
246 goto bail;
247 }
248#endif
249
250 /* Now do the horrible hacks */
251 tmp = (u32 *)get_property(pic->of_node, "#interrupt-cells", NULL);
252 if (tmp == NULL)
253 return NO_IRQ;
254 intsize = *tmp;
255 imap = (u32 *)get_property(pic->of_node, "interrupt-map", &imaplen);
256 if (imap == NULL || imaplen < (intsize + 1))
257 return NO_IRQ;
258 iic = of_find_node_by_phandle(imap[intsize]);
259 if (iic == NULL)
260 return NO_IRQ;
261 imap += intsize + 1;
262 tmp = (u32 *)get_property(iic, "#interrupt-cells", NULL);
263 if (tmp == NULL)
264 return NO_IRQ;
265 intsize = *tmp;
266 /* Assume unit is last entry of interrupt specifier */
267 unit = imap[intsize - 1];
268 /* Ok, we have a unit, now let's try to get the node */
269 tmp = (u32 *)get_property(iic, "ibm,interrupt-server-ranges", NULL);
270 if (tmp == NULL) {
271 of_node_put(iic);
272 return NO_IRQ;
273 }
274 /* ugly as hell but works for now */
275 pic->node_id = (*tmp) >> 1;
276 of_node_put(iic);
277
278 /* Ok, now let's get cracking. You may ask me why I just didn't match
279 * the iic host from the iic OF node, but that way I'm still compatible
280 * with really really old old firmwares for which we don't have a node
281 */
282 iic_host = iic_get_irq_host(pic->node_id);
283 if (iic_host == NULL)
284 return NO_IRQ;
285 /* Manufacture an IIC interrupt number of class 2 */
286 virq = irq_create_mapping(iic_host, 0x20 | unit, 0);
287 if (virq == NO_IRQ)
288 printk(KERN_ERR "spider_pic: failed to map cascade !");
289 return virq;
290}
291
145 292
146static void __init spider_init_one(int node, unsigned long addr) 293static void __init spider_init_one(struct device_node *of_node, int chip,
294 unsigned long addr)
147{ 295{
148 int n, irq; 296 struct spider_pic *pic = &spider_pics[chip];
297 int i, virq;
149 298
150 spider_pics[node] = ioremap(addr, 0x800); 299 /* Map registers */
151 if (spider_pics[node] == NULL) 300 pic->regs = ioremap(addr, 0x1000);
301 if (pic->regs == NULL)
152 panic("spider_pic: can't map registers !"); 302 panic("spider_pic: can't map registers !");
153 303
154 printk(KERN_INFO "spider_pic: mapped for node %d, addr: 0x%lx mapped to %p\n", 304 /* Allocate a host */
155 node, addr, spider_pics[node]); 305 pic->host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, SPIDER_SRC_COUNT,
306 &spider_host_ops, SPIDER_IRQ_INVALID);
307 if (pic->host == NULL)
308 panic("spider_pic: can't allocate irq host !");
309 pic->host->host_data = pic;
156 310
157 for (n = 0; n < IIC_NUM_EXT; n++) { 311 /* Fill out other bits */
158 if (n == IIC_EXT_CASCADE) 312 pic->of_node = of_node_get(of_node);
159 continue; 313
160 irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; 314 /* Go through all sources and disable them */
161 set_irq_chip_and_handler(irq, &spider_pic, handle_level_irq); 315 for (i = 0; i < SPIDER_SRC_COUNT; i++) {
162 get_irq_desc(irq)->status |= IRQ_LEVEL; 316 void __iomem *cfg = pic->regs + TIR_CFGA + 8 * i;
317 out_be32(cfg, in_be32(cfg) & ~0x30000000u);
163 } 318 }
164 319
165 /* do not mask any interrupts because of level */ 320 /* do not mask any interrupts because of level */
166 out_be32(spider_pics[node] + TIR_MSK, 0x0); 321 out_be32(pic->regs + TIR_MSK, 0x0);
167
168 /* disable edge detection clear */
169 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
170 322
171 /* enable interrupt packets to be output */ 323 /* enable interrupt packets to be output */
172 out_be32(spider_pics[node] + TIR_PIEN, 324 out_be32(pic->regs + TIR_PIEN, in_be32(pic->regs + TIR_PIEN) | 0x1);
173 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
174 325
175 /* Hook up cascade */ 326 /* Hook up the cascade interrupt to the iic and nodeid */
176 irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE; 327 virq = spider_find_cascade_and_node(pic);
177 set_irq_data(irq, (void *)(long)node); 328 if (virq == NO_IRQ)
178 set_irq_chained_handler(irq, spider_irq_cascade); 329 return;
330 set_irq_data(virq, pic);
331 set_irq_chained_handler(virq, spider_irq_cascade);
332
333 printk(KERN_INFO "spider_pic: node %d, addr: 0x%lx %s\n",
334 pic->node_id, addr, of_node->full_name);
179 335
180 /* Enable the interrupt detection enable bit. Do this last! */ 336 /* Enable the interrupt detection enable bit. Do this last! */
181 out_be32(spider_pics[node] + TIR_DEN, 337 out_be32(pic->regs + TIR_DEN, in_be32(pic->regs + TIR_DEN) | 0x1);
182 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
183} 338}
184 339
185void __init spider_init_IRQ(void) 340void __init spider_init_IRQ(void)
186{ 341{
187 unsigned long *spider_reg; 342 struct resource r;
188 struct device_node *dn; 343 struct device_node *dn;
189 char *compatible; 344 int chip = 0;
190 int node = 0; 345
191 346 /* XXX node numbers are totally bogus. We _hope_ we get the device
192 /* XXX node numbers are totally bogus. We _hope_ we get the device nodes in the right 347 * nodes in the right order here but that's definitely not guaranteed,
193 * order here but that's definitely not guaranteed, we need to get the node from the 348 * we need to get the node from the device tree instead.
194 * device tree instead. There is currently no proper property for it (but our whole 349 * There is currently no proper property for it (but our whole
195 * device-tree is bogus anyway) so all we can do is pray or maybe test the address 350 * device-tree is bogus anyway) so all we can do is pray or maybe test
196 * and deduce the node-id 351 * the address and deduce the node-id
197 */ 352 */
198 for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { 353 for (dn = NULL;
199 compatible = (char *)get_property(dn, "compatible", NULL); 354 (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
200 355 if (device_is_compatible(dn, "CBEA,platform-spider-pic")) {
201 if (!compatible) 356 if (of_address_to_resource(dn, 0, &r)) {
202 continue; 357 printk(KERN_WARNING "spider-pic: Failed\n");
203 358 continue;
204 if (strstr(compatible, "CBEA,platform-spider-pic")) 359 }
205 spider_reg = (unsigned long *)get_property(dn, "reg", NULL); 360 } else if (device_is_compatible(dn, "sti,platform-spider-pic")
206 else if (strstr(compatible, "sti,platform-spider-pic") && (node < 2)) { 361 && (chip < 2)) {
207 static long hard_coded_pics[] = { 0x24000008000, 0x34000008000 }; 362 static long hard_coded_pics[] =
208 spider_reg = &hard_coded_pics[node]; 363 { 0x24000008000, 0x34000008000 };
364 r.start = hard_coded_pics[chip];
209 } else 365 } else
210 continue; 366 continue;
211 367 spider_init_one(dn, chip++, r.start);
212 if (spider_reg == NULL)
213 printk(KERN_ERR "spider_pic: No address for node %d\n", node);
214
215 spider_init_one(node, *spider_reg);
216 node++;
217 } 368 }
218} 369}