original files of m241
This commit is contained in:
@@ -0,0 +1,561 @@
|
||||
/* loApicIntr.c - Intel Pentium[234] Local APIC/xAPIC driver */
|
||||
|
||||
/*
|
||||
* Copyright 1984-2008 Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01p,27aug08,jpb Renamed VSB header file
|
||||
01o,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
||||
for kernel configurations options set in vsb.
|
||||
01n,15mar07,scm correct mask in loApicIpi...
|
||||
01m,07dec06,scm smp:adjust loApicIpi for shorthand support...
|
||||
01l,15nov06,scm adjust loApicIpi for shortHand delivery...
|
||||
01k,13oct06,scm AP work...
|
||||
01j,09oct06,scm remove sysBp dependencey for SMP...
|
||||
01i,06sep06,scm debug for SMP...
|
||||
01h,26jul06,scm update for pentium/xeon support...
|
||||
01g,01apr04,dmh add support for multiple APICs
|
||||
01f,15may02,hdn changed apicId 8 bit to 16 bit, added DBG_MSG.
|
||||
added Error Status Register checking
|
||||
01e,08mar02,hdn updated loApicInit() and loApicIpi()
|
||||
added loApicEnable() for HTT (spr 73738)
|
||||
01d,29nov01,hdn doc update for 5.5
|
||||
01c,21jun01,hdn added support for Pentium4 Local xAPIC
|
||||
moved show routines to loApicIntrShow.c
|
||||
01b,25mar98,hdn re-written.
|
||||
01a,20jun97,sub written.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module is a driver for the local APIC/xAPIC (Advanced Programmable
|
||||
Interrupt Controller) in P6 (PentiumPro, II, III) family processors
|
||||
and P7 (Pentium4) family processors. The local APIC/xAPIC is included
|
||||
in selected P6 (PentiumPro, II, III) and P7 (Pentium4) family processors.
|
||||
Beginning with the P6 family processors, the presence or absence of an
|
||||
on-chip local APIC can be detected using the CPUID instruction. When the
|
||||
CPUID instruction is executed, bit 9 of the feature flags returned in the
|
||||
EDX register indicates the presence (set) or absence (clear) of an on-chip
|
||||
local APIC.
|
||||
|
||||
The local APIC performs two main functions for the processor:
|
||||
- It processes local external interrupts that the processor receives at its
|
||||
interrupt pins and local internal interrupts that software generates.
|
||||
- In multiple-processor systems, it communicates with an external IO APIC
|
||||
chip. The external IO APIC receives external interrupt events from the
|
||||
system and interprocessor interrupts from the processors on the system bus
|
||||
and distributes them to the processors on the system bus. The IO APIC is
|
||||
part of Intel's system chip set.
|
||||
The local APIC controls the dispatching of interrupts (to its associated
|
||||
processor) that it receives either locally or from the IO APIC. It provides
|
||||
facilities for queuing, nesting and masking of interrupts. It handles the
|
||||
interrupt delivery protocol with its local processor and accesses to APIC
|
||||
registers, and also manages interprocessor interrupts and remote APIC register
|
||||
reads. A timer on the local APIC allows local generation of interrupts, and
|
||||
local interrupt pins permit local reception of processor-specific interrupts.
|
||||
The local APIC can be disabled and used in conjunction with a standard 8259A
|
||||
style interrupt controller. Disabling the local APIC can be done in hardware
|
||||
for the Pentium processors or in software for the P6 and P7 (Pentium4) family
|
||||
processors.
|
||||
|
||||
The local APIC in the Pentium4 processors (called the xAPIC) is an extension
|
||||
of the local APIC found in the P6 family processors. The primary difference
|
||||
between the APIC architecture and xAPIC architecture is that with Pentium4
|
||||
processors, the local xAPICs and IO xAPIC communicate with one another through
|
||||
the processors system bus; whereas, with the P6 family processors, communication
|
||||
between the local APICs and the IO APIC is handled through a dedicated 3-wire
|
||||
APIC bus. Also, some of the architectural features of the local APIC have been
|
||||
extended and/or modified in the local xAPIC.
|
||||
|
||||
The base address of the local APIC and IO APIC is taken from the MP configuration
|
||||
table (see Intel MP Specification Version 1.4) or the IA32_APIC_BASE MSR.
|
||||
It uses LOAPIC_BASE and IOAPIC_INDEX_BASE defined in the BSP, if it is not able
|
||||
to find the addresses. This driver contains three routines for use. They are:
|
||||
loApicInit() initializes the Local APIC for the interrupt mode chosen.
|
||||
loApicEnable() enables or disables the Local APIC.
|
||||
loApicIpi() delivers the inter processor interrupt to the specified local APIC.
|
||||
|
||||
Local APIC is used in the Virtual Wire Mode (define VIRTUAL_WIRE_MODE in the
|
||||
BSP) and the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP), but not
|
||||
in the PIC Mode which is the default interrupt mode and uses 8259A PIC.
|
||||
|
||||
Virtual Wire Mode is one of three interrupt modes defined by the MP
|
||||
specification. In this mode, interrupts are generated by the 8259A equivalent
|
||||
PICs, but delivered to the Boot Strap Processor by the local APIC that is
|
||||
programmed to act as a "virtual Wire"; that is, the local APIC is logically
|
||||
indistinguishable from a hardware connection. This is a uniprocessor
|
||||
compatibility mode.
|
||||
|
||||
Symmetric IO Mode is one of three interrupt modes defined by the MP
|
||||
specification. In this mode, the local and IO APICs are fully functional,
|
||||
and interrupts are generated and delivered to the processors by the APICs.
|
||||
Any interrupt can be delivered to any processor. This is the only
|
||||
multiprocessor interrupt mode.
|
||||
The local and IO APICs support interrupts in the range of 32 to 255.
|
||||
Interrupt priority is implied by its vector, according to the following
|
||||
relationship: "priority = vector / 16".
|
||||
Here the quotient is rounded down to the nearest integer value to determine
|
||||
the priority, with 1 being the lowest and 15 is the highest. Because vectors
|
||||
0 through 31 are reserved for exclusive use by the processor, the priority of
|
||||
user defined interrupts range from 2 to 15. A value of 15 in the Interrupt
|
||||
Class field of the Task Priority Register (TPR) will mask off all interrupts,
|
||||
which require interrupt service.
|
||||
The P6 family processor's local APIC includes an in-service entry and a holding
|
||||
entry for each priority level. To avoid losing interrupts, software should
|
||||
allocate no more than 2 interrupt vectors per priority. The Pentium4 processor
|
||||
expands this support of all acceptance of two interrupts per vector rather than
|
||||
per priority level.
|
||||
|
||||
INCLUDE FILES: loApic.h
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include "drv/intrCtl/loApic.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#undef LOAPIC_DBG
|
||||
|
||||
#ifdef LOAPIC_DBG
|
||||
# define LOAPIC_DBG_MSG(STR,VALUE) logMsg(STR,VALUE,0,0,0,0,0);
|
||||
#else
|
||||
# define LOAPIC_DBG_MSG(STR,VALUE)
|
||||
#endif /* IPI_DEBUG */
|
||||
|
||||
|
||||
/* externs */
|
||||
|
||||
IMPORT CPUID sysCpuId; /* CPUID structure */
|
||||
IMPORT UINT sysProcessor; /* CPU family */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
|
||||
/* globals */
|
||||
|
||||
UINT32 loApicBase = LOAPIC_BASE; /* def Local APIC addr */
|
||||
UINT32 loApicId; /* local APIC Id */
|
||||
UINT32 loApicVersion; /* local APIC Version */
|
||||
UINT32 loApicMaxLvt; /* local APIC Max LVT */
|
||||
UINT32 loApicBusy = 0; /* counter for not sending IPI */
|
||||
|
||||
/* locals */
|
||||
|
||||
LOCAL UINT32 sysIntMaskLocalApic = 0;
|
||||
LOCAL UINT32 loApicOldSvr = 0; /* original SVR */
|
||||
LOCAL UINT32 loApicOldLint0 = 0; /* original LINT0 */
|
||||
LOCAL UINT32 loApicOldLint1 = 0; /* original LINT1 */
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
LOCAL void loApicIntEoi (INT32 irq);
|
||||
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
IMPORT int sysCpuNumGet (); /* define in sysLib.c of BSP */
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicInit - initialize the Local APIC or xAPIC
|
||||
*
|
||||
* This routine initializes Local APIC or xAPIC.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
*/
|
||||
|
||||
void loApicInit (void)
|
||||
{
|
||||
UINT32 apicBase[2];
|
||||
|
||||
/* override loApicBase, sysBp from MSR if available */
|
||||
|
||||
if (sysCpuId.featuresEdx & CPUID_APIC)
|
||||
{
|
||||
pentiumMsrGet (IA32_APIC_BASE, (long long int *)&apicBase);
|
||||
loApicBase = apicBase[0] & LOAPIC_BASE_MASK; /* override */
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
sysBp = apicBase[0] & LOAPIC_BSP ? TRUE : FALSE; /* override */
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
|
||||
/* enable the Local APIC explicitly */
|
||||
|
||||
apicBase[0] |= LOAPIC_GLOBAL_ENABLE; /* set E(nable) bit */
|
||||
pentiumMsrSet (IA32_APIC_BASE, (long long int *)&apicBase);
|
||||
}
|
||||
|
||||
/* remember the original state : SVR, LINT0, LINT1 for now */
|
||||
|
||||
loApicOldSvr = *(int *)(loApicBase + LOAPIC_SVR);
|
||||
loApicOldLint0 = *(int *)(loApicBase + LOAPIC_LINT0);
|
||||
loApicOldLint1 = *(int *)(loApicBase + LOAPIC_LINT1);
|
||||
|
||||
/* enable the Local APIC */
|
||||
|
||||
loApicEnable (TRUE);
|
||||
*(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_FOCUS_DISABLE |
|
||||
INT_NUM_LOAPIC_SPURIOUS;
|
||||
|
||||
/* get the Local APIC ID from Local APIC ID register */
|
||||
|
||||
loApicId = (*(int *)(loApicBase + LOAPIC_ID) & LOAPIC_ID_MASK) >> 24;
|
||||
|
||||
/* get the Local APIC Version from Local APIC Version register */
|
||||
|
||||
loApicVersion = *(int *)(loApicBase + LOAPIC_VER) & LOAPIC_VERSION_MASK;
|
||||
loApicMaxLvt = (*(int *)(loApicBase + LOAPIC_VER) & LOAPIC_MAXLVT_MASK)
|
||||
>> 16;
|
||||
|
||||
/* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_DFR) = (int)0xffffffff;
|
||||
*(int *)(loApicBase + LOAPIC_TPR) = (int)0x0;
|
||||
*(int *)(loApicBase + LOAPIC_TIMER_CONFIG) = (int)0x0;
|
||||
*(int *)(loApicBase + LOAPIC_TIMER_ICR) = (int)0x0;
|
||||
|
||||
#if defined(VIRTUAL_WIRE_MODE)
|
||||
|
||||
/* program Local Vector Table for the Virtual Wire Mode */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
if (sysBp)
|
||||
#else
|
||||
if (sysCpuNumGet() == 0)
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
{
|
||||
/* set LINT0: extInt, high-polarity, edge-trigger, not-masked */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) =
|
||||
(*(int *)(loApicBase + LOAPIC_LINT0) &
|
||||
~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
|
||||
(LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE);
|
||||
|
||||
/* set LINT1: NMI, high-polarity, edge-trigger, not-masked */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) =
|
||||
(*(int *)(loApicBase + LOAPIC_LINT1) &
|
||||
~(LOAPIC_MODE | LOAPIC_LOW | LOAPIC_LEVEL | LOAPIC_MASK)) |
|
||||
(LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
|
||||
}
|
||||
|
||||
#elif defined(SYMMETRIC_IO_MODE)
|
||||
|
||||
/* program Local Vector Table for the Symmetric IO Mode */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) = LOAPIC_MASK;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) = LOAPIC_MASK;
|
||||
|
||||
#endif /* defined(VIRTUAL_WIRE_MODE) */
|
||||
|
||||
/* lock the Local APIC interrupts */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_TIMER) = LOAPIC_MASK;
|
||||
*(int *)(loApicBase + LOAPIC_ERROR) = LOAPIC_MASK;
|
||||
|
||||
if (loApicMaxLvt >= LOAPIC_LVT_P6)
|
||||
*(int *)(loApicBase + LOAPIC_PMC) = LOAPIC_MASK;
|
||||
|
||||
if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4)
|
||||
*(int *)(loApicBase + LOAPIC_THERMAL) = LOAPIC_MASK;
|
||||
|
||||
/* discard a pending interrupt if any */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_EOI) = 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicEnable - enable or disable the Local xAPIC
|
||||
*
|
||||
* This routine enables or disables the Local xAPIC. If the parameter is TRUE,
|
||||
* the Local xAPIC is enabled. If the parameter is FALSE, the Local xAPIC
|
||||
* is disabled.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void loApicEnable
|
||||
(
|
||||
BOOL enable /* enable the Local xAPIC */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel;
|
||||
BOOL loApicImcr = FALSE; /* TRUE if IMCR exist (MP Table) */
|
||||
MP_FPS *pFps = mpApicFps;
|
||||
|
||||
/* check if the IMCR exists or not */
|
||||
|
||||
loApicImcr = (pFps->featureByte[1] & 0x80) ? TRUE : FALSE;
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
|
||||
/* enable or disable the Local APIC */
|
||||
|
||||
if (enable)
|
||||
{
|
||||
/* if the original mode is PIC mode, enable the Local APIC */
|
||||
|
||||
if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
|
||||
{
|
||||
*(int *)(loApicBase + LOAPIC_SVR) |= LOAPIC_ENABLE;
|
||||
}
|
||||
|
||||
#if defined (SYMMETRIC_IO_MODE)
|
||||
|
||||
/* switch to SYMMETRIC_IO mode from PIC/VIRTUAL_WIRE mode */
|
||||
|
||||
if (loApicImcr)
|
||||
{
|
||||
sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
|
||||
sysOutByte (IMCR_DATA, IMCR_IOAPIC_ON);
|
||||
}
|
||||
|
||||
#endif /* defined (SYMMETRIC_IO_MODE) */
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#if defined (SYMMETRIC_IO_MODE)
|
||||
|
||||
/* switch from SYMMETRIC_IO mode to PIC/VIRTUAL_WIRE mode */
|
||||
|
||||
if (loApicImcr)
|
||||
{
|
||||
sysOutByte (IMCR_ADRS, IMCR_REG_SEL);
|
||||
sysOutByte (IMCR_DATA, IMCR_IOAPIC_OFF);
|
||||
}
|
||||
|
||||
#endif /* defined (SYMMETRIC_IO_MODE) */
|
||||
|
||||
/* if the original mode is PIC mode, disable the Local APIC */
|
||||
|
||||
if ((loApicOldSvr & LOAPIC_ENABLE) == 0)
|
||||
{
|
||||
*(int *)(loApicBase + LOAPIC_SVR) &= ~LOAPIC_ENABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* restore the original value */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_SVR) = loApicOldSvr;
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) = loApicOldLint0;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) = loApicOldLint1;
|
||||
}
|
||||
}
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicIntLock - lock out all Local APIC interrupts
|
||||
*
|
||||
* This routine locks out all Local APIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: loApicIntUnlock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL void loApicIntLock (void)
|
||||
{
|
||||
|
||||
if (!(*(int *)(loApicBase + LOAPIC_TIMER) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_TIMER;
|
||||
*(int *)(loApicBase + LOAPIC_TIMER) |= LOAPIC_MASK;
|
||||
}
|
||||
if (!(*(int *)(loApicBase + LOAPIC_LINT0) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_LINT0;
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) |= LOAPIC_MASK;
|
||||
}
|
||||
if (!(*(int *)(loApicBase + LOAPIC_LINT1) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_LINT1;
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) |= LOAPIC_MASK;
|
||||
}
|
||||
if (!(*(int *)(loApicBase + LOAPIC_ERROR) & LOAPIC_MASK))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_ERROR;
|
||||
*(int *)(loApicBase + LOAPIC_ERROR) |= LOAPIC_MASK;
|
||||
}
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_P6) &&
|
||||
(!(*(int *)(loApicBase + LOAPIC_PMC) & LOAPIC_MASK)))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_PMC;
|
||||
*(int *)(loApicBase + LOAPIC_PMC) |= LOAPIC_MASK;
|
||||
}
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) &&
|
||||
(!(*(int *)(loApicBase + LOAPIC_THERMAL) & LOAPIC_MASK)))
|
||||
{
|
||||
sysIntMaskLocalApic |= LOCKED_THERMAL;
|
||||
*(int *)(loApicBase + LOAPIC_THERMAL) |= LOAPIC_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicIntUnlock - unlock the Local APIC interrupts
|
||||
*
|
||||
* This routine unlocks the Local APIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: loApicIntLock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL void loApicIntUnlock (void)
|
||||
{
|
||||
|
||||
if (sysIntMaskLocalApic & LOCKED_TIMER)
|
||||
*(int *)(loApicBase + LOAPIC_TIMER) &= ~LOAPIC_MASK;
|
||||
if (sysIntMaskLocalApic & LOCKED_LINT0)
|
||||
*(int *)(loApicBase + LOAPIC_LINT0) &= ~LOAPIC_MASK;
|
||||
if (sysIntMaskLocalApic & LOCKED_LINT1)
|
||||
*(int *)(loApicBase + LOAPIC_LINT1) &= ~LOAPIC_MASK;
|
||||
if (sysIntMaskLocalApic & LOCKED_ERROR)
|
||||
*(int *)(loApicBase + LOAPIC_ERROR) &= ~LOAPIC_MASK;
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_P6) &&
|
||||
(sysIntMaskLocalApic & LOCKED_PMC))
|
||||
*(int *)(loApicBase + LOAPIC_PMC) &= ~LOAPIC_MASK;
|
||||
if ((loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) &&
|
||||
(sysIntMaskLocalApic & LOCKED_THERMAL))
|
||||
*(int *)(loApicBase + LOAPIC_THERMAL) &= ~LOAPIC_MASK;
|
||||
|
||||
sysIntMaskLocalApic = 0; /* reset the flags */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* loApicIntEoi - send EOI (End Of Interrupt) signal to Local APIC
|
||||
*
|
||||
* This routine sends an EOI signal to the Local APIC's interrupting source.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void loApicIntEoi
|
||||
(
|
||||
INT32 irqNo /* INIIN number to send EOI */
|
||||
)
|
||||
{
|
||||
#ifdef SYS_INT_DEBUG
|
||||
extern UINT32 sysIntCount [];
|
||||
sysIntCount [irqNo]++;
|
||||
#endif /* SYS_INT_DEBUG */
|
||||
|
||||
*(int *)(loApicBase + LOAPIC_EOI) = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* loApicIpi - generate a Inter Processor Interrupt
|
||||
*
|
||||
* This routine delivers an Inter-Processor interrupt to the specified CPU
|
||||
* in the specified mode, with the specified vectorNo. Level should always
|
||||
* be 1 except INIT De-assert mode.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if the delivery status is not idle
|
||||
*/
|
||||
|
||||
STATUS loApicIpi
|
||||
(
|
||||
INT32 apicId, /* APIC ID number to send the interrupt */
|
||||
INT32 shortHand, /* destination short hand */
|
||||
INT32 trigger, /* trigger mode. 0: edge or 1: level */
|
||||
INT32 level, /* level. 0: de-assert or 1: assert */
|
||||
INT32 destMode, /* destination mode. 0: physical or 1: logical */
|
||||
INT32 deliMode, /* delivery mode. 000: fixed ... 110: startup */
|
||||
INT32 vectorNo /* vector number */
|
||||
)
|
||||
{
|
||||
UINT32 icrHi = (*(int *)(loApicBase + LOAPIC_ICRHI)) & 0x00ffffff;
|
||||
UINT32 icrLo = (*(int *)(loApicBase + LOAPIC_ICRLO)) & 0xfff32000;
|
||||
|
||||
/* ShortHand, Trigger, Level, DeliveryMode and Vector */
|
||||
|
||||
icrLo |= ((shortHand << 18) & 0xc0000) |
|
||||
((trigger << 15) & 0x8000) |
|
||||
((level << 14) & 0x4000) |
|
||||
((destMode << 11) & 0x800) |
|
||||
((deliMode << 8) & 0x700) |
|
||||
(vectorNo & 0xff);
|
||||
|
||||
/* Destination Apic Id */
|
||||
|
||||
icrHi |= (apicId << 24) & 0xff000000;
|
||||
|
||||
/* is the interrupt idle? */
|
||||
|
||||
if (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
|
||||
{
|
||||
loApicBusy++;
|
||||
LOAPIC_DBG_MSG ("ipi: LOAPIC busy 0x%x\n",
|
||||
*(int *)(loApicBase + LOAPIC_ESR))
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
/* reset the error status register */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
*(int *)(loApicBase + LOAPIC_ESR) = 0;
|
||||
*(int *)(loApicBase + LOAPIC_ESR) = 0;
|
||||
#endif /* !_WRS_CONFIG_SMP */
|
||||
|
||||
if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
|
||||
{
|
||||
LOAPIC_DBG_MSG ("ipi: 0. ESR=0x%x\n",
|
||||
*(int *)(loApicBase + LOAPIC_ESR))
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
/* Send it! */
|
||||
|
||||
#ifdef _WRS_CONFIG_SMP
|
||||
/* Can send shorthand message by performing a single
|
||||
* 32-bit memory write to the low half of the ICR.
|
||||
*/
|
||||
if ((shortHand == 0x00) || (destMode == 0x01))
|
||||
*(int *)(loApicBase + LOAPIC_ICRHI) = icrHi;
|
||||
#else
|
||||
*(int *)(loApicBase + LOAPIC_ICRHI) = icrHi;
|
||||
#endif
|
||||
*(int *)(loApicBase + LOAPIC_ICRLO) = icrLo;
|
||||
|
||||
/* Wait till interrupt is sent */
|
||||
|
||||
while (*(int *)(loApicBase + LOAPIC_ICRLO) & STATUS_PEND)
|
||||
if (*(int *)(loApicBase + LOAPIC_ESR) != 0)
|
||||
{
|
||||
LOAPIC_DBG_MSG ("ipi: 1. ESR=0x%x\n",
|
||||
*(int *)(loApicBase + LOAPIC_ESR))
|
||||
return (ERROR);
|
||||
}
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user