bk://bk.arm.linux.org.uk/linux-2.6-mmc
rmk@flint.arm.linux.org.uk|ChangeSet|20040906183650|43108 rmk

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/09/06 17:12:49-07:00 akpm@bix.(none) 
#   Merge bk://bk.arm.linux.org.uk/linux-2.6-mmc
#   into bix.(none):/usr/src/bk-mmc
# 
# drivers/mmc/mmc_block.c
#   2004/09/06 17:12:45-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/09/06 19:36:50+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMC_RSP_xxx combined response types.
#   
#   Create a set of MMC_RSP_xxx definitions which correspond to the
#   response type we expect at a high level.  These are created from
#   a set of flags; a MMC host driver can either interpret the flags
#   as the high level response type, or the low level individual
#   flags.
# 
# include/linux/mmc/mmc.h
#   2004/09/06 19:33:47+01:00 rmk@flint.arm.linux.org.uk +10 -0
#   Define MMC_RSP_xxx combined response types.
# 
# drivers/mmc/mmc_block.c
#   2004/09/06 19:33:47+01:00 rmk@flint.arm.linux.org.uk +5 -5
#   Use MMC_RSP_xxx combined response flags instead of individual bits.
# 
# drivers/mmc/mmc.c
#   2004/09/06 19:33:47+01:00 rmk@flint.arm.linux.org.uk +6 -6
#   Use MMC_RSP_xxx combined response flags instead of individual bits.
# 
# ChangeSet
#   2004/08/31 22:36:35-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mmc
# 
# drivers/mmc/mmc_block.c
#   2004/08/31 22:36:30-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/30 17:43:10+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] PXAMCI: Bracket power management calls with CONFIG_PM.
# 
# drivers/mmc/pxamci.c
#   2004/08/30 17:40:45+01:00 rmk@flint.arm.linux.org.uk +5 -0
#   Bracket power management calls with CONFIG_PM.
# 
# ChangeSet
#   2004/08/30 17:33:23+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: Ensure that we read all data from FIFO.
#   
#   When we are nearing the end of a transfer from the card, we may not
#   have sufficient data in the FIFO to trigger a "half FIFO full" IRQ.
#   Therefore, when we have less than MCI_FIFOSIZE bytes left, switch to
#   "FIFO contains data" IRQ mode instead.
# 
# drivers/mmc/mmci.c
#   2004/08/30 17:31:00+01:00 rmk@flint.arm.linux.org.uk +7 -0
#   Enable the rx data available irq mask towards then end of a receive
#   data transfer.
# 
# ChangeSet
#   2004/08/30 17:17:25+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: Add SG support to PIO data transfers
#   
#   This allows us to transfer a whole request for multiple pages in one
#   transaction with the MMC card, resulting in higher overall throughput.
# 
# drivers/mmc/mmci.c
#   2004/08/30 17:14:26+01:00 rmk@flint.arm.linux.org.uk +66 -5
#   Add scatter-gather support to PIO data transfers, and enable the
#   feature.
# 
# ChangeSet
#   2004/08/30 17:03:48+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: use bio_kmap_irq() rather than req->buffer
#   
#   This is in preparation for SG data IO.
# 
# drivers/mmc/mmci.c
#   2004/08/30 17:01:15+01:00 rmk@flint.arm.linux.org.uk +41 -22
#   Map BIO buffer with bio_kmap_irq() rather than using req->buffer
#   directly.
# 
# ChangeSet
#   2004/08/30 16:23:08+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: Maintain offset rather than buffer pointer for PIO
# 
# drivers/mmc/mmci.h
#   2004/08/30 16:20:21+01:00 rmk@flint.arm.linux.org.uk +1 -1
#   *buffer becomes offset
# 
# drivers/mmc/mmci.c
#   2004/08/30 16:20:20+01:00 rmk@flint.arm.linux.org.uk +11 -9
#   Maintain a buffer offset rather than the buffer pointer for PIO
#   data transfers.
# 
# ChangeSet
#   2004/08/30 16:13:28+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: split the PIO data read and write paths.
# 
# drivers/mmc/mmci.c
#   2004/08/30 16:11:08+01:00 rmk@flint.arm.linux.org.uk +64 -29
#   Separate the PIO data read and write paths.  We select read or write
#   depending on whether the TX or RX active status flags are set.
# 
# ChangeSet
#   2004/08/30 15:38:01+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: Manipulate IRQ masks according to the data FSM state.
#   
#   Prevent IRQ race conditions between the two handlers and within the
#   primecell itself.  Unfortunately, the primecell does not always mask
#   the FIFO empty interrupt we reach the end of a transfer to the card.
#   Also, we may receive the "data end" interrupt prior to finishing a
#   transfer from the card, so mask this off until we've read the last
#   bytes from the FIFO.
# 
# drivers/mmc/mmci.h
#   2004/08/30 15:35:25+01:00 rmk@flint.arm.linux.org.uk +1 -2
#   Disable data end IRQ mask
# 
# drivers/mmc/mmci.c
#   2004/08/30 15:35:25+01:00 rmk@flint.arm.linux.org.uk +13 -18
#   Manipulate IRQ masks according to the data FSM state.
# 
# ChangeSet
#   2004/08/30 12:46:45+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: data FSM handling updates
#   
#   - Use mmci_stop_host() to ensure that the data FSM is shut down and
#     any driver held data is properly released.
#   - FIFO size is 64 bytes not 16.
# 
# drivers/mmc/mmci.h
#   2004/08/30 12:44:09+01:00 rmk@flint.arm.linux.org.uk +4 -3
#   Correct MMCI fifo size.
#   Remove unused to_mmci_host macro.
# 
# drivers/mmc/mmci.c
#   2004/08/30 12:44:08+01:00 rmk@flint.arm.linux.org.uk +10 -3
#   Add mmci_stop_host() to disable MMCI data FSM.
# 
# ChangeSet
#   2004/08/30 11:12:18+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] MMCI: Remove hardcoded MCI_IRQMASK definition
# 
# drivers/mmc/mmci.h
#   2004/08/30 11:09:10+01:00 rmk@flint.arm.linux.org.uk +0 -5
#   Remove hardcoded MCI_IRQMASK definition.
# 
# drivers/mmc/mmci.c
#   2004/08/30 11:08:33+01:00 rmk@flint.arm.linux.org.uk +1 -3
#   Mask chip irq status with irq mask 0 to mask out unwanted IRQs
# 
# ChangeSet
#   2004/08/30 10:58:22+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] Give the MMC host the full-sized request.
#   
#   Pass the total number of MMC data blocks in the request to the
#   host driver.  Since existing MMC host drivers do not support
#   scatter-gather at present, the block queue defaults have been
#   chosen to prevent scatter-gather block requests for MMC.  A
#   host can alter these parameters when it wishes to take advantage
#   of SG capabilities.
# 
# drivers/mmc/mmc_block.c
#   2004/08/30 10:52:59+01:00 rmk@flint.arm.linux.org.uk +1 -1
#   Pass the total number of MMC data blocks in the request to the
#   host driver.
# 
# ChangeSet
#   2004/08/30 10:49:37+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] Add host specific block queue parameters
#   
#   Allow MMC host drivers to specify their data phase capabilities
#   to the block queue.  This will eventually allow us to perform
#   SG data phase operations, thereby processing a single request
#   in one go.
# 
# drivers/mmc/mmc_block.c
#   2004/08/30 10:43:31+01:00 rmk@flint.arm.linux.org.uk +0 -5
#   Remove 'maxsectors' parameter and associated queue setting.
#   This is a host specific parameter now.
# 
# drivers/mmc/mmc_queue.c
#   2004/08/30 10:41:24+01:00 rmk@flint.arm.linux.org.uk +7 -2
#   When creating a new block queue, set the queue parameters
#   from the host specific data.
# 
# drivers/mmc/mmc.c
#   2004/08/30 10:40:28+01:00 rmk@flint.arm.linux.org.uk +11 -1
#   Add host specific block queue default settings
# 
# include/linux/mmc/host.h
#   2004/08/30 10:40:06+01:00 rmk@flint.arm.linux.org.uk +7 -0
#   Add host specific block queue data
# 
# ChangeSet
#   2004/08/30 10:30:55+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] Remove unused host->priv
# 
# include/linux/mmc/host.h
#   2004/08/30 10:22:39+01:00 rmk@flint.arm.linux.org.uk +0 -1
#   Remove unused host->priv
# 
# drivers/mmc/mmc.c
#   2004/08/30 10:22:22+01:00 rmk@flint.arm.linux.org.uk +0 -2
#   Remove unused host->priv
# 
# ChangeSet
#   2004/08/30 10:20:35+01:00 rmk@flint.arm.linux.org.uk 
#   [MMC] Use local card pointer rather than md->queue.card
# 
# drivers/mmc/mmc_block.c
#   2004/08/30 10:16:45+01:00 rmk@flint.arm.linux.org.uk +3 -3
#   No point using md->queue.card when we already have a
#   pointer to the card itself.
# 
# ChangeSet
#   2004/08/28 16:33:46-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mmc
# 
# arch/arm/Kconfig
#   2004/08/28 16:33:42-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/25 19:21:58-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mmc
# 
# arch/arm/Kconfig
#   2004/08/25 19:21:54-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/24 21:17:52-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mmc
# 
# arch/arm/Kconfig
#   2004/08/24 21:17:48-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/23 16:36:54-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mmc
# 
# drivers/Makefile
#   2004/08/23 16:36:50-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/arm/Kconfig
#   2004/08/23 16:36:49-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/22 21:28:32-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-mmc
# 
# arch/arm/Kconfig
#   2004/08/22 21:28:28-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/08/19 02:03:19-07:00 akpm@bix.(none) 
#   Merge bk://bk.arm.linux.org.uk/linux-2.6-mmc
#   into bix.(none):/usr/src/bk-mmc
# 
# drivers/Makefile
#   2004/08/19 02:03:15-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# arch/arm/Kconfig
#   2004/08/19 02:03:15-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
diff -Nru a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
--- a/drivers/mmc/mmc.c	2004-09-06 17:13:54 -07:00
+++ b/drivers/mmc/mmc.c	2004-09-06 17:13:54 -07:00
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/mmc/mmc.c
  *
- *  Copyright (C) 2003 Russell King, All Rights Reserved.
+ *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -14,6 +14,7 @@
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/delay.h>
+#include <linux/pagemap.h>
 #include <linux/err.h>
 
 #include <linux/mmc/card.h>
@@ -212,7 +213,7 @@
 
 		cmd.opcode = MMC_SELECT_CARD;
 		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
+		cmd.flags = MMC_RSP_R1;
 
 		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
 	}
@@ -430,7 +431,7 @@
 
 	cmd.opcode = MMC_SEND_OP_COND;
 	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_SHORT;
+	cmd.flags = MMC_RSP_R3;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -468,7 +469,7 @@
 
 		cmd.opcode = MMC_ALL_SEND_CID;
 		cmd.arg = 0;
-		cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
+		cmd.flags = MMC_RSP_R2;
 
 		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
 		if (err == MMC_ERR_TIMEOUT) {
@@ -497,7 +498,7 @@
 
 		cmd.opcode = MMC_SET_RELATIVE_ADDR;
 		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
+		cmd.flags = MMC_RSP_R1;
 
 		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
 		if (err != MMC_ERR_NONE)
@@ -518,7 +519,7 @@
 
 		cmd.opcode = MMC_SEND_CSD;
 		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
+		cmd.flags = MMC_RSP_R2;
 
 		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
 		if (err != MMC_ERR_NONE) {
@@ -566,7 +567,7 @@
 
 		cmd.opcode = MMC_SEND_STATUS;
 		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
+		cmd.flags = MMC_RSP_R1;
 
 		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
 		if (err == MMC_ERR_NONE)
@@ -715,14 +716,21 @@
 	if (host) {
 		memset(host, 0, sizeof(struct mmc_host) + extra);
 
-		host->priv = host + 1;
-
 		spin_lock_init(&host->lock);
 		init_waitqueue_head(&host->wq);
 		INIT_LIST_HEAD(&host->cards);
 		INIT_WORK(&host->detect, mmc_rescan, host);
 
 		host->dev = dev;
+
+		/*
+		 * By default, hosts do not support SGIO or large requests.
+		 * They have to set these according to their abilities.
+		 */
+		host->max_hw_segs = 1;
+		host->max_phys_segs = 1;
+		host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
+		host->max_seg_size = PAGE_CACHE_SIZE;
 	}
 
 	return host;
diff -Nru a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
--- a/drivers/mmc/mmc_block.c	2004-09-06 17:13:54 -07:00
+++ b/drivers/mmc/mmc_block.c	2004-09-06 17:13:54 -07:00
@@ -43,7 +43,6 @@
 #define MMC_SHIFT	3
 
 static int mmc_major;
-static int maxsectors = 8;
 
 /*
  * There is one mmc_blk_data per slot.
@@ -180,22 +179,22 @@
 		brq.mrq.data = &brq.data;
 
 		brq.cmd.arg = req->sector << 9;
-		brq.cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
+		brq.cmd.flags = MMC_RSP_R1;
 		brq.data.req = req;
 		brq.data.timeout_ns = card->csd.tacc_ns * 10;
 		brq.data.timeout_clks = card->csd.tacc_clks * 10;
 		brq.data.blksz_bits = md->block_bits;
-		brq.data.blocks = req->current_nr_sectors >> (md->block_bits - 9);
+		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
 		brq.stop.opcode = MMC_STOP_TRANSMISSION;
 		brq.stop.arg = 0;
-		brq.stop.flags = MMC_RSP_SHORT | MMC_RSP_CRC | MMC_RSP_BUSY;
+		brq.stop.flags = MMC_RSP_R1B;
 
 		if (rq_data_dir(req) == READ) {
 			brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
 			brq.data.flags |= MMC_DATA_READ;
 		} else {
 			brq.cmd.opcode = MMC_WRITE_BLOCK;
-			brq.cmd.flags |= MMC_RSP_BUSY;
+			brq.cmd.flags = MMC_RSP_R1B;
 			brq.data.flags |= MMC_DATA_WRITE;
 			brq.data.blocks = 1;
 		}
@@ -225,7 +224,7 @@
 
 			cmd.opcode = MMC_SEND_STATUS;
 			cmd.arg = card->rca << 16;
-			cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
+			cmd.flags = MMC_RSP_R1;
 			err = mmc_wait_for_cmd(card->host, &cmd, 5);
 			if (err) {
 				printk(KERN_ERR "%s: error %d requesting status\n",
@@ -334,11 +333,10 @@
 		sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 		sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
 
-		md->block_bits = md->queue.card->csd.read_blkbits;
+		md->block_bits = card->csd.read_blkbits;
 
-		blk_queue_max_sectors(md->queue.queue, maxsectors);
 		blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
-		set_capacity(md->disk, md->queue.card->csd.capacity);
+		set_capacity(md->disk, card->csd.capacity);
 	}
  out:
 	return md;
@@ -353,7 +351,7 @@
 	mmc_card_claim_host(card);
 	cmd.opcode = MMC_SET_BLOCKLEN;
 	cmd.arg = 1 << card->csd.read_blkbits;
-	cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
+	cmd.flags = MMC_RSP_R1;
 	err = mmc_wait_for_cmd(card->host, &cmd, 5);
 	mmc_card_release_host(card);
 
@@ -440,7 +438,7 @@
 	struct mmc_blk_data *md = mmc_get_drvdata(card);
 
 	if (md) {
-		mmc_blk_set_blksize(md, md->queue.card);
+		mmc_blk_set_blksize(md, card);
 		blk_start_queue(md->queue.queue);
 	}
 	return 0;
@@ -489,9 +487,6 @@
 
 module_init(mmc_blk_init);
 module_exit(mmc_blk_exit);
-module_param(maxsectors, int, 0444);
-
-MODULE_PARM_DESC(maxsectors, "Maximum number of sectors for a single request");
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
diff -Nru a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
--- a/drivers/mmc/mmc_queue.c	2004-09-06 17:13:54 -07:00
+++ b/drivers/mmc/mmc_queue.c	2004-09-06 17:13:54 -07:00
@@ -124,11 +124,12 @@
  */
 int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
 {
+	struct mmc_host *host = card->host;
 	u64 limit = BLK_BOUNCE_HIGH;
 	int ret;
 
-	if (card->host->dev->dma_mask && *card->host->dev->dma_mask)
-		limit = *card->host->dev->dma_mask;
+	if (host->dev->dma_mask && *host->dev->dma_mask)
+		limit = *host->dev->dma_mask;
 
 	mq->card = card;
 	mq->queue = blk_init_queue(mmc_request, lock);
@@ -137,6 +138,10 @@
 
 	blk_queue_prep_rq(mq->queue, mmc_prep_request);
 	blk_queue_bounce_limit(mq->queue, limit);
+	blk_queue_max_sectors(mq->queue, host->max_sectors);
+	blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
+	blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
+	blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
 	mq->queue->queuedata = mq;
 	mq->req = NULL;
diff -Nru a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
--- a/drivers/mmc/mmci.c	2004-09-06 17:13:54 -07:00
+++ b/drivers/mmc/mmci.c	2004-09-06 17:13:54 -07:00
@@ -43,10 +43,9 @@
 mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
 {
 	writel(0, host->base + MMCICOMMAND);
+
 	host->mrq = NULL;
 	host->cmd = NULL;
-	host->data = NULL;
-	host->buffer = NULL;
 
 	if (mrq->data)
 		mrq->data->bytes_xfered = host->data_xfered;
@@ -60,6 +59,13 @@
 	spin_lock(&host->lock);
 }
 
+static void mmci_stop_data(struct mmci_host *host)
+{
+	writel(0, host->base + MMCIDATACTRL);
+	writel(0, host->base + MMCIMASK1);
+	host->data = NULL;
+}
+
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
 	unsigned int datactrl, timeout, irqmask;
@@ -69,7 +75,7 @@
 	    1 << data->blksz_bits, data->blocks, data->flags);
 
 	host->data = data;
-	host->buffer = data->req->buffer;
+	host->offset = 0;
 	host->size = data->blocks << data->blksz_bits;
 	host->data_xfered = 0;
 
@@ -94,6 +100,7 @@
 	}
 
 	writel(datactrl, base + MMCIDATACTRL);
+	writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
 	writel(irqmask, base + MMCIMASK1);
 }
 
@@ -147,7 +154,8 @@
 		status |= MCI_DATAEND;
 	}
 	if (status & MCI_DATAEND) {
-		host->data = NULL;
+		mmci_stop_data(host);
+
 		if (!data->stop) {
 			mmci_request_end(host, data->mrq);
 		} else {
@@ -182,72 +190,171 @@
 	}
 }
 
-/*
- * PIO data transfer IRQ handler.
- */
-static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
+static int mmci_pio_read(struct mmci_host *host, struct request *req, u32 status)
 {
-	struct mmci_host *host = dev_id;
 	void *base = host->base;
-	u32 status;
 	int ret = 0;
 
 	do {
-		status = readl(base + MMCISTATUS);
+		unsigned long flags;
+		unsigned int bio_remain;
+		char *buffer;
 
-		if (!(status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL|
-				MCI_TXFIFOHALFEMPTY)))
+		/*
+		 * Check for data available.
+		 */
+		if (!(status & MCI_RXDATAAVLBL))
 			break;
 
-		DBG(host, "irq1 %08x\n", status);
+		/*
+		 * Map the BIO buffer.
+		 */
+		buffer = bio_kmap_irq(req->cbio, &flags);
+		bio_remain = (req->current_nr_sectors << 9) - host->offset;
 
-		if (status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL)) {
-			unsigned int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
-			if (count < 0)
-				count = 0;
-			if (count && host->buffer) {
-				readsl(base + MMCIFIFO, host->buffer, count >> 2);
-				host->buffer += count;
+		do {
+			int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+
+			if (count > bio_remain)
+				count = bio_remain;
+
+			if (count > 0) {
+				ret = 1;
+				readsl(base + MMCIFIFO, buffer + host->offset, count >> 2);
+				host->offset += count;
 				host->size -= count;
-				if (host->size == 0)
-					host->buffer = NULL;
-			} else {
-				static int first = 1;
-				if (first) {
-					first = 0;
-					printk(KERN_ERR "MMCI: sinking excessive data\n");
-				}
-				readl(base + MMCIFIFO);
+				bio_remain -= count;
+				if (bio_remain == 0)
+					goto next_bio;
 			}
-		}
+
+			status = readl(base + MMCISTATUS);
+		} while (status & MCI_RXDATAAVLBL);
+
+		bio_kunmap_irq(buffer, &flags);
+		break;
+
+	 next_bio:
+		bio_kunmap_irq(buffer, &flags);
+
+		/*
+		 * Ok, we've completed that BIO, move on to next
+		 * BIO in the chain.  Note: this doesn't actually
+		 * complete the BIO!
+		 */
+		if (!process_that_request_first(req, req->current_nr_sectors))
+			break;
+
+		host->offset = 0;
+		status = readl(base + MMCISTATUS);
+	} while (1);
+
+	/*
+	 * If we're nearing the end of the read, switch to
+	 * "any data available" mode.
+	 */
+	if (host->size < MCI_FIFOSIZE)
+		writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
+
+	return ret;
+}
+
+static int mmci_pio_write(struct mmci_host *host, struct request *req, u32 status)
+{
+	void *base = host->base;
+	int ret = 0;
+
+	do {
+		unsigned long flags;
+		unsigned int bio_remain;
+		char *buffer;
 
 		/*
 		 * We only need to test the half-empty flag here - if
 		 * the FIFO is completely empty, then by definition
 		 * it is more than half empty.
 		 */
-		if (status & MCI_TXFIFOHALFEMPTY) {
-			unsigned int maxcnt = status & MCI_TXFIFOEMPTY ?
-					      MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
-			unsigned int count = min(host->size, maxcnt);
+		if (!(status & MCI_TXFIFOHALFEMPTY))
+			break;
+
+		/*
+		 * Map the BIO buffer.
+		 */
+		buffer = bio_kmap_irq(req->cbio, &flags);
+		bio_remain = (req->current_nr_sectors << 9) - host->offset;
+
+		do {
+			unsigned int count, maxcnt;
 
-			writesl(base + MMCIFIFO, host->buffer, count >> 2);
+			maxcnt = status & MCI_TXFIFOEMPTY ?
+				 MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
+			count = min(bio_remain, maxcnt);
 
-			host->buffer += count;
+			writesl(base + MMCIFIFO, buffer + host->offset, count >> 2);
+			host->offset += count;
 			host->size -= count;
+			bio_remain -= count;
 
-			/*
-			 * If we run out of data, disable the data IRQs;
-			 * this prevents a race where the FIFO becomes
-			 * empty before the chip itself has disabled the
-			 * data path.
-			 */
-			if (host->size == 0)
-				writel(0, base + MMCIMASK1);
-		}
+			ret = 1;
 
-		ret = 1;
-	} while (status);
+			if (bio_remain == 0)
+				goto next_bio;
+
+			status = readl(base + MMCISTATUS);
+		} while (status & MCI_TXFIFOHALFEMPTY);
+
+		bio_kunmap_irq(buffer, &flags);
+		break;
+
+	 next_bio:
+		bio_kunmap_irq(buffer, &flags);
+
+		/*
+		 * Ok, we've completed that BIO, move on to next
+		 * BIO in the chain.  Note: this doesn't actually
+		 * complete the BIO!
+		 */
+		if (!process_that_request_first(req, req->current_nr_sectors))
+			break;
+
+		host->offset = 0;
+		status = readl(base + MMCISTATUS);
+	} while (1);
+
+	return ret;
+}
+
+/*
+ * PIO data transfer IRQ handler.
+ */
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct mmci_host *host = dev_id;
+	struct request *req;
+	void *base = host->base;
+	u32 status;
+	int ret = 0;
+
+	status = readl(base + MMCISTATUS);
+
+	DBG(host, "irq1 %08x\n", status);
+
+	req = host->data->req;
+	if (status & MCI_RXACTIVE)
+		ret = mmci_pio_read(host, req, status);
+	else if (status & MCI_TXACTIVE)
+		ret = mmci_pio_write(host, req, status);
+
+	/*
+	 * If we run out of data, disable the data IRQs; this
+	 * prevents a race where the FIFO becomes empty before
+	 * the chip itself has disabled the data path, and
+	 * stops us racing with our data end IRQ.
+	 */
+	if (host->size == 0) {
+		writel(0, base + MMCIMASK1);
+		writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
+	}
 
 	return IRQ_RETVAL(ret);
 }
@@ -268,11 +375,9 @@
 		struct mmc_data *data;
 
 		status = readl(host->base + MMCISTATUS);
+		status &= readl(host->base + MMCIMASK0);
 		writel(status, host->base + MMCICLEAR);
 
-		if (!(status & MCI_IRQMASK))
-			break;
-
 		DBG(host, "irq0 %08x\n", status);
 
 		data = host->data;
@@ -426,6 +531,25 @@
 	mmc->f_min = (host->mclk + 511) / 512;
 	mmc->f_max = min(host->mclk, fmax);
 	mmc->ocr_avail = plat->ocr_mask;
+
+	/*
+	 * We can do SGIO
+	 */
+	mmc->max_hw_segs = 16;
+	mmc->max_phys_segs = 16;
+
+	/*
+	 * Since we only have a 16-bit data length register, we must
+	 * ensure that we don't exceed 2^16-1 bytes in a single request.
+	 * Choose 64 (512-byte) sectors as the limit.
+	 */
+	mmc->max_sectors = 64;
+
+	/*
+	 * Set the maximum segment size.  Since we aren't doing DMA
+	 * (yet) we are only limited by the data length register.
+	 */
+	mmc->max_seg_size = mmc->max_sectors << 9;
 
 	spin_lock_init(&host->lock);
 
diff -Nru a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h
--- a/drivers/mmc/mmci.h	2004-09-06 17:13:54 -07:00
+++ b/drivers/mmc/mmci.h	2004-09-06 17:13:54 -07:00
@@ -103,18 +103,15 @@
 #define MMCIFIFOCNT		0x048
 #define MMCIFIFO		0x080 /* to 0x0bc */
 
-#define MCI_IRQMASK	\
-	(MCI_CMDCRCFAIL|MCI_DATACRCFAIL|MCI_CMDTIMEOUT|MCI_DATATIMEOUT|	\
-	MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_CMDRESPEND|MCI_CMDSENT|	\
-	MCI_DATAEND|MCI_DATABLOCKEND)
-
 #define MCI_IRQENABLE	\
 	(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|	\
 	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\
-	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|		\
-	MCI_DATABLOCKENDMASK)
+	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
 
-#define MCI_FIFOSIZE	16
+/*
+ * The size of the FIFO in bytes.
+ */
+#define MCI_FIFOSIZE	(16*4)
 	
 #define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
 
@@ -141,8 +138,6 @@
 	unsigned int		oldstat;
 
 	/* pio stuff */
-	void			*buffer;
+	unsigned int		offset;
 	unsigned int		size;
 };
-
-#define to_mmci_host(mmc)	container_of(mmc, struct mmci_host, mmc)
diff -Nru a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
--- a/drivers/mmc/pxamci.c	2004-09-06 17:13:54 -07:00
+++ b/drivers/mmc/pxamci.c	2004-09-06 17:13:54 -07:00
@@ -530,6 +530,7 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
 static int pxamci_suspend(struct device *dev, u32 state, u32 level)
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -551,6 +552,10 @@
 
 	return ret;
 }
+#else
+#define pxamci_suspend	NULL
+#define pxamci_resume	NULL
+#endif
 
 static struct device_driver pxamci_driver = {
 	.name		= "pxa2xx-mci",
diff -Nru a/include/linux/mmc/host.h b/include/linux/mmc/host.h
--- a/include/linux/mmc/host.h	2004-09-06 17:13:54 -07:00
+++ b/include/linux/mmc/host.h	2004-09-06 17:13:54 -07:00
@@ -64,11 +64,17 @@
 struct mmc_host {
 	struct device		*dev;
 	struct mmc_host_ops	*ops;
-	void			*priv;
 	unsigned int		f_min;
 	unsigned int		f_max;
 	u32			ocr_avail;
 	char			host_name[8];
+
+	/* host specific block data */
+	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
+	unsigned short		max_hw_segs;	/* see blk_queue_max_hw_segments */
+	unsigned short		max_phys_segs;	/* see blk_queue_max_phys_segments */
+	unsigned short		max_sectors;	/* see blk_queue_max_sectors */
+	unsigned short		unused;
 
 	/* private data */
 	struct mmc_ios		ios;		/* current io bus settings */
diff -Nru a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
--- a/include/linux/mmc/mmc.h	2004-09-06 17:13:54 -07:00
+++ b/include/linux/mmc/mmc.h	2004-09-06 17:13:54 -07:00
@@ -28,6 +28,16 @@
 #define MMC_RSP_CRC	(1 << 3)		/* expect valid crc */
 #define MMC_RSP_BUSY	(1 << 4)		/* card may send busy */
 
+/*
+ * These are the response types, and correspond to valid bit
+ * patterns of the above flags.  One additional valid pattern
+ * is all zeros, which means we don't expect a response.
+ */
+#define MMC_RSP_R1	(MMC_RSP_SHORT|MMC_RSP_CRC)
+#define MMC_RSP_R1B	(MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_BUSY)
+#define MMC_RSP_R2	(MMC_RSP_LONG|MMC_RSP_CRC)
+#define MMC_RSP_R3	(MMC_RSP_SHORT)
+
 	unsigned int		retries;	/* max number of retries */
 	unsigned int		error;		/* command error */