altera_sdcard.c revision 245380
1/*- 2 * Copyright (c) 2012 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/dev/altera/sdcard/altera_sdcard.c 245380 2013-01-13 16:57:11Z rwatson $"); 33 34#include <sys/param.h> 35#include <sys/bus.h> 36#include <sys/condvar.h> 37#include <sys/conf.h> 38#include <sys/bio.h> 39#include <sys/kernel.h> 40#include <sys/lock.h> 41#include <sys/malloc.h> 42#include <sys/module.h> 43#include <sys/mutex.h> 44#include <sys/rman.h> 45#include <sys/systm.h> 46#include <sys/taskqueue.h> 47 48#include <machine/bus.h> 49#include <machine/resource.h> 50 51#include <geom/geom_disk.h> 52 53#include <dev/altera/sdcard/altera_sdcard.h> 54 55/* 56 * Device driver for the Altera University Program Secure Data Card IP Core, 57 * as described in the similarly named SOPC Builder IP Core specification. 58 * This soft core is not a full SD host controller interface (SDHCI) but 59 * instead provides a set of memory mapped registers and memory buffer that 60 * mildly abstract the SD Card protocol, but without providing DMA or 61 * interrupts. However, it does hide the details of voltage and 62 * communications negotiation. This driver implements disk(9), but due to the 63 * lack of interrupt support, must rely on timer-driven polling to determine 64 * when I/Os have completed. 65 * 66 * TODO: 67 * 68 * 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support. 69 * 2. Implement d_ident from SD Card CID serial number field. 70 * 3. Handle read-only SD Cards. 71 * 4. Tune timeouts based on real-world SD Card speeds. 72 */ 73devclass_t altera_sdcard_devclass; 74 75void 76altera_sdcard_attach(struct altera_sdcard_softc *sc) 77{ 78 79 ALTERA_SDCARD_LOCK_INIT(sc); 80 ALTERA_SDCARD_CONDVAR_INIT(sc); 81 sc->as_disk = NULL; 82 bioq_init(&sc->as_bioq); 83 sc->as_currentbio = NULL; 84 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 85 sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK, 86 taskqueue_thread_enqueue, &sc->as_taskqueue); 87 taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK, 88 "altera_sdcardc%d taskqueue", sc->as_unit); 89 TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0, 90 altera_sdcard_task, sc); 91 92 /* 93 * Kick off timer-driven processing with a manual poll so that we 94 * synchronously detect an already-inserted SD Card during the boot or 95 * other driver attach point. 96 */ 97 altera_sdcard_task(sc, 1); 98} 99 100void 101altera_sdcard_detach(struct altera_sdcard_softc *sc) 102{ 103 104 KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present", 105 __func__)); 106 107 /* 108 * Winding down the driver on detach is a bit complex. Update the 109 * flags to indicate that a detach has been requested, and then wait 110 * for in-progress I/O to wind down before continuing. 111 */ 112 ALTERA_SDCARD_LOCK(sc); 113 sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ; 114 while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED) 115 ALTERA_SDCARD_CONDVAR_WAIT(sc); 116 ALTERA_SDCARD_UNLOCK(sc); 117 118 /* 119 * Now wait for the possibly still executing taskqueue to drain. In 120 * principle no more events will be scheduled as we've transitioned to 121 * a detached state, but there might still be a request in execution. 122 */ 123 while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL)) 124 taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task); 125 126 /* 127 * Simulate a disk removal if one is present to deal with any pending 128 * or queued I/O. 129 */ 130 if (sc->as_disk != NULL) 131 altera_sdcard_disk_remove(sc); 132 KASSERT(bioq_first(&sc->as_bioq) == NULL, 133 ("%s: non-empty bioq", __func__)); 134 135 /* 136 * Free any remaining allocated resources. 137 */ 138 taskqueue_free(sc->as_taskqueue); 139 sc->as_taskqueue = NULL; 140 ALTERA_SDCARD_CONDVAR_DESTROY(sc); 141 ALTERA_SDCARD_LOCK_DESTROY(sc); 142} 143 144/* 145 * Set up and start the next I/O. Transition to the I/O state, but allow the 146 * caller to schedule the next timeout, as this may be called either from an 147 * initial attach context, or from the task queue, which requires different 148 * behaviour. 149 */ 150static void 151altera_sdcard_nextio(struct altera_sdcard_softc *sc) 152{ 153 struct bio *bp; 154 155 ALTERA_SDCARD_LOCK_ASSERT(sc); 156 KASSERT(sc->as_currentbio == NULL, 157 ("%s: bio already active", __func__)); 158 159 bp = bioq_takefirst(&sc->as_bioq); 160 if (bp == NULL) 161 panic("%s: bioq empty", __func__); 162 altera_sdcard_io_start(sc, bp); 163 sc->as_state = ALTERA_SDCARD_STATE_IO; 164} 165 166static void 167altera_sdcard_task_nocard(struct altera_sdcard_softc *sc) 168{ 169 170 ALTERA_SDCARD_LOCK_ASSERT(sc); 171 172 /* 173 * Handle device driver detach. 174 */ 175 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 176 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 177 return; 178 } 179 180 /* 181 * If there is no card insertion, remain in NOCARD. 182 */ 183 if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 184 return; 185 186 /* 187 * Read the CSD -- it may contain values that the driver can't handle, 188 * either because of an unsupported version/feature, or because the 189 * card is misbehaving. This triggers a transition to 190 * ALTERA_SDCARD_STATE_BADCARD. We rely on the CSD read to print a 191 * banner about how the card is problematic, since it has more 192 * information. The bad card state allows us to print that banner 193 * once rather than each time we notice the card is there, and still 194 * bad. 195 */ 196 if (altera_sdcard_read_csd(sc) != 0) { 197 sc->as_state = ALTERA_SDCARD_STATE_BADCARD; 198 return; 199 } 200 201 /* 202 * Process card insertion and upgrade to the IDLE state. 203 */ 204 altera_sdcard_disk_insert(sc); 205 sc->as_state = ALTERA_SDCARD_STATE_IDLE; 206} 207 208static void 209altera_sdcard_task_badcard(struct altera_sdcard_softc *sc) 210{ 211 212 ALTERA_SDCARD_LOCK_ASSERT(sc); 213 214 /* 215 * Handle device driver detach. 216 */ 217 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 218 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 219 return; 220 } 221 222 /* 223 * Handle safe card removal -- no teardown is required, just a state 224 * transition. 225 */ 226 if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 227 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 228} 229 230static void 231altera_sdcard_task_idle(struct altera_sdcard_softc *sc) 232{ 233 234 ALTERA_SDCARD_LOCK_ASSERT(sc); 235 236 /* 237 * Handle device driver detach. 238 */ 239 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 240 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 241 return; 242 } 243 244 /* 245 * Handle safe card removal. 246 */ 247 if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) { 248 altera_sdcard_disk_remove(sc); 249 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 250 } 251} 252 253static void 254altera_sdcard_task_io(struct altera_sdcard_softc *sc) 255{ 256 uint16_t asr; 257 258 ALTERA_SDCARD_LOCK_ASSERT(sc); 259 KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__)); 260 261 asr = altera_sdcard_read_asr(sc); 262 263 /* 264 * Check for unexpected card removal during an I/O. 265 */ 266 if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) { 267 altera_sdcard_disk_remove(sc); 268 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) 269 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 270 else 271 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 272 return; 273 } 274 275 /* 276 * If the I/O isn't complete, remain in the IO state without further 277 * action, even if DETACHREQ is in flight. 278 */ 279 if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS) 280 return; 281 282 /* 283 * Handle various forms of I/O completion, successful and otherwise. 284 * The I/O layer may restart the transaction if an error occurred, in 285 * which case remain in the IO state and reschedule. 286 */ 287 if (!altera_sdcard_io_complete(sc, asr)) 288 return; 289 290 /* 291 * Now that I/O is complete, process detach requests in preference to 292 * starting new I/O. 293 */ 294 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 295 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 296 return; 297 } 298 299 /* 300 * Finally, either start the next I/O or transition to the IDLE state. 301 */ 302 if (bioq_first(&sc->as_bioq) != NULL) 303 altera_sdcard_nextio(sc); 304 else 305 sc->as_state = ALTERA_SDCARD_STATE_IDLE; 306} 307 308static void 309altera_sdcard_task_rechedule(struct altera_sdcard_softc *sc) 310{ 311 int interval; 312 313 /* 314 * Reschedule based on new state. Or not, if detaching the device 315 * driver. Treat a bad card as though it were no card at all. 316 */ 317 switch (sc->as_state) { 318 case ALTERA_SDCARD_STATE_NOCARD: 319 case ALTERA_SDCARD_STATE_BADCARD: 320 interval = ALTERA_SDCARD_TIMEOUT_NOCARD; 321 break; 322 323 case ALTERA_SDCARD_STATE_IDLE: 324 interval = ALTERA_SDCARD_TIMEOUT_IDLE; 325 break; 326 327 case ALTERA_SDCARD_STATE_IO: 328 if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) 329 interval = ALTERA_SDCARD_TIMEOUT_IOERROR; 330 else 331 interval = ALTERA_SDCARD_TIMEOUT_IO; 332 break; 333 334 default: 335 panic("%s: invalid exit state %d", __func__, sc->as_state); 336 } 337 taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval); 338} 339 340/* 341 * Because the Altera SD Card IP Core doesn't support interrupts, we do all 342 * asynchronous work from a timeout. Poll at two different rates -- an 343 * infrequent check for card insertion status changes, and a frequent one for 344 * I/O completion. The task should never start in DETACHED, as that would 345 * imply that a previous instance failed to cancel rather than reschedule. 346 */ 347void 348altera_sdcard_task(void *arg, int pending) 349{ 350 struct altera_sdcard_softc *sc; 351 352 sc = arg; 353 KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED, 354 ("%s: already in detached", __func__)); 355 356 ALTERA_SDCARD_LOCK(sc); 357 switch (sc->as_state) { 358 case ALTERA_SDCARD_STATE_NOCARD: 359 altera_sdcard_task_nocard(sc); 360 break; 361 362 case ALTERA_SDCARD_STATE_BADCARD: 363 altera_sdcard_task_badcard(sc); 364 break; 365 366 case ALTERA_SDCARD_STATE_IDLE: 367 altera_sdcard_task_idle(sc); 368 break; 369 370 case ALTERA_SDCARD_STATE_IO: 371 altera_sdcard_task_io(sc); 372 break; 373 374 default: 375 panic("%s: invalid enter state %d", __func__, sc->as_state); 376 } 377 378 /* 379 * If we have transitioned to DETACHED, signal the detach thread and 380 * cancel the timeout-driven task. Otherwise reschedule on an 381 * appropriate timeout. 382 */ 383 if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED) 384 ALTERA_SDCARD_CONDVAR_SIGNAL(sc); 385 else 386 altera_sdcard_task_rechedule(sc); 387 ALTERA_SDCARD_UNLOCK(sc); 388} 389 390void 391altera_sdcard_start(struct altera_sdcard_softc *sc) 392{ 393 394 ALTERA_SDCARD_LOCK_ASSERT(sc); 395 396 KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE, 397 ("%s: starting when not IDLE", __func__)); 398 399 taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL); 400 altera_sdcard_nextio(sc); 401 taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, 402 ALTERA_SDCARD_TIMEOUT_IO); 403} 404