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

Cache object: cbf3941a260695647e561aed3ff56fdd


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