--- /dev/null
+From cd9253c23aedd61eb5ff11f37a36247cd46faf86 Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Thu, 29 Aug 2024 18:25:49 +0100
+Subject: btrfs: fix race between direct IO write and fsync when using same fd
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit cd9253c23aedd61eb5ff11f37a36247cd46faf86 upstream.
+
+If we have 2 threads that are using the same file descriptor and one of
+them is doing direct IO writes while the other is doing fsync, we have a
+race where we can end up either:
+
+1) Attempt a fsync without holding the inode's lock, triggering an
+ assertion failures when assertions are enabled;
+
+2) Do an invalid memory access from the fsync task because the file private
+ points to memory allocated on stack by the direct IO task and it may be
+ used by the fsync task after the stack was destroyed.
+
+The race happens like this:
+
+1) A user space program opens a file descriptor with O_DIRECT;
+
+2) The program spawns 2 threads using libpthread for example;
+
+3) One of the threads uses the file descriptor to do direct IO writes,
+ while the other calls fsync using the same file descriptor.
+
+4) Call task A the thread doing direct IO writes and task B the thread
+ doing fsyncs;
+
+5) Task A does a direct IO write, and at btrfs_direct_write() sets the
+ file's private to an on stack allocated private with the member
+ 'fsync_skip_inode_lock' set to true;
+
+6) Task B enters btrfs_sync_file() and sees that there's a private
+ structure associated to the file which has 'fsync_skip_inode_lock' set
+ to true, so it skips locking the inode's VFS lock;
+
+7) Task A completes the direct IO write, and resets the file's private to
+ NULL since it had no prior private and our private was stack allocated.
+ Then it unlocks the inode's VFS lock;
+
+8) Task B enters btrfs_get_ordered_extents_for_logging(), then the
+ assertion that checks the inode's VFS lock is held fails, since task B
+ never locked it and task A has already unlocked it.
+
+The stack trace produced is the following:
+
+ assertion failed: inode_is_locked(&inode->vfs_inode), in fs/btrfs/ordered-data.c:983
+ ------------[ cut here ]------------
+ kernel BUG at fs/btrfs/ordered-data.c:983!
+ Oops: invalid opcode: 0000 [#1] PREEMPT SMP PTI
+ CPU: 9 PID: 5072 Comm: worker Tainted: G U OE 6.10.5-1-default #1 openSUSE Tumbleweed 69f48d427608e1c09e60ea24c6c55e2ca1b049e8
+ Hardware name: Acer Predator PH315-52/Covini_CFS, BIOS V1.12 07/28/2020
+ RIP: 0010:btrfs_get_ordered_extents_for_logging.cold+0x1f/0x42 [btrfs]
+ Code: 50 d6 86 c0 e8 (...)
+ RSP: 0018:ffff9e4a03dcfc78 EFLAGS: 00010246
+ RAX: 0000000000000054 RBX: ffff9078a9868e98 RCX: 0000000000000000
+ RDX: 0000000000000000 RSI: ffff907dce4a7800 RDI: ffff907dce4a7800
+ RBP: ffff907805518800 R08: 0000000000000000 R09: ffff9e4a03dcfb38
+ R10: ffff9e4a03dcfb30 R11: 0000000000000003 R12: ffff907684ae7800
+ R13: 0000000000000001 R14: ffff90774646b600 R15: 0000000000000000
+ FS: 00007f04b96006c0(0000) GS:ffff907dce480000(0000) knlGS:0000000000000000
+ CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ CR2: 00007f32acbfc000 CR3: 00000001fd4fa005 CR4: 00000000003726f0
+ Call Trace:
+ <TASK>
+ ? __die_body.cold+0x14/0x24
+ ? die+0x2e/0x50
+ ? do_trap+0xca/0x110
+ ? do_error_trap+0x6a/0x90
+ ? btrfs_get_ordered_extents_for_logging.cold+0x1f/0x42 [btrfs bb26272d49b4cdc847cf3f7faadd459b62caee9a]
+ ? exc_invalid_op+0x50/0x70
+ ? btrfs_get_ordered_extents_for_logging.cold+0x1f/0x42 [btrfs bb26272d49b4cdc847cf3f7faadd459b62caee9a]
+ ? asm_exc_invalid_op+0x1a/0x20
+ ? btrfs_get_ordered_extents_for_logging.cold+0x1f/0x42 [btrfs bb26272d49b4cdc847cf3f7faadd459b62caee9a]
+ ? btrfs_get_ordered_extents_for_logging.cold+0x1f/0x42 [btrfs bb26272d49b4cdc847cf3f7faadd459b62caee9a]
+ btrfs_sync_file+0x21a/0x4d0 [btrfs bb26272d49b4cdc847cf3f7faadd459b62caee9a]
+ ? __seccomp_filter+0x31d/0x4f0
+ __x64_sys_fdatasync+0x4f/0x90
+ do_syscall_64+0x82/0x160
+ ? do_futex+0xcb/0x190
+ ? __x64_sys_futex+0x10e/0x1d0
+ ? switch_fpu_return+0x4f/0xd0
+ ? syscall_exit_to_user_mode+0x72/0x220
+ ? do_syscall_64+0x8e/0x160
+ ? syscall_exit_to_user_mode+0x72/0x220
+ ? do_syscall_64+0x8e/0x160
+ ? syscall_exit_to_user_mode+0x72/0x220
+ ? do_syscall_64+0x8e/0x160
+ ? syscall_exit_to_user_mode+0x72/0x220
+ ? do_syscall_64+0x8e/0x160
+ entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+Another problem here is if task B grabs the private pointer and then uses
+it after task A has finished, since the private was allocated in the stack
+of task A, it results in some invalid memory access with a hard to predict
+result.
+
+This issue, triggering the assertion, was observed with QEMU workloads by
+two users in the Link tags below.
+
+Fix this by not relying on a file's private to pass information to fsync
+that it should skip locking the inode and instead pass this information
+through a special value stored in current->journal_info. This is safe
+because in the relevant section of the direct IO write path we are not
+holding a transaction handle, so current->journal_info is NULL.
+
+The following C program triggers the issue:
+
+ $ cat repro.c
+ /* Get the O_DIRECT definition. */
+ #ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+ #endif
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <stdint.h>
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <string.h>
+ #include <pthread.h>
+
+ static int fd;
+
+ static ssize_t do_write(int fd, const void *buf, size_t count, off_t offset)
+ {
+ while (count > 0) {
+ ssize_t ret;
+
+ ret = pwrite(fd, buf, count, offset);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ return ret;
+ }
+ count -= ret;
+ buf += ret;
+ }
+ return 0;
+ }
+
+ static void *fsync_loop(void *arg)
+ {
+ while (1) {
+ int ret;
+
+ ret = fsync(fd);
+ if (ret != 0) {
+ perror("Fsync failed");
+ exit(6);
+ }
+ }
+ }
+
+ int main(int argc, char *argv[])
+ {
+ long pagesize;
+ void *write_buf;
+ pthread_t fsyncer;
+ int ret;
+
+ if (argc != 2) {
+ fprintf(stderr, "Use: %s <file path>\n", argv[0]);
+ return 1;
+ }
+
+ fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC | O_DIRECT, 0666);
+ if (fd == -1) {
+ perror("Failed to open/create file");
+ return 1;
+ }
+
+ pagesize = sysconf(_SC_PAGE_SIZE);
+ if (pagesize == -1) {
+ perror("Failed to get page size");
+ return 2;
+ }
+
+ ret = posix_memalign(&write_buf, pagesize, pagesize);
+ if (ret) {
+ perror("Failed to allocate buffer");
+ return 3;
+ }
+
+ ret = pthread_create(&fsyncer, NULL, fsync_loop, NULL);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to create writer thread: %d\n", ret);
+ return 4;
+ }
+
+ while (1) {
+ ret = do_write(fd, write_buf, pagesize, 0);
+ if (ret != 0) {
+ perror("Write failed");
+ exit(5);
+ }
+ }
+
+ return 0;
+ }
+
+ $ mkfs.btrfs -f /dev/sdi
+ $ mount /dev/sdi /mnt/sdi
+ $ timeout 10 ./repro /mnt/sdi/foo
+
+Usually the race is triggered within less than 1 second. A test case for
+fstests will follow soon.
+
+Reported-by: Paulo Dias <paulo.miguel.dias@gmail.com>
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=219187
+Reported-by: Andreas Jahn <jahn-andi@web.de>
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=219199
+Reported-by: syzbot+4704b3cc972bd76024f1@syzkaller.appspotmail.com
+Link: https://lore.kernel.org/linux-btrfs/00000000000044ff540620d7dee2@google.com/
+Fixes: 939b656bc8ab ("btrfs: fix corruption after buffer fault in during direct IO append write")
+CC: stable@vger.kernel.org # 5.15+
+Reviewed-by: Josef Bacik <josef@toxicpanda.com>
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/ctree.h | 1 -
+ fs/btrfs/file.c | 25 ++++++++++---------------
+ fs/btrfs/transaction.h | 6 ++++++
+ 3 files changed, 16 insertions(+), 16 deletions(-)
+
+--- a/fs/btrfs/ctree.h
++++ b/fs/btrfs/ctree.h
+@@ -457,7 +457,6 @@ struct btrfs_file_private {
+ void *filldir_buf;
+ u64 last_index;
+ struct extent_state *llseek_cached_state;
+- bool fsync_skip_inode_lock;
+ };
+
+ static inline u32 BTRFS_LEAF_DATA_SIZE(const struct btrfs_fs_info *info)
+--- a/fs/btrfs/file.c
++++ b/fs/btrfs/file.c
+@@ -1558,13 +1558,6 @@ again:
+ if (IS_ERR_OR_NULL(dio)) {
+ ret = PTR_ERR_OR_ZERO(dio);
+ } else {
+- struct btrfs_file_private stack_private = { 0 };
+- struct btrfs_file_private *private;
+- const bool have_private = (file->private_data != NULL);
+-
+- if (!have_private)
+- file->private_data = &stack_private;
+-
+ /*
+ * If we have a synchoronous write, we must make sure the fsync
+ * triggered by the iomap_dio_complete() call below doesn't
+@@ -1573,13 +1566,10 @@ again:
+ * partial writes due to the input buffer (or parts of it) not
+ * being already faulted in.
+ */
+- private = file->private_data;
+- private->fsync_skip_inode_lock = true;
++ ASSERT(current->journal_info == NULL);
++ current->journal_info = BTRFS_TRANS_DIO_WRITE_STUB;
+ ret = iomap_dio_complete(dio);
+- private->fsync_skip_inode_lock = false;
+-
+- if (!have_private)
+- file->private_data = NULL;
++ current->journal_info = NULL;
+ }
+
+ /* No increment (+=) because iomap returns a cumulative value. */
+@@ -1811,7 +1801,6 @@ static inline bool skip_inode_logging(co
+ */
+ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
+ {
+- struct btrfs_file_private *private = file->private_data;
+ struct dentry *dentry = file_dentry(file);
+ struct inode *inode = d_inode(dentry);
+ struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
+@@ -1821,7 +1810,13 @@ int btrfs_sync_file(struct file *file, l
+ int ret = 0, err;
+ u64 len;
+ bool full_sync;
+- const bool skip_ilock = (private ? private->fsync_skip_inode_lock : false);
++ bool skip_ilock = false;
++
++ if (current->journal_info == BTRFS_TRANS_DIO_WRITE_STUB) {
++ skip_ilock = true;
++ current->journal_info = NULL;
++ lockdep_assert_held(&inode->i_rwsem);
++ }
+
+ trace_btrfs_sync_file(file, datasync);
+
+--- a/fs/btrfs/transaction.h
++++ b/fs/btrfs/transaction.h
+@@ -27,6 +27,12 @@ struct btrfs_root_item;
+ struct btrfs_root;
+ struct btrfs_path;
+
++/*
++ * Signal that a direct IO write is in progress, to avoid deadlock for sync
++ * direct IO writes when fsync is called during the direct IO write path.
++ */
++#define BTRFS_TRANS_DIO_WRITE_STUB ((void *) 1)
++
+ /* Radix-tree tag for roots that are part of the trasaction. */
+ #define BTRFS_ROOT_TRANS_TAG 0
+
--- /dev/null
+From 43cf50eb1408ccb99cab01521263e8cb4cfdc023 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jouni=20H=C3=B6gander?= <jouni.hogander@intel.com>
+Date: Mon, 2 Sep 2024 09:42:40 +0300
+Subject: drm/i915/display: Add mechanism to use sink model when applying quirk
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jouni Högander <jouni.hogander@intel.com>
+
+commit 43cf50eb1408ccb99cab01521263e8cb4cfdc023 upstream.
+
+Currently there is no way to apply quirk on device only if certain panel
+model is installed. This patch implements such mechanism by adding new
+quirk type intel_dpcd_quirk which contains also sink_oui and sink_device_id
+fields and using also them to figure out if applying quirk is needed.
+
+New intel_init_dpcd_quirks is added and called after drm_dp_read_desc with
+proper sink device identity read from dpcdc.
+
+v3:
+ - !mem_is_zero fixed to mem_is_zero
+v2:
+ - instead of using struct intel_quirk add new struct intel_dpcd_quirk
+
+Signed-off-by: Jouni Högander <jouni.hogander@intel.com>
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20240902064241.1020965-2-jouni.hogander@intel.com
+(cherry picked from commit b3b91369908ac63be6f64905448b8ba5cd151875)
+Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/display/intel_display_types.h | 4 +
+ drivers/gpu/drm/i915/display/intel_dp.c | 4 +
+ drivers/gpu/drm/i915/display/intel_quirks.c | 51 +++++++++++++++++++++
+ drivers/gpu/drm/i915/display/intel_quirks.h | 5 ++
+ 4 files changed, 64 insertions(+)
+
+--- a/drivers/gpu/drm/i915/display/intel_display_types.h
++++ b/drivers/gpu/drm/i915/display/intel_display_types.h
+@@ -1840,6 +1840,10 @@ struct intel_dp {
+ unsigned long last_oui_write;
+
+ bool colorimetry_support;
++
++ struct {
++ unsigned long mask;
++ } quirks;
+ };
+
+ enum lspcon_vendor {
+--- a/drivers/gpu/drm/i915/display/intel_dp.c
++++ b/drivers/gpu/drm/i915/display/intel_dp.c
+@@ -79,6 +79,7 @@
+ #include "intel_pch_display.h"
+ #include "intel_pps.h"
+ #include "intel_psr.h"
++#include "intel_quirks.h"
+ #include "intel_tc.h"
+ #include "intel_vdsc.h"
+ #include "intel_vrr.h"
+@@ -3941,6 +3942,7 @@ intel_edp_init_dpcd(struct intel_dp *int
+
+ drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
+ drm_dp_is_branch(intel_dp->dpcd));
++ intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
+
+ /*
+ * Read the eDP display control registers.
+@@ -4053,6 +4055,8 @@ intel_dp_get_dpcd(struct intel_dp *intel
+ drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc,
+ drm_dp_is_branch(intel_dp->dpcd));
+
++ intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident);
++
+ intel_dp_update_sink_caps(intel_dp);
+ }
+
+--- a/drivers/gpu/drm/i915/display/intel_quirks.c
++++ b/drivers/gpu/drm/i915/display/intel_quirks.c
+@@ -14,6 +14,11 @@ static void intel_set_quirk(struct intel
+ display->quirks.mask |= BIT(quirk);
+ }
+
++static void intel_set_dpcd_quirk(struct intel_dp *intel_dp, enum intel_quirk_id quirk)
++{
++ intel_dp->quirks.mask |= BIT(quirk);
++}
++
+ /*
+ * Some machines (Lenovo U160) do not work with SSC on LVDS for some reason
+ */
+@@ -72,6 +77,21 @@ struct intel_quirk {
+ void (*hook)(struct intel_display *display);
+ };
+
++struct intel_dpcd_quirk {
++ int device;
++ int subsystem_vendor;
++ int subsystem_device;
++ u8 sink_oui[3];
++ u8 sink_device_id[6];
++ void (*hook)(struct intel_dp *intel_dp);
++};
++
++#define SINK_OUI(first, second, third) { (first), (second), (third) }
++#define SINK_DEVICE_ID(first, second, third, fourth, fifth, sixth) \
++ { (first), (second), (third), (fourth), (fifth), (sixth) }
++
++#define SINK_DEVICE_ID_ANY SINK_DEVICE_ID(0, 0, 0, 0, 0, 0)
++
+ /* For systems that don't have a meaningful PCI subdevice/subvendor ID */
+ struct intel_dmi_quirk {
+ void (*hook)(struct intel_display *display);
+@@ -203,6 +223,9 @@ static struct intel_quirk intel_quirks[]
+ { 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
+ };
+
++static struct intel_dpcd_quirk intel_dpcd_quirks[] = {
++};
++
+ void intel_init_quirks(struct intel_display *display)
+ {
+ struct pci_dev *d = to_pci_dev(display->drm->dev);
+@@ -224,7 +247,35 @@ void intel_init_quirks(struct intel_disp
+ }
+ }
+
++void intel_init_dpcd_quirks(struct intel_dp *intel_dp,
++ const struct drm_dp_dpcd_ident *ident)
++{
++ struct intel_display *display = to_intel_display(intel_dp);
++ struct pci_dev *d = to_pci_dev(display->drm->dev);
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(intel_dpcd_quirks); i++) {
++ struct intel_dpcd_quirk *q = &intel_dpcd_quirks[i];
++
++ if (d->device == q->device &&
++ (d->subsystem_vendor == q->subsystem_vendor ||
++ q->subsystem_vendor == PCI_ANY_ID) &&
++ (d->subsystem_device == q->subsystem_device ||
++ q->subsystem_device == PCI_ANY_ID) &&
++ !memcmp(q->sink_oui, ident->oui, sizeof(ident->oui)) &&
++ (!memcmp(q->sink_device_id, ident->device_id,
++ sizeof(ident->device_id)) ||
++ mem_is_zero(q->sink_device_id, sizeof(q->sink_device_id))))
++ q->hook(intel_dp);
++ }
++}
++
+ bool intel_has_quirk(struct intel_display *display, enum intel_quirk_id quirk)
+ {
+ return display->quirks.mask & BIT(quirk);
+ }
++
++bool intel_has_dpcd_quirk(struct intel_dp *intel_dp, enum intel_quirk_id quirk)
++{
++ return intel_dp->quirks.mask & BIT(quirk);
++}
+--- a/drivers/gpu/drm/i915/display/intel_quirks.h
++++ b/drivers/gpu/drm/i915/display/intel_quirks.h
+@@ -9,6 +9,8 @@
+ #include <linux/types.h>
+
+ struct intel_display;
++struct intel_dp;
++struct drm_dp_dpcd_ident;
+
+ enum intel_quirk_id {
+ QUIRK_BACKLIGHT_PRESENT,
+@@ -20,6 +22,9 @@ enum intel_quirk_id {
+ };
+
+ void intel_init_quirks(struct intel_display *display);
++void intel_init_dpcd_quirks(struct intel_dp *intel_dp,
++ const struct drm_dp_dpcd_ident *ident);
+ bool intel_has_quirk(struct intel_display *display, enum intel_quirk_id quirk);
++bool intel_has_dpcd_quirk(struct intel_dp *intel_dp, enum intel_quirk_id quirk);
+
+ #endif /* __INTEL_QUIRKS_H__ */
--- /dev/null
+From a13494de53258d8cf82ed3bcd69176bbf7f2640e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jouni=20H=C3=B6gander?= <jouni.hogander@intel.com>
+Date: Mon, 2 Sep 2024 09:42:41 +0300
+Subject: drm/i915/display: Increase Fast Wake Sync length as a quirk
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jouni Högander <jouni.hogander@intel.com>
+
+commit a13494de53258d8cf82ed3bcd69176bbf7f2640e upstream.
+
+In commit "drm/i915/display: Increase number of fast wake precharge pulses"
+we were increasing Fast Wake sync pulse length to fix problems observed on
+Dell Precision 5490 laptop with AUO panel. Later we have observed this is
+causing problems on other panels.
+
+Fix these problems by increasing Fast Wake sync pulse length as a quirk
+applied for Dell Precision 5490 with problematic panel.
+
+Fixes: f77772866385 ("drm/i915/display: Increase number of fast wake precharge pulses")
+Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Closes: http://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9739
+Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/2246
+Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/11762
+Signed-off-by: Jouni Högander <jouni.hogander@intel.com>
+Reviewed-by: Jani Nikula <jani.nikula@intel.com>
+Cc: <stable@vger.kernel.org> # v6.10+
+Link: https://patchwork.freedesktop.org/patch/msgid/20240902064241.1020965-3-jouni.hogander@intel.com
+(cherry picked from commit fcba2ed66b39252210f4e739722ebcc5398c2197)
+Requires: 43cf50eb1408 ("drm/i915/display: Add mechanism to use sink model when applying quirk")
+Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/i915/display/intel_dp_aux.c | 16 +++++++++++-----
+ drivers/gpu/drm/i915/display/intel_dp_aux.h | 2 +-
+ drivers/gpu/drm/i915/display/intel_psr.c | 2 +-
+ drivers/gpu/drm/i915/display/intel_quirks.c | 19 ++++++++++++++++++-
+ drivers/gpu/drm/i915/display/intel_quirks.h | 1 +
+ 5 files changed, 32 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/i915/display/intel_dp_aux.c
++++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c
+@@ -13,6 +13,7 @@
+ #include "intel_dp_aux.h"
+ #include "intel_dp_aux_regs.h"
+ #include "intel_pps.h"
++#include "intel_quirks.h"
+ #include "intel_tc.h"
+
+ #define AUX_CH_NAME_BUFSIZE 6
+@@ -142,16 +143,21 @@ static int intel_dp_aux_sync_len(void)
+ return precharge + preamble;
+ }
+
+-int intel_dp_aux_fw_sync_len(void)
++int intel_dp_aux_fw_sync_len(struct intel_dp *intel_dp)
+ {
++ int precharge = 10; /* 10-16 */
++ int preamble = 8;
++
+ /*
+ * We faced some glitches on Dell Precision 5490 MTL laptop with panel:
+ * "Manufacturer: AUO, Model: 63898" when using HW default 18. Using 20
+ * is fixing these problems with the panel. It is still within range
+- * mentioned in eDP specification.
++ * mentioned in eDP specification. Increasing Fast Wake sync length is
++ * causing problems with other panels: increase length as a quirk for
++ * this specific laptop.
+ */
+- int precharge = 12; /* 10-16 */
+- int preamble = 8;
++ if (intel_has_dpcd_quirk(intel_dp, QUIRK_FW_SYNC_LEN))
++ precharge += 2;
+
+ return precharge + preamble;
+ }
+@@ -211,7 +217,7 @@ static u32 skl_get_aux_send_ctl(struct i
+ DP_AUX_CH_CTL_TIME_OUT_MAX |
+ DP_AUX_CH_CTL_RECEIVE_ERROR |
+ DP_AUX_CH_CTL_MESSAGE_SIZE(send_bytes) |
+- DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(intel_dp_aux_fw_sync_len()) |
++ DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(intel_dp_aux_fw_sync_len(intel_dp)) |
+ DP_AUX_CH_CTL_SYNC_PULSE_SKL(intel_dp_aux_sync_len());
+
+ if (intel_tc_port_in_tbt_alt_mode(dig_port))
+--- a/drivers/gpu/drm/i915/display/intel_dp_aux.h
++++ b/drivers/gpu/drm/i915/display/intel_dp_aux.h
+@@ -20,6 +20,6 @@ enum aux_ch intel_dp_aux_ch(struct intel
+
+ void intel_dp_aux_irq_handler(struct drm_i915_private *i915);
+ u32 intel_dp_aux_pack(const u8 *src, int src_bytes);
+-int intel_dp_aux_fw_sync_len(void);
++int intel_dp_aux_fw_sync_len(struct intel_dp *intel_dp);
+
+ #endif /* __INTEL_DP_AUX_H__ */
+--- a/drivers/gpu/drm/i915/display/intel_psr.c
++++ b/drivers/gpu/drm/i915/display/intel_psr.c
+@@ -1356,7 +1356,7 @@ static bool _compute_alpm_params(struct
+ int tfw_exit_latency = 20; /* eDP spec */
+ int phy_wake = 4; /* eDP spec */
+ int preamble = 8; /* eDP spec */
+- int precharge = intel_dp_aux_fw_sync_len() - preamble;
++ int precharge = intel_dp_aux_fw_sync_len(intel_dp) - preamble;
+ u8 max_wake_lines;
+
+ io_wake_time = max(precharge, io_buffer_wake_time(crtc_state)) +
+--- a/drivers/gpu/drm/i915/display/intel_quirks.c
++++ b/drivers/gpu/drm/i915/display/intel_quirks.c
+@@ -70,6 +70,14 @@ static void quirk_no_pps_backlight_power
+ drm_info(display->drm, "Applying no pps backlight power quirk\n");
+ }
+
++static void quirk_fw_sync_len(struct intel_dp *intel_dp)
++{
++ struct intel_display *display = to_intel_display(intel_dp);
++
++ intel_set_dpcd_quirk(intel_dp, QUIRK_FW_SYNC_LEN);
++ drm_info(display->drm, "Applying Fast Wake sync pulse count quirk\n");
++}
++
+ struct intel_quirk {
+ int device;
+ int subsystem_vendor;
+@@ -224,6 +232,15 @@ static struct intel_quirk intel_quirks[]
+ };
+
+ static struct intel_dpcd_quirk intel_dpcd_quirks[] = {
++ /* Dell Precision 5490 */
++ {
++ .device = 0x7d55,
++ .subsystem_vendor = 0x1028,
++ .subsystem_device = 0x0cc7,
++ .sink_oui = SINK_OUI(0x38, 0xec, 0x11),
++ .hook = quirk_fw_sync_len,
++ },
++
+ };
+
+ void intel_init_quirks(struct intel_display *display)
+@@ -265,7 +282,7 @@ void intel_init_dpcd_quirks(struct intel
+ !memcmp(q->sink_oui, ident->oui, sizeof(ident->oui)) &&
+ (!memcmp(q->sink_device_id, ident->device_id,
+ sizeof(ident->device_id)) ||
+- mem_is_zero(q->sink_device_id, sizeof(q->sink_device_id))))
++ !memchr_inv(q->sink_device_id, 0, sizeof(q->sink_device_id))))
+ q->hook(intel_dp);
+ }
+ }
+--- a/drivers/gpu/drm/i915/display/intel_quirks.h
++++ b/drivers/gpu/drm/i915/display/intel_quirks.h
+@@ -19,6 +19,7 @@ enum intel_quirk_id {
+ QUIRK_INVERT_BRIGHTNESS,
+ QUIRK_LVDS_SSC_DISABLE,
+ QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK,
++ QUIRK_FW_SYNC_LEN,
+ };
+
+ void intel_init_quirks(struct intel_display *display);
nvmet-identify-active-namespace-id-list-command-shou.patch
ublk_drv-fix-null-pointer-dereference-in-ublk_ctrl_s.patch
x86-mm-fix-pti-for-i386-some-more.patch
+drm-i915-display-add-mechanism-to-use-sink-model-when-applying-quirk.patch
+drm-i915-display-increase-fast-wake-sync-length-as-a-quirk.patch
+btrfs-fix-race-between-direct-io-write-and-fsync-when-using-same-fd.patch