Add a kernel variable to let the user to select their preferred order

between ACPI and FDT. This will be needed on machines with both, e.g. the
SoftIron Overdrive 3000. The kernel will accept one or more comma separated
values of either 'acpi' or 'fdt'. Any other values are skipped.

To set it the user can either set it on the loader command line, or
in loader.conf e.g. in loader.conf:
kern.cfg.order=acpi,fdt

This will try using ACPI then FDT. If none of the selected options work the
kernel tries to use one to get the serial console, then panics.

Reviewed by:	emaste (earlier version)
Obtained from:	ABT Systems Ltd
MFC after:	1 month
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D7274
This commit is contained in:
Andrew Turner 2016-08-01 12:17:44 +00:00
parent 5a31465d50
commit 698c14e189
4 changed files with 97 additions and 21 deletions

View File

@ -25,6 +25,7 @@
*
*/
#include "opt_acpi.h"
#include "opt_platform.h"
#include "opt_ddb.h"
@ -82,11 +83,19 @@ __FBSDID("$FreeBSD$");
#include <machine/vfp.h>
#endif
#ifdef DEV_ACPI
#include <contrib/dev/acpica/include/acpi.h>
#include <machine/acpica_machdep.h>
#endif
#ifdef FDT
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#endif
enum arm64_bus arm64_bus_method = ARM64_BUS_NONE;
struct pcpu __pcpu[MAXCPU];
static struct trapframe proc0_tf;
@ -802,6 +811,61 @@ try_load_dtb(caddr_t kmdp)
}
#endif
static bool
bus_probe(void)
{
bool has_acpi, has_fdt;
char *order, *env;
has_acpi = has_fdt = false;
#ifdef FDT
has_fdt = (OF_peer(0) != 0);
#endif
#ifdef DEV_ACPI
has_acpi = (acpi_find_table(ACPI_SIG_SPCR) != 0);
#endif
env = kern_getenv("kern.cfg.order");
if (env != NULL) {
order = env;
while (order != NULL) {
if (has_acpi &&
strncmp(order, "acpi", 4) == 0 &&
(order[4] == ',' || order[4] == '\0')) {
arm64_bus_method = ARM64_BUS_ACPI;
break;
}
if (has_fdt &&
strncmp(order, "fdt", 3) == 0 &&
(order[3] == ',' || order[3] == '\0')) {
arm64_bus_method = ARM64_BUS_FDT;
break;
}
order = strchr(order, ',');
}
freeenv(env);
/* If we set the bus method it is valid */
if (arm64_bus_method != ARM64_BUS_NONE)
return (true);
}
/* If no order or an invalid order was set use the default */
if (arm64_bus_method == ARM64_BUS_NONE) {
if (has_fdt)
arm64_bus_method = ARM64_BUS_FDT;
else if (has_acpi)
arm64_bus_method = ARM64_BUS_ACPI;
}
/*
* If no option was set the default is valid, otherwise we are
* setting one to get cninit() working, then calling panic to tell
* the user about the invalid bus setup.
*/
return (env == NULL);
}
static void
cache_setup(void)
{
@ -849,6 +913,7 @@ initarm(struct arm64_bootparams *abp)
vm_offset_t lastaddr;
caddr_t kmdp;
vm_paddr_t mem_len;
bool valid;
int i;
/* Set the module data location */
@ -921,8 +986,14 @@ initarm(struct arm64_bootparams *abp)
devmap_bootstrap(0, NULL);
valid = bus_probe();
cninit();
if (!valid)
panic("Invalid bus configuration: %s",
kern_getenv("kern.cfg.order"));
init_proc0(abp->kern_stack);
msgbufinit(msgbufp, msgbufsize);
mutex_init();

View File

@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_kern.h>
#include <machine/debug_monitor.h>
#include <machine/machdep.h>
#include <machine/intr.h>
#include <machine/smp.h>
#ifdef VFP
@ -90,13 +91,6 @@ boolean_t ofw_cpu_reg(phandle_t node, u_int, cell_t *);
extern struct pcpu __pcpu[];
static enum {
CPUS_UNKNOWN,
#ifdef FDT
CPUS_FDT,
#endif
} cpu_enum_method;
static device_identify_t arm64_cpu_identify;
static device_probe_t arm64_cpu_probe;
static device_attach_t arm64_cpu_attach;
@ -499,14 +493,14 @@ cpu_mp_start(void)
CPU_SET(0, &all_cpus);
switch(cpu_enum_method) {
switch(arm64_bus_method) {
#ifdef FDT
case CPUS_FDT:
case ARM64_BUS_FDT:
KASSERT(cpu0 >= 0, ("Current CPU was not found"));
ofw_cpu_early_foreach(cpu_init_fdt, true);
break;
#endif
case CPUS_UNKNOWN:
default:
break;
}
}
@ -544,15 +538,17 @@ cpu_mp_setmaxid(void)
#ifdef FDT
int cores;
cores = ofw_cpu_early_foreach(cpu_find_cpu0_fdt, false);
if (cores > 0) {
cores = MIN(cores, MAXCPU);
if (bootverbose)
printf("Found %d CPUs in the device tree\n", cores);
mp_ncpus = cores;
mp_maxid = cores - 1;
cpu_enum_method = CPUS_FDT;
return;
if (arm64_bus_method == ARM64_BUS_FDT) {
cores = ofw_cpu_early_foreach(cpu_find_cpu0_fdt, false);
if (cores > 0) {
cores = MIN(cores, MAXCPU);
if (bootverbose)
printf("Found %d CPUs in the device tree\n",
cores);
mp_ncpus = cores;
mp_maxid = cores - 1;
return;
}
}
#endif

View File

@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <sys/interrupt.h>
#include <machine/machdep.h>
#include <machine/vmparam.h>
#include <machine/pcb.h>
#include <vm/vm.h>
@ -411,7 +412,7 @@ static int
nexus_fdt_probe(device_t dev)
{
if (OF_peer(0) == 0)
if (arm64_bus_method != ARM64_BUS_FDT)
return (ENXIO);
device_quiet(dev);
@ -455,7 +456,7 @@ static int
nexus_acpi_probe(device_t dev)
{
if (acpi_identify() != 0)
if (arm64_bus_method != ARM64_BUS_ACPI || acpi_identify() != 0)
return (ENXIO);
device_quiet(dev);

View File

@ -37,6 +37,14 @@ struct arm64_bootparams {
vm_offset_t kern_l0pt; /* L1 page table for the kernel */
};
enum arm64_bus {
ARM64_BUS_NONE,
ARM64_BUS_FDT,
ARM64_BUS_ACPI,
};
extern enum arm64_bus arm64_bus_method;
extern vm_paddr_t physmap[];
extern u_int physmap_idx;