summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/motorola_powerpc/irq
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>1999-06-14 16:51:13 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>1999-06-14 16:51:13 +0000
commitba46ffa6169c0927c19d97816286b5ffaf2e9ab2 (patch)
tree2d71e9fa43bed5fe628a202df8710772b7ddb037 /c/src/lib/libbsp/powerpc/motorola_powerpc/irq
parentRegenerated. (diff)
downloadrtems-ba46ffa6169c0927c19d97816286b5ffaf2e9ab2.tar.bz2
This is a large patch from Eric Valette <valette@crf.canon.fr> that was
described in the message following this paragraph. This patch also includes a mcp750 BSP. From valette@crf.canon.fr Mon Jun 14 10:03:08 1999 Date: Tue, 18 May 1999 01:30:14 +0200 (CEST) From: VALETTE Eric <valette@crf.canon.fr> To: joel@oarcorp.com Cc: raguet@crf.canon.fr, rtems-snapshots@oarcorp.com, valette@crf.canon.fr Subject: Questions/Suggestion regarding RTEMS PowerPC code (long) Dear knowledgeable RTEMS powerpc users, As some of you may know, I'm currently finalizing a port of RTEMS on a MCP750 Motorola board. I have done most of it but have some questions to ask before submitting the port. In order to understand some of the changes I have made or would like to make, maybe it is worth describing the MCP750 Motorola board. the MCP750 is a COMPACT PCI powerpc board with : 1) a MPC750 233 MHz processor, 2) a raven bus bridge/PCI controller that implement an OPENPIC compliant interrupt controller, 3) a VIA 82C586 PCI/ISA bridge that offers a PC compliant IO for keyboard, serial line, IDE, and the well known PC 8259 cascaded PIC interrupt architecture model, 4) a DEC 21140 Ethernet controller, 5) the PPCBUG Motorola firmware in flash, 6) A DEC PCI bridge, This architecture is common to most Motorola 60x/7xx board except that : 1) on VME board, the DEC PCI bridge is replaced by a VME chipset, 2) the VIA 82C586 PCI/ISA bridge is replaced by another bridge that is almost fully compatible with the via bridge... So the port should be a rather close basis for many 60x/7xx motorola board... On this board, I already have ported Linux 2.2.3 and use it both as a development and target board. Now the questions/suggestions I have : 1) EXCEPTION CODE ------------------- As far as I know exceptions on PPC are handled like interrupts. I dislike this very much as : a) Except for the decrementer exception (and maybe some other on mpc8xx), exceptions are not recoverable and the handler just need to print the full context and go to the firmware or debugger... b) The interrupt switch is only necessary for the decrementer and external interrupt (at least on 6xx,7xx). c) The full context for exception is never saved and thus cannot be used by debugger... I do understand the most important for interrupts low level code is to save the minimal context enabling to call C code for performance reasons. On non recoverable exception on the other hand, the most important is to save the maximum information concerning proc status in order to analyze the reason of the fault. At least we will need this in order to implement the port of RGDB on PPC ==> I wrote an API for connecting raw exceptions (and thus raw interrupts) for mpc750. It should be valid for most powerpc processors... I hope to find a way to make this coexist with actual code layout. The code is actually located in lib/libcpu/powerpc/mpc750 and is thus optional (provided I write my own version of exec/score/cpu/powerpc/cpu.c ...) See remark about files/directory layout organization in 4) 2) Current Implementation of ISR low level code ----------------------------------------------- I do not understand why the MSR EE flags is cleared again in exec/score/cpu/powerpc/irq_stubs.S #if (PPC_USE_SPRG) mfmsr r5 mfspr r6, sprg2 #else lwz r6,msr_initial(r11) lis r5,~PPC_MSR_DISABLE_MASK@ha ori r5,r5,~PPC_MSR_DISABLE_MASK@l and r6,r6,r5 mfmsr r5 #endif Reading the doc, when a decrementer interrupt or an external interrupt is active, the MSR EE flag is already cleared. BTW if exception/interrupt could occur, it would trash SRR0 and SRR1. In fact the code may be useful to set MSR[RI] that re-enables exception processing. BTW I will need to set other value in MSR to handle interrupts : a) I want the MSR[IR] and MSR[DR] to be set for performance reasons and also because I need DBAT support to have access to PCI memory space as the interrupt controller is in the PCI space. Reading the code, I see others have the same kind of request : /* SCE 980217 * * We need address translation ON when we call our ISR routine mtmsr r5 */ This is just another prof that even the lowest level IRQ code is fundamentally board dependent and not simply processor dependent especially when the processor use external interrupt controller because it has a single interrupt request line... Note that if you look at the PPC code high level interrupt handling code, as the "set_vector" routine that really connects the interrupt is in the BSP/startup/genpvec.c, the fact that IRQ handling is BSP specific is DE-FACTO acknowledged. I know I have already expressed this and understand that this would require some heavy change in the code but believe me you will reach a point where you will not be able to find a compatible while optimum implementation for low level interrupt handling code...) In my case this is already true... So please consider removing low level IRQ handling from exec/score/cpu/* and only let there exception handling code... Exceptions are usually only processor dependent and do not depend on external hardware mechanism to be masked or acknowledged or re-enabled (there are probably exception but ...) I have already done this for pc386 bsp but need to make it again. This time I will even propose an API. 3) R2/R13 manipulation for EABI implementation ---------------------------------------------- I do not understand the handling of r2 and r13 in the EABI case. The specification for r2 says pointer to sdata2, sbss2 section => constant. However I do not see -ffixed-r2 passed to any compilation system in make/custom/* (for info linux does this on PPC). So either this is a default compiler option when choosing powerpc-rtems and thus we do not need to do anything with this register as all the code is compiled with this compiler and linked together OR this register may be used by rtems code and then we do not need any special initialization or handling. The specification for r13 says pointer to the small data area. r13 argumentation is the same except that as far as I know the usage of the small data area requires specific compiler support so that access to variables is compiled via loading the LSB in a register and then using r13 to get full address... It is like a small memory model and it was present in IBM C compilers. => I propose to suppress any specific code for r2 and r13 in the EABI case. 4) Code layout organization (yes again :-)) ------------------------------------------- I think there are a number of design flaws in the way the code is for ppc organized and I will try to point them out. I have been beaten by this again on this new port, and was beaten last year while modifying code for pc386. a) exec/score/cpu/* vs lib/libcpu/cpu/*. I think that too many things are put in exec/score/cpu that have nothing to do with RTEMS internals but are rather related to CPU feature. This include at least : a) registers access routine (e.g GET_MSR_Value), b) interrupt masking/unmasking routines, c) cache_mngt_routine, d) mmu_mngt_routine, e) Routines to connect the raw_exception, raw_interrupt handler, b) lib/libcpu/cpu/powerpc/* With a processor family as exuberant as the powerpc family, and their well known subtle differences (604 vs 750) or unfortunately majors (8xx vs 60x) the directory structure is fine (except maybe the names that are not homogeneous) powerpc ppc421 mpc821 ... I only needed to add mpc750. But the fact that libcpu.a was not produced was a pain and the fact that this organization may duplicates code is also problematic. So, except if the support of automake provides a better solution I would like to propose something like this : powerpc mpc421 mpc821 ... mpc750 shared wrapup with the following rules : a) "shared" would act as a source container for sources that may be shared among processors. Needed files would be compiled inside the processor specific directory using the vpath Makefile mechanism. "shared" may also contain compilation code for routine that are really shared and not worth to inline... (did not found many things so far as registers access routine ARE WORTH INLINING)... In the case something is compiled there, it should create libcpushared.a b) layout under processor specific directory is free provided that 1)the result of the compilation process exports : libcpu/powerpc/"PROC"/*.h in $(PROJECT_INCLUDE)/libcpu 2) each processor specific directory creates a library called libcpuspecific.a Note that this organization enables to have a file that is nearly the same than in shared but that must differ because of processor differences... c) "wrapup" should create libcpu.a using libcpushared.a libcpuspecific.a and export it $(PROJECT_INCLUDE)/libcpu The only thing I have no ideal solution is the way to put shared definitions in "shared" and only processor specific definition in "proc". To give a concrete example, most MSR bit definition are shared among PPC processors and only some differs. if we create a single msr.h in shared it will have ifdef. If in msr.h we include libcpu/msr_c.h we will need to have it in each prowerpc specific directory (even empty). Opinions are welcomed ... Note that a similar mechanism exist in libbsp/i386 that also contains a shared directory that is used by several bsp like pc386 and i386ex and a similar wrapup mechanism... NB: I have done this for mpc750 and other processors could just use similar Makefiles... c) The exec/score/cpu/powerpc directory layout. I think the directory layout should be the same than the libcpu/powerpc. As it is not, there are a lot of ifdefs inside the code... And of course low level interrupt handling code should be removed... Besides that I do not understand why 1) things are compiled in the wrap directory, 2) some includes are moved to rtems/score, I think the "preinstall" mechanism enables to put everything in the current directory (or better in a per processor directory), 5) Interrupt handling API ------------------------- Again :-). But I think that using all the features the PIC offers is a MUST for RT system. I already explained in the prologue of this (long and probably boring) mail that the MCP750 boards offers an OPENPIC compliant architecture and that the VIA 82586 PCI/ISA bridge offers a PC compatible IO and PIC mapping. Here is a logical view of the RAVEN/VIA 82586 interrupt mapping : --------- 0 ------ | OPEN | <-----|8259| | PIC | | | 2 ------ |(RAVEN)| | | <-----|8259| | | | | | | 11 | | | | | | <---- | | | | | | | | | | | | --------- ------ | | ^ ------ | VIA PCI/ISA bridge | x -------- PCI interrupts OPENPIC offers interrupt priorities among PCI interrupts and interrupt selective masking. The 8259 offers the same kind of feature. With actual powerpc interrupt code : 1) there is no way to specify priorities among interrupts handler. This is REALLY a bad thing. For me it is as importnat as having priorities for threads... 2) for my implementation, each ISR should contain the code that acknowledge the RAVEN and 8259 cascade, modify interrupt mask on both chips, and reenable interrupt at processor level, ..., restore then on interrupt return,.... This code is actually similar to code located in some genpvec.c powerpc files, 3) I must update _ISR_Nesting_level because irq.inl use it... 4) the libchip code connects the ISR via set_vector but the libchip handler code does not contain any code to manipulate external interrupt controller hardware in order to acknoledge the interrupt or re-enable them (except for the target hardware of course) So this code is broken unless set_vector adds an additionnal prologue/epilogue before calling/returning from in order to acknoledge/mask the raven and the 8259 PICS... => Anyway already EACH BSP MUST REWRITE PART OF INTERRUPT HANDLING CODE TO CORRECTLY IMPLEMENT SET_VECTOR. I would rather offer an API similar to the one provided in libbsp/i386/shared/irq/irq.h so that : 1) Once the driver supplied methods is called the only things the ISR has to do is to worry about the external hardware that triggered the interrupt. Everything on openpic/VIA/processor would have been done by the low levels (same things as set-vector) 2) The caller will need to supply the on/off/isOn routine that are fundamental to correctly implements debuggers/performance monitoring is a portable way 3) A globally configurable interrupt priorities mechanism... I have nothing against providing a compatible set_vector just to make libchip happy but as I have already explained in other mails (months ago), I really think that the ISR connection should be handled by the BSP and that no code containing irq connection should exist the rtems generic layers... Thus I really dislike libchip on this aspect because in a long term it will force to adopt the less reach API for interrupt handling that exists (set_vector). Additional note : I think the _ISR_Is_in_progress() inline routine should be : 1) Put in a processor specific section, 2) Should not rely on a global variable, As : a) on symmetric MP, there is one interrupt level per CPU, b) On processor that have an ISP (e,g 68040), this variable is useless (MSR bit testing could be used) c) On PPC, instead of using the address of the variable via __CPU_IRQ_info.Nest_level a dedicated SPR could be used. NOTE: most of this is also true for _Thread_Dispatch_disable_level END NOTE -------- Please do not take what I said in the mail as a criticism for anyone who submitted ppc code. Any code present helped me a lot understanding PPC behavior. I just wanted by this mail to : 1) try to better understand the actual code, 2) propose concrete ways of enhancing current code by providing an alternative implementation for MCP750. I will make my best effort to try to brake nothing but this is actually hard due to the file layout organisation. 3) make understandable some changes I will probably make if joel let me do them :-) Any comments/objections are welcomed as usual. -- __ / ` Eric Valette /-- __ o _. Canon CRF (___, / (_(_(__ Rue de la touche lambert 35517 Cesson-Sevigne Cedex FRANCE Tel: +33 (0)2 99 87 68 91 Fax: +33 (0)2 99 84 11 30 E-mail: valette@crf.canon.fr
Diffstat (limited to 'c/src/lib/libbsp/powerpc/motorola_powerpc/irq')
-rw-r--r--c/src/lib/libbsp/powerpc/motorola_powerpc/irq/Makefile.in59
-rw-r--r--c/src/lib/libbsp/powerpc/motorola_powerpc/irq/i8259.c152
-rw-r--r--c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.c399
-rw-r--r--c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.h318
-rw-r--r--c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_asm.S308
-rw-r--r--c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_init.c288
6 files changed, 1524 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/Makefile.in b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/Makefile.in
new file mode 100644
index 0000000000..fb7c0f2c36
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/Makefile.in
@@ -0,0 +1,59 @@
+#
+# $Id$
+#
+
+@SET_MAKE@
+srcdir = @srcdir@
+VPATH = @srcdir@
+RTEMS_ROOT = @top_srcdir@
+PROJECT_ROOT = @PROJECT_ROOT@
+
+INSTALL = @INSTALL@
+
+# C source names, if any, go here -- minus the .c
+C_PIECES=irq_init i8259 irq
+C_FILES=$(C_PIECES:%=%.c)
+C_O_FILES=$(C_PIECES:%=${ARCH}/%.o)
+
+H_FILES=$(srcdir)/irq.h
+
+# Assembly source names, if any, go here -- minus the .s
+S_PIECES=irq_asm
+S_FILES=$(S_PIECES:%=%.S)
+S_O_FILES=$(S_FILES:%.S=${ARCH}/%.o)
+
+SRCS=$(C_FILES) $(CC_FILES) $(H_FILES) $(S_FILES)
+OBJS=$(S_O_FILES) $(C_O_FILES) $(CC_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/$(RTEMS_BSP).cfg
+include $(RTEMS_ROOT)/make/leaf.cfg
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+DEFINES +=
+CPPFLAGS +=
+CFLAGS +=
+
+LD_PATHS +=
+LD_LIBS +=
+LDFLAGS +=
+
+#
+# Add your list of files to delete here. The config files
+# already know how to delete some stuff, so you may want
+# to just run 'make clean' first to see what gets missed.
+# 'make clobber' already includes 'make clean'
+#
+
+CLEAN_ADDITIONS +=
+CLOBBER_ADDITIONS +=
+
+preinstall:
+ $(MKDIR) $(PROJECT_INCLUDE)/bsp
+ $(INSTALL_CHANGE) -m 444 $(H_FILES) $(PROJECT_INCLUDE)/bsp
+
+all: ${ARCH} $(SRCS) preinstall ${OBJS}
+
+install: all
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/i8259.c b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/i8259.c
new file mode 100644
index 0000000000..ae4f94dfea
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/i8259.c
@@ -0,0 +1,152 @@
+/* i8259.c
+ *
+ * This file contains the implementation of the function described in irq.h
+ * related to Intel 8259 Programmable Interrupt controller.
+ *
+ * CopyRight (C) 1998 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$
+ */
+
+
+#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.
+ * This cache is initialized in ldseg.s
+ */
+volatile rtems_i8259_masks i8259s_cache;
+
+/*-------------------------------------------------------------------------+
+| 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_SLAVE_COMMAND_IO_PORT, PIC_EOI);
+ }
+ outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
+
+ 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 */
+
+ i8259s_cache = 0xFFFB;
+}
+
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.c b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.c
new file mode 100644
index 0000000000..da67d7303c
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.c
@@ -0,0 +1,399 @@
+/* irq.c
+ *
+ * This file contains the implementation of the function described in irq.h
+ *
+ * CopyRight (C) 1998 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$
+ */
+
+
+#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/processor.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 (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...
+ */
+}
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.h b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.h
new file mode 100644
index 0000000000..6f80064847
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq.h
@@ -0,0 +1,318 @@
+/* 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$
+ */
+
+#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 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
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_asm.S b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_asm.S
new file mode 100644
index 0000000000..7937bbf400
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_asm.S
@@ -0,0 +1,308 @@
+/*
+ * (c) 1999, Eric Valette valette@crf.canon.fr
+ *
+ *
+ * This file contains the assembly code for the PowerPC
+ * IRQ veneers for RTEMS.
+ *
+ * $Id$
+ */
+
+
+
+#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
+ */
+ ori r3, r3, MSR_RI | MSR_IR | MSR_DR
+ 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
+ bl _ISR_Signals_to_thread_executing
+ /*
+ * 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
+
diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_init.c b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_init.c
new file mode 100644
index 0000000000..cc3f343315
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/irq/irq_init.c
@@ -0,0 +1,288 @@
+/* irq_init.c
+ *
+ * This file contains the implementation of rtems initialization
+ * related to interrupt handling.
+ *
+ * CopyRight (C) 1999 valette@crf.canon.fr
+ *
+ * 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$
+ */
+#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>
+
+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 isa_bridge_interrupts_setup(void)
+{
+ pci_isa_bridge_device pci_dev;
+ unsigned long 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_1 << 16)))
+ ||
+ (temp == (((unsigned short) PCI_VENDOR_ID_VIA) | (PCI_DEVICE_ID_VIA_82C586_0 << 16)))
+ ) {
+ bridge = pci_dev;
+ via_82c586 = &bridge;
+ /*
+ * 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);
+ 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)) {
+ printk("This is a second generation MCP750 board\n");
+ printk("We must reprogram the PCI/ISA bridge...\n");
+ pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
+ 0x47, &tmp);
+ printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
+ /*
+ * 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);
+ printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
+ tmp = 0;
+ pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
+ 0x54, tmp);
+ }
+ else {
+ printk("This is a first generation MCP750 board\n");
+ printk("We just show the actual value used by PCI/ISA bridge\n");
+ pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
+ 0x47, &tmp);
+ printk(" PCI ISA bridge control2 = %x\n", (unsigned) tmp);
+ /*
+ * 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);
+ tmp = inb(ISA8259_S_ELCR);
+ printk(" PCI ISA bridge slave edge/level control bit = %x\n", (unsigned) tmp);
+ tmp = inb(ISA8259_M_ELCR);;
+ printk(" PCI ISA bridge master edge/level control bit = %x\n", (unsigned) tmp);
+ /*
+ * Must disable the 4D0/4D1 ISA interrupt level/edge config registers
+ * or the card will die a soon as we we will enable external interrupts
+ */
+ pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
+ 0x47, &tmp);
+ tmp &= ~(0x20);
+ pci_write_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
+ 0x47, tmp);
+ /*
+ * Show the Interrupt inputs inverting/non-inverting level status
+ */
+ pci_read_config_byte(via_82c586->bus, via_82c586->device, via_82c586->function,
+ 0x54, &tmp);
+ printk(" PCI ISA bridge PCI/IRQ Edge/Level Select = %x\n", (unsigned) tmp);
+ }
+}
+
+ /*
+ * 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 this means the
+ * decrementer exception and the external exception.
+ */
+void BSP_rtems_irq_mng_init(unsigned cpuId)
+{
+ rtems_raw_except_connect_data vectorDesc;
+ int i;
+ register unsigned int msr;
+
+ /*
+ * First initialize the Interrupt management hardware
+ */
+ OpenPIC_InitSenses = mcp750_openpic_initsenses;
+ OpenPIC_NumInitSenses = sizeof(mcp750_openpic_initsenses) / sizeof(char);
+ printk("Going to initialize raven interrupt controller (openpic compliant)\n");
+ openpic_init(1);
+ printk("Going to initialize the PCI/ISA bridge IRQ related setting (VIA 82C586)\n");
+ isa_bridge_interrupts_setup();
+ printk("Going to initialize the ISA PC legacy IRQ management hardware\n");
+ 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 = &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 = &external_exception_vector_prolog_code_size;
+ if (!mpc60x_set_exception (&vectorDesc)) {
+ BSP_panic("Unable to initialize RTEMS external raw exception\n");
+ }
+ printk("RTEMS IRQ management is now operationnal\n");
+ printk("Going to enable interrupts at processor level\n");
+ _CPU_MSR_GET(msr);
+ msr = msr |= MSR_EE;
+ _CPU_MSR_SET(msr);
+ printk("Interrupts enabled\n");
+}
+