diff mbox series

[U-Boot,v1,2/2] WIP: x86: acpi: Generate SPCR table

Message ID 20180922130505.77474-3-andriy.shevchenko@linux.intel.com
State Superseded
Delegated to: Bin Meng
Headers show
Series ACPI: Generate SPCR table | expand

Commit Message

Andy Shevchenko Sept. 22, 2018, 1:05 p.m. UTC
TBD

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 arch/x86/include/asm/acpi_table.h | 25 ++++++++++
 arch/x86/lib/acpi_table.c         | 82 +++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

Comments

Patrice CHOTARD Sept. 24, 2018, 7:44 a.m. UTC | #1
On 09/22/2018 03:05 PM, Andy Shevchenko wrote:
> TBD

Same remark as Patch 1

> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  arch/x86/include/asm/acpi_table.h | 25 ++++++++++
>  arch/x86/lib/acpi_table.c         | 82 +++++++++++++++++++++++++++++++
>  2 files changed, 107 insertions(+)
> 
> diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
> index 95fae036f6..27435871b9 100644
> --- a/arch/x86/include/asm/acpi_table.h
> +++ b/arch/x86/include/asm/acpi_table.h
> @@ -303,6 +303,31 @@ struct acpi_mcfg_mmconfig {
>  /* ACPI global NVS structure */
>  struct acpi_global_nvs;
>  
> +/* SPCR (Serial Port Console Redirection table) */
> +struct __packed acpi_spcr {
> +	struct acpi_table_header header;	/* Common ACPI table header */
> +	u8 interface_type;	/* 0=full 16550, 1=subset of 16550 */
> +	u8 reserved[3];
> +	struct acpi_gen_regaddr serial_port;	/* The base address of the Serial Port register set */
> +	u8 interrupt_type;
> +	u8 pc_interrupt;
> +	u32 interrupt;		/* Global system interrupt */
> +	u8 baud_rate;
> +	u8 parity;
> +	u8 stop_bits;
> +	u8 flow_control;
> +	u8 terminal_type;
> +	u8 reserved1;
> +	u16 pci_device_id;	/* Must be 0xffff if not PCI device */
> +	u16 pci_vendor_id;	/* Must be 0xffff if not PCI device */
> +	u8 pci_bus;
> +	u8 pci_device;
> +	u8 pci_function;
> +	u32 pci_flags;
> +	u8 pci_segment;
> +	u32 reserved2;
> +};
> +
>  /* These can be used by the target port */
>  
>  void acpi_fill_header(struct acpi_table_header *header, char *signature);
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index c6b2026613..551a78b11a 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -12,6 +12,7 @@
>  #include <cpu.h>
>  #include <dm.h>
>  #include <dm/uclass-internal.h>
> +#include <serial.h>
>  #include <version.h>
>  #include <asm/acpi/global_nvs.h>
>  #include <asm/acpi_table.h>
> @@ -338,6 +339,79 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
>  	header->checksum = table_compute_checksum((void *)mcfg, header->length);
>  }
>  
> +static void acpi_create_spcr(struct acpi_spcr *spcr)
> +{
> +	struct acpi_table_header *header = &(spcr->header);
> +	struct serial_device_info info = {0};
> +	int access_size;
> +	int ret;
> +
> +	/* Fill out header fields */
> +	acpi_fill_header(header, "SPCR");
> +	header->length = sizeof(struct acpi_spcr);
> +	header->revision = 2;
> +
> +	ret = serial_getinfo(&info);
> +	if (ret)
> +		debug("Can't get information of serial device: %d\n", ret);
> +
> +	/* Encode baud rate */
> +	switch (info.baudrate) {
> +	case 9600:
> +		spcr->baud_rate = 3;
> +		break;
> +	case 19200:
> +		spcr->baud_rate = 4;
> +		break;
> +	case 57600:
> +		spcr->baud_rate = 6;
> +		break;
> +	case 115200:
> +		spcr->baud_rate = 7;
> +		break;
> +	default:
> +		spcr->baud_rate = 0;
> +		break;
> +	}
> +
> +	/* Encode register access size */
> +	switch (info.reg_shift) {
> +	case 0:
> +		access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
> +		break;
> +	case 1:
> +		access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
> +		break;
> +	case 2:
> +		access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
> +		break;
> +	case 3:
> +		access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
> +		break;
> +	default:
> +		access_size = ACPI_ACCESS_SIZE_UNDEFINED;
> +		break;
> +	}
> +
> +	spcr->serial_port.space_id = ACPI_ADDRESS_SPACE_MEMORY;
> +	spcr->serial_port.bit_width = info.reg_width;
> +	spcr->serial_port.bit_offset = info.reg_offset;
> +	spcr->serial_port.access_size = access_size;
> +	spcr->serial_port.addrl = info.addr >> 0;
> +	spcr->serial_port.addrh = info.addr >> 32;
> +
> +	/* Hard coded values for now */
> +	spcr->parity = 0;
> +	spcr->stop_bits = 1;
> +
> +	/* No PCI devices for now */
> +	spcr->pci_device_id = 0xffff;
> +	spcr->pci_vendor_id = 0xffff;
> +
> +	/* Fix checksum */
> +	header->checksum = table_compute_checksum((void *)spcr, header->length);
> +}
> +
>  /*
>   * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
>   */
> @@ -352,6 +426,7 @@ ulong write_acpi_tables(ulong start)
>  	struct acpi_fadt *fadt;
>  	struct acpi_mcfg *mcfg;
>  	struct acpi_madt *madt;
> +	struct acpi_spcr *spcr;
>  	int i;
>  
>  	current = start;
> @@ -440,6 +515,13 @@ ulong write_acpi_tables(ulong start)
>  	acpi_add_table(rsdp, mcfg);
>  	current = ALIGN(current, 16);
>  
> +	debug("ACPI:    * SPCR\n");
> +	spcr = (struct acpi_spcr *)current;
> +	acpi_create_spcr(spcr);
> +	current += spcr->header.length;
> +	acpi_add_table(rsdp, spcr);
> +	current = ALIGN(current, 16);
> +
>  	debug("current = %x\n", current);
>  
>  	acpi_rsdp_addr = (unsigned long)rsdp;
>
Bin Meng Sept. 25, 2018, 2:27 a.m. UTC | #2
Hi Andy,

On Sat, Sep 22, 2018 at 9:05 PM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> TBD
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  arch/x86/include/asm/acpi_table.h | 25 ++++++++++
>  arch/x86/lib/acpi_table.c         | 82 +++++++++++++++++++++++++++++++
>  2 files changed, 107 insertions(+)
>
> diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
> index 95fae036f6..27435871b9 100644
> --- a/arch/x86/include/asm/acpi_table.h
> +++ b/arch/x86/include/asm/acpi_table.h
> @@ -303,6 +303,31 @@ struct acpi_mcfg_mmconfig {
>  /* ACPI global NVS structure */
>  struct acpi_global_nvs;
>
> +/* SPCR (Serial Port Console Redirection table) */
> +struct __packed acpi_spcr {
> +       struct acpi_table_header header;        /* Common ACPI table header */
> +       u8 interface_type;      /* 0=full 16550, 1=subset of 16550 */
> +       u8 reserved[3];
> +       struct acpi_gen_regaddr serial_port;    /* The base address of the Serial Port register set */
> +       u8 interrupt_type;
> +       u8 pc_interrupt;
> +       u32 interrupt;          /* Global system interrupt */
> +       u8 baud_rate;
> +       u8 parity;
> +       u8 stop_bits;
> +       u8 flow_control;
> +       u8 terminal_type;
> +       u8 reserved1;
> +       u16 pci_device_id;      /* Must be 0xffff if not PCI device */
> +       u16 pci_vendor_id;      /* Must be 0xffff if not PCI device */
> +       u8 pci_bus;
> +       u8 pci_device;
> +       u8 pci_function;
> +       u32 pci_flags;
> +       u8 pci_segment;
> +       u32 reserved2;
> +};
> +
>  /* These can be used by the target port */
>
>  void acpi_fill_header(struct acpi_table_header *header, char *signature);
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index c6b2026613..551a78b11a 100644
> --- a/arch/x86/lib/acpi_table.c
> +++ b/arch/x86/lib/acpi_table.c
> @@ -12,6 +12,7 @@
>  #include <cpu.h>
>  #include <dm.h>
>  #include <dm/uclass-internal.h>
> +#include <serial.h>
>  #include <version.h>
>  #include <asm/acpi/global_nvs.h>
>  #include <asm/acpi_table.h>
> @@ -338,6 +339,79 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
>         header->checksum = table_compute_checksum((void *)mcfg, header->length);
>  }
>
> +static void acpi_create_spcr(struct acpi_spcr *spcr)
> +{
> +       struct acpi_table_header *header = &(spcr->header);
> +       struct serial_device_info info = {0};
> +       int access_size;
> +       int ret;
> +
> +       /* Fill out header fields */
> +       acpi_fill_header(header, "SPCR");
> +       header->length = sizeof(struct acpi_spcr);
> +       header->revision = 2;
> +
> +       ret = serial_getinfo(&info);
> +       if (ret)
> +               debug("Can't get information of serial device: %d\n", ret);
> +
> +       /* Encode baud rate */
> +       switch (info.baudrate) {
> +       case 9600:
> +               spcr->baud_rate = 3;
> +               break;
> +       case 19200:
> +               spcr->baud_rate = 4;
> +               break;
> +       case 57600:
> +               spcr->baud_rate = 6;
> +               break;
> +       case 115200:
> +               spcr->baud_rate = 7;
> +               break;
> +       default:
> +               spcr->baud_rate = 0;
> +               break;
> +       }
> +
> +       /* Encode register access size */
> +       switch (info.reg_shift) {
> +       case 0:
> +               access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
> +               break;
> +       case 1:
> +               access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
> +               break;
> +       case 2:
> +               access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
> +               break;
> +       case 3:
> +               access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
> +               break;
> +       default:
> +               access_size = ACPI_ACCESS_SIZE_UNDEFINED;
> +               break;
> +       }
> +
> +       spcr->serial_port.space_id = ACPI_ADDRESS_SPACE_MEMORY;
> +       spcr->serial_port.bit_width = info.reg_width;
> +       spcr->serial_port.bit_offset = info.reg_offset;
> +       spcr->serial_port.access_size = access_size;
> +       spcr->serial_port.addrl = info.addr >> 0;
> +       spcr->serial_port.addrh = info.addr >> 32;
> +
> +       /* Hard coded values for now */
> +       spcr->parity = 0;
> +       spcr->stop_bits = 1;
> +
> +       /* No PCI devices for now */
> +       spcr->pci_device_id = 0xffff;
> +       spcr->pci_vendor_id = 0xffff;
> +

I see not every member of 'struct __packed acpi_spcr' is populated.
Are they not used by kernel? If kernel does not use it, it is used by
Windows?

> +       /* Fix checksum */
> +       header->checksum = table_compute_checksum((void *)spcr, header->length);
> +}
> +
>  /*
>   * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
>   */
> @@ -352,6 +426,7 @@ ulong write_acpi_tables(ulong start)
>         struct acpi_fadt *fadt;
>         struct acpi_mcfg *mcfg;
>         struct acpi_madt *madt;
> +       struct acpi_spcr *spcr;
>         int i;
>
>         current = start;
> @@ -440,6 +515,13 @@ ulong write_acpi_tables(ulong start)
>         acpi_add_table(rsdp, mcfg);
>         current = ALIGN(current, 16);
>
> +       debug("ACPI:    * SPCR\n");
> +       spcr = (struct acpi_spcr *)current;
> +       acpi_create_spcr(spcr);
> +       current += spcr->header.length;
> +       acpi_add_table(rsdp, spcr);
> +       current = ALIGN(current, 16);
> +
>         debug("current = %x\n", current);
>
>         acpi_rsdp_addr = (unsigned long)rsdp;
> --

Regards,
Bin
Andy Shevchenko Nov. 15, 2018, 4:06 p.m. UTC | #3
On Tue, Sep 25, 2018 at 10:27:33AM +0800, Bin Meng wrote:
> On Sat, Sep 22, 2018 at 9:05 PM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:

> > +/* SPCR (Serial Port Console Redirection table) */
> > +struct __packed acpi_spcr {
> > +       struct acpi_table_header header;        /* Common ACPI table header */
> > +       u8 interface_type;      /* 0=full 16550, 1=subset of 16550 */
> > +       u8 reserved[3];
> > +       struct acpi_gen_regaddr serial_port;    /* The base address of the Serial Port register set */
> > +       u8 interrupt_type;
> > +       u8 pc_interrupt;
> > +       u32 interrupt;          /* Global system interrupt */
> > +       u8 baud_rate;
> > +       u8 parity;
> > +       u8 stop_bits;
> > +       u8 flow_control;
> > +       u8 terminal_type;
> > +       u8 reserved1;
> > +       u16 pci_device_id;      /* Must be 0xffff if not PCI device */
> > +       u16 pci_vendor_id;      /* Must be 0xffff if not PCI device */
> > +       u8 pci_bus;
> > +       u8 pci_device;
> > +       u8 pci_function;
> > +       u32 pci_flags;
> > +       u8 pci_segment;
> > +       u32 reserved2;
> > +};

> I see not every member of 'struct __packed acpi_spcr' is populated.
> Are they not used by kernel? If kernel does not use it, it is used by
> Windows?

No idea about Windows, but there are two statements:
- *not all* should be filled, otherwise it would be contradictory
  (PCI vs. non-PCI device, for example)
- Linux doesn't use all of them, indeed
diff mbox series

Patch

diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 95fae036f6..27435871b9 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -303,6 +303,31 @@  struct acpi_mcfg_mmconfig {
 /* ACPI global NVS structure */
 struct acpi_global_nvs;
 
+/* SPCR (Serial Port Console Redirection table) */
+struct __packed acpi_spcr {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u8 interface_type;	/* 0=full 16550, 1=subset of 16550 */
+	u8 reserved[3];
+	struct acpi_gen_regaddr serial_port;	/* The base address of the Serial Port register set */
+	u8 interrupt_type;
+	u8 pc_interrupt;
+	u32 interrupt;		/* Global system interrupt */
+	u8 baud_rate;
+	u8 parity;
+	u8 stop_bits;
+	u8 flow_control;
+	u8 terminal_type;
+	u8 reserved1;
+	u16 pci_device_id;	/* Must be 0xffff if not PCI device */
+	u16 pci_vendor_id;	/* Must be 0xffff if not PCI device */
+	u8 pci_bus;
+	u8 pci_device;
+	u8 pci_function;
+	u32 pci_flags;
+	u8 pci_segment;
+	u32 reserved2;
+};
+
 /* These can be used by the target port */
 
 void acpi_fill_header(struct acpi_table_header *header, char *signature);
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index c6b2026613..551a78b11a 100644
--- a/arch/x86/lib/acpi_table.c
+++ b/arch/x86/lib/acpi_table.c
@@ -12,6 +12,7 @@ 
 #include <cpu.h>
 #include <dm.h>
 #include <dm/uclass-internal.h>
+#include <serial.h>
 #include <version.h>
 #include <asm/acpi/global_nvs.h>
 #include <asm/acpi_table.h>
@@ -338,6 +339,79 @@  static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
 	header->checksum = table_compute_checksum((void *)mcfg, header->length);
 }
 
+static void acpi_create_spcr(struct acpi_spcr *spcr)
+{
+	struct acpi_table_header *header = &(spcr->header);
+	struct serial_device_info info = {0};
+	int access_size;
+	int ret;
+
+	/* Fill out header fields */
+	acpi_fill_header(header, "SPCR");
+	header->length = sizeof(struct acpi_spcr);
+	header->revision = 2;
+
+	ret = serial_getinfo(&info);
+	if (ret)
+		debug("Can't get information of serial device: %d\n", ret);
+
+	/* Encode baud rate */
+	switch (info.baudrate) {
+	case 9600:
+		spcr->baud_rate = 3;
+		break;
+	case 19200:
+		spcr->baud_rate = 4;
+		break;
+	case 57600:
+		spcr->baud_rate = 6;
+		break;
+	case 115200:
+		spcr->baud_rate = 7;
+		break;
+	default:
+		spcr->baud_rate = 0;
+		break;
+	}
+
+	/* Encode register access size */
+	switch (info.reg_shift) {
+	case 0:
+		access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
+		break;
+	case 1:
+		access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
+		break;
+	case 2:
+		access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
+		break;
+	case 3:
+		access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
+		break;
+	default:
+		access_size = ACPI_ACCESS_SIZE_UNDEFINED;
+		break;
+	}
+
+	spcr->serial_port.space_id = ACPI_ADDRESS_SPACE_MEMORY;
+	spcr->serial_port.bit_width = info.reg_width;
+	spcr->serial_port.bit_offset = info.reg_offset;
+	spcr->serial_port.access_size = access_size;
+	spcr->serial_port.addrl = info.addr >> 0;
+	spcr->serial_port.addrh = info.addr >> 32;
+
+	/* Hard coded values for now */
+	spcr->parity = 0;
+	spcr->stop_bits = 1;
+
+	/* No PCI devices for now */
+	spcr->pci_device_id = 0xffff;
+	spcr->pci_vendor_id = 0xffff;
+
+	/* Fix checksum */
+	header->checksum = table_compute_checksum((void *)spcr, header->length);
+}
+
 /*
  * QEMU's version of write_acpi_tables is defined in drivers/misc/qfw.c
  */
@@ -352,6 +426,7 @@  ulong write_acpi_tables(ulong start)
 	struct acpi_fadt *fadt;
 	struct acpi_mcfg *mcfg;
 	struct acpi_madt *madt;
+	struct acpi_spcr *spcr;
 	int i;
 
 	current = start;
@@ -440,6 +515,13 @@  ulong write_acpi_tables(ulong start)
 	acpi_add_table(rsdp, mcfg);
 	current = ALIGN(current, 16);
 
+	debug("ACPI:    * SPCR\n");
+	spcr = (struct acpi_spcr *)current;
+	acpi_create_spcr(spcr);
+	current += spcr->header.length;
+	acpi_add_table(rsdp, spcr);
+	current = ALIGN(current, 16);
+
 	debug("current = %x\n", current);
 
 	acpi_rsdp_addr = (unsigned long)rsdp;