altera_sdcard.c revision 245380
1239675Srwatson/*- 2239675Srwatson * Copyright (c) 2012 Robert N. M. Watson 3239675Srwatson * All rights reserved. 4239675Srwatson * 5239675Srwatson * This software was developed by SRI International and the University of 6239675Srwatson * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7239675Srwatson * ("CTSRD"), as part of the DARPA CRASH research programme. 8239675Srwatson * 9239675Srwatson * Redistribution and use in source and binary forms, with or without 10239675Srwatson * modification, are permitted provided that the following conditions 11239675Srwatson * are met: 12239675Srwatson * 1. Redistributions of source code must retain the above copyright 13239675Srwatson * notice, this list of conditions and the following disclaimer. 14239675Srwatson * 2. Redistributions in binary form must reproduce the above copyright 15239675Srwatson * notice, this list of conditions and the following disclaimer in the 16239675Srwatson * documentation and/or other materials provided with the distribution. 17239675Srwatson * 18239675Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19239675Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20239675Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21239675Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22239675Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23239675Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24239675Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25239675Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26239675Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27239675Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28239675Srwatson * SUCH DAMAGE. 29239675Srwatson */ 30239675Srwatson 31239675Srwatson#include <sys/cdefs.h> 32239675Srwatson__FBSDID("$FreeBSD: head/sys/dev/altera/sdcard/altera_sdcard.c 245380 2013-01-13 16:57:11Z rwatson $"); 33239675Srwatson 34239675Srwatson#include <sys/param.h> 35239675Srwatson#include <sys/bus.h> 36239675Srwatson#include <sys/condvar.h> 37239675Srwatson#include <sys/conf.h> 38239675Srwatson#include <sys/bio.h> 39239675Srwatson#include <sys/kernel.h> 40239675Srwatson#include <sys/lock.h> 41239675Srwatson#include <sys/malloc.h> 42239675Srwatson#include <sys/module.h> 43239675Srwatson#include <sys/mutex.h> 44239675Srwatson#include <sys/rman.h> 45239675Srwatson#include <sys/systm.h> 46239675Srwatson#include <sys/taskqueue.h> 47239675Srwatson 48239675Srwatson#include <machine/bus.h> 49239675Srwatson#include <machine/resource.h> 50239675Srwatson 51239675Srwatson#include <geom/geom_disk.h> 52239675Srwatson 53239675Srwatson#include <dev/altera/sdcard/altera_sdcard.h> 54239675Srwatson 55239675Srwatson/* 56239675Srwatson * Device driver for the Altera University Program Secure Data Card IP Core, 57239675Srwatson * as described in the similarly named SOPC Builder IP Core specification. 58239675Srwatson * This soft core is not a full SD host controller interface (SDHCI) but 59239675Srwatson * instead provides a set of memory mapped registers and memory buffer that 60239675Srwatson * mildly abstract the SD Card protocol, but without providing DMA or 61239675Srwatson * interrupts. However, it does hide the details of voltage and 62239675Srwatson * communications negotiation. This driver implements disk(9), but due to the 63239675Srwatson * lack of interrupt support, must rely on timer-driven polling to determine 64239675Srwatson * when I/Os have completed. 65239675Srwatson * 66239675Srwatson * TODO: 67239675Srwatson * 68239675Srwatson * 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support. 69239675Srwatson * 2. Implement d_ident from SD Card CID serial number field. 70239675Srwatson * 3. Handle read-only SD Cards. 71239675Srwatson * 4. Tune timeouts based on real-world SD Card speeds. 72239675Srwatson */ 73245380Srwatsondevclass_t altera_sdcard_devclass; 74239675Srwatson 75239675Srwatsonvoid 76239675Srwatsonaltera_sdcard_attach(struct altera_sdcard_softc *sc) 77239675Srwatson{ 78239675Srwatson 79239675Srwatson ALTERA_SDCARD_LOCK_INIT(sc); 80239675Srwatson ALTERA_SDCARD_CONDVAR_INIT(sc); 81239675Srwatson sc->as_disk = NULL; 82239675Srwatson bioq_init(&sc->as_bioq); 83239675Srwatson sc->as_currentbio = NULL; 84239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 85239675Srwatson sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK, 86239675Srwatson taskqueue_thread_enqueue, &sc->as_taskqueue); 87239675Srwatson taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK, 88239675Srwatson "altera_sdcardc%d taskqueue", sc->as_unit); 89239675Srwatson TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0, 90239675Srwatson altera_sdcard_task, sc); 91239675Srwatson 92239675Srwatson /* 93239675Srwatson * Kick off timer-driven processing with a manual poll so that we 94239675Srwatson * synchronously detect an already-inserted SD Card during the boot or 95239675Srwatson * other driver attach point. 96239675Srwatson */ 97239675Srwatson altera_sdcard_task(sc, 1); 98239675Srwatson} 99239675Srwatson 100239675Srwatsonvoid 101239675Srwatsonaltera_sdcard_detach(struct altera_sdcard_softc *sc) 102239675Srwatson{ 103239675Srwatson 104239675Srwatson KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present", 105239675Srwatson __func__)); 106239675Srwatson 107239675Srwatson /* 108239675Srwatson * Winding down the driver on detach is a bit complex. Update the 109239675Srwatson * flags to indicate that a detach has been requested, and then wait 110239675Srwatson * for in-progress I/O to wind down before continuing. 111239675Srwatson */ 112239675Srwatson ALTERA_SDCARD_LOCK(sc); 113239675Srwatson sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ; 114239675Srwatson while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED) 115239675Srwatson ALTERA_SDCARD_CONDVAR_WAIT(sc); 116239675Srwatson ALTERA_SDCARD_UNLOCK(sc); 117239675Srwatson 118239675Srwatson /* 119239675Srwatson * Now wait for the possibly still executing taskqueue to drain. In 120239675Srwatson * principle no more events will be scheduled as we've transitioned to 121239675Srwatson * a detached state, but there might still be a request in execution. 122239675Srwatson */ 123239675Srwatson while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL)) 124239675Srwatson taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task); 125239675Srwatson 126239675Srwatson /* 127239675Srwatson * Simulate a disk removal if one is present to deal with any pending 128239675Srwatson * or queued I/O. 129239675Srwatson */ 130239675Srwatson if (sc->as_disk != NULL) 131239675Srwatson altera_sdcard_disk_remove(sc); 132239675Srwatson KASSERT(bioq_first(&sc->as_bioq) == NULL, 133239675Srwatson ("%s: non-empty bioq", __func__)); 134239675Srwatson 135239675Srwatson /* 136239675Srwatson * Free any remaining allocated resources. 137239675Srwatson */ 138239675Srwatson taskqueue_free(sc->as_taskqueue); 139239675Srwatson sc->as_taskqueue = NULL; 140239675Srwatson ALTERA_SDCARD_CONDVAR_DESTROY(sc); 141239675Srwatson ALTERA_SDCARD_LOCK_DESTROY(sc); 142239675Srwatson} 143239675Srwatson 144239675Srwatson/* 145239675Srwatson * Set up and start the next I/O. Transition to the I/O state, but allow the 146239675Srwatson * caller to schedule the next timeout, as this may be called either from an 147239675Srwatson * initial attach context, or from the task queue, which requires different 148239675Srwatson * behaviour. 149239675Srwatson */ 150239675Srwatsonstatic void 151239675Srwatsonaltera_sdcard_nextio(struct altera_sdcard_softc *sc) 152239675Srwatson{ 153239675Srwatson struct bio *bp; 154239675Srwatson 155239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 156239675Srwatson KASSERT(sc->as_currentbio == NULL, 157239675Srwatson ("%s: bio already active", __func__)); 158239675Srwatson 159239675Srwatson bp = bioq_takefirst(&sc->as_bioq); 160239675Srwatson if (bp == NULL) 161239675Srwatson panic("%s: bioq empty", __func__); 162239675Srwatson altera_sdcard_io_start(sc, bp); 163239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_IO; 164239675Srwatson} 165239675Srwatson 166239675Srwatsonstatic void 167239675Srwatsonaltera_sdcard_task_nocard(struct altera_sdcard_softc *sc) 168239675Srwatson{ 169239675Srwatson 170239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 171239675Srwatson 172239675Srwatson /* 173239675Srwatson * Handle device driver detach. 174239675Srwatson */ 175239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 176239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 177239675Srwatson return; 178239675Srwatson } 179239675Srwatson 180239675Srwatson /* 181239675Srwatson * If there is no card insertion, remain in NOCARD. 182239675Srwatson */ 183239675Srwatson if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 184239675Srwatson return; 185239675Srwatson 186239675Srwatson /* 187239675Srwatson * Read the CSD -- it may contain values that the driver can't handle, 188239675Srwatson * either because of an unsupported version/feature, or because the 189239675Srwatson * card is misbehaving. This triggers a transition to 190239675Srwatson * ALTERA_SDCARD_STATE_BADCARD. We rely on the CSD read to print a 191239675Srwatson * banner about how the card is problematic, since it has more 192239675Srwatson * information. The bad card state allows us to print that banner 193239675Srwatson * once rather than each time we notice the card is there, and still 194239675Srwatson * bad. 195239675Srwatson */ 196239675Srwatson if (altera_sdcard_read_csd(sc) != 0) { 197239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_BADCARD; 198239675Srwatson return; 199239675Srwatson } 200239675Srwatson 201239675Srwatson /* 202239675Srwatson * Process card insertion and upgrade to the IDLE state. 203239675Srwatson */ 204239675Srwatson altera_sdcard_disk_insert(sc); 205239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_IDLE; 206239675Srwatson} 207239675Srwatson 208239675Srwatsonstatic void 209239675Srwatsonaltera_sdcard_task_badcard(struct altera_sdcard_softc *sc) 210239675Srwatson{ 211239675Srwatson 212239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 213239675Srwatson 214239675Srwatson /* 215239675Srwatson * Handle device driver detach. 216239675Srwatson */ 217239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 218239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 219239675Srwatson return; 220239675Srwatson } 221239675Srwatson 222239675Srwatson /* 223239675Srwatson * Handle safe card removal -- no teardown is required, just a state 224239675Srwatson * transition. 225239675Srwatson */ 226239675Srwatson if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 227239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 228239675Srwatson} 229239675Srwatson 230239675Srwatsonstatic void 231239675Srwatsonaltera_sdcard_task_idle(struct altera_sdcard_softc *sc) 232239675Srwatson{ 233239675Srwatson 234239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 235239675Srwatson 236239675Srwatson /* 237239675Srwatson * Handle device driver detach. 238239675Srwatson */ 239239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 240239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 241239675Srwatson return; 242239675Srwatson } 243239675Srwatson 244239675Srwatson /* 245239675Srwatson * Handle safe card removal. 246239675Srwatson */ 247239675Srwatson if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) { 248239675Srwatson altera_sdcard_disk_remove(sc); 249239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 250239675Srwatson } 251239675Srwatson} 252239675Srwatson 253239675Srwatsonstatic void 254239675Srwatsonaltera_sdcard_task_io(struct altera_sdcard_softc *sc) 255239675Srwatson{ 256239675Srwatson uint16_t asr; 257239675Srwatson 258239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 259239675Srwatson KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__)); 260239675Srwatson 261239675Srwatson asr = altera_sdcard_read_asr(sc); 262239675Srwatson 263239675Srwatson /* 264239675Srwatson * Check for unexpected card removal during an I/O. 265239675Srwatson */ 266239675Srwatson if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) { 267239675Srwatson altera_sdcard_disk_remove(sc); 268239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) 269239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 270239675Srwatson else 271239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 272239675Srwatson return; 273239675Srwatson } 274239675Srwatson 275239675Srwatson /* 276239675Srwatson * If the I/O isn't complete, remain in the IO state without further 277239675Srwatson * action, even if DETACHREQ is in flight. 278239675Srwatson */ 279239675Srwatson if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS) 280239675Srwatson return; 281239675Srwatson 282239675Srwatson /* 283239675Srwatson * Handle various forms of I/O completion, successful and otherwise. 284239675Srwatson * The I/O layer may restart the transaction if an error occurred, in 285239675Srwatson * which case remain in the IO state and reschedule. 286239675Srwatson */ 287239675Srwatson if (!altera_sdcard_io_complete(sc, asr)) 288239675Srwatson return; 289239675Srwatson 290239675Srwatson /* 291239675Srwatson * Now that I/O is complete, process detach requests in preference to 292239675Srwatson * starting new I/O. 293239675Srwatson */ 294239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 295239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 296239675Srwatson return; 297239675Srwatson } 298239675Srwatson 299239675Srwatson /* 300239675Srwatson * Finally, either start the next I/O or transition to the IDLE state. 301239675Srwatson */ 302239675Srwatson if (bioq_first(&sc->as_bioq) != NULL) 303239675Srwatson altera_sdcard_nextio(sc); 304239675Srwatson else 305239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_IDLE; 306239675Srwatson} 307239675Srwatson 308239675Srwatsonstatic void 309239675Srwatsonaltera_sdcard_task_rechedule(struct altera_sdcard_softc *sc) 310239675Srwatson{ 311239675Srwatson int interval; 312239675Srwatson 313239675Srwatson /* 314239675Srwatson * Reschedule based on new state. Or not, if detaching the device 315239675Srwatson * driver. Treat a bad card as though it were no card at all. 316239675Srwatson */ 317239675Srwatson switch (sc->as_state) { 318239675Srwatson case ALTERA_SDCARD_STATE_NOCARD: 319239675Srwatson case ALTERA_SDCARD_STATE_BADCARD: 320239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_NOCARD; 321239675Srwatson break; 322239675Srwatson 323239675Srwatson case ALTERA_SDCARD_STATE_IDLE: 324239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_IDLE; 325239675Srwatson break; 326239675Srwatson 327239675Srwatson case ALTERA_SDCARD_STATE_IO: 328239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) 329239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_IOERROR; 330239675Srwatson else 331239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_IO; 332239675Srwatson break; 333239675Srwatson 334239675Srwatson default: 335239675Srwatson panic("%s: invalid exit state %d", __func__, sc->as_state); 336239675Srwatson } 337239675Srwatson taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval); 338239675Srwatson} 339239675Srwatson 340239675Srwatson/* 341239675Srwatson * Because the Altera SD Card IP Core doesn't support interrupts, we do all 342239675Srwatson * asynchronous work from a timeout. Poll at two different rates -- an 343239675Srwatson * infrequent check for card insertion status changes, and a frequent one for 344239675Srwatson * I/O completion. The task should never start in DETACHED, as that would 345239675Srwatson * imply that a previous instance failed to cancel rather than reschedule. 346239675Srwatson */ 347239675Srwatsonvoid 348239675Srwatsonaltera_sdcard_task(void *arg, int pending) 349239675Srwatson{ 350239675Srwatson struct altera_sdcard_softc *sc; 351239675Srwatson 352239675Srwatson sc = arg; 353239675Srwatson KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED, 354239675Srwatson ("%s: already in detached", __func__)); 355239675Srwatson 356239675Srwatson ALTERA_SDCARD_LOCK(sc); 357239675Srwatson switch (sc->as_state) { 358239675Srwatson case ALTERA_SDCARD_STATE_NOCARD: 359239675Srwatson altera_sdcard_task_nocard(sc); 360239675Srwatson break; 361239675Srwatson 362239675Srwatson case ALTERA_SDCARD_STATE_BADCARD: 363239675Srwatson altera_sdcard_task_badcard(sc); 364239675Srwatson break; 365239675Srwatson 366239675Srwatson case ALTERA_SDCARD_STATE_IDLE: 367239675Srwatson altera_sdcard_task_idle(sc); 368239675Srwatson break; 369239675Srwatson 370239675Srwatson case ALTERA_SDCARD_STATE_IO: 371239675Srwatson altera_sdcard_task_io(sc); 372239675Srwatson break; 373239675Srwatson 374239675Srwatson default: 375239675Srwatson panic("%s: invalid enter state %d", __func__, sc->as_state); 376239675Srwatson } 377239675Srwatson 378239675Srwatson /* 379239675Srwatson * If we have transitioned to DETACHED, signal the detach thread and 380239675Srwatson * cancel the timeout-driven task. Otherwise reschedule on an 381239675Srwatson * appropriate timeout. 382239675Srwatson */ 383239675Srwatson if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED) 384239675Srwatson ALTERA_SDCARD_CONDVAR_SIGNAL(sc); 385239675Srwatson else 386239675Srwatson altera_sdcard_task_rechedule(sc); 387239675Srwatson ALTERA_SDCARD_UNLOCK(sc); 388239675Srwatson} 389239675Srwatson 390239675Srwatsonvoid 391239675Srwatsonaltera_sdcard_start(struct altera_sdcard_softc *sc) 392239675Srwatson{ 393239675Srwatson 394239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 395239675Srwatson 396239675Srwatson KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE, 397239675Srwatson ("%s: starting when not IDLE", __func__)); 398239675Srwatson 399239675Srwatson taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL); 400239675Srwatson altera_sdcard_nextio(sc); 401239675Srwatson taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, 402239675Srwatson ALTERA_SDCARD_TIMEOUT_IO); 403239675Srwatson} 404