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
This commit is contained in:
parent
cf8248866d
commit
d432e92a84
@ -33,6 +33,7 @@ MAN= aac.4 \
|
||||
ale.4 \
|
||||
alpm.4 \
|
||||
altera_avgen.4 \
|
||||
altera_sdcard.4 \
|
||||
altq.4 \
|
||||
amdpm.4 \
|
||||
${_amdsbwd.4} \
|
||||
|
118
share/man/man4/altera_sdcard.4
Normal file
118
share/man/man4/altera_sdcard.4
Normal file
@ -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.
|
@ -660,6 +660,10 @@ dev/aic7xxx/aic7xxx_pci.c optional ahc pci
|
||||
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
|
||||
|
402
sys/dev/altera/sdcard/altera_sdcard.c
Normal file
402
sys/dev/altera/sdcard/altera_sdcard.c
Normal file
@ -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);
|
||||
}
|
247
sys/dev/altera/sdcard/altera_sdcard.h
Normal file
247
sys/dev/altera/sdcard/altera_sdcard.h
Normal file
@ -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_ */
|
185
sys/dev/altera/sdcard/altera_sdcard_disk.c
Normal file
185
sys/dev/altera/sdcard/altera_sdcard_disk.c
Normal file
@ -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");
|
||||
}
|
447
sys/dev/altera/sdcard/altera_sdcard_io.c
Normal file
447
sys/dev/altera/sdcard/altera_sdcard_io.c
Normal file
@ -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
|
||||
* 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/endian.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>
|
||||
|
||||
int altera_sdcard_ignore_crc_errors = 1;
|
||||
int altera_sdcard_verify_rxtx_writes = 1;
|
||||
|
||||
/*
|
||||
* Low-level I/O routines for the Altera SD Card University IP Core driver.
|
||||
*
|
||||
* XXXRW: Throughout, it is assumed that the IP Core handles multibyte
|
||||
* registers as little endian, as is the case for other Altera IP cores.
|
||||
* However, the specification makes no reference to endianness, so this
|
||||
* assumption might not always be correct.
|
||||
*/
|
||||
uint16_t
|
||||
altera_sdcard_read_asr(struct altera_sdcard_softc *sc)
|
||||
{
|
||||
|
||||
return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_ASR)));
|
||||
}
|
||||
|
||||
static int
|
||||
altera_sdcard_process_csd0(struct altera_sdcard_softc *sc)
|
||||
{
|
||||
uint64_t c_size, c_size_mult, read_bl_len;
|
||||
uint8_t byte0, byte1, byte2;
|
||||
|
||||
ALTERA_SDCARD_LOCK_ASSERT(sc);
|
||||
|
||||
/*-
|
||||
* Compute card capacity per SD Card interface description as follows:
|
||||
*
|
||||
* Memory capacity = BLOCKNR * BLOCK_LEN
|
||||
*
|
||||
* Where:
|
||||
*
|
||||
* BLOCKNR = (C_SIZE + 1) * MULT
|
||||
* MULT = 2^(C_SIZE_MULT+2)
|
||||
* BLOCK_LEN = 2^READ_BL_LEN
|
||||
*/
|
||||
read_bl_len = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE];
|
||||
read_bl_len &= ALTERA_SDCARD_CSD_READ_BL_LEN_MASK;
|
||||
|
||||
byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
|
||||
byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
|
||||
byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
|
||||
byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
|
||||
c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
|
||||
(byte0 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
|
||||
|
||||
byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE0];
|
||||
byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MASK0;
|
||||
byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE1];
|
||||
byte2 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE2];
|
||||
byte2 &= ALTERA_SDCARD_CSD_C_SIZE_MASK2;
|
||||
c_size = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0) |
|
||||
(byte1 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1) |
|
||||
(byte2 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2);
|
||||
|
||||
byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
|
||||
byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
|
||||
byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
|
||||
byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
|
||||
c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
|
||||
(byte1 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
|
||||
|
||||
/*
|
||||
* If we're just getting back zero's, mark the card as bad, even
|
||||
* though it could just mean a Very Small Disk Indeed.
|
||||
*/
|
||||
if (c_size == 0 && c_size_mult == 0 && read_bl_len == 0) {
|
||||
device_printf(sc->as_dev, "Ignored zero-size card\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
sc->as_mediasize = (c_size + 1) * (1 << (c_size_mult + 2)) *
|
||||
(1 << read_bl_len);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
altera_sdcard_read_csd(struct altera_sdcard_softc *sc)
|
||||
{
|
||||
uint8_t csd_structure;
|
||||
int error;
|
||||
|
||||
ALTERA_SDCARD_LOCK_ASSERT(sc);
|
||||
|
||||
/*
|
||||
* XXXRW: Assume for now that when the SD Card IP Core negotiates
|
||||
* voltage/speed/etc, it must use the CSD register, and therefore
|
||||
* populates the SD Card IP Core's cache of the register value. This
|
||||
* means that we can read it without issuing further SD Card commands.
|
||||
* If this assumption proves false, we will (a) get back garbage and
|
||||
* (b) need to add additional states in the driver state machine in
|
||||
* order to query card properties before I/O can start.
|
||||
*
|
||||
* XXXRW: Treating this as an array of bytes, so no byte swapping --
|
||||
* is that a safe assumption?
|
||||
*/
|
||||
KASSERT(((uintptr_t)&sc->as_csd.csd_data) % 2 == 0,
|
||||
("%s: CSD buffer unaligned", __func__));
|
||||
bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_CSD,
|
||||
(uint16_t *)sc->as_csd.csd_data, sizeof(sc->as_csd) / 2);
|
||||
|
||||
/*
|
||||
* Interpret the loaded CSD, extracting certain fields and copying
|
||||
* them into the softc for easy software access.
|
||||
*
|
||||
* Currently, we support only CSD Version 1.0. If we detect a newer
|
||||
* version, suppress card detection.
|
||||
*/
|
||||
csd_structure = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_STRUCTURE_BYTE];
|
||||
csd_structure &= ALTERA_SDCARD_CSD_STRUCTURE_MASK;
|
||||
csd_structure >>= ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT;
|
||||
sc->as_csd_structure = csd_structure;
|
||||
|
||||
/*
|
||||
* Interpret the CSD field based on its version. Extract fields,
|
||||
* especially mediasize.
|
||||
*
|
||||
* XXXRW: Desirable to support further CSD versions here.
|
||||
*/
|
||||
switch (sc->as_csd_structure) {
|
||||
case 0:
|
||||
error = altera_sdcard_process_csd0(sc);
|
||||
if (error)
|
||||
return (error);
|
||||
break;
|
||||
|
||||
default:
|
||||
device_printf(sc->as_dev,
|
||||
"Ignored disk with unsupported CSD structure (%d)\n",
|
||||
sc->as_csd_structure);
|
||||
return (ENXIO);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXRW: The Altera IP Core specification indicates that RR1 is a 16-bit
|
||||
* register, but all bits it identifies are >16 bit. Most likely, RR1 is a
|
||||
* 32-bit register?
|
||||
*/
|
||||
static uint16_t
|
||||
altera_sdcard_read_rr1(struct altera_sdcard_softc *sc)
|
||||
{
|
||||
|
||||
return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_RR1)));
|
||||
}
|
||||
|
||||
static void
|
||||
altera_sdcard_write_cmd_arg(struct altera_sdcard_softc *sc, uint32_t cmd_arg)
|
||||
{
|
||||
|
||||
bus_write_4(sc->as_res, ALTERA_SDCARD_OFF_CMD_ARG, htole32(cmd_arg));
|
||||
}
|
||||
|
||||
static void
|
||||
altera_sdcard_write_cmd(struct altera_sdcard_softc *sc, uint16_t cmd)
|
||||
{
|
||||
|
||||
bus_write_2(sc->as_res, ALTERA_SDCARD_OFF_CMD, htole16(cmd));
|
||||
}
|
||||
|
||||
static void
|
||||
altera_sdcard_read_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
|
||||
size_t len)
|
||||
{
|
||||
|
||||
KASSERT((uintptr_t)data % 2 == 0,
|
||||
("%s: unaligned data %p", __func__, data));
|
||||
KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
|
||||
("%s: invalid length %ju", __func__, len));
|
||||
|
||||
bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
|
||||
(uint16_t *)data, len / 2);
|
||||
}
|
||||
|
||||
static void
|
||||
altera_sdcard_write_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
|
||||
size_t len)
|
||||
{
|
||||
u_int corrections, differences, i, retry_counter;
|
||||
uint16_t d, v;
|
||||
|
||||
KASSERT((uintptr_t)data % 2 == 0,
|
||||
("%s: unaligned data %p", __func__, data));
|
||||
KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
|
||||
("%s: invalid length %ju", __func__, len));
|
||||
|
||||
retry_counter = 0;
|
||||
do {
|
||||
bus_write_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
|
||||
(uint16_t *)data, len / 2);
|
||||
|
||||
/*
|
||||
* XXXRW: Due to a possible hardware bug, the above call to
|
||||
* bus_write_region_2() might not succeed. If the workaround
|
||||
* is enabled, verify each write and retry until it succeeds.
|
||||
*
|
||||
* XXXRW: Do we want a limit counter for retries here?
|
||||
*/
|
||||
recheck:
|
||||
corrections = 0;
|
||||
differences = 0;
|
||||
if (altera_sdcard_verify_rxtx_writes) {
|
||||
for (i = 0; i < ALTERA_SDCARD_SECTORSIZE; i += 2) {
|
||||
v = bus_read_2(sc->as_res,
|
||||
ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
|
||||
d = *(uint16_t *)((uint8_t *)data + i);
|
||||
if (v != d) {
|
||||
if (retry_counter == 0) {
|
||||
bus_write_2(sc->as_res,
|
||||
ALTERA_SDCARD_OFF_RXTX_BUFFER + i,
|
||||
d);
|
||||
v = bus_read_2(sc->as_res,
|
||||
ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
|
||||
if (v == d) {
|
||||
corrections++;
|
||||
device_printf(sc->as_dev,
|
||||
"%s: single word rewrite worked"
|
||||
" at offset %u\n",
|
||||
__func__, i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
differences++;
|
||||
device_printf(sc->as_dev,
|
||||
"%s: retrying write -- difference"
|
||||
" %u at offset %u, retry %u\n",
|
||||
__func__, differences, i,
|
||||
retry_counter);
|
||||
}
|
||||
}
|
||||
if (differences != 0) {
|
||||
retry_counter++;
|
||||
if (retry_counter == 1 &&
|
||||
corrections == differences)
|
||||
goto recheck;
|
||||
}
|
||||
}
|
||||
} while (differences != 0);
|
||||
if (retry_counter)
|
||||
device_printf(sc->as_dev, "%s: succeeded after %u retries\n",
|
||||
__func__, retry_counter);
|
||||
}
|
||||
|
||||
static void
|
||||
altera_sdcard_io_start_internal(struct altera_sdcard_softc *sc, struct bio *bp)
|
||||
{
|
||||
|
||||
switch (bp->bio_cmd) {
|
||||
case BIO_READ:
|
||||
altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
|
||||
ALTERA_SDCARD_SECTORSIZE);
|
||||
altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_READ_BLOCK);
|
||||
break;
|
||||
|
||||
case BIO_WRITE:
|
||||
altera_sdcard_write_rxtx_buffer(sc, bp->bio_data,
|
||||
bp->bio_bcount);
|
||||
altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
|
||||
ALTERA_SDCARD_SECTORSIZE);
|
||||
altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_WRITE_BLOCK);
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unsupported I/O operation %d", __func__,
|
||||
bp->bio_cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
altera_sdcard_io_start(struct altera_sdcard_softc *sc, struct bio *bp)
|
||||
{
|
||||
|
||||
ALTERA_SDCARD_LOCK_ASSERT(sc);
|
||||
KASSERT(sc->as_currentbio == NULL,
|
||||
("%s: bio already started", __func__));
|
||||
|
||||
/*
|
||||
* We advertise a block size and maximum I/O size up the stack of the
|
||||
* SD Card IP Core sector size. Catch any attempts to not follow the
|
||||
* rules.
|
||||
*/
|
||||
KASSERT(bp->bio_bcount == ALTERA_SDCARD_SECTORSIZE,
|
||||
("%s: I/O size not %d", __func__, ALTERA_SDCARD_SECTORSIZE));
|
||||
altera_sdcard_io_start_internal(sc, bp);
|
||||
sc->as_currentbio = bp;
|
||||
sc->as_retriesleft = ALTERA_SDCARD_RETRY_LIMIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle completed I/O. ASR is passed in to avoid reading it more than once.
|
||||
* Return 1 if the I/O is actually complete (success, or retry limit
|
||||
* exceeded), or 0 if not.
|
||||
*/
|
||||
int
|
||||
altera_sdcard_io_complete(struct altera_sdcard_softc *sc, uint16_t asr)
|
||||
{
|
||||
struct bio *bp;
|
||||
uint16_t rr1, mask;
|
||||
int error;
|
||||
|
||||
ALTERA_SDCARD_LOCK_ASSERT(sc);
|
||||
KASSERT(!(asr & ALTERA_SDCARD_ASR_CMDINPROGRESS),
|
||||
("%s: still in progress", __func__));
|
||||
KASSERT(asr & ALTERA_SDCARD_ASR_CARDPRESENT,
|
||||
("%s: card removed", __func__));
|
||||
|
||||
bp = sc->as_currentbio;
|
||||
|
||||
/*-
|
||||
* Handle I/O retries if an error is returned by the device. Various
|
||||
* quirks handled in the process:
|
||||
*
|
||||
* 1. ALTERA_SDCARD_ASR_CMDDATAERROR is ignored for BIO_WRITE.
|
||||
* 2. ALTERA_SDCARD_RR1_COMMANDCRCFAILED is optionally ignored for
|
||||
* BIO_READ.
|
||||
*/
|
||||
error = 0;
|
||||
rr1 = altera_sdcard_read_rr1(sc);
|
||||
switch (bp->bio_cmd) {
|
||||
case BIO_READ:
|
||||
mask = ALTERA_SDCARD_RR1_ERRORMASK;
|
||||
if (altera_sdcard_ignore_crc_errors)
|
||||
mask &= ~ALTERA_SDCARD_RR1_COMMANDCRCFAILED;
|
||||
if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
|
||||
error = EIO;
|
||||
else if ((asr & ALTERA_SDCARD_ASR_CMDDATAERROR) &&
|
||||
(rr1 & mask))
|
||||
error = EIO;
|
||||
else
|
||||
error = 0;
|
||||
break;
|
||||
|
||||
case BIO_WRITE:
|
||||
if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
|
||||
error = EIO;
|
||||
else
|
||||
error = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (error) {
|
||||
/*
|
||||
* This attempt experienced an error; possibly retry.
|
||||
*/
|
||||
sc->as_retriesleft--;
|
||||
if (sc->as_retriesleft != 0) {
|
||||
sc->as_flags |= ALTERA_SDCARD_FLAG_IOERROR;
|
||||
altera_sdcard_io_start_internal(sc, bp);
|
||||
return (0);
|
||||
}
|
||||
device_printf(sc->as_dev, "%s: %s operation block %ju length "
|
||||
"%ju failed; asr 0x%08x (rr1: 0x%04x)\n", __func__,
|
||||
bp->bio_cmd == BIO_READ ? "BIO_READ" :
|
||||
(bp->bio_cmd == BIO_WRITE ? "BIO_WRITE" : "unknown"),
|
||||
bp->bio_pblkno, bp->bio_bcount, asr, rr1);
|
||||
sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
|
||||
} else {
|
||||
/*
|
||||
* Successful I/O completion path.
|
||||
*/
|
||||
if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) {
|
||||
device_printf(sc->as_dev, "%s: %s operation block %ju"
|
||||
" length %ju succeeded after %d retries\n",
|
||||
__func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
|
||||
(bp->bio_cmd == BIO_WRITE ? "write" : "unknown"),
|
||||
bp->bio_pblkno, bp->bio_bcount,
|
||||
ALTERA_SDCARD_RETRY_LIMIT - sc->as_retriesleft);
|
||||
sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
|
||||
}
|
||||
switch (bp->bio_cmd) {
|
||||
case BIO_READ:
|
||||
altera_sdcard_read_rxtx_buffer(sc, bp->bio_data,
|
||||
bp->bio_bcount);
|
||||
break;
|
||||
|
||||
case BIO_WRITE:
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unsupported I/O operation %d", __func__,
|
||||
bp->bio_cmd);
|
||||
}
|
||||
bp->bio_resid = 0;
|
||||
error = 0;
|
||||
}
|
||||
biofinish(bp, NULL, error);
|
||||
sc->as_currentbio = NULL;
|
||||
return (1);
|
||||
}
|
116
sys/dev/altera/sdcard/altera_sdcard_nexus.c
Normal file
116
sys/dev/altera/sdcard/altera_sdcard_nexus.c
Normal file
@ -0,0 +1,116 @@
|
||||
/*-
|
||||
* 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>
|
||||
|
||||
/*
|
||||
* Nexus bus attachment for the Altera SD Card IP core. Appropriate for most
|
||||
* Altera FPGA SoC-style configurations in which the IP core will be exposed
|
||||
* to the processor via a memory-mapped Avalon bus.
|
||||
*/
|
||||
static int
|
||||
altera_sdcard_nexus_probe(device_t dev)
|
||||
{
|
||||
|
||||
device_set_desc(dev, "Altera Secure Data Card IP Core");
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
altera_sdcard_nexus_attach(device_t dev)
|
||||
{
|
||||
struct altera_sdcard_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->as_dev = dev;
|
||||
sc->as_unit = device_get_unit(dev);
|
||||
sc->as_rid = 0;
|
||||
sc->as_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
&sc->as_rid, RF_ACTIVE);
|
||||
if (sc->as_res == NULL) {
|
||||
device_printf(dev, "couldn't map memory\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
altera_sdcard_attach(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
altera_sdcard_nexus_detach(device_t dev)
|
||||
{
|
||||
struct altera_sdcard_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
KASSERT(sc->as_res != NULL, ("%s: resources not allocated",
|
||||
__func__));
|
||||
altera_sdcard_detach(sc);
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, sc->as_rid, sc->as_res);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t altera_sdcard_nexus_methods[] = {
|
||||
DEVMETHOD(device_probe, altera_sdcard_nexus_probe),
|
||||
DEVMETHOD(device_attach, altera_sdcard_nexus_attach),
|
||||
DEVMETHOD(device_detach, altera_sdcard_nexus_detach),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t altera_sdcard_nexus_driver = {
|
||||
"altera_sdcardc",
|
||||
altera_sdcard_nexus_methods,
|
||||
sizeof(struct altera_sdcard_softc),
|
||||
};
|
||||
|
||||
static devclass_t altera_sdcard_devclass;
|
||||
|
||||
DRIVER_MODULE(altera_sdcard, nexus, altera_sdcard_nexus_driver,
|
||||
altera_sdcard_devclass, 0, 0);
|
Loading…
Reference in New Issue
Block a user