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