summaryrefslogtreecommitdiffstats
path: root/sys/isa
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2003-11-03 21:53:38 +0000
committerjhb <jhb@FreeBSD.org>2003-11-03 21:53:38 +0000
commitdcec7e1907fe867da713052f8c91d79bbfe68000 (patch)
treec7dc6abe8f136cde7b0dbbc6ce1152f91bb42ad1 /sys/isa
parentaac4b7181cbed34861c76ff9d9142c7fdf212008 (diff)
downloadFreeBSD-src-dcec7e1907fe867da713052f8c91d79bbfe68000.zip
FreeBSD-src-dcec7e1907fe867da713052f8c91d79bbfe68000.tar.gz
New APIC support code:
- The apic interrupt entry points have been rewritten so that each entry point can serve 32 different vectors. When the entry is executed, it uses one of the 32-bit ISR registers to determine which vector in its assigned range was triggered. Thus, the apic code can support 159 different interrupt vectors with only 5 entry points. - We now always to disable the local APIC to work around an errata in certain PPros and then re-enable it again if we decide to use the APICs to route interrupts. - We no longer map IO APICs or local APICs using special page table entries. Instead, we just use pmap_mapdev(). We also no longer export the virtual address of the local APIC as a global symbol to the rest of the system, but only in local_apic.c. To aid this, the APIC ID of each CPU is exported as a per-CPU variable. - Interrupt sources are provided for each intpin on each IO APIC. Currently, each source is given a unique interrupt vector meaning that PCI interrupts are not shared on most machines with an I/O APIC. That mapping for interrupt sources to interrupt vectors is up to the APIC enumerator driver however. - We no longer probe to see if we need to use mixed mode to route IRQ 0, instead we always use mixed mode to route IRQ 0 for now. This can be disabled via the 'NO_MIXED_MODE' kernel option. - The npx(4) driver now always probes to see if a built-in FPU is present since this test can now be performed with the new APIC code. However, an SMP kernel will panic if there is more than one CPU and a built-in FPU is not found. - PCI interrupts are now properly routed when using APICs to route interrupts, so remove the hack to psuedo-route interrupts when the intpin register was read. - The apic.h header was moved to apicreg.h and a new apicvar.h header that declares the APIs used by the new APIC code was added.
Diffstat (limited to 'sys/isa')
-rw-r--r--sys/isa/atrtc.c199
1 files changed, 17 insertions, 182 deletions
diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c
index 0f8ac68..b389670 100644
--- a/sys/isa/atrtc.c
+++ b/sys/isa/atrtc.c
@@ -71,14 +71,12 @@ __FBSDID("$FreeBSD$");
#include <machine/clock.h>
#include <machine/cputypes.h>
#include <machine/frame.h>
+#include <machine/intr_machdep.h>
#include <machine/md_var.h>
#include <machine/psl.h>
-#ifdef APIC_IO
-#include <machine/segments.h>
-#endif
-#if defined(SMP) || defined(APIC_IO)
+#if defined(SMP)
#include <machine/smp.h>
-#endif /* SMP || APIC_IO */
+#endif
#include <machine/specialreg.h>
#include <i386/isa/icu.h>
@@ -89,20 +87,10 @@ __FBSDID("$FreeBSD$");
#endif
#include <i386/isa/timerreg.h>
-#include <i386/isa/intr_machdep.h>
-
#ifdef DEV_MCA
#include <i386/bios/mca_machdep.h>
#endif
-#ifdef APIC_IO
-#include <i386/isa/intr_machdep.h>
-/* The interrupt triggered by the 8254 (timer) chip */
-int apic_8254_intr;
-static u_long read_intr_count(int vec);
-static void setup_8254_mixed_mode(void);
-#endif
-
/*
* 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
* can use a simple formula for leap years.
@@ -150,6 +138,7 @@ static u_int hardclock_max_count;
static u_int32_t i8254_lastcount;
static u_int32_t i8254_offset;
static int i8254_ticked;
+static struct intsrc *i8254_intsrc;
#ifndef BURN_BRIDGES
/*
* XXX new_function and timer_func should not handle clockframes, but
@@ -187,7 +176,7 @@ static struct timecounter i8254_timecounter = {
};
static void
-clkintr(struct clockframe frame)
+clkintr(struct clockframe *frame)
{
if (timecounter->tc_get_timecount == i8254_get_timecount) {
@@ -201,7 +190,7 @@ clkintr(struct clockframe frame)
clkintr_pending = 0;
mtx_unlock_spin(&clock_lock);
}
- timer_func(&frame);
+ timer_func(frame);
#ifdef SMP
if (timer_func == hardclock)
forward_hardclock();
@@ -216,7 +205,7 @@ clkintr(struct clockframe frame)
if ((timer0_prescaler_count += timer0_max_count)
>= hardclock_max_count) {
timer0_prescaler_count -= hardclock_max_count;
- hardclock(&frame);
+ hardclock(frame);
#ifdef SMP
forward_hardclock();
#endif
@@ -251,7 +240,7 @@ clkintr(struct clockframe frame)
timer0_prescaler_count = 0;
timer_func = hardclock;
timer0_state = RELEASED;
- hardclock(&frame);
+ hardclock(frame);
#ifdef SMP
forward_hardclock();
#endif
@@ -379,16 +368,16 @@ release_timer2()
* in the statistics, but the stat clock will no longer stop.
*/
static void
-rtcintr(struct clockframe frame)
+rtcintr(struct clockframe *frame)
{
while (rtcin(RTC_INTR) & RTCIR_PERIOD) {
if (profprocs != 0) {
if (--pscnt == 0)
pscnt = psdiv;
- profclock(&frame);
+ profclock(frame);
}
if (pscnt == psdiv)
- statclock(&frame);
+ statclock(frame);
#ifdef SMP
forward_statclock();
#endif
@@ -931,11 +920,6 @@ void
cpu_initclocks()
{
int diag;
-#ifdef APIC_IO
- int apic_8254_trial;
- void *clkdesc;
-#endif /* APIC_IO */
- register_t crit;
if (statclock_disable) {
/*
@@ -951,47 +935,9 @@ cpu_initclocks()
profhz = RTC_PROFRATE;
}
- /* Finish initializing 8253 timer 0. */
-#ifdef APIC_IO
-
- apic_8254_intr = isa_apic_irq(0);
- apic_8254_trial = 0;
- if (apic_8254_intr >= 0 ) {
- if (apic_int_type(0, 0) == 3)
- apic_8254_trial = 1;
- } else {
- /* look for ExtInt on pin 0 */
- if (apic_int_type(0, 0) == 3) {
- apic_8254_intr = apic_irq(0, 0);
- setup_8254_mixed_mode();
- } else
- panic("APIC_IO: Cannot route 8254 interrupt to CPU");
- }
-
- inthand_add("clk", apic_8254_intr, (driver_intr_t *)clkintr, NULL,
- INTR_TYPE_CLK | INTR_FAST, &clkdesc);
- crit = intr_disable();
- mtx_lock_spin(&icu_lock);
- INTREN(1 << apic_8254_intr);
- mtx_unlock_spin(&icu_lock);
- intr_restore(crit);
-
-#else /* APIC_IO */
-
- /*
- * XXX Check the priority of this interrupt handler. I
- * couldn't find anything suitable in the BSD/OS code (grog,
- * 19 July 2000).
- */
- inthand_add("clk", 0, (driver_intr_t *)clkintr, NULL,
+ /* Finish initializing 8254 timer 0. */
+ intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL,
INTR_TYPE_CLK | INTR_FAST, NULL);
- crit = intr_disable();
- mtx_lock_spin(&icu_lock);
- INTREN(IRQ0);
- mtx_unlock_spin(&icu_lock);
- intr_restore(crit);
-
-#endif /* APIC_IO */
/* Initialize RTC. */
writertc(RTC_STATUSA, rtc_statusa);
@@ -1004,120 +950,15 @@ cpu_initclocks()
if (diag != 0)
printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS);
-#ifdef APIC_IO
- if (isa_apic_irq(8) != 8)
- panic("APIC RTC != 8");
-#endif /* APIC_IO */
-
- inthand_add("rtc", 8, (driver_intr_t *)rtcintr, NULL,
+ intr_add_handler("rtc", 8, (driver_intr_t *)rtcintr, NULL,
INTR_TYPE_CLK | INTR_FAST, NULL);
-
- crit = intr_disable();
- mtx_lock_spin(&icu_lock);
-#ifdef APIC_IO
- INTREN(APIC_IRQ8);
-#else
- INTREN(IRQ8);
-#endif /* APIC_IO */
- mtx_unlock_spin(&icu_lock);
- intr_restore(crit);
+ i8254_intsrc = intr_lookup_source(8);
writertc(RTC_STATUSB, rtc_statusb);
-#ifdef APIC_IO
- if (apic_8254_trial) {
-
- printf("APIC_IO: Testing 8254 interrupt delivery\n");
- while (read_intr_count(8) < 6)
- ; /* nothing */
- if (read_intr_count(apic_8254_intr) < 3) {
- /*
- * The MP table is broken.
- * The 8254 was not connected to the specified pin
- * on the IO APIC.
- * Workaround: Limited variant of mixed mode.
- */
-
- crit = intr_disable();
- mtx_lock_spin(&icu_lock);
- INTRDIS(1 << apic_8254_intr);
- mtx_unlock_spin(&icu_lock);
- intr_restore(crit);
- inthand_remove(clkdesc);
- printf("APIC_IO: Broken MP table detected: "
- "8254 is not connected to "
- "IOAPIC #%d intpin %d\n",
- int_to_apicintpin[apic_8254_intr].ioapic,
- int_to_apicintpin[apic_8254_intr].int_pin);
- /*
- * Revoke current ISA IRQ 0 assignment and
- * configure a fallback interrupt routing from
- * the 8254 Timer via the 8259 PIC to the
- * an ExtInt interrupt line on IOAPIC #0 intpin 0.
- * We reuse the low level interrupt handler number.
- */
- if (apic_irq(0, 0) < 0) {
- revoke_apic_irq(apic_8254_intr);
- assign_apic_irq(0, 0, apic_8254_intr);
- }
- apic_8254_intr = apic_irq(0, 0);
- setup_8254_mixed_mode();
- inthand_add("clk", apic_8254_intr,
- (driver_intr_t *)clkintr, NULL,
- INTR_TYPE_CLK | INTR_FAST, NULL);
- crit = intr_disable();
- mtx_lock_spin(&icu_lock);
- INTREN(1 << apic_8254_intr);
- mtx_unlock_spin(&icu_lock);
- intr_restore(crit);
- }
-
- }
- if (apic_int_type(0, 0) != 3 ||
- int_to_apicintpin[apic_8254_intr].ioapic != 0 ||
- int_to_apicintpin[apic_8254_intr].int_pin != 0)
- printf("APIC_IO: routing 8254 via IOAPIC #%d intpin %d\n",
- int_to_apicintpin[apic_8254_intr].ioapic,
- int_to_apicintpin[apic_8254_intr].int_pin);
- else
- printf("APIC_IO: "
- "routing 8254 via 8259 and IOAPIC #0 intpin 0\n");
-#endif
-
init_TSC_tc();
}
-#ifdef APIC_IO
-static u_long
-read_intr_count(int vec)
-{
- u_long *up;
- up = intr_countp[vec];
- if (up)
- return *up;
- return 0UL;
-}
-
-static void
-setup_8254_mixed_mode()
-{
- /*
- * Allow 8254 timer to INTerrupt 8259:
- * re-initialize master 8259:
- * reset; prog 4 bytes, single ICU, edge triggered
- */
- outb(IO_ICU1, 0x13);
- outb(IO_ICU1 + 1, NRSVIDT); /* start vector (unused) */
- outb(IO_ICU1 + 1, 0x00); /* ignore slave */
- outb(IO_ICU1 + 1, 0x03); /* auto EOI, 8086 */
- outb(IO_ICU1 + 1, 0xfe); /* unmask INT0 */
-
- /* program IO APIC for type 3 INT on INT0 */
- if (ext_int_setup(0, 0) < 0)
- panic("8254 redirect via APIC pin0 impossible!");
-}
-#endif
-
void
cpu_startprofclock(void)
{
@@ -1181,14 +1022,8 @@ i8254_get_timecount(struct timecounter *tc)
if (count < i8254_lastcount ||
(!i8254_ticked && (clkintr_pending ||
((count < 20 || (!(eflags & PSL_I) && count < timer0_max_count / 2u)) &&
-#ifdef APIC_IO
-#define lapic_irr1 ((volatile u_int *)&lapic)[0x210 / 4] /* XXX XXX */
- /* XXX this assumes that apic_8254_intr is < 24. */
- (lapic_irr1 & (1 << apic_8254_intr))))
-#else
- (inb(IO_ICU1) & 1)))
-#endif
- )) {
+ i8254_intsrc != NULL &&
+ i8254_intsrc->is_pic->pic_source_pending(i8254_intsrc))))) {
i8254_ticked = 1;
i8254_offset += timer0_max_count;
}
OpenPOWER on IntegriCloud