.. | .. |
---|
45 | 45 | #ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE |
---|
46 | 46 | #include <linux/rockchip/rockchip_sip.h> |
---|
47 | 47 | #endif |
---|
48 | | - |
---|
49 | | -#define UART_USR 0x1f /* In: UART Status Register */ |
---|
| 48 | +#define UART_USR 0x1f /* In: UART Status Register */ |
---|
50 | 49 | #define UART_USR_RX_FIFO_FULL 0x10 /* Receive FIFO full */ |
---|
51 | 50 | #define UART_USR_RX_FIFO_NOT_EMPTY 0x08 /* Receive FIFO not empty */ |
---|
52 | 51 | #define UART_USR_TX_FIFO_EMPTY 0x04 /* Transmit FIFO empty */ |
---|
53 | 52 | #define UART_USR_TX_FIFO_NOT_FULL 0x02 /* Transmit FIFO not full */ |
---|
54 | 53 | #define UART_USR_BUSY 0x01 /* UART busy indicator */ |
---|
55 | 54 | #define UART_SRR 0x22 /* software reset register */ |
---|
| 55 | +#define RK_UART_RFL 0x21 /* UART Receive Fifo Level Register */ |
---|
56 | 56 | |
---|
57 | 57 | struct rk_fiq_debugger { |
---|
58 | 58 | int irq; |
---|
.. | .. |
---|
150 | 150 | |
---|
151 | 151 | static int debug_getc(struct platform_device *pdev) |
---|
152 | 152 | { |
---|
153 | | - unsigned int lsr; |
---|
| 153 | + unsigned int lsr, usr, rfl, iir; |
---|
154 | 154 | struct rk_fiq_debugger *t; |
---|
155 | 155 | unsigned int temp; |
---|
156 | 156 | static unsigned int n; |
---|
.. | .. |
---|
160 | 160 | /* |
---|
161 | 161 | * Clear uart interrupt status |
---|
162 | 162 | */ |
---|
163 | | - rk_fiq_read(t, UART_USR); |
---|
| 163 | + iir = rk_fiq_read(t, UART_IIR); |
---|
| 164 | + usr = rk_fiq_read(t, UART_USR); |
---|
164 | 165 | lsr = rk_fiq_read_lsr(t); |
---|
| 166 | + |
---|
| 167 | + /* |
---|
| 168 | + * There are ways to get Designware-based UARTs into a state where |
---|
| 169 | + * they are asserting UART_IIR_RX_TIMEOUT but there is no actual |
---|
| 170 | + * data available. If we see such a case then we'll do a bogus |
---|
| 171 | + * read. If we don't do this then the "RX TIMEOUT" interrupt will |
---|
| 172 | + * fire forever. |
---|
| 173 | + */ |
---|
| 174 | + if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { |
---|
| 175 | + rfl = rk_fiq_read(t, RK_UART_RFL); |
---|
| 176 | + if (!(lsr & (UART_LSR_DR | UART_LSR_BI)) && !(usr & 0x1) && (rfl == 0)) |
---|
| 177 | + rk_fiq_read(t, UART_RX); |
---|
| 178 | + } |
---|
165 | 179 | |
---|
166 | 180 | if (lsr & UART_LSR_DR) { |
---|
167 | 181 | temp = rk_fiq_read(t, UART_RX); |
---|
.. | .. |
---|
215 | 229 | |
---|
216 | 230 | #ifdef CONFIG_RK_CONSOLE_THREAD |
---|
217 | 231 | #define FIFO_SIZE SZ_64K |
---|
218 | | -#define LINE_MAX 1024 |
---|
| 232 | +#define TTY_FIFO_SIZE SZ_64K |
---|
219 | 233 | static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE); |
---|
220 | | -static char console_buf[LINE_MAX]; /* avoid FRAME WARN */ |
---|
221 | | -static bool console_thread_stop; |
---|
| 234 | +static DEFINE_KFIFO(tty_fifo, unsigned char, TTY_FIFO_SIZE); |
---|
| 235 | +static bool console_thread_stop; /* write on console_write */ |
---|
| 236 | +static bool console_thread_running; /* write on console_thread */ |
---|
222 | 237 | static unsigned int console_dropped_messages; |
---|
| 238 | + |
---|
| 239 | +static int write_room(struct platform_device *pdev) |
---|
| 240 | +{ |
---|
| 241 | + return (TTY_FIFO_SIZE - kfifo_len(&tty_fifo)); |
---|
| 242 | +} |
---|
223 | 243 | |
---|
224 | 244 | static void console_putc(struct platform_device *pdev, unsigned int c) |
---|
225 | 245 | { |
---|
226 | 246 | struct rk_fiq_debugger *t; |
---|
227 | | - unsigned int count = 500; |
---|
| 247 | + unsigned int count = 2; /* loop 2 times is enough */ |
---|
| 248 | + unsigned long us = 400; /* the time to send 60 byte for baudrate 1500000 */ |
---|
228 | 249 | |
---|
229 | 250 | t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); |
---|
230 | 251 | |
---|
| 252 | + if (t->baudrate == 115200) |
---|
| 253 | + us = 5160; /* the time to send 60 byte for baudrate 115200 */ |
---|
| 254 | + |
---|
231 | 255 | while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) && |
---|
232 | 256 | count--) |
---|
233 | | - usleep_range(200, 210); |
---|
| 257 | + usleep_range(us, us + us / 20); |
---|
234 | 258 | |
---|
235 | 259 | rk_fiq_write(t, c, UART_TX); |
---|
236 | 260 | } |
---|
.. | .. |
---|
238 | 262 | static void console_flush(struct platform_device *pdev) |
---|
239 | 263 | { |
---|
240 | 264 | struct rk_fiq_debugger *t; |
---|
241 | | - unsigned int count = 500; |
---|
| 265 | + unsigned int count = 2; /* loop 2 times is enough */ |
---|
| 266 | + unsigned long us = 428; /* the time to send 64 byte for baudrate 1500000 */ |
---|
242 | 267 | |
---|
243 | 268 | t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); |
---|
244 | 269 | |
---|
| 270 | + if (t->baudrate == 115200) |
---|
| 271 | + us = 5500; /* the time to send 64 byte for baudrate 115200 */ |
---|
| 272 | + |
---|
245 | 273 | while (!(rk_fiq_read_lsr(t) & UART_LSR_TEMT) && count--) |
---|
246 | | - usleep_range(200, 210); |
---|
| 274 | + usleep_range(us, us + us / 20); |
---|
247 | 275 | } |
---|
248 | 276 | |
---|
249 | 277 | static void console_put(struct platform_device *pdev, |
---|
.. | .. |
---|
266 | 294 | } |
---|
267 | 295 | } |
---|
268 | 296 | |
---|
| 297 | +static void wake_up_console_thread(struct task_struct *console_task) |
---|
| 298 | +{ |
---|
| 299 | + /* |
---|
| 300 | + * Avoid dead lock on console_task->pi_lock and console_lock |
---|
| 301 | + * when call printk() in try_to_wake_up(). |
---|
| 302 | + * |
---|
| 303 | + * cpu0 hold console_lock, then try lock pi_lock fail: |
---|
| 304 | + * printk()->vprintk_emit()->console_unlock()->try_to_wake_up() |
---|
| 305 | + * ->lock(pi_lock)->deadlock |
---|
| 306 | + * |
---|
| 307 | + * cpu1 hold pi_lock, then try lock console_lock fail: |
---|
| 308 | + * console_thread()->console_put()->usleep_range()->run_hrtimer() |
---|
| 309 | + * ->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk() |
---|
| 310 | + * ->vprintk_emit()->console_trylock_spining()->cpu_relax()->deadlock |
---|
| 311 | + * |
---|
| 312 | + * if cpu0 does not hold console_lock, cpu1 also deadlock on pi_lock: |
---|
| 313 | + * ...->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk() |
---|
| 314 | + * ->vprintk_emit()->console_unlock()->try_to_wake_up() |
---|
| 315 | + * ->lock(pi_lock)->deadlock |
---|
| 316 | + * |
---|
| 317 | + * so when console_task is running on usleep_range(), printk() |
---|
| 318 | + * should not wakeup console_task to avoid lock(pi_lock) again, |
---|
| 319 | + * as run_hrtimer() will wakeup console_task later. |
---|
| 320 | + * console_thread_running==false guarantee that console_task |
---|
| 321 | + * is not running on usleep_range(). |
---|
| 322 | + */ |
---|
| 323 | + if (!READ_ONCE(console_thread_running)) |
---|
| 324 | + wake_up_process(console_task); |
---|
| 325 | +} |
---|
| 326 | + |
---|
269 | 327 | static int console_thread(void *data) |
---|
270 | 328 | { |
---|
271 | 329 | struct platform_device *pdev = data; |
---|
272 | | - char *buf = console_buf; |
---|
273 | | - unsigned int len; |
---|
| 330 | + char buf[64], c = 0; |
---|
| 331 | + unsigned int len = 0, len_tty = 0; |
---|
274 | 332 | |
---|
275 | 333 | while (1) { |
---|
276 | 334 | unsigned int dropped; |
---|
277 | 335 | |
---|
278 | 336 | set_current_state(TASK_INTERRUPTIBLE); |
---|
279 | | - if (kfifo_is_empty(&fifo)) |
---|
| 337 | + if (console_thread_stop || (kfifo_is_empty(&fifo) && kfifo_is_empty(&tty_fifo))) { |
---|
| 338 | + smp_store_mb(console_thread_running, false); |
---|
280 | 339 | schedule(); |
---|
| 340 | + smp_store_mb(console_thread_running, true); |
---|
| 341 | + } |
---|
281 | 342 | if (kthread_should_stop()) |
---|
282 | 343 | break; |
---|
283 | 344 | set_current_state(TASK_RUNNING); |
---|
284 | | - while (!console_thread_stop) { |
---|
285 | | - len = kfifo_out(&fifo, buf, LINE_MAX); |
---|
286 | | - if (!len) |
---|
287 | | - break; |
---|
288 | | - console_put(pdev, buf, len); |
---|
| 345 | + |
---|
| 346 | + while (!console_thread_stop && (!kfifo_is_empty(&fifo) || !kfifo_is_empty(&tty_fifo))) { |
---|
| 347 | + while (!console_thread_stop && kfifo_get(&fifo, &c)) { |
---|
| 348 | + console_put(pdev, &c, 1); |
---|
| 349 | + if (c == '\n') |
---|
| 350 | + break; |
---|
| 351 | + } |
---|
| 352 | + |
---|
| 353 | + while (!console_thread_stop && kfifo_get(&tty_fifo, &c)) { |
---|
| 354 | + console_putc(pdev, c); |
---|
| 355 | + len_tty++; |
---|
| 356 | + if (c == '\n') |
---|
| 357 | + break; |
---|
| 358 | + } |
---|
289 | 359 | } |
---|
| 360 | + |
---|
| 361 | + if (len_tty > 0) |
---|
| 362 | + fiq_tty_wake_up(pdev); |
---|
| 363 | + len_tty = 0; |
---|
| 364 | + |
---|
290 | 365 | dropped = console_dropped_messages; |
---|
291 | 366 | if (dropped && !console_thread_stop) { |
---|
292 | 367 | console_dropped_messages = 0; |
---|
293 | 368 | smp_wmb(); |
---|
294 | | - len = snprintf(buf, LINE_MAX, |
---|
295 | | - "** %u console messages dropped **\n", |
---|
| 369 | + len = sprintf(buf, "** %u console messages dropped **\n", |
---|
296 | 370 | dropped); |
---|
297 | 371 | console_put(pdev, buf, len); |
---|
298 | 372 | } |
---|
.. | .. |
---|
328 | 402 | } else if (count) { |
---|
329 | 403 | unsigned int ret = 0; |
---|
330 | 404 | |
---|
331 | | - if (kfifo_len(&fifo) + count < FIFO_SIZE) |
---|
| 405 | + if (kfifo_len(&fifo) + count <= FIFO_SIZE) |
---|
332 | 406 | ret = kfifo_in(&fifo, s, count); |
---|
333 | 407 | if (!ret) { |
---|
334 | 408 | console_dropped_messages++; |
---|
335 | 409 | smp_wmb(); |
---|
336 | 410 | } else { |
---|
337 | | - wake_up_process(t->console_task); |
---|
| 411 | + wake_up_console_thread(t->console_task); |
---|
338 | 412 | } |
---|
339 | 413 | } |
---|
340 | 414 | } |
---|
341 | | -#endif |
---|
342 | 415 | |
---|
| 416 | +static int tty_write(struct platform_device *pdev, const char *s, int count) |
---|
| 417 | +{ |
---|
| 418 | + unsigned int ret = 0; |
---|
| 419 | + struct rk_fiq_debugger *t; |
---|
| 420 | + |
---|
| 421 | + if (console_thread_stop) |
---|
| 422 | + return count; |
---|
| 423 | + t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); |
---|
| 424 | + |
---|
| 425 | + if (count > 0) { |
---|
| 426 | + if (kfifo_len(&tty_fifo) + count <= TTY_FIFO_SIZE) |
---|
| 427 | + ret = kfifo_in(&tty_fifo, s, count); |
---|
| 428 | + |
---|
| 429 | + if (ret <= 0) |
---|
| 430 | + return 0; |
---|
| 431 | + wake_up_console_thread(t->console_task); |
---|
| 432 | + } |
---|
| 433 | + return count; |
---|
| 434 | +} |
---|
| 435 | +#endif |
---|
343 | 436 | |
---|
344 | 437 | static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on) |
---|
345 | 438 | { |
---|
.. | .. |
---|
371 | 464 | return rk_fiq_sdei.fiq_en; |
---|
372 | 465 | } |
---|
373 | 466 | |
---|
374 | | -int fiq_sdei_event_callback(u32 event, struct pt_regs *regs, void *arg) |
---|
| 467 | +static int fiq_sdei_event_callback(u32 event, struct pt_regs *regs, void *arg) |
---|
375 | 468 | { |
---|
376 | 469 | int cpu_id = get_logical_index(read_cpuid_mpidr() & |
---|
377 | 470 | MPIDR_HWID_BITMASK); |
---|
.. | .. |
---|
380 | 473 | return 0; |
---|
381 | 474 | } |
---|
382 | 475 | |
---|
383 | | -void rk_fiq_sdei_event_sw_cpu(int wait_disable) |
---|
| 476 | +static void rk_fiq_sdei_event_sw_cpu(int wait_disable) |
---|
384 | 477 | { |
---|
385 | 478 | unsigned long affinity; |
---|
386 | 479 | int cnt = 100000; |
---|
.. | .. |
---|
402 | 495 | rk_fiq_sdei.cur_cpu = rk_fiq_sdei.sw_cpu; |
---|
403 | 496 | } |
---|
404 | 497 | |
---|
405 | | -int fiq_sdei_sw_cpu_event_callback(u32 event, struct pt_regs *regs, void *arg) |
---|
| 498 | +static int fiq_sdei_sw_cpu_event_callback(u32 event, struct pt_regs *regs, void *arg) |
---|
406 | 499 | { |
---|
407 | 500 | int cnt = 10000; |
---|
408 | 501 | int ret = 0; |
---|
.. | .. |
---|
454 | 547 | int cnt = 10000; |
---|
455 | 548 | |
---|
456 | 549 | if (rk_fiq_sdei.cur_cpu == cpu) { |
---|
457 | | - target_cpu = cpumask_first(cpu_online_mask); |
---|
| 550 | + target_cpu = cpumask_any_but(cpu_online_mask, cpu); |
---|
458 | 551 | _rk_fiq_dbg_sdei_switch_cpu(target_cpu, 1); |
---|
459 | 552 | |
---|
460 | 553 | while (rk_fiq_sdei.cur_cpu == cpu && cnt) { |
---|
.. | .. |
---|
495 | 588 | static int fiq_debugger_sdei_enable(struct rk_fiq_debugger *t) |
---|
496 | 589 | { |
---|
497 | 590 | int ret, cpu, i; |
---|
| 591 | + int is_dyn_event = false; |
---|
498 | 592 | |
---|
499 | 593 | ret = sip_fiq_debugger_sdei_get_event_id(&rk_fiq_sdei.event_id, |
---|
500 | 594 | &rk_fiq_sdei.cpu_sw_event_id, |
---|
.. | .. |
---|
503 | 597 | if (ret) { |
---|
504 | 598 | pr_err("%s: get event id error!\n", __func__); |
---|
505 | 599 | return ret; |
---|
| 600 | + } |
---|
| 601 | + |
---|
| 602 | + /* If we can't get a valid fiq event, use dynamic event instead */ |
---|
| 603 | + if (rk_fiq_sdei.event_id == 0) { |
---|
| 604 | + ret = sdei_interrupt_bind(serial_hwirq, &rk_fiq_sdei.event_id); |
---|
| 605 | + if (ret) { |
---|
| 606 | + pr_err("%s: bind intr:%d error!\n", __func__, serial_hwirq); |
---|
| 607 | + return ret; |
---|
| 608 | + } |
---|
| 609 | + |
---|
| 610 | + is_dyn_event = true; |
---|
506 | 611 | } |
---|
507 | 612 | |
---|
508 | 613 | ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, |
---|
.. | .. |
---|
583 | 688 | unregister_pm_notifier(&fiq_dbg_sdei_pm_nb); |
---|
584 | 689 | sdei_event_unregister(rk_fiq_sdei.event_id); |
---|
585 | 690 | |
---|
| 691 | + if (is_dyn_event) |
---|
| 692 | + sdei_interrupt_release(rk_fiq_sdei.event_id); |
---|
| 693 | + |
---|
586 | 694 | return ret; |
---|
587 | 695 | } |
---|
588 | 696 | |
---|
.. | .. |
---|
604 | 712 | sip_fiq_debugger_enable_debug(val); |
---|
605 | 713 | } |
---|
606 | 714 | |
---|
607 | | -static void fiq_debugger_uart_irq_tf(struct pt_regs *_pt_regs, uint32_t cpu) |
---|
| 715 | +static void fiq_debugger_uart_irq_tf(struct pt_regs *_pt_regs, unsigned long cpu) |
---|
608 | 716 | { |
---|
609 | 717 | fiq_debugger_fiq(_pt_regs, cpu); |
---|
610 | 718 | } |
---|
.. | .. |
---|
652 | 760 | |
---|
653 | 761 | if ((sip_fiq_debugger_is_enabled()) && |
---|
654 | 762 | (sip_fiq_debugger_get_target_cpu() == cpu)) { |
---|
655 | | - target_cpu = cpumask_first(cpu_online_mask); |
---|
| 763 | + target_cpu = cpumask_any_but(cpu_online_mask, cpu); |
---|
656 | 764 | sip_fiq_debugger_switch_cpu(target_cpu); |
---|
657 | 765 | } |
---|
658 | 766 | |
---|
.. | .. |
---|
730 | 838 | } |
---|
731 | 839 | #endif |
---|
732 | 840 | |
---|
733 | | -void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base, |
---|
734 | | - int irq, int signal_irq, |
---|
735 | | - int wakeup_irq, unsigned int baudrate) |
---|
| 841 | +static void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base, |
---|
| 842 | + int irq, int signal_irq, |
---|
| 843 | + int wakeup_irq, unsigned int baudrate) |
---|
736 | 844 | { |
---|
737 | 845 | struct rk_fiq_debugger *t = NULL; |
---|
738 | 846 | struct platform_device *pdev = NULL; |
---|
.. | .. |
---|
831 | 939 | |
---|
832 | 940 | #ifdef CONFIG_RK_CONSOLE_THREAD |
---|
833 | 941 | t->console_task = kthread_run(console_thread, pdev, "kconsole"); |
---|
834 | | - if (!IS_ERR(t->console_task)) |
---|
| 942 | + if (!IS_ERR(t->console_task)) { |
---|
835 | 943 | t->pdata.console_write = console_write; |
---|
| 944 | + t->pdata.tty_write = tty_write; |
---|
| 945 | + t->pdata.write_room = write_room; |
---|
| 946 | + } |
---|
836 | 947 | #endif |
---|
837 | 948 | |
---|
838 | 949 | pdev->name = "fiq_debugger"; |
---|
.. | .. |
---|
854 | 965 | kfree(t); |
---|
855 | 966 | } |
---|
856 | 967 | |
---|
857 | | -void rk_serial_debug_init_dummy(void) |
---|
| 968 | +static void rk_serial_debug_init_dummy(void) |
---|
858 | 969 | { |
---|
859 | 970 | struct rk_fiq_debugger *t = NULL; |
---|
860 | 971 | struct platform_device *pdev = NULL; |
---|