diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2011-11-14 00:25:18 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2011-11-14 00:25:18 +0000 |
commit | 91d2dce85a2672c3e6ba92441ac59d13ed59dd8a (patch) | |
tree | 31e09ad0ca099ec2625edb895e134191855fb5f9 | |
parent | e31c7c6b243341e13d714164a6cf0497224c77e1 (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.c | 6 | ||||
-rw-r--r-- | sys/dev/pci/ahci.c | 18 | ||||
-rw-r--r-- | sys/dev/pci/files.pci | 4 | ||||
-rw-r--r-- | sys/kern/subr_hibernate.c | 81 | ||||
-rw-r--r-- | sys/sys/hibernate.h | 3 |
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 */ |