forked from Imagelibrary/rtems
Update motorola_power to irq-generic interrupt management
- Add support to the BSP to enable irq-generic management - Update the powerpc shared irq code to support irq-generic. This is an opt in option for existing powerpc bsps. This change should be simpler now - Fix a number of issues in ISA IRQ controller handling by porting fixes from the i386 (PC) BSP Closes #4238 Closes #4239
This commit is contained in:
@@ -12,6 +12,19 @@
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#define PIC_EOSI 0x60 ///< End of Specific Interrupt (EOSI)
|
||||
#define PIC_EOI 0x20 ///< Generic End of Interrupt (EOI)
|
||||
|
||||
/* Operation control word type 3. Bit 3 (0x08) must be set. Even address. */
|
||||
#define PIC_OCW3_RIS 0x01 /* 1 = read IS, 0 = read IR */
|
||||
#define PIC_OCW3_RR 0x02 /* register read */
|
||||
#define PIC_OCW3_P 0x04 /* poll mode command */
|
||||
/* 0x08 must be 1 to select OCW3 vs OCW2 */
|
||||
#define PIC_OCW3_SEL 0x08 /* must be 1 */
|
||||
/* 0x10 must be 0 to select OCW3 vs ICW1 */
|
||||
#define PIC_OCW3_SMM 0x20 /* special mode mask */
|
||||
#define PIC_OCW3_ESMM 0x40 /* enable SMM */
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
|
||||
+--------------------------------------------------------------------------*/
|
||||
@@ -19,91 +32,137 @@
|
||||
* 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;
|
||||
static rtems_i8259_masks i8259s_imr_cache = 0xFFFB;
|
||||
static rtems_i8259_masks i8259s_in_progress = 0;
|
||||
|
||||
static inline
|
||||
void BSP_i8259s_irq_update_master_imr( void )
|
||||
{
|
||||
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
|
||||
outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
|
||||
}
|
||||
|
||||
static inline
|
||||
void BSP_i8259s_irq_update_slave_imr( void )
|
||||
{
|
||||
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
|
||||
outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the IRQ valid?
|
||||
*/
|
||||
static inline bool BSP_i8259s_irq_valid(const rtems_irq_number irqLine)
|
||||
{
|
||||
return ((int)irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) &&
|
||||
((int)irqLine <= BSP_ISA_IRQ_MAX_OFFSET);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the IRR register. The default.
|
||||
*/
|
||||
static inline uint8_t BSP_i8259s_irq_int_request_reg(uint32_t ioport)
|
||||
{
|
||||
uint8_t isr;
|
||||
inport_byte(ioport, isr);
|
||||
return isr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the ISR register. Keep the default of the IRR.
|
||||
*/
|
||||
static inline uint8_t BSP_i8259s_irq_in_service_reg(uint32_t ioport)
|
||||
{
|
||||
uint8_t isr;
|
||||
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
|
||||
inport_byte(ioport, isr);
|
||||
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
|
||||
return isr;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Function: BSP_irq_disable_at_i8259s
|
||||
| Description: Mask IRQ line in appropriate PIC chip.
|
||||
| Global Variables: i8259s_cache
|
||||
| Global Variables: i8259s_imr_cache, i8259s_in_progress
|
||||
| Arguments: vector_offset - number of IRQ line to mask.
|
||||
| Returns: original state or -1 on error.
|
||||
| Returns: 0 is OK.
|
||||
+--------------------------------------------------------------------------*/
|
||||
int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_disable_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
unsigned short mask;
|
||||
rtems_interrupt_level level;
|
||||
int rval;
|
||||
|
||||
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
|
||||
)
|
||||
if (!BSP_i8259s_irq_valid(irqLine))
|
||||
return -1;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
|
||||
mask = 1 << irqLine;
|
||||
rval = i8259s_cache & mask ? 0 : 1;
|
||||
i8259s_cache |= mask;
|
||||
i8259s_imr_cache |= mask;
|
||||
|
||||
if (irqLine < 8)
|
||||
{
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
}
|
||||
else
|
||||
{
|
||||
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
}
|
||||
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return rval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Function: BSP_irq_enable_at_i8259s
|
||||
| Description: Unmask IRQ line in appropriate PIC chip.
|
||||
| Global Variables: i8259s_cache
|
||||
| Global Variables: i8259s_imr_cache, i8259s_in_progress
|
||||
| Arguments: irqLine - number of IRQ line to mask.
|
||||
| Returns: Nothing.
|
||||
+--------------------------------------------------------------------------*/
|
||||
int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_enable_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
unsigned short mask;
|
||||
rtems_interrupt_level level;
|
||||
unsigned short mask;
|
||||
uint8_t isr;
|
||||
uint8_t irr;
|
||||
|
||||
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET )
|
||||
)
|
||||
if (!BSP_i8259s_irq_valid(irqLine))
|
||||
return 1;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
|
||||
mask = ~(1 << irqLine);
|
||||
i8259s_cache &= mask;
|
||||
mask = 1 << irqLine;
|
||||
i8259s_imr_cache &= ~mask;
|
||||
|
||||
if (irqLine < 8)
|
||||
{
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
||||
isr = BSP_i8259s_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
|
||||
irr = BSP_i8259s_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
}
|
||||
else
|
||||
{
|
||||
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
|
||||
isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
||||
irr = BSP_i8259s_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
}
|
||||
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return 0;
|
||||
} /* mask_irq */
|
||||
|
||||
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
unsigned short mask;
|
||||
|
||||
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
|
||||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
|
||||
)
|
||||
if (!BSP_i8259s_irq_valid(irqLine))
|
||||
return 1;
|
||||
|
||||
mask = (1 << irqLine);
|
||||
return (~(i8259s_cache & mask));
|
||||
return (~(i8259s_imr_cache & mask));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
@@ -113,24 +172,47 @@ int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
|
||||
| Arguments: irqLine - number of IRQ line to acknowledge.
|
||||
| Returns: Nothing.
|
||||
+--------------------------------------------------------------------------*/
|
||||
int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine)
|
||||
int BSP_irq_ack_at_i8259s(const rtems_irq_number irqLine)
|
||||
{
|
||||
uint8_t slave_isr = 0;
|
||||
|
||||
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));
|
||||
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
|
||||
slave_isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only issue the EOI to the master if there are no more interrupts in
|
||||
* service for the slave. i8259a data sheet page 18, The Special Fully Nested
|
||||
* Mode, b.
|
||||
*/
|
||||
if (slave_isr == 0)
|
||||
outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
|
||||
|
||||
return 0;
|
||||
|
||||
} /* ackIRQ */
|
||||
|
||||
unsigned short BSP_irq_suspend_i8259s(unsigned short mask)
|
||||
{
|
||||
unsigned short in_progress_save = i8259s_in_progress;
|
||||
i8259s_in_progress |= mask;
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
return in_progress_save;
|
||||
}
|
||||
|
||||
void BSP_irq_resume_i8259s(unsigned short in_progress_save)
|
||||
{
|
||||
i8259s_in_progress = in_progress_save;
|
||||
BSP_i8259s_irq_update_master_imr();
|
||||
BSP_i8259s_irq_update_slave_imr();
|
||||
}
|
||||
|
||||
void BSP_i8259s_init(void)
|
||||
{
|
||||
/*
|
||||
* init master 8259 interrupt controller
|
||||
* Always mask at least current interrupt to prevent re-entrance
|
||||
*/
|
||||
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
|
||||
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */
|
||||
|
||||
@@ -280,6 +280,7 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
|
||||
int known_cpi_isa_bridge = 0;
|
||||
#endif
|
||||
int i;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* First initialize the Interrupt management hardware
|
||||
@@ -351,7 +352,19 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
|
||||
initial_config.irqBase = BSP_LOWEST_OFFSET;
|
||||
initial_config.irqPrioTbl = irqPrioTable;
|
||||
|
||||
if (!BSP_rtems_irq_mngt_set(&initial_config)) {
|
||||
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
|
||||
#ifdef TRACE_IRQ_INIT
|
||||
printk("RTEMS IRQ management: irq-generic\n");
|
||||
#endif
|
||||
r = BSP_rtems_irq_generic_set(&initial_config);
|
||||
#else
|
||||
#ifdef TRACE_IRQ_INIT
|
||||
printk("RTEMS IRQ management: legacy\n");
|
||||
#endif
|
||||
r = BSP_rtems_irq_mngt_set(&initial_config);
|
||||
#endif
|
||||
|
||||
if (!r) {
|
||||
/*
|
||||
* put something here that will show the failure...
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/irq_supp.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
#ifndef BSP_HAS_NO_VME
|
||||
#include <bsp/VMEConfig.h>
|
||||
#endif
|
||||
@@ -234,15 +235,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
#if BSP_ISA_IRQ_NUMBER > 0
|
||||
register unsigned isaIntr; /* boolean */
|
||||
register unsigned oldMask = 0; /* old isa pic masks */
|
||||
register unsigned newMask; /* new isa pic masks */
|
||||
#endif
|
||||
|
||||
if (excNum == ASM_DEC_VECTOR) {
|
||||
|
||||
bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
|
||||
|
||||
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
|
||||
bsp_interrupt_handler_dispatch(BSP_DECREMENTER);
|
||||
#else
|
||||
bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#if BSP_PCI_IRQ_NUMBER > 0
|
||||
@@ -274,7 +275,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
|
||||
#if BSP_ISA_IRQ_NUMBER > 0
|
||||
#ifdef BSP_PCI_ISA_BRIDGE_IRQ
|
||||
#if 0 == BSP_PCI_IRQ_NUMBER
|
||||
#if 0 == BSP_PCI_IRQ_NUMBER
|
||||
#error "Configuration Error -- BSP w/o PCI IRQs MUST NOT define BSP_PCI_ISA_BRIDGE_IRQ"
|
||||
#endif
|
||||
isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
|
||||
@@ -289,11 +290,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
/*
|
||||
* 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));
|
||||
oldMask = BSP_irq_suspend_i8259s(irq_mask_or_tbl [irq]);
|
||||
BSP_irq_ack_at_i8259s (irq);
|
||||
#if BSP_PCI_IRQ_NUMBER > 0
|
||||
if ( OpenPIC )
|
||||
@@ -303,13 +300,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
#endif
|
||||
|
||||
/* dispatch handlers */
|
||||
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
|
||||
bsp_interrupt_handler_dispatch(irq);
|
||||
#else
|
||||
bsp_irq_dispatch_list(rtems_hdl_tbl, irq, default_rtems_entry.hdl);
|
||||
#endif
|
||||
|
||||
#if BSP_ISA_IRQ_NUMBER > 0
|
||||
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));
|
||||
BSP_irq_resume_i8259s(oldMask);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
117
bsps/powerpc/shared/irq/ppc-irq-generic.c
Normal file
117
bsps/powerpc/shared/irq/ppc-irq-generic.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/* SPDX-License-Identifier: BSD-2-Clause */
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup RTEMSBSPsPowerPC
|
||||
*
|
||||
* @brief Generic Interrupt suppoer
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2021 Chris Johns. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <stdlib.h>
|
||||
#include <rtems/bspIo.h> /* for printk */
|
||||
#include <libcpu/spr.h>
|
||||
#include <bsp/irq_supp.h>
|
||||
#include <bsp/irq-generic.h>
|
||||
#include <bsp/vectors.h>
|
||||
|
||||
SPR_RW(BOOKE_TSR)
|
||||
SPR_RW(PPC405_TSR)
|
||||
|
||||
/* legacy mode for bookE DEC exception;
|
||||
* to avoid the double layer of function calls
|
||||
* (dec_handler_bookE -> C_dispatch_irq_handler -> user handler)
|
||||
* it is preferrable for the user to hook the DEC
|
||||
* exception directly.
|
||||
* However, the legacy mode works with less modifications
|
||||
* of user code.
|
||||
*/
|
||||
static int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum)
|
||||
{
|
||||
/* clear interrupt; we must do this
|
||||
* before C_dispatch_irq_handler()
|
||||
* re-enables MSR_EE.
|
||||
* Note that PPC405 uses a different SPR# for TSR
|
||||
*/
|
||||
if (ppc_cpu_is_bookE()==PPC_BOOKE_405)
|
||||
_write_PPC405_TSR( BOOKE_TSR_DIS );
|
||||
else
|
||||
_write_BOOKE_TSR( BOOKE_TSR_DIS );
|
||||
return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR);
|
||||
}
|
||||
|
||||
/*
|
||||
* RTEMS Global Interrupt Handler Management Routines
|
||||
*/
|
||||
int BSP_rtems_irq_generic_set(rtems_irq_global_settings* config)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = BSP_setup_the_pic(config);
|
||||
if (!r)
|
||||
return r;
|
||||
|
||||
ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler);
|
||||
if ( ppc_cpu_is_bookE() ) {
|
||||
/* bookE decrementer interrupt needs to be cleared BEFORE
|
||||
* dispatching the user ISR (because the user ISR is called
|
||||
* with EE enabled)
|
||||
* We do this so that existing DEC handlers can be used
|
||||
* with minor modifications.
|
||||
*/
|
||||
ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE);
|
||||
} else {
|
||||
ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bsp_interrupt_vector_enable(rtems_vector_number vector)
|
||||
{
|
||||
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
||||
BSP_enable_irq_at_pic(vector);
|
||||
}
|
||||
|
||||
void bsp_interrupt_vector_disable(rtems_vector_number vector)
|
||||
{
|
||||
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
|
||||
BSP_disable_irq_at_pic(vector);
|
||||
}
|
||||
|
||||
rtems_status_code bsp_interrupt_facility_initialize(void)
|
||||
{
|
||||
/*
|
||||
* Initialize RTEMS IRQ system
|
||||
*/
|
||||
BSP_rtems_irq_mng_init(0);
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
Reference in New Issue
Block a user