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