fiq_debugger: tty write to tty fifo
It means printf(user) write log to tty fifo, to reduce printf time. Signed-off-by: Huibin Hong <huibin.hong@rock-chips.com> Change-Id: Iaf55719e7089a7c3b3638e2976c97868eed3868e
This commit is contained in:
@ -229,22 +229,32 @@ static void debug_flush(struct platform_device *pdev)
|
||||
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
#define FIFO_SIZE SZ_64K
|
||||
#define LINE_MAX 1024
|
||||
#define TTY_FIFO_SIZE SZ_64K
|
||||
static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE);
|
||||
static char console_buf[LINE_MAX]; /* avoid FRAME WARN */
|
||||
static bool console_thread_stop;
|
||||
static DEFINE_KFIFO(tty_fifo, unsigned char, TTY_FIFO_SIZE);
|
||||
static bool console_thread_stop; /* write on console_write */
|
||||
static bool console_thread_running; /* write on console_thread */
|
||||
static unsigned int console_dropped_messages;
|
||||
|
||||
static int write_room(struct platform_device *pdev)
|
||||
{
|
||||
return (TTY_FIFO_SIZE - kfifo_len(&tty_fifo));
|
||||
}
|
||||
|
||||
static void console_putc(struct platform_device *pdev, unsigned int c)
|
||||
{
|
||||
struct rk_fiq_debugger *t;
|
||||
unsigned int count = 500;
|
||||
unsigned int count = 2; /* loop 2 times is enough */
|
||||
unsigned long us = 400; /* the time to send 60 byte for baudrate 1500000 */
|
||||
|
||||
t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
|
||||
|
||||
if (t->baudrate == 115200)
|
||||
us = 5160; /* the time to send 60 byte for baudrate 115200 */
|
||||
|
||||
while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) &&
|
||||
count--)
|
||||
usleep_range(200, 210);
|
||||
usleep_range(us, us + us / 20);
|
||||
|
||||
rk_fiq_write(t, c, UART_TX);
|
||||
}
|
||||
@ -252,12 +262,16 @@ static void console_putc(struct platform_device *pdev, unsigned int c)
|
||||
static void console_flush(struct platform_device *pdev)
|
||||
{
|
||||
struct rk_fiq_debugger *t;
|
||||
unsigned int count = 500;
|
||||
unsigned int count = 2; /* loop 2 times is enough */
|
||||
unsigned long us = 428; /* the time to send 64 byte for baudrate 1500000 */
|
||||
|
||||
t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
|
||||
|
||||
if (t->baudrate == 115200)
|
||||
us = 5500; /* the time to send 64 byte for baudrate 115200 */
|
||||
|
||||
while (!(rk_fiq_read_lsr(t) & UART_LSR_TEMT) && count--)
|
||||
usleep_range(200, 210);
|
||||
usleep_range(us, us + us / 20);
|
||||
}
|
||||
|
||||
static void console_put(struct platform_device *pdev,
|
||||
@ -280,33 +294,79 @@ static void debug_put(struct platform_device *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void wake_up_console_thread(struct task_struct *console_task)
|
||||
{
|
||||
/*
|
||||
* Avoid dead lock on console_task->pi_lock and console_lock
|
||||
* when call printk() in try_to_wake_up().
|
||||
*
|
||||
* cpu0 hold console_lock, then try lock pi_lock fail:
|
||||
* printk()->vprintk_emit()->console_unlock()->try_to_wake_up()
|
||||
* ->lock(pi_lock)->deadlock
|
||||
*
|
||||
* cpu1 hold pi_lock, then try lock console_lock fail:
|
||||
* console_thread()->console_put()->usleep_range()->run_hrtimer()
|
||||
* ->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
|
||||
* ->vprintk_emit()->console_trylock_spining()->cpu_relax()->deadlock
|
||||
*
|
||||
* if cpu0 does not hold console_lock, cpu1 also deadlock on pi_lock:
|
||||
* ...->hrtimer_wakeup()->try_to_wake_up()[hold_pi_lock]->printk()
|
||||
* ->vprintk_emit()->console_unlock()->try_to_wake_up()
|
||||
* ->lock(pi_lock)->deadlock
|
||||
*
|
||||
* so when console_task is running on usleep_range(), printk()
|
||||
* should not wakeup console_task to avoid lock(pi_lock) again,
|
||||
* as run_hrtimer() will wakeup console_task later.
|
||||
* console_thread_running==false guarantee that console_task
|
||||
* is not running on usleep_range().
|
||||
*/
|
||||
if (!READ_ONCE(console_thread_running))
|
||||
wake_up_process(console_task);
|
||||
}
|
||||
|
||||
static int console_thread(void *data)
|
||||
{
|
||||
struct platform_device *pdev = data;
|
||||
char *buf = console_buf;
|
||||
unsigned int len;
|
||||
char buf[64], c = 0;
|
||||
unsigned int len = 0, len_tty = 0;
|
||||
|
||||
while (1) {
|
||||
unsigned int dropped;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kfifo_is_empty(&fifo))
|
||||
if (console_thread_stop || (kfifo_is_empty(&fifo) && kfifo_is_empty(&tty_fifo))) {
|
||||
smp_store_mb(console_thread_running, false);
|
||||
schedule();
|
||||
smp_store_mb(console_thread_running, true);
|
||||
}
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
set_current_state(TASK_RUNNING);
|
||||
while (!console_thread_stop) {
|
||||
len = kfifo_out(&fifo, buf, LINE_MAX);
|
||||
if (!len)
|
||||
break;
|
||||
console_put(pdev, buf, len);
|
||||
|
||||
while (!console_thread_stop && (!kfifo_is_empty(&fifo) || !kfifo_is_empty(&tty_fifo))) {
|
||||
while (!console_thread_stop && kfifo_get(&fifo, &c)) {
|
||||
console_put(pdev, &c, 1);
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
while (!console_thread_stop && kfifo_get(&tty_fifo, &c)) {
|
||||
console_putc(pdev, c);
|
||||
len_tty++;
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len_tty > 0)
|
||||
fiq_tty_wake_up(pdev);
|
||||
len_tty = 0;
|
||||
|
||||
dropped = console_dropped_messages;
|
||||
if (dropped && !console_thread_stop) {
|
||||
console_dropped_messages = 0;
|
||||
smp_wmb();
|
||||
len = snprintf(buf, LINE_MAX,
|
||||
"** %u console messages dropped **\n",
|
||||
len = sprintf(buf, "** %u console messages dropped **\n",
|
||||
dropped);
|
||||
console_put(pdev, buf, len);
|
||||
}
|
||||
@ -342,18 +402,37 @@ static void console_write(struct platform_device *pdev, const char *s, unsigned
|
||||
} else if (count) {
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (kfifo_len(&fifo) + count < FIFO_SIZE)
|
||||
if (kfifo_len(&fifo) + count <= FIFO_SIZE)
|
||||
ret = kfifo_in(&fifo, s, count);
|
||||
if (!ret) {
|
||||
console_dropped_messages++;
|
||||
smp_wmb();
|
||||
} else {
|
||||
wake_up_process(t->console_task);
|
||||
wake_up_console_thread(t->console_task);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tty_write(struct platform_device *pdev, const char *s, int count)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
struct rk_fiq_debugger *t;
|
||||
|
||||
if (console_thread_stop)
|
||||
return count;
|
||||
t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
|
||||
|
||||
if (count > 0) {
|
||||
if (kfifo_len(&tty_fifo) + count <= TTY_FIFO_SIZE)
|
||||
ret = kfifo_in(&tty_fifo, s, count);
|
||||
|
||||
if (ret <= 0)
|
||||
return 0;
|
||||
wake_up_console_thread(t->console_task);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on)
|
||||
{
|
||||
@ -860,8 +939,11 @@ static void rk_serial_debug_init(void __iomem *base, phys_addr_t phy_base,
|
||||
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
t->console_task = kthread_run(console_thread, pdev, "kconsole");
|
||||
if (!IS_ERR(t->console_task))
|
||||
if (!IS_ERR(t->console_task)) {
|
||||
t->pdata.console_write = console_write;
|
||||
t->pdata.tty_write = tty_write;
|
||||
t->pdata.write_room = write_room;
|
||||
}
|
||||
#endif
|
||||
|
||||
pdev->name = "fiq_debugger";
|
||||
|
||||
@ -1164,6 +1164,15 @@ void fiq_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
tty_port_close(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
void fiq_tty_wake_up(struct platform_device *pdev)
|
||||
{
|
||||
struct fiq_debugger_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
if (tty_port_initialized(&state->tty_port))
|
||||
tty_port_tty_wakeup(&state->tty_port);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fiq_tty_wake_up);
|
||||
|
||||
int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
{
|
||||
int i;
|
||||
@ -1174,6 +1183,11 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
if (!state->console_enable)
|
||||
return count;
|
||||
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
if (state->pdata->tty_write)
|
||||
return state->pdata->tty_write(state->pdev, buf, count);
|
||||
#endif
|
||||
|
||||
fiq_debugger_uart_enable(state);
|
||||
spin_lock_irq(&state->console_lock);
|
||||
for (i = 0; i < count; i++)
|
||||
@ -1186,7 +1200,15 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
|
||||
int fiq_tty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
return 16;
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
int line = tty->index;
|
||||
struct fiq_debugger_state **states = tty->driver->driver_state;
|
||||
struct fiq_debugger_state *state = states[line];
|
||||
|
||||
if (state->pdata->write_room)
|
||||
return state->pdata->write_room(state->pdev);
|
||||
#endif
|
||||
return 2048;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
|
||||
@ -63,6 +63,8 @@ struct fiq_debugger_pdata {
|
||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||
void (*console_write)(struct platform_device *pdev, const char *s,
|
||||
unsigned int count);
|
||||
int (*tty_write)(struct platform_device *pdev, const char *s, int count);
|
||||
int (*write_room)(struct platform_device *pdev);
|
||||
#endif
|
||||
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
|
||||
void (*switch_cpu)(struct platform_device *pdev, u32 cpu);
|
||||
@ -70,4 +72,5 @@ struct fiq_debugger_pdata {
|
||||
#endif
|
||||
};
|
||||
|
||||
void fiq_tty_wake_up(struct platform_device *pdev);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user