svn commit: r315430 - in head: . etc/mtree include sys/arm/ti sys/conf sys/dev/mmc sys/dev/sdhci sys/modules/mmc sys/modules/mmcsd sys/sys

Marius Strobl marius at FreeBSD.org
Thu Mar 16 22:23:06 UTC 2017


Author: marius
Date: Thu Mar 16 22:23:04 2017
New Revision: 315430
URL: https://svnweb.freebsd.org/changeset/base/315430

Log:
  - Add support for eMMC "partitions". Besides the user data area, i. e.
    the default partition, eMMC v4.41 and later devices can additionally
    provide up to:
    1 enhanced user data area partition
    2 boot partitions
    1 RPMB (Replay Protected Memory Block) partition
    4 general purpose partitions (optionally with a enhanced or extended
      attribute)
  
    Of these "partitions", only the enhanced user data area one actually
    slices the user data area partition and, thus, gets handled with the
    help of geom_flashmap(4). The other types of partitions have address
    space independent from the default partition and need to be switched
    to via CMD6 (SWITCH), i. e. constitute a set of additional "disks".
  
    The second kind of these "partitions" doesn't fit that well into the
    design of mmc(4) and mmcsd(4). I've decided to let mmcsd(4) hook all
    of these "partitions" up as disk(9)'s (except for the RPMB partition
    as it didn't seem to make much sense to be able to put a file-system
    there and may require authentication; therefore, RPMB partitions are
    solely accessible via the newly added IOCTL interface currently; see
    also below). This approach for one resulted in cleaner code. Second,
    it retains the notion of mmcsd(4) children corresponding to a single
    physical device each. With the addition of some layering violations,
    it also would have been possible for mmc(4) to add separate mmcsd(4)
    instances with one disk each for all of these "partitions", however.
    Still, both mmc(4) and mmcsd(4) share some common code now e. g. for
    issuing CMD6, which has been factored out into mmc_subr.c.
  
    Besides simply subdividing eMMC devices, some Intel NUCs having UEFI
    code in the boot partitions etc., another use case for the partition
    support is the activation of pseudo-SLC mode, which manufacturers of
    eMMC chips typically associate with the enhanced user data area and/
    or the enhanced attribute of general purpose partitions.
  
    CAVEAT EMPTOR: Partitioning eMMC devices is a one-time operation.
  
  - Now that properly issuing CMD6 is crucial (so data isn't written to
    the wrong partition for example), make a step into the direction of
    correctly handling the timeout for these commands in the MMC layer.
    Also, do a SEND_STATUS when CMD6 is invoked with an R1B response as
    recommended by relevant specifications. However, quite some work is
    left to be done in this regard; all other R1B-type commands done by
    the MMC layer also should be followed by a SEND_STATUS (CMD13), the
    erase timeout calculations/handling as documented in specifications
    are entirely ignored so far, the MMC layer doesn't provide timeouts
    applicable up to the bridge drivers and at least sdhci(4) currently
    is hardcoding 1 s as timeout for all command types unconditionally.
    Let alone already available return codes often not being checked in
    the MMC layer ...
  
  - Add an IOCTL interface to mmcsd(4); this is sufficiently compatible
    with Linux so that the GNU mmc-utils can be ported to and used with
    FreeBSD (note that due to the remaining deficiencies outlined above
    SANITIZE operations issued by/with `mmc` currently most likely will
    fail). These latter will be added to ports as sysutils/mmc-utils in
    a bit. Among others, the `mmc` tool of the GNU mmc-utils allows for
    partitioning eMMC devices (tested working).
  
  - For devices following the eMMC specification v4.41 or later, year 0
    is 2013 rather than 1997; so correct this for assembling the device
    ID string properly.
  
  - Let mmcsd.ko depend on mmc.ko. Additionally, bump MMC_VERSION as at
    least for some of the above a matching pair is required.
  
  - In the ACPI front-end of sdhci(4) describe the Intel eMMC and SDXC
    controllers as such in order to match the PCI one.
    Additionally, in the entry for the 80860F14 SDXC controller remove
    the eMMC-only SDHCI_QUIRK_INTEL_POWER_UP_RESET.
  
  OKed by:	imp
  Submitted by:	ian (mmc_switch_status() implementation)

Added:
  head/sys/dev/mmc/mmc_ioctl.h   (contents, props changed)
  head/sys/dev/mmc/mmc_private.h   (contents, props changed)
  head/sys/dev/mmc/mmc_subr.c
     - copied, changed from r313250, head/sys/dev/mmc/mmc.c
  head/sys/dev/mmc/mmc_subr.h   (contents, props changed)
Modified:
  head/UPDATING
  head/etc/mtree/BSD.include.dist
  head/include/Makefile
  head/sys/arm/ti/ti_sdhci.c
  head/sys/conf/files
  head/sys/dev/mmc/bridge.h
  head/sys/dev/mmc/mmc.c
  head/sys/dev/mmc/mmcbrvar.h
  head/sys/dev/mmc/mmcreg.h
  head/sys/dev/mmc/mmcsd.c
  head/sys/dev/mmc/mmcvar.h
  head/sys/dev/sdhci/sdhci.c
  head/sys/dev/sdhci/sdhci.h
  head/sys/dev/sdhci/sdhci_acpi.c
  head/sys/dev/sdhci/sdhci_pci.c
  head/sys/modules/mmc/Makefile
  head/sys/modules/mmcsd/Makefile
  head/sys/sys/param.h

Modified: head/UPDATING
==============================================================================
--- head/UPDATING	Thu Mar 16 22:15:43 2017	(r315429)
+++ head/UPDATING	Thu Mar 16 22:23:04 2017	(r315430)
@@ -51,6 +51,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12
 
 ****************************** SPECIAL WARNING: ******************************
 
+20170316:
+	The mmcsd.ko module now additionally depends on geom_flashmap.ko.
+	Also, mmc.ko and mmcsd.ko need to be a matching pair built from the
+	same source (previously, the dependency of mmcsd.ko on mmc.ko was
+	missing, but mmcsd.ko now will refuse to load if it is incompatible
+	with mmc.ko).
+
 20170315:
 	The syntax of ipfw(8) named states was changed to avoid ambiguity.
 	If you have used named states in the firewall rules, you need to modify

Modified: head/etc/mtree/BSD.include.dist
==============================================================================
--- head/etc/mtree/BSD.include.dist	Thu Mar 16 22:15:43 2017	(r315429)
+++ head/etc/mtree/BSD.include.dist	Thu Mar 16 22:23:04 2017	(r315430)
@@ -130,6 +130,8 @@
         ..
         mfi
         ..
+        mmc
+        ..
         mpt
             mpilib
             ..

Modified: head/include/Makefile
==============================================================================
--- head/include/Makefile	Thu Mar 16 22:15:43 2017	(r315429)
+++ head/include/Makefile	Thu Mar 16 22:23:04 2017	(r315430)
@@ -45,7 +45,7 @@ LDIRS=	bsm cam geom net net80211 netgrap
 LSUBDIRS=	cam/ata cam/nvme cam/scsi \
 	dev/acpica dev/agp dev/an dev/bktr dev/ciss dev/filemon dev/firewire \
 	dev/hwpmc dev/hyperv \
-	dev/ic dev/iicbus dev/io dev/lmc dev/mfi dev/nvme \
+	dev/ic dev/iicbus dev/io dev/lmc dev/mfi dev/mmc dev/nvme \
 	dev/ofw dev/pbio dev/pci ${_dev_powermac_nvram} dev/ppbus dev/smbus \
 	dev/speaker dev/utopia dev/vkbd dev/wi \
 	fs/devfs fs/fdescfs fs/msdosfs fs/nandfs fs/nfs fs/nullfs \

Modified: head/sys/arm/ti/ti_sdhci.c
==============================================================================
--- head/sys/arm/ti/ti_sdhci.c	Thu Mar 16 22:15:43 2017	(r315429)
+++ head/sys/arm/ti/ti_sdhci.c	Thu Mar 16 22:23:04 2017	(r315430)
@@ -606,6 +606,11 @@ ti_sdhci_attach(device_t dev)
 	 * before waiting to see them de-asserted.
 	 */
 	sc->slot.quirks |= SDHCI_QUIRK_WAITFOR_RESET_ASSERTED;
+	
+	/*
+	 * The controller waits for busy responses.
+	 */
+	sc->slot.quirks |= SDHCI_QUIRK_WAIT_WHILE_BUSY;
 
 	/*
 	 * DMA is not really broken, I just haven't implemented it yet.

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Thu Mar 16 22:15:43 2017	(r315429)
+++ head/sys/conf/files	Thu Mar 16 22:23:04 2017	(r315430)
@@ -2218,6 +2218,7 @@ dev/mlx/mlx.c			optional mlx
 dev/mlx/mlx_disk.c		optional mlx
 dev/mlx/mlx_pci.c		optional mlx pci
 dev/mly/mly.c			optional mly
+dev/mmc/mmc_subr.c		optional mmc | mmcsd
 dev/mmc/mmc.c			optional mmc
 dev/mmc/mmcbr_if.m		standard
 dev/mmc/mmcbus_if.m		standard
@@ -3429,7 +3430,7 @@ geom/geom_disk.c		standard
 geom/geom_dump.c		standard
 geom/geom_event.c		standard
 geom/geom_fox.c			optional geom_fox
-geom/geom_flashmap.c		optional fdt cfi | fdt nand | fdt mx25l
+geom/geom_flashmap.c		optional fdt cfi | fdt nand | fdt mx25l | mmcsd
 geom/geom_io.c			standard
 geom/geom_kern.c		standard
 geom/geom_map.c			optional geom_map

Modified: head/sys/dev/mmc/bridge.h
==============================================================================
--- head/sys/dev/mmc/bridge.h	Thu Mar 16 22:15:43 2017	(r315429)
+++ head/sys/dev/mmc/bridge.h	Thu Mar 16 22:23:04 2017	(r315430)
@@ -132,6 +132,8 @@ struct mmc_host {
 #define	MMC_CAP_4_BIT_DATA	(1 <<  0) /* Can do 4-bit data transfers */
 #define	MMC_CAP_8_BIT_DATA	(1 <<  1) /* Can do 8-bit data transfers */
 #define	MMC_CAP_HSPEED		(1 <<  2) /* Can do High Speed transfers */
+#define	MMC_CAP_BOOT_NOACC	(1 <<  4) /* Cannot access boot partitions */
+#define	MMC_CAP_WAIT_WHILE_BUSY	(1 <<  5) /* Host waits for busy responses */
 	enum mmc_card_mode mode;
 	struct mmc_ios ios;	/* Current state of the host */
 };
@@ -139,10 +141,12 @@ struct mmc_host {
 extern driver_t   mmc_driver;
 extern devclass_t mmc_devclass;
 
-#define	MMC_VERSION	1
+#define	MMC_VERSION	2
 
 #define	MMC_DECLARE_BRIDGE(name)					\
     DRIVER_MODULE(mmc, name, mmc_driver, mmc_devclass, NULL, NULL);	\
     MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION);
+#define	MMC_DEPEND(name)						\
+    MODULE_DEPEND(name, mmc, MMC_VERSION, MMC_VERSION, MMC_VERSION);
 
 #endif /* DEV_MMC_BRIDGE_H */

Modified: head/sys/dev/mmc/mmc.c
==============================================================================
--- head/sys/dev/mmc/mmc.c	Thu Mar 16 22:15:43 2017	(r315429)
+++ head/sys/dev/mmc/mmc.c	Thu Mar 16 22:23:04 2017	(r315430)
@@ -65,25 +65,16 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 #include <sys/time.h>
 
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmc_private.h>
+#include <dev/mmc/mmc_subr.h>
 #include <dev/mmc/mmcreg.h>
 #include <dev/mmc/mmcbrvar.h>
 #include <dev/mmc/mmcvar.h>
+
 #include "mmcbr_if.h"
 #include "mmcbus_if.h"
 
-struct mmc_softc {
-	device_t dev;
-	struct mtx sc_mtx;
-	struct intr_config_hook config_intrhook;
-	device_t owner;
-	uint32_t last_rca;
-	int	 squelched; /* suppress reporting of (expected) errors */
-	int	 log_count;
-	struct timeval log_time;
-};
-
-#define	LOG_PPS		5 /* Log no more than 5 errors per second. */
-
 /*
  * Per-card data
  */
@@ -91,7 +82,7 @@ struct mmc_ivars {
 	uint32_t raw_cid[4];	/* Raw bits of the CID */
 	uint32_t raw_csd[4];	/* Raw bits of the CSD */
 	uint32_t raw_scr[2];	/* Raw bits of the SCR */
-	uint8_t raw_ext_csd[512];	/* Raw bits of the EXT_CSD */
+	uint8_t raw_ext_csd[MMC_EXTCSD_SIZE]; /* Raw bits of the EXT_CSD */
 	uint32_t raw_sd_status[16];	/* Raw bits of the SD_STATUS */
 	uint16_t rca;
 	enum mmc_card_mode mode;
@@ -107,6 +98,7 @@ struct mmc_ivars {
 	uint32_t tran_speed;	/* Max speed in normal mode */
 	uint32_t hs_tran_speed;	/* Max speed in high speed mode */
 	uint32_t erase_sector;	/* Card native erase sector size */
+	uint32_t cmd6_time;	/* Generic switch timeout [us] */
 	char card_id_string[64];/* Formatted CID info (serial, MFG, etc) */
 	char card_sn_string[16];/* Formatted serial # for disk->d_ident */
 };
@@ -156,7 +148,8 @@ static int mmc_app_sd_status(struct mmc_
 static int mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca,
     uint32_t *rawscr);
 static int mmc_calculate_clock(struct mmc_softc *sc);
-static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid);
+static void mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid,
+    bool is_4_41p);
 static void mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid);
 static void mmc_decode_csd_mmc(uint32_t *raw_csd, struct mmc_csd *csd);
 static void mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd);
@@ -182,25 +175,17 @@ static uint32_t mmc_select_vdd(struct mm
 static int mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr,
     uint32_t *rocr);
 static int mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd);
-static int mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd);
 static int mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs);
 static int mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr,
     uint32_t *rocr);
 static int mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp);
-static int mmc_send_status(struct mmc_softc *sc, uint16_t rca,
-    uint32_t *status);
 static int mmc_set_blocklen(struct mmc_softc *sc, uint32_t len);
-static int mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca,
-    int width);
+static int mmc_set_card_bus_width(struct mmc_softc *sc,
+    struct mmc_ivars *ivar);
 static int mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp);
-static int mmc_set_timing(struct mmc_softc *sc, int timing);
-static int mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index,
-    uint8_t value);
+static int mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
+    int timing);
 static int mmc_test_bus_width(struct mmc_softc *sc);
-static int mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca,
-    struct mmc_command *cmd, int retries);
-static int mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd,
-    int retries);
 static int mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode,
     uint32_t arg, uint32_t flags, uint32_t *resp, int retries);
 static int mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req);
@@ -299,19 +284,19 @@ mmc_acquire_bus(device_t busdev, device_
 		 * unselect unless the bus code itself wants the mmc
 		 * bus, and constantly reselecting causes problems.
 		 */
-		rca = mmc_get_rca(dev);
+		ivar = device_get_ivars(dev);
+		rca = ivar->rca;
 		if (sc->last_rca != rca) {
 			mmc_select_card(sc, rca);
 			sc->last_rca = rca;
 			/* Prepare bus width for the new card. */
-			ivar = device_get_ivars(dev);
 			if (bootverbose || mmc_debug) {
 				device_printf(busdev,
 				    "setting bus width to %d bits\n",
 				    (ivar->bus_width == bus_width_4) ? 4 :
 				    (ivar->bus_width == bus_width_8) ? 8 : 1);
 			}
-			mmc_set_card_bus_width(sc, rca, ivar->bus_width);
+			mmc_set_card_bus_width(sc, ivar);
 			mmcbr_set_bus_width(busdev, ivar->bus_width);
 			mmcbr_update_ios(busdev);
 		}
@@ -417,74 +402,6 @@ mmc_wait_for_request(device_t brdev, dev
 }
 
 static int
-mmc_wait_for_cmd(struct mmc_softc *sc, struct mmc_command *cmd, int retries)
-{
-	struct mmc_request mreq;
-	int err;
-
-	do {
-		memset(&mreq, 0, sizeof(mreq));
-		memset(cmd->resp, 0, sizeof(cmd->resp));
-		cmd->retries = 0; /* Retries done here, not in hardware. */
-		cmd->mrq = &mreq;
-		mreq.cmd = cmd;
-		if (mmc_wait_for_req(sc, &mreq) != 0)
-			err = MMC_ERR_FAILED;
-		else
-			err = cmd->error;
-	} while (err != MMC_ERR_NONE && retries-- > 0);
-
-	if (err != MMC_ERR_NONE && sc->squelched == 0) {
-		if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) {
-			device_printf(sc->dev, "CMD%d failed, RESULT: %d\n",
-			    cmd->opcode, err);
-		}
-	}
-
-	return (err);
-}
-
-static int
-mmc_wait_for_app_cmd(struct mmc_softc *sc, uint32_t rca,
-    struct mmc_command *cmd, int retries)
-{
-	struct mmc_command appcmd;
-	int err;
-
-	/* Squelch error reporting at lower levels, we report below. */
-	sc->squelched++;
-	do {
-		memset(&appcmd, 0, sizeof(appcmd));
-		appcmd.opcode = MMC_APP_CMD;
-		appcmd.arg = rca << 16;
-		appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-		appcmd.data = NULL;
-		if (mmc_wait_for_cmd(sc, &appcmd, 0) != 0)
-			err = MMC_ERR_FAILED;
-		else
-			err = appcmd.error;
-		if (err == MMC_ERR_NONE) {
-			if (!(appcmd.resp[0] & R1_APP_CMD))
-				err = MMC_ERR_FAILED;
-			else if (mmc_wait_for_cmd(sc, cmd, 0) != 0)
-				err = MMC_ERR_FAILED;
-			else
-				err = cmd->error;
-		}
-	} while (err != MMC_ERR_NONE && retries-- > 0);
-	sc->squelched--;
-
-	if (err != MMC_ERR_NONE && sc->squelched == 0) {
-		if (ppsratecheck(&sc->log_time, &sc->log_count, LOG_PPS)) {
-			device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n",
-			    cmd->opcode, err);
-		}
-	}
-
-	return (err);
-}
-
-static int
 mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode,
     uint32_t arg, uint32_t flags, uint32_t *resp, int retries)
 {
@@ -496,7 +413,7 @@ mmc_wait_for_command(struct mmc_softc *s
 	cmd.arg = arg;
 	cmd.flags = flags;
 	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, retries);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, retries);
 	if (err)
 		return (err);
 	if (resp) {
@@ -524,7 +441,7 @@ mmc_idle_cards(struct mmc_softc *sc)
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
 	cmd.data = NULL;
-	mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	mmc_ms_delay(1);
 
 	mmcbr_set_chip_select(dev, cs_dontcare);
@@ -545,7 +462,8 @@ mmc_send_app_op_cond(struct mmc_softc *s
 	cmd.data = NULL;
 
 	for (i = 0; i < 1000; i++) {
-		err = mmc_wait_for_app_cmd(sc, 0, &cmd, CMD_RETRIES);
+		err = mmc_wait_for_app_cmd(sc->dev, sc->dev, 0, &cmd,
+		    CMD_RETRIES);
 		if (err != MMC_ERR_NONE)
 			break;
 		if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) ||
@@ -572,7 +490,7 @@ mmc_send_op_cond(struct mmc_softc *sc, u
 	cmd.data = NULL;
 
 	for (i = 0; i < 1000; i++) {
-		err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+		err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 		if (err != MMC_ERR_NONE)
 			break;
 		if ((cmd.resp[0] & MMC_OCR_CARD_BUSY) ||
@@ -598,7 +516,7 @@ mmc_send_if_cond(struct mmc_softc *sc, u
 	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
 	cmd.data = NULL;
 
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	return (err);
 }
 
@@ -649,24 +567,6 @@ mmc_select_card(struct mmc_softc *sc, ui
 }
 
 static int
-mmc_switch(struct mmc_softc *sc, uint8_t set, uint8_t index, uint8_t value)
-{
-	struct mmc_command cmd;
-	int err;
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.opcode = MMC_SWITCH_FUNC;
-	cmd.arg = (MMC_SWITCH_FUNC_WR << 24) |
-	    (index << 16) |
-	    (value << 8) |
-	    set;
-	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
-	return (err);
-}
-
-static int
 mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value,
     uint8_t *res)
 {
@@ -690,12 +590,12 @@ mmc_sd_switch(struct mmc_softc *sc, uint
 	data.len = 64;
 	data.flags = MMC_DATA_READ;
 
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	return (err);
 }
 
 static int
-mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, int width)
+mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar)
 {
 	struct mmc_command cmd;
 	int err;
@@ -706,13 +606,14 @@ mmc_set_card_bus_width(struct mmc_softc 
 		cmd.opcode = ACMD_SET_CLR_CARD_DETECT;
 		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 		cmd.arg = SD_CLR_CARD_DETECT;
-		err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
+		err = mmc_wait_for_app_cmd(sc->dev, sc->dev, ivar->rca, &cmd,
+		    CMD_RETRIES);
 		if (err != 0)
 			return (err);
 		memset(&cmd, 0, sizeof(cmd));
 		cmd.opcode = ACMD_SET_BUS_WIDTH;
 		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-		switch (width) {
+		switch (ivar->bus_width) {
 		case bus_width_1:
 			cmd.arg = SD_BUS_WIDTH_1;
 			break;
@@ -722,9 +623,10 @@ mmc_set_card_bus_width(struct mmc_softc 
 		default:
 			return (MMC_ERR_INVALID);
 		}
-		err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
+		err = mmc_wait_for_app_cmd(sc->dev, sc->dev, ivar->rca, &cmd,
+		    CMD_RETRIES);
 	} else {
-		switch (width) {
+		switch (ivar->bus_width) {
 		case bus_width_1:
 			value = EXT_CSD_BUS_WIDTH_1;
 			break;
@@ -737,18 +639,19 @@ mmc_set_card_bus_width(struct mmc_softc 
 		default:
 			return (MMC_ERR_INVALID);
 		}
-		err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
-		    value);
+		err = mmc_switch(sc->dev, sc->dev, ivar->rca,
+		    EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, value,
+		    ivar->cmd6_time, true);
 	}
 	return (err);
 }
 
 static int
-mmc_set_timing(struct mmc_softc *sc, int timing)
+mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar, int timing)
 {
 	u_char switch_res[64];
-	int err;
 	uint8_t	value;
+	int err;
 
 	switch (timing) {
 	case bus_timing_normal:
@@ -760,12 +663,26 @@ mmc_set_timing(struct mmc_softc *sc, int
 	default:
 		return (MMC_ERR_INVALID);
 	}
-	if (mmcbr_get_mode(sc->dev) == mode_sd)
+	if (mmcbr_get_mode(sc->dev) == mode_sd) {
 		err = mmc_sd_switch(sc, SD_SWITCH_MODE_SET, SD_SWITCH_GROUP1,
 		    value, switch_res);
-	else
-		err = mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL,
-		    EXT_CSD_HS_TIMING, value);
+		if (err != MMC_ERR_NONE)
+			return (err);
+		if ((switch_res[16] & 0xf) != value)
+			return (MMC_ERR_FAILED);
+		mmcbr_set_timing(sc->dev, timing);
+		mmcbr_update_ios(sc->dev);
+	} else {
+		err = mmc_switch(sc->dev, sc->dev, ivar->rca,
+		    EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, value,
+		    ivar->cmd6_time, false);
+		if (err != MMC_ERR_NONE)
+			return (err);
+		mmcbr_set_timing(sc->dev, timing);
+		mmcbr_update_ios(sc->dev);
+		err = mmc_switch_status(sc->dev, sc->dev, ivar->rca,
+		    ivar->cmd6_time);
+	}
 	return (err);
 }
 
@@ -808,7 +725,7 @@ mmc_test_bus_width(struct mmc_softc *sc)
 		data.data = __DECONST(void *, p8);
 		data.len = 8;
 		data.flags = MMC_DATA_WRITE;
-		mmc_wait_for_cmd(sc, &cmd, 0);
+		mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0);
 
 		memset(&cmd, 0, sizeof(cmd));
 		memset(&data, 0, sizeof(data));
@@ -820,7 +737,7 @@ mmc_test_bus_width(struct mmc_softc *sc)
 		data.data = buf;
 		data.len = 8;
 		data.flags = MMC_DATA_READ;
-		err = mmc_wait_for_cmd(sc, &cmd, 0);
+		err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0);
 		sc->squelched--;
 
 		mmcbr_set_bus_width(sc->dev, bus_width_1);
@@ -845,7 +762,7 @@ mmc_test_bus_width(struct mmc_softc *sc)
 		data.data = __DECONST(void *, p4);
 		data.len = 4;
 		data.flags = MMC_DATA_WRITE;
-		mmc_wait_for_cmd(sc, &cmd, 0);
+		mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0);
 
 		memset(&cmd, 0, sizeof(cmd));
 		memset(&data, 0, sizeof(data));
@@ -857,7 +774,7 @@ mmc_test_bus_width(struct mmc_softc *sc)
 		data.data = buf;
 		data.len = 4;
 		data.flags = MMC_DATA_READ;
-		err = mmc_wait_for_cmd(sc, &cmd, 0);
+		err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 0);
 		sc->squelched--;
 
 		mmcbr_set_bus_width(sc->dev, bus_width_1);
@@ -899,7 +816,7 @@ mmc_decode_cid_sd(uint32_t *raw_cid, str
 }
 
 static void
-mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid)
+mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid, bool is_4_41p)
 {
 	int i;
 
@@ -913,7 +830,11 @@ mmc_decode_cid_mmc(uint32_t *raw_cid, st
 	cid->prv = mmc_get_bits(raw_cid, 128, 48, 8);
 	cid->psn = mmc_get_bits(raw_cid, 128, 16, 32);
 	cid->mdt_month = mmc_get_bits(raw_cid, 128, 12, 4);
-	cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4) + 1997;
+	cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4);
+	if (is_4_41p)
+		cid->mdt_year += 2013;
+	else
+		cid->mdt_year += 1997;
 }
 
 static void
@@ -1125,7 +1046,7 @@ mmc_all_send_cid(struct mmc_softc *sc, u
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
 	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	memcpy(rawcid, cmd.resp, 4 * sizeof(uint32_t));
 	return (err);
 }
@@ -1141,7 +1062,7 @@ mmc_send_csd(struct mmc_softc *sc, uint1
 	cmd.arg = rca << 16;
 	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
 	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t));
 	return (err);
 }
@@ -1166,37 +1087,13 @@ mmc_app_send_scr(struct mmc_softc *sc, u
 	data.len = 8;
 	data.flags = MMC_DATA_READ;
 
-	err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_app_cmd(sc->dev, sc->dev, rca, &cmd, CMD_RETRIES);
 	rawscr[0] = be32toh(rawscr[0]);
 	rawscr[1] = be32toh(rawscr[1]);
 	return (err);
 }
 
 static int
-mmc_send_ext_csd(struct mmc_softc *sc, uint8_t *rawextcsd)
-{
-	struct mmc_command cmd;
-	struct mmc_data data;
-	int err;
-
-	memset(&cmd, 0, sizeof(cmd));
-	memset(&data, 0, sizeof(data));
-
-	memset(rawextcsd, 0, 512);
-	cmd.opcode = MMC_SEND_EXT_CSD;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-	cmd.arg = 0;
-	cmd.data = &data;
-
-	data.data = rawextcsd;
-	data.len = 512;
-	data.flags = MMC_DATA_READ;
-
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
-	return (err);
-}
-
-static int
 mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus)
 {
 	struct mmc_command cmd;
@@ -1216,7 +1113,7 @@ mmc_app_sd_status(struct mmc_softc *sc, 
 	data.len = 64;
 	data.flags = MMC_DATA_READ;
 
-	err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_app_cmd(sc->dev, sc->dev, rca, &cmd, CMD_RETRIES);
 	for (i = 0; i < 16; i++)
 	    rawsdstatus[i] = be32toh(rawsdstatus[i]);
 	return (err);
@@ -1233,7 +1130,7 @@ mmc_set_relative_addr(struct mmc_softc *
 	cmd.arg = resp << 16;
 	cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
 	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	return (err);
 }
 
@@ -1248,28 +1145,12 @@ mmc_send_relative_addr(struct mmc_softc 
 	cmd.arg = 0;
 	cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
 	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	*resp = cmd.resp[0];
 	return (err);
 }
 
 static int
-mmc_send_status(struct mmc_softc *sc, uint16_t rca, uint32_t *status)
-{
-	struct mmc_command cmd;
-	int err;
-
-	memset(&cmd, 0, sizeof(cmd));
-	cmd.opcode = MMC_SEND_STATUS;
-	cmd.arg = rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
-	*status = cmd.resp[0];
-	return (err);
-}
-
-static int
 mmc_set_blocklen(struct mmc_softc *sc, uint32_t len)
 {
 	struct mmc_command cmd;
@@ -1280,13 +1161,14 @@ mmc_set_blocklen(struct mmc_softc *sc, u
 	cmd.arg = len;
 	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 	cmd.data = NULL;
-	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, CMD_RETRIES);
 	return (err);
 }
 
 static void
 mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard)
 {
+
 	device_printf(dev, "Card at relative address 0x%04x%s:\n",
 	    ivar->rca, newcard ? " added" : "");
 	device_printf(dev, " card: %s\n", ivar->card_id_string);
@@ -1374,7 +1256,8 @@ mmc_discover_cards(struct mmc_softc *sc)
 			ivar->erase_sector = ivar->csd.erase_sector *
 			    ivar->csd.write_bl_len / MMC_SECTOR_SIZE;
 
-			err = mmc_send_status(sc, ivar->rca, &status);
+			err = mmc_send_status(sc->dev, sc->dev, ivar->rca,
+			    &status);
 			if (err != MMC_ERR_NONE) {
 				device_printf(sc->dev,
 				    "Error reading card status %d\n", err);
@@ -1386,7 +1269,7 @@ mmc_discover_cards(struct mmc_softc *sc)
 				break;
 			}
 
-			/* Get card SCR. Card must be selected to fetch it. */
+			/* Get card SCR.  Card must be selected to fetch it. */
 			mmc_select_card(sc, ivar->rca);
 			mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
 			mmc_app_decode_scr(ivar->raw_scr, &ivar->scr);
@@ -1396,7 +1279,7 @@ mmc_discover_cards(struct mmc_softc *sc)
 				mmc_sd_switch(sc, SD_SWITCH_MODE_CHECK,
 				    SD_SWITCH_GROUP1, SD_SWITCH_NOCHANGE,
 				    switch_res);
-				if (switch_res[13] & 2) {
+				if (switch_res[13] & (1 << SD_SWITCH_HS_MODE)) {
 					ivar->timing = bus_timing_hs;
 					ivar->hs_tran_speed = SD_MAX_HS;
 				}
@@ -1453,7 +1336,6 @@ mmc_discover_cards(struct mmc_softc *sc)
 			mmc_select_card(sc, 0);
 			return;
 		}
-		mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid);
 		ivar->rca = rca++;
 		mmc_set_relative_addr(sc, ivar->rca);
 		/* Get card CSD. */
@@ -1471,7 +1353,7 @@ mmc_discover_cards(struct mmc_softc *sc)
 		ivar->erase_sector = ivar->csd.erase_sector *
 		    ivar->csd.write_bl_len / MMC_SECTOR_SIZE;
 
-		err = mmc_send_status(sc, ivar->rca, &status);
+		err = mmc_send_status(sc->dev, sc->dev, ivar->rca, &status);
 		if (err != MMC_ERR_NONE) {
 			device_printf(sc->dev,
 			    "Error reading card status %d\n", err);
@@ -1485,9 +1367,15 @@ mmc_discover_cards(struct mmc_softc *sc)
 
 		mmc_select_card(sc, ivar->rca);
 
-		/* Only MMC >= 4.x cards support EXT_CSD. */
+		/* Only MMC >= 4.x devices support EXT_CSD. */
 		if (ivar->csd.spec_vers >= 4) {
-			mmc_send_ext_csd(sc, ivar->raw_ext_csd);
+			err = mmc_send_ext_csd(sc->dev, sc->dev,
+			    ivar->raw_ext_csd);
+			if (err != MMC_ERR_NONE) {
+				device_printf(sc->dev,
+				    "Error reading EXT_CSD %d\n", err);
+				break;
+			}
 			/* Handle extended capacity from EXT_CSD */
 			sec_count = ivar->raw_ext_csd[EXT_CSD_SEC_CNT] +
 			    (ivar->raw_ext_csd[EXT_CSD_SEC_CNT + 1] << 8) +
@@ -1507,14 +1395,31 @@ mmc_discover_cards(struct mmc_softc *sc)
 				ivar->hs_tran_speed = MMC_TYPE_26_MAX_HS;
 			else
 				ivar->hs_tran_speed = ivar->tran_speed;
+			/*
+			 * Determine generic switch timeout (provided in
+			 * units of 10 ms), defaulting to 500 ms.
+			 */
+			ivar->cmd6_time = 500 * 1000;
+			if (ivar->csd.spec_vers >= 6)
+				ivar->cmd6_time = 10 *
+				    ivar->raw_ext_csd[EXT_CSD_GEN_CMD6_TIME];
 			/* Find max supported bus width. */
 			ivar->bus_width = mmc_test_bus_width(sc);
 			/* Handle HC erase sector size. */
 			if (ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE] != 0) {
 				ivar->erase_sector = 1024 *
 				    ivar->raw_ext_csd[EXT_CSD_ERASE_GRP_SIZE];
-				mmc_switch(sc, EXT_CSD_CMD_SET_NORMAL,
-				    EXT_CSD_ERASE_GRP_DEF, 1);
+				err = mmc_switch(sc->dev, sc->dev, ivar->rca,
+				    EXT_CSD_CMD_SET_NORMAL,
+				    EXT_CSD_ERASE_GRP_DEF,
+				    EXT_CSD_ERASE_GRP_DEF_EN,
+				    ivar->cmd6_time, true);
+				if (err != MMC_ERR_NONE) {
+					device_printf(sc->dev,
+					    "Error setting erase group %d\n",
+					    err);
+					break;
+				}
 			}
 		} else {
 			ivar->bus_width = bus_width_1;
@@ -1533,6 +1438,8 @@ mmc_discover_cards(struct mmc_softc *sc)
 		    ivar->csd.write_bl_len != MMC_SECTOR_SIZE)
 			mmc_set_blocklen(sc, MMC_SECTOR_SIZE);
 
+		mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid,
+		    ivar->raw_ext_csd[EXT_CSD_REV] >= 5);
 		mmc_format_card_id_string(ivar);
 
 		if (bootverbose || mmc_debug)
@@ -1672,8 +1579,6 @@ mmc_go_discovery(struct mmc_softc *sc)
 	mmcbr_set_bus_mode(dev, pushpull);
 	mmcbr_update_ios(dev);
 	mmc_calculate_clock(sc);
-	bus_generic_attach(dev);
-/*	mmc_update_children_sysctl(dev);*/
 }
 
 static int
@@ -1700,27 +1605,26 @@ mmc_calculate_clock(struct mmc_softc *sc
 		if (ivar->hs_tran_speed < max_hs_dtr)
 			max_hs_dtr = ivar->hs_tran_speed;
 	}
+	if (bootverbose || mmc_debug) {
+		device_printf(sc->dev,
+		    "setting transfer rate to %d.%03dMHz%s\n",
+		    max_dtr / 1000000, (max_dtr / 1000) % 1000,
+		    max_timing == bus_timing_hs ? " (high speed timing)" : "");
+	}
 	for (i = 0; i < nkid; i++) {
 		ivar = device_get_ivars(kids[i]);
 		if (ivar->timing == bus_timing_normal)
 			continue;
 		mmc_select_card(sc, ivar->rca);
-		mmc_set_timing(sc, max_timing);
+		mmc_set_timing(sc, ivar, max_timing);
 	}
 	mmc_select_card(sc, 0);
 	free(kids, M_TEMP);
 	if (max_timing == bus_timing_hs)
 		max_dtr = max_hs_dtr;
-	if (bootverbose || mmc_debug) {
-		device_printf(sc->dev,
-		    "setting transfer rate to %d.%03dMHz%s\n",
-		    max_dtr / 1000000, (max_dtr / 1000) % 1000,
-		    max_timing == bus_timing_hs ? " (high speed timing)" : "");
-	}
-	mmcbr_set_timing(sc->dev, max_timing);
 	mmcbr_set_clock(sc->dev, max_dtr);
 	mmcbr_update_ios(sc->dev);
-	return max_dtr;
+	return (max_dtr);
 }
 
 static void
@@ -1731,6 +1635,8 @@ mmc_scan(struct mmc_softc *sc)
 	mmc_acquire_bus(dev, dev);
 	mmc_go_discovery(sc);
 	mmc_release_bus(dev, dev);
+
+	bus_generic_attach(dev);
 }
 
 static int
@@ -1741,6 +1647,9 @@ mmc_read_ivar(device_t bus, device_t chi
 	switch (which) {
 	default:
 		return (EINVAL);
+	case MMC_IVAR_SPEC_VERS:
+		*result = ivar->csd.spec_vers;
+		break;
 	case MMC_IVAR_DSR_IMP:
 		*result = ivar->csd.dsr_imp;
 		break;
@@ -1840,4 +1749,4 @@ driver_t mmc_driver = {
 };
 devclass_t mmc_devclass;
 
-MODULE_VERSION(mmc, 1);
+MODULE_VERSION(mmc, MMC_VERSION);

Added: head/sys/dev/mmc/mmc_ioctl.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/mmc/mmc_ioctl.h	Thu Mar 16 22:23:04 2017	(r315430)
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2017 Marius Strobl <marius at FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MMC_MMC_IOCTL_H_
+#define	_DEV_MMC_MMC_IOCTL_H_
+
+struct mmc_ioc_cmd {
+	int		write_flag; /* 0: RD, 1: WR, (1 << 31): reliable WR */
+	int		is_acmd;    /* 0: normal, 1: use CMD55 */
+	uint32_t	opcode;
+	uint32_t	arg;
+	uint32_t	response[4];
+	u_int		flags;
+	u_int		blksz;
+	u_int		blocks;
+	u_int		__spare[4];
+	uint32_t	__pad;
+	uint64_t	data_ptr;
+};
+
+#define	mmc_ioc_cmd_set_data(mic, ptr)					\
+    (mic).data_ptr = (uint64_t)(uintptr_t)(ptr)
+
+struct mmc_ioc_multi_cmd {
+	uint64_t		num_of_cmds;
+	struct mmc_ioc_cmd	cmds[0];
+};
+
+#define	MMC_IOC_BASE		'M'
+
+#define	MMC_IOC_CMD		_IOWR(MMC_IOC_BASE, 0, struct mmc_ioc_cmd)
+#define	MMC_IOC_CMD_MULTI	_IOWR(MMC_IOC_BASE, 1, struct mmc_ioc_multi_cmd)
+
+/* Maximum accepted data transfer size */
+#define	MMC_IOC_MAX_BYTES	(512  * 256)
+/* Maximum accepted number of commands */
+#define	MMC_IOC_MAX_CMDS	255
+
+#endif /* _DEV_MMC_MMC_IOCTL_H_ */

Added: head/sys/dev/mmc/mmc_private.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/mmc/mmc_private.h	Thu Mar 16 22:23:04 2017	(r315430)
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2006 Bernd Walter.  All rights reserved.
+ * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Portions of this software may have been developed with reference to
+ * the SD Simplified Specification.  The following disclaimer may apply:
+ *
+ * The following conditions apply to the release of the simplified
+ * specification ("Simplified Specification") by the SD Card Association and
+ * the SD Group. The Simplified Specification is a subset of the complete SD
+ * Specification which is owned by the SD Card Association and the SD
+ * Group. This Simplified Specification is provided on a non-confidential
+ * basis subject to the disclaimers below. Any implementation of the
+ * Simplified Specification may require a license from the SD Card
+ * Association, SD Group, SD-3C LLC or other third parties.
+ *
+ * Disclaimers:
+ *
+ * The information contained in the Simplified Specification is presented only
+ * as a standard specification for SD Cards and SD Host/Ancillary products and
+ * is provided "AS-IS" without any representations or warranties of any
+ * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
+ * Card Association for any damages, any infringements of patents or other
+ * right of the SD Group, SD-3C LLC, the SD Card Association or any third
+ * parties, which may result from its use. No license is granted by
+ * implication, estoppel or otherwise under any patent or other rights of the
+ * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
+ * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
+ * or the SD Card Association to disclose or distribute any technical
+ * information, know-how or other confidential information to any third party.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef DEV_MMC_PRIVATE_H
+#define	DEV_MMC_PRIVATE_H
+
+struct mmc_softc {
+	device_t dev;
+	struct mtx sc_mtx;
+	struct intr_config_hook config_intrhook;
+	device_t owner;
+	uint32_t last_rca;
+	int	 squelched; /* suppress reporting of (expected) errors */
+	int	 log_count;
+	struct timeval log_time;
+};
+
+#endif /* DEV_MMC_PRIVATE_H */

Copied and modified: head/sys/dev/mmc/mmc_subr.c (from r313250, head/sys/dev/mmc/mmc.c)
==============================================================================
--- head/sys/dev/mmc/mmc.c	Sat Feb  4 19:35:38 2017	(r313250, copy source)
+++ head/sys/dev/mmc/mmc_subr.c	Thu Mar 16 22:23:04 2017	(r315430)
@@ -56,369 +56,27 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/malloc.h>
 #include <sys/lock.h>
-#include <sys/module.h>
 #include <sys/mutex.h>
-#include <sys/bus.h>
-#include <sys/endian.h>
-#include <sys/sysctl.h>
 #include <sys/time.h>
 
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmc_private.h>
+#include <dev/mmc/mmc_subr.h>
 #include <dev/mmc/mmcreg.h>
 #include <dev/mmc/mmcbrvar.h>
-#include <dev/mmc/mmcvar.h>
-#include "mmcbr_if.h"
-#include "mmcbus_if.h"
-
-struct mmc_softc {
-	device_t dev;
-	struct mtx sc_mtx;
-	struct intr_config_hook config_intrhook;
-	device_t owner;
-	uint32_t last_rca;
-	int	 squelched; /* suppress reporting of (expected) errors */
-	int	 log_count;
-	struct timeval log_time;
-};
-
-#define	LOG_PPS		5 /* Log no more than 5 errors per second. */
 
-/*
- * Per-card data
- */
-struct mmc_ivars {
-	uint32_t raw_cid[4];	/* Raw bits of the CID */
-	uint32_t raw_csd[4];	/* Raw bits of the CSD */
-	uint32_t raw_scr[2];	/* Raw bits of the SCR */
-	uint8_t raw_ext_csd[512];	/* Raw bits of the EXT_CSD */
-	uint32_t raw_sd_status[16];	/* Raw bits of the SD_STATUS */
-	uint16_t rca;
-	enum mmc_card_mode mode;
-	struct mmc_cid cid;	/* cid decoded */
-	struct mmc_csd csd;	/* csd decoded */
-	struct mmc_scr scr;	/* scr decoded */
-	struct mmc_sd_status sd_status;	/* SD_STATUS decoded */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list