mmc: card: Add RPMB support in IOCTL interface
authorLoic Pallardy <loic.pallardy-ext@stericsson.com>
Mon, 6 Aug 2012 15:12:31 +0000 (17:12 +0200)
committerChris Ball <cjb@laptop.org>
Thu, 6 Dec 2012 18:54:49 +0000 (13:54 -0500)
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>
drivers/mmc/card/block.c

index 1d341f3..21056b9 100644 (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 @@ out:
        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);