| .. | .. |
|---|
| 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; |
|---|