1/* 2 * linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c 3 * 4 * This file is subject to the terms and conditions of the GNU General Public 5 * License. See the file COPYING in the main directory of this archive 6 * for more details. 7 * 8 * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com> 9 * Copyright (c) 1996 Roman Zippel 10 * Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org> 11 */ 12 13#include <linux/module.h> 14#include <linux/types.h> 15#include <linux/kernel.h> 16#include <linux/sched.h> 17#include <linux/kernel_stat.h> 18#include <linux/errno.h> 19 20#include <asm/system.h> 21#include <asm/irq.h> 22#include <asm/irqnode.h> 23#include <asm/traps.h> 24#include <asm/io.h> 25#include <asm/machdep.h> 26#include <asm/setup.h> 27#include <asm/m68360.h> 28 29/* from quicc/commproc.c: */ 30extern QUICC *pquicc; 31extern void cpm_interrupt_init(void); 32 33#define INTERNAL_IRQS (96) 34 35/* assembler routines */ 36asmlinkage void system_call(void); 37asmlinkage void buserr(void); 38asmlinkage void trap(void); 39asmlinkage irqreturn_t bad_interrupt(void); 40asmlinkage irqreturn_t inthandler(void); 41 42extern void *_ramvec[]; 43 44/* The number of spurious interrupts */ 45volatile unsigned int num_spurious; 46unsigned int local_irq_count[NR_CPUS]; 47 48/* irq node variables for the 32 (potential) on chip sources */ 49static irq_node_t int_irq_list[INTERNAL_IRQS]; 50 51static short int_irq_ablecount[INTERNAL_IRQS]; 52 53/* 54 * This function should be called during kernel startup to initialize 55 * IRQ handling routines. 56 */ 57 58void init_IRQ(void) 59{ 60 int i; 61 int vba = (CPM_VECTOR_BASE<<4); 62 63 /* set up the vectors */ 64 _ramvec[2] = buserr; 65 _ramvec[3] = trap; 66 _ramvec[4] = trap; 67 _ramvec[5] = trap; 68 _ramvec[6] = trap; 69 _ramvec[7] = trap; 70 _ramvec[8] = trap; 71 _ramvec[9] = trap; 72 _ramvec[10] = trap; 73 _ramvec[11] = trap; 74 _ramvec[12] = trap; 75 _ramvec[13] = trap; 76 _ramvec[14] = trap; 77 _ramvec[15] = trap; 78 79 _ramvec[32] = system_call; 80 _ramvec[33] = trap; 81 82 83 cpm_interrupt_init(); 84 85 /* set up CICR for vector base address and irq level */ 86 /* irl = 4, hp = 1f - see MC68360UM p 7-377 */ 87 pquicc->intr_cicr = 0x00e49f00 | vba; 88 89 /* CPM interrupt vectors: (p 7-376) */ 90 _ramvec[vba+CPMVEC_ERROR] = bad_interrupt; /* Error */ 91 _ramvec[vba+CPMVEC_PIO_PC11] = inthandler; /* pio - pc11 */ 92 _ramvec[vba+CPMVEC_PIO_PC10] = inthandler; /* pio - pc10 */ 93 _ramvec[vba+CPMVEC_SMC2] = inthandler; /* smc2/pip */ 94 _ramvec[vba+CPMVEC_SMC1] = inthandler; /* smc1 */ 95 _ramvec[vba+CPMVEC_SPI] = inthandler; /* spi */ 96 _ramvec[vba+CPMVEC_PIO_PC9] = inthandler; /* pio - pc9 */ 97 _ramvec[vba+CPMVEC_TIMER4] = inthandler; /* timer 4 */ 98 _ramvec[vba+CPMVEC_RESERVED1] = inthandler; /* reserved */ 99 _ramvec[vba+CPMVEC_PIO_PC8] = inthandler; /* pio - pc8 */ 100 _ramvec[vba+CPMVEC_PIO_PC7] = inthandler; /* pio - pc7 */ 101 _ramvec[vba+CPMVEC_PIO_PC6] = inthandler; /* pio - pc6 */ 102 _ramvec[vba+CPMVEC_TIMER3] = inthandler; /* timer 3 */ 103 _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* reserved */ 104 _ramvec[vba+CPMVEC_PIO_PC5] = inthandler; /* pio - pc5 */ 105 _ramvec[vba+CPMVEC_PIO_PC4] = inthandler; /* pio - pc4 */ 106 _ramvec[vba+CPMVEC_RESERVED2] = inthandler; /* reserved */ 107 _ramvec[vba+CPMVEC_RISCTIMER] = inthandler; /* timer table */ 108 _ramvec[vba+CPMVEC_TIMER2] = inthandler; /* timer 2 */ 109 _ramvec[vba+CPMVEC_RESERVED3] = inthandler; /* reserved */ 110 _ramvec[vba+CPMVEC_IDMA2] = inthandler; /* idma 2 */ 111 _ramvec[vba+CPMVEC_IDMA1] = inthandler; /* idma 1 */ 112 _ramvec[vba+CPMVEC_SDMA_CB_ERR] = inthandler; /* sdma channel bus error */ 113 _ramvec[vba+CPMVEC_PIO_PC3] = inthandler; /* pio - pc3 */ 114 _ramvec[vba+CPMVEC_PIO_PC2] = inthandler; /* pio - pc2 */ 115 /* _ramvec[vba+CPMVEC_TIMER1] = cpm_isr_timer1; */ /* timer 1 */ 116 _ramvec[vba+CPMVEC_TIMER1] = inthandler; /* timer 1 */ 117 _ramvec[vba+CPMVEC_PIO_PC1] = inthandler; /* pio - pc1 */ 118 _ramvec[vba+CPMVEC_SCC4] = inthandler; /* scc 4 */ 119 _ramvec[vba+CPMVEC_SCC3] = inthandler; /* scc 3 */ 120 _ramvec[vba+CPMVEC_SCC2] = inthandler; /* scc 2 */ 121 _ramvec[vba+CPMVEC_SCC1] = inthandler; /* scc 1 */ 122 _ramvec[vba+CPMVEC_PIO_PC0] = inthandler; /* pio - pc0 */ 123 124 125 /* turn off all CPM interrupts */ 126 pquicc->intr_cimr = 0x00000000; 127 128 /* initialize handlers */ 129 for (i = 0; i < INTERNAL_IRQS; i++) { 130 int_irq_list[i].handler = NULL; 131 int_irq_list[i].flags = IRQ_FLG_STD; 132 int_irq_list[i].dev_id = NULL; 133 int_irq_list[i].devname = NULL; 134 } 135} 136 137 138int request_irq( 139 unsigned int irq, 140 irqreturn_t (*handler)(int, void *, struct pt_regs *), 141 unsigned long flags, 142 const char *devname, 143 void *dev_id) 144{ 145 int mask = (1<<irq); 146 147 irq += (CPM_VECTOR_BASE<<4); 148 149 if (irq >= INTERNAL_IRQS) { 150 printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname); 151 return -ENXIO; 152 } 153 154 if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) { 155 if (int_irq_list[irq].flags & IRQ_FLG_LOCK) { 156 printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n", 157 __FUNCTION__, irq, int_irq_list[irq].devname); 158 return -EBUSY; 159 } 160 if (flags & IRQ_FLG_REPLACE) { 161 printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n", 162 __FUNCTION__, devname, irq, int_irq_list[irq].devname); 163 return -EBUSY; 164 } 165 } 166 int_irq_list[irq].handler = handler; 167 int_irq_list[irq].flags = flags; 168 int_irq_list[irq].dev_id = dev_id; 169 int_irq_list[irq].devname = devname; 170 171 /* enable in the CIMR */ 172 if (!int_irq_ablecount[irq]) 173 pquicc->intr_cimr |= mask; 174 /* *(volatile unsigned long *)0xfffff304 &= ~(1<<irq); */ 175 176 return 0; 177} 178 179EXPORT_SYMBOL(request_irq); 180 181void free_irq(unsigned int irq, void *dev_id) 182{ 183 if (irq >= INTERNAL_IRQS) { 184 printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq); 185 return; 186 } 187 188 if (int_irq_list[irq].dev_id != dev_id) 189 printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n", 190 __FUNCTION__, irq, int_irq_list[irq].devname); 191 int_irq_list[irq].handler = NULL; 192 int_irq_list[irq].flags = IRQ_FLG_STD; 193 int_irq_list[irq].dev_id = NULL; 194 int_irq_list[irq].devname = NULL; 195 196 *(volatile unsigned long *)0xfffff304 |= 1<<irq; 197} 198 199EXPORT_SYMBOL(free_irq); 200 201 202int show_interrupts(struct seq_file *p, void *v) 203{ 204 int i = *(loff_t *) v; 205 206 if (i < NR_IRQS) { 207 if (int_irq_list[i].devname) { 208 seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]); 209 if (int_irq_list[i].flags & IRQ_FLG_LOCK) 210 seq_printf(p, "L "); 211 else 212 seq_printf(p, " "); 213 seq_printf(p, "%s\n", int_irq_list[i].devname); 214 } 215 } 216 if (i == NR_IRQS) 217 seq_printf(p, " : %10u spurious\n", num_spurious); 218 219 return 0; 220} 221 222/* The 68k family did not have a good way to determine the source 223 * of interrupts until later in the family. The EC000 core does 224 * not provide the vector number on the stack, we vector everything 225 * into one vector and look in the blasted mask register... 226 * This code is designed to be fast, almost constant time, not clean! 227 */ 228void process_int(int vec, struct pt_regs *fp) 229{ 230 int irq; 231 int mask; 232 233 /* unsigned long pend = *(volatile unsigned long *)0xfffff30c; */ 234 235 /* irq = vec + (CPM_VECTOR_BASE<<4); */ 236 irq = vec; 237 238 /* unsigned long pend = *(volatile unsigned long *)pquicc->intr_cipr; */ 239 240 /* Bugger all that weirdness. For the moment, I seem to know where I came from; 241 * vec is passed from a specific ISR, so I'll use it. */ 242 243 if (int_irq_list[irq].handler) { 244 int_irq_list[irq].handler(irq , int_irq_list[irq].dev_id, fp); 245 kstat_cpu(0).irqs[irq]++; 246 pquicc->intr_cisr = (1 << vec); /* indicate that irq has been serviced */ 247 } else { 248 printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the CIMR...\n", irq); 249 /* *(volatile unsigned long *)0xfffff304 |= mask; */ 250 pquicc->intr_cimr &= ~(1 << vec); 251 num_spurious += 1; 252 } 253 return(IRQ_HANDLED); 254} 255