692 lines
21 KiB
C
692 lines
21 KiB
C
/* 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);
|
|
}
|