Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Dec 2016 14:35:05 +0000 (UTC)
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r309675 - head/sys/arm64/arm64
Message-ID:  <201612071435.uB7EZ5qc008249@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andrew
Date: Wed Dec  7 14:35:05 2016
New Revision: 309675
URL: https://svnweb.freebsd.org/changeset/base/309675

Log:
  Add ACPI support to the arm64 mp code. We use the Multiple APIC Description
  Table to find the CPUs to find the CPUs to start. Currently we assume PSCI,
  however this assumption is shared with the FDT code.
  
  Obtained from:	ABT Systems Ltd
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/arm64/arm64/mp_machdep.c

Modified: head/sys/arm64/arm64/mp_machdep.c
==============================================================================
--- head/sys/arm64/arm64/mp_machdep.c	Wed Dec  7 14:24:53 2016	(r309674)
+++ head/sys/arm64/arm64/mp_machdep.c	Wed Dec  7 14:35:05 2016	(r309675)
@@ -28,6 +28,7 @@
  *
  */
 
+#include "opt_acpi.h"
 #include "opt_kstack_pages.h"
 #include "opt_platform.h"
 
@@ -59,6 +60,11 @@ __FBSDID("$FreeBSD$");
 #include <machine/vfp.h>
 #endif
 
+#ifdef DEV_ACPI
+#include <contrib/dev/acpica/include/acpi.h>
+#include <dev/acpica/acpivar.h>
+#endif
+
 #ifdef FDT
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_cpu.h>
@@ -106,14 +112,12 @@ struct pcb stoppcbs[MAXCPU];
 
 static device_t cpu_list[MAXCPU];
 
-#ifdef FDT
 /*
  * Not all systems boot from the first CPU in the device tree. To work around
  * this we need to find which CPU we have booted from so when we later
  * enable the secondary CPUs we skip this one.
  */
 static int cpu0 = -1;
-#endif
 
 void mpentry(unsigned long cpuid);
 void init_secondary(uint64_t);
@@ -416,11 +420,9 @@ cpu_mp_probe(void)
 	return (1);
 }
 
-#ifdef FDT
-static boolean_t
-cpu_init_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
+static bool
+start_cpu(u_int id, uint64_t target_cpu)
 {
-	uint64_t target_cpu;
 	struct pcpu *pcpup;
 	vm_paddr_t pa;
 	u_int cpuid;
@@ -428,13 +430,13 @@ cpu_init_fdt(u_int id, phandle_t node, u
 
 	/* Check we are able to start this cpu */
 	if (id > mp_maxid)
-		return (0);
+		return (false);
 
 	KASSERT(id < MAXCPU, ("Too many CPUs"));
 
 	/* We are already running on cpu 0 */
 	if (id == cpu0)
-		return (1);
+		return (true);
 
 	/*
 	 * Rotate the CPU IDs to put the boot CPU as CPU 0. We keep the other
@@ -454,12 +456,6 @@ cpu_init_fdt(u_int id, phandle_t node, u
 	    M_WAITOK | M_ZERO);
 	dpcpu_init(dpcpu[cpuid - 1], cpuid);
 
-	target_cpu = reg[0];
-	if (addr_size == 2) {
-		target_cpu <<= 32;
-		target_cpu |= reg[1];
-	}
-
 	printf("Starting CPU %u (%lx)\n", cpuid, target_cpu);
 	pa = pmap_extract(kernel_pmap, (vm_offset_t)mpentry);
 
@@ -482,7 +478,67 @@ cpu_init_fdt(u_int id, phandle_t node, u
 	} else
 		CPU_SET(cpuid, &all_cpus);
 
-	return (1);
+	return (true);
+}
+
+#ifdef DEV_ACPI
+static void
+madt_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+	ACPI_MADT_GENERIC_INTERRUPT *intr;
+	u_int *cpuid;
+
+	switch(entry->Type) {
+	case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
+		intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
+		cpuid = arg;
+
+		start_cpu((*cpuid), intr->ArmMpidr);
+		(*cpuid)++;
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+cpu_init_acpi(void)
+{
+	ACPI_TABLE_MADT *madt;
+	vm_paddr_t physaddr;
+	u_int cpuid;
+
+	physaddr = acpi_find_table(ACPI_SIG_MADT);
+	if (physaddr == 0)
+		return;
+
+	madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
+	if (madt == NULL) {
+		printf("Unable to map the MADT, not starting APs\n");
+		return;
+	}
+
+	cpuid = 0;
+	acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+	    madt_handler, &cpuid);
+
+	acpi_unmap_table(madt);
+}
+#endif
+
+#ifdef FDT
+static boolean_t
+cpu_init_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
+{
+	uint64_t target_cpu;
+
+	target_cpu = reg[0];
+	if (addr_size == 2) {
+		target_cpu <<= 32;
+		target_cpu |= reg[1];
+	}
+
+	return (start_cpu(id, target_cpu) ? TRUE : FALSE);
 }
 #endif
 
@@ -496,6 +552,12 @@ cpu_mp_start(void)
 	CPU_SET(0, &all_cpus);
 
 	switch(arm64_bus_method) {
+#ifdef DEV_ACPI
+	case ARM64_BUS_ACPI:
+		KASSERT(cpu0 >= 0, ("Current CPU was not found"));
+		cpu_init_acpi();
+		break;
+#endif
 #ifdef FDT
 	case ARM64_BUS_FDT:
 		KASSERT(cpu0 >= 0, ("Current CPU was not found"));
@@ -513,6 +575,56 @@ cpu_mp_announce(void)
 {
 }
 
+#ifdef DEV_ACPI
+static void
+cpu_count_acpi_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+	ACPI_MADT_GENERIC_INTERRUPT *intr;
+	u_int *cores = arg;
+	uint64_t mpidr_reg;
+
+	switch(entry->Type) {
+	case ACPI_MADT_TYPE_GENERIC_INTERRUPT:
+		intr = (ACPI_MADT_GENERIC_INTERRUPT *)entry;
+		if (cpu0 < 0) {
+			mpidr_reg = READ_SPECIALREG(mpidr_el1);
+			if ((mpidr_reg & 0xff00fffffful) == intr->ArmMpidr)
+				cpu0 = *cores;
+		}
+		(*cores)++;
+		break;
+	default:
+		break;
+	}
+}
+
+static u_int
+cpu_count_acpi(void)
+{
+	ACPI_TABLE_MADT *madt;
+	vm_paddr_t physaddr;
+	u_int cores;
+
+	physaddr = acpi_find_table(ACPI_SIG_MADT);
+	if (physaddr == 0)
+		return (0);
+
+	madt = acpi_map_table(physaddr, ACPI_SIG_MADT);
+	if (madt == NULL) {
+		printf("Unable to map the MADT, not starting APs\n");
+		return (0);
+	}
+
+	cores = 0;
+	acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+	    cpu_count_acpi_handler, &cores);
+
+	acpi_unmap_table(madt);
+
+	return (cores);
+}
+#endif
+
 #ifdef FDT
 static boolean_t
 cpu_find_cpu0_fdt(u_int id, phandle_t node, u_int addr_size, pcell_t *reg)
@@ -539,10 +651,27 @@ cpu_find_cpu0_fdt(u_int id, phandle_t no
 void
 cpu_mp_setmaxid(void)
 {
-#ifdef FDT
+#if defined(DEV_ACPI) || defined(FDT)
 	int cores;
+#endif
 
-	if (arm64_bus_method == ARM64_BUS_FDT) {
+	switch(arm64_bus_method) {
+#ifdef DEV_ACPI
+	case ARM64_BUS_ACPI:
+		cores = cpu_count_acpi();
+		if (cores > 0) {
+			cores = MIN(cores, MAXCPU);
+			if (bootverbose)
+				printf("Found %d CPUs in the ACPI tables\n",
+				    cores);
+			mp_ncpus = cores;
+			mp_maxid = cores - 1;
+			return;
+		}
+		break;
+#endif
+#ifdef FDT
+	case ARM64_BUS_FDT:
 		cores = ofw_cpu_early_foreach(cpu_find_cpu0_fdt, false);
 		if (cores > 0) {
 			cores = MIN(cores, MAXCPU);
@@ -553,8 +682,11 @@ cpu_mp_setmaxid(void)
 			mp_maxid = cores - 1;
 			return;
 		}
-	}
+		break;
 #endif
+	default:
+		break;
+	}
 
 	if (bootverbose)
 		printf("No CPU data, limiting to 1 core\n");



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612071435.uB7EZ5qc008249>