airq.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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 <asm/isc.h>
  17. #include "cio.h"
  18. #include "cio_debug.h"
  19. #define NR_AIRQS 32
  20. #define NR_AIRQS_PER_WORD sizeof(unsigned long)
  21. #define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD)
  22. union indicator_t {
  23. unsigned long word[NR_AIRQ_WORDS];
  24. unsigned char byte[NR_AIRQS];
  25. } __attribute__((packed));
  26. struct airq_t {
  27. adapter_int_handler_t handler;
  28. void *drv_data;
  29. };
  30. static union indicator_t indicators[MAX_ISC+1];
  31. static struct airq_t *airqs[MAX_ISC+1][NR_AIRQS];
  32. static int register_airq(struct airq_t *airq, u8 isc)
  33. {
  34. int i;
  35. for (i = 0; i < NR_AIRQS; i++)
  36. if (!cmpxchg(&airqs[isc][i], NULL, airq))
  37. return i;
  38. return -ENOMEM;
  39. }
  40. /**
  41. * s390_register_adapter_interrupt() - register adapter interrupt handler
  42. * @handler: adapter handler to be registered
  43. * @drv_data: driver data passed with each call to the handler
  44. * @isc: isc for which the handler should be called
  45. *
  46. * Returns:
  47. * Pointer to the indicator to be used on success
  48. * ERR_PTR() if registration failed
  49. */
  50. void *s390_register_adapter_interrupt(adapter_int_handler_t handler,
  51. void *drv_data, u8 isc)
  52. {
  53. struct airq_t *airq;
  54. char dbf_txt[16];
  55. int ret;
  56. if (isc > MAX_ISC)
  57. return ERR_PTR(-EINVAL);
  58. airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL);
  59. if (!airq) {
  60. ret = -ENOMEM;
  61. goto out;
  62. }
  63. airq->handler = handler;
  64. airq->drv_data = drv_data;
  65. ret = register_airq(airq, isc);
  66. out:
  67. snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret);
  68. CIO_TRACE_EVENT(4, dbf_txt);
  69. if (ret < 0) {
  70. kfree(airq);
  71. return ERR_PTR(ret);
  72. } else
  73. return &indicators[isc].byte[ret];
  74. }
  75. EXPORT_SYMBOL(s390_register_adapter_interrupt);
  76. /**
  77. * s390_unregister_adapter_interrupt - unregister adapter interrupt handler
  78. * @ind: indicator for which the handler is to be unregistered
  79. * @isc: interruption subclass
  80. */
  81. void s390_unregister_adapter_interrupt(void *ind, u8 isc)
  82. {
  83. struct airq_t *airq;
  84. char dbf_txt[16];
  85. int i;
  86. i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]);
  87. snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i);
  88. CIO_TRACE_EVENT(4, dbf_txt);
  89. indicators[isc].byte[i] = 0;
  90. airq = xchg(&airqs[isc][i], NULL);
  91. /*
  92. * Allow interrupts to complete. This will ensure that the airq handle
  93. * is no longer referenced by any interrupt handler.
  94. */
  95. synchronize_sched();
  96. kfree(airq);
  97. }
  98. EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
  99. #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8))
  100. void do_adapter_IO(u8 isc)
  101. {
  102. int w;
  103. int i;
  104. unsigned long word;
  105. struct airq_t *airq;
  106. /*
  107. * Access indicator array in word-sized chunks to minimize storage
  108. * fetch operations.
  109. */
  110. for (w = 0; w < NR_AIRQ_WORDS; w++) {
  111. word = indicators[isc].word[w];
  112. i = w * NR_AIRQS_PER_WORD;
  113. /*
  114. * Check bytes within word for active indicators.
  115. */
  116. while (word) {
  117. if (word & INDICATOR_MASK) {
  118. airq = airqs[isc][i];
  119. /* Make sure gcc reads from airqs only once. */
  120. barrier();
  121. if (likely(airq))
  122. airq->handler(&indicators[isc].byte[i],
  123. airq->drv_data);
  124. else
  125. /*
  126. * Reset ill-behaved indicator.
  127. */
  128. indicators[isc].byte[i] = 0;
  129. }
  130. word <<= 8;
  131. i++;
  132. }
  133. }
  134. }