The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/mmc/mmc_subr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2006 Bernd Walter.  All rights reserved.
    3  * Copyright (c) 2006 M. Warner Losh <imp@FreeBSD.org>
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  *
   25  * Portions of this software may have been developed with reference to
   26  * the SD Simplified Specification.  The following disclaimer may apply:
   27  *
   28  * The following conditions apply to the release of the simplified
   29  * specification ("Simplified Specification") by the SD Card Association and
   30  * the SD Group. The Simplified Specification is a subset of the complete SD
   31  * Specification which is owned by the SD Card Association and the SD
   32  * Group. This Simplified Specification is provided on a non-confidential
   33  * basis subject to the disclaimers below. Any implementation of the
   34  * Simplified Specification may require a license from the SD Card
   35  * Association, SD Group, SD-3C LLC or other third parties.
   36  *
   37  * Disclaimers:
   38  *
   39  * The information contained in the Simplified Specification is presented only
   40  * as a standard specification for SD Cards and SD Host/Ancillary products and
   41  * is provided "AS-IS" without any representations or warranties of any
   42  * kind. No responsibility is assumed by the SD Group, SD-3C LLC or the SD
   43  * Card Association for any damages, any infringements of patents or other
   44  * right of the SD Group, SD-3C LLC, the SD Card Association or any third
   45  * parties, which may result from its use. No license is granted by
   46  * implication, estoppel or otherwise under any patent or other rights of the
   47  * SD Group, SD-3C LLC, the SD Card Association or any third party. Nothing
   48  * herein shall be construed as an obligation by the SD Group, the SD-3C LLC
   49  * or the SD Card Association to disclose or distribute any technical
   50  * information, know-how or other confidential information to any third party.
   51  */
   52 
   53 #include <sys/cdefs.h>
   54 __FBSDID("$FreeBSD$");
   55 
   56 #include <sys/param.h>
   57 #include <sys/systm.h>
   58 #include <sys/kernel.h>
   59 #include <sys/lock.h>
   60 #include <sys/mutex.h>
   61 #include <sys/time.h>
   62 
   63 #include <dev/mmc/bridge.h>
   64 #include <dev/mmc/mmc_private.h>
   65 #include <dev/mmc/mmc_subr.h>
   66 #include <dev/mmc/mmcreg.h>
   67 #include <dev/mmc/mmcbrvar.h>
   68 
   69 #include "mmcbus_if.h"
   70 
   71 #define CMD_RETRIES     3
   72 #define LOG_PPS         5 /* Log no more than 5 errors per second. */
   73 
   74 int
   75 mmc_wait_for_cmd(device_t busdev, device_t dev, struct mmc_command *cmd,
   76     int retries)
   77 {
   78         struct mmc_request mreq;
   79         struct mmc_softc *sc;
   80         int err;
   81 
   82         do {
   83                 memset(&mreq, 0, sizeof(mreq));
   84                 memset(cmd->resp, 0, sizeof(cmd->resp));
   85                 cmd->retries = 0; /* Retries done here, not in hardware. */
   86                 cmd->mrq = &mreq;
   87                 if (cmd->data != NULL)
   88                         cmd->data->mrq = &mreq;
   89                 mreq.cmd = cmd;
   90                 if (MMCBUS_WAIT_FOR_REQUEST(busdev, dev, &mreq) != 0)
   91                         err = MMC_ERR_FAILED;
   92                 else
   93                         err = cmd->error;
   94         } while (err != MMC_ERR_NONE && retries-- > 0);
   95 
   96         if (err != MMC_ERR_NONE && busdev == dev) {
   97                 sc = device_get_softc(busdev);
   98                 if (sc->squelched == 0 && ppsratecheck(&sc->log_time,
   99                     &sc->log_count, LOG_PPS)) {
  100                         device_printf(sc->dev, "CMD%d failed, RESULT: %d\n",
  101                             cmd->opcode, err);
  102                 }
  103         }
  104 
  105         return (err);
  106 }
  107 
  108 int
  109 mmc_wait_for_app_cmd(device_t busdev, device_t dev, uint16_t rca,
  110     struct mmc_command *cmd, int retries)
  111 {
  112         struct mmc_command appcmd;
  113         struct mmc_softc *sc;
  114         int err;
  115 
  116         sc = device_get_softc(busdev);
  117 
  118         /* Squelch error reporting at lower levels, we report below. */
  119         sc->squelched++;
  120         do {
  121                 memset(&appcmd, 0, sizeof(appcmd));
  122                 appcmd.opcode = MMC_APP_CMD;
  123                 appcmd.arg = (uint32_t)rca << 16;
  124                 appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
  125                 if (mmc_wait_for_cmd(busdev, dev, &appcmd, 0) != 0)
  126                         err = MMC_ERR_FAILED;
  127                 else
  128                         err = appcmd.error;
  129                 if (err == MMC_ERR_NONE) {
  130                         if (!(appcmd.resp[0] & R1_APP_CMD))
  131                                 err = MMC_ERR_FAILED;
  132                         else if (mmc_wait_for_cmd(busdev, dev, cmd, 0) != 0)
  133                                 err = MMC_ERR_FAILED;
  134                         else
  135                                 err = cmd->error;
  136                 }
  137         } while (err != MMC_ERR_NONE && retries-- > 0);
  138         sc->squelched--;
  139 
  140         if (err != MMC_ERR_NONE && busdev == dev) {
  141                 if (sc->squelched == 0 && ppsratecheck(&sc->log_time,
  142                     &sc->log_count, LOG_PPS)) {
  143                         device_printf(sc->dev, "ACMD%d failed, RESULT: %d\n",
  144                             cmd->opcode, err);
  145                 }
  146         }
  147 
  148         return (err);
  149 }
  150 
  151 int
  152 mmc_switch(device_t busdev, device_t dev, uint16_t rca, uint8_t set,
  153     uint8_t index, uint8_t value, u_int timeout, bool status)
  154 {
  155         struct mmc_command cmd;
  156         struct mmc_softc *sc;
  157         int err;
  158 
  159         KASSERT(timeout != 0, ("%s: no timeout", __func__));
  160 
  161         sc = device_get_softc(busdev);
  162 
  163         memset(&cmd, 0, sizeof(cmd));
  164         cmd.opcode = MMC_SWITCH_FUNC;
  165         cmd.arg = (MMC_SWITCH_FUNC_WR << 24) | (index << 16) | (value << 8) |
  166             set;
  167         /*
  168          * If the hardware supports busy detection but the switch timeout
  169          * exceeds the maximum host timeout, use a R1 instead of a R1B
  170          * response in order to keep the hardware from timing out.
  171          */
  172         if (mmcbr_get_caps(busdev) & MMC_CAP_WAIT_WHILE_BUSY &&
  173             timeout > mmcbr_get_max_busy_timeout(busdev))
  174                 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
  175         else
  176                 cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
  177         /*
  178          * Pause re-tuning so it won't interfere with the busy state and also
  179          * so that the result of CMD13 will always refer to switching rather
  180          * than to a tuning command that may have snuck in between.
  181          */
  182         sc->retune_paused++;
  183         err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES);
  184         if (err != MMC_ERR_NONE || status == false)
  185                 goto out;
  186         err = mmc_switch_status(busdev, dev, rca, timeout);
  187 out:
  188         sc->retune_paused--;
  189         return (err);
  190 }
  191 
  192 int
  193 mmc_switch_status(device_t busdev, device_t dev, uint16_t rca, u_int timeout)
  194 {
  195         struct timeval cur, end;
  196         int err, crc_timeout;
  197         uint32_t status;
  198 
  199         KASSERT(timeout != 0, ("%s: no timeout", __func__));
  200 
  201         /*
  202          * Note that when using a R1B response in mmc_switch(), bridges of
  203          * type MMC_CAP_WAIT_WHILE_BUSY will issue mmc_send_status() only
  204          * once and then exit the loop.
  205          */
  206         end.tv_sec = end.tv_usec = 0;
  207         for (;;) {
  208                 crc_timeout=0;
  209                 do {
  210                         /*
  211                          * CRC errors indicate that the command wasn't accepted
  212                          * and executed due to a communications error. Retry
  213                          * CRC errors a couple of times to cope with transient
  214                          * failures.
  215                          *
  216                          * This is required for some cheap laptops to boot.
  217                          */
  218                         err = mmc_send_status(busdev, dev, rca, &status);
  219                         crc_timeout++;
  220                 } while (err == MMC_ERR_BADCRC && crc_timeout < 10);
  221                 if (err != MMC_ERR_NONE)
  222                         break;
  223                 if (R1_CURRENT_STATE(status) == R1_STATE_TRAN)
  224                         break;
  225                 getmicrouptime(&cur);
  226                 if (end.tv_sec == 0 && end.tv_usec == 0) {
  227                         end.tv_usec = timeout;
  228                         timevaladd(&end, &cur);
  229                 }
  230                 if (timevalcmp(&cur, &end, >)) {
  231                         err = MMC_ERR_TIMEOUT;
  232                         break;
  233                 }
  234         }
  235         if (err == MMC_ERR_NONE && (status & R1_SWITCH_ERROR) != 0)
  236                 return (MMC_ERR_FAILED);
  237         return (err);
  238 }
  239 
  240 int
  241 mmc_send_ext_csd(device_t busdev, device_t dev, uint8_t *rawextcsd)
  242 {
  243         struct mmc_command cmd;
  244         struct mmc_data data;
  245         int err;
  246 
  247         memset(&cmd, 0, sizeof(cmd));
  248         memset(&data, 0, sizeof(data));
  249 
  250         memset(rawextcsd, 0, MMC_EXTCSD_SIZE);
  251         cmd.opcode = MMC_SEND_EXT_CSD;
  252         cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
  253         cmd.data = &data;
  254 
  255         data.data = rawextcsd;
  256         data.len = MMC_EXTCSD_SIZE;
  257         data.flags = MMC_DATA_READ;
  258 
  259         err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES);
  260         return (err);
  261 }
  262 
  263 int
  264 mmc_send_status(device_t busdev, device_t dev, uint16_t rca, uint32_t *status)
  265 {
  266         struct mmc_command cmd;
  267         int err;
  268 
  269         memset(&cmd, 0, sizeof(cmd));
  270         cmd.opcode = MMC_SEND_STATUS;
  271         cmd.arg = (uint32_t)rca << 16;
  272         cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
  273         err = mmc_wait_for_cmd(busdev, dev, &cmd, CMD_RETRIES);
  274         *status = cmd.resp[0];
  275         return (err);
  276 }

Cache object: 605c079cb95f3c7b9db075af2d954c03


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.