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 ...
This commit is contained in:
@@ -107,6 +107,8 @@ struct mmc_blk_data {
|
||||
*/
|
||||
unsigned int part_curr;
|
||||
struct device_attribute force_ro;
|
||||
struct device_attribute power_ro_lock;
|
||||
int area_type;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(open_lock);
|
||||
@@ -119,6 +121,7 @@ enum mmc_blk_status {
|
||||
MMC_BLK_ABORT,
|
||||
MMC_BLK_DATA_ERR,
|
||||
MMC_BLK_ECC_ERR,
|
||||
MMC_BLK_NOMEDIUM,
|
||||
};
|
||||
|
||||
module_param(perdev_minors, int, 0444);
|
||||
@@ -165,6 +168,70 @@ static void mmc_blk_put(struct mmc_blk_data *md)
|
||||
mutex_unlock(&open_lock);
|
||||
}
|
||||
|
||||
static ssize_t power_ro_lock_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret;
|
||||
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
|
||||
struct mmc_card *card = md->queue.card;
|
||||
int locked = 0;
|
||||
|
||||
if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
|
||||
locked = 2;
|
||||
else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
|
||||
locked = 1;
|
||||
|
||||
ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t power_ro_lock_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
struct mmc_blk_data *md, *part_md;
|
||||
struct mmc_card *card;
|
||||
unsigned long set;
|
||||
|
||||
if (kstrtoul(buf, 0, &set))
|
||||
return -EINVAL;
|
||||
|
||||
if (set != 1)
|
||||
return count;
|
||||
|
||||
md = mmc_blk_get(dev_to_disk(dev));
|
||||
card = md->queue.card;
|
||||
|
||||
mmc_claim_host(card->host);
|
||||
|
||||
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
|
||||
card->ext_csd.boot_ro_lock |
|
||||
EXT_CSD_BOOT_WP_B_PWR_WP_EN,
|
||||
card->ext_csd.part_time);
|
||||
if (ret)
|
||||
pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret);
|
||||
else
|
||||
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
|
||||
|
||||
mmc_release_host(card->host);
|
||||
|
||||
if (!ret) {
|
||||
pr_info("%s: Locking boot partition ro until next power on\n",
|
||||
md->disk->disk_name);
|
||||
set_disk_ro(md->disk, 1);
|
||||
|
||||
list_for_each_entry(part_md, &md->part, part)
|
||||
if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
|
||||
pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name);
|
||||
set_disk_ro(part_md->disk, 1);
|
||||
}
|
||||
}
|
||||
|
||||
mmc_blk_put(md);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
@@ -266,6 +333,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
|
||||
goto idata_err;
|
||||
}
|
||||
|
||||
if (!idata->buf_bytes)
|
||||
return idata;
|
||||
|
||||
idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
|
||||
if (!idata->buf) {
|
||||
err = -ENOMEM;
|
||||
@@ -312,25 +382,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
|
||||
if (IS_ERR(idata))
|
||||
return PTR_ERR(idata);
|
||||
|
||||
cmd.opcode = idata->ic.opcode;
|
||||
cmd.arg = idata->ic.arg;
|
||||
cmd.flags = idata->ic.flags;
|
||||
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
data.blksz = idata->ic.blksz;
|
||||
data.blocks = idata->ic.blocks;
|
||||
|
||||
sg_init_one(data.sg, idata->buf, idata->buf_bytes);
|
||||
|
||||
if (idata->ic.write_flag)
|
||||
data.flags = MMC_DATA_WRITE;
|
||||
else
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
mrq.data = &data;
|
||||
|
||||
md = mmc_blk_get(bdev->bd_disk);
|
||||
if (!md) {
|
||||
err = -EINVAL;
|
||||
@@ -343,6 +394,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
|
||||
goto cmd_done;
|
||||
}
|
||||
|
||||
cmd.opcode = idata->ic.opcode;
|
||||
cmd.arg = idata->ic.arg;
|
||||
cmd.flags = idata->ic.flags;
|
||||
|
||||
if (idata->buf_bytes) {
|
||||
data.sg = &sg;
|
||||
data.sg_len = 1;
|
||||
data.blksz = idata->ic.blksz;
|
||||
data.blocks = idata->ic.blocks;
|
||||
|
||||
sg_init_one(data.sg, idata->buf, idata->buf_bytes);
|
||||
|
||||
if (idata->ic.write_flag)
|
||||
data.flags = MMC_DATA_WRITE;
|
||||
else
|
||||
data.flags = MMC_DATA_READ;
|
||||
|
||||
/* data.flags must already be set before doing this. */
|
||||
mmc_set_data_timeout(&data, card);
|
||||
|
||||
/* Allow overriding the timeout_ns for empirical tuning. */
|
||||
if (idata->ic.data_timeout_ns)
|
||||
data.timeout_ns = idata->ic.data_timeout_ns;
|
||||
|
||||
if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
|
||||
/*
|
||||
* Pretend this is a data transfer and rely on the
|
||||
* host driver to compute timeout. When all host
|
||||
* drivers support cmd.cmd_timeout for R1B, this
|
||||
* can be changed to:
|
||||
*
|
||||
* mrq.data = NULL;
|
||||
* cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
|
||||
*/
|
||||
data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
|
||||
}
|
||||
|
||||
mrq.data = &data;
|
||||
}
|
||||
|
||||
mrq.cmd = &cmd;
|
||||
|
||||
mmc_claim_host(card->host);
|
||||
|
||||
if (idata->ic.is_acmd) {
|
||||
@@ -351,24 +444,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
|
||||
goto cmd_rel_host;
|
||||
}
|
||||
|
||||
/* data.flags must already be set before doing this. */
|
||||
mmc_set_data_timeout(&data, card);
|
||||
/* Allow overriding the timeout_ns for empirical tuning. */
|
||||
if (idata->ic.data_timeout_ns)
|
||||
data.timeout_ns = idata->ic.data_timeout_ns;
|
||||
|
||||
if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
|
||||
/*
|
||||
* Pretend this is a data transfer and rely on the host driver
|
||||
* to compute timeout. When all host drivers support
|
||||
* cmd.cmd_timeout for R1B, this can be changed to:
|
||||
*
|
||||
* mrq.data = NULL;
|
||||
* cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
|
||||
*/
|
||||
data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
|
||||
}
|
||||
|
||||
mmc_wait_for_req(card->host, &mrq);
|
||||
|
||||
if (cmd.error) {
|
||||
@@ -565,6 +640,7 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
|
||||
return err;
|
||||
}
|
||||
|
||||
#define ERR_NOMEDIUM 3
|
||||
#define ERR_RETRY 2
|
||||
#define ERR_ABORT 1
|
||||
#define ERR_CONTINUE 0
|
||||
@@ -632,6 +708,9 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
|
||||
u32 status, stop_status = 0;
|
||||
int err, retry;
|
||||
|
||||
if (mmc_card_removed(card))
|
||||
return ERR_NOMEDIUM;
|
||||
|
||||
/*
|
||||
* Try to get card status which indicates both the card state
|
||||
* and why there was no response. If the first attempt fails,
|
||||
@@ -648,8 +727,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
|
||||
}
|
||||
|
||||
/* We couldn't get a response from the card. Give up. */
|
||||
if (err)
|
||||
if (err) {
|
||||
/* Check if the card is removed */
|
||||
if (mmc_detect_card_removed(card->host))
|
||||
return ERR_NOMEDIUM;
|
||||
return ERR_ABORT;
|
||||
}
|
||||
|
||||
/* Flag ECC errors */
|
||||
if ((status & R1_CARD_ECC_FAILED) ||
|
||||
@@ -922,6 +1005,8 @@ static int mmc_blk_err_check(struct mmc_card *card,
|
||||
return MMC_BLK_RETRY;
|
||||
case ERR_ABORT:
|
||||
return MMC_BLK_ABORT;
|
||||
case ERR_NOMEDIUM:
|
||||
return MMC_BLK_NOMEDIUM;
|
||||
case ERR_CONTINUE:
|
||||
break;
|
||||
}
|
||||
@@ -1255,6 +1340,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
||||
if (!ret)
|
||||
goto start_new_req;
|
||||
break;
|
||||
case MMC_BLK_NOMEDIUM:
|
||||
goto cmd_abort;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
@@ -1271,6 +1358,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
||||
|
||||
cmd_abort:
|
||||
spin_lock_irq(&md->lock);
|
||||
if (mmc_card_removed(card))
|
||||
req->cmd_flags |= REQ_QUIET;
|
||||
while (ret)
|
||||
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
|
||||
spin_unlock_irq(&md->lock);
|
||||
@@ -1339,7 +1428,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
||||
struct device *parent,
|
||||
sector_t size,
|
||||
bool default_ro,
|
||||
const char *subname)
|
||||
const char *subname,
|
||||
int area_type)
|
||||
{
|
||||
struct mmc_blk_data *md;
|
||||
int devidx, ret;
|
||||
@@ -1364,11 +1454,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
||||
if (!subname) {
|
||||
md->name_idx = find_first_zero_bit(name_use, max_devices);
|
||||
__set_bit(md->name_idx, name_use);
|
||||
}
|
||||
else
|
||||
} else
|
||||
md->name_idx = ((struct mmc_blk_data *)
|
||||
dev_to_disk(parent)->private_data)->name_idx;
|
||||
|
||||
md->area_type = area_type;
|
||||
|
||||
/*
|
||||
* Set the read-only status based on the supported commands
|
||||
* and the write protect switch.
|
||||
@@ -1462,7 +1553,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
|
||||
size = card->csd.capacity << (card->csd.read_blkbits - 9);
|
||||
}
|
||||
|
||||
md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
|
||||
md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
|
||||
MMC_BLK_DATA_AREA_MAIN);
|
||||
return md;
|
||||
}
|
||||
|
||||
@@ -1471,13 +1563,14 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
|
||||
unsigned int part_type,
|
||||
sector_t size,
|
||||
bool default_ro,
|
||||
const char *subname)
|
||||
const char *subname,
|
||||
int area_type)
|
||||
{
|
||||
char cap_str[10];
|
||||
struct mmc_blk_data *part_md;
|
||||
|
||||
part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
|
||||
subname);
|
||||
subname, area_type);
|
||||
if (IS_ERR(part_md))
|
||||
return PTR_ERR(part_md);
|
||||
part_md->part_type = part_type;
|
||||
@@ -1510,7 +1603,8 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
|
||||
card->part[idx].part_cfg,
|
||||
card->part[idx].size >> 9,
|
||||
card->part[idx].force_ro,
|
||||
card->part[idx].name);
|
||||
card->part[idx].name,
|
||||
card->part[idx].area_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1539,9 +1633,16 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
|
||||
|
||||
static void mmc_blk_remove_req(struct mmc_blk_data *md)
|
||||
{
|
||||
struct mmc_card *card;
|
||||
|
||||
if (md) {
|
||||
card = md->queue.card;
|
||||
if (md->disk->flags & GENHD_FL_UP) {
|
||||
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
|
||||
if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
|
||||
card->ext_csd.boot_ro_lockable)
|
||||
device_remove_file(disk_to_dev(md->disk),
|
||||
&md->power_ro_lock);
|
||||
|
||||
/* Stop new requests from getting into the queue */
|
||||
del_gendisk(md->disk);
|
||||
@@ -1570,6 +1671,7 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
|
||||
static int mmc_add_disk(struct mmc_blk_data *md)
|
||||
{
|
||||
int ret;
|
||||
struct mmc_card *card = md->queue.card;
|
||||
|
||||
add_disk(md->disk);
|
||||
md->force_ro.show = force_ro_show;
|
||||
@@ -1579,18 +1681,53 @@ static int mmc_add_disk(struct mmc_blk_data *md)
|
||||
md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
|
||||
ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
|
||||
if (ret)
|
||||
del_gendisk(md->disk);
|
||||
goto force_ro_fail;
|
||||
|
||||
if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
|
||||
card->ext_csd.boot_ro_lockable) {
|
||||
mode_t mode;
|
||||
|
||||
if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
|
||||
mode = S_IRUGO;
|
||||
else
|
||||
mode = S_IRUGO | S_IWUSR;
|
||||
|
||||
md->power_ro_lock.show = power_ro_lock_show;
|
||||
md->power_ro_lock.store = power_ro_lock_store;
|
||||
md->power_ro_lock.attr.mode = mode;
|
||||
md->power_ro_lock.attr.name =
|
||||
"ro_lock_until_next_power_on";
|
||||
ret = device_create_file(disk_to_dev(md->disk),
|
||||
&md->power_ro_lock);
|
||||
if (ret)
|
||||
goto power_ro_lock_fail;
|
||||
}
|
||||
return ret;
|
||||
|
||||
power_ro_lock_fail:
|
||||
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
|
||||
force_ro_fail:
|
||||
del_gendisk(md->disk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CID_MANFID_SANDISK 0x2
|
||||
#define CID_MANFID_TOSHIBA 0x11
|
||||
#define CID_MANFID_MICRON 0x13
|
||||
|
||||
static const struct mmc_fixup blk_fixups[] =
|
||||
{
|
||||
MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
|
||||
MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
|
||||
MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
|
||||
MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
|
||||
MMC_QUIRK_INAND_CMD38),
|
||||
MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
|
||||
MMC_QUIRK_INAND_CMD38),
|
||||
|
||||
/*
|
||||
* Some MMC cards experience performance degradation with CMD23
|
||||
@@ -1600,18 +1737,18 @@ static const struct mmc_fixup blk_fixups[] =
|
||||
*
|
||||
* N.B. This doesn't affect SD cards.
|
||||
*/
|
||||
MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
|
||||
MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
|
||||
MMC_QUIRK_BLK_NO_CMD23),
|
||||
MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
|
||||
MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
|
||||
MMC_QUIRK_BLK_NO_CMD23),
|
||||
MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
|
||||
MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
|
||||
MMC_QUIRK_BLK_NO_CMD23),
|
||||
|
||||
/*
|
||||
* Some Micron MMC cards needs longer data read timeout than
|
||||
* indicated in CSD.
|
||||
*/
|
||||
MMC_FIXUP(CID_NAME_ANY, 0x13, 0x200, add_quirk_mmc,
|
||||
MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
|
||||
MMC_QUIRK_LONG_READ_TIME),
|
||||
|
||||
END_FIXUP
|
||||
|
@@ -1581,6 +1581,7 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
|
||||
|
||||
t->max_segs = test->card->host->max_segs;
|
||||
t->max_seg_sz = test->card->host->max_seg_size;
|
||||
t->max_seg_sz -= t->max_seg_sz % 512;
|
||||
|
||||
t->max_tfr = t->max_sz;
|
||||
if (t->max_tfr >> 9 > test->card->host->max_blk_count)
|
||||
|
@@ -29,6 +29,8 @@
|
||||
*/
|
||||
static int mmc_prep_request(struct request_queue *q, struct request *req)
|
||||
{
|
||||
struct mmc_queue *mq = q->queuedata;
|
||||
|
||||
/*
|
||||
* We only like normal block requests and discards.
|
||||
*/
|
||||
@@ -37,6 +39,9 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
|
||||
return BLKPREP_KILL;
|
||||
}
|
||||
|
||||
if (mq && mmc_card_removed(mq->card))
|
||||
return BLKPREP_KILL;
|
||||
|
||||
req->cmd_flags |= REQ_DONTPREP;
|
||||
|
||||
return BLKPREP_OK;
|
||||
|
Reference in New Issue
Block a user