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