kgdb,8250,pl011: Return immediately from console poll
The design of the kdb shell requires that every device that can provide input to kdb have a polling routine that exits immediately if there is no character available. This is required in order to get the page scrolling mechanism working. Changing the kernel debugger I/O API to require all polling character routines to exit immediately if there is no data allows the kernel debugger to process multiple input channels. NO_POLL_CHAR will be the return code to the polling routine when ever there is no character available. CC: linux-serial@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
This commit is contained in:
Родитель
dcc7871128
Коммит
f5316b4aea
|
@ -1891,8 +1891,8 @@ static int serial8250_get_poll_char(struct uart_port *port)
|
||||||
struct uart_8250_port *up = (struct uart_8250_port *)port;
|
struct uart_8250_port *up = (struct uart_8250_port *)port;
|
||||||
unsigned char lsr = serial_inp(up, UART_LSR);
|
unsigned char lsr = serial_inp(up, UART_LSR);
|
||||||
|
|
||||||
while (!(lsr & UART_LSR_DR))
|
if (!(lsr & UART_LSR_DR))
|
||||||
lsr = serial_inp(up, UART_LSR);
|
return NO_POLL_CHAR;
|
||||||
|
|
||||||
return serial_inp(up, UART_RX);
|
return serial_inp(up, UART_RX);
|
||||||
}
|
}
|
||||||
|
|
|
@ -342,9 +342,9 @@ static int pl010_get_poll_char(struct uart_port *port)
|
||||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
|
|
||||||
do {
|
status = readw(uap->port.membase + UART01x_FR);
|
||||||
status = readw(uap->port.membase + UART01x_FR);
|
if (status & UART01x_FR_RXFE)
|
||||||
} while (status & UART01x_FR_RXFE);
|
return NO_POLL_CHAR;
|
||||||
|
|
||||||
return readw(uap->port.membase + UART01x_DR);
|
return readw(uap->port.membase + UART01x_DR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
|
|
||||||
#define KDB_POLL_FUNC_MAX 5
|
#define KDB_POLL_FUNC_MAX 5
|
||||||
|
extern int kdb_poll_idx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* kdb_initial_cpu is initialized to -1, and is set to the cpu
|
* kdb_initial_cpu is initialized to -1, and is set to the cpu
|
||||||
|
|
|
@ -246,6 +246,7 @@ struct uart_ops {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NO_POLL_CHAR 0x00ff0000
|
||||||
#define UART_CONFIG_TYPE (1 << 0)
|
#define UART_CONFIG_TYPE (1 << 0)
|
||||||
#define UART_CONFIG_IRQ (1 << 1)
|
#define UART_CONFIG_IRQ (1 << 1)
|
||||||
|
|
||||||
|
|
|
@ -882,6 +882,8 @@ EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
|
||||||
int dbg_io_get_char(void)
|
int dbg_io_get_char(void)
|
||||||
{
|
{
|
||||||
int ret = dbg_io_ops->read_char();
|
int ret = dbg_io_ops->read_char();
|
||||||
|
if (ret == NO_POLL_CHAR)
|
||||||
|
return -1;
|
||||||
if (!dbg_kdb_mode)
|
if (!dbg_kdb_mode)
|
||||||
return ret;
|
return ret;
|
||||||
if (ret == 127)
|
if (ret == 127)
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/kgdb.h>
|
#include <linux/kgdb.h>
|
||||||
|
#include <linux/kdb.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <asm/cacheflush.h>
|
#include <asm/cacheflush.h>
|
||||||
|
@ -62,6 +63,30 @@ static int hex(char ch)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KGDB_KDB
|
||||||
|
static int gdbstub_read_wait(void)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* poll any additional I/O interfaces that are defined */
|
||||||
|
while (ret < 0)
|
||||||
|
for (i = 0; kdb_poll_funcs[i] != NULL; i++) {
|
||||||
|
ret = kdb_poll_funcs[i]();
|
||||||
|
if (ret > 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int gdbstub_read_wait(void)
|
||||||
|
{
|
||||||
|
int ret = dbg_io_ops->read_char();
|
||||||
|
while (ret == NO_POLL_CHAR)
|
||||||
|
ret = dbg_io_ops->read_char();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/* scan for the sequence $<data>#<checksum> */
|
/* scan for the sequence $<data>#<checksum> */
|
||||||
static void get_packet(char *buffer)
|
static void get_packet(char *buffer)
|
||||||
{
|
{
|
||||||
|
@ -75,7 +100,7 @@ static void get_packet(char *buffer)
|
||||||
* Spin and wait around for the start character, ignore all
|
* Spin and wait around for the start character, ignore all
|
||||||
* other characters:
|
* other characters:
|
||||||
*/
|
*/
|
||||||
while ((ch = (dbg_io_ops->read_char())) != '$')
|
while ((ch = (gdbstub_read_wait())) != '$')
|
||||||
/* nothing */;
|
/* nothing */;
|
||||||
|
|
||||||
kgdb_connected = 1;
|
kgdb_connected = 1;
|
||||||
|
@ -88,7 +113,7 @@ static void get_packet(char *buffer)
|
||||||
* now, read until a # or end of buffer is found:
|
* now, read until a # or end of buffer is found:
|
||||||
*/
|
*/
|
||||||
while (count < (BUFMAX - 1)) {
|
while (count < (BUFMAX - 1)) {
|
||||||
ch = dbg_io_ops->read_char();
|
ch = gdbstub_read_wait();
|
||||||
if (ch == '#')
|
if (ch == '#')
|
||||||
break;
|
break;
|
||||||
checksum = checksum + ch;
|
checksum = checksum + ch;
|
||||||
|
@ -98,8 +123,8 @@ static void get_packet(char *buffer)
|
||||||
buffer[count] = 0;
|
buffer[count] = 0;
|
||||||
|
|
||||||
if (ch == '#') {
|
if (ch == '#') {
|
||||||
xmitcsum = hex(dbg_io_ops->read_char()) << 4;
|
xmitcsum = hex(gdbstub_read_wait()) << 4;
|
||||||
xmitcsum += hex(dbg_io_ops->read_char());
|
xmitcsum += hex(gdbstub_read_wait());
|
||||||
|
|
||||||
if (checksum != xmitcsum)
|
if (checksum != xmitcsum)
|
||||||
/* failed checksum */
|
/* failed checksum */
|
||||||
|
@ -144,10 +169,10 @@ static void put_packet(char *buffer)
|
||||||
dbg_io_ops->flush();
|
dbg_io_ops->flush();
|
||||||
|
|
||||||
/* Now see what we get in reply. */
|
/* Now see what we get in reply. */
|
||||||
ch = dbg_io_ops->read_char();
|
ch = gdbstub_read_wait();
|
||||||
|
|
||||||
if (ch == 3)
|
if (ch == 3)
|
||||||
ch = dbg_io_ops->read_char();
|
ch = gdbstub_read_wait();
|
||||||
|
|
||||||
/* If we get an ACK, we are done. */
|
/* If we get an ACK, we are done. */
|
||||||
if (ch == '+')
|
if (ch == '+')
|
||||||
|
|
|
@ -20,7 +20,15 @@
|
||||||
get_char_func kdb_poll_funcs[] = {
|
get_char_func kdb_poll_funcs[] = {
|
||||||
dbg_io_get_char,
|
dbg_io_get_char,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
};
|
};
|
||||||
|
EXPORT_SYMBOL_GPL(kdb_poll_funcs);
|
||||||
|
|
||||||
|
int kdb_poll_idx = 1;
|
||||||
|
EXPORT_SYMBOL_GPL(kdb_poll_idx);
|
||||||
|
|
||||||
int kdb_stub(struct kgdb_state *ks)
|
int kdb_stub(struct kgdb_state *ks)
|
||||||
{
|
{
|
||||||
|
@ -85,6 +93,7 @@ int kdb_stub(struct kgdb_state *ks)
|
||||||
kdb_bp_remove();
|
kdb_bp_remove();
|
||||||
KDB_STATE_CLEAR(DOING_SS);
|
KDB_STATE_CLEAR(DOING_SS);
|
||||||
KDB_STATE_CLEAR(DOING_SSB);
|
KDB_STATE_CLEAR(DOING_SSB);
|
||||||
|
KDB_STATE_SET(PAGER);
|
||||||
/* zero out any offline cpu data */
|
/* zero out any offline cpu data */
|
||||||
for_each_present_cpu(i) {
|
for_each_present_cpu(i) {
|
||||||
if (!cpu_online(i)) {
|
if (!cpu_online(i)) {
|
||||||
|
@ -112,6 +121,7 @@ int kdb_stub(struct kgdb_state *ks)
|
||||||
kdb_initial_cpu = -1;
|
kdb_initial_cpu = -1;
|
||||||
kdb_current_task = NULL;
|
kdb_current_task = NULL;
|
||||||
kdb_current_regs = NULL;
|
kdb_current_regs = NULL;
|
||||||
|
KDB_STATE_CLEAR(PAGER);
|
||||||
kdbnearsym_cleanup();
|
kdbnearsym_cleanup();
|
||||||
if (error == KDB_CMD_KGDB) {
|
if (error == KDB_CMD_KGDB) {
|
||||||
if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) {
|
if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче