ItLpQueue.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * ItLpQueue.c
  3. * Copyright (C) 2001 Mike Corrigan IBM Corporation
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. */
  10. #include <linux/stddef.h>
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include <asm/system.h>
  14. #include <asm/paca.h>
  15. #include <asm/iSeries/ItLpQueue.h>
  16. #include <asm/iSeries/HvLpEvent.h>
  17. #include <asm/iSeries/HvCallEvent.h>
  18. static __inline__ int set_inUse( struct ItLpQueue * lpQueue )
  19. {
  20. int t;
  21. u32 * inUseP = &(lpQueue->xInUseWord);
  22. __asm__ __volatile__("\n\
  23. 1: lwarx %0,0,%2 \n\
  24. cmpwi 0,%0,0 \n\
  25. li %0,0 \n\
  26. bne- 2f \n\
  27. addi %0,%0,1 \n\
  28. stwcx. %0,0,%2 \n\
  29. bne- 1b \n\
  30. 2: eieio"
  31. : "=&r" (t), "=m" (lpQueue->xInUseWord)
  32. : "r" (inUseP), "m" (lpQueue->xInUseWord)
  33. : "cc");
  34. return t;
  35. }
  36. static __inline__ void clear_inUse( struct ItLpQueue * lpQueue )
  37. {
  38. lpQueue->xInUseWord = 0;
  39. }
  40. /* Array of LpEvent handler functions */
  41. extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
  42. unsigned long ItLpQueueInProcess = 0;
  43. struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue )
  44. {
  45. struct HvLpEvent * nextLpEvent =
  46. (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
  47. if ( nextLpEvent->xFlags.xValid ) {
  48. /* rmb() needed only for weakly consistent machines (regatta) */
  49. rmb();
  50. /* Set pointer to next potential event */
  51. lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
  52. LpEventAlign ) /
  53. LpEventAlign ) *
  54. LpEventAlign;
  55. /* Wrap to beginning if no room at end */
  56. if (lpQueue->xSlicCurEventPtr > lpQueue->xSlicLastValidEventPtr)
  57. lpQueue->xSlicCurEventPtr = lpQueue->xSlicEventStackPtr;
  58. }
  59. else
  60. nextLpEvent = NULL;
  61. return nextLpEvent;
  62. }
  63. int ItLpQueue_isLpIntPending( struct ItLpQueue * lpQueue )
  64. {
  65. int retval = 0;
  66. struct HvLpEvent * nextLpEvent;
  67. if ( lpQueue ) {
  68. nextLpEvent = (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
  69. retval = nextLpEvent->xFlags.xValid | lpQueue->xPlicOverflowIntPending;
  70. }
  71. return retval;
  72. }
  73. void ItLpQueue_clearValid( struct HvLpEvent * event )
  74. {
  75. /* Clear the valid bit of the event
  76. * Also clear bits within this event that might
  77. * look like valid bits (on 64-byte boundaries)
  78. */
  79. unsigned extra = (( event->xSizeMinus1 + LpEventAlign ) /
  80. LpEventAlign ) - 1;
  81. switch ( extra ) {
  82. case 3:
  83. ((struct HvLpEvent*)((char*)event+3*LpEventAlign))->xFlags.xValid=0;
  84. case 2:
  85. ((struct HvLpEvent*)((char*)event+2*LpEventAlign))->xFlags.xValid=0;
  86. case 1:
  87. ((struct HvLpEvent*)((char*)event+1*LpEventAlign))->xFlags.xValid=0;
  88. case 0:
  89. ;
  90. }
  91. mb();
  92. event->xFlags.xValid = 0;
  93. }
  94. unsigned ItLpQueue_process( struct ItLpQueue * lpQueue, struct pt_regs *regs )
  95. {
  96. unsigned numIntsProcessed = 0;
  97. struct HvLpEvent * nextLpEvent;
  98. /* If we have recursed, just return */
  99. if ( !set_inUse( lpQueue ) )
  100. return 0;
  101. if (ItLpQueueInProcess == 0)
  102. ItLpQueueInProcess = 1;
  103. else
  104. BUG();
  105. for (;;) {
  106. nextLpEvent = ItLpQueue_getNextLpEvent( lpQueue );
  107. if ( nextLpEvent ) {
  108. /* Count events to return to caller
  109. * and count processed events in lpQueue
  110. */
  111. ++numIntsProcessed;
  112. lpQueue->xLpIntCount++;
  113. /* Call appropriate handler here, passing
  114. * a pointer to the LpEvent. The handler
  115. * must make a copy of the LpEvent if it
  116. * needs it in a bottom half. (perhaps for
  117. * an ACK)
  118. *
  119. * Handlers are responsible for ACK processing
  120. *
  121. * The Hypervisor guarantees that LpEvents will
  122. * only be delivered with types that we have
  123. * registered for, so no type check is necessary
  124. * here!
  125. */
  126. if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes )
  127. lpQueue->xLpIntCountByType[nextLpEvent->xType]++;
  128. if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes &&
  129. lpEventHandler[nextLpEvent->xType] )
  130. lpEventHandler[nextLpEvent->xType](nextLpEvent, regs);
  131. else
  132. printk(KERN_INFO "Unexpected Lp Event type=%d\n", nextLpEvent->xType );
  133. ItLpQueue_clearValid( nextLpEvent );
  134. } else if ( lpQueue->xPlicOverflowIntPending )
  135. /*
  136. * No more valid events. If overflow events are
  137. * pending process them
  138. */
  139. HvCallEvent_getOverflowLpEvents( lpQueue->xIndex);
  140. else
  141. break;
  142. }
  143. ItLpQueueInProcess = 0;
  144. mb();
  145. clear_inUse( lpQueue );
  146. get_paca()->lpevent_count += numIntsProcessed;
  147. return numIntsProcessed;
  148. }