Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] m68k: convert generic irq code to irq controller

Convert the generic irq code to use irq controller, this gets rid of the
machine specific callbacks and gives better control over irq handling without
duplicating lots of code.

Signed-off-by: Roman Zippel <zippel@linux-m68k.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Roman Zippel and committed by
Linus Torvalds
68387c44 b5dc7840

+188 -148
+8 -3
arch/m68k/kernel/entry.S
··· 48 48 .globl sys_call_table 49 49 .globl sys_fork, sys_clone, sys_vfork 50 50 .globl ret_from_interrupt, bad_interrupt 51 + .globl auto_irqhandler_fixup 52 + .globl user_irqvec_fixup, user_irqhandler_fixup 51 53 52 54 .text 53 55 ENTRY(buserr) ··· 214 212 jbra 3f 215 213 1: 216 214 #endif 215 + auto_irqhandler_fixup = . + 2 217 216 jsr m68k_handle_int | process the IRQ 218 217 3: addql #8,%sp | pop parameters off stack 219 218 ··· 237 234 238 235 /* Handler for user defined interrupt vectors */ 239 236 240 - ENTRY(mach_inthandler) 237 + ENTRY(user_inthandler) 241 238 SAVE_ALL_INT 242 239 GET_CURRENT(%d0) 243 240 addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1) 244 241 | put exception # in d0 245 242 bfextu %sp@(PT_VECTOR){#4,#10},%d0 243 + user_irqvec_fixup = . + 2 244 + subw #VEC_USER,%d0 246 245 247 246 movel %sp,%sp@- 248 247 movel %d0,%sp@- | put vector # on stack 249 - movel mach_process_int,%a0 250 - jsr %a0@ | process the IRQ 248 + user_irqhandler_fixup = . + 2 249 + jsr m68k_handle_int | process the IRQ 251 250 addql #8,%sp | pop parameters off stack 252 251 253 252 subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
+152 -88
arch/m68k/kernel/ints.c
··· 39 39 #include <asm/traps.h> 40 40 #include <asm/page.h> 41 41 #include <asm/machdep.h> 42 + #include <asm/cacheflush.h> 42 43 43 44 #ifdef CONFIG_Q40 44 45 #include <asm/q40ints.h> 45 46 #endif 46 47 48 + extern u32 auto_irqhandler_fixup[]; 49 + extern u32 user_irqhandler_fixup[]; 50 + extern u16 user_irqvec_fixup[]; 51 + 47 52 /* table for system interrupt handlers */ 48 - static struct irq_node *irq_list[SYS_IRQS]; 49 - static struct irq_controller *irq_controller[SYS_IRQS]; 53 + static struct irq_node *irq_list[NR_IRQS]; 54 + static struct irq_controller *irq_controller[NR_IRQS]; 55 + static int irq_depth[NR_IRQS]; 56 + 57 + static int m68k_first_user_vec; 50 58 51 59 static struct irq_controller auto_irq_controller = { 52 60 .name = "auto", ··· 63 55 .shutdown = m68k_irq_shutdown, 64 56 }; 65 57 66 - static const char *default_names[SYS_IRQS] = { 67 - [0] = "spurious int", 68 - [1] = "int1 handler", 69 - [2] = "int2 handler", 70 - [3] = "int3 handler", 71 - [4] = "int4 handler", 72 - [5] = "int5 handler", 73 - [6] = "int6 handler", 74 - [7] = "int7 handler" 58 + static struct irq_controller user_irq_controller = { 59 + .name = "user", 60 + .lock = SPIN_LOCK_UNLOCKED, 61 + .startup = m68k_irq_startup, 62 + .shutdown = m68k_irq_shutdown, 75 63 }; 76 - 77 - /* The number of spurious interrupts */ 78 - volatile unsigned int num_spurious; 79 64 80 65 #define NUM_IRQ_NODES 100 81 66 static irq_node_t nodes[NUM_IRQ_NODES]; 82 - 83 - static void dummy_enable_irq(unsigned int irq); 84 - static void dummy_disable_irq(unsigned int irq); 85 - static int dummy_request_irq(unsigned int irq, 86 - irqreturn_t (*handler) (int, void *, struct pt_regs *), 87 - unsigned long flags, const char *devname, void *dev_id); 88 - static void dummy_free_irq(unsigned int irq, void *dev_id); 89 - 90 - void (*enable_irq) (unsigned int) = dummy_enable_irq; 91 - void (*disable_irq) (unsigned int) = dummy_disable_irq; 92 - 93 - int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *), 94 - unsigned long, const char *, void *) = dummy_request_irq; 95 - void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; 96 - 97 - void init_irq_proc(void); 98 67 99 68 /* 100 69 * void init_IRQ(void) ··· 94 109 hardirq_mask_is_broken(); 95 110 } 96 111 97 - for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) { 112 + for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) 98 113 irq_controller[i] = &auto_irq_controller; 99 - if (mach_default_handler && (*mach_default_handler)[i]) 100 - cpu_request_irq(i, (*mach_default_handler)[i], 101 - 0, default_names[i], NULL); 102 - } 103 114 104 - mach_init_IRQ (); 115 + mach_init_IRQ(); 116 + } 117 + 118 + /** 119 + * m68k_setup_auto_interrupt 120 + * @handler: called from auto vector interrupts 121 + * 122 + * setup the handler to be called from auto vector interrupts instead of the 123 + * standard m68k_handle_int(), it will be called with irq numbers in the range 124 + * from IRQ_AUTO_1 - IRQ_AUTO_7. 125 + */ 126 + void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) 127 + { 128 + if (handler) 129 + *auto_irqhandler_fixup = (u32)handler; 130 + flush_icache(); 131 + } 132 + 133 + /** 134 + * m68k_setup_user_interrupt 135 + * @vec: first user vector interrupt to handle 136 + * @cnt: number of active user vector interrupts 137 + * @handler: called from user vector interrupts 138 + * 139 + * setup user vector interrupts, this includes activating the specified range 140 + * of interrupts, only then these interrupts can be requested (note: this is 141 + * different from auto vector interrupts). An optional handler can be installed 142 + * to be called instead of the default m68k_handle_int(), it will be called 143 + * with irq numbers starting from IRQ_USER. 144 + */ 145 + void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, 146 + void (*handler)(unsigned int, struct pt_regs *)) 147 + { 148 + int i; 149 + 150 + m68k_first_user_vec = vec; 151 + for (i = 0; i < cnt; i++) 152 + irq_controller[IRQ_USER + i] = &user_irq_controller; 153 + *user_irqvec_fixup = vec - IRQ_USER; 154 + if (handler) 155 + *user_irqhandler_fixup = (u32)handler; 156 + flush_icache(); 157 + } 158 + 159 + /** 160 + * m68k_setup_irq_controller 161 + * @contr: irq controller which controls specified irq 162 + * @irq: first irq to be managed by the controller 163 + * 164 + * Change the controller for the specified range of irq, which will be used to 165 + * manage these irq. auto/user irq already have a default controller, which can 166 + * be changed as well, but the controller probably should use m68k_irq_startup/ 167 + * m68k_irq_shutdown. 168 + */ 169 + void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq, 170 + unsigned int cnt) 171 + { 172 + int i; 173 + 174 + for (i = 0; i < cnt; i++) 175 + irq_controller[irq + i] = contr; 105 176 } 106 177 107 178 irq_node_t *new_irq_node(void) ··· 176 135 return NULL; 177 136 } 178 137 179 - /* 180 - * We will keep these functions until I have convinced Linus to move 181 - * the declaration of them from include/linux/sched.h to 182 - * include/asm/irq.h. 183 - */ 184 - int request_irq(unsigned int irq, 185 - irqreturn_t (*handler) (int, void *, struct pt_regs *), 186 - unsigned long flags, const char *devname, void *dev_id) 187 - { 188 - return mach_request_irq(irq, handler, flags, devname, dev_id); 189 - } 190 - 191 - EXPORT_SYMBOL(request_irq); 192 - 193 - void free_irq(unsigned int irq, void *dev_id) 194 - { 195 - mach_free_irq(irq, dev_id); 196 - } 197 - 198 - EXPORT_SYMBOL(free_irq); 199 - 200 138 int setup_irq(unsigned int irq, struct irq_node *node) 201 139 { 202 140 struct irq_controller *contr; 203 141 struct irq_node **prev; 204 142 unsigned long flags; 205 143 206 - if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { 144 + if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 207 145 printk("%s: Incorrect IRQ %d from %s\n", 208 146 __FUNCTION__, irq, node->devname); 209 147 return -ENXIO; ··· 215 195 return 0; 216 196 } 217 197 218 - int cpu_request_irq(unsigned int irq, 219 - irqreturn_t (*handler)(int, void *, struct pt_regs *), 220 - unsigned long flags, const char *devname, void *dev_id) 198 + int request_irq(unsigned int irq, 199 + irqreturn_t (*handler) (int, void *, struct pt_regs *), 200 + unsigned long flags, const char *devname, void *dev_id) 221 201 { 222 202 struct irq_node *node; 223 203 int res; ··· 238 218 return res; 239 219 } 240 220 241 - void cpu_free_irq(unsigned int irq, void *dev_id) 221 + EXPORT_SYMBOL(request_irq); 222 + 223 + void free_irq(unsigned int irq, void *dev_id) 242 224 { 243 225 struct irq_controller *contr; 244 226 struct irq_node **p, *node; 245 227 unsigned long flags; 246 228 247 - if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { 229 + if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 248 230 printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); 249 231 return; 250 232 } ··· 267 245 printk("%s: Removing probably wrong IRQ %d\n", 268 246 __FUNCTION__, irq); 269 247 270 - if (!irq_list[irq]) 271 - contr->shutdown(irq); 248 + if (!irq_list[irq]) { 249 + if (contr->shutdown) 250 + contr->shutdown(irq); 251 + else 252 + contr->disable(irq); 253 + } 272 254 273 255 spin_unlock_irqrestore(&contr->lock, flags); 274 256 } 257 + 258 + EXPORT_SYMBOL(free_irq); 259 + 260 + void enable_irq(unsigned int irq) 261 + { 262 + struct irq_controller *contr; 263 + unsigned long flags; 264 + 265 + if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 266 + printk("%s: Incorrect IRQ %d\n", 267 + __FUNCTION__, irq); 268 + return; 269 + } 270 + 271 + spin_lock_irqsave(&contr->lock, flags); 272 + if (irq_depth[irq]) { 273 + if (!--irq_depth[irq]) { 274 + if (contr->enable) 275 + contr->enable(irq); 276 + } 277 + } else 278 + WARN_ON(1); 279 + spin_unlock_irqrestore(&contr->lock, flags); 280 + } 281 + 282 + EXPORT_SYMBOL(enable_irq); 283 + 284 + void disable_irq(unsigned int irq) 285 + { 286 + struct irq_controller *contr; 287 + unsigned long flags; 288 + 289 + if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { 290 + printk("%s: Incorrect IRQ %d\n", 291 + __FUNCTION__, irq); 292 + return; 293 + } 294 + 295 + spin_lock_irqsave(&contr->lock, flags); 296 + if (!irq_depth[irq]++) { 297 + if (contr->disable) 298 + contr->disable(irq); 299 + } 300 + spin_unlock_irqrestore(&contr->lock, flags); 301 + } 302 + 303 + EXPORT_SYMBOL(disable_irq); 275 304 276 305 int m68k_irq_startup(unsigned int irq) 277 306 { 278 307 if (irq <= IRQ_AUTO_7) 279 308 vectors[VEC_SPUR + irq] = auto_inthandler; 309 + else 310 + vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; 280 311 return 0; 281 312 } 282 313 ··· 337 262 { 338 263 if (irq <= IRQ_AUTO_7) 339 264 vectors[VEC_SPUR + irq] = bad_inthandler; 265 + else 266 + vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; 340 267 } 341 268 342 269 ··· 369 292 370 293 EXPORT_SYMBOL(probe_irq_off); 371 294 372 - static void dummy_enable_irq(unsigned int irq) 295 + unsigned int irq_canonicalize(unsigned int irq) 373 296 { 374 - printk("calling uninitialized enable_irq()\n"); 297 + #ifdef CONFIG_Q40 298 + if (MACH_IS_Q40 && irq == 11) 299 + irq = 10; 300 + #endif 301 + return irq; 375 302 } 376 303 377 - static void dummy_disable_irq(unsigned int irq) 378 - { 379 - printk("calling uninitialized disable_irq()\n"); 380 - } 381 - 382 - static int dummy_request_irq(unsigned int irq, 383 - irqreturn_t (*handler) (int, void *, struct pt_regs *), 384 - unsigned long flags, const char *devname, void *dev_id) 385 - { 386 - printk("calling uninitialized request_irq()\n"); 387 - return 0; 388 - } 389 - 390 - static void dummy_free_irq(unsigned int irq, void *dev_id) 391 - { 392 - printk("calling uninitialized disable_irq()\n"); 393 - } 304 + EXPORT_SYMBOL(irq_canonicalize); 394 305 395 306 asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) 396 307 { ··· 405 340 int i = *(loff_t *) v; 406 341 407 342 /* autovector interrupts */ 408 - if (i < SYS_IRQS && irq_list[i]) { 343 + if (irq_list[i]) { 409 344 contr = irq_controller[i]; 410 345 node = irq_list[i]; 411 - seq_printf(p, "%s %u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); 346 + seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); 412 347 while ((node = node->next)) 413 348 seq_printf(p, ", %s", node->devname); 414 349 seq_puts(p, "\n"); 415 - } else if (i == SYS_IRQS) 416 - mach_get_irq_list(p, v); 350 + } 417 351 return 0; 418 352 } 419 353
-2
arch/m68k/kernel/m68k_ksyms.c
··· 57 57 EXPORT_SYMBOL(strnlen); 58 58 EXPORT_SYMBOL(strrchr); 59 59 EXPORT_SYMBOL(strstr); 60 - EXPORT_SYMBOL(enable_irq); 61 - EXPORT_SYMBOL(disable_irq); 62 60 EXPORT_SYMBOL(kernel_thread); 63 61 #ifdef CONFIG_VME 64 62 EXPORT_SYMBOL(vme_brdtype);
-3
arch/m68k/kernel/setup.c
··· 68 68 void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL; 69 69 /* machine dependent irq functions */ 70 70 void (*mach_init_IRQ) (void) __initdata = NULL; 71 - irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *); 72 71 void (*mach_get_model) (char *model); 73 72 int (*mach_get_hardware_list) (char *buffer); 74 - int (*mach_get_irq_list) (struct seq_file *, void *); 75 - irqreturn_t (*mach_process_int) (int, struct pt_regs *); 76 73 /* machine dependent timer functions */ 77 74 unsigned long (*mach_gettimeoffset) (void); 78 75 int (*mach_hwclk) (int, struct rtc_time*);
+3 -4
arch/m68k/kernel/traps.c
··· 87 87 { 88 88 int i; 89 89 90 - vectors[VEC_SPUR] = bad_inthandler; 91 - for (i = VEC_INT1; i <= VEC_INT7; i++) 92 - vectors[i] = auto_inthandler; 90 + for (i = VEC_SPUR; i <= VEC_INT7; i++) 91 + vectors[i] = bad_inthandler; 93 92 94 93 for (i = 0; i < VEC_USER; i++) 95 94 if (!vectors[i]) 96 95 vectors[i] = trap; 97 96 98 97 for (i = VEC_USER; i < 256; i++) 99 - vectors[i] = mach_inthandler; 98 + vectors[i] = bad_inthandler; 100 99 101 100 #ifdef CONFIG_M68KFPU_EMU 102 101 if (FPU_IS_EMU)
+24 -41
include/asm-m68k/irq.h
··· 1 1 #ifndef _M68K_IRQ_H_ 2 2 #define _M68K_IRQ_H_ 3 3 4 + #include <linux/linkage.h> 4 5 #include <linux/hardirq.h> 5 6 #include <linux/spinlock_types.h> 6 - 7 - /* 8 - * # of m68k auto vector interrupts 9 - */ 10 - 11 - #define SYS_IRQS 8 12 7 13 8 /* 14 9 * This should be the same as the max(NUM_X_SOURCES) for all the ··· 11 16 * Currently the Atari has 72 and the Amiga 24, but if both are 12 17 * supported in the kernel it is better to make room for 72. 13 18 */ 14 - #if defined(CONFIG_ATARI) || defined(CONFIG_MAC) 15 - #define NR_IRQS (72+SYS_IRQS) 19 + #if defined(CONFIG_VME) || defined(CONFIG_SUN3) || defined(CONFIG_SUN3X) 20 + #define NR_IRQS 200 21 + #elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) 22 + #define NR_IRQS 72 23 + #elif defined(CONFIG_Q40) 24 + #define NR_IRQS 43 25 + #elif defined(CONFIG_AMIGA) 26 + #define NR_IRQS 32 27 + #elif defined(CONFIG_APOLLO) 28 + #define NR_IRQS 24 29 + #elif defined(CONFIG_HP300) 30 + #define NR_IRQS 8 16 31 #else 17 - #define NR_IRQS (24+SYS_IRQS) 32 + #error unknown nr of irqs 18 33 #endif 19 34 20 35 /* ··· 58 53 59 54 #define IRQ_USER 8 60 55 61 - static __inline__ int irq_canonicalize(int irq) 62 - { 63 - return irq; 64 - } 65 - 66 - /* 67 - * Machine specific interrupt sources. 68 - * 69 - * Adding an interrupt service routine for a source with this bit 70 - * set indicates a special machine specific interrupt source. 71 - * The machine specific files define these sources. 72 - * 73 - * The IRQ_MACHSPEC bit is now gone - the only thing it did was to 74 - * introduce unnecessary overhead. 75 - * 76 - * All interrupt handling is actually machine specific so it is better 77 - * to use function pointers, as used by the Sparc port, and select the 78 - * interrupt handling functions when initializing the kernel. This way 79 - * we save some unnecessary overhead at run-time. 80 - * 01/11/97 - Jes 81 - */ 82 - 83 - extern void (*enable_irq)(unsigned int); 84 - extern void (*disable_irq)(unsigned int); 56 + extern unsigned int irq_canonicalize(unsigned int irq); 57 + extern void enable_irq(unsigned int); 58 + extern void disable_irq(unsigned int); 85 59 #define disable_irq_nosync disable_irq 86 60 87 61 struct pt_regs; 88 - 89 - extern int cpu_request_irq(unsigned int, 90 - int (*)(int, void *, struct pt_regs *), 91 - unsigned long, const char *, void *); 92 - extern void cpu_free_irq(unsigned int, void *); 93 62 94 63 /* 95 64 * various flags for request_irq() - the Amiga now uses the standard ··· 112 133 extern int m68k_irq_startup(unsigned int); 113 134 extern void m68k_irq_shutdown(unsigned int); 114 135 115 - /* count of spurious interrupts */ 116 - extern volatile unsigned int num_spurious; 117 - 118 136 /* 119 137 * This function returns a new irq_node_t 120 138 */ 121 139 extern irq_node_t *new_irq_node(void); 140 + 141 + extern void m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)); 142 + extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, 143 + void (*handler)(unsigned int, struct pt_regs *)); 144 + extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int); 145 + 146 + asmlinkage void m68k_handle_int(unsigned int, struct pt_regs *); 122 147 123 148 #endif /* _M68K_IRQ_H_ */
-6
include/asm-m68k/machdep.h
··· 13 13 extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)); 14 14 /* machine dependent irq functions */ 15 15 extern void (*mach_init_IRQ) (void); 16 - extern irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *); 17 - extern int (*mach_request_irq) (unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), 18 - unsigned long flags, const char *devname, void *dev_id); 19 - extern void (*mach_free_irq) (unsigned int irq, void *dev_id); 20 16 extern void (*mach_get_model) (char *model); 21 17 extern int (*mach_get_hardware_list) (char *buffer); 22 - extern int (*mach_get_irq_list) (struct seq_file *p, void *v); 23 - extern irqreturn_t (*mach_process_int) (int irq, struct pt_regs *fp); 24 18 /* machine dependent timer functions */ 25 19 extern unsigned long (*mach_gettimeoffset)(void); 26 20 extern int (*mach_hwclk)(int, struct rtc_time*);
+1 -1
include/asm-m68k/traps.h
··· 19 19 typedef void (*e_vector)(void); 20 20 21 21 asmlinkage void auto_inthandler(void); 22 - asmlinkage void mach_inthandler(void); 22 + asmlinkage void user_inthandler(void); 23 23 asmlinkage void bad_inthandler(void); 24 24 25 25 extern e_vector vectors[];