From dc1fb809dcb1161c2304192796ceabb6201b9db5 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 23 Sep 2022 12:54:09 -0400 Subject: [PATCH] Fixes for 5.19 Signed-off-by: Sasha Levin --- queue-5.19/block-remove-queue_flag_dead.patch | 89 + queue-5.19/block-simplify-disk-shutdown.patch | 859 +++++++ ...ng-the-nomerges-flags-in-blk_cleanup.patch | 40 + ...lit-parse_driver_features-into-two-p.patch | 58 + ...lit-vbt-data-into-per-panel-vs.-glob.patch | 1969 +++++++++++++++++ ...lit-vbt-parsing-to-global-vs.-panel-.patch | 103 + ...ter-invalid-backlight-and-cabc-ports.patch | 66 + ...-dual-link-dsi-backlight-and-cabc-po.patch | 72 + ...i915-extract-intel_edp_fixup_vbt_bpp.patch | 147 ++ ...it-pps_init_delays-into-distinct-par.patch | 133 ++ ...s-fix-memory-leak-when-using-debugfs.patch | 51 + ...b-add-quirks-for-lenovo-onelink-dock.patch | 43 + ...t-udc-xilinx-replace-memcpy-with-mem.patch | 96 + .../scsi-core-fix-a-use-after-free.patch | 201 ++ queue-5.19/series | 27 + ...ry-data-corruption-in-collapse-range.patch | 94 + ...rary-data-corruption-in-insert-range.patch | 84 + ...ush-out-of-smb2_copychunk_range-into.patch | 95 + ..._write_and_wait_range-instead-of-fil.patch | 81 + ...b-add-quirks-for-lenovo-onelink-dock.patch | 51 + ...d-helper-functions-to-enable-disable.patch | 108 + ...nfigure-wakeup-interrupts-during-sus.patch | 156 ++ ...usb-dwc3-qcom-fix-gadget-only-builds.patch | 43 + ...-qcom-fix-peripheral-and-otg-suspend.patch | 78 + .../usb-dwc3-qcom-fix-runtime-pm-wakeup.patch | 110 + ...x-use-after-free-on-runtime-pm-wakeu.patch | 82 + ...ilinx-replace-memcpy-with-memcpy_toi.patch | 156 ++ .../xfrm-fix-xfrma_lastused-comment.patch | 35 + 28 files changed, 5127 insertions(+) create mode 100644 queue-5.19/block-remove-queue_flag_dead.patch create mode 100644 queue-5.19/block-simplify-disk-shutdown.patch create mode 100644 queue-5.19/block-stop-setting-the-nomerges-flags-in-blk_cleanup.patch create mode 100644 queue-5.19/drm-i915-bios-split-parse_driver_features-into-two-p.patch create mode 100644 queue-5.19/drm-i915-bios-split-vbt-data-into-per-panel-vs.-glob.patch create mode 100644 queue-5.19/drm-i915-bios-split-vbt-parsing-to-global-vs.-panel-.patch create mode 100644 queue-5.19/drm-i915-dsi-filter-invalid-backlight-and-cabc-ports.patch create mode 100644 queue-5.19/drm-i915-dsi-fix-dual-link-dsi-backlight-and-cabc-po.patch create mode 100644 queue-5.19/drm-i915-extract-intel_edp_fixup_vbt_bpp.patch create mode 100644 queue-5.19/drm-i915-pps-split-pps_init_delays-into-distinct-par.patch create mode 100644 queue-5.19/net-mvpp2-debugfs-fix-memory-leak-when-using-debugfs.patch create mode 100644 queue-5.19/revert-usb-add-quirks-for-lenovo-onelink-dock.patch create mode 100644 queue-5.19/revert-usb-gadget-udc-xilinx-replace-memcpy-with-mem.patch create mode 100644 queue-5.19/scsi-core-fix-a-use-after-free.patch create mode 100644 queue-5.19/series create mode 100644 queue-5.19/smb3-fix-temporary-data-corruption-in-collapse-range.patch create mode 100644 queue-5.19/smb3-fix-temporary-data-corruption-in-insert-range.patch create mode 100644 queue-5.19/smb3-move-the-flush-out-of-smb2_copychunk_range-into.patch create mode 100644 queue-5.19/smb3-use-filemap_write_and_wait_range-instead-of-fil.patch create mode 100644 queue-5.19/usb-add-quirks-for-lenovo-onelink-dock.patch create mode 100644 queue-5.19/usb-dwc3-qcom-add-helper-functions-to-enable-disable.patch create mode 100644 queue-5.19/usb-dwc3-qcom-configure-wakeup-interrupts-during-sus.patch create mode 100644 queue-5.19/usb-dwc3-qcom-fix-gadget-only-builds.patch create mode 100644 queue-5.19/usb-dwc3-qcom-fix-peripheral-and-otg-suspend.patch create mode 100644 queue-5.19/usb-dwc3-qcom-fix-runtime-pm-wakeup.patch create mode 100644 queue-5.19/usb-dwc3-qcom-fix-use-after-free-on-runtime-pm-wakeu.patch create mode 100644 queue-5.19/usb-gadget-udc-xilinx-replace-memcpy-with-memcpy_toi.patch create mode 100644 queue-5.19/xfrm-fix-xfrma_lastused-comment.patch diff --git a/queue-5.19/block-remove-queue_flag_dead.patch b/queue-5.19/block-remove-queue_flag_dead.patch new file mode 100644 index 00000000000..5b58a096c49 --- /dev/null +++ b/queue-5.19/block-remove-queue_flag_dead.patch @@ -0,0 +1,89 @@ +From 7de7e0ebef49d82376f8829aa3ea9e6c790b950f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jun 2022 08:05:49 +0200 +Subject: block: remove QUEUE_FLAG_DEAD + +From: Christoph Hellwig + +[ Upstream commit 1f90307e5f0d7bc9a336ead528f616a5df8e5944 ] + +Disallow setting the blk-mq state on any queue that is already dying as +setting the state even then is a bad idea, and remove the now unused +QUEUE_FLAG_DEAD flag. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Link: https://lore.kernel.org/r/20220619060552.1850436-4-hch@lst.de +Signed-off-by: Jens Axboe +Stable-dep-of: 8fe4ce5836e9 ("scsi: core: Fix a use-after-free") +Signed-off-by: Sasha Levin +--- + block/blk-core.c | 3 --- + block/blk-mq-debugfs.c | 8 +++----- + include/linux/blkdev.h | 2 -- + 3 files changed, 3 insertions(+), 10 deletions(-) + +diff --git a/block/blk-core.c b/block/blk-core.c +index cc6fbcb6d252..76f070c3a3b0 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -313,9 +313,6 @@ void blk_cleanup_queue(struct request_queue *q) + * after draining finished. + */ + blk_freeze_queue(q); +- +- blk_queue_flag_set(QUEUE_FLAG_DEAD, q); +- + blk_sync_queue(q); + if (queue_is_mq(q)) { + blk_mq_cancel_work_sync(q); +diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c +index 61f179e5f151..28adb01f6441 100644 +--- a/block/blk-mq-debugfs.c ++++ b/block/blk-mq-debugfs.c +@@ -116,7 +116,6 @@ static const char *const blk_queue_flag_name[] = { + QUEUE_FLAG_NAME(NOXMERGES), + QUEUE_FLAG_NAME(ADD_RANDOM), + QUEUE_FLAG_NAME(SAME_FORCE), +- QUEUE_FLAG_NAME(DEAD), + QUEUE_FLAG_NAME(INIT_DONE), + QUEUE_FLAG_NAME(STABLE_WRITES), + QUEUE_FLAG_NAME(POLL), +@@ -151,11 +150,10 @@ static ssize_t queue_state_write(void *data, const char __user *buf, + char opbuf[16] = { }, *op; + + /* +- * The "state" attribute is removed after blk_cleanup_queue() has called +- * blk_mq_free_queue(). Return if QUEUE_FLAG_DEAD has been set to avoid +- * triggering a use-after-free. ++ * The "state" attribute is removed when the queue is removed. Don't ++ * allow setting the state on a dying queue to avoid a use-after-free. + */ +- if (blk_queue_dead(q)) ++ if (blk_queue_dying(q)) + return -ENOENT; + + if (count >= sizeof(opbuf)) { +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 62e3ff52ab03..76f77eed58c3 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -559,7 +559,6 @@ struct request_queue { + #define QUEUE_FLAG_NOXMERGES 9 /* No extended merges */ + #define QUEUE_FLAG_ADD_RANDOM 10 /* Contributes to random pool */ + #define QUEUE_FLAG_SAME_FORCE 12 /* force complete on same CPU */ +-#define QUEUE_FLAG_DEAD 13 /* queue tear-down finished */ + #define QUEUE_FLAG_INIT_DONE 14 /* queue is initialized */ + #define QUEUE_FLAG_STABLE_WRITES 15 /* don't modify blks until WB is done */ + #define QUEUE_FLAG_POLL 16 /* IO polling enabled if set */ +@@ -587,7 +586,6 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q); + #define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) + #define blk_queue_dying(q) test_bit(QUEUE_FLAG_DYING, &(q)->queue_flags) + #define blk_queue_has_srcu(q) test_bit(QUEUE_FLAG_HAS_SRCU, &(q)->queue_flags) +-#define blk_queue_dead(q) test_bit(QUEUE_FLAG_DEAD, &(q)->queue_flags) + #define blk_queue_init_done(q) test_bit(QUEUE_FLAG_INIT_DONE, &(q)->queue_flags) + #define blk_queue_nomerges(q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags) + #define blk_queue_noxmerges(q) \ +-- +2.35.1 + diff --git a/queue-5.19/block-simplify-disk-shutdown.patch b/queue-5.19/block-simplify-disk-shutdown.patch new file mode 100644 index 00000000000..b10cf539731 --- /dev/null +++ b/queue-5.19/block-simplify-disk-shutdown.patch @@ -0,0 +1,859 @@ +From dc7d332c13cc0d553c6918d75a70f4166abc3883 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jun 2022 08:05:51 +0200 +Subject: block: simplify disk shutdown + +From: Christoph Hellwig + +[ Upstream commit 6f8191fdf41d3a53cc1d63fe2234e812c55a0092 ] + +Set the queue dying flag and call blk_mq_exit_queue from del_gendisk for +all disks that do not have separately allocated queues, and thus remove +the need to call blk_cleanup_queue for them. + +Rename blk_cleanup_disk to blk_mq_destroy_queue to make it clear that +this function is intended only for separately allocated blk-mq queues. + +This saves an extra queue freeze for devices without a separately +allocated queue. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Link: https://lore.kernel.org/r/20220619060552.1850436-6-hch@lst.de +Signed-off-by: Jens Axboe +Stable-dep-of: 8fe4ce5836e9 ("scsi: core: Fix a use-after-free") +Signed-off-by: Sasha Levin +--- + block/blk-core.c | 37 ------------------------- + block/blk-mq.c | 43 +++++++++++++++++++++++++++-- + block/blk-sysfs.c | 5 ---- + block/blk.h | 3 ++ + block/bsg-lib.c | 4 +-- + block/genhd.c | 23 ++++++++------- + drivers/block/ataflop.c | 1 - + drivers/block/loop.c | 1 - + drivers/block/mtip32xx/mtip32xx.c | 2 -- + drivers/block/rnbd/rnbd-clt.c | 2 +- + drivers/block/sx8.c | 4 +-- + drivers/block/virtio_blk.c | 1 - + drivers/block/z2ram.c | 1 - + drivers/cdrom/gdrom.c | 1 - + drivers/memstick/core/ms_block.c | 1 - + drivers/memstick/core/mspro_block.c | 1 - + drivers/mmc/core/block.c | 1 - + drivers/mmc/core/queue.c | 1 - + drivers/nvme/host/apple.c | 2 +- + drivers/nvme/host/core.c | 1 - + drivers/nvme/host/fc.c | 12 ++++---- + drivers/nvme/host/pci.c | 2 +- + drivers/nvme/host/rdma.c | 12 ++++---- + drivers/nvme/host/tcp.c | 12 ++++---- + drivers/nvme/target/loop.c | 12 ++++---- + drivers/s390/block/dasd.c | 2 +- + drivers/s390/block/dasd_genhd.c | 4 +-- + drivers/scsi/scsi_lib.c | 6 ++-- + drivers/scsi/scsi_sysfs.c | 2 +- + drivers/scsi/sd.c | 4 +-- + drivers/scsi/sr.c | 4 +-- + drivers/ufs/core/ufshcd.c | 4 +-- + include/linux/blk-mq.h | 3 ++ + include/linux/blkdev.h | 4 +-- + 34 files changed, 105 insertions(+), 113 deletions(-) + +diff --git a/block/blk-core.c b/block/blk-core.c +index b8083decc07f..7743c68177e8 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -284,43 +284,6 @@ void blk_queue_start_drain(struct request_queue *q) + wake_up_all(&q->mq_freeze_wq); + } + +-/** +- * blk_cleanup_queue - shutdown a request queue +- * @q: request queue to shutdown +- * +- * Mark @q DYING, drain all pending requests, mark @q DEAD, destroy and +- * put it. All future requests will be failed immediately with -ENODEV. +- * +- * Context: can sleep +- */ +-void blk_cleanup_queue(struct request_queue *q) +-{ +- /* cannot be called from atomic context */ +- might_sleep(); +- +- WARN_ON_ONCE(blk_queue_registered(q)); +- +- /* mark @q DYING, no new request or merges will be allowed afterwards */ +- blk_queue_flag_set(QUEUE_FLAG_DYING, q); +- blk_queue_start_drain(q); +- +- /* +- * Drain all requests queued before DYING marking. Set DEAD flag to +- * prevent that blk_mq_run_hw_queues() accesses the hardware queues +- * after draining finished. +- */ +- blk_freeze_queue(q); +- blk_sync_queue(q); +- if (queue_is_mq(q)) { +- blk_mq_cancel_work_sync(q); +- blk_mq_exit_queue(q); +- } +- +- /* @q is and will stay empty, shutdown and put */ +- blk_put_queue(q); +-} +-EXPORT_SYMBOL(blk_cleanup_queue); +- + /** + * blk_queue_enter() - try to increase q->q_usage_counter + * @q: request queue pointer +diff --git a/block/blk-mq.c b/block/blk-mq.c +index 0a299941c622..6e22700dd6cf 100644 +--- a/block/blk-mq.c ++++ b/block/blk-mq.c +@@ -3896,7 +3896,7 @@ static struct request_queue *blk_mq_init_queue_data(struct blk_mq_tag_set *set, + q->queuedata = queuedata; + ret = blk_mq_init_allocated_queue(set, q); + if (ret) { +- blk_cleanup_queue(q); ++ blk_put_queue(q); + return ERR_PTR(ret); + } + return q; +@@ -3908,6 +3908,35 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) + } + EXPORT_SYMBOL(blk_mq_init_queue); + ++/** ++ * blk_mq_destroy_queue - shutdown a request queue ++ * @q: request queue to shutdown ++ * ++ * This shuts down a request queue allocated by blk_mq_init_queue() and drops ++ * the initial reference. All future requests will failed with -ENODEV. ++ * ++ * Context: can sleep ++ */ ++void blk_mq_destroy_queue(struct request_queue *q) ++{ ++ WARN_ON_ONCE(!queue_is_mq(q)); ++ WARN_ON_ONCE(blk_queue_registered(q)); ++ ++ might_sleep(); ++ ++ blk_queue_flag_set(QUEUE_FLAG_DYING, q); ++ blk_queue_start_drain(q); ++ blk_freeze_queue(q); ++ ++ blk_sync_queue(q); ++ blk_mq_cancel_work_sync(q); ++ blk_mq_exit_queue(q); ++ ++ /* @q is and will stay empty, shutdown and put */ ++ blk_put_queue(q); ++} ++EXPORT_SYMBOL(blk_mq_destroy_queue); ++ + struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata, + struct lock_class_key *lkclass) + { +@@ -3920,13 +3949,23 @@ struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata, + + disk = __alloc_disk_node(q, set->numa_node, lkclass); + if (!disk) { +- blk_cleanup_queue(q); ++ blk_put_queue(q); + return ERR_PTR(-ENOMEM); + } ++ set_bit(GD_OWNS_QUEUE, &disk->state); + return disk; + } + EXPORT_SYMBOL(__blk_mq_alloc_disk); + ++struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q, ++ struct lock_class_key *lkclass) ++{ ++ if (!blk_get_queue(q)) ++ return NULL; ++ return __alloc_disk_node(q, NUMA_NO_NODE, lkclass); ++} ++EXPORT_SYMBOL(blk_mq_alloc_disk_for_queue); ++ + static struct blk_mq_hw_ctx *blk_mq_alloc_and_init_hctx( + struct blk_mq_tag_set *set, struct request_queue *q, + int hctx_idx, int node) +diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c +index 9b905e9443e4..84d7f8701567 100644 +--- a/block/blk-sysfs.c ++++ b/block/blk-sysfs.c +@@ -748,11 +748,6 @@ static void blk_free_queue_rcu(struct rcu_head *rcu_head) + * decremented with blk_put_queue(). Once the refcount reaches 0 this function + * is called. + * +- * For drivers that have a request_queue on a gendisk and added with +- * __device_add_disk() the refcount to request_queue will reach 0 with +- * the last put_disk() called by the driver. For drivers which don't use +- * __device_add_disk() this happens with blk_cleanup_queue(). +- * + * Drivers exist which depend on the release of the request_queue to be + * synchronous, it should not be deferred. + * +diff --git a/block/blk.h b/block/blk.h +index 434017701403..0d6668663ab5 100644 +--- a/block/blk.h ++++ b/block/blk.h +@@ -411,6 +411,9 @@ int bdev_resize_partition(struct gendisk *disk, int partno, sector_t start, + sector_t length); + void blk_drop_partitions(struct gendisk *disk); + ++struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, ++ struct lock_class_key *lkclass); ++ + int bio_add_hw_page(struct request_queue *q, struct bio *bio, + struct page *page, unsigned int len, unsigned int offset, + unsigned int max_sectors, bool *same_page); +diff --git a/block/bsg-lib.c b/block/bsg-lib.c +index acfe1357bf6c..fd4cd5e68282 100644 +--- a/block/bsg-lib.c ++++ b/block/bsg-lib.c +@@ -324,7 +324,7 @@ void bsg_remove_queue(struct request_queue *q) + container_of(q->tag_set, struct bsg_set, tag_set); + + bsg_unregister_queue(bset->bd); +- blk_cleanup_queue(q); ++ blk_mq_destroy_queue(q); + blk_mq_free_tag_set(&bset->tag_set); + kfree(bset); + } +@@ -399,7 +399,7 @@ struct request_queue *bsg_setup_queue(struct device *dev, const char *name, + + return q; + out_cleanup_queue: +- blk_cleanup_queue(q); ++ blk_mq_destroy_queue(q); + out_queue: + blk_mq_free_tag_set(set); + out_tag_set: +diff --git a/block/genhd.c b/block/genhd.c +index 278227ba1d53..4d15f828c449 100644 +--- a/block/genhd.c ++++ b/block/genhd.c +@@ -617,6 +617,8 @@ void del_gendisk(struct gendisk *disk) + * Fail any new I/O. + */ + set_bit(GD_DEAD, &disk->state); ++ if (test_bit(GD_OWNS_QUEUE, &disk->state)) ++ blk_queue_flag_set(QUEUE_FLAG_DYING, q); + set_capacity(disk, 0); + + /* +@@ -663,11 +665,16 @@ void del_gendisk(struct gendisk *disk) + blk_mq_unquiesce_queue(q); + + /* +- * Allow using passthrough request again after the queue is torn down. ++ * If the disk does not own the queue, allow using passthrough requests ++ * again. Else leave the queue frozen to fail all I/O. + */ +- blk_queue_flag_clear(QUEUE_FLAG_INIT_DONE, q); +- __blk_mq_unfreeze_queue(q, true); +- ++ if (!test_bit(GD_OWNS_QUEUE, &disk->state)) { ++ blk_queue_flag_clear(QUEUE_FLAG_INIT_DONE, q); ++ __blk_mq_unfreeze_queue(q, true); ++ } else { ++ if (queue_is_mq(q)) ++ blk_mq_exit_queue(q); ++ } + } + EXPORT_SYMBOL(del_gendisk); + +@@ -1338,9 +1345,6 @@ struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, + { + struct gendisk *disk; + +- if (!blk_get_queue(q)) +- return NULL; +- + disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id); + if (!disk) + goto out_put_queue; +@@ -1391,7 +1395,6 @@ struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, + blk_put_queue(q); + return NULL; + } +-EXPORT_SYMBOL(__alloc_disk_node); + + struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass) + { +@@ -1404,9 +1407,10 @@ struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass) + + disk = __alloc_disk_node(q, node, lkclass); + if (!disk) { +- blk_cleanup_queue(q); ++ blk_put_queue(q); + return NULL; + } ++ set_bit(GD_OWNS_QUEUE, &disk->state); + return disk; + } + EXPORT_SYMBOL(__blk_alloc_disk); +@@ -1439,7 +1443,6 @@ EXPORT_SYMBOL(put_disk); + */ + void blk_cleanup_disk(struct gendisk *disk) + { +- blk_cleanup_queue(disk->queue); + put_disk(disk); + } + EXPORT_SYMBOL(blk_cleanup_disk); +diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c +index e232cc4fd444..c6e41ee18aaa 100644 +--- a/drivers/block/ataflop.c ++++ b/drivers/block/ataflop.c +@@ -2045,7 +2045,6 @@ static void atari_floppy_cleanup(void) + if (!unit[i].disk[type]) + continue; + del_gendisk(unit[i].disk[type]); +- blk_cleanup_queue(unit[i].disk[type]->queue); + put_disk(unit[i].disk[type]); + } + blk_mq_free_tag_set(&unit[i].tag_set); +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index a59910ef948e..1c036ef686fb 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -2062,7 +2062,6 @@ static void loop_remove(struct loop_device *lo) + { + /* Make this loop device unreachable from pathname. */ + del_gendisk(lo->lo_disk); +- blk_cleanup_queue(lo->lo_disk->queue); + blk_mq_free_tag_set(&lo->tag_set); + + mutex_lock(&loop_ctl_mutex); +diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c +index 6699e4b2f7f4..06994a35acc7 100644 +--- a/drivers/block/mtip32xx/mtip32xx.c ++++ b/drivers/block/mtip32xx/mtip32xx.c +@@ -3677,7 +3677,6 @@ static int mtip_block_shutdown(struct driver_data *dd) + if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) + del_gendisk(dd->disk); + +- blk_cleanup_queue(dd->queue); + blk_mq_free_tag_set(&dd->tags); + put_disk(dd->disk); + return 0; +@@ -4040,7 +4039,6 @@ static void mtip_pci_remove(struct pci_dev *pdev) + dev_info(&dd->pdev->dev, "device %s surprise removal\n", + dd->disk->disk_name); + +- blk_cleanup_queue(dd->queue); + blk_mq_free_tag_set(&dd->tags); + + /* De-initialize the protocol layer. */ +diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c +index 409c76b81aed..a4470374f54f 100644 +--- a/drivers/block/rnbd/rnbd-clt.c ++++ b/drivers/block/rnbd/rnbd-clt.c +@@ -1755,7 +1755,7 @@ static void rnbd_destroy_sessions(void) + list_for_each_entry_safe(dev, tn, &sess->devs_list, list) { + /* + * Here unmap happens in parallel for only one reason: +- * blk_cleanup_queue() takes around half a second, so ++ * del_gendisk() takes around half a second, so + * on huge amount of devices the whole module unload + * procedure takes minutes. + */ +diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c +index 63b4f6431d2e..75057dbbcfbe 100644 +--- a/drivers/block/sx8.c ++++ b/drivers/block/sx8.c +@@ -1536,7 +1536,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) + clear_bit(0, &carm_major_alloc); + else if (host->major == 161) + clear_bit(1, &carm_major_alloc); +- blk_cleanup_queue(host->oob_q); ++ blk_mq_destroy_queue(host->oob_q); + blk_mq_free_tag_set(&host->tag_set); + err_out_dma_free: + dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma); +@@ -1570,7 +1570,7 @@ static void carm_remove_one (struct pci_dev *pdev) + clear_bit(0, &carm_major_alloc); + else if (host->major == 161) + clear_bit(1, &carm_major_alloc); +- blk_cleanup_queue(host->oob_q); ++ blk_mq_destroy_queue(host->oob_q); + blk_mq_free_tag_set(&host->tag_set); + dma_free_coherent(&pdev->dev, CARM_SHM_SIZE, host->shm, host->shm_dma); + iounmap(host->mmio); +diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c +index d756423e0059..59d6d5faf739 100644 +--- a/drivers/block/virtio_blk.c ++++ b/drivers/block/virtio_blk.c +@@ -1107,7 +1107,6 @@ static void virtblk_remove(struct virtio_device *vdev) + flush_work(&vblk->config_work); + + del_gendisk(vblk->disk); +- blk_cleanup_queue(vblk->disk->queue); + blk_mq_free_tag_set(&vblk->tag_set); + + mutex_lock(&vblk->vdev_mutex); +diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c +index 7a6ed83481b8..18ad43d9933e 100644 +--- a/drivers/block/z2ram.c ++++ b/drivers/block/z2ram.c +@@ -384,7 +384,6 @@ static void __exit z2_exit(void) + + for (i = 0; i < Z2MINOR_COUNT; i++) { + del_gendisk(z2ram_gendisk[i]); +- blk_cleanup_queue(z2ram_gendisk[i]->queue); + put_disk(z2ram_gendisk[i]); + } + blk_mq_free_tag_set(&tag_set); +diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c +index 8e78b37d0f6a..f4cc90ea6198 100644 +--- a/drivers/cdrom/gdrom.c ++++ b/drivers/cdrom/gdrom.c +@@ -831,7 +831,6 @@ static int probe_gdrom(struct platform_device *devptr) + + static int remove_gdrom(struct platform_device *devptr) + { +- blk_cleanup_queue(gd.gdrom_rq); + blk_mq_free_tag_set(&gd.tag_set); + free_irq(HW_EVENT_GDROM_CMD, &gd); + free_irq(HW_EVENT_GDROM_DMA, &gd); +diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c +index f8fdf88fb240..ecbc46714e68 100644 +--- a/drivers/memstick/core/ms_block.c ++++ b/drivers/memstick/core/ms_block.c +@@ -2188,7 +2188,6 @@ static void msb_remove(struct memstick_dev *card) + + /* Remove the disk */ + del_gendisk(msb->disk); +- blk_cleanup_queue(msb->queue); + blk_mq_free_tag_set(&msb->tag_set); + msb->queue = NULL; + +diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c +index 725ba74ded30..72e91c06c618 100644 +--- a/drivers/memstick/core/mspro_block.c ++++ b/drivers/memstick/core/mspro_block.c +@@ -1294,7 +1294,6 @@ static void mspro_block_remove(struct memstick_dev *card) + del_gendisk(msb->disk); + dev_dbg(&card->dev, "mspro block remove\n"); + +- blk_cleanup_queue(msb->queue); + blk_mq_free_tag_set(&msb->tag_set); + msb->queue = NULL; + +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index 912a398a9a76..2f89ae55c177 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -2509,7 +2509,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, + return md; + + err_cleanup_queue: +- blk_cleanup_queue(md->disk->queue); + blk_mq_free_tag_set(&md->queue.tag_set); + err_kfree: + kfree(md); +diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c +index fa5324ceeebe..f824cfdab75a 100644 +--- a/drivers/mmc/core/queue.c ++++ b/drivers/mmc/core/queue.c +@@ -494,7 +494,6 @@ void mmc_cleanup_queue(struct mmc_queue *mq) + if (blk_queue_quiesced(q)) + blk_mq_unquiesce_queue(q); + +- blk_cleanup_queue(q); + blk_mq_free_tag_set(&mq->tag_set); + + /* +diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c +index d702d7d60235..2d23b7d41f7e 100644 +--- a/drivers/nvme/host/apple.c ++++ b/drivers/nvme/host/apple.c +@@ -1502,7 +1502,7 @@ static int apple_nvme_probe(struct platform_device *pdev) + + if (!blk_get_queue(anv->ctrl.admin_q)) { + nvme_start_admin_queue(&anv->ctrl); +- blk_cleanup_queue(anv->ctrl.admin_q); ++ blk_mq_destroy_queue(anv->ctrl.admin_q); + anv->ctrl.admin_q = NULL; + ret = -ENODEV; + goto put_dev; +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 2f965356f345..6d76fc608b74 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -4105,7 +4105,6 @@ static void nvme_ns_remove(struct nvme_ns *ns) + if (!nvme_ns_head_multipath(ns->head)) + nvme_cdev_del(&ns->cdev, &ns->cdev_device); + del_gendisk(ns->disk); +- blk_cleanup_queue(ns->queue); + + down_write(&ns->ctrl->namespaces_rwsem); + list_del_init(&ns->list); +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 4aff83b1b0c0..9a5ce70d7f21 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -2392,7 +2392,7 @@ nvme_fc_ctrl_free(struct kref *ref) + unsigned long flags; + + if (ctrl->ctrl.tagset) { +- blk_cleanup_queue(ctrl->ctrl.connect_q); ++ blk_mq_destroy_queue(ctrl->ctrl.connect_q); + blk_mq_free_tag_set(&ctrl->tag_set); + } + +@@ -2402,8 +2402,8 @@ nvme_fc_ctrl_free(struct kref *ref) + spin_unlock_irqrestore(&ctrl->rport->lock, flags); + + nvme_start_admin_queue(&ctrl->ctrl); +- blk_cleanup_queue(ctrl->ctrl.admin_q); +- blk_cleanup_queue(ctrl->ctrl.fabrics_q); ++ blk_mq_destroy_queue(ctrl->ctrl.admin_q); ++ blk_mq_destroy_queue(ctrl->ctrl.fabrics_q); + blk_mq_free_tag_set(&ctrl->admin_tag_set); + + kfree(ctrl->queues); +@@ -2953,7 +2953,7 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl) + out_delete_hw_queues: + nvme_fc_delete_hw_io_queues(ctrl); + out_cleanup_blk_queue: +- blk_cleanup_queue(ctrl->ctrl.connect_q); ++ blk_mq_destroy_queue(ctrl->ctrl.connect_q); + out_free_tag_set: + blk_mq_free_tag_set(&ctrl->tag_set); + nvme_fc_free_io_queues(ctrl); +@@ -3642,9 +3642,9 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, + return ERR_PTR(-EIO); + + out_cleanup_admin_q: +- blk_cleanup_queue(ctrl->ctrl.admin_q); ++ blk_mq_destroy_queue(ctrl->ctrl.admin_q); + out_cleanup_fabrics_q: +- blk_cleanup_queue(ctrl->ctrl.fabrics_q); ++ blk_mq_destroy_queue(ctrl->ctrl.fabrics_q); + out_free_admin_tag_set: + blk_mq_free_tag_set(&ctrl->admin_tag_set); + out_free_queues: +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 9f6614f7dbeb..3516678d3754 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1760,7 +1760,7 @@ static void nvme_dev_remove_admin(struct nvme_dev *dev) + * queue to flush these to completion. + */ + nvme_start_admin_queue(&dev->ctrl); +- blk_cleanup_queue(dev->ctrl.admin_q); ++ blk_mq_destroy_queue(dev->ctrl.admin_q); + blk_mq_free_tag_set(&dev->admin_tagset); + } + } +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 46c2dcf72f7e..240024dd5d85 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -840,8 +840,8 @@ static void nvme_rdma_destroy_admin_queue(struct nvme_rdma_ctrl *ctrl, + bool remove) + { + if (remove) { +- blk_cleanup_queue(ctrl->ctrl.admin_q); +- blk_cleanup_queue(ctrl->ctrl.fabrics_q); ++ blk_mq_destroy_queue(ctrl->ctrl.admin_q); ++ blk_mq_destroy_queue(ctrl->ctrl.fabrics_q); + blk_mq_free_tag_set(ctrl->ctrl.admin_tagset); + } + if (ctrl->async_event_sqe.data) { +@@ -935,10 +935,10 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, + nvme_cancel_admin_tagset(&ctrl->ctrl); + out_cleanup_queue: + if (new) +- blk_cleanup_queue(ctrl->ctrl.admin_q); ++ blk_mq_destroy_queue(ctrl->ctrl.admin_q); + out_cleanup_fabrics_q: + if (new) +- blk_cleanup_queue(ctrl->ctrl.fabrics_q); ++ blk_mq_destroy_queue(ctrl->ctrl.fabrics_q); + out_free_tagset: + if (new) + blk_mq_free_tag_set(ctrl->ctrl.admin_tagset); +@@ -957,7 +957,7 @@ static void nvme_rdma_destroy_io_queues(struct nvme_rdma_ctrl *ctrl, + bool remove) + { + if (remove) { +- blk_cleanup_queue(ctrl->ctrl.connect_q); ++ blk_mq_destroy_queue(ctrl->ctrl.connect_q); + blk_mq_free_tag_set(ctrl->ctrl.tagset); + } + nvme_rdma_free_io_queues(ctrl); +@@ -1012,7 +1012,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new) + out_cleanup_connect_q: + nvme_cancel_tagset(&ctrl->ctrl); + if (new) +- blk_cleanup_queue(ctrl->ctrl.connect_q); ++ blk_mq_destroy_queue(ctrl->ctrl.connect_q); + out_free_tag_set: + if (new) + blk_mq_free_tag_set(ctrl->ctrl.tagset); +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index daa0e160e121..d7e5bbdb9b75 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1881,7 +1881,7 @@ static void nvme_tcp_destroy_io_queues(struct nvme_ctrl *ctrl, bool remove) + { + nvme_tcp_stop_io_queues(ctrl); + if (remove) { +- blk_cleanup_queue(ctrl->connect_q); ++ blk_mq_destroy_queue(ctrl->connect_q); + blk_mq_free_tag_set(ctrl->tagset); + } + nvme_tcp_free_io_queues(ctrl); +@@ -1936,7 +1936,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new) + out_cleanup_connect_q: + nvme_cancel_tagset(ctrl); + if (new) +- blk_cleanup_queue(ctrl->connect_q); ++ blk_mq_destroy_queue(ctrl->connect_q); + out_free_tag_set: + if (new) + blk_mq_free_tag_set(ctrl->tagset); +@@ -1949,8 +1949,8 @@ static void nvme_tcp_destroy_admin_queue(struct nvme_ctrl *ctrl, bool remove) + { + nvme_tcp_stop_queue(ctrl, 0); + if (remove) { +- blk_cleanup_queue(ctrl->admin_q); +- blk_cleanup_queue(ctrl->fabrics_q); ++ blk_mq_destroy_queue(ctrl->admin_q); ++ blk_mq_destroy_queue(ctrl->fabrics_q); + blk_mq_free_tag_set(ctrl->admin_tagset); + } + nvme_tcp_free_admin_queue(ctrl); +@@ -2008,10 +2008,10 @@ static int nvme_tcp_configure_admin_queue(struct nvme_ctrl *ctrl, bool new) + nvme_cancel_admin_tagset(ctrl); + out_cleanup_queue: + if (new) +- blk_cleanup_queue(ctrl->admin_q); ++ blk_mq_destroy_queue(ctrl->admin_q); + out_cleanup_fabrics_q: + if (new) +- blk_cleanup_queue(ctrl->fabrics_q); ++ blk_mq_destroy_queue(ctrl->fabrics_q); + out_free_tagset: + if (new) + blk_mq_free_tag_set(ctrl->admin_tagset); +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index 59024af2da2e..0f5c77e22a0a 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -266,8 +266,8 @@ static void nvme_loop_destroy_admin_queue(struct nvme_loop_ctrl *ctrl) + if (!test_and_clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags)) + return; + nvmet_sq_destroy(&ctrl->queues[0].nvme_sq); +- blk_cleanup_queue(ctrl->ctrl.admin_q); +- blk_cleanup_queue(ctrl->ctrl.fabrics_q); ++ blk_mq_destroy_queue(ctrl->ctrl.admin_q); ++ blk_mq_destroy_queue(ctrl->ctrl.fabrics_q); + blk_mq_free_tag_set(&ctrl->admin_tag_set); + } + +@@ -283,7 +283,7 @@ static void nvme_loop_free_ctrl(struct nvme_ctrl *nctrl) + mutex_unlock(&nvme_loop_ctrl_mutex); + + if (nctrl->tagset) { +- blk_cleanup_queue(ctrl->ctrl.connect_q); ++ blk_mq_destroy_queue(ctrl->ctrl.connect_q); + blk_mq_free_tag_set(&ctrl->tag_set); + } + kfree(ctrl->queues); +@@ -410,9 +410,9 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl) + + out_cleanup_queue: + clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags); +- blk_cleanup_queue(ctrl->ctrl.admin_q); ++ blk_mq_destroy_queue(ctrl->ctrl.admin_q); + out_cleanup_fabrics_q: +- blk_cleanup_queue(ctrl->ctrl.fabrics_q); ++ blk_mq_destroy_queue(ctrl->ctrl.fabrics_q); + out_free_tagset: + blk_mq_free_tag_set(&ctrl->admin_tag_set); + out_free_sq: +@@ -554,7 +554,7 @@ static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl) + return 0; + + out_cleanup_connect_q: +- blk_cleanup_queue(ctrl->ctrl.connect_q); ++ blk_mq_destroy_queue(ctrl->ctrl.connect_q); + out_free_tagset: + blk_mq_free_tag_set(&ctrl->tag_set); + out_destroy_queues: +diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c +index ba6d78789660..e8489331f12b 100644 +--- a/drivers/s390/block/dasd.c ++++ b/drivers/s390/block/dasd.c +@@ -3280,7 +3280,7 @@ static int dasd_alloc_queue(struct dasd_block *block) + static void dasd_free_queue(struct dasd_block *block) + { + if (block->request_queue) { +- blk_cleanup_queue(block->request_queue); ++ blk_mq_destroy_queue(block->request_queue); + blk_mq_free_tag_set(&block->tag_set); + block->request_queue = NULL; + } +diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c +index a7a33ebf4bbe..5a83f0a39901 100644 +--- a/drivers/s390/block/dasd_genhd.c ++++ b/drivers/s390/block/dasd_genhd.c +@@ -41,8 +41,8 @@ int dasd_gendisk_alloc(struct dasd_block *block) + if (base->devindex >= DASD_PER_MAJOR) + return -EBUSY; + +- gdp = __alloc_disk_node(block->request_queue, NUMA_NO_NODE, +- &dasd_bio_compl_lkclass); ++ gdp = blk_mq_alloc_disk_for_queue(block->request_queue, ++ &dasd_bio_compl_lkclass); + if (!gdp) + return -ENOMEM; + +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index f5c876d03c1a..0a267d6e2f7c 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -168,7 +168,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) + * Requeue this command. It will go before all other commands + * that are already in the queue. Schedule requeue work under + * lock such that the kblockd_schedule_work() call happens +- * before blk_cleanup_queue() finishes. ++ * before blk_mq_destroy_queue() finishes. + */ + cmd->result = 0; + +@@ -429,9 +429,9 @@ static void scsi_starved_list_run(struct Scsi_Host *shost) + * it and the queue. Mitigate by taking a reference to the + * queue and never touching the sdev again after we drop the + * host lock. Note: if __scsi_remove_device() invokes +- * blk_cleanup_queue() before the queue is run from this ++ * blk_mq_destroy_queue() before the queue is run from this + * function then blk_run_queue() will return immediately since +- * blk_cleanup_queue() marks the queue with QUEUE_FLAG_DYING. ++ * blk_mq_destroy_queue() marks the queue with QUEUE_FLAG_DYING. + */ + slq = sdev->request_queue; + if (!blk_get_queue(slq)) +diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c +index 43949798a2e4..aa70d9282161 100644 +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -1475,7 +1475,7 @@ void __scsi_remove_device(struct scsi_device *sdev) + scsi_device_set_state(sdev, SDEV_DEL); + mutex_unlock(&sdev->state_mutex); + +- blk_cleanup_queue(sdev->request_queue); ++ blk_mq_destroy_queue(sdev->request_queue); + cancel_work_sync(&sdev->requeue_work); + + if (sdev->host->hostt->slave_destroy) +diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c +index a1a2ac09066f..cb587e488601 100644 +--- a/drivers/scsi/sd.c ++++ b/drivers/scsi/sd.c +@@ -3440,8 +3440,8 @@ static int sd_probe(struct device *dev) + if (!sdkp) + goto out; + +- gd = __alloc_disk_node(sdp->request_queue, NUMA_NO_NODE, +- &sd_bio_compl_lkclass); ++ gd = blk_mq_alloc_disk_for_queue(sdp->request_queue, ++ &sd_bio_compl_lkclass); + if (!gd) + goto out_free; + +diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c +index 32d3b8274f14..a278b739d0c5 100644 +--- a/drivers/scsi/sr.c ++++ b/drivers/scsi/sr.c +@@ -624,8 +624,8 @@ static int sr_probe(struct device *dev) + if (!cd) + goto fail; + +- disk = __alloc_disk_node(sdev->request_queue, NUMA_NO_NODE, +- &sr_bio_compl_lkclass); ++ disk = blk_mq_alloc_disk_for_queue(sdev->request_queue, ++ &sr_bio_compl_lkclass); + if (!disk) + goto fail_free; + mutex_init(&cd->lock); +diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c +index 829da9cb14a8..55bb0d0422d5 100644 +--- a/drivers/ufs/core/ufshcd.c ++++ b/drivers/ufs/core/ufshcd.c +@@ -9519,7 +9519,7 @@ void ufshcd_remove(struct ufs_hba *hba) + ufs_bsg_remove(hba); + ufshpb_remove(hba); + ufs_sysfs_remove_nodes(hba->dev); +- blk_cleanup_queue(hba->tmf_queue); ++ blk_mq_destroy_queue(hba->tmf_queue); + blk_mq_free_tag_set(&hba->tmf_tag_set); + scsi_remove_host(hba->host); + /* disable interrupts */ +@@ -9815,7 +9815,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) + return 0; + + free_tmf_queue: +- blk_cleanup_queue(hba->tmf_queue); ++ blk_mq_destroy_queue(hba->tmf_queue); + free_tmf_tag_set: + blk_mq_free_tag_set(&hba->tmf_tag_set); + out_remove_scsi_host: +diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h +index e2d9daf7e8dd..0fd96e92c6c6 100644 +--- a/include/linux/blk-mq.h ++++ b/include/linux/blk-mq.h +@@ -686,10 +686,13 @@ struct gendisk *__blk_mq_alloc_disk(struct blk_mq_tag_set *set, void *queuedata, + \ + __blk_mq_alloc_disk(set, queuedata, &__key); \ + }) ++struct gendisk *blk_mq_alloc_disk_for_queue(struct request_queue *q, ++ struct lock_class_key *lkclass); + struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *); + int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, + struct request_queue *q); + void blk_mq_unregister_dev(struct device *, struct request_queue *); ++void blk_mq_destroy_queue(struct request_queue *); + + int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set); + int blk_mq_alloc_sq_tag_set(struct blk_mq_tag_set *set, +diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h +index 76f77eed58c3..83eb8869a8c9 100644 +--- a/include/linux/blkdev.h ++++ b/include/linux/blkdev.h +@@ -148,6 +148,7 @@ struct gendisk { + #define GD_NATIVE_CAPACITY 3 + #define GD_ADDED 4 + #define GD_SUPPRESS_PART_SCAN 5 ++#define GD_OWNS_QUEUE 6 + + struct mutex open_mutex; /* open/close mutex */ + unsigned open_partitions; /* number of open partitions */ +@@ -810,8 +811,6 @@ static inline u64 sb_bdev_nr_blocks(struct super_block *sb) + + int bdev_disk_changed(struct gendisk *disk, bool invalidate); + +-struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, +- struct lock_class_key *lkclass); + void put_disk(struct gendisk *disk); + struct gendisk *__blk_alloc_disk(int node, struct lock_class_key *lkclass); + +@@ -953,7 +952,6 @@ static inline unsigned int blk_max_size_offset(struct request_queue *q, + /* + * Access functions for manipulating queue properties + */ +-extern void blk_cleanup_queue(struct request_queue *); + void blk_queue_bounce_limit(struct request_queue *q, enum blk_bounce limit); + extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); + extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int); +-- +2.35.1 + diff --git a/queue-5.19/block-stop-setting-the-nomerges-flags-in-blk_cleanup.patch b/queue-5.19/block-stop-setting-the-nomerges-flags-in-blk_cleanup.patch new file mode 100644 index 00000000000..3c814a05b73 --- /dev/null +++ b/queue-5.19/block-stop-setting-the-nomerges-flags-in-blk_cleanup.patch @@ -0,0 +1,40 @@ +From 5968f92808e5a6ceca57cd07186e2de9aff90f08 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 19 Jun 2022 08:05:50 +0200 +Subject: block: stop setting the nomerges flags in blk_cleanup_queue + +From: Christoph Hellwig + +[ Upstream commit 0e3534022f26ae51f7cf28347a253230604b6f4e ] + +These flags only apply to file system I/O, and all file system I/O is +already drained by del_gendisk and thus can't be in progress when +blk_cleanup_queue is called. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Link: https://lore.kernel.org/r/20220619060552.1850436-5-hch@lst.de +Signed-off-by: Jens Axboe +Stable-dep-of: 8fe4ce5836e9 ("scsi: core: Fix a use-after-free") +Signed-off-by: Sasha Levin +--- + block/blk-core.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/block/blk-core.c b/block/blk-core.c +index 76f070c3a3b0..b8083decc07f 100644 +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -304,9 +304,6 @@ void blk_cleanup_queue(struct request_queue *q) + blk_queue_flag_set(QUEUE_FLAG_DYING, q); + blk_queue_start_drain(q); + +- blk_queue_flag_set(QUEUE_FLAG_NOMERGES, q); +- blk_queue_flag_set(QUEUE_FLAG_NOXMERGES, q); +- + /* + * Drain all requests queued before DYING marking. Set DEAD flag to + * prevent that blk_mq_run_hw_queues() accesses the hardware queues +-- +2.35.1 + diff --git a/queue-5.19/drm-i915-bios-split-parse_driver_features-into-two-p.patch b/queue-5.19/drm-i915-bios-split-parse_driver_features-into-two-p.patch new file mode 100644 index 00000000000..4daa516519f --- /dev/null +++ b/queue-5.19/drm-i915-bios-split-parse_driver_features-into-two-p.patch @@ -0,0 +1,58 @@ +From 1438bd4f63cae6ca04173ee98b4350f7190c554d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 May 2022 13:42:37 +0300 +Subject: drm/i915/bios: Split parse_driver_features() into two parts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit c3fbcf60bc74b630967f291f47f0d9d0de6fcea7 ] + +We use the "driver features" block for two different kinds +of data: global data, and per panel data. Split the function +into two parts along that line so that we can start doing the +parsing in two different locations. + +Reviewed-by: Jani Nikula +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-11-ville.syrjala@linux.intel.com +Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_bios.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c +index 91caf4523b34..5ceabc380808 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.c ++++ b/drivers/gpu/drm/i915/display/intel_bios.c +@@ -1188,6 +1188,16 @@ parse_driver_features(struct drm_i915_private *i915) + driver->lvds_config != BDB_DRIVER_FEATURE_INT_SDVO_LVDS) + i915->vbt.int_lvds_support = 0; + } ++} ++ ++static void ++parse_panel_driver_features(struct drm_i915_private *i915) ++{ ++ const struct bdb_driver_features *driver; ++ ++ driver = find_section(i915, BDB_DRIVER_FEATURES); ++ if (!driver) ++ return; + + if (i915->vbt.version < 228) { + drm_dbg_kms(&i915->drm, "DRRS State Enabled:%d\n", +@@ -2965,6 +2975,7 @@ void intel_bios_init(struct drm_i915_private *i915) + parse_lfp_backlight(i915); + parse_sdvo_panel_data(i915); + parse_driver_features(i915); ++ parse_panel_driver_features(i915); + parse_power_conservation_features(i915); + parse_edp(i915); + parse_psr(i915); +-- +2.35.1 + diff --git a/queue-5.19/drm-i915-bios-split-vbt-data-into-per-panel-vs.-glob.patch b/queue-5.19/drm-i915-bios-split-vbt-data-into-per-panel-vs.-glob.patch new file mode 100644 index 00000000000..db312f4d8a1 --- /dev/null +++ b/queue-5.19/drm-i915-bios-split-vbt-data-into-per-panel-vs.-glob.patch @@ -0,0 +1,1969 @@ +From 22bc5f164a8d11123afb423e73f891069d3a5e3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 May 2022 13:42:39 +0300 +Subject: drm/i915/bios: Split VBT data into per-panel vs. global parts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 3cf050762534cc268a02793ec00240f81c6e2229 ] + +Move the panel specific VBT parsing to happen during the +output probing stage. Needs to be done because the VBT +parsing will need to look at the EDID to determine +the correct panel_type on some machines. + +We split the parsed VBT data (i915->vbt) along the same +boundary. For the moment we just hoist all the panel +specific stuff into connector->panel.vbt since that seems +like the most convenient place for eg. the backlight code. + +Note that we simply drop the drrs type check from +intel_drrs_frontbuffer_update() since that operates on the whole +device rather than a specific connector/encoder. But the check +was just a micro optimization so removing it doesn't actually +mattter for correctness. + +TODO: Lot's of cleanup to be done in the future. Eg. most of +the DSI stuff could probably be eliminated entirely and just +parsed on demand during DSI init. + +v2: Note the intel_drrs_frontbuffer_update() change + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-13-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/icl_dsi.c | 11 +- + .../gpu/drm/i915/display/intel_backlight.c | 23 +- + drivers/gpu/drm/i915/display/intel_bios.c | 371 ++++++++++-------- + drivers/gpu/drm/i915/display/intel_bios.h | 5 +- + .../drm/i915/display/intel_ddi_buf_trans.c | 9 +- + drivers/gpu/drm/i915/display/intel_display.c | 1 - + .../drm/i915/display/intel_display_types.h | 69 ++++ + drivers/gpu/drm/i915/display/intel_dp.c | 21 +- + drivers/gpu/drm/i915/display/intel_dp.h | 1 + + .../drm/i915/display/intel_dp_aux_backlight.c | 6 +- + drivers/gpu/drm/i915/display/intel_drrs.c | 3 - + drivers/gpu/drm/i915/display/intel_dsi.c | 2 +- + .../i915/display/intel_dsi_dcs_backlight.c | 9 +- + drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 56 +-- + drivers/gpu/drm/i915/display/intel_lvds.c | 6 +- + drivers/gpu/drm/i915/display/intel_panel.c | 13 +- + drivers/gpu/drm/i915/display/intel_pps.c | 6 +- + drivers/gpu/drm/i915/display/intel_psr.c | 30 +- + drivers/gpu/drm/i915/display/intel_sdvo.c | 3 + + drivers/gpu/drm/i915/display/vlv_dsi.c | 14 +- + drivers/gpu/drm/i915/i915_drv.h | 63 --- + 21 files changed, 391 insertions(+), 331 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c +index 5508ebb9eb43..5c46acb46516 100644 +--- a/drivers/gpu/drm/i915/display/icl_dsi.c ++++ b/drivers/gpu/drm/i915/display/icl_dsi.c +@@ -1864,7 +1864,8 @@ static void icl_dphy_param_init(struct intel_dsi *intel_dsi) + { + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); +- struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; ++ struct intel_connector *connector = intel_dsi->attached_connector; ++ struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; + u32 tlpx_ns; + u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt; + u32 ths_prepare_ns, tclk_trail_ns; +@@ -2051,6 +2052,8 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) + /* attach connector to encoder */ + intel_connector_attach_encoder(intel_connector, encoder); + ++ intel_bios_init_panel(dev_priv, &intel_connector->panel); ++ + mutex_lock(&dev->mode_config.mutex); + intel_panel_add_vbt_lfp_fixed_mode(intel_connector); + mutex_unlock(&dev->mode_config.mutex); +@@ -2064,13 +2067,13 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) + + intel_backlight_setup(intel_connector, INVALID_PIPE); + +- if (dev_priv->vbt.dsi.config->dual_link) ++ if (intel_connector->panel.vbt.dsi.config->dual_link) + intel_dsi->ports = BIT(PORT_A) | BIT(PORT_B); + else + intel_dsi->ports = BIT(port); + +- intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports; +- intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports; ++ intel_dsi->dcs_backlight_ports = intel_connector->panel.vbt.dsi.bl_ports; ++ intel_dsi->dcs_cabc_ports = intel_connector->panel.vbt.dsi.cabc_ports; + + for_each_dsi_port(port, intel_dsi->ports) { + struct intel_dsi_host *host; +diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c +index 3e200a2e4ba2..5182bb66bd28 100644 +--- a/drivers/gpu/drm/i915/display/intel_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_backlight.c +@@ -1158,9 +1158,10 @@ static u32 vlv_hz_to_pwm(struct intel_connector *connector, u32 pwm_freq_hz) + return DIV_ROUND_CLOSEST(clock, pwm_freq_hz * mul); + } + +-static u16 get_vbt_pwm_freq(struct drm_i915_private *dev_priv) ++static u16 get_vbt_pwm_freq(struct intel_connector *connector) + { +- u16 pwm_freq_hz = dev_priv->vbt.backlight.pwm_freq_hz; ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ u16 pwm_freq_hz = connector->panel.vbt.backlight.pwm_freq_hz; + + if (pwm_freq_hz) { + drm_dbg_kms(&dev_priv->drm, +@@ -1180,7 +1181,7 @@ static u32 get_backlight_max_vbt(struct intel_connector *connector) + { + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_panel *panel = &connector->panel; +- u16 pwm_freq_hz = get_vbt_pwm_freq(dev_priv); ++ u16 pwm_freq_hz = get_vbt_pwm_freq(connector); + u32 pwm; + + if (!panel->backlight.pwm_funcs->hz_to_pwm) { +@@ -1217,11 +1218,11 @@ static u32 get_backlight_min_vbt(struct intel_connector *connector) + * against this by letting the minimum be at most (arbitrarily chosen) + * 25% of the max. + */ +- min = clamp_t(int, dev_priv->vbt.backlight.min_brightness, 0, 64); +- if (min != dev_priv->vbt.backlight.min_brightness) { ++ min = clamp_t(int, connector->panel.vbt.backlight.min_brightness, 0, 64); ++ if (min != connector->panel.vbt.backlight.min_brightness) { + drm_dbg_kms(&dev_priv->drm, + "clamping VBT min backlight %d/255 to %d/255\n", +- dev_priv->vbt.backlight.min_brightness, min); ++ connector->panel.vbt.backlight.min_brightness, min); + } + + /* vbt value is a coefficient in range [0..255] */ +@@ -1410,7 +1411,7 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) + struct intel_panel *panel = &connector->panel; + u32 pwm_ctl, val; + +- panel->backlight.controller = dev_priv->vbt.backlight.controller; ++ panel->backlight.controller = connector->panel.vbt.backlight.controller; + + pwm_ctl = intel_de_read(dev_priv, + BXT_BLC_PWM_CTL(panel->backlight.controller)); +@@ -1483,7 +1484,7 @@ static int ext_pwm_setup_backlight(struct intel_connector *connector, + u32 level; + + /* Get the right PWM chip for DSI backlight according to VBT */ +- if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { ++ if (connector->panel.vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { + panel->backlight.pwm = pwm_get(dev->dev, "pwm_pmic_backlight"); + desc = "PMIC"; + } else { +@@ -1512,11 +1513,11 @@ static int ext_pwm_setup_backlight(struct intel_connector *connector, + + drm_dbg_kms(&dev_priv->drm, "PWM already enabled at freq %ld, VBT freq %d, level %d\n", + NSEC_PER_SEC / (unsigned long)panel->backlight.pwm_state.period, +- get_vbt_pwm_freq(dev_priv), level); ++ get_vbt_pwm_freq(connector), level); + } else { + /* Set period from VBT frequency, leave other settings at 0. */ + panel->backlight.pwm_state.period = +- NSEC_PER_SEC / get_vbt_pwm_freq(dev_priv); ++ NSEC_PER_SEC / get_vbt_pwm_freq(connector); + } + + drm_info(&dev_priv->drm, "Using %s PWM for LCD backlight control\n", +@@ -1601,7 +1602,7 @@ int intel_backlight_setup(struct intel_connector *connector, enum pipe pipe) + struct intel_panel *panel = &connector->panel; + int ret; + +- if (!dev_priv->vbt.backlight.present) { ++ if (!connector->panel.vbt.backlight.present) { + if (dev_priv->quirks & QUIRK_BACKLIGHT_PRESENT) { + drm_dbg_kms(&dev_priv->drm, + "no backlight present per VBT, but present per quirk\n"); +diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c +index d5cae64b916b..d5d20a44f373 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.c ++++ b/drivers/gpu/drm/i915/display/intel_bios.c +@@ -682,7 +682,8 @@ static int get_panel_type(struct drm_i915_private *i915) + + /* Parse general panel options */ + static void +-parse_panel_options(struct drm_i915_private *i915) ++parse_panel_options(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_lvds_options *lvds_options; + int panel_type; +@@ -692,11 +693,11 @@ parse_panel_options(struct drm_i915_private *i915) + if (!lvds_options) + return; + +- i915->vbt.lvds_dither = lvds_options->pixel_dither; ++ panel->vbt.lvds_dither = lvds_options->pixel_dither; + + panel_type = get_panel_type(i915); + +- i915->vbt.panel_type = panel_type; ++ panel->vbt.panel_type = panel_type; + + drrs_mode = (lvds_options->dps_panel_type_bits + >> (panel_type * 2)) & MODE_MASK; +@@ -707,16 +708,16 @@ parse_panel_options(struct drm_i915_private *i915) + */ + switch (drrs_mode) { + case 0: +- i915->vbt.drrs_type = DRRS_TYPE_STATIC; ++ panel->vbt.drrs_type = DRRS_TYPE_STATIC; + drm_dbg_kms(&i915->drm, "DRRS supported mode is static\n"); + break; + case 2: +- i915->vbt.drrs_type = DRRS_TYPE_SEAMLESS; ++ panel->vbt.drrs_type = DRRS_TYPE_SEAMLESS; + drm_dbg_kms(&i915->drm, + "DRRS supported mode is seamless\n"); + break; + default: +- i915->vbt.drrs_type = DRRS_TYPE_NONE; ++ panel->vbt.drrs_type = DRRS_TYPE_NONE; + drm_dbg_kms(&i915->drm, + "DRRS not supported (VBT input)\n"); + break; +@@ -725,13 +726,14 @@ parse_panel_options(struct drm_i915_private *i915) + + static void + parse_lfp_panel_dtd(struct drm_i915_private *i915, ++ struct intel_panel *panel, + const struct bdb_lvds_lfp_data *lvds_lfp_data, + const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs) + { + const struct lvds_dvo_timing *panel_dvo_timing; + const struct lvds_fp_timing *fp_timing; + struct drm_display_mode *panel_fixed_mode; +- int panel_type = i915->vbt.panel_type; ++ int panel_type = panel->vbt.panel_type; + + panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, + lvds_lfp_data_ptrs, +@@ -743,7 +745,7 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, + + fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing); + +- i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; ++ panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; + + drm_dbg_kms(&i915->drm, + "Found panel mode in BIOS VBT legacy lfp table: " DRM_MODE_FMT "\n", +@@ -756,20 +758,21 @@ parse_lfp_panel_dtd(struct drm_i915_private *i915, + /* check the resolution, just to be sure */ + if (fp_timing->x_res == panel_fixed_mode->hdisplay && + fp_timing->y_res == panel_fixed_mode->vdisplay) { +- i915->vbt.bios_lvds_val = fp_timing->lvds_reg_val; ++ panel->vbt.bios_lvds_val = fp_timing->lvds_reg_val; + drm_dbg_kms(&i915->drm, + "VBT initial LVDS value %x\n", +- i915->vbt.bios_lvds_val); ++ panel->vbt.bios_lvds_val); + } + } + + static void +-parse_lfp_data(struct drm_i915_private *i915) ++parse_lfp_data(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_lvds_lfp_data *data; + const struct bdb_lvds_lfp_data_tail *tail; + const struct bdb_lvds_lfp_data_ptrs *ptrs; +- int panel_type = i915->vbt.panel_type; ++ int panel_type = panel->vbt.panel_type; + + ptrs = find_section(i915, BDB_LVDS_LFP_DATA_PTRS); + if (!ptrs) +@@ -779,24 +782,25 @@ parse_lfp_data(struct drm_i915_private *i915) + if (!data) + return; + +- if (!i915->vbt.lfp_lvds_vbt_mode) +- parse_lfp_panel_dtd(i915, data, ptrs); ++ if (!panel->vbt.lfp_lvds_vbt_mode) ++ parse_lfp_panel_dtd(i915, panel, data, ptrs); + + tail = get_lfp_data_tail(data, ptrs); + if (!tail) + return; + + if (i915->vbt.version >= 188) { +- i915->vbt.seamless_drrs_min_refresh_rate = ++ panel->vbt.seamless_drrs_min_refresh_rate = + tail->seamless_drrs_min_refresh_rate[panel_type]; + drm_dbg_kms(&i915->drm, + "Seamless DRRS min refresh rate: %d Hz\n", +- i915->vbt.seamless_drrs_min_refresh_rate); ++ panel->vbt.seamless_drrs_min_refresh_rate); + } + } + + static void +-parse_generic_dtd(struct drm_i915_private *i915) ++parse_generic_dtd(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_generic_dtd *generic_dtd; + const struct generic_dtd_entry *dtd; +@@ -831,14 +835,14 @@ parse_generic_dtd(struct drm_i915_private *i915) + + num_dtd = (get_blocksize(generic_dtd) - + sizeof(struct bdb_generic_dtd)) / generic_dtd->gdtd_size; +- if (i915->vbt.panel_type >= num_dtd) { ++ if (panel->vbt.panel_type >= num_dtd) { + drm_err(&i915->drm, + "Panel type %d not found in table of %d DTD's\n", +- i915->vbt.panel_type, num_dtd); ++ panel->vbt.panel_type, num_dtd); + return; + } + +- dtd = &generic_dtd->dtd[i915->vbt.panel_type]; ++ dtd = &generic_dtd->dtd[panel->vbt.panel_type]; + + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); + if (!panel_fixed_mode) +@@ -881,15 +885,16 @@ parse_generic_dtd(struct drm_i915_private *i915) + "Found panel mode in BIOS VBT generic dtd table: " DRM_MODE_FMT "\n", + DRM_MODE_ARG(panel_fixed_mode)); + +- i915->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; ++ panel->vbt.lfp_lvds_vbt_mode = panel_fixed_mode; + } + + static void +-parse_lfp_backlight(struct drm_i915_private *i915) ++parse_lfp_backlight(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_lfp_backlight_data *backlight_data; + const struct lfp_backlight_data_entry *entry; +- int panel_type = i915->vbt.panel_type; ++ int panel_type = panel->vbt.panel_type; + u16 level; + + backlight_data = find_section(i915, BDB_LVDS_BACKLIGHT); +@@ -905,15 +910,15 @@ parse_lfp_backlight(struct drm_i915_private *i915) + + entry = &backlight_data->data[panel_type]; + +- i915->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; +- if (!i915->vbt.backlight.present) { ++ panel->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; ++ if (!panel->vbt.backlight.present) { + drm_dbg_kms(&i915->drm, + "PWM backlight not present in VBT (type %u)\n", + entry->type); + return; + } + +- i915->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; ++ panel->vbt.backlight.type = INTEL_BACKLIGHT_DISPLAY_DDI; + if (i915->vbt.version >= 191) { + size_t exp_size; + +@@ -928,13 +933,13 @@ parse_lfp_backlight(struct drm_i915_private *i915) + const struct lfp_backlight_control_method *method; + + method = &backlight_data->backlight_control[panel_type]; +- i915->vbt.backlight.type = method->type; +- i915->vbt.backlight.controller = method->controller; ++ panel->vbt.backlight.type = method->type; ++ panel->vbt.backlight.controller = method->controller; + } + } + +- i915->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; +- i915->vbt.backlight.active_low_pwm = entry->active_low_pwm; ++ panel->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; ++ panel->vbt.backlight.active_low_pwm = entry->active_low_pwm; + + if (i915->vbt.version >= 234) { + u16 min_level; +@@ -955,28 +960,29 @@ parse_lfp_backlight(struct drm_i915_private *i915) + drm_warn(&i915->drm, "Brightness min level > 255\n"); + level = 255; + } +- i915->vbt.backlight.min_brightness = min_level; ++ panel->vbt.backlight.min_brightness = min_level; + +- i915->vbt.backlight.brightness_precision_bits = ++ panel->vbt.backlight.brightness_precision_bits = + backlight_data->brightness_precision_bits[panel_type]; + } else { + level = backlight_data->level[panel_type]; +- i915->vbt.backlight.min_brightness = entry->min_brightness; ++ panel->vbt.backlight.min_brightness = entry->min_brightness; + } + + drm_dbg_kms(&i915->drm, + "VBT backlight PWM modulation frequency %u Hz, " + "active %s, min brightness %u, level %u, controller %u\n", +- i915->vbt.backlight.pwm_freq_hz, +- i915->vbt.backlight.active_low_pwm ? "low" : "high", +- i915->vbt.backlight.min_brightness, ++ panel->vbt.backlight.pwm_freq_hz, ++ panel->vbt.backlight.active_low_pwm ? "low" : "high", ++ panel->vbt.backlight.min_brightness, + level, +- i915->vbt.backlight.controller); ++ panel->vbt.backlight.controller); + } + + /* Try to find sdvo panel data */ + static void +-parse_sdvo_panel_data(struct drm_i915_private *i915) ++parse_sdvo_panel_data(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_sdvo_panel_dtds *dtds; + struct drm_display_mode *panel_fixed_mode; +@@ -1009,7 +1015,7 @@ parse_sdvo_panel_data(struct drm_i915_private *i915) + + fill_detail_timing_data(panel_fixed_mode, &dtds->dtds[index]); + +- i915->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; ++ panel->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode; + + drm_dbg_kms(&i915->drm, + "Found SDVO panel mode in BIOS VBT tables: " DRM_MODE_FMT "\n", +@@ -1191,7 +1197,8 @@ parse_driver_features(struct drm_i915_private *i915) + } + + static void +-parse_panel_driver_features(struct drm_i915_private *i915) ++parse_panel_driver_features(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_driver_features *driver; + +@@ -1209,17 +1216,18 @@ parse_panel_driver_features(struct drm_i915_private *i915) + * driver->drrs_enabled=false + */ + if (!driver->drrs_enabled) +- i915->vbt.drrs_type = DRRS_TYPE_NONE; ++ panel->vbt.drrs_type = DRRS_TYPE_NONE; + +- i915->vbt.psr.enable = driver->psr_enabled; ++ panel->vbt.psr.enable = driver->psr_enabled; + } + } + + static void +-parse_power_conservation_features(struct drm_i915_private *i915) ++parse_power_conservation_features(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_lfp_power *power; +- u8 panel_type = i915->vbt.panel_type; ++ u8 panel_type = panel->vbt.panel_type; + + if (i915->vbt.version < 228) + return; +@@ -1228,7 +1236,7 @@ parse_power_conservation_features(struct drm_i915_private *i915) + if (!power) + return; + +- i915->vbt.psr.enable = power->psr & BIT(panel_type); ++ panel->vbt.psr.enable = power->psr & BIT(panel_type); + + /* + * If DRRS is not supported, drrs_type has to be set to 0. +@@ -1237,19 +1245,20 @@ parse_power_conservation_features(struct drm_i915_private *i915) + * power->drrs & BIT(panel_type)=false + */ + if (!(power->drrs & BIT(panel_type))) +- i915->vbt.drrs_type = DRRS_TYPE_NONE; ++ panel->vbt.drrs_type = DRRS_TYPE_NONE; + + if (i915->vbt.version >= 232) +- i915->vbt.edp.hobl = power->hobl & BIT(panel_type); ++ panel->vbt.edp.hobl = power->hobl & BIT(panel_type); + } + + static void +-parse_edp(struct drm_i915_private *i915) ++parse_edp(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_edp *edp; + const struct edp_power_seq *edp_pps; + const struct edp_fast_link_params *edp_link_params; +- int panel_type = i915->vbt.panel_type; ++ int panel_type = panel->vbt.panel_type; + + edp = find_section(i915, BDB_EDP); + if (!edp) +@@ -1257,13 +1266,13 @@ parse_edp(struct drm_i915_private *i915) + + switch ((edp->color_depth >> (panel_type * 2)) & 3) { + case EDP_18BPP: +- i915->vbt.edp.bpp = 18; ++ panel->vbt.edp.bpp = 18; + break; + case EDP_24BPP: +- i915->vbt.edp.bpp = 24; ++ panel->vbt.edp.bpp = 24; + break; + case EDP_30BPP: +- i915->vbt.edp.bpp = 30; ++ panel->vbt.edp.bpp = 30; + break; + } + +@@ -1271,14 +1280,14 @@ parse_edp(struct drm_i915_private *i915) + edp_pps = &edp->power_seqs[panel_type]; + edp_link_params = &edp->fast_link_params[panel_type]; + +- i915->vbt.edp.pps = *edp_pps; ++ panel->vbt.edp.pps = *edp_pps; + + switch (edp_link_params->rate) { + case EDP_RATE_1_62: +- i915->vbt.edp.rate = DP_LINK_BW_1_62; ++ panel->vbt.edp.rate = DP_LINK_BW_1_62; + break; + case EDP_RATE_2_7: +- i915->vbt.edp.rate = DP_LINK_BW_2_7; ++ panel->vbt.edp.rate = DP_LINK_BW_2_7; + break; + default: + drm_dbg_kms(&i915->drm, +@@ -1289,13 +1298,13 @@ parse_edp(struct drm_i915_private *i915) + + switch (edp_link_params->lanes) { + case EDP_LANE_1: +- i915->vbt.edp.lanes = 1; ++ panel->vbt.edp.lanes = 1; + break; + case EDP_LANE_2: +- i915->vbt.edp.lanes = 2; ++ panel->vbt.edp.lanes = 2; + break; + case EDP_LANE_4: +- i915->vbt.edp.lanes = 4; ++ panel->vbt.edp.lanes = 4; + break; + default: + drm_dbg_kms(&i915->drm, +@@ -1306,16 +1315,16 @@ parse_edp(struct drm_i915_private *i915) + + switch (edp_link_params->preemphasis) { + case EDP_PREEMPHASIS_NONE: +- i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0; ++ panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_0; + break; + case EDP_PREEMPHASIS_3_5dB: +- i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1; ++ panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_1; + break; + case EDP_PREEMPHASIS_6dB: +- i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2; ++ panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_2; + break; + case EDP_PREEMPHASIS_9_5dB: +- i915->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3; ++ panel->vbt.edp.preemphasis = DP_TRAIN_PRE_EMPH_LEVEL_3; + break; + default: + drm_dbg_kms(&i915->drm, +@@ -1326,16 +1335,16 @@ parse_edp(struct drm_i915_private *i915) + + switch (edp_link_params->vswing) { + case EDP_VSWING_0_4V: +- i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0; ++ panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_0; + break; + case EDP_VSWING_0_6V: +- i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1; ++ panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_1; + break; + case EDP_VSWING_0_8V: +- i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2; ++ panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_2; + break; + case EDP_VSWING_1_2V: +- i915->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3; ++ panel->vbt.edp.vswing = DP_TRAIN_VOLTAGE_SWING_LEVEL_3; + break; + default: + drm_dbg_kms(&i915->drm, +@@ -1349,24 +1358,25 @@ parse_edp(struct drm_i915_private *i915) + + /* Don't read from VBT if module parameter has valid value*/ + if (i915->params.edp_vswing) { +- i915->vbt.edp.low_vswing = ++ panel->vbt.edp.low_vswing = + i915->params.edp_vswing == 1; + } else { + vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF; +- i915->vbt.edp.low_vswing = vswing == 0; ++ panel->vbt.edp.low_vswing = vswing == 0; + } + } + +- i915->vbt.edp.drrs_msa_timing_delay = ++ panel->vbt.edp.drrs_msa_timing_delay = + (edp->sdrrs_msa_timing_delay >> (panel_type * 2)) & 3; + } + + static void +-parse_psr(struct drm_i915_private *i915) ++parse_psr(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_psr *psr; + const struct psr_table *psr_table; +- int panel_type = i915->vbt.panel_type; ++ int panel_type = panel->vbt.panel_type; + + psr = find_section(i915, BDB_PSR); + if (!psr) { +@@ -1376,11 +1386,11 @@ parse_psr(struct drm_i915_private *i915) + + psr_table = &psr->psr_table[panel_type]; + +- i915->vbt.psr.full_link = psr_table->full_link; +- i915->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup; ++ panel->vbt.psr.full_link = psr_table->full_link; ++ panel->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup; + + /* Allowed VBT values goes from 0 to 15 */ +- i915->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 : ++ panel->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 : + psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames; + + /* +@@ -1391,13 +1401,13 @@ parse_psr(struct drm_i915_private *i915) + (DISPLAY_VER(i915) >= 9 && !IS_BROXTON(i915))) { + switch (psr_table->tp1_wakeup_time) { + case 0: +- i915->vbt.psr.tp1_wakeup_time_us = 500; ++ panel->vbt.psr.tp1_wakeup_time_us = 500; + break; + case 1: +- i915->vbt.psr.tp1_wakeup_time_us = 100; ++ panel->vbt.psr.tp1_wakeup_time_us = 100; + break; + case 3: +- i915->vbt.psr.tp1_wakeup_time_us = 0; ++ panel->vbt.psr.tp1_wakeup_time_us = 0; + break; + default: + drm_dbg_kms(&i915->drm, +@@ -1405,19 +1415,19 @@ parse_psr(struct drm_i915_private *i915) + psr_table->tp1_wakeup_time); + fallthrough; + case 2: +- i915->vbt.psr.tp1_wakeup_time_us = 2500; ++ panel->vbt.psr.tp1_wakeup_time_us = 2500; + break; + } + + switch (psr_table->tp2_tp3_wakeup_time) { + case 0: +- i915->vbt.psr.tp2_tp3_wakeup_time_us = 500; ++ panel->vbt.psr.tp2_tp3_wakeup_time_us = 500; + break; + case 1: +- i915->vbt.psr.tp2_tp3_wakeup_time_us = 100; ++ panel->vbt.psr.tp2_tp3_wakeup_time_us = 100; + break; + case 3: +- i915->vbt.psr.tp2_tp3_wakeup_time_us = 0; ++ panel->vbt.psr.tp2_tp3_wakeup_time_us = 0; + break; + default: + drm_dbg_kms(&i915->drm, +@@ -1425,12 +1435,12 @@ parse_psr(struct drm_i915_private *i915) + psr_table->tp2_tp3_wakeup_time); + fallthrough; + case 2: +- i915->vbt.psr.tp2_tp3_wakeup_time_us = 2500; ++ panel->vbt.psr.tp2_tp3_wakeup_time_us = 2500; + break; + } + } else { +- i915->vbt.psr.tp1_wakeup_time_us = psr_table->tp1_wakeup_time * 100; +- i915->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100; ++ panel->vbt.psr.tp1_wakeup_time_us = psr_table->tp1_wakeup_time * 100; ++ panel->vbt.psr.tp2_tp3_wakeup_time_us = psr_table->tp2_tp3_wakeup_time * 100; + } + + if (i915->vbt.version >= 226) { +@@ -1452,62 +1462,64 @@ parse_psr(struct drm_i915_private *i915) + wakeup_time = 2500; + break; + } +- i915->vbt.psr.psr2_tp2_tp3_wakeup_time_us = wakeup_time; ++ panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = wakeup_time; + } else { + /* Reusing PSR1 wakeup time for PSR2 in older VBTs */ +- i915->vbt.psr.psr2_tp2_tp3_wakeup_time_us = i915->vbt.psr.tp2_tp3_wakeup_time_us; ++ panel->vbt.psr.psr2_tp2_tp3_wakeup_time_us = panel->vbt.psr.tp2_tp3_wakeup_time_us; + } + } + + static void parse_dsi_backlight_ports(struct drm_i915_private *i915, +- u16 version, enum port port) ++ struct intel_panel *panel, ++ enum port port) + { +- if (!i915->vbt.dsi.config->dual_link || version < 197) { +- i915->vbt.dsi.bl_ports = BIT(port); +- if (i915->vbt.dsi.config->cabc_supported) +- i915->vbt.dsi.cabc_ports = BIT(port); ++ if (!panel->vbt.dsi.config->dual_link || i915->vbt.version < 197) { ++ panel->vbt.dsi.bl_ports = BIT(port); ++ if (panel->vbt.dsi.config->cabc_supported) ++ panel->vbt.dsi.cabc_ports = BIT(port); + + return; + } + +- switch (i915->vbt.dsi.config->dl_dcs_backlight_ports) { ++ switch (panel->vbt.dsi.config->dl_dcs_backlight_ports) { + case DL_DCS_PORT_A: +- i915->vbt.dsi.bl_ports = BIT(PORT_A); ++ panel->vbt.dsi.bl_ports = BIT(PORT_A); + break; + case DL_DCS_PORT_C: +- i915->vbt.dsi.bl_ports = BIT(PORT_C); ++ panel->vbt.dsi.bl_ports = BIT(PORT_C); + break; + default: + case DL_DCS_PORT_A_AND_C: +- i915->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(PORT_C); ++ panel->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(PORT_C); + break; + } + +- if (!i915->vbt.dsi.config->cabc_supported) ++ if (!panel->vbt.dsi.config->cabc_supported) + return; + +- switch (i915->vbt.dsi.config->dl_dcs_cabc_ports) { ++ switch (panel->vbt.dsi.config->dl_dcs_cabc_ports) { + case DL_DCS_PORT_A: +- i915->vbt.dsi.cabc_ports = BIT(PORT_A); ++ panel->vbt.dsi.cabc_ports = BIT(PORT_A); + break; + case DL_DCS_PORT_C: +- i915->vbt.dsi.cabc_ports = BIT(PORT_C); ++ panel->vbt.dsi.cabc_ports = BIT(PORT_C); + break; + default: + case DL_DCS_PORT_A_AND_C: +- i915->vbt.dsi.cabc_ports = ++ panel->vbt.dsi.cabc_ports = + BIT(PORT_A) | BIT(PORT_C); + break; + } + } + + static void +-parse_mipi_config(struct drm_i915_private *i915) ++parse_mipi_config(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + const struct bdb_mipi_config *start; + const struct mipi_config *config; + const struct mipi_pps_data *pps; +- int panel_type = i915->vbt.panel_type; ++ int panel_type = panel->vbt.panel_type; + enum port port; + + /* parse MIPI blocks only if LFP type is MIPI */ +@@ -1515,7 +1527,7 @@ parse_mipi_config(struct drm_i915_private *i915) + return; + + /* Initialize this to undefined indicating no generic MIPI support */ +- i915->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; ++ panel->vbt.dsi.panel_id = MIPI_DSI_UNDEFINED_PANEL_ID; + + /* Block #40 is already parsed and panel_fixed_mode is + * stored in i915->lfp_lvds_vbt_mode +@@ -1542,17 +1554,17 @@ parse_mipi_config(struct drm_i915_private *i915) + pps = &start->pps[panel_type]; + + /* store as of now full data. Trim when we realise all is not needed */ +- i915->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); +- if (!i915->vbt.dsi.config) ++ panel->vbt.dsi.config = kmemdup(config, sizeof(struct mipi_config), GFP_KERNEL); ++ if (!panel->vbt.dsi.config) + return; + +- i915->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); +- if (!i915->vbt.dsi.pps) { +- kfree(i915->vbt.dsi.config); ++ panel->vbt.dsi.pps = kmemdup(pps, sizeof(struct mipi_pps_data), GFP_KERNEL); ++ if (!panel->vbt.dsi.pps) { ++ kfree(panel->vbt.dsi.config); + return; + } + +- parse_dsi_backlight_ports(i915, i915->vbt.version, port); ++ parse_dsi_backlight_ports(i915, panel, port); + + /* FIXME is the 90 vs. 270 correct? */ + switch (config->rotation) { +@@ -1561,25 +1573,25 @@ parse_mipi_config(struct drm_i915_private *i915) + * Most (all?) VBTs claim 0 degrees despite having + * an upside down panel, thus we do not trust this. + */ +- i915->vbt.dsi.orientation = ++ panel->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_UNKNOWN; + break; + case ENABLE_ROTATION_90: +- i915->vbt.dsi.orientation = ++ panel->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_RIGHT_UP; + break; + case ENABLE_ROTATION_180: +- i915->vbt.dsi.orientation = ++ panel->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP; + break; + case ENABLE_ROTATION_270: +- i915->vbt.dsi.orientation = ++ panel->vbt.dsi.orientation = + DRM_MODE_PANEL_ORIENTATION_LEFT_UP; + break; + } + + /* We have mandatory mipi config blocks. Initialize as generic panel */ +- i915->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; ++ panel->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID; + } + + /* Find the sequence block and size for the given panel. */ +@@ -1742,13 +1754,14 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total) + * Get len of pre-fixed deassert fragment from a v1 init OTP sequence, + * skip all delay + gpio operands and stop at the first DSI packet op. + */ +-static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915) ++static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { +- const u8 *data = i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; ++ const u8 *data = panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; + int index, len; + + if (drm_WARN_ON(&i915->drm, +- !data || i915->vbt.dsi.seq_version != 1)) ++ !data || panel->vbt.dsi.seq_version != 1)) + return 0; + + /* index = 1 to skip sequence byte */ +@@ -1776,7 +1789,8 @@ static int get_init_otp_deassert_fragment_len(struct drm_i915_private *i915) + * these devices we split the init OTP sequence into a deassert sequence and + * the actual init OTP part. + */ +-static void fixup_mipi_sequences(struct drm_i915_private *i915) ++static void fixup_mipi_sequences(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { + u8 *init_otp; + int len; +@@ -1786,18 +1800,18 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915) + return; + + /* Limit this to v1 vid-mode sequences */ +- if (i915->vbt.dsi.config->is_cmd_mode || +- i915->vbt.dsi.seq_version != 1) ++ if (panel->vbt.dsi.config->is_cmd_mode || ++ panel->vbt.dsi.seq_version != 1) + return; + + /* Only do this if there are otp and assert seqs and no deassert seq */ +- if (!i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] || +- !i915->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] || +- i915->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) ++ if (!panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] || ++ !panel->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] || ++ panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) + return; + + /* The deassert-sequence ends at the first DSI packet */ +- len = get_init_otp_deassert_fragment_len(i915); ++ len = get_init_otp_deassert_fragment_len(i915, panel); + if (!len) + return; + +@@ -1805,25 +1819,26 @@ static void fixup_mipi_sequences(struct drm_i915_private *i915) + "Using init OTP fragment to deassert reset\n"); + + /* Copy the fragment, update seq byte and terminate it */ +- init_otp = (u8 *)i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; +- i915->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL); +- if (!i915->vbt.dsi.deassert_seq) ++ init_otp = (u8 *)panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP]; ++ panel->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL); ++ if (!panel->vbt.dsi.deassert_seq) + return; +- i915->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET; +- i915->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END; ++ panel->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET; ++ panel->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END; + /* Use the copy for deassert */ +- i915->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] = +- i915->vbt.dsi.deassert_seq; ++ panel->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] = ++ panel->vbt.dsi.deassert_seq; + /* Replace the last byte of the fragment with init OTP seq byte */ + init_otp[len - 1] = MIPI_SEQ_INIT_OTP; + /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */ +- i915->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1; ++ panel->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1; + } + + static void +-parse_mipi_sequence(struct drm_i915_private *i915) ++parse_mipi_sequence(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { +- int panel_type = i915->vbt.panel_type; ++ int panel_type = panel->vbt.panel_type; + const struct bdb_mipi_sequence *sequence; + const u8 *seq_data; + u32 seq_size; +@@ -1831,7 +1846,7 @@ parse_mipi_sequence(struct drm_i915_private *i915) + int index = 0; + + /* Only our generic panel driver uses the sequence block. */ +- if (i915->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID) ++ if (panel->vbt.dsi.panel_id != MIPI_DSI_GENERIC_PANEL_ID) + return; + + sequence = find_section(i915, BDB_MIPI_SEQUENCE); +@@ -1877,7 +1892,7 @@ parse_mipi_sequence(struct drm_i915_private *i915) + drm_dbg_kms(&i915->drm, + "Unsupported sequence %u\n", seq_id); + +- i915->vbt.dsi.sequence[seq_id] = data + index; ++ panel->vbt.dsi.sequence[seq_id] = data + index; + + if (sequence->version >= 3) + index = goto_next_sequence_v3(data, index, seq_size); +@@ -1890,18 +1905,18 @@ parse_mipi_sequence(struct drm_i915_private *i915) + } + } + +- i915->vbt.dsi.data = data; +- i915->vbt.dsi.size = seq_size; +- i915->vbt.dsi.seq_version = sequence->version; ++ panel->vbt.dsi.data = data; ++ panel->vbt.dsi.size = seq_size; ++ panel->vbt.dsi.seq_version = sequence->version; + +- fixup_mipi_sequences(i915); ++ fixup_mipi_sequences(i915, panel); + + drm_dbg(&i915->drm, "MIPI related VBT parsing complete\n"); + return; + + err: + kfree(data); +- memset(i915->vbt.dsi.sequence, 0, sizeof(i915->vbt.dsi.sequence)); ++ memset(panel->vbt.dsi.sequence, 0, sizeof(panel->vbt.dsi.sequence)); + } + + static void +@@ -2655,15 +2670,6 @@ init_vbt_defaults(struct drm_i915_private *i915) + { + i915->vbt.crt_ddc_pin = GMBUS_PIN_VGADDC; + +- /* Default to having backlight */ +- i915->vbt.backlight.present = true; +- +- /* LFP panel data */ +- i915->vbt.lvds_dither = 1; +- +- /* SDVO panel data */ +- i915->vbt.sdvo_lvds_vbt_mode = NULL; +- + /* general features */ + i915->vbt.int_tv_support = 1; + i915->vbt.int_crt_support = 1; +@@ -2683,6 +2689,17 @@ init_vbt_defaults(struct drm_i915_private *i915) + i915->vbt.lvds_ssc_freq); + } + ++/* Common defaults which may be overridden by VBT. */ ++static void ++init_vbt_panel_defaults(struct intel_panel *panel) ++{ ++ /* Default to having backlight */ ++ panel->vbt.backlight.present = true; ++ ++ /* LFP panel data */ ++ panel->vbt.lvds_dither = true; ++} ++ + /* Defaults to initialize only if there is no VBT. */ + static void + init_vbt_missing_defaults(struct drm_i915_private *i915) +@@ -2988,19 +3005,22 @@ void intel_bios_init(struct drm_i915_private *i915) + kfree(oprom_vbt); + } + +-void intel_bios_init_panel(struct drm_i915_private *i915) ++void intel_bios_init_panel(struct drm_i915_private *i915, ++ struct intel_panel *panel) + { +- parse_panel_options(i915); +- parse_generic_dtd(i915); +- parse_lfp_data(i915); +- parse_lfp_backlight(i915); +- parse_sdvo_panel_data(i915); +- parse_panel_driver_features(i915); +- parse_power_conservation_features(i915); +- parse_edp(i915); +- parse_psr(i915); +- parse_mipi_config(i915); +- parse_mipi_sequence(i915); ++ init_vbt_panel_defaults(panel); ++ ++ parse_panel_options(i915, panel); ++ parse_generic_dtd(i915, panel); ++ parse_lfp_data(i915, panel); ++ parse_lfp_backlight(i915, panel); ++ parse_sdvo_panel_data(i915, panel); ++ parse_panel_driver_features(i915, panel); ++ parse_power_conservation_features(i915, panel); ++ parse_edp(i915, panel); ++ parse_psr(i915, panel); ++ parse_mipi_config(i915, panel); ++ parse_mipi_sequence(i915, panel); + } + + /** +@@ -3022,19 +3042,22 @@ void intel_bios_driver_remove(struct drm_i915_private *i915) + list_del(&entry->node); + kfree(entry); + } ++} + +- kfree(i915->vbt.sdvo_lvds_vbt_mode); +- i915->vbt.sdvo_lvds_vbt_mode = NULL; +- kfree(i915->vbt.lfp_lvds_vbt_mode); +- i915->vbt.lfp_lvds_vbt_mode = NULL; +- kfree(i915->vbt.dsi.data); +- i915->vbt.dsi.data = NULL; +- kfree(i915->vbt.dsi.pps); +- i915->vbt.dsi.pps = NULL; +- kfree(i915->vbt.dsi.config); +- i915->vbt.dsi.config = NULL; +- kfree(i915->vbt.dsi.deassert_seq); +- i915->vbt.dsi.deassert_seq = NULL; ++void intel_bios_fini_panel(struct intel_panel *panel) ++{ ++ kfree(panel->vbt.sdvo_lvds_vbt_mode); ++ panel->vbt.sdvo_lvds_vbt_mode = NULL; ++ kfree(panel->vbt.lfp_lvds_vbt_mode); ++ panel->vbt.lfp_lvds_vbt_mode = NULL; ++ kfree(panel->vbt.dsi.data); ++ panel->vbt.dsi.data = NULL; ++ kfree(panel->vbt.dsi.pps); ++ panel->vbt.dsi.pps = NULL; ++ kfree(panel->vbt.dsi.config); ++ panel->vbt.dsi.config = NULL; ++ kfree(panel->vbt.dsi.deassert_seq); ++ panel->vbt.dsi.deassert_seq = NULL; + } + + /** +diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h +index c744d75fa435..86129f015718 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.h ++++ b/drivers/gpu/drm/i915/display/intel_bios.h +@@ -36,6 +36,7 @@ struct drm_i915_private; + struct intel_bios_encoder_data; + struct intel_crtc_state; + struct intel_encoder; ++struct intel_panel; + enum port; + + enum intel_backlight_type { +@@ -230,7 +231,9 @@ struct mipi_pps_data { + } __packed; + + void intel_bios_init(struct drm_i915_private *dev_priv); +-void intel_bios_init_panel(struct drm_i915_private *dev_priv); ++void intel_bios_init_panel(struct drm_i915_private *dev_priv, ++ struct intel_panel *panel); ++void intel_bios_fini_panel(struct intel_panel *panel); + void intel_bios_driver_remove(struct drm_i915_private *dev_priv); + bool intel_bios_is_valid_vbt(const void *buf, size_t size); + bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); +diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +index 85f58dd3df72..b490acd0ab69 100644 +--- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c ++++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c +@@ -1062,17 +1062,18 @@ bool is_hobl_buf_trans(const struct intel_ddi_buf_trans *table) + + static bool use_edp_hobl(struct intel_encoder *encoder) + { +- struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ++ struct intel_connector *connector = intel_dp->attached_connector; + +- return i915->vbt.edp.hobl && !intel_dp->hobl_failed; ++ return connector->panel.vbt.edp.hobl && !intel_dp->hobl_failed; + } + + static bool use_edp_low_vswing(struct intel_encoder *encoder) + { +- struct drm_i915_private *i915 = to_i915(encoder->base.dev); ++ struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ++ struct intel_connector *connector = intel_dp->attached_connector; + +- return i915->vbt.edp.low_vswing; ++ return connector->panel.vbt.edp.low_vswing; + } + + static const struct intel_ddi_buf_trans * +diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c +index e384db157f34..806d50b302ab 100644 +--- a/drivers/gpu/drm/i915/display/intel_display.c ++++ b/drivers/gpu/drm/i915/display/intel_display.c +@@ -9580,7 +9580,6 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915) + } + + intel_bios_init(i915); +- intel_bios_init_panel(i915); + + ret = intel_vga_register(i915); + if (ret) +diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h +index 408152f9f46a..e2561c5d4953 100644 +--- a/drivers/gpu/drm/i915/display/intel_display_types.h ++++ b/drivers/gpu/drm/i915/display/intel_display_types.h +@@ -279,6 +279,73 @@ struct intel_panel_bl_funcs { + u32 (*hz_to_pwm)(struct intel_connector *connector, u32 hz); + }; + ++enum drrs_type { ++ DRRS_TYPE_NONE, ++ DRRS_TYPE_STATIC, ++ DRRS_TYPE_SEAMLESS, ++}; ++ ++struct intel_vbt_panel_data { ++ struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ ++ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ ++ ++ /* Feature bits */ ++ unsigned int panel_type:4; ++ unsigned int lvds_dither:1; ++ unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ ++ ++ u8 seamless_drrs_min_refresh_rate; ++ enum drrs_type drrs_type; ++ ++ struct { ++ int rate; ++ int lanes; ++ int preemphasis; ++ int vswing; ++ int bpp; ++ struct edp_power_seq pps; ++ u8 drrs_msa_timing_delay; ++ bool low_vswing; ++ bool initialized; ++ bool hobl; ++ } edp; ++ ++ struct { ++ bool enable; ++ bool full_link; ++ bool require_aux_wakeup; ++ int idle_frames; ++ int tp1_wakeup_time_us; ++ int tp2_tp3_wakeup_time_us; ++ int psr2_tp2_tp3_wakeup_time_us; ++ } psr; ++ ++ struct { ++ u16 pwm_freq_hz; ++ u16 brightness_precision_bits; ++ bool present; ++ bool active_low_pwm; ++ u8 min_brightness; /* min_brightness/255 of max */ ++ u8 controller; /* brightness controller number */ ++ enum intel_backlight_type type; ++ } backlight; ++ ++ /* MIPI DSI */ ++ struct { ++ u16 panel_id; ++ struct mipi_config *config; ++ struct mipi_pps_data *pps; ++ u16 bl_ports; ++ u16 cabc_ports; ++ u8 seq_version; ++ u32 size; ++ u8 *data; ++ const u8 *sequence[MIPI_SEQ_MAX]; ++ u8 *deassert_seq; /* Used by fixup_mipi_sequences() */ ++ enum drm_panel_orientation orientation; ++ } dsi; ++}; ++ + struct intel_panel { + struct list_head fixed_modes; + +@@ -318,6 +385,8 @@ struct intel_panel { + const struct intel_panel_bl_funcs *pwm_funcs; + void (*power)(struct intel_connector *, bool enable); + } backlight; ++ ++ struct intel_vbt_panel_data vbt; + }; + + struct intel_digital_port; +diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c +index affc820bf8d0..0efec6023fbe 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -1246,11 +1246,12 @@ static int intel_dp_max_bpp(struct intel_dp *intel_dp, + if (intel_dp_is_edp(intel_dp)) { + /* Get bpp from vbt only for panels that dont have bpp in edid */ + if (intel_connector->base.display_info.bpc == 0 && +- dev_priv->vbt.edp.bpp && dev_priv->vbt.edp.bpp < bpp) { ++ intel_connector->panel.vbt.edp.bpp && ++ intel_connector->panel.vbt.edp.bpp < bpp) { + drm_dbg_kms(&dev_priv->drm, + "clamping bpp for eDP panel to BIOS-provided %i\n", +- dev_priv->vbt.edp.bpp); +- bpp = dev_priv->vbt.edp.bpp; ++ intel_connector->panel.vbt.edp.bpp); ++ bpp = intel_connector->panel.vbt.edp.bpp; + } + } + +@@ -1907,7 +1908,7 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, + } + + if (IS_IRONLAKE(i915) || IS_SANDYBRIDGE(i915) || IS_IVYBRIDGE(i915)) +- pipe_config->msa_timing_delay = i915->vbt.edp.drrs_msa_timing_delay; ++ pipe_config->msa_timing_delay = connector->panel.vbt.edp.drrs_msa_timing_delay; + + pipe_config->has_drrs = true; + +@@ -2740,8 +2741,10 @@ static void intel_edp_mso_mode_fixup(struct intel_connector *connector, + void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp) + { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); ++ struct intel_dp *intel_dp = enc_to_intel_dp(encoder); ++ struct intel_connector *connector = intel_dp->attached_connector; + +- if (dev_priv->vbt.edp.bpp && pipe_bpp > dev_priv->vbt.edp.bpp) { ++ if (connector->panel.vbt.edp.bpp && pipe_bpp > connector->panel.vbt.edp.bpp) { + /* + * This is a big fat ugly hack. + * +@@ -2757,8 +2760,8 @@ void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp) + */ + drm_dbg_kms(&dev_priv->drm, + "pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n", +- pipe_bpp, dev_priv->vbt.edp.bpp); +- dev_priv->vbt.edp.bpp = pipe_bpp; ++ pipe_bpp, connector->panel.vbt.edp.bpp); ++ connector->panel.vbt.edp.bpp = pipe_bpp; + } + } + +@@ -5237,8 +5240,10 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, + } + intel_connector->edid = edid; + ++ intel_bios_init_panel(dev_priv, &intel_connector->panel); ++ + intel_panel_add_edid_fixed_modes(intel_connector, +- dev_priv->vbt.drrs_type != DRRS_TYPE_NONE); ++ intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE); + + /* MSO requires information from the EDID */ + intel_edp_mso_init(intel_dp); +diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h +index e794d910df56..a54902c713a3 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.h ++++ b/drivers/gpu/drm/i915/display/intel_dp.h +@@ -29,6 +29,7 @@ struct link_config_limits { + int min_bpp, max_bpp; + }; + ++void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp); + void intel_dp_adjust_compliance_config(struct intel_dp *intel_dp, + struct intel_crtc_state *pipe_config, + struct link_config_limits *limits); +diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +index fb6cf30ee628..c92d5bb2326a 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +@@ -370,7 +370,7 @@ static int intel_dp_aux_vesa_setup_backlight(struct intel_connector *connector, + int ret; + + ret = drm_edp_backlight_init(&intel_dp->aux, &panel->backlight.edp.vesa.info, +- i915->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd, ++ panel->vbt.backlight.pwm_freq_hz, intel_dp->edp_dpcd, + ¤t_level, ¤t_mode); + if (ret < 0) + return ret; +@@ -454,7 +454,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) + case INTEL_DP_AUX_BACKLIGHT_OFF: + return -ENODEV; + case INTEL_DP_AUX_BACKLIGHT_AUTO: +- switch (i915->vbt.backlight.type) { ++ switch (panel->vbt.backlight.type) { + case INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE: + try_vesa_interface = true; + break; +@@ -466,7 +466,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) + } + break; + case INTEL_DP_AUX_BACKLIGHT_ON: +- if (i915->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE) ++ if (panel->vbt.backlight.type != INTEL_BACKLIGHT_VESA_EDP_AUX_INTERFACE) + try_intel_interface = true; + + try_vesa_interface = true; +diff --git a/drivers/gpu/drm/i915/display/intel_drrs.c b/drivers/gpu/drm/i915/display/intel_drrs.c +index 166caf293f7b..7da4a9cbe4ba 100644 +--- a/drivers/gpu/drm/i915/display/intel_drrs.c ++++ b/drivers/gpu/drm/i915/display/intel_drrs.c +@@ -217,9 +217,6 @@ static void intel_drrs_frontbuffer_update(struct drm_i915_private *dev_priv, + { + struct intel_crtc *crtc; + +- if (dev_priv->vbt.drrs_type != DRRS_TYPE_SEAMLESS) +- return; +- + for_each_intel_crtc(&dev_priv->drm, crtc) { + unsigned int frontbuffer_bits; + +diff --git a/drivers/gpu/drm/i915/display/intel_dsi.c b/drivers/gpu/drm/i915/display/intel_dsi.c +index 389a8c24cdc1..35e121cd226c 100644 +--- a/drivers/gpu/drm/i915/display/intel_dsi.c ++++ b/drivers/gpu/drm/i915/display/intel_dsi.c +@@ -102,7 +102,7 @@ intel_dsi_get_panel_orientation(struct intel_connector *connector) + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + enum drm_panel_orientation orientation; + +- orientation = dev_priv->vbt.dsi.orientation; ++ orientation = connector->panel.vbt.dsi.orientation; + if (orientation != DRM_MODE_PANEL_ORIENTATION_UNKNOWN) + return orientation; + +diff --git a/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c b/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c +index 7d234429e71e..1bc7118c56a2 100644 +--- a/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c ++++ b/drivers/gpu/drm/i915/display/intel_dsi_dcs_backlight.c +@@ -160,12 +160,10 @@ static void dcs_enable_backlight(const struct intel_crtc_state *crtc_state, + static int dcs_setup_backlight(struct intel_connector *connector, + enum pipe unused) + { +- struct drm_device *dev = connector->base.dev; +- struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_panel *panel = &connector->panel; + +- if (dev_priv->vbt.backlight.brightness_precision_bits > 8) +- panel->backlight.max = (1 << dev_priv->vbt.backlight.brightness_precision_bits) - 1; ++ if (panel->vbt.backlight.brightness_precision_bits > 8) ++ panel->backlight.max = (1 << panel->vbt.backlight.brightness_precision_bits) - 1; + else + panel->backlight.max = PANEL_PWM_MAX_VALUE; + +@@ -185,11 +183,10 @@ static const struct intel_panel_bl_funcs dcs_bl_funcs = { + int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector) + { + struct drm_device *dev = intel_connector->base.dev; +- struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_encoder *encoder = intel_attached_encoder(intel_connector); + struct intel_panel *panel = &intel_connector->panel; + +- if (dev_priv->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS) ++ if (panel->vbt.backlight.type != INTEL_BACKLIGHT_DSI_DCS) + return -ENODEV; + + if (drm_WARN_ON(dev, encoder->type != INTEL_OUTPUT_DSI)) +diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +index dd24aef925f2..75e8cc4337c9 100644 +--- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c ++++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +@@ -240,9 +240,10 @@ static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data) + return data; + } + +-static void vlv_exec_gpio(struct drm_i915_private *dev_priv, ++static void vlv_exec_gpio(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) + { ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct gpio_map *map; + u16 pconf0, padval; + u32 tmp; +@@ -256,7 +257,7 @@ static void vlv_exec_gpio(struct drm_i915_private *dev_priv, + + map = &vlv_gpio_table[gpio_index]; + +- if (dev_priv->vbt.dsi.seq_version >= 3) { ++ if (connector->panel.vbt.dsi.seq_version >= 3) { + /* XXX: this assumes vlv_gpio_table only has NC GPIOs. */ + port = IOSF_PORT_GPIO_NC; + } else { +@@ -287,14 +288,15 @@ static void vlv_exec_gpio(struct drm_i915_private *dev_priv, + vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); + } + +-static void chv_exec_gpio(struct drm_i915_private *dev_priv, ++static void chv_exec_gpio(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) + { ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + u16 cfg0, cfg1; + u16 family_num; + u8 port; + +- if (dev_priv->vbt.dsi.seq_version >= 3) { ++ if (connector->panel.vbt.dsi.seq_version >= 3) { + if (gpio_index >= CHV_GPIO_IDX_START_SE) { + /* XXX: it's unclear whether 255->57 is part of SE. */ + gpio_index -= CHV_GPIO_IDX_START_SE; +@@ -340,9 +342,10 @@ static void chv_exec_gpio(struct drm_i915_private *dev_priv, + vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); + } + +-static void bxt_exec_gpio(struct drm_i915_private *dev_priv, ++static void bxt_exec_gpio(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) + { ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + /* XXX: this table is a quick ugly hack. */ + static struct gpio_desc *bxt_gpio_table[U8_MAX + 1]; + struct gpio_desc *gpio_desc = bxt_gpio_table[gpio_index]; +@@ -366,9 +369,11 @@ static void bxt_exec_gpio(struct drm_i915_private *dev_priv, + gpiod_set_value(gpio_desc, value); + } + +-static void icl_exec_gpio(struct drm_i915_private *dev_priv, ++static void icl_exec_gpio(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) + { ++ struct drm_i915_private *dev_priv = to_i915(connector->base.dev); ++ + drm_dbg_kms(&dev_priv->drm, "Skipping ICL GPIO element execution\n"); + } + +@@ -376,18 +381,19 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) + { + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); ++ struct intel_connector *connector = intel_dsi->attached_connector; + u8 gpio_source, gpio_index = 0, gpio_number; + bool value; + + drm_dbg_kms(&dev_priv->drm, "\n"); + +- if (dev_priv->vbt.dsi.seq_version >= 3) ++ if (connector->panel.vbt.dsi.seq_version >= 3) + gpio_index = *data++; + + gpio_number = *data++; + + /* gpio source in sequence v2 only */ +- if (dev_priv->vbt.dsi.seq_version == 2) ++ if (connector->panel.vbt.dsi.seq_version == 2) + gpio_source = (*data >> 1) & 3; + else + gpio_source = 0; +@@ -396,13 +402,13 @@ static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) + value = *data++ & 1; + + if (DISPLAY_VER(dev_priv) >= 11) +- icl_exec_gpio(dev_priv, gpio_source, gpio_index, value); ++ icl_exec_gpio(connector, gpio_source, gpio_index, value); + else if (IS_VALLEYVIEW(dev_priv)) +- vlv_exec_gpio(dev_priv, gpio_source, gpio_number, value); ++ vlv_exec_gpio(connector, gpio_source, gpio_number, value); + else if (IS_CHERRYVIEW(dev_priv)) +- chv_exec_gpio(dev_priv, gpio_source, gpio_number, value); ++ chv_exec_gpio(connector, gpio_source, gpio_number, value); + else +- bxt_exec_gpio(dev_priv, gpio_source, gpio_index, value); ++ bxt_exec_gpio(connector, gpio_source, gpio_index, value); + + return data; + } +@@ -585,14 +591,15 @@ static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, + enum mipi_seq seq_id) + { + struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); ++ struct intel_connector *connector = intel_dsi->attached_connector; + const u8 *data; + fn_mipi_elem_exec mipi_elem_exec; + + if (drm_WARN_ON(&dev_priv->drm, +- seq_id >= ARRAY_SIZE(dev_priv->vbt.dsi.sequence))) ++ seq_id >= ARRAY_SIZE(connector->panel.vbt.dsi.sequence))) + return; + +- data = dev_priv->vbt.dsi.sequence[seq_id]; ++ data = connector->panel.vbt.dsi.sequence[seq_id]; + if (!data) + return; + +@@ -605,7 +612,7 @@ static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, + data++; + + /* Skip Size of Sequence. */ +- if (dev_priv->vbt.dsi.seq_version >= 3) ++ if (connector->panel.vbt.dsi.seq_version >= 3) + data += 4; + + while (1) { +@@ -621,7 +628,7 @@ static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, + mipi_elem_exec = NULL; + + /* Size of Operation. */ +- if (dev_priv->vbt.dsi.seq_version >= 3) ++ if (connector->panel.vbt.dsi.seq_version >= 3) + operation_size = *data++; + + if (mipi_elem_exec) { +@@ -669,10 +676,10 @@ void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, + + void intel_dsi_msleep(struct intel_dsi *intel_dsi, int msec) + { +- struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev); ++ struct intel_connector *connector = intel_dsi->attached_connector; + + /* For v3 VBTs in vid-mode the delays are part of the VBT sequences */ +- if (is_vid_mode(intel_dsi) && dev_priv->vbt.dsi.seq_version >= 3) ++ if (is_vid_mode(intel_dsi) && connector->panel.vbt.dsi.seq_version >= 3) + return; + + msleep(msec); +@@ -734,9 +741,10 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) + { + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); +- struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; +- struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps; +- struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode; ++ struct intel_connector *connector = intel_dsi->attached_connector; ++ struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; ++ struct mipi_pps_data *pps = connector->panel.vbt.dsi.pps; ++ struct drm_display_mode *mode = connector->panel.vbt.lfp_lvds_vbt_mode; + u16 burst_mode_ratio; + enum port port; + +@@ -872,7 +880,8 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) + { + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); +- struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; ++ struct intel_connector *connector = intel_dsi->attached_connector; ++ struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; + enum gpiod_flags flags = panel_is_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + bool want_backlight_gpio = false; + bool want_panel_gpio = false; +@@ -927,7 +936,8 @@ void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi) + { + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); +- struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; ++ struct intel_connector *connector = intel_dsi->attached_connector; ++ struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; + + if (intel_dsi->gpio_panel) { + gpiod_put(intel_dsi->gpio_panel); +diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c +index e8478161f8b9..9f250a70519a 100644 +--- a/drivers/gpu/drm/i915/display/intel_lvds.c ++++ b/drivers/gpu/drm/i915/display/intel_lvds.c +@@ -809,7 +809,7 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) + else + val &= ~(LVDS_DETECTED | LVDS_PIPE_SEL_MASK); + if (val == 0) +- val = dev_priv->vbt.bios_lvds_val; ++ val = connector->panel.vbt.bios_lvds_val; + + return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP; + } +@@ -967,9 +967,11 @@ void intel_lvds_init(struct drm_i915_private *dev_priv) + } + intel_connector->edid = edid; + ++ intel_bios_init_panel(dev_priv, &intel_connector->panel); ++ + /* Try EDID first */ + intel_panel_add_edid_fixed_modes(intel_connector, +- dev_priv->vbt.drrs_type != DRRS_TYPE_NONE); ++ intel_connector->panel.vbt.drrs_type != DRRS_TYPE_NONE); + + /* Failed to get EDID, what about VBT? */ + if (!intel_panel_preferred_fixed_mode(intel_connector)) +diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c +index d1d1b59102d6..d055e4118558 100644 +--- a/drivers/gpu/drm/i915/display/intel_panel.c ++++ b/drivers/gpu/drm/i915/display/intel_panel.c +@@ -75,9 +75,8 @@ const struct drm_display_mode * + intel_panel_downclock_mode(struct intel_connector *connector, + const struct drm_display_mode *adjusted_mode) + { +- struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *fixed_mode, *best_mode = NULL; +- int min_vrefresh = i915->vbt.seamless_drrs_min_refresh_rate; ++ int min_vrefresh = connector->panel.vbt.seamless_drrs_min_refresh_rate; + int max_vrefresh = drm_mode_vrefresh(adjusted_mode); + + /* pick the fixed_mode with the lowest refresh rate */ +@@ -113,13 +112,11 @@ int intel_panel_get_modes(struct intel_connector *connector) + + enum drrs_type intel_panel_drrs_type(struct intel_connector *connector) + { +- struct drm_i915_private *i915 = to_i915(connector->base.dev); +- + if (list_empty(&connector->panel.fixed_modes) || + list_is_singular(&connector->panel.fixed_modes)) + return DRRS_TYPE_NONE; + +- return i915->vbt.drrs_type; ++ return connector->panel.vbt.drrs_type; + } + + int intel_panel_compute_config(struct intel_connector *connector, +@@ -260,7 +257,7 @@ void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector) + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *mode; + +- mode = i915->vbt.lfp_lvds_vbt_mode; ++ mode = connector->panel.vbt.lfp_lvds_vbt_mode; + if (!mode) + return; + +@@ -274,7 +271,7 @@ void intel_panel_add_vbt_sdvo_fixed_mode(struct intel_connector *connector) + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct drm_display_mode *mode; + +- mode = i915->vbt.sdvo_lvds_vbt_mode; ++ mode = connector->panel.vbt.sdvo_lvds_vbt_mode; + if (!mode) + return; + +@@ -639,6 +636,8 @@ void intel_panel_fini(struct intel_connector *connector) + + intel_backlight_destroy(panel); + ++ intel_bios_fini_panel(panel); ++ + list_for_each_entry_safe(fixed_mode, next, &panel->fixed_modes, head) { + list_del(&fixed_mode->head); + drm_mode_destroy(connector->base.dev, fixed_mode); +diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c +index 5b72c892a6f2..a226e4e5c569 100644 +--- a/drivers/gpu/drm/i915/display/intel_pps.c ++++ b/drivers/gpu/drm/i915/display/intel_pps.c +@@ -209,7 +209,8 @@ static int + bxt_power_sequencer_idx(struct intel_dp *intel_dp) + { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- int backlight_controller = dev_priv->vbt.backlight.controller; ++ struct intel_connector *connector = intel_dp->attached_connector; ++ int backlight_controller = connector->panel.vbt.backlight.controller; + + lockdep_assert_held(&dev_priv->pps_mutex); + +@@ -1175,8 +1176,9 @@ static void pps_init_delays_vbt(struct intel_dp *intel_dp, + struct edp_power_seq *vbt) + { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ struct intel_connector *connector = intel_dp->attached_connector; + +- *vbt = dev_priv->vbt.edp.pps; ++ *vbt = connector->panel.vbt.edp.pps; + + /* On Toshiba Satellite P50-C-18C system the VBT T12 delay + * of 500ms appears to be too short. Ocassionally the panel +diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c +index 06db407e2749..195ed9631128 100644 +--- a/drivers/gpu/drm/i915/display/intel_psr.c ++++ b/drivers/gpu/drm/i915/display/intel_psr.c +@@ -399,6 +399,7 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) + + static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) + { ++ struct intel_connector *connector = intel_dp->attached_connector; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + u32 val = 0; + +@@ -411,20 +412,20 @@ static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) + goto check_tp3_sel; + } + +- if (dev_priv->vbt.psr.tp1_wakeup_time_us == 0) ++ if (connector->panel.vbt.psr.tp1_wakeup_time_us == 0) + val |= EDP_PSR_TP1_TIME_0us; +- else if (dev_priv->vbt.psr.tp1_wakeup_time_us <= 100) ++ else if (connector->panel.vbt.psr.tp1_wakeup_time_us <= 100) + val |= EDP_PSR_TP1_TIME_100us; +- else if (dev_priv->vbt.psr.tp1_wakeup_time_us <= 500) ++ else if (connector->panel.vbt.psr.tp1_wakeup_time_us <= 500) + val |= EDP_PSR_TP1_TIME_500us; + else + val |= EDP_PSR_TP1_TIME_2500us; + +- if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us == 0) ++ if (connector->panel.vbt.psr.tp2_tp3_wakeup_time_us == 0) + val |= EDP_PSR_TP2_TP3_TIME_0us; +- else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us <= 100) ++ else if (connector->panel.vbt.psr.tp2_tp3_wakeup_time_us <= 100) + val |= EDP_PSR_TP2_TP3_TIME_100us; +- else if (dev_priv->vbt.psr.tp2_tp3_wakeup_time_us <= 500) ++ else if (connector->panel.vbt.psr.tp2_tp3_wakeup_time_us <= 500) + val |= EDP_PSR_TP2_TP3_TIME_500us; + else + val |= EDP_PSR_TP2_TP3_TIME_2500us; +@@ -441,13 +442,14 @@ static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) + + static u8 psr_compute_idle_frames(struct intel_dp *intel_dp) + { ++ struct intel_connector *connector = intel_dp->attached_connector; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + int idle_frames; + + /* Let's use 6 as the minimum to cover all known cases including the + * off-by-one issue that HW has in some cases. + */ +- idle_frames = max(6, dev_priv->vbt.psr.idle_frames); ++ idle_frames = max(6, connector->panel.vbt.psr.idle_frames); + idle_frames = max(idle_frames, intel_dp->psr.sink_sync_latency + 1); + + if (drm_WARN_ON(&dev_priv->drm, idle_frames > 0xf)) +@@ -483,18 +485,19 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) + + static u32 intel_psr2_get_tp_time(struct intel_dp *intel_dp) + { ++ struct intel_connector *connector = intel_dp->attached_connector; + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + u32 val = 0; + + if (dev_priv->params.psr_safest_params) + return EDP_PSR2_TP2_TIME_2500us; + +- if (dev_priv->vbt.psr.psr2_tp2_tp3_wakeup_time_us >= 0 && +- dev_priv->vbt.psr.psr2_tp2_tp3_wakeup_time_us <= 50) ++ if (connector->panel.vbt.psr.psr2_tp2_tp3_wakeup_time_us >= 0 && ++ connector->panel.vbt.psr.psr2_tp2_tp3_wakeup_time_us <= 50) + val |= EDP_PSR2_TP2_TIME_50us; +- else if (dev_priv->vbt.psr.psr2_tp2_tp3_wakeup_time_us <= 100) ++ else if (connector->panel.vbt.psr.psr2_tp2_tp3_wakeup_time_us <= 100) + val |= EDP_PSR2_TP2_TIME_100us; +- else if (dev_priv->vbt.psr.psr2_tp2_tp3_wakeup_time_us <= 500) ++ else if (connector->panel.vbt.psr.psr2_tp2_tp3_wakeup_time_us <= 500) + val |= EDP_PSR2_TP2_TIME_500us; + else + val |= EDP_PSR2_TP2_TIME_2500us; +@@ -2344,6 +2347,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv, + */ + void intel_psr_init(struct intel_dp *intel_dp) + { ++ struct intel_connector *connector = intel_dp->attached_connector; + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + +@@ -2368,13 +2372,13 @@ void intel_psr_init(struct intel_dp *intel_dp) + intel_dp->psr.source_support = true; + + if (dev_priv->params.enable_psr == -1) +- if (!dev_priv->vbt.psr.enable) ++ if (!connector->panel.vbt.psr.enable) + dev_priv->params.enable_psr = 0; + + /* Set link_standby x link_off defaults */ + if (DISPLAY_VER(dev_priv) < 12) + /* For new platforms up to TGL let's respect VBT back again */ +- intel_dp->psr.link_standby = dev_priv->vbt.psr.full_link; ++ intel_dp->psr.link_standby = connector->panel.vbt.psr.full_link; + + INIT_WORK(&intel_dp->psr.work, intel_psr_work); + INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, tgl_dc3co_disable_work); +diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c +index d81855d57cdc..14a64bd61176 100644 +--- a/drivers/gpu/drm/i915/display/intel_sdvo.c ++++ b/drivers/gpu/drm/i915/display/intel_sdvo.c +@@ -2869,6 +2869,7 @@ static bool + intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) + { + struct drm_encoder *encoder = &intel_sdvo->base.base; ++ struct drm_i915_private *i915 = to_i915(encoder->dev); + struct drm_connector *connector; + struct intel_connector *intel_connector; + struct intel_sdvo_connector *intel_sdvo_connector; +@@ -2900,6 +2901,8 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) + if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) + goto err; + ++ intel_bios_init_panel(i915, &intel_connector->panel); ++ + /* + * Fetch modes from VBT. For SDVO prefer the VBT mode since some + * SDVO->LVDS transcoders can't cope with the EDID mode. +diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c +index 1954f07f0d3e..be8fd3c362df 100644 +--- a/drivers/gpu/drm/i915/display/vlv_dsi.c ++++ b/drivers/gpu/drm/i915/display/vlv_dsi.c +@@ -782,6 +782,7 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, + { + struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder); + struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); ++ struct intel_connector *connector = to_intel_connector(conn_state->connector); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + enum port port; +@@ -838,7 +839,7 @@ static void intel_dsi_pre_enable(struct intel_atomic_state *state, + * the delay in that case. If there is no deassert-seq, then an + * unconditional msleep is used to give the panel time to power-on. + */ +- if (dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) { ++ if (connector->panel.vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET]) { + intel_dsi_msleep(intel_dsi, intel_dsi->panel_on_delay); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DEASSERT_RESET); + } else { +@@ -1690,7 +1691,8 @@ static void vlv_dphy_param_init(struct intel_dsi *intel_dsi) + { + struct drm_device *dev = intel_dsi->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); +- struct mipi_config *mipi_config = dev_priv->vbt.dsi.config; ++ struct intel_connector *connector = intel_dsi->attached_connector; ++ struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; + u32 tlpx_ns, extra_byte_count, tlpx_ui; + u32 ui_num, ui_den; + u32 prepare_cnt, exit_zero_cnt, clk_zero_cnt, trail_cnt; +@@ -1924,13 +1926,15 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) + + intel_dsi->panel_power_off_time = ktime_get_boottime(); + +- if (dev_priv->vbt.dsi.config->dual_link) ++ intel_bios_init_panel(dev_priv, &intel_connector->panel); ++ ++ if (intel_connector->panel.vbt.dsi.config->dual_link) + intel_dsi->ports = BIT(PORT_A) | BIT(PORT_C); + else + intel_dsi->ports = BIT(port); + +- intel_dsi->dcs_backlight_ports = dev_priv->vbt.dsi.bl_ports; +- intel_dsi->dcs_cabc_ports = dev_priv->vbt.dsi.cabc_ports; ++ intel_dsi->dcs_backlight_ports = intel_connector->panel.vbt.dsi.bl_ports; ++ intel_dsi->dcs_cabc_ports = intel_connector->panel.vbt.dsi.cabc_ports; + + /* Create a DSI host (and a device) for each port. */ + for_each_dsi_port(port, intel_dsi->ports) { +diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h +index 5184d70d4838..554d79bc0312 100644 +--- a/drivers/gpu/drm/i915/i915_drv.h ++++ b/drivers/gpu/drm/i915/i915_drv.h +@@ -194,12 +194,6 @@ struct drm_i915_display_funcs { + + #define I915_COLOR_UNEVICTABLE (-1) /* a non-vma sharing the address space */ + +-enum drrs_type { +- DRRS_TYPE_NONE, +- DRRS_TYPE_STATIC, +- DRRS_TYPE_SEAMLESS, +-}; +- + #define QUIRK_LVDS_SSC_DISABLE (1<<1) + #define QUIRK_INVERT_BRIGHTNESS (1<<2) + #define QUIRK_BACKLIGHT_PRESENT (1<<3) +@@ -308,76 +302,19 @@ struct intel_vbt_data { + /* bdb version */ + u16 version; + +- struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ +- struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ +- + /* Feature bits */ + unsigned int int_tv_support:1; +- unsigned int lvds_dither:1; + unsigned int int_crt_support:1; + unsigned int lvds_use_ssc:1; + unsigned int int_lvds_support:1; + unsigned int display_clock_mode:1; + unsigned int fdi_rx_polarity_inverted:1; +- unsigned int panel_type:4; + int lvds_ssc_freq; +- unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */ + enum drm_panel_orientation orientation; + + bool override_afc_startup; + u8 override_afc_startup_val; + +- u8 seamless_drrs_min_refresh_rate; +- enum drrs_type drrs_type; +- +- struct { +- int rate; +- int lanes; +- int preemphasis; +- int vswing; +- int bpp; +- struct edp_power_seq pps; +- u8 drrs_msa_timing_delay; +- bool low_vswing; +- bool initialized; +- bool hobl; +- } edp; +- +- struct { +- bool enable; +- bool full_link; +- bool require_aux_wakeup; +- int idle_frames; +- int tp1_wakeup_time_us; +- int tp2_tp3_wakeup_time_us; +- int psr2_tp2_tp3_wakeup_time_us; +- } psr; +- +- struct { +- u16 pwm_freq_hz; +- u16 brightness_precision_bits; +- bool present; +- bool active_low_pwm; +- u8 min_brightness; /* min_brightness/255 of max */ +- u8 controller; /* brightness controller number */ +- enum intel_backlight_type type; +- } backlight; +- +- /* MIPI DSI */ +- struct { +- u16 panel_id; +- struct mipi_config *config; +- struct mipi_pps_data *pps; +- u16 bl_ports; +- u16 cabc_ports; +- u8 seq_version; +- u32 size; +- u8 *data; +- const u8 *sequence[MIPI_SEQ_MAX]; +- u8 *deassert_seq; /* Used by fixup_mipi_sequences() */ +- enum drm_panel_orientation orientation; +- } dsi; +- + int crt_ddc_pin; + + struct list_head display_devices; +-- +2.35.1 + diff --git a/queue-5.19/drm-i915-bios-split-vbt-parsing-to-global-vs.-panel-.patch b/queue-5.19/drm-i915-bios-split-vbt-parsing-to-global-vs.-panel-.patch new file mode 100644 index 00000000000..42838e6ff31 --- /dev/null +++ b/queue-5.19/drm-i915-bios-split-vbt-parsing-to-global-vs.-panel-.patch @@ -0,0 +1,103 @@ +From ac9fe905031b0de0c092cb8010ed67a6f8d82f9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 May 2022 13:42:38 +0300 +Subject: drm/i915/bios: Split VBT parsing to global vs. panel specific parts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit c2fdb424d32204faf5be29d55f0086b611c94e38 ] + +Parsing the panel specific data (anything that depends on panel_type) +from VBT is currently happening too early. Split the whole thing +into global vs. panel specific parts so that we can start doing +the panel specific parsing at a later time. + +v2: Clarify that this is about panel_type (Jani) + Split out the leak checks (Jani) + +Reviewed-by: Jani Nikula +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-12-ville.syrjala@linux.intel.com +Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_bios.c | 26 +++++++++++--------- + drivers/gpu/drm/i915/display/intel_bios.h | 1 + + drivers/gpu/drm/i915/display/intel_display.c | 1 + + 3 files changed, 17 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c +index 5ceabc380808..d5cae64b916b 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.c ++++ b/drivers/gpu/drm/i915/display/intel_bios.c +@@ -2969,18 +2969,7 @@ void intel_bios_init(struct drm_i915_private *i915) + /* Grab useful general definitions */ + parse_general_features(i915); + parse_general_definitions(i915); +- parse_panel_options(i915); +- parse_generic_dtd(i915); +- parse_lfp_data(i915); +- parse_lfp_backlight(i915); +- parse_sdvo_panel_data(i915); + parse_driver_features(i915); +- parse_panel_driver_features(i915); +- parse_power_conservation_features(i915); +- parse_edp(i915); +- parse_psr(i915); +- parse_mipi_config(i915); +- parse_mipi_sequence(i915); + + /* Depends on child device list */ + parse_compression_parameters(i915); +@@ -2999,6 +2988,21 @@ void intel_bios_init(struct drm_i915_private *i915) + kfree(oprom_vbt); + } + ++void intel_bios_init_panel(struct drm_i915_private *i915) ++{ ++ parse_panel_options(i915); ++ parse_generic_dtd(i915); ++ parse_lfp_data(i915); ++ parse_lfp_backlight(i915); ++ parse_sdvo_panel_data(i915); ++ parse_panel_driver_features(i915); ++ parse_power_conservation_features(i915); ++ parse_edp(i915); ++ parse_psr(i915); ++ parse_mipi_config(i915); ++ parse_mipi_sequence(i915); ++} ++ + /** + * intel_bios_driver_remove - Free any resources allocated by intel_bios_init() + * @i915: i915 device instance +diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h +index 4709c4d29805..c744d75fa435 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.h ++++ b/drivers/gpu/drm/i915/display/intel_bios.h +@@ -230,6 +230,7 @@ struct mipi_pps_data { + } __packed; + + void intel_bios_init(struct drm_i915_private *dev_priv); ++void intel_bios_init_panel(struct drm_i915_private *dev_priv); + void intel_bios_driver_remove(struct drm_i915_private *dev_priv); + bool intel_bios_is_valid_vbt(const void *buf, size_t size); + bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv); +diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c +index 806d50b302ab..e384db157f34 100644 +--- a/drivers/gpu/drm/i915/display/intel_display.c ++++ b/drivers/gpu/drm/i915/display/intel_display.c +@@ -9580,6 +9580,7 @@ int intel_modeset_init_noirq(struct drm_i915_private *i915) + } + + intel_bios_init(i915); ++ intel_bios_init_panel(i915); + + ret = intel_vga_register(i915); + if (ret) +-- +2.35.1 + diff --git a/queue-5.19/drm-i915-dsi-filter-invalid-backlight-and-cabc-ports.patch b/queue-5.19/drm-i915-dsi-filter-invalid-backlight-and-cabc-ports.patch new file mode 100644 index 00000000000..bd71e062cc8 --- /dev/null +++ b/queue-5.19/drm-i915-dsi-filter-invalid-backlight-and-cabc-ports.patch @@ -0,0 +1,66 @@ +From 68d2795bac565378bf29af0db89f74a8634fc98f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Aug 2022 18:37:20 +0300 +Subject: drm/i915/dsi: filter invalid backlight and CABC ports + +From: Jani Nikula + +[ Upstream commit 607f41768a1ef9c7721866b00fbdeeea5359bc07 ] + +Avoid using ports that aren't initialized in case the VBT backlight or +CABC ports have invalid values. This fixes a NULL pointer dereference of +intel_dsi->dsi_hosts[port] in such cases. + +Cc: stable@vger.kernel.org +Signed-off-by: Jani Nikula +Reviewed-by: Stanislav Lisovskiy +Link: https://patchwork.freedesktop.org/patch/msgid/b0f4f087866257d280eb97d6bcfcefd109cc5fa2.1660664162.git.jani.nikula@intel.com +(cherry picked from commit f4a6c7a454a6e71c5ccf25af82694213a9784013) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/icl_dsi.c | 7 +++++++ + drivers/gpu/drm/i915/display/vlv_dsi.c | 7 +++++++ + 2 files changed, 14 insertions(+) + +diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c +index 5c46acb46516..f416499dad6f 100644 +--- a/drivers/gpu/drm/i915/display/icl_dsi.c ++++ b/drivers/gpu/drm/i915/display/icl_dsi.c +@@ -2072,7 +2072,14 @@ void icl_dsi_init(struct drm_i915_private *dev_priv) + else + intel_dsi->ports = BIT(port); + ++ if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.bl_ports & ~intel_dsi->ports)) ++ intel_connector->panel.vbt.dsi.bl_ports &= intel_dsi->ports; ++ + intel_dsi->dcs_backlight_ports = intel_connector->panel.vbt.dsi.bl_ports; ++ ++ if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.cabc_ports & ~intel_dsi->ports)) ++ intel_connector->panel.vbt.dsi.cabc_ports &= intel_dsi->ports; ++ + intel_dsi->dcs_cabc_ports = intel_connector->panel.vbt.dsi.cabc_ports; + + for_each_dsi_port(port, intel_dsi->ports) { +diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c +index be8fd3c362df..02f75e95b2ec 100644 +--- a/drivers/gpu/drm/i915/display/vlv_dsi.c ++++ b/drivers/gpu/drm/i915/display/vlv_dsi.c +@@ -1933,7 +1933,14 @@ void vlv_dsi_init(struct drm_i915_private *dev_priv) + else + intel_dsi->ports = BIT(port); + ++ if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.bl_ports & ~intel_dsi->ports)) ++ intel_connector->panel.vbt.dsi.bl_ports &= intel_dsi->ports; ++ + intel_dsi->dcs_backlight_ports = intel_connector->panel.vbt.dsi.bl_ports; ++ ++ if (drm_WARN_ON(&dev_priv->drm, intel_connector->panel.vbt.dsi.cabc_ports & ~intel_dsi->ports)) ++ intel_connector->panel.vbt.dsi.cabc_ports &= intel_dsi->ports; ++ + intel_dsi->dcs_cabc_ports = intel_connector->panel.vbt.dsi.cabc_ports; + + /* Create a DSI host (and a device) for each port. */ +-- +2.35.1 + diff --git a/queue-5.19/drm-i915-dsi-fix-dual-link-dsi-backlight-and-cabc-po.patch b/queue-5.19/drm-i915-dsi-fix-dual-link-dsi-backlight-and-cabc-po.patch new file mode 100644 index 00000000000..fb191391cb3 --- /dev/null +++ b/queue-5.19/drm-i915-dsi-fix-dual-link-dsi-backlight-and-cabc-po.patch @@ -0,0 +1,72 @@ +From f9b0de5da1b03b733800d36abb9da23ca3b1bf3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Aug 2022 18:37:21 +0300 +Subject: drm/i915/dsi: fix dual-link DSI backlight and CABC ports for display + 11+ + +From: Jani Nikula + +[ Upstream commit 13393f65b77445d8b0f99c7b605cc9ccc936586f ] + +The VBT dual-link DSI backlight and CABC still use ports A and C, both +in Bspec and code, while display 11+ DSI only supports ports A and +B. Assume port C actually means port B for display 11+ when parsing VBT. + +Bspec: 20154 +Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6476 +Cc: stable@vger.kernel.org +Signed-off-by: Jani Nikula +Reviewed-by: Stanislav Lisovskiy +Link: https://patchwork.freedesktop.org/patch/msgid/8c462718bcc7b36a83e09d0a5eef058b6bc8b1a2.1660664162.git.jani.nikula@intel.com +(cherry picked from commit ab55165d73a444606af1530cd0d6448b04370f68) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_bios.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c +index d5d20a44f373..b5de61fe9cc6 100644 +--- a/drivers/gpu/drm/i915/display/intel_bios.c ++++ b/drivers/gpu/drm/i915/display/intel_bios.c +@@ -1473,6 +1473,8 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915, + struct intel_panel *panel, + enum port port) + { ++ enum port port_bc = DISPLAY_VER(i915) >= 11 ? PORT_B : PORT_C; ++ + if (!panel->vbt.dsi.config->dual_link || i915->vbt.version < 197) { + panel->vbt.dsi.bl_ports = BIT(port); + if (panel->vbt.dsi.config->cabc_supported) +@@ -1486,11 +1488,11 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915, + panel->vbt.dsi.bl_ports = BIT(PORT_A); + break; + case DL_DCS_PORT_C: +- panel->vbt.dsi.bl_ports = BIT(PORT_C); ++ panel->vbt.dsi.bl_ports = BIT(port_bc); + break; + default: + case DL_DCS_PORT_A_AND_C: +- panel->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(PORT_C); ++ panel->vbt.dsi.bl_ports = BIT(PORT_A) | BIT(port_bc); + break; + } + +@@ -1502,12 +1504,12 @@ static void parse_dsi_backlight_ports(struct drm_i915_private *i915, + panel->vbt.dsi.cabc_ports = BIT(PORT_A); + break; + case DL_DCS_PORT_C: +- panel->vbt.dsi.cabc_ports = BIT(PORT_C); ++ panel->vbt.dsi.cabc_ports = BIT(port_bc); + break; + default: + case DL_DCS_PORT_A_AND_C: + panel->vbt.dsi.cabc_ports = +- BIT(PORT_A) | BIT(PORT_C); ++ BIT(PORT_A) | BIT(port_bc); + break; + } + } +-- +2.35.1 + diff --git a/queue-5.19/drm-i915-extract-intel_edp_fixup_vbt_bpp.patch b/queue-5.19/drm-i915-extract-intel_edp_fixup_vbt_bpp.patch new file mode 100644 index 00000000000..186bcdb48e4 --- /dev/null +++ b/queue-5.19/drm-i915-extract-intel_edp_fixup_vbt_bpp.patch @@ -0,0 +1,147 @@ +From 797e7c7efce2c27c112ce4fe231800d0951e00ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 May 2022 13:42:29 +0300 +Subject: drm/i915: Extract intel_edp_fixup_vbt_bpp() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 822e5ae701af2964c5808b6ade1d6f3b1eaec967 ] + +We have the same "override eDP VBT bpp with the current bpp" code +duplciated in two places. Extract it to a helper function. + +TODO: Having this in .get_config() is pretty ugly. Should probably +try to move it somewhere else (setup_hw_state()/etc.)... + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-3-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/g4x_dp.c | 22 ++------------------- + drivers/gpu/drm/i915/display/intel_ddi.c | 22 ++------------------- + drivers/gpu/drm/i915/display/intel_dp.c | 25 ++++++++++++++++++++++++ + drivers/gpu/drm/i915/display/intel_dp.h | 1 + + 4 files changed, 30 insertions(+), 40 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c +index 5a957acebfd6..82ad8fe7440c 100644 +--- a/drivers/gpu/drm/i915/display/g4x_dp.c ++++ b/drivers/gpu/drm/i915/display/g4x_dp.c +@@ -395,26 +395,8 @@ static void intel_dp_get_config(struct intel_encoder *encoder, + intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->dp_m_n); + +- if (intel_dp_is_edp(intel_dp) && dev_priv->vbt.edp.bpp && +- pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) { +- /* +- * This is a big fat ugly hack. +- * +- * Some machines in UEFI boot mode provide us a VBT that has 18 +- * bpp and 1.62 GHz link bandwidth for eDP, which for reasons +- * unknown we fail to light up. Yet the same BIOS boots up with +- * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as +- * max, not what it tells us to use. +- * +- * Note: This will still be broken if the eDP panel is not lit +- * up by the BIOS, and thus we can't get the mode at module +- * load. +- */ +- drm_dbg_kms(&dev_priv->drm, +- "pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n", +- pipe_config->pipe_bpp, dev_priv->vbt.edp.bpp); +- dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp; +- } ++ if (intel_dp_is_edp(intel_dp)) ++ intel_edp_fixup_vbt_bpp(encoder, pipe_config->pipe_bpp); + } + + static void +diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c +index 9e6fa59eabba..333871cf3a2c 100644 +--- a/drivers/gpu/drm/i915/display/intel_ddi.c ++++ b/drivers/gpu/drm/i915/display/intel_ddi.c +@@ -3433,26 +3433,8 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, + pipe_config->has_audio = + intel_ddi_is_audio_enabled(dev_priv, cpu_transcoder); + +- if (encoder->type == INTEL_OUTPUT_EDP && dev_priv->vbt.edp.bpp && +- pipe_config->pipe_bpp > dev_priv->vbt.edp.bpp) { +- /* +- * This is a big fat ugly hack. +- * +- * Some machines in UEFI boot mode provide us a VBT that has 18 +- * bpp and 1.62 GHz link bandwidth for eDP, which for reasons +- * unknown we fail to light up. Yet the same BIOS boots up with +- * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as +- * max, not what it tells us to use. +- * +- * Note: This will still be broken if the eDP panel is not lit +- * up by the BIOS, and thus we can't get the mode at module +- * load. +- */ +- drm_dbg_kms(&dev_priv->drm, +- "pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n", +- pipe_config->pipe_bpp, dev_priv->vbt.edp.bpp); +- dev_priv->vbt.edp.bpp = pipe_config->pipe_bpp; +- } ++ if (encoder->type == INTEL_OUTPUT_EDP) ++ intel_edp_fixup_vbt_bpp(encoder, pipe_config->pipe_bpp); + + ddi_dotclock_get(pipe_config); + +diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c +index fe8b6b72970a..affc820bf8d0 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.c ++++ b/drivers/gpu/drm/i915/display/intel_dp.c +@@ -2737,6 +2737,31 @@ static void intel_edp_mso_mode_fixup(struct intel_connector *connector, + DRM_MODE_ARG(mode)); + } + ++void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp) ++{ ++ struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); ++ ++ if (dev_priv->vbt.edp.bpp && pipe_bpp > dev_priv->vbt.edp.bpp) { ++ /* ++ * This is a big fat ugly hack. ++ * ++ * Some machines in UEFI boot mode provide us a VBT that has 18 ++ * bpp and 1.62 GHz link bandwidth for eDP, which for reasons ++ * unknown we fail to light up. Yet the same BIOS boots up with ++ * 24 bpp and 2.7 GHz link. Use the same bpp as the BIOS uses as ++ * max, not what it tells us to use. ++ * ++ * Note: This will still be broken if the eDP panel is not lit ++ * up by the BIOS, and thus we can't get the mode at module ++ * load. ++ */ ++ drm_dbg_kms(&dev_priv->drm, ++ "pipe has %d bpp for eDP panel, overriding BIOS-provided max %d bpp\n", ++ pipe_bpp, dev_priv->vbt.edp.bpp); ++ dev_priv->vbt.edp.bpp = pipe_bpp; ++ } ++} ++ + static void intel_edp_mso_init(struct intel_dp *intel_dp) + { + struct drm_i915_private *i915 = dp_to_i915(intel_dp); +diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h +index d457e17bdc57..e794d910df56 100644 +--- a/drivers/gpu/drm/i915/display/intel_dp.h ++++ b/drivers/gpu/drm/i915/display/intel_dp.h +@@ -63,6 +63,7 @@ enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port, + void intel_edp_backlight_on(const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); + void intel_edp_backlight_off(const struct drm_connector_state *conn_state); ++void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp); + void intel_dp_mst_suspend(struct drm_i915_private *dev_priv); + void intel_dp_mst_resume(struct drm_i915_private *dev_priv); + int intel_dp_max_link_rate(struct intel_dp *intel_dp); +-- +2.35.1 + diff --git a/queue-5.19/drm-i915-pps-split-pps_init_delays-into-distinct-par.patch b/queue-5.19/drm-i915-pps-split-pps_init_delays-into-distinct-par.patch new file mode 100644 index 00000000000..dddb11127e6 --- /dev/null +++ b/queue-5.19/drm-i915-pps-split-pps_init_delays-into-distinct-par.patch @@ -0,0 +1,133 @@ +From f5691f684277ee39b22b19193956ac4af131f923 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 May 2022 13:42:30 +0300 +Subject: drm/i915/pps: Split pps_init_delays() into distinct parts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +[ Upstream commit 75bd0d5e4eadb9ce3e9b6fb71971b6e87c38799e ] + +Split each of the hw/vbt/spec PPS delay initialization into +separate functions to make the whole thing less cluttered. + +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-4-ville.syrjala@linux.intel.com +Reviewed-by: Jani Nikula +Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports") +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/i915/display/intel_pps.c | 66 +++++++++++++++++------- + 1 file changed, 48 insertions(+), 18 deletions(-) + +diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c +index 5a598dd06039..5b72c892a6f2 100644 +--- a/drivers/gpu/drm/i915/display/intel_pps.c ++++ b/drivers/gpu/drm/i915/display/intel_pps.c +@@ -1159,53 +1159,83 @@ intel_pps_verify_state(struct intel_dp *intel_dp) + } + } + +-static void pps_init_delays(struct intel_dp *intel_dp) ++static void pps_init_delays_cur(struct intel_dp *intel_dp, ++ struct edp_power_seq *cur) + { + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); +- struct edp_power_seq cur, vbt, spec, +- *final = &intel_dp->pps.pps_delays; + + lockdep_assert_held(&dev_priv->pps_mutex); + +- /* already initialized? */ +- if (final->t11_t12 != 0) +- return; ++ intel_pps_readout_hw_state(intel_dp, cur); ++ ++ intel_pps_dump_state(intel_dp, "cur", cur); ++} + +- intel_pps_readout_hw_state(intel_dp, &cur); ++static void pps_init_delays_vbt(struct intel_dp *intel_dp, ++ struct edp_power_seq *vbt) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + +- intel_pps_dump_state(intel_dp, "cur", &cur); ++ *vbt = dev_priv->vbt.edp.pps; + +- vbt = dev_priv->vbt.edp.pps; + /* On Toshiba Satellite P50-C-18C system the VBT T12 delay + * of 500ms appears to be too short. Ocassionally the panel + * just fails to power back on. Increasing the delay to 800ms + * seems sufficient to avoid this problem. + */ + if (dev_priv->quirks & QUIRK_INCREASE_T12_DELAY) { +- vbt.t11_t12 = max_t(u16, vbt.t11_t12, 1300 * 10); ++ vbt->t11_t12 = max_t(u16, vbt->t11_t12, 1300 * 10); + drm_dbg_kms(&dev_priv->drm, + "Increasing T12 panel delay as per the quirk to %d\n", +- vbt.t11_t12); ++ vbt->t11_t12); + } ++ + /* T11_T12 delay is special and actually in units of 100ms, but zero + * based in the hw (so we need to add 100 ms). But the sw vbt + * table multiplies it with 1000 to make it in units of 100usec, + * too. */ +- vbt.t11_t12 += 100 * 10; ++ vbt->t11_t12 += 100 * 10; ++ ++ intel_pps_dump_state(intel_dp, "vbt", vbt); ++} ++ ++static void pps_init_delays_spec(struct intel_dp *intel_dp, ++ struct edp_power_seq *spec) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ ++ lockdep_assert_held(&dev_priv->pps_mutex); + + /* Upper limits from eDP 1.3 spec. Note that we use the clunky units of + * our hw here, which are all in 100usec. */ +- spec.t1_t3 = 210 * 10; +- spec.t8 = 50 * 10; /* no limit for t8, use t7 instead */ +- spec.t9 = 50 * 10; /* no limit for t9, make it symmetric with t8 */ +- spec.t10 = 500 * 10; ++ spec->t1_t3 = 210 * 10; ++ spec->t8 = 50 * 10; /* no limit for t8, use t7 instead */ ++ spec->t9 = 50 * 10; /* no limit for t9, make it symmetric with t8 */ ++ spec->t10 = 500 * 10; + /* This one is special and actually in units of 100ms, but zero + * based in the hw (so we need to add 100 ms). But the sw vbt + * table multiplies it with 1000 to make it in units of 100usec, + * too. */ +- spec.t11_t12 = (510 + 100) * 10; ++ spec->t11_t12 = (510 + 100) * 10; ++ ++ intel_pps_dump_state(intel_dp, "spec", spec); ++} ++ ++static void pps_init_delays(struct intel_dp *intel_dp) ++{ ++ struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); ++ struct edp_power_seq cur, vbt, spec, ++ *final = &intel_dp->pps.pps_delays; ++ ++ lockdep_assert_held(&dev_priv->pps_mutex); ++ ++ /* already initialized? */ ++ if (final->t11_t12 != 0) ++ return; + +- intel_pps_dump_state(intel_dp, "vbt", &vbt); ++ pps_init_delays_cur(intel_dp, &cur); ++ pps_init_delays_vbt(intel_dp, &vbt); ++ pps_init_delays_spec(intel_dp, &spec); + + /* Use the max of the register settings and vbt. If both are + * unset, fall back to the spec limits. */ +-- +2.35.1 + diff --git a/queue-5.19/net-mvpp2-debugfs-fix-memory-leak-when-using-debugfs.patch b/queue-5.19/net-mvpp2-debugfs-fix-memory-leak-when-using-debugfs.patch new file mode 100644 index 00000000000..01faa0ef8e1 --- /dev/null +++ b/queue-5.19/net-mvpp2-debugfs-fix-memory-leak-when-using-debugfs.patch @@ -0,0 +1,51 @@ +From 8e794602201b071b24a348dce799c504c202a5cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Sep 2022 15:41:11 +0200 +Subject: net: mvpp2: debugfs: fix memory leak when using debugfs_lookup() + +From: Greg Kroah-Hartman + +[ Upstream commit fe2c9c61f668cde28dac2b188028c5299cedcc1e ] + +When calling debugfs_lookup() the result must have dput() called on it, +otherwise the memory will leak over time. Fix this up to be much +simpler logic and only create the root debugfs directory once when the +driver is first accessed. That resolves the memory leak and makes +things more obvious as to what the intent is. + +Cc: Marcin Wojtas +Cc: Russell King +Cc: "David S. Miller" +Cc: Eric Dumazet +Cc: Jakub Kicinski +Cc: Paolo Abeni +Cc: netdev@vger.kernel.org +Cc: stable +Fixes: 21da57a23125 ("net: mvpp2: add a debugfs interface for the Header Parser") +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c +index 4a3baa7e0142..0eec05d905eb 100644 +--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c ++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c +@@ -700,10 +700,10 @@ void mvpp2_dbgfs_cleanup(struct mvpp2 *priv) + + void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name) + { +- struct dentry *mvpp2_dir, *mvpp2_root; ++ static struct dentry *mvpp2_root; ++ struct dentry *mvpp2_dir; + int ret, i; + +- mvpp2_root = debugfs_lookup(MVPP2_DRIVER_NAME, NULL); + if (!mvpp2_root) + mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL); + +-- +2.35.1 + diff --git a/queue-5.19/revert-usb-add-quirks-for-lenovo-onelink-dock.patch b/queue-5.19/revert-usb-add-quirks-for-lenovo-onelink-dock.patch new file mode 100644 index 00000000000..747efd8e595 --- /dev/null +++ b/queue-5.19/revert-usb-add-quirks-for-lenovo-onelink-dock.patch @@ -0,0 +1,43 @@ +From b8fc4a65f65b51bce40d2f1968f65155f1ff759c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Aug 2022 10:34:25 +0200 +Subject: Revert "usb: add quirks for Lenovo OneLink+ Dock" + +From: Greg Kroah-Hartman + +[ Upstream commit 58bfe7d8e31014d7ce246788df99c56e3cfe6c68 ] + +This reverts commit 3d5f70949f1b1168fbb17d06eb5c57e984c56c58. + +The quirk does not work properly, more work is needed to determine what +should be done here. + +Reported-by: Oliver Neukum +Cc: Jean-Francois Le Fillatre +Cc: stable +Fixes: 3d5f70949f1b ("usb: add quirks for Lenovo OneLink+ Dock") +Link: https://lore.kernel.org/r/9a17ea86-079f-510d-e919-01bc53a6d09f@gmx.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/core/quirks.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index 999b7c9697fc..f99a65a64588 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -437,10 +437,6 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x1532, 0x0116), .driver_info = + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + +- /* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */ +- { USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME }, +- { USB_DEVICE(0x17ef, 0x1019), .driver_info = USB_QUIRK_RESET_RESUME }, +- + /* Lenovo USB-C to Ethernet Adapter RTL8153-04 */ + { USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM }, + +-- +2.35.1 + diff --git a/queue-5.19/revert-usb-gadget-udc-xilinx-replace-memcpy-with-mem.patch b/queue-5.19/revert-usb-gadget-udc-xilinx-replace-memcpy-with-mem.patch new file mode 100644 index 00000000000..eaec4f55e6b --- /dev/null +++ b/queue-5.19/revert-usb-gadget-udc-xilinx-replace-memcpy-with-mem.patch @@ -0,0 +1,96 @@ +From 2fa098146195e3a8a32a5837e1329d606c7eed6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Sep 2022 09:10:08 +0200 +Subject: Revert "usb: gadget: udc-xilinx: replace memcpy with memcpy_toio" + +From: Greg Kroah-Hartman + +[ Upstream commit fe0a2ac7c627b064c479ad0c3b25e531d342e048 ] + +This reverts commit 8cb339f1c1f04baede9d54c1e40ac96247a6393b as it +throws up a bunch of sparse warnings as reported by the kernel test +robot. + +Reported-by: kernel test robot +Link: https://lore.kernel.org/r/202209020044.CX2PfZzM-lkp@intel.com +Fixes: 8cb339f1c1f0 ("usb: gadget: udc-xilinx: replace memcpy with memcpy_toio") +Cc: stable@vger.kernel.org +Cc: Linus Walleij +Cc: Piyush Mehta +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/udc-xilinx.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c +index 054b69dc2f0c..4827e3cd3834 100644 +--- a/drivers/usb/gadget/udc/udc-xilinx.c ++++ b/drivers/usb/gadget/udc/udc-xilinx.c +@@ -499,11 +499,11 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req, + /* Get the Buffer address and copy the transmit data.*/ + eprambase = (u32 __force *)(udc->addr + ep->rambase); + if (ep->is_in) { +- memcpy_toio(eprambase, bufferptr, bytestosend); ++ memcpy(eprambase, bufferptr, bytestosend); + udc->write_fn(udc->addr, ep->offset + + XUSB_EP_BUF0COUNT_OFFSET, bufferlen); + } else { +- memcpy_toio(bufferptr, eprambase, bytestosend); ++ memcpy(bufferptr, eprambase, bytestosend); + } + /* + * Enable the buffer for transmission. +@@ -517,11 +517,11 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req, + eprambase = (u32 __force *)(udc->addr + ep->rambase + + ep->ep_usb.maxpacket); + if (ep->is_in) { +- memcpy_toio(eprambase, bufferptr, bytestosend); ++ memcpy(eprambase, bufferptr, bytestosend); + udc->write_fn(udc->addr, ep->offset + + XUSB_EP_BUF1COUNT_OFFSET, bufferlen); + } else { +- memcpy_toio(bufferptr, eprambase, bytestosend); ++ memcpy(bufferptr, eprambase, bytestosend); + } + /* + * Enable the buffer for transmission. +@@ -1023,7 +1023,7 @@ static int __xudc_ep0_queue(struct xusb_ep *ep0, struct xusb_req *req) + udc->addr); + length = req->usb_req.actual = min_t(u32, length, + EP0_MAX_PACKET); +- memcpy_toio(corebuf, req->usb_req.buf, length); ++ memcpy(corebuf, req->usb_req.buf, length); + udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, length); + udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1); + } else { +@@ -1752,7 +1752,7 @@ static void xudc_handle_setup(struct xusb_udc *udc) + + /* Load up the chapter 9 command buffer.*/ + ep0rambase = (u32 __force *) (udc->addr + XUSB_SETUP_PKT_ADDR_OFFSET); +- memcpy_toio(&setup, ep0rambase, 8); ++ memcpy(&setup, ep0rambase, 8); + + udc->setup = setup; + udc->setup.wValue = cpu_to_le16(setup.wValue); +@@ -1839,7 +1839,7 @@ static void xudc_ep0_out(struct xusb_udc *udc) + (ep0->rambase << 2)); + buffer = req->usb_req.buf + req->usb_req.actual; + req->usb_req.actual = req->usb_req.actual + bytes_to_rx; +- memcpy_toio(buffer, ep0rambase, bytes_to_rx); ++ memcpy(buffer, ep0rambase, bytes_to_rx); + + if (req->usb_req.length == req->usb_req.actual) { + /* Data transfer completed get ready for Status stage */ +@@ -1915,7 +1915,7 @@ static void xudc_ep0_in(struct xusb_udc *udc) + (ep0->rambase << 2)); + buffer = req->usb_req.buf + req->usb_req.actual; + req->usb_req.actual = req->usb_req.actual + length; +- memcpy_toio(ep0rambase, buffer, length); ++ memcpy(ep0rambase, buffer, length); + } + udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, count); + udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1); +-- +2.35.1 + diff --git a/queue-5.19/scsi-core-fix-a-use-after-free.patch b/queue-5.19/scsi-core-fix-a-use-after-free.patch new file mode 100644 index 00000000000..fdabbb6a42a --- /dev/null +++ b/queue-5.19/scsi-core-fix-a-use-after-free.patch @@ -0,0 +1,201 @@ +From 1ca31cce4a18e6c68ea9817aa6b11e90abd7b180 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Aug 2022 17:26:34 -0700 +Subject: scsi: core: Fix a use-after-free + +From: Bart Van Assche + +[ Upstream commit 8fe4ce5836e932f5766317cb651c1ff2a4cd0506 ] + +There are two .exit_cmd_priv implementations. Both implementations use +resources associated with the SCSI host. Make sure that these resources are +still available when .exit_cmd_priv is called by waiting inside +scsi_remove_host() until the tag set has been freed. + +This commit fixes the following use-after-free: + +================================================================== +BUG: KASAN: use-after-free in srp_exit_cmd_priv+0x27/0xd0 [ib_srp] +Read of size 8 at addr ffff888100337000 by task multipathd/16727 +Call Trace: + + dump_stack_lvl+0x34/0x44 + print_report.cold+0x5e/0x5db + kasan_report+0xab/0x120 + srp_exit_cmd_priv+0x27/0xd0 [ib_srp] + scsi_mq_exit_request+0x4d/0x70 + blk_mq_free_rqs+0x143/0x410 + __blk_mq_free_map_and_rqs+0x6e/0x100 + blk_mq_free_tag_set+0x2b/0x160 + scsi_host_dev_release+0xf3/0x1a0 + device_release+0x54/0xe0 + kobject_put+0xa5/0x120 + device_release+0x54/0xe0 + kobject_put+0xa5/0x120 + scsi_device_dev_release_usercontext+0x4c1/0x4e0 + execute_in_process_context+0x23/0x90 + device_release+0x54/0xe0 + kobject_put+0xa5/0x120 + scsi_disk_release+0x3f/0x50 + device_release+0x54/0xe0 + kobject_put+0xa5/0x120 + disk_release+0x17f/0x1b0 + device_release+0x54/0xe0 + kobject_put+0xa5/0x120 + dm_put_table_device+0xa3/0x160 [dm_mod] + dm_put_device+0xd0/0x140 [dm_mod] + free_priority_group+0xd8/0x110 [dm_multipath] + free_multipath+0x94/0xe0 [dm_multipath] + dm_table_destroy+0xa2/0x1e0 [dm_mod] + __dm_destroy+0x196/0x350 [dm_mod] + dev_remove+0x10c/0x160 [dm_mod] + ctl_ioctl+0x2c2/0x590 [dm_mod] + dm_ctl_ioctl+0x5/0x10 [dm_mod] + __x64_sys_ioctl+0xb4/0xf0 + dm_ctl_ioctl+0x5/0x10 [dm_mod] + __x64_sys_ioctl+0xb4/0xf0 + do_syscall_64+0x3b/0x90 + entry_SYSCALL_64_after_hwframe+0x46/0xb0 + +Link: https://lore.kernel.org/r/20220826002635.919423-1-bvanassche@acm.org +Fixes: 65ca846a5314 ("scsi: core: Introduce {init,exit}_cmd_priv()") +Cc: Ming Lei +Cc: Christoph Hellwig +Cc: Mike Christie +Cc: Hannes Reinecke +Cc: John Garry +Cc: Li Zhijian +Reported-by: Li Zhijian +Tested-by: Li Zhijian +Signed-off-by: Bart Van Assche +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/hosts.c | 16 +++++++++++++--- + drivers/scsi/scsi_lib.c | 6 +++++- + drivers/scsi/scsi_priv.h | 2 +- + drivers/scsi/scsi_scan.c | 1 + + drivers/scsi/scsi_sysfs.c | 1 + + include/scsi/scsi_host.h | 2 ++ + 6 files changed, 23 insertions(+), 5 deletions(-) + +diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c +index 8352f90d997d..ae9a107c520d 100644 +--- a/drivers/scsi/hosts.c ++++ b/drivers/scsi/hosts.c +@@ -182,6 +182,15 @@ void scsi_remove_host(struct Scsi_Host *shost) + mutex_unlock(&shost->scan_mutex); + scsi_proc_host_rm(shost); + ++ /* ++ * New SCSI devices cannot be attached anymore because of the SCSI host ++ * state so drop the tag set refcnt. Wait until the tag set refcnt drops ++ * to zero because .exit_cmd_priv implementations may need the host ++ * pointer. ++ */ ++ kref_put(&shost->tagset_refcnt, scsi_mq_free_tags); ++ wait_for_completion(&shost->tagset_freed); ++ + spin_lock_irqsave(shost->host_lock, flags); + if (scsi_host_set_state(shost, SHOST_DEL)) + BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY)); +@@ -240,6 +249,9 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, + if (error) + goto fail; + ++ kref_init(&shost->tagset_refcnt); ++ init_completion(&shost->tagset_freed); ++ + /* + * Increase usage count temporarily here so that calling + * scsi_autopm_put_host() will trigger runtime idle if there is +@@ -312,6 +324,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, + pm_runtime_disable(&shost->shost_gendev); + pm_runtime_set_suspended(&shost->shost_gendev); + pm_runtime_put_noidle(&shost->shost_gendev); ++ kref_put(&shost->tagset_refcnt, scsi_mq_free_tags); + fail: + return error; + } +@@ -345,9 +358,6 @@ static void scsi_host_dev_release(struct device *dev) + kfree(dev_name(&shost->shost_dev)); + } + +- if (shost->tag_set.tags) +- scsi_mq_destroy_tags(shost); +- + kfree(shost->shost_data); + + ida_simple_remove(&host_index_ida, shost->host_no); +diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c +index 0a267d6e2f7c..7e990f7a9f16 100644 +--- a/drivers/scsi/scsi_lib.c ++++ b/drivers/scsi/scsi_lib.c +@@ -1995,9 +1995,13 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost) + return blk_mq_alloc_tag_set(tag_set); + } + +-void scsi_mq_destroy_tags(struct Scsi_Host *shost) ++void scsi_mq_free_tags(struct kref *kref) + { ++ struct Scsi_Host *shost = container_of(kref, typeof(*shost), ++ tagset_refcnt); ++ + blk_mq_free_tag_set(&shost->tag_set); ++ complete(&shost->tagset_freed); + } + + /** +diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h +index 5c4786310a31..a0ee31d55f5f 100644 +--- a/drivers/scsi/scsi_priv.h ++++ b/drivers/scsi/scsi_priv.h +@@ -94,7 +94,7 @@ extern void scsi_run_host_queues(struct Scsi_Host *shost); + extern void scsi_requeue_run_queue(struct work_struct *work); + extern void scsi_start_queue(struct scsi_device *sdev); + extern int scsi_mq_setup_tags(struct Scsi_Host *shost); +-extern void scsi_mq_destroy_tags(struct Scsi_Host *shost); ++extern void scsi_mq_free_tags(struct kref *kref); + extern void scsi_exit_queue(void); + extern void scsi_evt_thread(struct work_struct *work); + +diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c +index 91ac901a6682..5d27f5196de6 100644 +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -340,6 +340,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, + kfree(sdev); + goto out; + } ++ kref_get(&sdev->host->tagset_refcnt); + sdev->request_queue = q; + q->queuedata = sdev; + __scsi_init_queue(sdev->host, q); +diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c +index aa70d9282161..5d61f58399dc 100644 +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -1476,6 +1476,7 @@ void __scsi_remove_device(struct scsi_device *sdev) + mutex_unlock(&sdev->state_mutex); + + blk_mq_destroy_queue(sdev->request_queue); ++ kref_put(&sdev->host->tagset_refcnt, scsi_mq_free_tags); + cancel_work_sync(&sdev->requeue_work); + + if (sdev->host->hostt->slave_destroy) +diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h +index 667d889b92b5..3e1cea155049 100644 +--- a/include/scsi/scsi_host.h ++++ b/include/scsi/scsi_host.h +@@ -557,6 +557,8 @@ struct Scsi_Host { + struct scsi_host_template *hostt; + struct scsi_transport_template *transportt; + ++ struct kref tagset_refcnt; ++ struct completion tagset_freed; + /* Area to keep a shared tag map */ + struct blk_mq_tag_set tag_set; + +-- +2.35.1 + diff --git a/queue-5.19/series b/queue-5.19/series new file mode 100644 index 00000000000..492077e144c --- /dev/null +++ b/queue-5.19/series @@ -0,0 +1,27 @@ +usb-dwc3-qcom-add-helper-functions-to-enable-disable.patch +usb-dwc3-qcom-configure-wakeup-interrupts-during-sus.patch +usb-dwc3-qcom-fix-use-after-free-on-runtime-pm-wakeu.patch +drm-i915-extract-intel_edp_fixup_vbt_bpp.patch +drm-i915-pps-split-pps_init_delays-into-distinct-par.patch +drm-i915-bios-split-parse_driver_features-into-two-p.patch +drm-i915-bios-split-vbt-parsing-to-global-vs.-panel-.patch +drm-i915-bios-split-vbt-data-into-per-panel-vs.-glob.patch +drm-i915-dsi-filter-invalid-backlight-and-cabc-ports.patch +drm-i915-dsi-fix-dual-link-dsi-backlight-and-cabc-po.patch +smb3-move-the-flush-out-of-smb2_copychunk_range-into.patch +smb3-fix-temporary-data-corruption-in-collapse-range.patch +smb3-fix-temporary-data-corruption-in-insert-range.patch +usb-add-quirks-for-lenovo-onelink-dock.patch +usb-gadget-udc-xilinx-replace-memcpy-with-memcpy_toi.patch +smb3-use-filemap_write_and_wait_range-instead-of-fil.patch +revert-usb-add-quirks-for-lenovo-onelink-dock.patch +revert-usb-gadget-udc-xilinx-replace-memcpy-with-mem.patch +net-mvpp2-debugfs-fix-memory-leak-when-using-debugfs.patch +xfrm-fix-xfrma_lastused-comment.patch +usb-dwc3-qcom-fix-gadget-only-builds.patch +usb-dwc3-qcom-fix-runtime-pm-wakeup.patch +usb-dwc3-qcom-fix-peripheral-and-otg-suspend.patch +block-remove-queue_flag_dead.patch +block-stop-setting-the-nomerges-flags-in-blk_cleanup.patch +block-simplify-disk-shutdown.patch +scsi-core-fix-a-use-after-free.patch diff --git a/queue-5.19/smb3-fix-temporary-data-corruption-in-collapse-range.patch b/queue-5.19/smb3-fix-temporary-data-corruption-in-collapse-range.patch new file mode 100644 index 00000000000..2ed431a9c9d --- /dev/null +++ b/queue-5.19/smb3-fix-temporary-data-corruption-in-collapse-range.patch @@ -0,0 +1,94 @@ +From 1228cadaeb30d892724a74fc186816df199a458f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Aug 2022 14:07:41 +0100 +Subject: smb3: fix temporary data corruption in collapse range + +From: Steve French + +[ Upstream commit fa30a81f255a56cccd89552cd6ce7ea6e8d8acc4 ] + +collapse range doesn't discard the affected cached region +so can risk temporarily corrupting the file data. This +fixes xfstest generic/031 + +I also decided to merge a minor cleanup to this into the same patch +(avoiding rereading inode size repeatedly unnecessarily) to make it +clearer. + +Cc: stable@vger.kernel.org +Fixes: 5476b5dd82c8b ("cifs: add support for FALLOC_FL_COLLAPSE_RANGE") +Reported-by: David Howells +Tested-by: David Howells +Reviewed-by: David Howells +cc: Ronnie Sahlberg +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/smb2ops.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c +index ef8cb7fbabeb..8e55495c4f7e 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -3952,41 +3952,47 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, + { + int rc; + unsigned int xid; +- struct inode *inode; ++ struct inode *inode = file_inode(file); + struct cifsFileInfo *cfile = file->private_data; +- struct cifsInodeInfo *cifsi; ++ struct cifsInodeInfo *cifsi = CIFS_I(inode); + __le64 eof; ++ loff_t old_eof; + + xid = get_xid(); + +- inode = d_inode(cfile->dentry); +- cifsi = CIFS_I(inode); ++ inode_lock(inode); + +- if (off >= i_size_read(inode) || +- off + len >= i_size_read(inode)) { ++ old_eof = i_size_read(inode); ++ if ((off >= old_eof) || ++ off + len >= old_eof) { + rc = -EINVAL; + goto out; + } + ++ filemap_invalidate_lock(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); ++ truncate_pagecache_range(inode, off, old_eof); + + rc = smb2_copychunk_range(xid, cfile, cfile, off + len, +- i_size_read(inode) - off - len, off); ++ old_eof - off - len, off); + if (rc < 0) +- goto out; ++ goto out_2; + +- eof = cpu_to_le64(i_size_read(inode) - len); ++ eof = cpu_to_le64(old_eof - len); + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, cfile->pid, &eof); + if (rc < 0) +- goto out; ++ goto out_2; + + rc = 0; + + cifsi->server_eof = i_size_read(inode) - len; + truncate_setsize(inode, cifsi->server_eof); + fscache_resize_cookie(cifs_inode_cookie(inode), cifsi->server_eof); ++out_2: ++ filemap_invalidate_unlock(inode->i_mapping); + out: ++ inode_unlock(inode); + free_xid(xid); + return rc; + } +-- +2.35.1 + diff --git a/queue-5.19/smb3-fix-temporary-data-corruption-in-insert-range.patch b/queue-5.19/smb3-fix-temporary-data-corruption-in-insert-range.patch new file mode 100644 index 00000000000..e997c33efa3 --- /dev/null +++ b/queue-5.19/smb3-fix-temporary-data-corruption-in-insert-range.patch @@ -0,0 +1,84 @@ +From 8b64323e4828fd9b330d892005051e1d4f36dd0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Aug 2022 14:07:55 +0100 +Subject: smb3: fix temporary data corruption in insert range + +From: David Howells + +[ Upstream commit 9c8b7a293f50253e694f19161c045817a938e551 ] + +insert range doesn't discard the affected cached region +so can risk temporarily corrupting file data. + +Also includes some minor cleanup (avoiding rereading +inode size repeatedly unnecessarily) to make it clearer. + +Cc: stable@vger.kernel.org +Fixes: 7fe6fe95b936 ("cifs: add FALLOC_FL_INSERT_RANGE support") +Signed-off-by: David Howells +cc: Ronnie Sahlberg +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/smb2ops.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c +index 8e55495c4f7e..774c6e5f6584 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -4005,35 +4005,43 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, + struct cifsFileInfo *cfile = file->private_data; + struct inode *inode = file_inode(file); + __le64 eof; +- __u64 count; ++ __u64 count, old_eof; + + xid = get_xid(); + +- if (off >= i_size_read(inode)) { ++ inode_lock(inode); ++ ++ old_eof = i_size_read(inode); ++ if (off >= old_eof) { + rc = -EINVAL; + goto out; + } + +- count = i_size_read(inode) - off; +- eof = cpu_to_le64(i_size_read(inode) + len); ++ count = old_eof - off; ++ eof = cpu_to_le64(old_eof + len); + ++ filemap_invalidate_lock(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); ++ truncate_pagecache_range(inode, off, old_eof); + + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, cfile->pid, &eof); + if (rc < 0) +- goto out; ++ goto out_2; + + rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len); + if (rc < 0) +- goto out; ++ goto out_2; + +- rc = smb3_zero_range(file, tcon, off, len, 1); ++ rc = smb3_zero_data(file, tcon, off, len, xid); + if (rc < 0) +- goto out; ++ goto out_2; + + rc = 0; ++out_2: ++ filemap_invalidate_unlock(inode->i_mapping); + out: ++ inode_unlock(inode); + free_xid(xid); + return rc; + } +-- +2.35.1 + diff --git a/queue-5.19/smb3-move-the-flush-out-of-smb2_copychunk_range-into.patch b/queue-5.19/smb3-move-the-flush-out-of-smb2_copychunk_range-into.patch new file mode 100644 index 00000000000..ddf1d15d6c4 --- /dev/null +++ b/queue-5.19/smb3-move-the-flush-out-of-smb2_copychunk_range-into.patch @@ -0,0 +1,95 @@ +From dd21d6b9e45779fe64c07f4fa39a56502f2dc4eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Aug 2022 14:07:28 +0100 +Subject: smb3: Move the flush out of smb2_copychunk_range() into its callers + +From: David Howells + +[ Upstream commit c3a72bb213209adfe981a4a92ea5746a778323e4 ] + +Move the flush out of smb2_copychunk_range() into its callers. This will +allow the pagecache to be invalidated between the flush and the operation +in smb3_collapse_range() and smb3_insert_range(). + +Signed-off-by: David Howells +cc: Ronnie Sahlberg +Signed-off-by: Steve French +Stable-dep-of: fa30a81f255a ("smb3: fix temporary data corruption in collapse range") +Signed-off-by: Sasha Levin +--- + fs/cifs/cifsfs.c | 2 ++ + fs/cifs/smb2ops.c | 20 ++++++++------------ + 2 files changed, 10 insertions(+), 12 deletions(-) + +diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c +index 8f2e003e0590..2b51f0cbf4d2 100644 +--- a/fs/cifs/cifsfs.c ++++ b/fs/cifs/cifsfs.c +@@ -1203,6 +1203,8 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, + + cifs_dbg(FYI, "copychunk range\n"); + ++ filemap_write_and_wait(src_inode->i_mapping); ++ + if (!src_file->private_data || !dst_file->private_data) { + rc = -EBADF; + cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); +diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c +index e8a8daa82ed7..ef8cb7fbabeb 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -1886,17 +1886,8 @@ smb2_copychunk_range(const unsigned int xid, + int chunks_copied = 0; + bool chunk_sizes_updated = false; + ssize_t bytes_written, total_bytes_written = 0; +- struct inode *inode; + + pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); +- +- /* +- * We need to flush all unwritten data before we can send the +- * copychunk ioctl to the server. +- */ +- inode = d_inode(trgtfile->dentry); +- filemap_write_and_wait(inode->i_mapping); +- + if (pcchunk == NULL) + return -ENOMEM; + +@@ -3977,6 +3968,8 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, + goto out; + } + ++ filemap_write_and_wait(inode->i_mapping); ++ + rc = smb2_copychunk_range(xid, cfile, cfile, off + len, + i_size_read(inode) - off - len, off); + if (rc < 0) +@@ -4004,18 +3997,21 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, + int rc; + unsigned int xid; + struct cifsFileInfo *cfile = file->private_data; ++ struct inode *inode = file_inode(file); + __le64 eof; + __u64 count; + + xid = get_xid(); + +- if (off >= i_size_read(file->f_inode)) { ++ if (off >= i_size_read(inode)) { + rc = -EINVAL; + goto out; + } + +- count = i_size_read(file->f_inode) - off; +- eof = cpu_to_le64(i_size_read(file->f_inode) + len); ++ count = i_size_read(inode) - off; ++ eof = cpu_to_le64(i_size_read(inode) + len); ++ ++ filemap_write_and_wait(inode->i_mapping); + + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, cfile->pid, &eof); +-- +2.35.1 + diff --git a/queue-5.19/smb3-use-filemap_write_and_wait_range-instead-of-fil.patch b/queue-5.19/smb3-use-filemap_write_and_wait_range-instead-of-fil.patch new file mode 100644 index 00000000000..bc835940bd2 --- /dev/null +++ b/queue-5.19/smb3-use-filemap_write_and_wait_range-instead-of-fil.patch @@ -0,0 +1,81 @@ +From 4342751c15e194569c55acfe466e0d57b8ca9e01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Aug 2022 11:53:41 -0500 +Subject: smb3: use filemap_write_and_wait_range instead of + filemap_write_and_wait + +From: Steve French + +[ Upstream commit 3e3761f1ec7df67d88cfca5e2ea98538f529e645 ] + +When doing insert range and collapse range we should be +writing out the cached pages for the ranges affected but not +the whole file. + +Fixes: c3a72bb21320 ("smb3: Move the flush out of smb2_copychunk_range() into its callers") +Cc: stable@vger.kernel.org +Reviewed-by: Paulo Alcantara (SUSE) +Reviewed-by: David Howells +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/cifs/cifsfs.c | 8 ++++++-- + fs/cifs/smb2ops.c | 9 +++++++-- + 2 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c +index 2b51f0cbf4d2..97278c43f8dc 100644 +--- a/fs/cifs/cifsfs.c ++++ b/fs/cifs/cifsfs.c +@@ -1203,8 +1203,6 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, + + cifs_dbg(FYI, "copychunk range\n"); + +- filemap_write_and_wait(src_inode->i_mapping); +- + if (!src_file->private_data || !dst_file->private_data) { + rc = -EBADF; + cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); +@@ -1234,6 +1232,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, + lock_two_nondirectories(target_inode, src_inode); + + cifs_dbg(FYI, "about to flush pages\n"); ++ ++ rc = filemap_write_and_wait_range(src_inode->i_mapping, off, ++ off + len - 1); ++ if (rc) ++ goto out; ++ + /* should we flush first and last page first */ + truncate_inode_pages(&target_inode->i_data, 0); + +diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c +index 774c6e5f6584..cc180d37b8ce 100644 +--- a/fs/cifs/smb2ops.c ++++ b/fs/cifs/smb2ops.c +@@ -3970,7 +3970,10 @@ static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon, + } + + filemap_invalidate_lock(inode->i_mapping); +- filemap_write_and_wait(inode->i_mapping); ++ rc = filemap_write_and_wait_range(inode->i_mapping, off, old_eof - 1); ++ if (rc < 0) ++ goto out_2; ++ + truncate_pagecache_range(inode, off, old_eof); + + rc = smb2_copychunk_range(xid, cfile, cfile, off + len, +@@ -4021,7 +4024,9 @@ static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon, + eof = cpu_to_le64(old_eof + len); + + filemap_invalidate_lock(inode->i_mapping); +- filemap_write_and_wait(inode->i_mapping); ++ rc = filemap_write_and_wait_range(inode->i_mapping, off, old_eof + len - 1); ++ if (rc < 0) ++ goto out_2; + truncate_pagecache_range(inode, off, old_eof); + + rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, +-- +2.35.1 + diff --git a/queue-5.19/usb-add-quirks-for-lenovo-onelink-dock.patch b/queue-5.19/usb-add-quirks-for-lenovo-onelink-dock.patch new file mode 100644 index 00000000000..5712130ec53 --- /dev/null +++ b/queue-5.19/usb-add-quirks-for-lenovo-onelink-dock.patch @@ -0,0 +1,51 @@ +From 710e110297312ffc42ea62d68331214ac71a7d2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Aug 2022 21:13:21 +0200 +Subject: usb: add quirks for Lenovo OneLink+ Dock + +From: Jean-Francois Le Fillatre + +[ Upstream commit 3d5f70949f1b1168fbb17d06eb5c57e984c56c58 ] + +The Lenovo OneLink+ Dock contains two VL812 USB3.0 controllers: +17ef:1018 upstream +17ef:1019 downstream + +Those two controllers both have problems with some USB3.0 devices, +particularly self-powered ones. Typical error messages include: + + Timeout while waiting for setup device command + device not accepting address X, error -62 + unable to enumerate USB device + +By process of elimination the controllers themselves were identified as +the cause of the problem. Through trial and error the issue was solved +by using USB_QUIRK_RESET_RESUME for both chips. + +Signed-off-by: Jean-Francois Le Fillatre +Cc: stable +Link: https://lore.kernel.org/r/20220824191320.17883-1-jflf_kernel@gmx.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/core/quirks.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c +index f99a65a64588..999b7c9697fc 100644 +--- a/drivers/usb/core/quirks.c ++++ b/drivers/usb/core/quirks.c +@@ -437,6 +437,10 @@ static const struct usb_device_id usb_quirk_list[] = { + { USB_DEVICE(0x1532, 0x0116), .driver_info = + USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + ++ /* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */ ++ { USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME }, ++ { USB_DEVICE(0x17ef, 0x1019), .driver_info = USB_QUIRK_RESET_RESUME }, ++ + /* Lenovo USB-C to Ethernet Adapter RTL8153-04 */ + { USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM }, + +-- +2.35.1 + diff --git a/queue-5.19/usb-dwc3-qcom-add-helper-functions-to-enable-disable.patch b/queue-5.19/usb-dwc3-qcom-add-helper-functions-to-enable-disable.patch new file mode 100644 index 00000000000..a9d61e788bb --- /dev/null +++ b/queue-5.19/usb-dwc3-qcom-add-helper-functions-to-enable-disable.patch @@ -0,0 +1,108 @@ +From 78f61759ac383ddf34cd93009ea6eae1a75c234f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jun 2022 10:00:52 +0530 +Subject: usb: dwc3: qcom: Add helper functions to enable,disable wake irqs + +From: Sandeep Maheswaram + +[ Upstream commit 360e8230516de94d74d30c64f0cdcf228b8e8b67 ] + +Adding helper functions to enable,disable wake irqs to make +the code simple and readable. + +Reviewed-by: Matthias Kaehlcke +Reviewed-by: Pavankumar Kondeti +Signed-off-by: Sandeep Maheswaram +Signed-off-by: Krishna Kurapati +Link: https://lore.kernel.org/r/1655094654-24052-4-git-send-email-quic_kriskura@quicinc.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a872ab303d5d ("usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup") +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/dwc3-qcom.c | 58 ++++++++++++++++-------------------- + 1 file changed, 26 insertions(+), 32 deletions(-) + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index 3582fd6dfa14..27ff18aeea26 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -296,50 +296,44 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) + icc_put(qcom->icc_path_apps); + } + ++static void dwc3_qcom_enable_wakeup_irq(int irq) ++{ ++ if (!irq) ++ return; ++ ++ enable_irq(irq); ++ enable_irq_wake(irq); ++} ++ ++static void dwc3_qcom_disable_wakeup_irq(int irq) ++{ ++ if (!irq) ++ return; ++ ++ disable_irq_wake(irq); ++ disable_irq_nosync(irq); ++} ++ + static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) + { +- if (qcom->hs_phy_irq) { +- disable_irq_wake(qcom->hs_phy_irq); +- disable_irq_nosync(qcom->hs_phy_irq); +- } ++ dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq); + +- if (qcom->dp_hs_phy_irq) { +- disable_irq_wake(qcom->dp_hs_phy_irq); +- disable_irq_nosync(qcom->dp_hs_phy_irq); +- } ++ dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); + +- if (qcom->dm_hs_phy_irq) { +- disable_irq_wake(qcom->dm_hs_phy_irq); +- disable_irq_nosync(qcom->dm_hs_phy_irq); +- } ++ dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); + +- if (qcom->ss_phy_irq) { +- disable_irq_wake(qcom->ss_phy_irq); +- disable_irq_nosync(qcom->ss_phy_irq); +- } ++ dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); + } + + static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) + { +- if (qcom->hs_phy_irq) { +- enable_irq(qcom->hs_phy_irq); +- enable_irq_wake(qcom->hs_phy_irq); +- } ++ dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq); + +- if (qcom->dp_hs_phy_irq) { +- enable_irq(qcom->dp_hs_phy_irq); +- enable_irq_wake(qcom->dp_hs_phy_irq); +- } ++ dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq); + +- if (qcom->dm_hs_phy_irq) { +- enable_irq(qcom->dm_hs_phy_irq); +- enable_irq_wake(qcom->dm_hs_phy_irq); +- } ++ dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq); + +- if (qcom->ss_phy_irq) { +- enable_irq(qcom->ss_phy_irq); +- enable_irq_wake(qcom->ss_phy_irq); +- } ++ dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq); + } + + static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) +-- +2.35.1 + diff --git a/queue-5.19/usb-dwc3-qcom-configure-wakeup-interrupts-during-sus.patch b/queue-5.19/usb-dwc3-qcom-configure-wakeup-interrupts-during-sus.patch new file mode 100644 index 00000000000..3b7a2e9bdf2 --- /dev/null +++ b/queue-5.19/usb-dwc3-qcom-configure-wakeup-interrupts-during-sus.patch @@ -0,0 +1,156 @@ +From 920c841d0403e84b90d9027060cdfa180d9dc5d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jun 2022 10:00:53 +0530 +Subject: usb: dwc3: qcom: Configure wakeup interrupts during suspend + +From: Sandeep Maheswaram + +[ Upstream commit 6895ea55c385c9afdd2aec1eef27ec24917a112f ] + +Configure DP/DM line interrupts based on the USB2 device attached to +the root hub port. When HS/FS device is connected, configure the DP line +as falling edge to detect both disconnect and remote wakeup scenarios. When +LS device is connected, configure DM line as falling edge to detect both +disconnect and remote wakeup. When no device is connected, configure both +DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. + +Reviewed-by: Pavankumar Kondeti +Reviewed-by: Matthias Kaehlcke +Signed-off-by: Sandeep Maheswaram +Signed-off-by: Krishna Kurapati +Link: https://lore.kernel.org/r/1655094654-24052-5-git-send-email-quic_kriskura@quicinc.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: a872ab303d5d ("usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup") +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/dwc3-qcom.c | 72 +++++++++++++++++++++++++++++++----- + 1 file changed, 62 insertions(+), 10 deletions(-) + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index 27ff18aeea26..be2e3dd36440 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -20,7 +20,8 @@ + #include + #include + #include +- ++#include ++#include + #include "core.h" + + /* USB QSCRATCH Hardware registers */ +@@ -76,6 +77,7 @@ struct dwc3_qcom { + int dp_hs_phy_irq; + int dm_hs_phy_irq; + int ss_phy_irq; ++ enum usb_device_speed usb2_speed; + + struct extcon_dev *edev; + struct extcon_dev *host_edev; +@@ -296,11 +298,34 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) + icc_put(qcom->icc_path_apps); + } + +-static void dwc3_qcom_enable_wakeup_irq(int irq) ++static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) ++{ ++ struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); ++ struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci); ++ struct usb_device *udev; ++ ++ /* ++ * It is possible to query the speed of all children of ++ * USB2.0 root hub via usb_hub_for_each_child(). DWC3 code ++ * currently supports only 1 port per controller. So ++ * this is sufficient. ++ */ ++ udev = usb_hub_find_child(hcd->self.root_hub, 1); ++ ++ if (!udev) ++ return USB_SPEED_UNKNOWN; ++ ++ return udev->speed; ++} ++ ++static void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity) + { + if (!irq) + return; + ++ if (polarity) ++ irq_set_irq_type(irq, polarity); ++ + enable_irq(irq); + enable_irq_wake(irq); + } +@@ -318,22 +343,47 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) + { + dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq); + +- dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); +- +- dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); ++ if (qcom->usb2_speed == USB_SPEED_LOW) { ++ dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); ++ } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || ++ (qcom->usb2_speed == USB_SPEED_FULL)) { ++ dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); ++ } else { ++ dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); ++ dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); ++ } + + dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); + } + + static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) + { +- dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq); ++ dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq, 0); + +- dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq); ++ /* ++ * Configure DP/DM line interrupts based on the USB2 device attached to ++ * the root hub port. When HS/FS device is connected, configure the DP line ++ * as falling edge to detect both disconnect and remote wakeup scenarios. When ++ * LS device is connected, configure DM line as falling edge to detect both ++ * disconnect and remote wakeup. When no device is connected, configure both ++ * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. ++ */ + +- dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq); ++ if (qcom->usb2_speed == USB_SPEED_LOW) { ++ dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, ++ IRQ_TYPE_EDGE_FALLING); ++ } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || ++ (qcom->usb2_speed == USB_SPEED_FULL)) { ++ dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, ++ IRQ_TYPE_EDGE_FALLING); ++ } else { ++ dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, ++ IRQ_TYPE_EDGE_RISING); ++ dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, ++ IRQ_TYPE_EDGE_RISING); ++ } + +- dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq); ++ dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); + } + + static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) +@@ -355,8 +405,10 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) + if (ret) + dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret); + +- if (device_may_wakeup(qcom->dev)) ++ if (device_may_wakeup(qcom->dev)) { ++ qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom); + dwc3_qcom_enable_interrupts(qcom); ++ } + + qcom->is_suspended = true; + +-- +2.35.1 + diff --git a/queue-5.19/usb-dwc3-qcom-fix-gadget-only-builds.patch b/queue-5.19/usb-dwc3-qcom-fix-gadget-only-builds.patch new file mode 100644 index 00000000000..f1ca5cdf32f --- /dev/null +++ b/queue-5.19/usb-dwc3-qcom-fix-gadget-only-builds.patch @@ -0,0 +1,43 @@ +From 0a5869f3029e815c934296d794467722ed4f533d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Aug 2022 17:09:55 +0200 +Subject: usb: dwc3: qcom: fix gadget-only builds + +From: Johan Hovold + +[ Upstream commit c06795f114a6c4a423b11c9d9bbeb77ecbfbaa8b ] + +A recent change added a dependency to the USB host stack and broke +gadget-only builds of the driver. + +Fixes: 6895ea55c385 ("usb: dwc3: qcom: Configure wakeup interrupts during suspend") +Reported-by: Randy Dunlap +Reviewed-by: Randy Dunlap +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20220804151001.23612-4-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/dwc3-qcom.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index b0ae73b0b1a1..6884026b9fad 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -318,8 +318,11 @@ static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) + * currently supports only 1 port per controller. So + * this is sufficient. + */ ++#ifdef CONFIG_USB + udev = usb_hub_find_child(hcd->self.root_hub, 1); +- ++#else ++ udev = NULL; ++#endif + if (!udev) + return USB_SPEED_UNKNOWN; + +-- +2.35.1 + diff --git a/queue-5.19/usb-dwc3-qcom-fix-peripheral-and-otg-suspend.patch b/queue-5.19/usb-dwc3-qcom-fix-peripheral-and-otg-suspend.patch new file mode 100644 index 00000000000..b0074ffa386 --- /dev/null +++ b/queue-5.19/usb-dwc3-qcom-fix-peripheral-and-otg-suspend.patch @@ -0,0 +1,78 @@ +From a989a972abf4ae3f79bbff2d9dc9956eda25e2f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Aug 2022 17:09:58 +0200 +Subject: usb: dwc3: qcom: fix peripheral and OTG suspend + +From: Johan Hovold + +[ Upstream commit c5f14abeb52b0177b940fd734133d383da3521d8 ] + +A recent commit implementing wakeup support in host mode instead broke +suspend for peripheral and OTG mode. + +The hack that was added in the suspend path to determine the speed of +any device connected to the USB2 bus not only accesses internal driver +data for a child device, but also dereferences a NULL pointer or +accesses freed data when the controller is not acting as host. + +There's no quick fix to the layering violation, but since reverting +would leave us with broken suspend in host mode with wakeup triggering +immediately, let's keep the hack for now. + +Fix the immediate issues by only checking the host bus speed and +enabling wakeup interrupts when acting as host. + +Fixes: 6895ea55c385 ("usb: dwc3: qcom: Configure wakeup interrupts during suspend") +Reported-by: kernel test robot +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20220804151001.23612-7-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/dwc3-qcom.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index 05b4666fde14..6ae0b7fc4e2c 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -309,8 +309,13 @@ static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) + static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) + { + struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); +- struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci); + struct usb_device *udev; ++ struct usb_hcd *hcd; ++ ++ /* ++ * FIXME: Fix this layering violation. ++ */ ++ hcd = platform_get_drvdata(dwc->xhci); + + /* + * It is possible to query the speed of all children of +@@ -416,7 +421,11 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) + if (ret) + dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret); + +- if (wakeup) { ++ /* ++ * The role is stable during suspend as role switching is done from a ++ * freezable workqueue. ++ */ ++ if (dwc3_qcom_is_host(qcom) && wakeup) { + qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom); + dwc3_qcom_enable_interrupts(qcom); + } +@@ -434,7 +443,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup) + if (!qcom->is_suspended) + return 0; + +- if (wakeup) ++ if (dwc3_qcom_is_host(qcom) && wakeup) + dwc3_qcom_disable_interrupts(qcom); + + for (i = 0; i < qcom->num_clocks; i++) { +-- +2.35.1 + diff --git a/queue-5.19/usb-dwc3-qcom-fix-runtime-pm-wakeup.patch b/queue-5.19/usb-dwc3-qcom-fix-runtime-pm-wakeup.patch new file mode 100644 index 00000000000..eb05a8bc2ac --- /dev/null +++ b/queue-5.19/usb-dwc3-qcom-fix-runtime-pm-wakeup.patch @@ -0,0 +1,110 @@ +From f9697a17ff2d5fe5d3a0052b6482c955060dec07 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Aug 2022 17:09:57 +0200 +Subject: usb: dwc3: qcom: fix runtime PM wakeup + +From: Johan Hovold + +[ Upstream commit 6498a96c8c9ce8ae4078e586a607851491e29a33 ] + +A device must enable wakeups during runtime suspend regardless of +whether it is capable and allowed to wake the system up from system +suspend. + +Fixes: 2664deb09306 ("usb: dwc3: qcom: Honor wakeup enabled/disabled state") +Tested-by: Matthias Kaehlcke +Reviewed-by: Matthias Kaehlcke +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20220804151001.23612-6-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/dwc3-qcom.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index 6884026b9fad..05b4666fde14 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -397,7 +397,7 @@ static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) + dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); + } + +-static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) ++static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup) + { + u32 val; + int i, ret; +@@ -416,7 +416,7 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) + if (ret) + dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret); + +- if (device_may_wakeup(qcom->dev)) { ++ if (wakeup) { + qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom); + dwc3_qcom_enable_interrupts(qcom); + } +@@ -426,7 +426,7 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) + return 0; + } + +-static int dwc3_qcom_resume(struct dwc3_qcom *qcom) ++static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup) + { + int ret; + int i; +@@ -434,7 +434,7 @@ static int dwc3_qcom_resume(struct dwc3_qcom *qcom) + if (!qcom->is_suspended) + return 0; + +- if (device_may_wakeup(qcom->dev)) ++ if (wakeup) + dwc3_qcom_disable_interrupts(qcom); + + for (i = 0; i < qcom->num_clocks; i++) { +@@ -945,9 +945,11 @@ static int dwc3_qcom_remove(struct platform_device *pdev) + static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev) + { + struct dwc3_qcom *qcom = dev_get_drvdata(dev); ++ bool wakeup = device_may_wakeup(dev); + int ret = 0; + +- ret = dwc3_qcom_suspend(qcom); ++ ++ ret = dwc3_qcom_suspend(qcom, wakeup); + if (!ret) + qcom->pm_suspended = true; + +@@ -957,9 +959,10 @@ static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev) + static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev) + { + struct dwc3_qcom *qcom = dev_get_drvdata(dev); ++ bool wakeup = device_may_wakeup(dev); + int ret; + +- ret = dwc3_qcom_resume(qcom); ++ ret = dwc3_qcom_resume(qcom, wakeup); + if (!ret) + qcom->pm_suspended = false; + +@@ -970,14 +973,14 @@ static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev) + { + struct dwc3_qcom *qcom = dev_get_drvdata(dev); + +- return dwc3_qcom_suspend(qcom); ++ return dwc3_qcom_suspend(qcom, true); + } + + static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev) + { + struct dwc3_qcom *qcom = dev_get_drvdata(dev); + +- return dwc3_qcom_resume(qcom); ++ return dwc3_qcom_resume(qcom, true); + } + + static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = { +-- +2.35.1 + diff --git a/queue-5.19/usb-dwc3-qcom-fix-use-after-free-on-runtime-pm-wakeu.patch b/queue-5.19/usb-dwc3-qcom-fix-use-after-free-on-runtime-pm-wakeu.patch new file mode 100644 index 00000000000..4071b14b4dd --- /dev/null +++ b/queue-5.19/usb-dwc3-qcom-fix-use-after-free-on-runtime-pm-wakeu.patch @@ -0,0 +1,82 @@ +From 8dbc16b2e11c068a35bba2575b9c8e61b82ac2c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Aug 2022 17:09:56 +0200 +Subject: usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup + +From: Johan Hovold + +[ Upstream commit a872ab303d5ddd4c965f9cd868677781a33ce35a ] + +The Qualcomm dwc3 runtime-PM implementation checks the xhci +platform-device pointer in the wakeup-interrupt handler to determine +whether the controller is in host mode and if so triggers a resume. + +After a role switch in OTG mode the xhci platform-device would have been +freed and the next wakeup from runtime suspend would access the freed +memory. + +Note that role switching is executed from a freezable workqueue, which +guarantees that the pointer is stable during suspend. + +Also note that runtime PM has been broken since commit 2664deb09306 +("usb: dwc3: qcom: Honor wakeup enabled/disabled state"), which +incidentally also prevents this issue from being triggered. + +Fixes: a4333c3a6ba9 ("usb: dwc3: Add Qualcomm DWC3 glue driver") +Cc: stable@vger.kernel.org # 4.18 +Reviewed-by: Matthias Kaehlcke +Reviewed-by: Manivannan Sadhasivam +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20220804151001.23612-5-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/dwc3/dwc3-qcom.c | 14 +++++++++++++- + drivers/usb/dwc3/host.c | 1 + + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c +index be2e3dd36440..b0ae73b0b1a1 100644 +--- a/drivers/usb/dwc3/dwc3-qcom.c ++++ b/drivers/usb/dwc3/dwc3-qcom.c +@@ -298,6 +298,14 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) + icc_put(qcom->icc_path_apps); + } + ++/* Only usable in contexts where the role can not change. */ ++static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom) ++{ ++ struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); ++ ++ return dwc->xhci; ++} ++ + static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) + { + struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); +@@ -457,7 +465,11 @@ static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data) + if (qcom->pm_suspended) + return IRQ_HANDLED; + +- if (dwc->xhci) ++ /* ++ * This is safe as role switching is done from a freezable workqueue ++ * and the wakeup interrupts are disabled as part of resume. ++ */ ++ if (dwc3_qcom_is_host(qcom)) + pm_runtime_resume(&dwc->xhci->dev); + + return IRQ_HANDLED; +diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c +index 06b3d988fbf3..a7154fe8206d 100644 +--- a/drivers/usb/dwc3/host.c ++++ b/drivers/usb/dwc3/host.c +@@ -145,4 +145,5 @@ int dwc3_host_init(struct dwc3 *dwc) + void dwc3_host_exit(struct dwc3 *dwc) + { + platform_device_unregister(dwc->xhci); ++ dwc->xhci = NULL; + } +-- +2.35.1 + diff --git a/queue-5.19/usb-gadget-udc-xilinx-replace-memcpy-with-memcpy_toi.patch b/queue-5.19/usb-gadget-udc-xilinx-replace-memcpy-with-memcpy_toi.patch new file mode 100644 index 00000000000..16099cb16ed --- /dev/null +++ b/queue-5.19/usb-gadget-udc-xilinx-replace-memcpy-with-memcpy_toi.patch @@ -0,0 +1,156 @@ +From e6600e3398dae8339649463c395f66e197ebbaca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Aug 2022 12:42:53 +0530 +Subject: usb: gadget: udc-xilinx: replace memcpy with memcpy_toio + +From: Piyush Mehta + +[ Upstream commit 8cb339f1c1f04baede9d54c1e40ac96247a6393b ] + +For ARM processor, unaligned access to device memory is not allowed. +Method memcpy does not take care of alignment. + +USB detection failure with the unaligned address of memory access, with +below kernel crash. To fix the unaligned address the kernel panic issue, +replace memcpy with memcpy_toio method. + +Kernel crash: +Unable to handle kernel paging request at virtual address ffff80000c05008a +Mem abort info: + ESR = 0x96000061 + EC = 0x25: DABT (current EL), IL = 32 bits + SET = 0, FnV = 0 + EA = 0, S1PTW = 0 + FSC = 0x21: alignment fault +Data abort info: + ISV = 0, ISS = 0x00000061 + CM = 0, WnR = 1 +swapper pgtable: 4k pages, 48-bit VAs, pgdp=000000000143b000 +[ffff80000c05008a] pgd=100000087ffff003, p4d=100000087ffff003, +pud=100000087fffe003, pmd=1000000800bcc003, pte=00680000a0010713 +Internal error: Oops: 96000061 [#1] SMP +Modules linked in: +CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.15.19-xilinx-v2022.1 #1 +Hardware name: ZynqMP ZCU102 Rev1.0 (DT) +pstate: 200000c5 (nzCv daIF -PAN -UAO -TCO -DIT -SSBS BTYPE=--) +pc : __memcpy+0x30/0x260 +lr : __xudc_ep0_queue+0xf0/0x110 +sp : ffff800008003d00 +x29: ffff800008003d00 x28: ffff800009474e80 x27: 00000000000000a0 +x26: 0000000000000100 x25: 0000000000000012 x24: ffff000800bc8080 +x23: 0000000000000001 x22: 0000000000000012 x21: ffff000800bc8080 +x20: 0000000000000012 x19: ffff000800bc8080 x18: 0000000000000000 +x17: ffff800876482000 x16: ffff800008004000 x15: 0000000000004000 +x14: 00001f09785d0400 x13: 0103020101005567 x12: 0781400000000200 +x11: 00000000c5672a10 x10: 00000000000008d0 x9 : ffff800009463cf0 +x8 : ffff8000094757b0 x7 : 0201010055670781 x6 : 4000000002000112 +x5 : ffff80000c05009a x4 : ffff000800a15012 x3 : ffff00080362ad80 +x2 : 0000000000000012 x1 : ffff000800a15000 x0 : ffff80000c050088 +Call trace: + __memcpy+0x30/0x260 + xudc_ep0_queue+0x3c/0x60 + usb_ep_queue+0x38/0x44 + composite_ep0_queue.constprop.0+0x2c/0xc0 + composite_setup+0x8d0/0x185c + configfs_composite_setup+0x74/0xb0 + xudc_irq+0x570/0xa40 + __handle_irq_event_percpu+0x58/0x170 + handle_irq_event+0x60/0x120 + handle_fasteoi_irq+0xc0/0x220 + handle_domain_irq+0x60/0x90 + gic_handle_irq+0x74/0xa0 + call_on_irq_stack+0x2c/0x60 + do_interrupt_handler+0x54/0x60 + el1_interrupt+0x30/0x50 + el1h_64_irq_handler+0x18/0x24 + el1h_64_irq+0x78/0x7c + arch_cpu_idle+0x18/0x2c + do_idle+0xdc/0x15c + cpu_startup_entry+0x28/0x60 + rest_init+0xc8/0xe0 + arch_call_rest_init+0x10/0x1c + start_kernel+0x694/0x6d4 + __primary_switched+0xa4/0xac + +Fixes: 1f7c51660034 ("usb: gadget: Add xilinx usb2 device support") +Cc: stable@vger.kernel.org +Reviewed-by: Linus Walleij +Signed-off-by: Piyush Mehta +Link: https://lore.kernel.org/r/20220824071253.1261096-1-piyush.mehta@amd.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/gadget/udc/udc-xilinx.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c +index 4827e3cd3834..054b69dc2f0c 100644 +--- a/drivers/usb/gadget/udc/udc-xilinx.c ++++ b/drivers/usb/gadget/udc/udc-xilinx.c +@@ -499,11 +499,11 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req, + /* Get the Buffer address and copy the transmit data.*/ + eprambase = (u32 __force *)(udc->addr + ep->rambase); + if (ep->is_in) { +- memcpy(eprambase, bufferptr, bytestosend); ++ memcpy_toio(eprambase, bufferptr, bytestosend); + udc->write_fn(udc->addr, ep->offset + + XUSB_EP_BUF0COUNT_OFFSET, bufferlen); + } else { +- memcpy(bufferptr, eprambase, bytestosend); ++ memcpy_toio(bufferptr, eprambase, bytestosend); + } + /* + * Enable the buffer for transmission. +@@ -517,11 +517,11 @@ static int xudc_eptxrx(struct xusb_ep *ep, struct xusb_req *req, + eprambase = (u32 __force *)(udc->addr + ep->rambase + + ep->ep_usb.maxpacket); + if (ep->is_in) { +- memcpy(eprambase, bufferptr, bytestosend); ++ memcpy_toio(eprambase, bufferptr, bytestosend); + udc->write_fn(udc->addr, ep->offset + + XUSB_EP_BUF1COUNT_OFFSET, bufferlen); + } else { +- memcpy(bufferptr, eprambase, bytestosend); ++ memcpy_toio(bufferptr, eprambase, bytestosend); + } + /* + * Enable the buffer for transmission. +@@ -1023,7 +1023,7 @@ static int __xudc_ep0_queue(struct xusb_ep *ep0, struct xusb_req *req) + udc->addr); + length = req->usb_req.actual = min_t(u32, length, + EP0_MAX_PACKET); +- memcpy(corebuf, req->usb_req.buf, length); ++ memcpy_toio(corebuf, req->usb_req.buf, length); + udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, length); + udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1); + } else { +@@ -1752,7 +1752,7 @@ static void xudc_handle_setup(struct xusb_udc *udc) + + /* Load up the chapter 9 command buffer.*/ + ep0rambase = (u32 __force *) (udc->addr + XUSB_SETUP_PKT_ADDR_OFFSET); +- memcpy(&setup, ep0rambase, 8); ++ memcpy_toio(&setup, ep0rambase, 8); + + udc->setup = setup; + udc->setup.wValue = cpu_to_le16(setup.wValue); +@@ -1839,7 +1839,7 @@ static void xudc_ep0_out(struct xusb_udc *udc) + (ep0->rambase << 2)); + buffer = req->usb_req.buf + req->usb_req.actual; + req->usb_req.actual = req->usb_req.actual + bytes_to_rx; +- memcpy(buffer, ep0rambase, bytes_to_rx); ++ memcpy_toio(buffer, ep0rambase, bytes_to_rx); + + if (req->usb_req.length == req->usb_req.actual) { + /* Data transfer completed get ready for Status stage */ +@@ -1915,7 +1915,7 @@ static void xudc_ep0_in(struct xusb_udc *udc) + (ep0->rambase << 2)); + buffer = req->usb_req.buf + req->usb_req.actual; + req->usb_req.actual = req->usb_req.actual + length; +- memcpy(ep0rambase, buffer, length); ++ memcpy_toio(ep0rambase, buffer, length); + } + udc->write_fn(udc->addr, XUSB_EP_BUF0COUNT_OFFSET, count); + udc->write_fn(udc->addr, XUSB_BUFFREADY_OFFSET, 1); +-- +2.35.1 + diff --git a/queue-5.19/xfrm-fix-xfrma_lastused-comment.patch b/queue-5.19/xfrm-fix-xfrma_lastused-comment.patch new file mode 100644 index 00000000000..5f0b1cef350 --- /dev/null +++ b/queue-5.19/xfrm-fix-xfrma_lastused-comment.patch @@ -0,0 +1,35 @@ +From 3ad096e8de321762452e526c210d8e009777836d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 17:40:53 +0200 +Subject: xfrm: fix XFRMA_LASTUSED comment + +From: Antony Antony + +[ Upstream commit 36d763509be326bb383b1b1852a129ff58d74e3b ] + +It is a __u64, internally time64_t. + +Fixes: bf825f81b454 ("xfrm: introduce basic mark infrastructure") +Signed-off-by: Antony Antony +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + include/uapi/linux/xfrm.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h +index 65e13a099b1a..a9f5d884560a 100644 +--- a/include/uapi/linux/xfrm.h ++++ b/include/uapi/linux/xfrm.h +@@ -296,7 +296,7 @@ enum xfrm_attr_type_t { + XFRMA_ETIMER_THRESH, + XFRMA_SRCADDR, /* xfrm_address_t */ + XFRMA_COADDR, /* xfrm_address_t */ +- XFRMA_LASTUSED, /* unsigned long */ ++ XFRMA_LASTUSED, /* __u64 */ + XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */ + XFRMA_MIGRATE, + XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */ +-- +2.35.1 + -- 2.47.3