1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 78 void 79 altera_sdcard_attach(struct altera_sdcard_softc *sc) 80 { 81 82 ALTERA_SDCARD_LOCK_INIT(sc); 83 ALTERA_SDCARD_CONDVAR_INIT(sc); 84 sc->as_disk = NULL; 85 bioq_init(&sc->as_bioq); 86 sc->as_currentbio = NULL; 87 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 88 sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK, 89 taskqueue_thread_enqueue, &sc->as_taskqueue); 90 taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK, 91 "altera_sdcardc%d taskqueue", sc->as_unit); 92 TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0, 93 altera_sdcard_task, sc); 94 95 /* 96 * Kick off timer-driven processing with a manual poll so that we 97 * synchronously detect an already-inserted SD Card during the boot or 98 * other driver attach point. 99 */ 100 altera_sdcard_task(sc, 1); 101 } 102 103 void 104 altera_sdcard_detach(struct altera_sdcard_softc *sc) 105 { 106 107 KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present", 108 __func__)); 109 110 /* 111 * Winding down the driver on detach is a bit complex. Update the 112 * flags to indicate that a detach has been requested, and then wait 113 * for in-progress I/O to wind down before continuing. 114 */ 115 ALTERA_SDCARD_LOCK(sc); 116 sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ; 117 while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED) 118 ALTERA_SDCARD_CONDVAR_WAIT(sc); 119 ALTERA_SDCARD_UNLOCK(sc); 120 121 /* 122 * Now wait for the possibly still executing taskqueue to drain. In 123 * principle no more events will be scheduled as we've transitioned to 124 * a detached state, but there might still be a request in execution. 125 */ 126 while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL)) 127 taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task); 128 129 /* 130 * Simulate a disk removal if one is present to deal with any pending 131 * or queued I/O. 132 */ 133 if (sc->as_disk != NULL) 134 altera_sdcard_disk_remove(sc); 135 KASSERT(bioq_first(&sc->as_bioq) == NULL, 136 ("%s: non-empty bioq", __func__)); 137 138 /* 139 * Free any remaining allocated resources. 140 */ 141 taskqueue_free(sc->as_taskqueue); 142 sc->as_taskqueue = NULL; 143 ALTERA_SDCARD_CONDVAR_DESTROY(sc); 144 ALTERA_SDCARD_LOCK_DESTROY(sc); 145 } 146 147 /* 148 * Set up and start the next I/O. Transition to the I/O state, but allow the 149 * caller to schedule the next timeout, as this may be called either from an 150 * initial attach context, or from the task queue, which requires different 151 * behaviour. 152 */ 153 static void 154 altera_sdcard_nextio(struct altera_sdcard_softc *sc) 155 { 156 struct bio *bp; 157 158 ALTERA_SDCARD_LOCK_ASSERT(sc); 159 KASSERT(sc->as_currentbio == NULL, 160 ("%s: bio already active", __func__)); 161 162 bp = bioq_takefirst(&sc->as_bioq); 163 if (bp == NULL) 164 panic("%s: bioq empty", __func__); 165 altera_sdcard_io_start(sc, bp); 166 sc->as_state = ALTERA_SDCARD_STATE_IO; 167 } 168 169 static void 170 altera_sdcard_task_nocard(struct altera_sdcard_softc *sc) 171 { 172 173 ALTERA_SDCARD_LOCK_ASSERT(sc); 174 175 /* 176 * Handle device driver detach. 177 */ 178 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 179 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 180 return; 181 } 182 183 /* 184 * If there is no card insertion, remain in NOCARD. 185 */ 186 if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 187 return; 188 189 /* 190 * Read the CSD -- it may contain values that the driver can't handle, 191 * either because of an unsupported version/feature, or because the 192 * card is misbehaving. This triggers a transition to 193 * ALTERA_SDCARD_STATE_BADCARD. We rely on the CSD read to print a 194 * banner about how the card is problematic, since it has more 195 * information. The bad card state allows us to print that banner 196 * once rather than each time we notice the card is there, and still 197 * bad. 198 */ 199 if (altera_sdcard_read_csd(sc) != 0) { 200 sc->as_state = ALTERA_SDCARD_STATE_BADCARD; 201 return; 202 } 203 204 /* 205 * Process card insertion and upgrade to the IDLE state. 206 */ 207 altera_sdcard_disk_insert(sc); 208 sc->as_state = ALTERA_SDCARD_STATE_IDLE; 209 } 210 211 static void 212 altera_sdcard_task_badcard(struct altera_sdcard_softc *sc) 213 { 214 215 ALTERA_SDCARD_LOCK_ASSERT(sc); 216 217 /* 218 * Handle device driver detach. 219 */ 220 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 221 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 222 return; 223 } 224 225 /* 226 * Handle safe card removal -- no teardown is required, just a state 227 * transition. 228 */ 229 if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) 230 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 231 } 232 233 static void 234 altera_sdcard_task_idle(struct altera_sdcard_softc *sc) 235 { 236 237 ALTERA_SDCARD_LOCK_ASSERT(sc); 238 239 /* 240 * Handle device driver detach. 241 */ 242 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 243 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 244 return; 245 } 246 247 /* 248 * Handle safe card removal. 249 */ 250 if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) { 251 altera_sdcard_disk_remove(sc); 252 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 253 } 254 } 255 256 static void 257 altera_sdcard_task_io(struct altera_sdcard_softc *sc) 258 { 259 uint16_t asr; 260 261 ALTERA_SDCARD_LOCK_ASSERT(sc); 262 KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__)); 263 264 #ifdef ALTERA_SDCARD_FAST_SIM 265 recheck: 266 #endif 267 asr = altera_sdcard_read_asr(sc); 268 269 /* 270 * Check for unexpected card removal during an I/O. 271 */ 272 if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) { 273 altera_sdcard_disk_remove(sc); 274 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) 275 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 276 else 277 sc->as_state = ALTERA_SDCARD_STATE_NOCARD; 278 return; 279 } 280 281 /* 282 * If the I/O isn't complete, remain in the IO state without further 283 * action, even if DETACHREQ is in flight. 284 */ 285 if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS) 286 return; 287 288 /* 289 * Handle various forms of I/O completion, successful and otherwise. 290 * The I/O layer may restart the transaction if an error occurred, in 291 * which case remain in the IO state and reschedule. 292 */ 293 if (!altera_sdcard_io_complete(sc, asr)) 294 return; 295 296 /* 297 * Now that I/O is complete, process detach requests in preference to 298 * starting new I/O. 299 */ 300 if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) { 301 sc->as_state = ALTERA_SDCARD_STATE_DETACHED; 302 return; 303 } 304 305 /* 306 * Finally, either start the next I/O or transition to the IDLE state. 307 */ 308 if (bioq_first(&sc->as_bioq) != NULL) { 309 altera_sdcard_nextio(sc); 310 #ifdef ALTERA_SDCARD_FAST_SIM 311 goto recheck; 312 #endif 313 } else 314 sc->as_state = ALTERA_SDCARD_STATE_IDLE; 315 } 316 317 static void 318 altera_sdcard_task_rechedule(struct altera_sdcard_softc *sc) 319 { 320 int interval; 321 322 /* 323 * Reschedule based on new state. Or not, if detaching the device 324 * driver. Treat a bad card as though it were no card at all. 325 */ 326 switch (sc->as_state) { 327 case ALTERA_SDCARD_STATE_NOCARD: 328 case ALTERA_SDCARD_STATE_BADCARD: 329 interval = ALTERA_SDCARD_TIMEOUT_NOCARD; 330 break; 331 332 case ALTERA_SDCARD_STATE_IDLE: 333 interval = ALTERA_SDCARD_TIMEOUT_IDLE; 334 break; 335 336 case ALTERA_SDCARD_STATE_IO: 337 if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) 338 interval = ALTERA_SDCARD_TIMEOUT_IOERROR; 339 else 340 interval = ALTERA_SDCARD_TIMEOUT_IO; 341 break; 342 343 default: 344 panic("%s: invalid exit state %d", __func__, sc->as_state); 345 } 346 taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval); 347 } 348 349 /* 350 * Because the Altera SD Card IP Core doesn't support interrupts, we do all 351 * asynchronous work from a timeout. Poll at two different rates -- an 352 * infrequent check for card insertion status changes, and a frequent one for 353 * I/O completion. The task should never start in DETACHED, as that would 354 * imply that a previous instance failed to cancel rather than reschedule. 355 */ 356 void 357 altera_sdcard_task(void *arg, int pending) 358 { 359 struct altera_sdcard_softc *sc; 360 361 sc = arg; 362 KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED, 363 ("%s: already in detached", __func__)); 364 365 ALTERA_SDCARD_LOCK(sc); 366 switch (sc->as_state) { 367 case ALTERA_SDCARD_STATE_NOCARD: 368 altera_sdcard_task_nocard(sc); 369 break; 370 371 case ALTERA_SDCARD_STATE_BADCARD: 372 altera_sdcard_task_badcard(sc); 373 break; 374 375 case ALTERA_SDCARD_STATE_IDLE: 376 altera_sdcard_task_idle(sc); 377 break; 378 379 case ALTERA_SDCARD_STATE_IO: 380 altera_sdcard_task_io(sc); 381 break; 382 383 default: 384 panic("%s: invalid enter state %d", __func__, sc->as_state); 385 } 386 387 /* 388 * If we have transitioned to DETACHED, signal the detach thread and 389 * cancel the timeout-driven task. Otherwise reschedule on an 390 * appropriate timeout. 391 */ 392 if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED) 393 ALTERA_SDCARD_CONDVAR_SIGNAL(sc); 394 else 395 altera_sdcard_task_rechedule(sc); 396 ALTERA_SDCARD_UNLOCK(sc); 397 } 398 399 void 400 altera_sdcard_start(struct altera_sdcard_softc *sc) 401 { 402 403 ALTERA_SDCARD_LOCK_ASSERT(sc); 404 405 KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE, 406 ("%s: starting when not IDLE", __func__)); 407 408 taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL); 409 altera_sdcard_nextio(sc); 410 #ifdef ALTERA_SDCARD_FAST_SIM 411 altera_sdcard_task_io(sc); 412 #endif 413 altera_sdcard_task_rechedule(sc); 414 } 415