Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
[firefly-linux-kernel-4.4.55.git] / drivers / infiniband / hw / ocrdma / ocrdma_main.c
index 91443bcb9e0e89faf1a93d4dcacb22943f5e6e10..2ca86ca818bdf04d68a3f21c0cd74fa092c36504 100644 (file)
@@ -67,46 +67,24 @@ void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid)
        guid[7] = mac_addr[5];
 }
 
-static void ocrdma_build_sgid_mac(union ib_gid *sgid, unsigned char *mac_addr,
-                                 bool is_vlan, u16 vlan_id)
-{
-       sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
-       sgid->raw[8] = mac_addr[0] ^ 2;
-       sgid->raw[9] = mac_addr[1];
-       sgid->raw[10] = mac_addr[2];
-       if (is_vlan) {
-               sgid->raw[11] = vlan_id >> 8;
-               sgid->raw[12] = vlan_id & 0xff;
-       } else {
-               sgid->raw[11] = 0xff;
-               sgid->raw[12] = 0xfe;
-       }
-       sgid->raw[13] = mac_addr[3];
-       sgid->raw[14] = mac_addr[4];
-       sgid->raw[15] = mac_addr[5];
-}
-
-static bool ocrdma_add_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
-                           bool is_vlan, u16 vlan_id)
+static bool ocrdma_add_sgid(struct ocrdma_dev *dev, union ib_gid *new_sgid)
 {
        int i;
-       union ib_gid new_sgid;
        unsigned long flags;
 
        memset(&ocrdma_zero_sgid, 0, sizeof(union ib_gid));
 
-       ocrdma_build_sgid_mac(&new_sgid, mac_addr, is_vlan, vlan_id);
 
        spin_lock_irqsave(&dev->sgid_lock, flags);
        for (i = 0; i < OCRDMA_MAX_SGID; i++) {
                if (!memcmp(&dev->sgid_tbl[i], &ocrdma_zero_sgid,
                            sizeof(union ib_gid))) {
                        /* found free entry */
-                       memcpy(&dev->sgid_tbl[i], &new_sgid,
+                       memcpy(&dev->sgid_tbl[i], new_sgid,
                               sizeof(union ib_gid));
                        spin_unlock_irqrestore(&dev->sgid_lock, flags);
                        return true;
-               } else if (!memcmp(&dev->sgid_tbl[i], &new_sgid,
+               } else if (!memcmp(&dev->sgid_tbl[i], new_sgid,
                                   sizeof(union ib_gid))) {
                        /* entry already present, no addition is required. */
                        spin_unlock_irqrestore(&dev->sgid_lock, flags);
@@ -117,20 +95,17 @@ static bool ocrdma_add_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
        return false;
 }
 
-static bool ocrdma_del_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
-                           bool is_vlan, u16 vlan_id)
+static bool ocrdma_del_sgid(struct ocrdma_dev *dev, union ib_gid *sgid)
 {
        int found = false;
        int i;
-       union ib_gid sgid;
        unsigned long flags;
 
-       ocrdma_build_sgid_mac(&sgid, mac_addr, is_vlan, vlan_id);
 
        spin_lock_irqsave(&dev->sgid_lock, flags);
        /* first is default sgid, which cannot be deleted. */
        for (i = 1; i < OCRDMA_MAX_SGID; i++) {
-               if (!memcmp(&dev->sgid_tbl[i], &sgid, sizeof(union ib_gid))) {
+               if (!memcmp(&dev->sgid_tbl[i], sgid, sizeof(union ib_gid))) {
                        /* found matching entry */
                        memset(&dev->sgid_tbl[i], 0, sizeof(union ib_gid));
                        found = true;
@@ -141,75 +116,18 @@ static bool ocrdma_del_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,
        return found;
 }
 
-static void ocrdma_add_default_sgid(struct ocrdma_dev *dev)
-{
-       /* GID Index 0 - Invariant manufacturer-assigned EUI-64 */
-       union ib_gid *sgid = &dev->sgid_tbl[0];
-
-       sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
-       ocrdma_get_guid(dev, &sgid->raw[8]);
-}
-
-#if IS_ENABLED(CONFIG_VLAN_8021Q)
-static void ocrdma_add_vlan_sgids(struct ocrdma_dev *dev)
-{
-       struct net_device *netdev, *tmp;
-       u16 vlan_id;
-       bool is_vlan;
-
-       netdev = dev->nic_info.netdev;
-
-       rcu_read_lock();
-       for_each_netdev_rcu(&init_net, tmp) {
-               if (netdev == tmp || vlan_dev_real_dev(tmp) == netdev) {
-                       if (!netif_running(tmp) || !netif_oper_up(tmp))
-                               continue;
-                       if (netdev != tmp) {
-                               vlan_id = vlan_dev_vlan_id(tmp);
-                               is_vlan = true;
-                       } else {
-                               is_vlan = false;
-                               vlan_id = 0;
-                               tmp = netdev;
-                       }
-                       ocrdma_add_sgid(dev, tmp->dev_addr, is_vlan, vlan_id);
-               }
-       }
-       rcu_read_unlock();
-}
-#else
-static void ocrdma_add_vlan_sgids(struct ocrdma_dev *dev)
-{
-
-}
-#endif /* VLAN */
-
-static int ocrdma_build_sgid_tbl(struct ocrdma_dev *dev)
+static int ocrdma_addr_event(unsigned long event, struct net_device *netdev,
+                            union ib_gid *gid)
 {
-       ocrdma_add_default_sgid(dev);
-       ocrdma_add_vlan_sgids(dev);
-       return 0;
-}
-
-#if IS_ENABLED(CONFIG_IPV6)
-
-static int ocrdma_inet6addr_event(struct notifier_block *notifier,
-                                 unsigned long event, void *ptr)
-{
-       struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
-       struct net_device *netdev = ifa->idev->dev;
        struct ib_event gid_event;
        struct ocrdma_dev *dev;
        bool found = false;
        bool updated = false;
        bool is_vlan = false;
-       u16 vid = 0;
 
        is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN;
-       if (is_vlan) {
-               vid = vlan_dev_vlan_id(netdev);
+       if (is_vlan)
                netdev = vlan_dev_real_dev(netdev);
-       }
 
        rcu_read_lock();
        list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
@@ -222,16 +140,14 @@ static int ocrdma_inet6addr_event(struct notifier_block *notifier,
 
        if (!found)
                return NOTIFY_DONE;
-       if (!rdma_link_local_addr((struct in6_addr *)&ifa->addr))
-               return NOTIFY_DONE;
 
        mutex_lock(&dev->dev_lock);
        switch (event) {
        case NETDEV_UP:
-               updated = ocrdma_add_sgid(dev, netdev->dev_addr, is_vlan, vid);
+               updated = ocrdma_add_sgid(dev, gid);
                break;
        case NETDEV_DOWN:
-               updated = ocrdma_del_sgid(dev, netdev->dev_addr, is_vlan, vid);
+               updated = ocrdma_del_sgid(dev, gid);
                break;
        default:
                break;
@@ -247,6 +163,32 @@ static int ocrdma_inet6addr_event(struct notifier_block *notifier,
        return NOTIFY_OK;
 }
 
+static int ocrdma_inetaddr_event(struct notifier_block *notifier,
+                                 unsigned long event, void *ptr)
+{
+       struct in_ifaddr *ifa = ptr;
+       union ib_gid gid;
+       struct net_device *netdev = ifa->ifa_dev->dev;
+
+       ipv6_addr_set_v4mapped(ifa->ifa_address, (struct in6_addr *)&gid);
+       return ocrdma_addr_event(event, netdev, &gid);
+}
+
+static struct notifier_block ocrdma_inetaddr_notifier = {
+       .notifier_call = ocrdma_inetaddr_event
+};
+
+#if IS_ENABLED(CONFIG_IPV6)
+
+static int ocrdma_inet6addr_event(struct notifier_block *notifier,
+                                 unsigned long event, void *ptr)
+{
+       struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
+       union  ib_gid *gid = (union ib_gid *)&ifa->addr;
+       struct net_device *netdev = ifa->idev->dev;
+       return ocrdma_addr_event(event, netdev, gid);
+}
+
 static struct notifier_block ocrdma_inet6addr_notifier = {
        .notifier_call = ocrdma_inet6addr_event
 };
@@ -423,10 +365,6 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
        if (status)
                goto alloc_err;
 
-       status = ocrdma_build_sgid_tbl(dev);
-       if (status)
-               goto alloc_err;
-
        status = ocrdma_register_device(dev);
        if (status)
                goto alloc_err;
@@ -553,6 +491,10 @@ static int __init ocrdma_init_module(void)
 {
        int status;
 
+       status = register_inetaddr_notifier(&ocrdma_inetaddr_notifier);
+       if (status)
+               return status;
+
 #if IS_ENABLED(CONFIG_IPV6)
        status = register_inet6addr_notifier(&ocrdma_inet6addr_notifier);
        if (status)