kick.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /*
  2. * Copyright (C) 2009 Imagination Technologies
  3. *
  4. * This file is subject to the terms and conditions of the GNU General Public
  5. * License. See the file COPYING in the main directory of this archive
  6. * for more details.
  7. *
  8. * The Meta KICK interrupt mechanism is generally a useful feature, so
  9. * we provide an interface for registering multiple interrupt
  10. * handlers. All the registered interrupt handlers are "chained". When
  11. * a KICK interrupt is received the first function in the list is
  12. * called. If that interrupt handler cannot handle the KICK the next
  13. * one is called, then the next until someone handles it (or we run
  14. * out of functions). As soon as one function handles the interrupt no
  15. * other handlers are called.
  16. *
  17. * The only downside of chaining interrupt handlers is that each
  18. * handler must be able to detect whether the KICK was intended for it
  19. * or not. For example, when the IPI handler runs and it sees that
  20. * there are no IPI messages it must not signal that the KICK was
  21. * handled, thereby giving the other handlers a chance to run.
  22. *
  23. * The reason that we provide our own interface for calling KICK
  24. * handlers instead of using the generic kernel infrastructure is that
  25. * the KICK handlers require access to a CPU's pTBI structure. So we
  26. * pass it as an argument.
  27. */
  28. #include <linux/export.h>
  29. #include <linux/hardirq.h>
  30. #include <linux/irq.h>
  31. #include <linux/kernel.h>
  32. #include <linux/mm.h>
  33. #include <linux/types.h>
  34. #include <asm/traps.h>
  35. /*
  36. * All accesses/manipulations of kick_handlers_list should be
  37. * performed while holding kick_handlers_lock.
  38. */
  39. static DEFINE_SPINLOCK(kick_handlers_lock);
  40. static LIST_HEAD(kick_handlers_list);
  41. void kick_register_func(struct kick_irq_handler *kh)
  42. {
  43. unsigned long flags;
  44. spin_lock_irqsave(&kick_handlers_lock, flags);
  45. list_add_tail(&kh->list, &kick_handlers_list);
  46. spin_unlock_irqrestore(&kick_handlers_lock, flags);
  47. }
  48. EXPORT_SYMBOL(kick_register_func);
  49. void kick_unregister_func(struct kick_irq_handler *kh)
  50. {
  51. unsigned long flags;
  52. spin_lock_irqsave(&kick_handlers_lock, flags);
  53. list_del(&kh->list);
  54. spin_unlock_irqrestore(&kick_handlers_lock, flags);
  55. }
  56. EXPORT_SYMBOL(kick_unregister_func);
  57. TBIRES
  58. kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
  59. {
  60. struct pt_regs *old_regs;
  61. struct kick_irq_handler *kh;
  62. struct list_head *lh;
  63. int handled = 0;
  64. TBIRES ret;
  65. head_end(State, ~INTS_OFF_MASK);
  66. /* If we interrupted user code handle any critical sections. */
  67. if (State.Sig.SaveMask & TBICTX_PRIV_BIT)
  68. restart_critical_section(State);
  69. trace_hardirqs_off();
  70. old_regs = set_irq_regs((struct pt_regs *)State.Sig.pCtx);
  71. irq_enter();
  72. /*
  73. * There is no need to disable interrupts here because we
  74. * can't nest KICK interrupts in a KICK interrupt handler.
  75. */
  76. spin_lock(&kick_handlers_lock);
  77. list_for_each(lh, &kick_handlers_list) {
  78. kh = list_entry(lh, struct kick_irq_handler, list);
  79. ret = kh->func(State, SigNum, Triggers, Inst, pTBI, &handled);
  80. if (handled)
  81. break;
  82. }
  83. spin_unlock(&kick_handlers_lock);
  84. WARN_ON(!handled);
  85. irq_exit();
  86. set_irq_regs(old_regs);
  87. return tail_end(ret);
  88. }