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:
parent
67c79db8d9
commit
8d1e977da8
1 changed files with 64 additions and 0 deletions
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue