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