summaryrefslogtreecommitdiff
path: root/sys/arch/loongson
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 /sys/arch/loongson
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@
Diffstat (limited to 'sys/arch/loongson')
-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;