diff options
-rw-r--r-- | drivers/mmc/mmc.c | 10 | ||||
-rw-r--r-- | drivers/mmc/mmc_block.c | 175 | ||||
-rw-r--r-- | drivers/mmc/mmci.c | 17 | ||||
-rw-r--r-- | drivers/mmc/mmci.h | 4 | ||||
-rw-r--r-- | drivers/mmc/wbsd.c | 27 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 5 |
6 files changed, 163 insertions, 75 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index eb41391e06e9..6696f71363b9 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c | |||
@@ -550,6 +550,11 @@ static void mmc_decode_csd(struct mmc_card *card) | |||
550 | csd->capacity = (1 + m) << (e + 2); | 550 | csd->capacity = (1 + m) << (e + 2); |
551 | 551 | ||
552 | csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); | 552 | csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); |
553 | csd->read_partial = UNSTUFF_BITS(resp, 79, 1); | ||
554 | csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); | ||
555 | csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); | ||
556 | csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); | ||
557 | csd->write_partial = UNSTUFF_BITS(resp, 21, 1); | ||
553 | } else { | 558 | } else { |
554 | /* | 559 | /* |
555 | * We only understand CSD structure v1.1 and v1.2. | 560 | * We only understand CSD structure v1.1 and v1.2. |
@@ -579,6 +584,11 @@ static void mmc_decode_csd(struct mmc_card *card) | |||
579 | csd->capacity = (1 + m) << (e + 2); | 584 | csd->capacity = (1 + m) << (e + 2); |
580 | 585 | ||
581 | csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); | 586 | csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4); |
587 | csd->read_partial = UNSTUFF_BITS(resp, 79, 1); | ||
588 | csd->write_misalign = UNSTUFF_BITS(resp, 78, 1); | ||
589 | csd->read_misalign = UNSTUFF_BITS(resp, 77, 1); | ||
590 | csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4); | ||
591 | csd->write_partial = UNSTUFF_BITS(resp, 21, 1); | ||
582 | } | 592 | } |
583 | } | 593 | } |
584 | 594 | ||
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 8e380c14bf65..198561d21710 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 | ||
59 | static DECLARE_MUTEX(open_lock); | 60 | static 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 | ||
88 | static 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 | |||
94 | static int mmc_blk_open(struct inode *inode, struct file *filp) | 89 | static 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 | ||
300 | static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; | 294 | static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; |
301 | 295 | ||
296 | static 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 | |||
302 | static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) | 302 | static 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 | ||
373 | static int | 430 | static 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); |
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 166c9b0ad04e..2b10a2d4ae09 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/mmc/host.h> | 20 | #include <linux/mmc/host.h> |
21 | #include <linux/mmc/protocol.h> | 21 | #include <linux/mmc/protocol.h> |
22 | 22 | ||
23 | #include <asm/cacheflush.h> | ||
23 | #include <asm/div64.h> | 24 | #include <asm/div64.h> |
24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
25 | #include <asm/scatterlist.h> | 26 | #include <asm/scatterlist.h> |
@@ -157,6 +158,13 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, | |||
157 | else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) | 158 | else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN)) |
158 | data->error = MMC_ERR_FIFO; | 159 | data->error = MMC_ERR_FIFO; |
159 | status |= MCI_DATAEND; | 160 | status |= MCI_DATAEND; |
161 | |||
162 | /* | ||
163 | * We hit an error condition. Ensure that any data | ||
164 | * partially written to a page is properly coherent. | ||
165 | */ | ||
166 | if (host->sg_len && data->flags & MMC_DATA_READ) | ||
167 | flush_dcache_page(host->sg_ptr->page); | ||
160 | } | 168 | } |
161 | if (status & MCI_DATAEND) { | 169 | if (status & MCI_DATAEND) { |
162 | mmci_stop_data(host); | 170 | mmci_stop_data(host); |
@@ -292,7 +300,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) | |||
292 | /* | 300 | /* |
293 | * Unmap the buffer. | 301 | * Unmap the buffer. |
294 | */ | 302 | */ |
295 | mmci_kunmap_atomic(host, &flags); | 303 | mmci_kunmap_atomic(host, buffer, &flags); |
296 | 304 | ||
297 | host->sg_off += len; | 305 | host->sg_off += len; |
298 | host->size -= len; | 306 | host->size -= len; |
@@ -301,6 +309,13 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs) | |||
301 | if (remain) | 309 | if (remain) |
302 | break; | 310 | break; |
303 | 311 | ||
312 | /* | ||
313 | * If we were reading, and we have completed this | ||
314 | * page, ensure that the data cache is coherent. | ||
315 | */ | ||
316 | if (status & MCI_RXACTIVE) | ||
317 | flush_dcache_page(host->sg_ptr->page); | ||
318 | |||
304 | if (!mmci_next_sg(host)) | 319 | if (!mmci_next_sg(host)) |
305 | break; | 320 | break; |
306 | 321 | ||
diff --git a/drivers/mmc/mmci.h b/drivers/mmc/mmci.h index 4589bbd68192..6d7eadc9a678 100644 --- a/drivers/mmc/mmci.h +++ b/drivers/mmc/mmci.h | |||
@@ -172,8 +172,8 @@ static inline char *mmci_kmap_atomic(struct mmci_host *host, unsigned long *flag | |||
172 | return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; | 172 | return kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; |
173 | } | 173 | } |
174 | 174 | ||
175 | static inline void mmci_kunmap_atomic(struct mmci_host *host, unsigned long *flags) | 175 | static inline void mmci_kunmap_atomic(struct mmci_host *host, void *buffer, unsigned long *flags) |
176 | { | 176 | { |
177 | kunmap_atomic(host->sg_ptr->page, KM_BIO_SRC_IRQ); | 177 | kunmap_atomic(buffer, KM_BIO_SRC_IRQ); |
178 | local_irq_restore(*flags); | 178 | local_irq_restore(*flags); |
179 | } | 179 | } |
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index c7eb7c269081..4f13bd2ccf9a 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c | |||
@@ -1456,13 +1456,11 @@ static int __devinit wbsd_scan(struct wbsd_host* host) | |||
1456 | * Iterate through all ports, all codes to | 1456 | * Iterate through all ports, all codes to |
1457 | * find hardware that is in our known list. | 1457 | * find hardware that is in our known list. |
1458 | */ | 1458 | */ |
1459 | for (i = 0;i < sizeof(config_ports)/sizeof(int);i++) | 1459 | for (i = 0; i < ARRAY_SIZE(config_ports); i++) { |
1460 | { | ||
1461 | if (!request_region(config_ports[i], 2, DRIVER_NAME)) | 1460 | if (!request_region(config_ports[i], 2, DRIVER_NAME)) |
1462 | continue; | 1461 | continue; |
1463 | 1462 | ||
1464 | for (j = 0;j < sizeof(unlock_codes)/sizeof(int);j++) | 1463 | for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) { |
1465 | { | ||
1466 | id = 0xFFFF; | 1464 | id = 0xFFFF; |
1467 | 1465 | ||
1468 | host->config = config_ports[i]; | 1466 | host->config = config_ports[i]; |
@@ -1478,8 +1476,7 @@ static int __devinit wbsd_scan(struct wbsd_host* host) | |||
1478 | 1476 | ||
1479 | wbsd_lock_config(host); | 1477 | wbsd_lock_config(host); |
1480 | 1478 | ||
1481 | for (k = 0;k < sizeof(valid_ids)/sizeof(int);k++) | 1479 | for (k = 0; k < ARRAY_SIZE(valid_ids); k++) { |
1482 | { | ||
1483 | if (id == valid_ids[k]) | 1480 | if (id == valid_ids[k]) |
1484 | { | 1481 | { |
1485 | host->chip_id = id; | 1482 | host->chip_id = id; |
@@ -2090,10 +2087,20 @@ static int __init wbsd_drv_init(void) | |||
2090 | if (result < 0) | 2087 | if (result < 0) |
2091 | return result; | 2088 | return result; |
2092 | 2089 | ||
2093 | wbsd_device = platform_device_register_simple(DRIVER_NAME, -1, | 2090 | wbsd_device = platform_device_alloc(DRIVER_NAME, -1); |
2094 | NULL, 0); | 2091 | if (!wbsd_device) |
2095 | if (IS_ERR(wbsd_device)) | 2092 | { |
2096 | return PTR_ERR(wbsd_device); | 2093 | platform_driver_unregister(&wbsd_driver); |
2094 | return -ENOMEM; | ||
2095 | } | ||
2096 | |||
2097 | result = platform_device_add(wbsd_device); | ||
2098 | if (result) | ||
2099 | { | ||
2100 | platform_device_put(wbsd_device); | ||
2101 | platform_driver_unregister(&wbsd_driver); | ||
2102 | return result; | ||
2103 | } | ||
2097 | } | 2104 | } |
2098 | 2105 | ||
2099 | return 0; | 2106 | return 0; |
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 18fc77f682de..30dd978c1ec8 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
@@ -30,7 +30,12 @@ struct mmc_csd { | |||
30 | unsigned int tacc_ns; | 30 | unsigned int tacc_ns; |
31 | unsigned int max_dtr; | 31 | unsigned int max_dtr; |
32 | unsigned int read_blkbits; | 32 | unsigned int read_blkbits; |
33 | unsigned int write_blkbits; | ||
33 | unsigned int capacity; | 34 | unsigned int capacity; |
35 | unsigned int read_partial:1, | ||
36 | read_misalign:1, | ||
37 | write_partial:1, | ||
38 | write_misalign:1; | ||
34 | }; | 39 | }; |
35 | 40 | ||
36 | struct sd_scr { | 41 | struct sd_scr { |