]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/altera/sdcard/altera_sdcard.c
o Add support for BERI IOMMU device
[FreeBSD/FreeBSD.git] / sys / dev / altera / sdcard / altera_sdcard.c
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 }