fix(ch390): restore recovery after emergency reset
Re-sync the CH390 MAC and force a visible link recycle so TCP links are rebuilt after reset instead of staying half-recovered.
This commit is contained in:
+114
-39
@@ -40,12 +40,42 @@ static uint8_t g_ch390_ready;
|
||||
static ch390_diag_t g_diag;
|
||||
static uint8_t g_tx_consecutive_timeout;
|
||||
static uint8_t g_chip_reset_count;
|
||||
static uint8_t g_link_restart_pending;
|
||||
|
||||
#define TX_TIMEOUT_THRESHOLD 3u
|
||||
#define CHIP_RESET_MAX 3u
|
||||
#define TX_BUSY_WAIT_TIMEOUT_MS 10u
|
||||
#define TX_TIMEOUT_RESET_THRESHOLD 6u
|
||||
#define HEALTH_FAIL_THRESHOLD 3u
|
||||
#define RESTART_PENDING_FLAG 0x01u
|
||||
#define HEALTH_FAIL_SHIFT 4u
|
||||
#define HEALTH_FAIL_MASK 0xF0u
|
||||
|
||||
#define TX_TIMEOUT_THRESHOLD 3u
|
||||
#define CHIP_RESET_MAX 3u
|
||||
static bool ch390_mac_address_valid(const uint8_t *mac);
|
||||
|
||||
static uint8_t ch390_runtime_is_restart_pending(void)
|
||||
{
|
||||
return (uint8_t)(g_link_restart_pending & RESTART_PENDING_FLAG);
|
||||
}
|
||||
|
||||
static void ch390_runtime_set_restart_pending(void)
|
||||
{
|
||||
g_link_restart_pending = (uint8_t)(g_link_restart_pending | RESTART_PENDING_FLAG);
|
||||
}
|
||||
|
||||
static void ch390_runtime_clear_restart_pending(void)
|
||||
{
|
||||
g_link_restart_pending = (uint8_t)(g_link_restart_pending & (uint8_t)(~RESTART_PENDING_FLAG));
|
||||
}
|
||||
|
||||
static uint8_t ch390_runtime_get_health_fail_count(void)
|
||||
{
|
||||
return (uint8_t)((g_link_restart_pending & HEALTH_FAIL_MASK) >> HEALTH_FAIL_SHIFT);
|
||||
}
|
||||
|
||||
static void ch390_runtime_set_health_fail_count(uint8_t count)
|
||||
{
|
||||
g_link_restart_pending = (uint8_t)((g_link_restart_pending & (uint8_t)(~HEALTH_FAIL_MASK)) |
|
||||
(uint8_t)((count << HEALTH_FAIL_SHIFT) & HEALTH_FAIL_MASK));
|
||||
}
|
||||
|
||||
static uint8_t ch390_runtime_probe_identity(void)
|
||||
{
|
||||
@@ -76,6 +106,38 @@ static uint8_t ch390_runtime_probe_identity(void)
|
||||
return g_diag.id_valid;
|
||||
}
|
||||
|
||||
static void ch390_runtime_prepare_netif(struct netif *netif)
|
||||
{
|
||||
struct ethernetif *ethernetif;
|
||||
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
netif->mtu = 1500;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
|
||||
|
||||
ethernetif = (struct ethernetif *)netif->state;
|
||||
if (ethernetif != NULL) {
|
||||
ethernetif->rx_len = 0u;
|
||||
ethernetif->rx_status = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
static void ch390_runtime_sync_mac(struct netif *netif)
|
||||
{
|
||||
if (netif == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch390_mac_address_valid(netif->hwaddr)) {
|
||||
ch390_set_mac_address(netif->hwaddr);
|
||||
}
|
||||
|
||||
ch390_get_mac(netif->hwaddr);
|
||||
}
|
||||
|
||||
static void ch390_runtime_refresh_diag(void)
|
||||
{
|
||||
uint8_t id_valid = ch390_runtime_probe_identity();
|
||||
@@ -165,7 +227,7 @@ struct pbuf *ch390_runtime_input_frame(struct netif *netif)
|
||||
return p;
|
||||
}
|
||||
|
||||
bool ch390_mac_address_valid(const uint8_t *mac)
|
||||
static bool ch390_mac_address_valid(const uint8_t *mac)
|
||||
{
|
||||
if (mac == NULL) {
|
||||
return false;
|
||||
@@ -180,8 +242,6 @@ bool ch390_mac_address_valid(const uint8_t *mac)
|
||||
|
||||
void ch390_runtime_init(struct netif *netif, const uint8_t *mac)
|
||||
{
|
||||
struct ethernetif *ethernetif = (struct ethernetif *)netif->state;
|
||||
|
||||
SEGGER_RTT_WriteString(0, "ETH init: gpio\r\n");
|
||||
ch390_gpio_init();
|
||||
SEGGER_RTT_WriteString(0, "ETH init: spi\r\n");
|
||||
@@ -192,13 +252,7 @@ void ch390_runtime_init(struct netif *netif, const uint8_t *mac)
|
||||
SEGGER_RTT_WriteString(0, "ETH init: probe\r\n");
|
||||
g_ch390_ready = ch390_runtime_probe_identity();
|
||||
if (g_ch390_ready == 0u) {
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
netif->mtu = 1500;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
|
||||
|
||||
ethernetif->rx_len = 0u;
|
||||
ethernetif->rx_status = 0u;
|
||||
|
||||
ch390_runtime_prepare_netif(netif);
|
||||
netif_set_link_down(netif);
|
||||
SEGGER_RTT_WriteString(0, "ETH init: invalid chip id\r\n");
|
||||
return;
|
||||
@@ -221,14 +275,9 @@ void ch390_runtime_init(struct netif *netif, const uint8_t *mac)
|
||||
}
|
||||
}
|
||||
|
||||
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||
SEGGER_RTT_WriteString(0, "ETH init: getmac\r\n");
|
||||
ch390_runtime_prepare_netif(netif);
|
||||
ch390_get_mac(netif->hwaddr);
|
||||
netif->mtu = 1500;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
|
||||
|
||||
ethernetif->rx_len = 0u;
|
||||
ethernetif->rx_status = 0u;
|
||||
|
||||
ch390_runtime_refresh_diag();
|
||||
g_ch390_ready = g_diag.id_valid;
|
||||
@@ -306,6 +355,13 @@ void ch390_runtime_check_link(struct netif *netif)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ch390_runtime_is_restart_pending() != 0u) {
|
||||
netif_set_link_down(netif);
|
||||
ch390_runtime_clear_restart_pending();
|
||||
SEGGER_RTT_WriteString(0, "ETH restart pending: hold link down for app recycle\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ch390_runtime_refresh_diag();
|
||||
link_up = (uint8_t)ch390_get_link_status();
|
||||
|
||||
@@ -333,8 +389,6 @@ err_t ch390_runtime_output(struct netif *netif, struct pbuf *p)
|
||||
struct pbuf *q;
|
||||
uint32_t start_tick;
|
||||
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
|
||||
if (!g_ch390_ready) {
|
||||
LINK_STATS_INC(link.drop);
|
||||
return ERR_IF;
|
||||
@@ -346,15 +400,17 @@ err_t ch390_runtime_output(struct netif *netif, struct pbuf *p)
|
||||
|
||||
start_tick = HAL_GetTick();
|
||||
while (ch390_read_reg(CH390_TCR) & TCR_TXREQ) {
|
||||
if ((HAL_GetTick() - start_tick) > 10u) {
|
||||
if ((HAL_GetTick() - start_tick) > TX_BUSY_WAIT_TIMEOUT_MS) {
|
||||
#if ETH_PAD_SIZE
|
||||
pbuf_add_header(p, ETH_PAD_SIZE);
|
||||
#endif
|
||||
LINK_STATS_INC(link.drop);
|
||||
g_diag.tx_packets_timeout++;
|
||||
g_tx_consecutive_timeout++;
|
||||
if (g_tx_consecutive_timeout >= TX_TIMEOUT_THRESHOLD) {
|
||||
ch390_runtime_emergency_reset();
|
||||
if (g_tx_consecutive_timeout < 0xFFu) {
|
||||
g_tx_consecutive_timeout++;
|
||||
}
|
||||
if (g_tx_consecutive_timeout >= TX_TIMEOUT_RESET_THRESHOLD) {
|
||||
(void)ch390_runtime_emergency_reset(netif);
|
||||
}
|
||||
return ERR_TIMEOUT;
|
||||
}
|
||||
@@ -392,23 +448,26 @@ bool ch390_runtime_is_ready(void)
|
||||
return g_ch390_ready != 0u;
|
||||
}
|
||||
|
||||
bool ch390_runtime_emergency_reset(void)
|
||||
bool ch390_runtime_emergency_reset(struct netif *netif)
|
||||
{
|
||||
SEGGER_RTT_printf(0, "ETH emergency reset (tx_timeout=%u resets=%u/%u)\r\n",
|
||||
g_tx_consecutive_timeout, g_chip_reset_count, CHIP_RESET_MAX);
|
||||
SEGGER_RTT_printf(0, "ETH emergency reset (tx_timeout=%u resets=%u)\r\n",
|
||||
g_tx_consecutive_timeout, g_chip_reset_count);
|
||||
|
||||
if (g_chip_reset_count >= CHIP_RESET_MAX) {
|
||||
SEGGER_RTT_WriteString(0, "ETH: max resets reached, giving up\r\n");
|
||||
g_ch390_ready = 0u;
|
||||
return false;
|
||||
if (netif != NULL) {
|
||||
netif_set_link_down(netif);
|
||||
}
|
||||
|
||||
g_chip_reset_count++;
|
||||
if (g_chip_reset_count < 0xFFu) {
|
||||
g_chip_reset_count++;
|
||||
}
|
||||
g_tx_consecutive_timeout = 0u;
|
||||
|
||||
ch390_software_reset();
|
||||
ch390_delay_us(5000u);
|
||||
ch390_default_config();
|
||||
ch390_runtime_prepare_netif(netif);
|
||||
ch390_runtime_sync_mac(netif);
|
||||
g_ch390_irq_pending = 0u;
|
||||
|
||||
ch390_runtime_refresh_diag();
|
||||
g_ch390_ready = g_diag.id_valid;
|
||||
@@ -418,24 +477,40 @@ bool ch390_runtime_emergency_reset(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
ch390_runtime_set_health_fail_count(0u);
|
||||
ch390_runtime_set_restart_pending();
|
||||
SEGGER_RTT_WriteString(0, "ETH emergency reset: OK\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void ch390_runtime_health_check(struct netif *netif)
|
||||
{
|
||||
uint16_t vid;
|
||||
uint8_t fail_count;
|
||||
|
||||
if (!g_ch390_ready) {
|
||||
SEGGER_RTT_WriteString(0, "ETH health: chip not ready, attempting reset\r\n");
|
||||
(void)ch390_runtime_emergency_reset(netif);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify chip is still responding by reading vendor ID */
|
||||
uint16_t vid = ch390_get_vendor_id();
|
||||
vid = ch390_get_vendor_id();
|
||||
if (vid == 0x0000u || vid == 0xFFFFu) {
|
||||
SEGGER_RTT_printf(0, "ETH health: invalid VID=0x%04X, attempting reset\r\n", vid);
|
||||
netif_set_link_down(netif);
|
||||
if (ch390_runtime_emergency_reset()) {
|
||||
ch390_runtime_check_link(netif);
|
||||
fail_count = ch390_runtime_get_health_fail_count();
|
||||
if (fail_count < 0x0Fu) {
|
||||
fail_count++;
|
||||
}
|
||||
ch390_runtime_set_health_fail_count(fail_count);
|
||||
if (fail_count >= HEALTH_FAIL_THRESHOLD) {
|
||||
SEGGER_RTT_printf(0, "ETH health: invalid VID=0x%04X streak=%u, attempting reset\r\n",
|
||||
vid,
|
||||
fail_count);
|
||||
ch390_runtime_set_health_fail_count(0u);
|
||||
(void)ch390_runtime_emergency_reset(netif);
|
||||
}
|
||||
} else {
|
||||
ch390_runtime_set_health_fail_count(0u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ void ch390_runtime_check_link(struct netif *netif);
|
||||
err_t ch390_runtime_output(struct netif *netif, struct pbuf *p);
|
||||
void ch390_runtime_get_diag(ch390_diag_t *diag);
|
||||
bool ch390_runtime_is_ready(void);
|
||||
bool ch390_runtime_emergency_reset(void);
|
||||
bool ch390_runtime_emergency_reset(struct netif *netif);
|
||||
void ch390_runtime_health_check(struct netif *netif);
|
||||
uint8_t ch390_runtime_get_reset_count(void);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user