Module Name:    src
Committed By:   snj
Date:           Sat Jul  1 08:45:03 UTC 2017

Modified Files:
        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 #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.


To generate a diff of this commit:
cvs rdiff -u -r1.26.4.1 -r1.26.4.2 src/sys/dev/sdmmc/ld_sdmmc.c
cvs rdiff -u -r1.56.4.1 -r1.56.4.2 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.29 -r1.29.6.1 src/sys/dev/sdmmc/sdmmcreg.h
cvs rdiff -u -r1.23.6.1 -r1.23.6.2 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.26.4.1 src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.2
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.26.4.1	Fri Jun  9 16:52:10 2017
+++ src/sys/dev/sdmmc/ld_sdmmc.c	Sat Jul  1 08:45:03 2017
@@ -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_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.56.4.1 src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.2
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.56.4.1	Sun Jun  4 20:45:54 2017
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Sat Jul  1 08:45:03 2017
@@ -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_csd(struct sdm
 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 @@ static int
 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 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 	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 @@ sdmmc_mem_decode_scr(struct sdmmc_softc 
 }
 
 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 @@ 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.29.6.1
--- src/sys/dev/sdmmc/sdmmcreg.h:1.29	Fri Feb 17 10:51:48 2017
+++ src/sys/dev/sdmmc/sdmmcreg.h	Sat Jul  1 08:45:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcreg.h,v 1.29 2017/02/17 10:51:48 nonaka Exp $	*/
+/*	$NetBSD: sdmmcreg.h,v 1.29.6.1 2017/07/01 08:45:03 snj 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 */
@@ -68,6 +70,10 @@
 #define SD_APP_OP_COND			41	/* R3 */
 #define SD_APP_SEND_SCR			51	/* R1 */
 
+/* SD erase arguments */
+#define SD_ERASE_DISCARD		0x00000001
+#define SD_ERASE_FULE			0x00000002
+
 /* OCR bits */
 #define MMC_OCR_MEM_READY		(1U<<31)/* memory power-up status bit */
 #define MMC_OCR_HCS			(1<<30)	/* SD only */
@@ -343,6 +349,42 @@
 #define SCR_CMD_SUPPORT_CMD20(scr)	MMC_RSP_BITS((scr), 32, 1)
 #define SCR_RESERVED2(scr)		MMC_RSP_BITS((scr), 0, 32)
 
+/* SSR (SD Status Register) */
+#define SSR_DAT_BUS_WIDTH(resp)		__bitfield((resp), 510, 2)
+#define  SSR_DAT_BUS_WIDTH_1		0
+#define  SSR_DAT_BUS_WIDTH_4		2
+#define SSR_SECURED_MODE(resp)		__bitfield((resp), 509, 1)
+#define SSR_SD_CARD_TYPE(resp)		__bitfield((resp), 480, 16)
+#define  SSR_SD_CARD_TYPE_RDWR		0
+#define  SSR_SD_CARD_TYPE_ROM		1
+#define  SSR_SD_CARD_TYPE_OTP		2
+#define SSR_SIZE_OF_PROTECTED_AREA(resp) __bitfield((resp), 448, 32)
+#define SSR_SPEED_CLASS(resp)		__bitfield((resp), 440, 8)
+#define  SSR_SPEED_CLASS_0		0
+#define  SSR_SPEED_CLASS_2		1
+#define  SSR_SPEED_CLASS_4		2
+#define  SSR_SPEED_CLASS_6		3
+#define  SSR_SPEED_CLASS_10		4
+#define SSR_PERFORMANCE_MOVE(resp)	__bitfield((resp), 432, 8)
+#define SSR_AU_SIZE(resp)		__bitfield((resp), 428, 4)
+#define SSR_ERASE_SIZE(resp)		__bitfield((resp), 408, 16)
+#define SSR_ERASE_TIMEOUT(resp)		__bitfield((resp), 402, 6)
+#define SSR_ERASE_OFFSET(resp)		__bitfield((resp), 400, 2)
+#define SSR_UHS_SPEED_GRADE(resp)	__bitfield((resp), 396, 4)
+#define  SSR_UHS_SPEED_GRADE_10MB	1
+#define  SSR_UHS_SPEED_GRADE_30MB	3
+#define SSR_UHS_AU_SIZE(resp)		__bitfield((resp), 392, 4)
+#define SSR_VIDEO_SPEED_CLASS(resp)	__bitfield((resp), 384, 8)
+#define SSR_VSC_AU_SIZE(resp)		__bitfield((resp), 368, 10)
+#define SSR_SUS_ADDR(resp)		__bitfield((resp), 346, 22)
+#define SSR_APP_PERF_CLASS(resp)	__bitfield((resp), 336, 4)
+#define  SSR_APP_PERF_CLASS_UNSUPPORTED	0
+#define  SSR_APP_PERF_CLASS_A1		1
+#define  SSR_APP_PERF_CLASS_A2		2
+#define SSR_PERFORMANCE_ENHANCE(resp)	__bitfield((resp), 328, 8)
+#define SSR_DISCARD_SUPPORT(resp)	__bitfield((resp), 313, 1)
+#define SSR_FULE_SUPPORT(resp)		__bitfield((resp), 312, 1)
+
 /* Status of Switch Function */
 #define SFUNC_STATUS_GROUP(status, group) \
 	(__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16))

Index: src/sys/dev/sdmmc/sdmmcvar.h
diff -u src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.1 src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.2
--- src/sys/dev/sdmmc/sdmmcvar.h:1.23.6.1	Sun Jun  4 20:45:54 2017
+++ src/sys/dev/sdmmc/sdmmcvar.h	Sat Jul  1 08:45:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcvar.h,v 1.23.6.1 2017/06/04 20:45:54 bouyer Exp $	*/
+/*	$NetBSD: sdmmcvar.h,v 1.23.6.2 2017/07/01 08:45:03 snj 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_ */

Reply via email to