diff mbox series

[U-Boot,v2,5/5] x86: acpi: Generate SPCR table

Message ID 20181115175854.7550-6-andriy.shevchenko@linux.intel.com
State Superseded
Delegated to: Simon Glass
Headers show
Series ACPI: Generate SPCR table | expand

Commit Message

Andy Shevchenko Nov. 15, 2018, 5:58 p.m. UTC
Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
Let's provide it in U-Boot.

[1] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx

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

Comments

Alexander Graf Nov. 15, 2018, 6:27 p.m. UTC | #1
On 15.11.18 18:58, Andy Shevchenko wrote:
> Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
> Let's provide it in U-Boot.
> 
> [1] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  arch/x86/include/asm/acpi_table.h |  2 +
>  arch/x86/lib/acpi_table.c         | 85 +++++++++++++++++++++++++++++++
>  2 files changed, 87 insertions(+)
> 
> diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
> index 51cc806673..e3b65cff66 100644
> --- a/arch/x86/include/asm/acpi_table.h
> +++ b/arch/x86/include/asm/acpi_table.h
> @@ -327,6 +327,8 @@ struct acpi_global_nvs;
>  #define ACPI_DBG2_USB_XHCI		0x0000
>  #define ACPI_DBG2_USB_EHCI		0x0001
>  
> +#define ACPI_DBG2_UNKNOWN		0x00FF
> +
>  /* SPCR (Serial Port Console Redirection table) */
>  struct __packed acpi_spcr {
>  	struct acpi_table_header header;
> diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
> index c6b2026613..d8b44aea02 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,82 @@ 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)
> +		spcr->interface_type = ACPI_DBG2_UNKNOWN;
> +	else
> +		spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;

This sounds like pretty subtle semantics. Could you just include the
interface type in &info?

The main problem I'm seeing is that your UART might be a PL011
compatible which could still implement getinfo() but then wouldn't be
16660 compatible.

> +	debug("UART type %u (serial_getinfo() rc=%d)\n", spcr->interface_type, 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;

Are any higher (and lower) ones specified too? If so, you may want to
add them as well.

> +	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;

Can you guarantee that? Should probably be part of &info as well if addr is.

> +	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;
> +
> +	/* REVISIT: Hard coded values for now */
> +	spcr->parity = 0;
> +	spcr->stop_bits = 1;

IMHO those should be part of &info as well. If you have to hard code
them, better hard code them in the driver rather than the generic ACPI
generation code.


Alex

> +
> +	/* REVISIT: 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 +429,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 +518,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;
>
Andy Shevchenko Nov. 15, 2018, 7:43 p.m. UTC | #2
On Thu, Nov 15, 2018 at 8:27 PM Alexander Graf <agraf@suse.de> wrote:
> On 15.11.18 18:58, Andy Shevchenko wrote:
> > Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
> > Let's provide it in U-Boot.
> >
> > [1] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx

> > +     ret = serial_getinfo(&info);
> > +     if (ret)
> > +             spcr->interface_type = ACPI_DBG2_UNKNOWN;
> > +     else
> > +             spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
>
> This sounds like pretty subtle semantics. Could you just include the
> interface type in &info?

It might be another step if you provide a cool way to do so. Otherwise
we need first to de-x86 acpi stuff. I won't do it right now since it
so-o out of the scope of this series.

> The main problem I'm seeing is that your UART might be a PL011
> compatible which could still implement getinfo() but then wouldn't be
> 16660 compatible.

Yes, I know. Perhaps I forgot to mark it in "Known issues" section.

Have you seen, btw, PL011 on x86 environment?

> Are any higher (and lower) ones specified too? If so, you may want to
> add them as well.

There is a link to a specification. Care to read?

> > +     default:
> > +             spcr->baud_rate = 0;
> > +             break;

Going ahead.
This part actually something to develop through specifications, but I
need to ping Microsoft and our internal ACPI people for that.

> > +             break;
> > +     default:
> > +             access_size = ACPI_ACCESS_SIZE_UNDEFINED;
> > +             break;
> > +     }
> > +
> > +     spcr->serial_port.space_id = ACPI_ADDRESS_SPACE_MEMORY;
>
> Can you guarantee that? Should probably be part of &info as well if addr is.

Not now.
As per moving to info, see my comment about de-x86 of ACPI in U-Boot.

> > +     /* REVISIT: Hard coded values for now */
> > +     spcr->parity = 0;
> > +     spcr->stop_bits = 1;
>
> IMHO those should be part of &info as well. If you have to hard code
> them, better hard code them in the driver rather than the generic ACPI
> generation code.

Care to read cover letter carefully?
Alexander Graf Nov. 15, 2018, 8:19 p.m. UTC | #3
On 15.11.18 20:43, Andy Shevchenko wrote:
> On Thu, Nov 15, 2018 at 8:27 PM Alexander Graf <agraf@suse.de> wrote:
>> On 15.11.18 18:58, Andy Shevchenko wrote:
>>> Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
>>> Let's provide it in U-Boot.
>>>
>>> [1] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
> 
>>> +     ret = serial_getinfo(&info);
>>> +     if (ret)
>>> +             spcr->interface_type = ACPI_DBG2_UNKNOWN;
>>> +     else
>>> +             spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
>>
>> This sounds like pretty subtle semantics. Could you just include the
>> interface type in &info?
> 
> It might be another step if you provide a cool way to do so. Otherwise

Define an enum with serial_type where 0 is unknown and 1 is
16550_compatible. Provide that enum in getinfo().

Bonus points for keeping the enum and ACPI_DBG2 IDs in sync, so that we
don't need too much code to copy from one to the other.

> we need first to de-x86 acpi stuff. I won't do it right now since it
> so-o out of the scope of this series.

Well, we will probably want to be able to do that in the future. And
anything that hard codes more x86 assumptions is a step in the wrong
direction.

> 
>> The main problem I'm seeing is that your UART might be a PL011
>> compatible which could still implement getinfo() but then wouldn't be
>> 16660 compatible.
> 
> Yes, I know. Perhaps I forgot to mark it in "Known issues" section.
> 
> Have you seen, btw, PL011 on x86 environment?

I can create one for you in QEMU if you like?

> 
>> Are any higher (and lower) ones specified too? If so, you may want to
>> add them as well.
> 
> There is a link to a specification. Care to read?

A simple "no, the spec only defines the ones above" would've been a
better answer and saved both of us a few seconds of our lives ;).

> 
>>> +     default:
>>> +             spcr->baud_rate = 0;
>>> +             break;
> 
> Going ahead.
> This part actually something to develop through specifications, but I
> need to ping Microsoft and our internal ACPI people for that.
> 
>>> +             break;
>>> +     default:
>>> +             access_size = ACPI_ACCESS_SIZE_UNDEFINED;
>>> +             break;
>>> +     }
>>> +
>>> +     spcr->serial_port.space_id = ACPI_ADDRESS_SPACE_MEMORY;
>>
>> Can you guarantee that? Should probably be part of &info as well if addr is.
> 
> Not now.
> As per moving to info, see my comment about de-x86 of ACPI in U-Boot.

I don't understand how describing your address space correctly has
anything to do with de-x86'ing anything? x86 is the only (living) user
of non-MMIO address space out there.

> 
>>> +     /* REVISIT: Hard coded values for now */
>>> +     spcr->parity = 0;
>>> +     spcr->stop_bits = 1;
>>
>> IMHO those should be part of &info as well. If you have to hard code
>> them, better hard code them in the driver rather than the generic ACPI
>> generation code.
> 
> Care to read cover letter carefully?

Again, if you think your patch is terrible and shouldn't be applied
anyway, please mark it as RFC. I'll be happy to wait with review until
you've made up your mind then :).


Alex
Bin Meng Nov. 18, 2018, 12:37 p.m. UTC | #4
Hi Andy,

On Fri, Nov 16, 2018 at 1:59 AM Andy Shevchenko
<andriy.shevchenko@linux.intel.com> wrote:
>
> Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
> Let's provide it in U-Boot.
>
> [1] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
>

This URL redirects to
https://docs.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table.
It looks that the redirected one has a better name that deserves to be
mentioned in the commit message :)

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

[snip]

Regards,
Bin
Andy Shevchenko Nov. 20, 2018, 8:47 p.m. UTC | #5
On Sun, Nov 18, 2018 at 08:37:20PM +0800, Bin Meng wrote:
> Hi Andy,
> 
> On Fri, Nov 16, 2018 at 1:59 AM Andy Shevchenko
> <andriy.shevchenko@linux.intel.com> wrote:
> >
> > Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
> > Let's provide it in U-Boot.
> >
> > [1] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
> >
> 
> This URL redirects to
> https://docs.microsoft.com/en-us/windows-hardware/drivers/serports/serial-port-console-redirection-table.
> It looks that the redirected one has a better name that deserves to be
> mentioned in the commit message :)

Sure, thanks!
Andy Shevchenko Nov. 20, 2018, 9:06 p.m. UTC | #6
On Thu, Nov 15, 2018 at 09:19:38PM +0100, Alexander Graf wrote:
> On 15.11.18 20:43, Andy Shevchenko wrote:
> > On Thu, Nov 15, 2018 at 8:27 PM Alexander Graf <agraf@suse.de> wrote:
> >> On 15.11.18 18:58, Andy Shevchenko wrote:
> >>> Microsoft specifies a SPCR (Serial Port Console Redirection Table) [1].
> >>> Let's provide it in U-Boot.
> >>>
> >>> [1] https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx

Thanks for review.
diff mbox series

Patch

diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h
index 51cc806673..e3b65cff66 100644
--- a/arch/x86/include/asm/acpi_table.h
+++ b/arch/x86/include/asm/acpi_table.h
@@ -327,6 +327,8 @@  struct acpi_global_nvs;
 #define ACPI_DBG2_USB_XHCI		0x0000
 #define ACPI_DBG2_USB_EHCI		0x0001
 
+#define ACPI_DBG2_UNKNOWN		0x00FF
+
 /* SPCR (Serial Port Console Redirection table) */
 struct __packed acpi_spcr {
 	struct acpi_table_header header;
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c
index c6b2026613..d8b44aea02 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,82 @@  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)
+		spcr->interface_type = ACPI_DBG2_UNKNOWN;
+	else
+		spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
+	debug("UART type %u (serial_getinfo() rc=%d)\n", spcr->interface_type, 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;
+
+	/* REVISIT: Hard coded values for now */
+	spcr->parity = 0;
+	spcr->stop_bits = 1;
+
+	/* REVISIT: 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 +429,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 +518,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;