diff options
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r-- | arch/sparc64/kernel/irq.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 6b6165d36fd8..8cb3358674f5 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c | |||
@@ -293,6 +293,11 @@ static void sun4u_irq_enable(unsigned int virt_irq) | |||
293 | } | 293 | } |
294 | } | 294 | } |
295 | 295 | ||
296 | static void sun4u_set_affinity(unsigned int virt_irq, cpumask_t mask) | ||
297 | { | ||
298 | sun4u_irq_enable(virt_irq); | ||
299 | } | ||
300 | |||
296 | static void sun4u_irq_disable(unsigned int virt_irq) | 301 | static void sun4u_irq_disable(unsigned int virt_irq) |
297 | { | 302 | { |
298 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); | 303 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); |
@@ -309,6 +314,10 @@ static void sun4u_irq_disable(unsigned int virt_irq) | |||
309 | static void sun4u_irq_end(unsigned int virt_irq) | 314 | static void sun4u_irq_end(unsigned int virt_irq) |
310 | { | 315 | { |
311 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); | 316 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); |
317 | struct irq_desc *desc = irq_desc + virt_irq; | ||
318 | |||
319 | if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
320 | return; | ||
312 | 321 | ||
313 | if (likely(data)) | 322 | if (likely(data)) |
314 | upa_writeq(ICLR_IDLE, data->iclr); | 323 | upa_writeq(ICLR_IDLE, data->iclr); |
@@ -340,6 +349,24 @@ static void sun4v_irq_enable(unsigned int virt_irq) | |||
340 | } | 349 | } |
341 | } | 350 | } |
342 | 351 | ||
352 | static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask) | ||
353 | { | ||
354 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); | ||
355 | unsigned int ino = bucket - &ivector_table[0]; | ||
356 | |||
357 | if (likely(bucket)) { | ||
358 | unsigned long cpuid; | ||
359 | int err; | ||
360 | |||
361 | cpuid = irq_choose_cpu(virt_irq); | ||
362 | |||
363 | err = sun4v_intr_settarget(ino, cpuid); | ||
364 | if (err != HV_EOK) | ||
365 | printk("sun4v_intr_settarget(%x,%lu): err(%d)\n", | ||
366 | ino, cpuid, err); | ||
367 | } | ||
368 | } | ||
369 | |||
343 | static void sun4v_irq_disable(unsigned int virt_irq) | 370 | static void sun4v_irq_disable(unsigned int virt_irq) |
344 | { | 371 | { |
345 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); | 372 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); |
@@ -373,6 +400,10 @@ static void sun4v_irq_end(unsigned int virt_irq) | |||
373 | { | 400 | { |
374 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); | 401 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); |
375 | unsigned int ino = bucket - &ivector_table[0]; | 402 | unsigned int ino = bucket - &ivector_table[0]; |
403 | struct irq_desc *desc = irq_desc + virt_irq; | ||
404 | |||
405 | if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
406 | return; | ||
376 | 407 | ||
377 | if (likely(bucket)) { | 408 | if (likely(bucket)) { |
378 | int err; | 409 | int err; |
@@ -418,6 +449,28 @@ static void sun4v_virq_enable(unsigned int virt_irq) | |||
418 | } | 449 | } |
419 | } | 450 | } |
420 | 451 | ||
452 | static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask) | ||
453 | { | ||
454 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); | ||
455 | unsigned int ino = bucket - &ivector_table[0]; | ||
456 | |||
457 | if (likely(bucket)) { | ||
458 | unsigned long cpuid, dev_handle, dev_ino; | ||
459 | int err; | ||
460 | |||
461 | cpuid = irq_choose_cpu(virt_irq); | ||
462 | |||
463 | dev_handle = ino & IMAP_IGN; | ||
464 | dev_ino = ino & IMAP_INO; | ||
465 | |||
466 | err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); | ||
467 | if (err != HV_EOK) | ||
468 | printk("sun4v_vintr_set_target(%lx,%lx,%lu): " | ||
469 | "err(%d)\n", | ||
470 | dev_handle, dev_ino, cpuid, err); | ||
471 | } | ||
472 | } | ||
473 | |||
421 | static void sun4v_virq_disable(unsigned int virt_irq) | 474 | static void sun4v_virq_disable(unsigned int virt_irq) |
422 | { | 475 | { |
423 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); | 476 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); |
@@ -443,6 +496,10 @@ static void sun4v_virq_end(unsigned int virt_irq) | |||
443 | { | 496 | { |
444 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); | 497 | struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); |
445 | unsigned int ino = bucket - &ivector_table[0]; | 498 | unsigned int ino = bucket - &ivector_table[0]; |
499 | struct irq_desc *desc = irq_desc + virt_irq; | ||
500 | |||
501 | if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
502 | return; | ||
446 | 503 | ||
447 | if (likely(bucket)) { | 504 | if (likely(bucket)) { |
448 | unsigned long dev_handle, dev_ino; | 505 | unsigned long dev_handle, dev_ino; |
@@ -477,6 +534,7 @@ static struct irq_chip sun4u_irq = { | |||
477 | .enable = sun4u_irq_enable, | 534 | .enable = sun4u_irq_enable, |
478 | .disable = sun4u_irq_disable, | 535 | .disable = sun4u_irq_disable, |
479 | .end = sun4u_irq_end, | 536 | .end = sun4u_irq_end, |
537 | .set_affinity = sun4u_set_affinity, | ||
480 | }; | 538 | }; |
481 | 539 | ||
482 | static struct irq_chip sun4u_irq_ack = { | 540 | static struct irq_chip sun4u_irq_ack = { |
@@ -485,6 +543,7 @@ static struct irq_chip sun4u_irq_ack = { | |||
485 | .disable = sun4u_irq_disable, | 543 | .disable = sun4u_irq_disable, |
486 | .ack = run_pre_handler, | 544 | .ack = run_pre_handler, |
487 | .end = sun4u_irq_end, | 545 | .end = sun4u_irq_end, |
546 | .set_affinity = sun4u_set_affinity, | ||
488 | }; | 547 | }; |
489 | 548 | ||
490 | static struct irq_chip sun4v_irq = { | 549 | static struct irq_chip sun4v_irq = { |
@@ -492,6 +551,7 @@ static struct irq_chip sun4v_irq = { | |||
492 | .enable = sun4v_irq_enable, | 551 | .enable = sun4v_irq_enable, |
493 | .disable = sun4v_irq_disable, | 552 | .disable = sun4v_irq_disable, |
494 | .end = sun4v_irq_end, | 553 | .end = sun4v_irq_end, |
554 | .set_affinity = sun4v_set_affinity, | ||
495 | }; | 555 | }; |
496 | 556 | ||
497 | static struct irq_chip sun4v_irq_ack = { | 557 | static struct irq_chip sun4v_irq_ack = { |
@@ -500,6 +560,7 @@ static struct irq_chip sun4v_irq_ack = { | |||
500 | .disable = sun4v_irq_disable, | 560 | .disable = sun4v_irq_disable, |
501 | .ack = run_pre_handler, | 561 | .ack = run_pre_handler, |
502 | .end = sun4v_irq_end, | 562 | .end = sun4v_irq_end, |
563 | .set_affinity = sun4v_set_affinity, | ||
503 | }; | 564 | }; |
504 | 565 | ||
505 | #ifdef CONFIG_PCI_MSI | 566 | #ifdef CONFIG_PCI_MSI |
@@ -511,6 +572,7 @@ static struct irq_chip sun4v_msi = { | |||
511 | .disable = sun4v_msi_disable, | 572 | .disable = sun4v_msi_disable, |
512 | .ack = run_pre_handler, | 573 | .ack = run_pre_handler, |
513 | .end = sun4v_irq_end, | 574 | .end = sun4v_irq_end, |
575 | .set_affinity = sun4v_set_affinity, | ||
514 | }; | 576 | }; |
515 | #endif | 577 | #endif |
516 | 578 | ||
@@ -519,6 +581,7 @@ static struct irq_chip sun4v_virq = { | |||
519 | .enable = sun4v_virq_enable, | 581 | .enable = sun4v_virq_enable, |
520 | .disable = sun4v_virq_disable, | 582 | .disable = sun4v_virq_disable, |
521 | .end = sun4v_virq_end, | 583 | .end = sun4v_virq_end, |
584 | .set_affinity = sun4v_virt_set_affinity, | ||
522 | }; | 585 | }; |
523 | 586 | ||
524 | static struct irq_chip sun4v_virq_ack = { | 587 | static struct irq_chip sun4v_virq_ack = { |
@@ -527,6 +590,7 @@ static struct irq_chip sun4v_virq_ack = { | |||
527 | .disable = sun4v_virq_disable, | 590 | .disable = sun4v_virq_disable, |
528 | .ack = run_pre_handler, | 591 | .ack = run_pre_handler, |
529 | .end = sun4v_virq_end, | 592 | .end = sun4v_virq_end, |
593 | .set_affinity = sun4v_virt_set_affinity, | ||
530 | }; | 594 | }; |
531 | 595 | ||
532 | void irq_install_pre_handler(int virt_irq, | 596 | void irq_install_pre_handler(int virt_irq, |
@@ -739,6 +803,26 @@ void handler_irq(int irq, struct pt_regs *regs) | |||
739 | set_irq_regs(old_regs); | 803 | set_irq_regs(old_regs); |
740 | } | 804 | } |
741 | 805 | ||
806 | #ifdef CONFIG_HOTPLUG_CPU | ||
807 | void fixup_irqs(void) | ||
808 | { | ||
809 | unsigned int irq; | ||
810 | |||
811 | for (irq = 0; irq < NR_IRQS; irq++) { | ||
812 | unsigned long flags; | ||
813 | |||
814 | spin_lock_irqsave(&irq_desc[irq].lock, flags); | ||
815 | if (irq_desc[irq].action && | ||
816 | !(irq_desc[irq].status & IRQ_PER_CPU)) { | ||
817 | if (irq_desc[irq].chip->set_affinity) | ||
818 | irq_desc[irq].chip->set_affinity(irq, | ||
819 | irq_desc[irq].affinity); | ||
820 | } | ||
821 | spin_unlock_irqrestore(&irq_desc[irq].lock, flags); | ||
822 | } | ||
823 | } | ||
824 | #endif | ||
825 | |||
742 | struct sun5_timer { | 826 | struct sun5_timer { |
743 | u64 count0; | 827 | u64 count0; |
744 | u64 limit0; | 828 | u64 limit0; |