summaryrefslogtreecommitdiff
path: root/sys/kern/kern_cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_cpu.c')
-rw-r--r--sys/kern/kern_cpu.c118
1 files changed, 115 insertions, 3 deletions
diff --git a/sys/kern/kern_cpu.c b/sys/kern/kern_cpu.c
index 450d2a9a844..fafe364cc9f 100644
--- a/sys/kern/kern_cpu.c
+++ b/sys/kern/kern_cpu.c
@@ -1,7 +1,7 @@
-/* $NetBSD: kern_cpu.c,v 1.78 2019/12/01 15:34:46 ad Exp $ */
+/* $NetBSD: kern_cpu.c,v 1.79 2019/12/02 23:22:43 ad Exp $ */
/*-
- * Copyright (c) 2007, 2008, 2009, 2010, 2012 The NetBSD Foundation, Inc.
+ * Copyright (c) 2007, 2008, 2009, 2010, 2012, 2019 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -56,7 +56,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.78 2019/12/01 15:34:46 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.79 2019/12/02 23:22:43 ad Exp $");
#include "opt_cpu_ucode.h"
@@ -119,6 +119,7 @@ kmutex_t cpu_lock __cacheline_aligned;
int ncpu __read_mostly;
int ncpuonline __read_mostly;
bool mp_online __read_mostly;
+static bool cpu_topology_present __read_mostly;
/* An array of CPUs. There are ncpu entries. */
struct cpu_info **cpu_infos __read_mostly;
@@ -587,6 +588,117 @@ cpu_softintr_p(void)
return (curlwp->l_pflag & LP_INTR) != 0;
}
+/*
+ * Collect CPU topology information as each CPU is attached. This can be
+ * called early during boot, so we need to be careful what we do.
+ */
+void
+cpu_topology_set(struct cpu_info *ci, int package_id, int core_id, int smt_id)
+{
+
+ cpu_topology_present = true;
+ ci->ci_package_id = package_id;
+ ci->ci_core_id = core_id;
+ ci->ci_smt_id = smt_id;
+ ci->ci_package_cpus = ci;
+ ci->ci_npackage_cpus = 1;
+ ci->ci_core_cpus = ci;
+ ci->ci_ncore_cpus = 1;
+}
+
+/*
+ * Fake up toplogy info if we have none, or if what we got was bogus.
+ */
+static void
+cpu_topology_fake(void)
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ ci->ci_package_id = cpu_index(ci);
+ ci->ci_core_id = 0;
+ ci->ci_smt_id = 0;
+ ci->ci_ncore_cpus = 1;
+ ci->ci_core_cpus = ci;
+ ci->ci_package_cpus = ci;
+ ci->ci_npackage_cpus = 1;
+ }
+}
+
+/*
+ * Fix up basic CPU topology info. Right now that means attach each CPU to
+ * circular lists of its siblings in the same core, and in the same package.
+ */
+void
+cpu_topology_init(void)
+{
+ CPU_INFO_ITERATOR cii, cii2;
+ struct cpu_info *ci, *ci2, *ci3;
+
+ if (!cpu_topology_present) {
+ cpu_topology_fake();
+ return;
+ }
+
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ ci->ci_ncore_cpus = 1;
+ ci->ci_core_cpus = ci;
+ ci->ci_package_cpus = ci;
+ ci->ci_npackage_cpus = 1;
+ }
+
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ for (CPU_INFO_FOREACH(cii2, ci2)) {
+ /* Avoid bad things happening. */
+ if (ci2->ci_package_id == ci->ci_package_id &&
+ ci2->ci_core_id == ci->ci_core_id &&
+ ci2->ci_smt_id == ci->ci_smt_id &&
+ ci2 != ci) {
+ printf("cpu_topology_init: info bogus, "
+ "faking it\n");
+ cpu_topology_fake();
+ return;
+ }
+ if (ci2 == ci ||
+ ci2->ci_package_id != ci->ci_package_id) {
+ continue;
+ }
+ /*
+ * Find CPUs in the same core. Walk to the end of
+ * the existing circular list and append.
+ */
+ if (ci->ci_ncore_cpus == 1 &&
+ ci->ci_core_id == ci2->ci_core_id) {
+ for (ci3 = ci2;; ci3 = ci3->ci_core_cpus) {
+ ci3->ci_ncore_cpus++;
+ if (ci3->ci_core_cpus == ci2) {
+ break;
+ }
+ }
+ ci->ci_core_cpus = ci2;
+ ci3->ci_core_cpus = ci;
+ ci->ci_ncore_cpus = ci3->ci_ncore_cpus;
+ }
+ /* Same, but for package. */
+ if (ci->ci_npackage_cpus == 1) {
+ for (ci3 = ci2;; ci3 = ci3->ci_package_cpus) {
+ ci3->ci_npackage_cpus++;
+ if (ci3->ci_package_cpus == ci2) {
+ break;
+ }
+ }
+ ci->ci_package_cpus = ci2;
+ ci3->ci_package_cpus = ci;
+ ci->ci_npackage_cpus = ci3->ci_npackage_cpus;
+ }
+ if (ci->ci_ncore_cpus > 1 && ci->ci_npackage_cpus > 1) {
+ break;
+ }
+ }
+ }
+}
+
#ifdef CPU_UCODE
int
cpu_ucode_load(struct cpu_ucode_softc *sc, const char *fwname)