1/* sun4c_irq.c 2 * arch/sparc/kernel/sun4c_irq.c: 3 * 4 * djhr: Hacked out of irq.c into a CPU dependent version. 5 * 6 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 7 * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) 8 * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@yahoo.com) 9 * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) 10 */ 11 12#include <linux/errno.h> 13#include <linux/linkage.h> 14#include <linux/kernel_stat.h> 15#include <linux/signal.h> 16#include <linux/sched.h> 17#include <linux/ptrace.h> 18#include <linux/interrupt.h> 19#include <linux/slab.h> 20#include <linux/init.h> 21 22#include <asm/ptrace.h> 23#include <asm/processor.h> 24#include <asm/system.h> 25#include <asm/psr.h> 26#include <asm/vaddrs.h> 27#include <asm/timer.h> 28#include <asm/openprom.h> 29#include <asm/oplib.h> 30#include <asm/traps.h> 31#include <asm/irq.h> 32#include <asm/io.h> 33#include <asm/sun4paddr.h> 34#include <asm/idprom.h> 35#include <asm/machines.h> 36#include <asm/sbus.h> 37 38 39/* Pointer to the interrupt enable byte 40 * 41 * Dave Redman (djhr@tadpole.co.uk) 42 * What you may not be aware of is that entry.S requires this variable. 43 * 44 * --- linux_trap_nmi_sun4c -- 45 * 46 * so don't go making it static, like I tried. sigh. 47 */ 48unsigned char *interrupt_enable = NULL; 49 50static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 }; 51 52unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) 53{ 54 if (sbint >= sizeof(sun4c_pil_map)) { 55 printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint); 56 BUG(); 57 } 58 return sun4c_pil_map[sbint]; 59} 60 61static void sun4c_disable_irq(unsigned int irq_nr) 62{ 63 unsigned long flags; 64 unsigned char current_mask, new_mask; 65 66 local_irq_save(flags); 67 irq_nr &= (NR_IRQS - 1); 68 current_mask = *interrupt_enable; 69 switch(irq_nr) { 70 case 1: 71 new_mask = ((current_mask) & (~(SUN4C_INT_E1))); 72 break; 73 case 8: 74 new_mask = ((current_mask) & (~(SUN4C_INT_E8))); 75 break; 76 case 10: 77 new_mask = ((current_mask) & (~(SUN4C_INT_E10))); 78 break; 79 case 14: 80 new_mask = ((current_mask) & (~(SUN4C_INT_E14))); 81 break; 82 default: 83 local_irq_restore(flags); 84 return; 85 } 86 *interrupt_enable = new_mask; 87 local_irq_restore(flags); 88} 89 90static void sun4c_enable_irq(unsigned int irq_nr) 91{ 92 unsigned long flags; 93 unsigned char current_mask, new_mask; 94 95 local_irq_save(flags); 96 irq_nr &= (NR_IRQS - 1); 97 current_mask = *interrupt_enable; 98 switch(irq_nr) { 99 case 1: 100 new_mask = ((current_mask) | SUN4C_INT_E1); 101 break; 102 case 8: 103 new_mask = ((current_mask) | SUN4C_INT_E8); 104 break; 105 case 10: 106 new_mask = ((current_mask) | SUN4C_INT_E10); 107 break; 108 case 14: 109 new_mask = ((current_mask) | SUN4C_INT_E14); 110 break; 111 default: 112 local_irq_restore(flags); 113 return; 114 } 115 *interrupt_enable = new_mask; 116 local_irq_restore(flags); 117} 118 119#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */ 120#define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */ 121 122volatile struct sun4c_timer_info *sun4c_timers; 123 124#ifdef CONFIG_SUN4 125volatile struct sun4c_timer_info sun4_timer; 126#endif 127 128static void sun4c_clear_clock_irq(void) 129{ 130 volatile unsigned int clear_intr; 131#ifdef CONFIG_SUN4 132 if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) 133 clear_intr = sun4_timer.timer_limit10; 134 else 135#endif 136 clear_intr = sun4c_timers->timer_limit10; 137} 138 139static void sun4c_clear_profile_irq(int cpu) 140{ 141 /* Errm.. not sure how to do this.. */ 142} 143 144static void sun4c_load_profile_irq(int cpu, unsigned int limit) 145{ 146 /* Errm.. not sure how to do this.. */ 147} 148 149static void __init sun4c_init_timers(irq_handler_t counter_fn) 150{ 151 int irq; 152 153 /* Map the Timer chip, this is implemented in hardware inside 154 * the cache chip on the sun4c. 155 */ 156#ifdef CONFIG_SUN4 157 if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) 158 sun4c_timers = &sun4_timer; 159 else 160#endif 161 sun4c_timers = ioremap(SUN_TIMER_PHYSADDR, 162 sizeof(struct sun4c_timer_info)); 163 164 /* Have the level 10 timer tick at 100HZ. We don't touch the 165 * level 14 timer limit since we are letting the prom handle 166 * them until we have a real console driver so L1-A works. 167 */ 168 sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10); 169 master_l10_counter = &sun4c_timers->cur_count10; 170 master_l10_limit = &sun4c_timers->timer_limit10; 171 172 irq = request_irq(TIMER_IRQ, 173 counter_fn, 174 (IRQF_DISABLED | SA_STATIC_ALLOC), 175 "timer", NULL); 176 if (irq) { 177 prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); 178 prom_halt(); 179 } 180 181 claim_ticker14(NULL, PROFILE_IRQ, 0); 182} 183 184#ifdef CONFIG_SMP 185static void sun4c_nop(void) {} 186#endif 187 188void __init sun4c_init_IRQ(void) 189{ 190 struct linux_prom_registers int_regs[2]; 191 int ie_node; 192 193 if (ARCH_SUN4) { 194 interrupt_enable = (char *) 195 ioremap(sun4_ie_physaddr, PAGE_SIZE); 196 } else { 197 struct resource phyres; 198 199 ie_node = prom_searchsiblings (prom_getchild(prom_root_node), 200 "interrupt-enable"); 201 if(ie_node == 0) 202 panic("Cannot find /interrupt-enable node"); 203 204 /* Depending on the "address" property is bad news... */ 205 interrupt_enable = NULL; 206 if (prom_getproperty(ie_node, "reg", (char *) int_regs, 207 sizeof(int_regs)) != -1) { 208 memset(&phyres, 0, sizeof(struct resource)); 209 phyres.flags = int_regs[0].which_io; 210 phyres.start = int_regs[0].phys_addr; 211 interrupt_enable = (char *) sbus_ioremap(&phyres, 0, 212 int_regs[0].reg_size, "sun4c_intr"); 213 } 214 } 215 if (!interrupt_enable) 216 panic("Cannot map interrupt_enable"); 217 218 BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM); 219 BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); 220 BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); 221 BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); 222 BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); 223 BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); 224 BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); 225 BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); 226 sparc_init_timers = sun4c_init_timers; 227#ifdef CONFIG_SMP 228 BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); 229 BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); 230 BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); 231#endif 232 *interrupt_enable = (SUN4C_INT_ENABLE); 233 /* Cannot enable interrupts until OBP ticker is disabled. */ 234} 235