summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Larkin <mlarkin@cvs.openbsd.org>2011-11-14 00:25:18 +0000
committerMike Larkin <mlarkin@cvs.openbsd.org>2011-11-14 00:25:18 +0000
commit91d2dce85a2672c3e6ba92441ac59d13ed59dd8a (patch)
tree31e09ad0ca099ec2625edb895e134191855fb5f9
parente31c7c6b243341e13d714164a6cf0497224c77e1 (diff)
Use a fixed io_page for all hibernate I/O, which is needed for
ahci_hibernate_io, a skeleton of which is also provided in this diff. This code is from deraadt@. Tested on a few wd machines to ensure it works there as well.
-rw-r--r--sys/dev/ata/ata_wdc.c6
-rw-r--r--sys/dev/pci/ahci.c18
-rw-r--r--sys/dev/pci/files.pci4
-rw-r--r--sys/kern/subr_hibernate.c81
-rw-r--r--sys/sys/hibernate.h3
5 files changed, 61 insertions, 51 deletions
diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c
index 88bc1a51b85..1276ca7f10c 100644
--- a/sys/dev/ata/ata_wdc.c
+++ b/sys/dev/ata/ata_wdc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ata_wdc.c,v 1.42 2011/11/13 23:13:28 mlarkin Exp $ */
+/* $OpenBSD: ata_wdc.c,v 1.43 2011/11/14 00:25:17 mlarkin Exp $ */
/* $NetBSD: ata_wdc.c,v 1.21 1999/08/09 09:43:11 bouyer Exp $ */
/*
@@ -128,6 +128,10 @@ wd_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size, int op, voi
struct ata_bio *ata_bio;
extern struct cfdriver wd_cd;
+ /* early call for initialization */
+ if (op == HIB_INIT)
+ return(0);
+
real_wd = (struct wd_softc *)disk_lookup(&wd_cd, DISKUNIT(dev));
if (real_wd == NULL)
return (ENODEV);
diff --git a/sys/dev/pci/ahci.c b/sys/dev/pci/ahci.c
index 59f163648dc..6c07f248a6c 100644
--- a/sys/dev/pci/ahci.c
+++ b/sys/dev/pci/ahci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ahci.c,v 1.184 2011/10/27 08:03:50 jmatthew Exp $ */
+/* $OpenBSD: ahci.c,v 1.185 2011/11/14 00:25:17 mlarkin Exp $ */
/*
* Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
@@ -525,6 +525,13 @@ void ahci_pci_attach(struct device *, struct device *,
int ahci_pci_detach(struct device *, int);
int ahci_pci_activate(struct device *, int);
+#ifdef HIBERNATE
+#include <sys/hibernate.h>
+
+int ahci_hibernate_io(dev_t dev, daddr_t blkno,
+ vaddr_t addr, size_t size, int wr, void *page);
+#endif
+
struct cfattach ahci_pci_ca = {
sizeof(struct ahci_softc),
ahci_pci_match,
@@ -3707,3 +3714,12 @@ ahci_pmp_identify(struct ahci_port *ap, int *ret_nports)
*ret_nports = nports;
return (0);
}
+
+#ifdef HIBERNATE
+int
+ahci_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size,
+ int op, void *page)
+{
+ return (EIO);
+}
+#endif /* HIBERNATE */
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 961e9919e4f..ad258f51deb 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.279 2011/05/18 14:21:21 sthen Exp $
+# $OpenBSD: files.pci,v 1.280 2011/11/14 00:25:17 mlarkin Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -87,7 +87,7 @@ file dev/pci/jmb.c jmb
device ahci: scsi, atascsi
attach ahci at pci with ahci_pci
attach ahci at jmb with ahci_jmb
-file dev/pci/ahci.c ahci | ahci_pci | ahci_jmb
+file dev/pci/ahci.c ahci | ahci_pci | ahci_jmb needs-flag
# AMI MegaRAID Express x00/Elite 1500/Express 1x00 RAID Controllers
attach ami at pci with ami_pci
diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c
index 4a0e0f72c8d..c30eb2422bd 100644
--- a/sys/kern/subr_hibernate.c
+++ b/sys/kern/subr_hibernate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_hibernate.c,v 1.21 2011/11/13 23:13:29 mlarkin Exp $ */
+/* $OpenBSD: subr_hibernate.c,v 1.22 2011/11/14 00:25:17 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -653,10 +653,30 @@ get_hibernate_info(union hibernate_info *hiber_info, int suspend)
printf("Hibernate failed to allocate the piglet\n");
return (1);
}
+ hiber_info->io_page = (void *)hiber_info->piglet_va;
+ } else {
+ /*
+ * Resuming kernels use a regular I/O page since we won't
+ * have access to the suspended kernel's piglet VA at this
+ * point. No need to free this I/O page as it will vanish
+ * as part of the resume.
+ */
+ hiber_info->io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
+ if (!hiber_info->io_page)
+ return (1);
}
+
+ /*
+ * operation -1 (HIB_INIT) requests initialization of the hibernate
+ * IO function
+ */
+ if (hiber_info->io_func(hiber_info->device, 0,
+ (vaddr_t)NULL, 0, HIB_INIT, hiber_info->io_page) == -1)
+ goto fail;
+
if (get_hibernate_info_md(hiber_info))
- return (1);
+ goto fail;
/* Calculate memory image location */
hiber_info->image_offset = dl.d_partitions[1].p_offset +
@@ -666,6 +686,9 @@ get_hibernate_info(union hibernate_info *hiber_info, int suspend)
chunktable_size;
return (0);
+fail:
+ uvm_pmr_free_piglet(hiber_info->piglet_va, HIBERNATE_CHUNK_SIZE*3);
+ return (1);
}
/*
@@ -785,20 +808,10 @@ hibernate_deflate(union hibernate_info *hiber_info, paddr_t src,
int
hibernate_write_signature(union hibernate_info *hiber_info)
{
- u_int8_t *io_page;
- int result = 0;
-
- io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
- if (!io_page)
- return (1);
-
/* Write hibernate info to disk */
- if (hiber_info->io_func(hiber_info->device, hiber_info->sig_offset,
- (vaddr_t)hiber_info, hiber_info->secsize, HIB_W, io_page))
- result = 1;
-
- free(io_page, M_DEVBUF);
- return (result);
+ return (hiber_info->io_func(hiber_info->device, hiber_info->sig_offset,
+ (vaddr_t)hiber_info, hiber_info->secsize, HIB_W,
+ hiber_info->io_page));
}
/*
@@ -812,14 +825,9 @@ hibernate_write_chunktable(union hibernate_info *hiber_info)
struct hibernate_disk_chunk *chunks;
vaddr_t hibernate_chunk_table_start;
size_t hibernate_chunk_table_size;
- u_int8_t *io_page;
daddr_t chunkbase;
int i;
- io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
- if (!io_page)
- return (1);
-
hibernate_chunk_table_size = HIBERNATE_CHUNK_TABLE_SIZE;
chunkbase = hiber_info->sig_offset -
@@ -836,13 +844,10 @@ hibernate_write_chunktable(union hibernate_info *hiber_info)
if (hiber_info->io_func(hiber_info->device,
chunkbase + (i/hiber_info->secsize),
(vaddr_t)(hibernate_chunk_table_start + i),
- MAXPHYS, HIB_W, io_page)) {
- free(io_page, M_DEVBUF);
+ MAXPHYS, HIB_W, hiber_info->io_page))
return (1);
- }
}
- free(io_page, M_DEVBUF);
return (0);
}
@@ -855,7 +860,6 @@ hibernate_clear_signature(void)
{
union hibernate_info blank_hiber_info;
union hibernate_info hiber_info;
- u_int8_t *io_page;
/* Zero out a blank hiber_info */
bzero(&blank_hiber_info, sizeof(hiber_info));
@@ -863,18 +867,13 @@ hibernate_clear_signature(void)
if (get_hibernate_info(&hiber_info, 0))
return (1);
- io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
- if (!io_page)
- return (1);
-
/* Write (zeroed) hibernate info to disk */
/* XXX - use regular kernel write routine for this */
if (hiber_info.io_func(hiber_info.device, hiber_info.sig_offset,
- (vaddr_t)&blank_hiber_info, hiber_info.secsize, HIB_W, io_page))
+ (vaddr_t)&blank_hiber_info, hiber_info.secsize, HIB_W,
+ hiber_info.io_page))
panic("error hibernate write 6\n");
- free(io_page, M_DEVBUF);
-
return (0);
}
@@ -1004,7 +1003,6 @@ void
hibernate_resume(void)
{
union hibernate_info hiber_info;
- u_int8_t *io_page;
int s;
/* Scrub temporary vaddr ranges used during resume */
@@ -1018,20 +1016,15 @@ hibernate_resume(void)
if (get_hibernate_info(&hiber_info, 0))
return;
- io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT);
- if (!io_page)
- return;
-
/* Read hibernate info from disk */
s = splbio();
/* XXX use regular kernel read routine here */
if (hiber_info.io_func(hiber_info.device, hiber_info.sig_offset,
- (vaddr_t)&disk_hiber_info, hiber_info.secsize, HIB_R, io_page))
+ (vaddr_t)&disk_hiber_info, hiber_info.secsize, HIB_R,
+ hiber_info.io_page))
panic("error in hibernate read\n");
- free(io_page, M_DEVBUF);
-
/*
* If on-disk and in-memory hibernate signatures match,
* this means we should do a resume from hibernate.
@@ -1104,9 +1097,6 @@ fail:
km_free((void *)hibernate_fchunk_area, 3*PAGE_SIZE, &kv_any,
&kp_none);
- if (io_page)
- free((void *)io_page, M_DEVBUF);
-
if (hibernate_chunktable_area)
free((void *)hibernate_chunktable_area, M_DEVBUF);
}
@@ -1218,7 +1208,6 @@ hibernate_write_chunks(union hibernate_info *hiber_info)
paddr_t range_base, range_end, inaddr, temp_inaddr;
size_t nblocks, out_remaining, used, offset = 0;
struct hibernate_disk_chunk *chunks;
- vaddr_t hibernate_alloc_page = hiber_info->piglet_va;
vaddr_t hibernate_io_page = hiber_info->piglet_va + PAGE_SIZE;
daddr_t blkctr = hiber_info->image_offset;
int i;
@@ -1316,7 +1305,7 @@ hibernate_write_chunks(union hibernate_info *hiber_info)
if (hiber_info->io_func(hiber_info->device,
blkctr, (vaddr_t)hibernate_io_page,
- PAGE_SIZE, HIB_W, (void *)hibernate_alloc_page))
+ PAGE_SIZE, HIB_W, hiber_info->io_page))
return (1);
blkctr += nblocks;
@@ -1356,7 +1345,7 @@ hibernate_write_chunks(union hibernate_info *hiber_info)
/* Write final block(s) for this chunk */
if (hiber_info->io_func(hiber_info->device, blkctr,
(vaddr_t)hibernate_io_page, nblocks*hiber_info->secsize,
- HIB_W, (void *)hibernate_alloc_page))
+ HIB_W, hiber_info->io_page))
return (1);
blkctr += nblocks;
diff --git a/sys/sys/hibernate.h b/sys/sys/hibernate.h
index 9d0a1bd4023..8e67778bda3 100644
--- a/sys/sys/hibernate.h
+++ b/sys/sys/hibernate.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hibernate.h,v 1.16 2011/11/13 23:13:29 mlarkin Exp $ */
+/* $OpenBSD: hibernate.h,v 1.17 2011/11/14 00:25:17 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -90,6 +90,7 @@ union hibernate_info {
vaddr_t piglet_va;
char kernel_version[128];
hibio_fn io_func;
+ void *io_page;
};
/* XXX - remove restriction to have this union fit in a single block */