mmc: block: Fix missing blk_put_request()
[linux-2.6-microblaze.git] / drivers / mmc / core / block.c
index 2ad7b5c..f609398 100644 (file)
@@ -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 = "mmc_rpmb",
+};
+
+/**
+ * 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);
@@ -207,6 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
        req_to_mmc_queue_req(req)->drv_op = MMC_DRV_OP_BOOT_WP;
        blk_execute_rq(mq->queue, NULL, req, 0);
        ret = req_to_mmc_queue_req(req)->drv_op_result;
+       blk_put_request(req);
 
        if (!ret) {
                pr_info("%s: Locking boot partition ro until next power on\n",
@@ -299,6 +329,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 +468,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 +530,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 +540,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 +580,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 +596,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 +609,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 +626,8 @@ 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;
+       req_to_mmc_queue_req(req)->drv_op =
+               rpmb ? MMC_DRV_OP_IOCTL_RPMB : MMC_DRV_OP_IOCTL;
        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 +642,8 @@ cmd_done:
 }
 
 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 +674,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 +692,8 @@ 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;
+       req_to_mmc_queue_req(req)->drv_op =
+               rpmb ? MMC_DRV_OP_IOCTL_RPMB : 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 +741,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 +753,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:
@@ -1152,18 +1204,6 @@ static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
        md->reset_done &= ~type;
 }
 
-int mmc_access_rpmb(struct mmc_queue *mq)
-{
-       struct mmc_blk_data *md = mq->blkdata;
-       /*
-        * If this is a RPMB partition access, return ture
-        */
-       if (md && md->part_type == EXT_CSD_PART_CONFIG_ACC_RPMB)
-               return true;
-
-       return false;
-}
-
 /*
  * The non-block commands come back from the block layer after it queued it and
  * processed it with all other requests and then they get issued in this
@@ -1174,17 +1214,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 +1234,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,
@@ -1534,25 +1576,27 @@ static enum mmc_blk_status mmc_blk_err_check(struct mmc_card *card,
 }
 
 static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
-                             int disable_multi, bool *do_rel_wr,
-                             bool *do_data_tag)
+                             int disable_multi, bool *do_rel_wr_p,
+                             bool *do_data_tag_p)
 {
        struct mmc_blk_data *md = mq->blkdata;
        struct mmc_card *card = md->queue.card;
        struct mmc_blk_request *brq = &mqrq->brq;
        struct request *req = mmc_queue_req_to_req(mqrq);
+       bool do_rel_wr, do_data_tag;
 
        /*
         * Reliable writes are used to implement Forced Unit Access and
         * are supported only on MMCs.
         */
-       *do_rel_wr = (req->cmd_flags & REQ_FUA) &&
-                    rq_data_dir(req) == WRITE &&
-                    (md->flags & MMC_BLK_REL_WR);
+       do_rel_wr = (req->cmd_flags & REQ_FUA) &&
+                   rq_data_dir(req) == WRITE &&
+                   (md->flags & MMC_BLK_REL_WR);
 
        memset(brq, 0, sizeof(struct mmc_blk_request));
 
        brq->mrq.data = &brq->data;
+       brq->mrq.tag = req->tag;
 
        brq->stop.opcode = MMC_STOP_TRANSMISSION;
        brq->stop.arg = 0;
@@ -1567,6 +1611,14 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
 
        brq->data.blksz = 512;
        brq->data.blocks = blk_rq_sectors(req);
+       brq->data.blk_addr = blk_rq_pos(req);
+
+       /*
+        * The command queue supports 2 priorities: "high" (1) and "simple" (0).
+        * The eMMC will give "high" priority tasks priority over "simple"
+        * priority tasks. Here we always set "simple" priority by not setting
+        * MMC_DATA_PRIO.
+        */
 
        /*
         * The block layer doesn't support all sector count
@@ -1596,18 +1648,23 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
                                                brq->data.blocks);
        }
 
-       if (*do_rel_wr)
+       if (do_rel_wr) {
                mmc_apply_rel_rw(brq, card, req);
+               brq->data.flags |= MMC_DATA_REL_WR;
+       }
 
        /*
         * Data tag is used only during writing meta data to speed
         * up write and any subsequent read of this meta data
         */
-       *do_data_tag = card->ext_csd.data_tag_unit_size &&
-                      (req->cmd_flags & REQ_META) &&
-                      (rq_data_dir(req) == WRITE) &&
-                      ((brq->data.blocks * brq->data.blksz) >=
-                       card->ext_csd.data_tag_unit_size);
+       do_data_tag = card->ext_csd.data_tag_unit_size &&
+                     (req->cmd_flags & REQ_META) &&
+                     (rq_data_dir(req) == WRITE) &&
+                     ((brq->data.blocks * brq->data.blksz) >=
+                      card->ext_csd.data_tag_unit_size);
+
+       if (do_data_tag)
+               brq->data.flags |= MMC_DATA_DAT_TAG;
 
        mmc_set_data_timeout(&brq->data, card);
 
@@ -1634,6 +1691,12 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
        }
 
        mqrq->areq.mrq = &brq->mrq;
+
+       if (do_rel_wr_p)
+               *do_rel_wr_p = do_rel_wr;
+
+       if (do_data_tag_p)
+               *do_data_tag_p = do_data_tag;
 }
 
 static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
@@ -1948,7 +2011,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
        if (req && !mq->qcnt)
                /* claim host only for the first request */
-               mmc_get_card(card);
+               mmc_get_card(card, NULL);
 
        ret = mmc_blk_part_switch(card, md->part_type);
        if (ret) {
@@ -2011,7 +2074,7 @@ void mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
 out:
        if (!mq->qcnt)
-               mmc_put_card(card);
+               mmc_put_card(card, NULL);
 }
 
 static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -2068,6 +2131,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);
@@ -2186,6 +2250,158 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
        return 0;
 }
 
+/**
+ * mmc_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 mmc_rpmb_ioctl(struct file *filp, unsigned int cmd,
+                          unsigned long arg)
+{
+       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 mmc_rpmb_ioctl_compat(struct file *filp, unsigned int cmd,
+                             unsigned long arg)
+{
+       return mmc_rpmb_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
+static int mmc_rpmb_chrdev_open(struct inode *inode, struct file *filp)
+{
+       struct mmc_rpmb_data *rpmb = container_of(inode->i_cdev,
+                                                 struct mmc_rpmb_data, chrdev);
+
+       get_device(&rpmb->dev);
+       filp->private_data = rpmb;
+       mmc_blk_get(rpmb->md->disk);
+
+       return nonseekable_open(inode, filp);
+}
+
+static int mmc_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);
+       mmc_blk_put(rpmb->md);
+
+       return 0;
+}
+
+static const struct file_operations mmc_rpmb_fileops = {
+       .release = mmc_rpmb_chrdev_release,
+       .open = mmc_rpmb_chrdev_open,
+       .owner = THIS_MODULE,
+       .llseek = no_llseek,
+       .unlocked_ioctl = mmc_rpmb_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = mmc_rpmb_ioctl_compat,
+#endif
+};
+
+static void mmc_blk_rpmb_device_release(struct device *dev)
+{
+       struct mmc_rpmb_data *rpmb = dev_get_drvdata(dev);
+
+       ida_simple_remove(&mmc_rpmb_ida, rpmb->id);
+       kfree(rpmb);
+}
+
+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) {
+               ida_simple_remove(&mmc_rpmb_ida, devidx);
+               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;
+       rpmb->dev.release = mmc_blk_rpmb_device_release;
+       device_initialize(&rpmb->dev);
+       dev_set_drvdata(&rpmb->dev, rpmb);
+       rpmb->md = md;
+
+       cdev_init(&rpmb->chrdev, &mmc_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_put_device;
+       }
+
+       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_put_device:
+       put_device(&rpmb->dev);
+       return ret;
+}
+
+static void mmc_blk_remove_rpmb_part(struct mmc_rpmb_data *rpmb)
+
+{
+       cdev_device_del(&rpmb->chrdev, &rpmb->dev);
+       put_device(&rpmb->dev);
+}
+
 /* 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
@@ -2194,13 +2410,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,
@@ -2212,7 +2441,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)
@@ -2249,7 +2478,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);
@@ -2321,6 +2558,7 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
                *val = ret;
                ret = 0;
        }
+       blk_put_request(req);
 
        return ret;
 }
@@ -2351,6 +2589,7 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
        req_to_mmc_queue_req(req)->drv_op_data = &ext_csd;
        blk_execute_rq(mq->queue, NULL, req, 0);
        err = req_to_mmc_queue_req(req)->drv_op_result;
+       blk_put_request(req);
        if (err) {
                pr_err("FAILED %d\n", err);
                goto out_free;
@@ -2568,6 +2807,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);
 
@@ -2575,16 +2825,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;
 }
 
@@ -2592,6 +2846,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);