3 * Copyright (C) 2001 Mike Corrigan IBM Corporation
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.
11 #include <linux/stddef.h>
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <asm/system.h>
16 #include <asm/iSeries/ItLpQueue.h>
17 #include <asm/iSeries/HvLpEvent.h>
18 #include <asm/iSeries/HvCallEvent.h>
19 #include <asm/iSeries/LparData.h>
21 static __inline__
int set_inUse( struct ItLpQueue
* lpQueue
)
24 u32
* inUseP
= &(lpQueue
->xInUseWord
);
26 __asm__
__volatile__("\n\
35 : "=&r" (t
), "=m" (lpQueue
->xInUseWord
)
36 : "r" (inUseP
), "m" (lpQueue
->xInUseWord
)
42 static __inline__
void clear_inUse( struct ItLpQueue
* lpQueue
)
44 lpQueue
->xInUseWord
= 0;
47 /* Array of LpEvent handler functions */
48 extern LpEventHandler lpEventHandler
[HvLpEvent_Type_NumTypes
];
49 unsigned long ItLpQueueInProcess
= 0;
51 struct HvLpEvent
* ItLpQueue_getNextLpEvent( struct ItLpQueue
* lpQueue
)
53 struct HvLpEvent
* nextLpEvent
=
54 (struct HvLpEvent
*)lpQueue
->xSlicCurEventPtr
;
55 if ( nextLpEvent
->xFlags
.xValid
) {
56 /* rmb() needed only for weakly consistent machines (regatta) */
58 /* Set pointer to next potential event */
59 lpQueue
->xSlicCurEventPtr
+= ((nextLpEvent
->xSizeMinus1
+
63 /* Wrap to beginning if no room at end */
64 if (lpQueue
->xSlicCurEventPtr
> lpQueue
->xSlicLastValidEventPtr
)
65 lpQueue
->xSlicCurEventPtr
= lpQueue
->xSlicEventStackPtr
;
73 int ItLpQueue_isLpIntPending( struct ItLpQueue
* lpQueue
)
76 struct HvLpEvent
* nextLpEvent
;
78 nextLpEvent
= (struct HvLpEvent
*)lpQueue
->xSlicCurEventPtr
;
79 retval
= nextLpEvent
->xFlags
.xValid
| lpQueue
->xPlicOverflowIntPending
;
84 void ItLpQueue_clearValid( struct HvLpEvent
* event
)
86 /* Clear the valid bit of the event
87 * Also clear bits within this event that might
88 * look like valid bits (on 64-byte boundaries)
90 unsigned extra
= (( event
->xSizeMinus1
+ LpEventAlign
) /
94 ((struct HvLpEvent
*)((char*)event
+3*LpEventAlign
))->xFlags
.xValid
=0;
96 ((struct HvLpEvent
*)((char*)event
+2*LpEventAlign
))->xFlags
.xValid
=0;
98 ((struct HvLpEvent
*)((char*)event
+1*LpEventAlign
))->xFlags
.xValid
=0;
103 event
->xFlags
.xValid
= 0;
106 unsigned ItLpQueue_process( struct ItLpQueue
* lpQueue
, struct pt_regs
*regs
)
108 unsigned numIntsProcessed
= 0;
109 struct HvLpEvent
* nextLpEvent
;
111 /* If we have recursed, just return */
112 if ( !set_inUse( lpQueue
) )
115 if (ItLpQueueInProcess
== 0)
116 ItLpQueueInProcess
= 1;
121 nextLpEvent
= ItLpQueue_getNextLpEvent( lpQueue
);
123 /* Count events to return to caller
124 * and count processed events in lpQueue
127 lpQueue
->xLpIntCount
++;
128 /* Call appropriate handler here, passing
129 * a pointer to the LpEvent. The handler
130 * must make a copy of the LpEvent if it
131 * needs it in a bottom half. (perhaps for
134 * Handlers are responsible for ACK processing
136 * The Hypervisor guarantees that LpEvents will
137 * only be delivered with types that we have
138 * registered for, so no type check is necessary
141 if ( nextLpEvent
->xType
< HvLpEvent_Type_NumTypes
)
142 lpQueue
->xLpIntCountByType
[nextLpEvent
->xType
]++;
143 if ( nextLpEvent
->xType
< HvLpEvent_Type_NumTypes
&&
144 lpEventHandler
[nextLpEvent
->xType
] )
145 lpEventHandler
[nextLpEvent
->xType
](nextLpEvent
, regs
);
147 printk(KERN_INFO
"Unexpected Lp Event type=%d\n", nextLpEvent
->xType
);
149 ItLpQueue_clearValid( nextLpEvent
);
150 } else if ( lpQueue
->xPlicOverflowIntPending
)
152 * No more valid events. If overflow events are
153 * pending process them
155 HvCallEvent_getOverflowLpEvents( lpQueue
->xIndex
);
160 ItLpQueueInProcess
= 0;
162 clear_inUse( lpQueue
);
164 get_paca()->lpevent_count
+= numIntsProcessed
;
166 return numIntsProcessed
;