xref: /freebsd/sys/dev/altera/sdcard/altera_sdcard.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
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 
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