Skip to content

Commit a5f5774

Browse files
jonhunterstorulf
authored andcommitted
mmc: block: Add new ioctl to send multi commands
Certain eMMC devices allow vendor specific device information to be read via a sequence of vendor commands. These vendor commands must be issued in sequence and an atomic fashion. One way to support this would be to add an ioctl function for sending a sequence of commands to the device atomically as proposed here. These multi commands are simple array of the existing mmc_ioc_cmd structure. The structure passed via the ioctl uses a __u64 type to specify the number of commands (so that the structure is aligned on a 64-bit boundary) and a zero length array as a header for list of commands to be issued. The maximum number of commands that can be sent is determined by MMC_IOC_MAX_CMDS (which defaults to 255 and should be more than sufficient). This based upon work by Seshagiri Holi <sholi@nvidia.com>. Signed-off-by: Seshagiri Holi <sholi@nvidia.com> Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent aaa58d0 commit a5f5774

File tree

2 files changed

+169
-56
lines changed

2 files changed

+169
-56
lines changed

drivers/mmc/card/block.c

Lines changed: 151 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,24 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
387387
return ERR_PTR(err);
388388
}
389389

390+
static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr,
391+
struct mmc_blk_ioc_data *idata)
392+
{
393+
struct mmc_ioc_cmd *ic = &idata->ic;
394+
395+
if (copy_to_user(&(ic_ptr->response), ic->response,
396+
sizeof(ic->response)))
397+
return -EFAULT;
398+
399+
if (!idata->ic.write_flag) {
400+
if (copy_to_user((void __user *)(unsigned long)ic->data_ptr,
401+
idata->buf, idata->buf_bytes))
402+
return -EFAULT;
403+
}
404+
405+
return 0;
406+
}
407+
390408
static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
391409
u32 retries_max)
392410
{
@@ -447,12 +465,9 @@ static int ioctl_do_sanitize(struct mmc_card *card)
447465
return err;
448466
}
449467

450-
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
451-
struct mmc_ioc_cmd __user *ic_ptr)
468+
static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
469+
struct mmc_blk_ioc_data *idata)
452470
{
453-
struct mmc_blk_ioc_data *idata;
454-
struct mmc_blk_data *md;
455-
struct mmc_card *card;
456471
struct mmc_command cmd = {0};
457472
struct mmc_data data = {0};
458473
struct mmc_request mrq = {NULL};
@@ -461,33 +476,12 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
461476
int is_rpmb = false;
462477
u32 status = 0;
463478

464-
/*
465-
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
466-
* whole block device, not on a partition. This prevents overspray
467-
* between sibling partitions.
468-
*/
469-
if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
470-
return -EPERM;
471-
472-
idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
473-
if (IS_ERR(idata))
474-
return PTR_ERR(idata);
475-
476-
md = mmc_blk_get(bdev->bd_disk);
477-
if (!md) {
478-
err = -EINVAL;
479-
goto cmd_err;
480-
}
479+
if (!card || !md || !idata)
480+
return -EINVAL;
481481

482482
if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
483483
is_rpmb = true;
484484

485-
card = md->queue.card;
486-
if (IS_ERR(card)) {
487-
err = PTR_ERR(card);
488-
goto cmd_done;
489-
}
490-
491485
cmd.opcode = idata->ic.opcode;
492486
cmd.arg = idata->ic.arg;
493487
cmd.flags = idata->ic.flags;
@@ -530,23 +524,21 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
530524

531525
mrq.cmd = &cmd;
532526

533-
mmc_get_card(card);
534-
535527
err = mmc_blk_part_switch(card, md);
536528
if (err)
537-
goto cmd_rel_host;
529+
return err;
538530

539531
if (idata->ic.is_acmd) {
540532
err = mmc_app_cmd(card->host, card);
541533
if (err)
542-
goto cmd_rel_host;
534+
return err;
543535
}
544536

545537
if (is_rpmb) {
546538
err = mmc_set_blockcount(card, data.blocks,
547539
idata->ic.write_flag & (1 << 31));
548540
if (err)
549-
goto cmd_rel_host;
541+
return err;
550542
}
551543

552544
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
@@ -557,22 +549,20 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
557549
pr_err("%s: ioctl_do_sanitize() failed. err = %d",
558550
__func__, err);
559551

560-
goto cmd_rel_host;
552+
return err;
561553
}
562554

563555
mmc_wait_for_req(card->host, &mrq);
564556

565557
if (cmd.error) {
566558
dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
567559
__func__, cmd.error);
568-
err = cmd.error;
569-
goto cmd_rel_host;
560+
return cmd.error;
570561
}
571562
if (data.error) {
572563
dev_err(mmc_dev(card->host), "%s: data error %d\n",
573564
__func__, data.error);
574-
err = data.error;
575-
goto cmd_rel_host;
565+
return data.error;
576566
}
577567

578568
/*
@@ -582,18 +572,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
582572
if (idata->ic.postsleep_min_us)
583573
usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
584574

585-
if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) {
586-
err = -EFAULT;
587-
goto cmd_rel_host;
588-
}
589-
590-
if (!idata->ic.write_flag) {
591-
if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr,
592-
idata->buf, idata->buf_bytes)) {
593-
err = -EFAULT;
594-
goto cmd_rel_host;
595-
}
596-
}
575+
memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
597576

598577
if (is_rpmb) {
599578
/*
@@ -607,9 +586,42 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
607586
__func__, status, err);
608587
}
609588

610-
cmd_rel_host:
589+
return err;
590+
}
591+
592+
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
593+
struct mmc_ioc_cmd __user *ic_ptr)
594+
{
595+
struct mmc_blk_ioc_data *idata;
596+
struct mmc_blk_data *md;
597+
struct mmc_card *card;
598+
int err;
599+
600+
idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
601+
if (IS_ERR(idata))
602+
return PTR_ERR(idata);
603+
604+
md = mmc_blk_get(bdev->bd_disk);
605+
if (!md) {
606+
err = -EINVAL;
607+
goto cmd_err;
608+
}
609+
610+
card = md->queue.card;
611+
if (IS_ERR(card)) {
612+
err = PTR_ERR(card);
613+
goto cmd_done;
614+
}
615+
616+
mmc_get_card(card);
617+
618+
err = __mmc_blk_ioctl_cmd(card, md, idata);
619+
611620
mmc_put_card(card);
612621

622+
if (!err)
623+
err = mmc_blk_ioctl_copy_to_user(ic_ptr, idata);
624+
613625
cmd_done:
614626
mmc_blk_put(md);
615627
cmd_err:
@@ -618,13 +630,97 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
618630
return err;
619631
}
620632

633+
static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
634+
struct mmc_ioc_multi_cmd __user *user)
635+
{
636+
struct mmc_blk_ioc_data **idata = NULL;
637+
struct mmc_ioc_cmd __user *cmds = user->cmds;
638+
struct mmc_card *card;
639+
struct mmc_blk_data *md;
640+
int i, err = -EFAULT;
641+
__u64 num_of_cmds;
642+
643+
if (copy_from_user(&num_of_cmds, &user->num_of_cmds,
644+
sizeof(num_of_cmds)))
645+
return -EFAULT;
646+
647+
if (num_of_cmds > MMC_IOC_MAX_CMDS)
648+
return -EINVAL;
649+
650+
idata = kcalloc(num_of_cmds, sizeof(*idata), GFP_KERNEL);
651+
if (!idata)
652+
return -ENOMEM;
653+
654+
for (i = 0; i < num_of_cmds; i++) {
655+
idata[i] = mmc_blk_ioctl_copy_from_user(&cmds[i]);
656+
if (IS_ERR(idata[i])) {
657+
err = PTR_ERR(idata[i]);
658+
num_of_cmds = i;
659+
goto cmd_err;
660+
}
661+
}
662+
663+
md = mmc_blk_get(bdev->bd_disk);
664+
if (!md)
665+
goto cmd_err;
666+
667+
card = md->queue.card;
668+
if (IS_ERR(card)) {
669+
err = PTR_ERR(card);
670+
goto cmd_done;
671+
}
672+
673+
mmc_get_card(card);
674+
675+
for (i = 0; i < num_of_cmds; i++) {
676+
err = __mmc_blk_ioctl_cmd(card, md, idata[i]);
677+
if (err) {
678+
mmc_put_card(card);
679+
goto cmd_done;
680+
}
681+
}
682+
683+
mmc_put_card(card);
684+
685+
/* copy to user if data and response */
686+
for (i = 0; i < num_of_cmds; i++) {
687+
err = mmc_blk_ioctl_copy_to_user(&cmds[i], idata[i]);
688+
if (err)
689+
break;
690+
}
691+
692+
cmd_done:
693+
mmc_blk_put(md);
694+
cmd_err:
695+
for (i = 0; i < num_of_cmds; i++) {
696+
kfree(idata[i]->buf);
697+
kfree(idata[i]);
698+
}
699+
kfree(idata);
700+
return err;
701+
}
702+
621703
static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
622704
unsigned int cmd, unsigned long arg)
623705
{
624-
int ret = -EINVAL;
625-
if (cmd == MMC_IOC_CMD)
626-
ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
627-
return ret;
706+
/*
707+
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
708+
* whole block device, not on a partition. This prevents overspray
709+
* between sibling partitions.
710+
*/
711+
if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
712+
return -EPERM;
713+
714+
switch (cmd) {
715+
case MMC_IOC_CMD:
716+
return mmc_blk_ioctl_cmd(bdev,
717+
(struct mmc_ioc_cmd __user *)arg);
718+
case MMC_IOC_MULTI_CMD:
719+
return mmc_blk_ioctl_multi_cmd(bdev,
720+
(struct mmc_ioc_multi_cmd __user *)arg);
721+
default:
722+
return -EINVAL;
723+
}
628724
}
629725

630726
#ifdef CONFIG_COMPAT

include/uapi/linux/mmc/ioctl.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,30 @@ struct mmc_ioc_cmd {
4545
};
4646
#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr
4747

48-
#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
48+
/**
49+
* struct mmc_ioc_multi_cmd - multi command information
50+
* @num_of_cmds: Number of commands to send. Must be equal to or less than
51+
* MMC_IOC_MAX_CMDS.
52+
* @cmds: Array of commands with length equal to 'num_of_cmds'
53+
*/
54+
struct mmc_ioc_multi_cmd {
55+
__u64 num_of_cmds;
56+
struct mmc_ioc_cmd cmds[0];
57+
};
4958

59+
#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd)
60+
/*
61+
* MMC_IOC_MULTI_CMD: Used to send an array of MMC commands described by
62+
* the structure mmc_ioc_multi_cmd. The MMC driver will issue all
63+
* commands in array in sequence to card.
64+
*/
65+
#define MMC_IOC_MULTI_CMD _IOWR(MMC_BLOCK_MAJOR, 1, struct mmc_ioc_multi_cmd)
5066
/*
5167
* Since this ioctl is only meant to enhance (and not replace) normal access
5268
* to the mmc bus device, an upper data transfer limit of MMC_IOC_MAX_BYTES
5369
* is enforced per ioctl call. For larger data transfers, use the normal
5470
* block device operations.
5571
*/
5672
#define MMC_IOC_MAX_BYTES (512L * 256)
73+
#define MMC_IOC_MAX_CMDS 255
5774
#endif /* LINUX_MMC_IOCTL_H */

0 commit comments

Comments
 (0)