URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/rtems/c/src/lib/libbsp/powerpc/shared/irq
- from Rev 30 to Rev 173
- ↔ Reverse comparison
Rev 30 → Rev 173
/irq_init.c
0,0 → 1,303
/* irq_init.c |
* |
* This file contains the implementation of rtems initialization |
* related to interrupt handling. |
* |
* CopyRight (C) 1999 valette@crf.canon.fr |
* |
* Enhanced by Jay Kulpinski <jskulpin@eng01.gdds.com> |
* to make it valid for MVME2300 Motorola boards. |
* |
* The license and distribution terms for this file may be |
* found in the file LICENSE in this distribution or at |
* http://www.OARcorp.com/rtems/license.html. |
* |
* $Id: irq_init.c,v 1.2 2001-09-27 12:01:06 chris Exp $ |
*/ |
#include <bsp/consoleIo.h> |
#include <libcpu/io.h> |
#include <libcpu/spr.h> |
#include <bsp/pci.h> |
#include <bsp/residual.h> |
#include <bsp/openpic.h> |
#include <bsp/irq.h> |
#include <bsp.h> |
#include <libcpu/raw_exception.h> |
#include <bsp/motorola.h> |
|
/* |
#define SHOW_ISA_PCI_BRIDGE_SETTINGS |
*/ |
|
typedef struct { |
unsigned char bus; /* few chance the PCI/ISA bridge is not on first bus but ... */ |
unsigned char device; |
unsigned char function; |
} pci_isa_bridge_device; |
|
pci_isa_bridge_device* via_82c586 = 0; |
static pci_isa_bridge_device bridge; |
|
extern unsigned int external_exception_vector_prolog_code_size; |
extern void external_exception_vector_prolog_code(); |
extern unsigned int decrementer_exception_vector_prolog_code_size; |
extern void decrementer_exception_vector_prolog_code(); |
|
/* |
* default on/off function |
*/ |
static void nop_func(){} |
/* |
* default isOn function |
*/ |
static int not_connected() {return 0;} |
/* |
* default possible isOn function |
*/ |
static int connected() {return 1;} |
|
static rtems_irq_connect_data rtemsIrq[BSP_IRQ_NUMBER]; |
static rtems_irq_global_settings initial_config; |
static rtems_irq_connect_data defaultIrq = { |
/* vectorIdex, hdl , on , off , isOn */ |
0, nop_func , nop_func , nop_func , not_connected |
}; |
static rtems_irq_prio irqPrioTable[BSP_IRQ_NUMBER]={ |
/* |
* actual rpiorities for interrupt : |
* 0 means that only current interrupt is masked |
* 255 means all other interrupts are masked |
*/ |
/* |
* ISA interrupts. |
* The second entry has a priority of 255 because |
* it is the slave pic entry and is should always remain |
* unmasked. |
*/ |
0,0, |
255, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
/* |
* PCI Interrupts |
*/ |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* for raven prio 0 means unactive... */ |
/* |
* Processor exceptions handled as interrupts |
*/ |
0 |
}; |
|
static unsigned char mcp750_openpic_initsenses[] = { |
1, /* MCP750_INT_PCB(8259) */ |
0, /* MCP750_INT_FALCON_ECC_ERR */ |
1, /* MCP750_INT_PCI_ETHERNET */ |
1, /* MCP750_INT_PCI_PMC */ |
1, /* MCP750_INT_PCI_WATCHDOG_TIMER1 */ |
1, /* MCP750_INT_PCI_PRST_SIGNAL */ |
1, /* MCP750_INT_PCI_FALL_SIGNAL */ |
1, /* MCP750_INT_PCI_DEG_SIGNAL */ |
1, /* MCP750_INT_PCI_BUS1_INTA */ |
1, /* MCP750_INT_PCI_BUS1_INTB */ |
1, /* MCP750_INT_PCI_BUS1_INTC */ |
1, /* MCP750_INT_PCI_BUS1_INTD */ |
1, /* MCP750_INT_PCI_BUS2_INTA */ |
1, /* MCP750_INT_PCI_BUS2_INTB */ |
1, /* MCP750_INT_PCI_BUS2_INTC */ |
1, /* MCP750_INT_PCI_BUS2_INTD */ |
}; |
|
void VIA_isa_bridge_interrupts_setup(void) |
{ |
pci_isa_bridge_device pci_dev; |
unsigned int temp; |
unsigned char tmp; |
unsigned char maxBus; |
unsigned found = 0; |
|
maxBus = BusCountPCI(); |
pci_dev.function = 0; /* Assumes the bidge is the first function */ |
|
for (pci_dev.bus = 0; pci_dev.bus < maxBus; pci_dev.bus++) { |
#ifdef SCAN_PCI_PRINT |
printk("isa_bridge_interrupts_setup: Scanning bus %d\n", pci_dev.bus); |
#endif |
for (pci_dev.device = 0; pci_dev.device < PCI_MAX_DEVICES; pci_dev.device++) { |
#ifdef SCAN_PCI_PRINT |
printk("isa_bridge_interrupts_setup: Scanning device %d\n", pci_dev.device); |
#endif |
pci_read_config_dword(pci_dev.bus, pci_dev.device, pci_dev.function, |
PCI_VENDOR_ID, &temp); |
#ifdef SCAN_PCI_PRINT |
printk("Vendor/device = %x\n", temp); |
#endif |
if ((temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_0 << 16))) |
) { |
bridge = pci_dev; |
via_82c586 = &bridge; |
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS |
/* |
* Should print : bus = 0, device = 11, function = 0 on a MCP750. |
*/ |
printk("Via PCI/ISA bridge found at bus = %d, device = %d, function = %d\n", |
via_82c586->bus, |
via_82c586->device, |
via_82c586->function); |
#endif |
found = 1; |
goto loop_exit; |
|
} |
} |
} |
loop_exit: |
if (!found) BSP_panic("VIA_82C586 PCI/ISA bridge not found!n"); |
|
tmp = inb(0x810); |
if ( !(tmp & 0x2)) { |
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS |
printk("This is a second generation MCP750 board\n"); |
printk("We must reprogram the PCI/ISA bridge...\n"); |
#endif |
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, |
0x47, &tmp); |
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS |
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp); |
#endif |
/* |
* Enable 4D0/4D1 ISA interrupt level/edge config registers |
*/ |
tmp |= 0x20; |
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, |
0x47, tmp); |
/* |
* Now program the ISA interrupt edge/level |
*/ |
tmp = ELCRS_INT9_LVL | ELCRS_INT10_LVL | ELCRS_INT11_LVL; |
outb(tmp, ISA8259_S_ELCR); |
tmp = ELCRM_INT5_LVL; |
outb(tmp, ISA8259_M_ELCR);; |
/* |
* Set the Interrupt inputs to non-inverting level interrupt |
*/ |
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, |
0x54, &tmp); |
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS |
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp); |
#endif |
tmp = 0; |
pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, |
0x54, tmp); |
} |
else { |
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS |
printk("This is a first generation MCP750 board\n"); |
printk("We just show the actual value used by PCI/ISA bridge\n"); |
#endif |
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, |
0x47, &tmp); |
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS |
printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp); |
#endif |
/* |
* Show the Interrupt inputs inverting/non-inverting level status |
*/ |
pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function, |
0x54, &tmp); |
#ifdef SHOW_ISA_PCI_BRIDGE_SETTINGS |
printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp); |
#endif |
} |
} |
|
/* |
* This code assumes the exceptions management setup has already |
* been done. We just need to replace the exceptions that will |
* be handled like interrupt. On mcp750/mpc750 and many PPC processors |
* this means the decrementer exception and the external exception. |
*/ |
void BSP_rtems_irq_mng_init(unsigned cpuId) |
{ |
rtems_raw_except_connect_data vectorDesc; |
int known_cpi_isa_bridge = 0; |
int i; |
|
/* |
* First initialize the Interrupt management hardware |
*/ |
OpenPIC_InitSenses = mcp750_openpic_initsenses; |
OpenPIC_NumInitSenses = sizeof(mcp750_openpic_initsenses) / sizeof(char); |
#ifdef TRACE_IRQ_INIT |
printk("Going to initialize raven interrupt controller (openpic compliant)\n"); |
#endif |
openpic_init(1); |
#ifdef TRACE_IRQ_INIT |
printk("Going to initialize the PCI/ISA bridge IRQ related setting (VIA 82C586)\n"); |
#endif |
if ( currentBoard == MESQUITE ) { |
VIA_isa_bridge_interrupts_setup(); |
known_cpi_isa_bridge = 1; |
} |
if ( currentBoard == MVME_2300 ) { |
/* nothing to do for W83C553 bridge */ |
known_cpi_isa_bridge = 1; |
} |
if (!known_cpi_isa_bridge) { |
printk("Please add code for PCI/ISA bridge init to libbsp/shared/irq/irq_init.c\n"); |
printk("If your card works correctly please add a test and set known_cpi_isa_bridge to true\n"); |
} |
#ifdef TRACE_IRQ_INIT |
printk("Going to initialize the ISA PC legacy IRQ management hardware\n"); |
#endif |
BSP_i8259s_init(); |
/* |
* Initialize Rtems management interrupt table |
*/ |
/* |
* re-init the rtemsIrq table |
*/ |
for (i = 0; i < BSP_IRQ_NUMBER; i++) { |
rtemsIrq[i] = defaultIrq; |
rtemsIrq[i].name = i; |
} |
/* |
* Init initial Interrupt management config |
*/ |
initial_config.irqNb = BSP_IRQ_NUMBER; |
initial_config.defaultEntry = defaultIrq; |
initial_config.irqHdlTbl = rtemsIrq; |
initial_config.irqBase = BSP_ASM_IRQ_VECTOR_BASE; |
initial_config.irqPrioTbl = irqPrioTable; |
|
if (!BSP_rtems_irq_mngt_set(&initial_config)) { |
/* |
* put something here that will show the failure... |
*/ |
BSP_panic("Unable to initialize RTEMS interrupt Management!!! System locked\n"); |
} |
|
/* |
* We must connect the raw irq handler for the two |
* expected interrupt sources : decrementer and external interrupts. |
*/ |
vectorDesc.exceptIndex = ASM_DEC_VECTOR; |
vectorDesc.hdl.vector = ASM_DEC_VECTOR; |
vectorDesc.hdl.raw_hdl = decrementer_exception_vector_prolog_code; |
vectorDesc.hdl.raw_hdl_size = (unsigned) &decrementer_exception_vector_prolog_code_size; |
vectorDesc.on = nop_func; |
vectorDesc.off = nop_func; |
vectorDesc.isOn = connected; |
if (!mpc60x_set_exception (&vectorDesc)) { |
BSP_panic("Unable to initialize RTEMS decrementer raw exception\n"); |
} |
vectorDesc.exceptIndex = ASM_EXT_VECTOR; |
vectorDesc.hdl.vector = ASM_EXT_VECTOR; |
vectorDesc.hdl.raw_hdl = external_exception_vector_prolog_code; |
vectorDesc.hdl.raw_hdl_size = (unsigned) &external_exception_vector_prolog_code_size; |
if (!mpc60x_set_exception (&vectorDesc)) { |
BSP_panic("Unable to initialize RTEMS external raw exception\n"); |
} |
#ifdef TRACE_IRQ_INIT |
printk("RTEMS IRQ management is now operationnal\n"); |
#endif |
} |
|
/i8259.c
0,0 → 1,152
|
/* |
* This file contains the implementation of the function described in irq.h |
* related to Intel 8259 Programmable Interrupt controller. |
* |
* Copyright (C) 1998, 1999 valette@crf.canon.fr |
* |
* The license and distribution terms for this file may be |
* found in found in the file LICENSE in this distribution or at |
* http://www.OARcorp.com/rtems/license.html. |
* |
* $Id: i8259.c,v 1.2 2001-09-27 12:01:06 chris Exp $ |
*/ |
|
#include <bsp.h> |
#include <bsp/irq.h> |
|
/*-------------------------------------------------------------------------+ |
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register. |
+--------------------------------------------------------------------------*/ |
/* |
* lower byte is interrupt mask on the master PIC. |
* while upper bits are interrupt on the slave PIC. |
*/ |
volatile rtems_i8259_masks i8259s_cache = 0xfffb; |
|
/*-------------------------------------------------------------------------+ |
| Function: BSP_irq_disable_at_i8259s |
| Description: Mask IRQ line in appropriate PIC chip. |
| Global Variables: i8259s_cache |
| Arguments: vector_offset - number of IRQ line to mask. |
| Returns: Nothing. |
+--------------------------------------------------------------------------*/ |
int BSP_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine) |
{ |
unsigned short mask; |
unsigned int level; |
|
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) || |
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET) |
) |
return 1; |
|
_CPU_ISR_Disable(level); |
|
mask = 1 << irqLine; |
i8259s_cache |= mask; |
|
if (irqLine < 8) |
{ |
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); |
} |
else |
{ |
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); |
} |
_CPU_ISR_Enable (level); |
|
return 0; |
} |
|
/*-------------------------------------------------------------------------+ |
| Function: BSP_irq_enable_at_i8259s |
| Description: Unmask IRQ line in appropriate PIC chip. |
| Global Variables: i8259s_cache |
| Arguments: irqLine - number of IRQ line to mask. |
| Returns: Nothing. |
+--------------------------------------------------------------------------*/ |
int BSP_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine) |
{ |
unsigned short mask; |
unsigned int level; |
|
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) || |
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET ) |
) |
return 1; |
|
_CPU_ISR_Disable(level); |
|
mask = ~(1 << irqLine); |
i8259s_cache &= mask; |
|
if (irqLine < 8) |
{ |
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); |
} |
else |
{ |
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); |
} |
_CPU_ISR_Enable (level); |
|
return 0; |
} /* mask_irq */ |
|
int BSP_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine) |
{ |
unsigned short mask; |
|
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) || |
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET) |
) |
return 1; |
|
mask = (1 << irqLine); |
return (~(i8259s_cache & mask)); |
} |
|
|
/*-------------------------------------------------------------------------+ |
| Function: BSP_irq_ack_at_i8259s |
| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC. |
| Global Variables: None. |
| Arguments: irqLine - number of IRQ line to acknowledge. |
| Returns: Nothing. |
+--------------------------------------------------------------------------*/ |
int BSP_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine) |
{ |
if (irqLine >= 8) { |
outport_byte(PIC_MASTER_COMMAND_IO_PORT, SLAVE_PIC_EOSI); |
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, (PIC_EOSI | (irqLine - 8))); |
} |
else { |
outport_byte(PIC_MASTER_COMMAND_IO_PORT, (PIC_EOSI | irqLine)); |
} |
|
return 0; |
|
} /* ackIRQ */ |
|
void BSP_i8259s_init(void) |
{ |
/* |
* init master 8259 interrupt controller |
*/ |
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */ |
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */ |
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x04);/* edge tiggered, Cascade (slave) on IRQ2 */ |
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x01);/* Select 8086 mode */ |
outport_byte(PIC_MASTER_IMR_IO_PORT, 0xFB); /* Mask all except cascade */ |
/* |
* init slave interrupt controller |
*/ |
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, 0x11); /* Start init sequence */ |
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x08);/* Vector base = 8 */ |
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x02);/* edge triggered, Cascade (slave) on IRQ2 */ |
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0x01); /* Select 8086 mode */ |
outport_byte(PIC_SLAVE_IMR_IO_PORT, 0xFF); /* Mask all */ |
|
} |
|
/irq.h
0,0 → 1,319
/* irq.h |
* |
* This include file describe the data structure and the functions implemented |
* by rtems to write interrupt handlers. |
* |
* CopyRight (C) 1999 valette@crf.canon.fr |
* |
* This code is heavilly inspired by the public specification of STREAM V2 |
* that can be found at : |
* |
* <http://www.chorus.com/Documentation/index.html> by following |
* the STREAM API Specification Document link. |
* |
* The license and distribution terms for this file may be |
* found in found in the file LICENSE in this distribution or at |
* http://www.OARcorp.com/rtems/license.html. |
* |
* $Id: irq.h,v 1.2 2001-09-27 12:01:06 chris Exp $ |
*/ |
|
#ifndef LIBBSP_POWERPC_MCP750_IRQ_IRQ_H |
#define LIBBSP_POWERPC_MCP750_IRQ_IRQ_H |
|
|
/* |
* 8259 edge/level control definitions at VIA |
*/ |
#define ISA8259_M_ELCR 0x4d0 |
#define ISA8259_S_ELCR 0x4d1 |
|
#define ELCRS_INT15_LVL 0x80 |
#define ELCRS_INT14_LVL 0x40 |
#define ELCRS_INT13_LVL 0x20 |
#define ELCRS_INT12_LVL 0x10 |
#define ELCRS_INT11_LVL 0x08 |
#define ELCRS_INT10_LVL 0x04 |
#define ELCRS_INT9_LVL 0x02 |
#define ELCRS_INT8_LVL 0x01 |
#define ELCRM_INT7_LVL 0x80 |
#define ELCRM_INT6_LVL 0x40 |
#define ELCRM_INT5_LVL 0x20 |
#define ELCRM_INT4_LVL 0x10 |
#define ELCRM_INT3_LVL 0x8 |
#define ELCRM_INT2_LVL 0x4 |
#define ELCRM_INT1_LVL 0x2 |
#define ELCRM_INT0_LVL 0x1 |
|
#define BSP_ASM_IRQ_VECTOR_BASE 0x0 |
/* PIC's command and mask registers */ |
#define PIC_MASTER_COMMAND_IO_PORT 0x20 /* Master PIC command register */ |
#define PIC_SLAVE_COMMAND_IO_PORT 0xa0 /* Slave PIC command register */ |
#define PIC_MASTER_IMR_IO_PORT 0x21 /* Master PIC Interrupt Mask Register */ |
#define PIC_SLAVE_IMR_IO_PORT 0xa1 /* Slave PIC Interrupt Mask Register */ |
|
/* Command for specific EOI (End Of Interrupt): Interrupt acknowledge */ |
#define PIC_EOSI 0x60 /* End of Specific Interrupt (EOSI) */ |
#define SLAVE_PIC_EOSI 0x62 /* End of Specific Interrupt (EOSI) for cascade */ |
#define PIC_EOI 0x20 /* Generic End of Interrupt (EOI) */ |
|
#ifndef ASM |
|
|
/* |
* Symblolic IRQ names and related definitions. |
*/ |
|
typedef enum { |
/* Base vector for our ISA IRQ handlers. */ |
BSP_ISA_IRQ_VECTOR_BASE = BSP_ASM_IRQ_VECTOR_BASE, |
/* |
* ISA IRQ handler related definitions |
*/ |
BSP_ISA_IRQ_NUMBER = 16, |
BSP_ISA_IRQ_LOWEST_OFFSET = 0, |
BSP_ISA_IRQ_MAX_OFFSET = BSP_ISA_IRQ_LOWEST_OFFSET + BSP_ISA_IRQ_NUMBER - 1, |
/* |
* PCI IRQ handlers related definitions |
* CAUTION : BSP_PCI_IRQ_LOWEST_OFFSET should be equal to OPENPIC_VEC_SOURCE |
*/ |
BSP_PCI_IRQ_NUMBER = 16, |
BSP_PCI_IRQ_LOWEST_OFFSET = BSP_ISA_IRQ_NUMBER, |
BSP_PCI_IRQ_MAX_OFFSET = BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER - 1, |
/* |
* PowerPc exceptions handled as interrupt where a rtems managed interrupt |
* handler might be connected |
*/ |
BSP_PROCESSOR_IRQ_NUMBER = 1, |
BSP_PROCESSOR_IRQ_LOWEST_OFFSET = BSP_PCI_IRQ_MAX_OFFSET + 1, |
BSP_PROCESSOR_IRQ_MAX_OFFSET = BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER - 1, |
/* |
* Summary |
*/ |
BSP_IRQ_NUMBER = BSP_PROCESSOR_IRQ_MAX_OFFSET + 1, |
BSP_LOWEST_OFFSET = BSP_ISA_IRQ_LOWEST_OFFSET, |
BSP_MAX_OFFSET = BSP_PROCESSOR_IRQ_MAX_OFFSET, |
/* |
* Some ISA IRQ symbolic name definition |
*/ |
BSP_ISA_PERIODIC_TIMER = 0, |
|
BSP_ISA_KEYBOARD = 1, |
|
BSP_ISA_UART_COM2_IRQ = 3, |
|
BSP_ISA_UART_COM1_IRQ = 4, |
|
BSP_ISA_RT_TIMER1 = 8, |
|
BSP_ISA_RT_TIMER3 = 10, |
/* |
* Some PCI IRQ symbolic name definition |
*/ |
BSP_PCI_IRQ0 = BSP_PCI_IRQ_LOWEST_OFFSET, |
BSP_PCI_ISA_BRIDGE_IRQ = BSP_PCI_IRQ0, |
/* |
* Some Processor execption handled as rtems IRQ symbolic name definition |
*/ |
BSP_DECREMENTER = BSP_PROCESSOR_IRQ_LOWEST_OFFSET |
|
}rtems_irq_symbolic_name; |
|
|
|
|
/* |
* Type definition for RTEMS managed interrupts |
*/ |
typedef unsigned char rtems_irq_prio; |
typedef unsigned short rtems_i8259_masks; |
|
extern volatile rtems_i8259_masks i8259s_cache; |
|
struct __rtems_irq_connect_data__; /* forward declaratiuon */ |
|
typedef void (*rtems_irq_hdl) (void); |
typedef void (*rtems_irq_enable) (const struct __rtems_irq_connect_data__*); |
typedef void (*rtems_irq_disable) (const struct __rtems_irq_connect_data__*); |
typedef int (*rtems_irq_is_enabled) (const struct __rtems_irq_connect_data__*); |
|
typedef struct __rtems_irq_connect_data__ { |
/* |
* IRQ line |
*/ |
rtems_irq_symbolic_name name; |
/* |
* handler. See comment on handler properties below in function prototype. |
*/ |
rtems_irq_hdl hdl; |
/* |
* function for enabling interrupts at device level (ONLY!). |
* The BSP code will automatically enable it at i8259s level and openpic level. |
* RATIONALE : anyway such code has to exist in current driver code. |
* It is usually called immediately AFTER connecting the interrupt handler. |
* RTEMS may well need such a function when restoring normal interrupt |
* processing after a debug session. |
* |
*/ |
rtems_irq_enable on; |
/* |
* function for disabling interrupts at device level (ONLY!). |
* The code will disable it at i8259s level. RATIONALE : anyway |
* such code has to exist for clean shutdown. It is usually called |
* BEFORE disconnecting the interrupt. RTEMS may well need such |
* a function when disabling normal interrupt processing for |
* a debug session. May well be a NOP function. |
*/ |
rtems_irq_disable off; |
/* |
* function enabling to know what interrupt may currently occur |
* if someone manipulates the i8259s interrupt mask without care... |
*/ |
rtems_irq_is_enabled isOn; |
}rtems_irq_connect_data; |
|
typedef struct { |
/* |
* size of all the table fields (*Tbl) described below. |
*/ |
unsigned int irqNb; |
/* |
* Default handler used when disconnecting interrupts. |
*/ |
rtems_irq_connect_data defaultEntry; |
/* |
* Table containing initials/current value. |
*/ |
rtems_irq_connect_data* irqHdlTbl; |
/* |
* actual value of BSP_ISA_IRQ_VECTOR_BASE... |
*/ |
rtems_irq_symbolic_name irqBase; |
/* |
* software priorities associated with interrupts. |
* if irqPrio [i] > intrPrio [j] it means that |
* interrupt handler hdl connected for interrupt name i |
* will not be interrupted by the handler connected for interrupt j |
* The interrupt source will be physically masked at i8259 level. |
*/ |
rtems_irq_prio* irqPrioTbl; |
}rtems_irq_global_settings; |
|
|
|
|
/*-------------------------------------------------------------------------+ |
| Function Prototypes. |
+--------------------------------------------------------------------------*/ |
/* |
* ------------------------ Intel 8259 (or emulation) Mngt Routines ------- |
*/ |
|
/* |
* function to disable a particular irq at 8259 level. After calling |
* this function, even if the device asserts the interrupt line it will |
* not be propagated further to the processor |
*/ |
int BSP_irq_disable_at_i8259s (const rtems_irq_symbolic_name irqLine); |
/* |
* function to enable a particular irq at 8259 level. After calling |
* this function, if the device asserts the interrupt line it will |
* be propagated further to the processor |
*/ |
int BSP_irq_enable_at_i8259s (const rtems_irq_symbolic_name irqLine); |
/* |
* function to acknoledge a particular irq at 8259 level. After calling |
* this function, if a device asserts an enabled interrupt line it will |
* be propagated further to the processor. Mainly usefull for people |
* writting raw handlers as this is automagically done for rtems managed |
* handlers. |
*/ |
int BSP_irq_ack_at_i8259s (const rtems_irq_symbolic_name irqLine); |
/* |
* function to check if a particular irq is enabled at 8259 level. After calling |
*/ |
int BSP_irq_enabled_at_i8259s (const rtems_irq_symbolic_name irqLine); |
/* |
* ------------------------ RTEMS Single Irq Handler Mngt Routines ---------------- |
*/ |
/* |
* function to connect a particular irq handler. This hanlder will NOT be called |
* directly as the result of the corresponding interrupt. Instead, a RTEMS |
* irq prologue will be called that will : |
* |
* 1) save the C scratch registers, |
* 2) switch to a interrupt stack if the interrupt is not nested, |
* 3) store the current i8259s' interrupt masks |
* 4) modify them to disable the current interrupt at 8259 level (and may |
* be others depending on software priorities) |
* 5) aknowledge the i8259s', |
* 6) demask the processor, |
* 7) call the application handler |
* |
* As a result the hdl function provided |
* |
* a) can perfectly be written is C, |
* b) may also well directly call the part of the RTEMS API that can be used |
* from interrupt level, |
* c) It only responsible for handling the jobs that need to be done at |
* the device level including (aknowledging/re-enabling the interrupt at device, |
* level, getting the data,...) |
* |
* When returning from the function, the following will be performed by |
* the RTEMS irq epilogue : |
* |
* 1) masks the interrupts again, |
* 2) restore the original i8259s' interrupt masks |
* 3) switch back on the orinal stack if needed, |
* 4) perform rescheduling when necessary, |
* 5) restore the C scratch registers... |
* 6) restore initial execution flow |
* |
*/ |
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data*); |
/* |
* function to get the current RTEMS irq handler for ptr->name. It enables to |
* define hanlder chain... |
*/ |
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* ptr); |
/* |
* function to get disconnect the RTEMS irq handler for ptr->name. |
* This function checks that the value given is the current one for safety reason. |
* The user can use the previous function to get it. |
*/ |
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data*); |
|
/* |
* ------------------------ RTEMS Global Irq Handler Mngt Routines ---------------- |
*/ |
/* |
* (Re) Initialize the RTEMS interrupt management. |
* |
* The result of calling this function will be the same as if each individual |
* handler (config->irqHdlTbl[i].hdl) different from "config->defaultEntry.hdl" |
* has been individualy connected via |
* BSP_install_rtems_irq_handler(&config->irqHdlTbl[i]) |
* And each handler currently equal to config->defaultEntry.hdl |
* has been previously disconnected via |
* BSP_remove_rtems_irq_handler (&config->irqHdlTbl[i]) |
* |
* This is to say that all information given will be used and not just |
* only the space. |
* |
* CAUTION : the various table address contained in config will be used |
* directly by the interrupt mangement code in order to save |
* data size so they must stay valid after the call => they should |
* not be modified or declared on a stack. |
*/ |
|
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config); |
/* |
* (Re) get info on current RTEMS interrupt management. |
*/ |
int BSP_rtems_irq_mngt_get(rtems_irq_global_settings**); |
|
extern void BSP_rtems_irq_mng_init(unsigned cpuId); |
extern void BSP_i8259s_init(void); |
#endif |
|
#endif |
/Makefile.am
0,0 → 1,26
## |
## $Id: Makefile.am,v 1.2 2001-09-27 12:01:06 chris Exp $ |
## |
|
AUTOMAKE_OPTIONS = foreign 1.4 |
|
C_FILES = i8259.c irq.c irq_init.c |
|
H_FILES = irq.h |
|
S_FILES = irq_asm.S |
|
$(PROJECT_INCLUDE)/bsp: |
$(mkinstalldirs) $@ |
|
$(PROJECT_INCLUDE)/bsp/%.h: %.h |
$(INSTALL_DATA) $< $@ |
|
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp \ |
$(H_FILES:%.h=$(PROJECT_INCLUDE)/bsp/%.h) |
|
all-local: $(PREINSTALL_FILES) |
|
EXTRA_DIST = i8259.c irq.c irq.h irq_asm.S irq_init.c |
|
include $(top_srcdir)/../../../../../automake/local.am |
/irq.c
0,0 → 1,398
/* |
* |
* This file contains the implementation of the function described in irq.h |
* |
* Copyright (C) 1998, 1999 valette@crf.canon.fr |
* |
* The license and distribution terms for this file may be |
* found in found in the file LICENSE in this distribution or at |
* http://www.OARcorp.com/rtems/license.html. |
* |
* $Id: irq.c,v 1.2 2001-09-27 12:01:06 chris Exp $ |
*/ |
|
#include <bsp.h> |
#include <bsp/irq.h> |
#include <bsp/openpic.h> |
#include <rtems/score/thread.h> |
#include <rtems/score/apiext.h> |
#include <libcpu/raw_exception.h> |
#include <bsp/vectors.h> |
#include <libcpu/cpu.h> |
|
#define RAVEN_INTR_ACK_REG 0xfeff0030 |
|
/* |
* pointer to the mask representing the additionnal irq vectors |
* that must be disabled when a particular entry is activated. |
* They will be dynamically computed from teh prioruty table given |
* in BSP_rtems_irq_mngt_set(); |
* CAUTION : this table is accessed directly by interrupt routine |
* prologue. |
*/ |
rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_NUMBER]; |
/* |
* default handler connected on each irq after bsp initialization |
*/ |
static rtems_irq_connect_data default_rtems_entry; |
|
/* |
* location used to store initial tables used for interrupt |
* management. |
*/ |
static rtems_irq_global_settings* internal_config; |
static rtems_irq_connect_data* rtems_hdl_tbl; |
|
/* |
* Check if IRQ is an ISA IRQ |
*/ |
static inline int is_isa_irq(const rtems_irq_symbolic_name irqLine) |
{ |
return (((int) irqLine <= BSP_ISA_IRQ_MAX_OFFSET) & |
((int) irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) |
); |
} |
|
/* |
* Check if IRQ is an OPENPIC IRQ |
*/ |
static inline int is_pci_irq(const rtems_irq_symbolic_name irqLine) |
{ |
return (((int) irqLine <= BSP_PCI_IRQ_MAX_OFFSET) & |
((int) irqLine >= BSP_PCI_IRQ_LOWEST_OFFSET) |
); |
} |
|
/* |
* Check if IRQ is a Porcessor IRQ |
*/ |
static inline int is_processor_irq(const rtems_irq_symbolic_name irqLine) |
{ |
return (((int) irqLine <= BSP_PROCESSOR_IRQ_MAX_OFFSET) & |
((int) irqLine >= BSP_PROCESSOR_IRQ_LOWEST_OFFSET) |
); |
} |
|
|
/* |
* ------------------------ RTEMS Irq helper functions ---------------- |
*/ |
|
/* |
* Caution : this function assumes the variable "internal_config" |
* is already set and that the tables it contains are still valid |
* and accessible. |
*/ |
static void compute_i8259_masks_from_prio () |
{ |
unsigned int i; |
unsigned int j; |
/* |
* Always mask at least current interrupt to prevent re-entrance |
*/ |
for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) { |
* ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i); |
for (j = BSP_ISA_IRQ_LOWEST_OFFSET; j < BSP_ISA_IRQ_NUMBER; j++) { |
/* |
* Mask interrupts at i8259 level that have a lower priority |
*/ |
if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) { |
* ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j); |
} |
} |
} |
} |
|
/* |
* This function check that the value given for the irq line |
* is valid. |
*/ |
|
static int isValidInterrupt(int irq) |
{ |
if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET)) |
return 0; |
return 1; |
} |
|
/* |
* ------------------------ RTEMS Single Irq Handler Mngt Routines ---------------- |
*/ |
|
int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) |
{ |
unsigned int level; |
|
if (!isValidInterrupt(irq->name)) { |
return 0; |
} |
/* |
* Check if default handler is actually connected. If not issue an error. |
* You must first get the current handler via i386_get_current_idt_entry |
* and then disconnect it using i386_delete_idt_entry. |
* RATIONALE : to always have the same transition by forcing the user |
* to get the previous handler before accepting to disconnect. |
*/ |
if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { |
return 0; |
} |
_CPU_ISR_Disable(level); |
|
/* |
* store the data provided by user |
*/ |
rtems_hdl_tbl[irq->name] = *irq; |
|
if (is_isa_irq(irq->name)) { |
/* |
* Enable interrupt at PIC level |
*/ |
BSP_irq_enable_at_i8259s (irq->name); |
} |
|
if (is_pci_irq(irq->name)) { |
/* |
* Enable interrupt at OPENPIC level |
*/ |
openpic_enable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET); |
} |
|
if (is_processor_irq(irq->name)) { |
/* |
* Enable exception at processor level |
*/ |
} |
/* |
* Enable interrupt on device |
*/ |
irq->on(irq); |
|
_CPU_ISR_Enable(level); |
|
return 1; |
} |
|
|
int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) |
{ |
if (!isValidInterrupt(irq->name)) { |
return 0; |
} |
*irq = rtems_hdl_tbl[irq->name]; |
return 1; |
} |
|
int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) |
{ |
unsigned int level; |
|
if (!isValidInterrupt(irq->name)) { |
return 0; |
} |
/* |
* Check if default handler is actually connected. If not issue an error. |
* You must first get the current handler via i386_get_current_idt_entry |
* and then disconnect it using i386_delete_idt_entry. |
* RATIONALE : to always have the same transition by forcing the user |
* to get the previous handler before accepting to disconnect. |
*/ |
if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { |
return 0; |
} |
_CPU_ISR_Disable(level); |
|
if (is_isa_irq(irq->name)) { |
/* |
* disable interrupt at PIC level |
*/ |
BSP_irq_disable_at_i8259s (irq->name); |
} |
if (is_pci_irq(irq->name)) { |
/* |
* disable interrupt at OPENPIC level |
*/ |
openpic_disable_irq ((int) irq->name - BSP_PCI_IRQ_LOWEST_OFFSET); |
} |
if (is_processor_irq(irq->name)) { |
/* |
* disable exception at processor level |
*/ |
} |
|
/* |
* Disable interrupt on device |
*/ |
irq->off(irq); |
|
/* |
* restore the default irq value |
*/ |
rtems_hdl_tbl[irq->name] = default_rtems_entry; |
|
_CPU_ISR_Enable(level); |
|
return 1; |
} |
|
/* |
* ------------------------ RTEMS Global Irq Handler Mngt Routines ---------------- |
*/ |
|
int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) |
{ |
int i; |
unsigned int level; |
/* |
* Store various code accelerators |
*/ |
internal_config = config; |
default_rtems_entry = config->defaultEntry; |
rtems_hdl_tbl = config->irqHdlTbl; |
|
_CPU_ISR_Disable(level); |
/* |
* set up internal tables used by rtems interrupt prologue |
*/ |
/* |
* start with ISA IRQ |
*/ |
compute_i8259_masks_from_prio (); |
|
for (i=BSP_ISA_IRQ_LOWEST_OFFSET; i < BSP_ISA_IRQ_NUMBER; i++) { |
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { |
BSP_irq_enable_at_i8259s (i); |
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); |
} |
else { |
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); |
BSP_irq_disable_at_i8259s (i); |
} |
} |
/* |
* must enable slave pic anyway |
*/ |
BSP_irq_enable_at_i8259s (2); |
/* |
* continue with PCI IRQ |
*/ |
for (i=BSP_PCI_IRQ_LOWEST_OFFSET; i < BSP_PCI_IRQ_LOWEST_OFFSET + BSP_PCI_IRQ_NUMBER ; i++) { |
openpic_set_priority(0, internal_config->irqPrioTbl [i]); |
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { |
openpic_enable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET); |
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); |
} |
else { |
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); |
openpic_disable_irq ((int) i - BSP_PCI_IRQ_LOWEST_OFFSET); |
} |
} |
/* |
* Must enable PCI/ISA bridge IRQ |
*/ |
openpic_enable_irq (0); |
/* |
* finish with Processor exceptions handled like IRQ |
*/ |
for (i=BSP_PROCESSOR_IRQ_LOWEST_OFFSET; i < BSP_PROCESSOR_IRQ_LOWEST_OFFSET + BSP_PROCESSOR_IRQ_NUMBER; i++) { |
if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { |
rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); |
} |
else { |
rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); |
} |
} |
_CPU_ISR_Enable(level); |
return 1; |
} |
|
int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config) |
{ |
*config = internal_config; |
return 0; |
} |
|
static unsigned spuriousIntr = 0; |
/* |
* High level IRQ handler called from shared_raw_irq_code_entry |
*/ |
void C_dispatch_irq_handler (CPU_Interrupt_frame *frame, unsigned int excNum) |
{ |
register unsigned int irq; |
register unsigned isaIntr; /* boolean */ |
register unsigned oldMask; /* old isa pic masks */ |
register unsigned newMask; /* new isa pic masks */ |
register unsigned msr; |
register unsigned new_msr; |
|
|
if (excNum == ASM_DEC_VECTOR) { |
_CPU_MSR_GET(msr); |
new_msr = msr | MSR_EE; |
_CPU_MSR_SET(new_msr); |
|
rtems_hdl_tbl[BSP_DECREMENTER].hdl(); |
|
_CPU_MSR_SET(msr); |
return; |
|
} |
irq = openpic_irq(0); |
if (irq == OPENPIC_VEC_SPURIOUS) { |
++spuriousIntr; |
return; |
} |
isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ); |
if (isaIntr) { |
/* |
* Acknowledge and read 8259 vector |
*/ |
irq = (unsigned int) (*(unsigned char *) RAVEN_INTR_ACK_REG); |
/* |
* store current PIC mask |
*/ |
oldMask = i8259s_cache; |
newMask = oldMask | irq_mask_or_tbl [irq]; |
i8259s_cache = newMask; |
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); |
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); |
BSP_irq_ack_at_i8259s (irq); |
openpic_eoi(0); |
} |
_CPU_MSR_GET(msr); |
new_msr = msr | MSR_EE; |
_CPU_MSR_SET(new_msr); |
|
rtems_hdl_tbl[irq].hdl(); |
|
_CPU_MSR_SET(msr); |
|
if (isaIntr) { |
i8259s_cache = oldMask; |
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); |
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); |
} |
else { |
openpic_eoi(0); |
} |
} |
|
|
|
void _ThreadProcessSignalsFromIrq (BSP_Exception_frame* ctx) |
{ |
/* |
* Process pending signals that have not already been |
* processed by _Thread_Displatch. This happens quite |
* unfrequently : the ISR must have posted an action |
* to the current running thread. |
*/ |
if ( _Thread_Do_post_task_switch_extension || |
_Thread_Executing->do_post_task_switch_extension ) { |
_Thread_Executing->do_post_task_switch_extension = FALSE; |
_API_extensions_Run_postswitch(); |
} |
/* |
* I plan to process other thread related events here. |
* This will include DEBUG session requested from keyboard... |
*/ |
} |
/irq_asm.S
0,0 → 1,329
/* |
* This file contains the assembly code for the PowerPC |
* IRQ veneers for RTEMS. |
* |
* The license and distribution terms for this file may be |
* found in found in the file LICENSE in this distribution or at |
* http://www.OARcorp.com/rtems/license.html. |
* |
* Modified to support the MCP750. |
* Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr |
* |
* |
* $Id: irq_asm.S,v 1.2 2001-09-27 12:01:06 chris Exp $ |
*/ |
|
#include <bsp/vectors.h> |
#include <libcpu/cpu.h> |
#include <libcpu/raw_exception.h> |
#include <rtems/score/targopts.h> |
#include "asm.h" |
|
|
#define SYNC \ |
sync; \ |
isync |
|
.text |
.p2align 5 |
|
PUBLIC_VAR(decrementer_exception_vector_prolog_code) |
|
SYM (decrementer_exception_vector_prolog_code): |
/* |
* let room for exception frame |
*/ |
stwu r1, - (EXCEPTION_FRAME_END)(r1) |
stw r4, GPR4_OFFSET(r1) |
li r4, ASM_DEC_VECTOR |
ba shared_raw_irq_code_entry |
|
PUBLIC_VAR (decrementer_exception_vector_prolog_code_size) |
|
decrementer_exception_vector_prolog_code_size = . - decrementer_exception_vector_prolog_code |
|
PUBLIC_VAR(external_exception_vector_prolog_code) |
|
SYM (external_exception_vector_prolog_code): |
/* |
* let room for exception frame |
*/ |
stwu r1, - (EXCEPTION_FRAME_END)(r1) |
stw r4, GPR4_OFFSET(r1) |
li r4, ASM_EXT_VECTOR |
ba shared_raw_irq_code_entry |
|
PUBLIC_VAR (external_exception_vector_prolog_code_size) |
|
external_exception_vector_prolog_code_size = . - external_exception_vector_prolog_code |
|
PUBLIC_VAR(shared_raw_irq_code_entry) |
PUBLIC_VAR(C_dispatch_irq_handler) |
|
.p2align 5 |
SYM (shared_raw_irq_code_entry): |
/* |
* Entry conditions : |
* Registers already saved : R1, R4 |
* R1 : points to a location with enough room for the |
* interrupt frame |
* R4 : vector number |
*/ |
/* |
* Save SRR0/SRR1 As soon As possible as it is the minimal needed |
* to reenable exception processing |
*/ |
stw r0, GPR0_OFFSET(r1) |
stw r2, GPR2_OFFSET(r1) |
stw r3, GPR3_OFFSET(r1) |
|
mfsrr0 r0 |
mfsrr1 r2 |
mfmsr r3 |
|
stw r0, SRR0_FRAME_OFFSET(r1) |
stw r2, SRR1_FRAME_OFFSET(r1) |
/* |
* Enable data and instruction address translation, exception recovery |
* |
* also, on CPUs with FP, enable FP so that FP context can be |
* saved and restored (using FP instructions) |
*/ |
#if (PPC_HAS_FPU == 0) |
ori r3, r3, MSR_RI | MSR_IR | MSR_DR |
#else |
ori r3, r3, MSR_RI | MSR_IR | MSR_DR | MSR_FP |
#endif |
mtmsr r3 |
SYNC |
/* |
* Push C scratch registers on the current stack. It may |
* actually be the thread stack or the interrupt stack. |
* Anyway we have to make it in order to be able to call C/C++ |
* functions. Depending on the nesting interrupt level, we will |
* switch to the right stack later. |
*/ |
stw r5, GPR5_OFFSET(r1) |
stw r6, GPR6_OFFSET(r1) |
stw r7, GPR7_OFFSET(r1) |
stw r8, GPR8_OFFSET(r1) |
stw r9, GPR9_OFFSET(r1) |
stw r10, GPR10_OFFSET(r1) |
stw r11, GPR11_OFFSET(r1) |
stw r12, GPR12_OFFSET(r1) |
stw r13, GPR13_OFFSET(r1) |
|
mfcr r5 |
mfctr r6 |
mfxer r7 |
mflr r8 |
|
stw r5, EXC_CR_OFFSET(r1) |
stw r6, EXC_CTR_OFFSET(r1) |
stw r7, EXC_XER_OFFSET(r1) |
stw r8, EXC_LR_OFFSET(r1) |
|
/* |
* Add some non volatile registers to store information |
* that will be used when returning from C handler |
*/ |
stw r14, GPR14_OFFSET(r1) |
stw r15, GPR15_OFFSET(r1) |
/* |
* save current stack pointer location in R14 |
*/ |
addi r14, r1, 0 |
/* |
* store part of _Thread_Dispatch_disable_level address in R15 |
*/ |
addis r15,0, _Thread_Dispatch_disable_level@ha |
/* |
* Get current nesting level in R2 |
*/ |
mfspr r2, SPRG0 |
/* |
* Check if stack switch is necessary |
*/ |
cmpwi r2,0 |
bne nested |
mfspr r1, SPRG1 |
|
nested: |
/* |
* Start Incrementing nesting level in R2 |
*/ |
addi r2,r2,1 |
/* |
* Start Incrementing _Thread_Dispatch_disable_level R4 = _Thread_Dispatch_disable_level |
*/ |
lwz r6,_Thread_Dispatch_disable_level@l(r15) |
/* |
* store new nesting level in SPRG0 |
*/ |
mtspr SPRG0, r2 |
|
addi r6, r6, 1 |
mfmsr r5 |
/* |
* store new _Thread_Dispatch_disable_level value |
*/ |
stw r6, _Thread_Dispatch_disable_level@l(r15) |
/* |
* We are now running on the interrupt stack. External and decrementer |
* exceptions are still disabled. I see no purpose trying to optimize |
* further assembler code. |
*/ |
/* |
* Call C exception handler for decrementer Interrupt frame is passed just |
* in case... |
*/ |
addi r3, r14, 0x8 |
bl C_dispatch_irq_handler /* C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) */ |
/* |
* start decrementing nesting level. Note : do not test result against 0 |
* value as an easy exit condition because if interrupt nesting level > 1 |
* then _Thread_Dispatch_disable_level > 1 |
*/ |
mfspr r2, SPRG0 |
/* |
* start decrementing _Thread_Dispatch_disable_level |
*/ |
lwz r3,_Thread_Dispatch_disable_level@l(r15) |
addi r2, r2, -1 /* Continue decrementing nesting level */ |
addi r3, r3, -1 /* Continue decrementing _Thread_Dispatch_disable_level */ |
mtspr SPRG0, r2 /* End decrementing nesting level */ |
stw r3,_Thread_Dispatch_disable_level@l(r15) /* End decrementing _Thread_Dispatch_disable_level */ |
cmpwi r3, 0 |
/* |
* switch back to original stack (done here just optimize registers |
* contention. Could have been done before...) |
*/ |
addi r1, r14, 0 |
bne easy_exit /* if (_Thread_Dispatch_disable_level != 0) goto easy_exit */ |
/* |
* Here we are running again on the thread system stack. |
* We have interrupt nesting level = _Thread_Dispatch_disable_level = 0. |
* Interrupt are still disabled. Time to check if scheduler request to |
* do something with the current thread... |
*/ |
addis r4, 0, _Context_Switch_necessary@ha |
lwz r5, _Context_Switch_necessary@l(r4) |
cmpwi r5, 0 |
bne switch |
|
addis r6, 0, _ISR_Signals_to_thread_executing@ha |
lwz r7, _ISR_Signals_to_thread_executing@l(r6) |
cmpwi r7, 0 |
li r8, 0 |
beq easy_exit |
stw r8, _ISR_Signals_to_thread_executing@l(r6) |
/* |
* going to call _ThreadProcessSignalsFromIrq |
* Push a complete exception like frame... |
*/ |
stmw r16, GPR16_OFFSET(r1) |
addi r3, r1, 0x8 |
/* |
* compute SP at exception entry |
*/ |
addi r2, r1, EXCEPTION_FRAME_END |
/* |
* store it at the right place |
*/ |
stw r2, GPR1_OFFSET(r1) |
/* |
* Call High Level signal handling code |
*/ |
bl _ThreadProcessSignalsFromIrq |
/* |
* start restoring exception like frame |
*/ |
lwz r31, EXC_CTR_OFFSET(r1) |
lwz r30, EXC_XER_OFFSET(r1) |
lwz r29, EXC_CR_OFFSET(r1) |
lwz r28, EXC_LR_OFFSET(r1) |
|
mtctr r31 |
mtxer r30 |
mtcr r29 |
mtlr r28 |
|
lmw r4, GPR4_OFFSET(r1) |
lwz r2, GPR2_OFFSET(r1) |
lwz r0, GPR0_OFFSET(r1) |
|
/* |
* Disable data and instruction translation. Make path non recoverable... |
*/ |
mfmsr r3 |
xori r3, r3, MSR_RI | MSR_IR | MSR_DR |
mtmsr r3 |
SYNC |
/* |
* Restore rfi related settings |
*/ |
|
lwz r3, SRR1_FRAME_OFFSET(r1) |
mtsrr1 r3 |
lwz r3, SRR0_FRAME_OFFSET(r1) |
mtsrr0 r3 |
|
lwz r3, GPR3_OFFSET(r1) |
addi r1,r1, EXCEPTION_FRAME_END |
SYNC |
rfi |
|
switch: |
bl SYM (_Thread_Dispatch) |
|
easy_exit: |
/* |
* start restoring interrupt frame |
*/ |
lwz r3, EXC_CTR_OFFSET(r1) |
lwz r4, EXC_XER_OFFSET(r1) |
lwz r5, EXC_CR_OFFSET(r1) |
lwz r6, EXC_LR_OFFSET(r1) |
|
mtctr r3 |
mtxer r4 |
mtcr r5 |
mtlr r6 |
|
lwz r15, GPR15_OFFSET(r1) |
lwz r14, GPR14_OFFSET(r1) |
lwz r13, GPR13_OFFSET(r1) |
lwz r12, GPR12_OFFSET(r1) |
lwz r11, GPR11_OFFSET(r1) |
lwz r10, GPR10_OFFSET(r1) |
lwz r9, GPR9_OFFSET(r1) |
lwz r8, GPR8_OFFSET(r1) |
lwz r7, GPR7_OFFSET(r1) |
lwz r6, GPR6_OFFSET(r1) |
lwz r5, GPR5_OFFSET(r1) |
|
/* |
* Disable nested exception processing, data and instruction |
* translation. |
*/ |
mfmsr r3 |
xori r3, r3, MSR_RI | MSR_IR | MSR_DR |
mtmsr r3 |
SYNC |
/* |
* Restore rfi related settings |
*/ |
|
lwz r4, SRR1_FRAME_OFFSET(r1) |
lwz r2, SRR0_FRAME_OFFSET(r1) |
lwz r3, GPR3_OFFSET(r1) |
lwz r0, GPR0_OFFSET(r1) |
|
mtsrr1 r4 |
mtsrr0 r2 |
lwz r4, GPR4_OFFSET(r1) |
lwz r2, GPR2_OFFSET(r1) |
addi r1,r1, EXCEPTION_FRAME_END |
SYNC |
rfi |
|