diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 14:10:41 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 14:10:41 -0400 |
| commit | ac3ee84c604502240122c47b52f0542ec8774f15 (patch) | |
| tree | fa74b50e310af6cef3298a052514b2d42b260d6b /drivers | |
| parent | 90b9a32d8f441369b2f97a765d2d957b531eb653 (diff) | |
| parent | 4fe1da4ebc18c4c42fa56c228447f68033fce5f0 (diff) | |
Merge branch 'dbg-early-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'dbg-early-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb:
echi-dbgp: Add kernel debugger support for the usb debug port
earlyprintk,vga,kdb: Fix \b and \r for earlyprintk=vga with kdb
kgdboc: Add ekgdboc for early use of the kernel debugger
x86,early dr regs,kgdb: Allow kernel debugger early dr register access
x86,kgdb: Implement early hardware breakpoint debugging
x86, kgdb, init: Add early and late debug states
x86, kgdb: early trap init for early debug
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/serial/kgdboc.c | 19 | ||||
| -rw-r--r-- | drivers/usb/early/ehci-dbgp.c | 120 |
2 files changed, 130 insertions, 9 deletions
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index b765ab48dfe7..a9a94ae72349 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c | |||
| @@ -223,6 +223,25 @@ static struct kgdb_io kgdboc_io_ops = { | |||
| 223 | .post_exception = kgdboc_post_exp_handler, | 223 | .post_exception = kgdboc_post_exp_handler, |
| 224 | }; | 224 | }; |
| 225 | 225 | ||
| 226 | #ifdef CONFIG_KGDB_SERIAL_CONSOLE | ||
| 227 | /* This is only available if kgdboc is a built in for early debugging */ | ||
| 228 | int __init kgdboc_early_init(char *opt) | ||
| 229 | { | ||
| 230 | /* save the first character of the config string because the | ||
| 231 | * init routine can destroy it. | ||
| 232 | */ | ||
| 233 | char save_ch; | ||
| 234 | |||
| 235 | kgdboc_option_setup(opt); | ||
| 236 | save_ch = config[0]; | ||
| 237 | init_kgdboc(); | ||
| 238 | config[0] = save_ch; | ||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | early_param("ekgdboc", kgdboc_early_init); | ||
| 243 | #endif /* CONFIG_KGDB_SERIAL_CONSOLE */ | ||
| 244 | |||
| 226 | module_init(init_kgdboc); | 245 | module_init(init_kgdboc); |
| 227 | module_exit(cleanup_kgdboc); | 246 | module_exit(cleanup_kgdboc); |
| 228 | module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); | 247 | module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644); |
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 6e98a3697844..94ecdbc758ce 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c | |||
| @@ -19,6 +19,9 @@ | |||
| 19 | #include <linux/usb/ch9.h> | 19 | #include <linux/usb/ch9.h> |
| 20 | #include <linux/usb/ehci_def.h> | 20 | #include <linux/usb/ehci_def.h> |
| 21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
| 22 | #include <linux/serial_core.h> | ||
| 23 | #include <linux/kgdb.h> | ||
| 24 | #include <linux/kthread.h> | ||
| 22 | #include <asm/io.h> | 25 | #include <asm/io.h> |
| 23 | #include <asm/pci-direct.h> | 26 | #include <asm/pci-direct.h> |
| 24 | #include <asm/fixmap.h> | 27 | #include <asm/fixmap.h> |
| @@ -55,6 +58,7 @@ static struct ehci_regs __iomem *ehci_regs; | |||
| 55 | static struct ehci_dbg_port __iomem *ehci_debug; | 58 | static struct ehci_dbg_port __iomem *ehci_debug; |
| 56 | static int dbgp_not_safe; /* Cannot use debug device during ehci reset */ | 59 | static int dbgp_not_safe; /* Cannot use debug device during ehci reset */ |
| 57 | static unsigned int dbgp_endpoint_out; | 60 | static unsigned int dbgp_endpoint_out; |
| 61 | static unsigned int dbgp_endpoint_in; | ||
| 58 | 62 | ||
| 59 | struct ehci_dev { | 63 | struct ehci_dev { |
| 60 | u32 bus; | 64 | u32 bus; |
| @@ -91,6 +95,13 @@ static inline u32 dbgp_len_update(u32 x, u32 len) | |||
| 91 | return (x & ~0x0f) | (len & 0x0f); | 95 | return (x & ~0x0f) | (len & 0x0f); |
| 92 | } | 96 | } |
| 93 | 97 | ||
| 98 | #ifdef CONFIG_KGDB | ||
| 99 | static struct kgdb_io kgdbdbgp_io_ops; | ||
| 100 | #define dbgp_kgdb_mode (dbg_io_ops == &kgdbdbgp_io_ops) | ||
| 101 | #else | ||
| 102 | #define dbgp_kgdb_mode (0) | ||
| 103 | #endif | ||
| 104 | |||
| 94 | /* | 105 | /* |
| 95 | * USB Packet IDs (PIDs) | 106 | * USB Packet IDs (PIDs) |
| 96 | */ | 107 | */ |
| @@ -182,11 +193,10 @@ static void dbgp_breath(void) | |||
| 182 | /* Sleep to give the debug port a chance to breathe */ | 193 | /* Sleep to give the debug port a chance to breathe */ |
| 183 | } | 194 | } |
| 184 | 195 | ||
| 185 | static int dbgp_wait_until_done(unsigned ctrl) | 196 | static int dbgp_wait_until_done(unsigned ctrl, int loop) |
| 186 | { | 197 | { |
| 187 | u32 pids, lpid; | 198 | u32 pids, lpid; |
| 188 | int ret; | 199 | int ret; |
| 189 | int loop = DBGP_LOOPS; | ||
| 190 | 200 | ||
| 191 | retry: | 201 | retry: |
| 192 | writel(ctrl | DBGP_GO, &ehci_debug->control); | 202 | writel(ctrl | DBGP_GO, &ehci_debug->control); |
| @@ -276,13 +286,13 @@ static int dbgp_bulk_write(unsigned devnum, unsigned endpoint, | |||
| 276 | dbgp_set_data(bytes, size); | 286 | dbgp_set_data(bytes, size); |
| 277 | writel(addr, &ehci_debug->address); | 287 | writel(addr, &ehci_debug->address); |
| 278 | writel(pids, &ehci_debug->pids); | 288 | writel(pids, &ehci_debug->pids); |
| 279 | ret = dbgp_wait_until_done(ctrl); | 289 | ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS); |
| 280 | 290 | ||
| 281 | return ret; | 291 | return ret; |
| 282 | } | 292 | } |
| 283 | 293 | ||
| 284 | static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, | 294 | static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, |
| 285 | int size) | 295 | int size, int loops) |
| 286 | { | 296 | { |
| 287 | u32 pids, addr, ctrl; | 297 | u32 pids, addr, ctrl; |
| 288 | int ret; | 298 | int ret; |
| @@ -302,7 +312,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, | |||
| 302 | 312 | ||
| 303 | writel(addr, &ehci_debug->address); | 313 | writel(addr, &ehci_debug->address); |
| 304 | writel(pids, &ehci_debug->pids); | 314 | writel(pids, &ehci_debug->pids); |
| 305 | ret = dbgp_wait_until_done(ctrl); | 315 | ret = dbgp_wait_until_done(ctrl, loops); |
| 306 | if (ret < 0) | 316 | if (ret < 0) |
| 307 | return ret; | 317 | return ret; |
| 308 | 318 | ||
| @@ -343,12 +353,12 @@ static int dbgp_control_msg(unsigned devnum, int requesttype, | |||
| 343 | dbgp_set_data(&req, sizeof(req)); | 353 | dbgp_set_data(&req, sizeof(req)); |
| 344 | writel(addr, &ehci_debug->address); | 354 | writel(addr, &ehci_debug->address); |
| 345 | writel(pids, &ehci_debug->pids); | 355 | writel(pids, &ehci_debug->pids); |
| 346 | ret = dbgp_wait_until_done(ctrl); | 356 | ret = dbgp_wait_until_done(ctrl, DBGP_LOOPS); |
| 347 | if (ret < 0) | 357 | if (ret < 0) |
| 348 | return ret; | 358 | return ret; |
| 349 | 359 | ||
| 350 | /* Read the result */ | 360 | /* Read the result */ |
| 351 | return dbgp_bulk_read(devnum, 0, data, size); | 361 | return dbgp_bulk_read(devnum, 0, data, size, DBGP_LOOPS); |
| 352 | } | 362 | } |
| 353 | 363 | ||
| 354 | /* Find a PCI capability */ | 364 | /* Find a PCI capability */ |
| @@ -559,6 +569,7 @@ try_again: | |||
| 559 | goto err; | 569 | goto err; |
| 560 | } | 570 | } |
| 561 | dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; | 571 | dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint; |
| 572 | dbgp_endpoint_in = dbgp_desc.bDebugInEndpoint; | ||
| 562 | 573 | ||
| 563 | /* Move the device to 127 if it isn't already there */ | 574 | /* Move the device to 127 if it isn't already there */ |
| 564 | if (devnum != USB_DEBUG_DEVNUM) { | 575 | if (devnum != USB_DEBUG_DEVNUM) { |
| @@ -968,8 +979,9 @@ int dbgp_reset_prep(void) | |||
| 968 | if (!ehci_debug) | 979 | if (!ehci_debug) |
| 969 | return 0; | 980 | return 0; |
| 970 | 981 | ||
| 971 | if (early_dbgp_console.index != -1 && | 982 | if ((early_dbgp_console.index != -1 && |
| 972 | !(early_dbgp_console.flags & CON_BOOT)) | 983 | !(early_dbgp_console.flags & CON_BOOT)) || |
| 984 | dbgp_kgdb_mode) | ||
| 973 | return 1; | 985 | return 1; |
| 974 | /* This means the console is not initialized, or should get | 986 | /* This means the console is not initialized, or should get |
| 975 | * shutdown so as to allow for reuse of the usb device, which | 987 | * shutdown so as to allow for reuse of the usb device, which |
| @@ -982,3 +994,93 @@ int dbgp_reset_prep(void) | |||
| 982 | return 0; | 994 | return 0; |
| 983 | } | 995 | } |
| 984 | EXPORT_SYMBOL_GPL(dbgp_reset_prep); | 996 | EXPORT_SYMBOL_GPL(dbgp_reset_prep); |
| 997 | |||
| 998 | #ifdef CONFIG_KGDB | ||
| 999 | |||
| 1000 | static char kgdbdbgp_buf[DBGP_MAX_PACKET]; | ||
| 1001 | static int kgdbdbgp_buf_sz; | ||
| 1002 | static int kgdbdbgp_buf_idx; | ||
| 1003 | static int kgdbdbgp_loop_cnt = DBGP_LOOPS; | ||
| 1004 | |||
| 1005 | static int kgdbdbgp_read_char(void) | ||
| 1006 | { | ||
| 1007 | int ret; | ||
| 1008 | |||
| 1009 | if (kgdbdbgp_buf_idx < kgdbdbgp_buf_sz) { | ||
| 1010 | char ch = kgdbdbgp_buf[kgdbdbgp_buf_idx++]; | ||
| 1011 | return ch; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | ret = dbgp_bulk_read(USB_DEBUG_DEVNUM, dbgp_endpoint_in, | ||
| 1015 | &kgdbdbgp_buf, DBGP_MAX_PACKET, | ||
| 1016 | kgdbdbgp_loop_cnt); | ||
| 1017 | if (ret <= 0) | ||
| 1018 | return NO_POLL_CHAR; | ||
| 1019 | kgdbdbgp_buf_sz = ret; | ||
| 1020 | kgdbdbgp_buf_idx = 1; | ||
| 1021 | return kgdbdbgp_buf[0]; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | static void kgdbdbgp_write_char(u8 chr) | ||
| 1025 | { | ||
| 1026 | early_dbgp_write(NULL, &chr, 1); | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | static struct kgdb_io kgdbdbgp_io_ops = { | ||
| 1030 | .name = "kgdbdbgp", | ||
| 1031 | .read_char = kgdbdbgp_read_char, | ||
| 1032 | .write_char = kgdbdbgp_write_char, | ||
| 1033 | }; | ||
| 1034 | |||
| 1035 | static int kgdbdbgp_wait_time; | ||
| 1036 | |||
| 1037 | static int __init kgdbdbgp_parse_config(char *str) | ||
| 1038 | { | ||
| 1039 | char *ptr; | ||
| 1040 | |||
| 1041 | if (!ehci_debug) { | ||
| 1042 | if (early_dbgp_init(str)) | ||
| 1043 | return -1; | ||
| 1044 | } | ||
| 1045 | ptr = strchr(str, ','); | ||
| 1046 | if (ptr) { | ||
| 1047 | ptr++; | ||
| 1048 | kgdbdbgp_wait_time = simple_strtoul(ptr, &ptr, 10); | ||
| 1049 | } | ||
| 1050 | kgdb_register_io_module(&kgdbdbgp_io_ops); | ||
| 1051 | kgdbdbgp_io_ops.is_console = early_dbgp_console.index != -1; | ||
| 1052 | |||
| 1053 | return 0; | ||
| 1054 | } | ||
| 1055 | early_param("kgdbdbgp", kgdbdbgp_parse_config); | ||
| 1056 | |||
| 1057 | static int kgdbdbgp_reader_thread(void *ptr) | ||
| 1058 | { | ||
| 1059 | int ret; | ||
| 1060 | |||
| 1061 | while (readl(&ehci_debug->control) & DBGP_ENABLED) { | ||
| 1062 | kgdbdbgp_loop_cnt = 1; | ||
| 1063 | ret = kgdbdbgp_read_char(); | ||
| 1064 | kgdbdbgp_loop_cnt = DBGP_LOOPS; | ||
| 1065 | if (ret != NO_POLL_CHAR) { | ||
| 1066 | if (ret == 0x3 || ret == '$') { | ||
| 1067 | if (ret == '$') | ||
| 1068 | kgdbdbgp_buf_idx--; | ||
| 1069 | kgdb_breakpoint(); | ||
| 1070 | } | ||
| 1071 | continue; | ||
| 1072 | } | ||
| 1073 | schedule_timeout_interruptible(kgdbdbgp_wait_time * HZ); | ||
| 1074 | } | ||
| 1075 | return 0; | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | static int __init kgdbdbgp_start_thread(void) | ||
| 1079 | { | ||
| 1080 | if (dbgp_kgdb_mode && kgdbdbgp_wait_time) | ||
| 1081 | kthread_run(kgdbdbgp_reader_thread, NULL, "%s", "dbgp"); | ||
| 1082 | |||
| 1083 | return 0; | ||
| 1084 | } | ||
| 1085 | module_init(kgdbdbgp_start_thread); | ||
| 1086 | #endif /* CONFIG_KGDB */ | ||
