summaryrefslogtreecommitdiffstats
path: root/net/eth.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2012-09-26 17:53:29 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2012-09-27 23:55:12 +0200
commit0dc9de2efd7ea6fb613afec822b52b4bfe5a7b2e (patch)
treeba3e5e30565806280a1ee22dd49875cf61fa9cbe /net/eth.c
parent2263e27814f1db83745a9e65c373c957307c36a0 (diff)
downloadbarebox-0dc9de2efd7ea6fb613afec822b52b4bfe5a7b2e.tar.gz
barebox-0dc9de2efd7ea6fb613afec822b52b4bfe5a7b2e.tar.xz
net/eth: fix link handling
Check link status on eth device open time and then periodically every 5 seconds. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'net/eth.c')
-rw-r--r--net/eth.c75
1 files changed, 57 insertions, 18 deletions
diff --git a/net/eth.c b/net/eth.c
index 6cfe4f2bbc..9f528709d3 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -32,6 +32,7 @@
#include <malloc.h>
static struct eth_device *eth_current;
+static uint64_t last_link_check;
static LIST_HEAD(netdev_list);
@@ -128,24 +129,64 @@ int eth_complete(struct string_list *sl, char *instr)
}
#endif
-int eth_send(void *packet, int length)
+/*
+ * Check for link if we haven't done so for longer.
+ */
+static int eth_carrier_check(int force)
{
int ret;
- if (!eth_current)
- return -ENODEV;
+ if (!IS_ENABLED(CONFIG_PHYLIB))
+ return 0;
- if (!eth_current->active) {
- ret = eth_current->open(eth_current);
+ if (!eth_current->phydev)
+ return 0;
+
+ if (force || is_timeout(last_link_check, 5 * SECOND)) {
+ ret = phy_update_status(eth_current->phydev);
if (ret)
return ret;
-
- if (eth_current->phydev)
- eth_current->active = eth_current->phydev->link;
- else
- eth_current->active = 1;
+ last_link_check = get_time_ns();
}
+ return eth_current->phydev->link ? 0 : -ENETDOWN;
+}
+
+/*
+ * Check if we have a current ethernet device and
+ * eventually open it if we have to.
+ */
+static int eth_check_open(void)
+{
+ int ret;
+
+ if (!eth_current)
+ return -ENODEV;
+
+ if (eth_current->active)
+ return 0;
+
+ ret = eth_current->open(eth_current);
+ if (ret)
+ return ret;
+
+ eth_current->active = 1;
+
+ return eth_carrier_check(1);
+}
+
+int eth_send(void *packet, int length)
+{
+ int ret;
+
+ ret = eth_check_open();
+ if (ret)
+ return ret;
+
+ ret = eth_carrier_check(0);
+ if (ret)
+ return ret;
+
led_trigger_network(LED_TRIGGER_NET_TX);
return eth_current->send(eth_current, packet, length);
@@ -155,15 +196,13 @@ int eth_rx(void)
{
int ret;
- if (!eth_current)
- return -ENODEV;
+ ret = eth_check_open();
+ if (ret)
+ return ret;
- if (!eth_current->active) {
- ret = eth_current->open(eth_current);
- if (ret)
- return ret;
- eth_current->active = 1;
- }
+ ret = eth_carrier_check(0);
+ if (ret)
+ return ret;
return eth_current->recv(eth_current);
}