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