fix: stabilize lwip ethernet recovery
This commit is contained in:
@@ -16,6 +16,64 @@
|
|||||||
#include "app_runtime.h"
|
#include "app_runtime.h"
|
||||||
#include "debug_log.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)
|
void NetPollTask(void *argument)
|
||||||
{
|
{
|
||||||
const device_config_t *cfg;
|
const device_config_t *cfg;
|
||||||
@@ -98,6 +156,11 @@ void NetPollTask(void *argument)
|
|||||||
debug_log_write("[NET] loop-enter\r\n");
|
debug_log_write("[NET] loop-enter\r\n");
|
||||||
loop_logged = pdTRUE;
|
loop_logged = pdTRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (app_network_restart_requested() != pdFALSE) {
|
||||||
|
(void)net_poll_restart_network_stack(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
(void)xSemaphoreTake(xNetSemaphore, pdMS_TO_TICKS(2));
|
(void)xSemaphoreTake(xNetSemaphore, pdMS_TO_TICKS(2));
|
||||||
|
|
||||||
#if DIAG_CH390_RAW_POLL
|
#if DIAG_CH390_RAW_POLL
|
||||||
@@ -120,8 +183,10 @@ void NetPollTask(void *argument)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
if (g_netif_ready != pdFALSE) {
|
||||||
ethernetif_poll();
|
ethernetif_poll();
|
||||||
ethernetif_check_link();
|
ethernetif_check_link();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
*
|
*
|
||||||
* Key design decisions:
|
* Key design decisions:
|
||||||
* - netconn API for thread-safe multi-connection TCP
|
* - netconn API for thread-safe multi-connection TCP
|
||||||
* - tcpip_thread handles all lwIP core operations
|
* - tcpip_thread handles netconn API and timers
|
||||||
* - LWIP_TCPIP_CORE_LOCKING=1 allows direct send from application tasks
|
* - core locking lets the poll task process RX packets synchronously
|
||||||
* - Conservative memory footprint: target ~16KB for lwIP
|
* - Conservative memory footprint: target ~16KB for lwIP
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -27,9 +27,9 @@
|
|||||||
#define LWIP_NETCONN 1
|
#define LWIP_NETCONN 1
|
||||||
#define LWIP_NETIF_API 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 1
|
||||||
#define LWIP_TCPIP_CORE_LOCKING_INPUT 0
|
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
|
||||||
|
|
||||||
/* Critical section protection */
|
/* Critical section protection */
|
||||||
#define SYS_LIGHTWEIGHT_PROT 1
|
#define SYS_LIGHTWEIGHT_PROT 1
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
#define MEM_SIZE (7 * 1024)
|
#define MEM_SIZE (7 * 1024)
|
||||||
|
|
||||||
/* Number of pbufs in pool.
|
/* 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
|
#define PBUF_POOL_SIZE 8
|
||||||
|
|
||||||
/* Size of each pbuf in pool (must hold one Ethernet frame) */
|
/* Size of each pbuf in pool (must hold one Ethernet frame) */
|
||||||
|
|||||||
@@ -23,7 +23,23 @@ struct ethernetif {
|
|||||||
err_t ethernetif_init(struct netif *netif);
|
err_t ethernetif_init(struct netif *netif);
|
||||||
void ethernetif_input(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 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_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);
|
uint8_t ethernetif_link_is_up(void);
|
||||||
void ethernetif_poll(void);
|
void ethernetif_poll(void);
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ err_t ethernet_output(struct netif *netif,
|
|||||||
{
|
{
|
||||||
struct pbuf *q;
|
struct pbuf *q;
|
||||||
struct eth_hdr *ethhdr;
|
struct eth_hdr *ethhdr;
|
||||||
|
err_t err;
|
||||||
|
|
||||||
LWIP_ASSERT("netif != NULL", netif != NULL);
|
LWIP_ASSERT("netif != NULL", netif != NULL);
|
||||||
LWIP_ASSERT("p != NULL", p != 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));
|
SMEMCPY(ðhdr->src, src, sizeof(struct eth_addr));
|
||||||
ethhdr->type = lwip_htons(eth_type);
|
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)
|
err_t ethernet_input(struct pbuf *p, struct netif *netif)
|
||||||
|
|||||||
@@ -41,6 +41,14 @@ static SemaphoreHandle_t spi_mutex = NULL;
|
|||||||
static uint8_t s_rx_buffer[CH390_PKT_MAX];
|
static uint8_t s_rx_buffer[CH390_PKT_MAX];
|
||||||
static uint8_t s_tx_buffer[CH390_PKT_MAX];
|
static uint8_t s_tx_buffer[CH390_PKT_MAX];
|
||||||
static uint8_t s_garp_sent = 0u;
|
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_NONE 0u
|
||||||
#define ETH_RECOVERY_RX 1u
|
#define ETH_RECOVERY_RX 1u
|
||||||
@@ -50,6 +58,7 @@ struct ethernetif_recovery_state
|
|||||||
{
|
{
|
||||||
uint8_t pending;
|
uint8_t pending;
|
||||||
uint8_t in_progress;
|
uint8_t in_progress;
|
||||||
|
uint8_t tx_timeout_streak;
|
||||||
uint32_t tx_timeout_count;
|
uint32_t tx_timeout_count;
|
||||||
uint32_t rx_overflow_count;
|
uint32_t rx_overflow_count;
|
||||||
uint32_t rx_bad_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 uint8_t ethernetif_claim_recovery(void);
|
||||||
static void ethernetif_finish_recovery(void);
|
static void ethernetif_finish_recovery(void);
|
||||||
static uint8_t ethernetif_run_pending_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
|
* 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)
|
static err_t low_level_init(struct netif *netif)
|
||||||
{
|
{
|
||||||
struct ethernetif *ethernetif = netif->state;
|
|
||||||
const device_config_t *cfg = config_get();
|
const device_config_t *cfg = config_get();
|
||||||
|
|
||||||
/* Create SPI mutex */
|
/* 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_BCASTCR),
|
||||||
ch390_read_reg(CH390_MAR + 7));
|
ch390_read_reg(CH390_MAR + 7));
|
||||||
|
|
||||||
/* Apply configured MAC address to CH390 before reading it back into lwIP */
|
ethernetif_apply_configured_or_internal_mac_locked(cfg->net.mac);
|
||||||
ch390_set_mac_address((uint8_t *)cfg->net.mac);
|
|
||||||
|
|
||||||
/* Set MAC hardware address length */
|
ethernetif_prepare_runtime_netif_locked(netif);
|
||||||
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;
|
|
||||||
|
|
||||||
/* Enable CH390 interrupt */
|
/* Enable CH390 interrupt */
|
||||||
ch390_interrupt_init();
|
ch390_interrupt_init();
|
||||||
@@ -153,7 +162,11 @@ static uint32_t ethernetif_record_event_and_request(uint32_t *counter, uint8_t r
|
|||||||
|
|
||||||
taskENTER_CRITICAL();
|
taskENTER_CRITICAL();
|
||||||
++(*counter);
|
++(*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;
|
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;
|
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)
|
static uint8_t ethernetif_claim_recovery(void)
|
||||||
{
|
{
|
||||||
uint8_t recovery_type = ETH_RECOVERY_NONE;
|
uint8_t recovery_type = ETH_RECOVERY_NONE;
|
||||||
@@ -186,9 +222,21 @@ static void ethernetif_finish_recovery(void)
|
|||||||
taskEXIT_CRITICAL();
|
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)
|
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 recovery_type;
|
||||||
uint8_t link_status = 0u;
|
uint8_t link_status = 0u;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
@@ -199,47 +247,303 @@ static uint8_t ethernetif_run_pending_recovery(void)
|
|||||||
return ETH_RECOVERY_NONE;
|
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)
|
if (spi_mutex != NULL)
|
||||||
{
|
{
|
||||||
xSemaphoreTake(spi_mutex, portMAX_DELAY);
|
xSemaphoreTake(spi_mutex, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recovery_type == ETH_RECOVERY_FULL)
|
ch390_spi_init();
|
||||||
{
|
ch390_hardware_reset();
|
||||||
ch390_software_reset();
|
|
||||||
ch390_default_config();
|
ch390_default_config();
|
||||||
ch390_set_mac_address((uint8_t *)cfg->net.mac);
|
ethernetif_apply_configured_or_internal_mac_locked(mac);
|
||||||
ch390_set_phy_mode(CH390_AUTO);
|
ch390_set_phy_mode(CH390_AUTO);
|
||||||
ch390_rx_enable(1);
|
ch390_rx_enable(1);
|
||||||
link_status = (uint8_t)ch390_get_link_status();
|
ethernetif_prepare_runtime_netif_locked(&ch390_netif);
|
||||||
}
|
ethernetif_apply_runtime_netif_config_locked(ipaddr,
|
||||||
else
|
netmask,
|
||||||
{
|
gw,
|
||||||
ch390_rx_reset();
|
(s_effective_mac_valid != 0u) ? s_effective_mac : NULL);
|
||||||
}
|
local_link_status = (uint8_t)ch390_get_link_status();
|
||||||
|
|
||||||
if (spi_mutex != NULL)
|
if (spi_mutex != NULL)
|
||||||
{
|
{
|
||||||
xSemaphoreGive(spi_mutex);
|
xSemaphoreGive(spi_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recovery_type == ETH_RECOVERY_FULL)
|
|
||||||
{
|
|
||||||
ch390_interrupt_init();
|
ch390_interrupt_init();
|
||||||
|
|
||||||
|
if (link_status != NULL)
|
||||||
|
{
|
||||||
|
*link_status = local_link_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
count = ethernetif_record_counter(&s_recovery.full_recovery_count);
|
||||||
debug_log_printf("[ETH] rec full n=%lu link=%u\r\n",
|
debug_log_printf("[ETH] rec full n=%lu link=%u\r\n",
|
||||||
(unsigned long)count,
|
(unsigned long)count,
|
||||||
(unsigned int)link_status);
|
(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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ethernetif_finish_recovery();
|
void ethernetif_force_link_down(void)
|
||||||
return recovery_type;
|
{
|
||||||
|
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 offset;
|
||||||
uint16_t tx_len;
|
uint16_t tx_len;
|
||||||
int tx_rc;
|
int tx_rc;
|
||||||
uint32_t tx_timeout_count;
|
uint32_t tx_timeout_streak;
|
||||||
(void)netif;
|
(void)netif;
|
||||||
|
|
||||||
/* Take SPI mutex */
|
/* 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.drop);
|
||||||
LINK_STATS_INC(link.err);
|
LINK_STATS_INC(link.err);
|
||||||
tx_timeout_count = ethernetif_record_event_and_request(&s_recovery.tx_timeout_count, ETH_RECOVERY_FULL);
|
tx_timeout_streak = ethernetif_note_tx_timeout_streak();
|
||||||
debug_log_printf("[ETH] tx timeout n=%lu\r\n", (unsigned long)tx_timeout_count);
|
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;
|
return ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ethernetif_clear_tx_timeout_streak();
|
||||||
LINK_STATS_INC(link.xmit);
|
LINK_STATS_INC(link.xmit);
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
@@ -330,12 +641,9 @@ static struct pbuf *low_level_input(struct netif *netif)
|
|||||||
struct pbuf *p = NULL;
|
struct pbuf *p = NULL;
|
||||||
struct pbuf *q;
|
struct pbuf *q;
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
uint16_t peek_len;
|
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
uint32_t rx_len;
|
uint32_t rx_len;
|
||||||
uint8_t rx_status;
|
uint8_t rx_status;
|
||||||
uint32_t rx_bad_count;
|
|
||||||
int peek_ready;
|
|
||||||
|
|
||||||
/* Take SPI mutex */
|
/* Take SPI mutex */
|
||||||
if (spi_mutex != NULL)
|
if (spi_mutex != NULL)
|
||||||
@@ -343,37 +651,6 @@ static struct pbuf *low_level_input(struct netif *netif)
|
|||||||
xSemaphoreTake(spi_mutex, portMAX_DELAY);
|
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);
|
rx_len = ch390_runtime_receive_packet(s_rx_buffer, &rx_status);
|
||||||
ethernetif->rx_status = rx_status;
|
ethernetif->rx_status = rx_status;
|
||||||
ethernetif->rx_len = (uint16_t)rx_len;
|
ethernetif->rx_len = (uint16_t)rx_len;
|
||||||
@@ -384,14 +661,6 @@ static struct pbuf *low_level_input(struct netif *netif)
|
|||||||
{
|
{
|
||||||
xSemaphoreGive(spi_mutex);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,7 +869,7 @@ void ethernetif_diag_ch390_init(void)
|
|||||||
ch390_spi_init();
|
ch390_spi_init();
|
||||||
ch390_hardware_reset();
|
ch390_hardware_reset();
|
||||||
ch390_default_config();
|
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();
|
ch390_interrupt_init();
|
||||||
|
|
||||||
g_netif_init_ok = 1;
|
g_netif_init_ok = 1;
|
||||||
@@ -629,8 +898,12 @@ void ethernetif_diag_poll_status(void)
|
|||||||
*/
|
*/
|
||||||
static void ethernetif_update_link(uint8_t link_status)
|
static void ethernetif_update_link(uint8_t link_status)
|
||||||
{
|
{
|
||||||
|
uint8_t old_link_status;
|
||||||
|
|
||||||
LOCK_TCPIP_CORE();
|
LOCK_TCPIP_CORE();
|
||||||
|
|
||||||
|
old_link_status = netif_is_link_up(&ch390_netif) ? 1u : 0u;
|
||||||
|
|
||||||
if (link_status)
|
if (link_status)
|
||||||
{
|
{
|
||||||
if (!netif_is_link_up(&ch390_netif))
|
if (!netif_is_link_up(&ch390_netif))
|
||||||
@@ -653,6 +926,22 @@ static void ethernetif_update_link(uint8_t link_status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
UNLOCK_TCPIP_CORE();
|
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,8 +976,11 @@ void ethernetif_poll(void)
|
|||||||
{
|
{
|
||||||
LINK_STATS_INC(link.err);
|
LINK_STATS_INC(link.err);
|
||||||
rx_overflow_count = ethernetif_record_event_and_request(&s_recovery.rx_overflow_count, ETH_RECOVERY_RX);
|
rx_overflow_count = ethernetif_record_event_and_request(&s_recovery.rx_overflow_count, ETH_RECOVERY_RX);
|
||||||
|
if (ethernetif_should_log_counter(rx_overflow_count) != 0u)
|
||||||
|
{
|
||||||
debug_log_printf("[ETH] rx ovf n=%lu\r\n", (unsigned long)rx_overflow_count);
|
debug_log_printf("[ETH] rx ovf n=%lu\r\n", (unsigned long)rx_overflow_count);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
recovery_type = ethernetif_run_pending_recovery();
|
recovery_type = ethernetif_run_pending_recovery();
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,20 @@ void ethernetif_diag_poll_status(void);
|
|||||||
* @note Call this from the LwIP task periodically or on interrupt
|
* @note Call this from the LwIP task periodically or on interrupt
|
||||||
*/
|
*/
|
||||||
void ethernetif_check_link(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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query whether physical Ethernet link is currently up
|
* @brief Query whether physical Ethernet link is currently up
|
||||||
|
|||||||
Reference in New Issue
Block a user