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