From owner-svn-src-all@freebsd.org Tue Jun 5 11:03:25 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 3D999FE8172; Tue, 5 Jun 2018 11:03:25 +0000 (UTC) (envelope-from kibab@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id E4F637041A; Tue, 5 Jun 2018 11:03:24 +0000 (UTC) (envelope-from kibab@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id C22E01BA1C; Tue, 5 Jun 2018 11:03:24 +0000 (UTC) (envelope-from kibab@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w55B3Oe8001550; Tue, 5 Jun 2018 11:03:24 GMT (envelope-from kibab@FreeBSD.org) Received: (from kibab@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w55B3OnS001549; Tue, 5 Jun 2018 11:03:24 GMT (envelope-from kibab@FreeBSD.org) Message-Id: <201806051103.w55B3OnS001549@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kibab set sender to kibab@FreeBSD.org using -f From: Ilya Bakulin Date: Tue, 5 Jun 2018 11:03:24 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r334651 - head/sys/cam/mmc X-SVN-Group: head X-SVN-Commit-Author: kibab X-SVN-Commit-Paths: head/sys/cam/mmc X-SVN-Commit-Revision: 334651 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 05 Jun 2018 11:03:25 -0000 Author: kibab Date: Tue Jun 5 11:03:24 2018 New Revision: 334651 URL: https://svnweb.freebsd.org/changeset/base/334651 Log: Enable high-speed on the card before increasing frequency on the controller Increasing operating frequency without telling card to switch to high-speed mode first upsets some cards and generates CRC errors. While here, deselect / reselect cards after CMD6 and SCR fetch, as in original code. Approved by: imp (mentor) Differential Revision: https://reviews.freebsd.org/D15568 Modified: head/sys/cam/mmc/mmc_da.c Modified: head/sys/cam/mmc/mmc_da.c ============================================================================== --- head/sys/cam/mmc/mmc_da.c Tue Jun 5 09:52:38 2018 (r334650) +++ head/sys/cam/mmc/mmc_da.c Tue Jun 5 11:03:24 2018 (r334651) @@ -171,7 +171,7 @@ static void sdda_start_init_task(void *context, int pe static void sdda_process_mmc_partitions(struct cam_periph *periph, union ccb *start_ccb); static uint32_t sdda_get_host_caps(struct cam_periph *periph, union ccb *ccb); static void sdda_init_switch_part(struct cam_periph *periph, union ccb *start_ccb, u_int part); - +static int mmc_select_card(struct cam_periph *periph, union ccb *ccb, uint32_t rca); static inline uint32_t mmc_get_sector_size(struct cam_periph *periph) {return MMC_SECTOR_SIZE;} /* TODO: actually issue GET_TRAN_SETTINGS to get R/O status */ @@ -901,6 +901,38 @@ mmc_switch_fill_mmcio(union ccb *ccb, } static int +mmc_select_card(struct cam_periph *periph, union ccb *ccb, uint32_t rca) +{ + int flags; + + flags = (rca ? MMC_RSP_R1B : MMC_RSP_NONE) | MMC_CMD_AC; + cam_fill_mmcio(&ccb->mmcio, + /*retries*/ 0, + /*cbfcnp*/ NULL, + /*flags*/ CAM_DIR_IN, + /*mmc_opcode*/ MMC_SELECT_CARD, + /*mmc_arg*/ rca << 16, + /*mmc_flags*/ flags, + /*mmc_data*/ NULL, + /*timeout*/ 0); + + cam_periph_runccb(ccb, sddaerror, CAM_FLAG_NONE, /*sense_flags*/0, NULL); + + if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)) { + if (ccb->mmcio.cmd.error != 0) { + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_PERIPH, + ("%s: MMC_SELECT command failed", __func__)); + return EIO; + } + return 0; /* Normal return */ + } else { + CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_PERIPH, + ("%s: CAM request failed\n", __func__)); + return EIO; + } +} + +static int mmc_switch(struct cam_periph *periph, union ccb *ccb, uint8_t set, uint8_t index, uint8_t value, u_int timeout) { @@ -953,18 +985,24 @@ mmc_sd_switch(struct cam_periph *periph, union ccb *cc uint8_t *res) { struct mmc_data mmc_d; + uint32_t arg; memset(res, 0, 64); mmc_d.len = 64; mmc_d.data = res; mmc_d.flags = MMC_DATA_READ; + arg = mode << 31; /* 0 - check, 1 - set */ + arg |= 0x00FFFFFF; + arg &= ~(0xF << (grp * 4)); + arg |= value << (grp * 4); + cam_fill_mmcio(&ccb->mmcio, /*retries*/ 0, /*cbfcnp*/ NULL, /*flags*/ CAM_DIR_IN, /*mmc_opcode*/ SD_SWITCH_FUNC, - /*mmc_arg*/ mode << 31, + /*mmc_arg*/ arg, /*mmc_flags*/ MMC_RSP_R1 | MMC_CMD_ADTC, /*mmc_data*/ &mmc_d, /*timeout*/ 0); @@ -1273,6 +1311,19 @@ sdda_start_init(void *context, union ccb *start_ccb) CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Card supports HS\n")); softc->card_f_max = SD_HS_MAX; } + + /* + * We deselect then reselect the card here. Some cards + * become unselected and timeout with the above two + * commands, although the state tables / diagrams in the + * standard suggest they go back to the transfer state. + * Other cards don't become deselected, and if we + * attempt to blindly re-select them, we get timeout + * errors from some controllers. So we deselect then + * reselect to handle all situations. + */ + mmc_select_card(periph, start_ccb, 0); + mmc_select_card(periph, start_ccb, get_rca(periph)); } else { CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Not trying the switch\n")); goto finish_hs_tests; @@ -1293,6 +1344,15 @@ finish_hs_tests: f_max = min(host_f_max, softc->card_f_max); CAM_DEBUG(periph->path, CAM_DEBUG_PERIPH, ("Set SD freq to %d MHz (min out of host f=%d MHz and card f=%d MHz)\n", f_max / 1000000, host_f_max / 1000000, softc->card_f_max / 1000000)); + /* Enable high-speed timing on the card */ + if (f_max > 25000000) { + err = mmc_set_timing(periph, start_ccb, bus_timing_hs); + if (err != MMC_ERR_NONE) { + CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("Cannot switch card to high-speed mode")); + f_max = 25000000; + } + } + /* Set frequency on the controller */ start_ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS; start_ccb->ccb_h.flags = CAM_DIR_NONE; start_ccb->ccb_h.retry_count = 0; @@ -1326,12 +1386,6 @@ finish_hs_tests: bus_width_str(max_host_bus_width), bus_width_str(max_card_bus_width))); sdda_set_bus_width(periph, start_ccb, desired_bus_width); - - if (f_max > 25000000) { - err = mmc_set_timing(periph, start_ccb, bus_timing_hs); - if (err != MMC_ERR_NONE) - CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("Cannot switch card to high-speed mode")); - } softc->state = SDDA_STATE_NORMAL;