Re: [PATCH 7/8 v5] mmc: block: Convert RPMB to a character device

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, 2017-08-20 at 23:39 +0200, Linus Walleij wrote:
> The RPMB partition on the eMMC devices is a special area used
> for storing cryptographically safe information signed by a
> special secret key. To write and read records from this special
> area, authentication is needed.
> 
> The RPMB area is *only* and *exclusively* accessed using
> ioctl():s from userspace. It is not really a block device,
> as blocks cannot be read or written from the device, also
> the signed chunks that can be stored on the RPMB are actually
> 256 bytes, not 512 making a block device a real bad fit.
> 
> Currently the RPMB partition spawns a separate block device
> named /dev/mmcblkNrpmb for each device with an RPMB partition,
> including the creation of a block queue with its own kernel
> thread and all overhead associated with this. On the Ux500
> HREFv60 platform, for example, the two eMMCs means that two
> block queues with separate threads are created for no use
> whatsoever.
> 
> I have concluded that this block device design for RPMB is
> actually pretty wrong. The RPMB area should have been designed
> to be accessed from /dev/mmcblkN directly, using ioctl()s on
> the main block device. It is however way too late to change
> that, since userspace expects to open an RPMB device in
> /dev/mmcblkNrpmb and we cannot break userspace.
> 
> This patch tries to amend the situation using the following
> strategy:
> 
> - Stop creating a block device for the RPMB partition/area
> 
> - Instead create a custom, dynamic character device with
>   the same name.
> 
> - Make this new character device support exactly the same
>   set of ioctl()s as the old block device.
> 
> - Wrap the requests back to the same ioctl() handlers, but
>   issue them on the block queue of the main partition/area,
>   i.e. /dev/mmcblkN
> 
> We need to create a special "rpmb" bus type in order to get
> udev and/or busybox hot/coldplug to instantiate the device
> node properly.
> 
> Before the patch, this appears in 'ps aux':
> 
> 101 root       0:00 [mmcqd/2rpmb]
> 123 root       0:00 [mmcqd/3rpmb]
> 
> After applying the patch these surplus block queue threads
> are gone, but RPMB is as usable as ever using the userspace
> MMC tools, such as 'mmc rpmb read-counter'.
> 
> We get instead those dynamice devices in /dev:
> 
> brw-rw----    1 root     root      179,   0 Jan  1  2000 mmcblk0
> brw-rw----    1 root     root      179,   1 Jan  1  2000 mmcblk0p1
> brw-rw----    1 root     root      179,   2 Jan  1  2000 mmcblk0p2
> brw-rw----    1 root     root      179,   5 Jan  1  2000 mmcblk0p5
> brw-rw----    1 root     root      179,   8 Jan  1  2000 mmcblk2
> brw-rw----    1 root     root      179,  16 Jan  1  2000 mmcblk2boot0
> brw-rw----    1 root     root      179,  24 Jan  1  2000 mmcblk2boot1
> crw-rw----    1 root     root      248,   0 Jan  1  2000 mmcblk2rpmb
> brw-rw----    1 root     root      179,  32 Jan  1  2000 mmcblk3
> brw-rw----    1 root     root      179,  40 Jan  1  2000 mmcblk3boot0
> brw-rw----    1 root     root      179,  48 Jan  1  2000 mmcblk3boot1
> brw-rw----    1 root     root      179,  33 Jan  1  2000 mmcblk3p1
> crw-rw----    1 root     root      248,   1 Jan  1  2000 mmcblk3rpmb
> 
> Notice the (248,0) and (248,1) character devices for RPMB.
> 
> Cc: Tomas Winkler <tomas.winkler@xxxxxxxxx>
> Signed-off-by: Linus Walleij <linus.walleij@xxxxxxxxxx>
> ---
> ChangeLog v1 (RFC) -> v5:
> - Rebase.
> - Drop discussion comments, let's go for this unless someone
>   has a better idea.
> - Rename rpmb_devt and rpmb_bus_type to mmc_rpmb_devt and
>   mmc_rpmb_bus_type as requested by Tomas.
> - Handle multiple RPMB partitions as requested by Tomas.
> - Renumber v5 to keep together with the rest of the series.
> ---
>  drivers/mmc/core/block.c | 286 +++++++++++++++++++++++++++++++++++++++++++----
>  drivers/mmc/core/queue.h |   2 +
>  2 files changed, 266 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c
> index 502068b155b9..27e1cf07a7a2 100644
> --- a/drivers/mmc/core/block.c
> +++ b/drivers/mmc/core/block.c
> @@ -28,6 +28,7 @@
>  #include <linux/hdreg.h>
>  #include <linux/kdev_t.h>
>  #include <linux/blkdev.h>
> +#include <linux/cdev.h>
>  #include <linux/mutex.h>
>  #include <linux/scatterlist.h>
>  #include <linux/string_helpers.h>
> @@ -86,6 +87,7 @@ static int max_devices;
>  #define MAX_DEVICES 256
>  
>  static DEFINE_IDA(mmc_blk_ida);
> +static DEFINE_IDA(mmc_rpmb_ida);
>  
>  /*
>   * There is one mmc_blk_data per slot.
> @@ -96,6 +98,7 @@ struct mmc_blk_data {
>  	struct gendisk	*disk;
>  	struct mmc_queue queue;
>  	struct list_head part;
> +	struct list_head rpmbs;
>  
>  	unsigned int	flags;
>  #define MMC_BLK_CMD23	(1 << 0)	/* Can do SET_BLOCK_COUNT for multiblock */
> @@ -121,6 +124,32 @@ struct mmc_blk_data {
>  	int	area_type;
>  };
>  
> +/* Device type for RPMB character devices */
> +static dev_t mmc_rpmb_devt;
> +
> +/* Bus type for RPMB character devices */
> +static struct bus_type mmc_rpmb_bus_type = {
> +	.name = "rpmb",
Also need renaming to 'mmc_rpmb', this goes to ABI /sys/bus/mmc_rpmb/ 
I'm not CCed to whole series so not sure you've updated also
Documentation/ABI/testing/sysfs-bus-* 

> +};
> +
> +/**
> + * struct mmc_rpmb_data - special RPMB device type for these areas
> + * @dev: the device for the RPMB area
> + * @chrdev: character device for the RPMB area
> + * @id: unique device ID number
> + * @part_index: partition index (0 on first)
> + * @md: parent MMC block device
> + * @node: list item, so we can put this device on a list
> + */
> +struct mmc_rpmb_data {
> +	struct device dev;
> +	struct cdev chrdev;
> +	int id;
> +	unsigned int part_index;
> +	struct mmc_blk_data *md;
> +	struct list_head node;
> +};
> +
>  static DEFINE_MUTEX(open_lock);
>  
>  module_param(perdev_minors, int, 0444);
> @@ -299,6 +328,7 @@ struct mmc_blk_ioc_data {
>  	struct mmc_ioc_cmd ic;
>  	unsigned char *buf;
>  	u64 buf_bytes;
> +	struct mmc_rpmb_data *rpmb;
>  };
>  
>  static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
> @@ -437,14 +467,25 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
>  	struct mmc_request mrq = {};
>  	struct scatterlist sg;
>  	int err;
> -	bool is_rpmb = false;
> +	unsigned int target_part;
>  	u32 status = 0;
>  
>  	if (!card || !md || !idata)
>  		return -EINVAL;
>  
> -	if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
> -		is_rpmb = true;
> +	/*
> +	 * The RPMB accesses comes in from the character device, so we
> +	 * need to target these explicitly. Else we just target the
> +	 * partition type for the block device the ioctl() was issued
> +	 * on.
> +	 */
> +	if (idata->rpmb) {
> +		/* Support multiple RPMB partitions */
> +		target_part = idata->rpmb->part_index;
> +		target_part |= EXT_CSD_PART_CONFIG_ACC_RPMB;
> +	} else {
> +		target_part = md->part_type;
> +	}
>  
>  	cmd.opcode = idata->ic.opcode;
>  	cmd.arg = idata->ic.arg;
> @@ -488,7 +529,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
>  
>  	mrq.cmd = &cmd;
>  
> -	err = mmc_blk_part_switch(card, md->part_type);
> +	err = mmc_blk_part_switch(card, target_part);
>  	if (err)
>  		return err;
>  
> @@ -498,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
>  			return err;
>  	}
>  
> -	if (is_rpmb) {
> +	if (idata->rpmb) {
>  		err = mmc_set_blockcount(card, data.blocks,
>  			idata->ic.write_flag & (1 << 31));
>  		if (err)
> @@ -538,7 +579,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
>  
>  	memcpy(&(idata->ic.response), cmd.resp, sizeof(cmd.resp));
>  
> -	if (is_rpmb) {
> +	if (idata->rpmb) {
>  		/*
>  		 * Ensure RPMB command has completed by polling CMD13
>  		 * "Send Status".
> @@ -554,7 +595,8 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
>  }
>  
>  static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
> -			     struct mmc_ioc_cmd __user *ic_ptr)
> +			     struct mmc_ioc_cmd __user *ic_ptr,
> +			     struct mmc_rpmb_data *rpmb)
>  {
>  	struct mmc_blk_ioc_data *idata;
>  	struct mmc_blk_ioc_data *idatas[1];
> @@ -566,6 +608,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
>  	idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
>  	if (IS_ERR(idata))
>  		return PTR_ERR(idata);
> +	/* This will be NULL on non-RPMB ioctl():s */
> +	idata->rpmb = rpmb;
>  
>  	card = md->queue.card;
>  	if (IS_ERR(card)) {
> @@ -581,7 +625,10 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
>  		idata->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
>  		__GFP_RECLAIM);
>  	idatas[0] = idata;
> -	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
> +	if (rpmb)
> +		req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL_RPMB;
> +	else
> +		req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;

maybe neater to use = ?: here, it's used in this module often 
 
>  	req_to_mmc_queue_req(req)->drv_op_data = idatas;
>  	req_to_mmc_queue_req(req)->ioc_count = 1;
>  	blk_execute_rq(mq->queue, NULL, req, 0);
> @@ -596,7 +643,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_blk_data *md,
>  }
>  
>  static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
> -				   struct mmc_ioc_multi_cmd __user *user)
> +				   struct mmc_ioc_multi_cmd __user *user,
> +				   struct mmc_rpmb_data *rpmb)
>  {
>  	struct mmc_blk_ioc_data **idata = NULL;
>  	struct mmc_ioc_cmd __user *cmds = user->cmds;
> @@ -627,6 +675,8 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
>  			num_of_cmds = i;
>  			goto cmd_err;
>  		}
> +		/* This will be NULL on non-RPMB ioctl():s */
> +		idata[i]->rpmb = rpmb;
>  	}
>  
>  	card = md->queue.card;
> @@ -643,7 +693,10 @@ static int mmc_blk_ioctl_multi_cmd(struct mmc_blk_data *md,
>  	req = blk_get_request(mq->queue,
>  		idata[0]->ic.write_flag ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
>  		__GFP_RECLAIM);
> -	req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
> +	if (rpmb)
> +		req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL_RPMB;
> +	else
> +		req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_IOCTL;
>  	req_to_mmc_queue_req(req)->drv_op_data = idata;
>  	req_to_mmc_queue_req(req)->ioc_count = num_of_cmds;
>  	blk_execute_rq(mq->queue, NULL, req, 0);
> @@ -691,7 +744,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
>  		if (!md)
>  			return -EINVAL;
>  		ret = mmc_blk_ioctl_cmd(md,
> -					(struct mmc_ioc_cmd __user *)arg);
> +					(struct mmc_ioc_cmd __user *)arg,
> +					NULL);
>  		mmc_blk_put(md);
>  		return ret;
>  	case MMC_IOC_MULTI_CMD:
> @@ -702,7 +756,8 @@ static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
>  		if (!md)
>  			return -EINVAL;
>  		ret = mmc_blk_ioctl_multi_cmd(md,
> -					(struct mmc_ioc_multi_cmd __user *)arg);
> +					(struct mmc_ioc_multi_cmd __user *)arg,
> +					NULL);
>  		mmc_blk_put(md);
>  		return ret;
>  	default:
> @@ -1174,17 +1229,19 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
>  	struct mmc_queue_req *mq_rq;
>  	struct mmc_card *card = mq->card;
>  	struct mmc_blk_data *md = mq->blkdata;
> -	struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
>  	struct mmc_blk_ioc_data **idata;
> +	bool rpmb_ioctl;
>  	u8 **ext_csd;
>  	u32 status;
>  	int ret;
>  	int i;
>  
>  	mq_rq = req_to_mmc_queue_req(req);
> +	rpmb_ioctl = (mq_rq->drv_op == MMC_DRV_OP_IOCTL_RPMB);
>  
>  	switch (mq_rq->drv_op) {
>  	case MMC_DRV_OP_IOCTL:
> +	case MMC_DRV_OP_IOCTL_RPMB:
>  		idata = mq_rq->drv_op_data;
>  		for (i = 0, ret = 0; i < mq_rq->ioc_count; i++) {
>  			ret = __mmc_blk_ioctl_cmd(card, md, idata[i]);
> @@ -1192,8 +1249,8 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
>  				break;
>  		}
>  		/* Always switch back to main area after RPMB access */
> -		if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
> -			mmc_blk_part_switch(card, main_md->part_type);
> +		if (rpmb_ioctl)
> +			mmc_blk_part_switch(card, 0);
>  		break;
>  	case MMC_DRV_OP_BOOT_WP:
>  		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
> @@ -2022,6 +2079,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
>  
>  	spin_lock_init(&md->lock);
>  	INIT_LIST_HEAD(&md->part);
> +	INIT_LIST_HEAD(&md->rpmbs);
>  	md->usage = 1;
>  
>  	ret = mmc_init_queue(&md->queue, card, &md->lock, subname);
> @@ -2140,6 +2198,153 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
>  	return 0;
>  }
>  
> +/**
> + * rpmb_ioctl() - ioctl handler for the RPMB chardev
> + * @filp: the character device file
> + * @cmd: the ioctl() command
> + * @arg: the argument from userspace
> + *
> + * This will essentially just redirect the ioctl()s coming in over to
> + * the main block device spawning the RPMB character device.
> + */
> +static long rpmb_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
will keep the mmc_ prefix also here
> +{
> +	struct mmc_rpmb_data *rpmb = filp->private_data;
> +	int ret;
> +
> +	switch (cmd) {
> +	case MMC_IOC_CMD:
> +		ret = mmc_blk_ioctl_cmd(rpmb->md,
> +					(struct mmc_ioc_cmd __user *)arg,
> +					rpmb);
> +		break;
> +	case MMC_IOC_MULTI_CMD:
> +		ret = mmc_blk_ioctl_multi_cmd(rpmb->md,
> +					(struct mmc_ioc_multi_cmd __user *)arg,
> +					rpmb);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_COMPAT
> +static long rpmb_ioctl_compat(struct file *filp, unsigned int cmd,
> +			      unsigned long arg)
same here, the mmc_ prefix
> +{
> +	return rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
> +}
> +#endif
> +
> +static int rpmb_chrdev_open(struct inode *inode, struct file *filp)
> +{
prefix
> +	struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
> +						  struct mmc_rpmb_data, chrdev);
> +
> +	get_device(&rpmb->dev);
> +	filp->private_data = rpmb;
> +	mutex_lock(&open_lock);
> +	rpmb->md->usage++;
> +	mutex_unlock(&open_lock);
> +
> +	return nonseekable_open(inode, filp);
> +}
> +
> +static int rpmb_chrdev_release(struct inode *inode, struct file *filp)
> +{
> +	struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
> +						  struct mmc_rpmb_data, chrdev);
> +
> +	put_device(&rpmb->dev);
> +	mutex_lock(&open_lock);
> +	rpmb->md->usage--;
> +	mutex_unlock(&open_lock);
> +
> +	return 0;
> +}
> +
> +static const struct file_operations rpmb_fileops = {
> +	.release = rpmb_chrdev_release,
> +	.open = rpmb_chrdev_open,
> +	.owner = THIS_MODULE,
> +	.llseek = no_llseek,
> +	.unlocked_ioctl = rpmb_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl = rpmb_ioctl_compat,
> +#endif
> +};
> +
> +
> +static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,
> +				   struct mmc_blk_data *md,
> +				   unsigned int part_index,
> +				   sector_t size,
> +				   const char *subname)
> +{
> +	int devidx, ret;
> +	char rpmb_name[DISK_NAME_LEN];
> +	char cap_str[10];
> +	struct mmc_rpmb_data *rpmb;
> +
> +	/* This creates the minor number for the RPMB char device */
> +	devidx = ida_simple_get(&mmc_rpmb_ida, 0, max_devices, GFP_KERNEL);
> +	if (devidx < 0)
> +		return devidx;
> +
> +	rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL);
> +	if (!rpmb)
> +		return -ENOMEM;
> +
> +	snprintf(rpmb_name, sizeof(rpmb_name),
> +		 "mmcblk%u%s", card->host->index, subname ? subname : "");
> +
> +	rpmb->id = devidx;
> +	rpmb->part_index = part_index;
> +	rpmb->dev.init_name = rpmb_name;
> +	rpmb->dev.bus = &mmc_rpmb_bus_type;
> +	rpmb->dev.devt = MKDEV(MAJOR(mmc_rpmb_devt), rpmb->id);
> +	rpmb->dev.parent = &card->dev;
> +	device_initialize(&rpmb->dev);
> +	dev_set_drvdata(&rpmb->dev, rpmb);
> +	rpmb->md = md;
> +
> +	cdev_init(&rpmb->chrdev, &rpmb_fileops);
> +	rpmb->chrdev.owner = THIS_MODULE;
> +	ret = cdev_device_add(&rpmb->chrdev, &rpmb->dev);
> +	if (ret) {
> +		pr_err("%s: could not add character device\n", rpmb_name);
> +		goto out_remove_ida;
> +	}
> +
> +	list_add(&rpmb->node, &md->rpmbs);
> +
> +	string_get_size((u64)size, 512, STRING_UNITS_2,
> +			cap_str, sizeof(cap_str));
> +
> +	pr_info("%s: %s %s partition %u %s, chardev (%d:%d)\n",
> +		rpmb_name, mmc_card_id(card),
> +		mmc_card_name(card), EXT_CSD_PART_CONFIG_ACC_RPMB, cap_str,
> +		MAJOR(mmc_rpmb_devt), rpmb->id);
> +
> +	return 0;
> +
> +out_remove_ida:
> +	ida_simple_remove(&mmc_rpmb_ida, rpmb->id);
> +	kfree(rpmb);
> +	return ret;
> +}
> +
> +static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb)
> +{
> +	cdev_device_del(&rpmb->chrdev, &rpmb->dev);
> +	device_del(&rpmb->dev);
> +	ida_simple_remove(&mmc_rpmb_ida, rpmb->id);
> +	kfree(rpmb);
> +}
> +
>  /* MMC Physical partitions consist of two boot partitions and
>   * up to four general purpose partitions.
>   * For each partition enabled in EXT_CSD a block device will be allocatedi
> @@ -2148,13 +2353,26 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
>  
>  static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
>  {
> -	int idx, ret = 0;
> +	int idx, ret;
>  
>  	if (!mmc_card_mmc(card))
>  		return 0;
>  
>  	for (idx = 0; idx < card->nr_parts; idx++) {
> -		if (card->part[idx].size) {
> +		if (card->part[idx].area_type & MMC_BLK_DATA_AREA_RPMB) {
> +			/*
> +			 * RPMB partitions does not provide block access, they
> +			 * are only accessed using ioctl():s. Thus create
> +			 * special RPMB block devices that do not have a
> +			 * backing block queue for these.
> +			 */
> +			ret = mmc_blk_alloc_rpmb_part(card, md,
> +				card->part[idx].part_cfg,
> +				card->part[idx].size >> 9,
> +				card->part[idx].name);
> +			if (ret)
> +				return ret;
> +		} else if (card->part[idx].size) {
>  			ret = mmc_blk_alloc_part(card, md,
>  				card->part[idx].part_cfg,
>  				card->part[idx].size >> 9,
> @@ -2166,7 +2384,7 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
>  		}
>  	}
>  
> -	return ret;
> +	return 0;
>  }
>  
>  static void mmc_blk_remove_req(struct mmc_blk_data *md)
> @@ -2203,7 +2421,15 @@ static void mmc_blk_remove_parts(struct mmc_card *card,
>  {
>  	struct list_head *pos, *q;
>  	struct mmc_blk_data *part_md;
> +	struct mmc_rpmb_data *rpmb;
>  
> +	/* Remove RPMB partitions */
> +	list_for_each_safe(pos, q, &md->rpmbs) {
> +		rpmb = list_entry(pos, struct mmc_rpmb_data, node);
> +		list_del(pos);
> +		mmc_blk_remove_rpmb_part(rpmb);
> +	}
> +	/* Remove block partitions */
>  	list_for_each_safe(pos, q, &md->part) {
>  		part_md = list_entry(pos, struct mmc_blk_data, part);
>  		list_del(pos);
> @@ -2522,6 +2748,17 @@ static int __init mmc_blk_init(void)
>  {
>  	int res;
>  
> +	res  = bus_register(&mmc_rpmb_bus_type);
> +	if (res < 0) {
> +		pr_err("mmcblk: could not register RPMB bus type\n");
> +		return res;
> +	}
> +	res = alloc_chrdev_region(&mmc_rpmb_devt, 0, MAX_DEVICES, "rpmb");
> +	if (res < 0) {
> +		pr_err("mmcblk: failed to allocate rpmb chrdev region\n");
> +		goto out_bus_unreg;
> +	}
> +
>  	if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
>  		pr_info("mmcblk: using %d minors per device\n", perdev_minors);
>  
> @@ -2529,16 +2766,20 @@ static int __init mmc_blk_init(void)
>  
>  	res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
>  	if (res)
> -		goto out;
> +		goto out_chrdev_unreg;
>  
>  	res = mmc_register_driver(&mmc_driver);
>  	if (res)
> -		goto out2;
> +		goto out_blkdev_unreg;
>  
>  	return 0;
> - out2:
> +
> +out_blkdev_unreg:
>  	unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
> - out:
> +out_chrdev_unreg:
> +	unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
> +out_bus_unreg:
> +	bus_unregister(&mmc_rpmb_bus_type);
>  	return res;
>  }
>  
> @@ -2546,6 +2787,7 @@ static void __exit mmc_blk_exit(void)
>  {
>  	mmc_unregister_driver(&mmc_driver);
>  	unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
> +	unregister_chrdev_region(mmc_rpmb_devt, MAX_DEVICES);
>  }
>  
>  module_init(mmc_blk_init);
> diff --git a/drivers/mmc/core/queue.h b/drivers/mmc/core/queue.h
> index 04fc89360a7a..a2b6a9fcab01 100644
> --- a/drivers/mmc/core/queue.h
> +++ b/drivers/mmc/core/queue.h
> @@ -35,12 +35,14 @@ struct mmc_blk_request {
>  /**
>   * enum mmc_drv_op - enumerates the operations in the mmc_queue_req
>   * @MMC_DRV_OP_IOCTL: ioctl operation
> + * @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation
>   * @MMC_DRV_OP_BOOT_WP: write protect boot partitions
>   * @MMC_DRV_OP_GET_CARD_STATUS: get card status
>   * @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card
>   */
>  enum mmc_drv_op {
>  	MMC_DRV_OP_IOCTL,
> +	MMC_DRV_OP_IOCTL_RPMB,
>  	MMC_DRV_OP_BOOT_WP,
>  	MMC_DRV_OP_GET_CARD_STATUS,
>  	MMC_DRV_OP_GET_EXT_CSD,��.n��������+%������w��{.n�����{��i��)��jg��������ݢj����G�������j:+v���w�m������w�������h�����٥




[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux