irq.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  arch/s390/kernel/irq.c
  3.  *
  4.  *  S390 version
  5.  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  6.  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  7.  *
  8.  *  Derived from "arch/i386/kernel/irq.c"
  9.  *    Copyright (C) 1992, 1999 Linus Torvalds, Ingo Molnar
  10.  *
  11.  *  S/390 I/O interrupt processing and I/O request processing is
  12.  *   implemented in arch/s390/kernel/s390io.c
  13.  */
  14. #include <linux/module.h>
  15. #include <linux/config.h>
  16. #include <linux/ptrace.h>
  17. #include <linux/errno.h>
  18. #include <linux/kernel_stat.h>
  19. #include <linux/signal.h>
  20. #include <linux/sched.h>
  21. #include <linux/ioport.h>
  22. #include <linux/interrupt.h>
  23. #include <linux/timex.h>
  24. #include <linux/slab.h>
  25. #include <linux/string.h>
  26. #include <linux/random.h>
  27. #include <linux/smp.h>
  28. #include <linux/threads.h>
  29. #include <linux/smp_lock.h>
  30. #include <linux/init.h>
  31. #include <asm/system.h>
  32. #include <asm/io.h>
  33. #include <asm/irq.h>
  34. #include <asm/bitops.h>
  35. #include <asm/smp.h>
  36. #include <asm/pgtable.h>
  37. #include <asm/delay.h>
  38. #include <asm/lowcore.h>
  39. void          s390_init_IRQ   ( void );
  40. void          s390_free_irq   ( unsigned int irq, void *dev_id);
  41. int           s390_request_irq( unsigned int irq,
  42.                      void           (*handler)(int, void *, struct pt_regs *),
  43.                      unsigned long  irqflags,
  44.                      const char    *devname,
  45.                      void          *dev_id);
  46. #if 0
  47. /*
  48.  * The following vectors are part of the Linux architecture, there
  49.  * is no hardware IRQ pin equivalent for them, they are triggered
  50.  * through the ICC by us (IPIs), via smp_message_pass():
  51.  */
  52. BUILD_SMP_INTERRUPT(reschedule_interrupt)
  53. BUILD_SMP_INTERRUPT(invalidate_interrupt)
  54. BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
  55. BUILD_SMP_INTERRUPT(mtrr_interrupt)
  56. BUILD_SMP_INTERRUPT(spurious_interrupt)
  57. #endif
  58. /*
  59.  * Global interrupt locks for SMP. Allow interrupts to come in on any
  60.  * CPU, yet make cli/sti act globally to protect critical regions..
  61.  */
  62. #ifdef CONFIG_SMP
  63. atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
  64. atomic_t global_irq_lock = ATOMIC_INIT(0);
  65. atomic_t global_irq_count = ATOMIC_INIT(0);
  66. atomic_t global_bh_count;
  67. /*
  68.  * "global_cli()" is a special case, in that it can hold the
  69.  * interrupts disabled for a longish time, and also because
  70.  * we may be doing TLB invalidates when holding the global
  71.  * IRQ lock for historical reasons. Thus we may need to check
  72.  * SMP invalidate events specially by hand here (but not in
  73.  * any normal spinlocks)
  74.  *
  75.  * Thankfully we don't need this as we can deliver flush tlbs with
  76.  * interrupts disabled DJB :-)
  77.  */
  78. #define check_smp_invalidate(cpu)
  79. static void show(char * str)
  80. {
  81. int i;
  82. unsigned long *stack;
  83. int cpu = smp_processor_id();
  84. printk("n%s, CPU %d:n", str, cpu);
  85. printk("irq:  %d [%d]n",
  86.        atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
  87. printk("bh:   %d [%d]n",
  88.        atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
  89. stack = (unsigned long *) &str;
  90. for (i = 40; i ; i--) {
  91. unsigned long x = *++stack;
  92. if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {
  93. printk("<[%08lx]> ", x);
  94. }
  95. }
  96. }
  97. #define MAXCOUNT 100000000
  98. static inline void wait_on_bh(void)
  99. {
  100. int count = MAXCOUNT;
  101. do {
  102. if (!--count) {
  103. show("wait_on_bh");
  104. count = ~0;
  105. }
  106. /* nothing .. wait for the other bh's to go away */
  107. } while (atomic_read(&global_bh_count) != 0);
  108. }
  109. static inline void wait_on_irq(int cpu)
  110. {
  111. int count = MAXCOUNT;
  112. for (;;) {
  113. /*
  114.  * Wait until all interrupts are gone. Wait
  115.  * for bottom half handlers unless we're
  116.  * already executing in one..
  117.  */
  118. if (!atomic_read(&global_irq_count)) {
  119. if (local_bh_count(cpu)||
  120.     !atomic_read(&global_bh_count))
  121. break;
  122. }
  123. /* Duh, we have to loop. Release the lock to avoid deadlocks */
  124. atomic_set(&global_irq_lock, 0);
  125. for (;;) {
  126. if (!--count) {
  127. show("wait_on_irq");
  128. count = ~0;
  129. }
  130. __sti();
  131. SYNC_OTHER_CORES(cpu);
  132. __cli();
  133. check_smp_invalidate(cpu);
  134. if (atomic_read(&global_irq_count))
  135. continue;
  136. if (atomic_read(&global_irq_lock))
  137. continue;
  138. if (!local_bh_count(cpu)
  139.     && atomic_read(&global_bh_count))
  140. continue;
  141. if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
  142.  break;
  143. }
  144. }
  145. }
  146. /*
  147.  * This is called when we want to synchronize with
  148.  * bottom half handlers. We need to wait until
  149.  * no other CPU is executing any bottom half handler.
  150.  *
  151.  * Don't wait if we're already running in an interrupt
  152.  * context or are inside a bh handler.
  153.  */
  154. void synchronize_bh(void)
  155. {
  156. if (atomic_read(&global_bh_count) && !in_interrupt())
  157. wait_on_bh();
  158. }
  159. /*
  160.  * This is called when we want to synchronize with
  161.  * interrupts. We may for example tell a device to
  162.  * stop sending interrupts: but to make sure there
  163.  * are no interrupts that are executing on another
  164.  * CPU we need to call this function.
  165.  */
  166. void synchronize_irq(void)
  167. {
  168. if (atomic_read(&global_irq_count)) {
  169. /* Stupid approach */
  170. cli();
  171. sti();
  172. }
  173. }
  174. static inline void get_irqlock(int cpu)
  175. {
  176. if (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0) {
  177. /* do we already hold the lock? */
  178. if ( cpu == atomic_read(&global_irq_holder))
  179. return;
  180. /* Uhhuh.. Somebody else got it. Wait.. */
  181. do {
  182. check_smp_invalidate(cpu);
  183. } while (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0);
  184. }
  185. /*
  186.  * We also to make sure that nobody else is running
  187.  * in an interrupt context.
  188.  */
  189. wait_on_irq(cpu);
  190. /*
  191.  * Ok, finally..
  192.  */
  193. atomic_set(&global_irq_holder,cpu);
  194. }
  195. #define EFLAGS_I_SHIFT 25
  196. /*
  197.  * A global "cli()" while in an interrupt context
  198.  * turns into just a local cli(). Interrupts
  199.  * should use spinlocks for the (very unlikely)
  200.  * case that they ever want to protect against
  201.  * each other.
  202.  *
  203.  * If we already have local interrupts disabled,
  204.  * this will not turn a local disable into a
  205.  * global one (problems with spinlocks: this makes
  206.  * save_flags+cli+sti usable inside a spinlock).
  207.  */
  208. void __global_cli(void)
  209. {
  210. unsigned long flags;
  211. __save_flags(flags);
  212. if (flags & (1 << EFLAGS_I_SHIFT)) {
  213. int cpu = smp_processor_id();
  214. __cli();
  215. if (!in_irq())
  216. get_irqlock(cpu);
  217. }
  218. }
  219. void __global_sti(void)
  220. {
  221. if (!in_irq())
  222. release_irqlock(smp_processor_id());
  223. __sti();
  224. }
  225. /*
  226.  * SMP flags value to restore to:
  227.  * 0 - global cli
  228.  * 1 - global sti
  229.  * 2 - local cli
  230.  * 3 - local sti
  231.  */
  232. unsigned long __global_save_flags(void)
  233. {
  234. int retval;
  235. int local_enabled;
  236. unsigned long flags;
  237. __save_flags(flags);
  238. local_enabled = (flags >> EFLAGS_I_SHIFT) & 1;
  239. /* default to local */
  240. retval = 2 + local_enabled;
  241. /* check for global flags if we're not in an interrupt */
  242. if (!in_irq())
  243. {
  244. if (local_enabled)
  245. retval = 1;
  246. if (atomic_read(&global_irq_holder)== smp_processor_id())
  247. retval = 0;
  248. }
  249. return retval;
  250. }
  251. void __global_restore_flags(unsigned long flags)
  252. {
  253. switch (flags) {
  254. case 0:
  255. __global_cli();
  256. break;
  257. case 1:
  258. __global_sti();
  259. break;
  260. case 2:
  261. __cli();
  262. break;
  263. case 3:
  264. __sti();
  265. break;
  266. default:
  267. printk("global_restore_flags: %08lx (%08lx)n",
  268.        flags, (&flags)[-1]);
  269. }
  270. }
  271. #endif
  272. void __init init_IRQ(void)
  273. {
  274.         s390_init_IRQ();
  275. }
  276. void free_irq(unsigned int irq, void *dev_id)
  277. {
  278.    s390_free_irq( irq, dev_id);
  279. }
  280. int request_irq( unsigned int   irq,
  281.                  void           (*handler)(int, void *, struct pt_regs *),
  282.                  unsigned long  irqflags,
  283.                  const char    *devname,
  284.                  void          *dev_id)
  285. {
  286.    return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
  287. }
  288. void init_irq_proc(void)
  289. {
  290.         /* For now, nothing... */
  291. }
  292. #ifdef CONFIG_SMP
  293. EXPORT_SYMBOL(__global_cli);
  294. EXPORT_SYMBOL(__global_sti);
  295. EXPORT_SYMBOL(__global_save_flags);
  296. EXPORT_SYMBOL(__global_restore_flags);
  297. EXPORT_SYMBOL(global_irq_holder);
  298. EXPORT_SYMBOL(global_irq_lock);
  299. EXPORT_SYMBOL(global_irq_count);
  300. EXPORT_SYMBOL(global_bh_count);
  301. #endif
  302. EXPORT_SYMBOL(global_bh_lock);