From: Benjamin Herrenschmidt <b...@amazon.com> It is common for PCI based UARTs to use larger than one byte access sizes. This adds support for this and uses the information present in SPCR accordingly.
Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org> --- grub-core/term/ns8250-spcr.c | 3 +- grub-core/term/ns8250.c | 67 ++++++++++++++++++++++++++++++------ include/grub/serial.h | 10 ++++-- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/grub-core/term/ns8250-spcr.c b/grub-core/term/ns8250-spcr.c index 0b4417a30..f4b718833 100644 --- a/grub-core/term/ns8250-spcr.c +++ b/grub-core/term/ns8250-spcr.c @@ -74,7 +74,8 @@ grub_ns8250_spcr_init (void) switch (spcr->base_addr.space_id) { case GRUB_ACPI_GENADDR_MEM_SPACE: - return grub_serial_ns8250_add_mmio (spcr->base_addr.addr, &config); + return grub_serial_ns8250_add_mmio (spcr->base_addr.addr, + spcr->base_addr.access_size, &config); case GRUB_ACPI_GENADDR_IO_SPACE: return grub_serial_ns8250_add_port (spcr->base_addr.addr, &config); default: diff --git a/grub-core/term/ns8250.c b/grub-core/term/ns8250.c index d9d93fcf8..98f0b3bc3 100644 --- a/grub-core/term/ns8250.c +++ b/grub-core/term/ns8250.c @@ -42,16 +42,59 @@ ns8250_reg_read (struct grub_serial_port *port, grub_addr_t reg) { asm volatile("" : : : "memory"); if (port->mmio) - return *((volatile grub_uint8_t *) (port->mmio_base + reg)); + { + /* + * Note: we assume MMIO UARTs are little endian. This is not true of all + * embedded platforms but will do for now + */ + switch(port->access_size) + { + default: + /* ACPI tables occasionally uses "0" (legacy) as equivalent to "1" (byte) */ + case 1: + return *((volatile grub_uint8_t *) (port->mmio_base + reg)); + case 2: + return grub_le_to_cpu16 (*((volatile grub_uint16_t *) (port->mmio_base + (reg << 1)))); + case 3: + return grub_le_to_cpu32 (*((volatile grub_uint32_t *) (port->mmio_base + (reg << 2)))); + case 4: + /* + * This will only work properly on 64-bit systems since 64-bit + * accessors aren't atomic on 32-bit hardware. Thankfully the + * case of a UART with a 64-bit register spacing on 32-bit + * also probably doesn't exist. + */ + return grub_le_to_cpu64 (*((volatile grub_uint64_t *) (port->mmio_base + (reg << 3)))); + } + } return grub_inb (port->port + reg); } static void -ns8250_reg_write (struct grub_serial_port *port, grub_uint8_t, grub_addr_t reg) +ns8250_reg_write (struct grub_serial_port *port, grub_uint8_t value, grub_addr_t reg) { asm volatile("" : : : "memory"); if (port->mmio) - *((volatile grub_uint8_t *) (port->mmio_base + reg)) = value; + { + switch(port->access_size) + { + default: + /* ACPI tables occasionally uses "0" (legacy) as equivalent to "1" (byte) */ + case 1: + *((volatile grub_uint8_t *) (port->mmio_base + reg)) = value; + break; + case 2: + *((volatile grub_uint16_t *) (port->mmio_base + (reg << 1))) = grub_cpu_to_le16 (value); + break; + case 3: + *((volatile grub_uint32_t *) (port->mmio_base + (reg << 2))) = grub_cpu_to_le32 (value); + break; + case 4: + /* See commment in ns8250_reg_read() */ + *((volatile grub_uint64_t *) (port->mmio_base + (reg << 3))) = grub_cpu_to_le64 (value); + break; + } + } else grub_outb (value, port->port + reg); } @@ -286,6 +329,7 @@ grub_ns8250_init (void) grub_print_error (); grub_serial_register (&com_ports[i]); + com_ports[i].access_size = 1; } } @@ -312,12 +356,12 @@ grub_serial_ns8250_add_port (grub_port_t port, struct grub_serial_config *config for (i = 0; i < GRUB_SERIAL_PORT_NUM; i++) if (com_ports[i].port == port) { - if (dead_ports & (1 << i)) - return NULL; - /* give the opportunity for SPCR to configure a default com port */ - if (config != NULL) - grub_serial_port_configure (&com_ports[i], config); - return com_names[i]; + if (dead_ports & (1 << i)) + return NULL; + /* give the opportunity for SPCR to configure a default com port */ + if (config != NULL) + grub_serial_port_configure (&com_ports[i], config); + return com_names[i]; } grub_outb (0x5a, port + UART_SR); @@ -340,6 +384,7 @@ grub_serial_ns8250_add_port (grub_port_t port, struct grub_serial_config *config p->driver = &grub_ns8250_driver; p->mmio = false; p->port = port; + p->access_size = 1; if (config != NULL) grub_serial_port_configure (p, config); else @@ -350,7 +395,8 @@ grub_serial_ns8250_add_port (grub_port_t port, struct grub_serial_config *config } char * -grub_serial_ns8250_add_mmio (grub_addr_t addr, struct grub_serial_config *config) +grub_serial_ns8250_add_mmio (grub_addr_t addr, unsigned int acc_size, + struct grub_serial_config *config) { struct grub_serial_port *p; unsigned i; @@ -375,6 +421,7 @@ grub_serial_ns8250_add_mmio (grub_addr_t addr, struct grub_serial_config *config p->driver = &grub_ns8250_driver; p->mmio = true; p->mmio_base = addr; + p->access_size = acc_size; if (config != NULL) grub_serial_port_configure (p, config); else diff --git a/include/grub/serial.h b/include/grub/serial.h index 8d6ed56a3..65ccab4ff 100644 --- a/include/grub/serial.h +++ b/include/grub/serial.h @@ -94,7 +94,12 @@ struct grub_serial_port #if defined(__mips__) || defined (__i386__) || defined (__x86_64__) grub_port_t port; #endif - grub_addr_t mmio_base; + struct + { + grub_addr_t mmio_base; + /* Access size uses ACPI definition */ + grub_uint8_t access_size; + }; }; }; struct @@ -187,7 +192,8 @@ grub_serial_config_defaults (struct grub_serial_port *port) void grub_ns8250_init (void); char *grub_ns8250_spcr_init (void); char *grub_serial_ns8250_add_port (grub_port_t port, struct grub_serial_config *config); -char *grub_serial_ns8250_add_mmio (grub_addr_t addr, struct grub_serial_config *config); +char *grub_serial_ns8250_add_mmio (grub_addr_t addr, unsigned int acc_size, + struct grub_serial_config *config); #endif #ifdef GRUB_MACHINE_IEEE1275 void grub_ofserial_init (void); -- 2.34.1 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel