diff options
Diffstat (limited to 'arch/powerpc/sysdev/mpic.c')
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 482 |
1 files changed, 292 insertions, 190 deletions
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 7e469358895f..7d31d7cc392d 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -100,8 +100,8 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | |||
100 | 100 | ||
101 | if (mpic->flags & MPIC_PRIMARY) | 101 | if (mpic->flags & MPIC_PRIMARY) |
102 | cpu = hard_smp_processor_id(); | 102 | cpu = hard_smp_processor_id(); |
103 | 103 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, | |
104 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg); | 104 | mpic->cpuregs[cpu], reg); |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) | 107 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) |
@@ -340,27 +340,19 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) | |||
340 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 340 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
341 | 341 | ||
342 | 342 | ||
343 | #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | ||
344 | |||
343 | /* Find an mpic associated with a given linux interrupt */ | 345 | /* Find an mpic associated with a given linux interrupt */ |
344 | static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) | 346 | static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) |
345 | { | 347 | { |
346 | struct mpic *mpic = mpics; | 348 | unsigned int src = mpic_irq_to_hw(irq); |
347 | 349 | ||
348 | while(mpic) { | 350 | if (irq < NUM_ISA_INTERRUPTS) |
349 | /* search IPIs first since they may override the main interrupts */ | 351 | return NULL; |
350 | if (irq >= mpic->ipi_offset && irq < (mpic->ipi_offset + 4)) { | 352 | if (is_ipi) |
351 | if (is_ipi) | 353 | *is_ipi = (src >= MPIC_VEC_IPI_0 && src <= MPIC_VEC_IPI_3); |
352 | *is_ipi = 1; | 354 | |
353 | return mpic; | 355 | return irq_desc[irq].chip_data; |
354 | } | ||
355 | if (irq >= mpic->irq_offset && | ||
356 | irq < (mpic->irq_offset + mpic->irq_count)) { | ||
357 | if (is_ipi) | ||
358 | *is_ipi = 0; | ||
359 | return mpic; | ||
360 | } | ||
361 | mpic = mpic -> next; | ||
362 | } | ||
363 | return NULL; | ||
364 | } | 356 | } |
365 | 357 | ||
366 | /* Convert a cpu mask from logical to physical cpu numbers. */ | 358 | /* Convert a cpu mask from logical to physical cpu numbers. */ |
@@ -378,14 +370,14 @@ static inline u32 mpic_physmask(u32 cpumask) | |||
378 | /* Get the mpic structure from the IPI number */ | 370 | /* Get the mpic structure from the IPI number */ |
379 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) | 371 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) |
380 | { | 372 | { |
381 | return container_of(irq_desc[ipi].chip, struct mpic, hc_ipi); | 373 | return irq_desc[ipi].chip_data; |
382 | } | 374 | } |
383 | #endif | 375 | #endif |
384 | 376 | ||
385 | /* Get the mpic structure from the irq number */ | 377 | /* Get the mpic structure from the irq number */ |
386 | static inline struct mpic * mpic_from_irq(unsigned int irq) | 378 | static inline struct mpic * mpic_from_irq(unsigned int irq) |
387 | { | 379 | { |
388 | return container_of(irq_desc[irq].chip, struct mpic, hc_irq); | 380 | return irq_desc[irq].chip_data; |
389 | } | 381 | } |
390 | 382 | ||
391 | /* Send an EOI */ | 383 | /* Send an EOI */ |
@@ -398,9 +390,7 @@ static inline void mpic_eoi(struct mpic *mpic) | |||
398 | #ifdef CONFIG_SMP | 390 | #ifdef CONFIG_SMP |
399 | static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | 391 | static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) |
400 | { | 392 | { |
401 | struct mpic *mpic = dev_id; | 393 | smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0, regs); |
402 | |||
403 | smp_message_recv(irq - mpic->ipi_offset, regs); | ||
404 | return IRQ_HANDLED; | 394 | return IRQ_HANDLED; |
405 | } | 395 | } |
406 | #endif /* CONFIG_SMP */ | 396 | #endif /* CONFIG_SMP */ |
@@ -410,11 +400,11 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | |||
410 | */ | 400 | */ |
411 | 401 | ||
412 | 402 | ||
413 | static void mpic_enable_irq(unsigned int irq) | 403 | static void mpic_unmask_irq(unsigned int irq) |
414 | { | 404 | { |
415 | unsigned int loops = 100000; | 405 | unsigned int loops = 100000; |
416 | struct mpic *mpic = mpic_from_irq(irq); | 406 | struct mpic *mpic = mpic_from_irq(irq); |
417 | unsigned int src = irq - mpic->irq_offset; | 407 | unsigned int src = mpic_irq_to_hw(irq); |
418 | 408 | ||
419 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); | 409 | DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, irq, src); |
420 | 410 | ||
@@ -429,39 +419,13 @@ static void mpic_enable_irq(unsigned int irq) | |||
429 | break; | 419 | break; |
430 | } | 420 | } |
431 | } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); | 421 | } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); |
432 | |||
433 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
434 | if (mpic->flags & MPIC_BROKEN_U3) { | ||
435 | unsigned int src = irq - mpic->irq_offset; | ||
436 | if (mpic_is_ht_interrupt(mpic, src) && | ||
437 | (irq_desc[irq].status & IRQ_LEVEL)) | ||
438 | mpic_ht_end_irq(mpic, src); | ||
439 | } | ||
440 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
441 | } | ||
442 | |||
443 | static unsigned int mpic_startup_irq(unsigned int irq) | ||
444 | { | ||
445 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
446 | struct mpic *mpic = mpic_from_irq(irq); | ||
447 | unsigned int src = irq - mpic->irq_offset; | ||
448 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
449 | |||
450 | mpic_enable_irq(irq); | ||
451 | |||
452 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
453 | if (mpic_is_ht_interrupt(mpic, src)) | ||
454 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
455 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
456 | |||
457 | return 0; | ||
458 | } | 422 | } |
459 | 423 | ||
460 | static void mpic_disable_irq(unsigned int irq) | 424 | static void mpic_mask_irq(unsigned int irq) |
461 | { | 425 | { |
462 | unsigned int loops = 100000; | 426 | unsigned int loops = 100000; |
463 | struct mpic *mpic = mpic_from_irq(irq); | 427 | struct mpic *mpic = mpic_from_irq(irq); |
464 | unsigned int src = irq - mpic->irq_offset; | 428 | unsigned int src = mpic_irq_to_hw(irq); |
465 | 429 | ||
466 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); | 430 | DBG("%s: disable_irq: %d (src %d)\n", mpic->name, irq, src); |
467 | 431 | ||
@@ -478,23 +442,58 @@ static void mpic_disable_irq(unsigned int irq) | |||
478 | } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); | 442 | } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); |
479 | } | 443 | } |
480 | 444 | ||
481 | static void mpic_shutdown_irq(unsigned int irq) | 445 | static void mpic_end_irq(unsigned int irq) |
482 | { | 446 | { |
447 | struct mpic *mpic = mpic_from_irq(irq); | ||
448 | |||
449 | #ifdef DEBUG_IRQ | ||
450 | DBG("%s: end_irq: %d\n", mpic->name, irq); | ||
451 | #endif | ||
452 | /* We always EOI on end_irq() even for edge interrupts since that | ||
453 | * should only lower the priority, the MPIC should have properly | ||
454 | * latched another edge interrupt coming in anyway | ||
455 | */ | ||
456 | |||
457 | mpic_eoi(mpic); | ||
458 | } | ||
459 | |||
483 | #ifdef CONFIG_MPIC_BROKEN_U3 | 460 | #ifdef CONFIG_MPIC_BROKEN_U3 |
461 | |||
462 | static void mpic_unmask_ht_irq(unsigned int irq) | ||
463 | { | ||
484 | struct mpic *mpic = mpic_from_irq(irq); | 464 | struct mpic *mpic = mpic_from_irq(irq); |
485 | unsigned int src = irq - mpic->irq_offset; | 465 | unsigned int src = mpic_irq_to_hw(irq); |
486 | 466 | ||
487 | if (mpic_is_ht_interrupt(mpic, src)) | 467 | mpic_unmask_irq(irq); |
488 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
489 | 468 | ||
490 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 469 | if (irq_desc[irq].status & IRQ_LEVEL) |
470 | mpic_ht_end_irq(mpic, src); | ||
471 | } | ||
472 | |||
473 | static unsigned int mpic_startup_ht_irq(unsigned int irq) | ||
474 | { | ||
475 | struct mpic *mpic = mpic_from_irq(irq); | ||
476 | unsigned int src = mpic_irq_to_hw(irq); | ||
477 | |||
478 | mpic_unmask_irq(irq); | ||
479 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
491 | 480 | ||
492 | mpic_disable_irq(irq); | 481 | return 0; |
493 | } | 482 | } |
494 | 483 | ||
495 | static void mpic_end_irq(unsigned int irq) | 484 | static void mpic_shutdown_ht_irq(unsigned int irq) |
496 | { | 485 | { |
497 | struct mpic *mpic = mpic_from_irq(irq); | 486 | struct mpic *mpic = mpic_from_irq(irq); |
487 | unsigned int src = mpic_irq_to_hw(irq); | ||
488 | |||
489 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
490 | mpic_mask_irq(irq); | ||
491 | } | ||
492 | |||
493 | static void mpic_end_ht_irq(unsigned int irq) | ||
494 | { | ||
495 | struct mpic *mpic = mpic_from_irq(irq); | ||
496 | unsigned int src = mpic_irq_to_hw(irq); | ||
498 | 497 | ||
499 | #ifdef DEBUG_IRQ | 498 | #ifdef DEBUG_IRQ |
500 | DBG("%s: end_irq: %d\n", mpic->name, irq); | 499 | DBG("%s: end_irq: %d\n", mpic->name, irq); |
@@ -504,30 +503,25 @@ static void mpic_end_irq(unsigned int irq) | |||
504 | * latched another edge interrupt coming in anyway | 503 | * latched another edge interrupt coming in anyway |
505 | */ | 504 | */ |
506 | 505 | ||
507 | #ifdef CONFIG_MPIC_BROKEN_U3 | 506 | if (irq_desc[irq].status & IRQ_LEVEL) |
508 | if (mpic->flags & MPIC_BROKEN_U3) { | 507 | mpic_ht_end_irq(mpic, src); |
509 | unsigned int src = irq - mpic->irq_offset; | ||
510 | if (mpic_is_ht_interrupt(mpic, src) && | ||
511 | (irq_desc[irq].status & IRQ_LEVEL)) | ||
512 | mpic_ht_end_irq(mpic, src); | ||
513 | } | ||
514 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
515 | |||
516 | mpic_eoi(mpic); | 508 | mpic_eoi(mpic); |
517 | } | 509 | } |
518 | 510 | ||
511 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
512 | |||
519 | #ifdef CONFIG_SMP | 513 | #ifdef CONFIG_SMP |
520 | 514 | ||
521 | static void mpic_enable_ipi(unsigned int irq) | 515 | static void mpic_unmask_ipi(unsigned int irq) |
522 | { | 516 | { |
523 | struct mpic *mpic = mpic_from_ipi(irq); | 517 | struct mpic *mpic = mpic_from_ipi(irq); |
524 | unsigned int src = irq - mpic->ipi_offset; | 518 | unsigned int src = mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0; |
525 | 519 | ||
526 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); | 520 | DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, irq, src); |
527 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); | 521 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); |
528 | } | 522 | } |
529 | 523 | ||
530 | static void mpic_disable_ipi(unsigned int irq) | 524 | static void mpic_mask_ipi(unsigned int irq) |
531 | { | 525 | { |
532 | /* NEVER disable an IPI... that's just plain wrong! */ | 526 | /* NEVER disable an IPI... that's just plain wrong! */ |
533 | } | 527 | } |
@@ -551,29 +545,176 @@ static void mpic_end_ipi(unsigned int irq) | |||
551 | static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) | 545 | static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) |
552 | { | 546 | { |
553 | struct mpic *mpic = mpic_from_irq(irq); | 547 | struct mpic *mpic = mpic_from_irq(irq); |
548 | unsigned int src = mpic_irq_to_hw(irq); | ||
554 | 549 | ||
555 | cpumask_t tmp; | 550 | cpumask_t tmp; |
556 | 551 | ||
557 | cpus_and(tmp, cpumask, cpu_online_map); | 552 | cpus_and(tmp, cpumask, cpu_online_map); |
558 | 553 | ||
559 | mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_DESTINATION, | 554 | mpic_irq_write(src, MPIC_IRQ_DESTINATION, |
560 | mpic_physmask(cpus_addr(tmp)[0])); | 555 | mpic_physmask(cpus_addr(tmp)[0])); |
561 | } | 556 | } |
562 | 557 | ||
558 | static unsigned int mpic_flags_to_vecpri(unsigned int flags, int *level) | ||
559 | { | ||
560 | unsigned int vecpri; | ||
561 | |||
562 | /* Now convert sense value */ | ||
563 | switch(flags & IRQ_TYPE_SENSE_MASK) { | ||
564 | case IRQ_TYPE_EDGE_RISING: | ||
565 | vecpri = MPIC_VECPRI_SENSE_EDGE | | ||
566 | MPIC_VECPRI_POLARITY_POSITIVE; | ||
567 | *level = 0; | ||
568 | break; | ||
569 | case IRQ_TYPE_EDGE_FALLING: | ||
570 | vecpri = MPIC_VECPRI_SENSE_EDGE | | ||
571 | MPIC_VECPRI_POLARITY_NEGATIVE; | ||
572 | *level = 0; | ||
573 | break; | ||
574 | case IRQ_TYPE_LEVEL_HIGH: | ||
575 | vecpri = MPIC_VECPRI_SENSE_LEVEL | | ||
576 | MPIC_VECPRI_POLARITY_POSITIVE; | ||
577 | *level = 1; | ||
578 | break; | ||
579 | case IRQ_TYPE_LEVEL_LOW: | ||
580 | default: | ||
581 | vecpri = MPIC_VECPRI_SENSE_LEVEL | | ||
582 | MPIC_VECPRI_POLARITY_NEGATIVE; | ||
583 | *level = 1; | ||
584 | } | ||
585 | return vecpri; | ||
586 | } | ||
587 | |||
588 | static struct irq_chip mpic_irq_chip = { | ||
589 | .mask = mpic_mask_irq, | ||
590 | .unmask = mpic_unmask_irq, | ||
591 | .eoi = mpic_end_irq, | ||
592 | }; | ||
593 | |||
594 | #ifdef CONFIG_SMP | ||
595 | static struct irq_chip mpic_ipi_chip = { | ||
596 | .mask = mpic_mask_ipi, | ||
597 | .unmask = mpic_unmask_ipi, | ||
598 | .eoi = mpic_end_ipi, | ||
599 | }; | ||
600 | #endif /* CONFIG_SMP */ | ||
601 | |||
602 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
603 | static struct irq_chip mpic_irq_ht_chip = { | ||
604 | .startup = mpic_startup_ht_irq, | ||
605 | .shutdown = mpic_shutdown_ht_irq, | ||
606 | .mask = mpic_mask_irq, | ||
607 | .unmask = mpic_unmask_ht_irq, | ||
608 | .eoi = mpic_end_ht_irq, | ||
609 | }; | ||
610 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
611 | |||
612 | |||
613 | static int mpic_host_match(struct irq_host *h, struct device_node *node) | ||
614 | { | ||
615 | struct mpic *mpic = h->host_data; | ||
616 | |||
617 | /* Exact match, unless mpic node is NULL */ | ||
618 | return mpic->of_node == NULL || mpic->of_node == node; | ||
619 | } | ||
620 | |||
621 | static int mpic_host_map(struct irq_host *h, unsigned int virq, | ||
622 | irq_hw_number_t hw, unsigned int flags) | ||
623 | { | ||
624 | struct irq_desc *desc = get_irq_desc(virq); | ||
625 | struct irq_chip *chip; | ||
626 | struct mpic *mpic = h->host_data; | ||
627 | unsigned int vecpri = MPIC_VECPRI_SENSE_LEVEL | | ||
628 | MPIC_VECPRI_POLARITY_NEGATIVE; | ||
629 | int level; | ||
630 | |||
631 | pr_debug("mpic: map virq %d, hwirq 0x%lx, flags: 0x%x\n", | ||
632 | virq, hw, flags); | ||
633 | |||
634 | if (hw == MPIC_VEC_SPURRIOUS) | ||
635 | return -EINVAL; | ||
636 | #ifdef CONFIG_SMP | ||
637 | else if (hw >= MPIC_VEC_IPI_0) { | ||
638 | WARN_ON(!(mpic->flags & MPIC_PRIMARY)); | ||
639 | |||
640 | pr_debug("mpic: mapping as IPI\n"); | ||
641 | set_irq_chip_data(virq, mpic); | ||
642 | set_irq_chip_and_handler(virq, &mpic->hc_ipi, | ||
643 | handle_percpu_irq); | ||
644 | return 0; | ||
645 | } | ||
646 | #endif /* CONFIG_SMP */ | ||
647 | |||
648 | if (hw >= mpic->irq_count) | ||
649 | return -EINVAL; | ||
650 | |||
651 | /* If no sense provided, check default sense array */ | ||
652 | if (((flags & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_NONE) && | ||
653 | mpic->senses && hw < mpic->senses_count) | ||
654 | flags |= mpic->senses[hw]; | ||
655 | |||
656 | vecpri = mpic_flags_to_vecpri(flags, &level); | ||
657 | if (level) | ||
658 | desc->status |= IRQ_LEVEL; | ||
659 | chip = &mpic->hc_irq; | ||
660 | |||
661 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
662 | /* Check for HT interrupts, override vecpri */ | ||
663 | if (mpic_is_ht_interrupt(mpic, hw)) { | ||
664 | vecpri &= ~(MPIC_VECPRI_SENSE_MASK | | ||
665 | MPIC_VECPRI_POLARITY_MASK); | ||
666 | vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; | ||
667 | chip = &mpic->hc_ht_irq; | ||
668 | } | ||
669 | #endif | ||
670 | |||
671 | /* Reconfigure irq */ | ||
672 | vecpri |= MPIC_VECPRI_MASK | hw | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | ||
673 | mpic_irq_write(hw, MPIC_IRQ_VECTOR_PRI, vecpri); | ||
674 | |||
675 | pr_debug("mpic: mapping as IRQ\n"); | ||
676 | |||
677 | set_irq_chip_data(virq, mpic); | ||
678 | set_irq_chip_and_handler(virq, chip, handle_fasteoi_irq); | ||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | ||
683 | u32 *intspec, unsigned int intsize, | ||
684 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | ||
685 | |||
686 | { | ||
687 | static unsigned char map_mpic_senses[4] = { | ||
688 | IRQ_TYPE_EDGE_RISING, | ||
689 | IRQ_TYPE_LEVEL_LOW, | ||
690 | IRQ_TYPE_LEVEL_HIGH, | ||
691 | IRQ_TYPE_EDGE_FALLING, | ||
692 | }; | ||
693 | |||
694 | *out_hwirq = intspec[0]; | ||
695 | if (intsize > 1 && intspec[1] < 4) | ||
696 | *out_flags = map_mpic_senses[intspec[1]]; | ||
697 | else | ||
698 | *out_flags = IRQ_TYPE_NONE; | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static struct irq_host_ops mpic_host_ops = { | ||
704 | .match = mpic_host_match, | ||
705 | .map = mpic_host_map, | ||
706 | .xlate = mpic_host_xlate, | ||
707 | }; | ||
563 | 708 | ||
564 | /* | 709 | /* |
565 | * Exported functions | 710 | * Exported functions |
566 | */ | 711 | */ |
567 | 712 | ||
568 | 713 | struct mpic * __init mpic_alloc(struct device_node *node, | |
569 | struct mpic * __init mpic_alloc(unsigned long phys_addr, | 714 | unsigned long phys_addr, |
570 | unsigned int flags, | 715 | unsigned int flags, |
571 | unsigned int isu_size, | 716 | unsigned int isu_size, |
572 | unsigned int irq_offset, | ||
573 | unsigned int irq_count, | 717 | unsigned int irq_count, |
574 | unsigned int ipi_offset, | ||
575 | unsigned char *senses, | ||
576 | unsigned int senses_count, | ||
577 | const char *name) | 718 | const char *name) |
578 | { | 719 | { |
579 | struct mpic *mpic; | 720 | struct mpic *mpic; |
@@ -585,33 +726,38 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
585 | if (mpic == NULL) | 726 | if (mpic == NULL) |
586 | return NULL; | 727 | return NULL; |
587 | 728 | ||
588 | |||
589 | memset(mpic, 0, sizeof(struct mpic)); | 729 | memset(mpic, 0, sizeof(struct mpic)); |
590 | mpic->name = name; | 730 | mpic->name = name; |
731 | mpic->of_node = node ? of_node_get(node) : NULL; | ||
591 | 732 | ||
733 | mpic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 256, | ||
734 | &mpic_host_ops, | ||
735 | MPIC_VEC_SPURRIOUS); | ||
736 | if (mpic->irqhost == NULL) { | ||
737 | of_node_put(node); | ||
738 | return NULL; | ||
739 | } | ||
740 | |||
741 | mpic->irqhost->host_data = mpic; | ||
742 | mpic->hc_irq = mpic_irq_chip; | ||
592 | mpic->hc_irq.typename = name; | 743 | mpic->hc_irq.typename = name; |
593 | mpic->hc_irq.startup = mpic_startup_irq; | ||
594 | mpic->hc_irq.shutdown = mpic_shutdown_irq; | ||
595 | mpic->hc_irq.enable = mpic_enable_irq; | ||
596 | mpic->hc_irq.disable = mpic_disable_irq; | ||
597 | mpic->hc_irq.end = mpic_end_irq; | ||
598 | if (flags & MPIC_PRIMARY) | 744 | if (flags & MPIC_PRIMARY) |
599 | mpic->hc_irq.set_affinity = mpic_set_affinity; | 745 | mpic->hc_irq.set_affinity = mpic_set_affinity; |
746 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
747 | mpic->hc_ht_irq = mpic_irq_ht_chip; | ||
748 | mpic->hc_ht_irq.typename = name; | ||
749 | if (flags & MPIC_PRIMARY) | ||
750 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; | ||
751 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
600 | #ifdef CONFIG_SMP | 752 | #ifdef CONFIG_SMP |
753 | mpic->hc_ipi = mpic_ipi_chip; | ||
601 | mpic->hc_ipi.typename = name; | 754 | mpic->hc_ipi.typename = name; |
602 | mpic->hc_ipi.enable = mpic_enable_ipi; | ||
603 | mpic->hc_ipi.disable = mpic_disable_ipi; | ||
604 | mpic->hc_ipi.end = mpic_end_ipi; | ||
605 | #endif /* CONFIG_SMP */ | 755 | #endif /* CONFIG_SMP */ |
606 | 756 | ||
607 | mpic->flags = flags; | 757 | mpic->flags = flags; |
608 | mpic->isu_size = isu_size; | 758 | mpic->isu_size = isu_size; |
609 | mpic->irq_offset = irq_offset; | ||
610 | mpic->irq_count = irq_count; | 759 | mpic->irq_count = irq_count; |
611 | mpic->ipi_offset = ipi_offset; | ||
612 | mpic->num_sources = 0; /* so far */ | 760 | mpic->num_sources = 0; /* so far */ |
613 | mpic->senses = senses; | ||
614 | mpic->senses_count = senses_count; | ||
615 | 761 | ||
616 | /* Map the global registers */ | 762 | /* Map the global registers */ |
617 | mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); | 763 | mpic->gregs = ioremap(phys_addr + MPIC_GREG_BASE, 0x1000); |
@@ -679,8 +825,10 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
679 | mpic->next = mpics; | 825 | mpic->next = mpics; |
680 | mpics = mpic; | 826 | mpics = mpic; |
681 | 827 | ||
682 | if (flags & MPIC_PRIMARY) | 828 | if (flags & MPIC_PRIMARY) { |
683 | mpic_primary = mpic; | 829 | mpic_primary = mpic; |
830 | irq_set_default_host(mpic->irqhost); | ||
831 | } | ||
684 | 832 | ||
685 | return mpic; | 833 | return mpic; |
686 | } | 834 | } |
@@ -697,26 +845,10 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | |||
697 | mpic->num_sources = isu_first + mpic->isu_size; | 845 | mpic->num_sources = isu_first + mpic->isu_size; |
698 | } | 846 | } |
699 | 847 | ||
700 | void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler, | 848 | void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count) |
701 | void *data) | ||
702 | { | 849 | { |
703 | struct mpic *mpic = mpic_find(irq, NULL); | 850 | mpic->senses = senses; |
704 | unsigned long flags; | 851 | mpic->senses_count = count; |
705 | |||
706 | /* Synchronization here is a bit dodgy, so don't try to replace cascade | ||
707 | * interrupts on the fly too often ... but normally it's set up at boot. | ||
708 | */ | ||
709 | spin_lock_irqsave(&mpic_lock, flags); | ||
710 | if (mpic->cascade) | ||
711 | mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset); | ||
712 | mpic->cascade = NULL; | ||
713 | wmb(); | ||
714 | mpic->cascade_vec = irq - mpic->irq_offset; | ||
715 | mpic->cascade_data = data; | ||
716 | wmb(); | ||
717 | mpic->cascade = handler; | ||
718 | mpic_enable_irq(irq); | ||
719 | spin_unlock_irqrestore(&mpic_lock, flags); | ||
720 | } | 852 | } |
721 | 853 | ||
722 | void __init mpic_init(struct mpic *mpic) | 854 | void __init mpic_init(struct mpic *mpic) |
@@ -724,6 +856,11 @@ void __init mpic_init(struct mpic *mpic) | |||
724 | int i; | 856 | int i; |
725 | 857 | ||
726 | BUG_ON(mpic->num_sources == 0); | 858 | BUG_ON(mpic->num_sources == 0); |
859 | WARN_ON(mpic->num_sources > MPIC_VEC_IPI_0); | ||
860 | |||
861 | /* Sanitize source count */ | ||
862 | if (mpic->num_sources > MPIC_VEC_IPI_0) | ||
863 | mpic->num_sources = MPIC_VEC_IPI_0; | ||
727 | 864 | ||
728 | printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); | 865 | printk(KERN_INFO "mpic: Initializing for %d sources\n", mpic->num_sources); |
729 | 866 | ||
@@ -747,12 +884,6 @@ void __init mpic_init(struct mpic *mpic) | |||
747 | MPIC_VECPRI_MASK | | 884 | MPIC_VECPRI_MASK | |
748 | (10 << MPIC_VECPRI_PRIORITY_SHIFT) | | 885 | (10 << MPIC_VECPRI_PRIORITY_SHIFT) | |
749 | (MPIC_VEC_IPI_0 + i)); | 886 | (MPIC_VEC_IPI_0 + i)); |
750 | #ifdef CONFIG_SMP | ||
751 | if (!(mpic->flags & MPIC_PRIMARY)) | ||
752 | continue; | ||
753 | irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU; | ||
754 | irq_desc[mpic->ipi_offset+i].chip = &mpic->hc_ipi; | ||
755 | #endif /* CONFIG_SMP */ | ||
756 | } | 887 | } |
757 | 888 | ||
758 | /* Initialize interrupt sources */ | 889 | /* Initialize interrupt sources */ |
@@ -763,31 +894,21 @@ void __init mpic_init(struct mpic *mpic) | |||
763 | /* Do the HT PIC fixups on U3 broken mpic */ | 894 | /* Do the HT PIC fixups on U3 broken mpic */ |
764 | DBG("MPIC flags: %x\n", mpic->flags); | 895 | DBG("MPIC flags: %x\n", mpic->flags); |
765 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) | 896 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) |
766 | mpic_scan_ht_pics(mpic); | 897 | mpic_scan_ht_pics(mpic); |
767 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 898 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
768 | 899 | ||
769 | for (i = 0; i < mpic->num_sources; i++) { | 900 | for (i = 0; i < mpic->num_sources; i++) { |
770 | /* start with vector = source number, and masked */ | 901 | /* start with vector = source number, and masked */ |
771 | u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); | 902 | u32 vecpri = MPIC_VECPRI_MASK | i | (8 << MPIC_VECPRI_PRIORITY_SHIFT); |
772 | int level = 0; | 903 | int level = 1; |
773 | 904 | ||
774 | /* if it's an IPI, we skip it */ | ||
775 | if ((mpic->irq_offset + i) >= (mpic->ipi_offset + i) && | ||
776 | (mpic->irq_offset + i) < (mpic->ipi_offset + i + 4)) | ||
777 | continue; | ||
778 | |||
779 | /* do senses munging */ | 905 | /* do senses munging */ |
780 | if (mpic->senses && i < mpic->senses_count) { | 906 | if (mpic->senses && i < mpic->senses_count) |
781 | if (mpic->senses[i] & IRQ_SENSE_LEVEL) | 907 | vecpri = mpic_flags_to_vecpri(mpic->senses[i], |
782 | vecpri |= MPIC_VECPRI_SENSE_LEVEL; | 908 | &level); |
783 | if (mpic->senses[i] & IRQ_POLARITY_POSITIVE) | 909 | else |
784 | vecpri |= MPIC_VECPRI_POLARITY_POSITIVE; | ||
785 | } else | ||
786 | vecpri |= MPIC_VECPRI_SENSE_LEVEL; | 910 | vecpri |= MPIC_VECPRI_SENSE_LEVEL; |
787 | 911 | ||
788 | /* remember if it was a level interrupts */ | ||
789 | level = (vecpri & MPIC_VECPRI_SENSE_LEVEL); | ||
790 | |||
791 | /* deal with broken U3 */ | 912 | /* deal with broken U3 */ |
792 | if (mpic->flags & MPIC_BROKEN_U3) { | 913 | if (mpic->flags & MPIC_BROKEN_U3) { |
793 | #ifdef CONFIG_MPIC_BROKEN_U3 | 914 | #ifdef CONFIG_MPIC_BROKEN_U3 |
@@ -808,12 +929,6 @@ void __init mpic_init(struct mpic *mpic) | |||
808 | mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); | 929 | mpic_irq_write(i, MPIC_IRQ_VECTOR_PRI, vecpri); |
809 | mpic_irq_write(i, MPIC_IRQ_DESTINATION, | 930 | mpic_irq_write(i, MPIC_IRQ_DESTINATION, |
810 | 1 << hard_smp_processor_id()); | 931 | 1 << hard_smp_processor_id()); |
811 | |||
812 | /* init linux descriptors */ | ||
813 | if (i < mpic->irq_count) { | ||
814 | irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0; | ||
815 | irq_desc[mpic->irq_offset+i].chip = &mpic->hc_irq; | ||
816 | } | ||
817 | } | 932 | } |
818 | 933 | ||
819 | /* Init spurrious vector */ | 934 | /* Init spurrious vector */ |
@@ -854,19 +969,20 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) | |||
854 | { | 969 | { |
855 | int is_ipi; | 970 | int is_ipi; |
856 | struct mpic *mpic = mpic_find(irq, &is_ipi); | 971 | struct mpic *mpic = mpic_find(irq, &is_ipi); |
972 | unsigned int src = mpic_irq_to_hw(irq); | ||
857 | unsigned long flags; | 973 | unsigned long flags; |
858 | u32 reg; | 974 | u32 reg; |
859 | 975 | ||
860 | spin_lock_irqsave(&mpic_lock, flags); | 976 | spin_lock_irqsave(&mpic_lock, flags); |
861 | if (is_ipi) { | 977 | if (is_ipi) { |
862 | reg = mpic_ipi_read(irq - mpic->ipi_offset) & | 978 | reg = mpic_ipi_read(src - MPIC_VEC_IPI_0) & |
863 | ~MPIC_VECPRI_PRIORITY_MASK; | 979 | ~MPIC_VECPRI_PRIORITY_MASK; |
864 | mpic_ipi_write(irq - mpic->ipi_offset, | 980 | mpic_ipi_write(src - MPIC_VEC_IPI_0, |
865 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | 981 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); |
866 | } else { | 982 | } else { |
867 | reg = mpic_irq_read(irq - mpic->irq_offset,MPIC_IRQ_VECTOR_PRI) | 983 | reg = mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) |
868 | & ~MPIC_VECPRI_PRIORITY_MASK; | 984 | & ~MPIC_VECPRI_PRIORITY_MASK; |
869 | mpic_irq_write(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI, | 985 | mpic_irq_write(src, MPIC_IRQ_VECTOR_PRI, |
870 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); | 986 | reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT)); |
871 | } | 987 | } |
872 | spin_unlock_irqrestore(&mpic_lock, flags); | 988 | spin_unlock_irqrestore(&mpic_lock, flags); |
@@ -876,14 +992,15 @@ unsigned int mpic_irq_get_priority(unsigned int irq) | |||
876 | { | 992 | { |
877 | int is_ipi; | 993 | int is_ipi; |
878 | struct mpic *mpic = mpic_find(irq, &is_ipi); | 994 | struct mpic *mpic = mpic_find(irq, &is_ipi); |
995 | unsigned int src = mpic_irq_to_hw(irq); | ||
879 | unsigned long flags; | 996 | unsigned long flags; |
880 | u32 reg; | 997 | u32 reg; |
881 | 998 | ||
882 | spin_lock_irqsave(&mpic_lock, flags); | 999 | spin_lock_irqsave(&mpic_lock, flags); |
883 | if (is_ipi) | 1000 | if (is_ipi) |
884 | reg = mpic_ipi_read(irq - mpic->ipi_offset); | 1001 | reg = mpic_ipi_read(src = MPIC_VEC_IPI_0); |
885 | else | 1002 | else |
886 | reg = mpic_irq_read(irq - mpic->irq_offset, MPIC_IRQ_VECTOR_PRI); | 1003 | reg = mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI); |
887 | spin_unlock_irqrestore(&mpic_lock, flags); | 1004 | spin_unlock_irqrestore(&mpic_lock, flags); |
888 | return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; | 1005 | return (reg & MPIC_VECPRI_PRIORITY_MASK) >> MPIC_VECPRI_PRIORITY_SHIFT; |
889 | } | 1006 | } |
@@ -978,37 +1095,20 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) | |||
978 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); | 1095 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); |
979 | } | 1096 | } |
980 | 1097 | ||
981 | int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) | 1098 | unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) |
982 | { | 1099 | { |
983 | u32 irq; | 1100 | u32 src; |
984 | 1101 | ||
985 | irq = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; | 1102 | src = mpic_cpu_read(MPIC_CPU_INTACK) & MPIC_VECPRI_VECTOR_MASK; |
986 | #ifdef DEBUG_LOW | 1103 | #ifdef DEBUG_LOW |
987 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); | 1104 | DBG("%s: get_one_irq(): %d\n", mpic->name, src); |
988 | #endif | 1105 | #endif |
989 | if (mpic->cascade && irq == mpic->cascade_vec) { | 1106 | if (unlikely(src == MPIC_VEC_SPURRIOUS)) |
990 | #ifdef DEBUG_LOW | 1107 | return NO_IRQ; |
991 | DBG("%s: cascading ...\n", mpic->name); | 1108 | return irq_linear_revmap(mpic->irqhost, src); |
992 | #endif | ||
993 | irq = mpic->cascade(regs, mpic->cascade_data); | ||
994 | mpic_eoi(mpic); | ||
995 | return irq; | ||
996 | } | ||
997 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) | ||
998 | return -1; | ||
999 | if (irq < MPIC_VEC_IPI_0) { | ||
1000 | #ifdef DEBUG_IRQ | ||
1001 | DBG("%s: irq %d\n", mpic->name, irq + mpic->irq_offset); | ||
1002 | #endif | ||
1003 | return irq + mpic->irq_offset; | ||
1004 | } | ||
1005 | #ifdef DEBUG_IPI | ||
1006 | DBG("%s: ipi %d !\n", mpic->name, irq - MPIC_VEC_IPI_0); | ||
1007 | #endif | ||
1008 | return irq - MPIC_VEC_IPI_0 + mpic->ipi_offset; | ||
1009 | } | 1109 | } |
1010 | 1110 | ||
1011 | int mpic_get_irq(struct pt_regs *regs) | 1111 | unsigned int mpic_get_irq(struct pt_regs *regs) |
1012 | { | 1112 | { |
1013 | struct mpic *mpic = mpic_primary; | 1113 | struct mpic *mpic = mpic_primary; |
1014 | 1114 | ||
@@ -1022,25 +1122,27 @@ int mpic_get_irq(struct pt_regs *regs) | |||
1022 | void mpic_request_ipis(void) | 1122 | void mpic_request_ipis(void) |
1023 | { | 1123 | { |
1024 | struct mpic *mpic = mpic_primary; | 1124 | struct mpic *mpic = mpic_primary; |
1025 | 1125 | int i; | |
1126 | static char *ipi_names[] = { | ||
1127 | "IPI0 (call function)", | ||
1128 | "IPI1 (reschedule)", | ||
1129 | "IPI2 (unused)", | ||
1130 | "IPI3 (debugger break)", | ||
1131 | }; | ||
1026 | BUG_ON(mpic == NULL); | 1132 | BUG_ON(mpic == NULL); |
1027 | |||
1028 | printk("requesting IPIs ... \n"); | ||
1029 | 1133 | ||
1030 | /* | 1134 | printk(KERN_INFO "mpic: requesting IPIs ... \n"); |
1031 | * IPIs are marked IRQF_DISABLED as they must run with irqs | 1135 | |
1032 | * disabled | 1136 | for (i = 0; i < 4; i++) { |
1033 | */ | 1137 | unsigned int vipi = irq_create_mapping(mpic->irqhost, |
1034 | request_irq(mpic->ipi_offset+0, mpic_ipi_action, IRQF_DISABLED, | 1138 | MPIC_VEC_IPI_0 + i, 0); |
1035 | "IPI0 (call function)", mpic); | 1139 | if (vipi == NO_IRQ) { |
1036 | request_irq(mpic->ipi_offset+1, mpic_ipi_action, IRQF_DISABLED, | 1140 | printk(KERN_ERR "Failed to map IPI %d\n", i); |
1037 | "IPI1 (reschedule)", mpic); | 1141 | break; |
1038 | request_irq(mpic->ipi_offset+2, mpic_ipi_action, IRQF_DISABLED, | 1142 | } |
1039 | "IPI2 (unused)", mpic); | 1143 | request_irq(vipi, mpic_ipi_action, IRQF_DISABLED, |
1040 | request_irq(mpic->ipi_offset+3, mpic_ipi_action, IRQF_DISABLED, | 1144 | ipi_names[i], mpic); |
1041 | "IPI3 (debugger break)", mpic); | 1145 | } |
1042 | |||
1043 | printk("IPIs requested... \n"); | ||
1044 | } | 1146 | } |
1045 | 1147 | ||
1046 | void smp_mpic_message_pass(int target, int msg) | 1148 | void smp_mpic_message_pass(int target, int msg) |