diff options
Diffstat (limited to 'arch/powerpc/platforms/iseries/irq.c')
-rw-r--r-- | arch/powerpc/platforms/iseries/irq.c | 105 |
1 files changed, 64 insertions, 41 deletions
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index f70e820e7304..2275e64f3152 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c | |||
@@ -162,27 +162,6 @@ static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs) | |||
162 | printk(KERN_ERR "pci_event_handler: NULL event received\n"); | 162 | printk(KERN_ERR "pci_event_handler: NULL event received\n"); |
163 | } | 163 | } |
164 | 164 | ||
165 | /* | ||
166 | * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c | ||
167 | * It must be called before the bus walk. | ||
168 | */ | ||
169 | void __init iSeries_init_IRQ(void) | ||
170 | { | ||
171 | /* Register PCI event handler and open an event path */ | ||
172 | int ret; | ||
173 | |||
174 | ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, | ||
175 | &pci_event_handler); | ||
176 | if (ret == 0) { | ||
177 | ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); | ||
178 | if (ret != 0) | ||
179 | printk(KERN_ERR "iseries_init_IRQ: open event path " | ||
180 | "failed with rc 0x%x\n", ret); | ||
181 | } else | ||
182 | printk(KERN_ERR "iseries_init_IRQ: register handler " | ||
183 | "failed with rc 0x%x\n", ret); | ||
184 | } | ||
185 | |||
186 | #define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff) | 165 | #define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff) |
187 | #define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) | 166 | #define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) |
188 | #define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) | 167 | #define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) |
@@ -196,7 +175,7 @@ static void iseries_enable_IRQ(unsigned int irq) | |||
196 | { | 175 | { |
197 | u32 bus, dev_id, function, mask; | 176 | u32 bus, dev_id, function, mask; |
198 | const u32 sub_bus = 0; | 177 | const u32 sub_bus = 0; |
199 | unsigned int rirq = virt_irq_to_real_map[irq]; | 178 | unsigned int rirq = (unsigned int)irq_map[irq].hwirq; |
200 | 179 | ||
201 | /* The IRQ has already been locked by the caller */ | 180 | /* The IRQ has already been locked by the caller */ |
202 | bus = REAL_IRQ_TO_BUS(rirq); | 181 | bus = REAL_IRQ_TO_BUS(rirq); |
@@ -213,7 +192,7 @@ static unsigned int iseries_startup_IRQ(unsigned int irq) | |||
213 | { | 192 | { |
214 | u32 bus, dev_id, function, mask; | 193 | u32 bus, dev_id, function, mask; |
215 | const u32 sub_bus = 0; | 194 | const u32 sub_bus = 0; |
216 | unsigned int rirq = virt_irq_to_real_map[irq]; | 195 | unsigned int rirq = (unsigned int)irq_map[irq].hwirq; |
217 | 196 | ||
218 | bus = REAL_IRQ_TO_BUS(rirq); | 197 | bus = REAL_IRQ_TO_BUS(rirq); |
219 | function = REAL_IRQ_TO_FUNC(rirq); | 198 | function = REAL_IRQ_TO_FUNC(rirq); |
@@ -254,7 +233,7 @@ static void iseries_shutdown_IRQ(unsigned int irq) | |||
254 | { | 233 | { |
255 | u32 bus, dev_id, function, mask; | 234 | u32 bus, dev_id, function, mask; |
256 | const u32 sub_bus = 0; | 235 | const u32 sub_bus = 0; |
257 | unsigned int rirq = virt_irq_to_real_map[irq]; | 236 | unsigned int rirq = (unsigned int)irq_map[irq].hwirq; |
258 | 237 | ||
259 | /* irq should be locked by the caller */ | 238 | /* irq should be locked by the caller */ |
260 | bus = REAL_IRQ_TO_BUS(rirq); | 239 | bus = REAL_IRQ_TO_BUS(rirq); |
@@ -277,7 +256,7 @@ static void iseries_disable_IRQ(unsigned int irq) | |||
277 | { | 256 | { |
278 | u32 bus, dev_id, function, mask; | 257 | u32 bus, dev_id, function, mask; |
279 | const u32 sub_bus = 0; | 258 | const u32 sub_bus = 0; |
280 | unsigned int rirq = virt_irq_to_real_map[irq]; | 259 | unsigned int rirq = (unsigned int)irq_map[irq].hwirq; |
281 | 260 | ||
282 | /* The IRQ has already been locked by the caller */ | 261 | /* The IRQ has already been locked by the caller */ |
283 | bus = REAL_IRQ_TO_BUS(rirq); | 262 | bus = REAL_IRQ_TO_BUS(rirq); |
@@ -291,19 +270,19 @@ static void iseries_disable_IRQ(unsigned int irq) | |||
291 | 270 | ||
292 | static void iseries_end_IRQ(unsigned int irq) | 271 | static void iseries_end_IRQ(unsigned int irq) |
293 | { | 272 | { |
294 | unsigned int rirq = virt_irq_to_real_map[irq]; | 273 | unsigned int rirq = (unsigned int)irq_map[irq].hwirq; |
295 | 274 | ||
296 | HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), | 275 | HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), |
297 | (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); | 276 | (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); |
298 | } | 277 | } |
299 | 278 | ||
300 | static hw_irq_controller iSeries_IRQ_handler = { | 279 | static struct irq_chip iseries_pic = { |
301 | .typename = "iSeries irq controller", | 280 | .typename = "iSeries irq controller", |
302 | .startup = iseries_startup_IRQ, | 281 | .startup = iseries_startup_IRQ, |
303 | .shutdown = iseries_shutdown_IRQ, | 282 | .shutdown = iseries_shutdown_IRQ, |
304 | .enable = iseries_enable_IRQ, | 283 | .unmask = iseries_enable_IRQ, |
305 | .disable = iseries_disable_IRQ, | 284 | .mask = iseries_disable_IRQ, |
306 | .end = iseries_end_IRQ | 285 | .eoi = iseries_end_IRQ |
307 | }; | 286 | }; |
308 | 287 | ||
309 | /* | 288 | /* |
@@ -314,17 +293,14 @@ static hw_irq_controller iSeries_IRQ_handler = { | |||
314 | int __init iSeries_allocate_IRQ(HvBusNumber bus, | 293 | int __init iSeries_allocate_IRQ(HvBusNumber bus, |
315 | HvSubBusNumber sub_bus, u32 bsubbus) | 294 | HvSubBusNumber sub_bus, u32 bsubbus) |
316 | { | 295 | { |
317 | int virtirq; | ||
318 | unsigned int realirq; | 296 | unsigned int realirq; |
319 | u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); | 297 | u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); |
320 | u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); | 298 | u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); |
321 | 299 | ||
322 | realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) | 300 | realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) |
323 | + function; | 301 | + function; |
324 | virtirq = virt_irq_create_mapping(realirq); | ||
325 | 302 | ||
326 | irq_desc[virtirq].chip = &iSeries_IRQ_handler; | 303 | return irq_create_mapping(NULL, realirq, IRQ_TYPE_NONE); |
327 | return virtirq; | ||
328 | } | 304 | } |
329 | 305 | ||
330 | #endif /* CONFIG_PCI */ | 306 | #endif /* CONFIG_PCI */ |
@@ -332,10 +308,9 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus, | |||
332 | /* | 308 | /* |
333 | * Get the next pending IRQ. | 309 | * Get the next pending IRQ. |
334 | */ | 310 | */ |
335 | int iSeries_get_irq(struct pt_regs *regs) | 311 | unsigned int iSeries_get_irq(struct pt_regs *regs) |
336 | { | 312 | { |
337 | /* -2 means ignore this interrupt */ | 313 | int irq = NO_IRQ_IGNORE; |
338 | int irq = -2; | ||
339 | 314 | ||
340 | #ifdef CONFIG_SMP | 315 | #ifdef CONFIG_SMP |
341 | if (get_lppaca()->int_dword.fields.ipi_cnt) { | 316 | if (get_lppaca()->int_dword.fields.ipi_cnt) { |
@@ -358,9 +333,57 @@ int iSeries_get_irq(struct pt_regs *regs) | |||
358 | } | 333 | } |
359 | spin_unlock(&pending_irqs_lock); | 334 | spin_unlock(&pending_irqs_lock); |
360 | if (irq >= NR_IRQS) | 335 | if (irq >= NR_IRQS) |
361 | irq = -2; | 336 | irq = NO_IRQ_IGNORE; |
362 | } | 337 | } |
363 | #endif | 338 | #endif |
364 | 339 | ||
365 | return irq; | 340 | return irq; |
366 | } | 341 | } |
342 | |||
343 | static int iseries_irq_host_map(struct irq_host *h, unsigned int virq, | ||
344 | irq_hw_number_t hw, unsigned int flags) | ||
345 | { | ||
346 | set_irq_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static struct irq_host_ops iseries_irq_host_ops = { | ||
352 | .map = iseries_irq_host_map, | ||
353 | }; | ||
354 | |||
355 | /* | ||
356 | * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c | ||
357 | * It must be called before the bus walk. | ||
358 | */ | ||
359 | void __init iSeries_init_IRQ(void) | ||
360 | { | ||
361 | /* Register PCI event handler and open an event path */ | ||
362 | struct irq_host *host; | ||
363 | int ret; | ||
364 | |||
365 | /* | ||
366 | * The Hypervisor only allows us up to 256 interrupt | ||
367 | * sources (the irq number is passed in a u8). | ||
368 | */ | ||
369 | irq_set_virq_count(256); | ||
370 | |||
371 | /* Create irq host. No need for a revmap since HV will give us | ||
372 | * back our virtual irq number | ||
373 | */ | ||
374 | host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &iseries_irq_host_ops, 0); | ||
375 | BUG_ON(host == NULL); | ||
376 | irq_set_default_host(host); | ||
377 | |||
378 | ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, | ||
379 | &pci_event_handler); | ||
380 | if (ret == 0) { | ||
381 | ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); | ||
382 | if (ret != 0) | ||
383 | printk(KERN_ERR "iseries_init_IRQ: open event path " | ||
384 | "failed with rc 0x%x\n", ret); | ||
385 | } else | ||
386 | printk(KERN_ERR "iseries_init_IRQ: register handler " | ||
387 | "failed with rc 0x%x\n", ret); | ||
388 | } | ||
389 | |||