--- /dev/null
+From ee59420526d47ee7ea747caa98d04afdebeb2fc7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 19 Jun 2023 17:21:50 +0100
+Subject: btrfs: fix race between quota disable and relocation
+
+From: Filipe Manana <fdmanana@suse.com>
+
+[ Upstream commit 8a4a0b2a3eaf75ca8854f856ef29690c12b2f531 ]
+
+If we disable quotas while we have a relocation of a metadata block group
+that has extents belonging to the quota root, we can cause the relocation
+to fail with -ENOENT. This is because relocation builds backref nodes for
+extents of the quota root and later needs to walk the backrefs and access
+the quota root - however if in between a task disables quotas, it results
+in deleting the quota root from the root tree (with btrfs_del_root(),
+called from btrfs_quota_disable().
+
+This can be sporadically triggered by test case btrfs/255 from fstests:
+
+ $ ./check btrfs/255
+ FSTYP -- btrfs
+ PLATFORM -- Linux/x86_64 debian0 6.4.0-rc6-btrfs-next-134+ #1 SMP PREEMPT_DYNAMIC Thu Jun 15 11:59:28 WEST 2023
+ MKFS_OPTIONS -- /dev/sdc
+ MOUNT_OPTIONS -- /dev/sdc /home/fdmanana/btrfs-tests/scratch_1
+
+ btrfs/255 6s ... _check_dmesg: something found in dmesg (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.dmesg)
+ - output mismatch (see /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad)
+ --- tests/btrfs/255.out 2023-03-02 21:47:53.876609426 +0000
+ +++ /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad 2023-06-16 10:20:39.267563212 +0100
+ @@ -1,2 +1,4 @@
+ QA output created by 255
+ +ERROR: error during balancing '/home/fdmanana/btrfs-tests/scratch_1': No such file or directory
+ +There may be more info in syslog - try dmesg | tail
+ Silence is golden
+ ...
+ (Run 'diff -u /home/fdmanana/git/hub/xfstests/tests/btrfs/255.out /home/fdmanana/git/hub/xfstests/results//btrfs/255.out.bad' to see the entire diff)
+ Ran: btrfs/255
+ Failures: btrfs/255
+ Failed 1 of 1 tests
+
+To fix this make the quota disable operation take the cleaner mutex, as
+relocation of a block group also takes this mutex. This is also what we
+do when deleting a subvolume/snapshot, we take the cleaner mutex in the
+cleaner kthread (at cleaner_kthread()) and then we call btrfs_del_root()
+at btrfs_drop_snapshot() while under the protection of the cleaner mutex.
+
+Fixes: bed92eae26cc ("Btrfs: qgroup implementation and prototypes")
+CC: stable@vger.kernel.org # 5.4+
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/btrfs/qgroup.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
+index d408d1dfde7c8..d46a070275ff5 100644
+--- a/fs/btrfs/qgroup.c
++++ b/fs/btrfs/qgroup.c
+@@ -1201,12 +1201,23 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+ int ret = 0;
+
+ /*
+- * We need to have subvol_sem write locked, to prevent races between
+- * concurrent tasks trying to disable quotas, because we will unlock
+- * and relock qgroup_ioctl_lock across BTRFS_FS_QUOTA_ENABLED changes.
++ * We need to have subvol_sem write locked to prevent races with
++ * snapshot creation.
+ */
+ lockdep_assert_held_write(&fs_info->subvol_sem);
+
++ /*
++ * Lock the cleaner mutex to prevent races with concurrent relocation,
++ * because relocation may be building backrefs for blocks of the quota
++ * root while we are deleting the root. This is like dropping fs roots
++ * of deleted snapshots/subvolumes, we need the same protection.
++ *
++ * This also prevents races between concurrent tasks trying to disable
++ * quotas, because we will unlock and relock qgroup_ioctl_lock across
++ * BTRFS_FS_QUOTA_ENABLED changes.
++ */
++ mutex_lock(&fs_info->cleaner_mutex);
++
+ mutex_lock(&fs_info->qgroup_ioctl_lock);
+ if (!fs_info->quota_root)
+ goto out;
+@@ -1287,6 +1298,7 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
+ btrfs_end_transaction(trans);
+ else if (trans)
+ ret = btrfs_end_transaction(trans);
++ mutex_unlock(&fs_info->cleaner_mutex);
+
+ return ret;
+ }
+--
+2.39.2
+
--- /dev/null
+From 4f410636bcafe6febb64257cd99651160e10504a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Jul 2023 15:29:01 +0000
+Subject: cifs: if deferred close is disabled then close files immediately
+
+From: Bharath SM <bharathsm@microsoft.com>
+
+[ Upstream commit df9d70c18616760c6504b97fec66b6379c172dbb ]
+
+If defer close timeout value is set to 0, then there is no
+need to include files in the deferred close list and utilize
+the delayed worker for closing. Instead, we can close them
+immediately.
+
+Signed-off-by: Bharath SM <bharathsm@microsoft.com>
+Reviewed-by: Shyam Prasad N <sprasad@microsoft.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/file.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/cifs/file.c b/fs/cifs/file.c
+index 4e4f73a90574b..e65fbae9e804b 100644
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -880,8 +880,8 @@ int cifs_close(struct inode *inode, struct file *file)
+ cfile = file->private_data;
+ file->private_data = NULL;
+ dclose = kmalloc(sizeof(struct cifs_deferred_close), GFP_KERNEL);
+- if ((cinode->oplock == CIFS_CACHE_RHW_FLG) &&
+- cinode->lease_granted &&
++ if ((cifs_sb->ctx->closetimeo && cinode->oplock == CIFS_CACHE_RHW_FLG)
++ && cinode->lease_granted &&
+ !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags) &&
+ dclose) {
+ if (test_and_clear_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) {
+--
+2.39.2
+
--- /dev/null
+From 3113e3cbb7f24f98ee9c32672187cddbc3f24d1b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 13 Aug 2022 17:22:11 -0500
+Subject: cifs: missing directory in MAINTAINERS file
+
+From: Steve French <stfrench@microsoft.com>
+
+[ Upstream commit 5dd8ce24667a70bb9f7808f5eec0354bd37290c6 ]
+
+The include/uapi/linux/cifs directory (not just fs/cifs and
+fs/smbfs_common) should be included in cifs entry in the
+MAINTAINERS file.
+
+Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: df9d70c18616 ("cifs: if deferred close is disabled then close files immediately")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ MAINTAINERS | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 2bf1ad0fb2a6f..e6b53e76651be 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4666,6 +4666,7 @@ T: git git://git.samba.org/sfrench/cifs-2.6.git
+ F: Documentation/admin-guide/cifs/
+ F: fs/cifs/
+ F: fs/smbfs_common/
++F: include/uapi/linux/cifs
+
+ COMPACTPCI HOTPLUG CORE
+ M: Scott Murray <scott@spiteful.org>
+--
+2.39.2
+
--- /dev/null
+From 6e997dc19578b44af9b5e3aea9152e7f5812e359 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Oct 2022 18:41:20 -0300
+Subject: cifs: use fs_context for automounts
+
+From: Paulo Alcantara <pc@cjr.nz>
+
+[ Upstream commit 9fd29a5bae6e8f94b410374099a6fddb253d2d5f ]
+
+Use filesystem context support to handle dfs links.
+
+Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Stable-dep-of: df9d70c18616 ("cifs: if deferred close is disabled then close files immediately")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/cifs/cifs_dfs_ref.c | 100 +++++++++++++++++------------------------
+ 1 file changed, 40 insertions(+), 60 deletions(-)
+
+diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c
+index b0864da9ef434..020e71fe1454e 100644
+--- a/fs/cifs/cifs_dfs_ref.c
++++ b/fs/cifs/cifs_dfs_ref.c
+@@ -258,61 +258,23 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
+ goto compose_mount_options_out;
+ }
+
+-/**
+- * cifs_dfs_do_mount - mounts specified path using DFS full path
+- *
+- * Always pass down @fullpath to smb3_do_mount() so we can use the root server
+- * to perform failover in case we failed to connect to the first target in the
+- * referral.
+- *
+- * @mntpt: directory entry for the path we are trying to automount
+- * @cifs_sb: parent/root superblock
+- * @fullpath: full path in UNC format
+- */
+-static struct vfsmount *cifs_dfs_do_mount(struct dentry *mntpt,
+- struct cifs_sb_info *cifs_sb,
+- const char *fullpath)
+-{
+- struct vfsmount *mnt;
+- char *mountdata;
+- char *devname;
+-
+- devname = kstrdup(fullpath, GFP_KERNEL);
+- if (!devname)
+- return ERR_PTR(-ENOMEM);
+-
+- convert_delimiter(devname, '/');
+-
+- /* TODO: change to call fs_context_for_mount(), fill in context directly, call fc_mount */
+-
+- /* See afs_mntpt_do_automount in fs/afs/mntpt.c for an example */
+-
+- /* strip first '\' from fullpath */
+- mountdata = cifs_compose_mount_options(cifs_sb->ctx->mount_options,
+- fullpath + 1, NULL, NULL);
+- if (IS_ERR(mountdata)) {
+- kfree(devname);
+- return (struct vfsmount *)mountdata;
+- }
+-
+- mnt = vfs_submount(mntpt, &cifs_fs_type, devname, mountdata);
+- kfree(mountdata);
+- kfree(devname);
+- return mnt;
+-}
+-
+ /*
+ * Create a vfsmount that we can automount
+ */
+-static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
++static struct vfsmount *cifs_dfs_do_automount(struct path *path)
+ {
++ int rc;
++ struct dentry *mntpt = path->dentry;
++ struct fs_context *fc;
+ struct cifs_sb_info *cifs_sb;
+- void *page;
++ void *page = NULL;
++ struct smb3_fs_context *ctx, *cur_ctx;
++ struct smb3_fs_context tmp;
+ char *full_path;
+ struct vfsmount *mnt;
+
+- cifs_dbg(FYI, "in %s\n", __func__);
+- BUG_ON(IS_ROOT(mntpt));
++ if (IS_ROOT(mntpt))
++ return ERR_PTR(-ESTALE);
+
+ /*
+ * The MSDFS spec states that paths in DFS referral requests and
+@@ -321,29 +283,47 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
+ * gives us the latter, so we must adjust the result.
+ */
+ cifs_sb = CIFS_SB(mntpt->d_sb);
+- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS) {
+- mnt = ERR_PTR(-EREMOTE);
+- goto cdda_exit;
+- }
++ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_DFS)
++ return ERR_PTR(-EREMOTE);
++
++ cur_ctx = cifs_sb->ctx;
++
++ fc = fs_context_for_submount(path->mnt->mnt_sb->s_type, mntpt);
++ if (IS_ERR(fc))
++ return ERR_CAST(fc);
++
++ ctx = smb3_fc2context(fc);
+
+ page = alloc_dentry_path();
+ /* always use tree name prefix */
+ full_path = build_path_from_dentry_optional_prefix(mntpt, page, true);
+ if (IS_ERR(full_path)) {
+ mnt = ERR_CAST(full_path);
+- goto free_full_path;
++ goto out;
+ }
+
+- convert_delimiter(full_path, '\\');
++ convert_delimiter(full_path, '/');
+ cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
+
+- mnt = cifs_dfs_do_mount(mntpt, cifs_sb, full_path);
+- cifs_dbg(FYI, "%s: cifs_dfs_do_mount:%s , mnt:%p\n", __func__, full_path + 1, mnt);
++ tmp = *cur_ctx;
++ tmp.source = full_path;
++ tmp.UNC = tmp.prepath = NULL;
++
++ rc = smb3_fs_context_dup(ctx, &tmp);
++ if (rc) {
++ mnt = ERR_PTR(rc);
++ goto out;
++ }
++
++ rc = smb3_parse_devname(full_path, ctx);
++ if (!rc)
++ mnt = fc_mount(fc);
++ else
++ mnt = ERR_PTR(rc);
+
+-free_full_path:
++out:
++ put_fs_context(fc);
+ free_dentry_path(page);
+-cdda_exit:
+- cifs_dbg(FYI, "leaving %s\n" , __func__);
+ return mnt;
+ }
+
+@@ -354,9 +334,9 @@ struct vfsmount *cifs_dfs_d_automount(struct path *path)
+ {
+ struct vfsmount *newmnt;
+
+- cifs_dbg(FYI, "in %s\n", __func__);
++ cifs_dbg(FYI, "%s: %pd\n", __func__, path->dentry);
+
+- newmnt = cifs_dfs_do_automount(path->dentry);
++ newmnt = cifs_dfs_do_automount(path);
+ if (IS_ERR(newmnt)) {
+ cifs_dbg(FYI, "leaving %s [automount failed]\n" , __func__);
+ return newmnt;
+--
+2.39.2
+
--- /dev/null
+From cd247b5ace431ae27ed84f2a1571d879c2ba1164 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Apr 2022 16:06:32 -0400
+Subject: dlm: cleanup plock_op vs plock_xop
+
+From: Alexander Aring <aahringo@redhat.com>
+
+[ Upstream commit bcbb4ba6c9ba81e6975b642a2cade68044cd8a66 ]
+
+Lately the different casting between plock_op and plock_xop and list
+holders which was involved showed some issues which were hard to see.
+This patch removes the "plock_xop" structure and introduces a
+"struct plock_async_data". This structure will be set in "struct plock_op"
+in case of asynchronous lock handling as the original "plock_xop" was
+made for. There is no need anymore to cast pointers around for
+additional fields in case of asynchronous lock handling. As disadvantage
+another allocation was introduces but only needed in the asynchronous
+case which is currently only used in combination with nfs lockd.
+
+Signed-off-by: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: David Teigland <teigland@redhat.com>
+Stable-dep-of: 59e45c758ca1 ("fs: dlm: interrupt posix locks only when process is killed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/dlm/plock.c | 77 ++++++++++++++++++++++++++++++--------------------
+ 1 file changed, 46 insertions(+), 31 deletions(-)
+
+diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
+index edce0b25cd90e..e70e23eca03ec 100644
+--- a/fs/dlm/plock.c
++++ b/fs/dlm/plock.c
+@@ -19,20 +19,20 @@ static struct list_head recv_list;
+ static wait_queue_head_t send_wq;
+ static wait_queue_head_t recv_wq;
+
+-struct plock_op {
+- struct list_head list;
+- int done;
+- struct dlm_plock_info info;
+- int (*callback)(struct file_lock *fl, int result);
+-};
+-
+-struct plock_xop {
+- struct plock_op xop;
++struct plock_async_data {
+ void *fl;
+ void *file;
+ struct file_lock flc;
++ int (*callback)(struct file_lock *fl, int result);
+ };
+
++struct plock_op {
++ struct list_head list;
++ int done;
++ struct dlm_plock_info info;
++ /* if set indicates async handling */
++ struct plock_async_data *data;
++};
+
+ static inline void set_version(struct dlm_plock_info *info)
+ {
+@@ -58,6 +58,12 @@ static int check_version(struct dlm_plock_info *info)
+ return 0;
+ }
+
++static void dlm_release_plock_op(struct plock_op *op)
++{
++ kfree(op->data);
++ kfree(op);
++}
++
+ static void send_op(struct plock_op *op)
+ {
+ set_version(&op->info);
+@@ -101,22 +107,21 @@ static void do_unlock_close(struct dlm_ls *ls, u64 number,
+ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+ int cmd, struct file_lock *fl)
+ {
++ struct plock_async_data *op_data;
+ struct dlm_ls *ls;
+ struct plock_op *op;
+- struct plock_xop *xop;
+ int rv;
+
+ ls = dlm_find_lockspace_local(lockspace);
+ if (!ls)
+ return -EINVAL;
+
+- xop = kzalloc(sizeof(*xop), GFP_NOFS);
+- if (!xop) {
++ op = kzalloc(sizeof(*op), GFP_NOFS);
++ if (!op) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+- op = &xop->xop;
+ op->info.optype = DLM_PLOCK_OP_LOCK;
+ op->info.pid = fl->fl_pid;
+ op->info.ex = (fl->fl_type == F_WRLCK);
+@@ -125,22 +130,32 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+ op->info.number = number;
+ op->info.start = fl->fl_start;
+ op->info.end = fl->fl_end;
++ /* async handling */
+ if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
++ op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
++ if (!op_data) {
++ dlm_release_plock_op(op);
++ rv = -ENOMEM;
++ goto out;
++ }
++
+ /* fl_owner is lockd which doesn't distinguish
+ processes on the nfs client */
+ op->info.owner = (__u64) fl->fl_pid;
+- op->callback = fl->fl_lmops->lm_grant;
+- locks_init_lock(&xop->flc);
+- locks_copy_lock(&xop->flc, fl);
+- xop->fl = fl;
+- xop->file = file;
++ op_data->callback = fl->fl_lmops->lm_grant;
++ locks_init_lock(&op_data->flc);
++ locks_copy_lock(&op_data->flc, fl);
++ op_data->fl = fl;
++ op_data->file = file;
++
++ op->data = op_data;
+ } else {
+ op->info.owner = (__u64)(long) fl->fl_owner;
+ }
+
+ send_op(op);
+
+- if (!op->callback) {
++ if (!op->data) {
+ rv = wait_event_interruptible(recv_wq, (op->done != 0));
+ if (rv == -ERESTARTSYS) {
+ log_debug(ls, "dlm_posix_lock: wait killed %llx",
+@@ -148,7 +163,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+ spin_lock(&ops_lock);
+ list_del(&op->list);
+ spin_unlock(&ops_lock);
+- kfree(xop);
++ dlm_release_plock_op(op);
+ do_unlock_close(ls, number, file, fl);
+ goto out;
+ }
+@@ -173,7 +188,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+ (unsigned long long)number);
+ }
+
+- kfree(xop);
++ dlm_release_plock_op(op);
+ out:
+ dlm_put_lockspace(ls);
+ return rv;
+@@ -183,11 +198,11 @@ EXPORT_SYMBOL_GPL(dlm_posix_lock);
+ /* Returns failure iff a successful lock operation should be canceled */
+ static int dlm_plock_callback(struct plock_op *op)
+ {
++ struct plock_async_data *op_data = op->data;
+ struct file *file;
+ struct file_lock *fl;
+ struct file_lock *flc;
+ int (*notify)(struct file_lock *fl, int result) = NULL;
+- struct plock_xop *xop = (struct plock_xop *)op;
+ int rv = 0;
+
+ spin_lock(&ops_lock);
+@@ -199,10 +214,10 @@ static int dlm_plock_callback(struct plock_op *op)
+ spin_unlock(&ops_lock);
+
+ /* check if the following 2 are still valid or make a copy */
+- file = xop->file;
+- flc = &xop->flc;
+- fl = xop->fl;
+- notify = op->callback;
++ file = op_data->file;
++ flc = &op_data->flc;
++ fl = op_data->fl;
++ notify = op_data->callback;
+
+ if (op->info.rv) {
+ notify(fl, op->info.rv);
+@@ -233,7 +248,7 @@ static int dlm_plock_callback(struct plock_op *op)
+ }
+
+ out:
+- kfree(xop);
++ dlm_release_plock_op(op);
+ return rv;
+ }
+
+@@ -303,7 +318,7 @@ int dlm_posix_unlock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+ rv = 0;
+
+ out_free:
+- kfree(op);
++ dlm_release_plock_op(op);
+ out:
+ dlm_put_lockspace(ls);
+ fl->fl_flags = fl_flags;
+@@ -371,7 +386,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+ rv = 0;
+ }
+
+- kfree(op);
++ dlm_release_plock_op(op);
+ out:
+ dlm_put_lockspace(ls);
+ return rv;
+@@ -407,7 +422,7 @@ static ssize_t dev_read(struct file *file, char __user *u, size_t count,
+ (the process did not make an unlock call). */
+
+ if (op->info.flags & DLM_PLOCK_FL_CLOSE)
+- kfree(op);
++ dlm_release_plock_op(op);
+
+ if (copy_to_user(u, &info, sizeof(info)))
+ return -EFAULT;
+@@ -439,7 +454,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
+ op->info.owner == info.owner) {
+ list_del_init(&op->list);
+ memcpy(&op->info, &info, sizeof(info));
+- if (op->callback)
++ if (op->data)
+ do_callback = 1;
+ else
+ op->done = 1;
+--
+2.39.2
+
--- /dev/null
+From 9171eb97c29452e232caa4b44526dffa6e515757 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 4 Apr 2022 16:06:33 -0400
+Subject: dlm: rearrange async condition return
+
+From: Alexander Aring <aahringo@redhat.com>
+
+[ Upstream commit a800ba77fd285c6391a82819867ac64e9ab3af46 ]
+
+This patch moves the return of FILE_LOCK_DEFERRED a little bit earlier
+than checking afterwards again if the request was an asynchronous request.
+
+Signed-off-by: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: David Teigland <teigland@redhat.com>
+Stable-dep-of: 59e45c758ca1 ("fs: dlm: interrupt posix locks only when process is killed")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/dlm/plock.c | 27 +++++++++++++--------------
+ 1 file changed, 13 insertions(+), 14 deletions(-)
+
+diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
+index e70e23eca03ec..01fb7d8c0bca5 100644
+--- a/fs/dlm/plock.c
++++ b/fs/dlm/plock.c
+@@ -149,26 +149,25 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+ op_data->file = file;
+
+ op->data = op_data;
++
++ send_op(op);
++ rv = FILE_LOCK_DEFERRED;
++ goto out;
+ } else {
+ op->info.owner = (__u64)(long) fl->fl_owner;
+ }
+
+ send_op(op);
+
+- if (!op->data) {
+- rv = wait_event_interruptible(recv_wq, (op->done != 0));
+- if (rv == -ERESTARTSYS) {
+- log_debug(ls, "dlm_posix_lock: wait killed %llx",
+- (unsigned long long)number);
+- spin_lock(&ops_lock);
+- list_del(&op->list);
+- spin_unlock(&ops_lock);
+- dlm_release_plock_op(op);
+- do_unlock_close(ls, number, file, fl);
+- goto out;
+- }
+- } else {
+- rv = FILE_LOCK_DEFERRED;
++ rv = wait_event_interruptible(recv_wq, (op->done != 0));
++ if (rv == -ERESTARTSYS) {
++ log_debug(ls, "%s: wait killed %llx", __func__,
++ (unsigned long long)number);
++ spin_lock(&ops_lock);
++ list_del(&op->list);
++ spin_unlock(&ops_lock);
++ dlm_release_plock_op(op);
++ do_unlock_close(ls, number, file, fl);
+ goto out;
+ }
+
+--
+2.39.2
+
--- /dev/null
+From cb0e3d168f003d982d765720240b875c61a43964 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 Nov 2021 10:34:57 +0800
+Subject: drm/amdgpu: fix vkms crtc settings
+
+From: Flora Cui <flora.cui@amd.com>
+
+[ Upstream commit deefd07eedb7baa25956c8365373e6a58c81565a ]
+
+otherwise adev->mode_info.crtcs[] is NULL
+
+Signed-off-by: Flora Cui <flora.cui@amd.com>
+Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Stable-dep-of: b42ae87a7b38 ("drm/amdgpu/vkms: relax timer deactivation by hrtimer_try_to_cancel")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 42 ++++++++++++++++--------
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h | 5 ++-
+ 2 files changed, 30 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+index 7d58bf410be05..24251cdf95073 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+@@ -16,6 +16,8 @@
+ #include "ivsrcid/ivsrcid_vislands30.h"
+ #include "amdgpu_vkms.h"
+ #include "amdgpu_display.h"
++#include "atom.h"
++#include "amdgpu_irq.h"
+
+ /**
+ * DOC: amdgpu_vkms
+@@ -41,14 +43,13 @@ static const u32 amdgpu_vkms_formats[] = {
+
+ static enum hrtimer_restart amdgpu_vkms_vblank_simulate(struct hrtimer *timer)
+ {
+- struct amdgpu_vkms_output *output = container_of(timer,
+- struct amdgpu_vkms_output,
+- vblank_hrtimer);
+- struct drm_crtc *crtc = &output->crtc;
++ struct amdgpu_crtc *amdgpu_crtc = container_of(timer, struct amdgpu_crtc, vblank_timer);
++ struct drm_crtc *crtc = &amdgpu_crtc->base;
++ struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);
+ u64 ret_overrun;
+ bool ret;
+
+- ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
++ ret_overrun = hrtimer_forward_now(&amdgpu_crtc->vblank_timer,
+ output->period_ns);
+ WARN_ON(ret_overrun != 1);
+
+@@ -65,22 +66,21 @@ static int amdgpu_vkms_enable_vblank(struct drm_crtc *crtc)
+ unsigned int pipe = drm_crtc_index(crtc);
+ struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
+ struct amdgpu_vkms_output *out = drm_crtc_to_amdgpu_vkms_output(crtc);
++ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ drm_calc_timestamping_constants(crtc, &crtc->mode);
+
+- hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+- out->vblank_hrtimer.function = &amdgpu_vkms_vblank_simulate;
+ out->period_ns = ktime_set(0, vblank->framedur_ns);
+- hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL);
++ hrtimer_start(&amdgpu_crtc->vblank_timer, out->period_ns, HRTIMER_MODE_REL);
+
+ return 0;
+ }
+
+ static void amdgpu_vkms_disable_vblank(struct drm_crtc *crtc)
+ {
+- struct amdgpu_vkms_output *out = drm_crtc_to_amdgpu_vkms_output(crtc);
++ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+- hrtimer_cancel(&out->vblank_hrtimer);
++ hrtimer_cancel(&amdgpu_crtc->vblank_timer);
+ }
+
+ static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
+@@ -92,13 +92,14 @@ static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
+ unsigned int pipe = crtc->index;
+ struct amdgpu_vkms_output *output = drm_crtc_to_amdgpu_vkms_output(crtc);
+ struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
++ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+ if (!READ_ONCE(vblank->enabled)) {
+ *vblank_time = ktime_get();
+ return true;
+ }
+
+- *vblank_time = READ_ONCE(output->vblank_hrtimer.node.expires);
++ *vblank_time = READ_ONCE(amdgpu_crtc->vblank_timer.node.expires);
+
+ if (WARN_ON(*vblank_time == vblank->time))
+ return true;
+@@ -166,6 +167,8 @@ static const struct drm_crtc_helper_funcs amdgpu_vkms_crtc_helper_funcs = {
+ static int amdgpu_vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+ struct drm_plane *primary, struct drm_plane *cursor)
+ {
++ struct amdgpu_device *adev = drm_to_adev(dev);
++ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+ int ret;
+
+ ret = drm_crtc_init_with_planes(dev, crtc, primary, cursor,
+@@ -177,6 +180,17 @@ static int amdgpu_vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+
+ drm_crtc_helper_add(crtc, &amdgpu_vkms_crtc_helper_funcs);
+
++ amdgpu_crtc->crtc_id = drm_crtc_index(crtc);
++ adev->mode_info.crtcs[drm_crtc_index(crtc)] = amdgpu_crtc;
++
++ amdgpu_crtc->pll_id = ATOM_PPLL_INVALID;
++ amdgpu_crtc->encoder = NULL;
++ amdgpu_crtc->connector = NULL;
++ amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE;
++
++ hrtimer_init(&amdgpu_crtc->vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
++ amdgpu_crtc->vblank_timer.function = &amdgpu_vkms_vblank_simulate;
++
+ return ret;
+ }
+
+@@ -402,7 +416,7 @@ int amdgpu_vkms_output_init(struct drm_device *dev,
+ {
+ struct drm_connector *connector = &output->connector;
+ struct drm_encoder *encoder = &output->encoder;
+- struct drm_crtc *crtc = &output->crtc;
++ struct drm_crtc *crtc = &output->crtc.base;
+ struct drm_plane *primary, *cursor = NULL;
+ int ret;
+
+@@ -505,8 +519,8 @@ static int amdgpu_vkms_sw_fini(void *handle)
+ int i = 0;
+
+ for (i = 0; i < adev->mode_info.num_crtc; i++)
+- if (adev->amdgpu_vkms_output[i].vblank_hrtimer.function)
+- hrtimer_cancel(&adev->amdgpu_vkms_output[i].vblank_hrtimer);
++ if (adev->mode_info.crtcs[i])
++ hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer);
+
+ kfree(adev->mode_info.bios_hardcoded_edid);
+ kfree(adev->amdgpu_vkms_output);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h
+index 97f1b79c0724e..4f8722ff37c25 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.h
+@@ -10,15 +10,14 @@
+ #define YRES_MAX 16384
+
+ #define drm_crtc_to_amdgpu_vkms_output(target) \
+- container_of(target, struct amdgpu_vkms_output, crtc)
++ container_of(target, struct amdgpu_vkms_output, crtc.base)
+
+ extern const struct amdgpu_ip_block_version amdgpu_vkms_ip_block;
+
+ struct amdgpu_vkms_output {
+- struct drm_crtc crtc;
++ struct amdgpu_crtc crtc;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+- struct hrtimer vblank_hrtimer;
+ ktime_t period_ns;
+ struct drm_pending_vblank_event *event;
+ };
+--
+2.39.2
+
--- /dev/null
+From 2291d9f1bcb49b557c2877157eaa2d6bc91da1d3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Jul 2023 15:57:21 +0800
+Subject: drm/amdgpu/vkms: relax timer deactivation by hrtimer_try_to_cancel
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Guchun Chen <guchun.chen@amd.com>
+
+[ Upstream commit b42ae87a7b3878afaf4c3852ca66c025a5b996e0 ]
+
+In below thousands of screen rotation loop tests with virtual display
+enabled, a CPU hard lockup issue may happen, leading system to unresponsive
+and crash.
+
+do {
+ xrandr --output Virtual --rotate inverted
+ xrandr --output Virtual --rotate right
+ xrandr --output Virtual --rotate left
+ xrandr --output Virtual --rotate normal
+} while (1);
+
+NMI watchdog: Watchdog detected hard LOCKUP on cpu 1
+
+? hrtimer_run_softirq+0x140/0x140
+? store_vblank+0xe0/0xe0 [drm]
+hrtimer_cancel+0x15/0x30
+amdgpu_vkms_disable_vblank+0x15/0x30 [amdgpu]
+drm_vblank_disable_and_save+0x185/0x1f0 [drm]
+drm_crtc_vblank_off+0x159/0x4c0 [drm]
+? record_print_text.cold+0x11/0x11
+? wait_for_completion_timeout+0x232/0x280
+? drm_crtc_wait_one_vblank+0x40/0x40 [drm]
+? bit_wait_io_timeout+0xe0/0xe0
+? wait_for_completion_interruptible+0x1d7/0x320
+? mutex_unlock+0x81/0xd0
+amdgpu_vkms_crtc_atomic_disable
+
+It's caused by a stuck in lock dependency in such scenario on different
+CPUs.
+
+CPU1 CPU2
+drm_crtc_vblank_off hrtimer_interrupt
+ grab event_lock (irq disabled) __hrtimer_run_queues
+ grab vbl_lock/vblank_time_block amdgpu_vkms_vblank_simulate
+ amdgpu_vkms_disable_vblank drm_handle_vblank
+ hrtimer_cancel grab dev->event_lock
+
+So CPU1 stucks in hrtimer_cancel as timer callback is running endless on
+current clock base, as that timer queue on CPU2 has no chance to finish it
+because of failing to hold the lock. So NMI watchdog will throw the errors
+after its threshold, and all later CPUs are impacted/blocked.
+
+So use hrtimer_try_to_cancel to fix this, as disable_vblank callback
+does not need to wait the handler to finish. And also it's not necessary
+to check the return value of hrtimer_try_to_cancel, because even if it's
+-1 which means current timer callback is running, it will be reprogrammed
+in hrtimer_start with calling enable_vblank to make it works.
+
+v2: only re-arm timer when vblank is enabled (Christian) and add a Fixes
+tag as well
+
+v3: drop warn printing (Christian)
+
+v4: drop superfluous check of blank->enabled in timer function, as it's
+guaranteed in drm_handle_vblank (Christian)
+
+Fixes: 84ec374bd580 ("drm/amdgpu: create amdgpu_vkms (v4)")
+Cc: stable@vger.kernel.org
+Suggested-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Guchun Chen <guchun.chen@amd.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+index 24251cdf95073..4e8274de8fc0c 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
+@@ -54,8 +54,9 @@ static enum hrtimer_restart amdgpu_vkms_vblank_simulate(struct hrtimer *timer)
+ WARN_ON(ret_overrun != 1);
+
+ ret = drm_crtc_handle_vblank(crtc);
++ /* Don't queue timer again when vblank is disabled. */
+ if (!ret)
+- DRM_ERROR("amdgpu_vkms failure on handling vblank");
++ return HRTIMER_NORESTART;
+
+ return HRTIMER_RESTART;
+ }
+@@ -80,7 +81,7 @@ static void amdgpu_vkms_disable_vblank(struct drm_crtc *crtc)
+ {
+ struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+- hrtimer_cancel(&amdgpu_crtc->vblank_timer);
++ hrtimer_try_to_cancel(&amdgpu_crtc->vblank_timer);
+ }
+
+ static bool amdgpu_vkms_get_vblank_timestamp(struct drm_crtc *crtc,
+--
+2.39.2
+
--- /dev/null
+From cb49f8d791c2603eb5da6e5bbdbf36dcc53d37d3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 Jun 2023 11:14:49 +0200
+Subject: drm/ttm: Don't leak a resource on eviction error
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+
+[ Upstream commit e8188c461ee015ba0b9ab2fc82dbd5ebca5a5532 ]
+
+On eviction errors other than -EMULTIHOP we were leaking a resource.
+Fix.
+
+v2:
+- Avoid yet another goto (Andi Shyti)
+
+Fixes: 403797925768 ("drm/ttm: Fix multihop assert on eviction.")
+Cc: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
+Cc: Christian König <christian.koenig@amd.com>
+Cc: Christian Koenig <christian.koenig@amd.com>
+Cc: Huang Rui <ray.huang@amd.com>
+Cc: dri-devel@lists.freedesktop.org
+Cc: <stable@vger.kernel.org> # v5.15+
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Reviewed-by: Nirmoy Das <nirmoy.das@intel.com> #v1
+Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20230626091450.14757-4-thomas.hellstrom@linux.intel.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index cf390ab636978..6080f4b5c450c 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -552,18 +552,18 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
+ goto out;
+ }
+
+-bounce:
+- ret = ttm_bo_handle_move_mem(bo, evict_mem, true, ctx, &hop);
+- if (ret == -EMULTIHOP) {
++ do {
++ ret = ttm_bo_handle_move_mem(bo, evict_mem, true, ctx, &hop);
++ if (ret != -EMULTIHOP)
++ break;
++
+ ret = ttm_bo_bounce_temp_buffer(bo, &evict_mem, ctx, &hop);
+- if (ret) {
+- if (ret != -ERESTARTSYS && ret != -EINTR)
+- pr_err("Buffer eviction failed\n");
+- ttm_resource_free(bo, &evict_mem);
+- goto out;
+- }
+- /* try and move to final place now. */
+- goto bounce;
++ } while (!ret);
++
++ if (ret) {
++ ttm_resource_free(bo, &evict_mem);
++ if (ret != -ERESTARTSYS && ret != -EINTR)
++ pr_err("Buffer eviction failed\n");
+ }
+ out:
+ return ret;
+--
+2.39.2
+
--- /dev/null
+From cfdc82035adbf6df02439a902bf16a5f19898007 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 7 Mar 2023 15:46:19 +0100
+Subject: drm/ttm: Don't print error message if eviction was interrupted
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+
+[ Upstream commit 8ab3b0663e279ab550bc2c0b5d602960e8b94e02 ]
+
+Avoid printing an error message if eviction was interrupted by,
+for example, the user pressing CTRL-C. That may happen if eviction
+is waiting for something, like for example a free batch-buffer.
+
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Reviewed-by: Christian König <christian.koenig@amd.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20230307144621.10748-6-thomas.hellstrom@linux.intel.com
+Stable-dep-of: e8188c461ee0 ("drm/ttm: Don't leak a resource on eviction error")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index d5a2b69489e7f..cf390ab636978 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -557,7 +557,8 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo,
+ if (ret == -EMULTIHOP) {
+ ret = ttm_bo_bounce_temp_buffer(bo, &evict_mem, ctx, &hop);
+ if (ret) {
+- pr_err("Buffer eviction failed\n");
++ if (ret != -ERESTARTSYS && ret != -EINTR)
++ pr_err("Buffer eviction failed\n");
+ ttm_resource_free(bo, &evict_mem);
+ goto out;
+ }
+--
+2.39.2
+
--- /dev/null
+From f050822f2bc5bdcf55c3259f2428a89feeba62d4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 7 Jul 2023 11:25:00 +0200
+Subject: drm/ttm: never consider pinned BOs for eviction&swap
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Christian König <christian.koenig@amd.com>
+
+[ Upstream commit a2848d08742c8e8494675892c02c0d22acbe3cf8 ]
+
+There is a small window where we have already incremented the pin count
+but not yet moved the bo from the lru to the pinned list.
+
+Signed-off-by: Christian König <christian.koenig@amd.com>
+Reported-by: Pelloux-Prayer, Pierre-Eric <Pierre-eric.Pelloux-prayer@amd.com>
+Tested-by: Pelloux-Prayer, Pierre-Eric <Pierre-eric.Pelloux-prayer@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+Cc: stable@vger.kernel.org
+Link: https://patchwork.freedesktop.org/patch/msgid/20230707120826.3701-1-christian.koenig@amd.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/ttm/ttm_bo.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
+index 6080f4b5c450c..4d0ef5ab25319 100644
+--- a/drivers/gpu/drm/ttm/ttm_bo.c
++++ b/drivers/gpu/drm/ttm/ttm_bo.c
+@@ -604,6 +604,12 @@ static bool ttm_bo_evict_swapout_allowable(struct ttm_buffer_object *bo,
+ {
+ bool ret = false;
+
++ if (bo->pin_count) {
++ *locked = false;
++ *busy = false;
++ return false;
++ }
++
+ if (bo->base.resv == ctx->resv) {
+ dma_resv_assert_held(bo->base.resv);
+ if (ctx->allow_res_evict)
+--
+2.39.2
+
--- /dev/null
+From 72ce2ba1a355dc0d473cf395f58a8b1d94e376b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 19 May 2023 11:21:26 -0400
+Subject: fs: dlm: interrupt posix locks only when process is killed
+
+From: Alexander Aring <aahringo@redhat.com>
+
+[ Upstream commit 59e45c758ca1b9893ac923dd63536da946ac333b ]
+
+If a posix lock request is waiting for a result from user space
+(dlm_controld), do not let it be interrupted unless the process
+is killed. This reverts commit a6b1533e9a57 ("dlm: make posix locks
+interruptible"). The problem with the interruptible change is
+that all locks were cleared on any signal interrupt. If a signal
+was received that did not terminate the process, the process
+could continue running after all its dlm posix locks had been
+cleared. A future patch will add cancelation to allow proper
+interruption.
+
+Cc: stable@vger.kernel.org
+Fixes: a6b1533e9a57 ("dlm: make posix locks interruptible")
+Signed-off-by: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: David Teigland <teigland@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/dlm/plock.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c
+index 01fb7d8c0bca5..f3482e936cc25 100644
+--- a/fs/dlm/plock.c
++++ b/fs/dlm/plock.c
+@@ -159,7 +159,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
+
+ send_op(op);
+
+- rv = wait_event_interruptible(recv_wq, (op->done != 0));
++ rv = wait_event_killable(recv_wq, (op->done != 0));
+ if (rv == -ERESTARTSYS) {
+ log_debug(ls, "%s: wait killed %llx", __func__,
+ (unsigned long long)number);
+--
+2.39.2
+
--- /dev/null
+From 4b97e0208a504563b54b58de395f48e95caf4f3b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Jul 2023 13:41:01 +0200
+Subject: gpio: mvebu: fix irq domain leak
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[ Upstream commit 644ee70267a934be27370f9aa618b29af7290544 ]
+
+Uwe Kleine-König pointed out we still have one resource leak in the mvebu
+driver triggered on driver detach. Let's address it with a custom devm
+action.
+
+Fixes: 812d47889a8e ("gpio/mvebu: Use irq_domain_add_linear")
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-mvebu.c | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index 4d64b3358c50c..b965513f44fea 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -1112,6 +1112,13 @@ static int mvebu_gpio_probe_syscon(struct platform_device *pdev,
+ return 0;
+ }
+
++static void mvebu_gpio_remove_irq_domain(void *data)
++{
++ struct irq_domain *domain = data;
++
++ irq_domain_remove(domain);
++}
++
+ static int mvebu_gpio_probe(struct platform_device *pdev)
+ {
+ struct mvebu_gpio_chip *mvchip;
+@@ -1247,13 +1254,18 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+ return -ENODEV;
+ }
+
++ err = devm_add_action_or_reset(&pdev->dev, mvebu_gpio_remove_irq_domain,
++ mvchip->domain);
++ if (err)
++ return err;
++
+ err = irq_alloc_domain_generic_chips(
+ mvchip->domain, ngpios, 2, np->name, handle_level_irq,
+ IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
+ if (err) {
+ dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
+ mvchip->chip.label);
+- goto err_domain;
++ return err;
+ }
+
+ /*
+@@ -1293,10 +1305,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+ }
+
+ return 0;
+-
+-err_domain:
+- irq_domain_remove(mvchip->domain);
+- return err;
+ }
+
+ static struct platform_driver mvebu_gpio_driver = {
+--
+2.39.2
+
--- /dev/null
+From 4f63c883d0b08e81d08ca9e9f9473ad6abaac935 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 17 Jul 2023 16:27:43 +0200
+Subject: gpio: mvebu: Make use of devm_pwmchip_add
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 1945063eb59e64d2919cb14d54d081476d9e53bb ]
+
+This allows to get rid of a call to pwmchip_remove() in the error path. There
+is no .remove function for this driver, so this change fixes a resource leak
+when a gpio-mvebu device is unbound.
+
+Fixes: 757642f9a584 ("gpio: mvebu: Add limited PWM support")
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Andy Shevchenko <andy@kernel.org>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-mvebu.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index a245bfd5a6173..4d64b3358c50c 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -874,7 +874,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
+
+ spin_lock_init(&mvpwm->lock);
+
+- return pwmchip_add(&mvpwm->chip);
++ return devm_pwmchip_add(dev, &mvpwm->chip);
+ }
+
+ #ifdef CONFIG_DEBUG_FS
+@@ -1244,8 +1244,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+ if (!mvchip->domain) {
+ dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
+ mvchip->chip.label);
+- err = -ENODEV;
+- goto err_pwm;
++ return -ENODEV;
+ }
+
+ err = irq_alloc_domain_generic_chips(
+@@ -1297,9 +1296,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
+
+ err_domain:
+ irq_domain_remove(mvchip->domain);
+-err_pwm:
+- pwmchip_remove(&mvchip->mvpwm->chip);
+-
+ return err;
+ }
+
+--
+2.39.2
+
--- /dev/null
+From 5a7247b05210fcc9f1ecad601dcfcc57db3e0cf4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 10 Jul 2023 14:34:25 +0200
+Subject: gpio: tps68470: Make tps68470_gpio_output() always set the initial
+ value
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+[ Upstream commit 5a7adc6c1069ce31ef4f606ae9c05592c80a6ab5 ]
+
+Make tps68470_gpio_output() call tps68470_gpio_set() for output-only pins
+too, so that the initial value passed to gpiod_direction_output() is
+honored for these pins too.
+
+Fixes: 275b13a65547 ("gpio: Add support for TPS68470 GPIOs")
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
+Tested-by: Daniel Scally <dan.scally@ideasonboard.com>
+Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpio/gpio-tps68470.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpio/gpio-tps68470.c b/drivers/gpio/gpio-tps68470.c
+index 423b7bc30ae88..03a523a6d6fa4 100644
+--- a/drivers/gpio/gpio-tps68470.c
++++ b/drivers/gpio/gpio-tps68470.c
+@@ -91,13 +91,13 @@ static int tps68470_gpio_output(struct gpio_chip *gc, unsigned int offset,
+ struct tps68470_gpio_data *tps68470_gpio = gpiochip_get_data(gc);
+ struct regmap *regmap = tps68470_gpio->tps68470_regmap;
+
++ /* Set the initial value */
++ tps68470_gpio_set(gc, offset, value);
++
+ /* rest are always outputs */
+ if (offset >= TPS68470_N_REGULAR_GPIO)
+ return 0;
+
+- /* Set the initial value */
+- tps68470_gpio_set(gc, offset, value);
+-
+ return regmap_update_bits(regmap, TPS68470_GPIO_CTL_REG_A(offset),
+ TPS68470_GPIO_MODE_MASK,
+ TPS68470_GPIO_MODE_OUT_CMOS);
+--
+2.39.2
+
--- /dev/null
+From 09e26e1759387dfdab7326d4ba381b1f2dddf771 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Feb 2018 17:24:57 +0100
+Subject: i2c: Delete error messages for failed memory allocations
+
+From: Markus Elfring <elfring@users.sourceforge.net>
+
+[ Upstream commit 6b3b21a8542fd2fb6ffc61bc13b9419f0c58ebad ]
+
+These issues were detected by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-ibm_iic.c | 4 +---
+ drivers/i2c/busses/i2c-nomadik.c | 1 -
+ drivers/i2c/busses/i2c-sh7760.c | 1 -
+ drivers/i2c/busses/i2c-tiny-usb.c | 4 +---
+ 4 files changed, 2 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
+index 9f71daf6db64b..c073f5b8833a2 100644
+--- a/drivers/i2c/busses/i2c-ibm_iic.c
++++ b/drivers/i2c/busses/i2c-ibm_iic.c
+@@ -694,10 +694,8 @@ static int iic_probe(struct platform_device *ofdev)
+ int ret;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (!dev) {
+- dev_err(&ofdev->dev, "failed to allocate device data\n");
++ if (!dev)
+ return -ENOMEM;
+- }
+
+ platform_set_drvdata(ofdev, dev);
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index a2d12a5b1c34c..05eaae5aeb180 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -972,7 +972,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+- dev_err(&adev->dev, "cannot allocate memory\n");
+ ret = -ENOMEM;
+ goto err_no_mem;
+ }
+diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
+index 319d1fa617c88..a0ccc5d009874 100644
+--- a/drivers/i2c/busses/i2c-sh7760.c
++++ b/drivers/i2c/busses/i2c-sh7760.c
+@@ -445,7 +445,6 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
+
+ id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
+ if (!id) {
+- dev_err(&pdev->dev, "no mem for private data\n");
+ ret = -ENOMEM;
+ goto out0;
+ }
+diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
+index 7279ca0eaa2d0..d1fa9ff5aeab4 100644
+--- a/drivers/i2c/busses/i2c-tiny-usb.c
++++ b/drivers/i2c/busses/i2c-tiny-usb.c
+@@ -226,10 +226,8 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface,
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (dev == NULL) {
+- dev_err(&interface->dev, "Out of memory\n");
++ if (!dev)
+ goto error;
+- }
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+--
+2.39.2
+
--- /dev/null
+From 50ea2a0b7ebd12da80211ce37177e490e2e056c9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 2 Feb 2018 14:50:09 +0100
+Subject: i2c: Improve size determinations
+
+From: Markus Elfring <elfring@users.sourceforge.net>
+
+[ Upstream commit 06e989578232da33a7fe96b04191b862af8b2cec ]
+
+Replace the specification of a data structure by a pointer dereference
+as the parameter for the operator "sizeof" to make the corresponding
+size determination a bit safer according to the Linux coding style
+convention.
+
+This issue was detected by using the Coccinelle software.
+
+Signed-off-by: Markus Elfring <elfring@users.sourceforge.net>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 2 +-
+ drivers/i2c/busses/i2c-sh7760.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 05eaae5aeb180..5004b9dd98563 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -970,7 +970,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+ struct i2c_vendor_data *vendor = id->data;
+ u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+
+- dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
++ dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err_no_mem;
+diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c
+index a0ccc5d009874..051b904cb35f6 100644
+--- a/drivers/i2c/busses/i2c-sh7760.c
++++ b/drivers/i2c/busses/i2c-sh7760.c
+@@ -443,7 +443,7 @@ static int sh7760_i2c_probe(struct platform_device *pdev)
+ goto out0;
+ }
+
+- id = kzalloc(sizeof(struct cami2c), GFP_KERNEL);
++ id = kzalloc(sizeof(*id), GFP_KERNEL);
+ if (!id) {
+ ret = -ENOMEM;
+ goto out0;
+--
+2.39.2
+
--- /dev/null
+From 34a60f664ab617a1caf611af6355eeb3b51a9f0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 4 Jul 2023 21:50:28 +0200
+Subject: i2c: nomadik: Remove a useless call in the remove function
+
+From: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+
+[ Upstream commit 05f933d5f7318b03ff2028c1704dc867ac16f2c7 ]
+
+Since commit 235602146ec9 ("i2c-nomadik: turn the platform driver to an amba
+driver"), there is no more request_mem_region() call in this driver.
+
+So remove the release_mem_region() call from the remove function which is
+likely a left over.
+
+Fixes: 235602146ec9 ("i2c-nomadik: turn the platform driver to an amba driver")
+Cc: <stable@vger.kernel.org> # v3.6+
+Acked-by: Linus Walleij <linus.walleij@linaro.org>
+Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
+Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 2141ba05dfece..9c5d66bd6dc1c 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -1040,7 +1040,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ static void nmk_i2c_remove(struct amba_device *adev)
+ {
+- struct resource *res = &adev->res;
+ struct nmk_i2c_dev *dev = amba_get_drvdata(adev);
+
+ i2c_del_adapter(&dev->adap);
+@@ -1049,7 +1048,6 @@ static void nmk_i2c_remove(struct amba_device *adev)
+ clear_all_interrupts(dev);
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+- release_mem_region(res->start, resource_size(res));
+ }
+
+ static struct i2c_vendor_data vendor_stn8815 = {
+--
+2.39.2
+
--- /dev/null
+From 655c28066fa458bcb6ff3a4a156e7494256f2041 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Jun 2023 03:36:59 +0200
+Subject: i2c: nomadik: Remove unnecessary goto label
+
+From: Andi Shyti <andi.shyti@kernel.org>
+
+[ Upstream commit 1c5d33fff0d375e4ab7c4261dc62a286babbb4c6 ]
+
+The err_no_mem goto label doesn't do anything. Remove it.
+
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 21 ++++++++-------------
+ 1 file changed, 8 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 5004b9dd98563..8b9577318388e 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -971,10 +971,9 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+ u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
+
+ dev = devm_kzalloc(&adev->dev, sizeof(*dev), GFP_KERNEL);
+- if (!dev) {
+- ret = -ENOMEM;
+- goto err_no_mem;
+- }
++ if (!dev)
++ return -ENOMEM;
++
+ dev->vendor = vendor;
+ dev->adev = adev;
+ nmk_i2c_of_probe(np, dev);
+@@ -995,30 +994,27 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
+ resource_size(&adev->res));
+- if (!dev->virtbase) {
+- ret = -ENOMEM;
+- goto err_no_mem;
+- }
++ if (!dev->virtbase)
++ return -ENOMEM;
+
+ dev->irq = adev->irq[0];
+ ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
+ DRIVER_NAME, dev);
+ if (ret) {
+ dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
+- goto err_no_mem;
++ return ret;
+ }
+
+ dev->clk = devm_clk_get(&adev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+ dev_err(&adev->dev, "could not get i2c clock\n");
+- ret = PTR_ERR(dev->clk);
+- goto err_no_mem;
++ return PTR_ERR(dev->clk);
+ }
+
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ dev_err(&adev->dev, "can't prepare_enable clock\n");
+- goto err_no_mem;
++ return ret;
+ }
+
+ init_hw(dev);
+@@ -1049,7 +1045,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ err_no_adap:
+ clk_disable_unprepare(dev->clk);
+- err_no_mem:
+
+ return ret;
+ }
+--
+2.39.2
+
--- /dev/null
+From 497a487c66fefe6d04f96f9d4acc070d8689565f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 11 Jun 2023 03:37:00 +0200
+Subject: i2c: nomadik: Use devm_clk_get_enabled()
+
+From: Andi Shyti <andi.shyti@kernel.org>
+
+[ Upstream commit 9c7174db4cdd111e10d19eed5c36fd978a14c8a2 ]
+
+Replace the pair of functions, devm_clk_get() and
+clk_prepare_enable(), with a single function
+devm_clk_get_enabled().
+
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Signed-off-by: Wolfram Sang <wsa@kernel.org>
+Stable-dep-of: 05f933d5f731 ("i2c: nomadik: Remove a useless call in the remove function")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/i2c/busses/i2c-nomadik.c | 18 +++---------------
+ 1 file changed, 3 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
+index 8b9577318388e..2141ba05dfece 100644
+--- a/drivers/i2c/busses/i2c-nomadik.c
++++ b/drivers/i2c/busses/i2c-nomadik.c
+@@ -1005,18 +1005,12 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+ return ret;
+ }
+
+- dev->clk = devm_clk_get(&adev->dev, NULL);
++ dev->clk = devm_clk_get_enabled(&adev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
+- dev_err(&adev->dev, "could not get i2c clock\n");
++ dev_err(&adev->dev, "could enable i2c clock\n");
+ return PTR_ERR(dev->clk);
+ }
+
+- ret = clk_prepare_enable(dev->clk);
+- if (ret) {
+- dev_err(&adev->dev, "can't prepare_enable clock\n");
+- return ret;
+- }
+-
+ init_hw(dev);
+
+ adap = &dev->adap;
+@@ -1037,16 +1031,11 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+- goto err_no_adap;
++ return ret;
+
+ pm_runtime_put(&adev->dev);
+
+ return 0;
+-
+- err_no_adap:
+- clk_disable_unprepare(dev->clk);
+-
+- return ret;
+ }
+
+ static void nmk_i2c_remove(struct amba_device *adev)
+@@ -1060,7 +1049,6 @@ static void nmk_i2c_remove(struct amba_device *adev)
+ clear_all_interrupts(dev);
+ /* disable the controller */
+ i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
+- clk_disable_unprepare(dev->clk);
+ release_mem_region(res->start, resource_size(res));
+ }
+
+--
+2.39.2
+
--- /dev/null
+From 4b74f1cbdf97d18a5afa9ae0bcae7b211dbc1e02 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Jul 2023 13:56:07 +0200
+Subject: io_uring: don't audit the capability check in io_uring_create()
+
+From: Ondrej Mosnacek <omosnace@redhat.com>
+
+[ Upstream commit 6adc2272aaaf84f34b652cf77f770c6fcc4b8336 ]
+
+The check being unconditional may lead to unwanted denials reported by
+LSMs when a process has the capability granted by DAC, but denied by an
+LSM. In the case of SELinux such denials are a problem, since they can't
+be effectively filtered out via the policy and when not silenced, they
+produce noise that may hide a true problem or an attack.
+
+Since not having the capability merely means that the created io_uring
+context will be accounted against the current user's RLIMIT_MEMLOCK
+limit, we can disable auditing of denials for this check by using
+ns_capable_noaudit() instead of capable().
+
+Fixes: 2b188cc1bb85 ("Add io_uring IO interface")
+Link: https://bugzilla.redhat.com/show_bug.cgi?id=2193317
+Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
+Reviewed-by: Jeff Moyer <jmoyer@redhat.com>
+Link: https://lore.kernel.org/r/20230718115607.65652-1-omosnace@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/io_uring.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
+index d7f87157be9aa..f65c6811ede81 100644
+--- a/io_uring/io_uring.c
++++ b/io_uring/io_uring.c
+@@ -10602,7 +10602,7 @@ static int io_uring_create(unsigned entries, struct io_uring_params *p,
+ if (!ctx)
+ return -ENOMEM;
+ ctx->compat = in_compat_syscall();
+- if (!capable(CAP_IPC_LOCK))
++ if (!ns_capable_noaudit(&init_user_ns, CAP_IPC_LOCK))
+ ctx->user = get_uid(current_user());
+
+ /*
+--
+2.39.2
+
--- /dev/null
+From b756a018ae344b7a50133eec86185342030b7e89 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:27 +0800
+Subject: jbd2: fix a race when checking checkpoint buffer busy
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit 46f881b5b1758dc4a35fba4a643c10717d0cf427 ]
+
+Before removing checkpoint buffer from the t_checkpoint_list, we have to
+check both BH_Dirty and BH_Lock bits together to distinguish buffers
+have not been or were being written back. But __cp_buffer_busy() checks
+them separately, it first check lock state and then check dirty, the
+window between these two checks could be raced by writing back
+procedure, which locks buffer and clears buffer dirty before I/O
+completes. So it cannot guarantee checkpointing buffers been written
+back to disk if some error happens later. Finally, it may clean
+checkpoint transactions and lead to inconsistent filesystem.
+
+jbd2_journal_forget() and __journal_try_to_free_buffer() also have the
+same problem (journal_unmap_buffer() escape from this issue since it's
+running under the buffer lock), so fix them through introducing a new
+helper to try holding the buffer lock and remove really clean buffer.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
+Cc: stable@vger.kernel.org
+Suggested-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-6-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 38 +++++++++++++++++++++++++++++++++++---
+ fs/jbd2/transaction.c | 17 +++++------------
+ include/linux/jbd2.h | 1 +
+ 3 files changed, 41 insertions(+), 15 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index ab72aeb766a74..fc6989e7a8c51 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -376,11 +376,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+
+- if (!destroy && __cp_buffer_busy(jh))
+- continue;
++ if (destroy) {
++ ret = __jbd2_journal_remove_checkpoint(jh);
++ } else {
++ ret = jbd2_journal_try_remove_checkpoint(jh);
++ if (ret < 0)
++ continue;
++ }
+
+ nr_freed++;
+- ret = __jbd2_journal_remove_checkpoint(jh);
+ if (ret) {
+ *released = true;
+ break;
+@@ -616,6 +620,34 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
+ return 1;
+ }
+
++/*
++ * Check the checkpoint buffer and try to remove it from the checkpoint
++ * list if it's clean. Returns -EBUSY if it is not clean, returns 1 if
++ * it frees the transaction, 0 otherwise.
++ *
++ * This function is called with j_list_lock held.
++ */
++int jbd2_journal_try_remove_checkpoint(struct journal_head *jh)
++{
++ struct buffer_head *bh = jh2bh(jh);
++
++ if (!trylock_buffer(bh))
++ return -EBUSY;
++ if (buffer_dirty(bh)) {
++ unlock_buffer(bh);
++ return -EBUSY;
++ }
++ unlock_buffer(bh);
++
++ /*
++ * Buffer is clean and the IO has finished (we held the buffer
++ * lock) so the checkpoint is done. We can safely remove the
++ * buffer from this transaction.
++ */
++ JBUFFER_TRACE(jh, "remove from checkpoint list");
++ return __jbd2_journal_remove_checkpoint(jh);
++}
++
+ /*
+ * journal_insert_checkpoint: put a committed buffer onto a checkpoint
+ * list so that we know when it is safe to clean the transaction out of
+diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
+index ce4a5ccadeff4..62e68c5b8ec3d 100644
+--- a/fs/jbd2/transaction.c
++++ b/fs/jbd2/transaction.c
+@@ -1775,8 +1775,7 @@ int jbd2_journal_forget(handle_t *handle, struct buffer_head *bh)
+ * Otherwise, if the buffer has been written to disk,
+ * it is safe to remove the checkpoint and drop it.
+ */
+- if (!buffer_dirty(bh)) {
+- __jbd2_journal_remove_checkpoint(jh);
++ if (jbd2_journal_try_remove_checkpoint(jh) >= 0) {
+ spin_unlock(&journal->j_list_lock);
+ goto drop;
+ }
+@@ -2103,20 +2102,14 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
+
+ jh = bh2jh(bh);
+
+- if (buffer_locked(bh) || buffer_dirty(bh))
+- goto out;
+-
+ if (jh->b_next_transaction != NULL || jh->b_transaction != NULL)
+- goto out;
++ return;
+
+ spin_lock(&journal->j_list_lock);
+- if (jh->b_cp_transaction != NULL) {
+- /* written-back checkpointed metadata buffer */
+- JBUFFER_TRACE(jh, "remove from checkpoint list");
+- __jbd2_journal_remove_checkpoint(jh);
+- }
++ /* Remove written-back checkpointed metadata buffer */
++ if (jh->b_cp_transaction != NULL)
++ jbd2_journal_try_remove_checkpoint(jh);
+ spin_unlock(&journal->j_list_lock);
+-out:
+ return;
+ }
+
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index e6cfbcde96f29..ade8a6d7acff9 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -1441,6 +1441,7 @@ extern void jbd2_journal_commit_transaction(journal_t *);
+ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy);
+ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal, unsigned long *nr_to_scan);
+ int __jbd2_journal_remove_checkpoint(struct journal_head *);
++int jbd2_journal_try_remove_checkpoint(struct journal_head *jh);
+ void jbd2_journal_destroy_checkpoint(journal_t *journal);
+ void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
+
+--
+2.39.2
+
--- /dev/null
+From 8ef166c955d5e1682826ea7a9cd405ad77cc5240 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:26 +0800
+Subject: jbd2: Fix wrongly judgement for buffer head removing while doing
+ checkpoint
+
+From: Zhihao Cheng <chengzhihao1@huawei.com>
+
+[ Upstream commit e34c8dd238d0c9368b746480f313055f5bab5040 ]
+
+Following process,
+
+jbd2_journal_commit_transaction
+// there are several dirty buffer heads in transaction->t_checkpoint_list
+ P1 wb_workfn
+jbd2_log_do_checkpoint
+ if (buffer_locked(bh)) // false
+ __block_write_full_page
+ trylock_buffer(bh)
+ test_clear_buffer_dirty(bh)
+ if (!buffer_dirty(bh))
+ __jbd2_journal_remove_checkpoint(jh)
+ if (buffer_write_io_error(bh)) // false
+ >> bh IO error occurs <<
+ jbd2_cleanup_journal_tail
+ __jbd2_update_log_tail
+ jbd2_write_superblock
+ // The bh won't be replayed in next mount.
+, which could corrupt the ext4 image, fetch a reproducer in [Link].
+
+Since writeback process clears buffer dirty after locking buffer head,
+we can fix it by try locking buffer and check dirtiness while buffer is
+locked, the buffer head can be removed if it is neither dirty nor locked.
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
+Fixes: 470decc613ab ("[PATCH] jbd2: initial copy of files from jbd")
+Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-5-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index fe8bb031b7d7f..d2aba55833f92 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -221,20 +221,6 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+ jh = transaction->t_checkpoint_list;
+ bh = jh2bh(jh);
+
+- /*
+- * The buffer may be writing back, or flushing out in the
+- * last couple of cycles, or re-adding into a new transaction,
+- * need to check it again until it's unlocked.
+- */
+- if (buffer_locked(bh)) {
+- get_bh(bh);
+- spin_unlock(&journal->j_list_lock);
+- wait_on_buffer(bh);
+- /* the journal_head may have gone by now */
+- BUFFER_TRACE(bh, "brelse");
+- __brelse(bh);
+- goto retry;
+- }
+ if (jh->b_transaction != NULL) {
+ transaction_t *t = jh->b_transaction;
+ tid_t tid = t->t_tid;
+@@ -269,7 +255,22 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+ spin_lock(&journal->j_list_lock);
+ goto restart;
+ }
+- if (!buffer_dirty(bh)) {
++ if (!trylock_buffer(bh)) {
++ /*
++ * The buffer is locked, it may be writing back, or
++ * flushing out in the last couple of cycles, or
++ * re-adding into a new transaction, need to check
++ * it again until it's unlocked.
++ */
++ get_bh(bh);
++ spin_unlock(&journal->j_list_lock);
++ wait_on_buffer(bh);
++ /* the journal_head may have gone by now */
++ BUFFER_TRACE(bh, "brelse");
++ __brelse(bh);
++ goto retry;
++ } else if (!buffer_dirty(bh)) {
++ unlock_buffer(bh);
+ BUFFER_TRACE(bh, "remove from checkpoint");
+ /*
+ * If the transaction was released or the checkpoint
+@@ -279,6 +280,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
+ !transaction->t_checkpoint_list)
+ goto out;
+ } else {
++ unlock_buffer(bh);
+ /*
+ * We are about to write the buffer, it could be
+ * raced by some other transaction shrink or buffer
+--
+2.39.2
+
--- /dev/null
+From aecb975234f28cd552c2716b840cb4df901d3027 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:25 +0800
+Subject: jbd2: remove journal_clean_one_cp_list()
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit b98dba273a0e47dbfade89c9af73c5b012a4eabb ]
+
+journal_clean_one_cp_list() and journal_shrink_one_cp_list() are almost
+the same, so merge them into journal_shrink_one_cp_list(), remove the
+nr_to_scan parameter, always scan and try to free the whole checkpoint
+list.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-4-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 75 +++++++++----------------------------
+ include/trace/events/jbd2.h | 12 ++----
+ 2 files changed, 21 insertions(+), 66 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index c1f543e86170a..ab72aeb766a74 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -349,50 +349,10 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
+
+ /* Checkpoint list management */
+
+-/*
+- * journal_clean_one_cp_list
+- *
+- * Find all the written-back checkpoint buffers in the given list and
+- * release them. If 'destroy' is set, clean all buffers unconditionally.
+- *
+- * Called with j_list_lock held.
+- * Returns 1 if we freed the transaction, 0 otherwise.
+- */
+-static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
+-{
+- struct journal_head *last_jh;
+- struct journal_head *next_jh = jh;
+-
+- if (!jh)
+- return 0;
+-
+- last_jh = jh->b_cpprev;
+- do {
+- jh = next_jh;
+- next_jh = jh->b_cpnext;
+-
+- if (!destroy && __cp_buffer_busy(jh))
+- return 0;
+-
+- if (__jbd2_journal_remove_checkpoint(jh))
+- return 1;
+- /*
+- * This function only frees up some memory
+- * if possible so we dont have an obligation
+- * to finish processing. Bail out if preemption
+- * requested:
+- */
+- if (need_resched())
+- return 0;
+- } while (jh != last_jh);
+-
+- return 0;
+-}
+-
+ /*
+ * journal_shrink_one_cp_list
+ *
+- * Find 'nr_to_scan' written-back checkpoint buffers in the given list
++ * Find all the written-back checkpoint buffers in the given list
+ * and try to release them. If the whole transaction is released, set
+ * the 'released' parameter. Return the number of released checkpointed
+ * buffers.
+@@ -400,15 +360,15 @@ static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy)
+ * Called with j_list_lock held.
+ */
+ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+- unsigned long *nr_to_scan,
+- bool *released)
++ bool destroy, bool *released)
+ {
+ struct journal_head *last_jh;
+ struct journal_head *next_jh = jh;
+ unsigned long nr_freed = 0;
+ int ret;
+
+- if (!jh || *nr_to_scan == 0)
++ *released = false;
++ if (!jh)
+ return 0;
+
+ last_jh = jh->b_cpprev;
+@@ -416,8 +376,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+
+- (*nr_to_scan)--;
+- if (__cp_buffer_busy(jh))
++ if (!destroy && __cp_buffer_busy(jh))
+ continue;
+
+ nr_freed++;
+@@ -429,7 +388,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
+
+ if (need_resched())
+ break;
+- } while (jh != last_jh && *nr_to_scan);
++ } while (jh != last_jh);
+
+ return nr_freed;
+ }
+@@ -447,11 +406,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ unsigned long *nr_to_scan)
+ {
+ transaction_t *transaction, *last_transaction, *next_transaction;
+- bool released;
++ bool __maybe_unused released;
+ tid_t first_tid = 0, last_tid = 0, next_tid = 0;
+ tid_t tid = 0;
+ unsigned long nr_freed = 0;
+- unsigned long nr_scanned = *nr_to_scan;
++ unsigned long freed;
+
+ again:
+ spin_lock(&journal->j_list_lock);
+@@ -480,10 +439,11 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ transaction = next_transaction;
+ next_transaction = transaction->t_cpnext;
+ tid = transaction->t_tid;
+- released = false;
+
+- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
+- nr_to_scan, &released);
++ freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
++ false, &released);
++ nr_freed += freed;
++ (*nr_to_scan) -= min(*nr_to_scan, freed);
+ if (*nr_to_scan == 0)
+ break;
+ if (need_resched() || spin_needbreak(&journal->j_list_lock))
+@@ -504,9 +464,8 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ if (*nr_to_scan && next_tid)
+ goto again;
+ out:
+- nr_scanned -= *nr_to_scan;
+ trace_jbd2_shrink_checkpoint_list(journal, first_tid, tid, last_tid,
+- nr_freed, nr_scanned, next_tid);
++ nr_freed, next_tid);
+
+ return nr_freed;
+ }
+@@ -522,7 +481,7 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ {
+ transaction_t *transaction, *last_transaction, *next_transaction;
+- int ret;
++ bool released;
+
+ transaction = journal->j_checkpoint_transactions;
+ if (!transaction)
+@@ -533,8 +492,8 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ do {
+ transaction = next_transaction;
+ next_transaction = transaction->t_cpnext;
+- ret = journal_clean_one_cp_list(transaction->t_checkpoint_list,
+- destroy);
++ journal_shrink_one_cp_list(transaction->t_checkpoint_list,
++ destroy, &released);
+ /*
+ * This function only frees up some memory if possible so we
+ * dont have an obligation to finish processing. Bail out if
+@@ -547,7 +506,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ * avoids pointless scanning of transactions which still
+ * weren't checkpointed.
+ */
+- if (!ret)
++ if (!released)
+ return;
+ } while (transaction != last_transaction);
+ }
+diff --git a/include/trace/events/jbd2.h b/include/trace/events/jbd2.h
+index 29414288ea3e0..34ce197bd76e0 100644
+--- a/include/trace/events/jbd2.h
++++ b/include/trace/events/jbd2.h
+@@ -462,11 +462,9 @@ TRACE_EVENT(jbd2_shrink_scan_exit,
+ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+
+ TP_PROTO(journal_t *journal, tid_t first_tid, tid_t tid, tid_t last_tid,
+- unsigned long nr_freed, unsigned long nr_scanned,
+- tid_t next_tid),
++ unsigned long nr_freed, tid_t next_tid),
+
+- TP_ARGS(journal, first_tid, tid, last_tid, nr_freed,
+- nr_scanned, next_tid),
++ TP_ARGS(journal, first_tid, tid, last_tid, nr_freed, next_tid),
+
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+@@ -474,7 +472,6 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+ __field(tid_t, tid)
+ __field(tid_t, last_tid)
+ __field(unsigned long, nr_freed)
+- __field(unsigned long, nr_scanned)
+ __field(tid_t, next_tid)
+ ),
+
+@@ -484,15 +481,14 @@ TRACE_EVENT(jbd2_shrink_checkpoint_list,
+ __entry->tid = tid;
+ __entry->last_tid = last_tid;
+ __entry->nr_freed = nr_freed;
+- __entry->nr_scanned = nr_scanned;
+ __entry->next_tid = next_tid;
+ ),
+
+ TP_printk("dev %d,%d shrink transaction %u-%u(%u) freed %lu "
+- "scanned %lu next transaction %u",
++ "next transaction %u",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->first_tid, __entry->tid, __entry->last_tid,
+- __entry->nr_freed, __entry->nr_scanned, __entry->next_tid)
++ __entry->nr_freed, __entry->next_tid)
+ );
+
+ #endif /* _TRACE_JBD2_H */
+--
+2.39.2
+
--- /dev/null
+From 92d4d5454f0734d09f34beaae5f86cf3dcc3087f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 6 Jun 2023 21:59:24 +0800
+Subject: jbd2: remove t_checkpoint_io_list
+
+From: Zhang Yi <yi.zhang@huawei.com>
+
+[ Upstream commit be22255360f80d3af789daad00025171a65424a5 ]
+
+Since t_checkpoint_io_list was stop using in jbd2_log_do_checkpoint()
+now, it's time to remove the whole t_checkpoint_io_list logic.
+
+Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20230606135928.434610-3-yi.zhang@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 46f881b5b175 ("jbd2: fix a race when checking checkpoint buffer busy")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/jbd2/checkpoint.c | 42 ++----------------------------------------
+ fs/jbd2/commit.c | 3 +--
+ include/linux/jbd2.h | 6 ------
+ 3 files changed, 3 insertions(+), 48 deletions(-)
+
+diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
+index d2aba55833f92..c1f543e86170a 100644
+--- a/fs/jbd2/checkpoint.c
++++ b/fs/jbd2/checkpoint.c
+@@ -27,7 +27,7 @@
+ *
+ * Called with j_list_lock held.
+ */
+-static inline void __buffer_unlink_first(struct journal_head *jh)
++static inline void __buffer_unlink(struct journal_head *jh)
+ {
+ transaction_t *transaction = jh->b_cp_transaction;
+
+@@ -40,23 +40,6 @@ static inline void __buffer_unlink_first(struct journal_head *jh)
+ }
+ }
+
+-/*
+- * Unlink a buffer from a transaction checkpoint(io) list.
+- *
+- * Called with j_list_lock held.
+- */
+-static inline void __buffer_unlink(struct journal_head *jh)
+-{
+- transaction_t *transaction = jh->b_cp_transaction;
+-
+- __buffer_unlink_first(jh);
+- if (transaction->t_checkpoint_io_list == jh) {
+- transaction->t_checkpoint_io_list = jh->b_cpnext;
+- if (transaction->t_checkpoint_io_list == jh)
+- transaction->t_checkpoint_io_list = NULL;
+- }
+-}
+-
+ /*
+ * Check a checkpoint buffer could be release or not.
+ *
+@@ -505,15 +488,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
+ break;
+ if (need_resched() || spin_needbreak(&journal->j_list_lock))
+ break;
+- if (released)
+- continue;
+-
+- nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_io_list,
+- nr_to_scan, &released);
+- if (*nr_to_scan == 0)
+- break;
+- if (need_resched() || spin_needbreak(&journal->j_list_lock))
+- break;
+ } while (transaction != last_transaction);
+
+ if (transaction != last_transaction) {
+@@ -568,17 +542,6 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy)
+ */
+ if (need_resched())
+ return;
+- if (ret)
+- continue;
+- /*
+- * It is essential that we are as careful as in the case of
+- * t_checkpoint_list with removing the buffer from the list as
+- * we can possibly see not yet submitted buffers on io_list
+- */
+- ret = journal_clean_one_cp_list(transaction->
+- t_checkpoint_io_list, destroy);
+- if (need_resched())
+- return;
+ /*
+ * Stop scanning if we couldn't free the transaction. This
+ * avoids pointless scanning of transactions which still
+@@ -663,7 +626,7 @@ int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
+ jbd2_journal_put_journal_head(jh);
+
+ /* Is this transaction empty? */
+- if (transaction->t_checkpoint_list || transaction->t_checkpoint_io_list)
++ if (transaction->t_checkpoint_list)
+ return 0;
+
+ /*
+@@ -755,7 +718,6 @@ void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transact
+ J_ASSERT(transaction->t_forget == NULL);
+ J_ASSERT(transaction->t_shadow_list == NULL);
+ J_ASSERT(transaction->t_checkpoint_list == NULL);
+- J_ASSERT(transaction->t_checkpoint_io_list == NULL);
+ J_ASSERT(atomic_read(&transaction->t_updates) == 0);
+ J_ASSERT(journal->j_committing_transaction != transaction);
+ J_ASSERT(journal->j_running_transaction != transaction);
+diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
+index ac328e3321242..20294c1bbeab7 100644
+--- a/fs/jbd2/commit.c
++++ b/fs/jbd2/commit.c
+@@ -1184,8 +1184,7 @@ void jbd2_journal_commit_transaction(journal_t *journal)
+ spin_lock(&journal->j_list_lock);
+ commit_transaction->t_state = T_FINISHED;
+ /* Check if the transaction can be dropped now that we are finished */
+- if (commit_transaction->t_checkpoint_list == NULL &&
+- commit_transaction->t_checkpoint_io_list == NULL) {
++ if (commit_transaction->t_checkpoint_list == NULL) {
+ __jbd2_journal_drop_transaction(journal, commit_transaction);
+ jbd2_journal_free_transaction(commit_transaction);
+ }
+diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
+index d63b8106796e2..e6cfbcde96f29 100644
+--- a/include/linux/jbd2.h
++++ b/include/linux/jbd2.h
+@@ -626,12 +626,6 @@ struct transaction_s
+ */
+ struct journal_head *t_checkpoint_list;
+
+- /*
+- * Doubly-linked circular list of all buffers submitted for IO while
+- * checkpointing. [j_list_lock]
+- */
+- struct journal_head *t_checkpoint_io_list;
+-
+ /*
+ * Doubly-linked circular list of metadata buffers being
+ * shadowed by log IO. The IO buffers on the iobuf list and
+--
+2.39.2
+
--- /dev/null
+From d9c75a1623fdb440b59aae1d3bc66d6a49841d68 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 16 Mar 2023 07:34:33 +0900
+Subject: ksmbd: remove internal.h include
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit 211db0ac9e3dc6c46f2dd53395b34d76af929faf ]
+
+Since vfs_path_lookup is exported, It should not be internal.
+Move vfs_path_lookup prototype in internal.h to linux/namei.h.
+
+Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
+Reviewed-by: Christian Brauner <brauner@kernel.org>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Stable-dep-of: df9d70c18616 ("cifs: if deferred close is disabled then close files immediately")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/internal.h | 2 --
+ fs/ksmbd/vfs.c | 2 --
+ include/linux/namei.h | 2 ++
+ 3 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/fs/internal.h b/fs/internal.h
+index ceb154583a3c4..1ff8cfc94467b 100644
+--- a/fs/internal.h
++++ b/fs/internal.h
+@@ -58,8 +58,6 @@ extern int finish_clean_context(struct fs_context *fc);
+ */
+ extern int filename_lookup(int dfd, struct filename *name, unsigned flags,
+ struct path *path, struct path *root);
+-extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+- const char *, unsigned int, struct path *);
+ int do_rmdir(int dfd, struct filename *name);
+ int do_unlinkat(int dfd, struct filename *name);
+ int may_linkat(struct user_namespace *mnt_userns, struct path *link);
+diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c
+index 52cc6a9627ed7..f76acd83c2944 100644
+--- a/fs/ksmbd/vfs.c
++++ b/fs/ksmbd/vfs.c
+@@ -19,8 +19,6 @@
+ #include <linux/sched/xacct.h>
+ #include <linux/crc32c.h>
+
+-#include "../internal.h" /* for vfs_path_lookup */
+-
+ #include "glob.h"
+ #include "oplock.h"
+ #include "connection.h"
+diff --git a/include/linux/namei.h b/include/linux/namei.h
+index caeb08a98536c..40c693525f796 100644
+--- a/include/linux/namei.h
++++ b/include/linux/namei.h
+@@ -63,6 +63,8 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
+ extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
+ extern void done_path_create(struct path *, struct dentry *);
+ extern struct dentry *kern_path_locked(const char *, struct path *);
++int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *,
++ unsigned int, struct path *);
+
+ extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
+ extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
+--
+2.39.2
+
--- /dev/null
+From b295b7e4014dd96e83bfd9f8778f82dd01044ef5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 5 Jul 2023 13:19:37 +0200
+Subject: KVM: s390: pv: fix index value of replaced ASCE
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Claudio Imbrenda <imbrenda@linux.ibm.com>
+
+[ Upstream commit c2fceb59bbda16468bda82b002383bff59de89ab ]
+
+The index field of the struct page corresponding to a guest ASCE should
+be 0. When replacing the ASCE in s390_replace_asce(), the index of the
+new ASCE should also be set to 0.
+
+Having the wrong index might lead to the wrong addresses being passed
+around when notifying pte invalidations, and eventually to validity
+intercepts (VM crash) if the prefix gets unmapped and the notifier gets
+called with the wrong address.
+
+Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
+Fixes: faa2f72cb356 ("KVM: s390: pv: leak the topmost page table when destroy fails")
+Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
+Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
+Message-ID: <20230705111937.33472-3-imbrenda@linux.ibm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/s390/mm/gmap.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c
+index ff40bf92db43a..a2c872de29a66 100644
+--- a/arch/s390/mm/gmap.c
++++ b/arch/s390/mm/gmap.c
+@@ -2791,6 +2791,7 @@ int s390_replace_asce(struct gmap *gmap)
+ page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER);
+ if (!page)
+ return -ENOMEM;
++ page->index = 0;
+ table = page_to_virt(page);
+ memcpy(table, gmap->table, 1UL << (CRST_ALLOC_ORDER + PAGE_SHIFT));
+
+--
+2.39.2
+
--- /dev/null
+From 46947742388959c672d059772208ccb938fef065 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 11 Nov 2022 16:25:02 +0200
+Subject: n_tty: Rename tail to old_tail in n_tty_read()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit 947d66b68f3c4e7cf8f3f3500807b9d2a0de28ce ]
+
+The local tail variable in n_tty_read() is used for one purpose, it
+keeps the old tail. Thus, rename it appropriately to improve code
+readability.
+
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
+Link: https://lore.kernel.org/r/22b37499-ff9a-7fc1-f6e0-58411328d122@linux.intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 4903fde8047a ("tty: fix hang on tty device with no_room set")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_tty.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
+index 891036bd9f897..8f57448e1ce46 100644
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -2100,7 +2100,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+ ssize_t retval = 0;
+ long timeout;
+ bool packet;
+- size_t tail;
++ size_t old_tail;
+
+ /*
+ * Is this a continuation of a read started earler?
+@@ -2163,7 +2163,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+ }
+
+ packet = tty->ctrl.packet;
+- tail = ldata->read_tail;
++ old_tail = ldata->read_tail;
+
+ add_wait_queue(&tty->read_wait, &wait);
+ while (nr) {
+@@ -2252,7 +2252,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+ if (time)
+ timeout = time;
+ }
+- if (tail != ldata->read_tail)
++ if (old_tail != ldata->read_tail)
+ n_tty_kick_worker(tty);
+ up_read(&tty->termios_rwsem);
+
+--
+2.39.2
+
--- /dev/null
+From e8d78a001d6cd99367d133ad691f99306ade7ae0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 2 May 2023 11:39:23 +0300
+Subject: PCI/ASPM: Avoid link retraining race
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit e7e39756363ad5bd83ddeae1063193d0f13870fd ]
+
+PCIe r6.0.1, sec 7.5.3.7, recommends setting the link control parameters,
+then waiting for the Link Training bit to be clear before setting the
+Retrain Link bit.
+
+This avoids a race where the LTSSM may not use the updated parameters if it
+is already in the midst of link training because of other normal link
+activity.
+
+Wait for the Link Training bit to be clear before toggling the Retrain Link
+bit to ensure that the LTSSM uses the updated link control parameters.
+
+[bhelgaas: commit log, return 0 (success)/-ETIMEDOUT instead of bool for
+both pcie_wait_for_retrain() and the existing pcie_retrain_link()]
+Suggested-by: Lukas Wunner <lukas@wunner.de>
+Fixes: 7d715a6c1ae5 ("PCI: add PCI Express ASPM support")
+Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Lukas Wunner <lukas@wunner.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index 5e09cbb563366..3078de668f911 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -212,8 +212,19 @@ static int pcie_wait_for_retrain(struct pci_dev *pdev)
+ static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+ struct pci_dev *parent = link->pdev;
++ int rc;
+ u16 reg16;
+
++ /*
++ * Ensure the updated LNKCTL parameters are used during link
++ * training by checking that there is no ongoing link training to
++ * avoid LTSSM race as recommended in Implementation Note at the
++ * end of PCIe r6.0.1 sec 7.5.3.7.
++ */
++ rc = pcie_wait_for_retrain(parent);
++ if (rc)
++ return rc;
++
+ pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
+ reg16 |= PCI_EXP_LNKCTL_RL;
+ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+--
+2.39.2
+
--- /dev/null
+From 36264db8f61aace836eefc44d4b4ce6f14df5392 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Jun 2023 14:49:33 -0500
+Subject: PCI/ASPM: Factor out pcie_wait_for_retrain()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+
+[ Upstream commit 9c7f136433d26592cb4d9cd00b4e15c33d9797c6 ]
+
+Factor pcie_wait_for_retrain() out from pcie_retrain_link(). No functional
+change intended.
+
+[bhelgaas: split out from
+https: //lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com]
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: e7e39756363a ("PCI/ASPM: Avoid link retraining race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 30 ++++++++++++++++++------------
+ 1 file changed, 18 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index e7f742ff31c3c..5e09cbb563366 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -192,10 +192,26 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
+ link->clkpm_disable = blacklist ? 1 : 0;
+ }
+
++static int pcie_wait_for_retrain(struct pci_dev *pdev)
++{
++ unsigned long end_jiffies;
++ u16 reg16;
++
++ /* Wait for Link Training to be cleared by hardware */
++ end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
++ do {
++ pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, ®16);
++ if (!(reg16 & PCI_EXP_LNKSTA_LT))
++ return 0;
++ msleep(1);
++ } while (time_before(jiffies, end_jiffies));
++
++ return -ETIMEDOUT;
++}
++
+ static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+ struct pci_dev *parent = link->pdev;
+- unsigned long end_jiffies;
+ u16 reg16;
+
+ pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
+@@ -211,17 +227,7 @@ static int pcie_retrain_link(struct pcie_link_state *link)
+ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+ }
+
+- /* Wait for link training end. Break out after waiting for timeout */
+- end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
+- do {
+- pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16);
+- if (!(reg16 & PCI_EXP_LNKSTA_LT))
+- break;
+- msleep(1);
+- } while (time_before(jiffies, end_jiffies));
+- if (reg16 & PCI_EXP_LNKSTA_LT)
+- return -ETIMEDOUT;
+- return 0;
++ return pcie_wait_for_retrain(parent);
+ }
+
+ /*
+--
+2.39.2
+
--- /dev/null
+From 786317a4aaccf786bfb06a38f742fc49680c4ae3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 Jun 2023 14:44:55 -0500
+Subject: PCI/ASPM: Return 0 or -ETIMEDOUT from pcie_retrain_link()
+
+From: Bjorn Helgaas <bhelgaas@google.com>
+
+[ Upstream commit f5297a01ee805d7fa569d288ed65fc0f9ac9b03d ]
+
+"pcie_retrain_link" is not a question with a true/false answer, so "bool"
+isn't quite the right return type. Return 0 for success or -ETIMEDOUT if
+the retrain failed. No functional change intended.
+
+[bhelgaas: based on Ilpo's patch below]
+Link: https://lore.kernel.org/r/20230502083923.34562-1-ilpo.jarvinen@linux.intel.com
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Stable-dep-of: e7e39756363a ("PCI/ASPM: Avoid link retraining race")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/pcie/aspm.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
+index c58294f53fcd1..e7f742ff31c3c 100644
+--- a/drivers/pci/pcie/aspm.c
++++ b/drivers/pci/pcie/aspm.c
+@@ -192,7 +192,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
+ link->clkpm_disable = blacklist ? 1 : 0;
+ }
+
+-static bool pcie_retrain_link(struct pcie_link_state *link)
++static int pcie_retrain_link(struct pcie_link_state *link)
+ {
+ struct pci_dev *parent = link->pdev;
+ unsigned long end_jiffies;
+@@ -219,7 +219,9 @@ static bool pcie_retrain_link(struct pcie_link_state *link)
+ break;
+ msleep(1);
+ } while (time_before(jiffies, end_jiffies));
+- return !(reg16 & PCI_EXP_LNKSTA_LT);
++ if (reg16 & PCI_EXP_LNKSTA_LT)
++ return -ETIMEDOUT;
++ return 0;
+ }
+
+ /*
+@@ -288,15 +290,15 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
+ reg16 &= ~PCI_EXP_LNKCTL_CCC;
+ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
+
+- if (pcie_retrain_link(link))
+- return;
++ if (pcie_retrain_link(link)) {
+
+- /* Training failed. Restore common clock configurations */
+- pci_err(parent, "ASPM: Could not configure common clock\n");
+- list_for_each_entry(child, &linkbus->devices, bus_list)
+- pcie_capability_write_word(child, PCI_EXP_LNKCTL,
++ /* Training failed. Restore common clock configurations */
++ pci_err(parent, "ASPM: Could not configure common clock\n");
++ list_for_each_entry(child, &linkbus->devices, bus_list)
++ pcie_capability_write_word(child, PCI_EXP_LNKCTL,
+ child_reg[PCI_FUNC(child->devfn)]);
+- pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
++ pcie_capability_write_word(parent, PCI_EXP_LNKCTL, parent_reg);
++ }
+ }
+
+ /* Convert L0s latency encoding to ns */
+--
+2.39.2
+
--- /dev/null
+From 30c4c68808b06e28cf438684c3c0d54ab8a181b4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:57 +0200
+Subject: PCI: rockchip: Don't advertise MSI-X in PCIe capabilities
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit a52587e0bee14cbeeadf48a24013828cb04b8df8 ]
+
+The RK3399 PCIe endpoint controller cannot generate MSI-X IRQs.
+This is documented in the RK3399 technical reference manual (TRM)
+section 17.5.9 "Interrupt Support".
+
+MSI-X capability should therefore not be advertised. Remove the
+MSI-X capability by editing the capability linked-list. The
+previous entry is the MSI capability, therefore get the next
+entry from the MSI-X capability entry and set it as next entry
+for the MSI capability. This in effect removes MSI-X from the list.
+
+Linked list before : MSI cap -> MSI-X cap -> PCIe Device cap -> ...
+Linked list now : MSI cap -> PCIe Device cap -> ...
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-11-rick.wertenbroek@gmail.com
+Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller")
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 24 +++++++++++++++++++++++
+ drivers/pci/controller/pcie-rockchip.h | 5 +++++
+ 2 files changed, 29 insertions(+)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 3d6f828d29fc2..0af0e965fb57e 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -508,6 +508,7 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+ size_t max_regions;
+ struct pci_epc_mem_window *windows = NULL;
+ int err, i;
++ u32 cfg_msi, cfg_msix_cp;
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+@@ -583,6 +584,29 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+
+ ep->irq_pci_addr = ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR;
+
++ /*
++ * MSI-X is not supported but the controller still advertises the MSI-X
++ * capability by default, which can lead to the Root Complex side
++ * allocating MSI-X vectors which cannot be used. Avoid this by skipping
++ * the MSI-X capability entry in the PCIe capabilities linked-list: get
++ * the next pointer from the MSI-X entry and set that in the MSI
++ * capability entry (which is the previous entry). This way the MSI-X
++ * entry is skipped (left out of the linked-list) and not advertised.
++ */
++ cfg_msi = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_BASE +
++ ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
++
++ cfg_msi &= ~ROCKCHIP_PCIE_EP_MSI_CP1_MASK;
++
++ cfg_msix_cp = rockchip_pcie_read(rockchip, PCIE_EP_CONFIG_BASE +
++ ROCKCHIP_PCIE_EP_MSIX_CAP_REG) &
++ ROCKCHIP_PCIE_EP_MSIX_CAP_CP_MASK;
++
++ cfg_msi |= cfg_msix_cp;
++
++ rockchip_pcie_write(rockchip, cfg_msi,
++ PCIE_EP_CONFIG_BASE + ROCKCHIP_PCIE_EP_MSI_CTRL_REG);
++
+ rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE,
+ PCIE_CLIENT_CONFIG);
+
+diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
+index 498a40251d0be..88e2bf65e433a 100644
+--- a/drivers/pci/controller/pcie-rockchip.h
++++ b/drivers/pci/controller/pcie-rockchip.h
+@@ -228,6 +228,8 @@
+ #define ROCKCHIP_PCIE_EP_CMD_STATUS 0x4
+ #define ROCKCHIP_PCIE_EP_CMD_STATUS_IS BIT(19)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_REG 0x90
++#define ROCKCHIP_PCIE_EP_MSI_CP1_OFFSET 8
++#define ROCKCHIP_PCIE_EP_MSI_CP1_MASK GENMASK(15, 8)
+ #define ROCKCHIP_PCIE_EP_MSI_FLAGS_OFFSET 16
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_OFFSET 17
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MMC_MASK GENMASK(19, 17)
+@@ -235,6 +237,9 @@
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MME_MASK GENMASK(22, 20)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_ME BIT(16)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP BIT(24)
++#define ROCKCHIP_PCIE_EP_MSIX_CAP_REG 0xb0
++#define ROCKCHIP_PCIE_EP_MSIX_CAP_CP_OFFSET 8
++#define ROCKCHIP_PCIE_EP_MSIX_CAP_CP_MASK GENMASK(15, 8)
+ #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR 0x1
+ #define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR 0x3
+ #define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \
+--
+2.39.2
+
--- /dev/null
+From 654fa12adc6b26111c6aea4f41edab940ae82f85 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:55 +0200
+Subject: PCI: rockchip: Fix window mapping and address translation for
+ endpoint
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit dc73ed0f1b8bddd7f2bf70d123e68ffc99ad71ce ]
+
+The RK3399 PCI endpoint core has 33 windows for PCIe space, now in the
+driver up to 32 fixed size (1M) windows are used and pages are allocated
+and mapped accordingly. The driver first used a single window and allocated
+space inside which caused translation issues (between CPU space and PCI
+space) because a window can only have a single translation at a given
+time, which if multiple pages are allocated inside will cause conflicts.
+Now each window is a single region of 1M which will always guarantee that
+the translation is not in conflict.
+
+Set the translation register addresses for physical function. As documented
+in the technical reference manual (TRM) section 17.5.5 "PCIe Address
+Translation" and section 17.6.8 "Address Translation Registers Description"
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-9-rick.wertenbroek@gmail.com
+Fixes: cf590b078391 ("PCI: rockchip: Add EP driver for Rockchip PCIe controller")
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 128 ++++++++++------------
+ drivers/pci/controller/pcie-rockchip.h | 35 +++---
+ 2 files changed, 75 insertions(+), 88 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 9e17f3dba743a..3d6f828d29fc2 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -64,52 +64,29 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip,
+ }
+
+ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+- u32 r, u32 type, u64 cpu_addr,
+- u64 pci_addr, size_t size)
++ u32 r, u64 cpu_addr, u64 pci_addr,
++ size_t size)
+ {
+- u64 sz = 1ULL << fls64(size - 1);
+- int num_pass_bits = ilog2(sz);
+- u32 addr0, addr1, desc0, desc1;
+- bool is_nor_msg = (type == AXI_WRAPPER_NOR_MSG);
++ int num_pass_bits = fls64(size - 1);
++ u32 addr0, addr1, desc0;
+
+- /* The minimal region size is 1MB */
+ if (num_pass_bits < 8)
+ num_pass_bits = 8;
+
+- cpu_addr -= rockchip->mem_res->start;
+- addr0 = ((is_nor_msg ? 0x10 : (num_pass_bits - 1)) &
+- PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
+- (lower_32_bits(cpu_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+- addr1 = upper_32_bits(is_nor_msg ? cpu_addr : pci_addr);
+- desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | type;
+- desc1 = 0;
+-
+- if (is_nor_msg) {
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
+- rockchip_pcie_write(rockchip, desc0,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
+- rockchip_pcie_write(rockchip, desc1,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+- } else {
+- /* PCI bus address region */
+- rockchip_pcie_write(rockchip, addr0,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
+- rockchip_pcie_write(rockchip, addr1,
+- ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
+- rockchip_pcie_write(rockchip, desc0,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
+- rockchip_pcie_write(rockchip, desc1,
+- ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+-
+- addr0 =
+- ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
+- (lower_32_bits(cpu_addr) &
+- PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+- addr1 = upper_32_bits(cpu_addr);
+- }
++ addr0 = ((num_pass_bits - 1) & PCIE_CORE_OB_REGION_ADDR0_NUM_BITS) |
++ (lower_32_bits(pci_addr) & PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
++ addr1 = upper_32_bits(pci_addr);
++ desc0 = ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(fn) | AXI_WRAPPER_MEM_WRITE;
++
++ /* PCI bus address region */
++ rockchip_pcie_write(rockchip, addr0,
++ ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r));
++ rockchip_pcie_write(rockchip, addr1,
++ ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r));
++ rockchip_pcie_write(rockchip, desc0,
++ ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r));
++ rockchip_pcie_write(rockchip, 0,
++ ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r));
+ }
+
+ static int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+@@ -248,26 +225,20 @@ static void rockchip_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn, u8 vfn,
+ ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar));
+ }
+
++static inline u32 rockchip_ob_region(phys_addr_t addr)
++{
++ return (addr >> ilog2(SZ_1M)) & 0x1f;
++}
++
+ static int rockchip_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+ phys_addr_t addr, u64 pci_addr,
+ size_t size)
+ {
+ struct rockchip_pcie_ep *ep = epc_get_drvdata(epc);
+ struct rockchip_pcie *pcie = &ep->rockchip;
+- u32 r;
++ u32 r = rockchip_ob_region(addr);
+
+- r = find_first_zero_bit(&ep->ob_region_map, BITS_PER_LONG);
+- /*
+- * Region 0 is reserved for configuration space and shouldn't
+- * be used elsewhere per TRM, so leave it out.
+- */
+- if (r >= ep->max_regions - 1) {
+- dev_err(&epc->dev, "no free outbound region\n");
+- return -EINVAL;
+- }
+-
+- rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, AXI_WRAPPER_MEM_WRITE, addr,
+- pci_addr, size);
++ rockchip_pcie_prog_ep_ob_atu(pcie, fn, r, addr, pci_addr, size);
+
+ set_bit(r, &ep->ob_region_map);
+ ep->ob_addr[r] = addr;
+@@ -282,15 +253,11 @@ static void rockchip_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn, u8 vfn,
+ struct rockchip_pcie *rockchip = &ep->rockchip;
+ u32 r;
+
+- for (r = 0; r < ep->max_regions - 1; r++)
++ for (r = 0; r < ep->max_regions; r++)
+ if (ep->ob_addr[r] == addr)
+ break;
+
+- /*
+- * Region 0 is reserved for configuration space and shouldn't
+- * be used elsewhere per TRM, so leave it out.
+- */
+- if (r == ep->max_regions - 1)
++ if (r == ep->max_regions)
+ return;
+
+ rockchip_pcie_clear_ep_ob_atu(rockchip, r);
+@@ -387,7 +354,8 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
+ struct rockchip_pcie *rockchip = &ep->rockchip;
+ u32 flags, mme, data, data_mask;
+ u8 msi_count;
+- u64 pci_addr, pci_addr_mask = 0xff;
++ u64 pci_addr;
++ u32 r;
+
+ /* Check MSI enable bit */
+ flags = rockchip_pcie_read(&ep->rockchip,
+@@ -421,21 +389,20 @@ static int rockchip_pcie_ep_send_msi_irq(struct rockchip_pcie_ep *ep, u8 fn,
+ ROCKCHIP_PCIE_EP_FUNC_BASE(fn) +
+ ROCKCHIP_PCIE_EP_MSI_CTRL_REG +
+ PCI_MSI_ADDRESS_LO);
+- pci_addr &= GENMASK_ULL(63, 2);
+
+ /* Set the outbound region if needed. */
+- if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
++ if (unlikely(ep->irq_pci_addr != (pci_addr & PCIE_ADDR_MASK) ||
+ ep->irq_pci_fn != fn)) {
+- rockchip_pcie_prog_ep_ob_atu(rockchip, fn, ep->max_regions - 1,
+- AXI_WRAPPER_MEM_WRITE,
++ r = rockchip_ob_region(ep->irq_phys_addr);
++ rockchip_pcie_prog_ep_ob_atu(rockchip, fn, r,
+ ep->irq_phys_addr,
+- pci_addr & ~pci_addr_mask,
+- pci_addr_mask + 1);
+- ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
++ pci_addr & PCIE_ADDR_MASK,
++ ~PCIE_ADDR_MASK + 1);
++ ep->irq_pci_addr = (pci_addr & PCIE_ADDR_MASK);
+ ep->irq_pci_fn = fn;
+ }
+
+- writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
++ writew(data, ep->irq_cpu_addr + (pci_addr & ~PCIE_ADDR_MASK));
+ return 0;
+ }
+
+@@ -517,6 +484,8 @@ static int rockchip_pcie_parse_ep_dt(struct rockchip_pcie *rockchip,
+ if (err < 0 || ep->max_regions > MAX_REGION_LIMIT)
+ ep->max_regions = MAX_REGION_LIMIT;
+
++ ep->ob_region_map = 0;
++
+ err = of_property_read_u8(dev->of_node, "max-functions",
+ &ep->epc->max_functions);
+ if (err < 0)
+@@ -537,7 +506,8 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+ struct rockchip_pcie *rockchip;
+ struct pci_epc *epc;
+ size_t max_regions;
+- int err;
++ struct pci_epc_mem_window *windows = NULL;
++ int err, i;
+
+ ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+@@ -584,15 +554,27 @@ static int rockchip_pcie_ep_probe(struct platform_device *pdev)
+ /* Only enable function 0 by default */
+ rockchip_pcie_write(rockchip, BIT(0), PCIE_CORE_PHY_FUNC_CFG);
+
+- err = pci_epc_mem_init(epc, rockchip->mem_res->start,
+- resource_size(rockchip->mem_res), PAGE_SIZE);
++ windows = devm_kcalloc(dev, ep->max_regions,
++ sizeof(struct pci_epc_mem_window), GFP_KERNEL);
++ if (!windows) {
++ err = -ENOMEM;
++ goto err_uninit_port;
++ }
++ for (i = 0; i < ep->max_regions; i++) {
++ windows[i].phys_base = rockchip->mem_res->start + (SZ_1M * i);
++ windows[i].size = SZ_1M;
++ windows[i].page_size = SZ_1M;
++ }
++ err = pci_epc_multi_mem_init(epc, windows, ep->max_regions);
++ devm_kfree(dev, windows);
++
+ if (err < 0) {
+ dev_err(dev, "failed to initialize the memory space\n");
+ goto err_uninit_port;
+ }
+
+ ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
+- SZ_128K);
++ SZ_1M);
+ if (!ep->irq_cpu_addr) {
+ dev_err(dev, "failed to reserve memory space for MSI\n");
+ err = -ENOMEM;
+diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
+index cbd2fd25ba761..498a40251d0be 100644
+--- a/drivers/pci/controller/pcie-rockchip.h
++++ b/drivers/pci/controller/pcie-rockchip.h
+@@ -139,6 +139,7 @@
+
+ #define PCIE_RC_RP_ATS_BASE 0x400000
+ #define PCIE_RC_CONFIG_NORMAL_BASE 0x800000
++#define PCIE_EP_PF_CONFIG_REGS_BASE 0x800000
+ #define PCIE_RC_CONFIG_BASE 0xa00000
+ #define PCIE_EP_CONFIG_BASE 0xa00000
+ #define PCIE_EP_CONFIG_DID_VID (PCIE_EP_CONFIG_BASE + 0x00)
+@@ -158,10 +159,11 @@
+ #define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274)
+ #define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20)
+
++#define PCIE_ADDR_MASK 0xffffff00
+ #define PCIE_CORE_AXI_CONF_BASE 0xc00000
+ #define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0)
+ #define PCIE_CORE_OB_REGION_ADDR0_NUM_BITS 0x3f
+-#define PCIE_CORE_OB_REGION_ADDR0_LO_ADDR 0xffffff00
++#define PCIE_CORE_OB_REGION_ADDR0_LO_ADDR PCIE_ADDR_MASK
+ #define PCIE_CORE_OB_REGION_ADDR1 (PCIE_CORE_AXI_CONF_BASE + 0x4)
+ #define PCIE_CORE_OB_REGION_DESC0 (PCIE_CORE_AXI_CONF_BASE + 0x8)
+ #define PCIE_CORE_OB_REGION_DESC1 (PCIE_CORE_AXI_CONF_BASE + 0xc)
+@@ -169,7 +171,7 @@
+ #define PCIE_CORE_AXI_INBOUND_BASE 0xc00800
+ #define PCIE_RP_IB_ADDR0 (PCIE_CORE_AXI_INBOUND_BASE + 0x0)
+ #define PCIE_CORE_IB_REGION_ADDR0_NUM_BITS 0x3f
+-#define PCIE_CORE_IB_REGION_ADDR0_LO_ADDR 0xffffff00
++#define PCIE_CORE_IB_REGION_ADDR0_LO_ADDR PCIE_ADDR_MASK
+ #define PCIE_RP_IB_ADDR1 (PCIE_CORE_AXI_INBOUND_BASE + 0x4)
+
+ /* Size of one AXI Region (not Region 0) */
+@@ -234,13 +236,15 @@
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_ME BIT(16)
+ #define ROCKCHIP_PCIE_EP_MSI_CTRL_MASK_MSI_CAP BIT(24)
+ #define ROCKCHIP_PCIE_EP_DUMMY_IRQ_ADDR 0x1
+-#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))
++#define ROCKCHIP_PCIE_EP_PCI_LEGACY_IRQ_ADDR 0x3
++#define ROCKCHIP_PCIE_EP_FUNC_BASE(fn) \
++ (PCIE_EP_PF_CONFIG_REGS_BASE + (((fn) << 12) & GENMASK(19, 12)))
++#define ROCKCHIP_PCIE_EP_VIRT_FUNC_BASE(fn) \
++ (PCIE_EP_PF_CONFIG_REGS_BASE + 0x10000 + (((fn) << 12) & GENMASK(19, 12)))
+ #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
+- (PCIE_RC_RP_ATS_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
++ (PCIE_CORE_AXI_CONF_BASE + 0x0828 + (fn) * 0x0040 + (bar) * 0x0008)
+ #define ROCKCHIP_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
+- (PCIE_RC_RP_ATS_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
++ (PCIE_CORE_AXI_CONF_BASE + 0x082c + (fn) * 0x0040 + (bar) * 0x0008)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
+ (((devfn) << 12) & \
+@@ -248,20 +252,21 @@
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
+ (((bus) << 20) & ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
++#define PCIE_RC_EP_ATR_OB_REGIONS_1_32 (PCIE_CORE_AXI_CONF_BASE + 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0000 + ((r) & 0x1f) * 0x0020)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0004 + ((r) & 0x1f) * 0x0020)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
+ (((devfn) << 24) & ROCKCHIP_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
+ #define ROCKCHIP_PCIE_AT_OB_REGION_DESC0(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
+-#define ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
+- (PCIE_RC_RP_ATS_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0008 + ((r) & 0x1f) * 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_DESC1(r) \
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x000c + ((r) & 0x1f) * 0x0020)
++#define ROCKCHIP_PCIE_AT_OB_REGION_DESC2(r) \
++ (PCIE_RC_EP_ATR_OB_REGIONS_1_32 + 0x0010 + ((r) & 0x1f) * 0x0020)
+
+ #define ROCKCHIP_PCIE_CORE_EP_FUNC_BAR_CFG0(fn) \
+ (PCIE_CORE_CTRL_MGMT_BASE + 0x0240 + (fn) * 0x0008)
+--
+2.39.2
+
--- /dev/null
+From 3c396e7e23569e81b99a721c937a676dc265af4a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Apr 2023 09:46:48 +0200
+Subject: PCI: rockchip: Remove writes to unused registers
+
+From: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+
+[ Upstream commit 92a9c57c325dd51682d428ba960d961fec3c8a08 ]
+
+Remove write accesses to registers that are marked "unused" (and
+therefore read-only) in the technical reference manual (TRM)
+(see RK3399 TRM 17.6.8.1)
+
+Link: https://lore.kernel.org/r/20230418074700.1083505-2-rick.wertenbroek@gmail.com
+Tested-by: Damien Le Moal <dlemoal@kernel.org>
+Signed-off-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
+Signed-off-by: Lorenzo Pieralisi <lpieralisi@kernel.org>
+Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
+Stable-dep-of: dc73ed0f1b8b ("PCI: rockchip: Fix window mapping and address translation for endpoint")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/pcie-rockchip-ep.c | 10 ----------
+ 1 file changed, 10 deletions(-)
+
+diff --git a/drivers/pci/controller/pcie-rockchip-ep.c b/drivers/pci/controller/pcie-rockchip-ep.c
+index 827d91e73efab..9e17f3dba743a 100644
+--- a/drivers/pci/controller/pcie-rockchip-ep.c
++++ b/drivers/pci/controller/pcie-rockchip-ep.c
+@@ -61,10 +61,6 @@ static void rockchip_pcie_clear_ep_ob_atu(struct rockchip_pcie *rockchip,
+ ROCKCHIP_PCIE_AT_OB_REGION_DESC0(region));
+ rockchip_pcie_write(rockchip, 0,
+ ROCKCHIP_PCIE_AT_OB_REGION_DESC1(region));
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(region));
+- rockchip_pcie_write(rockchip, 0,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(region));
+ }
+
+ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+@@ -114,12 +110,6 @@ static void rockchip_pcie_prog_ep_ob_atu(struct rockchip_pcie *rockchip, u8 fn,
+ PCIE_CORE_OB_REGION_ADDR0_LO_ADDR);
+ addr1 = upper_32_bits(cpu_addr);
+ }
+-
+- /* CPU bus address region */
+- rockchip_pcie_write(rockchip, addr0,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR0(r));
+- rockchip_pcie_write(rockchip, addr1,
+- ROCKCHIP_PCIE_AT_OB_REGION_CPU_ADDR1(r));
+ }
+
+ static int rockchip_pcie_ep_write_header(struct pci_epc *epc, u8 fn, u8 vfn,
+--
+2.39.2
+
--- /dev/null
+From d3bef08736704119bf87858580b0a9539083d322 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 24 May 2023 21:48:36 +0200
+Subject: pwm: meson: fix handling of period/duty if greater than UINT_MAX
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Heiner Kallweit <hkallweit1@gmail.com>
+
+[ Upstream commit 87a2cbf02d7701255f9fcca7e5bd864a7bb397cf ]
+
+state->period/duty are of type u64, and if their value is greater than
+UINT_MAX, then the cast to uint will cause problems. Fix this by
+changing the type of the respective local variables to u64.
+
+Fixes: b79c3670e120 ("pwm: meson: Don't duplicate the polarity internally")
+Cc: stable@vger.kernel.org
+Suggested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
+Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-meson.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
+index 37bbad88a3ee5..ec6a544d6f526 100644
+--- a/drivers/pwm/pwm-meson.c
++++ b/drivers/pwm/pwm-meson.c
+@@ -163,8 +163,9 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+ const struct pwm_state *state)
+ {
+ struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+- unsigned int duty, period, pre_div, cnt, duty_cnt;
++ unsigned int pre_div, cnt, duty_cnt;
+ unsigned long fin_freq;
++ u64 duty, period;
+
+ duty = state->duty_cycle;
+ period = state->period;
+@@ -186,19 +187,19 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+
+ dev_dbg(meson->chip.dev, "fin_freq: %lu Hz\n", fin_freq);
+
+- pre_div = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * 0xffffLL);
++ pre_div = div64_u64(fin_freq * period, NSEC_PER_SEC * 0xffffLL);
+ if (pre_div > MISC_CLK_DIV_MASK) {
+ dev_err(meson->chip.dev, "unable to get period pre_div\n");
+ return -EINVAL;
+ }
+
+- cnt = div64_u64(fin_freq * (u64)period, NSEC_PER_SEC * (pre_div + 1));
++ cnt = div64_u64(fin_freq * period, NSEC_PER_SEC * (pre_div + 1));
+ if (cnt > 0xffff) {
+ dev_err(meson->chip.dev, "unable to get period cnt\n");
+ return -EINVAL;
+ }
+
+- dev_dbg(meson->chip.dev, "period=%u pre_div=%u cnt=%u\n", period,
++ dev_dbg(meson->chip.dev, "period=%llu pre_div=%u cnt=%u\n", period,
+ pre_div, cnt);
+
+ if (duty == period) {
+@@ -211,14 +212,13 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+ channel->lo = cnt;
+ } else {
+ /* Then check is we can have the duty with the same pre_div */
+- duty_cnt = div64_u64(fin_freq * (u64)duty,
+- NSEC_PER_SEC * (pre_div + 1));
++ duty_cnt = div64_u64(fin_freq * duty, NSEC_PER_SEC * (pre_div + 1));
+ if (duty_cnt > 0xffff) {
+ dev_err(meson->chip.dev, "unable to get duty cycle\n");
+ return -EINVAL;
+ }
+
+- dev_dbg(meson->chip.dev, "duty=%u pre_div=%u duty_cnt=%u\n",
++ dev_dbg(meson->chip.dev, "duty=%llu pre_div=%u duty_cnt=%u\n",
+ duty, pre_div, duty_cnt);
+
+ channel->pre_div = pre_div;
+--
+2.39.2
+
--- /dev/null
+From ca49b41a11f321f87f3aa9271261b5a23699911d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 8 Nov 2021 14:46:26 +0100
+Subject: pwm: meson: Simplify duplicated per-channel tracking
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 5f97f18feac9bd5a8163b108aee52d783114b36f ]
+
+The driver tracks per-channel data via struct pwm_device::chip_data and
+struct meson_pwm::channels[]. The latter holds the actual data, the former
+is only a pointer to the latter. So simplify by using struct
+meson_pwm::channels[] consistently.
+
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
+Stable-dep-of: 87a2cbf02d77 ("pwm: meson: fix handling of period/duty if greater than UINT_MAX")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pwm/pwm-meson.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
+index 76f702c43cbc3..37bbad88a3ee5 100644
+--- a/drivers/pwm/pwm-meson.c
++++ b/drivers/pwm/pwm-meson.c
+@@ -147,12 +147,13 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+ return err;
+ }
+
+- return pwm_set_chip_data(pwm, channel);
++ return 0;
+ }
+
+ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+ {
+- struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
++ struct meson_pwm *meson = to_meson_pwm(chip);
++ struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+
+ if (channel)
+ clk_disable_unprepare(channel->clk);
+@@ -161,7 +162,7 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+ const struct pwm_state *state)
+ {
+- struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
++ struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+ unsigned int duty, period, pre_div, cnt, duty_cnt;
+ unsigned long fin_freq;
+
+@@ -230,7 +231,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm,
+
+ static void meson_pwm_enable(struct meson_pwm *meson, struct pwm_device *pwm)
+ {
+- struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
++ struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+ struct meson_pwm_channel_data *channel_data;
+ unsigned long flags;
+ u32 value;
+@@ -273,8 +274,8 @@ static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm)
+ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+ {
+- struct meson_pwm_channel *channel = pwm_get_chip_data(pwm);
+ struct meson_pwm *meson = to_meson_pwm(chip);
++ struct meson_pwm_channel *channel = &meson->channels[pwm->hwpwm];
+ int err = 0;
+
+ if (!state)
+--
+2.39.2
+
--- /dev/null
+From 5a71e3f9d94ce54053dfb0cee214a0ac6766835f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jul 2023 23:15:57 +0900
+Subject: Revert "tracing: Add "(fault)" name injection to kernel probes"
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 4ed8f337dee32df71435689c19d22e4ee846e15a ]
+
+This reverts commit 2e9906f84fc7c99388bb7123ade167250d50f1c0.
+
+It was turned out that commit 2e9906f84fc7 ("tracing: Add "(fault)"
+name injection to kernel probes") did not work correctly and probe
+events still show just '(fault)' (instead of '"(fault)"'). Also,
+current '(fault)' is more explicit that it faulted.
+
+This also moves FAULT_STRING macro to trace.h so that synthetic
+event can keep using it, and uses it in trace_probe.c too.
+
+Link: https://lore.kernel.org/all/168908495772.123124.1250788051922100079.stgit@devnote2/
+Link: https://lore.kernel.org/all/20230706230642.3793a593@rorschach.local.home/
+
+Cc: stable@vger.kernel.org
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Tom Zanussi <zanussi@kernel.org>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: 797311bce5c2 ("tracing/probes: Fix to record 0-length data_loc in fetch_store_string*() if fails")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace.h | 2 ++
+ kernel/trace/trace_probe.c | 2 +-
+ kernel/trace/trace_probe_kernel.h | 31 ++++++-------------------------
+ 3 files changed, 9 insertions(+), 26 deletions(-)
+
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 33c55c8826a7e..43058077a4def 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -113,6 +113,8 @@ enum trace_type {
+ #define MEM_FAIL(condition, fmt, ...) \
+ DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__)
+
++#define FAULT_STRING "(fault)"
++
+ #define HIST_STACKTRACE_DEPTH 16
+ #define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
+ #define HIST_STACKTRACE_SKIP 5
+diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
+index 90bae188d0928..0888f0644d257 100644
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -64,7 +64,7 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent)
+ int len = *(u32 *)data >> 16;
+
+ if (!len)
+- trace_seq_puts(s, "(fault)");
++ trace_seq_puts(s, FAULT_STRING);
+ else
+ trace_seq_printf(s, "\"%s\"",
+ (const char *)get_loc_data(data, ent));
+diff --git a/kernel/trace/trace_probe_kernel.h b/kernel/trace/trace_probe_kernel.h
+index 77dbd9ff97826..1d43df29a1f8e 100644
+--- a/kernel/trace/trace_probe_kernel.h
++++ b/kernel/trace/trace_probe_kernel.h
+@@ -2,8 +2,6 @@
+ #ifndef __TRACE_PROBE_KERNEL_H_
+ #define __TRACE_PROBE_KERNEL_H_
+
+-#define FAULT_STRING "(fault)"
+-
+ /*
+ * This depends on trace_probe.h, but can not include it due to
+ * the way trace_probe_tmpl.h is used by trace_kprobe.c and trace_eprobe.c.
+@@ -15,16 +13,8 @@ static nokprobe_inline int
+ kern_fetch_store_strlen_user(unsigned long addr)
+ {
+ const void __user *uaddr = (__force const void __user *)addr;
+- int ret;
+
+- ret = strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
+- /*
+- * strnlen_user_nofault returns zero on fault, insert the
+- * FAULT_STRING when that occurs.
+- */
+- if (ret <= 0)
+- return strlen(FAULT_STRING) + 1;
+- return ret;
++ return strnlen_user_nofault(uaddr, MAX_STRING_SIZE);
+ }
+
+ /* Return the length of string -- including null terminal byte */
+@@ -44,18 +34,7 @@ kern_fetch_store_strlen(unsigned long addr)
+ len++;
+ } while (c && ret == 0 && len < MAX_STRING_SIZE);
+
+- /* For faults, return enough to hold the FAULT_STRING */
+- return (ret < 0) ? strlen(FAULT_STRING) + 1 : len;
+-}
+-
+-static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base, int len)
+-{
+- if (ret >= 0) {
+- *(u32 *)dest = make_data_loc(ret, __dest - base);
+- } else {
+- strscpy(__dest, FAULT_STRING, len);
+- ret = strlen(__dest) + 1;
+- }
++ return (ret < 0) ? ret : len;
+ }
+
+ /*
+@@ -76,7 +55,8 @@ kern_fetch_store_string_user(unsigned long addr, void *dest, void *base)
+ __dest = get_loc_data(dest, base);
+
+ ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
+- set_data_loc(ret, dest, __dest, base, maxlen);
++ if (ret >= 0)
++ *(u32 *)dest = make_data_loc(ret, __dest - base);
+
+ return ret;
+ }
+@@ -107,7 +87,8 @@ kern_fetch_store_string(unsigned long addr, void *dest, void *base)
+ * probing.
+ */
+ ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
+- set_data_loc(ret, dest, __dest, base, maxlen);
++ if (ret >= 0)
++ *(u32 *)dest = make_data_loc(ret, __dest - base);
+
+ return ret;
+ }
+--
+2.39.2
+
--- /dev/null
+From ca965bfd92d47bf2d16a179681e1779d841b71c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 15 Jun 2022 22:35:05 -0700
+Subject: scsi: qla2xxx: Add debug prints in the device remove path
+
+From: Arun Easi <aeasi@marvell.com>
+
+[ Upstream commit f12d2d130efc49464ef0666789bfeb9073162743 ]
+
+Add a debug print in the devloss callback.
+
+Link: https://lore.kernel.org/r/20220616053508.27186-9-njavali@marvell.com
+Signed-off-by: Arun Easi <aeasi@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 9ae615c5bfd3 ("scsi: qla2xxx: Fix hang in task management")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_attr.c | 3 +++
+ drivers/scsi/qla2xxx/qla_def.h | 6 ++++++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
+index de57d45ffc5cb..4a5df867057bc 100644
+--- a/drivers/scsi/qla2xxx/qla_attr.c
++++ b/drivers/scsi/qla2xxx/qla_attr.c
+@@ -2705,6 +2705,9 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
+ if (!fcport)
+ return;
+
++ ql_dbg(ql_dbg_async, fcport->vha, 0x5101,
++ DBG_FCPORT_PRFMT(fcport, "dev_loss_tmo expiry, rport_state=%d",
++ rport->port_state));
+
+ /*
+ * Now that the rport has been deleted, set the fcport state to
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index bbeb116c16cc3..2a2bca2fb57ee 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -5475,4 +5475,10 @@ struct ql_vnd_tgt_stats_resp {
+ #define IS_SESSION_DELETED(_fcport) (_fcport->disc_state == DSC_DELETE_PEND || \
+ _fcport->disc_state == DSC_DELETED)
+
++#define DBG_FCPORT_PRFMT(_fp, _fmt, _args...) \
++ "%s: %8phC: " _fmt " (state=%d disc_state=%d scan_state=%d loopid=0x%x deleted=%d flags=0x%x)\n", \
++ __func__, _fp->port_name, ##_args, atomic_read(&_fp->state), \
++ _fp->disc_state, _fp->scan_state, _fp->loop_id, _fp->deleted, \
++ _fp->flags
++
+ #endif
+--
+2.39.2
+
--- /dev/null
+From 92c8ae8a606aee9eeeb8e31aa58d646a6665bbfb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:36 -0700
+Subject: scsi: qla2xxx: Fix hang in task management
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 9ae615c5bfd37bd091772969b1153de5335ea986 ]
+
+Task management command hangs where a side
+band chip reset failed to nudge the TMF
+from it's current send path.
+
+Add additional error check to block TMF
+from entering during chip reset and along
+the TMF path to cause it to bail out, skip
+over abort of marker.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-5-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h | 4 +++
+ drivers/scsi/qla2xxx/qla_init.c | 60 +++++++++++++++++++++++++++++++--
+ 2 files changed, 61 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index 2a2bca2fb57ee..83228ce822af3 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -5481,4 +5481,8 @@ struct ql_vnd_tgt_stats_resp {
+ _fp->disc_state, _fp->scan_state, _fp->loop_id, _fp->deleted, \
+ _fp->flags
+
++#define TMF_NOT_READY(_fcport) \
++ (!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \
++ !_fcport->vha->hw->flags.fw_started)
++
+ #endif
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 2c42ecb2a64a5..a97872b6350ca 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -1998,6 +1998,11 @@ qla2x00_tmf_iocb_timeout(void *data)
+ int rc, h;
+ unsigned long flags;
+
++ if (sp->type == SRB_MARKER) {
++ complete(&tmf->u.tmf.comp);
++ return;
++ }
++
+ rc = qla24xx_async_abort_cmd(sp, false);
+ if (rc) {
+ spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
+@@ -2025,6 +2030,7 @@ static void qla_marker_sp_done(srb_t *sp, int res)
+ sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags,
+ sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id);
+
++ sp->u.iocb_cmd.u.tmf.data = res;
+ complete(&tmf->u.tmf.comp);
+ }
+
+@@ -2041,6 +2047,11 @@ static void qla_marker_sp_done(srb_t *sp, int res)
+ } while (cnt); \
+ }
+
++/**
++ * qla26xx_marker: send marker IOCB and wait for the completion of it.
++ * @arg: pointer to argument list.
++ * It is assume caller will provide an fcport pointer and modifier
++ */
+ static int
+ qla26xx_marker(struct tmf_arg *arg)
+ {
+@@ -2050,6 +2061,14 @@ qla26xx_marker(struct tmf_arg *arg)
+ int rval = QLA_FUNCTION_FAILED;
+ fc_port_t *fcport = arg->fcport;
+
++ if (TMF_NOT_READY(arg->fcport)) {
++ ql_dbg(ql_dbg_taskm, vha, 0x8039,
++ "FC port not ready for marker loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
++ fcport->loop_id, fcport->d_id.b24,
++ arg->modifier, arg->lun, arg->qpair->id);
++ return QLA_SUSPENDED;
++ }
++
+ /* ref: INIT */
+ sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
+ if (!sp)
+@@ -2076,11 +2095,19 @@ qla26xx_marker(struct tmf_arg *arg)
+
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0x8031,
+- "Marker IOCB failed (%x).\n", rval);
++ "Marker IOCB send failure (%x).\n", rval);
+ goto done_free_sp;
+ }
+
+ wait_for_completion(&tm_iocb->u.tmf.comp);
++ rval = tm_iocb->u.tmf.data;
++
++ if (rval != QLA_SUCCESS) {
++ ql_log(ql_log_warn, vha, 0x8019,
++ "Marker failed hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
++ sp->handle, fcport->loop_id, fcport->d_id.b24,
++ arg->modifier, arg->lun, sp->qpair->id, rval);
++ }
+
+ done_free_sp:
+ /* ref: INIT */
+@@ -2093,6 +2120,8 @@ static void qla2x00_tmf_sp_done(srb_t *sp, int res)
+ {
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+
++ if (res)
++ tmf->u.tmf.data = res;
+ complete(&tmf->u.tmf.comp);
+ }
+
+@@ -2106,6 +2135,14 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+
+ fc_port_t *fcport = arg->fcport;
+
++ if (TMF_NOT_READY(arg->fcport)) {
++ ql_dbg(ql_dbg_taskm, vha, 0x8032,
++ "FC port not ready for TM command loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
++ fcport->loop_id, fcport->d_id.b24,
++ arg->modifier, arg->lun, arg->qpair->id);
++ return QLA_SUSPENDED;
++ }
++
+ /* ref: INIT */
+ sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
+ if (!sp)
+@@ -2180,7 +2217,9 @@ int qla_get_tmf(fc_port_t *fcport)
+ msleep(1);
+
+ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+- if (fcport->deleted) {
++ if (TMF_NOT_READY(fcport)) {
++ ql_log(ql_log_warn, vha, 0x802c,
++ "Unable to acquire TM resource due to disruption.\n");
+ rc = EIO;
+ break;
+ }
+@@ -2206,7 +2245,10 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_qpair *qpair;
+ struct tmf_arg a;
+- int i, rval;
++ int i, rval = QLA_SUCCESS;
++
++ if (TMF_NOT_READY(fcport))
++ return QLA_SUSPENDED;
+
+ a.vha = fcport->vha;
+ a.fcport = fcport;
+@@ -2225,6 +2267,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+ qpair = vha->hw->queue_pair_map[i];
+ if (!qpair)
+ continue;
++
++ if (TMF_NOT_READY(fcport)) {
++ ql_log(ql_log_warn, vha, 0x8026,
++ "Unable to send TM due to disruption.\n");
++ rval = QLA_SUSPENDED;
++ break;
++ }
++
+ a.qpair = qpair;
+ a.flags = flags|TCF_NOTMCMD_TO_TARGET;
+ rval = __qla2x00_async_tm_cmd(&a);
+@@ -2233,10 +2283,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+ }
+ }
+
++ if (rval)
++ goto bailout;
++
+ a.qpair = vha->hw->base_qpair;
+ a.flags = flags;
+ rval = __qla2x00_async_tm_cmd(&a);
+
++bailout:
+ if (a.modifier == MK_SYNC_ID_LUN)
+ qla_put_tmf(fcport);
+
+--
+2.39.2
+
--- /dev/null
+From cc2d6f72c6b995159aecc843410b558cf9f36ee8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:35 -0700
+Subject: scsi: qla2xxx: Fix task management cmd fail due to unavailable
+ resource
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 6a87679626b51b53fbb6be417ad8eb083030b617 ]
+
+Task management command failed with status 2Ch which is
+a result of too many task management commands sent
+to the same target. Hence limit task management commands
+to 8 per target.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Link: https://lore.kernel.org/oe-kbuild-all/202304271952.NKNmoFzv-lkp@intel.com/
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-4-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h | 3 ++
+ drivers/scsi/qla2xxx/qla_init.c | 63 ++++++++++++++++++++++++++++++---
+ 2 files changed, 61 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index ca63aa8f33b5d..bbeb116c16cc3 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -2523,6 +2523,7 @@ enum rscn_addr_format {
+ typedef struct fc_port {
+ struct list_head list;
+ struct scsi_qla_host *vha;
++ struct list_head tmf_pending;
+
+ unsigned int conf_compl_supported:1;
+ unsigned int deleted:2;
+@@ -2543,6 +2544,8 @@ typedef struct fc_port {
+ unsigned int do_prli_nvme:1;
+
+ uint8_t nvme_flag;
++ uint8_t active_tmf;
++#define MAX_ACTIVE_TMF 8
+
+ uint8_t node_name[WWN_SIZE];
+ uint8_t port_name[WWN_SIZE];
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 9d9b16f7f34a6..2c42ecb2a64a5 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -2151,6 +2151,54 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+ return rval;
+ }
+
++static void qla_put_tmf(fc_port_t *fcport)
++{
++ struct scsi_qla_host *vha = fcport->vha;
++ struct qla_hw_data *ha = vha->hw;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
++ fcport->active_tmf--;
++ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
++}
++
++static
++int qla_get_tmf(fc_port_t *fcport)
++{
++ struct scsi_qla_host *vha = fcport->vha;
++ struct qla_hw_data *ha = vha->hw;
++ unsigned long flags;
++ int rc = 0;
++ LIST_HEAD(tmf_elem);
++
++ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
++ list_add_tail(&tmf_elem, &fcport->tmf_pending);
++
++ while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
++ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
++
++ msleep(1);
++
++ spin_lock_irqsave(&ha->tgt.sess_lock, flags);
++ if (fcport->deleted) {
++ rc = EIO;
++ break;
++ }
++ if (fcport->active_tmf < MAX_ACTIVE_TMF &&
++ list_is_first(&tmf_elem, &fcport->tmf_pending))
++ break;
++ }
++
++ list_del(&tmf_elem);
++
++ if (!rc)
++ fcport->active_tmf++;
++
++ spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
++
++ return rc;
++}
++
+ int
+ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+ uint32_t tag)
+@@ -2158,18 +2206,19 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+ struct scsi_qla_host *vha = fcport->vha;
+ struct qla_qpair *qpair;
+ struct tmf_arg a;
+- struct completion comp;
+ int i, rval;
+
+- init_completion(&comp);
+ a.vha = fcport->vha;
+ a.fcport = fcport;
+ a.lun = lun;
+-
+- if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
++ if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
+ a.modifier = MK_SYNC_ID_LUN;
+- else
++
++ if (qla_get_tmf(fcport))
++ return QLA_FUNCTION_FAILED;
++ } else {
+ a.modifier = MK_SYNC_ID;
++ }
+
+ if (vha->hw->mqenable) {
+ for (i = 0; i < vha->hw->num_qpairs; i++) {
+@@ -2188,6 +2237,9 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+ a.flags = flags;
+ rval = __qla2x00_async_tm_cmd(&a);
+
++ if (a.modifier == MK_SYNC_ID_LUN)
++ qla_put_tmf(fcport);
++
+ return rval;
+ }
+
+@@ -5423,6 +5475,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
+ INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
+ INIT_LIST_HEAD(&fcport->gnl_entry);
+ INIT_LIST_HEAD(&fcport->list);
++ INIT_LIST_HEAD(&fcport->tmf_pending);
+
+ INIT_LIST_HEAD(&fcport->sess_cmd_list);
+ spin_lock_init(&fcport->sess_cmd_lock);
+--
+2.39.2
+
--- /dev/null
+From 2f94cf7340cc56172560a73a72eb3964522f88e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:34 -0700
+Subject: scsi: qla2xxx: Fix task management cmd failure
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit 9803fb5d27597ea98f2e05b0b6cfc48ae808458e ]
+
+Task management cmd failed with status 30h which means
+FW is not able to finish processing one task management
+before another task management for the same lun.
+Hence add wait for completion of marker to space it out.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Link: https://lore.kernel.org/oe-kbuild-all/202304271802.uCZfwQC1-lkp@intel.com/
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-3-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com <mailto:himanshu.madhani@oracle.com>>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h | 6 ++
+ drivers/scsi/qla2xxx/qla_init.c | 102 +++++++++++++++++++++++++++-----
+ drivers/scsi/qla2xxx/qla_iocb.c | 28 +++++++--
+ drivers/scsi/qla2xxx/qla_isr.c | 26 +++++++-
+ 4 files changed, 139 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index d4b8d9dd8106d..ca63aa8f33b5d 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -458,6 +458,7 @@ struct tmf_arg {
+ struct scsi_qla_host *vha;
+ u64 lun;
+ u32 flags;
++ uint8_t modifier;
+ };
+
+ struct els_logo_payload {
+@@ -539,6 +540,10 @@ struct srb_iocb {
+ uint32_t data;
+ struct completion comp;
+ __le16 comp_status;
++
++ uint8_t modifier;
++ uint8_t vp_index;
++ uint16_t loop_id;
+ } tmf;
+ struct {
+ #define SRB_FXDISC_REQ_DMA_VALID BIT_0
+@@ -642,6 +647,7 @@ struct srb_iocb {
+ #define SRB_SA_UPDATE 25
+ #define SRB_ELS_CMD_HST_NOLOGIN 26
+ #define SRB_SA_REPLACE 27
++#define SRB_MARKER 28
+
+ struct qla_els_pt_arg {
+ u8 els_opcode;
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index f64c238e3a45b..9d9b16f7f34a6 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -2015,6 +2015,80 @@ qla2x00_tmf_iocb_timeout(void *data)
+ }
+ }
+
++static void qla_marker_sp_done(srb_t *sp, int res)
++{
++ struct srb_iocb *tmf = &sp->u.iocb_cmd;
++
++ if (res != QLA_SUCCESS)
++ ql_dbg(ql_dbg_taskm, sp->vha, 0x8004,
++ "Async-marker fail hdl=%x portid=%06x ctrl=%x lun=%lld qp=%d.\n",
++ sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags,
++ sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id);
++
++ complete(&tmf->u.tmf.comp);
++}
++
++#define START_SP_W_RETRIES(_sp, _rval) \
++{\
++ int cnt = 5; \
++ do { \
++ _rval = qla2x00_start_sp(_sp); \
++ if (_rval == EAGAIN) \
++ msleep(1); \
++ else \
++ break; \
++ cnt--; \
++ } while (cnt); \
++}
++
++static int
++qla26xx_marker(struct tmf_arg *arg)
++{
++ struct scsi_qla_host *vha = arg->vha;
++ struct srb_iocb *tm_iocb;
++ srb_t *sp;
++ int rval = QLA_FUNCTION_FAILED;
++ fc_port_t *fcport = arg->fcport;
++
++ /* ref: INIT */
++ sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
++ if (!sp)
++ goto done;
++
++ sp->type = SRB_MARKER;
++ sp->name = "marker";
++ qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), qla_marker_sp_done);
++ sp->u.iocb_cmd.timeout = qla2x00_tmf_iocb_timeout;
++
++ tm_iocb = &sp->u.iocb_cmd;
++ init_completion(&tm_iocb->u.tmf.comp);
++ tm_iocb->u.tmf.modifier = arg->modifier;
++ tm_iocb->u.tmf.lun = arg->lun;
++ tm_iocb->u.tmf.loop_id = fcport->loop_id;
++ tm_iocb->u.tmf.vp_index = vha->vp_idx;
++
++ START_SP_W_RETRIES(sp, rval);
++
++ ql_dbg(ql_dbg_taskm, vha, 0x8006,
++ "Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
++ sp->handle, fcport->loop_id, fcport->d_id.b24,
++ arg->modifier, arg->lun, sp->qpair->id, rval);
++
++ if (rval != QLA_SUCCESS) {
++ ql_log(ql_log_warn, vha, 0x8031,
++ "Marker IOCB failed (%x).\n", rval);
++ goto done_free_sp;
++ }
++
++ wait_for_completion(&tm_iocb->u.tmf.comp);
++
++done_free_sp:
++ /* ref: INIT */
++ kref_put(&sp->cmd_kref, qla2x00_sp_release);
++done:
++ return rval;
++}
++
+ static void qla2x00_tmf_sp_done(srb_t *sp, int res)
+ {
+ struct srb_iocb *tmf = &sp->u.iocb_cmd;
+@@ -2028,7 +2102,6 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+ struct scsi_qla_host *vha = arg->vha;
+ struct srb_iocb *tm_iocb;
+ srb_t *sp;
+- unsigned long flags;
+ int rval = QLA_FUNCTION_FAILED;
+
+ fc_port_t *fcport = arg->fcport;
+@@ -2050,11 +2123,12 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+ tm_iocb->u.tmf.flags = arg->flags;
+ tm_iocb->u.tmf.lun = arg->lun;
+
+- rval = qla2x00_start_sp(sp);
++ START_SP_W_RETRIES(sp, rval);
++
+ ql_dbg(ql_dbg_taskm, vha, 0x802f,
+- "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x ctrl=%x.\n",
+- sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+- fcport->d_id.b.area, fcport->d_id.b.al_pa, arg->flags);
++ "Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n",
++ sp->handle, fcport->loop_id, fcport->d_id.b24,
++ arg->flags, arg->lun, sp->qpair->id, rval);
+
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+@@ -2067,17 +2141,8 @@ __qla2x00_async_tm_cmd(struct tmf_arg *arg)
+ "TM IOCB failed (%x).\n", rval);
+ }
+
+- if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
+- flags = tm_iocb->u.tmf.flags;
+- if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|
+- TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
+- flags = MK_SYNC_ID_LUN;
+- else
+- flags = MK_SYNC_ID;
+-
+- qla2x00_marker(vha, sp->qpair,
+- sp->fcport->loop_id, arg->lun, flags);
+- }
++ if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw))
++ rval = qla26xx_marker(arg);
+
+ done_free_sp:
+ /* ref: INIT */
+@@ -2101,6 +2166,11 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+ a.fcport = fcport;
+ a.lun = lun;
+
++ if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
++ a.modifier = MK_SYNC_ID_LUN;
++ else
++ a.modifier = MK_SYNC_ID;
++
+ if (vha->hw->mqenable) {
+ for (i = 0; i < vha->hw->num_qpairs; i++) {
+ qpair = vha->hw->queue_pair_map[i];
+diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
+index ac82392c22eed..c9a686f06d29d 100644
+--- a/drivers/scsi/qla2xxx/qla_iocb.c
++++ b/drivers/scsi/qla2xxx/qla_iocb.c
+@@ -522,21 +522,25 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair,
+ return (QLA_FUNCTION_FAILED);
+ }
+
++ mrk24 = (struct mrk_entry_24xx *)mrk;
++
+ mrk->entry_type = MARKER_TYPE;
+ mrk->modifier = type;
+ if (type != MK_SYNC_ALL) {
+ if (IS_FWI2_CAPABLE(ha)) {
+- mrk24 = (struct mrk_entry_24xx *) mrk;
+ mrk24->nport_handle = cpu_to_le16(loop_id);
+ int_to_scsilun(lun, (struct scsi_lun *)&mrk24->lun);
+ host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
+ mrk24->vp_index = vha->vp_idx;
+- mrk24->handle = make_handle(req->id, mrk24->handle);
+ } else {
+ SET_TARGET_ID(ha, mrk->target, loop_id);
+ mrk->lun = cpu_to_le16((uint16_t)lun);
+ }
+ }
++
++ if (IS_FWI2_CAPABLE(ha))
++ mrk24->handle = QLA_SKIP_HANDLE;
++
+ wmb();
+
+ qla2x00_start_iocbs(vha, req);
+@@ -3860,9 +3864,9 @@ int qla_get_iocbs_resource(struct srb *sp)
+ case SRB_NACK_LOGO:
+ case SRB_LOGOUT_CMD:
+ case SRB_CTRL_VP:
+- push_it_through = true;
+- fallthrough;
++ case SRB_MARKER:
+ default:
++ push_it_through = true;
+ get_exch = false;
+ }
+
+@@ -3878,6 +3882,19 @@ int qla_get_iocbs_resource(struct srb *sp)
+ return qla_get_fw_resources(sp->qpair, &sp->iores);
+ }
+
++static void
++qla_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
++{
++ mrk->entry_type = MARKER_TYPE;
++ mrk->modifier = sp->u.iocb_cmd.u.tmf.modifier;
++ if (sp->u.iocb_cmd.u.tmf.modifier != MK_SYNC_ALL) {
++ mrk->nport_handle = cpu_to_le16(sp->u.iocb_cmd.u.tmf.loop_id);
++ int_to_scsilun(sp->u.iocb_cmd.u.tmf.lun, (struct scsi_lun *)&mrk->lun);
++ host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
++ mrk->vp_index = sp->u.iocb_cmd.u.tmf.vp_index;
++ }
++}
++
+ int
+ qla2x00_start_sp(srb_t *sp)
+ {
+@@ -3981,6 +3998,9 @@ qla2x00_start_sp(srb_t *sp)
+ case SRB_SA_REPLACE:
+ qla24xx_sa_replace_iocb(sp, pkt);
+ break;
++ case SRB_MARKER:
++ qla_marker_iocb(sp, pkt);
++ break;
+ default:
+ break;
+ }
+diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
+index 665959938e5e3..08d43f43995ef 100644
+--- a/drivers/scsi/qla2xxx/qla_isr.c
++++ b/drivers/scsi/qla2xxx/qla_isr.c
+@@ -3737,6 +3737,28 @@ static int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha,
+ return rc;
+ }
+
++static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
++ struct mrk_entry_24xx *pkt)
++{
++ const char func[] = "MRK-IOCB";
++ srb_t *sp;
++ int res = QLA_SUCCESS;
++
++ if (!IS_FWI2_CAPABLE(vha->hw))
++ return;
++
++ sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
++ if (!sp)
++ return;
++
++ if (pkt->entry_status) {
++ ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n");
++ res = QLA_COMMAND_ERROR;
++ }
++ sp->u.iocb_cmd.u.tmf.data = res;
++ sp->done(sp, res);
++}
++
+ /**
+ * qla24xx_process_response_queue() - Process response queue entries.
+ * @vha: SCSI driver HA context
+@@ -3858,9 +3880,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
+ (struct nack_to_isp *)pkt);
+ break;
+ case MARKER_TYPE:
+- /* Do nothing in this case, this check is to prevent it
+- * from falling into default case
+- */
++ qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt);
+ break;
+ case ABORT_IOCB_TYPE:
+ qla24xx_abort_iocb_entry(vha, rsp->req,
+--
+2.39.2
+
--- /dev/null
+From 7a5ff7d37980768885f42d099c91a9a258a920fd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Apr 2023 00:53:33 -0700
+Subject: scsi: qla2xxx: Multi-que support for TMF
+
+From: Quinn Tran <qutran@marvell.com>
+
+[ Upstream commit d90171dd0da50212f5950cc708240831e82f2f91 ]
+
+Add queue flush for task management command, before
+placing it on the wire.
+Do IO flush for all Request Q's.
+
+Reported-by: kernel test robot <lkp@intel.com>
+Link: https://lore.kernel.org/oe-kbuild-all/202304271702.GpIL391S-lkp@intel.com/
+Cc: stable@vger.kernel.org
+Signed-off-by: Quinn Tran <qutran@marvell.com>
+Signed-off-by: Nilesh Javali <njavali@marvell.com>
+Link: https://lore.kernel.org/r/20230428075339.32551-2-njavali@marvell.com
+Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com <mailto:himanshu.madhani@oracle.com>>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_def.h | 8 ++++
+ drivers/scsi/qla2xxx/qla_gbl.h | 2 +-
+ drivers/scsi/qla2xxx/qla_init.c | 69 ++++++++++++++++++++++++++-------
+ drivers/scsi/qla2xxx/qla_iocb.c | 5 ++-
+ 4 files changed, 66 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
+index e674d3fb59269..d4b8d9dd8106d 100644
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -452,6 +452,14 @@ static inline be_id_t port_id_to_be_id(port_id_t port_id)
+ return res;
+ }
+
++struct tmf_arg {
++ struct qla_qpair *qpair;
++ struct fc_port *fcport;
++ struct scsi_qla_host *vha;
++ u64 lun;
++ u32 flags;
++};
++
+ struct els_logo_payload {
+ uint8_t opcode;
+ uint8_t rsvd[3];
+diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
+index 4ed0777cd2a6f..9e467262c0f17 100644
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -69,7 +69,7 @@ extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
+ extern int qla2x00_async_prlo(struct scsi_qla_host *, fc_port_t *);
+ extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
+ uint16_t *);
+-extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
++extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint64_t, uint32_t);
+ struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
+ enum qla_work_type);
+ extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
+diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
+index 37cb469dc9257..f64c238e3a45b 100644
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -2022,17 +2022,19 @@ static void qla2x00_tmf_sp_done(srb_t *sp, int res)
+ complete(&tmf->u.tmf.comp);
+ }
+
+-int
+-qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+- uint32_t tag)
++static int
++__qla2x00_async_tm_cmd(struct tmf_arg *arg)
+ {
+- struct scsi_qla_host *vha = fcport->vha;
++ struct scsi_qla_host *vha = arg->vha;
+ struct srb_iocb *tm_iocb;
+ srb_t *sp;
++ unsigned long flags;
+ int rval = QLA_FUNCTION_FAILED;
+
++ fc_port_t *fcport = arg->fcport;
++
+ /* ref: INIT */
+- sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
++ sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+@@ -2045,15 +2047,15 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+
+ tm_iocb = &sp->u.iocb_cmd;
+ init_completion(&tm_iocb->u.tmf.comp);
+- tm_iocb->u.tmf.flags = flags;
+- tm_iocb->u.tmf.lun = lun;
++ tm_iocb->u.tmf.flags = arg->flags;
++ tm_iocb->u.tmf.lun = arg->lun;
+
++ rval = qla2x00_start_sp(sp);
+ ql_dbg(ql_dbg_taskm, vha, 0x802f,
+- "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n",
++ "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x ctrl=%x.\n",
+ sp->handle, fcport->loop_id, fcport->d_id.b.domain,
+- fcport->d_id.b.area, fcport->d_id.b.al_pa);
++ fcport->d_id.b.area, fcport->d_id.b.al_pa, arg->flags);
+
+- rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS)
+ goto done_free_sp;
+ wait_for_completion(&tm_iocb->u.tmf.comp);
+@@ -2067,12 +2069,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+
+ if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
+ flags = tm_iocb->u.tmf.flags;
+- lun = (uint16_t)tm_iocb->u.tmf.lun;
++ if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|
++ TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA))
++ flags = MK_SYNC_ID_LUN;
++ else
++ flags = MK_SYNC_ID;
+
+- /* Issue Marker IOCB */
+- qla2x00_marker(vha, vha->hw->base_qpair,
+- fcport->loop_id, lun,
+- flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
++ qla2x00_marker(vha, sp->qpair,
++ sp->fcport->loop_id, arg->lun, flags);
+ }
+
+ done_free_sp:
+@@ -2082,6 +2086,41 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+ return rval;
+ }
+
++int
++qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
++ uint32_t tag)
++{
++ struct scsi_qla_host *vha = fcport->vha;
++ struct qla_qpair *qpair;
++ struct tmf_arg a;
++ struct completion comp;
++ int i, rval;
++
++ init_completion(&comp);
++ a.vha = fcport->vha;
++ a.fcport = fcport;
++ a.lun = lun;
++
++ if (vha->hw->mqenable) {
++ for (i = 0; i < vha->hw->num_qpairs; i++) {
++ qpair = vha->hw->queue_pair_map[i];
++ if (!qpair)
++ continue;
++ a.qpair = qpair;
++ a.flags = flags|TCF_NOTMCMD_TO_TARGET;
++ rval = __qla2x00_async_tm_cmd(&a);
++ if (rval)
++ break;
++ }
++ }
++
++ a.qpair = vha->hw->base_qpair;
++ a.flags = flags;
++ rval = __qla2x00_async_tm_cmd(&a);
++
++ return rval;
++}
++
+ int
+ qla24xx_async_abort_command(srb_t *sp)
+ {
+diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
+index 7a4298388ef1d..ac82392c22eed 100644
+--- a/drivers/scsi/qla2xxx/qla_iocb.c
++++ b/drivers/scsi/qla2xxx/qla_iocb.c
+@@ -2542,7 +2542,7 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
+ scsi_qla_host_t *vha = fcport->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct srb_iocb *iocb = &sp->u.iocb_cmd;
+- struct req_que *req = vha->req;
++ struct req_que *req = sp->qpair->req;
+
+ flags = iocb->u.tmf.flags;
+ lun = iocb->u.tmf.lun;
+@@ -2558,7 +2558,8 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
+ tsk->port_id[2] = fcport->d_id.b.domain;
+ tsk->vp_index = fcport->vha->vp_idx;
+
+- if (flags == TCF_LUN_RESET) {
++ if (flags & (TCF_LUN_RESET | TCF_ABORT_TASK_SET|
++ TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
+ int_to_scsilun(lun, &tsk->lun);
+ host_to_fcp_swap((uint8_t *)&tsk->lun,
+ sizeof(tsk->lun));
+--
+2.39.2
+
--- /dev/null
+From 13832700de34ab55520788122d5f1451b2dc51a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 13 Sep 2022 10:37:21 +0800
+Subject: scsi: qla2xxx: Remove unused declarations for qla2xxx
+
+From: Gaosheng Cui <cuigaosheng1@huawei.com>
+
+[ Upstream commit 1b80addaae099dc33e683d971aba90eeeaf887a3 ]
+
+qla2x00_get_fw_version_str() has been removed since commit abbd8870b9cb
+("[SCSI] qla2xxx: Factor-out ISP specific functions to method-based call
+tables.").
+
+qla2x00_release_nvram_protection() has been removed since commit
+459c537807bd ("[SCSI] qla2xxx: Add ISP24xx flash-manipulation routines.").
+
+qla82xx_rdmem() and qla82xx_wrmem() have been removed since commit
+3711333dfbee ("[SCSI] qla2xxx: Updates for ISP82xx.").
+
+qla25xx_rd_req_reg(), qla24xx_rd_req_reg(), qla25xx_wrt_rsp_reg(),
+qla24xx_wrt_rsp_reg(), qla25xx_wrt_req_reg() and qla24xx_wrt_req_reg() have
+been removed since commit 08029990b25b ("[SCSI] qla2xxx: Refactor
+request/response-queue register handling.").
+
+qla2x00_async_login_done() has been removed since commit 726b85487067
+("qla2xxx: Add framework for async fabric discovery").
+
+qlt_24xx_process_response_error() has been removed since commit
+c5419e2618b9 ("scsi: qla2xxx: Combine Active command arrays.").
+
+Remove the declarations for them from header file.
+
+Link: https://lore.kernel.org/r/20220913023722.547249-2-cuigaosheng1@huawei.com
+Signed-off-by: Gaosheng Cui <cuigaosheng1@huawei.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Stable-dep-of: 6a87679626b5 ("scsi: qla2xxx: Fix task management cmd fail due to unavailable resource")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/qla2xxx/qla_gbl.h | 12 ------------
+ drivers/scsi/qla2xxx/qla_target.h | 2 --
+ 2 files changed, 14 deletions(-)
+
+diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
+index f82e4a348330a..4ed0777cd2a6f 100644
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -70,8 +70,6 @@ extern int qla2x00_async_prlo(struct scsi_qla_host *, fc_port_t *);
+ extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
+ uint16_t *);
+ extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
+-extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
+- uint16_t *);
+ struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *,
+ enum qla_work_type);
+ extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *);
+@@ -278,7 +276,6 @@ extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
+ extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *);
+
+ extern void qla2x00_sp_free_dma(srb_t *sp);
+-extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
+
+ extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int);
+ extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *);
+@@ -611,7 +608,6 @@ void __qla_consume_iocb(struct scsi_qla_host *vha, void **pkt, struct rsp_que **
+ /*
+ * Global Function Prototypes in qla_sup.c source file.
+ */
+-extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
+ extern int qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *,
+ uint32_t, uint32_t);
+ extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, void *, uint32_t,
+@@ -781,12 +777,6 @@ extern void qla2x00_init_response_q_entries(struct rsp_que *);
+ extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *);
+ extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *);
+ extern int qla25xx_delete_queues(struct scsi_qla_host *);
+-extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t);
+-extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t);
+-extern void qla24xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
+-extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t);
+-extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+-extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t);
+
+ /* qlafx00 related functions */
+ extern int qlafx00_pci_config(struct scsi_qla_host *);
+@@ -871,8 +861,6 @@ extern void qla82xx_init_flags(struct qla_hw_data *);
+ extern void qla82xx_set_drv_active(scsi_qla_host_t *);
+ extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32);
+ extern int qla82xx_rd_32(struct qla_hw_data *, ulong);
+-extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int);
+-extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int);
+
+ /* ISP 8021 IDC */
+ extern void qla82xx_clear_drv_active(struct qla_hw_data *);
+diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
+index 156b950ca7e72..aa83434448377 100644
+--- a/drivers/scsi/qla2xxx/qla_target.h
++++ b/drivers/scsi/qla2xxx/qla_target.h
+@@ -1080,8 +1080,6 @@ extern void qlt_81xx_config_nvram_stage2(struct scsi_qla_host *,
+ struct init_cb_81xx *);
+ extern void qlt_81xx_config_nvram_stage1(struct scsi_qla_host *,
+ struct nvram_81xx *);
+-extern int qlt_24xx_process_response_error(struct scsi_qla_host *,
+- struct sts_entry_24xx *);
+ extern void qlt_modify_vp_config(struct scsi_qla_host *,
+ struct vp_config_entry_24xx *);
+ extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
+--
+2.39.2
+
+jbd2-fix-wrongly-judgement-for-buffer-head-removing-.patch
+kvm-s390-pv-fix-index-value-of-replaced-asce.patch
+io_uring-don-t-audit-the-capability-check-in-io_urin.patch
+gpio-tps68470-make-tps68470_gpio_output-always-set-t.patch
+gpio-mvebu-make-use-of-devm_pwmchip_add.patch
+gpio-mvebu-fix-irq-domain-leak.patch
+btrfs-fix-race-between-quota-disable-and-relocation.patch
+i2c-delete-error-messages-for-failed-memory-allocati.patch
+i2c-improve-size-determinations.patch
+i2c-nomadik-remove-unnecessary-goto-label.patch
+i2c-nomadik-use-devm_clk_get_enabled.patch
+i2c-nomadik-remove-a-useless-call-in-the-remove-func.patch
+pci-aspm-return-0-or-etimedout-from-pcie_retrain_lin.patch
+pci-aspm-factor-out-pcie_wait_for_retrain.patch
+pci-aspm-avoid-link-retraining-race.patch
+pci-rockchip-remove-writes-to-unused-registers.patch
+pci-rockchip-fix-window-mapping-and-address-translat.patch
+pci-rockchip-don-t-advertise-msi-x-in-pcie-capabilit.patch
+dlm-cleanup-plock_op-vs-plock_xop.patch
+dlm-rearrange-async-condition-return.patch
+fs-dlm-interrupt-posix-locks-only-when-process-is-ki.patch
+drm-ttm-don-t-print-error-message-if-eviction-was-in.patch
+drm-ttm-don-t-leak-a-resource-on-eviction-error.patch
+n_tty-rename-tail-to-old_tail-in-n_tty_read.patch
+tty-fix-hang-on-tty-device-with-no_room-set.patch
+drm-ttm-never-consider-pinned-bos-for-eviction-swap.patch
+cifs-missing-directory-in-maintainers-file.patch
+cifs-use-fs_context-for-automounts.patch
+ksmbd-remove-internal.h-include.patch
+cifs-if-deferred-close-is-disabled-then-close-files-.patch
+pwm-meson-simplify-duplicated-per-channel-tracking.patch
+pwm-meson-fix-handling-of-period-duty-if-greater-tha.patch
+tracing-probes-add-symstr-type-for-dynamic-events.patch
+tracing-probes-fix-to-avoid-double-count-of-the-stri.patch
+tracing-allow-synthetic-events-to-pass-around-stackt.patch
+revert-tracing-add-fault-name-injection-to-kernel-pr.patch
+tracing-probes-fix-to-record-0-length-data_loc-in-fe.patch
+scsi-qla2xxx-remove-unused-declarations-for-qla2xxx.patch
+scsi-qla2xxx-multi-que-support-for-tmf.patch
+scsi-qla2xxx-fix-task-management-cmd-failure.patch
+scsi-qla2xxx-fix-task-management-cmd-fail-due-to-una.patch
+scsi-qla2xxx-add-debug-prints-in-the-device-remove-p.patch
+scsi-qla2xxx-fix-hang-in-task-management.patch
+drm-amdgpu-fix-vkms-crtc-settings.patch
+drm-amdgpu-vkms-relax-timer-deactivation-by-hrtimer_.patch
+jbd2-remove-t_checkpoint_io_list.patch
+jbd2-remove-journal_clean_one_cp_list.patch
+jbd2-fix-a-race-when-checking-checkpoint-buffer-busy.patch
--- /dev/null
+From e79460fddac99eb405ecd2ce0c248072680cbd60 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jan 2023 10:21:28 -0500
+Subject: tracing: Allow synthetic events to pass around stacktraces
+
+From: Steven Rostedt (Google) <rostedt@goodmis.org>
+
+[ Upstream commit 00cf3d672a9dd409418647e9f98784c339c3ff63 ]
+
+Allow a stacktrace from one event to be displayed by the end event of a
+synthetic event. This is very useful when looking for the longest latency
+of a sleep or something blocked on I/O.
+
+ # cd /sys/kernel/tracing/
+ # echo 's:block_lat pid_t pid; u64 delta; unsigned long[] stack;' > dynamic_events
+ # echo 'hist:keys=next_pid:ts=common_timestamp.usecs,st=stacktrace if prev_state == 1||prev_state == 2' > events/sched/sched_switch/trigger
+ # echo 'hist:keys=prev_pid:delta=common_timestamp.usecs-$ts,s=$st:onmax($delta).trace(block_lat,prev_pid,$delta,$s)' >> events/sched/sched_switch/trigger
+
+The above creates a "block_lat" synthetic event that take the stacktrace of
+when a task schedules out in either the interruptible or uninterruptible
+states, and on a new per process max $delta (the time it was scheduled
+out), will print the process id and the stacktrace.
+
+ # echo 1 > events/synthetic/block_lat/enable
+ # cat trace
+ # TASK-PID CPU# ||||| TIMESTAMP FUNCTION
+ # | | | ||||| | |
+ kworker/u16:0-767 [006] d..4. 560.645045: block_lat: pid=767 delta=66 stack=STACK:
+ => __schedule
+ => schedule
+ => pipe_read
+ => vfs_read
+ => ksys_read
+ => do_syscall_64
+ => 0x966000aa
+
+ <idle>-0 [003] d..4. 561.132117: block_lat: pid=0 delta=413787 stack=STACK:
+ => __schedule
+ => schedule
+ => schedule_hrtimeout_range_clock
+ => do_sys_poll
+ => __x64_sys_poll
+ => do_syscall_64
+ => 0x966000aa
+
+ <...>-153 [006] d..4. 562.068407: block_lat: pid=153 delta=54 stack=STACK:
+ => __schedule
+ => schedule
+ => io_schedule
+ => rq_qos_wait
+ => wbt_wait
+ => __rq_qos_throttle
+ => blk_mq_submit_bio
+ => submit_bio_noacct_nocheck
+ => ext4_bio_write_page
+ => mpage_submit_page
+ => mpage_process_page_bufs
+ => mpage_prepare_extent_to_map
+ => ext4_do_writepages
+ => ext4_writepages
+ => do_writepages
+ => __writeback_single_inode
+
+Link: https://lkml.kernel.org/r/20230117152236.010941267@goodmis.org
+
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Cc: Andrew Morton <akpm@linux-foundation.org>
+Cc: Tom Zanussi <zanussi@kernel.org>
+Cc: Ross Zwisler <zwisler@google.com>
+Cc: Ching-lin Yu <chinglinyu@google.com>
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Stable-dep-of: 797311bce5c2 ("tracing/probes: Fix to record 0-length data_loc in fetch_store_string*() if fails")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace.h | 4 ++
+ kernel/trace/trace_events_hist.c | 7 ++-
+ kernel/trace/trace_events_synth.c | 80 ++++++++++++++++++++++++++++++-
+ kernel/trace/trace_synth.h | 1 +
+ 4 files changed, 87 insertions(+), 5 deletions(-)
+
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index 2c3d9b6ce1485..33c55c8826a7e 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -113,6 +113,10 @@ enum trace_type {
+ #define MEM_FAIL(condition, fmt, ...) \
+ DO_ONCE_LITE_IF(condition, pr_err, "ERROR: " fmt, ##__VA_ARGS__)
+
++#define HIST_STACKTRACE_DEPTH 16
++#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
++#define HIST_STACKTRACE_SKIP 5
++
+ /*
+ * syscalls are special, and need special handling, this is why
+ * they are not included in trace_entries.h
+diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
+index 1b70fc4c703f7..c32a53f089229 100644
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -315,10 +315,6 @@ DEFINE_HIST_FIELD_FN(u8);
+ #define for_each_hist_key_field(i, hist_data) \
+ for ((i) = (hist_data)->n_vals; (i) < (hist_data)->n_fields; (i)++)
+
+-#define HIST_STACKTRACE_DEPTH 16
+-#define HIST_STACKTRACE_SIZE (HIST_STACKTRACE_DEPTH * sizeof(unsigned long))
+-#define HIST_STACKTRACE_SKIP 5
+-
+ #define HITCOUNT_IDX 0
+ #define HIST_KEY_SIZE_MAX (MAX_FILTER_STR_VAL + HIST_STACKTRACE_SIZE)
+
+@@ -3431,6 +3427,9 @@ static int check_synth_field(struct synth_event *event,
+ && field->is_dynamic)
+ return 0;
+
++ if (strstr(hist_field->type, "long[") && field->is_stack)
++ return 0;
++
+ if (strcmp(field->type, hist_field->type) != 0) {
+ if (field->size != hist_field->size ||
+ (!field->is_string && field->is_signed != hist_field->is_signed))
+diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
+index 08c7df42ade7e..ce8fad956b38d 100644
+--- a/kernel/trace/trace_events_synth.c
++++ b/kernel/trace/trace_events_synth.c
+@@ -165,6 +165,14 @@ static int synth_field_is_string(char *type)
+ return false;
+ }
+
++static int synth_field_is_stack(char *type)
++{
++ if (strstr(type, "long[") != NULL)
++ return true;
++
++ return false;
++}
++
+ static int synth_field_string_size(char *type)
+ {
+ char buf[4], *end, *start;
+@@ -240,6 +248,8 @@ static int synth_field_size(char *type)
+ size = sizeof(gfp_t);
+ else if (synth_field_is_string(type))
+ size = synth_field_string_size(type);
++ else if (synth_field_is_stack(type))
++ size = 0;
+
+ return size;
+ }
+@@ -284,6 +294,8 @@ static const char *synth_field_fmt(char *type)
+ fmt = "%x";
+ else if (synth_field_is_string(type))
+ fmt = "%.*s";
++ else if (synth_field_is_stack(type))
++ fmt = "%s";
+
+ return fmt;
+ }
+@@ -363,6 +375,23 @@ static enum print_line_t print_synth_event(struct trace_iterator *iter,
+ i == se->n_fields - 1 ? "" : " ");
+ n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
+ }
++ } else if (se->fields[i]->is_stack) {
++ u32 offset, data_offset, len;
++ unsigned long *p, *end;
++
++ offset = (u32)entry->fields[n_u64];
++ data_offset = offset & 0xffff;
++ len = offset >> 16;
++
++ p = (void *)entry + data_offset;
++ end = (void *)p + len - (sizeof(long) - 1);
++
++ trace_seq_printf(s, "%s=STACK:\n", se->fields[i]->name);
++
++ for (; *p && p < end; p++)
++ trace_seq_printf(s, "=> %pS\n", (void *)*p);
++ n_u64++;
++
+ } else {
+ struct trace_print_flags __flags[] = {
+ __def_gfpflag_names, {-1, NULL} };
+@@ -439,6 +468,43 @@ static unsigned int trace_string(struct synth_trace_event *entry,
+ return len;
+ }
+
++static unsigned int trace_stack(struct synth_trace_event *entry,
++ struct synth_event *event,
++ long *stack,
++ unsigned int data_size,
++ unsigned int *n_u64)
++{
++ unsigned int len;
++ u32 data_offset;
++ void *data_loc;
++
++ data_offset = struct_size(entry, fields, event->n_u64);
++ data_offset += data_size;
++
++ for (len = 0; len < HIST_STACKTRACE_DEPTH; len++) {
++ if (!stack[len])
++ break;
++ }
++
++ /* Include the zero'd element if it fits */
++ if (len < HIST_STACKTRACE_DEPTH)
++ len++;
++
++ len *= sizeof(long);
++
++ /* Find the dynamic section to copy the stack into. */
++ data_loc = (void *)entry + data_offset;
++ memcpy(data_loc, stack, len);
++
++ /* Fill in the field that holds the offset/len combo */
++ data_offset |= len << 16;
++ *(u32 *)&entry->fields[*n_u64] = data_offset;
++
++ (*n_u64)++;
++
++ return len;
++}
++
+ static notrace void trace_event_raw_event_synth(void *__data,
+ u64 *var_ref_vals,
+ unsigned int *var_ref_idx)
+@@ -491,6 +557,12 @@ static notrace void trace_event_raw_event_synth(void *__data,
+ event->fields[i]->is_dynamic,
+ data_size, &n_u64);
+ data_size += len; /* only dynamic string increments */
++ } if (event->fields[i]->is_stack) {
++ long *stack = (long *)(long)var_ref_vals[val_idx];
++
++ len = trace_stack(entry, event, stack,
++ data_size, &n_u64);
++ data_size += len;
+ } else {
+ struct synth_field *field = event->fields[i];
+ u64 val = var_ref_vals[val_idx];
+@@ -553,6 +625,9 @@ static int __set_synth_event_print_fmt(struct synth_event *event,
+ event->fields[i]->is_dynamic)
+ pos += snprintf(buf + pos, LEN_OR_ZERO,
+ ", __get_str(%s)", event->fields[i]->name);
++ else if (event->fields[i]->is_stack)
++ pos += snprintf(buf + pos, LEN_OR_ZERO,
++ ", __get_stacktrace(%s)", event->fields[i]->name);
+ else
+ pos += snprintf(buf + pos, LEN_OR_ZERO,
+ ", REC->%s", event->fields[i]->name);
+@@ -689,7 +764,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
+ ret = -EINVAL;
+ goto free;
+ } else if (size == 0) {
+- if (synth_field_is_string(field->type)) {
++ if (synth_field_is_string(field->type) ||
++ synth_field_is_stack(field->type)) {
+ char *type;
+
+ len = sizeof("__data_loc ") + strlen(field->type) + 1;
+@@ -720,6 +796,8 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
+
+ if (synth_field_is_string(field->type))
+ field->is_string = true;
++ else if (synth_field_is_stack(field->type))
++ field->is_stack = true;
+
+ field->is_signed = synth_field_signed(field->type);
+ out:
+diff --git a/kernel/trace/trace_synth.h b/kernel/trace/trace_synth.h
+index b29595fe3ac5a..43f6fb6078dbf 100644
+--- a/kernel/trace/trace_synth.h
++++ b/kernel/trace/trace_synth.h
+@@ -18,6 +18,7 @@ struct synth_field {
+ bool is_signed;
+ bool is_string;
+ bool is_dynamic;
++ bool is_stack;
+ };
+
+ struct synth_event {
+--
+2.39.2
+
--- /dev/null
+From 2042d57a437472c231b19ad0094733936e7981ed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 14 Nov 2022 13:47:56 +0900
+Subject: tracing/probes: Add symstr type for dynamic events
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit b26a124cbfa80f42bfc4e63e1d5643ca98159d66 ]
+
+Add 'symstr' type for storing the kernel symbol as a string data
+instead of the symbol address. This allows us to filter the
+events by wildcard symbol name.
+
+e.g.
+ # echo 'e:wqfunc workqueue.workqueue_execute_start symname=$function:symstr' >> dynamic_events
+ # cat events/eprobes/wqfunc/format
+ name: wqfunc
+ ID: 2110
+ format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:__data_loc char[] symname; offset:8; size:4; signed:1;
+
+ print fmt: " symname=\"%s\"", __get_str(symname)
+
+Note that there is already 'symbol' type which just change the
+print format (so it still stores the symbol address in the tracing
+ring buffer.) On the other hand, 'symstr' type stores the actual
+"symbol+offset/size" data as a string.
+
+Link: https://lore.kernel.org/all/166679930847.1528100.4124308529180235965.stgit@devnote3/
+
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Stable-dep-of: 66bcf65d6cf0 ("tracing/probes: Fix to avoid double count of the string length on the array")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ Documentation/trace/kprobetrace.rst | 8 +++--
+ kernel/trace/trace.c | 2 +-
+ kernel/trace/trace_probe.c | 44 ++++++++++++++++++---------
+ kernel/trace/trace_probe.h | 16 +++++++---
+ kernel/trace/trace_probe_tmpl.h | 47 +++++++++++++++++++++++++++--
+ 5 files changed, 91 insertions(+), 26 deletions(-)
+
+diff --git a/Documentation/trace/kprobetrace.rst b/Documentation/trace/kprobetrace.rst
+index b175d88f31ebb..15e4bfa2bd83c 100644
+--- a/Documentation/trace/kprobetrace.rst
++++ b/Documentation/trace/kprobetrace.rst
+@@ -58,8 +58,8 @@ Synopsis of kprobe_events
+ NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
+ FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
+ (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
+- (x8/x16/x32/x64), "string", "ustring" and bitfield
+- are supported.
++ (x8/x16/x32/x64), "string", "ustring", "symbol", "symstr"
++ and bitfield are supported.
+
+ (\*1) only for the probe on function entry (offs == 0).
+ (\*2) only for return probe.
+@@ -96,6 +96,10 @@ offset, and container-size (usually 32). The syntax is::
+
+ Symbol type('symbol') is an alias of u32 or u64 type (depends on BITS_PER_LONG)
+ which shows given pointer in "symbol+offset" style.
++On the other hand, symbol-string type ('symstr') converts the given address to
++"symbol+offset/symbolsize" style and stores it as a null-terminated string.
++With 'symstr' type, you can filter the event with wildcard pattern of the
++symbols, and you don't need to solve symbol name by yourself.
+ For $comm, the default type is "string"; any other type is invalid.
+
+ .. _user_mem_access:
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index 1dda36c7e5eb5..ae7005af78c34 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -5609,7 +5609,7 @@ static const char readme_msg[] =
+ "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
+ "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"
+ "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
+- "\t <type>\\[<array-size>\\]\n"
++ "\t symstr, <type>\\[<array-size>\\]\n"
+ #ifdef CONFIG_HIST_TRIGGERS
+ "\t field: <stype> <name>;\n"
+ "\t stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
+diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
+index cb8f9fe5669ad..90bae188d0928 100644
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -76,9 +76,11 @@ const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
+ /* Fetch type information table */
+ static const struct fetch_type probe_fetch_types[] = {
+ /* Special types */
+- __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1,
++ __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, 1,
+ "__data_loc char[]"),
+- __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1,
++ __ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, 1,
++ "__data_loc char[]"),
++ __ASSIGN_FETCH_TYPE("symstr", string, string, sizeof(u32), 1, 1,
+ "__data_loc char[]"),
+ /* Basic types */
+ ASSIGN_FETCH_TYPE(u8, u8, 0),
+@@ -658,16 +660,26 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
+
+ ret = -EINVAL;
+ /* Store operation */
+- if (!strcmp(parg->type->name, "string") ||
+- !strcmp(parg->type->name, "ustring")) {
+- if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
+- code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
+- code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
+- trace_probe_log_err(offset + (t ? (t - arg) : 0),
+- BAD_STRING);
+- goto fail;
++ if (parg->type->is_string) {
++ if (!strcmp(parg->type->name, "symstr")) {
++ if (code->op != FETCH_OP_REG && code->op != FETCH_OP_STACK &&
++ code->op != FETCH_OP_RETVAL && code->op != FETCH_OP_ARG &&
++ code->op != FETCH_OP_DEREF && code->op != FETCH_OP_TP_ARG) {
++ trace_probe_log_err(offset + (t ? (t - arg) : 0),
++ BAD_SYMSTRING);
++ goto fail;
++ }
++ } else {
++ if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF &&
++ code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM &&
++ code->op != FETCH_OP_DATA && code->op != FETCH_OP_TP_ARG) {
++ trace_probe_log_err(offset + (t ? (t - arg) : 0),
++ BAD_STRING);
++ goto fail;
++ }
+ }
+- if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
++ if (!strcmp(parg->type->name, "symstr") ||
++ (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM ||
+ code->op == FETCH_OP_DATA) || code->op == FETCH_OP_TP_ARG ||
+ parg->count) {
+ /*
+@@ -675,6 +687,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
+ * must be kept, and if parg->count != 0, this is an
+ * array of string pointers instead of string address
+ * itself.
++ * For the symstr, it doesn't need to dereference, thus
++ * it just get the value.
+ */
+ code++;
+ if (code->op != FETCH_OP_NOP) {
+@@ -686,6 +700,8 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
+ if (!strcmp(parg->type->name, "ustring") ||
+ code->op == FETCH_OP_UDEREF)
+ code->op = FETCH_OP_ST_USTRING;
++ else if (!strcmp(parg->type->name, "symstr"))
++ code->op = FETCH_OP_ST_SYMSTR;
+ else
+ code->op = FETCH_OP_ST_STRING;
+ code->size = parg->type->size;
+@@ -915,8 +931,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
+ for (i = 0; i < tp->nr_args; i++) {
+ parg = tp->args + i;
+ if (parg->count) {
+- if ((strcmp(parg->type->name, "string") == 0) ||
+- (strcmp(parg->type->name, "ustring") == 0))
++ if (parg->type->is_string)
+ fmt = ", __get_str(%s[%d])";
+ else
+ fmt = ", REC->%s[%d]";
+@@ -924,8 +939,7 @@ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
+ pos += snprintf(buf + pos, LEN_OR_ZERO,
+ fmt, parg->name, j);
+ } else {
+- if ((strcmp(parg->type->name, "string") == 0) ||
+- (strcmp(parg->type->name, "ustring") == 0))
++ if (parg->type->is_string)
+ fmt = ", __get_str(%s)";
+ else
+ fmt = ", REC->%s";
+diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
+index 84d495cbd876a..0f0e5005b97a0 100644
+--- a/kernel/trace/trace_probe.h
++++ b/kernel/trace/trace_probe.h
+@@ -99,6 +99,7 @@ enum fetch_op {
+ FETCH_OP_ST_UMEM, /* Mem: .offset, .size */
+ FETCH_OP_ST_STRING, /* String: .offset, .size */
+ FETCH_OP_ST_USTRING, /* User String: .offset, .size */
++ FETCH_OP_ST_SYMSTR, /* Kernel Symbol String: .offset, .size */
+ // Stage 4 (modify) op
+ FETCH_OP_MOD_BF, /* Bitfield: .basesize, .lshift, .rshift */
+ // Stage 5 (loop) op
+@@ -134,7 +135,8 @@ struct fetch_insn {
+ struct fetch_type {
+ const char *name; /* Name of type */
+ size_t size; /* Byte size of type */
+- int is_signed; /* Signed flag */
++ bool is_signed; /* Signed flag */
++ bool is_string; /* String flag */
+ print_type_func_t print; /* Print functions */
+ const char *fmt; /* Format string */
+ const char *fmttype; /* Name in format file */
+@@ -178,16 +180,19 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
+ #define _ADDR_FETCH_TYPE(t) __ADDR_FETCH_TYPE(t)
+ #define ADDR_FETCH_TYPE _ADDR_FETCH_TYPE(BITS_PER_LONG)
+
+-#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
+- {.name = _name, \
++#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, str, _fmttype) \
++ {.name = _name, \
+ .size = _size, \
+- .is_signed = sign, \
++ .is_signed = (bool)sign, \
++ .is_string = (bool)str, \
+ .print = PRINT_TYPE_FUNC_NAME(ptype), \
+ .fmt = PRINT_TYPE_FMT_NAME(ptype), \
+ .fmttype = _fmttype, \
+ }
++
++/* Non string types can use these macros */
+ #define _ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
+- __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, #_fmttype)
++ __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, 0, #_fmttype)
+ #define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \
+ _ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, ptype)
+
+@@ -432,6 +437,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
+ C(ARRAY_TOO_BIG, "Array number is too big"), \
+ C(BAD_TYPE, "Unknown type is specified"), \
+ C(BAD_STRING, "String accepts only memory argument"), \
++ C(BAD_SYMSTRING, "Symbol String doesn't accept data/userdata"), \
+ C(BAD_BITFIELD, "Invalid bitfield"), \
+ C(ARG_NAME_TOO_LONG, "Argument name is too long"), \
+ C(NO_ARG_NAME, "Argument name is not specified"), \
+diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
+index c293a607d5366..21799fa813ca8 100644
+--- a/kernel/trace/trace_probe_tmpl.h
++++ b/kernel/trace/trace_probe_tmpl.h
+@@ -67,6 +67,37 @@ probe_mem_read(void *dest, void *src, size_t size);
+ static nokprobe_inline int
+ probe_mem_read_user(void *dest, void *src, size_t size);
+
++static nokprobe_inline int
++fetch_store_symstrlen(unsigned long addr)
++{
++ char namebuf[KSYM_SYMBOL_LEN];
++ int ret;
++
++ ret = sprint_symbol(namebuf, addr);
++ if (ret < 0)
++ return 0;
++
++ return ret + 1;
++}
++
++/*
++ * Fetch a null-terminated symbol string + offset. Caller MUST set *(u32 *)buf
++ * with max length and relative data location.
++ */
++static nokprobe_inline int
++fetch_store_symstring(unsigned long addr, void *dest, void *base)
++{
++ int maxlen = get_loc_len(*(u32 *)dest);
++ void *__dest;
++
++ if (unlikely(!maxlen))
++ return -ENOMEM;
++
++ __dest = get_loc_data(dest, base);
++
++ return sprint_symbol(__dest, addr);
++}
++
+ /* From the 2nd stage, routine is same */
+ static nokprobe_inline int
+ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+@@ -99,16 +130,22 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+ stage3:
+ /* 3rd stage: store value to buffer */
+ if (unlikely(!dest)) {
+- if (code->op == FETCH_OP_ST_STRING) {
++ switch (code->op) {
++ case FETCH_OP_ST_STRING:
+ ret = fetch_store_strlen(val + code->offset);
+ code++;
+ goto array;
+- } else if (code->op == FETCH_OP_ST_USTRING) {
++ case FETCH_OP_ST_USTRING:
+ ret += fetch_store_strlen_user(val + code->offset);
+ code++;
+ goto array;
+- } else
++ case FETCH_OP_ST_SYMSTR:
++ ret += fetch_store_symstrlen(val + code->offset);
++ code++;
++ goto array;
++ default:
+ return -EILSEQ;
++ }
+ }
+
+ switch (code->op) {
+@@ -129,6 +166,10 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+ loc = *(u32 *)dest;
+ ret = fetch_store_string_user(val + code->offset, dest, base);
+ break;
++ case FETCH_OP_ST_SYMSTR:
++ loc = *(u32 *)dest;
++ ret = fetch_store_symstring(val + code->offset, dest, base);
++ break;
+ default:
+ return -EILSEQ;
+ }
+--
+2.39.2
+
--- /dev/null
+From 59d2bace78087a3c5992fcad7bc5ae9dcecb68de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jul 2023 23:15:29 +0900
+Subject: tracing/probes: Fix to avoid double count of the string length on the
+ array
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 66bcf65d6cf0ca6540e2341e88ee7ef02dbdda08 ]
+
+If an array is specified with the ustring or symstr, the length of the
+strings are accumlated on both of 'ret' and 'total', which means the
+length is double counted.
+Just set the length to the 'ret' value for avoiding double counting.
+
+Link: https://lore.kernel.org/all/168908492917.123124.15076463491122036025.stgit@devnote2/
+
+Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
+Closes: https://lore.kernel.org/all/8819b154-2ba1-43c3-98a2-cbde20892023@moroto.mountain/
+Fixes: 88903c464321 ("tracing/probe: Add ustring type for user-space string")
+Cc: stable@vger.kernel.org
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace_probe_tmpl.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
+index 21799fa813ca8..98ac09052fea4 100644
+--- a/kernel/trace/trace_probe_tmpl.h
++++ b/kernel/trace/trace_probe_tmpl.h
+@@ -136,11 +136,11 @@ process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
+ code++;
+ goto array;
+ case FETCH_OP_ST_USTRING:
+- ret += fetch_store_strlen_user(val + code->offset);
++ ret = fetch_store_strlen_user(val + code->offset);
+ code++;
+ goto array;
+ case FETCH_OP_ST_SYMSTR:
+- ret += fetch_store_symstrlen(val + code->offset);
++ ret = fetch_store_symstrlen(val + code->offset);
+ code++;
+ goto array;
+ default:
+--
+2.39.2
+
--- /dev/null
+From 8de4149670d00bd10367a4990957857868abf239 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 11 Jul 2023 23:16:07 +0900
+Subject: tracing/probes: Fix to record 0-length data_loc in
+ fetch_store_string*() if fails
+
+From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+
+[ Upstream commit 797311bce5c2ac90b8d65e357603cfd410d36ebb ]
+
+Fix to record 0-length data to data_loc in fetch_store_string*() if it fails
+to get the string data.
+Currently those expect that the data_loc is updated by store_trace_args() if
+it returns the error code. However, that does not work correctly if the
+argument is an array of strings. In that case, store_trace_args() only clears
+the first entry of the array (which may have no error) and leaves other
+entries. So it should be cleared by fetch_store_string*() itself.
+Also, 'dyndata' and 'maxlen' in store_trace_args() should be updated
+only if it is used (ret > 0 and argument is a dynamic data.)
+
+Link: https://lore.kernel.org/all/168908496683.123124.4761206188794205601.stgit@devnote2/
+
+Fixes: 40b53b771806 ("tracing: probeevent: Add array type support")
+Cc: stable@vger.kernel.org
+Reviewed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/trace/trace_probe_kernel.h | 13 +++++++++----
+ kernel/trace/trace_probe_tmpl.h | 10 +++-------
+ kernel/trace/trace_uprobe.c | 3 ++-
+ 3 files changed, 14 insertions(+), 12 deletions(-)
+
+diff --git a/kernel/trace/trace_probe_kernel.h b/kernel/trace/trace_probe_kernel.h
+index 1d43df29a1f8e..2da70be83831c 100644
+--- a/kernel/trace/trace_probe_kernel.h
++++ b/kernel/trace/trace_probe_kernel.h
+@@ -37,6 +37,13 @@ kern_fetch_store_strlen(unsigned long addr)
+ return (ret < 0) ? ret : len;
+ }
+
++static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base)
++{
++ if (ret < 0)
++ ret = 0;
++ *(u32 *)dest = make_data_loc(ret, __dest - base);
++}
++
+ /*
+ * Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf
+ * with max length and relative data location.
+@@ -55,8 +62,7 @@ kern_fetch_store_string_user(unsigned long addr, void *dest, void *base)
+ __dest = get_loc_data(dest, base);
+
+ ret = strncpy_from_user_nofault(__dest, uaddr, maxlen);
+- if (ret >= 0)
+- *(u32 *)dest = make_data_loc(ret, __dest - base);
++ set_data_loc(ret, dest, __dest, base);
+
+ return ret;
+ }
+@@ -87,8 +93,7 @@ kern_fetch_store_string(unsigned long addr, void *dest, void *base)
+ * probing.
+ */
+ ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen);
+- if (ret >= 0)
+- *(u32 *)dest = make_data_loc(ret, __dest - base);
++ set_data_loc(ret, dest, __dest, base);
+
+ return ret;
+ }
+diff --git a/kernel/trace/trace_probe_tmpl.h b/kernel/trace/trace_probe_tmpl.h
+index 98ac09052fea4..3e2f5a43b974c 100644
+--- a/kernel/trace/trace_probe_tmpl.h
++++ b/kernel/trace/trace_probe_tmpl.h
+@@ -247,13 +247,9 @@ store_trace_args(void *data, struct trace_probe *tp, void *rec,
+ if (unlikely(arg->dynamic))
+ *dl = make_data_loc(maxlen, dyndata - base);
+ ret = process_fetch_insn(arg->code, rec, dl, base);
+- if (arg->dynamic) {
+- if (unlikely(ret < 0)) {
+- *dl = make_data_loc(0, dyndata - base);
+- } else {
+- dyndata += ret;
+- maxlen -= ret;
+- }
++ if (arg->dynamic && likely(ret > 0)) {
++ dyndata += ret;
++ maxlen -= ret;
+ }
+ }
+ }
+diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
+index 78ec1c16ccf4b..debc651015489 100644
+--- a/kernel/trace/trace_uprobe.c
++++ b/kernel/trace/trace_uprobe.c
+@@ -168,7 +168,8 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
+ */
+ ret++;
+ *(u32 *)dest = make_data_loc(ret, (void *)dst - base);
+- }
++ } else
++ *(u32 *)dest = make_data_loc(0, (void *)dst - base);
+
+ return ret;
+ }
+--
+2.39.2
+
--- /dev/null
+From 04ea13fcf5ac39d5faed5c4a0f51f20aa9d4816a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 6 Apr 2023 10:44:50 +0800
+Subject: tty: fix hang on tty device with no_room set
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Hui Li <caelli@tencent.com>
+
+[ Upstream commit 4903fde8047a28299d1fc79c1a0dcc255e928f12 ]
+
+It is possible to hang pty devices in this case, the reader was
+blocking at epoll on master side, the writer was sleeping at
+wait_woken inside n_tty_write on slave side, and the write buffer
+on tty_port was full, we found that the reader and writer would
+never be woken again and blocked forever.
+
+The problem was caused by a race between reader and kworker:
+n_tty_read(reader): n_tty_receive_buf_common(kworker):
+copy_from_read_buf()|
+ |room = N_TTY_BUF_SIZE - (ldata->read_head - tail)
+ |room <= 0
+n_tty_kick_worker() |
+ |ldata->no_room = true
+
+After writing to slave device, writer wakes up kworker to flush
+data on tty_port to reader, and the kworker finds that reader
+has no room to store data so room <= 0 is met. At this moment,
+reader consumes all the data on reader buffer and calls
+n_tty_kick_worker to check ldata->no_room which is false and
+reader quits reading. Then kworker sets ldata->no_room=true
+and quits too.
+
+If write buffer is not full, writer will wake kworker to flush data
+again after following writes, but if write buffer is full and writer
+goes to sleep, kworker will never be woken again and tty device is
+blocked.
+
+This problem can be solved with a check for read buffer size inside
+n_tty_receive_buf_common, if read buffer is empty and ldata->no_room
+is true, a call to n_tty_kick_worker is necessary to keep flushing
+data to reader.
+
+Cc: <stable@vger.kernel.org>
+Fixes: 42458f41d08f ("n_tty: Ensure reader restarts worker for next reader")
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Hui Li <caelli@tencent.com>
+Message-ID: <1680749090-14106-1-git-send-email-caelli@tencent.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/n_tty.c | 25 +++++++++++++++++++++----
+ 1 file changed, 21 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
+index 8f57448e1ce46..6259249b11670 100644
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -202,8 +202,8 @@ static void n_tty_kick_worker(struct tty_struct *tty)
+ struct n_tty_data *ldata = tty->disc_data;
+
+ /* Did the input worker stop? Restart it */
+- if (unlikely(ldata->no_room)) {
+- ldata->no_room = 0;
++ if (unlikely(READ_ONCE(ldata->no_room))) {
++ WRITE_ONCE(ldata->no_room, 0);
+
+ WARN_RATELIMIT(tty->port->itty == NULL,
+ "scheduling with invalid itty\n");
+@@ -1661,7 +1661,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
+ if (overflow && room < 0)
+ ldata->read_head--;
+ room = overflow;
+- ldata->no_room = flow && !room;
++ WRITE_ONCE(ldata->no_room, flow && !room);
+ } else
+ overflow = 0;
+
+@@ -1692,6 +1692,17 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
+ } else
+ n_tty_check_throttle(tty);
+
++ if (unlikely(ldata->no_room)) {
++ /*
++ * Barrier here is to ensure to read the latest read_tail in
++ * chars_in_buffer() and to make sure that read_tail is not loaded
++ * before ldata->no_room is set.
++ */
++ smp_mb();
++ if (!chars_in_buffer(tty))
++ n_tty_kick_worker(tty);
++ }
++
+ up_read(&tty->termios_rwsem);
+
+ return rcvd;
+@@ -2252,8 +2263,14 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+ if (time)
+ timeout = time;
+ }
+- if (old_tail != ldata->read_tail)
++ if (old_tail != ldata->read_tail) {
++ /*
++ * Make sure no_room is not read in n_tty_kick_worker()
++ * before setting ldata->read_tail in copy_from_read_buf().
++ */
++ smp_mb();
+ n_tty_kick_worker(tty);
++ }
+ up_read(&tty->termios_rwsem);
+
+ remove_wait_queue(&tty->read_wait, &wait);
+--
+2.39.2
+