summaryrefslogtreecommitdiffstats
path: root/net/eth.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-05-14 16:08:04 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2014-05-15 08:16:30 +0200
commitbe0404c21f22da2d736168b2e56a9ae583cc3e95 (patch)
tree637570fff15aee4bc8f44376a04b4068fbeeb38f /net/eth.c
parent22b878d2518a2b31c5991f9c47a2b176f0ac246d (diff)
downloadbarebox-be0404c21f22da2d736168b2e56a9ae583cc3e95.tar.gz
barebox-be0404c21f22da2d736168b2e56a9ae583cc3e95.tar.xz
net: Allow to use multiple network interfaces at once
In barebox network packets always go out at the current ethernet device and are expected to be received from the current interface. This has some side effects. When for example an NFS is mounted when one interface is active and the interface is changed afterwards the NFS packets leave the new interface, but the NFS server won't be reachable there. Instead of changing the whole network traffic to the current ethernet interface we now initialize a network connection with the current network interface, but then the connection will continue to use that interface even when the current interface is changed. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'net/eth.c')
-rw-r--r--net/eth.c58
1 files changed, 31 insertions, 27 deletions
diff --git a/net/eth.c b/net/eth.c
index 3ced3cddbe..26a5ff747d 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -131,11 +131,6 @@ void of_eth_register_ethaddr(struct device_node *node, const char *ethaddr)
void eth_set_current(struct eth_device *eth)
{
- if (eth_current && eth_current->active) {
- eth_current->halt(eth_current);
- eth_current->active = 0;
- }
-
eth_current = eth;
}
@@ -178,83 +173,92 @@ int eth_complete(struct string_list *sl, char *instr)
/*
* Check for link if we haven't done so for longer.
*/
-static int eth_carrier_check(int force)
+static int eth_carrier_check(struct eth_device *edev, int force)
{
int ret;
if (!IS_ENABLED(CONFIG_PHYLIB))
return 0;
- if (!eth_current->phydev)
+ if (!edev->phydev)
return 0;
if (force)
- phy_wait_aneg_done(eth_current->phydev);
+ phy_wait_aneg_done(edev->phydev);
if (force || is_timeout(last_link_check, 5 * SECOND) ||
- !eth_current->phydev->link) {
- ret = phy_update_status(eth_current->phydev);
+ !edev->phydev->link) {
+ ret = phy_update_status(edev->phydev);
if (ret)
return ret;
last_link_check = get_time_ns();
}
- return eth_current->phydev->link ? 0 : -ENETDOWN;
+ return edev->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)
+static int eth_check_open(struct eth_device *edev)
{
int ret;
- if (!eth_current)
- return -ENODEV;
-
- if (eth_current->active)
+ if (edev->active)
return 0;
- ret = eth_current->open(eth_current);
+ ret = edev->open(eth_current);
if (ret)
return ret;
- eth_current->active = 1;
+ edev->active = 1;
- return eth_carrier_check(1);
+ return eth_carrier_check(edev, 1);
}
-int eth_send(void *packet, int length)
+int eth_send(struct eth_device *edev, void *packet, int length)
{
int ret;
- ret = eth_check_open();
+ ret = eth_check_open(edev);
if (ret)
return ret;
- ret = eth_carrier_check(0);
+ ret = eth_carrier_check(edev, 0);
if (ret)
return ret;
led_trigger_network(LED_TRIGGER_NET_TX);
- return eth_current->send(eth_current, packet, length);
+ return edev->send(eth_current, packet, length);
}
-int eth_rx(void)
+static int __eth_rx(struct eth_device *edev)
{
int ret;
- ret = eth_check_open();
+ ret = eth_check_open(edev);
if (ret)
return ret;
- ret = eth_carrier_check(0);
+ ret = eth_carrier_check(edev, 0);
if (ret)
return ret;
- return eth_current->recv(eth_current);
+ return edev->recv(eth_current);
+}
+
+int eth_rx(void)
+{
+ struct eth_device *edev;
+
+ list_for_each_entry(edev, &netdev_list, list) {
+ if (edev->active)
+ __eth_rx(edev);
+ }
+
+ return 0;
}
static int eth_set_ethaddr(struct param_d *param, void *priv)