From: Sasha Levin Date: Thu, 28 Sep 2023 20:55:27 +0000 (-0400) Subject: Fixes for 4.19 X-Git-Tag: v6.5.6~82 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8afaa371fffacb775900d5b74ca90fa950daa9d9;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 4.19 Signed-off-by: Sasha Levin --- diff --git a/queue-4.19/ext4-add-new-helper-interface-ext4_try_to_trim_range.patch b/queue-4.19/ext4-add-new-helper-interface-ext4_try_to_trim_range.patch new file mode 100644 index 00000000000..1facde40c2b --- /dev/null +++ b/queue-4.19/ext4-add-new-helper-interface-ext4_try_to_trim_range.patch @@ -0,0 +1,165 @@ +From d52bf582fb8877d648d6ba5f6f11aac09eea4639 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jul 2021 15:41:21 +0800 +Subject: ext4: add new helper interface ext4_try_to_trim_range() + +From: Wang Jianchao + +[ Upstream commit 6920b3913235f517728bb69abe9b39047a987113 ] + +There is no functional change in this patch but just split the +codes, which serachs free block and does trim, into a new function +ext4_try_to_trim_range. This is preparing for the following async +backgroup discard. + +Reviewed-by: Andreas Dilger +Signed-off-by: Wang Jianchao +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20210724074124.25731-3-jianchao.wan9@gmail.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc.c | 102 ++++++++++++++++++++++++++-------------------- + 1 file changed, 57 insertions(+), 45 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 7b81094831754..51def652098b3 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5184,6 +5184,54 @@ __acquires(bitlock) + return ret; + } + ++static int ext4_try_to_trim_range(struct super_block *sb, ++ struct ext4_buddy *e4b, ext4_grpblk_t start, ++ ext4_grpblk_t max, ext4_grpblk_t minblocks) ++{ ++ ext4_grpblk_t next, count, free_count; ++ void *bitmap; ++ int ret = 0; ++ ++ bitmap = e4b->bd_bitmap; ++ start = (e4b->bd_info->bb_first_free > start) ? ++ e4b->bd_info->bb_first_free : start; ++ count = 0; ++ free_count = 0; ++ ++ while (start <= max) { ++ start = mb_find_next_zero_bit(bitmap, max + 1, start); ++ if (start > max) ++ break; ++ next = mb_find_next_bit(bitmap, max + 1, start); ++ ++ if ((next - start) >= minblocks) { ++ ret = ext4_trim_extent(sb, start, next - start, e4b); ++ if (ret && ret != -EOPNOTSUPP) ++ break; ++ ret = 0; ++ count += next - start; ++ } ++ free_count += next - start; ++ start = next + 1; ++ ++ if (fatal_signal_pending(current)) { ++ count = -ERESTARTSYS; ++ break; ++ } ++ ++ if (need_resched()) { ++ ext4_unlock_group(sb, e4b->bd_group); ++ cond_resched(); ++ ext4_lock_group(sb, e4b->bd_group); ++ } ++ ++ if ((e4b->bd_info->bb_free - free_count) < minblocks) ++ break; ++ } ++ ++ return count; ++} ++ + /** + * ext4_trim_all_free -- function to trim all free space in alloc. group + * @sb: super block for file system +@@ -5207,10 +5255,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + ext4_grpblk_t start, ext4_grpblk_t max, + ext4_grpblk_t minblocks) + { +- void *bitmap; +- ext4_grpblk_t next, count = 0, free_count = 0; + struct ext4_buddy e4b; +- int ret = 0; ++ int ret; + + trace_ext4_trim_all_free(sb, group, start, max); + +@@ -5220,57 +5266,23 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + ret, group); + return ret; + } +- bitmap = e4b.bd_bitmap; + + ext4_lock_group(sb, group); +- if (EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) && +- minblocks >= atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) +- goto out; +- +- start = (e4b.bd_info->bb_first_free > start) ? +- e4b.bd_info->bb_first_free : start; +- +- while (start <= max) { +- start = mb_find_next_zero_bit(bitmap, max + 1, start); +- if (start > max) +- break; +- next = mb_find_next_bit(bitmap, max + 1, start); +- +- if ((next - start) >= minblocks) { +- ret = ext4_trim_extent(sb, start, next - start, &e4b); +- if (ret && ret != -EOPNOTSUPP) +- break; +- ret = 0; +- count += next - start; +- } +- free_count += next - start; +- start = next + 1; +- +- if (fatal_signal_pending(current)) { +- count = -ERESTARTSYS; +- break; +- } +- +- if (need_resched()) { +- ext4_unlock_group(sb, group); +- cond_resched(); +- ext4_lock_group(sb, group); +- } + +- if ((e4b.bd_info->bb_free - free_count) < minblocks) +- break; ++ if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) || ++ minblocks < atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) { ++ ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks); ++ if (ret >= 0) ++ EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); ++ } else { ++ ret = 0; + } + +- if (!ret) { +- ret = count; +- EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); +- } +-out: + ext4_unlock_group(sb, group); + ext4_mb_unload_buddy(&e4b); + + ext4_debug("trimmed %d blocks in the group %d\n", +- count, group); ++ ret, group); + + return ret; + } +-- +2.40.1 + diff --git a/queue-4.19/ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch b/queue-4.19/ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch new file mode 100644 index 00000000000..7d86a5d2ab8 --- /dev/null +++ b/queue-4.19/ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch @@ -0,0 +1,64 @@ +From 2d6c87ae043945d0e573fec55db8b466e4c79251 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Nov 2021 15:51:21 +0100 +Subject: ext4: change s_last_trim_minblks type to unsigned long + +From: Lukas Czerner + +[ Upstream commit 2327fb2e23416cfb2795ccca2f77d4d65925be99 ] + +There is no good reason for the s_last_trim_minblks to be atomic. There is +no data integrity needed and there is no real danger in setting and +reading it in a racy manner. Change it to be unsigned long, the same type +as s_clusters_per_group which is the maximum that's allowed. + +Signed-off-by: Lukas Czerner +Suggested-by: Andreas Dilger +Reviewed-by: Andreas Dilger +Link: https://lore.kernel.org/r/20211103145122.17338-1-lczerner@redhat.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + fs/ext4/ext4.h | 2 +- + fs/ext4/mballoc.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 909f231a387d7..fa2579abea7df 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -1500,7 +1500,7 @@ struct ext4_sb_info { + struct task_struct *s_mmp_tsk; + + /* record the last minlen when FITRIM is called. */ +- atomic_t s_last_trim_minblks; ++ unsigned long s_last_trim_minblks; + + /* Reference to checksum algorithm driver via cryptoapi */ + struct crypto_shash *s_chksum_driver; +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 58a0d2ea314b7..b76e8b8f01a10 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5269,7 +5269,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + ext4_lock_group(sb, group); + + if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) || +- minblocks < atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) { ++ minblocks < EXT4_SB(sb)->s_last_trim_minblks) { + ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks); + if (ret >= 0) + EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); +@@ -5378,7 +5378,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + } + + if (!ret) +- atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen); ++ EXT4_SB(sb)->s_last_trim_minblks = minlen; + + out: + range->len = EXT4_C2B(EXT4_SB(sb), trimmed) << sb->s_blocksize_bits; +-- +2.40.1 + diff --git a/queue-4.19/ext4-do-not-let-fstrim-block-system-suspend.patch b/queue-4.19/ext4-do-not-let-fstrim-block-system-suspend.patch new file mode 100644 index 00000000000..06509a77d0d --- /dev/null +++ b/queue-4.19/ext4-do-not-let-fstrim-block-system-suspend.patch @@ -0,0 +1,76 @@ +From 63fc38e35ab0e5b042f060431aae33af99041217 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Sep 2023 17:04:55 +0200 +Subject: ext4: do not let fstrim block system suspend + +From: Jan Kara + +[ Upstream commit 5229a658f6453362fbb9da6bf96872ef25a7097e ] + +Len Brown has reported that system suspend sometimes fail due to +inability to freeze a task working in ext4_trim_fs() for one minute. +Trimming a large filesystem on a disk that slowly processes discard +requests can indeed take a long time. Since discard is just an advisory +call, it is perfectly fine to interrupt it at any time and the return +number of discarded blocks until that moment. Do that when we detect the +task is being frozen. + +Cc: stable@kernel.org +Reported-by: Len Brown +Suggested-by: Dave Chinner +References: https://bugzilla.kernel.org/show_bug.cgi?id=216322 +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20230913150504.9054-2-jack@suse.cz +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 94b3bf8173e20..fb2f255c48e81 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + + #ifdef CONFIG_EXT4_DEBUG +@@ -5194,6 +5195,11 @@ static ext4_grpblk_t ext4_last_grp_cluster(struct super_block *sb, + EXT4_CLUSTER_BITS(sb); + } + ++static bool ext4_trim_interrupted(void) ++{ ++ return fatal_signal_pending(current) || freezing(current); ++} ++ + static int ext4_try_to_trim_range(struct super_block *sb, + struct ext4_buddy *e4b, ext4_grpblk_t start, + ext4_grpblk_t max, ext4_grpblk_t minblocks) +@@ -5225,8 +5231,8 @@ static int ext4_try_to_trim_range(struct super_block *sb, + free_count += next - start; + start = next + 1; + +- if (fatal_signal_pending(current)) +- return -ERESTARTSYS; ++ if (ext4_trim_interrupted()) ++ return count; + + if (need_resched()) { + ext4_unlock_group(sb, e4b->bd_group); +@@ -5353,6 +5359,8 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + end = EXT4_CLUSTERS_PER_GROUP(sb) - 1; + + for (group = first_group; group <= last_group; group++) { ++ if (ext4_trim_interrupted()) ++ break; + grp = ext4_get_group_info(sb, group); + /* We only do this if the grp has never been initialized */ + if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { +-- +2.40.1 + diff --git a/queue-4.19/ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch b/queue-4.19/ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch new file mode 100644 index 00000000000..ea98ff4476d --- /dev/null +++ b/queue-4.19/ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch @@ -0,0 +1,107 @@ +From e4ed3fc2904824cbb013485288c7dc6264b33f95 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 17 Apr 2022 20:03:15 +0300 +Subject: ext4: mark group as trimmed only if it was fully scanned + +From: Dmitry Monakhov + +[ Upstream commit d63c00ea435a5352f486c259665a4ced60399421 ] + +Otherwise nonaligned fstrim calls will works inconveniently for iterative +scanners, for example: + +// trim [0,16MB] for group-1, but mark full group as trimmed +fstrim -o $((1024*1024*128)) -l $((1024*1024*16)) ./m +// handle [16MB,16MB] for group-1, do nothing because group already has the flag. +fstrim -o $((1024*1024*144)) -l $((1024*1024*16)) ./m + +[ Update function documentation for ext4_trim_all_free -- TYT ] + +Signed-off-by: Dmitry Monakhov +Link: https://lore.kernel.org/r/1650214995-860245-1-git-send-email-dmtrmonakhov@yandex-team.ru +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index b76e8b8f01a10..e926b8c3ea893 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5238,6 +5238,7 @@ static int ext4_try_to_trim_range(struct super_block *sb, + * @start: first group block to examine + * @max: last group block to examine + * @minblocks: minimum extent block count ++ * @set_trimmed: set the trimmed flag if at least one block is trimmed + * + * ext4_trim_all_free walks through group's buddy bitmap searching for free + * extents. When the free block is found, ext4_trim_extent is called to TRIM +@@ -5252,7 +5253,7 @@ static int ext4_try_to_trim_range(struct super_block *sb, + static ext4_grpblk_t + ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + ext4_grpblk_t start, ext4_grpblk_t max, +- ext4_grpblk_t minblocks) ++ ext4_grpblk_t minblocks, bool set_trimmed) + { + struct ext4_buddy e4b; + int ret; +@@ -5271,7 +5272,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) || + minblocks < EXT4_SB(sb)->s_last_trim_minblks) { + ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks); +- if (ret >= 0) ++ if (ret >= 0 && set_trimmed) + EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); + } else { + ret = 0; +@@ -5308,6 +5309,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + ext4_fsblk_t first_data_blk = + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); + ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es); ++ bool whole_group, eof = false; + int ret = 0; + + start = range->start >> sb->s_blocksize_bits; +@@ -5326,8 +5328,10 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + if (minlen > EXT4_CLUSTERS_PER_GROUP(sb)) + goto out; + } +- if (end >= max_blks) ++ if (end >= max_blks - 1) { + end = max_blks - 1; ++ eof = true; ++ } + if (end <= first_data_blk) + goto out; + if (start < first_data_blk) +@@ -5341,6 +5345,7 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + + /* end now represents the last cluster to discard in this group */ + end = EXT4_CLUSTERS_PER_GROUP(sb) - 1; ++ whole_group = true; + + for (group = first_group; group <= last_group; group++) { + grp = ext4_get_group_info(sb, group); +@@ -5357,12 +5362,13 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + * change it for the last group, note that last_cluster is + * already computed earlier by ext4_get_group_no_and_offset() + */ +- if (group == last_group) ++ if (group == last_group) { + end = last_cluster; +- ++ whole_group = eof ? true : end == EXT4_CLUSTERS_PER_GROUP(sb) - 1; ++ } + if (grp->bb_free >= minlen) { + cnt = ext4_trim_all_free(sb, group, first_cluster, +- end, minlen); ++ end, minlen, whole_group); + if (cnt < 0) { + ret = cnt; + break; +-- +2.40.1 + diff --git a/queue-4.19/ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch b/queue-4.19/ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch new file mode 100644 index 00000000000..ae33d0d68ca --- /dev/null +++ b/queue-4.19/ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch @@ -0,0 +1,168 @@ +From 7615b899fabc012b520ccf99eb10a9507834b98b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Sep 2023 17:04:54 +0200 +Subject: ext4: move setting of trimmed bit into ext4_try_to_trim_range() + +From: Jan Kara + +[ Upstream commit 45e4ab320c9b5fa67b1fc3b6a9b381cfcc0c8488 ] + +Currently we set the group's trimmed bit in ext4_trim_all_free() based +on return value of ext4_try_to_trim_range(). However when we will want +to abort trimming because of suspend attempt, we want to return success +from ext4_try_to_trim_range() but not set the trimmed bit. Instead +implementing awkward propagation of this information, just move setting +of trimmed bit into ext4_try_to_trim_range() when the whole group is +trimmed. + +Cc: stable@kernel.org +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20230913150504.9054-1-jack@suse.cz +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc.c | 46 +++++++++++++++++++++++++--------------------- + 1 file changed, 25 insertions(+), 21 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 22da6b1143e5d..94b3bf8173e20 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5184,14 +5184,27 @@ __acquires(bitlock) + return ret; + } + ++static ext4_grpblk_t ext4_last_grp_cluster(struct super_block *sb, ++ ext4_group_t grp) ++{ ++ if (grp < ext4_get_groups_count(sb)) ++ return EXT4_CLUSTERS_PER_GROUP(sb) - 1; ++ return (ext4_blocks_count(EXT4_SB(sb)->s_es) - ++ ext4_group_first_block_no(sb, grp) - 1) >> ++ EXT4_CLUSTER_BITS(sb); ++} ++ + static int ext4_try_to_trim_range(struct super_block *sb, + struct ext4_buddy *e4b, ext4_grpblk_t start, + ext4_grpblk_t max, ext4_grpblk_t minblocks) + { + ext4_grpblk_t next, count, free_count; ++ bool set_trimmed = false; + void *bitmap; + + bitmap = e4b->bd_bitmap; ++ if (start == 0 && max >= ext4_last_grp_cluster(sb, e4b->bd_group)) ++ set_trimmed = true; + start = max(e4b->bd_info->bb_first_free, start); + count = 0; + free_count = 0; +@@ -5206,16 +5219,14 @@ static int ext4_try_to_trim_range(struct super_block *sb, + int ret = ext4_trim_extent(sb, start, next - start, e4b); + + if (ret && ret != -EOPNOTSUPP) +- break; ++ return count; + count += next - start; + } + free_count += next - start; + start = next + 1; + +- if (fatal_signal_pending(current)) { +- count = -ERESTARTSYS; +- break; +- } ++ if (fatal_signal_pending(current)) ++ return -ERESTARTSYS; + + if (need_resched()) { + ext4_unlock_group(sb, e4b->bd_group); +@@ -5227,6 +5238,9 @@ static int ext4_try_to_trim_range(struct super_block *sb, + break; + } + ++ if (set_trimmed) ++ EXT4_MB_GRP_SET_TRIMMED(e4b->bd_info); ++ + return count; + } + +@@ -5237,7 +5251,6 @@ static int ext4_try_to_trim_range(struct super_block *sb, + * @start: first group block to examine + * @max: last group block to examine + * @minblocks: minimum extent block count +- * @set_trimmed: set the trimmed flag if at least one block is trimmed + * + * ext4_trim_all_free walks through group's buddy bitmap searching for free + * extents. When the free block is found, ext4_trim_extent is called to TRIM +@@ -5252,7 +5265,7 @@ static int ext4_try_to_trim_range(struct super_block *sb, + static ext4_grpblk_t + ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + ext4_grpblk_t start, ext4_grpblk_t max, +- ext4_grpblk_t minblocks, bool set_trimmed) ++ ext4_grpblk_t minblocks) + { + struct ext4_buddy e4b; + int ret; +@@ -5269,13 +5282,10 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + ext4_lock_group(sb, group); + + if (!EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) || +- minblocks < EXT4_SB(sb)->s_last_trim_minblks) { ++ minblocks < EXT4_SB(sb)->s_last_trim_minblks) + ret = ext4_try_to_trim_range(sb, &e4b, start, max, minblocks); +- if (ret >= 0 && set_trimmed) +- EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); +- } else { ++ else + ret = 0; +- } + + ext4_unlock_group(sb, group); + ext4_mb_unload_buddy(&e4b); +@@ -5308,7 +5318,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + ext4_fsblk_t first_data_blk = + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); + ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es); +- bool whole_group, eof = false; + int ret = 0; + + start = range->start >> sb->s_blocksize_bits; +@@ -5327,10 +5336,8 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + if (minlen > EXT4_CLUSTERS_PER_GROUP(sb)) + goto out; + } +- if (end >= max_blks - 1) { ++ if (end >= max_blks - 1) + end = max_blks - 1; +- eof = true; +- } + if (end <= first_data_blk) + goto out; + if (start < first_data_blk) +@@ -5344,7 +5351,6 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + + /* end now represents the last cluster to discard in this group */ + end = EXT4_CLUSTERS_PER_GROUP(sb) - 1; +- whole_group = true; + + for (group = first_group; group <= last_group; group++) { + grp = ext4_get_group_info(sb, group); +@@ -5361,13 +5367,11 @@ int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) + * change it for the last group, note that last_cluster is + * already computed earlier by ext4_get_group_no_and_offset() + */ +- if (group == last_group) { ++ if (group == last_group) + end = last_cluster; +- whole_group = eof ? true : end == EXT4_CLUSTERS_PER_GROUP(sb) - 1; +- } + if (grp->bb_free >= minlen) { + cnt = ext4_trim_all_free(sb, group, first_cluster, +- end, minlen, whole_group); ++ end, minlen); + if (cnt < 0) { + ret = cnt; + break; +-- +2.40.1 + diff --git a/queue-4.19/ext4-remove-the-group-parameter-of-ext4_trim_extent.patch b/queue-4.19/ext4-remove-the-group-parameter-of-ext4_trim_extent.patch new file mode 100644 index 00000000000..c4bae6d8c0f --- /dev/null +++ b/queue-4.19/ext4-remove-the-group-parameter-of-ext4_trim_extent.patch @@ -0,0 +1,63 @@ +From 5b2e280bd439a66416f6278a45bfc619118ee65c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Jul 2021 15:41:20 +0800 +Subject: ext4: remove the 'group' parameter of ext4_trim_extent + +From: Wang Jianchao + +[ Upstream commit bd2eea8d0a6b6a9aca22f20bf74f73b71d8808af ] + +Get rid of the 'group' parameter of ext4_trim_extent as we can get +it from the 'e4b'. + +Reviewed-by: Andreas Dilger +Signed-off-by: Wang Jianchao +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20210724074124.25731-2-jianchao.wan9@gmail.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 7692c12b85285..7b81094831754 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5149,19 +5149,19 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, + * @sb: super block for the file system + * @start: starting block of the free extent in the alloc. group + * @count: number of blocks to TRIM +- * @group: alloc. group we are working with + * @e4b: ext4 buddy for the group + * + * Trim "count" blocks starting at "start" in the "group". To assure that no + * one will allocate those blocks, mark it as used in buddy bitmap. This must + * be called with under the group lock. + */ +-static int ext4_trim_extent(struct super_block *sb, int start, int count, +- ext4_group_t group, struct ext4_buddy *e4b) ++static int ext4_trim_extent(struct super_block *sb, ++ int start, int count, struct ext4_buddy *e4b) + __releases(bitlock) + __acquires(bitlock) + { + struct ext4_free_extent ex; ++ ext4_group_t group = e4b->bd_group; + int ret = 0; + + trace_ext4_trim_extent(sb, group, start, count); +@@ -5237,8 +5237,7 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, + next = mb_find_next_bit(bitmap, max + 1, start); + + if ((next - start) >= minblocks) { +- ret = ext4_trim_extent(sb, start, +- next - start, group, &e4b); ++ ret = ext4_trim_extent(sb, start, next - start, &e4b); + if (ret && ret != -EOPNOTSUPP) + break; + ret = 0; +-- +2.40.1 + diff --git a/queue-4.19/ext4-replace-the-traditional-ternary-conditional-ope.patch b/queue-4.19/ext4-replace-the-traditional-ternary-conditional-ope.patch new file mode 100644 index 00000000000..b88097dd797 --- /dev/null +++ b/queue-4.19/ext4-replace-the-traditional-ternary-conditional-ope.patch @@ -0,0 +1,49 @@ +From 4dbbba480ea84526dfbf9badd67d2c0ee5bf9434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Aug 2023 22:32:00 +0800 +Subject: ext4: replace the traditional ternary conditional operator with with + max()/min() + +From: Kemeng Shi + +[ Upstream commit de8bf0e5ee7482585450357c6d4eddec8efc5cb7 ] + +Replace the traditional ternary conditional operator with with max()/min() + +Signed-off-by: Kemeng Shi +Reviewed-by: Ritesh Harjani (IBM) +Link: https://lore.kernel.org/r/20230801143204.2284343-7-shikemeng@huaweicloud.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index e926b8c3ea893..22da6b1143e5d 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5192,8 +5192,7 @@ static int ext4_try_to_trim_range(struct super_block *sb, + void *bitmap; + + bitmap = e4b->bd_bitmap; +- start = (e4b->bd_info->bb_first_free > start) ? +- e4b->bd_info->bb_first_free : start; ++ start = max(e4b->bd_info->bb_first_free, start); + count = 0; + free_count = 0; + +@@ -5413,8 +5412,7 @@ ext4_mballoc_query_range( + + ext4_lock_group(sb, group); + +- start = (e4b.bd_info->bb_first_free > start) ? +- e4b.bd_info->bb_first_free : start; ++ start = max(e4b.bd_info->bb_first_free, start); + if (end >= EXT4_CLUSTERS_PER_GROUP(sb)) + end = EXT4_CLUSTERS_PER_GROUP(sb) - 1; + +-- +2.40.1 + diff --git a/queue-4.19/ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch b/queue-4.19/ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch new file mode 100644 index 00000000000..8229c745c76 --- /dev/null +++ b/queue-4.19/ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch @@ -0,0 +1,55 @@ +From 21abc74977d5eb29ce86d5eb9d66b9bad594bf87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 14:08:53 +0200 +Subject: ext4: scope ret locally in ext4_try_to_trim_range() + +From: Lukas Bulwahn + +[ Upstream commit afcc4e32f606dbfb47aa7309172c89174b86e74c ] + +As commit 6920b3913235 ("ext4: add new helper interface +ext4_try_to_trim_range()") moves some code into the separate function +ext4_try_to_trim_range(), the use of the variable ret within that +function is more limited and can be adjusted as well. + +Scope the use of the variable ret locally and drop dead assignments. + +No functional change. + +Signed-off-by: Lukas Bulwahn +Link: https://lore.kernel.org/r/20210820120853.23134-1-lukas.bulwahn@gmail.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 45e4ab320c9b ("ext4: move setting of trimmed bit into ext4_try_to_trim_range()") +Signed-off-by: Sasha Levin +--- + fs/ext4/mballoc.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c +index 51def652098b3..58a0d2ea314b7 100644 +--- a/fs/ext4/mballoc.c ++++ b/fs/ext4/mballoc.c +@@ -5190,7 +5190,6 @@ static int ext4_try_to_trim_range(struct super_block *sb, + { + ext4_grpblk_t next, count, free_count; + void *bitmap; +- int ret = 0; + + bitmap = e4b->bd_bitmap; + start = (e4b->bd_info->bb_first_free > start) ? +@@ -5205,10 +5204,10 @@ static int ext4_try_to_trim_range(struct super_block *sb, + next = mb_find_next_bit(bitmap, max + 1, start); + + if ((next - start) >= minblocks) { +- ret = ext4_trim_extent(sb, start, next - start, e4b); ++ int ret = ext4_trim_extent(sb, start, next - start, e4b); ++ + if (ret && ret != -EOPNOTSUPP) + break; +- ret = 0; + count += next - start; + } + free_count += next - start; +-- +2.40.1 + diff --git a/queue-4.19/input-i8042-add-quirk-for-tuxedo-gemini-17-gen1-clev.patch b/queue-4.19/input-i8042-add-quirk-for-tuxedo-gemini-17-gen1-clev.patch new file mode 100644 index 00000000000..96342928fcf --- /dev/null +++ b/queue-4.19/input-i8042-add-quirk-for-tuxedo-gemini-17-gen1-clev.patch @@ -0,0 +1,50 @@ +From 85b2d545e7b9ab18722f944b01307672b1737ad4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Jul 2023 11:56:51 -0700 +Subject: Input: i8042 - add quirk for TUXEDO Gemini 17 Gen1/Clevo PD70PN + +From: Werner Sembach + +[ Upstream commit eb09074bdb05ffd6bfe77f8b4a41b76ef78c997b ] + +The touchpad of this device is both connected via PS/2 and i2c. This causes +strange behavior when both driver fight for control. The easy fix is to +prevent the PS/2 driver from accessing the mouse port as the full feature +set of the touchpad is only supported in the i2c interface anyway. + +The strange behavior in this case is, that when an external screen is +connected and the notebook is closed, the pointer on the external screen is +moving to the lower right corner. When the notebook is opened again, this +movement stops, but the touchpad clicks are unresponsive afterwards until +reboot. + +Signed-off-by: Werner Sembach +Cc: stable@vger.kernel.org +Link: https://lore.kernel.org/r/20230607173331.851192-1-wse@tuxedocomputers.com +Signed-off-by: Dmitry Torokhov +Signed-off-by: Sasha Levin +--- + drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h +index da2bf8259330e..0cf9a37873261 100644 +--- a/drivers/input/serio/i8042-x86ia64io.h ++++ b/drivers/input/serio/i8042-x86ia64io.h +@@ -1188,6 +1188,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, ++ /* See comment on TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU above */ ++ { ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "PD5x_7xPNP_PNR_PNN_PNT"), ++ }, ++ .driver_data = (void *)(SERIO_QUIRK_NOAUX) ++ }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "X170SM"), +-- +2.40.1 + diff --git a/queue-4.19/scsi-megaraid_sas-fix-deadlock-on-firmware-crashdump.patch b/queue-4.19/scsi-megaraid_sas-fix-deadlock-on-firmware-crashdump.patch new file mode 100644 index 00000000000..2e555ebf9ba --- /dev/null +++ b/queue-4.19/scsi-megaraid_sas-fix-deadlock-on-firmware-crashdump.patch @@ -0,0 +1,183 @@ +From 91a3f294febcd7987d48cf7e248db51be5a93290 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Aug 2023 15:10:18 -0700 +Subject: scsi: megaraid_sas: Fix deadlock on firmware crashdump + +From: Junxiao Bi + +[ Upstream commit 0b0747d507bffb827e40fc0f9fb5883fffc23477 ] + +The following processes run into a deadlock. CPU 41 was waiting for CPU 29 +to handle a CSD request while holding spinlock "crashdump_lock", but CPU 29 +was hung by that spinlock with IRQs disabled. + + PID: 17360 TASK: ffff95c1090c5c40 CPU: 41 COMMAND: "mrdiagd" + !# 0 [ffffb80edbf37b58] __read_once_size at ffffffff9b871a40 include/linux/compiler.h:185:0 + !# 1 [ffffb80edbf37b58] atomic_read at ffffffff9b871a40 arch/x86/include/asm/atomic.h:27:0 + !# 2 [ffffb80edbf37b58] dump_stack at ffffffff9b871a40 lib/dump_stack.c:54:0 + # 3 [ffffb80edbf37b78] csd_lock_wait_toolong at ffffffff9b131ad5 kernel/smp.c:364:0 + # 4 [ffffb80edbf37b78] __csd_lock_wait at ffffffff9b131ad5 kernel/smp.c:384:0 + # 5 [ffffb80edbf37bf8] csd_lock_wait at ffffffff9b13267a kernel/smp.c:394:0 + # 6 [ffffb80edbf37bf8] smp_call_function_many at ffffffff9b13267a kernel/smp.c:843:0 + # 7 [ffffb80edbf37c50] smp_call_function at ffffffff9b13279d kernel/smp.c:867:0 + # 8 [ffffb80edbf37c50] on_each_cpu at ffffffff9b13279d kernel/smp.c:976:0 + # 9 [ffffb80edbf37c78] flush_tlb_kernel_range at ffffffff9b085c4b arch/x86/mm/tlb.c:742:0 + #10 [ffffb80edbf37cb8] __purge_vmap_area_lazy at ffffffff9b23a1e0 mm/vmalloc.c:701:0 + #11 [ffffb80edbf37ce0] try_purge_vmap_area_lazy at ffffffff9b23a2cc mm/vmalloc.c:722:0 + #12 [ffffb80edbf37ce0] free_vmap_area_noflush at ffffffff9b23a2cc mm/vmalloc.c:754:0 + #13 [ffffb80edbf37cf8] free_unmap_vmap_area at ffffffff9b23bb3b mm/vmalloc.c:764:0 + #14 [ffffb80edbf37cf8] remove_vm_area at ffffffff9b23bb3b mm/vmalloc.c:1509:0 + #15 [ffffb80edbf37d18] __vunmap at ffffffff9b23bb8a mm/vmalloc.c:1537:0 + #16 [ffffb80edbf37d40] vfree at ffffffff9b23bc85 mm/vmalloc.c:1612:0 + #17 [ffffb80edbf37d58] megasas_free_host_crash_buffer [megaraid_sas] at ffffffffc020b7f2 drivers/scsi/megaraid/megaraid_sas_fusion.c:3932:0 + #18 [ffffb80edbf37d80] fw_crash_state_store [megaraid_sas] at ffffffffc01f804d drivers/scsi/megaraid/megaraid_sas_base.c:3291:0 + #19 [ffffb80edbf37dc0] dev_attr_store at ffffffff9b56dd7b drivers/base/core.c:758:0 + #20 [ffffb80edbf37dd0] sysfs_kf_write at ffffffff9b326acf fs/sysfs/file.c:144:0 + #21 [ffffb80edbf37de0] kernfs_fop_write at ffffffff9b325fd4 fs/kernfs/file.c:316:0 + #22 [ffffb80edbf37e20] __vfs_write at ffffffff9b29418a fs/read_write.c:480:0 + #23 [ffffb80edbf37ea8] vfs_write at ffffffff9b294462 fs/read_write.c:544:0 + #24 [ffffb80edbf37ee8] SYSC_write at ffffffff9b2946ec fs/read_write.c:590:0 + #25 [ffffb80edbf37ee8] SyS_write at ffffffff9b2946ec fs/read_write.c:582:0 + #26 [ffffb80edbf37f30] do_syscall_64 at ffffffff9b003ca9 arch/x86/entry/common.c:298:0 + #27 [ffffb80edbf37f58] entry_SYSCALL_64 at ffffffff9ba001b1 arch/x86/entry/entry_64.S:238:0 + + PID: 17355 TASK: ffff95c1090c3d80 CPU: 29 COMMAND: "mrdiagd" + !# 0 [ffffb80f2d3c7d30] __read_once_size at ffffffff9b0f2ab0 include/linux/compiler.h:185:0 + !# 1 [ffffb80f2d3c7d30] native_queued_spin_lock_slowpath at ffffffff9b0f2ab0 kernel/locking/qspinlock.c:368:0 + # 2 [ffffb80f2d3c7d58] pv_queued_spin_lock_slowpath at ffffffff9b0f244b arch/x86/include/asm/paravirt.h:674:0 + # 3 [ffffb80f2d3c7d58] queued_spin_lock_slowpath at ffffffff9b0f244b arch/x86/include/asm/qspinlock.h:53:0 + # 4 [ffffb80f2d3c7d68] queued_spin_lock at ffffffff9b8961a6 include/asm-generic/qspinlock.h:90:0 + # 5 [ffffb80f2d3c7d68] do_raw_spin_lock_flags at ffffffff9b8961a6 include/linux/spinlock.h:173:0 + # 6 [ffffb80f2d3c7d68] __raw_spin_lock_irqsave at ffffffff9b8961a6 include/linux/spinlock_api_smp.h:122:0 + # 7 [ffffb80f2d3c7d68] _raw_spin_lock_irqsave at ffffffff9b8961a6 kernel/locking/spinlock.c:160:0 + # 8 [ffffb80f2d3c7d88] fw_crash_buffer_store [megaraid_sas] at ffffffffc01f8129 drivers/scsi/megaraid/megaraid_sas_base.c:3205:0 + # 9 [ffffb80f2d3c7dc0] dev_attr_store at ffffffff9b56dd7b drivers/base/core.c:758:0 + #10 [ffffb80f2d3c7dd0] sysfs_kf_write at ffffffff9b326acf fs/sysfs/file.c:144:0 + #11 [ffffb80f2d3c7de0] kernfs_fop_write at ffffffff9b325fd4 fs/kernfs/file.c:316:0 + #12 [ffffb80f2d3c7e20] __vfs_write at ffffffff9b29418a fs/read_write.c:480:0 + #13 [ffffb80f2d3c7ea8] vfs_write at ffffffff9b294462 fs/read_write.c:544:0 + #14 [ffffb80f2d3c7ee8] SYSC_write at ffffffff9b2946ec fs/read_write.c:590:0 + #15 [ffffb80f2d3c7ee8] SyS_write at ffffffff9b2946ec fs/read_write.c:582:0 + #16 [ffffb80f2d3c7f30] do_syscall_64 at ffffffff9b003ca9 arch/x86/entry/common.c:298:0 + #17 [ffffb80f2d3c7f58] entry_SYSCALL_64 at ffffffff9ba001b1 arch/x86/entry/entry_64.S:238:0 + +The lock is used to synchronize different sysfs operations, it doesn't +protect any resource that will be touched by an interrupt. Consequently +it's not required to disable IRQs. Replace the spinlock with a mutex to fix +the deadlock. + +Signed-off-by: Junxiao Bi +Link: https://lore.kernel.org/r/20230828221018.19471-1-junxiao.bi@oracle.com +Reviewed-by: Mike Christie +Cc: stable@vger.kernel.org +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/megaraid/megaraid_sas.h | 2 +- + drivers/scsi/megaraid/megaraid_sas_base.c | 21 +++++++++------------ + 2 files changed, 10 insertions(+), 13 deletions(-) + +diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h +index 80ae48b65b608..0d7cca9365aac 100644 +--- a/drivers/scsi/megaraid/megaraid_sas.h ++++ b/drivers/scsi/megaraid/megaraid_sas.h +@@ -2194,7 +2194,7 @@ struct megasas_instance { + u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */ + bool use_seqnum_jbod_fp; /* Added for PD sequence */ + bool smp_affinity_enable; +- spinlock_t crashdump_lock; ++ struct mutex crashdump_lock; + + struct megasas_register_set __iomem *reg_set; + u32 __iomem *reply_post_host_index_addr[MR_MAX_MSIX_REG_ARRAY]; +diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c +index 2b6b6d3deba86..bdfa36712fcc4 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_base.c ++++ b/drivers/scsi/megaraid/megaraid_sas_base.c +@@ -3004,14 +3004,13 @@ megasas_fw_crash_buffer_store(struct device *cdev, + struct megasas_instance *instance = + (struct megasas_instance *) shost->hostdata; + int val = 0; +- unsigned long flags; + + if (kstrtoint(buf, 0, &val) != 0) + return -EINVAL; + +- spin_lock_irqsave(&instance->crashdump_lock, flags); ++ mutex_lock(&instance->crashdump_lock); + instance->fw_crash_buffer_offset = val; +- spin_unlock_irqrestore(&instance->crashdump_lock, flags); ++ mutex_unlock(&instance->crashdump_lock); + return strlen(buf); + } + +@@ -3027,17 +3026,16 @@ megasas_fw_crash_buffer_show(struct device *cdev, + unsigned long dmachunk = CRASH_DMA_BUF_SIZE; + unsigned long chunk_left_bytes; + unsigned long src_addr; +- unsigned long flags; + u32 buff_offset; + +- spin_lock_irqsave(&instance->crashdump_lock, flags); ++ mutex_lock(&instance->crashdump_lock); + buff_offset = instance->fw_crash_buffer_offset; + if (!instance->crash_dump_buf || + !((instance->fw_crash_state == AVAILABLE) || + (instance->fw_crash_state == COPYING))) { + dev_err(&instance->pdev->dev, + "Firmware crash dump is not available\n"); +- spin_unlock_irqrestore(&instance->crashdump_lock, flags); ++ mutex_unlock(&instance->crashdump_lock); + return -EINVAL; + } + +@@ -3046,7 +3044,7 @@ megasas_fw_crash_buffer_show(struct device *cdev, + if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) { + dev_err(&instance->pdev->dev, + "Firmware crash dump offset is out of range\n"); +- spin_unlock_irqrestore(&instance->crashdump_lock, flags); ++ mutex_unlock(&instance->crashdump_lock); + return 0; + } + +@@ -3058,7 +3056,7 @@ megasas_fw_crash_buffer_show(struct device *cdev, + src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] + + (buff_offset % dmachunk); + memcpy(buf, (void *)src_addr, size); +- spin_unlock_irqrestore(&instance->crashdump_lock, flags); ++ mutex_unlock(&instance->crashdump_lock); + + return size; + } +@@ -3083,7 +3081,6 @@ megasas_fw_crash_state_store(struct device *cdev, + struct megasas_instance *instance = + (struct megasas_instance *) shost->hostdata; + int val = 0; +- unsigned long flags; + + if (kstrtoint(buf, 0, &val) != 0) + return -EINVAL; +@@ -3097,9 +3094,9 @@ megasas_fw_crash_state_store(struct device *cdev, + instance->fw_crash_state = val; + + if ((val == COPIED) || (val == COPY_ERROR)) { +- spin_lock_irqsave(&instance->crashdump_lock, flags); ++ mutex_lock(&instance->crashdump_lock); + megasas_free_host_crash_buffer(instance); +- spin_unlock_irqrestore(&instance->crashdump_lock, flags); ++ mutex_unlock(&instance->crashdump_lock); + if (val == COPY_ERROR) + dev_info(&instance->pdev->dev, "application failed to " + "copy Firmware crash dump\n"); +@@ -6463,7 +6460,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) + init_waitqueue_head(&instance->int_cmd_wait_q); + init_waitqueue_head(&instance->abort_cmd_wait_q); + +- spin_lock_init(&instance->crashdump_lock); ++ mutex_init(&instance->crashdump_lock); + spin_lock_init(&instance->mfi_pool_lock); + spin_lock_init(&instance->hba_lock); + spin_lock_init(&instance->stream_lock); +-- +2.40.1 + diff --git a/queue-4.19/scsi-megaraid_sas-load-balance-completions-across-al.patch b/queue-4.19/scsi-megaraid_sas-load-balance-completions-across-al.patch new file mode 100644 index 00000000000..f0710596e1b --- /dev/null +++ b/queue-4.19/scsi-megaraid_sas-load-balance-completions-across-al.patch @@ -0,0 +1,181 @@ +From 55ce88cf3cd84bb969f14dda7cd9030faffd71b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 May 2019 10:05:36 -0700 +Subject: scsi: megaraid_sas: Load balance completions across all MSI-X + +From: Shivasharan S + +[ Upstream commit 1d15d9098ad12b0021ac5a6b851f26d1ab021e5a ] + +Driver will use "reply descriptor post queues" in round robin fashion when +the combined MSI-X mode is not enabled. With this IO completions are +distributed and load balanced across all the available reply descriptor +post queues equally. + +This is enabled only if combined MSI-X mode is not enabled in firmware. +This improves performance and also fixes soft lockups. + +When load balancing is enabled, IRQ affinity from driver needs to be +disabled. + +Signed-off-by: Kashyap Desai +Signed-off-by: Shivasharan S +Signed-off-by: Martin K. Petersen +Stable-dep-of: 0b0747d507bf ("scsi: megaraid_sas: Fix deadlock on firmware crashdump") +Signed-off-by: Sasha Levin +--- + drivers/scsi/megaraid/megaraid_sas.h | 3 +++ + drivers/scsi/megaraid/megaraid_sas_base.c | 22 +++++++++++++++++---- + drivers/scsi/megaraid/megaraid_sas_fusion.c | 18 +++++++++++++---- + 3 files changed, 35 insertions(+), 8 deletions(-) + +diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h +index 67d356d847176..80ae48b65b608 100644 +--- a/drivers/scsi/megaraid/megaraid_sas.h ++++ b/drivers/scsi/megaraid/megaraid_sas.h +@@ -2193,6 +2193,7 @@ struct megasas_instance { + u32 secure_jbod_support; + u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */ + bool use_seqnum_jbod_fp; /* Added for PD sequence */ ++ bool smp_affinity_enable; + spinlock_t crashdump_lock; + + struct megasas_register_set __iomem *reg_set; +@@ -2210,6 +2211,7 @@ struct megasas_instance { + u16 ldio_threshold; + u16 cur_can_queue; + u32 max_sectors_per_req; ++ bool msix_load_balance; + struct megasas_aen_event *ev; + + struct megasas_cmd **cmd_list; +@@ -2246,6 +2248,7 @@ struct megasas_instance { + atomic_t sge_holes_type1; + atomic_t sge_holes_type2; + atomic_t sge_holes_type3; ++ atomic64_t total_io_count; + + struct megasas_instance_template *instancet; + struct tasklet_struct isr_tasklet; +diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c +index 8d1df03386b4f..2b6b6d3deba86 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_base.c ++++ b/drivers/scsi/megaraid/megaraid_sas_base.c +@@ -5101,6 +5101,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) + &instance->irq_context[j]); + /* Retry irq register for IO_APIC*/ + instance->msix_vectors = 0; ++ instance->msix_load_balance = false; + if (is_probe) { + pci_free_irq_vectors(instance->pdev); + return megasas_setup_irqs_ioapic(instance); +@@ -5109,6 +5110,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) + } + } + } ++ + return 0; + } + +@@ -5364,6 +5366,12 @@ static int megasas_init_fw(struct megasas_instance *instance) + if (rdpq_enable) + instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? + 1 : 0; ++ ++ if (!instance->msix_combined) { ++ instance->msix_load_balance = true; ++ instance->smp_affinity_enable = false; ++ } ++ + fw_msix_count = instance->msix_vectors; + /* Save 1-15 reply post index address to local memory + * Index 0 is already saved from reg offset +@@ -5382,17 +5390,20 @@ static int megasas_init_fw(struct megasas_instance *instance) + instance->msix_vectors); + } else /* MFI adapters */ + instance->msix_vectors = 1; ++ + /* Don't bother allocating more MSI-X vectors than cpus */ + instance->msix_vectors = min(instance->msix_vectors, + (unsigned int)num_online_cpus()); +- if (smp_affinity_enable) ++ if (instance->smp_affinity_enable) + irq_flags |= PCI_IRQ_AFFINITY; + i = pci_alloc_irq_vectors(instance->pdev, 1, + instance->msix_vectors, irq_flags); +- if (i > 0) ++ if (i > 0) { + instance->msix_vectors = i; +- else ++ } else { + instance->msix_vectors = 0; ++ instance->msix_load_balance = false; ++ } + } + /* + * MSI-X host index 0 is common for all adapter. +@@ -6447,6 +6458,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) + INIT_LIST_HEAD(&instance->internal_reset_pending_q); + + atomic_set(&instance->fw_outstanding, 0); ++ atomic64_set(&instance->total_io_count, 0); + + init_waitqueue_head(&instance->int_cmd_wait_q); + init_waitqueue_head(&instance->abort_cmd_wait_q); +@@ -6469,6 +6481,8 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) + instance->last_time = 0; + instance->disableOnlineCtrlReset = 1; + instance->UnevenSpanSupport = 0; ++ instance->smp_affinity_enable = smp_affinity_enable ? true : false; ++ instance->msix_load_balance = false; + + if (instance->adapter_type != MFI_SERIES) { + INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); +@@ -6818,7 +6832,7 @@ megasas_resume(struct pci_dev *pdev) + /* Now re-enable MSI-X */ + if (instance->msix_vectors) { + irq_flags = PCI_IRQ_MSIX; +- if (smp_affinity_enable) ++ if (instance->smp_affinity_enable) + irq_flags |= PCI_IRQ_AFFINITY; + } + rval = pci_alloc_irq_vectors(instance->pdev, 1, +diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c +index b400167f9ad42..294e1a3a6adfa 100644 +--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c ++++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c +@@ -2641,8 +2641,13 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, + fp_possible = (io_info.fpOkForIo > 0) ? true : false; + } + +- cmd->request_desc->SCSIIO.MSIxIndex = +- instance->reply_map[raw_smp_processor_id()]; ++ if (instance->msix_load_balance) ++ cmd->request_desc->SCSIIO.MSIxIndex = ++ (mega_mod64(atomic64_add_return(1, &instance->total_io_count), ++ instance->msix_vectors)); ++ else ++ cmd->request_desc->SCSIIO.MSIxIndex = ++ instance->reply_map[raw_smp_processor_id()]; + + praid_context = &io_request->RaidContext; + +@@ -2969,8 +2974,13 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, + + cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; + +- cmd->request_desc->SCSIIO.MSIxIndex = +- instance->reply_map[raw_smp_processor_id()]; ++ if (instance->msix_load_balance) ++ cmd->request_desc->SCSIIO.MSIxIndex = ++ (mega_mod64(atomic64_add_return(1, &instance->total_io_count), ++ instance->msix_vectors)); ++ else ++ cmd->request_desc->SCSIIO.MSIxIndex = ++ instance->reply_map[raw_smp_processor_id()]; + + if (!fp_possible) { + /* system pd firmware path */ +-- +2.40.1 + diff --git a/queue-4.19/scsi-qla2xxx-add-protection-mask-module-parameters.patch b/queue-4.19/scsi-qla2xxx-add-protection-mask-module-parameters.patch new file mode 100644 index 00000000000..859db7b516a --- /dev/null +++ b/queue-4.19/scsi-qla2xxx-add-protection-mask-module-parameters.patch @@ -0,0 +1,85 @@ +From e3c515b3a49c366558f2825541335093c9aeb991 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Dec 2018 09:33:44 -0800 +Subject: scsi: qla2xxx: Add protection mask module parameters + +From: Martin K. Petersen + +[ Upstream commit 7855d2ba1172d716d96a628af7c5bafa5725ac57 ] + +Allow user to selectively enable/disable DIF/DIX protection +capabilities mask. + +Signed-off-by: Martin K. Petersen +Signed-off-by: Himanshu Madhani +Signed-off-by: Martin K. Petersen +Stable-dep-of: e9105c4b7a92 ("scsi: qla2xxx: Remove unsupported ql2xenabledif option") +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_os.c | 36 +++++++++++++++++++++++++++-------- + 1 file changed, 28 insertions(+), 8 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index 4580774b2c3e7..27514d0abe845 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -277,6 +277,20 @@ MODULE_PARM_DESC(qla2xuseresexchforels, + "Reserve 1/2 of emergency exchanges for ELS.\n" + " 0 (default): disabled"); + ++int ql2xprotmask; ++module_param(ql2xprotmask, int, 0644); ++MODULE_PARM_DESC(ql2xprotmask, ++ "Override DIF/DIX protection capabilities mask\n" ++ "Default is 0 which sets protection mask based on " ++ "capabilities reported by HBA firmware.\n"); ++ ++int ql2xprotguard; ++module_param(ql2xprotguard, int, 0644); ++MODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n" ++ " 0 -- Let HBA firmware decide\n" ++ " 1 -- Force T10 CRC\n" ++ " 2 -- Force IP checksum\n"); ++ + /* + * SCSI host template entry points + */ +@@ -3293,13 +3307,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) + "Registering for DIF/DIX type 1 and 3 protection.\n"); + if (ql2xenabledif == 1) + prot = SHOST_DIX_TYPE0_PROTECTION; +- scsi_host_set_prot(host, +- prot | SHOST_DIF_TYPE1_PROTECTION +- | SHOST_DIF_TYPE2_PROTECTION +- | SHOST_DIF_TYPE3_PROTECTION +- | SHOST_DIX_TYPE1_PROTECTION +- | SHOST_DIX_TYPE2_PROTECTION +- | SHOST_DIX_TYPE3_PROTECTION); ++ if (ql2xprotmask) ++ scsi_host_set_prot(host, ql2xprotmask); ++ else ++ scsi_host_set_prot(host, ++ prot | SHOST_DIF_TYPE1_PROTECTION ++ | SHOST_DIF_TYPE2_PROTECTION ++ | SHOST_DIF_TYPE3_PROTECTION ++ | SHOST_DIX_TYPE1_PROTECTION ++ | SHOST_DIX_TYPE2_PROTECTION ++ | SHOST_DIX_TYPE3_PROTECTION); + + guard = SHOST_DIX_GUARD_CRC; + +@@ -3307,7 +3324,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) + (ql2xenabledif > 1 || IS_PI_DIFB_DIX0_CAPABLE(ha))) + guard |= SHOST_DIX_GUARD_IP; + +- scsi_host_set_guard(host, guard); ++ if (ql2xprotguard) ++ scsi_host_set_guard(host, ql2xprotguard); ++ else ++ scsi_host_set_guard(host, guard); + } else + base_vha->flags.difdix_supported = 0; + } +-- +2.40.1 + diff --git a/queue-4.19/scsi-qla2xxx-remove-unsupported-ql2xenabledif-option.patch b/queue-4.19/scsi-qla2xxx-remove-unsupported-ql2xenabledif-option.patch new file mode 100644 index 00000000000..c000990f2a2 --- /dev/null +++ b/queue-4.19/scsi-qla2xxx-remove-unsupported-ql2xenabledif-option.patch @@ -0,0 +1,84 @@ +From a845e49035f5cbcc27f60c2c9d081049a0a90bfd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Aug 2023 18:30:42 +0530 +Subject: scsi: qla2xxx: Remove unsupported ql2xenabledif option + +From: Manish Rangankar + +[ Upstream commit e9105c4b7a9208a21a9bda133707624f12ddabc2 ] + +User accidently passed module parameter ql2xenabledif=1 which is +unsupported. However, driver still initialized which lead to guard tag +errors during device discovery. + +Remove unsupported ql2xenabledif=1 option and validate the user input. + +Cc: stable@vger.kernel.org +Signed-off-by: Manish Rangankar +Signed-off-by: Nilesh Javali +Link: https://lore.kernel.org/r/20230821130045.34850-7-njavali@marvell.com +Reviewed-by: Himanshu Madhani +Signed-off-by: Martin K. Petersen +Signed-off-by: Sasha Levin +--- + drivers/scsi/qla2xxx/qla_attr.c | 2 -- + drivers/scsi/qla2xxx/qla_dbg.c | 2 +- + drivers/scsi/qla2xxx/qla_os.c | 9 +++++++-- + 3 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c +index 6c9095d0aa0f4..9a25e92ef1abe 100644 +--- a/drivers/scsi/qla2xxx/qla_attr.c ++++ b/drivers/scsi/qla2xxx/qla_attr.c +@@ -2088,8 +2088,6 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) + vha->flags.difdix_supported = 1; + ql_dbg(ql_dbg_user, vha, 0x7082, + "Registered for DIF/DIX type 1 and 3 protection.\n"); +- if (ql2xenabledif == 1) +- prot = SHOST_DIX_TYPE0_PROTECTION; + scsi_host_set_prot(vha->host, + prot | SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE2_PROTECTION +diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c +index 36871760a5d37..fcbadd41856c2 100644 +--- a/drivers/scsi/qla2xxx/qla_dbg.c ++++ b/drivers/scsi/qla2xxx/qla_dbg.c +@@ -22,7 +22,7 @@ + * | Queue Command and IO tracing | 0x3074 | 0x300b | + * | | | 0x3027-0x3028 | + * | | | 0x303d-0x3041 | +- * | | | 0x302d,0x3033 | ++ * | | | 0x302e,0x3033 | + * | | | 0x3036,0x3038 | + * | | | 0x303a | + * | DPC Thread | 0x4023 | 0x4002,0x4013 | +diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c +index 27514d0abe845..36dca08166f29 100644 +--- a/drivers/scsi/qla2xxx/qla_os.c ++++ b/drivers/scsi/qla2xxx/qla_os.c +@@ -3069,6 +3069,13 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) + host->max_id = ha->max_fibre_devices; + host->cmd_per_lun = 3; + host->unique_id = host->host_no; ++ ++ if (ql2xenabledif && ql2xenabledif != 2) { ++ ql_log(ql_log_warn, base_vha, 0x302d, ++ "Invalid value for ql2xenabledif, resetting it to default (2)\n"); ++ ql2xenabledif = 2; ++ } ++ + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) + host->max_cmd_len = 32; + else +@@ -3305,8 +3312,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) + base_vha->flags.difdix_supported = 1; + ql_dbg(ql_dbg_init, base_vha, 0x00f1, + "Registering for DIF/DIX type 1 and 3 protection.\n"); +- if (ql2xenabledif == 1) +- prot = SHOST_DIX_TYPE0_PROTECTION; + if (ql2xprotmask) + scsi_host_set_prot(host, ql2xprotmask); + else +-- +2.40.1 + diff --git a/queue-4.19/series b/queue-4.19/series index f87bd80c5f7..3dd27adc8fa 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -12,3 +12,20 @@ net-bridge-use-dev_stats_inc.patch team-fix-null-ptr-deref-when-team-device-type-is-cha.patch gpio-tb10x-fix-an-error-handling-path-in-tb10x_gpio_.patch i2c-mux-demux-pinctrl-check-the-return-value-of-devm.patch +input-i8042-add-quirk-for-tuxedo-gemini-17-gen1-clev.patch +scsi-qla2xxx-add-protection-mask-module-parameters.patch +scsi-qla2xxx-remove-unsupported-ql2xenabledif-option.patch +usb-typec-group-all-tcpci-tcpm-code-together.patch +usb-typec-tcpm-refactor-tcpm_handle_vdm_request-payl.patch +usb-typec-tcpm-refactor-tcpm_handle_vdm_request.patch +usb-typec-bus-verify-partner-exists-in-typec_altmode.patch +scsi-megaraid_sas-load-balance-completions-across-al.patch +scsi-megaraid_sas-fix-deadlock-on-firmware-crashdump.patch +ext4-remove-the-group-parameter-of-ext4_trim_extent.patch +ext4-add-new-helper-interface-ext4_try_to_trim_range.patch +ext4-scope-ret-locally-in-ext4_try_to_trim_range.patch +ext4-change-s_last_trim_minblks-type-to-unsigned-lon.patch +ext4-mark-group-as-trimmed-only-if-it-was-fully-scan.patch +ext4-replace-the-traditional-ternary-conditional-ope.patch +ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch +ext4-do-not-let-fstrim-block-system-suspend.patch diff --git a/queue-4.19/usb-typec-bus-verify-partner-exists-in-typec_altmode.patch b/queue-4.19/usb-typec-bus-verify-partner-exists-in-typec_altmode.patch new file mode 100644 index 00000000000..37b21951b83 --- /dev/null +++ b/queue-4.19/usb-typec-bus-verify-partner-exists-in-typec_altmode.patch @@ -0,0 +1,93 @@ +From a73fdd2d1d0ccdd40a7832fc85a8a7d6239b688e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Aug 2023 18:05:59 +0000 +Subject: usb: typec: bus: verify partner exists in typec_altmode_attention + +From: RD Babiera + +[ Upstream commit f23643306430f86e2f413ee2b986e0773e79da31 ] + +Some usb hubs will negotiate DisplayPort Alt mode with the device +but will then negotiate a data role swap after entering the alt +mode. The data role swap causes the device to unregister all alt +modes, however the usb hub will still send Attention messages +even after failing to reregister the Alt Mode. type_altmode_attention +currently does not verify whether or not a device's altmode partner +exists, which results in a NULL pointer error when dereferencing +the typec_altmode and typec_altmode_ops belonging to the altmode +partner. + +Verify the presence of a device's altmode partner before sending +the Attention message to the Alt Mode driver. + +Fixes: 8a37d87d72f0 ("usb: typec: Bus type for alternate modes") +Cc: stable@vger.kernel.org +Signed-off-by: RD Babiera +Reviewed-by: Heikki Krogerus +Reviewed-by: Guenter Roeck +Link: https://lore.kernel.org/r/20230814180559.923475-1-rdbabiera@google.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/bus.c | 12 ++++++++++-- + drivers/usb/typec/tcpm/tcpm.c | 3 ++- + include/linux/usb/typec_altmode.h | 2 +- + 3 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c +index 7605963f71ede..31188354bca04 100644 +--- a/drivers/usb/typec/bus.c ++++ b/drivers/usb/typec/bus.c +@@ -146,12 +146,20 @@ EXPORT_SYMBOL_GPL(typec_altmode_exit); + * + * Notifies the partner of @adev about Attention command. + */ +-void typec_altmode_attention(struct typec_altmode *adev, u32 vdo) ++int typec_altmode_attention(struct typec_altmode *adev, u32 vdo) + { +- struct typec_altmode *pdev = &to_altmode(adev)->partner->adev; ++ struct altmode *partner = to_altmode(adev)->partner; ++ struct typec_altmode *pdev; ++ ++ if (!partner) ++ return -ENODEV; ++ ++ pdev = &partner->adev; + + if (pdev->ops && pdev->ops->attention) + pdev->ops->attention(pdev, vdo); ++ ++ return 0; + } + EXPORT_SYMBOL_GPL(typec_altmode_attention); + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 9cb781e6a0b53..c5132f2942f71 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -1258,7 +1258,8 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, + } + break; + case ADEV_ATTENTION: +- typec_altmode_attention(adev, p[1]); ++ if (typec_altmode_attention(adev, p[1])) ++ tcpm_log(port, "typec_altmode_attention no port partner altmode"); + break; + } + } +diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h +index 9a88c74a1d0d0..969b7c5040875 100644 +--- a/include/linux/usb/typec_altmode.h ++++ b/include/linux/usb/typec_altmode.h +@@ -67,7 +67,7 @@ struct typec_altmode_ops { + + int typec_altmode_enter(struct typec_altmode *altmode); + int typec_altmode_exit(struct typec_altmode *altmode); +-void typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); ++int typec_altmode_attention(struct typec_altmode *altmode, u32 vdo); + int typec_altmode_vdm(struct typec_altmode *altmode, + const u32 header, const u32 *vdo, int count); + int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf, +-- +2.40.1 + diff --git a/queue-4.19/usb-typec-group-all-tcpci-tcpm-code-together.patch b/queue-4.19/usb-typec-group-all-tcpci-tcpm-code-together.patch new file mode 100644 index 00000000000..a027fd043fe --- /dev/null +++ b/queue-4.19/usb-typec-group-all-tcpci-tcpm-code-together.patch @@ -0,0 +1,259 @@ +From f2618e9c223c548dead24007d7ee7ab21531cab4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Sep 2018 14:23:47 +0300 +Subject: usb: typec: Group all TCPCI/TCPM code together + +From: Heikki Krogerus + +[ Upstream commit ae8a2ca8a2215c7e31e6d874f7303801bb15fbbc ] + +Moving all the drivers that depend on the Port Controller +Manager under a new directory drivers/usb/typec/tcpm/ and +making Guenter Roeck the designated reviewer of that code. + +Acked-by: Guenter Roeck +Signed-off-by: Heikki Krogerus +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: f23643306430 ("usb: typec: bus: verify partner exists in typec_altmode_attention") +Signed-off-by: Sasha Levin +--- + MAINTAINERS | 6 +++ + drivers/usb/typec/Kconfig | 45 +--------------- + drivers/usb/typec/Makefile | 6 +-- + drivers/usb/typec/fusb302/Kconfig | 7 --- + drivers/usb/typec/fusb302/Makefile | 2 - + drivers/usb/typec/tcpm/Kconfig | 52 +++++++++++++++++++ + drivers/usb/typec/tcpm/Makefile | 7 +++ + drivers/usb/typec/{fusb302 => tcpm}/fusb302.c | 0 + .../usb/typec/{fusb302 => tcpm}/fusb302_reg.h | 0 + drivers/usb/typec/{ => tcpm}/tcpci.c | 0 + drivers/usb/typec/{ => tcpm}/tcpci.h | 0 + drivers/usb/typec/{ => tcpm}/tcpci_rt1711h.c | 0 + drivers/usb/typec/{ => tcpm}/tcpm.c | 0 + .../usb/typec/{typec_wcove.c => tcpm/wcove.c} | 0 + 14 files changed, 67 insertions(+), 58 deletions(-) + delete mode 100644 drivers/usb/typec/fusb302/Kconfig + delete mode 100644 drivers/usb/typec/fusb302/Makefile + create mode 100644 drivers/usb/typec/tcpm/Kconfig + create mode 100644 drivers/usb/typec/tcpm/Makefile + rename drivers/usb/typec/{fusb302 => tcpm}/fusb302.c (100%) + rename drivers/usb/typec/{fusb302 => tcpm}/fusb302_reg.h (100%) + rename drivers/usb/typec/{ => tcpm}/tcpci.c (100%) + rename drivers/usb/typec/{ => tcpm}/tcpci.h (100%) + rename drivers/usb/typec/{ => tcpm}/tcpci_rt1711h.c (100%) + rename drivers/usb/typec/{ => tcpm}/tcpm.c (100%) + rename drivers/usb/typec/{typec_wcove.c => tcpm/wcove.c} (100%) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 59003315a9597..bf33725ca5157 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15307,6 +15307,12 @@ F: Documentation/driver-api/usb/typec_bus.rst + F: drivers/usb/typec/altmodes/ + F: include/linux/usb/typec_altmode.h + ++USB TYPEC PORT CONTROLLER DRIVERS ++M: Guenter Roeck ++L: linux-usb@vger.kernel.org ++S: Maintained ++F: drivers/usb/typec/tcpm/ ++ + USB UHCI DRIVER + M: Alan Stern + L: linux-usb@vger.kernel.org +diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig +index 8445890accdfe..e078f23e3f8d5 100644 +--- a/drivers/usb/typec/Kconfig ++++ b/drivers/usb/typec/Kconfig +@@ -45,50 +45,7 @@ menuconfig TYPEC + + if TYPEC + +-config TYPEC_TCPM +- tristate "USB Type-C Port Controller Manager" +- depends on USB +- select USB_ROLE_SWITCH +- select POWER_SUPPLY +- help +- The Type-C Port Controller Manager provides a USB PD and USB Type-C +- state machine for use with Type-C Port Controllers. +- +-if TYPEC_TCPM +- +-config TYPEC_TCPCI +- tristate "Type-C Port Controller Interface driver" +- depends on I2C +- select REGMAP_I2C +- help +- Type-C Port Controller driver for TCPCI-compliant controller. +- +-config TYPEC_RT1711H +- tristate "Richtek RT1711H Type-C chip driver" +- depends on I2C +- select TYPEC_TCPCI +- help +- Richtek RT1711H Type-C chip driver that works with +- Type-C Port Controller Manager to provide USB PD and USB +- Type-C functionalities. +- +-source "drivers/usb/typec/fusb302/Kconfig" +- +-config TYPEC_WCOVE +- tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" +- depends on ACPI +- depends on INTEL_SOC_PMIC +- depends on INTEL_PMC_IPC +- depends on BXT_WC_PMIC_OPREGION +- help +- This driver adds support for USB Type-C detection on Intel Broxton +- platforms that have Intel Whiskey Cove PMIC. The driver can detect the +- role and cable orientation. +- +- To compile this driver as module, choose M here: the module will be +- called typec_wcove +- +-endif # TYPEC_TCPM ++source "drivers/usb/typec/tcpm/Kconfig" + + source "drivers/usb/typec/ucsi/Kconfig" + +diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile +index 45b0aef428a82..6696b7263d61a 100644 +--- a/drivers/usb/typec/Makefile ++++ b/drivers/usb/typec/Makefile +@@ -2,11 +2,7 @@ + obj-$(CONFIG_TYPEC) += typec.o + typec-y := class.o mux.o bus.o + obj-$(CONFIG_TYPEC) += altmodes/ +-obj-$(CONFIG_TYPEC_TCPM) += tcpm.o +-obj-y += fusb302/ +-obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o ++obj-$(CONFIG_TYPEC_TCPM) += tcpm/ + obj-$(CONFIG_TYPEC_UCSI) += ucsi/ + obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o + obj-$(CONFIG_TYPEC) += mux/ +-obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o +-obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o +diff --git a/drivers/usb/typec/fusb302/Kconfig b/drivers/usb/typec/fusb302/Kconfig +deleted file mode 100644 +index fce099ff39fea..0000000000000 +--- a/drivers/usb/typec/fusb302/Kconfig ++++ /dev/null +@@ -1,7 +0,0 @@ +-config TYPEC_FUSB302 +- tristate "Fairchild FUSB302 Type-C chip driver" +- depends on I2C +- help +- The Fairchild FUSB302 Type-C chip driver that works with +- Type-C Port Controller Manager to provide USB PD and USB +- Type-C functionalities. +diff --git a/drivers/usb/typec/fusb302/Makefile b/drivers/usb/typec/fusb302/Makefile +deleted file mode 100644 +index 3b51b33631a08..0000000000000 +--- a/drivers/usb/typec/fusb302/Makefile ++++ /dev/null +@@ -1,2 +0,0 @@ +-# SPDX-License-Identifier: GPL-2.0 +-obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o +diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig +new file mode 100644 +index 0000000000000..f03ea8a617686 +--- /dev/null ++++ b/drivers/usb/typec/tcpm/Kconfig +@@ -0,0 +1,52 @@ ++config TYPEC_TCPM ++ tristate "USB Type-C Port Controller Manager" ++ depends on USB ++ select USB_ROLE_SWITCH ++ select POWER_SUPPLY ++ help ++ The Type-C Port Controller Manager provides a USB PD and USB Type-C ++ state machine for use with Type-C Port Controllers. ++ ++if TYPEC_TCPM ++ ++config TYPEC_TCPCI ++ tristate "Type-C Port Controller Interface driver" ++ depends on I2C ++ select REGMAP_I2C ++ help ++ Type-C Port Controller driver for TCPCI-compliant controller. ++ ++if TYPEC_TCPCI ++ ++config TYPEC_RT1711H ++ tristate "Richtek RT1711H Type-C chip driver" ++ help ++ Richtek RT1711H Type-C chip driver that works with ++ Type-C Port Controller Manager to provide USB PD and USB ++ Type-C functionalities. ++ ++endif # TYPEC_TCPCI ++ ++config TYPEC_FUSB302 ++ tristate "Fairchild FUSB302 Type-C chip driver" ++ depends on I2C ++ help ++ The Fairchild FUSB302 Type-C chip driver that works with ++ Type-C Port Controller Manager to provide USB PD and USB ++ Type-C functionalities. ++ ++config TYPEC_WCOVE ++ tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" ++ depends on ACPI ++ depends on INTEL_SOC_PMIC ++ depends on INTEL_PMC_IPC ++ depends on BXT_WC_PMIC_OPREGION ++ help ++ This driver adds support for USB Type-C on Intel Broxton platforms ++ that have Intel Whiskey Cove PMIC. The driver works with USB Type-C ++ Port Controller Manager to provide USB PD and Type-C functionalities. ++ ++ To compile this driver as module, choose M here: the module will be ++ called typec_wcove.ko ++ ++endif # TYPEC_TCPM +diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile +new file mode 100644 +index 0000000000000..a5ff6c8eb8922 +--- /dev/null ++++ b/drivers/usb/typec/tcpm/Makefile +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_TYPEC_TCPM) += tcpm.o ++obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o ++obj-$(CONFIG_TYPEC_WCOVE) += typec_wcove.o ++typec_wcove-y := wcove.o ++obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o ++obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o +diff --git a/drivers/usb/typec/fusb302/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +similarity index 100% +rename from drivers/usb/typec/fusb302/fusb302.c +rename to drivers/usb/typec/tcpm/fusb302.c +diff --git a/drivers/usb/typec/fusb302/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h +similarity index 100% +rename from drivers/usb/typec/fusb302/fusb302_reg.h +rename to drivers/usb/typec/tcpm/fusb302_reg.h +diff --git a/drivers/usb/typec/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c +similarity index 100% +rename from drivers/usb/typec/tcpci.c +rename to drivers/usb/typec/tcpm/tcpci.c +diff --git a/drivers/usb/typec/tcpci.h b/drivers/usb/typec/tcpm/tcpci.h +similarity index 100% +rename from drivers/usb/typec/tcpci.h +rename to drivers/usb/typec/tcpm/tcpci.h +diff --git a/drivers/usb/typec/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c +similarity index 100% +rename from drivers/usb/typec/tcpci_rt1711h.c +rename to drivers/usb/typec/tcpm/tcpci_rt1711h.c +diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +similarity index 100% +rename from drivers/usb/typec/tcpm.c +rename to drivers/usb/typec/tcpm/tcpm.c +diff --git a/drivers/usb/typec/typec_wcove.c b/drivers/usb/typec/tcpm/wcove.c +similarity index 100% +rename from drivers/usb/typec/typec_wcove.c +rename to drivers/usb/typec/tcpm/wcove.c +-- +2.40.1 + diff --git a/queue-4.19/usb-typec-tcpm-refactor-tcpm_handle_vdm_request-payl.patch b/queue-4.19/usb-typec-tcpm-refactor-tcpm_handle_vdm_request-payl.patch new file mode 100644 index 00000000000..f2ad1a2daba --- /dev/null +++ b/queue-4.19/usb-typec-tcpm-refactor-tcpm_handle_vdm_request-payl.patch @@ -0,0 +1,186 @@ +From 85a3921f0d91a275cdd0ede4cf05bf66ce215388 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2020 19:46:59 +0200 +Subject: usb: typec: tcpm: Refactor tcpm_handle_vdm_request payload handling + +From: Hans de Goede + +[ Upstream commit 8afe9a3548f9d1805dcea6d97978f2179c8403a3 ] + +Refactor the tcpm_handle_vdm_request payload handling by doing the +endianness conversion only once directly inside tcpm_handle_vdm_request +itself instead of doing it multiple times inside various helper functions +called by tcpm_handle_vdm_request. + +This is a preparation patch for some further refactoring to fix an AB BA +lock inversion between the tcpm code and some altmode drivers. + +Reviewed-by: Guenter Roeck +Reviewed-by: Heikki Krogerus +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20200724174702.61754-3-hdegoede@redhat.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: f23643306430 ("usb: typec: bus: verify partner exists in typec_altmode_attention") +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/tcpm/tcpm.c | 49 ++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 27 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 0fdae44c9b8cf..7487efbd8c2d3 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -957,16 +957,15 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, + port->vdm_state = VDM_STATE_READY; + } + +-static void svdm_consume_identity(struct tcpm_port *port, const __le32 *payload, +- int cnt) ++static void svdm_consume_identity(struct tcpm_port *port, const u32 *p, int cnt) + { +- u32 vdo = le32_to_cpu(payload[VDO_INDEX_IDH]); +- u32 product = le32_to_cpu(payload[VDO_INDEX_PRODUCT]); ++ u32 vdo = p[VDO_INDEX_IDH]; ++ u32 product = p[VDO_INDEX_PRODUCT]; + + memset(&port->mode_data, 0, sizeof(port->mode_data)); + + port->partner_ident.id_header = vdo; +- port->partner_ident.cert_stat = le32_to_cpu(payload[VDO_INDEX_CSTAT]); ++ port->partner_ident.cert_stat = p[VDO_INDEX_CSTAT]; + port->partner_ident.product = product; + + typec_partner_set_identity(port->partner); +@@ -976,17 +975,15 @@ static void svdm_consume_identity(struct tcpm_port *port, const __le32 *payload, + PD_PRODUCT_PID(product), product & 0xffff); + } + +-static bool svdm_consume_svids(struct tcpm_port *port, const __le32 *payload, +- int cnt) ++static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt) + { + struct pd_mode_data *pmdata = &port->mode_data; + int i; + + for (i = 1; i < cnt; i++) { +- u32 p = le32_to_cpu(payload[i]); + u16 svid; + +- svid = (p >> 16) & 0xffff; ++ svid = (p[i] >> 16) & 0xffff; + if (!svid) + return false; + +@@ -996,7 +993,7 @@ static bool svdm_consume_svids(struct tcpm_port *port, const __le32 *payload, + pmdata->svids[pmdata->nsvids++] = svid; + tcpm_log(port, "SVID %d: 0x%x", pmdata->nsvids, svid); + +- svid = p & 0xffff; ++ svid = p[i] & 0xffff; + if (!svid) + return false; + +@@ -1026,8 +1023,7 @@ static bool svdm_consume_svids(struct tcpm_port *port, const __le32 *payload, + return false; + } + +-static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload, +- int cnt) ++static void svdm_consume_modes(struct tcpm_port *port, const u32 *p, int cnt) + { + struct pd_mode_data *pmdata = &port->mode_data; + struct typec_altmode_desc *paltmode; +@@ -1044,7 +1040,7 @@ static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload, + + paltmode->svid = pmdata->svids[pmdata->svid_index]; + paltmode->mode = i; +- paltmode->vdo = le32_to_cpu(payload[i]); ++ paltmode->vdo = p[i]; + + tcpm_log(port, " Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x", + pmdata->altmodes, paltmode->svid, +@@ -1072,21 +1068,17 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port) + + #define supports_modal(port) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header) + +-static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, ++static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt, + u32 *response) + { + struct typec_altmode *adev; + struct typec_altmode *pdev; + struct pd_mode_data *modep; +- u32 p[PD_MAX_PAYLOAD]; + int rlen = 0; + int cmd_type; + int cmd; + int i; + +- for (i = 0; i < cnt; i++) +- p[i] = le32_to_cpu(payload[i]); +- + cmd_type = PD_VDO_CMDT(p[0]); + cmd = PD_VDO_CMD(p[0]); + +@@ -1147,13 +1139,13 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, + switch (cmd) { + case CMD_DISCOVER_IDENT: + /* 6.4.4.3.1 */ +- svdm_consume_identity(port, payload, cnt); ++ svdm_consume_identity(port, p, cnt); + response[0] = VDO(USB_SID_PD, 1, CMD_DISCOVER_SVID); + rlen = 1; + break; + case CMD_DISCOVER_SVID: + /* 6.4.4.3.2 */ +- if (svdm_consume_svids(port, payload, cnt)) { ++ if (svdm_consume_svids(port, p, cnt)) { + response[0] = VDO(USB_SID_PD, 1, + CMD_DISCOVER_SVID); + rlen = 1; +@@ -1165,7 +1157,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, + break; + case CMD_DISCOVER_MODES: + /* 6.4.4.3.3 */ +- svdm_consume_modes(port, payload, cnt); ++ svdm_consume_modes(port, p, cnt); + modep->svid_index++; + if (modep->svid_index < modep->nsvids) { + u16 svid = modep->svids[modep->svid_index]; +@@ -1228,15 +1220,18 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt, + static void tcpm_handle_vdm_request(struct tcpm_port *port, + const __le32 *payload, int cnt) + { +- int rlen = 0; ++ u32 p[PD_MAX_PAYLOAD]; + u32 response[8] = { }; +- u32 p0 = le32_to_cpu(payload[0]); ++ int i, rlen = 0; ++ ++ for (i = 0; i < cnt; i++) ++ p[i] = le32_to_cpu(payload[i]); + + if (port->vdm_state == VDM_STATE_BUSY) { + /* If UFP responded busy retry after timeout */ +- if (PD_VDO_CMDT(p0) == CMDT_RSP_BUSY) { ++ if (PD_VDO_CMDT(p[0]) == CMDT_RSP_BUSY) { + port->vdm_state = VDM_STATE_WAIT_RSP_BUSY; +- port->vdo_retry = (p0 & ~VDO_CMDT_MASK) | ++ port->vdo_retry = (p[0] & ~VDO_CMDT_MASK) | + CMDT_INIT; + mod_delayed_work(port->wq, &port->vdm_state_machine, + msecs_to_jiffies(PD_T_VDM_BUSY)); +@@ -1245,8 +1240,8 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, + port->vdm_state = VDM_STATE_DONE; + } + +- if (PD_VDO_SVDM(p0)) +- rlen = tcpm_pd_svdm(port, payload, cnt, response); ++ if (PD_VDO_SVDM(p[0])) ++ rlen = tcpm_pd_svdm(port, p, cnt, response); + + if (rlen > 0) { + tcpm_queue_vdm(port, response[0], &response[1], rlen - 1); +-- +2.40.1 + diff --git a/queue-4.19/usb-typec-tcpm-refactor-tcpm_handle_vdm_request.patch b/queue-4.19/usb-typec-tcpm-refactor-tcpm_handle_vdm_request.patch new file mode 100644 index 00000000000..9486df77115 --- /dev/null +++ b/queue-4.19/usb-typec-tcpm-refactor-tcpm_handle_vdm_request.patch @@ -0,0 +1,187 @@ +From f466ff43d249d583e28dbece37f4110f9c1f8239 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2020 19:47:00 +0200 +Subject: usb: typec: tcpm: Refactor tcpm_handle_vdm_request + +From: Hans de Goede + +[ Upstream commit 95b4d51c96a87cd760c2a4f27fb28a59a27b6368 ] + +Refactor tcpm_handle_vdm_request and its tcpm_pd_svdm helper function so +that reporting the results of the vdm to the altmode-driver is separated +out into a clear separate step inside tcpm_handle_vdm_request, instead +of being scattered over various places inside the tcpm_pd_svdm helper. + +This is a preparation patch for fixing an AB BA lock inversion between the +tcpm code and some altmode drivers. + +Reviewed-by: Heikki Krogerus +Reviewed-by: Guenter Roeck +Signed-off-by: Hans de Goede +Link: https://lore.kernel.org/r/20200724174702.61754-4-hdegoede@redhat.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: f23643306430 ("usb: typec: bus: verify partner exists in typec_altmode_attention") +Signed-off-by: Sasha Levin +--- + drivers/usb/typec/tcpm/tcpm.c | 76 ++++++++++++++++++++++------------- + 1 file changed, 48 insertions(+), 28 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 7487efbd8c2d3..9cb781e6a0b53 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -158,6 +158,14 @@ enum pd_msg_request { + PD_MSG_DATA_SOURCE_CAP, + }; + ++enum adev_actions { ++ ADEV_NONE = 0, ++ ADEV_NOTIFY_USB_AND_QUEUE_VDM, ++ ADEV_QUEUE_VDM, ++ ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL, ++ ADEV_ATTENTION, ++}; ++ + /* Events from low level driver */ + + #define TCPM_CC_EVENT BIT(0) +@@ -1068,10 +1076,10 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port) + + #define supports_modal(port) PD_IDH_MODAL_SUPP((port)->partner_ident.id_header) + +-static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt, +- u32 *response) ++static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, ++ const u32 *p, int cnt, u32 *response, ++ enum adev_actions *adev_action) + { +- struct typec_altmode *adev; + struct typec_altmode *pdev; + struct pd_mode_data *modep; + int rlen = 0; +@@ -1087,9 +1095,6 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt, + + modep = &port->mode_data; + +- adev = typec_match_altmode(port->port_altmode, ALTMODE_DISCOVERY_MAX, +- PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0])); +- + pdev = typec_match_altmode(port->partner_altmode, ALTMODE_DISCOVERY_MAX, + PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0])); + +@@ -1115,8 +1120,7 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt, + break; + case CMD_ATTENTION: + /* Attention command does not have response */ +- if (adev) +- typec_altmode_attention(adev, p[1]); ++ *adev_action = ADEV_ATTENTION; + return 0; + default: + break; +@@ -1170,23 +1174,15 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt, + case CMD_ENTER_MODE: + if (adev && pdev) { + typec_altmode_update_active(pdev, true); +- +- if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) { +- response[0] = VDO(adev->svid, 1, +- CMD_EXIT_MODE); +- response[0] |= VDO_OPOS(adev->mode); +- return 1; +- } ++ *adev_action = ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL; + } + return 0; + case CMD_EXIT_MODE: + if (adev && pdev) { + typec_altmode_update_active(pdev, false); +- + /* Back to USB Operation */ +- WARN_ON(typec_altmode_notify(adev, +- TYPEC_STATE_USB, +- NULL)); ++ *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM; ++ return 0; + } + break; + default: +@@ -1197,11 +1193,8 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt, + switch (cmd) { + case CMD_ENTER_MODE: + /* Back to USB Operation */ +- if (adev) +- WARN_ON(typec_altmode_notify(adev, +- TYPEC_STATE_USB, +- NULL)); +- break; ++ *adev_action = ADEV_NOTIFY_USB_AND_QUEUE_VDM; ++ return 0; + default: + break; + } +@@ -1211,15 +1204,15 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const u32 *p, int cnt, + } + + /* Informing the alternate mode drivers about everything */ +- if (adev) +- typec_altmode_vdm(adev, p[0], &p[1], cnt); +- ++ *adev_action = ADEV_QUEUE_VDM; + return rlen; + } + + static void tcpm_handle_vdm_request(struct tcpm_port *port, + const __le32 *payload, int cnt) + { ++ enum adev_actions adev_action = ADEV_NONE; ++ struct typec_altmode *adev; + u32 p[PD_MAX_PAYLOAD]; + u32 response[8] = { }; + int i, rlen = 0; +@@ -1227,6 +1220,9 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, + for (i = 0; i < cnt; i++) + p[i] = le32_to_cpu(payload[i]); + ++ adev = typec_match_altmode(port->port_altmode, ALTMODE_DISCOVERY_MAX, ++ PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0])); ++ + if (port->vdm_state == VDM_STATE_BUSY) { + /* If UFP responded busy retry after timeout */ + if (PD_VDO_CMDT(p[0]) == CMDT_RSP_BUSY) { +@@ -1241,7 +1237,31 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, + } + + if (PD_VDO_SVDM(p[0])) +- rlen = tcpm_pd_svdm(port, p, cnt, response); ++ rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action); ++ ++ if (adev) { ++ switch (adev_action) { ++ case ADEV_NONE: ++ break; ++ case ADEV_NOTIFY_USB_AND_QUEUE_VDM: ++ WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL)); ++ typec_altmode_vdm(adev, p[0], &p[1], cnt); ++ break; ++ case ADEV_QUEUE_VDM: ++ typec_altmode_vdm(adev, p[0], &p[1], cnt); ++ break; ++ case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL: ++ if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) { ++ response[0] = VDO(adev->svid, 1, CMD_EXIT_MODE); ++ response[0] |= VDO_OPOS(adev->mode); ++ rlen = 1; ++ } ++ break; ++ case ADEV_ATTENTION: ++ typec_altmode_attention(adev, p[1]); ++ break; ++ } ++ } + + if (rlen > 0) { + tcpm_queue_vdm(port, response[0], &response[1], rlen - 1); +-- +2.40.1 +