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