diff options
author | imp <imp@FreeBSD.org> | 2008-09-30 02:34:45 +0000 |
---|---|---|
committer | imp <imp@FreeBSD.org> | 2008-09-30 02:34:45 +0000 |
commit | 51dc1b851d697c82dd725789e7d2d156f445b980 (patch) | |
tree | 6447e133c0a464fe57da5a5086ae9d50e6719dbb | |
parent | 5a8e6d35724e8df2ff4dcb2547a9a7473a217fdb (diff) | |
download | FreeBSD-src-51dc1b851d697c82dd725789e7d2d156f445b980.zip FreeBSD-src-51dc1b851d697c82dd725789e7d2d156f445b980.tar.gz |
Improve support for multiple block read/write. This code is currently
disabled by default because there's problems with it on AT91RM9200,
currently the only host controller in the tree. I've not had time to
track those problems to ground. I'm committing because this is
important for other host controllers that are in the pipeline.
Submitted by: mav@
-rw-r--r-- | sys/dev/mmc/mmcsd.c | 80 |
1 files changed, 42 insertions, 38 deletions
diff --git a/sys/dev/mmc/mmcsd.c b/sys/dev/mmc/mmcsd.c index 5e60869..08a69f2 100644 --- a/sys/dev/mmc/mmcsd.c +++ b/sys/dev/mmc/mmcsd.c @@ -80,7 +80,7 @@ struct mmcsd_softc { int running; }; -#define MULTI_BLOCK_READ_BROKEN +#define MULTI_BLOCK_BROKEN /* bus entry points */ static int mmcsd_probe(device_t dev); @@ -106,7 +106,7 @@ static int mmcsd_probe(device_t dev) { - device_set_desc(dev, "mmc or sd flash card"); + device_set_desc(dev, "MMC/SD Memory Card"); return (0); } @@ -126,10 +126,16 @@ mmcsd_attach(device_t dev) // sc->disk->d_dump = mmcsd_dump; Need polling mmc layer sc->disk->d_name = "mmcsd"; sc->disk->d_drv1 = sc; - sc->disk->d_maxsize = DFLTPHYS; + sc->disk->d_maxsize = 256*1024; /* This is completely empirical */ sc->disk->d_sectorsize = mmc_get_sector_size(dev); - sc->disk->d_mediasize = mmc_get_media_size(dev); + sc->disk->d_mediasize = ((off_t)mmc_get_media_size(dev)) * + mmc_get_sector_size(dev); sc->disk->d_unit = device_get_unit(dev); + + device_printf(dev, "%juMB <MMC/SD Memory Card>%s at %s\n", + sc->disk->d_mediasize / 1048576, + mmc_get_read_only(dev)?" (read-only)":"", + device_get_nameunit(device_get_parent(sc->dev))); disk_create(sc->disk, DISK_VERSION); bioq_init(&sc->bio_queue); @@ -226,62 +232,60 @@ mmcsd_task(void *arg) MMCBUS_ACQUIRE_BUS(device_get_parent(dev), dev); sz = sc->disk->d_sectorsize; end = bp->bio_pblkno + (bp->bio_bcount / sz); - // XXX should use read/write_mulit for (block = bp->bio_pblkno; block < end;) { char *vaddr = bp->bio_data + (block - bp->bio_pblkno) * sz; + int numblocks; +#ifdef MULTI_BLOCK + numblocks = end - block; +#else + numblocks = 1; +#endif memset(&req, 0, sizeof(req)); memset(&cmd, 0, sizeof(cmd)); memset(&stop, 0, sizeof(stop)); req.cmd = &cmd; cmd.data = &data; if (bp->bio_cmd == BIO_READ) { -#ifdef MULTI_BLOCK_READ - if (end - block > 1) + if (numblocks > 1) cmd.opcode = MMC_READ_MULTIPLE_BLOCK; else cmd.opcode = MMC_READ_SINGLE_BLOCK; -#else - cmd.opcode = MMC_READ_SINGLE_BLOCK; -#endif - } else - cmd.opcode = MMC_WRITE_BLOCK; + } else { + if (numblocks > 1) + cmd.opcode = MMC_WRITE_MULTIPLE_BLOCK; + else + cmd.opcode = MMC_WRITE_BLOCK; + } cmd.arg = block << 9; cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - // data.timeout_ns = ; - // data.timeout_clks = ; data.data = vaddr; data.mrq = &req; - if (bp->bio_cmd == BIO_READ) { + if (bp->bio_cmd == BIO_READ) data.flags = MMC_DATA_READ; -#ifdef MULTI_BLOCK_READ - data.len = bp->bio_bcount; - if (end - block > 1) { - req.stop = &stop; - data.flags |= MMC_DATA_MULTI; - } - printf("Len %d %lld-%lld flags %#x sz %d\n", - data.len, block, end, data.flags, sz); - block = end; -#else - data.len = sz; - block++; -#endif - } else { + else data.flags = MMC_DATA_WRITE; - data.len = sz; - block++; + data.len = numblocks * sz; + if (numblocks > 1) { + data.flags |= MMC_DATA_MULTI; + stop.opcode = MMC_STOP_TRANSMISSION; + stop.arg = 0; + stop.flags = MMC_RSP_R1B | MMC_CMD_AC; + req.stop = &stop; } - stop.opcode = MMC_STOP_TRANSMISSION; - stop.arg = 0; - stop.flags = MMC_RSP_R1B | MMC_CMD_AC; +// printf("Len %d %lld-%lld flags %#x sz %d\n", +// (int)data.len, (long long)block, (long long)end, data.flags, sz); MMCBUS_WAIT_FOR_REQUEST(device_get_parent(dev), dev, &req); - // XXX error handling -//XXX while (!(mmc_send_status(dev) & R1_READY_FOR_DATA)) -// continue; - // XXX decode mmc status + if (req.cmd->error != MMC_ERR_NONE) + break; + block += numblocks; } MMCBUS_RELEASE_BUS(device_get_parent(dev), dev); + if (block < end) { + bp->bio_error = EIO; + bp->bio_resid = (end - block) * sz; + bp->bio_flags |= BIO_ERROR; + } biodone(bp); } |