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