1/* 2 * linux/arch/h8300/kernel/irq.c 3 * 4 * Copyright 2007 Yoshinori Sato <ysato@users.sourceforge.jp> 5 */ 6 7#include <linux/module.h> 8#include <linux/types.h> 9#include <linux/kernel.h> 10#include <linux/sched.h> 11#include <linux/kernel_stat.h> 12#include <linux/seq_file.h> 13#include <linux/init.h> 14#include <linux/random.h> 15#include <linux/bootmem.h> 16#include <linux/irq.h> 17 18#include <asm/system.h> 19#include <asm/traps.h> 20#include <asm/io.h> 21#include <asm/setup.h> 22#include <asm/errno.h> 23 24/*#define DEBUG*/ 25 26extern unsigned long *interrupt_redirect_table; 27extern const int h8300_saved_vectors[]; 28extern const unsigned long h8300_trap_table[]; 29int h8300_enable_irq_pin(unsigned int irq); 30void h8300_disable_irq_pin(unsigned int irq); 31 32#define CPU_VECTOR ((unsigned long *)0x000000) 33#define ADDR_MASK (0xffffff) 34 35static inline int is_ext_irq(unsigned int irq) 36{ 37 return (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS)); 38} 39 40static void h8300_enable_irq(unsigned int irq) 41{ 42 if (is_ext_irq(irq)) 43 IER_REGS |= 1 << (irq - EXT_IRQ0); 44} 45 46static void h8300_disable_irq(unsigned int irq) 47{ 48 if (is_ext_irq(irq)) 49 IER_REGS &= ~(1 << (irq - EXT_IRQ0)); 50} 51 52static void h8300_end_irq(unsigned int irq) 53{ 54} 55 56static unsigned int h8300_startup_irq(unsigned int irq) 57{ 58 if (is_ext_irq(irq)) 59 return h8300_enable_irq_pin(irq); 60 else 61 return 0; 62} 63 64static void h8300_shutdown_irq(unsigned int irq) 65{ 66 if (is_ext_irq(irq)) 67 h8300_disable_irq_pin(irq); 68} 69 70/* 71 * h8300 interrupt controler implementation 72 */ 73struct irq_chip h8300irq_chip = { 74 .name = "H8300-INTC", 75 .startup = h8300_startup_irq, 76 .shutdown = h8300_shutdown_irq, 77 .enable = h8300_enable_irq, 78 .disable = h8300_disable_irq, 79 .ack = NULL, 80 .end = h8300_end_irq, 81}; 82 83void ack_bad_irq(unsigned int irq) 84{ 85 printk("unexpected IRQ trap at vector %02x\n", irq); 86} 87 88#if defined(CONFIG_RAMKERNEL) 89static unsigned long __init *get_vector_address(void) 90{ 91 unsigned long *rom_vector = CPU_VECTOR; 92 unsigned long base,tmp; 93 int vec_no; 94 95 base = rom_vector[EXT_IRQ0] & ADDR_MASK; 96 97 /* check romvector format */ 98 for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) { 99 if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK)) 100 return NULL; 101 } 102 103 /* ramvector base address */ 104 base -= EXT_IRQ0*4; 105 106 /* writerble check */ 107 tmp = ~(*(volatile unsigned long *)base); 108 (*(volatile unsigned long *)base) = tmp; 109 if ((*(volatile unsigned long *)base) != tmp) 110 return NULL; 111 return (unsigned long *)base; 112} 113 114static void __init setup_vector(void) 115{ 116 int i; 117 unsigned long *ramvec,*ramvec_p; 118 const unsigned long *trap_entry; 119 const int *saved_vector; 120 121 ramvec = get_vector_address(); 122 if (ramvec == NULL) 123 panic("interrupt vector serup failed."); 124 else 125 printk(KERN_INFO "virtual vector at 0x%08lx\n",(unsigned long)ramvec); 126 127 /* create redirect table */ 128 ramvec_p = ramvec; 129 trap_entry = h8300_trap_table; 130 saved_vector = h8300_saved_vectors; 131 for ( i = 0; i < NR_IRQS; i++) { 132 if (i == *saved_vector) { 133 ramvec_p++; 134 saved_vector++; 135 } else { 136 if ( i < NR_TRAPS ) { 137 if (*trap_entry) 138 *ramvec_p = VECTOR(*trap_entry); 139 ramvec_p++; 140 trap_entry++; 141 } else 142 *ramvec_p++ = REDIRECT(interrupt_entry); 143 } 144 } 145 interrupt_redirect_table = ramvec; 146#ifdef DEBUG 147 ramvec_p = ramvec; 148 for (i = 0; i < NR_IRQS; i++) { 149 if ((i % 8) == 0) 150 printk(KERN_DEBUG "\n%p: ",ramvec_p); 151 printk(KERN_DEBUG "%p ",*ramvec_p); 152 ramvec_p++; 153 } 154 printk(KERN_DEBUG "\n"); 155#endif 156} 157#else 158#define setup_vector() do { } while(0) 159#endif 160 161void __init init_IRQ(void) 162{ 163 int c; 164 165 setup_vector(); 166 167 for (c = 0; c < NR_IRQS; c++) { 168 irq_desc[c].status = IRQ_DISABLED; 169 irq_desc[c].action = NULL; 170 irq_desc[c].depth = 1; 171 irq_desc[c].chip = &h8300irq_chip; 172 } 173} 174 175asmlinkage void do_IRQ(int irq) 176{ 177 irq_enter(); 178 __do_IRQ(irq); 179 irq_exit(); 180} 181 182#if defined(CONFIG_PROC_FS) 183int show_interrupts(struct seq_file *p, void *v) 184{ 185 int i = *(loff_t *) v, j; 186 struct irqaction * action; 187 unsigned long flags; 188 189 if (i == 0) 190 seq_puts(p, " CPU0"); 191 192 if (i < NR_IRQS) { 193 spin_lock_irqsave(&irq_desc[i].lock, flags); 194 action = irq_desc[i].action; 195 if (!action) 196 goto unlock; 197 seq_printf(p, "%3d: ",i); 198 seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); 199 seq_printf(p, " %14s", irq_desc[i].chip->name); 200 seq_printf(p, "-%-8s", irq_desc[i].name); 201 seq_printf(p, " %s", action->name); 202 203 for (action=action->next; action; action = action->next) 204 seq_printf(p, ", %s", action->name); 205 seq_putc(p, '\n'); 206unlock: 207 spin_unlock_irqrestore(&irq_desc[i].lock, flags); 208 } 209 return 0; 210} 211#endif 212