From 2cecc865ae9b9819ea7f56553847451c5e19e2f1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 6 Mar 2020 15:07:20 +0100 Subject: net: Call net_poll() in a poller This adds calling of net_poll() in a poller. With this we can react to incoming packets like ping requests or fastboot requests. We could change to call net_poll() from a poller exclusively, but this would significantly slow down USB network controllers. As described in the patch these take a long time in the packet receive path. To work around this we keep the networking users call net_poll() at a high rate when they are waiting for incoming packets and only every 10ms we call net_poll() from a poller to get incoming traffic when no networking protocol is actively calling net_poll(). Signed-off-by: Sascha Hauer --- net/Kconfig | 1 + net/eth.c | 14 +++++++++----- net/net.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/Kconfig b/net/Kconfig index 12b6bdb56d..dc32f6a2cb 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -1,5 +1,6 @@ menuconfig NET bool "Networking Support" + select POLLER if NET diff --git a/net/eth.c b/net/eth.c index 4cd7d6119e..85110ef695 100644 --- a/net/eth.c +++ b/net/eth.c @@ -269,11 +269,16 @@ static void eth_do_work(struct eth_device *edev) struct eth_q *q, *tmp; int ret; - slice_acquire(eth_device_slice(edev)); + if (!phy_acquired(edev->phydev)) { + ret = eth_carrier_check(edev, 0); + if (ret) + return; + } - ret = eth_carrier_check(edev, 0); - if (ret) - goto out; + if (slice_acquired(eth_device_slice(edev))) + return; + + slice_acquire(eth_device_slice(edev)); edev->recv(edev); @@ -285,7 +290,6 @@ static void eth_do_work(struct eth_device *edev) free(q); } -out: slice_release(eth_device_slice(edev)); } diff --git a/net/net.c b/net/net.c index 5fd6246ab2..69c1bc6222 100644 --- a/net/net.c +++ b/net/net.c @@ -251,8 +251,58 @@ static int arp_request(struct eth_device *edev, IPaddr_t dest, unsigned char *et void net_poll(void) { + static bool in_net_poll; + + if (in_net_poll) + return; + + in_net_poll = true; + eth_rx(); + + in_net_poll = false; +} + +static void __net_poll(struct poller_struct *poller) +{ + static uint64_t last; + + /* + * USB network controllers take a long time in the receive path, + * so limit the polling rate to once per 10ms. This is due to + * deficiencies in the barebox USB stack: We can't queue URBs and + * receive a callback when they are done. Instead, we always + * synchronously queue an URB and wait for its completion. In case + * of USB network adapters the only way to detect if packets have + * been received is to queue a RX URB and see if it completes (in + * which case we have received data) or if it timeouts (no data + * available). The timeout can't be arbitrarily small, 2ms is the + * smallest we can do with the 1ms USB frame size. + * + * Given that we do a mixture of polling-as-fast-as-possible when + * we are waiting for network traffic (tftp, nfs and other users + * actively calling net_poll()) and doing a low frequency polling + * here to still get packets when no user is actively waiting for + * incoming packets. This is used to receive incoming ping packets + * and to get fastboot over ethernet going. + */ + if (!is_timeout(last, 10 * MSECOND)) + return; + + net_poll(); + + last = get_time_ns(); +} + +static struct poller_struct net_poller = { + .func = __net_poll, +}; + +static int init_net_poll(void) +{ + return poller_register(&net_poller, "net"); } +device_initcall(init_net_poll); static uint16_t net_udp_new_localport(void) { -- cgit v1.2.1