787 lines
22 KiB
C
Raw Normal View History

2026-01-29 22:25:33 +08:00
// 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(&notifier->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(&notifier->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;
}