]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Jan 2020 12:11:12 +0000 (13:11 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Jan 2020 12:11:12 +0000 (13:11 +0100)
added patches:
mmc-block-convert-rpmb-to-a-character-device.patch
mmc-block-delete-mmc_access_rpmb.patch
mmc-block-fix-bug-when-removing-rpmb-chardev.patch
mmc-block-propagate-correct-returned-value-in-mmc_rpmb_ioctl.patch
mmc-core-prevent-bus-reference-leak-in-mmc_blk_init.patch
pci-switchtec-read-all-64-bits-of-part_event_bitmap.patch

queue-4.14/mmc-block-convert-rpmb-to-a-character-device.patch [new file with mode: 0644]
queue-4.14/mmc-block-delete-mmc_access_rpmb.patch [new file with mode: 0644]
queue-4.14/mmc-block-fix-bug-when-removing-rpmb-chardev.patch [new file with mode: 0644]
queue-4.14/mmc-block-propagate-correct-returned-value-in-mmc_rpmb_ioctl.patch [new file with mode: 0644]
queue-4.14/mmc-core-prevent-bus-reference-leak-in-mmc_blk_init.patch [new file with mode: 0644]
queue-4.14/pci-switchtec-read-all-64-bits-of-part_event_bitmap.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/mmc-block-convert-rpmb-to-a-character-device.patch b/queue-4.14/mmc-block-convert-rpmb-to-a-character-device.patch
new file mode 100644 (file)
index 0000000..846a09d
--- /dev/null
@@ -0,0 +1,610 @@
+From 97548575bef38abd06690a5a6f6816200c7e77f7 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 20 Sep 2017 10:02:00 +0200
+Subject: mmc: block: Convert RPMB to a character device
+
+From: Linus Walleij <linus.walleij@linaro.org>
+
+commit 97548575bef38abd06690a5a6f6816200c7e77f7 upstream.
+
+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@intel.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/core/block.c |  283 +++++++++++++++++++++++++++++++++++++++++++----
+ drivers/mmc/core/queue.h |    2 
+ 2 files changed, 263 insertions(+), 22 deletions(-)
+
+--- 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>
+@@ -87,6 +88,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.
+@@ -97,6 +99,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 */
+@@ -126,6 +129,32 @@ struct mmc_blk_data {
+       struct dentry *ext_csd_dentry;
+ };
++/* 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);
+@@ -309,6 +338,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(
+@@ -447,14 +477,25 @@ static int __mmc_blk_ioctl_cmd(struct mm
+       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;
+@@ -498,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mm
+       mrq.cmd = &cmd;
+-      err = mmc_blk_part_switch(card, md->part_type);
++      err = mmc_blk_part_switch(card, target_part);
+       if (err)
+               return err;
+@@ -508,7 +549,7 @@ static int __mmc_blk_ioctl_cmd(struct mm
+                       return err;
+       }
+-      if (is_rpmb) {
++      if (idata->rpmb) {
+               err = mmc_set_blockcount(card, data.blocks,
+                       idata->ic.write_flag & (1 << 31));
+               if (err)
+@@ -566,7 +607,7 @@ static int __mmc_blk_ioctl_cmd(struct mm
+       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".
+@@ -582,7 +623,8 @@ static int __mmc_blk_ioctl_cmd(struct mm
+ }
+ 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];
+@@ -594,6 +636,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_
+       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)) {
+@@ -613,7 +657,8 @@ static int mmc_blk_ioctl_cmd(struct mmc_
+               goto cmd_done;
+       }
+       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);
+@@ -628,7 +673,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;
+@@ -659,6 +705,8 @@ static int mmc_blk_ioctl_multi_cmd(struc
+                       num_of_cmds = i;
+                       goto cmd_err;
+               }
++              /* This will be NULL on non-RPMB ioctl():s */
++              idata[i]->rpmb = rpmb;
+       }
+       card = md->queue.card;
+@@ -679,7 +727,8 @@ static int mmc_blk_ioctl_multi_cmd(struc
+               err = PTR_ERR(req);
+               goto cmd_err;
+       }
+-      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);
+@@ -727,7 +776,8 @@ static int mmc_blk_ioctl(struct block_de
+               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:
+@@ -738,7 +788,8 @@ static int mmc_blk_ioctl(struct block_de
+               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:
+@@ -1210,17 +1261,19 @@ static void mmc_blk_issue_drv_op(struct
+       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]);
+@@ -1228,8 +1281,8 @@ static void mmc_blk_issue_drv_op(struct
+                               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,
+@@ -2114,6 +2167,7 @@ static struct mmc_blk_data *mmc_blk_allo
+       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);
+@@ -2232,6 +2286,154 @@ static int mmc_blk_alloc_part(struct mmc
+       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;
++      mutex_lock(&open_lock);
++      rpmb->md->usage++;
++      mutex_unlock(&open_lock);
++
++      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);
++      mutex_lock(&open_lock);
++      rpmb->md->usage--;
++      mutex_unlock(&open_lock);
++
++      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 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, &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_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
+@@ -2240,13 +2442,26 @@ static int mmc_blk_alloc_part(struct mmc
+ 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,
+@@ -2258,7 +2473,7 @@ static int mmc_blk_alloc_parts(struct mm
+               }
+       }
+-      return ret;
++      return 0;
+ }
+ static void mmc_blk_remove_req(struct mmc_blk_data *md)
+@@ -2295,7 +2510,15 @@ static void mmc_blk_remove_parts(struct
+ {
+       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);
+@@ -2649,6 +2872,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);
+@@ -2656,16 +2890,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;
+ }
+@@ -2673,6 +2911,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);
+--- a/drivers/mmc/core/queue.h
++++ b/drivers/mmc/core/queue.h
+@@ -36,12 +36,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,
diff --git a/queue-4.14/mmc-block-delete-mmc_access_rpmb.patch b/queue-4.14/mmc-block-delete-mmc_access_rpmb.patch
new file mode 100644 (file)
index 0000000..036e3cd
--- /dev/null
@@ -0,0 +1,74 @@
+From 14f4ca7e4d2825f9f71e22905ae177b899959f1d Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 20 Sep 2017 10:02:01 +0200
+Subject: mmc: block: Delete mmc_access_rpmb()
+
+From: Linus Walleij <linus.walleij@linaro.org>
+
+commit 14f4ca7e4d2825f9f71e22905ae177b899959f1d upstream.
+
+This function is used by the block layer queue to bail out of
+requests if the current request is towards an RPMB
+"block device".
+
+This was done to avoid boot time scanning of this "block
+device" which was never really a block device, thus duct-taping
+over the fact that it was badly engineered.
+
+This problem is now gone as we removed the offending RPMB block
+device in another patch and replaced it with a character
+device.
+
+Cc: Tomas Winkler <tomas.winkler@intel.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/core/block.c |   12 ------------
+ drivers/mmc/core/queue.c |    2 +-
+ drivers/mmc/core/queue.h |    2 --
+ 3 files changed, 1 insertion(+), 15 deletions(-)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -1239,18 +1239,6 @@ static inline void mmc_blk_reset_success
+       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
+--- a/drivers/mmc/core/queue.c
++++ b/drivers/mmc/core/queue.c
+@@ -30,7 +30,7 @@ static int mmc_prep_request(struct reque
+ {
+       struct mmc_queue *mq = q->queuedata;
+-      if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
++      if (mq && mmc_card_removed(mq->card))
+               return BLKPREP_KILL;
+       req->rq_flags |= RQF_DONTPREP;
+--- a/drivers/mmc/core/queue.h
++++ b/drivers/mmc/core/queue.h
+@@ -84,6 +84,4 @@ extern void mmc_queue_resume(struct mmc_
+ extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
+                                    struct mmc_queue_req *);
+-extern int mmc_access_rpmb(struct mmc_queue *);
+-
+ #endif
diff --git a/queue-4.14/mmc-block-fix-bug-when-removing-rpmb-chardev.patch b/queue-4.14/mmc-block-fix-bug-when-removing-rpmb-chardev.patch
new file mode 100644 (file)
index 0000000..309f088
--- /dev/null
@@ -0,0 +1,143 @@
+From 1c87f73578497a6c3cc77bcbfd2e5bf15fe753c7 Mon Sep 17 00:00:00 2001
+From: Linus Walleij <linus.walleij@linaro.org>
+Date: Wed, 4 Oct 2017 11:10:07 +0200
+Subject: mmc: block: Fix bug when removing RPMB chardev
+
+From: Linus Walleij <linus.walleij@linaro.org>
+
+commit 1c87f73578497a6c3cc77bcbfd2e5bf15fe753c7 upstream.
+
+I forgot to account for the fact that the device core holds a
+reference to a device added with device_initialize() that need
+to be released with a corresponding put_device() to reach a 0
+refcount at the end of the lifecycle.
+
+This led to a NULL pointer reference when freeing the device
+when e.g. unbidning the host device in sysfs.
+
+Fix this and use the device .release() callback to free the
+IDA and free:ing the memory used by the RPMB device.
+
+Before this patch:
+
+/sys/bus/amba/drivers/mmci-pl18x$ echo 80114000.sdi4_per2 > unbind
+[   29.797332] mmc3: card 0001 removed
+[   29.810791] Unable to handle kernel NULL pointer dereference at
+               virtual address 00000050
+[   29.818878] pgd = de70c000
+[   29.821624] [00000050] *pgd=1e70a831, *pte=00000000, *ppte=00000000
+[   29.827911] Internal error: Oops: 17 [#1] PREEMPT SMP ARM
+[   29.833282] Modules linked in:
+[   29.836334] CPU: 1 PID: 154 Comm: sh Not tainted
+               4.14.0-rc3-00039-g83318e309566-dirty #736
+[   29.844604] Hardware name: ST-Ericsson Ux5x0 platform (Device Tree Support)
+[   29.851562] task: de572700 task.stack: de742000
+[   29.856079] PC is at kernfs_find_ns+0x8/0x100
+[   29.860443] LR is at kernfs_find_and_get_ns+0x30/0x48
+
+After this patch:
+
+/sys/bus/amba/drivers/mmci-pl18x$ echo 80005000.sdi4_per2 > unbind
+[   20.623382] mmc3: card 0001 removed
+
+Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device")
+Reported-by: Adrian Hunter <adrian.hunter@intel.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+Acked-by: Adrian Hunter <adrian.hunter@intel.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/mmc/core/block.c |   32 ++++++++++++++++++--------------
+ 1 file changed, 18 insertions(+), 14 deletions(-)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2323,9 +2323,7 @@ static int mmc_rpmb_chrdev_open(struct i
+       get_device(&rpmb->dev);
+       filp->private_data = rpmb;
+-      mutex_lock(&open_lock);
+-      rpmb->md->usage++;
+-      mutex_unlock(&open_lock);
++      mmc_blk_get(rpmb->md->disk);
+       return nonseekable_open(inode, filp);
+ }
+@@ -2336,9 +2334,7 @@ static int mmc_rpmb_chrdev_release(struc
+                                                 struct mmc_rpmb_data, chrdev);
+       put_device(&rpmb->dev);
+-      mutex_lock(&open_lock);
+-      rpmb->md->usage--;
+-      mutex_unlock(&open_lock);
++      mmc_blk_put(rpmb->md);
+       return 0;
+ }
+@@ -2354,6 +2350,13 @@ static const struct file_operations mmc_
+ #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,
+@@ -2372,8 +2375,10 @@ static int mmc_blk_alloc_rpmb_part(struc
+               return devidx;
+       rpmb = kzalloc(sizeof(*rpmb), GFP_KERNEL);
+-      if (!rpmb)
++      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 : "");
+@@ -2384,6 +2389,7 @@ static int mmc_blk_alloc_rpmb_part(struc
+       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;
+@@ -2393,7 +2399,7 @@ static int mmc_blk_alloc_rpmb_part(struc
+       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;
++              goto out_put_device;
+       }
+       list_add(&rpmb->node, &md->rpmbs);
+@@ -2408,18 +2414,16 @@ static int mmc_blk_alloc_rpmb_part(struc
+       return 0;
+-out_remove_ida:
+-      ida_simple_remove(&mmc_rpmb_ida, rpmb->id);
+-      kfree(rpmb);
++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);
+-      device_del(&rpmb->dev);
+-      ida_simple_remove(&mmc_rpmb_ida, rpmb->id);
+-      kfree(rpmb);
++      put_device(&rpmb->dev);
+ }
+ /* MMC Physical partitions consist of two boot partitions and
diff --git a/queue-4.14/mmc-block-propagate-correct-returned-value-in-mmc_rpmb_ioctl.patch b/queue-4.14/mmc-block-propagate-correct-returned-value-in-mmc_rpmb_ioctl.patch
new file mode 100644 (file)
index 0000000..d3cd8ff
--- /dev/null
@@ -0,0 +1,44 @@
+From b25b750df99bcba29317d3f9d9f93c4ec58890e6 Mon Sep 17 00:00:00 2001
+From: Mathieu Malaterre <malat@debian.org>
+Date: Wed, 16 May 2018 21:20:20 +0200
+Subject: mmc: block: propagate correct returned value in mmc_rpmb_ioctl
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mathieu Malaterre <malat@debian.org>
+
+commit b25b750df99bcba29317d3f9d9f93c4ec58890e6 upstream.
+
+In commit 97548575bef3 ("mmc: block: Convert RPMB to a character device") a
+new function `mmc_rpmb_ioctl` was added. The final return is simply
+returning a value of `0` instead of propagating the correct return code.
+
+Discovered during a compilation with W=1, silence the following gcc warning
+
+drivers/mmc/core/block.c:2470:6: warning: variable ‘ret’ set but not used
+[-Wunused-but-set-variable]
+
+Signed-off-by: Mathieu Malaterre <malat@debian.org>
+Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
+Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device")
+Cc: stable@vger.kernel.org # v4.15+
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/core/block.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2305,7 +2305,7 @@ static long mmc_rpmb_ioctl(struct file *
+               break;
+       }
+-      return 0;
++      return ret;
+ }
+ #ifdef CONFIG_COMPAT
diff --git a/queue-4.14/mmc-core-prevent-bus-reference-leak-in-mmc_blk_init.patch b/queue-4.14/mmc-core-prevent-bus-reference-leak-in-mmc_blk_init.patch
new file mode 100644 (file)
index 0000000..b8dce21
--- /dev/null
@@ -0,0 +1,38 @@
+From d0a0852b9f81cf5f793bf2eae7336ed40a1a1815 Mon Sep 17 00:00:00 2001
+From: Alexander Kappner <agk@godking.net>
+Date: Wed, 28 Mar 2018 15:18:31 -0700
+Subject: mmc: core: Prevent bus reference leak in mmc_blk_init()
+
+From: Alexander Kappner <agk@godking.net>
+
+commit d0a0852b9f81cf5f793bf2eae7336ed40a1a1815 upstream.
+
+Upon module load, mmc_block allocates a bus with bus_registeri() in
+mmc_blk_init(). This reference never gets freed during module unload, which
+leads to subsequent re-insertions of the module fails and a WARN() splat is
+triggered.
+
+Fix the bug by dropping the reference for the bus in mmc_blk_exit().
+
+Signed-off-by: Alexander Kappner <agk@godking.net>
+Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device")
+Cc: <stable@vger.kernel.org>
+Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
+Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
+Cc: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mmc/core/block.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/mmc/core/block.c
++++ b/drivers/mmc/core/block.c
+@@ -2904,6 +2904,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);
++      bus_unregister(&mmc_rpmb_bus_type);
+ }
+ module_init(mmc_blk_init);
diff --git a/queue-4.14/pci-switchtec-read-all-64-bits-of-part_event_bitmap.patch b/queue-4.14/pci-switchtec-read-all-64-bits-of-part_event_bitmap.patch
new file mode 100644 (file)
index 0000000..5520132
--- /dev/null
@@ -0,0 +1,45 @@
+From 6acdf7e19b37cb3a9258603d0eab315079c19c5e Mon Sep 17 00:00:00 2001
+From: Logan Gunthorpe <logang@deltatee.com>
+Date: Tue, 10 Sep 2019 13:58:33 -0600
+Subject: PCI/switchtec: Read all 64 bits of part_event_bitmap
+
+From: Logan Gunthorpe <logang@deltatee.com>
+
+commit 6acdf7e19b37cb3a9258603d0eab315079c19c5e upstream.
+
+The part_event_bitmap register is 64 bits wide, so read it with ioread64()
+instead of the 32-bit ioread32().
+
+Fixes: 52eabba5bcdb ("switchtec: Add IOCTLs to the Switchtec driver")
+Link: https://lore.kernel.org/r/20190910195833.3891-1-logang@deltatee.com
+Reported-by: Doug Meyer <dmeyer@gigaio.com>
+Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Cc: stable@vger.kernel.org     # v4.12+
+Cc: Kelvin Cao <Kelvin.Cao@microchip.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/pci/switch/switchtec.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/pci/switch/switchtec.c
++++ b/drivers/pci/switch/switchtec.c
+@@ -23,7 +23,7 @@
+ #include <linux/pci.h>
+ #include <linux/cdev.h>
+ #include <linux/wait.h>
+-
++#include <linux/io-64-nonatomic-lo-hi.h>
+ #include <linux/nospec.h>
+ MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver");
+@@ -898,7 +898,7 @@ static int ioctl_event_summary(struct sw
+       u32 reg;
+       s.global = ioread32(&stdev->mmio_sw_event->global_summary);
+-      s.part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap);
++      s.part_bitmap = readq(&stdev->mmio_sw_event->part_event_bitmap);
+       s.local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary);
+       for (i = 0; i < stdev->partition_count; i++) {
index aa776c60ca07d1b4d86c6b11f79dc6277e3f212b..2fa97dda9fd425221e6a8c2f3f350f02723dbe8b 100644 (file)
@@ -39,3 +39,9 @@ llc2-fix-return-statement-of-llc_stat_ev_rx_null_dsa.patch
 hv_netvsc-fix-unwanted-rx_table-reset.patch
 bpf-reject-passing-modified-ctx-to-helper-functions.patch
 bpf-fix-passing-modified-ctx-to-ld-abs-ind-instruction.patch
+pci-switchtec-read-all-64-bits-of-part_event_bitmap.patch
+mmc-block-convert-rpmb-to-a-character-device.patch
+mmc-block-delete-mmc_access_rpmb.patch
+mmc-block-fix-bug-when-removing-rpmb-chardev.patch
+mmc-core-prevent-bus-reference-leak-in-mmc_blk_init.patch
+mmc-block-propagate-correct-returned-value-in-mmc_rpmb_ioctl.patch