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.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 "opt_altera_sdcard.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/bus.h>
   40 #include <sys/condvar.h>
   41 #include <sys/conf.h>
   42 #include <sys/bio.h>
   43 #include <sys/kernel.h>
   44 #include <sys/lock.h>
   45 #include <sys/malloc.h>
   46 #include <sys/module.h>
   47 #include <sys/mutex.h>
   48 #include <sys/rman.h>
   49 #include <sys/systm.h>
   50 #include <sys/taskqueue.h>
   51 
   52 #include <machine/bus.h>
   53 #include <machine/resource.h>
   54 
   55 #include <geom/geom_disk.h>
   56 
   57 #include <dev/altera/sdcard/altera_sdcard.h>
   58 
   59 /*
   60  * Device driver for the Altera University Program Secure Data Card IP Core,
   61  * as described in the similarly named SOPC Builder IP Core specification.
   62  * This soft core is not a full SD host controller interface (SDHCI) but
   63  * instead provides a set of memory mapped registers and memory buffer that
   64  * mildly abstract the SD Card protocol, but without providing DMA or
   65  * interrupts.  However, it does hide the details of voltage and
   66  * communications negotiation.  This driver implements disk(9), but due to the
   67  * lack of interrupt support, must rely on timer-driven polling to determine
   68  * when I/Os have completed.
   69  *
   70  * TODO:
   71  *
   72  * 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support.
   73  * 2. Implement d_ident from SD Card CID serial number field.
   74  * 3. Handle read-only SD Cards.
   75  * 4. Tune timeouts based on real-world SD Card speeds.
   76  */
   77 devclass_t      altera_sdcard_devclass;
   78 
   79 void
   80 altera_sdcard_attach(struct altera_sdcard_softc *sc)
   81 {
   82 
   83         ALTERA_SDCARD_LOCK_INIT(sc);
   84         ALTERA_SDCARD_CONDVAR_INIT(sc);
   85         sc->as_disk = NULL;
   86         bioq_init(&sc->as_bioq);
   87         sc->as_currentbio = NULL;
   88         sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
   89         sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK,
   90             taskqueue_thread_enqueue, &sc->as_taskqueue);
   91         taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK,
   92             "altera_sdcardc%d taskqueue", sc->as_unit);
   93         TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0,
   94             altera_sdcard_task, sc);
   95 
   96         /*
   97          * Kick off timer-driven processing with a manual poll so that we
   98          * synchronously detect an already-inserted SD Card during the boot or
   99          * other driver attach point.
  100          */
  101         altera_sdcard_task(sc, 1);
  102 }
  103 
  104 void
  105 altera_sdcard_detach(struct altera_sdcard_softc *sc)
  106 {
  107 
  108         KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present",
  109             __func__));
  110 
  111         /*
  112          * Winding down the driver on detach is a bit complex.  Update the
  113          * flags to indicate that a detach has been requested, and then wait
  114          * for in-progress I/O to wind down before continuing.
  115          */
  116         ALTERA_SDCARD_LOCK(sc);
  117         sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ;
  118         while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED)
  119                 ALTERA_SDCARD_CONDVAR_WAIT(sc);
  120         ALTERA_SDCARD_UNLOCK(sc);
  121 
  122         /*
  123          * Now wait for the possibly still executing taskqueue to drain.  In
  124          * principle no more events will be scheduled as we've transitioned to
  125          * a detached state, but there might still be a request in execution.
  126          */
  127         while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL))
  128                 taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task);
  129 
  130         /*
  131          * Simulate a disk removal if one is present to deal with any pending
  132          * or queued I/O.
  133          */
  134         if (sc->as_disk != NULL)
  135                 altera_sdcard_disk_remove(sc);
  136         KASSERT(bioq_first(&sc->as_bioq) == NULL,
  137             ("%s: non-empty bioq", __func__));
  138 
  139         /*
  140          * Free any remaining allocated resources.
  141          */
  142         taskqueue_free(sc->as_taskqueue);
  143         sc->as_taskqueue = NULL;
  144         ALTERA_SDCARD_CONDVAR_DESTROY(sc);
  145         ALTERA_SDCARD_LOCK_DESTROY(sc);
  146 }
  147 
  148 /*
  149  * Set up and start the next I/O.  Transition to the I/O state, but allow the
  150  * caller to schedule the next timeout, as this may be called either from an
  151  * initial attach context, or from the task queue, which requires different
  152  * behaviour.
  153  */
  154 static void
  155 altera_sdcard_nextio(struct altera_sdcard_softc *sc)
  156 {
  157         struct bio *bp;
  158 
  159         ALTERA_SDCARD_LOCK_ASSERT(sc);
  160         KASSERT(sc->as_currentbio == NULL,
  161             ("%s: bio already active", __func__));
  162 
  163         bp = bioq_takefirst(&sc->as_bioq);
  164         if (bp == NULL)
  165                 panic("%s: bioq empty", __func__);
  166         altera_sdcard_io_start(sc, bp);
  167         sc->as_state = ALTERA_SDCARD_STATE_IO;
  168 }
  169 
  170 static void
  171 altera_sdcard_task_nocard(struct altera_sdcard_softc *sc)
  172 {
  173 
  174         ALTERA_SDCARD_LOCK_ASSERT(sc);
  175 
  176         /*
  177          * Handle device driver detach.
  178          */
  179         if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
  180                 sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
  181                 return;
  182         }
  183 
  184         /*
  185          * If there is no card insertion, remain in NOCARD.
  186          */
  187         if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
  188                 return;
  189 
  190         /*
  191          * Read the CSD -- it may contain values that the driver can't handle,
  192          * either because of an unsupported version/feature, or because the
  193          * card is misbehaving.  This triggers a transition to
  194          * ALTERA_SDCARD_STATE_BADCARD.  We rely on the CSD read to print a
  195          * banner about how the card is problematic, since it has more
  196          * information.  The bad card state allows us to print that banner
  197          * once rather than each time we notice the card is there, and still
  198          * bad.
  199          */
  200         if (altera_sdcard_read_csd(sc) != 0) {
  201                 sc->as_state = ALTERA_SDCARD_STATE_BADCARD;
  202                 return;
  203         }
  204 
  205         /*
  206          * Process card insertion and upgrade to the IDLE state.
  207          */
  208         altera_sdcard_disk_insert(sc);
  209         sc->as_state = ALTERA_SDCARD_STATE_IDLE;
  210 }
  211 
  212 static void
  213 altera_sdcard_task_badcard(struct altera_sdcard_softc *sc)
  214 {
  215 
  216         ALTERA_SDCARD_LOCK_ASSERT(sc);
  217 
  218         /*
  219          * Handle device driver detach.
  220          */
  221         if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
  222                 sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
  223                 return;
  224         }
  225 
  226         /*
  227          * Handle safe card removal -- no teardown is required, just a state
  228          * transition.
  229          */
  230         if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
  231                 sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
  232 }
  233 
  234 static void
  235 altera_sdcard_task_idle(struct altera_sdcard_softc *sc)
  236 {
  237 
  238         ALTERA_SDCARD_LOCK_ASSERT(sc);
  239 
  240         /*
  241          * Handle device driver detach.
  242          */
  243         if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
  244                 sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
  245                 return;
  246         }
  247 
  248         /*
  249          * Handle safe card removal.
  250          */
  251         if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) {
  252                 altera_sdcard_disk_remove(sc);
  253                 sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
  254         }
  255 }
  256 
  257 static void
  258 altera_sdcard_task_io(struct altera_sdcard_softc *sc)
  259 {
  260         uint16_t asr;
  261 
  262         ALTERA_SDCARD_LOCK_ASSERT(sc);
  263         KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__));
  264 
  265 #ifdef ALTERA_SDCARD_FAST_SIM
  266 recheck:
  267 #endif
  268         asr = altera_sdcard_read_asr(sc);
  269 
  270         /*
  271          * Check for unexpected card removal during an I/O.
  272          */
  273         if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) {
  274                 altera_sdcard_disk_remove(sc);
  275                 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ)
  276                         sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
  277                 else
  278                         sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
  279                 return;
  280         }
  281 
  282         /*
  283          * If the I/O isn't complete, remain in the IO state without further
  284          * action, even if DETACHREQ is in flight.
  285          */
  286         if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS)
  287                 return;
  288 
  289         /*
  290          * Handle various forms of I/O completion, successful and otherwise.
  291          * The I/O layer may restart the transaction if an error occurred, in
  292          * which case remain in the IO state and reschedule.
  293          */
  294         if (!altera_sdcard_io_complete(sc, asr))
  295                 return;
  296 
  297         /*
  298          * Now that I/O is complete, process detach requests in preference to
  299          * starting new I/O.
  300          */
  301         if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
  302                 sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
  303                 return;
  304         }
  305 
  306         /*
  307          * Finally, either start the next I/O or transition to the IDLE state.
  308          */
  309         if (bioq_first(&sc->as_bioq) != NULL) {
  310                 altera_sdcard_nextio(sc);
  311 #ifdef ALTERA_SDCARD_FAST_SIM
  312                 goto recheck;
  313 #endif
  314         } else
  315                 sc->as_state = ALTERA_SDCARD_STATE_IDLE;
  316 }
  317 
  318 static void
  319 altera_sdcard_task_rechedule(struct altera_sdcard_softc *sc)
  320 {
  321         int interval;
  322 
  323         /*
  324          * Reschedule based on new state.  Or not, if detaching the device
  325          * driver.  Treat a bad card as though it were no card at all.
  326          */
  327         switch (sc->as_state) {
  328         case ALTERA_SDCARD_STATE_NOCARD:
  329         case ALTERA_SDCARD_STATE_BADCARD:
  330                 interval = ALTERA_SDCARD_TIMEOUT_NOCARD;
  331                 break;
  332 
  333         case ALTERA_SDCARD_STATE_IDLE:
  334                 interval = ALTERA_SDCARD_TIMEOUT_IDLE;
  335                 break;
  336 
  337         case ALTERA_SDCARD_STATE_IO:
  338                 if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR)
  339                         interval = ALTERA_SDCARD_TIMEOUT_IOERROR;
  340                 else
  341                         interval = ALTERA_SDCARD_TIMEOUT_IO;
  342                 break;
  343 
  344         default:
  345                 panic("%s: invalid exit state %d", __func__, sc->as_state);
  346         }
  347         taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval);
  348 }
  349 
  350 /*
  351  * Because the Altera SD Card IP Core doesn't support interrupts, we do all
  352  * asynchronous work from a timeout.  Poll at two different rates -- an
  353  * infrequent check for card insertion status changes, and a frequent one for
  354  * I/O completion.  The task should never start in DETACHED, as that would
  355  * imply that a previous instance failed to cancel rather than reschedule.
  356  */
  357 void
  358 altera_sdcard_task(void *arg, int pending)
  359 {
  360         struct altera_sdcard_softc *sc;
  361 
  362         sc = arg;
  363         KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED,
  364             ("%s: already in detached", __func__));
  365 
  366         ALTERA_SDCARD_LOCK(sc);
  367         switch (sc->as_state) {
  368         case ALTERA_SDCARD_STATE_NOCARD:
  369                 altera_sdcard_task_nocard(sc);
  370                 break;
  371 
  372         case ALTERA_SDCARD_STATE_BADCARD:
  373                 altera_sdcard_task_badcard(sc);
  374                 break;
  375 
  376         case ALTERA_SDCARD_STATE_IDLE:
  377                 altera_sdcard_task_idle(sc);
  378                 break;
  379 
  380         case ALTERA_SDCARD_STATE_IO:
  381                 altera_sdcard_task_io(sc);
  382                 break;
  383 
  384         default:
  385                 panic("%s: invalid enter state %d", __func__, sc->as_state);
  386         }
  387 
  388         /*
  389          * If we have transitioned to DETACHED, signal the detach thread and
  390          * cancel the timeout-driven task.  Otherwise reschedule on an
  391          * appropriate timeout.
  392          */
  393         if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED)
  394                 ALTERA_SDCARD_CONDVAR_SIGNAL(sc);
  395         else
  396                 altera_sdcard_task_rechedule(sc);
  397         ALTERA_SDCARD_UNLOCK(sc);
  398 }
  399 
  400 void
  401 altera_sdcard_start(struct altera_sdcard_softc *sc)
  402 {
  403 
  404         ALTERA_SDCARD_LOCK_ASSERT(sc);
  405 
  406         KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE,
  407             ("%s: starting when not IDLE", __func__));
  408 
  409         taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL);
  410         altera_sdcard_nextio(sc);
  411 #ifdef ALTERA_SDCARD_FAST_SIM
  412         altera_sdcard_task_io(sc);
  413 #endif
  414         altera_sdcard_task_rechedule(sc);
  415 }

Cache object: 5f9bd13e7a60e22a95b9d88151c6e519


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