summaryrefslogtreecommitdiffstats
path: root/drivers/mmc/wbsd.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@insightbb.com>2007-02-10 01:26:32 -0500
committerDmitry Torokhov <dtor@insightbb.com>2007-02-10 01:26:32 -0500
commitb22364c8eec89e6b0c081a237f3b6348df87796f (patch)
tree233a923281fb640106465d076997ff511efb6edf /drivers/mmc/wbsd.c
parent2c8dc071517ec2843869024dc82be2e246f41064 (diff)
parent66efc5a7e3061c3597ac43a8bb1026488d57e66b (diff)
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/mmc/wbsd.c')
-rw-r--r--drivers/mmc/wbsd.c102
1 files changed, 66 insertions, 36 deletions
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 7a282672f8e..a44d8777ab9 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
*
- * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2004-2006 Pierre Ossman, 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 as published by
@@ -272,16 +272,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
return host->num_sg;
}
-static inline char *wbsd_kmap_sg(struct wbsd_host *host)
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
{
- host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
- host->cur_sg->offset;
- return host->mapped_sg;
-}
-
-static inline void wbsd_kunmap_sg(struct wbsd_host *host)
-{
- kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+ return page_address(host->cur_sg->page) + host->cur_sg->offset;
}
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -302,12 +295,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(dmabuf, sgbuf, size);
else
memcpy(dmabuf, sgbuf, sg[i].length);
- kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
dmabuf += sg[i].length;
if (size < sg[i].length)
@@ -347,7 +339,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
* we do not transfer too much.
*/
for (i = 0; i < len; i++) {
- sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+ sgbuf = page_address(sg[i].page) + sg[i].offset;
if (size < sg[i].length)
memcpy(sgbuf, dmabuf, size);
else
@@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Drain the fifo. This has a tendency to loop longer
@@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* This is a very dirty hack to solve a
* hardware problem. The chip doesn't trigger
@@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
if (data->bytes_xfered == host->size)
return;
- buffer = wbsd_kmap_sg(host) + host->offset;
+ buffer = wbsd_sg_to_buffer(host) + host->offset;
/*
* Fill the fifo. This has a tendency to loop longer
@@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
/*
* Transfer done?
*/
- if (data->bytes_xfered == host->size) {
- wbsd_kunmap_sg(host);
+ if (data->bytes_xfered == host->size)
return;
- }
/*
* End of scatter list entry?
*/
if (host->remain == 0) {
- wbsd_kunmap_sg(host);
-
/*
* Get next entry. Check if last.
*/
@@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
return;
}
- buffer = wbsd_kmap_sg(host);
+ buffer = wbsd_sg_to_buffer(host);
}
}
}
- wbsd_kunmap_sg(host);
-
/*
* The controller stops sending interrupts for
* 'FIFO empty' under certain conditions. So we
@@ -910,6 +890,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
*/
if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
+ * The hardware is so delightfully stupid that it has a list
+ * of "data" commands. If a command isn't on this list, it'll
+ * just go back to the idle state and won't send any data
+ * interrupts.
+ */
+ switch (cmd->opcode) {
+ case 11:
+ case 17:
+ case 18:
+ case 20:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 30:
+ case 42:
+ case 56:
+ break;
+
+ /* ACMDs. We don't keep track of state, so we just treat them
+ * like any other command. */
+ case 51:
+ break;
+
+ default:
+#ifdef CONFIG_MMC_DEBUG
+ printk(KERN_WARNING "%s: Data command %d is not "
+ "supported by this controller.\n",
+ mmc_hostname(host->mmc), cmd->opcode);
+#endif
+ cmd->data->error = MMC_ERR_INVALID;
+
+ if (cmd->data->stop)
+ wbsd_send_command(host, cmd->data->stop);
+
+ goto done;
+ };
+
+ /*
* Dirty fix for hardware bug.
*/
if (host->dma == -1)
@@ -1343,16 +1362,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->max_phys_segs = 128;
/*
- * Maximum number of sectors in one transfer. Also limited by 64kB
- * buffer.
+ * Maximum request size. Also limited by 64KiB buffer.
*/
- mmc->max_sectors = 128;
+ mmc->max_req_size = 65536;
/*
* Maximum segment size. Could be one segment with the maximum number
- * of segments.
+ * of bytes.
+ */
+ mmc->max_seg_size = mmc->max_req_size;
+
+ /*
+ * Maximum block size. We have 12 bits (= 4095) but have to subtract
+ * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+ */
+ mmc->max_blk_size = 4087;
+
+ /*
+ * Maximum block count. There is no real limit so the maximum
+ * request size will be the only restriction.
*/
- mmc->max_seg_size = mmc->max_sectors * 512;
+ mmc->max_blk_count = mmc->max_req_size;
dev_set_drvdata(dev, mmc);