.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Linux network device link state notification |
---|
3 | 4 | * |
---|
4 | 5 | * Author: |
---|
5 | 6 | * Stefan Rompf <sux@loplof.de> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License |
---|
9 | | - * as published by the Free Software Foundation; either version |
---|
10 | | - * 2 of the License, or (at your option) any later version. |
---|
11 | | - * |
---|
12 | 7 | */ |
---|
13 | 8 | |
---|
14 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
39 | 34 | |
---|
40 | 35 | static unsigned char default_operstate(const struct net_device *dev) |
---|
41 | 36 | { |
---|
| 37 | + if (netif_testing(dev)) |
---|
| 38 | + return IF_OPER_TESTING; |
---|
| 39 | + |
---|
42 | 40 | if (!netif_carrier_ok(dev)) |
---|
43 | 41 | return (dev->ifindex != dev_get_iflink(dev) ? |
---|
44 | 42 | IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); |
---|
.. | .. |
---|
60 | 58 | write_lock_bh(&dev_base_lock); |
---|
61 | 59 | |
---|
62 | 60 | switch(dev->link_mode) { |
---|
| 61 | + case IF_LINK_MODE_TESTING: |
---|
| 62 | + if (operstate == IF_OPER_UP) |
---|
| 63 | + operstate = IF_OPER_TESTING; |
---|
| 64 | + break; |
---|
| 65 | + |
---|
63 | 66 | case IF_LINK_MODE_DORMANT: |
---|
64 | 67 | if (operstate == IF_OPER_UP) |
---|
65 | 68 | operstate = IF_OPER_DORMANT; |
---|
66 | 69 | break; |
---|
67 | | - |
---|
68 | 70 | case IF_LINK_MODE_DEFAULT: |
---|
69 | 71 | default: |
---|
70 | 72 | break; |
---|
.. | .. |
---|
79 | 81 | void linkwatch_init_dev(struct net_device *dev) |
---|
80 | 82 | { |
---|
81 | 83 | /* Handle pre-registration link state changes */ |
---|
82 | | - if (!netif_carrier_ok(dev) || netif_dormant(dev)) |
---|
| 84 | + if (!netif_carrier_ok(dev) || netif_dormant(dev) || |
---|
| 85 | + netif_testing(dev)) |
---|
83 | 86 | rfc2863_policy(dev); |
---|
84 | 87 | } |
---|
85 | 88 | |
---|
.. | .. |
---|
168 | 171 | |
---|
169 | 172 | static void __linkwatch_run_queue(int urgent_only) |
---|
170 | 173 | { |
---|
| 174 | +#define MAX_DO_DEV_PER_LOOP 100 |
---|
| 175 | + |
---|
| 176 | + int do_dev = MAX_DO_DEV_PER_LOOP; |
---|
171 | 177 | struct net_device *dev; |
---|
172 | 178 | LIST_HEAD(wrk); |
---|
| 179 | + |
---|
| 180 | + /* Give urgent case more budget */ |
---|
| 181 | + if (urgent_only) |
---|
| 182 | + do_dev += MAX_DO_DEV_PER_LOOP; |
---|
173 | 183 | |
---|
174 | 184 | /* |
---|
175 | 185 | * Limit the number of linkwatch events to one |
---|
.. | .. |
---|
189 | 199 | spin_lock_irq(&lweventlist_lock); |
---|
190 | 200 | list_splice_init(&lweventlist, &wrk); |
---|
191 | 201 | |
---|
192 | | - while (!list_empty(&wrk)) { |
---|
| 202 | + while (!list_empty(&wrk) && do_dev > 0) { |
---|
193 | 203 | |
---|
194 | 204 | dev = list_first_entry(&wrk, struct net_device, link_watch_list); |
---|
195 | 205 | list_del_init(&dev->link_watch_list); |
---|
196 | 206 | |
---|
197 | | - if (urgent_only && !linkwatch_urgent_event(dev)) { |
---|
| 207 | + if (!netif_device_present(dev) || |
---|
| 208 | + (urgent_only && !linkwatch_urgent_event(dev))) { |
---|
198 | 209 | list_add_tail(&dev->link_watch_list, &lweventlist); |
---|
199 | 210 | continue; |
---|
200 | 211 | } |
---|
201 | 212 | spin_unlock_irq(&lweventlist_lock); |
---|
202 | 213 | linkwatch_do_dev(dev); |
---|
| 214 | + do_dev--; |
---|
203 | 215 | spin_lock_irq(&lweventlist_lock); |
---|
204 | 216 | } |
---|
205 | 217 | |
---|
| 218 | + /* Add the remaining work back to lweventlist */ |
---|
| 219 | + list_splice_init(&wrk, &lweventlist); |
---|
| 220 | + |
---|
206 | 221 | if (!list_empty(&lweventlist)) |
---|
207 | 222 | linkwatch_schedule_work(0); |
---|
208 | 223 | spin_unlock_irq(&lweventlist_lock); |
---|