mmc: card: Add RPMB support in IOCTL interface

RPMB partition is accessing though /dev/block/mmcXrpmb device
User callers can read and write entire data frame(s) as defined
by JEDEC Standard JESD84-A441, using standard IOCTL interface.

Signed-off-by: Alex Macro <alex.macro@stericsson.com>
Signed-off-by: Loic Pallardy <loic.pallardy@stericsson.com>
Reviewed-by: Namjae Jeon <linkinjeon@gmail.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Krishna Konda <kkonda@codeaurora.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
This commit is contained in:
Loic Pallardy 2012-08-06 17:12:31 +02:00 committed by Chris Ball
parent 67c79db8d9
commit 8d1e977da8

View file

@ -127,6 +127,10 @@ enum mmc_blk_status {
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md);
static int get_card_status(struct mmc_card *card, u32 *status, int retries);
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@ -358,6 +362,38 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
return ERR_PTR(err);
}
static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
u32 retries_max)
{
int err;
u32 retry_count = 0;
if (!status || !retries_max)
return -EINVAL;
do {
err = get_card_status(card, status, 5);
if (err)
break;
if (!R1_STATUS(*status) &&
(R1_CURRENT_STATE(*status) != R1_STATE_PRG))
break; /* RPMB programming operation complete */
/*
* Rechedule to give the MMC device a chance to continue
* processing the previous command without being polled too
* frequently.
*/
usleep_range(1000, 5000);
} while (++retry_count < retries_max);
if (retry_count == retries_max)
err = -EPERM;
return err;
}
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
@ -369,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_request mrq = {NULL};
struct scatterlist sg;
int err;
int is_rpmb = false;
u32 status = 0;
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
@ -388,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_err;
}
if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
is_rpmb = true;
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
@ -438,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mmc_claim_host(card->host);
err = mmc_blk_part_switch(card, md);
if (err)
goto cmd_rel_host;
if (idata->ic.is_acmd) {
err = mmc_app_cmd(card->host, card);
if (err)
goto cmd_rel_host;
}
if (is_rpmb) {
err = mmc_set_blockcount(card, data.blocks,
idata->ic.write_flag & (1 << 31));
if (err)
goto cmd_rel_host;
}
mmc_wait_for_req(card->host, &mrq);
if (cmd.error) {
@ -479,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
}
}
if (is_rpmb) {
/*
* Ensure RPMB command has completed by polling CMD13
* "Send Status".
*/
err = ioctl_rpmb_card_status_poll(card, &status, 5);
if (err)
dev_err(mmc_dev(card->host),
"%s: Card Status=0x%08X, error %d\n",
__func__, status, err);
}
cmd_rel_host:
mmc_release_host(card->host);