On 02/29/2016 04:42 AM, Aleksey Makarov wrote: > 'ARM Server Base Boot Requirements' [1] mentions DBG2 (Microsoft Debug > Port Table 2) [2] as a mandatory ACPI table that specifies debug ports. > > - Implement macros > > ACPI_DBG2_DECLARE(name, type, subtype, setup_fn, data_ptr) > > that defines a handler for the port of given type and subtype. > > - For each declared port that is also described in the ACPI DBG2 table > call the provided callback.
On 02/22/2016 06:43 AM, Aleksey Makarov wrote: > On 02/19/2016 08:20 PM, Christopher Covington wrote: >> Can the device specified in DBG2 be used for both earlycon and KGDB? If it >> can only be used for one, let's make sure the choice of earlycon vs KGDB is >> intentional rather than accidental. > > I just sent the DBG2 series. It enables an earlycon on DBG2 port with > an "earlycon=acpi_dbg2" option (we can discuss particular name). > If you need KGDB on that port just support it for that port in the kernel > (i. e. add a new instance of ACPI_DBG2_DECLARE() macros for that port, see > the patches) > and change the command line options. > I hope that is OK. We could continue this discussion in the DBG2 thread. This method will not work for kgdb, since kgdb doesn't actually implement the i/o but rather runs on top of a console. > [1] > http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0044a/index.html > [2] http://go.microsoft.com/fwlink/p/?LinkId=234837 > > Signed-off-by: Aleksey Makarov <[email protected]> > --- > drivers/acpi/Kconfig | 3 ++ > drivers/acpi/Makefile | 1 + > drivers/acpi/dbg2.c | 88 > +++++++++++++++++++++++++++++++++++++++ > include/asm-generic/vmlinux.lds.h | 1 + > include/linux/acpi_dbg2.h | 48 +++++++++++++++++++++ > 5 files changed, 141 insertions(+) > create mode 100644 drivers/acpi/dbg2.c > create mode 100644 include/linux/acpi_dbg2.h > > diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig > index 65fb483..660666e 100644 > --- a/drivers/acpi/Kconfig > +++ b/drivers/acpi/Kconfig > @@ -57,6 +57,9 @@ config ACPI_SYSTEM_POWER_STATES_SUPPORT > config ACPI_CCA_REQUIRED > bool > > +config ACPI_DBG2_TABLE > + bool > + > config ACPI_DEBUGGER > bool "AML debugger interface" > select ACPI_DEBUG > diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile > index 7395928..3b5f1ea 100644 > --- a/drivers/acpi/Makefile > +++ b/drivers/acpi/Makefile > @@ -83,6 +83,7 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o > obj-$(CONFIG_ACPI_BGRT) += bgrt.o > obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o > obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o > +obj-$(CONFIG_ACPI_DBG2_TABLE) += dbg2.o > > # processor has its own "processor." module_param namespace > processor-y := processor_driver.o > diff --git a/drivers/acpi/dbg2.c b/drivers/acpi/dbg2.c > new file mode 100644 > index 0000000..0f0f6ca > --- /dev/null > +++ b/drivers/acpi/dbg2.c > @@ -0,0 +1,88 @@ > +/* > + * Copyright (c) 2012, Intel Corporation > + * Copyright (c) 2015, 2016 Linaro Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + */ > + > +#define pr_fmt(fmt) "ACPI: DBG2: " fmt > + > +#include <linux/acpi_dbg2.h> > +#include <linux/acpi.h> > +#include <linux/kernel.h> > + > +static const char * __init type2string(u16 type) > +{ > + switch (type) { > + case ACPI_DBG2_SERIAL_PORT: > + return "SERIAL"; > + case ACPI_DBG2_1394_PORT: > + return "1394"; > + case ACPI_DBG2_USB_PORT: > + return "USB"; > + case ACPI_DBG2_NET_PORT: > + return "NET"; > + default: > + return "?"; > + } > +} > + > +static const char * __init subtype2string(u16 subtype) > +{ > + switch (subtype) { > + case ACPI_DBG2_16550_COMPATIBLE: > + return "16550_COMPATIBLE"; > + case ACPI_DBG2_16550_SUBSET: > + return "16550_SUBSET"; > + case ACPI_DBG2_ARM_PL011: > + return "ARM_PL011"; > + case ACPI_DBG2_ARM_SBSA_32BIT: > + return "ARM_SBSA_32BIT"; > + case ACPI_DBG2_ARM_SBSA_GENERIC: > + return "ARM_SBSA_GENERIC"; > + case ACPI_DBG2_ARM_DCC: > + return "ARM_DCC"; > + case ACPI_DBG2_BCM2835: > + return "BCM2835"; > + default: > + return "?"; > + } > +} > + > +int __init acpi_dbg2_setup(struct acpi_table_header *table, const void *data) > +{ > + struct acpi_table_dbg2 *dbg2 = (struct acpi_table_dbg2 *)table; > + struct acpi_dbg2_data *dbg2_data = (struct acpi_dbg2_data *)data; > + struct acpi_dbg2_device *dbg2_device, *dbg2_end; > + int i; > + > + dbg2_device = ACPI_ADD_PTR(struct acpi_dbg2_device, dbg2, > + dbg2->info_offset); > + dbg2_end = ACPI_ADD_PTR(struct acpi_dbg2_device, dbg2, table->length); > + > + for (i = 0; i < dbg2->info_count; i++) { > + if (dbg2_device + 1 > dbg2_end) { > + pr_err("device pointer overflows, bad table\n"); > + return 0; > + } > + > + if (dbg2_device->port_type == dbg2_data->port_type && > + dbg2_device->port_subtype == dbg2_data->port_subtype) { > + if (dbg2_device->port_type == ACPI_DBG2_SERIAL_PORT) > + pr_info("debug port: SERIAL; subtype: %s\n", > + subtype2string(dbg2_device->port_subtype)); > + else > + pr_info("debug port: %s\n", > + type2string(dbg2_device->port_type)); > + dbg2_data->setup(dbg2_device, dbg2_data->data); > + } > + > + dbg2_device = ACPI_ADD_PTR(struct acpi_dbg2_device, dbg2_device, > + dbg2_device->length); > + } > + > + return 0; > +} > diff --git a/include/asm-generic/vmlinux.lds.h > b/include/asm-generic/vmlinux.lds.h > index 8f5a12a..8cc49ba 100644 > --- a/include/asm-generic/vmlinux.lds.h > +++ b/include/asm-generic/vmlinux.lds.h > @@ -526,6 +526,7 @@ > IRQCHIP_OF_MATCH_TABLE() \ > ACPI_PROBE_TABLE(irqchip) \ > ACPI_PROBE_TABLE(clksrc) \ > + ACPI_PROBE_TABLE(dbg2) \ > EARLYCON_TABLE() > > #define INIT_TEXT \ > diff --git a/include/linux/acpi_dbg2.h b/include/linux/acpi_dbg2.h > new file mode 100644 > index 0000000..125ae7e > --- /dev/null > +++ b/include/linux/acpi_dbg2.h > @@ -0,0 +1,48 @@ > +#ifndef _ACPI_DBG2_H_ > +#define _ACPI_DBG2_H_ > + > +#ifdef CONFIG_ACPI_DBG2_TABLE > + > +#include <linux/kernel.h> > + > +struct acpi_dbg2_device; > +struct acpi_table_header; > + > +struct acpi_dbg2_data { > + u16 port_type; > + u16 port_subtype; > + int (*setup)(struct acpi_dbg2_device *, void *); > + void *data; > +}; > + > +int acpi_dbg2_setup(struct acpi_table_header *header, const void *data); > + > +/** > + * ACPI_DBG2_DECLARE() - Define handler for ACPI DBG2 port > + * @name: Identifier to compose name of table data > + * @type: Type of the port > + * @subtype: Subtype of the port > + * @setup_fn: Function to be called to setup the port > + * (of type int (*)(struct acpi_dbg2_device *, void *);) > + * @data_ptr: Sideband data provided back to the driver > + */ > +#define ACPI_DBG2_DECLARE(name, type, subtype, setup_fn, data_ptr) \ > + static const struct acpi_dbg2_data \ > + __acpi_dbg2_data_##name __used = { \ > + .port_type = type, \ > + .port_subtype = subtype, \ > + .setup = setup_fn, \ > + .data = data_ptr, \ > + }; \ > + ACPI_DECLARE_PROBE_ENTRY(dbg2, name, ACPI_SIG_DBG2, \ > + acpi_dbg2_setup, &__acpi_dbg2_data_##name) > + > +#else > + > +#define ACPI_DBG2_DECLARE(name, type, subtype, setup_fn, data_ptr) \ > + static const void *__acpi_dbg_data_##name[] \ > + __used __initdata = { (void *)setup_fn, (void *)data_ptr } > + > +#endif > + > +#endif >

