diff options
Diffstat (limited to 'arch/sparc/kernel/pcic.c')
-rw-r--r-- | arch/sparc/kernel/pcic.c | 91 |
1 files changed, 59 insertions, 32 deletions
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index d36a8d391ca0..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 | ||
@@ -284,7 +287,7 @@ int __init pcic_probe(void) | |||
284 | struct linux_prom_registers regs[PROMREG_MAX]; | 287 | struct linux_prom_registers regs[PROMREG_MAX]; |
285 | struct linux_pbm_info* pbm; | 288 | struct linux_pbm_info* pbm; |
286 | char namebuf[64]; | 289 | char namebuf[64]; |
287 | int node; | 290 | phandle node; |
288 | int err; | 291 | int err; |
289 | 292 | ||
290 | if (pcic0_up) { | 293 | if (pcic0_up) { |
@@ -440,7 +443,7 @@ static int __devinit pdev_to_pnode(struct linux_pbm_info *pbm, | |||
440 | { | 443 | { |
441 | struct linux_prom_pci_registers regs[PROMREG_MAX]; | 444 | struct linux_prom_pci_registers regs[PROMREG_MAX]; |
442 | int err; | 445 | int err; |
443 | int node = prom_getchild(pbm->prom_node); | 446 | phandle node = prom_getchild(pbm->prom_node); |
444 | 447 | ||
445 | while(node) { | 448 | while(node) { |
446 | err = prom_getproperty(node, "reg", | 449 | err = prom_getproperty(node, "reg", |
@@ -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 | /* |
@@ -700,10 +704,8 @@ static void pcic_clear_clock_irq(void) | |||
700 | 704 | ||
701 | static irqreturn_t pcic_timer_handler (int irq, void *h) | 705 | static irqreturn_t pcic_timer_handler (int irq, void *h) |
702 | { | 706 | { |
703 | write_seqlock(&xtime_lock); /* Dummy, to show that we remember */ | ||
704 | pcic_clear_clock_irq(); | 707 | pcic_clear_clock_irq(); |
705 | do_timer(1); | 708 | xtime_update(1); |
706 | write_sequnlock(&xtime_lock); | ||
707 | #ifndef CONFIG_SMP | 709 | #ifndef CONFIG_SMP |
708 | update_process_times(user_mode(get_irq_regs())); | 710 | update_process_times(user_mode(get_irq_regs())); |
709 | #endif | 711 | #endif |
@@ -731,6 +733,7 @@ void __init pci_time_init(void) | |||
731 | struct linux_pcic *pcic = &pcic0; | 733 | struct linux_pcic *pcic = &pcic0; |
732 | unsigned long v; | 734 | unsigned long v; |
733 | int timer_irq, irq; | 735 | int timer_irq, irq; |
736 | int err; | ||
734 | 737 | ||
735 | do_arch_gettimeoffset = pci_gettimeoffset; | 738 | do_arch_gettimeoffset = pci_gettimeoffset; |
736 | 739 | ||
@@ -742,9 +745,10 @@ void __init pci_time_init(void) | |||
742 | timer_irq = PCI_COUNTER_IRQ_SYS(v); | 745 | timer_irq = PCI_COUNTER_IRQ_SYS(v); |
743 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), | 746 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), |
744 | pcic->pcic_regs+PCI_COUNTER_IRQ); | 747 | pcic->pcic_regs+PCI_COUNTER_IRQ); |
745 | irq = request_irq(timer_irq, pcic_timer_handler, | 748 | irq = pcic_build_device_irq(NULL, timer_irq); |
746 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | 749 | err = request_irq(irq, pcic_timer_handler, |
747 | if (irq) { | 750 | IRQF_TIMER, "timer", NULL); |
751 | if (err) { | ||
748 | 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); |
749 | prom_halt(); | 753 | prom_halt(); |
750 | } | 754 | } |
@@ -805,50 +809,73 @@ static inline unsigned long get_irqmask(int irq_nr) | |||
805 | return 1 << irq_nr; | 809 | return 1 << irq_nr; |
806 | } | 810 | } |
807 | 811 | ||
808 | static void pcic_disable_irq(unsigned int irq_nr) | 812 | static void pcic_mask_irq(struct irq_data *data) |
809 | { | 813 | { |
810 | unsigned long mask, flags; | 814 | unsigned long mask, flags; |
811 | 815 | ||
812 | mask = get_irqmask(irq_nr); | 816 | mask = (unsigned long)data->chip_data; |
813 | local_irq_save(flags); | 817 | local_irq_save(flags); |
814 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); | 818 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET); |
815 | local_irq_restore(flags); | 819 | local_irq_restore(flags); |
816 | } | 820 | } |
817 | 821 | ||
818 | static void pcic_enable_irq(unsigned int irq_nr) | 822 | static void pcic_unmask_irq(struct irq_data *data) |
819 | { | 823 | { |
820 | unsigned long mask, flags; | 824 | unsigned long mask, flags; |
821 | 825 | ||
822 | mask = get_irqmask(irq_nr); | 826 | mask = (unsigned long)data->chip_data; |
823 | local_irq_save(flags); | 827 | local_irq_save(flags); |
824 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); | 828 | writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); |
825 | local_irq_restore(flags); | 829 | local_irq_restore(flags); |
826 | } | 830 | } |
827 | 831 | ||
828 | static void pcic_load_profile_irq(int cpu, unsigned int limit) | 832 | static unsigned int pcic_startup_irq(struct irq_data *data) |
829 | { | 833 | { |
830 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); | 834 | irq_link(data->irq); |
835 | pcic_unmask_irq(data); | ||
836 | return 0; | ||
831 | } | 837 | } |
832 | 838 | ||
833 | /* We assume the caller has disabled local interrupts when these are called, | 839 | static struct irq_chip pcic_irq = { |
834 | * or else very bizarre behavior will result. | 840 | .name = "pcic", |
835 | */ | 841 | .irq_startup = pcic_startup_irq, |
836 | 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) | ||
837 | { | 848 | { |
838 | 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; | ||
839 | } | 867 | } |
840 | 868 | ||
841 | static void pcic_enable_pil_irq(unsigned int pil) | 869 | |
870 | static void pcic_load_profile_irq(int cpu, unsigned int limit) | ||
842 | { | 871 | { |
843 | writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR); | 872 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); |
844 | } | 873 | } |
845 | 874 | ||
846 | void __init sun4m_pci_init_IRQ(void) | 875 | void __init sun4m_pci_init_IRQ(void) |
847 | { | 876 | { |
848 | BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM); | 877 | sparc_irq_config.build_device_irq = pcic_build_device_irq; |
849 | BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM); | 878 | |
850 | BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM); | ||
851 | BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM); | ||
852 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); | 879 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); |
853 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); | 880 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); |
854 | } | 881 | } |