summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/transport/swd_core.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/src/transport/swd_core.c b/src/transport/swd_core.c
index f4ae8bea..d9431b0a 100644
--- a/src/transport/swd_core.c
+++ b/src/transport/swd_core.c
@@ -114,13 +114,38 @@ int oocd_swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack){
return ERROR_OK;
}
+/** This function flushes all enqueued operations into a hardware interface.
+ * swd_cmdq_flush() is called that calls swd_drv_transmit() which is using
+ * application specific drivers that are linked into target application binary.
+ * Because in SWD each operation is confirmed by Target with ACK answer
+ * we need to react on errors here. OpenOCD was constructed for use with JTAG
+ * and most functions use series of enqueue functions that are later flushed
+ * into a hardware interface with high level dap_run() / oocd_swd_run(), so
+ * this is the only sensible place to place error handling (otherwise code
+ * would need to be changed in lots of places). Caller function simply want
+ * to know if transfer succeeded, so we can perform handling such as retry
+ * on ACK=WAIT unless transfer fail with ACK={FAIL, UNKNOWN}.
+ */
+
int oocd_swd_run(struct adiv5_dap *dap){
- int retval;
- retval=swd_cmdq_flush((swd_ctx_t *)dap->ctx, SWD_OPERATION_EXECUTE);
- if (retval<0){
- LOG_ERROR("swd_cmdq_flush() error: %s", swd_error_string(retval));
- return retval;
- } else return ERROR_OK;
+ int retval, elmcnt=0;
+ swd_ctx_t *swdctx = (swd_ctx_t *)dap->ctx;
+ // This is risky to loop forever... but lets give it a try.
+ while (1) {
+ retval=swd_cmdq_flush(swdctx, &swdctx->cmdq, SWD_OPERATION_EXECUTE);
+ if (retval<0) {
+ LOG_INFO("==========oocd_swd_run(): swd_cmdq_flush() error: %s, trying to recover...", swd_error_string(retval));
+ retval = swd_error_handle((swd_ctx_t*)dap->ctx);
+ if (retval==SWD_ERROR_UNHANDLED){
+ printf("UNANDLED EXCEPTION!\n");
+ sleep(100);
+ return retval;
+ }
+ } else elmcnt+=retval;
+ // retval==0 when nothing more to send.
+ if (retval==0) break;
+ }
+ return ERROR_OK;
}
@@ -153,6 +178,10 @@ int oocd_swd_transport_init(struct command_context *ctx){
}
} else LOG_INFO("Working on existing transport context at 0x%p...", (void *)dap->ctx);
+ /** We disable automatic truncating of queue on error */
+ swd_ctx_t *swdctx=(swd_ctx_t *)dap->ctx;
+ swdctx->config.trunccmdqonerror=0;
+
/**
* Initialize driver and detect target working with selected transport.
* Because we can work on existing context there is no need to destroy it,