diff options
Diffstat (limited to 'arch/powerpc/sysdev/xics/xics-common.c')
-rw-r--r-- | arch/powerpc/sysdev/xics/xics-common.c | 59 |
1 files changed, 52 insertions, 7 deletions
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index a795a5f0301c..9d530f479588 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c | |||
@@ -328,8 +328,12 @@ static int xics_host_map(struct irq_domain *h, unsigned int virq, | |||
328 | 328 | ||
329 | pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw); | 329 | pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw); |
330 | 330 | ||
331 | /* They aren't all level sensitive but we just don't really know */ | 331 | /* |
332 | irq_set_status_flags(virq, IRQ_LEVEL); | 332 | * Mark interrupts as edge sensitive by default so that resend |
333 | * actually works. The device-tree parsing will turn the LSIs | ||
334 | * back to level. | ||
335 | */ | ||
336 | irq_clear_status_flags(virq, IRQ_LEVEL); | ||
333 | 337 | ||
334 | /* Don't call into ICS for IPIs */ | 338 | /* Don't call into ICS for IPIs */ |
335 | if (hw == XICS_IPI) { | 339 | if (hw == XICS_IPI) { |
@@ -351,13 +355,54 @@ static int xics_host_xlate(struct irq_domain *h, struct device_node *ct, | |||
351 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 355 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
352 | 356 | ||
353 | { | 357 | { |
354 | /* Current xics implementation translates everything | ||
355 | * to level. It is not technically right for MSIs but this | ||
356 | * is irrelevant at this point. We might get smarter in the future | ||
357 | */ | ||
358 | *out_hwirq = intspec[0]; | 358 | *out_hwirq = intspec[0]; |
359 | *out_flags = IRQ_TYPE_LEVEL_LOW; | ||
360 | 359 | ||
360 | /* | ||
361 | * If intsize is at least 2, we look for the type in the second cell, | ||
362 | * we assume the LSB indicates a level interrupt. | ||
363 | */ | ||
364 | if (intsize > 1) { | ||
365 | if (intspec[1] & 1) | ||
366 | *out_flags = IRQ_TYPE_LEVEL_LOW; | ||
367 | else | ||
368 | *out_flags = IRQ_TYPE_EDGE_RISING; | ||
369 | } else | ||
370 | *out_flags = IRQ_TYPE_LEVEL_LOW; | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | int xics_set_irq_type(struct irq_data *d, unsigned int flow_type) | ||
376 | { | ||
377 | /* | ||
378 | * We only support these. This has really no effect other than setting | ||
379 | * the corresponding descriptor bits mind you but those will in turn | ||
380 | * affect the resend function when re-enabling an edge interrupt. | ||
381 | * | ||
382 | * Set set the default to edge as explained in map(). | ||
383 | */ | ||
384 | if (flow_type == IRQ_TYPE_DEFAULT || flow_type == IRQ_TYPE_NONE) | ||
385 | flow_type = IRQ_TYPE_EDGE_RISING; | ||
386 | |||
387 | if (flow_type != IRQ_TYPE_EDGE_RISING && | ||
388 | flow_type != IRQ_TYPE_LEVEL_LOW) | ||
389 | return -EINVAL; | ||
390 | |||
391 | irqd_set_trigger_type(d, flow_type); | ||
392 | |||
393 | return IRQ_SET_MASK_OK_NOCOPY; | ||
394 | } | ||
395 | |||
396 | int xics_retrigger(struct irq_data *data) | ||
397 | { | ||
398 | /* | ||
399 | * We need to push a dummy CPPR when retriggering, since the subsequent | ||
400 | * EOI will try to pop it. Passing 0 works, as the function hard codes | ||
401 | * the priority value anyway. | ||
402 | */ | ||
403 | xics_push_cppr(0); | ||
404 | |||
405 | /* Tell the core to do a soft retrigger */ | ||
361 | return 0; | 406 | return 0; |
362 | } | 407 | } |
363 | 408 | ||