aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/mmc_block.c
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-01-03 17:38:44 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-01-03 17:38:44 -0500
commita6f6c96b65d7f65a7a7bf5cbe874eda182a6b2cc (patch)
tree5f3bd4dc24866f2b0e593b1457b1f22ec641139b /drivers/mmc/mmc_block.c
parent88026842b0a760145aa71d69e74fbc9ec118ca44 (diff)
[MMC] Improve MMC card block size selection
Select a block size for IO based on the read and write block size combinations, and whether the card supports partial block reads and/or partial block writes. If we are able to satisfy block reads but not block writes, mark the device read only. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc/mmc_block.c')
-rw-r--r--drivers/mmc/mmc_block.c175
1 files changed, 113 insertions, 62 deletions
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index abcf19116d70..b9837cc5b9ac 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -54,6 +54,7 @@ struct mmc_blk_data {
54 54
55 unsigned int usage; 55 unsigned int usage;
56 unsigned int block_bits; 56 unsigned int block_bits;
57 unsigned int read_only;
57}; 58};
58 59
59static DECLARE_MUTEX(open_lock); 60static DECLARE_MUTEX(open_lock);
@@ -85,12 +86,6 @@ static void mmc_blk_put(struct mmc_blk_data *md)
85 up(&open_lock); 86 up(&open_lock);
86} 87}
87 88
88static inline int mmc_blk_readonly(struct mmc_card *card)
89{
90 return mmc_card_readonly(card) ||
91 !(card->csd.cmdclass & CCC_BLOCK_WRITE);
92}
93
94static int mmc_blk_open(struct inode *inode, struct file *filp) 89static int mmc_blk_open(struct inode *inode, struct file *filp)
95{ 90{
96 struct mmc_blk_data *md; 91 struct mmc_blk_data *md;
@@ -102,8 +97,7 @@ static int mmc_blk_open(struct inode *inode, struct file *filp)
102 check_disk_change(inode->i_bdev); 97 check_disk_change(inode->i_bdev);
103 ret = 0; 98 ret = 0;
104 99
105 if ((filp->f_mode & FMODE_WRITE) && 100 if ((filp->f_mode & FMODE_WRITE) && md->read_only)
106 mmc_blk_readonly(md->queue.card))
107 ret = -EROFS; 101 ret = -EROFS;
108 } 102 }
109 103
@@ -299,6 +293,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
299 293
300static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; 294static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
301 295
296static inline int mmc_blk_readonly(struct mmc_card *card)
297{
298 return mmc_card_readonly(card) ||
299 !(card->csd.cmdclass & CCC_BLOCK_WRITE);
300}
301
302static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) 302static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
303{ 303{
304 struct mmc_blk_data *md; 304 struct mmc_blk_data *md;
@@ -310,64 +310,121 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
310 __set_bit(devidx, dev_use); 310 __set_bit(devidx, dev_use);
311 311
312 md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); 312 md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
313 if (md) { 313 if (!md) {
314 memset(md, 0, sizeof(struct mmc_blk_data)); 314 ret = -ENOMEM;
315 goto out;
316 }
315 317
316 md->disk = alloc_disk(1 << MMC_SHIFT); 318 memset(md, 0, sizeof(struct mmc_blk_data));
317 if (md->disk == NULL) {
318 kfree(md);
319 md = ERR_PTR(-ENOMEM);
320 goto out;
321 }
322 319
323 spin_lock_init(&md->lock); 320 /*
324 md->usage = 1; 321 * Set the read-only status based on the supported commands
322 * and the write protect switch.
323 */
324 md->read_only = mmc_blk_readonly(card);
325 325
326 ret = mmc_init_queue(&md->queue, card, &md->lock); 326 /*
327 if (ret) { 327 * Figure out a workable block size. MMC cards have:
328 put_disk(md->disk); 328 * - two block sizes, one for read and one for write.
329 kfree(md); 329 * - may support partial reads and/or writes
330 md = ERR_PTR(ret); 330 * (allows block sizes smaller than specified)
331 goto out; 331 */
332 md->block_bits = card->csd.read_blkbits;
333 if (card->csd.write_blkbits != card->csd.read_blkbits) {
334 if (card->csd.write_blkbits < card->csd.read_blkbits &&
335 card->csd.read_partial) {
336 /*
337 * write block size is smaller than read block
338 * size, but we support partial reads, so choose
339 * the smaller write block size.
340 */
341 md->block_bits = card->csd.write_blkbits;
342 } else if (card->csd.write_blkbits > card->csd.read_blkbits &&
343 card->csd.write_partial) {
344 /*
345 * read block size is smaller than write block
346 * size, but we support partial writes. Use read
347 * block size.
348 */
349 } else {
350 /*
351 * We don't support this configuration for writes.
352 */
353 printk(KERN_ERR "%s: unable to select block size for "
354 "writing (rb%u wb%u rp%u wp%u)\n",
355 md->disk->disk_name,
356 1 << card->csd.read_blkbits,
357 1 << card->csd.write_blkbits,
358 card->csd.read_partial,
359 card->csd.write_partial);
360 md->read_only = 1;
332 } 361 }
333 md->queue.prep_fn = mmc_blk_prep_rq; 362 }
334 md->queue.issue_fn = mmc_blk_issue_rq;
335 md->queue.data = md;
336 363
337 md->disk->major = major; 364 /*
338 md->disk->first_minor = devidx << MMC_SHIFT; 365 * Refuse to allow block sizes smaller than 512 bytes.
339 md->disk->fops = &mmc_bdops; 366 */
340 md->disk->private_data = md; 367 if (md->block_bits < 9) {
341 md->disk->queue = md->queue.queue; 368 printk(KERN_ERR "%s: unable to support block size %u\n",
342 md->disk->driverfs_dev = &card->dev; 369 mmc_card_id(card), 1 << md->block_bits);
370 ret = -EINVAL;
371 goto err_kfree;
372 }
343 373
344 /* 374 md->disk = alloc_disk(1 << MMC_SHIFT);
345 * As discussed on lkml, GENHD_FL_REMOVABLE should: 375 if (md->disk == NULL) {
346 * 376 ret = -ENOMEM;
347 * - be set for removable media with permanent block devices 377 goto err_kfree;
348 * - be unset for removable block devices with permanent media 378 }
349 *
350 * Since MMC block devices clearly fall under the second
351 * case, we do not set GENHD_FL_REMOVABLE. Userspace
352 * should use the block device creation/destruction hotplug
353 * messages to tell when the card is present.
354 */
355 379
356 sprintf(md->disk->disk_name, "mmcblk%d", devidx); 380 spin_lock_init(&md->lock);
357 sprintf(md->disk->devfs_name, "mmc/blk%d", devidx); 381 md->usage = 1;
358 382
359 md->block_bits = card->csd.read_blkbits; 383 ret = mmc_init_queue(&md->queue, card, &md->lock);
384 if (ret)
385 goto err_putdisk;
360 386
361 blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); 387 md->queue.prep_fn = mmc_blk_prep_rq;
388 md->queue.issue_fn = mmc_blk_issue_rq;
389 md->queue.data = md;
362 390
363 /* 391 md->disk->major = major;
364 * The CSD capacity field is in units of read_blkbits. 392 md->disk->first_minor = devidx << MMC_SHIFT;
365 * set_capacity takes units of 512 bytes. 393 md->disk->fops = &mmc_bdops;
366 */ 394 md->disk->private_data = md;
367 set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9)); 395 md->disk->queue = md->queue.queue;
368 } 396 md->disk->driverfs_dev = &card->dev;
369 out: 397
398 /*
399 * As discussed on lkml, GENHD_FL_REMOVABLE should:
400 *
401 * - be set for removable media with permanent block devices
402 * - be unset for removable block devices with permanent media
403 *
404 * Since MMC block devices clearly fall under the second
405 * case, we do not set GENHD_FL_REMOVABLE. Userspace
406 * should use the block device creation/destruction hotplug
407 * messages to tell when the card is present.
408 */
409
410 sprintf(md->disk->disk_name, "mmcblk%d", devidx);
411 sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
412
413 blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
414
415 /*
416 * The CSD capacity field is in units of read_blkbits.
417 * set_capacity takes units of 512 bytes.
418 */
419 set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
370 return md; 420 return md;
421
422 err_putdisk:
423 put_disk(md->disk);
424 err_kfree:
425 kfree(md);
426 out:
427 return ERR_PTR(ret);
371} 428}
372 429
373static int 430static int
@@ -403,12 +460,6 @@ static int mmc_blk_probe(struct mmc_card *card)
403 if (!(card->csd.cmdclass & CCC_BLOCK_READ)) 460 if (!(card->csd.cmdclass & CCC_BLOCK_READ))
404 return -ENODEV; 461 return -ENODEV;
405 462
406 if (card->csd.read_blkbits < 9) {
407 printk(KERN_WARNING "%s: read blocksize too small (%u)\n",
408 mmc_card_id(card), 1 << card->csd.read_blkbits);
409 return -ENODEV;
410 }
411
412 md = mmc_blk_alloc(card); 463 md = mmc_blk_alloc(card);
413 if (IS_ERR(md)) 464 if (IS_ERR(md))
414 return PTR_ERR(md); 465 return PTR_ERR(md);
@@ -419,7 +470,7 @@ static int mmc_blk_probe(struct mmc_card *card)
419 470
420 printk(KERN_INFO "%s: %s %s %luKiB %s\n", 471 printk(KERN_INFO "%s: %s %s %luKiB %s\n",
421 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), 472 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
422 get_capacity(md->disk) >> 1, mmc_blk_readonly(card)?"(ro)":""); 473 get_capacity(md->disk) >> 1, md->read_only ? "(ro)" : "");
423 474
424 mmc_set_drvdata(card, md); 475 mmc_set_drvdata(card, md);
425 add_disk(md->disk); 476 add_disk(md->disk);