diff options
-rw-r--r-- | src/transport/swd_core.c | 41 |
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, |