diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-10-26 18:46:54 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:22:36 -0500 |
commit | 2bdfe0baeca0e2750037b8fba71905c00ac3c515 (patch) | |
tree | feb34f19d0f280fe4b54bc49e49ab05ea7f085c7 | |
parent | 6c43ff18f91e54aa7555d8ae4f26eab7da5bce68 (diff) |
netpoll retry cleanup
The netpoll beast was still not happy. If the beast got
clogged pipes, it tended to stare blankly off in space
for a long time.
The problem couldn't be completely fixed because the
beast talked with irq's disabled. But it could be made
less painful and shorter.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
-rw-r--r-- | include/linux/netpoll.h | 1 | ||||
-rw-r--r-- | net/core/netpoll.c | 71 |
2 files changed, 33 insertions, 39 deletions
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index 93a8b7664423..c65d12ec7bb0 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h | |||
@@ -28,7 +28,6 @@ struct netpoll_info { | |||
28 | atomic_t refcnt; | 28 | atomic_t refcnt; |
29 | spinlock_t poll_lock; | 29 | spinlock_t poll_lock; |
30 | int poll_owner; | 30 | int poll_owner; |
31 | int tries; | ||
32 | int rx_flags; | 31 | int rx_flags; |
33 | spinlock_t rx_lock; | 32 | spinlock_t rx_lock; |
34 | struct netpoll *rx_np; /* netpoll that registered an rx_hook */ | 33 | struct netpoll *rx_np; /* netpoll that registered an rx_hook */ |
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 93cb828f3aaf..6b34c394672f 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -34,12 +34,12 @@ | |||
34 | #define MAX_UDP_CHUNK 1460 | 34 | #define MAX_UDP_CHUNK 1460 |
35 | #define MAX_SKBS 32 | 35 | #define MAX_SKBS 32 |
36 | #define MAX_QUEUE_DEPTH (MAX_SKBS / 2) | 36 | #define MAX_QUEUE_DEPTH (MAX_SKBS / 2) |
37 | #define MAX_RETRIES 20000 | ||
38 | 37 | ||
39 | static struct sk_buff_head skb_pool; | 38 | static struct sk_buff_head skb_pool; |
40 | 39 | ||
41 | static atomic_t trapped; | 40 | static atomic_t trapped; |
42 | 41 | ||
42 | #define USEC_PER_POLL 50 | ||
43 | #define NETPOLL_RX_ENABLED 1 | 43 | #define NETPOLL_RX_ENABLED 1 |
44 | #define NETPOLL_RX_DROP 2 | 44 | #define NETPOLL_RX_DROP 2 |
45 | 45 | ||
@@ -72,6 +72,7 @@ static void queue_process(void *p) | |||
72 | schedule_delayed_work(&npinfo->tx_work, HZ/10); | 72 | schedule_delayed_work(&npinfo->tx_work, HZ/10); |
73 | return; | 73 | return; |
74 | } | 74 | } |
75 | |||
75 | netif_tx_unlock_bh(dev); | 76 | netif_tx_unlock_bh(dev); |
76 | } | 77 | } |
77 | } | 78 | } |
@@ -244,50 +245,44 @@ repeat: | |||
244 | 245 | ||
245 | static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) | 246 | static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) |
246 | { | 247 | { |
247 | int status; | 248 | int status = NETDEV_TX_BUSY; |
248 | struct netpoll_info *npinfo; | 249 | unsigned long tries; |
250 | struct net_device *dev = np->dev; | ||
251 | struct netpoll_info *npinfo = np->dev->npinfo; | ||
252 | |||
253 | if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) { | ||
254 | __kfree_skb(skb); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | /* don't get messages out of order, and no recursion */ | ||
259 | if ( !(np->drop == netpoll_queue && skb_queue_len(&npinfo->txq)) | ||
260 | && npinfo->poll_owner != smp_processor_id() | ||
261 | && netif_tx_trylock(dev)) { | ||
262 | |||
263 | /* try until next clock tick */ | ||
264 | for(tries = jiffies_to_usecs(1)/USEC_PER_POLL; tries > 0; --tries) { | ||
265 | if (!netif_queue_stopped(dev)) | ||
266 | status = dev->hard_start_xmit(skb, dev); | ||
267 | |||
268 | if (status == NETDEV_TX_OK) | ||
269 | break; | ||
249 | 270 | ||
250 | if (!np || !np->dev || !netif_running(np->dev)) { | 271 | /* tickle device maybe there is some cleanup */ |
251 | __kfree_skb(skb); | 272 | netpoll_poll(np); |
252 | return; | ||
253 | } | ||
254 | 273 | ||
255 | npinfo = np->dev->npinfo; | 274 | udelay(USEC_PER_POLL); |
275 | } | ||
276 | netif_tx_unlock(dev); | ||
277 | } | ||
256 | 278 | ||
257 | /* avoid recursion */ | 279 | if (status != NETDEV_TX_OK) { |
258 | if (npinfo->poll_owner == smp_processor_id() || | 280 | /* requeue for later */ |
259 | np->dev->xmit_lock_owner == smp_processor_id()) { | ||
260 | if (np->drop) | 281 | if (np->drop) |
261 | np->drop(skb); | 282 | np->drop(skb); |
262 | else | 283 | else |
263 | __kfree_skb(skb); | 284 | __kfree_skb(skb); |
264 | return; | ||
265 | } | 285 | } |
266 | |||
267 | do { | ||
268 | npinfo->tries--; | ||
269 | netif_tx_lock(np->dev); | ||
270 | |||
271 | /* | ||
272 | * network drivers do not expect to be called if the queue is | ||
273 | * stopped. | ||
274 | */ | ||
275 | status = NETDEV_TX_BUSY; | ||
276 | if (!netif_queue_stopped(np->dev)) | ||
277 | status = np->dev->hard_start_xmit(skb, np->dev); | ||
278 | |||
279 | netif_tx_unlock(np->dev); | ||
280 | |||
281 | /* success */ | ||
282 | if(!status) { | ||
283 | npinfo->tries = MAX_RETRIES; /* reset */ | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | /* transmit busy */ | ||
288 | netpoll_poll(np); | ||
289 | udelay(50); | ||
290 | } while (npinfo->tries > 0); | ||
291 | } | 286 | } |
292 | 287 | ||
293 | void netpoll_send_udp(struct netpoll *np, const char *msg, int len) | 288 | void netpoll_send_udp(struct netpoll *np, const char *msg, int len) |
@@ -649,7 +644,7 @@ int netpoll_setup(struct netpoll *np) | |||
649 | npinfo->rx_np = NULL; | 644 | npinfo->rx_np = NULL; |
650 | spin_lock_init(&npinfo->poll_lock); | 645 | spin_lock_init(&npinfo->poll_lock); |
651 | npinfo->poll_owner = -1; | 646 | npinfo->poll_owner = -1; |
652 | npinfo->tries = MAX_RETRIES; | 647 | |
653 | spin_lock_init(&npinfo->rx_lock); | 648 | spin_lock_init(&npinfo->rx_lock); |
654 | skb_queue_head_init(&npinfo->arp_tx); | 649 | skb_queue_head_init(&npinfo->arp_tx); |
655 | skb_queue_head_init(&npinfo->txq); | 650 | skb_queue_head_init(&npinfo->txq); |