aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/early
diff options
context:
space:
mode:
authorJason Wessel <jason.wessel@windriver.com>2010-05-20 22:04:31 -0400
committerJason Wessel <jason.wessel@windriver.com>2010-05-20 22:04:31 -0400
commit4fe1da4ebc18c4c42fa56c228447f68033fce5f0 (patch)
treea21673cf5081db79936f2977f9efed4f7eee93eb /drivers/usb/early
parent61eaf539b9fb4926ed57e38f6545100c3432cf1b (diff)
echi-dbgp: Add kernel debugger support for the usb debug port
This patch adds the capability to use the usb debug port with the kernel debugger. It is also still possible to use this functionality with or without the earlyprintk=dbgpX. It is possible to use the kgdbwait boot argument to debug very early in the kernel start up code. There are two ways to use this driver extension with a kernel boot argument. 1) kgdbdbgp=# -- Where # is the number of the usb debug controller You must use sysrq-g to break into the kernel debugger on another connection type other than the dbgp. 2) kgdbdbgp=#debugControlNum#,#Seconds# In this mode, the usb debug port is polled every #Seconds# for character input. It is possible to use gdb or press control-c to break into the kernel debugger. From the implementation perspective there are 3 high level changes. 1) Allow variable retries for the the hardware via dbgp_bulk_read(). The amount of retries for the dbgp_bulk_read() needed to be variable instead of fixed. We do not want to poll at all when the kernel is operating in interrupt driven mode. The polling only occurs if the kernel was booted when specifying some number of seconds via the kgdbdbgp boot argument (IE kgdbdbgp=0,1). In this case the loop count is reduced to 1 so as introduce the smallest amount of latency as possible. 2) Save the bulk IN endpoint address for use by the kgdb code. 3) The addition of the kgdb interface code. This consisted of adding in a character read function for the dbgp as well as a polling thread to allow the dbgp to interrupt the kernel execution. The rest is the typical kgdb I/O api. CC: Eric Biederman <ebiederm@xmission.com> CC: Yinghai Lu <yhlu.kernel@gmail.com> CC: linux-usb@vger.kernel.org Signed-off-by: Jason Wessel <jason.wessel@windriver.com> Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/early')
-rw-r--r--drivers/usb/early/ehci-dbgp.c120
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;
55static struct ehci_dbg_port __iomem *ehci_debug; 58static struct ehci_dbg_port __iomem *ehci_debug;
56static int dbgp_not_safe; /* Cannot use debug device during ehci reset */ 59static int dbgp_not_safe; /* Cannot use debug device during ehci reset */
57static unsigned int dbgp_endpoint_out; 60static unsigned int dbgp_endpoint_out;
61static unsigned int dbgp_endpoint_in;
58 62
59struct ehci_dev { 63struct 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
99static 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
185static int dbgp_wait_until_done(unsigned ctrl) 196static 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
191retry: 201retry:
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
284static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data, 294static 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}
984EXPORT_SYMBOL_GPL(dbgp_reset_prep); 996EXPORT_SYMBOL_GPL(dbgp_reset_prep);
997
998#ifdef CONFIG_KGDB
999
1000static char kgdbdbgp_buf[DBGP_MAX_PACKET];
1001static int kgdbdbgp_buf_sz;
1002static int kgdbdbgp_buf_idx;
1003static int kgdbdbgp_loop_cnt = DBGP_LOOPS;
1004
1005static 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
1024static void kgdbdbgp_write_char(u8 chr)
1025{
1026 early_dbgp_write(NULL, &chr, 1);
1027}
1028
1029static struct kgdb_io kgdbdbgp_io_ops = {
1030 .name = "kgdbdbgp",
1031 .read_char = kgdbdbgp_read_char,
1032 .write_char = kgdbdbgp_write_char,
1033};
1034
1035static int kgdbdbgp_wait_time;
1036
1037static 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}
1055early_param("kgdbdbgp", kgdbdbgp_parse_config);
1056
1057static 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
1078static 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}
1085module_init(kgdbdbgp_start_thread);
1086#endif /* CONFIG_KGDB */