grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 7/8] ns8250: Support more MMIO access sizes


From: Benjamin Herrenschmidt
Subject: [PATCH v3 7/8] ns8250: Support more MMIO access sizes
Date: Fri, 23 Dec 2022 12:47:58 +1100

From: Benjamin Herrenschmidt <benh@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 <benh@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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]