--- /dev/null
+From 7de7e0ebef49d82376f8829aa3ea9e6c790b950f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jun 2022 08:05:49 +0200
+Subject: block: remove QUEUE_FLAG_DEAD
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ 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 <hch@lst.de>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Link: https://lore.kernel.org/r/20220619060552.1850436-4-hch@lst.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Stable-dep-of: 8fe4ce5836e9 ("scsi: core: Fix a use-after-free")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From dc7d332c13cc0d553c6918d75a70f4166abc3883 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jun 2022 08:05:51 +0200
+Subject: block: simplify disk shutdown
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ 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 <hch@lst.de>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Link: https://lore.kernel.org/r/20220619060552.1850436-6-hch@lst.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Stable-dep-of: 8fe4ce5836e9 ("scsi: core: Fix a use-after-free")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 5968f92808e5a6ceca57cd07186e2de9aff90f08 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 19 Jun 2022 08:05:50 +0200
+Subject: block: stop setting the nomerges flags in blk_cleanup_queue
+
+From: Christoph Hellwig <hch@lst.de>
+
+[ 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 <hch@lst.de>
+Reviewed-by: Hannes Reinecke <hare@suse.de>
+Link: https://lore.kernel.org/r/20220619060552.1850436-5-hch@lst.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Stable-dep-of: 8fe4ce5836e9 ("scsi: core: Fix a use-after-free")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 1438bd4f63cae6ca04173ee98b4350f7190c554d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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ä <ville.syrjala@linux.intel.com>
+
+[ 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 <jani.nikula@intel.com>
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+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 <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 22bc5f164a8d11123afb423e73f891069d3a5e3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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ä <ville.syrjala@linux.intel.com>
+
+[ 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ä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-13-ville.syrjala@linux.intel.com
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From ac9fe905031b0de0c092cb8010ed67a6f8d82f9b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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ä <ville.syrjala@linux.intel.com>
+
+[ 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 <jani.nikula@intel.com>
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+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 <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 68d2795bac565378bf29af0db89f74a8634fc98f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 Aug 2022 18:37:20 +0300
+Subject: drm/i915/dsi: filter invalid backlight and CABC ports
+
+From: Jani Nikula <jani.nikula@intel.com>
+
+[ 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 <jani.nikula@intel.com>
+Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/b0f4f087866257d280eb97d6bcfcefd109cc5fa2.1660664162.git.jani.nikula@intel.com
+(cherry picked from commit f4a6c7a454a6e71c5ccf25af82694213a9784013)
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From f9b0de5da1b03b733800d36abb9da23ca3b1bf3d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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 <jani.nikula@intel.com>
+
+[ 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 <jani.nikula@intel.com>
+Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/8c462718bcc7b36a83e09d0a5eef058b6bc8b1a2.1660664162.git.jani.nikula@intel.com
+(cherry picked from commit ab55165d73a444606af1530cd0d6448b04370f68)
+Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 797e7c7efce2c27c112ce4fe231800d0951e00ac Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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ä <ville.syrjala@linux.intel.com>
+
+[ 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ä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-3-ville.syrjala@linux.intel.com
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From f5691f684277ee39b22b19193956ac4af131f923 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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ä <ville.syrjala@linux.intel.com>
+
+[ 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ä <ville.syrjala@linux.intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20220510104242.6099-4-ville.syrjala@linux.intel.com
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+Stable-dep-of: 607f41768a1e ("drm/i915/dsi: filter invalid backlight and CABC ports")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 8e794602201b071b24a348dce799c504c202a5cc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Sep 2022 15:41:11 +0200
+Subject: net: mvpp2: debugfs: fix memory leak when using debugfs_lookup()
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+[ 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 <mw@semihalf.com>
+Cc: Russell King <linux@armlinux.org.uk>
+Cc: "David S. Miller" <davem@davemloft.net>
+Cc: Eric Dumazet <edumazet@google.com>
+Cc: Jakub Kicinski <kuba@kernel.org>
+Cc: Paolo Abeni <pabeni@redhat.com>
+Cc: netdev@vger.kernel.org
+Cc: stable <stable@kernel.org>
+Fixes: 21da57a23125 ("net: mvpp2: add a debugfs interface for the Header Parser")
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From b8fc4a65f65b51bce40d2f1968f65155f1ff759c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 31 Aug 2022 10:34:25 +0200
+Subject: Revert "usb: add quirks for Lenovo OneLink+ Dock"
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+[ 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 <oneukum@suse.com>
+Cc: Jean-Francois Le Fillatre <jflf_kernel@gmx.com>
+Cc: stable <stable@kernel.org>
+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 <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 2fa098146195e3a8a32a5837e1329d606c7eed6c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Sep 2022 09:10:08 +0200
+Subject: Revert "usb: gadget: udc-xilinx: replace memcpy with memcpy_toio"
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+[ 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 <lkp@intel.com>
+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 <linus.walleij@linaro.org>
+Cc: Piyush Mehta <piyush.mehta@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 1ca31cce4a18e6c68ea9817aa6b11e90abd7b180 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 25 Aug 2022 17:26:34 -0700
+Subject: scsi: core: Fix a use-after-free
+
+From: Bart Van Assche <bvanassche@acm.org>
+
+[ 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:
+ <TASK>
+ 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 <ming.lei@redhat.com>
+Cc: Christoph Hellwig <hch@lst.de>
+Cc: Mike Christie <michael.christie@oracle.com>
+Cc: Hannes Reinecke <hare@suse.de>
+Cc: John Garry <john.garry@huawei.com>
+Cc: Li Zhijian <lizhijian@fujitsu.com>
+Reported-by: Li Zhijian <lizhijian@fujitsu.com>
+Tested-by: Li Zhijian <lizhijian@fujitsu.com>
+Signed-off-by: Bart Van Assche <bvanassche@acm.org>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+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
--- /dev/null
+From 1228cadaeb30d892724a74fc186816df199a458f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Aug 2022 14:07:41 +0100
+Subject: smb3: fix temporary data corruption in collapse range
+
+From: Steve French <stfrench@microsoft.com>
+
+[ 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 <dhowells@redhat.com>
+Tested-by: David Howells <dhowells@redhat.com>
+Reviewed-by: David Howells <dhowells@redhat.com>
+cc: Ronnie Sahlberg <lsahlber@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 8b64323e4828fd9b330d892005051e1d4f36dd0f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Aug 2022 14:07:55 +0100
+Subject: smb3: fix temporary data corruption in insert range
+
+From: David Howells <dhowells@redhat.com>
+
+[ 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 <dhowells@redhat.com>
+cc: Ronnie Sahlberg <lsahlber@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From dd21d6b9e45779fe64c07f4fa39a56502f2dc4eb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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 <dhowells@redhat.com>
+
+[ 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 <dhowells@redhat.com>
+cc: Ronnie Sahlberg <lsahlber@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: fa30a81f255a ("smb3: fix temporary data corruption in collapse range")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 4342751c15e194569c55acfe466e0d57b8ca9e01 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+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 <stfrench@microsoft.com>
+
+[ 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) <pc@cjr.nz>
+Reviewed-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 710e110297312ffc42ea62d68331214ac71a7d2c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Aug 2022 21:13:21 +0200
+Subject: usb: add quirks for Lenovo OneLink+ Dock
+
+From: Jean-Francois Le Fillatre <jflf_kernel@gmx.com>
+
+[ 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 <jflf_kernel@gmx.com>
+Cc: stable <stable@kernel.org>
+Link: https://lore.kernel.org/r/20220824191320.17883-1-jflf_kernel@gmx.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 78f61759ac383ddf34cd93009ea6eae1a75c234f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jun 2022 10:00:52 +0530
+Subject: usb: dwc3: qcom: Add helper functions to enable,disable wake irqs
+
+From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
+
+[ Upstream commit 360e8230516de94d74d30c64f0cdcf228b8e8b67 ]
+
+Adding helper functions to enable,disable wake irqs to make
+the code simple and readable.
+
+Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
+Reviewed-by: Pavankumar Kondeti <quic_pkondeti@quicinc.com>
+Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
+Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
+Link: https://lore.kernel.org/r/1655094654-24052-4-git-send-email-quic_kriskura@quicinc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: a872ab303d5d ("usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 920c841d0403e84b90d9027060cdfa180d9dc5d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jun 2022 10:00:53 +0530
+Subject: usb: dwc3: qcom: Configure wakeup interrupts during suspend
+
+From: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
+
+[ 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 <quic_pkondeti@quicinc.com>
+Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
+Signed-off-by: Sandeep Maheswaram <quic_c_sanm@quicinc.com>
+Signed-off-by: Krishna Kurapati <quic_kriskura@quicinc.com>
+Link: https://lore.kernel.org/r/1655094654-24052-5-git-send-email-quic_kriskura@quicinc.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: a872ab303d5d ("usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 <linux/usb/of.h>
+ #include <linux/reset.h>
+ #include <linux/iopoll.h>
+-
++#include <linux/usb/hcd.h>
++#include <linux/usb.h>
+ #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
+
--- /dev/null
+From 0a5869f3029e815c934296d794467722ed4f533d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Aug 2022 17:09:55 +0200
+Subject: usb: dwc3: qcom: fix gadget-only builds
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ 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 <rdunlap@infradead.org>
+Reviewed-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20220804151001.23612-4-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From a989a972abf4ae3f79bbff2d9dc9956eda25e2f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Aug 2022 17:09:58 +0200
+Subject: usb: dwc3: qcom: fix peripheral and OTG suspend
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ 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 <lkp@intel.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20220804151001.23612-7-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From f9697a17ff2d5fe5d3a0052b6482c955060dec07 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Aug 2022 17:09:57 +0200
+Subject: usb: dwc3: qcom: fix runtime PM wakeup
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ 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 <mka@chromium.org>
+Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20220804151001.23612-6-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 8dbc16b2e11c068a35bba2575b9c8e61b82ac2c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 4 Aug 2022 17:09:56 +0200
+Subject: usb: dwc3: qcom: fix use-after-free on runtime-PM wakeup
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+[ 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 <mka@chromium.org>
+Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20220804151001.23612-5-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From e6600e3398dae8339649463c395f66e197ebbaca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Aug 2022 12:42:53 +0530
+Subject: usb: gadget: udc-xilinx: replace memcpy with memcpy_toio
+
+From: Piyush Mehta <piyush.mehta@amd.com>
+
+[ 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 <linus.walleij@linaro.org>
+Signed-off-by: Piyush Mehta <piyush.mehta@amd.com>
+Link: https://lore.kernel.org/r/20220824071253.1261096-1-piyush.mehta@amd.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+
--- /dev/null
+From 3ad096e8de321762452e526c210d8e009777836d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Jul 2022 17:40:53 +0200
+Subject: xfrm: fix XFRMA_LASTUSED comment
+
+From: Antony Antony <antony.antony@secunet.com>
+
+[ Upstream commit 36d763509be326bb383b1b1852a129ff58d74e3b ]
+
+It is a __u64, internally time64_t.
+
+Fixes: bf825f81b454 ("xfrm: introduce basic mark infrastructure")
+Signed-off-by: Antony Antony <antony.antony@secunet.com>
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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
+