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

Cache object: 776af48763a883feedee58b53e74f446


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