From: Sasha Levin Date: Sun, 2 Mar 2025 14:46:02 +0000 (-0500) Subject: Fixes for 6.12 X-Git-Tag: v6.6.81~39 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c10e5cd7d350f389fd179db981d7c6a7d689ad9c;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.12 Signed-off-by: Sasha Levin --- 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 index 0000000000..1c23b11622 --- /dev/null +++ b/queue-6.12/io_uring-net-save-msg_control-for-compat.patch @@ -0,0 +1,39 @@ +From db843bd4fc488cf0f1f24a668a67eedfeea8d9df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2025 15:59:02 +0000 +Subject: io_uring/net: save msg_control for compat + +From: Pavel Begunkov + +[ 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 +Link: https://lore.kernel.org/r/2a8418821fe83d3b64350ad2b3c0303e9b732bbd.1740498502.git.asml.silence@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..204480cd80 --- /dev/null +++ b/queue-6.12/objtool-fix-c-jump-table-annotations-for-clang.patch @@ -0,0 +1,106 @@ +From 273b2b356d477172d531f414fb47580deb21705d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Feb 2025 14:57:07 +0100 +Subject: objtool: Fix C jump table annotations for Clang + +From: Ard Biesheuvel + +[ 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 # on LoongArch +Signed-off-by: Ard Biesheuvel +Link: https://lore.kernel.org/r/20250221135704.431269-6-ardb+git@google.com +Signed-off-by: Josh Poimboeuf +Signed-off-by: Sasha Levin +--- + 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.: 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 + #include + +-#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 index 0000000000..8385780f0e --- /dev/null +++ b/queue-6.12/objtool-remove-annotate_-un-reachable.patch @@ -0,0 +1,131 @@ +From 50b86ed96bd4f0841461dd8516a20b5259c5445a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Nov 2024 10:39:04 +0100 +Subject: objtool: Remove annotate_{,un}reachable() + +From: Peter Zijlstra + +[ 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) +Acked-by: Josh Poimboeuf +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 +--- + 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 index 0000000000..a9ff268f90 --- /dev/null +++ b/queue-6.12/perf-core-order-the-pmu-list-to-fix-warning-about-un.patch @@ -0,0 +1,108 @@ +From 865be596804db96f9665c98997e719e0cff8e717 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Ingo Molnar +Reviewed-by: Kan Liang +Link: https://lore.kernel.org/r/20250122073356.1824736-1-luogengkun@huaweicloud.com +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/series b/queue-6.12/series index 5f62abf215..3642776612 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -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 index 0000000000..8cb034502f --- /dev/null +++ b/queue-6.12/thermal-core-move-lists-of-thermal-instances-to-trip.patch @@ -0,0 +1,459 @@ +From 6db51643767ef171b6d334feebbb44a19c4e38b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Oct 2024 21:39:19 +0200 +Subject: thermal: core: Move lists of thermal instances to trip descriptors + +From: Rafael J. Wysocki + +[ 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 +Link: https://patch.msgid.link/5522726.Sb9uPGUboI@rjwysocki.net +Reviewed-by: Lukasz Luba +Stable-dep-of: 0cde378a10c1 ("thermal: gov_power_allocator: Update total_weight on bind and cdev updates") +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..6ca9f91b73 --- /dev/null +++ b/queue-6.12/thermal-gov_power_allocator-fix-incorrect-calculatio.patch @@ -0,0 +1,46 @@ +From 7ec732857583bf683c75cefe3e716018ef20b77a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Reviewed-by: Lukasz Luba +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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..09e18b9ce3 --- /dev/null +++ b/queue-6.12/thermal-gov_power_allocator-update-total_weight-on-b.patch @@ -0,0 +1,94 @@ +From c5ae0581cd43b89545852d33a8b3a4a228165ed3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Link: https://patch.msgid.link/20250222-fix-power-allocator-weight-v2-1-a94de86b685a@chromium.org +[ rjw: Changelog edits ] +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..b8f7554580 --- /dev/null +++ b/queue-6.12/thermal-of-fix-cdev-lookup-in-thermal_of_should_bind.patch @@ -0,0 +1,106 @@ +From a750b19e95f0c2b68af962366ac3fec765725b64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Feb 2025 17:57:11 +0100 +Subject: thermal/of: Fix cdev lookup in thermal_of_should_bind() + +From: Rafael J. Wysocki + +[ 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 +Signed-off-by: Rafael J. Wysocki +Reviewed-by: Yu-Che Cheng +Tested-by: Yu-Che Cheng +Reviewed-by: Lukasz Luba +Tested-by: Lukasz Luba +Link: https://patch.msgid.link/2788228.mvXUDI8C0e@rjwysocki.net +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..11f486fde6 --- /dev/null +++ b/queue-6.12/thermal-of-simplify-thermal_of_should_bind-with-scop.patch @@ -0,0 +1,56 @@ +From 5004fc0d90c5949f971e3b9aedae262af1fd87e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Krzysztof Kozlowski +Link: https://patch.msgid.link/20241010-b4-cleanup-h-of-node-put-thermal-v4-1-bfbe29ad81f4@linaro.org +Signed-off-by: Rafael J. Wysocki +Stable-dep-of: 423de5b5bc5b ("thermal/of: Fix cdev lookup in thermal_of_should_bind()") +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..b348052699 --- /dev/null +++ b/queue-6.12/unreachable-unify.patch @@ -0,0 +1,72 @@ +From f5527c7ff93febbdfe53b178021f4e6f5b1f3d96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Nov 2024 10:39:01 +0100 +Subject: unreachable: Unify + +From: Peter Zijlstra + +[ 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) +Acked-by: Josh Poimboeuf +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 +--- + 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 index 0000000000..337d248eca --- /dev/null +++ b/queue-6.12/uprobes-reject-the-shared-zeropage-in-uprobe_write_o.patch @@ -0,0 +1,112 @@ +From 643cbcf70fcfe570981cb92cc4e34608746c51fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Feb 2025 11:11:49 +0800 +Subject: uprobes: Reject the shared zeropage in uprobe_write_opcode() + +From: Tong Tiangen + +[ 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: + + 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 +Signed-off-by: Ingo Molnar +Reviewed-by: David Hildenbrand +Reviewed-by: Oleg Nesterov +Cc: Peter Zijlstra +Cc: Masami Hiramatsu +Link: https://lore.kernel.org/r/20250224031149.1598949-1-tongtiangen@huawei.com +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..e99de6d1a9 --- /dev/null +++ b/queue-6.12/x86-cpu-fix-warm-boot-hang-regression-on-amd-sc1100-.patch @@ -0,0 +1,95 @@ +From e10710a4be5c1823d037fd53a3dd1f681a6aabb6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Russell Senior +Signed-off-by: Ingo Molnar +Link: https://lore.kernel.org/r/CAHP3WfOgs3Ms4Z+L9i0-iBOE21sdMk5erAiJurPjnrL9LSsgRA@mail.gmail.com +Cc: Matthew Whitehead +Cc: Thomas Gleixner +Signed-off-by: Sasha Levin +--- + 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 +