Skip to content

Commit f5316b4

Browse files
committed
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>
1 parent dcc7871 commit f5316b4

7 files changed

Lines changed: 50 additions & 11 deletions

File tree

drivers/serial/8250.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,8 +1891,8 @@ static int serial8250_get_poll_char(struct uart_port *port)
18911891
struct uart_8250_port *up = (struct uart_8250_port *)port;
18921892
unsigned char lsr = serial_inp(up, UART_LSR);
18931893

1894-
while (!(lsr & UART_LSR_DR))
1895-
lsr = serial_inp(up, UART_LSR);
1894+
if (!(lsr & UART_LSR_DR))
1895+
return NO_POLL_CHAR;
18961896

18971897
return serial_inp(up, UART_RX);
18981898
}

drivers/serial/amba-pl011.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,9 @@ static int pl010_get_poll_char(struct uart_port *port)
342342
struct uart_amba_port *uap = (struct uart_amba_port *)port;
343343
unsigned int status;
344344

345-
do {
346-
status = readw(uap->port.membase + UART01x_FR);
347-
} while (status & UART01x_FR_RXFE);
345+
status = readw(uap->port.membase + UART01x_FR);
346+
if (status & UART01x_FR_RXFE)
347+
return NO_POLL_CHAR;
348348

349349
return readw(uap->port.membase + UART01x_DR);
350350
}

include/linux/kdb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <asm/atomic.h>
2020

2121
#define KDB_POLL_FUNC_MAX 5
22+
extern int kdb_poll_idx;
2223

2324
/*
2425
* kdb_initial_cpu is initialized to -1, and is set to the cpu

include/linux/serial_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ struct uart_ops {
246246
#endif
247247
};
248248

249+
#define NO_POLL_CHAR 0x00ff0000
249250
#define UART_CONFIG_TYPE (1 << 0)
250251
#define UART_CONFIG_IRQ (1 << 1)
251252

kernel/debug/debug_core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,8 @@ EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
882882
int dbg_io_get_char(void)
883883
{
884884
int ret = dbg_io_ops->read_char();
885+
if (ret == NO_POLL_CHAR)
886+
return -1;
885887
if (!dbg_kdb_mode)
886888
return ret;
887889
if (ret == 127)

kernel/debug/gdbstub.c

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include <linux/kernel.h>
3232
#include <linux/kgdb.h>
33+
#include <linux/kdb.h>
3334
#include <linux/reboot.h>
3435
#include <linux/uaccess.h>
3536
#include <asm/cacheflush.h>
@@ -62,6 +63,30 @@ static int hex(char ch)
6263
return -1;
6364
}
6465

66+
#ifdef CONFIG_KGDB_KDB
67+
static int gdbstub_read_wait(void)
68+
{
69+
int ret = -1;
70+
int i;
71+
72+
/* poll any additional I/O interfaces that are defined */
73+
while (ret < 0)
74+
for (i = 0; kdb_poll_funcs[i] != NULL; i++) {
75+
ret = kdb_poll_funcs[i]();
76+
if (ret > 0)
77+
break;
78+
}
79+
return ret;
80+
}
81+
#else
82+
static int gdbstub_read_wait(void)
83+
{
84+
int ret = dbg_io_ops->read_char();
85+
while (ret == NO_POLL_CHAR)
86+
ret = dbg_io_ops->read_char();
87+
return ret;
88+
}
89+
#endif
6590
/* scan for the sequence $<data>#<checksum> */
6691
static void get_packet(char *buffer)
6792
{
@@ -75,7 +100,7 @@ static void get_packet(char *buffer)
75100
* Spin and wait around for the start character, ignore all
76101
* other characters:
77102
*/
78-
while ((ch = (dbg_io_ops->read_char())) != '$')
103+
while ((ch = (gdbstub_read_wait())) != '$')
79104
/* nothing */;
80105

81106
kgdb_connected = 1;
@@ -88,7 +113,7 @@ static void get_packet(char *buffer)
88113
* now, read until a # or end of buffer is found:
89114
*/
90115
while (count < (BUFMAX - 1)) {
91-
ch = dbg_io_ops->read_char();
116+
ch = gdbstub_read_wait();
92117
if (ch == '#')
93118
break;
94119
checksum = checksum + ch;
@@ -98,8 +123,8 @@ static void get_packet(char *buffer)
98123
buffer[count] = 0;
99124

100125
if (ch == '#') {
101-
xmitcsum = hex(dbg_io_ops->read_char()) << 4;
102-
xmitcsum += hex(dbg_io_ops->read_char());
126+
xmitcsum = hex(gdbstub_read_wait()) << 4;
127+
xmitcsum += hex(gdbstub_read_wait());
103128

104129
if (checksum != xmitcsum)
105130
/* failed checksum */
@@ -144,10 +169,10 @@ static void put_packet(char *buffer)
144169
dbg_io_ops->flush();
145170

146171
/* Now see what we get in reply. */
147-
ch = dbg_io_ops->read_char();
172+
ch = gdbstub_read_wait();
148173

149174
if (ch == 3)
150-
ch = dbg_io_ops->read_char();
175+
ch = gdbstub_read_wait();
151176

152177
/* If we get an ACK, we are done. */
153178
if (ch == '+')

kernel/debug/kdb/kdb_debugger.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,15 @@
2020
get_char_func kdb_poll_funcs[] = {
2121
dbg_io_get_char,
2222
NULL,
23+
NULL,
24+
NULL,
25+
NULL,
26+
NULL,
2327
};
28+
EXPORT_SYMBOL_GPL(kdb_poll_funcs);
29+
30+
int kdb_poll_idx = 1;
31+
EXPORT_SYMBOL_GPL(kdb_poll_idx);
2432

2533
int kdb_stub(struct kgdb_state *ks)
2634
{
@@ -85,6 +93,7 @@ int kdb_stub(struct kgdb_state *ks)
8593
kdb_bp_remove();
8694
KDB_STATE_CLEAR(DOING_SS);
8795
KDB_STATE_CLEAR(DOING_SSB);
96+
KDB_STATE_SET(PAGER);
8897
/* zero out any offline cpu data */
8998
for_each_present_cpu(i) {
9099
if (!cpu_online(i)) {
@@ -112,6 +121,7 @@ int kdb_stub(struct kgdb_state *ks)
112121
kdb_initial_cpu = -1;
113122
kdb_current_task = NULL;
114123
kdb_current_regs = NULL;
124+
KDB_STATE_CLEAR(PAGER);
115125
kdbnearsym_cleanup();
116126
if (error == KDB_CMD_KGDB) {
117127
if (KDB_STATE(DOING_KGDB) || KDB_STATE(DOING_KGDB2)) {

0 commit comments

Comments
 (0)