summaryrefslogtreecommitdiffstats
path: root/sys/i386/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/i386/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/i386/isa')
-rw-r--r--sys/i386/isa/clock.c199
-rw-r--r--sys/i386/isa/npx.c50
2 files changed, 30 insertions, 219 deletions
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c
index 0f8ac68..b389670 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/i386/isa/clock.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;
}
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index fbd4643..9e5a7ee 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/mutex.h>
#include <sys/proc.h>
+#include <sys/smp.h>
#include <sys/sysctl.h>
#include <machine/bus.h>
#include <sys/rman.h>
@@ -61,31 +62,25 @@ __FBSDID("$FreeBSD$");
#include <sys/signalvar.h>
#include <sys/user.h>
-#ifndef SMP
#include <machine/asmacros.h>
-#endif
#include <machine/cputypes.h>
#include <machine/frame.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/psl.h>
-#ifndef SMP
#include <machine/clock.h>
-#endif
#include <machine/resource.h>
#include <machine/specialreg.h>
#include <machine/segments.h>
#include <machine/ucontext.h>
-#ifndef SMP
#include <i386/isa/icu.h>
#ifdef PC98
#include <pc98/pc98/pc98.h>
#else
#include <i386/isa/isa.h>
#endif
-#endif
-#include <i386/isa/intr_machdep.h>
+#include <machine/intr_machdep.h>
#ifdef DEV_ISA
#include <isa/isavar.h>
#endif
@@ -165,9 +160,7 @@ static void fpusave(union savefpu *);
static void fpurstor(union savefpu *);
static int npx_attach(device_t dev);
static void npx_identify(driver_t *driver, device_t parent);
-#ifndef SMP
static void npx_intr(void *);
-#endif
static int npx_probe(device_t dev);
#ifdef I586_CPU_XXX
static long timezero(const char *funcname,
@@ -180,10 +173,8 @@ SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
CTLFLAG_RD, &hw_float, 0,
"Floatingpoint instructions executed in hardware");
-#ifndef SMP
static volatile u_int npx_intrs_while_probing;
static volatile u_int npx_traps_while_probing;
-#endif
static union savefpu npx_cleanstate;
static bool_t npx_cleanstate_ready;
@@ -191,7 +182,6 @@ static bool_t npx_ex16;
static bool_t npx_exists;
static bool_t npx_irq13;
-#ifndef SMP
alias_for_inthand_t probetrap;
__asm(" \n\
.text \n\
@@ -203,7 +193,6 @@ __asm(" \n\
fnclex \n\
iret \n\
");
-#endif /* SMP */
/*
* Identify routine. Create a connection point on our parent for probing.
@@ -220,7 +209,6 @@ npx_identify(driver, parent)
panic("npx_identify");
}
-#ifndef SMP
/*
* Do minimal handling of npx interrupts to convert them to traps.
*/
@@ -230,9 +218,7 @@ npx_intr(dummy)
{
struct thread *td;
-#ifndef SMP
npx_intrs_while_probing++;
-#endif
/*
* The BUSY# latch must be cleared in all cases so that the next
@@ -264,7 +250,6 @@ npx_intr(dummy)
mtx_unlock_spin(&sched_lock);
}
}
-#endif /* !SMP */
/*
* Probe routine. Initialize cr0 to give correct behaviour for [f]wait
@@ -276,7 +261,6 @@ static int
npx_probe(dev)
device_t dev;
{
-#ifndef SMP
struct gate_descriptor save_idt_npxtrap;
struct resource *ioport_res, *irq_res;
void *irq_cookie;
@@ -307,7 +291,6 @@ npx_probe(dev)
if (bus_setup_intr(dev, irq_res, INTR_TYPE_MISC | INTR_FAST, npx_intr,
NULL, &irq_cookie) != 0)
panic("npx: can't create intr");
-#endif /* !SMP */
/*
* Partially reset the coprocessor, if any. Some BIOS's don't reset
@@ -348,16 +331,6 @@ npx_probe(dev)
device_set_desc(dev, "math processor");
-#ifdef SMP
-
- /*
- * Exception 16 MUST work for SMP.
- */
- npx_ex16 = hw_float = npx_exists = 1;
- return (0);
-
-#else /* !SMP */
-
/*
* Don't use fwait here because it might hang.
* Don't use fnop here because it usually hangs if there is no FPU.
@@ -413,6 +386,10 @@ npx_probe(dev)
*/
npx_irq13 = 1;
idt[IDT_MF] = save_idt_npxtrap;
+#ifdef SMP
+ if (mp_ncpus > 1)
+ panic("npx0 cannot use IRQ 13 on an SMP system");
+#endif
return (0);
}
/*
@@ -425,6 +402,10 @@ npx_probe(dev)
* emulator and say that it has been installed. XXX handle devices
* that aren't really devices better.
*/
+#ifdef SMP
+ if (mp_ncpus > 1)
+ panic("npx0 cannot be emulated on an SMP system");
+#endif
/* FALLTHROUGH */
no_irq13:
idt[IDT_MF] = save_idt_npxtrap;
@@ -435,20 +416,15 @@ no_irq13:
* irq active then we would get it instead of exception 16.
*/
{
- register_t crit;
+ struct intsrc *isrc;
- crit = intr_disable();
- mtx_lock_spin(&icu_lock);
- INTRDIS(1 << irq_num);
- mtx_unlock_spin(&icu_lock);
- intr_restore(crit);
+ isrc = intr_lookup_source(irq_num);
+ isrc->is_pic->pic_disable_source(isrc);
}
bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res);
bus_release_resource(dev, SYS_RES_IOPORT, ioport_rid, ioport_res);
return (0);
-
-#endif /* SMP */
}
/*
OpenPOWER on IntegriCloud