18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 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 338c2ecf20Sopenharmony_ci#include <rdma/ib_mad.h> 348c2ecf20Sopenharmony_ci#include <rdma/ib_smi.h> 358c2ecf20Sopenharmony_ci#include <rdma/ib_sa.h> 368c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <linux/random.h> 398c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h> 408c2ecf20Sopenharmony_ci#include <linux/gfp.h> 418c2ecf20Sopenharmony_ci#include <rdma/ib_pma.h> 428c2ecf20Sopenharmony_ci#include <linux/ip.h> 438c2ecf20Sopenharmony_ci#include <net/ipv6.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include <linux/mlx4/driver.h> 468c2ecf20Sopenharmony_ci#include "mlx4_ib.h" 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum { 498c2ecf20Sopenharmony_ci MLX4_IB_VENDOR_CLASS1 = 0x9, 508c2ecf20Sopenharmony_ci MLX4_IB_VENDOR_CLASS2 = 0xa 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define MLX4_TUN_SEND_WRID_SHIFT 34 548c2ecf20Sopenharmony_ci#define MLX4_TUN_QPN_SHIFT 32 558c2ecf20Sopenharmony_ci#define MLX4_TUN_WRID_RECV (((u64) 1) << MLX4_TUN_SEND_WRID_SHIFT) 568c2ecf20Sopenharmony_ci#define MLX4_TUN_SET_WRID_QPN(a) (((u64) ((a) & 0x3)) << MLX4_TUN_QPN_SHIFT) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define MLX4_TUN_IS_RECV(a) (((a) >> MLX4_TUN_SEND_WRID_SHIFT) & 0x1) 598c2ecf20Sopenharmony_ci#define MLX4_TUN_WRID_QPN(a) (((a) >> MLX4_TUN_QPN_SHIFT) & 0x3) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Port mgmt change event handling */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define GET_BLK_PTR_FROM_EQE(eqe) be32_to_cpu(eqe->event.port_mgmt_change.params.tbl_change_info.block_ptr) 648c2ecf20Sopenharmony_ci#define GET_MASK_FROM_EQE(eqe) be32_to_cpu(eqe->event.port_mgmt_change.params.tbl_change_info.tbl_entries_mask) 658c2ecf20Sopenharmony_ci#define NUM_IDX_IN_PKEY_TBL_BLK 32 668c2ecf20Sopenharmony_ci#define GUID_TBL_ENTRY_SIZE 8 /* size in bytes */ 678c2ecf20Sopenharmony_ci#define GUID_TBL_BLK_NUM_ENTRIES 8 688c2ecf20Sopenharmony_ci#define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistruct mlx4_mad_rcv_buf { 718c2ecf20Sopenharmony_ci struct ib_grh grh; 728c2ecf20Sopenharmony_ci u8 payload[256]; 738c2ecf20Sopenharmony_ci} __packed; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct mlx4_mad_snd_buf { 768c2ecf20Sopenharmony_ci u8 payload[256]; 778c2ecf20Sopenharmony_ci} __packed; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistruct mlx4_tunnel_mad { 808c2ecf20Sopenharmony_ci struct ib_grh grh; 818c2ecf20Sopenharmony_ci struct mlx4_ib_tunnel_header hdr; 828c2ecf20Sopenharmony_ci struct ib_mad mad; 838c2ecf20Sopenharmony_ci} __packed; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct mlx4_rcv_tunnel_mad { 868c2ecf20Sopenharmony_ci struct mlx4_rcv_tunnel_hdr hdr; 878c2ecf20Sopenharmony_ci struct ib_grh grh; 888c2ecf20Sopenharmony_ci struct ib_mad mad; 898c2ecf20Sopenharmony_ci} __packed; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void handle_client_rereg_event(struct mlx4_ib_dev *dev, u8 port_num); 928c2ecf20Sopenharmony_cistatic void handle_lid_change_event(struct mlx4_ib_dev *dev, u8 port_num); 938c2ecf20Sopenharmony_cistatic void __propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, 948c2ecf20Sopenharmony_ci int block, u32 change_bitmap); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci__be64 mlx4_ib_gen_node_guid(void) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci#define NODE_GUID_HI ((u64) (((u64)IB_OPENIB_OUI) << 40)) 998c2ecf20Sopenharmony_ci return cpu_to_be64(NODE_GUID_HI | prandom_u32()); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci__be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return cpu_to_be64(atomic_inc_return(&ctx->tid)) | 1058c2ecf20Sopenharmony_ci cpu_to_be64(0xff00000000000000LL); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciint mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int mad_ifc_flags, 1098c2ecf20Sopenharmony_ci int port, const struct ib_wc *in_wc, 1108c2ecf20Sopenharmony_ci const struct ib_grh *in_grh, 1118c2ecf20Sopenharmony_ci const void *in_mad, void *response_mad) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 1148c2ecf20Sopenharmony_ci void *inbox; 1158c2ecf20Sopenharmony_ci int err; 1168c2ecf20Sopenharmony_ci u32 in_modifier = port; 1178c2ecf20Sopenharmony_ci u8 op_modifier = 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci inmailbox = mlx4_alloc_cmd_mailbox(dev->dev); 1208c2ecf20Sopenharmony_ci if (IS_ERR(inmailbox)) 1218c2ecf20Sopenharmony_ci return PTR_ERR(inmailbox); 1228c2ecf20Sopenharmony_ci inbox = inmailbox->buf; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci outmailbox = mlx4_alloc_cmd_mailbox(dev->dev); 1258c2ecf20Sopenharmony_ci if (IS_ERR(outmailbox)) { 1268c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev->dev, inmailbox); 1278c2ecf20Sopenharmony_ci return PTR_ERR(outmailbox); 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci memcpy(inbox, in_mad, 256); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* 1338c2ecf20Sopenharmony_ci * Key check traps can't be generated unless we have in_wc to 1348c2ecf20Sopenharmony_ci * tell us where to send the trap. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci if ((mad_ifc_flags & MLX4_MAD_IFC_IGNORE_MKEY) || !in_wc) 1378c2ecf20Sopenharmony_ci op_modifier |= 0x1; 1388c2ecf20Sopenharmony_ci if ((mad_ifc_flags & MLX4_MAD_IFC_IGNORE_BKEY) || !in_wc) 1398c2ecf20Sopenharmony_ci op_modifier |= 0x2; 1408c2ecf20Sopenharmony_ci if (mlx4_is_mfunc(dev->dev) && 1418c2ecf20Sopenharmony_ci (mad_ifc_flags & MLX4_MAD_IFC_NET_VIEW || in_wc)) 1428c2ecf20Sopenharmony_ci op_modifier |= 0x8; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (in_wc) { 1458c2ecf20Sopenharmony_ci struct { 1468c2ecf20Sopenharmony_ci __be32 my_qpn; 1478c2ecf20Sopenharmony_ci u32 reserved1; 1488c2ecf20Sopenharmony_ci __be32 rqpn; 1498c2ecf20Sopenharmony_ci u8 sl; 1508c2ecf20Sopenharmony_ci u8 g_path; 1518c2ecf20Sopenharmony_ci u16 reserved2[2]; 1528c2ecf20Sopenharmony_ci __be16 pkey; 1538c2ecf20Sopenharmony_ci u32 reserved3[11]; 1548c2ecf20Sopenharmony_ci u8 grh[40]; 1558c2ecf20Sopenharmony_ci } *ext_info; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci memset(inbox + 256, 0, 256); 1588c2ecf20Sopenharmony_ci ext_info = inbox + 256; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num); 1618c2ecf20Sopenharmony_ci ext_info->rqpn = cpu_to_be32(in_wc->src_qp); 1628c2ecf20Sopenharmony_ci ext_info->sl = in_wc->sl << 4; 1638c2ecf20Sopenharmony_ci ext_info->g_path = in_wc->dlid_path_bits | 1648c2ecf20Sopenharmony_ci (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0); 1658c2ecf20Sopenharmony_ci ext_info->pkey = cpu_to_be16(in_wc->pkey_index); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (in_grh) 1688c2ecf20Sopenharmony_ci memcpy(ext_info->grh, in_grh, 40); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci op_modifier |= 0x4; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci in_modifier |= ib_lid_cpu16(in_wc->slid) << 16; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma, in_modifier, 1768c2ecf20Sopenharmony_ci mlx4_is_master(dev->dev) ? (op_modifier & ~0x8) : op_modifier, 1778c2ecf20Sopenharmony_ci MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 1788c2ecf20Sopenharmony_ci (op_modifier & 0x8) ? MLX4_CMD_NATIVE : MLX4_CMD_WRAPPED); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (!err) 1818c2ecf20Sopenharmony_ci memcpy(response_mad, outmailbox->buf, 256); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev->dev, inmailbox); 1848c2ecf20Sopenharmony_ci mlx4_free_cmd_mailbox(dev->dev, outmailbox); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return err; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct ib_ah *new_ah; 1928c2ecf20Sopenharmony_ci struct rdma_ah_attr ah_attr; 1938c2ecf20Sopenharmony_ci unsigned long flags; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (!dev->send_agent[port_num - 1][0]) 1968c2ecf20Sopenharmony_ci return; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci memset(&ah_attr, 0, sizeof ah_attr); 1998c2ecf20Sopenharmony_ci ah_attr.type = rdma_ah_find_type(&dev->ib_dev, port_num); 2008c2ecf20Sopenharmony_ci rdma_ah_set_dlid(&ah_attr, lid); 2018c2ecf20Sopenharmony_ci rdma_ah_set_sl(&ah_attr, sl); 2028c2ecf20Sopenharmony_ci rdma_ah_set_port_num(&ah_attr, port_num); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci new_ah = rdma_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, 2058c2ecf20Sopenharmony_ci &ah_attr, 0); 2068c2ecf20Sopenharmony_ci if (IS_ERR(new_ah)) 2078c2ecf20Sopenharmony_ci return; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sm_lock, flags); 2108c2ecf20Sopenharmony_ci if (dev->sm_ah[port_num - 1]) 2118c2ecf20Sopenharmony_ci rdma_destroy_ah(dev->sm_ah[port_num - 1], 0); 2128c2ecf20Sopenharmony_ci dev->sm_ah[port_num - 1] = new_ah; 2138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sm_lock, flags); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * Snoop SM MADs for port info, GUID info, and P_Key table sets, so we can 2188c2ecf20Sopenharmony_ci * synthesize LID change, Client-Rereg, GID change, and P_Key change events. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_cistatic void smp_snoop(struct ib_device *ibdev, u8 port_num, const struct ib_mad *mad, 2218c2ecf20Sopenharmony_ci u16 prev_lid) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct ib_port_info *pinfo; 2248c2ecf20Sopenharmony_ci u16 lid; 2258c2ecf20Sopenharmony_ci __be16 *base; 2268c2ecf20Sopenharmony_ci u32 bn, pkey_change_bitmap; 2278c2ecf20Sopenharmony_ci int i; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 2318c2ecf20Sopenharmony_ci if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 2328c2ecf20Sopenharmony_ci mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 2338c2ecf20Sopenharmony_ci mad->mad_hdr.method == IB_MGMT_METHOD_SET) 2348c2ecf20Sopenharmony_ci switch (mad->mad_hdr.attr_id) { 2358c2ecf20Sopenharmony_ci case IB_SMP_ATTR_PORT_INFO: 2368c2ecf20Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data; 2398c2ecf20Sopenharmony_ci lid = be16_to_cpu(pinfo->lid); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci update_sm_ah(dev, port_num, 2428c2ecf20Sopenharmony_ci be16_to_cpu(pinfo->sm_lid), 2438c2ecf20Sopenharmony_ci pinfo->neighbormtu_mastersmsl & 0xf); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (pinfo->clientrereg_resv_subnetto & 0x80) 2468c2ecf20Sopenharmony_ci handle_client_rereg_event(dev, port_num); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (prev_lid != lid) 2498c2ecf20Sopenharmony_ci handle_lid_change_event(dev, port_num); 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci case IB_SMP_ATTR_PKEY_TABLE: 2538c2ecf20Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) 2548c2ecf20Sopenharmony_ci return; 2558c2ecf20Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev)) { 2568c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, 2578c2ecf20Sopenharmony_ci IB_EVENT_PKEY_CHANGE); 2588c2ecf20Sopenharmony_ci break; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* at this point, we are running in the master. 2628c2ecf20Sopenharmony_ci * Slaves do not receive SMPs. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci bn = be32_to_cpu(((struct ib_smp *)mad)->attr_mod) & 0xFFFF; 2658c2ecf20Sopenharmony_ci base = (__be16 *) &(((struct ib_smp *)mad)->data[0]); 2668c2ecf20Sopenharmony_ci pkey_change_bitmap = 0; 2678c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 2688c2ecf20Sopenharmony_ci pr_debug("PKEY[%d] = x%x\n", 2698c2ecf20Sopenharmony_ci i + bn*32, be16_to_cpu(base[i])); 2708c2ecf20Sopenharmony_ci if (be16_to_cpu(base[i]) != 2718c2ecf20Sopenharmony_ci dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32]) { 2728c2ecf20Sopenharmony_ci pkey_change_bitmap |= (1 << i); 2738c2ecf20Sopenharmony_ci dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32] = 2748c2ecf20Sopenharmony_ci be16_to_cpu(base[i]); 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci pr_debug("PKEY Change event: port=%d, " 2788c2ecf20Sopenharmony_ci "block=0x%x, change_bitmap=0x%x\n", 2798c2ecf20Sopenharmony_ci port_num, bn, pkey_change_bitmap); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (pkey_change_bitmap) { 2828c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, 2838c2ecf20Sopenharmony_ci IB_EVENT_PKEY_CHANGE); 2848c2ecf20Sopenharmony_ci if (!dev->sriov.is_going_down) 2858c2ecf20Sopenharmony_ci __propagate_pkey_ev(dev, port_num, bn, 2868c2ecf20Sopenharmony_ci pkey_change_bitmap); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci case IB_SMP_ATTR_GUID_INFO: 2918c2ecf20Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) 2928c2ecf20Sopenharmony_ci return; 2938c2ecf20Sopenharmony_ci /* paravirtualized master's guid is guid 0 -- does not change */ 2948c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 2958c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, 2968c2ecf20Sopenharmony_ci IB_EVENT_GID_CHANGE); 2978c2ecf20Sopenharmony_ci /*if master, notify relevant slaves*/ 2988c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev) && 2998c2ecf20Sopenharmony_ci !dev->sriov.is_going_down) { 3008c2ecf20Sopenharmony_ci bn = be32_to_cpu(((struct ib_smp *)mad)->attr_mod); 3018c2ecf20Sopenharmony_ci mlx4_ib_update_cache_on_guid_change(dev, bn, port_num, 3028c2ecf20Sopenharmony_ci (u8 *)(&((struct ib_smp *)mad)->data)); 3038c2ecf20Sopenharmony_ci mlx4_ib_notify_slaves_on_guid_change(dev, bn, port_num, 3048c2ecf20Sopenharmony_ci (u8 *)(&((struct ib_smp *)mad)->data)); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci case IB_SMP_ATTR_SL_TO_VL_TABLE: 3098c2ecf20Sopenharmony_ci /* cache sl to vl mapping changes for use in 3108c2ecf20Sopenharmony_ci * filling QP1 LRH VL field when sending packets 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV && 3138c2ecf20Sopenharmony_ci dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT) 3148c2ecf20Sopenharmony_ci return; 3158c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev->dev)) { 3168c2ecf20Sopenharmony_ci union sl2vl_tbl_to_u64 sl2vl64; 3178c2ecf20Sopenharmony_ci int jj; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci for (jj = 0; jj < 8; jj++) { 3208c2ecf20Sopenharmony_ci sl2vl64.sl8[jj] = ((struct ib_smp *)mad)->data[jj]; 3218c2ecf20Sopenharmony_ci pr_debug("port %u, sl2vl[%d] = %02x\n", 3228c2ecf20Sopenharmony_ci port_num, jj, sl2vl64.sl8[jj]); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci atomic64_set(&dev->sl2vl[port_num - 1], sl2vl64.sl64); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci default: 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic void __propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, 3348c2ecf20Sopenharmony_ci int block, u32 change_bitmap) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci int i, ix, slave, err; 3378c2ecf20Sopenharmony_ci int have_event = 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci for (slave = 0; slave < dev->dev->caps.sqp_demux; slave++) { 3408c2ecf20Sopenharmony_ci if (slave == mlx4_master_func_num(dev->dev)) 3418c2ecf20Sopenharmony_ci continue; 3428c2ecf20Sopenharmony_ci if (!mlx4_is_slave_active(dev->dev, slave)) 3438c2ecf20Sopenharmony_ci continue; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci have_event = 0; 3468c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 3478c2ecf20Sopenharmony_ci if (!(change_bitmap & (1 << i))) 3488c2ecf20Sopenharmony_ci continue; 3498c2ecf20Sopenharmony_ci for (ix = 0; 3508c2ecf20Sopenharmony_ci ix < dev->dev->caps.pkey_table_len[port_num]; ix++) { 3518c2ecf20Sopenharmony_ci if (dev->pkeys.virt2phys_pkey[slave][port_num - 1] 3528c2ecf20Sopenharmony_ci [ix] == i + 32 * block) { 3538c2ecf20Sopenharmony_ci err = mlx4_gen_pkey_eqe(dev->dev, slave, port_num); 3548c2ecf20Sopenharmony_ci pr_debug("propagate_pkey_ev: slave %d," 3558c2ecf20Sopenharmony_ci " port %d, ix %d (%d)\n", 3568c2ecf20Sopenharmony_ci slave, port_num, ix, err); 3578c2ecf20Sopenharmony_ci have_event = 1; 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci if (have_event) 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic void node_desc_override(struct ib_device *dev, 3688c2ecf20Sopenharmony_ci struct ib_mad *mad) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci unsigned long flags; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 3738c2ecf20Sopenharmony_ci mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 3748c2ecf20Sopenharmony_ci mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 3758c2ecf20Sopenharmony_ci mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 3768c2ecf20Sopenharmony_ci spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags); 3778c2ecf20Sopenharmony_ci memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 3788c2ecf20Sopenharmony_ci IB_DEVICE_NODE_DESC_MAX); 3798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, const struct ib_mad *mad) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 3868c2ecf20Sopenharmony_ci struct ib_mad_send_buf *send_buf; 3878c2ecf20Sopenharmony_ci struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 3888c2ecf20Sopenharmony_ci int ret; 3898c2ecf20Sopenharmony_ci unsigned long flags; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (agent) { 3928c2ecf20Sopenharmony_ci send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 3938c2ecf20Sopenharmony_ci IB_MGMT_MAD_DATA, GFP_ATOMIC, 3948c2ecf20Sopenharmony_ci IB_MGMT_BASE_VERSION); 3958c2ecf20Sopenharmony_ci if (IS_ERR(send_buf)) 3968c2ecf20Sopenharmony_ci return; 3978c2ecf20Sopenharmony_ci /* 3988c2ecf20Sopenharmony_ci * We rely here on the fact that MLX QPs don't use the 3998c2ecf20Sopenharmony_ci * address handle after the send is posted (this is 4008c2ecf20Sopenharmony_ci * wrong following the IB spec strictly, but we know 4018c2ecf20Sopenharmony_ci * it's OK for our devices). 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sm_lock, flags); 4048c2ecf20Sopenharmony_ci memcpy(send_buf->mad, mad, sizeof *mad); 4058c2ecf20Sopenharmony_ci if ((send_buf->ah = dev->sm_ah[port_num - 1])) 4068c2ecf20Sopenharmony_ci ret = ib_post_send_mad(send_buf, NULL); 4078c2ecf20Sopenharmony_ci else 4088c2ecf20Sopenharmony_ci ret = -EINVAL; 4098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sm_lock, flags); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (ret) 4128c2ecf20Sopenharmony_ci ib_free_send_mad(send_buf); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int mlx4_ib_demux_sa_handler(struct ib_device *ibdev, int port, int slave, 4178c2ecf20Sopenharmony_ci struct ib_sa_mad *sa_mad) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci int ret = 0; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* dispatch to different sa handlers */ 4228c2ecf20Sopenharmony_ci switch (be16_to_cpu(sa_mad->mad_hdr.attr_id)) { 4238c2ecf20Sopenharmony_ci case IB_SA_ATTR_MC_MEMBER_REC: 4248c2ecf20Sopenharmony_ci ret = mlx4_ib_mcg_demux_handler(ibdev, port, slave, sa_mad); 4258c2ecf20Sopenharmony_ci break; 4268c2ecf20Sopenharmony_ci default: 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci return ret; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciint mlx4_ib_find_real_gid(struct ib_device *ibdev, u8 port, __be64 guid) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 4358c2ecf20Sopenharmony_ci int i; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 4388c2ecf20Sopenharmony_ci if (dev->sriov.demux[port - 1].guid_cache[i] == guid) 4398c2ecf20Sopenharmony_ci return i; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci return -1; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int find_slave_port_pkey_ix(struct mlx4_ib_dev *dev, int slave, 4468c2ecf20Sopenharmony_ci u8 port, u16 pkey, u16 *ix) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int i, ret; 4498c2ecf20Sopenharmony_ci u8 unassigned_pkey_ix, pkey_ix, partial_ix = 0xFF; 4508c2ecf20Sopenharmony_ci u16 slot_pkey; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (slave == mlx4_master_func_num(dev->dev)) 4538c2ecf20Sopenharmony_ci return ib_find_cached_pkey(&dev->ib_dev, port, pkey, ix); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci unassigned_pkey_ix = dev->dev->phys_caps.pkey_phys_table_len[port] - 1; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.pkey_table_len[port]; i++) { 4588c2ecf20Sopenharmony_ci if (dev->pkeys.virt2phys_pkey[slave][port - 1][i] == unassigned_pkey_ix) 4598c2ecf20Sopenharmony_ci continue; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][i]; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ret = ib_get_cached_pkey(&dev->ib_dev, port, pkey_ix, &slot_pkey); 4648c2ecf20Sopenharmony_ci if (ret) 4658c2ecf20Sopenharmony_ci continue; 4668c2ecf20Sopenharmony_ci if ((slot_pkey & 0x7FFF) == (pkey & 0x7FFF)) { 4678c2ecf20Sopenharmony_ci if (slot_pkey & 0x8000) { 4688c2ecf20Sopenharmony_ci *ix = (u16) pkey_ix; 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci } else { 4718c2ecf20Sopenharmony_ci /* take first partial pkey index found */ 4728c2ecf20Sopenharmony_ci if (partial_ix == 0xFF) 4738c2ecf20Sopenharmony_ci partial_ix = pkey_ix; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (partial_ix < 0xFF) { 4798c2ecf20Sopenharmony_ci *ix = (u16) partial_ix; 4808c2ecf20Sopenharmony_ci return 0; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return -EINVAL; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int get_gids_from_l3_hdr(struct ib_grh *grh, union ib_gid *sgid, 4878c2ecf20Sopenharmony_ci union ib_gid *dgid) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci int version = ib_get_rdma_header_version((const union rdma_network_hdr *)grh); 4908c2ecf20Sopenharmony_ci enum rdma_network_type net_type; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (version == 4) 4938c2ecf20Sopenharmony_ci net_type = RDMA_NETWORK_IPV4; 4948c2ecf20Sopenharmony_ci else if (version == 6) 4958c2ecf20Sopenharmony_ci net_type = RDMA_NETWORK_IPV6; 4968c2ecf20Sopenharmony_ci else 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return ib_get_gids_from_rdma_hdr((union rdma_network_hdr *)grh, net_type, 5008c2ecf20Sopenharmony_ci sgid, dgid); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci int proxy_start = dev->dev->phys_caps.base_proxy_sqpn + 8 * slave; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return (qpn >= proxy_start && qpn <= proxy_start + 1); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ciint mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, 5118c2ecf20Sopenharmony_ci enum ib_qp_type dest_qpt, struct ib_wc *wc, 5128c2ecf20Sopenharmony_ci struct ib_grh *grh, struct ib_mad *mad) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct ib_sge list; 5158c2ecf20Sopenharmony_ci struct ib_ud_wr wr; 5168c2ecf20Sopenharmony_ci const struct ib_send_wr *bad_wr; 5178c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *tun_ctx; 5188c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 5198c2ecf20Sopenharmony_ci struct mlx4_rcv_tunnel_mad *tun_mad; 5208c2ecf20Sopenharmony_ci struct rdma_ah_attr attr; 5218c2ecf20Sopenharmony_ci struct ib_ah *ah; 5228c2ecf20Sopenharmony_ci struct ib_qp *src_qp = NULL; 5238c2ecf20Sopenharmony_ci unsigned tun_tx_ix = 0; 5248c2ecf20Sopenharmony_ci int dqpn; 5258c2ecf20Sopenharmony_ci int ret = 0; 5268c2ecf20Sopenharmony_ci u16 tun_pkey_ix; 5278c2ecf20Sopenharmony_ci u16 cached_pkey; 5288c2ecf20Sopenharmony_ci u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (dest_qpt > IB_QPT_GSI) { 5318c2ecf20Sopenharmony_ci pr_debug("dest_qpt (%d) > IB_QPT_GSI\n", dest_qpt); 5328c2ecf20Sopenharmony_ci return -EINVAL; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci tun_ctx = dev->sriov.demux[port-1].tun[slave]; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* check if proxy qp created */ 5388c2ecf20Sopenharmony_ci if (!tun_ctx || tun_ctx->state != DEMUX_PV_STATE_ACTIVE) 5398c2ecf20Sopenharmony_ci return -EAGAIN; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (!dest_qpt) 5428c2ecf20Sopenharmony_ci tun_qp = &tun_ctx->qp[0]; 5438c2ecf20Sopenharmony_ci else 5448c2ecf20Sopenharmony_ci tun_qp = &tun_ctx->qp[1]; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* compute P_Key index to put in tunnel header for slave */ 5478c2ecf20Sopenharmony_ci if (dest_qpt) { 5488c2ecf20Sopenharmony_ci u16 pkey_ix; 5498c2ecf20Sopenharmony_ci ret = ib_get_cached_pkey(&dev->ib_dev, port, wc->pkey_index, &cached_pkey); 5508c2ecf20Sopenharmony_ci if (ret) { 5518c2ecf20Sopenharmony_ci pr_debug("unable to get %s cached pkey for index %d, ret %d\n", 5528c2ecf20Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 5538c2ecf20Sopenharmony_ci wc->pkey_index, ret); 5548c2ecf20Sopenharmony_ci return -EINVAL; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci ret = find_slave_port_pkey_ix(dev, slave, port, cached_pkey, &pkey_ix); 5588c2ecf20Sopenharmony_ci if (ret) { 5598c2ecf20Sopenharmony_ci pr_debug("unable to get %s pkey ix for pkey 0x%x, ret %d\n", 5608c2ecf20Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 5618c2ecf20Sopenharmony_ci cached_pkey, ret); 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci tun_pkey_ix = pkey_ix; 5658c2ecf20Sopenharmony_ci } else 5668c2ecf20Sopenharmony_ci tun_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][0]; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci dqpn = dev->dev->phys_caps.base_proxy_sqpn + 8 * slave + port + (dest_qpt * 2) - 1; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* get tunnel tx data buf for slave */ 5718c2ecf20Sopenharmony_ci src_qp = tun_qp->qp; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* create ah. Just need an empty one with the port num for the post send. 5748c2ecf20Sopenharmony_ci * The driver will set the force loopback bit in post_send */ 5758c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof attr); 5768c2ecf20Sopenharmony_ci attr.type = rdma_ah_find_type(&dev->ib_dev, port); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci rdma_ah_set_port_num(&attr, port); 5798c2ecf20Sopenharmony_ci if (is_eth) { 5808c2ecf20Sopenharmony_ci union ib_gid sgid; 5818c2ecf20Sopenharmony_ci union ib_gid dgid; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (get_gids_from_l3_hdr(grh, &sgid, &dgid)) 5848c2ecf20Sopenharmony_ci return -EINVAL; 5858c2ecf20Sopenharmony_ci rdma_ah_set_grh(&attr, &dgid, 0, 0, 0, 0); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci ah = rdma_create_ah(tun_ctx->pd, &attr, 0); 5888c2ecf20Sopenharmony_ci if (IS_ERR(ah)) 5898c2ecf20Sopenharmony_ci return -ENOMEM; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* allocate tunnel tx buf after pass failure returns */ 5928c2ecf20Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 5938c2ecf20Sopenharmony_ci if (tun_qp->tx_ix_head - tun_qp->tx_ix_tail >= 5948c2ecf20Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)) 5958c2ecf20Sopenharmony_ci ret = -EAGAIN; 5968c2ecf20Sopenharmony_ci else 5978c2ecf20Sopenharmony_ci tun_tx_ix = (++tun_qp->tx_ix_head) & (MLX4_NUM_TUNNEL_BUFS - 1); 5988c2ecf20Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 5998c2ecf20Sopenharmony_ci if (ret) 6008c2ecf20Sopenharmony_ci goto end; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci tun_mad = (struct mlx4_rcv_tunnel_mad *) (tun_qp->tx_ring[tun_tx_ix].buf.addr); 6038c2ecf20Sopenharmony_ci if (tun_qp->tx_ring[tun_tx_ix].ah) 6048c2ecf20Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[tun_tx_ix].ah, 0); 6058c2ecf20Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].ah = ah; 6068c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(&dev->ib_dev, 6078c2ecf20Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].buf.map, 6088c2ecf20Sopenharmony_ci sizeof (struct mlx4_rcv_tunnel_mad), 6098c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* copy over to tunnel buffer */ 6128c2ecf20Sopenharmony_ci if (grh) 6138c2ecf20Sopenharmony_ci memcpy(&tun_mad->grh, grh, sizeof *grh); 6148c2ecf20Sopenharmony_ci memcpy(&tun_mad->mad, mad, sizeof *mad); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* adjust tunnel data */ 6178c2ecf20Sopenharmony_ci tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix); 6188c2ecf20Sopenharmony_ci tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF); 6198c2ecf20Sopenharmony_ci tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (is_eth) { 6228c2ecf20Sopenharmony_ci u16 vlan = 0; 6238c2ecf20Sopenharmony_ci if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan, 6248c2ecf20Sopenharmony_ci NULL)) { 6258c2ecf20Sopenharmony_ci /* VST mode */ 6268c2ecf20Sopenharmony_ci if (vlan != wc->vlan_id) 6278c2ecf20Sopenharmony_ci /* Packet vlan is not the VST-assigned vlan. 6288c2ecf20Sopenharmony_ci * Drop the packet. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci goto out; 6318c2ecf20Sopenharmony_ci else 6328c2ecf20Sopenharmony_ci /* Remove the vlan tag before forwarding 6338c2ecf20Sopenharmony_ci * the packet to the VF. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci vlan = 0xffff; 6368c2ecf20Sopenharmony_ci } else { 6378c2ecf20Sopenharmony_ci vlan = wc->vlan_id; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci tun_mad->hdr.sl_vid = cpu_to_be16(vlan); 6418c2ecf20Sopenharmony_ci memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4); 6428c2ecf20Sopenharmony_ci memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2); 6438c2ecf20Sopenharmony_ci } else { 6448c2ecf20Sopenharmony_ci tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12); 6458c2ecf20Sopenharmony_ci tun_mad->hdr.slid_mac_47_32 = ib_lid_be16(wc->slid); 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci ib_dma_sync_single_for_device(&dev->ib_dev, 6498c2ecf20Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].buf.map, 6508c2ecf20Sopenharmony_ci sizeof (struct mlx4_rcv_tunnel_mad), 6518c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci list.addr = tun_qp->tx_ring[tun_tx_ix].buf.map; 6548c2ecf20Sopenharmony_ci list.length = sizeof (struct mlx4_rcv_tunnel_mad); 6558c2ecf20Sopenharmony_ci list.lkey = tun_ctx->pd->local_dma_lkey; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci wr.ah = ah; 6588c2ecf20Sopenharmony_ci wr.port_num = port; 6598c2ecf20Sopenharmony_ci wr.remote_qkey = IB_QP_SET_QKEY; 6608c2ecf20Sopenharmony_ci wr.remote_qpn = dqpn; 6618c2ecf20Sopenharmony_ci wr.wr.next = NULL; 6628c2ecf20Sopenharmony_ci wr.wr.wr_id = ((u64) tun_tx_ix) | MLX4_TUN_SET_WRID_QPN(dest_qpt); 6638c2ecf20Sopenharmony_ci wr.wr.sg_list = &list; 6648c2ecf20Sopenharmony_ci wr.wr.num_sge = 1; 6658c2ecf20Sopenharmony_ci wr.wr.opcode = IB_WR_SEND; 6668c2ecf20Sopenharmony_ci wr.wr.send_flags = IB_SEND_SIGNALED; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci ret = ib_post_send(src_qp, &wr.wr, &bad_wr); 6698c2ecf20Sopenharmony_ci if (!ret) 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci out: 6728c2ecf20Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 6738c2ecf20Sopenharmony_ci tun_qp->tx_ix_tail++; 6748c2ecf20Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 6758c2ecf20Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].ah = NULL; 6768c2ecf20Sopenharmony_ciend: 6778c2ecf20Sopenharmony_ci rdma_destroy_ah(ah, 0); 6788c2ecf20Sopenharmony_ci return ret; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port, 6828c2ecf20Sopenharmony_ci struct ib_wc *wc, struct ib_grh *grh, 6838c2ecf20Sopenharmony_ci struct ib_mad *mad) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 6868c2ecf20Sopenharmony_ci int err, other_port; 6878c2ecf20Sopenharmony_ci int slave = -1; 6888c2ecf20Sopenharmony_ci u8 *slave_id; 6898c2ecf20Sopenharmony_ci int is_eth = 0; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) 6928c2ecf20Sopenharmony_ci is_eth = 0; 6938c2ecf20Sopenharmony_ci else 6948c2ecf20Sopenharmony_ci is_eth = 1; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (is_eth) { 6978c2ecf20Sopenharmony_ci union ib_gid dgid; 6988c2ecf20Sopenharmony_ci union ib_gid sgid; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (get_gids_from_l3_hdr(grh, &sgid, &dgid)) 7018c2ecf20Sopenharmony_ci return -EINVAL; 7028c2ecf20Sopenharmony_ci if (!(wc->wc_flags & IB_WC_GRH)) { 7038c2ecf20Sopenharmony_ci mlx4_ib_warn(ibdev, "RoCE grh not present.\n"); 7048c2ecf20Sopenharmony_ci return -EINVAL; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) { 7078c2ecf20Sopenharmony_ci mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n"); 7088c2ecf20Sopenharmony_ci return -EINVAL; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci err = mlx4_get_slave_from_roce_gid(dev->dev, port, dgid.raw, &slave); 7118c2ecf20Sopenharmony_ci if (err && mlx4_is_mf_bonded(dev->dev)) { 7128c2ecf20Sopenharmony_ci other_port = (port == 1) ? 2 : 1; 7138c2ecf20Sopenharmony_ci err = mlx4_get_slave_from_roce_gid(dev->dev, other_port, dgid.raw, &slave); 7148c2ecf20Sopenharmony_ci if (!err) { 7158c2ecf20Sopenharmony_ci port = other_port; 7168c2ecf20Sopenharmony_ci pr_debug("resolved slave %d from gid %pI6 wire port %d other %d\n", 7178c2ecf20Sopenharmony_ci slave, grh->dgid.raw, port, other_port); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci if (err) { 7218c2ecf20Sopenharmony_ci mlx4_ib_warn(ibdev, "failed matching grh\n"); 7228c2ecf20Sopenharmony_ci return -ENOENT; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci if (slave >= dev->dev->caps.sqp_demux) { 7258c2ecf20Sopenharmony_ci mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", 7268c2ecf20Sopenharmony_ci slave, dev->dev->caps.sqp_demux); 7278c2ecf20Sopenharmony_ci return -ENOENT; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (mlx4_ib_demux_cm_handler(ibdev, port, NULL, mad)) 7318c2ecf20Sopenharmony_ci return 0; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); 7348c2ecf20Sopenharmony_ci if (err) 7358c2ecf20Sopenharmony_ci pr_debug("failed sending %s to slave %d via tunnel qp (%d)\n", 7368c2ecf20Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 7378c2ecf20Sopenharmony_ci slave, err); 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Initially assume that this mad is for us */ 7428c2ecf20Sopenharmony_ci slave = mlx4_master_func_num(dev->dev); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* See if the slave id is encoded in a response mad */ 7458c2ecf20Sopenharmony_ci if (mad->mad_hdr.method & 0x80) { 7468c2ecf20Sopenharmony_ci slave_id = (u8 *) &mad->mad_hdr.tid; 7478c2ecf20Sopenharmony_ci slave = *slave_id; 7488c2ecf20Sopenharmony_ci if (slave != 255) /*255 indicates the dom0*/ 7498c2ecf20Sopenharmony_ci *slave_id = 0; /* remap tid */ 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* If a grh is present, we demux according to it */ 7538c2ecf20Sopenharmony_ci if (wc->wc_flags & IB_WC_GRH) { 7548c2ecf20Sopenharmony_ci if (grh->dgid.global.interface_id == 7558c2ecf20Sopenharmony_ci cpu_to_be64(IB_SA_WELL_KNOWN_GUID) && 7568c2ecf20Sopenharmony_ci grh->dgid.global.subnet_prefix == cpu_to_be64( 7578c2ecf20Sopenharmony_ci atomic64_read(&dev->sriov.demux[port - 1].subnet_prefix))) { 7588c2ecf20Sopenharmony_ci slave = 0; 7598c2ecf20Sopenharmony_ci } else { 7608c2ecf20Sopenharmony_ci slave = mlx4_ib_find_real_gid(ibdev, port, 7618c2ecf20Sopenharmony_ci grh->dgid.global.interface_id); 7628c2ecf20Sopenharmony_ci if (slave < 0) { 7638c2ecf20Sopenharmony_ci mlx4_ib_warn(ibdev, "failed matching grh\n"); 7648c2ecf20Sopenharmony_ci return -ENOENT; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci /* Class-specific handling */ 7698c2ecf20Sopenharmony_ci switch (mad->mad_hdr.mgmt_class) { 7708c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_SUBN_LID_ROUTED: 7718c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 7728c2ecf20Sopenharmony_ci /* 255 indicates the dom0 */ 7738c2ecf20Sopenharmony_ci if (slave != 255 && slave != mlx4_master_func_num(dev->dev)) { 7748c2ecf20Sopenharmony_ci if (!mlx4_vf_smi_enabled(dev->dev, slave, port)) 7758c2ecf20Sopenharmony_ci return -EPERM; 7768c2ecf20Sopenharmony_ci /* for a VF. drop unsolicited MADs */ 7778c2ecf20Sopenharmony_ci if (!(mad->mad_hdr.method & IB_MGMT_METHOD_RESP)) { 7788c2ecf20Sopenharmony_ci mlx4_ib_warn(ibdev, "demux QP0. rejecting unsolicited mad for slave %d class 0x%x, method 0x%x\n", 7798c2ecf20Sopenharmony_ci slave, mad->mad_hdr.mgmt_class, 7808c2ecf20Sopenharmony_ci mad->mad_hdr.method); 7818c2ecf20Sopenharmony_ci return -EINVAL; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_SUBN_ADM: 7868c2ecf20Sopenharmony_ci if (mlx4_ib_demux_sa_handler(ibdev, port, slave, 7878c2ecf20Sopenharmony_ci (struct ib_sa_mad *) mad)) 7888c2ecf20Sopenharmony_ci return 0; 7898c2ecf20Sopenharmony_ci break; 7908c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_CM: 7918c2ecf20Sopenharmony_ci if (mlx4_ib_demux_cm_handler(ibdev, port, &slave, mad)) 7928c2ecf20Sopenharmony_ci return 0; 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_DEVICE_MGMT: 7958c2ecf20Sopenharmony_ci if (mad->mad_hdr.method != IB_MGMT_METHOD_GET_RESP) 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci default: 7998c2ecf20Sopenharmony_ci /* Drop unsupported classes for slaves in tunnel mode */ 8008c2ecf20Sopenharmony_ci if (slave != mlx4_master_func_num(dev->dev)) { 8018c2ecf20Sopenharmony_ci pr_debug("dropping unsupported ingress mad from class:%d " 8028c2ecf20Sopenharmony_ci "for slave:%d\n", mad->mad_hdr.mgmt_class, slave); 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci /*make sure that no slave==255 was not handled yet.*/ 8078c2ecf20Sopenharmony_ci if (slave >= dev->dev->caps.sqp_demux) { 8088c2ecf20Sopenharmony_ci mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", 8098c2ecf20Sopenharmony_ci slave, dev->dev->caps.sqp_demux); 8108c2ecf20Sopenharmony_ci return -ENOENT; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); 8148c2ecf20Sopenharmony_ci if (err) 8158c2ecf20Sopenharmony_ci pr_debug("failed sending %s to slave %d via tunnel qp (%d)\n", 8168c2ecf20Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 8178c2ecf20Sopenharmony_ci slave, err); 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 8228c2ecf20Sopenharmony_ci const struct ib_wc *in_wc, const struct ib_grh *in_grh, 8238c2ecf20Sopenharmony_ci const struct ib_mad *in_mad, struct ib_mad *out_mad) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci u16 slid, prev_lid = 0; 8268c2ecf20Sopenharmony_ci int err; 8278c2ecf20Sopenharmony_ci struct ib_port_attr pattr; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci slid = in_wc ? ib_lid_cpu16(in_wc->slid) : be16_to_cpu(IB_LID_PERMISSIVE); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) { 8328c2ecf20Sopenharmony_ci forward_trap(to_mdev(ibdev), port_num, in_mad); 8338c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 8378c2ecf20Sopenharmony_ci in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 8388c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 8398c2ecf20Sopenharmony_ci in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 8408c2ecf20Sopenharmony_ci in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 8418c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * Don't process SMInfo queries -- the SMA can't handle them. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) 8478c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 8488c2ecf20Sopenharmony_ci } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 8498c2ecf20Sopenharmony_ci in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || 8508c2ecf20Sopenharmony_ci in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2 || 8518c2ecf20Sopenharmony_ci in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) { 8528c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 8538c2ecf20Sopenharmony_ci in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 8548c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 8558c2ecf20Sopenharmony_ci } else 8568c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 8598c2ecf20Sopenharmony_ci in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 8608c2ecf20Sopenharmony_ci in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && 8618c2ecf20Sopenharmony_ci in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 8628c2ecf20Sopenharmony_ci !ib_query_port(ibdev, port_num, &pattr)) 8638c2ecf20Sopenharmony_ci prev_lid = ib_lid_cpu16(pattr.lid); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci err = mlx4_MAD_IFC(to_mdev(ibdev), 8668c2ecf20Sopenharmony_ci (mad_flags & IB_MAD_IGNORE_MKEY ? MLX4_MAD_IFC_IGNORE_MKEY : 0) | 8678c2ecf20Sopenharmony_ci (mad_flags & IB_MAD_IGNORE_BKEY ? MLX4_MAD_IFC_IGNORE_BKEY : 0) | 8688c2ecf20Sopenharmony_ci MLX4_MAD_IFC_NET_VIEW, 8698c2ecf20Sopenharmony_ci port_num, in_wc, in_grh, in_mad, out_mad); 8708c2ecf20Sopenharmony_ci if (err) 8718c2ecf20Sopenharmony_ci return IB_MAD_RESULT_FAILURE; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (!out_mad->mad_hdr.status) { 8748c2ecf20Sopenharmony_ci smp_snoop(ibdev, port_num, in_mad, prev_lid); 8758c2ecf20Sopenharmony_ci /* slaves get node desc from FW */ 8768c2ecf20Sopenharmony_ci if (!mlx4_is_slave(to_mdev(ibdev)->dev)) 8778c2ecf20Sopenharmony_ci node_desc_override(ibdev, out_mad); 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci /* set return bit in status of directed route responses */ 8818c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 8828c2ecf20Sopenharmony_ci out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 8858c2ecf20Sopenharmony_ci /* no response for trap repress */ 8868c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic void edit_counter(struct mlx4_counter *cnt, void *counters, 8928c2ecf20Sopenharmony_ci __be16 attr_id) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci switch (attr_id) { 8958c2ecf20Sopenharmony_ci case IB_PMA_PORT_COUNTERS: 8968c2ecf20Sopenharmony_ci { 8978c2ecf20Sopenharmony_ci struct ib_pma_portcounters *pma_cnt = 8988c2ecf20Sopenharmony_ci (struct ib_pma_portcounters *)counters; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data, 9018c2ecf20Sopenharmony_ci (be64_to_cpu(cnt->tx_bytes) >> 2)); 9028c2ecf20Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data, 9038c2ecf20Sopenharmony_ci (be64_to_cpu(cnt->rx_bytes) >> 2)); 9048c2ecf20Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets, 9058c2ecf20Sopenharmony_ci be64_to_cpu(cnt->tx_frames)); 9068c2ecf20Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets, 9078c2ecf20Sopenharmony_ci be64_to_cpu(cnt->rx_frames)); 9088c2ecf20Sopenharmony_ci break; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci case IB_PMA_PORT_COUNTERS_EXT: 9118c2ecf20Sopenharmony_ci { 9128c2ecf20Sopenharmony_ci struct ib_pma_portcounters_ext *pma_cnt_ext = 9138c2ecf20Sopenharmony_ci (struct ib_pma_portcounters_ext *)counters; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci pma_cnt_ext->port_xmit_data = 9168c2ecf20Sopenharmony_ci cpu_to_be64(be64_to_cpu(cnt->tx_bytes) >> 2); 9178c2ecf20Sopenharmony_ci pma_cnt_ext->port_rcv_data = 9188c2ecf20Sopenharmony_ci cpu_to_be64(be64_to_cpu(cnt->rx_bytes) >> 2); 9198c2ecf20Sopenharmony_ci pma_cnt_ext->port_xmit_packets = cnt->tx_frames; 9208c2ecf20Sopenharmony_ci pma_cnt_ext->port_rcv_packets = cnt->rx_frames; 9218c2ecf20Sopenharmony_ci break; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic int iboe_process_mad_port_info(void *out_mad) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci struct ib_class_port_info cpi = {}; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci cpi.capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH; 9318c2ecf20Sopenharmony_ci memcpy(out_mad, &cpi, sizeof(cpi)); 9328c2ecf20Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 9368c2ecf20Sopenharmony_ci const struct ib_wc *in_wc, const struct ib_grh *in_grh, 9378c2ecf20Sopenharmony_ci const struct ib_mad *in_mad, struct ib_mad *out_mad) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci struct mlx4_counter counter_stats; 9408c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 9418c2ecf20Sopenharmony_ci struct counter_index *tmp_counter; 9428c2ecf20Sopenharmony_ci int err = IB_MAD_RESULT_FAILURE, stats_avail = 0; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT) 9458c2ecf20Sopenharmony_ci return -EINVAL; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO) 9488c2ecf20Sopenharmony_ci return iboe_process_mad_port_info((void *)(out_mad->data + 40)); 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci memset(&counter_stats, 0, sizeof(counter_stats)); 9518c2ecf20Sopenharmony_ci mutex_lock(&dev->counters_table[port_num - 1].mutex); 9528c2ecf20Sopenharmony_ci list_for_each_entry(tmp_counter, 9538c2ecf20Sopenharmony_ci &dev->counters_table[port_num - 1].counters_list, 9548c2ecf20Sopenharmony_ci list) { 9558c2ecf20Sopenharmony_ci err = mlx4_get_counter_stats(dev->dev, 9568c2ecf20Sopenharmony_ci tmp_counter->index, 9578c2ecf20Sopenharmony_ci &counter_stats, 0); 9588c2ecf20Sopenharmony_ci if (err) { 9598c2ecf20Sopenharmony_ci err = IB_MAD_RESULT_FAILURE; 9608c2ecf20Sopenharmony_ci stats_avail = 0; 9618c2ecf20Sopenharmony_ci break; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci stats_avail = 1; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci mutex_unlock(&dev->counters_table[port_num - 1].mutex); 9668c2ecf20Sopenharmony_ci if (stats_avail) { 9678c2ecf20Sopenharmony_ci switch (counter_stats.counter_mode & 0xf) { 9688c2ecf20Sopenharmony_ci case 0: 9698c2ecf20Sopenharmony_ci edit_counter(&counter_stats, 9708c2ecf20Sopenharmony_ci (void *)(out_mad->data + 40), 9718c2ecf20Sopenharmony_ci in_mad->mad_hdr.attr_id); 9728c2ecf20Sopenharmony_ci err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci default: 9758c2ecf20Sopenharmony_ci err = IB_MAD_RESULT_FAILURE; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return err; 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ciint mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 9838c2ecf20Sopenharmony_ci const struct ib_wc *in_wc, const struct ib_grh *in_grh, 9848c2ecf20Sopenharmony_ci const struct ib_mad *in, struct ib_mad *out, 9858c2ecf20Sopenharmony_ci size_t *out_mad_size, u16 *out_mad_pkey_index) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 9888c2ecf20Sopenharmony_ci enum rdma_link_layer link = rdma_port_get_link_layer(ibdev, port_num); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* iboe_process_mad() which uses the HCA flow-counters to implement IB PMA 9918c2ecf20Sopenharmony_ci * queries, should be called only by VFs and for that specific purpose 9928c2ecf20Sopenharmony_ci */ 9938c2ecf20Sopenharmony_ci if (link == IB_LINK_LAYER_INFINIBAND) { 9948c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev->dev) && 9958c2ecf20Sopenharmony_ci (in->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT && 9968c2ecf20Sopenharmony_ci (in->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS || 9978c2ecf20Sopenharmony_ci in->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS_EXT || 9988c2ecf20Sopenharmony_ci in->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO))) 9998c2ecf20Sopenharmony_ci return iboe_process_mad(ibdev, mad_flags, port_num, 10008c2ecf20Sopenharmony_ci in_wc, in_grh, in, out); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return ib_process_mad(ibdev, mad_flags, port_num, in_wc, in_grh, 10038c2ecf20Sopenharmony_ci in, out); 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (link == IB_LINK_LAYER_ETHERNET) 10078c2ecf20Sopenharmony_ci return iboe_process_mad(ibdev, mad_flags, port_num, in_wc, 10088c2ecf20Sopenharmony_ci in_grh, in, out); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return -EINVAL; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_cistatic void send_handler(struct ib_mad_agent *agent, 10148c2ecf20Sopenharmony_ci struct ib_mad_send_wc *mad_send_wc) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci if (mad_send_wc->send_buf->context[0]) 10178c2ecf20Sopenharmony_ci rdma_destroy_ah(mad_send_wc->send_buf->context[0], 0); 10188c2ecf20Sopenharmony_ci ib_free_send_mad(mad_send_wc->send_buf); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ciint mlx4_ib_mad_init(struct mlx4_ib_dev *dev) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci struct ib_mad_agent *agent; 10248c2ecf20Sopenharmony_ci int p, q; 10258c2ecf20Sopenharmony_ci int ret; 10268c2ecf20Sopenharmony_ci enum rdma_link_layer ll; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci for (p = 0; p < dev->num_ports; ++p) { 10298c2ecf20Sopenharmony_ci ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1); 10308c2ecf20Sopenharmony_ci for (q = 0; q <= 1; ++q) { 10318c2ecf20Sopenharmony_ci if (ll == IB_LINK_LAYER_INFINIBAND) { 10328c2ecf20Sopenharmony_ci agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 10338c2ecf20Sopenharmony_ci q ? IB_QPT_GSI : IB_QPT_SMI, 10348c2ecf20Sopenharmony_ci NULL, 0, send_handler, 10358c2ecf20Sopenharmony_ci NULL, NULL, 0); 10368c2ecf20Sopenharmony_ci if (IS_ERR(agent)) { 10378c2ecf20Sopenharmony_ci ret = PTR_ERR(agent); 10388c2ecf20Sopenharmony_ci goto err; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci dev->send_agent[p][q] = agent; 10418c2ecf20Sopenharmony_ci } else 10428c2ecf20Sopenharmony_ci dev->send_agent[p][q] = NULL; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci } 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci return 0; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cierr: 10498c2ecf20Sopenharmony_ci for (p = 0; p < dev->num_ports; ++p) 10508c2ecf20Sopenharmony_ci for (q = 0; q <= 1; ++q) 10518c2ecf20Sopenharmony_ci if (dev->send_agent[p][q]) 10528c2ecf20Sopenharmony_ci ib_unregister_mad_agent(dev->send_agent[p][q]); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return ret; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_civoid mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci struct ib_mad_agent *agent; 10608c2ecf20Sopenharmony_ci int p, q; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci for (p = 0; p < dev->num_ports; ++p) { 10638c2ecf20Sopenharmony_ci for (q = 0; q <= 1; ++q) { 10648c2ecf20Sopenharmony_ci agent = dev->send_agent[p][q]; 10658c2ecf20Sopenharmony_ci if (agent) { 10668c2ecf20Sopenharmony_ci dev->send_agent[p][q] = NULL; 10678c2ecf20Sopenharmony_ci ib_unregister_mad_agent(agent); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (dev->sm_ah[p]) 10728c2ecf20Sopenharmony_ci rdma_destroy_ah(dev->sm_ah[p], 0); 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic void handle_lid_change_event(struct mlx4_ib_dev *dev, u8 port_num) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_LID_CHANGE); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) 10818c2ecf20Sopenharmony_ci mlx4_gen_slaves_port_mgt_ev(dev->dev, port_num, 10828c2ecf20Sopenharmony_ci MLX4_EQ_PORT_INFO_LID_CHANGE_MASK); 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic void handle_client_rereg_event(struct mlx4_ib_dev *dev, u8 port_num) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci /* re-configure the alias-guid and mcg's */ 10888c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev)) { 10898c2ecf20Sopenharmony_ci mlx4_ib_invalidate_all_guid_record(dev, port_num); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (!dev->sriov.is_going_down) { 10928c2ecf20Sopenharmony_ci mlx4_ib_mcg_port_cleanup(&dev->sriov.demux[port_num - 1], 0); 10938c2ecf20Sopenharmony_ci mlx4_gen_slaves_port_mgt_ev(dev->dev, port_num, 10948c2ecf20Sopenharmony_ci MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* Update the sl to vl table from inside client rereg 10998c2ecf20Sopenharmony_ci * only if in secure-host mode (snooping is not possible) 11008c2ecf20Sopenharmony_ci * and the sl-to-vl change event is not generated by FW. 11018c2ecf20Sopenharmony_ci */ 11028c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev->dev) && 11038c2ecf20Sopenharmony_ci dev->dev->flags & MLX4_FLAG_SECURE_HOST && 11048c2ecf20Sopenharmony_ci !(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT)) { 11058c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev)) 11068c2ecf20Sopenharmony_ci /* already in work queue from mlx4_ib_event queueing 11078c2ecf20Sopenharmony_ci * mlx4_handle_port_mgmt_change_event, which calls 11088c2ecf20Sopenharmony_ci * this procedure. Therefore, call sl2vl_update directly. 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_ci mlx4_ib_sl2vl_update(dev, port_num); 11118c2ecf20Sopenharmony_ci else 11128c2ecf20Sopenharmony_ci mlx4_sched_ib_sl2vl_update_work(dev, port_num); 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_CLIENT_REREGISTER); 11158c2ecf20Sopenharmony_ci} 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_cistatic void propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, 11188c2ecf20Sopenharmony_ci struct mlx4_eqe *eqe) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci __propagate_pkey_ev(dev, port_num, GET_BLK_PTR_FROM_EQE(eqe), 11218c2ecf20Sopenharmony_ci GET_MASK_FROM_EQE(eqe)); 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic void handle_slaves_guid_change(struct mlx4_ib_dev *dev, u8 port_num, 11258c2ecf20Sopenharmony_ci u32 guid_tbl_blk_num, u32 change_bitmap) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct ib_smp *in_mad = NULL; 11288c2ecf20Sopenharmony_ci struct ib_smp *out_mad = NULL; 11298c2ecf20Sopenharmony_ci u16 i; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev) || !mlx4_is_master(dev->dev)) 11328c2ecf20Sopenharmony_ci return; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); 11358c2ecf20Sopenharmony_ci out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); 11368c2ecf20Sopenharmony_ci if (!in_mad || !out_mad) 11378c2ecf20Sopenharmony_ci goto out; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci guid_tbl_blk_num *= 4; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 11428c2ecf20Sopenharmony_ci if (change_bitmap && (!((change_bitmap >> (8 * i)) & 0xff))) 11438c2ecf20Sopenharmony_ci continue; 11448c2ecf20Sopenharmony_ci memset(in_mad, 0, sizeof *in_mad); 11458c2ecf20Sopenharmony_ci memset(out_mad, 0, sizeof *out_mad); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci in_mad->base_version = 1; 11488c2ecf20Sopenharmony_ci in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 11498c2ecf20Sopenharmony_ci in_mad->class_version = 1; 11508c2ecf20Sopenharmony_ci in_mad->method = IB_MGMT_METHOD_GET; 11518c2ecf20Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; 11528c2ecf20Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(guid_tbl_blk_num + i); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (mlx4_MAD_IFC(dev, 11558c2ecf20Sopenharmony_ci MLX4_MAD_IFC_IGNORE_KEYS | MLX4_MAD_IFC_NET_VIEW, 11568c2ecf20Sopenharmony_ci port_num, NULL, NULL, in_mad, out_mad)) { 11578c2ecf20Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "Failed in get GUID INFO MAD_IFC\n"); 11588c2ecf20Sopenharmony_ci goto out; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci mlx4_ib_update_cache_on_guid_change(dev, guid_tbl_blk_num + i, 11628c2ecf20Sopenharmony_ci port_num, 11638c2ecf20Sopenharmony_ci (u8 *)(&((struct ib_smp *)out_mad)->data)); 11648c2ecf20Sopenharmony_ci mlx4_ib_notify_slaves_on_guid_change(dev, guid_tbl_blk_num + i, 11658c2ecf20Sopenharmony_ci port_num, 11668c2ecf20Sopenharmony_ci (u8 *)(&((struct ib_smp *)out_mad)->data)); 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ciout: 11708c2ecf20Sopenharmony_ci kfree(in_mad); 11718c2ecf20Sopenharmony_ci kfree(out_mad); 11728c2ecf20Sopenharmony_ci return; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_civoid handle_port_mgmt_change_event(struct work_struct *work) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci struct ib_event_work *ew = container_of(work, struct ib_event_work, work); 11788c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = ew->ib_dev; 11798c2ecf20Sopenharmony_ci struct mlx4_eqe *eqe = &(ew->ib_eqe); 11808c2ecf20Sopenharmony_ci u8 port = eqe->event.port_mgmt_change.port; 11818c2ecf20Sopenharmony_ci u32 changed_attr; 11828c2ecf20Sopenharmony_ci u32 tbl_block; 11838c2ecf20Sopenharmony_ci u32 change_bitmap; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci switch (eqe->subtype) { 11868c2ecf20Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_PORT_INFO: 11878c2ecf20Sopenharmony_ci changed_attr = be32_to_cpu(eqe->event.port_mgmt_change.params.port_info.changed_attr); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci /* Update the SM ah - This should be done before handling 11908c2ecf20Sopenharmony_ci the other changed attributes so that MADs can be sent to the SM */ 11918c2ecf20Sopenharmony_ci if (changed_attr & MSTR_SM_CHANGE_MASK) { 11928c2ecf20Sopenharmony_ci u16 lid = be16_to_cpu(eqe->event.port_mgmt_change.params.port_info.mstr_sm_lid); 11938c2ecf20Sopenharmony_ci u8 sl = eqe->event.port_mgmt_change.params.port_info.mstr_sm_sl & 0xf; 11948c2ecf20Sopenharmony_ci update_sm_ah(dev, port, lid, sl); 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci /* Check if it is a lid change event */ 11988c2ecf20Sopenharmony_ci if (changed_attr & MLX4_EQ_PORT_INFO_LID_CHANGE_MASK) 11998c2ecf20Sopenharmony_ci handle_lid_change_event(dev, port); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* Generate GUID changed event */ 12028c2ecf20Sopenharmony_ci if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK) { 12038c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev)) { 12048c2ecf20Sopenharmony_ci union ib_gid gid; 12058c2ecf20Sopenharmony_ci int err = 0; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (!eqe->event.port_mgmt_change.params.port_info.gid_prefix) 12088c2ecf20Sopenharmony_ci err = __mlx4_ib_query_gid(&dev->ib_dev, port, 0, &gid, 1); 12098c2ecf20Sopenharmony_ci else 12108c2ecf20Sopenharmony_ci gid.global.subnet_prefix = 12118c2ecf20Sopenharmony_ci eqe->event.port_mgmt_change.params.port_info.gid_prefix; 12128c2ecf20Sopenharmony_ci if (err) { 12138c2ecf20Sopenharmony_ci pr_warn("Could not change QP1 subnet prefix for port %d: query_gid error (%d)\n", 12148c2ecf20Sopenharmony_ci port, err); 12158c2ecf20Sopenharmony_ci } else { 12168c2ecf20Sopenharmony_ci pr_debug("Changing QP1 subnet prefix for port %d. old=0x%llx. new=0x%llx\n", 12178c2ecf20Sopenharmony_ci port, 12188c2ecf20Sopenharmony_ci (u64)atomic64_read(&dev->sriov.demux[port - 1].subnet_prefix), 12198c2ecf20Sopenharmony_ci be64_to_cpu(gid.global.subnet_prefix)); 12208c2ecf20Sopenharmony_ci atomic64_set(&dev->sriov.demux[port - 1].subnet_prefix, 12218c2ecf20Sopenharmony_ci be64_to_cpu(gid.global.subnet_prefix)); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci } 12248c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 12258c2ecf20Sopenharmony_ci /*if master, notify all slaves*/ 12268c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev)) 12278c2ecf20Sopenharmony_ci mlx4_gen_slaves_port_mgt_ev(dev->dev, port, 12288c2ecf20Sopenharmony_ci MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (changed_attr & MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK) 12328c2ecf20Sopenharmony_ci handle_client_rereg_event(dev, port); 12338c2ecf20Sopenharmony_ci break; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE: 12368c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port, IB_EVENT_PKEY_CHANGE); 12378c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) 12388c2ecf20Sopenharmony_ci propagate_pkey_ev(dev, port, eqe); 12398c2ecf20Sopenharmony_ci break; 12408c2ecf20Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_GUID_INFO: 12418c2ecf20Sopenharmony_ci /* paravirtualized master's guid is guid 0 -- does not change */ 12428c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 12438c2ecf20Sopenharmony_ci mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 12448c2ecf20Sopenharmony_ci /*if master, notify relevant slaves*/ 12458c2ecf20Sopenharmony_ci else if (!dev->sriov.is_going_down) { 12468c2ecf20Sopenharmony_ci tbl_block = GET_BLK_PTR_FROM_EQE(eqe); 12478c2ecf20Sopenharmony_ci change_bitmap = GET_MASK_FROM_EQE(eqe); 12488c2ecf20Sopenharmony_ci handle_slaves_guid_change(dev, port, tbl_block, change_bitmap); 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_SL_TO_VL_MAP: 12538c2ecf20Sopenharmony_ci /* cache sl to vl mapping changes for use in 12548c2ecf20Sopenharmony_ci * filling QP1 LRH VL field when sending packets 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev->dev)) { 12578c2ecf20Sopenharmony_ci union sl2vl_tbl_to_u64 sl2vl64; 12588c2ecf20Sopenharmony_ci int jj; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci for (jj = 0; jj < 8; jj++) { 12618c2ecf20Sopenharmony_ci sl2vl64.sl8[jj] = 12628c2ecf20Sopenharmony_ci eqe->event.port_mgmt_change.params.sl2vl_tbl_change_info.sl2vl_table[jj]; 12638c2ecf20Sopenharmony_ci pr_debug("port %u, sl2vl[%d] = %02x\n", 12648c2ecf20Sopenharmony_ci port, jj, sl2vl64.sl8[jj]); 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci atomic64_set(&dev->sl2vl[port - 1], sl2vl64.sl64); 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci break; 12698c2ecf20Sopenharmony_ci default: 12708c2ecf20Sopenharmony_ci pr_warn("Unsupported subtype 0x%x for " 12718c2ecf20Sopenharmony_ci "Port Management Change event\n", eqe->subtype); 12728c2ecf20Sopenharmony_ci } 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci kfree(ew); 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_civoid mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num, 12788c2ecf20Sopenharmony_ci enum ib_event_type type) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci struct ib_event event; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci event.device = &dev->ib_dev; 12838c2ecf20Sopenharmony_ci event.element.port_num = port_num; 12848c2ecf20Sopenharmony_ci event.event = type; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci ib_dispatch_event(&event); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci unsigned long flags; 12928c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; 12938c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 12948c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 12958c2ecf20Sopenharmony_ci if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) 12968c2ecf20Sopenharmony_ci queue_work(ctx->wq, &ctx->work); 12978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 12988c2ecf20Sopenharmony_ci} 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic void mlx4_ib_wire_comp_handler(struct ib_cq *cq, void *arg) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci unsigned long flags; 13038c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; 13048c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 13078c2ecf20Sopenharmony_ci if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) 13088c2ecf20Sopenharmony_ci queue_work(ctx->wi_wq, &ctx->work); 13098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cistatic int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx, 13138c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp, 13148c2ecf20Sopenharmony_ci int index) 13158c2ecf20Sopenharmony_ci{ 13168c2ecf20Sopenharmony_ci struct ib_sge sg_list; 13178c2ecf20Sopenharmony_ci struct ib_recv_wr recv_wr; 13188c2ecf20Sopenharmony_ci const struct ib_recv_wr *bad_recv_wr; 13198c2ecf20Sopenharmony_ci int size; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci size = (tun_qp->qp->qp_type == IB_QPT_UD) ? 13228c2ecf20Sopenharmony_ci sizeof (struct mlx4_tunnel_mad) : sizeof (struct mlx4_mad_rcv_buf); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci sg_list.addr = tun_qp->ring[index].map; 13258c2ecf20Sopenharmony_ci sg_list.length = size; 13268c2ecf20Sopenharmony_ci sg_list.lkey = ctx->pd->local_dma_lkey; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci recv_wr.next = NULL; 13298c2ecf20Sopenharmony_ci recv_wr.sg_list = &sg_list; 13308c2ecf20Sopenharmony_ci recv_wr.num_sge = 1; 13318c2ecf20Sopenharmony_ci recv_wr.wr_id = (u64) index | MLX4_TUN_WRID_RECV | 13328c2ecf20Sopenharmony_ci MLX4_TUN_SET_WRID_QPN(tun_qp->proxy_qpt); 13338c2ecf20Sopenharmony_ci ib_dma_sync_single_for_device(ctx->ib_dev, tun_qp->ring[index].map, 13348c2ecf20Sopenharmony_ci size, DMA_FROM_DEVICE); 13358c2ecf20Sopenharmony_ci return ib_post_recv(tun_qp->qp, &recv_wr, &bad_recv_wr); 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_cistatic int mlx4_ib_multiplex_sa_handler(struct ib_device *ibdev, int port, 13398c2ecf20Sopenharmony_ci int slave, struct ib_sa_mad *sa_mad) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci int ret = 0; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* dispatch to different sa handlers */ 13448c2ecf20Sopenharmony_ci switch (be16_to_cpu(sa_mad->mad_hdr.attr_id)) { 13458c2ecf20Sopenharmony_ci case IB_SA_ATTR_MC_MEMBER_REC: 13468c2ecf20Sopenharmony_ci ret = mlx4_ib_mcg_multiplex_handler(ibdev, port, slave, sa_mad); 13478c2ecf20Sopenharmony_ci break; 13488c2ecf20Sopenharmony_ci default: 13498c2ecf20Sopenharmony_ci break; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci return ret; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ciint mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, 13558c2ecf20Sopenharmony_ci enum ib_qp_type dest_qpt, u16 pkey_index, 13568c2ecf20Sopenharmony_ci u32 remote_qpn, u32 qkey, struct rdma_ah_attr *attr, 13578c2ecf20Sopenharmony_ci u8 *s_mac, u16 vlan_id, struct ib_mad *mad) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci struct ib_sge list; 13608c2ecf20Sopenharmony_ci struct ib_ud_wr wr; 13618c2ecf20Sopenharmony_ci const struct ib_send_wr *bad_wr; 13628c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *sqp_ctx; 13638c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *sqp; 13648c2ecf20Sopenharmony_ci struct mlx4_mad_snd_buf *sqp_mad; 13658c2ecf20Sopenharmony_ci struct ib_ah *ah; 13668c2ecf20Sopenharmony_ci struct ib_qp *send_qp = NULL; 13678c2ecf20Sopenharmony_ci unsigned wire_tx_ix = 0; 13688c2ecf20Sopenharmony_ci u16 wire_pkey_ix; 13698c2ecf20Sopenharmony_ci int src_qpnum; 13708c2ecf20Sopenharmony_ci int ret; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci sqp_ctx = dev->sriov.sqps[port-1]; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci /* check if proxy qp created */ 13758c2ecf20Sopenharmony_ci if (!sqp_ctx || sqp_ctx->state != DEMUX_PV_STATE_ACTIVE) 13768c2ecf20Sopenharmony_ci return -EAGAIN; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (dest_qpt == IB_QPT_SMI) { 13798c2ecf20Sopenharmony_ci src_qpnum = 0; 13808c2ecf20Sopenharmony_ci sqp = &sqp_ctx->qp[0]; 13818c2ecf20Sopenharmony_ci wire_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][0]; 13828c2ecf20Sopenharmony_ci } else { 13838c2ecf20Sopenharmony_ci src_qpnum = 1; 13848c2ecf20Sopenharmony_ci sqp = &sqp_ctx->qp[1]; 13858c2ecf20Sopenharmony_ci wire_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][pkey_index]; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci send_qp = sqp->qp; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci ah = rdma_zalloc_drv_obj(sqp_ctx->pd->device, ib_ah); 13918c2ecf20Sopenharmony_ci if (!ah) 13928c2ecf20Sopenharmony_ci return -ENOMEM; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci ah->device = sqp_ctx->pd->device; 13958c2ecf20Sopenharmony_ci ah->pd = sqp_ctx->pd; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* create ah */ 13988c2ecf20Sopenharmony_ci ret = mlx4_ib_create_ah_slave(ah, attr, 13998c2ecf20Sopenharmony_ci rdma_ah_retrieve_grh(attr)->sgid_index, 14008c2ecf20Sopenharmony_ci s_mac, vlan_id); 14018c2ecf20Sopenharmony_ci if (ret) 14028c2ecf20Sopenharmony_ci goto out; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci spin_lock(&sqp->tx_lock); 14058c2ecf20Sopenharmony_ci if (sqp->tx_ix_head - sqp->tx_ix_tail >= 14068c2ecf20Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)) 14078c2ecf20Sopenharmony_ci ret = -EAGAIN; 14088c2ecf20Sopenharmony_ci else 14098c2ecf20Sopenharmony_ci wire_tx_ix = (++sqp->tx_ix_head) & (MLX4_NUM_WIRE_BUFS - 1); 14108c2ecf20Sopenharmony_ci spin_unlock(&sqp->tx_lock); 14118c2ecf20Sopenharmony_ci if (ret) 14128c2ecf20Sopenharmony_ci goto out; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci sqp_mad = (struct mlx4_mad_snd_buf *) (sqp->tx_ring[wire_tx_ix].buf.addr); 14158c2ecf20Sopenharmony_ci kfree(sqp->tx_ring[wire_tx_ix].ah); 14168c2ecf20Sopenharmony_ci sqp->tx_ring[wire_tx_ix].ah = ah; 14178c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(&dev->ib_dev, 14188c2ecf20Sopenharmony_ci sqp->tx_ring[wire_tx_ix].buf.map, 14198c2ecf20Sopenharmony_ci sizeof (struct mlx4_mad_snd_buf), 14208c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci memcpy(&sqp_mad->payload, mad, sizeof *mad); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci ib_dma_sync_single_for_device(&dev->ib_dev, 14258c2ecf20Sopenharmony_ci sqp->tx_ring[wire_tx_ix].buf.map, 14268c2ecf20Sopenharmony_ci sizeof (struct mlx4_mad_snd_buf), 14278c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci list.addr = sqp->tx_ring[wire_tx_ix].buf.map; 14308c2ecf20Sopenharmony_ci list.length = sizeof (struct mlx4_mad_snd_buf); 14318c2ecf20Sopenharmony_ci list.lkey = sqp_ctx->pd->local_dma_lkey; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci wr.ah = ah; 14348c2ecf20Sopenharmony_ci wr.port_num = port; 14358c2ecf20Sopenharmony_ci wr.pkey_index = wire_pkey_ix; 14368c2ecf20Sopenharmony_ci wr.remote_qkey = qkey; 14378c2ecf20Sopenharmony_ci wr.remote_qpn = remote_qpn; 14388c2ecf20Sopenharmony_ci wr.wr.next = NULL; 14398c2ecf20Sopenharmony_ci wr.wr.wr_id = ((u64) wire_tx_ix) | MLX4_TUN_SET_WRID_QPN(src_qpnum); 14408c2ecf20Sopenharmony_ci wr.wr.sg_list = &list; 14418c2ecf20Sopenharmony_ci wr.wr.num_sge = 1; 14428c2ecf20Sopenharmony_ci wr.wr.opcode = IB_WR_SEND; 14438c2ecf20Sopenharmony_ci wr.wr.send_flags = IB_SEND_SIGNALED; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci ret = ib_post_send(send_qp, &wr.wr, &bad_wr); 14468c2ecf20Sopenharmony_ci if (!ret) 14478c2ecf20Sopenharmony_ci return 0; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci spin_lock(&sqp->tx_lock); 14508c2ecf20Sopenharmony_ci sqp->tx_ix_tail++; 14518c2ecf20Sopenharmony_ci spin_unlock(&sqp->tx_lock); 14528c2ecf20Sopenharmony_ci sqp->tx_ring[wire_tx_ix].ah = NULL; 14538c2ecf20Sopenharmony_ciout: 14548c2ecf20Sopenharmony_ci kfree(ah); 14558c2ecf20Sopenharmony_ci return ret; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) 14618c2ecf20Sopenharmony_ci return slave; 14628c2ecf20Sopenharmony_ci return mlx4_get_base_gid_ix(dev->dev, slave, port); 14638c2ecf20Sopenharmony_ci} 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_cistatic void fill_in_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port, 14668c2ecf20Sopenharmony_ci struct rdma_ah_attr *ah_attr) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci struct ib_global_route *grh = rdma_ah_retrieve_grh(ah_attr); 14698c2ecf20Sopenharmony_ci if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) 14708c2ecf20Sopenharmony_ci grh->sgid_index = slave; 14718c2ecf20Sopenharmony_ci else 14728c2ecf20Sopenharmony_ci grh->sgid_index += get_slave_base_gid_ix(dev, slave, port); 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 14788c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp = &ctx->qp[MLX4_TUN_WRID_QPN(wc->wr_id)]; 14798c2ecf20Sopenharmony_ci int wr_ix = wc->wr_id & (MLX4_NUM_TUNNEL_BUFS - 1); 14808c2ecf20Sopenharmony_ci struct mlx4_tunnel_mad *tunnel = tun_qp->ring[wr_ix].addr; 14818c2ecf20Sopenharmony_ci struct mlx4_ib_ah ah; 14828c2ecf20Sopenharmony_ci struct rdma_ah_attr ah_attr; 14838c2ecf20Sopenharmony_ci u8 *slave_id; 14848c2ecf20Sopenharmony_ci int slave; 14858c2ecf20Sopenharmony_ci int port; 14868c2ecf20Sopenharmony_ci u16 vlan_id; 14878c2ecf20Sopenharmony_ci u8 qos; 14888c2ecf20Sopenharmony_ci u8 *dmac; 14898c2ecf20Sopenharmony_ci int sts; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci /* Get slave that sent this packet */ 14928c2ecf20Sopenharmony_ci if (wc->src_qp < dev->dev->phys_caps.base_proxy_sqpn || 14938c2ecf20Sopenharmony_ci wc->src_qp >= dev->dev->phys_caps.base_proxy_sqpn + 8 * MLX4_MFUNC_MAX || 14948c2ecf20Sopenharmony_ci (wc->src_qp & 0x1) != ctx->port - 1 || 14958c2ecf20Sopenharmony_ci wc->src_qp & 0x4) { 14968c2ecf20Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d\n", wc->src_qp); 14978c2ecf20Sopenharmony_ci return; 14988c2ecf20Sopenharmony_ci } 14998c2ecf20Sopenharmony_ci slave = ((wc->src_qp & ~0x7) - dev->dev->phys_caps.base_proxy_sqpn) / 8; 15008c2ecf20Sopenharmony_ci if (slave != ctx->slave) { 15018c2ecf20Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d: " 15028c2ecf20Sopenharmony_ci "belongs to another slave\n", wc->src_qp); 15038c2ecf20Sopenharmony_ci return; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci /* Map transaction ID */ 15078c2ecf20Sopenharmony_ci ib_dma_sync_single_for_cpu(ctx->ib_dev, tun_qp->ring[wr_ix].map, 15088c2ecf20Sopenharmony_ci sizeof (struct mlx4_tunnel_mad), 15098c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 15108c2ecf20Sopenharmony_ci switch (tunnel->mad.mad_hdr.method) { 15118c2ecf20Sopenharmony_ci case IB_MGMT_METHOD_SET: 15128c2ecf20Sopenharmony_ci case IB_MGMT_METHOD_GET: 15138c2ecf20Sopenharmony_ci case IB_MGMT_METHOD_REPORT: 15148c2ecf20Sopenharmony_ci case IB_SA_METHOD_GET_TABLE: 15158c2ecf20Sopenharmony_ci case IB_SA_METHOD_DELETE: 15168c2ecf20Sopenharmony_ci case IB_SA_METHOD_GET_MULTI: 15178c2ecf20Sopenharmony_ci case IB_SA_METHOD_GET_TRACE_TBL: 15188c2ecf20Sopenharmony_ci slave_id = (u8 *) &tunnel->mad.mad_hdr.tid; 15198c2ecf20Sopenharmony_ci if (*slave_id) { 15208c2ecf20Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "egress mad has non-null tid msb:%d " 15218c2ecf20Sopenharmony_ci "class:%d slave:%d\n", *slave_id, 15228c2ecf20Sopenharmony_ci tunnel->mad.mad_hdr.mgmt_class, slave); 15238c2ecf20Sopenharmony_ci return; 15248c2ecf20Sopenharmony_ci } else 15258c2ecf20Sopenharmony_ci *slave_id = slave; 15268c2ecf20Sopenharmony_ci default: 15278c2ecf20Sopenharmony_ci /* nothing */; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci /* Class-specific handling */ 15318c2ecf20Sopenharmony_ci switch (tunnel->mad.mad_hdr.mgmt_class) { 15328c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_SUBN_LID_ROUTED: 15338c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 15348c2ecf20Sopenharmony_ci if (slave != mlx4_master_func_num(dev->dev) && 15358c2ecf20Sopenharmony_ci !mlx4_vf_smi_enabled(dev->dev, slave, ctx->port)) 15368c2ecf20Sopenharmony_ci return; 15378c2ecf20Sopenharmony_ci break; 15388c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_SUBN_ADM: 15398c2ecf20Sopenharmony_ci if (mlx4_ib_multiplex_sa_handler(ctx->ib_dev, ctx->port, slave, 15408c2ecf20Sopenharmony_ci (struct ib_sa_mad *) &tunnel->mad)) 15418c2ecf20Sopenharmony_ci return; 15428c2ecf20Sopenharmony_ci break; 15438c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_CM: 15448c2ecf20Sopenharmony_ci if (mlx4_ib_multiplex_cm_handler(ctx->ib_dev, ctx->port, slave, 15458c2ecf20Sopenharmony_ci (struct ib_mad *) &tunnel->mad)) 15468c2ecf20Sopenharmony_ci return; 15478c2ecf20Sopenharmony_ci break; 15488c2ecf20Sopenharmony_ci case IB_MGMT_CLASS_DEVICE_MGMT: 15498c2ecf20Sopenharmony_ci if (tunnel->mad.mad_hdr.method != IB_MGMT_METHOD_GET && 15508c2ecf20Sopenharmony_ci tunnel->mad.mad_hdr.method != IB_MGMT_METHOD_SET) 15518c2ecf20Sopenharmony_ci return; 15528c2ecf20Sopenharmony_ci break; 15538c2ecf20Sopenharmony_ci default: 15548c2ecf20Sopenharmony_ci /* Drop unsupported classes for slaves in tunnel mode */ 15558c2ecf20Sopenharmony_ci if (slave != mlx4_master_func_num(dev->dev)) { 15568c2ecf20Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "dropping unsupported egress mad from class:%d " 15578c2ecf20Sopenharmony_ci "for slave:%d\n", tunnel->mad.mad_hdr.mgmt_class, slave); 15588c2ecf20Sopenharmony_ci return; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci /* We are using standard ib_core services to send the mad, so generate a 15638c2ecf20Sopenharmony_ci * stadard address handle by decoding the tunnelled mlx4_ah fields */ 15648c2ecf20Sopenharmony_ci memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av)); 15658c2ecf20Sopenharmony_ci ah.ibah.device = ctx->ib_dev; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci port = be32_to_cpu(ah.av.ib.port_pd) >> 24; 15688c2ecf20Sopenharmony_ci port = mlx4_slave_convert_port(dev->dev, slave, port); 15698c2ecf20Sopenharmony_ci if (port < 0) 15708c2ecf20Sopenharmony_ci return; 15718c2ecf20Sopenharmony_ci ah.av.ib.port_pd = cpu_to_be32(port << 24 | (be32_to_cpu(ah.av.ib.port_pd) & 0xffffff)); 15728c2ecf20Sopenharmony_ci ah.ibah.type = rdma_ah_find_type(&dev->ib_dev, port); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci mlx4_ib_query_ah(&ah.ibah, &ah_attr); 15758c2ecf20Sopenharmony_ci if (rdma_ah_get_ah_flags(&ah_attr) & IB_AH_GRH) 15768c2ecf20Sopenharmony_ci fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr); 15778c2ecf20Sopenharmony_ci dmac = rdma_ah_retrieve_dmac(&ah_attr); 15788c2ecf20Sopenharmony_ci if (dmac) 15798c2ecf20Sopenharmony_ci memcpy(dmac, tunnel->hdr.mac, ETH_ALEN); 15808c2ecf20Sopenharmony_ci vlan_id = be16_to_cpu(tunnel->hdr.vlan); 15818c2ecf20Sopenharmony_ci /* if slave have default vlan use it */ 15828c2ecf20Sopenharmony_ci if (mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave, 15838c2ecf20Sopenharmony_ci &vlan_id, &qos)) 15848c2ecf20Sopenharmony_ci rdma_ah_set_sl(&ah_attr, qos); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci sts = mlx4_ib_send_to_wire(dev, slave, ctx->port, 15878c2ecf20Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? 15888c2ecf20Sopenharmony_ci IB_QPT_SMI : IB_QPT_GSI, 15898c2ecf20Sopenharmony_ci be16_to_cpu(tunnel->hdr.pkey_index), 15908c2ecf20Sopenharmony_ci be32_to_cpu(tunnel->hdr.remote_qpn), 15918c2ecf20Sopenharmony_ci be32_to_cpu(tunnel->hdr.qkey), 15928c2ecf20Sopenharmony_ci &ah_attr, wc->smac, vlan_id, &tunnel->mad); 15938c2ecf20Sopenharmony_ci if (sts) 15948c2ecf20Sopenharmony_ci pr_debug("failed sending %s to wire on behalf of slave %d (%d)\n", 15958c2ecf20Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 15968c2ecf20Sopenharmony_ci slave, sts); 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_cistatic int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 16008c2ecf20Sopenharmony_ci enum ib_qp_type qp_type, int is_tun) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci int i; 16038c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 16048c2ecf20Sopenharmony_ci int rx_buf_size, tx_buf_size; 16058c2ecf20Sopenharmony_ci const int nmbr_bufs = is_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci if (qp_type > IB_QPT_GSI) 16088c2ecf20Sopenharmony_ci return -EINVAL; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci tun_qp = &ctx->qp[qp_type]; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci tun_qp->ring = kcalloc(nmbr_bufs, 16138c2ecf20Sopenharmony_ci sizeof(struct mlx4_ib_buf), 16148c2ecf20Sopenharmony_ci GFP_KERNEL); 16158c2ecf20Sopenharmony_ci if (!tun_qp->ring) 16168c2ecf20Sopenharmony_ci return -ENOMEM; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci tun_qp->tx_ring = kcalloc(nmbr_bufs, 16198c2ecf20Sopenharmony_ci sizeof (struct mlx4_ib_tun_tx_buf), 16208c2ecf20Sopenharmony_ci GFP_KERNEL); 16218c2ecf20Sopenharmony_ci if (!tun_qp->tx_ring) { 16228c2ecf20Sopenharmony_ci kfree(tun_qp->ring); 16238c2ecf20Sopenharmony_ci tun_qp->ring = NULL; 16248c2ecf20Sopenharmony_ci return -ENOMEM; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (is_tun) { 16288c2ecf20Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_tunnel_mad); 16298c2ecf20Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 16308c2ecf20Sopenharmony_ci } else { 16318c2ecf20Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 16328c2ecf20Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 16368c2ecf20Sopenharmony_ci tun_qp->ring[i].addr = kmalloc(rx_buf_size, GFP_KERNEL); 16378c2ecf20Sopenharmony_ci if (!tun_qp->ring[i].addr) 16388c2ecf20Sopenharmony_ci goto err; 16398c2ecf20Sopenharmony_ci tun_qp->ring[i].map = ib_dma_map_single(ctx->ib_dev, 16408c2ecf20Sopenharmony_ci tun_qp->ring[i].addr, 16418c2ecf20Sopenharmony_ci rx_buf_size, 16428c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 16438c2ecf20Sopenharmony_ci if (ib_dma_mapping_error(ctx->ib_dev, tun_qp->ring[i].map)) { 16448c2ecf20Sopenharmony_ci kfree(tun_qp->ring[i].addr); 16458c2ecf20Sopenharmony_ci goto err; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 16508c2ecf20Sopenharmony_ci tun_qp->tx_ring[i].buf.addr = 16518c2ecf20Sopenharmony_ci kmalloc(tx_buf_size, GFP_KERNEL); 16528c2ecf20Sopenharmony_ci if (!tun_qp->tx_ring[i].buf.addr) 16538c2ecf20Sopenharmony_ci goto tx_err; 16548c2ecf20Sopenharmony_ci tun_qp->tx_ring[i].buf.map = 16558c2ecf20Sopenharmony_ci ib_dma_map_single(ctx->ib_dev, 16568c2ecf20Sopenharmony_ci tun_qp->tx_ring[i].buf.addr, 16578c2ecf20Sopenharmony_ci tx_buf_size, 16588c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 16598c2ecf20Sopenharmony_ci if (ib_dma_mapping_error(ctx->ib_dev, 16608c2ecf20Sopenharmony_ci tun_qp->tx_ring[i].buf.map)) { 16618c2ecf20Sopenharmony_ci kfree(tun_qp->tx_ring[i].buf.addr); 16628c2ecf20Sopenharmony_ci goto tx_err; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci tun_qp->tx_ring[i].ah = NULL; 16658c2ecf20Sopenharmony_ci } 16668c2ecf20Sopenharmony_ci spin_lock_init(&tun_qp->tx_lock); 16678c2ecf20Sopenharmony_ci tun_qp->tx_ix_head = 0; 16688c2ecf20Sopenharmony_ci tun_qp->tx_ix_tail = 0; 16698c2ecf20Sopenharmony_ci tun_qp->proxy_qpt = qp_type; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci return 0; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_citx_err: 16748c2ecf20Sopenharmony_ci while (i > 0) { 16758c2ecf20Sopenharmony_ci --i; 16768c2ecf20Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 16778c2ecf20Sopenharmony_ci tx_buf_size, DMA_TO_DEVICE); 16788c2ecf20Sopenharmony_ci kfree(tun_qp->tx_ring[i].buf.addr); 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci i = nmbr_bufs; 16818c2ecf20Sopenharmony_cierr: 16828c2ecf20Sopenharmony_ci while (i > 0) { 16838c2ecf20Sopenharmony_ci --i; 16848c2ecf20Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 16858c2ecf20Sopenharmony_ci rx_buf_size, DMA_FROM_DEVICE); 16868c2ecf20Sopenharmony_ci kfree(tun_qp->ring[i].addr); 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci kfree(tun_qp->tx_ring); 16898c2ecf20Sopenharmony_ci tun_qp->tx_ring = NULL; 16908c2ecf20Sopenharmony_ci kfree(tun_qp->ring); 16918c2ecf20Sopenharmony_ci tun_qp->ring = NULL; 16928c2ecf20Sopenharmony_ci return -ENOMEM; 16938c2ecf20Sopenharmony_ci} 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_cistatic void mlx4_ib_free_pv_qp_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 16968c2ecf20Sopenharmony_ci enum ib_qp_type qp_type, int is_tun) 16978c2ecf20Sopenharmony_ci{ 16988c2ecf20Sopenharmony_ci int i; 16998c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 17008c2ecf20Sopenharmony_ci int rx_buf_size, tx_buf_size; 17018c2ecf20Sopenharmony_ci const int nmbr_bufs = is_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci if (qp_type > IB_QPT_GSI) 17048c2ecf20Sopenharmony_ci return; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci tun_qp = &ctx->qp[qp_type]; 17078c2ecf20Sopenharmony_ci if (is_tun) { 17088c2ecf20Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_tunnel_mad); 17098c2ecf20Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 17108c2ecf20Sopenharmony_ci } else { 17118c2ecf20Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 17128c2ecf20Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 17178c2ecf20Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 17188c2ecf20Sopenharmony_ci rx_buf_size, DMA_FROM_DEVICE); 17198c2ecf20Sopenharmony_ci kfree(tun_qp->ring[i].addr); 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 17238c2ecf20Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 17248c2ecf20Sopenharmony_ci tx_buf_size, DMA_TO_DEVICE); 17258c2ecf20Sopenharmony_ci kfree(tun_qp->tx_ring[i].buf.addr); 17268c2ecf20Sopenharmony_ci if (tun_qp->tx_ring[i].ah) 17278c2ecf20Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[i].ah, 0); 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci kfree(tun_qp->tx_ring); 17308c2ecf20Sopenharmony_ci kfree(tun_qp->ring); 17318c2ecf20Sopenharmony_ci} 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_cistatic void mlx4_ib_tunnel_comp_worker(struct work_struct *work) 17348c2ecf20Sopenharmony_ci{ 17358c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx; 17368c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 17378c2ecf20Sopenharmony_ci struct ib_wc wc; 17388c2ecf20Sopenharmony_ci int ret; 17398c2ecf20Sopenharmony_ci ctx = container_of(work, struct mlx4_ib_demux_pv_ctx, work); 17408c2ecf20Sopenharmony_ci ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci while (ib_poll_cq(ctx->cq, 1, &wc) == 1) { 17438c2ecf20Sopenharmony_ci tun_qp = &ctx->qp[MLX4_TUN_WRID_QPN(wc.wr_id)]; 17448c2ecf20Sopenharmony_ci if (wc.status == IB_WC_SUCCESS) { 17458c2ecf20Sopenharmony_ci switch (wc.opcode) { 17468c2ecf20Sopenharmony_ci case IB_WC_RECV: 17478c2ecf20Sopenharmony_ci mlx4_ib_multiplex_mad(ctx, &wc); 17488c2ecf20Sopenharmony_ci ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, 17498c2ecf20Sopenharmony_ci wc.wr_id & 17508c2ecf20Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)); 17518c2ecf20Sopenharmony_ci if (ret) 17528c2ecf20Sopenharmony_ci pr_err("Failed reposting tunnel " 17538c2ecf20Sopenharmony_ci "buf:%lld\n", wc.wr_id); 17548c2ecf20Sopenharmony_ci break; 17558c2ecf20Sopenharmony_ci case IB_WC_SEND: 17568c2ecf20Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[wc.wr_id & 17578c2ecf20Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)].ah, 0); 17588c2ecf20Sopenharmony_ci tun_qp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah 17598c2ecf20Sopenharmony_ci = NULL; 17608c2ecf20Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 17618c2ecf20Sopenharmony_ci tun_qp->tx_ix_tail++; 17628c2ecf20Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci break; 17658c2ecf20Sopenharmony_ci default: 17668c2ecf20Sopenharmony_ci break; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci } else { 17698c2ecf20Sopenharmony_ci pr_debug("mlx4_ib: completion error in tunnel: %d." 17708c2ecf20Sopenharmony_ci " status = %d, wrid = 0x%llx\n", 17718c2ecf20Sopenharmony_ci ctx->slave, wc.status, wc.wr_id); 17728c2ecf20Sopenharmony_ci if (!MLX4_TUN_IS_RECV(wc.wr_id)) { 17738c2ecf20Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[wc.wr_id & 17748c2ecf20Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)].ah, 0); 17758c2ecf20Sopenharmony_ci tun_qp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah 17768c2ecf20Sopenharmony_ci = NULL; 17778c2ecf20Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 17788c2ecf20Sopenharmony_ci tun_qp->tx_ix_tail++; 17798c2ecf20Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci} 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_cistatic void pv_qp_event_handler(struct ib_event *event, void *qp_context) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *sqp = qp_context; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci /* It's worse than that! He's dead, Jim! */ 17908c2ecf20Sopenharmony_ci pr_err("Fatal error (%d) on a MAD QP on port %d\n", 17918c2ecf20Sopenharmony_ci event->event, sqp->port); 17928c2ecf20Sopenharmony_ci} 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_cistatic int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx, 17958c2ecf20Sopenharmony_ci enum ib_qp_type qp_type, int create_tun) 17968c2ecf20Sopenharmony_ci{ 17978c2ecf20Sopenharmony_ci int i, ret; 17988c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 17998c2ecf20Sopenharmony_ci struct mlx4_ib_qp_tunnel_init_attr qp_init_attr; 18008c2ecf20Sopenharmony_ci struct ib_qp_attr attr; 18018c2ecf20Sopenharmony_ci int qp_attr_mask_INIT; 18028c2ecf20Sopenharmony_ci const int nmbr_bufs = create_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci if (qp_type > IB_QPT_GSI) 18058c2ecf20Sopenharmony_ci return -EINVAL; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci tun_qp = &ctx->qp[qp_type]; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci memset(&qp_init_attr, 0, sizeof qp_init_attr); 18108c2ecf20Sopenharmony_ci qp_init_attr.init_attr.send_cq = ctx->cq; 18118c2ecf20Sopenharmony_ci qp_init_attr.init_attr.recv_cq = ctx->cq; 18128c2ecf20Sopenharmony_ci qp_init_attr.init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; 18138c2ecf20Sopenharmony_ci qp_init_attr.init_attr.cap.max_send_wr = nmbr_bufs; 18148c2ecf20Sopenharmony_ci qp_init_attr.init_attr.cap.max_recv_wr = nmbr_bufs; 18158c2ecf20Sopenharmony_ci qp_init_attr.init_attr.cap.max_send_sge = 1; 18168c2ecf20Sopenharmony_ci qp_init_attr.init_attr.cap.max_recv_sge = 1; 18178c2ecf20Sopenharmony_ci if (create_tun) { 18188c2ecf20Sopenharmony_ci qp_init_attr.init_attr.qp_type = IB_QPT_UD; 18198c2ecf20Sopenharmony_ci qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_TUNNEL_QP; 18208c2ecf20Sopenharmony_ci qp_init_attr.port = ctx->port; 18218c2ecf20Sopenharmony_ci qp_init_attr.slave = ctx->slave; 18228c2ecf20Sopenharmony_ci qp_init_attr.proxy_qp_type = qp_type; 18238c2ecf20Sopenharmony_ci qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | 18248c2ecf20Sopenharmony_ci IB_QP_QKEY | IB_QP_PORT; 18258c2ecf20Sopenharmony_ci } else { 18268c2ecf20Sopenharmony_ci qp_init_attr.init_attr.qp_type = qp_type; 18278c2ecf20Sopenharmony_ci qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_SQP; 18288c2ecf20Sopenharmony_ci qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY; 18298c2ecf20Sopenharmony_ci } 18308c2ecf20Sopenharmony_ci qp_init_attr.init_attr.port_num = ctx->port; 18318c2ecf20Sopenharmony_ci qp_init_attr.init_attr.qp_context = ctx; 18328c2ecf20Sopenharmony_ci qp_init_attr.init_attr.event_handler = pv_qp_event_handler; 18338c2ecf20Sopenharmony_ci tun_qp->qp = ib_create_qp(ctx->pd, &qp_init_attr.init_attr); 18348c2ecf20Sopenharmony_ci if (IS_ERR(tun_qp->qp)) { 18358c2ecf20Sopenharmony_ci ret = PTR_ERR(tun_qp->qp); 18368c2ecf20Sopenharmony_ci tun_qp->qp = NULL; 18378c2ecf20Sopenharmony_ci pr_err("Couldn't create %s QP (%d)\n", 18388c2ecf20Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 18398c2ecf20Sopenharmony_ci return ret; 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci memset(&attr, 0, sizeof attr); 18438c2ecf20Sopenharmony_ci attr.qp_state = IB_QPS_INIT; 18448c2ecf20Sopenharmony_ci ret = 0; 18458c2ecf20Sopenharmony_ci if (create_tun) 18468c2ecf20Sopenharmony_ci ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave, 18478c2ecf20Sopenharmony_ci ctx->port, IB_DEFAULT_PKEY_FULL, 18488c2ecf20Sopenharmony_ci &attr.pkey_index); 18498c2ecf20Sopenharmony_ci if (ret || !create_tun) 18508c2ecf20Sopenharmony_ci attr.pkey_index = 18518c2ecf20Sopenharmony_ci to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0]; 18528c2ecf20Sopenharmony_ci attr.qkey = IB_QP1_QKEY; 18538c2ecf20Sopenharmony_ci attr.port_num = ctx->port; 18548c2ecf20Sopenharmony_ci ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT); 18558c2ecf20Sopenharmony_ci if (ret) { 18568c2ecf20Sopenharmony_ci pr_err("Couldn't change %s qp state to INIT (%d)\n", 18578c2ecf20Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 18588c2ecf20Sopenharmony_ci goto err_qp; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci attr.qp_state = IB_QPS_RTR; 18618c2ecf20Sopenharmony_ci ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE); 18628c2ecf20Sopenharmony_ci if (ret) { 18638c2ecf20Sopenharmony_ci pr_err("Couldn't change %s qp state to RTR (%d)\n", 18648c2ecf20Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 18658c2ecf20Sopenharmony_ci goto err_qp; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci attr.qp_state = IB_QPS_RTS; 18688c2ecf20Sopenharmony_ci attr.sq_psn = 0; 18698c2ecf20Sopenharmony_ci ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN); 18708c2ecf20Sopenharmony_ci if (ret) { 18718c2ecf20Sopenharmony_ci pr_err("Couldn't change %s qp state to RTS (%d)\n", 18728c2ecf20Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 18738c2ecf20Sopenharmony_ci goto err_qp; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 18778c2ecf20Sopenharmony_ci ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, i); 18788c2ecf20Sopenharmony_ci if (ret) { 18798c2ecf20Sopenharmony_ci pr_err(" mlx4_ib_post_pv_buf error" 18808c2ecf20Sopenharmony_ci " (err = %d, i = %d)\n", ret, i); 18818c2ecf20Sopenharmony_ci goto err_qp; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci return 0; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_cierr_qp: 18878c2ecf20Sopenharmony_ci ib_destroy_qp(tun_qp->qp); 18888c2ecf20Sopenharmony_ci tun_qp->qp = NULL; 18898c2ecf20Sopenharmony_ci return ret; 18908c2ecf20Sopenharmony_ci} 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci/* 18938c2ecf20Sopenharmony_ci * IB MAD completion callback for real SQPs 18948c2ecf20Sopenharmony_ci */ 18958c2ecf20Sopenharmony_cistatic void mlx4_ib_sqp_comp_worker(struct work_struct *work) 18968c2ecf20Sopenharmony_ci{ 18978c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx; 18988c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_qp *sqp; 18998c2ecf20Sopenharmony_ci struct ib_wc wc; 19008c2ecf20Sopenharmony_ci struct ib_grh *grh; 19018c2ecf20Sopenharmony_ci struct ib_mad *mad; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci ctx = container_of(work, struct mlx4_ib_demux_pv_ctx, work); 19048c2ecf20Sopenharmony_ci ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci while (mlx4_ib_poll_cq(ctx->cq, 1, &wc) == 1) { 19078c2ecf20Sopenharmony_ci sqp = &ctx->qp[MLX4_TUN_WRID_QPN(wc.wr_id)]; 19088c2ecf20Sopenharmony_ci if (wc.status == IB_WC_SUCCESS) { 19098c2ecf20Sopenharmony_ci switch (wc.opcode) { 19108c2ecf20Sopenharmony_ci case IB_WC_SEND: 19118c2ecf20Sopenharmony_ci kfree(sqp->tx_ring[wc.wr_id & 19128c2ecf20Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].ah); 19138c2ecf20Sopenharmony_ci sqp->tx_ring[wc.wr_id & (MLX4_NUM_WIRE_BUFS - 1)].ah 19148c2ecf20Sopenharmony_ci = NULL; 19158c2ecf20Sopenharmony_ci spin_lock(&sqp->tx_lock); 19168c2ecf20Sopenharmony_ci sqp->tx_ix_tail++; 19178c2ecf20Sopenharmony_ci spin_unlock(&sqp->tx_lock); 19188c2ecf20Sopenharmony_ci break; 19198c2ecf20Sopenharmony_ci case IB_WC_RECV: 19208c2ecf20Sopenharmony_ci mad = (struct ib_mad *) &(((struct mlx4_mad_rcv_buf *) 19218c2ecf20Sopenharmony_ci (sqp->ring[wc.wr_id & 19228c2ecf20Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].addr))->payload); 19238c2ecf20Sopenharmony_ci grh = &(((struct mlx4_mad_rcv_buf *) 19248c2ecf20Sopenharmony_ci (sqp->ring[wc.wr_id & 19258c2ecf20Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].addr))->grh); 19268c2ecf20Sopenharmony_ci mlx4_ib_demux_mad(ctx->ib_dev, ctx->port, &wc, grh, mad); 19278c2ecf20Sopenharmony_ci if (mlx4_ib_post_pv_qp_buf(ctx, sqp, wc.wr_id & 19288c2ecf20Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1))) 19298c2ecf20Sopenharmony_ci pr_err("Failed reposting SQP " 19308c2ecf20Sopenharmony_ci "buf:%lld\n", wc.wr_id); 19318c2ecf20Sopenharmony_ci break; 19328c2ecf20Sopenharmony_ci default: 19338c2ecf20Sopenharmony_ci break; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci } else { 19368c2ecf20Sopenharmony_ci pr_debug("mlx4_ib: completion error in tunnel: %d." 19378c2ecf20Sopenharmony_ci " status = %d, wrid = 0x%llx\n", 19388c2ecf20Sopenharmony_ci ctx->slave, wc.status, wc.wr_id); 19398c2ecf20Sopenharmony_ci if (!MLX4_TUN_IS_RECV(wc.wr_id)) { 19408c2ecf20Sopenharmony_ci kfree(sqp->tx_ring[wc.wr_id & 19418c2ecf20Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].ah); 19428c2ecf20Sopenharmony_ci sqp->tx_ring[wc.wr_id & (MLX4_NUM_WIRE_BUFS - 1)].ah 19438c2ecf20Sopenharmony_ci = NULL; 19448c2ecf20Sopenharmony_ci spin_lock(&sqp->tx_lock); 19458c2ecf20Sopenharmony_ci sqp->tx_ix_tail++; 19468c2ecf20Sopenharmony_ci spin_unlock(&sqp->tx_lock); 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci } 19498c2ecf20Sopenharmony_ci } 19508c2ecf20Sopenharmony_ci} 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_cistatic int alloc_pv_object(struct mlx4_ib_dev *dev, int slave, int port, 19538c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx **ret_ctx) 19548c2ecf20Sopenharmony_ci{ 19558c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci *ret_ctx = NULL; 19588c2ecf20Sopenharmony_ci ctx = kzalloc(sizeof (struct mlx4_ib_demux_pv_ctx), GFP_KERNEL); 19598c2ecf20Sopenharmony_ci if (!ctx) 19608c2ecf20Sopenharmony_ci return -ENOMEM; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci ctx->ib_dev = &dev->ib_dev; 19638c2ecf20Sopenharmony_ci ctx->port = port; 19648c2ecf20Sopenharmony_ci ctx->slave = slave; 19658c2ecf20Sopenharmony_ci *ret_ctx = ctx; 19668c2ecf20Sopenharmony_ci return 0; 19678c2ecf20Sopenharmony_ci} 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_cistatic void free_pv_object(struct mlx4_ib_dev *dev, int slave, int port) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci if (dev->sriov.demux[port - 1].tun[slave]) { 19728c2ecf20Sopenharmony_ci kfree(dev->sriov.demux[port - 1].tun[slave]); 19738c2ecf20Sopenharmony_ci dev->sriov.demux[port - 1].tun[slave] = NULL; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_cistatic int create_pv_resources(struct ib_device *ibdev, int slave, int port, 19788c2ecf20Sopenharmony_ci int create_tun, struct mlx4_ib_demux_pv_ctx *ctx) 19798c2ecf20Sopenharmony_ci{ 19808c2ecf20Sopenharmony_ci int ret, cq_size; 19818c2ecf20Sopenharmony_ci struct ib_cq_init_attr cq_attr = {}; 19828c2ecf20Sopenharmony_ci const int nmbr_bufs = create_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci if (ctx->state != DEMUX_PV_STATE_DOWN) 19858c2ecf20Sopenharmony_ci return -EEXIST; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci ctx->state = DEMUX_PV_STATE_STARTING; 19888c2ecf20Sopenharmony_ci /* have QP0 only if link layer is IB */ 19898c2ecf20Sopenharmony_ci if (rdma_port_get_link_layer(ibdev, ctx->port) == 19908c2ecf20Sopenharmony_ci IB_LINK_LAYER_INFINIBAND) 19918c2ecf20Sopenharmony_ci ctx->has_smi = 1; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci if (ctx->has_smi) { 19948c2ecf20Sopenharmony_ci ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_SMI, create_tun); 19958c2ecf20Sopenharmony_ci if (ret) { 19968c2ecf20Sopenharmony_ci pr_err("Failed allocating qp0 tunnel bufs (%d)\n", ret); 19978c2ecf20Sopenharmony_ci goto err_out; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_GSI, create_tun); 20028c2ecf20Sopenharmony_ci if (ret) { 20038c2ecf20Sopenharmony_ci pr_err("Failed allocating qp1 tunnel bufs (%d)\n", ret); 20048c2ecf20Sopenharmony_ci goto err_out_qp0; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci cq_size = 2 * nmbr_bufs; 20088c2ecf20Sopenharmony_ci if (ctx->has_smi) 20098c2ecf20Sopenharmony_ci cq_size *= 2; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci cq_attr.cqe = cq_size; 20128c2ecf20Sopenharmony_ci ctx->cq = ib_create_cq(ctx->ib_dev, 20138c2ecf20Sopenharmony_ci create_tun ? mlx4_ib_tunnel_comp_handler : mlx4_ib_wire_comp_handler, 20148c2ecf20Sopenharmony_ci NULL, ctx, &cq_attr); 20158c2ecf20Sopenharmony_ci if (IS_ERR(ctx->cq)) { 20168c2ecf20Sopenharmony_ci ret = PTR_ERR(ctx->cq); 20178c2ecf20Sopenharmony_ci pr_err("Couldn't create tunnel CQ (%d)\n", ret); 20188c2ecf20Sopenharmony_ci goto err_buf; 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci ctx->pd = ib_alloc_pd(ctx->ib_dev, 0); 20228c2ecf20Sopenharmony_ci if (IS_ERR(ctx->pd)) { 20238c2ecf20Sopenharmony_ci ret = PTR_ERR(ctx->pd); 20248c2ecf20Sopenharmony_ci pr_err("Couldn't create tunnel PD (%d)\n", ret); 20258c2ecf20Sopenharmony_ci goto err_cq; 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci if (ctx->has_smi) { 20298c2ecf20Sopenharmony_ci ret = create_pv_sqp(ctx, IB_QPT_SMI, create_tun); 20308c2ecf20Sopenharmony_ci if (ret) { 20318c2ecf20Sopenharmony_ci pr_err("Couldn't create %s QP0 (%d)\n", 20328c2ecf20Sopenharmony_ci create_tun ? "tunnel for" : "", ret); 20338c2ecf20Sopenharmony_ci goto err_pd; 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci ret = create_pv_sqp(ctx, IB_QPT_GSI, create_tun); 20388c2ecf20Sopenharmony_ci if (ret) { 20398c2ecf20Sopenharmony_ci pr_err("Couldn't create %s QP1 (%d)\n", 20408c2ecf20Sopenharmony_ci create_tun ? "tunnel for" : "", ret); 20418c2ecf20Sopenharmony_ci goto err_qp0; 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci if (create_tun) 20458c2ecf20Sopenharmony_ci INIT_WORK(&ctx->work, mlx4_ib_tunnel_comp_worker); 20468c2ecf20Sopenharmony_ci else 20478c2ecf20Sopenharmony_ci INIT_WORK(&ctx->work, mlx4_ib_sqp_comp_worker); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci ctx->wq = to_mdev(ibdev)->sriov.demux[port - 1].wq; 20508c2ecf20Sopenharmony_ci ctx->wi_wq = to_mdev(ibdev)->sriov.demux[port - 1].wi_wq; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci ret = ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 20538c2ecf20Sopenharmony_ci if (ret) { 20548c2ecf20Sopenharmony_ci pr_err("Couldn't arm tunnel cq (%d)\n", ret); 20558c2ecf20Sopenharmony_ci goto err_wq; 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci ctx->state = DEMUX_PV_STATE_ACTIVE; 20588c2ecf20Sopenharmony_ci return 0; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_cierr_wq: 20618c2ecf20Sopenharmony_ci ctx->wq = NULL; 20628c2ecf20Sopenharmony_ci ib_destroy_qp(ctx->qp[1].qp); 20638c2ecf20Sopenharmony_ci ctx->qp[1].qp = NULL; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_cierr_qp0: 20678c2ecf20Sopenharmony_ci if (ctx->has_smi) 20688c2ecf20Sopenharmony_ci ib_destroy_qp(ctx->qp[0].qp); 20698c2ecf20Sopenharmony_ci ctx->qp[0].qp = NULL; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_cierr_pd: 20728c2ecf20Sopenharmony_ci ib_dealloc_pd(ctx->pd); 20738c2ecf20Sopenharmony_ci ctx->pd = NULL; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_cierr_cq: 20768c2ecf20Sopenharmony_ci ib_destroy_cq(ctx->cq); 20778c2ecf20Sopenharmony_ci ctx->cq = NULL; 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cierr_buf: 20808c2ecf20Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, create_tun); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_cierr_out_qp0: 20838c2ecf20Sopenharmony_ci if (ctx->has_smi) 20848c2ecf20Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, create_tun); 20858c2ecf20Sopenharmony_cierr_out: 20868c2ecf20Sopenharmony_ci ctx->state = DEMUX_PV_STATE_DOWN; 20878c2ecf20Sopenharmony_ci return ret; 20888c2ecf20Sopenharmony_ci} 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cistatic void destroy_pv_resources(struct mlx4_ib_dev *dev, int slave, int port, 20918c2ecf20Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx, int flush) 20928c2ecf20Sopenharmony_ci{ 20938c2ecf20Sopenharmony_ci if (!ctx) 20948c2ecf20Sopenharmony_ci return; 20958c2ecf20Sopenharmony_ci if (ctx->state > DEMUX_PV_STATE_DOWN) { 20968c2ecf20Sopenharmony_ci ctx->state = DEMUX_PV_STATE_DOWNING; 20978c2ecf20Sopenharmony_ci if (flush) 20988c2ecf20Sopenharmony_ci flush_workqueue(ctx->wq); 20998c2ecf20Sopenharmony_ci if (ctx->has_smi) { 21008c2ecf20Sopenharmony_ci ib_destroy_qp(ctx->qp[0].qp); 21018c2ecf20Sopenharmony_ci ctx->qp[0].qp = NULL; 21028c2ecf20Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, 1); 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci ib_destroy_qp(ctx->qp[1].qp); 21058c2ecf20Sopenharmony_ci ctx->qp[1].qp = NULL; 21068c2ecf20Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, 1); 21078c2ecf20Sopenharmony_ci ib_dealloc_pd(ctx->pd); 21088c2ecf20Sopenharmony_ci ctx->pd = NULL; 21098c2ecf20Sopenharmony_ci ib_destroy_cq(ctx->cq); 21108c2ecf20Sopenharmony_ci ctx->cq = NULL; 21118c2ecf20Sopenharmony_ci ctx->state = DEMUX_PV_STATE_DOWN; 21128c2ecf20Sopenharmony_ci } 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_cistatic int mlx4_ib_tunnels_update(struct mlx4_ib_dev *dev, int slave, 21168c2ecf20Sopenharmony_ci int port, int do_init) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci int ret = 0; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (!do_init) { 21218c2ecf20Sopenharmony_ci clean_vf_mcast(&dev->sriov.demux[port - 1], slave); 21228c2ecf20Sopenharmony_ci /* for master, destroy real sqp resources */ 21238c2ecf20Sopenharmony_ci if (slave == mlx4_master_func_num(dev->dev)) 21248c2ecf20Sopenharmony_ci destroy_pv_resources(dev, slave, port, 21258c2ecf20Sopenharmony_ci dev->sriov.sqps[port - 1], 1); 21268c2ecf20Sopenharmony_ci /* destroy the tunnel qp resources */ 21278c2ecf20Sopenharmony_ci destroy_pv_resources(dev, slave, port, 21288c2ecf20Sopenharmony_ci dev->sriov.demux[port - 1].tun[slave], 1); 21298c2ecf20Sopenharmony_ci return 0; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci /* create the tunnel qp resources */ 21338c2ecf20Sopenharmony_ci ret = create_pv_resources(&dev->ib_dev, slave, port, 1, 21348c2ecf20Sopenharmony_ci dev->sriov.demux[port - 1].tun[slave]); 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci /* for master, create the real sqp resources */ 21378c2ecf20Sopenharmony_ci if (!ret && slave == mlx4_master_func_num(dev->dev)) 21388c2ecf20Sopenharmony_ci ret = create_pv_resources(&dev->ib_dev, slave, port, 0, 21398c2ecf20Sopenharmony_ci dev->sriov.sqps[port - 1]); 21408c2ecf20Sopenharmony_ci return ret; 21418c2ecf20Sopenharmony_ci} 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_civoid mlx4_ib_tunnels_update_work(struct work_struct *work) 21448c2ecf20Sopenharmony_ci{ 21458c2ecf20Sopenharmony_ci struct mlx4_ib_demux_work *dmxw; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci dmxw = container_of(work, struct mlx4_ib_demux_work, work); 21488c2ecf20Sopenharmony_ci mlx4_ib_tunnels_update(dmxw->dev, dmxw->slave, (int) dmxw->port, 21498c2ecf20Sopenharmony_ci dmxw->do_init); 21508c2ecf20Sopenharmony_ci kfree(dmxw); 21518c2ecf20Sopenharmony_ci return; 21528c2ecf20Sopenharmony_ci} 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_cistatic int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, 21558c2ecf20Sopenharmony_ci struct mlx4_ib_demux_ctx *ctx, 21568c2ecf20Sopenharmony_ci int port) 21578c2ecf20Sopenharmony_ci{ 21588c2ecf20Sopenharmony_ci char name[12]; 21598c2ecf20Sopenharmony_ci int ret = 0; 21608c2ecf20Sopenharmony_ci int i; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci ctx->tun = kcalloc(dev->dev->caps.sqp_demux, 21638c2ecf20Sopenharmony_ci sizeof (struct mlx4_ib_demux_pv_ctx *), GFP_KERNEL); 21648c2ecf20Sopenharmony_ci if (!ctx->tun) 21658c2ecf20Sopenharmony_ci return -ENOMEM; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci ctx->dev = dev; 21688c2ecf20Sopenharmony_ci ctx->port = port; 21698c2ecf20Sopenharmony_ci ctx->ib_dev = &dev->ib_dev; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci for (i = 0; 21728c2ecf20Sopenharmony_ci i < min(dev->dev->caps.sqp_demux, 21738c2ecf20Sopenharmony_ci (u16)(dev->dev->persist->num_vfs + 1)); 21748c2ecf20Sopenharmony_ci i++) { 21758c2ecf20Sopenharmony_ci struct mlx4_active_ports actv_ports = 21768c2ecf20Sopenharmony_ci mlx4_get_active_ports(dev->dev, i); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci if (!test_bit(port - 1, actv_ports.ports)) 21798c2ecf20Sopenharmony_ci continue; 21808c2ecf20Sopenharmony_ci 21818c2ecf20Sopenharmony_ci ret = alloc_pv_object(dev, i, port, &ctx->tun[i]); 21828c2ecf20Sopenharmony_ci if (ret) { 21838c2ecf20Sopenharmony_ci ret = -ENOMEM; 21848c2ecf20Sopenharmony_ci goto err_mcg; 21858c2ecf20Sopenharmony_ci } 21868c2ecf20Sopenharmony_ci } 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci ret = mlx4_ib_mcg_port_init(ctx); 21898c2ecf20Sopenharmony_ci if (ret) { 21908c2ecf20Sopenharmony_ci pr_err("Failed initializing mcg para-virt (%d)\n", ret); 21918c2ecf20Sopenharmony_ci goto err_mcg; 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "mlx4_ibt%d", port); 21958c2ecf20Sopenharmony_ci ctx->wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); 21968c2ecf20Sopenharmony_ci if (!ctx->wq) { 21978c2ecf20Sopenharmony_ci pr_err("Failed to create tunnelling WQ for port %d\n", port); 21988c2ecf20Sopenharmony_ci ret = -ENOMEM; 21998c2ecf20Sopenharmony_ci goto err_wq; 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "mlx4_ibwi%d", port); 22038c2ecf20Sopenharmony_ci ctx->wi_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); 22048c2ecf20Sopenharmony_ci if (!ctx->wi_wq) { 22058c2ecf20Sopenharmony_ci pr_err("Failed to create wire WQ for port %d\n", port); 22068c2ecf20Sopenharmony_ci ret = -ENOMEM; 22078c2ecf20Sopenharmony_ci goto err_wiwq; 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "mlx4_ibud%d", port); 22118c2ecf20Sopenharmony_ci ctx->ud_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); 22128c2ecf20Sopenharmony_ci if (!ctx->ud_wq) { 22138c2ecf20Sopenharmony_ci pr_err("Failed to create up/down WQ for port %d\n", port); 22148c2ecf20Sopenharmony_ci ret = -ENOMEM; 22158c2ecf20Sopenharmony_ci goto err_udwq; 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci return 0; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_cierr_udwq: 22218c2ecf20Sopenharmony_ci destroy_workqueue(ctx->wi_wq); 22228c2ecf20Sopenharmony_ci ctx->wi_wq = NULL; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_cierr_wiwq: 22258c2ecf20Sopenharmony_ci destroy_workqueue(ctx->wq); 22268c2ecf20Sopenharmony_ci ctx->wq = NULL; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_cierr_wq: 22298c2ecf20Sopenharmony_ci mlx4_ib_mcg_port_cleanup(ctx, 1); 22308c2ecf20Sopenharmony_cierr_mcg: 22318c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) 22328c2ecf20Sopenharmony_ci free_pv_object(dev, i, port); 22338c2ecf20Sopenharmony_ci kfree(ctx->tun); 22348c2ecf20Sopenharmony_ci ctx->tun = NULL; 22358c2ecf20Sopenharmony_ci return ret; 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_cistatic void mlx4_ib_free_sqp_ctx(struct mlx4_ib_demux_pv_ctx *sqp_ctx) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci if (sqp_ctx->state > DEMUX_PV_STATE_DOWN) { 22418c2ecf20Sopenharmony_ci sqp_ctx->state = DEMUX_PV_STATE_DOWNING; 22428c2ecf20Sopenharmony_ci flush_workqueue(sqp_ctx->wq); 22438c2ecf20Sopenharmony_ci if (sqp_ctx->has_smi) { 22448c2ecf20Sopenharmony_ci ib_destroy_qp(sqp_ctx->qp[0].qp); 22458c2ecf20Sopenharmony_ci sqp_ctx->qp[0].qp = NULL; 22468c2ecf20Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_SMI, 0); 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci ib_destroy_qp(sqp_ctx->qp[1].qp); 22498c2ecf20Sopenharmony_ci sqp_ctx->qp[1].qp = NULL; 22508c2ecf20Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_GSI, 0); 22518c2ecf20Sopenharmony_ci ib_dealloc_pd(sqp_ctx->pd); 22528c2ecf20Sopenharmony_ci sqp_ctx->pd = NULL; 22538c2ecf20Sopenharmony_ci ib_destroy_cq(sqp_ctx->cq); 22548c2ecf20Sopenharmony_ci sqp_ctx->cq = NULL; 22558c2ecf20Sopenharmony_ci sqp_ctx->state = DEMUX_PV_STATE_DOWN; 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci} 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_cistatic void mlx4_ib_free_demux_ctx(struct mlx4_ib_demux_ctx *ctx) 22608c2ecf20Sopenharmony_ci{ 22618c2ecf20Sopenharmony_ci int i; 22628c2ecf20Sopenharmony_ci if (ctx) { 22638c2ecf20Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 22648c2ecf20Sopenharmony_ci mlx4_ib_mcg_port_cleanup(ctx, 1); 22658c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 22668c2ecf20Sopenharmony_ci if (!ctx->tun[i]) 22678c2ecf20Sopenharmony_ci continue; 22688c2ecf20Sopenharmony_ci if (ctx->tun[i]->state > DEMUX_PV_STATE_DOWN) 22698c2ecf20Sopenharmony_ci ctx->tun[i]->state = DEMUX_PV_STATE_DOWNING; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci flush_workqueue(ctx->wq); 22728c2ecf20Sopenharmony_ci flush_workqueue(ctx->wi_wq); 22738c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 22748c2ecf20Sopenharmony_ci destroy_pv_resources(dev, i, ctx->port, ctx->tun[i], 0); 22758c2ecf20Sopenharmony_ci free_pv_object(dev, i, ctx->port); 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci kfree(ctx->tun); 22788c2ecf20Sopenharmony_ci destroy_workqueue(ctx->ud_wq); 22798c2ecf20Sopenharmony_ci destroy_workqueue(ctx->wi_wq); 22808c2ecf20Sopenharmony_ci destroy_workqueue(ctx->wq); 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci} 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_cistatic void mlx4_ib_master_tunnels(struct mlx4_ib_dev *dev, int do_init) 22858c2ecf20Sopenharmony_ci{ 22868c2ecf20Sopenharmony_ci int i; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 22898c2ecf20Sopenharmony_ci return; 22908c2ecf20Sopenharmony_ci /* initialize or tear down tunnel QPs for the master */ 22918c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.num_ports; i++) 22928c2ecf20Sopenharmony_ci mlx4_ib_tunnels_update(dev, mlx4_master_func_num(dev->dev), i + 1, do_init); 22938c2ecf20Sopenharmony_ci return; 22948c2ecf20Sopenharmony_ci} 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ciint mlx4_ib_init_sriov(struct mlx4_ib_dev *dev) 22978c2ecf20Sopenharmony_ci{ 22988c2ecf20Sopenharmony_ci int i = 0; 22998c2ecf20Sopenharmony_ci int err; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev)) 23028c2ecf20Sopenharmony_ci return 0; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci dev->sriov.is_going_down = 0; 23058c2ecf20Sopenharmony_ci spin_lock_init(&dev->sriov.going_down_lock); 23068c2ecf20Sopenharmony_ci mlx4_ib_cm_paravirt_init(dev); 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "multi-function enabled\n"); 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev->dev)) { 23118c2ecf20Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "operating in qp1 tunnel mode\n"); 23128c2ecf20Sopenharmony_ci return 0; 23138c2ecf20Sopenharmony_ci } 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 23168c2ecf20Sopenharmony_ci if (i == mlx4_master_func_num(dev->dev)) 23178c2ecf20Sopenharmony_ci mlx4_put_slave_node_guid(dev->dev, i, dev->ib_dev.node_guid); 23188c2ecf20Sopenharmony_ci else 23198c2ecf20Sopenharmony_ci mlx4_put_slave_node_guid(dev->dev, i, mlx4_ib_gen_node_guid()); 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci err = mlx4_ib_init_alias_guid_service(dev); 23238c2ecf20Sopenharmony_ci if (err) { 23248c2ecf20Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "Failed init alias guid process.\n"); 23258c2ecf20Sopenharmony_ci goto paravirt_err; 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci err = mlx4_ib_device_register_sysfs(dev); 23288c2ecf20Sopenharmony_ci if (err) { 23298c2ecf20Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "Failed to register sysfs\n"); 23308c2ecf20Sopenharmony_ci goto sysfs_err; 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n", 23348c2ecf20Sopenharmony_ci dev->dev->caps.sqp_demux); 23358c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_ports; i++) { 23368c2ecf20Sopenharmony_ci union ib_gid gid; 23378c2ecf20Sopenharmony_ci err = __mlx4_ib_query_gid(&dev->ib_dev, i + 1, 0, &gid, 1); 23388c2ecf20Sopenharmony_ci if (err) 23398c2ecf20Sopenharmony_ci goto demux_err; 23408c2ecf20Sopenharmony_ci dev->sriov.demux[i].guid_cache[0] = gid.global.interface_id; 23418c2ecf20Sopenharmony_ci atomic64_set(&dev->sriov.demux[i].subnet_prefix, 23428c2ecf20Sopenharmony_ci be64_to_cpu(gid.global.subnet_prefix)); 23438c2ecf20Sopenharmony_ci err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1, 23448c2ecf20Sopenharmony_ci &dev->sriov.sqps[i]); 23458c2ecf20Sopenharmony_ci if (err) 23468c2ecf20Sopenharmony_ci goto demux_err; 23478c2ecf20Sopenharmony_ci err = mlx4_ib_alloc_demux_ctx(dev, &dev->sriov.demux[i], i + 1); 23488c2ecf20Sopenharmony_ci if (err) 23498c2ecf20Sopenharmony_ci goto free_pv; 23508c2ecf20Sopenharmony_ci } 23518c2ecf20Sopenharmony_ci mlx4_ib_master_tunnels(dev, 1); 23528c2ecf20Sopenharmony_ci return 0; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_cifree_pv: 23558c2ecf20Sopenharmony_ci free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1); 23568c2ecf20Sopenharmony_cidemux_err: 23578c2ecf20Sopenharmony_ci while (--i >= 0) { 23588c2ecf20Sopenharmony_ci free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1); 23598c2ecf20Sopenharmony_ci mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci mlx4_ib_device_unregister_sysfs(dev); 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_cisysfs_err: 23648c2ecf20Sopenharmony_ci mlx4_ib_destroy_alias_guid_service(dev); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ciparavirt_err: 23678c2ecf20Sopenharmony_ci mlx4_ib_cm_paravirt_clean(dev, -1); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci return err; 23708c2ecf20Sopenharmony_ci} 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_civoid mlx4_ib_close_sriov(struct mlx4_ib_dev *dev) 23738c2ecf20Sopenharmony_ci{ 23748c2ecf20Sopenharmony_ci int i; 23758c2ecf20Sopenharmony_ci unsigned long flags; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev)) 23788c2ecf20Sopenharmony_ci return; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 23818c2ecf20Sopenharmony_ci dev->sriov.is_going_down = 1; 23828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 23838c2ecf20Sopenharmony_ci if (mlx4_is_master(dev->dev)) { 23848c2ecf20Sopenharmony_ci for (i = 0; i < dev->num_ports; i++) { 23858c2ecf20Sopenharmony_ci flush_workqueue(dev->sriov.demux[i].ud_wq); 23868c2ecf20Sopenharmony_ci mlx4_ib_free_sqp_ctx(dev->sriov.sqps[i]); 23878c2ecf20Sopenharmony_ci kfree(dev->sriov.sqps[i]); 23888c2ecf20Sopenharmony_ci dev->sriov.sqps[i] = NULL; 23898c2ecf20Sopenharmony_ci mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci mlx4_ib_cm_paravirt_clean(dev, -1); 23938c2ecf20Sopenharmony_ci mlx4_ib_destroy_alias_guid_service(dev); 23948c2ecf20Sopenharmony_ci mlx4_ib_device_unregister_sysfs(dev); 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci} 2397