diff options
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 116 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spider-pic.c | 106 |
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 | ||
177 | static int setup_iic(int cpu, struct iic *iic) | 177 | /* hardcoded part to be compatible with older firmware */ |
178 | |||
179 | static 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); | 221 | static 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); | |||
57 | extern u8 iic_get_target_id(int cpu); | 57 | extern u8 iic_get_target_id(int cpu); |
58 | 58 | ||
59 | extern void spider_init_IRQ(void); | 59 | extern void spider_init_IRQ(void); |
60 | extern int spider_get_irq(unsigned long int_pending); | 60 | extern 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 | ||
85 | static void spider_enable_irq(unsigned int irq) | 85 | static 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 | 135 | int spider_get_irq(int node) | |
135 | int 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 | ||
150 | void spider_init_IRQ(void) | 148 | /* hardcoded part to be compatible with older firmware */ |
149 | |||
150 | void 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 | |||
184 | void 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 | } |