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: releng/12.0/sys/dev/altera/sdcard/altera_sdcard_io.c 326255 2017-11-27 14:52:40Z pfg $");
   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, struct bio *bp)
  297 {
  298 
  299         switch (bp->bio_cmd) {
  300         case BIO_READ:
  301                 altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
  302                     ALTERA_SDCARD_SECTORSIZE);
  303                 altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_READ_BLOCK);
  304                 break;
  305 
  306         case BIO_WRITE:
  307                 altera_sdcard_write_rxtx_buffer(sc, bp->bio_data,
  308                     bp->bio_bcount);
  309                 altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
  310                     ALTERA_SDCARD_SECTORSIZE);
  311                 altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_WRITE_BLOCK);
  312                 break;
  313 
  314         default:
  315                 panic("%s: unsupported I/O operation %d", __func__,
  316                     bp->bio_cmd);
  317         }
  318 }
  319 
  320 void
  321 altera_sdcard_io_start(struct altera_sdcard_softc *sc, struct bio *bp)
  322 {
  323 
  324         ALTERA_SDCARD_LOCK_ASSERT(sc);
  325         KASSERT(sc->as_currentbio == NULL,
  326             ("%s: bio already started", __func__));
  327 
  328         /*
  329          * We advertise a block size and maximum I/O size up the stack of the
  330          * SD Card IP Core sector size.  Catch any attempts to not follow the
  331          * rules.
  332          */
  333         KASSERT(bp->bio_bcount == ALTERA_SDCARD_SECTORSIZE,
  334             ("%s: I/O size not %d", __func__, ALTERA_SDCARD_SECTORSIZE));
  335         altera_sdcard_io_start_internal(sc, bp);
  336         sc->as_currentbio = bp;
  337         sc->as_retriesleft = ALTERA_SDCARD_RETRY_LIMIT;
  338 }
  339 
  340 /*
  341  * Handle completed I/O.  ASR is passed in to avoid reading it more than once.
  342  * Return 1 if the I/O is actually complete (success, or retry limit
  343  * exceeded), or 0 if not.
  344  */
  345 int
  346 altera_sdcard_io_complete(struct altera_sdcard_softc *sc, uint16_t asr)
  347 {
  348         struct bio *bp;
  349         uint16_t rr1, mask;
  350         int error;
  351 
  352         ALTERA_SDCARD_LOCK_ASSERT(sc);
  353         KASSERT(!(asr & ALTERA_SDCARD_ASR_CMDINPROGRESS),
  354             ("%s: still in progress", __func__));
  355         KASSERT(asr & ALTERA_SDCARD_ASR_CARDPRESENT,
  356             ("%s: card removed", __func__));
  357 
  358         bp = sc->as_currentbio;
  359 
  360         /*-
  361          * Handle I/O retries if an error is returned by the device.  Various
  362          * quirks handled in the process:
  363          *
  364          * 1. ALTERA_SDCARD_ASR_CMDDATAERROR is ignored for BIO_WRITE.
  365          * 2. ALTERA_SDCARD_RR1_COMMANDCRCFAILED is optionally ignored for
  366          *    BIO_READ.
  367          */
  368         error = 0;
  369         rr1 = altera_sdcard_read_rr1(sc);
  370         switch (bp->bio_cmd) {
  371         case BIO_READ:
  372                 mask = ALTERA_SDCARD_RR1_ERRORMASK;
  373                 if (altera_sdcard_ignore_crc_errors)
  374                         mask &= ~ALTERA_SDCARD_RR1_COMMANDCRCFAILED;
  375                 if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
  376                         error = EIO;
  377                 else if ((asr & ALTERA_SDCARD_ASR_CMDDATAERROR) &&
  378                     (rr1 & mask))
  379                         error = EIO;
  380                 else
  381                         error = 0;
  382                 break;
  383 
  384         case BIO_WRITE:
  385                 if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
  386                         error = EIO;
  387                 else
  388                         error = 0;
  389                 break;
  390 
  391         default:
  392                 break;
  393         }
  394         if (error) {
  395                 sc->as_retriesleft--;
  396                 if (sc->as_retriesleft == 0 || bootverbose)
  397                         device_printf(sc->as_dev, "%s: %s operation block %ju "
  398                             "length %ju failed; asr 0x%08x (rr1: 0x%04x)%s\n",
  399                             __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
  400                             (bp->bio_cmd == BIO_WRITE ? "BIO_WRITE" :
  401                             "unknown"),
  402                             bp->bio_pblkno, bp->bio_bcount, asr, rr1,
  403                             sc->as_retriesleft != 0 ? " retrying" : "");
  404                 /*
  405                  * This attempt experienced an error; possibly retry.
  406                  */
  407                 if (sc->as_retriesleft != 0) {
  408                         sc->as_flags |= ALTERA_SDCARD_FLAG_IOERROR;
  409                         altera_sdcard_io_start_internal(sc, bp);
  410                         return (0);
  411                 }
  412                 sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
  413         } else {
  414                 /*
  415                  * Successful I/O completion path.
  416                  */
  417                 if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) {
  418                         device_printf(sc->as_dev, "%s: %s operation block %ju"
  419                             " length %ju succeeded after %d retries\n",
  420                             __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
  421                             (bp->bio_cmd == BIO_WRITE ? "write" : "unknown"),
  422                             bp->bio_pblkno, bp->bio_bcount,
  423                             ALTERA_SDCARD_RETRY_LIMIT - sc->as_retriesleft);
  424                         sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
  425                 }
  426                 switch (bp->bio_cmd) {
  427                 case BIO_READ:
  428                         altera_sdcard_read_rxtx_buffer(sc, bp->bio_data,
  429                             bp->bio_bcount);
  430                         break;
  431 
  432                 case BIO_WRITE:
  433                         break;
  434 
  435                 default:
  436                         panic("%s: unsupported I/O operation %d", __func__,
  437                             bp->bio_cmd);
  438                 }
  439                 bp->bio_resid = 0;
  440                 error = 0;
  441         }
  442         biofinish(bp, NULL, error);
  443         sc->as_currentbio = NULL;
  444         return (1);
  445 }

Cache object: 41817cbaca7eb93c66f105ad682ca0ae


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