From: Greg Kroah-Hartman Date: Fri, 10 Jan 2020 12:11:12 +0000 (+0100) Subject: 4.14-stable patches X-Git-Tag: v4.4.209~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ea48c069b02c3988ee6d849511e01237c0131b22;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches 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 --- 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 index 00000000000..846a09dd2ac --- /dev/null +++ b/queue-4.14/mmc-block-convert-rpmb-to-a-character-device.patch @@ -0,0 +1,610 @@ +From 97548575bef38abd06690a5a6f6816200c7e77f7 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 20 Sep 2017 10:02:00 +0200 +Subject: mmc: block: Convert RPMB to a character device + +From: Linus Walleij + +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 +Signed-off-by: Linus Walleij +Signed-off-by: Ulf Hansson +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 00000000000..036e3cdbedc --- /dev/null +++ b/queue-4.14/mmc-block-delete-mmc_access_rpmb.patch @@ -0,0 +1,74 @@ +From 14f4ca7e4d2825f9f71e22905ae177b899959f1d Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 20 Sep 2017 10:02:01 +0200 +Subject: mmc: block: Delete mmc_access_rpmb() + +From: Linus Walleij + +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 +Signed-off-by: Linus Walleij +Signed-off-by: Ulf Hansson +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..309f08888f9 --- /dev/null +++ b/queue-4.14/mmc-block-fix-bug-when-removing-rpmb-chardev.patch @@ -0,0 +1,143 @@ +From 1c87f73578497a6c3cc77bcbfd2e5bf15fe753c7 Mon Sep 17 00:00:00 2001 +From: Linus Walleij +Date: Wed, 4 Oct 2017 11:10:07 +0200 +Subject: mmc: block: Fix bug when removing RPMB chardev + +From: Linus Walleij + +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 +Signed-off-by: Linus Walleij +Acked-by: Adrian Hunter +Signed-off-by: Ulf Hansson +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..d3cd8ffa46e --- /dev/null +++ b/queue-4.14/mmc-block-propagate-correct-returned-value-in-mmc_rpmb_ioctl.patch @@ -0,0 +1,44 @@ +From b25b750df99bcba29317d3f9d9f93c4ec58890e6 Mon Sep 17 00:00:00 2001 +From: Mathieu Malaterre +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 + +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 +Reviewed-by: Shawn Lin +Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device") +Cc: stable@vger.kernel.org # v4.15+ +Signed-off-by: Ulf Hansson +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..b8dce217e80 --- /dev/null +++ b/queue-4.14/mmc-core-prevent-bus-reference-leak-in-mmc_blk_init.patch @@ -0,0 +1,38 @@ +From d0a0852b9f81cf5f793bf2eae7336ed40a1a1815 Mon Sep 17 00:00:00 2001 +From: Alexander Kappner +Date: Wed, 28 Mar 2018 15:18:31 -0700 +Subject: mmc: core: Prevent bus reference leak in mmc_blk_init() + +From: Alexander Kappner + +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 +Fixes: 97548575bef3 ("mmc: block: Convert RPMB to a character device") +Cc: +Reviewed-by: Shawn Lin +Signed-off-by: Ulf Hansson +Cc: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..55201320949 --- /dev/null +++ b/queue-4.14/pci-switchtec-read-all-64-bits-of-part_event_bitmap.patch @@ -0,0 +1,45 @@ +From 6acdf7e19b37cb3a9258603d0eab315079c19c5e Mon Sep 17 00:00:00 2001 +From: Logan Gunthorpe +Date: Tue, 10 Sep 2019 13:58:33 -0600 +Subject: PCI/switchtec: Read all 64 bits of part_event_bitmap + +From: Logan Gunthorpe + +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 +Signed-off-by: Logan Gunthorpe +Signed-off-by: Bjorn Helgaas +Cc: stable@vger.kernel.org # v4.12+ +Cc: Kelvin Cao +Signed-off-by: Greg Kroah-Hartman + +--- + 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 + #include + #include +- ++#include + #include + + 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++) { diff --git a/queue-4.14/series b/queue-4.14/series index aa776c60ca0..2fa97dda9fd 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -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