|
From: openocd-gerrit <ope...@us...> - 2025-08-24 05:05:11
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Main OpenOCD repository".
The branch, master has been updated
via 1879145bff1b4827f301eeb5039a6a722f3b2d2f (commit)
via b4a19768863825b5acddd6adc3ec44fd04acdea1 (commit)
via fe50eceaff056d366a1f33bc21f59fc830e4ca83 (commit)
from 0c575ced95219f11d554bdf5c34008362fb38f7b (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 1879145bff1b4827f301eeb5039a6a722f3b2d2f
Author: Tomas Vanek <va...@fb...>
Date: Sat Feb 8 22:40:43 2025 +0100
drivers/ch347: limit SWD packet size by processing time
CH347 chip firmware probably does not service USB poll/requests
from the host during processing of SWD packet. If the processing
takes longer than approx 8 ms, USB host disconnects the adapter
from the bus as if it were dead.
To avoid disconnect, compute approximate processing time
of SWD transactions and flush the queue if the total time
gets over the limit (use 7 ms to keep some safety margin).
Allow ch347_swd_send_idle() to split the requested delay
to more partial sequences. It prevents USB disconnect at beginning
of target examine, when memaccess 255 clk is used.
Also memaccess > 255 clk is now possible.
Set the maximal divisor to fit the longest ADI sequence
into 7 ms processing time.
Tested on a linux x64 PC and RPi 5.
Change-Id: Ibdcff4de52e3eb4d86ed83af81a1c64f1f9b5d24
Signed-off-by: Tomas Vanek <va...@fb...>
Reviewed-on: https://review.openocd.org/c/openocd/+/8746
Tested-by: jenkins
Reviewed-by: ZhiYuanNJ <871...@qq...>
diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c
index e420410f1..8f563acaf 100644
--- a/src/jtag/drivers/ch347.c
+++ b/src/jtag/drivers/ch347.c
@@ -115,13 +115,15 @@
#define CH347_CMD_SWD_REG_W 0xA0 // SWD Interface write reg
#define CH347_CMD_SWD_SEQ_W 0xA1 // SWD Interface write spec seq
#define CH347_CMD_SWD_REG_R 0xA2 // SWD Interface read reg
-#define CH347_MAX_SEND_CMD 19 // max send cmd number
-#define CH347_MAX_SEND_BUF 0X200
-#define CH347_MAX_RECV_BUF 0X200
+#define CH347_MAX_PROCESSING_US 7000 // max time in us for packet processing
+ // USB hosts disconnect the adapter if SWD processing takes more!
+#define CH347_MAX_SEND_BUF USBC_PACKET_USBHS
+#define CH347_MAX_RECV_BUF USBC_PACKET_USBHS
#define CH347_MAX_CMD_BUF 128
#define CH347_SWD_CLOCK_MAX 5000
#define CH347_SWD_CLOCK_BASE 1000
-#define CH347_SWD_CLOCK_MAX_DIVISOR 8
+// limited by the longest sequence processing time
+#define CH347_SWD_CLOCK_MAX_DIVISOR (CH347_MAX_PROCESSING_US / swd_seq_dormant_to_swd_len)
#define CH347_EPOUT 0x06u // the usb endpoint number for writing
#define CH347_EPIN 0x86u // the usb endpoint number for reading
@@ -240,6 +242,8 @@ struct ch347_swd_context {
int need_recv_len;
int queued_retval;
int sent_cmd_count;
+ unsigned int clk_divisor;
+ unsigned int total_swd_clk;
struct list_head send_cmd_head;
struct list_head free_cmd_head;
struct ch347_swd_io ch347_cmd_buf[CH347_MAX_CMD_BUF];
@@ -1640,6 +1644,7 @@ static int ch347_swd_init_cmd(uint8_t clock_divisor)
retval = ch347_single_read_get_byte(0, &init_result);
LOG_DEBUG("SWD init clk div %" PRIu8 ", result %02" PRIx8,
clock_divisor, init_result);
+ ch347_swd_context.clk_divisor = clock_divisor;
return retval;
}
@@ -1734,7 +1739,7 @@ static int ch347_speed_get_index(int khz, int *speed_idx)
// Don't allow too low clk speeds: packet processing is limited to ~8 msec
// or triggers host USB disconnect
*speed_idx = MIN(DIV_ROUND_UP(CH347_SWD_CLOCK_BASE, khz),
- CH347_SWD_CLOCK_MAX_DIVISOR);
+ (int)CH347_SWD_CLOCK_MAX_DIVISOR);
}
return ERROR_OK;
}
@@ -1990,6 +1995,7 @@ static void ch347_write_swd_reg(uint8_t cmd, const uint32_t out)
ch347_swd_context.send_buf[ch347_swd_context.send_len++] = parity_u32(out);
// 0xA0 + 1 byte(3bit ACK)
ch347_swd_context.need_recv_len += (1 + 1);
+ ch347_swd_context.total_swd_clk += 46;
}
static void ch347_write_spec_seq(const uint8_t *out, uint8_t out_len)
@@ -2001,6 +2007,7 @@ static void ch347_write_spec_seq(const uint8_t *out, uint8_t out_len)
for (uint8_t i = 0; i < DIV_ROUND_UP(out_len, 8); i++)
ch347_swd_context.send_buf[ch347_swd_context.send_len++] = out ? out[i] : 0x00;
ch347_swd_context.need_recv_len += 1; // 0xA1
+ ch347_swd_context.total_swd_clk += out_len;
}
static void ch347_read_swd_reg(uint8_t cmd)
@@ -2011,6 +2018,7 @@ static void ch347_read_swd_reg(uint8_t cmd)
ch347_swd_context.send_buf[ch347_swd_context.send_len++] = cmd;
// 0xA2 + 1 byte(3bit ACK) + 4 byte(data) + 1 byte(1bit parity+1bit trn)
ch347_swd_context.need_recv_len += 1 + 1 + 4 + 1;
+ ch347_swd_context.total_swd_clk += 46;
}
static int ch347_swd_switch_out(enum swd_special_seq seq, const uint8_t *out, unsigned int out_len)
@@ -2080,22 +2088,81 @@ static int ch347_swd_run_queue_inner(void);
static int ch347_swd_send_idle(uint32_t ap_delay_clk)
{
- struct ch347_swd_io *pswd_io = ch347_get_one_swd_io();
- if (!pswd_io) {
- int retval = ch347_swd_run_queue_inner();
- if (retval != ERROR_OK)
- return retval;
+ bool run_q = false;
+ struct ch347_swd_io *pswd_io = NULL;
+ unsigned int max_processing_clk = ch347_swd_context.clk_divisor
+ ? CH347_MAX_PROCESSING_US / ch347_swd_context.clk_divisor
+ : CH347_MAX_PROCESSING_US * 5;
+ bool more_q_runs =
+ 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8) > CH347_MAX_SEND_BUF
+ && ap_delay_clk > max_processing_clk;
+
+ if (ch347_swd_context.sent_cmd_count) {
+ unsigned int expected_total_clk = ch347_swd_context.total_swd_clk + ap_delay_clk;
+ unsigned int expected_send_len = ch347_swd_context.send_len
+ + 1 + 1 + 1 + DIV_ROUND_UP(ap_delay_clk, 8);
+ // 0xA1 + Len + rev + n byte(delay)
+ unsigned int expected_recv_len = ch347_swd_context.need_recv_len + 1;
+ // 0xA1
+ unsigned int expected_time = ch347_swd_context.clk_divisor
+ ? expected_total_clk * ch347_swd_context.clk_divisor
+ : expected_total_clk / 5;
+ if (expected_time > CH347_MAX_PROCESSING_US
+ || expected_send_len > CH347_MAX_SEND_BUF
+ || expected_recv_len > CH347_MAX_RECV_BUF) {
+ int send_room = CH347_MAX_SEND_BUF - ch347_swd_context.send_len - 1 - 1 - 1;
+ if (more_q_runs
+ && send_room > 0
+ && expected_recv_len <= CH347_MAX_RECV_BUF
+ && ch347_swd_context.total_swd_clk < max_processing_clk) {
+ pswd_io = ch347_get_one_swd_io();
+ if (pswd_io) {
+ // fill the rest of queue/time by part of delay
+ unsigned int this_delay_clk = MIN(ap_delay_clk, 255);
+ if ((unsigned int)send_room * 8 < this_delay_clk)
+ this_delay_clk = send_room * 8;
+ if (max_processing_clk - ch347_swd_context.total_swd_clk < this_delay_clk)
+ this_delay_clk = max_processing_clk - ch347_swd_context.total_swd_clk;
+ LOG_DEBUG_IO("partial delay %u clk", this_delay_clk);
+ ch347_write_spec_seq(NULL, this_delay_clk);
+ list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head);
+ ap_delay_clk -= this_delay_clk;
+ }
+ }
+ run_q = true;
+ }
+ }
+
+ do {
+ if (!run_q)
+ pswd_io = ch347_get_one_swd_io();
- pswd_io = ch347_get_one_swd_io();
if (!pswd_io) {
- LOG_ERROR("ch347 SWD queue not empty after ch347_swd_run_queue");
- ch347_swd_context.queued_retval = ERROR_FAIL;
- return ERROR_FAIL;
+ int retval = ch347_swd_run_queue_inner();
+ if (retval != ERROR_OK)
+ return retval;
+
+ pswd_io = ch347_get_one_swd_io();
+ if (!pswd_io) {
+ LOG_ERROR("ch347 SWD queue not empty after ch347_swd_run_queue");
+ ch347_swd_context.queued_retval = ERROR_FAIL;
+ return ERROR_FAIL;
+ }
}
- }
- ch347_write_spec_seq(NULL, ap_delay_clk);
- list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head);
+ unsigned int send_room = CH347_MAX_SEND_BUF - 1 - 1 - 1;
+ unsigned int this_delay_clk = MIN(ap_delay_clk, 255);
+ if (send_room * 8 < this_delay_clk)
+ this_delay_clk = send_room * 8;
+ if (max_processing_clk < this_delay_clk)
+ this_delay_clk = max_processing_clk;
+ LOG_DEBUG_IO("delay %u clk", this_delay_clk);
+ ch347_write_spec_seq(NULL, this_delay_clk);
+ list_add_tail(&pswd_io->list_entry, &ch347_swd_context.send_cmd_head);
+ ap_delay_clk -= this_delay_clk;
+ run_q = true;
+ pswd_io = NULL;
+ } while (ap_delay_clk);
return ERROR_OK;
}
@@ -2236,6 +2303,7 @@ skip:
ch347_swd_context.need_recv_len = CH347_CMD_HEADER;
ch347_swd_context.recv_len = 0;
ch347_swd_context.sent_cmd_count = 0;
+ ch347_swd_context.total_swd_clk = 0;
retval = ch347_swd_context.queued_retval;
ch347_swd_context.queued_retval = ERROR_OK;
return retval;
@@ -2255,22 +2323,28 @@ static int ch347_swd_run_queue(void)
static int ch347_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint32_t ap_delay_clk)
{
int retval = ERROR_OK;
- if (ap_delay_clk > 255)
- ap_delay_clk = 255; // limit imposed by spec. seq. size in one byte
-
- if (ch347_swd_context.sent_cmd_count >= CH347_MAX_SEND_CMD) {
- retval = ch347_swd_run_queue_inner();
- if (retval != ERROR_OK)
- return retval;
+ bool run_q = false;
+ if (ch347_swd_context.sent_cmd_count) {
+ unsigned int expected_total_clk = ch347_swd_context.total_swd_clk
+ + 46 // SWD transaction
+ + ap_delay_clk
+ + 8; // 8 idle cycles at the end of queue
+ unsigned int expected_time = ch347_swd_context.clk_divisor
+ ? expected_total_clk * ch347_swd_context.clk_divisor
+ : expected_total_clk / 5;
+ if (expected_time > CH347_MAX_PROCESSING_US) {
+ LOG_DEBUG_IO("Expected queue run %u cycles, with this cmd %u",
+ ch347_swd_context.total_swd_clk, expected_total_clk);
+ run_q = true;
+ } else if (!ch347_chk_buf_size(cmd, ap_delay_clk)) {
+ run_q = true;
+ }
}
- if (!ch347_chk_buf_size(cmd, ap_delay_clk)) {
- retval = ch347_swd_run_queue_inner();
- if (retval != ERROR_OK)
- return retval;
- }
+ struct ch347_swd_io *pswd_io = NULL;
+ if (!run_q)
+ pswd_io = ch347_get_one_swd_io();
- struct ch347_swd_io *pswd_io = ch347_get_one_swd_io();
if (!pswd_io) {
retval = ch347_swd_run_queue_inner();
if (retval != ERROR_OK)
commit b4a19768863825b5acddd6adc3ec44fd04acdea1
Author: Tomas Vanek <va...@fb...>
Date: Sun Feb 9 11:35:11 2025 +0100
drivers/ch347: fix SWD log messages
Remove annoying and not too informative error message `ack != SWD_ACK_OK`.
Fix copy&paste error in message `SWD Read data parity mismatch` logged
in case of a write returning bad ack.
Raise log level of read/write descriptive message to DEBUG when reg
read/writes returns bad ack.
Change-Id: Ic3433ae8bd02472756adf269658bfba0ba34dc26
Signed-off-by: Tomas Vanek <va...@fb...>
Reviewed-on: https://review.openocd.org/c/openocd/+/8747
Reviewed-by: ZhiYuanNJ <871...@qq...>
Tested-by: jenkins
diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c
index 57d1d0fdc..e420410f1 100644
--- a/src/jtag/drivers/ch347.c
+++ b/src/jtag/drivers/ch347.c
@@ -2153,13 +2153,25 @@ static int ch347_swd_run_queue_inner(void)
/* Devices do not reply to DP_TARGETSEL write
cmd, ignore received ack */
check_ack = swd_cmd_returns_ack(pswd_io->cmd);
- if (ack != SWD_ACK_OK && check_ack) {
- ch347_swd_context.queued_retval = swd_ack_to_error_code(ack);
- LOG_ERROR("ack != SWD_ACK_OK");
- goto skip;
- }
if (pswd_io->cmd & SWD_CMD_RNW) {
uint32_t data = buf_get_u32(&recv_buf[recv_len], 0, 32);
+
+ LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK)
+ ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO,
+ "%s%s %s read reg %X = %08" PRIx32,
+ check_ack ? "" : "ack ignored ",
+ ack == SWD_ACK_OK ? "OK" :
+ ack == SWD_ACK_WAIT ? "WAIT" :
+ ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
+ pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP",
+ (pswd_io->cmd & SWD_CMD_A32) >> 1,
+ data);
+
+ if (ack != SWD_ACK_OK && check_ack) {
+ ch347_swd_context.queued_retval = swd_ack_to_error_code(ack);
+ goto skip;
+ }
+
uint32_t parity = buf_get_u32(&recv_buf[recv_len], 32, 1);
if (parity != (uint32_t)parity_u32(data)) {
LOG_ERROR("SWD Read data parity mismatch");
@@ -2167,15 +2179,6 @@ static int ch347_swd_run_queue_inner(void)
goto skip;
}
- LOG_DEBUG_IO("%s%s %s %s reg %X = %08X - " PRIx32,
- check_ack ? "" : "ack ignored ",
- ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" :
- ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
- pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP",
- pswd_io->cmd & SWD_CMD_RNW ? "read" : "write",
- (pswd_io->cmd & SWD_CMD_A32) >> 1,
- data);
-
if (pswd_io->dst)
*pswd_io->dst = data;
} else {
@@ -2190,19 +2193,22 @@ static int ch347_swd_run_queue_inner(void)
/* Devices do not reply to DP_TARGETSEL write
cmd, ignore received ack */
check_ack = swd_cmd_returns_ack(pswd_io->cmd);
+
+ LOG_CUSTOM_LEVEL((check_ack && ack != SWD_ACK_OK)
+ ? LOG_LVL_DEBUG : LOG_LVL_DEBUG_IO,
+ "%s%s %s write reg %X = %08" PRIx32,
+ check_ack ? "" : "ack ignored ",
+ ack == SWD_ACK_OK ? "OK" :
+ ack == SWD_ACK_WAIT ? "WAIT" :
+ ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
+ pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP",
+ (pswd_io->cmd & SWD_CMD_A32) >> 1,
+ pswd_io->value);
+
if (ack != SWD_ACK_OK && check_ack) {
ch347_swd_context.queued_retval = swd_ack_to_error_code(ack);
- LOG_ERROR("SWD Read data parity mismatch");
goto skip;
}
- LOG_DEBUG_IO("%s%s %s %s reg %X = %08X - " PRIx32,
- check_ack ? "" : "ack ignored ",
- ack == SWD_ACK_OK ? "OK" : ack == SWD_ACK_WAIT ? "WAIT" :
- ack == SWD_ACK_FAULT ? "FAULT" : "JUNK",
- pswd_io->cmd & SWD_CMD_APNDP ? "AP" : "DP",
- pswd_io->cmd & SWD_CMD_RNW ? "read" : "write",
- (pswd_io->cmd & SWD_CMD_A32) >> 1,
- pswd_io->value);
} else {
ch347_swd_context.queued_retval = ERROR_FAIL;
LOG_ERROR("CH347 usb write/read failed recv_len = %d", recv_len);
commit fe50eceaff056d366a1f33bc21f59fc830e4ca83
Author: Tomas Vanek <va...@fb...>
Date: Sat Feb 8 22:00:40 2025 +0100
drivers/ch347: don't loose swd_read/write_reg errors
SWD read_reg() and write_reg() methods are declared with
void return. Save the error code to ch347_swd_context.queued_retval
(will be returned later by SWD run method) instead of ignoring it.
Change-Id: Ib95a1bc3398712ac2f8520c79d281633d75f0335
Signed-off-by: Tomas Vanek <va...@fb...>
Reviewed-on: https://review.openocd.org/c/openocd/+/8745
Reviewed-by: ZhiYuanNJ <871...@qq...>
Tested-by: jenkins
diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c
index 530ac5096..57d1d0fdc 100644
--- a/src/jtag/drivers/ch347.c
+++ b/src/jtag/drivers/ch347.c
@@ -2333,13 +2333,17 @@ static int ch347_swd_switch_seq(enum swd_special_seq seq)
static void ch347_swd_read_reg(uint8_t cmd, uint32_t *value, uint32_t ap_delay_clk)
{
assert(cmd & SWD_CMD_RNW);
- ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
+ int retval = ch347_swd_queue_cmd(cmd, value, 0, ap_delay_clk);
+ if (retval != ERROR_OK)
+ ch347_swd_context.queued_retval = retval;
}
static void ch347_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
{
assert(!(cmd & SWD_CMD_RNW));
- ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
+ int retval = ch347_swd_queue_cmd(cmd, NULL, value, ap_delay_clk);
+ if (retval != ERROR_OK)
+ ch347_swd_context.queued_retval = retval;
}
static const struct swd_driver ch347_swd = {
-----------------------------------------------------------------------
Summary of changes:
src/jtag/drivers/ch347.c | 194 +++++++++++++++++++++++++++++++++--------------
1 file changed, 139 insertions(+), 55 deletions(-)
hooks/post-receive
--
Main OpenOCD repository
|