787 lines
22 KiB
C
787 lines
22 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
||
// Copyright(c) 2024 Huawei Technologies Co., Ltd
|
||
|
||
#include "roce_netdev.h"
|
||
#include "roce_netdev_extension.h"
|
||
#include "roce_main_extension.h"
|
||
#include "roce_pub_cmd.h"
|
||
#include "hinic3_rdma.h"
|
||
#include "roce.h"
|
||
|
||
#ifdef ROCE_BONDING_EN
|
||
#include "roce_bond.h"
|
||
#endif
|
||
|
||
/*
|
||
****************************************************************************
|
||
Prototype : roce3_fill_gid_type
|
||
Description : fill gid type
|
||
Input : struct rdma_gid_entry *gid_entry
|
||
Output : None
|
||
|
||
1.Date : 2016/5/27
|
||
Modification : Created function
|
||
|
||
****************************************************************************
|
||
*/
|
||
static void roce3_fill_gid_type(struct rdma_gid_entry *gid_entry, enum roce3_gid_type new_gid_type)
|
||
{
|
||
static u32 index_roce3_gid_mapping[32][4] = {
|
||
{0x120E1436, 3452, 224529784, 0x180E252A},
|
||
{0x120E004A, 3472, 224660876, 0x6C0E403E},
|
||
{0x120E0042, 3464, 224660836, 0x840E4036},
|
||
{0x120E0042, 3464, 224398688, 0xC00E0036},
|
||
{0x1212143A, 3456, 224791932, 0x1812252E},
|
||
{0x1212004E, 3476, 224923024, 0x6C124042},
|
||
{0x12120046, 3468, 224922984, 0x8412403A},
|
||
{0x12120046, 3468, 224660836, 0xC012003A},
|
||
{0x1216143E, 3460, 225054080, 0x18162532},
|
||
{0x12160052, 3480, 225185172, 0x6C164046},
|
||
{0x1216004A, 3472, 225185132, 0x8416403E},
|
||
{0x1216004A, 3472, 224922984, 0xC016003E},
|
||
{0x10301458, 3484, 226626968, 0x1830254C},
|
||
{0x1030006C, 3504, 226758060, 0x6C304060},
|
||
{0x10300064, 3496, 226758020, 0x84304058},
|
||
{0x10300064, 3496, 226495872, 0xC0300058},
|
||
{0x10401468, 838864300, 227675560, 0x1840255C},
|
||
{0x1040007C, 1174408640, 227806652, 0x6C404070},
|
||
{0x10400074, 1040190904, 227806612, 0x84404068},
|
||
{0x10400074, 1040190904, 227544464, 0xC0400068},
|
||
{0x1044146C, 905973168, 227937708, 0x18442560},
|
||
{0x10440080, 1241517508, 228068800, 0x6C444074},
|
||
{0x10440078, 1107299772, 228068760, 0x8444406C},
|
||
{0x10440078, 1107299772, 227806612, 0xC044006C},
|
||
{0x10481470, 973082036, 228199856, 0x18482564},
|
||
{0x10480084, 1308626376, 228330948, 0x6C484078},
|
||
{0x1048007C, 1174408640, 228330908, 0x84484070},
|
||
{0x1048007C, 1174408640, 228068760, 0xC0480070},
|
||
{0x1262148A, 1040190928, 230034892, 0x1862257E},
|
||
{0x1262009E, 1375735268, 230165984, 0x6C624092},
|
||
{0x12620096, 1241517532, 230165944, 0x8462408A},
|
||
{0x12620096, 1241517532, 229903796, 0xC062008A},
|
||
};
|
||
u8 i = 0;
|
||
|
||
gid_entry->dw6_h.bs.gid_type = new_gid_type;
|
||
gid_entry->dw6_h.bs.gid_update = (new_gid_type == ROCE_IPv4_ROCEv2_GID);
|
||
|
||
i = ROCE_GID_MAP_TBL_IDX_GET(gid_entry->dw6_h.bs.tunnel, gid_entry->dw6_h.bs.tag,
|
||
(u16)new_gid_type);
|
||
gid_entry->hdr_len_value = index_roce3_gid_mapping[i][0];
|
||
if (new_gid_type == ROCE_IPv4_ROCEv2_GID) {
|
||
*((u32 *)(void *)gid_entry + 1) = cpu_to_be32(index_roce3_gid_mapping[i][1]);
|
||
*((u32 *)(void *)gid_entry + ROCE_GID_MAP_TBL_IDX2) =
|
||
cpu_to_be32(index_roce3_gid_mapping[i][ROCE_GID_MAP_TBL_IDX2]);
|
||
}
|
||
}
|
||
|
||
static void roce3_fill_gid_smac(struct net_device *net_dev, struct rdma_gid_entry *gid_entry)
|
||
{
|
||
memcpy((void *)gid_entry->smac, (void *)net_dev->dev_addr, sizeof(gid_entry->smac));
|
||
}
|
||
|
||
static void roce3_fill_gid_vlan(struct roce3_device *rdev, struct net_device *net_dev,
|
||
struct rdma_gid_entry *gid_entry)
|
||
{
|
||
gid_entry->dw6_h.bs.tunnel = ROCE_GID_TUNNEL_INVALID;
|
||
if (rdma_vlan_dev_vlan_id(net_dev) != 0xffff) {
|
||
gid_entry->dw4.bs.cvlan = rdma_vlan_dev_vlan_id(net_dev) & 0xfff;
|
||
gid_entry->dw6_h.bs.tag = ROCE_GID_VLAN_VALID;
|
||
}
|
||
}
|
||
|
||
/*
|
||
****************************************************************************
|
||
Prototype : roce3_dispatch_event
|
||
Description : roce3_dispatch_event
|
||
Input : struct roce3_device *rdev
|
||
int port_num
|
||
enum ib_event_type type
|
||
Output : None
|
||
|
||
1.Date : 2016/3/29
|
||
Modification : Created function
|
||
|
||
****************************************************************************
|
||
*/
|
||
static void roce3_dispatch_event(struct roce3_device *rdev, int port_num, enum ib_event_type type)
|
||
{
|
||
struct ib_event event;
|
||
|
||
if (rdev == NULL) {
|
||
pr_err("[ROCE, ERR] %s: Rdev is null\n", __func__);
|
||
return;
|
||
}
|
||
|
||
memset(&event, 0, sizeof(event));
|
||
|
||
event.device = &rdev->ib_dev;
|
||
event.element.port_num = (u8)port_num;
|
||
event.event = type;
|
||
|
||
ib_dispatch_event(&event);
|
||
}
|
||
|
||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||
struct sin6_list {
|
||
struct list_head list;
|
||
struct sockaddr_in6 sin6;
|
||
};
|
||
|
||
static int roce3_gid_fill(struct roce3_device *rdev, struct rdma_gid_entry *gid_entry,
|
||
struct net_device *event_netdev, struct sin6_list *sin6_iter)
|
||
{
|
||
int ret = 0;
|
||
|
||
if (cpu_to_be64(gid_entry->global.subnet_prefix) == ROCE_DEFAULT_GID_SUBNET_PREFIX)
|
||
return ret;
|
||
|
||
roce3_fill_gid_vlan(rdev, event_netdev, gid_entry);
|
||
roce3_fill_gid_smac(event_netdev, gid_entry);
|
||
|
||
/* RoCE V2 */
|
||
if (rdma_protocol_roce_udp_encap(&rdev->ib_dev, ROCE_DEFAULT_PORT_NUM)) {
|
||
roce3_fill_gid_type(gid_entry, ROCE_IPv6_ROCEv2_GID);
|
||
ret = roce3_rdma_update_gid_mac(rdev->hwdev, 0, gid_entry);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to update V2 gid(IPv6), func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
list_del(&sin6_iter->list);
|
||
kfree(sin6_iter);
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
roce3_dispatch_event(rdev, ROCE_DEFAULT_PORT_NUM, IB_EVENT_GID_CHANGE);
|
||
|
||
return ret;
|
||
}
|
||
|
||
static int roce3_netdev_event_ipv6_dev_scan(struct roce3_device *rdev,
|
||
struct net_device *event_netdev, struct rdma_gid_entry *gid_entry)
|
||
{
|
||
struct sin6_list *sin6_temp = NULL;
|
||
struct sin6_list *sin6_iter = NULL;
|
||
struct inet6_dev *in6_dev = NULL;
|
||
struct inet6_ifaddr *ifp = NULL;
|
||
struct sin6_list *entry = NULL;
|
||
int ret;
|
||
|
||
LIST_HEAD(sin6_init_list);
|
||
|
||
in6_dev = in6_dev_get(event_netdev);
|
||
if (in6_dev == NULL)
|
||
return 0;
|
||
|
||
read_lock_bh(&in6_dev->lock);
|
||
list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
|
||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||
if (entry == NULL)
|
||
continue;
|
||
|
||
entry->sin6.sin6_family = AF_INET6;
|
||
entry->sin6.sin6_addr = ifp->addr;
|
||
list_add_tail(&entry->list, &sin6_init_list);
|
||
}
|
||
|
||
read_unlock_bh(&in6_dev->lock);
|
||
in6_dev_put(in6_dev);
|
||
|
||
list_for_each_entry_safe(sin6_iter, sin6_temp, &sin6_init_list, list) {
|
||
memcpy((void *)gid_entry->raw, (void *)&sin6_iter->sin6.sin6_addr,
|
||
sizeof(union ib_gid));
|
||
|
||
ret = roce3_gid_fill(rdev, gid_entry, event_netdev, sin6_iter);
|
||
if (ret != 0)
|
||
goto err_free;
|
||
|
||
list_del(&sin6_iter->list);
|
||
kfree(sin6_iter);
|
||
}
|
||
|
||
return 0;
|
||
|
||
err_free:
|
||
list_for_each_entry_safe(sin6_iter, sin6_temp, &sin6_init_list, list) {
|
||
list_del(&sin6_iter->list);
|
||
kfree(sin6_iter);
|
||
}
|
||
return ret;
|
||
}
|
||
#endif
|
||
|
||
static int roce3_netdev_event_ip_dev_scan(struct roce3_device *rdev,
|
||
struct net_device *event_netdev)
|
||
{
|
||
struct rdma_gid_entry gid_entry;
|
||
int ret;
|
||
|
||
memset(&gid_entry, 0, sizeof(gid_entry));
|
||
|
||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||
ret = roce3_netdev_event_ipv6_dev_scan(rdev, event_netdev, &gid_entry);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to scan IPv6, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
#endif
|
||
|
||
return 0;
|
||
}
|
||
|
||
static struct roce3_vlan_dev_list *roce3_find_vlan_device_list(const struct list_head *mac_list,
|
||
const struct net_device *netdev)
|
||
{
|
||
struct roce3_vlan_dev_list *vlan_dev_list = NULL;
|
||
|
||
list_for_each_entry(vlan_dev_list, mac_list, list) {
|
||
if (vlan_dev_list->net_dev == netdev)
|
||
return vlan_dev_list;
|
||
}
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static int roce3_add_vlan_device(struct roce3_device *rdev, struct net_device *netdev)
|
||
{
|
||
struct roce3_vlan_dev_list *new_list;
|
||
|
||
new_list = kzalloc(sizeof(*new_list), GFP_KERNEL);
|
||
if (new_list == NULL)
|
||
return -ENOMEM;
|
||
|
||
new_list->ref_cnt = 1;
|
||
new_list->net_dev = netdev;
|
||
new_list->vlan_id = ROCE_GID_SET_VLAN_32BIT_VLAID(((u32)rdma_vlan_dev_vlan_id(netdev)));
|
||
memcpy(new_list->mac, netdev->dev_addr, ROCE_MAC_ADDR_LEN);
|
||
INIT_LIST_HEAD(&new_list->list);
|
||
list_add_tail(&new_list->list, &rdev->mac_vlan_list_head);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void roce3_del_vlan_device(struct roce3_device *rdev, struct roce3_vlan_dev_list *old_list)
|
||
{
|
||
list_del(&old_list->list);
|
||
kfree(old_list);
|
||
}
|
||
|
||
static int roce3_update_vlan_device_mac(struct roce3_device *rdev, struct net_device *netdev)
|
||
{
|
||
struct roce3_vlan_dev_list *old_list = NULL;
|
||
int ret;
|
||
|
||
mutex_lock(&rdev->mac_vlan_mutex);
|
||
old_list = roce3_find_vlan_device_list(&rdev->mac_vlan_list_head, netdev);
|
||
if (old_list == NULL) {
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
return 0;
|
||
}
|
||
|
||
if (ROCE_MEMCMP(old_list->mac, netdev->dev_addr, ROCE_MAC_ADDR_LEN) != 0) {
|
||
roce3_del_vlan_device_mac(rdev, old_list);
|
||
|
||
ret = roce3_add_vlan_device_mac(rdev, netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to add mac_vlan, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
return ret;
|
||
}
|
||
|
||
memcpy(old_list->mac, netdev->dev_addr, ROCE_MAC_ADDR_LEN);
|
||
}
|
||
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int roce3_update_real_device_mac(struct roce3_device *rdev, struct net_device *netdev)
|
||
{
|
||
int ret;
|
||
|
||
roce3_del_real_device_mac(rdev);
|
||
|
||
ret = roce3_add_real_device_mac(rdev, netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to add real device ipsu mac, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
void roce3_clean_vlan_device_mac(struct roce3_device *rdev)
|
||
{
|
||
struct roce3_vlan_dev_list *pos = NULL;
|
||
struct roce3_vlan_dev_list *tmp = NULL;
|
||
|
||
mutex_lock(&rdev->mac_vlan_mutex);
|
||
list_for_each_entry_safe(pos, tmp, &rdev->mac_vlan_list_head, list) {
|
||
#ifdef ROCE_BONDING_EN
|
||
if (roce3_bond_is_active(rdev))
|
||
(void)roce3_del_bond_vlan_slave_mac(rdev, pos->mac, (u16)pos->vlan_id);
|
||
#endif
|
||
roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, pos->mac, pos->vlan_id,
|
||
rdev->glb_func_id, hinic3_er_id(rdev->hwdev));
|
||
|
||
(void)roce3_del_mac_tbl_mac_entry(rdev->hwdev, pos->mac, pos->vlan_id,
|
||
rdev->glb_func_id, rdev->glb_func_id);
|
||
|
||
list_del(&pos->list);
|
||
kfree(pos);
|
||
}
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
}
|
||
|
||
void roce3_clean_real_device_mac(struct roce3_device *rdev)
|
||
{
|
||
#ifdef ROCE_BONDING_EN
|
||
if (roce3_bond_is_active(rdev))
|
||
(void)roce3_del_bond_real_slave_mac(rdev);
|
||
#endif
|
||
|
||
roce3_del_ipsu_tbl_mac_entry(rdev->hwdev, rdev->mac, 0, rdev->glb_func_id,
|
||
hinic3_er_id(rdev->hwdev));
|
||
}
|
||
|
||
static bool roce3_rdma_is_upper_dev_rcu(struct net_device *dev, struct net_device *upper)
|
||
{
|
||
struct net_device *rdev_upper = NULL;
|
||
struct net_device *master = NULL;
|
||
bool ret = false;
|
||
|
||
if ((upper == NULL) || (dev == NULL)) {
|
||
ret = false;
|
||
} else {
|
||
rdev_upper = rdma_vlan_dev_real_dev(upper);
|
||
master = netdev_master_upper_dev_get_rcu(dev);
|
||
ret = ((upper == master) || (rdev_upper && (rdev_upper == master)) ||
|
||
(rdev_upper == dev));
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/* check bonding device */
|
||
int roce3_is_eth_port_of_netdev(struct net_device *rdma_ndev, struct net_device *cookie)
|
||
{
|
||
struct net_device *real_dev = NULL;
|
||
int res;
|
||
|
||
if (rdma_ndev == NULL)
|
||
return 0;
|
||
|
||
rcu_read_lock();
|
||
real_dev = rdma_vlan_dev_real_dev(cookie);
|
||
if (real_dev == NULL)
|
||
real_dev = cookie;
|
||
|
||
res = (roce3_rdma_is_upper_dev_rcu(rdma_ndev, cookie) || (real_dev == rdma_ndev));
|
||
rcu_read_unlock();
|
||
return res;
|
||
}
|
||
|
||
int roce3_ifconfig_up_down_event_report(struct roce3_device *rdev, u8 net_event)
|
||
{
|
||
struct ib_event event = { 0 };
|
||
|
||
if ((net_event == IB_EVENT_PORT_ACTIVE) &&
|
||
(test_and_set_bit(ROCE3_PORT_EVENT, &rdev->status) != 0))
|
||
return -1;
|
||
|
||
if ((net_event == IB_EVENT_PORT_ERR) &&
|
||
(test_and_clear_bit(ROCE3_PORT_EVENT, &rdev->status) == 0))
|
||
return -1;
|
||
|
||
event.device = &rdev->ib_dev;
|
||
event.event = net_event;
|
||
event.element.port_num = ROCE_DEFAULT_PORT_NUM;
|
||
|
||
ib_dispatch_event(&event);
|
||
return 0;
|
||
}
|
||
|
||
static int roce3_netdev_event_raw_dev(unsigned long event, struct roce3_device *rdev,
|
||
struct net_device *event_netdev)
|
||
{
|
||
int ret;
|
||
|
||
if (event == NETDEV_REGISTER) {
|
||
ret = roce3_add_real_device_mac(rdev, event_netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to add real device mac, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
if (event == NETDEV_CHANGEADDR) {
|
||
ret = roce3_update_real_device_mac(rdev, event_netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to update readl device mac, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
|
||
ret = roce3_netdev_event_ip_dev_scan(rdev, event_netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to scan ip_dev, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
#ifdef ROCE_BONDING_EN
|
||
if (roce3_bond_is_active(rdev)) {
|
||
if ((event == NETDEV_DOWN) || (event == NETDEV_UP))
|
||
roce3_handle_bonded_port_state_event(rdev);
|
||
} else {
|
||
if (event == NETDEV_DOWN)
|
||
roce3_ifconfig_up_down_event_report(rdev, IB_EVENT_PORT_ERR);
|
||
if (event == NETDEV_UP)
|
||
roce3_event_up_extend(rdev);
|
||
}
|
||
#else
|
||
if (event == NETDEV_DOWN)
|
||
roce3_ifconfig_up_down_event_report(rdev, IB_EVENT_PORT_ERR);
|
||
if (event == NETDEV_UP)
|
||
roce3_event_up_extend(rdev);
|
||
#endif
|
||
return 0;
|
||
}
|
||
|
||
static int roce3_netdev_event_vlan_dev(unsigned long event, struct roce3_device *rdev,
|
||
struct net_device *event_netdev)
|
||
{
|
||
int ret;
|
||
|
||
if (event == NETDEV_CHANGEADDR) {
|
||
ret = roce3_update_vlan_device_mac(rdev, event_netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to update vlan device mac, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
|
||
ret = roce3_netdev_event_ip_dev_scan(rdev, event_netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to scan vlan device ip list, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static bool roce3_is_port_of_net_dev(struct roce3_device *rdev, struct net_device *event_netdev)
|
||
{
|
||
#ifdef ROCE_BONDING_EN
|
||
if (roce3_bond_is_active(rdev)) {
|
||
if (roce3_bond_is_eth_port_of_netdev(rdev, event_netdev) == 0)
|
||
return false;
|
||
} else
|
||
#endif
|
||
{
|
||
if (roce3_is_eth_port_of_netdev(rdev->ndev, event_netdev) == 0)
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
static int roce3_netdev_event(struct notifier_block *nb, unsigned long event, void *ptr)
|
||
{
|
||
struct net_device *event_netdev;
|
||
struct roce3_device *rdev = NULL;
|
||
struct roce3_notifier *notifier = NULL;
|
||
struct net_device *real_dev = NULL;
|
||
int ret;
|
||
|
||
if (nb == NULL || ptr == NULL)
|
||
goto err_out;
|
||
|
||
event_netdev = netdev_notifier_info_to_dev(ptr);
|
||
if (event_netdev->type != ARPHRD_ETHER)
|
||
goto err_out;
|
||
|
||
notifier = container_of(nb, struct roce3_notifier, nb);
|
||
rdev = container_of(notifier, struct roce3_device, notifier);
|
||
|
||
if (roce3_hca_is_present(rdev) == 0)
|
||
goto err_out;
|
||
|
||
if (!roce3_is_port_of_net_dev(rdev, (void *)event_netdev))
|
||
goto err_out;
|
||
|
||
/* get raw netdev from event_netdev */
|
||
real_dev = (rdma_vlan_dev_real_dev(event_netdev) != 0) ?
|
||
rdma_vlan_dev_real_dev(event_netdev) : event_netdev;
|
||
if (real_dev == event_netdev) {
|
||
ret = roce3_netdev_event_raw_dev(event, rdev, event_netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to deal with raw device, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
goto err_out;
|
||
}
|
||
} else {
|
||
ret = roce3_netdev_event_vlan_dev(event, rdev, event_netdev);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to deal with vlan device, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
goto err_out;
|
||
}
|
||
}
|
||
|
||
err_out:
|
||
return NOTIFY_DONE;
|
||
}
|
||
|
||
/*
|
||
****************************************************************************
|
||
Prototype : roce3_unregister_netdev_event
|
||
Description : unregister netdev event related function
|
||
Input : struct roce3_device *rdev
|
||
Output : None
|
||
|
||
1.Date : 2015/6/18
|
||
Modification : Created function
|
||
|
||
****************************************************************************
|
||
*/
|
||
void roce3_unregister_netdev_event(struct roce3_device *rdev)
|
||
{
|
||
int ret = 0;
|
||
struct roce3_notifier *notifier = &rdev->notifier;
|
||
|
||
if (notifier->nb.notifier_call) {
|
||
ret = unregister_netdevice_notifier(¬ifier->nb);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to unregister netdev notifier, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
}
|
||
|
||
notifier->nb.notifier_call = NULL;
|
||
}
|
||
}
|
||
|
||
/*
|
||
****************************************************************************
|
||
Prototype : roce3_register_netdev_event
|
||
Description : register netdev event related function
|
||
Input : struct roce3_device *rdev
|
||
Output : None
|
||
|
||
1.Date : 2015/6/18
|
||
Modification : Created function
|
||
|
||
****************************************************************************
|
||
*/
|
||
int roce3_register_netdev_event(struct roce3_device *rdev)
|
||
{
|
||
struct roce3_notifier *notifier = &rdev->notifier;
|
||
int ret;
|
||
|
||
notifier->nb.notifier_call = roce3_netdev_event;
|
||
ret = register_netdevice_notifier(¬ifier->nb);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to register netdev notifier, func_id(%d)\n",
|
||
__func__, rdev->glb_func_id);
|
||
notifier->nb.notifier_call = NULL;
|
||
return ret;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int roce3_set_gid_entry(struct roce3_device *rdev, struct rdma_gid_entry *gid_entry,
|
||
const struct ib_gid_attr *attr, const union ib_gid *gid)
|
||
{
|
||
static enum roce3_gid_type gid_type_map[ROCE_NETWORK_GID_TYPE_MAX] = {0};
|
||
enum rdma_network_type network_type;
|
||
enum roce3_gid_type roce_gid_type;
|
||
|
||
gid_type_map[RDMA_NETWORK_IPV4] = ROCE_IPv4_ROCEv2_GID;
|
||
gid_type_map[RDMA_NETWORK_IPV6] = ROCE_IPv6_ROCEv2_GID;
|
||
|
||
memset(gid_entry, 0, sizeof(*gid_entry));
|
||
network_type = rdma_gid_attr_network_type(attr);
|
||
memcpy((void *)gid_entry->raw, (void *)(&attr->gid), sizeof(union ib_gid));
|
||
if ((network_type == RDMA_NETWORK_IB) || (network_type == RDMA_NETWORK_ROCE_V1)) {
|
||
pr_err("[ROCE, ERR] %s: IB or RoCE v1 is no longer supported, network_type(%d)\n",
|
||
__func__, network_type);
|
||
return (-EINVAL);
|
||
}
|
||
|
||
roce_gid_type = gid_type_map[network_type];
|
||
roce3_fill_gid_vlan(rdev, attr->ndev, gid_entry);
|
||
roce3_fill_gid_type(gid_entry, roce_gid_type);
|
||
roce3_fill_gid_smac(attr->ndev, gid_entry);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int roce3_check_and_set_gid_entry(const struct ib_gid_attr *attr, const union ib_gid *gid,
|
||
struct rdma_gid_entry *gid_entry, struct roce3_device *rdev, unsigned int index)
|
||
{
|
||
if ((cpu_to_be64(gid->global.subnet_prefix) == ROCE_DEFAULT_GID_SUBNET_PREFIX) &&
|
||
(index > 1))
|
||
return -EINVAL;
|
||
|
||
memset(gid_entry, 0, sizeof(struct rdma_gid_entry));
|
||
if (roce3_set_gid_entry(rdev, gid_entry, attr, gid) != 0) {
|
||
pr_err("[ROCE, ERR] %s: Failed to set gid entry.\n", __func__);
|
||
return (-EINVAL);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* add vlan_mac list or ref_cnt + 1
|
||
* add mac_vlan when new list add
|
||
*/
|
||
static int roce3_notify_vlan(struct roce3_device *rdev, const struct ib_gid_attr *attr)
|
||
{
|
||
int ret;
|
||
struct roce3_vlan_dev_list *old_list = NULL;
|
||
|
||
mutex_lock(&rdev->mac_vlan_mutex);
|
||
pr_info("[ROCE] ADD vlan: Func_id:%d, Netdev:%s\n",
|
||
rdev->glb_func_id, attr->ndev->name);
|
||
old_list = roce3_find_vlan_device_list(&rdev->mac_vlan_list_head, attr->ndev);
|
||
if (old_list != NULL) {
|
||
old_list->ref_cnt++;
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
return 0;
|
||
}
|
||
|
||
ret = roce3_add_vlan_device(rdev, attr->ndev);
|
||
if (ret != 0) {
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
return ret;
|
||
}
|
||
|
||
ret = roce3_add_vlan_device_mac(rdev, attr->ndev);
|
||
if (ret != 0) {
|
||
old_list = roce3_find_vlan_device_list(&rdev->mac_vlan_list_head, attr->ndev);
|
||
if (old_list)
|
||
roce3_del_vlan_device(rdev, old_list);
|
||
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
return ret;
|
||
}
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
|
||
return 0;
|
||
}
|
||
|
||
int roce3_ib_add_gid(const struct ib_gid_attr *attr, __always_unused void **context)
|
||
{
|
||
int ret;
|
||
struct rdma_gid_entry gid_entry;
|
||
struct roce3_device *rdev = to_roce3_dev(attr->device); /*lint !e78 !e530*/
|
||
unsigned int index = attr->index; /*lint !e530*/
|
||
|
||
if (roce3_hca_is_present(rdev) == 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE] %s: HCA not present(return fail), func_id(%u)\n",
|
||
__func__, rdev->glb_func_id);
|
||
return -EPERM;
|
||
}
|
||
/*lint !e40*/
|
||
ret = roce3_check_and_set_gid_entry(attr, &(attr->gid), &gid_entry, rdev, index);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE] %s: set gid err, func_id(%u)\n", __func__,
|
||
rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
|
||
// 添加第一个gid时,设置ipsu mac
|
||
if (index == 0) {
|
||
ret = roce3_update_real_device_mac(rdev, attr->ndev);
|
||
if (ret != 0)
|
||
return ret;
|
||
}
|
||
|
||
ret = roce3_rdma_update_gid(rdev->hwdev, 0, index, &gid_entry);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to update gid. ret(%d),func_id(%d)\n",
|
||
__func__, ret, rdev->glb_func_id);
|
||
return ret;
|
||
}
|
||
|
||
rdev->gid_dev[index] = attr->ndev;
|
||
|
||
if (rdma_vlan_dev_real_dev(attr->ndev)) {
|
||
ret = roce3_notify_vlan(rdev, attr);
|
||
if (ret != 0) {
|
||
dev_err(rdev->hwdev_hdl,
|
||
"[ROCE, ERR] %s: Failed to nofify vlan, func_id(%d), ret(%d)\n",
|
||
__func__, rdev->glb_func_id, ret);
|
||
return ret;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int roce3_ib_del_gid(const struct ib_gid_attr *attr, __always_unused void **context)
|
||
{
|
||
struct roce3_vlan_dev_list *old_list = NULL;
|
||
struct roce3_device *rdev = NULL;
|
||
u32 index = 0;
|
||
|
||
if ((attr == NULL) || (attr->device == NULL)) { /*lint !e55 !e58 !e78*/
|
||
pr_err("[ROCE] %s: Attr or attr->device is null\n", __func__);
|
||
return (-EINVAL);
|
||
}
|
||
|
||
rdev = to_roce3_dev(attr->device); /*lint !e78*/
|
||
index = attr->index;
|
||
if (index >= rdev->rdma_cap.max_gid_per_port) {
|
||
dev_err(rdev->hwdev_hdl, "[ROCE] %s: Invalid gid index(%u), func_id(%d)\n",
|
||
__func__, index, rdev->glb_func_id);
|
||
return (-EINVAL);
|
||
}
|
||
|
||
/* del vlan_mac list or ref_cnt - 1 */
|
||
/* del mac_vlan when ref_cnt = 0 */
|
||
if (rdev->ndev != rdev->gid_dev[index]) {
|
||
mutex_lock(&rdev->mac_vlan_mutex);
|
||
old_list = roce3_find_vlan_device_list(&rdev->mac_vlan_list_head,
|
||
rdev->gid_dev[index]);
|
||
if (old_list) {
|
||
old_list->ref_cnt--;
|
||
if (old_list->ref_cnt == 0) {
|
||
roce3_del_vlan_device_mac(rdev, old_list);
|
||
|
||
roce3_del_vlan_device(rdev, old_list);
|
||
}
|
||
}
|
||
mutex_unlock(&rdev->mac_vlan_mutex);
|
||
}
|
||
/*
|
||
* delete gid no longer send cmd to ucode which write 0s to target entry,
|
||
* preventing PPE from building malformed packets.
|
||
*/
|
||
return 0;
|
||
}
|