From 5329dfcf7d3b09bae2db58cebe45fe50245ababf Mon Sep 17 00:00:00 2001 From: Paul Irofti Date: Sun, 2 Jun 2013 21:46:05 +0000 Subject: Start working on hibernate support for Loongson This is work in progress. Nothing to test or play with for now. Commiting it now so that I can work on it in-tree. Okay miod@ --- sys/arch/loongson/conf/files.loongson | 3 +- sys/arch/loongson/dev/apm.c | 26 +++- sys/arch/loongson/include/hibernate.h | 34 ++++ sys/arch/loongson/include/hibernate_var.h | 39 +++++ sys/arch/loongson/loongson/autoconf.c | 7 +- sys/arch/loongson/loongson/hibernate_machdep.c | 206 +++++++++++++++++++++++++ sys/arch/loongson/loongson/locore.S | 26 +++- sys/arch/loongson/loongson/loongson2_machdep.c | 9 +- sys/arch/loongson/loongson/machdep.c | 10 +- 9 files changed, 350 insertions(+), 10 deletions(-) create mode 100644 sys/arch/loongson/include/hibernate.h create mode 100644 sys/arch/loongson/include/hibernate_var.h create mode 100644 sys/arch/loongson/loongson/hibernate_machdep.c (limited to 'sys/arch/loongson') diff --git a/sys/arch/loongson/conf/files.loongson b/sys/arch/loongson/conf/files.loongson index 6b9a3dfa95c..092f5068d0c 100644 --- a/sys/arch/loongson/conf/files.loongson +++ b/sys/arch/loongson/conf/files.loongson @@ -1,4 +1,4 @@ -# $OpenBSD: files.loongson,v 1.14 2013/01/14 21:18:47 pirofti Exp $ +# $OpenBSD: files.loongson,v 1.15 2013/06/02 21:46:04 pirofti Exp $ # Standard stanzas config(8) can't run without maxpartitions 16 @@ -22,6 +22,7 @@ file arch/loongson/loongson/generic2e_machdep.c file arch/loongson/loongson/isa_machdep.c isa file arch/loongson/loongson/loongson2_machdep.c file arch/loongson/loongson/machdep.c +file arch/loongson/loongson/hibernate_machdep.c hibernate file arch/loongson/loongson/mutex.c file arch/loongson/loongson/pciide_machdep.c pciide file arch/loongson/loongson/pmon.c diff --git a/sys/arch/loongson/dev/apm.c b/sys/arch/loongson/dev/apm.c index 96484ae5794..564a9ea7b67 100644 --- a/sys/arch/loongson/dev/apm.c +++ b/sys/arch/loongson/dev/apm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apm.c,v 1.13 2012/10/17 22:49:27 deraadt Exp $ */ +/* $OpenBSD: apm.c,v 1.14 2013/06/02 21:46:04 pirofti Exp $ */ /*- * Copyright (c) 2001 Alexander Guy. All rights reserved. @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -87,7 +88,7 @@ int filt_apmread(struct knote *kn, long hint); int apmkqfilter(dev_t dev, struct knote *kn); int apm_getdefaultinfo(struct apm_power_info *); -int apm_suspend(void); +int apm_suspend(int state); struct filterops apmread_filtops = { 1, NULL, filt_apmrdetach, filt_apmread}; @@ -215,8 +216,11 @@ apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) case APM_IOC_STANDBY_REQ: if ((flag & FWRITE) == 0) error = EBADF; + else if (sys_platform->suspend == NULL || + sys_platform->resume == NULL) + error = EOPNOTSUPP; else - error = EOPNOTSUPP; /* XXX */ + error = apm_suspend(APM_STANDBY_REQ); break; case APM_IOC_SUSPEND: case APM_IOC_SUSPEND_REQ: @@ -226,7 +230,7 @@ apmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) sys_platform->resume == NULL) error = EOPNOTSUPP; else - error = apm_suspend(); + error = apm_suspend(APM_SUSPEND_REQ); break; case APM_IOC_PRN_CTL: if ((flag & FWRITE) == 0) @@ -351,7 +355,7 @@ apm_record_event(u_int event, const char *src, const char *msg) } int -apm_suspend() +apm_suspend(int state) { int rv; int s; @@ -371,6 +375,18 @@ apm_suspend() rv = config_suspend(TAILQ_FIRST(&alldevs), DVACT_SUSPEND); +#ifdef HIBERNATE + if (state == APM_STANDBY_REQ) { + uvm_pmr_zero_everything(); + if (hibernate_suspend()) { + printf("apm: hibernate_suspend failed"); + hibernate_free(); + uvm_pmr_dirty_everything(); + return (ECANCELED); + } + } +#endif + /* XXX * Flag to disk drivers that they should "power down" the disk * when we get to DVACT_POWERDOWN. diff --git a/sys/arch/loongson/include/hibernate.h b/sys/arch/loongson/include/hibernate.h new file mode 100644 index 00000000000..cf324beb420 --- /dev/null +++ b/sys/arch/loongson/include/hibernate.h @@ -0,0 +1,34 @@ +/* $OpenBSD: hibernate.h,v 1.1 2013/06/02 21:46:04 pirofti Exp $ */ + +/* + * Copyright (c) 2013 Paul Irofti. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include + +/* Loongson hibernate support structures and functions */ + +int get_hibernate_info_md(union hibernate_info *); +void hibernate_flush(void); +void hibernate_enter_resume_mapping(vaddr_t, paddr_t, int); +int hibernate_inflate_skip(union hibernate_info *, paddr_t); +void hibernate_prepare_resume_machdep(union hibernate_info *); +int hibernate_suspend(void); +void hibernate_switch_stack_machdep(void); +void hibernate_resume_machdep(void); +void hibernate_activate_resume_pt_machdep(void); +void hibernate_enable_intr_machdep(void); +void hibernate_disable_intr_machdep(void); diff --git a/sys/arch/loongson/include/hibernate_var.h b/sys/arch/loongson/include/hibernate_var.h new file mode 100644 index 00000000000..dda04d9906c --- /dev/null +++ b/sys/arch/loongson/include/hibernate_var.h @@ -0,0 +1,39 @@ +/* $OpenBSD: hibernate_var.h,v 1.1 2013/06/02 21:46:04 pirofti Exp $ */ + +/* + * Copyright (c) 2013 Paul Irofti. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Loongson hibernate support definitions */ + +#define PAGE_MASK_4M ((256 * PAGE_SIZE) - 1) + +#define PIGLET_PAGE_MASK ~((paddr_t)PAGE_MASK_4M) + +/* + * Steal hibernate pages right after the first page which is reserved + * for the exception area. + * */ +#define HIBERNATE_STACK_PAGE (PAGE_SIZE * 1) +#define HIBERNATE_INFLATE_PAGE (PAGE_SIZE * 2) +#define HIBERNATE_COPY_PAGE (PAGE_SIZE * 3) +#define HIBERNATE_HIBALLOC_PAGE (PAGE_SIZE * 4) + +#define HIBERNATE_RESERVED_PAGES 4 + +/* Use 4MB hibernation chunks */ +#define HIBERNATE_CHUNK_SIZE 0x400000 + +#define HIBERNATE_CHUNK_TABLE_SIZE 0x100000 diff --git a/sys/arch/loongson/loongson/autoconf.c b/sys/arch/loongson/loongson/autoconf.c index bd98f8c812a..40ea638e53c 100644 --- a/sys/arch/loongson/loongson/autoconf.c +++ b/sys/arch/loongson/loongson/autoconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: autoconf.c,v 1.5 2010/02/16 21:31:36 miod Exp $ */ +/* $OpenBSD: autoconf.c,v 1.6 2013/06/02 21:46:04 pirofti Exp $ */ /* * Copyright (c) 2009 Miodrag Vallat. * @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -93,6 +94,10 @@ diskconf(void) setroot(bootdv, 0, RB_USERREQ); dumpconf(); + +#ifdef HIBERNATE + hibernate_resume(); +#endif /* HIBERNATE */ } void diff --git a/sys/arch/loongson/loongson/hibernate_machdep.c b/sys/arch/loongson/loongson/hibernate_machdep.c new file mode 100644 index 00000000000..df45d74755b --- /dev/null +++ b/sys/arch/loongson/loongson/hibernate_machdep.c @@ -0,0 +1,206 @@ +/* $OpenBSD: hibernate_machdep.c,v 1.1 2013/06/02 21:46:04 pirofti Exp $ */ + +/* + * Copyright (c) 2013 Paul Irofti. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "wd.h" +#include "ahci.h" +#include "sd.h" + +#if NWD > 0 +#include +#include +#endif + +/* Hibernate support */ +void hibernate_enter_resume_4k_pte(vaddr_t, paddr_t); +void hibernate_enter_resume_2m_pde(vaddr_t, paddr_t); + +extern void hibernate_resume_machdep(void); +extern void hibernate_flush(void); +extern caddr_t start, end; +extern struct hibernate_state *hibernate_state; + +/* + * Loongson MD Hibernate functions + * + * see Loongson hibernate.h for lowmem layout used during hibernate + */ + +/* + * Returns the hibernate write I/O function to use on this machine + */ +hibio_fn +get_hibernate_io_function(void) +{ + char *blkname = findblkname(major(swdevt[0].sw_dev)); + + if (blkname == NULL) + return NULL; + +#if NWD > 0 + if (strcmp(blkname, "wd") == 0) + return wd_hibernate_io; +#endif +#if NAHCI > 0 && NSD > 0 + if (strcmp(blkname, "sd") == 0) { + extern struct cfdriver sd_cd; + extern int ahci_hibernate_io(dev_t dev, daddr_t blkno, + vaddr_t addr, size_t size, int op, void *page); + struct device *dv; + + dv = disk_lookup(&sd_cd, DISKUNIT(swdevt[0].sw_dev)); + if (dv && dv->dv_parent && dv->dv_parent->dv_parent && + strcmp(dv->dv_parent->dv_parent->dv_cfdata->cf_driver->cd_name, + "ahci") == 0) + return ahci_hibernate_io; + } +#endif + return NULL; +} + +/* + * Gather MD-specific data and store into hiber_info + */ +int +get_hibernate_info_md(union hibernate_info *hiber_info) +{ + int i; + + /* Calculate memory ranges */ + hiber_info->nranges = 0; + hiber_info->image_size = 0; + + for (i = 0; i < MAXMEMSEGS && mem_layout[i].mem_last_page != 0; i++) { + /* XXX: Adjust for stolen pages later */ + hiber_info->ranges[i].base = + mem_layout[i].mem_first_page >> PAGE_SHIFT; + hiber_info->ranges[i].end = + mem_layout[i].mem_last_page >> PAGE_SHIFT; + hiber_info->image_size += + hiber_info->ranges[i].end - hiber_info->ranges[i].base; + hiber_info->nranges++; + } + + return (0); +} + +/* + * Enter a mapping for va->pa in the resume pagetable + */ +void +hibernate_enter_resume_mapping(vaddr_t va, paddr_t pa, int size) +{ + /* XXX TBD */ +} + +/* + * Create the resume-time page table. This table maps the image(pig) area, + * the kernel text area, and various utility pages for use during resume, + * since we cannot overwrite the resuming kernel's page table during inflate + * and expect things to work properly. + */ +void +hibernate_populate_resume_pt(union hibernate_info *hib_info, + paddr_t image_start, paddr_t image_end) +{ + /* XXX TBD */ +} + +/* + * MD-specific resume preparation (creating resume time pagetables, + * stacks, etc). + */ +void +hibernate_prepare_resume_machdep(union hibernate_info *hib_info) +{ + paddr_t pa, piglet_end; + vaddr_t va; + + /* + * At this point, we are sure that the piglet's phys space is going to + * have been unused by the suspending kernel, but the vaddrs used by + * the suspending kernel may or may not be available to us here in the + * resuming kernel, so we allocate a new range of VAs for the piglet. + * Those VAs will be temporary and will cease to exist as soon as we + * switch to the resume PT, so we need to ensure that any VAs required + * during inflate are also entered into that map. + */ + + hib_info->piglet_va = (vaddr_t)km_alloc(HIBERNATE_CHUNK_SIZE*3, + &kv_any, &kp_none, &kd_nowait); + if (!hib_info->piglet_va) + panic("Unable to allocate vaddr for hibernate resume piglet\n"); + + piglet_end = hib_info->piglet_pa + HIBERNATE_CHUNK_SIZE*3; + + for (pa = hib_info->piglet_pa,va = hib_info->piglet_va; + pa <= piglet_end; pa += PAGE_SIZE, va += PAGE_SIZE) + pmap_kenter_pa(va, pa, VM_PROT_ALL); + + pmap_activate(curproc); +} + +/* + * During inflate, certain pages that contain our bookkeeping information + * (eg, the chunk table, scratch pages, etc) need to be skipped over and + * not inflated into. + * + * Returns 1 if the physical page at dest should be skipped, 0 otherwise + */ +int +hibernate_inflate_skip(union hibernate_info *hib_info, paddr_t dest) +{ + if (dest >= hib_info->piglet_pa && + dest <= (hib_info->piglet_pa + 3 * HIBERNATE_CHUNK_SIZE)) + return (1); + + return (0); +} + +void +hibernate_enable_intr_machdep(void) +{ + enableintr(); +} + +void +hibernate_disable_intr_machdep(void) +{ + disableintr(); +} + diff --git a/sys/arch/loongson/loongson/locore.S b/sys/arch/loongson/loongson/locore.S index 2c5af444e1c..1bf9849f2fd 100644 --- a/sys/arch/loongson/loongson/locore.S +++ b/sys/arch/loongson/loongson/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.3 2012/10/03 11:18:23 miod Exp $ */ +/* $OpenBSD: locore.S,v 1.4 2013/06/02 21:46:04 pirofti Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -74,3 +74,27 @@ start: PTR_L sp, 0(sp) jr ra nop + +#ifdef HIBERNATE + +LEAF(hibernate_flush, 0) /* { */ + /* XXX TBD */ + j ra +END(hibernate_flush) /* } */ + + /* Switch to hibernate resume pagetable */ +LEAF(hibernate_activate_resume_pt_machdep, 0) /* { */ + /* XXX TBD */ + j ra +END(hibernate_activate_resume_pt_machdep) /* } */ + +LEAF(hibernate_switch_stack_machdep, 0) /* { */ + /* XXX TBD */ + j ra +END(hibernate_switch_stack_machdep) /* } */ + +LEAF(hibernate_resume_machdep, 0) /* { */ + j ra +END(hibernate_resume_machdep) /* } */ + +#endif /* HIBERNATE */ diff --git a/sys/arch/loongson/loongson/loongson2_machdep.c b/sys/arch/loongson/loongson/loongson2_machdep.c index de80d22395e..d1b4d18501a 100644 --- a/sys/arch/loongson/loongson/loongson2_machdep.c +++ b/sys/arch/loongson/loongson/loongson2_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: loongson2_machdep.c,v 1.13 2013/01/16 20:28:06 miod Exp $ */ +/* $OpenBSD: loongson2_machdep.c,v 1.14 2013/06/02 21:46:04 pirofti Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -30,6 +30,10 @@ #include #include +#ifdef HIBERNATE +#include +#endif /* HIBERNATE */ + #include extern struct phys_mem_desc mem_layout[MAXMEMSEGS]; @@ -148,6 +152,9 @@ loongson2f_setup(u_long memlo, u_long memhi) if (memhi != 0) { /* do NOT stomp on exception area */ mem_layout[0].mem_first_page = atop(DDR_WINDOW_BASE) + 1; +#ifdef HIBERNATE + mem_layout[0].mem_first_page += HIBERNATE_RESERVED_PAGES; +#endif mem_layout[0].mem_last_page = atop(DDR_WINDOW_BASE) + memlo + memhi; loongson_dma_base = PCI_DDR_BASE ^ DDR_WINDOW_BASE; diff --git a/sys/arch/loongson/loongson/machdep.c b/sys/arch/loongson/loongson/machdep.c index 572136a8aab..bf53e35d593 100644 --- a/sys/arch/loongson/loongson/machdep.c +++ b/sys/arch/loongson/loongson/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.41 2013/01/15 23:30:36 pirofti Exp $ */ +/* $OpenBSD: machdep.c,v 1.42 2013/06/02 21:46:04 pirofti Exp $ */ /* * Copyright (c) 2009, 2010 Miodrag Vallat. @@ -62,6 +62,7 @@ #ifdef SYSVSEM #include #endif +#include #include #include @@ -76,6 +77,10 @@ #include #include +#ifdef HIBERNATE +#include +#endif /* HIBERNATE */ + #include #include @@ -497,6 +502,9 @@ mips_init(int32_t argc, int32_t argv, int32_t envp, int32_t cv, firstkernpage = atop(trunc_page(firstkernpa)) + mem_layout[0].mem_first_page - 1; +#ifdef HIBERNATE + firstkernpage -= HIBERNATE_RESERVED_PAGES; +#endif lastkernpage = atop(round_page(lastkernpa)) + mem_layout[0].mem_first_page - 1; -- cgit v1.2.3