From 8c204aad772ae54b09ce0a5f0f37a7bac60571a3 Mon Sep 17 00:00:00 2001 From: xiao Date: Wed, 29 Apr 2026 04:36:29 +0800 Subject: [PATCH] fix: stabilize lwip ethernet recovery --- App/task_net_poll.c | 69 ++- Drivers/LwIP/src/include/arch/lwipopts.h | 10 +- Drivers/LwIP/src/include/netif/ethernetif.h | 16 + Drivers/LwIP/src/netif/ethernet.c | 5 +- Drivers/LwIP/src/netif/ethernetif.c | 482 ++++++++++++++++---- Drivers/LwIP/src/netif/ethernetif.h | 14 + 6 files changed, 493 insertions(+), 103 deletions(-) diff --git a/App/task_net_poll.c b/App/task_net_poll.c index 9f9ec96..c666c66 100644 --- a/App/task_net_poll.c +++ b/App/task_net_poll.c @@ -16,6 +16,64 @@ #include "app_runtime.h" #include "debug_log.h" +#define CH390_RESTART_HOLD_DOWN_MS 500u +#define NETWORK_TASK_DELETE_SETTLE_MS 50u +#define CH390_EXPECTED_VENDOR_ID 0x1C00u +#define CH390_EXPECTED_PRODUCT_ID 0x9151u + +static void net_poll_wait_for_network_tasks_stop(void) +{ + while (app_network_tasks_are_stopped() == pdFALSE) { + vTaskDelay(pdMS_TO_TICKS(20)); + } +} + +static BaseType_t net_poll_restart_network_stack(const device_config_t *cfg) +{ +#if !DIAG_CH390_RAW_POLL + ip4_addr_t ipaddr; + ip4_addr_t netmask; + ip4_addr_t gateway; + uint16_t vendor_id; + uint16_t product_id; + uint8_t revision; + + IP4_ADDR(&ipaddr, cfg->net.ip[0], cfg->net.ip[1], cfg->net.ip[2], cfg->net.ip[3]); + IP4_ADDR(&netmask, cfg->net.mask[0], cfg->net.mask[1], cfg->net.mask[2], cfg->net.mask[3]); + IP4_ADDR(&gateway, cfg->net.gw[0], cfg->net.gw[1], cfg->net.gw[2], cfg->net.gw[3]); +#endif + + ethernetif_force_link_down(); + g_netif_ready = pdFALSE; + app_request_network_task_stop(); + net_poll_wait_for_network_tasks_stop(); + vTaskDelay(pdMS_TO_TICKS(NETWORK_TASK_DELETE_SETTLE_MS)); + vTaskDelay(pdMS_TO_TICKS(CH390_RESTART_HOLD_DOWN_MS)); + +#if DIAG_CH390_RAW_POLL + ethernetif_diag_ch390_init(); +#else + ethernetif_force_full_recovery(&ipaddr, &netmask, &gateway, cfg->net.mac); + vendor_id = ethernetif_ch390_get_vendor_id(); + product_id = ethernetif_ch390_get_product_id(); + revision = ethernetif_ch390_get_revision(); + if ((vendor_id != CH390_EXPECTED_VENDOR_ID) || (product_id != CH390_EXPECTED_PRODUCT_ID)) { + debug_log_printf("[NET] restart-recovery id-warn vid=0x%04X pid=0x%04X rev=0x%02X free=%lu min=%lu\r\n", + (unsigned int)vendor_id, + (unsigned int)product_id, + (unsigned int)revision, + (unsigned long)xPortGetFreeHeapSize(), + (unsigned long)xPortGetMinimumEverFreeHeapSize()); + } +#endif + + app_clear_network_task_stop(); + g_netif_ready = pdTRUE; + app_start_network_tasks(); + app_clear_network_restart_request(); + return pdTRUE; +} + void NetPollTask(void *argument) { const device_config_t *cfg; @@ -98,6 +156,11 @@ void NetPollTask(void *argument) debug_log_write("[NET] loop-enter\r\n"); loop_logged = pdTRUE; } + + if (app_network_restart_requested() != pdFALSE) { + (void)net_poll_restart_network_stack(cfg); + } + (void)xSemaphoreTake(xNetSemaphore, pdMS_TO_TICKS(2)); #if DIAG_CH390_RAW_POLL @@ -120,8 +183,10 @@ void NetPollTask(void *argument) } } #else - ethernetif_poll(); - ethernetif_check_link(); + if (g_netif_ready != pdFALSE) { + ethernetif_poll(); + ethernetif_check_link(); + } #endif } } diff --git a/Drivers/LwIP/src/include/arch/lwipopts.h b/Drivers/LwIP/src/include/arch/lwipopts.h index 3dd9ccf..608f28b 100644 --- a/Drivers/LwIP/src/include/arch/lwipopts.h +++ b/Drivers/LwIP/src/include/arch/lwipopts.h @@ -7,8 +7,8 @@ * * Key design decisions: * - netconn API for thread-safe multi-connection TCP - * - tcpip_thread handles all lwIP core operations - * - LWIP_TCPIP_CORE_LOCKING=1 allows direct send from application tasks + * - tcpip_thread handles netconn API and timers + * - core locking lets the poll task process RX packets synchronously * - Conservative memory footprint: target ~16KB for lwIP */ @@ -27,9 +27,9 @@ #define LWIP_NETCONN 1 #define LWIP_NETIF_API 1 -/* Core locking: allows netconn_write/recv from any task without going through mbox */ +/* Core locking: process netif RX synchronously instead of consuming TCPIP_MSG_INPKT slots. */ #define LWIP_TCPIP_CORE_LOCKING 1 -#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#define LWIP_TCPIP_CORE_LOCKING_INPUT 1 /* Critical section protection */ #define SYS_LIGHTWEIGHT_PROT 1 @@ -54,7 +54,7 @@ #define MEM_SIZE (7 * 1024) /* Number of pbufs in pool. - * 10 pools for 4 concurrent connections with some headroom. */ + * RX is processed synchronously under the core lock, so a small pool is sufficient. */ #define PBUF_POOL_SIZE 8 /* Size of each pbuf in pool (must hold one Ethernet frame) */ diff --git a/Drivers/LwIP/src/include/netif/ethernetif.h b/Drivers/LwIP/src/include/netif/ethernetif.h index aec39e2..8e49ff3 100644 --- a/Drivers/LwIP/src/include/netif/ethernetif.h +++ b/Drivers/LwIP/src/include/netif/ethernetif.h @@ -23,7 +23,23 @@ struct ethernetif { err_t ethernetif_init(struct netif *netif); void ethernetif_input(struct netif *netif); void lwip_netif_init(const ip4_addr_t *ipaddr, const ip4_addr_t *netmask, const ip4_addr_t *gw); +void ethernetif_diag_ch390_init(void); +void ethernetif_diag_poll_status(void); void ethernetif_check_link(void); +void ethernetif_apply_runtime_netif_config(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac); +void ethernetif_force_full_recovery(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac); +void ethernetif_force_link_down(void); +uint16_t ethernetif_ch390_get_vendor_id(void); +uint16_t ethernetif_ch390_get_product_id(void); +uint8_t ethernetif_ch390_get_revision(void); +uint8_t ethernetif_ch390_health_ok(void); +uint8_t ethernetif_get_effective_mac(uint8_t *mac); uint8_t ethernetif_link_is_up(void); void ethernetif_poll(void); diff --git a/Drivers/LwIP/src/netif/ethernet.c b/Drivers/LwIP/src/netif/ethernet.c index 38c90c9..86d4435 100644 --- a/Drivers/LwIP/src/netif/ethernet.c +++ b/Drivers/LwIP/src/netif/ethernet.c @@ -36,6 +36,7 @@ err_t ethernet_output(struct netif *netif, { struct pbuf *q; struct eth_hdr *ethhdr; + err_t err; LWIP_ASSERT("netif != NULL", netif != NULL); LWIP_ASSERT("p != NULL", p != NULL); @@ -56,7 +57,9 @@ err_t ethernet_output(struct netif *netif, SMEMCPY(ðhdr->src, src, sizeof(struct eth_addr)); ethhdr->type = lwip_htons(eth_type); - return netif->linkoutput(netif, q); + err = netif->linkoutput(netif, q); + pbuf_free(q); + return err; } err_t ethernet_input(struct pbuf *p, struct netif *netif) diff --git a/Drivers/LwIP/src/netif/ethernetif.c b/Drivers/LwIP/src/netif/ethernetif.c index 0772ccd..15bb614 100644 --- a/Drivers/LwIP/src/netif/ethernetif.c +++ b/Drivers/LwIP/src/netif/ethernetif.c @@ -41,6 +41,14 @@ static SemaphoreHandle_t spi_mutex = NULL; static uint8_t s_rx_buffer[CH390_PKT_MAX]; static uint8_t s_tx_buffer[CH390_PKT_MAX]; static uint8_t s_garp_sent = 0u; +static uint8_t s_effective_mac[ETHARP_HWADDR_LEN]; +static uint8_t s_effective_mac_valid = 0u; + +#define CH390_TX_TIMEOUT_RESTART_THRESHOLD 6u +#define CH390_EXPECTED_VENDOR_ID 0x1C00u +#define CH390_EXPECTED_PRODUCT_ID 0x9151u +#define ETH_RX_LOG_INITIAL_COUNT 3u +#define ETH_RX_LOG_EVERY_COUNT 64u #define ETH_RECOVERY_NONE 0u #define ETH_RECOVERY_RX 1u @@ -50,6 +58,7 @@ struct ethernetif_recovery_state { uint8_t pending; uint8_t in_progress; + uint8_t tx_timeout_streak; uint32_t tx_timeout_count; uint32_t rx_overflow_count; uint32_t rx_bad_count; @@ -69,6 +78,22 @@ static uint32_t ethernetif_record_event_and_request(uint32_t *counter, uint8_t r static uint8_t ethernetif_claim_recovery(void); static void ethernetif_finish_recovery(void); static uint8_t ethernetif_run_pending_recovery(void); +static uint8_t ethernetif_should_log_counter(uint32_t count); +static void ethernetif_clear_tx_timeout_streak(void); +static uint32_t ethernetif_note_tx_timeout_streak(void); +static uint8_t ethernetif_mac_is_all_zero(const uint8_t *mac); +static void ethernetif_store_effective_mac(const uint8_t *mac); +static void ethernetif_apply_configured_or_internal_mac_locked(const uint8_t *configured_mac); +static void ethernetif_prepare_runtime_netif_locked(struct netif *netif); +static void ethernetif_apply_runtime_netif_config_locked(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac); +static void ethernetif_perform_full_recovery(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac, + uint8_t *link_status); /*--------------------------------------------------------------------------- * Low Level Hardware Functions @@ -80,7 +105,6 @@ static uint8_t ethernetif_run_pending_recovery(void); */ static err_t low_level_init(struct netif *netif) { - struct ethernetif *ethernetif = netif->state; const device_config_t *cfg = config_get(); /* Create SPI mutex */ @@ -110,24 +134,9 @@ static err_t low_level_init(struct netif *netif) ch390_read_reg(CH390_BCASTCR), ch390_read_reg(CH390_MAR + 7)); - /* Apply configured MAC address to CH390 before reading it back into lwIP */ - ch390_set_mac_address((uint8_t *)cfg->net.mac); + ethernetif_apply_configured_or_internal_mac_locked(cfg->net.mac); - /* Set MAC hardware address length */ - netif->hwaddr_len = ETHARP_HWADDR_LEN; - - /* Get MAC address from CH390 */ - ch390_get_mac(netif->hwaddr); - - /* Maximum transfer unit */ - netif->mtu = 1500; - - /* Device capabilities */ - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET; - - /* Initialize state */ - ethernetif->rx_len = 0; - ethernetif->rx_status = 0; + ethernetif_prepare_runtime_netif_locked(netif); /* Enable CH390 interrupt */ ch390_interrupt_init(); @@ -153,7 +162,11 @@ static uint32_t ethernetif_record_event_and_request(uint32_t *counter, uint8_t r taskENTER_CRITICAL(); ++(*counter); - if (recovery_type > s_recovery.pending) + if (recovery_type == ETH_RECOVERY_FULL) + { + app_request_network_restart(); + } + else if (recovery_type > s_recovery.pending) { s_recovery.pending = recovery_type; } @@ -163,6 +176,29 @@ static uint32_t ethernetif_record_event_and_request(uint32_t *counter, uint8_t r return value; } +static void ethernetif_clear_tx_timeout_streak(void) +{ + taskENTER_CRITICAL(); + s_recovery.tx_timeout_streak = 0u; + taskEXIT_CRITICAL(); +} + +static uint32_t ethernetif_note_tx_timeout_streak(void) +{ + uint32_t streak; + + taskENTER_CRITICAL(); + ++s_recovery.tx_timeout_count; + if (s_recovery.tx_timeout_streak < 0xFFu) + { + ++s_recovery.tx_timeout_streak; + } + streak = s_recovery.tx_timeout_streak; + taskEXIT_CRITICAL(); + + return streak; +} + static uint8_t ethernetif_claim_recovery(void) { uint8_t recovery_type = ETH_RECOVERY_NONE; @@ -186,9 +222,21 @@ static void ethernetif_finish_recovery(void) taskEXIT_CRITICAL(); } +static uint8_t ethernetif_should_log_counter(uint32_t count) +{ + if (count <= ETH_RX_LOG_INITIAL_COUNT) + { + return 1u; + } + + return ((count % ETH_RX_LOG_EVERY_COUNT) == 0u) ? 1u : 0u; +} + static uint8_t ethernetif_run_pending_recovery(void) { - const device_config_t *cfg = config_get(); + ip4_addr_t ipaddr; + ip4_addr_t netmask; + ip4_addr_t gateway; uint8_t recovery_type; uint8_t link_status = 0u; uint32_t count; @@ -199,47 +247,303 @@ static uint8_t ethernetif_run_pending_recovery(void) return ETH_RECOVERY_NONE; } + if (recovery_type == ETH_RECOVERY_FULL) + { + const device_config_t *cfg = config_get(); + + IP4_ADDR(&ipaddr, cfg->net.ip[0], cfg->net.ip[1], cfg->net.ip[2], cfg->net.ip[3]); + IP4_ADDR(&netmask, cfg->net.mask[0], cfg->net.mask[1], cfg->net.mask[2], cfg->net.mask[3]); + IP4_ADDR(&gateway, cfg->net.gw[0], cfg->net.gw[1], cfg->net.gw[2], cfg->net.gw[3]); + ethernetif_clear_tx_timeout_streak(); + ethernetif_perform_full_recovery(&ipaddr, &netmask, &gateway, cfg->net.mac, &link_status); + } + else + { + if (spi_mutex != NULL) + { + xSemaphoreTake(spi_mutex, portMAX_DELAY); + } + ch390_rx_reset(); + if (spi_mutex != NULL) + { + xSemaphoreGive(spi_mutex); + } + } + + if (recovery_type == ETH_RECOVERY_FULL) + { + count = ethernetif_record_counter(&s_recovery.full_recovery_count); + debug_log_printf("[ETH] rec full n=%lu link=%u\r\n", + (unsigned long)count, + (unsigned int)link_status); + } + else + { + count = ethernetif_record_counter(&s_recovery.rx_recovery_count); + if (ethernetif_should_log_counter(count) != 0u) + { + debug_log_printf("[ETH] rec rx n=%lu\r\n", (unsigned long)count); + } + } + + ethernetif_finish_recovery(); + return recovery_type; +} + +static void ethernetif_perform_full_recovery(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac, + uint8_t *link_status) +{ + uint8_t local_link_status = 0u; + if (spi_mutex != NULL) { xSemaphoreTake(spi_mutex, portMAX_DELAY); } - if (recovery_type == ETH_RECOVERY_FULL) - { - ch390_software_reset(); - ch390_default_config(); - ch390_set_mac_address((uint8_t *)cfg->net.mac); - ch390_set_phy_mode(CH390_AUTO); - ch390_rx_enable(1); - link_status = (uint8_t)ch390_get_link_status(); - } - else - { - ch390_rx_reset(); - } + ch390_spi_init(); + ch390_hardware_reset(); + ch390_default_config(); + ethernetif_apply_configured_or_internal_mac_locked(mac); + ch390_set_phy_mode(CH390_AUTO); + ch390_rx_enable(1); + ethernetif_prepare_runtime_netif_locked(&ch390_netif); + ethernetif_apply_runtime_netif_config_locked(ipaddr, + netmask, + gw, + (s_effective_mac_valid != 0u) ? s_effective_mac : NULL); + local_link_status = (uint8_t)ch390_get_link_status(); if (spi_mutex != NULL) { xSemaphoreGive(spi_mutex); } - if (recovery_type == ETH_RECOVERY_FULL) + ch390_interrupt_init(); + + if (link_status != NULL) { - ch390_interrupt_init(); - count = ethernetif_record_counter(&s_recovery.full_recovery_count); - debug_log_printf("[ETH] rec full n=%lu link=%u\r\n", - (unsigned long)count, - (unsigned int)link_status); - ethernetif_update_link(link_status); - } - else - { - count = ethernetif_record_counter(&s_recovery.rx_recovery_count); - debug_log_printf("[ETH] rec rx n=%lu\r\n", (unsigned long)count); + *link_status = local_link_status; } - ethernetif_finish_recovery(); - return recovery_type; + ethernetif_update_link(local_link_status); +} + +static uint8_t ethernetif_mac_is_all_zero(const uint8_t *mac) +{ + uint32_t i; + + if (mac == NULL) + { + return 1u; + } + + for (i = 0u; i < ETHARP_HWADDR_LEN; ++i) + { + if (mac[i] != 0u) + { + return 0u; + } + } + + return 1u; +} + +static void ethernetif_store_effective_mac(const uint8_t *mac) +{ + if (mac == NULL) + { + s_effective_mac_valid = 0u; + return; + } + + MEMCPY(s_effective_mac, mac, ETHARP_HWADDR_LEN); + s_effective_mac_valid = 1u; +} + +static void ethernetif_apply_configured_or_internal_mac_locked(const uint8_t *configured_mac) +{ + uint8_t runtime_mac[ETHARP_HWADDR_LEN]; + + if (ethernetif_mac_is_all_zero(configured_mac) == 0u) + { + ch390_set_mac_address((uint8_t *)configured_mac); + ethernetif_store_effective_mac(configured_mac); + return; + } + + ch390_get_mac(runtime_mac); + ethernetif_store_effective_mac(runtime_mac); + debug_log_printf("[ETH] use internal mac=%02X:%02X:%02X:%02X:%02X:%02X\r\n", + (unsigned int)runtime_mac[0], + (unsigned int)runtime_mac[1], + (unsigned int)runtime_mac[2], + (unsigned int)runtime_mac[3], + (unsigned int)runtime_mac[4], + (unsigned int)runtime_mac[5]); +} + +static void ethernetif_prepare_runtime_netif_locked(struct netif *netif) +{ + struct ethernetif *ethernetif; + + if (netif == NULL) + { + return; + } + + netif->hwaddr_len = ETHARP_HWADDR_LEN; + ch390_get_mac(netif->hwaddr); + ethernetif_store_effective_mac(netif->hwaddr); + 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 ethernetif_apply_runtime_netif_config_locked(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac) +{ + err_t err; + + if (mac != NULL) + { + MEMCPY(ch390_netif.hwaddr, mac, ETHARP_HWADDR_LEN); + s_garp_sent = 0u; + } + + if (ipaddr != NULL && netmask != NULL && gw != NULL) + { + err = netifapi_netif_set_addr(&ch390_netif, ipaddr, netmask, gw); + if (err != ERR_OK) + { + debug_log_printf("[ETH] set-addr fail err=%d\r\n", (int)err); + } + } + + err = netifapi_netif_set_default(&ch390_netif); + if (err != ERR_OK) + { + debug_log_printf("[ETH] resync-default fail err=%d\r\n", (int)err); + } + + err = netifapi_netif_set_up(&ch390_netif); + if (err != ERR_OK) + { + debug_log_printf("[ETH] resync-up fail err=%d\r\n", (int)err); + } +} + +void ethernetif_apply_runtime_netif_config(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac) +{ + ethernetif_apply_runtime_netif_config_locked(ipaddr, netmask, gw, mac); +} + +void ethernetif_force_full_recovery(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac) +{ + uint8_t link_status = 0u; + uint32_t count; + + ethernetif_clear_tx_timeout_streak(); + ethernetif_perform_full_recovery(ipaddr, netmask, gw, mac, &link_status); + count = ethernetif_record_counter(&s_recovery.full_recovery_count); + debug_log_printf("[ETH] rec full n=%lu link=%u\r\n", + (unsigned long)count, + (unsigned int)link_status); +} + +void ethernetif_force_link_down(void) +{ + ethernetif_update_link(0u); +} + +uint8_t ethernetif_ch390_health_ok(void) +{ + return ((ethernetif_ch390_get_vendor_id() == CH390_EXPECTED_VENDOR_ID) && + (ethernetif_ch390_get_product_id() == CH390_EXPECTED_PRODUCT_ID)) ? 1u : 0u; +} + +uint8_t ethernetif_get_effective_mac(uint8_t *mac) +{ + if ((mac == NULL) || (s_effective_mac_valid == 0u)) + { + return 0u; + } + + MEMCPY(mac, s_effective_mac, ETHARP_HWADDR_LEN); + return 1u; +} + +uint16_t ethernetif_ch390_get_vendor_id(void) +{ + uint16_t vendor_id; + + if (spi_mutex != NULL) + { + xSemaphoreTake(spi_mutex, portMAX_DELAY); + } + + vendor_id = ch390_get_vendor_id(); + + if (spi_mutex != NULL) + { + xSemaphoreGive(spi_mutex); + } + + return vendor_id; +} + +uint16_t ethernetif_ch390_get_product_id(void) +{ + uint16_t product_id; + + if (spi_mutex != NULL) + { + xSemaphoreTake(spi_mutex, portMAX_DELAY); + } + + product_id = ch390_get_product_id(); + + if (spi_mutex != NULL) + { + xSemaphoreGive(spi_mutex); + } + + return product_id; +} + +uint8_t ethernetif_ch390_get_revision(void) +{ + uint8_t revision; + + if (spi_mutex != NULL) + { + xSemaphoreTake(spi_mutex, portMAX_DELAY); + } + + revision = ch390_get_revision(); + + if (spi_mutex != NULL) + { + xSemaphoreGive(spi_mutex); + } + + return revision; } /** @@ -254,7 +558,7 @@ static err_t low_level_output(struct netif *netif, struct pbuf *p) uint16_t offset; uint16_t tx_len; int tx_rc; - uint32_t tx_timeout_count; + uint32_t tx_timeout_streak; (void)netif; /* Take SPI mutex */ @@ -309,11 +613,18 @@ static err_t low_level_output(struct netif *netif, struct pbuf *p) { LINK_STATS_INC(link.drop); LINK_STATS_INC(link.err); - tx_timeout_count = ethernetif_record_event_and_request(&s_recovery.tx_timeout_count, ETH_RECOVERY_FULL); - debug_log_printf("[ETH] tx timeout n=%lu\r\n", (unsigned long)tx_timeout_count); + tx_timeout_streak = ethernetif_note_tx_timeout_streak(); + debug_log_printf("[ETH] tx timeout n=%lu streak=%lu\r\n", + (unsigned long)s_recovery.tx_timeout_count, + (unsigned long)tx_timeout_streak); + if (tx_timeout_streak >= CH390_TX_TIMEOUT_RESTART_THRESHOLD) + { + app_request_network_restart(); + } return ERR_TIMEOUT; } - + + ethernetif_clear_tx_timeout_streak(); LINK_STATS_INC(link.xmit); return ERR_OK; @@ -330,12 +641,9 @@ static struct pbuf *low_level_input(struct netif *netif) struct pbuf *p = NULL; struct pbuf *q; uint16_t offset; - uint16_t peek_len; uint16_t len; uint32_t rx_len; uint8_t rx_status; - uint32_t rx_bad_count; - int peek_ready; /* Take SPI mutex */ if (spi_mutex != NULL) @@ -343,37 +651,6 @@ static struct pbuf *low_level_input(struct netif *netif) xSemaphoreTake(spi_mutex, portMAX_DELAY); } - peek_len = 0u; - peek_ready = ch390_peek_packet(&rx_status, &peek_len); - ethernetif->rx_status = rx_status; - ethernetif->rx_len = peek_len; - - if (peek_ready == 0) - { - if (spi_mutex != NULL) - { - xSemaphoreGive(spi_mutex); - } - return NULL; - } - - if (((rx_status & 0x3Fu) != 0u) || (peek_len < 14u) || (peek_len > CH390_PKT_MAX)) - { - if (spi_mutex != NULL) - { - xSemaphoreGive(spi_mutex); - } - - LINK_STATS_INC(link.drop); - LINK_STATS_INC(link.err); - rx_bad_count = ethernetif_record_event_and_request(&s_recovery.rx_bad_count, ETH_RECOVERY_RX); - debug_log_printf("[ETH] rx bad n=%lu st=0x%02X len=%u\r\n", - (unsigned long)rx_bad_count, - (unsigned int)rx_status, - (unsigned int)peek_len); - return NULL; - } - rx_len = ch390_runtime_receive_packet(s_rx_buffer, &rx_status); ethernetif->rx_status = rx_status; ethernetif->rx_len = (uint16_t)rx_len; @@ -384,14 +661,6 @@ static struct pbuf *low_level_input(struct netif *netif) { xSemaphoreGive(spi_mutex); } - - LINK_STATS_INC(link.drop); - LINK_STATS_INC(link.err); - rx_bad_count = ethernetif_record_event_and_request(&s_recovery.rx_bad_count, ETH_RECOVERY_RX); - debug_log_printf("[ETH] rx lost n=%lu st=0x%02X len=%u\r\n", - (unsigned long)rx_bad_count, - (unsigned int)rx_status, - (unsigned int)peek_len); return NULL; } @@ -600,7 +869,7 @@ void ethernetif_diag_ch390_init(void) ch390_spi_init(); ch390_hardware_reset(); ch390_default_config(); - ch390_set_mac_address((uint8_t *)cfg->net.mac); + ethernetif_apply_configured_or_internal_mac_locked(cfg->net.mac); ch390_interrupt_init(); g_netif_init_ok = 1; @@ -629,8 +898,12 @@ void ethernetif_diag_poll_status(void) */ static void ethernetif_update_link(uint8_t link_status) { + uint8_t old_link_status; + LOCK_TCPIP_CORE(); + old_link_status = netif_is_link_up(&ch390_netif) ? 1u : 0u; + if (link_status) { if (!netif_is_link_up(&ch390_netif)) @@ -653,6 +926,22 @@ static void ethernetif_update_link(uint8_t link_status) } UNLOCK_TCPIP_CORE(); + + if (old_link_status != ((link_status != 0u) ? 1u : 0u)) + { + debug_log_printf("[ETH] link %s ip=%u.%u.%u.%u mac=%02X:%02X:%02X:%02X:%02X:%02X\r\n", + (link_status != 0u) ? "up" : "down", + (unsigned int)ip4_addr1_16(netif_ip4_addr(&ch390_netif)), + (unsigned int)ip4_addr2_16(netif_ip4_addr(&ch390_netif)), + (unsigned int)ip4_addr3_16(netif_ip4_addr(&ch390_netif)), + (unsigned int)ip4_addr4_16(netif_ip4_addr(&ch390_netif)), + (unsigned int)ch390_netif.hwaddr[0], + (unsigned int)ch390_netif.hwaddr[1], + (unsigned int)ch390_netif.hwaddr[2], + (unsigned int)ch390_netif.hwaddr[3], + (unsigned int)ch390_netif.hwaddr[4], + (unsigned int)ch390_netif.hwaddr[5]); + } } /** @@ -687,7 +976,10 @@ void ethernetif_poll(void) { LINK_STATS_INC(link.err); rx_overflow_count = ethernetif_record_event_and_request(&s_recovery.rx_overflow_count, ETH_RECOVERY_RX); - debug_log_printf("[ETH] rx ovf n=%lu\r\n", (unsigned long)rx_overflow_count); + if (ethernetif_should_log_counter(rx_overflow_count) != 0u) + { + debug_log_printf("[ETH] rx ovf n=%lu\r\n", (unsigned long)rx_overflow_count); + } } recovery_type = ethernetif_run_pending_recovery(); diff --git a/Drivers/LwIP/src/netif/ethernetif.h b/Drivers/LwIP/src/netif/ethernetif.h index 0886a49..e04cf0a 100644 --- a/Drivers/LwIP/src/netif/ethernetif.h +++ b/Drivers/LwIP/src/netif/ethernetif.h @@ -62,6 +62,20 @@ void ethernetif_diag_poll_status(void); * @note Call this from the LwIP task periodically or on interrupt */ void ethernetif_check_link(void); +void ethernetif_apply_runtime_netif_config(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac); +void ethernetif_force_full_recovery(const ip4_addr_t *ipaddr, + const ip4_addr_t *netmask, + const ip4_addr_t *gw, + const uint8_t *mac); +void ethernetif_force_link_down(void); +uint16_t ethernetif_ch390_get_vendor_id(void); +uint16_t ethernetif_ch390_get_product_id(void); +uint8_t ethernetif_ch390_get_revision(void); +uint8_t ethernetif_ch390_health_ok(void); +uint8_t ethernetif_get_effective_mac(uint8_t *mac); /** * @brief Query whether physical Ethernet link is currently up