irq_smp.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/arch/alpha/kernel/irq_smp.c
  3.  *
  4.  */
  5. #include <linux/kernel.h>
  6. #include <linux/signal.h>
  7. #include <linux/sched.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/random.h>
  10. #include <linux/init.h>
  11. #include <linux/delay.h>
  12. #include <linux/irq.h>
  13. #include <asm/system.h>
  14. #include <asm/io.h>
  15. /* Who has global_irq_lock. */
  16. int global_irq_holder = NO_PROC_ID;
  17. /* This protects IRQ's. */
  18. spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
  19. /* Global IRQ locking depth. */
  20. static void *previous_irqholder = NULL;
  21. #define MAXCOUNT 100000000
  22. static void
  23. show(char * str, void *where)
  24. {
  25. #if 0
  26. int i;
  27.         unsigned long *stack;
  28. #endif
  29.         int cpu = smp_processor_id();
  30.         printk("n%s, CPU %d: %pn", str, cpu, where);
  31.         printk("irq:  %d [%d %d]n",
  32.        irqs_running(),
  33.                local_irq_count(0),
  34.                local_irq_count(1));
  35.         printk("bh:   %d [%d %d]n",
  36.        spin_is_locked(&global_bh_lock) ? 1 : 0,
  37.        local_bh_count(0),
  38.        local_bh_count(1));
  39. #if 0
  40.         stack = (unsigned long *) &str;
  41.         for (i = 40; i ; i--) {
  42. unsigned long x = *++stack;
  43.                 if (x > (unsigned long) &init_task_union &&
  44.     x < (unsigned long) &vsprintf) {
  45. printk("<[%08lx]> ", x);
  46.                 }
  47.         }
  48. #endif
  49. }
  50. static inline void
  51. wait_on_irq(int cpu, void *where)
  52. {
  53. int count = MAXCOUNT;
  54. for (;;) {
  55. /*
  56.  * Wait until all interrupts are gone. Wait
  57.  * for bottom half handlers unless we're
  58.  * already executing in one..
  59.  */
  60. if (!irqs_running()) {
  61. if (local_bh_count(cpu)
  62.     || !spin_is_locked(&global_bh_lock))
  63. break;
  64. }
  65. /* Duh, we have to loop. Release the lock to avoid deadlocks */
  66. spin_unlock(&global_irq_lock);
  67. for (;;) {
  68. if (!--count) {
  69. show("wait_on_irq", where);
  70. count = MAXCOUNT;
  71. }
  72. __sti();
  73. udelay(1); /* make sure to run pending irqs */
  74. __cli();
  75. if (irqs_running())
  76. continue;
  77. if (spin_is_locked(&global_irq_lock))
  78. continue;
  79. if (!local_bh_count(cpu)
  80.     && spin_is_locked(&global_bh_lock))
  81. continue;
  82. if (spin_trylock(&global_irq_lock))
  83. break;
  84. }
  85. }
  86. }
  87. static inline void
  88. get_irqlock(int cpu, void* where)
  89. {
  90. if (!spin_trylock(&global_irq_lock)) {
  91. /* Do we already hold the lock?  */
  92. if (cpu == global_irq_holder)
  93. return;
  94. /* Uhhuh.. Somebody else got it.  Wait.  */
  95. spin_lock(&global_irq_lock);
  96. }
  97. /*
  98.  * Ok, we got the lock bit.
  99.  * But that's actually just the easy part.. Now
  100.  * we need to make sure that nobody else is running
  101.  * in an interrupt context. 
  102.  */
  103. wait_on_irq(cpu, where);
  104. /*
  105.  * Finally.
  106.  */
  107. #ifdef CONFIG_DEBUG_SPINLOCK
  108. global_irq_lock.task = current;
  109. global_irq_lock.previous = where;
  110. #endif
  111. global_irq_holder = cpu;
  112. previous_irqholder = where;
  113. }
  114. void
  115. __global_cli(void)
  116. {
  117. int cpu = smp_processor_id();
  118. void *where = __builtin_return_address(0);
  119. /*
  120.  * Maximize ipl.  If ipl was previously 0 and if this thread
  121.  * is not in an irq, then take global_irq_lock.
  122.  */
  123. if (swpipl(IPL_MAX) == IPL_MIN && !local_irq_count(cpu))
  124. get_irqlock(cpu, where);
  125. }
  126. void
  127. __global_sti(void)
  128. {
  129.         int cpu = smp_processor_id();
  130.         if (!local_irq_count(cpu))
  131. release_irqlock(cpu);
  132. __sti();
  133. }
  134. /*
  135.  * SMP flags value to restore to:
  136.  * 0 - global cli
  137.  * 1 - global sti
  138.  * 2 - local cli
  139.  * 3 - local sti
  140.  */
  141. unsigned long
  142. __global_save_flags(void)
  143. {
  144.         int retval;
  145.         int local_enabled;
  146.         unsigned long flags;
  147. int cpu = smp_processor_id();
  148.         __save_flags(flags);
  149.         local_enabled = (!(flags & 7));
  150.         /* default to local */
  151.         retval = 2 + local_enabled;
  152.         /* Check for global flags if we're not in an interrupt.  */
  153.         if (!local_irq_count(cpu)) {
  154.                 if (local_enabled)
  155.                         retval = 1;
  156.                 if (global_irq_holder == cpu)
  157.                         retval = 0;
  158. }
  159. return retval;
  160. }
  161. void
  162. __global_restore_flags(unsigned long flags)
  163. {
  164.         switch (flags) {
  165.         case 0:
  166.                 __global_cli();
  167.                 break;
  168.         case 1:
  169.                 __global_sti();
  170.                 break;
  171.         case 2:
  172.                 __cli();
  173.                 break;
  174.         case 3:
  175.                 __sti();
  176.                 break;
  177.         default:
  178.                 printk(KERN_ERR "global_restore_flags: %08lx (%p)n",
  179.                         flags, __builtin_return_address(0));
  180.         }
  181. }
  182. /*
  183.  * From its use, I infer that synchronize_irq() stalls a thread until
  184.  * the effects of a command to an external device are known to have
  185.  * taken hold.  Typically, the command is to stop sending interrupts.
  186.  * The strategy here is wait until there is at most one processor
  187.  * (this one) in an irq.  The memory barrier serializes the write to
  188.  * the device and the subsequent accesses of global_irq_count.
  189.  * --jmartin
  190.  */
  191. #define DEBUG_SYNCHRONIZE_IRQ 0
  192. void
  193. synchronize_irq(void)
  194. {
  195. #if 0
  196. /* Joe's version.  */
  197. int cpu = smp_processor_id();
  198. int local_count;
  199. int global_count;
  200. int countdown = 1<<24;
  201. void *where = __builtin_return_address(0);
  202. mb();
  203. do {
  204. local_count = local_irq_count(cpu);
  205. global_count = atomic_read(&global_irq_count);
  206. if (DEBUG_SYNCHRONIZE_IRQ && (--countdown == 0)) {
  207. printk("%d:%d/%dn", cpu, local_count, global_count);
  208. show("synchronize_irq", where);
  209. break;
  210. }
  211. } while (global_count != local_count);
  212. #else
  213. /* Jay's version.  */
  214. if (irqs_running()) {
  215. cli();
  216. sti();
  217. }
  218. #endif
  219. }