altera_sdcard_io.c revision 302408
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: stable/11/sys/dev/altera/sdcard/altera_sdcard_io.c 256743 2013-10-18 15:24:18Z brooks $");
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/endian.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/malloc.h>
43#include <sys/module.h>
44#include <sys/mutex.h>
45#include <sys/rman.h>
46#include <sys/systm.h>
47#include <sys/taskqueue.h>
48
49#include <machine/bus.h>
50#include <machine/resource.h>
51
52#include <geom/geom_disk.h>
53
54#include <dev/altera/sdcard/altera_sdcard.h>
55
56int altera_sdcard_ignore_crc_errors = 1;
57int altera_sdcard_verify_rxtx_writes = 1;
58
59/*
60 * Low-level I/O routines for the Altera SD Card University IP Core driver.
61 *
62 * XXXRW: Throughout, it is assumed that the IP Core handles multibyte
63 * registers as little endian, as is the case for other Altera IP cores.
64 * However, the specification makes no reference to endianness, so this
65 * assumption might not always be correct.
66 */
67uint16_t
68altera_sdcard_read_asr(struct altera_sdcard_softc *sc)
69{
70
71	return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_ASR)));
72}
73
74static int
75altera_sdcard_process_csd0(struct altera_sdcard_softc *sc)
76{
77	uint64_t c_size, c_size_mult, read_bl_len;
78	uint8_t byte0, byte1, byte2;
79
80	ALTERA_SDCARD_LOCK_ASSERT(sc);
81
82	/*-
83	 * Compute card capacity per SD Card interface description as follows:
84	 *
85	 *   Memory capacity = BLOCKNR * BLOCK_LEN
86	 *
87	 * Where:
88	 *
89	 *   BLOCKNR = (C_SIZE + 1) * MULT
90	 *   MULT = 2^(C_SIZE_MULT+2)
91	 *   BLOCK_LEN = 2^READ_BL_LEN
92	 */
93	read_bl_len = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE];
94	read_bl_len &= ALTERA_SDCARD_CSD_READ_BL_LEN_MASK;
95
96	byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE0];
97	byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MASK0;
98	byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE1];
99	byte2 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE2];
100	byte2 &= ALTERA_SDCARD_CSD_C_SIZE_MASK2;
101	c_size = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0) |
102	    (byte1 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1) |
103	    (byte2 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2);
104
105	byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
106	byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
107	byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
108	byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
109	c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
110	    (byte1 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
111
112	/*
113	 * If we're just getting back zero's, mark the card as bad, even
114	 * though it could just mean a Very Small Disk Indeed.
115	 */
116	if (c_size == 0 && c_size_mult == 0 && read_bl_len == 0) {
117		device_printf(sc->as_dev, "Ignored zero-size card\n");
118		return (ENXIO);
119	}
120	sc->as_mediasize = (c_size + 1) * (1 << (c_size_mult + 2)) *
121	    (1 << read_bl_len);
122	return (0);
123}
124
125int
126altera_sdcard_read_csd(struct altera_sdcard_softc *sc)
127{
128	uint8_t csd_structure;
129	int error;
130
131	ALTERA_SDCARD_LOCK_ASSERT(sc);
132
133	/*
134	 * XXXRW: Assume for now that when the SD Card IP Core negotiates
135	 * voltage/speed/etc, it must use the CSD register, and therefore
136	 * populates the SD Card IP Core's cache of the register value.  This
137	 * means that we can read it without issuing further SD Card commands.
138	 * If this assumption proves false, we will (a) get back garbage and
139	 * (b) need to add additional states in the driver state machine in
140	 * order to query card properties before I/O can start.
141	 *
142	 * XXXRW: Treating this as an array of bytes, so no byte swapping --
143	 * is that a safe assumption?
144	 */
145	KASSERT(((uintptr_t)&sc->as_csd.csd_data) % 2 == 0,
146	    ("%s: CSD buffer unaligned", __func__));
147	bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_CSD,
148	    (uint16_t *)sc->as_csd.csd_data, sizeof(sc->as_csd) / 2);
149
150	/*
151	 * Interpret the loaded CSD, extracting certain fields and copying
152	 * them into the softc for easy software access.
153	 *
154	 * Currently, we support only CSD Version 1.0.  If we detect a newer
155	 * version, suppress card detection.
156	 */
157	csd_structure = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_STRUCTURE_BYTE];
158	csd_structure &= ALTERA_SDCARD_CSD_STRUCTURE_MASK;
159	csd_structure >>= ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT;
160	sc->as_csd_structure = csd_structure;
161
162	/*
163	 * Interpret the CSD field based on its version.  Extract fields,
164	 * especially mediasize.
165	 *
166	 * XXXRW: Desirable to support further CSD versions here.
167	 */
168	switch (sc->as_csd_structure) {
169	case 0:
170		error = altera_sdcard_process_csd0(sc);
171		if (error)
172			return (error);
173		break;
174
175	default:
176		device_printf(sc->as_dev,
177		    "Ignored disk with unsupported CSD structure (%d)\n",
178		    sc->as_csd_structure);
179		return (ENXIO);
180	}
181	return (0);
182}
183
184/*
185 * XXXRW: The Altera IP Core specification indicates that RR1 is a 16-bit
186 * register, but all bits it identifies are >16 bit.  Most likely, RR1 is a
187 * 32-bit register?
188 */
189static uint16_t
190altera_sdcard_read_rr1(struct altera_sdcard_softc *sc)
191{
192
193	return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_RR1)));
194}
195
196static void
197altera_sdcard_write_cmd_arg(struct altera_sdcard_softc *sc, uint32_t cmd_arg)
198{
199
200	bus_write_4(sc->as_res, ALTERA_SDCARD_OFF_CMD_ARG, htole32(cmd_arg));
201}
202
203static void
204altera_sdcard_write_cmd(struct altera_sdcard_softc *sc, uint16_t cmd)
205{
206
207	bus_write_2(sc->as_res, ALTERA_SDCARD_OFF_CMD, htole16(cmd));
208}
209
210static void
211altera_sdcard_read_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
212    size_t len)
213{
214
215	KASSERT((uintptr_t)data % 2 == 0,
216	    ("%s: unaligned data %p", __func__, data));
217	KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
218	    ("%s: invalid length %ju", __func__, len));
219
220	bus_read_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
221	    (uint16_t *)data, len / 2);
222}
223
224static void
225altera_sdcard_write_rxtx_buffer(struct altera_sdcard_softc *sc, void *data,
226    size_t len)
227{
228	u_int corrections, differences, i, retry_counter;
229	uint16_t d, v;
230
231	KASSERT((uintptr_t)data % 2 == 0,
232	    ("%s: unaligned data %p", __func__, data));
233	KASSERT((len <= ALTERA_SDCARD_SECTORSIZE) && (len % 2 == 0),
234	    ("%s: invalid length %ju", __func__, len));
235
236	retry_counter = 0;
237	do {
238		bus_write_region_2(sc->as_res, ALTERA_SDCARD_OFF_RXTX_BUFFER,
239		    (uint16_t *)data, len / 2);
240
241		/*
242		 * XXXRW: Due to a possible hardware bug, the above call to
243		 * bus_write_region_2() might not succeed.  If the workaround
244		 * is enabled, verify each write and retry until it succeeds.
245		 *
246		 * XXXRW: Do we want a limit counter for retries here?
247		 */
248recheck:
249		corrections = 0;
250		differences = 0;
251		if (altera_sdcard_verify_rxtx_writes) {
252			for (i = 0; i < ALTERA_SDCARD_SECTORSIZE; i += 2) {
253				v = bus_read_2(sc->as_res,
254				    ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
255				d = *(uint16_t *)((uint8_t *)data + i);
256				if (v != d) {
257					if (retry_counter == 0) {
258						bus_write_2(sc->as_res,
259						    ALTERA_SDCARD_OFF_RXTX_BUFFER + i,
260						    d);
261						v = bus_read_2(sc->as_res,
262						    ALTERA_SDCARD_OFF_RXTX_BUFFER + i);
263						if (v == d) {
264							corrections++;
265							device_printf(sc->as_dev,
266							    "%s: single word rewrite worked"
267							    " at offset %u\n",
268							    __func__, i);
269							continue;
270						}
271					}
272					differences++;
273					device_printf(sc->as_dev,
274					    "%s: retrying write -- difference"
275					    " %u at offset %u, retry %u\n",
276					    __func__, differences, i,
277					    retry_counter);
278				}
279			}
280			if (differences != 0) {
281				retry_counter++;
282				if (retry_counter == 1 &&
283				    corrections == differences)
284					goto recheck;
285			}
286		}
287	} while (differences != 0);
288	if (retry_counter)
289		device_printf(sc->as_dev, "%s: succeeded after %u retries\n",
290		    __func__, retry_counter);
291}
292
293static void
294altera_sdcard_io_start_internal(struct altera_sdcard_softc *sc, struct bio *bp)
295{
296
297	switch (bp->bio_cmd) {
298	case BIO_READ:
299		altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
300		    ALTERA_SDCARD_SECTORSIZE);
301		altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_READ_BLOCK);
302		break;
303
304	case BIO_WRITE:
305		altera_sdcard_write_rxtx_buffer(sc, bp->bio_data,
306		    bp->bio_bcount);
307		altera_sdcard_write_cmd_arg(sc, bp->bio_pblkno *
308		    ALTERA_SDCARD_SECTORSIZE);
309		altera_sdcard_write_cmd(sc, ALTERA_SDCARD_CMD_WRITE_BLOCK);
310		break;
311
312	default:
313		panic("%s: unsupported I/O operation %d", __func__,
314		    bp->bio_cmd);
315	}
316}
317
318void
319altera_sdcard_io_start(struct altera_sdcard_softc *sc, struct bio *bp)
320{
321
322	ALTERA_SDCARD_LOCK_ASSERT(sc);
323	KASSERT(sc->as_currentbio == NULL,
324	    ("%s: bio already started", __func__));
325
326	/*
327	 * We advertise a block size and maximum I/O size up the stack of the
328	 * SD Card IP Core sector size.  Catch any attempts to not follow the
329	 * rules.
330	 */
331	KASSERT(bp->bio_bcount == ALTERA_SDCARD_SECTORSIZE,
332	    ("%s: I/O size not %d", __func__, ALTERA_SDCARD_SECTORSIZE));
333	altera_sdcard_io_start_internal(sc, bp);
334	sc->as_currentbio = bp;
335	sc->as_retriesleft = ALTERA_SDCARD_RETRY_LIMIT;
336}
337
338/*
339 * Handle completed I/O.  ASR is passed in to avoid reading it more than once.
340 * Return 1 if the I/O is actually complete (success, or retry limit
341 * exceeded), or 0 if not.
342 */
343int
344altera_sdcard_io_complete(struct altera_sdcard_softc *sc, uint16_t asr)
345{
346	struct bio *bp;
347	uint16_t rr1, mask;
348	int error;
349
350	ALTERA_SDCARD_LOCK_ASSERT(sc);
351	KASSERT(!(asr & ALTERA_SDCARD_ASR_CMDINPROGRESS),
352	    ("%s: still in progress", __func__));
353	KASSERT(asr & ALTERA_SDCARD_ASR_CARDPRESENT,
354	    ("%s: card removed", __func__));
355
356	bp = sc->as_currentbio;
357
358	/*-
359	 * Handle I/O retries if an error is returned by the device.  Various
360	 * quirks handled in the process:
361	 *
362	 * 1. ALTERA_SDCARD_ASR_CMDDATAERROR is ignored for BIO_WRITE.
363	 * 2. ALTERA_SDCARD_RR1_COMMANDCRCFAILED is optionally ignored for
364	 *    BIO_READ.
365	 */
366	error = 0;
367	rr1 = altera_sdcard_read_rr1(sc);
368	switch (bp->bio_cmd) {
369	case BIO_READ:
370		mask = ALTERA_SDCARD_RR1_ERRORMASK;
371		if (altera_sdcard_ignore_crc_errors)
372			mask &= ~ALTERA_SDCARD_RR1_COMMANDCRCFAILED;
373		if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
374			error = EIO;
375		else if ((asr & ALTERA_SDCARD_ASR_CMDDATAERROR) &&
376		    (rr1 & mask))
377			error = EIO;
378		else
379			error = 0;
380		break;
381
382	case BIO_WRITE:
383		if (asr & ALTERA_SDCARD_ASR_CMDTIMEOUT)
384			error = EIO;
385		else
386			error = 0;
387		break;
388
389	default:
390		break;
391	}
392	if (error) {
393		sc->as_retriesleft--;
394		if (sc->as_retriesleft == 0 || bootverbose)
395			device_printf(sc->as_dev, "%s: %s operation block %ju "
396			    "length %ju failed; asr 0x%08x (rr1: 0x%04x)%s\n",
397			    __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
398			    (bp->bio_cmd == BIO_WRITE ? "BIO_WRITE" :
399			    "unknown"),
400			    bp->bio_pblkno, bp->bio_bcount, asr, rr1,
401			    sc->as_retriesleft != 0 ? " retrying" : "");
402		/*
403		 * This attempt experienced an error; possibly retry.
404		 */
405		if (sc->as_retriesleft != 0) {
406			sc->as_flags |= ALTERA_SDCARD_FLAG_IOERROR;
407			altera_sdcard_io_start_internal(sc, bp);
408			return (0);
409		}
410		sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
411	} else {
412		/*
413		 * Successful I/O completion path.
414		 */
415		if (sc->as_flags & ALTERA_SDCARD_FLAG_IOERROR) {
416			device_printf(sc->as_dev, "%s: %s operation block %ju"
417			    " length %ju succeeded after %d retries\n",
418			    __func__, bp->bio_cmd == BIO_READ ? "BIO_READ" :
419			    (bp->bio_cmd == BIO_WRITE ? "write" : "unknown"),
420			    bp->bio_pblkno, bp->bio_bcount,
421			    ALTERA_SDCARD_RETRY_LIMIT - sc->as_retriesleft);
422			sc->as_flags &= ~ALTERA_SDCARD_FLAG_IOERROR;
423		}
424		switch (bp->bio_cmd) {
425		case BIO_READ:
426			altera_sdcard_read_rxtx_buffer(sc, bp->bio_data,
427			    bp->bio_bcount);
428			break;
429
430		case BIO_WRITE:
431			break;
432
433		default:
434			panic("%s: unsupported I/O operation %d", __func__,
435			    bp->bio_cmd);
436		}
437		bp->bio_resid = 0;
438		error = 0;
439	}
440	biofinish(bp, NULL, error);
441	sc->as_currentbio = NULL;
442	return (1);
443}
444