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
|
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||||
#define FIFO_SIZE SZ_64K
|
#define FIFO_SIZE SZ_64K
|
||||||
#define LINE_MAX 1024
|
#define TTY_FIFO_SIZE SZ_64K
|
||||||
static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE);
|
static DEFINE_KFIFO(fifo, unsigned char, FIFO_SIZE);
|
||||||
static char console_buf[LINE_MAX]; /* avoid FRAME WARN */
|
static DEFINE_KFIFO(tty_fifo, unsigned char, TTY_FIFO_SIZE);
|
||||||
static bool console_thread_stop;
|
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 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)
|
static void console_putc(struct platform_device *pdev, unsigned int c)
|
||||||
{
|
{
|
||||||
struct rk_fiq_debugger *t;
|
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);
|
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) &&
|
while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) &&
|
||||||
count--)
|
count--)
|
||||||
usleep_range(200, 210);
|
usleep_range(us, us + us / 20);
|
||||||
|
|
||||||
rk_fiq_write(t, c, UART_TX);
|
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)
|
static void console_flush(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct rk_fiq_debugger *t;
|
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);
|
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--)
|
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,
|
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)
|
static int console_thread(void *data)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = data;
|
struct platform_device *pdev = data;
|
||||||
char *buf = console_buf;
|
char buf[64], c = 0;
|
||||||
unsigned int len;
|
unsigned int len = 0, len_tty = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
unsigned int dropped;
|
unsigned int dropped;
|
||||||
|
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
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();
|
schedule();
|
||||||
|
smp_store_mb(console_thread_running, true);
|
||||||
|
}
|
||||||
if (kthread_should_stop())
|
if (kthread_should_stop())
|
||||||
break;
|
break;
|
||||||
set_current_state(TASK_RUNNING);
|
set_current_state(TASK_RUNNING);
|
||||||
while (!console_thread_stop) {
|
|
||||||
len = kfifo_out(&fifo, buf, LINE_MAX);
|
while (!console_thread_stop && (!kfifo_is_empty(&fifo) || !kfifo_is_empty(&tty_fifo))) {
|
||||||
if (!len)
|
while (!console_thread_stop && kfifo_get(&fifo, &c)) {
|
||||||
break;
|
console_put(pdev, &c, 1);
|
||||||
console_put(pdev, buf, len);
|
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;
|
dropped = console_dropped_messages;
|
||||||
if (dropped && !console_thread_stop) {
|
if (dropped && !console_thread_stop) {
|
||||||
console_dropped_messages = 0;
|
console_dropped_messages = 0;
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
len = snprintf(buf, LINE_MAX,
|
len = sprintf(buf, "** %u console messages dropped **\n",
|
||||||
"** %u console messages dropped **\n",
|
|
||||||
dropped);
|
dropped);
|
||||||
console_put(pdev, buf, len);
|
console_put(pdev, buf, len);
|
||||||
}
|
}
|
||||||
@ -342,18 +402,37 @@ static void console_write(struct platform_device *pdev, const char *s, unsigned
|
|||||||
} else if (count) {
|
} else if (count) {
|
||||||
unsigned int ret = 0;
|
unsigned int ret = 0;
|
||||||
|
|
||||||
if (kfifo_len(&fifo) + count < FIFO_SIZE)
|
if (kfifo_len(&fifo) + count <= FIFO_SIZE)
|
||||||
ret = kfifo_in(&fifo, s, count);
|
ret = kfifo_in(&fifo, s, count);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
console_dropped_messages++;
|
console_dropped_messages++;
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
} else {
|
} 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)
|
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
|
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||||
t->console_task = kthread_run(console_thread, pdev, "kconsole");
|
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.console_write = console_write;
|
||||||
|
t->pdata.tty_write = tty_write;
|
||||||
|
t->pdata.write_room = write_room;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pdev->name = "fiq_debugger";
|
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);
|
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 fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1174,6 +1183,11 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
|||||||
if (!state->console_enable)
|
if (!state->console_enable)
|
||||||
return count;
|
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);
|
fiq_debugger_uart_enable(state);
|
||||||
spin_lock_irq(&state->console_lock);
|
spin_lock_irq(&state->console_lock);
|
||||||
for (i = 0; i < count; i++)
|
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)
|
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
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
|
|||||||
@ -63,6 +63,8 @@ struct fiq_debugger_pdata {
|
|||||||
#ifdef CONFIG_RK_CONSOLE_THREAD
|
#ifdef CONFIG_RK_CONSOLE_THREAD
|
||||||
void (*console_write)(struct platform_device *pdev, const char *s,
|
void (*console_write)(struct platform_device *pdev, const char *s,
|
||||||
unsigned int count);
|
unsigned int count);
|
||||||
|
int (*tty_write)(struct platform_device *pdev, const char *s, int count);
|
||||||
|
int (*write_room)(struct platform_device *pdev);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
|
#ifdef CONFIG_FIQ_DEBUGGER_TRUST_ZONE
|
||||||
void (*switch_cpu)(struct platform_device *pdev, u32 cpu);
|
void (*switch_cpu)(struct platform_device *pdev, u32 cpu);
|
||||||
@ -70,4 +72,5 @@ struct fiq_debugger_pdata {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void fiq_tty_wake_up(struct platform_device *pdev);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user