Module Name: src
Committed By: jmcneill
Date: Sat Jun 24 11:27:33 UTC 2017
Modified Files:
src/sys/dev/sdmmc: ld_sdmmc.c sdmmc_mem.c sdmmcreg.h sdmmcvar.h
Log Message:
Add discard support to ld@sdmmc using the ERASE (CMD38) command.
To generate a diff of this commit:
cvs rdiff -u -r1.27 -r1.28 src/sys/dev/sdmmc/ld_sdmmc.c
cvs rdiff -u -r1.57 -r1.58 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.29 -r1.30 src/sys/dev/sdmmc/sdmmcreg.h
cvs rdiff -u -r1.24 -r1.25 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/dev/sdmmc/ld_sdmmc.c
diff -u src/sys/dev/sdmmc/ld_sdmmc.c:1.27 src/sys/dev/sdmmc/ld_sdmmc.c:1.28
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.27 Tue Jun 6 21:01:07 2017
+++ src/sys/dev/sdmmc/ld_sdmmc.c Sat Jun 24 11:27:33 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: ld_sdmmc.c,v 1.27 2017/06/06 21:01:07 jmcneill Exp $ */
+/* $NetBSD: ld_sdmmc.c,v 1.28 2017/06/24 11:27:33 jmcneill Exp $ */
/*
* Copyright (c) 2008 KIYOHARA Takashi
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.27 2017/06/06 21:01:07 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.28 2017/06/24 11:27:33 jmcneill Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -93,6 +93,7 @@ static int ld_sdmmc_detach(device_t, int
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_sdmmc_attach(device_t parent, device_
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 @@ ld_sdmmc_dump(struct ld_softc *ld, void
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
Index: src/sys/dev/sdmmc/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.57 src/sys/dev/sdmmc/sdmmc_mem.c:1.58
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.57 Sun Jun 4 15:00:02 2017
+++ src/sys/dev/sdmmc/sdmmc_mem.c Sat Jun 24 11:27:33 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmc_mem.c,v 1.57 2017/06/04 15:00:02 jmcneill Exp $ */
+/* $NetBSD: sdmmc_mem.c,v 1.58 2017/06/24 11:27:33 jmcneill 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.57 2017/06/04 15:00:02 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.58 2017/06/24 11:27:33 jmcneill Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -1987,3 +1987,68 @@ out:
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);
+
+#ifdef SDMMC_DEBUG
+ device_printf(sc->sc_dev, "discard blk %u-%u error %d\n",
+ sblkno, eblkno, error);
+#endif
+
+ return error;
+}
Index: src/sys/dev/sdmmc/sdmmcreg.h
diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.29 src/sys/dev/sdmmc/sdmmcreg.h:1.30
--- src/sys/dev/sdmmc/sdmmcreg.h:1.29 Fri Feb 17 10:51:48 2017
+++ src/sys/dev/sdmmc/sdmmcreg.h Sat Jun 24 11:27:33 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmcreg.h,v 1.29 2017/02/17 10:51:48 nonaka Exp $ */
+/* $NetBSD: sdmmcreg.h,v 1.30 2017/06/24 11:27:33 jmcneill Exp $ */
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -61,6 +61,8 @@
#define SD_SEND_SWITCH_FUNC 6 /* R1 */
#define SD_SEND_IF_COND 8 /* R7 */
#define SD_VOLTAGE_SWITCH 11 /* R1 */
+#define SD_ERASE_WR_BLK_START 32 /* R1 */
+#define SD_ERASE_WR_BLK_END 33 /* R1 */
/* SD application commands */ /* response type */
#define SD_APP_SET_BUS_WIDTH 6 /* R1 */
Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.24 src/sys/dev/sdmmc/sdmmcvar.h:1.25
--- src/sys/dev/sdmmc/sdmmcvar.h:1.24 Sun Jun 4 15:00:02 2017
+++ src/sys/dev/sdmmc/sdmmcvar.h Sat Jun 24 11:27:33 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: sdmmcvar.h,v 1.24 2017/06/04 15:00:02 jmcneill Exp $ */
+/* $NetBSD: sdmmcvar.h,v 1.25 2017/06/24 11:27:33 jmcneill Exp $ */
/* $OpenBSD: sdmmcvar.h,v 1.13 2009/01/09 10:55:22 jsg Exp $ */
/*
@@ -377,5 +377,6 @@ int sdmmc_mem_read_block(struct sdmmc_fu
size_t);
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);
#endif /* _SDMMCVAR_H_ */