Fixed bug in generic driver failing to create debug interfaces, because the
authorFlorian Pose <fp@igh-essen.com>
Thu, 05 Nov 2009 12:08:21 +0100
changeset 1557 daf92232d9c5
parent 1556 52ec7297637c
child 1558 55213fcc93a6
Fixed bug in generic driver failing to create debug interfaces, because the
interface lock is held.
devices/generic.c
--- a/devices/generic.c	Thu Nov 05 10:22:58 2009 +0100
+++ b/devices/generic.c	Thu Nov 05 12:08:21 2009 +0100
@@ -72,6 +72,13 @@
     ec_device_t *ecdev;
 } ec_gen_device_t;
 
+typedef struct {
+    struct list_head list;
+    char name[IFNAMSIZ];
+    int ifindex;
+    uint8_t dev_addr[ETH_ALEN];
+} ec_gen_interface_desc_t;
+
 int ec_gen_device_open(ec_gen_device_t *);
 int ec_gen_device_stop(ec_gen_device_t *);
 int ec_gen_device_start_xmit(ec_gen_device_t *, struct sk_buff *);
@@ -127,8 +134,7 @@
 /** Init generic device.
  */
 int ec_gen_device_init(
-        ec_gen_device_t *dev,
-        struct net_device *real_netdev
+        ec_gen_device_t *dev
         )
 {
     ec_gen_device_t **priv;
@@ -141,7 +147,6 @@
     if (!dev->netdev) {
         return -ENOMEM;
     }
-    memcpy(dev->netdev->dev_addr, real_netdev->dev_addr, ETH_ALEN);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
     dev->netdev->netdev_ops = &ec_gen_netdev_ops;
@@ -181,7 +186,7 @@
  */
 int ec_gen_device_create_socket(
         ec_gen_device_t *dev,
-        struct net_device *real_netdev
+        ec_gen_interface_desc_t *desc
         )
 {
     int ret;
@@ -194,12 +199,12 @@
     }
 
     printk(KERN_ERR PFX "Binding socket to interface %i (%s).\n",
-            real_netdev->ifindex, real_netdev->name);
+            desc->ifindex, desc->name);
 
     memset(&sa, 0x00, sizeof(sa));
     sa.sll_family = AF_PACKET;
     sa.sll_protocol = htons(ETH_P_ETHERCAT);
-    sa.sll_ifindex = real_netdev->ifindex;
+    sa.sll_ifindex = desc->ifindex;
     ret = kernel_bind(dev->socket, (struct sockaddr *) &sa, sizeof(sa));
     if (ret) {
         printk(KERN_ERR PFX "Failed to bind() socket to interface.\n");
@@ -217,14 +222,16 @@
  */
 int ec_gen_device_offer(
         ec_gen_device_t *dev,
-        struct net_device *real_netdev
+        ec_gen_interface_desc_t *desc
         )
 {
     int ret = 0;
 
+    memcpy(dev->netdev->dev_addr, desc->dev_addr, ETH_ALEN);
+
     dev->ecdev = ecdev_offer(dev->netdev, ec_gen_poll, THIS_MODULE);
     if (dev->ecdev) {
-        if (ec_gen_device_create_socket(dev, real_netdev)) {
+        if (ec_gen_device_create_socket(dev, desc)) {
             ecdev_withdraw(dev->ecdev);
             dev->ecdev = NULL;
         } else if (ecdev_open(dev->ecdev)) {
@@ -316,7 +323,7 @@
 /** Offer device.
  */
 int offer_device(
-        struct net_device *netdev
+        ec_gen_interface_desc_t *desc
         )
 {
     ec_gen_device_t *gendev;
@@ -327,13 +334,13 @@
         return -ENOMEM;
     }
 
-    ret = ec_gen_device_init(gendev, netdev);
+    ret = ec_gen_device_init(gendev);
     if (ret) {
         kfree(gendev);
         return ret;
     }
 
-    if (ec_gen_device_offer(gendev, netdev)) {
+    if (ec_gen_device_offer(gendev, desc)) {
         list_add_tail(&gendev->list, &generic_devices);
     } else {
         ec_gen_device_clear(gendev);
@@ -368,27 +375,47 @@
 int __init ec_gen_init_module(void)
 {
     int ret = 0;
+    struct list_head descs;
     struct net_device *netdev;
+    ec_gen_interface_desc_t *desc, *next;
 
     printk(KERN_INFO PFX "EtherCAT master generic Ethernet device module %s\n",
             EC_MASTER_VERSION);
 
     INIT_LIST_HEAD(&generic_devices);
+    INIT_LIST_HEAD(&descs);
 
     read_lock(&dev_base_lock);
     for_each_netdev(&init_net, netdev) {
         if (netdev->type != ARPHRD_ETHER)
             continue;
-        ret = offer_device(netdev);
-        if (ret) {
+        desc = kmalloc(sizeof(ec_gen_interface_desc_t), GFP_KERNEL);
+        if (!desc) {
+            ret = -ENOMEM;
             read_unlock(&dev_base_lock);
             goto out_err;
         }
+        strncpy(desc->name, netdev->name, IFNAMSIZ);
+        desc->ifindex = netdev->ifindex;
+        memcpy(desc->dev_addr, netdev->dev_addr, ETH_ALEN);
+        list_add_tail(&desc->list, &descs);
     }
     read_unlock(&dev_base_lock);
+
+    list_for_each_entry_safe(desc, next, &descs, list) {
+        ret = offer_device(desc);
+        if (ret) {
+            goto out_err;
+        }
+        kfree(desc);
+    }
     return ret;
 
 out_err:
+    list_for_each_entry_safe(desc, next, &descs, list) {
+        list_del(&desc->list);
+        kfree(desc);
+    }
     clear_devices();
     return ret;
 }