PERFORCE change 105561 for review
Bernd Walter
ticso at FreeBSD.org
Sat Sep 2 21:33:52 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=105561
Change 105561 by ticso at ticso on 2006/09/02 21:33:45
add bio_queue and interrupt support
Affected files ...
.. //depot/projects/arm/src/sys/arm/at91/at91_qdmmc.c#2 edit
Differences ...
==== //depot/projects/arm/src/sys/arm/at91/at91_qdmmc.c#2 (text+ko) ====
@@ -40,6 +40,7 @@
#include <sys/timetc.h>
#include <sys/watchdog.h>
#include <sys/conf.h>
+#include <sys/kthread.h>
#include <machine/bus.h>
#include <machine/cpu.h>
@@ -64,7 +65,9 @@
bus_dmamap_t map;
struct disk *disk; /* XXX support only one card for */
int nb_cards;
+ struct proc *p;
struct {
+ struct bio_queue_head bio_queue;
char name[7];
uint32_t addr;
uint32_t CID[4];
@@ -101,6 +104,7 @@
static int at91_qdmmc_open(struct disk *dp);
static int at91_qdmmc_close(struct disk *dp);
static void at91_qdmmc_strategy(struct bio *bp);
+static void at91_qdmmc_task(void *arg);
#define AT91_QDMMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define AT91_QDMMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
@@ -301,11 +305,14 @@
/* declare clockrate to 5MHz - XXX the card may allow more */
sc->cards[card].mode = 5 * MCI_MR_CLKDIV | MCI_MR_PWSDIV | (MCI_MR_PWSDIV << 1 | AT91C_MCI_MR_PDCMODE);
sc->cards[card].mode = 75 * MCI_MR_CLKDIV | MCI_MR_PWSDIV | (MCI_MR_PWSDIV << 1);
+
+ bioq_init(&sc->cards[0].bio_queue);
}
if (sc->nb_cards == 0) {
printf("No MMC cards found\n");
goto out;
} else {
+ AT91_QDMMC_LOCK(sc);
/*
* Register the (XXX) first media as a disk
*/
@@ -318,13 +325,16 @@
sc->disk->d_drv1 = sc;
sc->disk->d_maxsize = DFLTPHYS;
sc->disk->d_unit = 0;
- sc->disk->d_flags = DISKFLAG_NEEDSGIANT;
+ //sc->disk->d_flags = DISKFLAG_NEEDSGIANT;
disk_create(sc->disk, DISK_VERSION);
}
/* set clockrate to 5MHz - XXX the card may allow more */
WR4(sc, MCI_MR, 5 * MCI_MR_CLKDIV | MCI_MR_PWSDIV | (MCI_MR_PWSDIV << 1) | AT91C_MCI_MR_PDCMODE);
+ AT91_QDMMC_UNLOCK(sc);
+
+ kthread_create(&at91_qdmmc_task, sc, &sc->p, 0, 0, "task: at91_qdmmc");
out:;
if (err)
at91_qdmmc_deactivate(dev);
@@ -396,12 +406,14 @@
//printf("at91_qdmmc_open: called\n");
sc = (struct at91_qdmmc_softc *)dp->d_drv1;
+ AT91_QDMMC_LOCK(sc);
sc->disk->d_sectorsize = sc->cards[0].sector_size;
sc->disk->d_mediasize = sc->cards[0].size;
//softc->disk->d_fwsectors = softc->params.secs_per_track;
//softc->disk->d_fwheads = softc->params.heads;
//sc->disk->d_devstat->block_size = sc->cards[0].sector_size;
//softc->disk->d_devstat->flags &= ~DEVSTAT_BS_UNAVAILABLE;
+ AT91_QDMMC_UNLOCK(sc);
return 0;
}
@@ -413,152 +425,180 @@
//printf("at91_qdmmc_close: called\n");
sc = (struct at91_qdmmc_softc *)dp->d_drv1;
+ AT91_QDMMC_LOCK(sc);
+ AT91_QDMMC_UNLOCK(sc);
+
// XXX do nothing since we don't lock for now
return 0;
}
-// XXX in fact we should queue the transfer
static void at91_qdmmc_strategy(struct bio *bp)
{
struct at91_qdmmc_softc *sc;
- int status;
- bus_addr_t addr;
- int map = 0;
//printf("at91_qdmmc_strategy: called\n");
sc = (struct at91_qdmmc_softc *)bp->bio_disk->d_drv1;
+ AT91_QDMMC_LOCK(sc);
+ bioq_disksort(&sc->cards[0].bio_queue, bp);
+ wakeup(sc);
+ AT91_QDMMC_UNLOCK(sc);
+}
+
+static void at91_qdmmc_task(void *arg) {
+ struct at91_qdmmc_softc *sc = (struct at91_qdmmc_softc*)arg;
+ struct bio *bp;
+ int status;
+ bus_addr_t addr;
+ int map = 0;
+ uint32_t *tmpbuf;
- if (bp->bio_cmd == BIO_READ) {
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, (sc->cards[0].addr) << 16);
- //printf("at91_qdmmc_strategy: select_card-status = 0x%x\n", status);
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_SET_BLOCKLEN_CMD, sc->cards[0].sector_size);
- //printf("at91_qdmmc_strategy: set_blocklen-status = 0x%x\n", status);
- //printf("at91_qdmmc_strategy: read block %lld, bcount %ld\n", bp->bio_pblkno, bp->bio_bcount);
- uint32_t block;
- // Init Mode Register
- WR4(sc, MCI_MR, sc->cards[0].mode | (sc->cards[0].sector_size << 16));
- //printf("mode 0x%x\n", RD4(sc, MCI_MR));
- for (block = bp->bio_pblkno; block < bp->bio_pblkno + (bp->bio_bcount / sc->cards[0].sector_size); block++) {
+ tmpbuf = malloc(sc->cards[0].sector_size, M_DEVBUF, M_WAITOK);
+ AT91_QDMMC_LOCK(sc);
+ //printf("at91_qdmmc_task: start\n");
+ for (;;) {
+ do {
+ bp = bioq_first(&sc->cards[0].bio_queue);
+ if (bp == NULL)
+ msleep(sc, &sc->sc_mtx, PRIBIO, "jobqueue", 0);
+ } while (bp == NULL);
+ bioq_remove(&sc->cards[0].bio_queue, bp);
+ //printf("at91_qdmmc_task: request %p\n", bp);
+ if (bp->bio_cmd == BIO_READ) {
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, (sc->cards[0].addr) << 16);
+ //printf("at91_qdmmc_task: select_card-status = 0x%x\n", status);
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_SET_BLOCKLEN_CMD, sc->cards[0].sector_size);
+ //printf("at91_qdmmc_task: set_blocklen-status = 0x%x\n", status);
+ //printf("at91_qdmmc_task: read block %lld, bcount %ld\n", bp->bio_pblkno, bp->bio_bcount);
+ uint32_t block;
+ // Init Mode Register
+ WR4(sc, MCI_MR, sc->cards[0].mode | (sc->cards[0].sector_size << 16));
+ //printf("mode 0x%x\n", RD4(sc, MCI_MR));
+ for (block = bp->bio_pblkno; block < bp->bio_pblkno + (bp->bio_bcount / sc->cards[0].sector_size); block++) {
- WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
+ WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
- char *paddr = bp->bio_data + (block - bp->bio_pblkno) * sc->cards[0].sector_size;
+ char *paddr = bp->bio_data + (block - bp->bio_pblkno) * sc->cards[0].sector_size;
- if (bus_dmamap_load(sc->dmatag, sc->map, paddr,
- sc->cards[0].sector_size, at91_getaddr, &addr, 0) != 0)
- goto out;
- map = 1;
+ if (bus_dmamap_load(sc->dmatag, sc->map, paddr,
+ sc->cards[0].sector_size, at91_getaddr, &addr, 0) != 0)
+ goto out;
+ map = 1;
- bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREREAD);
- WR4(sc, PDC_RPR, addr);
- WR4(sc, PDC_RCR, sc->cards[0].sector_size / 4);
- WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
+ bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREREAD);
+ WR4(sc, PDC_RPR, addr);
+ WR4(sc, PDC_RCR, sc->cards[0].sector_size / 4);
+ WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN);
+ WR4(sc, MCI_IER, MCI_SR_RXBUFF);
- //printf("status = 0x%x, paddr = %p, RPR = 0x%x, RCR = 0x%x\n", status, paddr,
- // RD4(sc, PDC_RPR), RD4(sc, PDC_RCR));
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_READ_SINGLE_BLOCK_CMD, block * sc->cards[0].sector_size);
- //printf("at91_qdmmc_strategy: read-status = 0x%x\n", status);
+ //printf("status = 0x%x, paddr = %p, RPR = 0x%x, RCR = 0x%x\n", status, paddr,
+ // RD4(sc, PDC_RPR), RD4(sc, PDC_RCR));
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_READ_SINGLE_BLOCK_CMD, block * sc->cards[0].sector_size);
+ //printf("at91_qdmmc_task: read-status = 0x%x\n", status);
- // wait for completion
- // XXX should be done as an ISR of some sort.
- while ((RD4(sc, MCI_SR) & MCI_SR_ENDRX) == 0)
- DELAY(700);
+ // wait for completion
+ msleep(sc, &sc->sc_mtx, PRIBIO, "endrx", 0);
+ // safety check
+ while ((RD4(sc, MCI_SR) & MCI_SR_ENDRX) == 0)
+ DELAY(700);
- bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->dmatag, sc->map);
- map = 0;
+ bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->dmatag, sc->map);
+ map = 0;
- /* Fix Byteorder (Atmel Errata) */
- uint32_t* base = (uint32_t*)paddr;
- for (int i = 0; i < sc->cards[0].sector_size / 4; i++) {
- uint32_t tmp = base[i];
- base[i] = (((tmp >> 24) & 0xff)) |
- (((tmp >> 16) & 0xff) << 8) |
- (((tmp >> 8) & 0xff) << 16) |
- ((tmp & 0xff) << 24);
+ /* Fix Byteorder (Atmel Errata) */
+ uint32_t* base = (uint32_t*)paddr;
+ for (int i = 0; i < sc->cards[0].sector_size / 4; i++) {
+ uint32_t tmp = base[i];
+ base[i] = (((tmp >> 24) & 0xff)) |
+ (((tmp >> 16) & 0xff) << 8) |
+ (((tmp >> 8) & 0xff) << 16) |
+ ((tmp & 0xff) << 24);
+ }
}
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, 0);
+ //printf("at91_qdmmc_task: deselect_card-status = 0x%x\n", status);
+
+ // Reset Mode Register
+ WR4(sc, MCI_MR, sc->cards[0].mode);
+ biodone(bp);
+ continue;
}
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, 0);
- //printf("at91_qdmmc_strategy: deselect_card-status = 0x%x\n", status);
+ if (bp->bio_cmd == BIO_WRITE) {
+ //printf("at91_qdmmc_task: write block %lld, bcount %ld\n", bp->bio_pblkno, bp->bio_bcount);
+ uint32_t block;
+ //uint32_t *tmpbuf;
+
+ // Init Mode Register
+ WR4(sc, MCI_MR, sc->cards[0].mode | (sc->cards[0].sector_size << 16));
+ // printf("mode 0x%x\n", RD4(sc, MCI_MR));
- // Reset Mode Register
- WR4(sc, MCI_MR, sc->cards[0].mode);
- biodone(bp);
- return;
- }
- if (bp->bio_cmd == BIO_WRITE) {
- //printf("at91_qdmmc_strategy: write block %lld, bcount %ld\n", bp->bio_pblkno, bp->bio_bcount);
- uint32_t block;
- uint32_t *tmpbuf;
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, (sc->cards[0].addr) << 16);
+ // printf("at91_qdmmc_task: select_card-status = 0x%x\n", status);
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_SET_BLOCKLEN_CMD, sc->cards[0].sector_size);
+ // printf("at91_qdmmc_task: set_blocklen-status = 0x%x\n", status);
- // Init Mode Register
- WR4(sc, MCI_MR, sc->cards[0].mode | (sc->cards[0].sector_size << 16));
- // printf("mode 0x%x\n", RD4(sc, MCI_MR));
+ //tmpbuf = malloc(sc->cards[0].sector_size, M_DEVBUF, M_WAITOK);
+ for (block = bp->bio_pblkno; block < bp->bio_pblkno + (bp->bio_bcount / sc->cards[0].sector_size); block++) {
+ char *paddr = bp->bio_data + (block - bp->bio_pblkno) * sc->cards[0].sector_size;
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, (sc->cards[0].addr) << 16);
- // printf("at91_qdmmc_strategy: select_card-status = 0x%x\n", status);
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_SET_BLOCKLEN_CMD, sc->cards[0].sector_size);
- // printf("at91_qdmmc_strategy: set_blocklen-status = 0x%x\n", status);
+ /* Fix Byteorder (Atmel Errata) */
+ uint32_t* base = (uint32_t*)paddr;
+ for (int i = 0; i < sc->cards[0].sector_size / 4; i++) {
+ uint32_t tmp = base[i];
+ tmpbuf[i] = (((tmp >> 24) & 0xff)) |
+ (((tmp >> 16) & 0xff) << 8) |
+ (((tmp >> 8) & 0xff) << 16) |
+ ((tmp & 0xff) << 24);
+ }
- tmpbuf = malloc(sc->cards[0].sector_size, M_DEVBUF, M_WAITOK);
- for (block = bp->bio_pblkno; block < bp->bio_pblkno + (bp->bio_bcount / sc->cards[0].sector_size); block++) {
- char *paddr = bp->bio_data + (block - bp->bio_pblkno) * sc->cards[0].sector_size;
+ WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
- /* Fix Byteorder (Atmel Errata) */
- uint32_t* base = (uint32_t*)paddr;
- for (int i = 0; i < sc->cards[0].sector_size / 4; i++) {
- uint32_t tmp = base[i];
- tmpbuf[i] = (((tmp >> 24) & 0xff)) |
- (((tmp >> 16) & 0xff) << 8) |
- (((tmp >> 8) & 0xff) << 16) |
- ((tmp & 0xff) << 24);
- }
+ if (bus_dmamap_load(sc->dmatag, sc->map, tmpbuf,
+ sc->cards[0].sector_size, at91_getaddr, &addr, 0) != 0)
+ goto out;
+ map = 1;
- WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS);
+ bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREWRITE);
+ WR4(sc, PDC_TPR, addr);
+ WR4(sc, PDC_TCR, sc->cards[0].sector_size / 4);
- if (bus_dmamap_load(sc->dmatag, sc->map, tmpbuf,
- sc->cards[0].sector_size, at91_getaddr, &addr, 0) != 0)
- goto out;
- map = 1;
+ // printf("status = 0x%x, tmpbuf = %p, TPR = 0x%x, TCR = 0x%x\n", status, tmpbuf,
+ // RD4(sc, PDC_TPR), RD4(sc, PDC_TCR));
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_WRITE_BLOCK_CMD, block * sc->cards[0].sector_size);
+ // printf("at91_qdmmc_task: write-status = 0x%x\n", status);
+ WR4(sc, MCI_IER, MCI_SR_NOTBUSY);
+ WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN);
- bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREWRITE);
- WR4(sc, PDC_TPR, addr);
- WR4(sc, PDC_TCR, sc->cards[0].sector_size / 4);
+ // wait for completion
+ msleep(sc, &sc->sc_mtx, PRIBIO, "notbusy", 0);
+ // XXX don't know why this safety check is required
+ while ((RD4(sc, MCI_SR) & MCI_SR_NOTBUSY) == 0)
+ DELAY(700);
- // printf("status = 0x%x, tmpbuf = %p, TPR = 0x%x, TCR = 0x%x\n", status, tmpbuf,
- // RD4(sc, PDC_TPR), RD4(sc, PDC_TCR));
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_WRITE_BLOCK_CMD, block * sc->cards[0].sector_size);
- // printf("at91_qdmmc_strategy: write-status = 0x%x\n", status);
- WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN);
+ bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->dmatag, sc->map);
+ map = 0;
+ }
+ //free(tmpbuf, M_DEVBUF);
- // wait for completion
- // XXX should be done as an ISR of some sort.
- while ((RD4(sc, MCI_SR) & MCI_SR_NOTBUSY) == 0)
- DELAY(700);
+ status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, 0);
+ //printf("at91_qdmmc_task: deselect_card-status = 0x%x\n", status);
- bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->dmatag, sc->map);
- map = 0;
+ // Reset Mode Register
+ WR4(sc, MCI_MR, sc->cards[0].mode);
+ biodone(bp);
+ continue;
}
- free(tmpbuf, M_DEVBUF);
+out:
+ if (map)
+ bus_dmamap_unload(sc->dmatag, sc->map);
status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, 0);
- //printf("at91_qdmmc_strategy: deselect_card-status = 0x%x\n", status);
-
- // Reset Mode Register
- WR4(sc, MCI_MR, sc->cards[0].mode);
- biodone(bp);
- return;
+ //printf("at91_qdmmc_task: deselect_card-status = 0x%x\n", status);
+ AT91_QDMMC_UNLOCK(sc);
+ biofinish(bp, NULL, ENXIO);
}
-
-out:
- if (map)
- bus_dmamap_unload(sc->dmatag, sc->map);
- status = at91_qdmmc_SendCommand(sc->dev, AT91C_SEL_DESEL_CARD_CMD, 0);
- printf("at91_qdmmc_strategy: deselect_card-status = 0x%x\n", status);
- biofinish(bp, NULL, ENXIO);
- return;
}
static device_method_t at91_qdmmc_methods[] = {
@@ -581,5 +621,11 @@
static void
at91_qdmmc_intr(void *arg)
{
- // TODO
+ struct at91_qdmmc_softc *sc = (struct at91_qdmmc_softc*)arg;
+
+ AT91_QDMMC_LOCK(sc);
+ //printf("i 0x%x\n", RD4(sc, MCI_SR));
+ wakeup(sc);
+ WR4(sc, MCI_IDR, 0xffffffff);
+ AT91_QDMMC_UNLOCK(sc);
}
More information about the p4-projects
mailing list