diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2020-03-06 15:07:20 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2020-08-19 07:36:14 +0200 |
commit | 2cecc865ae9b9819ea7f56553847451c5e19e2f1 (patch) | |
tree | eedfe5d5ce62be1d9671084906cb8f71c50360d6 /net | |
parent | 5eb56c4e482937d2e01eb79fcc0086787084ba5a (diff) | |
download | barebox-2cecc865ae9b9819ea7f56553847451c5e19e2f1.tar.gz barebox-2cecc865ae9b9819ea7f56553847451c5e19e2f1.tar.xz |
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 <s.hauer@pengutronix.de>
Diffstat (limited to 'net')
-rw-r--r-- | net/Kconfig | 1 | ||||
-rw-r--r-- | net/eth.c | 14 | ||||
-rw-r--r-- | net/net.c | 50 |
3 files changed, 60 insertions, 5 deletions
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 @@ -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)); } @@ -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) { |