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 */
77devclass_t	altera_sdcard_devclass;
78
79void
80altera_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
104void
105altera_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 */
154static void
155altera_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
170static void
171altera_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
212static void
213altera_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
234static void
235altera_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
257static void
258altera_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
266recheck:
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
318static void
319altera_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 */
357void
358altera_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
400void
401altera_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}
416