aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJens Osterkamp <Jens.Osterkamp@de.ibm.com>2006-03-22 18:00:06 -0500
committerPaul Mackerras <paulus@samba.org>2006-03-26 22:48:18 -0500
commitd0e57c68373f8ded8c50245fd082e606f9f63221 (patch)
treee74b9d732e519c150e12b16026a782e4987b5c7c /arch
parent1a19f85584414ae0a9f94406ffd628096127583e (diff)
[PATCH] powerpc: cell interrupt controller updates
The current interrupt controller setup on Cell is done in a rather ad-hoc way with device tree properties that are not standardized at all. In an attempt to do something that follows the OF standard (or at least the IBM extensions to it) more closely, we have now come up with this patch. It still provides a fallback to the old behaviour when we find older firmware, that hack can not be removed until the existing customer installations have upgraded. Cc: hpenner@de.ibm.com Cc: stk@de.ibm.com Cc: Segher Boessenkool <segher@kernel.crashing.org> Cc: Milton Miller <miltonm@bga.com> Cc: benh@kernel.crashing.org Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c116
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h2
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c106
3 files changed, 169 insertions, 55 deletions
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 63aa52acf441..9d41e07b0c95 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -123,7 +123,7 @@ static int iic_external_get_irq(struct iic_pending_bits pending)
123 pending.class != 2) 123 pending.class != 2)
124 break; 124 break;
125 irq = IIC_EXT_OFFSET 125 irq = IIC_EXT_OFFSET
126 + spider_get_irq(pending.prio + node * IIC_NODE_STRIDE) 126 + spider_get_irq(node)
127 + node * IIC_NODE_STRIDE; 127 + node * IIC_NODE_STRIDE;
128 break; 128 break;
129 case 0x01 ... 0x04: 129 case 0x01 ... 0x04:
@@ -174,38 +174,102 @@ int iic_get_irq(struct pt_regs *regs)
174 return irq; 174 return irq;
175} 175}
176 176
177static int setup_iic(int cpu, struct iic *iic) 177/* hardcoded part to be compatible with older firmware */
178
179static int setup_iic_hardcoded(void)
178{ 180{
179 struct device_node *np; 181 struct device_node *np;
180 int nodeid = cpu / 2; 182 int nodeid, cpu;
181 unsigned long regs; 183 unsigned long regs;
184 struct iic *iic;
182 185
183 for (np = of_find_node_by_type(NULL, "cpu"); 186 for_each_cpu(cpu) {
184 np; 187 iic = &per_cpu(iic, cpu);
185 np = of_find_node_by_type(np, "cpu")) { 188 nodeid = cpu/2;
186 if (nodeid == *(int *)get_property(np, "node-id", NULL)) 189
187 break; 190 for (np = of_find_node_by_type(NULL, "cpu");
191 np;
192 np = of_find_node_by_type(np, "cpu")) {
193 if (nodeid == *(int *)get_property(np, "node-id", NULL))
194 break;
195 }
196
197 if (!np) {
198 printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
199 iic->regs = NULL;
200 iic->target_id = 0xff;
201 return -ENODEV;
202 }
203
204 regs = *(long *)get_property(np, "iic", NULL);
205
206 /* hack until we have decided on the devtree info */
207 regs += 0x400;
208 if (cpu & 1)
209 regs += 0x20;
210
211 printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
212 iic->regs = __ioremap(regs, sizeof(struct iic_regs),
213 _PAGE_NO_CACHE);
214
215 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
188 } 216 }
189 217
190 if (!np) { 218 return 0;
191 printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); 219}
192 iic->regs = NULL;
193 iic->target_id = 0xff;
194 return -ENODEV;
195 }
196 220
197 regs = *(long *)get_property(np, "iic", NULL); 221static int setup_iic(void)
222{
223 struct device_node *dn;
224 unsigned long *regs;
225 char *compatible;
226 unsigned *np, found = 0;
227 struct iic *iic = NULL;
228
229 for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
230 compatible = (char *)get_property(dn, "compatible", NULL);
231
232 if (!compatible) {
233 printk(KERN_WARNING "no compatible property found !\n");
234 continue;
235 }
198 236
199 /* hack until we have decided on the devtree info */ 237 if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller"))
200 regs += 0x400; 238 regs = (unsigned long *)get_property(dn,"reg", NULL);
201 if (cpu & 1) 239 else
202 regs += 0x20; 240 continue;
203 241
204 printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); 242 if (!regs)
205 iic->regs = __ioremap(regs, sizeof(struct iic_regs), 243 printk(KERN_WARNING "IIC: no reg property\n");
206 _PAGE_NO_CACHE); 244
207 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); 245 np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL);
208 return 0; 246
247 if (!np) {
248 printk(KERN_WARNING "IIC: CPU association not found\n");
249 iic->regs = NULL;
250 iic->target_id = 0xff;
251 return -ENODEV;
252 }
253
254 iic = &per_cpu(iic, np[0]);
255 iic->regs = __ioremap(regs[0], sizeof(struct iic_regs),
256 _PAGE_NO_CACHE);
257 iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
258 printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
259
260 iic = &per_cpu(iic, np[1]);
261 iic->regs = __ioremap(regs[2], sizeof(struct iic_regs),
262 _PAGE_NO_CACHE);
263 iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
264 printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
265
266 found++;
267 }
268
269 if (found)
270 return 0;
271 else
272 return -ENODEV;
209} 273}
210 274
211#ifdef CONFIG_SMP 275#ifdef CONFIG_SMP
@@ -283,10 +347,12 @@ void iic_init_IRQ(void)
283 int cpu, irq_offset; 347 int cpu, irq_offset;
284 struct iic *iic; 348 struct iic *iic;
285 349
350 if (setup_iic() < 0)
351 setup_iic_hardcoded();
352
286 irq_offset = 0; 353 irq_offset = 0;
287 for_each_cpu(cpu) { 354 for_each_cpu(cpu) {
288 iic = &per_cpu(iic, cpu); 355 iic = &per_cpu(iic, cpu);
289 setup_iic(cpu, iic);
290 if (iic->regs) 356 if (iic->regs)
291 out_be64(&iic->regs->prio, 0xff); 357 out_be64(&iic->regs->prio, 0xff);
292 } 358 }
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index a14bd38791c0..799f77d98f96 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -57,7 +57,7 @@ extern void iic_local_disable(void);
57extern u8 iic_get_target_id(int cpu); 57extern u8 iic_get_target_id(int cpu);
58 58
59extern void spider_init_IRQ(void); 59extern void spider_init_IRQ(void);
60extern int spider_get_irq(unsigned long int_pending); 60extern int spider_get_irq(int node);
61 61
62#endif 62#endif
63#endif /* ASM_CELL_PIC_H */ 63#endif /* ASM_CELL_PIC_H */
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index e74132188bdf..0e9bb0b72c50 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -84,10 +84,11 @@ static void __iomem *spider_get_irq_config(int irq)
84 84
85static void spider_enable_irq(unsigned int irq) 85static void spider_enable_irq(unsigned int irq)
86{ 86{
87 int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
87 void __iomem *cfg = spider_get_irq_config(irq); 88 void __iomem *cfg = spider_get_irq_config(irq);
88 irq = spider_get_nr(irq); 89 irq = spider_get_nr(irq);
89 90
90 out_be32(cfg, in_be32(cfg) | 0x3107000eu); 91 out_be32(cfg, in_be32(cfg) | 0x3107000eu | nodeid);
91 out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); 92 out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
92} 93}
93 94
@@ -131,61 +132,108 @@ static struct hw_interrupt_type spider_pic = {
131 .end = spider_end_irq, 132 .end = spider_end_irq,
132}; 133};
133 134
134 135int spider_get_irq(int node)
135int spider_get_irq(unsigned long int_pending)
136{ 136{
137 void __iomem *regs = spider_get_pic(int_pending);
138 unsigned long cs; 137 unsigned long cs;
139 int irq; 138 void __iomem *regs = spider_pics[node];
140
141 cs = in_be32(regs + TIR_CS);
142 139
143 irq = cs >> 24; 140 cs = in_be32(regs + TIR_CS) >> 24;
144 if (irq != 63)
145 return irq;
146 141
147 return -1; 142 if (cs == 63)
143 return -1;
144 else
145 return cs;
148} 146}
149 147
150void spider_init_IRQ(void) 148/* hardcoded part to be compatible with older firmware */
149
150void spider_init_IRQ_hardcoded(void)
151{ 151{
152 int node; 152 int node;
153 struct device_node *dn;
154 unsigned int *property;
155 long spiderpic; 153 long spiderpic;
154 long pics[] = { 0x24000008000, 0x34000008000 };
156 int n; 155 int n;
157 156
158/* FIXME: detect multiple PICs as soon as the device tree has them */ 157 pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
159 for (node = 0; node < 1; node++) {
160 dn = of_find_node_by_path("/");
161 n = prom_n_addr_cells(dn);
162 property = (unsigned int *) get_property(dn,
163 "platform-spider-pic", NULL);
164 158
165 if (!property) 159 for (node = 0; node < num_present_cpus()/2; node++) {
166 continue; 160 spiderpic = pics[node];
167 for (spiderpic = 0; n > 0; --n)
168 spiderpic = (spiderpic << 32) + *property++;
169 printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic); 161 printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
170 spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE); 162 spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE);
171 for (n = 0; n < IIC_NUM_EXT; n++) { 163 for (n = 0; n < IIC_NUM_EXT; n++) {
172 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; 164 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
173 get_irq_desc(irq)->handler = &spider_pic; 165 get_irq_desc(irq)->handler = &spider_pic;
166 }
174 167
175 /* do not mask any interrupts because of level */ 168 /* do not mask any interrupts because of level */
176 out_be32(spider_pics[node] + TIR_MSK, 0x0); 169 out_be32(spider_pics[node] + TIR_MSK, 0x0);
177 170
178 /* disable edge detection clear */ 171 /* disable edge detection clear */
179 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ 172 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
180 173
181 /* enable interrupt packets to be output */ 174 /* enable interrupt packets to be output */
182 out_be32(spider_pics[node] + TIR_PIEN, 175 out_be32(spider_pics[node] + TIR_PIEN,
183 in_be32(spider_pics[node] + TIR_PIEN) | 0x1); 176 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
184 177
185 /* Enable the interrupt detection enable bit. Do this last! */ 178 /* Enable the interrupt detection enable bit. Do this last! */
186 out_be32(spider_pics[node] + TIR_DEN, 179 out_be32(spider_pics[node] + TIR_DEN,
187 in_be32(spider_pics[node] +TIR_DEN) | 0x1); 180 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
181 }
182}
183
184void spider_init_IRQ(void)
185{
186 long spider_reg;
187 struct device_node *dn;
188 char *compatible;
189 int n, node = 0;
190
191 for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
192 compatible = (char *)get_property(dn, "compatible", NULL);
188 193
194 if (!compatible)
195 continue;
196
197 if (strstr(compatible, "CBEA,platform-spider-pic"))
198 spider_reg = *(long *)get_property(dn,"reg", NULL);
199 else if (strstr(compatible, "sti,platform-spider-pic")) {
200 spider_init_IRQ_hardcoded();
201 return;
202 } else
203 continue;
204
205 if (!spider_reg)
206 printk("interrupt controller does not have reg property !\n");
207
208 n = prom_n_addr_cells(dn);
209
210 if ( n != 2)
211 printk("reg property with invalid number of elements \n");
212
213 spider_pics[node] = __ioremap(spider_reg, 0x800, _PAGE_NO_CACHE);
214
215 printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
216 spider_reg, n, spider_pics[node]);
217
218 for (n = 0; n < IIC_NUM_EXT; n++) {
219 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
220 get_irq_desc(irq)->handler = &spider_pic;
189 } 221 }
222
223 /* do not mask any interrupts because of level */
224 out_be32(spider_pics[node] + TIR_MSK, 0x0);
225
226 /* disable edge detection clear */
227 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
228
229 /* enable interrupt packets to be output */
230 out_be32(spider_pics[node] + TIR_PIEN,
231 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
232
233 /* Enable the interrupt detection enable bit. Do this last! */
234 out_be32(spider_pics[node] + TIR_DEN,
235 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
236
237 node++;
190 } 238 }
191} 239}