diff options
Diffstat (limited to 'drivers/usb/early')
-rw-r--r-- | drivers/usb/early/ehci-dbgp.c | 120 |
1 files changed, 111 insertions, 9 deletions
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 */ | ||