Module Name:    src
Committed By:   jakllsch
Date:           Sat Dec 15 00:03:01 UTC 2012

Modified Files:
        src/sys/dev/sdmmc: sdmmc_mem.c sdmmcreg.h

Log Message:
Correctly read the 512-bit-wide big-endian Switch Function Status register.
Some of this could/will also be useful for the SD Status register.


To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.26 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/sdmmc/sdmmcreg.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/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.25 src/sys/dev/sdmmc/sdmmc_mem.c:1.26
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.25	Fri Dec 14 23:22:21 2012
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Sat Dec 15 00:03:00 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_mem.c,v 1.25 2012/12/14 23:22:21 jakllsch Exp $	*/
+/*	$NetBSD: sdmmc_mem.c,v 1.26 2012/12/15 00:03:00 jakllsch 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.25 2012/12/14 23:22:21 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.26 2012/12/15 00:03:00 jakllsch Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -67,6 +67,8 @@ __KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,
 #define DPRINTF(s)	do {} while (/*CONSTCOND*/0)
 #endif
 
+typedef struct { uint32_t _bits[512/32]; } __packed __aligned(4) sdmmc_bitfield512_t;
+
 static int sdmmc_mem_sd_init(struct sdmmc_softc *, struct sdmmc_function *);
 static int sdmmc_mem_mmc_init(struct sdmmc_softc *, struct sdmmc_function *);
 static int sdmmc_mem_send_cid(struct sdmmc_softc *, sdmmc_response *);
@@ -77,7 +79,7 @@ static int sdmmc_mem_send_scr(struct sdm
 static int sdmmc_mem_decode_scr(struct sdmmc_softc *, struct sdmmc_function *);
 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, void *);
+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);
 static int sdmmc_mem_spi_read_ocr(struct sdmmc_softc *, uint32_t, uint32_t *);
@@ -574,6 +576,20 @@ sdmmc_mem_set_blocklen(struct sdmmc_soft
 	return error;
 }
 
+/* make 512-bit BE quantity __bitfield()-compatible */
+static void
+sdmmc_be512_to_bitfield512(sdmmc_bitfield512_t *buf) {
+	size_t i;
+	uint32_t tmp0, tmp1;
+	const size_t bitswords = __arraycount(buf->_bits);
+	for (i = 0; i < bitswords/2; i++) {
+		tmp0 = buf->_bits[i];
+		tmp1 = buf->_bits[bitswords - 1 - i];
+		buf->_bits[i] = be32toh(tmp1);
+		buf->_bits[bitswords - 1 - i] = be32toh(tmp0);
+	}
+}
+
 static int
 sdmmc_mem_sd_init(struct sdmmc_softc *sc, struct sdmmc_function *sf)
 {
@@ -599,7 +615,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 		{ MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V,	 50000 },
 	};
 	int host_ocr, support_func, best_func, error, g, i;
-	char status[64];
+	sdmmc_bitfield512_t status; /* Switch Function Status */
 
 	error = sdmmc_mem_send_scr(sc, sf, sf->raw_scr);
 	if (error) {
@@ -625,7 +641,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 	if (sf->scr.sd_spec >= SCR_SD_SPEC_VER_1_10 &&
 	    ISSET(sf->csd.ccc, SD_CSD_CCC_SWITCH)) {
 		DPRINTF(("%s: switch func mode 0\n", SDMMCDEVNAME(sc)));
-		error = sdmmc_mem_sd_switch(sf, 0, 1, 0, status);
+		error = sdmmc_mem_sd_switch(sf, 0, 1, 0, &status);
 		if (error) {
 			aprint_error_dev(sc->sc_dev,
 			    "switch func mode 0 failed\n");
@@ -633,7 +649,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 		}
 
 		host_ocr = sdmmc_chip_host_ocr(sc->sc_sct, sc->sc_sch);
-		support_func = SFUNC_STATUS_GROUP(status, 1);
+		support_func = SFUNC_STATUS_GROUP(&status, 1);
 		best_func = 0;
 		for (i = 0, g = 1;
 		    i < __arraycount(switch_group0_functions); i++, g <<= 1) {
@@ -647,7 +663,7 @@ sdmmc_mem_sd_init(struct sdmmc_softc *sc
 			DPRINTF(("%s: switch func mode 1(func=%d)\n",
 			    SDMMCDEVNAME(sc), best_func));
 			error =
-			    sdmmc_mem_sd_switch(sf, 1, 1, best_func, status);
+			    sdmmc_mem_sd_switch(sf, 1, 1, best_func, &status);
 			if (error) {
 				aprint_error_dev(sc->sc_dev,
 				    "switch func mode 1 failed:"
@@ -1059,7 +1075,7 @@ sdmmc_set_bus_width(struct sdmmc_functio
 
 static int
 sdmmc_mem_sd_switch(struct sdmmc_function *sf, int mode, int group,
-    int function, void *status)
+    int function, sdmmc_bitfield512_t *status)
 {
 	struct sdmmc_softc *sc = sf->sc;
 	struct sdmmc_command cmd;
@@ -1132,6 +1148,10 @@ dmamem_free:
 			free(ptr, M_DEVBUF);
 		}
 	}
+
+	if (error == 0)
+		sdmmc_be512_to_bitfield512(status);
+
 	return error;
 }
 

Index: src/sys/dev/sdmmc/sdmmcreg.h
diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.12 src/sys/dev/sdmmc/sdmmcreg.h:1.13
--- src/sys/dev/sdmmc/sdmmcreg.h:1.12	Sat Jul 28 18:38:03 2012
+++ src/sys/dev/sdmmc/sdmmcreg.h	Sat Dec 15 00:03:00 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcreg.h,v 1.12 2012/07/28 18:38:03 matt Exp $	*/
+/*	$NetBSD: sdmmcreg.h,v 1.13 2012/12/15 00:03:00 jakllsch Exp $	*/
 /*	$OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -318,14 +318,14 @@
 
 /* Status of Switch Function */
 #define SFUNC_STATUS_GROUP(status, group) \
-	be16toh(__bitfield((uint32_t *)(status), (7 - (group)) << 4, 16))
+	(__bitfield((uint32_t *)(status), 400 + (group - 1) * 16, 16))
 
 /* This assumes the response fields are in host byte order in 32-bit units.  */
 #define MMC_RSP_BITS(resp, start, len)	__bitfield((resp), (start)-8, (len))
 static inline uint32_t
 __bitfield(const uint32_t *src, size_t start, size_t len)
 {
-	if (start + len > 128 || len == 0 || len > 32)
+	if (start + len > 512 || len == 0 || len > 32)
 		return 0;
 
 	src += start / 32;

Reply via email to