[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 6/6] ioapic support switchable back to pic
From: |
Damien Zammit |
Subject: |
[PATCH 6/6] ioapic support switchable back to pic |
Date: |
Sun, 28 Mar 2021 17:03:20 +1100 |
Use --enable-ncpus=x where x > 1 for SMP+APIC support.
Use --enable-apic=no for no SMP and old PIC support.
---
i386/Makefrag.am | 13 +-
i386/configfrag.ac | 12 +
i386/i386/apic.h | 4 +-
i386/i386/fpu.c | 2 +-
i386/i386/irq.c | 9 +-
i386/i386/irq.h | 6 +-
i386/i386/pit.c | 38 ++-
i386/i386/pit.h | 2 +
i386/i386at/autoconf.c | 2 +-
i386/i386at/interrupt.S | 27 ++-
i386/i386at/ioapic.c | 398 +++++++++++++++++++++++++++++++
i386/i386at/kd_mouse.c | 2 +-
i386/i386at/model_dep.c | 21 +-
linux/dev/arch/i386/kernel/irq.c | 26 +-
14 files changed, 524 insertions(+), 38 deletions(-)
create mode 100644 i386/i386at/ioapic.c
diff --git a/i386/Makefrag.am b/i386/Makefrag.am
index 73df45f4..679c0a3d 100644
--- a/i386/Makefrag.am
+++ b/i386/Makefrag.am
@@ -57,7 +57,6 @@ libkernel_a_SOURCES += \
i386/i386at/kdsoft.h \
i386/i386at/mem.c \
i386/i386at/mem.h \
- i386/i386at/pic_isa.c \
i386/i386at/rtc.c \
i386/i386at/rtc.h
endif
@@ -163,10 +162,18 @@ libkernel_a_SOURCES += \
i386/i386/io_map.c \
i386/i386/irq.c \
i386/i386/irq.h \
- i386/i386/pic.c \
- i386/i386/pic.h \
i386/i386/pit.c \
i386/i386/pit.h
+
+if enable_apic
+libkernel_a_SOURCES += \
+ i386/i386at/ioapic.c
+else
+libkernel_a_SOURCES += \
+ i386/i386/pic.c \
+ i386/i386/pic.h \
+ i386/i386at/pic_isa.c
+endif
endif
#
diff --git a/i386/configfrag.ac b/i386/configfrag.ac
index bf4af110..9a39ccbb 100644
--- a/i386/configfrag.ac
+++ b/i386/configfrag.ac
@@ -92,6 +92,18 @@ if [ x"$enable_lpr" = xyes ]; then]
AM_CONDITIONAL([enable_lpr], [false])
[fi]
+AC_ARG_ENABLE([apic],
+ AS_HELP_STRING([--enable-apic], [LAPIC/IOAPIC support (ix86-only); enabled
by default]))
+[case $host_platform:$host_cpu in
+ *:i?86)
+ enable_apic=${enable_apic-yes};;
+esac
+if [ x"$enable_apic" = xyes ]; then]
+ AC_DEFINE([APIC], [1], [APIC support])
+ AM_CONDITIONAL([enable_apic], [true])
+[else]
+ AM_CONDITIONAL([enable_apic], [false])
+[fi]
[case $host_platform:$host_cpu in
xen:i?86)
diff --git a/i386/i386/apic.h b/i386/i386/apic.h
index 54ccda5b..83f7776c 100644
--- a/i386/i386/apic.h
+++ b/i386/i386/apic.h
@@ -107,10 +107,10 @@ typedef struct IoApicData {
ApicIoUnit *ioapic;
} IoApicData;
-#define APIC_IRQ_OVERRIDE_ACTIVE_LOW 2
#define APIC_IRQ_OVERRIDE_POLARITY_MASK 1
-#define APIC_IRQ_OVERRIDE_LEVEL_TRIGGERED 8
+#define APIC_IRQ_OVERRIDE_ACTIVE_LOW 2
#define APIC_IRQ_OVERRIDE_TRIGGER_MASK 4
+#define APIC_IRQ_OVERRIDE_LEVEL_TRIGGERED 8
typedef struct IrqOverrideData {
uint8_t bus;
diff --git a/i386/i386/fpu.c b/i386/i386/fpu.c
index a8459d65..cdfe264b 100644
--- a/i386/i386/fpu.c
+++ b/i386/i386/fpu.c
@@ -51,7 +51,7 @@
#include <i386/thread.h>
#include <i386/fpu.h>
#include <i386/pio.h>
-#include <i386/pic.h>
+#include <i386/irq.h>
#include <i386/locore.h>
#include <i386/trap.h>
#include "cpu_number.h"
diff --git a/i386/i386/irq.c b/i386/i386/irq.c
index 35681191..42921617 100644
--- a/i386/i386/irq.c
+++ b/i386/i386/irq.c
@@ -29,7 +29,10 @@ extern queue_head_t main_intr_queue;
static void
irq_eoi (struct irqdev *dev, int id)
{
- /* TODO EOI(dev->irq[id]) */
+#ifdef APIC
+ ioapic_irq_eoi (dev->irq[id]);
+ lapic_eoi ();
+#endif
}
static unsigned int ndisabled_irq[NINTR];
@@ -62,6 +65,10 @@ __enable_irq (irq_t irq_nr)
struct irqdev irqtab = {
"irq", irq_eoi, &main_intr_queue, 0,
+#ifdef APIC
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23},
+#else
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+#endif
};
diff --git a/i386/i386/irq.h b/i386/i386/irq.h
index d48a8e92..72bbe57b 100644
--- a/i386/i386/irq.h
+++ b/i386/i386/irq.h
@@ -15,7 +15,11 @@
#ifndef _I386_IRQ_H
#define _I386_IRQ_H
-#include <i386/pic.h>
+#ifdef APIC
+# include <i386/apic.h>
+#else
+# include <i386/pic.h>
+#endif
typedef unsigned int irq_t;
diff --git a/i386/i386/pit.c b/i386/i386/pit.c
index 4e3feeec..1cc5bc19 100644
--- a/i386/i386/pit.c
+++ b/i386/i386/pit.c
@@ -51,7 +51,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <kern/mach_clock.h>
#include <i386/ipl.h>
-#include <i386/pic.h>
+#include <machine/irq.h>
#include <i386/pit.h>
#include <i386/pio.h>
#include <kern/cpu_number.h>
@@ -66,14 +66,44 @@ int pit0_mode = PIT_C0|PIT_SQUAREMODE|PIT_READMODE ;
unsigned int clknumb = CLKNUM; /* interrupt interval for timer 0 */
void
-clkstart(void)
+pit_prepare_sleep(int hz)
{
- unsigned char byte;
- unsigned long s;
+ /* Prepare to sleep for 1/hz seconds */
+ int val = 0;
+ int lsb, msb;
+
+ val = (inb(0x61) & 0xfd) | 0x1;
+ outb(0x61, val);
+ outb(0x43, 0xb2);
+ val = CLKNUM / hz;
+ lsb = val & 0xff;
+ msb = val >> 8;
+ outb(0x42, lsb);
+ val = inb(0x60);
+ outb(0x42, msb);
+ /* Start counting down */
+ val = inb(0x61) & 0xfe;
+ outb(0x61, val); /* Gate low */
+ val |= 0x1;
+ outb(0x61, val); /* Gate high */
+}
+
+void
+pit_sleep(void)
+{
+ /* Wait until counter reaches zero */
+ while ((inb(0x61) & 0x20) == 0);
+}
+
+void
+clkstart(void)
+{
if (cpu_number() != 0)
/* Only one PIT initialization is needed */
return;
+ unsigned char byte;
+ unsigned long s;
s = sploff(); /* disable interrupts */
diff --git a/i386/i386/pit.h b/i386/i386/pit.h
index e004c37c..6be7a9d4 100644
--- a/i386/i386/pit.h
+++ b/i386/i386/pit.h
@@ -82,5 +82,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#endif /* AT386 */
extern void clkstart(void);
+extern void pit_prepare_sleep(int hz);
+extern void pit_sleep(void);
#endif /* _I386_PIT_H_ */
diff --git a/i386/i386at/autoconf.c b/i386/i386at/autoconf.c
index 151e3fd2..0b1251f5 100644
--- a/i386/i386at/autoconf.c
+++ b/i386/i386at/autoconf.c
@@ -26,7 +26,7 @@
#include <kern/printf.h>
#include <mach/std_types.h>
-#include <i386/pic.h>
+#include <i386/irq.h>
#include <i386/ipl.h>
#include <chips/busses.h>
diff --git a/i386/i386at/interrupt.S b/i386/i386at/interrupt.S
index 23a2e582..bbf08045 100644
--- a/i386/i386at/interrupt.S
+++ b/i386/i386at/interrupt.S
@@ -16,7 +16,11 @@
#include <mach/machine/asm.h>
#include <i386/ipl.h>
-#include <i386/pic.h>
+#ifdef APIC
+# include <i386/apic.h>
+#else
+# include <i386/pic.h>
+#endif
#include <i386/i386asm.h>
#define READ_ISR (OCW_TEMPLATE|READ_NEXT_RD|READ_IS_ONRD)
@@ -29,6 +33,10 @@
ENTRY(interrupt)
pushl %eax /* save irq number */
movl %eax,%ecx /* copy irq number */
+#ifdef APIC
+ cmpl $255,%eax /* was this a spurious intr? */
+ je 2f /* if so, null+eoi handler */
+#endif
shll $2,%ecx /* irq * 4 */
call spl7 /* set ipl */
movl EXT(iunit)(%ecx),%edx /* get device unit number */
@@ -38,10 +46,9 @@ ENTRY(interrupt)
addl $4,%esp /* pop unit number */
call splx_cli /* restore previous ipl */
addl $4,%esp /* pop previous ipl */
-
cli /* XXX no more nested interrupts */
popl %ecx /* restore irq number */
-
+#ifndef APIC
movl $1,%eax
shll %cl,%eax /* get corresponding IRQ mask */
orl EXT(curr_pic_mask),%eax /* add current mask */
@@ -78,4 +85,18 @@ ENTRY(interrupt)
outb %al,$(PIC_MASTER_OCW) /* unmask master */
2:
ret
+#else
+ cmpl $16,%ecx /* was this a low ISA intr? */
+ jl 1f /* no, must be PCI */
+ ret /* let irq_acknowledge handle EOI */
+1:
+ movl %ecx,%eax /* load irq number */
+ call EXT(ioapic_irq_eoi) /* ioapic irq specific EOI */
+ call EXT(lapic_eoi) /* lapic broadcast EOI */
+ ret
+2:
+ popl %ecx /* restore irq number */
+ call EXT(lapic_eoi) /* lapic broadcast EOI */
+ ret
+#endif
END(interrupt)
diff --git a/i386/i386at/ioapic.c b/i386/i386at/ioapic.c
new file mode 100644
index 00000000..376d2dcc
--- /dev/null
+++ b/i386/i386at/ioapic.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2019 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Mach.
+ *
+ * GNU Mach is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Mach is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
+ */
+
+#include <sys/types.h>
+#include <i386/ipl.h>
+#include <machine/irq.h>
+#include <i386/fpu.h>
+#include <i386/hardclock.h>
+#include <i386at/kd.h>
+#include <i386at/idt.h>
+#include <i386/pio.h>
+#include <i386/pit.h>
+#include <mach/machine.h>
+#include <kern/printf.h>
+
+static int timer_gsi;
+int timer_pin;
+
+uint32_t lapic_timer_val = 0;
+uint32_t calibrated_ticks = 0;
+
+spl_t curr_ipl;
+
+int iunit[NINTR] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23};
+
+void (*ivect[NINTR])() = {
+ /* 00 */ intnull, /* install timer later */
+ /* 01 */ kdintr, /* kdintr, ... */
+ /* 02 */ intnull,
+ /* 03 */ intnull, /* lnpoll, comintr, ... */
+
+ /* 04 */ intnull, /* comintr, ... */
+ /* 05 */ intnull, /* comintr, wtintr, ... */
+ /* 06 */ intnull, /* fdintr, ... */
+ /* 07 */ intnull, /* qdintr, ... */
+
+ /* 08 */ intnull,
+ /* 09 */ intnull, /* ether */
+ /* 10 */ intnull,
+ /* 11 */ intnull,
+
+ /* 12 */ intnull,
+ /* 13 */ fpintr, /* always */
+ /* 14 */ intnull, /* hdintr, ... */
+ /* 15 */ intnull, /* ??? */
+
+ /* 16 */ intnull, /* PIRQA */
+ /* 17 */ intnull, /* PIRQB */
+ /* 18 */ intnull, /* PIRQC */
+ /* 19 */ intnull, /* PIRQD */
+ /* 20 */ intnull, /* PIRQE */
+ /* 21 */ intnull, /* PIRQF */
+ /* 22 */ intnull, /* PIRQG */
+ /* 23 */ intnull, /* PIRQH */
+};
+
+void
+picdisable(void)
+{
+ asm("cli");
+
+ /*
+ ** Disable PIC
+ */
+ outb ( 0xa1, 0xff );
+ outb ( 0x21, 0xff );
+
+ /*
+ ** Route interrupts through IOAPIC
+ */
+ outb(IMCR_SELECT, MODE_IMCR);
+ outb(IMCR_DATA, IMCR_USE_APIC);
+}
+
+void
+intnull(int unit_dev)
+{
+ printf("intnull(%d)\n", unit_dev);
+}
+
+static uint32_t
+ioapic_read(uint8_t id, uint8_t reg)
+{
+ volatile ApicIoUnit *ioapic = apic_get_ioapic(id)->ioapic;
+ ioapic->select.r = reg;
+ return ioapic->window.r;
+}
+
+static void
+ioapic_write(uint8_t id, uint8_t reg, uint32_t value)
+{
+ volatile ApicIoUnit *ioapic = apic_get_ioapic(id)->ioapic;
+ ioapic->select.r = reg;
+ ioapic->window.r = value;
+}
+
+static struct ioapic_route_entry
+ioapic_read_entry(int apic, int pin)
+{
+ union ioapic_route_entry_union entry;
+
+ entry.lo = ioapic_read(apic, APIC_IO_REDIR_LOW(pin));
+ entry.hi = ioapic_read(apic, APIC_IO_REDIR_HIGH(pin));
+
+ return entry.both;
+}
+
+/* Write the high word first because mask bit is in low word */
+static void
+ioapic_write_entry(int apic, int pin, struct ioapic_route_entry e)
+{
+ union ioapic_route_entry_union entry = {{0, 0}};
+
+ entry.both = e;
+ ioapic_write(apic, APIC_IO_REDIR_HIGH(pin), entry.hi);
+ ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo);
+}
+
+/* When toggling the interrupt via mask, write low word only */
+static void
+ioapic_toggle_entry(int apic, int pin, int mask)
+{
+ union ioapic_route_entry_union entry;
+
+ entry.both = ioapic_read_entry(apic, pin);
+ entry.both.mask = mask & 0x1;
+ ioapic_write(apic, APIC_IO_REDIR_LOW(pin), entry.lo);
+}
+
+static void
+cpu_rdmsr(uint32_t msr, uint32_t *lo, uint32_t *hi)
+{
+ __asm__ __volatile__("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
+}
+
+static void
+cpu_wrmsr(uint32_t msr, uint32_t lo, uint32_t hi)
+{
+ __asm__ __volatile__("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
+}
+
+static void
+global_enable_apic(void)
+{
+ uint32_t lo = 0;
+ uint32_t hi = 0;
+ uint32_t msr = 0x1b;
+
+ cpu_rdmsr(msr, &lo, &hi);
+
+ if (!(lo & (1 << 11))) {
+ lo |= (1 << 11);
+ cpu_wrmsr(msr, lo, hi);
+ }
+}
+
+static uint32_t
+pit_measure_apic_hz(void)
+{
+ uint32_t start = 0xffffffff;
+
+ /* Prepare accurate delay for 1/100 seconds */
+ pit_prepare_sleep(100);
+
+ /* Set APIC timer */
+ lapic->init_count.r = start;
+
+ /* zZz */
+ pit_sleep();
+
+ /* Stop APIC timer */
+ lapic->lvt_timer.r = LAPIC_DISABLE;
+
+ return start - lapic->cur_count.r;
+}
+
+void lapic_update_timer(void)
+{
+ /* Timer decrements until zero and then calls this on every interrupt */
+ lapic_timer_val += calibrated_ticks;
+}
+
+void
+lapic_enable_timer(void)
+{
+ spl_t s;
+
+ s = sploff();
+ asm("cli");
+
+ /* Set up counter */
+ lapic->init_count.r = calibrated_ticks;
+ lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16;
+
+ /* Set the timer to interrupt periodically on remapped timer GSI */
+ lapic->lvt_timer.r = (IOAPIC_INT_BASE + timer_gsi) | LAPIC_TIMER_PERIODIC;
+
+ /* Some buggy hardware requires this set again */
+ lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16;
+
+ /* Unmask the remapped timer pin and pin 0 always */
+ ioapic_toggle(0, IOAPIC_MASK_ENABLED);
+ ioapic_toggle(timer_pin, IOAPIC_MASK_ENABLED);
+
+ splon(s);
+ printf("LAPIC timer configured\n");
+}
+
+void
+ioapic_toggle(int pin, int mask)
+{
+ int apic = 0;
+ ioapic_toggle_entry(apic, pin, mask);
+}
+
+void
+lapic_eoi(void)
+{
+ lapic->eoi.r = 0;
+}
+
+void
+ioapic_irq_eoi(int pin)
+{
+ int apic = 0;
+ union ioapic_route_entry_union oldentry, entry;
+
+ /* Workaround for old IOAPICs with no specific EOI */
+
+ /* Mask the pin and change to edge triggered */
+ oldentry.both = entry.both = ioapic_read_entry(apic, pin);
+ entry.both.mask = IOAPIC_MASK_DISABLED;
+ entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
+ ioapic_write_entry(apic, pin, entry.both);
+
+ /* Restore level entry */
+ ioapic_write_entry(apic, pin, oldentry.both);
+}
+
+void
+unmask_irq(unsigned int irq)
+{
+ ioapic_toggle(irq, IOAPIC_MASK_ENABLED);
+}
+
+void
+mask_irq(unsigned int irq)
+{
+ ioapic_toggle(irq, IOAPIC_MASK_DISABLED);
+}
+
+static unsigned int
+override_irq(IrqOverrideData *override, union ioapic_route_entry_union *entry)
+{
+ if (override->flags & APIC_IRQ_OVERRIDE_TRIGGER_MASK) {
+ entry->both.trigger = (override->flags &
APIC_IRQ_OVERRIDE_LEVEL_TRIGGERED) ?
+ IOAPIC_LEVEL_TRIGGERED : IOAPIC_EDGE_TRIGGERED;
+ } else {
+ if (override->bus == 0) {
+ /* ISA is edge-triggered by default */
+ entry->both.trigger = IOAPIC_EDGE_TRIGGERED;
+ } else {
+ entry->both.trigger = IOAPIC_LEVEL_TRIGGERED;
+ }
+ }
+
+ if (override->flags & APIC_IRQ_OVERRIDE_POLARITY_MASK) {
+ entry->both.polarity = (override->flags &
APIC_IRQ_OVERRIDE_ACTIVE_LOW) ?
+ IOAPIC_ACTIVE_LOW : IOAPIC_ACTIVE_HIGH;
+ } else {
+ if (override->bus == 0) {
+ /* EISA is active-low for level-triggered interrupts */
+ if (entry->both.trigger == IOAPIC_LEVEL_TRIGGERED) {
+ entry->both.polarity = IOAPIC_ACTIVE_LOW;
+ } else {
+ entry->both.polarity = IOAPIC_ACTIVE_HIGH;
+ }
+ }
+ }
+ printf("IRQ override: pin=%d gsi=%d trigger=%s polarity=%s\n",
+ override->irq, override->gsi, entry->both.trigger ==
IOAPIC_LEVEL_TRIGGERED ? "LEVEL" : "EDGE",
+ entry->both.polarity == IOAPIC_ACTIVE_LOW ? "LOW" : "HIGH");
+
+ return override->gsi;
+}
+
+void
+ioapic_configure(void)
+{
+ /* Assume first IO APIC maps to GSI base 0 */
+ int gsi, apic = 0, bsp = 0, pin;
+ IrqOverrideData *irq_over;
+
+ /* Disable IOAPIC interrupts and set spurious interrupt */
+ lapic->spurious_vector.r = IOAPIC_SPURIOUS_BASE;
+
+ union ioapic_route_entry_union entry = {{0, 0}};
+ union ioapic_route_entry_union timer_entry = {{0, 0}};
+
+ entry.both.delvmode = IOAPIC_FIXED;
+ entry.both.destmode = IOAPIC_PHYSICAL;
+ entry.both.mask = IOAPIC_MASK_DISABLED;
+ entry.both.dest = apic_get_cpu_apic_id(bsp);
+
+ for (pin = 0; pin < 16; pin++) {
+ gsi = pin;
+
+ /* ISA legacy IRQs */
+ entry.both.trigger = IOAPIC_EDGE_TRIGGERED;
+ entry.both.polarity = IOAPIC_ACTIVE_HIGH;
+
+ if ((irq_over = acpi_get_irq_override(pin))) {
+ gsi = override_irq(irq_over, &entry);
+ }
+ entry.both.vector = IOAPIC_INT_BASE + gsi;
+ ioapic_write_entry(apic, pin, entry.both);
+
+ /* Timer workaround for x86 */
+ if (pin == 0) {
+ /* Save timer info */
+ timer_gsi = gsi;
+ timer_entry = entry;
+ } else {
+ /* Get the actual timer pin by assuming that the pin
+ * with duplicated gsi from pin 0 maps to the timer pin */
+ if (gsi == timer_gsi) {
+ timer_pin = pin;
+ /* Remap pin 0 interrupt vector to GSI base
+ * so we don't duplicate vectors */
+ timer_entry.both.vector = IOAPIC_INT_BASE;
+ ioapic_write_entry(apic, 0, timer_entry.both);
+ }
+ }
+ }
+
+ for (pin = 16; pin < 24; pin++) {
+ gsi = pin;
+
+ /* PCI IRQs PIRQ A-H */
+ entry.both.trigger = IOAPIC_LEVEL_TRIGGERED;
+ entry.both.polarity = IOAPIC_ACTIVE_LOW;
+
+ if ((irq_over = acpi_get_irq_override(pin))) {
+ gsi = override_irq(irq_over, &entry);
+ }
+ entry.both.vector = IOAPIC_INT_BASE + gsi;
+ ioapic_write_entry(apic, pin, entry.both);
+ }
+
+ /* Start the IO APIC receiving interrupts */
+ lapic->dest_format.r = 0xffffffff; /* flat model */
+ lapic->logical_dest.r = 0x00000000; /* default, but we use physical
*/
+ lapic->lvt_timer.r = LAPIC_DISABLE;
+ lapic->lvt_performance_monitor.r = LAPIC_NMI;
+ lapic->lvt_lint0.r = LAPIC_DISABLE;
+ lapic->lvt_lint1.r = LAPIC_DISABLE;
+ lapic->task_pri.r = 0;
+
+ global_enable_apic();
+
+ /* Enable IOAPIC interrupts */
+ lapic->spurious_vector.r |= LAPIC_ENABLE;
+
+ /* Set one-shot timer */
+ lapic->divider_config.r = LAPIC_TIMER_DIVIDE_16;
+ lapic->lvt_timer.r = IOAPIC_INT_BASE + timer_gsi;
+
+ /* Measure number of APIC timer ticks in 10ms */
+ calibrated_ticks = pit_measure_apic_hz();
+
+ /* Set up counter later */
+ lapic->lvt_timer.r = LAPIC_DISABLE;
+
+ /* Install clock interrupt handler on both remapped timer pin and pin 0
+ * since nobody knows how all x86 timers are wired up */
+ ivect[0] = hardclock;
+ ivect[timer_pin] = hardclock;
+
+ printf("IOAPIC 0 configured\n");
+}
diff --git a/i386/i386at/kd_mouse.c b/i386/i386at/kd_mouse.c
index 2995587c..4b883ba8 100644
--- a/i386/i386at/kd_mouse.c
+++ b/i386/i386at/kd_mouse.c
@@ -72,7 +72,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <device/io_req.h>
#include <device/subrs.h>
#include <i386/ipl.h>
-#include <i386/pic.h>
+#include <i386/irq.h>
#include <i386/pio.h>
#include <chips/busses.h>
#include <i386at/com.h>
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index 1e98c5c3..17d0638d 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -59,7 +59,6 @@
#include <i386/ldt.h>
#include <i386/machspl.h>
#include <i386/mp_desc.h>
-#include <i386/pic.h>
#include <i386/pit.h>
#include <i386/pmap.h>
#include <i386/proc_reg.h>
@@ -75,6 +74,7 @@
#include <i386at/kd.h>
#include <i386at/rtc.h>
#include <i386at/model_dep.h>
+#include <machine/irq.h>
#ifdef MACH_XEN
#include <xen/console.h>
@@ -169,17 +169,20 @@ void machine_init(void)
#ifdef MACH_HYP
hyp_init();
#else /* MACH_HYP */
+
+#if (NCPUS > 1) && defined(APIC)
+ smp_init();
+ ioapic_configure();
+ lapic_enable_timer();
+ unmask_irq(1);
+#endif /* NCPUS > 1 */
+
#ifdef LINUX_DEV
/*
* Initialize Linux drivers.
*/
linux_init();
#endif
-
-#if NCPUS > 1
- smp_init();
-#endif /* NCPUS > 1 */
-
/*
* Find the devices
*/
@@ -356,7 +359,11 @@ i386at_init(void)
* Initialize the PIC prior to any possible call to an spl.
*/
#ifndef MACH_HYP
+# ifdef APIC
+ picdisable();
+# else
picinit();
+# endif
#else /* MACH_HYP */
hyp_intrinit();
#endif /* MACH_HYP */
@@ -682,7 +689,9 @@ timemmap(dev, off, prot)
void
startrtclock(void)
{
+#ifndef APIC
clkstart();
+#endif
}
void
diff --git a/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c
index 06889e58..656c1470 100644
--- a/linux/dev/arch/i386/kernel/irq.c
+++ b/linux/dev/arch/i386/kernel/irq.c
@@ -29,7 +29,7 @@
#include <kern/assert.h>
#include <i386/spl.h>
-#include <i386/pic.h>
+#include <i386/irq.h>
#include <i386/pit.h>
#define MACH_INCLUDE
@@ -84,13 +84,7 @@ struct linux_action
user_intr_t *user_intr;
};
-static struct linux_action *irq_action[16] =
-{
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL
-};
+static struct linux_action *irq_action[NINTR] = {0};
/*
* Generic interrupt handler for Linux devices.
@@ -232,7 +226,7 @@ install_user_intr_handler (struct irqdev *dev, int id,
unsigned long flags,
unsigned int irq = dev->irq[id];
- assert (irq < 16);
+ assert (irq < NINTR);
/* Test whether the irq handler has been set */
// TODO I need to protect the array when iterating it.
@@ -279,7 +273,7 @@ request_irq (unsigned int irq, void (*handler) (int, void
*, struct pt_regs *),
struct linux_action *action;
int retval;
- assert (irq < 16);
+ assert (irq < NINTR);
if (!handler)
return -EINVAL;
@@ -315,7 +309,7 @@ free_irq (unsigned int irq, void *dev_id)
struct linux_action *action, **p;
unsigned long flags;
- if (irq > 15)
+ if (irq >= NINTR)
panic ("free_irq: bad irq number");
for (p = irq_action + irq; (action = *p) != NULL; p = &action->next)
@@ -354,7 +348,7 @@ probe_irq_on (void)
/*
* Allocate all available IRQs.
*/
- for (i = 15; i > 0; i--)
+ for (i = NINTR - 1; i > 0; i--)
{
if (!irq_action[i] && ivect[i] == intnull)
{
@@ -387,7 +381,7 @@ probe_irq_off (unsigned long irqs)
/*
* Disable unnecessary IRQs.
*/
- for (i = 15; i > 0; i--)
+ for (i = NINTR - 1; i > 0; i--)
{
if (!irq_action[i] && ivect[i] == intnull)
{
@@ -427,7 +421,7 @@ reserve_mach_irqs (void)
{
unsigned int i;
- for (i = 0; i < 16; i++)
+ for (i = 0; i < NINTR; i++)
{
if (ivect[i] != intnull)
/* This dummy action does not specify SA_SHIRQ, so
@@ -720,13 +714,15 @@ init_IRQ (void)
*/
(void) splhigh ();
+#ifndef APIC
/*
* Program counter 0 of 8253 to interrupt hz times per second.
*/
outb_p (PIT_C0 | PIT_SQUAREMODE | PIT_READMODE, PITCTL_PORT);
outb_p (latch & 0xff, PITCTR0_PORT);
outb (latch >> 8, PITCTR0_PORT);
-
+#endif
+
/*
* Install our clock interrupt handler.
*/
--
2.30.1
- Re: [PATCH 2/6] fixup acpi base table search, (continued)
- [PATCH 1/6] Make linux drivers optional, Damien Zammit, 2021/03/28
- [PATCH 3/6] Don't allow writing to acpi table in memory, Damien Zammit, 2021/03/28
- [PATCH 4/6] Existing SMP apic code improvements, Damien Zammit, 2021/03/28
- [PATCH 5/6] Move PIC interrupt vector base from 0x40 to 0x20, Damien Zammit, 2021/03/28
- [PATCH 6/6] ioapic support switchable back to pic,
Damien Zammit <=
- Re: [PATCH v2 gnumach] - IOAPIC and LAPIC support, Samuel Thibault, 2021/03/28