Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (c) 2010, 2014, 2022 The Linux Foundation. All rights reserved.  */
0003 
0004 #include <linux/console.h>
0005 #include <linux/cpu.h>
0006 #include <linux/cpumask.h>
0007 #include <linux/init.h>
0008 #include <linux/kfifo.h>
0009 #include <linux/serial.h>
0010 #include <linux/serial_core.h>
0011 #include <linux/smp.h>
0012 #include <linux/spinlock.h>
0013 
0014 #include <asm/dcc.h>
0015 #include <asm/processor.h>
0016 
0017 #include "hvc_console.h"
0018 
0019 /* DCC Status Bits */
0020 #define DCC_STATUS_RX       (1 << 30)
0021 #define DCC_STATUS_TX       (1 << 29)
0022 
0023 #define DCC_INBUF_SIZE      128
0024 #define DCC_OUTBUF_SIZE     1024
0025 
0026 /* Lock to serialize access to DCC fifo */
0027 static DEFINE_SPINLOCK(dcc_lock);
0028 
0029 static DEFINE_KFIFO(inbuf, unsigned char, DCC_INBUF_SIZE);
0030 static DEFINE_KFIFO(outbuf, unsigned char, DCC_OUTBUF_SIZE);
0031 
0032 static void dcc_uart_console_putchar(struct uart_port *port, unsigned char ch)
0033 {
0034     while (__dcc_getstatus() & DCC_STATUS_TX)
0035         cpu_relax();
0036 
0037     __dcc_putchar(ch);
0038 }
0039 
0040 static void dcc_early_write(struct console *con, const char *s, unsigned n)
0041 {
0042     struct earlycon_device *dev = con->data;
0043 
0044     uart_console_write(&dev->port, s, n, dcc_uart_console_putchar);
0045 }
0046 
0047 static int __init dcc_early_console_setup(struct earlycon_device *device,
0048                       const char *opt)
0049 {
0050     device->con->write = dcc_early_write;
0051 
0052     return 0;
0053 }
0054 
0055 EARLYCON_DECLARE(dcc, dcc_early_console_setup);
0056 
0057 static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count)
0058 {
0059     int i;
0060 
0061     for (i = 0; i < count; i++) {
0062         while (__dcc_getstatus() & DCC_STATUS_TX)
0063             cpu_relax();
0064 
0065         __dcc_putchar(buf[i]);
0066     }
0067 
0068     return count;
0069 }
0070 
0071 static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count)
0072 {
0073     int i;
0074 
0075     for (i = 0; i < count; ++i)
0076         if (__dcc_getstatus() & DCC_STATUS_RX)
0077             buf[i] = __dcc_getchar();
0078         else
0079             break;
0080 
0081     return i;
0082 }
0083 
0084 /*
0085  * Check if the DCC is enabled. If CONFIG_HVC_DCC_SERIALIZE_SMP is enabled,
0086  * then we assume then this function will be called first on core0. That way,
0087  * dcc_core0_available will be true only if it's available on core0.
0088  */
0089 static bool hvc_dcc_check(void)
0090 {
0091     unsigned long time = jiffies + (HZ / 10);
0092     static bool dcc_core0_available;
0093 
0094     /*
0095      * If we're not on core 0, but we previously confirmed that DCC is
0096      * active, then just return true.
0097      */
0098     int cpu = get_cpu();
0099 
0100     if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP) && cpu && dcc_core0_available) {
0101         put_cpu();
0102         return true;
0103     }
0104 
0105     put_cpu();
0106 
0107     /* Write a test character to check if it is handled */
0108     __dcc_putchar('\n');
0109 
0110     while (time_is_after_jiffies(time)) {
0111         if (!(__dcc_getstatus() & DCC_STATUS_TX)) {
0112             dcc_core0_available = true;
0113             return true;
0114         }
0115     }
0116 
0117     return false;
0118 }
0119 
0120 /*
0121  * Workqueue function that writes the output FIFO to the DCC on core 0.
0122  */
0123 static void dcc_put_work(struct work_struct *work)
0124 {
0125     unsigned char ch;
0126     unsigned long irqflags;
0127 
0128     spin_lock_irqsave(&dcc_lock, irqflags);
0129 
0130     /* While there's data in the output FIFO, write it to the DCC */
0131     while (kfifo_get(&outbuf, &ch))
0132         hvc_dcc_put_chars(0, &ch, 1);
0133 
0134     /* While we're at it, check for any input characters */
0135     while (!kfifo_is_full(&inbuf)) {
0136         if (!hvc_dcc_get_chars(0, &ch, 1))
0137             break;
0138         kfifo_put(&inbuf, ch);
0139     }
0140 
0141     spin_unlock_irqrestore(&dcc_lock, irqflags);
0142 }
0143 
0144 static DECLARE_WORK(dcc_pwork, dcc_put_work);
0145 
0146 /*
0147  * Workqueue function that reads characters from DCC and puts them into the
0148  * input FIFO.
0149  */
0150 static void dcc_get_work(struct work_struct *work)
0151 {
0152     unsigned char ch;
0153     unsigned long irqflags;
0154 
0155     /*
0156      * Read characters from DCC and put them into the input FIFO, as
0157      * long as there is room and we have characters to read.
0158      */
0159     spin_lock_irqsave(&dcc_lock, irqflags);
0160 
0161     while (!kfifo_is_full(&inbuf)) {
0162         if (!hvc_dcc_get_chars(0, &ch, 1))
0163             break;
0164         kfifo_put(&inbuf, ch);
0165     }
0166     spin_unlock_irqrestore(&dcc_lock, irqflags);
0167 }
0168 
0169 static DECLARE_WORK(dcc_gwork, dcc_get_work);
0170 
0171 /*
0172  * Write characters directly to the DCC if we're on core 0 and the FIFO
0173  * is empty, or write them to the FIFO if we're not.
0174  */
0175 static int hvc_dcc0_put_chars(u32 vt, const char *buf, int count)
0176 {
0177     int len;
0178     unsigned long irqflags;
0179 
0180     if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
0181         return hvc_dcc_put_chars(vt, buf, count);
0182 
0183     spin_lock_irqsave(&dcc_lock, irqflags);
0184     if (smp_processor_id() || (!kfifo_is_empty(&outbuf))) {
0185         len = kfifo_in(&outbuf, buf, count);
0186         spin_unlock_irqrestore(&dcc_lock, irqflags);
0187 
0188         /*
0189          * We just push data to the output FIFO, so schedule the
0190          * workqueue that will actually write that data to DCC.
0191          * CPU hotplug is disabled in dcc_init so CPU0 cannot be
0192          * offlined after the cpu online check.
0193          */
0194         if (cpu_online(0))
0195             schedule_work_on(0, &dcc_pwork);
0196 
0197         return len;
0198     }
0199 
0200     /*
0201      * If we're already on core 0, and the FIFO is empty, then just
0202      * write the data to DCC.
0203      */
0204     len = hvc_dcc_put_chars(vt, buf, count);
0205     spin_unlock_irqrestore(&dcc_lock, irqflags);
0206 
0207     return len;
0208 }
0209 
0210 /*
0211  * Read characters directly from the DCC if we're on core 0 and the FIFO
0212  * is empty, or read them from the FIFO if we're not.
0213  */
0214 static int hvc_dcc0_get_chars(u32 vt, char *buf, int count)
0215 {
0216     int len;
0217     unsigned long irqflags;
0218 
0219     if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
0220         return hvc_dcc_get_chars(vt, buf, count);
0221 
0222     spin_lock_irqsave(&dcc_lock, irqflags);
0223 
0224     if (smp_processor_id() || (!kfifo_is_empty(&inbuf))) {
0225         len = kfifo_out(&inbuf, buf, count);
0226         spin_unlock_irqrestore(&dcc_lock, irqflags);
0227 
0228         /*
0229          * If the FIFO was empty, there may be characters in the DCC
0230          * that we haven't read yet.  Schedule a workqueue to fill
0231          * the input FIFO, so that the next time this function is
0232          * called, we'll have data. CPU hotplug is disabled in dcc_init
0233          * so CPU0 cannot be offlined after the cpu online check.
0234          */
0235         if (!len && cpu_online(0))
0236             schedule_work_on(0, &dcc_gwork);
0237 
0238         return len;
0239     }
0240 
0241     /*
0242      * If we're already on core 0, and the FIFO is empty, then just
0243      * read the data from DCC.
0244      */
0245     len = hvc_dcc_get_chars(vt, buf, count);
0246     spin_unlock_irqrestore(&dcc_lock, irqflags);
0247 
0248     return len;
0249 }
0250 
0251 static const struct hv_ops hvc_dcc_get_put_ops = {
0252     .get_chars = hvc_dcc0_get_chars,
0253     .put_chars = hvc_dcc0_put_chars,
0254 };
0255 
0256 static int __init hvc_dcc_console_init(void)
0257 {
0258     int ret;
0259 
0260     if (!hvc_dcc_check())
0261         return -ENODEV;
0262 
0263     /* Returns -1 if error */
0264     ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
0265 
0266     return ret < 0 ? -ENODEV : 0;
0267 }
0268 console_initcall(hvc_dcc_console_init);
0269 
0270 static int __init hvc_dcc_init(void)
0271 {
0272     struct hvc_struct *p;
0273 
0274     if (!hvc_dcc_check())
0275         return -ENODEV;
0276 
0277     if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP)) {
0278         pr_warn("\n");
0279         pr_warn("********************************************************************\n");
0280         pr_warn("**     NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE           **\n");
0281         pr_warn("**                                                                **\n");
0282         pr_warn("**  HVC_DCC_SERIALIZE_SMP SUPPORT HAS BEEN ENABLED IN THIS KERNEL **\n");
0283         pr_warn("**                                                                **\n");
0284         pr_warn("** This means that this is a DEBUG kernel and unsafe for          **\n");
0285         pr_warn("** production use and has important feature like CPU hotplug      **\n");
0286         pr_warn("** disabled.                                                      **\n");
0287         pr_warn("**                                                                **\n");
0288         pr_warn("** If you see this message and you are not debugging the          **\n");
0289         pr_warn("** kernel, report this immediately to your vendor!                **\n");
0290         pr_warn("**                                                                **\n");
0291         pr_warn("**     NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE           **\n");
0292         pr_warn("********************************************************************\n");
0293 
0294         cpu_hotplug_disable();
0295     }
0296 
0297     p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
0298 
0299     return PTR_ERR_OR_ZERO(p);
0300 }
0301 device_initcall(hvc_dcc_init);