diff options
author | KATO Takenori <kato@FreeBSD.org> | 1997-04-27 13:22:09 +0000 |
---|---|---|
committer | KATO Takenori <kato@FreeBSD.org> | 1997-04-27 13:22:09 +0000 |
commit | e1ee467aaf742555065e30687c41267c74b09393 (patch) | |
tree | f5c73bde59bf014145b24ea3ca76758096a48d78 | |
parent | a8a74574b2e2ebfc5542f083310869539389cdb0 (diff) |
Notes
-rw-r--r-- | sys/conf/files.pc98 | 6 | ||||
-rw-r--r-- | sys/conf/options.pc98 | 19 | ||||
-rw-r--r-- | sys/pc98/cbus/clock.c | 105 | ||||
-rw-r--r-- | sys/pc98/cbus/pcrtc.c | 105 | ||||
-rw-r--r-- | sys/pc98/cbus/sio.c | 13 | ||||
-rw-r--r-- | sys/pc98/conf/files.pc98 | 6 | ||||
-rw-r--r-- | sys/pc98/conf/options.pc98 | 19 | ||||
-rw-r--r-- | sys/pc98/i386/machdep.c | 90 | ||||
-rw-r--r-- | sys/pc98/i386/microtime.s | 21 | ||||
-rw-r--r-- | sys/pc98/i386/trap.c | 21 | ||||
-rw-r--r-- | sys/pc98/pc98/clock.c | 105 | ||||
-rw-r--r-- | sys/pc98/pc98/machdep.c | 90 | ||||
-rw-r--r-- | sys/pc98/pc98/npx.c | 79 | ||||
-rw-r--r-- | sys/pc98/pc98/pc98.c | 99 | ||||
-rw-r--r-- | sys/pc98/pc98/sio.c | 13 |
15 files changed, 735 insertions, 56 deletions
diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 497b8172e968..94ced2f97a33 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -3,7 +3,7 @@ # # modified for PC-9801 # -# $Id: files.pc98,v 1.21 1997/04/08 10:33:24 kato Exp $ +# $Id: files.pc98,v 1.22 1997/04/15 11:43:10 kato Exp $ # aic7xxx_asm optional ahc device-driver \ dependency "$S/dev/aic7xxx/*.[chyl]" \ @@ -56,6 +56,10 @@ i386/i386/initcpu.c standard pc98/i386/machdep.c standard i386/i386/math_emulate.c optional math_emulate i386/i386/mem.c standard +i386/i386/mp_machdep.c optional smp +i386/i386/mpapic.c optional smp +i386/i386/mpboot.s optional smp +i386/i386/mplock.s optional smp pc98/i386/microtime.s standard i386/i386/perfmon.c optional perfmon profiling-routine i386/i386/perfmon.c optional perfmon diff --git a/sys/conf/options.pc98 b/sys/conf/options.pc98 index d45c99ae9381..190454ea8dfa 100644 --- a/sys/conf/options.pc98 +++ b/sys/conf/options.pc98 @@ -1,4 +1,4 @@ -# $Id: options.pc98,v 1.19 1997/03/22 18:54:15 kato Exp $ +# $Id: options.pc98,v 1.20 1997/04/05 15:06:30 kato Exp $ BOUNCEPAGES opt_bounce.h USER_LDT MATH_EMULATE opt_math_emulate.h @@ -28,6 +28,23 @@ PCVT_FREEBSD opt_pcvt.h PCVT_SCANSET opt_pcvt.h XSERVER opt_pcvt.h +SMP opt_smp.h +APIC_IO opt_smp.h +NCPU opt_smp.h +NBUS opt_smp.h +NAPIC opt_smp.h +NINTR opt_smp.h +SMP_TIMER_NC opt_smp.h + +# Should be working. When one cpu flushes it's TLB, it's propagated to all. +SMP_INVLTLB opt_smp_invltlb.h + +# These three are known to be broken, don't enable them. +SMP_PRIVPAGES opt_smp_privpages.h +SMP_AUTOSTART opt_smp_autostart.h + +SERIAL_DEBUG opt_serial.h + AHC_TAGENABLE opt_aic7xxx.h AHC_SCBPAGING_ENABLE opt_aic7xxx.h AHC_ALLOW_MEMIO opt_aic7xxx.h diff --git a/sys/pc98/cbus/clock.c b/sys/pc98/cbus/clock.c index c18ae1e08217..28c2a03b1893 100644 --- a/sys/pc98/cbus/clock.c +++ b/sys/pc98/cbus/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.18 1997/03/05 16:19:48 kato Exp $ + * $Id: clock.c,v 1.19 1997/04/07 10:53:14 kato Exp $ */ /* @@ -53,6 +53,7 @@ */ #include "opt_clock.h" +#include "opt_smp.h" #include "opt_cpu.h" #include <sys/param.h> @@ -110,7 +111,7 @@ int adjkerntz; /* local offset from GMT in seconds */ int disable_rtc_set; /* disable resettodr() if != 0 */ u_int idelayed; -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) u_int i586_ctr_bias; u_int i586_ctr_comultiplier; u_int i586_ctr_freq; @@ -176,7 +177,7 @@ static int rtc_inb __P((void)); static void rtc_outb __P((int)); #endif -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) static void set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq); #endif static void set_timer_freq(u_int freq, int intr_freq); @@ -694,7 +695,7 @@ calibrate_clocks(void) goto fail; tot_count = 0; -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) if (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686) wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */ #endif @@ -727,7 +728,7 @@ calibrate_clocks(void) goto fail; } -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) /* * Read the cpu cycle counter. The timing considerations are * similar to those for the i8254 clock. @@ -832,7 +833,7 @@ startrtclock() printf( "%d Hz differs from default of %d Hz by more than 1%%\n", freq, timer_freq); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) i586_ctr_freq = 0; #endif } @@ -840,7 +841,7 @@ startrtclock() set_timer_freq(timer_freq, hz); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) #ifndef CLK_USE_I586_CALIBRATION if (i586_ctr_freq != 0) { if (bootverbose) @@ -1123,12 +1124,29 @@ resettodr() #endif } +#if defined(APIC_IO) + +/* from icu.s: */ +extern u_int hwisrs[]; +extern void vec8254 __P((void)); +extern void vecRTC __P((void)); +extern u_int ivectors[]; +extern u_int Xintr8254; +extern u_int XintrRTC; +extern u_int mask8254; +extern u_int maskRTC; + +#endif /* APIC_IO */ + /* * Start both clocks running. */ void cpu_initclocks() { +#if defined(APIC_IO) + int x; +#endif /* APIC_IO */ #ifndef PC98 int diag; @@ -1149,11 +1167,51 @@ cpu_initclocks() #endif /* Finish initializing 8253 timer 0. */ +#if defined(APIC_IO) + /* 8254 is traditionally on ISA IRQ0 */ + if ((x = get_isa_apic_irq(0)) < 0) { + /* + * bummer, this mb doesn't have the 8254 on ISA irq0, + * perhaps it's on the EISA bus... + */ + if ((x = get_eisa_apic_irq(0)) < 0) { + /* double bummer, attempt to redirect thru the 8259 */ + if (bootverbose) + printf("APIC missing 8254 connection\n"); + + /* allow 8254 timer to INTerrupt 8259 */ +#if !defined(IO_ICU1) +#ifdef PC98 +#define IO_ICU1 0x00 +#else +#define IO_ICU1 0x20 +#endif +#endif + x = inb(IO_ICU1 + 1); /* current mask in 8259 */ + x &= ~1; /* clear 8254 timer mask */ + outb(IO_ICU1 + 1, x); /* write new mask */ + + /* program IO APIC for type 3 INT on INT0 */ + if (ext_int_setup(0, 0) < 0) + panic("8254 redirect impossible!"); + x = 0; /* 8259 is on 0 */ + } + } + + hwisrs[x] = (u_int)vec8254; + Xintr8254 = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ + mask8254 = (1 << x); + register_intr(/* irq */ x, /* XXX id */ 0, /* flags */ 0, + /* XXX */ (inthand2_t *)clkintr, &clk_imask, + /* unit */ 0); + INTREN(mask8254); +#else register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, /* XXX */ (inthand2_t *)clkintr, &clk_imask, /* unit */ 0); INTREN(IRQ0); -#if defined(I586_CPU) || defined(I686_CPU) +#endif /* APIC_IO */ +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) /* * Finish setting up anti-jitter measures. */ @@ -1172,12 +1230,37 @@ cpu_initclocks() diag = rtcin(RTC_DIAG); if (diag != 0) printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); +#if defined(APIC_IO) + /* RTC is traditionally on ISA IRQ8 */ + if ((x = get_isa_apic_irq(8)) < 0) { + if ((x = get_eisa_apic_irq(8)) < 0) { + panic("APIC missing RTC connection"); + } + } + + hwisrs[x] = (u_int)vecRTC; + XintrRTC = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ + maskRTC = (1 << x); + register_intr(/* irq */ x, /* XXX id */ 1, /* flags */ 0, + /* XXX */ (inthand2_t *)rtcintr, &stat_imask, + /* unit */ 0); + INTREN(maskRTC); +#else register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, /* XXX */ (inthand2_t *)rtcintr, &stat_imask, /* unit */ 0); INTREN(IRQ8); +#endif /* APIC_IO */ writertc(RTC_STATUSB, rtc_statusb); #endif + +#if defined(APIC_IO) + printf("Enabled INTs: "); + for (x = 0; x < 24; ++x) + if ((imen & (1 << x)) == 0) + printf("%d, ", x); + printf("imen: 0x%08x\n", imen); +#endif /* APIC_IO */ } void @@ -1208,7 +1291,7 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS if (timer0_state != 0) return (EBUSY); /* too much trouble to handle */ set_timer_freq(freq, hz); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) set_i586_ctr_freq(i586_ctr_freq, timer_freq); #endif } @@ -1218,7 +1301,7 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) static void set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq) { @@ -1257,4 +1340,4 @@ sysctl_machdep_i586_freq SYSCTL_HANDLER_ARGS SYSCTL_PROC(_machdep, OID_AUTO, i586_freq, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(u_int), sysctl_machdep_i586_freq, "I", ""); -#endif /* defined(I586_CPU) || defined(I686_CPU) */ +#endif /* (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) */ diff --git a/sys/pc98/cbus/pcrtc.c b/sys/pc98/cbus/pcrtc.c index c18ae1e08217..28c2a03b1893 100644 --- a/sys/pc98/cbus/pcrtc.c +++ b/sys/pc98/cbus/pcrtc.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.18 1997/03/05 16:19:48 kato Exp $ + * $Id: clock.c,v 1.19 1997/04/07 10:53:14 kato Exp $ */ /* @@ -53,6 +53,7 @@ */ #include "opt_clock.h" +#include "opt_smp.h" #include "opt_cpu.h" #include <sys/param.h> @@ -110,7 +111,7 @@ int adjkerntz; /* local offset from GMT in seconds */ int disable_rtc_set; /* disable resettodr() if != 0 */ u_int idelayed; -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) u_int i586_ctr_bias; u_int i586_ctr_comultiplier; u_int i586_ctr_freq; @@ -176,7 +177,7 @@ static int rtc_inb __P((void)); static void rtc_outb __P((int)); #endif -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) static void set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq); #endif static void set_timer_freq(u_int freq, int intr_freq); @@ -694,7 +695,7 @@ calibrate_clocks(void) goto fail; tot_count = 0; -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) if (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686) wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */ #endif @@ -727,7 +728,7 @@ calibrate_clocks(void) goto fail; } -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) /* * Read the cpu cycle counter. The timing considerations are * similar to those for the i8254 clock. @@ -832,7 +833,7 @@ startrtclock() printf( "%d Hz differs from default of %d Hz by more than 1%%\n", freq, timer_freq); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) i586_ctr_freq = 0; #endif } @@ -840,7 +841,7 @@ startrtclock() set_timer_freq(timer_freq, hz); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) #ifndef CLK_USE_I586_CALIBRATION if (i586_ctr_freq != 0) { if (bootverbose) @@ -1123,12 +1124,29 @@ resettodr() #endif } +#if defined(APIC_IO) + +/* from icu.s: */ +extern u_int hwisrs[]; +extern void vec8254 __P((void)); +extern void vecRTC __P((void)); +extern u_int ivectors[]; +extern u_int Xintr8254; +extern u_int XintrRTC; +extern u_int mask8254; +extern u_int maskRTC; + +#endif /* APIC_IO */ + /* * Start both clocks running. */ void cpu_initclocks() { +#if defined(APIC_IO) + int x; +#endif /* APIC_IO */ #ifndef PC98 int diag; @@ -1149,11 +1167,51 @@ cpu_initclocks() #endif /* Finish initializing 8253 timer 0. */ +#if defined(APIC_IO) + /* 8254 is traditionally on ISA IRQ0 */ + if ((x = get_isa_apic_irq(0)) < 0) { + /* + * bummer, this mb doesn't have the 8254 on ISA irq0, + * perhaps it's on the EISA bus... + */ + if ((x = get_eisa_apic_irq(0)) < 0) { + /* double bummer, attempt to redirect thru the 8259 */ + if (bootverbose) + printf("APIC missing 8254 connection\n"); + + /* allow 8254 timer to INTerrupt 8259 */ +#if !defined(IO_ICU1) +#ifdef PC98 +#define IO_ICU1 0x00 +#else +#define IO_ICU1 0x20 +#endif +#endif + x = inb(IO_ICU1 + 1); /* current mask in 8259 */ + x &= ~1; /* clear 8254 timer mask */ + outb(IO_ICU1 + 1, x); /* write new mask */ + + /* program IO APIC for type 3 INT on INT0 */ + if (ext_int_setup(0, 0) < 0) + panic("8254 redirect impossible!"); + x = 0; /* 8259 is on 0 */ + } + } + + hwisrs[x] = (u_int)vec8254; + Xintr8254 = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ + mask8254 = (1 << x); + register_intr(/* irq */ x, /* XXX id */ 0, /* flags */ 0, + /* XXX */ (inthand2_t *)clkintr, &clk_imask, + /* unit */ 0); + INTREN(mask8254); +#else register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, /* XXX */ (inthand2_t *)clkintr, &clk_imask, /* unit */ 0); INTREN(IRQ0); -#if defined(I586_CPU) || defined(I686_CPU) +#endif /* APIC_IO */ +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) /* * Finish setting up anti-jitter measures. */ @@ -1172,12 +1230,37 @@ cpu_initclocks() diag = rtcin(RTC_DIAG); if (diag != 0) printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); +#if defined(APIC_IO) + /* RTC is traditionally on ISA IRQ8 */ + if ((x = get_isa_apic_irq(8)) < 0) { + if ((x = get_eisa_apic_irq(8)) < 0) { + panic("APIC missing RTC connection"); + } + } + + hwisrs[x] = (u_int)vecRTC; + XintrRTC = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ + maskRTC = (1 << x); + register_intr(/* irq */ x, /* XXX id */ 1, /* flags */ 0, + /* XXX */ (inthand2_t *)rtcintr, &stat_imask, + /* unit */ 0); + INTREN(maskRTC); +#else register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, /* XXX */ (inthand2_t *)rtcintr, &stat_imask, /* unit */ 0); INTREN(IRQ8); +#endif /* APIC_IO */ writertc(RTC_STATUSB, rtc_statusb); #endif + +#if defined(APIC_IO) + printf("Enabled INTs: "); + for (x = 0; x < 24; ++x) + if ((imen & (1 << x)) == 0) + printf("%d, ", x); + printf("imen: 0x%08x\n", imen); +#endif /* APIC_IO */ } void @@ -1208,7 +1291,7 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS if (timer0_state != 0) return (EBUSY); /* too much trouble to handle */ set_timer_freq(freq, hz); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) set_i586_ctr_freq(i586_ctr_freq, timer_freq); #endif } @@ -1218,7 +1301,7 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) static void set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq) { @@ -1257,4 +1340,4 @@ sysctl_machdep_i586_freq SYSCTL_HANDLER_ARGS SYSCTL_PROC(_machdep, OID_AUTO, i586_freq, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(u_int), sysctl_machdep_i586_freq, "I", ""); -#endif /* defined(I586_CPU) || defined(I686_CPU) */ +#endif /* (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) */ diff --git a/sys/pc98/cbus/sio.c b/sys/pc98/cbus/sio.c index ac96b9deaa9e..320740868ab1 100644 --- a/sys/pc98/cbus/sio.c +++ b/sys/pc98/cbus/sio.c @@ -31,12 +31,13 @@ * SUCH DAMAGE. * * from: @(#)com.c 7.5 (Berkeley) 5/16/91 - * $Id: sio.c,v 1.21 1997/04/05 15:04:32 kato Exp $ + * $Id: sio.c,v 1.22 1997/04/19 14:54:32 kato Exp $ */ #include "opt_comconsole.h" #include "opt_ddb.h" #include "opt_sio.h" +#include "opt_smp.h" #include "sio.h" /* @@ -160,6 +161,16 @@ #include <pccard/slot.h> #endif +#if defined(APIC_IO) +/* + * INTs are masked in the (global) IO APIC, + * but the IRR register is in each LOCAL APIC, + * so we HAVE to unmask the INT to be able to "see INT pending" + * BUT how do we clear them??? + */ +#define isa_irq_pending icu_irq_pending +#endif /* APIC_IO */ + #define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ #define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE) #define RS_IBUFSIZE 256 diff --git a/sys/pc98/conf/files.pc98 b/sys/pc98/conf/files.pc98 index 497b8172e968..94ced2f97a33 100644 --- a/sys/pc98/conf/files.pc98 +++ b/sys/pc98/conf/files.pc98 @@ -3,7 +3,7 @@ # # modified for PC-9801 # -# $Id: files.pc98,v 1.21 1997/04/08 10:33:24 kato Exp $ +# $Id: files.pc98,v 1.22 1997/04/15 11:43:10 kato Exp $ # aic7xxx_asm optional ahc device-driver \ dependency "$S/dev/aic7xxx/*.[chyl]" \ @@ -56,6 +56,10 @@ i386/i386/initcpu.c standard pc98/i386/machdep.c standard i386/i386/math_emulate.c optional math_emulate i386/i386/mem.c standard +i386/i386/mp_machdep.c optional smp +i386/i386/mpapic.c optional smp +i386/i386/mpboot.s optional smp +i386/i386/mplock.s optional smp pc98/i386/microtime.s standard i386/i386/perfmon.c optional perfmon profiling-routine i386/i386/perfmon.c optional perfmon diff --git a/sys/pc98/conf/options.pc98 b/sys/pc98/conf/options.pc98 index d45c99ae9381..190454ea8dfa 100644 --- a/sys/pc98/conf/options.pc98 +++ b/sys/pc98/conf/options.pc98 @@ -1,4 +1,4 @@ -# $Id: options.pc98,v 1.19 1997/03/22 18:54:15 kato Exp $ +# $Id: options.pc98,v 1.20 1997/04/05 15:06:30 kato Exp $ BOUNCEPAGES opt_bounce.h USER_LDT MATH_EMULATE opt_math_emulate.h @@ -28,6 +28,23 @@ PCVT_FREEBSD opt_pcvt.h PCVT_SCANSET opt_pcvt.h XSERVER opt_pcvt.h +SMP opt_smp.h +APIC_IO opt_smp.h +NCPU opt_smp.h +NBUS opt_smp.h +NAPIC opt_smp.h +NINTR opt_smp.h +SMP_TIMER_NC opt_smp.h + +# Should be working. When one cpu flushes it's TLB, it's propagated to all. +SMP_INVLTLB opt_smp_invltlb.h + +# These three are known to be broken, don't enable them. +SMP_PRIVPAGES opt_smp_privpages.h +SMP_AUTOSTART opt_smp_autostart.h + +SERIAL_DEBUG opt_serial.h + AHC_TAGENABLE opt_aic7xxx.h AHC_SCBPAGING_ENABLE opt_aic7xxx.h AHC_ALLOW_MEMIO opt_aic7xxx.h diff --git a/sys/pc98/i386/machdep.c b/sys/pc98/i386/machdep.c index f762f1d41eab..e756255f3ed9 100644 --- a/sys/pc98/i386/machdep.c +++ b/sys/pc98/i386/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.36 1997/04/13 06:02:52 kato Exp $ + * $Id: machdep.c,v 1.37 1997/04/22 12:20:28 kato Exp $ */ #include "npx.h" @@ -44,6 +44,7 @@ #include "opt_bounce.h" #include "opt_machdep.h" #include "opt_perfmon.h" +#include "opt_smp.h" #include "opt_userconfig.h" #include <sys/param.h> @@ -107,6 +108,9 @@ #include <machine/cons.h> #include <machine/bootinfo.h> #include <machine/md_var.h> +#ifdef SMP +#include <machine/smp.h> +#endif #ifdef PERFMON #include <machine/perfmon.h> #endif @@ -220,6 +224,9 @@ cpu_startup(dummy) * Good {morning,afternoon,evening,night}. */ printf(version); +#ifdef SMP + mp_announce(); +#endif earlysetcpuclass(); startrtclock(); printcpuinfo(); @@ -355,6 +362,23 @@ again: u_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (maxproc*UPAGES*PAGE_SIZE), FALSE); +#if defined(SMP) && defined(SMP_PRIVPAGES) + /* Per-cpu pages.. (the story so far is... subject to change) + * ========= For the per-cpu data page ======== + * 1 private data page + * 1 PDE (per-cpu PTD entry page) + * 1 PT (per-cpu page table page) + * ============ For the idle loop ============= + * 2 UPAGEs (per-cpu idle procs) + * 1 PTD (for per-cpu equiv of IdlePTD) + * ============================================ + * = total of 6 pages per cpu. The BSP reuses the ones allocated + * by locore.s during boot to remove special cases at runtime. + */ + ppage_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + (NCPU*6*PAGE_SIZE), FALSE); +#endif + /* * Finally, allocate mbuf pool. Since mclrefcnt is an off-size * we use the more space efficient malloc in place of kmem_alloc. @@ -759,10 +783,24 @@ SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, int currentldt; int _default_ldt; +#ifdef SMP +union descriptor gdt[NGDT + NCPU]; /* global descriptor table */ +#else union descriptor gdt[NGDT]; /* global descriptor table */ +#endif struct gate_descriptor idt[NIDT]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ +#ifdef SMP +/* table descriptors - used to load tables by microp */ +struct region_descriptor r_gdt, r_idt; +#endif + +#ifdef SMP +struct i386tss SMPcommon_tss[NCPU]; /* One tss per cpu */ +struct i386tss *SMPcommon_tss_ptr[NCPU]; /* for the benefit of asmp code */ +#else struct i386tss common_tss; +#endif static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; @@ -775,7 +813,11 @@ int gsel_tss; #endif /* software prototypes -- in more palatable form */ -struct soft_segment_descriptor gdt_segs[] = { +struct soft_segment_descriptor gdt_segs[ +#ifdef SMP + NGDT + NCPU +#endif + ] = { /* GNULL_SEL 0 Null Descriptor */ { 0x0, /* segment base address */ 0x0, /* length */ @@ -831,7 +873,12 @@ struct soft_segment_descriptor gdt_segs[] = { 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GPROC0_SEL 6 Proc 0 Tss Descriptor */ -{ (int) &common_tss, /* segment base address */ +{ +#ifdef SMP + (int) &SMPcommon_tss[0],/* segment base address */ +#else + (int) &common_tss, /* segment base address */ +#endif sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ @@ -979,8 +1026,10 @@ init386(first) int gsel_tss; #endif struct isa_device *idp; +#ifndef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; +#endif int pagesinbase, pagesinext; int target_page, pa_indx; int off; @@ -1020,6 +1069,18 @@ init386(first) for (x = 0; x < NGDT; x++) ssdtosd(&gdt_segs[x], &gdt[x].sd); +#ifdef SMP + /* + * Oh puke! + */ + for (x = 0; x < NCPU; x++) { + SMPcommon_tss_ptr[x] = &SMPcommon_tss[x]; + gdt_segs[NGDT + x] = gdt_segs[GPROC0_SEL]; + gdt_segs[NGDT + x].ssd_base = (int) SMPcommon_tss_ptr[x]; + ssdtosd(&gdt_segs[NGDT + x], &gdt[NGDT + x].sd); + } +#endif + /* make ldt memory segments */ /* * The data segment limit must not cover the user area because we @@ -1180,7 +1241,13 @@ init386(first) } #endif +#ifdef SMP + /* make hole for AP bootstrap code */ + pagesinbase = mp_bootaddress(biosbasemem) / PAGE_SIZE; +#else pagesinbase = biosbasemem * 1024 / PAGE_SIZE; +#endif + pagesinext = biosextmem * 1024 / PAGE_SIZE; /* @@ -1219,6 +1286,11 @@ init386(first) /* call pmap initialization to make new kernel address space */ pmap_bootstrap (first, 0); +#ifdef SMP + /* fire up the APs and APICs */ + mp_start(); +#endif + /* * Size up each available chunk of physical memory. */ @@ -1351,12 +1423,23 @@ init386(first) avail_end + off, VM_PROT_ALL, TRUE); msgbufmapped = 1; +#ifdef SMP + for(x = 0; x < NCPU; x++) { + /* make an initial tss so cpu can get interrupt stack on syscall! */ + SMPcommon_tss[x].tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE; + SMPcommon_tss[x].tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ; + SMPcommon_tss[x].tss_ioopt = (sizeof SMPcommon_tss[x]) << 16; + } + gsel_tss = GSEL(NGDT + cpunumber(), SEL_KPL); + ltr(gsel_tss); +#else /* make an initial tss so cpu can get interrupt stack on syscall! */ common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE; common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ; common_tss.tss_ioopt = (sizeof common_tss) << 16; gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); ltr(gsel_tss); +#endif dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = dblfault_tss.tss_esp2 = (int) &dblfault_stack[sizeof(dblfault_stack)]; @@ -1397,6 +1480,7 @@ init386(first) /* setup proc 0's pcb */ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = IdlePTD; + proc0.p_addr->u_pcb.pcb_mpnest = 1; } /* diff --git a/sys/pc98/i386/microtime.s b/sys/pc98/i386/microtime.s index c1cad833bd37..1f1bb75d9c71 100644 --- a/sys/pc98/i386/microtime.s +++ b/sys/pc98/i386/microtime.s @@ -32,11 +32,15 @@ * SUCH DAMAGE. * * from: Steve McCanne's microtime code - * $Id$ + * $Id: microtime.s,v 1.8 1997/02/22 09:43:27 peter Exp $ */ #include "opt_cpu.h" +#include "opt_smp.h" +#ifdef APIC_IO +#include <machine/apic.h> +#endif /* APIC_IO */ #include <machine/asmacros.h> #include <i386/isa/icu.h> @@ -49,7 +53,7 @@ ENTRY(microtime) -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) movl _i586_ctr_freq, %ecx testl %ecx, %ecx jne pentium_microtime @@ -113,15 +117,26 @@ ENTRY(microtime) movl _timer0_max_count, %edx /* prepare for 2 uses */ +#if defined(APIC_IO) + movl _ipending, %eax + testl %eax, _mask8254 /* is soft timer interrupt pending? */ +#else testb $IRQ0, _ipending /* is a soft timer interrupt pending? */ +#endif /* APIC_IO */ jne overflow /* Do we have a possible overflow condition? */ cmpl _timer0_overflow_threshold, %ecx jbe 1f +#if defined(APIC_IO) + movl _apic_base, %eax + movl APIC_IRR1(%eax), %eax /** XXX assumption: IRQ0-24 */ + testl %eax, _mask8254 /* is a hard timer interrupt pending? */ +#else inb $IO_ICU1, %al /* read IRR in ICU */ testb $IRQ0, %al /* is a hard timer interrupt pending? */ +#endif /* APIC_IO */ je 1f overflow: subl %edx, %ecx /* some intr pending, count timer down through 0 */ @@ -248,7 +263,7 @@ common_microtime: ret -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) ALIGN_TEXT pentium_microtime: pushfl diff --git a/sys/pc98/i386/trap.c b/sys/pc98/i386/trap.c index 44a37a09fbbb..c456b3ca82dc 100644 --- a/sys/pc98/i386/trap.c +++ b/sys/pc98/i386/trap.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $Id: trap.c,v 1.16 1997/04/07 11:00:48 kato Exp $ + * $Id: trap.c,v 1.17 1997/04/15 11:49:00 kato Exp $ */ /* @@ -44,6 +44,7 @@ #include "opt_ktrace.h" #include "opt_ddb.h" +#include "opt_smp.h" #include <sys/param.h> #include <sys/systm.h> @@ -76,6 +77,7 @@ #include <machine/reg.h> #include <machine/trap.h> #include <machine/../isa/isa_device.h> +#include <machine/smp.h> #ifdef POWERFAIL_NMI #include <sys/syslog.h> @@ -85,7 +87,11 @@ #include "isa.h" #include "npx.h" +#ifdef SMP +extern struct i386tss *SMPcommon_tss_ptr[NCPU]; +#else extern struct i386tss common_tss; +#endif int (*pmath_emulate) __P((struct trapframe *)); @@ -728,6 +734,9 @@ trap_fatal(frame) printf("\n\nFatal trap %d: %s while in %s mode\n", type, trap_msg[type], ISPL(frame->tf_cs) == SEL_UPL ? "user" : "kernel"); +#ifdef SMP + printf("cpunumber = %d\n", cpunumber()); +#endif if (type == T_PAGEFLT) { printf("fault virtual address = 0x%x\n", eva); printf("fault code = %s %s, %s\n", @@ -790,6 +799,7 @@ trap_fatal(frame) if (kdb_trap (type, 0, frame)) return; #endif + printf("trap number = %d\n", type); if (type <= MAX_TRAP_MSG) panic(trap_msg[type]); else @@ -811,11 +821,20 @@ trap_fatal(frame) void dblfault_handler() { +#ifdef SMP + int x = cpunumber(); +#endif printf("\nFatal double fault:\n"); +#ifdef SMP + printf("eip = 0x%x\n", SMPcommon_tss_ptr[x]->tss_eip); + printf("esp = 0x%x\n", SMPcommon_tss_ptr[x]->tss_esp); + printf("ebp = 0x%x\n", SMPcommon_tss_ptr[x]->tss_ebp); +#else printf("eip = 0x%x\n", common_tss.tss_eip); printf("esp = 0x%x\n", common_tss.tss_esp); printf("ebp = 0x%x\n", common_tss.tss_ebp); +#endif panic("double fault"); } diff --git a/sys/pc98/pc98/clock.c b/sys/pc98/pc98/clock.c index c18ae1e08217..28c2a03b1893 100644 --- a/sys/pc98/pc98/clock.c +++ b/sys/pc98/pc98/clock.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)clock.c 7.2 (Berkeley) 5/12/91 - * $Id: clock.c,v 1.18 1997/03/05 16:19:48 kato Exp $ + * $Id: clock.c,v 1.19 1997/04/07 10:53:14 kato Exp $ */ /* @@ -53,6 +53,7 @@ */ #include "opt_clock.h" +#include "opt_smp.h" #include "opt_cpu.h" #include <sys/param.h> @@ -110,7 +111,7 @@ int adjkerntz; /* local offset from GMT in seconds */ int disable_rtc_set; /* disable resettodr() if != 0 */ u_int idelayed; -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) u_int i586_ctr_bias; u_int i586_ctr_comultiplier; u_int i586_ctr_freq; @@ -176,7 +177,7 @@ static int rtc_inb __P((void)); static void rtc_outb __P((int)); #endif -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) static void set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq); #endif static void set_timer_freq(u_int freq, int intr_freq); @@ -694,7 +695,7 @@ calibrate_clocks(void) goto fail; tot_count = 0; -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) if (cpu_class == CPUCLASS_586 || cpu_class == CPUCLASS_686) wrmsr(0x10, 0LL); /* XXX 0x10 is the MSR for the TSC */ #endif @@ -727,7 +728,7 @@ calibrate_clocks(void) goto fail; } -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) /* * Read the cpu cycle counter. The timing considerations are * similar to those for the i8254 clock. @@ -832,7 +833,7 @@ startrtclock() printf( "%d Hz differs from default of %d Hz by more than 1%%\n", freq, timer_freq); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) i586_ctr_freq = 0; #endif } @@ -840,7 +841,7 @@ startrtclock() set_timer_freq(timer_freq, hz); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) #ifndef CLK_USE_I586_CALIBRATION if (i586_ctr_freq != 0) { if (bootverbose) @@ -1123,12 +1124,29 @@ resettodr() #endif } +#if defined(APIC_IO) + +/* from icu.s: */ +extern u_int hwisrs[]; +extern void vec8254 __P((void)); +extern void vecRTC __P((void)); +extern u_int ivectors[]; +extern u_int Xintr8254; +extern u_int XintrRTC; +extern u_int mask8254; +extern u_int maskRTC; + +#endif /* APIC_IO */ + /* * Start both clocks running. */ void cpu_initclocks() { +#if defined(APIC_IO) + int x; +#endif /* APIC_IO */ #ifndef PC98 int diag; @@ -1149,11 +1167,51 @@ cpu_initclocks() #endif /* Finish initializing 8253 timer 0. */ +#if defined(APIC_IO) + /* 8254 is traditionally on ISA IRQ0 */ + if ((x = get_isa_apic_irq(0)) < 0) { + /* + * bummer, this mb doesn't have the 8254 on ISA irq0, + * perhaps it's on the EISA bus... + */ + if ((x = get_eisa_apic_irq(0)) < 0) { + /* double bummer, attempt to redirect thru the 8259 */ + if (bootverbose) + printf("APIC missing 8254 connection\n"); + + /* allow 8254 timer to INTerrupt 8259 */ +#if !defined(IO_ICU1) +#ifdef PC98 +#define IO_ICU1 0x00 +#else +#define IO_ICU1 0x20 +#endif +#endif + x = inb(IO_ICU1 + 1); /* current mask in 8259 */ + x &= ~1; /* clear 8254 timer mask */ + outb(IO_ICU1 + 1, x); /* write new mask */ + + /* program IO APIC for type 3 INT on INT0 */ + if (ext_int_setup(0, 0) < 0) + panic("8254 redirect impossible!"); + x = 0; /* 8259 is on 0 */ + } + } + + hwisrs[x] = (u_int)vec8254; + Xintr8254 = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ + mask8254 = (1 << x); + register_intr(/* irq */ x, /* XXX id */ 0, /* flags */ 0, + /* XXX */ (inthand2_t *)clkintr, &clk_imask, + /* unit */ 0); + INTREN(mask8254); +#else register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, /* XXX */ (inthand2_t *)clkintr, &clk_imask, /* unit */ 0); INTREN(IRQ0); -#if defined(I586_CPU) || defined(I686_CPU) +#endif /* APIC_IO */ +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) /* * Finish setting up anti-jitter measures. */ @@ -1172,12 +1230,37 @@ cpu_initclocks() diag = rtcin(RTC_DIAG); if (diag != 0) printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); +#if defined(APIC_IO) + /* RTC is traditionally on ISA IRQ8 */ + if ((x = get_isa_apic_irq(8)) < 0) { + if ((x = get_eisa_apic_irq(8)) < 0) { + panic("APIC missing RTC connection"); + } + } + + hwisrs[x] = (u_int)vecRTC; + XintrRTC = (u_int)ivectors[x]; /* XXX might need Xfastintr# */ + maskRTC = (1 << x); + register_intr(/* irq */ x, /* XXX id */ 1, /* flags */ 0, + /* XXX */ (inthand2_t *)rtcintr, &stat_imask, + /* unit */ 0); + INTREN(maskRTC); +#else register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, /* XXX */ (inthand2_t *)rtcintr, &stat_imask, /* unit */ 0); INTREN(IRQ8); +#endif /* APIC_IO */ writertc(RTC_STATUSB, rtc_statusb); #endif + +#if defined(APIC_IO) + printf("Enabled INTs: "); + for (x = 0; x < 24; ++x) + if ((imen & (1 << x)) == 0) + printf("%d, ", x); + printf("imen: 0x%08x\n", imen); +#endif /* APIC_IO */ } void @@ -1208,7 +1291,7 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS if (timer0_state != 0) return (EBUSY); /* too much trouble to handle */ set_timer_freq(freq, hz); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) set_i586_ctr_freq(i586_ctr_freq, timer_freq); #endif } @@ -1218,7 +1301,7 @@ sysctl_machdep_i8254_freq SYSCTL_HANDLER_ARGS SYSCTL_PROC(_machdep, OID_AUTO, i8254_freq, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(u_int), sysctl_machdep_i8254_freq, "I", ""); -#if defined(I586_CPU) || defined(I686_CPU) +#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) static void set_i586_ctr_freq(u_int i586_freq, u_int i8254_freq) { @@ -1257,4 +1340,4 @@ sysctl_machdep_i586_freq SYSCTL_HANDLER_ARGS SYSCTL_PROC(_machdep, OID_AUTO, i586_freq, CTLTYPE_INT | CTLFLAG_RW, 0, sizeof(u_int), sysctl_machdep_i586_freq, "I", ""); -#endif /* defined(I586_CPU) || defined(I686_CPU) */ +#endif /* (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP) */ diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c index f762f1d41eab..e756255f3ed9 100644 --- a/sys/pc98/pc98/machdep.c +++ b/sys/pc98/pc98/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.36 1997/04/13 06:02:52 kato Exp $ + * $Id: machdep.c,v 1.37 1997/04/22 12:20:28 kato Exp $ */ #include "npx.h" @@ -44,6 +44,7 @@ #include "opt_bounce.h" #include "opt_machdep.h" #include "opt_perfmon.h" +#include "opt_smp.h" #include "opt_userconfig.h" #include <sys/param.h> @@ -107,6 +108,9 @@ #include <machine/cons.h> #include <machine/bootinfo.h> #include <machine/md_var.h> +#ifdef SMP +#include <machine/smp.h> +#endif #ifdef PERFMON #include <machine/perfmon.h> #endif @@ -220,6 +224,9 @@ cpu_startup(dummy) * Good {morning,afternoon,evening,night}. */ printf(version); +#ifdef SMP + mp_announce(); +#endif earlysetcpuclass(); startrtclock(); printcpuinfo(); @@ -355,6 +362,23 @@ again: u_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, (maxproc*UPAGES*PAGE_SIZE), FALSE); +#if defined(SMP) && defined(SMP_PRIVPAGES) + /* Per-cpu pages.. (the story so far is... subject to change) + * ========= For the per-cpu data page ======== + * 1 private data page + * 1 PDE (per-cpu PTD entry page) + * 1 PT (per-cpu page table page) + * ============ For the idle loop ============= + * 2 UPAGEs (per-cpu idle procs) + * 1 PTD (for per-cpu equiv of IdlePTD) + * ============================================ + * = total of 6 pages per cpu. The BSP reuses the ones allocated + * by locore.s during boot to remove special cases at runtime. + */ + ppage_map = kmem_suballoc(kernel_map, &minaddr, &maxaddr, + (NCPU*6*PAGE_SIZE), FALSE); +#endif + /* * Finally, allocate mbuf pool. Since mclrefcnt is an off-size * we use the more space efficient malloc in place of kmem_alloc. @@ -759,10 +783,24 @@ SYSCTL_INT(_machdep, CPU_WALLCLOCK, wall_cmos_clock, int currentldt; int _default_ldt; +#ifdef SMP +union descriptor gdt[NGDT + NCPU]; /* global descriptor table */ +#else union descriptor gdt[NGDT]; /* global descriptor table */ +#endif struct gate_descriptor idt[NIDT]; /* interrupt descriptor table */ union descriptor ldt[NLDT]; /* local descriptor table */ +#ifdef SMP +/* table descriptors - used to load tables by microp */ +struct region_descriptor r_gdt, r_idt; +#endif + +#ifdef SMP +struct i386tss SMPcommon_tss[NCPU]; /* One tss per cpu */ +struct i386tss *SMPcommon_tss_ptr[NCPU]; /* for the benefit of asmp code */ +#else struct i386tss common_tss; +#endif static struct i386tss dblfault_tss; static char dblfault_stack[PAGE_SIZE]; @@ -775,7 +813,11 @@ int gsel_tss; #endif /* software prototypes -- in more palatable form */ -struct soft_segment_descriptor gdt_segs[] = { +struct soft_segment_descriptor gdt_segs[ +#ifdef SMP + NGDT + NCPU +#endif + ] = { /* GNULL_SEL 0 Null Descriptor */ { 0x0, /* segment base address */ 0x0, /* length */ @@ -831,7 +873,12 @@ struct soft_segment_descriptor gdt_segs[] = { 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* GPROC0_SEL 6 Proc 0 Tss Descriptor */ -{ (int) &common_tss, /* segment base address */ +{ +#ifdef SMP + (int) &SMPcommon_tss[0],/* segment base address */ +#else + (int) &common_tss, /* segment base address */ +#endif sizeof(struct i386tss)-1,/* length - all address space */ SDT_SYS386TSS, /* segment type */ 0, /* segment descriptor priority level */ @@ -979,8 +1026,10 @@ init386(first) int gsel_tss; #endif struct isa_device *idp; +#ifndef SMP /* table descriptors - used to load tables by microp */ struct region_descriptor r_gdt, r_idt; +#endif int pagesinbase, pagesinext; int target_page, pa_indx; int off; @@ -1020,6 +1069,18 @@ init386(first) for (x = 0; x < NGDT; x++) ssdtosd(&gdt_segs[x], &gdt[x].sd); +#ifdef SMP + /* + * Oh puke! + */ + for (x = 0; x < NCPU; x++) { + SMPcommon_tss_ptr[x] = &SMPcommon_tss[x]; + gdt_segs[NGDT + x] = gdt_segs[GPROC0_SEL]; + gdt_segs[NGDT + x].ssd_base = (int) SMPcommon_tss_ptr[x]; + ssdtosd(&gdt_segs[NGDT + x], &gdt[NGDT + x].sd); + } +#endif + /* make ldt memory segments */ /* * The data segment limit must not cover the user area because we @@ -1180,7 +1241,13 @@ init386(first) } #endif +#ifdef SMP + /* make hole for AP bootstrap code */ + pagesinbase = mp_bootaddress(biosbasemem) / PAGE_SIZE; +#else pagesinbase = biosbasemem * 1024 / PAGE_SIZE; +#endif + pagesinext = biosextmem * 1024 / PAGE_SIZE; /* @@ -1219,6 +1286,11 @@ init386(first) /* call pmap initialization to make new kernel address space */ pmap_bootstrap (first, 0); +#ifdef SMP + /* fire up the APs and APICs */ + mp_start(); +#endif + /* * Size up each available chunk of physical memory. */ @@ -1351,12 +1423,23 @@ init386(first) avail_end + off, VM_PROT_ALL, TRUE); msgbufmapped = 1; +#ifdef SMP + for(x = 0; x < NCPU; x++) { + /* make an initial tss so cpu can get interrupt stack on syscall! */ + SMPcommon_tss[x].tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE; + SMPcommon_tss[x].tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ; + SMPcommon_tss[x].tss_ioopt = (sizeof SMPcommon_tss[x]) << 16; + } + gsel_tss = GSEL(NGDT + cpunumber(), SEL_KPL); + ltr(gsel_tss); +#else /* make an initial tss so cpu can get interrupt stack on syscall! */ common_tss.tss_esp0 = (int) proc0.p_addr + UPAGES*PAGE_SIZE; common_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ; common_tss.tss_ioopt = (sizeof common_tss) << 16; gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); ltr(gsel_tss); +#endif dblfault_tss.tss_esp = dblfault_tss.tss_esp0 = dblfault_tss.tss_esp1 = dblfault_tss.tss_esp2 = (int) &dblfault_stack[sizeof(dblfault_stack)]; @@ -1397,6 +1480,7 @@ init386(first) /* setup proc 0's pcb */ proc0.p_addr->u_pcb.pcb_flags = 0; proc0.p_addr->u_pcb.pcb_cr3 = IdlePTD; + proc0.p_addr->u_pcb.pcb_mpnest = 1; } /* diff --git a/sys/pc98/pc98/npx.c b/sys/pc98/pc98/npx.c index 4249fe01b48e..3f8cd7bf1089 100644 --- a/sys/pc98/pc98/npx.c +++ b/sys/pc98/pc98/npx.c @@ -32,7 +32,7 @@ * SUCH DAMAGE. * * from: @(#)npx.c 7.2 (Berkeley) 5/12/91 - * $Id: npx.c,v 1.15 1997/03/24 12:29:39 bde Exp $ + * $Id: npx.c,v 1.16 1997/04/22 12:20:50 kato Exp $ */ #include "npx.h" @@ -40,6 +40,7 @@ #include "opt_cpu.h" #include "opt_math_emulate.h" +#include "opt_smp.h" #include <sys/param.h> #include <sys/systm.h> @@ -60,6 +61,10 @@ #include <machine/trap.h> #include <machine/clock.h> #include <machine/specialreg.h> +#if defined(APIC_IO) +#include <machine/apic.h> +#include <machine/mpapic.h> +#endif /* APIC_IO */ #include <i386/isa/icu.h> #include <i386/isa/isa_device.h> @@ -138,7 +143,12 @@ SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, "Floatingpoint instructions executed in hardware"); static u_int npx0_imask = SWI_CLOCK_MASK; +#ifdef SMP +#define npxproc (SMPnpxproc[cpunumber()]) +struct proc *SMPnpxproc[NCPU]; +#else struct proc *npxproc; +#endif static bool_t npx_ex16; static bool_t npx_exists; @@ -153,8 +163,32 @@ static volatile u_int npx_traps_while_probing; * interrupts. We'll still need a special exception 16 handler. The busy * latch stuff in probeintr() can be moved to npxprobe(). */ - inthand_t probeintr; + +#if defined(APIC_IO) + +asm +(" + .text + .p2align 2,0x90 +" __XSTRING(CNAME(probeintr)) ": + ss + incl " __XSTRING(CNAME(npx_intrs_while_probing)) " + pushl %eax + movl " __XSTRING(CNAME(apic_base)) ",%eax # EOI to local APIC + movl $0,0xb0(,%eax,1) # movl $0, APIC_EOI(%eax) + movb $0,%al +#ifdef PC98 + outb %al,$0xf8 # clear BUSY# latch +#else + outb %al,$0xf0 # clear BUSY# latch +#endif + popl %eax + iret +"); + +#else + asm (" .text @@ -181,6 +215,8 @@ asm iret "); +#endif /* APIC_IO */ + inthand_t probetrap; asm (" @@ -205,8 +241,12 @@ npxprobe(dvp) { int result; u_long save_eflags; +#if defined(APIC_IO) + u_int save_apic_mask; +#else u_char save_icu1_mask; u_char save_icu2_mask; +#endif /* APIC_IO */ struct gate_descriptor save_idt_npxintr; struct gate_descriptor save_idt_npxtrap; /* @@ -219,6 +259,9 @@ npxprobe(dvp) npx_intrno = NRSVIDT + ffs(dvp->id_irq) - 1; save_eflags = read_eflags(); disable_intr(); +#if defined(APIC_IO) + save_apic_mask = INTRGET(); +#else #ifdef PC98 save_icu1_mask = inb(IO_ICU1 + 2); save_icu2_mask = inb(IO_ICU2 + 2); @@ -226,8 +269,12 @@ npxprobe(dvp) save_icu1_mask = inb(IO_ICU1 + 1); save_icu2_mask = inb(IO_ICU2 + 1); #endif +#endif /* APIC_IO */ save_idt_npxintr = idt[npx_intrno]; save_idt_npxtrap = idt[16]; +#if defined(APIC_IO) + INTRSET( ~dvp->id_irq ); +#else #ifdef PC98 outb(IO_ICU1 + 2, ~(IRQ_SLAVE | dvp->id_irq)); outb(IO_ICU2 + 2, ~(dvp->id_irq >> 8)); @@ -235,12 +282,16 @@ npxprobe(dvp) outb(IO_ICU1 + 1, ~(IRQ_SLAVE | dvp->id_irq)); outb(IO_ICU2 + 1, ~(dvp->id_irq >> 8)); #endif +#endif /* APIC_IO */ setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); npx_idt_probeintr = idt[npx_intrno]; enable_intr(); result = npxprobe1(dvp); disable_intr(); +#if defined(APIC_IO) + INTRSET( save_apic_mask ); +#else #ifdef PC98 outb(IO_ICU1 + 2, save_icu1_mask); outb(IO_ICU2 + 2, save_icu2_mask); @@ -248,6 +299,7 @@ npxprobe(dvp) outb(IO_ICU1 + 1, save_icu1_mask); outb(IO_ICU2 + 1, save_icu2_mask); #endif +#endif /* APIC_IO */ idt[npx_intrno] = save_idt_npxintr; idt[16] = save_idt_npxtrap; write_eflags(save_eflags); @@ -406,7 +458,8 @@ npxattach(dvp) } npxinit(__INITIAL_NPXCW__); -#ifdef I586_CPU +#if defined(I586_CPU) && !defined(SMP) + /* FPU not working under SMP yet */ if (cpu_class == CPUCLASS_586 && npx_ex16) { if (!(dvp->id_flags & NPX_DISABLE_I586_OPTIMIZED_BCOPY)) { bcopy_vector = i586_bcopy; @@ -622,13 +675,21 @@ void npxsave(addr) struct save87 *addr; { +#if defined(APIC_IO) + u_int apic_mask; + u_int old_apic_mask; +#else u_char icu1_mask; u_char icu2_mask; u_char old_icu1_mask; u_char old_icu2_mask; +#endif /* APIC_IO */ struct gate_descriptor save_idt_npxintr; disable_intr(); +#if defined(APIC_IO) + old_apic_mask = INTRGET(); +#else #ifdef PC98 old_icu1_mask = inb(IO_ICU1 + 2); old_icu2_mask = inb(IO_ICU2 + 2); @@ -636,7 +697,12 @@ npxsave(addr) old_icu1_mask = inb(IO_ICU1 + 1); old_icu2_mask = inb(IO_ICU2 + 1); #endif +#endif /* APIC_IO */ save_idt_npxintr = idt[npx_intrno]; +#if defined(APIC_IO) + /** FIXME: try clrIoApicMaskBit( npx0_imask ); */ + INTRSET( old_apic_mask & ~(npx0_imask & 0xffff) ); +#else #ifdef PC98 outb(IO_ICU1 + 2, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask)); outb(IO_ICU2 + 2, old_icu2_mask & ~(npx0_imask >> 8)); @@ -644,6 +710,7 @@ npxsave(addr) outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask)); outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8)); #endif +#endif /* APIC_IO */ idt[npx_intrno] = npx_idt_probeintr; enable_intr(); stop_emulating(); @@ -652,6 +719,11 @@ npxsave(addr) start_emulating(); npxproc = NULL; disable_intr(); +#if defined(APIC_IO) + apic_mask = INTRGET(); /* masks may have changed */ + INTRSET( (apic_mask & ~(npx0_imask & 0xffff)) | + (old_apic_mask & (npx0_imask & 0xffff))); +#else #ifdef PC98 icu1_mask = inb(IO_ICU1 + 2); /* masks may have changed */ icu2_mask = inb(IO_ICU2 + 2); @@ -669,6 +741,7 @@ npxsave(addr) (icu2_mask & ~(npx0_imask >> 8)) | (old_icu2_mask & (npx0_imask >> 8))); #endif +#endif /* APIC_IO */ idt[npx_intrno] = save_idt_npxintr; enable_intr(); /* back to usual state */ } diff --git a/sys/pc98/pc98/pc98.c b/sys/pc98/pc98/pc98.c index f99043271683..76527159d9bc 100644 --- a/sys/pc98/pc98/pc98.c +++ b/sys/pc98/pc98/pc98.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: pc98.c,v 1.21 1997/03/29 02:43:49 kato Exp $ + * $Id: pc98.c,v 1.22 1997/04/11 12:29:51 kato Exp $ */ /* @@ -53,6 +53,7 @@ */ #include "opt_auto_eoi.h" +#include "opt_smp.h" #include "opt_ddb.h" #include <sys/param.h> @@ -62,6 +63,10 @@ #include <sys/malloc.h> #include <machine/md_var.h> #include <machine/segments.h> +#if defined(APIC_IO) +#include <machine/smp.h> +#include <machine/apic.h> +#endif /* APIC_IO */ #include <vm/vm.h> #include <vm/vm_param.h> #include <vm/pmap.h> @@ -78,6 +83,14 @@ #include <i386/isa/ic/i8237.h> #include "vector.h" +#ifdef APIC_IO +/* + * This is to accommodate "mixed-mode" programming for + * motherboards that don't connect the 8254 to the IO APIC. + */ +#define AUTO_EOI_1 +#endif + /* ** Register definitions for DMA controller 1 (channels 0..3): */ @@ -116,6 +129,16 @@ static inthand_t *fastintr[ICU_LEN] = { &IDTVEC(fastintr10), &IDTVEC(fastintr11), &IDTVEC(fastintr12), &IDTVEC(fastintr13), &IDTVEC(fastintr14), &IDTVEC(fastintr15) +#if defined(APIC_IO) + , &IDTVEC(fastintr16), &IDTVEC(fastintr17), + &IDTVEC(fastintr18), &IDTVEC(fastintr19), + &IDTVEC(fastintr20), &IDTVEC(fastintr21), + &IDTVEC(fastintr22), &IDTVEC(fastintr23) +#if defined(IPI_INTS) +/* XXX probably NOT needed, we register_intr(slowintr[I]) */ + , &IDTVEC(ipi24), &IDTVEC(ipi25), &IDTVEC(ipi26), &IDTVEC(ipi27) +#endif /* IPI_INTS */ +#endif /* APIC_IO */ }; static inthand_t *slowintr[ICU_LEN] = { @@ -123,6 +146,13 @@ static inthand_t *slowintr[ICU_LEN] = { &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) +#if defined(APIC_IO) + , &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19), + &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23) +#if defined(IPI_INTS) + , &IDTVEC(ipi24), &IDTVEC(ipi25), &IDTVEC(ipi26), &IDTVEC(ipi27) +#endif /* IPI_INTS */ +#endif /* APIC_IO */ }; static void config_isadev __P((struct isa_device *isdp, u_int *mp)); @@ -1016,6 +1046,39 @@ struct isa_device *find_isadev(table, driverp, unit) /* * Return nonzero if a (masked) irq is pending for a given device. */ +#if defined(APIC_IO) + +int +isa_irq_pending(dvp) + struct isa_device *dvp; +{ + /* read APIC IRR containing the 16 ISA INTerrupts */ +#if defined(TEST_UPPERPRIO) + if ((u_int32_t)dvp->id_irq == APIC_IRQ10) + return (int)(apic_base[APIC_IRR2] & 1); + else +#endif /** TEST_UPPERPRIO */ + return ((apic_base[APIC_IRR1] & 0x00ffffff) + & (u_int32_t)dvp->id_irq) ? 1 : 0; +} + +/* + * an 8259 specific routine, + * for use by boot probes in certain device drivers. + */ +int +icu_irq_pending(dvp) + struct isa_device *dvp; +{ + unsigned id_irq; + id_irq = dvp->id_irq; + if (id_irq & 0xff) + return (inb(IO_ICU1) & id_irq); + return (inb(IO_ICU2) & (id_irq >> 8)); +} + +#else /* APIC_IO */ + int isa_irq_pending(dvp) struct isa_device *dvp; @@ -1028,6 +1091,8 @@ isa_irq_pending(dvp) return (inb(IO_ICU2) & (id_irq >> 8)); } +#endif /* APIC_IO */ + int update_intr_masks(void) { @@ -1035,11 +1100,15 @@ update_intr_masks(void) u_int mask,*maskptr; for (intr=0; intr < ICU_LEN; intr ++) { +#if defined(APIC_IO) + /* no 8259 SLAVE to ignore */ +#else #ifdef PC98 - if (intr==7) continue; + if (intr==7) continue; /* ignore 8259 SLAVE output */ #else - if (intr==2) continue; + if (intr==2) continue; /* ignore 8259 SLAVE output */ #endif +#endif /* APIC_IO */ maskptr = intr_mptr[intr]; if (!maskptr) continue; *maskptr |= 1 << intr; @@ -1071,11 +1140,15 @@ register_intr(intr, device_id, flags, handler, maskptr, unit) int id; u_int mask = (maskptr ? *maskptr : 0); +#if defined(APIC_IO) + if ((u_int)intr >= ICU_LEN /* no 8259 SLAVE to ignore */ +#else #ifdef PC98 if ((u_int)intr >= ICU_LEN || intr == 7 #else if ((u_int)intr >= ICU_LEN || intr == 2 #endif +#endif /* APIC_IO */ || (u_int)device_id >= NR_DEVICES) return (EINVAL); if (intr_handler[intr] != isa_strayintr) @@ -1087,9 +1160,24 @@ register_intr(intr, device_id, flags, handler, maskptr, unit) intr_mptr[intr] = maskptr; intr_mask[intr] = mask | (1 << intr); intr_unit[intr] = unit; +#if defined(TEST_UPPERPRIO) + if (intr == 10) { + printf("--- setting IRQ10 to IDT64\n"); + setidt(64, + flags & RI_FAST ? fastintr[intr] : slowintr[intr], + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + } + else { + printf("setting IRQ%02d to IDT%02d\n", intr, ICU_OFFSET+intr); + setidt(ICU_OFFSET + intr, + flags & RI_FAST ? fastintr[intr] : slowintr[intr], + SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); + } +#else setidt(ICU_OFFSET + intr, flags & RI_FAST ? fastintr[intr] : slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#endif /** TEST_UPPERPRIO */ write_eflags(ef); for (cp = intrnames, id = 0; id <= device_id; id++) while (*cp++ != '\0') @@ -1099,9 +1187,12 @@ register_intr(intr, device_id, flags, handler, maskptr, unit) if (intr < 10) { cp[-3] = intr + '0'; cp[-2] = ' '; - } else { + } else if (intr < 20) { cp[-3] = '1'; cp[-2] = intr - 10 + '0'; + } else { + cp[-3] = '2'; + cp[-2] = intr - 20 + '0'; } return (0); } diff --git a/sys/pc98/pc98/sio.c b/sys/pc98/pc98/sio.c index ac96b9deaa9e..320740868ab1 100644 --- a/sys/pc98/pc98/sio.c +++ b/sys/pc98/pc98/sio.c @@ -31,12 +31,13 @@ * SUCH DAMAGE. * * from: @(#)com.c 7.5 (Berkeley) 5/16/91 - * $Id: sio.c,v 1.21 1997/04/05 15:04:32 kato Exp $ + * $Id: sio.c,v 1.22 1997/04/19 14:54:32 kato Exp $ */ #include "opt_comconsole.h" #include "opt_ddb.h" #include "opt_sio.h" +#include "opt_smp.h" #include "sio.h" /* @@ -160,6 +161,16 @@ #include <pccard/slot.h> #endif +#if defined(APIC_IO) +/* + * INTs are masked in the (global) IO APIC, + * but the IRR register is in each LOCAL APIC, + * so we HAVE to unmask the INT to be able to "see INT pending" + * BUT how do we clear them??? + */ +#define isa_irq_pending icu_irq_pending +#endif /* APIC_IO */ + #define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */ #define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE) #define RS_IBUFSIZE 256 |