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/altera/sdcard/altera_sdcard_io.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2012 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * This software was developed by SRI International and the University of
    8  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
    9  * ("CTSRD"), as part of the DARPA CRASH research programme.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/bus.h>
   38 #include <sys/condvar.h>
   39 #include <sys/conf.h>
   40 #include <sys/bio.h>
   41 #include <sys/endian.h>
   42 #include <sys/kernel.h>
   43 #include <sys/lock.h>
   44 #include <sys/malloc.h>
   45 #include <sys/module.h>
   46 #include <sys/mutex.h>
   47 #include <sys/rman.h>
   48 #include <sys/systm.h>
   49 #include <sys/taskqueue.h>
   50 
   51 #include <machine/bus.h>
   52 #include <machine/resource.h>
   53 
   54 #include <geom/geom_disk.h>
   55 
   56 #include <dev/altera/sdcard/altera_sdcard.h>
   57 
   58 int altera_sdcard_ignore_crc_errors = 1;
   59 int altera_sdcard_verify_rxtx_writes = 1;
   60 
   61 /*
   62  * Low-level I/O routines for the Altera SD Card University IP Core driver.
   63  *
   64  * XXXRW: Throughout, it is assumed that the IP Core handles multibyte
   65  * registers as little endian, as is the case for other Altera IP cores.
   66  * However, the specification makes no reference to endianness, so this
   67  * assumption might not always be correct.
   68  */
   69 uint16_t
   70 altera_sdcard_read_asr(struct altera_sdcard_softc *sc)
   71 {
   72 
   73         return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_ASR)));
   74 }
   75 
   76 static int
   77 altera_sdcard_process_csd0(struct altera_sdcard_softc *sc)
   78 {
   79         uint64_t c_size, c_size_mult, read_bl_len;
   80         uint8_t byte0, byte1, byte2;
   81 
   82         ALTERA_SDCARD_LOCK_ASSERT(sc);
   83 
   84         /*-
   85          * Compute card capacity per SD Card interface description as follows:
   86          *
   87          *   Memory capacity = BLOCKNR * BLOCK_LEN
   88          *
   89          * Where:
   90          *
   91          *   BLOCKNR = (C_SIZE + 1) * MULT
   92          *   MULT = 2^(C_SIZE_MULT+2)
   93          *   BLOCK_LEN = 2^READ_BL_LEN
   94          */
   95         read_bl_len = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE];
   96         read_bl_len &= ALTERA_SDCARD_CSD_READ_BL_LEN_MASK;
   97 
   98         byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE0];
   99         byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MASK0;
  100         byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE1];
  101         byte2 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE2];
  102         byte2 &= ALTERA_SDCARD_CSD_C_SIZE_MASK2;
  103         c_size = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0) |
  104             (byte1 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1) |
  105             (byte2 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2);
  106 
  107         byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
  108         byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
  109         byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
  110         byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
  111         c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
  112             (byte1 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
  113 
  114         /*
  115          * If we're just getting back zero's, mark the card as bad, even
  116          * though it could just mean a Very Small Disk Indeed.
  117          */
  118         if (c_size == 0 && c_size_mult == 0 && read_bl_len == 0) {
  119                 device_printf(sc->as_dev, "Ignored zero-size card\n");
  120                 return (ENXIO);
  121         }
  122         sc->as_mediasize = (c_size + 1) * (1 << (c_size_mult + 2)) *
  123             (1 << read_bl_len);
  124         return (0);
  125 }
  126 
  127 int
  128 altera_sdcard_read_csd(struct altera_sdcard_softc *sc)
  129 {
  130         uint8_t csd_structure;
  131         int error;
  132 
  133         ALTERA_SDCARD_LOCK_ASSERT(sc);
  134 
  135         /*
  136          * XXXRW: Assume for now that when the SD Card IP Core negotiates
  137          * voltage/speed/etc, it must use the CSD register, and therefore
  138          * populates the SD Card IP Core's cache of the register value.  This
  139          * means that we can read it without issuing further SD Card commands.
  140          * If this assumption proves false, we will (a) get back garbage and
  141          * (b) need to add additional states in the driver state machine in
  142          * order to query card properties before I/O can start.
  143          *
  144          * XXXRW: Treating this as an array of bytes, so no byte swapping --
  145          * is that a safe assumption?
  146          */
  147         KASSERT(((uintptr_t)&sc->as_csd.csd_data) % 2 == 0,
  148             ("%s: CSD buffer unaligned", __func__));
  149         bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_CSD,
  150             (uint16_t *)sc->as_csd.csd_data, sizeof(sc->as_csd) / 2);
  151 
  152         /*
  153          * Interpret the loaded CSD, extracting certain fields and copying
  154          * them into the softc for easy software access.
  155          *
  156          * Currently, we support only CSD Version 1.0.  If we detect a newer
  157          * version, suppress card detection.
  158          */
  159         csd_structure = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_STRUCTURE_BYTE];
  160         csd_structure &= ALTERA_SDCARD_CSD_STRUCTURE_MASK;
  161         csd_structure >>= ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT;
  162         sc->as_csd_structure = csd_structure;
  163 
  164         /*
  165          * Interpret the CSD field based on its version.  Extract fields,
  166          * especially mediasize.
  167          *
  168          * XXXRW: Desirable to support further CSD versions here.
  169          */
  170         switch (sc->as_csd_structure) {
  171         case 0:
  172                 error = altera_sdcard_process_csd0(sc);
  173                 if (error)
  174                         return (error);
  175                 break;
  176 
  177         default:
  178                 device_printf(sc->as_dev,
  179                     "Ignored disk with unsupported CSD structure (%d)\n",
  180                     sc->as_csd_structure);
  181                 return (ENXIO);
  182         }
  183         return (0);
  184 }
  185 
  186 /*
  187  * XXXRW: The Altera IP Core specification indicates that RR1 is a 16-bit
  188  * register, but all bits it identifies are >16 bit.  Most likely, RR1 is a
  189  * 32-bit register?
  190  */
  191 static uint16_t
  192 altera_sdcard_read_rr1(struct altera_sdcard_softc *sc)
  193 {
  194 
  195         return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_RR1)));
  196 }
  197 
  198 static void
  199 altera_sdcard_write_cmd_arg(struct altera_sdcard_softc *sc, uint32_t cmd_arg)
  200 {
  201 
  202         bus_write_4(sc->as_res, ALTERA_SDCARD_OFF_CMD_ARG, htole32(cmd_arg));
  203 }
  204 
  205 static void
  206 altera_sdcard_write_cmd(struct altera_sdcard_softc *sc, uint16_t cmd)
  207 {
  208 
  209         bus_write_2(sc->as_res, ALTERA_SDCARD_OFF_CMD, htole16(cmd));
  210 }
  211 
  212 static void
  213 altera_sdcard_read_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
  214     size_t len)
  215 {
  216 
  217         KASSERT((uintptr_t)data % 2 == 0,
  218             ("%s: unaligned data %p", __func__, data));
  219         KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
  220             ("%s: invalid length %ju", __func__, len));
  221 
  222         bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
  223             (uint16_t *)data, len / 2);
  224 }
  225 
  226 static void
  227 altera_sdcard_write_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
  228     size_t len)
  229 {
  230         u_int corrections, differences, i, retry_counter;
  231         uint16_t d, v;
  232 
  233         KASSERT((uintptr_t)data % 2 == 0,
  234             ("%s: unaligned data %p", __func__, data));
  235         KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
  236             ("%s: invalid length %ju", __func__, len));
  237 
  238         retry_counter = 0;
  239         do {
  240                 bus_write_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
  241                     (uint16_t *)data, len / 2);
  242 
  243                 /*
  244                  * XXXRW: Due to a possible hardware bug, the above call to
  245                  * bus_write_region_2() might not succeed.  If the workaround
  246                  * is enabled, verify each write and retry until it succeeds.
  247                  *
  248                  * XXXRW: Do we want a limit counter for retries here?
  249                  */
  250 recheck:
  251                 corrections = 0;
  252                 differences = 0;
  253                 if (altera_sdcard_verify_rxtx_writes) {
  254                         for (i = 0; i < ALTERA_SDCARD_SECTORSIZE; i += 2) {
  255                                 v = bus_read_2(sc->as_res,
  256                                     ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
  257                                 d = *(uint16_t *)((uint8_t *)data + i);
  258                                 if (v != d) {
  259                                         if (retry_counter == 0) {
  260                                                 bus_write_2(sc->as_res,
  261                                                     ALTERA_SDCARD_OFF_RXTX_BUFFER + i,
  262                                                     d);
  263                                                 v = bus_read_2(sc->as_res,
  264                                                     ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
  265                                                 if (v == d) {
  266                                                         corrections++;
  267                                                         device_printf(sc->as_dev,
  268                                                             "%s: single word rewrite worked"
  269                                                             " at offset %u\n", 
  270                                                             __func__, i);
  271                                                         continue;
  272                                                 }
  273                                         }
  274                                         differences++;
  275                                         device_printf(sc->as_dev,
  276                                             "%s: retrying write -- difference"
  277                                             " %u at offset %u, retry %u\n",
  278                                             __func__, differences, i,
  279                                             retry_counter);
  280                                 }
  281                         }
  282                         if (differences != 0) {
  283                                 retry_counter++;
  284                                 if (retry_counter == 1 &&
  285                                     corrections == differences)
  286                                         goto recheck;
  287                         }
  288                 }
  289         } while (differences != 0);
  290         if (retry_counter)
  291                 device_printf(sc->as_dev, "%s: succeeded after %u retries\n",
  292                     __func__, retry_counter);
  293 }
  294 
  295 static void
  296 altera_sdcard_io_start_internal(struct altera_sdcard_softc *sc,
  297     struct bio **bpp)
  298 {
  299         struct bio *bp;
  300 
  301         bp = *bpp;
  302 
  303         switch (bp->bio_cmd) {
  304         case BIO_READ:
  305                 altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
  306                     ALTERA_SDCARD_SECTORSIZE);
  307                 altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_READ_BLOCK);
  308                 break;
  309 
  310         case BIO_WRITE:
  311                 altera_sdcard_write_rxtx_buffer(sc, bp->bio_data,
  312                     bp->bio_bcount);
  313                 altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
  314                     ALTERA_SDCARD_SECTORSIZE);
  315                 altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_WRITE_BLOCK);
  316                 break;
  317 
  318         default:
  319                 biofinish(bp, NULL, EOPNOTSUPP);
  320                 *bpp = NULL;
  321         }
  322 }
  323 
  324 void
  325 altera_sdcard_io_start(struct altera_sdcard_softc *sc, struct bio *bp)
  326 {
  327 
  328         ALTERA_SDCARD_LOCK_ASSERT(sc);
  329         KASSERT(sc->as_currentbio == NULL,
  330             ("%s: bio already started", __func__));
  331 
  332         /*
  333          * We advertise a block size and maximum I/O size up the stack of the
  334          * SD Card IP Core sector size.  Catch any attempts to not follow the
  335          * rules.
  336          */
  337         KASSERT(bp->bio_bcount == ALTERA_SDCARD_SECTORSIZE,
  338             ("%s: I/O size not %d", __func__, ALTERA_SDCARD_SECTORSIZE));
  339         altera_sdcard_io_start_internal(sc, &bp);
  340         sc->as_currentbio = bp;
  341         sc->as_retriesleft = ALTERA_SDCARD_RETRY_LIMIT;
  342 }
  343 
  344 /*
  345  * Handle completed I/O.  ASR is passed in to avoid reading it more than once.
  346  * Return 1 if the I/O is actually complete (success, or retry limit
  347  * exceeded), or 0 if not.
  348  */
  349 int
  350 altera_sdcard_io_complete(struct altera_sdcard_softc *sc, uint16_t asr)
  351 {
  352         struct bio *bp;
  353         uint16_t rr1, mask;
  354         int error;
  355 
  356         ALTERA_SDCARD_LOCK_ASSERT(sc);
  357         KASSERT(!(asr & ALTERA_SDCARD_ASR_CMDINPROGRESS),
  358             ("%s: still in progress", __func__));
  359         KASSERT(asr & ALTERA_SDCARD_ASR_CARDPRESENT,
  360             ("%s: card removed", __func__));
  361 
  362         bp = sc->as_currentbio;
  363 
  364         /*-
  365          * Handle I/O retries if an error is returned by the device.  Various
  366          * quirks handled in the process:
  367          *
  368          * 1. ALTERA_SDCARD_ASR_CMDDATAERROR is ignored for BIO_WRITE.
  369          * 2. ALTERA_SDCARD_RR1_COMMANDCRCFAILED is optionally ignored for
  370          *    BIO_READ.
  371          */
  372         error = 0;
  373         rr1 = altera_sdcard_read_rr1(sc);
  374         switch (bp->bio_cmd) {
  375         case BIO_READ:
  376                 mask = ALTERA_SDCARD_RR1_ERRORMASK;
  377                 if (altera_sdcard_ignore_crc_errors)
  378                         mask &= ~ALTERA_SDCARD_RR1_COMMANDCRCFAILED;
  379                 if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
  380                         error = EIO;
  381                 else if ((asr & ALTERA_SDCARD_ASR_CMDDATAERROR) &&
  382                     (rr1 & mask))
  383                         error = EIO;
  384                 else
  385                         error = 0;
  386                 break;
  387 
  388         case BIO_WRITE:
  389                 if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
  390                         error = EIO;
  391                 else
  392                         error = 0;
  393                 break;
  394 
  395         default:
  396                 break;
  397         }
  398         if (error) {
  399                 sc->as_retriesleft--;
  400                 if (sc->as_retriesleft == 0 || bootverbose)
  401                         device_printf(sc->as_dev, "%s: %s operation block %ju "
  402                             "length %ju failed; asr 0x%08x (rr1: 0x%04x)%s\n",
  403                             __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
  404                             (bp->bio_cmd == BIO_WRITE ? "BIO_WRITE" :
  405                             "unknown"),
  406                             bp->bio_pblkno, bp->bio_bcount, asr, rr1,
  407                             sc->as_retriesleft != 0 ? " retrying" : "");
  408                 /*
  409                  * This attempt experienced an error; possibly retry.
  410                  */
  411                 if (sc->as_retriesleft != 0) {
  412                         sc->as_flags |= ALTERA_SDCARD_FLAG_IOERROR;
  413                         altera_sdcard_io_start_internal(sc, &bp);
  414                         return (0);
  415                 }
  416                 sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
  417         } else {
  418                 /*
  419                  * Successful I/O completion path.
  420                  */
  421                 if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) {
  422                         device_printf(sc->as_dev, "%s: %s operation block %ju"
  423                             " length %ju succeeded after %d retries\n",
  424                             __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
  425                             (bp->bio_cmd == BIO_WRITE ? "write" : "unknown"),
  426                             bp->bio_pblkno, bp->bio_bcount,
  427                             ALTERA_SDCARD_RETRY_LIMIT - sc->as_retriesleft);
  428                         sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
  429                 }
  430                 switch (bp->bio_cmd) {
  431                 case BIO_READ:
  432                         altera_sdcard_read_rxtx_buffer(sc, bp->bio_data,
  433                             bp->bio_bcount);
  434                         break;
  435 
  436                 case BIO_WRITE:
  437                         break;
  438 
  439                 default:
  440                         panic("%s: unsupported I/O operation %d", __func__,
  441                             bp->bio_cmd);
  442                 }
  443                 bp->bio_resid = 0;
  444                 error = 0;
  445         }
  446         biofinish(bp, NULL, error);
  447         sc->as_currentbio = NULL;
  448         return (1);
  449 }

Cache object: a754d4ccf88b71ad5db742d7599b0f18


[ 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.