Deleted Added
full compact
mptable.c (75724) mptable.c (76078)
1/*
2 * Copyright (c) 1996, by Steve Passe
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 8 unchanged lines hidden (view full) ---

17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
1/*
2 * Copyright (c) 1996, by Steve Passe
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 8 unchanged lines hidden (view full) ---

17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: head/sys/i386/i386/mptable.c 75724 2001-04-20 01:09:05Z jhb $
25 * $FreeBSD: head/sys/i386/i386/mptable.c 76078 2001-04-27 19:28:25Z jhb $
26 */
27
28#include "opt_cpu.h"
29
30#ifdef SMP
31#include <machine/smptests.h>
32#else
33#error
34#endif
35
36#include <sys/param.h>
37#include <sys/bus.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/proc.h>
41#include <sys/sysctl.h>
42#include <sys/malloc.h>
43#include <sys/memrange.h>
44#include <sys/mutex.h>
26 */
27
28#include "opt_cpu.h"
29
30#ifdef SMP
31#include <machine/smptests.h>
32#else
33#error
34#endif
35
36#include <sys/param.h>
37#include <sys/bus.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/proc.h>
41#include <sys/sysctl.h>
42#include <sys/malloc.h>
43#include <sys/memrange.h>
44#include <sys/mutex.h>
45#include <sys/smp.h>
45#include <sys/dkstat.h>
46#include <sys/cons.h> /* cngetc() */
47
48#include <vm/vm.h>
49#include <vm/vm_param.h>
50#include <vm/pmap.h>
51#include <vm/vm_kern.h>
52#include <vm/vm_extern.h>
53#include <sys/lock.h>
54#include <vm/vm_map.h>
55#include <sys/user.h>
56#ifdef GPROF
57#include <sys/gmon.h>
58#endif
59
46#include <sys/dkstat.h>
47#include <sys/cons.h> /* cngetc() */
48
49#include <vm/vm.h>
50#include <vm/vm_param.h>
51#include <vm/pmap.h>
52#include <vm/vm_kern.h>
53#include <vm/vm_extern.h>
54#include <sys/lock.h>
55#include <vm/vm_map.h>
56#include <sys/user.h>
57#ifdef GPROF
58#include <sys/gmon.h>
59#endif
60
60#include <machine/smp.h>
61#include <machine/apic.h>
62#include <machine/atomic.h>
61#include <machine/apic.h>
62#include <machine/atomic.h>
63#include <machine/cpu.h>
63#include <machine/cpufunc.h>
64#include <machine/ipl.h>
65#include <machine/mpapic.h>
66#include <machine/psl.h>
67#include <machine/segments.h>
68#include <machine/smptests.h> /** TEST_DEFAULT_CONFIG, TEST_TEST1 */
69#include <machine/tss.h>
70#include <machine/specialreg.h>

--- 167 unchanged lines hidden (view full) ---

238
239/** XXX FIXME: where does this really belong, isa.h/isa.c perhaps? */
240int current_postcode;
241
242/** XXX FIXME: what system files declare these??? */
243extern struct region_descriptor r_gdt, r_idt;
244
245int bsp_apic_ready = 0; /* flags useability of BSP apic */
64#include <machine/cpufunc.h>
65#include <machine/ipl.h>
66#include <machine/mpapic.h>
67#include <machine/psl.h>
68#include <machine/segments.h>
69#include <machine/smptests.h> /** TEST_DEFAULT_CONFIG, TEST_TEST1 */
70#include <machine/tss.h>
71#include <machine/specialreg.h>

--- 167 unchanged lines hidden (view full) ---

239
240/** XXX FIXME: where does this really belong, isa.h/isa.c perhaps? */
241int current_postcode;
242
243/** XXX FIXME: what system files declare these??? */
244extern struct region_descriptor r_gdt, r_idt;
245
246int bsp_apic_ready = 0; /* flags useability of BSP apic */
246int mp_ncpus; /* # of CPUs, including BSP */
247int mp_naps; /* # of Applications processors */
248int mp_nbusses; /* # of busses */
249int mp_napics; /* # of IO APICs */
250int boot_cpu_id; /* designated BSP */
251vm_offset_t cpu_apic_address;
252vm_offset_t io_apic_address[NAPICID]; /* NAPICID is more than enough */
253extern int nkpt;
254

--- 13 unchanged lines hidden (view full) ---

268 * APIC ID logical/physical mapping structures.
269 * We oversize these to simplify boot-time config.
270 */
271int cpu_num_to_apic_id[NAPICID];
272int io_num_to_apic_id[NAPICID];
273int apic_id_to_logical[NAPICID];
274
275
247int mp_naps; /* # of Applications processors */
248int mp_nbusses; /* # of busses */
249int mp_napics; /* # of IO APICs */
250int boot_cpu_id; /* designated BSP */
251vm_offset_t cpu_apic_address;
252vm_offset_t io_apic_address[NAPICID]; /* NAPICID is more than enough */
253extern int nkpt;
254

--- 13 unchanged lines hidden (view full) ---

268 * APIC ID logical/physical mapping structures.
269 * We oversize these to simplify boot-time config.
270 */
271int cpu_num_to_apic_id[NAPICID];
272int io_num_to_apic_id[NAPICID];
273int apic_id_to_logical[NAPICID];
274
275
276/* Bitmap of all available CPUs */
277u_int all_cpus;
278
279/* AP uses this during bootstrap. Do not staticize. */
280char *bootSTK;
281static int bootAP;
282
283/* Hotwire a 0->4MB V==P mapping */
284extern pt_entry_t *KPTphys;
285
286/* SMP page table page */
287extern pt_entry_t *SMPpt;
288
289struct pcb stoppcbs[MAXCPU];
290
276/* AP uses this during bootstrap. Do not staticize. */
277char *bootSTK;
278static int bootAP;
279
280/* Hotwire a 0->4MB V==P mapping */
281extern pt_entry_t *KPTphys;
282
283/* SMP page table page */
284extern pt_entry_t *SMPpt;
285
286struct pcb stoppcbs[MAXCPU];
287
291int smp_started; /* has the system started? */
292int smp_active = 0; /* are the APs allowed to run? */
293SYSCTL_INT(_machdep, OID_AUTO, smp_active, CTLFLAG_RW, &smp_active, 0, "");
294
295/* XXX maybe should be hw.ncpu */
296static int smp_cpus = 1; /* how many cpu's running */
297SYSCTL_INT(_machdep, OID_AUTO, smp_cpus, CTLFLAG_RD, &smp_cpus, 0, "");
298
299int invltlb_ok = 0; /* throttle smp_invltlb() till safe */
300SYSCTL_INT(_machdep, OID_AUTO, invltlb_ok, CTLFLAG_RW, &invltlb_ok, 0, "");
301
288int invltlb_ok = 0; /* throttle smp_invltlb() till safe */
289SYSCTL_INT(_machdep, OID_AUTO, invltlb_ok, CTLFLAG_RW, &invltlb_ok, 0, "");
290
302/* Enable forwarding of a signal to a process running on a different CPU */
303static int forward_signal_enabled = 1;
304SYSCTL_INT(_machdep, OID_AUTO, forward_signal_enabled, CTLFLAG_RW,
305 &forward_signal_enabled, 0, "");
306
307/* Enable forwarding of roundrobin to all other cpus */
308static int forward_roundrobin_enabled = 1;
309SYSCTL_INT(_machdep, OID_AUTO, forward_roundrobin_enabled, CTLFLAG_RW,
310 &forward_roundrobin_enabled, 0, "");
311
312
313/*
314 * Local data and functions.
315 */
316
317/* Set to 1 once we're ready to let the APs out of the pen. */
318static volatile int aps_ready = 0;
319
320static int mp_capable;

--- 28 unchanged lines hidden (view full) ---

349/* lock region used by kernel profiling */
350struct mtx mcount_mtx;
351
352#ifdef USE_COMLOCK
353/* locks com (tty) data/hardware accesses: a FASTINTR() */
354struct mtx com_mtx;
355#endif /* USE_COMLOCK */
356
291/*
292 * Local data and functions.
293 */
294
295/* Set to 1 once we're ready to let the APs out of the pen. */
296static volatile int aps_ready = 0;
297
298static int mp_capable;

--- 28 unchanged lines hidden (view full) ---

327/* lock region used by kernel profiling */
328struct mtx mcount_mtx;
329
330#ifdef USE_COMLOCK
331/* locks com (tty) data/hardware accesses: a FASTINTR() */
332struct mtx com_mtx;
333#endif /* USE_COMLOCK */
334
357/* lock around the MP rendezvous */
358static struct mtx smp_rv_mtx;
359
360static void
361init_locks(void)
362{
363 /*
364 * XXX The mcount mutex probably needs to be statically initialized,
365 * since it will be used even in the function calls that get us to this
366 * point.
367 */
368 mtx_init(&mcount_mtx, "mcount", MTX_DEF);
369
335static void
336init_locks(void)
337{
338 /*
339 * XXX The mcount mutex probably needs to be statically initialized,
340 * since it will be used even in the function calls that get us to this
341 * point.
342 */
343 mtx_init(&mcount_mtx, "mcount", MTX_DEF);
344
370 mtx_init(&smp_rv_mtx, "smp rendezvous", MTX_SPIN);
371
372#ifdef USE_COMLOCK
373 mtx_init(&com_mtx, "com", MTX_SPIN);
374#endif /* USE_COMLOCK */
345#ifdef USE_COMLOCK
346 mtx_init(&com_mtx, "com", MTX_SPIN);
347#endif /* USE_COMLOCK */
375
376 mtx_init(&ap_boot_mtx, "ap boot", MTX_SPIN);
377}
378
379/*
380 * Calculate usable address in base memory for AP trampoline code.
381 */
382u_int
383mp_bootaddress(u_int basemem)
384{

--- 7 unchanged lines hidden (view full) ---

392
393 return boot_address;
394}
395
396
397/*
398 * Look for an Intel MP spec table (ie, SMP capable hardware).
399 */
348}
349
350/*
351 * Calculate usable address in base memory for AP trampoline code.
352 */
353u_int
354mp_bootaddress(u_int basemem)
355{

--- 7 unchanged lines hidden (view full) ---

363
364 return boot_address;
365}
366
367
368/*
369 * Look for an Intel MP spec table (ie, SMP capable hardware).
370 */
400int
401mp_probe(void)
371void
372i386_mp_probe(void)
402{
403 int x;
404 u_long segment;
405 u_int32_t target;
406
407 POSTCODE(MP_PROBE_POST);
408
409 /* see if EBDA exists */

--- 12 unchanged lines hidden (view full) ---

422 /* search the BIOS */
423 target = (u_int32_t) BIOS_BASE;
424 if ((x = search_for_sig(target, BIOS_COUNT)) >= 0)
425 goto found;
426
427 /* nothing found */
428 mpfps = (mpfps_t)0;
429 mp_capable = 0;
373{
374 int x;
375 u_long segment;
376 u_int32_t target;
377
378 POSTCODE(MP_PROBE_POST);
379
380 /* see if EBDA exists */

--- 12 unchanged lines hidden (view full) ---

393 /* search the BIOS */
394 target = (u_int32_t) BIOS_BASE;
395 if ((x = search_for_sig(target, BIOS_COUNT)) >= 0)
396 goto found;
397
398 /* nothing found */
399 mpfps = (mpfps_t)0;
400 mp_capable = 0;
430 return 0;
401 return;
431
432found:
433 /* calculate needed resources */
434 mpfps = (mpfps_t)x;
435 mptable_pass1();
436
437 /* flag fact that we are running multiple processors */
438 mp_capable = 1;
402
403found:
404 /* calculate needed resources */
405 mpfps = (mpfps_t)x;
406 mptable_pass1();
407
408 /* flag fact that we are running multiple processors */
409 mp_capable = 1;
439 return 1;
440}
441
410}
411
412int
413cpu_mp_probe(void)
414{
415 return (mp_capable);
416}
442
443/*
444 * Initialize the SMP hardware and the APIC and start up the AP's.
445 */
446void
417
418/*
419 * Initialize the SMP hardware and the APIC and start up the AP's.
420 */
421void
447mp_start(void)
422cpu_mp_start(void)
448{
449 POSTCODE(MP_START_POST);
450
451 /* look for MP capable motherboard */
452 if (mp_capable)
453 mp_enable(boot_address);
454 else
455 panic("MP hardware not found!");
423{
424 POSTCODE(MP_START_POST);
425
426 /* look for MP capable motherboard */
427 if (mp_capable)
428 mp_enable(boot_address);
429 else
430 panic("MP hardware not found!");
431
432 cpu_setregs();
456}
457
458
459/*
460 * Print various information about the SMP system hardware and setup.
461 */
462void
433}
434
435
436/*
437 * Print various information about the SMP system hardware and setup.
438 */
439void
463mp_announce(void)
440cpu_mp_announce(void)
464{
465 int x;
466
467 POSTCODE(MP_ANNOUNCE_POST);
468
441{
442 int x;
443
444 POSTCODE(MP_ANNOUNCE_POST);
445
469 printf("FreeBSD/SMP: Multiprocessor motherboard\n");
470 printf(" cpu0 (BSP): apic id: %2d", CPU_TO_ID(0));
471 printf(", version: 0x%08x", cpu_apic_versions[0]);
472 printf(", at 0x%08x\n", cpu_apic_address);
473 for (x = 1; x <= mp_naps; ++x) {
474 printf(" cpu%d (AP): apic id: %2d", x, CPU_TO_ID(x));
475 printf(", version: 0x%08x", cpu_apic_versions[x]);
476 printf(", at 0x%08x\n", cpu_apic_address);
477 }

--- 140 unchanged lines hidden (view full) ---

618 /* install a 'Spurious INTerrupt' vector */
619 setidt(XSPURIOUSINT_OFFSET, Xspuriousint,
620 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
621
622 /* install an inter-CPU IPI for TLB invalidation */
623 setidt(XINVLTLB_OFFSET, Xinvltlb,
624 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
625
446 printf(" cpu0 (BSP): apic id: %2d", CPU_TO_ID(0));
447 printf(", version: 0x%08x", cpu_apic_versions[0]);
448 printf(", at 0x%08x\n", cpu_apic_address);
449 for (x = 1; x <= mp_naps; ++x) {
450 printf(" cpu%d (AP): apic id: %2d", x, CPU_TO_ID(x));
451 printf(", version: 0x%08x", cpu_apic_versions[x]);
452 printf(", at 0x%08x\n", cpu_apic_address);
453 }

--- 140 unchanged lines hidden (view full) ---

594 /* install a 'Spurious INTerrupt' vector */
595 setidt(XSPURIOUSINT_OFFSET, Xspuriousint,
596 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
597
598 /* install an inter-CPU IPI for TLB invalidation */
599 setidt(XINVLTLB_OFFSET, Xinvltlb,
600 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
601
626 /* install an inter-CPU IPI for reading processor state */
627 setidt(XCPUCHECKSTATE_OFFSET, Xcpucheckstate,
602 /* install an inter-CPU IPI for forwarding hardclock() */
603 setidt(XHARDCLOCK_OFFSET, Xhardclock,
628 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
629
604 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
605
606 /* install an inter-CPU IPI for forwarding statclock() */
607 setidt(XSTATCLOCK_OFFSET, Xstatclock,
608 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
609
630 /* install an inter-CPU IPI for all-CPU rendezvous */
631 setidt(XRENDEZVOUS_OFFSET, Xrendezvous,
632 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
633
634 /* install an inter-CPU IPI for forcing an additional software trap */
635 setidt(XCPUAST_OFFSET, Xcpuast,
636 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
637

--- 1295 unchanged lines hidden (view full) ---

1933 u_char mpbiosreason;
1934 u_long mpbioswarmvec;
1935 struct globaldata *gd;
1936 char *stack;
1937 uintptr_t kptbase;
1938
1939 POSTCODE(START_ALL_APS_POST);
1940
610 /* install an inter-CPU IPI for all-CPU rendezvous */
611 setidt(XRENDEZVOUS_OFFSET, Xrendezvous,
612 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
613
614 /* install an inter-CPU IPI for forcing an additional software trap */
615 setidt(XCPUAST_OFFSET, Xcpuast,
616 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
617

--- 1295 unchanged lines hidden (view full) ---

1913 u_char mpbiosreason;
1914 u_long mpbioswarmvec;
1915 struct globaldata *gd;
1916 char *stack;
1917 uintptr_t kptbase;
1918
1919 POSTCODE(START_ALL_APS_POST);
1920
1921 mtx_init(&ap_boot_mtx, "ap boot", MTX_SPIN);
1922
1941 /* initialize BSP's local APIC */
1942 apic_initialize();
1943 bsp_apic_ready = 1;
1944
1945 /* install the AP 1st level boot code */
1946 install_ap_tramp(boot_addr);
1947
1948

--- 31 unchanged lines hidden (view full) ---

1980
1981 /* allocate and set up an idle stack data page */
1982 stack = (char *)kmem_alloc(kernel_map, UPAGES*PAGE_SIZE);
1983 for (i = 0; i < UPAGES; i++)
1984 SMPpt[pg + 1 + i] = (pt_entry_t)
1985 (PG_V | PG_RW | vtophys(PAGE_SIZE * i + stack));
1986
1987 /* prime data page for it to use */
1923 /* initialize BSP's local APIC */
1924 apic_initialize();
1925 bsp_apic_ready = 1;
1926
1927 /* install the AP 1st level boot code */
1928 install_ap_tramp(boot_addr);
1929
1930

--- 31 unchanged lines hidden (view full) ---

1962
1963 /* allocate and set up an idle stack data page */
1964 stack = (char *)kmem_alloc(kernel_map, UPAGES*PAGE_SIZE);
1965 for (i = 0; i < UPAGES; i++)
1966 SMPpt[pg + 1 + i] = (pt_entry_t)
1967 (PG_V | PG_RW | vtophys(PAGE_SIZE * i + stack));
1968
1969 /* prime data page for it to use */
1988 SLIST_INSERT_HEAD(&cpuhead, gd, gd_allcpu);
1989 gd->gd_cpuid = x;
1970 gd->gd_cpuid = x;
1971 globaldata_register(gd);
1990
1991 /* setup a vector to our boot code */
1992 *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET;
1993 *((volatile u_short *) WARMBOOT_SEG) = (boot_addr >> 4);
1994#ifndef PC98
1995 outb(CMOS_REG, BIOS_RESET);
1996 outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */
1997#endif

--- 325 unchanged lines hidden (view full) ---

2323 /* ok, now grab sched_lock and enter the scheduler */
2324 enable_intr();
2325 mtx_lock_spin(&sched_lock);
2326 cpu_throw(); /* doesn't return */
2327
2328 panic("scheduler returned us to ap_init");
2329}
2330
1972
1973 /* setup a vector to our boot code */
1974 *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET;
1975 *((volatile u_short *) WARMBOOT_SEG) = (boot_addr >> 4);
1976#ifndef PC98
1977 outb(CMOS_REG, BIOS_RESET);
1978 outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */
1979#endif

--- 325 unchanged lines hidden (view full) ---

2305 /* ok, now grab sched_lock and enter the scheduler */
2306 enable_intr();
2307 mtx_lock_spin(&sched_lock);
2308 cpu_throw(); /* doesn't return */
2309
2310 panic("scheduler returned us to ap_init");
2311}
2312
2331#define CHECKSTATE_USER 0
2332#define CHECKSTATE_SYS 1
2333#define CHECKSTATE_INTR 2
2334
2335/* Do not staticize. Used from apic_vector.s */
2336struct proc* checkstate_curproc[MAXCPU];
2337int checkstate_cpustate[MAXCPU];
2338u_long checkstate_pc[MAXCPU];
2339
2340#define PC_TO_INDEX(pc, prof) \
2341 ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
2342 (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
2343
2344static void
2345addupc_intr_forwarded(struct proc *p, int id, int *astmap)
2313/*
2314 * For statclock, we send an IPI to all CPU's to have them call this
2315 * function.
2316 */
2317void
2318forwarded_statclock(struct trapframe frame)
2346{
2319{
2347 int i;
2348 struct uprof *prof;
2349 u_long pc;
2350
2320
2351 pc = checkstate_pc[id];
2352 prof = &p->p_stats->p_prof;
2353 if (pc >= prof->pr_off &&
2354 (i = PC_TO_INDEX(pc, prof)) < prof->pr_size) {
2355 mtx_assert(&sched_lock, MA_OWNED);
2356 if ((p->p_sflag & PS_OWEUPC) == 0) {
2357 prof->pr_addr = pc;
2358 prof->pr_ticks = 1;
2359 p->p_sflag |= PS_OWEUPC;
2360 }
2361 *astmap |= (1 << id);
2362 }
2321 mtx_lock_spin(&sched_lock);
2322 statclock_process(curproc, TRAPF_PC(&frame), TRAPF_USERMODE(&frame));
2323 mtx_unlock_spin(&sched_lock);
2363}
2364
2324}
2325
2365static void
2366forwarded_statclock(int id, int pscnt, int *astmap)
2367{
2368 struct pstats *pstats;
2369 long rss;
2370 struct rusage *ru;
2371 struct vmspace *vm;
2372 int cpustate;
2373 struct proc *p;
2374#ifdef GPROF
2375 register struct gmonparam *g;
2376 int i;
2377#endif
2378
2379 mtx_assert(&sched_lock, MA_OWNED);
2380 p = checkstate_curproc[id];
2381 cpustate = checkstate_cpustate[id];
2382
2383 /* XXX */
2384 if (p->p_ithd)
2385 cpustate = CHECKSTATE_INTR;
2386 else if (p == SMP_prvspace[id].globaldata.gd_idleproc)
2387 cpustate = CHECKSTATE_SYS;
2388
2389 switch (cpustate) {
2390 case CHECKSTATE_USER:
2391 if (p->p_sflag & PS_PROFIL)
2392 addupc_intr_forwarded(p, id, astmap);
2393 if (pscnt > 1)
2394 return;
2395 p->p_uticks++;
2396 if (p->p_nice > NZERO)
2397 cp_time[CP_NICE]++;
2398 else
2399 cp_time[CP_USER]++;
2400 break;
2401 case CHECKSTATE_SYS:
2402#ifdef GPROF
2403 /*
2404 * Kernel statistics are just like addupc_intr, only easier.
2405 */
2406 g = &_gmonparam;
2407 if (g->state == GMON_PROF_ON) {
2408 i = checkstate_pc[id] - g->lowpc;
2409 if (i < g->textsize) {
2410 i /= HISTFRACTION * sizeof(*g->kcount);
2411 g->kcount[i]++;
2412 }
2413 }
2414#endif
2415 if (pscnt > 1)
2416 return;
2417
2418 p->p_sticks++;
2419 if (p == SMP_prvspace[id].globaldata.gd_idleproc)
2420 cp_time[CP_IDLE]++;
2421 else
2422 cp_time[CP_SYS]++;
2423 break;
2424 case CHECKSTATE_INTR:
2425 default:
2426#ifdef GPROF
2427 /*
2428 * Kernel statistics are just like addupc_intr, only easier.
2429 */
2430 g = &_gmonparam;
2431 if (g->state == GMON_PROF_ON) {
2432 i = checkstate_pc[id] - g->lowpc;
2433 if (i < g->textsize) {
2434 i /= HISTFRACTION * sizeof(*g->kcount);
2435 g->kcount[i]++;
2436 }
2437 }
2438#endif
2439 if (pscnt > 1)
2440 return;
2441 KASSERT(p != NULL, ("NULL process in interrupt state"));
2442 p->p_iticks++;
2443 cp_time[CP_INTR]++;
2444 }
2445
2446 schedclock(p);
2447
2448 /* Update resource usage integrals and maximums. */
2449 if ((pstats = p->p_stats) != NULL &&
2450 (ru = &pstats->p_ru) != NULL &&
2451 (vm = p->p_vmspace) != NULL) {
2452 ru->ru_ixrss += pgtok(vm->vm_tsize);
2453 ru->ru_idrss += pgtok(vm->vm_dsize);
2454 ru->ru_isrss += pgtok(vm->vm_ssize);
2455 rss = pgtok(vmspace_resident_count(vm));
2456 if (ru->ru_maxrss < rss)
2457 ru->ru_maxrss = rss;
2458 }
2459}
2460
2461void
2326void
2462forward_statclock(int pscnt)
2327forward_statclock(void)
2463{
2464 int map;
2328{
2329 int map;
2465 int id;
2466 int i;
2467
2330
2468 /* Kludge. We don't yet have separate locks for the interrupts
2469 * and the kernel. This means that we cannot let the other processors
2470 * handle complex interrupts while inhibiting them from entering
2471 * the kernel in a non-interrupt context.
2472 *
2473 * What we can do, without changing the locking mechanisms yet,
2474 * is letting the other processors handle a very simple interrupt
2475 * (wich determines the processor states), and do the main
2476 * work ourself.
2477 */
2331 CTR0(KTR_SMP, "forward_statclock");
2478
2332
2479 CTR1(KTR_SMP, "forward_statclock(%d)", pscnt);
2480
2481 if (!smp_started || !invltlb_ok || cold || panicstr)
2482 return;
2483
2333 if (!smp_started || !invltlb_ok || cold || panicstr)
2334 return;
2335
2484 /* Step 1: Probe state (user, cpu, interrupt, spinlock, idle ) */
2485
2486 map = PCPU_GET(other_cpus) & ~stopped_cpus ;
2336 map = PCPU_GET(other_cpus) & ~stopped_cpus ;
2487 checkstate_probed_cpus = 0;
2488 if (map != 0)
2337 if (map != 0)
2489 ipi_selected(map, IPI_CHECKSTATE);
2490
2491 i = 0;
2492 while (checkstate_probed_cpus != map) {
2493 /* spin */
2494 i++;
2495 if (i == 100000) {
2496#ifdef DIAGNOSTIC
2497 printf("forward_statclock: checkstate %x\n",
2498 checkstate_probed_cpus);
2499#endif
2500 break;
2501 }
2502 }
2503
2504 /*
2505 * Step 2: walk through other processors processes, update ticks and
2506 * profiling info.
2507 */
2508
2509 map = 0;
2510 for (id = 0; id < mp_ncpus; id++) {
2511 if (id == PCPU_GET(cpuid))
2512 continue;
2513 if (((1 << id) & checkstate_probed_cpus) == 0)
2514 continue;
2515 forwarded_statclock(id, pscnt, &map);
2516 }
2517 if (map != 0) {
2518 checkstate_need_ast |= map;
2519 ipi_selected(map, IPI_AST);
2520 i = 0;
2521 while ((checkstate_need_ast & map) != 0) {
2522 /* spin */
2523 i++;
2524 if (i > 100000) {
2525#ifdef DIAGNOSTIC
2526 printf("forward_statclock: dropped ast 0x%x\n",
2527 checkstate_need_ast & map);
2528#endif
2529 break;
2530 }
2531 }
2532 }
2338 ipi_selected(map, IPI_STATCLOCK);
2533}
2534
2339}
2340
2535void
2536forward_hardclock(int pscnt)
2341/*
2342 * For each hardclock(), we send an IPI to all other CPU's to have them
2343 * execute this function. It would be nice to reduce contention on
2344 * sched_lock if we could simply peek at the CPU to determine the user/kernel
2345 * state and call hardclock_process() on the CPU receiving the clock interrupt
2346 * and then just use a simple IPI to handle any ast's if needed.
2347 */
2348void
2349forwarded_hardclock(struct trapframe frame)
2537{
2350{
2538 int map;
2539 int id;
2540 struct proc *p;
2541 struct pstats *pstats;
2542 int i;
2543
2351
2544 /* Kludge. We don't yet have separate locks for the interrupts
2545 * and the kernel. This means that we cannot let the other processors
2546 * handle complex interrupts while inhibiting them from entering
2547 * the kernel in a non-interrupt context.
2548 *
2549 * What we can do, without changing the locking mechanisms yet,
2550 * is letting the other processors handle a very simple interrupt
2551 * (wich determines the processor states), and do the main
2552 * work ourself.
2553 */
2554
2555 CTR1(KTR_SMP, "forward_hardclock(%d)", pscnt);
2556
2557 if (!smp_started || !invltlb_ok || cold || panicstr)
2558 return;
2559
2560 /* Step 1: Probe state (user, cpu, interrupt, spinlock, idle) */
2561
2562 map = PCPU_GET(other_cpus) & ~stopped_cpus ;
2563 checkstate_probed_cpus = 0;
2564 if (map != 0)
2565 ipi_selected(map, IPI_CHECKSTATE);
2566
2567 i = 0;
2568 while (checkstate_probed_cpus != map) {
2569 /* spin */
2570 i++;
2571 if (i == 100000) {
2572#ifdef DIAGNOSTIC
2573 printf("forward_hardclock: checkstate %x\n",
2574 checkstate_probed_cpus);
2575#endif
2576 break;
2577 }
2578 }
2579
2580 /*
2581 * Step 2: walk through other processors processes, update virtual
2582 * timer and profiling timer. If stathz == 0, also update ticks and
2583 * profiling info.
2584 */
2585
2586 map = 0;
2587 for (id = 0; id < mp_ncpus; id++) {
2588 if (id == PCPU_GET(cpuid))
2589 continue;
2590 if (((1 << id) & checkstate_probed_cpus) == 0)
2591 continue;
2592 p = checkstate_curproc[id];
2593 if (p) {
2594 pstats = p->p_stats;
2595 if (checkstate_cpustate[id] == CHECKSTATE_USER &&
2596 timevalisset(&pstats->p_timer[ITIMER_VIRTUAL].it_value) &&
2597 itimerdecr(&pstats->p_timer[ITIMER_VIRTUAL], tick) == 0) {
2598 p->p_sflag |= PS_ALRMPEND;
2599 map |= (1 << id);
2600 }
2601 if (timevalisset(&pstats->p_timer[ITIMER_PROF].it_value) &&
2602 itimerdecr(&pstats->p_timer[ITIMER_PROF], tick) == 0) {
2603 p->p_sflag |= PS_PROFPEND;
2604 map |= (1 << id);
2605 }
2606 }
2607 if (stathz == 0) {
2608 forwarded_statclock( id, pscnt, &map);
2609 }
2610 }
2611 if (map != 0) {
2612 checkstate_need_ast |= map;
2613 ipi_selected(map, IPI_AST);
2614 i = 0;
2615 while ((checkstate_need_ast & map) != 0) {
2616 /* spin */
2617 i++;
2618 if (i > 100000) {
2619#ifdef DIAGNOSTIC
2620 printf("forward_hardclock: dropped ast 0x%x\n",
2621 checkstate_need_ast & map);
2622#endif
2623 break;
2624 }
2625 }
2626 }
2352 mtx_lock_spin(&sched_lock);
2353 hardclock_process(curproc, TRAPF_USERMODE(&frame));
2354 mtx_unlock_spin(&sched_lock);
2627}
2628
2629void
2355}
2356
2357void
2630forward_signal(struct proc *p)
2358forward_hardclock(void)
2631{
2359{
2632 int map;
2633 int id;
2634 int i;
2635
2636 /* Kludge. We don't yet have separate locks for the interrupts
2637 * and the kernel. This means that we cannot let the other processors
2638 * handle complex interrupts while inhibiting them from entering
2639 * the kernel in a non-interrupt context.
2640 *
2641 * What we can do, without changing the locking mechanisms yet,
2642 * is letting the other processors handle a very simple interrupt
2643 * (wich determines the processor states), and do the main
2644 * work ourself.
2645 */
2646
2647 CTR1(KTR_SMP, "forward_signal(%p)", p);
2648
2649 if (!smp_started || !invltlb_ok || cold || panicstr)
2650 return;
2651 if (!forward_signal_enabled)
2652 return;
2653 mtx_lock_spin(&sched_lock);
2654 while (1) {
2655 if (p->p_stat != SRUN) {
2656 mtx_unlock_spin(&sched_lock);
2657 return;
2658 }
2659 id = p->p_oncpu;
2660 mtx_unlock_spin(&sched_lock);
2661 if (id == 0xff)
2662 return;
2663 map = (1<<id);
2664 checkstate_need_ast |= map;
2665 ipi_selected(map, IPI_AST);
2666 i = 0;
2667 while ((checkstate_need_ast & map) != 0) {
2668 /* spin */
2669 i++;
2670 if (i > 100000) {
2671#if 0
2672 printf("forward_signal: dropped ast 0x%x\n",
2673 checkstate_need_ast & map);
2674#endif
2675 break;
2676 }
2677 }
2678 mtx_lock_spin(&sched_lock);
2679 if (id == p->p_oncpu) {
2680 mtx_unlock_spin(&sched_lock);
2681 return;
2682 }
2683 }
2684}
2685
2686void
2687forward_roundrobin(void)
2688{
2689 u_int map;
2360 u_int map;
2690 int i;
2691
2361
2692 CTR0(KTR_SMP, "forward_roundrobin()");
2362 CTR0(KTR_SMP, "forward_hardclock");
2693
2694 if (!smp_started || !invltlb_ok || cold || panicstr)
2695 return;
2363
2364 if (!smp_started || !invltlb_ok || cold || panicstr)
2365 return;
2696 if (!forward_roundrobin_enabled)
2697 return;
2698 resched_cpus |= PCPU_GET(other_cpus);
2366
2699 map = PCPU_GET(other_cpus) & ~stopped_cpus ;
2367 map = PCPU_GET(other_cpus) & ~stopped_cpus ;
2700#if 1
2701 ipi_selected(map, IPI_AST);
2702#else
2703 ipi_all_but_self(IPI_AST);
2704#endif
2705 i = 0;
2706 while ((checkstate_need_ast & map) != 0) {
2707 /* spin */
2708 i++;
2709 if (i > 100000) {
2710#if 0
2711 printf("forward_roundrobin: dropped ast 0x%x\n",
2712 checkstate_need_ast & map);
2713#endif
2714 break;
2715 }
2716 }
2368 if (map != 0)
2369 ipi_selected(map, IPI_HARDCLOCK);
2717}
2718
2370}
2371
2719/*
2720 * When called the executing CPU will send an IPI to all other CPUs
2721 * requesting that they halt execution.
2722 *
2723 * Usually (but not necessarily) called with 'other_cpus' as its arg.
2724 *
2725 * - Signals all CPUs in map to stop.
2726 * - Waits for each to stop.
2727 *
2728 * Returns:
2729 * -1: error
2730 * 0: NA
2731 * 1: ok
2732 *
2733 * XXX FIXME: this is not MP-safe, needs a lock to prevent multiple CPUs
2734 * from executing at same time.
2735 */
2736int
2737stop_cpus(u_int map)
2738{
2739 int count = 0;
2740
2741 if (!smp_started)
2742 return 0;
2743
2744 /* send the Xcpustop IPI to all CPUs in map */
2745 ipi_selected(map, IPI_STOP);
2746
2747 while (count++ < 100000 && (stopped_cpus & map) != map)
2748 /* spin */ ;
2749
2750#ifdef DIAGNOSTIC
2751 if ((stopped_cpus & map) != map)
2752 printf("Warning: CPUs 0x%x did not stop!\n",
2753 (~(stopped_cpus & map)) & map);
2754#endif
2755
2756 return 1;
2757}
2758
2759
2760/*
2761 * Called by a CPU to restart stopped CPUs.
2762 *
2763 * Usually (but not necessarily) called with 'stopped_cpus' as its arg.
2764 *
2765 * - Signals all CPUs in map to restart.
2766 * - Waits for each to restart.
2767 *
2768 * Returns:
2769 * -1: error
2770 * 0: NA
2771 * 1: ok
2772 */
2773int
2774restart_cpus(u_int map)
2775{
2776 int count = 0;
2777
2778 if (!smp_started)
2779 return 0;
2780
2781 started_cpus = map; /* signal other cpus to restart */
2782
2783 /* wait for each to clear its bit */
2784 while (count++ < 100000 && (stopped_cpus & map) != 0)
2785 /* spin */ ;
2786
2787#ifdef DIAGNOSTIC
2788 if ((stopped_cpus & map) != 0)
2789 printf("Warning: CPUs 0x%x did not restart!\n",
2790 (~(stopped_cpus & map)) & map);
2791#endif
2792
2793 return 1;
2794}
2795
2796
2797#ifdef APIC_INTR_REORDER
2798/*
2799 * Maintain mapping from softintr vector to isr bit in local apic.
2800 */
2801void
2802set_lapic_isrloc(int intr, int vector)
2803{
2804 if (intr < 0 || intr > 32)
2805 panic("set_apic_isrloc: bad intr argument: %d",intr);
2806 if (vector < ICU_OFFSET || vector > 255)
2807 panic("set_apic_isrloc: bad vector argument: %d",vector);
2808 apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2);
2809 apic_isrbit_location[intr].bit = (1<<(vector & 31));
2810}
2811#endif
2812
2813/*
2372#ifdef APIC_INTR_REORDER
2373/*
2374 * Maintain mapping from softintr vector to isr bit in local apic.
2375 */
2376void
2377set_lapic_isrloc(int intr, int vector)
2378{
2379 if (intr < 0 || intr > 32)
2380 panic("set_apic_isrloc: bad intr argument: %d",intr);
2381 if (vector < ICU_OFFSET || vector > 255)
2382 panic("set_apic_isrloc: bad vector argument: %d",vector);
2383 apic_isrbit_location[intr].location = &lapic.isr0 + ((vector>>5)<<2);
2384 apic_isrbit_location[intr].bit = (1<<(vector & 31));
2385}
2386#endif
2387
2388/*
2814 * All-CPU rendezvous. CPUs are signalled, all execute the setup function
2815 * (if specified), rendezvous, execute the action function (if specified),
2816 * rendezvous again, execute the teardown function (if specified), and then
2817 * resume.
2818 *
2819 * Note that the supplied external functions _must_ be reentrant and aware
2820 * that they are running in parallel and in an unknown lock context.
2821 */
2822static void (*smp_rv_setup_func)(void *arg);
2823static void (*smp_rv_action_func)(void *arg);
2824static void (*smp_rv_teardown_func)(void *arg);
2825static void *smp_rv_func_arg;
2826static volatile int smp_rv_waiters[2];
2827
2828void
2829smp_rendezvous_action(void)
2830{
2831 /* setup function */
2832 if (smp_rv_setup_func != NULL)
2833 smp_rv_setup_func(smp_rv_func_arg);
2834 /* spin on entry rendezvous */
2835 atomic_add_int(&smp_rv_waiters[0], 1);
2836 while (smp_rv_waiters[0] < mp_ncpus)
2837 ;
2838 /* action function */
2839 if (smp_rv_action_func != NULL)
2840 smp_rv_action_func(smp_rv_func_arg);
2841 /* spin on exit rendezvous */
2842 atomic_add_int(&smp_rv_waiters[1], 1);
2843 while (smp_rv_waiters[1] < mp_ncpus)
2844 ;
2845 /* teardown function */
2846 if (smp_rv_teardown_func != NULL)
2847 smp_rv_teardown_func(smp_rv_func_arg);
2848}
2849
2850void
2851smp_rendezvous(void (* setup_func)(void *),
2852 void (* action_func)(void *),
2853 void (* teardown_func)(void *),
2854 void *arg)
2855{
2856
2857 /* obtain rendezvous lock */
2858 mtx_lock_spin(&smp_rv_mtx);
2859
2860 /* set static function pointers */
2861 smp_rv_setup_func = setup_func;
2862 smp_rv_action_func = action_func;
2863 smp_rv_teardown_func = teardown_func;
2864 smp_rv_func_arg = arg;
2865 smp_rv_waiters[0] = 0;
2866 smp_rv_waiters[1] = 0;
2867
2868 /*
2869 * signal other processors, which will enter the IPI with interrupts off
2870 */
2871 ipi_all_but_self(IPI_RENDEZVOUS);
2872
2873 /* call executor function */
2874 smp_rendezvous_action();
2875
2876 /* release lock */
2877 mtx_unlock_spin(&smp_rv_mtx);
2878}
2879
2880/*
2881 * send an IPI to a set of cpus.
2882 */
2883void
2884ipi_selected(u_int32_t cpus, u_int ipi)
2885{
2886
2887 CTR2(KTR_SMP, __func__ ": cpus: %x ipi: %x", cpus, ipi);
2888 selected_apic_ipi(cpus, ipi, APIC_DELMODE_FIXED);

--- 42 unchanged lines hidden ---
2389 * send an IPI to a set of cpus.
2390 */
2391void
2392ipi_selected(u_int32_t cpus, u_int ipi)
2393{
2394
2395 CTR2(KTR_SMP, __func__ ": cpus: %x ipi: %x", cpus, ipi);
2396 selected_apic_ipi(cpus, ipi, APIC_DELMODE_FIXED);

--- 42 unchanged lines hidden ---