Module Name: src Committed By: snj Date: Tue Jul 25 01:49:13 UTC 2017
Modified Files: src/sys/arch/arm/sunxi [netbsd-8]: sunxi_mmc.c src/sys/dev/sdmmc [netbsd-8]: ld_sdmmc.c sdmmc_mem.c sdmmcreg.h sdmmcvar.h Log Message: Pull up following revision(s) (requested by jmcneill in ticket #139): sys/arch/arm/sunxi/sunxi_mmc.c: revision 1.2 sys/dev/sdmmc/ld_sdmmc.c: revision 1.31 sys/dev/sdmmc/sdmmc_mem.c: revision 1.61 sys/dev/sdmmc/sdmmcreg.h: revision 1.32 sys/dev/sdmmc/sdmmcvar.h: revision 1.28 Add support for eMMC 4.5's optional cache feature. If a cache is present, and the host controller reports the SMC_CAPS_POLLING capability (needed to flush cache at shutdown), it will be automatically enabled and used. -- Add SMC_CAPS_POLLING support. To generate a diff of this commit: cvs rdiff -u -r1.3.4.2 -r1.3.4.3 src/sys/arch/arm/sunxi/sunxi_mmc.c cvs rdiff -u -r1.26.4.3 -r1.26.4.4 src/sys/dev/sdmmc/ld_sdmmc.c cvs rdiff -u -r1.56.4.2 -r1.56.4.3 src/sys/dev/sdmmc/sdmmc_mem.c cvs rdiff -u -r1.29.6.1 -r1.29.6.2 src/sys/dev/sdmmc/sdmmcreg.h cvs rdiff -u -r1.23.6.2 -r1.23.6.3 src/sys/dev/sdmmc/sdmmcvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/sunxi/sunxi_mmc.c diff -u src/sys/arch/arm/sunxi/sunxi_mmc.c:1.3.4.2 src/sys/arch/arm/sunxi/sunxi_mmc.c:1.3.4.3 --- src/sys/arch/arm/sunxi/sunxi_mmc.c:1.3.4.2 Tue Jul 18 19:13:08 2017 +++ src/sys/arch/arm/sunxi/sunxi_mmc.c Tue Jul 25 01:49:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sunxi_mmc.c,v 1.3.4.2 2017/07/18 19:13:08 snj Exp $ */ +/* $NetBSD: sunxi_mmc.c,v 1.3.4.3 2017/07/25 01:49:13 snj Exp $ */ /*- * Copyright (c) 2014-2017 Jared McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.3.4.2 2017/07/18 19:13:08 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.3.4.3 2017/07/25 01:49:13 snj Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -317,7 +317,8 @@ sunxi_mmc_attach_i(device_t self) SMC_CAPS_MULTI_SEG_DMA | SMC_CAPS_AUTO_STOP | SMC_CAPS_SD_HIGHSPEED | - SMC_CAPS_MMC_HIGHSPEED; + SMC_CAPS_MMC_HIGHSPEED | + SMC_CAPS_POLLING; if (width == 4) saa.saa_caps |= SMC_CAPS_4BIT_MODE; if (width == 8) @@ -368,7 +369,8 @@ sunxi_mmc_intr(void *priv) } static int -sunxi_mmc_wait_rint(struct sunxi_mmc_softc *sc, uint32_t mask, int timeout) +sunxi_mmc_wait_rint(struct sunxi_mmc_softc *sc, uint32_t mask, + int timeout, bool poll) { int retry; int error; @@ -378,15 +380,24 @@ sunxi_mmc_wait_rint(struct sunxi_mmc_sof if (sc->sc_intr_rint & mask) return 0; - retry = timeout / hz; + if (poll) + retry = timeout / hz * 1000; + else + retry = timeout / hz; while (retry > 0) { - error = cv_timedwait(&sc->sc_intr_cv, - &sc->sc_intr_lock, hz); - if (error && error != EWOULDBLOCK) - return error; + if (poll) { + sc->sc_intr_rint |= MMC_READ(sc, SUNXI_MMC_RINT); + } else { + error = cv_timedwait(&sc->sc_intr_cv, + &sc->sc_intr_lock, hz); + if (error && error != EWOULDBLOCK) + return error; + } if (sc->sc_intr_rint & mask) return 0; + if (poll) + delay(1000); --retry; } @@ -420,7 +431,6 @@ sunxi_mmc_host_reset(sdmmc_chipset_handl MMC_WRITE(sc, SUNXI_MMC_GCTRL, MMC_READ(sc, SUNXI_MMC_GCTRL) | SUNXI_MMC_GCTRL_INTEN); - return 0; } @@ -680,13 +690,14 @@ sunxi_mmc_exec_command(sdmmc_chipset_han { struct sunxi_mmc_softc *sc = sch; uint32_t cmdval = SUNXI_MMC_CMD_START; + const bool poll = (cmd->c_flags & SCF_POLL) != 0; int retry; #ifdef SUNXI_MMC_DEBUG aprint_normal_dev(sc->sc_dev, - "opcode %d flags 0x%x data %p datalen %d blklen %d\n", + "opcode %d flags 0x%x data %p datalen %d blklen %d poll %d\n", cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen, - cmd->c_blklen); + cmd->c_blklen, poll); #endif mutex_enter(&sc->sc_intr_lock); @@ -766,7 +777,7 @@ sunxi_mmc_exec_command(sdmmc_chipset_han } cmd->c_error = sunxi_mmc_wait_rint(sc, - SUNXI_MMC_INT_ERROR|SUNXI_MMC_INT_CMD_DONE, hz * 10); + SUNXI_MMC_INT_ERROR|SUNXI_MMC_INT_CMD_DONE, hz * 10, poll); if (cmd->c_error == 0 && (sc->sc_intr_rint & SUNXI_MMC_INT_ERROR)) { if (sc->sc_intr_rint & SUNXI_MMC_INT_RESP_TIMEOUT) { cmd->c_error = ETIMEDOUT; @@ -787,7 +798,7 @@ sunxi_mmc_exec_command(sdmmc_chipset_han SUNXI_MMC_INT_ERROR| SUNXI_MMC_INT_AUTO_CMD_DONE| SUNXI_MMC_INT_DATA_OVER, - hz*10); + hz*10, poll); if (cmd->c_error == 0 && (sc->sc_intr_rint & SUNXI_MMC_INT_ERROR)) { cmd->c_error = ETIMEDOUT; Index: src/sys/dev/sdmmc/ld_sdmmc.c diff -u src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.3 src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.4 --- src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.3 Mon Jul 10 12:29:47 2017 +++ src/sys/dev/sdmmc/ld_sdmmc.c Tue Jul 25 01:49:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: ld_sdmmc.c,v 1.26.4.3 2017/07/10 12:29:47 martin Exp $ */ +/* $NetBSD: ld_sdmmc.c,v 1.26.4.4 2017/07/25 01:49:13 snj Exp $ */ /* * Copyright (c) 2008 KIYOHARA Takashi @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.26.4.3 2017/07/10 12:29:47 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.26.4.4 2017/07/25 01:49:13 snj Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -94,6 +94,7 @@ static int ld_sdmmc_dump(struct ld_softc static int ld_sdmmc_start(struct ld_softc *, struct buf *); static void ld_sdmmc_restart(void *); static int ld_sdmmc_discard(struct ld_softc *, off_t, off_t); +static int ld_sdmmc_ioctl(struct ld_softc *, u_long, void *, int32_t, bool); static void ld_sdmmc_doattach(void *); static void ld_sdmmc_dobio(void *); @@ -151,6 +152,7 @@ ld_sdmmc_attach(device_t parent, device_ ld->sc_dump = ld_sdmmc_dump; ld->sc_start = ld_sdmmc_start; ld->sc_discard = ld_sdmmc_discard; + ld->sc_ioctl = ld_sdmmc_ioctl; /* * It is avoided that the error occurs when the card attaches it, @@ -169,11 +171,19 @@ ld_sdmmc_doattach(void *arg) struct ld_sdmmc_softc *sc = (struct ld_sdmmc_softc *)arg; struct ld_softc *ld = &sc->sc_ld; struct sdmmc_softc *ssc = device_private(device_parent(ld->sc_dv)); + const u_int cache_size = sc->sc_sf->ext_csd.cache_size; + char buf[sizeof("9999 KB")]; ldattach(ld, BUFQ_DISK_DEFAULT_STRAT); aprint_normal_dev(ld->sc_dv, "%d-bit width,", sc->sc_sf->width); if (ssc->sc_transfer_mode != NULL) aprint_normal(" %s,", ssc->sc_transfer_mode); + if (cache_size > 0) { + format_bytes(buf, sizeof(buf), cache_size); + aprint_normal(" %s cache%s,", buf, + ISSET(sc->sc_sf->flags, SFF_CACHE_ENABLED) ? "" : + " (disabled)"); + } if ((ssc->sc_busclk / 1000) != 0) aprint_normal(" %u.%03u MHz\n", ssc->sc_busclk / 1000, ssc->sc_busclk % 1000); @@ -307,6 +317,20 @@ ld_sdmmc_discard(struct ld_softc *ld, of return sdmmc_mem_discard(sc->sc_sf, pos, len); } +static int +ld_sdmmc_ioctl(struct ld_softc *ld, u_long cmd, void *addr, int32_t flag, + bool poll) +{ + struct ld_sdmmc_softc *sc = device_private(ld->sc_dv); + + switch (cmd) { + case DIOCCACHESYNC: + return sdmmc_mem_flush_cache(sc->sc_sf, poll); + default: + return EPASSTHROUGH; + } +} + MODULE(MODULE_CLASS_DRIVER, ld_sdmmc, "ld"); #ifdef _MODULE Index: src/sys/dev/sdmmc/sdmmc_mem.c diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.2 src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.3 --- src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.2 Sat Jul 1 08:45:03 2017 +++ src/sys/dev/sdmmc/sdmmc_mem.c Tue Jul 25 01:49:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_mem.c,v 1.56.4.2 2017/07/01 08:45:03 snj Exp $ */ +/* $NetBSD: sdmmc_mem.c,v 1.56.4.3 2017/07/25 01:49:13 snj Exp $ */ /* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -45,7 +45,7 @@ /* Routines for SD/MMC memory cards. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.56.4.2 2017/07/01 08:45:03 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.56.4.3 2017/07/25 01:49:13 snj Exp $"); #ifdef _KERNEL_OPT #include "opt_sdmmc.h" @@ -87,7 +87,7 @@ static int sdmmc_mem_send_cxd_data(struc static int sdmmc_set_bus_width(struct sdmmc_function *, int); static int sdmmc_mem_sd_switch(struct sdmmc_function *, int, int, int, sdmmc_bitfield512_t *); static int sdmmc_mem_mmc_switch(struct sdmmc_function *, uint8_t, uint8_t, - uint8_t); + uint8_t, bool); static int sdmmc_mem_signal_voltage(struct sdmmc_softc *, int); static int sdmmc_mem_spi_read_ocr(struct sdmmc_softc *, uint32_t, uint32_t *); static int sdmmc_mem_single_read_block(struct sdmmc_function *, uint32_t, @@ -981,7 +981,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s if (width != 1) { error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_BUS_WIDTH, value); + EXT_CSD_BUS_WIDTH, value, false); if (error == 0) error = sdmmc_chip_bus_width(sc->sc_sct, sc->sc_sch, width); @@ -1002,7 +1002,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s } if (hs_timing != EXT_CSD_HS_TIMING_LEGACY) { error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_HS_TIMING, hs_timing); + EXT_CSD_HS_TIMING, hs_timing, false); if (error) { aprint_error_dev(sc->sc_dev, "can't change high speed %d, error %d\n", @@ -1048,7 +1048,7 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s error = sdmmc_mem_mmc_switch(sf, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, (width == 8) ? EXT_CSD_BUS_WIDTH_8_DDR : - EXT_CSD_BUS_WIDTH_4_DDR); + EXT_CSD_BUS_WIDTH_4_DDR, false); if (error) { DPRINTF(("%s: can't switch to DDR" " (%d bit)\n", SDMMCDEVNAME(sc), width)); @@ -1104,6 +1104,23 @@ sdmmc_mem_mmc_init(struct sdmmc_softc *s sf->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; } + + if (sf->ext_csd.rev >= 6) { + sf->ext_csd.cache_size = + le32dec(&ext_csd[EXT_CSD_CACHE_SIZE]) * 1024; + } + if (sf->ext_csd.cache_size > 0) { + /* eMMC cache present, enable it */ + error = sdmmc_mem_mmc_switch(sf, + EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CACHE_CTRL, + EXT_CSD_CACHE_CTRL_CACHE_EN, false); + if (error) { + aprint_error_dev(sc->sc_dev, + "can't enable cache: %d\n", error); + } else { + SET(sf->flags, SFF_CACHE_ENABLED); + } + } } else { if (sc->sc_busclk > sf->csd.tran_speed) sc->sc_busclk = sf->csd.tran_speed; @@ -1600,7 +1617,7 @@ dmamem_free: static int sdmmc_mem_mmc_switch(struct sdmmc_function *sf, uint8_t set, uint8_t index, - uint8_t value) + uint8_t value, bool poll) { struct sdmmc_softc *sc = sf->sc; struct sdmmc_command cmd; @@ -1612,6 +1629,9 @@ sdmmc_mem_mmc_switch(struct sdmmc_functi (index << 16) | (value << 8) | set; cmd.c_flags = SCF_RSP_SPI_R1B | SCF_RSP_R1B | SCF_CMD_AC; + if (poll) + cmd.c_flags |= SCF_POLL; + error = sdmmc_mmc_command(sc, &cmd); if (error) return error; @@ -1623,6 +1643,8 @@ sdmmc_mem_mmc_switch(struct sdmmc_functi if (!ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE)) cmd.c_arg = MMC_ARG_RCA(sf->rca); cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1 | SCF_RSP_SPI_R2; + if (poll) + cmd.c_flags |= SCF_POLL; error = sdmmc_mmc_command(sc, &cmd); if (error) break; @@ -2193,3 +2215,29 @@ out: return error; } + +int +sdmmc_mem_flush_cache(struct sdmmc_function *sf, bool poll) +{ + struct sdmmc_softc *sc = sf->sc; + int error; + + if (!ISSET(sf->flags, SFF_CACHE_ENABLED)) + return 0; + + SDMMC_LOCK(sc); + mutex_enter(&sc->sc_mtx); + + error = sdmmc_mem_mmc_switch(sf, + EXT_CSD_CMD_SET_NORMAL, EXT_CSD_FLUSH_CACHE, + EXT_CSD_FLUSH_CACHE_FLUSH, poll); + + mutex_exit(&sc->sc_mtx); + SDMMC_UNLOCK(sc); + +#ifdef SDMMC_DEBUG + device_printf(sc->sc_dev, "mmc flush cache error %d\n", error); +#endif + + return error; +} Index: src/sys/dev/sdmmc/sdmmcreg.h diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.29.6.1 src/sys/dev/sdmmc/sdmmcreg.h:1.29.6.2 --- src/sys/dev/sdmmc/sdmmcreg.h:1.29.6.1 Sat Jul 1 08:45:03 2017 +++ src/sys/dev/sdmmc/sdmmcreg.h Tue Jul 25 01:49:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcreg.h,v 1.29.6.1 2017/07/01 08:45:03 snj Exp $ */ +/* $NetBSD: sdmmcreg.h,v 1.29.6.2 2017/07/25 01:49:13 snj Exp $ */ /* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -121,6 +121,8 @@ #define SD_ARG_BUS_WIDTH_4 2 /* EXT_CSD fields */ +#define EXT_CSD_FLUSH_CACHE 32 /* W/E_P */ +#define EXT_CSD_CACHE_CTRL 33 /* R/W/E_P */ #define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ #define EXT_CSD_BUS_WIDTH 183 /* W/E_P */ #define EXT_CSD_HS_TIMING 185 /* R/W/E_P */ @@ -128,12 +130,20 @@ #define EXT_CSD_STRUCTURE 194 /* R */ #define EXT_CSD_CARD_TYPE 196 /* R */ #define EXT_CSD_SEC_COUNT 212 /* R */ +#define EXT_CSD_CACHE_SIZE 249 /* R (4 bytes) */ /* EXT_CSD field definitions */ #define EXT_CSD_CMD_SET_NORMAL (1U << 0) #define EXT_CSD_CMD_SET_SECURE (1U << 1) #define EXT_CSD_CMD_SET_CPSECURE (1U << 2) +/* EXT_CSD_FLUSH_CACHE */ +#define EXT_CSD_FLUSH_CACHE_FLUSH (1U << 0) +#define EXT_CSD_FLUSH_CACHE_BARRIER (1U << 1) + +/* EXT_CSD_CACHE_CTRL */ +#define EXT_CSD_CACHE_CTRL_CACHE_EN (1U << 0) + /* EXT_CSD_BUS_WIDTH */ #define EXT_CSD_BUS_WIDTH_1 0 /* 1 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* 4 bit mode */ Index: src/sys/dev/sdmmc/sdmmcvar.h diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.2 src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.3 --- src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.2 Sat Jul 1 08:45:03 2017 +++ src/sys/dev/sdmmc/sdmmcvar.h Tue Jul 25 01:49:13 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmcvar.h,v 1.23.6.2 2017/07/01 08:45:03 snj Exp $ */ +/* $NetBSD: sdmmcvar.h,v 1.23.6.3 2017/07/25 01:49:13 snj Exp $ */ /* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */ /* @@ -52,6 +52,7 @@ struct sdmmc_csd { struct sdmmc_ext_csd { uint8_t rev; uint8_t rst_n_function; /* RST_n_FUNCTION */ + uint32_t cache_size; }; struct sdmmc_cid { @@ -122,8 +123,9 @@ struct sdmmc_command { #define SCF_RSP_SPI_BSY (1U << 13) /* Probing */ #define SCF_TOUT_OK (1U << 14) /* command timeout expected */ -/* Transfer hints */ +/* Command hints */ #define SCF_XFER_SDHC (1U << 15) /* card is SDHC */ +#define SCF_POLL (1U << 16) /* polling required */ /* response types */ #define SCF_RSP_R0 0 /* none */ #define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) @@ -185,6 +187,7 @@ struct sdmmc_function { int flags; #define SFF_ERROR 0x0001 /* function is poo; ignore it */ #define SFF_SDHC 0x0002 /* SD High Capacity card */ +#define SFF_CACHE_ENABLED 0x0004 /* cache enabled */ SIMPLEQ_ENTRY(sdmmc_function) sf_list; /* SD card I/O function members */ int number; /* I/O function number or -1 */ @@ -249,6 +252,7 @@ struct sdmmc_softc { | SMC_CAPS_UHS_SDR104 \ | SMC_CAPS_UHS_DDR50) #define SMC_CAPS_MMC_HS200 __BIT(15) /* eMMC HS200 timing */ +#define SMC_CAPS_POLLING __BIT(30) /* driver supports cmd polling */ /* function */ int sc_function_count; /* number of I/O functions (SDIO) */ @@ -378,5 +382,6 @@ int sdmmc_mem_read_block(struct sdmmc_fu int sdmmc_mem_write_block(struct sdmmc_function *, uint32_t, u_char *, size_t); int sdmmc_mem_discard(struct sdmmc_function *, off_t, off_t); +int sdmmc_mem_flush_cache(struct sdmmc_function *, bool); #endif /* _SDMMCVAR_H_ */