Author: rwatson
Date: Sat Aug 25 11:19:20 2012
New Revision: 239675
URL: http://svn.freebsd.org/changeset/base/239675

Log:
  Add a device driver for the Altera University Program SD Card IP Core,
  which can be synthesised in Altera FPGAs.  An altera_sdcardc device
  probes during the boot, and /dev/altera_sdcard devices come and go as
  inserted and removed.  The device driver attaches directly to the
  Nexus, as is common for system-on-chip device drivers.
  
  This IP core suffers a number of significant limitations, including a
  lack of interrupt-driven I/O -- we must implement timer-driven polling,
  only CSD 0 cards (up to 2G) are supported, there are serious memory
  access issues that require the driver to verify writes to memory-mapped
  buffers, undocumented alignment requirements, and erroneous error
  returns.  The driver must therefore work quite hard, despite a fairly
  simple hardware-software interface.  The IP core also supports at most
  one outstanding I/O at a time, so is not a speed demon.
  
  However, with the above workarounds, and subject to performance
  problems, it works quite reliably in practice, and we can use it for
  read-write mounts of root file systems, etc.
  
  Sponsored by: DARPA, AFRL

Added:
  head/share/man/man4/altera_sdcard.4   (contents, props changed)
  head/sys/dev/altera/sdcard/
  head/sys/dev/altera/sdcard/altera_sdcard.c   (contents, props changed)
  head/sys/dev/altera/sdcard/altera_sdcard.h   (contents, props changed)
  head/sys/dev/altera/sdcard/altera_sdcard_disk.c   (contents, props changed)
  head/sys/dev/altera/sdcard/altera_sdcard_io.c   (contents, props changed)
  head/sys/dev/altera/sdcard/altera_sdcard_nexus.c   (contents, props changed)
Modified:
  head/share/man/man4/Makefile
  head/sys/conf/files

Modified: head/share/man/man4/Makefile
==============================================================================
--- head/share/man/man4/Makefile        Sat Aug 25 11:07:43 2012        
(r239674)
+++ head/share/man/man4/Makefile        Sat Aug 25 11:19:20 2012        
(r239675)
@@ -33,6 +33,7 @@ MAN=  aac.4 \
        ale.4 \
        alpm.4 \
        altera_avgen.4 \
+       altera_sdcard.4 \
        altq.4 \
        amdpm.4 \
        ${_amdsbwd.4} \

Added: head/share/man/man4/altera_sdcard.4
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/share/man/man4/altera_sdcard.4 Sat Aug 25 11:19:20 2012        
(r239675)
@@ -0,0 +1,118 @@
+.\"-
+.\" Copyright (c) 2012 Robert N. M. Watson
+.\" All rights reserved.
+.\"
+.\" This software was developed by SRI International and the University of
+.\" Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+.\" ("CTSRD"), as part of the DARPA CRASH research programme.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd August 18, 2012
+.Dt ALTERA_SDCARD 4
+.Os
+.Sh NAME
+.Nm altera_sdcard
+.Nd driver for the Altera University Program Secure Data Card IP Core
+.Sh SYNOPSIS
+.Cd "device altera_sdcard"
+.Pp
+In
+.Pa /boot/device.hints :
+.Cd hint.altera_sdcardc.0.at="nexus0"
+.Cd hint.altera_sdcardc.0.maddr=0x7f008000
+.Cd hint.altera_sdcardc.0.msize=0x400
+.Sh DESCRIPTION
+The
+.Nm
+device driver provides support for the Altera University Program Secure Data
+Card (SD Card) IP Core device.
+A controller device,
+.Li altera_sdcardcX ,
+will be attached during boot.
+Inserted disks are presented as
+.Xr disk 9
+devices,
+.Li altera_sdcardX ,
+corresponding to the controller number.
+.Sh HARDWARE
+The current version of the
+.Nm
+driver supports the SD Card IP core as described in the August 2011 version of
+Altera's documentation.
+The core supports only cards up to 2G (CSD 0); larger cards, or cards using
+newer CSD versions, will not be detected.
+The IP core has two key limitations: a lack of interrupt support, requiring
+timer-driven polling to detect I/O completion, and support for only single
+512-byte block read and write operations at a time.
+The combined effect of those two limits is that the system clock rate,
+.Dv HZ ,
+must be set to at least 200 in order to accomplish the maximum 100KB/s data
+rate supported by the IP core.
+.Sh SEE ALSO
+.Xr disk 9
+.Rs
+.%T Altera University Program Secure Data Card IP Core
+.%D August 2011
+.%I Altera Corporation - University Program
+.%U 
ftp://ftp.altera.com/up/pub/Altera_Material/11.0/University_Program_IP_Cores/Memory/SD_Card_Interface_for_SoPC_Builder.pdf
+.Re
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 10.0 .
+.Sh AUTHORS
+The
+.Nm
+device driver and this manual page were
+developed by SRI International and the University of Cambridge Computer
+Laboratory under DARPA/AFRL contract
+.Pq FA8750-10-C-0237
+.Pq Do CTSRD Dc ,
+as part of the DARPA CRASH research programme.
+This device driver was written by
+.An Robert N. M. Watson .
+.Sh BUGS
+.Nm
+contains a number of work-arounds for IP core bugs.
+Perhaps most critically,
+.Nm
+ignores the CRC error bit returned in the RR1 register, which appears to be
+unexpectedly set by the IP core.
+.Pp
+.Nm
+uses fixed polling intervals are used for card insertion/removal and
+I/O completion detection; an adaptive strategy might improve performance by
+reducing the latency to detecting completed I/O.
+However, in our experiments, using polling rates greater than 200 times a
+second did not improve performance.
+.Pp
+.Nm
+supports only a
+.Li nexus
+bus attachment, which is appropriate for system-on-chip busses such as
+Altera's Avalon bus.
+If the IP core is configured off of another bus type, then additional bus
+attachments will be required.

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Sat Aug 25 11:07:43 2012        (r239674)
+++ head/sys/conf/files Sat Aug 25 11:19:20 2012        (r239675)
@@ -660,6 +660,10 @@ dev/aic7xxx/aic7xxx_pci.c  optional ahc p
 dev/alc/if_alc.c               optional alc pci
 dev/ale/if_ale.c               optional ale pci
 dev/altera/avgen/altera_avgen.c                optional altera_avgen
+dev/altera/sdcard/altera_sdcard.c      optional altera_sdcard
+dev/altera/sdcard/altera_sdcard_disk.c optional altera_sdcard
+dev/altera/sdcard/altera_sdcard_io.c   optional altera_sdcard
+dev/altera/sdcard/altera_sdcard_nexus.c        optional altera_sdcard
 dev/amr/amr.c                  optional amr
 dev/amr/amr_cam.c              optional amrp amr
 dev/amr/amr_disk.c             optional amr

Added: head/sys/dev/altera/sdcard/altera_sdcard.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/altera/sdcard/altera_sdcard.c  Sat Aug 25 11:19:20 2012        
(r239675)
@@ -0,0 +1,402 @@
+/*-
+ * Copyright (c) 2012 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/condvar.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/systm.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <geom/geom_disk.h>
+
+#include <dev/altera/sdcard/altera_sdcard.h>
+
+/*
+ * Device driver for the Altera University Program Secure Data Card IP Core,
+ * as described in the similarly named SOPC Builder IP Core specification.
+ * This soft core is not a full SD host controller interface (SDHCI) but
+ * instead provides a set of memory mapped registers and memory buffer that
+ * mildly abstract the SD Card protocol, but without providing DMA or
+ * interrupts.  However, it does hide the details of voltage and
+ * communications negotiation.  This driver implements disk(9), but due to the
+ * lack of interrupt support, must rely on timer-driven polling to determine
+ * when I/Os have completed.
+ *
+ * TODO:
+ *
+ * 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support.
+ * 2. Implement d_ident from SD Card CID serial number field.
+ * 3. Handle read-only SD Cards.
+ * 4. Tune timeouts based on real-world SD Card speeds.
+ */
+
+void
+altera_sdcard_attach(struct altera_sdcard_softc *sc)
+{
+
+       ALTERA_SDCARD_LOCK_INIT(sc);
+       ALTERA_SDCARD_CONDVAR_INIT(sc);
+       sc->as_disk = NULL;
+       bioq_init(&sc->as_bioq);
+       sc->as_currentbio = NULL;
+       sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
+       sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK,
+           taskqueue_thread_enqueue, &sc->as_taskqueue);
+       taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK,
+           "altera_sdcardc%d taskqueue", sc->as_unit);
+       TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0,
+           altera_sdcard_task, sc);
+
+       /*
+        * Kick off timer-driven processing with a manual poll so that we
+        * synchronously detect an already-inserted SD Card during the boot or
+        * other driver attach point.
+        */
+       altera_sdcard_task(sc, 1);
+}
+
+void
+altera_sdcard_detach(struct altera_sdcard_softc *sc)
+{
+
+       KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present",
+           __func__));
+
+       /*
+        * Winding down the driver on detach is a bit complex.  Update the
+        * flags to indicate that a detach has been requested, and then wait
+        * for in-progress I/O to wind down before continuing.
+        */
+       ALTERA_SDCARD_LOCK(sc);
+       sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ;
+       while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED)
+               ALTERA_SDCARD_CONDVAR_WAIT(sc);
+       ALTERA_SDCARD_UNLOCK(sc);
+
+       /*
+        * Now wait for the possibly still executing taskqueue to drain.  In
+        * principle no more events will be scheduled as we've transitioned to
+        * a detached state, but there might still be a request in execution.
+        */
+       while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL))
+               taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task);
+
+       /*
+        * Simulate a disk removal if one is present to deal with any pending
+        * or queued I/O.
+        */
+       if (sc->as_disk != NULL)
+               altera_sdcard_disk_remove(sc);
+       KASSERT(bioq_first(&sc->as_bioq) == NULL,
+           ("%s: non-empty bioq", __func__));
+
+       /*
+        * Free any remaining allocated resources.
+        */
+       taskqueue_free(sc->as_taskqueue);
+       sc->as_taskqueue = NULL;
+       ALTERA_SDCARD_CONDVAR_DESTROY(sc);
+       ALTERA_SDCARD_LOCK_DESTROY(sc);
+}
+
+/*
+ * Set up and start the next I/O.  Transition to the I/O state, but allow the
+ * caller to schedule the next timeout, as this may be called either from an
+ * initial attach context, or from the task queue, which requires different
+ * behaviour.
+ */
+static void
+altera_sdcard_nextio(struct altera_sdcard_softc *sc)
+{
+       struct bio *bp;
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+       KASSERT(sc->as_currentbio == NULL,
+           ("%s: bio already active", __func__));
+
+       bp = bioq_takefirst(&sc->as_bioq);
+       if (bp == NULL)
+               panic("%s: bioq empty", __func__);
+       altera_sdcard_io_start(sc, bp);
+       sc->as_state = ALTERA_SDCARD_STATE_IO;
+}
+
+static void
+altera_sdcard_task_nocard(struct altera_sdcard_softc *sc)
+{
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+
+       /*
+        * Handle device driver detach.
+        */
+       if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
+               sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
+               return;
+       }
+
+       /*
+        * If there is no card insertion, remain in NOCARD.
+        */
+       if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
+               return;
+
+       /*
+        * Read the CSD -- it may contain values that the driver can't handle,
+        * either because of an unsupported version/feature, or because the
+        * card is misbehaving.  This triggers a transition to
+        * ALTERA_SDCARD_STATE_BADCARD.  We rely on the CSD read to print a
+        * banner about how the card is problematic, since it has more
+        * information.  The bad card state allows us to print that banner
+        * once rather than each time we notice the card is there, and still
+        * bad.
+        */
+       if (altera_sdcard_read_csd(sc) != 0) {
+               sc->as_state = ALTERA_SDCARD_STATE_BADCARD;
+               return;
+       }
+
+       /*
+        * Process card insertion and upgrade to the IDLE state.
+        */
+       altera_sdcard_disk_insert(sc);
+       sc->as_state = ALTERA_SDCARD_STATE_IDLE;
+}
+
+static void
+altera_sdcard_task_badcard(struct altera_sdcard_softc *sc)
+{
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+
+       /*
+        * Handle device driver detach.
+        */
+       if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
+               sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
+               return;
+       }
+
+       /*
+        * Handle safe card removal -- no teardown is required, just a state
+        * transition.
+        */
+       if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
+               sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
+}
+
+static void
+altera_sdcard_task_idle(struct altera_sdcard_softc *sc)
+{
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+
+       /*
+        * Handle device driver detach.
+        */
+       if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
+               sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
+               return;
+       }
+
+       /*
+        * Handle safe card removal.
+        */
+       if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) {
+               altera_sdcard_disk_remove(sc);
+               sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
+       }
+}
+
+static void
+altera_sdcard_task_io(struct altera_sdcard_softc *sc)
+{
+       uint16_t asr;
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+       KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__));
+
+       asr = altera_sdcard_read_asr(sc);
+
+       /*
+        * Check for unexpected card removal during an I/O.
+        */
+       if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) {
+               altera_sdcard_disk_remove(sc);
+               if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ)
+                       sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
+               else
+                       sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
+               return;
+       }
+
+       /*
+        * If the I/O isn't complete, remain in the IO state without further
+        * action, even if DETACHREQ is in flight.
+        */
+       if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS)
+               return;
+
+       /*
+        * Handle various forms of I/O completion, successful and otherwise.
+        * The I/O layer may restart the transaction if an error occurred, in
+        * which case remain in the IO state and reschedule.
+        */
+       if (!altera_sdcard_io_complete(sc, asr))
+               return;
+
+       /*
+        * Now that I/O is complete, process detach requests in preference to
+        * starting new I/O.
+        */
+       if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
+               sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
+               return;
+       }
+
+       /*
+        * Finally, either start the next I/O or transition to the IDLE state.
+        */
+       if (bioq_first(&sc->as_bioq) != NULL)
+               altera_sdcard_nextio(sc);
+       else
+               sc->as_state = ALTERA_SDCARD_STATE_IDLE;
+}
+
+static void
+altera_sdcard_task_rechedule(struct altera_sdcard_softc *sc)
+{
+       int interval;
+
+       /*
+        * Reschedule based on new state.  Or not, if detaching the device
+        * driver.  Treat a bad card as though it were no card at all.
+        */
+       switch (sc->as_state) {
+       case ALTERA_SDCARD_STATE_NOCARD:
+       case ALTERA_SDCARD_STATE_BADCARD:
+               interval = ALTERA_SDCARD_TIMEOUT_NOCARD;
+               break;
+
+       case ALTERA_SDCARD_STATE_IDLE:
+               interval = ALTERA_SDCARD_TIMEOUT_IDLE;
+               break;
+
+       case ALTERA_SDCARD_STATE_IO:
+               if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR)
+                       interval = ALTERA_SDCARD_TIMEOUT_IOERROR;
+               else
+                       interval = ALTERA_SDCARD_TIMEOUT_IO;
+               break;
+
+       default:
+               panic("%s: invalid exit state %d", __func__, sc->as_state);
+       }
+       taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval);
+}
+
+/*
+ * Because the Altera SD Card IP Core doesn't support interrupts, we do all
+ * asynchronous work from a timeout.  Poll at two different rates -- an
+ * infrequent check for card insertion status changes, and a frequent one for
+ * I/O completion.  The task should never start in DETACHED, as that would
+ * imply that a previous instance failed to cancel rather than reschedule.
+ */
+void
+altera_sdcard_task(void *arg, int pending)
+{
+       struct altera_sdcard_softc *sc;
+
+       sc = arg;
+       KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED,
+           ("%s: already in detached", __func__));
+
+       ALTERA_SDCARD_LOCK(sc);
+       switch (sc->as_state) {
+       case ALTERA_SDCARD_STATE_NOCARD:
+               altera_sdcard_task_nocard(sc);
+               break;
+
+       case ALTERA_SDCARD_STATE_BADCARD:
+               altera_sdcard_task_badcard(sc);
+               break;
+
+       case ALTERA_SDCARD_STATE_IDLE:
+               altera_sdcard_task_idle(sc);
+               break;
+
+       case ALTERA_SDCARD_STATE_IO:
+               altera_sdcard_task_io(sc);
+               break;
+
+       default:
+               panic("%s: invalid enter state %d", __func__, sc->as_state);
+       }
+
+       /*
+        * If we have transitioned to DETACHED, signal the detach thread and
+        * cancel the timeout-driven task.  Otherwise reschedule on an
+        * appropriate timeout.
+        */
+       if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED)
+               ALTERA_SDCARD_CONDVAR_SIGNAL(sc);
+       else
+               altera_sdcard_task_rechedule(sc);
+       ALTERA_SDCARD_UNLOCK(sc);
+}
+
+void
+altera_sdcard_start(struct altera_sdcard_softc *sc)
+{
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+
+       KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE,
+           ("%s: starting when not IDLE", __func__));
+
+       taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL);
+       altera_sdcard_nextio(sc);
+       taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task,
+           ALTERA_SDCARD_TIMEOUT_IO);
+}

Added: head/sys/dev/altera/sdcard/altera_sdcard.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/altera/sdcard/altera_sdcard.h  Sat Aug 25 11:19:20 2012        
(r239675)
@@ -0,0 +1,247 @@
+/*-
+ * Copyright (c) 2012 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_ALTERA_SDCARD_H_
+#define        _DEV_ALTERA_SDCARD_H_
+
+#define        ALTERA_SDCARD_CSD_SIZE  16
+struct altera_sdcard_csd {
+       uint8_t          csd_data[ALTERA_SDCARD_CSD_SIZE];
+} __aligned(2);                /* CSD is read in 16-bit chunks, so align to 
match. */
+
+struct altera_sdcard_softc {
+       device_t                 as_dev;
+       int                      as_unit;
+       struct resource         *as_res;
+       int                      as_rid;
+       struct mtx               as_lock;
+       struct cv                as_condvar;
+       int                      as_state;
+       int                      as_flags;
+       struct disk             *as_disk;
+       struct taskqueue        *as_taskqueue;
+       struct timeout_task      as_task;
+
+       /*
+        * Fields relating to in-progress and pending I/O, if any.
+        */
+       struct bio_queue_head    as_bioq;
+       struct bio              *as_currentbio;
+       u_int                    as_retriesleft;
+
+       /*
+        * Infrequently changing fields cached from the SD Card IP Core.
+        */
+       struct altera_sdcard_csd         as_csd;
+       uint8_t                  as_csd_structure;      /* CSD version. */
+       uint64_t                 as_mediasize;
+};
+
+#define        ALTERA_SDCARD_LOCK(sc)          mtx_lock(&(sc)->as_lock)
+#define        ALTERA_SDCARD_LOCK_ASSERT(sc)   mtx_assert(&(sc)->as_lock, 
MA_OWNED)
+#define        ALTERA_SDCARD_LOCK_DESTROY(sc)  mtx_destroy(&(sc)->as_lock)
+#define        ALTERA_SDCARD_LOCK_INIT(sc)     mtx_init(&(sc)->as_lock,        
\
+                                           "altera_sdcard", NULL, MTX_DEF)
+#define        ALTERA_SDCARD_UNLOCK(sc)        mtx_unlock(&(sc)->as_lock)
+
+#define        ALTERA_SDCARD_CONDVAR_DESTROY(sc)       
cv_destroy(&(sc)->as_condvar)
+#define        ALTERA_SDCARD_CONDVAR_INIT(sc)          
cv_init(&(sc)->as_condvar, \
+                                                   "altera_sdcard_detach_wait")
+#define        ALTERA_SDCARD_CONDVAR_SIGNAL(dc)        
cv_signal(&(sc)->as_condvar)
+#define        ALTERA_SDCARD_CONDVAR_WAIT(sc)          
cv_wait(&(sc)->as_condvar, \
+                                                   &(sc)->as_lock)
+
+/*
+ * States an instance can be in at any given moment.
+ */
+#define        ALTERA_SDCARD_STATE_NOCARD      1       /* No card inserted. */
+#define        ALTERA_SDCARD_STATE_BADCARD     2       /* Card bad/not 
supported. */
+#define        ALTERA_SDCARD_STATE_IDLE        3       /* Card present but 
idle. */
+#define        ALTERA_SDCARD_STATE_IO          4       /* Card in I/O 
currently. */
+#define        ALTERA_SDCARD_STATE_DETACHED    5       /* Driver is detaching. 
*/
+
+/*
+ * Different timeout intervals based on state.  When just looking for a card
+ * status change, check twice a second.  When we're actively waiting on I/O
+ * completion, check every millisecond.
+ */
+#define        ALTERA_SDCARD_TIMEOUT_NOCARD    (hz/2)
+#define        ALTERA_SDCARD_TIMEOUT_IDLE      (hz/2)
+#define        ALTERA_SDCARD_TIMEOUT_IO        (1)
+#define        ALTERA_SDCARD_TIMEOUT_IOERROR   (hz/5)
+
+/*
+ * Maximum number of retries on an I/O.
+ */
+#define        ALTERA_SDCARD_RETRY_LIMIT       10
+
+/*
+ * Driver status flags.
+ */
+#define        ALTERA_SDCARD_FLAG_DETACHREQ    0x00000001      /* Detach 
requested. */
+#define        ALTERA_SDCARD_FLAG_IOERROR      0x00000002      /* Error in 
progress. */
+
+/*
+ * Functions for performing low-level register and memory I/O to/from the SD
+ * Card IP Core.  In general, only code in altera_sdcard_io.c is aware of the
+ * hardware interface.
+ */
+uint16_t       altera_sdcard_read_asr(struct altera_sdcard_softc *sc);
+int            altera_sdcard_read_csd(struct altera_sdcard_softc *sc);
+
+int    altera_sdcard_io_complete(struct altera_sdcard_softc *sc,
+           uint16_t asr);
+void   altera_sdcard_io_start(struct altera_sdcard_softc *sc,
+           struct bio *bp);
+
+/*
+ * Constants for interpreting the SD Card Card Specific Data (CSD) register.
+ */
+#define        ALTERA_SDCARD_CSD_STRUCTURE_BYTE        15
+#define        ALTERA_SDCARD_CSD_STRUCTURE_MASK        0xc0    /* 2 bits */
+#define        ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT      6
+
+#define        ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE      10
+#define        ALTERA_SDCARD_CSD_READ_BL_LEN_MASK      0x0f    /* 4 bits */
+
+/*
+ * C_SIZE is a 12-bit field helpfully split over three differe bytes of CSD
+ * data.  Software ease of use was not a design consideration.
+ */
+#define        ALTERA_SDCARD_CSD_C_SIZE_BYTE0          7
+#define        ALTERA_SDCARD_CSD_C_SIZE_MASK0          0xc     /* top 2 bits */
+#define        ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0        6
+
+#define        ALTERA_SDCARD_CSD_C_SIZE_BYTE1          8
+#define        ALTERA_SDCARD_CSD_C_SIZE_MASK1          0xff    /* 8 bits */
+#define        ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1        2
+
+#define        ALTERA_SDCARD_CSD_C_SIZE_BYTE2          9
+#define        ALTERA_SDCARD_CSD_C_SIZE_MASK2          0x03    /* bottom 2 
bits */
+#define        ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2        10
+
+#define        ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0     5
+#define        ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0     0x80    /* top 1 bit */
+#define        ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0   7
+
+#define        ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1     6
+#define        ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1     0x03    /* bottom 2 
bits */
+#define        ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1   1
+
+/*
+ * I/O register/buffer offsets, from Table 4.1.1 in the Altera University
+ * Program SD Card IP Core specification.
+ */
+#define        ALTERA_SDCARD_OFF_RXTX_BUFFER   0       /* 512-byte I/O buffer 
*/
+#define        ALTERA_SDCARD_OFF_CID           512     /* 16-byte Card ID 
number */
+#define        ALTERA_SDCARD_OFF_CSD           528     /* 16-byte Card 
Specific Data */
+#define        ALTERA_SDCARD_OFF_OCR           544     /* Operating Conditions 
Reg */
+#define        ALTERA_SDCARD_OFF_SR            548     /* SD Card Status 
Register */
+#define        ALTERA_SDCARD_OFF_RCA           552     /* Relative Card 
Address Reg */
+#define        ALTERA_SDCARD_OFF_CMD_ARG       556     /* Command Argument 
Register */
+#define        ALTERA_SDCARD_OFF_CMD           560     /* Command Register */
+#define        ALTERA_SDCARD_OFF_ASR           564     /* Auxiliary Status 
Register */
+#define        ALTERA_SDCARD_OFF_RR1           568     /* Response R1 */
+
+/*
+ * The Altera IP Core provides a 16-bit "Additional Status Register" (ASR)
+ * beyond those described in the SD Card specification that captures IP Core
+ * transaction state, such as whether the last command is in progress, the
+ * card has been removed, etc.
+ */
+#define        ALTERA_SDCARD_ASR_CMDVALID      0x0001
+#define        ALTERA_SDCARD_ASR_CARDPRESENT   0x0002
+#define        ALTERA_SDCARD_ASR_CMDINPROGRESS 0x0004
+#define        ALTERA_SDCARD_ASR_SRVALID       0x0008
+#define        ALTERA_SDCARD_ASR_CMDTIMEOUT    0x0010
+#define        ALTERA_SDCARD_ASR_CMDDATAERROR  0x0020
+
+/*
+ * The Altera IP Core claims to provide a 16-bit "Response R1" register (RR1)
+ * to provide more detailed error reporting when a read or write fails.
+ *
+ * XXXRW: The specification claims that this field is 16-bit, but then
+ * proceeds to define values as though it is 32-bit.  In practice, 16-bit
+ * seems more likely as the register is not 32-bit aligned.
+ */
+#define        ALTERA_SDCARD_RR1_INITPROCRUNNING       0x0100
+#define        ALTERA_SDCARD_RR1_ERASEINTERRUPTED      0x0200
+#define        ALTERA_SDCARD_RR1_ILLEGALCOMMAND        0x0400
+#define        ALTERA_SDCARD_RR1_COMMANDCRCFAILED      0x0800
+#define        ALTERA_SDCARD_RR1_ADDRESSMISALIGNED     0x1000
+#define        ALTERA_SDCARD_RR1_ADDRBLOCKRANGE        0x2000
+
+/*
+ * Not all RR1 values are "errors" per se -- check only for the ones that are
+ * when performing error handling.
+ */
+#define        ALTERA_SDCARD_RR1_ERRORMASK                                     
      \
+    (ALTERA_SDCARD_RR1_ERASEINTERRUPTED | ALTERA_SDCARD_RR1_ILLEGALCOMMAND |  \
+    ALTERA_SDCARD_RR1_COMMANDCRCFAILED | ALTERA_SDCARD_RR1_ADDRESSMISALIGNED |\
+    ALTERA_SDCARD_RR1_ADDRBLOCKRANGE)
+
+/*
+ * Although SD Cards may have various sector sizes, the Altera IP Core
+ * requires that I/O be done in 512-byte chunks.
+ */
+#define        ALTERA_SDCARD_SECTORSIZE        512
+
+/*
+ * SD Card commands used in this driver.
+ */
+#define        ALTERA_SDCARD_CMD_SEND_RCA      0x03    /* Retrieve card RCA. */
+#define        ALTERA_SDCARD_CMD_SEND_CSD      0x09    /* Retrieve CSD 
register. */
+#define        ALTERA_SDCARD_CMD_SEND_CID      0x0A    /* Retrieve CID 
register. */
+#define        ALTERA_SDCARD_CMD_READ_BLOCK    0x11    /* Read block from 
disk. */
+#define        ALTERA_SDCARD_CMD_WRITE_BLOCK   0x18    /* Write block to disk. 
*/
+
+/*
+ * Functions exposed by the device driver core to newbus(9) bus attachment
+ * implementations.
+ */
+void   altera_sdcard_attach(struct altera_sdcard_softc *sc);
+void   altera_sdcard_detach(struct altera_sdcard_softc *sc);
+void   altera_sdcard_task(void *arg, int pending);
+
+/*
+ * Functions exposed by the device driver core to the disk(9) front-end.
+ */
+void   altera_sdcard_start(struct altera_sdcard_softc *sc);
+
+/*
+ * Functions relating to the implementation of disk(9) KPIs for the SD Card
+ * driver.
+ */
+void   altera_sdcard_disk_insert(struct altera_sdcard_softc *sc);
+void   altera_sdcard_disk_remove(struct altera_sdcard_softc *sc);
+
+#endif /* _DEV_ALTERA_SDCARD_H_ */

Added: head/sys/dev/altera/sdcard/altera_sdcard_disk.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/altera/sdcard/altera_sdcard_disk.c     Sat Aug 25 11:19:20 
2012        (r239675)
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2012 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/condvar.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/systm.h>
+#include <sys/taskqueue.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <geom/geom_disk.h>
+
+#include <dev/altera/sdcard/altera_sdcard.h>
+
+static int
+altera_sdcard_disk_dump(void *arg, void *virtual, vm_offset_t physical,
+    off_t offset, size_t length)
+{
+
+       panic("%s: not yet", __func__);
+}
+
+static int
+altera_sdcard_disk_ioctl(struct disk *disk, u_long cmd, void *data, int fflag,
+    struct thread *td)
+{
+
+       /* XXXRW: more here? */
+       return (EINVAL);
+}
+
+static void
+altera_sdcard_disk_strategy(struct bio *bp)
+{
+       struct altera_sdcard_softc *sc;
+
+       /*
+        * Although the SD Card doesn't need sorting, we don't want to
+        * introduce barriers, so use bioq_disksort().
+        */
+       sc = bp->bio_disk->d_drv1;
+       ALTERA_SDCARD_LOCK(sc);
+       switch (sc->as_state) {
+       case ALTERA_SDCARD_STATE_NOCARD:
+               device_printf(sc->as_dev, "%s: unexpected I/O on NOCARD",
+                   __func__);
+               biofinish(bp, NULL, ENXIO);
+               break;
+
+       case ALTERA_SDCARD_STATE_BADCARD:
+               device_printf(sc->as_dev, "%s: unexpected I/O on BADCARD",
+                   __func__);
+               biofinish(bp, NULL, ENXIO);
+               break;
+
+       case ALTERA_SDCARD_STATE_DETACHED:
+               device_printf(sc->as_dev, "%s: unexpected I/O on DETACHED",
+                   __func__);
+               biofinish(bp, NULL, ENXIO);
+
+       case ALTERA_SDCARD_STATE_IDLE:
+               bioq_disksort(&sc->as_bioq, bp);
+               altera_sdcard_start(sc);
+               break;
+
+       case ALTERA_SDCARD_STATE_IO:
+               bioq_disksort(&sc->as_bioq, bp);
+               break;
+
+       default:
+               panic("%s: invalid state %d", __func__, sc->as_state);
+       }
+       ALTERA_SDCARD_UNLOCK(sc);
+}
+
+void
+altera_sdcard_disk_insert(struct altera_sdcard_softc *sc)
+{
+       struct disk *disk;
+       uint64_t size;
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+
+       /*
+        * Because the disk insertion routine occupies the driver instance's
+        * task queue thread, and the disk(9) instance isn't hooked up yet by
+        * definition, the only other source of events of concern is a thread
+        * initiating driver detach.  That thread has to issue a detach
+        * request and await an ACK from the taskqueue thread.  It is
+        * therefore safe to drop the lock here.
+        */
+       ALTERA_SDCARD_UNLOCK(sc);
+       disk = disk_alloc();
+       disk->d_drv1 = sc;
+       disk->d_name = "altera_sdcard";
+       disk->d_unit = sc->as_unit;
+       disk->d_strategy = altera_sdcard_disk_strategy;
+       disk->d_dump = altera_sdcard_disk_dump;
+       disk->d_ioctl = altera_sdcard_disk_ioctl;
+       disk->d_sectorsize = ALTERA_SDCARD_SECTORSIZE;
+       disk->d_mediasize = sc->as_mediasize;
+       disk->d_maxsize = ALTERA_SDCARD_SECTORSIZE;
+       sc->as_disk = disk;
+       disk_create(disk, DISK_VERSION);
+       ALTERA_SDCARD_LOCK(sc);
+
+       /*
+        * Print a pretty-ish card insertion string.  We could stand to
+        * decorate this further, e.g., with card vendor information.
+        */
+       size = sc->as_mediasize / (1000 * 1000);
+       device_printf(sc->as_dev, "%juM SD Card inserted\n", (uintmax_t)size);
+}
+
+void
+altera_sdcard_disk_remove(struct altera_sdcard_softc *sc)
+{
+       struct disk *disk;
+
+       ALTERA_SDCARD_LOCK_ASSERT(sc);
+       KASSERT(sc->as_disk != NULL, ("%s: as_disk NULL", __func__));
+
+       /*
+        * sc->as_state will be updated by the caller.
+        *
+        * XXXRW: Is it OK to call disk_destroy() under the mutex, or should
+        * we be deferring that to the calling context once it is released?
+        */
+       disk = sc->as_disk;
+       disk_gone(disk);
+       disk_destroy(disk);
+       sc->as_disk = NULL;
+
+       /*
+        * Cancel all outstanding I/O on the SD Card.
+        */
+       if (sc->as_currentbio != NULL) {
+               device_printf(sc->as_dev, "%s: SD Card removed during I/O",
+                   __func__);
+               biofinish(sc->as_currentbio, NULL, ENXIO);
+               sc->as_currentbio = NULL;
+       }
+       bioq_flush(&sc->as_bioq, NULL, ENXIO);
+       device_printf(sc->as_dev, "SD Card removed\n");
+}

Added: head/sys/dev/altera/sdcard/altera_sdcard_io.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/dev/altera/sdcard/altera_sdcard_io.c       Sat Aug 25 11:19:20 
2012        (r239675)
@@ -0,0 +1,447 @@
+/*-
+ * Copyright (c) 2012 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed by SRI International and the University of
+ * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
+ * ("CTSRD"), as part of the DARPA CRASH research programme.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to