2026-01-29 22:25:33 +08:00

787 lines
22 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}