1239675Srwatson/*-
2239675Srwatson * Copyright (c) 2012 Robert N. M. Watson
3239675Srwatson * All rights reserved.
4239675Srwatson *
5239675Srwatson * This software was developed by SRI International and the University of
6239675Srwatson * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7239675Srwatson * ("CTSRD"), as part of the DARPA CRASH research programme.
8239675Srwatson *
9239675Srwatson * Redistribution and use in source and binary forms, with or without
10239675Srwatson * modification, are permitted provided that the following conditions
11239675Srwatson * are met:
12239675Srwatson * 1. Redistributions of source code must retain the above copyright
13239675Srwatson *    notice, this list of conditions and the following disclaimer.
14239675Srwatson * 2. Redistributions in binary form must reproduce the above copyright
15239675Srwatson *    notice, this list of conditions and the following disclaimer in the
16239675Srwatson *    documentation and/or other materials provided with the distribution.
17239675Srwatson *
18239675Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19239675Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20239675Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21239675Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22239675Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23239675Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24239675Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25239675Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26239675Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27239675Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28239675Srwatson * SUCH DAMAGE.
29239675Srwatson */
30239675Srwatson
31239675Srwatson#include <sys/cdefs.h>
32239675Srwatson__FBSDID("$FreeBSD$");
33239675Srwatson
34256744Sbrooks#include "opt_altera_sdcard.h"
35256744Sbrooks
36239675Srwatson#include <sys/param.h>
37239675Srwatson#include <sys/bus.h>
38239675Srwatson#include <sys/condvar.h>
39239675Srwatson#include <sys/conf.h>
40239675Srwatson#include <sys/bio.h>
41239675Srwatson#include <sys/kernel.h>
42239675Srwatson#include <sys/lock.h>
43239675Srwatson#include <sys/malloc.h>
44239675Srwatson#include <sys/module.h>
45239675Srwatson#include <sys/mutex.h>
46239675Srwatson#include <sys/rman.h>
47239675Srwatson#include <sys/systm.h>
48239675Srwatson#include <sys/taskqueue.h>
49239675Srwatson
50239675Srwatson#include <machine/bus.h>
51239675Srwatson#include <machine/resource.h>
52239675Srwatson
53239675Srwatson#include <geom/geom_disk.h>
54239675Srwatson
55239675Srwatson#include <dev/altera/sdcard/altera_sdcard.h>
56239675Srwatson
57239675Srwatson/*
58239675Srwatson * Device driver for the Altera University Program Secure Data Card IP Core,
59239675Srwatson * as described in the similarly named SOPC Builder IP Core specification.
60239675Srwatson * This soft core is not a full SD host controller interface (SDHCI) but
61239675Srwatson * instead provides a set of memory mapped registers and memory buffer that
62239675Srwatson * mildly abstract the SD Card protocol, but without providing DMA or
63239675Srwatson * interrupts.  However, it does hide the details of voltage and
64239675Srwatson * communications negotiation.  This driver implements disk(9), but due to the
65239675Srwatson * lack of interrupt support, must rely on timer-driven polling to determine
66239675Srwatson * when I/Os have completed.
67239675Srwatson *
68239675Srwatson * TODO:
69239675Srwatson *
70239675Srwatson * 1. Implement DISKFLAG_CANDELETE / SD Card sector erase support.
71239675Srwatson * 2. Implement d_ident from SD Card CID serial number field.
72239675Srwatson * 3. Handle read-only SD Cards.
73239675Srwatson * 4. Tune timeouts based on real-world SD Card speeds.
74239675Srwatson */
75245380Srwatsondevclass_t	altera_sdcard_devclass;
76239675Srwatson
77239675Srwatsonvoid
78239675Srwatsonaltera_sdcard_attach(struct altera_sdcard_softc *sc)
79239675Srwatson{
80239675Srwatson
81239675Srwatson	ALTERA_SDCARD_LOCK_INIT(sc);
82239675Srwatson	ALTERA_SDCARD_CONDVAR_INIT(sc);
83239675Srwatson	sc->as_disk = NULL;
84239675Srwatson	bioq_init(&sc->as_bioq);
85239675Srwatson	sc->as_currentbio = NULL;
86239675Srwatson	sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
87239675Srwatson	sc->as_taskqueue = taskqueue_create("altera_sdcardc taskq", M_WAITOK,
88239675Srwatson	    taskqueue_thread_enqueue, &sc->as_taskqueue);
89239675Srwatson	taskqueue_start_threads(&sc->as_taskqueue, 1, PI_DISK,
90239675Srwatson	    "altera_sdcardc%d taskqueue", sc->as_unit);
91239675Srwatson	TIMEOUT_TASK_INIT(sc->as_taskqueue, &sc->as_task, 0,
92239675Srwatson	    altera_sdcard_task, sc);
93239675Srwatson
94239675Srwatson	/*
95239675Srwatson	 * Kick off timer-driven processing with a manual poll so that we
96239675Srwatson	 * synchronously detect an already-inserted SD Card during the boot or
97239675Srwatson	 * other driver attach point.
98239675Srwatson	 */
99239675Srwatson	altera_sdcard_task(sc, 1);
100239675Srwatson}
101239675Srwatson
102239675Srwatsonvoid
103239675Srwatsonaltera_sdcard_detach(struct altera_sdcard_softc *sc)
104239675Srwatson{
105239675Srwatson
106239675Srwatson	KASSERT(sc->as_taskqueue != NULL, ("%s: taskqueue not present",
107239675Srwatson	    __func__));
108239675Srwatson
109239675Srwatson	/*
110239675Srwatson	 * Winding down the driver on detach is a bit complex.  Update the
111239675Srwatson	 * flags to indicate that a detach has been requested, and then wait
112239675Srwatson	 * for in-progress I/O to wind down before continuing.
113239675Srwatson	 */
114239675Srwatson	ALTERA_SDCARD_LOCK(sc);
115239675Srwatson	sc->as_flags |= ALTERA_SDCARD_FLAG_DETACHREQ;
116239675Srwatson	while (sc->as_state != ALTERA_SDCARD_STATE_DETACHED)
117239675Srwatson		ALTERA_SDCARD_CONDVAR_WAIT(sc);
118239675Srwatson	ALTERA_SDCARD_UNLOCK(sc);
119239675Srwatson
120239675Srwatson	/*
121239675Srwatson	 * Now wait for the possibly still executing taskqueue to drain.  In
122239675Srwatson	 * principle no more events will be scheduled as we've transitioned to
123239675Srwatson	 * a detached state, but there might still be a request in execution.
124239675Srwatson	 */
125239675Srwatson	while (taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL))
126239675Srwatson		taskqueue_drain_timeout(sc->as_taskqueue, &sc->as_task);
127239675Srwatson
128239675Srwatson	/*
129239675Srwatson	 * Simulate a disk removal if one is present to deal with any pending
130239675Srwatson	 * or queued I/O.
131239675Srwatson	 */
132239675Srwatson	if (sc->as_disk != NULL)
133239675Srwatson		altera_sdcard_disk_remove(sc);
134239675Srwatson	KASSERT(bioq_first(&sc->as_bioq) == NULL,
135239675Srwatson	    ("%s: non-empty bioq", __func__));
136239675Srwatson
137239675Srwatson	/*
138239675Srwatson	 * Free any remaining allocated resources.
139239675Srwatson	 */
140239675Srwatson	taskqueue_free(sc->as_taskqueue);
141239675Srwatson	sc->as_taskqueue = NULL;
142239675Srwatson	ALTERA_SDCARD_CONDVAR_DESTROY(sc);
143239675Srwatson	ALTERA_SDCARD_LOCK_DESTROY(sc);
144239675Srwatson}
145239675Srwatson
146239675Srwatson/*
147239675Srwatson * Set up and start the next I/O.  Transition to the I/O state, but allow the
148239675Srwatson * caller to schedule the next timeout, as this may be called either from an
149239675Srwatson * initial attach context, or from the task queue, which requires different
150239675Srwatson * behaviour.
151239675Srwatson */
152239675Srwatsonstatic void
153239675Srwatsonaltera_sdcard_nextio(struct altera_sdcard_softc *sc)
154239675Srwatson{
155239675Srwatson	struct bio *bp;
156239675Srwatson
157239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
158239675Srwatson	KASSERT(sc->as_currentbio == NULL,
159239675Srwatson	    ("%s: bio already active", __func__));
160239675Srwatson
161239675Srwatson	bp = bioq_takefirst(&sc->as_bioq);
162239675Srwatson	if (bp == NULL)
163239675Srwatson		panic("%s: bioq empty", __func__);
164239675Srwatson	altera_sdcard_io_start(sc, bp);
165239675Srwatson	sc->as_state = ALTERA_SDCARD_STATE_IO;
166239675Srwatson}
167239675Srwatson
168239675Srwatsonstatic void
169239675Srwatsonaltera_sdcard_task_nocard(struct altera_sdcard_softc *sc)
170239675Srwatson{
171239675Srwatson
172239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
173239675Srwatson
174239675Srwatson	/*
175239675Srwatson	 * Handle device driver detach.
176239675Srwatson	 */
177239675Srwatson	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
178239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
179239675Srwatson		return;
180239675Srwatson	}
181239675Srwatson
182239675Srwatson	/*
183239675Srwatson	 * If there is no card insertion, remain in NOCARD.
184239675Srwatson	 */
185239675Srwatson	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
186239675Srwatson		return;
187239675Srwatson
188239675Srwatson	/*
189239675Srwatson	 * Read the CSD -- it may contain values that the driver can't handle,
190239675Srwatson	 * either because of an unsupported version/feature, or because the
191239675Srwatson	 * card is misbehaving.  This triggers a transition to
192239675Srwatson	 * ALTERA_SDCARD_STATE_BADCARD.  We rely on the CSD read to print a
193239675Srwatson	 * banner about how the card is problematic, since it has more
194239675Srwatson	 * information.  The bad card state allows us to print that banner
195239675Srwatson	 * once rather than each time we notice the card is there, and still
196239675Srwatson	 * bad.
197239675Srwatson	 */
198239675Srwatson	if (altera_sdcard_read_csd(sc) != 0) {
199239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_BADCARD;
200239675Srwatson		return;
201239675Srwatson	}
202239675Srwatson
203239675Srwatson	/*
204239675Srwatson	 * Process card insertion and upgrade to the IDLE state.
205239675Srwatson	 */
206239675Srwatson	altera_sdcard_disk_insert(sc);
207239675Srwatson	sc->as_state = ALTERA_SDCARD_STATE_IDLE;
208239675Srwatson}
209239675Srwatson
210239675Srwatsonstatic void
211239675Srwatsonaltera_sdcard_task_badcard(struct altera_sdcard_softc *sc)
212239675Srwatson{
213239675Srwatson
214239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
215239675Srwatson
216239675Srwatson	/*
217239675Srwatson	 * Handle device driver detach.
218239675Srwatson	 */
219239675Srwatson	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
220239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
221239675Srwatson		return;
222239675Srwatson	}
223239675Srwatson
224239675Srwatson	/*
225239675Srwatson	 * Handle safe card removal -- no teardown is required, just a state
226239675Srwatson	 * transition.
227239675Srwatson	 */
228239675Srwatson	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
229239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
230239675Srwatson}
231239675Srwatson
232239675Srwatsonstatic void
233239675Srwatsonaltera_sdcard_task_idle(struct altera_sdcard_softc *sc)
234239675Srwatson{
235239675Srwatson
236239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
237239675Srwatson
238239675Srwatson	/*
239239675Srwatson	 * Handle device driver detach.
240239675Srwatson	 */
241239675Srwatson	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
242239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
243239675Srwatson		return;
244239675Srwatson	}
245239675Srwatson
246239675Srwatson	/*
247239675Srwatson	 * Handle safe card removal.
248239675Srwatson	 */
249239675Srwatson	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) {
250239675Srwatson		altera_sdcard_disk_remove(sc);
251239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
252239675Srwatson	}
253239675Srwatson}
254239675Srwatson
255239675Srwatsonstatic void
256239675Srwatsonaltera_sdcard_task_io(struct altera_sdcard_softc *sc)
257239675Srwatson{
258239675Srwatson	uint16_t asr;
259239675Srwatson
260239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
261239675Srwatson	KASSERT(sc->as_currentbio != NULL, ("%s: no current I/O", __func__));
262239675Srwatson
263256744Sbrooks#ifdef ALTERA_SDCARD_FAST_SIM
264256744Sbrooksrecheck:
265256744Sbrooks#endif
266239675Srwatson	asr = altera_sdcard_read_asr(sc);
267239675Srwatson
268239675Srwatson	/*
269239675Srwatson	 * Check for unexpected card removal during an I/O.
270239675Srwatson	 */
271239675Srwatson	if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) {
272239675Srwatson		altera_sdcard_disk_remove(sc);
273239675Srwatson		if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ)
274239675Srwatson			sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
275239675Srwatson		else
276239675Srwatson			sc->as_state = ALTERA_SDCARD_STATE_NOCARD;
277239675Srwatson		return;
278239675Srwatson	}
279239675Srwatson
280239675Srwatson	/*
281239675Srwatson	 * If the I/O isn't complete, remain in the IO state without further
282239675Srwatson	 * action, even if DETACHREQ is in flight.
283239675Srwatson	 */
284239675Srwatson	if (asr & ALTERA_SDCARD_ASR_CMDINPROGRESS)
285239675Srwatson		return;
286239675Srwatson
287239675Srwatson	/*
288239675Srwatson	 * Handle various forms of I/O completion, successful and otherwise.
289239675Srwatson	 * The I/O layer may restart the transaction if an error occurred, in
290239675Srwatson	 * which case remain in the IO state and reschedule.
291239675Srwatson	 */
292239675Srwatson	if (!altera_sdcard_io_complete(sc, asr))
293239675Srwatson		return;
294239675Srwatson
295239675Srwatson	/*
296239675Srwatson	 * Now that I/O is complete, process detach requests in preference to
297239675Srwatson	 * starting new I/O.
298239675Srwatson	 */
299239675Srwatson	if (sc->as_flags & ALTERA_SDCARD_FLAG_DETACHREQ) {
300239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_DETACHED;
301239675Srwatson		return;
302239675Srwatson	}
303239675Srwatson
304239675Srwatson	/*
305239675Srwatson	 * Finally, either start the next I/O or transition to the IDLE state.
306239675Srwatson	 */
307256744Sbrooks	if (bioq_first(&sc->as_bioq) != NULL) {
308239675Srwatson		altera_sdcard_nextio(sc);
309256744Sbrooks#ifdef ALTERA_SDCARD_FAST_SIM
310256744Sbrooks		goto recheck;
311256744Sbrooks#endif
312256744Sbrooks	} else
313239675Srwatson		sc->as_state = ALTERA_SDCARD_STATE_IDLE;
314239675Srwatson}
315239675Srwatson
316239675Srwatsonstatic void
317239675Srwatsonaltera_sdcard_task_rechedule(struct altera_sdcard_softc *sc)
318239675Srwatson{
319239675Srwatson	int interval;
320239675Srwatson
321239675Srwatson	/*
322239675Srwatson	 * Reschedule based on new state.  Or not, if detaching the device
323239675Srwatson	 * driver.  Treat a bad card as though it were no card at all.
324239675Srwatson	 */
325239675Srwatson	switch (sc->as_state) {
326239675Srwatson	case ALTERA_SDCARD_STATE_NOCARD:
327239675Srwatson	case ALTERA_SDCARD_STATE_BADCARD:
328239675Srwatson		interval = ALTERA_SDCARD_TIMEOUT_NOCARD;
329239675Srwatson		break;
330239675Srwatson
331239675Srwatson	case ALTERA_SDCARD_STATE_IDLE:
332239675Srwatson		interval = ALTERA_SDCARD_TIMEOUT_IDLE;
333239675Srwatson		break;
334239675Srwatson
335239675Srwatson	case ALTERA_SDCARD_STATE_IO:
336239675Srwatson		if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR)
337239675Srwatson			interval = ALTERA_SDCARD_TIMEOUT_IOERROR;
338239675Srwatson		else
339239675Srwatson			interval = ALTERA_SDCARD_TIMEOUT_IO;
340239675Srwatson		break;
341239675Srwatson
342239675Srwatson	default:
343239675Srwatson		panic("%s: invalid exit state %d", __func__, sc->as_state);
344239675Srwatson	}
345239675Srwatson	taskqueue_enqueue_timeout(sc->as_taskqueue, &sc->as_task, interval);
346239675Srwatson}
347239675Srwatson
348239675Srwatson/*
349239675Srwatson * Because the Altera SD Card IP Core doesn't support interrupts, we do all
350239675Srwatson * asynchronous work from a timeout.  Poll at two different rates -- an
351239675Srwatson * infrequent check for card insertion status changes, and a frequent one for
352239675Srwatson * I/O completion.  The task should never start in DETACHED, as that would
353239675Srwatson * imply that a previous instance failed to cancel rather than reschedule.
354239675Srwatson */
355239675Srwatsonvoid
356239675Srwatsonaltera_sdcard_task(void *arg, int pending)
357239675Srwatson{
358239675Srwatson	struct altera_sdcard_softc *sc;
359239675Srwatson
360239675Srwatson	sc = arg;
361239675Srwatson	KASSERT(sc->as_state != ALTERA_SDCARD_STATE_DETACHED,
362239675Srwatson	    ("%s: already in detached", __func__));
363239675Srwatson
364239675Srwatson	ALTERA_SDCARD_LOCK(sc);
365239675Srwatson	switch (sc->as_state) {
366239675Srwatson	case ALTERA_SDCARD_STATE_NOCARD:
367239675Srwatson		altera_sdcard_task_nocard(sc);
368239675Srwatson		break;
369239675Srwatson
370239675Srwatson	case ALTERA_SDCARD_STATE_BADCARD:
371239675Srwatson		altera_sdcard_task_badcard(sc);
372239675Srwatson		break;
373239675Srwatson
374239675Srwatson	case ALTERA_SDCARD_STATE_IDLE:
375239675Srwatson		altera_sdcard_task_idle(sc);
376239675Srwatson		break;
377239675Srwatson
378239675Srwatson	case ALTERA_SDCARD_STATE_IO:
379239675Srwatson		altera_sdcard_task_io(sc);
380239675Srwatson		break;
381239675Srwatson
382239675Srwatson	default:
383239675Srwatson		panic("%s: invalid enter state %d", __func__, sc->as_state);
384239675Srwatson	}
385239675Srwatson
386239675Srwatson	/*
387239675Srwatson	 * If we have transitioned to DETACHED, signal the detach thread and
388239675Srwatson	 * cancel the timeout-driven task.  Otherwise reschedule on an
389239675Srwatson	 * appropriate timeout.
390239675Srwatson	 */
391239675Srwatson	if (sc->as_state == ALTERA_SDCARD_STATE_DETACHED)
392239675Srwatson		ALTERA_SDCARD_CONDVAR_SIGNAL(sc);
393239675Srwatson	else
394239675Srwatson		altera_sdcard_task_rechedule(sc);
395239675Srwatson	ALTERA_SDCARD_UNLOCK(sc);
396239675Srwatson}
397239675Srwatson
398239675Srwatsonvoid
399239675Srwatsonaltera_sdcard_start(struct altera_sdcard_softc *sc)
400239675Srwatson{
401239675Srwatson
402239675Srwatson	ALTERA_SDCARD_LOCK_ASSERT(sc);
403239675Srwatson
404239675Srwatson	KASSERT(sc->as_state == ALTERA_SDCARD_STATE_IDLE,
405239675Srwatson	    ("%s: starting when not IDLE", __func__));
406239675Srwatson
407239675Srwatson	taskqueue_cancel_timeout(sc->as_taskqueue, &sc->as_task, NULL);
408239675Srwatson	altera_sdcard_nextio(sc);
409256744Sbrooks#ifdef ALTERA_SDCARD_FAST_SIM
410256744Sbrooks	altera_sdcard_task_io(sc);
411256744Sbrooks#endif
412256744Sbrooks	altera_sdcard_task_rechedule(sc);
413239675Srwatson}
414