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 }
Cache object: 776af48763a883feedee58b53e74f446
|