git: ac9de183f370 - main - ofw_cpu: check for "disabled" status during probe

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Fri, 10 Jan 2025 19:18:31 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=ac9de183f37006fc2089757779d6d5065a530d5b

commit ac9de183f37006fc2089757779d6d5065a530d5b
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2025-01-10 18:46:56 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2025-01-10 18:59:08 +0000

    ofw_cpu: check for "disabled" status during probe
    
    Some RISC-V CPUs contain a "monitor core" with limited functionality (no
    MMU). These cores appear in some device trees, but we don't run the
    kernel on them; in early CPU start-up code we skip them, and they have
    no impact on mp_ncpu. It seems the new trend is to mark these monitor
    cores with a 'status' property of 'disabled'.
    
    However, we still instantiate an ofw_cpu pseudo device for the disabled
    core. This is generally harmless, but there is an impact when attempting
    to attach the cpufreq_dt driver. It counts more OFW CPU devices (unit
    number) than logical CPUs (mp_ncpus), and therefore fails to attach for
    the last logical CPU.
    
    The solution is to check the status property in ofw_cpu_probe(), and
    fail if the core is marked "disabled". This is subject to the same
    exception already in ofw_cpu_early_foreach(); that is, if a disabled CPU
    has an 'enable-method' property, it can be used by the kernel.
    
    Reviewed by:    andrew, jrtc27
    MFC after:      1 month
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D48123
---
 sys/dev/ofw/ofw_cpu.c | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/sys/dev/ofw/ofw_cpu.c b/sys/dev/ofw/ofw_cpu.c
index 339716a946ff..888af0440746 100644
--- a/sys/dev/ofw/ofw_cpu.c
+++ b/sys/dev/ofw/ofw_cpu.c
@@ -182,6 +182,24 @@ static driver_t ofw_cpu_driver = {
 
 DRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, 0, 0);
 
+static bool
+ofw_cpu_is_runnable(phandle_t node)
+{
+	/*
+	 * Per the DeviceTree Specification, a cpu node (under /cpus) that
+	 * has 'status = disabled' indicates that "the CPU is in a quiescent
+	 * state."
+	 *
+	 * A quiescent CPU that specifies an "enable-method", such as
+	 * "spin-table", can still be used by the kernel.
+	 *
+	 * Lacking this, any CPU marked "disabled" or other non-okay status
+	 * should be excluded from the kernel's view.
+	 */
+	return (ofw_bus_node_status_okay(node) ||
+	    OF_hasprop(node, "enable-method"));
+}
+
 static int
 ofw_cpu_probe(device_t dev)
 {
@@ -190,6 +208,9 @@ ofw_cpu_probe(device_t dev)
 	if (type == NULL || strcmp(type, "cpu") != 0)
 		return (ENXIO);
 
+	if (!ofw_cpu_is_runnable(ofw_bus_get_node(dev)))
+		return (ENXIO);
+
 	device_set_desc(dev, "Open Firmware CPU");
 	if (!bootverbose && device_get_unit(dev) != 0) {
 		device_quiet(dev);
@@ -352,7 +373,6 @@ ofw_cpu_early_foreach(ofw_cpu_foreach_cb callback, bool only_runnable)
 {
 	phandle_t node, child;
 	pcell_t addr_cells, reg[2];
-	char status[16];
 	char device_type[16];
 	u_int id, next_id;
 	int count, rv;
@@ -389,14 +409,8 @@ ofw_cpu_early_foreach(ofw_cpu_foreach_cb callback, bool only_runnable)
 		 * those that have been enabled, or do provide a method
 		 * to enable them.
 		 */
-		if (only_runnable) {
-			status[0] = '\0';
-			OF_getprop(child, "status", status, sizeof(status));
-			if (status[0] != '\0' && strcmp(status, "okay") != 0 &&
-				strcmp(status, "ok") != 0 &&
-				!OF_hasprop(child, "enable-method"))
-					continue;
-		}
+		if (only_runnable && !ofw_cpu_is_runnable(child))
+			continue;
 
 		/*
 		 * Check we have a register to identify the cpu