From 3c303eb55cd3ebece4f42cd6b8089455f1711b16 Mon Sep 17 00:00:00 2001 From: Tomek CEDRO Date: Thu, 9 Feb 2012 18:42:46 +0100 Subject: EXPERIMENTAL! Introducing infrastructure for automatic retry/error handling by libswd internals. Will change and might not work as expected, feel free to test and feedback results :-) The goal is to have enqueued by openocd operations executed with no need for error handling (which is impossible on multiple operations enqueued and also not supported by openocd anyway) just as they were executed correctly for the first time. Error handling, retries, communication verification, etc should be done by underlying transport library (libswd in this case). swdctx->config.trunccmdqonerror=0 will result in untouched queue on error response from target (before the queue was truncated to make room for manual error handling). work in progres... --- src/transport/swd_core.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'src/transport') 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, -- cgit v1.2.3