diff --git a/arch/x86_64/kdb/kdba_io.c b/arch/x86_64/kdb/kdba_io.c index 7170e97..3c7c269 100644 --- a/arch/x86_64/kdb/kdba_io.c +++ b/arch/x86_64/kdb/kdba_io.c @@ -444,6 +444,9 @@ #endif #ifdef CONFIG_KDB_USB get_usb_char, #endif +#if defined(CONFIG_NETCONSOLE) || defined(CONFIG_NETCONSOLE_MODULE) + kdb_get_netpoll_char, +#endif NULL }; diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index bf58db2..b1c91e7 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -46,6 +46,10 @@ #include #include #include +#ifdef CONFIG_KDB +#include +#endif + MODULE_AUTHOR("Maintainer: Matt Mackall "); MODULE_DESCRIPTION("Console driver for network interfaces"); MODULE_LICENSE("GPL"); @@ -60,6 +64,9 @@ static struct netpoll np = { .local_port = 6665, .remote_port = 6666, .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +#ifdef CONFIG_KDB + .rx_hook = kdb_netconsole_rx_hook, +#endif .drop = netpoll_queue, }; static int configured = 0; @@ -115,11 +122,18 @@ static int init_netconsole(void) register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); + +#ifdef CONFIG_KDB + kdb_register_netconsole(&np); +#endif return 0; } static void cleanup_netconsole(void) { +#ifdef CONFIG_KDB + kdb_unregister_netconsole(); +#endif unregister_console(&netconsole); netpoll_cleanup(&np); } diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 098145c..bd3c3f7 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h @@ -15,6 +15,7 @@ #define _KDB_H #include #include #include +#include #include /* These are really private, but they must be defined before including @@ -160,4 +161,8 @@ int kdb_process_cpu(const struct task_st extern const char kdb_serial_str[]; +extern void kdb_register_netconsole(struct netpoll *np); +extern void kdb_unregister_netconsole(void); +extern void kdb_netconsole_rx_hook(struct netpoll *, int source, char *buf, int size); + #endif /* !_KDB_H */ diff --git a/include/linux/kdbprivate.h b/include/linux/kdbprivate.h index 78a939f..ff9a252 100644 --- a/include/linux/kdbprivate.h +++ b/include/linux/kdbprivate.h @@ -489,6 +489,10 @@ #ifndef KDB_RUNNING_PROCESS_ORIGINAL #define KDB_RUNNING_PROCESS_ORIGINAL kdb_running_process #endif +#if defined(CONFIG_NETCONSOLE) || defined(CONFIG_NETCONSOLE_MODULE) +extern int kdb_get_netpoll_char(void); +#endif + extern int kdb_wait_for_cpus_secs; extern void kdba_cpu_up(void); diff --git a/kdb/kdb_io.c b/kdb/kdb_io.c index d271366..6c1f046 100644 --- a/kdb/kdb_io.c +++ b/kdb/kdb_io.c @@ -604,6 +604,100 @@ #endif /* kdba_setjmp */ ; } +#if defined(CONFIG_NETCONSOLE) || defined(CONFIG_NETCONSOLE_MODULE) + +#define RX_ACCUM_SIZE 0x10000 + +static struct netpoll *netconsole_np; +static int netconsole_context; + +static struct { + unsigned char buffer[RX_ACCUM_SIZE]; + int filled; + int read_ptr; + int write_ptr; +} rx_accum; + +void kdb_register_netconsole(struct netpoll *np) +{ + netconsole_np = np; +} + +void kdb_unregister_netconsole(void) +{ + netconsole_np = NULL; +} + +void kdb_netconsole_rx_hook(struct netpoll *np, int source, char *buf, int size) +{ + int partial; + + if (!netconsole_np) + return; + + if (!netconsole_context) + return; + +restart: + if (RX_ACCUM_SIZE - rx_accum.filled < size) + size = RX_ACCUM_SIZE - rx_accum.filled; + + if (size <= 0) + return; + + partial = RX_ACCUM_SIZE - rx_accum.write_ptr; + if (partial < size) { + memcpy(&rx_accum.buffer[rx_accum.write_ptr], buf, partial); + + size -= partial; + rx_accum.filled += partial; + rx_accum.write_ptr = 0; + buf += partial; + goto restart; + } + + memcpy(&rx_accum.buffer[rx_accum.write_ptr], buf, size); + rx_accum.filled += size; + rx_accum.write_ptr += size; +} + +int kdb_get_netpoll_char(void) +{ + int polled = 0; + + do { + if (rx_accum.filled > 0) { + int ret; + + ret = rx_accum.buffer[rx_accum.read_ptr]; + rx_accum.read_ptr += 1; + rx_accum.read_ptr %= RX_ACCUM_SIZE; + rx_accum.filled--; + + return ret; + } + + if (!netconsole_np) + return -1; + + if (polled) + break; + + netconsole_context = 1; + netpoll_poll(netconsole_np); + netconsole_context = 0; + polled++; + } while (1); + + return -1; +} + +EXPORT_SYMBOL(kdb_register_netconsole); +EXPORT_SYMBOL(kdb_unregister_netconsole); +EXPORT_SYMBOL(kdb_netconsole_rx_hook); + +#endif + /* * kdb_io_init *