From 51dc1b851d697c82dd725789e7d2d156f445b980 Mon Sep 17 00:00:00 2001 From: imp Date: Tue, 30 Sep 2008 02:34:45 +0000 Subject: 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@ --- sys/dev/mmc/mmcsd.c | 80 ++++++++++++++++++++++++++++------------------------- 1 file 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 %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); } -- cgit v1.1