Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[sfrench/cifs-2.6.git] / drivers / infiniband / ulp / ipoib / ipoib_main.c
index 855c9deca8b716569d7014a0117ad220d00b6c73..c9f6077b615eb62db39dae44f385976c50018865 100644 (file)
@@ -148,8 +148,6 @@ static int ipoib_stop(struct net_device *dev)
 
        netif_stop_queue(dev);
 
-       clear_bit(IPOIB_FLAG_NETIF_STOPPED, &priv->flags);
-
        /*
         * Now flush workqueue to make sure a scheduled task doesn't
         * bring our internal state back up.
@@ -462,6 +460,9 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
        struct ipoib_dev_priv *priv = netdev_priv(dev);
        struct ipoib_path *path;
 
+       if (!priv->broadcast)
+               return NULL;
+
        path = kzalloc(sizeof *path, GFP_ATOMIC);
        if (!path)
                return NULL;
@@ -473,9 +474,10 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid)
        INIT_LIST_HEAD(&path->neigh_list);
 
        memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
-       path->pathrec.sgid      = priv->local_gid;
-       path->pathrec.pkey      = cpu_to_be16(priv->pkey);
-       path->pathrec.numb_path = 1;
+       path->pathrec.sgid          = priv->local_gid;
+       path->pathrec.pkey          = cpu_to_be16(priv->pkey);
+       path->pathrec.numb_path     = 1;
+       path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
 
        return path;
 }
@@ -496,6 +498,7 @@ static int path_rec_start(struct net_device *dev,
                                   IB_SA_PATH_REC_DGID          |
                                   IB_SA_PATH_REC_SGID          |
                                   IB_SA_PATH_REC_NUMB_PATH     |
+                                  IB_SA_PATH_REC_TRAFFIC_CLASS |
                                   IB_SA_PATH_REC_PKEY,
                                   1000, GFP_ATOMIC,
                                   path_rec_completion,
@@ -515,7 +518,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
        struct ipoib_path *path;
        struct ipoib_neigh *neigh;
 
-       neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+       neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev);
        if (!neigh) {
                ++dev->stats.tx_dropped;
                dev_kfree_skb_any(skb);
@@ -690,9 +693,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                goto out;
                        }
                } else if (neigh->ah) {
-                       if (unlikely(memcmp(&neigh->dgid.raw,
+                       if (unlikely((memcmp(&neigh->dgid.raw,
                                            skb->dst->neighbour->ha + 4,
-                                           sizeof(union ib_gid)))) {
+                                           sizeof(union ib_gid))) ||
+                                        (neigh->dev != dev))) {
                                spin_lock(&priv->lock);
                                /*
                                 * It's safe to call ipoib_put_ah() inside
@@ -815,6 +819,13 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
        unsigned long flags;
        struct ipoib_ah *ah = NULL;
 
+       neigh = *to_ipoib_neigh(n);
+       if (neigh) {
+               priv = netdev_priv(neigh->dev);
+               ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n",
+                         n->dev->name);
+       } else
+               return;
        ipoib_dbg(priv,
                  "neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
                  IPOIB_QPN(n->ha),
@@ -822,13 +833,10 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
 
        spin_lock_irqsave(&priv->lock, flags);
 
-       neigh = *to_ipoib_neigh(n);
-       if (neigh) {
-               if (neigh->ah)
-                       ah = neigh->ah;
-               list_del(&neigh->list);
-               ipoib_neigh_free(n->dev, neigh);
-       }
+       if (neigh->ah)
+               ah = neigh->ah;
+       list_del(&neigh->list);
+       ipoib_neigh_free(n->dev, neigh);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -836,7 +844,8 @@ static void ipoib_neigh_cleanup(struct neighbour *n)
                ipoib_put_ah(ah);
 }
 
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
+struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour,
+                                     struct net_device *dev)
 {
        struct ipoib_neigh *neigh;
 
@@ -845,6 +854,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
                return NULL;
 
        neigh->neighbour = neighbour;
+       neigh->dev = dev;
        *to_ipoib_neigh(neighbour) = neigh;
        skb_queue_head_init(&neigh->queue);
        ipoib_cm_set(neigh, NULL);
@@ -893,7 +903,7 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
                goto out_rx_ring_cleanup;
        }
 
-       /* priv->tx_head & tx_tail are already 0 */
+       /* priv->tx_head, tx_tail & tx_outstanding are already 0 */
 
        if (ipoib_ib_dev_init(dev, ca, port))
                goto out_tx_ring_cleanup;
@@ -1015,6 +1025,37 @@ static ssize_t show_pkey(struct device *dev,
 }
 static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
 
+static ssize_t show_umcast(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+
+       return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags));
+}
+
+static ssize_t set_umcast(struct device *dev,
+                         struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+       unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
+
+       if (umcast_val > 0) {
+               set_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+               ipoib_warn(priv, "ignoring multicast groups joined directly "
+                               "by userspace\n");
+       } else
+               clear_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+
+       return count;
+}
+static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast);
+
+int ipoib_add_umcast_attr(struct net_device *dev)
+{
+       return device_create_file(&dev->dev, &dev_attr_umcast);
+}
+
 static ssize_t create_child(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf, size_t count)
@@ -1081,7 +1122,7 @@ static struct net_device *ipoib_add_port(const char *format,
        if (result) {
                printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n",
                       hca->name, port, result);
-               goto alloc_mem_failed;
+               goto device_init_failed;
        }
 
        /*
@@ -1097,7 +1138,7 @@ static struct net_device *ipoib_add_port(const char *format,
        if (result) {
                printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n",
                       hca->name, port, result);
-               goto alloc_mem_failed;
+               goto device_init_failed;
        } else
                memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid));
 
@@ -1132,6 +1173,8 @@ static struct net_device *ipoib_add_port(const char *format,
                goto sysfs_failed;
        if (ipoib_add_pkey_attr(priv->dev))
                goto sysfs_failed;
+       if (ipoib_add_umcast_attr(priv->dev))
+               goto sysfs_failed;
        if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
                goto sysfs_failed;
        if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))