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