0001
0002
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
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
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
0086
0087
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
0096
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
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
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
0131 while (kfifo_get(&outbuf, &ch))
0132 hvc_dcc_put_chars(0, &ch, 1);
0133
0134
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
0148
0149
0150 static void dcc_get_work(struct work_struct *work)
0151 {
0152 unsigned char ch;
0153 unsigned long irqflags;
0154
0155
0156
0157
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
0173
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
0190
0191
0192
0193
0194 if (cpu_online(0))
0195 schedule_work_on(0, &dcc_pwork);
0196
0197 return len;
0198 }
0199
0200
0201
0202
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
0212
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
0230
0231
0232
0233
0234
0235 if (!len && cpu_online(0))
0236 schedule_work_on(0, &dcc_gwork);
0237
0238 return len;
0239 }
0240
0241
0242
0243
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
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);