svn commit: r338638 - stable/10/sys/dev/mmc
Marius Strobl
marius at FreeBSD.org
Thu Sep 13 10:18:52 UTC 2018
Author: marius
Date: Thu Sep 13 10:18:50 2018
New Revision: 338638
URL: https://svnweb.freebsd.org/changeset/base/338638
Log:
MFC: r333614, r333647, r338275, r338280, r338513
- Let mmcsd_ioctl() ensure appropriate privileges via priv_check(9).
- If present, take advantage of the R/W cache of eMMC revision 1.5 and
later devices. These caches work akin to the ones found in HDDs/SSDs
that ada(4)/da(4) also enable if existent, but likewise increase the
likelihood of data loss in case of a sudden power outage etc. On the
other hand, write performance is up to twice as high for e. g. 1 GiB
files depending on the actual chip and transfer mode employed.
For maximum data integrity, the usage of eMMC caches can be disabled
via the hw.mmcsd.cache tunable.
- Get rid of the NOP mmcsd_open().
- Obtain the bus mode (MMC or SD) from the directly superordinated
bus rather than reaching up to the bridge and use the cached mode
in mmcsd_delete(), too.
- Use le32dec(9) for decoding EXT_CSD values where it makes sense. [1]
- Locally cache some instance variable values in mmc_discover_cards()
in order to improve the code readability a bit.
Obtained from: NetBSD [1]
Modified:
stable/10/sys/dev/mmc/mmc.c
stable/10/sys/dev/mmc/mmcreg.h
stable/10/sys/dev/mmc/mmcsd.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/dev/mmc/mmc.c
==============================================================================
--- stable/10/sys/dev/mmc/mmc.c Thu Sep 13 10:18:47 2018 (r338637)
+++ stable/10/sys/dev/mmc/mmc.c Thu Sep 13 10:18:50 2018 (r338638)
@@ -1588,10 +1588,13 @@ mmc_discover_cards(struct mmc_softc *sc)
uint32_t raw_cid[4];
struct mmc_ivars *ivar = NULL;
const struct mmc_quirk *quirk;
+ const uint8_t *ext_csd;
device_t child;
int err, host_caps, i, newcard;
uint32_t resp, sec_count, status;
uint16_t rca = 2;
+ int16_t rev;
+ uint8_t card_type;
host_caps = mmcbr_get_caps(sc->dev);
if (bootverbose || mmc_debug)
@@ -1779,6 +1782,7 @@ mmc_discover_cards(struct mmc_softc *sc)
goto free_ivar;
}
+ rev = -1;
/* Only MMC >= 4.x devices support EXT_CSD. */
if (ivar->csd.spec_vers >= 4) {
err = mmc_send_ext_csd(sc->dev, sc->dev,
@@ -1788,11 +1792,10 @@ mmc_discover_cards(struct mmc_softc *sc)
"Error reading EXT_CSD %d\n", err);
goto free_ivar;
}
+ ext_csd = ivar->raw_ext_csd;
+ rev = ext_csd[EXT_CSD_REV];
/* Handle extended capacity from EXT_CSD */
- sec_count = ivar->raw_ext_csd[EXT_CSD_SEC_CNT] +
- (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 1] << 8) +
- (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 2] << 16) +
- (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
+ sec_count = le32dec(&ext_csd[EXT_CSD_SEC_CNT]);
if (sec_count != 0) {
ivar->sec_count = sec_count;
ivar->high_cap = 1;
@@ -1800,65 +1803,56 @@ mmc_discover_cards(struct mmc_softc *sc)
/* Find maximum supported bus width. */
ivar->bus_width = mmc_test_bus_width(sc);
/* Get device speeds beyond normal mode. */
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS_52) != 0) {
+ card_type = ext_csd[EXT_CSD_CARD_TYPE];
+ if ((card_type & EXT_CSD_CARD_TYPE_HS_52) != 0) {
setbit(&ivar->timings, bus_timing_hs);
ivar->hs_tran_speed = MMC_TYPE_HS_52_MAX;
- } else if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS_26) != 0) {
+ } else if ((card_type & EXT_CSD_CARD_TYPE_HS_26) != 0) {
setbit(&ivar->timings, bus_timing_hs);
ivar->hs_tran_speed = MMC_TYPE_HS_26_MAX;
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_DDR_52_1_2V) != 0 &&
+ if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_2V) != 0 &&
(host_caps & MMC_CAP_SIGNALING_120) != 0) {
setbit(&ivar->timings, bus_timing_mmc_ddr52);
setbit(&ivar->vccq_120, bus_timing_mmc_ddr52);
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_DDR_52_1_8V) != 0 &&
+ if ((card_type & EXT_CSD_CARD_TYPE_DDR_52_1_8V) != 0 &&
(host_caps & MMC_CAP_SIGNALING_180) != 0) {
setbit(&ivar->timings, bus_timing_mmc_ddr52);
setbit(&ivar->vccq_180, bus_timing_mmc_ddr52);
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 &&
+ if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 &&
(host_caps & MMC_CAP_SIGNALING_120) != 0) {
setbit(&ivar->timings, bus_timing_mmc_hs200);
setbit(&ivar->vccq_120, bus_timing_mmc_hs200);
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 &&
+ if ((card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 &&
(host_caps & MMC_CAP_SIGNALING_180) != 0) {
setbit(&ivar->timings, bus_timing_mmc_hs200);
setbit(&ivar->vccq_180, bus_timing_mmc_hs200);
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
+ if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
(host_caps & MMC_CAP_SIGNALING_120) != 0 &&
ivar->bus_width == bus_width_8) {
setbit(&ivar->timings, bus_timing_mmc_hs400);
setbit(&ivar->vccq_120, bus_timing_mmc_hs400);
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
+ if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
(host_caps & MMC_CAP_SIGNALING_180) != 0 &&
ivar->bus_width == bus_width_8) {
setbit(&ivar->timings, bus_timing_mmc_hs400);
setbit(&ivar->vccq_180, bus_timing_mmc_hs400);
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
- (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] &
+ if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
+ (ext_csd[EXT_CSD_STROBE_SUPPORT] &
EXT_CSD_STROBE_SUPPORT_EN) != 0 &&
(host_caps & MMC_CAP_SIGNALING_120) != 0 &&
ivar->bus_width == bus_width_8) {
setbit(&ivar->timings, bus_timing_mmc_hs400es);
setbit(&ivar->vccq_120, bus_timing_mmc_hs400es);
}
- if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
- EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
- (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] &
+ if ((card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
+ (ext_csd[EXT_CSD_STROBE_SUPPORT] &
EXT_CSD_STROBE_SUPPORT_EN) != 0 &&
(host_caps & MMC_CAP_SIGNALING_180) != 0 &&
ivar->bus_width == bus_width_8) {
@@ -1870,13 +1864,13 @@ mmc_discover_cards(struct mmc_softc *sc)
* units of 10 ms), defaulting to 500 ms.
*/
ivar->cmd6_time = 500 * 1000;
- if (ivar->raw_ext_csd[EXT_CSD_REV] >= 6)
+ if (rev >= 6)
ivar->cmd6_time = 10 *
- ivar->raw_ext_csd[EXT_CSD_GEN_CMD6_TIME];
+ ext_csd[EXT_CSD_GEN_CMD6_TIME];
/* Handle HC erase sector size. */
- if (ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) {
+ if (ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) {
ivar->erase_sector = 1024 *
- ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE];
+ ext_csd[EXT_CSD_ERASE_GRP_SIZE];
err = mmc_switch(sc->dev, sc->dev, ivar->rca,
EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_ERASE_GRP_DEF,
@@ -1891,8 +1885,7 @@ mmc_discover_cards(struct mmc_softc *sc)
}
}
- mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid,
- ivar->raw_ext_csd[EXT_CSD_REV] >= 5);
+ mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid, rev >= 5);
child_common:
for (quirk = &mmc_quirks[0]; quirk->mid != 0x0; quirk++) {
Modified: stable/10/sys/dev/mmc/mmcreg.h
==============================================================================
--- stable/10/sys/dev/mmc/mmcreg.h Thu Sep 13 10:18:47 2018 (r338637)
+++ stable/10/sys/dev/mmc/mmcreg.h Thu Sep 13 10:18:50 2018 (r338638)
@@ -300,6 +300,8 @@ struct mmc_request {
/*
* EXT_CSD fields
*/
+#define EXT_CSD_FLUSH_CACHE 32 /* W/E */
+#define EXT_CSD_CACHE_CTRL 33 /* R/W/E */
#define EXT_CSD_EXT_PART_ATTR 52 /* R/W, 2 bytes */
#define EXT_CSD_ENH_START_ADDR 136 /* R/W, 4 bytes */
#define EXT_CSD_ENH_SIZE_MULT 140 /* R/W, 3 bytes */
@@ -333,12 +335,19 @@ struct mmc_request {
#define EXT_CSD_PWR_CL_200_360 237 /* RO */
#define EXT_CSD_PWR_CL_52_195_DDR 238 /* RO */
#define EXT_CSD_PWR_CL_52_360_DDR 239 /* RO */
+#define EXT_CSD_CACHE_FLUSH_POLICY 249 /* RO */
#define EXT_CSD_GEN_CMD6_TIME 248 /* RO */
+#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_200_360_DDR 253 /* RO */
/*
* EXT_CSD field definitions
*/
+#define EXT_CSD_FLUSH_CACHE_FLUSH 0x01
+#define EXT_CSD_FLUSH_CACHE_BARRIER 0x02
+
+#define EXT_CSD_CACHE_CTRL_CACHE_EN 0x01
+
#define EXT_CSD_EXT_PART_ATTR_DEFAULT 0x0
#define EXT_CSD_EXT_PART_ATTR_SYSTEMCODE 0x1
#define EXT_CSD_EXT_PART_ATTR_NPERSISTENT 0x2
@@ -417,6 +426,8 @@ struct mmc_request {
#define EXT_CSD_SEC_FEATURE_SUPPORT_BD_BLK_EN 0x04
#define EXT_CSD_SEC_FEATURE_SUPPORT_GB_CL_EN 0x10
#define EXT_CSD_SEC_FEATURE_SUPPORT_SANITIZE 0x40
+
+#define EXT_CSD_CACHE_FLUSH_POLICY_FIFO 0x01
/*
* Vendor specific EXT_CSD fields
Modified: stable/10/sys/dev/mmc/mmcsd.c
==============================================================================
--- stable/10/sys/dev/mmc/mmcsd.c Thu Sep 13 10:18:47 2018 (r338637)
+++ stable/10/sys/dev/mmc/mmcsd.c Thu Sep 13 10:18:50 2018 (r338638)
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bio.h>
#include <sys/bus.h>
#include <sys/conf.h>
+#include <sys/endian.h>
#include <sys/fcntl.h>
#include <sys/ioccom.h>
#include <sys/kernel.h>
@@ -67,7 +68,9 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
+#include <sys/priv.h>
#include <sys/slicer.h>
+#include <sys/sysctl.h>
#include <sys/time.h>
#include <geom/geom.h>
@@ -129,6 +132,8 @@ struct mmcsd_softc {
uint32_t flags;
#define MMCSD_INAND_CMD38 0x0001
#define MMCSD_USE_TRIM 0x0002
+#define MMCSD_FLUSH_CACHE 0x0004
+#define MMCSD_DIRTY 0x0008
uint32_t cmd6_time; /* Generic switch timeout [us] */
uint32_t part_time; /* Partition switch timeout [us] */
off_t enh_base; /* Enhanced user data area slice base ... */
@@ -149,12 +154,20 @@ static const char *errmsg[] =
"NO MEMORY"
};
+static SYSCTL_NODE(_hw, OID_AUTO, mmcsd, CTLFLAG_RD, NULL, "mmcsd driver");
+
+static int mmcsd_cache = 1;
+TUNABLE_INT("hw.mmcsd.cache", &mmcsd_cache);
+SYSCTL_INT(_hw_mmcsd, OID_AUTO, cache, CTLFLAG_RDTUN, &mmcsd_cache, 0,
+ "Device R/W cache enabled if present");
+
#define LOG_PPS 5 /* Log no more than 5 errors per second. */
/* bus entry points */
static int mmcsd_attach(device_t dev);
static int mmcsd_detach(device_t dev);
static int mmcsd_probe(device_t dev);
+static int mmcsd_shutdown(device_t dev);
/* disk routines */
static int mmcsd_close(struct disk *dp);
@@ -163,7 +176,6 @@ static int mmcsd_dump(void *arg, void *virtual, vm_off
static int mmcsd_getattr(struct bio *);
static int mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data,
int fflag, struct thread *td);
-static int mmcsd_open(struct disk *dp);
static void mmcsd_strategy(struct bio *bp);
static void mmcsd_task(void *arg);
@@ -176,8 +188,9 @@ static void mmcsd_add_part(struct mmcsd_softc *sc, u_i
static int mmcsd_bus_bit_width(device_t dev);
static daddr_t mmcsd_delete(struct mmcsd_part *part, struct bio *bp);
static const char *mmcsd_errmsg(int e);
+static int mmcsd_flush_cache(struct mmcsd_softc *sc);
static int mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data,
- int fflag);
+ int fflag, struct thread *td);
static int mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic,
int fflag);
static uintmax_t mmcsd_pretty_size(off_t size, char *unit);
@@ -234,7 +247,7 @@ mmcsd_attach(device_t dev)
sc = device_get_softc(dev);
sc->dev = dev;
sc->mmcbus = mmcbus = device_get_parent(dev);
- sc->mode = mmcbr_get_mode(mmcbus);
+ sc->mode = mmc_get_card_type(dev);
/*
* Note that in principle with an SDHCI-like re-tuning implementation,
* the maximum data size can change at runtime due to a device removal/
@@ -294,6 +307,28 @@ mmcsd_attach(device_t dev)
rev = ext_csd[EXT_CSD_REV];
/*
+ * With revision 1.5 (MMC v4.5, EXT_CSD_REV == 6) and later, take
+ * advantage of the device R/W cache if present and useage is not
+ * disabled.
+ */
+ if (rev >= 6 && mmcsd_cache != 0) {
+ size = le32dec(&ext_csd[EXT_CSD_CACHE_SIZE]);
+ if (bootverbose)
+ device_printf(dev, "cache size %juKB\n", size);
+ if (size > 0) {
+ MMCBUS_ACQUIRE_BUS(mmcbus, dev);
+ err = mmc_switch(mmcbus, dev, sc->rca,
+ EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL,
+ EXT_CSD_CACHE_CTRL_CACHE_EN, sc->cmd6_time, true);
+ MMCBUS_RELEASE_BUS(mmcbus, dev);
+ if (err != MMC_ERR_NONE)
+ device_printf(dev, "failed to enable cache\n");
+ else
+ sc->flags |= MMCSD_FLUSH_CACHE;
+ }
+ }
+
+ /*
* Ignore user-creatable enhanced user data area and general purpose
* partitions partitions as long as partitioning hasn't been finished.
*/
@@ -323,10 +358,8 @@ mmcsd_attach(device_t dev)
size *= erase_size * wp_size;
if (size != mmc_get_media_size(dev) * sector_size) {
sc->enh_size = size;
- sc->enh_base = (ext_csd[EXT_CSD_ENH_START_ADDR] +
- (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
- (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
- (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24)) *
+ sc->enh_base =
+ le32dec(&ext_csd[EXT_CSD_ENH_START_ADDR]) *
(sc->high_cap != 0 ? MMC_SECTOR_SIZE : 1);
} else if (bootverbose)
device_printf(dev,
@@ -502,7 +535,6 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, con
MMCSD_DISK_LOCK_INIT(part);
d = part->disk = disk_alloc();
- d->d_open = mmcsd_open;
d->d_close = mmcsd_close;
d->d_strategy = mmcsd_strategy;
d->d_ioctl = mmcsd_ioctl_disk;
@@ -516,6 +548,8 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, con
d->d_stripesize = sc->erase_sector * d->d_sectorsize;
d->d_unit = cnt;
d->d_flags = DISKFLAG_CANDELETE;
+ if ((sc->flags & MMCSD_FLUSH_CACHE) != 0)
+ d->d_flags |= DISKFLAG_CANFLUSHCACHE;
d->d_delmaxsize = mmc_get_erase_sector(dev) * d->d_sectorsize;
strlcpy(d->d_ident, mmc_get_card_sn_string(dev),
sizeof(d->d_ident));
@@ -668,10 +702,22 @@ mmcsd_detach(device_t dev)
free(part, M_DEVBUF);
}
}
+ if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
+ device_printf(dev, "failed to flush cache\n");
return (0);
}
static int
+mmcsd_shutdown(device_t dev)
+{
+ struct mmcsd_softc *sc = device_get_softc(dev);
+
+ if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
+ device_printf(dev, "failed to flush cache\n");
+ return (0);
+}
+
+static int
mmcsd_suspend(device_t dev)
{
struct mmcsd_softc *sc = device_get_softc(dev);
@@ -703,6 +749,8 @@ mmcsd_suspend(device_t dev)
MMCSD_IOCTL_UNLOCK(part);
}
}
+ if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
+ device_printf(dev, "failed to flush cache\n");
return (0);
}
@@ -737,19 +785,18 @@ mmcsd_resume(device_t dev)
}
static int
-mmcsd_open(struct disk *dp __unused)
+mmcsd_close(struct disk *dp)
{
+ struct mmcsd_softc *sc;
+ if ((dp->d_flags & DISKFLAG_OPEN) != 0) {
+ sc = ((struct mmcsd_part *)dp->d_drv1)->sc;
+ if (mmcsd_flush_cache(sc) != MMC_ERR_NONE)
+ device_printf(sc->dev, "failed to flush cache\n");
+ }
return (0);
}
-static int
-mmcsd_close(struct disk *dp __unused)
-{
-
- return (0);
-}
-
static void
mmcsd_strategy(struct bio *bp)
{
@@ -771,22 +818,23 @@ mmcsd_strategy(struct bio *bp)
static int
mmcsd_ioctl_rpmb(struct cdev *dev, u_long cmd, caddr_t data,
- int fflag, struct thread *td __unused)
+ int fflag, struct thread *td)
{
- return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag));
+ return (mmcsd_ioctl(dev->si_drv1, cmd, data, fflag, td));
}
static int
mmcsd_ioctl_disk(struct disk *disk, u_long cmd, void *data, int fflag,
- struct thread *td __unused)
+ struct thread *td)
{
- return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag));
+ return (mmcsd_ioctl(disk->d_drv1, cmd, data, fflag, td));
}
static int
-mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag)
+mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag,
+ struct thread *td)
{
struct mmc_ioc_cmd *mic;
struct mmc_ioc_multi_cmd *mimc;
@@ -796,6 +844,10 @@ mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void
if ((fflag & FREAD) == 0)
return (EBADF);
+ err = priv_check(td, PRIV_DRIVER);
+ if (err != 0)
+ return (err);
+
err = 0;
switch (cmd) {
case MMC_IOC_CMD:
@@ -937,6 +989,8 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_io
if (err != MMC_ERR_NONE)
goto switch_back;
}
+ if (mic->write_flag != 0)
+ sc->flags |= MMCSD_DIRTY;
if (mic->is_acmd != 0)
(void)mmc_wait_for_app_cmd(mmcbus, dev, rca, &cmd, 0);
else
@@ -1149,6 +1203,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp)
else
cmd.opcode = MMC_READ_SINGLE_BLOCK;
} else {
+ sc->flags |= MMCSD_DIRTY;
if (numblocks > 1)
cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK;
else
@@ -1257,7 +1312,7 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
memset(&cmd, 0, sizeof(cmd));
cmd.mrq = &req;
req.cmd = &cmd;
- if (mmc_get_card_type(dev) == mode_sd)
+ if (sc->mode == mode_sd)
cmd.opcode = SD_ERASE_WR_BLK_START;
else
cmd.opcode = MMC_ERASE_GROUP_START;
@@ -1276,7 +1331,7 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
memset(&req, 0, sizeof(req));
memset(&cmd, 0, sizeof(cmd));
req.cmd = &cmd;
- if (mmc_get_card_type(dev) == mode_sd)
+ if (sc->mode == mode_sd)
cmd.opcode = SD_ERASE_WR_BLK_END;
else
cmd.opcode = MMC_ERASE_GROUP_END;
@@ -1334,13 +1389,18 @@ mmcsd_dump(void *arg, void *virtual, vm_offset_t physi
device_t dev, mmcbus;
int err;
- /* length zero is special and really means flush buffers to media */
- if (!length)
- return (0);
-
disk = arg;
part = disk->d_drv1;
sc = part->sc;
+
+ /* length zero is special and really means flush buffers to media */
+ if (length == 0) {
+ err = mmcsd_flush_cache(sc);
+ if (err != MMC_ERR_NONE)
+ return (EIO);
+ return (0);
+ }
+
dev = sc->dev;
mmcbus = sc->mmcbus;
@@ -1390,6 +1450,14 @@ mmcsd_task(void *arg)
"mmcsd disk jobqueue", 0);
} while (bp == NULL);
MMCSD_DISK_UNLOCK(part);
+ if (__predict_false(bp->bio_cmd == BIO_FLUSH)) {
+ if (mmcsd_flush_cache(sc) != MMC_ERR_NONE) {
+ bp->bio_error = EIO;
+ bp->bio_flags |= BIO_ERROR;
+ }
+ biodone(bp);
+ continue;
+ }
if (bp->bio_cmd != BIO_READ && part->ro) {
bp->bio_error = EROFS;
bp->bio_resid = bp->bio_bcount;
@@ -1447,10 +1515,35 @@ mmcsd_bus_bit_width(device_t dev)
return (8);
}
+static int
+mmcsd_flush_cache(struct mmcsd_softc *sc)
+{
+ device_t dev, mmcbus;
+ int err;
+
+ if ((sc->flags & MMCSD_FLUSH_CACHE) == 0)
+ return (MMC_ERR_NONE);
+
+ dev = sc->dev;
+ mmcbus = sc->mmcbus;
+ MMCBUS_ACQUIRE_BUS(mmcbus, dev);
+ if ((sc->flags & MMCSD_DIRTY) == 0) {
+ MMCBUS_RELEASE_BUS(mmcbus, dev);
+ return (MMC_ERR_NONE);
+ }
+ err = mmc_switch(mmcbus, dev, sc->rca, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_FLUSH_CACHE, EXT_CSD_FLUSH_CACHE_FLUSH, 60 * 1000, true);
+ if (err == MMC_ERR_NONE)
+ sc->flags &= ~MMCSD_DIRTY;
+ MMCBUS_RELEASE_BUS(mmcbus, dev);
+ return (err);
+}
+
static device_method_t mmcsd_methods[] = {
DEVMETHOD(device_probe, mmcsd_probe),
DEVMETHOD(device_attach, mmcsd_attach),
DEVMETHOD(device_detach, mmcsd_detach),
+ DEVMETHOD(device_shutdown, mmcsd_shutdown),
DEVMETHOD(device_suspend, mmcsd_suspend),
DEVMETHOD(device_resume, mmcsd_resume),
DEVMETHOD_END
More information about the svn-src-stable-10
mailing list