commit 3491cb2bfc76504d2fe3c6ee2cb30528d4589c92
parent ae7e5259441321338769bacf0895af7fd604c474
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 21 Jun 2015 02:29:19 -0700
debugger: attempt to auto-recover from swd errors
Diffstat:
3 files changed, 45 insertions(+), 4 deletions(-)
diff --git a/tools/debugger-core.c b/tools/debugger-core.c
@@ -67,6 +67,7 @@ static void m_event(const char *evt) {
 
 static void monitor(void) {
 	u32 v;
+	if (swdp_clear_error()) return;
 	if (swdp_ahb_read(DFSR, &v) == 0) {
 		if (v & DFSR_MASK) {
 			swdp_ahb_write(DFSR, DFSR_MASK);
@@ -84,6 +85,10 @@ static pthread_t _dbg_thread;
 
 void debugger_lock() {
 	pthread_mutex_lock(&_dbg_lock);
+	if (swdp_clear_error()) {
+		xprintf("SWD ERROR persists. Attempting link reset.\n");
+		swdp_reset();
+	}
 }
 
 void debugger_unlock() {
@@ -105,9 +110,13 @@ void debugger_init() {
 
 #else
 
-void debugger_lock() { }
-void debugger_unlock() { }
-void debugger_init() { }
+void debugger_lock() {
+	swdp_clear_error();
+}
+void debugger_unlock() {
+}
+void debugger_init() {
+}
 
 #endif
 
diff --git a/tools/rswdp.c b/tools/rswdp.c
@@ -37,6 +37,8 @@ static u16 sequence = 1;
 
 static usb_handle *usb;
 
+static int swd_error = 0;
+
 #define MAXWORDS 512
 
 struct txn {
@@ -110,7 +112,15 @@ static int process_reply(struct txn *t, u32 *data, int count) {
 			}
 			continue;
 		case CMD_STATUS:
-			return op ? -op : 0;
+			if (op) {
+				if (swd_error == 0) {
+					swd_error = -op;
+					fprintf(stderr, "SWD ERROR\n");
+				}
+				return -op;
+			} else {
+				return 0;
+			}
 		default:
 			fprintf(stderr,"unknown command 0x%02x\n", RSWD_MSG_CMD(msg));
 			return -1;
@@ -505,6 +515,7 @@ int swdp_reset(void) {
 	struct txn t;
 	u32 n, idcode;
 
+	swd_error = 0;
 	q_init(&t);
 	t.tx[t.txc++] = RSWD_MSG(CMD_ATTACH, 0, 0);
 	t.tx[t.txc++] = SWD_RD(DP_IDCODE, 1);
@@ -513,6 +524,7 @@ int swdp_reset(void) {
 
 	fprintf(stderr,"IDCODE: %08x\n", idcode);
 
+	swd_error = 0;
 	q_init(&t);
  	/* clear any stale errors */
 	t.tx[t.txc++] = SWD_WR(DP_ABORT, 1);
@@ -535,6 +547,22 @@ int swdp_reset(void) {
 	return 0;
 }
 
+int swdp_clear_error(void) {
+	if (swd_error == 0) {
+		return 0;
+	} else {
+		struct txn t;
+		swd_error = 0;
+
+		q_init(&t);
+		t.tx[t.txc++] = SWD_WR(DP_ABORT, 1);
+		t.tx[t.txc++] = 0x1E;
+		q_exec(&t);
+
+		return swd_error;
+	}
+}
+
 void swdp_enable_tracing(int yes) {
 	struct txn t;
 	q_init(&t);
diff --git a/tools/rswdp.h b/tools/rswdp.h
@@ -46,6 +46,10 @@ int swdp_watchpoint_rd(unsigned n, u32 addr);
 int swdp_watchpoint_wr(unsigned n, u32 addr);
 int swdp_watchpoint_rw(unsigned n, u32 addr);
 
+/* attempt to clear any error state from previous transactions */
+/* return 0 if successful (or no error state existed) */
+int swdp_clear_error(void);
+
 int swdp_reset(void);
 
 int swdp_open(void);