drivers: ethernet: w5500: Add link status detection

Implemented link status detection using the W5500 built-in registers.
Added periodic link status polling, configurable via Kconfig.
Speeds up DHCPv4 from 9 seconds at best, to ~2 seconds after power-up.

Signed-off-by: Volodymyr Shymanskyy <vshymanskyi@gmail.com>
This commit is contained in:
Volodymyr Shymanskyy 2024-02-08 15:54:59 +02:00 committed by Alberto Escolar
parent 487a14c046
commit 77fc3eaf06
2 changed files with 60 additions and 18 deletions

View file

@ -275,6 +275,30 @@ static void w5500_rx(const struct device *dev)
w5500_command(dev, S0_CR_RECV);
}
static void w5500_update_link_status(const struct device *dev)
{
uint8_t phycfgr;
struct w5500_runtime *ctx = dev->data;
if (w5500_spi_read(dev, W5500_PHYCFGR, &phycfgr, 1) < 0) {
return;
}
if (phycfgr & 0x01) {
if (ctx->link_up != true) {
LOG_INF("%s: Link up", dev->name);
ctx->link_up = true;
net_eth_carrier_on(ctx->iface);
}
} else {
if (ctx->link_up != false) {
LOG_INF("%s: Link down", dev->name);
ctx->link_up = false;
net_eth_carrier_off(ctx->iface);
}
}
}
static void w5500_thread(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p2);
@ -282,11 +306,18 @@ static void w5500_thread(void *p1, void *p2, void *p3)
const struct device *dev = p1;
uint8_t ir;
int res;
struct w5500_runtime *ctx = dev->data;
const struct w5500_config *config = dev->config;
while (true) {
k_sem_take(&ctx->int_sem, K_FOREVER);
res = k_sem_take(&ctx->int_sem, K_MSEC(CONFIG_PHY_MONITOR_PERIOD));
if (res == 0) {
/* semaphore taken, update link status and receive packets */
if (ctx->link_up != true) {
w5500_update_link_status(dev);
}
while (gpio_pin_get_dt(&(config->interrupt))) {
/* Read interrupt */
@ -309,6 +340,10 @@ static void w5500_thread(void *p1, void *p2, void *p3)
}
}
}
} else if (res == -EAGAIN) {
/* semaphore timeout period expired, check link status */
w5500_update_link_status(dev);
}
}
}
@ -326,6 +361,9 @@ static void w5500_iface_init(struct net_if *iface)
}
ethernet_init(iface);
/* Do not start the interface until PHY link is up */
net_if_carrier_off(iface);
}
static enum ethernet_hw_caps w5500_get_capabilities(const struct device *dev)
@ -505,6 +543,8 @@ static int w5500_init(const struct device *dev)
const struct w5500_config *config = dev->config;
struct w5500_runtime *ctx = dev->data;
ctx->link_up = false;
if (!spi_is_ready_dt(&config->spi)) {
LOG_ERR("SPI master port %s not ready", config->spi.bus->name);
return -EINVAL;

View file

@ -25,6 +25,7 @@
#define W5500_SHAR 0x0009 /* Source MAC address */
#define W5500_IR 0x0015 /* Interrupt Register */
#define W5500_COMMON_REGS_LEN 0x0040
#define W5500_PHYCFGR 0x002E /* PHY Configuration register */
#define W5500_Sn_MR 0x0000 /* Sn Mode Register */
#define W5500_Sn_CR 0x0001 /* Sn Command Register */
@ -97,6 +98,7 @@ struct w5500_runtime {
struct gpio_callback gpio_cb;
struct k_sem tx_sem;
struct k_sem int_sem;
bool link_up;
void (*generate_mac)(uint8_t *mac);
uint8_t buf[NET_ETH_MAX_FRAME_SIZE];
};