ItLpQueue.c 4.4 KB

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