diff options
Diffstat (limited to 'net/core/netpoll.c')
-rw-r--r-- | net/core/netpoll.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/net/core/netpoll.c b/net/core/netpoll.c index de1b26aa5720..abe6e3a4cc44 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c | |||
@@ -119,19 +119,22 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh, | |||
119 | static void poll_napi(struct netpoll *np) | 119 | static void poll_napi(struct netpoll *np) |
120 | { | 120 | { |
121 | struct netpoll_info *npinfo = np->dev->npinfo; | 121 | struct netpoll_info *npinfo = np->dev->npinfo; |
122 | struct napi_struct *napi; | ||
122 | int budget = 16; | 123 | int budget = 16; |
123 | 124 | ||
124 | if (test_bit(__LINK_STATE_RX_SCHED, &np->dev->state) && | 125 | list_for_each_entry(napi, &np->dev->napi_list, dev_list) { |
125 | npinfo->poll_owner != smp_processor_id() && | 126 | if (test_bit(NAPI_STATE_SCHED, &napi->state) && |
126 | spin_trylock(&npinfo->poll_lock)) { | 127 | napi->poll_owner != smp_processor_id() && |
127 | npinfo->rx_flags |= NETPOLL_RX_DROP; | 128 | spin_trylock(&napi->poll_lock)) { |
128 | atomic_inc(&trapped); | 129 | npinfo->rx_flags |= NETPOLL_RX_DROP; |
130 | atomic_inc(&trapped); | ||
129 | 131 | ||
130 | np->dev->poll(np->dev, &budget); | 132 | napi->poll(napi, budget); |
131 | 133 | ||
132 | atomic_dec(&trapped); | 134 | atomic_dec(&trapped); |
133 | npinfo->rx_flags &= ~NETPOLL_RX_DROP; | 135 | npinfo->rx_flags &= ~NETPOLL_RX_DROP; |
134 | spin_unlock(&npinfo->poll_lock); | 136 | spin_unlock(&napi->poll_lock); |
137 | } | ||
135 | } | 138 | } |
136 | } | 139 | } |
137 | 140 | ||
@@ -157,7 +160,7 @@ void netpoll_poll(struct netpoll *np) | |||
157 | 160 | ||
158 | /* Process pending work on NIC */ | 161 | /* Process pending work on NIC */ |
159 | np->dev->poll_controller(np->dev); | 162 | np->dev->poll_controller(np->dev); |
160 | if (np->dev->poll) | 163 | if (!list_empty(&np->dev->napi_list)) |
161 | poll_napi(np); | 164 | poll_napi(np); |
162 | 165 | ||
163 | service_arp_queue(np->dev->npinfo); | 166 | service_arp_queue(np->dev->npinfo); |
@@ -233,6 +236,17 @@ repeat: | |||
233 | return skb; | 236 | return skb; |
234 | } | 237 | } |
235 | 238 | ||
239 | static int netpoll_owner_active(struct net_device *dev) | ||
240 | { | ||
241 | struct napi_struct *napi; | ||
242 | |||
243 | list_for_each_entry(napi, &dev->napi_list, dev_list) { | ||
244 | if (napi->poll_owner == smp_processor_id()) | ||
245 | return 1; | ||
246 | } | ||
247 | return 0; | ||
248 | } | ||
249 | |||
236 | static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) | 250 | static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) |
237 | { | 251 | { |
238 | int status = NETDEV_TX_BUSY; | 252 | int status = NETDEV_TX_BUSY; |
@@ -246,8 +260,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) | |||
246 | } | 260 | } |
247 | 261 | ||
248 | /* don't get messages out of order, and no recursion */ | 262 | /* don't get messages out of order, and no recursion */ |
249 | if (skb_queue_len(&npinfo->txq) == 0 && | 263 | if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) { |
250 | npinfo->poll_owner != smp_processor_id()) { | ||
251 | unsigned long flags; | 264 | unsigned long flags; |
252 | 265 | ||
253 | local_irq_save(flags); | 266 | local_irq_save(flags); |
@@ -652,8 +665,6 @@ int netpoll_setup(struct netpoll *np) | |||
652 | 665 | ||
653 | npinfo->rx_flags = 0; | 666 | npinfo->rx_flags = 0; |
654 | npinfo->rx_np = NULL; | 667 | npinfo->rx_np = NULL; |
655 | spin_lock_init(&npinfo->poll_lock); | ||
656 | npinfo->poll_owner = -1; | ||
657 | 668 | ||
658 | spin_lock_init(&npinfo->rx_lock); | 669 | spin_lock_init(&npinfo->rx_lock); |
659 | skb_queue_head_init(&npinfo->arp_tx); | 670 | skb_queue_head_init(&npinfo->arp_tx); |