From a8234af06c16500426a421910886d26a46e6fa53 Mon Sep 17 00:00:00 2001
From: David Brownell <dbrownell@users.sourceforge.net>
Date: Thu, 8 Oct 2009 11:14:00 -0700
Subject: [PATCH] prevent abort via polling during jtag_reset

Observed:

  openocd: core.c:318: jtag_checks: Assertion `jtag_trst == 0' failed.

The issue was that nothing disabled background polling during calls
from the TCL shell to "jtag_reset 1 1".  Fix by moving the existing
poll-disable mechanism to the JTAG layer where it belongs, and then
augmenting it to always pay attention to TRST and SRST.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
 src/jtag/core.c     | 26 ++++++++++++++++++++++++++
 src/jtag/jtag.h     | 17 +++++++++++++++++
 src/target/target.c | 17 ++++++++---------
 3 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/src/jtag/core.c b/src/jtag/core.c
index b8235eb1e..bdfd6e5b2 100644
--- a/src/jtag/core.c
+++ b/src/jtag/core.c
@@ -137,6 +137,32 @@ int jtag_error_clear(void)
 	return temp;
 }
 
+/************/
+
+static bool jtag_poll = 1;
+
+bool is_jtag_poll_safe(void)
+{
+	/* Polling can be disabled explicitly with set_enabled(false).
+	 * It is also implicitly disabled while TRST is active and
+	 * while SRST is gating the JTAG clock.
+	 */
+	if (!jtag_poll || jtag_trst != 0)
+		return false;
+	return jtag_srst == 0 || (jtag_reset_config & RESET_SRST_NO_GATING);
+}
+
+bool jtag_poll_get_enabled(void)
+{
+	return jtag_poll;
+}
+
+void jtag_poll_set_enabled(bool value)
+{
+	jtag_poll = value;
+}
+
+/************/
 
 jtag_tap_t *jtag_all_taps(void)
 {
diff --git a/src/jtag/jtag.h b/src/jtag/jtag.h
index 0126b3310..5085445f3 100644
--- a/src/jtag/jtag.h
+++ b/src/jtag/jtag.h
@@ -737,4 +737,21 @@ int jtag_get_error(void);
  */
 int jtag_error_clear(void);
 
+/**
+ * Return true if it's safe for a background polling task to access the
+ * JTAG scan chain.  Polling may be explicitly disallowed, and is also
+ * unsafe while nTRST is active or the JTAG clock is gated off.,
+ */
+bool is_jtag_poll_safe(void);
+
+/**
+ * Return flag reporting whether JTAG polling is disallowed.
+ */
+bool jtag_poll_get_enabled(void);
+
+/**
+ * Assign flag reporting whether JTAG polling is disallowed.
+ */
+void jtag_poll_set_enabled(bool value);
+
 #endif /* JTAG_H */
diff --git a/src/target/target.c b/src/target/target.c
index 253a7e464..ced09e900 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -269,8 +269,6 @@ static int new_target_number(void)
 	return x + 1;
 }
 
-static int target_continuous_poll = 1;
-
 /* read a uint32_t from a buffer in target memory endianness */
 uint32_t target_buffer_get_u32(target_t *target, const uint8_t *buffer)
 {
@@ -436,13 +434,14 @@ int target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mo
 	 * more predictable, i.e. dr/irscan & pathmove in events will
 	 * not have JTAG operations injected into the middle of a sequence.
 	 */
-	int save_poll = target_continuous_poll;
-	target_continuous_poll = 0;
+	bool save_poll = jtag_poll_get_enabled();
+
+	jtag_poll_set_enabled(false);
 
 	sprintf(buf, "ocd_process_reset %s", n->name);
 	retval = Jim_Eval(interp, buf);
 
-	target_continuous_poll = save_poll;
+	jtag_poll_set_enabled(save_poll);
 
 	if (retval != JIM_OK) {
 		Jim_PrintErrorMessage(interp);
@@ -1726,7 +1725,7 @@ int handle_target(void *priv)
 	 * Skip targets that are currently disabled.
 	 */
 	for (target_t *target = all_targets;
-			target_continuous_poll && target;
+			is_jtag_poll_safe() && target;
 			target = target->next)
 	{
 		if (!target->tap->enabled)
@@ -1886,7 +1885,7 @@ static int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, cha
 	if (argc == 0)
 	{
 		command_print(cmd_ctx, "background polling: %s",
-				target_continuous_poll ?  "on" : "off");
+				jtag_poll_get_enabled() ? "on" : "off");
 		command_print(cmd_ctx, "TAP: %s (%s)",
 				target->tap->dotted_name,
 				target->tap->enabled ? "enabled" : "disabled");
@@ -1902,11 +1901,11 @@ static int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, cha
 	{
 		if (strcmp(args[0], "on") == 0)
 		{
-			target_continuous_poll = 1;
+			jtag_poll_set_enabled(true);
 		}
 		else if (strcmp(args[0], "off") == 0)
 		{
-			target_continuous_poll = 0;
+			jtag_poll_set_enabled(false);
 		}
 		else
 		{