Furquan Shaikh (furquan(a)google.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17773
-gerrit
commit e4b49d7ff0dbc1c288a68fb6d40d44d7ee396116
Author: Furquan Shaikh <furquan(a)chromium.org>
Date: Wed Dec 7 20:34:32 2016 -0800
include/stddef: Ensure NULL is not redefined
Some third party libraries might define NULL and so it is important to
ensure that NULL is not redefined by stddef. Thus, add a check before
defining NULL.
Change-Id: I600083c5d8f672518beaa1119f14f67728a433aa
Signed-off-by: Furquan Shaikh <furquan(a)chromium.org>
---
src/include/stddef.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/include/stddef.h b/src/include/stddef.h
index d0308d2..e6ed703 100644
--- a/src/include/stddef.h
+++ b/src/include/stddef.h
@@ -19,7 +19,9 @@ typedef __SIZE_TYPE__ ssize_t;
typedef int wchar_t;
typedef unsigned int wint_t;
+#ifndef NULL
#define NULL ((void *)0)
+#endif
#ifdef __PRE_RAM__
#define ROMSTAGE_CONST const
Marty Plummer (ntzrmtthihu777(a)gmail.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17669
-gerrit
commit 16d67ae23ee60c07404405dbdb0e0d55032a9ee5
Author: Marty Plummer <ntzrmtthihu777(a)gmail.com>
Date: Thu Dec 1 02:14:39 2016 -0600
superio/fintek: Add support for Fintek F71889A.
Datasheet: F71889A rev V0.21P
Change-Id: I91c60a3b48cd4872ae7a27de8f49faa40e877a27
Signed-off-by: Marty Plummer <ntzrmtthihu777(a)gmail.com>
---
src/superio/fintek/Makefile.inc | 1 +
src/superio/fintek/f71889a/Kconfig | 20 +++++++++
src/superio/fintek/f71889a/Makefile.inc | 18 ++++++++
src/superio/fintek/f71889a/f71889a.h | 33 +++++++++++++++
src/superio/fintek/f71889a/superio.c | 73 +++++++++++++++++++++++++++++++++
5 files changed, 145 insertions(+)
diff --git a/src/superio/fintek/Makefile.inc b/src/superio/fintek/Makefile.inc
index 0d0ae66..d70fc99 100644
--- a/src/superio/fintek/Makefile.inc
+++ b/src/superio/fintek/Makefile.inc
@@ -21,6 +21,7 @@ subdirs-y += f71859
subdirs-y += f71863fg
subdirs-y += f71869ad
subdirs-y += f71872
+subdirs-y += f71889a
subdirs-y += f81216h
subdirs-y += f81865f
subdirs-y += f81866d
diff --git a/src/superio/fintek/f71889a/Kconfig b/src/superio/fintek/f71889a/Kconfig
new file mode 100644
index 0000000..96366d9
--- /dev/null
+++ b/src/superio/fintek/f71889a/Kconfig
@@ -0,0 +1,20 @@
+#
+# This file is part of the coreboot project.
+#
+# Copyright (C) 2014 Edward O'Callaghan <eocallaghan(a)alterapraxis.com>
+# Copyright (C) 2016 Marty Plummer <ntzrmtthihu777(a)gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+config SUPERIO_FINTEK_F71889A
+ bool
+ select SUPERIO_FINTEK_COMMON_ROMSTAGE
diff --git a/src/superio/fintek/f71889a/Makefile.inc b/src/superio/fintek/f71889a/Makefile.inc
new file mode 100644
index 0000000..06fcff9
--- /dev/null
+++ b/src/superio/fintek/f71889a/Makefile.inc
@@ -0,0 +1,18 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2014 Edward O'Callaghan <eocallaghan(a)alterapraxis.com>
+## Copyright (C) 2016 Marty Plummer <ntzrmtthihu777(a)gmail.com>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+
+ramstage-$(CONFIG_SUPERIO_FINTEK_F71889A) += superio.c
diff --git a/src/superio/fintek/f71889a/f71889a.h b/src/superio/fintek/f71889a/f71889a.h
new file mode 100644
index 0000000..4a272a6
--- /dev/null
+++ b/src/superio/fintek/f71889a/f71889a.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Edward O'Callaghan <eocallaghan(a)alterapraxis.com>
+ * Copyright (C) 2016 Marty Plummer <ntzrmtthihu777(a)gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SUPERIO_FINTEK_F71889A_H
+#define SUPERIO_FINTEK_F71889A_H
+
+/* Logical Device Numbers (LDN). */
+#define F71889A_SP1 0x01 /* UART1 */
+#define F71889A_SP2 0x02 /* UART2 */
+#define F71889A_PP 0x03 /* Parallel Port */
+#define F71889A_HWM 0x04 /* Hardware Monitor */
+#define F71889A_KBC 0x05 /* Keyboard/Mouse */
+#define F71889A_GPIO 0x06 /* GPIO */
+#define F71889A_WDT 0x07 /* WDT */
+#define F71889A_CIR 0x08 /* CIR */
+#define F71889A_PM 0x0a /* ACPI/PME */
+#define F71889A_VREF 0x0b /* VREF */
+
+#endif /* SUPERIO_FINTEK_F71889A_H */
diff --git a/src/superio/fintek/f71889a/superio.c b/src/superio/fintek/f71889a/superio.c
new file mode 100644
index 0000000..1473e76
--- /dev/null
+++ b/src/superio/fintek/f71889a/superio.c
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Edward O'Callaghan <eocallaghan(a)alterapraxis.com>
+ * Copyright (C) 2016 Marty Plummer <ntzrmtthihu777(a)gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pnp.h>
+#include <superio/conf_mode.h>
+#include <console/console.h>
+#include <stdlib.h>
+#include <pc80/keyboard.h>
+#include "f71889a.h"
+
+static void f71889a_init(struct device *dev)
+{
+ if (!dev->enabled)
+ return;
+
+ switch (dev->path.pnp.device) {
+
+ case F71889A_KBC:
+ pc_keyboard_init(NO_AUX_DEVICE);
+ break;
+ }
+}
+
+static struct device_operations ops = {
+ .read_resources = pnp_read_resources,
+ .set_resources = pnp_set_resources,
+ .enable_resources = pnp_enable_resources,
+ .enable = pnp_alt_enable,
+ .init = f71889a_init,
+ .ops_pnp_mode = &pnp_conf_mode_8787_aa,
+};
+
+static struct pnp_info pnp_dev_info[] = {
+ /* TODO: Some of the 0x07f8 etc. values may not be correct.
+ * double check bitmasks
+ */
+ { &ops, F71889A_SP1, PNP_IO0 | PNP_IRQ0, {0x07f8, 0}, },
+ { &ops, F71889A_SP2, PNP_IO0 | PNP_IRQ0, {0x07f8, 0}, },
+ { &ops, F71889A_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, {0x07f8, 0}, },
+ { &ops, F71889A_HWM, PNP_IO0 | PNP_IRQ0, {0x07f8, 0}, },
+ { &ops, F71889A_KBC, PNP_IO0 | PNP_IRQ0 | PNP_IRQ1, {0x07f8, 0}, },
+ { &ops, F71889A_GPIO, },
+ { &ops, F71889A_WDT, PNP_IO0, {0x07f8, 0}, },
+ { &ops, F71889A_CIR, PNP_IO0 | PNP_IRQ0, {0x7f8, 0}, },
+ { &ops, F71889A_PM, },
+ { &ops, F71889A_VREF, },
+};
+
+static void enable_dev(struct device *dev)
+{
+ pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
+}
+
+struct chip_operations superio_fintek_f71889a_ops = {
+ CHIP_NAME("Fintek F71889A Super I/O")
+ .enable_dev = enable_dev
+};
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17772
-gerrit
commit 5030fc7d10d63c84f2eb796a451fde6cb5cfb669
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed Dec 7 17:39:09 2016 -0600
mainboard/google/reef: fill in NHLT ACPI OEM header fields
Fill in the NHLT ACPI OEM header fields to differentiate
different audio solutions on a per board basis. This handles
boards that share a firmware that are differentiated by
the SKU id and boards that have their own firmware. For the
latter, the Oem Table ID uses the VARIANT_DIR to differentiate.
"reef" is always used for Oem ID which is treated as more of
family in this case.
iasl -d shows the following on reef:
[00Ah 0010 6] Oem ID : "reef"
[010h 0016 8] Oem Table ID : "reef"
[018h 0024 4] Oem Revision : 00000008
BUG=chrome-os-partner:60494
BRANCH=reef
Change-Id: I5daa6f0306bc05e812a8737ce61ee37177a36b76
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/mainboard/google/reef/mainboard.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/mainboard/google/reef/mainboard.c b/src/mainboard/google/reef/mainboard.c
index e350df2..702269c 100644
--- a/src/mainboard/google/reef/mainboard.c
+++ b/src/mainboard/google/reef/mainboard.c
@@ -77,6 +77,9 @@ void __attribute__((weak)) variant_nhlt_oem_overrides(const char **oem_id,
const char **oem_table_id,
uint32_t *oem_revision)
{
+ *oem_id = "reef";
+ *oem_table_id = CONFIG_VARIANT_DIR;
+ *oem_revision = board_sku();
}
static unsigned long mainboard_write_acpi_tables(
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17745
-gerrit
commit b3bb50d9721ac9df0649a217ddaadc19165c79b2
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed Dec 7 00:32:19 2016 -0600
cpu/x86: allow AP callbacks after MP init
There are circumstances where the APs need to run a piece of
code later in the boot flow. The current MP init just parks
the APs after MP init is completed so there's not an opportunity
to target running a piece of code on all the APs at a later time.
Therefore, provide an option, PARALLEL_MP_AP_WORK, that allows
the APs to perform callbacks.
BUG=chrome-os-partner:60657
BRANCH=reef
Change-Id: I849ecfdd6641dd9424943e246317cd1996ef1ba6
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/arch/x86/cpu.c | 13 ++++++
src/cpu/x86/Kconfig | 6 +++
src/cpu/x86/mp_init.c | 107 +++++++++++++++++++++++++++++++++++++++++++----
src/include/cpu/x86/mp.h | 18 ++++++++
4 files changed, 137 insertions(+), 7 deletions(-)
diff --git a/src/arch/x86/cpu.c b/src/arch/x86/cpu.c
index fbd48b0..1e74d0c 100644
--- a/src/arch/x86/cpu.c
+++ b/src/arch/x86/cpu.c
@@ -11,11 +11,13 @@
* GNU General Public License for more details.
*/
+#include <bootstate.h>
#include <boot/coreboot_tables.h>
#include <console/console.h>
#include <cpu/cpu.h>
#include <arch/io.h>
#include <string.h>
+#include <cpu/x86/mp.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/lapic.h>
@@ -310,3 +312,14 @@ void lb_arch_add_records(struct lb_header *header)
tsc_info->size = sizeof(*tsc_info);
tsc_info->freq_khz = freq_khz;
}
+
+void arch_bootstate_coreboot_exit(void)
+{
+ /* APs are already parked by existing infrastructure. */
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK))
+ return;
+
+ /* APs are waiting for work. Last thing to do is park them. */
+ if (mp_park_aps())
+ printk(BIOS_ERR, "Parking APs failed.\n");
+}
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 3e56d72..2e233cc 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -10,6 +10,12 @@ config PARALLEL_MP
in parallel. It additionally provides a more flexible mechanism
for sequencing the steps of bringing up the APs.
+config PARALLEL_MP_AP_WORK
+ def_bool n
+ depends on PARALLEL_MP
+ help
+ Allow APs to do other work after initialization instead of going
+ to sleep.
config UDELAY_IO
bool
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c
index baa3599..c989963 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -127,6 +127,7 @@ struct mp_flight_plan {
struct mp_flight_record *records;
};
+static int global_num_aps;
static struct mp_flight_plan mp_info;
struct cpu_map {
@@ -185,6 +186,11 @@ static void ap_do_flight_plan(void)
}
}
+static void park_this_cpu(void)
+{
+ stop_this_cpu();
+}
+
/* By the time APs call ap_init() caching has been setup, and microcode has
* been loaded. */
static void asmlinkage ap_init(unsigned int cpu)
@@ -210,7 +216,7 @@ static void asmlinkage ap_init(unsigned int cpu)
ap_do_flight_plan();
/* Park the AP. */
- stop_this_cpu();
+ park_this_cpu();
}
static void setup_default_sipi_vector_params(struct sipi_params *sp)
@@ -587,7 +593,6 @@ static void init_bsp(struct bus *cpu_bus)
static int mp_init(struct bus *cpu_bus, struct mp_params *p)
{
int num_cpus;
- int num_aps;
atomic_t *ap_count;
init_bsp(cpu_bus);
@@ -621,11 +626,11 @@ static int mp_init(struct bus *cpu_bus, struct mp_params *p)
wbinvd();
/* Start the APs providing number of APs and the cpus_entered field. */
- num_aps = p->num_cpus - 1;
- if (start_aps(cpu_bus, num_aps, ap_count) < 0) {
+ global_num_aps = p->num_cpus - 1;
+ if (start_aps(cpu_bus, global_num_aps, ap_count) < 0) {
mdelay(1000);
printk(BIOS_DEBUG, "%d/%d eventually checked in?\n",
- atomic_read(ap_count), num_aps);
+ atomic_read(ap_count), global_num_aps);
return -1;
}
@@ -838,6 +843,94 @@ static void trigger_smm_relocation(void)
mp_state.ops.per_cpu_smm_trigger();
}
+static mp_callback_t ap_callbacks[CONFIG_MAX_CPUS];
+
+static mp_callback_t read_callback(mp_callback_t *slot)
+{
+ return *(volatile mp_callback_t *)slot;
+}
+
+static void store_callback(mp_callback_t *slot, mp_callback_t value)
+{
+ *(volatile mp_callback_t *)slot = value;
+}
+
+static int run_ap_work(mp_callback_t func, long expire_us)
+{
+ int i;
+ int cpus_accepted;
+ struct stopwatch sw;
+ int cur_cpu = cpu_index();
+
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK)) {
+ printk(BIOS_ERR, "APs already parked. PARALLEL_MP_AP_WORK not selected.\n");
+ return -1;
+ }
+
+ /* Signal to all the APs to run the func. */
+ for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) {
+ if (cur_cpu == i)
+ continue;
+ store_callback(&ap_callbacks[i], func);
+ }
+ mfence();
+
+ /* Wait for all the APs to signal back that call has been accepted. */
+ stopwatch_init_usecs_expire(&sw, expire_us);
+ for (cpus_accepted = 0; !stopwatch_expired(&sw); cpus_accepted = 0) {
+ for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) {
+ if (cur_cpu == i)
+ continue;
+ if (read_callback(&ap_callbacks[i]) == NULL)
+ cpus_accepted++;
+ }
+ if (cpus_accepted == global_num_aps)
+ return 0;
+ }
+
+ printk(BIOS_ERR, "AP call expired. %d/%d CPUs accepted.\n",
+ cpus_accepted, global_num_aps);
+ return -1;
+}
+
+static void ap_wait_for_instruction(void)
+{
+ int cur_cpu = cpu_index();
+
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK))
+ return;
+
+ while (1) {
+ mp_callback_t func = read_callback(&ap_callbacks[cur_cpu]);
+
+ if (func == NULL) {
+ asm ("pause");
+ continue;
+ }
+
+ store_callback(&ap_callbacks[cur_cpu], NULL);
+ mfence();
+ func();
+ }
+}
+
+int mp_run_on_aps(void (*func)(void), long expire_us)
+{
+ return run_ap_work(func, expire_us);
+}
+
+int mp_run_on_all_cpus(void (*func)(void), long expire_us)
+{
+ /* Run on BSP first. */
+ func();
+ return mp_run_on_aps(func, expire_us);
+}
+
+int mp_park_aps(void)
+{
+ return mp_run_on_aps(park_this_cpu, 10 * USECS_PER_MSEC);
+}
+
static struct mp_flight_record mp_steps[] = {
/* Once the APs are up load the SMM handlers. */
MP_FR_BLOCK_APS(NULL, load_smm_handlers),
@@ -845,8 +938,8 @@ static struct mp_flight_record mp_steps[] = {
MP_FR_NOBLOCK_APS(trigger_smm_relocation, trigger_smm_relocation),
/* Initialize each CPU through the driver framework. */
MP_FR_BLOCK_APS(mp_initialize_cpu, mp_initialize_cpu),
- /* Wait for APs to finish everything else then let them park. */
- MP_FR_BLOCK_APS(NULL, NULL),
+ /* Wait for APs to finish then optionally start looking for work. */
+ MP_FR_BLOCK_APS(ap_wait_for_instruction, NULL),
};
static void fill_mp_state(struct mp_state *state, const struct mp_ops *ops)
diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h
index 6d51d7b..b9b4d57 100644
--- a/src/include/cpu/x86/mp.h
+++ b/src/include/cpu/x86/mp.h
@@ -124,6 +124,24 @@ struct mp_ops {
*/
int mp_init_with_smm(struct bus *cpu_bus, const struct mp_ops *mp_ops);
+
+/*
+ * After APs are up and PARALLEL_MP_AP_WORK is enabled one can issue work
+ * to all the APs to perform. Currently the BSP is the only CPU that is allowed
+ * to issue work. i.e. the APs should not call any of these functions.
+ * All functions return < 0 on error, 0 on success.
+ */
+int mp_run_on_aps(void (*func)(void), long expire_us);
+
+/* Like mp_run_on_aps() but also runs func on BSP. */
+int mp_run_on_all_cpus(void (*func)(void), long expire_us);
+
+/*
+ * Park all APs to prepare for OS boot. This is handled automatically
+ * by the coreboot infrastructure.
+ */
+int mp_park_aps(void);
+
/*
* SMM helpers to use with initializing CPUs.
*/
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17745
-gerrit
commit 58671696296613034747bbcdeeca87d19e9a2f20
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed Dec 7 00:32:19 2016 -0600
cpu/x86: allow AP callbacks after MP init
There are circumstances where the APs need to run a piece of
code later in the boot flow. The current MP init just parks
the APs after MP init is completed so there's not an opportunity
to target running a piece of code on all the APs at a later time.
Therefore, provide an option, PARALLEL_MP_AP_WORK, that allows
the APs to perform callbacks.
BUG=chrome-os-partner:60657
BRANCH=reef
Change-Id: I849ecfdd6641dd9424943e246317cd1996ef1ba6
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/arch/x86/cpu.c | 13 ++++++
src/cpu/x86/Kconfig | 6 +++
src/cpu/x86/mp_init.c | 100 +++++++++++++++++++++++++++++++++++++++++++----
src/include/cpu/x86/mp.h | 15 +++++++
4 files changed, 127 insertions(+), 7 deletions(-)
diff --git a/src/arch/x86/cpu.c b/src/arch/x86/cpu.c
index fbd48b0..1e74d0c 100644
--- a/src/arch/x86/cpu.c
+++ b/src/arch/x86/cpu.c
@@ -11,11 +11,13 @@
* GNU General Public License for more details.
*/
+#include <bootstate.h>
#include <boot/coreboot_tables.h>
#include <console/console.h>
#include <cpu/cpu.h>
#include <arch/io.h>
#include <string.h>
+#include <cpu/x86/mp.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/lapic.h>
@@ -310,3 +312,14 @@ void lb_arch_add_records(struct lb_header *header)
tsc_info->size = sizeof(*tsc_info);
tsc_info->freq_khz = freq_khz;
}
+
+void arch_bootstate_coreboot_exit(void)
+{
+ /* APs are already parked by existing infrastructure. */
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK))
+ return;
+
+ /* APs are waiting for work. Last thing to do is park them. */
+ if (mp_park_aps())
+ printk(BIOS_ERR, "Parking APs failed.\n");
+}
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 3e56d72..2e233cc 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -10,6 +10,12 @@ config PARALLEL_MP
in parallel. It additionally provides a more flexible mechanism
for sequencing the steps of bringing up the APs.
+config PARALLEL_MP_AP_WORK
+ def_bool n
+ depends on PARALLEL_MP
+ help
+ Allow APs to do other work after initialization instead of going
+ to sleep.
config UDELAY_IO
bool
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c
index baa3599..b046b8d 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -127,6 +127,7 @@ struct mp_flight_plan {
struct mp_flight_record *records;
};
+static int global_num_aps;
static struct mp_flight_plan mp_info;
struct cpu_map {
@@ -185,6 +186,11 @@ static void ap_do_flight_plan(void)
}
}
+static void park_this_cpu(void)
+{
+ stop_this_cpu();
+}
+
/* By the time APs call ap_init() caching has been setup, and microcode has
* been loaded. */
static void asmlinkage ap_init(unsigned int cpu)
@@ -210,7 +216,7 @@ static void asmlinkage ap_init(unsigned int cpu)
ap_do_flight_plan();
/* Park the AP. */
- stop_this_cpu();
+ park_this_cpu();
}
static void setup_default_sipi_vector_params(struct sipi_params *sp)
@@ -587,7 +593,6 @@ static void init_bsp(struct bus *cpu_bus)
static int mp_init(struct bus *cpu_bus, struct mp_params *p)
{
int num_cpus;
- int num_aps;
atomic_t *ap_count;
init_bsp(cpu_bus);
@@ -621,11 +626,11 @@ static int mp_init(struct bus *cpu_bus, struct mp_params *p)
wbinvd();
/* Start the APs providing number of APs and the cpus_entered field. */
- num_aps = p->num_cpus - 1;
- if (start_aps(cpu_bus, num_aps, ap_count) < 0) {
+ global_num_aps = p->num_cpus - 1;
+ if (start_aps(cpu_bus, global_num_aps, ap_count) < 0) {
mdelay(1000);
printk(BIOS_DEBUG, "%d/%d eventually checked in?\n",
- atomic_read(ap_count), num_aps);
+ atomic_read(ap_count), global_num_aps);
return -1;
}
@@ -838,6 +843,87 @@ static void trigger_smm_relocation(void)
mp_state.ops.per_cpu_smm_trigger();
}
+static mp_callback_t ap_callbacks[CONFIG_MAX_CPUS];
+
+static mp_callback_t read_callback(mp_callback_t *slot)
+{
+ return *(volatile mp_callback_t *)slot;
+}
+
+static void store_callback(mp_callback_t *slot, mp_callback_t value)
+{
+ *(volatile mp_callback_t *)slot = value;
+}
+
+static int run_ap_work(mp_callback_t func, long expire_us)
+{
+ int i;
+ int cpus_accepted;
+ struct stopwatch sw;
+ int cur_cpu = cpu_index();
+
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK)) {
+ printk(BIOS_ERR, "APs already parked. PARALLEL_MP_AP_WORK not selected.\n");
+ return -1;
+ }
+
+ /* Signal to all the APs to run the func. */
+ for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) {
+ if (cur_cpu == i)
+ continue;
+ store_callback(&ap_callbacks[i], func);
+ }
+ mfence();
+
+ /* Wait for all the APs to signal back that call has been accepted. */
+ stopwatch_init_usecs_expire(&sw, expire_us);
+ for (cpus_accepted = 0; !stopwatch_expired(&sw); cpus_accepted = 0) {
+ for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) {
+ if (cur_cpu == i)
+ continue;
+ if (read_callback(&ap_callbacks[i]) == NULL)
+ cpus_accepted++;
+ }
+ if (cpus_accepted == global_num_aps)
+ return 0;
+ }
+
+ printk(BIOS_ERR, "AP call expired. %d/%d CPUs accepted.\n",
+ cpus_accepted, global_num_aps);
+ return -1;
+}
+
+static void ap_wait_for_instruction(void)
+{
+ int cur_cpu = cpu_index();
+
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK))
+ return;
+
+ while (1) {
+ mp_callback_t func = read_callback(&ap_callbacks[cur_cpu]);
+
+ if (func == NULL) {
+ asm ("pause");
+ continue;
+ }
+
+ store_callback(&ap_callbacks[cur_cpu], NULL);
+ mfence();
+ func();
+ }
+}
+
+int mp_run_on_aps(void (*func)(void), long expire_us)
+{
+ return run_ap_work(func, expire_us);
+}
+
+int mp_park_aps(void)
+{
+ return mp_run_on_aps(park_this_cpu, 10 * USECS_PER_MSEC);
+}
+
static struct mp_flight_record mp_steps[] = {
/* Once the APs are up load the SMM handlers. */
MP_FR_BLOCK_APS(NULL, load_smm_handlers),
@@ -845,8 +931,8 @@ static struct mp_flight_record mp_steps[] = {
MP_FR_NOBLOCK_APS(trigger_smm_relocation, trigger_smm_relocation),
/* Initialize each CPU through the driver framework. */
MP_FR_BLOCK_APS(mp_initialize_cpu, mp_initialize_cpu),
- /* Wait for APs to finish everything else then let them park. */
- MP_FR_BLOCK_APS(NULL, NULL),
+ /* Wait for APs to finish then optionally start looking for work. */
+ MP_FR_BLOCK_APS(ap_wait_for_instruction, NULL),
};
static void fill_mp_state(struct mp_state *state, const struct mp_ops *ops)
diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h
index 6d51d7b..5841a80 100644
--- a/src/include/cpu/x86/mp.h
+++ b/src/include/cpu/x86/mp.h
@@ -124,6 +124,21 @@ struct mp_ops {
*/
int mp_init_with_smm(struct bus *cpu_bus, const struct mp_ops *mp_ops);
+
+/*
+ * After APs are up and PARALLEL_MP_AP_WORK is enabled one can issue work
+ * to all the APs to perform. Currently the BSP is the only CPU that is allowed
+ * to issue work. i.e. the APs should not call any of these functions.
+ * All functions return < 0 on error, 0 on success.
+ */
+int mp_run_on_aps(void (*func)(void), long expire_us);
+
+/*
+ * Park all APs to prepare for OS boot. This is handled automatically
+ * by the coreboot infrastructure.
+ */
+int mp_park_aps(void);
+
/*
* SMM helpers to use with initializing CPUs.
*/
Aaron Durbin (adurbin(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/17745
-gerrit
commit c7ac87043cbdbce6a49ba7607ee25ebe5926d9e8
Author: Aaron Durbin <adurbin(a)chromium.org>
Date: Wed Dec 7 00:32:19 2016 -0600
cpu/x86: allow AP callbacks after MP init
There are circumstances where the APs need to run a piece of
code later in the boot flow. The current MP init just parks
the APs after MP init is completed so there's not an opportunity
to target running a piece of code on all the APs at a later time.
Therefore, provide an option, PARALLEL_MP_AP_WORK, that allows
the APs to perform callbacks.
BUG=chrome-os-partner:60657
BRANCH=reef
Change-Id: I849ecfdd6641dd9424943e246317cd1996ef1ba6
Signed-off-by: Aaron Durbin <adurbin(a)chromium.org>
---
src/arch/x86/cpu.c | 13 ++++++
src/cpu/x86/Kconfig | 6 +++
src/cpu/x86/mp_init.c | 102 +++++++++++++++++++++++++++++++++++++++++++----
src/include/cpu/x86/mp.h | 15 +++++++
4 files changed, 129 insertions(+), 7 deletions(-)
diff --git a/src/arch/x86/cpu.c b/src/arch/x86/cpu.c
index fbd48b0..1e74d0c 100644
--- a/src/arch/x86/cpu.c
+++ b/src/arch/x86/cpu.c
@@ -11,11 +11,13 @@
* GNU General Public License for more details.
*/
+#include <bootstate.h>
#include <boot/coreboot_tables.h>
#include <console/console.h>
#include <cpu/cpu.h>
#include <arch/io.h>
#include <string.h>
+#include <cpu/x86/mp.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/lapic.h>
@@ -310,3 +312,14 @@ void lb_arch_add_records(struct lb_header *header)
tsc_info->size = sizeof(*tsc_info);
tsc_info->freq_khz = freq_khz;
}
+
+void arch_bootstate_coreboot_exit(void)
+{
+ /* APs are already parked by existing infrastructure. */
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK))
+ return;
+
+ /* APs are waiting for work. Last thing to do is park them. */
+ if (mp_park_aps())
+ printk(BIOS_ERR, "Parking APs failed.\n");
+}
diff --git a/src/cpu/x86/Kconfig b/src/cpu/x86/Kconfig
index 3e56d72..2e233cc 100644
--- a/src/cpu/x86/Kconfig
+++ b/src/cpu/x86/Kconfig
@@ -10,6 +10,12 @@ config PARALLEL_MP
in parallel. It additionally provides a more flexible mechanism
for sequencing the steps of bringing up the APs.
+config PARALLEL_MP_AP_WORK
+ def_bool n
+ depends on PARALLEL_MP
+ help
+ Allow APs to do other work after initialization instead of going
+ to sleep.
config UDELAY_IO
bool
diff --git a/src/cpu/x86/mp_init.c b/src/cpu/x86/mp_init.c
index baa3599..aee2c3e 100644
--- a/src/cpu/x86/mp_init.c
+++ b/src/cpu/x86/mp_init.c
@@ -127,6 +127,7 @@ struct mp_flight_plan {
struct mp_flight_record *records;
};
+static int global_num_aps;
static struct mp_flight_plan mp_info;
struct cpu_map {
@@ -185,6 +186,11 @@ static void ap_do_flight_plan(void)
}
}
+static void park_this_cpu(void)
+{
+ stop_this_cpu();
+}
+
/* By the time APs call ap_init() caching has been setup, and microcode has
* been loaded. */
static void asmlinkage ap_init(unsigned int cpu)
@@ -210,7 +216,7 @@ static void asmlinkage ap_init(unsigned int cpu)
ap_do_flight_plan();
/* Park the AP. */
- stop_this_cpu();
+ park_this_cpu();
}
static void setup_default_sipi_vector_params(struct sipi_params *sp)
@@ -587,7 +593,6 @@ static void init_bsp(struct bus *cpu_bus)
static int mp_init(struct bus *cpu_bus, struct mp_params *p)
{
int num_cpus;
- int num_aps;
atomic_t *ap_count;
init_bsp(cpu_bus);
@@ -621,11 +626,11 @@ static int mp_init(struct bus *cpu_bus, struct mp_params *p)
wbinvd();
/* Start the APs providing number of APs and the cpus_entered field. */
- num_aps = p->num_cpus - 1;
- if (start_aps(cpu_bus, num_aps, ap_count) < 0) {
+ global_num_aps = p->num_cpus - 1;
+ if (start_aps(cpu_bus, global_num_aps, ap_count) < 0) {
mdelay(1000);
printk(BIOS_DEBUG, "%d/%d eventually checked in?\n",
- atomic_read(ap_count), num_aps);
+ atomic_read(ap_count), global_num_aps);
return -1;
}
@@ -838,6 +843,89 @@ static void trigger_smm_relocation(void)
mp_state.ops.per_cpu_smm_trigger();
}
+static mp_callback_t ap_callbacks[CONFIG_MAX_CPUS];
+
+static mp_callback_t read_callback(mp_callback_t *slot)
+{
+ return *(volatile mp_callback_t *)slot;
+}
+
+static void store_callback(mp_callback_t *slot, mp_callback_t value)
+{
+ *(volatile mp_callback_t *)slot = value;
+}
+
+static int run_ap_work(mp_callback_t func, long expire_us)
+{
+ int i;
+ int cpus_accepted;
+ struct stopwatch sw;
+ int cur_cpu = cpu_index();
+
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK)) {
+ printk(BIOS_ERR, "APs already parked. PARALLEL_MP_AP_WORK not selected.\n");
+ return -1;
+ }
+
+ /* Signal to all the APs to run the func. */
+ for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) {
+ if (cur_cpu == i)
+ continue;
+ store_callback(&ap_callbacks[i], func);
+ }
+ mfence();
+
+ /* Wait for all the APs to signal back that call has been accepted. */
+ stopwatch_init_usecs_expire(&sw, expire_us);
+ cpus_accepted = 0;
+ while (!stopwatch_expired(&sw)) {
+ cpus_accepted = 0;
+ for (i = 0; i < ARRAY_SIZE(ap_callbacks); i++) {
+ if (cur_cpu == i)
+ continue;
+ if (read_callback(&ap_callbacks[i]) == NULL)
+ cpus_accepted++;
+ }
+ if (cpus_accepted == global_num_aps)
+ return 0;
+ }
+
+ printk(BIOS_ERR, "AP call expired. %d/%d CPUs accepted.\n",
+ cpus_accepted, global_num_aps);
+ return -1;
+}
+
+static void ap_wait_for_instruction(void)
+{
+ int cur_cpu = cpu_index();
+
+ if (!IS_ENABLED(CONFIG_PARALLEL_MP_AP_WORK))
+ return;
+
+ while (1) {
+ mp_callback_t func = read_callback(&ap_callbacks[cur_cpu]);
+
+ if (func == NULL) {
+ asm ("pause");
+ continue;
+ }
+
+ store_callback(&ap_callbacks[cur_cpu], NULL);
+ mfence();
+ func();
+ }
+}
+
+int mp_run_on_aps(void (*func)(void), long expire_us)
+{
+ return run_ap_work(func, expire_us);
+}
+
+int mp_park_aps(void)
+{
+ return mp_run_on_aps(park_this_cpu, 10 * USECS_PER_MSEC);
+}
+
static struct mp_flight_record mp_steps[] = {
/* Once the APs are up load the SMM handlers. */
MP_FR_BLOCK_APS(NULL, load_smm_handlers),
@@ -845,8 +933,8 @@ static struct mp_flight_record mp_steps[] = {
MP_FR_NOBLOCK_APS(trigger_smm_relocation, trigger_smm_relocation),
/* Initialize each CPU through the driver framework. */
MP_FR_BLOCK_APS(mp_initialize_cpu, mp_initialize_cpu),
- /* Wait for APs to finish everything else then let them park. */
- MP_FR_BLOCK_APS(NULL, NULL),
+ /* Wait for APs to finish then optionally start looking for work. */
+ MP_FR_BLOCK_APS(ap_wait_for_instruction, NULL),
};
static void fill_mp_state(struct mp_state *state, const struct mp_ops *ops)
diff --git a/src/include/cpu/x86/mp.h b/src/include/cpu/x86/mp.h
index 6d51d7b..5841a80 100644
--- a/src/include/cpu/x86/mp.h
+++ b/src/include/cpu/x86/mp.h
@@ -124,6 +124,21 @@ struct mp_ops {
*/
int mp_init_with_smm(struct bus *cpu_bus, const struct mp_ops *mp_ops);
+
+/*
+ * After APs are up and PARALLEL_MP_AP_WORK is enabled one can issue work
+ * to all the APs to perform. Currently the BSP is the only CPU that is allowed
+ * to issue work. i.e. the APs should not call any of these functions.
+ * All functions return < 0 on error, 0 on success.
+ */
+int mp_run_on_aps(void (*func)(void), long expire_us);
+
+/*
+ * Park all APs to prepare for OS boot. This is handled automatically
+ * by the coreboot infrastructure.
+ */
+int mp_park_aps(void);
+
/*
* SMM helpers to use with initializing CPUs.
*/
the following patch was just integrated into master:
commit d1e2edf7084f7d61b758a3e0d31cefffcb1cc9f6
Author: Nico Huber <nico.huber(a)secunet.com>
Date: Sun Oct 23 02:26:57 2016 +0200
libpayload: Add Cougar Point PCH's AHCI to whitelist
Change-Id: Ie8ca342a32323be4c26c236a5209052ec724317f
Signed-off-by: Nico Huber <nico.huber(a)secunet.com>
Reviewed-on: https://review.coreboot.org/17353
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Reviewed-by: Ronald G. Minnich <rminnich(a)gmail.com>
See https://review.coreboot.org/17353 for details.
-gerrit
the following patch was just integrated into master:
commit bd202bcdf35ee7fab0b17d9cc49a465a4a90e829
Author: Dennis Wassenberg <dennis.wassenberg(a)secunet.com>
Date: Wed Nov 2 08:12:52 2016 +0100
nb/intel/sandybridge: Lock PAVPC
This makes CHIPSEC happy. We don't enable PAVP, but it shouldn't hurt
to lock it nevertheless.
Change-Id: I9428f0b6e8868832eb79f7aea24cbc7961c2aa8f
Signed-off-by: Dennis Wassenberg <dennis.wassenberg(a)secunet.com>
Reviewed-on: https://review.coreboot.org/17352
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Reviewed-by: Ronald G. Minnich <rminnich(a)gmail.com>
See https://review.coreboot.org/17352 for details.
-gerrit