From: Benjamin Herrenschmidt Date: Fri, 23 Dec 2022 01:47:58 +0000 (+1100) Subject: term/ns8250: Support more MMIO access sizes X-Git-Tag: grub-2.12-rc1~170 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f5e1d23a187cfb511a22e9fb0d9f673db34518a0;p=thirdparty%2Fgrub.git term/ns8250: Support more MMIO access sizes 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 Reviewed-by: Daniel Kiper --- diff --git a/grub-core/term/ns8250-spcr.c b/grub-core/term/ns8250-spcr.c index 8885d24b4..1adc6063b 100644 --- a/grub-core/term/ns8250-spcr.c +++ b/grub-core/term/ns8250-spcr.c @@ -76,7 +76,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 7294d451b..172bca9c4 100644 --- a/grub-core/term/ns8250.c +++ b/grub-core/term/ns8250.c @@ -42,7 +42,31 @@ ns8250_reg_read (struct grub_serial_port *port, grub_addr_t reg) { asm volatile("" : : : "memory"); if (port->mmio == true) - 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); } @@ -51,7 +75,26 @@ ns8250_reg_write (struct grub_serial_port *port, grub_uint8_t value, grub_addr_t { asm volatile("" : : : "memory"); if (port->mmio == true) - *((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; } } @@ -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..36be4b7ee 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);