original files of m241
This commit is contained in:
@@ -0,0 +1,691 @@
|
||||
/* ioApicIntr.c - Intel IO APIC/xAPIC driver */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1997-1998, 2000-2002, 2004, 2006-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
|
||||
--------------------
|
||||
01n,27aug08,jpb Renamed VSB header file
|
||||
01m,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
||||
for kernel configurations options set in vsb.
|
||||
01l,26apr07,dlk PCI interrupt temporary workaround for SMP --
|
||||
For VXBUS case, ioApicInit() allocates memory using
|
||||
hwMemAlloc().
|
||||
01k,09oct06,scm remove sysBp dependencey for SMP...
|
||||
01j,26jul06,scm update for pentium/xeon support...
|
||||
01i,18aug04,dmh parameter checking
|
||||
01h,01apr04,dmh add support for multiple APICs
|
||||
01g,08mar02,hdn updated ioApicInit(), added ioApicEnable()
|
||||
removed redTable, added ioApicRedS/G(HTT (spr 73738)
|
||||
01f,29nov01,hdn doc update for 5.5
|
||||
01e,07nov01,hdn updated the interrupt delivery type setting
|
||||
added new routine ioApicIrqMove ()
|
||||
01d,26jun01,hdn added support for Pentium4 IO xAPIC
|
||||
moved show routine to ioApicIntrShow.c
|
||||
01c,17nov00,mks importing loApicBase and loApicId for successful compilation,
|
||||
added redTablePtr and made redTableNumEnt global. SPR 35733.
|
||||
01b,25mar98,hdn re-written.
|
||||
01a,20jun97,sub written.
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This module is a driver for the IO APIC/xAPIC (Advanced Programmable
|
||||
Interrupt Controller) for P6 (PentiumPro, II, III) family processors
|
||||
and P7 (Pentium4) family processors. The IO APIC/xAPIC is included
|
||||
in the Intel's system chip set, such as ICH2. Software intervention
|
||||
may be required to enable the IO APIC/xAPIC in some chip sets.
|
||||
The 8259A interrupt controller is intended for use in a uni-processor
|
||||
system, IO APIC can be used in either a uni-processor or multi-processor
|
||||
system. The IO APIC handles interrupts very differently than the 8259A.
|
||||
Briefly, these differences are:
|
||||
- Method of Interrupt Transmission. The IO APIC transmits interrupts
|
||||
through a 3-wire bus and interrupts are handled without the need for
|
||||
the processor to run an interrupt acknowledge cycle.
|
||||
- Interrupt Priority. The priority of interrupts in the IO APIC is
|
||||
independent of the interrupt number. For example, interrupt 10 can
|
||||
be given a higher priority than interrupt 3.
|
||||
- More Interrupts. The IO APIC supports a total of 24 interrupts.
|
||||
|
||||
The IO APIC unit consists of a set of interrupt input signals, a 24-entry
|
||||
by 64-bit Interrupt Redirection Table, programmable registers, and a message
|
||||
unit for sending and receiving APIC messages over the APIC bus or the
|
||||
Front-Side (system) bus. IO devices inject interrupts into the system by
|
||||
asserting one of the interrupt lines to the IO APIC. The IO APIC selects the
|
||||
corresponding entry in the Redirection Table and uses the information in that
|
||||
entry to format an interrupt request message. Each entry in the Redirection
|
||||
Table can be individually programmed to indicate edge/level sensitive interrupt
|
||||
signals, the interrupt vector and priority, the destination processor, and how
|
||||
the processor is selected (statically and dynamically). The information in
|
||||
the table is used to transmit a message to other APIC units (via the APIC bus
|
||||
or the Front-Side (system) bus).
|
||||
IO APIC is used in the Symmetric IO Mode (define SYMMETRIC_IO_MODE in the BSP).
|
||||
The base address of IO APIC is determined in loApicInit() and stored in the
|
||||
global variable ioApicBase and ioApicData. ioApicInit() initializes the IO
|
||||
APIC with information stored in ioApicRed0_15 and ioApicRed16_23.
|
||||
The ioApicRed0_15 is the default lower 32 bit value of the redirection table
|
||||
entries for IRQ 0 to 15 that are edge triggered positive high, and
|
||||
the ioApicRed16_23 is for IRQ 16 to 23 that are level triggered positive low.
|
||||
ioApicRedSet() and ioApicRedGet() are used to access the redirection table.
|
||||
ioApicEnable() enables the IO APIC or xAPIC. ioApicIrqSet() set the specific
|
||||
IRQ to be delivered to the specific Local APIC.
|
||||
This implementation doesn't support multiple IO APIC configuration.
|
||||
|
||||
INCLUDE FILES: loApic.h, ioApic.h
|
||||
|
||||
SEE ALSO: loApicIntr.c
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
#include <vsbConfig.h>
|
||||
|
||||
#include "intLib.h"
|
||||
#include "drv/intrCtl/loApic.h"
|
||||
#include "drv/intrCtl/ioApic.h"
|
||||
|
||||
/* externs */
|
||||
|
||||
IMPORT UINT32 loApicBase; /* addr of Local APIC */
|
||||
IMPORT UINT32 loApicId; /* local APIC Id */
|
||||
IMPORT UINT32 sysProcessor; /* 0=386, 1=486, 2=P5, 4=P6, 5=P7 */
|
||||
IMPORT INT8 excCallTbl []; /* table of Calls in excALib.s */
|
||||
IMPORT INT32 sysCsInt; /* CS for interrupt */
|
||||
IMPORT VOIDFUNCPTR intEoiGet; /* function used in intConnect() for B/EOI */
|
||||
IMPORT UINT32 sysIntIdtType; /* IDT entry type */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
IMPORT BOOL sysBp; /* TRUE(default) for BP, FALSE for AP */
|
||||
#else
|
||||
IMPORT int sysCpuNumGet (); /* define in sysLib.c of BSP */
|
||||
#endif
|
||||
|
||||
IMPORT void sysPciIoApicEnable(); /* enable/disable the IO APIC */
|
||||
IMPORT void sysPciPirqEnable(); /* enable/disable the PCI PIRQ */
|
||||
|
||||
#ifdef INCLUDE_VXBUS
|
||||
IMPORT char * hwMemAlloc (int reqSize);
|
||||
#endif
|
||||
|
||||
/* globals */
|
||||
|
||||
const UINT32 ioApicRed0_15 = IOAPIC_EDGE | IOAPIC_HIGH | IOAPIC_FIXED;
|
||||
const UINT32 ioApicRed16_23 = IOAPIC_LEVEL | IOAPIC_LOW | IOAPIC_FIXED;
|
||||
|
||||
UINT32 ioApicVersion[MAX_IOAPICS]; /* IO APIC version register per APIC */
|
||||
UINT8 ioApicRedNum[MAX_IOAPICS]; /* IO APIC redirection table number per APIC */
|
||||
UINT32 ioApicRedEntries = 24;
|
||||
|
||||
/* locals */
|
||||
|
||||
LOCAL UINT32 * ioApicIntTable;
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
STATUS ioApicIrqMove (INT32 srcIrq, INT32 dstIrq); /* not published yet */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicInit - initialize the IO APIC or xAPIC
|
||||
*
|
||||
* This routine initializes the IO APIC or xAPIC.
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS ioApicInit (void)
|
||||
{
|
||||
INT32 ix,ioApicId;
|
||||
UINT32 ioApicBase,ioApicData;
|
||||
UINT32 entries = 0;
|
||||
|
||||
/* enable the IOAPIC */
|
||||
|
||||
if (MAX_IOAPICS < NUM_IOAPICS)
|
||||
return (ERROR);
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
if (sysBp)
|
||||
#else
|
||||
if (sysCpuNumGet() == 0)
|
||||
#endif
|
||||
ioApicEnable (TRUE);
|
||||
|
||||
|
||||
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
{
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
/* get the IOAPIC version */
|
||||
|
||||
ioApicVersion[ioApicId] = ioApicGet (ioApicBase, ioApicData, IOAPIC_VERS);
|
||||
|
||||
/* get a number of redirection table entries */
|
||||
ioApicRedNum[ioApicId] = ((ioApicVersion[ioApicId] & IOAPIC_MRE_MASK) >> 16) + 1;
|
||||
}
|
||||
|
||||
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
entries += ioApicRedNum[ioApicId];
|
||||
|
||||
ioApicRedEntries = entries;
|
||||
|
||||
/* allocate memory for saving the interrupt mask bit */
|
||||
|
||||
#if !defined (INCLUDE_VXBUS)
|
||||
|
||||
ioApicIntTable = (UINT32 *) memalign (_CACHE_ALIGN_SIZE, entries * sizeof (UINT32));
|
||||
|
||||
#else /* defined (INCLUDE_VXBUS) */
|
||||
|
||||
/* Note, hwMemAlloc() doesn't return on failure. */
|
||||
ioApicIntTable = (UINT32 *)
|
||||
hwMemAlloc (_CACHE_ALIGN_SIZE + entries * sizeof (UINT32));
|
||||
ioApicIntTable = (UINT32 *)(((UINT32)ioApicIntTable + _CACHE_ALIGN_SIZE - 1) &
|
||||
~(_CACHE_ALIGN_SIZE - 1));
|
||||
|
||||
#endif /* defined (INCLUDE_VXBUS) */
|
||||
|
||||
#ifndef _WRS_CONFIG_SMP
|
||||
if (sysBp == FALSE)
|
||||
#else
|
||||
if (sysCpuNumGet() != 0)
|
||||
#endif /* _WRS_CONFIG_SMP */
|
||||
return (OK);
|
||||
|
||||
for (ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
{
|
||||
int lastentry = 0;
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
entries = ioApicRedNum[ioApicId];
|
||||
|
||||
/* set the IOAPIC bus arbitration ID */
|
||||
|
||||
ioApicSet (ioApicBase, ioApicData, IOAPIC_ID,
|
||||
ioApicGet (ioApicBase, ioApicData, IOAPIC_ID));
|
||||
|
||||
/* set the int-delivery type to Front Side Bus, not APIC Serial Bus */
|
||||
|
||||
if (sysProcessor == X86CPU_PENTIUM4)
|
||||
ioApicSet (ioApicBase, ioApicData, IOAPIC_BOOT, IOAPIC_DT_FS);
|
||||
|
||||
/* initialize the redirection table for the first ioapic with the default values */
|
||||
if(ioApicId == 0)
|
||||
{
|
||||
for (ix = 0; ix < entries; ix++)
|
||||
{
|
||||
UINT32 lower32;
|
||||
UINT32 upper32 = (loApicId << 24);
|
||||
UINT32 vector = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | sysInumTbl[ix]);
|
||||
|
||||
if (ix < 16)
|
||||
lower32 = (ioApicRed0_15 | vector);
|
||||
else
|
||||
lower32 = (ioApicRed16_23 | vector);
|
||||
|
||||
ioApicRedSet (ix, upper32, lower32, ioApicId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (ix = 0; ix < entries; ix++)
|
||||
{
|
||||
UINT32 lower32, vector;
|
||||
UINT32 upper32 = (loApicId << 24);
|
||||
if(ix < NUM_REDIRECTION_ENTRIES(ioApicId))
|
||||
{
|
||||
vector = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | sysInumTbl[ix + IRQ_OFFSET(ioApicId)]);
|
||||
lower32 = (IOAPIC_INT_MASK | IOAPIC_PHYSICAL | ioApicRed16_23 | vector);
|
||||
}
|
||||
else
|
||||
lower32 = IOAPIC_INT_MASK;
|
||||
|
||||
ioApicRedSet (IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32, ioApicId);
|
||||
}
|
||||
}
|
||||
lastentry += entries;
|
||||
}
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicEnable - enable or disable the IO xAPIC in ICHx
|
||||
*
|
||||
* This routine enables or disables the IO xAPIC in ICHx. If the parameter is
|
||||
* TRUE, the IO xAPIC in ICHx is enabled and the default ISA IRQ routing
|
||||
* information is saved in the table. If the parameter is FALSE, the IO xAPIC
|
||||
* in ICHx is disabled.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void ioApicEnable
|
||||
(
|
||||
BOOL enable /* enable the IO xAPIC in ICHx */
|
||||
)
|
||||
{
|
||||
/* enables or disables the IO APIC */
|
||||
|
||||
sysPciIoApicEnable (enable);
|
||||
|
||||
/* enables or disables the PIRQ direct handling */
|
||||
|
||||
sysPciPirqEnable (enable);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntEoi - send EOI (End Of Interrupt) signal to IO APIC
|
||||
*
|
||||
* This routine sends an EOI signal to the IO APIC's interrupting source.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
LOCAL void ioApicIntEoi
|
||||
(
|
||||
INT32 irqNo /* INTIN number to send EOI */
|
||||
)
|
||||
{
|
||||
UINT32 ioApicId;
|
||||
#ifdef SYS_INT_DEBUG
|
||||
extern UINT32 sysIntCount [];
|
||||
sysIntCount [irqNo]++;
|
||||
#endif /* SYS_INT_DEBUG */
|
||||
for(ioApicId = 0; ioApicId < NUM_IOAPICS; ioApicId++)
|
||||
{
|
||||
|
||||
if (ioApicVersion[ioApicId] & IOAPIC_PRQ)
|
||||
{
|
||||
*(int *)(LID_TO_BASE(ioApicId) + IOAPIC_EOI) = INT_NUM_GET(irqNo);
|
||||
#ifdef SYS_INT_DEBUG
|
||||
/* do not log console interrupts */
|
||||
if(irqNo != (devParas[CONSOLE_TTY].intLevel))
|
||||
logMsg ("IRQ(%d), serviced by IOAPIC(%d), Vector(%x)\n",
|
||||
irqNo, 0, INT_NUM_GET(irqNo), 4,5,6);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*(int *)(loApicBase + LOAPIC_EOI) = 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntEnable - enable a specified APIC interrupt input line
|
||||
*
|
||||
* This routine enables a specified APIC interrupt input line.
|
||||
*
|
||||
* RETURNS: OK or ERROR if the interrupt input line number is invalid
|
||||
*
|
||||
* SEE ALSO: ioApicIntDisable()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
STATUS ioApicIntEnable
|
||||
(
|
||||
INT32 irqNo /* INTIN number to enable */
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase,ioApicData, ioApicId;
|
||||
UINT32 lower32, upper32;
|
||||
|
||||
ioApicId = irqNo / 24;
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
ioApicRedGet((INT32) (IRQ_TO_BIRQ(ioApicId, irqNo)), (INT32 *) &upper32,
|
||||
(INT32 *) &lower32, (INT32) ioApicId);
|
||||
upper32 = (loApicId << 24);
|
||||
|
||||
/* enable the interrupt */
|
||||
return ioApicRedSet(IRQ_TO_BIRQ(ioApicId, irqNo), upper32, lower32 & ~IOAPIC_INT_MASK, ioApicId);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntDisable - disable a specified APIC interrupt input line
|
||||
*
|
||||
* This routine disables a specified APIC interrupt input line.
|
||||
*
|
||||
* RETURNS: OK or ERROR if the interrupt input line number is invalid
|
||||
*
|
||||
* SEE ALSO: ioApicIntEnable()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL STATUS ioApicIntDisable
|
||||
(
|
||||
INT32 irqNo /* INTIN number to disable */
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase,ioApicData, ioApicId;
|
||||
UINT32 lower32, upper32;
|
||||
ioApicId = irqNo / 24;
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
ioApicRedGet((INT32) (IRQ_TO_BIRQ(ioApicId, irqNo)), (INT32 *) &upper32,
|
||||
(INT32 *) &lower32, (INT32) ioApicId);
|
||||
|
||||
/* disable the interrupt */
|
||||
return ioApicRedSet(IRQ_TO_BIRQ(ioApicId, irqNo), upper32, lower32 | IOAPIC_INT_MASK, ioApicId);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntLock - lock out all IO APIC interrupts
|
||||
*
|
||||
* This routine saves the mask and locks out all IO APIC interrupts.
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: ioApicIntUnlock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL VOID ioApicIntLock (void)
|
||||
|
||||
{
|
||||
INT32 ix;
|
||||
INT32 upper32;
|
||||
INT32 lower32;
|
||||
INT32 ioApicId = 0;
|
||||
|
||||
for (ix = 0; ix < 24; ix++)
|
||||
{
|
||||
ioApicRedGet (IRQ_TO_BIRQ(ioApicId, ix), &upper32, &lower32, ioApicId);
|
||||
|
||||
/* lock if the destination is my Local APIC and unlocked */
|
||||
|
||||
if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId) &&
|
||||
((lower32 & IOAPIC_INT_MASK) == 0))
|
||||
{
|
||||
ioApicRedSet(IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32 | IOAPIC_INT_MASK, ioApicId);
|
||||
ioApicIntTable[ix] = lower32; /* save the old state */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIntUnlock - unlock the IO APIC interrupts
|
||||
*
|
||||
* This routine restores the mask and unlocks the IO APIC interrupts
|
||||
* It should be called in the interrupt disable state(IF bit is 0).
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* SEE ALSO: ioApicIntLock()
|
||||
*
|
||||
* ARGSUSED0
|
||||
*/
|
||||
|
||||
LOCAL VOID ioApicIntUnlock (void)
|
||||
|
||||
{
|
||||
INT32 ix;
|
||||
INT32 upper32;
|
||||
INT32 lower32;
|
||||
INT32 ioApicId = 0;
|
||||
|
||||
for (ix = 0; ix < 24; ix++)
|
||||
{
|
||||
ioApicRedGet (IRQ_TO_BIRQ(ioApicId, ix), &upper32, &lower32, ioApicId);
|
||||
|
||||
/* unlock if the destination is my Local APIC and unlocked */
|
||||
|
||||
if ((((upper32 & IOAPIC_DESTINATION) >> 24) == loApicId)
|
||||
&& ((ioApicIntTable[ix] & IOAPIC_INT_MASK) == 0))
|
||||
{
|
||||
ioApicRedSet(IRQ_TO_BIRQ(ioApicId, ix), upper32, lower32 & ~IOAPIC_INT_MASK, ioApicId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicGet - get a value from the IO APIC register.
|
||||
*
|
||||
* This routine gets a value from the IO APIC register.
|
||||
*
|
||||
* RETURNS: A value of the IO APIC register.
|
||||
*/
|
||||
|
||||
INT32 ioApicGet
|
||||
(
|
||||
UINT32 index, /* IO register select (index) */
|
||||
UINT32 data, /* IO window (data) */
|
||||
INT32 offset /* offset to the register */
|
||||
)
|
||||
{
|
||||
INT32 value;
|
||||
INT32 oldLevel;
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
*(char *)index = (char)offset; /* select the register */
|
||||
value = *(int *)data; /* must be a 32bit read */
|
||||
intUnlock (oldLevel); /* UNLOCK */
|
||||
|
||||
return (value);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicSet - set a value into the IO APIC register.
|
||||
*
|
||||
* This routine sets a value into the IO APIC register.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*/
|
||||
|
||||
void ioApicSet
|
||||
(
|
||||
UINT32 index, /* IO register select (index) */
|
||||
UINT32 data, /* IO window (data) */
|
||||
INT32 offset, /* offset to the register */
|
||||
INT32 value /* value to set the register */
|
||||
)
|
||||
{
|
||||
INT32 oldLevel;
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPT */
|
||||
*(char *)index = (char)offset; /* select the register */
|
||||
*(int *)data = value; /* must be a 32bit write */
|
||||
intUnlock (oldLevel); /* UNLOCK */
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicRedGet - get a specified entry in the Redirection Table
|
||||
*
|
||||
* This routine gets a specified entry in the Redirection Table
|
||||
*
|
||||
* RETURNS: OK, or ERROR if intNum is out of range
|
||||
*/
|
||||
|
||||
STATUS ioApicRedGet
|
||||
(
|
||||
INT32 irq, /* index of the table */
|
||||
INT32 * pUpper32, /* upper 32 bit (MS LONG) */
|
||||
INT32 * pLower32, /* lower 32 bit (LS LONG) */
|
||||
INT32 ioApicId
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase,ioApicData;
|
||||
INT32 offset;
|
||||
|
||||
if (irq >= ioApicRedNum[ioApicId])
|
||||
return (ERROR);
|
||||
|
||||
offset = IOAPIC_REDTBL + (irq << 1);
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
|
||||
*pUpper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
|
||||
*pLower32 = ioApicGet (ioApicBase, ioApicData, offset);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicRedSet - set a specified entry in the Redirection Table
|
||||
*
|
||||
* This routine sets a specified entry in the Redirection Table
|
||||
*
|
||||
* RETURNS: OK, or ERROR if intNum is out of range
|
||||
*/
|
||||
|
||||
STATUS ioApicRedSet
|
||||
(
|
||||
INT32 irq, /* index of the table */
|
||||
INT32 upper32, /* upper 32 bit (MS LONG) */
|
||||
INT32 lower32, /* lower 32 bit (LS LONG) */
|
||||
INT32 ioApicId
|
||||
)
|
||||
{
|
||||
UINT32 ioApicBase, ioApicData;
|
||||
INT32 offset;
|
||||
|
||||
if (irq >= ioApicRedNum[ioApicId])
|
||||
return (ERROR);
|
||||
|
||||
ioApicBase = LID_TO_BASE(ioApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
offset = IOAPIC_REDTBL + (irq << 1);
|
||||
|
||||
ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
|
||||
ioApicSet (ioApicBase, ioApicData, offset, lower32);
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIrqMove - move interrupt handler from source IRQ to destination IRQ
|
||||
*
|
||||
* This routine moves the interrupt handler from the source IRQ to the
|
||||
* destination IRQ. If the source IRQ's interrupt handler is the default
|
||||
* handler, it just returns. Otherwise it is moved and the destination IRQ's
|
||||
* vector table entry will be overridden. This routine is for the chipset
|
||||
* that have programmable IRQ capability. This routine should be called at
|
||||
* the initialization time, otherwise there are no guarantee for losing
|
||||
* interrupts. The polarity and the trigger mode of the IRQ is not changed.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if the source intHandler is the default handler.
|
||||
*/
|
||||
|
||||
STATUS ioApicIrqMove
|
||||
(
|
||||
INT32 srcIrq, /* source IRQ moving from */
|
||||
INT32 dstIrq /* destination IRQ moving to */
|
||||
)
|
||||
{
|
||||
FUNCPTR intHandler; /* interrupt handler */
|
||||
INT32 idtType; /* IDT type */
|
||||
INT32 selector; /* code selector */
|
||||
INT32 srcInum = INT_NUM_GET (srcIrq);
|
||||
INT32 dstInum = INT_NUM_GET (dstIrq);
|
||||
INT8 * pCode; /* pointer to intConnect code */
|
||||
INT32 oldLevel;
|
||||
|
||||
/* lock interrupts */
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
ioApicIntDisable (srcIrq);
|
||||
ioApicIntDisable (dstIrq);
|
||||
|
||||
/* get the info from the source IRQ vector table entry */
|
||||
|
||||
intVecGet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum), &intHandler,
|
||||
&idtType, &selector);
|
||||
|
||||
/* return if the intHandler is the default handler */
|
||||
|
||||
if (intHandler == (FUNCPTR)&excCallTbl[srcInum * 5])
|
||||
return (ERROR);
|
||||
|
||||
/* set the info to the destination IRQ vector table entry */
|
||||
|
||||
intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (dstInum), intHandler,
|
||||
idtType, selector);
|
||||
|
||||
/* update the IRQ (parameter of EOI routine) in the intConnect code */
|
||||
|
||||
if (intEoiGet != NULL)
|
||||
{
|
||||
pCode = (INT8 *)intHandler;
|
||||
*(INT32 *)(pCode + ICC_EOI_PARAM) = dstIrq;
|
||||
}
|
||||
|
||||
/* set the default interrupt handler to the source IRQ */
|
||||
|
||||
intVecSet2 ((FUNCPTR *)INUM_TO_IVEC (srcInum),
|
||||
(FUNCPTR)&excCallTbl[srcInum * 5],
|
||||
sysIntIdtType, sysCsInt);
|
||||
|
||||
/* unlock interrupts */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
ioApicIntEnable (dstIrq);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ioApicIrqSet - set the Local APIC ID of the specified IRQ
|
||||
*
|
||||
* This routine sets the Local APIC ID of the specified IRQ in the IO APIC
|
||||
* Redirection Table.
|
||||
*
|
||||
* RETURNS: OK, or ERROR if the IRQ is out of bound
|
||||
*/
|
||||
|
||||
STATUS ioApicIrqSet
|
||||
(
|
||||
INT32 irq, /* IRQ */
|
||||
INT32 destApicId, /* Local APIC ID */
|
||||
INT32 sourceApicId
|
||||
)
|
||||
{
|
||||
INT32 upper32;
|
||||
INT32 oldLevel;
|
||||
UINT32 ioApicBase,ioApicData;
|
||||
INT32 offset = IOAPIC_REDTBL + (irq * 2);
|
||||
ioApicBase = LID_TO_BASE(sourceApicId);
|
||||
ioApicData = ioApicBase + IOAPIC_DATA;
|
||||
|
||||
if (irq >= ioApicRedNum[destApicId])
|
||||
return (ERROR);
|
||||
|
||||
/* lock interrupts */
|
||||
|
||||
oldLevel = intLock (); /* LOCK INTERRUPTS */
|
||||
ioApicIntDisable (irq);
|
||||
|
||||
/* set the loApicId */
|
||||
|
||||
upper32 = ioApicGet (ioApicBase, ioApicData, offset + 1);
|
||||
upper32 = (upper32 & ~IOAPIC_DESTINATION) | (destApicId << 24);
|
||||
ioApicSet (ioApicBase, ioApicData, offset + 1, upper32);
|
||||
|
||||
/* unlock interrupts */
|
||||
|
||||
intUnlock (oldLevel); /* UNLOCK INTERRUPTS */
|
||||
ioApicIntEnable (irq);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
Reference in New Issue
Block a user