|
@@ -32,9 +32,8 @@
|
|
|
* ethtool, use ethtool_ops. Also, since driver might sleep need to
|
|
|
* not be holding any locks.
|
|
|
*/
|
|
|
-static int br_initial_port_cost(struct net_device *dev)
|
|
|
+static int port_cost(struct net_device *dev)
|
|
|
{
|
|
|
-
|
|
|
struct ethtool_cmd ecmd = { ETHTOOL_GSET };
|
|
|
struct ifreq ifr;
|
|
|
mm_segment_t old_fs;
|
|
@@ -58,10 +57,6 @@ static int br_initial_port_cost(struct net_device *dev)
|
|
|
return 2;
|
|
|
case SPEED_10:
|
|
|
return 100;
|
|
|
- default:
|
|
|
- pr_info("bridge: can't decode speed from %s: %d\n",
|
|
|
- dev->name, ecmd.speed);
|
|
|
- return 100;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -75,6 +70,35 @@ static int br_initial_port_cost(struct net_device *dev)
|
|
|
return 100; /* assume old 10Mbps */
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+/*
|
|
|
+ * Check for port carrier transistions.
|
|
|
+ * Called from work queue to allow for calling functions that
|
|
|
+ * might sleep (such as speed check), and to debounce.
|
|
|
+ */
|
|
|
+static void port_carrier_check(void *arg)
|
|
|
+{
|
|
|
+ struct net_bridge_port *p = arg;
|
|
|
+
|
|
|
+ rtnl_lock();
|
|
|
+ if (netif_carrier_ok(p->dev)) {
|
|
|
+ u32 cost = port_cost(p->dev);
|
|
|
+
|
|
|
+ spin_lock_bh(&p->br->lock);
|
|
|
+ if (p->state == BR_STATE_DISABLED) {
|
|
|
+ p->path_cost = cost;
|
|
|
+ br_stp_enable_port(p);
|
|
|
+ }
|
|
|
+ spin_unlock_bh(&p->br->lock);
|
|
|
+ } else {
|
|
|
+ spin_lock_bh(&p->br->lock);
|
|
|
+ if (p->state != BR_STATE_DISABLED)
|
|
|
+ br_stp_disable_port(p);
|
|
|
+ spin_unlock_bh(&p->br->lock);
|
|
|
+ }
|
|
|
+ rtnl_unlock();
|
|
|
+}
|
|
|
+
|
|
|
static void destroy_nbp(struct net_bridge_port *p)
|
|
|
{
|
|
|
struct net_device *dev = p->dev;
|
|
@@ -102,6 +126,9 @@ static void del_nbp(struct net_bridge_port *p)
|
|
|
dev->br_port = NULL;
|
|
|
dev_set_promiscuity(dev, -1);
|
|
|
|
|
|
+ cancel_delayed_work(&p->carrier_check);
|
|
|
+ flush_scheduled_work();
|
|
|
+
|
|
|
spin_lock_bh(&br->lock);
|
|
|
br_stp_disable_port(p);
|
|
|
spin_unlock_bh(&br->lock);
|
|
@@ -195,10 +222,9 @@ static int find_portno(struct net_bridge *br)
|
|
|
return (index >= BR_MAX_PORTS) ? -EXFULL : index;
|
|
|
}
|
|
|
|
|
|
-/* called with RTNL */
|
|
|
+/* called with RTNL but without bridge lock */
|
|
|
static struct net_bridge_port *new_nbp(struct net_bridge *br,
|
|
|
- struct net_device *dev,
|
|
|
- unsigned long cost)
|
|
|
+ struct net_device *dev)
|
|
|
{
|
|
|
int index;
|
|
|
struct net_bridge_port *p;
|
|
@@ -215,12 +241,13 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
|
|
|
p->br = br;
|
|
|
dev_hold(dev);
|
|
|
p->dev = dev;
|
|
|
- p->path_cost = cost;
|
|
|
+ p->path_cost = port_cost(dev);
|
|
|
p->priority = 0x8000 >> BR_PORT_BITS;
|
|
|
dev->br_port = p;
|
|
|
p->port_no = index;
|
|
|
br_init_port(p);
|
|
|
p->state = BR_STATE_DISABLED;
|
|
|
+ INIT_WORK(&p->carrier_check, port_carrier_check, p);
|
|
|
kobject_init(&p->kobj);
|
|
|
|
|
|
return p;
|
|
@@ -351,7 +378,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
|
|
|
if (dev->br_port != NULL)
|
|
|
return -EBUSY;
|
|
|
|
|
|
- if (IS_ERR(p = new_nbp(br, dev, br_initial_port_cost(dev))))
|
|
|
+ if (IS_ERR(p = new_nbp(br, dev)))
|
|
|
return PTR_ERR(p);
|
|
|
|
|
|
if ((err = br_fdb_insert(br, p, dev->dev_addr)))
|