Commit c1671470 authored by Stefan Richter's avatar Stefan Richter

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: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent 18bb36f9
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/firewire.h> #include <linux/firewire.h>
#include <linux/firewire-constants.h> #include <linux/firewire-constants.h>
#include <linux/highmem.h> #include <linux/highmem.h>
...@@ -178,8 +179,8 @@ struct fwnet_device { ...@@ -178,8 +179,8 @@ struct fwnet_device {
/* Number of tx datagrams that have been queued but not yet acked */ /* Number of tx datagrams that have been queued but not yet acked */
int queued_datagrams; int queued_datagrams;
int peer_count;
int peer_count;
struct list_head peer_list; struct list_head peer_list;
struct fw_card *card; struct fw_card *card;
struct net_device *netdev; struct net_device *netdev;
...@@ -1222,6 +1223,14 @@ static int fwnet_broadcast_start(struct fwnet_device *dev) ...@@ -1222,6 +1223,14 @@ static int fwnet_broadcast_start(struct fwnet_device *dev)
return retval; 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 */ /* ifup */
static int fwnet_open(struct net_device *net) static int fwnet_open(struct net_device *net)
{ {
...@@ -1235,6 +1244,10 @@ static int fwnet_open(struct net_device *net) ...@@ -1235,6 +1244,10 @@ static int fwnet_open(struct net_device *net)
} }
netif_start_queue(net); netif_start_queue(net);
spin_lock_irq(&dev->lock);
set_carrier_state(dev);
spin_unlock_irq(&dev->lock);
return 0; return 0;
} }
...@@ -1429,7 +1442,6 @@ static void fwnet_init_dev(struct net_device *net) ...@@ -1429,7 +1442,6 @@ static void fwnet_init_dev(struct net_device *net)
net->type = ARPHRD_IEEE1394; net->type = ARPHRD_IEEE1394;
net->tx_queue_len = FWNET_TX_QUEUE_LEN; net->tx_queue_len = FWNET_TX_QUEUE_LEN;
net->ethtool_ops = &fwnet_ethtool_ops; net->ethtool_ops = &fwnet_ethtool_ops;
} }
/* caller must hold fwnet_device_mutex */ /* caller must hold fwnet_device_mutex */
...@@ -1471,6 +1483,7 @@ static int fwnet_add_peer(struct fwnet_device *dev, ...@@ -1471,6 +1483,7 @@ static int fwnet_add_peer(struct fwnet_device *dev,
spin_lock_irq(&dev->lock); spin_lock_irq(&dev->lock);
list_add_tail(&peer->peer_link, &dev->peer_list); list_add_tail(&peer->peer_link, &dev->peer_list);
dev->peer_count++; dev->peer_count++;
set_carrier_state(dev);
spin_unlock_irq(&dev->lock); spin_unlock_irq(&dev->lock);
return 0; return 0;
...@@ -1542,9 +1555,6 @@ static int fwnet_probe(struct device *_dev) ...@@ -1542,9 +1555,6 @@ static int fwnet_probe(struct device *_dev)
unregister_netdev(net); unregister_netdev(net);
list_del(&dev->dev_link); list_del(&dev->dev_link);
} }
if (dev->peer_count > 1)
netif_carrier_on(net);
out: out:
if (ret && allocated_netdev) if (ret && allocated_netdev)
free_netdev(net); free_netdev(net);
...@@ -1554,14 +1564,15 @@ static int fwnet_probe(struct device *_dev) ...@@ -1554,14 +1564,15 @@ static int fwnet_probe(struct device *_dev)
return ret; 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; struct fwnet_partial_datagram *pd, *pd_next;
spin_lock_irq(&peer->dev->lock); spin_lock_irq(&dev->lock);
list_del(&peer->peer_link); list_del(&peer->peer_link);
peer->dev->peer_count--; dev->peer_count--;
spin_unlock_irq(&peer->dev->lock); set_carrier_state(dev);
spin_unlock_irq(&dev->lock);
list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link) list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)
fwnet_pd_delete(pd); fwnet_pd_delete(pd);
...@@ -1578,12 +1589,7 @@ static int fwnet_remove(struct device *_dev) ...@@ -1578,12 +1589,7 @@ static int fwnet_remove(struct device *_dev)
mutex_lock(&fwnet_device_mutex); mutex_lock(&fwnet_device_mutex);
fwnet_remove_peer(peer); fwnet_remove_peer(peer, dev);
/* If we serve just one node, that means we lost link
with outer world */
if (dev->peer_count == 1)
netif_carrier_off(dev->netdev);
if (list_empty(&dev->peer_list)) { if (list_empty(&dev->peer_list)) {
net = dev->netdev; net = dev->netdev;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment