'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.

[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 <aleksey.maka...@linaro.org>
---
 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
-- 
2.7.1

Reply via email to