kernel-ark/arch/ppc64/kernel/ItLpQueue.c
Michael Ellerman 1b19bc7214 [PATCH] ppc64: Don't pass the pointers to xItLpQueue around
Because there's only one ItLpQueue and we know where it is, ie. xItLpQueue,
there's no point passing pointers to it it around all over the place.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
Acked-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2005-06-30 15:07:57 +10:00

189 lines
4.7 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(void)
{
int t;
u32 * inUseP = &xItLpQueue.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" (xItLpQueue.xInUseWord)
: "r" (inUseP), "m" (xItLpQueue.xInUseWord)
: "cc");
return t;
}
static __inline__ void clear_inUse(void)
{
xItLpQueue.xInUseWord = 0;
}
/* Array of LpEvent handler functions */
extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
unsigned long ItLpQueueInProcess = 0;
struct HvLpEvent * ItLpQueue_getNextLpEvent(void)
{
struct HvLpEvent * nextLpEvent =
(struct HvLpEvent *)xItLpQueue.xSlicCurEventPtr;
if ( nextLpEvent->xFlags.xValid ) {
/* rmb() needed only for weakly consistent machines (regatta) */
rmb();
/* Set pointer to next potential event */
xItLpQueue.xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
LpEventAlign ) /
LpEventAlign ) *
LpEventAlign;
/* Wrap to beginning if no room at end */
if (xItLpQueue.xSlicCurEventPtr > xItLpQueue.xSlicLastValidEventPtr)
xItLpQueue.xSlicCurEventPtr = xItLpQueue.xSlicEventStackPtr;
}
else
nextLpEvent = NULL;
return nextLpEvent;
}
static unsigned long spread_lpevents = NR_CPUS;
int ItLpQueue_isLpIntPending(void)
{
struct HvLpEvent *next_event;
if (smp_processor_id() >= spread_lpevents)
return 0;
next_event = (struct HvLpEvent *)xItLpQueue.xSlicCurEventPtr;
return next_event->xFlags.xValid | xItLpQueue.xPlicOverflowIntPending;
}
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 pt_regs *regs)
{
unsigned numIntsProcessed = 0;
struct HvLpEvent * nextLpEvent;
/* If we have recursed, just return */
if ( !set_inUse() )
return 0;
if (ItLpQueueInProcess == 0)
ItLpQueueInProcess = 1;
else
BUG();
for (;;) {
nextLpEvent = ItLpQueue_getNextLpEvent();
if ( nextLpEvent ) {
/* Count events to return to caller
* and count processed events in xItLpQueue
*/
++numIntsProcessed;
xItLpQueue.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 )
xItLpQueue.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 ( xItLpQueue.xPlicOverflowIntPending )
/*
* No more valid events. If overflow events are
* pending process them
*/
HvCallEvent_getOverflowLpEvents( xItLpQueue.xIndex);
else
break;
}
ItLpQueueInProcess = 0;
mb();
clear_inUse();
get_paca()->lpevent_count += numIntsProcessed;
return numIntsProcessed;
}
static int set_spread_lpevents(char *str)
{
unsigned long val = simple_strtoul(str, NULL, 0);
/*
* The parameter is the number of processors to share in processing
* lp events.
*/
if (( val > 0) && (val <= NR_CPUS)) {
spread_lpevents = val;
printk("lpevent processing spread over %ld processors\n", val);
} else {
printk("invalid spread_lpevents %ld\n", val);
}
return 1;
}
__setup("spread_lpevents=", set_spread_lpevents);