18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SCLP line mode console driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 1999, 2009 68c2ecf20Sopenharmony_ci * Author(s): Martin Peschke <mpeschke@de.ibm.com> 78c2ecf20Sopenharmony_ci * Martin Schwidefsky <schwidefsky@de.ibm.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kmod.h> 118c2ecf20Sopenharmony_ci#include <linux/console.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/timer.h> 148c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 158c2ecf20Sopenharmony_ci#include <linux/termios.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/reboot.h> 188c2ecf20Sopenharmony_ci#include <linux/gfp.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "sclp.h" 218c2ecf20Sopenharmony_ci#include "sclp_rw.h" 228c2ecf20Sopenharmony_ci#include "sclp_tty.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define sclp_console_major 4 /* TTYAUX_MAJOR */ 258c2ecf20Sopenharmony_ci#define sclp_console_minor 64 268c2ecf20Sopenharmony_ci#define sclp_console_name "ttyS" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Lock to guard over changes to global variables */ 298c2ecf20Sopenharmony_cistatic spinlock_t sclp_con_lock; 308c2ecf20Sopenharmony_ci/* List of free pages that can be used for console output buffering */ 318c2ecf20Sopenharmony_cistatic struct list_head sclp_con_pages; 328c2ecf20Sopenharmony_ci/* List of full struct sclp_buffer structures ready for output */ 338c2ecf20Sopenharmony_cistatic struct list_head sclp_con_outqueue; 348c2ecf20Sopenharmony_ci/* Pointer to current console buffer */ 358c2ecf20Sopenharmony_cistatic struct sclp_buffer *sclp_conbuf; 368c2ecf20Sopenharmony_ci/* Timer for delayed output of console messages */ 378c2ecf20Sopenharmony_cistatic struct timer_list sclp_con_timer; 388c2ecf20Sopenharmony_ci/* Suspend mode flag */ 398c2ecf20Sopenharmony_cistatic int sclp_con_suspended; 408c2ecf20Sopenharmony_ci/* Flag that output queue is currently running */ 418c2ecf20Sopenharmony_cistatic int sclp_con_queue_running; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* Output format for console messages */ 448c2ecf20Sopenharmony_cistatic unsigned short sclp_con_columns; 458c2ecf20Sopenharmony_cistatic unsigned short sclp_con_width_htab; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void 488c2ecf20Sopenharmony_cisclp_conbuf_callback(struct sclp_buffer *buffer, int rc) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci unsigned long flags; 518c2ecf20Sopenharmony_ci void *page; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci do { 548c2ecf20Sopenharmony_ci page = sclp_unmake_buffer(buffer); 558c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* Remove buffer from outqueue */ 588c2ecf20Sopenharmony_ci list_del(&buffer->list); 598c2ecf20Sopenharmony_ci list_add_tail((struct list_head *) page, &sclp_con_pages); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Check if there is a pending buffer on the out queue. */ 628c2ecf20Sopenharmony_ci buffer = NULL; 638c2ecf20Sopenharmony_ci if (!list_empty(&sclp_con_outqueue)) 648c2ecf20Sopenharmony_ci buffer = list_first_entry(&sclp_con_outqueue, 658c2ecf20Sopenharmony_ci struct sclp_buffer, list); 668c2ecf20Sopenharmony_ci if (!buffer || sclp_con_suspended) { 678c2ecf20Sopenharmony_ci sclp_con_queue_running = 0; 688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 728c2ecf20Sopenharmony_ci } while (sclp_emit_buffer(buffer, sclp_conbuf_callback)); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * Finalize and emit first pending buffer. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistatic void sclp_conbuf_emit(void) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct sclp_buffer* buffer; 818c2ecf20Sopenharmony_ci unsigned long flags; 828c2ecf20Sopenharmony_ci int rc; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 858c2ecf20Sopenharmony_ci if (sclp_conbuf) 868c2ecf20Sopenharmony_ci list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue); 878c2ecf20Sopenharmony_ci sclp_conbuf = NULL; 888c2ecf20Sopenharmony_ci if (sclp_con_queue_running || sclp_con_suspended) 898c2ecf20Sopenharmony_ci goto out_unlock; 908c2ecf20Sopenharmony_ci if (list_empty(&sclp_con_outqueue)) 918c2ecf20Sopenharmony_ci goto out_unlock; 928c2ecf20Sopenharmony_ci buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer, 938c2ecf20Sopenharmony_ci list); 948c2ecf20Sopenharmony_ci sclp_con_queue_running = 1; 958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); 988c2ecf20Sopenharmony_ci if (rc) 998c2ecf20Sopenharmony_ci sclp_conbuf_callback(buffer, rc); 1008c2ecf20Sopenharmony_ci return; 1018c2ecf20Sopenharmony_ciout_unlock: 1028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * Wait until out queue is empty 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_cistatic void sclp_console_sync_queue(void) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci unsigned long flags; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 1138c2ecf20Sopenharmony_ci if (timer_pending(&sclp_con_timer)) 1148c2ecf20Sopenharmony_ci del_timer(&sclp_con_timer); 1158c2ecf20Sopenharmony_ci while (sclp_con_queue_running) { 1168c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 1178c2ecf20Sopenharmony_ci sclp_sync_wait(); 1188c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * When this routine is called from the timer then we flush the 1258c2ecf20Sopenharmony_ci * temporary write buffer without further waiting on a final new line. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistatic void 1288c2ecf20Sopenharmony_cisclp_console_timeout(struct timer_list *unused) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci sclp_conbuf_emit(); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * Drop oldest console buffer if sclp_con_drop is set 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_cistatic int 1378c2ecf20Sopenharmony_cisclp_console_drop_buffer(void) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct list_head *list; 1408c2ecf20Sopenharmony_ci struct sclp_buffer *buffer; 1418c2ecf20Sopenharmony_ci void *page; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (!sclp_console_drop) 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci list = sclp_con_outqueue.next; 1468c2ecf20Sopenharmony_ci if (sclp_con_queue_running) 1478c2ecf20Sopenharmony_ci /* The first element is in I/O */ 1488c2ecf20Sopenharmony_ci list = list->next; 1498c2ecf20Sopenharmony_ci if (list == &sclp_con_outqueue) 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci list_del(list); 1528c2ecf20Sopenharmony_ci buffer = list_entry(list, struct sclp_buffer, list); 1538c2ecf20Sopenharmony_ci page = sclp_unmake_buffer(buffer); 1548c2ecf20Sopenharmony_ci list_add_tail((struct list_head *) page, &sclp_con_pages); 1558c2ecf20Sopenharmony_ci return 1; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* 1598c2ecf20Sopenharmony_ci * Writes the given message to S390 system console 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_cistatic void 1628c2ecf20Sopenharmony_cisclp_console_write(struct console *console, const char *message, 1638c2ecf20Sopenharmony_ci unsigned int count) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci unsigned long flags; 1668c2ecf20Sopenharmony_ci void *page; 1678c2ecf20Sopenharmony_ci int written; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (count == 0) 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * process escape characters, write message into buffer, 1748c2ecf20Sopenharmony_ci * send buffer to SCLP 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci do { 1778c2ecf20Sopenharmony_ci /* make sure we have a console output buffer */ 1788c2ecf20Sopenharmony_ci if (sclp_conbuf == NULL) { 1798c2ecf20Sopenharmony_ci if (list_empty(&sclp_con_pages)) 1808c2ecf20Sopenharmony_ci sclp_console_full++; 1818c2ecf20Sopenharmony_ci while (list_empty(&sclp_con_pages)) { 1828c2ecf20Sopenharmony_ci if (sclp_con_suspended) 1838c2ecf20Sopenharmony_ci goto out; 1848c2ecf20Sopenharmony_ci if (sclp_console_drop_buffer()) 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 1878c2ecf20Sopenharmony_ci sclp_sync_wait(); 1888c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci page = sclp_con_pages.next; 1918c2ecf20Sopenharmony_ci list_del((struct list_head *) page); 1928c2ecf20Sopenharmony_ci sclp_conbuf = sclp_make_buffer(page, sclp_con_columns, 1938c2ecf20Sopenharmony_ci sclp_con_width_htab); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci /* try to write the string to the current output buffer */ 1968c2ecf20Sopenharmony_ci written = sclp_write(sclp_conbuf, (const unsigned char *) 1978c2ecf20Sopenharmony_ci message, count); 1988c2ecf20Sopenharmony_ci if (written == count) 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci /* 2018c2ecf20Sopenharmony_ci * Not all characters could be written to the current 2028c2ecf20Sopenharmony_ci * output buffer. Emit the buffer, create a new buffer 2038c2ecf20Sopenharmony_ci * and then output the rest of the string. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 2068c2ecf20Sopenharmony_ci sclp_conbuf_emit(); 2078c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 2088c2ecf20Sopenharmony_ci message += written; 2098c2ecf20Sopenharmony_ci count -= written; 2108c2ecf20Sopenharmony_ci } while (count > 0); 2118c2ecf20Sopenharmony_ci /* Setup timer to output current console buffer after 1/10 second */ 2128c2ecf20Sopenharmony_ci if (sclp_conbuf != NULL && sclp_chars_in_buffer(sclp_conbuf) != 0 && 2138c2ecf20Sopenharmony_ci !timer_pending(&sclp_con_timer)) { 2148c2ecf20Sopenharmony_ci mod_timer(&sclp_con_timer, jiffies + HZ / 10); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ciout: 2178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic struct tty_driver * 2218c2ecf20Sopenharmony_cisclp_console_device(struct console *c, int *index) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci *index = c->index; 2248c2ecf20Sopenharmony_ci return sclp_tty_driver; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/* 2288c2ecf20Sopenharmony_ci * Make sure that all buffers will be flushed to the SCLP. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistatic void 2318c2ecf20Sopenharmony_cisclp_console_flush(void) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci sclp_conbuf_emit(); 2348c2ecf20Sopenharmony_ci sclp_console_sync_queue(); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * Resume console: If there are cached messages, emit them. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_cistatic void sclp_console_resume(void) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci unsigned long flags; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 2458c2ecf20Sopenharmony_ci sclp_con_suspended = 0; 2468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 2478c2ecf20Sopenharmony_ci sclp_conbuf_emit(); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * Suspend console: Set suspend flag and flush console 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_cistatic void sclp_console_suspend(void) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci unsigned long flags; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci spin_lock_irqsave(&sclp_con_lock, flags); 2588c2ecf20Sopenharmony_ci sclp_con_suspended = 1; 2598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sclp_con_lock, flags); 2608c2ecf20Sopenharmony_ci sclp_console_flush(); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int sclp_console_notify(struct notifier_block *self, 2648c2ecf20Sopenharmony_ci unsigned long event, void *data) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci sclp_console_flush(); 2678c2ecf20Sopenharmony_ci return NOTIFY_OK; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic struct notifier_block on_panic_nb = { 2718c2ecf20Sopenharmony_ci .notifier_call = sclp_console_notify, 2728c2ecf20Sopenharmony_ci .priority = SCLP_PANIC_PRIO_CLIENT, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic struct notifier_block on_reboot_nb = { 2768c2ecf20Sopenharmony_ci .notifier_call = sclp_console_notify, 2778c2ecf20Sopenharmony_ci .priority = 1, 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/* 2818c2ecf20Sopenharmony_ci * used to register the SCLP console to the kernel and to 2828c2ecf20Sopenharmony_ci * give printk necessary information 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_cistatic struct console sclp_console = 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci .name = sclp_console_name, 2878c2ecf20Sopenharmony_ci .write = sclp_console_write, 2888c2ecf20Sopenharmony_ci .device = sclp_console_device, 2898c2ecf20Sopenharmony_ci .flags = CON_PRINTBUFFER, 2908c2ecf20Sopenharmony_ci .index = 0 /* ttyS0 */ 2918c2ecf20Sopenharmony_ci}; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* 2948c2ecf20Sopenharmony_ci * This function is called for SCLP suspend and resume events. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_civoid sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci switch (sclp_pm_event) { 2998c2ecf20Sopenharmony_ci case SCLP_PM_EVENT_FREEZE: 3008c2ecf20Sopenharmony_ci sclp_console_suspend(); 3018c2ecf20Sopenharmony_ci break; 3028c2ecf20Sopenharmony_ci case SCLP_PM_EVENT_RESTORE: 3038c2ecf20Sopenharmony_ci case SCLP_PM_EVENT_THAW: 3048c2ecf20Sopenharmony_ci sclp_console_resume(); 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* 3108c2ecf20Sopenharmony_ci * called by console_init() in drivers/char/tty_io.c at boot-time. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_cistatic int __init 3138c2ecf20Sopenharmony_cisclp_console_init(void) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci void *page; 3168c2ecf20Sopenharmony_ci int i; 3178c2ecf20Sopenharmony_ci int rc; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* SCLP consoles are handled together */ 3208c2ecf20Sopenharmony_ci if (!(CONSOLE_IS_SCLP || CONSOLE_IS_VT220)) 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci rc = sclp_rw_init(); 3238c2ecf20Sopenharmony_ci if (rc) 3248c2ecf20Sopenharmony_ci return rc; 3258c2ecf20Sopenharmony_ci /* Allocate pages for output buffering */ 3268c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sclp_con_pages); 3278c2ecf20Sopenharmony_ci for (i = 0; i < sclp_console_pages; i++) { 3288c2ecf20Sopenharmony_ci page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 3298c2ecf20Sopenharmony_ci list_add_tail(page, &sclp_con_pages); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sclp_con_outqueue); 3328c2ecf20Sopenharmony_ci spin_lock_init(&sclp_con_lock); 3338c2ecf20Sopenharmony_ci sclp_conbuf = NULL; 3348c2ecf20Sopenharmony_ci timer_setup(&sclp_con_timer, sclp_console_timeout, 0); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Set output format */ 3378c2ecf20Sopenharmony_ci if (MACHINE_IS_VM) 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * save 4 characters for the CPU number 3408c2ecf20Sopenharmony_ci * written at start of each line by VM/CP 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci sclp_con_columns = 76; 3438c2ecf20Sopenharmony_ci else 3448c2ecf20Sopenharmony_ci sclp_con_columns = 80; 3458c2ecf20Sopenharmony_ci sclp_con_width_htab = 8; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* enable printk-access to this driver */ 3488c2ecf20Sopenharmony_ci atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); 3498c2ecf20Sopenharmony_ci register_reboot_notifier(&on_reboot_nb); 3508c2ecf20Sopenharmony_ci register_console(&sclp_console); 3518c2ecf20Sopenharmony_ci return 0; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciconsole_initcall(sclp_console_init); 355