forked from Imagelibrary/rtems
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:
@@ -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/irq_asm.h shared/irq/irq_asm.S
|
||||||
EXTRA_DIST += shared/irq/idt.c
|
EXTRA_DIST += shared/irq/idt.c
|
||||||
EXTRA_DIST += shared/irq/irq_init.c
|
EXTRA_DIST += shared/irq/irq_init.c
|
||||||
|
EXTRA_DIST += shared/irq/elcr.c
|
||||||
|
|
||||||
# shared/pci
|
# shared/pci
|
||||||
EXTRA_DIST += shared/pci/pcibios.c
|
EXTRA_DIST += shared/pci/pcibios.c
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ libbsp_a_SOURCES += startup/bspreset.c
|
|||||||
libbsp_a_SOURCES += ../../i386/shared/irq/idt.c
|
libbsp_a_SOURCES += ../../i386/shared/irq/idt.c
|
||||||
libbsp_a_SOURCES += ../../i386/shared/irq/irq.c
|
libbsp_a_SOURCES += ../../i386/shared/irq/irq.c
|
||||||
libbsp_a_SOURCES += ../../i386/shared/irq/irq_init.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/bootcard.c
|
||||||
libbsp_a_SOURCES += ../../shared/sbrk.c
|
libbsp_a_SOURCES += ../../shared/sbrk.c
|
||||||
libbsp_a_SOURCES += startup/ldsegs.S
|
libbsp_a_SOURCES += startup/ldsegs.S
|
||||||
|
|||||||
170
c/src/lib/libbsp/i386/shared/irq/elcr.c
Normal file
170
c/src/lib/libbsp/i386/shared/irq/elcr.c
Normal 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);
|
||||||
|
}
|
||||||
37
c/src/lib/libbsp/i386/shared/irq/elcr.h
Normal file
37
c/src/lib/libbsp/i386/shared/irq/elcr.h
Normal 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
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "elcr.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pointer to the mask representing the additionnal irq vectors
|
* pointer to the mask representing the additionnal irq vectors
|
||||||
* that must be disabled when a particular entry is activated.
|
* that must be disabled when a particular entry is activated.
|
||||||
@@ -27,137 +30,173 @@
|
|||||||
* CAUTION : this table is accessed directly by interrupt routine
|
* CAUTION : this table is accessed directly by interrupt routine
|
||||||
* prologue.
|
* 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)
|
* Edge or level trigger interrupts.
|
||||||
{
|
*/
|
||||||
uint32_t tot = 0;
|
static enum intr_trigger irq_trigger[BSP_IRQ_LINES_NUMBER];
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
/*-------------------------------------------------------------------------+
|
||||||
| 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.
|
* lower byte is interrupt mask on the master PIC.
|
||||||
* while upper bits are interrupt on the slave PIC.
|
* while upper bits are interrupt on the slave PIC.
|
||||||
* This cache is initialized in ldseg.s
|
* This cache is initialized in ldseg.s
|
||||||
*/
|
*/
|
||||||
rtems_i8259_masks i8259s_cache = 0xFFFB;
|
static rtems_i8259_masks i8259a_cache = 0xFFFB;
|
||||||
rtems_i8259_masks i8259s_super_imr = 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.
|
| 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.
|
| 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;
|
unsigned short mask;
|
||||||
rtems_interrupt_level level;
|
rtems_interrupt_level level;
|
||||||
|
|
||||||
if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
|
|
||||||
((int)irqLine > BSP_MAX_ON_i8259S )
|
|
||||||
)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
rtems_interrupt_disable(level);
|
rtems_interrupt_disable(level);
|
||||||
|
|
||||||
mask = 1 << irqLine;
|
mask = 1 << irqLine;
|
||||||
i8259s_cache |= mask;
|
i8259a_cache |= mask;
|
||||||
i8259s_super_imr |= mask;
|
|
||||||
|
|
||||||
if (irqLine < 8)
|
if (irqLine < 8)
|
||||||
{
|
{
|
||||||
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
|
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259a_cache & 0xff);
|
||||||
}
|
}
|
||||||
else
|
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);
|
rtems_interrupt_enable(level);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------+
|
/*-------------------------------------------------------------------------+
|
||||||
| Function: BSP_irq_enable_at_i8259s
|
| Function: BSP_irq_enable_at_i8259a
|
||||||
| Description: Unmask IRQ line in appropriate PIC chip.
|
| Description: Unmask IRQ line in appropriate PIC chip.
|
||||||
| Global Variables: i8259s_cache
|
| Global Variables: i8259a_cache
|
||||||
| Arguments: irqLine - number of IRQ line to mask.
|
| Arguments: irqLine - number of IRQ line to mask.
|
||||||
| Returns: Nothing.
|
| 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;
|
unsigned short mask;
|
||||||
rtems_interrupt_level level;
|
rtems_interrupt_level level;
|
||||||
|
uint8_t isr;
|
||||||
if ( ((int)irqLine < BSP_LOWEST_OFFSET) ||
|
uint8_t irr;
|
||||||
((int)irqLine > BSP_MAX_ON_i8259S )
|
|
||||||
)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
rtems_interrupt_disable(level);
|
rtems_interrupt_disable(level);
|
||||||
|
|
||||||
mask = ~(1 << irqLine);
|
mask = 1 << irqLine;
|
||||||
i8259s_cache &= mask;
|
i8259a_cache &= ~mask;
|
||||||
i8259s_super_imr &= mask;
|
|
||||||
|
|
||||||
if (irqLine < 8)
|
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
|
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);
|
rtems_interrupt_enable(level);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* mask_irq */
|
} /* 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.
|
| Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
|
||||||
| Global Variables: None.
|
| Global Variables: None.
|
||||||
| Arguments: irqLine - number of IRQ line to acknowledge.
|
| Arguments: irqLine - number of IRQ line to acknowledge.
|
||||||
| Returns: Nothing.
|
| 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) ||
|
uint8_t slave_isr = 0;
|
||||||
((int)irqLine > BSP_MAX_ON_i8259S )
|
|
||||||
)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (irqLine >= 8) {
|
if (irqLine >= 8) {
|
||||||
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
|
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);
|
outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -179,7 +218,7 @@ static rtems_irq_prio irqPrioTable[BSP_IRQ_LINES_NUMBER]={
|
|||||||
*/
|
*/
|
||||||
0,0,
|
0,0,
|
||||||
255,
|
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)
|
static void compute_i8259_masks_from_prio (void)
|
||||||
@@ -208,22 +247,29 @@ static void compute_i8259_masks_from_prio (void)
|
|||||||
rtems_interrupt_enable(level);
|
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)
|
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;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
|
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;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_status_code bsp_interrupt_facility_initialize(void)
|
rtems_status_code bsp_interrupt_facility_initialize(void)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set up internal tables used by rtems interrupt prologue
|
* 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
|
* 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;
|
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]++;
|
uint16_t old_imr = 0;
|
||||||
bsp_interrupt_handler_dispatch(vector);
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,28 +52,35 @@ extern "C" {
|
|||||||
|
|
||||||
/** @brief Base vector for our IRQ handlers. */
|
/** @brief Base vector for our IRQ handlers. */
|
||||||
#define BSP_IRQ_VECTOR_BASE BSP_ASM_IRQ_VECTOR_BASE
|
#define BSP_IRQ_VECTOR_BASE BSP_ASM_IRQ_VECTOR_BASE
|
||||||
#define BSP_IRQ_LINES_NUMBER 17
|
#define BSP_IRQ_LINES_NUMBER 16
|
||||||
#define BSP_LOWEST_OFFSET 0
|
#define BSP_IRQ_MAX_ON_i8259A (BSP_IRQ_LINES_NUMBER - 1)
|
||||||
#define BSP_MAX_ON_i8259S (BSP_IRQ_LINES_NUMBER - 2)
|
|
||||||
#define BSP_MAX_OFFSET (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
|
/** @brief
|
||||||
* Interrupt offset in comparison to BSP_ASM_IRQ_VECTOR_BASE
|
* Interrupt offset in comparison to BSP_ASM_IRQ_VECTOR_BASE
|
||||||
* NB : 1) Interrupt vector number in IDT = offset + 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
|
* 2) The same name should be defined on all architecture
|
||||||
* so that handler connection can be unchanged.
|
* so that handler connection can be unchanged.
|
||||||
*/
|
*/
|
||||||
#define BSP_PERIODIC_TIMER 0
|
#define BSP_PERIODIC_TIMER 0 /* fixed on all builds of PC */
|
||||||
#define BSP_KEYBOARD 1
|
#define BSP_KEYBOARD 1 /* fixed on all builds of PC */
|
||||||
#define BSP_UART_COM2_IRQ 3
|
#define BSP_UART_COM2_IRQ 3 /* fixed for ISA bus */
|
||||||
#define BSP_UART_COM1_IRQ 4
|
#define BSP_UART_COM1_IRQ 4 /* fixed for ISA bus */
|
||||||
#define BSP_UART_COM3_IRQ 5
|
#define BSP_UART_COM3_IRQ 5
|
||||||
#define BSP_UART_COM4_IRQ 6
|
#define BSP_UART_COM4_IRQ 6
|
||||||
#define BSP_RT_TIMER1 8
|
#define BSP_RT_TIMER1 8
|
||||||
#define BSP_RT_TIMER3 10
|
#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_MIN BSP_IRQ_VECTOR_LOWEST_OFFSET
|
||||||
#define BSP_INTERRUPT_VECTOR_MAX BSP_MAX_OFFSET
|
#define BSP_INTERRUPT_VECTOR_MAX BSP_IRQ_VECTOR_MAX_OFFSET
|
||||||
|
|
||||||
/** @brief
|
/** @brief
|
||||||
* Type definition for RTEMS managed interrupts
|
* Type definition for RTEMS managed interrupts
|
||||||
@@ -83,7 +90,7 @@ typedef unsigned short rtems_i8259_masks;
|
|||||||
/**
|
/**
|
||||||
* @brief Contains the current IMR of both i8259s.
|
* @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
|
* @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
|
* This enables a bsp_interrupt_vector_disable() in interrupt handlers. This
|
||||||
* is required for the interrupt server support used by the new network stack.
|
* 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.
|
| 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
|
* this function, even if the device asserts the interrupt line it will
|
||||||
* not be propagated further to the processor
|
* 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
|
/** @brief
|
||||||
* function to enable a particular irq at 8259 level. After calling
|
* function to enable a particular irq at 8259 level. After calling
|
||||||
* this function, if the device asserts the interrupt line it will
|
* this function, if the device asserts the interrupt line it will
|
||||||
* be propagated further to the processor
|
* 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
|
/** @brief
|
||||||
* function to acknoledge a particular irq at 8259 level. After calling
|
* function to acknoledge a particular irq at 8259 level. After calling
|
||||||
* this function, if a device asserts an enabled interrupt line it will
|
* 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
|
* writting raw handlers as this is automagically done for rtems managed
|
||||||
* handlers.
|
* handlers.
|
||||||
*/
|
*/
|
||||||
int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine);
|
//int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine);
|
||||||
/** @brief
|
/** @brief
|
||||||
* function to check if a particular irq is enabled at 8259 level. After calling
|
* 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);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include <rtems/asm.h>
|
#include <rtems/asm.h>
|
||||||
#include <rtems/system.h>
|
#include <rtems/system.h>
|
||||||
#include <bspopts.h>
|
#include <bspopts.h>
|
||||||
#include <bsp/irq_asm.h>
|
|
||||||
#include <rtems/score/cpu.h>
|
#include <rtems/score/cpu.h>
|
||||||
#include <rtems/score/percpu.h>
|
#include <rtems/score/percpu.h>
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@
|
|||||||
|
|
||||||
/* Stack frame we use for intermediate storage */
|
/* Stack frame we use for intermediate storage */
|
||||||
#define ARG_OFF 0
|
#define ARG_OFF 0
|
||||||
#define MSK_OFF 4
|
#define MSK_OFF 4 /* not used any more */
|
||||||
#define EBX_OFF 8 /* ebx */
|
#define EBX_OFF 8 /* ebx */
|
||||||
#define EBP_OFF 12 /* code restoring ebp/esp relies on */
|
#define EBP_OFF 12 /* code restoring ebp/esp relies on */
|
||||||
#define ESP_OFF 16 /* esp being on top of ebp! */
|
#define ESP_OFF 16 /* esp being on top of ebp! */
|
||||||
@@ -77,7 +76,7 @@ SYM (_ISR_Handler):
|
|||||||
* saved ebx
|
* saved ebx
|
||||||
* saved ebp
|
* saved ebp
|
||||||
* saved irq mask
|
* saved irq mask
|
||||||
* vector arg to C_dispatch_isr <- aligned SP
|
* vector arg to BSP_dispatch_isr <- aligned SP
|
||||||
*/
|
*/
|
||||||
movl esp, eax
|
movl esp, eax
|
||||||
subl $FRM_SIZ, esp
|
subl $FRM_SIZ, esp
|
||||||
@@ -86,6 +85,13 @@ SYM (_ISR_Handler):
|
|||||||
movl eax, ESP_OFF(esp)
|
movl eax, ESP_OFF(esp)
|
||||||
movl ebp, EBP_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__
|
#ifdef __SSE__
|
||||||
/* NOTE: SSE only is supported if the BSP enables fxsave/fxrstor
|
/* NOTE: SSE only is supported if the BSP enables fxsave/fxrstor
|
||||||
* to save/restore SSE context! This is so far only implemented
|
* 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 */
|
ldmxcsr ARG_OFF(esp) /* clean-slate MXCSR */
|
||||||
#endif
|
#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
|
* Now switch stacks if necessary
|
||||||
*/
|
*/
|
||||||
@@ -171,19 +144,6 @@ nested:
|
|||||||
incl PER_CPU_ISR_NEST_LEVEL(ebx) /* one nest level deeper */
|
incl PER_CPU_ISR_NEST_LEVEL(ebx) /* one nest level deeper */
|
||||||
incl PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) /* disable
|
incl PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) /* disable
|
||||||
multitasking */
|
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
|
* ECX is preloaded with the vector number; store as arg
|
||||||
* on top of stack. Note that _CPU_Interrupt_stack_high
|
* 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 */
|
movl ecx, ARG_OFF(esp) /* store vector arg in stack */
|
||||||
call C_dispatch_isr
|
call BSP_dispatch_isr
|
||||||
|
|
||||||
/*
|
|
||||||
* disable interrupts_again
|
|
||||||
*/
|
|
||||||
cli
|
|
||||||
|
|
||||||
movl ARG_OFF(esp), ecx /* grab vector arg from stack */
|
movl ARG_OFF(esp), ecx /* grab vector arg from stack */
|
||||||
|
|
||||||
@@ -207,22 +162,6 @@ nested:
|
|||||||
*/
|
*/
|
||||||
movl ebp, esp
|
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 */
|
decl PER_CPU_ISR_NEST_LEVEL(ebx) /* one less ISR nest level */
|
||||||
/* If interrupts are nested, */
|
/* If interrupts are nested, */
|
||||||
/* then dispatching is disabled */
|
/* then dispatching is disabled */
|
||||||
|
|||||||
@@ -12,12 +12,14 @@
|
|||||||
*
|
*
|
||||||
* COPYRIGHT (c) 1998 valette@crf.canon.fr
|
* 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
|
* The license and distribution terms for this file may be
|
||||||
* found in the file LICENSE in this distribution or at
|
* found in the file LICENSE in this distribution or at
|
||||||
* http://www.rtems.org/license/LICENSE.
|
* http://www.rtems.org/license/LICENSE.
|
||||||
*/
|
*/
|
||||||
#ifndef __IRQ_ASM_H__
|
#ifndef __I8259S_H__
|
||||||
#define __IRQ_ASM_H__
|
#define __I8259S_H__
|
||||||
|
|
||||||
#define BSP_ASM_IRQ_VECTOR_BASE 0x20
|
#define BSP_ASM_IRQ_VECTOR_BASE 0x20
|
||||||
/** @brief PIC's command and mask registers */
|
/** @brief PIC's command and mask registers */
|
||||||
@@ -30,4 +32,14 @@
|
|||||||
#define PIC_EOSI 0x60 ///< End of Specific Interrupt (EOSI)
|
#define PIC_EOSI 0x60 ///< End of Specific Interrupt (EOSI)
|
||||||
#define PIC_EOI 0x20 ///< Generic End of Interrupt (EOI)
|
#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
|
#endif
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ static int raw_not_connected(
|
|||||||
|
|
||||||
static rtems_raw_irq_connect_data idtHdl[IDT_SIZE];
|
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_0,
|
||||||
rtems_irq_prologue_1,
|
rtems_irq_prologue_1,
|
||||||
rtems_irq_prologue_2,
|
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
|
* Patch the entry that will be used by RTEMS for interrupt management
|
||||||
* with RTEMS prologue.
|
* 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]);
|
create_interrupt_gate_descriptor(&idtEntry, rtemsIrq[i]);
|
||||||
idt_entry_tbl[i + BSP_ASM_IRQ_VECTOR_BASE] = idtEntry;
|
idt_entry_tbl[i + BSP_ASM_IRQ_VECTOR_BASE] = idtEntry;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user