summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/mmc
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-08-07 14:56:50 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-09-21 10:29:37 +0200
commitc37f9fba70085fedc8eede7559489d2321393005 (patch)
tree042455ebf1fa89a277a825f72e1ed805d0b4d296 /freebsd/sys/dev/mmc
parentUpdate to FreeBSD head 2017-06-01 (diff)
downloadrtems-libbsd-c37f9fba70085fedc8eede7559489d2321393005.tar.bz2
Update to FreeBSD head 2017-08-01
Git mirror commit f5002f5e5f78cae9f0269d812dc0aedb0339312c. Update #3472.
Diffstat (limited to 'freebsd/sys/dev/mmc')
-rw-r--r--freebsd/sys/dev/mmc/bridge.h8
-rw-r--r--freebsd/sys/dev/mmc/mmc.c848
-rw-r--r--freebsd/sys/dev/mmc/mmc_ioctl.h2
-rw-r--r--freebsd/sys/dev/mmc/mmc_private.h11
-rw-r--r--freebsd/sys/dev/mmc/mmc_subr.c20
-rw-r--r--freebsd/sys/dev/mmc/mmcbrvar.h16
-rw-r--r--freebsd/sys/dev/mmc/mmcreg.h119
-rw-r--r--freebsd/sys/dev/mmc/mmcsd.c298
8 files changed, 1054 insertions, 268 deletions
diff --git a/freebsd/sys/dev/mmc/bridge.h b/freebsd/sys/dev/mmc/bridge.h
index a780ffae..53e61b48 100644
--- a/freebsd/sys/dev/mmc/bridge.h
+++ b/freebsd/sys/dev/mmc/bridge.h
@@ -137,6 +137,10 @@ enum mmc_card_mode {
mode_mmc, mode_sd
};
+enum mmc_retune_req {
+ retune_req_none = 0, retune_req_normal, retune_req_reset
+};
+
struct mmc_host {
int f_min;
int f_max;
@@ -174,15 +178,17 @@ struct mmc_host {
struct mmc_ios ios; /* Current state of the host */
};
+#ifdef _KERNEL
extern driver_t mmc_driver;
extern devclass_t mmc_devclass;
-#define MMC_VERSION 3
+#define MMC_VERSION 4
#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 /* _KERNEL */
#endif /* DEV_MMC_BRIDGE_H */
diff --git a/freebsd/sys/dev/mmc/mmc.c b/freebsd/sys/dev/mmc/mmc.c
index 023091eb..74e26332 100644
--- a/freebsd/sys/dev/mmc/mmc.c
+++ b/freebsd/sys/dev/mmc/mmc.c
@@ -90,14 +90,14 @@ struct mmc_ivars {
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;
+ u_char read_only; /* True when the device is read-only */
+ u_char high_cap; /* High Capacity device (block addressed) */
enum mmc_card_mode mode;
+ enum mmc_bus_width bus_width; /* Bus width to use */
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 */
- u_char read_only; /* True when the device is read-only */
- u_char bus_width; /* Bus width to use */
- u_char high_cap; /* High Capacity card (block addressed) */
uint32_t sec_count; /* Card capacity in 512byte blocks */
uint32_t timings; /* Mask of bus timings supported */
uint32_t vccq_120; /* Mask of bus timings at VCCQ of 1.2 V */
@@ -129,8 +129,10 @@ static int mmc_read_ivar(device_t bus, device_t child, int which,
uintptr_t *result);
static int mmc_release_bus(device_t busdev, device_t dev);
static int mmc_resume(device_t dev);
+static void mmc_retune_pause(device_t busdev, device_t dev, bool retune);
+static void mmc_retune_unpause(device_t busdev, device_t dev);
static int mmc_suspend(device_t dev);
-static int mmc_wait_for_request(device_t brdev, device_t reqdev,
+static int mmc_wait_for_request(device_t busdev, device_t dev,
struct mmc_request *req);
static int mmc_write_ivar(device_t bus, device_t child, int which,
uintptr_t value);
@@ -157,21 +159,23 @@ 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);
+static int mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd);
static void mmc_delayed_attach(void *xsc);
-static int mmc_delete_cards(struct mmc_softc *sc);
+static int mmc_delete_cards(struct mmc_softc *sc, bool final);
static void mmc_discover_cards(struct mmc_softc *sc);
static void mmc_format_card_id_string(struct mmc_ivars *ivar);
static void mmc_go_discovery(struct mmc_softc *sc);
static uint32_t mmc_get_bits(uint32_t *bits, int bit_len, int start,
int size);
static int mmc_highest_voltage(uint32_t ocr);
+static bool mmc_host_timing(device_t dev, enum mmc_bus_timing timing);
static void mmc_idle_cards(struct mmc_softc *sc);
static void mmc_ms_delay(int ms);
static void mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard);
static void mmc_power_down(struct mmc_softc *sc);
static void mmc_power_up(struct mmc_softc *sc);
static void mmc_rescan_cards(struct mmc_softc *sc);
+static int mmc_retune(device_t busdev, device_t dev, bool reset);
static void mmc_scan(struct mmc_softc *sc);
static int mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp,
uint8_t value, uint8_t *res);
@@ -185,15 +189,23 @@ 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_set_blocklen(struct mmc_softc *sc, uint32_t len);
-static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar);
+static int mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing);
static int mmc_set_power_class(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, struct mmc_ivars *ivar,
enum mmc_bus_timing timing);
+static int mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing);
+static int mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t clock);
+static int mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t max_dtr, enum mmc_bus_timing max_timing);
static int mmc_test_bus_width(struct mmc_softc *sc);
static uint32_t mmc_timing_to_dtr(struct mmc_ivars *ivar,
enum mmc_bus_timing timing);
static const char *mmc_timing_to_string(enum mmc_bus_timing timing);
+static void mmc_update_child_list(struct mmc_softc *sc);
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);
@@ -237,7 +249,8 @@ mmc_detach(device_t dev)
struct mmc_softc *sc = device_get_softc(dev);
int err;
- if ((err = mmc_delete_cards(sc)) != 0)
+ err = mmc_delete_cards(sc, true);
+ if (err != 0)
return (err);
mmc_power_down(sc);
MMC_LOCK_DESTROY(sc);
@@ -252,10 +265,21 @@ mmc_suspend(device_t dev)
int err;
err = bus_generic_suspend(dev);
- if (err)
+ if (err != 0)
+ return (err);
+ /*
+ * We power down with the bus acquired here, mainly so that no device
+ * is selected any longer and sc->last_rca gets set to 0. Otherwise,
+ * the deselect as part of the bus acquisition in mmc_scan() may fail
+ * during resume, as the bus isn't powered up again before later in
+ * mmc_go_discovery().
+ */
+ err = mmc_acquire_bus(dev, dev);
+ if (err != 0)
return (err);
mmc_power_down(sc);
- return (0);
+ err = mmc_release_bus(dev, dev);
+ return (err);
}
static int
@@ -272,7 +296,8 @@ mmc_acquire_bus(device_t busdev, device_t dev)
{
struct mmc_softc *sc;
struct mmc_ivars *ivar;
- int err, rca;
+ int err;
+ uint16_t rca;
enum mmc_bus_timing timing;
err = MMCBR_ACQUIRE_HOST(device_get_parent(busdev), busdev);
@@ -296,12 +321,27 @@ mmc_acquire_bus(device_t busdev, device_t dev)
rca = ivar->rca;
if (sc->last_rca != rca) {
if (mmc_select_card(sc, rca) != MMC_ERR_NONE) {
- device_printf(sc->dev, "Card at relative "
- "address %d failed to select.\n", rca);
+ device_printf(busdev, "Card at relative "
+ "address %d failed to select\n", rca);
return (ENXIO);
}
sc->last_rca = rca;
timing = mmcbr_get_timing(busdev);
+ /*
+ * For eMMC modes, setting/updating bus width and VCCQ
+ * only really is necessary if there actually is more
+ * than one device on the bus as generally that already
+ * had to be done by mmc_calculate_clock() or one of
+ * its calees. Moreover, setting the bus width anew
+ * can trigger re-tuning (via a CRC error on the next
+ * CMD), even if not switching between devices an the
+ * previously selected one is still tuned. Obviously,
+ * we need to re-tune the host controller if devices
+ * are actually switched, though.
+ */
+ if (timing >= bus_timing_mmc_ddr52 &&
+ sc->child_count == 1)
+ return (0);
/* Prepare bus width for the new card. */
if (bootverbose || mmc_debug) {
device_printf(busdev,
@@ -310,38 +350,34 @@ mmc_acquire_bus(device_t busdev, device_t dev)
(ivar->bus_width == bus_width_8) ? 8 : 1,
mmc_timing_to_string(timing));
}
- if (mmc_set_card_bus_width(sc, ivar) != MMC_ERR_NONE) {
- device_printf(sc->dev, "Card at relative "
- "address %d failed to set bus width.\n",
+ if (mmc_set_card_bus_width(sc, ivar, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(busdev, "Card at relative "
+ "address %d failed to set bus width\n",
rca);
return (ENXIO);
}
- if (isset(&ivar->vccq_120, timing))
- mmcbr_set_vccq(busdev, vccq_120);
- else if (isset(&ivar->vccq_180, timing))
- mmcbr_set_vccq(busdev, vccq_180);
- else
- mmcbr_set_vccq(busdev, vccq_330);
- if (mmcbr_switch_vccq(busdev) != 0) {
- device_printf(sc->dev, "Failed to set VCCQ "
- "for card at relative address %d.\n", rca);
+ mmcbr_set_bus_width(busdev, ivar->bus_width);
+ mmcbr_update_ios(busdev);
+ if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(busdev, "Failed to set VCCQ "
+ "for card at relative address %d\n", rca);
return (ENXIO);
}
- if (mmc_set_power_class(sc, ivar) != MMC_ERR_NONE) {
- device_printf(sc->dev, "Card at relative "
- "address %d failed to set power class.\n",
- rca);
+ if (timing >= bus_timing_mmc_hs200 &&
+ mmc_retune(busdev, dev, true) != 0) {
+ device_printf(busdev, "Card at relative "
+ "address %d failed to re-tune\n", rca);
return (ENXIO);
}
- mmcbr_set_bus_width(busdev, ivar->bus_width);
- mmcbr_update_ios(busdev);
}
} else {
/*
* If there's a card selected, stand down.
*/
if (sc->last_rca != 0) {
- mmc_select_card(sc, 0);
+ if (mmc_select_card(sc, 0) != MMC_ERR_NONE)
+ return (ENXIO);
sc->last_rca = 0;
}
}
@@ -416,7 +452,7 @@ mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req)
#endif /* __rtems__ */
req->done = mmc_wakeup;
req->done_data = sc;
- if (mmc_debug > 1) {
+ if (__predict_false(mmc_debug > 1)) {
device_printf(sc->dev, "REQUEST: CMD%d arg %#x flags %#x",
req->cmd->opcode, req->cmd->arg, req->cmd->flags);
if (req->cmd->data) {
@@ -434,18 +470,66 @@ mmc_wait_for_req(struct mmc_softc *sc, struct mmc_request *req)
rtems_binary_semaphore_wait(&req->req_done);
rtems_binary_semaphore_destroy(&req->req_done);
#endif /* __rtems__ */
- if (mmc_debug > 2 || (mmc_debug > 0 && req->cmd->error != MMC_ERR_NONE))
+ if (__predict_false(mmc_debug > 2 || (mmc_debug > 0 &&
+ req->cmd->error != MMC_ERR_NONE)))
device_printf(sc->dev, "CMD%d RESULT: %d\n",
req->cmd->opcode, req->cmd->error);
return (0);
}
static int
-mmc_wait_for_request(device_t brdev, device_t reqdev __unused,
- struct mmc_request *req)
+mmc_wait_for_request(device_t busdev, device_t dev, struct mmc_request *req)
{
- struct mmc_softc *sc = device_get_softc(brdev);
+ struct mmc_softc *sc;
+ struct mmc_ivars *ivar;
+ int err, i;
+ enum mmc_retune_req retune_req;
+
+ sc = device_get_softc(busdev);
+ KASSERT(sc->owner != NULL,
+ ("%s: Request from %s without bus being acquired.", __func__,
+ device_get_nameunit(dev)));
+ /*
+ * Unless no device is selected or re-tuning is already ongoing,
+ * execute re-tuning if a) the bridge is requesting to do so and
+ * re-tuning hasn't been otherwise paused, or b) if a child asked
+ * to be re-tuned prior to pausing (see also mmc_retune_pause()).
+ */
+ if (__predict_false(sc->last_rca != 0 && sc->retune_ongoing == 0 &&
+ (((retune_req = mmcbr_get_retune_req(busdev)) != retune_req_none &&
+ sc->retune_paused == 0) || sc->retune_needed == 1))) {
+ if (__predict_false(mmc_debug > 1)) {
+ device_printf(busdev,
+ "Re-tuning with%s circuit reset required\n",
+ retune_req == retune_req_reset ? "" : "out");
+ }
+ if (device_get_parent(dev) == busdev)
+ ivar = device_get_ivars(dev);
+ else {
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
+ if (ivar->rca == sc->last_rca)
+ break;
+ }
+ if (ivar->rca != sc->last_rca)
+ return (EINVAL);
+ }
+ sc->retune_ongoing = 1;
+ err = mmc_retune(busdev, dev, retune_req == retune_req_reset);
+ sc->retune_ongoing = 0;
+ switch (err) {
+ case MMC_ERR_NONE:
+ case MMC_ERR_FAILED: /* Re-tune error but still might work */
+ break;
+ case MMC_ERR_BADCRC: /* Switch failure on HS400 recovery */
+ return (ENXIO);
+ case MMC_ERR_INVALID: /* Driver implementation b0rken */
+ default: /* Unknown error, should not happen */
+ return (EINVAL);
+ }
+ sc->retune_needed = 0;
+ }
return (mmc_wait_for_req(sc, req));
}
@@ -613,11 +697,14 @@ mmc_power_down(struct mmc_softc *sc)
static int
mmc_select_card(struct mmc_softc *sc, uint16_t rca)
{
- int flags;
+ int err, flags;
flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC;
- return (mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16,
- flags, NULL, CMD_RETRIES));
+ sc->retune_paused++;
+ err = mmc_wait_for_command(sc, MMC_SELECT_CARD, (uint32_t)rca << 16,
+ flags, NULL, CMD_RETRIES);
+ sc->retune_paused--;
+ return (err);
}
static int
@@ -649,7 +736,8 @@ mmc_sd_switch(struct mmc_softc *sc, uint8_t mode, uint8_t grp, uint8_t value,
}
static int
-mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar)
+mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing)
{
struct mmc_command cmd;
int err;
@@ -682,28 +770,33 @@ mmc_set_card_bus_width(struct mmc_softc *sc, struct mmc_ivars *ivar)
} else {
switch (ivar->bus_width) {
case bus_width_1:
+ if (timing == bus_timing_mmc_hs400 ||
+ timing == bus_timing_mmc_hs400es)
+ return (MMC_ERR_INVALID);
value = EXT_CSD_BUS_WIDTH_1;
break;
case bus_width_4:
- switch (mmcbr_get_timing(sc->dev)) {
+ switch (timing) {
case bus_timing_mmc_ddr52:
- case bus_timing_mmc_hs200:
- case bus_timing_mmc_hs400:
- case bus_timing_mmc_hs400es:
value = EXT_CSD_BUS_WIDTH_4_DDR;
break;
+ case bus_timing_mmc_hs400:
+ case bus_timing_mmc_hs400es:
+ return (MMC_ERR_INVALID);
default:
value = EXT_CSD_BUS_WIDTH_4;
break;
}
break;
case bus_width_8:
- switch (mmcbr_get_timing(sc->dev)) {
+ value = 0;
+ switch (timing) {
+ case bus_timing_mmc_hs400es:
+ value = EXT_CSD_BUS_WIDTH_ES;
+ /* FALLTHROUGH */
case bus_timing_mmc_ddr52:
- case bus_timing_mmc_hs200:
case bus_timing_mmc_hs400:
- case bus_timing_mmc_hs400es:
- value = EXT_CSD_BUS_WIDTH_8_DDR;
+ value |= EXT_CSD_BUS_WIDTH_8_DDR;
break;
default:
value = EXT_CSD_BUS_WIDTH_8;
@@ -828,6 +921,13 @@ mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
case bus_timing_mmc_ddr52:
value = EXT_CSD_HS_TIMING_HS;
break;
+ case bus_timing_mmc_hs200:
+ value = EXT_CSD_HS_TIMING_HS200;
+ break;
+ case bus_timing_mmc_hs400:
+ case bus_timing_mmc_hs400es:
+ value = EXT_CSD_HS_TIMING_HS400;
+ break;
default:
return (MMC_ERR_INVALID);
}
@@ -844,6 +944,23 @@ mmc_set_timing(struct mmc_softc *sc, struct mmc_ivars *ivar,
return (err);
}
+static int
+mmc_set_vccq(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ enum mmc_bus_timing timing)
+{
+
+ if (isset(&ivar->vccq_120, timing))
+ mmcbr_set_vccq(sc->dev, vccq_120);
+ else if (isset(&ivar->vccq_180, timing))
+ mmcbr_set_vccq(sc->dev, vccq_180);
+ else
+ mmcbr_set_vccq(sc->dev, vccq_330);
+ if (mmcbr_switch_vccq(sc->dev) != 0)
+ return (MMC_ERR_INVALID);
+ else
+ return (MMC_ERR_NONE);
+}
+
static const uint8_t p8[8] = {
0x55, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -1051,7 +1168,7 @@ static const int cur_max[8] = {
1000, 5000, 10000, 25000, 35000, 45000, 800000, 200000
};
-static void
+static int
mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
{
int v;
@@ -1092,6 +1209,7 @@ mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
+ return (MMC_ERR_NONE);
} else if (v == 1) {
m = mmc_get_bits(raw_csd, 128, 115, 4);
e = mmc_get_bits(raw_csd, 128, 112, 3);
@@ -1115,8 +1233,9 @@ mmc_decode_csd_sd(uint32_t *raw_csd, struct mmc_csd *csd)
csd->r2w_factor = 1 << mmc_get_bits(raw_csd, 128, 26, 3);
csd->write_bl_len = 1 << mmc_get_bits(raw_csd, 128, 22, 4);
csd->write_bl_partial = mmc_get_bits(raw_csd, 128, 21, 1);
- } else
- panic("unknown SD CSD version");
+ return (MMC_ERR_NONE);
+ }
+ return (MMC_ERR_INVALID);
}
static void
@@ -1380,6 +1499,53 @@ mmc_timing_to_string(enum mmc_bus_timing timing)
return ("");
}
+static bool
+mmc_host_timing(device_t dev, enum mmc_bus_timing timing)
+{
+ int host_caps;
+
+ host_caps = mmcbr_get_caps(dev);
+
+#define HOST_TIMING_CAP(host_caps, cap) ({ \
+ bool retval; \
+ if (((host_caps) & (cap)) == (cap)) \
+ retval = true; \
+ else \
+ retval = false; \
+ retval; \
+})
+
+ switch (timing) {
+ case bus_timing_normal:
+ return (true);
+ case bus_timing_hs:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_HSPEED));
+ case bus_timing_uhs_sdr12:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR12));
+ case bus_timing_uhs_sdr25:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR25));
+ case bus_timing_uhs_ddr50:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_DDR50));
+ case bus_timing_uhs_sdr50:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR50));
+ case bus_timing_uhs_sdr104:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_UHS_SDR104));
+ case bus_timing_mmc_ddr52:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_DDR52));
+ case bus_timing_mmc_hs200:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200));
+ case bus_timing_mmc_hs400:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400));
+ case bus_timing_mmc_hs400es:
+ return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400 |
+ MMC_CAP_MMC_ENH_STROBE));
+ }
+
+#undef HOST_TIMING_CAP
+
+ return (false);
+}
+
static void
mmc_log_card(device_t dev, struct mmc_ivars *ivar, int newcard)
{
@@ -1411,9 +1577,8 @@ mmc_discover_cards(struct mmc_softc *sc)
u_char switch_res[64];
uint32_t raw_cid[4];
struct mmc_ivars *ivar = NULL;
- device_t *devlist;
device_t child;
- int devcount, err, host_caps, i, newcard;
+ int err, host_caps, i, newcard;
uint32_t resp, sec_count, status;
uint16_t rca = 2;
@@ -1421,6 +1586,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (bootverbose || mmc_debug)
device_printf(sc->dev, "Probing cards\n");
while (1) {
+ child = NULL;
sc->squelched++; /* Errors are expected, squelch reporting. */
err = mmc_all_send_cid(sc, raw_cid);
sc->squelched--;
@@ -1431,18 +1597,14 @@ mmc_discover_cards(struct mmc_softc *sc)
break;
}
newcard = 1;
- if ((err = device_get_children(sc->dev, &devlist,
- &devcount)) != 0)
- return;
- for (i = 0; i < devcount; i++) {
- ivar = device_get_ivars(devlist[i]);
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if (memcmp(ivar->raw_cid, raw_cid, sizeof(raw_cid)) ==
0) {
newcard = 0;
break;
}
}
- free(devlist, M_TEMP);
if (bootverbose || mmc_debug) {
device_printf(sc->dev,
"%sard detected (CID %08x%08x%08x%08x)\n",
@@ -1465,7 +1627,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error getting RCA %d\n", err);
- break;
+ goto free_ivar;
}
ivar->rca = resp >> 16;
/* Get card CSD. */
@@ -1473,7 +1635,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error getting CSD %d\n", err);
- break;
+ goto free_ivar;
}
if (bootverbose || mmc_debug)
device_printf(sc->dev,
@@ -1481,7 +1643,11 @@ mmc_discover_cards(struct mmc_softc *sc)
newcard ? "New c" : "C", ivar->raw_csd[0],
ivar->raw_csd[1], ivar->raw_csd[2],
ivar->raw_csd[3]);
- mmc_decode_csd_sd(ivar->raw_csd, &ivar->csd);
+ err = mmc_decode_csd_sd(ivar->raw_csd, &ivar->csd);
+ if (err != MMC_ERR_NONE) {
+ device_printf(sc->dev, "Error decoding CSD\n");
+ goto free_ivar;
+ }
ivar->sec_count = ivar->csd.capacity / MMC_SECTOR_SIZE;
if (ivar->csd.csd_structure > 0)
ivar->high_cap = 1;
@@ -1494,12 +1660,12 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading card status %d\n", err);
- break;
+ goto free_ivar;
}
if ((status & R1_CARD_IS_LOCKED) != 0) {
device_printf(sc->dev,
- "Card is password protected, skipping.\n");
- break;
+ "Card is password protected, skipping\n");
+ goto free_ivar;
}
/* Get card SCR. Card must be selected to fetch it. */
@@ -1507,13 +1673,13 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error selecting card %d\n", err);
- break;
+ goto free_ivar;
}
err = mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading SCR %d\n", err);
- break;
+ goto free_ivar;
}
mmc_app_decode_scr(ivar->raw_scr, &ivar->scr);
/* Get card switch capabilities (command class 10). */
@@ -1541,7 +1707,7 @@ mmc_discover_cards(struct mmc_softc *sc)
* use from the sd_status is the erase sector size, but
* it is still nice to get that right.
*/
- mmc_select_card(sc, 0);
+ (void)mmc_select_card(sc, 0);
(void)mmc_select_card(sc, ivar->rca);
(void)mmc_app_sd_status(sc, ivar->rca,
ivar->raw_sd_status);
@@ -1551,47 +1717,24 @@ mmc_discover_cards(struct mmc_softc *sc)
ivar->erase_sector =
16 << ivar->sd_status.au_size;
}
- /* Find max supported bus width. */
+ /* Find maximum supported bus width. */
if ((host_caps & MMC_CAP_4_BIT_DATA) &&
(ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4))
ivar->bus_width = bus_width_4;
- /*
- * Some cards that report maximum I/O block sizes
- * greater than 512 require the block length to be
- * set to 512, even though that is supposed to be
- * the default. Example:
- *
- * Transcend 2GB SDSC card, CID:
- * mid=0x1b oid=0x534d pnm="00000" prv=1.0 mdt=00.2000
- */
- if (ivar->csd.read_bl_len != MMC_SECTOR_SIZE ||
- ivar->csd.write_bl_len != MMC_SECTOR_SIZE)
- mmc_set_blocklen(sc, MMC_SECTOR_SIZE);
-
- mmc_format_card_id_string(ivar);
-
- if (bootverbose || mmc_debug)
- mmc_log_card(sc->dev, ivar, newcard);
- if (newcard) {
- /* Add device. */
- child = device_add_child(sc->dev, NULL, -1);
- device_set_ivars(child, ivar);
- }
- mmc_select_card(sc, 0);
- return;
+ goto child_common;
}
ivar->rca = rca++;
err = mmc_set_relative_addr(sc, ivar->rca);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev, "Error setting RCA %d\n", err);
- break;
+ goto free_ivar;
}
/* Get card CSD. */
err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev, "Error getting CSD %d\n", err);
- break;
+ goto free_ivar;
}
if (bootverbose || mmc_debug)
device_printf(sc->dev,
@@ -1610,19 +1753,19 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading card status %d\n", err);
- break;
+ goto free_ivar;
}
if ((status & R1_CARD_IS_LOCKED) != 0) {
device_printf(sc->dev,
- "Card is password protected, skipping.\n");
- break;
+ "Card is password protected, skipping\n");
+ goto free_ivar;
}
err = mmc_select_card(sc, ivar->rca);
if (err != MMC_ERR_NONE) {
device_printf(sc->dev, "Error selecting card %d\n",
err);
- break;
+ goto free_ivar;
}
/* Only MMC >= 4.x devices support EXT_CSD. */
@@ -1632,7 +1775,7 @@ mmc_discover_cards(struct mmc_softc *sc)
if (err != MMC_ERR_NONE) {
device_printf(sc->dev,
"Error reading EXT_CSD %d\n", err);
- break;
+ goto free_ivar;
}
/* Handle extended capacity from EXT_CSD */
sec_count = ivar->raw_ext_csd[EXT_CSD_SEC_CNT] +
@@ -1643,6 +1786,8 @@ mmc_discover_cards(struct mmc_softc *sc)
ivar->sec_count = sec_count;
ivar->high_cap = 1;
}
+ /* Find maximum supported bus width. */
+ ivar->bus_width = mmc_test_bus_width(sc);
/* Get device speeds beyond normal mode. */
if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
EXT_CSD_CARD_TYPE_HS_52) != 0) {
@@ -1665,6 +1810,50 @@ mmc_discover_cards(struct mmc_softc *sc)
setbit(&ivar->timings, bus_timing_mmc_ddr52);
setbit(&ivar->vccq_180, bus_timing_mmc_ddr52);
}
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS200_1_2V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_120) != 0) {
+ setbit(&ivar->timings, bus_timing_mmc_hs200);
+ setbit(&ivar->vccq_120, bus_timing_mmc_hs200);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS200_1_8V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_180) != 0) {
+ setbit(&ivar->timings, bus_timing_mmc_hs200);
+ setbit(&ivar->vccq_180, bus_timing_mmc_hs200);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_120) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400);
+ setbit(&ivar->vccq_120, bus_timing_mmc_hs400);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_180) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400);
+ setbit(&ivar->vccq_180, bus_timing_mmc_hs400);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_2V) != 0 &&
+ (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] &
+ EXT_CSD_STROBE_SUPPORT_EN) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_120) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400es);
+ setbit(&ivar->vccq_120, bus_timing_mmc_hs400es);
+ }
+ if ((ivar->raw_ext_csd[EXT_CSD_CARD_TYPE] &
+ EXT_CSD_CARD_TYPE_HS400_1_8V) != 0 &&
+ (ivar->raw_ext_csd[EXT_CSD_STROBE_SUPPORT] &
+ EXT_CSD_STROBE_SUPPORT_EN) != 0 &&
+ (host_caps & MMC_CAP_SIGNALING_180) != 0 &&
+ ivar->bus_width == bus_width_8) {
+ setbit(&ivar->timings, bus_timing_mmc_hs400es);
+ setbit(&ivar->vccq_180, bus_timing_mmc_hs400es);
+ }
/*
* Determine generic switch timeout (provided in
* units of 10 ms), defaulting to 500 ms.
@@ -1673,8 +1862,6 @@ mmc_discover_cards(struct mmc_softc *sc)
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 *
@@ -1688,11 +1875,15 @@ mmc_discover_cards(struct mmc_softc *sc)
device_printf(sc->dev,
"Error setting erase group %d\n",
err);
- break;
+ goto free_ivar;
}
}
}
+ mmc_decode_cid_mmc(ivar->raw_cid, &ivar->cid,
+ ivar->raw_ext_csd[EXT_CSD_REV] >= 5);
+
+child_common:
/*
* Some cards that report maximum I/O block sizes greater
* than 512 require the block length to be set to 512, even
@@ -1705,8 +1896,6 @@ 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)
@@ -1714,56 +1903,111 @@ mmc_discover_cards(struct mmc_softc *sc)
if (newcard) {
/* Add device. */
child = device_add_child(sc->dev, NULL, -1);
- device_set_ivars(child, ivar);
+ if (child != NULL) {
+ device_set_ivars(child, ivar);
+ sc->child_list = realloc(sc->child_list,
+ sizeof(device_t) * sc->child_count + 1,
+ M_DEVBUF, M_WAITOK);
+ sc->child_list[sc->child_count++] = child;
+ } else
+ device_printf(sc->dev, "Error adding child\n");
}
- mmc_select_card(sc, 0);
+
+free_ivar:
+ if (newcard && child == NULL)
+ free(ivar, M_DEVBUF);
+ (void)mmc_select_card(sc, 0);
+ /*
+ * Not returning here when one MMC device could no be added
+ * potentially would mean looping forever when that device
+ * is broken (in which case it also may impact the remainder
+ * of the bus anyway, though).
+ */
+ if ((newcard && child == NULL) ||
+ mmcbr_get_mode(sc->dev) == mode_sd)
+ return;
}
}
static void
+mmc_update_child_list(struct mmc_softc *sc)
+{
+ device_t child;
+ int i, j;
+
+ if (sc->child_count == 0) {
+ free(sc->child_list, M_DEVBUF);
+ return;
+ }
+ for (i = j = 0; i < sc->child_count; i++) {
+ for (;;) {
+ child = sc->child_list[j++];
+ if (child != NULL)
+ break;
+ }
+ if (i != j)
+ sc->child_list[i] = child;
+ }
+ sc->child_list = realloc(sc->child_list, sizeof(device_t) *
+ sc->child_count, M_DEVBUF, M_WAITOK);
+}
+
+static void
mmc_rescan_cards(struct mmc_softc *sc)
{
struct mmc_ivars *ivar;
- device_t *devlist;
- int err, i, devcount;
+ int err, i, j;
- if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
- return;
- for (i = 0; i < devcount; i++) {
- ivar = device_get_ivars(devlist[i]);
+ for (i = j = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if (mmc_select_card(sc, ivar->rca) != MMC_ERR_NONE) {
if (bootverbose || mmc_debug)
device_printf(sc->dev,
- "Card at relative address %d lost.\n",
+ "Card at relative address %d lost\n",
ivar->rca);
- device_delete_child(sc->dev, devlist[i]);
+ err = device_delete_child(sc->dev, sc->child_list[i]);
+ if (err != 0) {
+ j++;
+ continue;
+ }
free(ivar, M_DEVBUF);
- }
+ } else
+ j++;
}
- free(devlist, M_TEMP);
- mmc_select_card(sc, 0);
+ if (sc->child_count == j)
+ goto out;
+ sc->child_count = j;
+ mmc_update_child_list(sc);
+out:
+ (void)mmc_select_card(sc, 0);
}
static int
-mmc_delete_cards(struct mmc_softc *sc)
+mmc_delete_cards(struct mmc_softc *sc, bool final)
{
struct mmc_ivars *ivar;
- device_t *devlist;
- int err, i, devcount;
+ int err, i, j;
- if ((err = device_get_children(sc->dev, &devlist, &devcount)) != 0)
- return (err);
- for (i = 0; i < devcount; i++) {
- ivar = device_get_ivars(devlist[i]);
+ err = 0;
+ for (i = j = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if (bootverbose || mmc_debug)
device_printf(sc->dev,
- "Card at relative address %d deleted.\n",
+ "Card at relative address %d deleted\n",
ivar->rca);
- device_delete_child(sc->dev, devlist[i]);
+ err = device_delete_child(sc->dev, sc->child_list[i]);
+ if (err != 0) {
+ j++;
+ if (final == false)
+ continue;
+ else
+ break;
+ }
free(ivar, M_DEVBUF);
}
- free(devlist, M_TEMP);
- return (0);
+ sc->child_count = j;
+ mmc_update_child_list(sc);
+ return (err);
}
static void
@@ -1827,7 +2071,7 @@ mmc_go_discovery(struct mmc_softc *sc)
mmcbr_get_ocr(dev));
if (mmcbr_get_ocr(dev) == 0) {
device_printf(sc->dev, "No compatible cards found on bus\n");
- mmc_delete_cards(sc);
+ (void)mmc_delete_cards(sc, false);
mmc_power_down(sc);
return;
}
@@ -1851,31 +2095,27 @@ mmc_go_discovery(struct mmc_softc *sc)
static int
mmc_calculate_clock(struct mmc_softc *sc)
{
- device_t *kids;
+ device_t dev;
struct mmc_ivars *ivar;
- int host_caps, i, nkid;
+ int i;
uint32_t dtr, max_dtr;
+ uint16_t rca;
enum mmc_bus_timing max_timing, timing;
- bool changed;
+ bool changed, hs400;
- max_dtr = mmcbr_get_f_max(sc->dev);
- host_caps = mmcbr_get_caps(sc->dev);
- if ((host_caps & MMC_CAP_MMC_DDR52) != 0)
- max_timing = bus_timing_mmc_ddr52;
- else if ((host_caps & MMC_CAP_HSPEED) != 0)
- max_timing = bus_timing_hs;
- else
- max_timing = bus_timing_normal;
- if (device_get_children(sc->dev, &kids, &nkid) != 0)
- panic("can't get children");
+ dev = sc->dev;
+ max_dtr = mmcbr_get_f_max(dev);
+ max_timing = bus_timing_max;
do {
changed = false;
- for (i = 0; i < nkid; i++) {
- ivar = device_get_ivars(kids[i]);
- if (isclr(&ivar->timings, max_timing)) {
- for (timing = max_timing; timing >=
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
+ if (isclr(&ivar->timings, max_timing) ||
+ !mmc_host_timing(dev, max_timing)) {
+ for (timing = max_timing - 1; timing >=
bus_timing_normal; timing--) {
- if (isset(&ivar->timings, timing)) {
+ if (isset(&ivar->timings, timing) &&
+ mmc_host_timing(dev, timing)) {
max_timing = timing;
break;
}
@@ -1889,38 +2129,316 @@ mmc_calculate_clock(struct mmc_softc *sc)
}
}
} while (changed == true);
+
if (bootverbose || mmc_debug) {
- device_printf(sc->dev,
+ device_printf(dev,
"setting transfer rate to %d.%03dMHz (%s timing)\n",
max_dtr / 1000000, (max_dtr / 1000) % 1000,
mmc_timing_to_string(max_timing));
}
- for (i = 0; i < nkid; i++) {
- ivar = device_get_ivars(kids[i]);
+
+ /*
+ * HS400 must be tuned in HS200 mode, so in case of HS400 we begin
+ * with HS200 following the sequence as described in "6.6.2.2 HS200
+ * timing mode selection" of the eMMC specification v5.1, too, and
+ * switch to max_timing later. HS400ES requires no tuning and, thus,
+ * can be switch to directly, but requires the same detour via high
+ * speed mode as does HS400 (see mmc_switch_to_hs400()).
+ */
+ hs400 = max_timing == bus_timing_mmc_hs400;
+ timing = hs400 == true ? bus_timing_mmc_hs200 : max_timing;
+ for (i = 0; i < sc->child_count; i++) {
+ ivar = device_get_ivars(sc->child_list[i]);
if ((ivar->timings & ~(1 << bus_timing_normal)) == 0)
continue;
- if (mmc_select_card(sc, ivar->rca) != MMC_ERR_NONE ||
- mmc_set_timing(sc, ivar, max_timing) != MMC_ERR_NONE)
- device_printf(sc->dev, "Card at relative address %d "
- "failed to set timing.\n", ivar->rca);
+
+ rca = ivar->rca;
+ if (mmc_select_card(sc, rca) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to select\n", rca);
+ continue;
+ }
+
+ if (timing == bus_timing_mmc_hs200 || /* includes HS400 */
+ timing == bus_timing_mmc_hs400es) {
+ if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Failed to set VCCQ for "
+ "card at relative address %d\n", rca);
+ continue;
+ }
+ }
+
+ if (timing == bus_timing_mmc_hs200) { /* includes HS400 */
+ /* Set bus width (required for initial tuning). */
+ if (mmc_set_card_bus_width(sc, ivar, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address "
+ "%d failed to set bus width\n", rca);
+ continue;
+ }
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_update_ios(dev);
+ } else if (timing == bus_timing_mmc_hs400es) {
+ if (mmc_switch_to_hs400(sc, ivar, max_dtr, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address "
+ "%d failed to set %s timing\n", rca,
+ mmc_timing_to_string(timing));
+ continue;
+ }
+ goto power_class;
+ }
+
+ if (mmc_set_timing(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to set %s timing\n", rca,
+ mmc_timing_to_string(timing));
+ continue;
+ }
+
+ if (timing == bus_timing_mmc_ddr52) {
+ /*
+ * Set EXT_CSD_BUS_WIDTH_n_DDR in EXT_CSD_BUS_WIDTH
+ * (must be done after switching to EXT_CSD_HS_TIMING).
+ */
+ if (mmc_set_card_bus_width(sc, ivar, timing) !=
+ MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address "
+ "%d failed to set bus width\n", rca);
+ continue;
+ }
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_update_ios(dev);
+ if (mmc_set_vccq(sc, ivar, timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Failed to set VCCQ for "
+ "card at relative address %d\n", rca);
+ continue;
+ }
+ }
+
+ /* Set clock (must be done before initial tuning). */
+ mmcbr_set_clock(dev, max_dtr);
+ mmcbr_update_ios(dev);
+
+ if (mmcbr_tune(dev, hs400) != 0) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to execute initial tuning\n", rca);
+ continue;
+ }
+
+ if (hs400 == true && mmc_switch_to_hs400(sc, ivar, max_dtr,
+ max_timing) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to set %s timing\n", rca,
+ mmc_timing_to_string(max_timing));
+ continue;
+ }
+
+power_class:
+ if (mmc_set_power_class(sc, ivar) != MMC_ERR_NONE) {
+ device_printf(dev, "Card at relative address %d "
+ "failed to set power class\n", rca);
+ }
}
- mmc_select_card(sc, 0);
- free(kids, M_TEMP);
- mmcbr_set_clock(sc->dev, max_dtr);
- mmcbr_update_ios(sc->dev);
+ (void)mmc_select_card(sc, 0);
return (max_dtr);
}
+/*
+ * Switch from HS200 to HS400 (either initially or for re-tuning) or directly
+ * to HS400ES. This follows the sequences described in "6.6.2.3 HS400 timing
+ * mode selection" of the eMMC specification v5.1.
+ */
+static int
+mmc_switch_to_hs400(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t clock, enum mmc_bus_timing max_timing)
+{
+ device_t dev;
+ int err;
+ uint16_t rca;
+
+ dev = sc->dev;
+ rca = ivar->rca;
+
+ /*
+ * Both clock and timing must be set as appropriate for high speed
+ * before eventually switching to HS400/HS400ES; mmc_set_timing()
+ * will issue mmcbr_update_ios().
+ */
+ mmcbr_set_clock(dev, ivar->hs_tran_speed);
+ err = mmc_set_timing(sc, ivar, bus_timing_hs);
+ if (err != MMC_ERR_NONE)
+ return (err);
+
+ /*
+ * Set EXT_CSD_BUS_WIDTH_8_DDR in EXT_CSD_BUS_WIDTH (and additionally
+ * EXT_CSD_BUS_WIDTH_ES for HS400ES).
+ */
+ err = mmc_set_card_bus_width(sc, ivar, max_timing);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_update_ios(dev);
+
+ /* Finally, switch to HS400/HS400ES mode. */
+ err = mmc_set_timing(sc, ivar, max_timing);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_clock(dev, clock);
+ mmcbr_update_ios(dev);
+ return (MMC_ERR_NONE);
+}
+
+/*
+ * Switch from HS400 to HS200 (for re-tuning).
+ */
+static int
+mmc_switch_to_hs200(struct mmc_softc *sc, struct mmc_ivars *ivar,
+ uint32_t clock)
+{
+ device_t dev;
+ int err;
+ uint16_t rca;
+
+ dev = sc->dev;
+ rca = ivar->rca;
+
+ /*
+ * Both clock and timing must initially be set as appropriate for
+ * DDR52 before eventually switching to HS200; mmc_set_timing()
+ * will issue mmcbr_update_ios().
+ */
+ mmcbr_set_clock(dev, ivar->hs_tran_speed);
+ err = mmc_set_timing(sc, ivar, bus_timing_mmc_ddr52);
+ if (err != MMC_ERR_NONE)
+ return (err);
+
+ /*
+ * Next, switch to high speed. Thus, clear EXT_CSD_BUS_WIDTH_n_DDR
+ * in EXT_CSD_BUS_WIDTH and update bus width and timing in ios.
+ */
+ err = mmc_set_card_bus_width(sc, ivar, bus_timing_hs);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_bus_width(dev, ivar->bus_width);
+ mmcbr_set_timing(sc->dev, bus_timing_hs);
+ mmcbr_update_ios(dev);
+
+ /* Finally, switch to HS200 mode. */
+ err = mmc_set_timing(sc, ivar, bus_timing_mmc_hs200);
+ if (err != MMC_ERR_NONE)
+ return (err);
+ mmcbr_set_clock(dev, clock);
+ mmcbr_update_ios(dev);
+ return (MMC_ERR_NONE);
+}
+
+static int
+mmc_retune(device_t busdev, device_t dev, bool reset)
+{
+ struct mmc_softc *sc;
+ struct mmc_ivars *ivar;
+ int err;
+ uint32_t clock;
+ enum mmc_bus_timing timing;
+
+ if (device_get_parent(dev) != busdev)
+ return (MMC_ERR_INVALID);
+
+ sc = device_get_softc(busdev);
+ if (sc->retune_needed != 1 && sc->retune_paused != 0)
+ return (MMC_ERR_INVALID);
+
+ timing = mmcbr_get_timing(busdev);
+ if (timing == bus_timing_mmc_hs400) {
+ /*
+ * Controllers use the data strobe line to latch data from
+ * the devices in HS400 mode so periodic re-tuning isn't
+ * expected to be required, i. e. only if a CRC or tuning
+ * error is signaled to the bridge. In these latter cases
+ * we are asked to reset the tuning circuit and need to do
+ * the switch timing dance.
+ */
+ if (reset == false)
+ return (0);
+ ivar = device_get_ivars(dev);
+ clock = mmcbr_get_clock(busdev);
+ if (mmc_switch_to_hs200(sc, ivar, clock) != MMC_ERR_NONE)
+ return (MMC_ERR_BADCRC);
+ }
+ err = mmcbr_retune(busdev, reset);
+ if (err != 0 && timing == bus_timing_mmc_hs400)
+ return (MMC_ERR_BADCRC);
+ switch (err) {
+ case 0:
+ break;
+ case EIO:
+ return (MMC_ERR_FAILED);
+ default:
+ return (MMC_ERR_INVALID);
+ }
+ if (timing == bus_timing_mmc_hs400) {
+ if (mmc_switch_to_hs400(sc, ivar, clock, timing) !=
+ MMC_ERR_NONE)
+ return (MMC_ERR_BADCRC);
+ }
+ return (MMC_ERR_NONE);
+}
+
+static void
+mmc_retune_pause(device_t busdev, device_t dev, bool retune)
+{
+ struct mmc_softc *sc;
+
+ sc = device_get_softc(busdev);
+ KASSERT(device_get_parent(dev) == busdev,
+ ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev),
+ device_get_nameunit(busdev)));
+ KASSERT(sc->owner != NULL,
+ ("%s: Request from %s without bus being acquired.", __func__,
+ device_get_nameunit(dev)));
+
+ if (retune == true && sc->retune_paused == 0)
+ sc->retune_needed = 1;
+ sc->retune_paused++;
+}
+
+static void
+mmc_retune_unpause(device_t busdev, device_t dev)
+{
+ struct mmc_softc *sc;
+
+ sc = device_get_softc(busdev);
+ KASSERT(device_get_parent(dev) == busdev,
+ ("%s: %s is not a child of %s", __func__, device_get_nameunit(dev),
+ device_get_nameunit(busdev)));
+ KASSERT(sc->owner != NULL,
+ ("%s: Request from %s without bus being acquired.", __func__,
+ device_get_nameunit(dev)));
+ KASSERT(sc->retune_paused != 0,
+ ("%s: Re-tune pause count already at 0", __func__));
+
+ sc->retune_paused--;
+}
+
static void
mmc_scan(struct mmc_softc *sc)
{
device_t dev = sc->dev;
+ int err;
- mmc_acquire_bus(dev, dev);
+ err = mmc_acquire_bus(dev, dev);
+ if (err != 0) {
+ device_printf(dev, "Failed to acquire bus for scanning\n");
+ return;
+ }
mmc_go_discovery(sc);
- mmc_release_bus(dev, dev);
-
- bus_generic_attach(dev);
+ err = mmc_release_bus(dev, dev);
+ if (err != 0) {
+ device_printf(dev, "Failed to release bus after scanning\n");
+ return;
+ }
+ (void)bus_generic_attach(dev);
}
static int
@@ -2019,6 +2537,8 @@ static device_method_t mmc_methods[] = {
DEVMETHOD(bus_child_location_str, mmc_child_location_str),
/* MMC Bus interface */
+ DEVMETHOD(mmcbus_retune_pause, mmc_retune_pause),
+ DEVMETHOD(mmcbus_retune_unpause, mmc_retune_unpause),
DEVMETHOD(mmcbus_wait_for_request, mmc_wait_for_request),
DEVMETHOD(mmcbus_acquire_bus, mmc_acquire_bus),
DEVMETHOD(mmcbus_release_bus, mmc_release_bus),
diff --git a/freebsd/sys/dev/mmc/mmc_ioctl.h b/freebsd/sys/dev/mmc/mmc_ioctl.h
index 97cff068..e633fec9 100644
--- a/freebsd/sys/dev/mmc/mmc_ioctl.h
+++ b/freebsd/sys/dev/mmc/mmc_ioctl.h
@@ -54,7 +54,7 @@ struct mmc_ioc_multi_cmd {
#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)
+#define MMC_IOC_MULTI_CMD _IOWR(MMC_IOC_BASE, 1, struct mmc_ioc_multi_cmd)
/* Maximum accepted data transfer size */
#define MMC_IOC_MAX_BYTES (512 * 256)
diff --git a/freebsd/sys/dev/mmc/mmc_private.h b/freebsd/sys/dev/mmc/mmc_private.h
index bbca0c60..633d0784 100644
--- a/freebsd/sys/dev/mmc/mmc_private.h
+++ b/freebsd/sys/dev/mmc/mmc_private.h
@@ -60,9 +60,14 @@ struct mmc_softc {
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;
+ device_t *child_list;
+ int child_count;
+ uint16_t last_rca;
+ uint16_t retune_paused;
+ uint8_t retune_needed;
+ uint8_t retune_ongoing;
+ uint16_t squelched; /* suppress reporting of (expected) errors */
+ int log_count;
struct timeval log_time;
};
diff --git a/freebsd/sys/dev/mmc/mmc_subr.c b/freebsd/sys/dev/mmc/mmc_subr.c
index f76e9637..006354ba 100644
--- a/freebsd/sys/dev/mmc/mmc_subr.c
+++ b/freebsd/sys/dev/mmc/mmc_subr.c
@@ -140,7 +140,6 @@ mmc_wait_for_app_cmd(device_t brdev, device_t reqdev, uint16_t rca,
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",
@@ -156,10 +155,13 @@ 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;
+ struct mmc_softc *sc;
int err;
KASSERT(timeout != 0, ("%s: no timeout", __func__));
+ sc = device_get_softc(brdev);
+
memset(&cmd, 0, sizeof(cmd));
cmd.opcode = MMC_SWITCH_FUNC;
cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) |
@@ -174,10 +176,19 @@ mmc_switch(device_t brdev, device_t reqdev, uint16_t rca, uint8_t set,
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
else
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ /*
+ * Pause re-tuning so it won't interfere with the busy state and also
+ * so that the result of CMD13 will always refer to switching rather
+ * than to a tuning command that may have snuck in between.
+ */
+ sc->retune_paused++;
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));
+ goto out;
+ err = mmc_switch_status(brdev, reqdev, rca, timeout);
+out:
+ sc->retune_paused--;
+ return (err);
}
int
@@ -194,6 +205,7 @@ mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout)
* type MMC_CAP_WAIT_WHILE_BUSY will issue mmc_send_status() only
* once and then exit the loop.
*/
+ end.tv_sec = end.tv_usec = 0;
for (;;) {
err = mmc_send_status(brdev, reqdev, rca, &status);
if (err != MMC_ERR_NONE)
@@ -210,7 +222,7 @@ mmc_switch_status(device_t brdev, device_t reqdev, uint16_t rca, u_int timeout)
break;
}
}
- if (err == MMC_ERR_NONE && R1_CURRENT_STATE(status) == R1_SWITCH_ERROR)
+ if (err == MMC_ERR_NONE && (status & R1_SWITCH_ERROR) != 0)
return (MMC_ERR_FAILED);
return (err);
}
diff --git a/freebsd/sys/dev/mmc/mmcbrvar.h b/freebsd/sys/dev/mmc/mmcbrvar.h
index 77c304b4..c70af92a 100644
--- a/freebsd/sys/dev/mmc/mmcbrvar.h
+++ b/freebsd/sys/dev/mmc/mmcbrvar.h
@@ -70,6 +70,7 @@ enum mmcbr_device_ivars {
MMCBR_IVAR_MODE,
MMCBR_IVAR_OCR,
MMCBR_IVAR_POWER_MODE,
+ MMCBR_IVAR_RETUNE_REQ,
MMCBR_IVAR_VDD,
MMCBR_IVAR_VCCQ,
MMCBR_IVAR_CAPS,
@@ -94,6 +95,7 @@ MMCBR_ACCESSOR(host_ocr, HOST_OCR, int)
MMCBR_ACCESSOR(mode, MODE, int)
MMCBR_ACCESSOR(ocr, OCR, int)
MMCBR_ACCESSOR(power_mode, POWER_MODE, int)
+MMCBR_ACCESSOR(retune_req, RETUNE_REQ, int)
MMCBR_ACCESSOR(vdd, VDD, int)
MMCBR_ACCESSOR(vccq, VCCQ, int)
MMCBR_ACCESSOR(caps, CAPS, int)
@@ -109,6 +111,20 @@ mmcbr_update_ios(device_t dev)
}
static int __inline
+mmcbr_tune(device_t dev, bool hs400)
+{
+
+ return (MMCBR_TUNE(device_get_parent(dev), dev, hs400));
+}
+
+static int __inline
+mmcbr_retune(device_t dev, bool reset)
+{
+
+ return (MMCBR_RETUNE(device_get_parent(dev), dev, reset));
+}
+
+static int __inline
mmcbr_switch_vccq(device_t dev)
{
diff --git a/freebsd/sys/dev/mmc/mmcreg.h b/freebsd/sys/dev/mmc/mmcreg.h
index 39680ad6..80f433c1 100644
--- a/freebsd/sys/dev/mmc/mmcreg.h
+++ b/freebsd/sys/dev/mmc/mmcreg.h
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2006 M. Warner Losh. All rights reserved.
* Copyright (c) 2017 Marius Strobl <marius@FreeBSD.org>
+ * Copyright (c) 2015-2016 Ilya Bakulin <kibab@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -159,6 +160,34 @@ struct mmc_command {
#define R1_STATE_PRG 7
#define R1_STATE_DIS 8
+/* R4 response (SDIO) */
+#define R4_IO_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3)
+#define R4_IO_MEM_PRESENT (0x1<<27)
+#define R4_IO_OCR_MASK 0x00fffff0
+
+/*
+ * R5 responses
+ *
+ * Types (per SD 2.0 standard)
+ *e : error bit
+ *s : status bit
+ *r : detected and set for the actual command response
+ *x : Detected and set during command execution. The host can get
+ * the status by issuing a command with R1 response.
+ *
+ * Clear Condition (per SD 2.0 standard)
+ *a : according to the card current state.
+ *b : always related to the previous command. reception of a valid
+ * command will clear it (with a delay of one command).
+ *c : clear by read
+ */
+#define R5_COM_CRC_ERROR (1u << 15)/* er, b */
+#define R5_ILLEGAL_COMMAND (1u << 14)/* er, b */
+#define R5_IO_CURRENT_STATE_MASK (3u << 12)/* s, b */
+#define R5_IO_CURRENT_STATE(x) (((x) & R5_IO_CURRENT_STATE_MASK) >> 12)
+#define R5_ERROR (1u << 11)/* erx, c */
+#define R5_FUNCTION_NUMBER (1u << 9)/* er, c */
+#define R5_OUT_OF_RANGE (1u << 8)/* er, c */
struct mmc_data {
size_t len; /* size of the data */
size_t xfer_len;
@@ -176,10 +205,12 @@ struct mmc_request {
struct mmc_command *stop;
void (*done)(struct mmc_request *); /* Completion function */
void *done_data; /* requestor set data */
-#ifndef __rtems__
uint32_t flags;
+#ifndef __rtems__
#define MMC_REQ_DONE 1
-#else /* __rtems__ */
+#endif /* __rtems__ */
+#define MMC_TUNE_DONE 2
+#ifdef __rtems__
rtems_binary_semaphore req_done;
#endif /* __rtems__ */
};
@@ -194,6 +225,7 @@ struct mmc_request {
#define SD_SEND_RELATIVE_ADDR 3
#define MMC_SET_DSR 4
#define MMC_SLEEP_AWAKE 5
+#define IO_SEND_OP_COND 5
#define MMC_SWITCH_FUNC 6
#define MMC_SWITCH_FUNC_CMDS 0
#define MMC_SWITCH_FUNC_SET 1
@@ -276,7 +308,31 @@ struct mmc_request {
/* Class 9: I/O cards (sd) */
#define SD_IO_RW_DIRECT 52
+/* CMD52 arguments */
+#define SD_ARG_CMD52_READ (0<<31)
+#define SD_ARG_CMD52_WRITE (1<<31)
+#define SD_ARG_CMD52_FUNC_SHIFT 28
+#define SD_ARG_CMD52_FUNC_MASK 0x7
+#define SD_ARG_CMD52_EXCHANGE (1<<27)
+#define SD_ARG_CMD52_REG_SHIFT 9
+#define SD_ARG_CMD52_REG_MASK 0x1ffff
+#define SD_ARG_CMD52_DATA_SHIFT 0
+#define SD_ARG_CMD52_DATA_MASK 0xff
+#define SD_R5_DATA(resp) ((resp)[0] & 0xff)
+
#define SD_IO_RW_EXTENDED 53
+/* CMD53 arguments */
+#define SD_ARG_CMD53_READ (0<<31)
+#define SD_ARG_CMD53_WRITE (1<<31)
+#define SD_ARG_CMD53_FUNC_SHIFT 28
+#define SD_ARG_CMD53_FUNC_MASK 0x7
+#define SD_ARG_CMD53_BLOCK_MODE (1<<27)
+#define SD_ARG_CMD53_INCREMENT (1<<26)
+#define SD_ARG_CMD53_REG_SHIFT 9
+#define SD_ARG_CMD53_REG_MASK 0x1ffff
+#define SD_ARG_CMD53_LENGTH_SHIFT 0
+#define SD_ARG_CMD53_LENGTH_MASK 0x1ff
+#define SD_ARG_CMD53_LENGTH_MAX 64 /* XXX should be 511? */
/* Class 10: Switch function commands */
#define SD_SWITCH_FUNC 6
@@ -384,8 +440,8 @@ struct mmc_request {
#define EXT_CSD_HS_TIMING_BC 0
#define EXT_CSD_HS_TIMING_HS 1
-#define EXT_CSD_HS_TIMING_DDR200 2
-#define EXT_CSD_HS_TIMING_DDR400 3
+#define EXT_CSD_HS_TIMING_HS200 2
+#define EXT_CSD_HS_TIMING_HS400 3
#define EXT_CSD_HS_TIMING_DRV_STR_SHIFT 4
#define EXT_CSD_POWER_CLASS_8BIT_MASK 0xf0
@@ -401,7 +457,6 @@ struct mmc_request {
#define EXT_CSD_CARD_TYPE_HS200_1_2V 0x0020
#define EXT_CSD_CARD_TYPE_HS400_1_8V 0x0040
#define EXT_CSD_CARD_TYPE_HS400_1_2V 0x0080
-#define EXT_CSD_CARD_TYPE_HS400ES 0x0100
#define EXT_CSD_BUS_WIDTH_1 0
#define EXT_CSD_BUS_WIDTH_4 1
@@ -410,6 +465,8 @@ struct mmc_request {
#define EXT_CSD_BUS_WIDTH_8_DDR 6
#define EXT_CSD_BUS_WIDTH_ES 0x80
+#define EXT_CSD_STROBE_SUPPORT_EN 0x01
+
#define MMC_TYPE_HS_26_MAX 26000000
#define MMC_TYPE_HS_52_MAX 52000000
#define MMC_TYPE_DDR52_MAX 52000000
@@ -447,6 +504,54 @@ struct mmc_request {
/* Specifications require 400 kHz max. during ID phase. */
#define SD_MMC_CARD_ID_FREQUENCY 400000
+/*
+ * SDIO Direct & Extended I/O
+ */
+#define SD_IO_RW_WR (1u << 31)
+#define SD_IO_RW_FUNC(x) (((x) & 0x7) << 28)
+#define SD_IO_RW_RAW (1u << 27)
+#define SD_IO_RW_INCR (1u << 26)
+#define SD_IO_RW_ADR(x) (((x) & 0x1FFFF) << 9)
+#define SD_IO_RW_DAT(x) (((x) & 0xFF) << 0)
+#define SD_IO_RW_LEN(x) (((x) & 0xFF) << 0)
+
+#define SD_IOE_RW_LEN(x) (((x) & 0x1FF) << 0)
+#define SD_IOE_RW_BLK (1u << 27)
+
+/* Card Common Control Registers (CCCR) */
+#define SD_IO_CCCR_START 0x00000
+#define SD_IO_CCCR_SIZE 0x100
+#define SD_IO_CCCR_FN_ENABLE 0x02
+#define SD_IO_CCCR_FN_READY 0x03
+#define SD_IO_CCCR_INT_ENABLE 0x04
+#define SD_IO_CCCR_INT_PENDING 0x05
+#define SD_IO_CCCR_CTL 0x06
+#define CCCR_CTL_RES (1<<3)
+#define SD_IO_CCCR_BUS_WIDTH 0x07
+#define CCCR_BUS_WIDTH_4 (1<<1)
+#define CCCR_BUS_WIDTH_1 (1<<0)
+#define SD_IO_CCCR_CARDCAP 0x08
+#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */
+
+/* Function Basic Registers (FBR) */
+#define SD_IO_FBR_START 0x00100
+#define SD_IO_FBR_SIZE 0x00700
+
+/* Card Information Structure (CIS) */
+#define SD_IO_CIS_START 0x01000
+#define SD_IO_CIS_SIZE 0x17000
+
+/* CIS tuple codes (based on PC Card 16) */
+#define SD_IO_CISTPL_VERS_1 0x15
+#define SD_IO_CISTPL_MANFID 0x20
+#define SD_IO_CISTPL_FUNCID 0x21
+#define SD_IO_CISTPL_FUNCE 0x22
+#define SD_IO_CISTPL_END 0xff
+
+/* CISTPL_FUNCID codes */
+/* OpenBSD incorrectly defines 0x0c as FUNCTION_WLAN */
+/* #define SDMMC_FUNCTION_WLAN 0x0c */
+
/* OCR bits */
/*
@@ -562,6 +667,10 @@ struct mmc_sd_status
#define MMC_PART_GP_MAX 4
#define MMC_PART_MAX 8
+#define MMC_TUNING_MAX 64 /* Maximum tuning iterations */
+#define MMC_TUNING_LEN 64 /* Size of tuning data */
+#define MMC_TUNING_LEN_HS200 128 /* Size of tuning data in HS200 mode */
+
/*
* 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
diff --git a/freebsd/sys/dev/mmc/mmcsd.c b/freebsd/sys/dev/mmc/mmcsd.c
index 5066e250..195feae2 100644
--- a/freebsd/sys/dev/mmc/mmcsd.c
+++ b/freebsd/sys/dev/mmc/mmcsd.c
@@ -108,7 +108,8 @@ __FBSDID("$FreeBSD$");
struct mmcsd_softc;
struct mmcsd_part {
- struct mtx part_mtx;
+ struct mtx disk_mtx;
+ struct mtx ioctl_mtx;
struct mmcsd_softc *sc;
#ifndef __rtems__
struct disk *disk;
@@ -120,6 +121,7 @@ struct mmcsd_part {
u_int type;
int running;
int suspend;
+ int ioctl;
bool ro;
char name[MMCSD_PART_NAMELEN];
};
@@ -129,6 +131,9 @@ struct mmcsd_softc {
device_t mmcbr;
struct mmcsd_part *part[MMC_PART_MAX];
enum mmc_card_mode mode;
+ u_int max_data; /* Maximum data size [blocks] */
+ u_int erase_sector; /* Device native erase sector size [blocks] */
+ uint8_t high_cap; /* High Capacity device (block addressed) */
uint8_t part_curr; /* Partition currently switched to */
uint8_t ext_csd[MMC_EXTCSD_SIZE];
uint16_t rca;
@@ -199,15 +204,25 @@ static int mmcsd_slicer(device_t dev, const char *provider,
static int mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca,
u_int part);
-#define MMCSD_PART_LOCK(_part) mtx_lock(&(_part)->part_mtx)
-#define MMCSD_PART_UNLOCK(_part) mtx_unlock(&(_part)->part_mtx)
-#define MMCSD_PART_LOCK_INIT(_part) \
- mtx_init(&(_part)->part_mtx, (_part)->name, "mmcsd part", MTX_DEF)
-#define MMCSD_PART_LOCK_DESTROY(_part) mtx_destroy(&(_part)->part_mtx);
-#define MMCSD_PART_ASSERT_LOCKED(_part) \
- mtx_assert(&(_part)->part_mtx, MA_OWNED);
-#define MMCSD_PART_ASSERT_UNLOCKED(_part) \
- mtx_assert(&(_part)->part_mtx, MA_NOTOWNED);
+#define MMCSD_DISK_LOCK(_part) mtx_lock(&(_part)->disk_mtx)
+#define MMCSD_DISK_UNLOCK(_part) mtx_unlock(&(_part)->disk_mtx)
+#define MMCSD_DISK_LOCK_INIT(_part) \
+ mtx_init(&(_part)->disk_mtx, (_part)->name, "mmcsd disk", MTX_DEF)
+#define MMCSD_DISK_LOCK_DESTROY(_part) mtx_destroy(&(_part)->disk_mtx);
+#define MMCSD_DISK_ASSERT_LOCKED(_part) \
+ mtx_assert(&(_part)->disk_mtx, MA_OWNED);
+#define MMCSD_DISK_ASSERT_UNLOCKED(_part) \
+ mtx_assert(&(_part)->disk_mtx, MA_NOTOWNED);
+
+#define MMCSD_IOCTL_LOCK(_part) mtx_lock(&(_part)->ioctl_mtx)
+#define MMCSD_IOCTL_UNLOCK(_part) mtx_unlock(&(_part)->ioctl_mtx)
+#define MMCSD_IOCTL_LOCK_INIT(_part) \
+ mtx_init(&(_part)->ioctl_mtx, (_part)->name, "mmcsd IOCTL", MTX_DEF)
+#define MMCSD_IOCTL_LOCK_DESTROY(_part) mtx_destroy(&(_part)->ioctl_mtx);
+#define MMCSD_IOCTL_ASSERT_LOCKED(_part) \
+ mtx_assert(&(_part)->ioctl_mtx, MA_OWNED);
+#define MMCSD_IOCLT_ASSERT_UNLOCKED(_part) \
+ mtx_assert(&(_part)->ioctl_mtx, MA_NOTOWNED);
static int
mmcsd_probe(device_t dev)
@@ -277,7 +292,7 @@ rtems_bsd_mmcsd_disk_read_write(struct mmcsd_part *part, rtems_blkdev_request *b
data_flags = MMC_DATA_READ;
}
- MMCSD_PART_LOCK(part);
+ MMCSD_DISK_LOCK(part);
for (i = 0; i < buffer_count; ++i) {
rtems_blkdev_sg_buffer *sg = &blkreq->bufs [i];
@@ -354,7 +369,7 @@ rtems_bsd_mmcsd_disk_read_write(struct mmcsd_part *part, rtems_blkdev_request *b
error:
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
rtems_blkdev_request_done(blkreq, status_code);
@@ -439,6 +454,18 @@ mmcsd_attach(device_t dev)
sc->dev = dev;
sc->mmcbr = mmcbr = device_get_parent(dev);
sc->mode = mmcbr_get_mode(mmcbr);
+ /*
+ * Note that in principle with an SDHCI-like re-tuning implementation,
+ * the maximum data size can change at runtime due to a device removal/
+ * insertion that results in switches to/from a transfer mode involving
+ * re-tuning, iff there are multiple devices on a given bus. Until now
+ * mmc(4) lacks support for rescanning already attached buses, however,
+ * and sdhci(4) to date has no support for shared buses in the first
+ * place either.
+ */
+ sc->max_data = mmc_get_max_data(dev);
+ sc->erase_sector = mmc_get_erase_sector(dev);
+ sc->high_cap = mmc_get_high_cap(dev);
sc->rca = mmc_get_rca(dev);
/* Only MMC >= 4.x devices support EXT_CSD. */
@@ -492,7 +519,7 @@ mmcsd_attach(device_t dev)
(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24)) *
- (mmc_get_high_cap(dev) ? MMC_SECTOR_SIZE : 1);
+ (sc->high_cap != 0 ? MMC_SECTOR_SIZE : 1);
} else if (bootverbose)
device_printf(dev,
"enhanced user data area spans entire device\n");
@@ -505,7 +532,7 @@ mmcsd_attach(device_t dev)
ro = mmc_get_read_only(dev);
mmcsd_add_part(sc, EXT_CSD_PART_CONFIG_ACC_DEFAULT, "mmcsd",
device_get_unit(dev), mmc_get_media_size(dev) * sector_size,
- mmc_get_erase_sector(dev) * sector_size, ro);
+ sc->erase_sector * sector_size, ro);
if (mmc_get_spec_vers(dev) < 3)
return (0);
@@ -644,7 +671,16 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
part->ro = ro;
snprintf(part->name, sizeof(part->name), name, device_get_unit(dev));
- /* For the RPMB partition, allow IOCTL access only. */
+ MMCSD_IOCTL_LOCK_INIT(part);
+
+ /*
+ * For the RPMB partition, allow IOCTL access only.
+ * NB: If ever attaching RPMB partitions to disk(9), the re-tuning
+ * implementation and especially its pausing need to be revisited,
+ * because then re-tuning requests may be issued by the IOCTL half
+ * of this driver while re-tuning is already paused by the disk(9)
+ * one and vice versa.
+ */
if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
make_dev_args_init(&args);
args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
@@ -659,7 +695,7 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
return;
}
} else {
- MMCSD_PART_LOCK_INIT(part);
+ MMCSD_DISK_LOCK_INIT(part);
#ifndef __rtems__
d = part->disk = disk_alloc();
@@ -672,7 +708,7 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
d->d_name = part->name;
d->d_drv1 = part;
d->d_sectorsize = mmc_get_sector_size(dev);
- d->d_maxsize = mmc_get_max_data(dev) * d->d_sectorsize;
+ d->d_maxsize = sc->max_data * d->d_sectorsize;
d->d_mediasize = media_size;
d->d_stripesize = erase_size;
d->d_unit = cnt;
@@ -704,7 +740,7 @@ mmcsd_add_part(struct mmcsd_softc *sc, u_int type, const char *name, u_int cnt,
part->name, cnt, bytes, unit, mmc_get_card_id_string(dev),
ro ? " (read-only)" : "", device_get_nameunit(mmcbr),
speed / 1000000, (speed / 100000) % 10,
- mmcsd_bus_bit_width(dev), mmc_get_max_data(dev));
+ mmcsd_bus_bit_width(dev), sc->max_data);
} else if (type == EXT_CSD_PART_CONFIG_ACC_RPMB) {
printf("%s: %ju%sB partion %d%s at %s\n", part->name, bytes,
unit, type, ro ? " (read-only)" : "",
@@ -795,19 +831,27 @@ mmcsd_detach(device_t dev)
for (i = 0; i < MMC_PART_MAX; i++) {
part = sc->part[i];
- if (part != NULL && part->disk != NULL) {
- MMCSD_PART_LOCK(part);
- part->suspend = 0;
- if (part->running > 0) {
- /* kill thread */
- part->running = 0;
- wakeup(part);
- /* wait for thread to finish. */
- while (part->running != -1)
- msleep(part, &part->part_mtx, 0,
- "detach", 0);
+ if (part != NULL) {
+ if (part->disk != NULL) {
+ MMCSD_DISK_LOCK(part);
+ part->suspend = 0;
+ if (part->running > 0) {
+ /* kill thread */
+ part->running = 0;
+ wakeup(part);
+ /* wait for thread to finish. */
+ while (part->running != -1)
+ msleep(part, &part->disk_mtx, 0,
+ "mmcsd disk detach", 0);
+ }
+ MMCSD_DISK_UNLOCK(part);
}
- MMCSD_PART_UNLOCK(part);
+ MMCSD_IOCTL_LOCK(part);
+ while (part->ioctl > 0)
+ msleep(part, &part->ioctl_mtx, 0,
+ "mmcsd IOCTL detach", 0);
+ part->ioctl = -1;
+ MMCSD_IOCTL_UNLOCK(part);
}
}
@@ -823,8 +867,9 @@ mmcsd_detach(device_t dev)
/* kill disk */
disk_destroy(part->disk);
- MMCSD_PART_LOCK_DESTROY(part);
+ MMCSD_DISK_LOCK_DESTROY(part);
}
+ MMCSD_IOCTL_LOCK_DESTROY(part);
free(part, M_DEVBUF);
}
}
@@ -844,19 +889,27 @@ mmcsd_suspend(device_t dev)
for (i = 0; i < MMC_PART_MAX; i++) {
part = sc->part[i];
- if (part != NULL && part->disk != NULL) {
- MMCSD_PART_LOCK(part);
- part->suspend = 1;
- if (part->running > 0) {
- /* kill thread */
- part->running = 0;
- wakeup(part);
- /* wait for thread to finish. */
- while (part->running != -1)
- msleep(part, &part->part_mtx, 0,
- "detach", 0);
+ if (part != NULL) {
+ if (part->disk != NULL) {
+ MMCSD_DISK_LOCK(part);
+ part->suspend = 1;
+ if (part->running > 0) {
+ /* kill thread */
+ part->running = 0;
+ wakeup(part);
+ /* wait for thread to finish. */
+ while (part->running != -1)
+ msleep(part, &part->disk_mtx, 0,
+ "mmcsd disk suspension", 0);
+ }
+ MMCSD_DISK_UNLOCK(part);
}
- MMCSD_PART_UNLOCK(part);
+ MMCSD_IOCTL_LOCK(part);
+ while (part->ioctl > 0)
+ msleep(part, &part->ioctl_mtx, 0,
+ "mmcsd IOCTL suspension", 0);
+ part->ioctl = -1;
+ MMCSD_IOCTL_UNLOCK(part);
}
}
#else /* __rtems__ */
@@ -875,16 +928,22 @@ mmcsd_resume(device_t dev)
for (i = 0; i < MMC_PART_MAX; i++) {
part = sc->part[i];
- if (part != NULL && part->disk != NULL) {
- MMCSD_PART_LOCK(part);
- part->suspend = 0;
- if (part->running <= 0) {
- part->running = 1;
- kproc_create(&mmcsd_task, part, &part->p, 0, 0,
- "%s%d: mmc/sd card", part->name, part->cnt);
- MMCSD_PART_UNLOCK(part);
- } else
- MMCSD_PART_UNLOCK(part);
+ if (part != NULL) {
+ if (part->disk != NULL) {
+ MMCSD_DISK_LOCK(part);
+ part->suspend = 0;
+ if (part->running <= 0) {
+ part->running = 1;
+ MMCSD_DISK_UNLOCK(part);
+ kproc_create(&mmcsd_task, part,
+ &part->p, 0, 0, "%s%d: mmc/sd card",
+ part->name, part->cnt);
+ } else
+ MMCSD_DISK_UNLOCK(part);
+ }
+ MMCSD_IOCTL_LOCK(part);
+ part->ioctl = 0;
+ MMCSD_IOCTL_UNLOCK(part);
}
}
#else /* __rtems__ */
@@ -916,13 +975,13 @@ mmcsd_strategy(struct bio *bp)
part = bp->bio_disk->d_drv1;
sc = part->sc;
- MMCSD_PART_LOCK(part);
+ MMCSD_DISK_LOCK(part);
if (part->running > 0 || part->suspend > 0) {
bioq_disksort(&part->bio_queue, bp);
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
wakeup(part);
} else {
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
biofinish(bp, NULL, ENXIO);
}
}
@@ -961,9 +1020,9 @@ mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag)
switch (cmd) {
case MMC_IOC_CMD:
mic = data;
- err = mmcsd_ioctl_cmd(part, data, fflag);
+ err = mmcsd_ioctl_cmd(part, mic, fflag);
break;
- case MMC_IOC_CMD_MULTI:
+ case MMC_IOC_MULTI_CMD:
mimc = data;
if (mimc->num_of_cmds == 0)
break;
@@ -973,12 +1032,12 @@ mmcsd_ioctl(struct mmcsd_part *part, u_long cmd, void *data, int fflag)
size = sizeof(*mic) * cnt;
mic = malloc(size, M_TEMP, M_WAITOK);
err = copyin((const void *)mimc->cmds, mic, size);
- if (err != 0)
- break;
- for (i = 0; i < cnt; i++) {
- err = mmcsd_ioctl_cmd(part, &mic[i], fflag);
- if (err != 0)
- break;
+ if (err == 0) {
+ for (i = 0; i < cnt; i++) {
+ err = mmcsd_ioctl_cmd(part, &mic[i], fflag);
+ if (err != 0)
+ break;
+ }
}
free(mic, M_TEMP);
break;
@@ -1007,11 +1066,31 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag)
if (part->ro == TRUE && mic->write_flag != 0)
return (EROFS);
+ /*
+ * We don't need to explicitly lock against the disk(9) half of this
+ * driver as MMCBUS_ACQUIRE_BUS() will serialize us. However, it's
+ * necessary to protect against races with detachment and suspension,
+ * especially since it's required to switch away from RPMB partitions
+ * again after an access (see mmcsd_switch_part()).
+ */
+ MMCSD_IOCTL_LOCK(part);
+ while (part->ioctl != 0) {
+ if (part->ioctl < 0) {
+ MMCSD_IOCTL_UNLOCK(part);
+ return (ENXIO);
+ }
+ msleep(part, &part->ioctl_mtx, 0, "mmcsd IOCTL", 0);
+ }
+ part->ioctl = 1;
+ MMCSD_IOCTL_UNLOCK(part);
+
err = 0;
dp = NULL;
len = mic->blksz * mic->blocks;
- if (len > MMC_IOC_MAX_BYTES)
- return (EOVERFLOW);
+ if (len > MMC_IOC_MAX_BYTES) {
+ err = EOVERFLOW;
+ goto out;
+ }
if (len != 0) {
dp = malloc(len, M_TEMP, M_WAITOK);
err = copyin((void *)(uintptr_t)mic->data_ptr, dp, len);
@@ -1066,7 +1145,7 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag)
err = mmcsd_set_blockcount(sc, mic->blocks,
mic->write_flag & (1 << 31));
if (err != MMC_ERR_NONE)
- goto release;
+ goto switch_back;
}
if (mic->is_acmd != 0)
(void)mmc_wait_for_app_cmd(mmcbr, dev, rca, &cmd, 0);
@@ -1088,6 +1167,7 @@ mmcsd_ioctl_cmd(struct mmcsd_part *part, struct mmc_ioc_cmd *mic, int fflag)
DELAY(1000);
} while (retries-- > 0);
+switch_back:
/* ... and always switch back to the default partition. */
err = mmcsd_switch_part(mmcbr, dev, rca,
EXT_CSD_PART_CONFIG_ACC_DEFAULT);
@@ -1138,6 +1218,10 @@ release:
err = EIO;
out:
+ MMCSD_IOCTL_LOCK(part);
+ part->ioctl = 0;
+ MMCSD_IOCTL_UNLOCK(part);
+ wakeup(part);
if (dp != NULL)
free(dp, M_TEMP);
return (err);
@@ -1191,10 +1275,23 @@ mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part)
sc = device_get_softc(dev);
- if (sc->part_curr == part)
+ if (sc->mode == mode_sd)
return (MMC_ERR_NONE);
- if (sc->mode == mode_sd)
+ /*
+ * According to section "6.2.2 Command restrictions" of the eMMC
+ * specification v5.1, CMD19/CMD21 aren't allowed to be used with
+ * RPMB partitions. So we pause re-tuning along with triggering
+ * it up-front to decrease the likelihood of re-tuning becoming
+ * necessary while accessing an RPMB partition. Consequently, an
+ * RPMB partition should immediately be switched away from again
+ * after an access in order to allow for re-tuning to take place
+ * anew.
+ */
+ if (part == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ MMCBUS_RETUNE_PAUSE(sc->mmcbr, sc->dev, true);
+
+ if (sc->part_curr == part)
return (MMC_ERR_NONE);
value = (sc->ext_csd[EXT_CSD_PART_CONFIG] &
@@ -1202,10 +1299,15 @@ mmcsd_switch_part(device_t bus, device_t dev, uint16_t rca, u_int part)
/* Jump! */
err = mmc_switch(bus, dev, rca, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONFIG, value, sc->part_time, true);
- if (err != MMC_ERR_NONE)
+ if (err != MMC_ERR_NONE) {
+ if (part == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ MMCBUS_RETUNE_UNPAUSE(sc->mmcbr, sc->dev);
return (err);
+ }
sc->ext_csd[EXT_CSD_PART_CONFIG] = value;
+ if (sc->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
+ MMCBUS_RETUNE_UNPAUSE(sc->mmcbr, sc->dev);
sc->part_curr = part;
return (MMC_ERR_NONE);
}
@@ -1217,7 +1319,7 @@ mmcsd_errmsg(int e)
if (e < 0 || e > MMC_ERR_MAX)
return "Bad error code";
- return errmsg[e];
+ return (errmsg[e]);
}
static daddr_t
@@ -1230,7 +1332,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp)
struct mmc_data data;
struct mmcsd_softc *sc;
device_t dev, mmcbr;
- int numblocks, sz;
+ u_int numblocks, sz;
char *vaddr;
sc = part->sc;
@@ -1242,7 +1344,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp)
end = bp->bio_pblkno + (bp->bio_bcount / sz);
while (block < end) {
vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz;
- numblocks = min(end - block, mmc_get_max_data(dev));
+ numblocks = min(end - block, sc->max_data);
memset(&req, 0, sizeof(req));
memset(&cmd, 0, sizeof(cmd));
memset(&stop, 0, sizeof(stop));
@@ -1262,7 +1364,7 @@ mmcsd_rw(struct mmcsd_part *part, struct bio *bp)
cmd.opcode = MMC_WRITE_BLOCK;
}
cmd.arg = block;
- if (!mmc_get_high_cap(dev))
+ if (sc->high_cap == 0)
cmd.arg <<= 9;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
data.data = vaddr;
@@ -1302,7 +1404,7 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
struct mmc_request req;
struct mmcsd_softc *sc;
device_t dev, mmcbr;
- int erase_sector, sz;
+ u_int erase_sector, sz;
sc = part->sc;
dev = sc->dev;
@@ -1317,7 +1419,7 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
if (end >= part->eblock && end < part->eend)
end = part->eend;
/* Safe round to the erase sector boundaries. */
- erase_sector = mmc_get_erase_sector(dev);
+ erase_sector = sc->erase_sector;
start = block + erase_sector - 1; /* Round up. */
start -= start % erase_sector;
stop = end; /* Round down. */
@@ -1329,6 +1431,12 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
return (end);
}
+ /*
+ * Pause re-tuning so it won't interfere with the order of erase
+ * commands. Note that these latter don't use the data lines, so
+ * re-tuning shouldn't actually become necessary during erase.
+ */
+ MMCBUS_RETUNE_PAUSE(mmcbr, dev, false);
/* Set erase start position. */
memset(&req, 0, sizeof(req));
memset(&cmd, 0, sizeof(cmd));
@@ -1339,13 +1447,15 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
else
cmd.opcode = MMC_ERASE_GROUP_START;
cmd.arg = start;
- if (!mmc_get_high_cap(dev))
+ if (sc->high_cap == 0)
cmd.arg <<= 9;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req);
if (req.cmd->error != MMC_ERR_NONE) {
- printf("erase err1: %d\n", req.cmd->error);
- return (block);
+ device_printf(dev, "Setting erase start position failed %d\n",
+ req.cmd->error);
+ block = bp->bio_pblkno;
+ goto unpause;
}
/* Set erase stop position. */
memset(&req, 0, sizeof(req));
@@ -1356,14 +1466,16 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
else
cmd.opcode = MMC_ERASE_GROUP_END;
cmd.arg = stop;
- if (!mmc_get_high_cap(dev))
+ if (sc->high_cap == 0)
cmd.arg <<= 9;
cmd.arg--;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req);
if (req.cmd->error != MMC_ERR_NONE) {
- printf("erase err2: %d\n", req.cmd->error);
- return (block);
+ device_printf(dev, "Setting erase stop position failed %d\n",
+ req.cmd->error);
+ block = bp->bio_pblkno;
+ goto unpause;
}
/* Erase range. */
memset(&req, 0, sizeof(req));
@@ -1374,8 +1486,11 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
MMCBUS_WAIT_FOR_REQUEST(mmcbr, dev, &req);
if (req.cmd->error != MMC_ERR_NONE) {
- printf("erase err3 %d\n", req.cmd->error);
- return (block);
+ device_printf(dev, "erase err3: %d\n", req.cmd->error);
+ device_printf(dev, "Issuing erase command failed %d\n",
+ req.cmd->error);
+ block = bp->bio_pblkno;
+ goto unpause;
}
/* Store one of remaining parts for the next call. */
if (bp->bio_pblkno >= part->eblock || block == start) {
@@ -1385,7 +1500,10 @@ mmcsd_delete(struct mmcsd_part *part, struct bio *bp)
part->eblock = block; /* Predict next backward. */
part->eend = start;
}
- return (end);
+ block = end;
+unpause:
+ MMCBUS_RETUNE_UNPAUSE(mmcbr, dev);
+ return (block);
}
static int
@@ -1446,16 +1564,16 @@ mmcsd_task(void *arg)
mmcbr = sc->mmcbr;
while (1) {
- MMCSD_PART_LOCK(part);
+ MMCSD_DISK_LOCK(part);
do {
if (part->running == 0)
goto out;
bp = bioq_takefirst(&part->bio_queue);
if (bp == NULL)
- msleep(part, &part->part_mtx, PRIBIO,
- "jobqueue", 0);
+ msleep(part, &part->disk_mtx, PRIBIO,
+ "mmcsd disk jobqueue", 0);
} while (bp == NULL);
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
if (bp->bio_cmd != BIO_READ && part->ro) {
bp->bio_error = EROFS;
bp->bio_resid = bp->bio_bcount;
@@ -1496,7 +1614,7 @@ release:
out:
/* tell parent we're done */
part->running = -1;
- MMCSD_PART_UNLOCK(part);
+ MMCSD_DISK_UNLOCK(part);
wakeup(part);
kproc_exit(0);