atm/br2684: register notifier event for carrier signal changes.
Karl Hiramoto [Thu, 8 Jul 2010 20:55:31 +0000 (20:55 +0000)]
When a signal change event occurs call netif_carrier_on/off.

Signed-off-by: Karl Hiramoto <karl@hiramoto.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/atm/br2684.c

index 6719af6..651babd 100644 (file)
@@ -139,6 +139,43 @@ static struct net_device *br2684_find_dev(const struct br2684_if_spec *s)
        return NULL;
 }
 
+static int atm_dev_event(struct notifier_block *this, unsigned long event,
+                void *arg)
+{
+       struct atm_dev *atm_dev = arg;
+       struct list_head *lh;
+       struct net_device *net_dev;
+       struct br2684_vcc *brvcc;
+       struct atm_vcc *atm_vcc;
+       unsigned long flags;
+
+       pr_debug("event=%ld dev=%p\n", event, atm_dev);
+
+       read_lock_irqsave(&devs_lock, flags);
+       list_for_each(lh, &br2684_devs) {
+               net_dev = list_entry_brdev(lh);
+
+               list_for_each_entry(brvcc, &BRPRIV(net_dev)->brvccs, brvccs) {
+                       atm_vcc = brvcc->atmvcc;
+                       if (atm_vcc && brvcc->atmvcc->dev == atm_dev) {
+
+                               if (atm_vcc->dev->signal == ATM_PHY_SIG_LOST)
+                                       netif_carrier_off(net_dev);
+                               else
+                                       netif_carrier_on(net_dev);
+
+                       }
+               }
+       }
+       read_unlock_irqrestore(&devs_lock, flags);
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block atm_dev_notifier = {
+       .notifier_call = atm_dev_event,
+};
+
 /* chained vcc->pop function.  Check if we should wake the netif_queue */
 static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
 {
@@ -362,6 +399,12 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
                        unregister_netdev(net_dev);
                        free_netdev(net_dev);
                }
+               read_lock_irq(&devs_lock);
+               if (list_empty(&br2684_devs)) {
+                       /* last br2684 device */
+                       unregister_atmdevice_notifier(&atm_dev_notifier);
+               }
+               read_unlock_irq(&devs_lock);
                return;
        }
 
@@ -530,6 +573,13 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
 
                br2684_push(atmvcc, skb);
        }
+
+       /* initialize netdev carrier state */
+       if (atmvcc->dev->signal == ATM_PHY_SIG_LOST)
+               netif_carrier_off(net_dev);
+       else
+               netif_carrier_on(net_dev);
+
        __module_get(THIS_MODULE);
        return 0;
 
@@ -620,9 +670,16 @@ static int br2684_create(void __user *arg)
        }
 
        write_lock_irq(&devs_lock);
+
        brdev->payload = payload;
-       brdev->number = list_empty(&br2684_devs) ? 1 :
-           BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
+
+       if (list_empty(&br2684_devs)) {
+               /* 1st br2684 device */
+               register_atmdevice_notifier(&atm_dev_notifier);
+               brdev->number = 1;
+       } else
+               brdev->number = BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
+
        list_add_tail(&brdev->br2684_devs, &br2684_devs);
        write_unlock_irq(&devs_lock);
        return 0;
@@ -772,6 +829,11 @@ static void __exit br2684_exit(void)
        remove_proc_entry("br2684", atm_proc_root);
 #endif
 
+
+       /* if not already empty */
+       if (!list_empty(&br2684_devs))
+               unregister_atmdevice_notifier(&atm_dev_notifier);
+
        while (!list_empty(&br2684_devs)) {
                net_dev = list_entry_brdev(br2684_devs.next);
                brdev = BRPRIV(net_dev);