1/* 2 * linux/arch/h8300/kernel/ints.c 3 * 4 * Yoshinori Sato <ysato@users.sourceforge.jp> 5 * 6 * Based on linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file COPYING in the main directory of this archive 10 * for more details. 11 * 12 * Copyright 1996 Roman Zippel 13 * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com> 14 */ 15 16#include <linux/module.h> 17#include <linux/types.h> 18#include <linux/kernel.h> 19#include <linux/sched.h> 20#include <linux/kernel_stat.h> 21#include <linux/seq_file.h> 22#include <linux/interrupt.h> 23#include <linux/init.h> 24#include <linux/random.h> 25#include <linux/bootmem.h> 26#include <linux/hardirq.h> 27 28#include <asm/system.h> 29#include <asm/irq.h> 30#include <asm/traps.h> 31#include <asm/io.h> 32#include <asm/setup.h> 33#include <asm/errno.h> 34 35/* 36 * This structure has only 4 elements for speed reasons 37 */ 38typedef struct irq_handler { 39 irqreturn_t (*handler)(int, void *, struct pt_regs *); 40 int flags; 41 int count; 42 void *dev_id; 43 const char *devname; 44} irq_handler_t; 45 46static irq_handler_t *irq_list[NR_IRQS]; 47static int use_kmalloc; 48 49extern unsigned long *interrupt_redirect_table; 50extern const int h8300_saved_vectors[]; 51extern const unsigned long h8300_trap_table[]; 52int h8300_enable_irq_pin(unsigned int irq); 53void h8300_disable_irq_pin(unsigned int irq); 54 55#define CPU_VECTOR ((unsigned long *)0x000000) 56#define ADDR_MASK (0xffffff) 57 58#if defined(CONFIG_RAMKERNEL) 59static unsigned long __init *get_vector_address(void) 60{ 61 unsigned long *rom_vector = CPU_VECTOR; 62 unsigned long base,tmp; 63 int vec_no; 64 65 base = rom_vector[EXT_IRQ0] & ADDR_MASK; 66 67 /* check romvector format */ 68 for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) { 69 if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK)) 70 return NULL; 71 } 72 73 /* ramvector base address */ 74 base -= EXT_IRQ0*4; 75 76 /* writerble check */ 77 tmp = ~(*(volatile unsigned long *)base); 78 (*(volatile unsigned long *)base) = tmp; 79 if ((*(volatile unsigned long *)base) != tmp) 80 return NULL; 81 return (unsigned long *)base; 82} 83#endif 84 85void __init init_IRQ(void) 86{ 87#if defined(CONFIG_RAMKERNEL) 88 int i; 89 unsigned long *ramvec,*ramvec_p; 90 const unsigned long *trap_entry; 91 const int *saved_vector; 92 93 ramvec = get_vector_address(); 94 if (ramvec == NULL) 95 panic("interrupt vector serup failed."); 96 else 97 printk(KERN_INFO "virtual vector at 0x%08lx\n",(unsigned long)ramvec); 98 99 /* create redirect table */ 100 ramvec_p = ramvec; 101 trap_entry = h8300_trap_table; 102 saved_vector = h8300_saved_vectors; 103 for ( i = 0; i < NR_IRQS; i++) { 104 if (i == *saved_vector) { 105 ramvec_p++; 106 saved_vector++; 107 } else { 108 if ( i < NR_TRAPS ) { 109 if (*trap_entry) 110 *ramvec_p = VECTOR(*trap_entry); 111 ramvec_p++; 112 trap_entry++; 113 } else 114 *ramvec_p++ = REDIRECT(interrupt_entry); 115 } 116 } 117 interrupt_redirect_table = ramvec; 118#ifdef DUMP_VECTOR 119 ramvec_p = ramvec; 120 for (i = 0; i < NR_IRQS; i++) { 121 if ((i % 8) == 0) 122 printk(KERN_DEBUG "\n%p: ",ramvec_p); 123 printk(KERN_DEBUG "%p ",*ramvec_p); 124 ramvec_p++; 125 } 126 printk(KERN_DEBUG "\n"); 127#endif 128#endif 129} 130 131int request_irq(unsigned int irq, 132 irqreturn_t (*handler)(int, void *, struct pt_regs *), 133 unsigned long flags, const char *devname, void *dev_id) 134{ 135 irq_handler_t *irq_handle; 136 if (irq < 0 || irq >= NR_IRQS) { 137 printk(KERN_ERR "Incorrect IRQ %d from %s\n", irq, devname); 138 return -EINVAL; 139 } 140 141 if (irq_list[irq] || (h8300_enable_irq_pin(irq) == -EBUSY)) 142 return -EBUSY; 143 144 if (use_kmalloc) 145 irq_handle = kmalloc(sizeof(irq_handler_t), GFP_ATOMIC); 146 else { 147 /* use bootmem allocater */ 148 irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t)); 149 irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000); 150 } 151 152 if (irq_handle == NULL) 153 return -ENOMEM; 154 155 irq_handle->handler = handler; 156 irq_handle->flags = flags; 157 irq_handle->count = 0; 158 irq_handle->dev_id = dev_id; 159 irq_handle->devname = devname; 160 irq_list[irq] = irq_handle; 161 162 if (irq_handle->flags & IRQF_SAMPLE_RANDOM) 163 rand_initialize_irq(irq); 164 165 enable_irq(irq); 166 return 0; 167} 168 169EXPORT_SYMBOL(request_irq); 170 171void free_irq(unsigned int irq, void *dev_id) 172{ 173 if (irq >= NR_IRQS) 174 return; 175 176 if (!irq_list[irq] || irq_list[irq]->dev_id != dev_id) 177 printk(KERN_WARNING "Removing probably wrong IRQ %d from %s\n", 178 irq, irq_list[irq]->devname); 179 disable_irq(irq); 180 h8300_disable_irq_pin(irq); 181 if (((unsigned long)irq_list[irq] & 0x80000000) == 0) { 182 kfree(irq_list[irq]); 183 irq_list[irq] = NULL; 184 } 185} 186 187EXPORT_SYMBOL(free_irq); 188 189/* 190 * Do we need these probe functions on the m68k? 191 */ 192unsigned long probe_irq_on (void) 193{ 194 return 0; 195} 196 197EXPORT_SYMBOL(probe_irq_on); 198 199int probe_irq_off (unsigned long irqs) 200{ 201 return 0; 202} 203 204EXPORT_SYMBOL(probe_irq_off); 205 206void enable_irq(unsigned int irq) 207{ 208 if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS)) 209 IER_REGS |= 1 << (irq - EXT_IRQ0); 210} 211 212void disable_irq(unsigned int irq) 213{ 214 if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS)) 215 IER_REGS &= ~(1 << (irq - EXT_IRQ0)); 216} 217 218asmlinkage void process_int(int irq, struct pt_regs *fp) 219{ 220 irq_enter(); 221 h8300_clear_isr(irq); 222 if (irq >= NR_TRAPS && irq < NR_IRQS) { 223 if (irq_list[irq]) { 224 irq_list[irq]->handler(irq, irq_list[irq]->dev_id, fp); 225 irq_list[irq]->count++; 226 if (irq_list[irq]->flags & IRQF_SAMPLE_RANDOM) 227 add_interrupt_randomness(irq); 228 } 229 } else { 230 BUG(); 231 } 232 irq_exit(); 233} 234 235int show_interrupts(struct seq_file *p, void *v) 236{ 237 int i = *(loff_t *) v; 238 239 if ((i < NR_IRQS) && (irq_list[i]!=NULL)) { 240 seq_printf(p, "%3d: %10u ",i,irq_list[i]->count); 241 seq_printf(p, "%s\n", irq_list[i]->devname); 242 } 243 244 return 0; 245} 246 247void init_irq_proc(void) 248{ 249} 250 251static int __init enable_kmalloc(void) 252{ 253 use_kmalloc = 1; 254 return 0; 255} 256core_initcall(enable_kmalloc); 257