kernel-ark/arch/ppc64/kernel/ItLpQueue.c
Stephen Rothwell 0bc0ffd5f0 [PATCH] ppc64 iSeries: remove LparData.h
include/asm-ppc64/iSeries/LparData.h just included a whole lot of other files
to declare variables that would be better declared in those other files.  So,
remove it.  This will reduce that number of things needed to be included in
most cases to access the relevant variables.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-06-21 18:46:27 -07:00

167 lines
4.4 KiB
C

/*
* ItLpQueue.c
* Copyright (C) 2001 Mike Corrigan IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/system.h>
#include <asm/paca.h>
#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/HvCallEvent.h>
static __inline__ int set_inUse( struct ItLpQueue * lpQueue )
{
int t;
u32 * inUseP = &(lpQueue->xInUseWord);
__asm__ __volatile__("\n\
1: lwarx %0,0,%2 \n\
cmpwi 0,%0,0 \n\
li %0,0 \n\
bne- 2f \n\
addi %0,%0,1 \n\
stwcx. %0,0,%2 \n\
bne- 1b \n\
2: eieio"
: "=&r" (t), "=m" (lpQueue->xInUseWord)
: "r" (inUseP), "m" (lpQueue->xInUseWord)
: "cc");
return t;
}
static __inline__ void clear_inUse( struct ItLpQueue * lpQueue )
{
lpQueue->xInUseWord = 0;
}
/* Array of LpEvent handler functions */
extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
unsigned long ItLpQueueInProcess = 0;
struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue )
{
struct HvLpEvent * nextLpEvent =
(struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
if ( nextLpEvent->xFlags.xValid ) {
/* rmb() needed only for weakly consistent machines (regatta) */
rmb();
/* Set pointer to next potential event */
lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
LpEventAlign ) /
LpEventAlign ) *
LpEventAlign;
/* Wrap to beginning if no room at end */
if (lpQueue->xSlicCurEventPtr > lpQueue->xSlicLastValidEventPtr)
lpQueue->xSlicCurEventPtr = lpQueue->xSlicEventStackPtr;
}
else
nextLpEvent = NULL;
return nextLpEvent;
}
int ItLpQueue_isLpIntPending( struct ItLpQueue * lpQueue )
{
int retval = 0;
struct HvLpEvent * nextLpEvent;
if ( lpQueue ) {
nextLpEvent = (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
retval = nextLpEvent->xFlags.xValid | lpQueue->xPlicOverflowIntPending;
}
return retval;
}
void ItLpQueue_clearValid( struct HvLpEvent * event )
{
/* Clear the valid bit of the event
* Also clear bits within this event that might
* look like valid bits (on 64-byte boundaries)
*/
unsigned extra = (( event->xSizeMinus1 + LpEventAlign ) /
LpEventAlign ) - 1;
switch ( extra ) {
case 3:
((struct HvLpEvent*)((char*)event+3*LpEventAlign))->xFlags.xValid=0;
case 2:
((struct HvLpEvent*)((char*)event+2*LpEventAlign))->xFlags.xValid=0;
case 1:
((struct HvLpEvent*)((char*)event+1*LpEventAlign))->xFlags.xValid=0;
case 0:
;
}
mb();
event->xFlags.xValid = 0;
}
unsigned ItLpQueue_process( struct ItLpQueue * lpQueue, struct pt_regs *regs )
{
unsigned numIntsProcessed = 0;
struct HvLpEvent * nextLpEvent;
/* If we have recursed, just return */
if ( !set_inUse( lpQueue ) )
return 0;
if (ItLpQueueInProcess == 0)
ItLpQueueInProcess = 1;
else
BUG();
for (;;) {
nextLpEvent = ItLpQueue_getNextLpEvent( lpQueue );
if ( nextLpEvent ) {
/* Count events to return to caller
* and count processed events in lpQueue
*/
++numIntsProcessed;
lpQueue->xLpIntCount++;
/* Call appropriate handler here, passing
* a pointer to the LpEvent. The handler
* must make a copy of the LpEvent if it
* needs it in a bottom half. (perhaps for
* an ACK)
*
* Handlers are responsible for ACK processing
*
* The Hypervisor guarantees that LpEvents will
* only be delivered with types that we have
* registered for, so no type check is necessary
* here!
*/
if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes )
lpQueue->xLpIntCountByType[nextLpEvent->xType]++;
if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes &&
lpEventHandler[nextLpEvent->xType] )
lpEventHandler[nextLpEvent->xType](nextLpEvent, regs);
else
printk(KERN_INFO "Unexpected Lp Event type=%d\n", nextLpEvent->xType );
ItLpQueue_clearValid( nextLpEvent );
} else if ( lpQueue->xPlicOverflowIntPending )
/*
* No more valid events. If overflow events are
* pending process them
*/
HvCallEvent_getOverflowLpEvents( lpQueue->xIndex);
else
break;
}
ItLpQueueInProcess = 0;
mb();
clear_inUse( lpQueue );
get_paca()->lpevent_count += numIntsProcessed;
return numIntsProcessed;
}