diff mbox series

[Xen-devel,v3] ns16550: Add ACPI support for ARM only

Message ID 5E38023B.8090306@hisilicon.com
State Superseded
Headers show
Series [Xen-devel,v3] ns16550: Add ACPI support for ARM only | expand

Commit Message

Wei Xu Feb. 3, 2020, 11:21 a.m. UTC
Parse the ACPI SPCR table and initialize the 16550 compatible serial port
for ARM only. Currently we only support one UART on ARM. Some fields
which we do not care yet on ARM are ignored.

Signed-off-by: Wei Xu <xuwei5@hisilicon.com>

---
Changes in v3:
- address the code style comments from Jan
- use container_of to do cast
- list all fields we ignored
- check the console redirection is disabled or not before init the uart
- init the uart io_size and width via spcr->serial_port

Changes in v2:
- improve commit message
- remove the spcr initialization
- add comments for the uart initialization and configuration
- adjust the code style issue
- limit the code only built on ACPI and ARM
---
 xen/drivers/char/ns16550.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

Comments

Jan Beulich Feb. 17, 2020, 1:53 p.m. UTC | #1
On 03.02.2020 12:21, Wei Xu wrote:
> Parse the ACPI SPCR table and initialize the 16550 compatible serial port
> for ARM only. Currently we only support one UART on ARM. Some fields
> which we do not care yet on ARM are ignored.
> 
> Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
> 
> ---
> Changes in v3:
> - address the code style comments from Jan
> - use container_of to do cast
> - list all fields we ignored
> - check the console redirection is disabled or not before init the uart
> - init the uart io_size and width via spcr->serial_port
> 
> Changes in v2:
> - improve commit message
> - remove the spcr initialization
> - add comments for the uart initialization and configuration
> - adjust the code style issue
> - limit the code only built on ACPI and ARM
> ---
>  xen/drivers/char/ns16550.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 75 insertions(+)
> 
> diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
> index aa87c57..741b510 100644
> --- a/xen/drivers/char/ns16550.c
> +++ b/xen/drivers/char/ns16550.c
> @@ -1620,6 +1620,81 @@ DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
>  DT_DEVICE_END
> 
>  #endif /* HAS_DEVICE_TREE */
> +
> +#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)
> +#include <xen/acpi.h>
> +
> +static int __init ns16550_acpi_uart_init(const void *data)
> +{
> +    struct acpi_table_header *table;
> +    struct acpi_table_spcr *spcr;
> +    acpi_status status;
> +    /*
> +     * Same as the DT part.
> +     * Only support one UART on ARM which happen to be ns16550_com[0].
> +     */
> +    struct ns16550 *uart = &ns16550_com[0];
> +
> +    status = acpi_get_table(ACPI_SIG_SPCR, 0, &table);
> +    if ( ACPI_FAILURE(status) )
> +    {
> +        printk("ns16550: Failed to get SPCR table\n");
> +        return -EINVAL;
> +    }
> +
> +    spcr = container_of(table, struct acpi_table_spcr, header);
> +
> +    /*
> +     * The serial port address may be 0 for example
> +     * if the console redirection is disabled.
> +     */
> +    if ( unlikely(!spcr->serial_port.address) )
> +    {
> +        printk("ns16550: the serial port address is invalid\n");

Is zero really an invalid address, or is it rather a proper
indicator of there not being any device?

> +        return -EINVAL;
> +    }
> +
> +    ns16550_init_common(uart);
> +
> +    /*
> +     * The baud rate is pre-configured by the firmware.

But this isn't the same as BAUD_AUTO, is it? If firmware pre-configures
the baud rate, isn't it this structure which it would use to communicate
the information?

> +     * And currently the ACPI part is only targeting ARM so the following
> +     * fields pc_interrupt, pci_device_id, pci_vendor_id, pci_bus, pci_device,
> +     * pci_function, pci_flags, pci_segment and flow_control which we do not
> +     * care yet are ignored.

How come flow control is of no interest?

I'd also group all the pci_* fields into a simple "and all PCI related
ones".

> +     */
> +    uart->baud = BAUD_AUTO;
> +    uart->data_bits = 8;
> +    uart->parity = spcr->parity;
> +    uart->stop_bits = spcr->stop_bits;
> +    uart->io_base = spcr->serial_port.address;
> +    uart->io_size = spcr->serial_port.bit_width;

Once again: You should not ignore the GAS address space indicator.

Jan
Wei Xu Feb. 20, 2020, 7:44 a.m. UTC | #2
Hi Jan,

On 2020/2/17 21:53, Jan Beulich wrote:
> On 03.02.2020 12:21, Wei Xu wrote:
>> Parse the ACPI SPCR table and initialize the 16550 compatible serial port
>> for ARM only. Currently we only support one UART on ARM. Some fields
>> which we do not care yet on ARM are ignored.
>>
>> Signed-off-by: Wei Xu <xuwei5@hisilicon.com>
>>
>> ---
>> Changes in v3:
>> - address the code style comments from Jan
>> - use container_of to do cast
>> - list all fields we ignored
>> - check the console redirection is disabled or not before init the uart
>> - init the uart io_size and width via spcr->serial_port
>>
>> Changes in v2:
>> - improve commit message
>> - remove the spcr initialization
>> - add comments for the uart initialization and configuration
>> - adjust the code style issue
>> - limit the code only built on ACPI and ARM
>> ---
>>  xen/drivers/char/ns16550.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 75 insertions(+)
>>
>> diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
>> index aa87c57..741b510 100644
>> --- a/xen/drivers/char/ns16550.c
>> +++ b/xen/drivers/char/ns16550.c
>> @@ -1620,6 +1620,81 @@ DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
>>  DT_DEVICE_END
>>
>>  #endif /* HAS_DEVICE_TREE */
>> +
>> +#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)
>> +#include <xen/acpi.h>
>> +
>> +static int __init ns16550_acpi_uart_init(const void *data)
>> +{
>> +    struct acpi_table_header *table;
>> +    struct acpi_table_spcr *spcr;
>> +    acpi_status status;
>> +    /*
>> +     * Same as the DT part.
>> +     * Only support one UART on ARM which happen to be ns16550_com[0].
>> +     */
>> +    struct ns16550 *uart = &ns16550_com[0];
>> +
>> +    status = acpi_get_table(ACPI_SIG_SPCR, 0, &table);
>> +    if ( ACPI_FAILURE(status) )
>> +    {
>> +        printk("ns16550: Failed to get SPCR table\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    spcr = container_of(table, struct acpi_table_spcr, header);
>> +
>> +    /*
>> +     * The serial port address may be 0 for example
>> +     * if the console redirection is disabled.
>> +     */
>> +    if ( unlikely(!spcr->serial_port.address) )
>> +    {
>> +        printk("ns16550: the serial port address is invalid\n");
> 
> Is zero really an invalid address, or is it rather a proper
> indicator of there not being any device?

I will change the msg to "The console redirection is disabled." following the description in the spcr.
Is that OK?

> 
>> +        return -EINVAL;
>> +    }
>> +
>> +    ns16550_init_common(uart);
>> +
>> +    /*
>> +     * The baud rate is pre-configured by the firmware.
> 
> But this isn't the same as BAUD_AUTO, is it? If firmware pre-configures
> the baud rate, isn't it this structure which it would use to communicate
> the information?
>

No, the comments of the BAUD_AUTO stated like that
and in fact the baud rate is not changed after the firmmware.
But I can add the baud setting if you prefer to.

>> +     * And currently the ACPI part is only targeting ARM so the following
>> +     * fields pc_interrupt, pci_device_id, pci_vendor_id, pci_bus, pci_device,
>> +     * pci_function, pci_flags, pci_segment and flow_control which we do not
>> +     * care yet are ignored.
> 
> How come flow control is of no interest?

There is no flow control in the DTS part and same for ACPI on ARM platform.

> 
> I'd also group all the pci_* fields into a simple "and all PCI related
> ones".

OK.

> 
>> +     */
>> +    uart->baud = BAUD_AUTO;
>> +    uart->data_bits = 8;
>> +    uart->parity = spcr->parity;
>> +    uart->stop_bits = spcr->stop_bits;
>> +    uart->io_base = spcr->serial_port.address;
>> +    uart->io_size = spcr->serial_port.bit_width;
> 
> Once again: You should not ignore the GAS address space indicator.

Sorry, I did not get the point.
Do you mean check the address is 0 or not?
Thanks!

Best Regards,
Wei

> 
> Jan
> 
> .
>
Jan Beulich Feb. 20, 2020, 8:33 a.m. UTC | #3
On 20.02.2020 08:44, Wei Xu wrote:
> On 2020/2/17 21:53, Jan Beulich wrote:
>> On 03.02.2020 12:21, Wei Xu wrote:
>>> +static int __init ns16550_acpi_uart_init(const void *data)
>>> +{
>>> +    struct acpi_table_header *table;
>>> +    struct acpi_table_spcr *spcr;
>>> +    acpi_status status;
>>> +    /*
>>> +     * Same as the DT part.
>>> +     * Only support one UART on ARM which happen to be ns16550_com[0].
>>> +     */
>>> +    struct ns16550 *uart = &ns16550_com[0];
>>> +
>>> +    status = acpi_get_table(ACPI_SIG_SPCR, 0, &table);
>>> +    if ( ACPI_FAILURE(status) )
>>> +    {
>>> +        printk("ns16550: Failed to get SPCR table\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    spcr = container_of(table, struct acpi_table_spcr, header);
>>> +
>>> +    /*
>>> +     * The serial port address may be 0 for example
>>> +     * if the console redirection is disabled.
>>> +     */
>>> +    if ( unlikely(!spcr->serial_port.address) )
>>> +    {
>>> +        printk("ns16550: the serial port address is invalid\n");
>>
>> Is zero really an invalid address, or is it rather a proper
>> indicator of there not being any device?
> 
> I will change the msg to "The console redirection is disabled." following the description in the spcr.
> Is that OK?

With the "The" preferably dropped, yes.

>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    ns16550_init_common(uart);
>>> +
>>> +    /*
>>> +     * The baud rate is pre-configured by the firmware.
>>
>> But this isn't the same as BAUD_AUTO, is it? If firmware pre-configures
>> the baud rate, isn't it this structure which it would use to communicate
>> the information?
>>
> 
> No, the comments of the BAUD_AUTO stated like that
> and in fact the baud rate is not changed after the firmmware.

Oh, I see. I should have checked the comment instead of implying
meaning assigned to similarly named things elsewhere. Keep as is.

>>> +     */
>>> +    uart->baud = BAUD_AUTO;
>>> +    uart->data_bits = 8;
>>> +    uart->parity = spcr->parity;
>>> +    uart->stop_bits = spcr->stop_bits;
>>> +    uart->io_base = spcr->serial_port.address;
>>> +    uart->io_size = spcr->serial_port.bit_width;
>>
>> Once again: You should not ignore the GAS address space indicator.
> 
> Sorry, I did not get the point.
> Do you mean check the address is 0 or not?

No. I mean you shouldn't ignore other parts of the structure:

struct acpi_generic_address {
	u8 space_id;		/* Address space where struct or register exists */
	u8 bit_width;		/* Size in bits of given register */
	u8 bit_offset;		/* Bit offset within the register */
	u8 access_width;	/* Minimum Access size (ACPI 3.0) */
	u64 address;		/* 64-bit address of struct or register */
};

Iirc you now consume all fields except space_id, yet space_id
is a qualifier to the address field (which you obviously use).

Jan
Wei Xu Feb. 20, 2020, 9:59 a.m. UTC | #4
Hi Jan,

On 2020/2/20 16:33, Jan Beulich wrote:
> On 20.02.2020 08:44, Wei Xu wrote:
>> On 2020/2/17 21:53, Jan Beulich wrote:
>>> On 03.02.2020 12:21, Wei Xu wrote:
>>>> +static int __init ns16550_acpi_uart_init(const void *data)
>>>> +{
>>>> +    struct acpi_table_header *table;
>>>> +    struct acpi_table_spcr *spcr;
>>>> +    acpi_status status;
>>>> +    /*
>>>> +     * Same as the DT part.
>>>> +     * Only support one UART on ARM which happen to be ns16550_com[0].
>>>> +     */
>>>> +    struct ns16550 *uart = &ns16550_com[0];
>>>> +
>>>> +    status = acpi_get_table(ACPI_SIG_SPCR, 0, &table);
>>>> +    if ( ACPI_FAILURE(status) )
>>>> +    {
>>>> +        printk("ns16550: Failed to get SPCR table\n");
>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    spcr = container_of(table, struct acpi_table_spcr, header);
>>>> +
>>>> +    /*
>>>> +     * The serial port address may be 0 for example
>>>> +     * if the console redirection is disabled.
>>>> +     */
>>>> +    if ( unlikely(!spcr->serial_port.address) )
>>>> +    {
>>>> +        printk("ns16550: the serial port address is invalid\n");
>>>
>>> Is zero really an invalid address, or is it rather a proper
>>> indicator of there not being any device?
>>
>> I will change the msg to "The console redirection is disabled." following the description in the spcr.
>> Is that OK?
> 
> With the "The" preferably dropped, yes.
> 

Got it.

>>>> +        return -EINVAL;
>>>> +    }
>>>> +
>>>> +    ns16550_init_common(uart);
>>>> +
>>>> +    /*
>>>> +     * The baud rate is pre-configured by the firmware.
>>>
>>> But this isn't the same as BAUD_AUTO, is it? If firmware pre-configures
>>> the baud rate, isn't it this structure which it would use to communicate
>>> the information?
>>>
>>
>> No, the comments of the BAUD_AUTO stated like that
>> and in fact the baud rate is not changed after the firmmware.
> 
> Oh, I see. I should have checked the comment instead of implying
> meaning assigned to similarly named things elsewhere. Keep as is.
> 

Got it.

>>>> +     */
>>>> +    uart->baud = BAUD_AUTO;
>>>> +    uart->data_bits = 8;
>>>> +    uart->parity = spcr->parity;
>>>> +    uart->stop_bits = spcr->stop_bits;
>>>> +    uart->io_base = spcr->serial_port.address;
>>>> +    uart->io_size = spcr->serial_port.bit_width;
>>>
>>> Once again: You should not ignore the GAS address space indicator.
>>
>> Sorry, I did not get the point.
>> Do you mean check the address is 0 or not?
> 
> No. I mean you shouldn't ignore other parts of the structure:
> 
> struct acpi_generic_address {
> 	u8 space_id;		/* Address space where struct or register exists */
> 	u8 bit_width;		/* Size in bits of given register */
> 	u8 bit_offset;		/* Bit offset within the register */
> 	u8 access_width;	/* Minimum Access size (ACPI 3.0) */
> 	u64 address;		/* 64-bit address of struct or register */
> };
> 
> Iirc you now consume all fields except space_id, yet space_id
> is a qualifier to the address field (which you obviously use).

I did not know what the space_id means yet.
I will investigate it.
Thanks a lot!

Best Regards,
Wei

> 
> Jan
> 
> .
>
diff mbox series

Patch

diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index aa87c57..741b510 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -1620,6 +1620,81 @@  DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
 DT_DEVICE_END

 #endif /* HAS_DEVICE_TREE */
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)
+#include <xen/acpi.h>
+
+static int __init ns16550_acpi_uart_init(const void *data)
+{
+    struct acpi_table_header *table;
+    struct acpi_table_spcr *spcr;
+    acpi_status status;
+    /*
+     * Same as the DT part.
+     * Only support one UART on ARM which happen to be ns16550_com[0].
+     */
+    struct ns16550 *uart = &ns16550_com[0];
+
+    status = acpi_get_table(ACPI_SIG_SPCR, 0, &table);
+    if ( ACPI_FAILURE(status) )
+    {
+        printk("ns16550: Failed to get SPCR table\n");
+        return -EINVAL;
+    }
+
+    spcr = container_of(table, struct acpi_table_spcr, header);
+
+    /*
+     * The serial port address may be 0 for example
+     * if the console redirection is disabled.
+     */
+    if ( unlikely(!spcr->serial_port.address) )
+    {
+        printk("ns16550: the serial port address is invalid\n");
+        return -EINVAL;
+    }
+
+    ns16550_init_common(uart);
+
+    /*
+     * The baud rate is pre-configured by the firmware.
+     * And currently the ACPI part is only targeting ARM so the following
+     * fields pc_interrupt, pci_device_id, pci_vendor_id, pci_bus, pci_device,
+     * pci_function, pci_flags, pci_segment and flow_control which we do not
+     * care yet are ignored.
+     */
+    uart->baud = BAUD_AUTO;
+    uart->data_bits = 8;
+    uart->parity = spcr->parity;
+    uart->stop_bits = spcr->stop_bits;
+    uart->io_base = spcr->serial_port.address;
+    uart->io_size = spcr->serial_port.bit_width;
+    uart->reg_shift = spcr->serial_port.bit_offset;
+    uart->reg_width = spcr->serial_port.access_width;
+
+    /* The trigger/polarity information is not available in spcr. */
+    irq_set_type(spcr->interrupt, IRQ_TYPE_LEVEL_HIGH);
+    uart->irq = spcr->interrupt;
+
+    uart->vuart.base_addr = uart->io_base;
+    uart->vuart.size = uart->io_size;
+    uart->vuart.data_off = UART_THR << uart->reg_shift;
+    uart->vuart.status_off = UART_LSR << uart->reg_shift;
+    uart->vuart.status = UART_LSR_THRE | UART_LSR_TEMT;
+
+    /* Register with generic serial driver. */
+    serial_register_uart(SERHND_DTUART, &ns16550_driver, uart);
+
+    return 0;
+}
+
+ACPI_DEVICE_START(ans16550, "NS16550 UART", DEVICE_SERIAL)
+    .class_type = ACPI_DBG2_16550_COMPATIBLE,
+    .init = ns16550_acpi_uart_init,
+ACPI_DEVICE_END
+
+#endif /* CONFIG_ACPI && CONFIG_ARM */
+
 /*
  * Local variables:
  * mode: C