A step to correctly handling command timeouts in the MMC layer. master
authorImre Vadász <imre@vdsz.com>
Sun, 21 May 2017 14:02:20 +0000 (16:02 +0200)
committerImre Vadász <imre@vdsz.com>
Mon, 22 May 2017 19:58:37 +0000 (21:58 +0200)
    - 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 ...

    - 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.

* This omits all the parts specific to eMMC "partitions" from the FreeBSD
  change.

* Add the Intel sdhci controller ids to sdhci_pci.c to set the
  SDHCI_QUIRK_WAIT_WHILE_BUSY quirk there.
  This also disables DMA on apollo lake sdhci, while there and whitelists
  ADMA2 on Bay Trail and Braswell sdhci controllers.

Taken-From: FreeBSD (svn r315430)

15 files changed:
sys/bus/mmc/Makefile
sys/bus/mmc/bridge.h
sys/bus/mmc/mmc.c
sys/bus/mmc/mmc_private.h [copied from sys/bus/mmc/mmcvar.h with 71% similarity]
sys/bus/mmc/mmc_subr.c [new file with mode: 0644]
sys/bus/mmc/mmc_subr.h [copied from sys/bus/mmc/mmcvar.h with 71% similarity]
sys/bus/mmc/mmcbrvar.h
sys/bus/mmc/mmcreg.h
sys/bus/mmc/mmcvar.h
sys/conf/files
sys/dev/disk/mmcsd/mmcsd.c
sys/dev/disk/sdhci/sdhci.c
sys/dev/disk/sdhci/sdhci.h
sys/dev/disk/sdhci/sdhci_acpi.c
sys/dev/disk/sdhci/sdhci_pci.c

index d5bb7d1..ca5f732 100644 (file)
@@ -1,6 +1,6 @@
 # $FreeBSD: src/sys/modules/mmc/Makefile,v 1.1 2006/10/20 06:52:59 imp Exp $
 
 KMOD=  mmc
-SRCS=  mmc.c mmcbr_if.h mmcbus_if.h device_if.h bus_if.h
+SRCS=  bus_if.h device_if.h mmc_subr.c mmc.c mmcbr_if.h mmcbus_if.h
 
 .include <bsd.kmod.mk>
index 59331e8..03c56f7 100644 (file)
@@ -131,6 +131,7 @@ 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_WAIT_WHILE_BUSY        (1 << 3) /* Host waits for busy responses */
        enum mmc_card_mode mode;
        struct mmc_ios ios;     /* Current state of the host */
 };
index 1ff8aa9..7a193e0 100644 (file)
 #include <sys/sysctl.h>
 #include <sys/time.h>
 
+#include <bus/mmc/bridge.h>
+#include <bus/mmc/mmc_private.h>
+#include <bus/mmc/mmc_subr.h>
 #include <bus/mmc/mmcreg.h>
 #include <bus/mmc/mmcbrvar.h>
 #include <bus/mmc/mmcvar.h>
 #include "mmcbr_if.h"
 #include "mmcbus_if.h"
 
-struct mmc_softc {
-       device_t dev;
-       struct lock sc_lock;
-       struct intr_config_hook config_intrhook;
-       device_t owner;
-       uint32_t last_rca;
-       int      squelched; /* suppress reporting of (expected) errors */
-       int      log_count;
-       int      retries;   /* retries @ 10ms */
-       struct timeval log_time;
-};
-
-#define        LOG_PPS         5 /* Log no more than 5 errors per second. */
-
 /*
  * Per-card data
  */
@@ -91,7 +80,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 +96,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 */
 };
@@ -153,7 +143,8 @@ static int mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca,
 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);
@@ -179,25 +170,16 @@ static uint32_t mmc_select_vdd(struct mmc_softc *sc, uint32_t ocr);
 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);
@@ -304,19 +286,19 @@ mmc_acquire_bus(device_t busdev, device_t dev)
                 * 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);
                }
@@ -422,74 +404,6 @@ mmc_wait_for_request(device_t brdev, device_t reqdev __unused,
 }
 
 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)
 {
@@ -501,7 +415,7 @@ mmc_wait_for_command(struct mmc_softc *sc, uint32_t opcode,
        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) {
@@ -529,7 +443,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);
@@ -550,7 +464,8 @@ mmc_send_app_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr)
        cmd.data = NULL;
 
        for (i = 0; i < sc->retries; 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) ||
@@ -579,7 +494,7 @@ mmc_send_op_cond(struct mmc_softc *sc, uint32_t ocr, uint32_t *rocr)
        cmd.data = NULL;
 
        for (i = 0; i < sc->retries; 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) ||
@@ -607,7 +522,7 @@ mmc_send_if_cond(struct mmc_softc *sc, uint8_t vhs)
        cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
        cmd.data = NULL;
 
-       err = mmc_wait_for_cmd(sc, &cmd, 5*CMD_RETRIES);
+       err = mmc_wait_for_cmd(sc->dev, sc->dev, &cmd, 5*CMD_RETRIES);
        return (err);
 }
 
@@ -658,24 +573,6 @@ mmc_select_card(struct mmc_softc *sc, uint16_t rca)
 }
 
 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)
 {
@@ -699,12 +596,12 @@ mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value,
        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;
@@ -715,13 +612,14 @@ mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, int width)
                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;
@@ -731,9 +629,10 @@ mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, int width)
                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;
@@ -746,18 +645,19 @@ mmc_set_card_bus_width(struct mmc_softc *sc, uint16_t rca, int width)
                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)
 {
-       int err;
-       uint8_t value;
        u_char switch_res[64];
+       uint8_t value;
+       int err;
 
        switch (timing) {
        case bus_timing_normal:
@@ -769,12 +669,26 @@ mmc_set_timing(struct mmc_softc *sc, int timing)
        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);
 }
 
@@ -817,7 +731,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));
@@ -829,7 +743,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);
@@ -854,7 +768,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));
@@ -866,7 +780,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);
@@ -909,7 +823,7 @@ mmc_decode_cid_sd(uint32_t *raw_cid, struct mmc_cid *cid)
 }
 
 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;
 
@@ -923,7 +837,11 @@ mmc_decode_cid_mmc(uint32_t *raw_cid, struct mmc_cid *cid)
        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
@@ -1131,7 +1049,7 @@ mmc_all_send_cid(struct mmc_softc *sc, uint32_t *rawcid)
        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);
 }
@@ -1147,7 +1065,7 @@ mmc_send_csd(struct mmc_softc *sc, uint16_t rca, uint32_t *rawcsd)
        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);
 }
@@ -1172,37 +1090,13 @@ mmc_app_send_scr(struct mmc_softc *sc, uint16_t rca, uint32_t *rawscr)
        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)
-{
-       int err;
-       struct mmc_command cmd;
-       struct mmc_data data;
-
-       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)
 {
        int err, i;
@@ -1222,7 +1116,7 @@ mmc_app_sd_status(struct mmc_softc *sc, uint16_t rca, uint32_t *rawsdstatus)
        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);
@@ -1239,7 +1133,7 @@ mmc_set_relative_addr(struct mmc_softc *sc, uint16_t resp)
        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);
 }
 
@@ -1254,28 +1148,12 @@ mmc_send_relative_addr(struct mmc_softc *sc, uint32_t *resp)
        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;
@@ -1286,7 +1164,7 @@ mmc_set_blocklen(struct mmc_softc *sc, uint32_t len)
        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);
 }
 
@@ -1377,7 +1255,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);
@@ -1389,7 +1268,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);
@@ -1399,7 +1278,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;
                                }
@@ -1456,7 +1335,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. */
@@ -1474,7 +1352,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);
@@ -1488,9 +1366,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) +
@@ -1510,14 +1394,32 @@ 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;
@@ -1536,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)
@@ -1669,8 +1573,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
@@ -1698,27 +1600,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);
        kfree(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
@@ -1729,6 +1630,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
@@ -1739,6 +1642,9 @@ mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
        switch (which) {
        default:
                return (EINVAL);
+       case MMC_IVAR_SPEC_VERS:
+               *result = ivar->csd.spec_vers;
+               break;
        case MMC_IVAR_DSR_IMP:
                *(int *)result = ivar->csd.dsr_imp;
                break;
similarity index 71%
copy from sys/bus/mmc/mmcvar.h
copy to sys/bus/mmc/mmc_private.h
index ca6dd0b..e01761b 100644 (file)
  * or the SD Card Association to disclose or distribute any technical
  * information, know-how or other confidential information to any third party.
  *
- * $FreeBSD: src/sys/dev/mmc/mmcvar.h,v 1.9 2008/10/29 20:01:26 mav Exp $
+ * $FreeBSD: head/sys/dev/mmc/mmc_private.h 315430 2017-03-16 22:23:04Z marius $
  */
 
-#ifndef BUS_MMC_MMCVAR_H
-#define BUS_MMC_MMCVAR_H
+#ifndef DEV_MMC_PRIVATE_H
+#define        DEV_MMC_PRIVATE_H
 
-#include <bus/mmc/bridge.h>
-
-enum mmc_device_ivars {
-    MMC_IVAR_DSR_IMP,
-    MMC_IVAR_MEDIA_SIZE,
-    MMC_IVAR_RCA,
-    MMC_IVAR_SECTOR_SIZE,
-    MMC_IVAR_TRAN_SPEED,
-    MMC_IVAR_READ_ONLY,
-    MMC_IVAR_HIGH_CAP,
-    MMC_IVAR_CARD_TYPE,
-    MMC_IVAR_BUS_WIDTH,
-    MMC_IVAR_ERASE_SECTOR,
-    MMC_IVAR_MAX_DATA,
-    MMC_IVAR_CARD_ID_STRING,
-    MMC_IVAR_CARD_SN_STRING,
+struct mmc_softc {
+       device_t dev;
+        struct lock sc_lock;
+       struct intr_config_hook config_intrhook;
+       device_t owner;
+       uint32_t last_rca;
+       int      squelched;     /* suppress reporting of (expected) errors */
+       int      log_count;
+       int     retries;        /* retries @ 10ms */
+       struct timeval log_time;
 };
 
-/*
- * Simplified accessors for mmc devices
- */
-#define MMC_ACCESSOR(var, ivar, type)                                  \
-       __BUS_ACCESSOR(mmc, var, MMC, ivar, type)
-
-MMC_ACCESSOR(dsr_imp, DSR_IMP, int)
-MMC_ACCESSOR(media_size, MEDIA_SIZE, long)
-MMC_ACCESSOR(rca, RCA, int)
-MMC_ACCESSOR(sector_size, SECTOR_SIZE, int)
-MMC_ACCESSOR(tran_speed, TRAN_SPEED, int)
-MMC_ACCESSOR(read_only, READ_ONLY, int)
-MMC_ACCESSOR(high_cap, HIGH_CAP, int)
-MMC_ACCESSOR(card_type, CARD_TYPE, int)
-MMC_ACCESSOR(bus_width, BUS_WIDTH, int)
-MMC_ACCESSOR(erase_sector, ERASE_SECTOR, int)
-MMC_ACCESSOR(max_data, MAX_DATA, int)
-MMC_ACCESSOR(card_id_string, CARD_ID_STRING, const char *)
-MMC_ACCESSOR(card_sn_string, CARD_SN_STRING, const char *)
-
-#endif /* BUS_MMC_MMCVAR_H */
+#endif /* DEV_MMC_PRIVATE_H */
diff --git a/sys/bus/mmc/mmc_subr.c b/sys/bus/mmc/mmc_subr.c
new file mode 100644 (file)
index 0000000..3c5bc94
--- /dev/null
@@ -0,0 +1,251 @@
+/*-
+ * 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: head/sys/dev/mmc/mmc_subr.c 315430 2017-03-16 22:23:04Z marius $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+
+#include <bus/mmc/bridge.h>
+#include <bus/mmc/mmc_private.h>
+#include <bus/mmc/mmc_subr.h>
+#include <bus/mmc/mmcreg.h>
+#include <bus/mmc/mmcbrvar.h>
+
+#include "mmcbus_if.h"
+
+#define        CMD_RETRIES     3
+#define        LOG_PPS         5 /* Log no more than 5 errors per second. */
+
+int
+mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd,
+    int retries)
+{
+       struct mmc_request mreq;
+       struct mmc_softc *sc;
+       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;
+               if (cmd->data != NULL)
+                       cmd->data->mrq = &mreq;
+               mreq.cmd = cmd;
+               if (MMCBUS_WAIT_FOR_REQUEST(brdev, reqdev, &mreq) != 0)
+                       err = MMC_ERR_FAILED;
+               else
+                       err = cmd->error;
+       } while (err != MMC_ERR_NONE && retries-- > 0);
+
+       if (err != MMC_ERR_NONE && brdev == reqdev) {
+               sc = device_get_softc(brdev);
+               if (sc->squelched == 0 && ppsratecheck(&sc->log_time,
+                   &sc->log_count, LOG_PPS)) {
+                       device_printf(sc->dev, "CMD%d failed, RESULT: %d\n",
+                           cmd->opcode, err);
+               }
+       }
+
+       return (err);
+}
+
+int
+mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca,
+    struct mmc_command *cmd, int retries)
+{
+       struct mmc_command appcmd;
+       struct mmc_softc *sc;
+       int err;
+
+       sc = device_get_softc(brdev);
+
+       /* Squelch error reporting at lower levels, we report below. */
+       sc->squelched++;
+       do {
+               memset(&appcmd, 0, sizeof(appcmd));
+               appcmd.opcode = MMC_APP_CMD;
+               appcmd.arg = (uint32_t)rca << 16;
+               appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+               if (mmc_wait_for_cmd(brdev, reqdev, &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(brdev, reqdev, 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 && brdev == reqdev) {
+               sc = device_get_softc(brdev);
+               if (sc->squelched == 0 && ppsratecheck(&sc->log_time,
+                   &sc->log_count, LOG_PPS)) {
+                       device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n",
+                           cmd->opcode, err);
+               }
+       }
+
+       return (err);
+}
+
+int
+mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set,
+    uint8_t index, uint8_t value, u_int timeout, bool status)
+{
+       struct mmc_command cmd;
+       int err;
+
+       KASSERT(timeout != 0, ("%s: no timeout", __func__));
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.opcode = MMC_SWITCH_FUNC;
+       cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) |
+           set;
+       /*
+        * If the hardware supports busy detection but the switch timeout
+        * exceeds the maximum host timeout, use a R1 instead of a R1B
+        * response in order to keep the hardware from timing out.
+        */
+       if (mmcbr_get_caps(brdev) & MMC_CAP_WAIT_WHILE_BUSY &&
+           timeout > mmcbr_get_max_busy_timeout(brdev))
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+       else
+               cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+       err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES);
+       if (err != MMC_ERR_NONE || status == false)
+               return (err);
+       return (mmc_switch_status(brdev, reqdev, rca, timeout));
+}
+
+int
+mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout)
+{
+       struct timeval cur, end;
+       int err;
+       uint32_t status;
+
+       KASSERT(timeout != 0, ("%s: no timeout", __func__));
+
+       /*
+        * Note that when using a R1B response in mmc_switch(), bridges of
+        * type MMC_CAP_WAIT_WHILE_BUSY will issue mmc_send_status() only
+        * once and then exit the loop.
+        */
+       for (;;) {
+               err = mmc_send_status(brdev, reqdev, rca, &status);
+               if (err != MMC_ERR_NONE)
+                       break;
+               if (R1_CURRENT_STATE(status) == R1_STATE_TRAN)
+                       break;
+               getmicrouptime(&cur);
+               if (end.tv_sec == 0 && end.tv_usec == 0) {
+                       end.tv_usec = timeout;
+                       timevaladd(&end, &cur);
+               }
+               if (timevalcmp(&cur, &end, >)) {
+                       err = MMC_ERR_TIMEOUT;
+                       break;
+               }
+       }
+       if (err == MMC_ERR_NONE && R1_CURRENT_STATE(status) == R1_SWITCH_ERROR)
+               return (MMC_ERR_FAILED);
+       return (err);
+}
+
+int
+mmc_send_ext_csd(device_t brdev, device_t reqdev, 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, MMC_EXTCSD_SIZE);
+       cmd.opcode = MMC_SEND_EXT_CSD;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+       cmd.data = &data;
+
+       data.data = rawextcsd;
+       data.len = MMC_EXTCSD_SIZE;
+       data.flags = MMC_DATA_READ;
+
+       err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES);
+       return (err);
+}
+
+int
+mmc_send_status(device_t brdev, device_t reqdev, uint16_t rca, uint32_t *status)
+{
+       struct mmc_command cmd;
+       int err;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.opcode = MMC_SEND_STATUS;
+       cmd.arg = (uint32_t)rca << 16;
+       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+       err = mmc_wait_for_cmd(brdev, reqdev, &cmd, CMD_RETRIES);
+       *status = cmd.resp[0];
+       return (err);
+}
similarity index 71%
copy from sys/bus/mmc/mmcvar.h
copy to sys/bus/mmc/mmc_subr.h
index ca6dd0b..8b73c8b 100644 (file)
  * or the SD Card Association to disclose or distribute any technical
  * information, know-how or other confidential information to any third party.
  *
- * $FreeBSD: src/sys/dev/mmc/mmcvar.h,v 1.9 2008/10/29 20:01:26 mav Exp $
+ * $FreeBSD: head/sys/dev/mmc/mmc_subr.h 315430 2017-03-16 22:23:04Z marius $
  */
 
-#ifndef BUS_MMC_MMCVAR_H
-#define BUS_MMC_MMCVAR_H
+#ifndef DEV_MMC_SUBR_H
+#define        DEV_MMC_SUBR_H
 
-#include <bus/mmc/bridge.h>
+struct mmc_command;
 
-enum mmc_device_ivars {
-    MMC_IVAR_DSR_IMP,
-    MMC_IVAR_MEDIA_SIZE,
-    MMC_IVAR_RCA,
-    MMC_IVAR_SECTOR_SIZE,
-    MMC_IVAR_TRAN_SPEED,
-    MMC_IVAR_READ_ONLY,
-    MMC_IVAR_HIGH_CAP,
-    MMC_IVAR_CARD_TYPE,
-    MMC_IVAR_BUS_WIDTH,
-    MMC_IVAR_ERASE_SECTOR,
-    MMC_IVAR_MAX_DATA,
-    MMC_IVAR_CARD_ID_STRING,
-    MMC_IVAR_CARD_SN_STRING,
-};
+int mmc_send_ext_csd(device_t brdev, device_t reqdev, uint8_t *rawextcsd);
+int mmc_send_status(device_t brdev, device_t reqdev, uint16_t rca,
+    uint32_t *status);
+int mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set,
+    uint8_t index, uint8_t value, u_int timeout, bool send_status);
+int mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca,
+    u_int timeout);
+int mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca,
+    struct mmc_command *cmd, int retries);
+int mmc_wait_for_cmd(device_t brdev, device_t reqdev, struct mmc_command *cmd,
+    int retries);
 
-/*
- * Simplified accessors for mmc devices
- */
-#define MMC_ACCESSOR(var, ivar, type)                                  \
-       __BUS_ACCESSOR(mmc, var, MMC, ivar, type)
-
-MMC_ACCESSOR(dsr_imp, DSR_IMP, int)
-MMC_ACCESSOR(media_size, MEDIA_SIZE, long)
-MMC_ACCESSOR(rca, RCA, int)
-MMC_ACCESSOR(sector_size, SECTOR_SIZE, int)
-MMC_ACCESSOR(tran_speed, TRAN_SPEED, int)
-MMC_ACCESSOR(read_only, READ_ONLY, int)
-MMC_ACCESSOR(high_cap, HIGH_CAP, int)
-MMC_ACCESSOR(card_type, CARD_TYPE, int)
-MMC_ACCESSOR(bus_width, BUS_WIDTH, int)
-MMC_ACCESSOR(erase_sector, ERASE_SECTOR, int)
-MMC_ACCESSOR(max_data, MAX_DATA, int)
-MMC_ACCESSOR(card_id_string, CARD_ID_STRING, const char *)
-MMC_ACCESSOR(card_sn_string, CARD_SN_STRING, const char *)
-
-#endif /* BUS_MMC_MMCVAR_H */
+#endif /* DEV_MMC_SUBR_H */
index 99e4cdf..0767286 100644 (file)
@@ -55,7 +55,7 @@
 #ifndef BUS_MMC_MMCBRVAR_H
 #define BUS_MMC_MMCBRVAR_H
 
-#include <bus/mmc/bridge.h>
+#include <bus/mmc/mmcreg.h>
 
 #include "mmcbr_if.h"
 
@@ -73,11 +73,12 @@ enum mmcbr_device_ivars {
     MMCBR_IVAR_VDD,
     MMCBR_IVAR_CAPS,
     MMCBR_IVAR_TIMING,
-    MMCBR_IVAR_MAX_DATA
+    MMCBR_IVAR_MAX_DATA,
+    MMCBR_IVAR_MAX_BUSY_TIMEOUT
 };
 
 /*
- * Simplified accessors for pci devices
+ * Simplified accessors for bridge devices
  */
 #define MMCBR_ACCESSOR(var, ivar, type)                                        \
        __BUS_ACCESSOR(mmcbr, var, MMCBR, ivar, type)
@@ -96,6 +97,7 @@ MMCBR_ACCESSOR(vdd, VDD, int)
 MMCBR_ACCESSOR(caps, CAPS, int)
 MMCBR_ACCESSOR(timing, TIMING, int)
 MMCBR_ACCESSOR(max_data, MAX_DATA, int)
+MMCBR_ACCESSOR(max_busy_timeout, MAX_BUSY_TIMEOUT, u_int)
 
 static __inline int
 mmcbr_update_ios(device_t dev)
index 8f53f62..b8f4826 100644 (file)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2006 M. Warner Losh.  All rights reserved.
+ * Copyright (c) 2017 Marius Strobl <marius@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -137,6 +138,7 @@ struct mmc_command {
 #define        R1_ERASE_RESET (1u << 13)               /* sr, c */
 #define        R1_CURRENT_STATE_MASK (0xfu << 9)       /* sx, b */
 #define        R1_READY_FOR_DATA (1u << 8)             /* sx, a */
+#define        R1_SWITCH_ERROR (1u << 7)               /* sx, c */
 #define        R1_APP_CMD (1u << 5)                    /* sr, c */
 #define        R1_AKE_SEQ_ERROR (1u << 3)              /* er, c */
 #define        R1_STATUS(x)            ((x) & 0xFFFFE000)
@@ -181,7 +183,7 @@ struct mmc_request {
 #define        MMC_SET_RELATIVE_ADDR   3
 #define        SD_SEND_RELATIVE_ADDR   3
 #define        MMC_SET_DSR             4
-                       /* reserved: 5 */
+#define MMC_SLEEP_AWAKE                5
 #define        MMC_SWITCH_FUNC         6
 #define         MMC_SWITCH_FUNC_CMDS    0
 #define         MMC_SWITCH_FUNC_SET     1
@@ -275,7 +277,6 @@ struct mmc_request {
                        /* reserved: 50 */
                        /* reserved: 57 */
 
-
 /* Application specific commands for SD */
 #define        ACMD_SET_BUS_WIDTH      6
 #define        ACMD_SD_STATUS          13
@@ -288,18 +289,72 @@ struct mmc_request {
 /*
  * EXT_CSD fields
  */
+#define        EXT_CSD_EXT_PART_ATTR   52      /* R/W, 2 bytes */
+#define        EXT_CSD_ENH_START_ADDR  136     /* R/W, 4 bytes */
+#define        EXT_CSD_ENH_SIZE_MULT   140     /* R/W, 3 bytes */
+#define        EXT_CSD_GP_SIZE_MULT    143     /* R/W, 12 bytes */
+#define        EXT_CSD_PART_SET        155     /* R/W */
+#define        EXT_CSD_PART_ATTR       156     /* R/W */
+#define        EXT_CSD_PART_SUPPORT    160     /* RO */
+#define        EXT_CSD_RPMB_MULT       168     /* RO */
+#define        EXT_CSD_BOOT_WP_STATUS  174     /* RO */
 #define EXT_CSD_ERASE_GRP_DEF  175     /* R/W */
+#define        EXT_CSD_PART_CONFIG     179     /* R/W */
 #define EXT_CSD_BUS_WIDTH      183     /* R/W */
 #define EXT_CSD_HS_TIMING      185     /* R/W */
 #define EXT_CSD_CARD_TYPE      196     /* RO */
 #define EXT_CSD_REV            192     /* RO */
+#define        EXT_CSD_PART_SWITCH_TO  199     /* RO */
 #define EXT_CSD_SEC_CNT                212     /* RO, 4 bytes */
+#define        EXT_CSD_HC_WP_GRP_SIZE  221     /* RO */
 #define EXT_CSD_ERASE_TO_MULT  223     /* RO */
 #define EXT_CSD_ERASE_GRP_SIZE 224     /* RO */
+#define        EXT_CSD_BOOT_SIZE_MULT  226     /* RO */
+#define        EXT_CSD_GEN_CMD6_TIME   248     /* RO */
 
 /*
  * EXT_CSD field definitions
  */
+#define        EXT_CSD_EXT_PART_ATTR_DEFAULT           0x0
+#define        EXT_CSD_EXT_PART_ATTR_SYSTEMCODE        0x1
+#define        EXT_CSD_EXT_PART_ATTR_NPERSISTENT       0x2
+
+#define        EXT_CSD_PART_SET_COMPLETED              0x01
+
+#define        EXT_CSD_PART_ATTR_ENH_USR               0x01
+#define        EXT_CSD_PART_ATTR_ENH_GP0               0x02
+#define        EXT_CSD_PART_ATTR_ENH_GP1               0x04
+#define        EXT_CSD_PART_ATTR_ENH_GP2               0x08
+#define        EXT_CSD_PART_ATTR_ENH_GP3               0x10
+#define        EXT_CSD_PART_ATTR_ENH_MASK              0x1f
+
+#define        EXT_CSD_PART_SUPPORT_EN                 0x01
+#define        EXT_CSD_PART_SUPPORT_ENH_ATTR_EN        0x02
+#define        EXT_CSD_PART_SUPPORT_EXT_ATTR_EN        0x04
+
+#define        EXT_CSD_BOOT_WP_STATUS_BOOT0_PWR        0x01
+#define        EXT_CSD_BOOT_WP_STATUS_BOOT0_PERM       0x02
+#define        EXT_CSD_BOOT_WP_STATUS_BOOT0_MASK       0x03
+#define        EXT_CSD_BOOT_WP_STATUS_BOOT1_PWR        0x04
+#define        EXT_CSD_BOOT_WP_STATUS_BOOT1_PERM       0x08
+#define        EXT_CSD_BOOT_WP_STATUS_BOOT1_MASK       0x0c
+
+#define        EXT_CSD_ERASE_GRP_DEF_EN        0x01
+
+#define        EXT_CSD_PART_CONFIG_ACC_DEFAULT 0x00
+#define        EXT_CSD_PART_CONFIG_ACC_BOOT0   0x01
+#define        EXT_CSD_PART_CONFIG_ACC_BOOT1   0x02
+#define        EXT_CSD_PART_CONFIG_ACC_RPMB    0x03
+#define        EXT_CSD_PART_CONFIG_ACC_GP0     0x04
+#define        EXT_CSD_PART_CONFIG_ACC_GP1     0x05
+#define        EXT_CSD_PART_CONFIG_ACC_GP2     0x06
+#define        EXT_CSD_PART_CONFIG_ACC_GP3     0x07
+#define        EXT_CSD_PART_CONFIG_ACC_MASK    0x07
+#define        EXT_CSD_PART_CONFIG_BOOT0       0x08
+#define        EXT_CSD_PART_CONFIG_BOOT1       0x10
+#define        EXT_CSD_PART_CONFIG_BOOT_USR    0x38
+#define        EXT_CSD_PART_CONFIG_BOOT_MASK   0x38
+
 #define EXT_CSD_CMD_SET_NORMAL         1
 #define EXT_CSD_CMD_SET_SECURE         2
 #define EXT_CSD_CMD_SET_CPSECURE       4
@@ -435,6 +490,16 @@ struct mmc_sd_status
 };
 
 /*
+ * Various MMC/SD constants
+ */
+#define        MMC_BOOT_RPMB_BLOCK_SIZE        (128 * 1024)
+
+#define        MMC_EXTCSD_SIZE 512
+
+#define        MMC_PART_GP_MAX 4
+#define        MMC_PART_MAX    8
+
+/*
  * Older versions of the MMC standard had a variable sector size.  However,
  * I've been able to find no old MMC or SD cards that have a non 512
  * byte sector size anywhere, so we assume that such cards are very rare
index ca6dd0b..41bcc7a 100644 (file)
@@ -55,9 +55,8 @@
 #ifndef BUS_MMC_MMCVAR_H
 #define BUS_MMC_MMCVAR_H
 
-#include <bus/mmc/bridge.h>
-
 enum mmc_device_ivars {
+    MMC_IVAR_SPEC_VERS,
     MMC_IVAR_DSR_IMP,
     MMC_IVAR_MEDIA_SIZE,
     MMC_IVAR_RCA,
@@ -79,6 +78,7 @@ enum mmc_device_ivars {
 #define MMC_ACCESSOR(var, ivar, type)                                  \
        __BUS_ACCESSOR(mmc, var, MMC, ivar, type)
 
+MMC_ACCESSOR(spec_vers, SPEC_VERS, uint8_t)
 MMC_ACCESSOR(dsr_imp, DSR_IMP, int)
 MMC_ACCESSOR(media_size, MEDIA_SIZE, long)
 MMC_ACCESSOR(rca, RCA, int)
index 0a13e90..073e6b7 100644 (file)
@@ -878,6 +878,7 @@ dev/raid/mlx/mlx_disk.c             optional mlx
 dev/raid/mlx/mlx_pci.c         optional mlx
 dev/raid/mlx/mlx.c             optional mlx
 dev/raid/mly/mly.c             optional mly
+bus/mmc/mmc_subr.c             optional mmc
 bus/mmc/mmc.c                  optional mmc
 bus/mmc/mmcbr_if.m             standard
 bus/mmc/mmcbus_if.m            standard
index e2b621c..daa9d53 100644 (file)
@@ -69,6 +69,7 @@
 
 #include <sys/buf2.h>
 
+#include <bus/mmc/bridge.h>
 #include <bus/mmc/mmcvar.h>
 #include <bus/mmc/mmcreg.h>
 
index e029401..6f42afd 100644 (file)
@@ -717,6 +717,8 @@ sdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
                slot->host.caps |= MMC_CAP_8_BIT_DATA;
        if (caps & SDHCI_CAN_DO_HISPD)
                slot->host.caps |= MMC_CAP_HSPEED;
+       if (slot->quirks & SDHCI_QUIRK_WAIT_WHILE_BUSY)
+               slot->host.caps |= MMC_CAP_WAIT_WHILE_BUSY;
        /* Decide if we have usable DMA. */
        if (caps & SDHCI_CAN_DO_DMA)
                slot->opt |= SDHCI_HAVE_SDMA;
@@ -1025,7 +1027,7 @@ sdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd)
        /* 
         * Interrupt aggregation: To reduce total number of interrupts
         * group response interrupt with data interrupt when possible.
-        * If there going to be data interrupt, mask response one.
+        * If there is going to be a data interrupt, mask the response one.
         */
        if (slot->data_done == 0) {
                WR4(slot, SDHCI_SIGNAL_ENABLE,
@@ -1707,6 +1709,12 @@ sdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *resu
        case MMCBR_IVAR_MAX_DATA:
                *(int *)result = 65535;
                break;
+       case MMCBR_IVAR_MAX_BUSY_TIMEOUT:
+               /*
+                * Currently, sdhci_start_data() hardcodes 1 s for all CMDs.
+                */
+               *result = 1000000;
+               break;
        }
        return (0);
 }
index 395e296..fdd02f6 100644 (file)
@@ -67,6 +67,9 @@
 #define        SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC              (1<<16)
 /* Allow ADMA2 to be used. */
 #define        SDHCI_QUIRK_WHITELIST_ADMA2                     (1<<17)
+/* Controller waits for busy responses. */
+#define        SDHCI_QUIRK_WAIT_WHILE_BUSY                     (1<<22)
+
 
 /*
  * Controller registers
index 4631eba..54c6fe5 100644 (file)
@@ -143,13 +143,28 @@ sdhci_acpi_write_multi_4(device_t dev, struct sdhci_slot *slot __unused,
 
 static void sdhci_acpi_intr(void *arg);
 
+static struct {
+       char *hid;
+       u_int quirks;
+} sdhci_devices[] = {
+       /* The Intel Bay Trail and Braswell controllers work fine with ADMA2. */
+       {"80860F14", SDHCI_QUIRK_WHITELIST_ADMA2 | SDHCI_QUIRK_WAIT_WHILE_BUSY},
+       {"80860F16", SDHCI_QUIRK_WHITELIST_ADMA2 | SDHCI_QUIRK_WAIT_WHILE_BUSY},
+};
+
+static char *sdhci_ids[] = {
+       "80860F14",
+       "80860F16",
+       NULL
+};
+
 static int
 sdhci_acpi_probe(device_t dev)
 {
-       static char *sdhci_ids[] = { "80860F14", "80860F16", NULL };
+       if (acpi_disabled("sdhci"))
+               return (ENXIO);
 
-       if (acpi_disabled("sdhci") ||
-           ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids) == NULL)
+       if (ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids) == NULL)
                return (ENXIO);
 
        device_set_desc(dev, "SDHCI controller");
@@ -160,11 +175,24 @@ static int
 sdhci_acpi_attach(device_t dev)
 {
        struct sdhci_acpi_softc *sc = device_get_softc(dev);
-       int err, rid;
+       char *id;
+       int err, i, rid, quirks;
+
+       id = ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_ids);
+       if (id == NULL)
+               return (ENXIO);
 
        sc->dev = dev;
        sc->handle = acpi_get_handle(dev);
 
+       quirks = 0;
+       for (i = 0; i < NELEM(sdhci_devices); i++) {
+               if (strcmp(sdhci_devices[i].hid, id) == 0) {
+                       quirks = sdhci_devices[i].quirks;
+                       break;
+               }
+       }
+
        /* Allocate IRQ. */
        rid = 0;
        sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
@@ -186,8 +214,8 @@ sdhci_acpi_attach(device_t dev)
        }
 
        pci_set_powerstate(dev, PCI_POWERSTATE_D0);
-       /* The Intel sdhci controllers all work fine with ADMA2. */
-       sc->slot.quirks = SDHCI_QUIRK_WHITELIST_ADMA2;
+
+       sc->slot.quirks = quirks;
        if (sdhci_init_slot(dev, &sc->slot, 0) != 0) {
                device_printf(dev, "sdhci initialization failed\n");
                pci_set_powerstate(dev, PCI_POWERSTATE_D3);
index b8cbf76..3d0f7a4 100644 (file)
@@ -100,6 +100,27 @@ static const struct sdhci_device {
            SDHCI_QUIRK_RESET_AFTER_REQUEST },
        { 0x16bc14e4,   0xffff, "Broadcom BCM577xx SDXC/MMC Card Reader",
            SDHCI_QUIRK_BCM577XX_400KHZ_CLKSRC },
+       { 0x0f148086,   0xffff, "Intel Bay Trail eMMC 4.5 Controller",
+           SDHCI_QUIRK_WHITELIST_ADMA2 |
+           SDHCI_QUIRK_WAIT_WHILE_BUSY },
+       { 0x0f158086,   0xffff, "Intel Bay Trail SDXC Controller",
+           SDHCI_QUIRK_WHITELIST_ADMA2 |
+           SDHCI_QUIRK_WAIT_WHILE_BUSY },
+       { 0x0f508086,   0xffff, "Intel Bay Trail eMMC 4.5 Controller",
+           SDHCI_QUIRK_WHITELIST_ADMA2 |
+           SDHCI_QUIRK_WAIT_WHILE_BUSY },
+       { 0x22948086,   0xffff, "Intel Braswell eMMC 4.5.1 Controller",
+           SDHCI_QUIRK_WHITELIST_ADMA2 |
+           SDHCI_QUIRK_WAIT_WHILE_BUSY },
+       { 0x22968086,   0xffff, "Intel Braswell SDXC Controller",
+           SDHCI_QUIRK_WHITELIST_ADMA2 |
+           SDHCI_QUIRK_WAIT_WHILE_BUSY },
+       { 0x5aca8086,   0xffff, "Intel Apollo Lake SDXC Controller",
+           SDHCI_QUIRK_BROKEN_DMA |    /* APL18 erratum */
+           SDHCI_QUIRK_WAIT_WHILE_BUSY },
+       { 0x5acc8086,   0xffff, "Intel Apollo Lake eMMC 5.0 Controller",
+           SDHCI_QUIRK_BROKEN_DMA |    /* APL18 erratum */
+           SDHCI_QUIRK_WAIT_WHILE_BUSY },
        { 0,            0xffff, NULL,
            0 }
 };