diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-13 23:41:15 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-13 23:41:15 -0500 |
| commit | 4b8be38cf782f8ebebc089083fa0572ade79d7ca (patch) | |
| tree | 2f88a0a5c1c0be9121c31b5a2775ae2f979cfa66 /drivers/mmc/card | |
| parent | 5df1b274cd2f0304339c7f5586fa16cce0fdfce2 (diff) | |
| parent | 0db13fc2abbb0b1a8d8efee20dfbd7f3c5d54022 (diff) | |
Merge tag 'mmc-merge-for-3.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
MMC highlights for 3.3:
Core:
* Support for the HS200 high-speed eMMC mode.
* Support SDIO 3.0 Ultra High Speed cards.
* Kill pending block requests immediately if card is removed.
* Enable the eMMC feature for locking boot partitions read-only
until next power on, exposed via sysfs.
Drivers:
* Runtime PM support for Intel Medfield SDIO.
* Suspend/resume support for sdhci-spear.
* sh-mmcif now processes requests asynchronously.
* tag 'mmc-merge-for-3.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (58 commits)
mmc: fix a deadlock between system suspend and MMC block IO
mmc: sdhci: restore the enabled dma when do reset all
mmc: dw_mmc: miscaculated the fifo-depth with wrong bit operation
mmc: host: Adds support for eMMC 4.5 HS200 mode
mmc: core: HS200 mode support for eMMC 4.5
mmc: dw_mmc: fixed wrong bit operation for SDMMC_GET_FCNT()
mmc: core: Separate the timeout value for cache-ctrl
mmc: sdhci-spear: Fix compilation error
mmc: sdhci: Deal with failure case in sdhci_suspend_host
mmc: dw_mmc: Clear the DDR mode for non-DDR
mmc: sd: Fix SDR12 timing regression
mmc: sdhci: Fix tuning timer incorrect setting when suspending host
mmc: core: Add option to prevent eMMC sleep command
mmc: omap_hsmmc: use threaded irq handler for card-detect.
mmc: sdhci-pci: enable runtime PM for Medfield SDIO
mmc: sdhci: Always pass clock request value zero to set_clock host op
mmc: sdhci-pci: remove SDHCI_QUIRK2_OWN_CARD_DETECTION
mmc: sdhci-pci: get gpio numbers from platform data
mmc: sdhci-pci: add platform data
mmc: sdhci: prevent card detection activity for non-removable cards
...
Diffstat (limited to 'drivers/mmc/card')
| -rw-r--r-- | drivers/mmc/card/block.c | 247 | ||||
| -rw-r--r-- | drivers/mmc/card/mmc_test.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.c | 5 |
3 files changed, 198 insertions, 55 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 1e0e27cbe98..0cad48a284a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
| @@ -107,6 +107,8 @@ struct mmc_blk_data { | |||
| 107 | */ | 107 | */ |
| 108 | unsigned int part_curr; | 108 | unsigned int part_curr; |
| 109 | struct device_attribute force_ro; | 109 | struct device_attribute force_ro; |
| 110 | struct device_attribute power_ro_lock; | ||
| 111 | int area_type; | ||
| 110 | }; | 112 | }; |
| 111 | 113 | ||
| 112 | static DEFINE_MUTEX(open_lock); | 114 | static DEFINE_MUTEX(open_lock); |
| @@ -119,6 +121,7 @@ enum mmc_blk_status { | |||
| 119 | MMC_BLK_ABORT, | 121 | MMC_BLK_ABORT, |
| 120 | MMC_BLK_DATA_ERR, | 122 | MMC_BLK_DATA_ERR, |
| 121 | MMC_BLK_ECC_ERR, | 123 | MMC_BLK_ECC_ERR, |
| 124 | MMC_BLK_NOMEDIUM, | ||
| 122 | }; | 125 | }; |
| 123 | 126 | ||
| 124 | module_param(perdev_minors, int, 0444); | 127 | module_param(perdev_minors, int, 0444); |
| @@ -165,6 +168,70 @@ static void mmc_blk_put(struct mmc_blk_data *md) | |||
| 165 | mutex_unlock(&open_lock); | 168 | mutex_unlock(&open_lock); |
| 166 | } | 169 | } |
| 167 | 170 | ||
| 171 | static ssize_t power_ro_lock_show(struct device *dev, | ||
| 172 | struct device_attribute *attr, char *buf) | ||
| 173 | { | ||
| 174 | int ret; | ||
| 175 | struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev)); | ||
| 176 | struct mmc_card *card = md->queue.card; | ||
| 177 | int locked = 0; | ||
| 178 | |||
| 179 | if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN) | ||
| 180 | locked = 2; | ||
| 181 | else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN) | ||
| 182 | locked = 1; | ||
| 183 | |||
| 184 | ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); | ||
| 185 | |||
| 186 | return ret; | ||
| 187 | } | ||
| 188 | |||
| 189 | static ssize_t power_ro_lock_store(struct device *dev, | ||
| 190 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 191 | { | ||
| 192 | int ret; | ||
| 193 | struct mmc_blk_data *md, *part_md; | ||
| 194 | struct mmc_card *card; | ||
| 195 | unsigned long set; | ||
| 196 | |||
| 197 | if (kstrtoul(buf, 0, &set)) | ||
| 198 | return -EINVAL; | ||
| 199 | |||
| 200 | if (set != 1) | ||
| 201 | return count; | ||
| 202 | |||
| 203 | md = mmc_blk_get(dev_to_disk(dev)); | ||
| 204 | card = md->queue.card; | ||
| 205 | |||
| 206 | mmc_claim_host(card->host); | ||
| 207 | |||
| 208 | ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, | ||
| 209 | card->ext_csd.boot_ro_lock | | ||
| 210 | EXT_CSD_BOOT_WP_B_PWR_WP_EN, | ||
| 211 | card->ext_csd.part_time); | ||
| 212 | if (ret) | ||
| 213 | pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret); | ||
| 214 | else | ||
| 215 | card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN; | ||
| 216 | |||
| 217 | mmc_release_host(card->host); | ||
| 218 | |||
| 219 | if (!ret) { | ||
| 220 | pr_info("%s: Locking boot partition ro until next power on\n", | ||
| 221 | md->disk->disk_name); | ||
| 222 | set_disk_ro(md->disk, 1); | ||
| 223 | |||
| 224 | list_for_each_entry(part_md, &md->part, part) | ||
| 225 | if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) { | ||
| 226 | pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name); | ||
| 227 | set_disk_ro(part_md->disk, 1); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | mmc_blk_put(md); | ||
| 232 | return count; | ||
| 233 | } | ||
| 234 | |||
| 168 | static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, | 235 | static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr, |
| 169 | char *buf) | 236 | char *buf) |
| 170 | { | 237 | { |
| @@ -266,6 +333,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( | |||
| 266 | goto idata_err; | 333 | goto idata_err; |
| 267 | } | 334 | } |
| 268 | 335 | ||
| 336 | if (!idata->buf_bytes) | ||
| 337 | return idata; | ||
| 338 | |||
| 269 | idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); | 339 | idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); |
| 270 | if (!idata->buf) { | 340 | if (!idata->buf) { |
| 271 | err = -ENOMEM; | 341 | err = -ENOMEM; |
| @@ -312,25 +382,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
| 312 | if (IS_ERR(idata)) | 382 | if (IS_ERR(idata)) |
| 313 | return PTR_ERR(idata); | 383 | return PTR_ERR(idata); |
| 314 | 384 | ||
| 315 | cmd.opcode = idata->ic.opcode; | ||
| 316 | cmd.arg = idata->ic.arg; | ||
| 317 | cmd.flags = idata->ic.flags; | ||
| 318 | |||
| 319 | data.sg = &sg; | ||
| 320 | data.sg_len = 1; | ||
| 321 | data.blksz = idata->ic.blksz; | ||
| 322 | data.blocks = idata->ic.blocks; | ||
| 323 | |||
| 324 | sg_init_one(data.sg, idata->buf, idata->buf_bytes); | ||
| 325 | |||
| 326 | if (idata->ic.write_flag) | ||
| 327 | data.flags = MMC_DATA_WRITE; | ||
| 328 | else | ||
| 329 | data.flags = MMC_DATA_READ; | ||
| 330 | |||
| 331 | mrq.cmd = &cmd; | ||
| 332 | mrq.data = &data; | ||
| 333 | |||
| 334 | md = mmc_blk_get(bdev->bd_disk); | 385 | md = mmc_blk_get(bdev->bd_disk); |
| 335 | if (!md) { | 386 | if (!md) { |
| 336 | err = -EINVAL; | 387 | err = -EINVAL; |
| @@ -343,6 +394,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
| 343 | goto cmd_done; | 394 | goto cmd_done; |
| 344 | } | 395 | } |
| 345 | 396 | ||
| 397 | cmd.opcode = idata->ic.opcode; | ||
| 398 | cmd.arg = idata->ic.arg; | ||
| 399 | cmd.flags = idata->ic.flags; | ||
| 400 | |||
| 401 | if (idata->buf_bytes) { | ||
| 402 | data.sg = &sg; | ||
| 403 | data.sg_len = 1; | ||
| 404 | data.blksz = idata->ic.blksz; | ||
| 405 | data.blocks = idata->ic.blocks; | ||
| 406 | |||
| 407 | sg_init_one(data.sg, idata->buf, idata->buf_bytes); | ||
| 408 | |||
| 409 | if (idata->ic.write_flag) | ||
| 410 | data.flags = MMC_DATA_WRITE; | ||
| 411 | else | ||
| 412 | data.flags = MMC_DATA_READ; | ||
| 413 | |||
| 414 | /* data.flags must already be set before doing this. */ | ||
| 415 | mmc_set_data_timeout(&data, card); | ||
| 416 | |||
| 417 | /* Allow overriding the timeout_ns for empirical tuning. */ | ||
| 418 | if (idata->ic.data_timeout_ns) | ||
| 419 | data.timeout_ns = idata->ic.data_timeout_ns; | ||
| 420 | |||
| 421 | if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { | ||
| 422 | /* | ||
| 423 | * Pretend this is a data transfer and rely on the | ||
| 424 | * host driver to compute timeout. When all host | ||
| 425 | * drivers support cmd.cmd_timeout for R1B, this | ||
| 426 | * can be changed to: | ||
| 427 | * | ||
| 428 | * mrq.data = NULL; | ||
| 429 | * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; | ||
| 430 | */ | ||
| 431 | data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; | ||
| 432 | } | ||
| 433 | |||
| 434 | mrq.data = &data; | ||
| 435 | } | ||
| 436 | |||
| 437 | mrq.cmd = &cmd; | ||
| 438 | |||
| 346 | mmc_claim_host(card->host); | 439 | mmc_claim_host(card->host); |
| 347 | 440 | ||
| 348 | if (idata->ic.is_acmd) { | 441 | if (idata->ic.is_acmd) { |
| @@ -351,24 +444,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
| 351 | goto cmd_rel_host; | 444 | goto cmd_rel_host; |
| 352 | } | 445 | } |
| 353 | 446 | ||
| 354 | /* data.flags must already be set before doing this. */ | ||
| 355 | mmc_set_data_timeout(&data, card); | ||
| 356 | /* Allow overriding the timeout_ns for empirical tuning. */ | ||
| 357 | if (idata->ic.data_timeout_ns) | ||
| 358 | data.timeout_ns = idata->ic.data_timeout_ns; | ||
| 359 | |||
| 360 | if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { | ||
| 361 | /* | ||
| 362 | * Pretend this is a data transfer and rely on the host driver | ||
