18c2ecf20Sopenharmony_ci/* QLogic qedr NIC Driver 28c2ecf20Sopenharmony_ci * Copyright (c) 2015-2016 QLogic Corporation 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and /or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#include <linux/module.h> 338c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h> 348c2ecf20Sopenharmony_ci#include <rdma/ib_addr.h> 358c2ecf20Sopenharmony_ci#include <rdma/ib_user_verbs.h> 368c2ecf20Sopenharmony_ci#include <rdma/iw_cm.h> 378c2ecf20Sopenharmony_ci#include <rdma/ib_mad.h> 388c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 398c2ecf20Sopenharmony_ci#include <linux/iommu.h> 408c2ecf20Sopenharmony_ci#include <linux/pci.h> 418c2ecf20Sopenharmony_ci#include <net/addrconf.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <linux/qed/qed_chain.h> 448c2ecf20Sopenharmony_ci#include <linux/qed/qed_if.h> 458c2ecf20Sopenharmony_ci#include "qedr.h" 468c2ecf20Sopenharmony_ci#include "verbs.h" 478c2ecf20Sopenharmony_ci#include <rdma/qedr-abi.h> 488c2ecf20Sopenharmony_ci#include "qedr_iw_cm.h" 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic 40G/100G ROCE Driver"); 518c2ecf20Sopenharmony_ciMODULE_AUTHOR("QLogic Corporation"); 528c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define QEDR_WQ_MULTIPLIER_DFT (3) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic void qedr_ib_dispatch_event(struct qedr_dev *dev, u8 port_num, 578c2ecf20Sopenharmony_ci enum ib_event_type type) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct ib_event ibev; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci ibev.device = &dev->ibdev; 628c2ecf20Sopenharmony_ci ibev.element.port_num = port_num; 638c2ecf20Sopenharmony_ci ibev.event = type; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci ib_dispatch_event(&ibev); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic enum rdma_link_layer qedr_link_layer(struct ib_device *device, 698c2ecf20Sopenharmony_ci u8 port_num) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci return IB_LINK_LAYER_ETHERNET; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void qedr_get_dev_fw_str(struct ib_device *ibdev, char *str) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct qedr_dev *qedr = get_qedr_dev(ibdev); 778c2ecf20Sopenharmony_ci u32 fw_ver = (u32)qedr->attr.fw_ver; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci snprintf(str, IB_FW_VERSION_NAME_MAX, "%d.%d.%d.%d", 808c2ecf20Sopenharmony_ci (fw_ver >> 24) & 0xFF, (fw_ver >> 16) & 0xFF, 818c2ecf20Sopenharmony_ci (fw_ver >> 8) & 0xFF, fw_ver & 0xFF); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int qedr_roce_port_immutable(struct ib_device *ibdev, u8 port_num, 858c2ecf20Sopenharmony_ci struct ib_port_immutable *immutable) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct ib_port_attr attr; 888c2ecf20Sopenharmony_ci int err; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci err = qedr_query_port(ibdev, port_num, &attr); 918c2ecf20Sopenharmony_ci if (err) 928c2ecf20Sopenharmony_ci return err; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci immutable->pkey_tbl_len = attr.pkey_tbl_len; 958c2ecf20Sopenharmony_ci immutable->gid_tbl_len = attr.gid_tbl_len; 968c2ecf20Sopenharmony_ci immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE | 978c2ecf20Sopenharmony_ci RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP; 988c2ecf20Sopenharmony_ci immutable->max_mad_size = IB_MGMT_MAD_SIZE; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int qedr_iw_port_immutable(struct ib_device *ibdev, u8 port_num, 1048c2ecf20Sopenharmony_ci struct ib_port_immutable *immutable) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct ib_port_attr attr; 1078c2ecf20Sopenharmony_ci int err; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci err = qedr_query_port(ibdev, port_num, &attr); 1108c2ecf20Sopenharmony_ci if (err) 1118c2ecf20Sopenharmony_ci return err; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci immutable->gid_tbl_len = 1; 1148c2ecf20Sopenharmony_ci immutable->core_cap_flags = RDMA_CORE_PORT_IWARP; 1158c2ecf20Sopenharmony_ci immutable->max_mad_size = 0; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* QEDR sysfs interface */ 1218c2ecf20Sopenharmony_cistatic ssize_t hw_rev_show(struct device *device, struct device_attribute *attr, 1228c2ecf20Sopenharmony_ci char *buf) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct qedr_dev *dev = 1258c2ecf20Sopenharmony_ci rdma_device_to_drv_device(device, struct qedr_dev, ibdev); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "0x%x\n", dev->attr.hw_ver); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(hw_rev); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic ssize_t hca_type_show(struct device *device, 1328c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct qedr_dev *dev = 1358c2ecf20Sopenharmony_ci rdma_device_to_drv_device(device, struct qedr_dev, ibdev); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "FastLinQ QL%x %s\n", 1388c2ecf20Sopenharmony_ci dev->pdev->device, 1398c2ecf20Sopenharmony_ci rdma_protocol_iwarp(&dev->ibdev, 1) ? 1408c2ecf20Sopenharmony_ci "iWARP" : "RoCE"); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(hca_type); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic struct attribute *qedr_attributes[] = { 1458c2ecf20Sopenharmony_ci &dev_attr_hw_rev.attr, 1468c2ecf20Sopenharmony_ci &dev_attr_hca_type.attr, 1478c2ecf20Sopenharmony_ci NULL 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic const struct attribute_group qedr_attr_group = { 1518c2ecf20Sopenharmony_ci .attrs = qedr_attributes, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic const struct ib_device_ops qedr_iw_dev_ops = { 1558c2ecf20Sopenharmony_ci .get_port_immutable = qedr_iw_port_immutable, 1568c2ecf20Sopenharmony_ci .iw_accept = qedr_iw_accept, 1578c2ecf20Sopenharmony_ci .iw_add_ref = qedr_iw_qp_add_ref, 1588c2ecf20Sopenharmony_ci .iw_connect = qedr_iw_connect, 1598c2ecf20Sopenharmony_ci .iw_create_listen = qedr_iw_create_listen, 1608c2ecf20Sopenharmony_ci .iw_destroy_listen = qedr_iw_destroy_listen, 1618c2ecf20Sopenharmony_ci .iw_get_qp = qedr_iw_get_qp, 1628c2ecf20Sopenharmony_ci .iw_reject = qedr_iw_reject, 1638c2ecf20Sopenharmony_ci .iw_rem_ref = qedr_iw_qp_rem_ref, 1648c2ecf20Sopenharmony_ci .query_gid = qedr_iw_query_gid, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int qedr_iw_register_device(struct qedr_dev *dev) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci dev->ibdev.node_type = RDMA_NODE_RNIC; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ib_set_device_ops(&dev->ibdev, &qedr_iw_dev_ops); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci memcpy(dev->ibdev.iw_ifname, 1748c2ecf20Sopenharmony_ci dev->ndev->name, sizeof(dev->ibdev.iw_ifname)); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const struct ib_device_ops qedr_roce_dev_ops = { 1808c2ecf20Sopenharmony_ci .alloc_xrcd = qedr_alloc_xrcd, 1818c2ecf20Sopenharmony_ci .dealloc_xrcd = qedr_dealloc_xrcd, 1828c2ecf20Sopenharmony_ci .get_port_immutable = qedr_roce_port_immutable, 1838c2ecf20Sopenharmony_ci .query_pkey = qedr_query_pkey, 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void qedr_roce_register_device(struct qedr_dev *dev) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci dev->ibdev.node_type = RDMA_NODE_IB_CA; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ib_set_device_ops(&dev->ibdev, &qedr_roce_dev_ops); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci dev->ibdev.uverbs_cmd_mask |= QEDR_UVERBS(OPEN_XRCD) | 1938c2ecf20Sopenharmony_ci QEDR_UVERBS(CLOSE_XRCD) | 1948c2ecf20Sopenharmony_ci QEDR_UVERBS(CREATE_XSRQ); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic const struct ib_device_ops qedr_dev_ops = { 1988c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1998c2ecf20Sopenharmony_ci .driver_id = RDMA_DRIVER_QEDR, 2008c2ecf20Sopenharmony_ci .uverbs_abi_ver = QEDR_ABI_VERSION, 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci .alloc_mr = qedr_alloc_mr, 2038c2ecf20Sopenharmony_ci .alloc_pd = qedr_alloc_pd, 2048c2ecf20Sopenharmony_ci .alloc_ucontext = qedr_alloc_ucontext, 2058c2ecf20Sopenharmony_ci .create_ah = qedr_create_ah, 2068c2ecf20Sopenharmony_ci .create_cq = qedr_create_cq, 2078c2ecf20Sopenharmony_ci .create_qp = qedr_create_qp, 2088c2ecf20Sopenharmony_ci .create_srq = qedr_create_srq, 2098c2ecf20Sopenharmony_ci .dealloc_pd = qedr_dealloc_pd, 2108c2ecf20Sopenharmony_ci .dealloc_ucontext = qedr_dealloc_ucontext, 2118c2ecf20Sopenharmony_ci .dereg_mr = qedr_dereg_mr, 2128c2ecf20Sopenharmony_ci .destroy_ah = qedr_destroy_ah, 2138c2ecf20Sopenharmony_ci .destroy_cq = qedr_destroy_cq, 2148c2ecf20Sopenharmony_ci .destroy_qp = qedr_destroy_qp, 2158c2ecf20Sopenharmony_ci .destroy_srq = qedr_destroy_srq, 2168c2ecf20Sopenharmony_ci .get_dev_fw_str = qedr_get_dev_fw_str, 2178c2ecf20Sopenharmony_ci .get_dma_mr = qedr_get_dma_mr, 2188c2ecf20Sopenharmony_ci .get_link_layer = qedr_link_layer, 2198c2ecf20Sopenharmony_ci .map_mr_sg = qedr_map_mr_sg, 2208c2ecf20Sopenharmony_ci .mmap = qedr_mmap, 2218c2ecf20Sopenharmony_ci .mmap_free = qedr_mmap_free, 2228c2ecf20Sopenharmony_ci .modify_qp = qedr_modify_qp, 2238c2ecf20Sopenharmony_ci .modify_srq = qedr_modify_srq, 2248c2ecf20Sopenharmony_ci .poll_cq = qedr_poll_cq, 2258c2ecf20Sopenharmony_ci .post_recv = qedr_post_recv, 2268c2ecf20Sopenharmony_ci .post_send = qedr_post_send, 2278c2ecf20Sopenharmony_ci .post_srq_recv = qedr_post_srq_recv, 2288c2ecf20Sopenharmony_ci .process_mad = qedr_process_mad, 2298c2ecf20Sopenharmony_ci .query_device = qedr_query_device, 2308c2ecf20Sopenharmony_ci .query_port = qedr_query_port, 2318c2ecf20Sopenharmony_ci .query_qp = qedr_query_qp, 2328c2ecf20Sopenharmony_ci .query_srq = qedr_query_srq, 2338c2ecf20Sopenharmony_ci .reg_user_mr = qedr_reg_user_mr, 2348c2ecf20Sopenharmony_ci .req_notify_cq = qedr_arm_cq, 2358c2ecf20Sopenharmony_ci .resize_cq = qedr_resize_cq, 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ah, qedr_ah, ibah), 2388c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_cq, qedr_cq, ibcq), 2398c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_pd, qedr_pd, ibpd), 2408c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_srq, qedr_srq, ibsrq), 2418c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_xrcd, qedr_xrcd, ibxrcd), 2428c2ecf20Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ucontext, qedr_ucontext, ibucontext), 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int qedr_register_device(struct qedr_dev *dev) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci int rc; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci dev->ibdev.node_guid = dev->attr.node_guid; 2508c2ecf20Sopenharmony_ci memcpy(dev->ibdev.node_desc, QEDR_NODE_DESC, sizeof(QEDR_NODE_DESC)); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dev->ibdev.uverbs_cmd_mask = QEDR_UVERBS(GET_CONTEXT) | 2538c2ecf20Sopenharmony_ci QEDR_UVERBS(QUERY_DEVICE) | 2548c2ecf20Sopenharmony_ci QEDR_UVERBS(QUERY_PORT) | 2558c2ecf20Sopenharmony_ci QEDR_UVERBS(ALLOC_PD) | 2568c2ecf20Sopenharmony_ci QEDR_UVERBS(DEALLOC_PD) | 2578c2ecf20Sopenharmony_ci QEDR_UVERBS(CREATE_COMP_CHANNEL) | 2588c2ecf20Sopenharmony_ci QEDR_UVERBS(CREATE_CQ) | 2598c2ecf20Sopenharmony_ci QEDR_UVERBS(RESIZE_CQ) | 2608c2ecf20Sopenharmony_ci QEDR_UVERBS(DESTROY_CQ) | 2618c2ecf20Sopenharmony_ci QEDR_UVERBS(REQ_NOTIFY_CQ) | 2628c2ecf20Sopenharmony_ci QEDR_UVERBS(CREATE_QP) | 2638c2ecf20Sopenharmony_ci QEDR_UVERBS(MODIFY_QP) | 2648c2ecf20Sopenharmony_ci QEDR_UVERBS(QUERY_QP) | 2658c2ecf20Sopenharmony_ci QEDR_UVERBS(DESTROY_QP) | 2668c2ecf20Sopenharmony_ci QEDR_UVERBS(CREATE_SRQ) | 2678c2ecf20Sopenharmony_ci QEDR_UVERBS(DESTROY_SRQ) | 2688c2ecf20Sopenharmony_ci QEDR_UVERBS(QUERY_SRQ) | 2698c2ecf20Sopenharmony_ci QEDR_UVERBS(MODIFY_SRQ) | 2708c2ecf20Sopenharmony_ci QEDR_UVERBS(POST_SRQ_RECV) | 2718c2ecf20Sopenharmony_ci QEDR_UVERBS(REG_MR) | 2728c2ecf20Sopenharmony_ci QEDR_UVERBS(DEREG_MR) | 2738c2ecf20Sopenharmony_ci QEDR_UVERBS(POLL_CQ) | 2748c2ecf20Sopenharmony_ci QEDR_UVERBS(POST_SEND) | 2758c2ecf20Sopenharmony_ci QEDR_UVERBS(POST_RECV); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (IS_IWARP(dev)) { 2788c2ecf20Sopenharmony_ci rc = qedr_iw_register_device(dev); 2798c2ecf20Sopenharmony_ci if (rc) 2808c2ecf20Sopenharmony_ci return rc; 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci qedr_roce_register_device(dev); 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci dev->ibdev.phys_port_cnt = 1; 2868c2ecf20Sopenharmony_ci dev->ibdev.num_comp_vectors = dev->num_cnq; 2878c2ecf20Sopenharmony_ci dev->ibdev.dev.parent = &dev->pdev->dev; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci rdma_set_device_sysfs_group(&dev->ibdev, &qedr_attr_group); 2908c2ecf20Sopenharmony_ci ib_set_device_ops(&dev->ibdev, &qedr_dev_ops); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci rc = ib_device_set_netdev(&dev->ibdev, dev->ndev, 1); 2938c2ecf20Sopenharmony_ci if (rc) 2948c2ecf20Sopenharmony_ci return rc; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci dma_set_max_seg_size(&dev->pdev->dev, UINT_MAX); 2978c2ecf20Sopenharmony_ci return ib_register_device(&dev->ibdev, "qedr%d", &dev->pdev->dev); 2988c2ecf20Sopenharmony_ci} 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/* This function allocates fast-path status block memory */ 3018c2ecf20Sopenharmony_cistatic int qedr_alloc_mem_sb(struct qedr_dev *dev, 3028c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info, u16 sb_id) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct status_block_e4 *sb_virt; 3058c2ecf20Sopenharmony_ci dma_addr_t sb_phys; 3068c2ecf20Sopenharmony_ci int rc; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci sb_virt = dma_alloc_coherent(&dev->pdev->dev, 3098c2ecf20Sopenharmony_ci sizeof(*sb_virt), &sb_phys, GFP_KERNEL); 3108c2ecf20Sopenharmony_ci if (!sb_virt) 3118c2ecf20Sopenharmony_ci return -ENOMEM; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci rc = dev->ops->common->sb_init(dev->cdev, sb_info, 3148c2ecf20Sopenharmony_ci sb_virt, sb_phys, sb_id, 3158c2ecf20Sopenharmony_ci QED_SB_TYPE_CNQ); 3168c2ecf20Sopenharmony_ci if (rc) { 3178c2ecf20Sopenharmony_ci pr_err("Status block initialization failed\n"); 3188c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, sizeof(*sb_virt), 3198c2ecf20Sopenharmony_ci sb_virt, sb_phys); 3208c2ecf20Sopenharmony_ci return rc; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void qedr_free_mem_sb(struct qedr_dev *dev, 3278c2ecf20Sopenharmony_ci struct qed_sb_info *sb_info, int sb_id) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci if (sb_info->sb_virt) { 3308c2ecf20Sopenharmony_ci dev->ops->common->sb_release(dev->cdev, sb_info, sb_id, 3318c2ecf20Sopenharmony_ci QED_SB_TYPE_CNQ); 3328c2ecf20Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, sizeof(*sb_info->sb_virt), 3338c2ecf20Sopenharmony_ci (void *)sb_info->sb_virt, sb_info->sb_phys); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic void qedr_free_resources(struct qedr_dev *dev) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci int i; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (IS_IWARP(dev)) 3428c2ecf20Sopenharmony_ci destroy_workqueue(dev->iwarp_wq); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_cnq; i++) { 3458c2ecf20Sopenharmony_ci qedr_free_mem_sb(dev, &dev->sb_array[i], dev->sb_start + i); 3468c2ecf20Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &dev->cnq_array[i].pbl); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci kfree(dev->cnq_array); 3508c2ecf20Sopenharmony_ci kfree(dev->sb_array); 3518c2ecf20Sopenharmony_ci kfree(dev->sgid_tbl); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int qedr_alloc_resources(struct qedr_dev *dev) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct qed_chain_init_params params = { 3578c2ecf20Sopenharmony_ci .mode = QED_CHAIN_MODE_PBL, 3588c2ecf20Sopenharmony_ci .intended_use = QED_CHAIN_USE_TO_CONSUME, 3598c2ecf20Sopenharmony_ci .cnt_type = QED_CHAIN_CNT_TYPE_U16, 3608c2ecf20Sopenharmony_ci .elem_size = sizeof(struct regpair *), 3618c2ecf20Sopenharmony_ci }; 3628c2ecf20Sopenharmony_ci struct qedr_cnq *cnq; 3638c2ecf20Sopenharmony_ci __le16 *cons_pi; 3648c2ecf20Sopenharmony_ci int i, rc; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci dev->sgid_tbl = kcalloc(QEDR_MAX_SGID, sizeof(union ib_gid), 3678c2ecf20Sopenharmony_ci GFP_KERNEL); 3688c2ecf20Sopenharmony_ci if (!dev->sgid_tbl) 3698c2ecf20Sopenharmony_ci return -ENOMEM; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci spin_lock_init(&dev->sgid_lock); 3728c2ecf20Sopenharmony_ci xa_init_flags(&dev->srqs, XA_FLAGS_LOCK_IRQ); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (IS_IWARP(dev)) { 3758c2ecf20Sopenharmony_ci xa_init(&dev->qps); 3768c2ecf20Sopenharmony_ci dev->iwarp_wq = create_singlethread_workqueue("qedr_iwarpq"); 3778c2ecf20Sopenharmony_ci if (!dev->iwarp_wq) { 3788c2ecf20Sopenharmony_ci rc = -ENOMEM; 3798c2ecf20Sopenharmony_ci goto err1; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Allocate Status blocks for CNQ */ 3848c2ecf20Sopenharmony_ci dev->sb_array = kcalloc(dev->num_cnq, sizeof(*dev->sb_array), 3858c2ecf20Sopenharmony_ci GFP_KERNEL); 3868c2ecf20Sopenharmony_ci if (!dev->sb_array) { 3878c2ecf20Sopenharmony_ci rc = -ENOMEM; 3888c2ecf20Sopenharmony_ci goto err_destroy_wq; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci dev->cnq_array = kcalloc(dev->num_cnq, 3928c2ecf20Sopenharmony_ci sizeof(*dev->cnq_array), GFP_KERNEL); 3938c2ecf20Sopenharmony_ci if (!dev->cnq_array) { 3948c2ecf20Sopenharmony_ci rc = -ENOMEM; 3958c2ecf20Sopenharmony_ci goto err2; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci dev->sb_start = dev->ops->rdma_get_start_sb(dev->cdev); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Allocate CNQ PBLs */ 4018c2ecf20Sopenharmony_ci params.num_elems = min_t(u32, QED_RDMA_MAX_CNQ_SIZE, 4028c2ecf20Sopenharmony_ci QEDR_ROCE_MAX_CNQ_SIZE); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_cnq; i++) { 4058c2ecf20Sopenharmony_ci cnq = &dev->cnq_array[i]; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci rc = qedr_alloc_mem_sb(dev, &dev->sb_array[i], 4088c2ecf20Sopenharmony_ci dev->sb_start + i); 4098c2ecf20Sopenharmony_ci if (rc) 4108c2ecf20Sopenharmony_ci goto err3; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci rc = dev->ops->common->chain_alloc(dev->cdev, &cnq->pbl, 4138c2ecf20Sopenharmony_ci ¶ms); 4148c2ecf20Sopenharmony_ci if (rc) 4158c2ecf20Sopenharmony_ci goto err4; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci cnq->dev = dev; 4188c2ecf20Sopenharmony_ci cnq->sb = &dev->sb_array[i]; 4198c2ecf20Sopenharmony_ci cons_pi = dev->sb_array[i].sb_virt->pi_array; 4208c2ecf20Sopenharmony_ci cnq->hw_cons_ptr = &cons_pi[QED_ROCE_PROTOCOL_INDEX]; 4218c2ecf20Sopenharmony_ci cnq->index = i; 4228c2ecf20Sopenharmony_ci sprintf(cnq->name, "qedr%d@pci:%s", i, pci_name(dev->pdev)); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "cnq[%d].cons=%d\n", 4258c2ecf20Sopenharmony_ci i, qed_chain_get_cons_idx(&cnq->pbl)); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_cierr4: 4308c2ecf20Sopenharmony_ci qedr_free_mem_sb(dev, &dev->sb_array[i], dev->sb_start + i); 4318c2ecf20Sopenharmony_cierr3: 4328c2ecf20Sopenharmony_ci for (--i; i >= 0; i--) { 4338c2ecf20Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &dev->cnq_array[i].pbl); 4348c2ecf20Sopenharmony_ci qedr_free_mem_sb(dev, &dev->sb_array[i], dev->sb_start + i); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci kfree(dev->cnq_array); 4378c2ecf20Sopenharmony_cierr2: 4388c2ecf20Sopenharmony_ci kfree(dev->sb_array); 4398c2ecf20Sopenharmony_cierr_destroy_wq: 4408c2ecf20Sopenharmony_ci if (IS_IWARP(dev)) 4418c2ecf20Sopenharmony_ci destroy_workqueue(dev->iwarp_wq); 4428c2ecf20Sopenharmony_cierr1: 4438c2ecf20Sopenharmony_ci kfree(dev->sgid_tbl); 4448c2ecf20Sopenharmony_ci return rc; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void qedr_pci_set_atomic(struct qedr_dev *dev, struct pci_dev *pdev) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci int rc = pci_enable_atomic_ops_to_root(pdev, 4508c2ecf20Sopenharmony_ci PCI_EXP_DEVCAP2_ATOMIC_COMP64); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (rc) { 4538c2ecf20Sopenharmony_ci dev->atomic_cap = IB_ATOMIC_NONE; 4548c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "Atomic capability disabled\n"); 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci dev->atomic_cap = IB_ATOMIC_GLOB; 4578c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "Atomic capability enabled\n"); 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic const struct qed_rdma_ops *qed_ops; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo)) 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic irqreturn_t qedr_irq_handler(int irq, void *handle) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci u16 hw_comp_cons, sw_comp_cons; 4688c2ecf20Sopenharmony_ci struct qedr_cnq *cnq = handle; 4698c2ecf20Sopenharmony_ci struct regpair *cq_handle; 4708c2ecf20Sopenharmony_ci struct qedr_cq *cq; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci qed_sb_ack(cnq->sb, IGU_INT_DISABLE, 0); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci qed_sb_update_sb_idx(cnq->sb); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci hw_comp_cons = le16_to_cpu(*cnq->hw_cons_ptr); 4778c2ecf20Sopenharmony_ci sw_comp_cons = qed_chain_get_cons_idx(&cnq->pbl); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* Align protocol-index and chain reads */ 4808c2ecf20Sopenharmony_ci rmb(); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci while (sw_comp_cons != hw_comp_cons) { 4838c2ecf20Sopenharmony_ci cq_handle = (struct regpair *)qed_chain_consume(&cnq->pbl); 4848c2ecf20Sopenharmony_ci cq = (struct qedr_cq *)(uintptr_t)HILO_U64(cq_handle->hi, 4858c2ecf20Sopenharmony_ci cq_handle->lo); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (cq == NULL) { 4888c2ecf20Sopenharmony_ci DP_ERR(cnq->dev, 4898c2ecf20Sopenharmony_ci "Received NULL CQ cq_handle->hi=%d cq_handle->lo=%d sw_comp_cons=%d hw_comp_cons=%d\n", 4908c2ecf20Sopenharmony_ci cq_handle->hi, cq_handle->lo, sw_comp_cons, 4918c2ecf20Sopenharmony_ci hw_comp_cons); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (cq->sig != QEDR_CQ_MAGIC_NUMBER) { 4978c2ecf20Sopenharmony_ci DP_ERR(cnq->dev, 4988c2ecf20Sopenharmony_ci "Problem with cq signature, cq_handle->hi=%d ch_handle->lo=%d cq=%p\n", 4998c2ecf20Sopenharmony_ci cq_handle->hi, cq_handle->lo, cq); 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci cq->arm_flags = 0; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (!cq->destroyed && cq->ibcq.comp_handler) 5068c2ecf20Sopenharmony_ci (*cq->ibcq.comp_handler) 5078c2ecf20Sopenharmony_ci (&cq->ibcq, cq->ibcq.cq_context); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* The CQ's CNQ notification counter is checked before 5108c2ecf20Sopenharmony_ci * destroying the CQ in a busy-wait loop that waits for all of 5118c2ecf20Sopenharmony_ci * the CQ's CNQ interrupts to be processed. It is increased 5128c2ecf20Sopenharmony_ci * here, only after the completion handler, to ensure that the 5138c2ecf20Sopenharmony_ci * the handler is not running when the CQ is destroyed. 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci cq->cnq_notif++; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci sw_comp_cons = qed_chain_get_cons_idx(&cnq->pbl); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci cnq->n_comp++; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci qed_ops->rdma_cnq_prod_update(cnq->dev->rdma_ctx, cnq->index, 5238c2ecf20Sopenharmony_ci sw_comp_cons); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci qed_sb_ack(cnq->sb, IGU_INT_ENABLE, 1); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void qedr_sync_free_irqs(struct qedr_dev *dev) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci u32 vector; 5338c2ecf20Sopenharmony_ci u16 idx; 5348c2ecf20Sopenharmony_ci int i; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci for (i = 0; i < dev->int_info.used_cnt; i++) { 5378c2ecf20Sopenharmony_ci if (dev->int_info.msix_cnt) { 5388c2ecf20Sopenharmony_ci idx = i * dev->num_hwfns + dev->affin_hwfn_idx; 5398c2ecf20Sopenharmony_ci vector = dev->int_info.msix[idx].vector; 5408c2ecf20Sopenharmony_ci synchronize_irq(vector); 5418c2ecf20Sopenharmony_ci free_irq(vector, &dev->cnq_array[i]); 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci dev->int_info.used_cnt = 0; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int qedr_req_msix_irqs(struct qedr_dev *dev) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci int i, rc = 0; 5518c2ecf20Sopenharmony_ci u16 idx; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (dev->num_cnq > dev->int_info.msix_cnt) { 5548c2ecf20Sopenharmony_ci DP_ERR(dev, 5558c2ecf20Sopenharmony_ci "Interrupt mismatch: %d CNQ queues > %d MSI-x vectors\n", 5568c2ecf20Sopenharmony_ci dev->num_cnq, dev->int_info.msix_cnt); 5578c2ecf20Sopenharmony_ci return -EINVAL; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_cnq; i++) { 5618c2ecf20Sopenharmony_ci idx = i * dev->num_hwfns + dev->affin_hwfn_idx; 5628c2ecf20Sopenharmony_ci rc = request_irq(dev->int_info.msix[idx].vector, 5638c2ecf20Sopenharmony_ci qedr_irq_handler, 0, dev->cnq_array[i].name, 5648c2ecf20Sopenharmony_ci &dev->cnq_array[i]); 5658c2ecf20Sopenharmony_ci if (rc) { 5668c2ecf20Sopenharmony_ci DP_ERR(dev, "Request cnq %d irq failed\n", i); 5678c2ecf20Sopenharmony_ci qedr_sync_free_irqs(dev); 5688c2ecf20Sopenharmony_ci } else { 5698c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, 5708c2ecf20Sopenharmony_ci "Requested cnq irq for %s [entry %d]. Cookie is at %p\n", 5718c2ecf20Sopenharmony_ci dev->cnq_array[i].name, i, 5728c2ecf20Sopenharmony_ci &dev->cnq_array[i]); 5738c2ecf20Sopenharmony_ci dev->int_info.used_cnt++; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return rc; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int qedr_setup_irqs(struct qedr_dev *dev) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci int rc; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_setup_irqs\n"); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* Learn Interrupt configuration */ 5878c2ecf20Sopenharmony_ci rc = dev->ops->rdma_set_rdma_int(dev->cdev, dev->num_cnq); 5888c2ecf20Sopenharmony_ci if (rc < 0) 5898c2ecf20Sopenharmony_ci return rc; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci rc = dev->ops->rdma_get_rdma_int(dev->cdev, &dev->int_info); 5928c2ecf20Sopenharmony_ci if (rc) { 5938c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "get_rdma_int failed\n"); 5948c2ecf20Sopenharmony_ci return rc; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (dev->int_info.msix_cnt) { 5988c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "rdma msix_cnt = %d\n", 5998c2ecf20Sopenharmony_ci dev->int_info.msix_cnt); 6008c2ecf20Sopenharmony_ci rc = qedr_req_msix_irqs(dev); 6018c2ecf20Sopenharmony_ci if (rc) 6028c2ecf20Sopenharmony_ci return rc; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "qedr_setup_irqs succeeded\n"); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic int qedr_set_device_attr(struct qedr_dev *dev) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct qed_rdma_device *qed_attr; 6138c2ecf20Sopenharmony_ci struct qedr_device_attr *attr; 6148c2ecf20Sopenharmony_ci u32 page_size; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* Part 1 - query core capabilities */ 6178c2ecf20Sopenharmony_ci qed_attr = dev->ops->rdma_query_device(dev->rdma_ctx); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Part 2 - check capabilities */ 6208c2ecf20Sopenharmony_ci page_size = ~qed_attr->page_size_caps + 1; 6218c2ecf20Sopenharmony_ci if (page_size > PAGE_SIZE) { 6228c2ecf20Sopenharmony_ci DP_ERR(dev, 6238c2ecf20Sopenharmony_ci "Kernel PAGE_SIZE is %ld which is smaller than minimum page size (%d) required by qedr\n", 6248c2ecf20Sopenharmony_ci PAGE_SIZE, page_size); 6258c2ecf20Sopenharmony_ci return -ENODEV; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* Part 3 - copy and update capabilities */ 6298c2ecf20Sopenharmony_ci attr = &dev->attr; 6308c2ecf20Sopenharmony_ci attr->vendor_id = qed_attr->vendor_id; 6318c2ecf20Sopenharmony_ci attr->vendor_part_id = qed_attr->vendor_part_id; 6328c2ecf20Sopenharmony_ci attr->hw_ver = qed_attr->hw_ver; 6338c2ecf20Sopenharmony_ci attr->fw_ver = qed_attr->fw_ver; 6348c2ecf20Sopenharmony_ci attr->node_guid = qed_attr->node_guid; 6358c2ecf20Sopenharmony_ci attr->sys_image_guid = qed_attr->sys_image_guid; 6368c2ecf20Sopenharmony_ci attr->max_cnq = qed_attr->max_cnq; 6378c2ecf20Sopenharmony_ci attr->max_sge = qed_attr->max_sge; 6388c2ecf20Sopenharmony_ci attr->max_inline = qed_attr->max_inline; 6398c2ecf20Sopenharmony_ci attr->max_sqe = min_t(u32, qed_attr->max_wqe, QEDR_MAX_SQE); 6408c2ecf20Sopenharmony_ci attr->max_rqe = min_t(u32, qed_attr->max_wqe, QEDR_MAX_RQE); 6418c2ecf20Sopenharmony_ci attr->max_qp_resp_rd_atomic_resc = qed_attr->max_qp_resp_rd_atomic_resc; 6428c2ecf20Sopenharmony_ci attr->max_qp_req_rd_atomic_resc = qed_attr->max_qp_req_rd_atomic_resc; 6438c2ecf20Sopenharmony_ci attr->max_dev_resp_rd_atomic_resc = 6448c2ecf20Sopenharmony_ci qed_attr->max_dev_resp_rd_atomic_resc; 6458c2ecf20Sopenharmony_ci attr->max_cq = qed_attr->max_cq; 6468c2ecf20Sopenharmony_ci attr->max_qp = qed_attr->max_qp; 6478c2ecf20Sopenharmony_ci attr->max_mr = qed_attr->max_mr; 6488c2ecf20Sopenharmony_ci attr->max_mr_size = qed_attr->max_mr_size; 6498c2ecf20Sopenharmony_ci attr->max_cqe = min_t(u64, qed_attr->max_cqe, QEDR_MAX_CQES); 6508c2ecf20Sopenharmony_ci attr->max_mw = qed_attr->max_mw; 6518c2ecf20Sopenharmony_ci attr->max_mr_mw_fmr_pbl = qed_attr->max_mr_mw_fmr_pbl; 6528c2ecf20Sopenharmony_ci attr->max_mr_mw_fmr_size = qed_attr->max_mr_mw_fmr_size; 6538c2ecf20Sopenharmony_ci attr->max_pd = qed_attr->max_pd; 6548c2ecf20Sopenharmony_ci attr->max_ah = qed_attr->max_ah; 6558c2ecf20Sopenharmony_ci attr->max_pkey = qed_attr->max_pkey; 6568c2ecf20Sopenharmony_ci attr->max_srq = qed_attr->max_srq; 6578c2ecf20Sopenharmony_ci attr->max_srq_wr = qed_attr->max_srq_wr; 6588c2ecf20Sopenharmony_ci attr->dev_caps = qed_attr->dev_caps; 6598c2ecf20Sopenharmony_ci attr->page_size_caps = qed_attr->page_size_caps; 6608c2ecf20Sopenharmony_ci attr->dev_ack_delay = qed_attr->dev_ack_delay; 6618c2ecf20Sopenharmony_ci attr->reserved_lkey = qed_attr->reserved_lkey; 6628c2ecf20Sopenharmony_ci attr->bad_pkey_counter = qed_attr->bad_pkey_counter; 6638c2ecf20Sopenharmony_ci attr->max_stats_queues = qed_attr->max_stats_queues; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return 0; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic void qedr_unaffiliated_event(void *context, u8 event_code) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci pr_err("unaffiliated event not implemented yet\n"); 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic void qedr_affiliated_event(void *context, u8 e_code, void *fw_handle) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci#define EVENT_TYPE_NOT_DEFINED 0 6768c2ecf20Sopenharmony_ci#define EVENT_TYPE_CQ 1 6778c2ecf20Sopenharmony_ci#define EVENT_TYPE_QP 2 6788c2ecf20Sopenharmony_ci#define EVENT_TYPE_SRQ 3 6798c2ecf20Sopenharmony_ci struct qedr_dev *dev = (struct qedr_dev *)context; 6808c2ecf20Sopenharmony_ci struct regpair *async_handle = (struct regpair *)fw_handle; 6818c2ecf20Sopenharmony_ci u64 roce_handle64 = ((u64) async_handle->hi << 32) + async_handle->lo; 6828c2ecf20Sopenharmony_ci u8 event_type = EVENT_TYPE_NOT_DEFINED; 6838c2ecf20Sopenharmony_ci struct ib_event event; 6848c2ecf20Sopenharmony_ci struct ib_srq *ibsrq; 6858c2ecf20Sopenharmony_ci struct qedr_srq *srq; 6868c2ecf20Sopenharmony_ci unsigned long flags; 6878c2ecf20Sopenharmony_ci struct ib_cq *ibcq; 6888c2ecf20Sopenharmony_ci struct ib_qp *ibqp; 6898c2ecf20Sopenharmony_ci struct qedr_cq *cq; 6908c2ecf20Sopenharmony_ci struct qedr_qp *qp; 6918c2ecf20Sopenharmony_ci u16 srq_id; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (IS_ROCE(dev)) { 6948c2ecf20Sopenharmony_ci switch (e_code) { 6958c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_CQ_OVERFLOW_ERR: 6968c2ecf20Sopenharmony_ci event.event = IB_EVENT_CQ_ERR; 6978c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_CQ; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_SQ_DRAINED: 7008c2ecf20Sopenharmony_ci event.event = IB_EVENT_SQ_DRAINED; 7018c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_QP; 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_QP_CATASTROPHIC_ERR: 7048c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_FATAL; 7058c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_QP; 7068c2ecf20Sopenharmony_ci break; 7078c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_LOCAL_INVALID_REQUEST_ERR: 7088c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_REQ_ERR; 7098c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_QP; 7108c2ecf20Sopenharmony_ci break; 7118c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_LOCAL_ACCESS_ERR: 7128c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_ACCESS_ERR; 7138c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_QP; 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_SRQ_LIMIT: 7168c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_LIMIT_REACHED; 7178c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_SRQ; 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_SRQ_EMPTY: 7208c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_ERR; 7218c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_SRQ; 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_XRC_DOMAIN_ERR: 7248c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_ACCESS_ERR; 7258c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_QP; 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_INVALID_XRCETH_ERR: 7288c2ecf20Sopenharmony_ci event.event = IB_EVENT_QP_ACCESS_ERR; 7298c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_QP; 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci case ROCE_ASYNC_EVENT_XRC_SRQ_CATASTROPHIC_ERR: 7328c2ecf20Sopenharmony_ci event.event = IB_EVENT_CQ_ERR; 7338c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_CQ; 7348c2ecf20Sopenharmony_ci break; 7358c2ecf20Sopenharmony_ci default: 7368c2ecf20Sopenharmony_ci DP_ERR(dev, "unsupported event %d on handle=%llx\n", 7378c2ecf20Sopenharmony_ci e_code, roce_handle64); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci switch (e_code) { 7418c2ecf20Sopenharmony_ci case QED_IWARP_EVENT_SRQ_LIMIT: 7428c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_LIMIT_REACHED; 7438c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_SRQ; 7448c2ecf20Sopenharmony_ci break; 7458c2ecf20Sopenharmony_ci case QED_IWARP_EVENT_SRQ_EMPTY: 7468c2ecf20Sopenharmony_ci event.event = IB_EVENT_SRQ_ERR; 7478c2ecf20Sopenharmony_ci event_type = EVENT_TYPE_SRQ; 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci default: 7508c2ecf20Sopenharmony_ci DP_ERR(dev, "unsupported event %d on handle=%llx\n", e_code, 7518c2ecf20Sopenharmony_ci roce_handle64); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci switch (event_type) { 7558c2ecf20Sopenharmony_ci case EVENT_TYPE_CQ: 7568c2ecf20Sopenharmony_ci cq = (struct qedr_cq *)(uintptr_t)roce_handle64; 7578c2ecf20Sopenharmony_ci if (cq) { 7588c2ecf20Sopenharmony_ci ibcq = &cq->ibcq; 7598c2ecf20Sopenharmony_ci if (ibcq->event_handler) { 7608c2ecf20Sopenharmony_ci event.device = ibcq->device; 7618c2ecf20Sopenharmony_ci event.element.cq = ibcq; 7628c2ecf20Sopenharmony_ci ibcq->event_handler(&event, ibcq->cq_context); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci } else { 7658c2ecf20Sopenharmony_ci WARN(1, 7668c2ecf20Sopenharmony_ci "Error: CQ event with NULL pointer ibcq. Handle=%llx\n", 7678c2ecf20Sopenharmony_ci roce_handle64); 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci DP_ERR(dev, "CQ event %d on handle %p\n", e_code, cq); 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci case EVENT_TYPE_QP: 7728c2ecf20Sopenharmony_ci qp = (struct qedr_qp *)(uintptr_t)roce_handle64; 7738c2ecf20Sopenharmony_ci if (qp) { 7748c2ecf20Sopenharmony_ci ibqp = &qp->ibqp; 7758c2ecf20Sopenharmony_ci if (ibqp->event_handler) { 7768c2ecf20Sopenharmony_ci event.device = ibqp->device; 7778c2ecf20Sopenharmony_ci event.element.qp = ibqp; 7788c2ecf20Sopenharmony_ci ibqp->event_handler(&event, ibqp->qp_context); 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci } else { 7818c2ecf20Sopenharmony_ci WARN(1, 7828c2ecf20Sopenharmony_ci "Error: QP event with NULL pointer ibqp. Handle=%llx\n", 7838c2ecf20Sopenharmony_ci roce_handle64); 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci DP_ERR(dev, "QP event %d on handle %p\n", e_code, qp); 7868c2ecf20Sopenharmony_ci break; 7878c2ecf20Sopenharmony_ci case EVENT_TYPE_SRQ: 7888c2ecf20Sopenharmony_ci srq_id = (u16)roce_handle64; 7898c2ecf20Sopenharmony_ci xa_lock_irqsave(&dev->srqs, flags); 7908c2ecf20Sopenharmony_ci srq = xa_load(&dev->srqs, srq_id); 7918c2ecf20Sopenharmony_ci if (srq) { 7928c2ecf20Sopenharmony_ci ibsrq = &srq->ibsrq; 7938c2ecf20Sopenharmony_ci if (ibsrq->event_handler) { 7948c2ecf20Sopenharmony_ci event.device = ibsrq->device; 7958c2ecf20Sopenharmony_ci event.element.srq = ibsrq; 7968c2ecf20Sopenharmony_ci ibsrq->event_handler(&event, 7978c2ecf20Sopenharmony_ci ibsrq->srq_context); 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci } else { 8008c2ecf20Sopenharmony_ci DP_NOTICE(dev, 8018c2ecf20Sopenharmony_ci "SRQ event with NULL pointer ibsrq. Handle=%llx\n", 8028c2ecf20Sopenharmony_ci roce_handle64); 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci xa_unlock_irqrestore(&dev->srqs, flags); 8058c2ecf20Sopenharmony_ci DP_NOTICE(dev, "SRQ event %d on handle %p\n", e_code, srq); 8068c2ecf20Sopenharmony_ci default: 8078c2ecf20Sopenharmony_ci break; 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int qedr_init_hw(struct qedr_dev *dev) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct qed_rdma_add_user_out_params out_params; 8148c2ecf20Sopenharmony_ci struct qed_rdma_start_in_params *in_params; 8158c2ecf20Sopenharmony_ci struct qed_rdma_cnq_params *cur_pbl; 8168c2ecf20Sopenharmony_ci struct qed_rdma_events events; 8178c2ecf20Sopenharmony_ci dma_addr_t p_phys_table; 8188c2ecf20Sopenharmony_ci u32 page_cnt; 8198c2ecf20Sopenharmony_ci int rc = 0; 8208c2ecf20Sopenharmony_ci int i; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci in_params = kzalloc(sizeof(*in_params), GFP_KERNEL); 8238c2ecf20Sopenharmony_ci if (!in_params) { 8248c2ecf20Sopenharmony_ci rc = -ENOMEM; 8258c2ecf20Sopenharmony_ci goto out; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci in_params->desired_cnq = dev->num_cnq; 8298c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_cnq; i++) { 8308c2ecf20Sopenharmony_ci cur_pbl = &in_params->cnq_pbl_list[i]; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci page_cnt = qed_chain_get_page_cnt(&dev->cnq_array[i].pbl); 8338c2ecf20Sopenharmony_ci cur_pbl->num_pbl_pages = page_cnt; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci p_phys_table = qed_chain_get_pbl_phys(&dev->cnq_array[i].pbl); 8368c2ecf20Sopenharmony_ci cur_pbl->pbl_ptr = (u64)p_phys_table; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci events.affiliated_event = qedr_affiliated_event; 8408c2ecf20Sopenharmony_ci events.unaffiliated_event = qedr_unaffiliated_event; 8418c2ecf20Sopenharmony_ci events.context = dev; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci in_params->events = &events; 8448c2ecf20Sopenharmony_ci in_params->cq_mode = QED_RDMA_CQ_MODE_32_BITS; 8458c2ecf20Sopenharmony_ci in_params->max_mtu = dev->ndev->mtu; 8468c2ecf20Sopenharmony_ci dev->iwarp_max_mtu = dev->ndev->mtu; 8478c2ecf20Sopenharmony_ci ether_addr_copy(&in_params->mac_addr[0], dev->ndev->dev_addr); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci rc = dev->ops->rdma_init(dev->cdev, in_params); 8508c2ecf20Sopenharmony_ci if (rc) 8518c2ecf20Sopenharmony_ci goto out; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci rc = dev->ops->rdma_add_user(dev->rdma_ctx, &out_params); 8548c2ecf20Sopenharmony_ci if (rc) 8558c2ecf20Sopenharmony_ci goto out; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci dev->db_addr = out_params.dpi_addr; 8588c2ecf20Sopenharmony_ci dev->db_phys_addr = out_params.dpi_phys_addr; 8598c2ecf20Sopenharmony_ci dev->db_size = out_params.dpi_size; 8608c2ecf20Sopenharmony_ci dev->dpi = out_params.dpi; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci rc = qedr_set_device_attr(dev); 8638c2ecf20Sopenharmony_ciout: 8648c2ecf20Sopenharmony_ci kfree(in_params); 8658c2ecf20Sopenharmony_ci if (rc) 8668c2ecf20Sopenharmony_ci DP_ERR(dev, "Init HW Failed rc = %d\n", rc); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci return rc; 8698c2ecf20Sopenharmony_ci} 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_cistatic void qedr_stop_hw(struct qedr_dev *dev) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci dev->ops->rdma_remove_user(dev->rdma_ctx, dev->dpi); 8748c2ecf20Sopenharmony_ci dev->ops->rdma_stop(dev->rdma_ctx); 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, 8788c2ecf20Sopenharmony_ci struct net_device *ndev) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct qed_dev_rdma_info dev_info; 8818c2ecf20Sopenharmony_ci struct qedr_dev *dev; 8828c2ecf20Sopenharmony_ci int rc = 0; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci dev = ib_alloc_device(qedr_dev, ibdev); 8858c2ecf20Sopenharmony_ci if (!dev) { 8868c2ecf20Sopenharmony_ci pr_err("Unable to allocate ib device\n"); 8878c2ecf20Sopenharmony_ci return NULL; 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "qedr add device called\n"); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci dev->pdev = pdev; 8938c2ecf20Sopenharmony_ci dev->ndev = ndev; 8948c2ecf20Sopenharmony_ci dev->cdev = cdev; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci qed_ops = qed_get_rdma_ops(); 8978c2ecf20Sopenharmony_ci if (!qed_ops) { 8988c2ecf20Sopenharmony_ci DP_ERR(dev, "Failed to get qed roce operations\n"); 8998c2ecf20Sopenharmony_ci goto init_err; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci dev->ops = qed_ops; 9038c2ecf20Sopenharmony_ci rc = qed_ops->fill_dev_info(cdev, &dev_info); 9048c2ecf20Sopenharmony_ci if (rc) 9058c2ecf20Sopenharmony_ci goto init_err; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci dev->user_dpm_enabled = dev_info.user_dpm_enabled; 9088c2ecf20Sopenharmony_ci dev->rdma_type = dev_info.rdma_type; 9098c2ecf20Sopenharmony_ci dev->num_hwfns = dev_info.common.num_hwfns; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (IS_IWARP(dev) && QEDR_IS_CMT(dev)) { 9128c2ecf20Sopenharmony_ci rc = dev->ops->iwarp_set_engine_affin(cdev, false); 9138c2ecf20Sopenharmony_ci if (rc) { 9148c2ecf20Sopenharmony_ci DP_ERR(dev, "iWARP is disabled over a 100g device Enabling it may impact L2 performance. To enable it run devlink dev param set <dev> name iwarp_cmt value true cmode runtime\n"); 9158c2ecf20Sopenharmony_ci goto init_err; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci dev->affin_hwfn_idx = dev->ops->common->get_affin_hwfn_idx(cdev); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci dev->rdma_ctx = dev->ops->rdma_get_rdma_ctx(cdev); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev); 9238c2ecf20Sopenharmony_ci if (!dev->num_cnq) { 9248c2ecf20Sopenharmony_ci DP_ERR(dev, "Failed. At least one CNQ is required.\n"); 9258c2ecf20Sopenharmony_ci rc = -ENOMEM; 9268c2ecf20Sopenharmony_ci goto init_err; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci dev->wq_multiplier = QEDR_WQ_MULTIPLIER_DFT; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci qedr_pci_set_atomic(dev, pdev); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci rc = qedr_alloc_resources(dev); 9348c2ecf20Sopenharmony_ci if (rc) 9358c2ecf20Sopenharmony_ci goto init_err; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci rc = qedr_init_hw(dev); 9388c2ecf20Sopenharmony_ci if (rc) 9398c2ecf20Sopenharmony_ci goto alloc_err; 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci rc = qedr_setup_irqs(dev); 9428c2ecf20Sopenharmony_ci if (rc) 9438c2ecf20Sopenharmony_ci goto irq_err; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci rc = qedr_register_device(dev); 9468c2ecf20Sopenharmony_ci if (rc) { 9478c2ecf20Sopenharmony_ci DP_ERR(dev, "Unable to allocate register device\n"); 9488c2ecf20Sopenharmony_ci goto reg_err; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) 9528c2ecf20Sopenharmony_ci qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n"); 9558c2ecf20Sopenharmony_ci return dev; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cireg_err: 9588c2ecf20Sopenharmony_ci qedr_sync_free_irqs(dev); 9598c2ecf20Sopenharmony_ciirq_err: 9608c2ecf20Sopenharmony_ci qedr_stop_hw(dev); 9618c2ecf20Sopenharmony_cialloc_err: 9628c2ecf20Sopenharmony_ci qedr_free_resources(dev); 9638c2ecf20Sopenharmony_ciinit_err: 9648c2ecf20Sopenharmony_ci ib_dealloc_device(&dev->ibdev); 9658c2ecf20Sopenharmony_ci DP_ERR(dev, "qedr driver load failed rc=%d\n", rc); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return NULL; 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic void qedr_remove(struct qedr_dev *dev) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci /* First unregister with stack to stop all the active traffic 9738c2ecf20Sopenharmony_ci * of the registered clients. 9748c2ecf20Sopenharmony_ci */ 9758c2ecf20Sopenharmony_ci ib_unregister_device(&dev->ibdev); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci qedr_stop_hw(dev); 9788c2ecf20Sopenharmony_ci qedr_sync_free_irqs(dev); 9798c2ecf20Sopenharmony_ci qedr_free_resources(dev); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (IS_IWARP(dev) && QEDR_IS_CMT(dev)) 9828c2ecf20Sopenharmony_ci dev->ops->iwarp_set_engine_affin(dev->cdev, true); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci ib_dealloc_device(&dev->ibdev); 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic void qedr_close(struct qedr_dev *dev) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci if (test_and_clear_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) 9908c2ecf20Sopenharmony_ci qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ERR); 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic void qedr_shutdown(struct qedr_dev *dev) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci qedr_close(dev); 9968c2ecf20Sopenharmony_ci qedr_remove(dev); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic void qedr_open(struct qedr_dev *dev) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) 10028c2ecf20Sopenharmony_ci qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic void qedr_mac_address_change(struct qedr_dev *dev) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci union ib_gid *sgid = &dev->sgid_tbl[0]; 10088c2ecf20Sopenharmony_ci u8 guid[8], mac_addr[6]; 10098c2ecf20Sopenharmony_ci int rc; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* Update SGID */ 10128c2ecf20Sopenharmony_ci ether_addr_copy(&mac_addr[0], dev->ndev->dev_addr); 10138c2ecf20Sopenharmony_ci guid[0] = mac_addr[0] ^ 2; 10148c2ecf20Sopenharmony_ci guid[1] = mac_addr[1]; 10158c2ecf20Sopenharmony_ci guid[2] = mac_addr[2]; 10168c2ecf20Sopenharmony_ci guid[3] = 0xff; 10178c2ecf20Sopenharmony_ci guid[4] = 0xfe; 10188c2ecf20Sopenharmony_ci guid[5] = mac_addr[3]; 10198c2ecf20Sopenharmony_ci guid[6] = mac_addr[4]; 10208c2ecf20Sopenharmony_ci guid[7] = mac_addr[5]; 10218c2ecf20Sopenharmony_ci sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); 10228c2ecf20Sopenharmony_ci memcpy(&sgid->raw[8], guid, sizeof(guid)); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* Update LL2 */ 10258c2ecf20Sopenharmony_ci rc = dev->ops->ll2_set_mac_filter(dev->cdev, 10268c2ecf20Sopenharmony_ci dev->gsi_ll2_mac_address, 10278c2ecf20Sopenharmony_ci dev->ndev->dev_addr); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_GID_CHANGE); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (rc) 10348c2ecf20Sopenharmony_ci DP_ERR(dev, "Error updating mac filter\n"); 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci/* event handling via NIC driver ensures that all the NIC specific 10388c2ecf20Sopenharmony_ci * initialization done before RoCE driver notifies 10398c2ecf20Sopenharmony_ci * event to stack. 10408c2ecf20Sopenharmony_ci */ 10418c2ecf20Sopenharmony_cistatic void qedr_notify(struct qedr_dev *dev, enum qede_rdma_event event) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci switch (event) { 10448c2ecf20Sopenharmony_ci case QEDE_UP: 10458c2ecf20Sopenharmony_ci qedr_open(dev); 10468c2ecf20Sopenharmony_ci break; 10478c2ecf20Sopenharmony_ci case QEDE_DOWN: 10488c2ecf20Sopenharmony_ci qedr_close(dev); 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci case QEDE_CLOSE: 10518c2ecf20Sopenharmony_ci qedr_shutdown(dev); 10528c2ecf20Sopenharmony_ci break; 10538c2ecf20Sopenharmony_ci case QEDE_CHANGE_ADDR: 10548c2ecf20Sopenharmony_ci qedr_mac_address_change(dev); 10558c2ecf20Sopenharmony_ci break; 10568c2ecf20Sopenharmony_ci case QEDE_CHANGE_MTU: 10578c2ecf20Sopenharmony_ci if (rdma_protocol_iwarp(&dev->ibdev, 1)) 10588c2ecf20Sopenharmony_ci if (dev->ndev->mtu != dev->iwarp_max_mtu) 10598c2ecf20Sopenharmony_ci DP_NOTICE(dev, 10608c2ecf20Sopenharmony_ci "Mtu was changed from %d to %d. This will not take affect for iWARP until qedr is reloaded\n", 10618c2ecf20Sopenharmony_ci dev->iwarp_max_mtu, dev->ndev->mtu); 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci default: 10648c2ecf20Sopenharmony_ci pr_err("Event not supported\n"); 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci} 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_cistatic struct qedr_driver qedr_drv = { 10698c2ecf20Sopenharmony_ci .name = "qedr_driver", 10708c2ecf20Sopenharmony_ci .add = qedr_add, 10718c2ecf20Sopenharmony_ci .remove = qedr_remove, 10728c2ecf20Sopenharmony_ci .notify = qedr_notify, 10738c2ecf20Sopenharmony_ci}; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cistatic int __init qedr_init_module(void) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci return qede_rdma_register_driver(&qedr_drv); 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic void __exit qedr_exit_module(void) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci qede_rdma_unregister_driver(&qedr_drv); 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cimodule_init(qedr_init_module); 10868c2ecf20Sopenharmony_cimodule_exit(qedr_exit_module); 1087