1 /* 2 * arch/sh/kernel/cpu/irq/imask.c 3 * 4 * Copyright (C) 1999, 2000 Niibe Yutaka 5 * 6 * Simple interrupt handling using IMASK of SR register. 7 * 8 */ 9 /* NOTE: Will not work on level 15 */ 10 #include <linux/ptrace.h> 11 #include <linux/errno.h> 12 #include <linux/kernel_stat.h> 13 #include <linux/signal.h> 14 #include <linux/sched.h> 15 #include <linux/interrupt.h> 16 #include <linux/init.h> 17 #include <linux/bitops.h> 18 #include <linux/spinlock.h> 19 #include <linux/cache.h> 20 #include <linux/irq.h> 21 #include <asm/system.h> 22 #include <asm/irq.h> 23 24 /* Bitmap of IRQ masked */ 25 static unsigned long imask_mask = 0x7fff; 26 static int interrupt_priority = 0; 27 28 static void enable_imask_irq(unsigned int irq); 29 static void disable_imask_irq(unsigned int irq); 30 static void shutdown_imask_irq(unsigned int irq); 31 static void mask_and_ack_imask(unsigned int); 32 static void end_imask_irq(unsigned int irq); 33 34 #define IMASK_PRIORITY 15 35 36 static unsigned int startup_imask_irq(unsigned int irq) 37 { 38 /* Nothing to do */ 39 return 0; /* never anything pending */ 40 } 41 42 static struct hw_interrupt_type imask_irq_type = { 43 .typename = "SR.IMASK", 44 .startup = startup_imask_irq, 45 .shutdown = shutdown_imask_irq, 46 .enable = enable_imask_irq, 47 .disable = disable_imask_irq, 48 .ack = mask_and_ack_imask, 49 .end = end_imask_irq 50 }; 51 52 void static inline set_interrupt_registers(int ip) 53 { 54 unsigned long __dummy; 55 56 asm volatile( 57 #ifdef CONFIG_CPU_HAS_SR_RB 58 "ldc %2, r6_bank\n\t" 59 #endif 60 "stc sr, %0\n\t" 61 "and #0xf0, %0\n\t" 62 "shlr2 %0\n\t" 63 "cmp/eq #0x3c, %0\n\t" 64 "bt/s 1f ! CLI-ed\n\t" 65 " stc sr, %0\n\t" 66 "and %1, %0\n\t" 67 "or %2, %0\n\t" 68 "ldc %0, sr\n" 69 "1:" 70 : "=&z" (__dummy) 71 : "r" (~0xf0), "r" (ip << 4) 72 : "t"); 73 } 74 75 static void disable_imask_irq(unsigned int irq) 76 { 77 clear_bit(irq, &imask_mask); 78 if (interrupt_priority < IMASK_PRIORITY - irq) 79 interrupt_priority = IMASK_PRIORITY - irq; 80 81 set_interrupt_registers(interrupt_priority); 82 } 83 84 static void enable_imask_irq(unsigned int irq) 85 { 86 set_bit(irq, &imask_mask); 87 interrupt_priority = IMASK_PRIORITY - ffz(imask_mask); 88 89 set_interrupt_registers(interrupt_priority); 90 } 91 92 static void mask_and_ack_imask(unsigned int irq) 93 { 94 disable_imask_irq(irq); 95 } 96 97 static void end_imask_irq(unsigned int irq) 98 { 99 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 100 enable_imask_irq(irq); 101 } 102 103 static void shutdown_imask_irq(unsigned int irq) 104 { 105 /* Nothing to do */ 106 } 107 108 void make_imask_irq(unsigned int irq) 109 { 110 disable_irq_nosync(irq); 111 irq_desc[irq].chip = &imask_irq_type; 112 enable_irq(irq); 113 } 114