]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/firewire/net.c
firewire: net: add carrier detection
[mv-sheeva.git] / drivers / firewire / net.c
index 1a467a91fb0b2c8ee4c7ac577f02c497d249e1dc..7fd51c9e243dd978a8651b7e1c56cbe0ff162f3c 100644 (file)
@@ -178,6 +178,7 @@ struct fwnet_device {
 
        /* Number of tx datagrams that have been queued but not yet acked */
        int queued_datagrams;
+       int peer_count;
 
        struct list_head peer_list;
        struct fw_card *card;
@@ -996,15 +997,23 @@ static void fwnet_transmit_packet_failed(struct fwnet_packet_task *ptask)
 static void fwnet_write_complete(struct fw_card *card, int rcode,
                                 void *payload, size_t length, void *data)
 {
-       struct fwnet_packet_task *ptask;
-
-       ptask = data;
+       struct fwnet_packet_task *ptask = data;
+       static unsigned long j;
+       static int last_rcode, errors_skipped;
 
        if (rcode == RCODE_COMPLETE) {
                fwnet_transmit_packet_done(ptask);
        } else {
-               fw_error("fwnet_write_complete: failed: %x\n", rcode);
                fwnet_transmit_packet_failed(ptask);
+
+               if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) {
+                       fw_error("fwnet_write_complete: "
+                               "failed: %x (skipped %d)\n", rcode, errors_skipped);
+
+                       errors_skipped = 0;
+                       last_rcode = rcode;
+               } else
+                       errors_skipped++;
        }
 }
 
@@ -1397,6 +1406,10 @@ static int fwnet_change_mtu(struct net_device *net, int new_mtu)
        return 0;
 }
 
+static const struct ethtool_ops fwnet_ethtool_ops = {
+       .get_link       = ethtool_op_get_link,
+};
+
 static const struct net_device_ops fwnet_netdev_ops = {
        .ndo_open       = fwnet_open,
        .ndo_stop       = fwnet_stop,
@@ -1415,6 +1428,8 @@ static void fwnet_init_dev(struct net_device *net)
        net->hard_header_len    = FWNET_HLEN;
        net->type               = ARPHRD_IEEE1394;
        net->tx_queue_len       = FWNET_TX_QUEUE_LEN;
+       net->ethtool_ops        = &fwnet_ethtool_ops;
+
 }
 
 /* caller must hold fwnet_device_mutex */
@@ -1455,6 +1470,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++;
        spin_unlock_irq(&dev->lock);
 
        return 0;
@@ -1526,6 +1542,9 @@ 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);
@@ -1541,6 +1560,7 @@ static void fwnet_remove_peer(struct fwnet_peer *peer)
 
        spin_lock_irq(&peer->dev->lock);
        list_del(&peer->peer_link);
+       peer->dev->peer_count--;
        spin_unlock_irq(&peer->dev->lock);
 
        list_for_each_entry_safe(pd, pd_next, &peer->pd_list, pd_link)
@@ -1560,6 +1580,11 @@ static int fwnet_remove(struct device *_dev)
 
        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);
+
        if (list_empty(&dev->peer_list)) {
                net = dev->netdev;
                unregister_netdev(net);