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> 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #include <asm/ptrace.h> 251da177e4SLinus Torvalds #include <asm/processor.h> 261da177e4SLinus Torvalds #include <asm/system.h> 271da177e4SLinus Torvalds #include <asm/psr.h> 281da177e4SLinus Torvalds #include <asm/vaddrs.h> 291da177e4SLinus Torvalds #include <asm/timer.h> 301da177e4SLinus Torvalds #include <asm/openprom.h> 311da177e4SLinus Torvalds #include <asm/oplib.h> 321da177e4SLinus Torvalds #include <asm/traps.h> 331da177e4SLinus Torvalds #include <asm/pgalloc.h> 341da177e4SLinus Torvalds #include <asm/pgtable.h> 351da177e4SLinus Torvalds #include <asm/smp.h> 361da177e4SLinus Torvalds #include <asm/irq.h> 371da177e4SLinus Torvalds #include <asm/io.h> 381da177e4SLinus Torvalds #include <asm/sbus.h> 391da177e4SLinus Torvalds #include <asm/cacheflush.h> 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds static unsigned long dummy; 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds struct sun4m_intregs *sun4m_interrupts; 441da177e4SLinus Torvalds unsigned long *irq_rcvreg = &dummy; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds /* These tables only apply for interrupts greater than 15.. 471da177e4SLinus Torvalds * 481da177e4SLinus Torvalds * any intr value below 0x10 is considered to be a soft-int 491da177e4SLinus Torvalds * this may be useful or it may not.. but that's how I've done it. 501da177e4SLinus Torvalds * and it won't clash with what OBP is telling us about devices. 511da177e4SLinus Torvalds * 521da177e4SLinus Torvalds * take an encoded intr value and lookup if it's valid 531da177e4SLinus Torvalds * then get the mask bits that match from irq_mask 541da177e4SLinus Torvalds * 551da177e4SLinus Torvalds * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. 561da177e4SLinus Torvalds */ 571da177e4SLinus Torvalds static unsigned char irq_xlate[32] = { 581da177e4SLinus Torvalds /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ 591da177e4SLinus Torvalds 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, 601da177e4SLinus Torvalds 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 611da177e4SLinus Torvalds }; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds static unsigned long irq_mask[] = { 641da177e4SLinus Torvalds 0, /* illegal index */ 651da177e4SLinus Torvalds SUN4M_INT_SCSI, /* 1 irq 4 */ 661da177e4SLinus Torvalds SUN4M_INT_ETHERNET, /* 2 irq 6 */ 671da177e4SLinus Torvalds SUN4M_INT_VIDEO, /* 3 irq 8 */ 681da177e4SLinus Torvalds SUN4M_INT_REALTIME, /* 4 irq 10 */ 691da177e4SLinus Torvalds SUN4M_INT_FLOPPY, /* 5 irq 11 */ 701da177e4SLinus Torvalds (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ 711da177e4SLinus Torvalds SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ 721da177e4SLinus Torvalds SUN4M_INT_SBUS(0), /* 8 irq 2 */ 731da177e4SLinus Torvalds SUN4M_INT_SBUS(1), /* 9 irq 3 */ 741da177e4SLinus Torvalds SUN4M_INT_SBUS(2), /* 10 irq 5 */ 751da177e4SLinus Torvalds SUN4M_INT_SBUS(3), /* 11 irq 7 */ 761da177e4SLinus Torvalds SUN4M_INT_SBUS(4), /* 12 irq 9 */ 771da177e4SLinus Torvalds SUN4M_INT_SBUS(5), /* 13 irq 11 */ 781da177e4SLinus Torvalds SUN4M_INT_SBUS(6) /* 14 irq 13 */ 791da177e4SLinus Torvalds }; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 }; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) 841da177e4SLinus Torvalds { 851da177e4SLinus Torvalds if (sbint >= sizeof(sun4m_pil_map)) { 861da177e4SLinus Torvalds printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint); 871da177e4SLinus Torvalds BUG(); 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds return sun4m_pil_map[sbint] | 0x30; 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds inline unsigned long sun4m_get_irqmask(unsigned int irq) 931da177e4SLinus Torvalds { 941da177e4SLinus Torvalds unsigned long mask; 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds if (irq > 0x20) { 971da177e4SLinus Torvalds /* OBIO/SBUS interrupts */ 981da177e4SLinus Torvalds irq &= 0x1f; 991da177e4SLinus Torvalds mask = irq_mask[irq_xlate[irq]]; 1001da177e4SLinus Torvalds if (!mask) 1011da177e4SLinus Torvalds printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); 1021da177e4SLinus Torvalds } else { 1031da177e4SLinus Torvalds /* Soft Interrupts will come here. 1041da177e4SLinus Torvalds * Currently there is no way to trigger them but I'm sure 1051da177e4SLinus Torvalds * something could be cooked up. 1061da177e4SLinus Torvalds */ 1071da177e4SLinus Torvalds irq &= 0xf; 1081da177e4SLinus Torvalds mask = SUN4M_SOFT_INT(irq); 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds return mask; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds static void sun4m_disable_irq(unsigned int irq_nr) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds unsigned long mask, flags; 1161da177e4SLinus Torvalds int cpu = smp_processor_id(); 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 1191da177e4SLinus Torvalds local_irq_save(flags); 1201da177e4SLinus Torvalds if (irq_nr > 15) 1211da177e4SLinus Torvalds sun4m_interrupts->set = mask; 1221da177e4SLinus Torvalds else 1231da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].set = mask; 1241da177e4SLinus Torvalds local_irq_restore(flags); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static void sun4m_enable_irq(unsigned int irq_nr) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds unsigned long mask, flags; 1301da177e4SLinus Torvalds int cpu = smp_processor_id(); 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds /* Dreadful floppy hack. When we use 0x2b instead of 1331da177e4SLinus Torvalds * 0x0b the system blows (it starts to whistle!). 1341da177e4SLinus Torvalds * So we continue to use 0x0b. Fixme ASAP. --P3 1351da177e4SLinus Torvalds */ 1361da177e4SLinus Torvalds if (irq_nr != 0x0b) { 1371da177e4SLinus Torvalds mask = sun4m_get_irqmask(irq_nr); 1381da177e4SLinus Torvalds local_irq_save(flags); 1391da177e4SLinus Torvalds if (irq_nr > 15) 1401da177e4SLinus Torvalds sun4m_interrupts->clear = mask; 1411da177e4SLinus Torvalds else 1421da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].clear = mask; 1431da177e4SLinus Torvalds local_irq_restore(flags); 1441da177e4SLinus Torvalds } else { 1451da177e4SLinus Torvalds local_irq_save(flags); 1461da177e4SLinus Torvalds sun4m_interrupts->clear = SUN4M_INT_FLOPPY; 1471da177e4SLinus Torvalds local_irq_restore(flags); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static unsigned long cpu_pil_to_imask[16] = { 1521da177e4SLinus Torvalds /*0*/ 0x00000000, 1531da177e4SLinus Torvalds /*1*/ 0x00000000, 1541da177e4SLinus Torvalds /*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0), 1551da177e4SLinus Torvalds /*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1), 1561da177e4SLinus Torvalds /*4*/ SUN4M_INT_SCSI, 1571da177e4SLinus Torvalds /*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2), 1581da177e4SLinus Torvalds /*6*/ SUN4M_INT_ETHERNET, 1591da177e4SLinus Torvalds /*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3), 1601da177e4SLinus Torvalds /*8*/ SUN4M_INT_VIDEO, 1611da177e4SLinus Torvalds /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, 1621da177e4SLinus Torvalds /*10*/ SUN4M_INT_REALTIME, 1631da177e4SLinus Torvalds /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, 1641da177e4SLinus Torvalds /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, 1651da177e4SLinus Torvalds /*13*/ SUN4M_INT_AUDIO, 1661da177e4SLinus Torvalds /*14*/ SUN4M_INT_E14, 1671da177e4SLinus Torvalds /*15*/ 0x00000000 1681da177e4SLinus Torvalds }; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* We assume the caller has disabled local interrupts when these are called, 1711da177e4SLinus Torvalds * or else very bizarre behavior will result. 1721da177e4SLinus Torvalds */ 1731da177e4SLinus Torvalds static void sun4m_disable_pil_irq(unsigned int pil) 1741da177e4SLinus Torvalds { 1751da177e4SLinus Torvalds sun4m_interrupts->set = cpu_pil_to_imask[pil]; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds static void sun4m_enable_pil_irq(unsigned int pil) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds sun4m_interrupts->clear = cpu_pil_to_imask[pil]; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds #ifdef CONFIG_SMP 1841da177e4SLinus Torvalds static void sun4m_send_ipi(int cpu, int level) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds unsigned long mask; 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds mask = sun4m_get_irqmask(level); 1891da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].set = mask; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static void sun4m_clear_ipi(int cpu, int level) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds unsigned long mask; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds mask = sun4m_get_irqmask(level); 1971da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[cpu].clear = mask; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds static void sun4m_set_udt(int cpu) 2011da177e4SLinus Torvalds { 2021da177e4SLinus Torvalds sun4m_interrupts->undirected_target = cpu; 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds #endif 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds #define OBIO_INTR 0x20 2071da177e4SLinus Torvalds #define TIMER_IRQ (OBIO_INTR | 10) 2081da177e4SLinus Torvalds #define PROFILE_IRQ (OBIO_INTR | 14) 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds struct sun4m_timer_regs *sun4m_timers; 2111da177e4SLinus Torvalds unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static void sun4m_clear_clock_irq(void) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds volatile unsigned int clear_intr; 2161da177e4SLinus Torvalds clear_intr = sun4m_timers->l10_timer_limit; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds static void sun4m_clear_profile_irq(int cpu) 2201da177e4SLinus Torvalds { 2211da177e4SLinus Torvalds volatile unsigned int clear; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds static void sun4m_load_profile_irq(int cpu, unsigned int limit) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 231*40220c1aSDavid Howells static void __init sun4m_init_timers(irq_handler_t counter_fn) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds int reg_count, irq, cpu; 2341da177e4SLinus Torvalds struct linux_prom_registers cnt_regs[PROMREG_MAX]; 2351da177e4SLinus Torvalds int obio_node, cnt_node; 2361da177e4SLinus Torvalds struct resource r; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds cnt_node = 0; 2391da177e4SLinus Torvalds if((obio_node = 2401da177e4SLinus Torvalds prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || 2411da177e4SLinus Torvalds (obio_node = prom_getchild (obio_node)) == 0 || 2421da177e4SLinus Torvalds (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { 2431da177e4SLinus Torvalds prom_printf("Cannot find /obio/counter node\n"); 2441da177e4SLinus Torvalds prom_halt(); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds reg_count = prom_getproperty(cnt_node, "reg", 2471da177e4SLinus Torvalds (void *) cnt_regs, sizeof(cnt_regs)); 2481da177e4SLinus Torvalds reg_count = (reg_count/sizeof(struct linux_prom_registers)); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* Apply the obio ranges to the timer registers. */ 2511da177e4SLinus Torvalds prom_apply_obio_ranges(cnt_regs, reg_count); 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; 2541da177e4SLinus Torvalds cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; 2551da177e4SLinus Torvalds cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; 2561da177e4SLinus Torvalds for(obio_node = 1; obio_node < 4; obio_node++) { 2571da177e4SLinus Torvalds cnt_regs[obio_node].phys_addr = 2581da177e4SLinus Torvalds cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; 2591da177e4SLinus Torvalds cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; 2601da177e4SLinus Torvalds cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds memset((char*)&r, 0, sizeof(struct resource)); 2641da177e4SLinus Torvalds /* Map the per-cpu Counter registers. */ 2651da177e4SLinus Torvalds r.flags = cnt_regs[0].which_io; 2661da177e4SLinus Torvalds r.start = cnt_regs[0].phys_addr; 2671da177e4SLinus Torvalds sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0, 2681da177e4SLinus Torvalds PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); 2691da177e4SLinus Torvalds /* Map the system Counter register. */ 2701da177e4SLinus Torvalds /* XXX Here we expect consequent calls to yeld adjusent maps. */ 2711da177e4SLinus Torvalds r.flags = cnt_regs[4].which_io; 2721da177e4SLinus Torvalds r.start = cnt_regs[4].phys_addr; 2731da177e4SLinus Torvalds sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); 2761da177e4SLinus Torvalds master_l10_counter = &sun4m_timers->l10_cur_count; 2771da177e4SLinus Torvalds master_l10_limit = &sun4m_timers->l10_timer_limit; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds irq = request_irq(TIMER_IRQ, 2801da177e4SLinus Torvalds counter_fn, 28167413202SThomas Gleixner (IRQF_DISABLED | SA_STATIC_ALLOC), 2821da177e4SLinus Torvalds "timer", NULL); 2831da177e4SLinus Torvalds if (irq) { 2841da177e4SLinus Torvalds prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); 2851da177e4SLinus Torvalds prom_halt(); 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds if (!cpu_find_by_instance(1, NULL, NULL)) { 2891da177e4SLinus Torvalds for(cpu = 0; cpu < 4; cpu++) 2901da177e4SLinus Torvalds sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; 2911da177e4SLinus Torvalds sun4m_interrupts->set = SUN4M_INT_E14; 2921da177e4SLinus Torvalds } else { 2931da177e4SLinus Torvalds sun4m_timers->cpu_timers[0].l14_timer_limit = 0; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds #ifdef CONFIG_SMP 2961da177e4SLinus Torvalds { 2971da177e4SLinus Torvalds unsigned long flags; 2981da177e4SLinus Torvalds extern unsigned long lvl14_save[4]; 2991da177e4SLinus Torvalds struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /* For SMP we use the level 14 ticker, however the bootup code 3021da177e4SLinus Torvalds * has copied the firmwares level 14 vector into boot cpu's 3031da177e4SLinus Torvalds * trap table, we must fix this now or we get squashed. 3041da177e4SLinus Torvalds */ 3051da177e4SLinus Torvalds local_irq_save(flags); 3061da177e4SLinus Torvalds trap_table->inst_one = lvl14_save[0]; 3071da177e4SLinus Torvalds trap_table->inst_two = lvl14_save[1]; 3081da177e4SLinus Torvalds trap_table->inst_three = lvl14_save[2]; 3091da177e4SLinus Torvalds trap_table->inst_four = lvl14_save[3]; 3101da177e4SLinus Torvalds local_flush_cache_all(); 3111da177e4SLinus Torvalds local_irq_restore(flags); 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds #endif 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds void __init sun4m_init_IRQ(void) 3171da177e4SLinus Torvalds { 3181da177e4SLinus Torvalds int ie_node,i; 3191da177e4SLinus Torvalds struct linux_prom_registers int_regs[PROMREG_MAX]; 3201da177e4SLinus Torvalds int num_regs; 3211da177e4SLinus Torvalds struct resource r; 3221da177e4SLinus Torvalds int mid; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds local_irq_disable(); 3251da177e4SLinus Torvalds if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || 3261da177e4SLinus Torvalds (ie_node = prom_getchild (ie_node)) == 0 || 3271da177e4SLinus Torvalds (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { 3281da177e4SLinus Torvalds prom_printf("Cannot find /obio/interrupt node\n"); 3291da177e4SLinus Torvalds prom_halt(); 3301da177e4SLinus Torvalds } 3311da177e4SLinus Torvalds num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, 3321da177e4SLinus Torvalds sizeof(int_regs)); 3331da177e4SLinus Torvalds num_regs = (num_regs/sizeof(struct linux_prom_registers)); 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds /* Apply the obio ranges to these registers. */ 3361da177e4SLinus Torvalds prom_apply_obio_ranges(int_regs, num_regs); 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; 3391da177e4SLinus Torvalds int_regs[4].reg_size = int_regs[num_regs-1].reg_size; 3401da177e4SLinus Torvalds int_regs[4].which_io = int_regs[num_regs-1].which_io; 3411da177e4SLinus Torvalds for(ie_node = 1; ie_node < 4; ie_node++) { 3421da177e4SLinus Torvalds int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; 3431da177e4SLinus Torvalds int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; 3441da177e4SLinus Torvalds int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds memset((char *)&r, 0, sizeof(struct resource)); 3481da177e4SLinus Torvalds /* Map the interrupt registers for all possible cpus. */ 3491da177e4SLinus Torvalds r.flags = int_regs[0].which_io; 3501da177e4SLinus Torvalds r.start = int_regs[0].phys_addr; 3511da177e4SLinus Torvalds sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0, 3521da177e4SLinus Torvalds PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds /* Map the system interrupt control registers. */ 3551da177e4SLinus Torvalds r.flags = int_regs[4].which_io; 3561da177e4SLinus Torvalds r.start = int_regs[4].phys_addr; 3571da177e4SLinus Torvalds sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds sun4m_interrupts->set = ~SUN4M_INT_MASKALL; 3601da177e4SLinus Torvalds for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 3611da177e4SLinus Torvalds sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds if (!cpu_find_by_instance(1, NULL, NULL)) { 3641da177e4SLinus Torvalds /* system wide interrupts go to cpu 0, this should always 3651da177e4SLinus Torvalds * be safe because it is guaranteed to be fitted or OBP doesn't 3661da177e4SLinus Torvalds * come up 3671da177e4SLinus Torvalds * 3681da177e4SLinus Torvalds * Not sure, but writing here on SLAVIO systems may puke 3691da177e4SLinus Torvalds * so I don't do it unless there is more than 1 cpu. 3701da177e4SLinus Torvalds */ 3711da177e4SLinus Torvalds irq_rcvreg = (unsigned long *) 3721da177e4SLinus Torvalds &sun4m_interrupts->undirected_target; 3731da177e4SLinus Torvalds sun4m_interrupts->undirected_target = 0; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM); 3761da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 3771da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 3781da177e4SLinus Torvalds BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); 3791da177e4SLinus Torvalds BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); 3801da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); 3811da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); 3821da177e4SLinus Torvalds BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); 3831da177e4SLinus Torvalds sparc_init_timers = sun4m_init_timers; 3841da177e4SLinus Torvalds #ifdef CONFIG_SMP 3851da177e4SLinus Torvalds BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); 3861da177e4SLinus Torvalds BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 3871da177e4SLinus Torvalds BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 3881da177e4SLinus Torvalds #endif 3891da177e4SLinus Torvalds /* Cannot enable interrupts until OBP ticker is disabled. */ 3901da177e4SLinus Torvalds } 391