diff --git a/.hgtags b/.hgtags index f6001e15b5..dfe9bc1c82 100644 --- a/.hgtags +++ b/.hgtags @@ -5,6 +5,7 @@ dc2f08429f17e6614fd2f1ab88cc09ca0a850f32 RELEASE-2.0.2 fb875591fd72e15c31879c0e9034d99b80225595 RELEASE-2.0.4 1a522944f76540ea9d73fcc1b0d13d0f670183f0 RELEASE-2.0.5 487b2ee37d1cecb5f3e7a546b05ad097a0226f2f beta1 +1f84d0497a5901b9f8d1a051b87871d140b7e23f ia64-stable 3d330e41f41ce1bc118c02346e18949ad5d67f6b latest-semistable 30c521db4c71960b0cf1d9c9e1b658e77b535a3e latest-stable 9afec5bc14aeb197ef37ea54a57eacd427463fc3 semistable diff --git a/.rootkeys b/.rootkeys index 68ad03e99e..fbd8a2f9d4 100644 --- a/.rootkeys +++ b/.rootkeys @@ -21,6 +21,7 @@ 412f4bd9sm5mCQ8BkrgKcAKZGadq7Q docs/misc/blkif-drivers-explained.txt 420b949cy9ZGzED74Fz_DaWlK7tT4g docs/misc/crashdb.txt 4251a1f82AexscYEiF4Iku8Gc_kWfQ docs/misc/grant-tables.txt +424d462b5GuApQ_NyMsRFt9LbrsWow docs/misc/sedf_scheduler_mini-HOWTO.txt 40d6ccbfKKBq8jE0ula4eHEzBiQuDA docs/misc/xen_config.html 410a4c2bAO_m_l4RsiiPHnZ4ixHWbQ docs/misc/xend.tex 3f9e7d564bWFB-Czjv1qdmE6o0GqNg docs/src/interface.tex @@ -248,6 +249,7 @@ 40f562389xNa78YBZciUibQjyRU_Lg linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c 40f56238JypKAUG01ZojFwH7qnZ5uA linux-2.6.11-xen-sparse/arch/xen/i386/kernel/vsyscall.S 40f56238wi6AdNQjm0RT57bSkwb6hg linux-2.6.11-xen-sparse/arch/xen/i386/kernel/vsyscall.lds +427245dboQBkhq841wIPqlRD-AG9Jw linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile 40f56238a3w6-byOzexIlMgni76Lcg linux-2.6.11-xen-sparse/arch/xen/i386/mm/Makefile 40f56238ILx8xlbywNbzTdv5Zr4xXQ linux-2.6.11-xen-sparse/arch/xen/i386/mm/fault.c 4118cc35CbY8rfGVspF5O-7EkXBEAA linux-2.6.11-xen-sparse/arch/xen/i386/mm/highmem.c @@ -465,6 +467,7 @@ 422e4430-gOD358H8nGGnNWes08Nng netbsd-2.0-xen-sparse/sys/miscfs/kernfs/kernfs_vnops.c 413cb3b53nyOv1OIeDSsCXhBFDXvJA netbsd-2.0-xen-sparse/sys/nfs/files.nfs 413aa1d0oNP8HXLvfPuMe6cSroUfSA patches/linux-2.6.11/agpgart.patch +427261074Iy1MkbbqIV6zdZDWWx_Jg patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch 42372652KCUP-IOH9RN19YQmGhs4aA patches/linux-2.6.11/iomap.patch 424f001e_M1Tnxc52rDrmCLelnDWMQ patches/linux-2.6.11/x86_64-linux.patch 3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile @@ -742,6 +745,7 @@ 3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h 42337174PxyzzPk62raDiYCIsfStDg tools/libxc/xc_ptrace.c 4273458duzL--nsTfT6e_q6Kfij48g tools/libxc/xc_ptrace_core.c +41ebbfe9U0b0kI-HgjK7VEY4EvW7_w tools/libxc/xc_sedf.c 41dde8b0pLfAKMs_L9Uri2hnzHiCRQ tools/libxc/xc_vmx_build.c 40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c @@ -1202,7 +1206,7 @@ 427664f5eygrc3nEhI3RKf0Y37PzyA xen/arch/ia64/xentime.c 3ddb79bcZbRBzT3elFWSX7u6NtMagQ xen/arch/x86/Makefile 3ddb79bcBQF85CfLS4i1WGZ4oLLaCA xen/arch/x86/Rules.mk -3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi.c +3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi/boot.c 3ddb79bcsjinG9k1KcvbVBuas1R2dA xen/arch/x86/apic.c 42360b3244-Q6BpEKhR_A1YtG1wPNQ xen/arch/x86/audit.c 3ddb79c4yGZ7_22QAFFwPzqP4NSHwA xen/arch/x86/boot/mkelf32.c @@ -1264,6 +1268,7 @@ 422f27c8J9DQfCpegccMid59XhSmGA xen/arch/x86/x86_emulate.c 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile 3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c +427fa2d0J0LU2s5oKbsM0nTZ2iyd2Q xen/common/bitmap.c 3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c 3e6377e4i0c9GtKN65e99OtRbw3AZw xen/common/dom_mem_ops.c 3ddb79bdYO5D8Av12NHqPeSviav7cg xen/common/domain.c @@ -1276,8 +1281,8 @@ 41a61536SZbR6cj1ukWTb0DYU-vz9w xen/common/multicall.c 3ddb79bdD4SLmmdMD7yLW5HcUWucXw xen/common/page_alloc.c 3e54c38dkHAev597bPr71-hGzTdocg xen/common/perfc.c -3ddb79bdHqdQpATqC0rmUZNbsb6L6A xen/common/resource.c 40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c +41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c 3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c 3e7f358awXBC3Vw-wFRwPw18qL1khg xen/common/string.c @@ -1358,18 +1363,37 @@ 4204e7acwXDo-5iAAiO2eQbtDeYZXA xen/include/asm-x86/init.h 3ddb79c3fQ_O3o5NHK2N8AJdk0Ea4Q xen/include/asm-x86/io.h 3ddb79c2TKeScYHQZreTdHqYNLbehQ xen/include/asm-x86/io_apic.h -42605109qxLSrHVE2SRhGXmgk907iw xen/include/asm-x86/io_ports.h 3ddb79c2L7rTlFzazOLW1XuSZefpFw xen/include/asm-x86/irq.h 404f1b93OjLO4bFfBXYNaJdIqlNz-Q xen/include/asm-x86/ldt.h -4260510aYPj2kr6rMbBfMxcvvmXndQ xen/include/asm-x86/mach_apic.h +427fa2d0m8MOSSXT13zgb-q0fGA_Dw xen/include/asm-x86/mach-default/apm.h +427fa2d0suK9Av7vsAXhsQxZjqpc_Q xen/include/asm-x86/mach-default/bios_ebda.h +427fa2d0yC3KzLozoeK3Xa3uGVfIdw xen/include/asm-x86/mach-default/do_timer.h +427fa2d0bWQkR1mW5OBYxn07AN-bDw xen/include/asm-x86/mach-default/entry_arch.h +427fa2d0-SWcuwbdSypo4953bc2JdQ xen/include/asm-x86/mach-default/io_ports.h +427fa2d0eyAl7LAeO-SVV4IW7lZPGQ xen/include/asm-x86/mach-default/irq_vectors.h +427fa2d0df7VWG4KKpnKbKR2Cbd1_w xen/include/asm-x86/mach-default/irq_vectors_limits.h +4260510aYPj2kr6rMbBfMxcvvmXndQ xen/include/asm-x86/mach-default/mach_apic.h +427fa2d0I3FWjE2tWdOhlEOJn7stcg xen/include/asm-x86/mach-default/mach_apicdef.h +427fa2d093fDS2gOBLcl7Yndzl7HmA xen/include/asm-x86/mach-default/mach_ipi.h +427fa2d0Y7bD35d-FvDAeiJDIdRw2A xen/include/asm-x86/mach-default/mach_mpparse.h +427fa2d0aLQgE9e1GY9ZP5jrMOC8pQ xen/include/asm-x86/mach-default/mach_mpspec.h +427fa2d0fJ5nNn5ydJuOaZIL6F2fjQ xen/include/asm-x86/mach-default/mach_reboot.h +427fa2d0VlN555TE68TjKMsrOoFXNA xen/include/asm-x86/mach-default/mach_time.h +427fa2d0C0jWTKYjy7WJjGKeujSpSg xen/include/asm-x86/mach-default/mach_timer.h +427fa2d0UXLiS1scpNrK26ZT6Oes3g xen/include/asm-x86/mach-default/mach_traps.h +427fa2d0OfglYyfpDTD5DII4M0uZRw xen/include/asm-x86/mach-default/mach_wakecpu.h +427fa2d0_OBPxdi5Qo04JWgZhz7BFA xen/include/asm-x86/mach-default/pci-functions.h +427fa2d0mrTtXrliqDfLuJc5LLVXaA xen/include/asm-x86/mach-default/setup_arch_post.h +427fa2d0Uoo7gC61Kep6Yy7Os367Hg xen/include/asm-x86/mach-default/setup_arch_pre.h +427fa2d1EKnA8zCq2QLHiGOUqOgszg xen/include/asm-x86/mach-default/smpboot_hooks.h 3ddb79c3I98vWcQR8xEo34JMJ4Ahyw xen/include/asm-x86/mc146818rtc.h 40ec25fd7cSvbP7Biw91zaU_g0xsEQ xen/include/asm-x86/mm.h 3ddb79c3n_UbPuxlkNxvvLycClIkxA xen/include/asm-x86/mpspec.h +427fa2d1eJRenftJJnRyLsHKl1ghtA xen/include/asm-x86/mpspec_def.h 3ddb79c2wa0dA_LGigxOelSGbJ284Q xen/include/asm-x86/msr.h 41aaf567Mi3OishhvrCtET1y-mxQBg xen/include/asm-x86/mtrr.h 41a61536MFhNalgbVmYGXAhQsPTZNw xen/include/asm-x86/multicall.h 3ddb79c3xjYnrv5t3VqYlR4tNEOl4Q xen/include/asm-x86/page.h -3ddb79c3ysKUbxZuwKBRK3WXU2TlEg xen/include/asm-x86/pci.h 42422fb0FVX-TJkSvAXnbfwMf19XFA xen/include/asm-x86/physdev.h 3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h 40cf1596bim9F9DNdV75klgRSZ6Y2A xen/include/asm-x86/regs.h @@ -1426,11 +1450,15 @@ 3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/public/xen.h 3e397e66m2tO3s-J8Jnr7Ws_tGoPTg xen/include/xen/ac_timer.h 40715b2epYl2jBbxzz9CI2rgIca7Zg xen/include/xen/acpi.h +422f0995xCgnbsVhTjSncnqIABs64g xen/include/xen/adv_sched_hist.h +427fa2d1wyoVbvCyZRLposYjA_D_4g xen/include/xen/bitmap.h +427fa2d1ItcC_yWuBUkhc7adedP5ow xen/include/xen/bitops.h 3ddb79c0c0cX_DZE209-Bb-Rx1v-Aw xen/include/xen/cache.h 41f2cea7Yna7xc0X9fyavIjoSFFeVg xen/include/xen/compile.h.in 3f840f12CkbYSlwMrY2S11Mpyxg7Nw xen/include/xen/compiler.h 3ddb79c259jh8hE7vre_8NuE7nwNSA xen/include/xen/config.h 3eb165e0eawr3R-p2ZQtSdLWtLRN_A xen/include/xen/console.h +427fa2d1bQCWgEQqTTh5MjG4MPEH9g xen/include/xen/cpumask.h 3ddb79c1V44RD26YqCUm-kqIupM37A xen/include/xen/ctype.h 3ddb79c05DdHQ0UxX_jKsXdR4QlMCA xen/include/xen/delay.h 40f2b4a2hC3HtChu-ArD8LyojxWMjg xen/include/xen/domain.h @@ -1439,7 +1467,7 @@ 3ddb79c1W0lQca8gRV7sN6j3iY4Luw xen/include/xen/event.h 41262590CyJy4vd42dnqzsn8-eeGvw xen/include/xen/grant_table.h 3ddb79c0GurNF9tDWqQbAwJFH8ugfA xen/include/xen/init.h -3ddb79c1nzaWu8NoF4xCCMSFJR4MlA xen/include/xen/ioport.h +428084e41zemtCAtYLcD9bUzwE35SA xen/include/xen/inttypes.h 3ddb79c2qAxCOABlkKtD8Txohe-qEw xen/include/xen/irq.h 3ddb79c2b3qe-6Ann09FqZBF4IrJaQ xen/include/xen/irq_cpustat.h 3e4540ccPHqIIv2pvnQ1gV8LUnoHIg xen/include/xen/kernel.h @@ -1449,7 +1477,6 @@ 3ddb79c1gs2VbLbQlw0dcDUXYIepDA xen/include/xen/mm.h 3ddb79c1ieLZfGSFwfvvSQ2NK1BMSg xen/include/xen/multiboot.h 41a61536ii6j2lJ2rXwMOLaG1CHPvw xen/include/xen/multicall.h -3ddb79c2Fg44_PBPVxHSC0gTOMq4Ow xen/include/xen/pci.h 3ddb79c0MOVXq8qZDQRGb6z64_xAwg xen/include/xen/pci_ids.h 3e54c38dlSCVdyVM4PKcrSfzLLxWUQ xen/include/xen/perfc.h 3e54c38de9SUSYSAwxDf_DwkpAnQFA xen/include/xen/perfc_defn.h diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 17f57acbf9..379ce87a72 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -60,6 +60,7 @@ kmacy@shemp.lab.netapp.com kraxel@bytesex.org laudney@eclipse.(none) leendert@watson.ibm.com +lists-xen@pimb.org lynx@idefix.cl.cam.ac.uk maf46@burn.cl.cam.ac.uk mafetter@fleming.research diff --git a/docs/misc/sedf_scheduler_mini-HOWTO.txt b/docs/misc/sedf_scheduler_mini-HOWTO.txt new file mode 100644 index 0000000000..ad3cc62e1f --- /dev/null +++ b/docs/misc/sedf_scheduler_mini-HOWTO.txt @@ -0,0 +1,44 @@ +sEDF scheduler +-------------- +Author: + Stephan.Diestelhorst@{cl.cam.ac.uk, inf.tu-dresden.de} + +Overview: + This scheduler provides weighted CPU sharing in an intuitive way and + uses realtime-algorithms to ensure time guarantees. + +Usage: +   -add "sched=sedf" on Xen's boot command-line +   -create domains as usual +   -use "xm sedf " +  Where: +  -period/slice are the normal EDF scheduling parameters in nanosecs +  -latency-hint is the scaled period in case the domain is doing heavy I/O + (unused by the currently compiled version) +  -extra is a flag (0/1), which controls whether the domain can run in + extra-time +  -weight is mutually exclusive with period/slice and specifies another + way of setting a domains cpu slice + +Examples: + normal EDF (20ms/5ms): +  xm sedf 20000000 5000000 0 0 0 + + best-effort domains (i.e. non-realtime): +  xm sedf 20000000 0 0 1 0 +  + normal EDF (20ms/5ms) + share of extra-time: +  xm sedf 20000000 5000000 0 1 0 + + 4 domains with weights 2:3:4:2 +  xm sedf 0 0 0 0 2 +  xm sedf 0 0 0 0 3 +  xm sedf 0 0 0 0 4 +  xm sedf 0 0 0 0 2 + + 1 fully-specified (10ms/3ms) domain, 3 other domains share + available rest in 2:7:3 ratio: +  xm sedf 10000000 3000000 0 0 0 +  xm sedf 0 0 0 0 2 +  xm sedf 0 0 0 0 7 +  xm sedf 0 0 0 0 3 \ No newline at end of file diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c index 1a25569d4b..902ae965e8 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c @@ -87,6 +87,12 @@ __FBSDID("$FreeBSD: src/sys/i386/isa/clock.c,v 1.207 2003/11/13 10:02:12 phk Exp /* XEN specific defines */ #include +#include /* needed by machine/pmap.h */ +#include /* needed by machine/pmap.h */ +#include /* needed by xen-os.h */ +#include +#include /* needed by xenfunc.h */ +#include /* * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we @@ -129,7 +135,15 @@ static uint64_t shadow_system_time; static uint32_t shadow_time_version; static struct timeval shadow_tv; +#define DEFINE_PER_CPU(type, name) \ + __typeof__(type) per_cpu__##name + +#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var)) + + static uint64_t processed_system_time;/* System time (ns) at last processing. */ +static DEFINE_PER_CPU(uint64_t, processed_system_time); + #define NS_PER_TICK (1000000000ULL/hz) @@ -202,18 +216,19 @@ static struct timecounter xen_timecounter = { static void clkintr(struct clockframe *frame) { - int64_t delta; + int64_t cpu_delta, delta; + int cpu = smp_processor_id(); long ticks = 0; - do { __get_time_values_from_xen(); - delta = (int64_t)(shadow_system_time + - xen_get_offset() * 1000 - - processed_system_time); + delta = cpu_delta = (int64_t)shadow_system_time + + (int64_t)xen_get_offset() * 1000; + delta -= processed_system_time; + cpu_delta -= per_cpu(processed_system_time, cpu); } while (!TIME_VALUES_UP_TO_DATE); - if (unlikely(delta < 0)) { + if (unlikely(delta < 0) || unlikely(cpu_delta < 0)) { printk("Timer ISR: Time went backwards: %lld\n", delta); return; } @@ -225,15 +240,28 @@ clkintr(struct clockframe *frame) delta -= NS_PER_TICK; processed_system_time += NS_PER_TICK; } - - if (ticks > 0) { - if (frame) - timer_func(frame); -#ifdef SMP - if (timer_func == hardclock && frame) - forward_hardclock(); + /* Local CPU jiffy work. */ + while (cpu_delta >= NS_PER_TICK) { + cpu_delta -= NS_PER_TICK; + per_cpu(processed_system_time, cpu) += NS_PER_TICK; +#if 0 + update_process_times(user_mode(regs)); + profile_tick(CPU_PROFILING, regs); #endif } + if (ticks > 0) { + if (frame) timer_func(frame); + } + + if (cpu != 0) + return; + /* + * Take synchronised time from Xen once a minute if we're not + * synchronised ourselves, and we haven't chosen to keep an independent + * time base. + */ + + /* XXX TODO */ } #include "opt_ddb.h" @@ -429,7 +457,7 @@ resettodr() * Start clocks running. */ void -cpu_initclocks() +cpu_initclocks(void) { int diag; int time_irq = bind_virq_to_irq(VIRQ_TIMER); @@ -445,8 +473,26 @@ cpu_initclocks() /* initialize xen values */ __get_time_values_from_xen(); processed_system_time = shadow_system_time; + per_cpu(processed_system_time, 0) = processed_system_time; + } +#ifdef SMP +void +ap_cpu_initclocks(void) +{ + int irq; + int cpu = smp_processor_id(); + + per_cpu(processed_system_time, cpu) = shadow_system_time; + + irq = bind_virq_to_irq(VIRQ_TIMER); + PCPU_SET(time_irq, irq); + PANIC_IF(intr_add_handler("clk", irq, (driver_intr_t *)clkintr, + NULL, INTR_TYPE_CLK | INTR_FAST, NULL)); +} +#endif + void cpu_startprofclock(void) { diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c index d6bda9ecc5..fde7fda330 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c @@ -79,9 +79,14 @@ evtchn_do_upcall(struct intrframe *frame) l2 &= ~(1 << l2i); port = (l1i << 5) + l2i; + irq = evtchn_to_irq[port]; +#ifdef SMP + if (irq == PCPU_GET(cpuast)) + continue; +#endif if ( (owned = mtx_owned(&sched_lock)) != 0 ) mtx_unlock_spin_flags(&sched_lock, MTX_QUIET); - if ( (irq = evtchn_to_irq[port]) != -1 ) { + if ( irq != -1 ) { struct intsrc *isrc = intr_lookup_source(irq); intr_execute_handlers(isrc, frame); } else { @@ -584,6 +589,7 @@ ap_evtchn_init(int cpu) PCPU_GET(virq_to_irq)[i] = -1; } + static void evtchn_init(void *dummy __unused) { @@ -591,13 +597,6 @@ evtchn_init(void *dummy __unused) struct xenpic *xp; struct xenpic_intsrc *pin; - /* - * xenpic_lock: in order to allow an interrupt to occur in a critical - * section, to set pcpu->ipending (etc...) properly, we - * must be able to get the icu lock, so it can't be - * under witness. - */ - mtx_init(&irq_mapping_update_lock, "xp", NULL, MTX_DEF); /* XXX -- expedience hack */ PCPU_SET(virq_to_irq, (int *)&virq_to_irq[0]); @@ -657,3 +656,11 @@ evtchn_init(void *dummy __unused) } SYSINIT(evtchn_init, SI_SUB_INTR, SI_ORDER_ANY, evtchn_init, NULL); + /* + * xenpic_lock: in order to allow an interrupt to occur in a critical + * section, to set pcpu->ipending (etc...) properly, we + * must be able to get the icu lock, so it can't be + * under witness. + */ + +MTX_SYSINIT(irq_mapping_update_lock, &irq_mapping_update_lock, "xp", MTX_DEF|MTX_NOWITNESS); diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c index ba1adb1de9..2343e63409 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c @@ -78,6 +78,7 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/machdep.c,v 1.584 2003/12/03 21:12:09 jhb #include #include #include +#include #include #include #include @@ -883,14 +884,6 @@ SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, static void cpu_idle_default(void) { -#if 0 - /* - * we must absolutely guarentee that hlt is the - * absolute next instruction after sti or we - * introduce a timing window. - */ - __asm __volatile("sti; hlt"); -#endif idle_block(); enable_intr(); } @@ -1376,6 +1369,7 @@ pteinfo_t *pteinfo_list; unsigned long *xen_machine_phys = ((unsigned long *)VADDR(1008, 0)); int preemptable; int gdt_set; +static int ncpus; /* Linux infection */ #define PAGE_OFFSET KERNBASE @@ -1387,6 +1381,10 @@ initvalues(start_info_t *startinfo) int i; vm_paddr_t pdir_shadow_ma, KPTphys; vm_offset_t *pdir_shadow; +#ifdef SMP + int j; +#endif + #ifdef WRITABLE_PAGETABLES printk("using writable pagetables\n"); HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); @@ -1447,18 +1445,19 @@ initvalues(start_info_t *startinfo) #ifdef SMP +#if 0 /* allocate cpu0 private page */ cpu0prvpage = (KERNBASE + (tmpindex << PAGE_SHIFT)); tmpindex++; - +#endif /* allocate SMP page table */ SMPpt = (unsigned long *)(KERNBASE + (tmpindex << PAGE_SHIFT)); - +#if 0 /* Map the private page into the SMP page table */ SMPpt[0] = vtomach(cpu0prvpage) | PG_RW | PG_M | PG_V | PG_A; - +#endif /* map SMP page table RO */ - PT_SET_MA(SMPpt, vtomach(SMPpt) & ~PG_RW); + PT_SET_MA(SMPpt, *vtopte((vm_offset_t)SMPpt) & ~PG_RW); /* put the page table into the page directory */ xen_queue_pt_update((vm_paddr_t)(IdlePTD + MPPTDI), @@ -1496,44 +1495,61 @@ initvalues(start_info_t *startinfo) tmpindex++; HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list = (unsigned long)xen_phys_machine; + ncpus = HYPERVISOR_shared_info->n_vcpu; +#ifdef SMP + for (i = 0; i < ncpus; i++) { + int npages = (sizeof(struct privatespace) + 1)/PAGE_SIZE; + for (j = 0; j < npages; j++) { + vm_paddr_t ma = xpmap_ptom(tmpindex << PAGE_SHIFT); + tmpindex++; + PT_SET_VA_MA(SMPpt + i*npages + j, ma | PG_A | PG_V | PG_RW | PG_M, FALSE); + } + } + xen_flush_queue(); +#endif init_first = tmpindex; } + +trap_info_t trap_table[] = { + { 0, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(div)}, + { 1, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dbg)}, + { 3, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bpt)}, + { 4, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ofl)}, + /* This is UPL on Linux and KPL on BSD */ + { 5, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bnd)}, + { 6, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ill)}, + { 7, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dna)}, + /* + * { 8, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(XXX)}, + * no handler for double fault + */ + { 9, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpusegm)}, + {10, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(tss)}, + {11, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(missing)}, + {12, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(stk)}, + {13, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(prot)}, + {14, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(page)}, + {15, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(rsvd)}, + {16, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpu)}, + {17, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(align)}, + {18, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(mchk)}, + {19, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(xmm)}, + {0x80, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(int0x80_syscall)}, + { 0, 0, 0, 0 } +}; + void init386(void) { int gsel_tss, metadata_missing, off, x, error; struct pcpu *pc; unsigned long gdtmachpfn; - trap_info_t trap_table[] = { - { 0, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(div)}, - { 1, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dbg)}, - { 3, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bpt)}, - { 4, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ofl)}, - /* This is UPL on Linux and KPL on BSD */ - { 5, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bnd)}, - { 6, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ill)}, - { 7, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dna)}, - /* - * { 8, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(XXX)}, - * no handler for double fault - */ - { 9, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpusegm)}, - {10, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(tss)}, - {11, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(missing)}, - {12, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(stk)}, - {13, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(prot)}, - {14, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(page)}, - {15, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(rsvd)}, - {16, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpu)}, - {17, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(align)}, - {18, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(mchk)}, - {19, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(xmm)}, - {0x80, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(int0x80_syscall)}, - { 0, 0, 0, 0 } - }; +#ifdef SMP + int i; +#endif proc0.p_uarea = proc0uarea; thread0.td_kstack = proc0kstack; thread0.td_pcb = (struct pcb *) @@ -1583,26 +1599,42 @@ init386(void) gdt_segs[GDATA_SEL].ssd_limit = atop(0 - ((1 << 26) - (1 << 22) + (1 << 16))); #endif #ifdef SMP - /* this correspond to the cpu private page as mapped into the SMP page - * table in initvalues + /* XXX this will blow up if there are more than 512/NGDT vcpus - will never + * be an issue in the real world but should add an assert on general principles + * we'll likely blow up when we hit LAST_RESERVED_GDT_ENTRY, at which point we + * would need to start allocating more pages for the GDT */ pc = &SMP_prvspace[0].pcpu; - gdt_segs[GPRIV_SEL].ssd_limit = - atop(sizeof(struct privatespace) - 1); + for (i = 0; i < ncpus; i++) { + cpu_add(i, (i == 0)); + + gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[i]; + gdt_segs[GPRIV_SEL].ssd_limit = + atop(sizeof(struct privatespace) - 1); + gdt_segs[GPROC0_SEL].ssd_base = + (int) &SMP_prvspace[i].pcpu.pc_common_tss; + SMP_prvspace[i].pcpu.pc_prvspace = + &SMP_prvspace[i].pcpu; + + for (x = 0; x < NGDT; x++) { + ssdtosd(&gdt_segs[x], &gdt[i * NGDT + x].sd); + } + } #else pc = &__pcpu; gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct pcpu) - 1); -#endif gdt_segs[GPRIV_SEL].ssd_base = (int) pc; gdt_segs[GPROC0_SEL].ssd_base = (int) &pc->pc_common_tss; for (x = 0; x < NGDT; x++) ssdtosd(&gdt_segs[x], &gdt[x].sd); +#endif + PT_SET_MA(gdt, *vtopte((unsigned long)gdt) & ~PG_RW); gdtmachpfn = vtomach(gdt) >> PAGE_SHIFT; - if ((error = HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1))) - panic("set_gdt failed"); + PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1) != 0); + lgdt_finish(); gdt_set = 1; diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c index b975c9e491..64f42259e8 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c @@ -83,7 +83,16 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.235.2.3 2004/09/24 15:02: #include #include + +/* XEN includes */ #include +#include + +void Xhypervisor_callback(void); +void failsafe_callback(void); + +/***************/ + #define WARMBOOT_TARGET 0 #define WARMBOOT_OFF (KERNBASE + 0x0467) @@ -94,6 +103,10 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.235.2.3 2004/09/24 15:02: #define BIOS_RESET (0x0f) #define BIOS_WARM (0x0a) + +#undef POSTCODE +#define POSTCODE(x) + /* * this code MUST be enabled here and in mpboot.s. * it follows the very early stages of AP boot by placing values in CMOS ram. @@ -175,6 +188,8 @@ extern pt_entry_t *KPTphys; /* SMP page table page */ extern pt_entry_t *SMPpt; +extern trap_info_t trap_table[]; + struct pcb stoppcbs[MAXCPU]; /* Variables needed for SMP tlb shootdown. */ @@ -208,7 +223,9 @@ static u_int boot_address; static void set_logical_apic_ids(void); static int start_all_aps(void); +#if 0 static void install_ap_tramp(void); +#endif static int start_ap(int apic_id); static void release_aps(void *dummy); @@ -314,6 +331,7 @@ int cpu_mp_probe(void) { + mp_ncpus = HYPERVISOR_shared_info->n_vcpu; /* * Always record BSP in CPU map so that the mbuf init code works * correctly. @@ -342,20 +360,24 @@ cpu_mp_probe(void) return (1); } -/* - * Initialize the IPI handlers and start up the AP's. - */ -void -cpu_mp_start(void) +static void +cpu_mp_ipi_init(void) { - int i; - - POSTCODE(MP_START_POST); - - /* Initialize the logical ID to APIC ID table. */ - for (i = 0; i < MAXCPU; i++) - cpu_apic_ids[i] = -1; - + int irq; + int cpu = smp_processor_id(); + /* + * these are not needed by XenFreeBSD - from Keir: + * For TLB-flush related IPIs, Xen has hypercalls + * you should use instead. You can pass a pointer + * to a vcpu bitmap to update_va_mapping(), and to + * MMUEXT_flush_tlb_multi and MMEXT_invlpg_multi. + * Xen will then make sure that those vcpus get + * flushed appropriately before returning to the + * caller. + * There is also no indication that we need to forward + * clock interrupts. + */ +#if 0 /* Install an inter-CPU IPI for TLB invalidation */ setidt(IPI_INVLTLB, IDTVEC(invltlb), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -371,22 +393,69 @@ cpu_mp_start(void) /* Install an inter-CPU IPI for forwarding statclock() */ setidt(IPI_STATCLOCK, IDTVEC(statclock), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - +#endif + + /* + * These can all be consolidated. For now leaving + * as individual IPIs. + * + */ +#if 0 /* Install an inter-CPU IPI for lazy pmap release */ setidt(IPI_LAZYPMAP, IDTVEC(lazypmap), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#else + irq = bind_ipi_on_cpu_to_irq(cpu, IPI_LAZYPMAP); + PCPU_SET(lazypmap, irq); + PANIC_IF(intr_add_handler("pmap_lazyfix", irq, + (driver_intr_t *)pmap_lazyfix_action, + NULL, INTR_TYPE_CLK | INTR_FAST, NULL)); +#endif +#if 0 /* Install an inter-CPU IPI for all-CPU rendezvous */ setidt(IPI_RENDEZVOUS, IDTVEC(rendezvous), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#else + irq = bind_ipi_on_cpu_to_irq(cpu, IPI_RENDEZVOUS); + PCPU_SET(rendezvous, irq); + PANIC_IF(intr_add_handler("smp_rendezvous", irq, + (driver_intr_t *)smp_rendezvous_action, + NULL, INTR_TYPE_CLK | INTR_FAST, NULL)); +#endif +#if 0 /* Install an inter-CPU IPI for forcing an additional software trap */ setidt(IPI_AST, IDTVEC(cpuast), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - +#else + irq = bind_ipi_on_cpu_to_irq(cpu, IPI_AST); + PCPU_SET(cpuast, irq); +#endif + /* XXX ignore for now */ +#if 0 /* Install an inter-CPU IPI for CPU stop/restart */ setidt(IPI_STOP, IDTVEC(cpustop), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#endif + +} + +SYSINIT(ipi_setup, SI_SUB_INTR, SI_ORDER_ANY, cpu_mp_ipi_init, NULL); + +/* + * Initialize the IPI handlers and start up the AP's. + */ +void +cpu_mp_start(void) /* --- Start here --- */ +{ + int i; + + POSTCODE(MP_START_POST); + + /* Initialize the logical ID to APIC ID table. */ + for (i = 0; i < MAXCPU; i++) + cpu_apic_ids[i] = -1; /* Set boot_cpu_id if needed. */ @@ -437,35 +506,44 @@ cpu_mp_announce(void) void init_secondary(void) { - int gsel_tss; - int x, myid; + int myid; + unsigned long gdtmachpfn; + printk("MADE IT!!"); + #if 0 u_int cr0; #endif + /* Steps to booting SMP on xen as gleaned from XenLinux: + * - cpu_init() - processor specific initialization + * - smp_callin() + * - wait 2s for BP to finish its startup sequence + * - map_cpu_to_logical_apicid() + * - save cpuid info + * - set bit in callin map to let master (BP?) continue + * - local setup timer() - per cpu timer initialization + * - ldebug_setup() - bind debug IRQ to local CPU. + * - smp_intr_init() - IPI setup that we do in cpu_mp_start + * - local_irq_enable() - enable interrupts locally + * - cpu_set(id, map) - announce that we're up + * - cpu_idle() - make us schedulable + */ + + /* bootAP is set in start_ap() to our ID. */ myid = bootAP; - gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[myid]; - gdt_segs[GPROC0_SEL].ssd_base = - (int) &SMP_prvspace[myid].pcpu.pc_common_tss; - SMP_prvspace[myid].pcpu.pc_prvspace = - &SMP_prvspace[myid].pcpu; - for (x = 0; x < NGDT; x++) { - ssdtosd(&gdt_segs[x], &gdt[myid * NGDT + x].sd); - } + gdtmachpfn = vtomach(gdt) >> PAGE_SHIFT; + PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1) != 0); -#if 0 - r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; - r_gdt.rd_base = (int) &gdt[myid * NGDT]; - lgdt(&r_gdt); /* does magic intra-segment return */ + + lgdt_finish(); - lidt(&r_idt); - lldt(_default_ldt); -#endif + PCPU_SET(cpuid, myid); + + + set_user_ldt((struct mdproc *)_default_ldt); PCPU_SET(currentldt, _default_ldt); - gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); - gdt[myid * NGDT + GPROC0_SEL].sd.sd_type = SDT_SYS386TSS; PCPU_SET(common_tss.tss_esp0, 0); /* not used until after switch */ PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL)); PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); @@ -557,6 +635,13 @@ init_secondary(void) while (smp_started == 0) ia32_pause(); + /* need to wait until now to setup the IPIs as SI_SUB_CPU is + * much earlier than SI_SUB_INTR + */ + ap_evtchn_init(myid); + ap_cpu_initclocks(); + cpu_mp_ipi_init(); + /* ok, now grab sched_lock and enter the scheduler */ mtx_lock_spin(&sched_lock); @@ -610,28 +695,35 @@ set_logical_apic_ids(void) static int start_all_aps(void) { -#ifndef PC98 - u_char mpbiosreason; -#endif - u_long mpbioswarmvec; struct pcpu *pc; char *stack; - uintptr_t kptbase; - int i, pg, apic_id, cpu; + int i, apic_id, cpu; + + /* + * This function corresponds most closely to + * smp_boot_cpus in XenLinux - the sequence there + * is: + * - check if SMP config is found - if not: + * - clear the I/O APIC IRQs + * - map cpu to logical apicid + * - exit + * - smp_intr_init - IPI initialization + * - map cpu to logical apicid + * - boot each of the vcpus + * - clear and then construct the cpu sibling [logical CPUs] map. + * + */ POSTCODE(START_ALL_APS_POST); mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); - +#if 0 /* install the AP 1st level boot code */ install_ap_tramp(); /* save the current value of the warm-start vector */ mpbioswarmvec = *((u_long *) WARMBOOT_OFF); -#ifndef PC98 - outb(CMOS_REG, BIOS_RESET); - mpbiosreason = inb(CMOS_DATA); -#endif + /* set up temporary P==V mapping for AP boot */ /* XXX this is a hack, we should boot the AP on its own stack/PTD */ @@ -640,7 +732,7 @@ start_all_aps(void) PTD[i] = (pd_entry_t)(PG_V | PG_RW | ((kptbase + i * PAGE_SIZE) & PG_FRAME)); invltlb(); - +#endif /* start each AP */ for (cpu = 0, apic_id = 0; apic_id < MAXCPU; apic_id++) { if (!cpu_info[apic_id].cpu_present || @@ -650,7 +742,7 @@ start_all_aps(void) /* save APIC ID for this logical ID */ cpu_apic_ids[cpu] = apic_id; - +#if 0 /* first page of AP's private space */ pg = cpu * i386_btop(sizeof(struct privatespace)); @@ -665,11 +757,14 @@ start_all_aps(void) for (i = 0; i < KSTACK_PAGES; i++) SMPpt[pg + 1 + i] = (pt_entry_t) (PG_V | PG_RW | vtophys(PAGE_SIZE * i + stack)); +#endif + pc = &SMP_prvspace[cpu].pcpu; /* prime data page for it to use */ pcpu_init(pc, cpu, sizeof(struct pcpu)); pc->pc_apic_id = apic_id; +#if 0 /* setup a vector to our boot code */ *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET; *((volatile u_short *) WARMBOOT_SEG) = (boot_address >> 4); @@ -677,7 +772,7 @@ start_all_aps(void) outb(CMOS_REG, BIOS_RESET); outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */ #endif - +#endif bootSTK = &SMP_prvspace[cpu].idlekstack[KSTACK_PAGES * PAGE_SIZE]; bootAP = cpu; @@ -700,13 +795,10 @@ start_all_aps(void) /* build our map of 'other' CPUs */ PCPU_SET(other_cpus, all_cpus & ~PCPU_GET(cpumask)); +#if 0 /* restore the warmstart vector */ *(u_long *) WARMBOOT_OFF = mpbioswarmvec; -#ifndef PC98 - outb(CMOS_REG, BIOS_RESET); - outb(CMOS_DATA, mpbiosreason); #endif - /* * Set up the idle context for the BSP. Similar to above except * that some was done by locore, some by pmap.c and some is implicit @@ -739,7 +831,7 @@ extern void bootDataSeg(void); extern void MPentry(void); extern u_int MP_GDT; extern u_int mp_gdtbase; - +#if 0 static void install_ap_tramp(void) { @@ -791,6 +883,21 @@ install_ap_tramp(void) *dst16 = (u_int) boot_address & 0xffff; *dst8 = ((u_int) boot_address >> 16) & 0xff; } +#endif + +static int +cpu_mp_trap_init(trap_info_t *trap_ctxt) +{ + + trap_info_t *t = trap_table; + + for (t = trap_table; t->address; t++) { + trap_ctxt[t->vector].flags = t->flags; + trap_ctxt[t->vector].cs = t->cs; + trap_ctxt[t->vector].address = t->address; + } + return 0x80 /*SYSCALL_VECTOR*/; +} /* * This function starts the AP (application processor) identified @@ -802,8 +909,25 @@ install_ap_tramp(void) static int start_ap(int apic_id) { - int vector, ms; - int cpus; + int vector, ms, i; + int cpus, boot_error; + vcpu_guest_context_t ctxt; + + /* + * This is the FreeBSD equivalent to do_boot_cpu(apicid) in + * smpboot.c. + * its initialization sequence consists of: + * - fork_idle(cpu) to create separate idle context + * - initialization of idle's context to start_secondary + * - initialization of cpu ctxt to start in startup_32_smp + * - then we call HYPERVISOR_boot_vcpu with the cpu index and + * a pointer to the context. + * - on boot success we: + * - set ourselves in the callout_map + * - wait up to 5 seconds for us to be set in the callin map + * - set x86_cpu_to_apicid[cpu] = apicid; + * + */ POSTCODE(START_AP_POST); @@ -813,6 +937,55 @@ start_ap(int apic_id) /* used as a watchpoint to signal AP startup */ cpus = mp_naps; + memset(&ctxt, 0, sizeof(ctxt)); + + ctxt.user_regs.ds = GSEL(GDATA_SEL, SEL_KPL); + ctxt.user_regs.es = GSEL(GDATA_SEL, SEL_KPL); + ctxt.user_regs.fs = 0; + ctxt.user_regs.gs = 0; + ctxt.user_regs.ss = __KERNEL_DS; + ctxt.user_regs.cs = __KERNEL_CS; + ctxt.user_regs.eip = (unsigned long)init_secondary; + ctxt.user_regs.esp = (unsigned long)bootSTK; +#ifdef notyet + ctxt.user_regs.eflags = (1<<9) | (1<<2) | (idle->thread.io_pl<<12); +#else + ctxt.user_regs.eflags = (1<<9) | (1<<2); +#endif + /* FPU is set up to default initial state. */ + memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt)); + + /* Virtual IDT is empty at start-of-day. */ + for ( i = 0; i < 256; i++ ) + { + ctxt.trap_ctxt[i].vector = i; + ctxt.trap_ctxt[i].cs = FLAT_KERNEL_CS; + } + ctxt.fast_trap_idx = cpu_mp_trap_init(ctxt.trap_ctxt); + + /* No LDT. */ + ctxt.ldt_ents = 0; + + /* Ring 1 stack is the initial stack. */ + ctxt.kernel_ss = __KERNEL_DS; + ctxt.kernel_sp = (unsigned long)bootSTK; + + /* Callback handlers. */ + ctxt.event_callback_cs = __KERNEL_CS; + ctxt.event_callback_eip = (unsigned long)Xhypervisor_callback; + ctxt.failsafe_callback_cs = __KERNEL_CS; + ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback; + + ctxt.pt_base = (vm_paddr_t)IdlePTD; + + boot_error = HYPERVISOR_boot_vcpu(bootAP, &ctxt); + + + if (boot_error) + printk("Houston we have a problem\n"); + else + printk("boot_vcpu succeeded\n"); +#if 0 /* * first we do an INIT/RESET IPI this INIT IPI might be run, reseting * and running the target CPU. OR this INIT IPI might be latched (P5 @@ -862,6 +1035,7 @@ start_ap(int apic_id) APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | vector, apic_id); lapic_ipi_wait(-1); +#endif DELAY(200); /* wait ~200uS */ /* Wait up to 5 seconds for it to start. */ diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c index 79b052a34c..6529602eb7 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c @@ -1374,7 +1374,6 @@ static u_int *lazymask; static u_int lazyptd; static volatile u_int lazywait; -void pmap_lazyfix_action(void); void pmap_lazyfix_action(void) diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c index 85794f2c2e..2d7f184ac7 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c @@ -380,8 +380,6 @@ printk(const char *fmt, ...) (void)HYPERVISOR_console_write(buf, ret); } -#define PANIC_IF(exp) if (unlikely(exp)) {printk("%s failed\n",#exp); panic("%s: %s:%d", #exp, __FILE__, __LINE__);} - #define XPQUEUE_SIZE 128 #ifdef SMP diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h b/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h index 94c449ded9..824ca96cee 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h @@ -441,4 +441,20 @@ HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type) return ret; } +static inline int +HYPERVISOR_boot_vcpu( + unsigned long vcpu, vcpu_guest_context_t *ctxt) +{ + int ret; + unsigned long ign1, ign2; + + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret), "=b" (ign1), "=c" (ign2) + : "0" (__HYPERVISOR_boot_vcpu), "1" (vcpu), "2" (ctxt) + : "memory"); + + return ret; +} + #endif /* __HYPERVISOR_H__ */ diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h b/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h index e373697cca..42941d5a91 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h @@ -53,7 +53,12 @@ int *pc_ipi_to_evtchn; \ int *pc_virq_to_irq; \ u_int pc_cr2; \ - u_int pc_pdir + u_int pc_pdir; \ + u_int pc_lazypmap; \ + u_int pc_rendezvous; \ + u_int pc_cpuast; \ + u_int pc_time_irq; \ + uint64_t pc_processed_system_time; #if defined(lint) diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h b/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h index c067a19969..d7f1923234 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h @@ -343,6 +343,7 @@ void pmap_set_pg(void); void pmap_invalidate_page(pmap_t, vm_offset_t); void pmap_invalidate_range(pmap_t, vm_offset_t, vm_offset_t); void pmap_invalidate_all(pmap_t); +void pmap_lazyfix_action(void); void pmap_map_readonly(pmap_t pmap, vm_offset_t va, int len); void pmap_map_readwrite(pmap_t pmap, vm_offset_t va, int len); diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h b/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h index bd35cf2ff1..e2b682265f 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h @@ -61,6 +61,9 @@ void load_cr3(uint32_t val); void xen_machphys_update(unsigned long, unsigned long); void xen_update_descriptor(union descriptor *, union descriptor *); void lldt(u_short sel); +void ap_cpu_initclocks(void); + + /* * Invalidate a patricular VA on all cpus * @@ -79,5 +82,6 @@ invltlb(void) } +#define PANIC_IF(exp) if (unlikely(exp)) {printk("%s failed\n",#exp); panic("%s: %s:%d", #exp, __FILE__, __LINE__);} #endif /* _XEN_XENFUNC_H_ */ diff --git a/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers b/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers index 8158f26fd0..cb30533783 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers +++ b/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers @@ -49,9 +49,46 @@ source "drivers/infiniband/Kconfig" endif if !XEN_PHYSDEV_ACCESS + +menu "Character devices" + config UNIX98_PTYS bool default y + +config LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx + for masters and /dev/ttyxx for slaves of pseudo + terminals. This scheme has a number of problems, including + security. This option enables these legacy devices; on most + systems, it is safe to say N. + + +config LEGACY_PTY_COUNT + int "Maximum number of legacy PTY in use" + depends on LEGACY_PTYS + range 1 256 + default "256" + ---help--- + The maximum number of legacy PTYs that can be used at any one time. + The default is 256, and should be more than enough. Embedded + systems may want to reduce this to save memory. + + When not in use, each legacy PTY occupies 12 bytes on 32-bit + architectures and 24 bytes on 64-bit architectures. + +endmenu + endif endmenu diff --git a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 index 0ecf7968e2..478d412669 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 +++ b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_32 @@ -340,6 +340,12 @@ CONFIG_NETDEVICES=y # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# Character devices +# # # File systems diff --git a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 index 9aa0f4f70e..e766ae7da1 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 +++ b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 @@ -316,6 +316,12 @@ CONFIG_NETDEVICES=y # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# Character devices +# # # File systems diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig index 3ed45ade7b..d1ffcb05d1 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig @@ -636,7 +636,7 @@ config MTRR config IRQBALANCE bool "Enable kernel irq balancing" - depends on SMP && X86_IO_APIC + depends on SMP && X86_IO_APIC && !XEN default y help The default yes will allow the kernel to do irq load balancing. @@ -677,6 +677,16 @@ config X86_IO_APIC depends on !SMP && X86_UP_IOAPIC default y +config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + depends on SMP && HOTPLUG && EXPERIMENTAL + ---help--- + Say Y here to experiment with turning CPUs off and on. CPUs + can be controlled through /sys/devices/system/cpu. + + Say N. + + if XEN_PHYSDEV_ACCESS menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile b/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile index 8af1059853..053c0984ac 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile @@ -72,6 +72,7 @@ head-y := arch/xen/i386/kernel/head.o arch/xen/i386/kernel/init_task.o libs-y += arch/i386/lib/ core-y += arch/xen/i386/kernel/ \ arch/xen/i386/mm/ \ + arch/xen/i386/mach-default/ \ arch/i386/crypto/ # \ # arch/xen/$(mcore-y)/ diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c index 6fbaa19613..882ff3fe9c 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c @@ -726,6 +726,7 @@ void fastcall send_IPI_self(int vector) } #endif /* !CONFIG_SMP */ + /* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c index 6cd16ccfdc..f31697ecb1 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #ifndef CONFIG_X86_LOCAL_APIC /* @@ -207,9 +210,8 @@ int show_interrupts(struct seq_file *p, void *v) if (i == 0) { seq_printf(p, " "); - for (j=0; jtypename); seq_printf(p, " %s", action->name); @@ -237,16 +238,13 @@ skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); } else if (i == NR_IRQS) { seq_printf(p, "NMI: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", nmi_count(j)); + for_each_cpu(j) + seq_printf(p, "%10u ", nmi_count(j)); seq_putc(p, '\n'); #ifdef CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", - irq_stat[j].apic_timer_irqs); + for_each_cpu(j) + seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); @@ -256,3 +254,44 @@ skip: } return 0; } + +#ifdef CONFIG_HOTPLUG_CPU + +void fixup_irqs(cpumask_t map) +{ + unsigned int irq; + static int warned; + + for (irq = 0; irq < NR_IRQS; irq++) { + cpumask_t mask; + if (irq == 2) + continue; + + cpus_and(mask, irq_affinity[irq], map); + if (any_online_cpu(mask) == NR_CPUS) { + printk("Breaking affinity for irq %i\n", irq); + mask = map; + } + if (irq_desc[irq].handler->set_affinity) + irq_desc[irq].handler->set_affinity(irq, mask); + else if (irq_desc[irq].action && !(warned++)) + printk("Cannot set affinity for irq %i\n", irq); + } + +#if 0 + barrier(); + /* Ingo Molnar says: "after the IO-APIC masks have been redirected + [note the nop - the interrupt-enable boundary on x86 is two + instructions from sti] - to flush out pending hardirqs and + IPIs. After this point nothing is supposed to reach this CPU." */ + __asm__ __volatile__("sti; nop; cli"); + barrier(); +#else + /* That doesn't seem sufficient. Give it 1ms. */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); +#endif +} +#endif + diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c index 0f9a2eed70..9061053081 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -54,6 +55,9 @@ #include #include +#include +#include + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); int hlt_counter; @@ -112,6 +116,33 @@ void xen_idle(void) } } +#ifdef CONFIG_HOTPLUG_CPU +#include +/* We don't actually take CPU down, just spin without interrupts. */ +static inline void play_dead(void) +{ + /* Ack it */ + __get_cpu_var(cpu_state) = CPU_DEAD; + + /* We shouldn't have to disable interrupts while dead, but + * some interrupts just don't seem to go away, and this makes + * it "work" for testing purposes. */ + /* Death loop */ + while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) + HYPERVISOR_yield(); + + local_irq_disable(); + __flush_tlb_all(); + cpu_set(smp_processor_id(), cpu_online_map); + local_irq_enable(); +} +#else +static inline void play_dead(void) +{ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + /* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a @@ -130,6 +161,9 @@ void cpu_idle (void) cpu_clear(cpu, cpu_idle_map); rmb(); + if (cpu_is_offline(cpu)) + play_dead(); + irq_stat[cpu].idle_timestamp = jiffies; xen_idle(); } diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c index 915034b36d..fddadbba25 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -185,6 +186,7 @@ void send_IPI_mask_bitmask(cpumask_t mask, int vector) unsigned int cpu; local_irq_save(flags); + WARN_ON(cpus_addr(mask)[0] & ~cpus_addr(cpu_online_map)[0]); for (cpu = 0; cpu < NR_CPUS; ++cpu) { if (cpu_isset(cpu, mask)) { @@ -320,21 +322,21 @@ out: static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, unsigned long va) { - cpumask_t tmp; /* * A couple of (to be removed) sanity checks: * - * - we do not send IPIs to not-yet booted CPUs. * - current CPU must not be in mask * - mask must exist :) */ BUG_ON(cpus_empty(cpumask)); - - cpus_and(tmp, cpumask, cpu_online_map); - BUG_ON(!cpus_equal(cpumask, tmp)); BUG_ON(cpu_isset(smp_processor_id(), cpumask)); BUG_ON(!mm); + /* If a CPU which we ran on has gone down, OK. */ + cpus_and(cpumask, cpumask, cpu_online_map); + if (cpus_empty(cpumask)) + return; + /* * i'm not happy about this global shared spinlock in the * MM hot path, but we'll see how contended it is. @@ -465,6 +467,7 @@ void flush_tlb_all(void) */ void smp_send_reschedule(int cpu) { + WARN_ON(cpu_is_offline(cpu)); send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); } @@ -505,10 +508,16 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, */ { struct call_data_struct data; - int cpus = num_online_cpus()-1; + int cpus; - if (!cpus) + /* Holding any lock stops cpus from going down. */ + spin_lock(&call_lock); + cpus = num_online_cpus()-1; + + if (!cpus) { + spin_unlock(&call_lock); return 0; + } /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); @@ -520,7 +529,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, if (wait) atomic_set(&data.finished, 0); - spin_lock(&call_lock); call_data = &data; mb(); diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c index ec1b3b9dea..7c1ef78cd9 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -44,6 +44,9 @@ #include #include #include +#include +#include +#include #include #include @@ -51,11 +54,7 @@ #include #include -#if 1 -#define Dprintk(args...) -#else #include -#endif #include #include @@ -93,7 +92,14 @@ extern unsigned char trampoline_data []; extern unsigned char trampoline_end []; static unsigned char *trampoline_base; static int trampoline_exec; +#endif +#ifdef CONFIG_HOTPLUG_CPU +/* State of each CPU. */ +DEFINE_PER_CPU(int, cpu_state) = { 0 }; +#endif + +#if 0 /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller @@ -462,7 +468,7 @@ extern void local_setup_timer(void); /* * Activate a secondary processor. */ -static int __init start_secondary(void *unused) +static void __init start_secondary(void *unused) { /* * Dont put anything before smp_callin(), SMP @@ -488,17 +494,6 @@ static int __init start_secondary(void *unused) local_irq_enable(); wmb(); - if (0) { - char *msg2 = "delay2\n"; - int timeout; - for (timeout = 0; timeout < 50000; timeout++) { - udelay(1000); - if (timeout == 2000) { - (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg2), msg2); - timeout = 0; - } - } - } cpu_idle(); } @@ -1105,15 +1100,15 @@ static void __init smp_boot_cpus(unsigned int max_cpus) * If we couldn't find an SMP configuration at boot time, * get out of here now! */ - if (!smp_found_config /* && !acpi_lapic) */) { + if (!smp_found_config && !acpi_lapic) { printk(KERN_NOTICE "SMP motherboard not detected.\n"); smpboot_clear_io_apic_irqs(); #if 0 phys_cpu_present_map = physid_mask_of_physid(0); +#endif if (APIC_init_uniprocessor()) printk(KERN_NOTICE "Local APIC not detected." " Using dummy APIC emulation.\n"); -#endif map_cpu_to_logical_apicid(); return; } @@ -1267,9 +1262,11 @@ static void __init smp_boot_cpus(unsigned int max_cpus) #if 0 if (nmi_watchdog == NMI_LOCAL_APIC) check_nmi_watchdog(); +#endif smpboot_setup_io_apic(); +#if 0 setup_boot_APIC_clock(); /* @@ -1284,6 +1281,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus) who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */ void __init smp_prepare_cpus(unsigned int max_cpus) { + smp_commenced_mask = cpumask_of_cpu(0); + cpu_callin_map = cpumask_of_cpu(0); + mb(); smp_boot_cpus(max_cpus); } @@ -1293,20 +1293,97 @@ void __devinit smp_prepare_boot_cpu(void) cpu_set(smp_processor_id(), cpu_callout_map); } +#ifdef CONFIG_HOTPLUG_CPU + +/* must be called with the cpucontrol mutex held */ +static int __devinit cpu_enable(unsigned int cpu) +{ + /* get the target out of its holding state */ + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; + wmb(); + + /* wait for the processor to ack it. timeout? */ + while (!cpu_online(cpu)) + cpu_relax(); + + fixup_irqs(cpu_online_map); + /* counter the disable in fixup_irqs() */ + local_irq_enable(); + return 0; +} + +int __cpu_disable(void) +{ + cpumask_t map = cpu_online_map; + int cpu = smp_processor_id(); + + /* + * Perhaps use cpufreq to drop frequency, but that could go + * into generic code. + * + * We won't take down the boot processor on i386 due to some + * interrupts only being able to be serviced by the BSP. + * Especially so if we're not using an IOAPIC -zwane + */ + if (cpu == 0) + return -EBUSY; + + /* Allow any queued timer interrupts to get serviced */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); + + cpu_clear(cpu, map); + fixup_irqs(map); + /* It's now safe to remove this processor from the online map */ + cpu_clear(cpu, cpu_online_map); + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + /* We don't do anything here: idle task is faking death itself. */ + unsigned int i; + + for (i = 0; i < 10; i++) { + /* They ack this in play_dead by setting CPU_DEAD */ + if (per_cpu(cpu_state, cpu) == CPU_DEAD) + return; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); + } + printk(KERN_ERR "CPU %u didn't die...\n", cpu); +} +#else /* ... !CONFIG_HOTPLUG_CPU */ +int __cpu_disable(void) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ + /* We said "no" in __cpu_disable */ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + int __devinit __cpu_up(unsigned int cpu) { - /* This only works at boot for x86. See "rewrite" above. */ - if (cpu_isset(cpu, smp_commenced_mask)) { - local_irq_enable(); - return -ENOSYS; - } - /* In case one didn't come up */ if (!cpu_isset(cpu, cpu_callin_map)) { + printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu); local_irq_enable(); return -EIO; } +#ifdef CONFIG_HOTPLUG_CPU + /* Already up, and in cpu_quiescent now? */ + if (cpu_isset(cpu, smp_commenced_mask)) { + cpu_enable(cpu); + return 0; + } +#endif + local_irq_enable(); /* Unleash the CPU! */ cpu_set(cpu, smp_commenced_mask); diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c index a6615b7e18..d0718b5299 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c @@ -609,6 +609,14 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code) nmi_enter(); cpu = smp_processor_id(); + +#ifdef CONFIG_HOTPLUG_CPU + if (!cpu_online(cpu)) { + nmi_exit(); + return; + } +#endif + ++nmi_count(cpu); if (!nmi_callback(regs, cpu)) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile b/linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile new file mode 100644 index 0000000000..7d50b2926e --- /dev/null +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the linux kernel. +# + +c-obj-y := topology.o + +$(patsubst %.o,$(obj)/%.c,$(c-obj-y)): + @ln -fsn $(srctree)/arch/i386/mach-default/$(notdir $@) $@ + +obj-y += $(c-obj-y) + +clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-)) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c index e3a588e029..b571bd6aaf 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c @@ -361,6 +361,7 @@ static void __init pagetable_init (void) make_page_writable(old_pgd); __flush_tlb_all(); free_bootmem(__pa(old_pgd), PAGE_SIZE); + init_mm.context.pinned = 1; kernel_physical_mapping_init(pgd_base); remap_numa_kva(); diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c index 59399cceff..0215422a5a 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -480,7 +481,6 @@ void mm_unpin(struct mm_struct *mm) void _arch_exit_mmap(struct mm_struct *mm) { - unsigned int cpu = smp_processor_id(); struct task_struct *tsk = current; task_lock(tsk); @@ -494,9 +494,7 @@ void _arch_exit_mmap(struct mm_struct *mm) tsk->active_mm = &init_mm; atomic_inc(&init_mm.mm_count); - cpu_set(cpu, init_mm.cpu_vm_mask); - load_cr3(swapper_pg_dir); - cpu_clear(cpu, mm->cpu_vm_mask); + switch_mm(mm, &init_mm, tsk); atomic_dec(&mm->mm_count); BUG_ON(atomic_read(&mm->mm_count) == 0); diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile b/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile index d6a253a090..47dbc45daa 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile +++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile @@ -12,7 +12,7 @@ c-obj-y := i386.o c-obj-y += fixup.o c-obj-$(CONFIG_ACPI_PCI) += acpi.o c-obj-y += legacy.o common.o -c-xen-obj-$(CONFIG_PCI_DIRECT)+= direct.o +c-obj-$(CONFIG_PCI_DIRECT)+= direct.o c-xen-obj-y += irq.o # mmconfig has a 64bit special c-obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h index 421a81f17b..c2c211e5ea 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h @@ -3,11 +3,7 @@ static inline void smpboot_clear_io_apic_irqs(void) { -#if 1 - printk("smpboot_clear_io_apic_irqs\n"); -#else io_apic_irqs = 0; -#endif } static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) @@ -43,16 +39,12 @@ static inline void smpboot_restore_warm_reset_vector(void) static inline void smpboot_setup_io_apic(void) { -#if 1 - printk("smpboot_setup_io_apic\n"); -#else /* * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); -#endif } diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h index 421a81f17b..c2c211e5ea 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h @@ -3,11 +3,7 @@ static inline void smpboot_clear_io_apic_irqs(void) { -#if 1 - printk("smpboot_clear_io_apic_irqs\n"); -#else io_apic_irqs = 0; -#endif } static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) @@ -43,16 +39,12 @@ static inline void smpboot_restore_warm_reset_vector(void) static inline void smpboot_setup_io_apic(void) { -#if 1 - printk("smpboot_setup_io_apic\n"); -#else /* * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); -#endif } diff --git a/patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch b/patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch new file mode 100644 index 0000000000..ec39143743 --- /dev/null +++ b/patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch @@ -0,0 +1,656 @@ + +From: Zwane Mwaikambo + +Find attached the i386 cpu hotplug patch updated for Ingo's latest round of +goodies. In order to avoid dumping cpu hotplug code into kernel/irq/* i +dropped the cpu_online check in do_IRQ() by modifying fixup_irqs(). The +difference being that on cpu offline, fixup_irqs() is called before we +clear the cpu from cpu_online_map and a long delay in order to ensure that +we never have any queued external interrupts on the APICs. Due to my usual +test victims being in boxes a continent away this hasn't been tested, but +i'll cover bug reports (nudge, Nathan! ;) + +1) Add CONFIG_HOTPLUG_CPU +2) disable local APIC timer on dead cpus. +3) Disable preempt around irq balancing to prevent CPUs going down. +4) Print irq stats for all possible cpus. +5) Debugging check for interrupts on offline cpus. +6) Hacky fixup_irqs() to redirect irqs when cpus go off/online. +7) play_dead() for offline cpus to spin inside. +8) Handle offline cpus set in flush_tlb_others(). +9) Grab lock earlier in smp_call_function() to prevent CPUs going down. +10) Implement __cpu_disable() and __cpu_die(). +11) Enable local interrupts in cpu_enable() after fixup_irqs() +12) Don't fiddle with NMI on dead cpu, but leave intact on other cpus. +13) Program IRQ affinity whilst cpu is still in cpu_online_map on offline. + +Signed-off-by: Zwane Mwaikambo +DESC +ppc64: fix hotplug cpu +EDESC +From: Zwane Mwaikambo + +I seem to have broken this when I moved the clearing of the dying cpu to +arch specific code. + +Signed-off-by: Zwane Mwaikambo +Signed-off-by: Andrew Morton +--- + + 25-akpm/arch/i386/Kconfig | 9 ++ + 25-akpm/arch/i386/kernel/apic.c | 3 + 25-akpm/arch/i386/kernel/io_apic.c | 2 + 25-akpm/arch/i386/kernel/irq.c | 66 +++++++++++++++++---- + 25-akpm/arch/i386/kernel/msr.c | 2 + 25-akpm/arch/i386/kernel/process.c | 35 +++++++++++ + 25-akpm/arch/i386/kernel/smp.c | 25 +++++--- + 25-akpm/arch/i386/kernel/smpboot.c | 98 ++++++++++++++++++++++++++++++-- + 25-akpm/arch/i386/kernel/traps.c | 8 ++ + 25-akpm/arch/ia64/kernel/smpboot.c | 3 + 25-akpm/arch/ppc64/kernel/pSeries_smp.c | 5 + + 25-akpm/arch/s390/kernel/smp.c | 4 - + 25-akpm/include/asm-i386/cpu.h | 2 + 25-akpm/include/asm-i386/irq.h | 4 + + 25-akpm/include/asm-i386/smp.h | 3 + 25-akpm/kernel/cpu.c | 14 +--- + arch/ppc64/kernel/smp.c | 0 + 17 files changed, 242 insertions(+), 41 deletions(-) + +diff -puN arch/i386/Kconfig~i386-cpu-hotplug-updated-for-mm arch/i386/Kconfig +--- 25/arch/i386/Kconfig~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/Kconfig 2005-02-23 02:20:06.000000000 -0800 +@@ -1205,6 +1205,15 @@ config SCx200 + This support is also available as a module. If compiled as a + module, it will be called scx200. + ++config HOTPLUG_CPU ++ bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" ++ depends on SMP && HOTPLUG && EXPERIMENTAL ++ ---help--- ++ Say Y here to experiment with turning CPUs off and on. CPUs ++ can be controlled through /sys/devices/system/cpu. ++ ++ Say N. ++ + source "drivers/pcmcia/Kconfig" + + source "drivers/pci/hotplug/Kconfig" +diff -puN arch/i386/kernel/apic.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/apic.c +--- 25/arch/i386/kernel/apic.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/apic.c 2005-02-23 02:20:06.000000000 -0800 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1048,7 +1049,7 @@ void __init setup_secondary_APIC_clock(v + setup_APIC_timer(calibration_result); + } + +-void __init disable_APIC_timer(void) ++void __devinit disable_APIC_timer(void) + { + if (using_apic_timer) { + unsigned long v; +diff -puN arch/i386/kernel/io_apic.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/io_apic.c +--- 25/arch/i386/kernel/io_apic.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/io_apic.c 2005-02-23 02:20:06.000000000 -0800 +@@ -576,9 +576,11 @@ static int balanced_irq(void *unused) + try_to_freeze(PF_FREEZE); + if (time_after(jiffies, + prev_balance_time+balanced_irq_interval)) { ++ preempt_disable(); + do_irq_balance(); + prev_balance_time = jiffies; + time_remaining = balanced_irq_interval; ++ preempt_enable(); + } + } + return 0; +diff -puN arch/i386/kernel/irq.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/irq.c +--- 25/arch/i386/kernel/irq.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/irq.c 2005-02-23 02:20:06.000000000 -0800 +@@ -15,6 +15,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #ifndef CONFIG_X86_LOCAL_APIC + /* +@@ -209,9 +212,8 @@ int show_interrupts(struct seq_file *p, + + if (i == 0) { + seq_printf(p, " "); +- for (j=0; jtypename); + seq_printf(p, " %s", action->name); +@@ -239,16 +240,13 @@ skip: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } else if (i == NR_IRQS) { + seq_printf(p, "NMI: "); +- for (j = 0; j < NR_CPUS; j++) +- if (cpu_online(j)) +- seq_printf(p, "%10u ", nmi_count(j)); ++ for_each_cpu(j) ++ seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); + #ifdef CONFIG_X86_LOCAL_APIC + seq_printf(p, "LOC: "); +- for (j = 0; j < NR_CPUS; j++) +- if (cpu_online(j)) +- seq_printf(p, "%10u ", +- irq_stat[j].apic_timer_irqs); ++ for_each_cpu(j) ++ seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); + seq_putc(p, '\n'); + #endif + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +@@ -258,3 +256,45 @@ skip: + } + return 0; + } ++ ++#ifdef CONFIG_HOTPLUG_CPU ++#include ++ ++void fixup_irqs(cpumask_t map) ++{ ++ unsigned int irq; ++ static int warned; ++ ++ for (irq = 0; irq < NR_IRQS; irq++) { ++ cpumask_t mask; ++ if (irq == 2) ++ continue; ++ ++ cpus_and(mask, irq_affinity[irq], map); ++ if (any_online_cpu(mask) == NR_CPUS) { ++ printk("Breaking affinity for irq %i\n", irq); ++ mask = map; ++ } ++ if (irq_desc[irq].handler->set_affinity) ++ irq_desc[irq].handler->set_affinity(irq, mask); ++ else if (irq_desc[irq].action && !(warned++)) ++ printk("Cannot set affinity for irq %i\n", irq); ++ } ++ ++#if 0 ++ barrier(); ++ /* Ingo Molnar says: "after the IO-APIC masks have been redirected ++ [note the nop - the interrupt-enable boundary on x86 is two ++ instructions from sti] - to flush out pending hardirqs and ++ IPIs. After this point nothing is supposed to reach this CPU." */ ++ __asm__ __volatile__("sti; nop; cli"); ++ barrier(); ++#else ++ /* That doesn't seem sufficient. Give it 1ms. */ ++ local_irq_enable(); ++ mdelay(1); ++ local_irq_disable(); ++#endif ++} ++#endif ++ +diff -puN arch/i386/kernel/msr.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/msr.c +--- 25/arch/i386/kernel/msr.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/msr.c 2005-02-23 02:20:06.000000000 -0800 +@@ -260,7 +260,7 @@ static struct file_operations msr_fops = + .open = msr_open, + }; + +-static int msr_class_simple_device_add(int i) ++static int __devinit msr_class_simple_device_add(int i) + { + int err = 0; + struct class_device *class_err; +diff -puN arch/i386/kernel/process.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/process.c +--- 25/arch/i386/kernel/process.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/process.c 2005-02-23 02:20:06.000000000 -0800 +@@ -13,6 +13,7 @@ + + #include + ++#include + #include + #include + #include +@@ -55,6 +56,9 @@ + #include + #include + ++#include ++#include ++ + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + + int hlt_counter; +@@ -139,6 +143,34 @@ static void poll_idle (void) + } + } + ++#ifdef CONFIG_HOTPLUG_CPU ++#include ++/* We don't actually take CPU down, just spin without interrupts. */ ++static inline void play_dead(void) ++{ ++ /* Ack it */ ++ __get_cpu_var(cpu_state) = CPU_DEAD; ++ ++ /* We shouldn't have to disable interrupts while dead, but ++ * some interrupts just don't seem to go away, and this makes ++ * it "work" for testing purposes. */ ++ /* Death loop */ ++ while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) ++ cpu_relax(); ++ ++ local_irq_disable(); ++ __flush_tlb_all(); ++ cpu_set(smp_processor_id(), cpu_online_map); ++ enable_APIC_timer(); ++ local_irq_enable(); ++} ++#else ++static inline void play_dead(void) ++{ ++ BUG(); ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ + /* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a +@@ -162,6 +194,9 @@ void cpu_idle (void) + if (!idle) + idle = default_idle; + ++ if (cpu_is_offline(cpu)) ++ play_dead(); ++ + irq_stat[cpu].idle_timestamp = jiffies; + idle(); + } +diff -puN arch/i386/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/smpboot.c +--- 25/arch/i386/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/smpboot.c 2005-02-23 02:20:06.000000000 -0800 +@@ -44,6 +44,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include + #include +@@ -89,6 +92,9 @@ extern unsigned char trampoline_end []; + static unsigned char *trampoline_base; + static int trampoline_exec; + ++/* State of each CPU. */ ++DEFINE_PER_CPU(int, cpu_state) = { 0 }; ++ + /* + * Currently trivial. Write the real->protected mode + * bootstrap into the page concerned. The caller +@@ -1095,6 +1101,9 @@ static void __init smp_boot_cpus(unsigne + who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */ + void __init smp_prepare_cpus(unsigned int max_cpus) + { ++ smp_commenced_mask = cpumask_of_cpu(0); ++ cpu_callin_map = cpumask_of_cpu(0); ++ mb(); + smp_boot_cpus(max_cpus); + } + +@@ -1104,20 +1113,99 @@ void __devinit smp_prepare_boot_cpu(void + cpu_set(smp_processor_id(), cpu_callout_map); + } + +-int __devinit __cpu_up(unsigned int cpu) ++#ifdef CONFIG_HOTPLUG_CPU ++ ++/* must be called with the cpucontrol mutex held */ ++static int __devinit cpu_enable(unsigned int cpu) + { +- /* This only works at boot for x86. See "rewrite" above. */ +- if (cpu_isset(cpu, smp_commenced_mask)) { +- local_irq_enable(); +- return -ENOSYS; ++ /* get the target out of its holding state */ ++ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; ++ wmb(); ++ ++ /* wait for the processor to ack it. timeout? */ ++ while (!cpu_online(cpu)) ++ cpu_relax(); ++ ++ fixup_irqs(cpu_online_map); ++ /* counter the disable in fixup_irqs() */ ++ local_irq_enable(); ++ return 0; ++} ++ ++int __cpu_disable(void) ++{ ++ cpumask_t map = cpu_online_map; ++ int cpu = smp_processor_id(); ++ ++ /* ++ * Perhaps use cpufreq to drop frequency, but that could go ++ * into generic code. ++ * ++ * We won't take down the boot processor on i386 due to some ++ * interrupts only being able to be serviced by the BSP. ++ * Especially so if we're not using an IOAPIC -zwane ++ */ ++ if (cpu == 0) ++ return -EBUSY; ++ ++ /* We enable the timer again on the exit path of the death loop */ ++ disable_APIC_timer(); ++ /* Allow any queued timer interrupts to get serviced */ ++ local_irq_enable(); ++ mdelay(1); ++ local_irq_disable(); ++ ++ cpu_clear(cpu, map); ++ fixup_irqs(map); ++ /* It's now safe to remove this processor from the online map */ ++ cpu_clear(cpu, cpu_online_map); ++ return 0; ++} ++ ++void __cpu_die(unsigned int cpu) ++{ ++ /* We don't do anything here: idle task is faking death itself. */ ++ unsigned int i; ++ ++ for (i = 0; i < 10; i++) { ++ /* They ack this in play_dead by setting CPU_DEAD */ ++ if (per_cpu(cpu_state, cpu) == CPU_DEAD) ++ return; ++ current->state = TASK_UNINTERRUPTIBLE; ++ schedule_timeout(HZ/10); + } ++ printk(KERN_ERR "CPU %u didn't die...\n", cpu); ++} ++#else /* ... !CONFIG_HOTPLUG_CPU */ ++int __cpu_disable(void) ++{ ++ return -ENOSYS; ++} + ++void __cpu_die(unsigned int cpu) ++{ ++ /* We said "no" in __cpu_disable */ ++ BUG(); ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++int __devinit __cpu_up(unsigned int cpu) ++{ + /* In case one didn't come up */ + if (!cpu_isset(cpu, cpu_callin_map)) { ++ printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu); + local_irq_enable(); + return -EIO; + } + ++#ifdef CONFIG_HOTPLUG_CPU ++ /* Already up, and in cpu_quiescent now? */ ++ if (cpu_isset(cpu, smp_commenced_mask)) { ++ cpu_enable(cpu); ++ return 0; ++ } ++#endif ++ + local_irq_enable(); + /* Unleash the CPU! */ + cpu_set(cpu, smp_commenced_mask); +diff -puN arch/i386/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/smp.c +--- 25/arch/i386/kernel/smp.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/smp.c 2005-02-23 02:20:06.000000000 -0800 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -163,7 +164,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu + unsigned long flags; + + local_irq_save(flags); +- ++ WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); + /* + * Wait for idle. + */ +@@ -345,21 +346,21 @@ out: + static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, + unsigned long va) + { +- cpumask_t tmp; + /* + * A couple of (to be removed) sanity checks: + * +- * - we do not send IPIs to not-yet booted CPUs. + * - current CPU must not be in mask + * - mask must exist :) + */ + BUG_ON(cpus_empty(cpumask)); +- +- cpus_and(tmp, cpumask, cpu_online_map); +- BUG_ON(!cpus_equal(cpumask, tmp)); + BUG_ON(cpu_isset(smp_processor_id(), cpumask)); + BUG_ON(!mm); + ++ /* If a CPU which we ran on has gone down, OK. */ ++ cpus_and(cpumask, cpumask, cpu_online_map); ++ if (cpus_empty(cpumask)) ++ return; ++ + /* + * i'm not happy about this global shared spinlock in the + * MM hot path, but we'll see how contended it is. +@@ -484,6 +485,7 @@ void smp_send_nmi_allbutself(void) + */ + void smp_send_reschedule(int cpu) + { ++ WARN_ON(cpu_is_offline(cpu)); + send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); + } + +@@ -524,10 +526,16 @@ int smp_call_function (void (*func) (voi + */ + { + struct call_data_struct data; +- int cpus = num_online_cpus()-1; ++ int cpus; + +- if (!cpus) ++ /* Holding any lock stops cpus from going down. */ ++ spin_lock(&call_lock); ++ cpus = num_online_cpus()-1; ++ ++ if (!cpus) { ++ spin_unlock(&call_lock); + return 0; ++ } + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); +@@ -539,7 +547,6 @@ int smp_call_function (void (*func) (voi + if (wait) + atomic_set(&data.finished, 0); + +- spin_lock(&call_lock); + call_data = &data; + mb(); + +diff -puN arch/i386/kernel/traps.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/traps.c +--- 25/arch/i386/kernel/traps.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/traps.c 2005-02-23 02:20:06.000000000 -0800 +@@ -669,6 +669,14 @@ fastcall void do_nmi(struct pt_regs * re + nmi_enter(); + + cpu = smp_processor_id(); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ if (!cpu_online(cpu)) { ++ nmi_exit(); ++ return; ++ } ++#endif ++ + ++nmi_count(cpu); + + if (!nmi_callback(regs, cpu)) +diff -puN arch/ia64/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm arch/ia64/kernel/smpboot.c +--- 25/arch/ia64/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/ia64/kernel/smpboot.c 2005-02-23 02:20:06.000000000 -0800 +@@ -590,9 +590,10 @@ int __cpu_disable(void) + if (cpu == 0) + return -EBUSY; + ++ cpu_clear(cpu, cpu_online_map); + fixup_irqs(); + local_flush_tlb_all(); +- printk ("Disabled cpu %u\n", smp_processor_id()); ++ printk("Disabled cpu %u\n", cpu); + return 0; + } + +diff -puN arch/ppc64/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/ppc64/kernel/smp.c +diff -puN arch/s390/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/s390/kernel/smp.c +--- 25/arch/s390/kernel/smp.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/s390/kernel/smp.c 2005-02-23 02:20:06.000000000 -0800 +@@ -679,12 +679,14 @@ __cpu_disable(void) + { + unsigned long flags; + ec_creg_mask_parms cr_parms; ++ int cpu = smp_processor_id(); + + spin_lock_irqsave(&smp_reserve_lock, flags); +- if (smp_cpu_reserved[smp_processor_id()] != 0) { ++ if (smp_cpu_reserved[cpu] != 0) { + spin_unlock_irqrestore(&smp_reserve_lock, flags); + return -EBUSY; + } ++ cpu_clear(cpu, cpu_online_map); + + #ifdef CONFIG_PFAULT + /* Disable pfault pseudo page faults on this cpu. */ +diff -puN include/asm-i386/cpu.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/cpu.h +--- 25/include/asm-i386/cpu.h~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/include/asm-i386/cpu.h 2005-02-23 02:20:06.000000000 -0800 +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include + +@@ -17,4 +18,5 @@ extern int arch_register_cpu(int num); + extern void arch_unregister_cpu(int); + #endif + ++DECLARE_PER_CPU(int, cpu_state); + #endif /* _ASM_I386_CPU_H_ */ +diff -puN include/asm-i386/irq.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/irq.h +--- 25/include/asm-i386/irq.h~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/include/asm-i386/irq.h 2005-02-23 02:20:06.000000000 -0800 +@@ -38,4 +38,8 @@ extern void release_vm86_irqs(struct tas + extern int irqbalance_disable(char *str); + #endif + ++#ifdef CONFIG_HOTPLUG_CPU ++extern void fixup_irqs(cpumask_t map); ++#endif ++ + #endif /* _ASM_IRQ_H */ +diff -puN include/asm-i386/smp.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/smp.h +--- 25/include/asm-i386/smp.h~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/include/asm-i386/smp.h 2005-02-23 02:20:06.000000000 -0800 +@@ -85,6 +85,9 @@ static __inline int logical_smp_processo + } + + #endif ++ ++extern int __cpu_disable(void); ++extern void __cpu_die(unsigned int cpu); + #endif /* !__ASSEMBLY__ */ + + #define NO_PROC_ID 0xFF /* No processor magic marker */ +diff -puN kernel/cpu.c~i386-cpu-hotplug-updated-for-mm kernel/cpu.c +--- 25/kernel/cpu.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/kernel/cpu.c 2005-02-23 02:20:06.000000000 -0800 +@@ -63,19 +63,15 @@ static int take_cpu_down(void *unused) + { + int err; + +- /* Take offline: makes arch_cpu_down somewhat easier. */ +- cpu_clear(smp_processor_id(), cpu_online_map); +- + /* Ensure this CPU doesn't handle any more interrupts. */ + err = __cpu_disable(); + if (err < 0) +- cpu_set(smp_processor_id(), cpu_online_map); +- else +- /* Force idle task to run as soon as we yield: it should +- immediately notice cpu is offline and die quickly. */ +- sched_idle_next(); ++ return err; + +- return err; ++ /* Force idle task to run as soon as we yield: it should ++ immediately notice cpu is offline and die quickly. */ ++ sched_idle_next(); ++ return 0; + } + + int cpu_down(unsigned int cpu) +diff -puN arch/ppc64/kernel/pSeries_smp.c~i386-cpu-hotplug-updated-for-mm arch/ppc64/kernel/pSeries_smp.c +--- 25/arch/ppc64/kernel/pSeries_smp.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:08.000000000 -0800 ++++ 25-akpm/arch/ppc64/kernel/pSeries_smp.c 2005-02-23 02:20:08.000000000 -0800 +@@ -86,10 +86,13 @@ static int query_cpu_stopped(unsigned in + + int pSeries_cpu_disable(void) + { ++ int cpu = smp_processor_id(); ++ ++ cpu_clear(cpu, cpu_online_map); + systemcfg->processorCount--; + + /*fix boot_cpuid here*/ +- if (smp_processor_id() == boot_cpuid) ++ if (cpu == boot_cpuid) + boot_cpuid = any_online_cpu(cpu_online_map); + + /* FIXME: abstract this to not be platform specific later on */ +_ diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c index 0e35f30294..e2c72f8798 100644 --- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c +++ b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c @@ -338,7 +338,9 @@ regsets_store_inferior_registers () } else { +#ifdef DEBUG perror ("Warning: ptrace(regsets_store_inferior_registers)"); +#endif } } regset ++; @@ -364,7 +366,6 @@ linux_fetch_registers (int regno) void linux_store_registers (int regno) { - printf("store %d\n", regno); if (use_regsets_p) { if (regsets_store_inferior_registers () == 0) diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index e458444bb0..041bf44423 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -16,6 +16,7 @@ vpath %c $(XEN_LIBXUTIL) INCLUDES += -I $(XEN_LIBXUTIL) SRCS := +SRCS += xc_sedf.c SRCS += xc_bvtsched.c SRCS += xc_core.c SRCS += xc_domain.c diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index d9c4414e30..dd7a712ad6 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -296,6 +296,14 @@ int xc_bvtsched_domain_get(int xc_handle, long long *warpl, long long *warpu); +int xc_sedf_domain_set(int xc_handle, + u32 domid, + u64 period, u64 slice, u64 latency, u16 extratime, u16 weight); + +int xc_sedf_domain_get(int xc_handle, + u32 domid, + u64* period, u64 *slice, u64 *latency, u16 *extratime, u16* weight); + typedef evtchn_status_t xc_evtchn_status_t; /* diff --git a/tools/libxc/xc_sedf.c b/tools/libxc/xc_sedf.c new file mode 100644 index 0000000000..a3a0598a7d --- /dev/null +++ b/tools/libxc/xc_sedf.c @@ -0,0 +1,51 @@ +/****************************************************************************** + * xc_sedf.c + * + * API for manipulating parameters of the Simple EDF scheduler. + * + * changes by Stephan Diestelhorst + * based on code + * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge. + */ + +#include "xc_private.h" + +int xc_sedf_domain_set(int xc_handle, + u32 domid, u64 period, u64 slice,u64 latency, u16 extratime,u16 weight) +{ + dom0_op_t op; + struct sedf_adjdom *p = &op.u.adjustdom.u.sedf; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_SEDF; + op.u.adjustdom.direction = SCHED_INFO_PUT; + + p->period = period; + p->slice = slice; + p->latency = latency; + p->extratime = extratime; + p->weight = weight; + return do_dom0_op(xc_handle, &op); +} + +int xc_sedf_domain_get(int xc_handle, u32 domid, u64 *period, u64 *slice, u64* latency, u16* extratime, u16* weight) +{ + dom0_op_t op; + int ret; + struct sedf_adjdom *p = &op.u.adjustdom.u.sedf; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_SEDF; + op.u.adjustdom.direction = SCHED_INFO_GET; + + ret = do_dom0_op(xc_handle, &op); + + *period = p->period; + *slice = p->slice; + *latency = p->latency; + *extratime = p->extratime; + *weight = p->weight; + return ret; +} diff --git a/tools/libxutil/sxpr_parser.h b/tools/libxutil/sxpr_parser.h index 0736fd3d40..0a3fde55fd 100644 --- a/tools/libxutil/sxpr_parser.h +++ b/tools/libxutil/sxpr_parser.h @@ -28,7 +28,7 @@ /** Size of a parser input buffer. * Tokens read must fit into this size (including trailing null). */ -#define PARSER_BUF_SIZE 1024 +#define PARSER_BUF_SIZE 4096 struct Parser; typedef int ParserStateFn(struct Parser *, char c); diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 5b76a20f43..faa6e06d62 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -827,6 +827,52 @@ static PyObject *pyxc_physinfo(PyObject *self, "cpu_khz", info.cpu_khz); } +static PyObject *pyxc_sedf_domain_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice, latency; + u16 extratime, weight; + static char *kwd_list[] = { "dom", "period", "slice", "latency", "extratime", "weight",NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLhh", kwd_list, &domid, + &period, &slice, &latency, &extratime, &weight) ) + return NULL; + if ( xc_sedf_domain_set(xc->xc_handle, domid, period, slice, latency, extratime,weight) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_sedf_domain_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice,latency; + u16 weight, extratime; + + static char *kwd_list[] = { "dom", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) + return NULL; + + if ( xc_sedf_domain_get( xc->xc_handle, domid, &period, + &slice,&latency,&extratime,&weight) ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}", + "domain", domid, + "period", period, + "slice", slice, + "latency", latency, + "extratime", extratime); +} + static PyObject *pyxc_shadow_control(PyObject *self, PyObject *args, PyObject *kwds) @@ -1027,6 +1073,30 @@ static PyMethodDef pyxc_methods[] = { " warpu [long]: Unwarp requirement.\n" " warpl [long]: Warp limit,\n" }, + + { "sedf_domain_set", + (PyCFunction)pyxc_sedf_domain_set, + METH_KEYWORDS, "\n" + "Set the scheduling parameters for a domain when running with Atropos.\n" + " dom [int]: domain to set\n" + " period [long]: domain's scheduling period\n" + " slice [long]: domain's slice per period\n" + " latency [long]: domain's wakeup latency hint\n" + " extratime [int]: domain aware of extratime?\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "sedf_domain_get", + (PyCFunction)pyxc_sedf_domain_get, + METH_KEYWORDS, "\n" + "Get the current scheduling parameters for a domain when running with\n" + "the Atropos scheduler." + " dom [int]: domain to query\n" + "Returns: [dict]\n" + " domain [int]: domain ID\n" + " period [long]: scheduler period\n" + " slice [long]: CPU reservation per period\n" + " latency [long]: domain's wakeup latency hint\n" + " extratime [int]: domain aware of extratime?\n"}, { "evtchn_alloc_unbound", (PyCFunction)pyxc_evtchn_alloc_unbound, diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 6b29f21e7b..0be643a47f 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -250,6 +250,15 @@ class Xend: 'warpl' : warpl, 'warpu' : warpu }) + def xend_domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): + return self.xendPost(self.domainurl(id), + {'op' : 'cpu_sedf_set', + 'period' : period, + 'slice' : slice, + 'latency' : latency, + 'extratime' : extratime, + 'weight' : weight }) + def xend_domain_maxmem_set(self, id, memory): return self.xendPost(self.domainurl(id), { 'op' : 'maxmem_set', diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index fbb21c9e63..7c503f0c50 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -707,6 +707,24 @@ class XendDomain: except Exception, ex: raise XendError(str(ex)) + + def domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): + """Set Simple EDF scheduler parameters for a domain. + """ + dominfo = self.domain_lookup(id) + try: + return xc.sedf_domain_set(dominfo.dom, period, slice, latency, extratime, weight) + except Exception, ex: + raise XendError(str(ex)) + + def domain_cpu_sedf_get(self, id): + """Get Atropos scheduler parameters for a domain. + """ + dominfo = self.domain_lookup(id) + try: + return xc.sedf_domain_get(dominfo.dom) + except Exception, ex: + raise XendError(str(ex)) def domain_device_create(self, id, devconfig): """Create a new device for a domain. diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 80fbd97703..b58b0dd947 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -103,6 +103,18 @@ class SrvDomain(SrvDir): val = fn(req.args, {'dom': self.dom.id}) return val + + def op_cpu_sedf_set(self, op, req): + fn = FormFn(self.xd.domain_cpu_sedf_set, + [['dom', 'str'], + ['period', 'int'], + ['slice', 'int'], + ['latency', 'int'], + ['extratime', 'int'], + ['weight', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val + def op_maxmem_set(self, op, req): fn = FormFn(self.xd.domain_maxmem_set, [['dom', 'str'], diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index e1494bc3a1..76873778fd 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -591,6 +591,23 @@ class ProgBvtslice(Prog): xm.prog(ProgBvtslice) +class ProgSedf(Prog): + group = 'scheduler' + name= "sedf" + info = """Set simple EDF parameters.""" + + def help(self, args): + print args[0], "DOM PERIOD SLICE LATENCY EXTRATIME WEIGHT" + print "\nSet simple EDF parameters." + + def main(self, args): + if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0]) + dom = args[1] + v = map(int, args[2:7]) + server.xend_domain_cpu_sedf_set(dom, *v) + +xm.prog(ProgSedf) + class ProgInfo(Prog): group = 'host' name = "info" diff --git a/xen/Rules.mk b/xen/Rules.mk index 1fb12e8479..1db12a3d0d 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -2,6 +2,7 @@ verbose ?= n debug ?= n perfc ?= n +perfc_arrays?= n trace ?= n optimize ?= y domu_debug ?= n @@ -54,6 +55,9 @@ endif ifeq ($(perfc),y) CFLAGS += -DPERF_COUNTERS +ifeq ($(perfc_arrays),y) +CFLAGS += -DPERF_ARRAYS +endif endif ifeq ($(trace),y) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index 73f2500f81..4326ea0078 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -8,6 +8,7 @@ #include #include #include +#include #define task_struct exec_domain @@ -37,6 +38,9 @@ void foo(void) BLANK(); + DEFINE(XSI_PSR_IC_OFS, offsetof(vcpu_info_t, arch.interrupt_collection_enabled)); + DEFINE(XSI_PSR_IC, (SHAREDINFO_ADDR+offsetof(vcpu_info_t, arch.interrupt_collection_enabled))); + DEFINE(XSI_PSR_I_OFS, offsetof(vcpu_info_t, arch.interrupt_delivery_enabled)); //DEFINE(IA64_TASK_BLOCKED_OFFSET,offsetof (struct task_struct, blocked)); //DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); //DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); @@ -46,8 +50,8 @@ void foo(void) //DEFINE(IA64_TASK_SIGHAND_OFFSET,offsetof (struct task_struct, sighand)); //DEFINE(IA64_TASK_SIGNAL_OFFSET,offsetof (struct task_struct, signal)); //DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid)); - DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct task_struct, thread.ksp)); - DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct task_struct, thread.on_ustack)); + DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct exec_domain, arch._thread.ksp)); + DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct exec_domain, arch._thread.on_ustack)); BLANK(); diff --git a/xen/arch/ia64/domain.c b/xen/arch/ia64/domain.c index 9f0d9d20ba..eb342e7021 100644 --- a/xen/arch/ia64/domain.c +++ b/xen/arch/ia64/domain.c @@ -191,7 +191,7 @@ void arch_do_createdomain(struct exec_domain *ed) // stay on kernel stack because may get interrupts! // ia64_ret_from_clone (which b0 gets in new_thread) switches // to user stack - ed->thread.on_ustack = 0; + ed->arch._thread.on_ustack = 0; } void arch_do_boot_vcpu(struct exec_domain *p) @@ -261,7 +261,7 @@ void new_thread(struct exec_domain *ed, printf("new_thread: ed=%p, start_pc=%p, regs=%p, sw=%p, new_rbs=%p, IA64_STK_OFFSET=%p, &r8=%p\n", ed,start_pc,regs,sw,new_rbs,IA64_STK_OFFSET,®s->r8); sw->b0 = (unsigned long) &ia64_ret_from_clone; - ed->thread.ksp = (unsigned long) sw - 16; + ed->arch._thread.ksp = (unsigned long) sw - 16; //ed->thread_info->flags = 0; printk("new_thread, about to call init_all_rr\n"); init_all_rr(ed); @@ -626,7 +626,7 @@ int construct_dom0(struct domain *d, #ifndef CLONE_DOMAIN0 if ( d != dom0 ) BUG(); - if ( test_bit(DF_CONSTRUCTED, &d->d_flags) ) + if ( test_bit(DF_CONSTRUCTED, &d->flags) ) BUG(); #endif @@ -753,7 +753,7 @@ int construct_dom0(struct domain *d, #endif console_endboot(strstr(cmdline, "tty0") != NULL); - set_bit(DF_CONSTRUCTED, &d->d_flags); + set_bit(DF_CONSTRUCTED, &d->flags); new_thread(ed, pkern_entry, 0, 0); // FIXME: Hack for keyboard input @@ -783,7 +783,7 @@ int construct_domU(struct domain *d, unsigned long pkern_entry; #ifndef DOMU_AUTO_RESTART - if ( test_bit(DF_CONSTRUCTED, &d->d_flags) ) BUG(); + if ( test_bit(DF_CONSTRUCTED, &d->flags) ) BUG(); #endif printk("*** LOADING DOMAIN %d ***\n",d->id); @@ -816,7 +816,7 @@ int construct_domU(struct domain *d, loaddomainelfimage(d,image_start); printk("loaddomainelfimage returns\n"); - set_bit(DF_CONSTRUCTED, &d->d_flags); + set_bit(DF_CONSTRUCTED, &d->flags); printk("calling new_thread, entry=%p\n",pkern_entry); #ifdef DOMU_AUTO_RESTART diff --git a/xen/arch/ia64/idle0_task.c b/xen/arch/ia64/idle0_task.c index b7523ea502..4bc636ae6e 100644 --- a/xen/arch/ia64/idle0_task.c +++ b/xen/arch/ia64/idle0_task.c @@ -22,7 +22,7 @@ #define IDLE0_DOMAIN(_t) \ { \ id: IDLE_DOMAIN_ID, \ - d_flags: 1<handler->startup(irq); /* Attempt to bind the interrupt target to the correct CPU. */ +#if 0 /* FIXME CONFIG_SMP ??? */ if ( desc->handler->set_affinity != NULL ) desc->handler->set_affinity( irq, apicid_to_phys_cpu_present(d->processor)); +#endif } else if ( !will_share || !action->shareable ) { diff --git a/xen/arch/ia64/ivt.S b/xen/arch/ia64/ivt.S index f68e78a834..a44f5eb8a9 100644 --- a/xen/arch/ia64/ivt.S +++ b/xen/arch/ia64/ivt.S @@ -778,10 +778,22 @@ ENTRY(break_fault) mov r17=cr.iim mov r31=pr ;; + movl r18=XSI_PSR_IC + ;; + ld8 r19=[r18] + ;; cmp.eq p7,p0=r0,r17 // is this a psuedo-cover? - // FIXME: may also need to check slot==2? (p7) br.sptk.many dispatch_privop_fault + ;; + cmp.ne p7,p0=r0,r19 +(p7) br.sptk.many dispatch_break_fault + // If we get to here, we have a hyperprivop + // For now, hyperprivops are handled through the break mechanism + // Later, they will be fast hand-coded assembly with psr.ic off + // which means no calls, no use of r1-r15 and no memory accesses + // except to pinned addresses! br.sptk.many dispatch_break_fault + ;; #endif mov r16=IA64_KR(CURRENT) // r16 = current task; 12 cycle read lat. mov r17=cr.iim diff --git a/xen/arch/ia64/mm_init.c b/xen/arch/ia64/mm_init.c index d316e05357..0e3ce45dec 100644 --- a/xen/arch/ia64/mm_init.c +++ b/xen/arch/ia64/mm_init.c @@ -227,7 +227,7 @@ ia64_set_rbs_bot (void) if (stack_size > MAX_USER_STACK_SIZE) stack_size = MAX_USER_STACK_SIZE; - current->thread.rbs_bot = STACK_TOP - stack_size; + current->arch._thread.rbs_bot = STACK_TOP - stack_size; } /* @@ -255,7 +255,7 @@ printf("ia64_init_addr_space: called, not implemented\n"); if (vma) { memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; - vma->vm_start = current->thread.rbs_bot & PAGE_MASK; + vma->vm_start = current->arch._thread.rbs_bot & PAGE_MASK; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; diff --git a/xen/arch/ia64/patch/linux-2.6.11/unaligned.c b/xen/arch/ia64/patch/linux-2.6.11/unaligned.c index bcc165e95e..0ed114e064 100644 --- a/xen/arch/ia64/patch/linux-2.6.11/unaligned.c +++ b/xen/arch/ia64/patch/linux-2.6.11/unaligned.c @@ -1,5 +1,5 @@ --- ../../linux-2.6.11/arch/ia64/kernel/unaligned.c 2005-03-02 00:38:25.000000000 -0700 -+++ arch/ia64/unaligned.c 2005-04-28 15:40:13.000000000 -0600 ++++ arch/ia64/unaligned.c 2005-05-10 15:46:09.000000000 -0600 @@ -437,7 +437,11 @@ } @@ -12,7 +12,31 @@ setreg (unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *) regs - 1; -@@ -611,7 +615,11 @@ +@@ -522,7 +526,11 @@ + */ + if (regnum >= IA64_FIRST_ROTATING_FR) { + ia64_sync_fph(current); ++#ifdef XEN ++ current->arch._thread.fph[fph_index(regs, regnum)] = *fpval; ++#else + current->thread.fph[fph_index(regs, regnum)] = *fpval; ++#endif + } else { + /* + * pt_regs or switch_stack ? +@@ -581,7 +589,11 @@ + */ + if (regnum >= IA64_FIRST_ROTATING_FR) { + ia64_flush_fph(current); ++#ifdef XEN ++ *fpval = current->arch._thread.fph[fph_index(regs, regnum)]; ++#else + *fpval = current->thread.fph[fph_index(regs, regnum)]; ++#endif + } else { + /* + * f0 = 0.0, f1= 1.0. Those registers are constant and are thus +@@ -611,7 +623,11 @@ } @@ -24,7 +48,7 @@ getreg (unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *) regs - 1; -@@ -1294,6 +1302,9 @@ +@@ -1294,6 +1310,9 @@ void ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) { @@ -34,7 +58,7 @@ struct ia64_psr *ipsr = ia64_psr(regs); mm_segment_t old_fs = get_fs(); unsigned long bundle[2]; -@@ -1502,4 +1513,5 @@ +@@ -1502,4 +1521,5 @@ si.si_imm = 0; force_sig_info(SIGBUS, &si, current); goto done; diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c index 0b59b60ad8..aec763f80d 100644 --- a/xen/arch/ia64/privop.c +++ b/xen/arch/ia64/privop.c @@ -205,7 +205,8 @@ IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst) return(IA64_ILLOP_FAULT); if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M41.r2); + if (!inst.inst) pte = vcpu_get_tmp(vcpu,0); + else pte = vcpu_get_gr(vcpu,inst.M41.r2); return (vcpu_itc_d(vcpu,pte,itir,ifa)); } @@ -219,7 +220,8 @@ IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst) return(IA64_ILLOP_FAULT); if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M41.r2); + if (!inst.inst) pte = vcpu_get_tmp(vcpu,0); + else pte = vcpu_get_gr(vcpu,inst.M41.r2); return (vcpu_itc_i(vcpu,pte,itir,ifa)); } @@ -417,10 +419,17 @@ IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst) UINT64 val; IA64FAULT fault; - fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); - if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1, val); - else return fault; + if (inst.M43.r1 > 63) { // privified mov from pmd + fault = vcpu_get_pmd(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1-64, val); + } + else { + fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1, val); + } + return fault; } unsigned long from_cr_cnt[128] = { 0 }; @@ -531,6 +540,8 @@ struct { unsigned long bsw0; unsigned long bsw1; unsigned long cover; + unsigned long fc; + unsigned long cpuid; unsigned long Mpriv_cnt[64]; } privcnt = { 0 }; @@ -631,7 +642,11 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) else x6 = 0x1a; } } - privcnt.Mpriv_cnt[x6]++; + if (x6 == 52 && inst.M28.r3 > 63) + privcnt.fc++; + else if (x6 == 16 && inst.M43.r3 > 63) + privcnt.cpuid++; + else privcnt.Mpriv_cnt[x6]++; return (*pfunc)(vcpu,inst); break; case B: @@ -682,7 +697,7 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) //printf("We who are about do die salute you\n"); printf("handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d)\n", iip, (UINT64)inst.inst, slot, slot_type); - //printf("vtop(0x%lx)==0x%lx\r\n", iip, tr_vtop(iip)); + //printf("vtop(0x%lx)==0x%lx\n", iip, tr_vtop(iip)); //thread_mozambique("privop fault\n"); return (IA64_ILLOP_FAULT); } @@ -745,6 +760,64 @@ priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr) } +// FIXME: Move these to include/public/arch-ia64? +#define HYPERPRIVOP_RFI 0x1 +#define HYPERPRIVOP_RSM_DT 0x2 +#define HYPERPRIVOP_SSM_DT 0x3 +#define HYPERPRIVOP_COVER 0x4 +#define HYPERPRIVOP_ITC_D 0x5 +#define HYPERPRIVOP_ITC_I 0x6 +#define HYPERPRIVOP_MAX 0x6 + +char *hyperpriv_str[HYPERPRIVOP_MAX+1] = { + 0, "rfi", "rsm.dt", "ssm.dt", "cover", "itc.d", "itc.i", + 0 +}; + +unsigned long hyperpriv_cnt[HYPERPRIVOP_MAX+1] = { 0 }; + +/* hyperprivops are generally executed in assembly (with physical psr.ic off) + * so this code is primarily used for debugging them */ +int +ia64_hyperprivop(unsigned long iim, REGS *regs) +{ + struct exec_domain *ed = (struct domain *) current; + INST64 inst; + UINT64 val; + +// FIXME: Add instrumentation for these +// FIXME: Handle faults appropriately for these + if (!iim || iim > HYPERPRIVOP_MAX) { + printf("bad hyperprivop; ignored\n"); + return 1; + } + hyperpriv_cnt[iim]++; + switch(iim) { + case HYPERPRIVOP_RFI: + (void)vcpu_rfi(ed); + return 0; // don't update iip + case HYPERPRIVOP_RSM_DT: + (void)vcpu_reset_psr_dt(ed); + return 1; + case HYPERPRIVOP_SSM_DT: + (void)vcpu_set_psr_dt(ed); + return 1; + case HYPERPRIVOP_COVER: + (void)vcpu_cover(ed); + return 1; + case HYPERPRIVOP_ITC_D: + inst.inst = 0; + (void)priv_itc_d(ed,inst); + return 1; + case HYPERPRIVOP_ITC_I: + inst.inst = 0; + (void)priv_itc_i(ed,inst); + return 1; + } + return 0; +} + + /************************************************************************** Privileged operation instrumentation routines **************************************************************************/ @@ -798,55 +871,61 @@ int dump_privop_counts(char *buf) sum += privcnt.rfi; sum += privcnt.bsw0; sum += privcnt.bsw1; sum += privcnt.cover; for (i=0; i < 64; i++) sum += privcnt.Mpriv_cnt[i]; - s += sprintf(s,"Privop statistics: (Total privops: %ld)\r\n",sum); + s += sprintf(s,"Privop statistics: (Total privops: %ld)\n",sum); if (privcnt.mov_to_ar_imm) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.mov_to_ar_imm, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_imm, "mov_to_ar_imm", (privcnt.mov_to_ar_imm*100L)/sum); if (privcnt.mov_to_ar_reg) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.mov_to_ar_reg, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_reg, "mov_to_ar_reg", (privcnt.mov_to_ar_reg*100L)/sum); if (privcnt.mov_from_ar) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.mov_from_ar, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_from_ar, "privified-mov_from_ar", (privcnt.mov_from_ar*100L)/sum); if (privcnt.ssm) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.ssm, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.ssm, "ssm", (privcnt.ssm*100L)/sum); if (privcnt.rsm) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.rsm, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rsm, "rsm", (privcnt.rsm*100L)/sum); if (privcnt.rfi) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.rfi, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rfi, "rfi", (privcnt.rfi*100L)/sum); if (privcnt.bsw0) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.bsw0, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw0, "bsw0", (privcnt.bsw0*100L)/sum); if (privcnt.bsw1) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.bsw1, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw1, "bsw1", (privcnt.bsw1*100L)/sum); if (privcnt.cover) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.cover, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cover, "cover", (privcnt.cover*100L)/sum); + if (privcnt.fc) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.fc, + "privified-fc", (privcnt.fc*100L)/sum); + if (privcnt.cpuid) + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cpuid, + "privified-getcpuid", (privcnt.cpuid*100L)/sum); for (i=0; i < 64; i++) if (privcnt.Mpriv_cnt[i]) { - if (!Mpriv_str[i]) s += sprintf(s,"PRIVSTRING NULL!!\r\n"); - else s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.Mpriv_cnt[i], + if (!Mpriv_str[i]) s += sprintf(s,"PRIVSTRING NULL!!\n"); + else s += sprintf(s,"%10d %s [%d%%]\n", privcnt.Mpriv_cnt[i], Mpriv_str[i], (privcnt.Mpriv_cnt[i]*100L)/sum); if (i == 0x24) { // mov from CR s += sprintf(s," ["); for (j=0; j < 128; j++) if (from_cr_cnt[j]) { if (!cr_str[j]) - s += sprintf(s,"PRIVSTRING NULL!!\r\n"); + s += sprintf(s,"PRIVSTRING NULL!!\n"); s += sprintf(s,"%s(%d),",cr_str[j],from_cr_cnt[j]); } - s += sprintf(s,"]\r\n"); + s += sprintf(s,"]\n"); } else if (i == 0x2c) { // mov to CR s += sprintf(s," ["); for (j=0; j < 128; j++) if (to_cr_cnt[j]) { if (!cr_str[j]) - s += sprintf(s,"PRIVSTRING NULL!!\r\n"); + s += sprintf(s,"PRIVSTRING NULL!!\n"); s += sprintf(s,"%s(%d),",cr_str[j],to_cr_cnt[j]); } - s += sprintf(s,"]\r\n"); + s += sprintf(s,"]\n"); } } return s - buf; @@ -864,19 +943,88 @@ int zero_privop_counts(char *buf) privcnt.ssm = 0; privcnt.rsm = 0; privcnt.rfi = 0; privcnt.bsw0 = 0; privcnt.bsw1 = 0; privcnt.cover = 0; + privcnt.fc = 0; privcnt.cpuid = 0; for (i=0; i < 64; i++) privcnt.Mpriv_cnt[i] = 0; for (j=0; j < 128; j++) from_cr_cnt[j] = 0; for (j=0; j < 128; j++) to_cr_cnt[j] = 0; - s += sprintf(s,"All privop statistics zeroed\r\n"); + s += sprintf(s,"All privop statistics zeroed\n"); return s - buf; } +#ifdef PRIVOP_ADDR_COUNT + +extern struct privop_addr_count privop_addr_counter[]; + +void privop_count_addr(unsigned long iip, int inst) +{ + struct privop_addr_count *v = &privop_addr_counter[inst]; + int i; + + for (i = 0; i < PRIVOP_COUNT_NADDRS; i++) { + if (!v->addr[i]) { v->addr[i] = iip; v->count[i]++; return; } + else if (v->addr[i] == iip) { v->count[i]++; return; } + } + v->overflow++;; +} + +int dump_privop_addrs(char *buf) +{ + int i,j; + char *s = buf; + s += sprintf(s,"Privop addresses:\n"); + for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { + struct privop_addr_count *v = &privop_addr_counter[i]; + s += sprintf(s,"%s:\n",v->instname); + for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) { + if (!v->addr[j]) break; + s += sprintf(s," @%p #%ld\n",v->addr[j],v->count[j]); + } + if (v->overflow) + s += sprintf(s," other #%ld\n",v->overflow); + } + return s - buf; +} + +void zero_privop_addrs(void) +{ + int i,j; + for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { + struct privop_addr_count *v = &privop_addr_counter[i]; + for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) + v->addr[j] = v->count[j] = 0; + v->overflow = 0; + } +} +#endif + +int dump_hyperprivop_counts(char *buf) +{ + int i; + char *s = buf; + s += sprintf(s,"Hyperprivops:\n"); + for (i = 1; i <= HYPERPRIVOP_MAX; i++) + if (hyperpriv_cnt[i]) + s += sprintf(s,"%10d %s\n", + hyperpriv_cnt[i], hyperpriv_str[i]); + return s - buf; +} + +void zero_hyperprivop_counts(void) +{ + int i; + for (i = 0; i <= HYPERPRIVOP_MAX; i++) hyperpriv_cnt[i] = 0; +} + #define TMPBUFLEN 8*1024 int dump_privop_counts_to_user(char __user *ubuf, int len) { char buf[TMPBUFLEN]; int n = dump_privop_counts(buf); + n += dump_hyperprivop_counts(buf + n); +#ifdef PRIVOP_ADDR_COUNT + n += dump_privop_addrs(buf + n); +#endif if (len < TMPBUFLEN) return -1; if (__copy_to_user(ubuf,buf,n)) return -1; return n; @@ -887,6 +1035,10 @@ int zero_privop_counts_to_user(char __user *ubuf, int len) char buf[TMPBUFLEN]; int n = zero_privop_counts(buf); + zero_hyperprivop_counts(); +#ifdef PRIVOP_ADDR_COUNT + zero_privop_addrs(); +#endif if (len < TMPBUFLEN) return -1; if (__copy_to_user(ubuf,buf,n)) return -1; return n; diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c index 221812123d..dd9e58071f 100644 --- a/xen/arch/ia64/process.c +++ b/xen/arch/ia64/process.c @@ -51,6 +51,7 @@ extern unsigned long dom0_start, dom0_size; IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA) #define PSCB(x,y) x->vcpu_info->arch.y +#define PSCBX(x,y) x->arch.y extern unsigned long vcpu_verbose; @@ -154,7 +155,7 @@ panic_domain(regs,"psr.ic off, delivering fault=%lx,iip=%p,ifa=%p,isr=%p,PSCB.ii } //printf("Delivering NESTED DATA TLB fault\n"); vector = IA64_DATA_NESTED_TLB_VECTOR; - regs->cr_iip = ((unsigned long) PSCB(ed,iva) + vector) & ~0xffUL; + regs->cr_iip = ((unsigned long) PSCBX(ed,iva) + vector) & ~0xffUL; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; // NOTE: nested trap must NOT pass PSCB address //regs->r31 = (unsigned long) &PSCB(ed); @@ -187,7 +188,7 @@ panic_domain(regs,"psr.ic off, delivering fault=%lx,iip=%p,ifa=%p,isr=%p,PSCB.ii PSCB(ed,ifs) = 0; PSCB(ed,incomplete_regframe) = 0; - regs->cr_iip = ((unsigned long) PSCB(ed,iva) + vector) & ~0xffUL; + regs->cr_iip = ((unsigned long) PSCBX(ed,iva) + vector) & ~0xffUL; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; #ifdef CONFIG_SMP #error "sharedinfo doesn't handle smp yet" @@ -516,7 +517,7 @@ printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n", case 32: /* fp fault */ case 33: /* fp trap */ //result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); - if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { + //if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { //siginfo.si_signo = SIGFPE; //siginfo.si_errno = 0; //siginfo.si_code = FPE_FLTINV; @@ -525,7 +526,7 @@ printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n", //siginfo.si_isr = isr; //siginfo.si_imm = 0; //force_sig_info(SIGFPE, &siginfo, current); - } + //} //return; sprintf(buf, "FP fault/trap"); break; @@ -722,6 +723,10 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, u if (ia64_hypercall(regs)) vcpu_increment_iip(current); } + else if (!PSCB(ed,interrupt_collection_enabled)) { + if (ia64_hyperprivop(iim,regs)) + vcpu_increment_iip(current); + } else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR); } diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index d1769a20c3..29b20a4df0 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -1,6 +1,6 @@ /* * Virtualized CPU functions - * + * * Copyright (C) 2004 Hewlett-Packard Co. * Dan Magenheimer (dan.magenheimer@hp.com) * @@ -26,6 +26,7 @@ typedef union { // this def for vcpu_regs won't work if kernel stack is present #define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs) #define PSCB(x,y) x->vcpu_info->arch.y +#define PSCBX(x,y) x->arch.y #define TRUE 1 #define FALSE 0 @@ -37,6 +38,17 @@ typedef union { #define STATIC +#ifdef PRIVOP_ADDR_COUNT +struct privop_addr_count privop_addr_counter[PRIVOP_COUNT_NINSTS] = { + { "rsm", { 0 }, { 0 }, 0 }, + { "ssm", { 0 }, { 0 }, 0 } +}; +extern void privop_count_addr(unsigned long addr, int inst); +#define PRIVOP_COUNT_ADDR(regs,inst) privop_count_addr(regs->cr_iip,inst) +#else +#define PRIVOP_COUNT_ADDR(x,y) do {} while (0) +#endif + unsigned long vcpu_verbose = 0; #define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0) @@ -77,30 +89,20 @@ vcpu_set_gr(VCPU *vcpu, unsigned reg, UINT64 value) IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val) { if (reg == 44) return (vcpu_set_itc(vcpu,val)); - if (reg == 27) return (IA64_ILLOP_FAULT); - if (reg > 7) return (IA64_ILLOP_FAULT); - PSCB(vcpu,krs[reg]) = val; -#if 0 -// for now, privify kr read's so all kr accesses are privileged - switch (reg) { - case 0: asm volatile ("mov ar.k0=%0" :: "r"(val)); break; - case 1: asm volatile ("mov ar.k1=%0" :: "r"(val)); break; - case 2: asm volatile ("mov ar.k2=%0" :: "r"(val)); break; - case 3: asm volatile ("mov ar.k3=%0" :: "r"(val)); break; - case 4: asm volatile ("mov ar.k4=%0" :: "r"(val)); break; - case 5: asm volatile ("mov ar.k5=%0" :: "r"(val)); break; - case 6: asm volatile ("mov ar.k6=%0" :: "r"(val)); break; - case 7: asm volatile ("mov ar.k7=%0" :: "r"(val)); break; - case 27: asm volatile ("mov ar.cflg=%0" :: "r"(val)); break; - } -#endif + else if (reg == 27) return (IA64_ILLOP_FAULT); + else if (reg == 24) + printf("warning: setting ar.eflg is a no-op; no IA-32 support\n"); + else if (reg > 7) return (IA64_ILLOP_FAULT); + else PSCB(vcpu,krs[reg]) = val; return IA64_NO_FAULT; } IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val) { - if (reg > 7) return (IA64_ILLOP_FAULT); - *val = PSCB(vcpu,krs[reg]); + if (reg == 24) + printf("warning: getting ar.eflg is a no-op; no IA-32 support\n"); + else if (reg > 7) return (IA64_ILLOP_FAULT); + else *val = PSCB(vcpu,krs[reg]); return IA64_NO_FAULT; } @@ -119,11 +121,18 @@ void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode) } } +IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu) +{ + vcpu_set_metaphysical_mode(vcpu,TRUE); + return IA64_NO_FAULT; +} + IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) { struct ia64_psr psr, imm, *ipsr; REGS *regs = vcpu_regs(vcpu); + PRIVOP_COUNT_ADDR(regs,_RSM); // TODO: All of these bits need to be virtualized // TODO: Only allowed for current vcpu __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); @@ -152,12 +161,19 @@ IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu); #define SPURIOUS_VECTOR 0xf +IA64FAULT vcpu_set_psr_dt(VCPU *vcpu) +{ + vcpu_set_metaphysical_mode(vcpu,FALSE); + return IA64_NO_FAULT; +} + IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) { struct ia64_psr psr, imm, *ipsr; REGS *regs = vcpu_regs(vcpu); UINT64 mask, enabling_interrupts = 0; + PRIVOP_COUNT_ADDR(regs,_SSM); // TODO: All of these bits need to be virtualized __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); imm = *(struct ia64_psr *)&imm24; @@ -274,9 +290,9 @@ BOOLEAN vcpu_get_psr_i(VCPU *vcpu) UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr) { - UINT64 dcr = PSCB(vcpu,dcr); + UINT64 dcr = PSCBX(vcpu,dcr); PSR psr = {0}; - + //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...",prevpsr); psr.i64 = prevpsr; psr.ia64_psr.be = 0; if (dcr & IA64_DCR_BE) psr.ia64_psr.be = 1; @@ -302,13 +318,13 @@ extern unsigned long privop_trace; //verbose("vcpu_get_dcr: called @%p\n",PSCB(vcpu,iip)); // Reads of cr.dcr on Xen always have the sign bit set, so // a domain can differentiate whether it is running on SP or not - *pval = PSCB(vcpu,dcr) | 0x8000000000000000L; + *pval = PSCBX(vcpu,dcr) | 0x8000000000000000L; return (IA64_NO_FAULT); } IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval) { - *pval = PSCB(vcpu,iva) & ~0x7fffL; + *pval = PSCBX(vcpu,iva) & ~0x7fffL; return (IA64_NO_FAULT); } @@ -408,13 +424,13 @@ extern unsigned long privop_trace; // a domain can differentiate whether it is running on SP or not // Thus, writes of DCR should ignore the sign bit //verbose("vcpu_set_dcr: called\n"); - PSCB(vcpu,dcr) = val & ~0x8000000000000000L; + PSCBX(vcpu,dcr) = val & ~0x8000000000000000L; return (IA64_NO_FAULT); } IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val) { - PSCB(vcpu,iva) = val & ~0x7fffL; + PSCBX(vcpu,iva) = val & ~0x7fffL; return (IA64_NO_FAULT); } @@ -508,16 +524,16 @@ void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) return; } if (!test_bit(vector,PSCB(vcpu,delivery_mask))) return; - if (test_bit(vector,PSCB(vcpu,irr))) { + if (test_bit(vector,PSCBX(vcpu,irr))) { //printf("vcpu_pend_interrupt: overrun\n"); } - set_bit(vector,PSCB(vcpu,irr)); + set_bit(vector,PSCBX(vcpu,irr)); PSCB(vcpu,pending_interruption) = 1; } void early_tick(VCPU *vcpu) { - UINT64 *p = &PSCB(vcpu,irr[3]); + UINT64 *p = &PSCBX(vcpu,irr[3]); printf("vcpu_check_pending: about to deliver early tick\n"); printf("&irr[0]=%p, irr[0]=0x%lx\n",p,*p); } @@ -535,9 +551,9 @@ UINT64 vcpu_check_pending_interrupts(VCPU *vcpu) { UINT64 *p, *q, *r, bits, bitnum, mask, i, vector; - p = &PSCB(vcpu,irr[3]); + p = &PSCBX(vcpu,irr[3]); q = &PSCB(vcpu,delivery_mask[3]); - r = &PSCB(vcpu,insvc[3]); + r = &PSCBX(vcpu,insvc[3]); for (i = 3; ; p--, q--, r--, i--) { bits = *p & *q; if (bits) break; // got a potential interrupt @@ -577,9 +593,9 @@ UINT64 vcpu_check_pending_interrupts(VCPU *vcpu) #if 0 if (vector == (PSCB(vcpu,itv) & 0xff)) { UINT64 now = ia64_get_itc(); - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); if (now < itm) early_tick(vcpu); - + } #endif return vector; @@ -639,13 +655,13 @@ IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval) i = vector >> 6; mask = 1L << (vector & 0x3f); //printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %ld\n",vector); - PSCB(vcpu,insvc[i]) |= mask; - PSCB(vcpu,irr[i]) &= ~mask; + PSCBX(vcpu,insvc[i]) |= mask; + PSCBX(vcpu,irr[i]) &= ~mask; //PSCB(vcpu,pending_interruption)--; *pval = vector; // if delivering a timer interrupt, remember domain_itm if (vector == (PSCB(vcpu,itv) & 0xff)) { - PSCB(vcpu,domain_itm_last) = PSCB(vcpu,domain_itm); + PSCBX(vcpu,domain_itm_last) = PSCBX(vcpu,domain_itm); } return IA64_NO_FAULT; } @@ -760,7 +776,7 @@ IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val) UINT64 *p, bits, vec, bitnum; int i; - p = &PSCB(vcpu,insvc[3]); + p = &PSCBX(vcpu,insvc[3]); for (i = 3; (i >= 0) && !(bits = *p); i--, p--); if (i < 0) { printf("Trying to EOI interrupt when none are in-service.\r\n"); @@ -811,8 +827,8 @@ extern unsigned long privop_trace; if (val & 0xef00) return (IA64_ILLOP_FAULT); PSCB(vcpu,itv) = val; if (val & 0x10000) { -printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCB(vcpu,domain_itm)); - PSCB(vcpu,domain_itm) = 0; +printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCBX(vcpu,domain_itm)); + PSCBX(vcpu,domain_itm) = 0; } else vcpu_enable_timer(vcpu,1000000L); return (IA64_NO_FAULT); @@ -832,6 +848,20 @@ IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val) return (IA64_NO_FAULT); } +/************************************************************************** + VCPU temporary register access routines +**************************************************************************/ +UINT64 vcpu_get_tmp(VCPU *vcpu, UINT64 index) +{ + if (index > 7) return 0; + return PSCB(vcpu,tmp[index]); +} + +void vcpu_set_tmp(VCPU *vcpu, UINT64 index, UINT64 val) +{ + if (index <= 7) PSCB(vcpu,tmp[index]) = val; +} + /************************************************************************** Interval timer routines **************************************************************************/ @@ -845,14 +875,14 @@ BOOLEAN vcpu_timer_disabled(VCPU *vcpu) BOOLEAN vcpu_timer_inservice(VCPU *vcpu) { UINT64 itv = PSCB(vcpu,itv); - return (test_bit(itv, PSCB(vcpu,insvc))); + return (test_bit(itv, PSCBX(vcpu,insvc))); } BOOLEAN vcpu_timer_expired(VCPU *vcpu) { - unsigned long domain_itm = PSCB(vcpu,domain_itm); + unsigned long domain_itm = PSCBX(vcpu,domain_itm); unsigned long now = ia64_get_itc(); - + if (!domain_itm) return FALSE; if (now < domain_itm) return FALSE; if (vcpu_timer_disabled(vcpu)) return FALSE; @@ -877,36 +907,36 @@ void vcpu_safe_set_itm(unsigned long val) void vcpu_set_next_timer(VCPU *vcpu) { - UINT64 d = PSCB(vcpu,domain_itm); - //UINT64 s = PSCB(vcpu,xen_itm); + UINT64 d = PSCBX(vcpu,domain_itm); + //UINT64 s = PSCBX(vcpu,xen_itm); UINT64 s = local_cpu_data->itm_next; UINT64 now = ia64_get_itc(); - //UINT64 interval = PSCB(vcpu,xen_timer_interval); + //UINT64 interval = PSCBX(vcpu,xen_timer_interval); /* gloss over the wraparound problem for now... we know it exists * but it doesn't matter right now */ #if 0 /* ensure at least next SP tick is in the future */ - if (!interval) PSCB(vcpu,xen_itm) = now + + if (!interval) PSCBX(vcpu,xen_itm) = now + #if 0 (running_on_sim() ? SIM_DEFAULT_CLOCK_RATE : - DEFAULT_CLOCK_RATE); + DEFAULT_CLOCK_RATE); #else 3000000; //printf("vcpu_set_next_timer: HACK!\n"); #endif #if 0 - if (PSCB(vcpu,xen_itm) < now) - while (PSCB(vcpu,xen_itm) < now + (interval>>1)) - PSCB(vcpu,xen_itm) += interval; + if (PSCBX(vcpu,xen_itm) < now) + while (PSCBX(vcpu,xen_itm) < now + (interval>>1)) + PSCBX(vcpu,xen_itm) += interval; #endif #endif if (is_idle_task(vcpu->domain)) { printf("****** vcpu_set_next_timer called during idle!!\n"); } - //s = PSCB(vcpu,xen_itm); + //s = PSCBX(vcpu,xen_itm); if (d && (d > now) && (d < s)) { vcpu_safe_set_itm(d); //using_domain_as_itm++; @@ -920,10 +950,10 @@ void vcpu_set_next_timer(VCPU *vcpu) // parameter is a time interval specified in cycles void vcpu_enable_timer(VCPU *vcpu,UINT64 cycles) { - PSCB(vcpu,xen_timer_interval) = cycles; + PSCBX(vcpu,xen_timer_interval) = cycles; vcpu_set_next_timer(vcpu); printf("vcpu_enable_timer(%d): interval set to %d cycles\n", - PSCB(vcpu,xen_timer_interval)); + PSCBX(vcpu,xen_timer_interval)); __set_bit(PSCB(vcpu,itv), PSCB(vcpu,delivery_mask)); } @@ -933,30 +963,30 @@ IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val) //if (val < now) val = now + 1000; //printf("*** vcpu_set_itm: called with %lx\n",val); - PSCB(vcpu,domain_itm) = val; + PSCBX(vcpu,domain_itm) = val; vcpu_set_next_timer(vcpu); return (IA64_NO_FAULT); } IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val) { - + UINT64 oldnow = ia64_get_itc(); - UINT64 olditm = PSCB(vcpu,domain_itm); + UINT64 olditm = PSCBX(vcpu,domain_itm); unsigned long d = olditm - oldnow; unsigned long x = local_cpu_data->itm_next - oldnow; - + UINT64 newnow = val, min_delta; local_irq_disable(); if (olditm) { printf("**** vcpu_set_itc(%lx): vitm changed to %lx\n",val,newnow+d); - PSCB(vcpu,domain_itm) = newnow + d; + PSCBX(vcpu,domain_itm) = newnow + d; } local_cpu_data->itm_next = newnow + x; - d = PSCB(vcpu,domain_itm); + d = PSCBX(vcpu,domain_itm); x = local_cpu_data->itm_next; - + ia64_set_itc(newnow); if (d && (d > newnow) && (d < x)) { vcpu_safe_set_itm(d); @@ -991,7 +1021,7 @@ void vcpu_pend_timer(VCPU *vcpu) if (vcpu_timer_disabled(vcpu)) return; //if (vcpu_timer_inservice(vcpu)) return; - if (PSCB(vcpu,domain_itm_last) == PSCB(vcpu,domain_itm)) { + if (PSCBX(vcpu,domain_itm_last) == PSCBX(vcpu,domain_itm)) { // already delivered an interrupt for this so // don't deliver another return; @@ -999,7 +1029,7 @@ void vcpu_pend_timer(VCPU *vcpu) #if 0 // attempt to flag "timer tick before its due" source { - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); UINT64 now = ia64_get_itc(); if (now < itm) printf("******* vcpu_pend_timer: pending before due!\n"); } @@ -1011,7 +1041,7 @@ void vcpu_pend_timer(VCPU *vcpu) UINT64 vcpu_timer_pending_early(VCPU *vcpu) { UINT64 now = ia64_get_itc(); - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); if (vcpu_timer_disabled(vcpu)) return 0; if (!itm) return 0; @@ -1023,7 +1053,7 @@ void vcpu_poke_timer(VCPU *vcpu) { UINT64 itv = PSCB(vcpu,itv) & 0xff; UINT64 now = ia64_get_itc(); - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); UINT64 irr; if (vcpu_timer_disabled(vcpu)) return; @@ -1033,8 +1063,8 @@ void vcpu_poke_timer(VCPU *vcpu) while(1); } // using 0xef instead of itv so can get real irr - if (now > itm && !test_bit(0xefL, PSCB(vcpu,insvc))) { - if (!test_bit(0xefL,PSCB(vcpu,irr))) { + if (now > itm && !test_bit(0xefL, PSCBX(vcpu,insvc))) { + if (!test_bit(0xefL,PSCBX(vcpu,irr))) { irr = ia64_getreg(_IA64_REG_CR_IRR3); if (irr & (1L<<(0xef-0xc0))) return; if (now-itm>0x800000) @@ -1091,7 +1121,7 @@ printf("SI_CR_IIP/IPSR/IFS_OFFSET CHANGED, SEE dorfirfi\n"); printf("SI_CR_IIP=0x%x,IPSR=0x%x,IFS_OFFSET=0x%x\n",SI_OFS(iip),SI_OFS(ipsr),SI_OFS(ifs)); while(1); } - // TODO: validate PSCB(vcpu,iip) + // TODO: validate PSCB(vcpu,iip) // TODO: PSCB(vcpu,ipsr) = psr; PSCB(vcpu,ipsr) = psr.i64; // now set up the trampoline @@ -1338,7 +1368,6 @@ IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval) unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr) { - ia64_rr rr; rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; @@ -1348,7 +1377,6 @@ unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr) unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr) { - ia64_rr rr; rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; @@ -1358,7 +1386,6 @@ unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr) unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr) { - ia64_rr rr; rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; @@ -1445,8 +1472,8 @@ TR_ENTRY *vcpu_match_tr_entry(VCPU *vcpu, TR_ENTRY *trp, UINT64 ifa, int count) for (i = 0; i < count; i++, trp++) { if (!trp->p) continue; if (physicalize_rid(vcpu,trp->rid) != rid) continue; - if (ifa < trp->vadr) continue; - if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue; + if (ifa < trp->vadr) continue; + if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue; //if (trp->key && !match_pkr(vcpu,trp->key)) continue; return trp; } @@ -1457,9 +1484,9 @@ TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa) { TR_ENTRY *trp; - trp = vcpu_match_tr_entry(vcpu,vcpu->vcpu_info->arch.dtrs,ifa,NDTRS); + trp = vcpu_match_tr_entry(vcpu,vcpu->arch.dtrs,ifa,NDTRS); if (trp) return trp; - trp = vcpu_match_tr_entry(vcpu,vcpu->vcpu_info->arch.itrs,ifa,NITRS); + trp = vcpu_match_tr_entry(vcpu,vcpu->arch.itrs,ifa,NITRS); if (trp) return trp; return 0; } @@ -1470,7 +1497,8 @@ IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, TR_ENTRY *trp; if (slot >= NDTRS) return IA64_RSVDREG_FAULT; - trp = &PSCB(vcpu,dtrs[slot]); + trp = &PSCBX(vcpu,dtrs[slot]); +//printf("***** itr.d: setting slot %d: ifa=%p\n",slot,ifa); vcpu_set_tr_entry(trp,pte,itir,ifa); return IA64_NO_FAULT; } @@ -1481,7 +1509,8 @@ IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, TR_ENTRY *trp; if (slot >= NITRS) return IA64_RSVDREG_FAULT; - trp = &PSCB(vcpu,itrs[slot]); + trp = &PSCBX(vcpu,itrs[slot]); +//printf("***** itr.i: setting slot %d: ifa=%p\n",slot,ifa); vcpu_set_tr_entry(trp,pte,itir,ifa); return IA64_NO_FAULT; } @@ -1524,12 +1553,12 @@ void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 #endif if (IorD & 0x4) return; // don't place in 1-entry TLB if (IorD & 0x1) { - vcpu_set_tr_entry(&PSCB(vcpu,itlb),pte,ps<<2,vaddr); - PSCB(vcpu,itlb_pte) = mp_pte; + vcpu_set_tr_entry(&PSCBX(vcpu,itlb),pte,ps<<2,vaddr); + PSCBX(vcpu,itlb_pte) = mp_pte; } if (IorD & 0x2) { - vcpu_set_tr_entry(&PSCB(vcpu,dtlb),pte,ps<<2,vaddr); - PSCB(vcpu,dtlb_pte) = mp_pte; + vcpu_set_tr_entry(&PSCBX(vcpu,dtlb),pte,ps<<2,vaddr); + PSCBX(vcpu,dtlb_pte) = mp_pte; } } @@ -1539,9 +1568,9 @@ unsigned long match_dtlb(VCPU *vcpu, unsigned long ifa, unsigned long *ps, unsig { TR_ENTRY *trp; - if (trp = vcpu_match_tr_entry(vcpu,&vcpu->vcpu_info->arch.dtlb,ifa,1)) { + if (trp = vcpu_match_tr_entry(vcpu,&vcpu->arch.dtlb,ifa,1)) { if (ps) *ps = trp->ps; - if (mp_pte) *mp_pte = vcpu->vcpu_info->arch.dtlb_pte; + if (mp_pte) *mp_pte = vcpu->arch.dtlb_pte; return (trp->page_flags); } return 0UL; @@ -1645,8 +1674,8 @@ IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) #endif local_flush_tlb_all(); // just invalidate the "whole" tlb - vcpu_purge_tr_entry(&PSCB(vcpu,dtlb)); - vcpu_purge_tr_entry(&PSCB(vcpu,itlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); return IA64_NO_FAULT; } @@ -1666,8 +1695,8 @@ IA64FAULT vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 addr_range) vhpt_flush_address(vadr,addr_range); #endif ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT); - vcpu_purge_tr_entry(&PSCB(vcpu,dtlb)); - vcpu_purge_tr_entry(&PSCB(vcpu,itlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); return IA64_NO_FAULT; } diff --git a/xen/arch/ia64/xenmisc.c b/xen/arch/ia64/xenmisc.c index 8d94e3f536..2f5562c46a 100644 --- a/xen/arch/ia64/xenmisc.c +++ b/xen/arch/ia64/xenmisc.c @@ -79,6 +79,14 @@ void raise_actimer_softirq(void) raise_softirq(AC_TIMER_SOFTIRQ); } +unsigned long __hypercall_create_continuation( + unsigned int op, unsigned int nr_args, ...) +{ + printf("__hypercall_create_continuation: not implemented!!!\n"); +} + +/////////////////////////////// + /////////////////////////////// // from arch/x86/apic.c /////////////////////////////// @@ -139,7 +147,7 @@ void free_page_type(struct pfn_info *page, unsigned int type) void show_registers(struct pt_regs *regs) { printf("*** ADD REGISTER DUMP HERE FOR DEBUGGING\n"); -} +} /////////////////////////////// // from common/keyhandler.c @@ -240,7 +248,7 @@ int id = ((struct exec_domain *)current)->domain->id & 0xf; if (!cnt[id]--) { printk("%x",id); cnt[id] = 50; } if (!i--) { printk("+",id); cnt[id] = 100; } } - clear_bit(EDF_RUNNING, &prev->ed_flags); + clear_bit(EDF_RUNNING, &prev->flags); //if (!is_idle_task(next->domain) ) //send_guest_virq(next, VIRQ_TIMER); load_region_regs(current); @@ -270,7 +278,7 @@ loop: printf(buf); if (regs) show_registers(regs); domain_pause_by_systemcontroller(current->domain); - set_bit(DF_CRASHED, ed->domain->d_flags); + set_bit(DF_CRASHED, ed->domain->flags); if (ed->domain->id == 0) { int i = 1000000000L; // if domain0 crashes, just periodically print out panic diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c index 7d497ea40c..ec864e1ef2 100644 --- a/xen/arch/ia64/xensetup.c +++ b/xen/arch/ia64/xensetup.c @@ -267,7 +267,7 @@ printk("About to call init_idle_task()\n"); if ( dom0 == NULL ) panic("Error creating domain 0\n"); - set_bit(DF_PRIVILEGED, &dom0->d_flags); + set_bit(DF_PRIVILEGED, &dom0->flags); /* * We're going to setup domain0 using the module(s) that we stashed safely diff --git a/xen/arch/ia64/xentime.c b/xen/arch/ia64/xentime.c index 20d13eb7ef..a3790b4577 100644 --- a/xen/arch/ia64/xentime.c +++ b/xen/arch/ia64/xentime.c @@ -84,6 +84,17 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) { unsigned long new_itm; +#define HEARTBEAT_FREQ 16 // period in seconds +#ifdef HEARTBEAT_FREQ + static long count = 0; + if (!(++count & ((HEARTBEAT_FREQ*1024)-1))) { + printf("Heartbeat... iip=%p,psr.i=%d,pend=%d\n", + regs->cr_iip, + current->vcpu_info->arch.interrupt_delivery_enabled, + current->vcpu_info->arch.pending_interruption); + count = 0; + } +#endif #ifndef XEN if (unlikely(cpu_is_offline(smp_processor_id()))) { return IRQ_HANDLED; diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 42d828f7f5..dfc64ddf9c 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -3,6 +3,7 @@ include $(BASEDIR)/Rules.mk OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S)) OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c)) +OBJS += $(patsubst %.c,%.o,$(wildcard acpi/*.c)) OBJS += $(patsubst %.c,%.o,$(wildcard mtrr/*.c)) OBJS := $(subst $(TARGET_SUBARCH)/asm-offsets.o,,$(OBJS)) @@ -34,6 +35,7 @@ clean: rm -f x86_32/*.o x86_32/*~ x86_32/core rm -f x86_64/*.o x86_64/*~ x86_64/core rm -f mtrr/*.o mtrr/*~ mtrr/core + rm -f acpi/*.o acpi/*~ acpi/core delete-unfresh-files: # nothing diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk index 915a646bed..f21be04704 100644 --- a/xen/arch/x86/Rules.mk +++ b/xen/arch/x86/Rules.mk @@ -2,8 +2,8 @@ # x86-specific definitions CFLAGS += -nostdinc -fno-builtin -fno-common -fno-strict-aliasing -CFLAGS += -iwithprefix include -Wall -Werror -pipe -CFLAGS += -I$(BASEDIR)/include -Wno-pointer-arith -Wredundant-decls +CFLAGS += -iwithprefix include -Wall -Werror -Wno-pointer-arith -pipe +CFLAGS += -I$(BASEDIR)/include -I$(BASEDIR)/include/asm-x86/mach-default ifeq ($(optimize),y) CFLAGS += -O3 -fomit-frame-pointer diff --git a/xen/arch/x86/acpi.c b/xen/arch/x86/acpi.c deleted file mode 100644 index 4d3cc212b1..0000000000 --- a/xen/arch/x86/acpi.c +++ /dev/null @@ -1,729 +0,0 @@ -/* - * acpi.c - Architecture-Specific Low-Level ACPI Support - * - * Copyright (C) 2001, 2002 Paul Diefenbaugh - * Copyright (C) 2001 Jun Nakajima - * Copyright (C) 2001 Patrick Mochel - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define PREFIX "ACPI: " - -int acpi_lapic; -int acpi_ioapic; -int acpi_strict; - -acpi_interrupt_flags acpi_sci_flags __initdata; -int acpi_sci_override_gsi __initdata; -/* -------------------------------------------------------------------------- - Boot-time Configuration - -------------------------------------------------------------------------- */ - -int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ -int acpi_ht __initdata = 1; /* enable HT */ - -enum acpi_irq_model_id acpi_irq_model; - - -/* - * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, - * to map the target physical address. The problem is that set_fixmap() - * provides a single page, and it is possible that the page is not - * sufficient. - * By using this area, we can map up to MAX_IO_APICS pages temporarily, - * i.e. until the next __va_range() call. - * - * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* - * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and - * count idx down while incrementing the phys address. - */ -char *__acpi_map_table(unsigned long phys, unsigned long size) -{ - unsigned long base, offset, mapped_size; - int idx; - - if (phys + size < 8*1024*1024) - return __va(phys); - - offset = phys & (PAGE_SIZE - 1); - mapped_size = PAGE_SIZE - offset; - set_fixmap(FIX_ACPI_END, phys); - base = fix_to_virt(FIX_ACPI_END); - - /* - * Most cases can be covered by the below. - */ - idx = FIX_ACPI_END; - while (mapped_size < size) { - if (--idx < FIX_ACPI_BEGIN) - return 0; /* cannot handle this */ - phys += PAGE_SIZE; - set_fixmap(idx, phys); - mapped_size += PAGE_SIZE; - } - - return ((char *) base + offset); -} - - -#ifdef CONFIG_X86_LOCAL_APIC - -static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; - - -static int __init -acpi_parse_madt ( - unsigned long phys_addr, - unsigned long size) -{ - struct acpi_table_madt *madt = NULL; - - if (!phys_addr || !size) - return -EINVAL; - - madt = (struct acpi_table_madt *) __acpi_map_table(phys_addr, size); - if (!madt) { - printk(KERN_WARNING PREFIX "Unable to map MADT\n"); - return -ENODEV; - } - - if (madt->lapic_address) - acpi_lapic_addr = (u64) madt->lapic_address; - - printk(KERN_INFO PREFIX "Local APIC address 0x%08x\n", - madt->lapic_address); - - detect_clustered_apic(madt->header.oem_id, madt->header.oem_table_id); - - return 0; -} - - -static int __init -acpi_parse_lapic ( - acpi_table_entry_header *header) -{ - struct acpi_table_lapic *processor = NULL; - - processor = (struct acpi_table_lapic*) header; - if (!processor) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - mp_register_lapic ( - processor->id, /* APIC ID */ - processor->flags.enabled); /* Enabled? */ - - return 0; -} - - -static int __init -acpi_parse_lapic_addr_ovr ( - acpi_table_entry_header *header) -{ - struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; - - lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr*) header; - if (!lapic_addr_ovr) - return -EINVAL; - - acpi_lapic_addr = lapic_addr_ovr->address; - - return 0; -} - -static int __init -acpi_parse_lapic_nmi ( - acpi_table_entry_header *header) -{ - struct acpi_table_lapic_nmi *lapic_nmi = NULL; - - lapic_nmi = (struct acpi_table_lapic_nmi*) header; - if (!lapic_nmi) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - if (lapic_nmi->lint != 1) - printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); - - return 0; -} - -#endif /*CONFIG_X86_LOCAL_APIC*/ - -#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ - -static int __init -acpi_parse_ioapic ( - acpi_table_entry_header *header) -{ - struct acpi_table_ioapic *ioapic = NULL; - - ioapic = (struct acpi_table_ioapic*) header; - if (!ioapic) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - mp_register_ioapic ( - ioapic->id, - ioapic->address, - ioapic->global_irq_base); - - return 0; -} - -#ifdef CONFIG_ACPI_INTERPRETER -/* - * Parse Interrupt Source Override for the ACPI SCI - */ -static void -acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) -{ - if (trigger == 0) /* compatible SCI trigger is level */ - trigger = 3; - - if (polarity == 0) /* compatible SCI polarity is low */ - polarity = 3; - - /* Command-line over-ride via acpi_sci= */ - if (acpi_sci_flags.trigger) - trigger = acpi_sci_flags.trigger; - - if (acpi_sci_flags.polarity) - polarity = acpi_sci_flags.polarity; - - /* - * mp_config_acpi_legacy_irqs() already setup IRQs < 16 - * If GSI is < 16, this will update its flags, - * else it will create a new mp_irqs[] entry. - */ - mp_override_legacy_irq(gsi, polarity, trigger, gsi); - - /* - * stash over-ride to indicate we've been here - * and for later update of acpi_fadt - */ - acpi_sci_override_gsi = gsi; - return; -} -#endif - -static int __init -acpi_parse_fadt(unsigned long phys, unsigned long size) -{ - struct fadt_descriptor_rev2 *fadt =0; - - fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); - if (!fadt) { - printk(KERN_WARNING PREFIX "Unable to map FADT\n"); - return 0; - } - -#ifdef CONFIG_ACPI_INTERPRETER - /* initialize sci_int early for INT_SRC_OVR MADT parsing */ - acpi_fadt.sci_int = fadt->sci_int; -#endif - - return 0; -} - - -static int __init -acpi_parse_int_src_ovr ( - acpi_table_entry_header *header) -{ - struct acpi_table_int_src_ovr *intsrc = NULL; - - intsrc = (struct acpi_table_int_src_ovr*) header; - if (!intsrc) - return -EINVAL; - - acpi_table_print_madt_entry(header); - -#ifdef CONFIG_ACPI_INTERPRETER - if (intsrc->bus_irq == acpi_fadt.sci_int) { - acpi_sci_ioapic_setup(intsrc->global_irq, - intsrc->flags.polarity, intsrc->flags.trigger); - return 0; - } -#endif - - mp_override_legacy_irq ( - intsrc->bus_irq, - intsrc->flags.polarity, - intsrc->flags.trigger, - intsrc->global_irq); - - return 0; -} - - -static int __init -acpi_parse_nmi_src ( - acpi_table_entry_header *header) -{ - struct acpi_table_nmi_src *nmi_src = NULL; - - nmi_src = (struct acpi_table_nmi_src*) header; - if (!nmi_src) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - /* TBD: Support nimsrc entries? */ - - return 0; -} - -#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/ - - -static unsigned long __init -acpi_scan_rsdp ( - unsigned long start, - unsigned long length) -{ - unsigned long offset = 0; - unsigned long sig_len = sizeof("RSD PTR ") - 1; - - /* - * Scan all 16-byte boundaries of the physical memory region for the - * RSDP signature. - */ - for (offset = 0; offset < length; offset += 16) { - if (strncmp((char *) (start + offset), "RSD PTR ", sig_len)) - continue; - return (start + offset); - } - - return 0; -} - - -unsigned long __init -acpi_find_rsdp (void) -{ - unsigned long rsdp_phys = 0; - - /* - * Scan memory looking for the RSDP signature. First search EBDA (low - * memory) paragraphs and then search upper memory (E0000-FFFFF). - */ - rsdp_phys = acpi_scan_rsdp (0, 0x400); - if (!rsdp_phys) - rsdp_phys = acpi_scan_rsdp (0xE0000, 0x20000); - - return rsdp_phys; -} - - -/* - * acpi_boot_init() - * called from setup_arch(), always. - * 1. maps ACPI tables for later use - * 2. enumerates lapics - * 3. enumerates io-apics - * - * side effects: - * acpi_lapic = 1 if LAPIC found - * acpi_ioapic = 1 if IOAPIC found - * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; - * if acpi_blacklisted() disable_acpi() - * acpi_irq_model=... - * ... - * - * return value: (currently ignored) - * 0: success - * !0: failure - */ -int __init -acpi_boot_init (void) -{ - int result = 0; - - if (acpi_disabled && !acpi_ht) - return(1); - - /* - * The default interrupt routing model is PIC (8259). This gets - * overriden if IOAPICs are enumerated (below). - */ - acpi_irq_model = ACPI_IRQ_MODEL_PIC; - - /* - * Initialize the ACPI boot-time table parser. - */ - result = acpi_table_init(); - if (result) { - disable_acpi(); - return result; - } - - result = acpi_blacklisted(); - if (result) { - printk(KERN_NOTICE PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); - disable_acpi(); - return result; - } - -#ifdef CONFIG_X86_LOCAL_APIC - - /* - * MADT - * ---- - * Parse the Multiple APIC Description Table (MADT), if exists. - * Note that this table provides platform SMP configuration - * information -- the successor to MPS tables. - */ - - result = acpi_table_parse(ACPI_APIC, acpi_parse_madt); - if (!result) { - return 0; - } - else if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing MADT\n"); - return result; - } - else if (result > 1) - printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n"); - - /* - * Local APIC - * ---------- - * Note that the LAPIC address is obtained from the MADT (32-bit value) - * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). - */ - - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - return result; - } - - mp_register_lapic_address(acpi_lapic_addr); - - result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); - if (!result) { - printk(KERN_ERR PREFIX "No LAPIC entries present\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return -ENODEV; - } - else if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - - acpi_lapic = 1; - -#endif /*CONFIG_X86_LOCAL_APIC*/ - -#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ - - /* - * I/O APIC - * -------- - */ - -#if 0 - /* - * ACPI interpreter is required to complete interrupt setup, - * so if it is off, don't enumerate the io-apics with ACPI. - * If MPS is present, it will handle them, - * otherwise the system will stay in PIC mode - */ - if (acpi_disabled || acpi_noirq) { - return 1; - } -#endif - - /* - * if "noapic" boot option, don't look for IO-APICs - */ - if (ioapic_setup_disabled()) { - printk(KERN_INFO PREFIX "Skipping IOAPIC probe " - "due to 'noapic' option.\n"); - return 1; - } - - - result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); - if (!result) { - printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); - return -ENODEV; - } - else if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n"); - return result; - } - - /* Build a default routing table for legacy (ISA) interrupts. */ - mp_config_acpi_legacy_irqs(); - - /* Record sci_int for use when looking for MADT sci_int override */ - acpi_table_parse(ACPI_FADT, acpi_parse_fadt); - - result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - -#ifdef CONFIG_ACPI_INTERPRETER - /* - * If BIOS did not supply an INT_SRC_OVR for the SCI - * pretend we got one so we can set the SCI flags. - */ - if (!acpi_sci_override_gsi) - acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); -#endif - - result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - - acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; - - acpi_irq_balance_set(NULL); - - acpi_ioapic = 1; - - if (acpi_lapic && acpi_ioapic) - smp_found_config = 1; - -#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/ - - return 0; -} - - -#ifdef CONFIG_ACPI_BUS -/* - * acpi_pic_sci_set_trigger() - * - * use ELCR to set PIC-mode trigger type for SCI - * - * If a PIC-mode SCI is not recognized or gives spurious IRQ7's - * it may require Edge Trigger -- use "acpi_sci=edge" - * - * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers - * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. - * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) - * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) - */ - -void __init -acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) -{ - unsigned char mask = 1 << (irq & 7); - unsigned int port = 0x4d0 + (irq >> 3); - unsigned char val = inb(port); - - - printk(PREFIX "IRQ%d SCI:", irq); - if (!(val & mask)) { - printk(" Edge"); - - if (trigger == 3) { - printk(" set to Level"); - outb(val | mask, port); - } - } else { - printk(" Level"); - - if (trigger == 1) { - printk(" set to Edge"); - outb(val & ~mask, port); - } - } - printk(" Trigger.\n"); -} - -#endif /* CONFIG_ACPI_BUS */ - - -/* -------------------------------------------------------------------------- - Low-Level Sleep Support - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_ACPI_SLEEP - -#define DEBUG - -#ifdef DEBUG -#include -#endif - -/* address in low memory of the wakeup routine. */ -unsigned long acpi_wakeup_address = 0; - -/* new page directory that we will be using */ -static pmd_t *pmd; - -/* saved page directory */ -static pmd_t saved_pmd; - -/* page which we'll use for the new page directory */ -static pte_t *ptep; - -extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); - -/* - * acpi_create_identity_pmd - * - * Create a new, identity mapped pmd. - * - * Do this by creating new page directory, and marking all the pages as R/W - * Then set it as the new Page Middle Directory. - * And, of course, flush the TLB so it takes effect. - * - * We save the address of the old one, for later restoration. - */ -static void acpi_create_identity_pmd (void) -{ - pgd_t *pgd; - int i; - - ptep = (pte_t*)__get_free_page(GFP_KERNEL); - - /* fill page with low mapping */ - for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(ptep + i, mk_pte_phys(i << PAGE_SHIFT, PAGE_SHARED)); - - pgd = pgd_offset(current->active_mm, 0); - pmd = pmd_alloc(current->mm,pgd, 0); - - /* save the old pmd */ - saved_pmd = *pmd; - - /* set the new one */ - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(ptep))); - - /* flush the TLB */ - local_flush_tlb(); -} - -/* - * acpi_restore_pmd - * - * Restore the old pmd saved by acpi_create_identity_pmd and - * free the page that said function alloc'd - */ -static void acpi_restore_pmd (void) -{ - set_pmd(pmd, saved_pmd); - local_flush_tlb(); - free_page((unsigned long)ptep); -} - -/** - * acpi_save_state_mem - save kernel state - * - * Create an identity mapped page table and copy the wakeup routine to - * low memory. - */ -int acpi_save_state_mem (void) -{ - acpi_create_identity_pmd(); - acpi_copy_wakeup_routine(acpi_wakeup_address); - - return 0; -} - -/** - * acpi_save_state_disk - save kernel state to disk - * - */ -int acpi_save_state_disk (void) -{ - return 1; -} - -/* - * acpi_restore_state - */ -void acpi_restore_state_mem (void) -{ - acpi_restore_pmd(); -} - -/** - * acpi_reserve_bootmem - do _very_ early ACPI initialisation - * - * We allocate a page in low memory for the wakeup - * routine for when we come back from a sleep state. The - * runtime allocator allows specification of <16M pages, but not - * <1M pages. - */ -void __init acpi_reserve_bootmem(void) -{ - acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); - if (!acpi_wakeup_address) - printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); -} - -void do_suspend_lowlevel_s4bios(int resume) -{ - if (!resume) { - save_processor_context(); - acpi_save_register_state((unsigned long)&&acpi_sleep_done); - acpi_enter_sleep_state_s4bios(); - return; - } -acpi_sleep_done: - restore_processor_context(); -} - - -#endif /*CONFIG_ACPI_SLEEP*/ - diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c new file mode 100644 index 0000000000..c8525bce64 --- /dev/null +++ b/xen/arch/x86/acpi/boot.c @@ -0,0 +1,915 @@ +/* + * boot.c - Architecture-Specific Low-Level ACPI Boot Support + * + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int sbf_port; +#define end_pfn_map max_page +#define CONFIG_ACPI_PCI + +#ifdef CONFIG_X86_64 + +static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id) { } +extern void __init clustered_apic_check(void); +static inline int ioapic_setup_disabled(void) { return 0; } + +#else /* X86 */ + +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#endif /* CONFIG_X86_LOCAL_APIC */ + +#endif /* X86 */ + +#define BAD_MADT_ENTRY(entry, end) ( \ + (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ + ((acpi_table_entry_header *)entry)->length != sizeof(*entry)) + +#define PREFIX "ACPI: " + +#ifdef CONFIG_ACPI_PCI +int acpi_noirq __initdata; /* skip ACPI IRQ initialization */ +int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */ +#else +int acpi_noirq __initdata = 1; +int acpi_pci_disabled __initdata = 1; +#endif +int acpi_ht __initdata = 1; /* enable HT */ + +int acpi_lapic; +int acpi_ioapic; +int acpi_strict; +EXPORT_SYMBOL(acpi_strict); + +acpi_interrupt_flags acpi_sci_flags __initdata; +int acpi_sci_override_gsi __initdata; +int acpi_skip_timer_override __initdata; + +#ifdef CONFIG_X86_LOCAL_APIC +static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; +#endif + +#ifndef __HAVE_ARCH_CMPXCHG +#warning ACPI uses CMPXCHG, i486 and later hardware +#endif + +#define MAX_MADT_ENTRIES 256 +u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = + { [0 ... MAX_MADT_ENTRIES-1] = 0xff }; +EXPORT_SYMBOL(x86_acpiid_to_apicid); + +/* -------------------------------------------------------------------------- + Boot-time Configuration + -------------------------------------------------------------------------- */ + +/* + * The default interrupt routing model is PIC (8259). This gets + * overriden if IOAPICs are enumerated (below). + */ +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC; + +#ifdef CONFIG_X86_64 + +/* rely on all ACPI tables being in the direct mapping */ +char *__acpi_map_table(unsigned long phys_addr, unsigned long size) +{ + if (!phys_addr || !size) + return NULL; + + if (phys_addr < (end_pfn_map << PAGE_SHIFT)) + return __va(phys_addr); + + return NULL; +} + +#else + +/* + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, + * to map the target physical address. The problem is that set_fixmap() + * provides a single page, and it is possible that the page is not + * sufficient. + * By using this area, we can map up to MAX_IO_APICS pages temporarily, + * i.e. until the next __va_range() call. + * + * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* + * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and + * count idx down while incrementing the phys address. + */ +char *__acpi_map_table(unsigned long phys, unsigned long size) +{ + unsigned long base, offset, mapped_size; + int idx; + + if (phys + size < 8*1024*1024) + return __va(phys); + + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; + set_fixmap(FIX_ACPI_END, phys); + base = fix_to_virt(FIX_ACPI_END); + + /* + * Most cases can be covered by the below. + */ + idx = FIX_ACPI_END; + while (mapped_size < size) { + if (--idx < FIX_ACPI_BEGIN) + return NULL; /* cannot handle this */ + phys += PAGE_SIZE; + set_fixmap(idx, phys); + mapped_size += PAGE_SIZE; + } + + return ((char *) base + offset); +} +#endif + +#ifdef CONFIG_PCI_MMCONFIG +static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_mcfg *mcfg; + + if (!phys_addr || !size) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size); + if (!mcfg) { + printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); + return -ENODEV; + } + + if (mcfg->base_reserved) { + printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); + return -ENODEV; + } + + pci_mmcfg_base_addr = mcfg->base_address; + + return 0; +} +#else +#define acpi_parse_mcfg NULL +#endif /* !CONFIG_PCI_MMCONFIG */ + +#ifdef CONFIG_X86_LOCAL_APIC +static int __init +acpi_parse_madt ( + unsigned long phys_addr, + unsigned long size) +{ + struct acpi_table_madt *madt = NULL; + + if (!phys_addr || !size) + return -EINVAL; + + madt = (struct acpi_table_madt *) __acpi_map_table(phys_addr, size); + if (!madt) { + printk(KERN_WARNING PREFIX "Unable to map MADT\n"); + return -ENODEV; + } + + if (madt->lapic_address) { + acpi_lapic_addr = (u64) madt->lapic_address; + + printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n", + madt->lapic_address); + } + + acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id); + + return 0; +} + + +static int __init +acpi_parse_lapic ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic *processor = NULL; + + processor = (struct acpi_table_lapic*) header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* no utility in registering a disabled processor */ + if (processor->flags.enabled == 0) + return 0; + + x86_acpiid_to_apicid[processor->acpi_id] = processor->id; + + mp_register_lapic ( + processor->id, /* APIC ID */ + processor->flags.enabled); /* Enabled? */ + + return 0; +} + +static int __init +acpi_parse_lapic_addr_ovr ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; + + lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr*) header; + + if (BAD_MADT_ENTRY(lapic_addr_ovr, end)) + return -EINVAL; + + acpi_lapic_addr = lapic_addr_ovr->address; + + return 0; +} + +static int __init +acpi_parse_lapic_nmi ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic_nmi *lapic_nmi = NULL; + + lapic_nmi = (struct acpi_table_lapic_nmi*) header; + + if (BAD_MADT_ENTRY(lapic_nmi, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + if (lapic_nmi->lint != 1) + printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); + + return 0; +} + + +#endif /*CONFIG_X86_LOCAL_APIC*/ + +#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ + +static int __init +acpi_parse_ioapic ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_ioapic *ioapic = NULL; + + ioapic = (struct acpi_table_ioapic*) header; + + if (BAD_MADT_ENTRY(ioapic, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + mp_register_ioapic ( + ioapic->id, + ioapic->address, + ioapic->global_irq_base); + + return 0; +} + +#ifdef CONFIG_ACPI_INTERPRETER +/* + * Parse Interrupt Source Override for the ACPI SCI + */ +static void +acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) +{ + if (trigger == 0) /* compatible SCI trigger is level */ + trigger = 3; + + if (polarity == 0) /* compatible SCI polarity is low */ + polarity = 3; + + /* Command-line over-ride via acpi_sci= */ + if (acpi_sci_flags.trigger) + trigger = acpi_sci_flags.trigger; + + if (acpi_sci_flags.polarity) + polarity = acpi_sci_flags.polarity; + + /* + * mp_config_acpi_legacy_irqs() already setup IRQs < 16 + * If GSI is < 16, this will update its flags, + * else it will create a new mp_irqs[] entry. + */ + mp_override_legacy_irq(gsi, polarity, trigger, gsi); + + /* + * stash over-ride to indicate we've been here + * and for later update of acpi_fadt + */ + acpi_sci_override_gsi = gsi; + return; +} +#endif + +static int __init +acpi_parse_int_src_ovr ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_int_src_ovr *intsrc = NULL; + + intsrc = (struct acpi_table_int_src_ovr*) header; + + if (BAD_MADT_ENTRY(intsrc, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + +#ifdef CONFIG_ACPI_INTERPRETER + if (intsrc->bus_irq == acpi_fadt.sci_int) { + acpi_sci_ioapic_setup(intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); + return 0; + } +#endif + + if (acpi_skip_timer_override && + intsrc->bus_irq == 0 && intsrc->global_irq == 2) { + printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n"); + return 0; + } + + mp_override_legacy_irq ( + intsrc->bus_irq, + intsrc->flags.polarity, + intsrc->flags.trigger, + intsrc->global_irq); + + return 0; +} + + +static int __init +acpi_parse_nmi_src ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_nmi_src *nmi_src = NULL; + + nmi_src = (struct acpi_table_nmi_src*) header; + + if (BAD_MADT_ENTRY(nmi_src, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* TBD: Support nimsrc entries? */ + + return 0; +} + +#endif /* CONFIG_X86_IO_APIC */ + +#ifdef CONFIG_ACPI_BUS + +/* + * acpi_pic_sci_set_trigger() + * + * use ELCR to set PIC-mode trigger type for SCI + * + * If a PIC-mode SCI is not recognized or gives spurious IRQ7's + * it may require Edge Trigger -- use "acpi_sci=edge" + * + * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers + * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. + * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) + * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) + */ + +void __init +acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) +{ + unsigned int mask = 1 << irq; + unsigned int old, new; + + /* Real old ELCR mask */ + old = inb(0x4d0) | (inb(0x4d1) << 8); + + /* + * If we use ACPI to set PCI irq's, then we should clear ELCR + * since we will set it correctly as we enable the PCI irq + * routing. + */ + new = acpi_noirq ? old : 0; + + /* + * Update SCI information in the ELCR, it isn't in the PCI + * routing tables.. + */ + switch (trigger) { + case 1: /* Edge - clear */ + new &= ~mask; + break; + case 3: /* Level - set */ + new |= mask; + break; + } + + if (old == new) + return; + + printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old); + outb(new, 0x4d0); + outb(new >> 8, 0x4d1); +} + + +#endif /* CONFIG_ACPI_BUS */ + +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ +#ifdef CONFIG_X86_IO_APIC + if (use_pci_vector() && !platform_legacy_irq(gsi)) + *irq = IO_APIC_VECTOR(gsi); + else +#endif + *irq = gsi; + return 0; +} + +unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low) +{ + unsigned int irq; + unsigned int plat_gsi = gsi; + +#ifdef CONFIG_PCI + /* + * Make sure all (legacy) PCI IRQs are set as level-triggered. + */ + if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) { + extern void eisa_set_level_irq(unsigned int irq); + + if (edge_level == ACPI_LEVEL_SENSITIVE) + eisa_set_level_irq(gsi); + } +#endif + +#ifdef CONFIG_X86_IO_APIC + if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) { + plat_gsi = mp_register_gsi(gsi, edge_level, active_high_low); + } +#endif + acpi_gsi_to_irq(plat_gsi, &irq); + return irq; +} +EXPORT_SYMBOL(acpi_register_gsi); + +/* + * ACPI based hotplug support for CPU + */ +#ifdef CONFIG_ACPI_HOTPLUG_CPU +int +acpi_map_lsapic(acpi_handle handle, int *pcpu) +{ + /* TBD */ + return -EINVAL; +} +EXPORT_SYMBOL(acpi_map_lsapic); + + +int +acpi_unmap_lsapic(int cpu) +{ + /* TBD */ + return -EINVAL; +} +EXPORT_SYMBOL(acpi_unmap_lsapic); +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ + +static unsigned long __init +acpi_scan_rsdp ( + unsigned long start, + unsigned long length) +{ + unsigned long offset = 0; + unsigned long sig_len = sizeof("RSD PTR ") - 1; + + /* + * Scan all 16-byte boundaries of the physical memory region for the + * RSDP signature. + */ + for (offset = 0; offset < length; offset += 16) { + if (strncmp((char *) (start + offset), "RSD PTR ", sig_len)) + continue; + return (start + offset); + } + + return 0; +} + +static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_sbf *sb; + + if (!phys_addr || !size) + return -EINVAL; + + sb = (struct acpi_table_sbf *) __acpi_map_table(phys_addr, size); + if (!sb) { + printk(KERN_WARNING PREFIX "Unable to map SBF\n"); + return -ENODEV; + } + + sbf_port = sb->sbf_cmos; /* Save CMOS port */ + + return 0; +} + + +#ifdef CONFIG_HPET_TIMER + +static int __init acpi_parse_hpet(unsigned long phys, unsigned long size) +{ + struct acpi_table_hpet *hpet_tbl; + + if (!phys || !size) + return -EINVAL; + + hpet_tbl = (struct acpi_table_hpet *) __acpi_map_table(phys, size); + if (!hpet_tbl) { + printk(KERN_WARNING PREFIX "Unable to map HPET\n"); + return -ENODEV; + } + + if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) { + printk(KERN_WARNING PREFIX "HPET timers must be located in " + "memory.\n"); + return -1; + } + +#ifdef CONFIG_X86_64 + vxtime.hpet_address = hpet_tbl->addr.addrl | + ((long) hpet_tbl->addr.addrh << 32); + + printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", + hpet_tbl->id, vxtime.hpet_address); +#else /* X86 */ + { + extern unsigned long hpet_address; + + hpet_address = hpet_tbl->addr.addrl; + printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", + hpet_tbl->id, hpet_address); + } +#endif /* X86 */ + + return 0; +} +#else +#define acpi_parse_hpet NULL +#endif + +#ifdef CONFIG_X86_PM_TIMER +extern u32 pmtmr_ioport; +#endif + +static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) +{ + struct fadt_descriptor_rev2 *fadt = NULL; + + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); + if(!fadt) { + printk(KERN_WARNING PREFIX "Unable to map FADT\n"); + return 0; + } + +#ifdef CONFIG_ACPI_INTERPRETER + /* initialize sci_int early for INT_SRC_OVR MADT parsing */ + acpi_fadt.sci_int = fadt->sci_int; +#endif + +#ifdef CONFIG_X86_PM_TIMER + /* detect the location of the ACPI PM Timer */ + if (fadt->revision >= FADT2_REVISION_ID) { + /* FADT rev. 2 */ + if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) + return 0; + + pmtmr_ioport = fadt->xpm_tmr_blk.address; + } else { + /* FADT rev. 1 */ + pmtmr_ioport = fadt->V1_pm_tmr_blk; + } + if (pmtmr_ioport) + printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport); +#endif + return 0; +} + + +unsigned long __init +acpi_find_rsdp (void) +{ + unsigned long rsdp_phys = 0; + +#if 0 + if (efi_enabled) { + if (efi.acpi20) + return __pa(efi.acpi20); + else if (efi.acpi) + return __pa(efi.acpi); + } +#endif + /* + * Scan memory looking for the RSDP signature. First search EBDA (low + * memory) paragraphs and then search upper memory (E0000-FFFFF). + */ + rsdp_phys = acpi_scan_rsdp (0, 0x400); + if (!rsdp_phys) + rsdp_phys = acpi_scan_rsdp (0xE0000, 0x20000); + + return rsdp_phys; +} + +#ifdef CONFIG_X86_LOCAL_APIC +/* + * Parse LAPIC entries in MADT + * returns 0 on success, < 0 on error + */ +static int __init +acpi_parse_madt_lapic_entries(void) +{ + int count; + + /* + * Note that the LAPIC address is obtained from the MADT (32-bit value) + * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). + */ + + count = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); + return count; + } + + mp_register_lapic_address(acpi_lapic_addr); + + count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + MAX_APICS); + if (!count) { + printk(KERN_ERR PREFIX "No LAPIC entries present\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return -ENODEV; + } + else if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + + count = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + return 0; +} +#endif /* CONFIG_X86_LOCAL_APIC */ + +#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ +/* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error + */ +static int __init +acpi_parse_madt_ioapic_entries(void) +{ + int count; + + /* + * ACPI interpreter is required to complete interrupt setup, + * so if it is off, don't enumerate the io-apics with ACPI. + * If MPS is present, it will handle them, + * otherwise the system will stay in PIC mode + */ + if (acpi_disabled || acpi_noirq) { + return -ENODEV; + } + + /* + * if "noapic" boot option, don't look for IO-APICs + */ + if (skip_ioapic_setup) { + printk(KERN_INFO PREFIX "Skipping IOAPIC probe " + "due to 'noapic' option.\n"); + return -ENODEV; + } + + count = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); + if (!count) { + printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); + return -ENODEV; + } + else if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n"); + return count; + } + + count = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + +#ifdef CONFIG_ACPI_INTERPRETER + /* + * If BIOS did not supply an INT_SRC_OVR for the SCI + * pretend we got one so we can set the SCI flags. + */ + if (!acpi_sci_override_gsi) + acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); +#endif + + /* Fill in identity legacy mapings where no override */ + mp_config_acpi_legacy_irqs(); + + count = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + + return 0; +} +#else +static inline int acpi_parse_madt_ioapic_entries(void) +{ + return -1; +} +#endif /* !(CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER) */ + + +static void __init +acpi_process_madt(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + int count, error; + + count = acpi_table_parse(ACPI_APIC, acpi_parse_madt); + if (count >= 1) { + + /* + * Parse MADT LAPIC entries + */ + error = acpi_parse_madt_lapic_entries(); + if (!error) { + acpi_lapic = 1; + + /* + * Parse MADT IO-APIC entries + */ + error = acpi_parse_madt_ioapic_entries(); + if (!error) { + acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + acpi_irq_balance_set(NULL); + acpi_ioapic = 1; + + smp_found_config = 1; + clustered_apic_check(); + } + } + if (error == -EINVAL) { + /* + * Dell Precision Workstation 410, 610 come here. + */ + printk(KERN_ERR PREFIX "Invalid BIOS MADT, disabling ACPI\n"); + disable_acpi(); + } + } +#endif + return; +} + +/* + * acpi_boot_table_init() and acpi_boot_init() + * called from setup_arch(), always. + * 1. checksums all tables + * 2. enumerates lapics + * 3. enumerates io-apics + * + * acpi_table_init() is separate to allow reading SRAT without + * other side effects. + * + * side effects of acpi_boot_init: + * acpi_lapic = 1 if LAPIC found + * acpi_ioapic = 1 if IOAPIC found + * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; + * if acpi_blacklisted() acpi_disabled = 1; + * acpi_irq_model=... + * ... + * + * return value: (currently ignored) + * 0: success + * !0: failure + */ + +int __init +acpi_boot_table_init(void) +{ + int error; + + /* + * If acpi_disabled, bail out + * One exception: acpi=ht continues far enough to enumerate LAPICs + */ + if (acpi_disabled && !acpi_ht) + return 1; + + /* + * Initialize the ACPI boot-time table parser. + */ + error = acpi_table_init(); + if (error) { + disable_acpi(); + return error; + } + + acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + + /* + * blacklist may disable ACPI entirely + */ + error = acpi_blacklisted(); + if (error) { + extern int acpi_force; + + if (acpi_force) { + printk(KERN_WARNING PREFIX "acpi=force override\n"); + } else { + printk(KERN_WARNING PREFIX "Disabling ACPI support\n"); + disable_acpi(); + return error; + } + } + + return 0; +} + + +int __init acpi_boot_init(void) +{ + /* + * If acpi_disabled, bail out + * One exception: acpi=ht continues far enough to enumerate LAPICs + */ + if (acpi_disabled && !acpi_ht) + return 1; + + acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + + /* + * set sci_int and PM timer address + */ + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); + + /* + * Process the Multiple APIC Description Table (MADT), if present + */ + acpi_process_madt(); + + acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + + return 0; +} + diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index 766a10ed7c..f368608635 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -34,14 +34,27 @@ #include #include #include -#include -#include +#include +#include /* Using APIC to generate smp_local_timer_interrupt? */ int using_apic_timer = 0; +int apic_verbosity; + static int enabled_via_apicbase; +int get_physical_broadcast(void) +{ + unsigned int lvr, version; + lvr = apic_read(APIC_LVR); + version = GET_APIC_VERSION(lvr); + if (!APIC_INTEGRATED(version) || version >= 0x14) + return 0xff; + else + return 0xf; +} + int get_maxlvt(void) { unsigned int v, ver, maxlvt; @@ -907,7 +920,7 @@ int __init APIC_init_uniprocessor (void) #ifdef CONFIG_SMP cpu_online_map = 1; #endif - phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); apic_write_around(APIC_ID, boot_cpu_physical_apicid); setup_local_APIC(); diff --git a/xen/arch/x86/audit.c b/xen/arch/x86/audit.c index 2df4d69be8..b7e874c62d 100644 --- a/xen/arch/x86/audit.c +++ b/xen/arch/x86/audit.c @@ -49,7 +49,8 @@ static int l1, l2, oos_count, page_count; int audit_adjust_pgtables(struct domain *d, int dir, int noisy) { int errors = 0; - int shadow_enabled = shadow_mode_enabled(d) ? 1 : 0; + int shadow_refcounts = !!shadow_mode_refcounts(d); + int shadow_enabled = !!shadow_mode_enabled(d); int l2limit; void _adjust(struct pfn_info *page, int adjtype ADJUST_EXTRA_ARGS) @@ -119,7 +120,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) page->count_info += dir; } - void adjust_l2_page(unsigned long mfn) + void adjust_l2_page(unsigned long mfn, int shadow) { unsigned long *pt = map_domain_mem(mfn << PAGE_SHIFT); int i; @@ -133,7 +134,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) if ( noisy ) { - if ( shadow_enabled ) + if ( shadow ) { if ( page_get_owner(l1page) != NULL ) { @@ -145,6 +146,17 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; continue; } + + u32 page_type = l1page->u.inuse.type_info & PGT_type_mask; + + if ( page_type != PGT_l1_shadow ) + { + printk("Audit %d: [Shadow L2 mfn=%lx i=%x] " + "Expected Shadow L1 t=%x mfn=%lx\n", + d->id, mfn, i, + l1page->u.inuse.type_info, l1mfn); + errors++; + } } else { @@ -154,7 +166,9 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) "belonging to other dom %p (id=%d)\n", l1mfn, page_get_owner(l1page), - page_get_owner(l1page)->id); + (page_get_owner(l1page) + ? page_get_owner(l1page)->id + : -1)); errors++; continue; } @@ -179,7 +193,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) } } - adjust(l1page, !shadow_enabled); + adjust(l1page, !shadow); } } @@ -280,7 +294,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; } - if ( shadow_enabled && + if ( shadow_refcounts && page_is_page_table(gpage) && ! page_out_of_sync(gpage) ) { @@ -336,19 +350,21 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) break; case PGT_l1_shadow: adjust(pfn_to_page(gmfn), 0); - adjust_l1_page(smfn); + if ( shadow_refcounts ) + adjust_l1_page(smfn); if ( page->u.inuse.type_info & PGT_pinned ) adjust(page, 0); break; case PGT_hl2_shadow: adjust(pfn_to_page(gmfn), 0); - adjust_hl2_page(smfn); + if ( shadow_refcounts ) + adjust_hl2_page(smfn); if ( page->u.inuse.type_info & PGT_pinned ) adjust(page, 0); break; case PGT_l2_shadow: adjust(pfn_to_page(gmfn), 0); - adjust_l2_page(smfn); + adjust_l2_page(smfn, 1); if ( page->u.inuse.type_info & PGT_pinned ) adjust(page, 0); break; @@ -391,45 +407,43 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) struct exec_domain *ed; for_each_exec_domain(d, ed) - { - if ( !shadow_enabled ) - { - if ( pagetable_val(ed->arch.guest_table) ) - adjust(&frame_table[pagetable_val(ed->arch.guest_table) - >> PAGE_SHIFT], 1); - } - else - { - if ( pagetable_val(ed->arch.guest_table) ) - adjust(&frame_table[pagetable_val(ed->arch.guest_table) - >> PAGE_SHIFT], 0); - if ( pagetable_val(ed->arch.shadow_table) ) - adjust(&frame_table[pagetable_val(ed->arch.shadow_table) - >> PAGE_SHIFT], 0); - if ( ed->arch.monitor_shadow_ref ) - adjust(&frame_table[ed->arch.monitor_shadow_ref], 0); - } - } + { + if ( pagetable_val(ed->arch.guest_table) ) + adjust(&frame_table[pagetable_get_pfn(ed->arch.guest_table)], 1); + if ( pagetable_val(ed->arch.shadow_table) ) + adjust(&frame_table[pagetable_get_pfn(ed->arch.shadow_table)], 0); + if ( ed->arch.monitor_shadow_ref ) + adjust(&frame_table[ed->arch.monitor_shadow_ref], 0); + } } void adjust_guest_pages() { struct list_head *list_ent = d->page_list.next; struct pfn_info *page; - unsigned long mfn; + unsigned long mfn, snapshot_mfn; while ( list_ent != &d->page_list ) { u32 page_type; page = list_entry(list_ent, struct pfn_info, list); - mfn = page_to_pfn(page); + snapshot_mfn = mfn = page_to_pfn(page); page_type = page->u.inuse.type_info & PGT_type_mask; BUG_ON(page_get_owner(page) != d); page_count++; + if ( shadow_enabled && !shadow_refcounts && + page_out_of_sync(page) ) + { + unsigned long gpfn = __mfn_to_gpfn(d, mfn); + ASSERT( VALID_M2P(gpfn) ); + snapshot_mfn = __shadow_status(d, gpfn, PGT_snapshot); + ASSERT( snapshot_mfn ); + } + switch ( page_type ) { case PGT_l2_page_table: @@ -437,7 +451,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) if ( noisy ) { - if ( shadow_enabled ) + if ( shadow_refcounts ) { printk("Audit %d: found an L2 guest page " "mfn=%lx t=%08x c=%08x while in shadow mode\n", @@ -446,19 +460,22 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; } - if ( (page->u.inuse.type_info & PGT_validated) != - PGT_validated ) + if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) { - printk("Audit %d: L2 mfn=%lx not validated %08x\n", - d->id, mfn, page->u.inuse.type_info); - errors++; - } + if ( (page->u.inuse.type_info & PGT_validated) != + PGT_validated ) + { + printk("Audit %d: L2 mfn=%lx not validated %08x\n", + d->id, mfn, page->u.inuse.type_info); + errors++; + } - if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) - { - printk("Audit %d: L2 mfn=%lx not pinned t=%08x\n", - d->id, mfn, page->u.inuse.type_info); - errors++; + if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) + { + printk("Audit %d: L2 mfn=%lx not pinned t=%08x\n", + d->id, mfn, page->u.inuse.type_info); + errors++; + } } } @@ -466,7 +483,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) adjust(page, 1); if ( page->u.inuse.type_info & PGT_validated ) - adjust_l2_page(mfn); + adjust_l2_page(snapshot_mfn, 0); break; @@ -475,7 +492,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) if ( noisy ) { - if ( shadow_enabled ) + if ( shadow_refcounts ) { printk("found an L1 guest page mfn=%lx t=%08x c=%08x " "while in shadow mode\n", @@ -483,21 +500,24 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; } - if ( (page->u.inuse.type_info & PGT_validated) != PGT_validated ) + if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) { - printk("Audit %d: L1 not validated mfn=%lx t=%08x\n", - d->id, mfn, page->u.inuse.type_info); - errors++; - } - - if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) - { - if ( !VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ) + if ( (page->u.inuse.type_info & PGT_validated) != + PGT_validated ) { - printk("Audit %d: L1 mfn=%lx not pinned t=%08x\n", + printk("Audit %d: L1 not validated mfn=%lx t=%08x\n", d->id, mfn, page->u.inuse.type_info); errors++; } + + if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) + { + if ( !VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ) + { + printk("Audit %d: L1 mfn=%lx not pinned t=%08x\n", + d->id, mfn, page->u.inuse.type_info); + } + } } } @@ -505,7 +525,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) adjust(page, 1); if ( page->u.inuse.type_info & PGT_validated ) - adjust_l1_page(mfn); + adjust_l1_page(snapshot_mfn); break; @@ -520,7 +540,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) break; case PGT_writable_page: - if ( shadow_enabled ) + if ( shadow_refcounts ) { // In shadow mode, writable pages can get pinned by // paravirtualized guests that think they are pinning @@ -589,6 +609,8 @@ void audit_pagelist(struct domain *d) void _audit_domain(struct domain *d, int flags) { + int shadow_refcounts = !!shadow_mode_refcounts(d); + void scan_for_pfn_in_mfn(struct domain *d, unsigned long xmfn, unsigned long mfn) { @@ -608,8 +630,29 @@ void _audit_domain(struct domain *d, int flags) unmap_domain_mem(pt); } + void scan_for_pfn_in_grant_table(struct domain *d, unsigned xmfn) + { + int i; + active_grant_entry_t *act = d->grant_table->active; + + spin_lock(&d->grant_table->lock); + + for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) + { + if ( act[i].pin && (act[i].frame == xmfn) ) + { + printk(" found active grant table entry i=%d dom=%d pin=%d\n", + i, act[i].domid, act[i].pin); + } + } + + spin_unlock(&d->grant_table->lock); + } + void scan_for_pfn(struct domain *d, unsigned long xmfn) { + scan_for_pfn_in_grant_table(d, xmfn); + if ( !shadow_mode_enabled(d) ) { struct list_head *list_ent = d->page_list.next; @@ -688,7 +731,7 @@ void _audit_domain(struct domain *d, int flags) // Maybe we should just be using BIGLOCK? // - if ( !(flags & AUDIT_ALREADY_LOCKED) ) + if ( !(flags & AUDIT_SHADOW_ALREADY_LOCKED) ) shadow_lock(d); spin_lock(&d->page_alloc_lock); @@ -716,7 +759,7 @@ void _audit_domain(struct domain *d, int flags) errors++; } - if ( shadow_mode_enabled(d) && + if ( shadow_mode_refcounts(d) && (page_type == PGT_writable_page) && !(page->u.inuse.type_info & PGT_validated) ) { @@ -764,7 +807,9 @@ void _audit_domain(struct domain *d, int flags) mfn); errors++; } - if ( page_type != PGT_writable_page ) + if ( shadow_refcounts + ? (page_type != PGT_writable_page) + : !(page_type && (page_type <= PGT_l4_page_table)) ) { printk("out of sync page mfn=%lx has strange type " "t=%08x c=%08x\n", @@ -821,7 +866,7 @@ void _audit_domain(struct domain *d, int flags) d->id, page->u.inuse.type_info, page->tlbflush_timestamp, page->count_info, mfn); - errors++; + //errors++; } break; default: @@ -835,7 +880,7 @@ void _audit_domain(struct domain *d, int flags) page->count_info, page->u.inuse.type_info, page->tlbflush_timestamp, mfn ); - errors++; + //errors++; scan_for_pfn_remote(mfn); } @@ -870,6 +915,8 @@ void _audit_domain(struct domain *d, int flags) d->id, page_to_pfn(page), page->u.inuse.type_info, page->count_info); + printk("a->gpfn_and_flags=%p\n", + (void *)a->gpfn_and_flags); errors++; } break; @@ -905,7 +952,7 @@ void _audit_domain(struct domain *d, int flags) "pages=%d oos=%d l1=%d l2=%d ctot=%d ttot=%d\n", d->id, page_count, oos_count, l1, l2, ctot, ttot); - if ( !(flags & AUDIT_ALREADY_LOCKED) ) + if ( !(flags & AUDIT_SHADOW_ALREADY_LOCKED) ) shadow_unlock(d); if ( d != current->domain ) diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index 722317b698..a3251368ce 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -397,7 +397,7 @@ void arch_getdomaininfo_ctxt( #endif c->flags = 0; - if ( test_bit(EDF_DONEFPUINIT, &ed->ed_flags) ) + if ( test_bit(EDF_DONEFPUINIT, &ed->flags) ) c->flags |= VGCF_I387_VALID; if ( KERNEL_MODE(ed, &ed->arch.guest_context.user_regs) ) c->flags |= VGCF_IN_KERNEL; diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 3d275206b4..ebfc81387c 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -252,7 +252,7 @@ void arch_do_createdomain(struct exec_domain *ed) d->shared_info = (void *)alloc_xenheap_page(); memset(d->shared_info, 0, PAGE_SIZE); - ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid]; + ed->vcpu_info = &d->shared_info->vcpu_data[ed->id]; SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d); machine_to_phys_mapping[virt_to_phys(d->shared_info) >> PAGE_SHIFT] = INVALID_M2P_ENTRY; @@ -294,7 +294,7 @@ void arch_do_boot_vcpu(struct exec_domain *ed) struct domain *d = ed->domain; ed->arch.schedule_tail = d->exec_domain[0]->arch.schedule_tail; ed->arch.perdomain_ptes = - d->arch.mm_perdomain_pt + (ed->eid << PDPT_VCPU_SHIFT); + d->arch.mm_perdomain_pt + (ed->id << PDPT_VCPU_SHIFT); ed->arch.flags = TF_kernel_mode; } @@ -364,7 +364,8 @@ static int vmx_final_setup_guest( /* Put the domain in shadow mode even though we're going to be using * the shared 1:1 page table initially. It shouldn't hurt */ - shadow_mode_enable(ed->domain, SHM_enable|SHM_translate|SHM_external); + shadow_mode_enable(ed->domain, + SHM_enable|SHM_refcounts|SHM_translate|SHM_external); } return 0; @@ -397,9 +398,9 @@ int arch_set_info_guest( return -EINVAL; } - clear_bit(EDF_DONEFPUINIT, &ed->ed_flags); + clear_bit(EDF_DONEFPUINIT, &ed->flags); if ( c->flags & VGCF_I387_VALID ) - set_bit(EDF_DONEFPUINIT, &ed->ed_flags); + set_bit(EDF_DONEFPUINIT, &ed->flags); ed->arch.flags &= ~TF_kernel_mode; if ( c->flags & VGCF_IN_KERNEL ) @@ -415,7 +416,7 @@ int arch_set_info_guest( if ( !IS_PRIV(d) ) ed->arch.guest_context.user_regs.eflags &= 0xffffcfff; - if ( test_bit(EDF_DONEINIT, &ed->ed_flags) ) + if ( test_bit(EDF_DONEINIT, &ed->flags) ) return 0; if ( (rc = (int)set_fast_trap(ed, c->fast_trap_idx)) != 0 ) @@ -426,13 +427,13 @@ int arch_set_info_guest( for ( i = 0; i < 8; i++ ) (void)set_debugreg(ed, i, c->debugreg[i]); - if ( ed->eid == 0 ) + if ( ed->id == 0 ) d->vm_assist = c->vm_assist; phys_basetab = c->pt_base; ed->arch.guest_table = mk_pagetable(phys_basetab); - if ( shadow_mode_enabled(d) ) + if ( shadow_mode_refcounts(d) ) { if ( !get_page(&frame_table[phys_basetab>>PAGE_SHIFT], d) ) return -EINVAL; @@ -478,7 +479,7 @@ int arch_set_info_guest( update_pagetables(ed); /* Don't redo final setup */ - set_bit(EDF_DONEINIT, &ed->ed_flags); + set_bit(EDF_DONEINIT, &ed->flags); return 0; } @@ -796,7 +797,7 @@ void context_switch(struct exec_domain *prev, struct exec_domain *next) * 'prev' (after this point, a dying domain's info structure may be freed * without warning). */ - clear_bit(EDF_RUNNING, &prev->ed_flags); + clear_bit(EDF_RUNNING, &prev->flags); schedule_tail(next); BUG(); @@ -981,17 +982,21 @@ void domain_relinquish_resources(struct domain *d) { if ( pagetable_val(ed->arch.guest_table) != 0 ) { - (shadow_mode_enabled(d) ? put_page : put_page_and_type) - (&frame_table[pagetable_val( - ed->arch.guest_table) >> PAGE_SHIFT]); + if ( shadow_mode_refcounts(d) ) + put_page(&frame_table[pagetable_get_pfn(ed->arch.guest_table)]); + else + put_page_and_type(&frame_table[pagetable_get_pfn(ed->arch.guest_table)]); + ed->arch.guest_table = mk_pagetable(0); } if ( pagetable_val(ed->arch.guest_table_user) != 0 ) { - (shadow_mode_enabled(d) ? put_page : put_page_and_type) - (&frame_table[pagetable_val( - ed->arch.guest_table_user) >> PAGE_SHIFT]); + if ( shadow_mode_refcounts(d) ) + put_page(&frame_table[pagetable_get_pfn(ed->arch.guest_table_user)]); + else + put_page_and_type(&frame_table[pagetable_get_pfn(ed->arch.guest_table_user)]); + ed->arch.guest_table_user = mk_pagetable(0); } diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 5a82ac60eb..7ed67f4b6b 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -114,7 +114,7 @@ int construct_dom0(struct domain *d, /* Sanity! */ if ( d->id != 0 ) BUG(); - if ( test_bit(DF_CONSTRUCTED, &d->d_flags) ) + if ( test_bit(DF_CONSTRUCTED, &d->flags) ) BUG(); memset(&dsi, 0, sizeof(struct domain_setup_info)); @@ -540,14 +540,14 @@ int construct_dom0(struct domain *d, /* DOM0 gets access to everything. */ physdev_init_dom0(d); - set_bit(DF_CONSTRUCTED, &d->d_flags); + set_bit(DF_CONSTRUCTED, &d->flags); new_thread(ed, dsi.v_kernentry, vstack_end, vstartinfo_start); if ( opt_dom0_shadow || opt_dom0_translate ) { shadow_mode_enable(d, (opt_dom0_translate - ? SHM_enable | SHM_translate + ? SHM_enable | SHM_refcounts | SHM_translate : SHM_enable)); if ( opt_dom0_translate ) { @@ -570,7 +570,7 @@ int construct_dom0(struct domain *d, idle_pg_table[1] = root_create_phys(pagetable_val(d->arch.phys_table), __PAGE_HYPERVISOR); translate_l2pgtable(d, (l1_pgentry_t *)(1u << L2_PAGETABLE_SHIFT), - pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT); + pagetable_get_pfn(ed->arch.guest_table)); idle_pg_table[1] = root_empty(); local_flush_tlb(); } diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c index 08dc9fdcb7..af54d0af8a 100644 --- a/xen/arch/x86/i387.c +++ b/xen/arch/x86/i387.c @@ -18,7 +18,7 @@ void init_fpu(void) __asm__ __volatile__ ( "fninit" ); if ( cpu_has_xmm ) load_mxcsr(0x1f80); - set_bit(EDF_DONEFPUINIT, ¤t->ed_flags); + set_bit(EDF_DONEFPUINIT, ¤t->flags); } void save_init_fpu(struct exec_domain *tsk) @@ -28,7 +28,7 @@ void save_init_fpu(struct exec_domain *tsk) * This causes us to set the real flag, so we'll need * to temporarily clear it while saving f-p state. */ - if ( test_bit(EDF_GUEST_STTS, &tsk->ed_flags) ) + if ( test_bit(EDF_GUEST_STTS, &tsk->flags) ) clts(); if ( cpu_has_fxsr ) @@ -40,7 +40,7 @@ void save_init_fpu(struct exec_domain *tsk) "fnsave %0 ; fwait" : "=m" (tsk->arch.guest_context.fpu_ctxt) ); - clear_bit(EDF_USEDFPU, &tsk->ed_flags); + clear_bit(EDF_USEDFPU, &tsk->flags); stts(); } diff --git a/xen/arch/x86/i8259.c b/xen/arch/x86/i8259.c index 62eb07ada0..8111260050 100644 --- a/xen/arch/x86/i8259.c +++ b/xen/arch/x86/i8259.c @@ -45,7 +45,7 @@ BUILD_COMMON_IRQ() /* * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: - * (these are usually mapped to vectors 0x30-0x3f) + * (these are usually mapped to vectors 0x20-0x2f) */ BUILD_16_IRQS(0x0) @@ -58,7 +58,7 @@ BUILD_16_IRQS(0x0) * of these. Plus, more powerful systems might have more than 64 * IO-APIC registers. * - * (these are usually mapped into the 0x30-0xff vector range) + * (these are usually mapped into the 0x20-0xff vector range) */ BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) @@ -101,7 +101,7 @@ BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) - void *interrupt[NR_IRQS] = { + void (*interrupt[NR_IRQS])(void) = { IRQLIST_16(0x0), #ifdef CONFIG_X86_IO_APIC @@ -341,7 +341,7 @@ void __init init_8259A(int auto_eoi) * outb_p - this has to work on a wide range of PC hardware. */ outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ - outb_p(0x30 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */ + outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */ outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ if (auto_eoi) outb_p(0x03, 0x21); /* master does Auto EOI */ @@ -349,7 +349,7 @@ void __init init_8259A(int auto_eoi) outb_p(0x01, 0x21); /* master expects normal EOI */ outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ - outb_p(0x30 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x38-0x3f */ + outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */ outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode is to be investigated) */ diff --git a/xen/arch/x86/idle0_task.c b/xen/arch/x86/idle0_task.c index 71fbc34dd6..43c0c31c25 100644 --- a/xen/arch/x86/idle0_task.c +++ b/xen/arch/x86/idle0_task.c @@ -5,7 +5,7 @@ struct domain idle0_domain = { id: IDLE_DOMAIN_ID, - d_flags: 1< #include #include -#include -#include +#include #include -#include -#include +#include #include #include -#include +#include +#include -#ifdef CONFIG_X86_IO_APIC +int (*ioapic_renumber_irq)(int ioapic, int irq); +atomic_t irq_mis_count; -#undef APIC_LOCKUP_DEBUG - -#define APIC_LOCKUP_DEBUG - -static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; - -unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL; -unsigned char int_delivery_mode = dest_LowestPrio; +static DEFINE_SPINLOCK(ioapic_lock); +int skip_ioapic_setup; /* * # of IRQ routing registers @@ -69,12 +63,20 @@ static struct irq_pin_list { int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; +int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; +#ifdef CONFIG_PCI_MSI +#define vector_to_irq(vector) \ + (platform_legacy_irq(vector) ? vector : vector_irq[vector]) +#else +#define vector_to_irq(vector) (vector) +#endif + /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void __init add_pin_to_irq(unsigned int irq, int apic, int pin) +static void add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; @@ -112,36 +114,48 @@ static void __init replace_pin_at_irq(unsigned int irq, } } -#define __DO_ACTION(R, ACTION, FINAL) \ - \ -{ \ - int pin; \ - struct irq_pin_list *entry = irq_2_pin + irq; \ - \ - for (;;) { \ - unsigned int reg; \ - pin = entry->pin; \ - if (pin == -1) \ - break; \ - reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ - reg ACTION; \ - io_apic_write(entry->apic, 0x10 + R + pin*2, reg); \ - if (!entry->next) \ - break; \ - entry = irq_2_pin + entry->next; \ - } \ - FINAL; \ +static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable) +{ + struct irq_pin_list *entry = irq_2_pin + irq; + unsigned int pin, reg; + + for (;;) { + pin = entry->pin; + if (pin == -1) + break; + reg = io_apic_read(entry->apic, 0x10 + pin*2); + reg &= ~disable; + reg |= enable; + io_apic_modify(entry->apic, 0x10 + pin*2, reg); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } } -#define DO_ACTION(name,R,ACTION, FINAL) \ - \ - static void name##_IO_APIC_irq (unsigned int irq) \ - __DO_ACTION(R, ACTION, FINAL) +/* mask = 1 */ +static void __mask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00010000, 0); +} -DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) -DO_ACTION( __unmask, 0, &= 0xfffeffff, ) -DO_ACTION( __edge, 0, &= 0xffff7fff, ) -DO_ACTION( __level, 0, |= 0x00008000, ) +/* mask = 0 */ +static void __unmask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0, 0x00010000); +} + +/* trigger = 0 */ +static void __edge_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0, 0x00008000); +} + +/* trigger = 1 */ +static void __level_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00008000, 0); +} static void mask_IO_APIC_irq (unsigned int irq) { @@ -165,7 +179,7 @@ void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; unsigned long flags; - + /* Check delivery_mode to be sure we're not clearing an SMI pin */ spin_lock_irqsave(&ioapic_lock, flags); *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); @@ -194,85 +208,467 @@ static void clear_IO_APIC (void) clear_IO_APIC_pin(apic, pin); } -static void set_ioapic_affinity (unsigned int irq, unsigned long mask) +static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) { unsigned long flags; - - /* - * Only the first 8 bits are valid. - */ - mask = mask << 24; + int pin; + struct irq_pin_list *entry = irq_2_pin + irq; + unsigned int apicid_value; + + apicid_value = cpu_mask_to_apicid(cpumask); + /* Prepare to do the io_apic_write */ + apicid_value = apicid_value << 24; spin_lock_irqsave(&ioapic_lock, flags); - __DO_ACTION(1, = mask, ) + for (;;) { + pin = entry->pin; + if (pin == -1) + break; + io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } spin_unlock_irqrestore(&ioapic_lock, flags); } -#define balance_irq(_irq) ((void)0) +#if defined(CONFIG_IRQBALANCE) +# include /* kernel_thread() */ +# include /* kstat */ +# include /* kmalloc() */ +# include /* time_after() */ + +# ifdef CONFIG_BALANCED_IRQ_DEBUG +# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0) +# define Dprintk(x...) do { TDprintk(x); } while (0) +# else +# define TDprintk(x...) +# define Dprintk(x...) +# endif -/* - * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to - * specific CPU-side IRQs. - */ +cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS]; -#define MAX_PIRQS 8 -int pirq_entries [MAX_PIRQS]; -int pirqs_enabled; +#define IRQBALANCE_CHECK_ARCH -999 +static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; +static int physical_balance = 0; -int skip_ioapic_setup; -#if 0 +struct irq_cpu_info { + unsigned long * last_irq; + unsigned long * irq_delta; + unsigned long irq; +} irq_cpu_data[NR_CPUS]; -static int __init noioapic_setup(char *str) +#define CPU_IRQ(cpu) (irq_cpu_data[cpu].irq) +#define LAST_CPU_IRQ(cpu,irq) (irq_cpu_data[cpu].last_irq[irq]) +#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq]) + +#define IDLE_ENOUGH(cpu,now) \ + (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1)) + +#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask) + +#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) + +#define MAX_BALANCED_IRQ_INTERVAL (5*HZ) +#define MIN_BALANCED_IRQ_INTERVAL (HZ/2) +#define BALANCED_IRQ_MORE_DELTA (HZ/10) +#define BALANCED_IRQ_LESS_DELTA (HZ) + +long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL; + +static unsigned long move(int curr_cpu, cpumask_t allowed_mask, + unsigned long now, int direction) { - skip_ioapic_setup = 1; - return 1; + int search_idle = 1; + int cpu = curr_cpu; + + goto inside; + + do { + if (unlikely(cpu == curr_cpu)) + search_idle = 0; +inside: + if (direction == 1) { + cpu++; + if (cpu >= NR_CPUS) + cpu = 0; + } else { + cpu--; + if (cpu == -1) + cpu = NR_CPUS-1; + } + } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) || + (search_idle && !IDLE_ENOUGH(cpu,now))); + + return cpu; } -__setup("noapic", noioapic_setup); - -static int __init ioapic_setup(char *str) +static inline void balance_irq(int cpu, int irq) { - skip_ioapic_setup = 0; - return 1; -} + unsigned long now = jiffies; + cpumask_t allowed_mask; + unsigned int new_cpu; + + if (irqbalance_disabled) + return; -__setup("apic", ioapic_setup); + cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]); + new_cpu = move(cpu, allowed_mask, now, 1); + if (cpu != new_cpu) { + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; - - -static int __init ioapic_pirq_setup(char *str) -{ - int i, max; - int ints[MAX_PIRQS+1]; - - get_options(str, ARRAY_SIZE(ints), ints); - - for (i = 0; i < MAX_PIRQS; i++) - pirq_entries[i] = -1; - - pirqs_enabled = 1; - printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); - max = MAX_PIRQS; - if (ints[0] < MAX_PIRQS) - max = ints[0]; - - for (i = 0; i < max; i++) { - printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); - /* - * PIRQs are mapped upside down, usually. - */ - pirq_entries[MAX_PIRQS-i-1] = ints[i+1]; + spin_lock_irqsave(&desc->lock, flags); + pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu); + spin_unlock_irqrestore(&desc->lock, flags); } - return 1; } -__setup("pirq=", ioapic_pirq_setup); +static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold) +{ + int i, j; + Dprintk("Rotating IRQs among CPUs.\n"); + for (i = 0; i < NR_CPUS; i++) { + for (j = 0; cpu_online(i) && (j < NR_IRQS); j++) { + if (!irq_desc[j].action) + continue; + /* Is it a significant load ? */ + if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) < + useful_load_threshold) + continue; + balance_irq(i, j); + } + } + balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, + balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); + return; +} -#endif +static void do_irq_balance(void) +{ + int i, j; + unsigned long max_cpu_irq = 0, min_cpu_irq = (~0); + unsigned long move_this_load = 0; + int max_loaded = 0, min_loaded = 0; + int load; + unsigned long useful_load_threshold = balanced_irq_interval + 10; + int selected_irq; + int tmp_loaded, first_attempt = 1; + unsigned long tmp_cpu_irq; + unsigned long imbalance = 0; + cpumask_t allowed_mask, target_cpu_mask, tmp; + + for (i = 0; i < NR_CPUS; i++) { + int package_index; + CPU_IRQ(i) = 0; + if (!cpu_online(i)) + continue; + package_index = CPU_TO_PACKAGEINDEX(i); + for (j = 0; j < NR_IRQS; j++) { + unsigned long value_now, delta; + /* Is this an active IRQ? */ + if (!irq_desc[j].action) + continue; + if ( package_index == i ) + IRQ_DELTA(package_index,j) = 0; + /* Determine the total count per processor per IRQ */ + value_now = (unsigned long) kstat_cpu(i).irqs[j]; + + /* Determine the activity per processor per IRQ */ + delta = value_now - LAST_CPU_IRQ(i,j); + + /* Update last_cpu_irq[][] for the next time */ + LAST_CPU_IRQ(i,j) = value_now; + + /* Ignore IRQs whose rate is less than the clock */ + if (delta < useful_load_threshold) + continue; + /* update the load for the processor or package total */ + IRQ_DELTA(package_index,j) += delta; + + /* Keep track of the higher numbered sibling as well */ + if (i != package_index) + CPU_IRQ(i) += delta; + /* + * We have sibling A and sibling B in the package + * + * cpu_irq[A] = load for cpu A + load for cpu B + * cpu_irq[B] = load for cpu B + */ + CPU_IRQ(package_index) += delta; + } + } + /* Find the least loaded processor package */ + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (i != CPU_TO_PACKAGEINDEX(i)) + continue; + if (min_cpu_irq > CPU_IRQ(i)) { + min_cpu_irq = CPU_IRQ(i); + min_loaded = i; + } + } + max_cpu_irq = ULONG_MAX; + +tryanothercpu: + /* Look for heaviest loaded processor. + * We may come back to get the next heaviest loaded processor. + * Skip processors with trivial loads. + */ + tmp_cpu_irq = 0; + tmp_loaded = -1; + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (i != CPU_TO_PACKAGEINDEX(i)) + continue; + if (max_cpu_irq <= CPU_IRQ(i)) + continue; + if (tmp_cpu_irq < CPU_IRQ(i)) { + tmp_cpu_irq = CPU_IRQ(i); + tmp_loaded = i; + } + } + + if (tmp_loaded == -1) { + /* In the case of small number of heavy interrupt sources, + * loading some of the cpus too much. We use Ingo's original + * approach to rotate them around. + */ + if (!first_attempt && imbalance >= useful_load_threshold) { + rotate_irqs_among_cpus(useful_load_threshold); + return; + } + goto not_worth_the_effort; + } + + first_attempt = 0; /* heaviest search */ + max_cpu_irq = tmp_cpu_irq; /* load */ + max_loaded = tmp_loaded; /* processor */ + imbalance = (max_cpu_irq - min_cpu_irq) / 2; + + Dprintk("max_loaded cpu = %d\n", max_loaded); + Dprintk("min_loaded cpu = %d\n", min_loaded); + Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq); + Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq); + Dprintk("load imbalance = %lu\n", imbalance); + + /* if imbalance is less than approx 10% of max load, then + * observe diminishing returns action. - quit + */ + if (imbalance < (max_cpu_irq >> 3)) { + Dprintk("Imbalance too trivial\n"); + goto not_worth_the_effort; + } + +tryanotherirq: + /* if we select an IRQ to move that can't go where we want, then + * see if there is another one to try. + */ + move_this_load = 0; + selected_irq = -1; + for (j = 0; j < NR_IRQS; j++) { + /* Is this an active IRQ? */ + if (!irq_desc[j].action) + continue; + if (imbalance <= IRQ_DELTA(max_loaded,j)) + continue; + /* Try to find the IRQ that is closest to the imbalance + * without going over. + */ + if (move_this_load < IRQ_DELTA(max_loaded,j)) { + move_this_load = IRQ_DELTA(max_loaded,j); + selected_irq = j; + } + } + if (selected_irq == -1) { + goto tryanothercpu; + } + + imbalance = move_this_load; + + /* For physical_balance case, we accumlated both load + * values in the one of the siblings cpu_irq[], + * to use the same code for physical and logical processors + * as much as possible. + * + * NOTE: the cpu_irq[] array holds the sum of the load for + * sibling A and sibling B in the slot for the lowest numbered + * sibling (A), _AND_ the load for sibling B in the slot for + * the higher numbered sibling. + * + * We seek the least loaded sibling by making the comparison + * (A+B)/2 vs B + */ + load = CPU_IRQ(min_loaded) >> 1; + for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) { + if (load > CPU_IRQ(j)) { + /* This won't change cpu_sibling_map[min_loaded] */ + load = CPU_IRQ(j); + min_loaded = j; + } + } + + cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]); + target_cpu_mask = cpumask_of_cpu(min_loaded); + cpus_and(tmp, target_cpu_mask, allowed_mask); + + if (!cpus_empty(tmp)) { + irq_desc_t *desc = irq_desc + selected_irq; + unsigned long flags; + + Dprintk("irq = %d moved to cpu = %d\n", + selected_irq, min_loaded); + /* mark for change destination */ + spin_lock_irqsave(&desc->lock, flags); + pending_irq_balance_cpumask[selected_irq] = + cpumask_of_cpu(min_loaded); + spin_unlock_irqrestore(&desc->lock, flags); + /* Since we made a change, come back sooner to + * check for more variation. + */ + balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, + balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); + return; + } + goto tryanotherirq; + +not_worth_the_effort: + /* + * if we did not find an IRQ to move, then adjust the time interval + * upward + */ + balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL, + balanced_irq_interval + BALANCED_IRQ_MORE_DELTA); + Dprintk("IRQ worth rotating not found\n"); + return; +} + +static int balanced_irq(void *unused) +{ + int i; + unsigned long prev_balance_time = jiffies; + long time_remaining = balanced_irq_interval; + + daemonize("kirqd"); + + /* push everything to CPU 0 to give us a starting point. */ + for (i = 0 ; i < NR_IRQS ; i++) { + pending_irq_balance_cpumask[i] = cpumask_of_cpu(0); + } + + for ( ; ; ) { + set_current_state(TASK_INTERRUPTIBLE); + time_remaining = schedule_timeout(time_remaining); + try_to_freeze(PF_FREEZE); + if (time_after(jiffies, + prev_balance_time+balanced_irq_interval)) { + do_irq_balance(); + prev_balance_time = jiffies; + time_remaining = balanced_irq_interval; + } + } + return 0; +} + +static int __init balanced_irq_init(void) +{ + int i; + struct cpuinfo_x86 *c; + cpumask_t tmp; + + cpus_shift_right(tmp, cpu_online_map, 2); + c = &boot_cpu_data; + /* When not overwritten by the command line ask subarchitecture. */ + if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) + irqbalance_disabled = NO_BALANCE_IRQ; + if (irqbalance_disabled) + return 0; + + /* disable irqbalance completely if there is only one processor online */ + if (num_online_cpus() < 2) { + irqbalance_disabled = 1; + return 0; + } + /* + * Enable physical balance only if more than 1 physical processor + * is present + */ + if (smp_num_siblings > 1 && !cpus_empty(tmp)) + physical_balance = 1; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); + irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); + if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) { + printk(KERN_ERR "balanced_irq_init: out of memory"); + goto failed; + } + memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS); + memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS); + } + + printk(KERN_INFO "Starting balanced_irq\n"); + if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) + return 0; + else + printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); +failed: + for (i = 0; i < NR_CPUS; i++) { + if(irq_cpu_data[i].irq_delta) + kfree(irq_cpu_data[i].irq_delta); + if(irq_cpu_data[i].last_irq) + kfree(irq_cpu_data[i].last_irq); + } + return 0; +} + +int __init irqbalance_disable(char *str) +{ + irqbalance_disabled = 1; + return 0; +} + +__setup("noirqbalance", irqbalance_disable); + +static inline void move_irq(int irq) +{ + /* note - we hold the desc->lock */ + if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) { + set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]); + cpus_clear(pending_irq_balance_cpumask[irq]); + } +} + +late_initcall(balanced_irq_init); + +#else /* !CONFIG_IRQBALANCE */ +static inline void move_irq(int irq) { } +#endif /* CONFIG_IRQBALANCE */ + +#ifndef CONFIG_SMP +void fastcall send_IPI_self(int vector) +{ + unsigned int cfg; + + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL; + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write_around(APIC_ICR, cfg); +} +#endif /* !CONFIG_SMP */ /* * Find the IRQ entry number of a certain pin. */ -static int __init find_irq_entry(int apic, int pin, int type) +static int find_irq_entry(int apic, int pin, int type) { int i; @@ -289,7 +685,7 @@ static int __init find_irq_entry(int apic, int pin, int type) /* * Find the pin to which IRQ[irq] (ISA) is connected */ -static int __init find_isa_irq_pin(int irq, int type) +static int find_isa_irq_pin(int irq, int type) { int i; @@ -298,7 +694,9 @@ static int __init find_isa_irq_pin(int irq, int type) if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || mp_bus_id_to_type[lbus] == MP_BUS_EISA || - mp_bus_id_to_type[lbus] == MP_BUS_MCA) && + mp_bus_id_to_type[lbus] == MP_BUS_MCA || + mp_bus_id_to_type[lbus] == MP_BUS_NEC98 + ) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == irq)) @@ -313,16 +711,81 @@ static int __init find_isa_irq_pin(int irq, int type) */ static int pin_2_irq(int idx, int apic, int pin); +int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) +{ + int apic, i, best_guess = -1; + + apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " + "slot:%d, pin:%d.\n", bus, slot, pin); + if (mp_bus_id_to_pci_bus[bus] == -1) { + printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); + return -1; + } + for (i = 0; i < mp_irq_entries; i++) { + int lbus = mp_irqs[i].mpc_srcbus; + + for (apic = 0; apic < nr_ioapics; apic++) + if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || + mp_irqs[i].mpc_dstapic == MP_APIC_ALL) + break; + + if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) && + !mp_irqs[i].mpc_irqtype && + (bus == lbus) && + (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { + int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); + + if (!(apic || IO_APIC_IRQ(irq))) + continue; + + if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) + return irq; + /* + * Use the first all-but-pin matching entry as a + * best-guess fuzzy result for broken mptables. + */ + if (best_guess < 0) + best_guess = irq; + } + } + return best_guess; +} + +/* + * This function currently is only a helper for the i386 smp boot process where + * we need to reprogram the ioredtbls to cater for the cpus which have come online + * so mask in all cases should simply be TARGET_CPUS + */ +void __init setup_ioapic_dest(void) +{ + int pin, ioapic, irq, irq_entry; + + if (skip_ioapic_setup == 1) + return; + + for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { + for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { + irq_entry = find_irq_entry(ioapic, pin, mp_INT); + if (irq_entry == -1) + continue; + irq = pin_2_irq(irq_entry, ioapic, pin); + set_ioapic_affinity_irq(irq, TARGET_CPUS); + } + + } +} + /* * EISA Edge/Level control register, ELCR */ -static int __init EISA_ELCR(unsigned int irq) +static int EISA_ELCR(unsigned int irq) { if (irq < 16) { unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } - printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); + apic_printk(APIC_VERBOSE, KERN_INFO + "Broken MPtable reports ISA irq %d\n", irq); return 0; } @@ -352,6 +815,12 @@ static int __init EISA_ELCR(unsigned int irq) #define default_MCA_trigger(idx) (1) #define default_MCA_polarity(idx) (0) +/* NEC98 interrupts are always polarity zero edge triggered, + * when listed as conforming in the MP table. */ + +#define default_NEC98_trigger(idx) (0) +#define default_NEC98_polarity(idx) (0) + static int __init MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; @@ -386,6 +855,11 @@ static int __init MPBIOS_polarity(int idx) polarity = default_MCA_polarity(idx); break; } + case MP_BUS_NEC98: /* NEC 98 pin */ + { + polarity = default_NEC98_polarity(idx); + break; + } default: { printk(KERN_WARNING "broken BIOS!!\n"); @@ -421,7 +895,7 @@ static int __init MPBIOS_polarity(int idx) return polarity; } -static int __init MPBIOS_trigger(int idx) +static int MPBIOS_trigger(int idx) { int bus = mp_irqs[idx].mpc_srcbus; int trigger; @@ -455,6 +929,11 @@ static int __init MPBIOS_trigger(int idx) trigger = default_MCA_trigger(idx); break; } + case MP_BUS_NEC98: /* NEC 98 pin */ + { + trigger = default_NEC98_trigger(idx); + break; + } default: { printk(KERN_WARNING "broken BIOS!!\n"); @@ -516,6 +995,7 @@ static int pin_2_irq(int idx, int apic, int pin) case MP_BUS_ISA: /* ISA pin */ case MP_BUS_EISA: case MP_BUS_MCA: + case MP_BUS_NEC98: { irq = mp_irqs[idx].mpc_srcbusirq; break; @@ -529,6 +1009,13 @@ static int pin_2_irq(int idx, int apic, int pin) while (i < apic) irq += nr_ioapic_registers[i++]; irq += pin; + + /* + * For MPS mode, so far only needed by ES7000 platform + */ + if (ioapic_renumber_irq) + irq = ioapic_renumber_irq(apic, irq); + break; } default: @@ -539,20 +1026,6 @@ static int pin_2_irq(int idx, int apic, int pin) } } - /* - * PCI IRQ command line redirection. Yes, limits are hardcoded. - */ - if ((pin >= 16) && (pin <= 23)) { - if (pirq_entries[pin-16] != -1) { - if (!pirq_entries[pin-16]) { - printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); - } else { - irq = pirq_entries[pin-16]; - printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", - pin-16, irq); - } - } - } return irq; } @@ -573,90 +1046,74 @@ static inline int IO_APIC_irq_trigger(int irq) return 0; } -int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 }; - -int vector_irq[256]; +/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ +u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; int assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; - if (IO_APIC_VECTOR(irq) > 0) + + BUG_ON(irq >= NR_IRQ_VECTORS); + if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) return IO_APIC_VECTOR(irq); next: current_vector += 8; - /* Skip the hypercall vector. */ - if (current_vector == HYPERCALL_VECTOR) goto next; - /* Skip the Linux/BSD fast-trap vector. */ - if (current_vector == 0x80) goto next; + /* Skip the hypercall vector. */ + if (current_vector == HYPERCALL_VECTOR) + goto next; - if (current_vector > FIRST_SYSTEM_VECTOR) { + /* Skip the Linux/BSD fast-trap vector. */ + if (current_vector == 0x80) + goto next; + + if (current_vector >= FIRST_SYSTEM_VECTOR) { offset++; + if (!(offset%8)) + return -ENOSPC; current_vector = FIRST_DEVICE_VECTOR + offset; } - if (current_vector == FIRST_SYSTEM_VECTOR) - panic("ran out of interrupt sources!"); - - IO_APIC_VECTOR(irq) = current_vector; - - vector_irq[current_vector] = irq; + vector_irq[current_vector] = irq; + if (irq != AUTO_ASSIGN) + IO_APIC_VECTOR(irq) = current_vector; return current_vector; } -extern void (*interrupt[NR_IRQS])(void); +static struct hw_interrupt_type ioapic_level_type; +static struct hw_interrupt_type ioapic_edge_type; -/* - * Level and edge triggered IO-APIC interrupts need different handling, - * so we use two separate IRQ descriptors. Edge triggered IRQs can be - * handled with the level-triggered descriptor, but that one has slightly - * more overhead. Level-triggered interrupts cannot be handled with the - * edge-triggered handler, without risking IRQ storms and other ugly - * races. - */ +#define IOAPIC_AUTO -1 +#define IOAPIC_EDGE 0 +#define IOAPIC_LEVEL 1 -static unsigned int startup_edge_ioapic_irq(unsigned int irq); -#define shutdown_edge_ioapic_irq disable_edge_ioapic_irq -#define enable_edge_ioapic_irq unmask_IO_APIC_irq -static void disable_edge_ioapic_irq (unsigned int irq); -static void ack_edge_ioapic_irq(unsigned int irq); -static void end_edge_ioapic_irq (unsigned int i); -static struct hw_interrupt_type ioapic_edge_irq_type = { - "IO-APIC-edge", - startup_edge_ioapic_irq, - shutdown_edge_ioapic_irq, - enable_edge_ioapic_irq, - disable_edge_ioapic_irq, - ack_edge_ioapic_irq, - end_edge_ioapic_irq, - set_ioapic_affinity, -}; - -static unsigned int startup_level_ioapic_irq (unsigned int irq); -#define shutdown_level_ioapic_irq mask_IO_APIC_irq -#define enable_level_ioapic_irq unmask_IO_APIC_irq -#define disable_level_ioapic_irq mask_IO_APIC_irq -static void mask_and_ack_level_ioapic_irq (unsigned int irq); -static void end_level_ioapic_irq (unsigned int irq); -static struct hw_interrupt_type ioapic_level_irq_type = { - "IO-APIC-level", - startup_level_ioapic_irq, - shutdown_level_ioapic_irq, - enable_level_ioapic_irq, - disable_level_ioapic_irq, - mask_and_ack_level_ioapic_irq, - end_level_ioapic_irq, - set_ioapic_affinity, -}; +static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger) +{ + if (use_pci_vector() && !platform_legacy_irq(irq)) { + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) + irq_desc[vector].handler = &ioapic_level_type; + else + irq_desc[vector].handler = &ioapic_edge_type; + set_intr_gate(vector, interrupt[vector]); + } else { + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) + irq_desc[irq].handler = &ioapic_level_type; + else + irq_desc[irq].handler = &ioapic_edge_type; + set_intr_gate(vector, interrupt[irq]); + } +} void __init setup_IO_APIC_irqs(void) { struct IO_APIC_route_entry entry; - int apic, pin, idx, irq, vector; + int apic, pin, idx, irq, first_notcon = 1, vector; unsigned long flags; - printk(KERN_DEBUG "init IO_APIC IRQs\n"); + apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -667,13 +1124,24 @@ void __init setup_IO_APIC_irqs(void) memset(&entry,0,sizeof(entry)); entry.delivery_mode = INT_DELIVERY_MODE; - entry.dest_mode = (INT_DEST_ADDR_MODE != 0); + entry.dest_mode = INT_DEST_MODE; entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = target_cpus(); + entry.dest.logical.logical_dest = + cpu_mask_to_apicid(TARGET_CPUS); idx = find_irq_entry(apic,pin,mp_INT); - if (idx == -1) + if (idx == -1) { + if (first_notcon) { + apic_printk(APIC_VERBOSE, KERN_DEBUG + " IO-APIC (apicid-pin) %d-%d", + mp_ioapics[apic].mpc_apicid, + pin); + first_notcon = 0; + } else + apic_printk(APIC_VERBOSE, ", %d-%d", + mp_ioapics[apic].mpc_apicid, pin); continue; + } entry.trigger = irq_trigger(idx); entry.polarity = irq_polarity(idx); @@ -688,8 +1156,7 @@ void __init setup_IO_APIC_irqs(void) * skip adding the timer int on secondary nodes, which causes * a small but painful rift in the time-space continuum */ - if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) - && (apic != 0) && (irq == 0)) + if (multi_timer_check(apic, irq)) continue; else add_pin_to_irq(irq, apic, pin); @@ -700,13 +1167,7 @@ void __init setup_IO_APIC_irqs(void) if (IO_APIC_IRQ(irq)) { vector = assign_irq_vector(irq); entry.vector = vector; - - if (IO_APIC_irq_trigger(irq)) - irq_desc[irq].handler = &ioapic_level_irq_type; - else - irq_desc[irq].handler = &ioapic_edge_irq_type; - - set_intr_gate(vector, interrupt[irq]); + ioapic_register_intr(irq, vector, IOAPIC_AUTO); if (!apic && (irq < 16)) disable_8259A_irq(irq); @@ -717,11 +1178,13 @@ void __init setup_IO_APIC_irqs(void) spin_unlock_irqrestore(&ioapic_lock, flags); } } + + if (!first_notcon) + apic_printk(APIC_VERBOSE, " not connected.\n"); } /* - * Set up the 8259A-master output pin as broadcast to all - * CPUs. + * Set up the 8259A-master output pin: */ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) { @@ -739,9 +1202,9 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) * We use logical delivery to get the timer IRQ * to the first CPU. */ - entry.dest_mode = (INT_DEST_ADDR_MODE != 0); + entry.dest_mode = INT_DEST_MODE; entry.mask = 0; /* unmask IRQ now */ - entry.dest.logical.logical_dest = target_cpus(); + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.delivery_mode = INT_DELIVERY_MODE; entry.polarity = 0; entry.trigger = 0; @@ -751,7 +1214,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) * The timer IRQ doesn't have to know that behind the * scene we have a 8259A-master in AEOI mode ... */ - irq_desc[0].handler = &ioapic_edge_irq_type; + irq_desc[0].handler = &ioapic_edge_type; /* * Add it to the IO-APIC irq-routing table: @@ -764,23 +1227,22 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) enable_8259A_irq(0); } -void __init UNEXPECTED_IO_APIC(void) +static inline void UNEXPECTED_IO_APIC(void) { - printk(KERN_WARNING - "An unexpected IO-APIC was found. If this kernel release is less than\n" - "three months old please report this to linux-smp@vger.kernel.org\n"); } void __init print_IO_APIC(void) { -#ifdef VERBOSE int apic, i; - struct IO_APIC_reg_00 reg_00; - struct IO_APIC_reg_01 reg_01; - struct IO_APIC_reg_02 reg_02; - struct IO_APIC_reg_03 reg_03; + union IO_APIC_reg_00 reg_00; + union IO_APIC_reg_01 reg_01; + union IO_APIC_reg_02 reg_02; + union IO_APIC_reg_03 reg_03; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", @@ -795,47 +1257,46 @@ void __init print_IO_APIC(void) for (apic = 0; apic < nr_ioapics; apic++) { spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(apic, 0); - *(int *)®_01 = io_apic_read(apic, 1); - if (reg_01.version >= 0x10) - *(int *)®_02 = io_apic_read(apic, 2); - if (reg_01.version >= 0x20) - *(int *)®_03 = io_apic_read(apic, 3); + reg_00.raw = io_apic_read(apic, 0); + reg_01.raw = io_apic_read(apic, 1); + if (reg_01.bits.version >= 0x10) + reg_02.raw = io_apic_read(apic, 2); + if (reg_01.bits.version >= 0x20) + reg_03.raw = io_apic_read(apic, 3); spin_unlock_irqrestore(&ioapic_lock, flags); - printk("\n"); printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); - printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)®_00); - printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.ID); - printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.delivery_type); - printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.LTS); - if (reg_00.__reserved_0 || reg_00.__reserved_1 || reg_00.__reserved_2) + printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); + printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); + printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); + printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); + if (reg_00.bits.ID >= get_physical_broadcast()) + UNEXPECTED_IO_APIC(); + if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) UNEXPECTED_IO_APIC(); - printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); - printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.entries); - if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */ - (reg_01.entries != 0x17) && /* typical ISA+PCI boards */ - (reg_01.entries != 0x1b) && /* Compaq Proliant boards */ - (reg_01.entries != 0x1f) && /* dual Xeon boards */ - (reg_01.entries != 0x22) && /* bigger Xeon boards */ - (reg_01.entries != 0x2E) && - (reg_01.entries != 0x3F) + printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw); + printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); + if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ + (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ + (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ + (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ + (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ + (reg_01.bits.entries != 0x2E) && + (reg_01.bits.entries != 0x3F) ) UNEXPECTED_IO_APIC(); - printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.PRQ); - printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.version); - if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */ - (reg_01.version != 0x02) && /* VIA */ - (reg_01.version != 0x03) && /* later VIA */ - (reg_01.version != 0x10) && /* oldest IO-APICs */ - (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */ - (reg_01.version != 0x13) && /* Xeon IO-APICs */ - (reg_01.version != 0x20) /* Intel P64H (82806 AA) */ + printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); + printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); + if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ + (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ + (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ + (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ + (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ ) UNEXPECTED_IO_APIC(); - if (reg_01.__reserved_1 || reg_01.__reserved_2) + if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) UNEXPECTED_IO_APIC(); /* @@ -843,10 +1304,10 @@ void __init print_IO_APIC(void) * but the value of reg_02 is read as the previous read register * value, so ignore it if reg_02 == reg_01. */ - if (reg_01.version >= 0x10 && *(int *)®_02 != *(int *)®_01) { - printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)®_02); - printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration); - if (reg_02.__reserved_1 || reg_02.__reserved_2) + if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) { + printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); + printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); + if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) UNEXPECTED_IO_APIC(); } @@ -855,11 +1316,11 @@ void __init print_IO_APIC(void) * or reg_03, but the value of reg_0[23] is read as the previous read * register value, so ignore it if reg_03 == reg_0[12]. */ - if (reg_01.version >= 0x20 && *(int *)®_03 != *(int *)®_02 && - *(int *)®_03 != *(int *)®_01) { - printk(KERN_DEBUG ".... register #03: %08X\n", *(int *)®_03); - printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.boot_DT); - if (reg_03.__reserved_1) + if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw && + reg_03.raw != reg_01.raw) { + printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw); + printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT); + if (reg_03.bits.__reserved_1) UNEXPECTED_IO_APIC(); } @@ -868,7 +1329,7 @@ void __init print_IO_APIC(void) printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" " Stat Dest Deli Vect: \n"); - for (i = 0; i <= reg_01.entries; i++) { + for (i = 0; i <= reg_01.bits.entries; i++) { struct IO_APIC_route_entry entry; spin_lock_irqsave(&ioapic_lock, flags); @@ -894,12 +1355,17 @@ void __init print_IO_APIC(void) ); } } + if (use_pci_vector()) + printk(KERN_INFO "Using vector-based indexing\n"); printk(KERN_DEBUG "IRQ to pin mappings:\n"); for (i = 0; i < NR_IRQS; i++) { struct irq_pin_list *entry = irq_2_pin + i; if (entry->pin < 0) continue; - printk(KERN_DEBUG "IRQ%d ", i); + if (use_pci_vector() && !platform_legacy_irq(i)) + printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); + else + printk(KERN_DEBUG "IRQ%d ", i); for (;;) { printk("-> %d:%d", entry->apic, entry->pin); if (!entry->next) @@ -910,152 +1376,13 @@ void __init print_IO_APIC(void) } printk(KERN_INFO ".................................... done.\n"); -#endif + + return; } - -#if 0 /* Maybe useful for debugging, but not currently used anywhere. */ - -static void print_APIC_bitfield (int base) -{ - unsigned int v; - int i, j; - - printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); - for (i = 0; i < 8; i++) { - v = apic_read(base + i*0x10); - for (j = 0; j < 32; j++) { - if (v & (1< 3) /* Due to the Pentium erratum 3AP. */ - apic_write(APIC_ESR, 0); - v = apic_read(APIC_ESR); - printk(KERN_DEBUG "... APIC ESR: %08x\n", v); - } - - v = apic_read(APIC_ICR); - printk(KERN_DEBUG "... APIC ICR: %08x\n", v); - v = apic_read(APIC_ICR2); - printk(KERN_DEBUG "... APIC ICR2: %08x\n", v); - - v = apic_read(APIC_LVTT); - printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); - - if (maxlvt > 3) { /* PC is LVT#4. */ - v = apic_read(APIC_LVTPC); - printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v); - } - v = apic_read(APIC_LVT0); - printk(KERN_DEBUG "... APIC LVT0: %08x\n", v); - v = apic_read(APIC_LVT1); - printk(KERN_DEBUG "... APIC LVT1: %08x\n", v); - - if (maxlvt > 2) { /* ERR is LVT#3. */ - v = apic_read(APIC_LVTERR); - printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v); - } - - v = apic_read(APIC_TMICT); - printk(KERN_DEBUG "... APIC TMICT: %08x\n", v); - v = apic_read(APIC_TMCCT); - printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v); - v = apic_read(APIC_TDCR); - printk(KERN_DEBUG "... APIC TDCR: %08x\n", v); - printk("\n"); -} - -void print_all_local_APICs (void) -{ - smp_call_function(print_local_APIC, NULL, 1, 1); - print_local_APIC(NULL); -} - -void /*__init*/ print_PIC(void) -{ - extern spinlock_t i8259A_lock; - unsigned int v, flags; - - printk(KERN_DEBUG "\nprinting PIC contents\n"); - - spin_lock_irqsave(&i8259A_lock, flags); - - v = inb(0xa1) << 8 | inb(0x21); - printk(KERN_DEBUG "... PIC IMR: %04x\n", v); - - v = inb(0xa0) << 8 | inb(0x20); - printk(KERN_DEBUG "... PIC IRR: %04x\n", v); - - outb(0x0b,0xa0); - outb(0x0b,0x20); - v = inb(0xa0) << 8 | inb(0x20); - outb(0x0a,0xa0); - outb(0x0a,0x20); - - spin_unlock_irqrestore(&i8259A_lock, flags); - - printk(KERN_DEBUG "... PIC ISR: %04x\n", v); - - v = inb(0x4d1) << 8 | inb(0x4d0); - printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); -} - -#endif /* 0 */ - - static void __init enable_IO_APIC(void) { - struct IO_APIC_reg_01 reg_01; + union IO_APIC_reg_01 reg_01; int i; unsigned long flags; @@ -1063,18 +1390,15 @@ static void __init enable_IO_APIC(void) irq_2_pin[i].pin = -1; irq_2_pin[i].next = 0; } - if (!pirqs_enabled) - for (i = 0; i < MAX_PIRQS; i++) - pirq_entries[i] = -1; /* * The number of IO-APIC IRQ registers (== #pins): */ for (i = 0; i < nr_ioapics; i++) { spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_01 = io_apic_read(i, 1); + reg_01.raw = io_apic_read(i, 1); spin_unlock_irqrestore(&ioapic_lock, flags); - nr_ioapic_registers[i] = reg_01.entries+1; + nr_ioapic_registers[i] = reg_01.bits.entries+1; } /* @@ -1103,18 +1427,22 @@ void disable_IO_APIC(void) * by Matt Domsch Tue Dec 21 12:25:05 CST 1999 */ -static void __init setup_ioapic_ids_from_mpc (void) +#ifndef CONFIG_X86_NUMAQ +static void __init setup_ioapic_ids_from_mpc(void) { - struct IO_APIC_reg_00 reg_00; - unsigned long phys_id_present_map = phys_cpu_present_map; + union IO_APIC_reg_00 reg_00; + physid_mask_t phys_id_present_map; int apic; int i; unsigned char old_id; unsigned long flags; - if (clustered_apic_mode) - /* We don't have a good way to do this yet - hack */ - phys_id_present_map = (u_long) 0xf; + /* + * This is broken; anything with a real cpu count has to + * circumvent this idiocy regardless. + */ + phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map); + /* * Set the IOAPIC ID to the value stored in the MPC table. */ @@ -1122,41 +1450,48 @@ static void __init setup_ioapic_ids_from_mpc (void) /* Read the register 0 value */ spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(apic, 0); + reg_00.raw = io_apic_read(apic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); old_id = mp_ioapics[apic].mpc_apicid; - if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) { + if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", apic, mp_ioapics[apic].mpc_apicid); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", - reg_00.ID); - mp_ioapics[apic].mpc_apicid = reg_00.ID; + reg_00.bits.ID); + mp_ioapics[apic].mpc_apicid = reg_00.bits.ID; } + /* Don't check I/O APIC IDs for some xAPIC systems. They have + * no meaning without the serial APIC bus. */ + if (NO_IOAPIC_CHECK) + continue; /* * Sanity check, is the ID really free? Every APIC in a * system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. - * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs. */ - if ((clustered_apic_mode != CLUSTERED_APIC_XAPIC) && - (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) { + if (check_apicid_used(phys_id_present_map, + mp_ioapics[apic].mpc_apicid)) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", apic, mp_ioapics[apic].mpc_apicid); - for (i = 0; i < 0xf; i++) - if (!(phys_id_present_map & (1 << i))) + for (i = 0; i < get_physical_broadcast(); i++) + if (!physid_isset(i, phys_id_present_map)) break; - if (i >= apic_broadcast_id) + if (i >= get_physical_broadcast()) panic("Max APIC ID exceeded!\n"); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", i); - phys_id_present_map |= 1 << i; + physid_set(i, phys_id_present_map); mp_ioapics[apic].mpc_apicid = i; } else { - printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid); - phys_id_present_map |= 1 << mp_ioapics[apic].mpc_apicid; + physid_mask_t tmp; + tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, "Setting %d in the " + "phys_id_present_map\n", + mp_ioapics[apic].mpc_apicid); + physids_or(phys_id_present_map, phys_id_present_map, tmp); } @@ -1174,26 +1509,30 @@ static void __init setup_ioapic_ids_from_mpc (void) * Read the right value from the MPC table and * write it into the ID register. */ - printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", - mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, KERN_INFO + "...changing IO-APIC physical APIC ID to %d ...", + mp_ioapics[apic].mpc_apicid); - reg_00.ID = mp_ioapics[apic].mpc_apicid; + reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; spin_lock_irqsave(&ioapic_lock, flags); - io_apic_write(apic, 0, *(int *)®_00); + io_apic_write(apic, 0, reg_00.raw); spin_unlock_irqrestore(&ioapic_lock, flags); /* * Sanity check */ spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(apic, 0); + reg_00.raw = io_apic_read(apic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); - if (reg_00.ID != mp_ioapics[apic].mpc_apicid) - panic("could not set ID!\n"); + if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) + printk("could not set ID!\n"); else - printk(" ok.\n"); + apic_printk(APIC_VERBOSE, " ok.\n"); } } +#else +static void __init setup_ioapic_ids_from_mpc(void) { } +#endif /* * There is a nasty bug in some older SMP boards, their mptable lies @@ -1205,9 +1544,9 @@ static void __init setup_ioapic_ids_from_mpc (void) */ static int __init timer_irq_works(void) { - unsigned int t1 = jiffies; + unsigned long t1 = jiffies; - __sti(); + local_irq_enable(); /* Let ten ticks pass... */ mdelay((10 * 1000) / HZ); @@ -1224,7 +1563,18 @@ static int __init timer_irq_works(void) return 0; } -static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } +/* + * In the SMP+IOAPIC case it might happen that there are an unspecified + * number of pending IRQ events unhandled. These cases are very rare, + * so we 'resend' these IRQs via IPIs, to the same CPU. It's much + * better to do it this way as thus we do not have to be aware of + * 'pending' interrupts in the IRQ path, except at this point. + */ +/* + * Edge triggered needs to resend any interrupt + * that was delayed but this is now handled in the device + * independent code. + */ /* * Starting up a edge-triggered IO-APIC interrupt is @@ -1235,7 +1585,6 @@ static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } * This is not complete - we should be able to fake * an edge even if it isn't on the 8259A... */ - static unsigned int startup_edge_ioapic_irq(unsigned int irq) { int was_pending = 0; @@ -1260,16 +1609,13 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) */ static void ack_edge_ioapic_irq(unsigned int irq) { - balance_irq(irq); + move_irq(irq); if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) mask_IO_APIC_irq(irq); ack_APIC_irq(); } -static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ } - - /* * Level triggered interrupts can just be masked, * and shutting down and starting up the interrupt @@ -1291,15 +1637,14 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq) return 0; /* don't check for pending */ } -static void mask_and_ack_level_ioapic_irq(unsigned int irq) +static void mask_and_ack_level_ioapic_irq (unsigned int irq) { unsigned long v; int i; - balance_irq(irq); + move_irq(irq); mask_IO_APIC_irq(irq); - /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1320,45 +1665,114 @@ static void mask_and_ack_level_ioapic_irq(unsigned int irq) * The idea is from Manfred Spraul. --macro */ i = IO_APIC_VECTOR(irq); + v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); ack_APIC_irq(); if (!(v & (1 << (i & 0x1f)))) { -#ifdef APIC_LOCKUP_DEBUG - struct irq_pin_list *entry; -#endif - -#ifdef APIC_MISMATCH_DEBUG atomic_inc(&irq_mis_count); -#endif spin_lock(&ioapic_lock); __edge_IO_APIC_irq(irq); -#ifdef APIC_LOCKUP_DEBUG - for (entry = irq_2_pin + irq;;) { - unsigned int reg; - - if (entry->pin == -1) - break; - reg = io_apic_read(entry->apic, 0x10 + entry->pin * 2); - if (reg & 0x00004000) - printk(KERN_CRIT "Aieee!!! Remote IRR" - " still set after unlock!\n"); - if (!entry->next) - break; - entry = irq_2_pin + entry->next; - } -#endif __level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); } } -static void end_level_ioapic_irq(unsigned int irq) +static void end_level_ioapic_irq (unsigned int irq) { unmask_IO_APIC_irq(irq); } +#ifdef CONFIG_PCI_MSI +static unsigned int startup_edge_ioapic_vector(unsigned int vector) +{ + int irq = vector_to_irq(vector); + + return startup_edge_ioapic_irq(irq); +} + +static void ack_edge_ioapic_vector(unsigned int vector) +{ + int irq = vector_to_irq(vector); + + ack_edge_ioapic_irq(irq); +} + +static unsigned int startup_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + return startup_level_ioapic_irq (irq); +} + +static void mask_and_ack_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + mask_and_ack_level_ioapic_irq(irq); +} + +static void end_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + end_level_ioapic_irq(irq); +} + +static void mask_IO_APIC_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + mask_IO_APIC_irq(irq); +} + +static void unmask_IO_APIC_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + unmask_IO_APIC_irq(irq); +} + +static void set_ioapic_affinity_vector (unsigned int vector, + cpumask_t cpu_mask) +{ + int irq = vector_to_irq(vector); + + set_ioapic_affinity_irq(irq, cpu_mask); +} +#endif + +/* + * Level and edge triggered IO-APIC interrupts need different handling, + * so we use two separate IRQ descriptors. Edge triggered IRQs can be + * handled with the level-triggered descriptor, but that one has slightly + * more overhead. Level-triggered interrupts cannot be handled with the + * edge-triggered handler, without risking IRQ storms and other ugly + * races. + */ +static struct hw_interrupt_type ioapic_edge_type = { + .typename = "IO-APIC-edge", + .startup = startup_edge_ioapic, + .shutdown = shutdown_edge_ioapic, + .enable = enable_edge_ioapic, + .disable = disable_edge_ioapic, + .ack = ack_edge_ioapic, + .end = end_edge_ioapic, + .set_affinity = set_ioapic_affinity, +}; + +static struct hw_interrupt_type ioapic_level_type = { + .typename = "IO-APIC-level", + .startup = startup_level_ioapic, + .shutdown = shutdown_level_ioapic, + .enable = enable_level_ioapic, + .disable = disable_level_ioapic, + .ack = mask_and_ack_level_ioapic, + .end = end_level_ioapic, + .set_affinity = set_ioapic_affinity, +}; + static inline void init_IO_APIC_traps(void) { int irq; @@ -1375,7 +1789,13 @@ static inline void init_IO_APIC_traps(void) * 0x80, because int 0x80 is hm, kind of importantish. ;) */ for (irq = 0; irq < NR_IRQS ; irq++) { - if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) { + int tmp = irq; + if (use_pci_vector()) { + if (!platform_legacy_irq(tmp)) + if ((tmp = vector_to_irq(tmp)) == -1) + continue; + } + if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { /* * Hmm.. We don't have an entry for this, * so default to an old-fashioned 8259 @@ -1414,13 +1834,13 @@ static void ack_lapic_irq (unsigned int irq) static void end_lapic_irq (unsigned int i) { /* nothing */ } static struct hw_interrupt_type lapic_irq_type = { - "local-APIC-edge", - NULL, /* startup_irq() not used for IRQ0 */ - NULL, /* shutdown_irq() not used for IRQ0 */ - enable_lapic_irq, - disable_lapic_irq, - ack_lapic_irq, - end_lapic_irq + .typename = "local-APIC-edge", + .startup = NULL, /* startup_irq() not used for IRQ0 */ + .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ + .enable = enable_lapic_irq, + .disable = disable_lapic_irq, + .ack = ack_lapic_irq, + .end = end_lapic_irq }; /* @@ -1493,7 +1913,6 @@ static inline void unlock_ExtINT_logic(void) */ static inline void check_timer(void) { - extern int timer_ack; int pin1, pin2; int vector; @@ -1526,8 +1945,9 @@ static inline void check_timer(void) * Ok, does IRQ0 through the IOAPIC work? */ unmask_IO_APIC_irq(0); - if (timer_irq_works()) + if (timer_irq_works()) { return; + } clear_IO_APIC_pin(0, pin1); printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); } @@ -1554,6 +1974,11 @@ static inline void check_timer(void) } printk(" failed.\n"); + if (nmi_watchdog == NMI_IO_APIC) { + printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); + nmi_watchdog = 0; + } + printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); disable_8259A_irq(0); @@ -1570,6 +1995,7 @@ static inline void check_timer(void) printk(KERN_INFO "...trying to set up timer as ExtINT IRQ..."); + timer_ack = 0; init_8259A(0); make_8259A_irq(0); apic_write_around(APIC_LVT0, APIC_DM_EXTINT); @@ -1581,7 +2007,8 @@ static inline void check_timer(void) return; } printk(" failed :(.\n"); - panic("IO-APIC + timer doesn't work! pester mingo@redhat.com"); + panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " + "report. Then try booting with the 'noapic' option"); } #define NR_IOAPIC_BIOSIDS 256 @@ -1596,20 +2023,12 @@ static void store_ioapic_biosid_mapping(void) /* * - * IRQ's that are handled by the old PIC in all cases: + * IRQ's that are handled by the PIC in the MPS IOAPIC case. * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. * Linux doesn't really care, as it's not actually used * for any interrupt handling anyway. - * - There used to be IRQ13 here as well, but all - * MPS-compliant must not use it for FPU coupling and we - * want to use exception 16 anyway. And there are - * systems who connect it to an I/O APIC for other uses. - * Thus we don't mark it special any longer. - * - * Additionally, something is definitely wrong with irq9 - * on PIIX4 boards. */ -#define PIC_IRQS (1<<2) +#define PIC_IRQS (1 << PIC_CASCADE_IR) void __init setup_IO_APIC(void) { @@ -1617,7 +2036,11 @@ void __init setup_IO_APIC(void) enable_IO_APIC(); - io_apic_irqs = ~PIC_IRQS; + if (acpi_ioapic) + io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ + else + io_apic_irqs = ~PIC_IRQS; + printk("ENABLING IO-APIC IRQs\n"); /* @@ -1632,22 +2055,17 @@ void __init setup_IO_APIC(void) print_IO_APIC(); } -#endif /* CONFIG_X86_IO_APIC */ - - - /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ #ifdef CONFIG_ACPI_BOOT -#define IO_APIC_MAX_ID 15 - int __init io_apic_get_unique_id (int ioapic, int apic_id) { - struct IO_APIC_reg_00 reg_00; - static unsigned long apic_id_map = 0; + union IO_APIC_reg_00 reg_00; + static physid_mask_t apic_id_map = PHYSID_MASK_NONE; + physid_mask_t tmp; unsigned long flags; int i = 0; @@ -1660,38 +2078,31 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) * advantage of new APIC bus architecture. */ - if (!apic_id_map) - apic_id_map = phys_cpu_present_map; + if (physids_empty(apic_id_map)) + apic_id_map = ioapic_phys_id_map(phys_cpu_present_map); spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(ioapic, 0); + reg_00.raw = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); - if (apic_id >= IO_APIC_MAX_ID) { + if (apic_id >= get_physical_broadcast()) { printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " - "%d\n", ioapic, apic_id, reg_00.ID); - apic_id = reg_00.ID; - } - - /* XAPICs do not need unique IDs */ - if (clustered_apic_mode == CLUSTERED_APIC_XAPIC){ - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", - ioapic, apic_id); - return apic_id; + "%d\n", ioapic, apic_id, reg_00.bits.ID); + apic_id = reg_00.bits.ID; } /* * Every APIC in a system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. */ - if (apic_id_map & (1 << apic_id)) { + if (check_apicid_used(apic_id_map, apic_id)) { - for (i = 0; i < IO_APIC_MAX_ID; i++) { - if (!(apic_id_map & (1 << i))) + for (i = 0; i < get_physical_broadcast(); i++) { + if (!check_apicid_used(apic_id_map, i)) break; } - if (i == IO_APIC_MAX_ID) + if (i == get_physical_broadcast()) panic("Max apic_id exceeded!\n"); printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " @@ -1700,22 +2111,24 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) apic_id = i; } - apic_id_map |= (1 << apic_id); + tmp = apicid_to_cpu_present(apic_id); + physids_or(apic_id_map, apic_id_map, tmp); - if (reg_00.ID != apic_id) { - reg_00.ID = apic_id; + if (reg_00.bits.ID != apic_id) { + reg_00.bits.ID = apic_id; spin_lock_irqsave(&ioapic_lock, flags); - io_apic_write(ioapic, 0, *(int *)®_00); - *(int *)®_00 = io_apic_read(ioapic, 0); + io_apic_write(ioapic, 0, reg_00.raw); + reg_00.raw = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); /* Sanity check */ - if (reg_00.ID != apic_id) + if (reg_00.bits.ID != apic_id) panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); } - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); + apic_printk(APIC_VERBOSE, KERN_INFO + "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } @@ -1723,27 +2136,27 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) int __init io_apic_get_version (int ioapic) { - struct IO_APIC_reg_01 reg_01; + union IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_01 = io_apic_read(ioapic, 1); + reg_01.raw = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); - return reg_01.version; + return reg_01.bits.version; } int __init io_apic_get_redir_entries (int ioapic) { - struct IO_APIC_reg_01 reg_01; + union IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_01 = io_apic_read(ioapic, 1); + reg_01.raw = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); - return reg_01.entries; + return reg_01.bits.entries; } @@ -1753,7 +2166,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a unsigned long flags; if (!IO_APIC_IRQ(irq)) { - printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0/n", + printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", ioapic); return -EINVAL; } @@ -1766,12 +2179,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a memset(&entry,0,sizeof(entry)); - entry.delivery_mode = dest_LowestPrio; - entry.dest_mode = INT_DELIVERY_MODE; - entry.dest.logical.logical_dest = target_cpus(); - entry.mask = 1; /* Disabled (masked) */ + entry.delivery_mode = INT_DELIVERY_MODE; + entry.dest_mode = INT_DEST_MODE; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.trigger = edge_level; entry.polarity = active_high_low; + entry.mask = 1; /* * IRQs < 16 are already in the irq_2_pin[] map @@ -1781,17 +2194,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a entry.vector = assign_irq_vector(irq); - printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " - "IRQ %d Mode:%i Active:%i)\n", ioapic, - mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); + apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " + "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, + mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, + edge_level, active_high_low); - if (edge_level) { - irq_desc[irq].handler = &ioapic_level_irq_type; - } else { - irq_desc[irq].handler = &ioapic_edge_irq_type; - } - - set_intr_gate(entry.vector, interrupt[irq]); + ioapic_register_intr(irq, entry.vector, edge_level); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); @@ -1806,123 +2214,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a #endif /*CONFIG_ACPI_BOOT*/ -/* opt_leveltrigger, opt_edgetrigger: Force an IO-APIC-routed IRQ to be */ -/* level- or edge-triggered. */ -/* Example: 'leveltrigger=4,5,6,20 edgetrigger=21'. */ -static char opt_leveltrigger[30] = "", opt_edgetrigger[30] = ""; -string_param("leveltrigger", opt_leveltrigger); -string_param("edgetrigger", opt_edgetrigger); - -static int __init ioapic_trigger_setup(void) -{ - char *p; - irq_desc_t *desc; - long irq; - - p = opt_leveltrigger; - while ( *p != '\0' ) - { - irq = simple_strtol(p, &p, 10); - if ( (irq <= 0) || (irq >= NR_IRQS) ) - { - printk("IRQ '%ld' out of range in level-trigger list '%s'\n", - irq, opt_leveltrigger); - break; - } - - printk("Forcing IRQ %ld to level-trigger: ", irq); - - desc = &irq_desc[irq]; - spin_lock_irq(&desc->lock); - - if ( desc->handler == &ioapic_level_irq_type ) - { - printk("already level-triggered (no force applied).\n"); - } - else if ( desc->handler != &ioapic_edge_irq_type ) - { - printk("cannot force (can only force IO-APIC-edge IRQs).\n"); - } - else - { - desc->handler = &ioapic_level_irq_type; - __mask_IO_APIC_irq(irq); - __level_IO_APIC_irq(irq); - printk("done.\n"); - } - - spin_unlock_irq(&desc->lock); - - if ( *p == '\0' ) - break; - - if ( *p != ',' ) - { - printk("Unexpected character '%c' in level-trigger list '%s'\n", - *p, opt_leveltrigger); - break; - } - - p++; - } - - p = opt_edgetrigger; - while ( *p != '\0' ) - { - irq = simple_strtol(p, &p, 10); - if ( (irq <= 0) || (irq >= NR_IRQS) ) - { - printk("IRQ '%ld' out of range in edge-trigger list '%s'\n", - irq, opt_edgetrigger); - break; - } - - printk("Forcing IRQ %ld to edge-trigger: ", irq); - - desc = &irq_desc[irq]; - spin_lock_irq(&desc->lock); - - if ( desc->handler == &ioapic_edge_irq_type ) - { - printk("already edge-triggered (no force applied).\n"); - } - else if ( desc->handler != &ioapic_level_irq_type ) - { - printk("cannot force (can only force IO-APIC-level IRQs).\n"); - } - else - { - desc->handler = &ioapic_edge_irq_type; - __edge_IO_APIC_irq(irq); - desc->status |= IRQ_PENDING; /* may have lost a masked edge */ - printk("done.\n"); - } - - spin_unlock_irq(&desc->lock); - - if ( *p == '\0' ) - break; - - if ( *p != ',' ) - { - printk("Unexpected character '%c' in edge-trigger list '%s'\n", - *p, opt_edgetrigger); - break; - } - - p++; - } - - return 0; -} - -__initcall(ioapic_trigger_setup); int ioapic_guest_read(int apicid, int address, u32 *pval) { u32 val; int apicenum; - struct IO_APIC_reg_00 reg_00; + union IO_APIC_reg_00 reg_00; unsigned long flags; if ( (apicid >= NR_IOAPIC_BIOSIDS) || @@ -1936,9 +2233,9 @@ int ioapic_guest_read(int apicid, int address, u32 *pval) /* Rewrite APIC ID to what the BIOS originally specified. */ if ( address == 0 ) { - *(int *)®_00 = val; - reg_00.ID = apicid; - val = *(u32 *)®_00; + reg_00.raw = val; + reg_00.bits.ID = apicid; + val = reg_00.raw; } *pval = val; @@ -1974,7 +2271,7 @@ int ioapic_guest_write(int apicid, int address, u32 val) /* Set the correct irq-handling type. */ irq_desc[irq].handler = rte.trigger ? - &ioapic_level_irq_type: &ioapic_edge_irq_type; + &ioapic_level_type: &ioapic_edge_type; /* Record the pin<->irq mapping. */ for ( entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next] ) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 86b3d7da99..aaaff647ce 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -42,7 +42,6 @@ struct hw_interrupt_type no_irq_type = { }; atomic_t irq_err_count; -atomic_t irq_mis_count; inline void disable_irq_nosync(unsigned int irq) { diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c index d811e7ed70..4cbafae1e6 100644 --- a/xen/arch/x86/microcode.c +++ b/xen/arch/x86/microcode.c @@ -87,13 +87,6 @@ #define vmalloc(_s) xmalloc_bytes(_s) #define vfree(_p) xfree(_p) #define num_online_cpus() smp_num_cpus -static inline int on_each_cpu( - void (*func) (void *info), void *info, int retry, int wait) -{ - int ret = smp_call_function(func, info, retry, wait); - func(info); - return ret; -} #if 0 MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 43d2d2daea..d355b7e9af 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -316,7 +316,7 @@ int map_ldt_shadow_page(unsigned int off) res = get_page_and_type(&frame_table[gmfn], d, PGT_ldt_page); - if ( !res && unlikely(shadow_mode_enabled(d)) ) + if ( !res && unlikely(shadow_mode_refcounts(d)) ) { shadow_lock(d); shadow_remove_all_write_access(d, gpfn, gmfn); @@ -392,7 +392,7 @@ get_linear_pagetable( struct pfn_info *page; unsigned long pfn; - ASSERT( !shadow_mode_enabled(d) ); + ASSERT( !shadow_mode_refcounts(d) ); if ( (root_get_flags(re) & _PAGE_RW) ) { @@ -482,7 +482,7 @@ get_page_from_l2e( { int rc; - ASSERT(!shadow_mode_enabled(d)); + ASSERT(!shadow_mode_refcounts(d)); if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) return 1; @@ -512,6 +512,8 @@ static int get_page_from_l3e( l3_pgentry_t l3e, unsigned long pfn, struct domain *d) { + ASSERT( !shadow_mode_refcounts(d) ); + if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ) return 1; @@ -533,6 +535,8 @@ get_page_from_l4e( { int rc; + ASSERT( !shadow_mode_refcounts(d) ); + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) return 1; @@ -641,7 +645,7 @@ static int alloc_l1_table(struct pfn_info *page) l1_pgentry_t *pl1e; int i; - ASSERT(!shadow_mode_enabled(d)); + ASSERT(!shadow_mode_refcounts(d)); pl1e = map_domain_mem(pfn << PAGE_SHIFT); @@ -670,10 +674,12 @@ static int alloc_l2_table(struct pfn_info *page) l2_pgentry_t *pl2e; int i; + // See the code in shadow_promote() to understand why this is here... if ( (PGT_base_page_table == PGT_l2_page_table) && - shadow_mode_enabled(d) ) + unlikely(shadow_mode_refcounts(d)) ) return 1; - ASSERT( !shadow_mode_enabled(d) ); + + ASSERT( !shadow_mode_refcounts(d) ); pl2e = map_domain_mem(pfn << PAGE_SHIFT); @@ -716,7 +722,7 @@ static int alloc_l3_table(struct pfn_info *page) l3_pgentry_t *pl3e = page_to_virt(page); int i; - ASSERT( !shadow_mode_enabled(d) ); + ASSERT( !shadow_mode_refcounts(d) ); for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ ) if ( is_guest_l3_slot(i) && @@ -741,10 +747,12 @@ static int alloc_l4_table(struct pfn_info *page) l4_pgentry_t *pl4e = page_to_virt(page); int i; + // See the code in shadow_promote() to understand why this is here... if ( (PGT_base_page_table == PGT_l4_page_table) && - shadow_mode_enabled(d) ) + shadow_mode_refcounts(d) ) return 1; - ASSERT( !shadow_mode_enabled(d) ); + + ASSERT( !shadow_mode_refcounts(d) ); for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ ) if ( is_guest_l4_slot(i) && @@ -861,11 +869,12 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e) l1_pgentry_t ol1e; struct domain *d = current->domain; - ASSERT( !shadow_mode_enabled(d) ); - if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) ) return 0; + if ( unlikely(shadow_mode_refcounts(d)) ) + return update_l1e(pl1e, ol1e, nl1e); + if ( l1e_get_flags(nl1e) & _PAGE_PRESENT ) { if ( unlikely(l1e_get_flags(nl1e) & L1_DISALLOW_MASK) ) @@ -893,7 +902,7 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e) if ( unlikely(!update_l1e(pl1e, ol1e, nl1e)) ) return 0; } - + put_page_from_l1e(ol1e, d); return 1; } @@ -1095,8 +1104,19 @@ int alloc_page_type(struct pfn_info *page, unsigned int type) void free_page_type(struct pfn_info *page, unsigned int type) { struct domain *owner = page_get_owner(page); - if ( likely(owner != NULL) && unlikely(shadow_mode_enabled(owner)) ) - return; + unsigned long gpfn; + + if ( owner != NULL ) + { + if ( unlikely(shadow_mode_refcounts(owner)) ) + return; + if ( unlikely(shadow_mode_enabled(owner)) ) + { + gpfn = __mfn_to_gpfn(owner, page_to_pfn(page)); + ASSERT(VALID_M2P(gpfn)); + remove_shadow(owner, gpfn, type); + } + } switch ( type ) { @@ -1142,7 +1162,7 @@ void put_page_type(struct pfn_info *page) * See domain.c:relinquish_list(). */ ASSERT((x & PGT_validated) || - test_bit(DF_DYING, &page_get_owner(page)->d_flags)); + test_bit(DF_DYING, &page_get_owner(page)->flags)); if ( unlikely((nx & PGT_count_mask) == 0) ) { @@ -1287,7 +1307,7 @@ int new_guest_cr3(unsigned long mfn) int okay; unsigned long old_base_mfn; - if ( shadow_mode_enabled(d) ) + if ( shadow_mode_refcounts(d) ) okay = get_page_from_pagenr(mfn, d); else okay = get_page_and_type_from_pagenr(mfn, PGT_root_page_table, d); @@ -1296,24 +1316,24 @@ int new_guest_cr3(unsigned long mfn) { invalidate_shadow_ldt(ed); - old_base_mfn = pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT; + old_base_mfn = pagetable_get_pfn(ed->arch.guest_table); ed->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT); update_pagetables(ed); /* update shadow_table and monitor_table */ write_ptbase(ed); - if ( shadow_mode_enabled(d) ) + if ( shadow_mode_refcounts(d) ) put_page(&frame_table[old_base_mfn]); else put_page_and_type(&frame_table[old_base_mfn]); - /* CR3 holds its own ref to its shadow. */ + /* CR3 also holds a ref to its shadow... */ if ( shadow_mode_enabled(d) ) { if ( ed->arch.monitor_shadow_ref ) put_shadow_ref(ed->arch.monitor_shadow_ref); ed->arch.monitor_shadow_ref = - pagetable_val(ed->arch.monitor_table) >> PAGE_SHIFT; + pagetable_get_pfn(ed->arch.monitor_table); ASSERT(!page_get_owner(&frame_table[ed->arch.monitor_shadow_ref])); get_shadow_ref(ed->arch.monitor_shadow_ref); } @@ -1486,7 +1506,7 @@ int do_mmuext_op( type = PGT_l1_page_table | PGT_va_mutable; pin_page: - if ( shadow_mode_enabled(FOREIGNDOM) ) + if ( shadow_mode_refcounts(FOREIGNDOM) ) type = PGT_writable_page; okay = get_page_and_type_from_pagenr(op.mfn, type, FOREIGNDOM); @@ -1557,7 +1577,7 @@ int do_mmuext_op( else { unsigned long old_mfn = - pagetable_val(ed->arch.guest_table_user) >> PAGE_SHIFT; + pagetable_get_pfn(ed->arch.guest_table_user); ed->arch.guest_table_user = mk_pagetable(op.mfn << PAGE_SHIFT); if ( old_mfn != 0 ) put_page_and_type(&frame_table[old_mfn]); @@ -1691,13 +1711,13 @@ int do_mmuext_op( * it is dying. */ ASSERT(e->tot_pages <= e->max_pages); - if ( unlikely(test_bit(DF_DYING, &e->d_flags)) || + if ( unlikely(test_bit(DF_DYING, &e->flags)) || unlikely(e->tot_pages == e->max_pages) || unlikely(IS_XEN_HEAP_FRAME(page)) ) { MEM_LOG("Transferee has no reservation headroom (%d,%d), or " "page is in Xen heap (%lx), or dom is dying (%ld).\n", - e->tot_pages, e->max_pages, op.mfn, e->d_flags); + e->tot_pages, e->max_pages, op.mfn, e->flags); okay = 0; goto reassign_fail; } @@ -1785,13 +1805,15 @@ int do_mmu_update( unsigned int foreigndom) { mmu_update_t req; - unsigned long va = 0, mfn, prev_mfn = 0, gpfn; + void *va; + unsigned long gpfn, mfn; struct pfn_info *page; int rc = 0, okay = 1, i = 0, cpu = smp_processor_id(); unsigned int cmd, done = 0; struct exec_domain *ed = current; struct domain *d = ed->domain; u32 type_info; + struct map_dom_mem_cache mapcache, sh_mapcache; LOCK_BIGLOCK(d); @@ -1807,6 +1829,9 @@ int do_mmu_update( (void)get_user(done, pdone); } + init_map_domain_mem_cache(&mapcache); + init_map_domain_mem_cache(&sh_mapcache); + if ( !set_foreigndom(cpu, foreigndom) ) { rc = -EINVAL; @@ -1841,8 +1866,6 @@ int do_mmu_update( } cmd = req.ptr & (sizeof(l1_pgentry_t)-1); - mfn = req.ptr >> PAGE_SHIFT; - okay = 0; switch ( cmd ) @@ -1851,73 +1874,75 @@ int do_mmu_update( * MMU_NORMAL_PT_UPDATE: Normal update to any level of page table. */ case MMU_NORMAL_PT_UPDATE: + + gpfn = req.ptr >> PAGE_SHIFT; + mfn = __gpfn_to_mfn(d, gpfn); + if ( unlikely(!get_page_from_pagenr(mfn, current->domain)) ) { MEM_LOG("Could not get page for normal update"); break; } - if ( likely(prev_mfn == mfn) ) - { - va = (va & PAGE_MASK) | (req.ptr & ~PAGE_MASK); - } - else - { - if ( prev_mfn != 0 ) - unmap_domain_mem((void *)va); - va = (unsigned long)map_domain_mem(req.ptr); - prev_mfn = mfn; - } - + va = map_domain_mem_with_cache(req.ptr, &mapcache); page = &frame_table[mfn]; + switch ( (type_info = page->u.inuse.type_info) & PGT_type_mask ) { case PGT_l1_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type( page, type_info & (PGT_type_mask|PGT_va_mask))) ) { - l1_pgentry_t pte; + l1_pgentry_t l1e; /* FIXME: doesn't work with PAE */ - pte = l1e_create_phys(req.val, req.val); - okay = mod_l1_entry((l1_pgentry_t *)va, pte); + l1e = l1e_create_phys(req.val, req.val); + okay = mod_l1_entry(va, l1e); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l1_normal_pt_update(d, req.ptr, l1e, &sh_mapcache); put_page_type(page); } break; case PGT_l2_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type(page, PGT_l2_page_table)) ) { l2_pgentry_t l2e; /* FIXME: doesn't work with PAE */ l2e = l2e_create_phys(req.val, req.val); - okay = mod_l2_entry((l2_pgentry_t *)va, l2e, mfn); + okay = mod_l2_entry(va, l2e, mfn); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l2_normal_pt_update(d, req.ptr, l2e, &sh_mapcache); put_page_type(page); } break; #ifdef __x86_64__ case PGT_l3_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type(page, PGT_l3_page_table)) ) { l3_pgentry_t l3e; /* FIXME: doesn't work with PAE */ l3e = l3e_create_phys(req.val,req.val); - okay = mod_l3_entry((l3_pgentry_t *)va, l3e, mfn); + okay = mod_l3_entry(va, l3e, mfn); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l3_normal_pt_update(d, req.ptr, l3e, &sh_mapcache); put_page_type(page); } break; case PGT_l4_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type(page, PGT_l4_page_table)) ) { l4_pgentry_t l4e; l4e = l4e_create_phys(req.val,req.val); - okay = mod_l4_entry((l4_pgentry_t *)va, l4e, mfn); + okay = mod_l4_entry(va, l4e, mfn); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l4_normal_pt_update(d, req.ptr, l4e, &sh_mapcache); put_page_type(page); } break; @@ -1932,9 +1957,6 @@ int do_mmu_update( if ( shadow_mode_log_dirty(d) ) __mark_dirty(d, mfn); - gpfn = __mfn_to_gpfn(d, mfn); - ASSERT(VALID_M2P(gpfn)); - if ( page_is_page_table(page) && !page_out_of_sync(page) ) { @@ -1953,24 +1975,29 @@ int do_mmu_update( break; } + unmap_domain_mem_with_cache(va, &mapcache); + put_page(page); break; case MMU_MACHPHYS_UPDATE: + mfn = req.ptr >> PAGE_SHIFT; + gpfn = req.val; + /* HACK ALERT... Need to think about this some more... */ if ( unlikely(shadow_mode_translate(FOREIGNDOM) && IS_PRIV(d)) ) { - rc = FOREIGNDOM->next_io_page++; - printk("privileged guest dom%d requests mfn=%lx for dom%d, " - "gets pfn=%x\n", - d->id, mfn, FOREIGNDOM->id, rc); - set_machinetophys(mfn, rc); - set_p2m_entry(FOREIGNDOM, rc, mfn); + shadow_lock(FOREIGNDOM); + printk("privileged guest dom%d requests pfn=%lx to map mfn=%lx for dom%d\n", + d->id, gpfn, mfn, FOREIGNDOM->id); + set_machinetophys(mfn, gpfn); + set_p2m_entry(FOREIGNDOM, gpfn, mfn, &sh_mapcache, &mapcache); okay = 1; + shadow_unlock(FOREIGNDOM); break; } - + if ( unlikely(!get_page_from_pagenr(mfn, FOREIGNDOM)) ) { MEM_LOG("Could not get page for mach->phys update"); @@ -1983,7 +2010,7 @@ int do_mmu_update( break; } - set_machinetophys(mfn, req.val); + set_machinetophys(mfn, gpfn); okay = 1; /* @@ -2012,8 +2039,8 @@ int do_mmu_update( } out: - if ( prev_mfn != 0 ) - unmap_domain_mem((void *)va); + destroy_map_domain_mem_cache(&mapcache); + destroy_map_domain_mem_cache(&sh_mapcache); process_deferred_ops(cpu); @@ -2031,73 +2058,6 @@ int do_mmu_update( /* This function assumes the caller is holding the domain's BIGLOCK * and is running in a shadow mode */ -int update_shadow_va_mapping(unsigned long va, - l1_pgentry_t val, - struct exec_domain *ed, - struct domain *d) -{ - unsigned long l1mfn; - l1_pgentry_t spte; - int rc = 0; - - check_pagetable(ed, "pre-va"); /* debug */ - shadow_lock(d); - - // This is actually overkill - we don't need to sync the L1 itself, - // just everything involved in getting to this L1 (i.e. we need - // linear_pg_table[l1_linear_offset(va)] to be in sync)... - // - __shadow_sync_va(ed, va); - -#if 1 /* keep check_pagetables() happy */ - /* - * However, the above doesn't guarantee that there's no snapshot of - * the L1 table in question; it just says that the relevant L2 and L1 - * entries for VA are in-sync. There might still be a snapshot. - * - * The checking code in _check_pagetables() assumes that no one will - * mutate the shadow of a page that has a snapshot. It's actually - * OK to not sync this page, but it seems simpler to: - * 1) keep all code paths the same, and - * 2) maintain the invariant for _check_pagetables(), rather than try - * to teach it about this boundary case. - * So we flush this L1 page, if it's out of sync. - */ - l1mfn = l2e_get_pfn(linear_l2_table(ed)[l2_table_offset(va)]); - if ( mfn_out_of_sync(l1mfn) ) - { - perfc_incrc(extra_va_update_sync); - __shadow_sync_mfn(d, l1mfn); - } -#endif /* keep check_pagetables() happy */ - - if ( unlikely(__copy_to_user(&linear_pg_table[l1_linear_offset(va)], - &val, sizeof(val)))) - { - rc = -EINVAL; - goto out; - } - - // also need to update the shadow - - l1pte_propagate_from_guest(d, val, &spte); - shadow_set_l1e(va, spte, 0); - - /* - * If we're in log-dirty mode then we need to note that we've updated - * the PTE in the PT-holding page. We need the machine frame number - * for this. - */ - if ( shadow_mode_log_dirty(d) ) - mark_dirty(d, va_to_l1mfn(ed, va)); - - out: - shadow_unlock(d); - check_pagetable(ed, "post-va"); /* debug */ - - return rc; -} - int update_grant_va_mapping(unsigned long va, l1_pgentry_t _nl1e, struct domain *d, @@ -2116,11 +2076,17 @@ int update_grant_va_mapping(unsigned long va, cleanup_writable_pagetable(d); + // This is actually overkill - we don't need to sync the L1 itself, + // just everything involved in getting to this L1 (i.e. we need + // linear_pg_table[l1_linear_offset(va)] to be in sync)... + // + __shadow_sync_va(ed, va); + pl1e = &linear_pg_table[l1_linear_offset(va)]; if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) ) rc = -EINVAL; - else + else if ( !shadow_mode_refcounts(d) ) { if ( update_l1e(pl1e, ol1e, _nl1e) ) { @@ -2133,9 +2099,14 @@ int update_grant_va_mapping(unsigned long va, else rc = -EINVAL; } + else + { + printk("grant tables and shadow mode currently don't work together\n"); + BUG(); + } if ( unlikely(shadow_mode_enabled(d)) ) - update_shadow_va_mapping(va, _nl1e, ed, d); + shadow_do_update_va_mapping(va, _nl1e, ed); return rc; } @@ -2161,6 +2132,13 @@ int do_update_va_mapping(unsigned long va, cleanup_writable_pagetable(d); if ( unlikely(shadow_mode_enabled(d)) ) + check_pagetable(ed, "pre-va"); /* debug */ + + if ( unlikely(!mod_l1_entry(&linear_pg_table[l1_linear_offset(va)], + val)) ) + rc = -EINVAL; + + if ( likely(rc == 0) && unlikely(shadow_mode_enabled(d)) ) { if ( unlikely(percpu_info[cpu].foreign && (shadow_mode_translate(d) || @@ -2173,11 +2151,10 @@ int do_update_va_mapping(unsigned long va, domain_crash(); } - rc = update_shadow_va_mapping(va, val, ed, d); + rc = shadow_do_update_va_mapping(va, val, ed); + + check_pagetable(ed, "post-va"); /* debug */ } - else if ( unlikely(!mod_l1_entry(&linear_pg_table[l1_linear_offset(va)], - val)) ) - rc = -EINVAL; switch ( flags & UVMF_FLUSHTYPE_MASK ) { @@ -2468,14 +2445,68 @@ int ptwr_debug = 0x0; #define PTWR_PRINTK(_f, _a...) ((void)0) #endif +/* Re-validate a given p.t. page, given its prior snapshot */ +int revalidate_l1(struct domain *d, l1_pgentry_t *l1page, l1_pgentry_t *snapshot) +{ + l1_pgentry_t ol1e, nl1e; + int modified = 0, i; + +#if 0 + if ( d->id ) + printk("%s: l1page mfn=%lx snapshot mfn=%lx\n", __func__, + l1e_get_pfn(linear_pg_table[l1_linear_offset((unsigned long)l1page)]), + l1e_get_pfn(linear_pg_table[l1_linear_offset((unsigned long)snapshot)])); +#endif + + for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) + { + ol1e = snapshot[i]; + nl1e = l1page[i]; + + if ( likely(l1e_get_value(ol1e) == l1e_get_value(nl1e)) ) + continue; + + /* Update number of entries modified. */ + modified++; + + /* + * Fast path for PTEs that have merely been write-protected + * (e.g., during a Unix fork()). A strict reduction in privilege. + */ + if ( likely(l1e_get_value(ol1e) == (l1e_get_value(nl1e)|_PAGE_RW)) ) + { + if ( likely(l1e_get_flags(nl1e) & _PAGE_PRESENT) ) + put_page_type(&frame_table[l1e_get_pfn(nl1e)]); + continue; + } + + if ( unlikely(!get_page_from_l1e(nl1e, d)) ) + { + MEM_LOG("ptwr: Could not re-validate l1 page\n"); + /* + * Make the remaining p.t's consistent before crashing, so the + * reference counts are correct. + */ + memcpy(&l1page[i], &snapshot[i], + (L1_PAGETABLE_ENTRIES - i) * sizeof(l1_pgentry_t)); + domain_crash(); + break; + } + + put_page_from_l1e(ol1e, d); + } + + return modified; +} + + /* Flush the given writable p.t. page and write-protect it again. */ void ptwr_flush(struct domain *d, const int which) { unsigned long pte, *ptep, l1va; - l1_pgentry_t *pl1e, ol1e, nl1e; + l1_pgentry_t *pl1e; l2_pgentry_t *pl2e; - int i; - unsigned int modified = 0; + unsigned int modified; ASSERT(!shadow_mode_enabled(d)); @@ -2524,45 +2555,8 @@ void ptwr_flush(struct domain *d, const int which) */ pl1e = d->arch.ptwr[which].pl1e; - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - { - ol1e = d->arch.ptwr[which].page[i]; - nl1e = pl1e[i]; - - if ( likely(l1e_get_value(ol1e) == l1e_get_value(nl1e)) ) - continue; - - /* Update number of entries modified. */ - modified++; - - /* - * Fast path for PTEs that have merely been write-protected - * (e.g., during a Unix fork()). A strict reduction in privilege. - */ - if ( likely(l1e_get_value(ol1e) == (l1e_get_value(nl1e)|_PAGE_RW)) ) - { - if ( likely(l1e_get_flags(nl1e) & _PAGE_PRESENT) ) - put_page_type(&frame_table[l1e_get_pfn(nl1e)]); - continue; - } - - if ( unlikely(!get_page_from_l1e(nl1e, d)) ) - { - MEM_LOG("ptwr: Could not re-validate l1 page\n"); - /* - * Make the remaining p.t's consistent before crashing, so the - * reference counts are correct. - */ - memcpy(&pl1e[i], &d->arch.ptwr[which].page[i], - (L1_PAGETABLE_ENTRIES - i) * sizeof(l1_pgentry_t)); - domain_crash(); - break; - } - - put_page_from_l1e(ol1e, d); - } + modified = revalidate_l1(d, pl1e, d->arch.ptwr[which].page); unmap_domain_mem(pl1e); - perfc_incr_histo(wpt_updates, modified, PT_UPDATES); d->arch.ptwr[which].prev_nr_updates = modified; @@ -2776,7 +2770,7 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr) * If this is a multi-processor guest then ensure that the page is hooked * into at most one L2 table, which must be the one running on this VCPU. */ - if ( (d->exec_domain[0]->ed_next_list != NULL) && + if ( (d->exec_domain[0]->next_in_list != NULL) && ((page->u.inuse.type_info & PGT_count_mask) != (!!(page->u.inuse.type_info & PGT_pinned) + (which == PTWR_PT_ACTIVE))) ) @@ -2945,13 +2939,13 @@ void ptwr_destroy(struct domain *d) * Also, a domain mustn't have PGC_allocated pages when it is dying. */ ASSERT(e->tot_pages <= e->max_pages); - if ( unlikely(test_bit(DF_DYING, &e->d_flags)) || + if ( unlikely(test_bit(DF_DYING, &e->flags)) || unlikely(e->tot_pages == e->max_pages) || unlikely(!gnttab_prepare_for_transfer(e, d, gntref)) ) { MEM_LOG("Transferee has no reservation headroom (%d,%d), or " "provided a bad grant ref, or is dying (%p).\n", - e->tot_pages, e->max_pages, e->d_flags); + e->tot_pages, e->max_pages, e->flags); spin_unlock(&e->page_alloc_lock); put_domain(e); okay = 0; diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c index 6b4599fdf4..83d93ef3e6 100644 --- a/xen/arch/x86/mpparse.c +++ b/xen/arch/x86/mpparse.c @@ -1,5 +1,5 @@ /* - * Intel Multiprocessor Specificiation 1.1 and 1.4 + * Intel Multiprocessor Specification 1.1 and 1.4 * compliant MP-table parsing routines. * * (c) 1995 Alan Cox, Building #3 @@ -14,44 +14,48 @@ */ #include -#include -#include -#include +#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include -int numnodes = 1; /* XXX Xen */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define es7000_plat 0 /* XXX XEN */ /* Have we found an MP table */ int smp_found_config; +unsigned int __initdata maxcpus = NR_CPUS; /* * Various Linux-internal data structures created from the * MP-table. */ int apic_version [MAX_APICS]; +int mp_bus_id_to_type [MAX_MP_BUSSES]; +int mp_bus_id_to_node [MAX_MP_BUSSES]; +int mp_bus_id_to_local [MAX_MP_BUSSES]; int quad_local_to_mp_bus_id [NR_CPUS/4][4]; +int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_current_pci_id; -int *mp_bus_id_to_type; -int *mp_bus_id_to_node; -int *mp_bus_id_to_local; -int *mp_bus_id_to_pci_bus; -int max_mp_busses; -int max_irq_sources; /* I/O APIC entries */ struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; /* # of MP IRQ source entries */ -struct mpc_config_intsrc *mp_irqs; +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* MP IRQ source entries */ int mp_irq_entries; @@ -65,24 +69,18 @@ unsigned long mp_lapic_addr; unsigned int boot_cpu_physical_apicid = -1U; unsigned int boot_cpu_logical_apicid = -1U; /* Internal processor count */ -static unsigned int num_processors; +static unsigned int __initdata num_processors; /* Bitmask of physically existing CPUs */ -unsigned long phys_cpu_present_map; -unsigned long logical_cpu_present_map; +physid_mask_t phys_cpu_present_map; -#ifdef CONFIG_X86_CLUSTERED_APIC -unsigned char esr_disable = 0; -unsigned char clustered_apic_mode = CLUSTERED_APIC_NONE; -unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC; -#endif -unsigned char raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; +u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; /* * Intel MP BIOS table parsing routines: */ -#ifndef CONFIG_X86_VISWS_APIC + /* * Checksum an MP configuration block. */ @@ -98,48 +96,6 @@ static int __init mpf_checksum(unsigned char *mp, int len) } /* - * Processor encoding in an MP configuration block - */ - -static char __init *mpc_family(int family,int model) -{ - static char n[32]; - static char *model_defs[]= - { - "80486DX","80486DX", - "80486SX","80486DX/2 or 80487", - "80486SL","80486SX/2", - "Unknown","80486DX/2-WB", - "80486DX/4","80486DX/4-WB" - }; - - switch (family) { - case 0x04: - if (model < 10) - return model_defs[model]; - break; - - case 0x05: - return("Pentium(tm)"); - - case 0x06: - return("Pentium(tm) Pro"); - - case 0x0F: - if (model == 0x00) - return("Pentium 4(tm)"); - if (model == 0x01) - return("Pentium 4(tm)"); - if (model == 0x02) - return("Pentium 4(tm) XEON(tm)"); - if (model == 0x0F) - return("Special controller"); - } - sprintf(n,"Unknown CPU [%d:%d]",family, model); - return n; -} - -/* * Have to match translation table entries to main table entries by counter * hence the mpc_record variable .... can't see a less disgusting way of * doing this .... @@ -148,30 +104,30 @@ static char __init *mpc_family(int family,int model) static int mpc_record; static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata; +#ifdef CONFIG_X86_NUMAQ +static int MP_valid_apicid(int apicid, int version) +{ + return hweight_long(apicid & 0xf) == 1 && (apicid >> 4) != 0xf; +} +#else +static int MP_valid_apicid(int apicid, int version) +{ + if (version >= 0x14) + return apicid < 0xff; + else + return apicid < 0xf; +} +#endif + void __init MP_processor_info (struct mpc_config_processor *m) { - int ver, quad, logical_apicid; + int ver, apicid; + physid_mask_t tmp; if (!(m->mpc_cpuflag & CPU_ENABLED)) return; - logical_apicid = m->mpc_apicid; - if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) { - quad = translation_table[mpc_record]->trans_quad; - logical_apicid = (quad << 4) + - (m->mpc_apicid ? m->mpc_apicid << 1 : 1); - printk("Processor #%d %s APIC version %d (quad %d, apic %d)\n", - m->mpc_apicid, - mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , - (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), - m->mpc_apicver, quad, logical_apicid); - } else { - printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, - mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , - (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), - m->mpc_apicver); - } + apicid = mpc_apic_id(m, translation_table[mpc_record]); if (m->mpc_featureflag&(1<<0)) Dprintk(" Floating point unit present.\n"); @@ -224,68 +180,68 @@ void __init MP_processor_info (struct mpc_config_processor *m) if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { Dprintk(" Bootup CPU\n"); boot_cpu_physical_apicid = m->mpc_apicid; - boot_cpu_logical_apicid = logical_apicid; + boot_cpu_logical_apicid = apicid; } - if (num_processors >= NR_CPUS){ - printk(KERN_WARNING "NR_CPUS limit of %i reached. Cannot " - "boot CPU(apicid 0x%x).\n", NR_CPUS, m->mpc_apicid); + if (num_processors >= NR_CPUS) { + printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." + " Processor ignored.\n", NR_CPUS); + return; + } + + if (num_processors >= maxcpus) { + printk(KERN_WARNING "WARNING: maxcpus limit of %i reached." + " Processor ignored.\n", maxcpus); return; } num_processors++; + ver = m->mpc_apicver; - if (m->mpc_apicid > MAX_APICS) { - printk("Processor #%d INVALID. (Max ID: %d).\n", + if (!MP_valid_apicid(apicid, ver)) { + printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n", m->mpc_apicid, MAX_APICS); --num_processors; return; } - ver = m->mpc_apicver; - logical_cpu_present_map |= 1 << (num_processors-1); - phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid); - + tmp = apicid_to_cpu_present(apicid); + physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp); + /* * Validate version */ if (ver == 0x0) { - printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); + printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); ver = 0x10; } apic_version[m->mpc_apicid] = ver; - raw_phys_apicid[num_processors - 1] = m->mpc_apicid; + bios_cpu_apicid[num_processors - 1] = m->mpc_apicid; } static void __init MP_bus_info (struct mpc_config_bus *m) { char str[7]; - int quad; memcpy(str, m->mpc_bustype, 6); str[6] = 0; - - if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) { - quad = translation_table[mpc_record]->trans_quad; - mp_bus_id_to_node[m->mpc_busid] = quad; - mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local; - quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid; - printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad); - } else { - Dprintk("Bus #%d is %s\n", m->mpc_busid, str); - } + + mpc_oem_bus_info(m, str, translation_table[mpc_record]); if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) { + mpc_oem_pci_bus(m, translation_table[mpc_record]); mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; mp_current_pci_id++; } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; + } else if (strncmp(str, BUSTYPE_NEC98, sizeof(BUSTYPE_NEC98)-1) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_NEC98; } else { - printk("Unknown bustype %s - ignoring\n", str); + printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str); } } @@ -294,10 +250,10 @@ static void __init MP_ioapic_info (struct mpc_config_ioapic *m) if (!(m->mpc_flags & MPC_APIC_USABLE)) return; - printk("I/O APIC #%d Version %d at 0x%X.\n", + printk(KERN_INFO "I/O APIC #%d Version %d at 0x%X.\n", m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); if (nr_ioapics >= MAX_IO_APICS) { - printk("Max # of I/O APICs (%d) exceeded (found %d).\n", + printk(KERN_CRIT "Max # of I/O APICs (%d) exceeded (found %d).\n", MAX_IO_APICS, nr_ioapics); panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); } @@ -318,7 +274,7 @@ static void __init MP_intsrc_info (struct mpc_config_intsrc *m) m->mpc_irqtype, m->mpc_irqflag & 3, (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus, m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq); - if (++mp_irq_entries == max_irq_sources) + if (++mp_irq_entries == MAX_IRQ_SOURCES) panic("Max # of irq sources exceeded!!\n"); } @@ -344,16 +300,17 @@ static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) BUG(); } +#ifdef CONFIG_X86_NUMAQ static void __init MP_translation_info (struct mpc_config_translation *m) { - printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local); + printk(KERN_INFO "Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local); if (mpc_record >= MAX_MPC_ENTRY) - printk("MAX_MPC_ENTRY exceeded!\n"); + printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n"); else translation_table[mpc_record] = m; /* stash this for later */ - if (m->trans_quad+1 > numnodes) - numnodes = m->trans_quad+1; + if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad)) + node_set_online(m->trans_quad); } /* @@ -366,10 +323,11 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ int count = sizeof (*oemtable); /* the header size */ unsigned char *oemptr = ((unsigned char *)oemtable)+count; - printk("Found an OEM MPC table at %8p - parsing it ... \n", oemtable); + mpc_record = 0; + printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n", oemtable); if (memcmp(oemtable->oem_signature,MPC_OEM_SIGNATURE,4)) { - printk("SMP mpc oemtable: bad signature [%c%c%c%c]!\n", + printk(KERN_WARNING "SMP mpc oemtable: bad signature [%c%c%c%c]!\n", oemtable->oem_signature[0], oemtable->oem_signature[1], oemtable->oem_signature[2], @@ -378,7 +336,7 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ } if (mpf_checksum((unsigned char *)oemtable,oemtable->oem_length)) { - printk("SMP oem mptable: checksum error!\n"); + printk(KERN_WARNING "SMP oem mptable: checksum error!\n"); return; } while (count < oemtable->oem_length) { @@ -395,36 +353,42 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ } default: { - printk("Unrecognised OEM table entry type! - %d\n", (int) *oemptr); + printk(KERN_WARNING "Unrecognised OEM table entry type! - %d\n", (int) *oemptr); return; } } } } +static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, + char *productid) +{ + if (strncmp(oem, "IBM NUMA", 8)) + printk("Warning! May not be a NUMA-Q system!\n"); + if (mpc->mpc_oemptr) + smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, + mpc->mpc_oemsize); +} +#endif /* CONFIG_X86_NUMAQ */ + /* * Read/parse the MPC */ static int __init smp_read_mpc(struct mp_config_table *mpc) { - char oem[16], prod[14]; + char str[16]; + char oem[10]; int count=sizeof(*mpc); unsigned char *mpt=((unsigned char *)mpc)+count; - int num_bus = 0; - int num_irq = 0; - unsigned char *bus_data; if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) { - panic("SMP mptable: bad signature [%c%c%c%c]!\n", - mpc->mpc_signature[0], - mpc->mpc_signature[1], - mpc->mpc_signature[2], - mpc->mpc_signature[3]); + printk(KERN_ERR "SMP mptable: bad signature [0x%x]!\n", + *(u32 *)mpc->mpc_signature); return 0; } if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) { - panic("SMP mptable: checksum error!\n"); + printk(KERN_ERR "SMP mptable: checksum error!\n"); return 0; } if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) { @@ -438,14 +402,14 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) } memcpy(oem,mpc->mpc_oem,8); oem[8]=0; - printk("OEM ID: %s ",oem); + printk(KERN_INFO "OEM ID: %s ",oem); - memcpy(prod,mpc->mpc_productid,12); - prod[12]=0; - printk("Product ID: %s ",prod); + memcpy(str,mpc->mpc_productid,12); + str[12]=0; + printk("Product ID: %s ",str); + + mps_oem_check(mpc, oem, str); - detect_clustered_apic(oem, prod); - printk("APIC at: 0x%X\n",mpc->mpc_lapic); /* @@ -455,77 +419,10 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) if (!acpi_lapic) mp_lapic_addr = mpc->mpc_lapic; - if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) && mpc->mpc_oemptr) { - /* We need to process the oem mpc tables to tell us which quad things are in ... */ - mpc_record = 0; - smp_read_mpc_oem((struct mp_config_oemtable *)(unsigned long)mpc->mpc_oemptr, mpc->mpc_oemsize); - mpc_record = 0; - } - - /* Pre-scan to determine the number of bus and - * interrupts records we have - */ - while (count < mpc->mpc_length) { - switch (*mpt) { - case MP_PROCESSOR: - mpt += sizeof(struct mpc_config_processor); - count += sizeof(struct mpc_config_processor); - break; - case MP_BUS: - ++num_bus; - mpt += sizeof(struct mpc_config_bus); - count += sizeof(struct mpc_config_bus); - break; - case MP_INTSRC: - ++num_irq; - mpt += sizeof(struct mpc_config_intsrc); - count += sizeof(struct mpc_config_intsrc); - break; - case MP_IOAPIC: - mpt += sizeof(struct mpc_config_ioapic); - count += sizeof(struct mpc_config_ioapic); - break; - case MP_LINTSRC: - mpt += sizeof(struct mpc_config_lintsrc); - count += sizeof(struct mpc_config_lintsrc); - break; - default: - count = mpc->mpc_length; - break; - } - } - /* - * Paranoia: Allocate one extra of both the number of busses and number - * of irqs, and make sure that we have at least 4 interrupts per PCI - * slot. But some machines do not report very many busses, so we need - * to fall back on the older defaults. - */ - ++num_bus; - max_mp_busses = max(num_bus, MAX_MP_BUSSES); - if (num_irq < (4 * max_mp_busses)) - num_irq = 4 * num_bus; /* 4 intr/PCI slot */ - ++num_irq; - max_irq_sources = max(num_irq, MAX_IRQ_SOURCES); - - count = (max_mp_busses * sizeof(int)) * 4; - count += (max_irq_sources * sizeof(struct mpc_config_intsrc)); - bus_data = (void *)alloc_xenheap_pages(get_order(count)); - if (!bus_data) { - printk(KERN_ERR "SMP mptable: out of memory!\n"); - return 0; - } - mp_bus_id_to_type = (int *)&bus_data[0]; - mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))]; - mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2]; - mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3]; - mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4]; - memset(mp_bus_id_to_pci_bus, -1, max_mp_busses * sizeof(int)); - /* * Now process the configuration blocks. */ - count = sizeof(*mpc); - mpt = ((unsigned char *)mpc)+count; + mpc_record = 0; while (count < mpc->mpc_length) { switch(*mpt) { case MP_PROCESSOR: @@ -584,21 +481,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) } ++mpc_record; } - - if (clustered_apic_mode){ - phys_cpu_present_map = logical_cpu_present_map; - } - - - printk("Enabling APIC mode: "); - if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ) - printk("Clustered Logical. "); - else if(clustered_apic_mode == CLUSTERED_APIC_XAPIC) - printk("Physical. "); - else - printk("Flat. "); - printk("Using %d I/O APICs\n",nr_ioapics); - + clustered_apic_check(); if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; @@ -634,12 +517,12 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type) * If it does, we assume it's valid. */ if (mpc_default_type == 5) { - printk("ISA/PCI bus type with no IRQ information... falling back to ELCR\n"); + printk(KERN_INFO "ISA/PCI bus type with no IRQ information... falling back to ELCR\n"); if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13)) - printk("ELCR contains invalid data... not using ELCR\n"); + printk(KERN_WARNING "ELCR contains invalid data... not using ELCR\n"); else { - printk("Using ELCR to identify PCI interrupts\n"); + printk(KERN_INFO "Using ELCR to identify PCI interrupts\n"); ELCR_fallback = 1; } } @@ -686,24 +569,6 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) struct mpc_config_lintsrc lintsrc; int linttypes[2] = { mp_ExtINT, mp_NMI }; int i; - struct { - int mp_bus_id_to_type[MAX_MP_BUSSES]; - int mp_bus_id_to_node[MAX_MP_BUSSES]; - int mp_bus_id_to_local[MAX_MP_BUSSES]; - int mp_bus_id_to_pci_bus[MAX_MP_BUSSES]; - struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; - } *bus_data; - - bus_data = (void *)alloc_xenheap_pages(get_order(sizeof(*bus_data))); - if (!bus_data) - panic("SMP mptable: out of memory!\n"); - mp_bus_id_to_type = bus_data->mp_bus_id_to_type; - mp_bus_id_to_node = bus_data->mp_bus_id_to_node; - mp_bus_id_to_local = bus_data->mp_bus_id_to_local; - mp_bus_id_to_pci_bus = bus_data->mp_bus_id_to_pci_bus; - mp_irqs = bus_data->mp_irqs; - for (i = 0; i < MAX_MP_BUSSES; ++i) - mp_bus_id_to_pci_bus[i] = -1; /* * local APIC has default address @@ -732,7 +597,8 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) bus.mpc_busid = 0; switch (mpc_default_type) { default: - printk("???\nUnknown standard configuration %d\n", + printk("???\n"); + printk(KERN_ERR "Unknown standard configuration %d\n", mpc_default_type); /* fall through */ case 1: @@ -790,7 +656,7 @@ void __init get_smp_config (void) /* * ACPI may be used to obtain the entire SMP configuration or just to - * enumerate/configure processors (CONFIG_ACPI_HT_ONLY). Note that + * enumerate/configure processors (CONFIG_ACPI_BOOT). Note that * ACPI supports both logical (e.g. Hyper-Threading) and physical * processors, where MPS only supports physical. */ @@ -801,12 +667,12 @@ void __init get_smp_config (void) else if (acpi_lapic) printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n"); - printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); + printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { - printk(" IMCR and PIC compatibility mode.\n"); + printk(KERN_INFO " IMCR and PIC compatibility mode.\n"); pic_mode = 1; } else { - printk(" Virtual Wire compatibility mode.\n"); + printk(KERN_INFO " Virtual Wire compatibility mode.\n"); pic_mode = 0; } @@ -815,7 +681,7 @@ void __init get_smp_config (void) */ if (mpf->mpf_feature1 != 0) { - printk("Default MP configuration #%d\n", mpf->mpf_feature1); + printk(KERN_INFO "Default MP configuration #%d\n", mpf->mpf_feature1); construct_default_ISA_mptable(mpf->mpf_feature1); } else if (mpf->mpf_physptr) { @@ -838,7 +704,7 @@ void __init get_smp_config (void) if (!mp_irq_entries) { struct mpc_config_bus bus; - printk("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); + printk(KERN_ERR "BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); bus.mpc_type = MP_BUS; bus.mpc_busid = 0; @@ -851,7 +717,7 @@ void __init get_smp_config (void) } else BUG(); - printk("Processors: %d\n", num_processors); + printk(KERN_INFO "Processors: %d\n", num_processors); /* * Only use the first configuration found. */ @@ -875,11 +741,27 @@ static int __init smp_scan_config (unsigned long base, unsigned long length) || (mpf->mpf_specification == 4)) ) { smp_found_config = 1; - printk("found SMP MP-table at %08lx\n", + printk(KERN_INFO "found SMP MP-table at %08lx\n", virt_to_phys(mpf)); +#if 0 reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE); - if (mpf->mpf_physptr) - reserve_bootmem((unsigned long)mpf->mpf_physptr, PAGE_SIZE); + if (mpf->mpf_physptr) { + /* + * We cannot access to MPC table to compute + * table size yet, as only few megabytes from + * the bottom is mapped now. + * PC-9800's MPC table places on the very last + * of physical memory; so that simply reserving + * PAGE_SIZE from mpg->mpf_physptr yields BUG() + * in reserve_bootmem. + */ + unsigned long size = PAGE_SIZE; + unsigned long end = max_low_pfn * PAGE_SIZE; + if (mpf->mpf_physptr + size > end) + size = end - mpf->mpf_physptr; + reserve_bootmem(mpf->mpf_physptr, size); + } +#endif mpf_found = mpf; return 1; } @@ -889,7 +771,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length) return 0; } -void __init find_intel_smp (void) +void __init find_smp_config (void) { unsigned int address; @@ -913,53 +795,20 @@ void __init find_intel_smp (void) * there is a real-mode segmented pointer pointing to the * 4K EBDA area at 0x40E, calculate and scan it here. * - * NOTE! There were Linux loaders that will corrupt the EBDA + * NOTE! There are Linux loaders that will corrupt the EBDA * area, and as such this kind of SMP config may be less * trustworthy, simply because the SMP table may have been - * stomped on during early boot. Thankfully the bootloaders - * now honour the EBDA. + * stomped on during early boot. These loaders are buggy and + * should be fixed. + * + * MP1.4 SPEC states to only scan first 1K of 4K EBDA. */ - address = *(unsigned short *)phys_to_virt(0x40E); - address <<= 4; - smp_scan_config(address, 0x1000); + address = get_bios_ebda(); + if (address) + smp_scan_config(address, 0x400); } -#else - -/* - * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesn't have a BIOS(-configuration table). - * No problem for Linux. - */ -void __init find_visws_smp(void) -{ - smp_found_config = 1; - - phys_cpu_present_map |= 2; /* or in id 1 */ - apic_version[1] |= 0x10; /* integrated APIC */ - apic_version[0] |= 0x10; - - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; -} - -#endif - -/* - * - Intel MP Configuration Table - * - or SGI Visual Workstation configuration - */ -void __init find_smp_config (void) -{ -#ifdef CONFIG_X86_LOCAL_APIC - find_intel_smp(); -#endif -#ifdef CONFIG_VISWS - find_visws_smp(); -#endif -} - - /* -------------------------------------------------------------------------- ACPI-based MP Configuration -------------------------------------------------------------------------- */ @@ -987,7 +836,7 @@ void __init mp_register_lapic ( struct mpc_config_processor processor; int boot_cpu = 0; - if (id >= MAX_APICS) { + if (MAX_APICS - id <= 0) { printk(KERN_WARNING "Processor #%d invalid (max %d)\n", id, MAX_APICS); return; @@ -998,14 +847,7 @@ void __init mp_register_lapic ( processor.mpc_type = MP_PROCESSOR; processor.mpc_apicid = id; - - /* - * mp_register_lapic_address() which is called before the - * current function does the fixmap of FIX_APIC_BASE. - * Read in the correct APIC version from there - */ - processor.mpc_apicver = apic_read(APIC_LVR); - + processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR)); processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0); processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0); processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | @@ -1017,32 +859,32 @@ void __init mp_register_lapic ( MP_processor_info(&processor); } -#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ +#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_ACPI_BOOT)) #define MP_ISA_BUS 0 #define MP_MAX_IOAPIC_PIN 127 struct mp_ioapic_routing { int apic_id; - int irq_start; - int irq_end; + int gsi_base; + int gsi_end; u32 pin_programmed[4]; } mp_ioapic_routing[MAX_IO_APICS]; -static int __init mp_find_ioapic ( - int irq) +static int mp_find_ioapic ( + int gsi) { int i = 0; - /* Find the IOAPIC that manages this IRQ. */ + /* Find the IOAPIC that manages this GSI. */ for (i = 0; i < nr_ioapics; i++) { - if ((irq >= mp_ioapic_routing[i].irq_start) - && (irq <= mp_ioapic_routing[i].irq_end)) + if ((gsi >= mp_ioapic_routing[i].gsi_base) + && (gsi <= mp_ioapic_routing[i].gsi_end)) return i; } - printk(KERN_ERR "ERROR: Unable to locate IOAPIC for IRQ %d\n", irq); + printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); return -1; } @@ -1051,7 +893,7 @@ static int __init mp_find_ioapic ( void __init mp_register_ioapic ( u8 id, u32 address, - u32 irq_base) + u32 gsi_base) { int idx = 0; @@ -1077,19 +919,19 @@ void __init mp_register_ioapic ( mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx); /* - * Build basic IRQ lookup table to facilitate irq->io_apic lookups - * and to prevent reprogramming of IOAPIC pins (PCI IRQs). + * Build basic GSI lookup table to facilitate gsi->io_apic lookups + * and to prevent reprogramming of IOAPIC pins (PCI GSIs). */ mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid; - mp_ioapic_routing[idx].irq_start = irq_base; - mp_ioapic_routing[idx].irq_end = irq_base + + mp_ioapic_routing[idx].gsi_base = gsi_base; + mp_ioapic_routing[idx].gsi_end = gsi_base + io_apic_get_redir_entries(idx); printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " - "IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, + "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, - mp_ioapic_routing[idx].irq_start, - mp_ioapic_routing[idx].irq_end); + mp_ioapic_routing[idx].gsi_base, + mp_ioapic_routing[idx].gsi_end); return; } @@ -1099,21 +941,19 @@ void __init mp_override_legacy_irq ( u8 bus_irq, u8 polarity, u8 trigger, - u32 global_irq) + u32 gsi) { struct mpc_config_intsrc intsrc; - int i = 0; - int found = 0; int ioapic = -1; int pin = -1; /* - * Convert 'global_irq' to 'ioapic.pin'. + * Convert 'gsi' to 'ioapic.pin'. */ - ioapic = mp_find_ioapic(global_irq); + ioapic = mp_find_ioapic(gsi); if (ioapic < 0) return; - pin = global_irq - mp_ioapic_routing[ioapic].irq_start; + pin = gsi - mp_ioapic_routing[ioapic].gsi_base; /* * TBD: This check is for faulty timer entries, where the override @@ -1136,23 +976,9 @@ void __init mp_override_legacy_irq ( (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq); - /* - * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it. - * Otherwise create a new entry (e.g. global_irq == 2). - */ - for (i = 0; i < mp_irq_entries; i++) { - if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) - && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq)) { - mp_irqs[i] = intsrc; - found = 1; - break; - } - } - if (!found) { - mp_irqs[mp_irq_entries] = intsrc; - if (++mp_irq_entries == MAX_IRQ_SOURCES) - panic("Max # of irq sources exceeded!\n"); - } + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); return; } @@ -1160,35 +986,22 @@ void __init mp_override_legacy_irq ( void __init mp_config_acpi_legacy_irqs (void) { + struct mpc_config_intsrc intsrc; int i = 0; int ioapic = -1; - /* - * Initialize mp_irqs for IRQ configuration. - */ - unsigned char *bus_data; - int count; - - count = (MAX_MP_BUSSES * sizeof(int)) * 4; - count += (MAX_IRQ_SOURCES * sizeof(int)) * 4; - bus_data = (void *)alloc_xenheap_pages(get_order(count)); - if (!bus_data) { - panic("Fatal: can't allocate bus memory for ACPI legacy IRQ!"); - } - mp_bus_id_to_type = (int *)&bus_data[0]; - mp_bus_id_to_node = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int))]; - mp_bus_id_to_local = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 2]; - mp_bus_id_to_pci_bus = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 3]; - mp_irqs = (struct mpc_config_intsrc *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 4]; - for (i = 0; i < MAX_MP_BUSSES; ++i) - mp_bus_id_to_pci_bus[i] = -1; - /* * Fabricate the legacy ISA bus (bus #31). */ mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; Dprintk("Bus #%d is ISA\n", MP_ISA_BUS); + /* + * ES7000 has no legacy identity mappings + */ + if (es7000_plat) + return; + /* * Locate the IOAPIC that manages the ISA IRQs (0-15). */ @@ -1196,118 +1009,101 @@ void __init mp_config_acpi_legacy_irqs (void) if (ioapic < 0) return; + intsrc.mpc_type = MP_INTSRC; + intsrc.mpc_irqflag = 0; /* Conforming */ + intsrc.mpc_srcbus = MP_ISA_BUS; + intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; + /* - * Use the default configuration for the IRQs 0-15. These may be + * Use the default configuration for the IRQs 0-15. Unless * overriden by (MADT) interrupt source override entries. */ for (i = 0; i < 16; i++) { + int idx; - if (i == 2) - continue; /* Don't connect IRQ2 */ + for (idx = 0; idx < mp_irq_entries; idx++) { + struct mpc_config_intsrc *irq = mp_irqs + idx; - mp_irqs[mp_irq_entries].mpc_type = MP_INTSRC; - mp_irqs[mp_irq_entries].mpc_irqflag = 0; /* Conforming */ - mp_irqs[mp_irq_entries].mpc_srcbus = MP_ISA_BUS; - mp_irqs[mp_irq_entries].mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; - mp_irqs[mp_irq_entries].mpc_irqtype = mp_INT; - mp_irqs[mp_irq_entries].mpc_srcbusirq = i; /* Identity mapped */ - mp_irqs[mp_irq_entries].mpc_dstirq = i; + /* Do we already have a mapping for this ISA IRQ? */ + if (irq->mpc_srcbus == MP_ISA_BUS && irq->mpc_srcbusirq == i) + break; + + /* Do we already have a mapping for this IOAPIC pin */ + if ((irq->mpc_dstapic == intsrc.mpc_dstapic) && + (irq->mpc_dstirq == i)) + break; + } + + if (idx != mp_irq_entries) { + printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i); + continue; /* IRQ already used */ + } + + intsrc.mpc_irqtype = mp_INT; + intsrc.mpc_srcbusirq = i; /* Identity mapped */ + intsrc.mpc_dstirq = i; Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, " - "%d-%d\n", - mp_irqs[mp_irq_entries].mpc_irqtype, - mp_irqs[mp_irq_entries].mpc_irqflag & 3, - (mp_irqs[mp_irq_entries].mpc_irqflag >> 2) & 3, - mp_irqs[mp_irq_entries].mpc_srcbus, - mp_irqs[mp_irq_entries].mpc_srcbusirq, - mp_irqs[mp_irq_entries].mpc_dstapic, - mp_irqs[mp_irq_entries].mpc_dstirq); + "%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, + (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, + intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, + intsrc.mpc_dstirq); + mp_irqs[mp_irq_entries] = intsrc; if (++mp_irq_entries == MAX_IRQ_SOURCES) panic("Max # of irq sources exceeded!\n"); } } -#ifdef CONFIG_ACPI_PCI - -void __init mp_parse_prt (void) +int mp_register_gsi (u32 gsi, int edge_level, int active_high_low) { - struct acpi_prt_entry *entry = NULL; int ioapic = -1; int ioapic_pin = 0; - int irq = 0; int idx, bit = 0; - int edge_level = 0; - int active_high_low = 0; - /* - * Parsing through the PCI Interrupt Routing Table (PRT) and program - * routing for all entries. - */ - list_for_each_entry(entry, &acpi_prt.entries, node) { - /* Need to get irq for dynamic entry */ - if (entry->link.handle) { - irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low); - if (!irq) - continue; - } - else { - /* Hardwired IRQ. Assume PCI standard settings */ - irq = entry->link.index; - edge_level = 1; - active_high_low = 1; - } +#ifdef CONFIG_ACPI_BUS + /* Don't set up the ACPI SCI because it's already set up */ + if (acpi_fadt.sci_int == gsi) + return gsi; +#endif - /* Don't set up the ACPI SCI because it's already set up */ - if (acpi_fadt.sci_int == irq) { - entry->irq = irq; /*we still need to set entry's irq*/ - continue; - } - - ioapic = mp_find_ioapic(irq); - if (ioapic < 0) - continue; - ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; - - /* - * Avoid pin reprogramming. PRTs typically include entries - * with redundant pin->irq mappings (but unique PCI devices); - * we only only program the IOAPIC on the first. - */ - bit = ioapic_pin % 32; - idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32); - if (idx > 3) { - printk(KERN_ERR "Invalid reference to IOAPIC pin " - "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, - ioapic_pin); - continue; - } - if ((1<irq = irq; - continue; - } - - mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<irq = irq; - - printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", - entry->id.segment, entry->id.bus, - entry->id.device, ('A' + entry->pin), - mp_ioapic_routing[ioapic].apic_id, ioapic_pin, - entry->irq); + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) { + printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); + return gsi; } - - print_IO_APIC(); - return; + ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base; + + if (ioapic_renumber_irq) + gsi = ioapic_renumber_irq(ioapic, gsi); + + /* + * Avoid pin reprogramming. PRTs typically include entries + * with redundant pin->gsi mappings (but unique PCI devices); + * we only program the IOAPIC on the first. + */ + bit = ioapic_pin % 32; + idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32); + if (idx > 3) { + printk(KERN_ERR "Invalid reference to IOAPIC pin " + "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, + ioapic_pin); + return gsi; + } + if ((1< #include -#include +#include #include +#include #include #include #include @@ -95,25 +96,6 @@ void set_mtrr_ops(struct mtrr_ops * ops) /* Returns non-zero if we have the write-combining memory type */ static int have_wrcomb(void) { - struct pci_dev *dev; - - if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { - /* ServerWorks LE chipsets have problems with write-combining - Don't allow it and leave room for other chipsets to be tagged */ - if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) { - printk(KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n"); - return 0; - } - /* Intel 450NX errata # 23. Non ascending cachline evictions to - write combining memory may resulting in data corruption */ - if (dev->vendor == PCI_VENDOR_ID_INTEL && - dev->device == PCI_DEVICE_ID_INTEL_82451NX) - { - printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n"); - return 0; - } - } return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0); } diff --git a/xen/arch/x86/nmi.c b/xen/arch/x86/nmi.c index ee798f9a36..afdf8051bb 100644 --- a/xen/arch/x86/nmi.c +++ b/xen/arch/x86/nmi.c @@ -86,24 +86,20 @@ extern int logical_proc_id[]; int __init check_nmi_watchdog (void) { unsigned int prev_nmi_count[NR_CPUS]; - int j, cpu; + int cpu; if ( !nmi_watchdog ) return 0; printk("Testing NMI watchdog --- "); - for ( j = 0; j < smp_num_cpus; j++ ) - { - cpu = cpu_logical_map(j); + for ( cpu = 0; cpu < smp_num_cpus; cpu++ ) prev_nmi_count[cpu] = nmi_count(cpu); - } __sti(); mdelay((10*1000)/nmi_hz); /* wait 10 ticks */ - for ( j = 0; j < smp_num_cpus; j++ ) + for ( cpu = 0; cpu < smp_num_cpus; cpu++ ) { - cpu = cpu_logical_map(j); if ( nmi_count(cpu) - prev_nmi_count[cpu] <= 5 ) printk("CPU#%d stuck. ", cpu); else diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 9e47826998..5de96ec96d 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -10,8 +10,6 @@ #include #include -extern void (*interrupt[])(void); - extern int ioapic_guest_read(int apicid, int address, u32 *pval); extern int ioapic_guest_write(int apicid, int address, u32 pval); @@ -130,7 +128,7 @@ void physdev_init_dom0(struct domain *d) BUG_ON(d->arch.iobmp_mask == NULL); memset(d->arch.iobmp_mask, 0, IOBMP_BYTES); - set_bit(DF_PHYSDEV, &d->d_flags); + set_bit(DF_PHYSDEV, &d->flags); } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 8b8f8182e0..7310095f64 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include @@ -77,12 +76,7 @@ unsigned long wait_init_idle; struct exec_domain *idle_task[NR_CPUS] = { &idle0_exec_domain }; -#ifdef CONFIG_ACPI_INTERPRETER -int acpi_disabled = 0; -#else -int acpi_disabled = 1; -#endif -EXPORT_SYMBOL(acpi_disabled); +int acpi_disabled; int phys_proc_id[NR_CPUS]; int logical_proc_id[NR_CPUS]; @@ -341,12 +335,8 @@ static void __init do_initcalls(void) (*call)(); } -unsigned long pci_mem_start = 0x10000000; - static void __init start_of_day(void) { - unsigned long low_mem_size; - #ifdef MEMORY_GUARD /* Unmap the first page of CPU0's stack. */ extern unsigned long cpu0_stack[]; @@ -362,10 +352,6 @@ static void __init start_of_day(void) arch_do_createdomain(current); - /* Tell the PCI layer not to allocate too close to the RAM area.. */ - low_mem_size = ((max_page << PAGE_SHIFT) + 0xfffff) & ~0xfffff; - if ( low_mem_size > pci_mem_start ) pci_mem_start = low_mem_size; - identify_cpu(&boot_cpu_data); /* get CPU type info */ if ( cpu_has_fxsr ) set_in_cr4(X86_CR4_OSFXSR); if ( cpu_has_xmm ) set_in_cr4(X86_CR4_OSXMMEXCPT); @@ -383,7 +369,10 @@ static void __init start_of_day(void) #endif paging_init(); /* not much here now, but sets up fixmap */ if ( !opt_noacpi ) + { + acpi_boot_table_init(); acpi_boot_init(); + } #ifdef CONFIG_SMP if ( smp_found_config ) get_smp_config(); @@ -581,7 +570,7 @@ void __init __start_xen(multiboot_info_t *mbi) if ( dom0 == NULL ) panic("Error creating domain 0\n"); - set_bit(DF_PRIVILEGED, &dom0->d_flags); + set_bit(DF_PRIVILEGED, &dom0->flags); /* Grab the DOM0 command line. Skip past the image name. */ cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL); diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index 3651d9c9aa..3aa12ee5ea 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -30,11 +30,17 @@ #include #include +#define MFN_PINNED(_x) (frame_table[_x].u.inuse.type_info & PGT_pinned) + static void shadow_free_snapshot(struct domain *d, struct out_of_sync_entry *entry); static void remove_out_of_sync_entries(struct domain *d, unsigned long smfn); static void free_writable_pte_predictions(struct domain *d); +#if SHADOW_DEBUG +static void mark_shadows_as_reflecting_snapshot(struct domain *d, unsigned long gpfn); +#endif + /******** There's a per-domain shadow table spin lock which works fine for SMP @@ -62,6 +68,9 @@ shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn, __shadow_sync_mfn(d, gmfn); } + if ( !shadow_mode_refcounts(d) ) + return 1; + if ( unlikely(page_is_page_table(page)) ) return 1; @@ -89,7 +98,7 @@ shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn, // TLB flushes required when promoting a writable page, and also deal // with any outstanding (external) writable refs to this page (by // refusing to promote it). The pinning headache complicates this - // code -- it would all much get simpler if we stop using + // code -- it would all get much simpler if we stop using // shadow_lock() and move the shadow code to BIGLOCK(). // if ( unlikely(!get_page(page, d)) ) @@ -130,6 +139,9 @@ shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn, static inline void shadow_demote(struct domain *d, unsigned long gpfn, unsigned long gmfn) { + if ( !shadow_mode_refcounts(d) ) + return; + ASSERT(frame_table[gmfn].count_info & PGC_page_table); if ( shadow_max_pgtable_type(d, gpfn, NULL) == PGT_none ) @@ -210,7 +222,7 @@ alloc_shadow_page(struct domain *d, else { page = alloc_domheap_page(NULL); - void *l1 = map_domain_mem(page_to_pfn(page) << PAGE_SHIFT); + void *l1 = map_domain_mem(page_to_phys(page)); memset(l1, 0, PAGE_SIZE); unmap_domain_mem(l1); } @@ -312,7 +324,7 @@ free_shadow_l1_table(struct domain *d, unsigned long smfn) for ( i = min; i <= max; i++ ) { - put_page_from_l1e(pl1e[i], d); + shadow_put_page_from_l1e(pl1e[i], d); pl1e[i] = l1e_empty(); } @@ -348,21 +360,20 @@ free_shadow_hl2_table(struct domain *d, unsigned long smfn) static void inline free_shadow_l2_table(struct domain *d, unsigned long smfn) { - unsigned long *pl2e = map_domain_mem(smfn << PAGE_SHIFT); + l2_pgentry_t *pl2e = map_domain_mem(smfn << PAGE_SHIFT); int i, external = shadow_mode_external(d); for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) if ( external || is_guest_l2_slot(i) ) - if ( pl2e[i] & _PAGE_PRESENT ) - put_shadow_ref(pl2e[i] >> PAGE_SHIFT); + if ( l2e_get_flags(pl2e[i]) & _PAGE_PRESENT ) + put_shadow_ref(l2e_get_pfn(pl2e[i])); if ( (PGT_base_page_table == PGT_l2_page_table) && shadow_mode_translate(d) && !external ) { // free the ref to the hl2 // - put_shadow_ref(pl2e[l2_table_offset(LINEAR_PT_VIRT_START)] - >> PAGE_SHIFT); + put_shadow_ref(l2e_get_pfn(pl2e[l2_table_offset(LINEAR_PT_VIRT_START)])); } unmap_domain_mem(pl2e); @@ -428,6 +439,26 @@ void free_shadow_page(unsigned long smfn) free_domheap_page(page); } +void +remove_shadow(struct domain *d, unsigned long gpfn, u32 stype) +{ + unsigned long smfn; + + //printk("%s(gpfn=%lx, type=%x)\n", __func__, gpfn, stype); + + shadow_lock(d); + + while ( stype >= PGT_l1_shadow ) + { + smfn = __shadow_status(d, gpfn, stype); + if ( smfn && MFN_PINNED(smfn) ) + shadow_unpin(smfn); + stype -= PGT_l1_shadow; + } + + shadow_unlock(d); +} + static void inline release_out_of_sync_entry(struct domain *d, struct out_of_sync_entry *entry) { @@ -537,15 +568,22 @@ static void free_shadow_pages(struct domain *d) // free_out_of_sync_state(d); - // second, remove any outstanding refs from ed->arch.shadow_table... + // second, remove any outstanding refs from ed->arch.shadow_table + // and CR3. // for_each_exec_domain(d, ed) { if ( pagetable_val(ed->arch.shadow_table) ) { - put_shadow_ref(pagetable_val(ed->arch.shadow_table) >> PAGE_SHIFT); + put_shadow_ref(pagetable_get_pfn(ed->arch.shadow_table)); ed->arch.shadow_table = mk_pagetable(0); } + + if ( ed->arch.monitor_shadow_ref ) + { + put_shadow_ref(ed->arch.monitor_shadow_ref); + ed->arch.monitor_shadow_ref = 0; + } } // For external shadows, remove the monitor table's refs @@ -584,7 +622,6 @@ static void free_shadow_pages(struct domain *d) // under us... First, collect the list of pinned pages, then // free them. // -#define PINNED(_x) (frame_table[_x].u.inuse.type_info & PGT_pinned) for ( i = 0; i < shadow_ht_buckets; i++ ) { u32 count; @@ -596,7 +633,7 @@ static void free_shadow_pages(struct domain *d) count = 0; for ( x = &d->arch.shadow_ht[i]; x != NULL; x = x->next ) - if ( PINNED(x->smfn) ) + if ( MFN_PINNED(x->smfn) ) count++; if ( !count ) continue; @@ -604,7 +641,7 @@ static void free_shadow_pages(struct domain *d) mfn_list = xmalloc_array(unsigned long, count); count = 0; for ( x = &d->arch.shadow_ht[i]; x != NULL; x = x->next ) - if ( PINNED(x->smfn) ) + if ( MFN_PINNED(x->smfn) ) mfn_list[count++] = x->smfn; while ( count ) @@ -613,7 +650,18 @@ static void free_shadow_pages(struct domain *d) } xfree(mfn_list); } -#undef PINNED + + // Now free the pre-zero'ed pages from the domain + // + struct list_head *list_ent, *tmp; + list_for_each_safe(list_ent, tmp, &d->arch.free_shadow_frames) + { + list_del(list_ent); + perfc_decr(free_l1_pages); + + struct pfn_info *page = list_entry(list_ent, struct pfn_info, list); + free_domheap_page(page); + } shadow_audit(d, 0); @@ -624,9 +672,9 @@ void shadow_mode_init(void) { } -int _shadow_mode_enabled(struct domain *d) +int _shadow_mode_refcounts(struct domain *d) { - return shadow_mode_enabled(d); + return shadow_mode_refcounts(d); } static void alloc_monitor_pagetable(struct exec_domain *ed) @@ -706,7 +754,7 @@ void free_monitor_pagetable(struct exec_domain *ed) /* * Then free monitor_table. */ - mfn = (pagetable_val(ed->arch.monitor_table)) >> PAGE_SHIFT; + mfn = pagetable_get_pfn(ed->arch.monitor_table); free_domheap_page(&frame_table[mfn]); ed->arch.monitor_table = mk_pagetable(0); @@ -714,7 +762,9 @@ void free_monitor_pagetable(struct exec_domain *ed) } int -set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn) +set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn, + struct map_dom_mem_cache *l2cache, + struct map_dom_mem_cache *l1cache) { unsigned long phystab = pagetable_val(d->arch.phys_table); l2_pgentry_t *l2, l2e; @@ -724,26 +774,29 @@ set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn) ASSERT( phystab ); - l2 = map_domain_mem(phystab); + l2 = map_domain_mem_with_cache(phystab, l2cache); l2e = l2[l2_table_offset(va)]; - if ( !l2e_get_value(l2e) ) /* FIXME: check present bit? */ + if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) { l1page = alloc_domheap_page(NULL); if ( !l1page ) + { + unmap_domain_mem_with_cache(l2, l2cache); return 0; + } - l1 = map_domain_mem(page_to_pfn(l1page) << PAGE_SHIFT); + l1 = map_domain_mem_with_cache(page_to_phys(l1page), l1cache); memset(l1, 0, PAGE_SIZE); - unmap_domain_mem(l1); + unmap_domain_mem_with_cache(l1, l1cache); l2e = l2e_create_pfn(page_to_pfn(l1page), __PAGE_HYPERVISOR); l2[l2_table_offset(va)] = l2e; } - unmap_domain_mem(l2); + unmap_domain_mem_with_cache(l2, l2cache); - l1 = map_domain_mem(l2e_get_phys(l2e)); + l1 = map_domain_mem_with_cache(l2e_get_phys(l2e), l1cache); l1[l1_table_offset(va)] = l1e_create_pfn(mfn, __PAGE_HYPERVISOR); - unmap_domain_mem(l1); + unmap_domain_mem_with_cache(l1, l1cache); return 1; } @@ -755,14 +808,19 @@ alloc_p2m_table(struct domain *d) struct pfn_info *page, *l2page; l2_pgentry_t *l2; unsigned long mfn, pfn; + struct map_dom_mem_cache l1cache, l2cache; l2page = alloc_domheap_page(NULL); - if ( !l2page ) + if ( l2page == NULL ) return 0; - d->arch.phys_table = mk_pagetable(page_to_pfn(l2page) << PAGE_SHIFT); - l2 = map_domain_mem(page_to_pfn(l2page) << PAGE_SHIFT); + + init_map_domain_mem_cache(&l1cache); + init_map_domain_mem_cache(&l2cache); + + d->arch.phys_table = mk_pagetable(page_to_phys(l2page)); + l2 = map_domain_mem_with_cache(page_to_phys(l2page), &l2cache); memset(l2, 0, PAGE_SIZE); - unmap_domain_mem(l2); + unmap_domain_mem_with_cache(l2, &l2cache); list_ent = d->page_list.next; while ( list_ent != &d->page_list ) @@ -773,7 +831,7 @@ alloc_p2m_table(struct domain *d) ASSERT(pfn != INVALID_M2P_ENTRY); ASSERT(pfn < (1u<<20)); - set_p2m_entry(d, pfn, mfn); + set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache); list_ent = page->list.next; } @@ -787,12 +845,15 @@ alloc_p2m_table(struct domain *d) if ( (pfn != INVALID_M2P_ENTRY) && (pfn < (1u<<20)) ) { - set_p2m_entry(d, pfn, mfn); + set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache); } list_ent = page->list.next; } + destroy_map_domain_mem_cache(&l2cache); + destroy_map_domain_mem_cache(&l1cache); + return 1; } @@ -915,13 +976,13 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) { // external guests provide their own memory for their P2M maps. // - ASSERT( d == page_get_owner(&frame_table[pagetable_val( - d->arch.phys_table)>>PAGE_SHIFT]) ); + ASSERT( d == page_get_owner( + &frame_table[pagetable_get_pfn(d->arch.phys_table)]) ); } } printk("audit1\n"); - _audit_domain(d, AUDIT_ALREADY_LOCKED | AUDIT_ERRORS_OK); + _audit_domain(d, AUDIT_SHADOW_ALREADY_LOCKED | AUDIT_ERRORS_OK); printk("audit1 done\n"); // Get rid of any shadow pages from any previous shadow mode. @@ -929,15 +990,9 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) free_shadow_pages(d); printk("audit2\n"); - _audit_domain(d, AUDIT_ALREADY_LOCKED | AUDIT_ERRORS_OK); + _audit_domain(d, AUDIT_SHADOW_ALREADY_LOCKED | AUDIT_ERRORS_OK); printk("audit2 done\n"); - // Turn off writable page tables. - // It doesn't mix with shadow mode. - // And shadow mode offers a superset of functionality. - // - vm_assist(d, VMASST_CMD_disable, VMASST_TYPE_writable_pagetables); - /* * Tear down it's counts by disassembling its page-table-based ref counts. * Also remove CR3's gcount/tcount. @@ -959,23 +1014,27 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) * Assert that no pages are left with L1/L2/L3/L4 type. */ audit_adjust_pgtables(d, -1, 1); + d->arch.shadow_mode = mode; - struct list_head *list_ent = d->page_list.next; - while ( list_ent != &d->page_list ) + if ( shadow_mode_refcounts(d) ) { - struct pfn_info *page = list_entry(list_ent, struct pfn_info, list); - if ( !get_page_type(page, PGT_writable_page) ) - BUG(); - put_page_type(page); + struct list_head *list_ent = d->page_list.next; + while ( list_ent != &d->page_list ) + { + struct pfn_info *page = list_entry(list_ent, struct pfn_info, list); + if ( !get_page_type(page, PGT_writable_page) ) + BUG(); + put_page_type(page); - list_ent = page->list.next; + list_ent = page->list.next; + } } audit_adjust_pgtables(d, 1, 1); printk("audit3\n"); - _audit_domain(d, AUDIT_ALREADY_LOCKED); + _audit_domain(d, AUDIT_SHADOW_ALREADY_LOCKED | AUDIT_ERRORS_OK); printk("audit3 done\n"); return 0; @@ -1120,8 +1179,8 @@ void __shadow_mode_disable(struct domain *d) * Currently this does not fix up page ref counts, so it is valid to call * only when a domain is being destroyed. */ - BUG_ON(!test_bit(DF_DYING, &d->d_flags)); - d->arch.shadow_tainted_refcnts = 1; + BUG_ON(!test_bit(DF_DYING, &d->flags) && shadow_mode_refcounts(d)); + d->arch.shadow_tainted_refcnts = shadow_mode_refcounts(d); free_shadow_pages(d); free_writable_pte_predictions(d); @@ -1138,11 +1197,17 @@ void __shadow_mode_disable(struct domain *d) } } #endif - + d->arch.shadow_mode = 0; free_shadow_ht_entries(d); free_out_of_sync_entries(d); + + struct exec_domain *ed; + for_each_exec_domain(d, ed) + { + update_pagetables(ed); + } } static int shadow_mode_table_op( @@ -1281,6 +1346,7 @@ int shadow_mode_control(struct domain *d, dom0_shadow_control_t *sc) switch ( op ) { case DOM0_SHADOW_CONTROL_OP_OFF: + __shadow_sync_all(d); __shadow_mode_disable(d); break; @@ -1298,7 +1364,7 @@ int shadow_mode_control(struct domain *d, dom0_shadow_control_t *sc) case DOM0_SHADOW_CONTROL_OP_ENABLE_TRANSLATE: free_shadow_pages(d); rc = __shadow_mode_enable( - d, d->arch.shadow_mode|SHM_enable|SHM_translate); + d, d->arch.shadow_mode|SHM_enable|SHM_refcounts|SHM_translate); break; default: @@ -1560,23 +1626,23 @@ void shadow_map_l1_into_current_l2(unsigned long va) if ( init_table ) { + l1_pgentry_t sl1e; + int index = l1_table_offset(va); + int min = 1, max = 0; + gpl1e = &(linear_pg_table[l1_linear_offset(va) & ~(L1_PAGETABLE_ENTRIES-1)]); spl1e = &(shadow_linear_pg_table[l1_linear_offset(va) & ~(L1_PAGETABLE_ENTRIES-1)]); - l1_pgentry_t sl1e; - int index = l1_table_offset(va); - int min = 1, max = 0; - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) { l1pte_propagate_from_guest(d, gpl1e[i], &sl1e); if ( (l1e_get_flags(sl1e) & _PAGE_PRESENT) && - !shadow_get_page_from_l1e(sl1e, d) ) + unlikely(!shadow_get_page_from_l1e(sl1e, d)) ) sl1e = l1e_empty(); - if ( l1e_get_value(sl1e) == 0 ) /* FIXME: check flags? */ + if ( l1e_get_flags(sl1e) == 0 ) { // First copy entries from 0 until first invalid. // Then copy entries from index until first invalid. @@ -1695,7 +1761,8 @@ shadow_make_snapshot( if ( !get_shadow_ref(smfn) ) BUG(); - if ( shadow_max_pgtable_type(d, gpfn, &sl1mfn) == PGT_l1_shadow ) + if ( shadow_mode_refcounts(d) && + (shadow_max_pgtable_type(d, gpfn, &sl1mfn) == PGT_l1_shadow) ) min_max = pfn_to_page(sl1mfn)->tlbflush_timestamp; pfn_to_page(smfn)->tlbflush_timestamp = min_max; @@ -1748,7 +1815,18 @@ shadow_mark_mfn_out_of_sync(struct exec_domain *ed, unsigned long gpfn, ASSERT(spin_is_locked(&d->arch.shadow_lock)); ASSERT(pfn_valid(mfn)); - ASSERT((page->u.inuse.type_info & PGT_type_mask) == PGT_writable_page); + +#ifndef NDEBUG + u32 type = page->u.inuse.type_info & PGT_type_mask; + if ( shadow_mode_refcounts(d) ) + { + ASSERT(type == PGT_writable_page); + } + else + { + ASSERT(type && (type < PGT_l4_page_table)); + } +#endif FSH_LOG("%s(gpfn=%lx, mfn=%lx) c=%08x t=%08x", __func__, gpfn, mfn, page->count_info, page->u.inuse.type_info); @@ -1766,6 +1844,10 @@ shadow_mark_mfn_out_of_sync(struct exec_domain *ed, unsigned long gpfn, entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn); entry->writable_pl1e = -1; +#if SHADOW_DEBUG + mark_shadows_as_reflecting_snapshot(d, gpfn); +#endif + // increment guest's ref count to represent the entry in the // full shadow out-of-sync list. // @@ -1819,37 +1901,34 @@ void shadow_mark_va_out_of_sync( * Returns 0 otherwise. */ static int snapshot_entry_matches( - struct exec_domain *ed, unsigned long gmfn, unsigned index) + struct domain *d, l1_pgentry_t *guest_pt, + unsigned long gpfn, unsigned index) { - unsigned long gpfn = __mfn_to_gpfn(ed->domain, gmfn); - unsigned long smfn = __shadow_status(ed->domain, gpfn, PGT_snapshot); - unsigned long *guest, *snapshot; - int compare; - - ASSERT( ! IS_INVALID_M2P_ENTRY(gpfn) ); + unsigned long smfn = __shadow_status(d, gpfn, PGT_snapshot); + l1_pgentry_t *snapshot; // could be L1s or L2s or ... + int entries_match; perfc_incrc(snapshot_entry_matches_calls); if ( !smfn ) return 0; - guest = map_domain_mem(gmfn << PAGE_SHIFT); snapshot = map_domain_mem(smfn << PAGE_SHIFT); // This could probably be smarter, but this is sufficent for // our current needs. // - compare = (guest[index] == snapshot[index]); + entries_match = !l1e_has_changed(&guest_pt[index], &snapshot[index], + PAGE_FLAG_MASK); - unmap_domain_mem(guest); unmap_domain_mem(snapshot); #ifdef PERF_COUNTERS - if ( compare ) + if ( entries_match ) perfc_incrc(snapshot_entry_matches_true); #endif - return compare; + return entries_match; } /* @@ -1859,30 +1938,36 @@ static int snapshot_entry_matches( int __shadow_out_of_sync(struct exec_domain *ed, unsigned long va) { struct domain *d = ed->domain; - unsigned long l2mfn = pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT; + unsigned long l2mfn = pagetable_get_pfn(ed->arch.guest_table); + unsigned long l2pfn = __mfn_to_gpfn(d, l2mfn); l2_pgentry_t l2e; - unsigned long l1mfn; + unsigned long l1pfn, l1mfn; ASSERT(spin_is_locked(&d->arch.shadow_lock)); + ASSERT(VALID_M2P(l2pfn)); perfc_incrc(shadow_out_of_sync_calls); if ( page_out_of_sync(&frame_table[l2mfn]) && - !snapshot_entry_matches(ed, l2mfn, l2_table_offset(va)) ) + !snapshot_entry_matches(d, (l1_pgentry_t *)ed->arch.guest_vtable, + l2pfn, l2_table_offset(va)) ) return 1; __guest_get_l2e(ed, va, &l2e); if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) return 0; - l1mfn = __gpfn_to_mfn(d, l2e_get_pfn(l2e)); + l1pfn = l2e_get_pfn(l2e); + l1mfn = __gpfn_to_mfn(d, l1pfn); // If the l1 pfn is invalid, it can't be out of sync... if ( !VALID_MFN(l1mfn) ) return 0; if ( page_out_of_sync(&frame_table[l1mfn]) && - !snapshot_entry_matches(ed, l1mfn, l1_table_offset(va)) ) + !snapshot_entry_matches( + d, &linear_pg_table[l1_linear_offset(va) & ~(L1_PAGETABLE_ENTRIES-1)], + l1pfn, l1_table_offset(va)) ) return 1; return 0; @@ -2002,7 +2087,7 @@ static u32 remove_all_write_access_in_ptpage( found++; pt[i] = new; if ( is_l1_shadow ) - put_page_from_l1e(old, d); + shadow_put_page_from_l1e(old, d); #if 0 printk("removed write access to pfn=%lx mfn=%lx in smfn=%lx entry %x " @@ -2060,8 +2145,7 @@ int shadow_remove_all_write_access( // write_refs = (frame_table[readonly_gmfn].u.inuse.type_info & PGT_count_mask); - if ( write_refs && - (frame_table[readonly_gmfn].u.inuse.type_info & PGT_pinned) ) + if ( write_refs && MFN_PINNED(readonly_gmfn) ) { write_refs--; } @@ -2141,7 +2225,7 @@ static u32 remove_all_access_in_page( count++; if ( is_l1_shadow ) - put_page_from_l1e(ol2e, d); + shadow_put_page_from_l1e(ol2e, d); else /* must be an hl2 page */ put_page(&frame_table[forbidden_gmfn]); } @@ -2210,8 +2294,23 @@ static int resync_all(struct domain *d, u32 stype) if ( entry->snapshot_mfn == SHADOW_SNAPSHOT_ELSEWHERE ) continue; - if ( !(smfn = __shadow_status(d, entry->gpfn, stype)) ) - continue; + smfn = __shadow_status(d, entry->gpfn, stype); + + if ( !smfn ) + { + if ( shadow_mode_refcounts(d) ) + continue; + + // For light weight shadows, even when no shadow page exists, + // we need to resync the refcounts to the new contents of the + // guest page. + // This only applies when we have writable page tables. + // + if ( (stype == PGT_l1_shadow) && !VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ) + continue; + if ( (stype != PGT_l1_shadow) && !shadow_mode_write_all(d) ) + continue; + } FSH_LOG("resyncing t=%08x gpfn=%lx gmfn=%lx smfn=%lx snapshot_mfn=%lx", stype, entry->gpfn, entry->gmfn, smfn, entry->snapshot_mfn); @@ -2221,12 +2320,29 @@ static int resync_all(struct domain *d, u32 stype) // guest = map_domain_mem(entry->gmfn << PAGE_SHIFT); snapshot = map_domain_mem(entry->snapshot_mfn << PAGE_SHIFT); - shadow = map_domain_mem(smfn << PAGE_SHIFT); + + if ( smfn ) + shadow = map_domain_mem(smfn << PAGE_SHIFT); + else + shadow = NULL; + unshadow = 0; switch ( stype ) { case PGT_l1_shadow: { + l1_pgentry_t *guest1 = guest; + l1_pgentry_t *shadow1 = shadow; + l1_pgentry_t *snapshot1 = snapshot; + + ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)); + + if ( !shadow_mode_refcounts(d) ) + revalidate_l1(d, guest1, snapshot1); + + if ( !smfn ) + break; + u32 min_max_shadow = pfn_to_page(smfn)->tlbflush_timestamp; int min_shadow = SHADOW_MIN(min_max_shadow); int max_shadow = SHADOW_MAX(min_max_shadow); @@ -2236,10 +2352,6 @@ static int resync_all(struct domain *d, u32 stype) int min_snapshot = SHADOW_MIN(min_max_snapshot); int max_snapshot = SHADOW_MAX(min_max_snapshot); - l1_pgentry_t *guest1 = guest; - l1_pgentry_t *shadow1 = shadow; - l1_pgentry_t *snapshot1 = snapshot; - changed = 0; for ( i = min_shadow; i <= max_shadow; i++ ) @@ -2270,6 +2382,9 @@ static int resync_all(struct domain *d, u32 stype) l2_pgentry_t *shadow2 = shadow; l2_pgentry_t *snapshot2 = snapshot; + ASSERT(shadow_mode_write_all(d)); + BUG_ON(!shadow_mode_refcounts(d)); // not yet implemented + changed = 0; for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) { @@ -2295,8 +2410,7 @@ static int resync_all(struct domain *d, u32 stype) // Need a better solution long term. if ( !(l2e_get_flags(new_pde) & _PAGE_PRESENT) && unlikely(l2e_get_value(new_pde) != 0) && - !unshadow && - (frame_table[smfn].u.inuse.type_info & PGT_pinned) ) + !unshadow && MFN_PINNED(smfn) ) unshadow = 1; } if ( max == -1 ) @@ -2311,6 +2425,9 @@ static int resync_all(struct domain *d, u32 stype) l2_pgentry_t *snapshot2 = snapshot; l1_pgentry_t *shadow2 = shadow; + ASSERT(shadow_mode_write_all(d)); + BUG_ON(!shadow_mode_refcounts(d)); // not yet implemented + changed = 0; for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) { @@ -2338,7 +2455,8 @@ static int resync_all(struct domain *d, u32 stype) BUG(); } - unmap_domain_mem(shadow); + if ( smfn ) + unmap_domain_mem(shadow); unmap_domain_mem(snapshot); unmap_domain_mem(guest); @@ -2351,7 +2469,7 @@ static int resync_all(struct domain *d, u32 stype) unsigned long hl2mfn; if ( (hl2mfn = __shadow_status(d, entry->gpfn, PGT_hl2_shadow)) && - (frame_table[hl2mfn].u.inuse.type_info & PGT_pinned) ) + MFN_PINNED(hl2mfn) ) shadow_unpin(hl2mfn); } } @@ -2388,7 +2506,7 @@ void __shadow_sync_all(struct domain *d) !shadow_get_page_from_l1e(npte, d) ) BUG(); *ppte = npte; - put_page_from_l1e(opte, d); + shadow_put_page_from_l1e(opte, d); unmap_domain_mem(ppte); } @@ -2475,13 +2593,23 @@ int shadow_fault(unsigned long va, struct cpu_user_regs *regs) /* Write fault? */ if ( regs->error_code & 2 ) { + int allow_writes = 0; + if ( unlikely(!(l1e_get_flags(gpte) & _PAGE_RW)) ) { - /* Write fault on a read-only mapping. */ - SH_VVLOG("shadow_fault - EXIT: wr fault on RO page (%lx)", - l1e_get_value(gpte)); - perfc_incrc(shadow_fault_bail_ro_mapping); - goto fail; + if ( shadow_mode_page_writable(d, l1e_get_pfn(gpte)) ) + { + allow_writes = 1; + l1e_add_flags(&gpte, _PAGE_RW); + } + else + { + /* Write fault on a read-only mapping. */ + SH_VVLOG("shadow_fault - EXIT: wr fault on RO page (%lx)", + l1e_get_value(gpte)); + perfc_incrc(shadow_fault_bail_ro_mapping); + goto fail; + } } if ( !l1pte_write_fault(ed, &gpte, &spte, va) ) @@ -2491,6 +2619,9 @@ int shadow_fault(unsigned long va, struct cpu_user_regs *regs) shadow_unlock(d); return 0; } + + if ( allow_writes ) + l1e_remove_flags(&gpte, _PAGE_RW); } else { @@ -2506,21 +2637,22 @@ int shadow_fault(unsigned long va, struct cpu_user_regs *regs) /* * STEP 3. Write the modified shadow PTE and guest PTE back to the tables. */ - - /* XXX Watch out for read-only L2 entries! (not used in Linux). */ - if ( unlikely(__copy_to_user(&linear_pg_table[l1_linear_offset(va)], - &gpte, sizeof(gpte))) ) + if ( l1e_has_changed(&orig_gpte, &gpte, PAGE_FLAG_MASK) ) { - printk("shadow_fault() failed, crashing domain %d " - "due to a read-only L2 page table (gpde=%lx), va=%lx\n", - d->id, l2e_get_value(gpde), va); - domain_crash_synchronous(); - } + /* XXX Watch out for read-only L2 entries! (not used in Linux). */ + if ( unlikely(__copy_to_user(&linear_pg_table[l1_linear_offset(va)], + &gpte, sizeof(gpte))) ) + { + printk("%s() failed, crashing domain %d " + "due to a read-only L2 page table (gpde=%lx), va=%lx\n", + __func__, d->id, l2e_get_value(gpde), va); + domain_crash_synchronous(); + } - // if necessary, record the page table page as dirty - if ( unlikely(shadow_mode_log_dirty(d)) && - l1e_has_changed(&orig_gpte, &gpte, PAGE_FLAG_MASK)) - mark_dirty(d, __gpfn_to_mfn(d, l2e_get_pfn(gpde))); + // if necessary, record the page table page as dirty + if ( unlikely(shadow_mode_log_dirty(d)) ) + __mark_dirty(d, __gpfn_to_mfn(d, l2e_get_pfn(gpde))); + } shadow_set_l1e(va, spte, 1); @@ -2537,6 +2669,109 @@ int shadow_fault(unsigned long va, struct cpu_user_regs *regs) return 0; } +void shadow_l1_normal_pt_update( + struct domain *d, + unsigned long pa, l1_pgentry_t gpte, + struct map_dom_mem_cache *cache) +{ + unsigned long sl1mfn; + l1_pgentry_t *spl1e, spte; + + shadow_lock(d); + + sl1mfn = __shadow_status(current->domain, pa >> PAGE_SHIFT, PGT_l1_shadow); + if ( sl1mfn ) + { + SH_VVLOG("shadow_l1_normal_pt_update pa=%p, gpte=%08lx", + (void *)pa, l1e_get_value(gpte)); + l1pte_propagate_from_guest(current->domain, gpte, &spte); + + spl1e = map_domain_mem_with_cache(sl1mfn << PAGE_SHIFT, cache); + spl1e[(pa & ~PAGE_MASK) / sizeof(l1_pgentry_t)] = spte; + unmap_domain_mem_with_cache(spl1e, cache); + } + + shadow_unlock(d); +} + +void shadow_l2_normal_pt_update( + struct domain *d, + unsigned long pa, l2_pgentry_t gpde, + struct map_dom_mem_cache *cache) +{ + unsigned long sl2mfn; + l2_pgentry_t *spl2e; + + shadow_lock(d); + + sl2mfn = __shadow_status(current->domain, pa >> PAGE_SHIFT, PGT_l2_shadow); + if ( sl2mfn ) + { + SH_VVLOG("shadow_l2_normal_pt_update pa=%p, gpde=%08lx", + (void *)pa, l2e_get_value(gpde)); + spl2e = map_domain_mem_with_cache(sl2mfn << PAGE_SHIFT, cache); + validate_pde_change(d, gpde, + &spl2e[(pa & ~PAGE_MASK) / sizeof(l2_pgentry_t)]); + unmap_domain_mem_with_cache(spl2e, cache); + } + + shadow_unlock(d); +} + +#ifdef __x86_64__ +void shadow_l3_normal_pt_update( + struct domain *d, + unsigned long pa, l3_pgentry_t gpde, + struct map_dom_mem_cache *cache) +{ + BUG(); // not yet implemented +} + +void shadow_l4_normal_pt_update( + struct domain *d, + unsigned long pa, l4_pgentry_t gpde, + struct map_dom_mem_cache *cache) +{ + BUG(); // not yet implemented +} +#endif + +int shadow_do_update_va_mapping(unsigned long va, + l1_pgentry_t val, + struct exec_domain *ed) +{ + struct domain *d = ed->domain; + l1_pgentry_t spte; + int rc = 0; + + shadow_lock(d); + + //printk("%s(va=%p, val=%p)\n", __func__, (void *)va, (void *)l1e_get_value(val)); + + // This is actually overkill - we don't need to sync the L1 itself, + // just everything involved in getting to this L1 (i.e. we need + // linear_pg_table[l1_linear_offset(va)] to be in sync)... + // + __shadow_sync_va(ed, va); + + l1pte_propagate_from_guest(d, val, &spte); + shadow_set_l1e(va, spte, 0); + + /* + * If we're in log-dirty mode then we need to note that we've updated + * the PTE in the PT-holding page. We need the machine frame number + * for this. + */ + if ( shadow_mode_log_dirty(d) ) + __mark_dirty(d, va_to_l1mfn(ed, va)); + +// out: + shadow_unlock(d); + + return rc; +} + + /* * What lives where in the 32-bit address space in the various shadow modes, * and what it uses to get/maintain that mapping. @@ -2566,7 +2801,7 @@ int shadow_fault(unsigned long va, struct cpu_user_regs *regs) void __update_pagetables(struct exec_domain *ed) { struct domain *d = ed->domain; - unsigned long gmfn = pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT; + unsigned long gmfn = pagetable_get_pfn(ed->arch.guest_table); unsigned long gpfn = __mfn_to_gpfn(d, gmfn); unsigned long smfn, hl2mfn, old_smfn; @@ -2595,7 +2830,7 @@ void __update_pagetables(struct exec_domain *ed) smfn = shadow_l2_table(d, gpfn, gmfn); if ( !get_shadow_ref(smfn) ) BUG(); - old_smfn = pagetable_val(ed->arch.shadow_table) >> PAGE_SHIFT; + old_smfn = pagetable_get_pfn(ed->arch.shadow_table); ed->arch.shadow_table = mk_pagetable(smfn << PAGE_SHIFT); if ( old_smfn ) put_shadow_ref(old_smfn); @@ -2665,6 +2900,47 @@ void __update_pagetables(struct exec_domain *ed) #if SHADOW_DEBUG +// The following is entirely for _check_pagetable()'s benefit. +// _check_pagetable() wants to know whether a given entry in a +// shadow page table is supposed to be the shadow of the guest's +// current entry, or the shadow of the entry held in the snapshot +// taken above. +// +// Here, we mark all currently existing entries as reflecting +// the snapshot, above. All other places in xen that update +// the shadow will keep the shadow in sync with the guest's +// entries (via l1pte_propagate_from_guest and friends), which clear +// the SHADOW_REFLECTS_SNAPSHOT bit. +// +static void +mark_shadows_as_reflecting_snapshot(struct domain *d, unsigned long gpfn) +{ + unsigned long smfn; + l1_pgentry_t *l1e; + l2_pgentry_t *l2e; + unsigned i; + + if ( (smfn = __shadow_status(d, gpfn, PGT_l1_shadow)) ) + { + l1e = map_domain_mem(smfn << PAGE_SHIFT); + for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) + if ( is_guest_l1_slot(i) && + (l1e_get_flags(l1e[i]) & _PAGE_PRESENT) ) + l1e_add_flags(&l1e[i], SHADOW_REFLECTS_SNAPSHOT); + unmap_domain_mem(l1e); + } + + if ( (smfn = __shadow_status(d, gpfn, PGT_l2_shadow)) ) + { + l2e = map_domain_mem(smfn << PAGE_SHIFT); + for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) + if ( is_guest_l2_slot(i) && + (l2e_get_flags(l2e[i]) & _PAGE_PRESENT) ) + l2e_add_flags(&l2e[i], SHADOW_REFLECTS_SNAPSHOT); + unmap_domain_mem(l2e); + } +} + // BUG: these are not SMP safe... static int sh_l2_present; static int sh_l1_present; @@ -2687,96 +2963,109 @@ int shadow_status_noswap; #define FAIL(_f, _a...) \ do { \ - printk("XXX %s-FAIL (%d,%d,%d)" _f " at %s(%d)\n", \ + printk("XXX %s-FAIL (%d,%d,%d) " _f " at %s(%d)\n", \ sh_check_name, level, l2_idx, l1_idx, ## _a, \ __FILE__, __LINE__); \ - printk("g=%lx s=%lx &g=%p &s=%p" \ - " v2m(&g)=%08lx v2m(&s)=%08lx ea=%08x\n", \ - l1e_get_value(gpte), l1e_get_value(spte), pgpte, pspte, \ - v2m(ed, pgpte), v2m(ed, pspte), \ + printk("guest_pte=%lx eff_guest_pte=%lx shadow_pte=%lx " \ + "snapshot_pte=%lx &guest=%p &shadow=%p &snap=%p " \ + "v2m(&guest)=%p v2m(&shadow)=%p v2m(&snap)=%p ea=%08x\n", \ + l1e_get_value(guest_pte), l1e_get_value(eff_guest_pte), \ + l1e_get_value(shadow_pte), l1e_get_value(snapshot_pte), \ + p_guest_pte, p_shadow_pte, p_snapshot_pte, \ + (void *)v2m(ed, p_guest_pte), (void *)v2m(ed, p_shadow_pte), \ + (void *)v2m(ed, p_snapshot_pte), \ (l2_idx << L2_PAGETABLE_SHIFT) | \ (l1_idx << L1_PAGETABLE_SHIFT)); \ errors++; \ } while ( 0 ) static int check_pte( - struct exec_domain *ed, l1_pgentry_t *pgpte, l1_pgentry_t *pspte, - int level, int l2_idx, int l1_idx, int oos_ptes) + struct exec_domain *ed, + l1_pgentry_t *p_guest_pte, + l1_pgentry_t *p_shadow_pte, + l1_pgentry_t *p_snapshot_pte, + int level, int l2_idx, int l1_idx) { struct domain *d = ed->domain; - l1_pgentry_t gpte = *pgpte; - l1_pgentry_t spte = *pspte; - unsigned long mask, gpfn, smfn, gmfn; - int errors = 0; + l1_pgentry_t guest_pte = *p_guest_pte; + l1_pgentry_t shadow_pte = *p_shadow_pte; + l1_pgentry_t snapshot_pte = p_snapshot_pte ? *p_snapshot_pte : l1e_empty(); + l1_pgentry_t eff_guest_pte; + unsigned long mask, eff_guest_pfn, eff_guest_mfn, shadow_mfn; + int errors = 0, guest_writable; int page_table_page; - if ( (l1e_get_value(spte) == 0) || - (l1e_get_value(spte) == 0xdeadface) || - (l1e_get_value(spte) == 0x00000E00) ) + if ( (l1e_get_value(shadow_pte) == 0) || + (l1e_get_value(shadow_pte) == 0xdeadface) || + (l1e_get_value(shadow_pte) == 0x00000E00) ) return errors; /* always safe */ - if ( !(l1e_get_flags(spte) & _PAGE_PRESENT) ) - FAIL("Non zero not present spte"); + if ( !(l1e_get_flags(shadow_pte) & _PAGE_PRESENT) ) + FAIL("Non zero not present shadow_pte"); if ( level == 2 ) sh_l2_present++; if ( level == 1 ) sh_l1_present++; - if ( !(l1e_get_flags(gpte) & _PAGE_PRESENT) ) + if ( (l1e_get_flags(shadow_pte) & SHADOW_REFLECTS_SNAPSHOT) && p_snapshot_pte ) + eff_guest_pte = snapshot_pte; + else + eff_guest_pte = guest_pte; + + if ( !(l1e_get_flags(eff_guest_pte) & _PAGE_PRESENT) ) FAIL("Guest not present yet shadow is"); - mask = ~(_PAGE_GLOBAL|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW|PAGE_MASK); + mask = ~(_PAGE_GLOBAL|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW|_PAGE_AVAIL|PAGE_MASK); - if ( (l1e_get_value(spte) & mask) != (l1e_get_value(gpte) & mask) ) + if ( ((l1e_get_value(shadow_pte) & mask) != (l1e_get_value(eff_guest_pte) & mask)) ) FAIL("Corrupt?"); if ( (level == 1) && - (l1e_get_flags(spte) & _PAGE_DIRTY) && - !(l1e_get_flags(gpte) & _PAGE_DIRTY) && !oos_ptes ) + (l1e_get_flags(shadow_pte) & _PAGE_DIRTY) && + !(l1e_get_flags(eff_guest_pte) & _PAGE_DIRTY) ) FAIL("Dirty coherence"); - if ( (l1e_get_flags(spte) & _PAGE_ACCESSED) && - !(l1e_get_flags(gpte) & _PAGE_ACCESSED) && !oos_ptes ) + if ( (l1e_get_flags(shadow_pte) & _PAGE_ACCESSED) && + !(l1e_get_flags(eff_guest_pte) & _PAGE_ACCESSED) ) FAIL("Accessed coherence"); - if ( l1e_get_flags(spte) & _PAGE_GLOBAL ) + if ( l1e_get_flags(shadow_pte) & _PAGE_GLOBAL ) FAIL("global bit set in shadow"); - smfn = l1e_get_pfn(spte); - gpfn = l1e_get_pfn(gpte); - gmfn = __gpfn_to_mfn(d, gpfn); + eff_guest_pfn = l1e_get_pfn(eff_guest_pte); + eff_guest_mfn = __gpfn_to_mfn(d, eff_guest_pfn); + shadow_mfn = l1e_get_pfn(shadow_pte); - if ( !VALID_MFN(gmfn) ) - FAIL("%s: invalid gpfn=%lx gpte=%lx\n", __func__, gpfn, - l1e_get_value(gpte)); + if ( !VALID_MFN(eff_guest_mfn) && !shadow_mode_refcounts(d) ) + FAIL("%s: invalid eff_guest_pfn=%lx eff_guest_pte=%lx\n", __func__, eff_guest_pfn, + l1e_get_value(eff_guest_pte)); - page_table_page = mfn_is_page_table(gmfn); + page_table_page = mfn_is_page_table(eff_guest_mfn); - if ( (l1e_get_flags(spte) & _PAGE_RW ) && - !(l1e_get_flags(gpte) & _PAGE_RW) && !oos_ptes ) + guest_writable = + (l1e_get_flags(eff_guest_pte) & _PAGE_RW) || + (VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && (level == 1) && mfn_out_of_sync(eff_guest_mfn)); + + if ( (l1e_get_flags(shadow_pte) & _PAGE_RW ) && !guest_writable ) { - printk("gpfn=%lx gmfn=%lx smfn=%lx t=0x%08x page_table_page=%d " - "oos_ptes=%d\n", - gpfn, gmfn, smfn, - frame_table[gmfn].u.inuse.type_info, - page_table_page, oos_ptes); + printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=0x%08x page_table_page=%d\n", + eff_guest_pfn, eff_guest_mfn, shadow_mfn, + frame_table[eff_guest_mfn].u.inuse.type_info, + page_table_page); FAIL("RW coherence"); } if ( (level == 1) && - (l1e_get_flags(spte) & _PAGE_RW ) && - !((l1e_get_flags(gpte) & _PAGE_RW) && - (l1e_get_flags(gpte) & _PAGE_DIRTY)) && - !oos_ptes ) + (l1e_get_flags(shadow_pte) & _PAGE_RW ) && + !(guest_writable && (l1e_get_flags(eff_guest_pte) & _PAGE_DIRTY)) ) { - printk("gpfn=%lx gmfn=%lx smfn=%lx t=0x%08x page_table_page=%d " - "oos_ptes=%d\n", - gpfn, gmfn, smfn, - frame_table[gmfn].u.inuse.type_info, - page_table_page, oos_ptes); + printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=0x%08x page_table_page=%d\n", + eff_guest_pfn, eff_guest_mfn, shadow_mfn, + frame_table[eff_guest_mfn].u.inuse.type_info, + page_table_page); FAIL("RW2 coherence"); } - if ( gmfn == smfn ) + if ( eff_guest_mfn == shadow_mfn ) { if ( level > 1 ) FAIL("Linear map ???"); /* XXX this will fail on BSD */ @@ -2788,9 +3077,9 @@ static int check_pte( if ( level == 2 ) { - if ( __shadow_status(d, gpfn, PGT_l1_shadow) != smfn ) - FAIL("smfn problem gpfn=%lx smfn=%lx", gpfn, - __shadow_status(d, gpfn, PGT_l1_shadow)); + if ( __shadow_status(d, eff_guest_pfn, PGT_l1_shadow) != shadow_mfn ) + FAIL("shadow_mfn problem eff_guest_pfn=%lx shadow_mfn=%lx", eff_guest_pfn, + __shadow_status(d, eff_guest_pfn, PGT_l1_shadow)); } else BUG(); // XXX -- not handled yet. @@ -2807,24 +3096,29 @@ static int check_l1_table( { struct domain *d = ed->domain; int i; - l1_pgentry_t *gpl1e, *spl1e; - int errors = 0, oos_ptes = 0; + unsigned long snapshot_mfn; + l1_pgentry_t *p_guest, *p_shadow, *p_snapshot = NULL; + int errors = 0; if ( page_out_of_sync(pfn_to_page(gmfn)) ) { - gmfn = __shadow_status(d, gpfn, PGT_snapshot); - oos_ptes = 1; - ASSERT(gmfn); + snapshot_mfn = __shadow_status(d, gpfn, PGT_snapshot); + ASSERT(snapshot_mfn); + p_snapshot = map_domain_mem(snapshot_mfn << PAGE_SHIFT); } - gpl1e = map_domain_mem(gmfn << PAGE_SHIFT); - spl1e = map_domain_mem(smfn << PAGE_SHIFT); + p_guest = map_domain_mem(gmfn << PAGE_SHIFT); + p_shadow = map_domain_mem(smfn << PAGE_SHIFT); for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - errors += check_pte(ed, &gpl1e[i], &spl1e[i], 1, l2_idx, i, oos_ptes); + errors += check_pte(ed, p_guest+i, p_shadow+i, + p_snapshot ? p_snapshot+i : NULL, + 1, l2_idx, i); - unmap_domain_mem(spl1e); - unmap_domain_mem(gpl1e); + unmap_domain_mem(p_shadow); + unmap_domain_mem(p_guest); + if ( p_snapshot ) + unmap_domain_mem(p_snapshot); return errors; } @@ -2909,7 +3203,8 @@ int check_l2_table( errors += check_pte(ed, (l1_pgentry_t*)(&gpl2e[i]), /* Hmm, dirty ... */ (l1_pgentry_t*)(&spl2e[i]), - 2, i, 0, 0); + NULL, + 2, i, 0); unmap_domain_mem(spl2e); unmap_domain_mem(gpl2e); diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index a992045be2..7a3abe9913 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -48,8 +48,8 @@ #include #include #include - -#ifdef CONFIG_SMP +#include +#include /* Cconfigured maximum number of CPUs to activate. We name the parameter "maxcpus" rather than max_cpus to be compatible with Linux */ @@ -63,10 +63,10 @@ int smp_num_cpus = 1; int ht_per_core = 1; /* Bitmask of currently online CPUs */ -unsigned long cpu_online_map; +cpumask_t cpu_online_map; -static volatile unsigned long cpu_callin_map; -static volatile unsigned long cpu_callout_map; +cpumask_t cpu_callin_map; +cpumask_t cpu_callout_map; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS]; @@ -658,7 +658,7 @@ static void __init do_boot_cpu (int apicid) ed = idle->exec_domain[0]; - set_bit(DF_IDLETASK, &idle->d_flags); + set_bit(DF_IDLETASK, &idle->flags); ed->arch.monitor_table = mk_pagetable(__pa(idle_pg_table)); @@ -800,7 +800,8 @@ void __init smp_boot_cpus(void) if (!smp_found_config) { printk("SMP motherboard not detected.\n"); io_apic_irqs = 0; - cpu_online_map = phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_online_map = 1; smp_num_cpus = 1; if (APIC_init_uniprocessor()) printk("Local APIC not detected." @@ -815,7 +816,7 @@ void __init smp_boot_cpus(void) if (!test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map)) { printk("weird, boot CPU (#%d) not listed by the BIOS.\n", boot_cpu_physical_apicid); - phys_cpu_present_map |= (1 << hard_smp_processor_id()); + physid_set(hard_smp_processor_id(), phys_cpu_present_map); } /* @@ -827,7 +828,8 @@ void __init smp_boot_cpus(void) boot_cpu_physical_apicid); printk("... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); io_apic_irqs = 0; - cpu_online_map = phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_online_map = 1; smp_num_cpus = 1; goto smp_done; } @@ -841,7 +843,8 @@ void __init smp_boot_cpus(void) smp_found_config = 0; printk("SMP mode deactivated, forcing use of dummy APIC emulation.\n"); io_apic_irqs = 0; - cpu_online_map = phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_online_map = 1; smp_num_cpus = 1; goto smp_done; } @@ -875,7 +878,7 @@ void __init smp_boot_cpus(void) if (opt_noht && (apicid & (ht_per_core - 1))) continue; - if (!(phys_cpu_present_map & (1 << bit))) + if (!check_apicid_present(bit)) continue; if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) continue; @@ -886,7 +889,7 @@ void __init smp_boot_cpus(void) * Make sure we unmap all failed CPUs */ if ((boot_apicid_to_cpu(apicid) == -1) && - (phys_cpu_present_map & (1 << bit))) + (!check_apicid_present(bit))) printk("CPU #%d not responding - cannot use it.\n", apicid); } @@ -923,7 +926,10 @@ void __init smp_boot_cpus(void) if ( nr_ioapics ) setup_IO_APIC(); /* Set up all local APIC timers in the system. */ - setup_APIC_clocks(); + { + extern void setup_APIC_clocks(void); + setup_APIC_clocks(); + } /* Synchronize the TSC with the AP(s). */ if ( cpucount ) synchronize_tsc_bp(); @@ -932,8 +938,6 @@ void __init smp_boot_cpus(void) ; } -#endif /* CONFIG_SMP */ - /* * Local variables: * mode: C diff --git a/xen/arch/x86/string.c b/xen/arch/x86/string.c index b45a9197d5..745670b926 100644 --- a/xen/arch/x86/string.c +++ b/xen/arch/x86/string.c @@ -8,25 +8,6 @@ #include #include -#undef memmove -void *memmove(void *dest, const void *src, size_t n) -{ - int d0, d1, d2; - - if ( dest < src ) - return memcpy(dest, src, n); - - __asm__ __volatile__ ( - " std ; " - " rep ; movsb ; " - " cld " - : "=&c" (d0), "=&S" (d1), "=&D" (d2) - : "0" (n), "1" (n-1+(const char *)src), "2" (n-1+(char *)dest) - : "memory"); - - return dest; -} - #undef memcpy void *memcpy(void *dest, const void *src, size_t n) { @@ -61,3 +42,22 @@ void *memset(void *s, int c, size_t n) return s; } + +#undef memmove +void *memmove(void *dest, const void *src, size_t n) +{ + int d0, d1, d2; + + if ( dest < src ) + return memcpy(dest, src, n); + + __asm__ __volatile__ ( + " std ; " + " rep ; movsb ; " + " cld " + : "=&c" (d0), "=&S" (d1), "=&D" (d2) + : "0" (n), "1" (n-1+(const char *)src), "2" (n-1+(char *)dest) + : "memory"); + + return dest; +} diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 3c5cc07c0c..52bd64ac9b 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -115,7 +115,8 @@ asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs) if ( trapnr == TRAP_page_fault ) { __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (cr2) : ); - printk("Faulting linear address might be %p\n", _p(cr2)); + printk("Faulting linear address: %p\n", _p(cr2)); + show_page_walk(cr2); } printk("************************************\n"); @@ -271,7 +272,8 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) perfc_incrc(page_faults); - if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) ) + if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && + !shadow_mode_enabled(d)) ) { LOCK_BIGLOCK(d); if ( unlikely(d->arch.ptwr[PTWR_PT_ACTIVE].l1va) && @@ -287,8 +289,6 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) ((regs->error_code & 3) == 3) && /* write-protection fault */ ptwr_do_page_fault(d, addr) ) { - if ( unlikely(shadow_mode_enabled(d)) ) - (void)shadow_fault(addr, regs); UNLOCK_BIGLOCK(d); return EXCRET_fault_fixed; } @@ -350,7 +350,7 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) show_page_walk(addr); panic("CPU%d FATAL PAGE FAULT\n" "[error_code=%04x]\n" - "Faulting linear address might be %p\n", + "Faulting linear address: %p\n", smp_processor_id(), regs->error_code, addr); return 0; } @@ -361,13 +361,13 @@ long do_fpu_taskswitch(int set) if ( set ) { - set_bit(EDF_GUEST_STTS, &ed->ed_flags); + set_bit(EDF_GUEST_STTS, &ed->flags); stts(); } else { - clear_bit(EDF_GUEST_STTS, &ed->ed_flags); - if ( test_bit(EDF_USEDFPU, &ed->ed_flags) ) + clear_bit(EDF_GUEST_STTS, &ed->flags); + if ( test_bit(EDF_USEDFPU, &ed->flags) ) clts(); } @@ -665,7 +665,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 0: /* Read CR0 */ *reg = (read_cr0() & ~X86_CR0_TS) | - (test_bit(EDF_GUEST_STTS, &ed->ed_flags) ? X86_CR0_TS : 0); + (test_bit(EDF_GUEST_STTS, &ed->flags) ? X86_CR0_TS : 0); break; case 2: /* Read CR2 */ @@ -919,15 +919,15 @@ asmlinkage int math_state_restore(struct cpu_user_regs *regs) /* Prevent recursion. */ clts(); - if ( !test_and_set_bit(EDF_USEDFPU, ¤t->ed_flags) ) + if ( !test_and_set_bit(EDF_USEDFPU, ¤t->flags) ) { - if ( test_bit(EDF_DONEFPUINIT, ¤t->ed_flags) ) + if ( test_bit(EDF_DONEFPUINIT, ¤t->flags) ) restore_fpu(current); else init_fpu(); } - if ( test_and_clear_bit(EDF_GUEST_STTS, ¤t->ed_flags) ) + if ( test_and_clear_bit(EDF_GUEST_STTS, ¤t->flags) ) { struct trap_bounce *tb = ¤t->arch.trap_bounce; tb->flags = TBF_EXCEPTION; diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c index 24a9bc7089..7fa433c0c1 100644 --- a/xen/arch/x86/vmx.c +++ b/xen/arch/x86/vmx.c @@ -672,7 +672,7 @@ static int vmx_set_cr0(unsigned long value) d->arch.arch_vmx.cpu_cr3); domain_crash_synchronous(); /* need to take a clean path */ } - old_base_mfn = pagetable_val(d->arch.guest_table) >> PAGE_SHIFT; + old_base_mfn = pagetable_get_pfn(d->arch.guest_table); if (old_base_mfn) put_page(pfn_to_page(old_base_mfn)); @@ -798,7 +798,7 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) "Invalid CR3 value=%lx", value); domain_crash_synchronous(); /* need to take a clean path */ } - old_base_mfn = pagetable_val(d->arch.guest_table) >> PAGE_SHIFT; + old_base_mfn = pagetable_get_pfn(d->arch.guest_table); d->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT); if (old_base_mfn) put_page(pfn_to_page(old_base_mfn)); diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index bd14acde01..d3453802b9 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -273,12 +273,8 @@ long set_fast_trap(struct exec_domain *p, int idx) return 0; } - /* - * We only fast-trap vectors 0x20-0x2f, and vector 0x80. - * The former range is used by Windows and MS-DOS. - * Vector 0x80 is used by Linux and the BSD variants. - */ - if ( (idx != 0x80) && ((idx < 0x20) || (idx > 0x2f)) ) + /* We only fast-trap vector 0x80 (used by Linux and the BSD variants). */ + if ( idx != 0x80 ) return -1; ti = &p->arch.guest_context.trap_ctxt[idx]; diff --git a/xen/common/bitmap.c b/xen/common/bitmap.c new file mode 100644 index 0000000000..d931eca83c --- /dev/null +++ b/xen/common/bitmap.c @@ -0,0 +1,365 @@ +/* + * lib/bitmap.c + * Helper functions for bitmap.h. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ +#include +#include +#include +#include +#include +#include + +/* + * bitmaps provide an array of bits, implemented using an an + * array of unsigned longs. The number of valid bits in a + * given bitmap does _not_ need to be an exact multiple of + * BITS_PER_LONG. + * + * The possible unused bits in the last, partially used word + * of a bitmap are 'don't care'. The implementation makes + * no particular effort to keep them zero. It ensures that + * their value will not affect the results of any operation. + * The bitmap operations that return Boolean (bitmap_empty, + * for example) or scalar (bitmap_weight, for example) results + * carefully filter out these unused bits from impacting their + * results. + * + * These operations actually hold to a slightly stronger rule: + * if you don't input any bitmaps to these ops that have some + * unused bits set, then they won't output any set unused bits + * in output bitmaps. + * + * The byte ordering of bitmaps is more natural on little + * endian architectures. See the big-endian headers + * include/asm-ppc64/bitops.h and include/asm-s390/bitops.h + * for the best explanations of this ordering. + */ + +int __bitmap_empty(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} +EXPORT_SYMBOL(__bitmap_empty); + +int __bitmap_full(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (~bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} +EXPORT_SYMBOL(__bitmap_full); + +int __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] != bitmap2[k]) + return 0; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} +EXPORT_SYMBOL(__bitmap_equal); + +void __bitmap_complement(unsigned long *dst, const unsigned long *src, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + dst[k] = ~src[k]; + + if (bits % BITS_PER_LONG) + dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits); +} +EXPORT_SYMBOL(__bitmap_complement); + +/* + * __bitmap_shift_right - logical right shift of the bits in a bitmap + * @dst - destination bitmap + * @src - source bitmap + * @nbits - shift by this many bits + * @bits - bitmap size, in bits + * + * Shifting right (dividing) means moving bits in the MS -> LS bit + * direction. Zeros are fed into the vacated MS positions and the + * LS bits shifted off the bottom are lost. + */ +void __bitmap_shift_right(unsigned long *dst, + const unsigned long *src, int shift, int bits) +{ + int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG; + int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; + unsigned long mask = (1UL << left) - 1; + for (k = 0; off + k < lim; ++k) { + unsigned long upper, lower; + + /* + * If shift is not word aligned, take lower rem bits of + * word above and make them the top rem bits of result. + */ + if (!rem || off + k + 1 >= lim) + upper = 0; + else { + upper = src[off + k + 1]; + if (off + k + 1 == lim - 1 && left) + upper &= mask; + } + lower = src[off + k]; + if (left && off + k == lim - 1) + lower &= mask; + dst[k] = upper << (BITS_PER_LONG - rem) | lower >> rem; + if (left && k == lim - 1) + dst[k] &= mask; + } + if (off) + memset(&dst[lim - off], 0, off*sizeof(unsigned long)); +} +EXPORT_SYMBOL(__bitmap_shift_right); + + +/* + * __bitmap_shift_left - logical left shift of the bits in a bitmap + * @dst - destination bitmap + * @src - source bitmap + * @nbits - shift by this many bits + * @bits - bitmap size, in bits + * + * Shifting left (multiplying) means moving bits in the LS -> MS + * direction. Zeros are fed into the vacated LS bit positions + * and those MS bits shifted off the top are lost. + */ + +void __bitmap_shift_left(unsigned long *dst, + const unsigned long *src, int shift, int bits) +{ + int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG; + int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; + for (k = lim - off - 1; k >= 0; --k) { + unsigned long upper, lower; + + /* + * If shift is not word aligned, take upper rem bits of + * word below and make them the bottom rem bits of result. + */ + if (rem && k > 0) + lower = src[k - 1]; + else + lower = 0; + upper = src[k]; + if (left && k == lim - 1) + upper &= (1UL << left) - 1; + dst[k + off] = lower >> (BITS_PER_LONG - rem) | upper << rem; + if (left && k + off == lim - 1) + dst[k + off] &= (1UL << left) - 1; + } + if (off) + memset(dst, 0, off*sizeof(unsigned long)); +} +EXPORT_SYMBOL(__bitmap_shift_left); + +void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] & bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_and); + +void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] | bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_or); + +void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] ^ bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_xor); + +void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] & ~bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_andnot); + +int __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] & bitmap2[k]) + return 1; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 1; + return 0; +} +EXPORT_SYMBOL(__bitmap_intersects); + +int __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] & ~bitmap2[k]) + return 0; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 0; + return 1; +} +EXPORT_SYMBOL(__bitmap_subset); + +#if BITS_PER_LONG == 32 +int __bitmap_weight(const unsigned long *bitmap, int bits) +{ + int k, w = 0, lim = bits/BITS_PER_LONG; + + for (k = 0; k < lim; k++) + w += hweight32(bitmap[k]); + + if (bits % BITS_PER_LONG) + w += hweight32(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); + + return w; +} +#else +int __bitmap_weight(const unsigned long *bitmap, int bits) +{ + int k, w = 0, lim = bits/BITS_PER_LONG; + + for (k = 0; k < lim; k++) + w += hweight64(bitmap[k]); + + if (bits % BITS_PER_LONG) + w += hweight64(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); + + return w; +} +#endif +EXPORT_SYMBOL(__bitmap_weight); + +/** + * bitmap_find_free_region - find a contiguous aligned mem region + * @bitmap: an array of unsigned longs corresponding to the bitmap + * @bits: number of bits in the bitmap + * @order: region size to find (size is actually 1< BITS_PER_LONG) + return -EINVAL; + + /* make a mask of the order */ + mask = (1ul << (pages - 1)); + mask += mask - 1; + + /* run up the bitmap pages bits at a time */ + for (i = 0; i < bits; i += pages) { + int index = i/BITS_PER_LONG; + int offset = i - (index * BITS_PER_LONG); + if((bitmap[index] & (mask << offset)) == 0) { + /* set region in bimap */ + bitmap[index] |= (mask << offset); + return i; + } + } + return -ENOMEM; +} +EXPORT_SYMBOL(bitmap_find_free_region); + +/** + * bitmap_release_region - release allocated bitmap region + * @bitmap: a pointer to the bitmap + * @pos: the beginning of the region + * @order: the order of the bits to release (number is 1< BITS_PER_LONG. The + * algorithm would be a simple look for multiple zeros in the + * array, but there's no driver today that needs this. If you + * trip this BUG(), you get to code it... */ + BUG_ON(pages > BITS_PER_LONG); + mask += mask - 1; + if (bitmap[index] & (mask << offset)) + return -EBUSY; + bitmap[index] |= (mask << offset); + return 0; +} +EXPORT_SYMBOL(bitmap_allocate_region); diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 750eb14813..23fc589d4d 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -139,7 +139,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) { ret = -EINVAL; if ( (d != current->domain) && - test_bit(DF_CONSTRUCTED, &d->d_flags) ) + test_bit(DF_CONSTRUCTED, &d->flags) ) { domain_unpause_by_systemcontroller(d); ret = 0; @@ -246,14 +246,14 @@ long do_dom0_op(dom0_op_t *u_dom0_op) if ( cpu == -1 ) { - clear_bit(EDF_CPUPINNED, &ed->ed_flags); + clear_bit(EDF_CPUPINNED, &ed->flags); } else { exec_domain_pause(ed); if ( ed->processor != (cpu % smp_num_cpus) ) - set_bit(EDF_MIGRATED, &ed->ed_flags); - set_bit(EDF_CPUPINNED, &ed->ed_flags); + set_bit(EDF_MIGRATED, &ed->flags); + set_bit(EDF_CPUPINNED, &ed->flags); ed->processor = cpu % smp_num_cpus; exec_domain_unpause(ed); } @@ -311,12 +311,12 @@ long do_dom0_op(dom0_op_t *u_dom0_op) ed = d->exec_domain[op->u.getdomaininfo.exec_domain]; op->u.getdomaininfo.flags = - (test_bit( DF_DYING, &d->d_flags) ? DOMFLAGS_DYING : 0) | - (test_bit( DF_CRASHED, &d->d_flags) ? DOMFLAGS_CRASHED : 0) | - (test_bit( DF_SHUTDOWN, &d->d_flags) ? DOMFLAGS_SHUTDOWN : 0) | - (test_bit(EDF_CTRLPAUSE, &ed->ed_flags) ? DOMFLAGS_PAUSED : 0) | - (test_bit(EDF_BLOCKED, &ed->ed_flags) ? DOMFLAGS_BLOCKED : 0) | - (test_bit(EDF_RUNNING, &ed->ed_flags) ? DOMFLAGS_RUNNING : 0); + (test_bit( DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) | + (test_bit( DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) | + (test_bit( DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) | + (test_bit(EDF_CTRLPAUSE, &ed->flags) ? DOMFLAGS_PAUSED : 0) | + (test_bit(EDF_BLOCKED, &ed->flags) ? DOMFLAGS_BLOCKED : 0) | + (test_bit(EDF_RUNNING, &ed->flags) ? DOMFLAGS_RUNNING : 0); op->u.getdomaininfo.flags |= ed->processor << DOMFLAGS_CPUSHIFT; op->u.getdomaininfo.flags |= diff --git a/xen/common/domain.c b/xen/common/domain.c index 253a6b102b..7ab17768c6 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -66,12 +66,12 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu) { write_lock(&domlist_lock); pd = &domain_list; /* NB. domain_list maintained in order of dom_id. */ - for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_list ) + for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) if ( (*pd)->id > d->id ) break; - d->next_list = *pd; + d->next_in_list = *pd; *pd = d; - d->next_hash = domain_hash[DOMAIN_HASH(dom_id)]; + d->next_in_hashbucket = domain_hash[DOMAIN_HASH(dom_id)]; domain_hash[DOMAIN_HASH(dom_id)] = d; write_unlock(&domlist_lock); } @@ -94,7 +94,7 @@ struct domain *find_domain_by_id(domid_t dom) d = NULL; break; } - d = d->next_hash; + d = d->next_in_hashbucket; } read_unlock(&domlist_lock); @@ -107,7 +107,7 @@ void domain_kill(struct domain *d) struct exec_domain *ed; domain_pause(d); - if ( !test_and_set_bit(DF_DYING, &d->d_flags) ) + if ( !test_and_set_bit(DF_DYING, &d->flags) ) { for_each_exec_domain(d, ed) sched_rem_domain(ed); @@ -124,7 +124,7 @@ void domain_crash(void) if ( d->id == 0 ) BUG(); - set_bit(DF_CRASHED, &d->d_flags); + set_bit(DF_CRASHED, &d->flags); send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC); @@ -164,9 +164,9 @@ void domain_shutdown(u8 reason) } if ( (d->shutdown_code = reason) == SHUTDOWN_crash ) - set_bit(DF_CRASHED, &d->d_flags); + set_bit(DF_CRASHED, &d->flags); else - set_bit(DF_SHUTDOWN, &d->d_flags); + set_bit(DF_SHUTDOWN, &d->flags); send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC); @@ -180,7 +180,7 @@ void domain_destruct(struct domain *d) struct domain **pd; atomic_t old, new; - if ( !test_bit(DF_DYING, &d->d_flags) ) + if ( !test_bit(DF_DYING, &d->flags) ) BUG(); /* May be already destructed, or get_domain() can race us. */ @@ -194,12 +194,12 @@ void domain_destruct(struct domain *d) write_lock(&domlist_lock); pd = &domain_list; while ( *pd != d ) - pd = &(*pd)->next_list; - *pd = d->next_list; + pd = &(*pd)->next_in_list; + *pd = d->next_in_list; pd = &domain_hash[DOMAIN_HASH(d->id)]; while ( *pd != d ) - pd = &(*pd)->next_hash; - *pd = d->next_hash; + pd = &(*pd)->next_in_hashbucket; + *pd = d->next_in_hashbucket; write_unlock(&domlist_lock); destroy_event_channels(d); @@ -227,8 +227,8 @@ int set_info_guest(struct domain *p, dom0_setdomaininfo_t *setdomaininfo) if ( (vcpu >= MAX_VIRT_CPUS) || ((ed = p->exec_domain[vcpu]) == NULL) ) return -EINVAL; - if (test_bit(DF_CONSTRUCTED, &p->d_flags) && - !test_bit(EDF_CTRLPAUSE, &ed->ed_flags)) + if (test_bit(DF_CONSTRUCTED, &p->flags) && + !test_bit(EDF_CTRLPAUSE, &ed->flags)) return -EINVAL; if ( (c = xmalloc(struct vcpu_guest_context)) == NULL ) @@ -243,7 +243,7 @@ int set_info_guest(struct domain *p, dom0_setdomaininfo_t *setdomaininfo) if ( (rc = arch_set_info_guest(ed, c)) != 0 ) goto out; - set_bit(DF_CONSTRUCTED, &p->d_flags); + set_bit(DF_CONSTRUCTED, &p->flags); out: xfree(c); @@ -294,7 +294,7 @@ long do_boot_vcpu(unsigned long vcpu, struct vcpu_guest_context *ctxt) sched_add_domain(ed); /* domain_unpause_by_systemcontroller */ - if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->ed_flags) ) + if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->flags) ) domain_wake(ed); xfree(c); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index b1ed16ac37..22b01ad541 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -40,7 +40,7 @@ static int get_free_port(struct exec_domain *ed) max = d->max_event_channel; chn = d->event_channel; - for ( port = ed->eid * EVENT_CHANNELS_SPREAD; port < max; port++ ) + for ( port = ed->id * EVENT_CHANNELS_SPREAD; port < max; port++ ) if ( chn[port].state == ECS_FREE ) break; diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index ca43f2f3c3..3449143458 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -109,7 +109,7 @@ static void do_task_queues(unsigned char key) for_each_domain ( d ) { printk("Xen: DOM %u, flags=%lx refcnt=%d nr_pages=%d " - "xenheap_pages=%d\n", d->id, d->d_flags, + "xenheap_pages=%d\n", d->id, d->flags, atomic_read(&d->refcnt), d->tot_pages, d->xenheap_pages); dump_pageframe_info(d); @@ -118,11 +118,11 @@ static void do_task_queues(unsigned char key) printk("Guest: %p CPU %d [has=%c] flags=%lx " "upcall_pend = %02x, upcall_mask = %02x\n", ed, ed->processor, - test_bit(EDF_RUNNING, &ed->ed_flags) ? 'T':'F', - ed->ed_flags, + test_bit(EDF_RUNNING, &ed->flags) ? 'T':'F', + ed->flags, ed->vcpu_info->evtchn_upcall_pending, ed->vcpu_info->evtchn_upcall_mask); - printk("Notifying guest... %d/%d\n", d->id, ed->eid); + printk("Notifying guest... %d/%d\n", d->id, ed->id); printk("port %d/%d stat %d %d %d\n", VIRQ_DEBUG, ed->virq_to_evtchn[VIRQ_DEBUG], test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 5573ced957..5a4115c82e 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -503,13 +504,13 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, unsigned int order) spin_lock(&d->page_alloc_lock); - if ( unlikely(test_bit(DF_DYING, &d->d_flags)) || + if ( unlikely(test_bit(DF_DYING, &d->flags)) || unlikely((d->tot_pages + (1 << order)) > d->max_pages) ) { DPRINTK("Over-allocation for domain %u: %u > %u\n", d->id, d->tot_pages + (1 << order), d->max_pages); DPRINTK("...or the domain is dying (%d)\n", - !!test_bit(DF_DYING, &d->d_flags)); + !!test_bit(DF_DYING, &d->flags)); spin_unlock(&d->page_alloc_lock); free_heap_pages(MEMZONE_DOM, pg, order); return NULL; @@ -574,7 +575,7 @@ void free_domheap_pages(struct pfn_info *pg, unsigned int order) spin_unlock_recursive(&d->page_alloc_lock); - if ( likely(!test_bit(DF_DYING, &d->d_flags)) ) + if ( likely(!test_bit(DF_DYING, &d->flags)) ) { free_heap_pages(MEMZONE_DOM, pg, order); } diff --git a/xen/common/perfc.c b/xen/common/perfc.c index 14ac09af41..157d49ffc8 100644 --- a/xen/common/perfc.c +++ b/xen/common/perfc.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,14 @@ void perfc_printall(unsigned char key) for ( j = sum = 0; j < perfc_info[i].nr_elements; j++ ) sum += atomic_read(&counters[j]); printk("TOTAL[%10d] ", sum); +#ifdef PERF_ARRAYS + for ( j = 0; j < perfc_info[i].nr_elements; j++ ) + { + if ( (j != 0) && ((j % 4) == 0) ) + printk("\n "); + printk("ARR%02d[%10d] ", j, atomic_read(&counters[j])); + } +#endif counters += j; break; } diff --git a/xen/common/resource.c b/xen/common/resource.c deleted file mode 100644 index 5f264c9806..0000000000 --- a/xen/common/resource.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * linux/kernel/resource.c - * - * Copyright (C) 1999 Linus Torvalds - * Copyright (C) 1999 Martin Mares - * - * Arbitrary resource management. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO }; -struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM }; - -static rwlock_t resource_lock = RW_LOCK_UNLOCKED; - -/* - * This generates reports for /proc/ioports and /proc/iomem - */ -static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end) -{ - if (offset < 0) - offset = 0; - - while (entry) { - const char *name = entry->name; - unsigned long from, to; - - if ((int) (end-buf) < 80) - return buf; - - from = entry->start; - to = entry->end; - if (!name) - name = ""; - - buf += sprintf(buf, fmt + offset, from, to, name); - if (entry->child) - buf = do_resource_list(entry->child, fmt, offset-2, buf, end); - entry = entry->sibling; - } - - return buf; -} - -int get_resource_list(struct resource *root, char *buf, int size) -{ - char *fmt; - int retval; - - fmt = " %08lx-%08lx : %s\n"; - if (root->end < 0x10000) - fmt = " %04lx-%04lx : %s\n"; - read_lock(&resource_lock); - retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf; - read_unlock(&resource_lock); - return retval; -} - -/* Return the conflict entry if you can't request it */ -static struct resource * __request_resource(struct resource *root, struct resource *new) -{ - unsigned long start = new->start; - unsigned long end = new->end; - struct resource *tmp, **p; - - if (end < start) - return root; - if (start < root->start) - return root; - if (end > root->end) - return root; - p = &root->child; - for (;;) { - tmp = *p; - if (!tmp || tmp->start > end) { - new->sibling = tmp; - *p = new; - new->parent = root; - return NULL; - } - p = &tmp->sibling; - if (tmp->end < start) - continue; - return tmp; - } -} - -static int __release_resource(struct resource *old) -{ - struct resource *tmp, **p; - - p = &old->parent->child; - for (;;) { - tmp = *p; - if (!tmp) - break; - if (tmp == old) { - *p = tmp->sibling; - old->parent = NULL; - return 0; - } - p = &tmp->sibling; - } - return -EINVAL; -} - -int request_resource(struct resource *root, struct resource *new) -{ - struct resource *conflict; - - write_lock(&resource_lock); - conflict = __request_resource(root, new); - write_unlock(&resource_lock); - return conflict ? -EBUSY : 0; -} - -int release_resource(struct resource *old) -{ - int retval; - - write_lock(&resource_lock); - retval = __release_resource(old); - write_unlock(&resource_lock); - return retval; -} - -int check_resource(struct resource *root, unsigned long start, unsigned long len) -{ - struct resource *conflict, tmp; - - tmp.start = start; - tmp.end = start + len - 1; - write_lock(&resource_lock); - conflict = __request_resource(root, &tmp); - if (!conflict) - __release_resource(&tmp); - write_unlock(&resource_lock); - return conflict ? -EBUSY : 0; -} - -/* - * Find empty slot in the resource tree given range and alignment. - */ -static int find_resource(struct resource *root, struct resource *new, - unsigned long size, - unsigned long min, unsigned long max, - unsigned long align, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data) -{ - struct resource *this = root->child; - - new->start = root->start; - for(;;) { - if (this) - new->end = this->start; - else - new->end = root->end; - if (new->start < min) - new->start = min; - if (new->end > max) - new->end = max; - new->start = (new->start + align - 1) & ~(align - 1); - if (alignf) - alignf(alignf_data, new, size, align); - if (new->start < new->end && new->end - new->start + 1 >= size) { - new->end = new->start + size - 1; - return 0; - } - if (!this) - break; - new->start = this->end + 1; - this = this->sibling; - } - return -EBUSY; -} - -/* - * Allocate empty slot in the resource tree given range and alignment. - */ -int allocate_resource(struct resource *root, struct resource *new, - unsigned long size, - unsigned long min, unsigned long max, - unsigned long align, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data) -{ - int err; - - write_lock(&resource_lock); - err = find_resource(root, new, size, min, max, align, alignf, alignf_data); - if (err >= 0 && __request_resource(root, new)) - err = -EBUSY; - write_unlock(&resource_lock); - return err; -} - -/* - * This is compatibility stuff for IO resources. - * - * Note how this, unlike the above, knows about - * the IO flag meanings (busy etc). - * - * Request-region creates a new busy region. - * - * Check-region returns non-zero if the area is already busy - * - * Release-region releases a matching busy region. - */ -struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name) -{ - struct resource *res = xmalloc(struct resource); - - if (res) { - memset(res, 0, sizeof(*res)); - res->name = name; - res->start = start; - res->end = start + n - 1; - res->flags = IORESOURCE_BUSY; - - write_lock(&resource_lock); - - for (;;) { - struct resource *conflict; - - conflict = __request_resource(parent, res); - if (!conflict) - break; - if (conflict != parent) { - parent = conflict; - if (!(conflict->flags & IORESOURCE_BUSY)) - continue; - } - - /* Uhhuh, that didn't work out.. */ - xfree(res); - res = NULL; - break; - } - write_unlock(&resource_lock); - } - return res; -} - -void __release_region(struct resource *parent, unsigned long start, unsigned long n) -{ - struct resource **p; - unsigned long end; - - p = &parent->child; - end = start + n - 1; - - for (;;) { - struct resource *res = *p; - - if (!res) - break; - if (res->start <= start && res->end >= end) { - if (!(res->flags & IORESOURCE_BUSY)) { - p = &res->child; - continue; - } - if (res->start != start || res->end != end) - break; - *p = res->sibling; - xfree(res); - return; - } - p = &res->sibling; - } - printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end); -} - - -#if 0 -/* - * Called from init/main.c to reserve IO ports. - */ -#define MAXRESERVE 4 -static int __init reserve_setup(char *str) -{ - static int reserved = 0; - static struct resource reserve[MAXRESERVE]; - - for (;;) { - int io_start, io_num; - int x = reserved; - - if (get_option (&str, &io_start) != 2) - break; - if (get_option (&str, &io_num) == 0) - break; - if (x < MAXRESERVE) { - struct resource *res = reserve + x; - res->name = "reserved"; - res->start = io_start; - res->end = io_start + io_num - 1; - res->flags = IORESOURCE_BUSY; - res->child = NULL; - if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0) - reserved = x+1; - } - } - return 1; -} - -__setup("reserve=", reserve_setup); -#endif - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 8 - * tab-width: 8 - * indent-tabs-mode: t - * End: - */ diff --git a/xen/common/sched_bvt.c b/xen/common/sched_bvt.c index 65fa6125bf..276479e490 100644 --- a/xen/common/sched_bvt.c +++ b/xen/common/sched_bvt.c @@ -59,7 +59,7 @@ struct bvt_cpu_info }; #define BVT_INFO(p) ((struct bvt_dom_info *)(p)->sched_priv) -#define EBVT_INFO(p) ((struct bvt_edom_info *)(p)->ed_sched_priv) +#define EBVT_INFO(p) ((struct bvt_edom_info *)(p)->sched_priv) #define CPU_INFO(cpu) ((struct bvt_cpu_info *)(schedule_data[cpu]).sched_priv) #define RUNLIST(p) ((struct list_head *)&(EBVT_INFO(p)->run_list)) #define RUNQUEUE(cpu) ((struct list_head *)&(CPU_INFO(cpu)->runqueue)) @@ -174,9 +174,9 @@ static int bvt_alloc_task(struct exec_domain *ed) return -1; memset(d->sched_priv, 0, sizeof(struct bvt_dom_info)); } - ed->ed_sched_priv = &BVT_INFO(d)->ed_inf[ed->eid]; - BVT_INFO(d)->ed_inf[ed->eid].inf = BVT_INFO(d); - BVT_INFO(d)->ed_inf[ed->eid].exec_domain = ed; + ed->sched_priv = &BVT_INFO(d)->ed_inf[ed->id]; + BVT_INFO(d)->ed_inf[ed->id].inf = BVT_INFO(d); + BVT_INFO(d)->ed_inf[ed->id].exec_domain = ed; return 0; } @@ -190,7 +190,7 @@ static void bvt_add_task(struct exec_domain *d) ASSERT(inf != NULL); ASSERT(d != NULL); - if (d->eid == 0) { + if (d->id == 0) { inf->mcu_advance = MCU_ADVANCE; inf->domain = d->domain; inf->warpback = 0; @@ -224,43 +224,43 @@ static void bvt_add_task(struct exec_domain *d) } } -static int bvt_init_idle_task(struct exec_domain *p) +static int bvt_init_idle_task(struct exec_domain *ed) { - if ( bvt_alloc_task(p) < 0 ) + if ( bvt_alloc_task(ed) < 0 ) return -1; - bvt_add_task(p); + bvt_add_task(ed); + + set_bit(EDF_RUNNING, &ed->flags); + if ( !__task_on_runqueue(ed) ) + __add_to_runqueue_head(ed); - set_bit(EDF_RUNNING, &p->ed_flags); - if ( !__task_on_runqueue(p) ) - __add_to_runqueue_head(p); - return 0; } -static void bvt_wake(struct exec_domain *d) +static void bvt_wake(struct exec_domain *ed) { - struct bvt_edom_info *einf = EBVT_INFO(d); + struct bvt_edom_info *einf = EBVT_INFO(ed); struct exec_domain *curr; s_time_t now, r_time; - int cpu = d->processor; + int cpu = ed->processor; u32 curr_evt; - if ( unlikely(__task_on_runqueue(d)) ) + if ( unlikely(__task_on_runqueue(ed)) ) return; - __add_to_runqueue_head(d); + __add_to_runqueue_head(ed); now = NOW(); /* Set the BVT parameters. AVT should always be updated if CPU migration ocurred.*/ if ( einf->avt < CPU_SVT(cpu) || - unlikely(test_bit(EDF_MIGRATED, &d->ed_flags)) ) + unlikely(test_bit(EDF_MIGRATED, &ed->flags)) ) einf->avt = CPU_SVT(cpu); /* Deal with warping here. */ - einf->evt = calc_evt(d, einf->avt); + einf->evt = calc_evt(ed, einf->avt); curr = schedule_data[cpu].curr; curr_evt = calc_evt(curr, calc_avt(curr, now)); @@ -277,12 +277,12 @@ static void bvt_wake(struct exec_domain *d) } -static void bvt_sleep(struct exec_domain *d) +static void bvt_sleep(struct exec_domain *ed) { - if ( test_bit(EDF_RUNNING, &d->ed_flags) ) - cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); - else if ( __task_on_runqueue(d) ) - __del_from_runqueue(d); + if ( test_bit(EDF_RUNNING, &ed->flags) ) + cpu_raise_softirq(ed->processor, SCHEDULE_SOFTIRQ); + else if ( __task_on_runqueue(ed) ) + __del_from_runqueue(ed); } /** @@ -377,7 +377,7 @@ static struct task_slice bvt_do_schedule(s_time_t now) struct bvt_edom_info *next_prime_einf = NULL; struct task_slice ret; - ASSERT(prev->ed_sched_priv != NULL); + ASSERT(prev->sched_priv != NULL); ASSERT(prev_einf != NULL); ASSERT(__task_on_runqueue(prev)); @@ -526,8 +526,8 @@ static void bvt_dump_cpu_state(int i) { struct list_head *queue; int loop = 0; - struct bvt_edom_info *d_inf; - struct exec_domain *d; + struct bvt_edom_info *ed_inf; + struct exec_domain *ed; printk("svt=0x%08lX ", CPU_SVT(i)); @@ -535,15 +535,15 @@ static void bvt_dump_cpu_state(int i) printk("QUEUE rq %lx n: %lx, p: %lx\n", (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); - list_for_each_entry ( d_inf, queue, run_list ) + list_for_each_entry ( ed_inf, queue, run_list ) { - d = d_inf->exec_domain; - printk("%3d: %u has=%c ", loop++, d->domain->id, - test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F'); - bvt_dump_runq_el(d); - printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time); + ed = ed_inf->exec_domain; + printk("%3d: %u has=%c ", loop++, ed->domain->id, + test_bit(EDF_RUNNING, &ed->flags) ? 'T':'F'); + bvt_dump_runq_el(ed); + printk("c=0x%X%08X\n", (u32)(ed->cpu_time>>32), (u32)ed->cpu_time); printk(" l: %p n: %p p: %p\n", - &d_inf->run_list, d_inf->run_list.next, d_inf->run_list.prev); + &ed_inf->run_list, ed_inf->run_list.next, ed_inf->run_list.prev); } } diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c new file mode 100644 index 0000000000..6bd8b5a0be --- /dev/null +++ b/xen/common/sched_sedf.c @@ -0,0 +1,1477 @@ +/****************************************************************************** + * Simple EDF scheduler for xen + * + * by Stephan Diestelhorst (C) 2004 Cambridge University + * based on code by Mark Williamson (C) 2004 Intel Research Cambridge + */ + +#include +#include +#include +#include +#include +#include +#include + +/*#include */ + +/*verbosity settings*/ +#define SEDFLEVEL 0 +#define PRINT(_f, _a...) \ +if ((_f)<=SEDFLEVEL) printk(_a ); + +#ifndef NDEBUG + #define SEDF_STATS + #define CHECK(_p) if ( !(_p) ) \ + { printk("Check '%s' failed, line %d, file %s\n", #_p , __LINE__,\ + __FILE__);} +#else + #define CHECK(_p) ((void)0) +#endif + +/*various ways of unblocking domains*/ +#define UNBLOCK_ISOCHRONOUS_EDF 1 +#define UNBLOCK_EDF 2 +#define UNBLOCK_ATROPOS 3 +#define UNBLOCK_SHORT_RESUME 4 +#define UNBLOCK_BURST 5 +#define UNBLOCK_EXTRA_SUPPORT 6 +#define UNBLOCK UNBLOCK_EXTRA_SUPPORT + +/*various ways of treating extra-time*/ +#define EXTRA_OFF 1 +#define EXTRA_ROUNDR 2 +#define EXTRA_SLICE_WEIGHT 3 +#define EXTRA_BLOCK_WEIGHT 4 + +#define EXTRA EXTRA_BLOCK_WEIGHT + +#define EXTRA_NONE (0) +#define EXTRA_AWARE (1) +#define EXTRA_RUN_PEN (2) +#define EXTRA_RUN_UTIL (4) +#define EXTRA_WANT_PEN_Q (8) +#define EXTRA_PEN_Q (0) +#define EXTRA_UTIL_Q (1) +#define SEDF_ASLEEP (16) + +#define EXTRA_QUANTUM (MICROSECS(500)) +#define WEIGHT_PERIOD (MILLISECS(100)) +#define WEIGHT_SAFETY (MILLISECS(5)) + +#define IMPLY(a, b) (!(a) || (b)) +#define EQ(a, b) ((!!(a)) == (!!(b))) + + +struct sedf_dom_info { + struct domain *domain; +}; +struct sedf_edom_info +{ + struct exec_domain *exec_domain; + struct list_head list; + struct list_head extralist[2]; + + /*Parameters for EDF*/ + s_time_t period; /*=(relative deadline)*/ + s_time_t slice; /*=worst case execution time*/ + + /*Advaced Parameters*/ + /*Latency Scaling*/ + s_time_t period_orig; + s_time_t slice_orig; + s_time_t latency; + + /*status of domain*/ + int status; + /*weights for "Scheduling for beginners/ lazy/ etc." ;)*/ + short weight; + short extraweight; + /*Bookkeeping*/ + s_time_t deadl_abs; + s_time_t sched_start_abs; + s_time_t cputime; + /* times the domain un-/blocked */ + s_time_t block_abs; + s_time_t unblock_abs; + + /*scores for {util, block penalty}-weighted extratime distribution*/ + int score[2]; + s_time_t short_block_lost_tot; + + /*Statistics*/ + s_time_t extra_time_tot; + +#ifdef SEDF_STATS + s_time_t block_time_tot; + s_time_t penalty_time_tot; + int block_tot; + int short_block_tot; + int long_block_tot; + int short_cont; + int pen_extra_blocks; + int pen_extra_slices; +#endif +}; + +struct sedf_cpu_info { + struct list_head runnableq; + struct list_head waitq; + struct list_head extraq[2]; +}; + +#define EDOM_INFO(d) ((struct sedf_edom_info *)((d)->sched_priv)) +#define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) +#define LIST(d) (&EDOM_INFO(d)->list) +#define EXTRALIST(d,i) (&(EDOM_INFO(d)->extralist[i])) +#define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) +#define WAITQ(cpu) (&CPU_INFO(cpu)->waitq) +#define EXTRAQ(cpu,i) (&(CPU_INFO(cpu)->extraq[i])) +#define IDLETASK(cpu) ((struct exec_domain *)schedule_data[cpu].idle) + +#define PERIOD_BEGIN(inf) ((inf)->deadl_abs - (inf)->period) + +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define DIV_UP(x,y) (((x) + (y) - 1) / y) + +#define extra_runs(inf) ((inf->status) & 6) +#define extra_get_cur_q(inf) (((inf->status & 6) >> 1)-1) +#define sedf_runnable(edom) (!(EDOM_INFO(edom)->status & SEDF_ASLEEP)) + + +static void sedf_dump_cpu_state(int i); + +static inline int extraq_on(struct exec_domain *d, int i) { + return ((EXTRALIST(d,i)->next != NULL) && + (EXTRALIST(d,i)->next != EXTRALIST(d,i))); +} + +static inline void extraq_add_head(struct exec_domain *d, int i) +{ + list_add(EXTRALIST(d,i), EXTRAQ(d->processor,i)); + ASSERT(extraq_on(d, i)); +} + +static inline void extraq_add_tail(struct exec_domain *d, int i) +{ + list_add_tail(EXTRALIST(d,i), EXTRAQ(d->processor,i)); + ASSERT(extraq_on(d, i)); +} + +static inline void extraq_del(struct exec_domain *d, int i) +{ + struct list_head *list = EXTRALIST(d,i); + ASSERT(extraq_on(d,i)); + PRINT(3, "Removing domain %i.%i from L%i extraq\n", d->domain->id, + d->id, i); + list_del(list); + list->next = NULL; + ASSERT(!extraq_on(d, i)); +} + +/* adds a domain to the queue of processes which are aware of extra time. List + is sorted by score, where a lower score means higher priority for an extra + slice. It also updates the score, by simply subtracting a fixed value from + each entry, in order to avoid overflow. The algorithm works by simply + charging each domain that recieved extratime with an inverse of its weight. + */ +static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) { + struct list_head *cur; + struct sedf_edom_info *curinf; + + ASSERT(!extraq_on(d,i)); + PRINT(3, "Adding domain %i.%i (score= %i, short_pen= %"PRIi64")" + " to L%i extraq\n", + d->domain->id, d->id, EDOM_INFO(d)->score[i], + EDOM_INFO(d)->short_block_lost_tot, i); + /*iterate through all elements to find our "hole" and on our way + update all the other scores*/ + list_for_each(cur,EXTRAQ(d->processor,i)){ + curinf = list_entry(cur,struct sedf_edom_info,extralist[i]); + curinf->score[i] -= sub; + if (EDOM_INFO(d)->score[i] < curinf->score[i]) + break; + else + PRINT(4,"\tbehind domain %i.%i (score= %i)\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->id, curinf->score[i]); + } + /*cur now contains the element, before which we'll enqueue*/ + PRINT(3, "\tlist_add to %p\n", cur->prev); + list_add(EXTRALIST(d,i),cur->prev); + + /*continue updating the extraq*/ + if ((cur != EXTRAQ(d->processor,i)) && sub) + for (cur = cur->next; cur != EXTRAQ(d->processor,i); + cur = cur-> next) { + curinf = list_entry(cur,struct sedf_edom_info, + extralist[i]); + curinf->score[i] -= sub; + PRINT(4, "\tupdating domain %i.%i (score= %u)\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->id, curinf->score[i]); + } + ASSERT(extraq_on(d,i)); +} +static inline void extraq_check(struct exec_domain *d) { + if (extraq_on(d, EXTRA_UTIL_Q)) { + PRINT(2,"Dom %i.%i is on L1 extraQ\n",d->domain->id, d->id); + if (!(EDOM_INFO(d)->status & EXTRA_AWARE) && + !extra_runs(EDOM_INFO(d))) { + extraq_del(d, EXTRA_UTIL_Q); + PRINT(2,"Removed dom %i.%i from L1 extraQ\n", + d->domain->id, d->id); + } + } else { + PRINT(2,"Dom %i.%i is NOT on L1 extraQ\n",d->domain->id, + d->id); + if ((EDOM_INFO(d)->status & EXTRA_AWARE) && sedf_runnable(d)) + { + #if (EXTRA == EXTRA_ROUNDR) + extraq_add_tail(d, EXTRA_UTIL_Q); + #elif (EXTRA == EXTRA_SLICE_WEIGHT || \ + EXTRA == EXTRA_BLOCK_WEIGHT) + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); + #elif + ; + #endif + PRINT(2,"Added dom %i.%i to L1 extraQ\n",d->domain->id, + d->id); + } + } +} + +static inline void extraq_check_add_unblocked(struct exec_domain *d, + int priority) { + struct sedf_edom_info *inf = EDOM_INFO(d); + if (inf->status & EXTRA_AWARE) + #if (EXTRA == EXTRA_ROUNDR) + if (priority) + extraq_add_head(d,EXTRA_UTIL_Q); + else + extraq_add_tail(d,EXTRA_UTIL_Q); + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ + || EXTRA == EXTRA_BLOCK_WEIGHT) + /*put in on the weighted extraq, + without updating any scores*/ + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); + #else + ; + #endif +} + +static inline int __task_on_queue(struct exec_domain *d) { + return (((LIST(d))->next != NULL) && (LIST(d)->next != LIST(d))); +} +static inline void __del_from_queue(struct exec_domain *d) +{ + struct list_head *list = LIST(d); + ASSERT(__task_on_queue(d)); + PRINT(3,"Removing domain %i.%i (bop= %"PRIu64") from runq/waitq\n", + d->domain->id, d->id, PERIOD_BEGIN(EDOM_INFO(d))); + list_del(list); + list->next = NULL; + ASSERT(!__task_on_queue(d)); +} + +typedef int(*list_comparer)(struct list_head* el1, struct list_head* el2); + +static inline void list_insert_sort(struct list_head *list, + struct list_head *element, list_comparer comp) { + struct list_head *cur; + /*iterate through all elements to find our "hole"*/ + list_for_each(cur,list){ + if (comp(element, cur) < 0) + break; + } + /*cur now contains the element, before which we'll enqueue*/ + PRINT(3,"\tlist_add to %p\n",cur->prev); + list_add(element, cur->prev); +} +#define DOMAIN_COMPARER(name, field, comp1, comp2) \ +int name##_comp(struct list_head* el1, struct list_head* el2) \ +{ \ + struct sedf_edom_info *d1, *d2; \ + d1 = list_entry(el1,struct sedf_edom_info, field); \ + d2 = list_entry(el2,struct sedf_edom_info, field); \ + if ((comp1) == (comp2)) \ + return 0; \ + if ((comp1) < (comp2)) \ + return -1; \ + else \ + return 1; \ +} +/* adds a domain to the queue of processes which wait for the beginning of the + next period; this list is therefore sortet by this time, which is simply + absol. deadline - period + */ +DOMAIN_COMPARER(waitq, list, PERIOD_BEGIN(d1), PERIOD_BEGIN(d2)) +static inline void __add_to_waitqueue_sort(struct exec_domain *d) { + ASSERT(!__task_on_queue(d)); + PRINT(3,"Adding domain %i.%i (bop= %"PRIu64") to waitq\n", + d->domain->id, d->id, PERIOD_BEGIN(EDOM_INFO(d))); + list_insert_sort(WAITQ(d->processor), LIST(d), waitq_comp); + ASSERT(__task_on_queue(d)); +} + +/* adds a domain to the queue of processes which have started their current + period and are runnable (i.e. not blocked, dieing,...). The first element + on this list is running on the processor, if the list is empty the idle + task will run. As we are implementing EDF, this list is sorted by deadlines. + */ +DOMAIN_COMPARER(runq, list, d1->deadl_abs, d2->deadl_abs) +static inline void __add_to_runqueue_sort(struct exec_domain *d) { + PRINT(3,"Adding domain %i.%i (deadl= %"PRIu64") to runq\n", + d->domain->id, d->id, EDOM_INFO(d)->deadl_abs); + list_insert_sort(RUNQ(d->processor), LIST(d), runq_comp); +} + +/* Initialises the queues */ +static int sedf_init_scheduler() { + int i; + PRINT(2,"sedf_init_scheduler was called\n"); + + for ( i = 0; i < NR_CPUS; i++ ) { + schedule_data[i].sched_priv = + xmalloc(struct sedf_cpu_info); + if ( schedule_data[i].sched_priv == NULL ) + return -1; + INIT_LIST_HEAD(WAITQ(i)); + INIT_LIST_HEAD(RUNQ(i)); + INIT_LIST_HEAD(EXTRAQ(i,EXTRA_PEN_Q)); + INIT_LIST_HEAD(EXTRAQ(i,EXTRA_UTIL_Q)); + } + return 0; +} + +/* Allocates memory for per domain private scheduling data*/ +static int sedf_alloc_task(struct exec_domain *d) { + PRINT(2,"sedf_alloc_task was called, domain-id %i.%i\n",d->domain->id, + d->id); + if (d->domain->sched_priv == NULL) { + if ((d->domain->sched_priv = + xmalloc(struct sedf_dom_info)) == NULL ) + return -1; + memset(d->domain->sched_priv, 0, sizeof(struct sedf_dom_info)); + } + if ((d->sched_priv = xmalloc(struct sedf_edom_info)) == NULL ) + return -1; + memset(d->sched_priv, 0, sizeof(struct sedf_edom_info)); + return 0; +} + +/* Setup the sedf_dom_info */ +static void sedf_add_task(struct exec_domain *d) +{ + struct sedf_edom_info *inf = EDOM_INFO(d); + inf->exec_domain = d; + + PRINT(2,"sedf_add_task was called, domain-id %i.%i\n",d->domain->id, + d->id); + + if (d->domain->id==0) { + /*set dom0 to something useful to boot the machine*/ + inf->period = MILLISECS(20); + inf->slice = MILLISECS(15); + inf->latency = 0; + inf->deadl_abs = 0; + inf->status = EXTRA_NONE | SEDF_ASLEEP;/*EXTRA_AWARE; */ + } + else { + /*other domains run in best effort mode*/ + inf->period = WEIGHT_PERIOD; + inf->slice = 0; + inf->deadl_abs = 0; + inf->latency = 0; + inf->status = EXTRA_AWARE | SEDF_ASLEEP; + inf->extraweight = 1; + } + inf->period_orig = inf->period; inf->slice_orig = inf->slice; + INIT_LIST_HEAD(&(inf->list)); + INIT_LIST_HEAD(&(inf->extralist[EXTRA_PEN_Q])); + INIT_LIST_HEAD(&(inf->extralist[EXTRA_UTIL_Q])); + + if (d->domain->id != IDLE_DOMAIN_ID) { + extraq_check(d); + } +} + +/* Frees memory used by domain info */ +static void sedf_free_task(struct domain *d) +{ + int i; + PRINT(2,"sedf_free_task was called, domain-id %i\n",d->id); + ASSERT(d->sched_priv != NULL); + xfree(d->sched_priv); + + for (i = 0; i < MAX_VIRT_CPUS; i++) + if ( d->exec_domain[i] ) { + ASSERT(d->exec_domain[i]->sched_priv != NULL); + xfree(d->exec_domain[i]->sched_priv); + } +} + +/* Initialises idle task */ +static int sedf_init_idle_task(struct exec_domain *d) { + PRINT(2,"sedf_init_idle_task was called, domain-id %i.%i\n", + d->domain->id, d->id); + if ( sedf_alloc_task(d) < 0 ) + return -1; + + sedf_add_task(d); + EDOM_INFO(d)->deadl_abs = 0; + EDOM_INFO(d)->status &= ~SEDF_ASLEEP; + set_bit(EDF_RUNNING, &d->flags); + /*the idle task doesn't have to turn up on any list...*/ + return 0; +} + +/* handles the rescheduling, bookkeeping of domains running in their realtime-time :)*/ +static inline void desched_edf_dom (s_time_t now, struct exec_domain* d) { + struct sedf_edom_info* inf = EDOM_INFO(d); + /*current domain is running in real time mode*/ + + ASSERT(__task_on_queue(d)); + /*update the domains cputime*/ + inf->cputime += now - inf->sched_start_abs; + + /*scheduling decisions, which don't remove the running domain + from the runq*/ + if ((inf->cputime < inf->slice) && sedf_runnable(d)) + return; + + __del_from_queue(d); + + /*manage bookkeeping (i.e. calculate next deadline, + memorize overun-time of slice) of finished domains*/ + if (inf->cputime >= inf->slice) { + inf->cputime -= inf->slice; + + if (inf->period < inf->period_orig) { + /*this domain runs in latency scaling or burst mode*/ + #if (UNBLOCK == UNBLOCK_BURST) + /*if we are runnig in burst scaling wait for two periods + before scaling periods up again*/ + if (now - inf->unblock_abs >= 2 * inf->period) + #endif + { + inf->period *= 2; inf->slice *= 2; + if ((inf->period > inf->period_orig) || + (inf->slice > inf->slice_orig)) { + /*reset slice & period*/ + inf->period = inf->period_orig; + inf->slice = inf->slice_orig; + } + } + } + /*set next deadline*/ + inf->deadl_abs += inf->period; + } + + /*add a runnable domain to the waitqueue*/ + if (sedf_runnable(d)) + __add_to_waitqueue_sort(d); + else { + /*we have a blocked realtime task -> remove it from exqs too*/ + #if (EXTRA > EXTRA_OFF) + #if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (extraq_on(d, EXTRA_PEN_Q)) extraq_del(d, EXTRA_PEN_Q); + #endif + if (extraq_on(d, EXTRA_UTIL_Q)) extraq_del(d, EXTRA_UTIL_Q); + #endif + } + ASSERT(EQ(sedf_runnable(d), __task_on_queue(d))); + ASSERT(IMPLY(extraq_on(d, EXTRA_UTIL_Q) || extraq_on(d, EXTRA_PEN_Q), + sedf_runnable(d))); +} + +/* Update all elements on the queues */ +static inline void update_queues(s_time_t now, struct list_head* runq, +struct list_head* waitq) { + struct list_head *cur,*tmp; + struct sedf_edom_info *curinf; + + PRINT(3,"Updating waitq..\n"); + /*check for the first elements of the waitqueue, whether their + next period has already started*/ + list_for_each_safe(cur, tmp, waitq) { + curinf = list_entry(cur, struct sedf_edom_info, list); + PRINT(4,"\tLooking @ dom %i.%i\n", + curinf->exec_domain->domain->id, curinf->exec_domain->id); + if (PERIOD_BEGIN(curinf) <= now) { + __del_from_queue(curinf->exec_domain); + __add_to_runqueue_sort(curinf->exec_domain); + } + else + break; + } + + PRINT(3,"Updating runq..\n"); + /*process the runq, find domains that are on + the runqueue which shouldn't be there*/ + list_for_each_safe(cur, tmp, runq) { + curinf = list_entry(cur,struct sedf_edom_info,list); + PRINT(4,"\tLooking @ dom %i.%i\n", + curinf->exec_domain->domain->id, curinf->exec_domain->id); + if (unlikely(curinf->slice == 0)) { + /*ignore domains with empty slice*/ + PRINT(4,"\tUpdating zero-slice domain %i.%i\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->id); + __del_from_queue(curinf->exec_domain); + + /*move them to their next period*/ + curinf->deadl_abs += curinf->period; + /*and put them back into the queue*/ + __add_to_waitqueue_sort(curinf->exec_domain); + continue; + } + if (unlikely((curinf->deadl_abs < now) || + (curinf->cputime > curinf->slice))) { + /*we missed the deadline or the slice was + already finished... might hapen because + of dom_adj.*/ + PRINT(4,"\tDomain %i.%i exceeded it's deadline/" + "slice (%"PRIu64" / %"PRIu64") now: %"PRIu64 + " cputime: %"PRIu64"\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->id, + curinf->deadl_abs, curinf->slice, now, + curinf->cputime); + __del_from_queue(curinf->exec_domain); + /*common case: we miss one period!*/ + curinf->deadl_abs += curinf->period; + + /*if we are still behind: modulo arithmetic, + force deadline to be in future and + aligned to period borders!*/ + if (unlikely(curinf->deadl_abs < now)) + curinf->deadl_abs += + DIV_UP(now - curinf->deadl_abs, + curinf->period) * curinf->period; + ASSERT(curinf->deadl_abs > now); + /*give a fresh slice*/ + curinf->cputime = 0; + if (PERIOD_BEGIN(curinf) > now) + __add_to_waitqueue_sort(curinf->exec_domain); + else + __add_to_runqueue_sort(curinf->exec_domain); + } + else + break; + } + PRINT(3,"done updating the queues\n"); +} + +#if (EXTRA > EXTRA_OFF) +/* removes a domain from the head of the according extraQ and + requeues it at a specified position: + round-robin extratime: end of extraQ + weighted ext.: insert in sorted list by score + if the domain is blocked / has regained its short-block-loss + time it is not put on any queue */ +static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { + struct sedf_edom_info *inf = EDOM_INFO(d); + int i = extra_get_cur_q(inf); + +#if (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + unsigned long oldscore; +#endif + ASSERT(extraq_on(d, i)); + /*unset all running flags*/ + inf->status &= ~(EXTRA_RUN_PEN | EXTRA_RUN_UTIL); + /*fresh slice for the next run*/ + inf->cputime = 0; + /*accumulate total extratime*/ + inf->extra_time_tot += now - inf->sched_start_abs; + /*remove extradomain from head of the queue*/ + extraq_del(d, i); + +#if (EXTRA == EXTRA_ROUNDR) + if (sedf_runnable(d) && (inf->status & EXTRA_AWARE)) + /*add to the tail if it is runnable => round-robin*/ + extraq_add_tail(d, EXTRA_UTIL_Q); +#elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + /*update the score*/ + oldscore = inf->score[i]; +#if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (i == EXTRA_PEN_Q) { + /*domain was running in L0 extraq*/ + /*reduce block lost, probably more sophistication here!*/ + /*inf->short_block_lost_tot -= EXTRA_QUANTUM;*/ + inf->short_block_lost_tot -= now - inf->sched_start_abs; + PRINT(3,"Domain %i.%i: Short_block_loss: %"PRIi64"\n", + inf->exec_domain->domain->id, inf->exec_domain->id, + inf->short_block_lost_tot); + if (inf->short_block_lost_tot <= 0) { + PRINT(4,"Domain %i.%i compensated short block loss!\n", + inf->exec_domain->domain->id, inf->exec_domain->id); + /*we have (over-)compensated our block penalty*/ + inf->short_block_lost_tot = 0; + /*we don't want a place on the penalty queue anymore!*/ + inf->status &= ~EXTRA_WANT_PEN_Q; + goto check_extra_queues; + } + /*we have to go again for another try in the block-extraq, + the score is not used incremantally here, as this is + already done by recalculating the block_lost*/ + inf->score[EXTRA_PEN_Q] = (inf->period << 10) / + inf->short_block_lost_tot; + oldscore = 0; + } else +#endif + { + /*domain was running in L1 extraq => score is inverse of + utilization and is used somewhat incremental!*/ + if (!inf->extraweight) + /*NB: use fixed point arithmetic with 10 bits*/ + inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / + inf->slice; + else + /*give a domain w/ exweight = 1 as much as a domain with + util = 1/128*/ + inf->score[EXTRA_UTIL_Q] = (1<<17) / inf->extraweight; + } +check_extra_queues: + /* Adding a runnable domain to the right queue and removing blocked ones*/ + if (sedf_runnable(d)) { + /*add according to score: weighted round robin*/ + if (inf->status & (EXTRA_AWARE | EXTRA_WANT_PEN_Q)) + extraq_add_sort_update(d, i, oldscore); + } + else { + /*remove this blocked domain from the waitq!*/ + __del_from_queue(d); +#if (EXTRA == EXTRA_BLOCK_WEIGHT) + /*make sure that we remove a blocked domain from the other + extraq too*/ + if (i == EXTRA_PEN_Q) { + if (extraq_on(d, EXTRA_UTIL_Q)) + extraq_del(d, EXTRA_UTIL_Q); + } + else { + if (extraq_on(d, EXTRA_PEN_Q)) + extraq_del(d, EXTRA_PEN_Q); + } +#endif + } +#endif + ASSERT(EQ(sedf_runnable(d), __task_on_queue(d))); + ASSERT(IMPLY(extraq_on(d, EXTRA_UTIL_Q) || extraq_on(d, EXTRA_PEN_Q), + sedf_runnable(d))); +} +#endif + +static inline struct task_slice sedf_do_extra_schedule (s_time_t now, + s_time_t end_xt, struct list_head *extraq[], int cpu) { + struct task_slice ret; + struct sedf_edom_info *runinf; + + /* Enough time left to use for extratime? */ + if (end_xt - now < EXTRA_QUANTUM) + goto return_idle; +#if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (!list_empty(extraq[EXTRA_PEN_Q])) { + /*we still have elements on the level 0 extraq + => let those run first!*/ + runinf = list_entry(extraq[EXTRA_PEN_Q]->next, + struct sedf_edom_info, extralist[EXTRA_PEN_Q]); + runinf->status |= EXTRA_RUN_PEN; + ret.task = runinf->exec_domain; + ret.time = EXTRA_QUANTUM; +#ifdef SEDF_STATS + runinf->pen_extra_slices++; +#endif + } else +#endif + if (!list_empty(extraq[EXTRA_UTIL_Q])) { + /*use elements from the normal extraqueue*/ + runinf = list_entry(extraq[EXTRA_UTIL_Q]->next, + struct sedf_edom_info, extralist[EXTRA_UTIL_Q]); + runinf->status |= EXTRA_RUN_UTIL; + ret.task = runinf->exec_domain; + ret.time = EXTRA_QUANTUM; + } + else + goto return_idle; + + ASSERT(ret.time > 0); + ASSERT(sedf_runnable(ret.task)); + return ret; + +return_idle: + ret.task = IDLETASK(cpu); + ret.time = end_xt - now; + ASSERT(ret.time > 0); + ASSERT(sedf_runnable(ret.task)); + return ret; +} +/* Main scheduling function + Reasons for calling this function are: + -timeslice for the current period used up + -domain on waitqueue has started it's period + -and various others ;) in general: determine which domain to run next*/ +static struct task_slice sedf_do_schedule(s_time_t now) +{ + int cpu = current->processor; + struct list_head *runq = RUNQ(cpu); + struct list_head *waitq = WAITQ(cpu); + #if (EXTRA > EXTRA_OFF) + struct sedf_edom_info *inf = EDOM_INFO(current); + struct list_head *extraq[] = {EXTRAQ(cpu, EXTRA_PEN_Q), + EXTRAQ(cpu, EXTRA_UTIL_Q)}; + #endif + struct task_slice ret; + /*int i = 0;*/ + /*idle tasks don't need any of the following stuf*/ + if (is_idle_task(current->domain)) + goto check_waitq; + + /* create local state of the status of the domain, in order to avoid + inconsistent state during scheduling decisions, because data for + domain_runnable is not protected by the scheduling lock!*/ + if(!domain_runnable(current)) + inf->status |= SEDF_ASLEEP; + + if (inf->status & SEDF_ASLEEP) + inf->block_abs = now; + + #if (EXTRA > EXTRA_OFF) + if (unlikely(extra_runs(inf))) { + /*special treatment of domains running in extra time*/ + desched_extra_dom(now, current); + } + else + #endif + { + desched_edf_dom(now, current); + } +check_waitq: + update_queues(now, runq, waitq); + + /*now simply pick the first domain from the runqueue, which has the + earliest deadline, because the list is sorted*/ + struct sedf_edom_info *runinf, *waitinf; + + if (!list_empty(runq)) { + runinf = list_entry(runq->next,struct sedf_edom_info,list); + ret.task = runinf->exec_domain; + if (!list_empty(waitq)) { + waitinf = list_entry(waitq->next, + struct sedf_edom_info,list); + /*rerun scheduler, when scheduled domain reaches it's + end of slice or the first domain from the waitqueue + gets ready*/ + ret.time = MIN(now + runinf->slice - runinf->cputime, + PERIOD_BEGIN(waitinf)) - now; + } + else { + ret.time = runinf->slice - runinf->cputime; + } + CHECK(ret.time > 0); + goto sched_done; + } + + if (!list_empty(waitq)) { + waitinf = list_entry(waitq->next,struct sedf_edom_info, list); + /*we could not find any suitable domain + => look for domains that are aware of extratime*/ + #if (EXTRA > EXTRA_OFF) + ret = sedf_do_extra_schedule(now, PERIOD_BEGIN(waitinf), + extraq, cpu); + #else + ret.task = IDLETASK(cpu); + ret.time = PERIOD_BEGIN(waitinf) - now; + #endif + CHECK(ret.time > 0); + } + else { + /*this could probably never happen, but one never knows...*/ + /*it can... imagine a second CPU, which is pure scifi ATM, + but one never knows ;)*/ + ret.task = IDLETASK(cpu); + ret.time = SECONDS(1); + } + +sched_done: + /*TODO: Do something USEFUL when this happens and find out, why it + still can happen!!!*/ + if (ret.time<0) { + printk("Ouch! We are seriously BEHIND schedule! %"PRIi64"\n", + ret.time); + ret.time = EXTRA_QUANTUM; + } + EDOM_INFO(ret.task)->sched_start_abs = now; + CHECK(ret.time > 0); + ASSERT(sedf_runnable(ret.task)); + return ret; +} + +static void sedf_sleep(struct exec_domain *d) { + PRINT(2,"sedf_sleep was called, domain-id %i.%i\n",d->domain->id, d->id); + + if (is_idle_task(d->domain)) + return; + + EDOM_INFO(d)->status |= SEDF_ASLEEP; + + if ( test_bit(EDF_RUNNING, &d->flags) ) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(d->processor); +#endif + cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); + } + else { + if ( __task_on_queue(d) ) + __del_from_queue(d); + #if (EXTRA > EXTRA_OFF) + if (extraq_on(d, EXTRA_UTIL_Q)) + extraq_del(d, EXTRA_UTIL_Q); + #endif + #if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (extraq_on(d, EXTRA_PEN_Q)) + extraq_del(d, EXTRA_PEN_Q); + #endif + } +} + +/* This function wakes up a domain, i.e. moves them into the waitqueue + * things to mention are: admission control is taking place nowhere at + * the moment, so we can't be sure, whether it is safe to wake the domain + * up at all. Anyway, even if it is safe (total cpu usage <=100%) there are + * some considerations on when to allow the domain to wake up and have it's + * first deadline... + * I detected 3 cases, which could describe the possible behaviour of the + * scheduler, + * and I'll try to make them more clear: + * + * 1. Very conservative + * -when a blocked domain unblocks, it is allowed to start execution at + * the beginning of the next complete period + * (D..deadline, R..running, B..blocking/sleeping, U..unblocking/waking up + * + * DRRB_____D__U_____DRRRRR___D________ ... + * + * -this causes the domain to miss a period (and a deadlline) + * -doesn't disturb the schedule at all + * -deadlines keep occuring isochronous + * + * 2. Conservative Part 1: Short Unblocking + * -when a domain unblocks in the same period as it was blocked it + * unblocks and may consume the rest of it's original time-slice minus + * the time it was blocked + * (assume period=9, slice=5) + * + * DRB_UR___DRRRRR___D... + * + * -this also doesn't disturb scheduling, but might lead to the fact, that + * the domain can't finish it's workload in the period + * -in addition to that the domain can be treated prioritised when + * extratime is available + * -addition: experiments hve shown that this may have a HUGE impact on + * performance of other domains, becaus it can lead to excessive context + * switches + + * Part2: Long Unblocking + * Part 2a + * -it is obvious that such accounting of block time, applied when + * unblocking is happening in later periods, works fine aswell + * -the domain is treated as if it would have been running since the start + * of its new period + * + * DRB______D___UR___D... + * + * Part 2b + * -if one needs the full slice in the next period, it is necessary to + * treat the unblocking time as the start of the new period, i.e. move + * the deadline further back (later) + * -this doesn't disturb scheduling as well, because for EDF periods can + * be treated as minimal inter-release times and scheduling stays + * correct, when deadlines are kept relative to the time the process + * unblocks + * + * DRB______D___URRRR___D... + * (D) <- old deadline was here + * -problem: deadlines don't occur isochronous anymore + * Part 2c (Improved Atropos design) + * -when a domain unblocks it is given a very short period (=latency hint) + * and slice length scaled accordingly + * -both rise again to the original value (e.g. get doubled every period) + * + * 3. Unconservative (i.e. incorrect) + * -to boost the performance of I/O dependent domains it would be possible + * to put the domain into the runnable queue immediately, and let it run + * for the remainder of the slice of the current period + * (or even worse: allocate a new full slice for the domain) + * -either behaviour can lead to missed deadlines in other domains as + * opposed to approaches 1,2a,2b + */ +static inline void unblock_short_vcons +(struct sedf_edom_info* inf, s_time_t now) { + inf->deadl_abs += inf->period; + inf->cputime = 0; +} + +static inline void unblock_short_cons(struct sedf_edom_info* inf, s_time_t now) +{ + /*treat blocked time as consumed by the domain*/ + inf->cputime += now - inf->block_abs; + if (inf->cputime + EXTRA_QUANTUM > inf->slice) { + /*we don't have a reasonable amount of time in + our slice left :( => start in next period!*/ + unblock_short_vcons(inf, now); + } +#ifdef SEDF_STATS + else + inf->short_cont++; +#endif +} +static inline void unblock_short_extra_support (struct sedf_edom_info* inf, + s_time_t now) { + /*this unblocking scheme tries to support the domain, by assigning it + a priority in extratime distribution according to the loss of time + in this slice due to blocking*/ + s_time_t pen; + + /*no more realtime execution in this period!*/ + inf->deadl_abs += inf->period; + if (likely(inf->block_abs)) { + //treat blocked time as consumed by the domain*/ + /*inf->cputime += now - inf->block_abs;*/ + /*penalty is time the domain would have + had if it continued to run */ + pen = (inf->slice - inf->cputime); + if (pen < 0) pen = 0; + /*accumulate all penalties over the periods*/ + /*inf->short_block_lost_tot += pen;*/ + /*set penalty to the current value*/ + inf->short_block_lost_tot = pen; + /*not sure which one is better.. but seems to work well...*/ + + if (inf->short_block_lost_tot) { + inf->score[0] = (inf->period << 10) / + inf->short_block_lost_tot; +#ifdef SEDF_STATS + inf->pen_extra_blocks++; +#endif + if (extraq_on(inf->exec_domain, EXTRA_PEN_Q)) + /*remove domain for possible resorting!*/ + extraq_del(inf->exec_domain, EXTRA_PEN_Q); + else + /*remember that we want to be on the penalty q + so that we can continue when we (un-)block + in penalty-extratime*/ + inf->status |= EXTRA_WANT_PEN_Q; + + /*(re-)add domain to the penalty extraq*/ + extraq_add_sort_update(inf->exec_domain, + EXTRA_PEN_Q, 0); + } + } + /*give it a fresh slice in the next period!*/ + inf->cputime = 0; +} +static inline void unblock_long_vcons(struct sedf_edom_info* inf, s_time_t now) +{ + /* align to next future period */ + inf->deadl_abs += (DIV_UP(now - inf->deadl_abs, inf->period) +1) + * inf->period; + inf->cputime = 0; +} + +static inline void unblock_long_cons_a (struct sedf_edom_info* inf, + s_time_t now) { + /*treat the time the domain was blocked in the + CURRENT period as consumed by the domain*/ + inf->cputime = (now - inf->deadl_abs) % inf->period; + if (inf->cputime + EXTRA_QUANTUM > inf->slice) { + /*we don't have a reasonable amount of time in our slice + left :( => start in next period!*/ + unblock_long_vcons(inf, now); + } +} +static inline void unblock_long_cons_b(struct sedf_edom_info* inf,s_time_t now) { + /*Conservative 2b*/ + /*Treat the unblocking time as a start of a new period */ + inf->deadl_abs = now + inf->period; + inf->cputime = 0; +} +static inline void unblock_long_cons_c(struct sedf_edom_info* inf,s_time_t now) { + if (likely(inf->latency)) { + /*scale the slice and period accordingly to the latency hint*/ + /*reduce period temporarily to the latency hint*/ + inf->period = inf->latency; + /*this results in max. 4s slice/period length*/ + ASSERT((inf->period < ULONG_MAX) + && (inf->slice_orig < ULONG_MAX)); + /*scale slice accordingly, so that utilisation stays the same*/ + inf->slice = (inf->period * inf->slice_orig) + / inf->period_orig; + inf->deadl_abs = now + inf->period; + inf->cputime = 0; + } + else { + /*we don't have a latency hint.. use some other technique*/ + unblock_long_cons_b(inf, now); + } +} +/*a new idea of dealing with short blocks: burst period scaling*/ +static inline void unblock_short_burst(struct sedf_edom_info* inf, s_time_t now) +{ + /*treat blocked time as consumed by the domain*/ + inf->cputime += now - inf->block_abs; + + if (inf->cputime + EXTRA_QUANTUM <= inf->slice) { + /*if we can still use some time in the current slice + then use it!*/ +#ifdef SEDF_STATS + /*we let the domain run in the current period*/ + inf->short_cont++; +#endif + } + else { + /*we don't have a reasonable amount of time in + our slice left => switch to burst mode*/ + if (likely(inf->unblock_abs)) { + /*set the period-length to the current blocking + interval, possible enhancements: average over last + blocking intervals, user-specified minimum,...*/ + inf->period = now - inf->unblock_abs; + /*check for overflow on multiplication*/ + ASSERT((inf->period < ULONG_MAX) + && (inf->slice_orig < ULONG_MAX)); + /*scale slice accordingly, so that utilisation + stays the same*/ + inf->slice = (inf->period * inf->slice_orig) + / inf->period_orig; + /*set new (shorter) deadline*/ + inf->deadl_abs += inf->period; + } + else { + /*in case we haven't unblocked before + start in next period!*/ + inf->cputime=0; + inf->deadl_abs += inf->period; + } + } + inf->unblock_abs = now; +} +static inline void unblock_long_burst(struct sedf_edom_info* inf, s_time_t now) { + if (unlikely(inf->latency && (inf->period > inf->latency))) { + /*scale the slice and period accordingly to the latency hint*/ + inf->period = inf->latency; + /*check for overflows on multiplication*/ + ASSERT((inf->period < ULONG_MAX) + && (inf->slice_orig < ULONG_MAX)); + /*scale slice accordingly, so that utilisation stays the same*/ + inf->slice = (inf->period * inf->slice_orig) + / inf->period_orig; + inf->deadl_abs = now + inf->period; + inf->cputime = 0; + } + else { + /*we don't have a latency hint.. or we are currently in + "burst mode": use some other technique + NB: this should be in fact the normal way of operation, + when we are in sync with the device!*/ + unblock_long_cons_b(inf, now); + } + inf->unblock_abs = now; +} + +#define DOMAIN_EDF 1 +#define DOMAIN_EXTRA_PEN 2 +#define DOMAIN_EXTRA_UTIL 3 +#define DOMAIN_IDLE 4 +static inline int get_run_type(struct exec_domain* d) { + struct sedf_edom_info* inf = EDOM_INFO(d); + if (is_idle_task(d->domain)) + return DOMAIN_IDLE; + if (inf->status & EXTRA_RUN_PEN) + return DOMAIN_EXTRA_PEN; + if (inf->status & EXTRA_RUN_UTIL) + return DOMAIN_EXTRA_UTIL; + return DOMAIN_EDF; +} +/*Compares two domains in the relation of whether the one is allowed to + interrupt the others execution. + It returns true (!=0) if a switch to the other domain is good. + Current Priority scheme is as follows: + EDF > L0 (penalty based) extra-time > + L1 (utilization) extra-time > idle-domain + In the same class priorities are assigned as following: + EDF: early deadline > late deadline + L0 extra-time: lower score > higher score*/ +static inline int should_switch(struct exec_domain* cur, + struct exec_domain* other, s_time_t now) { + struct sedf_edom_info *cur_inf, *other_inf; + cur_inf = EDOM_INFO(cur); + other_inf = EDOM_INFO(other); + + /*check whether we need to make an earlier sched-decision*/ + if ((PERIOD_BEGIN(other_inf) < + schedule_data[other->processor].s_timer.expires)) + return 1; + /*no timing-based switches need to be taken into account here*/ + switch (get_run_type(cur)) { + case DOMAIN_EDF: + /* do not interrupt a running EDF domain */ + return 0; + case DOMAIN_EXTRA_PEN: + /*check whether we also want + the L0 ex-q with lower score*/ + if ((other_inf->status & EXTRA_WANT_PEN_Q) + && (other_inf->score[EXTRA_PEN_Q] < + cur_inf->score[EXTRA_PEN_Q])) + return 1; + else return 0; + case DOMAIN_EXTRA_UTIL: + /*check whether we want the L0 extraq, don't + switch if both domains want L1 extraq */ + if (other_inf->status & EXTRA_WANT_PEN_Q) + return 1; + else return 0; + case DOMAIN_IDLE: + return 1; + } + return 1; +} +void sedf_wake(struct exec_domain *d) { + s_time_t now = NOW(); + struct sedf_edom_info* inf = EDOM_INFO(d); + + PRINT(3, "sedf_wake was called, domain-id %i.%i\n",d->domain->id, d->id); + + if (unlikely(is_idle_task(d->domain))) + return; + + if ( unlikely(__task_on_queue(d)) ) { + PRINT(3,"\tdomain %i.%i is already in some queue\n", + d->domain->id, d->id); + return; + } + ASSERT(!sedf_runnable(d)); + inf->status &= ~SEDF_ASLEEP; + ASSERT(!extraq_on(d, EXTRA_UTIL_Q)); + ASSERT(!extraq_on(d, EXTRA_PEN_Q)); + + if (unlikely(inf->deadl_abs == 0)) + /*initial setup of the deadline*/ + inf->deadl_abs = now + inf->slice; + + PRINT(3,"waking up domain %i.%i (deadl= %"PRIu64" period= %"PRIu64" "\ + "now= %"PRIu64")\n", d->domain->id, d->id, inf->deadl_abs, + inf->period, now); +#ifdef SEDF_STATS + inf->block_tot++; +#endif + if (unlikely(now < PERIOD_BEGIN(inf))) { + PRINT(4,"extratime unblock\n"); + /* unblocking in extra-time! */ + #if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (inf->status & EXTRA_WANT_PEN_Q) { + /*we have a domain that wants compensation + for block penalty and did just block in + its compensation time. Give it another + chance!*/ + extraq_add_sort_update(d, EXTRA_PEN_Q, 0); + } + #endif + extraq_check_add_unblocked(d, 0); + } + else { + if (now < inf->deadl_abs) { + PRINT(4,"short unblocking\n"); + /*short blocking*/ +#ifdef SEDF_STATS + inf->short_block_tot++; +#endif + #if (UNBLOCK <= UNBLOCK_ATROPOS) + unblock_short_vcons(inf, now); + #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) + unblock_short_cons(inf, now); + #elif (UNBLOCK == UNBLOCK_BURST) + unblock_short_burst(inf, now); + #elif (UNBLOCK == UNBLOCK_EXTRA_SUPPORT) + unblock_short_extra_support(inf, now); + #endif + + extraq_check_add_unblocked(d, 1); + } + else { + PRINT(4,"long unblocking\n"); + /*long unblocking*/ +#ifdef SEDF_STATS + inf->long_block_tot++; +#endif + #if (UNBLOCK == UNBLOCK_ISOCHRONOUS_EDF) + unblock_long_vcons(inf, now); + #elif (UNBLOCK == UNBLOCK_EDF \ + || UNBLOCK == UNBLOCK_EXTRA_SUPPORT) + unblock_long_cons_b(inf, now); + #elif (UNBLOCK == UNBLOCK_ATROPOS) + unblock_long_cons_c(inf, now); + #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) + unblock_long_cons_b(inf, now); + /*unblock_short_cons_c(inf, now);*/ + #elif (UNBLOCK == UNBLOCK_BURST) + unblock_long_burst(inf, now); + #endif + + extraq_check_add_unblocked(d, 1); + } + } + PRINT(3,"woke up domain %i.%i (deadl= %"PRIu64" period= %"PRIu64" "\ + "now= %"PRIu64")\n", d->domain->id, d->id, inf->deadl_abs, + inf->period, now); + if (PERIOD_BEGIN(inf) > now) { + __add_to_waitqueue_sort(d); + PRINT(3,"added to waitq\n"); + } + else { + __add_to_runqueue_sort(d); + PRINT(3,"added to runq\n"); + } + +#ifdef SEDF_STATS + /*do some statistics here...*/ + if (inf->block_abs != 0) { + inf->block_time_tot += now - inf->block_abs; + inf->penalty_time_tot += + PERIOD_BEGIN(inf) + inf->cputime - inf->block_abs; + } +#endif + /*sanity check: make sure each extra-aware domain IS on the util-q!*/ + ASSERT(IMPLY(inf->status & EXTRA_AWARE, extraq_on(d, EXTRA_UTIL_Q))); + ASSERT(__task_on_queue(d)); + /*check whether the awakened task needs to invoke the do_schedule + routine. Try to avoid unnecessary runs but: + Save approximation: Always switch to scheduler!*/ + if (should_switch(schedule_data[d->processor].curr, d, now)){ +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(d->processor); +#endif + cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); + } +} + +/*Print a lot of use-{full, less} information about a domains in the system*/ +static void sedf_dump_domain(struct exec_domain *d) { + printk("%i.%i has=%c ", d->domain->id, d->id, + test_bit(EDF_RUNNING, &d->flags) ? 'T':'F'); + printk("p=%"PRIu64" sl=%"PRIu64" ddl=%"PRIu64" w=%hu c=%"PRIu64" sc=%i xtr(%s)=%"PRIu64" ew=%hu", + EDOM_INFO(d)->period, EDOM_INFO(d)->slice, EDOM_INFO(d)->deadl_abs, + EDOM_INFO(d)->weight, d->cpu_time, EDOM_INFO(d)->score[EXTRA_UTIL_Q], + (EDOM_INFO(d)->status & EXTRA_AWARE) ? "yes" : "no", + EDOM_INFO(d)->extra_time_tot, EDOM_INFO(d)->extraweight); + if (d->cpu_time !=0) + printf(" (%"PRIu64"%%)", (EDOM_INFO(d)->extra_time_tot * 100) + / d->cpu_time); +#ifdef SEDF_STATS + if (EDOM_INFO(d)->block_time_tot!=0) + printf(" pen=%"PRIu64"%%", (EDOM_INFO(d)->penalty_time_tot * 100) / + EDOM_INFO(d)->block_time_tot); + if (EDOM_INFO(d)->block_tot!=0) + printf("\n blks=%u sh=%u (%u%%) (shc=%u (%u%%) shex=%i "\ + "shexsl=%i) l=%u (%u%%) avg: b=%"PRIu64" p=%"PRIu64"", + EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_block_tot, + (EDOM_INFO(d)->short_block_tot * 100) + / EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_cont, + (EDOM_INFO(d)->short_cont * 100) / EDOM_INFO(d)->block_tot, + EDOM_INFO(d)->pen_extra_blocks, + EDOM_INFO(d)->pen_extra_slices, + EDOM_INFO(d)->long_block_tot, + (EDOM_INFO(d)->long_block_tot * 100) / EDOM_INFO(d)->block_tot, + (EDOM_INFO(d)->block_time_tot) / EDOM_INFO(d)->block_tot, + (EDOM_INFO(d)->penalty_time_tot) / EDOM_INFO(d)->block_tot); +#endif + printf("\n"); +} + +/*dumps all domains on hte specified cpu*/ +static void sedf_dump_cpu_state(int i) +{ + struct list_head *list, *queue, *tmp; + struct sedf_edom_info *d_inf; + struct domain *d; + struct exec_domain *ed; + int loop = 0; + + printk("now=%"PRIu64"\n",NOW()); + queue = RUNQ(i); + printk("RUNQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) { + printk("%3d: ",loop++); + d_inf = list_entry(list, struct sedf_edom_info, list); + sedf_dump_domain(d_inf->exec_domain); + } + + queue = WAITQ(i); loop = 0; + printk("\nWAITQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) { + printk("%3d: ",loop++); + d_inf = list_entry(list, struct sedf_edom_info, list); + sedf_dump_domain(d_inf->exec_domain); + } + + queue = EXTRAQ(i,EXTRA_PEN_Q); loop = 0; + printk("\nEXTRAQ (penalty) rq %lx n: %lx, p: %lx\n", + (unsigned long)queue, (unsigned long) queue->next, + (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) { + d_inf = list_entry(list, struct sedf_edom_info, + extralist[EXTRA_PEN_Q]); + printk("%3d: ",loop++); + sedf_dump_domain(d_inf->exec_domain); + } + + queue = EXTRAQ(i,EXTRA_UTIL_Q); loop = 0; + printk("\nEXTRAQ (utilization) rq %lx n: %lx, p: %lx\n", + (unsigned long)queue, (unsigned long) queue->next, + (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) { + d_inf = list_entry(list, struct sedf_edom_info, + extralist[EXTRA_UTIL_Q]); + printk("%3d: ",loop++); + sedf_dump_domain(d_inf->exec_domain); + } + + loop = 0; + printk("\nnot on Q\n"); + for_each_domain(d) + for_each_exec_domain(d, ed) + { + if (!__task_on_queue(ed) && (ed->processor == i)) { + printk("%3d: ",loop++); + sedf_dump_domain(ed); + } + } +} +/*Adjusts periods and slices of the domains accordingly to their weights*/ +static inline int sedf_adjust_weights(struct sched_adjdom_cmd *cmd) { + struct exec_domain *p; + struct domain *d; + int sumw[NR_CPUS]; + s_time_t sumt[NR_CPUS]; + int cpu; + + for (cpu=0; cpu < NR_CPUS; cpu++) { + sumw[cpu] = 0; + sumt[cpu] = 0; + } + /*sum up all weights*/ + for_each_domain(d) + for_each_exec_domain(d, p) { + if (EDOM_INFO(p)->weight) + sumw[p->processor] += EDOM_INFO(p)->weight; + else { + /*don't modify domains who don't have a weight, but sum + up the time they need, projected to a WEIGHT_PERIOD, + so that this time is not given to the weight-driven + domains*/ + /*check for overflows*/ + ASSERT((WEIGHT_PERIOD < ULONG_MAX) + && (EDOM_INFO(p)->slice_orig < ULONG_MAX)); + sumt[p->processor] += (WEIGHT_PERIOD * + EDOM_INFO(p)->slice_orig) / EDOM_INFO(p)->period_orig; + } + } + /*adjust all slices (and periods) to the new weight*/ + for_each_domain(d) + for_each_exec_domain(d, p) { + if (EDOM_INFO(p)->weight) { + EDOM_INFO(p)->period_orig = + EDOM_INFO(p)->period = WEIGHT_PERIOD; + EDOM_INFO(p)->slice_orig = + EDOM_INFO(p)->slice = (EDOM_INFO(p)->weight * + (WEIGHT_PERIOD -WEIGHT_SAFETY - + sumt[p->processor])) / sumw[p->processor]; + } + } + return 0; +} + +/* set or fetch domain scheduling parameters */ +static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { + struct exec_domain *ed; + + PRINT(2,"sedf_adjdom was called, domain-id %i new period %"PRIu64" "\ + "new slice %"PRIu64"\nlatency %"PRIu64" extra:%s\n", + p->id, cmd->u.sedf.period, cmd->u.sedf.slice, + cmd->u.sedf.latency, (cmd->u.sedf.extratime)?"yes":"no"); + if ( cmd->direction == SCHED_INFO_PUT ) + { + /*check for sane parameters*/ + if (!cmd->u.sedf.period && !cmd->u.sedf.weight) + return -EINVAL; + if (cmd->u.sedf.weight) { + if ((cmd->u.sedf.extratime & EXTRA_AWARE) && + (! cmd->u.sedf.period)) { + /*weight driven domains with xtime ONLY!*/ + for_each_exec_domain(p, ed) { + EDOM_INFO(ed)->extraweight = cmd->u.sedf.weight; + EDOM_INFO(ed)->weight = 0; + EDOM_INFO(ed)->slice = 0; + EDOM_INFO(ed)->period = WEIGHT_PERIOD; + } + } else { + /*weight driven domains with real-time execution*/ + for_each_exec_domain(p, ed) + EDOM_INFO(ed)->weight = cmd->u.sedf.weight; + } + } + else { + /*time driven domains*/ + for_each_exec_domain(p, ed) { + /* sanity checking! */ + if(cmd->u.sedf.slice > cmd->u.sedf.period ) + return -EINVAL; + EDOM_INFO(ed)->weight = 0; + EDOM_INFO(ed)->extraweight = 0; + EDOM_INFO(ed)->period_orig = + EDOM_INFO(ed)->period = cmd->u.sedf.period; + EDOM_INFO(ed)->slice_orig = + EDOM_INFO(ed)->slice = cmd->u.sedf.slice; + } + } + if (sedf_adjust_weights(cmd)) + return -EINVAL; + + for_each_exec_domain(p, ed) { + EDOM_INFO(ed)->status = (EDOM_INFO(ed)->status & + ~EXTRA_AWARE) | (cmd->u.sedf.extratime & EXTRA_AWARE); + EDOM_INFO(ed)->latency = cmd->u.sedf.latency; + extraq_check(ed); + } + } + else if ( cmd->direction == SCHED_INFO_GET ) + { + cmd->u.sedf.period = EDOM_INFO(p->exec_domain[0])->period; + cmd->u.sedf.slice = EDOM_INFO(p->exec_domain[0])->slice; + cmd->u.sedf.extratime = EDOM_INFO(p->exec_domain[0])->status + & EXTRA_AWARE; + cmd->u.sedf.latency = EDOM_INFO(p->exec_domain[0])->latency; + cmd->u.sedf.weight = EDOM_INFO(p->exec_domain[0])->weight; + } + PRINT(2,"sedf_adjdom_finished\n"); + return 0; +} + +struct scheduler sched_sedf_def = { + .name = "Simple EDF Scheduler", + .opt_name = "sedf", + .sched_id = SCHED_SEDF, + + .init_idle_task = sedf_init_idle_task, + .alloc_task = sedf_alloc_task, + .add_task = sedf_add_task, + .free_task = sedf_free_task, + .init_scheduler = sedf_init_scheduler, + .do_schedule = sedf_do_schedule, + .dump_cpu_state = sedf_dump_cpu_state, + .sleep = sedf_sleep, + .wake = sedf_wake, + .adjdom = sedf_adjdom, +}; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 4123231dd1..491c2f22ac 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -34,12 +34,24 @@ #include #include #include +#include #include /* opt_sched: scheduler - default to Borrowed Virtual Time */ static char opt_sched[10] = "bvt"; string_param("sched", opt_sched); +/*#define WAKE_HISTO*/ +/*#define BLOCKTIME_HISTO*/ +/*#define ADV_SCHED_HISTO*/ +//#include + +#if defined(WAKE_HISTO) +#define BUCKETS 31 +#elif defined(BLOCKTIME_HISTO) +#define BUCKETS 200 +#endif + #define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */ /* Various timer handlers. */ @@ -51,8 +63,10 @@ static void dom_timer_fn(unsigned long data); struct schedule_data schedule_data[NR_CPUS]; extern struct scheduler sched_bvt_def; +extern struct scheduler sched_sedf_def; static struct scheduler *schedulers[] = { &sched_bvt_def, + &sched_sedf_def, NULL }; @@ -93,24 +107,27 @@ struct exec_domain *alloc_exec_domain_struct(struct domain *d, d->exec_domain[vcpu] = ed; ed->domain = d; - ed->eid = vcpu; + ed->id = vcpu; if ( SCHED_OP(alloc_task, ed) < 0 ) goto out; - if (vcpu != 0) { - ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid]; + if ( vcpu != 0 ) + { + ed->vcpu_info = &d->shared_info->vcpu_data[ed->id]; - for_each_exec_domain(d, edc) { - if (edc->ed_next_list == NULL || edc->ed_next_list->eid > vcpu) + for_each_exec_domain( d, edc ) + { + if ( (edc->next_in_list == NULL) || + (edc->next_in_list->id > vcpu) ) break; } - ed->ed_next_list = edc->ed_next_list; - edc->ed_next_list = ed; + ed->next_in_list = edc->next_in_list; + edc->next_in_list = ed; - if (test_bit(EDF_CPUPINNED, &edc->ed_flags)) { + if (test_bit(EDF_CPUPINNED, &edc->flags)) { ed->processor = (edc->processor + 1) % smp_num_cpus; - set_bit(EDF_CPUPINNED, &ed->ed_flags); + set_bit(EDF_CPUPINNED, &ed->flags); } else { ed->processor = (edc->processor + 1) % smp_num_cpus; /* XXX */ } @@ -152,7 +169,7 @@ void sched_add_domain(struct exec_domain *ed) struct domain *d = ed->domain; /* Must be unpaused by control software to start execution. */ - set_bit(EDF_CTRLPAUSE, &ed->ed_flags); + set_bit(EDF_CTRLPAUSE, &ed->flags); if ( d->id != IDLE_DOMAIN_ID ) { @@ -168,14 +185,14 @@ void sched_add_domain(struct exec_domain *ed) } SCHED_OP(add_task, ed); - TRACE_2D(TRC_SCHED_DOM_ADD, d->id, ed->eid); + TRACE_2D(TRC_SCHED_DOM_ADD, d->id, ed->id); } void sched_rem_domain(struct exec_domain *ed) { rem_ac_timer(&ed->timer); SCHED_OP(rem_task, ed); - TRACE_2D(TRC_SCHED_DOM_REM, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_DOM_REM, ed->domain->id, ed->id); } void init_idle_task(void) @@ -193,10 +210,10 @@ void domain_sleep(struct exec_domain *ed) SCHED_OP(sleep, ed); spin_unlock_irqrestore(&schedule_data[ed->processor].schedule_lock, flags); - TRACE_2D(TRC_SCHED_SLEEP, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_SLEEP, ed->domain->id, ed->id); /* Synchronous. */ - while ( test_bit(EDF_RUNNING, &ed->ed_flags) && !domain_runnable(ed) ) + while ( test_bit(EDF_RUNNING, &ed->flags) && !domain_runnable(ed) ) cpu_relax(); } @@ -212,10 +229,10 @@ void domain_wake(struct exec_domain *ed) ed->wokenup = NOW(); #endif } - clear_bit(EDF_MIGRATED, &ed->ed_flags); + clear_bit(EDF_MIGRATED, &ed->flags); spin_unlock_irqrestore(&schedule_data[ed->processor].schedule_lock, flags); - TRACE_2D(TRC_SCHED_WAKE, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_WAKE, ed->domain->id, ed->id); } /* Block the currently-executing domain until a pertinent event occurs. */ @@ -223,17 +240,21 @@ long do_block(void) { struct exec_domain *ed = current; +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(current->processor); +#endif + ed->vcpu_info->evtchn_upcall_mask = 0; - set_bit(EDF_BLOCKED, &ed->ed_flags); + set_bit(EDF_BLOCKED, &ed->flags); /* Check for events /after/ blocking: avoids wakeup waiting race. */ if ( event_pending(ed) ) { - clear_bit(EDF_BLOCKED, &ed->ed_flags); + clear_bit(EDF_BLOCKED, &ed->flags); } else { - TRACE_2D(TRC_SCHED_BLOCK, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_BLOCK, ed->domain->id, ed->id); __enter_scheduler(); } @@ -243,7 +264,11 @@ long do_block(void) /* Voluntarily yield the processor for this allocation. */ static long do_yield(void) { - TRACE_2D(TRC_SCHED_YIELD, current->domain->id, current->eid); +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(current->processor); +#endif + + TRACE_2D(TRC_SCHED_YIELD, current->domain->id, current->id); __enter_scheduler(); return 0; } @@ -272,7 +297,7 @@ long do_sched_op(unsigned long op) case SCHEDOP_shutdown: { - TRACE_3D(TRC_SCHED_SHUTDOWN, current->domain->id, current->eid, + TRACE_3D(TRC_SCHED_SHUTDOWN, current->domain->id, current->id, (op >> SCHEDOP_reasonshift)); domain_shutdown((u8)(op >> SCHEDOP_reasonshift)); break; @@ -319,10 +344,22 @@ long sched_ctl(struct sched_ctl_cmd *cmd) long sched_adjdom(struct sched_adjdom_cmd *cmd) { struct domain *d; + struct exec_domain *ed; + int cpu; +#if NR_CPUS <=32 + unsigned long have_lock; + #else + unsigned long long have_lock; +#endif + int succ; + #define __set_cpu_bit(cpu, data) data |= ((typeof(data))1)<sched_id != ops.sched_id ) return -EINVAL; - + if ( cmd->direction != SCHED_INFO_PUT && cmd->direction != SCHED_INFO_GET ) return -EINVAL; @@ -330,9 +367,38 @@ long sched_adjdom(struct sched_adjdom_cmd *cmd) if ( d == NULL ) return -ESRCH; - spin_lock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); + /* acquire locks on all CPUs on which exec_domains of this domain run */ + do { + succ = 0; + __clear_cpu_bits(have_lock); + for_each_exec_domain(d, ed) { + cpu = ed->processor; + if (!__get_cpu_bit(cpu, have_lock)) { + /* if we don't have a lock on this CPU: acquire it*/ + if (spin_trylock(&schedule_data[cpu].schedule_lock)) { + /*we have this lock!*/ + __set_cpu_bit(cpu, have_lock); + succ = 1; + } else { + /*we didn,t get this lock -> free all other locks too!*/ + for (cpu = 0; cpu < NR_CPUS; cpu++) + if (__get_cpu_bit(cpu, have_lock)) + spin_unlock(&schedule_data[cpu].schedule_lock); + /* and start from the beginning! */ + succ = 0; + /* leave the "for_each_domain_loop" */ + break; + } + } + } + } while (!succ); + //spin_lock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); SCHED_OP(adjdom, d, cmd); - spin_unlock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); + //spin_unlock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); + for (cpu = 0; cpu < NR_CPUS; cpu++) + if (__get_cpu_bit(cpu, have_lock)) + spin_unlock(&schedule_data[cpu].schedule_lock); + __clear_cpu_bits(have_lock); TRACE_1D(TRC_SCHED_ADJDOM, d->id); put_domain(d); @@ -355,8 +421,14 @@ static void __enter_scheduler(void) perfc_incrc(sched_run); spin_lock_irq(&schedule_data[cpu].schedule_lock); - + +#ifdef ADV_SCHED_HISTO + adv_sched_hist_from_stop(cpu); +#endif now = NOW(); +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(cpu); +#endif rem_ac_timer(&schedule_data[cpu].s_timer); @@ -379,13 +451,16 @@ static void __enter_scheduler(void) add_ac_timer(&schedule_data[cpu].s_timer); /* Must be protected by the schedule_lock! */ - set_bit(EDF_RUNNING, &next->ed_flags); + set_bit(EDF_RUNNING, &next->flags); spin_unlock_irq(&schedule_data[cpu].schedule_lock); - if ( unlikely(prev == next) ) + if ( unlikely(prev == next) ) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_to_stop(cpu); +#endif return continue_running(prev); - + } perfc_incrc(sched_ctx); #if defined(WAKE_HISTO) @@ -417,8 +492,12 @@ static void __enter_scheduler(void) } TRACE_4D(TRC_SCHED_SWITCH, - prev->domain->id, prev->eid, - next->domain->id, next->eid); + prev->domain->id, prev->id, + next->domain->id, next->id); + +#ifdef ADV_SCHED_HISTO + adv_sched_hist_to_stop(cpu); +#endif context_switch(prev, next); } @@ -441,6 +520,10 @@ int idle_cpu(int cpu) /* The scheduler timer: force a run through the scheduler */ static void s_timer_fn(unsigned long unused) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(current->processor); +#endif + raise_softirq(SCHEDULE_SOFTIRQ); perfc_incrc(sched_irq); } @@ -584,9 +667,66 @@ void reset_sched_histo(unsigned char key) schedule_data[j].hist[i] = 0; } #else +#if defined(ADV_SCHED_HISTO) +void print_sched_histo(unsigned char key) +{ + int i, j, k,t; + printf("Hello!\n"); + for ( k = 0; k < smp_num_cpus; k++ ) + { + j = 0; + t = 0; + printf ("CPU[%02d]: scheduler latency histogram FROM (ms:[count])\n", k); + for ( i = 0; i < BUCKETS; i++ ) + { + //if ( schedule_data[k].hist[i] != 0 ) + { + t += schedule_data[k].from_hist[i]; + if ( i < BUCKETS-1 ) + printk("%3d:[%7u] ", i, schedule_data[k].from_hist[i]); + else + printk(" >:[%7u] ", schedule_data[k].from_hist[i]); + //if ( !(++j % 5) ) + printk("\n"); + } + } + printk("\nTotal: %i\n",t); + } + for ( k = 0; k < smp_num_cpus; k++ ) + { + j = 0; t = 0; + printf ("CPU[%02d]: scheduler latency histogram TO (ms:[count])\n", k); + for ( i = 0; i < BUCKETS; i++ ) + { + //if ( schedule_data[k].hist[i] != 0 ) + { + t += schedule_data[k].from_hist[i]; + if ( i < BUCKETS-1 ) + printk("%3d:[%7u] ", i, schedule_data[k].to_hist[i]); + else + printk(" >:[%7u] ", schedule_data[k].to_hist[i]); + //if ( !(++j % 5) ) + printk("\n"); + } + } + printk("\nTotal: %i\n",t); + } + +} +void reset_sched_histo(unsigned char key) +{ + int i, j; + for ( j = 0; j < smp_num_cpus; j++ ) { + for ( i=0; i < BUCKETS; i++ ) + schedule_data[j].to_hist[i] = schedule_data[j].from_hist[i] = 0; + schedule_data[j].save_tsc = 0; + } +} +#else void print_sched_histo(unsigned char key) { } void reset_sched_histo(unsigned char key) { } #endif +#endif /* * Local variables: diff --git a/xen/common/xmalloc.c b/xen/common/xmalloc.c index bb90cc392d..de4831e18c 100644 --- a/xen/common/xmalloc.c +++ b/xen/common/xmalloc.c @@ -42,7 +42,7 @@ struct xmalloc_hdr /* Total including this hdr. */ size_t size; struct list_head freelist; -} __attribute__((__aligned__(SMP_CACHE_BYTES))); +} __cacheline_aligned; static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block) { diff --git a/xen/drivers/acpi/tables.c b/xen/drivers/acpi/tables.c index 64a05061a6..1c718efc88 100644 --- a/xen/drivers/acpi/tables.c +++ b/xen/drivers/acpi/tables.c @@ -58,6 +58,7 @@ static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { [ACPI_SSDT] = "SSDT", [ACPI_SPMI] = "SPMI", [ACPI_HPET] = "HPET", + [ACPI_MCFG] = "MCFG", }; static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; @@ -100,7 +101,7 @@ acpi_table_print ( else name = header->signature; - printk(KERN_INFO PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name, header->revision, header->oem_id, header->oem_table_id, header->oem_revision, header->asl_compiler_id, header->asl_compiler_revision, @@ -130,7 +131,7 @@ acpi_table_print_madt_entry ( { struct acpi_table_ioapic *p = (struct acpi_table_ioapic*) header; - printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] global_irq_base[0x%x])\n", + printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", p->id, p->address, p->global_irq_base); } break; @@ -184,8 +185,8 @@ acpi_table_print_madt_entry ( { struct acpi_table_iosapic *p = (struct acpi_table_iosapic*) header; - printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] global_irq_base[0x%x] address[%p])\n", - p->id, p->global_irq_base, (void *) (unsigned long) p->address); + printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", + p->id, (void *) (unsigned long) p->address, p->global_irq_base); } break; @@ -285,7 +286,7 @@ acpi_get_table_header_early ( *header = (void *) __acpi_map_table(fadt->V1_dsdt, sizeof(struct acpi_table_header)); } else - *header = 0; + *header = NULL; if (!*header) { printk(KERN_WARNING PREFIX "Unable to map DSDT\n"); @@ -302,13 +303,14 @@ acpi_table_parse_madt_family ( enum acpi_table_id id, unsigned long madt_size, int entry_id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { void *madt = NULL; - acpi_table_entry_header *entry = NULL; - unsigned long count = 0; - unsigned long madt_end = 0; - unsigned int i = 0; + acpi_table_entry_header *entry; + unsigned int count = 0; + unsigned long madt_end; + unsigned int i; if (!handler) return -EINVAL; @@ -341,14 +343,20 @@ acpi_table_parse_madt_family ( entry = (acpi_table_entry_header *) ((unsigned long) madt + madt_size); - while (((unsigned long) entry) < madt_end) { - if (entry->type == entry_id) { - count++; - handler(entry); - } + while (((unsigned long) entry) + sizeof(acpi_table_entry_header) < madt_end) { + if (entry->type == entry_id && + (!max_entries || count++ < max_entries)) + if (handler(entry, madt_end)) + return -EINVAL; + entry = (acpi_table_entry_header *) ((unsigned long) entry + entry->length); } + if (max_entries && count > max_entries) { + printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of " + "%i found\n", acpi_table_signatures[id], entry_id, + count - max_entries, count); + } return count; } @@ -357,10 +365,11 @@ acpi_table_parse_madt_family ( int __init acpi_table_parse_madt ( enum acpi_madt_entry_id id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { return acpi_table_parse_madt_family(ACPI_APIC, sizeof(struct acpi_table_madt), - id, handler); + id, handler, max_entries); } @@ -378,8 +387,13 @@ acpi_table_parse ( for (i = 0; i < sdt_count; i++) { if (sdt_entry[i].id != id) continue; - handler(sdt_entry[i].pa, sdt_entry[i].size); count++; + if (count == 1) + handler(sdt_entry[i].pa, sdt_entry[i].size); + + else + printk(KERN_WARNING PREFIX "%d duplicate %s table ignored.\n", + count, acpi_table_signatures[id]); } return count; @@ -543,6 +557,14 @@ acpi_table_get_sdt ( return 0; } +/* + * acpi_table_init() + * + * find RSDP, find and checksum SDT/XSDT. + * checksum all tables, print SDT/XSDT + * + * result: sdt_entry[] is initialized + */ int __init acpi_table_init (void) @@ -565,7 +587,7 @@ acpi_table_init (void) return -ENODEV; } - printk(KERN_INFO PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", rsdp->revision, rsdp->oem_id, (void *) rsdp_phys); if (rsdp->revision < 2) @@ -585,4 +607,3 @@ acpi_table_init (void) return 0; } - diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index f20d664c91..d9eb0c474a 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index ebfd44cea8..7d9852ebab 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -26,71 +26,6 @@ static char opt_com1[30] = OPT_COM1_STR, opt_com2[30] = OPT_COM2_STR; string_param("com1", opt_com1); string_param("com2", opt_com2); -/* Register offsets */ -#define RBR 0x00 /* receive buffer */ -#define THR 0x00 /* transmit holding */ -#define IER 0x01 /* interrupt enable */ -#define IIR 0x02 /* interrupt identity */ -#define FCR 0x02 /* FIFO control */ -#define LCR 0x03 /* line control */ -#define MCR 0x04 /* Modem control */ -#define LSR 0x05 /* line status */ -#define MSR 0x06 /* Modem status */ -#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */ -#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */ - -/* Interrupt Enable Register */ -#define IER_ERDAI 0x01 /* rx data recv'd */ -#define IER_ETHREI 0x02 /* tx reg. empty */ -#define IER_ELSI 0x04 /* rx line status */ -#define IER_EMSI 0x08 /* MODEM status */ - -/* FIFO control register */ -#define FCR_ENABLE 0x01 /* enable FIFO */ -#define FCR_CLRX 0x02 /* clear Rx FIFO */ -#define FCR_CLTX 0x04 /* clear Tx FIFO */ -#define FCR_DMA 0x10 /* enter DMA mode */ -#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ -#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ -#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ -#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ - -/* Line control register */ -#define LCR_DLAB 0x80 /* Divisor Latch Access */ - -/* Modem Control Register */ -#define MCR_DTR 0x01 /* Data Terminal Ready */ -#define MCR_RTS 0x02 /* Request to Send */ -#define MCR_OUT2 0x08 /* OUT2: interrupt mask */ - -/* Line Status Register */ -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit hold reg empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -/* These parity settings can be ORed directly into the LCR. */ -#define PARITY_NONE (0<<3) -#define PARITY_ODD (1<<3) -#define PARITY_EVEN (3<<3) -#define PARITY_MARK (5<<3) -#define PARITY_SPACE (7<<3) - -#define RXBUFSZ 32 -#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1)) -struct uart { - int baud, data_bits, parity, stop_bits, io_base, irq; - serial_rx_fn rx_lo, rx_hi, rx; - spinlock_t lock; - unsigned char rxbuf[RXBUFSZ]; - unsigned int rxbufp, rxbufc; - struct irqaction irqaction; -}; - static struct uart com[2] = { { 0, 0, 0, 0, 0x3f8, 4, NULL, NULL, NULL, diff --git a/xen/include/acpi/acconfig.h b/xen/include/acpi/acconfig.h index 8879c2c830..6701c11b40 100644 --- a/xen/include/acpi/acconfig.h +++ b/xen/include/acpi/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,11 +64,21 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20040116 +#define ACPI_CA_VERSION 0x20050211 + +/* + * OS name, used for the _OS object. The _OS object is essentially obsolete, + * but there is a large base of ASL/AML code in existing machines that check + * for the string below. The use of this string usually guarantees that + * the ASL will execute down the most tested code path. Also, there is some + * code that will not execute the _OSI method unless _OS matches the string + * below. Therefore, change this string at your own risk. + */ +#define ACPI_OS_NAME "Microsoft Windows NT" /* Maximum objects in the various object caches */ -#define ACPI_MAX_STATE_CACHE_DEPTH 64 /* State objects for stacks */ +#define ACPI_MAX_STATE_CACHE_DEPTH 64 /* State objects */ #define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ #define ACPI_MAX_EXTPARSE_CACHE_DEPTH 64 /* Parse tree objects */ #define ACPI_MAX_OBJECT_CACHE_DEPTH 64 /* Interpreter operand objects */ @@ -89,7 +99,7 @@ /* Version of ACPI supported */ -#define ACPI_CA_SUPPORT_LEVEL 2 +#define ACPI_CA_SUPPORT_LEVEL 3 /* String size constants */ @@ -152,10 +162,11 @@ /* Constants used in searching for the RSDP in low memory */ -#define ACPI_LO_RSDP_WINDOW_BASE 0 /* Physical Address */ -#define ACPI_HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ -#define ACPI_LO_RSDP_WINDOW_SIZE 0x400 -#define ACPI_HI_RSDP_WINDOW_SIZE 0x20000 +#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ +#define ACPI_EBDA_PTR_LENGTH 2 +#define ACPI_EBDA_WINDOW_SIZE 1024 +#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */ +#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000 #define ACPI_RSDP_SCAN_STEP 16 /* Operation regions */ @@ -185,6 +196,10 @@ #define ACPI_SMBUS_BUFFER_SIZE 34 +/* Number of strings associated with the _OSI reserved method */ + +#define ACPI_NUM_OSI_STRINGS 9 + /****************************************************************************** * diff --git a/xen/include/acpi/acexcep.h b/xen/include/acpi/acexcep.h index 9441f5c1a7..53f8b50fac 100644 --- a/xen/include/acpi/acexcep.h +++ b/xen/include/acpi/acexcep.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -95,8 +95,9 @@ #define AE_LOGICAL_ADDRESS (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL) #define AE_ABORT_METHOD (acpi_status) (0x001C | AE_CODE_ENVIRONMENTAL) #define AE_SAME_HANDLER (acpi_status) (0x001D | AE_CODE_ENVIRONMENTAL) +#define AE_WAKE_ONLY_GPE (acpi_status) (0x001E | AE_CODE_ENVIRONMENTAL) -#define AE_CODE_ENV_MAX 0x001D +#define AE_CODE_ENV_MAX 0x001E /* * Programmer exceptions @@ -165,7 +166,7 @@ #define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x0020 | AE_CODE_AML) #define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x0021 | AE_CODE_AML) -#define AE_CODE_AML_MAX 0x0020 +#define AE_CODE_AML_MAX 0x0021 /* * Internal exceptions used for control @@ -222,7 +223,8 @@ char const *acpi_gbl_exception_names_env[] = "AE_NO_GLOBAL_LOCK", "AE_LOGICAL_ADDRESS", "AE_ABORT_METHOD", - "AE_SAME_HANDLER" + "AE_SAME_HANDLER", + "AE_WAKE_ONLY_GPE" }; char const *acpi_gbl_exception_names_pgm[] = diff --git a/xen/include/acpi/acglobal.h b/xen/include/acpi/acglobal.h index 9cf587e950..c7f387a972 100644 --- a/xen/include/acpi/acglobal.h +++ b/xen/include/acpi/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,17 +46,26 @@ /* - * Ensure that the globals are actually defined only once. + * Ensure that the globals are actually defined and initialized only once. * - * The use of these defines allows a single list of globals (here) in order + * The use of these macros allows a single list of globals (here) in order * to simplify maintenance of the code. */ #ifdef DEFINE_ACPI_GLOBALS #define ACPI_EXTERN +#define ACPI_INIT_GLOBAL(a,b) a=b #else #define ACPI_EXTERN extern +#define ACPI_INIT_GLOBAL(a,b) a #endif +/* + * Keep local copies of these FADT-based registers. NOTE: These globals + * are first in this file for alignment reasons on 64-bit systems. + */ +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; + /***************************************************************************** * @@ -74,6 +83,46 @@ extern u32 acpi_dbg_layer; extern u32 acpi_gbl_nesting_level; +/***************************************************************************** + * + * Runtime configuration (static defaults that can be overriden at runtime) + * + ****************************************************************************/ + +/* + * Enable "slack" in the AML interpreter? Default is FALSE, and the + * interpreter strictly follows the ACPI specification. Setting to TRUE + * allows the interpreter to forgive certain bad AML constructs. Currently: + * 1) Allow "implicit return" of last value in a control method + * 2) Allow access beyond end of operation region + * 3) Allow access to uninitialized locals/args (auto-init to integer 0) + * 4) Allow ANY object type to be a source operand for the Store() operator + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_enable_interpreter_slack, FALSE); + +/* + * Automatically serialize ALL control methods? Default is FALSE, meaning + * to use the Serialized/not_serialized method flags on a per method basis. + * Only change this if the ASL code is poorly written and cannot handle + * reentrancy even though methods are marked "not_serialized". + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_all_methods_serialized, FALSE); + +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPI CA is fully compatible with other ACPI implementations. + * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_create_osi_method, TRUE); + +/* + * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and + * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only + * be enabled just before going to sleep. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_leave_wake_gpes_disabled, TRUE); + + /***************************************************************************** * * ACPI Table globals @@ -87,7 +136,6 @@ extern u32 acpi_gbl_nesting_level; * * These tables are single-table only; meaning that there can be at most one * of each in the system. Each global points to the actual table. - * */ ACPI_EXTERN u32 acpi_gbl_table_flags; ACPI_EXTERN u32 acpi_gbl_rsdt_table_count; @@ -97,6 +145,11 @@ ACPI_EXTERN FADT_DESCRIPTOR *acpi_gbl_FADT; ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT; ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS; ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; +/* + * Since there may be multiple SSDTs and PSDTS, a single pointer is not + * sufficient; Therefore, there isn't one! + */ + /* * Handle both ACPI 1.0 and ACPI 2.0 Integer widths @@ -107,17 +160,6 @@ ACPI_EXTERN u8 acpi_gbl_integer_bit_width; ACPI_EXTERN u8 acpi_gbl_integer_byte_width; ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; -/* Keep local copies of these FADT-based registers */ - -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; - -/* - * Since there may be multiple SSDTs and PSDTS, a single pointer is not - * sufficient; Therefore, there isn't one! - */ - - /* * ACPI Table info arrays */ @@ -142,6 +184,7 @@ ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[NUM_MUTEX]; ACPI_EXTERN struct acpi_memory_list acpi_gbl_memory_lists[ACPI_NUM_MEM_LISTS]; ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify; ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify; +ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler; ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler; ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk; ACPI_EXTERN acpi_handle acpi_gbl_global_lock_semaphore; @@ -161,13 +204,16 @@ ACPI_EXTERN u8 acpi_gbl_step_to_next_call; ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ACPI_EXTERN u8 acpi_gbl_global_lock_present; ACPI_EXTERN u8 acpi_gbl_events_initialized; +ACPI_EXTERN u8 acpi_gbl_system_awake_and_running; extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; extern const u8 acpi_gbl_decode_to8bit[8]; -extern const char *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_highest_dstate_names[4]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; +extern const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS]; /***************************************************************************** @@ -178,7 +224,7 @@ extern const char *acpi_gbl_region_types[ACPI_NUM_P #define NUM_NS_TYPES ACPI_TYPE_INVALID+1 -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) #define NUM_PREDEFINED_NAMES 10 #else #define NUM_PREDEFINED_NAMES 9 @@ -186,6 +232,7 @@ extern const char *acpi_gbl_region_types[ACPI_NUM_P ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct; ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node; +ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device; extern const u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; extern const struct acpi_predefined_names acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; diff --git a/xen/include/acpi/achware.h b/xen/include/acpi/achware.h index cfcff91f6d..28ad1398c1 100644 --- a/xen/include/acpi/achware.h +++ b/xen/include/acpi/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -114,15 +114,7 @@ acpi_hw_clear_acpi_status ( /* GPE support */ acpi_status -acpi_hw_enable_gpe ( - struct acpi_gpe_event_info *gpe_event_info); - -void -acpi_hw_enable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info); - -acpi_status -acpi_hw_disable_gpe ( +acpi_hw_write_gpe_enable_reg ( struct acpi_gpe_event_info *gpe_event_info); acpi_status @@ -130,10 +122,6 @@ acpi_hw_disable_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); -void -acpi_hw_disable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info); - acpi_status acpi_hw_clear_gpe ( struct acpi_gpe_event_info *gpe_event_info); @@ -143,22 +131,39 @@ acpi_hw_clear_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_hw_get_gpe_status ( struct acpi_gpe_event_info *gpe_event_info, acpi_event_status *event_status); +#endif acpi_status -acpi_hw_disable_non_wakeup_gpes ( - void); +acpi_hw_disable_all_gpes ( + u32 flags); acpi_status -acpi_hw_enable_non_wakeup_gpes ( - void); +acpi_hw_enable_all_runtime_gpes ( + u32 flags); + +acpi_status +acpi_hw_enable_all_wakeup_gpes ( + u32 flags); + +acpi_status +acpi_hw_enable_runtime_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); + +acpi_status +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); /* ACPI Timer prototypes */ +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_timer_resolution ( u32 *resolution); @@ -172,6 +177,6 @@ acpi_get_timer_duration ( u32 start_ticks, u32 end_ticks, u32 *time_elapsed); - +#endif /* ACPI_FUTURE_USAGE */ #endif /* __ACHWARE_H__ */ diff --git a/xen/include/acpi/aclocal.h b/xen/include/acpi/aclocal.h index 129422eacc..f2b96f6be4 100644 --- a/xen/include/acpi/aclocal.h +++ b/xen/include/acpi/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ typedef u32 acpi_mutex_handle; /* Total number of aml opcodes defined */ -#define AML_NUM_OPCODES 0x7E +#define AML_NUM_OPCODES 0x7F /***************************************************************************** @@ -189,8 +189,6 @@ struct acpi_namespace_node u8 type; /* Type associated with this name */ u16 owner_id; union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ - - union acpi_operand_object *object; /* Pointer to attached ACPI object (optional) */ struct acpi_namespace_node *child; /* First child */ struct acpi_namespace_node *peer; /* Next peer*/ @@ -211,10 +209,8 @@ struct acpi_namespace_node #define ANOBJ_METHOD_LOCAL 0x10 #define ANOBJ_METHOD_NO_RETVAL 0x20 #define ANOBJ_METHOD_SOME_NO_RETVAL 0x40 - #define ANOBJ_IS_BIT_OFFSET 0x80 - /* * ACPI Table Descriptor. One per ACPI table */ @@ -309,16 +305,31 @@ struct acpi_create_field_info * ****************************************************************************/ -/* Information about a GPE, one per each GPE in an array */ +/* Dispatch info for each GPE -- either a method or handler, cannot be both */ -struct acpi_gpe_event_info +struct acpi_handler_info +{ + acpi_event_handler address; /* Address of handler, if any */ + void *context; /* Context to be passed to handler */ + struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ +}; + +union acpi_gpe_dispatch_info { struct acpi_namespace_node *method_node; /* Method node for this GPE level */ - acpi_gpe_handler handler; /* Address of handler, if any */ - void *context; /* Context to be passed to handler */ + struct acpi_handler_info *handler; +}; + +/* + * Information about a GPE, one per each GPE in an array. + * NOTE: Important to keep this struct as small as possible. + */ +struct acpi_gpe_event_info +{ + union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */ struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ - u8 flags; /* Level or Edge */ - u8 bit_mask; /* This GPE within the register */ + u8 flags; /* Misc info about this GPE */ + u8 register_bit; /* This GPE bit within the register */ }; /* Information about a GPE register pair, one per each status/enable pair in an array */ @@ -327,9 +338,8 @@ struct acpi_gpe_register_info { struct acpi_generic_address status_address; /* Address of status reg */ struct acpi_generic_address enable_address; /* Address of enable reg */ - u8 status; /* Current value of status reg */ - u8 enable; /* Current value of enable reg */ - u8 wake_enable; /* Mask of bits to keep enabled when sleeping */ + u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ + u8 enable_for_run; /* GPEs to keep enabled when running */ u8 base_gpe_number; /* Base GPE number for this register */ }; @@ -339,6 +349,7 @@ struct acpi_gpe_register_info */ struct acpi_gpe_block_info { + struct acpi_namespace_node *node; struct acpi_gpe_block_info *previous; struct acpi_gpe_block_info *next; struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ @@ -360,6 +371,13 @@ struct acpi_gpe_xrupt_info }; +struct acpi_gpe_walk_info +{ + struct acpi_namespace_node *gpe_device; + struct acpi_gpe_block_info *gpe_block; +}; + + typedef acpi_status (*ACPI_GPE_CALLBACK) ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); @@ -495,7 +513,7 @@ struct acpi_thread_state struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ u32 thread_id; /* Running thread ID */ - u16 current_sync_level; /* Mutex Sync (nested acquire) level */ + u8 current_sync_level; /* Mutex Sync (nested acquire) level */ }; @@ -544,7 +562,7 @@ union acpi_generic_state struct acpi_scope_state scope; struct acpi_pscope_state parse_scope; struct acpi_pkg_state pkg; - struct acpi_thread_state acpi_thread; + struct acpi_thread_state thread; struct acpi_result_values results; struct acpi_notify_info notify; }; @@ -844,7 +862,6 @@ struct acpi_bit_register_info /* * Large resource descriptor types */ - #define ACPI_RDESC_TYPE_MEMORY_24 0x81 #define ACPI_RDESC_TYPE_GENERAL_REGISTER 0x82 #define ACPI_RDESC_TYPE_LARGE_VENDOR 0x84 @@ -854,6 +871,7 @@ struct acpi_bit_register_info #define ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE 0x88 #define ACPI_RDESC_TYPE_EXTENDED_XRUPT 0x89 #define ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE 0x8A +#define ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE 0x8B /***************************************************************************** diff --git a/xen/include/acpi/acmacros.h b/xen/include/acpi/acmacros.h index e1abf964bf..fcaced16b1 100644 --- a/xen/include/acpi/acmacros.h +++ b/xen/include/acpi/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,6 +53,10 @@ #define ACPI_LOBYTE(l) ((u8)(u16)(l)) #define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) +#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) +#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) +#define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) + #if ACPI_MACHINE_WIDTH == 16 @@ -97,7 +101,7 @@ * printf() format helpers */ -/* Split 64-bit integer into two 32-bit values. use with %8,8_x%8.8X */ +/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */ #define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i) @@ -361,24 +365,6 @@ #define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) -/* Macros for GAS addressing */ - -#if ACPI_MACHINE_WIDTH != 16 - -#define ACPI_PCI_DEVICE(a) (u16) ((ACPI_HIDWORD ((a))) & 0x0000FFFF) -#define ACPI_PCI_FUNCTION(a) (u16) ((ACPI_LODWORD ((a))) >> 16) -#define ACPI_PCI_REGISTER(a) (u16) ((ACPI_LODWORD ((a))) & 0x0000FFFF) - -#else - -/* No support for GAS and PCI IDs in 16-bit mode */ - -#define ACPI_PCI_FUNCTION(a) (u16) ((a) & 0xFFFF0000) -#define ACPI_PCI_DEVICE(a) (u16) ((a) & 0x0000FFFF) -#define ACPI_PCI_REGISTER(a) (u16) ((a) & 0x0000FFFF) - -#endif - /* Bitfields within ACPI registers */ @@ -502,19 +488,19 @@ * The first parameter should be the procedure name as a quoted string. This is declared * as a local string ("_proc_name) so that it can be also used by the function exit macros below. */ -#define ACPI_FUNCTION_NAME(a) struct acpi_debug_print_info _dbg; \ - _dbg.component_id = _COMPONENT; \ - _dbg.proc_name = a; \ - _dbg.module_name = _THIS_MODULE; +#define ACPI_FUNCTION_NAME(a) struct acpi_debug_print_info _debug_info; \ + _debug_info.component_id = _COMPONENT; \ + _debug_info.proc_name = a; \ + _debug_info.module_name = _THIS_MODULE; #define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace(__LINE__,&_dbg) + acpi_ut_trace(__LINE__,&_debug_info) #define ACPI_FUNCTION_TRACE_PTR(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_ptr(__LINE__,&_dbg,(void *)b) + acpi_ut_trace_ptr(__LINE__,&_debug_info,(void *)b) #define ACPI_FUNCTION_TRACE_U32(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_u32(__LINE__,&_dbg,(u32)b) + acpi_ut_trace_u32(__LINE__,&_debug_info,(u32)b) #define ACPI_FUNCTION_TRACE_STR(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_str(__LINE__,&_dbg,(char *)b) + acpi_ut_trace_str(__LINE__,&_debug_info,(char *)b) #define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr() @@ -531,10 +517,10 @@ #define ACPI_DO_WHILE0(a) a #endif -#define return_VOID ACPI_DO_WHILE0 ({acpi_ut_exit(__LINE__,&_dbg);return;}) -#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({acpi_ut_status_exit(__LINE__,&_dbg,(s));return((s));}) -#define return_VALUE(s) ACPI_DO_WHILE0 ({acpi_ut_value_exit(__LINE__,&_dbg,(acpi_integer)(s));return((s));}) -#define return_PTR(s) ACPI_DO_WHILE0 ({acpi_ut_ptr_exit(__LINE__,&_dbg,(u8 *)(s));return((s));}) +#define return_VOID ACPI_DO_WHILE0 ({acpi_ut_exit(__LINE__,&_debug_info);return;}) +#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({acpi_ut_status_exit(__LINE__,&_debug_info,(s));return((s));}) +#define return_VALUE(s) ACPI_DO_WHILE0 ({acpi_ut_value_exit(__LINE__,&_debug_info,(acpi_integer)(s));return((s));}) +#define return_PTR(s) ACPI_DO_WHILE0 ({acpi_ut_ptr_exit(__LINE__,&_debug_info,(u8 *)(s));return((s));}) /* Conditional execution */ @@ -548,12 +534,16 @@ /* Stack and buffer dumping */ -#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand(a) +#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a),0) #define ACPI_DUMP_OPERANDS(a,b,c,d,e) acpi_ex_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__) #define ACPI_DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b) +#endif + #define ACPI_DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d) #define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) #define ACPI_DUMP_BUFFER(a,b) acpi_ut_dump_buffer((u8 *)a,b,DB_BYTE_DISPLAY,_COMPONENT) @@ -606,7 +596,11 @@ #define ACPI_DUMP_STACK_ENTRY(a) #define ACPI_DUMP_OPERANDS(a,b,c,d,e) #define ACPI_DUMP_ENTRY(a,b) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_DUMP_TABLES(a,b) +#endif + #define ACPI_DUMP_PATHNAME(a,b,c,d) #define ACPI_DUMP_RESOURCE_LIST(a) #define ACPI_DUMP_BUFFER(a,b) @@ -681,7 +675,4 @@ #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ - -#define ACPI_GET_STACK_POINTER _asm {mov eax, ebx} - #endif /* ACMACROS_H */ diff --git a/xen/include/acpi/acobject.h b/xen/include/acpi/acobject.h index 6caaf6ade2..036023a940 100644 --- a/xen/include/acpi/acobject.h +++ b/xen/include/acpi/acobject.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -94,9 +94,7 @@ u32 bit_length; /* Length of field in bits */\ u32 base_byte_offset; /* Byte offset within containing object */\ u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ - u8 datum_valid_bits; /* Valid bit in first "Field datum" */\ - u8 end_field_valid_bits; /* Valid bits in the last "field datum" */\ - u8 end_buffer_valid_bits; /* Valid bits in the last "buffer datum" */\ + u8 access_bit_width; /* Read/Write size in bits (8-64) */\ u32 value; /* Value to store into the Bank or Index register */\ struct acpi_namespace_node *node; /* Link back to parent node */ @@ -135,7 +133,10 @@ struct acpi_object_integer acpi_integer value; }; - +/* + * Note: The String and Buffer object must be identical through the Pointer + * element. There is code that depends on this. + */ struct acpi_object_string /* Null terminated, ASCII characters only */ { ACPI_OBJECT_COMMON_HEADER @@ -180,7 +181,11 @@ struct acpi_object_event }; -#define INFINITE_CONCURRENCY 0xFF +#define ACPI_INFINITE_CONCURRENCY 0xFF + +typedef +acpi_status (*ACPI_INTERNAL_METHOD) ( + struct acpi_walk_state *walk_state); struct acpi_object_method { @@ -190,6 +195,7 @@ struct acpi_object_method u32 aml_length; void *semaphore; u8 *aml_start; + ACPI_INTERNAL_METHOD implementation; u8 concurrency; u8 thread_count; acpi_owner_id owning_id; @@ -199,13 +205,14 @@ struct acpi_object_method struct acpi_object_mutex { ACPI_OBJECT_COMMON_HEADER - u16 sync_level; - u16 acquisition_depth; - struct acpi_thread_state *owner_thread; - void *semaphore; + u8 sync_level; /* 0-15, specified in Mutex() call */ + u16 acquisition_depth; /* Allow multiple Acquires, same thread */ + struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ + void *semaphore; /* Actual OS synchronization object */ union acpi_operand_object *prev; /* Link for list of acquired mutexes */ union acpi_operand_object *next; /* Link for list of acquired mutexes */ - struct acpi_namespace_node *node; /* containing object */ + struct acpi_namespace_node *node; /* Containing namespace node */ + u8 original_sync_level; /* Owner's original sync level (0-15) */ }; @@ -215,7 +222,7 @@ struct acpi_object_region u8 space_id; union acpi_operand_object *handler; /* Handler for region access */ - struct acpi_namespace_node *node; /* containing object */ + struct acpi_namespace_node *node; /* Containing namespace node */ union acpi_operand_object *next; u32 length; acpi_physical_address address; diff --git a/xen/include/acpi/acoutput.h b/xen/include/acpi/acoutput.h index 0ed98ae4d3..2fbe180fee 100644 --- a/xen/include/acpi/acoutput.h +++ b/xen/include/acpi/acoutput.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -136,7 +136,7 @@ /* * Debug level macros that are used in the DEBUG_PRINT macros */ -#define ACPI_DEBUG_LEVEL(dl) (u32) dl,__LINE__,&_dbg +#define ACPI_DEBUG_LEVEL(dl) (u32) dl,__LINE__,&_debug_info /* Exception level -- used in the global "debug_level" */ diff --git a/xen/include/acpi/acpi.h b/xen/include/acpi/acpi.h index bb5bd8f03e..ad53252dd4 100644 --- a/xen/include/acpi/acpi.h +++ b/xen/include/acpi/acpi.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/xen/include/acpi/acpi_bus.h b/xen/include/acpi/acpi_bus.h index 4326bc934b..a4197e9abe 100644 --- a/xen/include/acpi/acpi_bus.h +++ b/xen/include/acpi/acpi_bus.h @@ -26,16 +26,10 @@ #ifndef __ACPI_BUS_H__ #define __ACPI_BUS_H__ -#if 0 -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,4)) -#include -#define CONFIG_LDM -#endif -#endif /* 0 */ - #include +#define PREFIX "ACPI: " + /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { @@ -66,10 +60,10 @@ acpi_evaluate_reference ( #ifdef CONFIG_ACPI_BUS -/*#include */ +#include #define ACPI_BUS_FILE_ROOT "acpi" -/*extern struct proc_dir_entry *acpi_root_dir;*/ +extern struct proc_dir_entry *acpi_root_dir; extern FADT_DESCRIPTOR acpi_fadt; enum acpi_bus_removal_type { @@ -108,6 +102,9 @@ typedef int (*acpi_op_suspend) (struct acpi_device *device, int state); typedef int (*acpi_op_resume) (struct acpi_device *device, int state); typedef int (*acpi_op_scan) (struct acpi_device *device); typedef int (*acpi_op_bind) (struct acpi_device *device); +typedef int (*acpi_op_unbind) (struct acpi_device *device); +typedef int (*acpi_op_match) (struct acpi_device *device, + struct acpi_driver *driver); struct acpi_device_ops { acpi_op_add add; @@ -119,13 +116,15 @@ struct acpi_device_ops { acpi_op_resume resume; acpi_op_scan scan; acpi_op_bind bind; + acpi_op_unbind unbind; + acpi_op_match match; }; struct acpi_driver { struct list_head node; char name[80]; char class[80]; - int references; + atomic_t references; char *ids; /* Supported Hardware IDs */ struct acpi_device_ops ops; }; @@ -161,7 +160,8 @@ struct acpi_device_flags { u32 suprise_removal_ok:1; u32 power_manageable:1; u32 performance_manageable:1; - u32 reserved:21; + u32 wake_capable:1; /* Wakeup(_PRW) supported? */ + u32 reserved:20; }; @@ -207,10 +207,8 @@ struct acpi_device_power_flags { u32 explicit_get:1; /* _PSC present? */ u32 power_resources:1; /* Power resources */ u32 inrush_current:1; /* Serialize Dx->D0 */ - u32 wake_capable:1; /* Wakeup supported? */ - u32 wake_enabled:1; /* Enabled for wakeup */ u32 power_removed:1; /* Optimize Dx->D0 */ - u32 reserved:26; + u32 reserved:28; }; struct acpi_device_power_state { @@ -254,6 +252,25 @@ struct acpi_device_perf { struct acpi_device_perf_state *states; }; +/* Wakeup Management */ +struct acpi_device_wakeup_flags { + u8 valid:1; /* Can successfully enable wakeup? */ + u8 run_wake:1; /* Run-Wake GPE devices */ +}; + +struct acpi_device_wakeup_state { + u8 enabled:1; + u8 active:1; +}; + +struct acpi_device_wakeup { + acpi_handle gpe_device; + acpi_integer gpe_number;; + acpi_integer sleep_state; + struct acpi_handle_list resources; + struct acpi_device_wakeup_state state; + struct acpi_device_wakeup_flags flags; +}; /* Device */ @@ -262,18 +279,19 @@ struct acpi_device { struct acpi_device *parent; struct list_head children; struct list_head node; + struct list_head wakeup_list; + struct list_head g_list; struct acpi_device_status status; struct acpi_device_flags flags; struct acpi_device_pnp pnp; struct acpi_device_power power; + struct acpi_device_wakeup wakeup; struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_device_ops ops; struct acpi_driver *driver; void *driver_data; -#ifdef CONFIG_LDM - struct device dev; -#endif + struct kobject kobj; }; #define acpi_driver_data(d) ((d)->driver_data) @@ -292,12 +310,14 @@ struct acpi_bus_event { u32 data; }; +extern struct subsystem acpi_subsys; /* * External Functions */ -int acpi_bus_get_device(acpi_handle, struct acpi_device **device); +int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); +void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context); int acpi_bus_get_status (struct acpi_device *device); int acpi_bus_get_power (acpi_handle handle, int *state); int acpi_bus_set_power (acpi_handle handle, int state); @@ -305,11 +325,16 @@ int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data); int acpi_bus_receive_event (struct acpi_bus_event *event); int acpi_bus_register_driver (struct acpi_driver *driver); int acpi_bus_unregister_driver (struct acpi_driver *driver); -int acpi_bus_scan (struct acpi_device *device); -int acpi_init (void); -void acpi_exit (void); +int acpi_bus_scan (struct acpi_device *start); +int acpi_bus_trim(struct acpi_device *start, int rmdevice); +int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, + acpi_handle handle, int type); +int acpi_match_ids (struct acpi_device *device, char *ids); +int acpi_create_dir(struct acpi_device *); +void acpi_remove_dir(struct acpi_device *); + #endif /*CONFIG_ACPI_BUS*/ #endif /*__ACPI_BUS_H__*/ diff --git a/xen/include/acpi/acpi_drivers.h b/xen/include/acpi/acpi_drivers.h index 3b5273a230..c26d5ea5b1 100644 --- a/xen/include/acpi/acpi_drivers.h +++ b/xen/include/acpi/acpi_drivers.h @@ -1,5 +1,5 @@ /* - * acpi_drivers.h ($Revision: 32 $) + * acpi_drivers.h ($Revision: 31 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -27,122 +27,22 @@ #define __ACPI_DRIVERS_H__ #include -#include "acpi_bus.h" +#include #define ACPI_MAX_STRING 80 - -/* -------------------------------------------------------------------------- - ACPI Bus - -------------------------------------------------------------------------- */ - #define ACPI_BUS_COMPONENT 0x00010000 -#define ACPI_BUS_CLASS "system_bus" -#define ACPI_BUS_HID "ACPI_BUS" -#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" -#define ACPI_BUS_DEVICE_NAME "System Bus" +#define ACPI_SYSTEM_COMPONENT 0x02000000 +/* _HID definitions */ -/* -------------------------------------------------------------------------- - AC Adapter - -------------------------------------------------------------------------- */ - -#define ACPI_AC_COMPONENT 0x00020000 -#define ACPI_AC_CLASS "ac_adapter" -#define ACPI_AC_HID "ACPI0003" -#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" -#define ACPI_AC_DEVICE_NAME "AC Adapter" -#define ACPI_AC_FILE_STATE "state" -#define ACPI_AC_NOTIFY_STATUS 0x80 -#define ACPI_AC_STATUS_OFFLINE 0x00 -#define ACPI_AC_STATUS_ONLINE 0x01 -#define ACPI_AC_STATUS_UNKNOWN 0xFF - - -/* -------------------------------------------------------------------------- - Battery - -------------------------------------------------------------------------- */ - -#define ACPI_BATTERY_COMPONENT 0x00040000 -#define ACPI_BATTERY_CLASS "battery" -#define ACPI_BATTERY_HID "PNP0C0A" -#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" -#define ACPI_BATTERY_DEVICE_NAME "Battery" -#define ACPI_BATTERY_FILE_INFO "info" -#define ACPI_BATTERY_FILE_STATUS "state" -#define ACPI_BATTERY_FILE_ALARM "alarm" -#define ACPI_BATTERY_NOTIFY_STATUS 0x80 -#define ACPI_BATTERY_NOTIFY_INFO 0x81 -#define ACPI_BATTERY_UNITS_WATTS "mW" -#define ACPI_BATTERY_UNITS_AMPS "mA" - - -/* -------------------------------------------------------------------------- - Button - -------------------------------------------------------------------------- */ - -#define ACPI_BUTTON_COMPONENT 0x00080000 -#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" -#define ACPI_BUTTON_CLASS "button" -#define ACPI_BUTTON_FILE_INFO "info" -#define ACPI_BUTTON_FILE_STATE "state" -#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 -#define ACPI_BUTTON_NOTIFY_STATUS 0x80 - -#define ACPI_BUTTON_SUBCLASS_POWER "power" -#define ACPI_BUTTON_HID_POWER "PNP0C0C" +#define ACPI_POWER_HID "ACPI_PWR" +#define ACPI_PROCESSOR_HID "ACPI_CPU" +#define ACPI_SYSTEM_HID "ACPI_SYS" +#define ACPI_THERMAL_HID "ACPI_THM" #define ACPI_BUTTON_HID_POWERF "ACPI_FPB" -#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)" -#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)" -#define ACPI_BUTTON_TYPE_POWER 0x01 -#define ACPI_BUTTON_TYPE_POWERF 0x02 - -#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" -#define ACPI_BUTTON_HID_SLEEP "PNP0C0E" #define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB" -#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)" -#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)" -#define ACPI_BUTTON_TYPE_SLEEP 0x03 -#define ACPI_BUTTON_TYPE_SLEEPF 0x04 - -#define ACPI_BUTTON_SUBCLASS_LID "lid" -#define ACPI_BUTTON_HID_LID "PNP0C0D" -#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" -#define ACPI_BUTTON_TYPE_LID 0x05 - - -/* -------------------------------------------------------------------------- - Embedded Controller - -------------------------------------------------------------------------- */ - -#define ACPI_EC_COMPONENT 0x00100000 -#define ACPI_EC_CLASS "embedded_controller" -#define ACPI_EC_HID "PNP0C09" -#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" -#define ACPI_EC_DEVICE_NAME "Embedded Controller" -#define ACPI_EC_FILE_INFO "info" - -#ifdef CONFIG_ACPI_EC - -int acpi_ec_ecdt_probe (void); -int acpi_ec_init (void); -void acpi_ec_exit (void); - -#endif - - -/* -------------------------------------------------------------------------- - Fan - -------------------------------------------------------------------------- */ - -#define ACPI_FAN_COMPONENT 0x00200000 -#define ACPI_FAN_CLASS "fan" -#define ACPI_FAN_HID "PNP0C0B" -#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" -#define ACPI_FAN_DEVICE_NAME "Fan" -#define ACPI_FAN_FILE_STATE "state" -#define ACPI_FAN_NOTIFY_STATUS 0x80 /* -------------------------------------------------------------------------- @@ -153,41 +53,28 @@ void acpi_ec_exit (void); #define ACPI_PCI_COMPONENT 0x00400000 -/* ACPI PCI Root Bridge (pci_root.c) */ - -#define ACPI_PCI_ROOT_CLASS "pci_bridge" -#define ACPI_PCI_ROOT_HID "PNP0A03" -#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" -#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" - -int acpi_pci_root_init (void); -void acpi_pci_root_exit (void); - /* ACPI PCI Interrupt Link (pci_link.c) */ -#define ACPI_PCI_LINK_CLASS "pci_irq_routing" -#define ACPI_PCI_LINK_HID "PNP0C0F" -#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" -#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" -#define ACPI_PCI_LINK_FILE_INFO "info" -#define ACPI_PCI_LINK_FILE_STATUS "state" - -int acpi_pci_link_check (void); +int acpi_irq_penalty_init (void); int acpi_pci_link_get_irq (acpi_handle handle, int index, int* edge_level, int* active_high_low); -int acpi_pci_link_init (void); -void acpi_pci_link_exit (void); /* ACPI PCI Interrupt Routing (pci_irq.c) */ int acpi_pci_irq_add_prt (acpi_handle handle, int segment, int bus); +void acpi_pci_irq_del_prt (int segment, int bus); /* ACPI PCI Device Binding (pci_bind.c) */ struct pci_bus; int acpi_pci_bind (struct acpi_device *device); +int acpi_pci_unbind (struct acpi_device *device); int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus); +/* Arch-defined function to add a bus to the system */ + +struct pci_bus *pci_acpi_scan_root(struct acpi_device *device, int domain, int bus); + #endif /*CONFIG_ACPI_PCI*/ @@ -195,43 +82,25 @@ int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, stru Power Resource -------------------------------------------------------------------------- */ -#define ACPI_POWER_COMPONENT 0x00800000 -#define ACPI_POWER_CLASS "power_resource" -#define ACPI_POWER_HID "ACPI_PWR" -#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" -#define ACPI_POWER_DEVICE_NAME "Power Resource" -#define ACPI_POWER_FILE_INFO "info" -#define ACPI_POWER_FILE_STATUS "state" -#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 -#define ACPI_POWER_RESOURCE_STATE_ON 0x01 -#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF - #ifdef CONFIG_ACPI_POWER - +int acpi_enable_wakeup_device_power (struct acpi_device *dev); +int acpi_disable_wakeup_device_power (struct acpi_device *dev); int acpi_power_get_inferred_state (struct acpi_device *device); int acpi_power_transition (struct acpi_device *device, int state); -int acpi_power_init (void); -void acpi_power_exit (void); - #endif +/* -------------------------------------------------------------------------- + Embedded Controller + -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_EC +int acpi_ec_ecdt_probe (void); +#endif + /* -------------------------------------------------------------------------- Processor -------------------------------------------------------------------------- */ -#define ACPI_PROCESSOR_COMPONENT 0x01000000 -#define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_HID "ACPI_CPU" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" -#define ACPI_PROCESSOR_DEVICE_NAME "Processor" -#define ACPI_PROCESSOR_FILE_INFO "info" -#define ACPI_PROCESSOR_FILE_POWER "power" -#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" -#define ACPI_PROCESSOR_FILE_THROTTLING "throttling" -#define ACPI_PROCESSOR_FILE_LIMIT "limit" -#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 -#define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_LIMIT_NONE 0x00 #define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01 #define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02 @@ -239,109 +108,4 @@ void acpi_power_exit (void); int acpi_processor_set_thermal_limit(acpi_handle handle, int type); -/* -------------------------------------------------------------------------- - System - -------------------------------------------------------------------------- */ - -#define ACPI_SYSTEM_COMPONENT 0x02000000 -#define ACPI_SYSTEM_CLASS "system" -#define ACPI_SYSTEM_HID "ACPI_SYS" -#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" -#define ACPI_SYSTEM_DEVICE_NAME "System" -#define ACPI_SYSTEM_FILE_INFO "info" -#define ACPI_SYSTEM_FILE_EVENT "event" -#define ACPI_SYSTEM_FILE_ALARM "alarm" -#define ACPI_SYSTEM_FILE_DSDT "dsdt" -#define ACPI_SYSTEM_FILE_FADT "fadt" -#define ACPI_SYSTEM_FILE_SLEEP "sleep" -#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" -#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" - -#ifdef CONFIG_ACPI_SYSTEM - -int acpi_system_init (void); -void acpi_system_exit (void); - -#endif - - -/* -------------------------------------------------------------------------- - Thermal Zone - -------------------------------------------------------------------------- */ - -#define ACPI_THERMAL_COMPONENT 0x04000000 -#define ACPI_THERMAL_CLASS "thermal_zone" -#define ACPI_THERMAL_HID "ACPI_THM" -#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" -#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" -#define ACPI_THERMAL_FILE_STATE "state" -#define ACPI_THERMAL_FILE_TEMPERATURE "temperature" -#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points" -#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode" -#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency" -#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 -#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81 -#define ACPI_THERMAL_NOTIFY_DEVICES 0x82 -#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0 -#define ACPI_THERMAL_NOTIFY_HOT 0xF1 -#define ACPI_THERMAL_MODE_ACTIVE 0x00 -#define ACPI_THERMAL_MODE_PASSIVE 0x01 -#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" - - -/* -------------------------------------------------------------------------- - Debug Support - -------------------------------------------------------------------------- */ - -#define ACPI_DEBUG_RESTORE 0 -#define ACPI_DEBUG_LOW 1 -#define ACPI_DEBUG_MEDIUM 2 -#define ACPI_DEBUG_HIGH 3 -#define ACPI_DEBUG_DRIVERS 4 - -/*extern u32 acpi_dbg_level;*/ -/*extern u32 acpi_dbg_layer;*/ - -static inline void -acpi_set_debug ( - u32 flag) -{ - static u32 layer_save; - static u32 level_save; - - switch (flag) { - case ACPI_DEBUG_RESTORE: - acpi_dbg_layer = layer_save; - acpi_dbg_level = level_save; - break; - case ACPI_DEBUG_LOW: - case ACPI_DEBUG_MEDIUM: - case ACPI_DEBUG_HIGH: - case ACPI_DEBUG_DRIVERS: - layer_save = acpi_dbg_layer; - level_save = acpi_dbg_level; - break; - } - - switch (flag) { - case ACPI_DEBUG_LOW: - acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; - acpi_dbg_level = ACPI_DEBUG_DEFAULT; - break; - case ACPI_DEBUG_MEDIUM: - acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; - acpi_dbg_level = ACPI_LV_FUNCTIONS | ACPI_LV_ALL_EXCEPTIONS; - break; - case ACPI_DEBUG_HIGH: - acpi_dbg_layer = 0xFFFFFFFF; - acpi_dbg_level = 0xFFFFFFFF; - break; - case ACPI_DEBUG_DRIVERS: - acpi_dbg_layer = ACPI_ALL_DRIVERS; - acpi_dbg_level = 0xFFFFFFFF; - break; - } -} - - #endif /*__ACPI_DRIVERS_H__*/ diff --git a/xen/include/acpi/acpiosxf.h b/xen/include/acpi/acpiosxf.h index 6f485231ac..57779919c1 100644 --- a/xen/include/acpi/acpiosxf.h +++ b/xen/include/acpi/acpiosxf.h @@ -9,7 +9,7 @@ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -169,17 +169,19 @@ acpi_status acpi_os_map_memory ( acpi_physical_address physical_address, acpi_size size, - void **logical_address); + void __iomem **logical_address); void acpi_os_unmap_memory ( - void *logical_address, + void __iomem *logical_address, acpi_size size); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_os_get_physical_address ( void *logical_address, acpi_physical_address *physical_address); +#endif /* @@ -188,14 +190,14 @@ acpi_os_get_physical_address ( acpi_status acpi_os_install_interrupt_handler ( - u32 interrupt_number, - OSD_HANDLER service_routine, + u32 gsi, + acpi_osd_handler service_routine, void *context); acpi_status acpi_os_remove_interrupt_handler ( - u32 interrupt_number, - OSD_HANDLER service_routine); + u32 gsi, + acpi_osd_handler service_routine); /* @@ -209,13 +211,16 @@ acpi_os_get_thread_id ( acpi_status acpi_os_queue_for_execution ( u32 priority, - OSD_EXECUTION_CALLBACK function, + acpi_osd_exec_callback function, + void *context); + +void +acpi_os_wait_events_complete ( void *context); void acpi_os_sleep ( - u32 seconds, - u32 milliseconds); + acpi_integer milliseconds); void acpi_os_stall ( @@ -258,25 +263,28 @@ acpi_os_write_memory ( /* * Platform and hardware-independent PCI configuration space access + * Note: Can't use "Register" as a parameter, changed to "Reg" -- + * certain compilers complain. */ acpi_status acpi_os_read_pci_configuration ( struct acpi_pci_id *pci_id, - u32 register, + u32 reg, void *value, u32 width); acpi_status acpi_os_write_pci_configuration ( struct acpi_pci_id *pci_id, - u32 register, + u32 reg, acpi_integer value, u32 width); /* * Interim function needed for PCI IRQ routing */ + void acpi_os_derive_pci_id( acpi_handle rhandle, @@ -292,12 +300,14 @@ acpi_os_readable ( void *pointer, acpi_size length); +#ifdef ACPI_FUTURE_USAGE u8 acpi_os_writable ( void *pointer, acpi_size length); +#endif -u32 +u64 acpi_os_get_timer ( void); @@ -329,9 +339,11 @@ acpi_os_redirect_output ( * Debug input */ +#ifdef ACPI_FUTURE_USAGE u32 acpi_os_get_line ( char *buffer); +#endif /* diff --git a/xen/include/acpi/acpixf.h b/xen/include/acpi/acpixf.h index fcebceb3e2..00d78b7965 100644 --- a/xen/include/acpi/acpixf.h +++ b/xen/include/acpi/acpixf.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,9 +70,11 @@ acpi_status acpi_terminate ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_subsystem_status ( void); +#endif acpi_status acpi_enable ( @@ -82,9 +84,11 @@ acpi_status acpi_disable ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_system_info ( struct acpi_buffer *ret_buffer); +#endif const char * acpi_format_exception ( @@ -94,10 +98,12 @@ acpi_status acpi_purge_cached_objects ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_install_initialization_handler ( acpi_init_handler handler, u32 function); +#endif /* * ACPI Memory manager @@ -129,6 +135,7 @@ acpi_status acpi_load_tables ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_load_table ( struct acpi_table_header *table_ptr); @@ -142,6 +149,7 @@ acpi_get_table_header ( acpi_table_type table_type, u32 instance, struct acpi_table_header *out_table_header); +#endif /* ACPI_FUTURE_USAGE */ acpi_status acpi_get_table ( @@ -218,6 +226,7 @@ acpi_evaluate_object ( struct acpi_object_list *parameter_objects, struct acpi_buffer *return_object_buffer); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_evaluate_object_typed ( acpi_handle object, @@ -225,6 +234,7 @@ acpi_evaluate_object_typed ( struct acpi_object_list *external_params, struct acpi_buffer *return_buffer, acpi_object_type return_type); +#endif acpi_status acpi_get_object_info ( @@ -296,9 +306,20 @@ acpi_install_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, u32 type, - acpi_gpe_handler handler, + acpi_event_handler address, void *context); +#ifdef ACPI_FUTURE_USAGE +acpi_status +acpi_install_exception_handler ( + acpi_exception_handler handler); +#endif + + +/* + * Event interfaces + */ + acpi_status acpi_acquire_global_lock ( u16 timeout, @@ -312,7 +333,7 @@ acpi_status acpi_remove_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, - acpi_gpe_handler handler); + acpi_event_handler address); acpi_status acpi_enable_event ( @@ -328,10 +349,18 @@ acpi_status acpi_clear_event ( u32 event); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_event_status ( u32 event, acpi_event_status *event_status); +#endif /* ACPI_FUTURE_USAGE */ + +acpi_status +acpi_set_gpe_type ( + acpi_handle gpe_device, + u32 gpe_number, + u8 type); acpi_status acpi_enable_gpe ( @@ -351,12 +380,14 @@ acpi_clear_gpe ( u32 gpe_number, u32 flags); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_gpe_status ( acpi_handle gpe_device, u32 gpe_number, u32 flags, acpi_event_status *event_status); +#endif /* ACPI_FUTURE_USAGE */ acpi_status acpi_install_gpe_block ( @@ -385,10 +416,12 @@ acpi_get_current_resources( acpi_handle device_handle, struct acpi_buffer *ret_buffer); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_possible_resources( acpi_handle device_handle, struct acpi_buffer *ret_buffer); +#endif acpi_status acpi_walk_resources ( @@ -432,9 +465,11 @@ acpi_status acpi_set_firmware_waking_vector ( acpi_physical_address physical_address); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_firmware_waking_vector ( acpi_physical_address *physical_address); +#endif acpi_status acpi_get_sleep_type_data ( @@ -446,11 +481,11 @@ acpi_status acpi_enter_sleep_state_prep ( u8 sleep_state); -acpi_status +acpi_status asmlinkage acpi_enter_sleep_state ( u8 sleep_state); -acpi_status +acpi_status asmlinkage acpi_enter_sleep_state_s4bios ( void); diff --git a/xen/include/acpi/acstruct.h b/xen/include/acpi/acstruct.h index c746cb9c3b..6b2284c9e8 100644 --- a/xen/include/acpi/acstruct.h +++ b/xen/include/acpi/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,13 +69,14 @@ struct acpi_walk_state { u8 data_type; /* To differentiate various internal objs MUST BE FIRST!*/\ + u8 walk_type; acpi_owner_id owner_id; /* Owner of objects created during the walk */ u8 last_predicate; /* Result of last predicate */ + u8 reserved; /* For alignment */ u8 current_result; /* */ u8 next_op_info; /* Info about next_op */ u8 num_operands; /* Stack pointer for Operands[] array */ u8 return_used; - u8 walk_type; u16 opcode; /* Current AML opcode */ u8 scope_depth; u8 reserved1; @@ -91,7 +92,8 @@ struct acpi_walk_state struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ union acpi_operand_object **caller_return_desc; union acpi_generic_state *control_state; /* List of control states (nested IFs) */ - struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ + struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ + struct acpi_gpe_event_info *gpe_event_info; /* Info for GPE (_Lxx/_Exx methods only */ struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ struct acpi_namespace_node *method_call_node; /* Called method Node*/ union acpi_parse_object *method_call_op; /* method_call Op if running a method */ @@ -112,7 +114,7 @@ struct acpi_walk_state union acpi_parse_object *next_op; /* next op to be processed */ acpi_parse_downwards descending_callback; acpi_parse_upwards ascending_callback; - struct acpi_thread_state *acpi_thread; + struct acpi_thread_state *thread; struct acpi_walk_state *next; /* Next walk_state in list */ }; @@ -200,4 +202,21 @@ union acpi_aml_operands }; +/* Internal method parameter list */ + +struct acpi_parameter_info +{ + struct acpi_namespace_node *node; + union acpi_operand_object **parameters; + union acpi_operand_object *return_object; + u8 parameter_type; + u8 return_object_type; +}; + +/* Types for parameter_type above */ + +#define ACPI_PARAM_ARGS 0 +#define ACPI_PARAM_GPE 1 + + #endif diff --git a/xen/include/acpi/actbl.h b/xen/include/acpi/actbl.h index 55680ad34b..f39ed91b5b 100644 --- a/xen/include/acpi/actbl.h +++ b/xen/include/acpi/actbl.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -288,19 +288,6 @@ struct smart_battery_table }; -/* - * High performance timer - */ -struct hpet_table -{ - ACPI_TABLE_HEADER_DEF - u32 hardware_id; - u32 base_address [3]; - u8 hpet_number; - u16 clock_tick; - u8 attributes; -}; - #pragma pack() @@ -343,5 +330,23 @@ struct acpi_table_support #include "actbl1.h" /* Acpi 1.0 table definitions */ #include "actbl2.h" /* Acpi 2.0 table definitions */ +extern u8 acpi_fadt_is_v1; /* is set to 1 if FADT is revision 1, + * needed for certain workarounds */ + +#pragma pack(1) +/* + * High performance timer + */ +struct hpet_table +{ + ACPI_TABLE_HEADER_DEF + u32 hardware_id; + struct acpi_generic_address base_address; + u8 hpet_number; + u16 clock_tick; + u8 attributes; +}; + +#pragma pack() #endif /* __ACTBL_H__ */ diff --git a/xen/include/acpi/actbl1.h b/xen/include/acpi/actbl1.h index 0db07c3291..33de5f4d2c 100644 --- a/xen/include/acpi/actbl1.h +++ b/xen/include/acpi/actbl1.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/xen/include/acpi/actbl2.h b/xen/include/acpi/actbl2.h index 188cedb529..ea3ca08d88 100644 --- a/xen/include/acpi/actbl2.h +++ b/xen/include/acpi/actbl2.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,6 +62,7 @@ #define BAF_8042_KEYBOARD_CONTROLLER 0x0002 #define FADT2_REVISION_ID 3 +#define FADT2_MINUS_REVISION_ID 2 #pragma pack(1) @@ -114,53 +115,56 @@ struct acpi_generic_address u8 address_space_id; /* Address space where struct or register exists. */ u8 register_bit_width; /* Size in bits of given register */ u8 register_bit_offset; /* Bit offset within the register */ - u8 reserved; /* Must be 0 */ + u8 access_width; /* Minimum Access size (ACPI 3.0) */ u64 address; /* 64-bit address of struct or register */ }; +#define FADT_REV2_COMMON \ + u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \ + u32 V1_dsdt; /* 32-bit physical address of DSDT */ \ + u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \ + u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \ + u16 sci_int; /* System vector of SCI interrupt */ \ + u32 smi_cmd; /* Port address of SMI command port */ \ + u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ \ + u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ \ + u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ \ + u8 pstate_cnt; /* Processor performance state control*/ \ + u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ \ + u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ \ + u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \ + u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \ + u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \ + u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \ + u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \ + u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \ + u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ \ + u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ \ + u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \ + u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \ + u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \ + u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ \ + u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ \ + u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ \ + u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \ + u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \ + u16 flush_size; /* Number of flush strides that need to be read */ \ + u16 flush_stride; /* Processor's memory cache line width, in bytes */ \ + u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \ + u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \ + u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \ + u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \ + u8 century; /* Index to century in RTC CMOS RAM */ \ + u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ + /* * ACPI 2.0 Fixed ACPI Description Table (FADT) */ struct fadt_descriptor_rev2 { ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ - u32 V1_dsdt; /* 32-bit physical address of DSDT */ - u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ - u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ - u16 sci_int; /* System vector of SCI interrupt */ - u32 smi_cmd; /* Port address of SMI command port */ - u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ - u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ - u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - u8 pstate_cnt; /* Processor performance state control*/ - u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ - u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ - u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ - u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ - u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ - u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ - u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ - u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ - u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ - u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ - u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ - u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ - u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ - u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ - u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ - u16 flush_size; /* Number of flush strides that need to be read */ - u16 flush_stride; /* Processor's memory cache line width, in bytes */ - u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ - u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ - u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ - u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* Index to century in RTC CMOS RAM */ - u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ + FADT_REV2_COMMON u8 reserved2; /* Reserved */ u32 wb_invd : 1; /* The wbinvd instruction works properly */ u32 wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ @@ -195,6 +199,20 @@ struct fadt_descriptor_rev2 }; +/* "Downrevved" ACPI 2.0 FADT descriptor */ + +struct fadt_descriptor_rev2_minus +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + FADT_REV2_COMMON + u8 reserved2; /* Reserved */ + u32 flags; + struct acpi_generic_address reset_register; /* Reset register address in GAS format */ + u8 reset_value; /* Value to write to the reset_register port to reset the system. */ + u8 reserved7[3]; /* These three bytes must be zero */ +}; + + /* Embedded Controller */ struct ec_boot_resources diff --git a/xen/include/acpi/actypes.h b/xen/include/acpi/actypes.h index ae1a73e617..51cb780c24 100644 --- a/xen/include/acpi/actypes.h +++ b/xen/include/acpi/actypes.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -303,7 +303,7 @@ struct uint32_struct typedef u32 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT32_MAX #define ACPI_INTEGER_BIT_SIZE 32 -#define ACPI_MAX_DECIMAL_DIGITS 10 +#define ACPI_MAX_DECIMAL_DIGITS 10 /* 2^32 = 4,294,967,296 */ #define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 32-bit divide */ @@ -315,13 +315,18 @@ typedef u32 acpi_integer; typedef u64 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT64_MAX #define ACPI_INTEGER_BIT_SIZE 64 -#define ACPI_MAX_DECIMAL_DIGITS 19 +#define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ + #if ACPI_MACHINE_WIDTH == 64 #define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 64-bit divide */ #endif #endif +#define ACPI_MAX64_DECIMAL_DIGITS 20 +#define ACPI_MAX32_DECIMAL_DIGITS 10 +#define ACPI_MAX16_DECIMAL_DIGITS 5 +#define ACPI_MAX8_DECIMAL_DIGITS 3 /* * Constants with special meanings @@ -349,7 +354,6 @@ typedef u64 acpi_integer; /* * Power state values */ - #define ACPI_STATE_UNKNOWN (u8) 0xFF #define ACPI_STATE_S0 (u8) 0 @@ -393,7 +397,6 @@ typedef u64 acpi_integer; #define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 6 #define ACPI_NOTIFY_POWER_FAULT (u8) 7 - /* * Table types. These values are passed to the table related APIs */ @@ -409,14 +412,13 @@ typedef u32 acpi_table_type; #define ACPI_TABLE_MAX 6 #define NUM_ACPI_TABLE_TYPES (ACPI_TABLE_MAX+1) - /* * Types associated with ACPI names and objects. The first group of * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition * of the ACPI object_type() operator (See the ACPI Spec). Therefore, * only add to the first group if the spec changes. * - * Types must be kept in sync with the global acpi_ns_properties + * NOTE: Types must be kept in sync with the global acpi_ns_properties * and acpi_ns_type_names arrays. */ typedef u32 acpi_object_type; @@ -453,26 +455,27 @@ typedef u32 acpi_object_type; #define ACPI_TYPE_LOCAL_INDEX_FIELD 0x13 #define ACPI_TYPE_LOCAL_REFERENCE 0x14 /* Arg#, Local#, Name, Debug, ref_of, Index */ #define ACPI_TYPE_LOCAL_ALIAS 0x15 -#define ACPI_TYPE_LOCAL_NOTIFY 0x16 -#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x17 -#define ACPI_TYPE_LOCAL_RESOURCE 0x18 -#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x19 -#define ACPI_TYPE_LOCAL_SCOPE 0x1A /* 1 Name, multiple object_list Nodes */ +#define ACPI_TYPE_LOCAL_METHOD_ALIAS 0x16 +#define ACPI_TYPE_LOCAL_NOTIFY 0x17 +#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18 +#define ACPI_TYPE_LOCAL_RESOURCE 0x19 +#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x1A +#define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple object_list Nodes */ -#define ACPI_TYPE_NS_NODE_MAX 0x1A /* Last typecode used within a NS Node */ +#define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */ /* * These are special object types that never appear in * a Namespace node, only in an union acpi_operand_object */ -#define ACPI_TYPE_LOCAL_EXTRA 0x1B -#define ACPI_TYPE_LOCAL_DATA 0x1C +#define ACPI_TYPE_LOCAL_EXTRA 0x1C +#define ACPI_TYPE_LOCAL_DATA 0x1D -#define ACPI_TYPE_LOCAL_MAX 0x1C +#define ACPI_TYPE_LOCAL_MAX 0x1D /* All types above here are invalid */ -#define ACPI_TYPE_INVALID 0x1D +#define ACPI_TYPE_INVALID 0x1E #define ACPI_TYPE_NOT_FOUND 0xFF @@ -514,9 +517,8 @@ typedef u32 acpi_object_type; #define ACPI_WRITE 1 #define ACPI_IO_MASK 1 - /* - * Acpi Event Types: Fixed & General Purpose + * Event Types: Fixed & General Purpose */ typedef u32 acpi_event_type; @@ -531,25 +533,8 @@ typedef u32 acpi_event_type; #define ACPI_EVENT_MAX 4 #define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1 -#define ACPI_GPE_INVALID 0xFF -#define ACPI_GPE_MAX 0xFF -#define ACPI_NUM_GPE 256 - -#define ACPI_EVENT_LEVEL_TRIGGERED 1 -#define ACPI_EVENT_EDGE_TRIGGERED 2 - /* - * Flags for GPE and Lock interfaces - */ -#define ACPI_EVENT_WAKE_ENABLE 0x2 -#define ACPI_EVENT_WAKE_DISABLE 0x2 - -#define ACPI_NOT_ISR 0x1 -#define ACPI_ISR 0x0 - - -/* - * acpi_event Status: + * Event Status - Per event * ------------- * The encoding of acpi_event_status is illustrated below. * Note that a set bit (1) indicates the property is TRUE @@ -570,12 +555,74 @@ typedef u32 acpi_event_status; #define ACPI_EVENT_FLAG_WAKE_ENABLED (acpi_event_status) 0x02 #define ACPI_EVENT_FLAG_SET (acpi_event_status) 0x04 +/* + * General Purpose Events (GPE) + */ +#define ACPI_GPE_INVALID 0xFF +#define ACPI_GPE_MAX 0xFF +#define ACPI_NUM_GPE 256 + +#define ACPI_GPE_ENABLE 0 +#define ACPI_GPE_DISABLE 1 + + +/* + * GPE info flags - Per GPE + * +-+-+-+---+---+-+ + * |7|6|5|4:3|2:1|0| + * +-+-+-+---+---+-+ + * | | | | | | + * | | | | | +--- Interrupt type: Edge or Level Triggered + * | | | | +--- Type: Wake-only, Runtime-only, or wake/runtime + * | | | +--- Type of dispatch -- to method, handler, or none + * | | +--- Enabled for runtime? + * | +--- Enabled for wake? + * +--- System state when GPE ocurred (running/waking) + */ +#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x01 +#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x01 +#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 + +#define ACPI_GPE_TYPE_MASK (u8) 0x06 +#define ACPI_GPE_TYPE_WAKE_RUN (u8) 0x06 +#define ACPI_GPE_TYPE_WAKE (u8) 0x02 +#define ACPI_GPE_TYPE_RUNTIME (u8) 0x04 /* Default */ + +#define ACPI_GPE_DISPATCH_MASK (u8) 0x18 +#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x08 +#define ACPI_GPE_DISPATCH_METHOD (u8) 0x10 +#define ACPI_GPE_DISPATCH_NOT_USED (u8) 0x00 /* Default */ + +#define ACPI_GPE_RUN_ENABLE_MASK (u8) 0x20 +#define ACPI_GPE_RUN_ENABLED (u8) 0x20 +#define ACPI_GPE_RUN_DISABLED (u8) 0x00 /* Default */ + +#define ACPI_GPE_WAKE_ENABLE_MASK (u8) 0x40 +#define ACPI_GPE_WAKE_ENABLED (u8) 0x40 +#define ACPI_GPE_WAKE_DISABLED (u8) 0x00 /* Default */ + +#define ACPI_GPE_ENABLE_MASK (u8) 0x60 /* Both run/wake */ + +#define ACPI_GPE_SYSTEM_MASK (u8) 0x80 +#define ACPI_GPE_SYSTEM_RUNNING (u8) 0x80 +#define ACPI_GPE_SYSTEM_WAKING (u8) 0x00 + +/* + * Flags for GPE and Lock interfaces + */ +#define ACPI_EVENT_WAKE_ENABLE 0x2 /* acpi_gpe_enable */ +#define ACPI_EVENT_WAKE_DISABLE 0x2 /* acpi_gpe_disable */ + +#define ACPI_NOT_ISR 0x1 +#define ACPI_ISR 0x0 + /* Notify types */ -#define ACPI_SYSTEM_NOTIFY 0 -#define ACPI_DEVICE_NOTIFY 1 -#define ACPI_MAX_NOTIFY_HANDLER_TYPE 1 +#define ACPI_SYSTEM_NOTIFY 0x1 +#define ACPI_DEVICE_NOTIFY 0x2 +#define ACPI_ALL_NOTIFY 0x3 +#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 #define ACPI_MAX_SYS_NOTIFY 0x7f @@ -756,11 +803,11 @@ struct acpi_system_info */ typedef u32 -(ACPI_SYSTEM_XFACE *OSD_HANDLER) ( +(ACPI_SYSTEM_XFACE *acpi_osd_handler) ( void *context); typedef void -(ACPI_SYSTEM_XFACE *OSD_EXECUTION_CALLBACK) ( +(ACPI_SYSTEM_XFACE *acpi_osd_exec_callback) ( void *context); /* @@ -770,10 +817,6 @@ typedef u32 (*acpi_event_handler) ( void *context); -typedef -void (*acpi_gpe_handler) ( - void *context); - typedef void (*acpi_notify_handler) ( acpi_handle device, @@ -793,8 +836,16 @@ acpi_status (*acpi_init_handler) ( #define ACPI_INIT_DEVICE_INI 1 +typedef +acpi_status (*acpi_exception_handler) ( + acpi_status aml_status, + acpi_name name, + u16 opcode, + u32 aml_offset, + void *context); -/* Address Spaces (Operation Regions */ + +/* Address Spaces (For Operation Regions) */ typedef acpi_status (*acpi_adr_space_handler) ( @@ -861,6 +912,7 @@ struct acpi_compatible_id_list #define ACPI_VALID_HID 0x0004 #define ACPI_VALID_UID 0x0008 #define ACPI_VALID_CID 0x0010 +#define ACPI_VALID_SXDS 0x0020 #define ACPI_COMMON_OBJ_INFO \ @@ -880,11 +932,12 @@ struct acpi_device_info { ACPI_COMMON_OBJ_INFO; - u32 valid; /* Indicates which fields are valid */ + u32 valid; /* Indicates which fields below are valid */ u32 current_status; /* _STA value */ acpi_integer address; /* _ADR value if any */ struct acpi_device_id hardware_id; /* _HID value if any */ struct acpi_device_id unique_id; /* _UID value if any */ + u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ struct acpi_compatible_id_list compatibility_id; /* List of _CIDs if any */ }; diff --git a/xen/include/acpi/acutils.h b/xen/include/acpi/acutils.h index 4927d6beab..0de26b8f10 100644 --- a/xen/include/acpi/acutils.h +++ b/xen/include/acpi/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,6 @@ acpi_status (*acpi_pkg_callback) ( union acpi_generic_state *state, void *context); - acpi_status acpi_ut_walk_package_tree ( union acpi_operand_object *source_object, @@ -60,7 +59,6 @@ acpi_ut_walk_package_tree ( acpi_pkg_callback walk_callback, void *context); - struct acpi_pkg_info { u8 *free_space; @@ -179,6 +177,12 @@ acpi_ut_strncpy ( const char *src_string, acpi_size count); +int +acpi_ut_memcmp ( + const char *buffer1, + const char *buffer2, + acpi_size count); + int acpi_ut_strncmp ( const char *string1, @@ -473,8 +477,13 @@ acpi_ut_delete_internal_object_list ( #define METHOD_NAME__PRT "_PRT" #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__PRS "_PRS" +#define METHOD_NAME__PRW "_PRW" +acpi_status +acpi_ut_osi_implementation ( + struct acpi_walk_state *walk_state); + acpi_status acpi_ut_evaluate_object ( struct acpi_namespace_node *prefix_node, @@ -508,6 +517,10 @@ acpi_ut_execute_UID ( struct acpi_namespace_node *device_node, struct acpi_device_id *uid); +acpi_status +acpi_ut_execute_sxds ( + struct acpi_namespace_node *device_node, + u8 *highest); /* * ut_mutex - mutual exclusion interfaces @@ -570,6 +583,10 @@ union acpi_operand_object * acpi_ut_create_buffer_object ( acpi_size buffer_size); +union acpi_operand_object * +acpi_ut_create_string_object ( + acpi_size string_size); + /* * ut_ref_cnt - Object reference count management @@ -649,12 +666,14 @@ acpi_ut_create_update_state_and_push ( u16 action, union acpi_generic_state **state_list); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_ut_create_pkg_state_and_push ( void *internal_object, void *external_object, u16 index, union acpi_generic_state **state_list); +#endif union acpi_generic_state * acpi_ut_create_control_state ( @@ -664,6 +683,7 @@ void acpi_ut_delete_generic_state ( union acpi_generic_state *state); +#ifdef ACPI_ENABLE_OBJECT_CACHE void acpi_ut_delete_generic_state_cache ( void); @@ -671,6 +691,7 @@ acpi_ut_delete_generic_state_cache ( void acpi_ut_delete_object_cache ( void); +#endif /* * utmisc @@ -683,14 +704,14 @@ acpi_ut_print_string ( acpi_status acpi_ut_divide ( - acpi_integer *in_dividend, - acpi_integer *in_divisor, + acpi_integer in_dividend, + acpi_integer in_divisor, acpi_integer *out_quotient, acpi_integer *out_remainder); acpi_status acpi_ut_short_divide ( - acpi_integer *in_dividend, + acpi_integer in_dividend, u32 divisor, acpi_integer *out_quotient, u32 *out_remainder); @@ -709,9 +730,15 @@ acpi_ut_strtoul64 ( u32 base, acpi_integer *ret_integer); +/* Values for Base above (16=Hex, 10=Decimal) */ + +#define ACPI_ANY_BASE 0 + +#ifdef ACPI_FUTURE_USAGE char * acpi_ut_strupr ( char *src_string); +#endif u8 * acpi_ut_get_resource_end_tag ( @@ -753,9 +780,11 @@ acpi_ut_release_to_cache ( u32 list_id, void *object); +#ifdef ACPI_ENABLE_OBJECT_CACHE void acpi_ut_delete_generic_cache ( u32 list_id); +#endif acpi_status acpi_ut_validate_buffer ( @@ -830,9 +859,11 @@ acpi_ut_remove_allocation ( char *module, u32 line); +#ifdef ACPI_FUTURE_USAGE void acpi_ut_dump_allocation_info ( void); +#endif void acpi_ut_dump_allocations ( diff --git a/xen/include/acpi/platform/acenv.h b/xen/include/acpi/platform/acenv.h index 9a0cd41084..5a956b549b 100644 --- a/xen/include/acpi/platform/acenv.h +++ b/xen/include/acpi/platform/acenv.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,6 +57,7 @@ #define ACPI_DISASSEMBLER #define ACPI_NO_METHOD_EXECUTION #define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_ENABLE_OBJECT_CACHE #endif #ifdef _ACPI_EXEC_APP @@ -67,6 +68,7 @@ #define ACPI_DEBUGGER #define ACPI_DISASSEMBLER #define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_ENABLE_OBJECT_CACHE #endif #ifdef _ACPI_ASL_COMPILER @@ -75,6 +77,7 @@ #define ACPI_DISASSEMBLER #define ACPI_CONSTANT_EVAL_ONLY #define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_ENABLE_OBJECT_CACHE #endif /* @@ -152,12 +155,8 @@ #define COMPILER_DEPENDENT_INT64 long long #define COMPILER_DEPENDENT_UINT64 unsigned long long - -/* Name of host operating system (returned by the _OS_ namespace object) */ - -#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" - -/* This macro is used to tag functions as "printf-like" because +/* + * This macro is used to tag functions as "printf-like" because * some compilers can catch printf format string problems. MSVC * doesn't, so this is proprocessed away. */ @@ -227,7 +226,11 @@ */ #define ACPI_STRSTR(s1,s2) strstr((s1), (s2)) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s)) +#endif + #define ACPI_STRLEN(s) (acpi_size) strlen((s)) #define ACPI_STRCPY(d,s) (void) strcpy((d), (s)) #define ACPI_STRNCPY(d,s,n) (void) strncpy((d), (s), (acpi_size)(n)) @@ -236,6 +239,7 @@ #define ACPI_STRCAT(d,s) (void) strcat((d), (s)) #define ACPI_STRNCAT(d,s,n) strncat((d), (s), (acpi_size)(n)) #define ACPI_STRTOUL(d,s,n) strtoul((d), (s), (acpi_size)(n)) +#define ACPI_MEMCMP(s1,s2,n) memcmp((s1), (s2), (acpi_size)(n)) #define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (acpi_size)(n)) #define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (acpi_size)(n)) @@ -290,7 +294,11 @@ typedef char *va_list; #define ACPI_STRSTR(s1,s2) acpi_ut_strstr ((s1), (s2)) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s)) +#endif + #define ACPI_STRLEN(s) (acpi_size) acpi_ut_strlen ((s)) #define ACPI_STRCPY(d,s) (void) acpi_ut_strcpy ((d), (s)) #define ACPI_STRNCPY(d,s,n) (void) acpi_ut_strncpy ((d), (s), (acpi_size)(n)) @@ -299,6 +307,7 @@ typedef char *va_list; #define ACPI_STRCAT(d,s) (void) acpi_ut_strcat ((d), (s)) #define ACPI_STRNCAT(d,s,n) acpi_ut_strncat ((d), (s), (acpi_size)(n)) #define ACPI_STRTOUL(d,s,n) acpi_ut_strtoul ((d), (s), (acpi_size)(n)) +#define ACPI_MEMCMP(s1,s2,n) acpi_ut_memcmp((s1), (s2), (acpi_size)(n)) #define ACPI_MEMCPY(d,s,n) (void) acpi_ut_memcpy ((d), (s), (acpi_size)(n)) #define ACPI_MEMSET(d,v,n) (void) acpi_ut_memset ((d), (v), (acpi_size)(n)) #define ACPI_TOUPPER acpi_ut_to_upper diff --git a/xen/include/acpi/platform/acgcc.h b/xen/include/acpi/platform/acgcc.h index ac15b08460..91fda36b04 100644 --- a/xen/include/acpi/platform/acgcc.h +++ b/xen/include/acpi/platform/acgcc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,6 +54,6 @@ * to to tell the compiler warning in a per-variable manner that a variable * is unused. */ -#define ACPI_UNUSED_VAR __attribute_used__ +#define ACPI_UNUSED_VAR __attribute__ ((unused)) #endif /* __ACGCC_H__ */ diff --git a/xen/include/acpi/platform/aclinux.h b/xen/include/acpi/platform/aclinux.h index eecd6c888c..4006b0ce01 100644 --- a/xen/include/acpi/platform/aclinux.h +++ b/xen/include/acpi/platform/aclinux.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,8 +44,6 @@ #ifndef __ACLINUX_H__ #define __ACLINUX_H__ -#define ACPI_OS_NAME "Linux" - #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 @@ -83,6 +81,8 @@ #define ACPI_USE_NATIVE_DIVIDE #endif +#define __cdecl +#define ACPI_FLUSH_CPU_CACHE() #endif /* __KERNEL__ */ /* Linux uses GCC */ diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index 74dbb3a4e5..9b656e493b 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -31,10 +31,6 @@ typedef int pid_t; #define touch_nmi_watchdog() // from linux/include/linux/types.h -#define BITS_TO_LONGS(bits) \ - (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) -#define DECLARE_BITMAP(name,bits) \ - unsigned long name[BITS_TO_LONGS(bits)] #define CLEAR_BITMAP(name,bits) \ memset(name, 0, BITS_TO_LONGS(bits)*sizeof(unsigned long)) @@ -57,7 +53,6 @@ extern char _end[]; /* standard ELF symbol */ //#define __kernel //#define __safe #define __force -#define __iomem #define __chk_user_ptr(x) (void)0 //#define __chk_io_ptr(x) (void)0 //#define __builtin_warning(x, y...) (1) @@ -77,9 +72,6 @@ extern char _end[]; /* standard ELF symbol */ //#define CONFIG_NR_CPUS 16 #define barrier() __asm__ __volatile__("": : :"memory") -// linux/include/spinlock.h -#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED - /////////////////////////////////////////////////////////////// // xen/include/asm/config.h // Natural boundary upon TR size to define xenheap space @@ -174,12 +166,6 @@ struct device { #endif }; -// from linux/include/linux/pci.h -struct pci_bus_region { - unsigned long start; - unsigned long end; -}; - // warning: unless search_extable is declared, the return value gets // truncated to 32-bits, causing a very strange error in privop handling struct exception_table_entry; @@ -264,6 +250,14 @@ struct screen_info { }; #define seq_printf(a,b...) printf(b) #define CONFIG_BLK_DEV_INITRD // needed to reserve memory for domain0 +// +#define __smp_processor_id() (current->processor) + +// needed for newer ACPI code +#define asmlinkage + +#define FORCE_CRASH() asm("break 0;;"); + // these declarations got moved at some point, find a better place for them extern int opt_noht; extern int ht_per_core; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 6425368f51..7b6758078e 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -37,12 +37,30 @@ struct arch_domain { #define shared_info_va arch.shared_info_va struct arch_exec_domain { +#if 1 + TR_ENTRY itrs[NITRS]; + TR_ENTRY dtrs[NDTRS]; + TR_ENTRY itlb; + TR_ENTRY dtlb; + unsigned long itlb_pte; + unsigned long dtlb_pte; + unsigned long irr[4]; + unsigned long insvc[4]; + unsigned long iva; + unsigned long dcr; + unsigned long itc; + unsigned long domain_itm; + unsigned long domain_itm_last; + unsigned long xen_itm; + unsigned long xen_timer_interval; +#endif void *regs; /* temporary until find a better way to do privops */ - struct thread_struct _thread; struct mm_struct *active_mm; + struct thread_struct _thread; // this must be last }; + #define active_mm arch.active_mm -#define thread arch._thread +//#define thread arch._thread // FOLLOWING FROM linux-2.6.7/include/sched.h diff --git a/xen/include/asm-ia64/serial.h b/xen/include/asm-ia64/serial.h index 7011963fb1..1ef5776032 100644 --- a/xen/include/asm-ia64/serial.h +++ b/xen/include/asm-ia64/serial.h @@ -21,69 +21,6 @@ #define OPT_COM1_STR "115200" #define OPT_COM2_STR "" -/* Register offsets */ -#define RBR 0x00 /* receive buffer */ -#define THR 0x00 /* transmit holding */ -#define IER 0x01 /* interrupt enable */ -#define IIR 0x02 /* interrupt identity */ -#define FCR 0x02 /* FIFO control */ -#define LCR 0x03 /* line control */ -#define MCR 0x04 /* Modem control */ -#define LSR 0x05 /* line status */ -#define MSR 0x06 /* Modem status */ -#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */ -#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */ - -/* Interrupt Enable Register */ -#define IER_ERDAI 0x01 /* rx data recv'd */ -#define IER_ETHREI 0x02 /* tx reg. empty */ -#define IER_ELSI 0x04 /* rx line status */ -#define IER_EMSI 0x08 /* MODEM status */ - -/* FIFO control register */ -#define FCR_ENABLE 0x01 /* enable FIFO */ -#define FCR_CLRX 0x02 /* clear Rx FIFO */ -#define FCR_CLTX 0x04 /* clear Tx FIFO */ -#define FCR_DMA 0x10 /* enter DMA mode */ -#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ -#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ -#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ -#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ - -/* Line control register */ -#define LCR_DLAB 0x80 /* Divisor Latch Access */ - -/* Modem Control Register */ -#define MCR_DTR 0x01 /* Data Terminal Ready */ -#define MCR_RTS 0x02 /* Request to Send */ -#define MCR_OUT2 0x08 /* OUT2: interrupt mask */ - -/* Line Status Register */ -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit hold reg empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -/* These parity settings can be ORed directly into the LCR. */ -#define PARITY_NONE (0<<3) -#define PARITY_ODD (1<<3) -#define PARITY_EVEN (3<<3) -#define PARITY_MARK (5<<3) -#define PARITY_SPACE (7<<3) - -#define RXBUFSZ 32 -#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1)) - -#define UART_ENABLED(_u) ((_u)->baud != 0) -#define DISABLE_UART(_u) ((_u)->baud = 0) - -/* 'Serial handles' are comprise the following fields. */ -#define SERHND_IDX (1<<0) /* COM1 or COM2? */ - unsigned char irq_serial_getc(int handle); void serial_force_unlock(int handle); diff --git a/xen/include/asm-ia64/vcpu.h b/xen/include/asm-ia64/vcpu.h index 6ee2e73dde..bb24bad2b2 100644 --- a/xen/include/asm-ia64/vcpu.h +++ b/xen/include/asm-ia64/vcpu.h @@ -21,6 +21,21 @@ typedef struct pt_regs REGS; //#define vcpu_regs(vcpu) &((struct spk_thread_t *)vcpu)->thread_regs //#define vcpu_thread(vcpu) ((struct spk_thread_t *)vcpu) +#define PRIVOP_ADDR_COUNT +#ifdef PRIVOP_ADDR_COUNT +#define _RSM 0 +#define _SSM 1 +#define PRIVOP_COUNT_NINSTS 2 +#define PRIVOP_COUNT_NADDRS 30 + +struct privop_addr_count { + char *instname; + unsigned long addr[PRIVOP_COUNT_NADDRS]; + unsigned long count[PRIVOP_COUNT_NADDRS]; + unsigned long overflow; +}; +#endif + /* general registers */ extern UINT64 vcpu_get_gr(VCPU *vcpu, unsigned reg); extern IA64FAULT vcpu_set_gr(VCPU *vcpu, unsigned reg, UINT64 value); @@ -132,6 +147,8 @@ extern void vcpu_set_next_timer(VCPU *vcpu); extern BOOLEAN vcpu_timer_expired(VCPU *vcpu); extern UINT64 vcpu_deliverable_interrupts(VCPU *vcpu); extern void vcpu_itc_no_srlz(VCPU *vcpu, UINT64, UINT64, UINT64, UINT64, UINT64); +extern UINT64 vcpu_get_tmp(VCPU *, UINT64); +extern void vcpu_set_tmp(VCPU *, UINT64, UINT64); #endif diff --git a/xen/include/asm-x86/apic.h b/xen/include/asm-x86/apic.h index 61d3f8fe47..73112359a5 100644 --- a/xen/include/asm-x86/apic.h +++ b/xen/include/asm-x86/apic.h @@ -2,19 +2,34 @@ #define __ASM_APIC_H #include -#include +#include #include #include -#ifdef CONFIG_X86_LOCAL_APIC - -#define APIC_DEBUG 0 - -#if APIC_DEBUG -#define Dprintk(x...) printk(x) -#else #define Dprintk(x...) -#endif + +/* + * Debugging macros + */ +#define APIC_QUIET 0 +#define APIC_VERBOSE 1 +#define APIC_DEBUG 2 + +extern int apic_verbosity; + +/* + * Define the default level of output to be very little + * This can be turned up by using apic=verbose for more + * information and apic=debug for _lots_ of information. + * apic_verbosity is defined in apic.c + */ +#define apic_printk(v, s, a...) do { \ + if ((v) <= apic_verbosity) \ + printk(s, ##a); \ + } while (0) + + +#ifdef CONFIG_X86_LOCAL_APIC /* * Basic functions accessing APICs. @@ -37,9 +52,12 @@ static __inline u32 apic_read(unsigned long reg) static __inline__ void apic_wait_icr_idle(void) { - do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ); + while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ) + cpu_relax(); } +int get_physical_broadcast(void); + #ifdef CONFIG_X86_GOOD_APIC # define FORCE_READ_AROUND_WRITE 0 # define apic_read_around(x) @@ -63,21 +81,29 @@ static inline void ack_APIC_irq(void) apic_write_around(APIC_EOI, 0); } +extern void (*wait_timer_tick)(void); + extern int get_maxlvt(void); extern void clear_local_APIC(void); extern void connect_bsp_APIC (void); extern void disconnect_bsp_APIC (void); extern void disable_local_APIC (void); +extern void lapic_shutdown (void); extern int verify_local_APIC (void); extern void cache_APIC_registers (void); extern void sync_Arb_IDs (void); extern void init_bsp_APIC (void); extern void setup_local_APIC (void); extern void init_apic_mappings (void); -extern void smp_local_timer_interrupt (struct cpu_user_regs * regs); -extern void setup_APIC_clocks (void); +extern void smp_local_timer_interrupt (struct cpu_user_regs *regs); +extern void setup_boot_APIC_clock (void); +extern void setup_secondary_APIC_clock (void); extern void setup_apic_nmi_watchdog (void); -extern void nmi_watchdog_tick (struct cpu_user_regs * regs); +extern int reserve_lapic_nmi(void); +extern void release_lapic_nmi(void); +extern void disable_timer_nmi_watchdog(void); +extern void enable_timer_nmi_watchdog(void); +extern void nmi_watchdog_tick (struct cpu_user_regs *regs); extern void touch_nmi_watchdog(void); extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); @@ -85,6 +111,7 @@ extern void enable_APIC_timer(void); extern unsigned int watchdog_on; extern int check_nmi_watchdog (void); +extern void enable_NMI_through_LVT0 (void * dummy); extern unsigned int nmi_watchdog; #define NMI_NONE 0 @@ -92,6 +119,9 @@ extern unsigned int nmi_watchdog; #define NMI_LOCAL_APIC 2 #define NMI_INVALID 3 -#endif /* CONFIG_X86_LOCAL_APIC */ +#else /* !CONFIG_X86_LOCAL_APIC */ +static inline void lapic_shutdown(void) { } + +#endif /* !CONFIG_X86_LOCAL_APIC */ #endif /* __ASM_APIC_H */ diff --git a/xen/include/asm-x86/apicdef.h b/xen/include/asm-x86/apicdef.h index 8d7f3aa3d7..911a55ef82 100644 --- a/xen/include/asm-x86/apicdef.h +++ b/xen/include/asm-x86/apicdef.h @@ -11,14 +11,11 @@ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 #define APIC_ID 0x20 -#define APIC_ID_MASK (0x0F<<24) -#define GET_APIC_ID(x) (((x)>>24)&0x0F) #define APIC_LVR 0x30 #define APIC_LVR_MASK 0xFF00FF #define GET_APIC_VERSION(x) ((x)&0xFF) #define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF) #define APIC_INTEGRATED(x) ((x)&0xF0) -#define APIC_XAPIC_SUPPORT(x) ((x)>=0x14) #define APIC_TASKPRI 0x80 #define APIC_TPRI_MASK 0xFF #define APIC_ARBPRI 0x90 @@ -33,8 +30,8 @@ #define SET_APIC_LOGICAL_ID(x) (((x)<<24)) #define APIC_ALL_CPUS 0xFF #define APIC_DFR 0xE0 -#define APIC_DFR_CLUSTER 0x0FFFFFFFul /* Clustered */ -#define APIC_DFR_FLAT 0xFFFFFFFFul /* Flat mode */ +#define APIC_DFR_CLUSTER 0x0FFFFFFFul +#define APIC_DFR_FLAT 0xFFFFFFFFul #define APIC_SPIV 0xF0 #define APIC_SPIV_FOCUS_DISABLED (1<<9) #define APIC_SPIV_APIC_ENABLED (1<<8) @@ -60,7 +57,6 @@ #define APIC_INT_LEVELTRIG 0x08000 #define APIC_INT_ASSERT 0x04000 #define APIC_ICR_BUSY 0x01000 -#define APIC_DEST_PHYSICAL 0x00000 #define APIC_DEST_LOGICAL 0x00800 #define APIC_DM_FIXED 0x00000 #define APIC_DM_LOWEST 0x00100 @@ -75,6 +71,7 @@ #define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF) #define SET_APIC_DEST_FIELD(x) ((x)<<24) #define APIC_LVTT 0x320 +#define APIC_LVTTHMR 0x330 #define APIC_LVTPC 0x340 #define APIC_LVT0 0x350 #define APIC_LVT_TIMER_BASE_MASK (0x3<<18) @@ -111,18 +108,272 @@ #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) -#ifdef CONFIG_X86_CLUSTERED_APIC -#define MAX_IO_APICS 32 +#ifdef CONFIG_NUMA + #define MAX_IO_APICS 32 #else -#define MAX_IO_APICS 8 + #define MAX_IO_APICS 8 #endif - /* - * The broadcast ID is 0xF for old APICs and 0xFF for xAPICs. SAPICs - * don't broadcast (yet?), but if they did, they might use 0xFFFF. + * the local APIC register structure, memory mapped. Not terribly well + * tested, but we might eventually use this one in the future - the + * problem why we cannot use it right now is the P5 APIC, it has an + * errata which cannot take 8-bit reads and writes, only 32-bit ones ... */ -#define APIC_BROADCAST_ID_XAPIC (0xFF) -#define APIC_BROADCAST_ID_APIC (0x0F) +#define u32 unsigned int + +#define lapic ((volatile struct local_apic *)APIC_BASE) + +#ifndef __ASSEMBLY__ +struct local_apic { + +/*000*/ struct { u32 __reserved[4]; } __reserved_01; + +/*010*/ struct { u32 __reserved[4]; } __reserved_02; + +/*020*/ struct { /* APIC ID Register */ + u32 __reserved_1 : 24, + phys_apic_id : 4, + __reserved_2 : 4; + u32 __reserved[3]; + } id; + +/*030*/ const + struct { /* APIC Version Register */ + u32 version : 8, + __reserved_1 : 8, + max_lvt : 8, + __reserved_2 : 8; + u32 __reserved[3]; + } version; + +/*040*/ struct { u32 __reserved[4]; } __reserved_03; + +/*050*/ struct { u32 __reserved[4]; } __reserved_04; + +/*060*/ struct { u32 __reserved[4]; } __reserved_05; + +/*070*/ struct { u32 __reserved[4]; } __reserved_06; + +/*080*/ struct { /* Task Priority Register */ + u32 priority : 8, + __reserved_1 : 24; + u32 __reserved_2[3]; + } tpr; + +/*090*/ const + struct { /* Arbitration Priority Register */ + u32 priority : 8, + __reserved_1 : 24; + u32 __reserved_2[3]; + } apr; + +/*0A0*/ const + struct { /* Processor Priority Register */ + u32 priority : 8, + __reserved_1 : 24; + u32 __reserved_2[3]; + } ppr; + +/*0B0*/ struct { /* End Of Interrupt Register */ + u32 eoi; + u32 __reserved[3]; + } eoi; + +/*0C0*/ struct { u32 __reserved[4]; } __reserved_07; + +/*0D0*/ struct { /* Logical Destination Register */ + u32 __reserved_1 : 24, + logical_dest : 8; + u32 __reserved_2[3]; + } ldr; + +/*0E0*/ struct { /* Destination Format Register */ + u32 __reserved_1 : 28, + model : 4; + u32 __reserved_2[3]; + } dfr; + +/*0F0*/ struct { /* Spurious Interrupt Vector Register */ + u32 spurious_vector : 8, + apic_enabled : 1, + focus_cpu : 1, + __reserved_2 : 22; + u32 __reserved_3[3]; + } svr; + +/*100*/ struct { /* In Service Register */ +/*170*/ u32 bitfield; + u32 __reserved[3]; + } isr [8]; + +/*180*/ struct { /* Trigger Mode Register */ +/*1F0*/ u32 bitfield; + u32 __reserved[3]; + } tmr [8]; + +/*200*/ struct { /* Interrupt Request Register */ +/*270*/ u32 bitfield; + u32 __reserved[3]; + } irr [8]; + +/*280*/ union { /* Error Status Register */ + struct { + u32 send_cs_error : 1, + receive_cs_error : 1, + send_accept_error : 1, + receive_accept_error : 1, + __reserved_1 : 1, + send_illegal_vector : 1, + receive_illegal_vector : 1, + illegal_register_address : 1, + __reserved_2 : 24; + u32 __reserved_3[3]; + } error_bits; + struct { + u32 errors; + u32 __reserved_3[3]; + } all_errors; + } esr; + +/*290*/ struct { u32 __reserved[4]; } __reserved_08; + +/*2A0*/ struct { u32 __reserved[4]; } __reserved_09; + +/*2B0*/ struct { u32 __reserved[4]; } __reserved_10; + +/*2C0*/ struct { u32 __reserved[4]; } __reserved_11; + +/*2D0*/ struct { u32 __reserved[4]; } __reserved_12; + +/*2E0*/ struct { u32 __reserved[4]; } __reserved_13; + +/*2F0*/ struct { u32 __reserved[4]; } __reserved_14; + +/*300*/ struct { /* Interrupt Command Register 1 */ + u32 vector : 8, + delivery_mode : 3, + destination_mode : 1, + delivery_status : 1, + __reserved_1 : 1, + level : 1, + trigger : 1, + __reserved_2 : 2, + shorthand : 2, + __reserved_3 : 12; + u32 __reserved_4[3]; + } icr1; + +/*310*/ struct { /* Interrupt Command Register 2 */ + union { + u32 __reserved_1 : 24, + phys_dest : 4, + __reserved_2 : 4; + u32 __reserved_3 : 24, + logical_dest : 8; + } dest; + u32 __reserved_4[3]; + } icr2; + +/*320*/ struct { /* LVT - Timer */ + u32 vector : 8, + __reserved_1 : 4, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + timer_mode : 1, + __reserved_3 : 14; + u32 __reserved_4[3]; + } lvt_timer; + +/*330*/ struct { /* LVT - Thermal Sensor */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + __reserved_3 : 15; + u32 __reserved_4[3]; + } lvt_thermal; + +/*340*/ struct { /* LVT - Performance Counter */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + __reserved_3 : 15; + u32 __reserved_4[3]; + } lvt_pc; + +/*350*/ struct { /* LVT - LINT0 */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + polarity : 1, + remote_irr : 1, + trigger : 1, + mask : 1, + __reserved_2 : 15; + u32 __reserved_3[3]; + } lvt_lint0; + +/*360*/ struct { /* LVT - LINT1 */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + polarity : 1, + remote_irr : 1, + trigger : 1, + mask : 1, + __reserved_2 : 15; + u32 __reserved_3[3]; + } lvt_lint1; + +/*370*/ struct { /* LVT - Error */ + u32 vector : 8, + __reserved_1 : 4, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + __reserved_3 : 15; + u32 __reserved_4[3]; + } lvt_error; + +/*380*/ struct { /* Timer Initial Count Register */ + u32 initial_count; + u32 __reserved_2[3]; + } timer_icr; + +/*390*/ const + struct { /* Timer Current Count Register */ + u32 curr_count; + u32 __reserved_2[3]; + } timer_ccr; + +/*3A0*/ struct { u32 __reserved[4]; } __reserved_16; + +/*3B0*/ struct { u32 __reserved[4]; } __reserved_17; + +/*3C0*/ struct { u32 __reserved[4]; } __reserved_18; + +/*3D0*/ struct { u32 __reserved[4]; } __reserved_19; + +/*3E0*/ struct { /* Timer Divide Configuration Register */ + u32 divisor : 4, + __reserved_1 : 28; + u32 __reserved_2[3]; + } timer_dcr; + +/*3F0*/ struct { u32 __reserved[4]; } __reserved_20; + +} __attribute__ ((packed)); +#endif /* !__ASSEMBLY__ */ + +#undef u32 #endif diff --git a/xen/include/asm-x86/bitops.h b/xen/include/asm-x86/bitops.h index cf98f2e118..2337197670 100644 --- a/xen/include/asm-x86/bitops.h +++ b/xen/include/asm-x86/bitops.h @@ -368,6 +368,7 @@ static __inline__ unsigned long find_first_set_bit(unsigned long word) * The Hamming Weight of a number is the total number of bits set in it. */ +#define hweight64(x) generic_hweight64(x) #define hweight32(x) generic_hweight32(x) #define hweight16(x) generic_hweight16(x) #define hweight8(x) generic_hweight8(x) diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index fabe304155..1ddc8228db 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -69,6 +69,8 @@ extern unsigned long _end; /* standard ELF symbol */ #if defined(__x86_64__) +#define CONFIG_X86_64 1 + #define asmlinkage #define XENHEAP_DEFAULT_MB (16) @@ -179,6 +181,8 @@ extern unsigned long _end; /* standard ELF symbol */ #elif defined(__i386__) +#define CONFIG_X86_32 1 + #define asmlinkage __attribute__((regparm(0))) /* @@ -271,9 +275,9 @@ extern unsigned long _end; /* standard ELF symbol */ extern unsigned long xenheap_phys_end; /* user-configurable */ #endif -#define GDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + ((ed)->eid << PDPT_VCPU_VA_SHIFT)) +#define GDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + ((ed)->id << PDPT_VCPU_VA_SHIFT)) #define GDT_VIRT_END(ed) (GDT_VIRT_START(ed) + (64*1024)) -#define LDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + (64*1024) + ((ed)->eid << PDPT_VCPU_VA_SHIFT)) +#define LDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + (64*1024) + ((ed)->id << PDPT_VCPU_VA_SHIFT)) #define LDT_VIRT_END(ed) (LDT_VIRT_START(ed) + (64*1024)) #define PDPT_VCPU_SHIFT 5 diff --git a/xen/include/asm-x86/debugger.h b/xen/include/asm-x86/debugger.h index 0d6221a25e..6e9cf223d5 100644 --- a/xen/include/asm-x86/debugger.h +++ b/xen/include/asm-x86/debugger.h @@ -69,7 +69,7 @@ static inline int debugger_trap_entry( { case TRAP_int3: case TRAP_debug: - set_bit(EDF_CTRLPAUSE, &ed->ed_flags); + set_bit(EDF_CTRLPAUSE, &ed->flags); raise_softirq(SCHEDULE_SOFTIRQ); return 1; } diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 514ccdf0f1..683ba2ac0c 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -2,7 +2,9 @@ #ifndef __ASM_DOMAIN_H__ #define __ASM_DOMAIN_H__ +#include #include +#include struct trap_bounce { unsigned long error_code; diff --git a/xen/include/asm-x86/fixmap.h b/xen/include/asm-x86/fixmap.h index e123cb791a..c70b2a8b01 100644 --- a/xen/include/asm-x86/fixmap.h +++ b/xen/include/asm-x86/fixmap.h @@ -13,6 +13,7 @@ #define _ASM_FIXMAP_H #include +#include #include #include #include @@ -52,6 +53,15 @@ extern void __set_fixmap( #define set_fixmap_nocache(idx, phys) \ __set_fixmap(idx, phys, PAGE_HYPERVISOR_NOCACHE) -#define fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) +#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) +#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) + +#define fix_to_virt(x) (__fix_to_virt(x)) + +static inline unsigned long virt_to_fix(const unsigned long vaddr) +{ + BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); + return __virt_to_fix(vaddr); +} #endif diff --git a/xen/include/asm-x86/i387.h b/xen/include/asm-x86/i387.h index 9f6bb78b90..ca81778089 100644 --- a/xen/include/asm-x86/i387.h +++ b/xen/include/asm-x86/i387.h @@ -19,7 +19,7 @@ extern void save_init_fpu(struct exec_domain *tsk); extern void restore_fpu(struct exec_domain *tsk); #define unlazy_fpu(_tsk) do { \ - if ( test_bit(EDF_USEDFPU, &(_tsk)->ed_flags) ) \ + if ( test_bit(EDF_USEDFPU, &(_tsk)->flags) ) \ save_init_fpu(_tsk); \ } while ( 0 ) diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 1cc4e557a6..5e9448a847 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -2,7 +2,8 @@ #define __ASM_IO_APIC_H #include -#include +#include +#include #include /* @@ -13,42 +14,89 @@ #ifdef CONFIG_X86_IO_APIC -#define APIC_MISMATCH_DEBUG +#ifdef CONFIG_PCI_MSI +static inline int use_pci_vector(void) {return 1;} +static inline void disable_edge_ioapic_vector(unsigned int vector) { } +static inline void end_edge_ioapic_vector (unsigned int vector) { } +#define startup_level_ioapic startup_level_ioapic_vector +#define shutdown_level_ioapic mask_IO_APIC_vector +#define enable_level_ioapic unmask_IO_APIC_vector +#define disable_level_ioapic mask_IO_APIC_vector +#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector +#define end_level_ioapic end_level_ioapic_vector +#define set_ioapic_affinity set_ioapic_affinity_vector + +#define startup_edge_ioapic startup_edge_ioapic_vector +#define shutdown_edge_ioapic disable_edge_ioapic_vector +#define enable_edge_ioapic unmask_IO_APIC_vector +#define disable_edge_ioapic disable_edge_ioapic_vector +#define ack_edge_ioapic ack_edge_ioapic_vector +#define end_edge_ioapic end_edge_ioapic_vector +#else +static inline int use_pci_vector(void) {return 0;} +static inline void disable_edge_ioapic_irq(unsigned int irq) { } +static inline void end_edge_ioapic_irq (unsigned int irq) { } +#define startup_level_ioapic startup_level_ioapic_irq +#define shutdown_level_ioapic mask_IO_APIC_irq +#define enable_level_ioapic unmask_IO_APIC_irq +#define disable_level_ioapic mask_IO_APIC_irq +#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq +#define end_level_ioapic end_level_ioapic_irq +#define set_ioapic_affinity set_ioapic_affinity_irq + +#define startup_edge_ioapic startup_edge_ioapic_irq +#define shutdown_edge_ioapic disable_edge_ioapic_irq +#define enable_edge_ioapic unmask_IO_APIC_irq +#define disable_edge_ioapic disable_edge_ioapic_irq +#define ack_edge_ioapic ack_edge_ioapic_irq +#define end_edge_ioapic end_edge_ioapic_irq +#endif #define IO_APIC_BASE(idx) \ - ((volatile int *)(fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ + ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK))) /* * The structure of the IO-APIC: */ -struct IO_APIC_reg_00 { - __u32 __reserved_2 : 14, - LTS : 1, - delivery_type : 1, - __reserved_1 : 8, - ID : 4, - __reserved_0 : 4; -} __attribute__ ((packed)); +union IO_APIC_reg_00 { + u32 raw; + struct { + u32 __reserved_2 : 14, + LTS : 1, + delivery_type : 1, + __reserved_1 : 8, + ID : 8; + } __attribute__ ((packed)) bits; +}; -struct IO_APIC_reg_01 { - __u32 version : 8, - __reserved_2 : 7, - PRQ : 1, - entries : 8, - __reserved_1 : 8; -} __attribute__ ((packed)); +union IO_APIC_reg_01 { + u32 raw; + struct { + u32 version : 8, + __reserved_2 : 7, + PRQ : 1, + entries : 8, + __reserved_1 : 8; + } __attribute__ ((packed)) bits; +}; -struct IO_APIC_reg_02 { - __u32 __reserved_2 : 24, - arbitration : 4, - __reserved_1 : 4; -} __attribute__ ((packed)); +union IO_APIC_reg_02 { + u32 raw; + struct { + u32 __reserved_2 : 24, + arbitration : 4, + __reserved_1 : 4; + } __attribute__ ((packed)) bits; +}; -struct IO_APIC_reg_03 { - __u32 boot_DT : 1, - __reserved_1 : 31; -} __attribute__ ((packed)); +union IO_APIC_reg_03 { + u32 raw; + struct { + u32 boot_DT : 1, + __reserved_1 : 31; + } __attribute__ ((packed)) bits; +}; /* * # of IO-APICs and # of IRQ routing registers @@ -106,7 +154,7 @@ extern struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; extern int mp_irq_entries; /* MP IRQ source entries */ -extern struct mpc_config_intsrc *mp_irqs; +extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* non-0 if default (table-less) MP configuration */ extern int mpc_default_type; @@ -124,47 +172,41 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i } /* - * Synchronize the IO-APIC and the CPU by doing - * a dummy read from the IO-APIC + * Re-write a value: to be used for read-modify-write + * cycles where the read already set up the index register. + * + * Older SiS APIC requires we rewrite the index regiser */ -static inline void io_apic_sync(unsigned int apic) +#define sis_apic_bug 0 /* This may need propagating from domain0. */ +static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) { - (void) *(IO_APIC_BASE(apic)+4); + if (sis_apic_bug) + *IO_APIC_BASE(apic) = reg; + *(IO_APIC_BASE(apic)+4) = value; } +/* 1 if "noapic" boot option passed */ +extern int skip_ioapic_setup; + /* * If we use the IO-APIC for IRQ routing, disable automatic * assignment of PCI IRQ's. */ -#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup) +#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs) #ifdef CONFIG_ACPI_BOOT extern int io_apic_get_unique_id (int ioapic, int apic_id); extern int io_apic_get_version (int ioapic); extern int io_apic_get_redir_entries (int ioapic); extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low); +#endif /*CONFIG_ACPI_BOOT*/ + +extern int (*ioapic_renumber_irq)(int ioapic, int irq); + +#else /* !CONFIG_X86_IO_APIC */ +#define io_apic_assign_pci_irqs 0 #endif -extern int skip_ioapic_setup; /* 1 for "noapic" */ - -static inline void disable_ioapic_setup(void) -{ - skip_ioapic_setup = 1; -} - -static inline int ioapic_setup_disabled(void) -{ - return skip_ioapic_setup; -} - extern int assign_irq_vector(int irq); -#else /* !CONFIG_X86_IO_APIC */ -#define io_apic_assign_pci_irqs 0 - -static inline void disable_ioapic_setup(void) -{ } - -#endif /* !CONFIG_X86_IO_APIC */ - #endif diff --git a/xen/include/asm-x86/io_ports.h b/xen/include/asm-x86/io_ports.h deleted file mode 100644 index db490bd142..0000000000 --- a/xen/include/asm-x86/io_ports.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * based on linux-2.6.10/include/asm-i386/mach-default/io_ports.h - * - * Machine specific IO port address definition for generic. - * Written by Osamu Tomita - */ -#ifndef _MACH_IO_PORTS_H -#define _MACH_IO_PORTS_H - -/* i8253A PIT registers */ -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 -#define PIT_CH2 0x42 - -/* i8259A PIC registers */ -#define PIC_MASTER_CMD 0x20 -#define PIC_MASTER_IMR 0x21 -#define PIC_MASTER_ISR PIC_MASTER_CMD -#define PIC_MASTER_POLL PIC_MASTER_ISR -#define PIC_MASTER_OCW3 PIC_MASTER_ISR -#define PIC_SLAVE_CMD 0xa0 -#define PIC_SLAVE_IMR 0xa1 - -/* i8259A PIC related value */ -#define PIC_CASCADE_IR 2 -#define MASTER_ICW4_DEFAULT 0x01 -#define SLAVE_ICW4_DEFAULT 0x01 -#define PIC_ICW4_AEOI 2 - -#endif /* !_MACH_IO_PORTS_H */ diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index bc7ecfa317..1a38b524a6 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -6,59 +6,19 @@ #include #include #include +#include extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); -/* - * IDT vectors usable for external interrupt sources start - * at 0x20: - */ -#define FIRST_EXTERNAL_VECTOR 0x30 - -#define NR_IRQS (256 - FIRST_EXTERNAL_VECTOR) - -#define HYPERCALL_VECTOR 0x82 - -/* - * Vectors 0x30-0x3f are used for ISA interrupts. - */ - -/* - * Special IRQ vectors used by the SMP architecture, 0xf0-0xff - */ -#define SPURIOUS_APIC_VECTOR 0xff -#define ERROR_APIC_VECTOR 0xfe -#define INVALIDATE_TLB_VECTOR 0xfd -#define EVENT_CHECK_VECTOR 0xfc -#define CALL_FUNCTION_VECTOR 0xfb -#define KDB_VECTOR 0xfa - -/* - * Local APIC timer IRQ vector is on a different priority level, - * to work around the 'lost local interrupt if more than 2 IRQ - * sources per level' errata. - */ -#define LOCAL_TIMER_VECTOR 0xef - -/* - * First APIC vector available to drivers: (vectors 0x40-0xee) - * we start at 0x41 to spread out vectors evenly between priority - * levels. (0x82 is the hypercall vector) - */ -#define FIRST_DEVICE_VECTOR 0x41 -#define FIRST_SYSTEM_VECTOR 0xef - -extern int irq_vector[NR_IRQS]; +extern u8 irq_vector[NR_IRQ_VECTORS]; #define IO_APIC_VECTOR(irq) irq_vector[irq] +#define AUTO_ASSIGN -1 -/* - * Various low-level irq details needed by irq.c, process.c, - * time.c, io_apic.c and smp.c - * - * Interrupt entry/exit code at both C and assembly level - */ +extern void (*interrupt[NR_IRQS])(void); + +#define platform_legacy_irq(irq) ((irq) < 16) extern void mask_irq(unsigned int irq); extern void unmask_irq(unsigned int irq); diff --git a/xen/include/asm-x86/mach-default/apm.h b/xen/include/asm-x86/mach-default/apm.h new file mode 100644 index 0000000000..1f730b8bd1 --- /dev/null +++ b/xen/include/asm-x86/mach-default/apm.h @@ -0,0 +1,75 @@ +/* + * include/asm-i386/mach-default/apm.h + * + * Machine specific APM BIOS functions for generic. + * Split out from apm.c by Osamu Tomita + */ + +#ifndef _ASM_APM_H +#define _ASM_APM_H + +#ifdef APM_ZERO_SEGS +# define APM_DO_ZERO_SEGS \ + "pushl %%ds\n\t" \ + "pushl %%es\n\t" \ + "xorl %%edx, %%edx\n\t" \ + "mov %%dx, %%ds\n\t" \ + "mov %%dx, %%es\n\t" \ + "mov %%dx, %%fs\n\t" \ + "mov %%dx, %%gs\n\t" +# define APM_DO_POP_SEGS \ + "popl %%es\n\t" \ + "popl %%ds\n\t" +#else +# define APM_DO_ZERO_SEGS +# define APM_DO_POP_SEGS +#endif + +static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, + u32 *eax, u32 *ebx, u32 *ecx, + u32 *edx, u32 *esi) +{ + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall *%%cs:apm_bios_entry\n\t" + "setc %%al\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx), + "=S" (*esi) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); +} + +static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in, + u32 ecx_in, u32 *eax) +{ + int cx, dx, si; + u8 error; + + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall *%%cs:apm_bios_entry\n\t" + "setc %%bl\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx), + "=S" (si) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); + return error; +} + +#endif /* _ASM_APM_H */ diff --git a/xen/include/asm-x86/mach-default/bios_ebda.h b/xen/include/asm-x86/mach-default/bios_ebda.h new file mode 100644 index 0000000000..9cbd9a668a --- /dev/null +++ b/xen/include/asm-x86/mach-default/bios_ebda.h @@ -0,0 +1,15 @@ +#ifndef _MACH_BIOS_EBDA_H +#define _MACH_BIOS_EBDA_H + +/* + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E. + */ +static inline unsigned int get_bios_ebda(void) +{ + unsigned int address = *(unsigned short *)phys_to_virt(0x40E); + address <<= 4; + return address; /* 0 means none */ +} + +#endif /* _MACH_BIOS_EBDA_H */ diff --git a/xen/include/asm-x86/mach-default/do_timer.h b/xen/include/asm-x86/mach-default/do_timer.h new file mode 100644 index 0000000000..03dd13a48a --- /dev/null +++ b/xen/include/asm-x86/mach-default/do_timer.h @@ -0,0 +1,85 @@ +/* defines for inline arch setup functions */ + +#include + +/** + * do_timer_interrupt_hook - hook into timer tick + * @regs: standard registers from interrupt + * + * Description: + * This hook is called immediately after the timer interrupt is ack'd. + * It's primary purpose is to allow architectures that don't possess + * individual per CPU clocks (like the CPU APICs supply) to broadcast the + * timer interrupt as a means of triggering reschedules etc. + **/ + +static inline void do_timer_interrupt_hook(struct pt_regs *regs) +{ + do_timer(regs); +#ifndef CONFIG_SMP + update_process_times(user_mode(regs)); +#endif +/* + * In the SMP case we use the local APIC timer interrupt to do the + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. + */ +#ifndef CONFIG_X86_LOCAL_APIC + profile_tick(CPU_PROFILING, regs); +#else + if (!using_apic_timer) + smp_local_timer_interrupt(regs); +#endif +} + + +/* you can safely undefine this if you don't have the Neptune chipset */ + +#define BUGGY_NEPTUN_TIMER + +/** + * do_timer_overflow - process a detected timer overflow condition + * @count: hardware timer interrupt count on overflow + * + * Description: + * This call is invoked when the jiffies count has not incremented but + * the hardware timer interrupt has. It means that a timer tick interrupt + * came along while the previous one was pending, thus a tick was missed + **/ +static inline int do_timer_overflow(int count) +{ + int i; + + spin_lock(&i8259A_lock); + /* + * This is tricky when I/O APICs are used; + * see do_timer_interrupt(). + */ + i = inb(0x20); + spin_unlock(&i8259A_lock); + + /* assumption about timer being IRQ0 */ + if (i & 0x01) { + /* + * We cannot detect lost timer interrupts ... + * well, that's why we call them lost, don't we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { +#ifdef BUGGY_NEPTUN_TIMER + /* + * for the Neptun bug we know that the 'latch' + * command doesn't latch the high and low value + * of the counter atomically. Thus we have to + * substract 256 from the counter + * ... funny, isnt it? :) + */ + + count -= 256; +#else + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); +#endif + } + return count; +} diff --git a/xen/include/asm-x86/mach-default/entry_arch.h b/xen/include/asm-x86/mach-default/entry_arch.h new file mode 100644 index 0000000000..bc861469bd --- /dev/null +++ b/xen/include/asm-x86/mach-default/entry_arch.h @@ -0,0 +1,34 @@ +/* + * This file is designed to contain the BUILD_INTERRUPT specifications for + * all of the extra named interrupt vectors used by the architecture. + * Usually this is the Inter Process Interrupts (IPIs) + */ + +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +#ifdef CONFIG_X86_SMP +BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) +BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#endif + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +#ifdef CONFIG_X86_LOCAL_APIC +BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) + +#ifdef CONFIG_X86_MCE_P4THERMAL +BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) +#endif + +#endif diff --git a/xen/include/asm-x86/mach-default/io_ports.h b/xen/include/asm-x86/mach-default/io_ports.h new file mode 100644 index 0000000000..a96d9f6604 --- /dev/null +++ b/xen/include/asm-x86/mach-default/io_ports.h @@ -0,0 +1,30 @@ +/* + * arch/i386/mach-generic/io_ports.h + * + * Machine specific IO port address definition for generic. + * Written by Osamu Tomita + */ +#ifndef _MACH_IO_PORTS_H +#define _MACH_IO_PORTS_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 +#define PIT_CH2 0x42 + +/* i8259A PIC registers */ +#define PIC_MASTER_CMD 0x20 +#define PIC_MASTER_IMR 0x21 +#define PIC_MASTER_ISR PIC_MASTER_CMD +#define PIC_MASTER_POLL PIC_MASTER_ISR +#define PIC_MASTER_OCW3 PIC_MASTER_ISR +#define PIC_SLAVE_CMD 0xa0 +#define PIC_SLAVE_IMR 0xa1 + +/* i8259A PIC related value */ +#define PIC_CASCADE_IR 2 +#define MASTER_ICW4_DEFAULT 0x01 +#define SLAVE_ICW4_DEFAULT 0x01 +#define PIC_ICW4_AEOI 2 + +#endif /* !_MACH_IO_PORTS_H */ diff --git a/xen/include/asm-x86/mach-default/irq_vectors.h b/xen/include/asm-x86/mach-default/irq_vectors.h new file mode 100644 index 0000000000..de16b5bc9c --- /dev/null +++ b/xen/include/asm-x86/mach-default/irq_vectors.h @@ -0,0 +1,96 @@ +/* + * This file should contain #defines for all of the interrupt vector + * numbers used by this architecture. + * + * In addition, there are some standard defines: + * + * FIRST_EXTERNAL_VECTOR: + * The first free place for external interrupts + * + * SYSCALL_VECTOR: + * The IRQ vector a syscall makes the user to kernel transition + * under. + * + * TIMER_IRQ: + * The IRQ number the timer interrupt comes in at. + * + * NR_IRQS: + * The total number of interrupt vectors (including all the + * architecture specific interrupts) needed. + * + */ +#ifndef _ASM_IRQ_VECTORS_H +#define _ASM_IRQ_VECTORS_H + +/* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define HYPERCALL_VECTOR 0x82 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + * + * Vectors 0xf0-0xfa are free (reserved for future Linux use). + */ +#define SPURIOUS_APIC_VECTOR 0xff +#define ERROR_APIC_VECTOR 0xfe +#define INVALIDATE_TLB_VECTOR 0xfd +#define EVENT_CHECK_VECTOR 0xfc +#define CALL_FUNCTION_VECTOR 0xfb + +#define THERMAL_APIC_VECTOR 0xf0 +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xef + +/* + * First APIC vector available to drivers: (vectors 0x30-0xee) + * we start at 0x31 to spread out vectors evenly between priority + * levels. (0x80 is the syscall vector) + */ +#define FIRST_DEVICE_VECTOR 0x31 +#define FIRST_SYSTEM_VECTOR 0xef + +#define TIMER_IRQ 0 + +/* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. + * 256 vectors is an architectural limit. (we can have + * more than 256 devices theoretically, but they will + * have to use shared interrupts) + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ + +/* + * The maximum number of vectors supported by i386 processors + * is limited to 256. For processors other than i386, NR_VECTORS + * should be changed accordingly. + */ +#define NR_VECTORS 256 + +#include "irq_vectors_limits.h" + +#define FPU_IRQ 13 + +#define FIRST_VM86_IRQ 3 +#define LAST_VM86_IRQ 15 +#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15) + + +#endif /* _ASM_IRQ_VECTORS_H */ diff --git a/xen/include/asm-x86/mach-default/irq_vectors_limits.h b/xen/include/asm-x86/mach-default/irq_vectors_limits.h new file mode 100644 index 0000000000..b330026e6f --- /dev/null +++ b/xen/include/asm-x86/mach-default/irq_vectors_limits.h @@ -0,0 +1,21 @@ +#ifndef _ASM_IRQ_VECTORS_LIMITS_H +#define _ASM_IRQ_VECTORS_LIMITS_H + +#ifdef CONFIG_PCI_MSI +#define NR_IRQS FIRST_SYSTEM_VECTOR +#define NR_IRQ_VECTORS NR_IRQS +#else +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +# if (224 >= 32 * NR_CPUS) +# define NR_IRQ_VECTORS NR_IRQS +# else +# define NR_IRQ_VECTORS (32 * NR_CPUS) +# endif +#else +#define NR_IRQS 16 +#define NR_IRQ_VECTORS NR_IRQS +#endif +#endif + +#endif /* _ASM_IRQ_VECTORS_LIMITS_H */ diff --git a/xen/include/asm-x86/mach-default/mach_apic.h b/xen/include/asm-x86/mach-default/mach_apic.h new file mode 100644 index 0000000000..4bf3c5ae34 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_apic.h @@ -0,0 +1,133 @@ +#ifndef __ASM_MACH_APIC_H +#define __ASM_MACH_APIC_H + +#include +#include + +#define APIC_DFR_VALUE (APIC_DFR_FLAT) + +static inline cpumask_t target_cpus(void) +{ +#ifdef CONFIG_SMP + return cpu_online_map; +#else + return cpumask_of_cpu(0); +#endif +} +#define TARGET_CPUS (target_cpus()) + +#define NO_BALANCE_IRQ (0) +#define esr_disable (0) + +#define NO_IOAPIC_CHECK (0) + +#define INT_DELIVERY_MODE dest_LowestPrio +#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ + +static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) +{ + return physid_isset(apicid, bitmap); +} + +static inline unsigned long check_apicid_present(int bit) +{ + return physid_isset(bit, phys_cpu_present_map); +} + +/* + * Set up the logical destination ID. + * + * Intel recommends to set DFR, LDR and TPR before enabling + * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel + * document number 292116). So here it goes... + */ +static inline void init_apic_ldr(void) +{ + unsigned long val; + + apic_write_around(APIC_DFR, APIC_DFR_VALUE); + val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; + val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); + apic_write_around(APIC_LDR, val); +} + +static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map) +{ + return phys_map; +} + +static inline void clustered_apic_check(void) +{ + printk("Enabling APIC mode: %s. Using %d I/O APICs\n", + "Flat", nr_ioapics); +} + +static inline int multi_timer_check(int apic, int irq) +{ + return 0; +} + +static inline int apicid_to_node(int logical_apicid) +{ + return 0; +} + +/* Mapping from cpu number to logical apicid */ +static inline int cpu_to_logical_apicid(int cpu) +{ + return 1 << cpu; +} + +static inline int cpu_present_to_apicid(int mps_cpu) +{ + if (mps_cpu < get_physical_broadcast()) + return mps_cpu; + else + return BAD_APICID; +} + +static inline physid_mask_t apicid_to_cpu_present(int phys_apicid) +{ + return physid_mask_of_physid(phys_apicid); +} + +static inline int mpc_apic_id(struct mpc_config_processor *m, + struct mpc_config_translation *translation_record) +{ + printk("Processor #%d %d:%d APIC version %d\n", + m->mpc_apicid, + (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8, + (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, + m->mpc_apicver); + return (m->mpc_apicid); +} + +static inline void setup_portio_remap(void) +{ +} + +static inline int check_phys_apicid_present(int boot_cpu_physical_apicid) +{ + return physid_isset(boot_cpu_physical_apicid, phys_cpu_present_map); +} + +static inline int apic_id_registered(void) +{ + return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map); +} + +static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) +{ + return cpus_addr(cpumask)[0]; +} + +static inline void enable_apic_mode(void) +{ +} + +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return cpuid_apic >> index_msb; +} + +#endif /* __ASM_MACH_APIC_H */ diff --git a/xen/include/asm-x86/mach-default/mach_apicdef.h b/xen/include/asm-x86/mach-default/mach_apicdef.h new file mode 100644 index 0000000000..7bcb350c3e --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_apicdef.h @@ -0,0 +1,13 @@ +#ifndef __ASM_MACH_APICDEF_H +#define __ASM_MACH_APICDEF_H + +#define APIC_ID_MASK (0xF<<24) + +static inline unsigned get_apic_id(unsigned long x) +{ + return (((x)>>24)&0xF); +} + +#define GET_APIC_ID(x) get_apic_id(x) + +#endif diff --git a/xen/include/asm-x86/mach-default/mach_ipi.h b/xen/include/asm-x86/mach-default/mach_ipi.h new file mode 100644 index 0000000000..6f2b17a200 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_ipi.h @@ -0,0 +1,30 @@ +#ifndef __ASM_MACH_IPI_H +#define __ASM_MACH_IPI_H + +void send_IPI_mask_bitmask(cpumask_t mask, int vector); +void __send_IPI_shortcut(unsigned int shortcut, int vector); + +static inline void send_IPI_mask(cpumask_t mask, int vector) +{ + send_IPI_mask_bitmask(mask, vector); +} + +static inline void send_IPI_allbutself(int vector) +{ + /* + * if there are no other CPUs in the system then we get an APIC send + * error if we try to broadcast, thus avoid sending IPIs in this case. + */ + if (!(num_online_cpus() > 1)) + return; + + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); + return; +} + +static inline void send_IPI_all(int vector) +{ + __send_IPI_shortcut(APIC_DEST_ALLINC, vector); +} + +#endif /* __ASM_MACH_IPI_H */ diff --git a/xen/include/asm-x86/mach-default/mach_mpparse.h b/xen/include/asm-x86/mach-default/mach_mpparse.h new file mode 100644 index 0000000000..1d38324825 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_mpparse.h @@ -0,0 +1,28 @@ +#ifndef __ASM_MACH_MPPARSE_H +#define __ASM_MACH_MPPARSE_H + +static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, + struct mpc_config_translation *translation) +{ +// Dprintk("Bus #%d is %s\n", m->mpc_busid, name); +} + +static inline void mpc_oem_pci_bus(struct mpc_config_bus *m, + struct mpc_config_translation *translation) +{ +} + +static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, + char *productid) +{ + return 0; +} + +/* Hook from generic ACPI tables.c */ +static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + return 0; +} + + +#endif /* __ASM_MACH_MPPARSE_H */ diff --git a/xen/include/asm-x86/mach-default/mach_mpspec.h b/xen/include/asm-x86/mach-default/mach_mpspec.h new file mode 100644 index 0000000000..6b5dadcf1d --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_mpspec.h @@ -0,0 +1,8 @@ +#ifndef __ASM_MACH_MPSPEC_H +#define __ASM_MACH_MPSPEC_H + +#define MAX_IRQ_SOURCES 256 + +#define MAX_MP_BUSSES 32 + +#endif /* __ASM_MACH_MPSPEC_H */ diff --git a/xen/include/asm-x86/mach-default/mach_reboot.h b/xen/include/asm-x86/mach-default/mach_reboot.h new file mode 100644 index 0000000000..521e227db6 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_reboot.h @@ -0,0 +1,30 @@ +/* + * arch/i386/mach-generic/mach_reboot.h + * + * Machine specific reboot functions for generic. + * Split out from reboot.c by Osamu Tomita + */ +#ifndef _MACH_REBOOT_H +#define _MACH_REBOOT_H + +static inline void kb_wait(void) +{ + int i; + + for (i = 0; i < 0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +static inline void mach_reboot(void) +{ + int i; + for (i = 0; i < 100; i++) { + kb_wait(); + udelay(50); + outb(0xfe, 0x64); /* pulse reset low */ + udelay(50); + } +} + +#endif /* !_MACH_REBOOT_H */ diff --git a/xen/include/asm-x86/mach-default/mach_time.h b/xen/include/asm-x86/mach-default/mach_time.h new file mode 100644 index 0000000000..b749aa44a8 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_time.h @@ -0,0 +1,122 @@ +/* + * include/asm-i386/mach-default/mach_time.h + * + * Machine specific set RTC function for generic. + * Split out from time.c by Osamu Tomita + */ +#ifndef _MACH_TIME_H +#define _MACH_TIME_H + +#include + +/* for check timing call set_rtc_mmss() 500ms */ +/* used in arch/i386/time.c::do_timer_interrupt() */ +#define USEC_AFTER 500000 +#define USEC_BEFORE 500000 + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! + */ +static inline int mach_set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + +static inline unsigned long mach_get_cmos_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +#endif /* !_MACH_TIME_H */ diff --git a/xen/include/asm-x86/mach-default/mach_timer.h b/xen/include/asm-x86/mach-default/mach_timer.h new file mode 100644 index 0000000000..4b9703bb02 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_timer.h @@ -0,0 +1,48 @@ +/* + * include/asm-i386/mach-default/mach_timer.h + * + * Machine specific calibrate_tsc() for generic. + * Split out from timer_tsc.c by Osamu Tomita + */ +/* ------ Calibrate the TSC ------- + * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). + * Too much 64-bit arithmetic here to do this cleanly in C, and for + * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) + * output busy loop as low as possible. We avoid reading the CTC registers + * directly because of the awkward 8-bit access mechanism of the 82C54 + * device. + */ +#ifndef _MACH_TIMER_H +#define _MACH_TIMER_H + +#define CALIBRATE_LATCH (5 * LATCH) + +static inline void mach_prepare_counter(void) +{ + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + /* + * Now let's take care of CTC channel 2 + * + * Set the Gate high, program CTC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + * + * Some devices need a delay here. + */ + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ + outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ + outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ +} + +static inline void mach_countup(unsigned long *count_p) +{ + unsigned long count = 0; + do { + count++; + } while ((inb_p(0x61) & 0x20) == 0); + *count_p = count; +} + +#endif /* !_MACH_TIMER_H */ diff --git a/xen/include/asm-x86/mach-default/mach_traps.h b/xen/include/asm-x86/mach-default/mach_traps.h new file mode 100644 index 0000000000..c98c2880c5 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_traps.h @@ -0,0 +1,29 @@ +/* + * include/asm-i386/mach-default/mach_traps.h + * + * Machine specific NMI handling for generic. + * Split out from traps.c by Osamu Tomita + */ +#ifndef _MACH_TRAPS_H +#define _MACH_TRAPS_H + +static inline void clear_mem_error(unsigned char reason) +{ + reason = (reason & 0xf) | 4; + outb(reason, 0x61); +} + +static inline unsigned char get_nmi_reason(void) +{ + return inb(0x61); +} + +static inline void reassert_nmi(void) +{ + outb(0x8f, 0x70); + inb(0x71); /* dummy */ + outb(0x0f, 0x70); + inb(0x71); /* dummy */ +} + +#endif /* !_MACH_TRAPS_H */ diff --git a/xen/include/asm-x86/mach-default/mach_wakecpu.h b/xen/include/asm-x86/mach-default/mach_wakecpu.h new file mode 100644 index 0000000000..673b85c9b2 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_wakecpu.h @@ -0,0 +1,41 @@ +#ifndef __ASM_MACH_WAKECPU_H +#define __ASM_MACH_WAKECPU_H + +/* + * This file copes with machines that wakeup secondary CPUs by the + * INIT, INIT, STARTUP sequence. + */ + +#define WAKE_SECONDARY_VIA_INIT + +#define TRAMPOLINE_LOW phys_to_virt(0x467) +#define TRAMPOLINE_HIGH phys_to_virt(0x469) + +#define boot_cpu_apicid boot_cpu_physical_apicid + +static inline void wait_for_init_deassert(atomic_t *deassert) +{ + while (!atomic_read(deassert)); + return; +} + +/* Nothing to do for most platforms, since cleared by the INIT cycle */ +static inline void smp_callin_clear_local_apic(void) +{ +} + +static inline void store_NMI_vector(unsigned short *high, unsigned short *low) +{ +} + +static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) +{ +} + +#if APIC_DEBUG + #define inquire_remote_apic(apicid) __inquire_remote_apic(apicid) +#else + #define inquire_remote_apic(apicid) {} +#endif + +#endif /* __ASM_MACH_WAKECPU_H */ diff --git a/xen/include/asm-x86/mach-default/pci-functions.h b/xen/include/asm-x86/mach-default/pci-functions.h new file mode 100644 index 0000000000..ed0bab4273 --- /dev/null +++ b/xen/include/asm-x86/mach-default/pci-functions.h @@ -0,0 +1,19 @@ +/* + * PCI BIOS function numbering for conventional PCI BIOS + * systems + */ + +#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX +#define PCIBIOS_PCI_BIOS_PRESENT 0xb101 +#define PCIBIOS_FIND_PCI_DEVICE 0xb102 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103 +#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106 +#define PCIBIOS_READ_CONFIG_BYTE 0xb108 +#define PCIBIOS_READ_CONFIG_WORD 0xb109 +#define PCIBIOS_READ_CONFIG_DWORD 0xb10a +#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b +#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c +#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d +#define PCIBIOS_GET_ROUTING_OPTIONS 0xb10e +#define PCIBIOS_SET_PCI_HW_INT 0xb10f + diff --git a/xen/include/asm-x86/mach-default/setup_arch_post.h b/xen/include/asm-x86/mach-default/setup_arch_post.h new file mode 100644 index 0000000000..2fc4888721 --- /dev/null +++ b/xen/include/asm-x86/mach-default/setup_arch_post.h @@ -0,0 +1,40 @@ +/** + * machine_specific_memory_setup - Hook for machine specific memory setup. + * + * Description: + * This is included late in kernel/setup.c so that it can make + * use of all of the static functions. + **/ + +static char * __init machine_specific_memory_setup(void) +{ + char *who; + + + who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } + return who; +} diff --git a/xen/include/asm-x86/mach-default/setup_arch_pre.h b/xen/include/asm-x86/mach-default/setup_arch_pre.h new file mode 100644 index 0000000000..fb42099e7b --- /dev/null +++ b/xen/include/asm-x86/mach-default/setup_arch_pre.h @@ -0,0 +1,5 @@ +/* Hook to call BIOS initialisation function */ + +/* no action for generic */ + +#define ARCH_SETUP diff --git a/xen/include/asm-x86/mach-default/smpboot_hooks.h b/xen/include/asm-x86/mach-default/smpboot_hooks.h new file mode 100644 index 0000000000..7f45f63110 --- /dev/null +++ b/xen/include/asm-x86/mach-default/smpboot_hooks.h @@ -0,0 +1,44 @@ +/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws + * which needs to alter them. */ + +static inline void smpboot_clear_io_apic_irqs(void) +{ + io_apic_irqs = 0; +} + +static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) +{ + CMOS_WRITE(0xa, 0xf); + local_flush_tlb(); + Dprintk("1.\n"); + *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4; + Dprintk("2.\n"); + *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf; + Dprintk("3.\n"); +} + +static inline void smpboot_restore_warm_reset_vector(void) +{ + /* + * Install writable page 0 entry to set BIOS data area. + */ + local_flush_tlb(); + + /* + * Paranoid: Set warm reset code and vector here back + * to default values. + */ + CMOS_WRITE(0, 0xf); + + *((volatile long *) phys_to_virt(0x467)) = 0; +} + +static inline void smpboot_setup_io_apic(void) +{ + /* + * Here we can be sure that there is an IO-APIC in the system. Let's + * go and set it up: + */ + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +} diff --git a/xen/include/asm-x86/mach_apic.h b/xen/include/asm-x86/mach_apic.h deleted file mode 100644 index e93b0808d5..0000000000 --- a/xen/include/asm-x86/mach_apic.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * based on linux-2.6.10/include/asm-i386/mach-default/mach_apic.h - * - */ -#ifndef __ASM_MACH_APIC_H -#define __ASM_MACH_APIC_H - -#define APIC_DFR_VALUE (APIC_DFR_FLAT) -#define esr_disable (0) - -/* - * Set up the logical destination ID. - * - * Intel recommends to set DFR, LDR and TPR before enabling - * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel - * document number 292116). So here it goes... - */ -static inline void init_apic_ldr(void) -{ - unsigned long val; - - apic_write_around(APIC_DFR, APIC_DFR_VALUE); - val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; - val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); - apic_write_around(APIC_LDR, val); -} - -static inline int apic_id_registered(void) -{ - return test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map); -} -#endif /* __ASM_MACH_APIC_H */ diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 014fa7e45d..cf4e88bc6d 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -150,7 +150,7 @@ extern void invalidate_shadow_ldt(struct exec_domain *d); extern int shadow_remove_all_write_access( struct domain *d, unsigned long gpfn, unsigned long gmfn); extern u32 shadow_remove_all_access( struct domain *d, unsigned long gmfn); -extern int _shadow_mode_enabled(struct domain *d); +extern int _shadow_mode_refcounts(struct domain *d); static inline void put_page(struct pfn_info *page) { @@ -182,7 +182,7 @@ static inline int get_page(struct pfn_info *page, unlikely((nx & PGC_count_mask) == 0) || /* Count overflow? */ unlikely(d != _domain) ) /* Wrong owner? */ { - if ( !_shadow_mode_enabled(domain) ) + if ( !_shadow_mode_refcounts(domain) ) DPRINTK("Error pfn %lx: rd=%p, od=%p, caf=%08x, taf=%08x\n", page_to_pfn(page), domain, unpickle_domptr(d), x, page->u.inuse.type_info); @@ -315,14 +315,21 @@ int ptwr_init(struct domain *); void ptwr_destroy(struct domain *); void ptwr_flush(struct domain *, const int); int ptwr_do_page_fault(struct domain *, unsigned long); +int revalidate_l1(struct domain *, l1_pgentry_t *, l1_pgentry_t *); #define cleanup_writable_pagetable(_d) \ do { \ - if ( unlikely(VM_ASSIST((_d), VMASST_TYPE_writable_pagetables)) ) { \ - if ( (_d)->arch.ptwr[PTWR_PT_ACTIVE].l1va ) \ - ptwr_flush((_d), PTWR_PT_ACTIVE); \ - if ( (_d)->arch.ptwr[PTWR_PT_INACTIVE].l1va ) \ - ptwr_flush((_d), PTWR_PT_INACTIVE); \ + if ( likely(VM_ASSIST((_d), VMASST_TYPE_writable_pagetables)) ) \ + { \ + if ( likely(!shadow_mode_enabled(_d)) ) \ + { \ + if ( (_d)->arch.ptwr[PTWR_PT_ACTIVE].l1va ) \ + ptwr_flush((_d), PTWR_PT_ACTIVE); \ + if ( (_d)->arch.ptwr[PTWR_PT_INACTIVE].l1va ) \ + ptwr_flush((_d), PTWR_PT_INACTIVE); \ + } \ + else \ + shadow_sync_all(_d); \ } \ } while ( 0 ) @@ -330,9 +337,9 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy); #ifndef NDEBUG -#define AUDIT_ALREADY_LOCKED ( 1u << 0 ) -#define AUDIT_ERRORS_OK ( 1u << 1 ) -#define AUDIT_QUIET ( 1u << 2 ) +#define AUDIT_SHADOW_ALREADY_LOCKED ( 1u << 0 ) +#define AUDIT_ERRORS_OK ( 1u << 1 ) +#define AUDIT_QUIET ( 1u << 2 ) void _audit_domain(struct domain *d, int flags); #define audit_domain(_d) _audit_domain((_d), AUDIT_ERRORS_OK) diff --git a/xen/include/asm-x86/mpspec.h b/xen/include/asm-x86/mpspec.h index 1e73671c25..7add527173 100644 --- a/xen/include/asm-x86/mpspec.h +++ b/xen/include/asm-x86/mpspec.h @@ -1,242 +1,84 @@ #ifndef __ASM_MPSPEC_H #define __ASM_MPSPEC_H -#include -#include +#include +#include +#include -/* - * Structure definitions for SMP machines following the - * Intel Multiprocessing Specification 1.1 and 1.4. - */ - -/* - * This tag identifies where the SMP configuration - * information is. - */ - -#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') - -/* - * a maximum of 16 APICs with the current APIC ID architecture. - * xAPICs can have up to 256. SAPICs have 16 ID bits. - */ -#ifdef CONFIG_X86_CLUSTERED_APIC -#define MAX_APICS 256 -#else -#define MAX_APICS 16 -#endif - -#define MAX_MPC_ENTRY 1024 - -struct intel_mp_floating -{ - char mpf_signature[4]; /* "_MP_" */ - unsigned int mpf_physptr; /* Configuration table address */ - unsigned char mpf_length; /* Our length (paragraphs) */ - unsigned char mpf_specification;/* Specification version */ - unsigned char mpf_checksum; /* Checksum (makes sum 0) */ - unsigned char mpf_feature1; /* Standard or configuration ? */ - unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */ - unsigned char mpf_feature3; /* Unused (0) */ - unsigned char mpf_feature4; /* Unused (0) */ - unsigned char mpf_feature5; /* Unused (0) */ -}; - -struct mp_config_table -{ - char mpc_signature[4]; -#define MPC_SIGNATURE "PCMP" - unsigned short mpc_length; /* Size of table */ - char mpc_spec; /* 0x01 */ - char mpc_checksum; - char mpc_oem[8]; - char mpc_productid[12]; - unsigned int mpc_oemptr; /* 0 if not present */ - unsigned short mpc_oemsize; /* 0 if not present */ - unsigned short mpc_oemcount; - unsigned int mpc_lapic; /* APIC address */ - unsigned int reserved; -}; - -/* Followed by entries */ - -#define MP_PROCESSOR 0 -#define MP_BUS 1 -#define MP_IOAPIC 2 -#define MP_INTSRC 3 -#define MP_LINTSRC 4 -#define MP_TRANSLATION 192 /* Used by IBM NUMA-Q to describe node locality */ - -struct mpc_config_processor -{ - unsigned char mpc_type; - unsigned char mpc_apicid; /* Local APIC number */ - unsigned char mpc_apicver; /* Its versions */ - unsigned char mpc_cpuflag; -#define CPU_ENABLED 1 /* Processor is available */ -#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ - unsigned int mpc_cpufeature; -#define CPU_STEPPING_MASK 0x0F -#define CPU_MODEL_MASK 0xF0 -#define CPU_FAMILY_MASK 0xF00 - unsigned int mpc_featureflag; /* CPUID feature value */ - unsigned int mpc_reserved[2]; -}; - -struct mpc_config_bus -{ - unsigned char mpc_type; - unsigned char mpc_busid; - unsigned char mpc_bustype[6] __attribute((packed)); -}; - -/* List of Bus Type string values, Intel MP Spec. */ -#define BUSTYPE_EISA "EISA" -#define BUSTYPE_ISA "ISA" -#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ -#define BUSTYPE_MCA "MCA" -#define BUSTYPE_VL "VL" /* Local bus */ -#define BUSTYPE_PCI "PCI" -#define BUSTYPE_PCMCIA "PCMCIA" -#define BUSTYPE_CBUS "CBUS" -#define BUSTYPE_CBUSII "CBUSII" -#define BUSTYPE_FUTURE "FUTURE" -#define BUSTYPE_MBI "MBI" -#define BUSTYPE_MBII "MBII" -#define BUSTYPE_MPI "MPI" -#define BUSTYPE_MPSA "MPSA" -#define BUSTYPE_NUBUS "NUBUS" -#define BUSTYPE_TC "TC" -#define BUSTYPE_VME "VME" -#define BUSTYPE_XPRESS "XPRESS" - -struct mpc_config_ioapic -{ - unsigned char mpc_type; - unsigned char mpc_apicid; - unsigned char mpc_apicver; - unsigned char mpc_flags; -#define MPC_APIC_USABLE 0x01 - unsigned int mpc_apicaddr; -}; - -struct mpc_config_intsrc -{ - unsigned char mpc_type; - unsigned char mpc_irqtype; - unsigned short mpc_irqflag; - unsigned char mpc_srcbus; - unsigned char mpc_srcbusirq; - unsigned char mpc_dstapic; - unsigned char mpc_dstirq; -}; - -enum mp_irq_source_types { - mp_INT = 0, - mp_NMI = 1, - mp_SMI = 2, - mp_ExtINT = 3 -}; - -#define MP_IRQDIR_DEFAULT 0 -#define MP_IRQDIR_HIGH 1 -#define MP_IRQDIR_LOW 3 - - -struct mpc_config_lintsrc -{ - unsigned char mpc_type; - unsigned char mpc_irqtype; - unsigned short mpc_irqflag; - unsigned char mpc_srcbusid; - unsigned char mpc_srcbusirq; - unsigned char mpc_destapic; -#define MP_APIC_ALL 0xFF - unsigned char mpc_destapiclint; -}; - -struct mp_config_oemtable -{ - char oem_signature[4]; -#define MPC_OEM_SIGNATURE "_OEM" - unsigned short oem_length; /* Size of table */ - char oem_rev; /* 0x01 */ - char oem_checksum; - char mpc_oem[8]; -}; - -struct mpc_config_translation -{ - unsigned char mpc_type; - unsigned char trans_len; - unsigned char trans_type; - unsigned char trans_quad; - unsigned char trans_global; - unsigned char trans_local; - unsigned short trans_reserved; -}; - -/* - * Default configurations - * - * 1 2 CPU ISA 82489DX - * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining - * 3 2 CPU EISA 82489DX - * 4 2 CPU MCA 82489DX - * 5 2 CPU ISA+PCI - * 6 2 CPU EISA+PCI - * 7 2 CPU MCA+PCI - */ - -#ifdef CONFIG_MULTIQUAD -#define MAX_IRQ_SOURCES 512 -#else /* !CONFIG_MULTIQUAD */ -#define MAX_IRQ_SOURCES 256 -#endif /* CONFIG_MULTIQUAD */ - -#define MAX_MP_BUSSES 32 -enum mp_bustype { - MP_BUS_ISA = 1, - MP_BUS_EISA, - MP_BUS_PCI, - MP_BUS_MCA -}; -extern int *mp_bus_id_to_type; -extern int *mp_bus_id_to_node; -extern int *mp_bus_id_to_local; -extern int *mp_bus_id_to_pci_bus; +extern int mp_bus_id_to_type [MAX_MP_BUSSES]; +extern int mp_bus_id_to_node [MAX_MP_BUSSES]; +extern int mp_bus_id_to_local [MAX_MP_BUSSES]; extern int quad_local_to_mp_bus_id [NR_CPUS/4][4]; +extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; extern unsigned int boot_cpu_physical_apicid; -/*extern unsigned long phys_cpu_present_map;*/ extern int smp_found_config; extern void find_smp_config (void); extern void get_smp_config (void); -/*extern int nr_ioapics;*/ +extern int nr_ioapics; extern int apic_version [MAX_APICS]; -/*extern int mp_irq_entries;*/ -/*extern struct mpc_config_intsrc *mp_irqs;*/ -/*extern int mpc_default_type;*/ +extern int mp_bus_id_to_type [MAX_MP_BUSSES]; +extern int mp_irq_entries; +extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; +extern int mpc_default_type; +extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; extern int mp_current_pci_id; extern unsigned long mp_lapic_addr; -/*extern int pic_mode;*/ +extern int pic_mode; extern int using_apic_timer; #ifdef CONFIG_ACPI_BOOT extern void mp_register_lapic (u8 id, u8 enabled); extern void mp_register_lapic_address (u64 address); - -#ifdef CONFIG_X86_IO_APIC -extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base); -extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq); +extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base); +extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi); extern void mp_config_acpi_legacy_irqs (void); -extern void mp_config_ioapic_for_sci(int irq); -extern void mp_parse_prt (void); -#else /*!CONFIG_X86_IO_APIC*/ -static inline void mp_config_ioapic_for_sci(int irq) { } -#endif /*!CONFIG_X86_IO_APIC*/ - +extern int mp_register_gsi (u32 gsi, int edge_level, int active_high_low); #endif /*CONFIG_ACPI_BOOT*/ +#define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS) + +struct physid_mask +{ + unsigned long mask[PHYSID_ARRAY_SIZE]; +}; + +typedef struct physid_mask physid_mask_t; + +#define physid_set(physid, map) set_bit(physid, (map).mask) +#define physid_clear(physid, map) clear_bit(physid, (map).mask) +#define physid_isset(physid, map) test_bit(physid, (map).mask) +#define physid_test_and_set(physid, map) test_and_set_bit(physid, (map).mask) + +#define physids_and(dst, src1, src2) bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_APICS) +#define physids_or(dst, src1, src2) bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_APICS) +#define physids_clear(map) bitmap_zero((map).mask, MAX_APICS) +#define physids_complement(dst, src) bitmap_complement((dst).mask,(src).mask, MAX_APICS) +#define physids_empty(map) bitmap_empty((map).mask, MAX_APICS) +#define physids_equal(map1, map2) bitmap_equal((map1).mask, (map2).mask, MAX_APICS) +#define physids_weight(map) bitmap_weight((map).mask, MAX_APICS) +#define physids_shift_right(d, s, n) bitmap_shift_right((d).mask, (s).mask, n, MAX_APICS) +#define physids_shift_left(d, s, n) bitmap_shift_left((d).mask, (s).mask, n, MAX_APICS) +#define physids_coerce(map) ((map).mask[0]) + +#define physids_promote(physids) \ + ({ \ + physid_mask_t __physid_mask = PHYSID_MASK_NONE; \ + __physid_mask.mask[0] = physids; \ + __physid_mask; \ + }) + +#define physid_mask_of_physid(physid) \ + ({ \ + physid_mask_t __physid_mask = PHYSID_MASK_NONE; \ + physid_set(physid, __physid_mask); \ + __physid_mask; \ + }) + +#define PHYSID_MASK_ALL { {[0 ... PHYSID_ARRAY_SIZE-1] = ~0UL} } +#define PHYSID_MASK_NONE { {[0 ... PHYSID_ARRAY_SIZE-1] = 0UL} } + +extern physid_mask_t phys_cpu_present_map; + #endif diff --git a/xen/include/asm-x86/mpspec_def.h b/xen/include/asm-x86/mpspec_def.h new file mode 100644 index 0000000000..902c030f7f --- /dev/null +++ b/xen/include/asm-x86/mpspec_def.h @@ -0,0 +1,188 @@ +#ifndef __ASM_MPSPEC_DEF_H +#define __ASM_MPSPEC_DEF_H + +/* + * Structure definitions for SMP machines following the + * Intel Multiprocessing Specification 1.1 and 1.4. + */ + +/* + * This tag identifies where the SMP configuration + * information is. + */ + +#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') + +#define MAX_MPC_ENTRY 1024 +#define MAX_APICS 256 + +struct intel_mp_floating +{ + char mpf_signature[4]; /* "_MP_" */ + unsigned int mpf_physptr; /* Configuration table address */ + unsigned char mpf_length; /* Our length (paragraphs) */ + unsigned char mpf_specification;/* Specification version */ + unsigned char mpf_checksum; /* Checksum (makes sum 0) */ + unsigned char mpf_feature1; /* Standard or configuration ? */ + unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */ + unsigned char mpf_feature3; /* Unused (0) */ + unsigned char mpf_feature4; /* Unused (0) */ + unsigned char mpf_feature5; /* Unused (0) */ +}; + +struct mp_config_table +{ + char mpc_signature[4]; +#define MPC_SIGNATURE "PCMP" + unsigned short mpc_length; /* Size of table */ + char mpc_spec; /* 0x01 */ + char mpc_checksum; + char mpc_oem[8]; + char mpc_productid[12]; + unsigned int mpc_oemptr; /* 0 if not present */ + unsigned short mpc_oemsize; /* 0 if not present */ + unsigned short mpc_oemcount; + unsigned int mpc_lapic; /* APIC address */ + unsigned int reserved; +}; + +/* Followed by entries */ + +#define MP_PROCESSOR 0 +#define MP_BUS 1 +#define MP_IOAPIC 2 +#define MP_INTSRC 3 +#define MP_LINTSRC 4 +#define MP_TRANSLATION 192 /* Used by IBM NUMA-Q to describe node locality */ + +struct mpc_config_processor +{ + unsigned char mpc_type; + unsigned char mpc_apicid; /* Local APIC number */ + unsigned char mpc_apicver; /* Its versions */ + unsigned char mpc_cpuflag; +#define CPU_ENABLED 1 /* Processor is available */ +#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ + unsigned int mpc_cpufeature; +#define CPU_STEPPING_MASK 0x0F +#define CPU_MODEL_MASK 0xF0 +#define CPU_FAMILY_MASK 0xF00 + unsigned int mpc_featureflag; /* CPUID feature value */ + unsigned int mpc_reserved[2]; +}; + +struct mpc_config_bus +{ + unsigned char mpc_type; + unsigned char mpc_busid; + unsigned char mpc_bustype[6] __attribute((packed)); +}; + +/* List of Bus Type string values, Intel MP Spec. */ +#define BUSTYPE_EISA "EISA" +#define BUSTYPE_ISA "ISA" +#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ +#define BUSTYPE_MCA "MCA" +#define BUSTYPE_VL "VL" /* Local bus */ +#define BUSTYPE_PCI "PCI" +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_CBUS "CBUS" +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_MBI "MBI" +#define BUSTYPE_MBII "MBII" +#define BUSTYPE_MPI "MPI" +#define BUSTYPE_MPSA "MPSA" +#define BUSTYPE_NUBUS "NUBUS" +#define BUSTYPE_TC "TC" +#define BUSTYPE_VME "VME" +#define BUSTYPE_XPRESS "XPRESS" +#define BUSTYPE_NEC98 "NEC98" + +struct mpc_config_ioapic +{ + unsigned char mpc_type; + unsigned char mpc_apicid; + unsigned char mpc_apicver; + unsigned char mpc_flags; +#define MPC_APIC_USABLE 0x01 + unsigned int mpc_apicaddr; +}; + +struct mpc_config_intsrc +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbus; + unsigned char mpc_srcbusirq; + unsigned char mpc_dstapic; + unsigned char mpc_dstirq; +}; + +enum mp_irq_source_types { + mp_INT = 0, + mp_NMI = 1, + mp_SMI = 2, + mp_ExtINT = 3 +}; + +#define MP_IRQDIR_DEFAULT 0 +#define MP_IRQDIR_HIGH 1 +#define MP_IRQDIR_LOW 3 + + +struct mpc_config_lintsrc +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbusid; + unsigned char mpc_srcbusirq; + unsigned char mpc_destapic; +#define MP_APIC_ALL 0xFF + unsigned char mpc_destapiclint; +}; + +struct mp_config_oemtable +{ + char oem_signature[4]; +#define MPC_OEM_SIGNATURE "_OEM" + unsigned short oem_length; /* Size of table */ + char oem_rev; /* 0x01 */ + char oem_checksum; + char mpc_oem[8]; +}; + +struct mpc_config_translation +{ + unsigned char mpc_type; + unsigned char trans_len; + unsigned char trans_type; + unsigned char trans_quad; + unsigned char trans_global; + unsigned char trans_local; + unsigned short trans_reserved; +}; + +/* + * Default configurations + * + * 1 2 CPU ISA 82489DX + * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining + * 3 2 CPU EISA 82489DX + * 4 2 CPU MCA 82489DX + * 5 2 CPU ISA+PCI + * 6 2 CPU EISA+PCI + * 7 2 CPU MCA+PCI + */ + +enum mp_bustype { + MP_BUS_ISA = 1, + MP_BUS_EISA, + MP_BUS_PCI, + MP_BUS_MCA, + MP_BUS_NEC98 +}; +#endif + diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h index a925f90fc8..64b0635ce6 100644 --- a/xen/include/asm-x86/page.h +++ b/xen/include/asm-x86/page.h @@ -23,6 +23,7 @@ #ifndef __ASSEMBLY__ typedef struct { unsigned long pt_lo; } pagetable_t; #define pagetable_val(_x) ((_x).pt_lo) +#define pagetable_get_pfn(_x) ((_x).pt_lo >> PAGE_SHIFT) #define mk_pagetable(_x) ( (pagetable_t) { (_x) } ) #endif @@ -103,6 +104,7 @@ extern void paging_init(void); #define _PAGE_PAT 0x080UL #define _PAGE_PSE 0x080UL #define _PAGE_GLOBAL 0x100UL +#define _PAGE_AVAIL 0xe00UL #define __PAGE_HYPERVISOR \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) @@ -129,8 +131,6 @@ static __inline__ int get_order(unsigned long size) return order; } -extern void zap_low_mappings(void); - /* Map physical byte range (@p, @p+@s) at virt address @v in pagetable @pt. */ extern int map_pages( diff --git a/xen/include/asm-x86/pci.h b/xen/include/asm-x86/pci.h deleted file mode 100644 index c5f72c0fae..0000000000 --- a/xen/include/asm-x86/pci.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __X86_PCI_H -#define __X86_PCI_H - -#include - -/* Can be used to override the logic in pci_scan_bus for skipping - already-configured bus numbers - to be used for buggy BIOSes - or architectures with incomplete PCI setup by the loader */ - -#ifdef CONFIG_PCI -extern unsigned int pcibios_assign_all_busses(void); -#else -#define pcibios_assign_all_busses() 0 -#endif -#define pcibios_scan_all_fns(a,b) 0 - -extern unsigned long pci_mem_start; -#define PCIBIOS_MIN_IO 0x1000 -#define PCIBIOS_MIN_MEM (pci_mem_start) - -void pcibios_config_init(void); -struct pci_bus * pcibios_scan_root(int bus); -extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); -extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); - -void pcibios_set_master(struct pci_dev *dev); -void pcibios_penalize_isa_irq(int irq); -struct irq_routing_table *pcibios_get_irq_routing_table(void); -int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); - -#include -#include -#include - -#endif /* __X86_PCI_H */ diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index d31b9769b9..8cd4755cba 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -5,16 +5,13 @@ #define __ASM_X86_PROCESSOR_H #ifndef __ASSEMBLY__ -#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include #endif /* @@ -166,7 +163,7 @@ struct cpuinfo_x86 { int x86_cache_size; /* in KB - for CPUS that support this call */ int x86_clflush_size; int x86_tlbsize; /* number of 4K pages in DTLB/ITLB combined */ -} __attribute__((__aligned__(SMP_CACHE_BYTES))); +} __cacheline_aligned; /* * capabilities of CPUs @@ -369,7 +366,7 @@ struct tss_struct { u16 bitmap; /* Pads the TSS to be cacheline-aligned (total size is 0x80). */ u8 __cacheline_filler[24]; -} __cacheline_aligned PACKED; +} __cacheline_aligned __attribute__((packed)); #define IDT_ENTRIES 256 extern idt_entry_t idt_table[]; diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index d52708ac1e..202453194f 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -33,11 +34,17 @@ /* Shadow PT operation mode : shadow-mode variable in arch_domain. */ #define SHM_enable (1<<0) /* we're in one of the shadow modes */ -#define SHM_log_dirty (1<<1) /* enable log dirty mode */ -#define SHM_translate (1<<2) /* do p2m tranaltion on guest tables */ -#define SHM_external (1<<3) /* external page table, not used by Xen */ +#define SHM_refcounts (1<<1) /* refcounts based on shadow tables instead of + guest tables */ +#define SHM_write_all (1<<2) /* allow write access to all guest pt pages, + regardless of pte write permissions */ +#define SHM_log_dirty (1<<3) /* enable log dirty mode */ +#define SHM_translate (1<<4) /* do p2m tranaltion on guest tables */ +#define SHM_external (1<<5) /* external page table, not used by Xen */ #define shadow_mode_enabled(_d) ((_d)->arch.shadow_mode) +#define shadow_mode_refcounts(_d) ((_d)->arch.shadow_mode & SHM_refcounts) +#define shadow_mode_write_all(_d) ((_d)->arch.shadow_mode & SHM_write_all) #define shadow_mode_log_dirty(_d) ((_d)->arch.shadow_mode & SHM_log_dirty) #define shadow_mode_translate(_d) ((_d)->arch.shadow_mode & SHM_translate) #define shadow_mode_external(_d) ((_d)->arch.shadow_mode & SHM_external) @@ -72,7 +79,29 @@ extern void free_monitor_pagetable(struct exec_domain *ed); extern void __shadow_sync_all(struct domain *d); extern int __shadow_out_of_sync(struct exec_domain *ed, unsigned long va); extern int set_p2m_entry( - struct domain *d, unsigned long pfn, unsigned long mfn); + struct domain *d, unsigned long pfn, unsigned long mfn, + struct map_dom_mem_cache *l2cache, + struct map_dom_mem_cache *l1cache); +extern void remove_shadow(struct domain *d, unsigned long gpfn, u32 stype); + +extern void shadow_l1_normal_pt_update(struct domain *d, + unsigned long pa, l1_pgentry_t l1e, + struct map_dom_mem_cache *cache); +extern void shadow_l2_normal_pt_update(struct domain *d, + unsigned long pa, l2_pgentry_t l2e, + struct map_dom_mem_cache *cache); +#ifdef __x86_64__ +extern void shadow_l3_normal_pt_update(struct domain *d, + unsigned long pa, l3_pgentry_t l3e, + struct map_dom_mem_cache *cache); +extern void shadow_l4_normal_pt_update(struct domain *d, + unsigned long pa, l4_pgentry_t l4e, + struct map_dom_mem_cache *cache); +#endif +extern int shadow_do_update_va_mapping(unsigned long va, + l1_pgentry_t val, + struct exec_domain *ed); + static inline unsigned long __shadow_status( struct domain *d, unsigned long gpfn, unsigned long stype); @@ -82,7 +111,13 @@ extern void vmx_shadow_clear_state(struct domain *); static inline int page_is_page_table(struct pfn_info *page) { - return page->count_info & PGC_page_table; + struct domain *owner = page_get_owner(page); + + if ( owner && shadow_mode_refcounts(owner) ) + return page->count_info & PGC_page_table; + + u32 type_info = page->u.inuse.type_info & PGT_type_mask; + return type_info && (type_info <= PGT_l4_page_table); } static inline int mfn_is_page_table(unsigned long mfn) @@ -90,7 +125,7 @@ static inline int mfn_is_page_table(unsigned long mfn) if ( !pfn_valid(mfn) ) return 0; - return frame_table[mfn].count_info & PGC_page_table; + return page_is_page_table(pfn_to_page(mfn)); } static inline int page_out_of_sync(struct pfn_info *page) @@ -103,7 +138,7 @@ static inline int mfn_out_of_sync(unsigned long mfn) if ( !pfn_valid(mfn) ) return 0; - return frame_table[mfn].count_info & PGC_out_of_sync; + return page_out_of_sync(pfn_to_page(mfn)); } @@ -191,10 +226,12 @@ static inline void shadow_mode_disable(struct domain *d) : (mfn) ) #define __gpfn_to_mfn(_d, gpfn) \ - ( (shadow_mode_translate(_d)) \ - ? ({ ASSERT(current->domain == (_d)); \ - phys_to_machine_mapping(gpfn); }) \ - : (gpfn) ) + ({ \ + ASSERT(current->domain == (_d)); \ + (shadow_mode_translate(_d)) \ + ? phys_to_machine_mapping(gpfn) \ + : (gpfn); \ + }) #define __gpfn_to_mfn_foreign(_d, gpfn) \ ( (shadow_mode_translate(_d)) \ @@ -237,6 +274,8 @@ struct out_of_sync_entry { #if SHADOW_DEBUG extern int shadow_status_noswap; +#define _SHADOW_REFLECTS_SNAPSHOT ( 9) +#define SHADOW_REFLECTS_SNAPSHOT (1u << _SHADOW_REFLECTS_SNAPSHOT) #endif #ifdef VERBOSE @@ -292,15 +331,18 @@ shadow_get_page_from_l1e(l1_pgentry_t l1e, struct domain *d) ASSERT(l1e_get_flags(l1e) & _PAGE_PRESENT); + if ( !shadow_mode_refcounts(d) ) + return 1; + nl1e = l1e; l1e_remove_flags(&nl1e, _PAGE_GLOBAL); res = get_page_from_l1e(nl1e, d); if ( unlikely(!res) && IS_PRIV(d) && !shadow_mode_translate(d) && - !(l1e_get_flags(l1e) & L1_DISALLOW_MASK) && - (mfn = l1e_get_pfn(l1e)) && + !(l1e_get_flags(nl1e) & L1_DISALLOW_MASK) && + (mfn = l1e_get_pfn(nl1e)) && pfn_valid(mfn) && - (owner = page_get_owner(pfn_to_page(l1e_get_pfn(l1e)))) && + (owner = page_get_owner(pfn_to_page(mfn))) && (d != owner) ) { res = get_page_from_l1e(nl1e, owner); @@ -319,6 +361,103 @@ shadow_get_page_from_l1e(l1_pgentry_t l1e, struct domain *d) return res; } +static inline void +shadow_put_page_from_l1e(l1_pgentry_t l1e, struct domain *d) +{ + if ( !shadow_mode_refcounts(d) ) + return; + + put_page_from_l1e(l1e, d); +} + +static inline void +shadow_put_page_type(struct domain *d, struct pfn_info *page) +{ + if ( !shadow_mode_refcounts(d) ) + return; + + put_page_type(page); +} + +static inline int shadow_get_page(struct domain *d, + struct pfn_info *page, + struct domain *owner) +{ + if ( !shadow_mode_refcounts(d) ) + return 1; + return get_page(page, owner); +} + +static inline void shadow_put_page(struct domain *d, + struct pfn_info *page) +{ + if ( !shadow_mode_refcounts(d) ) + return; + put_page(page); +} + +/************************************************************************/ + +static inline int __mark_dirty(struct domain *d, unsigned int mfn) +{ + unsigned long pfn; + int rc = 0; + + ASSERT(spin_is_locked(&d->arch.shadow_lock)); + ASSERT(d->arch.shadow_dirty_bitmap != NULL); + + if ( !VALID_MFN(mfn) ) + return rc; + + // N.B. This doesn't use __mfn_to_gpfn(). + // This wants the nice compact set of PFNs from 0..domain's max, + // which __mfn_to_gpfn() only returns for translated domains. + // + pfn = machine_to_phys_mapping[mfn]; + + /* + * Values with the MSB set denote MFNs that aren't really part of the + * domain's pseudo-physical memory map (e.g., the shared info frame). + * Nothing to do here... + */ + if ( unlikely(IS_INVALID_M2P_ENTRY(pfn)) ) + return rc; + + if ( likely(pfn < d->arch.shadow_dirty_bitmap_size) ) + { + /* N.B. Can use non-atomic TAS because protected by shadow_lock. */ + if ( !__test_and_set_bit(pfn, d->arch.shadow_dirty_bitmap) ) + { + d->arch.shadow_dirty_count++; + rc = 1; + } + } +#ifndef NDEBUG + else if ( mfn < max_page ) + { + SH_LOG("mark_dirty OOR! mfn=%x pfn=%lx max=%x (dom %p)", + mfn, pfn, d->arch.shadow_dirty_bitmap_size, d); + SH_LOG("dom=%p caf=%08x taf=%08x", + page_get_owner(&frame_table[mfn]), + frame_table[mfn].count_info, + frame_table[mfn].u.inuse.type_info ); + } +#endif + + return rc; +} + + +static inline int mark_dirty(struct domain *d, unsigned int mfn) +{ + int rc; + shadow_lock(d); + rc = __mark_dirty(d, mfn); + shadow_unlock(d); + return rc; +} + + /************************************************************************/ static inline void @@ -350,10 +489,15 @@ static inline void __guest_set_l2e( struct exec_domain *ed, unsigned long va, l2_pgentry_t value) { + struct domain *d = ed->domain; + ed->arch.guest_vtable[l2_table_offset(va)] = value; - if ( unlikely(shadow_mode_translate(ed->domain)) ) + if ( unlikely(shadow_mode_translate(d)) ) update_hl2e(ed, va); + + if ( unlikely(shadow_mode_log_dirty(d)) ) + __mark_dirty(d, pagetable_get_pfn(ed->arch.guest_table)); } static inline void @@ -375,33 +519,35 @@ update_hl2e(struct exec_domain *ed, unsigned long va) else new_hl2e = l1e_empty(); - // only do the ref counting if something important changed. + // only do the ref counting if something has changed. // - if ( (l1e_has_changed(&old_hl2e, &new_hl2e, _PAGE_PRESENT)) ) + if ( (l1e_has_changed(&old_hl2e, &new_hl2e, PAGE_FLAG_MASK)) ) { if ( (l1e_get_flags(new_hl2e) & _PAGE_PRESENT) && - !get_page(pfn_to_page(l1e_get_pfn(new_hl2e)), ed->domain) ) + !shadow_get_page(ed->domain, pfn_to_page(l1e_get_pfn(new_hl2e)), + ed->domain) ) new_hl2e = l1e_empty(); if ( l1e_get_flags(old_hl2e) & _PAGE_PRESENT ) { - put_page(pfn_to_page(l1e_get_pfn(old_hl2e))); + shadow_put_page(ed->domain, pfn_to_page(l1e_get_pfn(old_hl2e))); need_flush = 1; } - } - ed->arch.hl2_vtable[l2_table_offset(va)] = new_hl2e; + ed->arch.hl2_vtable[l2_table_offset(va)] = new_hl2e; - if ( need_flush ) - { - perfc_incrc(update_hl2e_invlpg); - local_flush_tlb_one(&linear_pg_table[l1_linear_offset(va)]); + if ( need_flush ) + { + perfc_incrc(update_hl2e_invlpg); + // SMP BUG??? + local_flush_tlb_one(&linear_pg_table[l1_linear_offset(va)]); + } } } static inline void shadow_drop_references( struct domain *d, struct pfn_info *page) { - if ( likely(!shadow_mode_enabled(d)) || + if ( likely(!shadow_mode_refcounts(d)) || ((page->u.inuse.type_info & PGT_count_mask) == 0) ) return; @@ -423,7 +569,7 @@ static inline void shadow_drop_references( static inline void shadow_sync_and_drop_references( struct domain *d, struct pfn_info *page) { - if ( likely(!shadow_mode_enabled(d)) ) + if ( likely(!shadow_mode_refcounts(d)) ) return; shadow_lock(d); @@ -520,64 +666,6 @@ shadow_unpin(unsigned long smfn) } -/************************************************************************/ - -static inline int __mark_dirty(struct domain *d, unsigned int mfn) -{ - unsigned long pfn; - int rc = 0; - - ASSERT(spin_is_locked(&d->arch.shadow_lock)); - ASSERT(d->arch.shadow_dirty_bitmap != NULL); - - if ( !VALID_MFN(mfn) ) - return rc; - - pfn = __mfn_to_gpfn(d, mfn); - - /* - * Values with the MSB set denote MFNs that aren't really part of the - * domain's pseudo-physical memory map (e.g., the shared info frame). - * Nothing to do here... - */ - if ( unlikely(IS_INVALID_M2P_ENTRY(pfn)) ) - return rc; - - if ( likely(pfn < d->arch.shadow_dirty_bitmap_size) ) - { - /* N.B. Can use non-atomic TAS because protected by shadow_lock. */ - if ( !__test_and_set_bit(pfn, d->arch.shadow_dirty_bitmap) ) - { - d->arch.shadow_dirty_count++; - rc = 1; - } - } -#ifndef NDEBUG - else if ( mfn < max_page ) - { - SH_LOG("mark_dirty OOR! mfn=%x pfn=%lx max=%x (dom %p)", - mfn, pfn, d->arch.shadow_dirty_bitmap_size, d); - SH_LOG("dom=%p caf=%08x taf=%08x\n", - page_get_owner(&frame_table[mfn]), - frame_table[mfn].count_info, - frame_table[mfn].u.inuse.type_info ); - } -#endif - - return rc; -} - - -static inline int mark_dirty(struct domain *d, unsigned int mfn) -{ - int rc; - shadow_lock(d); - rc = __mark_dirty(d, mfn); - shadow_unlock(d); - return rc; -} - - /************************************************************************/ extern void shadow_mark_va_out_of_sync( @@ -666,8 +754,10 @@ static inline void l1pte_propagate_from_guest( (_PAGE_PRESENT|_PAGE_ACCESSED)) && VALID_MFN(mfn = __gpfn_to_mfn(d, l1e_get_pfn(gpte))) ) { - spte = l1e_create_pfn(mfn, l1e_get_flags(gpte) & ~_PAGE_GLOBAL); - + spte = l1e_create_pfn(mfn, + l1e_get_flags(gpte) & + ~(_PAGE_GLOBAL | _PAGE_AVAIL)); + if ( shadow_mode_log_dirty(d) || !(l1e_get_flags(gpte) & _PAGE_DIRTY) || mfn_is_page_table(mfn) ) @@ -729,14 +819,13 @@ static inline void l2pde_general( spde = l2e_empty(); if ( (l2e_get_flags(gpde) & _PAGE_PRESENT) && (sl1mfn != 0) ) { - spde = l2e_create_pfn(sl1mfn, - l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED); - l2e_add_flags(&gpde, _PAGE_ACCESSED); /* N.B. PDEs do not have a dirty bit. */ + spde = l2e_create_pfn(sl1mfn, + (l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED) + & ~(_PAGE_AVAIL)); + + /* N.B. PDEs do not have a dirty bit. */ + l2e_add_flags(&gpde, _PAGE_ACCESSED); - // XXX mafetter: Hmm... - // Shouldn't the dirty log be checked/updated here? - // Actually, it needs to be done in this function's callers. - // *gpde_p = gpde; } @@ -769,34 +858,57 @@ validate_pte_change( l1_pgentry_t *shadow_pte_p) { l1_pgentry_t old_spte, new_spte; + int need_flush = 0; perfc_incrc(validate_pte_calls); -#if 0 - FSH_LOG("validate_pte(old=%lx new=%lx)", old_pte, new_pte); -#endif - - old_spte = *shadow_pte_p; l1pte_propagate_from_guest(d, new_pte, &new_spte); - // only do the ref counting if something important changed. - // - if ( ((l1e_get_value(old_spte) | l1e_get_value(new_spte)) & _PAGE_PRESENT ) && - l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + if ( shadow_mode_refcounts(d) ) { - perfc_incrc(validate_pte_changes); + old_spte = *shadow_pte_p; - if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && - !shadow_get_page_from_l1e(new_spte, d) ) - new_spte = l1e_empty(); - if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) - put_page_from_l1e(old_spte, d); + if ( l1e_get_value(old_spte) == l1e_get_value(new_spte) ) + { + // No accounting required... + // + perfc_incrc(validate_pte_changes1); + } + else if ( l1e_get_value(old_spte) == (l1e_get_value(new_spte)|_PAGE_RW) ) + { + // Fast path for PTEs that have merely been write-protected + // (e.g., during a Unix fork()). A strict reduction in privilege. + // + perfc_incrc(validate_pte_changes2); + if ( likely(l1e_get_flags(new_spte) & _PAGE_PRESENT) ) + shadow_put_page_type(d, &frame_table[l1e_get_pfn(new_spte)]); + } + else if ( ((l1e_get_flags(old_spte) | l1e_get_flags(new_spte)) & + _PAGE_PRESENT ) && + l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + { + // only do the ref counting if something important changed. + // + perfc_incrc(validate_pte_changes3); + + if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && + !shadow_get_page_from_l1e(new_spte, d) ) + new_spte = l1e_empty(); + if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) + { + shadow_put_page_from_l1e(old_spte, d); + need_flush = 1; + } + } + else + { + perfc_incrc(validate_pte_changes4); + } } *shadow_pte_p = new_spte; - // paranoia rules! - return 1; + return need_flush; } // returns true if a tlb flush is needed @@ -808,6 +920,7 @@ validate_hl2e_change( l1_pgentry_t *shadow_hl2e_p) { l1_pgentry_t old_hl2e, new_hl2e; + int need_flush = 0; perfc_incrc(validate_hl2e_calls); @@ -825,14 +938,15 @@ validate_hl2e_change( !get_page(pfn_to_page(l1e_get_pfn(new_hl2e)), d) ) new_hl2e = l1e_empty(); if ( l1e_get_flags(old_hl2e) & _PAGE_PRESENT ) + { put_page(pfn_to_page(l1e_get_pfn(old_hl2e))); + need_flush = 1; + } } *shadow_hl2e_p = new_hl2e; - // paranoia rules! - return 1; - + return need_flush; } // returns true if a tlb flush is needed @@ -844,15 +958,13 @@ validate_pde_change( l2_pgentry_t *shadow_pde_p) { l2_pgentry_t old_spde, new_spde; + int need_flush = 0; perfc_incrc(validate_pde_calls); old_spde = *shadow_pde_p; l2pde_propagate_from_guest(d, &new_gpde, &new_spde); - // XXX Shouldn't we propagate the new_gpde to the guest? - // And then mark the guest's L2 page as dirty? - // Only do the ref counting if something important changed. // if ( ((l2e_get_value(old_spde) | l2e_get_value(new_spde)) & _PAGE_PRESENT) && @@ -864,13 +976,15 @@ validate_pde_change( !get_shadow_ref(l2e_get_pfn(new_spde)) ) BUG(); if ( l2e_get_flags(old_spde) & _PAGE_PRESENT ) + { put_shadow_ref(l2e_get_pfn(old_spde)); + need_flush = 1; + } } *shadow_pde_p = new_spde; - // paranoia rules! - return 1; + return need_flush; } /*********************************************************************/ @@ -1035,10 +1149,19 @@ static inline unsigned long __shadow_status( { perfc_incrc(shadow_status_shortcut); #ifndef NDEBUG - ASSERT(___shadow_status(d, gpfn, stype) == 0); + if ( ___shadow_status(d, gpfn, stype) != 0 ) + { + printk("d->id=%d gpfn=%lx gmfn=%lx stype=%lx c=%x t=%x " + "mfn_out_of_sync(gmfn)=%d mfn_is_page_table(gmfn)=%d\n", + d->id, gpfn, gmfn, stype, + frame_table[gmfn].count_info, + frame_table[gmfn].u.inuse.type_info, + mfn_out_of_sync(gmfn), mfn_is_page_table(gmfn)); + BUG(); + } - // Undo the affects of the above ASSERT on ___shadow_status()'s perf - // counters. + // Undo the affects of the above call to ___shadow_status()'s perf + // counters, since that call is really just part of an assertion. // perfc_decrc(shadow_status_calls); perfc_decrc(shadow_status_miss); @@ -1056,12 +1179,12 @@ static inline unsigned long __shadow_status( * * Either returns PGT_none, or PGT_l{1,2,3,4}_page_table. */ -static inline unsigned long +static inline u32 shadow_max_pgtable_type(struct domain *d, unsigned long gpfn, unsigned long *smfn) { struct shadow_status *x; - unsigned long pttype = PGT_none, type; + u32 pttype = PGT_none, type; ASSERT(spin_is_locked(&d->arch.shadow_lock)); ASSERT(gpfn == (gpfn & PGT_mfn_mask)); @@ -1379,12 +1502,6 @@ shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow) struct exec_domain *ed = current; struct domain *d = ed->domain; l2_pgentry_t sl2e; - l1_pgentry_t old_spte; - -#if 0 - printk("shadow_set_l1e(va=%p, new_spte=%p, create=%d)\n", - va, l1e_get_value(new_spte), create_l1_shadow); -#endif __shadow_get_l2e(ed, va, &sl2e); if ( !(l2e_get_flags(sl2e) & _PAGE_PRESENT) ) @@ -1424,17 +1541,20 @@ shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow) } } - old_spte = shadow_linear_pg_table[l1_linear_offset(va)]; - - // only do the ref counting if something important changed. - // - if ( l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + if ( shadow_mode_refcounts(d) ) { - if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && - !shadow_get_page_from_l1e(new_spte, d) ) - new_spte = l1e_empty(); - if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) - put_page_from_l1e(old_spte, d); + l1_pgentry_t old_spte = shadow_linear_pg_table[l1_linear_offset(va)]; + + // only do the ref counting if something important changed. + // + if ( l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + { + if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && + !shadow_get_page_from_l1e(new_spte, d) ) + new_spte = l1e_empty(); + if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) + shadow_put_page_from_l1e(old_spte, d); + } } shadow_linear_pg_table[l1_linear_offset(va)] = new_spte; @@ -1444,6 +1564,27 @@ shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow) /************************************************************************/ +static inline int +shadow_mode_page_writable(struct domain *d, unsigned long gpfn) +{ + unsigned long mfn = __gpfn_to_mfn(d, gpfn); + u32 type = frame_table[mfn].u.inuse.type_info & PGT_type_mask; + + if ( shadow_mode_refcounts(d) && + (type == PGT_writable_page) ) + type = shadow_max_pgtable_type(d, gpfn, NULL); + + if ( VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && + (type == PGT_l1_page_table) ) + return 1; + + if ( shadow_mode_write_all(d) && + type && (type <= PGT_l4_page_table) ) + return 1; + + return 0; +} + static inline l1_pgentry_t gva_to_gpte(unsigned long gva) { l2_pgentry_t gpde; diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index e1e9443035..f8edfd1fca 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -1,14 +1,28 @@ #ifndef __ASM_SMP_H #define __ASM_SMP_H +/* + * We need the APIC definitions automatically as part of 'smp.h' + */ #ifndef __ASSEMBLY__ #include -#include -#include -#include -#include +#include +#include #endif +#ifdef CONFIG_X86_LOCAL_APIC +#ifndef __ASSEMBLY__ +#include +#include +#include +#ifdef CONFIG_X86_IO_APIC +#include +#endif +#include +#endif +#endif + +#define BAD_APICID 0xFFu #ifdef CONFIG_SMP #ifndef __ASSEMBLY__ @@ -17,79 +31,61 @@ */ extern void smp_alloc_memory(void); -extern unsigned long phys_cpu_present_map; -extern unsigned long cpu_online_map; -extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; extern int smp_num_siblings; -extern int cpu_sibling_map[]; +extern cpumask_t cpu_sibling_map[]; -/* - * On x86 all CPUs are mapped 1:1 to the APIC space. - * This simplifies scheduling and IPI sending and - * compresses data structures. - */ -static inline int cpu_logical_map(int cpu) -{ - return cpu; -} -static inline int cpu_number_map(int cpu) -{ - return cpu; -} +extern void smp_flush_tlb(void); +extern void smp_invalidate_rcv(void); /* Process an NMI */ +extern void (*mtrr_hook) (void); +extern void zap_low_mappings (void); -/* - * Some lowlevel functions might want to know about - * the real APIC ID <-> CPU # mapping. - */ #define MAX_APICID 256 -extern volatile int cpu_to_physical_apicid[NR_CPUS]; -extern volatile int physical_apicid_to_cpu[MAX_APICID]; -extern volatile int cpu_to_logical_apicid[NR_CPUS]; -extern volatile int logical_apicid_to_cpu[MAX_APICID]; - -/* - * General functions that each host system must provide. - */ - -/*extern void smp_boot_cpus(void);*/ -extern void smp_store_cpu_info(int id); /* Store per CPU info (like the initial udelay numbers */ +extern u8 x86_cpu_to_apicid[]; /* * This function is needed by all SMP systems. It must _always_ be valid * from the initial startup. We map APIC_BASE very early in page_setup(), * so this is correct in the x86 case. */ +#define __smp_processor_id() (current->processor) -#define smp_processor_id() (current->processor) +extern cpumask_t cpu_callout_map; +extern cpumask_t cpu_callin_map; +#define cpu_possible_map cpu_callout_map -static __inline int hard_smp_processor_id(void) +/* We don't mark CPUs online until __cpu_up(), so we need another measure */ +static inline int num_booting_cpus(void) +{ + return cpus_weight(cpu_callout_map); +} + +extern void map_cpu_to_logical_apicid(void); +extern void unmap_cpu_to_logical_apicid(int cpu); + +#ifdef CONFIG_X86_LOCAL_APIC + +#ifdef APIC_DEFINITION +extern int hard_smp_processor_id(void); +#else +#include +static inline int hard_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ - return GET_APIC_ID(*(unsigned *)(APIC_BASE+APIC_ID)); + return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); } +#endif static __inline int logical_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ - return GET_APIC_LOGICAL_ID(*(unsigned *)(APIC_BASE+APIC_LDR)); + return GET_APIC_LOGICAL_ID(*(unsigned int *)(APIC_BASE+APIC_LDR)); } +#endif #endif /* !__ASSEMBLY__ */ #define NO_PROC_ID 0xFF /* No processor magic marker */ -/* - * This magic constant controls our willingness to transfer - * a process across CPUs. Such a transfer incurs misses on the L1 - * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My - * gut feeling is this will vary by board in value. For a board - * with separate L2 cache it probably depends also on the RSS, and - * for a board with shared L2 cache it ought to decay fast as other - * processes are run. - */ - -#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ - #endif #endif diff --git a/xen/include/asm-x86/smpboot.h b/xen/include/asm-x86/smpboot.h index 7a0b157114..6def59963b 100644 --- a/xen/include/asm-x86/smpboot.h +++ b/xen/include/asm-x86/smpboot.h @@ -1,132 +1,16 @@ #ifndef __ASM_SMPBOOT_H #define __ASM_SMPBOOT_H -/*emum for clustered_apic_mode values*/ -enum{ - CLUSTERED_APIC_NONE = 0, - CLUSTERED_APIC_XAPIC, - CLUSTERED_APIC_NUMAQ -}; - -#ifdef CONFIG_X86_CLUSTERED_APIC -extern unsigned int apic_broadcast_id; -extern unsigned char clustered_apic_mode; -extern unsigned char esr_disable; -extern unsigned char int_delivery_mode; -extern unsigned int int_dest_addr_mode; -extern int cyclone_setup(char*); - -static inline void detect_clustered_apic(char* oem, char* prod) -{ - /* - * Can't recognize Summit xAPICs at present, so use the OEM ID. - */ - if (!strncmp(oem, "IBM ENSW", 8) && !strncmp(prod, "VIGIL SMP", 9)){ - clustered_apic_mode = CLUSTERED_APIC_XAPIC; - apic_broadcast_id = APIC_BROADCAST_ID_XAPIC; - int_dest_addr_mode = APIC_DEST_PHYSICAL; - int_delivery_mode = dest_Fixed; - esr_disable = 1; - /*Start cyclone clock*/ - cyclone_setup(0); - /* check for ACPI tables */ - } else if (!strncmp(oem, "IBM", 3) && - (!strncmp(prod, "SERVIGIL", 8) || - !strncmp(prod, "EXA", 3) || - !strncmp(prod, "RUTHLESS", 8))){ - clustered_apic_mode = CLUSTERED_APIC_XAPIC; - apic_broadcast_id = APIC_BROADCAST_ID_XAPIC; - int_dest_addr_mode = APIC_DEST_PHYSICAL; - int_delivery_mode = dest_Fixed; - esr_disable = 1; - /*Start cyclone clock*/ - cyclone_setup(0); - } else if (!strncmp(oem, "IBM NUMA", 8)){ - clustered_apic_mode = CLUSTERED_APIC_NUMAQ; - apic_broadcast_id = APIC_BROADCAST_ID_APIC; - int_dest_addr_mode = APIC_DEST_LOGICAL; - int_delivery_mode = dest_LowestPrio; - esr_disable = 1; - } -} -#define INT_DEST_ADDR_MODE (int_dest_addr_mode) -#define INT_DELIVERY_MODE (int_delivery_mode) -#else /* CONFIG_X86_CLUSTERED_APIC */ -#define apic_broadcast_id (APIC_BROADCAST_ID_APIC) -#define clustered_apic_mode (CLUSTERED_APIC_NONE) -#define esr_disable (0) -#define detect_clustered_apic(x,y) -#define INT_DEST_ADDR_MODE (APIC_DEST_LOGICAL) /* logical delivery */ -#define INT_DELIVERY_MODE (dest_LowestPrio) -#endif /* CONFIG_X86_CLUSTERED_APIC */ -#define BAD_APICID 0xFFu - -#define TRAMPOLINE_LOW phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0x8:0x467) -#define TRAMPOLINE_HIGH phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0xa:0x469) - -#define boot_cpu_apicid ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?boot_cpu_logical_apicid:boot_cpu_physical_apicid) - -extern unsigned char raw_phys_apicid[NR_CPUS]; - -/* - * How to map from the cpu_present_map - */ -static inline int cpu_present_to_apicid(int mps_cpu) -{ - if (clustered_apic_mode == CLUSTERED_APIC_XAPIC) - return raw_phys_apicid[mps_cpu]; - if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ) - return (mps_cpu/4)*16 + (1<<(mps_cpu%4)); - return mps_cpu; -} - static inline unsigned long apicid_to_phys_cpu_present(int apicid) { - if(clustered_apic_mode) - return 1UL << (((apicid >> 4) << 2) + (apicid & 0x3)); return 1UL << apicid; } -#define physical_to_logical_apicid(phys_apic) ( (1ul << (phys_apic & 0x3)) | (phys_apic & 0xF0u) ) - -/* - * Mappings between logical cpu number and logical / physical apicid - * The first four macros are trivial, but it keeps the abstraction consistent - */ extern volatile int logical_apicid_2_cpu[]; extern volatile int cpu_2_logical_apicid[]; extern volatile int physical_apicid_2_cpu[]; extern volatile int cpu_2_physical_apicid[]; -#define logical_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu] -#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu] -#ifdef CONFIG_MULTIQUAD /* use logical IDs to bootstrap */ -#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu] -#else /* !CONFIG_MULTIQUAD */ /* use physical IDs to bootstrap */ #define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu] -#endif /* CONFIG_MULTIQUAD */ -#ifdef CONFIG_X86_CLUSTERED_APIC -static inline int target_cpus(void) -{ - static int cpu; - switch(clustered_apic_mode){ - case CLUSTERED_APIC_NUMAQ: - /* Broadcast intrs to local quad only. */ - return APIC_BROADCAST_ID_APIC; - case CLUSTERED_APIC_XAPIC: - /*round robin the interrupts*/ - cpu = (cpu+1)%smp_num_cpus; - return cpu_to_physical_apicid(cpu); - default: - } - return cpu_online_map; -} -#else -#define target_cpus() (cpu_online_map) -#endif #endif diff --git a/xen/include/asm-x86/system.h b/xen/include/asm-x86/system.h index 49355af7d6..cd0619008d 100644 --- a/xen/include/asm-x86/system.h +++ b/xen/include/asm-x86/system.h @@ -112,6 +112,7 @@ static always_inline unsigned long __cmpxchg(volatile void *ptr, unsigned long o return old; } +#define __HAVE_ARCH_CMPXCHG #define cmpxchg(ptr,o,n)\ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ (unsigned long)(n),sizeof(*(ptr)))) diff --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h index 2256145bec..8f48cd31dc 100644 --- a/xen/include/asm-x86/time.h +++ b/xen/include/asm-x86/time.h @@ -2,6 +2,6 @@ #ifndef __X86_TIME_H__ #define __X86_TIME_H__ -/* nothing */ +extern int timer_ack; #endif /* __X86_TIME_H__ */ diff --git a/xen/include/asm-x86/x86_32/domain_page.h b/xen/include/asm-x86/x86_32/domain_page.h index f72bce7936..7ebb72eb72 100644 --- a/xen/include/asm-x86/x86_32/domain_page.h +++ b/xen/include/asm-x86/x86_32/domain_page.h @@ -26,4 +26,54 @@ extern void *map_domain_mem(unsigned long pa); */ extern void unmap_domain_mem(void *va); +struct map_dom_mem_cache { + unsigned long pa; + void *va; +}; + +static inline void +init_map_domain_mem_cache(struct map_dom_mem_cache *cache) +{ + ASSERT(cache != NULL); + cache->pa = 0; +} + +static inline void * +map_domain_mem_with_cache(unsigned long pa, struct map_dom_mem_cache *cache) +{ + ASSERT(cache != NULL); + + if ( likely(cache->pa) ) + { + if ( likely((pa & PAGE_MASK) == (cache->pa & PAGE_MASK)) ) + goto done; + unmap_domain_mem(cache->va); + } + + cache->pa = (pa & PAGE_MASK) | 1; + cache->va = map_domain_mem(cache->pa); + + done: + return (void *)(((unsigned long)cache->va & PAGE_MASK) | + (pa & ~PAGE_MASK)); +} + +static inline void +unmap_domain_mem_with_cache(void *va, struct map_dom_mem_cache *cache) +{ + ASSERT(cache != NULL); + unmap_domain_mem(va); +} + +static inline void +destroy_map_domain_mem_cache(struct map_dom_mem_cache *cache) +{ + ASSERT(cache != NULL); + if ( likely(cache->pa) ) + { + unmap_domain_mem(cache->va); + cache->pa = 0; + } +} + #endif /* __ASM_DOMAIN_PAGE_H__ */ diff --git a/xen/include/asm-x86/x86_64/domain_page.h b/xen/include/asm-x86/x86_64/domain_page.h index 8a6081cde4..2a59fb1e5e 100644 --- a/xen/include/asm-x86/x86_64/domain_page.h +++ b/xen/include/asm-x86/x86_64/domain_page.h @@ -10,4 +10,12 @@ #define map_domain_mem(_pa) phys_to_virt(_pa) #define unmap_domain_mem(_va) ((void)(_va)) +struct map_dom_mem_cache { +}; + +#define init_map_domain_mem_cache(_c) ((void)(_c)) +#define map_domain_mem_with_cache(_p,_c) (map_domain_mem(_p)) +#define unmap_domain_mem_with_cache(_v,_c) ((void)(_v)) +#define destroy_map_domain_mem_cache(_c) ((void)(_c)) + #endif /* __ASM_DOMAIN_PAGE_H__ */ diff --git a/xen/include/asm-x86/x86_64/string.h b/xen/include/asm-x86/x86_64/string.h index 6c1cc902f9..613c982718 100644 --- a/xen/include/asm-x86/x86_64/string.h +++ b/xen/include/asm-x86/x86_64/string.h @@ -1,10 +1,6 @@ #ifndef _X86_64_STRING_H_ #define _X86_64_STRING_H_ -#define __HAVE_ARCH_MEMMOVE -#define memmove(dest,src,n) (__memmove((dest),(src),(n))) -#define __memmove(dest,src,n) (__builtin_memmove((dest),(src),(n))) - #define __HAVE_ARCH_MEMCPY #define memcpy(t,f,n) (__memcpy((t),(f),(n))) #define __memcpy(t,f,n) (__builtin_memcpy((t),(f),(n))) @@ -13,4 +9,8 @@ #define memset(s, c, count) (__memset((s),(c),(count))) #define __memset(s, c, count) (__builtin_memset((s),(c),(count))) +/* Some versions of 64-bit gcc don't have this built in. */ +#define __HAVE_ARCH_MEMMOVE +extern void *memmove(void *dest, const void *src, size_t n); + #endif diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index ad24299a0d..8c785d65d6 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -63,24 +63,8 @@ typedef struct { unsigned long bank1_regs[16]; // bank1 regs (r16-r31) when bank0 active unsigned long rrs[8]; // region registers unsigned long krs[8]; // kernel registers - unsigned long pkrs[8]; // protection key registers - // FIXME: These shouldn't be here as they can be overwritten by guests - // and validation at TLB miss time would be too expensive. - TR_ENTRY itrs[NITRS]; - TR_ENTRY dtrs[NDTRS]; - TR_ENTRY itlb; - TR_ENTRY dtlb; - unsigned long itlb_pte; - unsigned long dtlb_pte; - unsigned long irr[4]; - unsigned long insvc[4]; - unsigned long iva; - unsigned long dcr; - unsigned long itc; - unsigned long domain_itm; - unsigned long domain_itm_last; - unsigned long xen_itm; - unsigned long xen_timer_interval; + unsigned long pkrs[8]; // protection key registers + unsigned long tmp[8]; // temp registers (e.g. for hyperprivops) //} PACKED arch_shared_info_t; } arch_vcpu_info_t; // DON'T PACK diff --git a/xen/include/public/sched_ctl.h b/xen/include/public/sched_ctl.h index ac376d4226..01d6481c6e 100644 --- a/xen/include/public/sched_ctl.h +++ b/xen/include/public/sched_ctl.h @@ -9,6 +9,7 @@ /* Scheduler types. */ #define SCHED_BVT 0 +#define SCHED_SEDF 4 /* Set or get info? */ #define SCHED_INFO_PUT 0 @@ -31,18 +32,31 @@ struct sched_ctl_cmd struct sched_adjdom_cmd { - u32 sched_id; - u32 direction; - domid_t domain; - union { - struct bvt_adjdom { - u32 mcu_adv; /* mcu advance: inverse of weight */ - u32 warpback; /* warp? */ - s32 warpvalue; /* warp value */ - long long warpl; /* warp limit */ - long long warpu; /* unwarp time requirement */ - } bvt; - } u; -}; + u32 sched_id; /* 0 */ + u32 direction; /* 4 */ + domid_t domain; /* 8 */ + u16 __pad0; + u32 __pad1; + union { /* 16 */ + struct bvt_adjdom + { + u32 mcu_adv; /* 16: mcu advance: inverse of weight */ + u32 warpback; /* 20: warp? */ + s32 warpvalue; /* 24: warp value */ + long long warpl; /* 32: warp limit */ + long long warpu; /* 40: unwarp time requirement */ + } PACKED bvt; + + struct sedf_adjdom + { + u64 period; /* 16 */ + u64 slice; /* 24 */ + u64 latency; /* 32 */ + u16 extratime; /* 36 */ + u16 weight; /* 38 */ + } PACKED sedf; + + } PACKED u; +} PACKED; /* 40 bytes */ #endif /* __XEN_PUBLIC_SCHED_CTL_H__ */ diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h index feda09036a..b84f047651 100644 --- a/xen/include/xen/acpi.h +++ b/xen/include/xen/acpi.h @@ -80,7 +80,7 @@ typedef struct { struct acpi_table_rsdt { struct acpi_table_header header; - u32 entry[1]; + u32 entry[8]; } __attribute__ ((packed)); /* Extended System Description Table (XSDT) */ @@ -232,9 +232,28 @@ struct acpi_table_hpet { u8 page_protect; } __attribute__ ((packed)); +/* + * Simple Boot Flags + * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx + */ +struct acpi_table_sbf +{ + u8 sbf_signature[4]; + u32 sbf_len; + u8 sbf_revision; + u8 sbf_csum; + u8 sbf_oemid[6]; + u8 sbf_oemtable[8]; + u8 sbf_revdata[4]; + u8 sbf_creator[4]; + u8 sbf_crearev[4]; + u8 sbf_cmos; + u8 sbf_spare[3]; +} __attribute__ ((packed)); + /* * System Resource Affinity Table (SRAT) - * see http://www.microsoft.com/hwdev/design/srat.htm + * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx */ struct acpi_table_srat { @@ -309,7 +328,7 @@ struct acpi_table_sbst { /* Embedded Controller Boot Resources Table (ECDT) */ struct acpi_table_ecdt { - struct acpi_table_header header; + struct acpi_table_header header; struct acpi_generic_address ec_control; struct acpi_generic_address ec_data; u32 uid; @@ -317,6 +336,15 @@ struct acpi_table_ecdt { char ec_id[0]; } __attribute__ ((packed)); +/* PCI MMCONFIG */ + +struct acpi_table_mcfg { + struct acpi_table_header header; + u8 reserved[8]; + u32 base_address; + u32 base_reserved; +} __attribute__ ((packed)); + /* Table Handlers */ enum acpi_table_id { @@ -338,6 +366,7 @@ enum acpi_table_id { ACPI_SSDT, ACPI_SPMI, ACPI_HPET, + ACPI_MCFG, ACPI_TABLE_COUNT }; @@ -345,18 +374,19 @@ typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size); extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT]; -typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header); +typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header, const unsigned long end); char * __acpi_map_table (unsigned long phys_addr, unsigned long size); unsigned long acpi_find_rsdp (void); int acpi_boot_init (void); +int acpi_boot_table_init (void); int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header); -int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler); -int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler); +int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print_madt_entry (acpi_table_entry_header *madt); void acpi_table_print_srat_entry (acpi_table_entry_header *srat); @@ -367,15 +397,45 @@ void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma); void acpi_numa_arch_fixup(void); -#else /*!CONFIG_ACPI_BOOT*/ +#ifdef CONFIG_ACPI_HOTPLUG_CPU +/* Arch dependent functions for cpu hotplug support */ +int acpi_map_lsapic(acpi_handle handle, int *pcpu); +int acpi_unmap_lsapic(int cpu); +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ + +extern int acpi_mp_config; + +extern u32 pci_mmcfg_base_addr; + +extern int sbf_port ; + +#else /*!CONFIG_ACPI_BOOT*/ + +#define acpi_mp_config 0 static inline int acpi_boot_init(void) { return 0; } -#endif /*!CONFIG_ACPI_BOOT*/ +static inline int acpi_boot_table_init(void) +{ + return 0; +} +#endif /*!CONFIG_ACPI_BOOT*/ + +unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low); +int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); + +/* + * This function undoes the effect of one call to acpi_register_gsi(). + * If this matches the last registration, any IRQ resources for gsi + * are freed. + */ +#ifdef CONFIG_ACPI_DEALLOCATE_IRQ +void acpi_unregister_gsi (u32 gsi); +#endif #ifdef CONFIG_ACPI_PCI @@ -400,7 +460,11 @@ extern struct acpi_prt_list acpi_prt; struct pci_dev; int acpi_pci_irq_enable (struct pci_dev *dev); -int acpi_pci_irq_init (void); +void acpi_penalize_isa_irq(int irq); + +#ifdef CONFIG_ACPI_DEALLOCATE_IRQ +void acpi_pci_irq_disable (struct pci_dev *dev); +#endif struct acpi_pci_driver { struct acpi_pci_driver *next; @@ -415,14 +479,15 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver); #ifdef CONFIG_ACPI_EC -int ec_read(u8 addr, u8 *val); -int ec_write(u8 addr, u8 val); +extern int ec_read(u8 addr, u8 *val); +extern int ec_write(u8 addr, u8 val); #endif /*CONFIG_ACPI_EC*/ #ifdef CONFIG_ACPI_INTERPRETER -int acpi_blacklisted(void); +extern int acpi_blacklisted(void); +extern void acpi_bios_year(char *s); #else /*!CONFIG_ACPI_INTERPRETER*/ @@ -433,4 +498,41 @@ static inline int acpi_blacklisted(void) #endif /*!CONFIG_ACPI_INTERPRETER*/ +#define ACPI_CSTATE_LIMIT_DEFINED /* for driver builds */ +#ifdef CONFIG_ACPI + +/* + * Set highest legal C-state + * 0: C0 okay, but not C1 + * 1: C1 okay, but not C2 + * 2: C2 okay, but not C3 etc. + */ + +extern unsigned int max_cstate; + +static inline unsigned int acpi_get_cstate_limit(void) +{ + return max_cstate; +} +static inline void acpi_set_cstate_limit(unsigned int new_limit) +{ + max_cstate = new_limit; + return; +} +#else +static inline unsigned int acpi_get_cstate_limit(void) { return 0; } +static inline void acpi_set_cstate_limit(unsigned int new_limit) { return; } +#endif + +#ifdef CONFIG_ACPI_NUMA +int acpi_get_pxm(acpi_handle handle); +#else +static inline int acpi_get_pxm(acpi_handle handle) +{ + return 0; +} +#endif + +extern int pnpacpi_disabled; + #endif /*_LINUX_ACPI_H*/ diff --git a/xen/include/xen/adv_sched_hist.h b/xen/include/xen/adv_sched_hist.h new file mode 100644 index 0000000000..d8d56275d4 --- /dev/null +++ b/xen/include/xen/adv_sched_hist.h @@ -0,0 +1,40 @@ +/* Some functions to suport advanced scheduler histograms + Author: Stephan.Diestelhorst@cl.cam.ac.uk */ +//#include +//#include +#include +#define ADV_SCHED_HISTO +static inline void adv_sched_hist_start(int cpu) { + u64 now; + rdtscll(now); + if (!schedule_data[cpu].save_tsc) + schedule_data[cpu].save_tsc = now; +} +static inline void adv_sched_hist_from_stop(int cpu) { + u64 now; + rdtscll(now); + if (schedule_data[cpu].save_tsc) { + now -= schedule_data[cpu].save_tsc; + now /= 7; + if (now < BUCKETS-1) + schedule_data[cpu].from_hist[now]++; + else + schedule_data[cpu].from_hist[BUCKETS-1]++; + + schedule_data[cpu].save_tsc = 0; + } +} +static inline void adv_sched_hist_to_stop(int cpu) { + u64 now; + rdtscll(now); + if (schedule_data[cpu].save_tsc) { + now -= schedule_data[cpu].save_tsc; + now /= 24; + if (now < BUCKETS-1) + schedule_data[cpu].to_hist[now]++; + else + schedule_data[cpu].to_hist[BUCKETS-1]++; + + schedule_data[cpu].save_tsc = 0; + } +} diff --git a/xen/include/xen/bitmap.h b/xen/include/xen/bitmap.h new file mode 100644 index 0000000000..c91a10aef0 --- /dev/null +++ b/xen/include/xen/bitmap.h @@ -0,0 +1,249 @@ +#ifndef __XEN_BITMAP_H +#define __XEN_BITMAP_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +/* + * bitmaps provide bit arrays that consume one or more unsigned + * longs. The bitmap interface and available operations are listed + * here, in bitmap.h + * + * Function implementations generic to all architectures are in + * lib/bitmap.c. Functions implementations that are architecture + * specific are in various include/asm-/bitops.h headers + * and other arch/ specific files. + * + * See lib/bitmap.c for more details. + */ + +/* + * The available bitmap operations and their rough meaning in the + * case that the bitmap is a single unsigned long are thus: + * + * bitmap_zero(dst, nbits) *dst = 0UL + * bitmap_fill(dst, nbits) *dst = ~0UL + * bitmap_copy(dst, src, nbits) *dst = *src + * bitmap_and(dst, src1, src2, nbits) *dst = *src1 & *src2 + * bitmap_or(dst, src1, src2, nbits) *dst = *src1 | *src2 + * bitmap_xor(dst, src1, src2, nbits) *dst = *src1 ^ *src2 + * bitmap_andnot(dst, src1, src2, nbits) *dst = *src1 & ~(*src2) + * bitmap_complement(dst, src, nbits) *dst = ~(*src) + * bitmap_equal(src1, src2, nbits) Are *src1 and *src2 equal? + * bitmap_intersects(src1, src2, nbits) Do *src1 and *src2 overlap? + * bitmap_subset(src1, src2, nbits) Is *src1 a subset of *src2? + * bitmap_empty(src, nbits) Are all bits zero in *src? + * bitmap_full(src, nbits) Are all bits set in *src? + * bitmap_weight(src, nbits) Hamming Weight: number set bits + * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n + * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n + */ + +/* + * Also the following operations in asm/bitops.h apply to bitmaps. + * + * set_bit(bit, addr) *addr |= bit + * clear_bit(bit, addr) *addr &= ~bit + * change_bit(bit, addr) *addr ^= bit + * test_bit(bit, addr) Is bit set in *addr? + * test_and_set_bit(bit, addr) Set bit and return old value + * test_and_clear_bit(bit, addr) Clear bit and return old value + * test_and_change_bit(bit, addr) Change bit and return old value + * find_first_zero_bit(addr, nbits) Position first zero bit in *addr + * find_first_bit(addr, nbits) Position first set bit in *addr + * find_next_zero_bit(addr, nbits, bit) Position next zero bit in *addr >= bit + * find_next_bit(addr, nbits, bit) Position next set bit in *addr >= bit + */ + +/* + * The DECLARE_BITMAP(name,bits) macro, in xen/types.h, can be used + * to declare an array named 'name' of just enough unsigned longs to + * contain all bit positions from 0 to 'bits' - 1. + */ + +/* + * lib/bitmap.c provides these functions: + */ + +extern int __bitmap_empty(const unsigned long *bitmap, int bits); +extern int __bitmap_full(const unsigned long *bitmap, int bits); +extern int __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_complement(unsigned long *dst, const unsigned long *src, + int bits); +extern void __bitmap_shift_right(unsigned long *dst, + const unsigned long *src, int shift, int bits); +extern void __bitmap_shift_left(unsigned long *dst, + const unsigned long *src, int shift, int bits); +extern void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern int __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern int __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern int __bitmap_weight(const unsigned long *bitmap, int bits); + +extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order); +extern void bitmap_release_region(unsigned long *bitmap, int pos, int order); +extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order); + +#define BITMAP_LAST_WORD_MASK(nbits) \ +( \ + ((nbits) % BITS_PER_LONG) ? \ + (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \ +) + +static inline void bitmap_zero(unsigned long *dst, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = 0UL; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memset(dst, 0, len); + } +} + +static inline void bitmap_fill(unsigned long *dst, int nbits) +{ + size_t nlongs = BITS_TO_LONGS(nbits); + if (nlongs > 1) { + int len = (nlongs - 1) * sizeof(unsigned long); + memset(dst, 0xff, len); + } + dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); +} + +static inline void bitmap_copy(unsigned long *dst, const unsigned long *src, + int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memcpy(dst, src, len); + } +} + +static inline void bitmap_and(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 & *src2; + else + __bitmap_and(dst, src1, src2, nbits); +} + +static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 | *src2; + else + __bitmap_or(dst, src1, src2, nbits); +} + +static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 ^ *src2; + else + __bitmap_xor(dst, src1, src2, nbits); +} + +static inline void bitmap_andnot(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 & ~(*src2); + else + __bitmap_andnot(dst, src1, src2, nbits); +} + +static inline void bitmap_complement(unsigned long *dst, const unsigned long *src, + int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits); + else + __bitmap_complement(dst, src, nbits); +} + +static inline int bitmap_equal(const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_equal(src1, src2, nbits); +} + +static inline int bitmap_intersects(const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; + else + return __bitmap_intersects(src1, src2, nbits); +} + +static inline int bitmap_subset(const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_subset(src1, src2, nbits); +} + +static inline int bitmap_empty(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_empty(src, nbits); +} + +static inline int bitmap_full(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_full(src, nbits); +} + +static inline int bitmap_weight(const unsigned long *src, int nbits) +{ + return __bitmap_weight(src, nbits); +} + +static inline void bitmap_shift_right(unsigned long *dst, + const unsigned long *src, int n, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src >> n; + else + __bitmap_shift_right(dst, src, n, nbits); +} + +static inline void bitmap_shift_left(unsigned long *dst, + const unsigned long *src, int n, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = (*src << n) & BITMAP_LAST_WORD_MASK(nbits); + else + __bitmap_shift_left(dst, src, n, nbits); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __XEN_BITMAP_H */ diff --git a/xen/include/xen/bitops.h b/xen/include/xen/bitops.h new file mode 100644 index 0000000000..e743c0059d --- /dev/null +++ b/xen/include/xen/bitops.h @@ -0,0 +1,129 @@ +#ifndef _LINUX_BITOPS_H +#define _LINUX_BITOPS_H +#include + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +static inline int generic_ffs(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} + +/* + * fls: find last bit set. + */ + +static __inline__ int generic_fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +/* + * Include this here because some architectures need generic_ffs/fls in + * scope + */ +#include + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +static inline unsigned int generic_hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +static inline unsigned int generic_hweight16(unsigned int w) +{ + unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555); + res = (res & 0x3333) + ((res >> 2) & 0x3333); + res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); + return (res & 0x00FF) + ((res >> 8) & 0x00FF); +} + +static inline unsigned int generic_hweight8(unsigned int w) +{ + unsigned int res = (w & 0x55) + ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res & 0x0F) + ((res >> 4) & 0x0F); +} + +static inline unsigned long generic_hweight64(__u64 w) +{ +#if BITS_PER_LONG < 64 + return generic_hweight32((unsigned int)(w >> 32)) + + generic_hweight32((unsigned int)w); +#else + u64 res; + res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul); + res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); + res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful); + res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul); + res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul); + return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul); +#endif +} + +static inline unsigned long hweight_long(unsigned long w) +{ + return sizeof(w) == 4 ? generic_hweight32(w) : generic_hweight64(w); +} + +#endif diff --git a/xen/include/xen/config.h b/xen/include/xen/config.h index 95101174ba..ca3650f80f 100644 --- a/xen/include/xen/config.h +++ b/xen/include/xen/config.h @@ -15,7 +15,7 @@ #define always_inline __inline__ __attribute__ ((always_inline)) -/* syslog levels ==> nothing! */ +/* Linux syslog levels. */ #define KERN_NOTICE "" #define KERN_WARNING "" #define KERN_DEBUG "" @@ -25,6 +25,10 @@ #define KERN_EMERG "" #define KERN_ALERT "" +/* Linux 'checker' project. */ +#define __iomem +#define __user + #ifdef VERBOSE #define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \ __FILE__ , __LINE__ , ## _a ) diff --git a/xen/include/xen/cpumask.h b/xen/include/xen/cpumask.h new file mode 100644 index 0000000000..4881447842 --- /dev/null +++ b/xen/include/xen/cpumask.h @@ -0,0 +1,27 @@ +/* + * XXX This to be replaced with the Linux file in the near future. + */ + +#ifndef __XEN_CPUMASK_H__ +#define __XEN_CPUMASK_H__ + +#include + +typedef u32 cpumask_t; + +#ifndef cpu_online_map +extern cpumask_t cpu_online_map; +#endif + +static inline int cpus_weight(cpumask_t w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +#define cpus_addr(_m) (&(_m)) + +#endif /* __XEN_CPUMASK_H__ */ diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index f0f3d61fd6..ac7ce6b1a0 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -43,7 +43,7 @@ static inline void evtchn_set_pending(struct exec_domain *ed, int port) * NB2. We save DF_RUNNING across the unblock to avoid a needless * IPI for domains that we IPI'd to unblock. */ - running = test_bit(EDF_RUNNING, &ed->ed_flags); + running = test_bit(EDF_RUNNING, &ed->flags); exec_domain_unblock(ed); if ( running ) smp_send_event_check_cpu(ed->processor); diff --git a/xen/include/xen/inttypes.h b/xen/include/xen/inttypes.h new file mode 100644 index 0000000000..2163244326 --- /dev/null +++ b/xen/include/xen/inttypes.h @@ -0,0 +1,251 @@ +/* Copyright (C) 1997-2001, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * ISO C99: 7.8 Format conversion of integer types + */ + +#ifndef _XEN_INTTYPES_H +#define _XEN_INTTYPES_H 1 + +#include +#include + +# if BITS_PER_LONG == 64 +# define __PRI64_PREFIX "l" +# define __PRIPTR_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# define __PRIPTR_PREFIX +# endif + +/* Macros for printing format specifiers. */ + +/* Decimal notation. */ +# define PRId8 "d" +# define PRId16 "d" +# define PRId32 "d" +# define PRId64 __PRI64_PREFIX "d" + +# define PRIdLEAST8 "d" +# define PRIdLEAST16 "d" +# define PRIdLEAST32 "d" +# define PRIdLEAST64 __PRI64_PREFIX "d" + +# define PRIdFAST8 "d" +# define PRIdFAST16 __PRIPTR_PREFIX "d" +# define PRIdFAST32 __PRIPTR_PREFIX "d" +# define PRIdFAST64 __PRI64_PREFIX "d" + + +# define PRIi8 "i" +# define PRIi16 "i" +# define PRIi32 "i" +# define PRIi64 __PRI64_PREFIX "i" + +# define PRIiLEAST8 "i" +# define PRIiLEAST16 "i" +# define PRIiLEAST32 "i" +# define PRIiLEAST64 __PRI64_PREFIX "i" + +# define PRIiFAST8 "i" +# define PRIiFAST16 __PRIPTR_PREFIX "i" +# define PRIiFAST32 __PRIPTR_PREFIX "i" +# define PRIiFAST64 __PRI64_PREFIX "i" + +/* Octal notation. */ +# define PRIo8 "o" +# define PRIo16 "o" +# define PRIo32 "o" +# define PRIo64 __PRI64_PREFIX "o" + +# define PRIoLEAST8 "o" +# define PRIoLEAST16 "o" +# define PRIoLEAST32 "o" +# define PRIoLEAST64 __PRI64_PREFIX "o" + +# define PRIoFAST8 "o" +# define PRIoFAST16 __PRIPTR_PREFIX "o" +# define PRIoFAST32 __PRIPTR_PREFIX "o" +# define PRIoFAST64 __PRI64_PREFIX "o" + +/* Unsigned integers. */ +# define PRIu8 "u" +# define PRIu16 "u" +# define PRIu32 "u" +# define PRIu64 __PRI64_PREFIX "u" + +# define PRIuLEAST8 "u" +# define PRIuLEAST16 "u" +# define PRIuLEAST32 "u" +# define PRIuLEAST64 __PRI64_PREFIX "u" + +# define PRIuFAST8 "u" +# define PRIuFAST16 __PRIPTR_PREFIX "u" +# define PRIuFAST32 __PRIPTR_PREFIX "u" +# define PRIuFAST64 __PRI64_PREFIX "u" + +/* lowercase hexadecimal notation. */ +# define PRIx8 "x" +# define PRIx16 "x" +# define PRIx32 "x" +# define PRIx64 __PRI64_PREFIX "x" + +# define PRIxLEAST8 "x" +# define PRIxLEAST16 "x" +# define PRIxLEAST32 "x" +# define PRIxLEAST64 __PRI64_PREFIX "x" + +# define PRIxFAST8 "x" +# define PRIxFAST16 __PRIPTR_PREFIX "x" +# define PRIxFAST32 __PRIPTR_PREFIX "x" +# define PRIxFAST64 __PRI64_PREFIX "x" + +/* UPPERCASE hexadecimal notation. */ +# define PRIX8 "X" +# define PRIX16 "X" +# define PRIX32 "X" +# define PRIX64 __PRI64_PREFIX "X" + +# define PRIXLEAST8 "X" +# define PRIXLEAST16 "X" +# define PRIXLEAST32 "X" +# define PRIXLEAST64 __PRI64_PREFIX "X" + +# define PRIXFAST8 "X" +# define PRIXFAST16 __PRIPTR_PREFIX "X" +# define PRIXFAST32 __PRIPTR_PREFIX "X" +# define PRIXFAST64 __PRI64_PREFIX "X" + + +/* Macros for printing `intmax_t' and `uintmax_t'. */ +# define PRIdMAX __PRI64_PREFIX "d" +# define PRIiMAX __PRI64_PREFIX "i" +# define PRIoMAX __PRI64_PREFIX "o" +# define PRIuMAX __PRI64_PREFIX "u" +# define PRIxMAX __PRI64_PREFIX "x" +# define PRIXMAX __PRI64_PREFIX "X" + + +/* Macros for printing `intptr_t' and `uintptr_t'. */ +# define PRIdPTR __PRIPTR_PREFIX "d" +# define PRIiPTR __PRIPTR_PREFIX "i" +# define PRIoPTR __PRIPTR_PREFIX "o" +# define PRIuPTR __PRIPTR_PREFIX "u" +# define PRIxPTR __PRIPTR_PREFIX "x" +# define PRIXPTR __PRIPTR_PREFIX "X" + + +/* Macros for scanning format specifiers. */ + +/* Signed decimal notation. */ +# define SCNd8 "hhd" +# define SCNd16 "hd" +# define SCNd32 "d" +# define SCNd64 __PRI64_PREFIX "d" + +# define SCNdLEAST8 "hhd" +# define SCNdLEAST16 "hd" +# define SCNdLEAST32 "d" +# define SCNdLEAST64 __PRI64_PREFIX "d" + +# define SCNdFAST8 "hhd" +# define SCNdFAST16 __PRIPTR_PREFIX "d" +# define SCNdFAST32 __PRIPTR_PREFIX "d" +# define SCNdFAST64 __PRI64_PREFIX "d" + +/* Signed decimal notation. */ +# define SCNi8 "hhi" +# define SCNi16 "hi" +# define SCNi32 "i" +# define SCNi64 __PRI64_PREFIX "i" + +# define SCNiLEAST8 "hhi" +# define SCNiLEAST16 "hi" +# define SCNiLEAST32 "i" +# define SCNiLEAST64 __PRI64_PREFIX "i" + +# define SCNiFAST8 "hhi" +# define SCNiFAST16 __PRIPTR_PREFIX "i" +# define SCNiFAST32 __PRIPTR_PREFIX "i" +# define SCNiFAST64 __PRI64_PREFIX "i" + +/* Unsigned decimal notation. */ +# define SCNu8 "hhu" +# define SCNu16 "hu" +# define SCNu32 "u" +# define SCNu64 __PRI64_PREFIX "u" + +# define SCNuLEAST8 "hhu" +# define SCNuLEAST16 "hu" +# define SCNuLEAST32 "u" +# define SCNuLEAST64 __PRI64_PREFIX "u" + +# define SCNuFAST8 "hhu" +# define SCNuFAST16 __PRIPTR_PREFIX "u" +# define SCNuFAST32 __PRIPTR_PREFIX "u" +# define SCNuFAST64 __PRI64_PREFIX "u" + +/* Octal notation. */ +# define SCNo8 "hho" +# define SCNo16 "ho" +# define SCNo32 "o" +# define SCNo64 __PRI64_PREFIX "o" + +# define SCNoLEAST8 "hho" +# define SCNoLEAST16 "ho" +# define SCNoLEAST32 "o" +# define SCNoLEAST64 __PRI64_PREFIX "o" + +# define SCNoFAST8 "hho" +# define SCNoFAST16 __PRIPTR_PREFIX "o" +# define SCNoFAST32 __PRIPTR_PREFIX "o" +# define SCNoFAST64 __PRI64_PREFIX "o" + +/* Hexadecimal notation. */ +# define SCNx8 "hhx" +# define SCNx16 "hx" +# define SCNx32 "x" +# define SCNx64 __PRI64_PREFIX "x" + +# define SCNxLEAST8 "hhx" +# define SCNxLEAST16 "hx" +# define SCNxLEAST32 "x" +# define SCNxLEAST64 __PRI64_PREFIX "x" + +# define SCNxFAST8 "hhx" +# define SCNxFAST16 __PRIPTR_PREFIX "x" +# define SCNxFAST32 __PRIPTR_PREFIX "x" +# define SCNxFAST64 __PRI64_PREFIX "x" + + +/* Macros for scanning `intmax_t' and `uintmax_t'. */ +# define SCNdMAX __PRI64_PREFIX "d" +# define SCNiMAX __PRI64_PREFIX "i" +# define SCNoMAX __PRI64_PREFIX "o" +# define SCNuMAX __PRI64_PREFIX "u" +# define SCNxMAX __PRI64_PREFIX "x" + +/* Macros for scaning `intptr_t' and `uintptr_t'. */ +# define SCNdPTR __PRIPTR_PREFIX "d" +# define SCNiPTR __PRIPTR_PREFIX "i" +# define SCNoPTR __PRIPTR_PREFIX "o" +# define SCNuPTR __PRIPTR_PREFIX "u" +# define SCNxPTR __PRIPTR_PREFIX "x" + +#endif /* _XEN_INTTYPES_H */ diff --git a/xen/include/xen/ioport.h b/xen/include/xen/ioport.h deleted file mode 100644 index b39d07ae32..0000000000 --- a/xen/include/xen/ioport.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ioport.h Definitions of routines for detecting, reserving and - * allocating system resources. - * - * Authors: Linus Torvalds - */ - -#ifndef _LINUX_IOPORT_H -#define _LINUX_IOPORT_H - -/* - * Resources are tree-like, allowing - * nesting etc.. - */ -struct resource { - const char *name; - unsigned long start, end; - unsigned long flags; - struct resource *parent, *sibling, *child; -}; - -struct resource_list { - struct resource_list *next; - struct resource *res; - struct pci_dev *dev; -}; - -/* - * IO resources have these defined flags. - */ -#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ - -#define IORESOURCE_IO 0x00000100 /* Resource type */ -#define IORESOURCE_MEM 0x00000200 -#define IORESOURCE_IRQ 0x00000400 -#define IORESOURCE_DMA 0x00000800 - -#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ -#define IORESOURCE_READONLY 0x00002000 -#define IORESOURCE_CACHEABLE 0x00004000 -#define IORESOURCE_RANGELENGTH 0x00008000 -#define IORESOURCE_SHADOWABLE 0x00010000 -#define IORESOURCE_BUS_HAS_VGA 0x00080000 - -#define IORESOURCE_UNSET 0x20000000 -#define IORESOURCE_AUTO 0x40000000 -#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ - -/* ISA PnP IRQ specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_IRQ_HIGHEDGE (1<<0) -#define IORESOURCE_IRQ_LOWEDGE (1<<1) -#define IORESOURCE_IRQ_HIGHLEVEL (1<<2) -#define IORESOURCE_IRQ_LOWLEVEL (1<<3) - -/* ISA PnP DMA specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_DMA_TYPE_MASK (3<<0) -#define IORESOURCE_DMA_8BIT (0<<0) -#define IORESOURCE_DMA_8AND16BIT (1<<0) -#define IORESOURCE_DMA_16BIT (2<<0) - -#define IORESOURCE_DMA_MASTER (1<<2) -#define IORESOURCE_DMA_BYTE (1<<3) -#define IORESOURCE_DMA_WORD (1<<4) - -#define IORESOURCE_DMA_SPEED_MASK (3<<6) -#define IORESOURCE_DMA_COMPATIBLE (0<<6) -#define IORESOURCE_DMA_TYPEA (1<<6) -#define IORESOURCE_DMA_TYPEB (2<<6) -#define IORESOURCE_DMA_TYPEF (3<<6) - -/* ISA PnP memory I/O specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */ -#define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */ -#define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */ -#define IORESOURCE_MEM_TYPE_MASK (3<<3) -#define IORESOURCE_MEM_8BIT (0<<3) -#define IORESOURCE_MEM_16BIT (1<<3) -#define IORESOURCE_MEM_8AND16BIT (2<<3) -#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ -#define IORESOURCE_MEM_EXPANSIONROM (1<<6) - -/* PC/ISA/whatever - the normal PC address spaces: IO and memory */ -extern struct resource ioport_resource; -extern struct resource iomem_resource; - -extern int get_resource_list(struct resource *, char *buf, int size); - -extern int check_resource(struct resource *root, unsigned long, unsigned long); -extern int request_resource(struct resource *root, struct resource *new); -extern int release_resource(struct resource *new); -extern int allocate_resource(struct resource *root, struct resource *new, - unsigned long size, - unsigned long min, unsigned long max, - unsigned long align, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data); - -/* Convenience shorthand with allocation */ -#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) -#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name)) - -#define release_region(start,n) __release_region(&ioport_resource, (start), (n)) -#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n)) - -extern void __release_region(struct resource *, unsigned long, unsigned long); - -extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name); - -#define get_ioport_list(buf) get_resource_list(&ioport_resource, buf, PAGE_SIZE) -#define get_mem_list(buf) get_resource_list(&iomem_resource, buf, PAGE_SIZE) - -#define HAVE_AUTOIRQ -extern void autoirq_setup(int waittime); -extern int autoirq_report(int waittime); - -#endif /* _LINUX_IOPORT_H */ diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index 6c77460f41..f419f0c182 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -2,6 +2,7 @@ #define __XEN_IRQ_H__ #include +#include #include #include #include @@ -35,7 +36,7 @@ struct hw_interrupt_type { void (*disable)(unsigned int irq); void (*ack)(unsigned int irq); void (*end)(unsigned int irq); - void (*set_affinity)(unsigned int irq, unsigned long mask); + void (*set_affinity)(unsigned int irq, cpumask_t mask); }; typedef struct hw_interrupt_type hw_irq_controller; diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h index 313635f82a..b8a981a632 100644 --- a/xen/include/xen/lib.h +++ b/xen/include/xen/lib.h @@ -1,6 +1,7 @@ #ifndef __LIB_H__ #define __LIB_H__ +#include #include #include #include @@ -15,7 +16,7 @@ #define BUG_ON(_p) do { if (_p) BUG(); } while ( 0 ) #ifndef NDEBUG -#define ASSERT(_p) if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s\n", #_p , __LINE__, __FILE__); BUG(); } +#define ASSERT(_p) { if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s\n", #_p , __LINE__, __FILE__); BUG(); } } #else #define ASSERT(_p) ((void)0) #endif diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h deleted file mode 100644 index 5f8740a31c..0000000000 --- a/xen/include/xen/pci.h +++ /dev/null @@ -1,838 +0,0 @@ -/* - * $Id: pci.h,v 1.87 1998/10/11 15:13:12 mj Exp $ - * - * PCI defines and function prototypes - * Copyright 1994, Drew Eckhardt - * Copyright 1997--1999 Martin Mares - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - */ - -#ifndef LINUX_PCI_H -#define LINUX_PCI_H - -/* - * Under PCI, each device has 256 bytes of configuration address space, - * of which the first 64 bytes are standardized as follows: - */ -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ - -#define PCI_STATUS 0x06 /* 16 bits */ -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ -#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ -#define PCI_STATUS_DEVSEL_FAST 0x000 -#define PCI_STATUS_DEVSEL_MEDIUM 0x200 -#define PCI_STATUS_DEVSEL_SLOW 0x400 -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ - -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 - revision */ -#define PCI_REVISION_ID 0x08 /* Revision ID */ -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ - -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ -#define PCI_HEADER_TYPE 0x0e /* 8 bits */ -#define PCI_HEADER_TYPE_NORMAL 0 -#define PCI_HEADER_TYPE_BRIDGE 1 -#define PCI_HEADER_TYPE_CARDBUS 2 - -#define PCI_BIST 0x0f /* 8 bits */ -#define PCI_BIST_CODE_MASK 0x0f /* Return result */ -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ - -/* - * Base addresses specify locations in memory or I/O space. - * Decoded size can be determined by writing a value of - * 0xffffffff to the register, and reading it back. Only - * 1 bits are decoded. - */ -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) -#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) -/* bit 1 is reserved if address_space = 1 */ - -/* Header type 0 (normal devices) */ -#define PCI_CARDBUS_CIS 0x28 -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c -#define PCI_SUBSYSTEM_ID 0x2e -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ -#define PCI_ROM_ADDRESS_ENABLE 0x01 -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) - -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ - -/* 0x35-0x3b are reserved */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* Header type 1 (PCI-to-PCI bridges) */ -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ -#define PCI_IO_LIMIT 0x1d -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ -#define PCI_IO_RANGE_TYPE_16 0x00 -#define PCI_IO_RANGE_TYPE_32 0x01 -#define PCI_IO_RANGE_MASK (~0x0fUL) -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ -#define PCI_MEMORY_LIMIT 0x22 -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL -#define PCI_MEMORY_RANGE_MASK (~0x0fUL) -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ -#define PCI_PREF_MEMORY_LIMIT 0x26 -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL -#define PCI_PREF_RANGE_TYPE_32 0x00 -#define PCI_PREF_RANGE_TYPE_64 0x01 -#define PCI_PREF_RANGE_MASK (~0x0fUL) -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ -#define PCI_PREF_LIMIT_UPPER32 0x2c -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ -#define PCI_IO_LIMIT_UPPER16 0x32 -/* 0x34 same as for htype 0 */ -/* 0x35-0x3b is reserved */ -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_BRIDGE_CONTROL 0x3e -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ -#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */ -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ - -/* Header type 2 (CardBus bridges) */ -#define PCI_CB_CAPABILITY_LIST 0x14 -/* 0x15 reserved */ -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ -#define PCI_CB_MEMORY_BASE_0 0x1c -#define PCI_CB_MEMORY_LIMIT_0 0x20 -#define PCI_CB_MEMORY_BASE_1 0x24 -#define PCI_CB_MEMORY_LIMIT_1 0x28 -#define PCI_CB_IO_BASE_0 0x2c -#define PCI_CB_IO_BASE_0_HI 0x2e -#define PCI_CB_IO_LIMIT_0 0x30 -#define PCI_CB_IO_LIMIT_0_HI 0x32 -#define PCI_CB_IO_BASE_1 0x34 -#define PCI_CB_IO_BASE_1_HI 0x36 -#define PCI_CB_IO_LIMIT_1 0x38 -#define PCI_CB_IO_LIMIT_1_HI 0x3a -#define PCI_CB_IO_RANGE_MASK (~0x03UL) -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_CB_BRIDGE_CONTROL 0x3e -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ -#define PCI_CB_BRIDGE_CTL_SERR 0x02 -#define PCI_CB_BRIDGE_CTL_ISA 0x04 -#define PCI_CB_BRIDGE_CTL_VGA 0x08 -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 -#define PCI_CB_SUBSYSTEM_ID 0x42 -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ -/* 0x48-0x7f reserved */ - -/* Capability lists */ - -#define PCI_CAP_LIST_ID 0 /* Capability ID */ -#define PCI_CAP_ID_PM 0x01 /* Power Management */ -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ -#define PCI_CAP_SIZEOF 4 - -/* Power Management Registers */ - -#define PCI_PM_PMC 2 /* PM Capabilities Register */ -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ -#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxilliary power support mask */ -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ -#define PCI_PM_CTRL 4 /* PM control and status register */ -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ -#define PCI_PM_DATA_REGISTER 7 /* (??) */ -#define PCI_PM_SIZEOF 8 - -/* AGP registers */ - -#define PCI_AGP_VERSION 2 /* BCD version number */ -#define PCI_AGP_RFU 3 /* Rest of capability flags */ -#define PCI_AGP_STATUS 4 /* Status register */ -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ -#define PCI_AGP_COMMAND 8 /* Control register */ -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ -#define PCI_AGP_SIZEOF 12 - -/* Slot Identification */ - -#define PCI_SID_ESR 2 /* Expansion Slot Register */ -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ - -/* Message Signalled Interrupts registers */ - -#define PCI_MSI_FLAGS 2 /* Various flags */ -#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ -#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ -#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ -#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ -#define PCI_MSI_RFU 3 /* Rest of capability flags */ -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ - -/* CompactPCI Hotswap Register */ - -#define PCI_CHSWP_CSR 2 /* Control and Status Register */ -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ -#define PCI_CHSWP_PI 0x30 /* Programming Interface */ -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ - -/* PCI-X registers */ - -#define PCI_X_CMD 2 /* Modes & Features */ -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ -#define PCI_X_DEVFN 4 /* A copy of devfn. */ -#define PCI_X_BUSNR 5 /* Bus segment number */ -#define PCI_X_STATUS 6 /* PCI-X capabilities */ -#define PCI_X_STATUS_64BIT 0x0001 /* 64-bit device */ -#define PCI_X_STATUS_133MHZ 0x0002 /* 133 MHz capable */ -#define PCI_X_STATUS_SPL_DISC 0x0004 /* Split Completion Discarded */ -#define PCI_X_STATUS_UNX_SPL 0x0008 /* Unexpected Split Completion */ -#define PCI_X_STATUS_COMPLEX 0x0010 /* Device Complexity */ -#define PCI_X_STATUS_MAX_READ 0x0060 /* Designed Maximum Memory Read Count */ -#define PCI_X_STATUS_MAX_SPLIT 0x0380 /* Design Max Outstanding Split Trans */ -#define PCI_X_STATUS_MAX_CUM 0x1c00 /* Designed Max Cumulative Read Size */ -#define PCI_X_STATUS_SPL_ERR 0x2000 /* Rcvd Split Completion Error Msg */ - -/* Include the ID list */ - -#include - -/* - * The PCI interface treats multi-function devices as independent - * devices. The slot/function address of each device is encoded - * in a single byte as follows: - * - * 7:3 = slot - * 2:0 = function - */ -#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) -#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) -#define PCI_FUNC(devfn) ((devfn) & 0x07) - -/* Ioctls for /proc/bus/pci/X/Y nodes. */ -#define PCIIOC_BASE ('P' << 24 | 'C' << 16 | 'I' << 8) -#define PCIIOC_CONTROLLER (PCIIOC_BASE | 0x00) /* Get controller for PCI device. */ -#define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01) /* Set mmap state to I/O space. */ -#define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */ -#define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */ - -#include -#include -#include -#include -#include - -/* File state for mmap()s on /proc/bus/pci/X/Y */ -enum pci_mmap_state { - pci_mmap_io, - pci_mmap_mem -}; - -/* This defines the direction arg to the DMA mapping routines. */ -#define PCI_DMA_BIDIRECTIONAL 0 -#define PCI_DMA_TODEVICE 1 -#define PCI_DMA_FROMDEVICE 2 -#define PCI_DMA_NONE 3 - -#define DEVICE_COUNT_COMPATIBLE 4 -#define DEVICE_COUNT_IRQ 2 -#define DEVICE_COUNT_DMA 2 -#define DEVICE_COUNT_RESOURCE 12 - -#define PCI_ANY_ID (~0) - -#define pci_present pcibios_present - - -#define pci_for_each_dev_reverse(dev) \ - for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev)) - -#define pci_for_each_bus(bus) \ - list_for_each_entry(bus, &pci_root_buses, node) - -/* - * The pci_dev structure is used to describe both PCI and ISAPnP devices. - */ -struct pci_dev { - struct list_head global_list; /* node in list of all PCI devices */ - struct list_head bus_list; /* node in per-bus list */ - struct pci_bus *bus; /* bus this device is on */ - struct pci_bus *subordinate; /* bus this device bridges to */ - - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */ - - unsigned int devfn; /* encoded device & function index */ - unsigned short vendor; - unsigned short device; - unsigned short subsystem_vendor; - unsigned short subsystem_device; - unsigned int class; /* 3 bytes: (base,sub,prog-if) */ - u8 hdr_type; /* PCI header type (`multi' flag masked out) */ - u8 rom_base_reg; /* which config register controls the ROM */ - - struct pci_driver *driver; /* which driver has allocated this device */ - void *driver_data; /* data private to the driver */ - u64 dma_mask; /* Mask of the bits of bus address this - device implements. Normally this is - 0xffffffff. You only need to change - this if your device has broken DMA - or supports 64-bit transfers. */ - - u32 current_state; /* Current operating state. In ACPI-speak, - this is D0-D3, D0 being fully functional, - and D3 being off. */ - -#ifdef LINUX_2_6 - struct device dev; /* Generic device interface */ -#endif - - /* device is compatible with these IDs */ - unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE]; - unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE]; - - /* - * Instead of touching interrupt line and base address registers - * directly, use the values stored here. They might be different! - */ - unsigned int irq; - struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ - struct resource dma_resource[DEVICE_COUNT_DMA]; - struct resource irq_resource[DEVICE_COUNT_IRQ]; - - char name[90]; /* device name */ - char slot_name[8]; /* slot name */ - int active; /* ISAPnP: device is active */ - int ro; /* ISAPnP: read only */ - unsigned short regs; /* ISAPnP: supported registers */ - - /* These fields are used by common fixups */ - unsigned short transparent:1; /* Transparent PCI bridge */ - - int (*prepare)(struct pci_dev *dev); /* ISAPnP hooks */ - int (*activate)(struct pci_dev *dev); - int (*deactivate)(struct pci_dev *dev); -}; - -#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list) -#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list) - -/* - * For PCI devices, the region numbers are assigned this way: - * - * 0-5 standard PCI regions - * 6 expansion ROM - * 7-10 bridges: address space assigned to buses behind the bridge - */ - -#define PCI_ROM_RESOURCE 6 -#define PCI_BRIDGE_RESOURCES 7 -#define PCI_NUM_RESOURCES 11 - -#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */ - -struct pci_bus { - struct list_head node; /* node in list of buses */ - struct pci_bus *parent; /* parent bus this bridge is on */ - struct list_head children; /* list of child buses */ - struct list_head devices; /* list of devices on this bus */ - struct pci_dev *self; /* bridge device as seen by parent */ - struct resource *resource[4]; /* address space routed to this bus */ - - struct pci_ops *ops; /* configuration access functions */ - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */ - - unsigned char number; /* bus number */ - unsigned char primary; /* number of primary bridge */ - unsigned char secondary; /* number of secondary bridge */ - unsigned char subordinate; /* max number of subordinate buses */ - - char name[48]; - unsigned short vendor; - unsigned short device; - unsigned int serial; /* serial number */ - unsigned char pnpver; /* Plug & Play version */ - unsigned char productver; /* product version */ - unsigned char checksum; /* if zero - checksum passed */ - unsigned char pad1; -}; - -#define pci_bus_b(n) list_entry(n, struct pci_bus, node) - -extern struct list_head pci_root_buses; /* list of all known PCI buses */ -extern struct list_head pci_devices; /* list of all devices */ - -extern struct proc_dir_entry *proc_bus_pci_dir; -/* - * Error values that may be returned by PCI functions. - */ -#define PCIBIOS_SUCCESSFUL 0x00 -#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 -#define PCIBIOS_BAD_VENDOR_ID 0x83 -#define PCIBIOS_DEVICE_NOT_FOUND 0x86 -#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 -#define PCIBIOS_SET_FAILED 0x88 -#define PCIBIOS_BUFFER_TOO_SMALL 0x89 - -/* Low-level architecture-dependent routines */ - -struct pci_ops { - int (*read_byte)(struct pci_dev *, int where, u8 *val); - int (*read_word)(struct pci_dev *, int where, u16 *val); - int (*read_dword)(struct pci_dev *, int where, u32 *val); - int (*write_byte)(struct pci_dev *, int where, u8 val); - int (*write_word)(struct pci_dev *, int where, u16 val); - int (*write_dword)(struct pci_dev *, int where, u32 val); -}; - -struct pbus_set_ranges_data -{ - unsigned long io_start, io_end; - unsigned long mem_start, mem_end; - unsigned long prefetch_start, prefetch_end; -}; - -struct pci_device_id { - unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ - unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ - unsigned long driver_data; /* Data private to the driver */ -}; - -struct pci_driver { - struct list_head node; - char *name; - const struct pci_device_id *id_table; /* NULL if wants all devices */ - int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ - void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ - int (*save_state) (struct pci_dev *dev, u32 state); /* Save Device Context */ - int (*suspend) (struct pci_dev *dev, u32 state); /* Device suspended */ - int (*resume) (struct pci_dev *dev); /* Device woken up */ - int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ -}; - -/** - * PCI_DEVICE - macro used to describe a specific pci device - * @vend: the 16 bit PCI Vendor ID - * @dev: the 16 bit PCI Device ID - * - * This macro is used to create a struct pci_device_id that matches a - * specific device. The subvendor and subdevice fields will be set to - * PCI_ANY_ID. - */ -#define PCI_DEVICE(vend,dev) \ - .vendor = (vend), .device = (dev), \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID - -/** - * PCI_DEVICE_CLASS - macro used to describe a specific pci device class - * @dev_class: the class, subclass, prog-if triple for this device - * @dev_class_mask: the class mask for this device - * - * This macro is used to create a struct pci_device_id that matches a - * specific PCI class. The vendor, device, subvendor, and subdevice - * fields will be set to PCI_ANY_ID. - */ -#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \ - .class = (dev_class), .class_mask = (dev_class_mask), \ - .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID - -/* these external functions are only available when PCI support is enabled */ -#ifdef CONFIG_PCI - -#define pci_for_each_dev(dev) \ - for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) - -void pcibios_init(void); -void pcibios_fixup_bus(struct pci_bus *); -int pcibios_enable_device(struct pci_dev *, int mask); -char *pcibios_setup (char *str); - -/* Used only when drivers/pci/setup.c is used */ -void pcibios_align_resource(void *, struct resource *, - unsigned long, unsigned long); -void pcibios_update_resource(struct pci_dev *, struct resource *, - struct resource *, int); -void pcibios_update_irq(struct pci_dev *, int irq); -void pcibios_fixup_pbus_ranges(struct pci_bus *, struct pbus_set_ranges_data *); - -/* Backward compatibility, don't use in new code! */ - -int pcibios_present(void); -int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char *val); -int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short *val); -int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int *val); -int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char val); -int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short val); -int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int val); -int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn); -int pcibios_find_device (unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus, - unsigned char *dev_fn); - -/* Generic PCI functions used internally */ - -void pci_init(void); -int pci_bus_exists(const struct list_head *list, int nr); -struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); -struct pci_bus *pci_alloc_primary_bus(int bus); -struct pci_dev *pci_scan_slot(struct pci_dev *temp); -int pci_proc_attach_device(struct pci_dev *dev); -int pci_proc_detach_device(struct pci_dev *dev); -int pci_proc_attach_bus(struct pci_bus *bus); -int pci_proc_detach_bus(struct pci_bus *bus); -void pci_name_device(struct pci_dev *dev); -char *pci_class_name(u32 class); -void pci_read_bridge_bases(struct pci_bus *child); -struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); -int pci_setup_device(struct pci_dev *dev); -int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); - -/* Generic PCI functions exported to card drivers */ - -struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); -struct pci_dev *pci_find_subsys (unsigned int vendor, unsigned int device, - unsigned int ss_vendor, unsigned int ss_device, - const struct pci_dev *from); -struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from); -struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); -int pci_find_capability (struct pci_dev *dev, int cap); - -int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val); -int pci_read_config_word(struct pci_dev *dev, int where, u16 *val); -int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val); -int pci_write_config_byte(struct pci_dev *dev, int where, u8 val); -int pci_write_config_word(struct pci_dev *dev, int where, u16 val); -int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); - -int pci_enable_device(struct pci_dev *dev); -int pci_enable_device_bars(struct pci_dev *dev, int mask); -void pci_disable_device(struct pci_dev *dev); -void pci_set_master(struct pci_dev *dev); -#define HAVE_PCI_SET_MWI -int pci_set_mwi(struct pci_dev *dev); -void pci_clear_mwi(struct pci_dev *dev); -int pci_set_dma_mask(struct pci_dev *dev, u64 mask); -int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask); -int pci_assign_resource(struct pci_dev *dev, int i); - -/* Power management related routines */ -int pci_save_state(struct pci_dev *dev, u32 *buffer); -int pci_restore_state(struct pci_dev *dev, u32 *buffer); -int pci_set_power_state(struct pci_dev *dev, int state); -int pci_enable_wake(struct pci_dev *dev, u32 state, int enable); - -/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ - -int pci_claim_resource(struct pci_dev *, int); -void pci_assign_unassigned_resources(void); -void pdev_enable_device(struct pci_dev *); -void pdev_sort_resources(struct pci_dev *, struct resource_list *); -unsigned long pci_bridge_check_io(struct pci_dev *); -void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), - int (*)(struct pci_dev *, u8, u8)); -#define HAVE_PCI_REQ_REGIONS 2 -int pci_request_regions(struct pci_dev *, char *); -void pci_release_regions(struct pci_dev *); -int pci_request_region(struct pci_dev *, int, char *); -void pci_release_region(struct pci_dev *, int); - -/* New-style probing supporting hot-pluggable devices */ -int pci_register_driver(struct pci_driver *); -void pci_unregister_driver(struct pci_driver *); -void pci_insert_device(struct pci_dev *, struct pci_bus *); -void pci_remove_device(struct pci_dev *); -struct pci_driver *pci_dev_driver(const struct pci_dev *); -const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); -void pci_announce_device_to_drivers(struct pci_dev *); -unsigned int pci_do_scan_bus(struct pci_bus *bus); -struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); - -#if 0 -/* xmem_cache style wrapper around pci_alloc_consistent() */ -struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev, - size_t size, size_t align, size_t allocation, int flags); -void pci_pool_destroy (struct pci_pool *pool); - -void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle); -void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr); -#endif - -#endif /* CONFIG_PCI */ - -/* Include architecture-dependent settings and functions */ - -#include - -/* - * If the system does not have PCI, clearly these return errors. Define - * these as simple inline functions to avoid hair in drivers. - */ - -#ifndef CONFIG_PCI -static inline int pcibios_present(void) { return 0; } -static inline int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn) -{ return PCIBIOS_DEVICE_NOT_FOUND; } - -#define _PCI_NOP(o,s,t) \ - static inline int pcibios_##o##_config_##s (u8 bus, u8 dfn, u8 where, t val) \ - { return PCIBIOS_FUNC_NOT_SUPPORTED; } \ - static inline int pci_##o##_config_##s (struct pci_dev *dev, int where, t val) \ - { return PCIBIOS_FUNC_NOT_SUPPORTED; } -#define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \ - _PCI_NOP(o,word,u16 x) \ - _PCI_NOP(o,dword,u32 x) -_PCI_NOP_ALL(read, *) -_PCI_NOP_ALL(write,) - -static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) -{ return NULL; } - -static inline struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from) -{ return NULL; } - -static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) -{ return NULL; } - -static inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device, -unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) -{ return NULL; } - -static inline void pci_set_master(struct pci_dev *dev) { } -static inline int pci_enable_device_bars(struct pci_dev *dev, int mask) { return -EBUSY; } -static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } -static inline void pci_disable_device(struct pci_dev *dev) { } -static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } -static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } -static inline int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } -static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} -static inline int pci_register_driver(struct pci_driver *drv) { return 0;} -static inline void pci_unregister_driver(struct pci_driver *drv) { } -static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } -static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } -static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } - -/* Power management related routines */ -static inline int pci_save_state(struct pci_dev *dev, u32 *buffer) { return 0; } -static inline int pci_restore_state(struct pci_dev *dev, u32 *buffer) { return 0; } -static inline int pci_set_power_state(struct pci_dev *dev, int state) { return 0; } -static inline int pci_enable_wake(struct pci_dev *dev, u32 state, int enable) { return 0; } - -#define pci_for_each_dev(dev) \ - for(dev = NULL; 0; ) - -#else - -/* - * a helper function which helps ensure correct pci_driver - * setup and cleanup for commonly-encountered hotplug/modular cases - * - * This MUST stay in a header, as it checks for -DMODULE - */ -static inline int pci_module_init(struct pci_driver *drv) -{ - int rc = pci_register_driver (drv); - - if (rc > 0) - return 0; - - /* iff CONFIG_HOTPLUG and built into kernel, we should - * leave the driver around for future hotplug events. - * For the module case, a hotplug daemon of some sort - * should load a module in response to an insert event. */ -#if defined(CONFIG_HOTPLUG) && !defined(MODULE) - if (rc == 0) - return 0; -#else - if (rc == 0) - rc = -ENODEV; -#endif - - /* if we get here, we need to clean up pci driver instance - * and return some sort of error */ - pci_unregister_driver (drv); - - return rc; -} - -#endif /* !CONFIG_PCI */ - -/* these helpers provide future and backwards compatibility - * for accessing popular PCI BAR info */ -#define pci_resource_start(dev,bar) ((dev)->resource[(bar)].start) -#define pci_resource_end(dev,bar) ((dev)->resource[(bar)].end) -#define pci_resource_flags(dev,bar) ((dev)->resource[(bar)].flags) -#define pci_resource_len(dev,bar) \ - ((pci_resource_start((dev),(bar)) == 0 && \ - pci_resource_end((dev),(bar)) == \ - pci_resource_start((dev),(bar))) ? 0 : \ - \ - (pci_resource_end((dev),(bar)) - \ - pci_resource_start((dev),(bar)) + 1)) - -/* Similar to the helpers above, these manipulate per-pci_dev - * driver-specific data. Currently stored as pci_dev::driver_data, - * a void pointer, but it is not present on older kernels. - */ -static inline void *pci_get_drvdata (struct pci_dev *pdev) -{ - return pdev->driver_data; -} - -static inline void pci_set_drvdata (struct pci_dev *pdev, void *data) -{ - pdev->driver_data = data; -} - -static inline char *pci_name(struct pci_dev *pdev) -{ - return pdev->slot_name; -} - -/* - * The world is not perfect and supplies us with broken PCI devices. - * For at least a part of these bugs we need a work-around, so both - * generic (drivers/pci/quirks.c) and per-architecture code can define - * fixup hooks to be called for particular buggy devices. - */ - -struct pci_fixup { - int pass; - u16 vendor, device; /* You can use PCI_ANY_ID here of course */ - void (*hook)(struct pci_dev *dev); -}; - -extern struct pci_fixup pcibios_fixups[]; - -#define PCI_FIXUP_HEADER 1 /* Called immediately after reading configuration header */ -#define PCI_FIXUP_FINAL 2 /* Final phase of device fixups */ - -void pci_fixup_device(int pass, struct pci_dev *dev); - -extern int pci_pci_problems; -#define PCIPCI_FAIL 1 -#define PCIPCI_TRITON 2 -#define PCIPCI_NATOMA 4 -#define PCIPCI_VIAETBF 8 -#define PCIPCI_VSFX 16 -#define PCIPCI_ALIMAGIK 32 - -#endif /* LINUX_PCI_H */ diff --git a/xen/include/xen/perfc.h b/xen/include/xen/perfc.h index 6d758497b1..48c7e90fb4 100644 --- a/xen/include/xen/perfc.h +++ b/xen/include/xen/perfc.h @@ -87,6 +87,7 @@ extern struct perfcounter perfcounters; * Histogram: special treatment for 0 and 1 count. After that equally spaced * with last bucket taking the rest. */ +#ifdef PERFC_ARRAYS #define perfc_incr_histo(_x,_v,_n) \ do { \ if ( (_v) == 0 ) \ @@ -99,6 +100,9 @@ extern struct perfcounter perfcounters; else \ perfc_incra(_x, PERFC_MAX_ ## _n - 1); \ } while ( 0 ) +#else +#define perfc_incr_histo(_x,_v,_n) ((void)0) +#endif #else /* PERF_COUNTERS */ diff --git a/xen/include/xen/perfc_defn.h b/xen/include/xen/perfc_defn.h index 501851ec55..c7f2493a1a 100644 --- a/xen/include/xen/perfc_defn.h +++ b/xen/include/xen/perfc_defn.h @@ -86,12 +86,14 @@ PERFCOUNTER_CPU(resync_hl2, "resync HL2 page") PERFCOUNTER_CPU(shadow_make_snapshot, "snapshots created") PERFCOUNTER_CPU(shadow_mark_mfn_out_of_sync_calls, "calls to shadow_mk_out_of_sync") PERFCOUNTER_CPU(shadow_out_of_sync_calls, "calls to shadow_out_of_sync") -PERFCOUNTER_CPU(extra_va_update_sync, "extra syncs for bug in chk_pgtb") PERFCOUNTER_CPU(snapshot_entry_matches_calls, "calls to ss_entry_matches") PERFCOUNTER_CPU(snapshot_entry_matches_true, "ss_entry_matches returns true") PERFCOUNTER_CPU(validate_pte_calls, "calls to validate_pte_change") -PERFCOUNTER_CPU(validate_pte_changes, "validate_pte makes changes") +PERFCOUNTER_CPU(validate_pte_changes1, "validate_pte makes changes1") +PERFCOUNTER_CPU(validate_pte_changes2, "validate_pte makes changes2") +PERFCOUNTER_CPU(validate_pte_changes3, "validate_pte makes changes3") +PERFCOUNTER_CPU(validate_pte_changes4, "validate_pte makes changes4") PERFCOUNTER_CPU(validate_pde_calls, "calls to validate_pde_change") PERFCOUNTER_CPU(validate_pde_changes, "validate_pde makes changes") PERFCOUNTER_CPU(shadow_get_page_fail, "shadow_get_page_from_l1e fails" ) diff --git a/xen/include/xen/sched-if.h b/xen/include/xen/sched-if.h index 3e352f4fe8..7cd5295fea 100644 --- a/xen/include/xen/sched-if.h +++ b/xen/include/xen/sched-if.h @@ -8,6 +8,10 @@ #ifndef __XEN_SCHED_IF_H__ #define __XEN_SCHED_IF_H__ +//#define ADV_SCHED_HISTO +#define BUCKETS 10 +/*300*/ + struct schedule_data { spinlock_t schedule_lock; /* spinlock protecting curr */ struct exec_domain *curr; /* current task */ @@ -15,6 +19,11 @@ struct schedule_data { void *sched_priv; struct ac_timer s_timer; /* scheduling timer */ unsigned long tick; /* current periodic 'tick' */ +#ifdef ADV_SCHED_HISTO + u32 to_hist[BUCKETS]; + u32 from_hist[BUCKETS]; + u64 save_tsc; +#endif #ifdef BUCKETS u32 hist[BUCKETS]; /* for scheduler latency histogram */ #endif diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 266e34e8ec..6f64e0c057 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -60,13 +60,14 @@ int init_exec_domain_event_channels(struct exec_domain *ed); struct exec_domain { - u32 processor; + int id; - vcpu_info_t *vcpu_info; + int processor; - struct domain *domain; - struct exec_domain *ed_next_list; - int eid; + vcpu_info_t *vcpu_info; + + struct domain *domain; + struct exec_domain *next_in_list; struct ac_timer timer; /* one-shot timer for timeout values */ unsigned long sleep_tick; /* tick at which this vcpu started sleep */ @@ -75,13 +76,13 @@ struct exec_domain s_time_t lastdeschd; /* time this domain was last descheduled */ s_time_t cpu_time; /* total CPU time received till now */ s_time_t wokenup; /* time domain got woken up */ - void *ed_sched_priv; /* scheduler-specific data */ + void *sched_priv; /* scheduler-specific data */ - unsigned long ed_flags; + unsigned long flags; - u16 virq_to_evtchn[NR_VIRQS]; + u16 virq_to_evtchn[NR_VIRQS]; - atomic_t pausecnt; + atomic_t pausecnt; struct arch_exec_domain arch; }; @@ -111,14 +112,15 @@ struct domain int shutdown_code; /* code value from OS (if DF_SHUTDOWN). */ void *sched_priv; /* scheduler-specific data */ - struct domain *next_list, *next_hash; + struct domain *next_in_list; + struct domain *next_in_hashbucket; /* Event channel information. */ event_channel_t *event_channel; unsigned int max_event_channel; spinlock_t event_channel_lock; - grant_table_t *grant_table; + grant_table_t *grant_table; /* * Interrupt to event-channel mappings. Updates should be protected by the @@ -126,13 +128,13 @@ struct domain * the lock, but races don't usually matter. */ #define NR_PIRQS 128 /* Put this somewhere sane! */ - u16 pirq_to_evtchn[NR_PIRQS]; - u32 pirq_mask[NR_PIRQS/32]; + u16 pirq_to_evtchn[NR_PIRQS]; + u32 pirq_mask[NR_PIRQS/32]; - unsigned long d_flags; - unsigned long vm_assist; + unsigned long flags; + unsigned long vm_assist; - atomic_t refcnt; + atomic_t refcnt; struct exec_domain *exec_domain[MAX_VIRT_CPUS]; @@ -166,7 +168,7 @@ extern struct exec_domain idle0_exec_domain; extern struct exec_domain *idle_task[NR_CPUS]; #define IDLE_DOMAIN_ID (0x7FFFU) -#define is_idle_task(_p) (test_bit(DF_IDLETASK, &(_p)->d_flags)) +#define is_idle_task(_p) (test_bit(DF_IDLETASK, &(_p)->flags)) struct exec_domain *alloc_exec_domain_struct(struct domain *d, unsigned long vcpu); @@ -315,35 +317,36 @@ extern struct domain *domain_hash[DOMAIN_HASH_SIZE]; extern struct domain *domain_list; #define for_each_domain(_d) \ - for ( (_d) = domain_list; (_d) != NULL; (_d) = (_d)->next_list ) + for ( (_d) = domain_list; (_d) != NULL; (_d) = (_d)->next_in_list ) #define for_each_exec_domain(_d,_ed) \ for ( (_ed) = (_d)->exec_domain[0]; \ (_ed) != NULL; \ - (_ed) = (_ed)->ed_next_list ) + (_ed) = (_ed)->next_in_list ) #define EDF_DONEFPUINIT 0 /* Has the FPU been initialised for this task? */ #define EDF_USEDFPU 1 /* Has this task used the FPU since last save? */ #define EDF_GUEST_STTS 2 /* Has the guest OS requested 'stts'? */ -#define DF_CONSTRUCTED 3 /* Has the guest OS been fully built yet? */ -#define DF_IDLETASK 4 /* Is this one of the per-CPU idle domains? */ -#define DF_PRIVILEGED 5 /* Is this domain privileged? */ -#define DF_PHYSDEV 6 /* May this domain do IO to physical devices? */ -#define EDF_BLOCKED 7 /* Domain is blocked waiting for an event. */ -#define EDF_CTRLPAUSE 8 /* Domain is paused by controller software. */ -#define DF_SHUTDOWN 9 /* Guest shut itself down for some reason. */ -#define DF_CRASHED 10 /* Domain crashed inside Xen, cannot continue. */ -#define DF_DYING 11 /* Death rattle. */ -#define EDF_RUNNING 12 /* Currently running on a CPU. */ -#define EDF_CPUPINNED 13 /* Disables auto-migration. */ -#define EDF_MIGRATED 14 /* Domain migrated between CPUs. */ -#define EDF_DONEINIT 15 /* Initialization completed . */ +#define EDF_BLOCKED 3 /* Domain is blocked waiting for an event. */ +#define EDF_CTRLPAUSE 4 /* Domain is paused by controller software. */ +#define EDF_RUNNING 5 /* Currently running on a CPU. */ +#define EDF_CPUPINNED 6 /* Disables auto-migration. */ +#define EDF_MIGRATED 7 /* Domain migrated between CPUs. */ +#define EDF_DONEINIT 8 /* Initialization completed . */ -static inline int domain_runnable(struct exec_domain *d) +#define DF_CONSTRUCTED 0 /* Has the guest OS been fully built yet? */ +#define DF_IDLETASK 1 /* Is this one of the per-CPU idle domains? */ +#define DF_PRIVILEGED 2 /* Is this domain privileged? */ +#define DF_PHYSDEV 3 /* May this domain do IO to physical devices? */ +#define DF_SHUTDOWN 4 /* Guest shut itself down for some reason. */ +#define DF_CRASHED 5 /* Domain crashed inside Xen, cannot continue. */ +#define DF_DYING 6 /* Death rattle. */ + +static inline int domain_runnable(struct exec_domain *ed) { - return ( (atomic_read(&d->pausecnt) == 0) && - !(d->ed_flags & ((1<domain->d_flags & ((1<pausecnt) == 0) && + !(ed->flags & ((1<domain->flags & ((1<ed_flags) ) + if ( test_and_clear_bit(EDF_BLOCKED, &ed->flags) ) domain_wake(ed); } @@ -396,7 +399,7 @@ static inline void domain_pause_by_systemcontroller(struct domain *d) for_each_exec_domain ( d, ed ) { ASSERT(ed != current); - if ( !test_and_set_bit(EDF_CTRLPAUSE, &ed->ed_flags) ) + if ( !test_and_set_bit(EDF_CTRLPAUSE, &ed->flags) ) domain_sleep(ed); } @@ -409,14 +412,14 @@ static inline void domain_unpause_by_systemcontroller(struct domain *d) for_each_exec_domain ( d, ed ) { - if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->ed_flags) ) + if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->flags) ) domain_wake(ed); } } -#define IS_PRIV(_d) (test_bit(DF_PRIVILEGED, &(_d)->d_flags)) -#define IS_CAPABLE_PHYSDEV(_d) (test_bit(DF_PHYSDEV, &(_d)->d_flags)) +#define IS_PRIV(_d) (test_bit(DF_PRIVILEGED, &(_d)->flags)) +#define IS_CAPABLE_PHYSDEV(_d) (test_bit(DF_PHYSDEV, &(_d)->flags)) #define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist)) diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 01e5236dd5..51a0d1a1f2 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -11,9 +11,79 @@ #ifndef __XEN_SERIAL_H__ #define __XEN_SERIAL_H__ +#include #include #include +/* Register offsets */ +#define RBR 0x00 /* receive buffer */ +#define THR 0x00 /* transmit holding */ +#define IER 0x01 /* interrupt enable */ +#define IIR 0x02 /* interrupt identity */ +#define FCR 0x02 /* FIFO control */ +#define LCR 0x03 /* line control */ +#define MCR 0x04 /* Modem control */ +#define LSR 0x05 /* line status */ +#define MSR 0x06 /* Modem status */ +#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */ +#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */ + +/* Interrupt Enable Register */ +#define IER_ERDAI 0x01 /* rx data recv'd */ +#define IER_ETHREI 0x02 /* tx reg. empty */ +#define IER_ELSI 0x04 /* rx line status */ +#define IER_EMSI 0x08 /* MODEM status */ + +/* FIFO control register */ +#define FCR_ENABLE 0x01 /* enable FIFO */ +#define FCR_CLRX 0x02 /* clear Rx FIFO */ +#define FCR_CLTX 0x04 /* clear Tx FIFO */ +#define FCR_DMA 0x10 /* enter DMA mode */ +#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ +#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ +#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ +#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ + +/* Line control register */ +#define LCR_DLAB 0x80 /* Divisor Latch Access */ + +/* Modem Control Register */ +#define MCR_DTR 0x01 /* Data Terminal Ready */ +#define MCR_RTS 0x02 /* Request to Send */ +#define MCR_OUT2 0x08 /* OUT2: interrupt mask */ + +/* Line Status Register */ +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit hold reg empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +/* These parity settings can be ORed directly into the LCR. */ +#define PARITY_NONE (0<<3) +#define PARITY_ODD (1<<3) +#define PARITY_EVEN (3<<3) +#define PARITY_MARK (5<<3) +#define PARITY_SPACE (7<<3) + +/* Register a character-receive hook on the specified COM port. */ +typedef void (*serial_rx_fn)(unsigned char, struct cpu_user_regs *); +void serial_set_rx_handler(int handle, serial_rx_fn fn); + +#define RXBUFSZ 32 +#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1)) +struct uart { + int baud, data_bits, parity, stop_bits, io_base, irq; + serial_rx_fn rx_lo, rx_hi, rx; + spinlock_t lock; + unsigned char rxbuf[RXBUFSZ]; + unsigned int rxbufp, rxbufc; + struct irqaction irqaction; +}; + /* 'Serial handles' are comprise the following fields. */ #define SERHND_IDX (1<<0) /* COM1 or COM2? */ #define SERHND_HI (1<<1) /* Mux/demux each transferred char by MSB. */ @@ -27,10 +97,6 @@ void serial_init_stage2(void); /* Takes a config string and creates a numeric handle on the COM port. */ int parse_serial_handle(char *conf); -/* Register a character-receive hook on the specified COM port. */ -typedef void (*serial_rx_fn)(unsigned char, struct cpu_user_regs *); -void serial_set_rx_handler(int handle, serial_rx_fn fn); - /* Transmit a single character via the specified COM port. */ void serial_putc(int handle, unsigned char c); diff --git a/xen/include/xen/slab.h b/xen/include/xen/slab.h index c4c8231f78..a3a7daf7d6 100644 --- a/xen/include/xen/slab.h +++ b/xen/include/xen/slab.h @@ -3,12 +3,7 @@ #define __SLAB_H__ #include - -#ifdef __ARCH_HAS_SLAB_ALLOCATOR - -#include - -#else +#include /* Allocate space for typed object. */ #define xmalloc(_type) ((_type *)_xmalloc(sizeof(_type), __alignof__(_type))) @@ -32,6 +27,4 @@ static inline void *_xmalloc_array(size_t size, size_t align, size_t num) return _xmalloc(size * num, align); } -#endif /* __ARCH_HAS_SLAB_ALLOCATOR */ - #endif /* __SLAB_H__ */ diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h index df80e23295..811e25ac24 100644 --- a/xen/include/xen/smp.h +++ b/xen/include/xen/smp.h @@ -46,6 +46,17 @@ extern void smp_commence(void); extern int smp_call_function( void (*func) (void *info), void *info, int retry, int wait); +/* + * Call a function on all processors + */ +static inline int on_each_cpu(void (*func) (void *info), void *info, + int retry, int wait) +{ + int ret = smp_call_function(func, info, retry, wait); + func(info); + return ret; +} + /* * True once the per process idle is forked */ @@ -85,7 +96,15 @@ extern volatile int smp_msg_id; #define cpu_logical_map(cpu) 0 #define cpu_number_map(cpu) 0 #define smp_call_function(func,info,retry,wait) 0 +#define on_each_cpu(func,info,retry,wait) ({ func(info); 0; }) #define cpu_online_map 1 #endif + +#ifdef __smp_processor_id +#define smp_processor_id() __smp_processor_id() +#else +extern unsigned int smp_processor_id(void); +#endif + #endif diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h index ef58ba591b..73184daad8 100644 --- a/xen/include/xen/spinlock.h +++ b/xen/include/xen/spinlock.h @@ -82,4 +82,7 @@ typedef struct { int gcc_is_buggy; } rwlock_t; #define write_lock(_lock) _raw_write_lock(_lock) #define write_unlock(_lock) _raw_write_unlock(_lock) +#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED +#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED + #endif /* __SPINLOCK_H__ */ diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h index cd55353dfe..6258a745cf 100644 --- a/xen/include/xen/types.h +++ b/xen/include/xen/types.h @@ -1,8 +1,14 @@ #ifndef __TYPES_H__ #define __TYPES_H__ +#include #include +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + #ifndef NULL #define NULL ((void*)0) #endif