diff options
Diffstat (limited to 'arch/sparc/kernel/pcic.c')
-rw-r--r-- | arch/sparc/kernel/pcic.c | 83 |
1 files changed, 56 insertions, 27 deletions
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 2cdc131b50ac..948601a066ff 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c | |||
@@ -164,6 +164,9 @@ void __iomem *pcic_regs; | |||
164 | volatile int pcic_speculative; | 164 | volatile int pcic_speculative; |
165 | volatile int pcic_trapped; | 165 | volatile int pcic_trapped; |
166 | 166 | ||
167 | /* forward */ | ||
168 | unsigned int pcic_build_device_irq(struct platform_device *op, | ||
169 | unsigned int real_irq); | ||
167 | 170 | ||
168 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) | 171 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3)) |
169 | 172 | ||
@@ -523,6 +526,7 @@ static void | |||
523 | pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) | 526 | pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) |
524 | { | 527 | { |
525 | struct pcic_ca2irq *p; | 528 | struct pcic_ca2irq *p; |
529 | unsigned int real_irq; | ||
526 | int i, ivec; | 530 | int i, ivec; |
527 | char namebuf[64]; | 531 | char namebuf[64]; |
528 | 532 | ||
@@ -551,26 +555,25 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) | |||
551 | i = p->pin; | 555 | i = p->pin; |
552 | if (i >= 0 && i < 4) { | 556 | if (i >= 0 && i < 4) { |
553 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); | 557 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO); |
554 | dev->irq = ivec >> (i << 2) & 0xF; | 558 | real_irq = ivec >> (i << 2) & 0xF; |
555 | } else if (i >= 4 && i < 8) { | 559 | } else if (i >= 4 && i < 8) { |
556 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); | 560 | ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI); |
557 | dev->irq = ivec >> ((i-4) << 2) & 0xF; | 561 | real_irq = ivec >> ((i-4) << 2) & 0xF; |
558 | } else { /* Corrupted map */ | 562 | } else { /* Corrupted map */ |
559 | printk("PCIC: BAD PIN %d\n", i); for (;;) {} | 563 | printk("PCIC: BAD PIN %d\n", i); for (;;) {} |
560 | } | 564 | } |
561 | /* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */ | 565 | /* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */ |
562 | 566 | ||
563 | /* | 567 | /* real_irq means PROM did not bother to program the upper |
564 | * dev->irq=0 means PROM did not bother to program the upper | ||
565 | * half of PCIC. This happens on JS-E with PROM 3.11, for instance. | 568 | * half of PCIC. This happens on JS-E with PROM 3.11, for instance. |
566 | */ | 569 | */ |
567 | if (dev->irq == 0 || p->force) { | 570 | if (real_irq == 0 || p->force) { |
568 | if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */ | 571 | if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */ |
569 | printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {} | 572 | printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {} |
570 | } | 573 | } |
571 | printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n", | 574 | printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n", |
572 | p->irq, p->pin, dev->bus->number, dev->devfn); | 575 | p->irq, p->pin, dev->bus->number, dev->devfn); |
573 | dev->irq = p->irq; | 576 | real_irq = p->irq; |
574 | 577 | ||
575 | i = p->pin; | 578 | i = p->pin; |
576 | if (i >= 4) { | 579 | if (i >= 4) { |
@@ -584,7 +587,8 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) | |||
584 | ivec |= p->irq << (i << 2); | 587 | ivec |= p->irq << (i << 2); |
585 | writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO); | 588 | writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO); |
586 | } | 589 | } |
587 | } | 590 | } |
591 | dev->irq = pcic_build_device_irq(NULL, real_irq); | ||
588 | } | 592 | } |
589 | 593 | ||
590 | /* | 594 | /* |
@@ -729,6 +733,7 @@ void __init pci_time_init(void) | |||
729 | struct linux_pcic *pcic = &pcic0; | 733 | struct linux_pcic *pcic = &pcic0; |
730 | unsigned long v; | 734 | unsigned long v; |
731 | int timer_irq, irq; | 735 | int timer_irq, irq; |
736 | int err; | ||
732 | 737 | ||
733 | do_arch_gettimeoffset = pci_gettimeoffset; | 738 | do_arch_gettimeoffset = pci_gettimeoffset; |
734 | 739 | ||
@@ -740,9 +745,10 @@ void __init pci_time_init(void) | |||
740 | timer_irq = PCI_COUNTER_IRQ_SYS(v); | 745 | timer_irq = PCI_COUNTER_IRQ_SYS(v); |
741 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), | 746 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), |
742 | pcic->pcic_regs+PCI_COUNTER_IRQ); | 747 | pcic->pcic_regs+PCI_COUNTER_IRQ); |
743 | irq = request_irq(timer_irq, pcic_timer_handler, | 748 | irq = pcic_build_device_irq(NULL, timer_irq); |
744 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | 749 | err = request_irq(irq, pcic_timer_handler, |
745 | if (irq) { | 750 | IRQF_TIMER, "timer", NULL); |
751 | if (err) { | ||
746 | prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); | 752 | prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); |
747 | prom_halt(); | 753 | prom_halt(); |
748 | } | 754 | } |
@@ -803,50 +809,73 @@ static inline unsigned long get_irqmask(int irq_nr) | |||
803 | return 1 << irq_nr; | 809 | return 1 << irq_nr; |
804 | } | 810 | } |
805 | 811 | ||
806 | static void pcic_disable_irq(unsigned int irq_nr) | 812 | static void pcic_mask_irq(struct irq_data *data) |
807 | { | 813 | { |
808 | unsigned long mask, flags; | 814 | unsigned long mask, flags; |
809 | 815 | ||
810 | mask = get_irqmask(irq_nr); | 816 | mask = (unsigned long)data->chip_data; |
811 | local_irq_save(flags); | 817 | local_irq_save(flags); |
812 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); | 818 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); |
813 | local_irq_restore(flags); | 819 | local_irq_restore(flags); |
814 | } | 820 | } |
815 | 821 | ||
816 | static void pcic_enable_irq(unsigned int irq_nr) | 822 | static void pcic_unmask_irq(struct irq_data *data) |
817 | { | 823 | { |
818 | unsigned long mask, flags; | 824 | unsigned long mask, flags; |
819 | 825 | ||
820 | mask = get_irqmask(irq_nr); | 826 | mask = (unsigned long)data->chip_data; |
821 | local_irq_save(flags); | 827 | local_irq_save(flags); |
822 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); | 828 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); |
823 | local_irq_restore(flags); | 829 | local_irq_restore(flags); |
824 | } | 830 | } |
825 | 831 | ||
826 | static void pcic_load_profile_irq(int cpu, unsigned int limit) | 832 | static unsigned int pcic_startup_irq(struct irq_data *data) |
827 | { | 833 | { |
828 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); | 834 | irq_link(data->irq); |
835 | pcic_unmask_irq(data); | ||
836 | return 0; | ||
829 | } | 837 | } |
830 | 838 | ||
831 | /* We assume the caller has disabled local interrupts when these are called, | 839 | static struct irq_chip pcic_irq = { |
832 | * or else very bizarre behavior will result. | 840 | .name = "pcic", |
833 | */ | 841 | .irq_startup = pcic_startup_irq, |
834 | static void pcic_disable_pil_irq(unsigned int pil) | 842 | .irq_mask = pcic_mask_irq, |
843 | .irq_unmask = pcic_unmask_irq, | ||
844 | }; | ||
845 | |||
846 | unsigned int pcic_build_device_irq(struct platform_device *op, | ||
847 | unsigned int real_irq) | ||
835 | { | 848 | { |
836 | writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); | 849 | unsigned int irq; |
850 | unsigned long mask; | ||
851 | |||
852 | irq = 0; | ||
853 | mask = get_irqmask(real_irq); | ||
854 | if (mask == 0) | ||
855 | goto out; | ||
856 | |||
857 | irq = irq_alloc(real_irq, real_irq); | ||
858 | if (irq == 0) | ||
859 | goto out; | ||
860 | |||
861 | irq_set_chip_and_handler_name(irq, &pcic_irq, | ||
862 | handle_level_irq, "PCIC"); | ||
863 | irq_set_chip_data(irq, (void *)mask); | ||
864 | |||
865 | out: | ||
866 | return irq; | ||
837 | } | 867 | } |
838 | 868 | ||
839 | static void pcic_enable_pil_irq(unsigned int pil) | 869 | |
870 | static void pcic_load_profile_irq(int cpu, unsigned int limit) | ||
840 | { | 871 | { |
841 | writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); | 872 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); |
842 | } | 873 | } |
843 | 874 | ||
844 | void __init sun4m_pci_init_IRQ(void) | 875 | void __init sun4m_pci_init_IRQ(void) |
845 | { | 876 | { |
846 | BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM); | 877 | sparc_irq_config.build_device_irq = pcic_build_device_irq; |
847 | BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM); | 878 | |
848 | BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM); | ||
849 | BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM); | ||
850 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); | 879 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); |
851 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); | 880 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); |
852 | } | 881 | } |