|
@@ -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);
|
|
|
+}
|
|
|
+
|
|
|
+#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_inetaddr_notifier = {
|
|
|
+ .notifier_call = ocrdma_inetaddr_event
|
|
|
+};
|
|
|
+
|
|
|
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)
|