]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ACPI: processor_idle: Fix invalid comparison with insertion sort for latency
authorKuan-Wei Chiu <visitorckw@gmail.com>
Mon, 1 Jul 2024 20:56:39 +0000 (04:56 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 27 Jul 2024 08:33:43 +0000 (10:33 +0200)
commit 233323f9b9f828cd7cd5145ad811c1990b692542 upstream.

The acpi_cst_latency_cmp() comparison function currently used for
sorting C-state latencies does not satisfy transitivity, causing
incorrect sorting results.

Specifically, if there are two valid acpi_processor_cx elements A and B
and one invalid element C, it may occur that A < B, A = C, and B = C.
Sorting algorithms assume that if A < B and A = C, then C < B, leading
to incorrect ordering.

Given the small size of the array (<=8), we replace the library sort
function with a simple insertion sort that properly ignores invalid
elements and sorts valid ones based on latency. This change ensures
correct ordering of the C-state latencies.

Fixes: 65ea8f2c6e23 ("ACPI: processor idle: Fix up C-state latency if not ordered")
Reported-by: Julian Sikorski <belegdol@gmail.com>
Closes: https://lore.kernel.org/lkml/70674dc7-5586-4183-8953-8095567e73df@gmail.com
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Tested-by: Julian Sikorski <belegdol@gmail.com>
Cc: All applicable <stable@vger.kernel.org>
Link: https://patch.msgid.link/20240701205639.117194-1-visitorckw@gmail.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/acpi/processor_idle.c

index 22b56a6e9ccace6f41929db97b6eac0a1f3aecf9..363c149e8237f5d736fbbf93f07ba080cd52c11d 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/acpi.h>
 #include <linux/dmi.h>
 #include <linux/sched.h>       /* need_resched() */
-#include <linux/sort.h>
 #include <linux/tick.h>
 #include <linux/cpuidle.h>
 #include <linux/cpu.h>
@@ -545,28 +544,24 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
        return;
 }
 
-static int acpi_cst_latency_cmp(const void *a, const void *b)
+static void acpi_cst_latency_sort(struct acpi_processor_cx *states, size_t length)
 {
-       const struct acpi_processor_cx *x = a, *y = b;
+       int i, j, k;
 
-       if (!(x->valid && y->valid))
-               return 0;
-       if (x->latency > y->latency)
-               return 1;
-       if (x->latency < y->latency)
-               return -1;
-       return 0;
-}
-static void acpi_cst_latency_swap(void *a, void *b, int n)
-{
-       struct acpi_processor_cx *x = a, *y = b;
-       u32 tmp;
+       for (i = 1; i < length; i++) {
+               if (!states[i].valid)
+                       continue;
 
-       if (!(x->valid && y->valid))
-               return;
-       tmp = x->latency;
-       x->latency = y->latency;
-       y->latency = tmp;
+               for (j = i - 1, k = i; j >= 0; j--) {
+                       if (!states[j].valid)
+                               continue;
+
+                       if (states[j].latency > states[k].latency)
+                               swap(states[j].latency, states[k].latency);
+
+                       k = j;
+               }
+       }
 }
 
 static int acpi_processor_power_verify(struct acpi_processor *pr)
@@ -611,10 +606,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
 
        if (buggy_latency) {
                pr_notice("FW issue: working around C-state latencies out of order\n");
-               sort(&pr->power.states[1], max_cstate,
-                    sizeof(struct acpi_processor_cx),
-                    acpi_cst_latency_cmp,
-                    acpi_cst_latency_swap);
+               acpi_cst_latency_sort(&pr->power.states[1], max_cstate);
        }
 
        lapic_timer_propagate_broadcast(pr);