diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-05-07 02:55:41 +0000 |
commit | dcec8a13bf565e47942a1751a9cec21bec5648fe (patch) | |
tree | 548b69625b18cc2e88c3e68d0923be546c9ebb03 /arch/sparc64/kernel/irq.c | |
parent | 2e0f55e79c49509b7ff70ff1a10e1e9e90a3dfd4 (diff) |
o Merge with Linux 2.1.99.
o Fix ancient bug in the ELF loader making ldd crash.
o Fix ancient bug in the keyboard code for SGI, SNI and Jazz.
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r-- | arch/sparc64/kernel/irq.c | 392 |
1 files changed, 188 insertions, 204 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index a84fe8eaa..176079643 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,7 +1,8 @@ -/* $Id: irq.c,v 1.47 1998/01/10 18:26:17 ecd Exp $ +/* $Id: irq.c,v 1.52 1998/03/19 00:22:54 ecd Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) */ #include <linux/config.h> @@ -98,12 +99,22 @@ int get_irq_list(char *buf) { int i, len = 0; struct irqaction *action; +#ifdef __SMP__ + int j; +#endif for(i = 0; i < (NR_IRQS + 1); i++) { if(!(action = *(i + irq_action))) continue; - len += sprintf(buf + len, "%2d: %8d %c %s", - i, kstat.interrupts[i], + len += sprintf(buf + len, "%3d: ", i); +#ifndef __SMP__ + len += sprintf(buf + len, "%10u ", kstat_irqs(i)); +#else + for (j = 0; j < smp_num_cpus; j++) + len += sprintf(buf + len, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); +#endif + len += sprintf(buf + len, "%c %s", (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for(action = action->next; action; action = action->next) { @@ -113,19 +124,6 @@ int get_irq_list(char *buf) } len += sprintf(buf + len, "\n"); } -#if 0 -#ifdef CONFIG_PCI - { - struct linux_psycho *p; - for (p = psycho_root; p; p = p->next) - len += sprintf(buf + len, - "ISTAT[%d]: PCI[%016lx] OBIO[%016lx]\n", - p->index, - p->psycho_regs->pci_istate, - p->psycho_regs->obio_istate); - } -#endif -#endif return len; } @@ -197,8 +195,7 @@ static unsigned int *sysio_irq_to_imap(unsigned int irq) unsigned long offset; struct sysio_regs *sregs; - if((irq == 14) || - (irq >= NUM_SYSIO_OFFSETS) || + if((irq >= NUM_SYSIO_OFFSETS) || ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1))) return NULL; sregs = SBus_chain->iommu->sysio_regs; @@ -224,8 +221,8 @@ static unsigned int *sysio_imap_to_iclr(unsigned int *imap) unsigned char psycho_ino_to_pil[] = { 7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */ 7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */ - 0, 0, 0, 0, - 0, 0, 0, 0, + 7, 5, 5, 2, /* PCI A slot 2 Int A, B, C, D */ + 7, 5, 5, 2, /* PCI A slot 3 Int A, B, C, D */ 6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */ 6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */ 6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */ @@ -255,13 +252,13 @@ unsigned char psycho_ino_to_pil[] = { */ #define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x))) -#define psycho_imap_offset(ino) \ - ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \ +#define psycho_imap_offset(ino) \ + ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \ (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1))) -#define psycho_iclr_offset(ino) \ - ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \ - (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3))) +#define psycho_iclr_offset(ino) \ + ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \ + (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f)<<3))) #endif @@ -529,7 +526,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) unsigned long flags; unsigned int *imap, *iclr; void *bus_id = NULL; - int ivindex, ivindex_fixup, cpu_irq = -1, pending; + int ivindex = -1, ivindex_fixup, cpu_irq = -1, pending = 0; if(!handler) return -EINVAL; @@ -537,43 +534,47 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) imap = iclr = NULL; ivindex_fixup = 0; + + if (irq == 0) { + cpu_irq = irq; + irqflags &= ~(SA_IMAP_MASKED); + } else { + irqflags |= SA_IMAP_MASKED; #ifdef CONFIG_PCI - if(PCI_IRQ_P(irq)) { - pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); - } else + if(PCI_IRQ_P(irq)) { + pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); + } else #endif - if(irqflags & SA_DCOOKIE) { - if(!dev_id) { - printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n"); - panic("Bogus irq registry."); - } - dcookie = dev_id; - dev_id = dcookie->real_dev_id; - cpu_irq = dcookie->pil; - imap = dcookie->imap; - iclr = dcookie->iclr; - bus_id = dcookie->bus_cookie; - get_irq_translations(&cpu_irq, &ivindex_fixup, &imap, - &iclr, bus_id, irqflags, irq); - } else { - /* XXX NOTE: This code is maintained for compatability until I can - * XXX verify that all drivers sparc64 will use are updated - * XXX to use the new IRQ registry dcookie interface. -DaveM - */ - if(irq == 14) - cpu_irq = irq; - else + if(irqflags & SA_DCOOKIE) { + if(!dev_id) { + printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n"); + panic("Bogus irq registry."); + } + dcookie = dev_id; + dev_id = dcookie->real_dev_id; + cpu_irq = dcookie->pil; + imap = dcookie->imap; + iclr = dcookie->iclr; + bus_id = dcookie->bus_cookie; + get_irq_translations(&cpu_irq, &ivindex_fixup, &imap, + &iclr, bus_id, irqflags, irq); + } else { + /* XXX NOTE: This code is maintained for compatability until I can + * XXX verify that all drivers sparc64 will use are updated + * XXX to use the new IRQ registry dcookie interface. -DaveM + */ cpu_irq = sysio_ino_to_pil[irq]; - imap = sysio_irq_to_imap(irq); - if(!imap) { - printk("request_irq: BAD, null imap for old style " - "irq registry IRQ[%x].\n", irq); - panic("Bad IRQ registery..."); + imap = sysio_irq_to_imap(irq); + if(!imap) { + printk("request_irq: BAD, null imap for old style " + "irq registry IRQ[%x].\n", irq); + panic("Bad IRQ registery..."); + } + iclr = sysio_imap_to_iclr(imap); } - iclr = sysio_imap_to_iclr(imap); + ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + ivindex += ivindex_fixup; } - ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); - ivindex += ivindex_fixup; action = *(cpu_irq + irq_action); if(action) { @@ -612,26 +613,28 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) return -ENOMEM; } - bucket = add_ino_hash(ivindex, imap, iclr, irqflags); - if(!bucket) { - kfree(action); - restore_flags(flags); - return -ENOMEM; - } + if (irqflags & SA_IMAP_MASKED) { + bucket = add_ino_hash(ivindex, imap, iclr, irqflags); + if(!bucket) { + kfree(action); + restore_flags(flags); + return -ENOMEM; + } - pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0); - ivector_to_mask[ivindex] = (1 << cpu_irq); - if(pending) - ivector_to_mask[ivindex] |= 0x80000000; + pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0); + ivector_to_mask[ivindex] = (1 << cpu_irq); + if(pending) + ivector_to_mask[ivindex] |= 0x80000000; - if(dcookie) { - dcookie->ret_ino = ivindex; - dcookie->ret_pil = cpu_irq; + if(dcookie) { + dcookie->ret_ino = ivindex; + dcookie->ret_pil = cpu_irq; + } } action->mask = (unsigned long) bucket; action->handler = handler; - action->flags = irqflags | SA_IMAP_MASKED; + action->flags = irqflags; action->name = name; action->next = NULL; action->dev_id = dev_id; @@ -664,7 +667,7 @@ void free_irq(unsigned int irq, void *dev_id) unsigned int cpu_irq; int ivindex = -1; - if(irq == 14) { + if(irq == 0) { cpu_irq = irq; } else { #ifdef CONFIG_PCI @@ -951,34 +954,43 @@ void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs) void handler_irq(int irq, struct pt_regs *regs) { struct ino_bucket *bucket = NULL; - struct irqaction *action; + struct irqaction *action, *act; int cpu = smp_processor_id(); +#ifndef __SMP__ + /* + * Check for TICK_INT on level 14 softint. + */ + if ((irq == 14) && get_softint() & (1UL << 0)) + irq = 0; +#endif clear_softint(1 << irq); irq_enter(cpu, irq); action = *(irq + irq_action); - kstat.interrupts[irq]++; + kstat.irqs[cpu][irq]++; if(!action) { unexpected_irq(irq, 0, regs); } else { + act = action; do { - unsigned long *swmask = NULL; - - if(action->flags & SA_IMAP_MASKED) { - bucket = (struct ino_bucket *)action->mask; - - swmask = &ivector_to_mask[bucket->ino]; - if(!(*swmask & 0x80000000)) + if(act->flags & SA_IMAP_MASKED) { + bucket = (struct ino_bucket *)act->mask; + if(!(ivector_to_mask[bucket->ino] & 0x80000000)) continue; } - - action->handler(irq, action->dev_id, regs); - if(swmask) { - *swmask &= ~(0x80000000); + act->handler(irq, act->dev_id, regs); + } while((act = act->next) != NULL); + act = action; + do { + if(act->flags & SA_IMAP_MASKED) { + bucket = (struct ino_bucket *)act->mask; + if(!(ivector_to_mask[bucket->ino] & 0x80000000)) + continue; + ivector_to_mask[bucket->ino] &= ~(0x80000000); *(bucket->iclr) = SYSIO_ICLR_IDLE; } - } while((action = action->next) != NULL); + } while((act = act->next) != NULL); } irq_exit(cpu, irq); } @@ -993,6 +1005,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) int cpu = smp_processor_id(); irq_enter(cpu, irq); + kstat.irqs[cpu][irq]++; bucket = (struct ino_bucket *)action->mask; floppy_interrupt(irq, dev_cookie, regs); ivector_to_mask[bucket->ino] &= ~(0x80000000); @@ -1036,13 +1049,19 @@ int request_fast_irq(unsigned int irq, unsigned long flags; unsigned int *imap, *iclr; void *bus_id = NULL; - int ivindex, ivindex_fixup, cpu_irq = -1; + int ivindex = -1, ivindex_fixup, cpu_irq = -1; if(!handler) return -EINVAL; imap = iclr = NULL; ivindex_fixup = 0; + + if ((irq == 0) || (irq == 14)) { + printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n"); + return -EBUSY; + } + #ifdef CONFIG_PCI if(PCI_IRQ_P(irq)) { pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); @@ -1066,10 +1085,7 @@ int request_fast_irq(unsigned int irq, * XXX verify that all drivers sparc64 will use are updated * XXX to use the new IRQ registry dcookie interface. -DaveM */ - if(irq == 14) - cpu_irq = irq; - else - cpu_irq = sysio_ino_to_pil[irq]; + cpu_irq = sysio_ino_to_pil[irq]; imap = sysio_irq_to_imap(irq); if(!imap) { printk("request_irq: BAD, null imap for old style " @@ -1153,85 +1169,100 @@ int probe_irq_off(unsigned long mask) return 0; } -struct sun5_timer *linux_timers = NULL; - -/* This is gets the master level10 timer going. */ -void init_timers(void (*cfunc)(int, void *, struct pt_regs *)) +/* This is gets the master TICK_INT timer going. */ +void init_timers(void (*cfunc)(int, void *, struct pt_regs *), + unsigned long *clock) { - struct linux_prom64_registers pregs[3]; - struct devid_cookie dcookie; - unsigned int *imap, *iclr; - u32 pirqs[2]; + unsigned long flags; + unsigned long timer_tick_offset; int node, err; - node = prom_finddevice("/counter-timer"); - if(node == 0 || node == -1) { - prom_printf("init_timers: Cannot find counter-timer PROM node.\n"); - prom_halt(); - } - err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs)); - if(err == -1) { - prom_printf("init_timers: Cannot obtain 'reg' for counter-timer.\n"); - prom_halt(); - } - err = prom_getproperty(node, "interrupts", (char *)&pirqs[0], sizeof(pirqs)); - if(err == -1) { - prom_printf("init_timers: Cannot obtain 'interrupts' " - "for counter-timer.\n"); - prom_halt(); - } - linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr); - iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1); - imap = (((unsigned int *)__va(pregs[2].phys_addr))+1); - - /* Shut it up first. */ - linux_timers->limit0 = 0; + node = linux_cpus[0].prom_node; + *clock = prom_getint(node, "clock-frequency"); + timer_tick_offset = *clock / HZ; /* Register IRQ handler. */ - dcookie.real_dev_id = NULL; - dcookie.imap = imap; - dcookie.iclr = iclr; - dcookie.pil = 10; - dcookie.bus_cookie = NULL; - - err = request_irq(pirqs[0], cfunc, - (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC), - "timer", &dcookie); + err = request_irq(0, cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), + "timer", NULL); if(err) { - prom_printf("Serious problem, cannot register timer interrupt\n"); + prom_printf("Serious problem, cannot register TICK_INT\n"); prom_halt(); - } else { - unsigned long flags; + } - save_and_cli(flags); + save_and_cli(flags); - /* Set things up so user can access tick register for profiling - * purposes. - */ - __asm__ __volatile__(" - sethi %%hi(0x80000000), %%g1 - sllx %%g1, 32, %%g1 - rd %%tick, %%g2 - add %%g2, 6, %%g2 - andn %%g2, %%g1, %%g2 - wrpr %%g2, 0, %%tick -" : /* no outputs */ - : /* no inputs */ - : "g1", "g2"); - - linux_timers->limit0 = - (SUN5_LIMIT_ENABLE | SUN5_LIMIT_ZRESTART | SUN5_LIMIT_TOZERO | - (SUN5_HZ_TO_LIMIT(HZ) & SUN5_LIMIT_CMASK)); + /* Set things up so user can access tick register for profiling + * purposes. + */ + __asm__ __volatile__(" + sethi %%hi(0x80000000), %%g1 + sllx %%g1, 32, %%g1 + rd %%tick, %%g2 + add %%g2, 6, %%g2 + andn %%g2, %%g1, %%g2 + wrpr %%g2, 0, %%tick +" : /* no outputs */ + : /* no inputs */ + : "g1", "g2"); - restore_flags(flags); - } + __asm__ __volatile__(" + rd %%tick, %%g1 + add %%g1, %0, %%g1 + wr %%g1, 0x0, %%tick_cmpr" + : /* no outputs */ + : "r" (timer_tick_offset) + : "g1"); + restore_flags(flags); sti(); } -struct sun5_timer *prom_timers; +#ifdef __SMP__ +/* Called from smp_commence, when we know how many cpus are in the system + * and can have device IRQ's directed at them. + */ +void distribute_irqs(void) +{ + unsigned long flags; + int cpu, level; + + printk("SMP: redistributing interrupts...\n"); + save_and_cli(flags); + cpu = 0; + for(level = 0; level < NR_IRQS; level++) { + struct irqaction *p = irq_action[level]; + + while(p) { + if(p->flags & SA_IMAP_MASKED) { + struct ino_bucket *bucket = (struct ino_bucket *)p->mask; + unsigned int *imap = bucket->imap; + unsigned int val; + unsigned long tid = __cpu_logical_map[cpu] << 9; + + val = *imap; + *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); + printk("SMP: Redirecting IGN[%x] INO[%x] " + "to cpu %d [%s]\n", + (val & SYSIO_IMAP_IGN) >> 6, + (val & SYSIO_IMAP_INO), cpu, + p->name); + + cpu++; + if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1) + cpu = 0; + } + p = p->next; + } + } + restore_flags(flags); + irqs_have_been_distributed = 1; +} +#endif + + +struct sun5_timer *prom_timers; static u64 prom_limit0, prom_limit1; static void map_prom_timers(void) @@ -1245,9 +1276,8 @@ static void map_prom_timers(void) /* Assume if node is not present, PROM uses different tick mechanism * which we should not care about. */ - if(tnode == 0) { + if(tnode == 0 || tnode == -1) { prom_timers = (struct sun5_timer *) 0; - prom_printf("AIEEE, no timers\n"); return; } @@ -1300,52 +1330,6 @@ void enable_prom_timer(void) prom_timers->count0 = 0; } -#ifdef __SMP__ -/* Called from smp_commence, when we know how many cpus are in the system - * and can have device IRQ's directed at them. - */ -void distribute_irqs(void) -{ - unsigned long flags; - int cpu, level; - - printk("SMP: redistributing interrupts...\n"); - save_and_cli(flags); - cpu = 0; - for(level = 0; level < NR_IRQS; level++) { - struct irqaction *p = irq_action[level]; - - while(p) { - if(p->flags & SA_IMAP_MASKED) { - struct ino_bucket *bucket = (struct ino_bucket *)p->mask; - unsigned int *imap = bucket->imap; - unsigned int val; - unsigned long tid = linux_cpus[cpu].mid << 9; - - val = *imap; - *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); - - printk("SMP: Redirecting IGN[%x] INO[%x] " - "to cpu %d [%s]\n", - (val & SYSIO_IMAP_IGN) >> 6, - (val & SYSIO_IMAP_INO), cpu, - p->name); - - cpu += 1; - while(!(cpu_present_map & (1UL << cpu))) { - cpu += 1; - if(cpu >= smp_num_cpus) - cpu = 0; - } - } - p = p->next; - } - } - restore_flags(flags); - irqs_have_been_distributed = 1; -} -#endif - __initfunc(void init_IRQ(void)) { int i; |