]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/infiniband/hw/mlx4/main.c
infiniband: remove dev_base_lock use
[net-next-2.6.git] / drivers / infiniband / hw / mlx4 / main.c
index e65db73fc2778437815f47a2f5ec8771a16cd0b4..4e55a28fb6d41d7c692295c7e42ae032b50337bf 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
 #include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
 
 #include <rdma/ib_smi.h>
 #include <rdma/ib_user_verbs.h>
@@ -79,6 +80,8 @@ static void init_query_mad(struct ib_smp *mad)
        mad->method        = IB_MGMT_METHOD_GET;
 }
 
+static union ib_gid zgid;
+
 static int mlx4_ib_query_device(struct ib_device *ibdev,
                                struct ib_device_attr *props)
 {
@@ -148,7 +151,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
        props->max_srq             = dev->dev->caps.num_srqs - dev->dev->caps.reserved_srqs;
        props->max_srq_wr          = dev->dev->caps.max_srq_wqes - 1;
        props->max_srq_sge         = dev->dev->caps.max_srq_sge;
-       props->max_fast_reg_page_list_len = PAGE_SIZE / sizeof (u64);
+       props->max_fast_reg_page_list_len = MLX4_MAX_FAST_REG_PAGES;
        props->local_ca_ack_delay  = dev->dev->caps.local_ca_ack_delay;
        props->atomic_cap          = dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_ATOMIC ?
                IB_ATOMIC_HCA : IB_ATOMIC_NONE;
@@ -369,14 +372,32 @@ out:
 static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
                                 struct ib_device_modify *props)
 {
+       struct mlx4_cmd_mailbox *mailbox;
+
        if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
                return -EOPNOTSUPP;
 
-       if (mask & IB_DEVICE_MODIFY_NODE_DESC) {
-               spin_lock(&to_mdev(ibdev)->sm_lock);
-               memcpy(ibdev->node_desc, props->node_desc, 64);
-               spin_unlock(&to_mdev(ibdev)->sm_lock);
-       }
+       if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
+               return 0;
+
+       spin_lock(&to_mdev(ibdev)->sm_lock);
+       memcpy(ibdev->node_desc, props->node_desc, 64);
+       spin_unlock(&to_mdev(ibdev)->sm_lock);
+
+       /*
+        * If possible, pass node desc to FW, so it can generate
+        * a 144 trap.  If cmd fails, just ignore.
+        */
+       mailbox = mlx4_alloc_cmd_mailbox(to_mdev(ibdev)->dev);
+       if (IS_ERR(mailbox))
+               return 0;
+
+       memset(mailbox->buf, 0, 256);
+       memcpy(mailbox->buf, props->node_desc, 64);
+       mlx4_cmd(to_mdev(ibdev)->dev, mailbox->dma, 1, 0,
+                MLX4_CMD_SET_NODE, MLX4_CMD_TIME_CLASS_A);
+
+       mlx4_free_cmd_mailbox(to_mdev(ibdev)->dev, mailbox);
 
        return 0;
 }
@@ -755,12 +776,17 @@ static struct device_attribute *mlx4_class_attributes[] = {
        &dev_attr_board_id
 };
 
-static void mlx4_addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
+static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, struct net_device *dev)
 {
        memcpy(eui, dev->dev_addr, 3);
        memcpy(eui + 5, dev->dev_addr + 3, 3);
-       eui[3] = 0xFF;
-       eui[4] = 0xFE;
+       if (vlan_id < 0x1000) {
+               eui[3] = vlan_id >> 8;
+               eui[4] = vlan_id & 0xff;
+       } else {
+               eui[3] = 0xff;
+               eui[4] = 0xfe;
+       }
        eui[0] ^= 2;
 }
 
@@ -802,28 +828,93 @@ static int update_ipv6_gids(struct mlx4_ib_dev *dev, int port, int clear)
 {
        struct net_device *ndev = dev->iboe.netdevs[port - 1];
        struct update_gid_work *work;
+       struct net_device *tmp;
+       int i;
+       u8 *hits;
+       int ret;
+       union ib_gid gid;
+       int free;
+       int found;
+       int need_update = 0;
+       u16 vid;
 
        work = kzalloc(sizeof *work, GFP_ATOMIC);
        if (!work)
                return -ENOMEM;
 
-       if (!clear) {
-               mlx4_addrconf_ifid_eui48(&work->gids[0].raw[8], ndev);
-               work->gids[0].global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+       hits = kzalloc(128, GFP_ATOMIC);
+       if (!hits) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rcu_read_lock();
+       for_each_netdev_rcu(&init_net, tmp) {
+               if (ndev && (tmp == ndev || rdma_vlan_dev_real_dev(tmp) == ndev)) {
+                       gid.global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+                       vid = rdma_vlan_dev_vlan_id(tmp);
+                       mlx4_addrconf_ifid_eui48(&gid.raw[8], vid, ndev);
+                       found = 0;
+                       free = -1;
+                       for (i = 0; i < 128; ++i) {
+                               if (free < 0 &&
+                                   !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid))
+                                       free = i;
+                               if (!memcmp(&dev->iboe.gid_table[port - 1][i], &gid, sizeof gid)) {
+                                       hits[i] = 1;
+                                       found = 1;
+                                       break;
+                               }
+                       }
+
+                       if (!found) {
+                               if (tmp == ndev &&
+                                   (memcmp(&dev->iboe.gid_table[port - 1][0],
+                                           &gid, sizeof gid) ||
+                                    !memcmp(&dev->iboe.gid_table[port - 1][0],
+                                            &zgid, sizeof gid))) {
+                                       dev->iboe.gid_table[port - 1][0] = gid;
+                                       ++need_update;
+                                       hits[0] = 1;
+                               } else if (free >= 0) {
+                                       dev->iboe.gid_table[port - 1][free] = gid;
+                                       hits[free] = 1;
+                                       ++need_update;
+                               }
+                       }
+               }
        }
+       rcu_read_unlock();
 
-       INIT_WORK(&work->work, update_gids_task);
-       work->port = port;
-       work->dev = dev;
-       queue_work(wq, &work->work);
+       for (i = 0; i < 128; ++i)
+               if (!hits[i]) {
+                       if (memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, sizeof zgid))
+                               ++need_update;
+                       dev->iboe.gid_table[port - 1][i] = zgid;
+               }
+
+       if (need_update) {
+               memcpy(work->gids, dev->iboe.gid_table[port - 1], sizeof work->gids);
+               INIT_WORK(&work->work, update_gids_task);
+               work->port = port;
+               work->dev = dev;
+               queue_work(wq, &work->work);
+       } else
+               kfree(work);
 
+       kfree(hits);
        return 0;
+
+out:
+       kfree(work);
+       return ret;
 }
 
 static void handle_en_event(struct mlx4_ib_dev *dev, int port, unsigned long event)
 {
        switch (event) {
        case NETDEV_UP:
+       case NETDEV_CHANGEADDR:
                update_ipv6_gids(dev, port, 0);
                break;
 
@@ -871,9 +962,11 @@ static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event
                }
        }
 
-       if (dev == iboe->netdevs[0])
+       if (dev == iboe->netdevs[0] ||
+           (iboe->netdevs[0] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[0]))
                handle_en_event(ibdev, 1, event);
-       else if (dev == iboe->netdevs[1])
+       else if (dev == iboe->netdevs[1]
+                || (iboe->netdevs[1] && rdma_vlan_dev_real_dev(dev) == iboe->netdevs[1]))
                handle_en_event(ibdev, 2, event);
 
        spin_unlock(&iboe->lock);