itlpqueue.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 179 行
C
179 行
/* * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/sched.h>#include <asm/system.h>#include <asm/iSeries/ItLpQueue.h>#include <asm/iSeries/HvLpEvent.h>#include <asm/iSeries/HvCallEvent.h>#include <asm/iSeries/LparData.h>static __inline__ int set_inUse( struct ItLpQueue * lpQueue ){ int t; u32 * inUseP = &(lpQueue->xInUseWord); __asm__ __volatile__("\n\1: lwarx %0,0,%2 \n\ cmpi 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 functionsextern 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 ) { // 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 ){ struct HvLpEvent * nextLpEvent = (struct HvLpEvent *)lpQueue->xSlicCurEventPtr; return ( nextLpEvent->xFlags.xValid | lpQueue->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;}// No lock is necessary when processing the Lp Queue because a single// processor is assigned to each lpqueue. Interrupts are disabled// while processing events.// Some device drivers' interrupt handlers run with interrupts // enabled. This requires us to prevent being re-entered here.// We use the xInUse flag for that.unsigned lpQueue_proc_count[32] = {};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(); ++lpQueue_proc_count[current->processor]; 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 // No more valid events // If overflow events are pending // process them if ( lpQueue->xPlicOverflowIntPending ) { HvCallEvent_getOverflowLpEvents( lpQueue->xIndex); } else // If nothing left then we are done break; } ItLpQueueInProcess = 0; mb(); clear_inUse( lpQueue ); return numIntsProcessed;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?