From: Sasha Levin Date: Tue, 8 Apr 2025 00:42:37 +0000 (-0400) Subject: Fixes for 6.12 X-Git-Tag: v5.4.292~73 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bedd3213bfaa3378e335c6532a6d973e19fa678b;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.12 Signed-off-by: Sasha Levin --- diff --git a/queue-6.12/arm64-dts-rockchip-add-missing-pcie-supplies-to-rock.patch b/queue-6.12/arm64-dts-rockchip-add-missing-pcie-supplies-to-rock.patch new file mode 100644 index 0000000000..c3a8db4ef8 --- /dev/null +++ b/queue-6.12/arm64-dts-rockchip-add-missing-pcie-supplies-to-rock.patch @@ -0,0 +1,91 @@ +From 8aee6471dd6b35fc567fb1629dbeb376bfd80a93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 2 Mar 2025 19:48:04 +0100 +Subject: arm64: dts: rockchip: Add missing PCIe supplies to RockPro64 board + dtsi + +From: Dragan Simic + +[ Upstream commit ffcef3df680c437ca33ff434be18ec24d72907c2 ] + +Add missing "vpcie0v9-supply" and "vpcie1v8-supply" properties to the "pcie0" +node in the Pine64 RockPro64 board dtsi file. This eliminates the following +warnings from the kernel log: + + rockchip-pcie f8000000.pcie: supply vpcie1v8 not found, using dummy regulator + rockchip-pcie f8000000.pcie: supply vpcie0v9 not found, using dummy regulator + +These additions improve the accuracy of hardware description of the RockPro64 +and, in theory, they should result in no functional changes to the way board +works after the changes, because the "vcca_0v9" and "vcca_1v8" regulators are +always enabled. [1][2] However, extended reliability testing, performed by +Chris, [3] has proven that the age-old issues with some PCI Express cards, +when used with a Pine64 RockPro64, are also resolved. + +Those issues were already mentioned in the commit 43853e843aa6 (arm64: dts: +rockchip: Remove unsupported node from the Pinebook Pro dts, 2024-04-01), +together with a brief description of the out-of-tree enumeration delay patch +that reportedly resolves those issues. In a nutshell, booting a RockPro64 +with some PCI Express cards attached to it caused a kernel oops. [4] + +Symptomatically enough, to the commit author's best knowledge, only the Pine64 +RockPro64, out of all RK3399-based boards and devices supported upstream, has +been reported to suffer from those PCI Express issues, and only the RockPro64 +had some of the PCI Express supplies missing in its DT. Thus, perhaps some +weird timing issues exist that caused the "vcca_1v8" always-on regulator, +which is part of the RK808 PMIC, to actually not be enabled before the PCI +Express is initialized and enumerated on the RockPro64, causing oopses with +some PCIe cards, and the aforementioned enumeration delay patch [4] probably +acted as just a workaround for the underlying timing issue. + +Admittedly, the Pine64 RockPro64 is a bit specific board by having a standard +PCI Express slot, allowing use of various standard cards, but pretty much +standard PCI Express cards have been attached to other RK3399 boards as well, +and the commit author is unaware ot such issues reported for them. + +It's quite hard to be sure that the PCI Express issues are fully resolved by +these additions to the DT, without some really extensive and time-consuming +testing. However, these additions to the DT can result in good things and +improvements anyway, making them perfectly safe from the standpoint of being +unable to do any harm or cause some unforeseen regressions. + +These changes apply to the both supported hardware revisions of the Pine64 +RockPro64, i.e. to the production-run revisions 2.0 and 2.1. [1][2] + +[1] https://files.pine64.org/doc/rockpro64/rockpro64_v21-SCH.pdf +[2] https://files.pine64.org/doc/rockpro64/rockpro64_v20-SCH.pdf +[3] https://z9.de/hedgedoc/s/nF4d5G7rg#reboot-tests-for-PCIe-improvements +[4] https://lore.kernel.org/lkml/20230509153912.515218-1-vincenzopalazzodev@gmail.com/T/#u + +Fixes: bba821f5479e ("arm64: dts: rockchip: add PCIe nodes on rk3399-rockpro64") +Cc: stable@vger.kernel.org +Cc: Vincenzo Palazzo +Cc: Peter Geis +Cc: Bjorn Helgaas +Reported-by: Diederik de Haas +Tested-by: Chris Vogel +Signed-off-by: Dragan Simic +Tested-by: Diederik de Haas +Link: https://lore.kernel.org/r/b39cfd7490d8194f053bf3971f13a43472d1769e.1740941097.git.dsimic@manjaro.org +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +index 11d99d8b34a2b..fd8296c1d3fad 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +@@ -661,6 +661,8 @@ &pcie0 { + num-lanes = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_perst>; ++ vpcie0v9-supply = <&vcca_0v9>; ++ vpcie1v8-supply = <&vcca_1v8>; + vpcie12v-supply = <&vcc12v_dcin>; + vpcie3v3-supply = <&vcc3v3_pcie>; + status = "okay"; +-- +2.39.5 + diff --git a/queue-6.12/cgroup-rstat-fix-forceidle-time-in-cpu.stat.patch b/queue-6.12/cgroup-rstat-fix-forceidle-time-in-cpu.stat.patch new file mode 100644 index 0000000000..52442627b8 --- /dev/null +++ b/queue-6.12/cgroup-rstat-fix-forceidle-time-in-cpu.stat.patch @@ -0,0 +1,81 @@ +From 3688c3d36624a88b385f6329bce71f9dbad5e560 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Feb 2025 14:13:11 +0800 +Subject: cgroup/rstat: Fix forceidle time in cpu.stat + +From: Abel Wu + +[ Upstream commit c4af66a95aa3bc1d4f607ebd4eea524fb58946e3 ] + +The commit b824766504e4 ("cgroup/rstat: add force idle show helper") +retrieves forceidle_time outside cgroup_rstat_lock for non-root cgroups +which can be potentially inconsistent with other stats. + +Rather than reverting that commit, fix it in a way that retains the +effort of cleaning up the ifdef-messes. + +Fixes: b824766504e4 ("cgroup/rstat: add force idle show helper") +Signed-off-by: Abel Wu +Signed-off-by: Tejun Heo +Signed-off-by: Sasha Levin +--- + kernel/cgroup/rstat.c | 29 +++++++++++++---------------- + 1 file changed, 13 insertions(+), 16 deletions(-) + +diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c +index aac91466279f1..3e01781aeb7bd 100644 +--- a/kernel/cgroup/rstat.c ++++ b/kernel/cgroup/rstat.c +@@ -612,36 +612,33 @@ static void cgroup_force_idle_show(struct seq_file *seq, struct cgroup_base_stat + void cgroup_base_stat_cputime_show(struct seq_file *seq) + { + struct cgroup *cgrp = seq_css(seq)->cgroup; +- u64 usage, utime, stime, ntime; ++ struct cgroup_base_stat bstat; + + if (cgroup_parent(cgrp)) { + cgroup_rstat_flush_hold(cgrp); +- usage = cgrp->bstat.cputime.sum_exec_runtime; ++ bstat = cgrp->bstat; + cputime_adjust(&cgrp->bstat.cputime, &cgrp->prev_cputime, +- &utime, &stime); +- ntime = cgrp->bstat.ntime; ++ &bstat.cputime.utime, &bstat.cputime.stime); + cgroup_rstat_flush_release(cgrp); + } else { +- /* cgrp->bstat of root is not actually used, reuse it */ +- root_cgroup_cputime(&cgrp->bstat); +- usage = cgrp->bstat.cputime.sum_exec_runtime; +- utime = cgrp->bstat.cputime.utime; +- stime = cgrp->bstat.cputime.stime; +- ntime = cgrp->bstat.ntime; ++ root_cgroup_cputime(&bstat); + } + +- do_div(usage, NSEC_PER_USEC); +- do_div(utime, NSEC_PER_USEC); +- do_div(stime, NSEC_PER_USEC); +- do_div(ntime, NSEC_PER_USEC); ++ do_div(bstat.cputime.sum_exec_runtime, NSEC_PER_USEC); ++ do_div(bstat.cputime.utime, NSEC_PER_USEC); ++ do_div(bstat.cputime.stime, NSEC_PER_USEC); ++ do_div(bstat.ntime, NSEC_PER_USEC); + + seq_printf(seq, "usage_usec %llu\n" + "user_usec %llu\n" + "system_usec %llu\n" + "nice_usec %llu\n", +- usage, utime, stime, ntime); ++ bstat.cputime.sum_exec_runtime, ++ bstat.cputime.utime, ++ bstat.cputime.stime, ++ bstat.ntime); + +- cgroup_force_idle_show(seq, &cgrp->bstat); ++ cgroup_force_idle_show(seq, &bstat); + } + + /* Add bpf kfuncs for cgroup_rstat_updated() and cgroup_rstat_flush() */ +-- +2.39.5 + diff --git a/queue-6.12/cgroup-rstat-tracking-cgroup-level-niced-cpu-time.patch b/queue-6.12/cgroup-rstat-tracking-cgroup-level-niced-cpu-time.patch new file mode 100644 index 0000000000..e7b4598eaa --- /dev/null +++ b/queue-6.12/cgroup-rstat-tracking-cgroup-level-niced-cpu-time.patch @@ -0,0 +1,121 @@ +From 81eb252d83568dc0a16a2b00105bf563ff5bdcb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Oct 2024 11:47:16 -0700 +Subject: cgroup/rstat: Tracking cgroup-level niced CPU time + +From: Joshua Hahn + +[ Upstream commit aefa398d93d5db7c555be78a605ff015357f127d ] + +Cgroup-level CPU statistics currently include time spent on +user/system processes, but do not include niced CPU time (despite +already being tracked). This patch exposes niced CPU time to the +userspace, allowing users to get a better understanding of their +hardware limits and can facilitate more informed workload distribution. + +A new field 'ntime' is added to struct cgroup_base_stat as opposed to +struct task_cputime to minimize footprint. + +Signed-off-by: Joshua Hahn +Signed-off-by: Tejun Heo +Stable-dep-of: c4af66a95aa3 ("cgroup/rstat: Fix forceidle time in cpu.stat") +Signed-off-by: Sasha Levin +--- + include/linux/cgroup-defs.h | 1 + + kernel/cgroup/rstat.c | 19 ++++++++++++++----- + 2 files changed, 15 insertions(+), 5 deletions(-) + +diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h +index a32eebcd23da4..38b2af336e4a0 100644 +--- a/include/linux/cgroup-defs.h ++++ b/include/linux/cgroup-defs.h +@@ -324,6 +324,7 @@ struct cgroup_base_stat { + #ifdef CONFIG_SCHED_CORE + u64 forceidle_sum; + #endif ++ u64 ntime; + }; + + /* +diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c +index ce295b73c0a36..aac91466279f1 100644 +--- a/kernel/cgroup/rstat.c ++++ b/kernel/cgroup/rstat.c +@@ -444,6 +444,7 @@ static void cgroup_base_stat_add(struct cgroup_base_stat *dst_bstat, + #ifdef CONFIG_SCHED_CORE + dst_bstat->forceidle_sum += src_bstat->forceidle_sum; + #endif ++ dst_bstat->ntime += src_bstat->ntime; + } + + static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat, +@@ -455,6 +456,7 @@ static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat, + #ifdef CONFIG_SCHED_CORE + dst_bstat->forceidle_sum -= src_bstat->forceidle_sum; + #endif ++ dst_bstat->ntime -= src_bstat->ntime; + } + + static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu) +@@ -534,8 +536,10 @@ void __cgroup_account_cputime_field(struct cgroup *cgrp, + rstatc = cgroup_base_stat_cputime_account_begin(cgrp, &flags); + + switch (index) { +- case CPUTIME_USER: + case CPUTIME_NICE: ++ rstatc->bstat.ntime += delta_exec; ++ fallthrough; ++ case CPUTIME_USER: + rstatc->bstat.cputime.utime += delta_exec; + break; + case CPUTIME_SYSTEM: +@@ -590,6 +594,7 @@ static void root_cgroup_cputime(struct cgroup_base_stat *bstat) + #ifdef CONFIG_SCHED_CORE + bstat->forceidle_sum += cpustat[CPUTIME_FORCEIDLE]; + #endif ++ bstat->ntime += cpustat[CPUTIME_NICE]; + } + } + +@@ -607,13 +612,14 @@ static void cgroup_force_idle_show(struct seq_file *seq, struct cgroup_base_stat + void cgroup_base_stat_cputime_show(struct seq_file *seq) + { + struct cgroup *cgrp = seq_css(seq)->cgroup; +- u64 usage, utime, stime; ++ u64 usage, utime, stime, ntime; + + if (cgroup_parent(cgrp)) { + cgroup_rstat_flush_hold(cgrp); + usage = cgrp->bstat.cputime.sum_exec_runtime; + cputime_adjust(&cgrp->bstat.cputime, &cgrp->prev_cputime, + &utime, &stime); ++ ntime = cgrp->bstat.ntime; + cgroup_rstat_flush_release(cgrp); + } else { + /* cgrp->bstat of root is not actually used, reuse it */ +@@ -621,16 +627,19 @@ void cgroup_base_stat_cputime_show(struct seq_file *seq) + usage = cgrp->bstat.cputime.sum_exec_runtime; + utime = cgrp->bstat.cputime.utime; + stime = cgrp->bstat.cputime.stime; ++ ntime = cgrp->bstat.ntime; + } + + do_div(usage, NSEC_PER_USEC); + do_div(utime, NSEC_PER_USEC); + do_div(stime, NSEC_PER_USEC); ++ do_div(ntime, NSEC_PER_USEC); + + seq_printf(seq, "usage_usec %llu\n" +- "user_usec %llu\n" +- "system_usec %llu\n", +- usage, utime, stime); ++ "user_usec %llu\n" ++ "system_usec %llu\n" ++ "nice_usec %llu\n", ++ usage, utime, stime, ntime); + + cgroup_force_idle_show(seq, &cgrp->bstat); + } +-- +2.39.5 + diff --git a/queue-6.12/drm-amdgpu-gfx11-fix-num_mec.patch b/queue-6.12/drm-amdgpu-gfx11-fix-num_mec.patch new file mode 100644 index 0000000000..44c961a5e4 --- /dev/null +++ b/queue-6.12/drm-amdgpu-gfx11-fix-num_mec.patch @@ -0,0 +1,35 @@ +From 1dcbcfc8cecd06b4d17ea40725c5b01045bbff70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Mar 2025 09:35:02 -0400 +Subject: drm/amdgpu/gfx11: fix num_mec + +From: Alex Deucher + +[ Upstream commit 4161050d47e1b083a7e1b0b875c9907e1a6f1f1f ] + +GC11 only has 1 mec. + +Fixes: 3d879e81f0f9 ("drm/amdgpu: add init support for GFX11 (v2)") +Reviewed-by: Sunil Khatri +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +index d3e8be82a1727..84cf5fd297b7f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +@@ -1549,7 +1549,7 @@ static int gfx_v11_0_sw_init(void *handle) + adev->gfx.me.num_me = 1; + adev->gfx.me.num_pipe_per_me = 1; + adev->gfx.me.num_queue_per_pipe = 1; +- adev->gfx.mec.num_mec = 2; ++ adev->gfx.mec.num_mec = 1; + adev->gfx.mec.num_pipe_per_mec = 4; + adev->gfx.mec.num_queue_per_pipe = 4; + break; +-- +2.39.5 + diff --git a/queue-6.12/drm-amdgpu-gfx12-fix-num_mec.patch b/queue-6.12/drm-amdgpu-gfx12-fix-num_mec.patch new file mode 100644 index 0000000000..7f37869fc7 --- /dev/null +++ b/queue-6.12/drm-amdgpu-gfx12-fix-num_mec.patch @@ -0,0 +1,35 @@ +From e26545b909edce0ef0d297d5b8c1dcde8ae836d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Mar 2025 12:09:11 -0400 +Subject: drm/amdgpu/gfx12: fix num_mec + +From: Alex Deucher + +[ Upstream commit dce8bd9137b88735dd0efc4e2693213d98c15913 ] + +GC12 only has 1 mec. + +Fixes: 52cb80c12e8a ("drm/amdgpu: Add gfx v12_0 ip block support (v6)") +Reviewed-by: Sunil Khatri +Signed-off-by: Alex Deucher +Signed-off-by: Sasha Levin +--- + drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +index d3798a333d1f8..b259e217930c7 100644 +--- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c ++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +@@ -1332,7 +1332,7 @@ static int gfx_v12_0_sw_init(void *handle) + adev->gfx.me.num_me = 1; + adev->gfx.me.num_pipe_per_me = 1; + adev->gfx.me.num_queue_per_pipe = 1; +- adev->gfx.mec.num_mec = 2; ++ adev->gfx.mec.num_mec = 1; + adev->gfx.mec.num_pipe_per_mec = 2; + adev->gfx.mec.num_queue_per_pipe = 4; + break; +-- +2.39.5 + diff --git a/queue-6.12/kbuild-deb-pkg-don-t-set-kbuild_build_version-uncond.patch b/queue-6.12/kbuild-deb-pkg-don-t-set-kbuild_build_version-uncond.patch new file mode 100644 index 0000000000..baec79b1dd --- /dev/null +++ b/queue-6.12/kbuild-deb-pkg-don-t-set-kbuild_build_version-uncond.patch @@ -0,0 +1,64 @@ +From fcc1c27fce9bf7cc20ea2e56bd15ba1d69f3a7ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Mar 2025 13:10:53 +0000 +Subject: kbuild: deb-pkg: don't set KBUILD_BUILD_VERSION unconditionally + +From: Alexandru Gagniuc + +[ Upstream commit 62604063621fb075c7966286bdddcb057d883fa8 ] + +In ThinPro, we use the convention +hp for +the kernel package. This does not have a dash in the name or version. +This is built by editing ".version" before a build, and setting +EXTRAVERSION="+hp" and KDEB_PKGVERSION make variables: + + echo 68 > .version + make -j EXTRAVERSION="+hp" bindeb-pkg KDEB_PKGVERSION=6.12.2+hp69 + + .deb name: linux-image-6.12.2+hp_6.12.2+hp69_amd64.deb + +Since commit 7d4f07d5cb71 ("kbuild: deb-pkg: squash +scripts/package/deb-build-option to debian/rules"), this no longer +works. The deb build logic changed, even though, the commit message +implies that the logic should be unmodified. + +Before, KBUILD_BUILD_VERSION was not set if the KDEB_PKGVERSION did +not contain a dash. After the change KBUILD_BUILD_VERSION is always +set to KDEB_PKGVERSION. Since this determines UTS_VERSION, the uname +output to look off: + + (now) uname -a: version 6.12.2+hp ... #6.12.2+hp69 + (expected) uname -a: version 6.12.2+hp ... #69 + +Update the debian/rules logic to restore the original behavior. + +Fixes: 7d4f07d5cb71 ("kbuild: deb-pkg: squash scripts/package/deb-build-option to debian/rules") +Signed-off-by: Alexandru Gagniuc +Reviewed-by: Nicolas Schier +Signed-off-by: Masahiro Yamada +Signed-off-by: Sasha Levin +--- + scripts/package/debian/rules | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/scripts/package/debian/rules b/scripts/package/debian/rules +index ca07243bd5cdf..2b3f9a0bd6c40 100755 +--- a/scripts/package/debian/rules ++++ b/scripts/package/debian/rules +@@ -21,9 +21,11 @@ ifeq ($(origin KBUILD_VERBOSE),undefined) + endif + endif + +-revision = $(lastword $(subst -, ,$(shell dpkg-parsechangelog -S Version))) ++revision = $(shell dpkg-parsechangelog -S Version | sed -n 's/.*-//p') + CROSS_COMPILE ?= $(filter-out $(DEB_BUILD_GNU_TYPE)-, $(DEB_HOST_GNU_TYPE)-) +-make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) KBUILD_BUILD_VERSION=$(revision) $(addprefix CROSS_COMPILE=,$(CROSS_COMPILE)) ++make-opts = ARCH=$(ARCH) KERNELRELEASE=$(KERNELRELEASE) \ ++ $(addprefix KBUILD_BUILD_VERSION=,$(revision)) \ ++ $(addprefix CROSS_COMPILE=,$(CROSS_COMPILE)) + + binary-targets := $(addprefix binary-, image image-dbg headers libc-dev) + +-- +2.39.5 + diff --git a/queue-6.12/perf-core-fix-child_total_time_enabled-accounting-bu.patch b/queue-6.12/perf-core-fix-child_total_time_enabled-accounting-bu.patch new file mode 100644 index 0000000000..1828c5672a --- /dev/null +++ b/queue-6.12/perf-core-fix-child_total_time_enabled-accounting-bu.patch @@ -0,0 +1,143 @@ +From 7c391d34740d24cf6351da8d3ac4a2a0aeafffa5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Mar 2025 08:20:03 +0000 +Subject: perf/core: Fix child_total_time_enabled accounting bug at task exit + +From: Yeoreum Yun + +[ Upstream commit a3c3c66670cee11eb13aa43905904bf29cb92d32 ] + +The perf events code fails to account for total_time_enabled of +inactive events. + +Here is a failure case for accounting total_time_enabled for +CPU PMU events: + + sudo ./perf stat -vvv -e armv8_pmuv3_0/event=0x08/ -e armv8_pmuv3_1/event=0x08/ -- stress-ng --pthread=2 -t 2s + ... + + armv8_pmuv3_0/event=0x08/: 1138698008 2289429840 2174835740 + armv8_pmuv3_1/event=0x08/: 1826791390 1950025700 847648440 + ` ` ` + ` ` > total_time_running with child + ` > total_time_enabled with child + > count with child + + Performance counter stats for 'stress-ng --pthread=2 -t 2s': + + 1,138,698,008 armv8_pmuv3_0/event=0x08/ (94.99%) + 1,826,791,390 armv8_pmuv3_1/event=0x08/ (43.47%) + +The two events above are opened on two different CPU PMUs, for example, +each event is opened for a cluster in an Arm big.LITTLE system, they +will never run on the same CPU. In theory, the total enabled time should +be same for both events, as two events are opened and closed together. + +As the result show, the two events' total enabled time including +child event is different (2289429840 vs 1950025700). + +This is because child events are not accounted properly +if a event is INACTIVE state when the task exits: + + perf_event_exit_event() + `> perf_remove_from_context() + `> __perf_remove_from_context() + `> perf_child_detach() -> Accumulate child_total_time_enabled + `> list_del_event() -> Update child event's time + +The problem is the time accumulation happens prior to child event's +time updating. Thus, it misses to account the last period's time when +the event exits. + +The perf core layer follows the rule that timekeeping is tied to state +change. To address the issue, make __perf_remove_from_context() +handle the task exit case by passing 'DETACH_EXIT' to it and +invoke perf_event_state() for state alongside with accounting the time. + +Then, perf_child_detach() populates the time into the parent's time metrics. + +After this patch, the bug is fixed: + + sudo ./perf stat -vvv -e armv8_pmuv3_0/event=0x08/ -e armv8_pmuv3_1/event=0x08/ -- stress-ng --pthread=2 -t 10s + ... + armv8_pmuv3_0/event=0x08/: 15396770398 32157963940 21898169000 + armv8_pmuv3_1/event=0x08/: 22428964974 32157963940 10259794940 + + Performance counter stats for 'stress-ng --pthread=2 -t 10s': + + 15,396,770,398 armv8_pmuv3_0/event=0x08/ (68.10%) + 22,428,964,974 armv8_pmuv3_1/event=0x08/ (31.90%) + +[ mingo: Clarified the changelog. ] + +Fixes: ef54c1a476aef ("perf: Rework perf_event_exit_event()") +Suggested-by: Peter Zijlstra +Signed-off-by: Yeoreum Yun +Signed-off-by: Ingo Molnar +Tested-by: Leo Yan +Link: https://lore.kernel.org/r/20250326082003.1630986-1-yeoreum.yun@arm.com +Signed-off-by: Sasha Levin +--- + kernel/events/core.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/kernel/events/core.c b/kernel/events/core.c +index cf2ec0a1582fd..b5ccf52bb71ba 100644 +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -2407,6 +2407,7 @@ ctx_time_update_event(struct perf_event_context *ctx, struct perf_event *event) + #define DETACH_GROUP 0x01UL + #define DETACH_CHILD 0x02UL + #define DETACH_DEAD 0x04UL ++#define DETACH_EXIT 0x08UL + + /* + * Cross CPU call to remove a performance event +@@ -2421,6 +2422,7 @@ __perf_remove_from_context(struct perf_event *event, + void *info) + { + struct perf_event_pmu_context *pmu_ctx = event->pmu_ctx; ++ enum perf_event_state state = PERF_EVENT_STATE_OFF; + unsigned long flags = (unsigned long)info; + + ctx_time_update(cpuctx, ctx); +@@ -2429,16 +2431,19 @@ __perf_remove_from_context(struct perf_event *event, + * Ensure event_sched_out() switches to OFF, at the very least + * this avoids raising perf_pending_task() at this time. + */ +- if (flags & DETACH_DEAD) ++ if (flags & DETACH_EXIT) ++ state = PERF_EVENT_STATE_EXIT; ++ if (flags & DETACH_DEAD) { + event->pending_disable = 1; ++ state = PERF_EVENT_STATE_DEAD; ++ } + event_sched_out(event, ctx); ++ perf_event_set_state(event, min(event->state, state)); + if (flags & DETACH_GROUP) + perf_group_detach(event); + if (flags & DETACH_CHILD) + perf_child_detach(event); + list_del_event(event, ctx); +- if (flags & DETACH_DEAD) +- event->state = PERF_EVENT_STATE_DEAD; + + if (!pmu_ctx->nr_events) { + pmu_ctx->rotate_necessary = 0; +@@ -13343,12 +13348,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx) + mutex_lock(&parent_event->child_mutex); + } + +- perf_remove_from_context(event, detach_flags); +- +- raw_spin_lock_irq(&ctx->lock); +- if (event->state > PERF_EVENT_STATE_EXIT) +- perf_event_set_state(event, PERF_EVENT_STATE_EXIT); +- raw_spin_unlock_irq(&ctx->lock); ++ perf_remove_from_context(event, detach_flags | DETACH_EXIT); + + /* + * Child events can be freed. +-- +2.39.5 + diff --git a/queue-6.12/series b/queue-6.12/series index db22a24bb8..f3116a7f48 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -342,3 +342,18 @@ ipv6-start-path-selection-from-the-first-nexthop.patch ipv6-do-not-consider-link-down-nexthops-in-path-sele.patch arcnet-add-null-check-in-com20020pci_probe.patch net-ibmveth-make-veth_pool_store-stop-hanging.patch +kbuild-deb-pkg-don-t-set-kbuild_build_version-uncond.patch +drm-amdgpu-gfx11-fix-num_mec.patch +drm-amdgpu-gfx12-fix-num_mec.patch +perf-core-fix-child_total_time_enabled-accounting-bu.patch +tools-power-turbostat-report-corethr-per-measurement.patch +tracing-switch-trace_events_hist.c-code-over-to-use-.patch +tracing-hist-add-poll-pollin-support-on-hist-file.patch +tracing-hist-support-pollpri-event-for-poll-on-histo.patch +tracing-correct-the-refcount-if-the-hist-hist_debug-.patch +arm64-dts-rockchip-add-missing-pcie-supplies-to-rock.patch +cgroup-rstat-tracking-cgroup-level-niced-cpu-time.patch +cgroup-rstat-fix-forceidle-time-in-cpu.stat.patch +tty-serial-fsl_lpuart-use-u32-and-u8-for-register-va.patch +tty-serial-fsl_lpuart-use-port-struct-directly-to-si.patch +tty-serial-lpuart-only-disable-cts-instead-of-overwr.patch diff --git a/queue-6.12/tools-power-turbostat-report-corethr-per-measurement.patch b/queue-6.12/tools-power-turbostat-report-corethr-per-measurement.patch new file mode 100644 index 0000000000..a6948a3aa4 --- /dev/null +++ b/queue-6.12/tools-power-turbostat-report-corethr-per-measurement.patch @@ -0,0 +1,59 @@ +From 881de3425a604dcd1706578f93f1e9a3ffbdaa06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 6 Apr 2025 11:18:39 -0400 +Subject: tools/power turbostat: report CoreThr per measurement interval + +From: Len Brown + +[ Upstream commit f729775f79a9c942c6c82ed6b44bd030afe10423 ] + +The CoreThr column displays total thermal throttling events +since boot time. + +Change it to report events during the measurement interval. + +This is more useful for showing a user the current conditions. +Total events since boot time are still available to the user via +/sys/devices/system/cpu/cpu*/thermal_throttle/* + +Document CoreThr on turbostat.8 + +Fixes: eae97e053fe30 ("turbostat: Support thermal throttle count print") +Reported-by: Arjan van de Ven +Signed-off-by: Len Brown +Cc: Chen Yu +Signed-off-by: Sasha Levin +--- + tools/power/x86/turbostat/turbostat.8 | 2 ++ + tools/power/x86/turbostat/turbostat.c | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 +index 56c7ff6efcdab..a3cf1d17163ae 100644 +--- a/tools/power/x86/turbostat/turbostat.8 ++++ b/tools/power/x86/turbostat/turbostat.8 +@@ -168,6 +168,8 @@ The system configuration dump (if --quiet is not used) is followed by statistics + .PP + \fBPkgTmp\fP Degrees Celsius reported by the per-package Package Thermal Monitor. + .PP ++\fBCoreThr\fP Core Thermal Throttling events during the measurement interval. Note that events since boot can be find in /sys/devices/system/cpu/cpu*/thermal_throttle/* ++.PP + \fBGFX%rc6\fP The percentage of time the GPU is in the "render C6" state, rc6, during the measurement interval. From /sys/class/drm/card0/power/rc6_residency_ms or /sys/class/drm/card0/gt/gt0/rc6_residency_ms or /sys/class/drm/card0/device/tile0/gtN/gtidle/idle_residency_ms depending on the graphics driver being used. + .PP + \fBGFXMHz\fP Instantaneous snapshot of what sysfs presents at the end of the measurement interval. From /sys/class/graphics/fb0/device/drm/card0/gt_cur_freq_mhz or /sys/class/drm/card0/gt_cur_freq_mhz or /sys/class/drm/card0/gt/gt0/rps_cur_freq_mhz or /sys/class/drm/card0/device/tile0/gtN/freq0/cur_freq depending on the graphics driver being used. +diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c +index 235e82fe7d0a5..77ef60980ee58 100644 +--- a/tools/power/x86/turbostat/turbostat.c ++++ b/tools/power/x86/turbostat/turbostat.c +@@ -3242,7 +3242,7 @@ void delta_core(struct core_data *new, struct core_data *old) + old->c6 = new->c6 - old->c6; + old->c7 = new->c7 - old->c7; + old->core_temp_c = new->core_temp_c; +- old->core_throt_cnt = new->core_throt_cnt; ++ old->core_throt_cnt = new->core_throt_cnt - old->core_throt_cnt; + old->mc6_us = new->mc6_us - old->mc6_us; + + DELTA_WRAP32(new->core_energy.raw_value, old->core_energy.raw_value); +-- +2.39.5 + diff --git a/queue-6.12/tracing-correct-the-refcount-if-the-hist-hist_debug-.patch b/queue-6.12/tracing-correct-the-refcount-if-the-hist-hist_debug-.patch new file mode 100644 index 0000000000..2668aaf6ea --- /dev/null +++ b/queue-6.12/tracing-correct-the-refcount-if-the-hist-hist_debug-.patch @@ -0,0 +1,92 @@ +From bee63bfc84c5002560f57a76806247a786cd2932 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Mar 2025 06:53:35 +0000 +Subject: tracing: Correct the refcount if the hist/hist_debug file fails to + open + +From: Tengda Wu + +[ Upstream commit 0b4ffbe4888a2c71185eaf5c1a02dd3586a9bc04 ] + +The function event_{hist,hist_debug}_open() maintains the refcount of +'file->tr' and 'file' through tracing_open_file_tr(). However, it does +not roll back these counts on subsequent failure paths, resulting in a +refcount leak. + +A very obvious case is that if the hist/hist_debug file belongs to a +specific instance, the refcount leak will prevent the deletion of that +instance, as it relies on the condition 'tr->ref == 1' within +__remove_instance(). + +Fix this by calling tracing_release_file_tr() on all failure paths in +event_{hist,hist_debug}_open() to correct the refcount. + +Cc: stable@vger.kernel.org +Cc: Masami Hiramatsu +Cc: Mathieu Desnoyers +Cc: Zheng Yejian +Link: https://lore.kernel.org/20250314065335.1202817-1-wutengda@huaweicloud.com +Fixes: 1cc111b9cddc ("tracing: Fix uaf issue when open the hist or hist_debug file") +Signed-off-by: Tengda Wu +Signed-off-by: Steven Rostedt (Google) +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index e07d75adab8e3..4ebafc655223a 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -5692,12 +5692,16 @@ static int event_hist_open(struct inode *inode, struct file *file) + guard(mutex)(&event_mutex); + + event_file = event_file_data(file); +- if (!event_file) +- return -ENODEV; ++ if (!event_file) { ++ ret = -ENODEV; ++ goto err; ++ } + + hist_file = kzalloc(sizeof(*hist_file), GFP_KERNEL); +- if (!hist_file) +- return -ENOMEM; ++ if (!hist_file) { ++ ret = -ENOMEM; ++ goto err; ++ } + + hist_file->file = file; + hist_file->last_act = get_hist_hit_count(event_file); +@@ -5705,9 +5709,14 @@ static int event_hist_open(struct inode *inode, struct file *file) + /* Clear private_data to avoid warning in single_open() */ + file->private_data = NULL; + ret = single_open(file, hist_show, hist_file); +- if (ret) ++ if (ret) { + kfree(hist_file); ++ goto err; ++ } + ++ return 0; ++err: ++ tracing_release_file_tr(inode, file); + return ret; + } + +@@ -5982,7 +5991,10 @@ static int event_hist_debug_open(struct inode *inode, struct file *file) + + /* Clear private_data to avoid warning in single_open() */ + file->private_data = NULL; +- return single_open(file, hist_debug_show, file); ++ ret = single_open(file, hist_debug_show, file); ++ if (ret) ++ tracing_release_file_tr(inode, file); ++ return ret; + } + + const struct file_operations event_hist_debug_fops = { +-- +2.39.5 + diff --git a/queue-6.12/tracing-hist-add-poll-pollin-support-on-hist-file.patch b/queue-6.12/tracing-hist-add-poll-pollin-support-on-hist-file.patch new file mode 100644 index 0000000000..48021f33fc --- /dev/null +++ b/queue-6.12/tracing-hist-add-poll-pollin-support-on-hist-file.patch @@ -0,0 +1,216 @@ +From 53017ac3bba8fd7b36949e6eab5c60eafd6cf56a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Dec 2024 13:07:57 +0900 +Subject: tracing/hist: Add poll(POLLIN) support on hist file + +From: Masami Hiramatsu (Google) + +[ Upstream commit 1bd13edbbed6e7e396f1aab92b224a4775218e68 ] + +Add poll syscall support on the `hist` file. The Waiter will be waken +up when the histogram is updated with POLLIN. + +Currently, there is no way to wait for a specific event in userspace. +So user needs to peek the `trace` periodicaly, or wait on `trace_pipe`. +But it is not a good idea to peek at the `trace` for an event that +randomly happens. And `trace_pipe` is not coming back until a page is +filled with events. + +This allows a user to wait for a specific event on the `hist` file. User +can set a histogram trigger on the event which they want to monitor +and poll() on its `hist` file. Since this poll() returns POLLIN, the next +poll() will return soon unless a read() happens on that hist file. + +NOTE: To read the hist file again, you must set the file offset to 0, +but just for monitoring the event, you may not need to read the +histogram. + +Cc: Shuah Khan +Cc: Mathieu Desnoyers +Link: https://lore.kernel.org/173527247756.464571.14236296701625509931.stgit@devnote2 +Signed-off-by: Masami Hiramatsu (Google) +Reviewed-by: Tom Zanussi +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: 0b4ffbe4888a ("tracing: Correct the refcount if the hist/hist_debug file fails to open") +Signed-off-by: Sasha Levin +--- + include/linux/trace_events.h | 14 +++++++ + kernel/trace/trace_events.c | 14 +++++++ + kernel/trace/trace_events_hist.c | 70 ++++++++++++++++++++++++++++++-- + 3 files changed, 95 insertions(+), 3 deletions(-) + +diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h +index 77769ff505444..fcf5a64d5cfe2 100644 +--- a/include/linux/trace_events.h ++++ b/include/linux/trace_events.h +@@ -689,6 +689,20 @@ struct trace_event_file { + atomic_t tm_ref; /* trigger-mode reference counter */ + }; + ++#ifdef CONFIG_HIST_TRIGGERS ++extern struct irq_work hist_poll_work; ++extern wait_queue_head_t hist_poll_wq; ++ ++static inline void hist_poll_wakeup(void) ++{ ++ if (wq_has_sleeper(&hist_poll_wq)) ++ irq_work_queue(&hist_poll_work); ++} ++ ++#define hist_poll_wait(file, wait) \ ++ poll_wait(file, &hist_poll_wq, wait) ++#endif ++ + #define __TRACE_EVENT_FLAGS(name, value) \ + static int __init trace_init_flags_##name(void) \ + { \ +diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c +index ea9b44847ce6b..29eba68e07859 100644 +--- a/kernel/trace/trace_events.c ++++ b/kernel/trace/trace_events.c +@@ -3111,6 +3111,20 @@ static bool event_in_systems(struct trace_event_call *call, + return !*p || isspace(*p) || *p == ','; + } + ++#ifdef CONFIG_HIST_TRIGGERS ++/* ++ * Wake up waiter on the hist_poll_wq from irq_work because the hist trigger ++ * may happen in any context. ++ */ ++static void hist_poll_event_irq_work(struct irq_work *work) ++{ ++ wake_up_all(&hist_poll_wq); ++} ++ ++DEFINE_IRQ_WORK(hist_poll_work, hist_poll_event_irq_work); ++DECLARE_WAIT_QUEUE_HEAD(hist_poll_wq); ++#endif ++ + static struct trace_event_file * + trace_create_new_event(struct trace_event_call *call, + struct trace_array *tr) +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 5d344bc690d99..9e33cd2a73b5c 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -5314,6 +5314,8 @@ static void event_hist_trigger(struct event_trigger_data *data, + + if (resolve_var_refs(hist_data, key, var_ref_vals, true)) + hist_trigger_actions(hist_data, elt, buffer, rec, rbe, key, var_ref_vals); ++ ++ hist_poll_wakeup(); + } + + static void hist_trigger_stacktrace_print(struct seq_file *m, +@@ -5593,15 +5595,36 @@ static void hist_trigger_show(struct seq_file *m, + n_entries, (u64)atomic64_read(&hist_data->map->drops)); + } + ++struct hist_file_data { ++ struct file *file; ++ u64 last_read; ++}; ++ ++static u64 get_hist_hit_count(struct trace_event_file *event_file) ++{ ++ struct hist_trigger_data *hist_data; ++ struct event_trigger_data *data; ++ u64 ret = 0; ++ ++ list_for_each_entry(data, &event_file->triggers, list) { ++ if (data->cmd_ops->trigger_type == ETT_EVENT_HIST) { ++ hist_data = data->private_data; ++ ret += atomic64_read(&hist_data->map->hits); ++ } ++ } ++ return ret; ++} ++ + static int hist_show(struct seq_file *m, void *v) + { ++ struct hist_file_data *hist_file = m->private; + struct event_trigger_data *data; + struct trace_event_file *event_file; + int n = 0; + + guard(mutex)(&event_mutex); + +- event_file = event_file_file(m->private); ++ event_file = event_file_file(hist_file->file); + if (unlikely(!event_file)) + return -ENODEV; + +@@ -5609,27 +5632,68 @@ static int hist_show(struct seq_file *m, void *v) + if (data->cmd_ops->trigger_type == ETT_EVENT_HIST) + hist_trigger_show(m, data, n++); + } ++ hist_file->last_read = get_hist_hit_count(event_file); ++ + return 0; + } + ++static __poll_t event_hist_poll(struct file *file, struct poll_table_struct *wait) ++{ ++ struct trace_event_file *event_file; ++ struct seq_file *m = file->private_data; ++ struct hist_file_data *hist_file = m->private; ++ ++ guard(mutex)(&event_mutex); ++ ++ event_file = event_file_data(file); ++ if (!event_file) ++ return EPOLLERR; ++ ++ hist_poll_wait(file, wait); ++ ++ if (hist_file->last_read != get_hist_hit_count(event_file)) ++ return EPOLLIN | EPOLLRDNORM; ++ ++ return 0; ++} ++ ++static int event_hist_release(struct inode *inode, struct file *file) ++{ ++ struct seq_file *m = file->private_data; ++ struct hist_file_data *hist_file = m->private; ++ ++ kfree(hist_file); ++ return tracing_single_release_file_tr(inode, file); ++} ++ + static int event_hist_open(struct inode *inode, struct file *file) + { ++ struct hist_file_data *hist_file; + int ret; + + ret = tracing_open_file_tr(inode, file); + if (ret) + return ret; + ++ hist_file = kzalloc(sizeof(*hist_file), GFP_KERNEL); ++ if (!hist_file) ++ return -ENOMEM; ++ hist_file->file = file; ++ + /* Clear private_data to avoid warning in single_open() */ + file->private_data = NULL; +- return single_open(file, hist_show, file); ++ ret = single_open(file, hist_show, hist_file); ++ if (ret) ++ kfree(hist_file); ++ return ret; + } + + const struct file_operations event_hist_fops = { + .open = event_hist_open, + .read = seq_read, + .llseek = seq_lseek, +- .release = tracing_single_release_file_tr, ++ .release = event_hist_release, ++ .poll = event_hist_poll, + }; + + #ifdef CONFIG_HIST_TRIGGERS_DEBUG +-- +2.39.5 + diff --git a/queue-6.12/tracing-hist-support-pollpri-event-for-poll-on-histo.patch b/queue-6.12/tracing-hist-support-pollpri-event-for-poll-on-histo.patch new file mode 100644 index 0000000000..ef08cd454c --- /dev/null +++ b/queue-6.12/tracing-hist-support-pollpri-event-for-poll-on-histo.patch @@ -0,0 +1,119 @@ +From 5f46ffca965a46d46f287ae82f0d9744b78fd823 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Dec 2024 13:08:07 +0900 +Subject: tracing/hist: Support POLLPRI event for poll on histogram + +From: Masami Hiramatsu (Google) + +[ Upstream commit 66fc6f521a0b91051ce6968a216a30bc52267bf8 ] + +Since POLLIN will not be flushed until the hist file is read, the user +needs to repeatedly read() and poll() on the hist file for monitoring the +event continuously. But the read() is somewhat redundant when the user is +only monitoring for event updates. + +Add POLLPRI poll event on the hist file so the event returns when a +histogram is updated after open(), poll() or read(). Thus it is possible +to wait for the next event without having to issue a read(). + +Cc: Shuah Khan +Cc: Mathieu Desnoyers +Link: https://lore.kernel.org/173527248770.464571.2536902137325258133.stgit@devnote2 +Signed-off-by: Masami Hiramatsu (Google) +Reviewed-by: Tom Zanussi +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: 0b4ffbe4888a ("tracing: Correct the refcount if the hist/hist_debug file fails to open") +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 29 ++++++++++++++++++++++++++--- + 1 file changed, 26 insertions(+), 3 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 9e33cd2a73b5c..e07d75adab8e3 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -5598,6 +5598,7 @@ static void hist_trigger_show(struct seq_file *m, + struct hist_file_data { + struct file *file; + u64 last_read; ++ u64 last_act; + }; + + static u64 get_hist_hit_count(struct trace_event_file *event_file) +@@ -5633,6 +5634,11 @@ static int hist_show(struct seq_file *m, void *v) + hist_trigger_show(m, data, n++); + } + hist_file->last_read = get_hist_hit_count(event_file); ++ /* ++ * Update last_act too so that poll()/POLLPRI can wait for the next ++ * event after any syscall on hist file. ++ */ ++ hist_file->last_act = hist_file->last_read; + + return 0; + } +@@ -5642,6 +5648,8 @@ static __poll_t event_hist_poll(struct file *file, struct poll_table_struct *wai + struct trace_event_file *event_file; + struct seq_file *m = file->private_data; + struct hist_file_data *hist_file = m->private; ++ __poll_t ret = 0; ++ u64 cnt; + + guard(mutex)(&event_mutex); + +@@ -5651,10 +5659,15 @@ static __poll_t event_hist_poll(struct file *file, struct poll_table_struct *wai + + hist_poll_wait(file, wait); + +- if (hist_file->last_read != get_hist_hit_count(event_file)) +- return EPOLLIN | EPOLLRDNORM; ++ cnt = get_hist_hit_count(event_file); ++ if (hist_file->last_read != cnt) ++ ret |= EPOLLIN | EPOLLRDNORM; ++ if (hist_file->last_act != cnt) { ++ hist_file->last_act = cnt; ++ ret |= EPOLLPRI; ++ } + +- return 0; ++ return ret; + } + + static int event_hist_release(struct inode *inode, struct file *file) +@@ -5668,6 +5681,7 @@ static int event_hist_release(struct inode *inode, struct file *file) + + static int event_hist_open(struct inode *inode, struct file *file) + { ++ struct trace_event_file *event_file; + struct hist_file_data *hist_file; + int ret; + +@@ -5675,16 +5689,25 @@ static int event_hist_open(struct inode *inode, struct file *file) + if (ret) + return ret; + ++ guard(mutex)(&event_mutex); ++ ++ event_file = event_file_data(file); ++ if (!event_file) ++ return -ENODEV; ++ + hist_file = kzalloc(sizeof(*hist_file), GFP_KERNEL); + if (!hist_file) + return -ENOMEM; ++ + hist_file->file = file; ++ hist_file->last_act = get_hist_hit_count(event_file); + + /* Clear private_data to avoid warning in single_open() */ + file->private_data = NULL; + ret = single_open(file, hist_show, hist_file); + if (ret) + kfree(hist_file); ++ + return ret; + } + +-- +2.39.5 + diff --git a/queue-6.12/tracing-switch-trace_events_hist.c-code-over-to-use-.patch b/queue-6.12/tracing-switch-trace_events_hist.c-code-over-to-use-.patch new file mode 100644 index 0000000000..6426db2fdd --- /dev/null +++ b/queue-6.12/tracing-switch-trace_events_hist.c-code-over-to-use-.patch @@ -0,0 +1,99 @@ +From 1eb6498abff861ae18309f8c57be3b4f98425ce0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Dec 2024 15:12:05 -0500 +Subject: tracing: Switch trace_events_hist.c code over to use guard() + +From: Steven Rostedt + +[ Upstream commit 2b36a97aeeb71b1e4a48bfedc7f21f44aeb1e6fb ] + +There are a couple functions in trace_events_hist.c that have "goto out" or +equivalent on error in order to release locks that were taken. This can be +error prone or just simply make the code more complex. + +Switch every location that ends with unlocking a mutex on error over to +using the guard(mutex)() infrastructure to let the compiler worry about +releasing locks. This makes the code easier to read and understand. + +Cc: Masami Hiramatsu +Cc: Mark Rutland +Cc: Mathieu Desnoyers +Cc: Andrew Morton +Cc: Peter Zijlstra +Link: https://lore.kernel.org/20241219201345.694601480@goodmis.org +Signed-off-by: Steven Rostedt (Google) +Stable-dep-of: 0b4ffbe4888a ("tracing: Correct the refcount if the hist/hist_debug file fails to open") +Signed-off-by: Sasha Levin +--- + kernel/trace/trace_events_hist.c | 32 ++++++++++---------------------- + 1 file changed, 10 insertions(+), 22 deletions(-) + +diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c +index 31f5ad322fab0..5d344bc690d99 100644 +--- a/kernel/trace/trace_events_hist.c ++++ b/kernel/trace/trace_events_hist.c +@@ -5597,25 +5597,19 @@ static int hist_show(struct seq_file *m, void *v) + { + struct event_trigger_data *data; + struct trace_event_file *event_file; +- int n = 0, ret = 0; ++ int n = 0; + +- mutex_lock(&event_mutex); ++ guard(mutex)(&event_mutex); + + event_file = event_file_file(m->private); +- if (unlikely(!event_file)) { +- ret = -ENODEV; +- goto out_unlock; +- } ++ if (unlikely(!event_file)) ++ return -ENODEV; + + list_for_each_entry(data, &event_file->triggers, list) { + if (data->cmd_ops->trigger_type == ETT_EVENT_HIST) + hist_trigger_show(m, data, n++); + } +- +- out_unlock: +- mutex_unlock(&event_mutex); +- +- return ret; ++ return 0; + } + + static int event_hist_open(struct inode *inode, struct file *file) +@@ -5876,25 +5870,19 @@ static int hist_debug_show(struct seq_file *m, void *v) + { + struct event_trigger_data *data; + struct trace_event_file *event_file; +- int n = 0, ret = 0; ++ int n = 0; + +- mutex_lock(&event_mutex); ++ guard(mutex)(&event_mutex); + + event_file = event_file_file(m->private); +- if (unlikely(!event_file)) { +- ret = -ENODEV; +- goto out_unlock; +- } ++ if (unlikely(!event_file)) ++ return -ENODEV; + + list_for_each_entry(data, &event_file->triggers, list) { + if (data->cmd_ops->trigger_type == ETT_EVENT_HIST) + hist_trigger_debug_show(m, data, n++); + } +- +- out_unlock: +- mutex_unlock(&event_mutex); +- +- return ret; ++ return 0; + } + + static int event_hist_debug_open(struct inode *inode, struct file *file) +-- +2.39.5 + diff --git a/queue-6.12/tty-serial-fsl_lpuart-use-port-struct-directly-to-si.patch b/queue-6.12/tty-serial-fsl_lpuart-use-port-struct-directly-to-si.patch new file mode 100644 index 0000000000..d2086ab174 --- /dev/null +++ b/queue-6.12/tty-serial-fsl_lpuart-use-port-struct-directly-to-si.patch @@ -0,0 +1,523 @@ +From 937ce975f6fc60b4ad00a4759e55b66820814c4c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Mar 2025 10:39:03 +0800 +Subject: tty: serial: fsl_lpuart: use port struct directly to simply code + +From: Sherry Sun + +[ Upstream commit 3cc16ae096f164ae0c6b98416c25a01db5f3a529 ] + +Most lpuart functions have the parameter struct uart_port *port, but +still use the &sport->port to get the uart_port instead of use it +directly, let's simply the code logic, directly use this struct instead +of covert it from struct sport. + +Signed-off-by: Sherry Sun +Link: https://lore.kernel.org/r/20250312023904.1343351-3-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: e98ab45ec518 ("tty: serial: lpuart: only disable CTS instead of overwriting the whole UARTMODIR register") +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/fsl_lpuart.c | 213 +++++++++++++++----------------- + 1 file changed, 102 insertions(+), 111 deletions(-) + +diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c +index e86fb9c60f1c3..c2b522843b72c 100644 +--- a/drivers/tty/serial/fsl_lpuart.c ++++ b/drivers/tty/serial/fsl_lpuart.c +@@ -580,7 +580,7 @@ static int lpuart_dma_tx_request(struct uart_port *port) + ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig); + + if (ret) { +- dev_err(sport->port.dev, ++ dev_err(port->dev, + "DMA slave config failed, err = %d\n", ret); + return ret; + } +@@ -610,13 +610,13 @@ static void lpuart_flush_buffer(struct uart_port *port) + } + + if (lpuart_is_32(sport)) { +- val = lpuart32_read(&sport->port, UARTFIFO); ++ val = lpuart32_read(port, UARTFIFO); + val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; +- lpuart32_write(&sport->port, val, UARTFIFO); ++ lpuart32_write(port, val, UARTFIFO); + } else { +- val = readb(sport->port.membase + UARTCFIFO); ++ val = readb(port->membase + UARTCFIFO); + val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH; +- writeb(val, sport->port.membase + UARTCFIFO); ++ writeb(val, port->membase + UARTCFIFO); + } + } + +@@ -638,38 +638,36 @@ static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset, + + static int lpuart_poll_init(struct uart_port *port) + { +- struct lpuart_port *sport = container_of(port, +- struct lpuart_port, port); + unsigned long flags; + u8 temp; + +- sport->port.fifosize = 0; ++ port->fifosize = 0; + +- uart_port_lock_irqsave(&sport->port, &flags); ++ uart_port_lock_irqsave(port, &flags); + /* Disable Rx & Tx */ +- writeb(0, sport->port.membase + UARTCR2); ++ writeb(0, port->membase + UARTCR2); + +- temp = readb(sport->port.membase + UARTPFIFO); ++ temp = readb(port->membase + UARTPFIFO); + /* Enable Rx and Tx FIFO */ + writeb(temp | UARTPFIFO_RXFE | UARTPFIFO_TXFE, +- sport->port.membase + UARTPFIFO); ++ port->membase + UARTPFIFO); + + /* flush Tx and Rx FIFO */ + writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH, +- sport->port.membase + UARTCFIFO); ++ port->membase + UARTCFIFO); + + /* explicitly clear RDRF */ +- if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) { +- readb(sport->port.membase + UARTDR); +- writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO); ++ if (readb(port->membase + UARTSR1) & UARTSR1_RDRF) { ++ readb(port->membase + UARTDR); ++ writeb(UARTSFIFO_RXUF, port->membase + UARTSFIFO); + } + +- writeb(0, sport->port.membase + UARTTWFIFO); +- writeb(1, sport->port.membase + UARTRWFIFO); ++ writeb(0, port->membase + UARTTWFIFO); ++ writeb(1, port->membase + UARTRWFIFO); + + /* Enable Rx and Tx */ +- writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2); +- uart_port_unlock_irqrestore(&sport->port, flags); ++ writeb(UARTCR2_RE | UARTCR2_TE, port->membase + UARTCR2); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -692,33 +690,32 @@ static int lpuart_poll_get_char(struct uart_port *port) + static int lpuart32_poll_init(struct uart_port *port) + { + unsigned long flags; +- struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + u32 temp; + +- sport->port.fifosize = 0; ++ port->fifosize = 0; + +- uart_port_lock_irqsave(&sport->port, &flags); ++ uart_port_lock_irqsave(port, &flags); + + /* Disable Rx & Tx */ +- lpuart32_write(&sport->port, 0, UARTCTRL); ++ lpuart32_write(port, 0, UARTCTRL); + +- temp = lpuart32_read(&sport->port, UARTFIFO); ++ temp = lpuart32_read(port, UARTFIFO); + + /* Enable Rx and Tx FIFO */ +- lpuart32_write(&sport->port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO); ++ lpuart32_write(port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO); + + /* flush Tx and Rx FIFO */ +- lpuart32_write(&sport->port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO); ++ lpuart32_write(port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO); + + /* explicitly clear RDRF */ +- if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { +- lpuart32_read(&sport->port, UARTDATA); +- lpuart32_write(&sport->port, UARTFIFO_RXUF, UARTFIFO); ++ if (lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF) { ++ lpuart32_read(port, UARTDATA); ++ lpuart32_write(port, UARTFIFO_RXUF, UARTFIFO); + } + + /* Enable Rx and Tx */ +- lpuart32_write(&sport->port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL); +- uart_port_unlock_irqrestore(&sport->port, flags); ++ lpuart32_write(port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL); ++ uart_port_unlock_irqrestore(port, flags); + + return 0; + } +@@ -1448,12 +1445,9 @@ static void lpuart_dma_rx_free(struct uart_port *port) + static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) + { +- struct lpuart_port *sport = container_of(port, +- struct lpuart_port, port); +- +- u8 modem = readb(sport->port.membase + UARTMODEM) & ++ u8 modem = readb(port->membase + UARTMODEM) & + ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); +- writeb(modem, sport->port.membase + UARTMODEM); ++ writeb(modem, port->membase + UARTMODEM); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ +@@ -1471,32 +1465,29 @@ static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios, + modem &= ~UARTMODEM_TXRTSPOL; + } + +- writeb(modem, sport->port.membase + UARTMODEM); ++ writeb(modem, port->membase + UARTMODEM); + return 0; + } + + static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios, + struct serial_rs485 *rs485) + { +- struct lpuart_port *sport = container_of(port, +- struct lpuart_port, port); +- +- u32 modem = lpuart32_read(&sport->port, UARTMODIR) ++ u32 modem = lpuart32_read(port, UARTMODIR) + & ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE); + u32 ctrl; + + /* TXRTSE and TXRTSPOL only can be changed when transmitter is disabled. */ +- ctrl = lpuart32_read(&sport->port, UARTCTRL); ++ ctrl = lpuart32_read(port, UARTCTRL); + if (ctrl & UARTCTRL_TE) { + /* wait for the transmit engine to complete */ +- lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); +- lpuart32_write(&sport->port, ctrl & ~UARTCTRL_TE, UARTCTRL); ++ lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); ++ lpuart32_write(port, ctrl & ~UARTCTRL_TE, UARTCTRL); + +- while (lpuart32_read(&sport->port, UARTCTRL) & UARTCTRL_TE) ++ while (lpuart32_read(port, UARTCTRL) & UARTCTRL_TE) + cpu_relax(); + } + +- lpuart32_write(&sport->port, modem, UARTMODIR); ++ lpuart32_write(port, modem, UARTMODIR); + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ +@@ -1514,10 +1505,10 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio + modem &= ~UARTMODIR_TXRTSPOL; + } + +- lpuart32_write(&sport->port, modem, UARTMODIR); ++ lpuart32_write(port, modem, UARTMODIR); + + if (ctrl & UARTCTRL_TE) +- lpuart32_write(&sport->port, ctrl, UARTCTRL); ++ lpuart32_write(port, ctrl, UARTCTRL); + + return 0; + } +@@ -1828,11 +1819,11 @@ static int lpuart_startup(struct uart_port *port) + u8 temp; + + /* determine FIFO size and enable FIFO mode */ +- temp = readb(sport->port.membase + UARTPFIFO); ++ temp = readb(port->membase + UARTPFIFO); + + sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK); +- sport->port.fifosize = sport->txfifo_size; ++ port->fifosize = sport->txfifo_size; + + sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK); +@@ -1888,11 +1879,11 @@ static int lpuart32_startup(struct uart_port *port) + u32 temp; + + /* determine FIFO size */ +- temp = lpuart32_read(&sport->port, UARTFIFO); ++ temp = lpuart32_read(port, UARTFIFO); + + sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK); +- sport->port.fifosize = sport->txfifo_size; ++ port->fifosize = sport->txfifo_size; + + sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK); +@@ -1905,7 +1896,7 @@ static int lpuart32_startup(struct uart_port *port) + if (is_layerscape_lpuart(sport)) { + sport->rxfifo_size = 16; + sport->txfifo_size = 16; +- sport->port.fifosize = sport->txfifo_size; ++ port->fifosize = sport->txfifo_size; + } + + lpuart_request_dma(sport); +@@ -1965,8 +1956,8 @@ static void lpuart32_shutdown(struct uart_port *port) + uart_port_lock_irqsave(port, &flags); + + /* clear status */ +- temp = lpuart32_read(&sport->port, UARTSTAT); +- lpuart32_write(&sport->port, temp, UARTSTAT); ++ temp = lpuart32_read(port, UARTSTAT); ++ lpuart32_write(port, temp, UARTSTAT); + + /* disable Rx/Tx DMA */ + temp = lpuart32_read(port, UARTBAUD); +@@ -1995,12 +1986,12 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + unsigned int sbr, brfa; + +- cr1 = old_cr1 = readb(sport->port.membase + UARTCR1); +- old_cr2 = readb(sport->port.membase + UARTCR2); +- cr3 = readb(sport->port.membase + UARTCR3); +- cr4 = readb(sport->port.membase + UARTCR4); +- bdh = readb(sport->port.membase + UARTBDH); +- modem = readb(sport->port.membase + UARTMODEM); ++ cr1 = old_cr1 = readb(port->membase + UARTCR1); ++ old_cr2 = readb(port->membase + UARTCR2); ++ cr3 = readb(port->membase + UARTCR3); ++ cr4 = readb(port->membase + UARTCR4); ++ bdh = readb(port->membase + UARTBDH); ++ modem = readb(port->membase + UARTMODEM); + /* + * only support CS8 and CS7, and for CS7 must enable PE. + * supported mode: +@@ -2032,7 +2023,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + * When auto RS-485 RTS mode is enabled, + * hardware flow control need to be disabled. + */ +- if (sport->port.rs485.flags & SER_RS485_ENABLED) ++ if (port->rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + + if (termios->c_cflag & CRTSCTS) +@@ -2073,59 +2064,59 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + * Need to update the Ring buffer length according to the selected + * baud rate and restart Rx DMA path. + * +- * Since timer function acqures sport->port.lock, need to stop before ++ * Since timer function acqures port->lock, need to stop before + * acquring same lock because otherwise del_timer_sync() can deadlock. + */ + if (old && sport->lpuart_dma_rx_use) +- lpuart_dma_rx_free(&sport->port); ++ lpuart_dma_rx_free(port); + +- uart_port_lock_irqsave(&sport->port, &flags); ++ uart_port_lock_irqsave(port, &flags); + +- sport->port.read_status_mask = 0; ++ port->read_status_mask = 0; + if (termios->c_iflag & INPCK) +- sport->port.read_status_mask |= UARTSR1_FE | UARTSR1_PE; ++ port->read_status_mask |= UARTSR1_FE | UARTSR1_PE; + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) +- sport->port.read_status_mask |= UARTSR1_FE; ++ port->read_status_mask |= UARTSR1_FE; + + /* characters to ignore */ +- sport->port.ignore_status_mask = 0; ++ port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) +- sport->port.ignore_status_mask |= UARTSR1_PE; ++ port->ignore_status_mask |= UARTSR1_PE; + if (termios->c_iflag & IGNBRK) { +- sport->port.ignore_status_mask |= UARTSR1_FE; ++ port->ignore_status_mask |= UARTSR1_FE; + /* + * if we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) +- sport->port.ignore_status_mask |= UARTSR1_OR; ++ port->ignore_status_mask |= UARTSR1_OR; + } + + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + + /* wait transmit engin complete */ +- lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC); ++ lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TC); + + /* disable transmit and receive */ + writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE), +- sport->port.membase + UARTCR2); ++ port->membase + UARTCR2); + +- sbr = sport->port.uartclk / (16 * baud); +- brfa = ((sport->port.uartclk - (16 * sbr * baud)) * 2) / baud; ++ sbr = port->uartclk / (16 * baud); ++ brfa = ((port->uartclk - (16 * sbr * baud)) * 2) / baud; + bdh &= ~UARTBDH_SBR_MASK; + bdh |= (sbr >> 8) & 0x1F; + cr4 &= ~UARTCR4_BRFA_MASK; + brfa &= UARTCR4_BRFA_MASK; +- writeb(cr4 | brfa, sport->port.membase + UARTCR4); +- writeb(bdh, sport->port.membase + UARTBDH); +- writeb(sbr & 0xFF, sport->port.membase + UARTBDL); +- writeb(cr3, sport->port.membase + UARTCR3); +- writeb(cr1, sport->port.membase + UARTCR1); +- writeb(modem, sport->port.membase + UARTMODEM); ++ writeb(cr4 | brfa, port->membase + UARTCR4); ++ writeb(bdh, port->membase + UARTBDH); ++ writeb(sbr & 0xFF, port->membase + UARTBDL); ++ writeb(cr3, port->membase + UARTCR3); ++ writeb(cr1, port->membase + UARTCR1); ++ writeb(modem, port->membase + UARTMODEM); + + /* restore control register */ +- writeb(old_cr2, sport->port.membase + UARTCR2); ++ writeb(old_cr2, port->membase + UARTCR2); + + if (old && sport->lpuart_dma_rx_use) { + if (!lpuart_start_rx_dma(sport)) +@@ -2134,7 +2125,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + sport->lpuart_dma_rx_use = false; + } + +- uart_port_unlock_irqrestore(&sport->port, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static void __lpuart32_serial_setbrg(struct uart_port *port, +@@ -2232,9 +2223,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + unsigned int baud; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + +- ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL); +- bd = lpuart32_read(&sport->port, UARTBAUD); +- modem = lpuart32_read(&sport->port, UARTMODIR); ++ ctrl = old_ctrl = lpuart32_read(port, UARTCTRL); ++ bd = lpuart32_read(port, UARTBAUD); ++ modem = lpuart32_read(port, UARTMODIR); + sport->is_cs7 = false; + /* + * only support CS8 and CS7, and for CS7 must enable PE. +@@ -2267,7 +2258,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + * When auto RS-485 RTS mode is enabled, + * hardware flow control need to be disabled. + */ +- if (sport->port.rs485.flags & SER_RS485_ENABLED) ++ if (port->rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + + if (termios->c_cflag & CRTSCTS) +@@ -2308,32 +2299,32 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + * Need to update the Ring buffer length according to the selected + * baud rate and restart Rx DMA path. + * +- * Since timer function acqures sport->port.lock, need to stop before ++ * Since timer function acqures port->lock, need to stop before + * acquring same lock because otherwise del_timer_sync() can deadlock. + */ + if (old && sport->lpuart_dma_rx_use) +- lpuart_dma_rx_free(&sport->port); ++ lpuart_dma_rx_free(port); + +- uart_port_lock_irqsave(&sport->port, &flags); ++ uart_port_lock_irqsave(port, &flags); + +- sport->port.read_status_mask = 0; ++ port->read_status_mask = 0; + if (termios->c_iflag & INPCK) +- sport->port.read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; ++ port->read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) +- sport->port.read_status_mask |= UARTSTAT_FE; ++ port->read_status_mask |= UARTSTAT_FE; + + /* characters to ignore */ +- sport->port.ignore_status_mask = 0; ++ port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) +- sport->port.ignore_status_mask |= UARTSTAT_PE; ++ port->ignore_status_mask |= UARTSTAT_PE; + if (termios->c_iflag & IGNBRK) { +- sport->port.ignore_status_mask |= UARTSTAT_FE; ++ port->ignore_status_mask |= UARTSTAT_FE; + /* + * if we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) +- sport->port.ignore_status_mask |= UARTSTAT_OR; ++ port->ignore_status_mask |= UARTSTAT_OR; + } + + /* update the per-port timeout */ +@@ -2345,22 +2336,22 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + * asserted. + */ + if (!(old_ctrl & UARTCTRL_SBK)) { +- lpuart32_write(&sport->port, 0, UARTMODIR); +- lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); ++ lpuart32_write(port, 0, UARTMODIR); ++ lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); + } + + /* disable transmit and receive */ +- lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), ++ lpuart32_write(port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), + UARTCTRL); + +- lpuart32_write(&sport->port, bd, UARTBAUD); ++ lpuart32_write(port, bd, UARTBAUD); + lpuart32_serial_setbrg(sport, baud); + /* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */ +- lpuart32_write(&sport->port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); ++ lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); + /* restore control register */ +- lpuart32_write(&sport->port, ctrl, UARTCTRL); ++ lpuart32_write(port, ctrl, UARTCTRL); + /* re-enable the CTS if needed */ +- lpuart32_write(&sport->port, modem, UARTMODIR); ++ lpuart32_write(port, modem, UARTMODIR); + + if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE) + sport->is_cs7 = true; +@@ -2372,7 +2363,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + sport->lpuart_dma_rx_use = false; + } + +- uart_port_unlock_irqrestore(&sport->port, flags); ++ uart_port_unlock_irqrestore(port, flags); + } + + static const char *lpuart_type(struct uart_port *port) +@@ -2810,7 +2801,7 @@ static int lpuart_global_reset(struct lpuart_port *sport) + + ret = clk_prepare_enable(sport->ipg_clk); + if (ret) { +- dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret); ++ dev_err(port->dev, "failed to enable uart ipg clk: %d\n", ret); + return ret; + } + +@@ -2821,10 +2812,10 @@ static int lpuart_global_reset(struct lpuart_port *sport) + */ + ctrl = lpuart32_read(port, UARTCTRL); + if (ctrl & UARTCTRL_TE) { +- bd = lpuart32_read(&sport->port, UARTBAUD); ++ bd = lpuart32_read(port, UARTBAUD); + if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false, + port)) { +- dev_warn(sport->port.dev, ++ dev_warn(port->dev, + "timeout waiting for transmit engine to complete\n"); + clk_disable_unprepare(sport->ipg_clk); + return 0; +@@ -3176,7 +3167,7 @@ static void lpuart_console_fixup(struct lpuart_port *sport) + * in VLLS mode, or restore console setting here. + */ + if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) && +- console_suspend_enabled && uart_console(&sport->port)) { ++ console_suspend_enabled && uart_console(uport)) { + + mutex_lock(&port->mutex); + memset(&termios, 0, sizeof(struct ktermios)); +-- +2.39.5 + diff --git a/queue-6.12/tty-serial-fsl_lpuart-use-u32-and-u8-for-register-va.patch b/queue-6.12/tty-serial-fsl_lpuart-use-u32-and-u8-for-register-va.patch new file mode 100644 index 0000000000..e3c1137f44 --- /dev/null +++ b/queue-6.12/tty-serial-fsl_lpuart-use-u32-and-u8-for-register-va.patch @@ -0,0 +1,407 @@ +From e081c64f1c74ae9b29e61979af91680a8a962185 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 12 Mar 2025 10:39:02 +0800 +Subject: tty: serial: fsl_lpuart: Use u32 and u8 for register variables + +From: Sherry Sun + +[ Upstream commit b6a8f6ab2c53e5ea3c7f2a3978db378a89bb7595 ] + +Use u32 and u8 rather than unsigned long or unsigned char for register +variables for clarity and consistency. + +Signed-off-by: Sherry Sun +Link: https://lore.kernel.org/r/20250312023904.1343351-2-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: e98ab45ec518 ("tty: serial: lpuart: only disable CTS instead of overwriting the whole UARTMODIR register") +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/fsl_lpuart.c | 93 ++++++++++++++++----------------- + 1 file changed, 46 insertions(+), 47 deletions(-) + +diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c +index 9f9fc733eb2c1..e86fb9c60f1c3 100644 +--- a/drivers/tty/serial/fsl_lpuart.c ++++ b/drivers/tty/serial/fsl_lpuart.c +@@ -440,7 +440,7 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport) + + static void lpuart_stop_tx(struct uart_port *port) + { +- unsigned char temp; ++ u8 temp; + + temp = readb(port->membase + UARTCR2); + temp &= ~(UARTCR2_TIE | UARTCR2_TCIE); +@@ -449,7 +449,7 @@ static void lpuart_stop_tx(struct uart_port *port) + + static void lpuart32_stop_tx(struct uart_port *port) + { +- unsigned long temp; ++ u32 temp; + + temp = lpuart32_read(port, UARTCTRL); + temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); +@@ -458,7 +458,7 @@ static void lpuart32_stop_tx(struct uart_port *port) + + static void lpuart_stop_rx(struct uart_port *port) + { +- unsigned char temp; ++ u8 temp; + + temp = readb(port->membase + UARTCR2); + writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2); +@@ -466,7 +466,7 @@ static void lpuart_stop_rx(struct uart_port *port) + + static void lpuart32_stop_rx(struct uart_port *port) + { +- unsigned long temp; ++ u32 temp; + + temp = lpuart32_read(port, UARTCTRL); + lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL); +@@ -641,7 +641,7 @@ static int lpuart_poll_init(struct uart_port *port) + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + unsigned long flags; +- unsigned char temp; ++ u8 temp; + + sport->port.fifosize = 0; + +@@ -751,7 +751,7 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) + static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) + { + struct tty_port *tport = &sport->port.state->port; +- unsigned long txcnt; ++ u32 txcnt; + unsigned char c; + + if (sport->port.x_char) { +@@ -788,7 +788,7 @@ static void lpuart_start_tx(struct uart_port *port) + { + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); +- unsigned char temp; ++ u8 temp; + + temp = readb(port->membase + UARTCR2); + writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); +@@ -805,7 +805,7 @@ static void lpuart_start_tx(struct uart_port *port) + static void lpuart32_start_tx(struct uart_port *port) + { + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); +- unsigned long temp; ++ u32 temp; + + if (sport->lpuart_dma_tx_use) { + if (!lpuart_stopped_or_empty(port)) +@@ -838,8 +838,8 @@ static unsigned int lpuart_tx_empty(struct uart_port *port) + { + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); +- unsigned char sr1 = readb(port->membase + UARTSR1); +- unsigned char sfifo = readb(port->membase + UARTSFIFO); ++ u8 sr1 = readb(port->membase + UARTSR1); ++ u8 sfifo = readb(port->membase + UARTSFIFO); + + if (sport->dma_tx_in_progress) + return 0; +@@ -854,9 +854,9 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) + { + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); +- unsigned long stat = lpuart32_read(port, UARTSTAT); +- unsigned long sfifo = lpuart32_read(port, UARTFIFO); +- unsigned long ctrl = lpuart32_read(port, UARTCTRL); ++ u32 stat = lpuart32_read(port, UARTSTAT); ++ u32 sfifo = lpuart32_read(port, UARTFIFO); ++ u32 ctrl = lpuart32_read(port, UARTCTRL); + + if (sport->dma_tx_in_progress) + return 0; +@@ -883,7 +883,7 @@ static void lpuart_rxint(struct lpuart_port *sport) + { + unsigned int flg, ignored = 0, overrun = 0; + struct tty_port *port = &sport->port.state->port; +- unsigned char rx, sr; ++ u8 rx, sr; + + uart_port_lock(&sport->port); + +@@ -960,7 +960,7 @@ static void lpuart32_rxint(struct lpuart_port *sport) + { + unsigned int flg, ignored = 0; + struct tty_port *port = &sport->port.state->port; +- unsigned long rx, sr; ++ u32 rx, sr; + bool is_break; + + uart_port_lock(&sport->port); +@@ -1038,7 +1038,7 @@ static void lpuart32_rxint(struct lpuart_port *sport) + static irqreturn_t lpuart_int(int irq, void *dev_id) + { + struct lpuart_port *sport = dev_id; +- unsigned char sts; ++ u8 sts; + + sts = readb(sport->port.membase + UARTSR1); + +@@ -1112,7 +1112,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) + int count, copied; + + if (lpuart_is_32(sport)) { +- unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); ++ u32 sr = lpuart32_read(&sport->port, UARTSTAT); + + if (sr & (UARTSTAT_PE | UARTSTAT_FE)) { + /* Clear the error flags */ +@@ -1124,10 +1124,10 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) + sport->port.icount.frame++; + } + } else { +- unsigned char sr = readb(sport->port.membase + UARTSR1); ++ u8 sr = readb(sport->port.membase + UARTSR1); + + if (sr & (UARTSR1_PE | UARTSR1_FE)) { +- unsigned char cr2; ++ u8 cr2; + + /* Disable receiver during this operation... */ + cr2 = readb(sport->port.membase + UARTCR2); +@@ -1278,7 +1278,7 @@ static void lpuart32_dma_idleint(struct lpuart_port *sport) + static irqreturn_t lpuart32_int(int irq, void *dev_id) + { + struct lpuart_port *sport = dev_id; +- unsigned long sts, rxcount; ++ u32 sts, rxcount; + + sts = lpuart32_read(&sport->port, UARTSTAT); + rxcount = lpuart32_read(&sport->port, UARTWATER); +@@ -1410,12 +1410,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) + dma_async_issue_pending(chan); + + if (lpuart_is_32(sport)) { +- unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); ++ u32 temp = lpuart32_read(&sport->port, UARTBAUD); + + lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD); + + if (sport->dma_idle_int) { +- unsigned long ctrl = lpuart32_read(&sport->port, UARTCTRL); ++ u32 ctrl = lpuart32_read(&sport->port, UARTCTRL); + + lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL); + } +@@ -1481,7 +1481,7 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + +- unsigned long modem = lpuart32_read(&sport->port, UARTMODIR) ++ u32 modem = lpuart32_read(&sport->port, UARTMODIR) + & ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE); + u32 ctrl; + +@@ -1576,7 +1576,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) + + static void lpuart_break_ctl(struct uart_port *port, int break_state) + { +- unsigned char temp; ++ u8 temp; + + temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK; + +@@ -1588,7 +1588,7 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state) + + static void lpuart32_break_ctl(struct uart_port *port, int break_state) + { +- unsigned long temp; ++ u32 temp; + + temp = lpuart32_read(port, UARTCTRL); + +@@ -1622,8 +1622,7 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state) + + static void lpuart_setup_watermark(struct lpuart_port *sport) + { +- unsigned char val, cr2; +- unsigned char cr2_saved; ++ u8 val, cr2, cr2_saved; + + cr2 = readb(sport->port.membase + UARTCR2); + cr2_saved = cr2; +@@ -1656,7 +1655,7 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) + + static void lpuart_setup_watermark_enable(struct lpuart_port *sport) + { +- unsigned char cr2; ++ u8 cr2; + + lpuart_setup_watermark(sport); + +@@ -1667,8 +1666,7 @@ static void lpuart_setup_watermark_enable(struct lpuart_port *sport) + + static void lpuart32_setup_watermark(struct lpuart_port *sport) + { +- unsigned long val, ctrl; +- unsigned long ctrl_saved; ++ u32 val, ctrl, ctrl_saved; + + ctrl = lpuart32_read(&sport->port, UARTCTRL); + ctrl_saved = ctrl; +@@ -1777,7 +1775,7 @@ static void lpuart_tx_dma_startup(struct lpuart_port *sport) + static void lpuart_rx_dma_startup(struct lpuart_port *sport) + { + int ret; +- unsigned char cr3; ++ u8 cr3; + + if (uart_console(&sport->port)) + goto err; +@@ -1827,7 +1825,7 @@ static void lpuart_hw_setup(struct lpuart_port *sport) + static int lpuart_startup(struct uart_port *port) + { + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); +- unsigned char temp; ++ u8 temp; + + /* determine FIFO size and enable FIFO mode */ + temp = readb(sport->port.membase + UARTPFIFO); +@@ -1847,7 +1845,7 @@ static int lpuart_startup(struct uart_port *port) + + static void lpuart32_hw_disable(struct lpuart_port *sport) + { +- unsigned long temp; ++ u32 temp; + + temp = lpuart32_read(&sport->port, UARTCTRL); + temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE | +@@ -1857,7 +1855,7 @@ static void lpuart32_hw_disable(struct lpuart_port *sport) + + static void lpuart32_configure(struct lpuart_port *sport) + { +- unsigned long temp; ++ u32 temp; + + temp = lpuart32_read(&sport->port, UARTCTRL); + if (!sport->lpuart_dma_rx_use) +@@ -1887,7 +1885,7 @@ static void lpuart32_hw_setup(struct lpuart_port *sport) + static int lpuart32_startup(struct uart_port *port) + { + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); +- unsigned long temp; ++ u32 temp; + + /* determine FIFO size */ + temp = lpuart32_read(&sport->port, UARTFIFO); +@@ -1941,7 +1939,7 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport) + static void lpuart_shutdown(struct uart_port *port) + { + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); +- unsigned char temp; ++ u8 temp; + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); +@@ -1961,7 +1959,7 @@ static void lpuart32_shutdown(struct uart_port *port) + { + struct lpuart_port *sport = + container_of(port, struct lpuart_port, port); +- unsigned long temp; ++ u32 temp; + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); +@@ -1992,7 +1990,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, + { + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long flags; +- unsigned char cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem; ++ u8 cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem; + unsigned int baud; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + unsigned int sbr, brfa; +@@ -2230,7 +2228,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + { + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned long flags; +- unsigned long ctrl, old_ctrl, bd, modem; ++ u32 ctrl, old_ctrl, bd, modem; + unsigned int baud; + unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; + +@@ -2487,7 +2485,7 @@ static void + lpuart_console_write(struct console *co, const char *s, unsigned int count) + { + struct lpuart_port *sport = lpuart_ports[co->index]; +- unsigned char old_cr2, cr2; ++ u8 old_cr2, cr2; + unsigned long flags; + int locked = 1; + +@@ -2517,7 +2515,7 @@ static void + lpuart32_console_write(struct console *co, const char *s, unsigned int count) + { + struct lpuart_port *sport = lpuart_ports[co->index]; +- unsigned long old_cr, cr; ++ u32 old_cr, cr; + unsigned long flags; + int locked = 1; + +@@ -2551,7 +2549,7 @@ static void __init + lpuart_console_get_options(struct lpuart_port *sport, int *baud, + int *parity, int *bits) + { +- unsigned char cr, bdh, bdl, brfa; ++ u8 cr, bdh, bdl, brfa; + unsigned int sbr, uartclk, baud_raw; + + cr = readb(sport->port.membase + UARTCR2); +@@ -2600,7 +2598,7 @@ static void __init + lpuart32_console_get_options(struct lpuart_port *sport, int *baud, + int *parity, int *bits) + { +- unsigned long cr, bd; ++ u32 cr, bd; + unsigned int sbr, uartclk, baud_raw; + + cr = lpuart32_read(&sport->port, UARTCTRL); +@@ -2806,7 +2804,7 @@ static int lpuart_global_reset(struct lpuart_port *sport) + { + struct uart_port *port = &sport->port; + void __iomem *global_addr; +- unsigned long ctrl, bd; ++ u32 ctrl, bd; + unsigned int val = 0; + int ret; + +@@ -3012,7 +3010,7 @@ static int lpuart_runtime_resume(struct device *dev) + + static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on) + { +- unsigned int val, baud; ++ u32 val, baud; + + if (lpuart_is_32(sport)) { + val = lpuart32_read(&sport->port, UARTCTRL); +@@ -3077,7 +3075,7 @@ static int lpuart_suspend_noirq(struct device *dev) + static int lpuart_resume_noirq(struct device *dev) + { + struct lpuart_port *sport = dev_get_drvdata(dev); +- unsigned int val; ++ u32 val; + + pinctrl_pm_select_default_state(dev); + +@@ -3097,7 +3095,8 @@ static int lpuart_resume_noirq(struct device *dev) + static int lpuart_suspend(struct device *dev) + { + struct lpuart_port *sport = dev_get_drvdata(dev); +- unsigned long temp, flags; ++ u32 temp; ++ unsigned long flags; + + uart_suspend_port(&lpuart_reg, &sport->port); + +-- +2.39.5 + diff --git a/queue-6.12/tty-serial-lpuart-only-disable-cts-instead-of-overwr.patch b/queue-6.12/tty-serial-lpuart-only-disable-cts-instead-of-overwr.patch new file mode 100644 index 0000000000..3fa85cbe75 --- /dev/null +++ b/queue-6.12/tty-serial-lpuart-only-disable-cts-instead-of-overwr.patch @@ -0,0 +1,65 @@ +From 2ae3bf84c036c1480900f85c931409511ce282ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 7 Mar 2025 14:54:46 +0800 +Subject: tty: serial: lpuart: only disable CTS instead of overwriting the + whole UARTMODIR register + +From: Sherry Sun + +[ Upstream commit e98ab45ec5182605d2e00114cba3bbf46b0ea27f ] + +No need to overwrite the whole UARTMODIR register before waiting the +transmit engine complete, actually our target here is only to disable +CTS flow control to avoid the dirty data in TX FIFO may block the +transmit engine complete. +Also delete the following duplicate CTS disable configuration. + +Fixes: d5a2e0834364 ("tty: serial: lpuart: disable flow control while waiting for the transmit engine to complete") +Cc: stable +Signed-off-by: Sherry Sun +Link: https://lore.kernel.org/r/20250307065446.1122482-1-sherry.sun@nxp.com +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/tty/serial/fsl_lpuart.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c +index c2b522843b72c..951c3cdac3b94 100644 +--- a/drivers/tty/serial/fsl_lpuart.c ++++ b/drivers/tty/serial/fsl_lpuart.c +@@ -2330,15 +2330,19 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + ++ /* ++ * disable CTS to ensure the transmit engine is not blocked by the flow ++ * control when there is dirty data in TX FIFO ++ */ ++ lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); ++ + /* + * LPUART Transmission Complete Flag may never be set while queuing a break + * character, so skip waiting for transmission complete when UARTCTRL_SBK is + * asserted. + */ +- if (!(old_ctrl & UARTCTRL_SBK)) { +- lpuart32_write(port, 0, UARTMODIR); ++ if (!(old_ctrl & UARTCTRL_SBK)) + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC); +- } + + /* disable transmit and receive */ + lpuart32_write(port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), +@@ -2346,8 +2350,6 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, + + lpuart32_write(port, bd, UARTBAUD); + lpuart32_serial_setbrg(sport, baud); +- /* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */ +- lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR); + /* restore control register */ + lpuart32_write(port, ctrl, UARTCTRL); + /* re-enable the CTS if needed */ +-- +2.39.5 +