From owner-svn-src-head@FreeBSD.ORG Sat Aug 25 11:19:20 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id CBA6F106566B; Sat, 25 Aug 2012 11:19:20 +0000 (UTC) (envelope-from rwatson@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id B38CE8FC12; Sat, 25 Aug 2012 11:19:20 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q7PBJK6J029552; Sat, 25 Aug 2012 11:19:20 GMT (envelope-from rwatson@svn.freebsd.org) Received: (from rwatson@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q7PBJKtf029543; Sat, 25 Aug 2012 11:19:20 GMT (envelope-from rwatson@svn.freebsd.org) Message-Id: <201208251119.q7PBJKtf029543@svn.freebsd.org> From: Robert Watson Date: Sat, 25 Aug 2012 11:19:20 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r239675 - in head: share/man/man4 sys/conf sys/dev/altera/sdcard X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Aug 2012 11:19:20 -0000 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +/* + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +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 ***