Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Loic Pallardy and committed by
Chris Ball
8d1e977d 67c79db8

+64
+64
drivers/mmc/card/block.c
··· 127 127 module_param(perdev_minors, int, 0444); 128 128 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); 129 129 130 + static inline int mmc_blk_part_switch(struct mmc_card *card, 131 + struct mmc_blk_data *md); 132 + static int get_card_status(struct mmc_card *card, u32 *status, int retries); 133 + 130 134 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) 131 135 { 132 136 struct mmc_blk_data *md; ··· 362 358 return ERR_PTR(err); 363 359 } 364 360 361 + static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, 362 + u32 retries_max) 363 + { 364 + int err; 365 + u32 retry_count = 0; 366 + 367 + if (!status || !retries_max) 368 + return -EINVAL; 369 + 370 + do { 371 + err = get_card_status(card, status, 5); 372 + if (err) 373 + break; 374 + 375 + if (!R1_STATUS(*status) && 376 + (R1_CURRENT_STATE(*status) != R1_STATE_PRG)) 377 + break; /* RPMB programming operation complete */ 378 + 379 + /* 380 + * Rechedule to give the MMC device a chance to continue 381 + * processing the previous command without being polled too 382 + * frequently. 383 + */ 384 + usleep_range(1000, 5000); 385 + } while (++retry_count < retries_max); 386 + 387 + if (retry_count == retries_max) 388 + err = -EPERM; 389 + 390 + return err; 391 + } 392 + 365 393 static int mmc_blk_ioctl_cmd(struct block_device *bdev, 366 394 struct mmc_ioc_cmd __user *ic_ptr) 367 395 { ··· 405 369 struct mmc_request mrq = {NULL}; 406 370 struct scatterlist sg; 407 371 int err; 372 + int is_rpmb = false; 373 + u32 status = 0; 408 374 409 375 /* 410 376 * The caller must have CAP_SYS_RAWIO, and must be calling this on the ··· 425 387 err = -EINVAL; 426 388 goto cmd_err; 427 389 } 390 + 391 + if (md->area_type & MMC_BLK_DATA_AREA_RPMB) 392 + is_rpmb = true; 428 393 429 394 card = md->queue.card; 430 395 if (IS_ERR(card)) { ··· 479 438 480 439 mmc_claim_host(card->host); 481 440 441 + err = mmc_blk_part_switch(card, md); 442 + if (err) 443 + goto cmd_rel_host; 444 + 482 445 if (idata->ic.is_acmd) { 483 446 err = mmc_app_cmd(card->host, card); 447 + if (err) 448 + goto cmd_rel_host; 449 + } 450 + 451 + if (is_rpmb) { 452 + err = mmc_set_blockcount(card, data.blocks, 453 + idata->ic.write_flag & (1 << 31)); 484 454 if (err) 485 455 goto cmd_rel_host; 486 456 } ··· 529 477 err = -EFAULT; 530 478 goto cmd_rel_host; 531 479 } 480 + } 481 + 482 + if (is_rpmb) { 483 + /* 484 + * Ensure RPMB command has completed by polling CMD13 485 + * "Send Status". 486 + */ 487 + err = ioctl_rpmb_card_status_poll(card, &status, 5); 488 + if (err) 489 + dev_err(mmc_dev(card->host), 490 + "%s: Card Status=0x%08X, error %d\n", 491 + __func__, status, err); 532 492 } 533 493 534 494 cmd_rel_host: