Index: sys/arch/amd64/conf/XEN3_DOM0 =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/conf/XEN3_DOM0,v retrieving revision 1.42 diff -u -p -r1.42 XEN3_DOM0 --- sys/arch/amd64/conf/XEN3_DOM0 20 Apr 2009 20:50:37 -0000 1.42 +++ sys/arch/amd64/conf/XEN3_DOM0 18 May 2009 14:48:49 -0000 @@ -42,6 +42,7 @@ options SYSCTL_INCLUDE_DESCR # Include # Diagnostic/debugging support options options DIAGNOSTIC # expensive kernel consistency checks options DEBUG # expensive debugging checks/support +options LOCKDEBUG options KMEMSTATS # kernel memory statistics (vmstat -m) options DDB # in-kernel debugger options DDB_ONPANIC=1 # see also sysctl(8): `ddb.onpanic' @@ -137,7 +138,8 @@ options IPFILTER_LOOKUP # ippool(8) sup #options ALTQ_WFQ # Weighted Fair Queueing options NFS_BOOT_DHCP,NFS_BOOT_BOOTPARAM -#options NFS_BOOT_BOOTSTATIC +options NFS_BOOT_BOOTSTATIC +options NFS_BOOT_RWSIZE=16384 #options NFS_BOOTSTATIC_MYIP="\"169.254.1.2\"" #options NFS_BOOTSTATIC_GWIP="\"169.254.1.1\"" #options NFS_BOOTSTATIC_MASK="\"255.255.255.0\"" @@ -204,8 +206,8 @@ options MPBIOS_SCANPCI # MPBIOS config #options PCI_ADDR_FIXUP # fixup PCI I/O addresses #options PCI_BUS_FIXUP # fixup PCI bus numbering #options PCI_INTR_FIXUP # fixup PCI interrupt routing -#options PCIVERBOSE # verbose PCI device autoconfig messages -#options USBVERBOSE # verbose USB device autoconfig messages +options PCIVERBOSE # verbose PCI device autoconfig messages +options USBVERBOSE # verbose USB device autoconfig messages ioapic* at mainbus? apid ? Index: sys/arch/x86/include/cpu.h =================================================================== RCS file: /cvsroot/src/sys/arch/x86/include/cpu.h,v retrieving revision 1.17 diff -u -p -r1.17 cpu.h --- sys/arch/x86/include/cpu.h 30 Apr 2009 00:07:23 -0000 1.17 +++ sys/arch/x86/include/cpu.h 18 May 2009 14:48:49 -0000 @@ -375,6 +375,7 @@ void child_trampoline(void); void startrtclock(void); void xen_delay(unsigned int); void xen_initclocks(void); +void xen_suspendclocks(void); #else /* clock.c */ void initrtclock(u_long); Index: sys/arch/xen/include/evtchn.h =================================================================== RCS file: /cvsroot/src/sys/arch/xen/include/evtchn.h,v retrieving revision 1.17 diff -u -p -r1.17 evtchn.h --- sys/arch/xen/include/evtchn.h 24 Oct 2008 21:09:24 -0000 1.17 +++ sys/arch/xen/include/evtchn.h 18 May 2009 14:48:49 -0000 @@ -40,6 +40,9 @@ extern struct evtsource *evtsource[]; void events_default_setup(void); void events_init(void); +bool events_suspend(void); +bool events_resume(void); + unsigned int evtchn_do_event(int, struct intrframe *); void call_evtchn_do_event(int, struct intrframe *); void call_xenevt_event(int); Index: sys/arch/xen/include/granttables.h =================================================================== RCS file: /cvsroot/src/sys/arch/xen/include/granttables.h,v retrieving revision 1.6 diff -u -p -r1.6 granttables.h --- sys/arch/xen/include/granttables.h 30 Oct 2008 09:24:37 -0000 1.6 +++ sys/arch/xen/include/granttables.h 18 May 2009 14:48:49 -0000 @@ -35,6 +35,10 @@ void xengnt_init(void); +/* suspend/resume grant table, for save/restore operations */ +bool xengnt_suspend(void); +bool xengnt_resume(void); + /* * grant access to a remote domain. Returns a handle on the allocated grant * entry in table in grant_ref_t *. Index: sys/arch/xen/include/hypervisor.h =================================================================== RCS file: /cvsroot/src/sys/arch/xen/include/hypervisor.h,v retrieving revision 1.29 diff -u -p -r1.29 hypervisor.h --- sys/arch/xen/include/hypervisor.h 13 Nov 2008 18:44:51 -0000 1.29 +++ sys/arch/xen/include/hypervisor.h 18 May 2009 14:48:49 -0000 @@ -153,6 +153,7 @@ void hypervisor_clear_event(unsigned int void hypervisor_enable_ipl(unsigned int); void hypervisor_set_ipending(uint32_t, int, int); void hypervisor_machdep_attach(void); +void hypervisor_machdep_resume(void); /* * Force a proper event-channel callback from Xen after clearing the Index: sys/arch/xen/include/xen.h =================================================================== RCS file: /cvsroot/src/sys/arch/xen/include/xen.h,v retrieving revision 1.31 diff -u -p -r1.31 xen.h --- sys/arch/xen/include/xen.h 13 Feb 2009 21:03:59 -0000 1.31 +++ sys/arch/xen/include/xen.h 18 May 2009 14:48:49 -0000 @@ -69,6 +69,9 @@ void xenevt_notify(void); void idle_block(void); +/* xen_machdep.c */ +void sysctl_xen_sleepstate_setup(void); + #if defined(XENDEBUG) || 1 /* XXX */ void printk(const char *, ...); void vprintk(const char *, _BSD_VA_LIST_); Index: sys/arch/xen/include/xenpmap.h =================================================================== RCS file: /cvsroot/src/sys/arch/xen/include/xenpmap.h,v retrieving revision 1.22 diff -u -p -r1.22 xenpmap.h --- sys/arch/xen/include/xenpmap.h 10 Mar 2009 20:05:31 -0000 1.22 +++ sys/arch/xen/include/xenpmap.h 18 May 2009 14:48:49 -0000 @@ -68,6 +68,11 @@ extern unsigned long *xpmap_phys_to_mach #define mfn_to_pfn(mfn) (machine_to_phys_mapping[(mfn)]) #define pfn_to_mfn(pfn) (xpmap_phys_to_machine_mapping[(pfn)]) +void xen_init_ptom_lock(void); +void xen_acquire_reader_ptom_lock(void); +void xen_acquire_writer_ptom_lock(void); +void xen_release_ptom_lock(void); + static __inline paddr_t xpmap_mtop(paddr_t mpa) { Index: sys/arch/xen/x86/cpu.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/x86/cpu.c,v retrieving revision 1.31 diff -u -p -r1.31 cpu.c --- sys/arch/xen/x86/cpu.c 23 Dec 2008 20:06:16 -0000 1.31 +++ sys/arch/xen/x86/cpu.c 18 May 2009 14:48:50 -0000 @@ -85,6 +85,7 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.31 #include #include #include +#include #include @@ -124,9 +125,15 @@ void vcpu_attach(device_t, device_t, void cpu_attach_common(device_t, device_t, void *); void cpu_offline_md(void); +#if 0 +static bool cpu_suspend(device_t PMF_FN_PROTO); +static bool cpu_resume(device_t PMF_FN_PROTO); +#endif + struct cpu_softc { device_t sc_dev; /* device tree glue */ struct cpu_info *sc_info; /* pointer to CPU info */ + bool sc_wasonline; }; int mp_cpu_start(struct cpu_info *, paddr_t); @@ -233,12 +240,22 @@ cpu_attach(device_t parent, device_t sel * structure, otherwise use the primary's. */ if (caa->cpu_role == CPU_ROLE_AP) { + if ((boothowto & RB_MD1) != 0) { + aprint_error(": multiprocessor boot disabled\n"); + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, + "couldn't establish power handler\n"); + return; + } + aprint_naive(": Application Processor\n"); ci = kmem_zalloc(sizeof(*ci), KM_SLEEP); ci->ci_curldt = -1; if (phycpu_info[cpunum] != NULL) panic("cpu at apic id %d already attached?", cpunum); phycpu_info[cpunum] = ci; } else { + aprint_naive(": %s Processor\n", + caa->cpu_role == CPU_ROLE_SP ? "Single" : "Boot"); ci = &phycpu_info_primary; if (cpunum != 0) { phycpu_info[0] = NULL; @@ -275,6 +292,10 @@ cpu_attach(device_t parent, device_t sel default: panic("unknown processor type??\n"); } + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); + return; #else cpu_attach_common(parent, self, aux); @@ -298,6 +319,9 @@ vcpu_attach(device_t parent, device_t se struct vcpu_attach_args *vcaa = aux; cpu_attach_common(parent, self, &vcaa->vcaa_caa); + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); } #endif Index: sys/arch/xen/x86/hypervisor_machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/x86/hypervisor_machdep.c,v retrieving revision 1.11 diff -u -p -r1.11 hypervisor_machdep.c --- sys/arch/xen/x86/hypervisor_machdep.c 21 Oct 2008 15:46:32 -0000 1.11 +++ sys/arch/xen/x86/hypervisor_machdep.c 18 May 2009 14:48:50 -0000 @@ -391,6 +391,12 @@ hypervisor_machdep_attach(void) { } +void +hypervisor_machdep_resume(void) +{ + +} + #ifdef XEN3 /* * Generate the p2m_frame_list_list table, Index: sys/arch/xen/x86/mainbus.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/x86/mainbus.c,v retrieving revision 1.7 diff -u -p -r1.7 mainbus.c --- sys/arch/xen/x86/mainbus.c 18 Jan 2009 20:50:43 -0000 1.7 +++ sys/arch/xen/x86/mainbus.c 18 May 2009 14:48:50 -0000 @@ -216,6 +216,11 @@ mainbus_attach(device_t parent, device_t mba.mba_haa.haa_busname = "hypervisor"; config_found_ia(self, "hypervisorbus", &mba.mba_haa, mainbus_print); #endif + + /* save/restore for Xen */ + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); + } int Index: sys/arch/xen/xen/clock.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/clock.c,v retrieving revision 1.49 diff -u -p -r1.49 clock.c --- sys/arch/xen/xen/clock.c 16 Jan 2009 20:16:47 -0000 1.49 +++ sys/arch/xen/xen/clock.c 18 May 2009 14:48:50 -0000 @@ -486,6 +486,20 @@ xen_initclocks(void) #endif } +void +xen_suspendclocks(void) +{ + int evtch; + + evtch = unbind_virq_from_evtch(VIRQ_TIMER); + hypervisor_mask_event(evtch); + event_remove_handler(evtch, (int (*)(void *))xen_timer_handler, NULL); + + aprint_verbose("Xen clock: removed event channel %d\n", evtch); + + tc_detach(&xen_timecounter); +} + /* ARGSUSED */ static int xen_timer_handler(void *arg, struct intrframe *regs) Index: sys/arch/xen/xen/evtchn.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/evtchn.c,v retrieving revision 1.43 diff -u -p -r1.43 evtchn.c --- sys/arch/xen/xen/evtchn.c 27 Mar 2009 15:47:33 -0000 1.43 +++ sys/arch/xen/xen/evtchn.c 18 May 2009 14:48:50 -0000 @@ -205,6 +205,34 @@ events_init(void) x86_enable_intr(); /* at long last... */ } +bool +events_suspend(void) +{ + int evtch; + + x86_disable_intr(); + + /* VIRQ_DEBUG is the last interrupt to remove */ + evtch = unbind_virq_from_evtch(VIRQ_DEBUG); + hypervisor_mask_event(evtch); + + /* Remove the non-NULL value set in events_init() */ + evtsource[evtch] = NULL; + aprint_verbose("VIRQ_DEBUG interrupt disabled, event channel %d removed\n", + evtch); + + return true; +} + +bool +events_resume (void) +{ + events_init(); + + return true; +} + + unsigned int evtchn_do_event(int evtch, struct intrframe *regs) { Index: sys/arch/xen/xen/hypervisor.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/hypervisor.c,v retrieving revision 1.46 diff -u -p -r1.46 hypervisor.c --- sys/arch/xen/xen/hypervisor.c 18 Apr 2009 09:51:21 -0000 1.46 +++ sys/arch/xen/xen/hypervisor.c 18 May 2009 14:48:50 -0000 @@ -209,6 +209,12 @@ static struct sysmon_pswitch hysw_reboot }; #endif +#ifdef XEN3 +/* power management, for save/restore */ +static bool hypervisor_suspend(device_t PMF_FN_PROTO); +static bool hypervisor_resume(device_t PMF_FN_PROTO); +#endif + /* * Probe for the hypervisor; always succeeds. */ @@ -396,8 +402,37 @@ hypervisor_attach(device_t parent, devic #endif hypervisor_machdep_attach(); + +#ifdef XEN3 + if (!pmf_device_register(self, hypervisor_suspend, hypervisor_resume)) + aprint_error_dev(self, "couldn't establish power handler\n"); +#endif + } +#ifdef XEN3 +static bool +hypervisor_suspend(device_t dev PMF_FN_ARGS) +{ + events_suspend(); + xengnt_suspend(); + + return true; +} + +static bool +hypervisor_resume(device_t dev PMF_FN_ARGS) +{ + hypervisor_machdep_resume(); + + xengnt_resume(); + events_resume(); + + return true; +} +#endif + + static int hypervisor_print(void *aux, const char *parent) { Index: sys/arch/xen/xen/shutdown_xenbus.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/shutdown_xenbus.c,v retrieving revision 1.5 diff -u -p -r1.5 shutdown_xenbus.c --- sys/arch/xen/xen/shutdown_xenbus.c 24 Oct 2008 18:02:58 -0000 1.5 +++ sys/arch/xen/xen/shutdown_xenbus.c 18 May 2009 14:48:50 -0000 @@ -82,6 +82,10 @@ static struct sysmon_pswitch xenbus_rese .smpsw_type = PSWITCH_TYPE_RESET, .smpsw_name = "xenbus", }; +static struct sysmon_pswitch xenbus_sleep = { + .smpsw_type = PSWITCH_TYPE_SLEEP, + .smpsw_name = "xenbus", +}; static void xenbus_shutdown_handler(struct xenbus_watch *watch, const char **vec, @@ -130,8 +134,9 @@ again: sysmon_pswitch_event(&xenbus_power, PSWITCH_EVENT_PRESSED); } else if (strcmp(reqstr, "reboot") == 0) { sysmon_pswitch_event(&xenbus_reset, PSWITCH_EVENT_PRESSED); + } else if (strcmp(reqstr, "suspend") == 0) { + sysmon_pswitch_event(&xenbus_sleep, PSWITCH_EVENT_PRESSED); } else { - /* XXX suspend */ printf("ignore shutdown request: %s\n", reqstr); } free(reqstr, M_DEVBUF); @@ -147,7 +152,8 @@ shutdown_xenbus_setup(void) { if (sysmon_pswitch_register(&xenbus_power) != 0 || - sysmon_pswitch_register(&xenbus_reset) != 0) { + sysmon_pswitch_register(&xenbus_reset) != 0 || + sysmon_pswitch_register(&xenbus_sleep) != 0) { aprint_error("%s: unable to register with sysmon\n", __func__); return; } Index: sys/arch/xen/xen/xen_acpi_machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/xen_acpi_machdep.c,v retrieving revision 1.4 diff -u -p -r1.4 xen_acpi_machdep.c --- sys/arch/xen/xen/xen_acpi_machdep.c 17 Feb 2008 14:03:16 -0000 1.4 +++ sys/arch/xen/xen/xen_acpi_machdep.c 18 May 2009 14:48:50 -0000 @@ -10,9 +10,106 @@ __KERNEL_RCSID(0, "$NetBSD: xen_acpi_mac #define ACPI_MACHDEP_PRIVATE #include +static int +xen_dom0_sleepenter(int sleep_state, int pm1a_control, int pm1b_control) +{ + struct xen_platform_op op = { + .cmd = XENPF_enter_acpi_sleep, + .interface_version = XENPF_INTERFACE_VERSION, + .u = { + .enter_acpi_sleep = { + .pm1a_cnt_val = pm1a_control, + .pm1b_cnt_val = pm1b_control, + .sleep_state = sleep_state, + }, + }, + }; + + return HYPERVISOR_platform_op(&op); +} + +static ACPI_STATUS +acpi_md_get_pm1controls(uint32_t *pm1a_control, uint32_t *pm1b_control) +{ + ACPI_STATUS status = 0; + uint32_t pm1a, pm1b; + struct acpi_bit_register_info *sleep_type_reg_info; + struct acpi_bit_register_info *sleep_enable_reg_info; + + *pm1a_control = *pm1b_control = 0; + + sleep_type_reg_info = + AcpiHwGetBitRegisterInfo(ACPI_BITREG_SLEEP_TYPE_A); + sleep_enable_reg_info = + AcpiHwGetBitRegisterInfo(ACPI_BITREG_SLEEP_ENABLE); + + status = AcpiHwRegisterRead(ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_CONTROL, &pm1a); + if (ACPI_FAILURE(status)) + return status; + + /* Clear SLP_EN and SLP_TYP fields */ + pm1a &= ~(sleep_type_reg_info->AccessBitMask | + sleep_enable_reg_info->AccessBitMask); + pm1b = pm1a; + + /* Insert SLP_TYP bits */ + pm1a |= (AcpiGbl_SleepTypeA << sleep_type_reg_info->BitPosition); + pm1b |= (AcpiGbl_SleepTypeB << sleep_type_reg_info->BitPosition); + + /* Split the writes of SLP_TYP and SLP_EN to workaround + * poorly implemented hardware + */ + + /* Write #1: fill in SLP_TYP data */ + status = AcpiHwRegisterWrite(ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1A_CONTROL, + pm1a); + if (ACPI_FAILURE(status)) + return status; + + status = AcpiHwRegisterWrite(ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1B_CONTROL, + pm1b); + if (ACPI_FAILURE(status)) + return status; + + /* Insert SLP_ENABLE bit */ + + pm1a |= sleep_enable_reg_info->AccessBitMask; + pm1b |= sleep_enable_reg_info->AccessBitMask; + + ACPI_FLUSH_CPU_CACHE(); + + *pm1a_control = pm1a; + *pm1b_control = pm1b; + + return status; +} + int acpi_md_sleep(int state) { - printf("acpi: sleep not implemented\n"); - return (-1); + int error; + ACPI_STATUS status; + uint32_t pm1a_control, pm1b_control; + + /* XXX Xen version check: + * Xen <= 3.2 : no s3 support available. + * Xen >= 3.3 : s3 support present. + */ + + status = acpi_md_get_pm1controls(&pm1a_control, &pm1b_control); + if (ACPI_FAILURE(status)) { + printf("xenacpi: can't enter sleep mode. acpi error %i\n", + status); + return -1; + } + + printf("xenacpi: entering hypervisor for suspending\n"); + error = xen_dom0_sleepenter(state, pm1a_control, pm1b_control); + printf("xenacpi: resuming from hypervisor. Hypervisor returned code %i\n", + error); + + return error; } Index: sys/arch/xen/xen/xen_machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/xen_machdep.c,v retrieving revision 1.5 diff -u -p -r1.5 xen_machdep.c --- sys/arch/xen/xen/xen_machdep.c 13 Feb 2009 21:04:00 -0000 1.5 +++ sys/arch/xen/xen/xen_machdep.c 18 May 2009 14:48:50 -0000 @@ -73,13 +73,30 @@ __KERNEL_RCSID(0, "$NetBSD: xen_machdep. #include #include #include +#include +#include + +#include #include +#include +#include + +#define DPRINTK(x) printk x +#if 0 +#define DPRINTK(x) +#endif u_int tsc_get_timecount(struct timecounter *); uint64_t tsc_freq; /* XXX */ +#ifdef XEN3 +void xen_suspend_domain(int state); +static void xen_prepare_suspend(void); +static void xen_prepare_resume(void); +#endif + void xen_parse_cmdline(int what, union xen_cmdline_parseinfo *xcp) { @@ -214,3 +231,121 @@ tsc_get_timecount(struct timecounter *tc panic("xen: tsc_get_timecount"); } + +#ifdef XEN3 +/* + * Last operations before suspending domain + */ +static void +xen_prepare_suspend(void) +{ + kpreempt_disable(); + + xen_suspendclocks(); + + //xen_acquire_writer_ptom_lock(); + /* + * save/restore code does not translate these MFNs to their + * associated PFNs, so we must do it + */ + xen_start_info.store_mfn = mfn_to_pfn(xen_start_info.store_mfn); + xen_start_info.console_mfn = mfn_to_pfn(xen_start_info.console_mfn); + + DPRINTK(("suspending domain\n")); + aprint_verbose("suspending domain\n"); + + /* invalidate the shared_info page */ + if (HYPERVISOR_update_va_mapping((vaddr_t)HYPERVISOR_shared_info, + 0, UVMF_INVLPG)) { + DPRINTK(("HYPERVISOR_shared_info page invalidation failed")); + HYPERVISOR_crash(); + } +} + +/* + * First operations before restoring domain context + */ +static void +xen_prepare_resume(void) +{ + /* map the new shared_info page */ + if (HYPERVISOR_update_va_mapping((vaddr_t)HYPERVISOR_shared_info, + xen_start_info.shared_info | PG_RW | PG_V, + UVMF_INVLPG)) + { + DPRINTK(("could not map new shared info page")); + HYPERVISOR_crash(); + } + + if (xen_start_info.nr_pages != physmem) { + /* + * XXX JYM for now, we crash - fix it with balloon when + * supported + */ + DPRINTK(("xen_start_info.nr_pages != physmem")); + HYPERVISOR_crash(); + } + + //xen_release_ptom_lock(); + + DPRINTK(("preparing domain resume\n")); + aprint_verbose("preparing domain resume\n"); + + xen_initclocks(); + + kpreempt_enable(); +} + +void +xen_suspend_domain(int state) +{ + paddr_t mfn; + int s; + + KASSERT(!xendomain_is_dom0()); + + s = splvm(); + + /* + * console becomes unavailable when suspended, so + * direct communications to domain are hampered from there on. + * We can only rely on low level primitives like printk(), until + * console is fully restored + */ + if (!pmf_system_suspend(PMF_F_NONE)) { + DPRINTK(("devices suspend failed")); + HYPERVISOR_crash(); + } + + /* + * obtain the MFN of the start_info page now, as we will not be + * able to do it once pmap is locked + */ + pmap_extract_ma(pmap_kernel(), (vaddr_t)&xen_start_info, &mfn); + mfn >>= PAGE_SHIFT; + + xen_prepare_suspend(); + + DPRINTK(("calling HYPERVISOR_suspend()\n")); + if (HYPERVISOR_suspend(mfn) != 0) { + /* XXX JYM: implement checkpoint/snapshot (ret == 1) */ + DPRINTK(("HYPERVISOR_suspend() failed")); + HYPERVISOR_crash(); + } + + DPRINTK(("left HYPERVISOR_suspend()\n")); + xen_prepare_resume(); + + DPRINTK(("resuming devices\n")); + if (!pmf_system_resume(PMF_F_NONE)) { + DPRINTK(("devices resume failed\n")); + HYPERVISOR_crash(); + } + + splx(s); + + /* xencons is back online, we can print to console */ + aprint_verbose("domain resumed\n"); + +} +#endif Index: sys/arch/xen/xen/xencons.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/xencons.c,v retrieving revision 1.31 diff -u -p -r1.31 xencons.c --- sys/arch/xen/xen/xencons.c 16 Jan 2009 20:16:47 -0000 1.31 +++ sys/arch/xen/xen/xencons.c 18 May 2009 14:48:50 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: xencons.c,v 1.31 2009/01/16 20:16:47 jym Exp $ */ +/* $NetBSD: xencons.c,v 1.31.2.1 2009/02/09 00:03:55 jym Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -63,7 +63,7 @@ #include -__KERNEL_RCSID(0, "$NetBSD: xencons.c,v 1.31 2009/01/16 20:16:47 jym Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xencons.c,v 1.31.2.1 2009/02/09 00:03:55 jym Exp $"); #include "opt_xen.h" @@ -152,6 +152,9 @@ const struct cdevsw xencons_cdevsw = { #ifdef XEN3 static int xencons_handler(void *); +/* power management, for save/restore */ +static bool xencons_suspend(device_t PMF_FN_PROTO); +static bool xencons_resume(device_t PMF_FN_PROTO); #else static void xencons_rx(ctrl_msg_t *, unsigned long); #endif @@ -210,31 +213,74 @@ xencons_attach(device_t parent, device_t /* Set db_max_line to avoid paging. */ db_max_line = 0x7fffffff; #endif + xencons_console_device = sc; - if (xendomain_is_dom0()) { - int evtch = bind_virq_to_evtch(VIRQ_CONSOLE); - aprint_verbose_dev(self, "using event channel %d\n", - evtch); - if (event_set_handler(evtch, xencons_intr, sc, - IPL_TTY, "xencons") != 0) - printf("console: " - "can't register xencons_intr\n"); - hypervisor_enable_event(evtch); - } else { + xencons_resume(self, PMF_F_NONE); + } + sc->polling = 0; + + if (!pmf_device_register(self, xencons_suspend, xencons_resume)) + aprint_error_dev(self, "couldn't establish power handler\n"); +} + +static bool +xencons_suspend(device_t dev PMF_FN_ARGS) +{ + int evtch = -1; + + if (xendomain_is_dom0()) { +#if 0 + evtch = unbind_virq_from_evtch(VIRQ_CONSOLE); + hypervisor_mask_event(evtch); + if (event_remove_handler(evtch, xencons_intr, + xencons_console_device) != 0) + aprint_error_dev(dev, + "can't remove handler: xencons_intr\n"); +#endif + } else { #ifdef XEN3 - printf("%s: using event channel %d\n", - device_xname(self), xen_start_info.console.domU.evtchn); - event_set_handler(xen_start_info.console.domU.evtchn, - xencons_handler, sc, IPL_TTY, "xencons"); - hypervisor_enable_event(xen_start_info.console.domU.evtchn); + evtch = xen_start_info.console_evtchn; + hypervisor_mask_event(evtch); + if (event_remove_handler(evtch, xencons_handler, + xencons_console_device) != 0) + aprint_error_dev(dev, + "can't remove handler: xencons_handler\n"); +#endif + } + + aprint_verbose_dev(dev, "removed event channel %d\n", evtch); + + return true; +} + +static bool +xencons_resume(device_t dev PMF_FN_ARGS) +{ + int evtch = -1; + + if (xendomain_is_dom0()) { + evtch = bind_virq_to_evtch(VIRQ_CONSOLE); + if (event_set_handler(evtch, xencons_intr, + xencons_console_device, IPL_TTY, "xencons") != 0) + aprint_error_dev(dev, "can't register xencons_intr\n"); + } else { +#ifdef XEN3 + evtch = xen_start_info.console_evtchn; + if (event_set_handler(evtch, xencons_handler, + xencons_console_device, IPL_TTY, "xencons") != 0) + aprint_error_dev(dev, "can't register xencons_handler\n"); #else - (void)ctrl_if_register_receiver(CMSG_CONSOLE, - xencons_rx, 0); + (void)ctrl_if_register_receiver(CMSG_CONSOLE, + xencons_rx, 0); #endif - } - xencons_console_device = sc; } - sc->polling = 0; + + if (evtch != -1) { + aprint_verbose_dev(dev, "using event channel %d\n", evtch); + hypervisor_enable_event(evtch); + } + + return true; } int Index: sys/arch/xen/xen/xengnt.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xen/xengnt.c,v retrieving revision 1.14 diff -u -p -r1.14 xengnt.c --- sys/arch/xen/xen/xengnt.c 16 Mar 2009 06:18:32 -0000 1.14 +++ sys/arch/xen/xen/xengnt.c 18 May 2009 14:48:50 -0000 @@ -72,7 +72,6 @@ grant_entry_t *grant_table; static grant_ref_t xengnt_get_entry(void); static void xengnt_free_entry(grant_ref_t); -static void xengnt_resume(void); static int xengnt_more_entries(void); void @@ -105,7 +104,6 @@ xengnt_init(void) for (i = 0; i <= nr_grant_entries; i++) gnt_entries[i] = XENGNT_NO_ENTRY; - last_gnt_entry = 0; xengnt_resume(); } @@ -113,17 +111,44 @@ xengnt_init(void) /* * Resume grant table state */ -static void +bool xengnt_resume(void) { int previous_nr_grant_frames = gnt_nr_grant_frames; + + last_gnt_entry = 0; gnt_nr_grant_frames = 0; + while (gnt_nr_grant_frames < previous_nr_grant_frames) { if (xengnt_more_entries() != 0) panic("xengnt_resume: can't restore grant frames"); } + return true; +} + +/* + * Suspend grant table state + */ +bool +xengnt_suspend(void) +{ + int i; + + KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); + + for (i = 0; i < last_gnt_entry; i++) { + /* invalidate all grant entries (necessary for resume) */ + gnt_entries[i] = XENGNT_NO_ENTRY; + } + + /* Remove virtual => machine mapping */ + pmap_kremove((vaddr_t)grant_table, gnt_nr_grant_frames * PAGE_SIZE); + pmap_update(pmap_kernel()); + + return true; } + /* * Add another page to the grant table * Returns 0 on success, ENOMEM on failure Index: sys/arch/xen/xenbus/xenbus_comms.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xenbus/xenbus_comms.c,v retrieving revision 1.12 diff -u -p -r1.12 xenbus_comms.c --- sys/arch/xen/xenbus/xenbus_comms.c 16 Jan 2009 20:16:47 -0000 1.12 +++ sys/arch/xen/xenbus/xenbus_comms.c 18 May 2009 14:48:50 -0000 @@ -53,8 +53,6 @@ __KERNEL_RCSID(0, "$NetBSD: xenbus_comms struct xenstore_domain_interface *xenstore_interface; -static int xenbus_irq = 0; - extern int xenstored_ready; // static DECLARE_WORK(probe_work, xenbus_probe, NULL); @@ -219,22 +217,42 @@ int xb_init_comms(device_t dev) { int err; + int evtchn; - if (xenbus_irq) - event_remove_handler(xenbus_irq, wake_waiting, NULL); + evtchn = xen_start_info.store_evtchn; - err = event_set_handler(xen_start_info.store_evtchn, wake_waiting, - NULL, IPL_TTY, "xenbus"); + err = event_set_handler(evtchn, wake_waiting, NULL, IPL_TTY, "xenbus"); if (err) { aprint_error_dev(dev, "request irq failed %i\n", err); return err; } - xenbus_irq = xen_start_info.store_evtchn; - aprint_verbose_dev(dev, "using event channel %d\n", xenbus_irq); - hypervisor_enable_event(xenbus_irq); + + hypervisor_enable_event(evtchn); + aprint_verbose_dev(dev, "using event channel %d\n", evtchn); + return 0; } +void +xb_suspend_comms(device_t dev) +{ + int err; + int evtchn; + + evtchn = xen_start_info.store_evtchn; + + hypervisor_mask_event(evtchn); + + err = event_remove_handler(evtchn, wake_waiting, NULL); + if (err) { + aprint_error_dev(dev, + "can't remove handler: wake_waiting\n"); + } + + aprint_verbose_dev(dev, "removed event channel %d\n", evtchn); +} + + /* * Local variables: * c-file-style: "linux" Index: sys/arch/xen/xenbus/xenbus_comms.h =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xenbus/xenbus_comms.h,v retrieving revision 1.5 diff -u -p -r1.5 xenbus_comms.h --- sys/arch/xen/xenbus/xenbus_comms.h 24 Oct 2008 21:09:24 -0000 1.5 +++ sys/arch/xen/xenbus/xenbus_comms.h 18 May 2009 14:48:50 -0000 @@ -32,6 +32,8 @@ void xenbus_kernfs_init(void); int xs_init(device_t dev); int xb_init_comms(device_t dev); +void xb_suspend_comms(device_t dev); +void xb_resume_comms(device_t dev); /* Low level routines. */ int xb_write(const void *data, unsigned len); Index: sys/arch/xen/xenbus/xenbus_probe.c =================================================================== RCS file: /cvsroot/src/sys/arch/xen/xenbus/xenbus_probe.c,v retrieving revision 1.27 diff -u -p -r1.27 xenbus_probe.c --- sys/arch/xen/xenbus/xenbus_probe.c 9 Jan 2009 22:26:25 -0000 1.27 +++ sys/arch/xen/xenbus/xenbus_probe.c 18 May 2009 14:48:50 -0000 @@ -69,6 +69,10 @@ static void xenbus_probe_init(void *); static struct xenbus_device *xenbus_lookup_device_path(const char *); +/* power management, for save/restore */ +static bool xenbus_suspend(device_t PMF_FN_PROTO); +static bool xenbus_resume(device_t PMF_FN_PROTO); + CFATTACH_DECL_NEW(xenbus, 0, xenbus_match, xenbus_attach, NULL, NULL); @@ -102,8 +106,31 @@ xenbus_attach(device_t parent, device_t if (err) aprint_error_dev(xenbus_dev, "kthread_create(xenbus_probe): %d\n", err); + + if (!pmf_device_register(self, xenbus_suspend, xenbus_resume)) + aprint_error_dev(self, "couldn't establish power handler\n"); + +} + +static bool +xenbus_suspend(device_t dev PMF_FN_ARGS) +{ + xs_suspend(); + xb_suspend_comms(dev); + + return true; +} + +static bool +xenbus_resume(device_t dev PMF_FN_ARGS) +{ + xb_init_comms(dev); + xs_resume(); + + return true; } + void xenbus_backend_register(struct xenbus_backend_driver *xbakd) {