summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/hibernate_machdep.c8
-rw-r--r--sys/arch/i386/i386/hibernate_machdep.c8
-rw-r--r--sys/dev/sdmmc/files.sdmmc4
-rw-r--r--sys/dev/sdmmc/sdhc.c72
-rw-r--r--sys/dev/sdmmc/sdmmc.c5
-rw-r--r--sys/dev/sdmmc/sdmmc_mem.c40
-rw-r--r--sys/dev/sdmmc/sdmmc_scsi.c99
-rw-r--r--sys/dev/sdmmc/sdmmcchip.h4
-rw-r--r--sys/dev/sdmmc/sdmmcvar.h7
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>