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$"); 33239675Srwatson 34256744Sbrooks#include "opt_altera_sdcard.h" 35256744Sbrooks 36239675Srwatson#include <sys/param.h> 37239675Srwatson#include <sys/bus.h> 38239675Srwatson#include <sys/condvar.h> 39239675Srwatson#include <sys/conf.h> 40239675Srwatson#include <sys/bio.h> 41239675Srwatson#include <sys/kernel.h> 42239675Srwatson#include <sys/lock.h> 43239675Srwatson#include <sys/malloc.h> 44239675Srwatson#include <sys/module.h> 45239675Srwatson#include <sys/mutex.h> 46239675Srwatson#include <sys/rman.h> 47239675Srwatson#include <sys/systm.h> 48239675Srwatson#include <sys/taskqueue.h> 49239675Srwatson 50239675Srwatson#include <machine/bus.h> 51239675Srwatson#include <machine/resource.h> 52239675Srwatson 53239675Srwatson#include <geom/geom_disk.h> 54239675Srwatson 55239675Srwatson#include <dev/altera/sdcard/altera_sdcard.h> 56239675Srwatson 57239675Srwatson/* 58239675Srwatson * Device driver for the Altera University Program Secure Data Card IP Core, 59239675Srwatson * as described in the similarly named SOPC Builder IP Core specification. 60239675Srwatson * This soft core is not a full SD host controller interface (SDHCI) but 61239675Srwatson * instead provides a set of memory mapped registers and memory buffer that 62239675Srwatson * mildly abstract the SD Card protocol, but without providing DMA or 63239675Srwatson * interrupts. However, it does hide the details of voltage and 64239675Srwatson * communications negotiation. This driver implements disk(9), but due to the 65239675Srwatson * lack of interrupt support, must rely on timer-driven polling to determine 66239675Srwatson * when I/Os have completed. 67239675Srwatson * 68239675Srwatson * TODO: 69239675Srwatson * 70239675Srwatson * 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support. 71239675Srwatson * 2. Implement d_ident from SD Card CID serial number field. 72239675Srwatson * 3. Handle read-only SD Cards. 73239675Srwatson * 4. Tune timeouts based on real-world SD Card speeds. 74239675Srwatson */ 75245380Srwatsondevclass_t altera_sdcard_devclass; 76239675Srwatson 77239675Srwatsonvoid 78239675Srwatsonaltera_sdcard_attach(struct altera_sdcard_softc *sc) 79239675Srwatson{ 80239675Srwatson 81239675Srwatson ALTERA_SDCARD_LOCK_INIT(sc); 82239675Srwatson ALTERA_SDCARD_CONDVAR_INIT(sc); 83239675Srwatson sc->as_disk = NULL; 84239675Srwatson bioq_init(&sc->as_bioq); 85239675Srwatson sc->as_currentbio = NULL; 86239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 87239675Srwatson sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK, 88239675Srwatson taskqueue_thread_enqueue, &sc->as_taskqueue); 89239675Srwatson taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK, 90239675Srwatson "altera_sdcardc%d taskqueue", sc->as_unit); 91239675Srwatson TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0, 92239675Srwatson altera_sdcard_task, sc); 93239675Srwatson 94239675Srwatson /* 95239675Srwatson * Kick off timer-driven processing with a manual poll so that we 96239675Srwatson * synchronously detect an already-inserted SD Card during the boot or 97239675Srwatson * other driver attach point. 98239675Srwatson */ 99239675Srwatson altera_sdcard_task(sc, 1); 100239675Srwatson} 101239675Srwatson 102239675Srwatsonvoid 103239675Srwatsonaltera_sdcard_detach(struct altera_sdcard_softc *sc) 104239675Srwatson{ 105239675Srwatson 106239675Srwatson KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present", 107239675Srwatson __func__)); 108239675Srwatson 109239675Srwatson /* 110239675Srwatson * Winding down the driver on detach is a bit complex. Update the 111239675Srwatson * flags to indicate that a detach has been requested, and then wait 112239675Srwatson * for in-progress I/O to wind down before continuing. 113239675Srwatson */ 114239675Srwatson ALTERA_SDCARD_LOCK(sc); 115239675Srwatson sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ; 116239675Srwatson while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED) 117239675Srwatson ALTERA_SDCARD_CONDVAR_WAIT(sc); 118239675Srwatson ALTERA_SDCARD_UNLOCK(sc); 119239675Srwatson 120239675Srwatson /* 121239675Srwatson * Now wait for the possibly still executing taskqueue to drain. In 122239675Srwatson * principle no more events will be scheduled as we've transitioned to 123239675Srwatson * a detached state, but there might still be a request in execution. 124239675Srwatson */ 125239675Srwatson while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL)) 126239675Srwatson taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task); 127239675Srwatson 128239675Srwatson /* 129239675Srwatson * Simulate a disk removal if one is present to deal with any pending 130239675Srwatson * or queued I/O. 131239675Srwatson */ 132239675Srwatson if (sc->as_disk != NULL) 133239675Srwatson altera_sdcard_disk_remove(sc); 134239675Srwatson KASSERT(bioq_first(&sc->as_bioq) == NULL, 135239675Srwatson ("%s: non-empty bioq", __func__)); 136239675Srwatson 137239675Srwatson /* 138239675Srwatson * Free any remaining allocated resources. 139239675Srwatson */ 140239675Srwatson taskqueue_free(sc->as_taskqueue); 141239675Srwatson sc->as_taskqueue = NULL; 142239675Srwatson ALTERA_SDCARD_CONDVAR_DESTROY(sc); 143239675Srwatson ALTERA_SDCARD_LOCK_DESTROY(sc); 144239675Srwatson} 145239675Srwatson 146239675Srwatson/* 147239675Srwatson * Set up and start the next I/O. Transition to the I/O state, but allow the 148239675Srwatson * caller to schedule the next timeout, as this may be called either from an 149239675Srwatson * initial attach context, or from the task queue, which requires different 150239675Srwatson * behaviour. 151239675Srwatson */ 152239675Srwatsonstatic void 153239675Srwatsonaltera_sdcard_nextio(struct altera_sdcard_softc *sc) 154239675Srwatson{ 155239675Srwatson struct bio *bp; 156239675Srwatson 157239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 158239675Srwatson KASSERT(sc->as_currentbio == NULL, 159239675Srwatson ("%s: bio already active", __func__)); 160239675Srwatson 161239675Srwatson bp = bioq_takefirst(&sc->as_bioq); 162239675Srwatson if (bp == NULL) 163239675Srwatson panic("%s: bioq empty", __func__); 164239675Srwatson altera_sdcard_io_start(sc, bp); 165239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_IO; 166239675Srwatson} 167239675Srwatson 168239675Srwatsonstatic void 169239675Srwatsonaltera_sdcard_task_nocard(struct altera_sdcard_softc *sc) 170239675Srwatson{ 171239675Srwatson 172239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 173239675Srwatson 174239675Srwatson /* 175239675Srwatson * Handle device driver detach. 176239675Srwatson */ 177239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 178239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 179239675Srwatson return; 180239675Srwatson } 181239675Srwatson 182239675Srwatson /* 183239675Srwatson * If there is no card insertion, remain in NOCARD. 184239675Srwatson */ 185239675Srwatson if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 186239675Srwatson return; 187239675Srwatson 188239675Srwatson /* 189239675Srwatson * Read the CSD -- it may contain values that the driver can't handle, 190239675Srwatson * either because of an unsupported version/feature, or because the 191239675Srwatson * card is misbehaving. This triggers a transition to 192239675Srwatson * ALTERA_SDCARD_STATE_BADCARD. We rely on the CSD read to print a 193239675Srwatson * banner about how the card is problematic, since it has more 194239675Srwatson * information. The bad card state allows us to print that banner 195239675Srwatson * once rather than each time we notice the card is there, and still 196239675Srwatson * bad. 197239675Srwatson */ 198239675Srwatson if (altera_sdcard_read_csd(sc) != 0) { 199239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_BADCARD; 200239675Srwatson return; 201239675Srwatson } 202239675Srwatson 203239675Srwatson /* 204239675Srwatson * Process card insertion and upgrade to the IDLE state. 205239675Srwatson */ 206239675Srwatson altera_sdcard_disk_insert(sc); 207239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_IDLE; 208239675Srwatson} 209239675Srwatson 210239675Srwatsonstatic void 211239675Srwatsonaltera_sdcard_task_badcard(struct altera_sdcard_softc *sc) 212239675Srwatson{ 213239675Srwatson 214239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 215239675Srwatson 216239675Srwatson /* 217239675Srwatson * Handle device driver detach. 218239675Srwatson */ 219239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 220239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 221239675Srwatson return; 222239675Srwatson } 223239675Srwatson 224239675Srwatson /* 225239675Srwatson * Handle safe card removal -- no teardown is required, just a state 226239675Srwatson * transition. 227239675Srwatson */ 228239675Srwatson if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 229239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 230239675Srwatson} 231239675Srwatson 232239675Srwatsonstatic void 233239675Srwatsonaltera_sdcard_task_idle(struct altera_sdcard_softc *sc) 234239675Srwatson{ 235239675Srwatson 236239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 237239675Srwatson 238239675Srwatson /* 239239675Srwatson * Handle device driver detach. 240239675Srwatson */ 241239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 242239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 243239675Srwatson return; 244239675Srwatson } 245239675Srwatson 246239675Srwatson /* 247239675Srwatson * Handle safe card removal. 248239675Srwatson */ 249239675Srwatson if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) { 250239675Srwatson altera_sdcard_disk_remove(sc); 251239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 252239675Srwatson } 253239675Srwatson} 254239675Srwatson 255239675Srwatsonstatic void 256239675Srwatsonaltera_sdcard_task_io(struct altera_sdcard_softc *sc) 257239675Srwatson{ 258239675Srwatson uint16_t asr; 259239675Srwatson 260239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 261239675Srwatson KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__)); 262239675Srwatson 263256744Sbrooks#ifdef ALTERA_SDCARD_FAST_SIM 264256744Sbrooksrecheck: 265256744Sbrooks#endif 266239675Srwatson asr = altera_sdcard_read_asr(sc); 267239675Srwatson 268239675Srwatson /* 269239675Srwatson * Check for unexpected card removal during an I/O. 270239675Srwatson */ 271239675Srwatson if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) { 272239675Srwatson altera_sdcard_disk_remove(sc); 273239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) 274239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 275239675Srwatson else 276239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 277239675Srwatson return; 278239675Srwatson } 279239675Srwatson 280239675Srwatson /* 281239675Srwatson * If the I/O isn't complete, remain in the IO state without further 282239675Srwatson * action, even if DETACHREQ is in flight. 283239675Srwatson */ 284239675Srwatson if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS) 285239675Srwatson return; 286239675Srwatson 287239675Srwatson /* 288239675Srwatson * Handle various forms of I/O completion, successful and otherwise. 289239675Srwatson * The I/O layer may restart the transaction if an error occurred, in 290239675Srwatson * which case remain in the IO state and reschedule. 291239675Srwatson */ 292239675Srwatson if (!altera_sdcard_io_complete(sc, asr)) 293239675Srwatson return; 294239675Srwatson 295239675Srwatson /* 296239675Srwatson * Now that I/O is complete, process detach requests in preference to 297239675Srwatson * starting new I/O. 298239675Srwatson */ 299239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 300239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 301239675Srwatson return; 302239675Srwatson } 303239675Srwatson 304239675Srwatson /* 305239675Srwatson * Finally, either start the next I/O or transition to the IDLE state. 306239675Srwatson */ 307256744Sbrooks if (bioq_first(&sc->as_bioq) != NULL) { 308239675Srwatson altera_sdcard_nextio(sc); 309256744Sbrooks#ifdef ALTERA_SDCARD_FAST_SIM 310256744Sbrooks goto recheck; 311256744Sbrooks#endif 312256744Sbrooks } else 313239675Srwatson sc->as_state = ALTERA_SDCARD_STATE_IDLE; 314239675Srwatson} 315239675Srwatson 316239675Srwatsonstatic void 317239675Srwatsonaltera_sdcard_task_rechedule(struct altera_sdcard_softc *sc) 318239675Srwatson{ 319239675Srwatson int interval; 320239675Srwatson 321239675Srwatson /* 322239675Srwatson * Reschedule based on new state. Or not, if detaching the device 323239675Srwatson * driver. Treat a bad card as though it were no card at all. 324239675Srwatson */ 325239675Srwatson switch (sc->as_state) { 326239675Srwatson case ALTERA_SDCARD_STATE_NOCARD: 327239675Srwatson case ALTERA_SDCARD_STATE_BADCARD: 328239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_NOCARD; 329239675Srwatson break; 330239675Srwatson 331239675Srwatson case ALTERA_SDCARD_STATE_IDLE: 332239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_IDLE; 333239675Srwatson break; 334239675Srwatson 335239675Srwatson case ALTERA_SDCARD_STATE_IO: 336239675Srwatson if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) 337239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_IOERROR; 338239675Srwatson else 339239675Srwatson interval = ALTERA_SDCARD_TIMEOUT_IO; 340239675Srwatson break; 341239675Srwatson 342239675Srwatson default: 343239675Srwatson panic("%s: invalid exit state %d", __func__, sc->as_state); 344239675Srwatson } 345239675Srwatson taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval); 346239675Srwatson} 347239675Srwatson 348239675Srwatson/* 349239675Srwatson * Because the Altera SD Card IP Core doesn't support interrupts, we do all 350239675Srwatson * asynchronous work from a timeout. Poll at two different rates -- an 351239675Srwatson * infrequent check for card insertion status changes, and a frequent one for 352239675Srwatson * I/O completion. The task should never start in DETACHED, as that would 353239675Srwatson * imply that a previous instance failed to cancel rather than reschedule. 354239675Srwatson */ 355239675Srwatsonvoid 356239675Srwatsonaltera_sdcard_task(void *arg, int pending) 357239675Srwatson{ 358239675Srwatson struct altera_sdcard_softc *sc; 359239675Srwatson 360239675Srwatson sc = arg; 361239675Srwatson KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED, 362239675Srwatson ("%s: already in detached", __func__)); 363239675Srwatson 364239675Srwatson ALTERA_SDCARD_LOCK(sc); 365239675Srwatson switch (sc->as_state) { 366239675Srwatson case ALTERA_SDCARD_STATE_NOCARD: 367239675Srwatson altera_sdcard_task_nocard(sc); 368239675Srwatson break; 369239675Srwatson 370239675Srwatson case ALTERA_SDCARD_STATE_BADCARD: 371239675Srwatson altera_sdcard_task_badcard(sc); 372239675Srwatson break; 373239675Srwatson 374239675Srwatson case ALTERA_SDCARD_STATE_IDLE: 375239675Srwatson altera_sdcard_task_idle(sc); 376239675Srwatson break; 377239675Srwatson 378239675Srwatson case ALTERA_SDCARD_STATE_IO: 379239675Srwatson altera_sdcard_task_io(sc); 380239675Srwatson break; 381239675Srwatson 382239675Srwatson default: 383239675Srwatson panic("%s: invalid enter state %d", __func__, sc->as_state); 384239675Srwatson } 385239675Srwatson 386239675Srwatson /* 387239675Srwatson * If we have transitioned to DETACHED, signal the detach thread and 388239675Srwatson * cancel the timeout-driven task. Otherwise reschedule on an 389239675Srwatson * appropriate timeout. 390239675Srwatson */ 391239675Srwatson if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED) 392239675Srwatson ALTERA_SDCARD_CONDVAR_SIGNAL(sc); 393239675Srwatson else 394239675Srwatson altera_sdcard_task_rechedule(sc); 395239675Srwatson ALTERA_SDCARD_UNLOCK(sc); 396239675Srwatson} 397239675Srwatson 398239675Srwatsonvoid 399239675Srwatsonaltera_sdcard_start(struct altera_sdcard_softc *sc) 400239675Srwatson{ 401239675Srwatson 402239675Srwatson ALTERA_SDCARD_LOCK_ASSERT(sc); 403239675Srwatson 404239675Srwatson KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE, 405239675Srwatson ("%s: starting when not IDLE", __func__)); 406239675Srwatson 407239675Srwatson taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL); 408239675Srwatson altera_sdcard_nextio(sc); 409256744Sbrooks#ifdef ALTERA_SDCARD_FAST_SIM 410256744Sbrooks altera_sdcard_task_io(sc); 411256744Sbrooks#endif 412256744Sbrooks altera_sdcard_task_rechedule(sc); 413239675Srwatson} 414