Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-8]: src/sys/dev/sdmmc Pull up following revision(s) (requested by...



details:   https://anonhg.NetBSD.org/src/rev/d990a9414e6b
branches:  netbsd-8
changeset: 850773:d990a9414e6b
user:      snj <snj%NetBSD.org@localhost>
date:      Sat Jul 01 08:45:03 2017 +0000

description:
Pull up following revision(s) (requested by jmcneill in ticket #67):
        sys/dev/sdmmc/ld_sdmmc.c: 1.28
        sys/dev/sdmmc/sdmmc_mem.c: 1.58-1.60
        sys/dev/sdmmc/sdmmcreg.h: 1.30, 1.31
        sys/dev/sdmmc/sdmmcvar.h: 1.25-1.27
Add discard support to ld@sdmmc using the ERASE (CMD38) command.
--
Read SD status register and print card status when a new SD card is found:
  sdmmc0: SD card status: 4-bit, C10, U1, V10
If the SD status register reports discard support, set the DISCARD arg to
the ERASE operation to let the card know that the host doesn't care if the
erase is performed.
--
Revert part of previous; the SD card spec recommends not to issue a DISCARD
command to the file system area.

diffstat:

 sys/dev/sdmmc/ld_sdmmc.c  |   14 ++-
 sys/dev/sdmmc/sdmmc_mem.c |  212 +++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/sdmmc/sdmmcreg.h  |   44 +++++++++-
 sys/dev/sdmmc/sdmmcvar.h  |    3 +-
 4 files changed, 266 insertions(+), 7 deletions(-)

diffs (truncated from 395 to 300 lines):

diff -r 6e46847d7962 -r d990a9414e6b sys/dev/sdmmc/ld_sdmmc.c
--- a/sys/dev/sdmmc/ld_sdmmc.c  Sat Jul 01 08:41:23 2017 +0000
+++ b/sys/dev/sdmmc/ld_sdmmc.c  Sat Jul 01 08:45:03 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ld_sdmmc.c,v 1.26.4.1 2017/06/09 16:52:10 snj Exp $    */
+/*     $NetBSD: ld_sdmmc.c,v 1.26.4.2 2017/07/01 08:45:03 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.1 2017/06/09 16:52:10 snj Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.26.4.2 2017/07/01 08:45:03 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -93,6 +93,7 @@
 static int ld_sdmmc_dump(struct ld_softc *, void *, int, int);
 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 void ld_sdmmc_doattach(void *);
 static void ld_sdmmc_dobio(void *);
@@ -149,6 +150,7 @@
        ld->sc_maxqueuecnt = LD_SDMMC_MAXQUEUECNT;
        ld->sc_dump = ld_sdmmc_dump;
        ld->sc_start = ld_sdmmc_start;
+       ld->sc_discard = ld_sdmmc_discard;
 
        /*
         * It is avoided that the error occurs when the card attaches it,
@@ -297,6 +299,14 @@
            blkcnt * ld->sc_secsize);
 }
 
+static int
+ld_sdmmc_discard(struct ld_softc *ld, off_t pos, off_t len)
+{
+       struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
+
+       return sdmmc_mem_discard(sc->sc_sf, pos, len);
+}
+
 MODULE(MODULE_CLASS_DRIVER, ld_sdmmc, "ld");
 
 #ifdef _MODULE
diff -r 6e46847d7962 -r d990a9414e6b sys/dev/sdmmc/sdmmc_mem.c
--- a/sys/dev/sdmmc/sdmmc_mem.c Sat Jul 01 08:41:23 2017 +0000
+++ b/sys/dev/sdmmc/sdmmc_mem.c Sat Jul 01 08:45:03 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sdmmc_mem.c,v 1.56.4.1 2017/06/04 20:45:54 bouyer Exp $        */
+/*     $NetBSD: sdmmc_mem.c,v 1.56.4.2 2017/07/01 08:45:03 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.1 2017/06/04 20:45:54 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.56.4.2 2017/07/01 08:45:03 snj Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -79,6 +79,10 @@
 static int sdmmc_mem_send_scr(struct sdmmc_softc *, struct sdmmc_function *,
     uint32_t *scr);
 static int sdmmc_mem_decode_scr(struct sdmmc_softc *, struct sdmmc_function *);
+static int sdmmc_mem_send_ssr(struct sdmmc_softc *, struct sdmmc_function *,
+    sdmmc_bitfield512_t *);
+static int sdmmc_mem_decode_ssr(struct sdmmc_softc *, struct sdmmc_function *,
+    sdmmc_bitfield512_t *);
 static int sdmmc_mem_send_cxd_data(struct sdmmc_softc *, int, void *, size_t);
 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 *);
@@ -778,7 +782,7 @@
 sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
        int support_func, best_func, bus_clock, error, i;
-       sdmmc_bitfield512_t status; /* Switch Function Status */
+       sdmmc_bitfield512_t status;
        bool ddr = false;
 
        /* change bus clock */
@@ -888,6 +892,15 @@
        sc->sc_transfer_mode = switch_group0_functions[best_func].name;
        sc->sc_busddr = ddr;
 
+       /* get card status */
+       error = sdmmc_mem_send_ssr(sc, sf, &status);
+       if (error) {
+               aprint_error_dev(sc->sc_dev, "can't get SD status: %d\n",
+                   error);
+               return error;
+       }
+       sdmmc_mem_decode_ssr(sc, sf, &status);
+
        /* execute tuning (UHS) */
        error = sdmmc_mem_execute_tuning(sc, sf);
        if (error) {
@@ -1270,6 +1283,134 @@
 }
 
 static int
+sdmmc_mem_send_ssr(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+    sdmmc_bitfield512_t *ssr)
+{
+       struct sdmmc_command cmd;
+       bus_dma_segment_t ds[1];
+       void *ptr = NULL;
+       int datalen = 64;
+       int rseg;
+       int error = 0;
+
+       /* Don't lock */
+
+       if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+               error = bus_dmamem_alloc(sc->sc_dmat, datalen, PAGE_SIZE, 0,
+                   ds, 1, &rseg, BUS_DMA_NOWAIT);
+               if (error)
+                       goto out;
+               error = bus_dmamem_map(sc->sc_dmat, ds, 1, datalen, &ptr,
+                   BUS_DMA_NOWAIT);
+               if (error)
+                       goto dmamem_free;
+               error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmap, ptr, datalen,
+                   NULL, BUS_DMA_NOWAIT|BUS_DMA_STREAMING|BUS_DMA_READ);
+               if (error)
+                       goto dmamem_unmap;
+
+               bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+                   BUS_DMASYNC_PREREAD);
+       } else {
+               ptr = malloc(datalen, M_DEVBUF, M_NOWAIT | M_ZERO);
+               if (ptr == NULL)
+                       goto out;
+       }
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.c_data = ptr;
+       cmd.c_datalen = datalen;
+       cmd.c_blklen = datalen;
+       cmd.c_arg = 0;
+       cmd.c_flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1 | SCF_RSP_SPI_R1;
+       cmd.c_opcode = SD_APP_SD_STATUS;
+       if (ISSET(sc->sc_caps, SMC_CAPS_DMA))
+               cmd.c_dmamap = sc->sc_dmap;
+
+       error = sdmmc_app_command(sc, sf, &cmd);
+       if (error == 0) {
+               if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+                       bus_dmamap_sync(sc->sc_dmat, sc->sc_dmap, 0, datalen,
+                           BUS_DMASYNC_POSTREAD);
+               }
+               memcpy(ssr, ptr, datalen);
+       }
+
+out:
+       if (ptr != NULL) {
+               if (ISSET(sc->sc_caps, SMC_CAPS_DMA)) {
+                       bus_dmamap_unload(sc->sc_dmat, sc->sc_dmap);
+dmamem_unmap:
+                       bus_dmamem_unmap(sc->sc_dmat, ptr, datalen);
+dmamem_free:
+                       bus_dmamem_free(sc->sc_dmat, ds, rseg);
+               } else {
+                       free(ptr, M_DEVBUF);
+               }
+       }
+       DPRINTF(("%s: sdmem_mem_send_ssr: error = %d\n", SDMMCDEVNAME(sc),
+           error));
+
+       if (error == 0)
+               sdmmc_be512_to_bitfield512(ssr);
+
+#ifdef SDMMC_DEBUG
+       if (error == 0)
+               sdmmc_dump_data("SSR", ssr, datalen);
+#endif
+       return error;
+}
+
+static int
+sdmmc_mem_decode_ssr(struct sdmmc_softc *sc, struct sdmmc_function *sf,
+    sdmmc_bitfield512_t *ssr_bitfield)
+{
+       uint32_t *ssr = (uint32_t *)ssr_bitfield;
+       int speed_class_val, bus_width_val;
+
+       const int bus_width = SSR_DAT_BUS_WIDTH(ssr);
+       const int speed_class = SSR_SPEED_CLASS(ssr);
+       const int uhs_speed_grade = SSR_UHS_SPEED_GRADE(ssr);
+       const int video_speed_class = SSR_VIDEO_SPEED_CLASS(ssr);
+       const int app_perf_class = SSR_APP_PERF_CLASS(ssr);
+
+       switch (speed_class) {
+       case SSR_SPEED_CLASS_0: speed_class_val = 0; break;
+       case SSR_SPEED_CLASS_2: speed_class_val = 2; break;
+       case SSR_SPEED_CLASS_4: speed_class_val = 4; break;
+       case SSR_SPEED_CLASS_6: speed_class_val = 6; break;
+       case SSR_SPEED_CLASS_10: speed_class_val = 10; break;
+       default: speed_class_val = -1; break;
+       }
+
+       switch (bus_width) {
+       case SSR_DAT_BUS_WIDTH_1: bus_width_val = 1; break;
+       case SSR_DAT_BUS_WIDTH_4: bus_width_val = 4; break;
+       default: bus_width_val = -1;
+       }
+
+       /*
+        * Log card status
+        */
+       device_printf(sc->sc_dev, "SD card status:");
+       if (bus_width_val != -1)
+               printf(" %d-bit", bus_width_val);
+       else
+               printf(" unknown bus width");
+       if (speed_class_val != -1)
+               printf(", C%d", speed_class_val);
+       if (uhs_speed_grade)
+               printf(", U%d", uhs_speed_grade);
+       if (video_speed_class)
+               printf(", V%d", video_speed_class);
+       if (app_perf_class)
+               printf(", A%d", app_perf_class);
+       printf("\n");
+
+       return 0;
+}
+
+static int
 sdmmc_mem_send_cxd_data(struct sdmmc_softc *sc, int opcode, void *data,
     size_t datalen)
 {
@@ -1987,3 +2128,68 @@
 
        return error;
 }
+
+int
+sdmmc_mem_discard(struct sdmmc_function *sf, off_t pos, off_t len)
+{
+       struct sdmmc_softc *sc = sf->sc;
+       struct sdmmc_command cmd;
+       int error;
+
+       if (ISSET(sc->sc_caps, SMC_CAPS_SPI_MODE))
+               return ENODEV;  /* XXX not tested */
+
+       /* Erase what we can in the specified range. */
+       const off_t start = roundup(pos, SDMMC_SECTOR_SIZE);
+       const off_t end = rounddown(pos + len, SDMMC_SECTOR_SIZE) - 1;
+       if (end < start)
+               return EINVAL;
+       const uint32_t sblkno = start / SDMMC_SECTOR_SIZE;
+       const uint32_t eblkno = end / SDMMC_SECTOR_SIZE;
+
+       SDMMC_LOCK(sc);
+       mutex_enter(&sc->sc_mtx);
+
+       /* Set the address of the first write block to be erased */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.c_opcode = ISSET(sc->sc_flags, SMF_SD_MODE) ?
+           SD_ERASE_WR_BLK_START : MMC_TAG_ERASE_GROUP_START;
+       cmd.c_arg = sblkno;
+       if (!ISSET(sf->flags, SFF_SDHC))
+               cmd.c_arg <<= SDMMC_SECTOR_SIZE_SB;
+       cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
+       error = sdmmc_mmc_command(sc, &cmd);
+       if (error)
+               goto out;
+
+       /* Set the address of the last write block to be erased */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.c_opcode = ISSET(sc->sc_flags, SMF_SD_MODE) ?
+           SD_ERASE_WR_BLK_END : MMC_TAG_ERASE_GROUP_END;
+       cmd.c_arg = eblkno;
+       if (!ISSET(sf->flags, SFF_SDHC))
+               cmd.c_arg <<= SDMMC_SECTOR_SIZE_SB;
+       cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1;
+       error = sdmmc_mmc_command(sc, &cmd);
+       if (error)
+               goto out;
+
+       /* Start the erase operation */
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.c_opcode = MMC_ERASE;
+       cmd.c_flags = SCF_CMD_AC | SCF_RSP_R1B;
+       error = sdmmc_mmc_command(sc, &cmd);
+       if (error)
+               goto out;
+
+out:
+       mutex_exit(&sc->sc_mtx);
+       SDMMC_UNLOCK(sc);
+



Home | Main Index | Thread Index | Old Index