[084/108] x86: acpi: Support generation of the DBG2 table

Message ID 20200126220508.84.I8f7a76fcf50225b3e105c3230c1c5cd66e76967b@changeid
State New
Headers show
Series
  • RFC: dm: Add programatic generation of ACPI tables
Related show

Commit Message

Simon Glass Jan. 27, 2020, 5:06 a.m.
Add an implementation of the DBG2 (Debug Port Table 2) ACPI table.
Adjust one of the header includes to be in the correct order, before
adding more.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 arch/x86/lib/acpi_table.c | 112 +++++++++++++++++++++++++++++++++++++-
 include/acpi_table.h      |  31 +++++++++++
 2 files changed, 142 insertions(+), 1 deletion(-)

Comments

Leif Lindholm Jan. 27, 2020, 12:34 p.m. | #1
Hi Simon,

A portion of this set is very much not x86-specific. (more below)

On Sun, Jan 26, 2020 at 22:06:31 -0700, Simon Glass wrote:
> Add an implementation of the DBG2 (Debug Port Table 2) ACPI table.
> Adjust one of the header includes to be in the correct order, before
> adding more.
> 
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
> 
>  arch/x86/lib/acpi_table.c | 112 +++++++++++++++++++++++++++++++++++++-
>  include/acpi_table.h      |  31 +++++++++++
>  2 files changed, 142 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index a810b12cfe..f12344de50 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -8,6 +8,8 @@
>  
>  #include <common.h>
>  #include <acpigen.h>
> +#include <acpi_device.h>
> +#include <acpi_table.h>
>  #include <cpu.h>
>  #include <dm.h>
>  #include <dm/uclass-internal.h>
> @@ -15,7 +17,6 @@
>  #include <serial.h>
>  #include <version.h>
>  #include <asm/acpi/global_nvs.h>
> -#include <acpi_table.h>
>  #include <asm/ioapic.h>
>  #include <asm/lapic.h>
>  #include <asm/mpspec.h>
> @@ -52,6 +53,50 @@ int acpi_write_hpet(struct acpi_ctx *ctx, const struct udevice *dev)
>  	return 0;
>  }
>  
> +int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
> +			     uint access_size)
> +{

So, this one could possibly be argued either way (it is certainly not
fully generic).

> +	struct acpi_dbg2_header *dbg2 = ctx->current;
> +	char path[ACPI_PATH_MAX];
> +	struct acpi_gen_regaddr address;
> +	phys_addr_t addr;
> +	int ret;
> +
> +	if (!dev) {
> +		log_err("Device not found\n");
> +		return -ENODEV;
> +	}
> +	if (!device_active(dev)) {
> +		log_info("Device not enabled\n");
> +		return -EACCES;
> +	}
> +	/*
> +	 * PCI devices don't remember their resource allocation information in
> +	 * U-Boot at present. We assume that MMIO is used for the UART and that
> +	 * the address space is 32 bytes: ns16550 uses 8 registers of up to
> +	 * 32-bits each. This is only for debugging so it is not a big deal.
> +	 */
> +	addr = dm_pci_read_bar32(dev, 0);
> +	printf("UART addr %lx\n", (ulong)addr);
> +
> +	memset(&address, '\0', sizeof(address));
> +	address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
> +	address.addrl = (uint32_t)addr;
> +	address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
> +	address.access_size = access_size;
> +
> +	ret = acpi_device_path(dev, path, sizeof(path));
> +	if (ret)
> +		return log_msg_ret("path", ret);
> +	acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
> +			 ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
> +
> +	acpi_inc_align(ctx, dbg2->header.length);
> +	acpi_add_table(ctx, dbg2);
> +
> +	return 0;
> +}
> +
>  static void acpi_create_facs(struct acpi_facs *facs)
>  {
>  	memset((void *)facs, 0, sizeof(struct acpi_facs));
> @@ -439,6 +484,71 @@ int acpi_create_hpet(struct acpi_hpet *hpet)
>  	return 0;
>  }
>  
> +void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
> +		      int port_type, int port_subtype,
> +		      struct acpi_gen_regaddr *address, u32 address_size,
> +		      const char *device_path)

But this one would be usable by any of the architectures supported by
ACPI. Could the acpi_create_* functions be moved somewhere
non-arch-specific, like a new lib/acpi?

/
    Leif

> +{
> +	uintptr_t current;
> +	struct acpi_dbg2_device *device;
> +	u32 *dbg2_addr_size;
> +	struct acpi_table_header *header;
> +	size_t path_len;
> +	const char *path;
> +	char *namespace;
> +
> +	/* Fill out header fields. */
> +	current = (uintptr_t)dbg2;
> +	memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
> +	header = &dbg2->header;
> +
> +	header->revision = acpi_get_table_revision(ACPITAB_DBG2);
> +	acpi_fill_header(header, "DBG2");
> +	header->aslc_revision = ASL_REVISION;
> +
> +	/* One debug device defined */
> +	dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
> +	dbg2->devices_count = 1;
> +	current += sizeof(struct acpi_dbg2_header);
> +
> +	/* Device comes after the header */
> +	device = (struct acpi_dbg2_device *)current;
> +	memset(device, 0, sizeof(struct acpi_dbg2_device));
> +	current += sizeof(struct acpi_dbg2_device);
> +
> +	device->revision = 0;
> +	device->address_count = 1;
> +	device->port_type = port_type;
> +	device->port_subtype = port_subtype;
> +
> +	/* Base Address comes after device structure */
> +	memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
> +	device->base_address_offset = current - (uintptr_t)device;
> +	current += sizeof(struct acpi_gen_regaddr);
> +
> +	/* Address Size comes after address structure */
> +	dbg2_addr_size = (uint32_t *)current;
> +	device->address_size_offset = current - (uintptr_t)device;
> +	*dbg2_addr_size = address_size;
> +	current += sizeof(uint32_t);
> +
> +	/* Namespace string comes last, use '.' if not provided */
> +	path = device_path ? : ".";
> +	/* Namespace string length includes NULL terminator */
> +	path_len = strlen(path) + 1;
> +	namespace = (char *)current;
> +	device->namespace_string_length = path_len;
> +	device->namespace_string_offset = current - (uintptr_t)device;
> +	strncpy(namespace, path, path_len);
> +	current += path_len;
> +
> +	/* Update structure lengths and checksum */
> +	device->length = current - (uintptr_t)device;
> +	header->length = current - (uintptr_t)dbg2;
> +	header->checksum = table_compute_checksum((uint8_t *)dbg2,
> +						  header->length);
> +}
> +
>  /*
>   * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
>   */
> diff --git a/include/acpi_table.h b/include/acpi_table.h
> index 1d78665abe..6d91ae85e2 100644
> --- a/include/acpi_table.h
> +++ b/include/acpi_table.h
> @@ -489,6 +489,29 @@ struct acpi_dmar {
>  
>  #define ACPI_DBG2_UNKNOWN		0x00FF
>  
> +/* DBG2: Microsoft Debug Port Table 2 header */
> +struct __packed acpi_dbg2_header {
> +	struct acpi_table_header header;
> +	u32 devices_offset;
> +	u32 devices_count;
> +};
> +
> +/* DBG2: Microsoft Debug Port Table 2 device entry */
> +struct __packed acpi_dbg2_device {
> +	u8  revision;
> +	u16 length;
> +	u8 address_count;
> +	u16 namespace_string_length;
> +	u16 namespace_string_offset;
> +	u16 oem_data_length;
> +	u16 oem_data_offset;
> +	u16 port_type;
> +	u16 port_subtype;
> +	u8  reserved[2];
> +	u16 base_address_offset;
> +	u16 address_size_offset;
> +};
> +
>  /* SPCR (Serial Port Console Redirection table) */
>  struct __packed acpi_spcr {
>  	struct acpi_table_header header;
> @@ -564,6 +587,11 @@ int acpi_get_table_revision(enum acpi_tables table);
>   */
>  int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
>  
> +void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
> +		      int port_type, int port_subtype,
> +		      struct acpi_gen_regaddr *address, uint32_t address_size,
> +		      const char *device_path);
> +
>  /**
>   * acpi_fill_header() - Set up a new table header
>   *
> @@ -631,6 +659,9 @@ int acpi_write_hpet(struct acpi_ctx *ctx, const struct udevice *dev);
>  
>  int acpi_create_hpet(struct acpi_hpet *hpet);
>  
> +int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
> +			     uint access_size);
> +
>  #endif /* !__ACPI__*/
>  
>  #include <asm/acpi_table.h>
> -- 
> 2.25.0.341.g760bfbb309-goog
>
Simon Glass March 14, 2020, 8:35 p.m. | #2
Hi Leif,

On Mon, 27 Jan 2020 at 05:34, Leif Lindholm <leif at nuviainc.com> wrote:
>
> Hi Simon,
>
> A portion of this set is very much not x86-specific. (more below)
>
> On Sun, Jan 26, 2020 at 22:06:31 -0700, Simon Glass wrote:
> > Add an implementation of the DBG2 (Debug Port Table 2) ACPI table.
> > Adjust one of the header includes to be in the correct order, before
> > adding more.
> >
> > Signed-off-by: Simon Glass <sjg at chromium.org>
> > ---
> >
> >  arch/x86/lib/acpi_table.c | 112 +++++++++++++++++++++++++++++++++++++-
> >  include/acpi_table.h      |  31 +++++++++++
> >  2 files changed, 142 insertions(+), 1 deletion(-)
> >

[..]

> > +void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
> > +                   int port_type, int port_subtype,
> > +                   struct acpi_gen_regaddr *address, u32 address_size,
> > +                   const char *device_path)
>
> But this one would be usable by any of the architectures supported by
> ACPI. Could the acpi_create_* functions be moved somewhere
> non-arch-specific, like a new lib/acpi?
>
> /
>     Leif

OK I'll move this one. In general I don't know which ones are generic
and I'd rather keep them x86-specific unless we know.

Regards,
Simon

Patch

diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index a810b12cfe..f12344de50 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -8,6 +8,8 @@ 
 
 #include <common.h>
 #include <acpigen.h>
+#include <acpi_device.h>
+#include <acpi_table.h>
 #include <cpu.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
@@ -15,7 +17,6 @@ 
 #include <serial.h>
 #include <version.h>
 #include <asm/acpi/global_nvs.h>
-#include <acpi_table.h>
 #include <asm/ioapic.h>
 #include <asm/lapic.h>
 #include <asm/mpspec.h>
@@ -52,6 +53,50 @@  int acpi_write_hpet(struct acpi_ctx *ctx, const struct udevice *dev)
 	return 0;
 }
 
+int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
+			     uint access_size)
+{
+	struct acpi_dbg2_header *dbg2 = ctx->current;
+	char path[ACPI_PATH_MAX];
+	struct acpi_gen_regaddr address;
+	phys_addr_t addr;
+	int ret;
+
+	if (!dev) {
+		log_err("Device not found\n");
+		return -ENODEV;
+	}
+	if (!device_active(dev)) {
+		log_info("Device not enabled\n");
+		return -EACCES;
+	}
+	/*
+	 * PCI devices don't remember their resource allocation information in
+	 * U-Boot at present. We assume that MMIO is used for the UART and that
+	 * the address space is 32 bytes: ns16550 uses 8 registers of up to
+	 * 32-bits each. This is only for debugging so it is not a big deal.
+	 */
+	addr = dm_pci_read_bar32(dev, 0);
+	printf("UART addr %lx\n", (ulong)addr);
+
+	memset(&address, '\0', sizeof(address));
+	address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
+	address.addrl = (uint32_t)addr;
+	address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
+	address.access_size = access_size;
+
+	ret = acpi_device_path(dev, path, sizeof(path));
+	if (ret)
+		return log_msg_ret("path", ret);
+	acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
+			 ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
+
+	acpi_inc_align(ctx, dbg2->header.length);
+	acpi_add_table(ctx, dbg2);
+
+	return 0;
+}
+
 static void acpi_create_facs(struct acpi_facs *facs)
 {
 	memset((void *)facs, 0, sizeof(struct acpi_facs));
@@ -439,6 +484,71 @@  int acpi_create_hpet(struct acpi_hpet *hpet)
 	return 0;
 }
 
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+		      int port_type, int port_subtype,
+		      struct acpi_gen_regaddr *address, u32 address_size,
+		      const char *device_path)
+{
+	uintptr_t current;
+	struct acpi_dbg2_device *device;
+	u32 *dbg2_addr_size;
+	struct acpi_table_header *header;
+	size_t path_len;
+	const char *path;
+	char *namespace;
+
+	/* Fill out header fields. */
+	current = (uintptr_t)dbg2;
+	memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
+	header = &dbg2->header;
+
+	header->revision = acpi_get_table_revision(ACPITAB_DBG2);
+	acpi_fill_header(header, "DBG2");
+	header->aslc_revision = ASL_REVISION;
+
+	/* One debug device defined */
+	dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
+	dbg2->devices_count = 1;
+	current += sizeof(struct acpi_dbg2_header);
+
+	/* Device comes after the header */
+	device = (struct acpi_dbg2_device *)current;
+	memset(device, 0, sizeof(struct acpi_dbg2_device));
+	current += sizeof(struct acpi_dbg2_device);
+
+	device->revision = 0;
+	device->address_count = 1;
+	device->port_type = port_type;
+	device->port_subtype = port_subtype;
+
+	/* Base Address comes after device structure */
+	memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
+	device->base_address_offset = current - (uintptr_t)device;
+	current += sizeof(struct acpi_gen_regaddr);
+
+	/* Address Size comes after address structure */
+	dbg2_addr_size = (uint32_t *)current;
+	device->address_size_offset = current - (uintptr_t)device;
+	*dbg2_addr_size = address_size;
+	current += sizeof(uint32_t);
+
+	/* Namespace string comes last, use '.' if not provided */
+	path = device_path ? : ".";
+	/* Namespace string length includes NULL terminator */
+	path_len = strlen(path) + 1;
+	namespace = (char *)current;
+	device->namespace_string_length = path_len;
+	device->namespace_string_offset = current - (uintptr_t)device;
+	strncpy(namespace, path, path_len);
+	current += path_len;
+
+	/* Update structure lengths and checksum */
+	device->length = current - (uintptr_t)device;
+	header->length = current - (uintptr_t)dbg2;
+	header->checksum = table_compute_checksum((uint8_t *)dbg2,
+						  header->length);
+}
+
 /*
  * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
  */
diff --git a/include/acpi_table.h b/include/acpi_table.h
index 1d78665abe..6d91ae85e2 100644
--- a/include/acpi_table.h
+++ b/include/acpi_table.h
@@ -489,6 +489,29 @@  struct acpi_dmar {
 
 #define ACPI_DBG2_UNKNOWN		0x00FF
 
+/* DBG2: Microsoft Debug Port Table 2 header */
+struct __packed acpi_dbg2_header {
+	struct acpi_table_header header;
+	u32 devices_offset;
+	u32 devices_count;
+};
+
+/* DBG2: Microsoft Debug Port Table 2 device entry */
+struct __packed acpi_dbg2_device {
+	u8  revision;
+	u16 length;
+	u8 address_count;
+	u16 namespace_string_length;
+	u16 namespace_string_offset;
+	u16 oem_data_length;
+	u16 oem_data_offset;
+	u16 port_type;
+	u16 port_subtype;
+	u8  reserved[2];
+	u16 base_address_offset;
+	u16 address_size_offset;
+};
+
 /* SPCR (Serial Port Console Redirection table) */
 struct __packed acpi_spcr {
 	struct acpi_table_header header;
@@ -564,6 +587,11 @@  int acpi_get_table_revision(enum acpi_tables table);
  */
 int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags);
 
+void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
+		      int port_type, int port_subtype,
+		      struct acpi_gen_regaddr *address, uint32_t address_size,
+		      const char *device_path);
+
 /**
  * acpi_fill_header() - Set up a new table header
  *
@@ -631,6 +659,9 @@  int acpi_write_hpet(struct acpi_ctx *ctx, const struct udevice *dev);
 
 int acpi_create_hpet(struct acpi_hpet *hpet);
 
+int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
+			     uint access_size);
+
 #endif /* !__ACPI__*/
 
 #include <asm/acpi_table.h>