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:
parent
487a14c046
commit
77fc3eaf06
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue