• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2010, 2014, 2022 The Linux Foundation. All rights reserved.  */
3 
4 #include <linux/console.h>
5 #include <linux/cpu.h>
6 #include <linux/cpumask.h>
7 #include <linux/init.h>
8 #include <linux/kfifo.h>
9 #include <linux/moduleparam.h>
10 #include <linux/serial.h>
11 #include <linux/serial_core.h>
12 #include <linux/smp.h>
13 #include <linux/spinlock.h>
14 
15 #include <asm/dcc.h>
16 #include <asm/processor.h>
17 
18 #include "hvc_console.h"
19 
20 /*
21  * Disable DCC driver at runtime. Want driver enabled for GKI, but some devices
22  * do not support the registers and crash when driver pokes the registers
23  */
24 static bool enable;
25 module_param(enable, bool, 0444);
26 
27 /* DCC Status Bits */
28 #define DCC_STATUS_RX		(1 << 30)
29 #define DCC_STATUS_TX		(1 << 29)
30 
31 #define DCC_INBUF_SIZE		128
32 #define DCC_OUTBUF_SIZE		1024
33 
34 /* Lock to serialize access to DCC fifo */
35 static DEFINE_SPINLOCK(dcc_lock);
36 
37 static DEFINE_KFIFO(inbuf, u8, DCC_INBUF_SIZE);
38 static DEFINE_KFIFO(outbuf, u8, DCC_OUTBUF_SIZE);
39 
dcc_uart_console_putchar(struct uart_port * port,u8 ch)40 static void dcc_uart_console_putchar(struct uart_port *port, u8 ch)
41 {
42 	while (__dcc_getstatus() & DCC_STATUS_TX)
43 		cpu_relax();
44 
45 	__dcc_putchar(ch);
46 }
47 
dcc_early_write(struct console * con,const char * s,unsigned n)48 static void dcc_early_write(struct console *con, const char *s, unsigned n)
49 {
50 	struct earlycon_device *dev = con->data;
51 
52 	uart_console_write(&dev->port, s, n, dcc_uart_console_putchar);
53 }
54 
dcc_early_console_setup(struct earlycon_device * device,const char * opt)55 static int __init dcc_early_console_setup(struct earlycon_device *device,
56 					  const char *opt)
57 {
58 	unsigned int count = 0x4000000;
59 
60 	while (--count && (__dcc_getstatus() & DCC_STATUS_TX))
61 		cpu_relax();
62 
63 	if (__dcc_getstatus() & DCC_STATUS_TX)
64 		return -ENODEV;
65 
66 	device->con->write = dcc_early_write;
67 
68 	return 0;
69 }
70 
71 EARLYCON_DECLARE(dcc, dcc_early_console_setup);
72 
hvc_dcc_put_chars(uint32_t vt,const u8 * buf,size_t count)73 static ssize_t hvc_dcc_put_chars(uint32_t vt, const u8 *buf, size_t count)
74 {
75 	size_t i;
76 
77 	for (i = 0; i < count; i++) {
78 		while (__dcc_getstatus() & DCC_STATUS_TX)
79 			cpu_relax();
80 
81 		__dcc_putchar(buf[i]);
82 	}
83 
84 	return count;
85 }
86 
hvc_dcc_get_chars(uint32_t vt,u8 * buf,size_t count)87 static ssize_t hvc_dcc_get_chars(uint32_t vt, u8 *buf, size_t count)
88 {
89 	size_t i;
90 
91 	for (i = 0; i < count; ++i)
92 		if (__dcc_getstatus() & DCC_STATUS_RX)
93 			buf[i] = __dcc_getchar();
94 		else
95 			break;
96 
97 	return i;
98 }
99 
100 /*
101  * Check if the DCC is enabled. If CONFIG_HVC_DCC_SERIALIZE_SMP is enabled,
102  * then we assume then this function will be called first on core0. That way,
103  * dcc_core0_available will be true only if it's available on core0.
104  */
hvc_dcc_check(void)105 static bool hvc_dcc_check(void)
106 {
107 	unsigned long time = jiffies + (HZ / 10);
108 	static bool dcc_core0_available;
109 
110 	/*
111 	 * If we're not on core 0, but we previously confirmed that DCC is
112 	 * active, then just return true.
113 	 */
114 	int cpu = get_cpu();
115 
116 	if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP) && cpu && dcc_core0_available) {
117 		put_cpu();
118 		return true;
119 	}
120 
121 	put_cpu();
122 
123 	/* Write a test character to check if it is handled */
124 	__dcc_putchar('\n');
125 
126 	while (time_is_after_jiffies(time)) {
127 		if (!(__dcc_getstatus() & DCC_STATUS_TX)) {
128 			dcc_core0_available = true;
129 			return true;
130 		}
131 	}
132 
133 	return false;
134 }
135 
136 /*
137  * Workqueue function that writes the output FIFO to the DCC on core 0.
138  */
dcc_put_work(struct work_struct * work)139 static void dcc_put_work(struct work_struct *work)
140 {
141 	unsigned char ch;
142 	unsigned long irqflags;
143 
144 	spin_lock_irqsave(&dcc_lock, irqflags);
145 
146 	/* While there's data in the output FIFO, write it to the DCC */
147 	while (kfifo_get(&outbuf, &ch))
148 		hvc_dcc_put_chars(0, &ch, 1);
149 
150 	/* While we're at it, check for any input characters */
151 	while (!kfifo_is_full(&inbuf)) {
152 		if (!hvc_dcc_get_chars(0, &ch, 1))
153 			break;
154 		kfifo_put(&inbuf, ch);
155 	}
156 
157 	spin_unlock_irqrestore(&dcc_lock, irqflags);
158 }
159 
160 static DECLARE_WORK(dcc_pwork, dcc_put_work);
161 
162 /*
163  * Workqueue function that reads characters from DCC and puts them into the
164  * input FIFO.
165  */
dcc_get_work(struct work_struct * work)166 static void dcc_get_work(struct work_struct *work)
167 {
168 	unsigned long irqflags;
169 	u8 ch;
170 
171 	/*
172 	 * Read characters from DCC and put them into the input FIFO, as
173 	 * long as there is room and we have characters to read.
174 	 */
175 	spin_lock_irqsave(&dcc_lock, irqflags);
176 
177 	while (!kfifo_is_full(&inbuf)) {
178 		if (!hvc_dcc_get_chars(0, &ch, 1))
179 			break;
180 		kfifo_put(&inbuf, ch);
181 	}
182 	spin_unlock_irqrestore(&dcc_lock, irqflags);
183 }
184 
185 static DECLARE_WORK(dcc_gwork, dcc_get_work);
186 
187 /*
188  * Write characters directly to the DCC if we're on core 0 and the FIFO
189  * is empty, or write them to the FIFO if we're not.
190  */
hvc_dcc0_put_chars(u32 vt,const u8 * buf,size_t count)191 static ssize_t hvc_dcc0_put_chars(u32 vt, const u8 *buf, size_t count)
192 {
193 	unsigned long irqflags;
194 	ssize_t len;
195 
196 	if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
197 		return hvc_dcc_put_chars(vt, buf, count);
198 
199 	spin_lock_irqsave(&dcc_lock, irqflags);
200 	if (smp_processor_id() || (!kfifo_is_empty(&outbuf))) {
201 		len = kfifo_in(&outbuf, buf, count);
202 		spin_unlock_irqrestore(&dcc_lock, irqflags);
203 
204 		/*
205 		 * We just push data to the output FIFO, so schedule the
206 		 * workqueue that will actually write that data to DCC.
207 		 * CPU hotplug is disabled in dcc_init so CPU0 cannot be
208 		 * offlined after the cpu online check.
209 		 */
210 		if (cpu_online(0))
211 			schedule_work_on(0, &dcc_pwork);
212 
213 		return len;
214 	}
215 
216 	/*
217 	 * If we're already on core 0, and the FIFO is empty, then just
218 	 * write the data to DCC.
219 	 */
220 	len = hvc_dcc_put_chars(vt, buf, count);
221 	spin_unlock_irqrestore(&dcc_lock, irqflags);
222 
223 	return len;
224 }
225 
226 /*
227  * Read characters directly from the DCC if we're on core 0 and the FIFO
228  * is empty, or read them from the FIFO if we're not.
229  */
hvc_dcc0_get_chars(u32 vt,u8 * buf,size_t count)230 static ssize_t hvc_dcc0_get_chars(u32 vt, u8 *buf, size_t count)
231 {
232 	unsigned long irqflags;
233 	ssize_t len;
234 
235 	if (!IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP))
236 		return hvc_dcc_get_chars(vt, buf, count);
237 
238 	spin_lock_irqsave(&dcc_lock, irqflags);
239 
240 	if (smp_processor_id() || (!kfifo_is_empty(&inbuf))) {
241 		len = kfifo_out(&inbuf, buf, count);
242 		spin_unlock_irqrestore(&dcc_lock, irqflags);
243 
244 		/*
245 		 * If the FIFO was empty, there may be characters in the DCC
246 		 * that we haven't read yet.  Schedule a workqueue to fill
247 		 * the input FIFO, so that the next time this function is
248 		 * called, we'll have data. CPU hotplug is disabled in dcc_init
249 		 * so CPU0 cannot be offlined after the cpu online check.
250 		 */
251 		if (!len && cpu_online(0))
252 			schedule_work_on(0, &dcc_gwork);
253 
254 		return len;
255 	}
256 
257 	/*
258 	 * If we're already on core 0, and the FIFO is empty, then just
259 	 * read the data from DCC.
260 	 */
261 	len = hvc_dcc_get_chars(vt, buf, count);
262 	spin_unlock_irqrestore(&dcc_lock, irqflags);
263 
264 	return len;
265 }
266 
267 static const struct hv_ops hvc_dcc_get_put_ops = {
268 	.get_chars = hvc_dcc0_get_chars,
269 	.put_chars = hvc_dcc0_put_chars,
270 };
271 
hvc_dcc_console_init(void)272 static int __init hvc_dcc_console_init(void)
273 {
274 	int ret;
275 
276 	if (!enable || !hvc_dcc_check())
277 		return -ENODEV;
278 
279 	/* Returns -1 if error */
280 	ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops);
281 
282 	return ret < 0 ? -ENODEV : 0;
283 }
284 console_initcall(hvc_dcc_console_init);
285 
hvc_dcc_init(void)286 static int __init hvc_dcc_init(void)
287 {
288 	struct hvc_struct *p;
289 
290 	if (!enable || !hvc_dcc_check())
291 		return -ENODEV;
292 
293 	if (IS_ENABLED(CONFIG_HVC_DCC_SERIALIZE_SMP)) {
294 		pr_warn("\n");
295 		pr_warn("********************************************************************\n");
296 		pr_warn("**     NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE           **\n");
297 		pr_warn("**                                                                **\n");
298 		pr_warn("**  HVC_DCC_SERIALIZE_SMP SUPPORT HAS BEEN ENABLED IN THIS KERNEL **\n");
299 		pr_warn("**                                                                **\n");
300 		pr_warn("** This means that this is a DEBUG kernel and unsafe for          **\n");
301 		pr_warn("** production use and has important feature like CPU hotplug      **\n");
302 		pr_warn("** disabled.                                                      **\n");
303 		pr_warn("**                                                                **\n");
304 		pr_warn("** If you see this message and you are not debugging the          **\n");
305 		pr_warn("** kernel, report this immediately to your vendor!                **\n");
306 		pr_warn("**                                                                **\n");
307 		pr_warn("**     NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE           **\n");
308 		pr_warn("********************************************************************\n");
309 
310 		cpu_hotplug_disable();
311 	}
312 
313 	p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128);
314 
315 	return PTR_ERR_OR_ZERO(p);
316 }
317 device_initcall(hvc_dcc_init);
318