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

[PATCH] m68k: introduce irq controller

Introduce irq controller and use it to manage auto vector interrupts.
Introduce setup_irq() which can be used for irq setup.

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
b5dc7840 1d174cfb

+152 -103
+1 -3
arch/m68k/amiga/amiints.c
··· 40 40 #include <linux/sched.h> 41 41 #include <linux/kernel_stat.h> 42 42 #include <linux/init.h> 43 + #include <linux/interrupt.h> 43 44 #include <linux/errno.h> 44 45 #include <linux/seq_file.h> 45 46 ··· 485 484 } 486 485 487 486 irqreturn_t (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { 488 - [0] = ami_badint, 489 487 [1] = ami_int1, 490 - [2] = ami_badint, 491 488 [3] = ami_int3, 492 489 [4] = ami_int4, 493 490 [5] = ami_int5, 494 - [6] = ami_badint, 495 491 [7] = ami_int7 496 492 }; 497 493
+1
arch/m68k/bvme6000/bvmeints.c
··· 14 14 #include <linux/types.h> 15 15 #include <linux/kernel.h> 16 16 #include <linux/errno.h> 17 + #include <linux/interrupt.h> 17 18 #include <linux/seq_file.h> 18 19 19 20 #include <asm/ptrace.h>
+127 -52
arch/m68k/kernel/ints.c
··· 45 45 #endif 46 46 47 47 /* table for system interrupt handlers */ 48 - static irq_handler_t irq_list[SYS_IRQS]; 48 + static struct irq_node *irq_list[SYS_IRQS]; 49 + static struct irq_controller *irq_controller[SYS_IRQS]; 50 + 51 + static struct irq_controller auto_irq_controller = { 52 + .name = "auto", 53 + .lock = SPIN_LOCK_UNLOCKED, 54 + .startup = m68k_irq_startup, 55 + .shutdown = m68k_irq_shutdown, 56 + }; 49 57 50 58 static const char *default_names[SYS_IRQS] = { 51 59 [0] = "spurious int", ··· 109 101 hardirq_mask_is_broken(); 110 102 } 111 103 112 - for (i = 0; i < SYS_IRQS; i++) { 113 - if (mach_default_handler) 114 - irq_list[i].handler = (*mach_default_handler)[i]; 115 - irq_list[i].flags = 0; 116 - irq_list[i].dev_id = NULL; 117 - irq_list[i].devname = default_names[i]; 104 + for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) { 105 + irq_controller[i] = &auto_irq_controller; 106 + if (mach_default_handler && (*mach_default_handler)[i]) 107 + cpu_request_irq(i, (*mach_default_handler)[i], 108 + 0, default_names[i], NULL); 118 109 } 119 - 120 - for (i = 0; i < NUM_IRQ_NODES; i++) 121 - nodes[i].handler = NULL; 122 110 123 111 mach_init_IRQ (); 124 112 } ··· 124 120 irq_node_t *node; 125 121 short i; 126 122 127 - for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) 128 - if (!node->handler) 123 + for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) { 124 + if (!node->handler) { 125 + memset(node, 0, sizeof(*node)); 129 126 return node; 127 + } 128 + } 130 129 131 130 printk ("new_irq_node: out of nodes\n"); 132 131 return NULL; ··· 156 149 157 150 EXPORT_SYMBOL(free_irq); 158 151 152 + int setup_irq(unsigned int irq, struct irq_node *node) 153 + { 154 + struct irq_controller *contr; 155 + struct irq_node **prev; 156 + unsigned long flags; 157 + 158 + if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { 159 + printk("%s: Incorrect IRQ %d from %s\n", 160 + __FUNCTION__, irq, node->devname); 161 + return -ENXIO; 162 + } 163 + 164 + spin_lock_irqsave(&contr->lock, flags); 165 + 166 + prev = irq_list + irq; 167 + if (*prev) { 168 + /* Can't share interrupts unless both agree to */ 169 + if (!((*prev)->flags & node->flags & SA_SHIRQ)) { 170 + spin_unlock_irqrestore(&contr->lock, flags); 171 + return -EBUSY; 172 + } 173 + while (*prev) 174 + prev = &(*prev)->next; 175 + } 176 + 177 + if (!irq_list[irq]) { 178 + if (contr->startup) 179 + contr->startup(irq); 180 + else 181 + contr->enable(irq); 182 + } 183 + node->next = NULL; 184 + *prev = node; 185 + 186 + spin_unlock_irqrestore(&contr->lock, flags); 187 + 188 + return 0; 189 + } 190 + 159 191 int cpu_request_irq(unsigned int irq, 160 192 irqreturn_t (*handler)(int, void *, struct pt_regs *), 161 193 unsigned long flags, const char *devname, void *dev_id) 162 194 { 163 - if (irq < IRQ_AUTO_1 || irq > IRQ_AUTO_7) { 164 - printk("%s: Incorrect IRQ %d from %s\n", 165 - __FUNCTION__, irq, devname); 166 - return -ENXIO; 167 - } 195 + struct irq_node *node; 196 + int res; 168 197 169 - #if 0 170 - if (!(irq_list[irq].flags & IRQ_FLG_STD)) { 171 - if (irq_list[irq].flags & IRQ_FLG_LOCK) { 172 - printk("%s: IRQ %d from %s is not replaceable\n", 173 - __FUNCTION__, irq, irq_list[irq].devname); 174 - return -EBUSY; 175 - } 176 - if (!(flags & IRQ_FLG_REPLACE)) { 177 - printk("%s: %s can't replace IRQ %d from %s\n", 178 - __FUNCTION__, devname, irq, irq_list[irq].devname); 179 - return -EBUSY; 180 - } 181 - } 182 - #endif 198 + node = new_irq_node(); 199 + if (!node) 200 + return -ENOMEM; 183 201 184 - irq_list[irq].handler = handler; 185 - irq_list[irq].flags = flags; 186 - irq_list[irq].dev_id = dev_id; 187 - irq_list[irq].devname = devname; 188 - return 0; 202 + node->handler = handler; 203 + node->flags = flags; 204 + node->dev_id = dev_id; 205 + node->devname = devname; 206 + 207 + res = setup_irq(irq, node); 208 + if (res) 209 + node->handler = NULL; 210 + 211 + return res; 189 212 } 190 213 191 214 void cpu_free_irq(unsigned int irq, void *dev_id) 192 215 { 193 - if (irq < IRQ_AUTO_1 || irq > IRQ_AUTO_7) { 216 + struct irq_controller *contr; 217 + struct irq_node **p, *node; 218 + unsigned long flags; 219 + 220 + if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { 194 221 printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); 195 222 return; 196 223 } 197 224 198 - if (irq_list[irq].dev_id != dev_id) 199 - printk("%s: Removing probably wrong IRQ %d from %s\n", 200 - __FUNCTION__, irq, irq_list[irq].devname); 225 + spin_lock_irqsave(&contr->lock, flags); 201 226 202 - irq_list[irq].handler = (*mach_default_handler)[irq]; 203 - irq_list[irq].flags = 0; 204 - irq_list[irq].dev_id = NULL; 205 - irq_list[irq].devname = default_names[irq]; 227 + p = irq_list + irq; 228 + while ((node = *p)) { 229 + if (node->dev_id == dev_id) 230 + break; 231 + p = &node->next; 232 + } 233 + 234 + if (node) { 235 + *p = node->next; 236 + node->handler = NULL; 237 + } else 238 + printk("%s: Removing probably wrong IRQ %d\n", 239 + __FUNCTION__, irq); 240 + 241 + if (!irq_list[irq]) 242 + contr->shutdown(irq); 243 + 244 + spin_unlock_irqrestore(&contr->lock, flags); 206 245 } 246 + 247 + int m68k_irq_startup(unsigned int irq) 248 + { 249 + if (irq <= IRQ_AUTO_7) 250 + vectors[VEC_SPUR + irq] = auto_inthandler; 251 + return 0; 252 + } 253 + 254 + void m68k_irq_shutdown(unsigned int irq) 255 + { 256 + if (irq <= IRQ_AUTO_7) 257 + vectors[VEC_SPUR + irq] = bad_inthandler; 258 + } 259 + 207 260 208 261 /* 209 262 * Do we need these probe functions on the m68k? ··· 317 250 318 251 asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) 319 252 { 253 + struct irq_node *node; 254 + 320 255 kstat_cpu(0).irqs[irq]++; 321 - irq_list[irq].handler(irq, irq_list[irq].dev_id, regs); 256 + node = irq_list[irq]; 257 + do { 258 + node->handler(irq, node->dev_id, regs); 259 + node = node->next; 260 + } while (node); 322 261 } 323 262 324 263 asmlinkage void handle_badint(struct pt_regs *regs) ··· 335 262 336 263 int show_interrupts(struct seq_file *p, void *v) 337 264 { 265 + struct irq_controller *contr; 266 + struct irq_node *node; 338 267 int i = *(loff_t *) v; 339 268 340 269 /* autovector interrupts */ 341 - if (i < SYS_IRQS) { 342 - if (mach_default_handler) { 343 - seq_printf(p, "auto %2d: %10u ", i, 344 - i ? kstat_cpu(0).irqs[i] : num_spurious); 345 - seq_puts(p, " "); 346 - seq_printf(p, "%s\n", irq_list[i].devname); 347 - } 270 + if (i < SYS_IRQS && irq_list[i]) { 271 + contr = irq_controller[i]; 272 + node = irq_list[i]; 273 + seq_printf(p, "%s %u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); 274 + while ((node = node->next)) 275 + seq_printf(p, ", %s", node->devname); 276 + seq_puts(p, "\n"); 348 277 } else if (i == SYS_IRQS) 349 278 mach_get_irq_list(p, v); 350 279 return 0;
-15
arch/m68k/mac/config.c
··· 94 94 via_init_clock(vector); 95 95 } 96 96 97 - extern irqreturn_t mac_default_handler(int, void *, struct pt_regs *); 98 - 99 - irqreturn_t (*mac_handlers[8])(int, void *, struct pt_regs *)= 100 - { 101 - mac_default_handler, 102 - mac_default_handler, 103 - mac_default_handler, 104 - mac_default_handler, 105 - mac_default_handler, 106 - mac_default_handler, 107 - mac_default_handler, 108 - mac_default_handler 109 - }; 110 - 111 97 /* 112 98 * Parse a Macintosh-specific record in the bootinfo 113 99 */ ··· 174 188 enable_irq = mac_enable_irq; 175 189 disable_irq = mac_disable_irq; 176 190 mach_get_model = mac_get_model; 177 - mach_default_handler = &mac_handlers; 178 191 mach_get_irq_list = show_mac_interrupts; 179 192 mach_gettimeoffset = mac_gettimeoffset; 180 193 #warning move to adb/via init
-7
arch/m68k/mac/macints.c
··· 637 637 return 0; 638 638 } 639 639 640 - void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs) 641 - { 642 - #ifdef DEBUG_SPURIOUS 643 - printk("Unexpected IRQ %d on device %p\n", irq, dev_id); 644 - #endif 645 - } 646 - 647 640 static int num_debug[8]; 648 641 649 642 irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
+1
arch/m68k/mvme147/147ints.c
··· 14 14 #include <linux/types.h> 15 15 #include <linux/kernel.h> 16 16 #include <linux/errno.h> 17 + #include <linux/interrupt.h> 17 18 #include <linux/seq_file.h> 18 19 19 20 #include <asm/ptrace.h>
+1
arch/m68k/mvme16x/16xints.c
··· 14 14 #include <linux/types.h> 15 15 #include <linux/kernel.h> 16 16 #include <linux/errno.h> 17 + #include <linux/interrupt.h> 17 18 #include <linux/seq_file.h> 18 19 19 20 #include <asm/system.h>
-2
arch/m68k/q40/config.c
··· 37 37 #include <asm/q40_master.h> 38 38 39 39 extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); 40 - extern irqreturn_t (*q40_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */ 41 40 extern void q40_init_IRQ (void); 42 41 extern void q40_free_irq (unsigned int, void *); 43 42 extern int show_q40_interrupts (struct seq_file *, void *); ··· 180 181 mach_request_irq = q40_request_irq; 181 182 enable_irq = q40_enable_irq; 182 183 disable_irq = q40_disable_irq; 183 - mach_default_handler = &q40_default_handler; 184 184 mach_get_model = q40_get_model; 185 185 mach_get_hardware_list = q40_get_hardware_list; 186 186
-17
arch/m68k/q40/q40ints.c
··· 46 46 47 47 48 48 static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp); 49 - static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs); 50 49 51 50 52 51 #define DEVNAME_SIZE 24 ··· 414 415 else master_outb(-1,KEYBOARD_UNLOCK_REG); 415 416 return IRQ_NONE; 416 417 } 417 - static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs) 418 - { 419 - printk ("Uninitialised interrupt level %d\n", lev); 420 - return IRQ_NONE; 421 - } 422 - 423 - irqreturn_t (*q40_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { 424 - [0] = default_handler, 425 - [1] = default_handler, 426 - [2] = default_handler, 427 - [3] = default_handler, 428 - [4] = default_handler, 429 - [5] = default_handler, 430 - [6] = default_handler, 431 - [7] = default_handler 432 - }; 433 418 434 419 435 420 void q40_enable_irq (unsigned int irq)
+1
drivers/block/amiflop.c
··· 64 64 #include <linux/buffer_head.h> 65 65 #include <linux/blkdev.h> 66 66 #include <linux/elevator.h> 67 + #include <linux/interrupt.h> 67 68 68 69 #include <asm/setup.h> 69 70 #include <asm/uaccess.h>
+1 -1
include/asm-m68k/atari_stdma.h
··· 3 3 #define _atari_stdma_h 4 4 5 5 6 - #include <asm/irq.h> 6 + #include <linux/interrupt.h> 7 7 8 8 9 9 /***************************** Prototypes *****************************/
+19 -6
include/asm-m68k/irq.h
··· 1 1 #ifndef _M68K_IRQ_H_ 2 2 #define _M68K_IRQ_H_ 3 3 4 - #include <linux/interrupt.h> 4 + #include <linux/hardirq.h> 5 + #include <linux/spinlock_types.h> 5 6 6 7 /* 7 8 * # of m68k auto vector interrupts ··· 82 81 struct pt_regs; 83 82 84 83 extern int cpu_request_irq(unsigned int, 85 - irqreturn_t (*)(int, void *, struct pt_regs *), 84 + int (*)(int, void *, struct pt_regs *), 86 85 unsigned long, const char *, void *); 87 86 extern void cpu_free_irq(unsigned int, void *); 88 87 ··· 104 103 * interrupt source (if it supports chaining). 105 104 */ 106 105 typedef struct irq_node { 107 - irqreturn_t (*handler)(int, void *, struct pt_regs *); 108 - unsigned long flags; 106 + int (*handler)(int, void *, struct pt_regs *); 109 107 void *dev_id; 110 - const char *devname; 111 108 struct irq_node *next; 109 + unsigned long flags; 110 + const char *devname; 112 111 } irq_node_t; 113 112 114 113 /* 115 114 * This structure has only 4 elements for speed reasons 116 115 */ 117 116 typedef struct irq_handler { 118 - irqreturn_t (*handler)(int, void *, struct pt_regs *); 117 + int (*handler)(int, void *, struct pt_regs *); 119 118 unsigned long flags; 120 119 void *dev_id; 121 120 const char *devname; 122 121 } irq_handler_t; 122 + 123 + struct irq_controller { 124 + const char *name; 125 + spinlock_t lock; 126 + int (*startup)(unsigned int irq); 127 + void (*shutdown)(unsigned int irq); 128 + void (*enable)(unsigned int irq); 129 + void (*disable)(unsigned int irq); 130 + }; 131 + 132 + extern int m68k_irq_startup(unsigned int); 133 + extern void m68k_irq_shutdown(unsigned int); 123 134 124 135 /* count of spurious interrupts */ 125 136 extern volatile unsigned int num_spurious;