airq.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * drivers/s390/cio/airq.c
  3. * Support for adapter interruptions
  4. *
  5. * Copyright IBM Corp. 1999,2007
  6. * Author(s): Ingo Adlung <adlung@de.ibm.com>
  7. * Cornelia Huck <cornelia.huck@de.ibm.com>
  8. * Arnd Bergmann <arndb@de.ibm.com>
  9. * Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  10. */
  11. #include <linux/init.h>
  12. #include <linux/module.h>
  13. #include <linux/slab.h>
  14. #include <linux/rcupdate.h>
  15. #include <asm/airq.h>
  16. #include "cio.h"
  17. #include "cio_debug.h"
  18. #define NR_AIRQS 32
  19. #define NR_AIRQS_PER_WORD sizeof(unsigned long)
  20. #define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD)
  21. union indicator_t {
  22. unsigned long word[NR_AIRQ_WORDS];
  23. unsigned char byte[NR_AIRQS];
  24. } __attribute__((packed));
  25. struct airq_t {
  26. adapter_int_handler_t handler;
  27. void *drv_data;
  28. };
  29. static union indicator_t indicators;
  30. static struct airq_t *airqs[NR_AIRQS];
  31. static int register_airq(struct airq_t *airq)
  32. {
  33. int i;
  34. for (i = 0; i < NR_AIRQS; i++)
  35. if (!cmpxchg(&airqs[i], NULL, airq))
  36. return i;
  37. return -ENOMEM;
  38. }
  39. /**
  40. * s390_register_adapter_interrupt() - register adapter interrupt handler
  41. * @handler: adapter handler to be registered
  42. * @drv_data: driver data passed with each call to the handler
  43. *
  44. * Returns:
  45. * Pointer to the indicator to be used on success
  46. * ERR_PTR() if registration failed
  47. */
  48. void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
  49. void *drv_data)
  50. {
  51. struct airq_t *airq;
  52. char dbf_txt[16];
  53. int ret;
  54. airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
  55. if (!airq) {
  56. ret = -ENOMEM;
  57. goto out;
  58. }
  59. airq->handler = handler;
  60. airq->drv_data = drv_data;
  61. ret = register_airq(airq);
  62. if (ret < 0)
  63. kfree(airq);
  64. out:
  65. snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
  66. CIO_TRACE_EVENT(4, dbf_txt);
  67. if (ret < 0)
  68. return ERR_PTR(ret);
  69. else
  70. return &indicators.byte[ret];
  71. }
  72. EXPORT_SYMBOL(s390_register_adapter_interrupt);
  73. /**
  74. * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
  75. * @ind: indicator for which the handler is to be unregistered
  76. */
  77. void s390_unregister_adapter_interrupt(void *ind)
  78. {
  79. struct airq_t *airq;
  80. char dbf_txt[16];
  81. int i;
  82. i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]);
  83. snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
  84. CIO_TRACE_EVENT(4, dbf_txt);
  85. indicators.byte[i] = 0;
  86. airq = xchg(&airqs[i], NULL);
  87. /*
  88. * Allow interrupts to complete. This will ensure that the airq handle
  89. * is no longer referenced by any interrupt handler.
  90. */
  91. synchronize_sched();
  92. kfree(airq);
  93. }
  94. EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
  95. #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
  96. void do_adapter_IO(void)
  97. {
  98. int w;
  99. int i;
  100. unsigned long word;
  101. struct airq_t *airq;
  102. /*
  103. * Access indicator array in word-sized chunks to minimize storage
  104. * fetch operations.
  105. */
  106. for (w = 0; w < NR_AIRQ_WORDS; w++) {
  107. word = indicators.word[w];
  108. i = w * NR_AIRQS_PER_WORD;
  109. /*
  110. * Check bytes within word for active indicators.
  111. */
  112. while (word) {
  113. if (word & INDICATOR_MASK) {
  114. airq = airqs[i];
  115. if (likely(airq))
  116. airq->handler(&indicators.byte[i],
  117. airq->drv_data);
  118. else
  119. /*
  120. * Reset ill-behaved indicator.
  121. */
  122. indicators.byte[i] = 0;
  123. }
  124. word <<= 8;
  125. i++;
  126. }
  127. }
  128. }