Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 22 Jul 2021 17:16:58 GMT
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 41607b5ed446 - stable/13 - mmccam: Add two new XPT for MMC and use them in mmc_sim and sdhci
Message-ID:  <202107221716.16MHGwb5091286@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by manu:

URL: https://cgit.FreeBSD.org/src/commit/?id=41607b5ed446415c225dd7a9c307dca1fe0fd96e

commit 41607b5ed446415c225dd7a9c307dca1fe0fd96e
Author:     Emmanuel Vadot <manu@FreeBSD.org>
AuthorDate: 2021-04-29 15:48:49 +0000
Commit:     Emmanuel Vadot <manu@FreeBSD.org>
CommitDate: 2021-07-22 17:09:38 +0000

    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
    
    (cherry picked from commit af2253f61c43a7608cdf6995701c1dc361320064)
---
 sys/cam/cam_ccb.h     |   3 ++
 sys/cam/cam_xpt.c     |   2 +
 sys/cam/mmc/mmc_sim.c |  45 ++++++++++++++++++++-
 sys/cam/mmc/mmc_sim.h |   4 ++
 sys/cam/mmc/mmc_xpt.c | 109 ++++++++++++++++++++++++++++++++++++++------------
 sys/dev/sdhci/sdhci.c |   2 +
 6 files changed, 137 insertions(+), 28 deletions(-)

diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h
index 221b24a7c187..b853e3165ba3 100644
--- a/sys/cam/cam_ccb.h
+++ b/sys/cam/cam_ccb.h
@@ -247,6 +247,9 @@ typedef enum {
 	XPT_REPROBE_LUN		= 0x38 | XPT_FC_QUEUED | XPT_FC_USER_CCB,
 				/* Query device capacity and notify GEOM */
 
+	XPT_MMC_SET_TRAN_SETTINGS = 0x40 | XPT_FC_DEV_QUEUED,
+	XPT_MMC_GET_TRAN_SETTINGS = 0x41 | XPT_FC_DEV_QUEUED,
+
 /* Vendor Unique codes: 0x80->0x8F */
 	XPT_VUNIQUE		= 0x80
 } xpt_opcode;
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index ba01e741c5a7..e3b43e70dc61 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -2689,6 +2689,8 @@ xpt_action_default(union ccb *start_ccb)
 	case XPT_NVME_IO:
 	case XPT_NVME_ADMIN:
 	case XPT_MMC_IO:
+	case XPT_MMC_GET_TRAN_SETTINGS:
+	case XPT_MMC_SET_TRAN_SETTINGS:
 	case XPT_RESET_DEV:
 	case XPT_ENG_EXEC:
 	case XPT_SMP_IO:
diff --git a/sys/cam/mmc/mmc_sim.c b/sys/cam/mmc/mmc_sim.c
index 03269a0b3d4d..1500e3f6f1cd 100644
--- a/sys/cam/mmc/mmc_sim.c
+++ b/sys/cam/mmc/mmc_sim.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org>
+ * Copyright (c) 2020-2021 Emmanuel Vadot <manu@FreeBSD.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,6 +50,30 @@ mmc_cam_default_poll(struct cam_sim *sim)
 	return;
 }
 
+static void
+mmc_sim_task(void *arg, int pending)
+{
+	struct mmc_sim *mmc_sim;
+	struct ccb_trans_settings *cts;
+	int rv;
+
+	mmc_sim = arg;
+
+	if (mmc_sim->ccb == NULL)
+		return;
+
+	cts = &mmc_sim->ccb->cts;
+	rv = MMC_SIM_SET_TRAN_SETTINGS(mmc_sim->dev, &cts->proto_specific.mmc);
+	if (rv != 0)
+		mmc_sim->ccb->ccb_h.status = CAM_REQ_INVALID;
+	else
+		mmc_sim->ccb->ccb_h.status = CAM_REQ_CMP;
+
+	xpt_done(mmc_sim->ccb);
+	mmc_sim->ccb = NULL;
+}
+
+
 static void
 mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb)
 {
@@ -67,6 +91,12 @@ mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb)
 
 	mtx_assert(&mmc_sim->mtx, MA_OWNED);
 
+	if (mmc_sim->ccb != NULL) {
+		ccb->ccb_h.status = CAM_BUSY;
+		xpt_done(ccb);
+		return;
+	}
+
 	switch (ccb->ccb_h.func_code) {
 	case XPT_PATH_INQ:
 		rv = MMC_SIM_GET_TRAN_SETTINGS(mmc_sim->dev, &mmc);
@@ -78,6 +108,7 @@ mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb)
 		}
 		break;
 	case XPT_GET_TRAN_SETTINGS:
+	case XPT_MMC_GET_TRAN_SETTINGS:
 	{
 		struct ccb_trans_settings *cts = &ccb->cts;
 
@@ -105,6 +136,15 @@ mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb)
 			ccb->ccb_h.status = CAM_REQ_CMP;
 		break;
 	}
+	case XPT_MMC_SET_TRAN_SETTINGS:
+	{
+		ccb->ccb_h.status = CAM_SIM_QUEUED;
+		mmc_sim->ccb = ccb;
+		taskqueue_enqueue(taskqueue_thread, &mmc_sim->sim_task);
+		return;
+		/* NOTREACHED */
+		break;
+	}
 	case XPT_RESET_BUS:
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		break;
@@ -112,7 +152,7 @@ mmc_cam_sim_default_action(struct cam_sim *sim, union ccb *ccb)
 	{
 		rv = MMC_SIM_CAM_REQUEST(mmc_sim->dev, ccb);
 		if (rv != 0)
-			ccb->ccb_h.status = CAM_REQ_INPROG;
+			ccb->ccb_h.status = CAM_SIM_QUEUED;
 		else
 			ccb->ccb_h.status = CAM_REQ_INVALID;
 		return;
@@ -163,6 +203,7 @@ mmc_cam_sim_alloc(device_t dev, const char *name, struct mmc_sim *mmc_sim)
 	}
 
 	mtx_unlock(&mmc_sim->mtx);
+	TASK_INIT(&mmc_sim->sim_task, 0, mmc_sim_task, mmc_sim);
 
 	return (0);
 
diff --git a/sys/cam/mmc/mmc_sim.h b/sys/cam/mmc/mmc_sim.h
index 629144656e51..2b1159a9758e 100644
--- a/sys/cam/mmc/mmc_sim.h
+++ b/sys/cam/mmc/mmc_sim.h
@@ -28,12 +28,16 @@
 #ifndef __MMC_SIM_H__
 #define	__MMC_SIM_H__
 
+#include <sys/taskqueue.h>
+
 struct mmc_sim {
 	struct mmc_cam_sim_softc	*sc;
 	struct mtx			mtx;
 	struct cam_devq			*devq;
 	struct cam_sim			*sim;
 	device_t			dev;
+	struct task			sim_task;
+	union ccb			*ccb;
 };
 
 int mmc_cam_sim_alloc(device_t dev, const char *name, struct mmc_sim *mmc_sim);
diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c
index aa552ecb3280..f050f9a5ccb6 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 */
@@ -583,7 +596,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"));
@@ -611,25 +623,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;
@@ -638,25 +654,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 */
@@ -667,6 +684,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"));
@@ -804,7 +822,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;
@@ -815,6 +833,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;
 
diff --git a/sys/dev/sdhci/sdhci.c b/sys/dev/sdhci/sdhci.c
index 91474cabd2d3..0441320d4b35 100644
--- a/sys/dev/sdhci/sdhci.c
+++ b/sys/dev/sdhci/sdhci.c
@@ -2537,6 +2537,7 @@ sdhci_cam_action(struct cam_sim *sim, union ccb *ccb)
 		mmc_path_inq(&ccb->cpi, "Deglitch Networks", sim, maxphys);
 		break;
 
+	case XPT_MMC_GET_TRAN_SETTINGS:
 	case XPT_GET_TRAN_SETTINGS:
 	{
 		struct ccb_trans_settings *cts = &ccb->cts;
@@ -2571,6 +2572,7 @@ sdhci_cam_action(struct cam_sim *sim, union ccb *ccb)
 		ccb->ccb_h.status = CAM_REQ_CMP;
 		break;
 	}
+	case XPT_MMC_SET_TRAN_SETTINGS:
 	case XPT_SET_TRAN_SETTINGS:
 		if (sdhci_debug > 1)
 			slot_printf(slot, "Got XPT_SET_TRAN_SETTINGS\n");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202107221716.16MHGwb5091286>