11da177e4SLinus Torvalds /* sun4m_irq.c 21da177e4SLinus Torvalds * arch/sparc/kernel/sun4m_irq.c: 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * djhr: Hacked out of irq.c into a CPU dependent version. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 71da177e4SLinus Torvalds * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) 81da177e4SLinus Torvalds * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@yahoo.com) 91da177e4SLinus Torvalds * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/errno.h> 131da177e4SLinus Torvalds #include <linux/linkage.h> 141da177e4SLinus Torvalds #include <linux/kernel_stat.h> 151da177e4SLinus Torvalds #include <linux/signal.h> 161da177e4SLinus Torvalds #include <linux/sched.h> 171da177e4SLinus Torvalds #include <linux/ptrace.h> 181da177e4SLinus Torvalds #include <linux/smp.h> 191da177e4SLinus Torvalds #include <linux/interrupt.h> 201da177e4SLinus Torvalds #include <linux/slab.h> 211da177e4SLinus Torvalds #include <linux/init.h> 221da177e4SLinus Torvalds #include <linux/ioport.h> 23*454eeb2dSDavid S. Miller #include <linux/of.h> 24*454eeb2dSDavid S. Miller #include <linux/of_device.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <asm/ptrace.h> 271da177e4SLinus Torvalds #include <asm/processor.h> 281da177e4SLinus Torvalds #include <asm/system.h> 291da177e4SLinus Torvalds #include <asm/psr.h> 301da177e4SLinus Torvalds #include <asm/vaddrs.h> 311da177e4SLinus Torvalds #include <asm/timer.h> 321da177e4SLinus Torvalds #include <asm/openprom.h> 331da177e4SLinus Torvalds #include <asm/oplib.h> 341da177e4SLinus Torvalds #include <asm/traps.h> 351da177e4SLinus Torvalds #include <asm/pgalloc.h> 361da177e4SLinus Torvalds #include <asm/pgtable.h> 371da177e4SLinus Torvalds #include <asm/smp.h> 381da177e4SLinus Torvalds #include <asm/irq.h> 391da177e4SLinus Torvalds #include <asm/io.h> 401da177e4SLinus Torvalds #include <asm/cacheflush.h> 411da177e4SLinus Torvalds 4232231a66SAl Viro #include "irq.h" 4332231a66SAl Viro 4432231a66SAl Viro /* On the sun4m, just like the timers, we have both per-cpu and master 4532231a66SAl Viro * interrupt registers. 4632231a66SAl Viro */ 4732231a66SAl Viro 4832231a66SAl Viro /* These registers are used for sending/receiving irqs from/to 4932231a66SAl Viro * different cpu's. 5032231a66SAl Viro */ 5132231a66SAl Viro struct sun4m_intreg_percpu { 5232231a66SAl Viro unsigned int tbt; /* Interrupts still pending for this cpu. */ 5332231a66SAl Viro 5432231a66SAl Viro /* These next two registers are WRITE-ONLY and are only 5532231a66SAl Viro * "on bit" sensitive, "off bits" written have NO affect. 5632231a66SAl Viro */ 5732231a66SAl Viro unsigned int clear; /* Clear this cpus irqs here. */ 5832231a66SAl Viro unsigned int set; /* Set this cpus irqs here. */ 5932231a66SAl Viro unsigned char space[PAGE_SIZE - 12]; 6032231a66SAl Viro }; 6132231a66SAl Viro 6232231a66SAl Viro /* 6332231a66SAl Viro * djhr 6432231a66SAl Viro * Actually the clear and set fields in this struct are misleading.. 6532231a66SAl Viro * according to the SLAVIO manual (and the same applies for the SEC) 6632231a66SAl Viro * the clear field clears bits in the mask which will ENABLE that IRQ 6732231a66SAl Viro * the set field sets bits in the mask to DISABLE the IRQ. 6832231a66SAl Viro * 6932231a66SAl Viro * Also the undirected_xx address in the SLAVIO is defined as 7032231a66SAl Viro * RESERVED and write only.. 7132231a66SAl Viro * 7232231a66SAl Viro * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor 7332231a66SAl Viro * sun4m machines, for MP the layout makes more sense. 7432231a66SAl Viro */ 7532231a66SAl Viro struct sun4m_intregs { 7632231a66SAl Viro struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS]; 7732231a66SAl Viro unsigned int tbt; /* IRQ's that are still pending. */ 7832231a66SAl Viro unsigned int irqs; /* Master IRQ bits. */ 7932231a66SAl Viro 8032231a66SAl Viro /* Again, like the above, two these registers are WRITE-ONLY. */ 8132231a66SAl Viro unsigned int clear; /* Clear master IRQ's by setting bits here. */ 8232231a66SAl Viro unsigned int set; /* Set master IRQ's by setting bits here. */ 8332231a66SAl Viro 8432231a66SAl Viro /* This register is both READ and WRITE. */ 8532231a66SAl Viro unsigned int undirected_target; /* Which cpu gets undirected irqs. */ 8632231a66SAl Viro }; 8732231a66SAl Viro 881da177e4SLinus Torvalds static unsigned long dummy; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds struct sun4m_intregs *sun4m_interrupts; 911da177e4SLinus Torvalds unsigned long *irq_rcvreg = &dummy; 921da177e4SLinus Torvalds 9332231a66SAl Viro /* Dave Redman (djhr@tadpole.co.uk) 9432231a66SAl Viro * The sun4m interrupt registers. 9532231a66SAl Viro */ 9632231a66SAl Viro #define SUN4M_INT_ENABLE 0x80000000 9732231a66SAl Viro #define SUN4M_INT_E14 0x00000080 9832231a66SAl Viro #define SUN4M_INT_E10 0x00080000 9932231a66SAl Viro 10032231a66SAl Viro #define SUN4M_HARD_INT(x) (0x000000001 << (x)) 10132231a66SAl Viro #define SUN4M_SOFT_INT(x) (0x000010000 << (x)) 10232231a66SAl Viro 10332231a66SAl Viro #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ 10432231a66SAl Viro #define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ 10532231a66SAl Viro #define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ 10632231a66SAl Viro #define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ 10732231a66SAl Viro #define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ 10832231a66SAl Viro #define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ 10932231a66SAl Viro #define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ 11032231a66SAl Viro #define SUN4M_INT_REALTIME 0x00080000 /* system timer */ 11132231a66SAl Viro #define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ 11232231a66SAl Viro #define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ 11332231a66SAl Viro #define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ 11432231a66SAl Viro #define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ 11532231a66SAl Viro #define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ 11632231a66SAl Viro #define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ 11732231a66SAl Viro 11832231a66SAl Viro #define SUN4M_INT_SBUS(x) (1 << (x+7)) 11932231a66SAl Viro #define SUN4M_INT_VME(x) (1 << (x)) 12032231a66SAl Viro 1211da177e4SLinus Torvalds /* These tables only apply for interrupts greater than 15.. 1221da177e4SLinus Torvalds * 1231da177e4SLinus Torvalds * any intr value below 0x10 is considered to be a soft-int 1241da177e4SLinus Torvalds * this may be useful or it may not.. but that's how I've done it. 1251da177e4SLinus Torvalds * and it won't clash with what OBP is telling us about devices. 1261da177e4SLinus Torvalds * 1271da177e4SLinus Torvalds * take an encoded intr value and lookup if it's valid 1281da177e4SLinus Torvalds * then get the mask bits that match from irq_mask 1291da177e4SLinus Torvalds * 1301da177e4SLinus Torvalds * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. 1311da177e4SLinus Torvalds */ 1321da177e4SLinus Torvalds static unsigned char irq_xlate[32] = { 1331da177e4SLinus Torvalds /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ 1341da177e4SLinus Torvalds 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, 1351da177e4SLinus Torvalds 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 1361da177e4SLinus Torvalds }; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds static unsigned long irq_mask[] = { 1391da177e4SLinus Torvalds 0, /* illegal index */ 1401da177e4SLinus Torvalds SUN4M_INT_SCSI, /* 1 irq 4 */ 1411da177e4SLinus Torvalds SUN4M_INT_ETHERNET, /* 2 irq 6 */ 1421da177e4SLinus Torvalds SUN4M_INT_VIDEO, /* 3 irq 8 */ 1431da177e4SLinus Torvalds SUN4M_INT_REALTIME, /* 4 irq 10 */ 1441da177e4SLinus Torvalds SUN4M_INT_FLOPPY, /* 5 irq 11 */ 1451da177e4SLinus Torvalds (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ 1461da177e4SLinus Torvalds SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ 1471da177e4SLinus Torvalds SUN4M_INT_SBUS(0), /* 8 irq 2 */ 1481da177e4SLinus Torvalds SUN4M_INT_SBUS(1), /* 9 irq 3 */ 1491da177e4SLinus Torvalds SUN4M_INT_SBUS(2), /* 10 irq 5 */ 1501da177e4SLinus Torvalds SUN4M_INT_SBUS(3), /* 11 irq 7 */ 1511da177e4SLinus Torvalds SUN4M_INT_SBUS(4), /* 12 irq 9 */ 1521da177e4SLinus Torvalds SUN4M_INT_SBUS(5), /* 13 irq 11 */ 1531da177e4SLinus Torvalds SUN4M_INT_SBUS(6) /* 14 irq 13 */ 1541da177e4SLinus Torvalds }; 1551da177e4SLinus Torvalds 156c61c65cdSAdrian Bunk static unsigned long sun4m_get_irqmask(unsigned int irq) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds unsigned long mask; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds if (irq > 0x20) { 1611da177e4SLinus Torvalds /* OBIO/SBUS interrupts */ 1621da177e4SLinus Torvalds irq &= 0x1f; 1631da177e4SLinus Torvalds mask = irq_mask[irq_xlate[irq]]; 1641da177e4SLinus Torvalds if (!mask) 1651da177e4SLinus Torvalds printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); 1661da177e4SLinus Torvalds } else { 1671da177e4SLinus Torvalds /* Soft Interrupts will come here. 1681da177e4SLinus Torvalds * Currently there is no way to trigger them but I'm sure 1691da177e4SLinus Torvalds * something could be cooked up. 1701da177e4SLinus Torvalds */ 1711da177e4SLinus Torvalds irq &= 0xf; 1721da177e4SLinus Torvalds mask = SUN4M_SOFT_INT(irq); 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds return mask; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds static void sun4m_disable_irq(unsigned int irq_nr) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds unsigned long mask, flags; 1801da177e4SLinus Torvalds int cpu = smp_processor_id(); 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 1831da177e4SLinus Torvalds local_irq_save(flags); 1841da177e4SLinus Torvalds if (irq_nr > 15) 1851da177e4SLinus Torvalds sun4m_interrupts->set = mask; 1861da177e4SLinus Torvalds else 1871da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].set = mask; 1881da177e4SLinus Torvalds local_irq_restore(flags); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds static void sun4m_enable_irq(unsigned int irq_nr) 1921da177e4SLinus Torvalds { 1931da177e4SLinus Torvalds unsigned long mask, flags; 1941da177e4SLinus Torvalds int cpu = smp_processor_id(); 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* Dreadful floppy hack. When we use 0x2b instead of 1971da177e4SLinus Torvalds * 0x0b the system blows (it starts to whistle!). 1981da177e4SLinus Torvalds * So we continue to use 0x0b. Fixme ASAP. --P3 1991da177e4SLinus Torvalds */ 2001da177e4SLinus Torvalds if (irq_nr != 0x0b) { 2011da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 2021da177e4SLinus Torvalds local_irq_save(flags); 2031da177e4SLinus Torvalds if (irq_nr > 15) 2041da177e4SLinus Torvalds sun4m_interrupts->clear = mask; 2051da177e4SLinus Torvalds else 2061da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].clear = mask; 2071da177e4SLinus Torvalds local_irq_restore(flags); 2081da177e4SLinus Torvalds } else { 2091da177e4SLinus Torvalds local_irq_save(flags); 2101da177e4SLinus Torvalds sun4m_interrupts->clear = SUN4M_INT_FLOPPY; 2111da177e4SLinus Torvalds local_irq_restore(flags); 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds static unsigned long cpu_pil_to_imask[16] = { 2161da177e4SLinus Torvalds /*0*/ 0x00000000, 2171da177e4SLinus Torvalds /*1*/ 0x00000000, 2181da177e4SLinus Torvalds /*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), 2191da177e4SLinus Torvalds /*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), 2201da177e4SLinus Torvalds /*4*/ SUN4M_INT_SCSI, 2211da177e4SLinus Torvalds /*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), 2221da177e4SLinus Torvalds /*6*/ SUN4M_INT_ETHERNET, 2231da177e4SLinus Torvalds /*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), 2241da177e4SLinus Torvalds /*8*/ SUN4M_INT_VIDEO, 2251da177e4SLinus Torvalds /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, 2261da177e4SLinus Torvalds /*10*/ SUN4M_INT_REALTIME, 2271da177e4SLinus Torvalds /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, 2281da177e4SLinus Torvalds /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 2291da177e4SLinus Torvalds /*13*/ SUN4M_INT_AUDIO, 2301da177e4SLinus Torvalds /*14*/ SUN4M_INT_E14, 2311da177e4SLinus Torvalds /*15*/ 0x00000000 2321da177e4SLinus Torvalds }; 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds /* We assume the caller has disabled local interrupts when these are called, 2351da177e4SLinus Torvalds * or else very bizarre behavior will result. 2361da177e4SLinus Torvalds */ 2371da177e4SLinus Torvalds static void sun4m_disable_pil_irq(unsigned int pil) 2381da177e4SLinus Torvalds { 2391da177e4SLinus Torvalds sun4m_interrupts->set = cpu_pil_to_imask[pil]; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds static void sun4m_enable_pil_irq(unsigned int pil) 2431da177e4SLinus Torvalds { 2441da177e4SLinus Torvalds sun4m_interrupts->clear = cpu_pil_to_imask[pil]; 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds #ifdef CONFIG_SMP 2481da177e4SLinus Torvalds static void sun4m_send_ipi(int cpu, int level) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds unsigned long mask; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds mask = sun4m_get_irqmask(level); 2531da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].set = mask; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds static void sun4m_clear_ipi(int cpu, int level) 2571da177e4SLinus Torvalds { 2581da177e4SLinus Torvalds unsigned long mask; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds mask = sun4m_get_irqmask(level); 2611da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].clear = mask; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds static void sun4m_set_udt(int cpu) 2651da177e4SLinus Torvalds { 2661da177e4SLinus Torvalds sun4m_interrupts->undirected_target = cpu; 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds #endif 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds #define OBIO_INTR 0x20 2711da177e4SLinus Torvalds #define TIMER_IRQ (OBIO_INTR | 10) 2721da177e4SLinus Torvalds #define PROFILE_IRQ (OBIO_INTR | 14) 2731da177e4SLinus Torvalds 274c61c65cdSAdrian Bunk static struct sun4m_timer_regs *sun4m_timers; 2751da177e4SLinus Torvalds unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds static void sun4m_clear_clock_irq(void) 2781da177e4SLinus Torvalds { 2791da177e4SLinus Torvalds volatile unsigned int clear_intr; 2801da177e4SLinus Torvalds clear_intr = sun4m_timers->l10_timer_limit; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds static void sun4m_clear_profile_irq(int cpu) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds volatile unsigned int clear; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit; 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds static void sun4m_load_profile_irq(int cpu, unsigned int limit) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 29540220c1aSDavid Howells static void __init sun4m_init_timers(irq_handler_t counter_fn) 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds int reg_count, irq, cpu; 2981da177e4SLinus Torvalds struct linux_prom_registers cnt_regs[PROMREG_MAX]; 2991da177e4SLinus Torvalds int obio_node, cnt_node; 3001da177e4SLinus Torvalds struct resource r; 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds cnt_node = 0; 3031da177e4SLinus Torvalds if((obio_node = 3041da177e4SLinus Torvalds prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || 3051da177e4SLinus Torvalds (obio_node = prom_getchild (obio_node)) == 0 || 3061da177e4SLinus Torvalds (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { 3071da177e4SLinus Torvalds prom_printf("Cannot find /obio/counter node\n"); 3081da177e4SLinus Torvalds prom_halt(); 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds reg_count = prom_getproperty(cnt_node, "reg", 3111da177e4SLinus Torvalds (void *) cnt_regs, sizeof(cnt_regs)); 3121da177e4SLinus Torvalds reg_count = (reg_count/sizeof(struct linux_prom_registers)); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds /* Apply the obio ranges to the timer registers. */ 3151da177e4SLinus Torvalds prom_apply_obio_ranges(cnt_regs, reg_count); 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; 3181da177e4SLinus Torvalds cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; 3191da177e4SLinus Torvalds cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; 3201da177e4SLinus Torvalds for(obio_node = 1; obio_node < 4; obio_node++) { 3211da177e4SLinus Torvalds cnt_regs[obio_node].phys_addr = 3221da177e4SLinus Torvalds cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; 3231da177e4SLinus Torvalds cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; 3241da177e4SLinus Torvalds cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds memset((char*)&r, 0, sizeof(struct resource)); 3281da177e4SLinus Torvalds /* Map the per-cpu Counter registers. */ 3291da177e4SLinus Torvalds r.flags = cnt_regs[0].which_io; 3301da177e4SLinus Torvalds r.start = cnt_regs[0].phys_addr; 331*454eeb2dSDavid S. Miller sun4m_timers = (struct sun4m_timer_regs *) of_ioremap(&r, 0, 3321da177e4SLinus Torvalds PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); 3331da177e4SLinus Torvalds /* Map the system Counter register. */ 3341da177e4SLinus Torvalds /* XXX Here we expect consequent calls to yeld adjusent maps. */ 3351da177e4SLinus Torvalds r.flags = cnt_regs[4].which_io; 3361da177e4SLinus Torvalds r.start = cnt_regs[4].phys_addr; 337*454eeb2dSDavid S. Miller of_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); 3401da177e4SLinus Torvalds master_l10_counter = &sun4m_timers->l10_cur_count; 3411da177e4SLinus Torvalds master_l10_limit = &sun4m_timers->l10_timer_limit; 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds irq = request_irq(TIMER_IRQ, 3441da177e4SLinus Torvalds counter_fn, 34567413202SThomas Gleixner (IRQF_DISABLED | SA_STATIC_ALLOC), 3461da177e4SLinus Torvalds "timer", NULL); 3471da177e4SLinus Torvalds if (irq) { 3481da177e4SLinus Torvalds prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); 3491da177e4SLinus Torvalds prom_halt(); 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds if (!cpu_find_by_instance(1, NULL, NULL)) { 3531da177e4SLinus Torvalds for(cpu = 0; cpu < 4; cpu++) 3541da177e4SLinus Torvalds sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; 3551da177e4SLinus Torvalds sun4m_interrupts->set = SUN4M_INT_E14; 3561da177e4SLinus Torvalds } else { 3571da177e4SLinus Torvalds sun4m_timers->cpu_timers[0].l14_timer_limit = 0; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds #ifdef CONFIG_SMP 3601da177e4SLinus Torvalds { 3611da177e4SLinus Torvalds unsigned long flags; 3621da177e4SLinus Torvalds extern unsigned long lvl14_save[4]; 3631da177e4SLinus Torvalds struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; 3641da177e4SLinus Torvalds 3651da177e4SLinus Torvalds /* For SMP we use the level 14 ticker, however the bootup code 366d1a78c32SSimon Arlott * has copied the firmware's level 14 vector into the boot cpu's 3671da177e4SLinus Torvalds * trap table, we must fix this now or we get squashed. 3681da177e4SLinus Torvalds */ 3691da177e4SLinus Torvalds local_irq_save(flags); 3701da177e4SLinus Torvalds trap_table->inst_one = lvl14_save[0]; 3711da177e4SLinus Torvalds trap_table->inst_two = lvl14_save[1]; 3721da177e4SLinus Torvalds trap_table->inst_three = lvl14_save[2]; 3731da177e4SLinus Torvalds trap_table->inst_four = lvl14_save[3]; 3741da177e4SLinus Torvalds local_flush_cache_all(); 3751da177e4SLinus Torvalds local_irq_restore(flags); 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds #endif 3781da177e4SLinus Torvalds } 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds void __init sun4m_init_IRQ(void) 3811da177e4SLinus Torvalds { 3821da177e4SLinus Torvalds int ie_node,i; 3831da177e4SLinus Torvalds struct linux_prom_registers int_regs[PROMREG_MAX]; 3841da177e4SLinus Torvalds int num_regs; 3851da177e4SLinus Torvalds struct resource r; 3861da177e4SLinus Torvalds int mid; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds local_irq_disable(); 3891da177e4SLinus Torvalds if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || 3901da177e4SLinus Torvalds (ie_node = prom_getchild (ie_node)) == 0 || 3911da177e4SLinus Torvalds (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { 3921da177e4SLinus Torvalds prom_printf("Cannot find /obio/interrupt node\n"); 3931da177e4SLinus Torvalds prom_halt(); 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, 3961da177e4SLinus Torvalds sizeof(int_regs)); 3971da177e4SLinus Torvalds num_regs = (num_regs/sizeof(struct linux_prom_registers)); 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds /* Apply the obio ranges to these registers. */ 4001da177e4SLinus Torvalds prom_apply_obio_ranges(int_regs, num_regs); 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; 4031da177e4SLinus Torvalds int_regs[4].reg_size = int_regs[num_regs-1].reg_size; 4041da177e4SLinus Torvalds int_regs[4].which_io = int_regs[num_regs-1].which_io; 4051da177e4SLinus Torvalds for(ie_node = 1; ie_node < 4; ie_node++) { 4061da177e4SLinus Torvalds int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; 4071da177e4SLinus Torvalds int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; 4081da177e4SLinus Torvalds int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds memset((char *)&r, 0, sizeof(struct resource)); 4121da177e4SLinus Torvalds /* Map the interrupt registers for all possible cpus. */ 4131da177e4SLinus Torvalds r.flags = int_regs[0].which_io; 4141da177e4SLinus Torvalds r.start = int_regs[0].phys_addr; 415*454eeb2dSDavid S. Miller sun4m_interrupts = (struct sun4m_intregs *) of_ioremap(&r, 0, 4161da177e4SLinus Torvalds PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds /* Map the system interrupt control registers. */ 4191da177e4SLinus Torvalds r.flags = int_regs[4].which_io; 4201da177e4SLinus Torvalds r.start = int_regs[4].phys_addr; 421*454eeb2dSDavid S. Miller of_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds sun4m_interrupts->set = ~SUN4M_INT_MASKALL; 4241da177e4SLinus Torvalds for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 4251da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds if (!cpu_find_by_instance(1, NULL, NULL)) { 4281da177e4SLinus Torvalds /* system wide interrupts go to cpu 0, this should always 4291da177e4SLinus Torvalds * be safe because it is guaranteed to be fitted or OBP doesn't 4301da177e4SLinus Torvalds * come up 4311da177e4SLinus Torvalds * 4321da177e4SLinus Torvalds * Not sure, but writing here on SLAVIO systems may puke 4331da177e4SLinus Torvalds * so I don't do it unless there is more than 1 cpu. 4341da177e4SLinus Torvalds */ 4351da177e4SLinus Torvalds irq_rcvreg = (unsigned long *) 4361da177e4SLinus Torvalds &sun4m_interrupts->undirected_target; 4371da177e4SLinus Torvalds sun4m_interrupts->undirected_target = 0; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 4401da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 4411da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); 4421da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); 4431da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); 4441da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); 4451da177e4SLinus Torvalds BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); 4461da177e4SLinus Torvalds sparc_init_timers = sun4m_init_timers; 4471da177e4SLinus Torvalds #ifdef CONFIG_SMP 4481da177e4SLinus Torvalds BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); 4491da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 4501da177e4SLinus Torvalds BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 4511da177e4SLinus Torvalds #endif 4521da177e4SLinus Torvalds /* Cannot enable interrupts until OBP ticker is disabled. */ 4531da177e4SLinus Torvalds } 454