From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1p8XBZ-0004J9-Ag for mharc-grub-devel@gnu.org; Thu, 22 Dec 2022 20:49:21 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1p8XBT-0004I5-PB for grub-devel@gnu.org; Thu, 22 Dec 2022 20:49:15 -0500 Received: from gate.crashing.org ([63.228.1.57]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1p8XBR-0002Gc-W8 for grub-devel@gnu.org; Thu, 22 Dec 2022 20:49:15 -0500 Received: from u0f3226c756e75a.ant.amazon.com (localhost.localdomain [127.0.0.1]) by gate.crashing.org (8.14.1/8.14.1) with ESMTP id 2BN1m0pN029703; Thu, 22 Dec 2022 19:48:12 -0600 From: Benjamin Herrenschmidt To: grub-devel@gnu.org Cc: Daniel Kiper Subject: [PATCH v3 7/8] ns8250: Support more MMIO access sizes Date: Fri, 23 Dec 2022 12:47:58 +1100 Message-Id: <20221223014759.2112747-8-benh@kernel.crashing.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221223014759.2112747-1-benh@kernel.crashing.org> References: <20221223014759.2112747-1-benh@kernel.crashing.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Received-SPF: pass client-ip=63.228.1.57; envelope-from=benh@kernel.crashing.org; helo=gate.crashing.org X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 Dec 2022 01:49:16 -0000 From: Benjamin Herrenschmidt 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 --- 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