// SPDX-License-Identifier: GPL-2.0 // Copyright(c) 2024 Huawei Technologies Co., Ltd #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hinic3_crm.h" #include "hinic3_hw.h" #include "hinic3_hwdev.h" #include "hinic3_srv_nic.h" #include "hinic3_rdma.h" #include "hinic3_bond.h" #include "hinic3_pci_id_tbl.h" #include "roce_event.h" #include "roce_compat.h" #include "roce_dfx.h" #include "roce_mr.h" #include "roce_main_extension.h" #ifdef ROCE_NETLINK_EN #include "roce_netlink.h" #endif #ifdef ROCE_BONDING_EN #include "roce_bond.h" #endif #include "roce_pub_cmd.h" MODULE_AUTHOR(HIROCE3_DRV_AUTHOR); MODULE_DESCRIPTION(HIROCE3_DRV_DESC); MODULE_VERSION(HIROCE3_DRV_VERSION); MODULE_LICENSE("GPL"); static int g_loop_times = 50000; module_param(g_loop_times, int, 0444); //lint !e806 MODULE_PARM_DESC(g_loop_times, "default: 50000"); static bool g_ppf_stateful_init; static u8 g_vf_stateful_num; #ifdef ROCE_BONDING_EN static int g_want_bond_slave_cnt = ROCE_BOND_WANT_TWO_SLAVES; module_param(g_want_bond_slave_cnt, int, 0444); MODULE_PARM_DESC(g_want_bond_slave_cnt, "default: 2, 2: two slaves, 3: three slaves, 4: four slaves"); static int g_want_bond0_slave_bits = 0x3; /* 0011 */ module_param(g_want_bond0_slave_bits, int, 0444); MODULE_PARM_DESC(g_want_bond0_slave_bits, "default: 0x3(PF0+PF1), 4bits"); static char *g_bond_name; module_param(g_bond_name, charp, 0444); MODULE_PARM_DESC(g_bond_name, "bond name for sdi"); #endif struct roce3_func_info { u16 func_id; struct list_head node; }; LIST_HEAD(g_roce_device_list); static void roce3_remove_device_from_list(struct hinic3_lld_dev *lld_dev); static int roce3_add_device_to_list(struct hinic3_lld_dev *lld_dev); static void roce3_wait_probe(struct hinic3_lld_dev *lld_dev); DECLARE_WAIT_QUEUE_HEAD(g_roce_probe_queue); /* **************************************************************************** Prototype : roce3_cq_completion Description : RoCE's callback function for CQ's completion events on ARM CQs Input : void *svc_hd u32 cqn void *cq_handler Output : None 1.Date : 2015/5/27 Modification : Created function **************************************************************************** */ void roce3_cq_completion(void *svc_hd, u32 cqn, void *cq_handler) { struct roce3_cq *cq = NULL; struct ib_cq *ibcq = NULL; if (cq_handler == NULL) { pr_err("[ROCE, ERR] %s: Cq_handler is null\n", __func__); return; } cq = (struct roce3_cq *)cq_handler; ++cq->arm_sn; cq->arm_flag = 0; ibcq = &cq->ibcq; ibcq->comp_handler(ibcq, ibcq->cq_context); } /* **************************************************************************** Prototype : get_cpu_endian Description : Acquire CPU's enianness Return Value : 0: little endian; 1: big endian 1.Date : 2016/6/23 Modification : Created function **************************************************************************** */ static int get_cpu_endian(void) { int cpu_mode = 0; union { unsigned int i; unsigned char s[4]; } c; c.i = 0x12345678; if (c.s[0] == 0x12) { pr_info("[ROCE] %s: CPU is be\n", __func__); cpu_mode = 1; } else { pr_info("[ROCE] %s: CPU is le\n", __func__); cpu_mode = 0; } return cpu_mode; } static int roce3_alloc_hw_resource(struct roce3_device *rdev) { int ret; ret = roce3_rdma_init_rsvd_lkey(rdev->hwdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to init rsvd lkey, func_id(%u)\n", __func__, rdev->glb_func_id); return ret; } ret = roce3_rdma_reset_gid_table(rdev->hwdev, 0); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR]: Failed to reset gid_table, func_id(%u)\n", rdev->glb_func_id); goto err_gid_reset; } return 0; err_gid_reset: roce3_rdma_free_rsvd_lkey(rdev->hwdev); return ret; } static void roce3_dealloc_hw_resource(struct roce3_device *rdev) { roce3_rdma_free_rsvd_lkey(rdev->hwdev); } static struct roce3_device *roce3_rdev_alloc(struct hinic3_lld_dev *lld_dev, void **uld_dev, const struct rdma_service_cap *rdma_cap) { struct roce3_device *rdev = NULL; rdev = (struct roce3_device *)roce3_rdev_alloc_ext(); if (rdev == NULL) { pr_err("[ROCE, ERR] %s: Failed to alloc rdev\n", __func__); return NULL; } *uld_dev = (void *)rdev; rdev->lld_dev = lld_dev; rdev->hwdev = lld_dev->hwdev; rdev->pdev = lld_dev->pdev; mutex_init(&rdev->qp_cnt.cur_qps_mutex); rdev->hwdev_hdl = ((struct hinic3_hwdev *)(rdev->hwdev))->dev_hdl; memcpy((void *)&rdev->rdma_cap, (void *)rdma_cap, sizeof(*rdma_cap)); rdev->ndev = hinic3_get_netdev_by_lld(rdev->lld_dev); if (rdev->ndev == NULL) { pr_err("[ROCE, ERR] %s roce add failed, netdev is null.\n", __func__); ib_dealloc_device(&rdev->ib_dev); return NULL; } roce3_rdev_set_ext(rdev); return rdev; } static int roce3_board_info_get(struct roce3_device *rdev) { int ret = 0; ret = hinic3_get_board_info(rdev->hwdev, &rdev->board_info, HINIC3_CHANNEL_ROCE); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to get board info\n", __func__); return ret; } pr_info("[ROCE] Get board info success, board_type:0x%x, port_num:0x%x, pf_num:0x%x, vf_total_num:0x%x, work_mode:0x%x, service_mode:0x%x, speed:0x%x.\n", rdev->board_info.board_type, rdev->board_info.port_num, rdev->board_info.pf_num, rdev->board_info.vf_total_num, rdev->board_info.work_mode, rdev->board_info.service_mode, rdev->board_info.port_speed); #ifdef ROCE_BONDING_EN ret = roce3_bond_attach(rdev); if (ret != 0) return ret; #endif ret = roce3_board_cfg_check(rdev); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to check board cfg info\n", __func__); return ret; } return ret; } static int roce3_init_info_get(struct roce3_device *rdev) { int ret = 0; ret = roce3_board_info_get(rdev); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to get board info\n", __func__); return ret; } return ret; } static void roce3_fix_ibdev_name(struct roce3_device *rdev) { #ifdef ROCE_BONDING_EN if (roce3_bond_is_active(rdev)) { strscpy(rdev->ib_dev.name, "hrn3_bond_%d", sizeof("hrn3_bond_%d")); return; } #endif { strscpy(rdev->ib_dev.name, (rdev->is_vroce ? "efi_%d" : "hrn3_%d"), (rdev->is_vroce ? sizeof("efi_%d") : sizeof("hrn3_%d"))); } } static int roce3_register_template(struct roce3_device *rdev) { struct tag_service_register_template svc_template; int ret; memset(&svc_template, 0, sizeof(svc_template)); svc_template.service_type = SERVICE_T_ROCE; svc_template.scq_ctx_size = rdev->rdma_cap.cqc_entry_sz; svc_template.srq_ctx_size = rdev->rdma_cap.dev_rdma_cap.roce_own_cap.srqc_entry_sz; svc_template.service_handle = rdev; svc_template.embedded_cq_ceq_callback = NULL; svc_template.no_cq_ceq_callback = NULL; svc_template.shared_cq_ceq_callback = roce3_cq_completion; svc_template.aeq_level_callback = roce3_async_event_level; svc_template.aeq_callback = roce3_async_event; ret = cqm_service_register(rdev->hwdev, &svc_template); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to register cqm_service, func(%u)\n", __func__, rdev->glb_func_id); return ret; } return 0; } int roce3_init_dev_file(struct roce3_device *rdev) { int ret = 0; ret = roce3_init_sysfs(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to init sysfs, func_id(%u) ret(%d)\n", __func__, rdev->glb_func_id, ret); return ret; } ret = roce3_init_cdev(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to init cdev, func_id(%u)\n", __func__, rdev->glb_func_id); roce3_remove_sysfs(rdev); } return ret; } void roce3_remove_dev_file(struct roce3_device *rdev) { roce3_remove_cdev(rdev); roce3_remove_sysfs(rdev); } /* Alloc CEQs and alloc CEQN */ static int roce3_alloc_ceq(struct roce3_device *rdev) { int ret; ret = hinic3_alloc_ceqs(rdev->hwdev, SERVICE_T_ROCE, rdev->ib_dev.num_comp_vectors, rdev->ceqn, &rdev->ceq_num); if (ret < 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc cqes, num_comp_vectors(%d), func_id(%u)\n", __func__, rdev->ib_dev.num_comp_vectors, rdev->glb_func_id); return ret; } return 0; } static void roce3_free_ceq(struct roce3_device *rdev) { int i; for (i = 0; i < rdev->ceq_num; ++i) hinic3_free_ceq(rdev->hwdev, SERVICE_T_ROCE, rdev->ceqn[i]); } static void roce3_init_hw_info(struct roce3_device *rdev) { int ret; struct roce_group_id group_id = {0}; rdev->hw_info.config_num_ports = (int)rdev->rdma_cap.num_ports; rdev->hw_info.ep_id = hinic3_ep_id(rdev->hwdev); rdev->hw_info.phy_port = 1; rdev->hw_info.is_vf = (hinic3_func_type(rdev->hwdev) == TYPE_VF); rdev->hw_info.cpu_endian = (u8)get_cpu_endian(); if (!rdev->is_vroce) return; ret = roce3_get_group_id(rdev->glb_func_id, rdev->hwdev, &group_id); if (!!ret) { dev_info(rdev->hwdev_hdl, "[ROCE , INFO] Failed to get group id, ret(%d)", ret); return; } rdev->group_rc_cos = group_id.group_rc_cos; rdev->group_ud_cos = group_id.group_ud_cos; rdev->group_xrc_cos = group_id.group_xrc_cos; dev_info(rdev->hwdev_hdl, "[ROCE , INFO] group id rc(%u), ud(%u), xrc(%u)", group_id.group_rc_cos, group_id.group_ud_cos, group_id.group_xrc_cos); } static int roce3_init_dev_upper(struct roce3_device *rdev) { int ret; /* Set function table to ENABLE */ ret = roce3_set_func_tbl_func_state(rdev, ROCE_FUNC_ENABLE); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to set func_tbl, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_set_func_tbl; } return 0; err_set_func_tbl: return ret; } static void roce3_deinit_dev_upper(struct roce3_device *rdev) { (void)roce3_set_func_tbl_func_state(rdev, ROCE_FUNC_DISABLE); } static int roce3_init_dev_info(struct roce3_device *rdev) { int ret; ret = roce3_set_func_tbl_cpu_endian(rdev->hwdev, rdev->hw_info.cpu_endian, rdev->glb_func_id); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR]: Failed to set func_tbl cpu_endian, func_id(%u)\n", rdev->glb_func_id); goto err_init_endianness; } ret = roce3_init_dev_ext(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR]: Failed to init extended service for func_id(%u)\n", rdev->glb_func_id); goto err_init_dev_ext; } ret = roce3_dfx_mem_alloc(rdev); if (ret != 0) goto err_init_dev_dfx; ret = roce3_init_dev_upper(rdev); if (ret != 0) goto err_init_dev_upper; return 0; err_init_dev_upper: roce3_dfx_mem_free(rdev); err_init_dev_dfx: roce3_remove_clean_res_ext(rdev); err_init_dev_ext: err_init_endianness: return ret; } static void roce3_deinit_dev_info(struct roce3_device *rdev) { roce3_deinit_dev_upper(rdev); roce3_dfx_mem_free(rdev); roce3_remove_clean_res_ext(rdev); } #ifdef ROCE_BONDING_EN static int roce3_ib_register_bond_device(struct roce3_device *rdev) { return ib_register_device(&rdev->ib_dev, "hrn3_bond_%d", &rdev->pdev->dev); } #endif // ROCE_BONDING_EN static int roce3_ib_register_unbond_device(struct roce3_device *rdev) { return ib_register_device(&rdev->ib_dev, "hrn3_%d", &rdev->pdev->dev); } static int roce3_ib_register_device(struct roce3_device *rdev) { #ifdef ROCE_BONDING_EN if (roce3_bond_is_active(rdev)) return roce3_ib_register_bond_device(rdev); #endif return roce3_ib_register_unbond_device(rdev); } static int roce3_init_dev(struct roce3_device *rdev, char *uld_dev_name) { int ret; ret = roce3_init_dev_info(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to init dev info, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_init_dev_info; } /* Clear gid table before register for a new IB device */ ret = roce3_alloc_hw_resource(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc hw res, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_alloc_hw_res; } roce3_wait_probe(rdev->lld_dev); ret = roce3_ib_register_device(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to reg ibdev, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_reg_dev; } roce3_remove_device_from_list(rdev->lld_dev); memcpy(uld_dev_name, rdev->ib_dev.name, ROCE_ULD_DEV_NAME_LEN); ret = roce3_register_netdev_event(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to reg netdev, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_memcpy_uld; } ret = roce3_init_dev_file(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to init sysfs, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_init_dev_file; } rdev->ib_active = true; dev_info(rdev->hwdev_hdl, "[ROCE] %s: RoCE add init all ok, func_id(%u), dev_name(%s)\n", __func__, rdev->glb_func_id, rdev->ib_dev.name); return 0; err_init_dev_file: roce3_unregister_netdev_event(rdev); err_memcpy_uld: ib_unregister_device(&rdev->ib_dev); err_reg_dev: roce3_dealloc_hw_resource(rdev); err_alloc_hw_res: roce3_deinit_dev_info(rdev); err_init_dev_info: return ret; } static int roce3_add_rdev_init(struct roce3_device *rdev) { int ret = 0; ret = roce3_init_info_get(rdev); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to check\n", __func__); return ret; } rdev->gid_dev = kzalloc(rdev->rdma_cap.max_gid_per_port * sizeof(struct net_device *), GFP_KERNEL); if (rdev->gid_dev == NULL) return -ENOMEM; ret = roce3_rdma_init_resource(rdev->hwdev); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to init rdma resources.\n", __func__); goto err_init_resource; } pr_info("[ROCE] %s: Initializing(%s)\n", __func__, pci_name(rdev->pdev)); rdev->glb_func_id = hinic3_global_func_id(rdev->hwdev); rdev->is_vroce = false; roce3_init_hw_info(rdev); ret = roce3_init_cfg_info(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR]%s: Failed to get roce cfg, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_init_cfg; } return 0; err_init_cfg: roce3_rdma_cleanup_resource(rdev->hwdev); err_init_resource: if (rdev->gid_dev != NULL) kfree(rdev->gid_dev); return ret; } static void roce3_add_rdev_unit(struct roce3_device *rdev) { roce3_rdma_cleanup_resource(rdev->hwdev); if (rdev->gid_dev != NULL) kfree(rdev->gid_dev); } static __be64 rdma_gen_node_guid(u8 *dev_mac) { u8 guid[8]; u8 mac_addr[6]; __be64 node_guid = 0; if (dev_mac == NULL) { pr_err("[ROCE, ERR]%s: Dev_mac is null\n", __func__); return RDMA_INVALID_GUID; } memcpy((void *)&mac_addr[0], (void *)dev_mac, sizeof(mac_addr)); /* * 0 is mac & guid array idx * 1 is mac & guid array idx * 2 is mac & guid array idx * 3 is guid array idx * 4 is guid array idx * 5 is guid array idx, 3 is mac array idx * 6 is guid array idx, 4 is mac array idx * 7 is guid array idx, 5 is mac array idx */ guid[0] = mac_addr[0] ^ DEV_ADDR_FIRST_BYTE_VAL_MASK; guid[1] = mac_addr[1]; guid[2] = mac_addr[2]; guid[3] = 0xff; guid[4] = 0xfe; guid[5] = mac_addr[3]; guid[6] = mac_addr[4]; guid[7] = mac_addr[5]; /* node_guid is calculated by guid. */ node_guid = ((u64)guid[0] << 56) | // 0 is guid array idx, 56 is guid offset ((u64)guid[1] << 48) | // 1 is guid array idx, 48 is guid offset ((u64)guid[2] << 40) | // 2 is guid array idx, 40 is guid offset ((u64)guid[3] << 32) | // 3 is guid array idx, 32 is guid offset ((u64)guid[4] << 24) | // 4 is guid array idx, 24 is guid offset ((u64)guid[5] << 16) | // 5 is guid array idx, 16 is guid offset ((u64)guid[6] << 8) | // 6 is guid array idx, 8 is guid offset (u64)guid[7]; // 7 is guid array idx return (__be64)cpu_to_be64(node_guid); } static __be64 roce3_rdma_init_guid(void *hwdev, struct net_device *netdev) { struct rdma_comp_priv *comp_priv = NULL; if ((hwdev == NULL) || (netdev == NULL)) { pr_err("[ROCE, ERR]%s: Hwdev or netdev is null\n", __func__); return ~0ULL; } comp_priv = get_rdma_comp_priv(hwdev); if (comp_priv == NULL) { pr_err("[ROCE, ERR]%s: Comp_priv is null\n", __func__); return ~0ULL; } comp_priv->rdma_comp_res.node_guid = rdma_gen_node_guid((u8 *)netdev->dev_addr); return comp_priv->rdma_comp_res.node_guid; } static const struct ib_device_ops dev_ops = { .owner = THIS_MODULE, .uverbs_abi_ver = ROCE_IB_UVERBS_ABI_VERSION, .create_qp = roce3_create_qp, .modify_qp = roce3_modify_qp, .query_qp = roce3_query_qp, .destroy_qp = roce3_destroy_qp, .post_send = roce3_post_send, .post_recv = roce3_post_recv, .create_cq = roce3_create_cq, .modify_cq = roce3_modify_cq, .resize_cq = roce3_resize_cq, .destroy_cq = roce3_destroy_cq, .poll_cq = roce3_poll_cq, .req_notify_cq = roce3_arm_cq, .create_srq = roce3_create_srq, .modify_srq = roce3_modify_srq, .query_srq = roce3_query_srq, .destroy_srq = roce3_destroy_srq, .post_srq_recv = roce3_post_srq_recv, .map_mr_sg = roce3_map_kernel_frmr_sg, .get_dma_mr = roce3_get_dma_mr, .reg_user_mr = roce3_reg_user_mr, .dereg_mr = roce3_dereg_mr, .alloc_mr = roce3_alloc_mr, .alloc_mw = roce3_alloc_mw, .dealloc_mw = roce3_dealloc_mw, .query_device = roce3_query_device, .query_port = roce3_query_port, .get_link_layer = roce3_port_link_layer, .query_gid = roce3_query_gid, .add_gid = roce3_ib_add_gid, .del_gid = roce3_ib_del_gid, .query_pkey = roce3_query_pkey, .modify_device = roce3_modify_device, .modify_port = roce3_modify_port, .alloc_ucontext = roce3_alloc_ucontext, .dealloc_ucontext = roce3_dealloc_ucontext, .mmap = roce3_mmap, .alloc_pd = roce3_alloc_pd, .dealloc_pd = roce3_dealloc_pd, .create_ah = roce3_create_ah, .query_ah = roce3_query_ah, .destroy_ah = roce3_destroy_ah, .alloc_xrcd = roce3_alloc_xrcd, .dealloc_xrcd = roce3_dealloc_xrcd, .get_port_immutable = roce3_port_immutable, .get_netdev = roce3_ib_get_netdev, INIT_RDMA_OBJ_SIZE(ib_qp, roce3_qp, ibqp), INIT_RDMA_OBJ_SIZE(ib_ah, roce3_ah, ibah), INIT_RDMA_OBJ_SIZE(ib_cq, roce3_cq, ibcq), INIT_RDMA_OBJ_SIZE(ib_pd, roce3_pd, ibpd), INIT_RDMA_OBJ_SIZE(ib_srq, roce3_srq, ibsrq), INIT_RDMA_OBJ_SIZE(ib_ucontext, roce3_ucontext, ibucontext), INIT_RDMA_OBJ_SIZE(ib_xrcd, roce3_xrcd, ibxrcd), INIT_RDMA_OBJ_SIZE(ib_mw, roce3_mw, ibmw), }; static void roce3_add_init(struct roce3_device *rdev) { struct ib_device *ib_dev = &rdev->ib_dev; ib_dev->local_dma_lkey = rdev->rdma_cap.reserved_lkey; ib_dev->phys_port_cnt = (u8)rdev->rdma_cap.num_ports; ib_dev->num_comp_vectors = (rdev->rdma_cap.num_comp_vectors <= MAX_CEQ_NEED) ? (int)rdev->rdma_cap.num_comp_vectors : MAX_CEQ_NEED; ib_dev->node_type = RDMA_NODE_IB_CA; ib_dev->node_guid = roce3_rdma_init_guid(rdev->hwdev, rdev->ndev); ib_dev->dma_device = &rdev->pdev->dev; ib_dev->dev.parent = ib_dev->dma_device; strscpy(ib_dev->node_desc, "hrn3", sizeof("hrn3")); rdev->ib_dev.uverbs_cmd_mask = ROCE_UVERBS_CMD_MASK; ib_set_device_ops(ib_dev, &dev_ops); roce3_init_dev_ext_handlers(rdev); } static void roce3_mod_param_parse(struct roce3_device *rdev) { rdev->try_times = g_loop_times; #ifdef ROCE_BONDING_EN if (g_bond_name != NULL) { rdev->want_bond_slave_cnt = SDI_BOND_SUPPORT_ROCE_FUNC_CNT; rdev->want_bond_slave_bits[0] = SDI_BOND_SUPPORT_ROCE_FUNC_BIT; rdev->want_bond_slave_bits[1] = 0; rdev->sdi_bond_name = g_bond_name; return; } rdev->want_bond_slave_cnt = g_want_bond_slave_cnt; rdev->want_bond_slave_bits[0] = g_want_bond0_slave_bits; rdev->want_bond_slave_bits[1] = 0; rdev->sdi_bond_name = NULL; #endif } static void *roce3_get_ppf_lld_dev(struct roce3_device *rdev) { struct hinic3_lld_dev *ppf_lld_dev = NULL; ppf_lld_dev = hinic3_get_ppf_lld_dev_unsafe(rdev->lld_dev); if (!ppf_lld_dev) { pr_err("[ROCE, ERR] %s: Failed to get ppf lld_dev\n", __func__); return ERR_PTR(-EINVAL); } return ppf_lld_dev->hwdev; } static int roce3_rdev_init(struct roce3_device *rdev) { int ret; void *ppf_hwdev = NULL; if (!hinic3_is_vm_slave_host(rdev->hwdev)) { if ((hinic3_func_type(rdev->hwdev) == TYPE_VF) && (g_ppf_stateful_init == false) && (g_vf_stateful_num == 0)) { ppf_hwdev = roce3_get_ppf_lld_dev(rdev); ret = hinic3_stateful_init(ppf_hwdev); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to init ppf stateful resource\n", __func__); return ret; } } if (hinic3_func_type(rdev->hwdev) == TYPE_PPF) g_ppf_stateful_init = true; } // BM:When the device is PPF, stateful_init is performed only when g_vf_stateful_num is 0. if (hinic3_is_vm_slave_host(rdev->hwdev) || (hinic3_func_type(rdev->hwdev) != TYPE_PPF) || !g_vf_stateful_num) { ret = hinic3_stateful_init(rdev->hwdev); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to init stateful resource\n", __func__); goto err_stateful_init; } } ret = roce3_add_rdev_init(rdev); if (ret != 0) goto err_rdev_init; /*lint -e708*/ spin_lock_init(&rdev->node_desc_lock); /*lint +e708*/ mutex_init(&rdev->cap_mask_mutex); INIT_LIST_HEAD(&rdev->mac_vlan_list_head); mutex_init(&rdev->mac_vlan_mutex); /*lint -e708*/ spin_lock_init(&rdev->reset_flow_resource_lock); /*lint +e708*/ INIT_LIST_HEAD(&rdev->qp_list); roce3_mod_param_parse(rdev); roce3_fix_ibdev_name(rdev); if (hinic3_func_type(rdev->hwdev) == TYPE_VF) g_vf_stateful_num++; return 0; err_rdev_init: hinic3_stateful_deinit(rdev->hwdev); err_stateful_init: if ((g_vf_stateful_num == 0) && (g_ppf_stateful_init == false)) hinic3_stateful_deinit(ppf_hwdev); return ret; } static void roce3_stateful_unit(struct roce3_device *rdev) { void *ppf_hwdev = NULL; if (!hinic3_is_vm_slave_host(rdev->hwdev)) { if (hinic3_func_type(rdev->hwdev) == TYPE_VF) { hinic3_stateful_deinit(rdev->hwdev); g_vf_stateful_num--; // Delete the last VF when no PF is added if ((g_vf_stateful_num == 0) && (g_ppf_stateful_init == false)) { ppf_hwdev = roce3_get_ppf_lld_dev(rdev); hinic3_stateful_deinit(ppf_hwdev); } } else { if (g_vf_stateful_num == 0) hinic3_stateful_deinit(rdev->hwdev); } } else { hinic3_stateful_deinit(rdev->hwdev); } } #ifdef ROCE_NETLINK_EN static void roce3_adapt_unit(struct roce3_device *rdev) { struct hiroce_netlink_dev *adp_dev; int offset = 0; offset = get_instance_of_func_id(rdev->glb_func_id); if (offset >= MAX_FUNCTION_NUM) { pr_err("[ROCE, ERR] %s: offset is over size\n", __func__); return; } adp_dev = hiroce_get_adp(); mutex_lock(&adp_dev->mutex_dev); adp_dev->used_dev_num--; if (adp_dev->used_dev_num <= 0 && adp_dev->netlink) kfree(adp_dev->netlink); mutex_unlock(&adp_dev->mutex_dev); } #endif static void roce3_rdev_unit(struct roce3_device *rdev) { /* FLR by MPU when hotplug, don't need deinit anymore */ if (hinic3_func_type(rdev->hwdev) == TYPE_PPF) g_ppf_stateful_init = false; if (roce3_hca_is_present(rdev) != 0) roce3_stateful_unit(rdev); #ifdef ROCE_NETLINK_EN roce3_netlink_unit(); roce3_adapt_unit(rdev); #endif roce3_add_rdev_unit(rdev); } #ifdef ROCE_NETLINK_EN static int roce3_adapt_init(struct roce3_device *rdev) { int offset = 0; struct hiroce_netlink_dev *adp_dev = NULL; offset = get_instance_of_func_id(rdev->glb_func_id); if (offset >= ROCE_MAX_FUNCTION) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to get offset , func_id(%u)\n", __func__, rdev->glb_func_id); return -EINVAL; } adp_dev = hiroce_get_adp(); mutex_lock(&adp_dev->mutex_dev); if (adp_dev->used_dev_num == 0 && adp_dev->netlink == NULL) { adp_dev->netlink = kzalloc(sizeof(struct hiroce_netlink_dev), GFP_KERNEL); if (adp_dev->netlink == NULL) { mutex_unlock(&adp_dev->mutex_dev); return -EINVAL; } } adp_dev->used_dev_num++; mutex_unlock(&adp_dev->mutex_dev); adp_dev->netlink->rdev[offset] = rdev; return 0; } #endif static int roce3_add_do_init(struct roce3_device *rdev, char *uld_dev_name) { int ret; ret = roce3_rdev_init(rdev); if (ret != 0) goto err_init_rdev; ret = roce3_register_template(rdev); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to register cqm_service, func_id(%u) ret(%d)\n", __func__, rdev->glb_func_id, ret); goto err_cqm_register; } ret = hinic3_alloc_db_addr(rdev->hwdev, &rdev->kernel_db_map, &rdev->kernel_dwqe_map); if (ret != 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Failed to alloc db or dwqe, func_id(%u)\n", __func__, rdev->glb_func_id); goto err_alloc_db; } roce3_add_init(rdev); ret = roce3_alloc_ceq(rdev); if (ret < 0) { dev_err(rdev->hwdev_hdl, "[ROCE, ERR]: Failed to alloc ceqs, func_id(%u)\n", rdev->glb_func_id); goto err_alloc_ceq; } ret = roce3_init_dev(rdev, uld_dev_name); if (ret != 0) goto err_init_dev; #ifdef ROCE_NETLINK_EN ret = roce3_adapt_init(rdev); if (ret != 0) goto err_init_adp; roce3_netlink_init(); return 0; err_init_adp: roce3_adapt_unit(rdev); #else return 0; #endif err_init_dev: roce3_free_ceq(rdev); err_alloc_ceq: hinic3_free_db_addr(rdev->hwdev, rdev->kernel_db_map, rdev->kernel_dwqe_map); err_alloc_db: cqm_service_unregister(rdev->hwdev, SERVICE_T_ROCE); err_cqm_register: roce3_rdev_unit(rdev); err_init_rdev: roce3_remove_device_from_list(rdev->lld_dev); return ret; } static bool is_device_v100(const struct hinic3_lld_dev *lld_dev) { struct pci_dev *pdev = lld_dev->pdev; unsigned short ssdid = pdev->subsystem_device; return (ssdid == HINIC3_DEV_SSID_2X25G) || (ssdid == HINIC3_DEV_SSID_4X25G) || (ssdid == HINIC3_DEV_SSID_2X100G) || (ssdid == HINIC3_DEV_SSID_2X100G_VF); } static int roce3_add_check(const struct hinic3_lld_dev *lld_dev) { int ret = 0; u16 func_id; u8 enable_roce = false; bool is_slave_func = false; if (lld_dev == NULL) { pr_err("[ROCE, ERR] %s: Lld_dev is null\n", __func__); return (-EINVAL); } if (!is_device_v100(lld_dev)) { pr_err("[ROCE, ERR] %s: ssdid 0x%x is NOT standard Card\n", __func__, lld_dev->pdev->subsystem_device); return -ENXIO; } ret = hinic3_is_slave_func(lld_dev->hwdev, &is_slave_func); if (ret != 0) pr_err("[ROCE, ERR] %s: Failed to get slave_func.\n", __func__); if (!is_slave_func) return 0; func_id = hinic3_global_func_id(lld_dev->hwdev); ret = hinic3_get_func_vroce_enable(lld_dev->hwdev, func_id, &enable_roce); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to get roce state.\n", __func__); return ret; } if (!enable_roce) { pr_warn("[ROCE] %s: %s RoCE dev is not enable, func: %u\n", __func__, pci_name(lld_dev->pdev), func_id); return (-EPERM); } return 0; } static void roce3_remove_device_from_list(struct hinic3_lld_dev *lld_dev) { struct roce3_func_info *info; struct roce3_func_info *tmp; if (list_empty(&g_roce_device_list)) return; list_for_each_entry_safe(info, tmp, &g_roce_device_list, node) { if (info->func_id == hinic3_global_func_id(lld_dev->hwdev)) { list_del(&info->node); kfree(info); } } wake_up(&g_roce_probe_queue); } static int roce3_add_device_to_list(struct hinic3_lld_dev *lld_dev) { struct roce3_func_info *info = kzalloc( sizeof(struct roce3_func_info), GFP_ATOMIC); if (info == NULL) { pr_err("[ROCE, ERR] %s: no memory\n", __func__); return -ENOMEM; } info->func_id = hinic3_global_func_id(lld_dev->hwdev); list_add_tail(&info->node, &g_roce_device_list); return 0; } static void roce3_wait_probe(struct hinic3_lld_dev *lld_dev) { struct roce3_func_info *info = NULL; bool wait_flg = false; DECLARE_WAITQUEUE(wait_queue, current); add_wait_queue(&g_roce_probe_queue, &wait_queue); pr_info("[ROCE] %s func %u start to wait\n", __func__, hinic3_global_func_id(lld_dev->hwdev)); do { might_sleep(); info = list_first_entry(&g_roce_device_list, struct roce3_func_info, node); wait_flg = (info->func_id == hinic3_global_func_id(lld_dev->hwdev)) ? true : false; if (!wait_flg) { set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { /* if alarmed by signal */ goto out; } } } while (!wait_flg); set_current_state(TASK_RUNNING); remove_wait_queue(&g_roce_probe_queue, &wait_queue); pr_info("[ROCE] %s func %u wait finished\n", __func__, hinic3_global_func_id(lld_dev->hwdev)); return; out: pr_info("[ROCE] %s func %u wait fail\n", __func__, hinic3_global_func_id(lld_dev->hwdev)); remove_wait_queue(&g_roce_probe_queue, &wait_queue); set_current_state(TASK_RUNNING); } /* **************************************************************************** Prototype : roce3_add Description : roce3_add Input : struct hinic_lld_dev *lld_dev void **uld_dev char *uld_dev_name Output : None 1.Date : 2015/5/27 Modification : Created function **************************************************************************** */ static int roce3_add(struct hinic3_lld_dev *lld_dev, void **uld_dev, char *uld_dev_name) { struct roce3_device *rdev = NULL; struct rdma_service_cap rdma_cap; int ret = 0; ret = roce3_add_check(lld_dev); if (ret != 0) goto err_check; pr_info("[ROCE] %s: Initializing pci(%s)\n", __func__, pci_name(lld_dev->pdev)); /* return 0 if the rdev don't support ROCE, make sure it probe success */ if (!hinic3_support_roce(lld_dev->hwdev, &rdma_cap)) { pr_err("[ROCE, ERR] %s: %s Not support RoCE, func: %u\n", __func__, pci_name(lld_dev->pdev), hinic3_global_func_id(lld_dev->hwdev)); goto err_check; } /* make sure roce device probe in order */ ret = roce3_add_device_to_list(lld_dev); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to add device to list, ret: %d, func: %u\n", __func__, ret, hinic3_global_func_id(lld_dev->hwdev)); return ret; } roce3_rdma_cap_ext(&rdma_cap); rdev = roce3_rdev_alloc(lld_dev, uld_dev, &rdma_cap); if (rdev == NULL) { roce3_remove_device_from_list(lld_dev); pr_err("[ROCE, ERR] %s: Failed to alloc rdev, func: %u\n", __func__, hinic3_global_func_id(lld_dev->hwdev)); return -EINVAL; } ret = roce3_add_do_init(rdev, uld_dev_name); if (ret != 0) goto err_do_init; return 0; err_do_init: ib_dealloc_device(&rdev->ib_dev); err_check: *uld_dev = NULL; return ret; } static void roce3_do_remove(struct roce3_device *rdev, u16 glb_func_id, const char *dev_name) { roce3_remove_dev_file(rdev); roce3_unregister_netdev_event(rdev); if (roce3_hca_is_present(rdev) == 0) { roce3_handle_hotplug_arm_cq(rdev); roce3_kernel_hotplug_event_trigger(rdev); } ib_unregister_device(&rdev->ib_dev); pr_info("[ROCE] %s: Unregister IB device ok, func_id(%u), name(%s), pci(%s)\n", __func__, glb_func_id, dev_name, pci_name(rdev->pdev)); roce3_dealloc_hw_resource(rdev); roce3_deinit_dev_info(rdev); #ifdef ROCE_BONDING_EN roce3_set_bond_ipsurx_en(true); #endif roce3_clean_vlan_device_mac(rdev); roce3_clean_real_device_mac(rdev); roce3_free_ceq(rdev); hinic3_free_db_addr(rdev->hwdev, rdev->kernel_db_map, rdev->kernel_dwqe_map); cqm_service_unregister(rdev->hwdev, SERVICE_T_ROCE); roce3_del_func_res(rdev); pr_info("[ROCE] %s: Function level resource clear ok, func_id(%u), name(%s), pci(%s)\n", __func__, glb_func_id, dev_name, pci_name(rdev->pdev)); roce3_do_cache_out(rdev->hwdev, ROCE_CL_TYPE_CQC_SRQC, rdev->glb_func_id); roce3_rdev_unit(rdev); pr_info("[ROCE] %s: RoCE rdev uninit ok, func_id(%u), name(%s)\n", __func__, glb_func_id, dev_name); ib_dealloc_device(&rdev->ib_dev); } static int roce3_remove_check(const struct hinic3_lld_dev *lld_dev, const void *uld_dev) { if ((uld_dev == NULL) || (lld_dev == NULL)) { pr_err("[ROCE, ERR] %s: input param is null\n", __func__); return (-EINVAL); } return 0; } static void roce3_remove(struct hinic3_lld_dev *lld_dev, void *uld_dev) { struct roce3_device *rdev = NULL; char *dev_name = NULL; u16 glb_func_id; int ret; ret = roce3_remove_check(lld_dev, uld_dev); if (ret != 0) return; rdev = (struct roce3_device *)uld_dev; rdev->ib_active = false; dev_name = rdev->ib_dev.name; glb_func_id = rdev->glb_func_id; if (!hinic3_support_roce(rdev->hwdev, NULL)) { pr_err("[ROCE, ERR] %s: Not support RoCE\n", __func__); return; } dev_info(rdev->hwdev_hdl, "[ROCE] %s: RoCE remove start, func_id(%u), name(%s), pci(%s)\n", __func__, rdev->glb_func_id, dev_name, pci_name(rdev->pdev)); roce3_do_remove(rdev, glb_func_id, dev_name); pr_info("[ROCE] %s: RoCE remove end, func_id(%u), name(%s)\n", __func__, glb_func_id, dev_name); } static bool roce3_need_proc_link_event(void *hwdev) { int ret = 0; u16 func_id; u8 roce_enable = false; bool is_slave_func = false; struct hinic3_hw_bond_infos hw_bond_infos = {0}; ret = hinic3_is_slave_func(hwdev, &is_slave_func); if (ret != 0) { pr_err("[ROCE, ERR] %s: lld_dev is null\n", __func__); return true; } if (!is_slave_func) return true; func_id = hinic3_global_func_id(hwdev); ret = hinic3_get_func_vroce_enable(hwdev, func_id, &roce_enable); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to get vroce info\n", __func__); return true; } if (!roce_enable) return true; hw_bond_infos.bond_id = HINIC_OVS_BOND_DEFAULT_ID; ret = hinic3_get_hw_bond_infos(hwdev, &hw_bond_infos, HINIC3_CHANNEL_COMM); if (ret != 0) { pr_err("[ROCE, ERR] Get chipf bond info failed (%d)\n", ret); return true; } if (!hw_bond_infos.valid) return true; return false; } static bool roce3_need_proc_bond_event(void *hwdev) { return !roce3_need_proc_link_event(hwdev); } static int roce3_proc_bond_status_change(struct roce3_device *rdev, const struct hinic3_event_info *event) { switch (event->type) { case EVENT_NIC_BOND_UP: if (!roce3_need_proc_bond_event(rdev->hwdev)) { dev_info(rdev->hwdev_hdl, "[ROCE, WARN] %s: RoCE don't need proc bond event\n", __func__); return -1; } if (test_and_set_bit(ROCE3_PORT_EVENT, &rdev->status) != 0) return -1; dev_info(rdev->hwdev_hdl, "[ROCE, WARN] %s: RoCE report NIC BOND_UP, func_id(%u)\n", __func__, rdev->glb_func_id); return IB_EVENT_PORT_ACTIVE; case EVENT_NIC_BOND_DOWN: if (!roce3_need_proc_bond_event(rdev->hwdev)) { dev_info(rdev->hwdev_hdl, "[ROCE, WARN] %s: RoCE don't need proc bond event\n", __func__); return -1; } if (test_and_clear_bit(ROCE3_PORT_EVENT, &rdev->status) == 0) return -1; dev_info(rdev->hwdev_hdl, "[ROCE, WARN] %s: RoCE report NIC BOND_DOWN, func_id(%u)\n", __func__, rdev->glb_func_id); return IB_EVENT_PORT_ERR; default: dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Nic event unsupported, func_id(%u), event(%hu)\n", __func__, rdev->glb_func_id, event->type); return -1; } } static int roce3_set_nic_event(struct roce3_device *rdev, const struct hinic3_event_info *event) { switch (event->type) { case EVENT_NIC_LINK_UP: if (test_and_set_bit(ROCE3_PORT_EVENT, &rdev->status) != 0) return -1; dev_info(rdev->hwdev_hdl, "[ROCE, WARN] %s: RoCE report NIC LINK_UP, func_id(%u)\n", __func__, rdev->glb_func_id); return IB_EVENT_PORT_ACTIVE; case EVENT_NIC_LINK_DOWN: if (!roce3_need_proc_link_event(rdev->hwdev)) { dev_info(rdev->hwdev_hdl, "[ROCE, WARN] %s: RoCE don't need proc link event\n", __func__); return -1; } if (test_and_clear_bit(ROCE3_PORT_EVENT, &rdev->status) == 0) return -1; dev_info(rdev->hwdev_hdl, "[ROCE, WARN] %s: RoCE report NIC LINK_DOWN, func_id(%u)\n", __func__, rdev->glb_func_id); return IB_EVENT_PORT_ERR; case EVENT_NIC_BOND_UP: case EVENT_NIC_BOND_DOWN: return roce3_proc_bond_status_change(rdev, event); case EVENT_NIC_DCB_STATE_CHANGE: dev_info(rdev->hwdev_hdl, "[ROCE]%s: DCB state change no longer requires RoCE involvement, func_id(%u)\n", __func__, rdev->glb_func_id); return -1; default: dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: Nic event unsupported, func_id(%u), event(%hu)\n", __func__, rdev->glb_func_id, event->type); return -1; } } static int roce3_set_ib_event(struct roce3_device *rdev, const struct hinic3_event_info *event) { switch (event->service) { case EVENT_SRV_NIC: return roce3_set_nic_event(rdev, event); case EVENT_SRV_COMM: return roce3_set_comm_event(rdev, event); default: dev_err(rdev->hwdev_hdl, "[ROCE, ERR] %s: func_id(%u) event from svc(%hu) is not supported, event(%hu)\n", __func__, rdev->glb_func_id, event->service, event->type); return -1; } } static void roce3_event(struct hinic3_lld_dev *lld_dev, void *uld_dev, struct hinic3_event_info *event) { struct ib_event ibevent; struct roce3_device *rdev = NULL; int type; int ret = 0; roce3_lock_rdev(); ret = roce3_get_rdev_by_uld(lld_dev, uld_dev, &rdev, event); if (ret != 0) { pr_err("[ROCE] %s: find rdev failed, ret(%d)\n", __func__, ret); goto err_unlock; } #ifdef ROCE_BONDING_EN if (roce3_bond_is_active(rdev)) { roce3_handle_bonded_port_state_event(rdev); goto err_unlock; } #endif type = roce3_set_ib_event(rdev, event); if (type == -1) goto err_unlock; ibevent.event = (enum ib_event_type)type; ibevent.device = &rdev->ib_dev; ibevent.element.port_num = ROCE_DEFAULT_PORT_NUM; if (rdev->ib_active) ib_dispatch_event(&ibevent); err_unlock: roce3_unlock_rdev(); } typedef int (*roce3_adm_func_t)(struct roce3_device *rdev, const void *buf_in, u32 in_size, void *buf_out, u32 *out_size); /*lint -e26*/ static roce3_adm_func_t g_roce3_adm_funcs[COMMON_CMD_VM_COMPAT_TEST] = { [COMMON_CMD_GET_DRV_VERSION] = roce3_get_drv_version, #ifdef __ROCE_DFX__ [ROCE_CMD_GET_QPC_FROM_CACHE] = roce3_adm_dfx_query, [ROCE_CMD_GET_QPC_FROM_HOST] = roce3_adm_dfx_query, [ROCE_CMD_GET_CQC_FROM_CACHE] = roce3_adm_dfx_query, [ROCE_CMD_GET_CQC_FROM_HOST] = roce3_adm_dfx_query, [ROCE_CMD_GET_SRQC_FROM_CACHE] = roce3_adm_dfx_query, [ROCE_CMD_GET_SRQC_FROM_HOST] = roce3_adm_dfx_query, [ROCE_CMD_GET_MPT_FROM_CACHE] = roce3_adm_dfx_query, [ROCE_CMD_GET_MPT_FROM_HOST] = roce3_adm_dfx_query, [ROCE_CMD_GET_GID_FROM_CACHE] = roce3_adm_dfx_query, [ROCE_CMD_GET_QPC_CQC_PI_CI] = roce3_adm_dfx_query, [ROCE_CMD_GET_QP_COUNT] = roce3_adm_dfx_query, [ROCE_CMD_GET_DEV_ALGO] = roce3_adm_dfx_query, #ifdef ROCE_PKT_CAP_EN [ROCE_CMD_START_CAP_PACKET] = roce3_adm_dfx_capture, [ROCE_CMD_STOP_CAP_PACKET] = roce3_adm_dfx_capture, [ROCE_CMD_QUERY_CAP_INFO] = roce3_adm_dfx_capture, [ROCE_CMD_ENABLE_QP_CAP_PACKET] = roce3_adm_dfx_capture, [ROCE_CMD_DISABLE_QP_CAP_PACKET] = roce3_adm_dfx_capture, [ROCE_CMD_QUERY_QP_CAP_INFO] = roce3_adm_dfx_capture, #endif /* ROCE_PKT_CAP_EN */ #endif /* __ROCE_DFX__ */ [ROCE_CMD_ENABLE_BW_CTRL] = roce3_adm_dfx_bw_ctrl, [ROCE_CMD_DISABLE_BW_CTRL] = roce3_adm_dfx_bw_ctrl, [ROCE_CMD_CHANGE_BW_CTRL_PARAM] = roce3_adm_dfx_bw_ctrl, [ROCE_CMD_QUERY_BW_CTRL_PARAM] = roce3_adm_dfx_bw_ctrl, }; /*lint +e26*/ static int roce3_adm(void *uld_dev, u32 cmd, const void *buf_in, u32 in_size, void *buf_out, u32 *out_size) { struct roce3_device *rdev = (struct roce3_device *)uld_dev; roce3_adm_func_t roce3_adm_func; if (uld_dev == NULL || buf_in == NULL || buf_out == NULL || out_size == NULL) { pr_err("[ROCE] %s: Input params is null\n", __func__); return -EINVAL; } if (!hinic3_support_roce(rdev->hwdev, NULL)) { pr_err("[ROCE, ERR] %s: %s Not support RoCE\n", __func__, pci_name(rdev->pdev)); return -EINVAL; } rdev = (struct roce3_device *)uld_dev; 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; } if (cmd >= COMMON_CMD_VM_COMPAT_TEST) { dev_err(rdev->hwdev_hdl, "Not support this type(%u)", cmd); return -EINVAL; } roce3_adm_func = g_roce3_adm_funcs[cmd]; if (roce3_adm_func == NULL) { dev_err(rdev->hwdev_hdl, "Not support this type(%u)", cmd); return -EINVAL; } return roce3_adm_func(rdev, buf_in, in_size, buf_out, out_size); } struct hinic3_uld_info roce3_info = { .probe = roce3_add, .remove = roce3_remove, .suspend = NULL, .resume = NULL, .event = roce3_event, .ioctl = roce3_adm, }; struct hinic3_uld_info *roce3_info_get(void) { return &roce3_info; } /* **************************************************************************** Prototype : roce3_service_init Description : Input : void Output : None Return Value : Calls : Called By : History : 1.Date : 2015/5/27 Author : Modification : Created function **************************************************************************** */ static int __init roce3_service_init(void) { int ret; INIT_LIST_HEAD(&g_roce_device_list); init_waitqueue_head(&g_roce_probe_queue); roce3_service_init_pre(); #ifdef ROCE_NETLINK_EN /* init mutex */ mutex_init(&hiroce_get_adp()->mutex_dev); #endif ret = hinic3_register_uld(SERVICE_T_ROCE, roce3_info_get()); if (ret != 0) { pr_err("[ROCE, ERR] %s: Failed to register uld. ret(%d)\n", __func__, ret); return ret; } roce3_service_init_ext(); #ifdef ROCE_BONDING_EN ret = roce3_bond_init(); #endif pr_info("[ROCE] %s: Register roce service done, ret(%d).\n", __func__, ret); return ret; } /* **************************************************************************** Prototype : roce3_service_exit Description : roce service disable Input : void Output : None Return Value : Calls : Called By : History : 1.Date : 2015/5/27 Author : Modification : Created function **************************************************************************** */ static void __exit roce3_service_exit(void) { #ifdef ROCE_BONDING_EN roce3_bond_pre_exit(); #endif hinic3_unregister_uld(SERVICE_T_ROCE); #ifdef ROCE_BONDING_EN pr_info("[ROCE] %s: Bond remove all.\n", __func__); roce3_bond_exit(); #endif pr_info("[ROCE] %s: Unregister roce service successful\n", __func__); } bool roce3_is_roceaa(u8 scence_id) { if ((scence_id == SCENES_ID_STORAGE_ROCEAA_2x100) || (scence_id == SCENES_ID_STORAGE_ROCEAA_4x25)) return true; return false; } module_init(roce3_service_init); module_exit(roce3_service_exit);