From 0c6390307115b48e57deeecf0be8f5eca89604ac Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Sat, 10 Jul 2021 22:42:48 +0200 Subject: [PATCH] adiv5: Recover from bad AP access. E.g. AP1 on a STM32WLE5 points to a ROM table, but access to the ROM table via AP1 hangs forever. - Substantial reduce timeout when wait for a response. Valid access should succeed fast. - Abort AP access to free DP for other accesses - Don't throw exception, only set dp->fault - React on higher level --- src/remote.c | 2 ++ src/target/adiv5.c | 28 ++++++++++++---------------- src/target/adiv5.h | 1 + src/target/adiv5_jtagdp.c | 14 +++++++------- src/target/adiv5_swdp.c | 11 ++++++++--- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/remote.c b/src/remote.c index 691f1e9..b86943e 100644 --- a/src/remote.c +++ b/src/remote.c @@ -144,6 +144,7 @@ void remotePacketProcessSWD(uint8_t i, char *packet) if (i==2) { remote_dp.dp_read = firmware_swdp_read; remote_dp.low_access = firmware_swdp_low_access; + remote_dp.abort = firmware_swdp_abort; swdptap_init(&remote_dp); _respond(REMOTE_RESP_OK, 0); } else { @@ -194,6 +195,7 @@ void remotePacketProcessJTAG(uint8_t i, char *packet) case REMOTE_INIT: /* JS = initialise ============================= */ remote_dp.dp_read = fw_adiv5_jtagdp_read; remote_dp.low_access = fw_adiv5_jtagdp_low_access; + remote_dp.abort = adiv5_jtagdp_abort; jtagtap_init(); _respond(REMOTE_RESP_OK, 0); break; diff --git a/src/target/adiv5.c b/src/target/adiv5.c index 06cb09b..1994ea6 100644 --- a/src/target/adiv5.c +++ b/src/target/adiv5.c @@ -414,16 +414,11 @@ static void adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion, if (addr == 0) /* No rom table on this AP */ return; volatile uint32_t cidr; - volatile struct exception e; - TRY_CATCH (e, EXCEPTION_TIMEOUT) { - cidr = adiv5_ap_read_id(ap, addr + CIDR0_OFFSET); - } - if (e.type) { - DEBUG_WARN("CIDR read timeout on AP%d, aborting.\n", num_entry); - adiv5_dp_abort(ap->dp, ADIV5_DP_ABORT_DAPABORT); + cidr = adiv5_ap_read_id(ap, addr + CIDR0_OFFSET); + if (ap->dp->fault) { + DEBUG_WARN("CIDR read timeout on AP%d, aborting.\n", ap->apsel); return; } - if ((cidr & ~CID_CLASS_MASK) != CID_PREAMBLE) return; #if defined(ENABLE_DEBUG) @@ -603,6 +598,15 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel) if(!tmpap.idr) /* IDR Invalid */ return NULL; + tmpap.csw = adiv5_ap_read(&tmpap, ADIV5_AP_CSW) & + ~(ADIV5_AP_CSW_SIZE_MASK | ADIV5_AP_CSW_ADDRINC_MASK); + + if (tmpap.csw & ADIV5_AP_CSW_TRINPROG) { + DEBUG_WARN("AP %d: Transaction in progress. AP is not be usable!\n", + apsel); + return NULL; + } + /* It's valid to so create a heap copy */ ap = malloc(sizeof(*ap)); if (!ap) { /* malloc failed: heap exhaustion */ @@ -612,14 +616,6 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel) memcpy(ap, &tmpap, sizeof(*ap)); - ap->csw = adiv5_ap_read(ap, ADIV5_AP_CSW) & - ~(ADIV5_AP_CSW_SIZE_MASK | ADIV5_AP_CSW_ADDRINC_MASK); - - if (ap->csw & ADIV5_AP_CSW_TRINPROG) { - DEBUG_WARN("AP transaction in progress. Target may not be usable.\n"); - ap->csw &= ~ADIV5_AP_CSW_TRINPROG; - } - #if defined(ENABLE_DEBUG) uint32_t cfg = adiv5_ap_read(ap, ADIV5_AP_CFG); DEBUG_INFO("AP %3d: IDR=%08"PRIx32" CFG=%08"PRIx32" BASE=%08" PRIx32 diff --git a/src/target/adiv5.h b/src/target/adiv5.h index 1d2a227..5a10543 100644 --- a/src/target/adiv5.h +++ b/src/target/adiv5.h @@ -310,4 +310,5 @@ uint32_t fw_adiv5_jtagdp_read(ADIv5_DP_t *dp, uint16_t addr); uint32_t firmware_swdp_error(ADIv5_DP_t *dp); void firmware_swdp_abort(ADIv5_DP_t *dp, uint32_t abort); +void adiv5_jtagdp_abort(ADIv5_DP_t *dp, uint32_t abort); #endif diff --git a/src/target/adiv5_jtagdp.c b/src/target/adiv5_jtagdp.c index 11f11ed..2c87dc7 100644 --- a/src/target/adiv5_jtagdp.c +++ b/src/target/adiv5_jtagdp.c @@ -39,8 +39,6 @@ static uint32_t adiv5_jtagdp_error(ADIv5_DP_t *dp); -static void adiv5_jtagdp_abort(ADIv5_DP_t *dp, uint32_t abort); - void adiv5_jtag_dp_handler(uint8_t jd_index, uint32_t j_idcode) { ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); @@ -87,23 +85,25 @@ uint32_t fw_adiv5_jtagdp_low_access(ADIv5_DP_t *dp, uint8_t RnW, jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, APnDP ? IR_APACC : IR_DPACC); - platform_timeout_set(&timeout, 2000); + platform_timeout_set(&timeout, 20); do { jtag_dev_shift_dr(&jtag_proc, dp->dp_jd_index, (uint8_t*)&response, (uint8_t*)&request, 35); ack = response & 0x07; } while(!platform_timeout_is_expired(&timeout) && (ack == JTAGDP_ACK_WAIT)); - if (ack == JTAGDP_ACK_WAIT) - raise_exception(EXCEPTION_TIMEOUT, "JTAG-DP ACK timeout"); - + if (ack == JTAGDP_ACK_WAIT) { + dp->abort(dp, ADIV5_DP_ABORT_DAPABORT); + dp->fault = 1; + return 0; + } if((ack != JTAGDP_ACK_OK)) raise_exception(EXCEPTION_ERROR, "JTAG-DP invalid ACK"); return (uint32_t)(response >> 3); } -static void adiv5_jtagdp_abort(ADIv5_DP_t *dp, uint32_t abort) +void adiv5_jtagdp_abort(ADIv5_DP_t *dp, uint32_t abort) { uint64_t request = (uint64_t)abort << 3; jtag_dev_write_ir(&jtag_proc, dp->dp_jd_index, IR_ABORT); diff --git a/src/target/adiv5_swdp.c b/src/target/adiv5_swdp.c index 66766fb..9edb5d1 100644 --- a/src/target/adiv5_swdp.c +++ b/src/target/adiv5_swdp.c @@ -93,6 +93,8 @@ int adiv5_swdp_scan(uint32_t targetid) initial_dp->error = firmware_swdp_error; if (!initial_dp->low_access) initial_dp->low_access = firmware_swdp_low_access; + if (!initial_dp->abort) + initial_dp->abort = firmware_swdp_abort; /* DORMANT-> SWD sequence*/ initial_dp->seq_out(0xFFFFFFFF, 32); initial_dp->seq_out(0xFFFFFFFF, 32); @@ -241,7 +243,7 @@ uint32_t firmware_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW, if((addr & ADIV5_APnDP) && dp->fault) return 0; - platform_timeout_set(&timeout, 2000); + platform_timeout_set(&timeout, 20); do { dp->seq_out(request, 8); ack = dp->seq_in(3); @@ -251,8 +253,11 @@ uint32_t firmware_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW, } } while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout)); - if (ack == SWDP_ACK_WAIT) - raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout"); + if (ack == SWDP_ACK_WAIT) { + dp->abort(dp, ADIV5_DP_ABORT_DAPABORT); + dp->fault = 1; + return 0; + } if(ack == SWDP_ACK_FAULT) { dp->fault = 1;