提交 0493f6fe 编写于 作者: L Linus Walleij 提交者: Ulf Hansson

mmc: block: Move boot partition locking into a driver op

This moves the boot partition lock command (issued from sysfs)
into a custom block layer request, just like the ioctl()s,
getting rid of yet another instance of mmc_get_card().

Since we now have two operations issuing special DRV_OP's, we
rename the result variable ->drv_op_result.

Tested by locking the boot partition from userspace:
> cd /sys/devices/platform/soc/80114000.sdi4_per2/mmc_host/mmc3/
     mmc3:0001/block/mmcblk3/mmcblk3boot0
> echo 1 > ro_lock_until_next_power_on
[  178.645324] mmcblk3boot1: Locking boot partition ro until next power on
[  178.652221] mmcblk3boot0: Locking boot partition ro until next power on

Also tested this with a huge dd job in the background: it
is now possible to lock the boot partitions on the card even
under heavy I/O.
Signed-off-by: NLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: NUlf Hansson <ulf.hansson@linaro.org>
上级 5ec12396
...@@ -190,6 +190,8 @@ static ssize_t power_ro_lock_store(struct device *dev, ...@@ -190,6 +190,8 @@ static ssize_t power_ro_lock_store(struct device *dev,
int ret; int ret;
struct mmc_blk_data *md, *part_md; struct mmc_blk_data *md, *part_md;
struct mmc_card *card; struct mmc_card *card;
struct mmc_queue *mq;
struct request *req;
unsigned long set; unsigned long set;
if (kstrtoul(buf, 0, &set)) if (kstrtoul(buf, 0, &set))
...@@ -199,20 +201,14 @@ static ssize_t power_ro_lock_store(struct device *dev, ...@@ -199,20 +201,14 @@ static ssize_t power_ro_lock_store(struct device *dev,
return count; return count;
md = mmc_blk_get(dev_to_disk(dev)); md = mmc_blk_get(dev_to_disk(dev));
mq = &md->queue;
card = md->queue.card; card = md->queue.card;
mmc_get_card(card); /* Dispatch locking to the block layer */
req = blk_get_request(mq->queue, REQ_OP_DRV_OUT, __GFP_RECLAIM);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
card->ext_csd.boot_ro_lock | blk_execute_rq(mq->queue, NULL, req, 0);
EXT_CSD_BOOT_WP_B_PWR_WP_EN, ret = req_to_mmc_queue_req(req)->drv_op_result;
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_put_card(card);
if (!ret) { if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n", pr_info("%s: Locking boot partition ro until next power on\n",
...@@ -606,7 +602,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -606,7 +602,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
req_to_mmc_queue_req(req)->idata = idatas; req_to_mmc_queue_req(req)->idata = idatas;
req_to_mmc_queue_req(req)->ioc_count = 1; req_to_mmc_queue_req(req)->ioc_count = 1;
blk_execute_rq(mq->queue, NULL, req, 0); blk_execute_rq(mq->queue, NULL, req, 0);
ioc_err = req_to_mmc_queue_req(req)->ioc_result; ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata); err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
blk_put_request(req); blk_put_request(req);
...@@ -682,7 +678,7 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev, ...@@ -682,7 +678,7 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
req_to_mmc_queue_req(req)->idata = idata; req_to_mmc_queue_req(req)->idata = idata;
req_to_mmc_queue_req(req)->ioc_count = num_of_cmds; req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
blk_execute_rq(mq->queue, NULL, req, 0); blk_execute_rq(mq->queue, NULL, req, 0);
ioc_err = req_to_mmc_queue_req(req)->ioc_result; ioc_err = req_to_mmc_queue_req(req)->drv_op_result;
/* copy to user if data and response */ /* copy to user if data and response */
for (i = 0; i < num_of_cmds && !err; i++) for (i = 0; i < num_of_cmds && !err; i++)
...@@ -1195,7 +1191,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) ...@@ -1195,7 +1191,7 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
struct mmc_queue_req *mq_rq; struct mmc_queue_req *mq_rq;
struct mmc_card *card = mq->card; struct mmc_card *card = mq->card;
struct mmc_blk_data *md = mq->blkdata; struct mmc_blk_data *md = mq->blkdata;
int ioc_err; int ret;
int i; int i;
mq_rq = req_to_mmc_queue_req(req); mq_rq = req_to_mmc_queue_req(req);
...@@ -1203,23 +1199,34 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req) ...@@ -1203,23 +1199,34 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
switch (mq_rq->drv_op) { switch (mq_rq->drv_op) {
case MMC_DRV_OP_IOCTL: case MMC_DRV_OP_IOCTL:
for (i = 0; i < mq_rq->ioc_count; i++) { for (i = 0; i < mq_rq->ioc_count; i++) {
ioc_err = ret = __mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]);
__mmc_blk_ioctl_cmd(card, md, mq_rq->idata[i]); if (ret)
if (ioc_err)
break; break;
} }
mq_rq->ioc_result = ioc_err;
/* Always switch back to main area after RPMB access */ /* Always switch back to main area after RPMB access */
if (md->area_type & MMC_BLK_DATA_AREA_RPMB) if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
mmc_blk_part_switch(card, dev_get_drvdata(&card->dev)); mmc_blk_part_switch(card, dev_get_drvdata(&card->dev));
break;
blk_end_request_all(req, ioc_err); case MMC_DRV_OP_BOOT_WP:
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;
break; break;
default: default:
/* Unknown operation */ pr_err("%s: unknown driver specific operation\n",
md->disk->disk_name);
ret = -EINVAL;
break; break;
} }
mq_rq->drv_op_result = ret;
blk_end_request_all(req, ret);
} }
static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
......
...@@ -35,9 +35,11 @@ struct mmc_blk_request { ...@@ -35,9 +35,11 @@ struct mmc_blk_request {
/** /**
* enum mmc_drv_op - enumerates the operations in the mmc_queue_req * enum mmc_drv_op - enumerates the operations in the mmc_queue_req
* @MMC_DRV_OP_IOCTL: ioctl operation * @MMC_DRV_OP_IOCTL: ioctl operation
* @MMC_DRV_OP_BOOT_WP: write protect boot partitions
*/ */
enum mmc_drv_op { enum mmc_drv_op {
MMC_DRV_OP_IOCTL, MMC_DRV_OP_IOCTL,
MMC_DRV_OP_BOOT_WP,
}; };
struct mmc_queue_req { struct mmc_queue_req {
...@@ -48,7 +50,7 @@ struct mmc_queue_req { ...@@ -48,7 +50,7 @@ struct mmc_queue_req {
unsigned int bounce_sg_len; unsigned int bounce_sg_len;
struct mmc_async_req areq; struct mmc_async_req areq;
enum mmc_drv_op drv_op; enum mmc_drv_op drv_op;
int ioc_result; int drv_op_result;
struct mmc_blk_ioc_data **idata; struct mmc_blk_ioc_data **idata;
unsigned int ioc_count; unsigned int ioc_count;
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册