summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Irofti <pirofti@cvs.openbsd.org>2013-06-02 21:46:05 +0000
committerPaul Irofti <pirofti@cvs.openbsd.org>2013-06-02 21:46:05 +0000
commit5329dfcf7d3b09bae2db58cebe45fe50245ababf (patch)
tree37672346954cce8510331595d688f440de5f6080
parenta57f39a6139b4768b12fe0dd74d1a9a941d71aea (diff)
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@
-rw-r--r--sys/arch/loongson/conf/files.loongson3
-rw-r--r--sys/arch/loongson/dev/apm.c26
-rw-r--r--sys/arch/loongson/include/hibernate.h34
-rw-r--r--sys/arch/loongson/include/hibernate_var.h39
-rw-r--r--sys/arch/loongson/loongson/autoconf.c7
-rw-r--r--sys/arch/loongson/loongson/hibernate_machdep.c206
-rw-r--r--sys/arch/loongson/loongson/locore.S26
-rw-r--r--sys/arch/loongson/loongson/loongson2_machdep.c9
-rw-r--r--sys/arch/loongson/loongson/machdep.c10
9 files changed, 350 insertions, 10 deletions
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 <sys/buf.h>
#include <sys/event.h>
#include <sys/reboot.h>
+#include <sys/hibernate.h>
#include <machine/autoconf.h>
#include <machine/conf.h>
@@ -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 <machine/hibernate_var.h>
+
+/* 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 <sys/conf.h>
#include <sys/device.h>
#include <sys/reboot.h>
+#include <sys/hibernate.h>
#include <machine/autoconf.h>
@@ -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 <sys/param.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/hibernate.h>
+#include <sys/timeout.h>
+#include <sys/malloc.h>
+#include <sys/kcore.h>
+
+#include <uvm/uvm_extern.h>
+#include <uvm/uvm_pmemrange.h>
+
+#include <machine/hibernate.h>
+#include <machine/hibernate_var.h>
+#include <machine/kcore.h>
+#include <machine/pmap.h>
+#include <machine/memconf.h>
+
+#include "wd.h"
+#include "ahci.h"
+#include "sd.h"
+
+#if NWD > 0
+#include <dev/ata/atavar.h>
+#include <dev/ata/wdvar.h>
+#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 <machine/memconf.h>
#include <machine/pmon.h>
+#ifdef HIBERNATE
+#include <machine/hibernate_var.h>
+#endif /* HIBERNATE */
+
#include <loongson/dev/bonitoreg.h>
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 <sys/sem.h>
#endif
+#include <sys/kcore.h>
#include <net/if.h>
#include <uvm/uvm.h>
@@ -76,6 +77,10 @@
#include <machine/memconf.h>
#include <machine/pmon.h>
+#ifdef HIBERNATE
+#include <machine/hibernate_var.h>
+#endif /* HIBERNATE */
+
#include <dev/cons.h>
#include <dev/pci/pcireg.h>
@@ -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;