parisc: Convert PDC console to an early console
authorHelge Deller <deller@gmx.de>
Fri, 30 Sep 2022 22:32:07 +0000 (00:32 +0200)
committerHelge Deller <deller@gmx.de>
Tue, 11 Oct 2022 10:01:24 +0000 (12:01 +0200)
Rewrite the PDC console to become an early console.
Beside the fact that now boot information is visible until another
(text- or graphics) console takes over, this benefits as well machines
with a yet-unsupported STI console and kgdb.

Signed-off-by: Helge Deller <deller@gmx.de>
arch/parisc/include/asm/pdc.h
arch/parisc/kernel/pdc_cons.c
arch/parisc/kernel/setup.c
arch/parisc/kernel/traps.c
drivers/tty/serial/Kconfig
lib/Kconfig.kgdb

index b643092d4b985370702d13cbef4e6d9d143bfc85..fcbcf9a96c1112d39de10868cab3ac544a5b161e 100644 (file)
@@ -19,9 +19,6 @@ extern unsigned long parisc_pat_pdc_cap; /* PDC capabilities (PAT) */
 #define PDC_TYPE_SYSTEM_MAP     1 /* 32-bit, but supports PDC_SYSTEM_MAP */
 #define PDC_TYPE_SNAKE          2 /* Doesn't support SYSTEM_MAP */
 
-void pdc_console_init(void);   /* in pdc_console.c */
-void pdc_console_restart(void);
-
 void setup_pdc(void);          /* in inventory.c */
 
 /* wrapper-functions from pdc.c */
index 2661cdd256ae7deabd69d06d492bc833f50e2a0d..7d0989f523d031bf74888e4ab96ed22b291ea457 100644 (file)
@@ -1,46 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /* 
- *    PDC Console support - ie use firmware to dump text via boot console
+ *    PDC early console support - use PDC firmware to dump text via boot console
  *
- *    Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org>
- *    Copyright (C) 2000 Martin K Petersen <mkp at mkp.net>
- *    Copyright (C) 2000 John Marvin <jsm at parisc-linux.org>
- *    Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org>
- *    Copyright (C) 2000 Philipp Rumpf <prumpf with tux.org>
- *    Copyright (C) 2000 Michael Ang <mang with subcarrier.org>
- *    Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org>
- *    Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org>
- *    Copyright (C) 2001 Helge Deller <deller at parisc-linux.org>
- *    Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
- *    Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
- *    Copyright (C) 2010 Guy Martin <gmsoft at tuxicoman.be>
+ *    Copyright (C) 2001-2022 Helge Deller <deller@gmx.de>
  */
 
-/*
- *  The PDC console is a simple console, which can be used for debugging 
- *  boot related problems on HP PA-RISC machines. It is also useful when no
- *  other console works.
- *
- *  This code uses the ROM (=PDC) based functions to read and write characters
- *  from and to PDC's boot path.
- */
-
-/* Define EARLY_BOOTUP_DEBUG to debug kernel related boot problems. 
- * On production kernels EARLY_BOOTUP_DEBUG should be undefined. */
-#define EARLY_BOOTUP_DEBUG
-
-
-#include <linux/kernel.h>
 #include <linux/console.h>
-#include <linux/string.h>
 #include <linux/init.h>
-#include <linux/major.h>
-#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <linux/kgdb.h>
 #include <asm/page.h>          /* for PAGE0 */
 #include <asm/pdc.h>           /* for iodc_call() proto and friends */
 
 static DEFINE_SPINLOCK(pdc_console_lock);
-static struct console pdc_cons;
 
 static void pdc_console_write(struct console *co, const char *s, unsigned count)
 {
@@ -54,7 +26,8 @@ static void pdc_console_write(struct console *co, const char *s, unsigned count)
        spin_unlock_irqrestore(&pdc_console_lock, flags);
 }
 
-int pdc_console_poll_key(struct console *co)
+#ifdef CONFIG_KGDB
+static int kgdb_pdc_read_char(void)
 {
        int c;
        unsigned long flags;
@@ -63,201 +36,40 @@ int pdc_console_poll_key(struct console *co)
        c = pdc_iodc_getc();
        spin_unlock_irqrestore(&pdc_console_lock, flags);
 
-       return c;
-}
-
-static int pdc_console_setup(struct console *co, char *options)
-{
-       return 0;
-}
-
-#if defined(CONFIG_PDC_CONSOLE)
-#include <linux/vt_kern.h>
-#include <linux/tty_flip.h>
-
-#define PDC_CONS_POLL_DELAY (30 * HZ / 1000)
-
-static void pdc_console_poll(struct timer_list *unused);
-static DEFINE_TIMER(pdc_console_timer, pdc_console_poll);
-static struct tty_port tty_port;
-
-static int pdc_console_tty_open(struct tty_struct *tty, struct file *filp)
-{
-       tty_port_tty_set(&tty_port, tty);
-       mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
-
-       return 0;
+       return (c <= 0) ? NO_POLL_CHAR : c;
 }
 
-static void pdc_console_tty_close(struct tty_struct *tty, struct file *filp)
+static void kgdb_pdc_write_char(u8 chr)
 {
-       if (tty->count == 1) {
-               del_timer_sync(&pdc_console_timer);
-               tty_port_tty_set(&tty_port, NULL);
-       }
+       if (PAGE0->mem_cons.cl_class != CL_DUPLEX)
+               pdc_console_write(NULL, &chr, 1);
 }
 
-static int pdc_console_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-       pdc_console_write(NULL, buf, count);
-       return count;
-}
-
-static unsigned int pdc_console_tty_write_room(struct tty_struct *tty)
-{
-       return 32768; /* no limit, no buffer used */
-}
-
-static const struct tty_operations pdc_console_tty_ops = {
-       .open = pdc_console_tty_open,
-       .close = pdc_console_tty_close,
-       .write = pdc_console_tty_write,
-       .write_room = pdc_console_tty_write_room,
+static struct kgdb_io kgdb_pdc_io_ops = {
+       .name = "kgdb_pdc",
+       .read_char = kgdb_pdc_read_char,
+       .write_char = kgdb_pdc_write_char,
 };
-
-static void pdc_console_poll(struct timer_list *unused)
-{
-       int data, count = 0;
-
-       while (1) {
-               data = pdc_console_poll_key(NULL);
-               if (data == -1)
-                       break;
-               tty_insert_flip_char(&tty_port, data & 0xFF, TTY_NORMAL);
-               count ++;
-       }
-
-       if (count)
-               tty_flip_buffer_push(&tty_port);
-
-       if (pdc_cons.flags & CON_ENABLED)
-               mod_timer(&pdc_console_timer, jiffies + PDC_CONS_POLL_DELAY);
-}
-
-static struct tty_driver *pdc_console_tty_driver;
-
-static int __init pdc_console_tty_driver_init(void)
-{
-       struct tty_driver *driver;
-       int err;
-
-       /* Check if the console driver is still registered.
-        * It is unregistered if the pdc console was not selected as the
-        * primary console. */
-
-       struct console *tmp;
-
-       console_lock();
-       for_each_console(tmp)
-               if (tmp == &pdc_cons)
-                       break;
-       console_unlock();
-
-       if (!tmp) {
-               printk(KERN_INFO "PDC console driver not registered anymore, not creating %s\n", pdc_cons.name);
-               return -ENODEV;
-       }
-
-       printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
-       pdc_cons.flags &= ~CON_BOOT;
-
-       driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW |
-                       TTY_DRIVER_RESET_TERMIOS);
-       if (IS_ERR(driver))
-               return PTR_ERR(driver);
-
-       tty_port_init(&tty_port);
-
-       driver->driver_name = "pdc_cons";
-       driver->name = "ttyB";
-       driver->major = MUX_MAJOR;
-       driver->minor_start = 0;
-       driver->type = TTY_DRIVER_TYPE_SYSTEM;
-       driver->init_termios = tty_std_termios;
-       tty_set_operations(driver, &pdc_console_tty_ops);
-       tty_port_link_device(&tty_port, driver, 0);
-
-       err = tty_register_driver(driver);
-       if (err) {
-               printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
-               tty_port_destroy(&tty_port);
-               tty_driver_kref_put(driver);
-               return err;
-       }
-
-       pdc_console_tty_driver = driver;
-
-       return 0;
-}
-device_initcall(pdc_console_tty_driver_init);
-
-static struct tty_driver * pdc_console_device (struct console *c, int *index)
-{
-       *index = c->index;
-       return pdc_console_tty_driver;
-}
-#else
-#define pdc_console_device NULL
 #endif
 
-static struct console pdc_cons = {
-       .name =         "ttyB",
-       .write =        pdc_console_write,
-       .device =       pdc_console_device,
-       .setup =        pdc_console_setup,
-       .flags =        CON_BOOT | CON_PRINTBUFFER,
-       .index =        -1,
-};
-
-static int pdc_console_initialized;
-
-static void pdc_console_init_force(void)
+static int __init pdc_earlycon_setup(struct earlycon_device *device,
+                                    const char *opt)
 {
-       if (pdc_console_initialized)
-               return;
-       ++pdc_console_initialized;
-       
+       struct console *earlycon_console;
+
        /* If the console is duplex then copy the COUT parameters to CIN. */
        if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
                memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
 
-       /* register the pdc console */
-       register_console(&pdc_cons);
-}
+       earlycon_console = device->con;
+       earlycon_console->write = pdc_console_write;
+       device->port.iotype = UPIO_MEM32BE;
 
-void __init pdc_console_init(void)
-{
-#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
-       pdc_console_init_force();
+#ifdef CONFIG_KGDB
+       kgdb_register_io_module(&kgdb_pdc_io_ops);
 #endif
-#ifdef EARLY_BOOTUP_DEBUG
-       printk(KERN_INFO "Initialized PDC Console for debugging.\n");
-#endif
-}
-
-
-/*
- * Used for emergencies. Currently only used if an HPMC occurs. If an
- * HPMC occurs, it is possible that the current console may not be
- * properly initialised after the PDC IO reset. This routine unregisters
- * all of the current consoles, reinitializes the pdc console and
- * registers it.
- */
-
-void pdc_console_restart(void)
-{
-       struct console *console;
-
-       if (pdc_console_initialized)
-               return;
 
-       /* If we've already seen the output, don't bother to print it again */
-       if (console_drivers != NULL)
-               pdc_cons.flags &= ~CON_PRINTBUFFER;
-
-       while ((console = console_drivers) != NULL)
-               unregister_console(console_drivers);
-
-       /* force registering the pdc console */
-       pdc_console_init_force();
+       return 0;
 }
+
+EARLYCON_DECLARE(pdc, pdc_earlycon_setup);
index f005ddedb50e469653bcec1d5eb10c062a414311..375f38d6e1a4de1b3d73d330facb9c484ba84427 100644 (file)
@@ -70,6 +70,10 @@ void __init setup_cmdline(char **cmdline_p)
                        strlcat(p, "tty0", COMMAND_LINE_SIZE);
        }
 
+       /* default to use early console */
+       if (!strstr(p, "earlycon"))
+               strlcat(p, " earlycon=pdc", COMMAND_LINE_SIZE);
+
 #ifdef CONFIG_BLK_DEV_INITRD
                if (boot_args[2] != 0) /* did palo pass us a ramdisk? */
                {
@@ -139,8 +143,6 @@ void __init setup_arch(char **cmdline_p)
        if (__pa((unsigned long) &_end) >= KERNEL_INITIAL_SIZE)
                panic("KERNEL_INITIAL_ORDER too small!");
 
-       pdc_console_init();
-
 #ifdef CONFIG_64BIT
        if(parisc_narrow_firmware) {
                printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
index b78f1b9d45c18b1e382e6c68961db149fa03c5f0..f9696fbf646c473cffbe26f316b1bcd289054431 100644 (file)
@@ -239,13 +239,6 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
        /* unlock the pdc lock if necessary */
        pdc_emergency_unlock();
 
-       /* maybe the kernel hasn't booted very far yet and hasn't been able 
-        * to initialize the serial or STI console. In that case we should 
-        * re-enable the pdc console, so that the user will be able to 
-        * identify the problem. */
-       if (!console_drivers)
-               pdc_console_restart();
-       
        if (err)
                printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
                        current->comm, task_pid_nr(current), str, err);
@@ -429,10 +422,6 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
        /* unlock the pdc lock if necessary */
        pdc_emergency_unlock();
 
-       /* restart pdc console if necessary */
-       if (!console_drivers)
-               pdc_console_restart();
-
        /* Not all paths will gutter the processor... */
        switch(code){
 
@@ -482,9 +471,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
        unsigned long fault_space = 0;
        int si_code;
 
-       if (code == 1)
-           pdc_console_restart();  /* switch back to pdc if HPMC */
-       else if (!irqs_disabled_flags(regs->gr[0]))
+       if (!irqs_disabled_flags(regs->gr[0]))
            local_irq_enable();
 
        /* Security check:
index 877173907c5369a58d48f563612164f251ee8de5..898728ab2c18e6443a32536030b4388126ae36a0 100644 (file)
@@ -602,21 +602,6 @@ config SERIAL_MUX_CONSOLE
        select SERIAL_CORE_CONSOLE
        default y
 
-config PDC_CONSOLE
-       bool "PDC software console support"
-       depends on PARISC && !SERIAL_MUX && VT
-       help
-         Saying Y here will enable the software based PDC console to be 
-         used as the system console.  This is useful for machines in 
-         which the hardware based console has not been written yet.  The
-         following steps must be completed to use the PDC console:
-
-           1. create the device entry (mknod /dev/ttyB0 c 11 0)
-           2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
-           3. Add device ttyB0 to /etc/securetty (if you want to log on as
-                root on this console.)
-           4. Change the kernel command console parameter to: console=ttyB0
-
 config SERIAL_SUNSAB
        tristate "Sun Siemens SAB82532 serial support"
        depends on SPARC && PCI
index 05dae05b6cc9ef84e2443b0ea713ec59940d6963..3b9a44008433201ec86443fe0626967c37a488a3 100644 (file)
@@ -121,7 +121,7 @@ config KDB_DEFAULT_ENABLE
 
 config KDB_KEYBOARD
        bool "KGDB_KDB: keyboard as input device"
-       depends on VT && KGDB_KDB
+       depends on VT && KGDB_KDB && !PARISC
        default n
        help
          KDB can use a PS/2 type keyboard for an input device