summaryrefslogtreecommitdiff
path: root/drivers/mmc/card
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/card')
-rw-r--r--drivers/mmc/card/Kconfig26
-rw-r--r--drivers/mmc/card/block.c105
-rw-r--r--drivers/mmc/card/mmc_test.c12
-rw-r--r--drivers/mmc/card/queue.c8
4 files changed, 98 insertions, 53 deletions
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index 3f2a912659a..cc9d7e77c25 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -14,6 +14,23 @@ config MMC_BLOCK
mount the filesystem. Almost everyone wishing MMC support
should say Y or M here.
+config MMC_BLOCK_MINORS
+ int "Number of minors per block device"
+ range 4 256
+ default 8
+ help
+ Number of minors per block device. One is needed for every
+ partition on the disk (plus one for the whole disk).
+
+ Number of total MMC minors available is 256, so your number
+ of supported block devices will be limited to 256 divided
+ by this number.
+
+ Default is 8 to be backwards compatible with previous
+ hardwired device numbering.
+
+ If unsure, say 8 here.
+
config MMC_BLOCK_BOUNCE
bool "Use bounce buffer for simple hosts"
depends on MMC_BLOCK
@@ -32,6 +49,15 @@ config MMC_BLOCK_BOUNCE
If unsure, say Y here.
+config MMC_BLOCK_DEFERRED_RESUME
+ bool "Deferr MMC layer resume until I/O is requested"
+ depends on MMC_BLOCK
+ default n
+ help
+ Say Y here to enable deferred MMC resume until I/O
+ is requested. This will reduce overall resume latency and
+ save power when theres an SD card inserted but not being used.
+
config SDIO_UART
tristate "SDIO UART/GPS class support"
help
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index cb9fbc83b09..ed17a3d1499 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -43,14 +43,27 @@
#include "queue.h"
MODULE_ALIAS("mmc:block");
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "mmcblk."
+
+static DEFINE_MUTEX(block_mutex);
/*
- * max 8 partitions per card
+ * The defaults come from config options but can be overriden by module
+ * or bootarg options.
*/
-#define MMC_SHIFT 3
-#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
+static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
-static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
+/*
+ * We've only got one major, so number of mmcblk devices is
+ * limited to 256 / number of minors per device.
+ */
+static int max_devices;
+
+/* 256 minors, so at most 256 separate devices */
+static DECLARE_BITMAP(dev_use, 256);
/*
* There is one mmc_blk_data per slot.
@@ -66,6 +79,9 @@ struct mmc_blk_data {
static DEFINE_MUTEX(open_lock);
+module_param(perdev_minors, int, 0444);
+MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@@ -87,10 +103,10 @@ static void mmc_blk_put(struct mmc_blk_data *md)
md->usage--;
if (md->usage == 0) {
int devmaj = MAJOR(disk_devt(md->disk));
- int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
+ int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
if (!devmaj)
- devidx = md->disk->first_minor >> MMC_SHIFT;
+ devidx = md->disk->first_minor / perdev_minors;
blk_cleanup_queue(md->queue.queue);
@@ -242,6 +258,24 @@ static u32 get_card_status(struct mmc_card *card, struct request *req)
return cmd.resp[0];
}
+static int
+mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
+{
+ int err;
+
+ mmc_claim_host(card->host);
+ err = mmc_set_blocklen(card, 512);
+ mmc_release_host(card->host);
+
+ if (err) {
+ printk(KERN_ERR "%s: unable to set block size to 512: %d\n",
+ md->disk->disk_name, err);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
@@ -249,6 +283,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
struct mmc_blk_request brq;
int ret = 1, disable_multi = 0;
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ if (mmc_bus_needs_resume(card->host)) {
+ mmc_resume_bus(card->host);
+ mmc_blk_set_blksize(md, card);
+ }
+#endif
+
mmc_claim_host(card->host);
do {
@@ -299,7 +340,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
readcmd = MMC_READ_SINGLE_BLOCK;
writecmd = MMC_WRITE_BLOCK;
}
-
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = readcmd;
brq.data.flags |= MMC_DATA_READ;
@@ -352,6 +392,8 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
continue;
}
status = get_card_status(card, req);
+ } else if (disable_multi == 1) {
+ disable_multi = 0;
}
if (brq.cmd.error) {
@@ -482,8 +524,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
struct mmc_blk_data *md;
int devidx, ret;
- devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
- if (devidx >= MMC_NUM_MINORS)
+ devidx = find_first_zero_bit(dev_use, max_devices);
+ if (devidx >= max_devices)
return ERR_PTR(-ENOSPC);
__set_bit(devidx, dev_use);
@@ -500,7 +542,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
*/
md->read_only = mmc_blk_readonly(card);
- md->disk = alloc_disk(1 << MMC_SHIFT);
+ md->disk = alloc_disk(perdev_minors);
if (md->disk == NULL) {
ret = -ENOMEM;
goto err_kfree;
@@ -517,11 +559,12 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
md->queue.data = md;
md->disk->major = MMC_BLOCK_MAJOR;
- md->disk->first_minor = devidx << MMC_SHIFT;
+ md->disk->first_minor = devidx * perdev_minors;
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = &card->dev;
+ md->disk->flags = GENHD_FL_EXT_DEVT;
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:
@@ -563,37 +606,10 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
return ERR_PTR(ret);
}
-static int
-mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
-{
- struct mmc_command cmd;
- int err;
-
- /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
- if (mmc_card_blockaddr(card))
- return 0;
-
- mmc_claim_host(card->host);
- cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = 512;
- cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 5);
- mmc_release_host(card->host);
-
- if (err) {
- printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
- md->disk->disk_name, cmd.arg, err);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md;
int err;
-
char cap_str[10];
/*
@@ -617,6 +633,9 @@ static int mmc_blk_probe(struct mmc_card *card)
cap_str, md->read_only ? "(ro)" : "");
mmc_set_drvdata(card, md);
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ mmc_set_bus_resume_policy(card->host, 1);
+#endif
add_disk(md->disk);
return 0;
@@ -641,6 +660,9 @@ static void mmc_blk_remove(struct mmc_card *card)
mmc_blk_put(md);
}
mmc_set_drvdata(card, NULL);
+#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
+ mmc_set_bus_resume_policy(card->host, 0);
+#endif
}
#ifdef CONFIG_PM
@@ -659,7 +681,9 @@ static int mmc_blk_resume(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
+#ifndef CONFIG_MMC_BLOCK_DEFERRED_RESUME
mmc_blk_set_blksize(md, card);
+#endif
mmc_queue_resume(&md->queue);
}
return 0;
@@ -683,6 +707,11 @@ static int __init mmc_blk_init(void)
{
int res;
+ if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
+ pr_info("mmcblk: using %d minors per device\n", perdev_minors);
+
+ max_devices = 256 / perdev_minors;
+
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
if (res)
goto out;
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 445d7db2277..785b4822a0a 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -44,17 +44,7 @@ struct mmc_test_card {
*/
static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
{
- struct mmc_command cmd;
- int ret;
-
- cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = size;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
- if (ret)
- return ret;
-
- return 0;
+ return mmc_set_blocklen(test->card, size);
}
/*
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index d6ded247d94..bd7da55cce4 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -132,7 +132,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
#ifdef CONFIG_MMC_BLOCK_BOUNCE
- if (host->max_hw_segs == 1) {
+ if (host->max_segs == 1) {
unsigned int bouncesz;
bouncesz = MMC_QUEUE_BOUNCESZ;
@@ -182,16 +182,16 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_bounce_limit(mq->queue, limit);
blk_queue_max_hw_sectors(mq->queue,
min(host->max_blk_count, host->max_req_size / 512));
- blk_queue_max_segments(mq->queue, host->max_hw_segs);
+ blk_queue_max_segments(mq->queue, host->max_segs);
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
mq->sg = kmalloc(sizeof(struct scatterlist) *
- host->max_phys_segs, GFP_KERNEL);
+ host->max_segs, GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
goto cleanup_queue;
}
- sg_init_table(mq->sg, host->max_phys_segs);
+ sg_init_table(mq->sg, host->max_segs);
}
init_MUTEX(&mq->thread_sem);