ItLpQueue.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:4k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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. cmpi 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=%dn", nextLpEvent->xType );
  134. ItLpQueue_clearValid( nextLpEvent );
  135. }
  136. else  /* No more valid events
  137.  * If overflow events are pending
  138.  * process them
  139.  */
  140. if ( lpQueue->xPlicOverflowIntPending ) {
  141. HvCallEvent_getOverflowLpEvents( 
  142. lpQueue->xIndex);
  143. }
  144. else /* If nothing left then we are done */
  145. break;
  146. }
  147. ItLpQueueInProcess = 0;
  148. mb();
  149. clear_inUse( lpQueue );
  150. get_paca()->lpEvent_count += numIntsProcessed;
  151. return numIntsProcessed;
  152. }