aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/pcic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/pcic.c')
-rw-r--r--arch/sparc/kernel/pcic.c83
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;
164volatile int pcic_speculative; 164volatile int pcic_speculative;
165volatile int pcic_trapped; 165volatile int pcic_trapped;
166 166
167/* forward */
168unsigned 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
523pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node) 526pcic_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
806static void pcic_disable_irq(unsigned int irq_nr) 812static 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
816static void pcic_enable_irq(unsigned int irq_nr) 822static 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
826static void pcic_load_profile_irq(int cpu, unsigned int limit) 832static 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, 839static struct irq_chip pcic_irq = {
832 * or else very bizarre behavior will result. 840 .name = "pcic",
833 */ 841 .irq_startup = pcic_startup_irq,
834static void pcic_disable_pil_irq(unsigned int pil) 842 .irq_mask = pcic_mask_irq,
843 .irq_unmask = pcic_unmask_irq,
844};
845
846unsigned 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
865out:
866 return irq;
837} 867}
838 868
839static void pcic_enable_pil_irq(unsigned int pil) 869
870static 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
844void __init sun4m_pci_init_IRQ(void) 875void __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}