diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-12-17 22:22:33 +0100 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2010-12-19 15:27:02 +0100 |
commit | c16714704bb35165e5b85d927873dcc643772648 (patch) | |
tree | c8aa70b7d7aaf3984a7c1b8579bd7f2ae29ec39d /drivers/firewire | |
parent | 18bb36f9fab5980efeff063755c037a622f0231c (diff) | |
download | linux-c16714704bb35165e5b85d927873dcc643772648.tar.gz linux-c16714704bb35165e5b85d927873dcc643772648.tar.bz2 linux-c16714704bb35165e5b85d927873dcc643772648.zip |
firewire: net: set carrier state at ifup
At ifup, carrier status would be shown on even if it actually was off.
Also add an include for ethtool_ops rather than to rely on the one from
netdevice.h.
Note, we can alas not use fwnet_device_mutex to serialize access to
dev->peer_count (as I originally wanted). This would cause a lock
inversion:
- fwnet_probe | takes fwnet_device_mutex
+ register_netdev | takes rtnl_mutex
- devinet_ioctl | takes rtnl_mutex
+ fwnet_open | ...must not take fwnet_device_mutex
Hence use the dev->lock spinlock for serialization.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/net.c | 36 |
1 files changed, 21 insertions, 15 deletions
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 7fd51c9e243d..c2e194c58667 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -9,6 +9,7 @@ #include <linux/bug.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/ethtool.h> #include <linux/firewire.h> #include <linux/firewire-constants.h> #include <linux/highmem.h> @@ -178,8 +179,8 @@ struct fwnet_device { /* Number of tx datagrams that have been queued but not yet acked */ int queued_datagrams; - int peer_count; + int peer_count; struct list_head peer_list; struct fw_card *card; struct net_device *netdev; @@ -1222,6 +1223,14 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) return retval; } +static void set_carrier_state(struct fwnet_device *dev) +{ + if (dev->peer_count > 1) + netif_carrier_on(dev->netdev); + else + netif_carrier_off(dev->netdev); +} + /* ifup */ static int fwnet_open(struct net_device *net) { @@ -1235,6 +1244,10 @@ static int fwnet_open(struct net_device *net) } netif_start_queue(net); + spin_lock_irq(&dev->lock); + set_carrier_state(dev); + spin_unlock_irq(&dev->lock); + return 0; } @@ -1429,7 +1442,6 @@ static void fwnet_init_dev(struct net_device *net) net->type = ARPHRD_IEEE1394; net->tx_queue_len = FWNET_TX_QUEUE_LEN; net->ethtool_ops = &fwnet_ethtool_ops; - } /* caller must hold fwnet_device_mutex */ @@ -1471,6 +1483,7 @@ static int fwnet_add_peer(struct fwnet_device *dev, spin_lock_irq(&dev->lock); list_add_tail(&peer->peer_link, &dev->peer_list); dev->peer_count++; + set_carrier_state(dev); spin_unlock_irq(&dev->lock); return 0; @@ -1542,9 +1555,6 @@ static int fwnet_probe(struct device *_dev) unregister_netdev(net); list_del(&dev->dev_link); } - - if (dev->peer_count > 1) - netif_carrier_on(net); out: if (ret && allocated_netdev) free_netdev(net); @@ -1554,14 +1564,15 @@ static int fwnet_probe(struct device *_dev) return ret; } -static void fwnet_remove_peer(struct fwnet_peer *peer) +static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev) { struct fwnet_partial_datagram *pd, *pd_next; - spin_lock_irq(&peer->dev->lock); + spin_lock_irq(&dev->lock); list_del(&peer->peer_link); - peer->dev->peer_count--; - spin_unlock_irq(&peer->dev->lock); + dev->peer_count--; + set_carrier_state(dev); + spin_unlock_irq(&dev->lock); list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link) fwnet_pd_delete(pd); @@ -1578,12 +1589,7 @@ static int fwnet_remove(struct device *_dev) mutex_lock(&fwnet_device_mutex); - fwnet_remove_peer(peer); - - /* If we serve just one node, that means we lost link - with outer world */ - if (dev->peer_count == 1) - netif_carrier_off(dev->netdev); + fwnet_remove_peer(peer, dev); if (list_empty(&dev->peer_list)) { net = dev->netdev; |