i386/pc386: Fix interrupt support.

Fix the interrupt and stop the spurious interrupt from happening.

The fix moves the EOI to C code and cleans that functionality out
of the asm part of the ISR handler.

The code checks the ISR and IRR registers on the enable.

Only ack the master for a slave IRQ if the slave has no other pending
requests.
This commit is contained in:
Chris Johns
2016-05-06 17:55:29 +10:00
parent 292dbff069
commit 93fb879796
9 changed files with 471 additions and 172 deletions

View File

@@ -19,6 +19,7 @@ EXTRA_DIST += shared/irq/irq.h shared/irq/irq.c
EXTRA_DIST += shared/irq/irq_asm.h shared/irq/irq_asm.S
EXTRA_DIST += shared/irq/idt.c
EXTRA_DIST += shared/irq/irq_init.c
EXTRA_DIST += shared/irq/elcr.c
# shared/pci
EXTRA_DIST += shared/pci/pcibios.c

View File

@@ -161,6 +161,7 @@ libbsp_a_SOURCES += startup/bspreset.c
libbsp_a_SOURCES += ../../i386/shared/irq/idt.c
libbsp_a_SOURCES += ../../i386/shared/irq/irq.c
libbsp_a_SOURCES += ../../i386/shared/irq/irq_init.c
libbsp_a_SOURCES += ../../i386/shared/irq/elcr.c
libbsp_a_SOURCES += ../../shared/bootcard.c
libbsp_a_SOURCES += ../../shared/sbrk.c
libbsp_a_SOURCES += startup/ldsegs.S

View File

@@ -0,0 +1,170 @@
/*-
* Copyright (c) 2004 John Baldwin <jhb@FreeBSD.org>
* 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 AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
#ifndef __rtems__
__FBSDID("$FreeBSD$");
#endif /* __rtems__ */
/*
* The ELCR is a register that controls the trigger mode and polarity of
* EISA and ISA interrupts. In FreeBSD 3.x and 4.x, the ELCR was only
* consulted for determining the appropriate trigger mode of EISA
* interrupts when using an APIC. However, it seems that almost all
* systems that include PCI also include an ELCR that manages the ISA
* IRQs 0 through 15. Thus, we check for the presence of an ELCR on
* every machine by checking to see if the values found at bootup are
* sane. Note that the polarity of ISA and EISA IRQs are linked to the
* trigger mode. All edge triggered IRQs use active-hi polarity, and
* all level triggered interrupts use active-lo polarity.
*
* The format of the ELCR is simple: it is a 16-bit bitmap where bit 0
* controls IRQ 0, bit 1 controls IRQ 1, etc. If the bit is zero, the
* associated IRQ is edge triggered. If the bit is one, the IRQ is
* level triggered.
*/
#ifndef __rtems__
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/systm.h>
#include <machine/intr_machdep.h>
#endif /* __rtems__ */
#ifdef __rtems__
#include <bsp.h>
#include "i386_io.h"
#include <errno.h>
#include "elcr.h"
#endif /* __rtems__ */
#define ELCR_PORT 0x4d0
#define ELCR_MASK(irq) (1 << (irq))
static int elcr_status;
#ifdef __rtems__
static
#endif /* __rtems__ */
int elcr_found;
#ifdef __rtems__
#undef printf
#define printf printk
#define bootverbose 1
#define KASSERT(...)
#endif /* __rtems__ */
/*
* Check to see if we have what looks like a valid ELCR. We do this by
* verifying that IRQs 0, 1, 2, and 13 are all edge triggered.
*/
int
elcr_probe(void)
{
int i;
elcr_status = inb(ELCR_PORT) | inb(ELCR_PORT + 1) << 8;
if ((elcr_status & (ELCR_MASK(0) | ELCR_MASK(1) | ELCR_MASK(2) |
ELCR_MASK(8) | ELCR_MASK(13))) != 0)
return (ENXIO);
if (bootverbose) {
printf("ELCR Found. ISA IRQs programmed as:\n");
for (i = 0; i < 16; i++)
printf(" %2d", i);
printf("\n");
for (i = 0; i < 16; i++)
if (elcr_status & ELCR_MASK(i))
printf(" L");
else
printf(" E");
printf("\n");
}
#ifndef __rtems__
if (resource_disabled("elcr", 0))
return (ENXIO);
#endif /* __rtems__ */
elcr_found = 1;
return (0);
}
/*
* Returns 1 for level trigger, 0 for edge.
*/
enum intr_trigger
elcr_read_trigger(u_int irq)
{
#ifdef __rtems__
if (!elcr_found)
return INTR_TRIGGER_EDGE;
#endif /* __rtems__ */
KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq));
if (elcr_status & ELCR_MASK(irq))
return (INTR_TRIGGER_LEVEL);
else
return (INTR_TRIGGER_EDGE);
}
/*
* Set the trigger mode for a specified IRQ. Mode of 0 means edge triggered,
* and a mode of 1 means level triggered.
*/
void
elcr_write_trigger(u_int irq, enum intr_trigger trigger)
{
int new_status;
#ifdef __rtems__
if (!elcr_found)
return;
#endif /* __rtems__ */
KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
KASSERT(irq <= 15, ("%s: invalid IRQ %u", __func__, irq));
if (trigger == INTR_TRIGGER_LEVEL)
new_status = elcr_status | ELCR_MASK(irq);
else
new_status = elcr_status & ~ELCR_MASK(irq);
if (new_status == elcr_status)
return;
elcr_status = new_status;
if (irq >= 8)
outb(ELCR_PORT + 1, elcr_status >> 8);
else
outb(ELCR_PORT, elcr_status & 0xff);
}
void
elcr_resume(void)
{
#ifdef __rtems__
if (!elcr_found)
return;
#endif /* __rtems__ */
KASSERT(elcr_found, ("%s: no ELCR was found!", __func__));
outb(ELCR_PORT, elcr_status & 0xff);
outb(ELCR_PORT + 1, elcr_status >> 8);
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2016 Chris Johns <chrisj@rtems.org>
*
* Header for the FreeBSD ported elcr.c
*/
#ifndef _IRQ_ELCR_H_
#define _IRQ_ELCR_H_
#include <sys/cdefs.h>
enum intr_trigger {
INTR_TRIGGER_EDGE,
INTR_TRIGGER_LEVEL
};
/*
* Check to see if we have what looks like a valid ELCR. We do this by
* verifying that IRQs 0, 1, 2, and 13 are all edge triggered.
*/
int elcr_probe(void);
/*
* Returns 1 for level trigger, 0 for edge.
*/
enum intr_trigger elcr_read_trigger(u_int irq);
/*
* Set the trigger mode for a specified IRQ. Mode of 0 means edge triggered,
* and a mode of 1 means level triggered.
*/
void elcr_write_trigger(u_int irq, enum intr_trigger trigger);
void elcr_resume(void);
#endif

View File

@@ -19,6 +19,9 @@
#include <stdio.h>
#include <inttypes.h>
#include "elcr.h"
/*
* pointer to the mask representing the additionnal irq vectors
* that must be disabled when a particular entry is activated.
@@ -27,137 +30,173 @@
* CAUTION : this table is accessed directly by interrupt routine
* prologue.
*/
rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER];
static rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER];
uint32_t irq_count[BSP_IRQ_LINES_NUMBER] = {0};
/*
* Stats of interrupts dispatched.
*/
static uint32_t irq_count[BSP_IRQ_VECTOR_NUMBER] = {0};
static uint32_t spurious_count;
uint32_t
BSP_irq_count_dump(FILE *f)
{
uint32_t tot = 0;
int i;
if ( !f )
f = stdout;
for ( i=0; i<BSP_IRQ_LINES_NUMBER; i++ ) {
tot += irq_count[i];
fprintf(f,"IRQ %2u: %9"PRIu32"\n", i, irq_count[i]);
}
return tot;
}
/*
* Edge or level trigger interrupts.
*/
static enum intr_trigger irq_trigger[BSP_IRQ_LINES_NUMBER];
/*-------------------------------------------------------------------------+
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
| Cache for 1st and 2nd PIC IRQ line's mssk (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
*/
rtems_i8259_masks i8259s_cache = 0xFFFB;
rtems_i8259_masks i8259s_super_imr = 0xFFFB;
static rtems_i8259_masks i8259a_cache = 0xFFFB;
/*
* Print the stats.
*/
uint32_t BSP_irq_count_dump(FILE *f)
{
uint32_t tot = 0;
int i;
if ( !f )
f = stdout;
fprintf(f,"SPURIOUS: %9"PRIu32"\n", spurious_count);
for ( i = 0; i < BSP_IRQ_VECTOR_NUMBER; i++ ) {
char type = '-';
if (i < BSP_IRQ_LINES_NUMBER)
type = irq_trigger[i] == INTR_TRIGGER_EDGE ? 'E' : 'L';
tot += irq_count[i];
fprintf(f,"IRQ %2u: %c %9"PRIu32"\n", i, type, irq_count[i]);
}
return tot;
}
/*
* Is the IRQ valid?
*/
static inline bool BSP_i8259a_irq_valid(const rtems_irq_number irqLine)
{
return ((int)irqLine >= BSP_IRQ_VECTOR_LOWEST_OFFSET) &&
((int)irqLine <= BSP_IRQ_MAX_ON_i8259A);
}
/*
* Read the IRR register. The default.
*/
static inline uint8_t BSP_i8259a_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_i8259a_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
| Function: BSP_irq_disable_at_i8259a
| Description: Mask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Global Variables: i8259a_cache
| Arguments: vector_offset - number of IRQ line to mask.
| Returns: Nothing.
| Returns: 0 is OK.
+--------------------------------------------------------------------------*/
int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine)
static int BSP_irq_disable_at_i8259a(const rtems_irq_number irqLine)
{
unsigned short mask;
rtems_interrupt_level level;
if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
((int)irqLine > BSP_MAX_ON_i8259S )
)
return 1;
rtems_interrupt_disable(level);
mask = 1 << irqLine;
i8259s_cache |= mask;
i8259s_super_imr |= mask;
i8259a_cache |= mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259a_cache & 0xff);
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
outport_byte(PIC_SLAVE_IMR_IO_PORT, (i8259a_cache >> 8) & 0xff);
}
rtems_interrupt_enable(level);
return 0;
}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_enable_at_i8259s
| Function: BSP_irq_enable_at_i8259a
| Description: Unmask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Global Variables: i8259a_cache
| Arguments: irqLine - number of IRQ line to mask.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine)
static int BSP_irq_enable_at_i8259a(const rtems_irq_number irqLine)
{
unsigned short mask;
rtems_interrupt_level level;
if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
((int)irqLine > BSP_MAX_ON_i8259S )
)
return 1;
uint8_t isr;
uint8_t irr;
rtems_interrupt_disable(level);
mask = ~(1 << irqLine);
i8259s_cache &= mask;
i8259s_super_imr &= mask;
mask = 1 << irqLine;
i8259a_cache &= ~mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
irr = BSP_i8259a_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259a_cache & 0xff);
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
irr = BSP_i8259a_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
outport_byte(PIC_SLAVE_IMR_IO_PORT, (i8259a_cache >> 8) & 0xff);
}
if (((isr ^ irr) & mask) != 0)
printk("i386: isr=%x irr=%x\n", isr, irr);
rtems_interrupt_enable(level);
return 0;
} /* mask_irq */
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
{
unsigned short mask;
if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
((int)irqLine > BSP_MAX_ON_i8259S )
)
return 1;
mask = (1 << irqLine);
return (~(i8259s_cache & mask));
}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_ack_at_i8259s
| Function: BSP_irq_ack_at_i8259a
| 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_number irqLine)
static int BSP_irq_ack_at_i8259a(const rtems_irq_number irqLine)
{
if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
((int)irqLine > BSP_MAX_ON_i8259S )
)
return 1;
uint8_t slave_isr = 0;
if (irqLine >= 8) {
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
slave_isr = BSP_i8259a_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;
@@ -179,7 +218,7 @@ static rtems_irq_prio irqPrioTable[BSP_IRQ_LINES_NUMBER]={
*/
0,0,
255,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static void compute_i8259_masks_from_prio (void)
@@ -208,22 +247,29 @@ static void compute_i8259_masks_from_prio (void)
rtems_interrupt_enable(level);
}
static inline bool bsp_interrupt_vector_is_valid(rtems_vector_number vector)
{
return BSP_i8259a_irq_valid((const rtems_irq_number) vector);
}
rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
{
BSP_irq_enable_at_i8259s(vector);
if (bsp_interrupt_vector_is_valid(vector))
BSP_irq_enable_at_i8259a(vector);
return RTEMS_SUCCESSFUL;
}
rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
{
BSP_irq_disable_at_i8259s(vector);
if (bsp_interrupt_vector_is_valid(vector))
BSP_irq_disable_at_i8259a(vector);
return RTEMS_SUCCESSFUL;
}
rtems_status_code bsp_interrupt_facility_initialize(void)
{
int i;
/*
* set up internal tables used by rtems interrupt prologue
*/
@@ -232,13 +278,99 @@ rtems_status_code bsp_interrupt_facility_initialize(void)
/*
* must enable slave pic anyway
*/
BSP_irq_enable_at_i8259s(2);
BSP_irq_enable_at_i8259a(2);
/*
* Probe the ELCR.
*/
elcr_probe();
for (i = 0; i < BSP_IRQ_LINES_NUMBER; i++)
irq_trigger[i] = elcr_read_trigger(i);
return RTEMS_SUCCESSFUL;
}
void C_dispatch_isr(int vector)
/*
* Global so the asm handler can call it.
*/
void BSP_dispatch_isr(int vector);
void BSP_dispatch_isr(int vector)
{
irq_count[vector]++;
bsp_interrupt_handler_dispatch(vector);
uint16_t old_imr = 0;
if (vector < BSP_IRQ_VECTOR_NUMBER) {
/*
* Hardware?
*/
if (vector <= BSP_IRQ_MAX_ON_i8259A) {
/*
* See if this is a spurious interrupt.
*/
if ((vector == 7 || vector == 15)) {
/*
* Only check it there no handler for 7 or 15.
*/
if (bsp_interrupt_handler_is_empty(vector)) {
/*
* Read the ISR register to see if IRQ 7/15 is really pending.
*/
uint8_t isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
if ((isr & (1 << 7)) == 0) {
++spurious_count;
return;
}
}
}
/*
* Save the current cached value for the IMR. It will have the bit for this
* vector clear.
*/
if (vector <= BSP_IRQ_MAX_ON_i8259A) {
old_imr = i8259a_cache;
i8259a_cache |= irq_mask_or_tbl[vector];
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259a_cache & 0xff);
outport_byte(PIC_SLAVE_IMR_IO_PORT, (i8259a_cache >> 8) & 0xff);
}
/*
* Do not use auto-EOI as some slave PIC do not work correctly.
*/
BSP_irq_ack_at_i8259a(vector);
}
/*
* Count the interrupt.
*/
irq_count[vector]++;
/*
* Allow nesting.
*/
__asm__ __volatile__("sti");
bsp_interrupt_handler_dispatch(vector);
/*
* Disallow nesting.
*/
__asm__ __volatile__("cli");
if (vector <= BSP_IRQ_MAX_ON_i8259A) {
/*
* Put the mask back but keep this vector masked if the trigger type is
* level. The driver or a thread level interrupt server needs to enable it
* again.
*/
if (vector <= BSP_IRQ_MAX_ON_i8259A) {
if (irq_trigger[vector] == INTR_TRIGGER_LEVEL)
old_imr |= 1 << vector;
i8259a_cache = old_imr;
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259a_cache & 0xff);
outport_byte(PIC_SLAVE_IMR_IO_PORT, (i8259a_cache >> 8) & 0xff);
}
}
}
}

View File

@@ -52,28 +52,35 @@ extern "C" {
/** @brief Base vector for our IRQ handlers. */
#define BSP_IRQ_VECTOR_BASE BSP_ASM_IRQ_VECTOR_BASE
#define BSP_IRQ_LINES_NUMBER 17
#define BSP_LOWEST_OFFSET 0
#define BSP_MAX_ON_i8259S (BSP_IRQ_LINES_NUMBER - 2)
#define BSP_MAX_OFFSET (BSP_IRQ_LINES_NUMBER - 1)
#define BSP_IRQ_LINES_NUMBER 16
#define BSP_IRQ_MAX_ON_i8259A (BSP_IRQ_LINES_NUMBER - 1)
/*
* Define the number of valid vectors. This is different to the number of IRQ
* signals supported. Use this value to allocation vector data or range check.
*/
#define BSP_IRQ_VECTOR_NUMBER 17
#define BSP_IRQ_VECTOR_LOWEST_OFFSET 0
#define BSP_IRQ_VECTOR_MAX_OFFSET (BSP_IRQ_VECTOR_NUMBER - 1)
/** @brief
* Interrupt offset in comparison to BSP_ASM_IRQ_VECTOR_BASE
* NB : 1) Interrupt vector number in IDT = offset + BSP_ASM_IRQ_VECTOR_BASE
* 2) The same name should be defined on all architecture
* so that handler connection can be unchanged.
*/
#define BSP_PERIODIC_TIMER 0
#define BSP_KEYBOARD 1
#define BSP_UART_COM2_IRQ 3
#define BSP_UART_COM1_IRQ 4
#define BSP_PERIODIC_TIMER 0 /* fixed on all builds of PC */
#define BSP_KEYBOARD 1 /* fixed on all builds of PC */
#define BSP_UART_COM2_IRQ 3 /* fixed for ISA bus */
#define BSP_UART_COM1_IRQ 4 /* fixed for ISA bus */
#define BSP_UART_COM3_IRQ 5
#define BSP_UART_COM4_IRQ 6
#define BSP_RT_TIMER1 8
#define BSP_RT_TIMER3 10
#define BSP_SMP_IPI 16
#define BSP_SMP_IPI 16 /* not part of the ATPIC */
#define BSP_INTERRUPT_VECTOR_MIN BSP_LOWEST_OFFSET
#define BSP_INTERRUPT_VECTOR_MAX BSP_MAX_OFFSET
#define BSP_INTERRUPT_VECTOR_MIN BSP_IRQ_VECTOR_LOWEST_OFFSET
#define BSP_INTERRUPT_VECTOR_MAX BSP_IRQ_VECTOR_MAX_OFFSET
/** @brief
* Type definition for RTEMS managed interrupts
@@ -83,7 +90,7 @@ typedef unsigned short rtems_i8259_masks;
/**
* @brief Contains the current IMR of both i8259s.
*/
extern rtems_i8259_masks i8259s_cache;
//extern rtems_i8259_masks i8259s_cache;
/**
* @brief Contains the super IMR of both i8259s to overrule i8259s_cache during
@@ -92,7 +99,7 @@ extern rtems_i8259_masks i8259s_cache;
* This enables a bsp_interrupt_vector_disable() in interrupt handlers. This
* is required for the interrupt server support used by the new network stack.
*/
extern rtems_i8259_masks i8259s_super_imr;
//extern rtems_i8259_masks i8259s_super_imr;
/*-------------------------------------------------------------------------+
| Function Prototypes.
@@ -106,13 +113,13 @@ extern rtems_i8259_masks i8259s_super_imr;
* 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_number irqLine);
//int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine);
/** @brief
* 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_number irqLine);
//int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine);
/** @brief
* function to acknoledge a particular irq at 8259 level. After calling
* this function, if a device asserts an enabled interrupt line it will
@@ -120,11 +127,11 @@ int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine);
* writting raw handlers as this is automagically done for rtems managed
* handlers.
*/
int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine);
//int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine);
/** @brief
* function to check if a particular irq is enabled at 8259 level. After calling
*/
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine);
//int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine);
/** @} */

View File

@@ -16,7 +16,6 @@
#include <rtems/asm.h>
#include <rtems/system.h>
#include <bspopts.h>
#include <bsp/irq_asm.h>
#include <rtems/score/cpu.h>
#include <rtems/score/percpu.h>
@@ -28,7 +27,7 @@
/* Stack frame we use for intermediate storage */
#define ARG_OFF 0
#define MSK_OFF 4
#define MSK_OFF 4 /* not used any more */
#define EBX_OFF 8 /* ebx */
#define EBP_OFF 12 /* code restoring ebp/esp relies on */
#define ESP_OFF 16 /* esp being on top of ebp! */
@@ -77,7 +76,7 @@ SYM (_ISR_Handler):
* saved ebx
* saved ebp
* saved irq mask
* vector arg to C_dispatch_isr <- aligned SP
* vector arg to BSP_dispatch_isr <- aligned SP
*/
movl esp, eax
subl $FRM_SIZ, esp
@@ -86,6 +85,13 @@ SYM (_ISR_Handler):
movl eax, ESP_OFF(esp)
movl ebp, EBP_OFF(esp)
/*
* GCC versions starting with 4.3 no longer place the cld
* instruction before string operations. We need to ensure
* it is set correctly for ISR handlers.
*/
cld
#ifdef __SSE__
/* NOTE: SSE only is supported if the BSP enables fxsave/fxrstor
* to save/restore SSE context! This is so far only implemented
@@ -105,39 +111,6 @@ SYM (_ISR_Handler):
ldmxcsr ARG_OFF(esp) /* clean-slate MXCSR */
#endif
/* Do not disable any 8259 interrupts if this isn't from one */
cmp ecx, 16 /* is this a PIC IRQ? */
jge .check_stack_switch
/*
* acknowledge the interrupt
*/
movw SYM (i8259s_cache), ax /* save current i8259 interrupt mask */
movl eax, MSK_OFF(esp) /* save in stack frame */
/*
* compute the new PIC mask:
*
* <new mask> = <old mask> | irq_mask_or_tbl[<intr number aka ecx>]
*/
movw SYM (irq_mask_or_tbl) (,ecx,2), dx
orw dx, ax
/*
* Install new computed value on the i8259 and update cache
* accordingly
*/
movw ax, SYM (i8259s_cache)
outb $PIC_MASTER_IMR_IO_PORT
movb ah, al
outb $PIC_SLAVE_IMR_IO_PORT
movb $PIC_EOI, al
cmpl $7, ecx
jbe .master
outb $PIC_SLAVE_COMMAND_IO_PORT
.master:
outb $PIC_MASTER_COMMAND_IO_PORT
/*
* Now switch stacks if necessary
*/
@@ -171,19 +144,6 @@ nested:
incl PER_CPU_ISR_NEST_LEVEL(ebx) /* one nest level deeper */
incl PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) /* disable
multitasking */
/*
* GCC versions starting with 4.3 no longer place the cld
* instruction before string operations. We need to ensure
* it is set correctly for ISR handlers.
*/
cld
/*
* re-enable interrupts at processor level as the current
* interrupt source is now masked via i8259
*/
sti
/*
* ECX is preloaded with the vector number; store as arg
* on top of stack. Note that _CPU_Interrupt_stack_high
@@ -192,12 +152,7 @@ nested:
*/
movl ecx, ARG_OFF(esp) /* store vector arg in stack */
call C_dispatch_isr
/*
* disable interrupts_again
*/
cli
call BSP_dispatch_isr
movl ARG_OFF(esp), ecx /* grab vector arg from stack */
@@ -207,22 +162,6 @@ nested:
*/
movl ebp, esp
/*
* restore the original i8259 masks
*/
/* Do not touch 8259 interrupts if this isn't from one */
cmp ecx, 16 /* is this a PIC IRQ? */
jge .dont_restore_i8259
movw SYM (i8259s_super_imr), dx
movl MSK_OFF(esp), eax
orw dx, ax
movw ax, SYM (i8259s_cache)
outb $PIC_MASTER_IMR_IO_PORT
movb ah, al
outb $PIC_SLAVE_IMR_IO_PORT
.dont_restore_i8259:
decl PER_CPU_ISR_NEST_LEVEL(ebx) /* one less ISR nest level */
/* If interrupts are nested, */
/* then dispatching is disabled */

View File

@@ -12,12 +12,14 @@
*
* COPYRIGHT (c) 1998 valette@crf.canon.fr
*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#ifndef __IRQ_ASM_H__
#define __IRQ_ASM_H__
#ifndef __I8259S_H__
#define __I8259S_H__
#define BSP_ASM_IRQ_VECTOR_BASE 0x20
/** @brief PIC's command and mask registers */
@@ -30,4 +32,14 @@
#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 */
#endif

View File

@@ -66,7 +66,7 @@ static int raw_not_connected(
static rtems_raw_irq_connect_data idtHdl[IDT_SIZE];
static rtems_raw_irq_hdl rtemsIrq[BSP_IRQ_LINES_NUMBER] = {
static rtems_raw_irq_hdl rtemsIrq[BSP_IRQ_VECTOR_NUMBER] = {
rtems_irq_prologue_0,
rtems_irq_prologue_1,
rtems_irq_prologue_2,
@@ -149,7 +149,7 @@ void rtems_irq_mngt_init(void)
* Patch the entry that will be used by RTEMS for interrupt management
* with RTEMS prologue.
*/
for (i = 0; i < BSP_IRQ_LINES_NUMBER; i++) {
for (i = 0; i < BSP_IRQ_VECTOR_NUMBER; i++) {
create_interrupt_gate_descriptor(&idtEntry, rtemsIrq[i]);
idt_entry_tbl[i + BSP_ASM_IRQ_VECTOR_BASE] = idtEntry;
}