aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2005-12-20 18:19:51 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-01-03 16:11:01 -0500
commit4433f420e57afae0ab308b1e2b979f09c86bc115 (patch)
tree3481cdce9a8ba28ba8ad26d0ed49151c1d08f4b7 /net
parent4505a3ef720845b5db3ddb440de13cd4800fd508 (diff)
[BRIDGE]: handle speed detection after carrier changes
Speed of a interface may not be available until carrier is detected in the case of autonegotiation. To get the correct value we need to recheck speed after carrier event. But the check needs to be done in a context that is similar to normal ethtool interface (can sleep). Also, delay check for 1ms to try avoid any carrier bounce transitions. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_if.c49
-rw-r--r--net/bridge/br_notify.c14
-rw-r--r--net/bridge/br_private.h3
3 files changed, 44 insertions, 22 deletions
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 975abe254b7a..e6b8bb51d613 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -32,9 +32,8 @@
32 * ethtool, use ethtool_ops. Also, since driver might sleep need to 32 * ethtool, use ethtool_ops. Also, since driver might sleep need to
33 * not be holding any locks. 33 * not be holding any locks.
34 */ 34 */
35static int br_initial_port_cost(struct net_device *dev) 35static int port_cost(struct net_device *dev)
36{ 36{
37
38 struct ethtool_cmd ecmd = { ETHTOOL_GSET }; 37 struct ethtool_cmd ecmd = { ETHTOOL_GSET };
39 struct ifreq ifr; 38 struct ifreq ifr;
40 mm_segment_t old_fs; 39 mm_segment_t old_fs;
@@ -58,10 +57,6 @@ static int br_initial_port_cost(struct net_device *dev)
58 return 2; 57 return 2;
59 case SPEED_10: 58 case SPEED_10:
60 return 100; 59 return 100;
61 default:
62 pr_info("bridge: can't decode speed from %s: %d\n",
63 dev->name, ecmd.speed);
64 return 100;
65 } 60 }
66 } 61 }
67 62
@@ -75,6 +70,35 @@ static int br_initial_port_cost(struct net_device *dev)
75 return 100; /* assume old 10Mbps */ 70 return 100; /* assume old 10Mbps */
76} 71}
77 72
73
74/*
75 * Check for port carrier transistions.
76 * Called from work queue to allow for calling functions that
77 * might sleep (such as speed check), and to debounce.
78 */
79static void port_carrier_check(void *arg)
80{
81 struct net_bridge_port *p = arg;
82
83 rtnl_lock();
84 if (netif_carrier_ok(p->dev)) {
85 u32 cost = port_cost(p->dev);
86
87 spin_lock_bh(&p->br->lock);
88 if (p->state == BR_STATE_DISABLED) {
89 p->path_cost = cost;
90 br_stp_enable_port(p);
91 }
92 spin_unlock_bh(&p->br->lock);
93 } else {
94 spin_lock_bh(&p->br->lock);
95 if (p->state != BR_STATE_DISABLED)
96 br_stp_disable_port(p);
97 spin_unlock_bh(&p->br->lock);
98 }
99 rtnl_unlock();
100}
101
78static void destroy_nbp(struct net_bridge_port *p) 102static void destroy_nbp(struct net_bridge_port *p)
79{ 103{
80 struct net_device *dev = p->dev; 104 struct net_device *dev = p->dev;
@@ -102,6 +126,9 @@ static void del_nbp(struct net_bridge_port *p)
102 dev->br_port = NULL; 126 dev->br_port = NULL;
103 dev_set_promiscuity(dev, -1); 127 dev_set_promiscuity(dev, -1);
104 128
129 cancel_delayed_work(&p->carrier_check);
130 flush_scheduled_work();
131
105 spin_lock_bh(&br->lock); 132 spin_lock_bh(&br->lock);
106 br_stp_disable_port(p); 133 br_stp_disable_port(p);
107 spin_unlock_bh(&br->lock); 134 spin_unlock_bh(&br->lock);
@@ -195,10 +222,9 @@ static int find_portno(struct net_bridge *br)
195 return (index >= BR_MAX_PORTS) ? -EXFULL : index; 222 return (index >= BR_MAX_PORTS) ? -EXFULL : index;
196} 223}
197 224
198/* called with RTNL */ 225/* called with RTNL but without bridge lock */
199static struct net_bridge_port *new_nbp(struct net_bridge *br, 226static struct net_bridge_port *new_nbp(struct net_bridge *br,
200 struct net_device *dev, 227 struct net_device *dev)
201 unsigned long cost)
202{ 228{
203 int index; 229 int index;
204 struct net_bridge_port *p; 230 struct net_bridge_port *p;
@@ -215,12 +241,13 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
215 p->br = br; 241 p->br = br;
216 dev_hold(dev); 242 dev_hold(dev);
217 p->dev = dev; 243 p->dev = dev;
218 p->path_cost = cost; 244 p->path_cost = port_cost(dev);
219 p->priority = 0x8000 >> BR_PORT_BITS; 245 p->priority = 0x8000 >> BR_PORT_BITS;
220 dev->br_port = p; 246 dev->br_port = p;
221 p->port_no = index; 247 p->port_no = index;
222 br_init_port(p); 248 br_init_port(p);
223 p->state = BR_STATE_DISABLED; 249 p->state = BR_STATE_DISABLED;
250 INIT_WORK(&p->carrier_check, port_carrier_check, p);
224 kobject_init(&p->kobj); 251 kobject_init(&p->kobj);
225 252
226 return p; 253 return p;
@@ -351,7 +378,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
351 if (dev->br_port != NULL) 378 if (dev->br_port != NULL)
352 return -EBUSY; 379 return -EBUSY;
353 380
354 if (IS_ERR(p = new_nbp(br, dev, br_initial_port_cost(dev)))) 381 if (IS_ERR(p = new_nbp(br, dev)))
355 return PTR_ERR(p); 382 return PTR_ERR(p);
356 383
357 if ((err = br_fdb_insert(br, p, dev->dev_addr))) 384 if ((err = br_fdb_insert(br, p, dev->dev_addr)))
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 917311c6828b..a43a9c1d50d7 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -52,17 +52,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
52 br_stp_recalculate_bridge_id(br); 52 br_stp_recalculate_bridge_id(br);
53 break; 53 break;
54 54
55 case NETDEV_CHANGE: /* device is up but carrier changed */ 55 case NETDEV_CHANGE:
56 if (!(br->dev->flags & IFF_UP)) 56 if (br->dev->flags & IFF_UP)
57 break; 57 schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE);
58
59 if (netif_carrier_ok(dev)) {
60 if (p->state == BR_STATE_DISABLED)
61 br_stp_enable_port(p);
62 } else {
63 if (p->state != BR_STATE_DISABLED)
64 br_stp_disable_port(p);
65 }
66 break; 58 break;
67 59
68 case NETDEV_FEAT_CHANGE: 60 case NETDEV_FEAT_CHANGE:
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 2c249486476f..7ad53c2aa684 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -27,6 +27,8 @@
27#define BR_PORT_BITS 10 27#define BR_PORT_BITS 10
28#define BR_MAX_PORTS (1<<BR_PORT_BITS) 28#define BR_MAX_PORTS (1<<BR_PORT_BITS)
29 29
30#define BR_PORT_DEBOUNCE (HZ/10)
31
30typedef struct bridge_id bridge_id; 32typedef struct bridge_id bridge_id;
31typedef struct mac_addr mac_addr; 33typedef struct mac_addr mac_addr;
32typedef __u16 port_id; 34typedef __u16 port_id;
@@ -78,6 +80,7 @@ struct net_bridge_port
78 struct timer_list hold_timer; 80 struct timer_list hold_timer;
79 struct timer_list message_age_timer; 81 struct timer_list message_age_timer;
80 struct kobject kobj; 82 struct kobject kobj;
83 struct work_struct carrier_check;
81 struct rcu_head rcu; 84 struct rcu_head rcu;
82}; 85};
83 86