]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.12
authorSasha Levin <sashal@kernel.org>
Sun, 2 Mar 2025 14:46:02 +0000 (09:46 -0500)
committerSasha Levin <sashal@kernel.org>
Sun, 2 Mar 2025 14:46:02 +0000 (09:46 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
13 files changed:
queue-6.12/io_uring-net-save-msg_control-for-compat.patch [new file with mode: 0644]
queue-6.12/objtool-fix-c-jump-table-annotations-for-clang.patch [new file with mode: 0644]
queue-6.12/objtool-remove-annotate_-un-reachable.patch [new file with mode: 0644]
queue-6.12/perf-core-order-the-pmu-list-to-fix-warning-about-un.patch [new file with mode: 0644]
queue-6.12/series
queue-6.12/thermal-core-move-lists-of-thermal-instances-to-trip.patch [new file with mode: 0644]
queue-6.12/thermal-gov_power_allocator-fix-incorrect-calculatio.patch [new file with mode: 0644]
queue-6.12/thermal-gov_power_allocator-update-total_weight-on-b.patch [new file with mode: 0644]
queue-6.12/thermal-of-fix-cdev-lookup-in-thermal_of_should_bind.patch [new file with mode: 0644]
queue-6.12/thermal-of-simplify-thermal_of_should_bind-with-scop.patch [new file with mode: 0644]
queue-6.12/unreachable-unify.patch [new file with mode: 0644]
queue-6.12/uprobes-reject-the-shared-zeropage-in-uprobe_write_o.patch [new file with mode: 0644]
queue-6.12/x86-cpu-fix-warm-boot-hang-regression-on-amd-sc1100-.patch [new file with mode: 0644]

diff --git a/queue-6.12/io_uring-net-save-msg_control-for-compat.patch b/queue-6.12/io_uring-net-save-msg_control-for-compat.patch
new file mode 100644 (file)
index 0000000..1c23b11
--- /dev/null
@@ -0,0 +1,39 @@
+From db843bd4fc488cf0f1f24a668a67eedfeea8d9df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 15:59:02 +0000
+Subject: io_uring/net: save msg_control for compat
+
+From: Pavel Begunkov <asml.silence@gmail.com>
+
+[ Upstream commit 6ebf05189dfc6d0d597c99a6448a4d1064439a18 ]
+
+Match the compat part of io_sendmsg_copy_hdr() with its counterpart and
+save msg_control.
+
+Fixes: c55978024d123 ("io_uring/net: move receive multishot out of the generic msghdr path")
+Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
+Link: https://lore.kernel.org/r/2a8418821fe83d3b64350ad2b3c0303e9b732bbd.1740498502.git.asml.silence@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/net.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/io_uring/net.c b/io_uring/net.c
+index 3974c417fe264..f32311f641133 100644
+--- a/io_uring/net.c
++++ b/io_uring/net.c
+@@ -334,7 +334,9 @@ static int io_sendmsg_copy_hdr(struct io_kiocb *req,
+               if (unlikely(ret))
+                       return ret;
+-              return __get_compat_msghdr(&iomsg->msg, &cmsg, NULL);
++              ret = __get_compat_msghdr(&iomsg->msg, &cmsg, NULL);
++              sr->msg_control = iomsg->msg.msg_control_user;
++              return ret;
+       }
+ #endif
+-- 
+2.39.5
+
diff --git a/queue-6.12/objtool-fix-c-jump-table-annotations-for-clang.patch b/queue-6.12/objtool-fix-c-jump-table-annotations-for-clang.patch
new file mode 100644 (file)
index 0000000..204480c
--- /dev/null
@@ -0,0 +1,106 @@
+From 273b2b356d477172d531f414fb47580deb21705d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 14:57:07 +0100
+Subject: objtool: Fix C jump table annotations for Clang
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+[ Upstream commit 73cfc53cc3b6380eccf013049574485f64cb83ca ]
+
+A C jump table (such as the one used by the BPF interpreter) is a const
+global array of absolute code addresses, and this means that the actual
+values in the table may not be known until the kernel is booted (e.g.,
+when using KASLR or when the kernel VA space is sized dynamically).
+
+When using PIE codegen, the compiler will default to placing such const
+global objects in .data.rel.ro (which is annotated as writable), rather
+than .rodata (which is annotated as read-only). As C jump tables are
+explicitly emitted into .rodata, this used to result in warnings for
+LoongArch builds (which uses PIE codegen for the entire kernel) like
+
+  Warning: setting incorrect section attributes for .rodata..c_jump_table
+
+due to the fact that the explicitly specified .rodata section inherited
+the read-write annotation that the compiler uses for such objects when
+using PIE codegen.
+
+This warning was suppressed by explicitly adding the read-only
+annotation to the __attribute__((section(""))) string, by commit
+
+  c5b1184decc8 ("compiler.h: specify correct attribute for .rodata..c_jump_table")
+
+Unfortunately, this hack does not work on Clang's integrated assembler,
+which happily interprets the appended section type and permission
+specifiers as part of the section name, which therefore no longer
+matches the hard-coded pattern '.rodata..c_jump_table' that objtool
+expects, causing it to emit a warning
+
+  kernel/bpf/core.o: warning: objtool: ___bpf_prog_run+0x20: sibling call from callable instruction with modified stack frame
+
+Work around this, by emitting C jump tables into .data.rel.ro instead,
+which is treated as .rodata by the linker script for all builds, not
+just PIE based ones.
+
+Fixes: c5b1184decc8 ("compiler.h: specify correct attribute for .rodata..c_jump_table")
+Tested-by: Tiezhu Yang <yangtiezhu@loongson.cn> # on LoongArch
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Link: https://lore.kernel.org/r/20250221135704.431269-6-ardb+git@google.com
+Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/compiler.h                | 2 +-
+ tools/objtool/check.c                   | 7 ++++---
+ tools/objtool/include/objtool/special.h | 2 +-
+ 3 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/include/linux/compiler.h b/include/linux/compiler.h
+index 75a83394824c4..b15911e201bf9 100644
+--- a/include/linux/compiler.h
++++ b/include/linux/compiler.h
+@@ -110,7 +110,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
+ /* Unreachable code */
+ #ifdef CONFIG_OBJTOOL
+ /* Annotate a C jump table to allow objtool to follow the code flow */
+-#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
++#define __annotate_jump_table __section(".data.rel.ro.c_jump_table")
+ #else /* !CONFIG_OBJTOOL */
+ #define __annotate_jump_table
+ #endif /* CONFIG_OBJTOOL */
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 3e72c9f9b7f37..1691aa6e6ce32 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -2589,13 +2589,14 @@ static void mark_rodata(struct objtool_file *file)
+        *
+        * - .rodata: can contain GCC switch tables
+        * - .rodata.<func>: same, if -fdata-sections is being used
+-       * - .rodata..c_jump_table: contains C annotated jump tables
++       * - .data.rel.ro.c_jump_table: contains C annotated jump tables
+        *
+        * .rodata.str1.* sections are ignored; they don't contain jump tables.
+        */
+       for_each_sec(file, sec) {
+-              if (!strncmp(sec->name, ".rodata", 7) &&
+-                  !strstr(sec->name, ".str1.")) {
++              if ((!strncmp(sec->name, ".rodata", 7) &&
++                   !strstr(sec->name, ".str1.")) ||
++                  !strncmp(sec->name, ".data.rel.ro", 12)) {
+                       sec->rodata = true;
+                       found = true;
+               }
+diff --git a/tools/objtool/include/objtool/special.h b/tools/objtool/include/objtool/special.h
+index 86d4af9c5aa9d..89ee12b1a1384 100644
+--- a/tools/objtool/include/objtool/special.h
++++ b/tools/objtool/include/objtool/special.h
+@@ -10,7 +10,7 @@
+ #include <objtool/check.h>
+ #include <objtool/elf.h>
+-#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
++#define C_JUMP_TABLE_SECTION ".data.rel.ro.c_jump_table"
+ struct special_alt {
+       struct list_head list;
+-- 
+2.39.5
+
diff --git a/queue-6.12/objtool-remove-annotate_-un-reachable.patch b/queue-6.12/objtool-remove-annotate_-un-reachable.patch
new file mode 100644 (file)
index 0000000..8385780
--- /dev/null
@@ -0,0 +1,131 @@
+From 50b86ed96bd4f0841461dd8516a20b5259c5445a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Nov 2024 10:39:04 +0100
+Subject: objtool: Remove annotate_{,un}reachable()
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit 06e24745985c8dd0da18337503afcf2f2fdbdff1 ]
+
+There are no users of annotate_reachable() left.
+
+And the annotate_unreachable() usage in unreachable() is plain wrong;
+it will hide dangerous fall-through code-gen.
+
+Remove both.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Link: https://lore.kernel.org/r/20241128094312.235637588@infradead.org
+Stable-dep-of: 73cfc53cc3b6 ("objtool: Fix C jump table annotations for Clang")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/compiler.h | 27 -------------------------
+ tools/objtool/check.c    | 43 ++--------------------------------------
+ 2 files changed, 2 insertions(+), 68 deletions(-)
+
+diff --git a/include/linux/compiler.h b/include/linux/compiler.h
+index 0d10d75218f51..75a83394824c4 100644
+--- a/include/linux/compiler.h
++++ b/include/linux/compiler.h
+@@ -109,35 +109,9 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
+ /* Unreachable code */
+ #ifdef CONFIG_OBJTOOL
+-/*
+- * These macros help objtool understand GCC code flow for unreachable code.
+- * The __COUNTER__ based labels are a hack to make each instance of the macros
+- * unique, to convince GCC not to merge duplicate inline asm statements.
+- */
+-#define __stringify_label(n) #n
+-
+-#define __annotate_reachable(c) ({                                    \
+-      asm volatile(__stringify_label(c) ":\n\t"                       \
+-                      ".pushsection .discard.reachable\n\t"           \
+-                      ".long " __stringify_label(c) "b - .\n\t"       \
+-                      ".popsection\n\t");                             \
+-})
+-#define annotate_reachable() __annotate_reachable(__COUNTER__)
+-
+-#define __annotate_unreachable(c) ({                                  \
+-      asm volatile(__stringify_label(c) ":\n\t"                       \
+-                   ".pushsection .discard.unreachable\n\t"            \
+-                   ".long " __stringify_label(c) "b - .\n\t"          \
+-                   ".popsection\n\t" : : "i" (c));                    \
+-})
+-#define annotate_unreachable() __annotate_unreachable(__COUNTER__)
+-
+ /* Annotate a C jump table to allow objtool to follow the code flow */
+ #define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
+-
+ #else /* !CONFIG_OBJTOOL */
+-#define annotate_reachable()
+-#define annotate_unreachable()
+ #define __annotate_jump_table
+ #endif /* CONFIG_OBJTOOL */
+@@ -147,7 +121,6 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
+  * control elsewhere.
+  */
+ #define unreachable() do {            \
+-      annotate_unreachable();         \
+       barrier_before_unreachable();   \
+       __builtin_unreachable();        \
+ } while (0)
+diff --git a/tools/objtool/check.c b/tools/objtool/check.c
+index 8e02db7e83323..3e72c9f9b7f37 100644
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -639,47 +639,8 @@ static int add_dead_ends(struct objtool_file *file)
+       uint64_t offset;
+       /*
+-       * Check for manually annotated dead ends.
+-       */
+-      rsec = find_section_by_name(file->elf, ".rela.discard.unreachable");
+-      if (!rsec)
+-              goto reachable;
+-
+-      for_each_reloc(rsec, reloc) {
+-              if (reloc->sym->type == STT_SECTION) {
+-                      offset = reloc_addend(reloc);
+-              } else if (reloc->sym->local_label) {
+-                      offset = reloc->sym->offset;
+-              } else {
+-                      WARN("unexpected relocation symbol type in %s", rsec->name);
+-                      return -1;
+-              }
+-
+-              insn = find_insn(file, reloc->sym->sec, offset);
+-              if (insn)
+-                      insn = prev_insn_same_sec(file, insn);
+-              else if (offset == reloc->sym->sec->sh.sh_size) {
+-                      insn = find_last_insn(file, reloc->sym->sec);
+-                      if (!insn) {
+-                              WARN("can't find unreachable insn at %s+0x%" PRIx64,
+-                                   reloc->sym->sec->name, offset);
+-                              return -1;
+-                      }
+-              } else {
+-                      WARN("can't find unreachable insn at %s+0x%" PRIx64,
+-                           reloc->sym->sec->name, offset);
+-                      return -1;
+-              }
+-
+-              insn->dead_end = true;
+-      }
+-
+-reachable:
+-      /*
+-       * These manually annotated reachable checks are needed for GCC 4.4,
+-       * where the Linux unreachable() macro isn't supported.  In that case
+-       * GCC doesn't know the "ud2" is fatal, so it generates code as if it's
+-       * not a dead end.
++       * UD2 defaults to being a dead-end, allow them to be annotated for
++       * non-fatal, eg WARN.
+        */
+       rsec = find_section_by_name(file->elf, ".rela.discard.reachable");
+       if (!rsec)
+-- 
+2.39.5
+
diff --git a/queue-6.12/perf-core-order-the-pmu-list-to-fix-warning-about-un.patch b/queue-6.12/perf-core-order-the-pmu-list-to-fix-warning-about-un.patch
new file mode 100644 (file)
index 0000000..a9ff268
--- /dev/null
@@ -0,0 +1,108 @@
+From 865be596804db96f9665c98997e719e0cff8e717 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Jan 2025 07:33:56 +0000
+Subject: perf/core: Order the PMU list to fix warning about unordered
+ pmu_ctx_list
+
+From: Luo Gengkun <luogengkun@huaweicloud.com>
+
+[ Upstream commit 2016066c66192a99d9e0ebf433789c490a6785a2 ]
+
+Syskaller triggers a warning due to prev_epc->pmu != next_epc->pmu in
+perf_event_swap_task_ctx_data(). vmcore shows that two lists have the same
+perf_event_pmu_context, but not in the same order.
+
+The problem is that the order of pmu_ctx_list for the parent is impacted by
+the time when an event/PMU is added. While the order for a child is
+impacted by the event order in the pinned_groups and flexible_groups. So
+the order of pmu_ctx_list in the parent and child may be different.
+
+To fix this problem, insert the perf_event_pmu_context to its proper place
+after iteration of the pmu_ctx_list.
+
+The follow testcase can trigger above warning:
+
+ # perf record -e cycles --call-graph lbr -- taskset -c 3 ./a.out &
+ # perf stat -e cpu-clock,cs -p xxx // xxx is the pid of a.out
+
+ test.c
+
+ void main() {
+        int count = 0;
+        pid_t pid;
+
+        printf("%d running\n", getpid());
+        sleep(30);
+        printf("running\n");
+
+        pid = fork();
+        if (pid == -1) {
+                printf("fork error\n");
+                return;
+        }
+        if (pid == 0) {
+                while (1) {
+                        count++;
+                }
+        } else {
+                while (1) {
+                        count++;
+                }
+        }
+ }
+
+The testcase first opens an LBR event, so it will allocate task_ctx_data,
+and then open tracepoint and software events, so the parent context will
+have 3 different perf_event_pmu_contexts. On inheritance, child ctx will
+insert the perf_event_pmu_context in another order and the warning will
+trigger.
+
+[ mingo: Tidied up the changelog. ]
+
+Fixes: bd2756811766 ("perf: Rewrite core context handling")
+Signed-off-by: Luo Gengkun <luogengkun@huaweicloud.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: Kan Liang <kan.liang@linux.intel.com>
+Link: https://lore.kernel.org/r/20250122073356.1824736-1-luogengkun@huaweicloud.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 501d8c2fedff4..07cd2dbab0e88 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4957,7 +4957,7 @@ static struct perf_event_pmu_context *
+ find_get_pmu_context(struct pmu *pmu, struct perf_event_context *ctx,
+                    struct perf_event *event)
+ {
+-      struct perf_event_pmu_context *new = NULL, *epc;
++      struct perf_event_pmu_context *new = NULL, *pos = NULL, *epc;
+       void *task_ctx_data = NULL;
+       if (!ctx->task) {
+@@ -5014,12 +5014,19 @@ find_get_pmu_context(struct pmu *pmu, struct perf_event_context *ctx,
+                       atomic_inc(&epc->refcount);
+                       goto found_epc;
+               }
++              /* Make sure the pmu_ctx_list is sorted by PMU type: */
++              if (!pos && epc->pmu->type > pmu->type)
++                      pos = epc;
+       }
+       epc = new;
+       new = NULL;
+-      list_add(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list);
++      if (!pos)
++              list_add_tail(&epc->pmu_ctx_entry, &ctx->pmu_ctx_list);
++      else
++              list_add(&epc->pmu_ctx_entry, pos->pmu_ctx_entry.prev);
++
+       epc->ctx = ctx;
+ found_epc:
+-- 
+2.39.5
+
index 5f62abf2151134d0edba0033a20cd8aee793f9dd..36427766123d9f3a8d7a79e1ae5df6fd8870781b 100644 (file)
@@ -64,3 +64,15 @@ net-ipv6-fix-dst-ref-loop-on-input-in-rpl-lwt.patch
 selftests-drv-net-check-if-combined-count-exists.patch
 idpf-fix-checksums-set-in-idpf_rx_rsc.patch
 net-ti-icss-iep-reject-perout-generation-request.patch
+thermal-gov_power_allocator-fix-incorrect-calculatio.patch
+perf-core-order-the-pmu-list-to-fix-warning-about-un.patch
+uprobes-reject-the-shared-zeropage-in-uprobe_write_o.patch
+thermal-of-simplify-thermal_of_should_bind-with-scop.patch
+thermal-of-fix-cdev-lookup-in-thermal_of_should_bind.patch
+thermal-core-move-lists-of-thermal-instances-to-trip.patch
+thermal-gov_power_allocator-update-total_weight-on-b.patch
+io_uring-net-save-msg_control-for-compat.patch
+unreachable-unify.patch
+objtool-remove-annotate_-un-reachable.patch
+objtool-fix-c-jump-table-annotations-for-clang.patch
+x86-cpu-fix-warm-boot-hang-regression-on-amd-sc1100-.patch
diff --git a/queue-6.12/thermal-core-move-lists-of-thermal-instances-to-trip.patch b/queue-6.12/thermal-core-move-lists-of-thermal-instances-to-trip.patch
new file mode 100644 (file)
index 0000000..8cb0345
--- /dev/null
@@ -0,0 +1,459 @@
+From 6db51643767ef171b6d334feebbb44a19c4e38b5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 4 Oct 2024 21:39:19 +0200
+Subject: thermal: core: Move lists of thermal instances to trip descriptors
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 0dc23567c20639049ad57fd8cc2165ee9f493ab6 ]
+
+In almost all places where a thermal zone's list of thermal instances
+is walked, there is a check to match a specific trip point and it is
+walked in vain whenever there are no cooling devices associated with
+the given trip.
+
+To address this, store the lists of thermal instances in trip point
+descriptors instead of storing them in thermal zones and adjust all
+code using those lists accordingly.
+
+No intentional functional impact.
+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Link: https://patch.msgid.link/5522726.Sb9uPGUboI@rjwysocki.net
+Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
+Stable-dep-of: 0cde378a10c1 ("thermal: gov_power_allocator: Update total_weight on bind and cdev updates")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/gov_bang_bang.c       | 11 ++++----
+ drivers/thermal/gov_fair_share.c      | 16 ++++-------
+ drivers/thermal/gov_power_allocator.c | 40 +++++++++++++--------------
+ drivers/thermal/gov_step_wise.c       | 16 +++++------
+ drivers/thermal/thermal_core.c        | 33 ++++++++++++----------
+ drivers/thermal/thermal_core.h        |  5 ++--
+ drivers/thermal/thermal_helpers.c     |  5 ++--
+ 7 files changed, 62 insertions(+), 64 deletions(-)
+
+diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
+index 863e7a4272e66..b887e48e8c7e6 100644
+--- a/drivers/thermal/gov_bang_bang.c
++++ b/drivers/thermal/gov_bang_bang.c
+@@ -67,6 +67,7 @@ static void bang_bang_control(struct thermal_zone_device *tz,
+                             const struct thermal_trip *trip,
+                             bool crossed_up)
+ {
++      const struct thermal_trip_desc *td = trip_to_trip_desc(trip);
+       struct thermal_instance *instance;
+       lockdep_assert_held(&tz->lock);
+@@ -75,10 +76,8 @@ static void bang_bang_control(struct thermal_zone_device *tz,
+               thermal_zone_trip_id(tz, trip), trip->temperature,
+               tz->temperature, trip->hysteresis);
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+-              if (instance->trip == trip)
+-                      bang_bang_set_instance_target(instance, crossed_up);
+-      }
++      list_for_each_entry(instance, &td->thermal_instances, trip_node)
++              bang_bang_set_instance_target(instance, crossed_up);
+ }
+ static void bang_bang_manage(struct thermal_zone_device *tz)
+@@ -104,8 +103,8 @@ static void bang_bang_manage(struct thermal_zone_device *tz)
+                * to the thermal zone temperature and the trip point threshold.
+                */
+               turn_on = tz->temperature >= td->threshold;
+-              list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+-                      if (!instance->initialized && instance->trip == trip)
++              list_for_each_entry(instance, &td->thermal_instances, trip_node) {
++                      if (!instance->initialized)
+                               bang_bang_set_instance_target(instance, turn_on);
+               }
+       }
+diff --git a/drivers/thermal/gov_fair_share.c b/drivers/thermal/gov_fair_share.c
+index ce0ea571ed67a..d37d57d48c389 100644
+--- a/drivers/thermal/gov_fair_share.c
++++ b/drivers/thermal/gov_fair_share.c
+@@ -44,7 +44,7 @@ static int get_trip_level(struct thermal_zone_device *tz)
+ /**
+  * fair_share_throttle - throttles devices associated with the given zone
+  * @tz: thermal_zone_device
+- * @trip: trip point
++ * @td: trip point descriptor
+  * @trip_level: number of trips crossed by the zone temperature
+  *
+  * Throttling Logic: This uses three parameters to calculate the new
+@@ -61,29 +61,23 @@ static int get_trip_level(struct thermal_zone_device *tz)
+  * new_state of cooling device = P3 * P2 * P1
+  */
+ static void fair_share_throttle(struct thermal_zone_device *tz,
+-                              const struct thermal_trip *trip,
++                              const struct thermal_trip_desc *td,
+                               int trip_level)
+ {
+       struct thermal_instance *instance;
+       int total_weight = 0;
+       int nr_instances = 0;
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+-              if (instance->trip != trip)
+-                      continue;
+-
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
+               total_weight += instance->weight;
+               nr_instances++;
+       }
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
+               struct thermal_cooling_device *cdev = instance->cdev;
+               u64 dividend;
+               u32 divisor;
+-              if (instance->trip != trip)
+-                      continue;
+-
+               dividend = trip_level;
+               dividend *= cdev->max_state;
+               divisor = tz->num_trips;
+@@ -116,7 +110,7 @@ static void fair_share_manage(struct thermal_zone_device *tz)
+                   trip->type == THERMAL_TRIP_HOT)
+                       continue;
+-              fair_share_throttle(tz, trip, trip_level);
++              fair_share_throttle(tz, td, trip_level);
+       }
+ }
+diff --git a/drivers/thermal/gov_power_allocator.c b/drivers/thermal/gov_power_allocator.c
+index d59549e616399..b00da17c66a90 100644
+--- a/drivers/thermal/gov_power_allocator.c
++++ b/drivers/thermal/gov_power_allocator.c
+@@ -97,11 +97,9 @@ struct power_allocator_params {
+       struct power_actor *power;
+ };
+-static bool power_actor_is_valid(struct power_allocator_params *params,
+-                               struct thermal_instance *instance)
++static bool power_actor_is_valid(struct thermal_instance *instance)
+ {
+-      return (instance->trip == params->trip_max &&
+-               cdev_is_power_actor(instance->cdev));
++      return cdev_is_power_actor(instance->cdev);
+ }
+ /**
+@@ -118,13 +116,14 @@ static bool power_actor_is_valid(struct power_allocator_params *params,
+ static u32 estimate_sustainable_power(struct thermal_zone_device *tz)
+ {
+       struct power_allocator_params *params = tz->governor_data;
++      const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
+       struct thermal_cooling_device *cdev;
+       struct thermal_instance *instance;
+       u32 sustainable_power = 0;
+       u32 min_power;
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+-              if (!power_actor_is_valid(params, instance))
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
++              if (!power_actor_is_valid(instance))
+                       continue;
+               cdev = instance->cdev;
+@@ -400,6 +399,7 @@ static void divvy_up_power(struct power_actor *power, int num_actors,
+ static void allocate_power(struct thermal_zone_device *tz, int control_temp)
+ {
+       struct power_allocator_params *params = tz->governor_data;
++      const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
+       unsigned int num_actors = params->num_actors;
+       struct power_actor *power = params->power;
+       struct thermal_cooling_device *cdev;
+@@ -417,10 +417,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp)
+       /* Clean all buffers for new power estimations */
+       memset(power, 0, params->buffer_size);
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
+               struct power_actor *pa = &power[i];
+-              if (!power_actor_is_valid(params, instance))
++              if (!power_actor_is_valid(instance))
+                       continue;
+               cdev = instance->cdev;
+@@ -454,10 +454,10 @@ static void allocate_power(struct thermal_zone_device *tz, int control_temp)
+                      power_range);
+       i = 0;
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
+               struct power_actor *pa = &power[i];
+-              if (!power_actor_is_valid(params, instance))
++              if (!power_actor_is_valid(instance))
+                       continue;
+               power_actor_set_power(instance->cdev, instance,
+@@ -538,12 +538,13 @@ static void reset_pid_controller(struct power_allocator_params *params)
+ static void allow_maximum_power(struct thermal_zone_device *tz)
+ {
+       struct power_allocator_params *params = tz->governor_data;
++      const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
+       struct thermal_cooling_device *cdev;
+       struct thermal_instance *instance;
+       u32 req_power;
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+-              if (!power_actor_is_valid(params, instance))
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
++              if (!power_actor_is_valid(instance))
+                       continue;
+               cdev = instance->cdev;
+@@ -581,13 +582,11 @@ static void allow_maximum_power(struct thermal_zone_device *tz)
+ static int check_power_actors(struct thermal_zone_device *tz,
+                             struct power_allocator_params *params)
+ {
++      const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
+       struct thermal_instance *instance;
+       int ret = 0;
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+-              if (instance->trip != params->trip_max)
+-                      continue;
+-
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
+               if (!cdev_is_power_actor(instance->cdev)) {
+                       dev_warn(&tz->device, "power_allocator: %s is not a power actor\n",
+                                instance->cdev->type);
+@@ -635,14 +634,15 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz,
+                                     enum thermal_notify_event reason)
+ {
+       struct power_allocator_params *params = tz->governor_data;
++      const struct thermal_trip_desc *td = trip_to_trip_desc(params->trip_max);
+       struct thermal_instance *instance;
+       int num_actors = 0;
+       switch (reason) {
+       case THERMAL_TZ_BIND_CDEV:
+       case THERMAL_TZ_UNBIND_CDEV:
+-              list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+-                      if (power_actor_is_valid(params, instance))
++              list_for_each_entry(instance, &td->thermal_instances, trip_node)
++                      if (power_actor_is_valid(instance))
+                               num_actors++;
+               if (num_actors == params->num_actors)
+@@ -652,8 +652,8 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz,
+               break;
+       case THERMAL_INSTANCE_WEIGHT_CHANGED:
+               params->total_weight = 0;
+-              list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+-                      if (power_actor_is_valid(params, instance))
++              list_for_each_entry(instance, &td->thermal_instances, trip_node)
++                      if (power_actor_is_valid(instance))
+                               params->total_weight += instance->weight;
+               break;
+       default:
+diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c
+index fd5527188cf91..ea4bf88d37f33 100644
+--- a/drivers/thermal/gov_step_wise.c
++++ b/drivers/thermal/gov_step_wise.c
+@@ -66,9 +66,10 @@ static unsigned long get_target_state(struct thermal_instance *instance,
+ }
+ static void thermal_zone_trip_update(struct thermal_zone_device *tz,
+-                                   const struct thermal_trip *trip,
++                                   const struct thermal_trip_desc *td,
+                                    int trip_threshold)
+ {
++      const struct thermal_trip *trip = &td->trip;
+       enum thermal_trend trend = get_tz_trend(tz, trip);
+       int trip_id = thermal_zone_trip_id(tz, trip);
+       struct thermal_instance *instance;
+@@ -82,12 +83,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz,
+       dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
+               trip_id, trip->type, trip_threshold, trend, throttle);
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
++      list_for_each_entry(instance, &td->thermal_instances, trip_node) {
+               int old_target;
+-              if (instance->trip != trip)
+-                      continue;
+-
+               old_target = instance->target;
+               instance->target = get_target_state(instance, trend, throttle);
+@@ -127,11 +125,13 @@ static void step_wise_manage(struct thermal_zone_device *tz)
+                   trip->type == THERMAL_TRIP_HOT)
+                       continue;
+-              thermal_zone_trip_update(tz, trip, td->threshold);
++              thermal_zone_trip_update(tz, td, td->threshold);
+       }
+-      list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+-              thermal_cdev_update(instance->cdev);
++      for_each_trip_desc(tz, td) {
++              list_for_each_entry(instance, &td->thermal_instances, trip_node)
++                      thermal_cdev_update(instance->cdev);
++      }
+ }
+ static struct thermal_governor thermal_gov_step_wise = {
+diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
+index 1d2f2b307bac5..c2fa236e10cda 100644
+--- a/drivers/thermal/thermal_core.c
++++ b/drivers/thermal/thermal_core.c
+@@ -490,7 +490,7 @@ static void thermal_zone_device_check(struct work_struct *work)
+ static void thermal_zone_device_init(struct thermal_zone_device *tz)
+ {
+-      struct thermal_instance *pos;
++      struct thermal_trip_desc *td;
+       INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
+@@ -498,8 +498,12 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz)
+       tz->passive = 0;
+       tz->prev_low_trip = -INT_MAX;
+       tz->prev_high_trip = INT_MAX;
+-      list_for_each_entry(pos, &tz->thermal_instances, tz_node)
+-              pos->initialized = false;
++      for_each_trip_desc(tz, td) {
++              struct thermal_instance *instance;
++
++              list_for_each_entry(instance, &td->thermal_instances, trip_node)
++                      instance->initialized = false;
++      }
+ }
+ static void thermal_governor_trip_crossed(struct thermal_governor *governor,
+@@ -764,12 +768,12 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id)
+  * Return: 0 on success, the proper error value otherwise.
+  */
+ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
+-                                   const struct thermal_trip *trip,
++                                   struct thermal_trip *trip,
+                                    struct thermal_cooling_device *cdev,
+                                    struct cooling_spec *cool_spec)
+ {
+-      struct thermal_instance *dev;
+-      struct thermal_instance *pos;
++      struct thermal_trip_desc *td = trip_to_trip_desc(trip);
++      struct thermal_instance *dev, *instance;
+       bool upper_no_limit;
+       int result;
+@@ -832,13 +836,13 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
+               goto remove_trip_file;
+       mutex_lock(&cdev->lock);
+-      list_for_each_entry(pos, &tz->thermal_instances, tz_node)
+-              if (pos->trip == trip && pos->cdev == cdev) {
++      list_for_each_entry(instance, &td->thermal_instances, trip_node)
++              if (instance->cdev == cdev) {
+                       result = -EEXIST;
+                       break;
+               }
+       if (!result) {
+-              list_add_tail(&dev->tz_node, &tz->thermal_instances);
++              list_add_tail(&dev->trip_node, &td->thermal_instances);
+               list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
+               atomic_set(&tz->need_update, 1);
+@@ -872,15 +876,16 @@ static int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
+  * This function is usually called in the thermal zone device .unbind callback.
+  */
+ static void thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz,
+-                                        const struct thermal_trip *trip,
++                                        struct thermal_trip *trip,
+                                         struct thermal_cooling_device *cdev)
+ {
++      struct thermal_trip_desc *td = trip_to_trip_desc(trip);
+       struct thermal_instance *pos, *next;
+       mutex_lock(&cdev->lock);
+-      list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
+-              if (pos->trip == trip && pos->cdev == cdev) {
+-                      list_del(&pos->tz_node);
++      list_for_each_entry_safe(pos, next, &td->thermal_instances, trip_node) {
++              if (pos->cdev == cdev) {
++                      list_del(&pos->trip_node);
+                       list_del(&pos->cdev_node);
+                       thermal_governor_update_tz(tz, THERMAL_TZ_UNBIND_CDEV);
+@@ -1435,7 +1440,6 @@ thermal_zone_device_register_with_trips(const char *type,
+               }
+       }
+-      INIT_LIST_HEAD(&tz->thermal_instances);
+       INIT_LIST_HEAD(&tz->node);
+       ida_init(&tz->ida);
+       mutex_init(&tz->lock);
+@@ -1459,6 +1463,7 @@ thermal_zone_device_register_with_trips(const char *type,
+       tz->num_trips = num_trips;
+       for_each_trip_desc(tz, td) {
+               td->trip = *trip++;
++              INIT_LIST_HEAD(&td->thermal_instances);
+               /*
+                * Mark all thresholds as invalid to start with even though
+                * this only matters for the trips that start as invalid and
+diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
+index 421522a2bb9d4..163871699a602 100644
+--- a/drivers/thermal/thermal_core.h
++++ b/drivers/thermal/thermal_core.h
+@@ -30,6 +30,7 @@ struct thermal_trip_desc {
+       struct thermal_trip trip;
+       struct thermal_trip_attrs trip_attrs;
+       struct list_head notify_list_node;
++      struct list_head thermal_instances;
+       int notify_temp;
+       int threshold;
+ };
+@@ -99,7 +100,6 @@ struct thermal_governor {
+  * @tzp:      thermal zone parameters
+  * @governor: pointer to the governor for this thermal zone
+  * @governor_data:    private pointer for governor data
+- * @thermal_instances:        list of &struct thermal_instance of this thermal zone
+  * @ida:      &struct ida to generate unique id for this zone's cooling
+  *            devices
+  * @lock:     lock to protect thermal_instances list
+@@ -133,7 +133,6 @@ struct thermal_zone_device {
+       struct thermal_zone_params *tzp;
+       struct thermal_governor *governor;
+       void *governor_data;
+-      struct list_head thermal_instances;
+       struct ida ida;
+       struct mutex lock;
+       struct list_head node;
+@@ -230,7 +229,7 @@ struct thermal_instance {
+       struct device_attribute attr;
+       char weight_attr_name[THERMAL_NAME_LENGTH];
+       struct device_attribute weight_attr;
+-      struct list_head tz_node; /* node in tz->thermal_instances */
++      struct list_head trip_node; /* node in trip->thermal_instances */
+       struct list_head cdev_node; /* node in cdev->thermal_instances */
+       unsigned int weight; /* The weight of the cooling device */
+       bool upper_no_limit;
+diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c
+index dc374a7a1a659..403d62d3ce77e 100644
+--- a/drivers/thermal/thermal_helpers.c
++++ b/drivers/thermal/thermal_helpers.c
+@@ -43,10 +43,11 @@ static bool thermal_instance_present(struct thermal_zone_device *tz,
+                                    struct thermal_cooling_device *cdev,
+                                    const struct thermal_trip *trip)
+ {
++      const struct thermal_trip_desc *td = trip_to_trip_desc(trip);
+       struct thermal_instance *ti;
+-      list_for_each_entry(ti, &tz->thermal_instances, tz_node) {
+-              if (ti->trip == trip && ti->cdev == cdev)
++      list_for_each_entry(ti, &td->thermal_instances, trip_node) {
++              if (ti->cdev == cdev)
+                       return true;
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.12/thermal-gov_power_allocator-fix-incorrect-calculatio.patch b/queue-6.12/thermal-gov_power_allocator-fix-incorrect-calculatio.patch
new file mode 100644 (file)
index 0000000..6ca9f91
--- /dev/null
@@ -0,0 +1,46 @@
+From 7ec732857583bf683c75cefe3e716018ef20b77a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 19 Feb 2025 15:07:48 +0800
+Subject: thermal: gov_power_allocator: Fix incorrect calculation in
+ divvy_up_power()
+
+From: Yu-Che Cheng <giver@chromium.org>
+
+[ Upstream commit 4ecaa75771a75f2b78a431bf67dea165d19d72a6 ]
+
+divvy_up_power() should use weighted_req_power instead of req_power to
+calculate granted_power. Otherwise, granted_power may be unexpected as
+the denominator total_req_power is a weighted sum.
+
+This is a mistake made during the previous refactor.
+
+Replace req_power with weighted_req_power in divvy_up_power()
+calculation.
+
+Fixes: 912e97c67cc3 ("thermal: gov_power_allocator: Move memory allocation out of throttle()")
+Signed-off-by: Yu-Che Cheng <giver@chromium.org>
+Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
+Link: https://patch.msgid.link/20250219-fix-power-allocator-calc-v1-1-48b860291919@chromium.org
+[ rjw: Subject and changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/gov_power_allocator.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/thermal/gov_power_allocator.c b/drivers/thermal/gov_power_allocator.c
+index 1b2345a697c5a..d59549e616399 100644
+--- a/drivers/thermal/gov_power_allocator.c
++++ b/drivers/thermal/gov_power_allocator.c
+@@ -364,7 +364,7 @@ static void divvy_up_power(struct power_actor *power, int num_actors,
+       for (i = 0; i < num_actors; i++) {
+               struct power_actor *pa = &power[i];
+-              u64 req_range = (u64)pa->req_power * power_range;
++              u64 req_range = (u64)pa->weighted_req_power * power_range;
+               pa->granted_power = DIV_ROUND_CLOSEST_ULL(req_range,
+                                                         total_req_power);
+-- 
+2.39.5
+
diff --git a/queue-6.12/thermal-gov_power_allocator-update-total_weight-on-b.patch b/queue-6.12/thermal-gov_power_allocator-update-total_weight-on-b.patch
new file mode 100644 (file)
index 0000000..09e18b9
--- /dev/null
@@ -0,0 +1,94 @@
+From c5ae0581cd43b89545852d33a8b3a4a228165ed3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Feb 2025 11:20:34 +0800
+Subject: thermal: gov_power_allocator: Update total_weight on bind and cdev
+ updates
+
+From: Yu-Che Cheng <giver@chromium.org>
+
+[ Upstream commit 0cde378a10c1cbfaa8dd2b89672d42f36c2809c3 ]
+
+params->total_weight is not initialized during bind and not updated when
+the bound cdev changes. The cooling device weight will not be used due
+to the uninitialized total_weight, until an update via sysfs is
+triggered.
+
+The bound cdevs are updated during thermal zone registration, where each
+cooling device will be bound to the thermal zone one by one, but
+power_allocator_bind() can be called without an additional cdev update
+when manually changing the policy of a thermal zone via sysfs.
+
+Add a new function to handle weight update logic, including updating
+total_weight, and call it when bind, weight changes, and cdev updates to
+ensure total_weight is always correct.
+
+Fixes: a3cd6db4cc2e ("thermal: gov_power_allocator: Support new update callback of weights")
+Signed-off-by: Yu-Che Cheng <giver@chromium.org>
+Link: https://patch.msgid.link/20250222-fix-power-allocator-weight-v2-1-a94de86b685a@chromium.org
+[ rjw: Changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/gov_power_allocator.c | 30 ++++++++++++++++++++-------
+ 1 file changed, 22 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/thermal/gov_power_allocator.c b/drivers/thermal/gov_power_allocator.c
+index b00da17c66a90..8117959dc6c42 100644
+--- a/drivers/thermal/gov_power_allocator.c
++++ b/drivers/thermal/gov_power_allocator.c
+@@ -630,6 +630,22 @@ static int allocate_actors_buffer(struct power_allocator_params *params,
+       return ret;
+ }
++static void power_allocator_update_weight(struct power_allocator_params *params)
++{
++      const struct thermal_trip_desc *td;
++      struct thermal_instance *instance;
++
++      if (!params->trip_max)
++              return;
++
++      td = trip_to_trip_desc(params->trip_max);
++
++      params->total_weight = 0;
++      list_for_each_entry(instance, &td->thermal_instances, trip_node)
++              if (power_actor_is_valid(instance))
++                      params->total_weight += instance->weight;
++}
++
+ static void power_allocator_update_tz(struct thermal_zone_device *tz,
+                                     enum thermal_notify_event reason)
+ {
+@@ -645,16 +661,12 @@ static void power_allocator_update_tz(struct thermal_zone_device *tz,
+                       if (power_actor_is_valid(instance))
+                               num_actors++;
+-              if (num_actors == params->num_actors)
+-                      return;
++              if (num_actors != params->num_actors)
++                      allocate_actors_buffer(params, num_actors);
+-              allocate_actors_buffer(params, num_actors);
+-              break;
++              fallthrough;
+       case THERMAL_INSTANCE_WEIGHT_CHANGED:
+-              params->total_weight = 0;
+-              list_for_each_entry(instance, &td->thermal_instances, trip_node)
+-                      if (power_actor_is_valid(instance))
+-                              params->total_weight += instance->weight;
++              power_allocator_update_weight(params);
+               break;
+       default:
+               break;
+@@ -720,6 +732,8 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
+       tz->governor_data = params;
++      power_allocator_update_weight(params);
++
+       return 0;
+ free_params:
+-- 
+2.39.5
+
diff --git a/queue-6.12/thermal-of-fix-cdev-lookup-in-thermal_of_should_bind.patch b/queue-6.12/thermal-of-fix-cdev-lookup-in-thermal_of_should_bind.patch
new file mode 100644 (file)
index 0000000..b8f7554
--- /dev/null
@@ -0,0 +1,106 @@
+From a750b19e95f0c2b68af962366ac3fec765725b64 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 21 Feb 2025 17:57:11 +0100
+Subject: thermal/of: Fix cdev lookup in thermal_of_should_bind()
+
+From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+
+[ Upstream commit 423de5b5bc5b267586b449abd1c4fde562aa0cf9 ]
+
+Since thermal_of_should_bind() terminates the loop after processing
+the first child found in cooling-maps, it will never match more than
+one cdev to a given trip point which is incorrect, as there may be
+cooling-maps associating one trip point with multiple cooling devices.
+
+Address this by letting the loop continue until either all
+children have been processed or a matching one has been found.
+
+To avoid adding conditionals or goto statements, put the loop in
+question into a separate function and make that function return
+right away after finding a matching cooling-maps entry.
+
+Fixes: 94c6110b0b13 ("thermal/of: Use the .should_bind() thermal zone callback")
+Link: https://lore.kernel.org/linux-pm/20250219-fix-thermal-of-v1-1-de36e7a590c4@chromium.org/
+Reported-by: Yu-Che Cheng <giver@chromium.org>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Reviewed-by: Yu-Che Cheng <giver@chromium.org>
+Tested-by: Yu-Che Cheng <giver@chromium.org>
+Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
+Tested-by: Lukasz Luba <lukasz.luba@arm.com>
+Link: https://patch.msgid.link/2788228.mvXUDI8C0e@rjwysocki.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/thermal_of.c | 50 +++++++++++++++++++++---------------
+ 1 file changed, 29 insertions(+), 21 deletions(-)
+
+diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
+index 111d2c15601b9..e0aa9d9d5604b 100644
+--- a/drivers/thermal/thermal_of.c
++++ b/drivers/thermal/thermal_of.c
+@@ -293,6 +293,34 @@ static bool thermal_of_get_cooling_spec(struct device_node *map_np, int index,
+       return true;
+ }
++static bool thermal_of_cm_lookup(struct device_node *cm_np,
++                               const struct thermal_trip *trip,
++                               struct thermal_cooling_device *cdev,
++                               struct cooling_spec *c)
++{
++      for_each_child_of_node_scoped(cm_np, child) {
++              struct device_node *tr_np;
++              int count, i;
++
++              tr_np = of_parse_phandle(child, "trip", 0);
++              if (tr_np != trip->priv)
++                      continue;
++
++              /* The trip has been found, look up the cdev. */
++              count = of_count_phandle_with_args(child, "cooling-device",
++                                                 "#cooling-cells");
++              if (count <= 0)
++                      pr_err("Add a cooling_device property with at least one device\n");
++
++              for (i = 0; i < count; i++) {
++                      if (thermal_of_get_cooling_spec(child, i, cdev, c))
++                              return true;
++              }
++      }
++
++      return false;
++}
++
+ static bool thermal_of_should_bind(struct thermal_zone_device *tz,
+                                  const struct thermal_trip *trip,
+                                  struct thermal_cooling_device *cdev,
+@@ -312,27 +340,7 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz,
+               goto out;
+       /* Look up the trip and the cdev in the cooling maps. */
+-      for_each_child_of_node_scoped(cm_np, child) {
+-              struct device_node *tr_np;
+-              int count, i;
+-
+-              tr_np = of_parse_phandle(child, "trip", 0);
+-              if (tr_np != trip->priv)
+-                      continue;
+-
+-              /* The trip has been found, look up the cdev. */
+-              count = of_count_phandle_with_args(child, "cooling-device", "#cooling-cells");
+-              if (count <= 0)
+-                      pr_err("Add a cooling_device property with at least one device\n");
+-
+-              for (i = 0; i < count; i++) {
+-                      result = thermal_of_get_cooling_spec(child, i, cdev, c);
+-                      if (result)
+-                              break;
+-              }
+-
+-              break;
+-      }
++      result = thermal_of_cm_lookup(cm_np, trip, cdev, c);
+       of_node_put(cm_np);
+ out:
+-- 
+2.39.5
+
diff --git a/queue-6.12/thermal-of-simplify-thermal_of_should_bind-with-scop.patch b/queue-6.12/thermal-of-simplify-thermal_of_should_bind-with-scop.patch
new file mode 100644 (file)
index 0000000..11f486f
--- /dev/null
@@ -0,0 +1,56 @@
+From 5004fc0d90c5949f971e3b9aedae262af1fd87e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 10 Oct 2024 20:06:17 +0200
+Subject: thermal: of: Simplify thermal_of_should_bind with scoped for each OF
+ child
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 69f3aa6ad92447d6e9f50c5b5aea85b56e80b198 ]
+
+Use scoped for_each_child_of_node_scoped() when iterating over device
+nodes to make code a bit simpler.
+
+Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Link: https://patch.msgid.link/20241010-b4-cleanup-h-of-node-put-thermal-v4-1-bfbe29ad81f4@linaro.org
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Stable-dep-of: 423de5b5bc5b ("thermal/of: Fix cdev lookup in thermal_of_should_bind()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/thermal/thermal_of.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
+index 5d3d8ce672cd5..111d2c15601b9 100644
+--- a/drivers/thermal/thermal_of.c
++++ b/drivers/thermal/thermal_of.c
+@@ -298,7 +298,7 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz,
+                                  struct thermal_cooling_device *cdev,
+                                  struct cooling_spec *c)
+ {
+-      struct device_node *tz_np, *cm_np, *child;
++      struct device_node *tz_np, *cm_np;
+       bool result = false;
+       tz_np = thermal_of_zone_get_by_name(tz);
+@@ -312,7 +312,7 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz,
+               goto out;
+       /* Look up the trip and the cdev in the cooling maps. */
+-      for_each_child_of_node(cm_np, child) {
++      for_each_child_of_node_scoped(cm_np, child) {
+               struct device_node *tr_np;
+               int count, i;
+@@ -331,7 +331,6 @@ static bool thermal_of_should_bind(struct thermal_zone_device *tz,
+                               break;
+               }
+-              of_node_put(child);
+               break;
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.12/unreachable-unify.patch b/queue-6.12/unreachable-unify.patch
new file mode 100644 (file)
index 0000000..b348052
--- /dev/null
@@ -0,0 +1,72 @@
+From f5527c7ff93febbdfe53b178021f4e6f5b1f3d96 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Nov 2024 10:39:01 +0100
+Subject: unreachable: Unify
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+[ Upstream commit c837de3810982cd41cd70e5170da1931439f025c ]
+
+Since barrier_before_unreachable() is empty for !GCC it is trivial to
+unify the two definitions. Less is more.
+
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Link: https://lore.kernel.org/r/20241128094311.924381359@infradead.org
+Stable-dep-of: 73cfc53cc3b6 ("objtool: Fix C jump table annotations for Clang")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/linux/compiler-gcc.h | 12 ------------
+ include/linux/compiler.h     | 10 +++++++---
+ 2 files changed, 7 insertions(+), 15 deletions(-)
+
+diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
+index cd6f9aae311fc..070b3b680209c 100644
+--- a/include/linux/compiler-gcc.h
++++ b/include/linux/compiler-gcc.h
+@@ -52,18 +52,6 @@
+  */
+ #define barrier_before_unreachable() asm volatile("")
+-/*
+- * Mark a position in code as unreachable.  This can be used to
+- * suppress control flow warnings after asm blocks that transfer
+- * control elsewhere.
+- */
+-#define unreachable() \
+-      do {                                    \
+-              annotate_unreachable();         \
+-              barrier_before_unreachable();   \
+-              __builtin_unreachable();        \
+-      } while (0)
+-
+ #if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP)
+ #define __HAVE_BUILTIN_BSWAP32__
+ #define __HAVE_BUILTIN_BSWAP64__
+diff --git a/include/linux/compiler.h b/include/linux/compiler.h
+index 2d962dade9fae..0d10d75218f51 100644
+--- a/include/linux/compiler.h
++++ b/include/linux/compiler.h
+@@ -141,12 +141,16 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
+ #define __annotate_jump_table
+ #endif /* CONFIG_OBJTOOL */
+-#ifndef unreachable
+-# define unreachable() do {           \
++/*
++ * Mark a position in code as unreachable.  This can be used to
++ * suppress control flow warnings after asm blocks that transfer
++ * control elsewhere.
++ */
++#define unreachable() do {            \
+       annotate_unreachable();         \
++      barrier_before_unreachable();   \
+       __builtin_unreachable();        \
+ } while (0)
+-#endif
+ /*
+  * KENTRY - kernel entry point
+-- 
+2.39.5
+
diff --git a/queue-6.12/uprobes-reject-the-shared-zeropage-in-uprobe_write_o.patch b/queue-6.12/uprobes-reject-the-shared-zeropage-in-uprobe_write_o.patch
new file mode 100644 (file)
index 0000000..337d248
--- /dev/null
@@ -0,0 +1,112 @@
+From 643cbcf70fcfe570981cb92cc4e34608746c51fa Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 11:11:49 +0800
+Subject: uprobes: Reject the shared zeropage in uprobe_write_opcode()
+
+From: Tong Tiangen <tongtiangen@huawei.com>
+
+[ Upstream commit bddf10d26e6e5114e7415a0e442ec6f51a559468 ]
+
+We triggered the following crash in syzkaller tests:
+
+  BUG: Bad page state in process syz.7.38  pfn:1eff3
+  page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1eff3
+  flags: 0x3fffff00004004(referenced|reserved|node=0|zone=1|lastcpupid=0x1fffff)
+  raw: 003fffff00004004 ffffe6c6c07bfcc8 ffffe6c6c07bfcc8 0000000000000000
+  raw: 0000000000000000 0000000000000000 00000000fffffffe 0000000000000000
+  page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
+  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014
+  Call Trace:
+   <TASK>
+   dump_stack_lvl+0x32/0x50
+   bad_page+0x69/0xf0
+   free_unref_page_prepare+0x401/0x500
+   free_unref_page+0x6d/0x1b0
+   uprobe_write_opcode+0x460/0x8e0
+   install_breakpoint.part.0+0x51/0x80
+   register_for_each_vma+0x1d9/0x2b0
+   __uprobe_register+0x245/0x300
+   bpf_uprobe_multi_link_attach+0x29b/0x4f0
+   link_create+0x1e2/0x280
+   __sys_bpf+0x75f/0xac0
+   __x64_sys_bpf+0x1a/0x30
+   do_syscall_64+0x56/0x100
+   entry_SYSCALL_64_after_hwframe+0x78/0xe2
+
+   BUG: Bad rss-counter state mm:00000000452453e0 type:MM_FILEPAGES val:-1
+
+The following syzkaller test case can be used to reproduce:
+
+  r2 = creat(&(0x7f0000000000)='./file0\x00', 0x8)
+  write$nbd(r2, &(0x7f0000000580)=ANY=[], 0x10)
+  r4 = openat(0xffffffffffffff9c, &(0x7f0000000040)='./file0\x00', 0x42, 0x0)
+  mmap$IORING_OFF_SQ_RING(&(0x7f0000ffd000/0x3000)=nil, 0x3000, 0x0, 0x12, r4, 0x0)
+  r5 = userfaultfd(0x80801)
+  ioctl$UFFDIO_API(r5, 0xc018aa3f, &(0x7f0000000040)={0xaa, 0x20})
+  r6 = userfaultfd(0x80801)
+  ioctl$UFFDIO_API(r6, 0xc018aa3f, &(0x7f0000000140))
+  ioctl$UFFDIO_REGISTER(r6, 0xc020aa00, &(0x7f0000000100)={{&(0x7f0000ffc000/0x4000)=nil, 0x4000}, 0x2})
+  ioctl$UFFDIO_ZEROPAGE(r5, 0xc020aa04, &(0x7f0000000000)={{&(0x7f0000ffd000/0x1000)=nil, 0x1000}})
+  r7 = bpf$PROG_LOAD(0x5, &(0x7f0000000140)={0x2, 0x3, &(0x7f0000000200)=ANY=[@ANYBLOB="1800000000120000000000000000000095"], &(0x7f0000000000)='GPL\x00', 0x7, 0x0, 0x0, 0x0, 0x0, '\x00', 0x0, @fallback=0x30, 0xffffffffffffffff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x0, @void, @value}, 0x94)
+  bpf$BPF_LINK_CREATE_XDP(0x1c, &(0x7f0000000040)={r7, 0x0, 0x30, 0x1e, @val=@uprobe_multi={&(0x7f0000000080)='./file0\x00', &(0x7f0000000100)=[0x2], 0x0, 0x0, 0x1}}, 0x40)
+
+The cause is that zero pfn is set to the PTE without increasing the RSS
+count in mfill_atomic_pte_zeropage() and the refcount of zero folio does
+not increase accordingly. Then, the operation on the same pfn is performed
+in uprobe_write_opcode()->__replace_page() to unconditional decrease the
+RSS count and old_folio's refcount.
+
+Therefore, two bugs are introduced:
+
+ 1. The RSS count is incorrect, when process exit, the check_mm() report
+    error "Bad rss-count".
+
+ 2. The reserved folio (zero folio) is freed when folio->refcount is zero,
+    then free_pages_prepare->free_page_is_bad() report error
+    "Bad page state".
+
+There is more, the following warning could also theoretically be triggered:
+
+  __replace_page()
+    -> ...
+      -> folio_remove_rmap_pte()
+        -> VM_WARN_ON_FOLIO(is_zero_folio(folio), folio)
+
+Considering that uprobe hit on the zero folio is a very rare case, just
+reject zero old folio immediately after get_user_page_vma_remote().
+
+[ mingo: Cleaned up the changelog ]
+
+Fixes: 7396fa818d62 ("uprobes/core: Make background page replacement logic account for rss_stat counters")
+Fixes: 2b1444983508 ("uprobes, mm, x86: Add the ability to install and remove uprobes breakpoints")
+Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Reviewed-by: David Hildenbrand <david@redhat.com>
+Reviewed-by: Oleg Nesterov <oleg@redhat.com>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Masami Hiramatsu <mhiramat@kernel.org>
+Link: https://lore.kernel.org/r/20250224031149.1598949-1-tongtiangen@huawei.com
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/uprobes.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
+index 4b52cb2ae6d62..a0e0676f5d8bb 100644
+--- a/kernel/events/uprobes.c
++++ b/kernel/events/uprobes.c
+@@ -489,6 +489,11 @@ int uprobe_write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
+       if (ret <= 0)
+               goto put_old;
++      if (is_zero_page(old_page)) {
++              ret = -EINVAL;
++              goto put_old;
++      }
++
+       if (WARN(!is_register && PageCompound(old_page),
+                "uprobe unregister should never work on compound page\n")) {
+               ret = -EINVAL;
+-- 
+2.39.5
+
diff --git a/queue-6.12/x86-cpu-fix-warm-boot-hang-regression-on-amd-sc1100-.patch b/queue-6.12/x86-cpu-fix-warm-boot-hang-regression-on-amd-sc1100-.patch
new file mode 100644 (file)
index 0000000..e99de6d
--- /dev/null
@@ -0,0 +1,95 @@
+From e10710a4be5c1823d037fd53a3dd1f681a6aabb6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 22:31:20 +0100
+Subject: x86/CPU: Fix warm boot hang regression on AMD SC1100 SoC systems
+
+From: Russell Senior <russell@personaltelco.net>
+
+[ Upstream commit bebe35bb738b573c32a5033499cd59f20293f2a3 ]
+
+I still have some Soekris net4826 in a Community Wireless Network I
+volunteer with. These devices use an AMD SC1100 SoC. I am running
+OpenWrt on them, which uses a patched kernel, that naturally has
+evolved over time.  I haven't updated the ones in the field in a
+number of years (circa 2017), but have one in a test bed, where I have
+intermittently tried out test builds.
+
+A few years ago, I noticed some trouble, particularly when "warm
+booting", that is, doing a reboot without removing power, and noticed
+the device was hanging after the kernel message:
+
+  [    0.081615] Working around Cyrix MediaGX virtual DMA bugs.
+
+If I removed power and then restarted, it would boot fine, continuing
+through the message above, thusly:
+
+  [    0.081615] Working around Cyrix MediaGX virtual DMA bugs.
+  [    0.090076] Enable Memory-Write-back mode on Cyrix/NSC processor.
+  [    0.100000] Enable Memory access reorder on Cyrix/NSC processor.
+  [    0.100070] Last level iTLB entries: 4KB 0, 2MB 0, 4MB 0
+  [    0.110058] Last level dTLB entries: 4KB 0, 2MB 0, 4MB 0, 1GB 0
+  [    0.120037] CPU: NSC Geode(TM) Integrated Processor by National Semi (family: 0x5, model: 0x9, stepping: 0x1)
+  [...]
+
+In order to continue using modern tools, like ssh, to interact with
+the software on these old devices, I need modern builds of the OpenWrt
+firmware on the devices. I confirmed that the warm boot hang was still
+an issue in modern OpenWrt builds (currently using a patched linux
+v6.6.65).
+
+Last night, I decided it was time to get to the bottom of the warm
+boot hang, and began bisecting. From preserved builds, I narrowed down
+the bisection window from late February to late May 2019. During this
+period, the OpenWrt builds were using 4.14.x. I was able to build
+using period-correct Ubuntu 18.04.6. After a number of bisection
+iterations, I identified a kernel bump from 4.14.112 to 4.14.113 as
+the commit that introduced the warm boot hang.
+
+  https://github.com/openwrt/openwrt/commit/07aaa7e3d62ad32767d7067107db64b6ade81537
+
+Looking at the upstream changes in the stable kernel between 4.14.112
+and 4.14.113 (tig v4.14.112..v4.14.113), I spotted a likely suspect:
+
+  https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=20afb90f730982882e65b01fb8bdfe83914339c5
+
+So, I tried reverting just that kernel change on top of the breaking
+OpenWrt commit, and my warm boot hang went away.
+
+Presumably, the warm boot hang is due to some register not getting
+cleared in the same way that a loss of power does. That is
+approximately as much as I understand about the problem.
+
+More poking/prodding and coaching from Jonas Gorski, it looks
+like this test patch fixes the problem on my board: Tested against
+v6.6.67 and v4.14.113.
+
+Fixes: 18fb053f9b82 ("x86/cpu/cyrix: Use correct macros for Cyrix calls on Geode processors")
+Debugged-by: Jonas Gorski <jonas.gorski@gmail.com>
+Signed-off-by: Russell Senior <russell@personaltelco.net>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Link: https://lore.kernel.org/r/CAHP3WfOgs3Ms4Z+L9i0-iBOE21sdMk5erAiJurPjnrL9LSsgRA@mail.gmail.com
+Cc: Matthew Whitehead <tedheadster@gmail.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/x86/kernel/cpu/cyrix.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c
+index 9651275aecd1b..dfec2c61e3547 100644
+--- a/arch/x86/kernel/cpu/cyrix.c
++++ b/arch/x86/kernel/cpu/cyrix.c
+@@ -153,8 +153,8 @@ static void geode_configure(void)
+       u8 ccr3;
+       local_irq_save(flags);
+-      /* Suspend on halt power saving and enable #SUSP pin */
+-      setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
++      /* Suspend on halt power saving */
++      setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x08);
+       ccr3 = getCx86(CX86_CCR3);
+       setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);       /* enable MAPEN */
+-- 
+2.39.5
+