aboutsummaryrefslogtreecommitdiff
path: root/sys/cam/mmc/mmc_xpt.c
diff options
context:
space:
mode:
authorEmmanuel Vadot <manu@FreeBSD.org>2021-04-29 15:48:49 +0000
committerEmmanuel Vadot <manu@FreeBSD.org>2021-05-21 15:34:05 +0000
commitaf2253f61c43a7608cdf6995701c1dc361320064 (patch)
tree7a71070876a9ede5fbbd34c4eb53c66753a34e72 /sys/cam/mmc/mmc_xpt.c
parent788401188f950001cd9796cdcea9a7e5f92050ab (diff)
downloadsrc-af2253f61c43a7608cdf6995701c1dc361320064.tar.gz
src-af2253f61c43a7608cdf6995701c1dc361320064.zip
mmccam: Add two new XPT for MMC and use them in mmc_sim and sdhci
For the discovery phase of SD/eMMC we need to do some transaction in a async way. The classic CAM XPT_{GET,SET}_TRAN_SETTING cannot be used in a async way. This also allow us to split the discovery phase into a more complete state machine and we don't mtx_sleep with a random number to wait for completion of the tasks. For mmc_sim we now do the SET_TRAN_SETTING in a taskqueue so we can call the needed function for regulators/clocks without the cam lock(s). This part is still needed to be done for sdhci. We also now save the host OCR in the discovery phase as it wasn't done before and only worked because the same ccb was reused. Reviewed by: imp, kibab, bz Differential Revision: https://reviews.freebsd.org/D30038
Diffstat (limited to 'sys/cam/mmc/mmc_xpt.c')
-rw-r--r--sys/cam/mmc/mmc_xpt.c109
1 files changed, 83 insertions, 26 deletions
diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c
index 847fd7cdb412..6b2fecdab0fb 100644
--- a/sys/cam/mmc/mmc_xpt.c
+++ b/sys/cam/mmc/mmc_xpt.c
@@ -90,6 +90,12 @@ static void mmc_proto_debug_out(union ccb *ccb);
typedef enum {
PROBE_RESET,
PROBE_IDENTIFY,
+ PROBE_POWER_OFF,
+ PROBE_GET_HOST_OCR,
+ PROBE_RESET_BUS,
+ PROBE_SET_ID_FREQ,
+ PROBE_SET_CS,
+ PROBE_GO_IDLE_STATE,
PROBE_SDIO_RESET,
PROBE_SEND_IF_COND,
PROBE_SDIO_INIT,
@@ -107,6 +113,12 @@ typedef enum {
static char *probe_action_text[] = {
"PROBE_RESET",
"PROBE_IDENTIFY",
+ "PROBE_POWER_OFF",
+ "PROBE_GET_HOST_OCR",
+ "PROBE_RESET_BUS",
+ "PROBE_SET_ID_FREQ",
+ "PROBE_SET_CS",
+ "PROBE_GO_IDLE_STATE",
"PROBE_SDIO_RESET",
"PROBE_SEND_IF_COND",
"PROBE_SDIO_INIT",
@@ -165,6 +177,7 @@ typedef struct {
probe_action action;
int restart;
union ccb saved_ccb;
+ uint32_t host_ocr;
uint32_t flags;
#define PROBE_FLAG_ACMD_SENT 0x1 /* CMD55 is sent, card expects ACMD */
#define PROBE_FLAG_HOST_CAN_DO_18V 0x2 /* Host can do 1.8V signaling */
@@ -584,7 +597,6 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
mmcprobe_softc *softc;
struct cam_path *path;
struct ccb_mmcio *mmcio;
- struct mtx *p_mtx = cam_periph_mtx(periph);
struct ccb_trans_settings_mmc *cts;
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("mmcprobe_start\n"));
@@ -612,25 +624,29 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
case PROBE_IDENTIFY:
xpt_path_inq(&start_ccb->cpi, periph->path);
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_IDENTIFY\n"));
- init_standard_ccb(start_ccb, XPT_GET_TRAN_SETTINGS);
- xpt_action(start_ccb);
- if (cts->ios.power_mode != power_off) {
- init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
- cts->ios.power_mode = power_off;
- cts->ios_valid = MMC_PM;
- xpt_action(start_ccb);
- mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
- }
- /* mmc_power_up */
- /* Get the host OCR */
- init_standard_ccb(start_ccb, XPT_GET_TRAN_SETTINGS);
- xpt_action(start_ccb);
+ init_standard_ccb(start_ccb, XPT_MMC_GET_TRAN_SETTINGS);
+ break;
+
+ case PROBE_POWER_OFF:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("power off the card\n"));
+ init_standard_ccb(start_ccb, XPT_MMC_SET_TRAN_SETTINGS);
+ cts->ios.power_mode = power_off;
+ cts->ios_valid = MMC_PM;
+ break;
+
+ case PROBE_GET_HOST_OCR:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("get the host ocr\n"));
+ init_standard_ccb(start_ccb, XPT_MMC_GET_TRAN_SETTINGS);
+ break;
+ case PROBE_RESET_BUS:
+ {
uint32_t host_caps = cts->host_caps;
if (host_caps & MMC_CAP_SIGNALING_180)
softc->flags |= PROBE_FLAG_HOST_CAN_DO_18V;
- uint32_t hv = mmc_highest_voltage(cts->host_ocr);
- init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ uint32_t hv = mmc_highest_voltage(softc->host_ocr);
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("reseting the bus\n"));
+ init_standard_ccb(start_ccb, XPT_MMC_SET_TRAN_SETTINGS);
cts->ios.vdd = hv;
cts->ios.bus_mode = opendrain;
cts->ios.chip_select = cs_dontcare;
@@ -639,25 +655,26 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
cts->ios.clock = 0;
cts->ios_valid = MMC_VDD | MMC_PM | MMC_BM |
MMC_CS | MMC_BW | MMC_CLK;
- xpt_action(start_ccb);
- mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
+ break;
+ }
- init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ case PROBE_SET_ID_FREQ:
+ CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("setting the ID freq\n"));
+ init_standard_ccb(start_ccb, XPT_MMC_SET_TRAN_SETTINGS);
cts->ios.power_mode = power_on;
cts->ios.clock = CARD_ID_FREQUENCY;
cts->ios.timing = bus_timing_normal;
cts->ios_valid = MMC_PM | MMC_CLK | MMC_BT;
- xpt_action(start_ccb);
- mtx_sleep(periph, p_mtx, 0, "mmcios", 100);
- /* End for mmc_power_on */
+ break;
+ case PROBE_SET_CS:
/* Begin mmc_idle_cards() */
- init_standard_ccb(start_ccb, XPT_SET_TRAN_SETTINGS);
+ init_standard_ccb(start_ccb, XPT_MMC_SET_TRAN_SETTINGS);
cts->ios.chip_select = cs_high;
cts->ios_valid = MMC_CS;
- xpt_action(start_ccb);
- mtx_sleep(periph, p_mtx, 0, "mmcios", 1);
+ break;
+ case PROBE_GO_IDLE_STATE:
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Send first XPT_MMC_IO\n"));
init_standard_ccb(start_ccb, XPT_MMC_IO);
mmcio->cmd.opcode = MMC_GO_IDLE_STATE; /* CMD 0 */
@@ -668,6 +685,7 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
/* XXX Reset I/O portion as well */
break;
+
case PROBE_SDIO_RESET:
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE,
("Start with PROBE_SDIO_RESET\n"));
@@ -805,7 +823,7 @@ mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb)
struct ccb_mmcio *mmcio;
u_int32_t priority;
- CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("mmcprobe_done\n"));
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("mmcprobe_done\n"));
softc = (mmcprobe_softc *)periph->softc;
path = done_ccb->ccb_h.path;
priority = done_ccb->ccb_h.pinfo.priority;
@@ -816,6 +834,45 @@ mmcprobe_done(struct cam_periph *periph, union ccb *done_ccb)
case PROBE_IDENTIFY:
{
CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_RESET\n"));
+ PROBE_SET_ACTION(softc, PROBE_POWER_OFF);
+ break;
+ }
+ case PROBE_POWER_OFF:
+ {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_POWER_OFF\n"));
+ PROBE_SET_ACTION(softc, PROBE_GET_HOST_OCR);
+ break;
+ }
+ case PROBE_GET_HOST_OCR:
+ {
+ struct ccb_trans_settings_mmc *cts;
+ cts = &done_ccb->cts.proto_specific.mmc;
+ softc->host_ocr = cts->host_ocr;
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_GET_HOST_OCR (Got OCR=%x\n", softc->host_ocr));
+ PROBE_SET_ACTION(softc, PROBE_RESET_BUS);
+ break;
+ }
+ case PROBE_RESET_BUS:
+ {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_RESET_BUS\n"));
+ PROBE_SET_ACTION(softc, PROBE_SET_ID_FREQ);
+ break;
+ }
+ case PROBE_SET_ID_FREQ:
+ {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_SET_ID_FREQ\n"));
+ PROBE_SET_ACTION(softc, PROBE_SET_CS);
+ break;
+ }
+ case PROBE_SET_CS:
+ {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_SET_CS\n"));
+ PROBE_SET_ACTION(softc, PROBE_GO_IDLE_STATE);
+ break;
+ }
+ case PROBE_GO_IDLE_STATE:
+ {
+ CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("done with PROBE_GO_IDLE_STATE\n"));
mmcio = &done_ccb->mmcio;
err = mmcio->cmd.error;