diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/hibernate_machdep.c | 8 | ||||
-rw-r--r-- | sys/arch/i386/i386/hibernate_machdep.c | 8 | ||||
-rw-r--r-- | sys/dev/sdmmc/files.sdmmc | 4 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdhc.c | 72 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc.c | 5 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_mem.c | 40 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmc_scsi.c | 99 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcchip.h | 4 | ||||
-rw-r--r-- | sys/dev/sdmmc/sdmmcvar.h | 7 |
9 files changed, 235 insertions, 12 deletions
diff --git a/sys/arch/amd64/amd64/hibernate_machdep.c b/sys/arch/amd64/amd64/hibernate_machdep.c index f2185eb836d..c1d7b6a8a0e 100644 --- a/sys/arch/amd64/amd64/hibernate_machdep.c +++ b/sys/arch/amd64/amd64/hibernate_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate_machdep.c,v 1.40 2018/02/10 05:11:06 jmatthew Exp $ */ +/* $OpenBSD: hibernate_machdep.c,v 1.41 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2012 Mike Larkin <mlarkin@openbsd.org> @@ -48,6 +48,7 @@ #include "softraid.h" #include "sd.h" #include "nvme.h" +#include "sdmmc.h" /* Hibernate support */ void hibernate_enter_resume_4k_pte(vaddr_t, paddr_t); @@ -94,6 +95,8 @@ get_hibernate_io_function(dev_t dev) vaddr_t addr, size_t size, int op, void *page); extern int sr_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size, int op, void *page); + extern int sdmmc_scsi_hibernate_io(dev_t dev, daddr_t blkno, + vaddr_t addr, size_t size, int op, void *page); struct device *dv = disk_lookup(&sd_cd, DISKUNIT(dev)); struct { const char *driver; @@ -108,6 +111,9 @@ get_hibernate_io_function(dev_t dev) #if NSOFTRAID > 0 { "softraid", sr_hibernate_io }, #endif +#if NSDMMC > 0 + { "sdmmc", sdmmc_scsi_hibernate_io }, +#endif }; if (dv && dv->dv_parent && dv->dv_parent->dv_parent) { diff --git a/sys/arch/i386/i386/hibernate_machdep.c b/sys/arch/i386/i386/hibernate_machdep.c index 5bc05033673..f98d6c5a49e 100644 --- a/sys/arch/i386/i386/hibernate_machdep.c +++ b/sys/arch/i386/i386/hibernate_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate_machdep.c,v 1.50 2018/02/10 05:11:06 jmatthew Exp $ */ +/* $OpenBSD: hibernate_machdep.c,v 1.51 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2011 Mike Larkin <mlarkin@openbsd.org> @@ -45,6 +45,7 @@ #include "ahci.h" #include "softraid.h" #include "sd.h" +#include "sdmmc.h" /* Hibernate support */ void hibernate_enter_resume_4k_pte(vaddr_t, paddr_t); @@ -97,6 +98,8 @@ get_hibernate_io_function(dev_t dev) vaddr_t addr, size_t size, int op, void *page); extern int sr_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size, int op, void *page); + extern int sdmmc_scsi_hibernate_io(dev_t dev, daddr_t blkno, + vaddr_t addr, size_t size, int op, void *page); struct device *dv = disk_lookup(&sd_cd, DISKUNIT(dev)); struct { const char *driver; @@ -108,6 +111,9 @@ get_hibernate_io_function(dev_t dev) #if NSOFTRAID > 0 { "softraid", sr_hibernate_io }, #endif +#if SDMMC > 0 + { "sdmmc", sdmmc_scsi_hibernate_io }, +#endif }; if (dv && dv->dv_parent && dv->dv_parent->dv_parent) { diff --git a/sys/dev/sdmmc/files.sdmmc b/sys/dev/sdmmc/files.sdmmc index 1b70aa8672f..c9c05242d23 100644 --- a/sys/dev/sdmmc/files.sdmmc +++ b/sys/dev/sdmmc/files.sdmmc @@ -1,4 +1,4 @@ -# $OpenBSD: files.sdmmc,v 1.5 2017/10/11 17:19:50 patrick Exp $ +# $OpenBSD: files.sdmmc,v 1.6 2018/03/20 04:18:40 jmatthew Exp $ # # Config file and device description for machine-independent SD/MMC code. # Included by ports that need it. @@ -6,7 +6,7 @@ define sdmmc {} device sdmmc: scsi attach sdmmc at sdmmcbus -file dev/sdmmc/sdmmc.c sdmmc +file dev/sdmmc/sdmmc.c sdmmc needs-flag file dev/sdmmc/sdmmc_cis.c sdmmc file dev/sdmmc/sdmmc_io.c sdmmc file dev/sdmmc/sdmmc_mem.c sdmmc diff --git a/sys/dev/sdmmc/sdhc.c b/sys/dev/sdmmc/sdhc.c index e7881a1a607..bfb3596bcc3 100644 --- a/sys/dev/sdmmc/sdhc.c +++ b/sys/dev/sdmmc/sdhc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdhc.c,v 1.57 2018/03/19 21:40:32 kettenis Exp $ */ +/* $OpenBSD: sdhc.c,v 1.58 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -96,10 +96,12 @@ void sdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); int sdhc_start_command(struct sdhc_host *, struct sdmmc_command *); int sdhc_wait_state(struct sdhc_host *, u_int32_t, u_int32_t); int sdhc_soft_reset(struct sdhc_host *, int); +int sdhc_wait_intr_cold(struct sdhc_host *, int, int); int sdhc_wait_intr(struct sdhc_host *, int, int); void sdhc_transfer_data(struct sdhc_host *, struct sdmmc_command *); void sdhc_read_data(struct sdhc_host *, u_char *, int); void sdhc_write_data(struct sdhc_host *, u_char *, int); +int sdhc_hibernate_init(sdmmc_chipset_handle_t, void *); #ifdef SDHC_DEBUG int sdhcdebug = 0; @@ -127,7 +129,9 @@ struct sdmmc_chip_functions sdhc_functions = { sdhc_card_intr_mask, sdhc_card_intr_ack, /* UHS functions */ - sdhc_signal_voltage + sdhc_signal_voltage, + /* hibernate */ + sdhc_hibernate_init, }; struct cfdriver sdhc_cd = { @@ -1074,11 +1078,64 @@ sdhc_soft_reset(struct sdhc_host *hp, int mask) } int +sdhc_wait_intr_cold(struct sdhc_host *hp, int mask, int timo) +{ + int status; + + mask |= SDHC_ERROR_INTERRUPT; + timo = timo * tick; + status = hp->intr_status; + while ((status & mask) == 0) { + + status = HREAD2(hp, SDHC_NINTR_STATUS); + if (ISSET(status, SDHC_NINTR_STATUS_MASK)) { + HWRITE2(hp, SDHC_NINTR_STATUS, status); + if (ISSET(status, SDHC_ERROR_INTERRUPT)) { + uint16_t error; + error = HREAD2(hp, SDHC_EINTR_STATUS); + HWRITE2(hp, SDHC_EINTR_STATUS, error); + hp->intr_status |= status; + + if (ISSET(error, SDHC_CMD_TIMEOUT_ERROR| + SDHC_DATA_TIMEOUT_ERROR)) + break; + } + + if (ISSET(status, SDHC_BUFFER_READ_READY | + SDHC_BUFFER_WRITE_READY | SDHC_COMMAND_COMPLETE | + SDHC_TRANSFER_COMPLETE)) { + hp->intr_status |= status; + break; + } + + if (ISSET(status, SDHC_CARD_INTERRUPT)) { + HSET2(hp, SDHC_NINTR_STATUS_EN, + SDHC_CARD_INTERRUPT); + } + + continue; + } + + delay(1); + if (timo-- == 0) { + status |= SDHC_ERROR_INTERRUPT; + break; + } + } + + hp->intr_status &= ~(status & mask); + return (status & mask); +} + +int sdhc_wait_intr(struct sdhc_host *hp, int mask, int timo) { int status; int s; + if (cold) + return (sdhc_wait_intr_cold(hp, mask, timo)); + mask |= SDHC_ERROR_INTERRUPT; s = splsdmmc(); @@ -1222,3 +1279,14 @@ sdhc_dump_regs(struct sdhc_host *hp) HREAD4(hp, SDHC_MAX_CAPABILITIES)); } #endif + +int +sdhc_hibernate_init(sdmmc_chipset_handle_t sch, void *fake_softc) +{ + struct sdhc_host *hp, *fhp; + fhp = fake_softc; + hp = sch; + *fhp = *hp; + + return (0); +} diff --git a/sys/dev/sdmmc/sdmmc.c b/sys/dev/sdmmc/sdmmc.c index bb7d4cc96b6..7a7fc01389e 100644 --- a/sys/dev/sdmmc/sdmmc.c +++ b/sys/dev/sdmmc/sdmmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc.c,v 1.49 2018/02/11 20:58:40 patrick Exp $ */ +/* $OpenBSD: sdmmc.c,v 1.50 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -630,7 +630,8 @@ sdmmc_mmc_command(struct sdmmc_softc *sc, struct sdmmc_command *cmd) #endif error = cmd->c_error; - wakeup(cmd); + if (!cold) + wakeup(cmd); return error; } diff --git a/sys/dev/sdmmc/sdmmc_mem.c b/sys/dev/sdmmc/sdmmc_mem.c index 4d926ff0f63..8c7f1728e26 100644 --- a/sys/dev/sdmmc/sdmmc_mem.c +++ b/sys/dev/sdmmc/sdmmc_mem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_mem.c,v 1.30 2017/04/06 03:15:29 deraadt Exp $ */ +/* $OpenBSD: sdmmc_mem.c,v 1.31 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -28,6 +28,10 @@ #include <dev/sdmmc/sdmmcreg.h> #include <dev/sdmmc/sdmmcvar.h> +#ifdef HIBERNATE +#include <uvm/uvm_extern.h> +#endif + typedef struct { uint32_t _bits[512/32]; } __packed __aligned(4) sdmmc_bitfield512_t; void sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *); @@ -1104,3 +1108,37 @@ out: rw_exit(&sc->sc_lock); return (error); } + +#ifdef HIBERNATE +int +sdmmc_mem_hibernate_write(struct sdmmc_function *sf, daddr_t blkno, + u_char *data, size_t datalen) +{ + struct sdmmc_softc *sc = sf->sc; + int i, error; + struct bus_dmamap dmamap; + paddr_t phys_addr; + + if (ISSET(sc->sc_caps, SMC_CAPS_SINGLE_ONLY)) { + for (i = 0; i < datalen / sf->csd.sector_size; i++) { + error = sdmmc_mem_write_block_subr(sf, NULL, blkno + i, + data + i * sf->csd.sector_size, + sf->csd.sector_size); + if (error) + return (error); + } + } else if (!ISSET(sc->sc_caps, SMC_CAPS_DMA)) { + return (sdmmc_mem_write_block_subr(sf, NULL, blkno, data, + datalen)); + } + + /* pretend we're bus_dmamap_load */ + bzero(&dmamap, sizeof(dmamap)); + pmap_extract(pmap_kernel(), (vaddr_t)data, &phys_addr); + dmamap.dm_mapsize = datalen; + dmamap.dm_nsegs = 1; + dmamap.dm_segs[0].ds_addr = phys_addr; + dmamap.dm_segs[0].ds_len = datalen; + return (sdmmc_mem_write_block_subr(sf, &dmamap, blkno, data, datalen)); +} +#endif diff --git a/sys/dev/sdmmc/sdmmc_scsi.c b/sys/dev/sdmmc/sdmmc_scsi.c index 7c84610a742..3060a76ffba 100644 --- a/sys/dev/sdmmc/sdmmc_scsi.c +++ b/sys/dev/sdmmc/sdmmc_scsi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmc_scsi.c,v 1.40 2017/04/06 17:00:53 deraadt Exp $ */ +/* $OpenBSD: sdmmc_scsi.c,v 1.41 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -32,6 +32,13 @@ #include <dev/sdmmc/sdmmc_scsi.h> #include <dev/sdmmc/sdmmcvar.h> +#ifdef HIBERNATE +#include <sys/hibernate.h> +#include <sys/disk.h> +#include <sys/disklabel.h> +#include <sys/rwlock.h> +#endif + #define SDMMC_SCSIID_HOST 0x00 #define SDMMC_SCSIID_MAX 0x0f @@ -552,3 +559,93 @@ sdmmc_scsi_minphys(struct buf *bp, struct scsi_link *sl) minphys(bp); } + +#ifdef HIBERNATE +int +sdmmc_scsi_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size, + int op, void *page) +{ + struct { + struct sdmmc_softc sdmmc_sc; + struct sdmmc_function sdmmc_sf; + daddr_t poffset; + size_t psize; + struct sdmmc_function *orig_sf; + char chipset_softc[0]; /* size depends on the chipset layer */ + } *state = page; + extern struct cfdriver sd_cd; + struct device *disk, *scsibus, *chip, *sdmmc; + struct scsibus_softc *bus_sc; + struct sdmmc_scsi_softc *scsi_sc; + struct scsi_link *link; + struct sdmmc_function *sf; + struct sdmmc_softc *sc; + int error; + + switch (op) { + case HIB_INIT: + /* find device (sdmmc_softc, sdmmc_function) */ + disk = disk_lookup(&sd_cd, DISKUNIT(dev)); + scsibus = disk->dv_parent; + sdmmc = scsibus->dv_parent; + chip = sdmmc->dv_parent; + + bus_sc = (struct scsibus_softc *)scsibus; + scsi_sc = (struct sdmmc_scsi_softc *)scsibus; + SLIST_FOREACH(link, &bus_sc->sc_link_list, bus_list) { + if (link->device_softc == disk) { + sc = (struct sdmmc_softc *)link->adapter_softc; + scsi_sc = sc->sc_scsibus; + sf = scsi_sc->sc_tgt[link->target].card; + } + } + + /* if the chipset doesn't do hibernate, bail out now */ + sc = (struct sdmmc_softc *)sdmmc; + if (sc->sct->hibernate_init == NULL) + return (ENOTTY); + + state->sdmmc_sc = *sc; + state->sdmmc_sf = *sf; + state->sdmmc_sf.sc = &state->sdmmc_sc; + + /* pretend we own the lock */ + state->sdmmc_sc.sc_lock.rwl_owner = + (((long)curproc) & ~RWLOCK_MASK) | RWLOCK_WRLOCK; + + /* build chip layer fake softc */ + error = state->sdmmc_sc.sct->hibernate_init(state->sdmmc_sc.sch, + &state->chipset_softc); + if (error) + return (error); + state->sdmmc_sc.sch = state->chipset_softc; + + /* make sure we're talking to the right target */ + state->orig_sf = sc->sc_card; + error = sdmmc_select_card(&state->sdmmc_sc, &state->sdmmc_sf); + if (error) + return (error); + + state->poffset = blkno; + state->psize = size; + return (0); + + case HIB_W: + if (blkno > state->psize) + return (E2BIG); + return (sdmmc_mem_hibernate_write(&state->sdmmc_sf, + blkno + state->poffset, (u_char *)addr, size)); + + case HIB_DONE: + /* + * bring the hardware state back into line with the real + * softc by operating on the fake one + */ + sdmmc_select_card(&state->sdmmc_sc, state->orig_sf); + return (0); + } + + return (EINVAL); +} + +#endif diff --git a/sys/dev/sdmmc/sdmmcchip.h b/sys/dev/sdmmc/sdmmcchip.h index 464521602f7..a370bf10638 100644 --- a/sys/dev/sdmmc/sdmmcchip.h +++ b/sys/dev/sdmmc/sdmmcchip.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcchip.h,v 1.10 2017/12/24 12:55:52 kettenis Exp $ */ +/* $OpenBSD: sdmmcchip.h,v 1.11 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -46,6 +46,8 @@ struct sdmmc_chip_functions { void (*card_intr_ack)(sdmmc_chipset_handle_t); /* UHS functions */ int (*signal_voltage)(sdmmc_chipset_handle_t, int); + /* hibernate */ + int (*hibernate_init)(sdmmc_chipset_handle_t, void *); }; /* host controller reset */ diff --git a/sys/dev/sdmmc/sdmmcvar.h b/sys/dev/sdmmc/sdmmcvar.h index 0510bdaa6d1..af8a2f85506 100644 --- a/sys/dev/sdmmc/sdmmcvar.h +++ b/sys/dev/sdmmc/sdmmcvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdmmcvar.h,v 1.28 2018/02/11 20:58:40 patrick Exp $ */ +/* $OpenBSD: sdmmcvar.h,v 1.29 2018/03/20 04:18:40 jmatthew Exp $ */ /* * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> @@ -280,6 +280,11 @@ int sdmmc_mem_init(struct sdmmc_softc *, struct sdmmc_function *); int sdmmc_mem_read_block(struct sdmmc_function *, int, u_char *, size_t); int sdmmc_mem_write_block(struct sdmmc_function *, int, u_char *, size_t); +#ifdef HIBERNATE +int sdmmc_mem_hibernate_write(struct sdmmc_function *, daddr_t, u_char *, + size_t); +#endif + /* ioctls */ #include <sys/ioccom.h> |