162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <rdma/ib_mad.h> 3462306a36Sopenharmony_ci#include <rdma/ib_smi.h> 3562306a36Sopenharmony_ci#include <rdma/ib_sa.h> 3662306a36Sopenharmony_ci#include <rdma/ib_cache.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include <linux/random.h> 3962306a36Sopenharmony_ci#include <linux/mlx4/cmd.h> 4062306a36Sopenharmony_ci#include <linux/gfp.h> 4162306a36Sopenharmony_ci#include <rdma/ib_pma.h> 4262306a36Sopenharmony_ci#include <linux/ip.h> 4362306a36Sopenharmony_ci#include <net/ipv6.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <linux/mlx4/driver.h> 4662306a36Sopenharmony_ci#include "mlx4_ib.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cienum { 4962306a36Sopenharmony_ci MLX4_IB_VENDOR_CLASS1 = 0x9, 5062306a36Sopenharmony_ci MLX4_IB_VENDOR_CLASS2 = 0xa 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define MLX4_TUN_SEND_WRID_SHIFT 34 5462306a36Sopenharmony_ci#define MLX4_TUN_QPN_SHIFT 32 5562306a36Sopenharmony_ci#define MLX4_TUN_WRID_RECV (((u64) 1) << MLX4_TUN_SEND_WRID_SHIFT) 5662306a36Sopenharmony_ci#define MLX4_TUN_SET_WRID_QPN(a) (((u64) ((a) & 0x3)) << MLX4_TUN_QPN_SHIFT) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define MLX4_TUN_IS_RECV(a) (((a) >> MLX4_TUN_SEND_WRID_SHIFT) & 0x1) 5962306a36Sopenharmony_ci#define MLX4_TUN_WRID_QPN(a) (((a) >> MLX4_TUN_QPN_SHIFT) & 0x3) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Port mgmt change event handling */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define GET_BLK_PTR_FROM_EQE(eqe) be32_to_cpu(eqe->event.port_mgmt_change.params.tbl_change_info.block_ptr) 6462306a36Sopenharmony_ci#define GET_MASK_FROM_EQE(eqe) be32_to_cpu(eqe->event.port_mgmt_change.params.tbl_change_info.tbl_entries_mask) 6562306a36Sopenharmony_ci#define NUM_IDX_IN_PKEY_TBL_BLK 32 6662306a36Sopenharmony_ci#define GUID_TBL_ENTRY_SIZE 8 /* size in bytes */ 6762306a36Sopenharmony_ci#define GUID_TBL_BLK_NUM_ENTRIES 8 6862306a36Sopenharmony_ci#define GUID_TBL_BLK_SIZE (GUID_TBL_ENTRY_SIZE * GUID_TBL_BLK_NUM_ENTRIES) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistruct mlx4_mad_rcv_buf { 7162306a36Sopenharmony_ci struct ib_grh grh; 7262306a36Sopenharmony_ci u8 payload[256]; 7362306a36Sopenharmony_ci} __packed; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistruct mlx4_mad_snd_buf { 7662306a36Sopenharmony_ci u8 payload[256]; 7762306a36Sopenharmony_ci} __packed; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct mlx4_tunnel_mad { 8062306a36Sopenharmony_ci struct ib_grh grh; 8162306a36Sopenharmony_ci struct mlx4_ib_tunnel_header hdr; 8262306a36Sopenharmony_ci struct ib_mad mad; 8362306a36Sopenharmony_ci} __packed; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct mlx4_rcv_tunnel_mad { 8662306a36Sopenharmony_ci struct mlx4_rcv_tunnel_hdr hdr; 8762306a36Sopenharmony_ci struct ib_grh grh; 8862306a36Sopenharmony_ci struct ib_mad mad; 8962306a36Sopenharmony_ci} __packed; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void handle_client_rereg_event(struct mlx4_ib_dev *dev, u32 port_num); 9262306a36Sopenharmony_cistatic void handle_lid_change_event(struct mlx4_ib_dev *dev, u32 port_num); 9362306a36Sopenharmony_cistatic void __propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, 9462306a36Sopenharmony_ci int block, u32 change_bitmap); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci__be64 mlx4_ib_gen_node_guid(void) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci#define NODE_GUID_HI ((u64) (((u64)IB_OPENIB_OUI) << 40)) 9962306a36Sopenharmony_ci return cpu_to_be64(NODE_GUID_HI | get_random_u32()); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci__be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return cpu_to_be64(atomic_inc_return(&ctx->tid)) | 10562306a36Sopenharmony_ci cpu_to_be64(0xff00000000000000LL); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciint mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int mad_ifc_flags, 10962306a36Sopenharmony_ci int port, const struct ib_wc *in_wc, 11062306a36Sopenharmony_ci const struct ib_grh *in_grh, 11162306a36Sopenharmony_ci const void *in_mad, void *response_mad) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 11462306a36Sopenharmony_ci void *inbox; 11562306a36Sopenharmony_ci int err; 11662306a36Sopenharmony_ci u32 in_modifier = port; 11762306a36Sopenharmony_ci u8 op_modifier = 0; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci inmailbox = mlx4_alloc_cmd_mailbox(dev->dev); 12062306a36Sopenharmony_ci if (IS_ERR(inmailbox)) 12162306a36Sopenharmony_ci return PTR_ERR(inmailbox); 12262306a36Sopenharmony_ci inbox = inmailbox->buf; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci outmailbox = mlx4_alloc_cmd_mailbox(dev->dev); 12562306a36Sopenharmony_ci if (IS_ERR(outmailbox)) { 12662306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev->dev, inmailbox); 12762306a36Sopenharmony_ci return PTR_ERR(outmailbox); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci memcpy(inbox, in_mad, 256); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* 13362306a36Sopenharmony_ci * Key check traps can't be generated unless we have in_wc to 13462306a36Sopenharmony_ci * tell us where to send the trap. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci if ((mad_ifc_flags & MLX4_MAD_IFC_IGNORE_MKEY) || !in_wc) 13762306a36Sopenharmony_ci op_modifier |= 0x1; 13862306a36Sopenharmony_ci if ((mad_ifc_flags & MLX4_MAD_IFC_IGNORE_BKEY) || !in_wc) 13962306a36Sopenharmony_ci op_modifier |= 0x2; 14062306a36Sopenharmony_ci if (mlx4_is_mfunc(dev->dev) && 14162306a36Sopenharmony_ci (mad_ifc_flags & MLX4_MAD_IFC_NET_VIEW || in_wc)) 14262306a36Sopenharmony_ci op_modifier |= 0x8; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (in_wc) { 14562306a36Sopenharmony_ci struct { 14662306a36Sopenharmony_ci __be32 my_qpn; 14762306a36Sopenharmony_ci u32 reserved1; 14862306a36Sopenharmony_ci __be32 rqpn; 14962306a36Sopenharmony_ci u8 sl; 15062306a36Sopenharmony_ci u8 g_path; 15162306a36Sopenharmony_ci u16 reserved2[2]; 15262306a36Sopenharmony_ci __be16 pkey; 15362306a36Sopenharmony_ci u32 reserved3[11]; 15462306a36Sopenharmony_ci u8 grh[40]; 15562306a36Sopenharmony_ci } *ext_info; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci memset(inbox + 256, 0, 256); 15862306a36Sopenharmony_ci ext_info = inbox + 256; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num); 16162306a36Sopenharmony_ci ext_info->rqpn = cpu_to_be32(in_wc->src_qp); 16262306a36Sopenharmony_ci ext_info->sl = in_wc->sl << 4; 16362306a36Sopenharmony_ci ext_info->g_path = in_wc->dlid_path_bits | 16462306a36Sopenharmony_ci (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0); 16562306a36Sopenharmony_ci ext_info->pkey = cpu_to_be16(in_wc->pkey_index); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (in_grh) 16862306a36Sopenharmony_ci memcpy(ext_info->grh, in_grh, 40); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci op_modifier |= 0x4; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci in_modifier |= ib_lid_cpu16(in_wc->slid) << 16; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma, in_modifier, 17662306a36Sopenharmony_ci mlx4_is_master(dev->dev) ? (op_modifier & ~0x8) : op_modifier, 17762306a36Sopenharmony_ci MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 17862306a36Sopenharmony_ci (op_modifier & 0x8) ? MLX4_CMD_NATIVE : MLX4_CMD_WRAPPED); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (!err) 18162306a36Sopenharmony_ci memcpy(response_mad, outmailbox->buf, 256); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev->dev, inmailbox); 18462306a36Sopenharmony_ci mlx4_free_cmd_mailbox(dev->dev, outmailbox); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return err; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void update_sm_ah(struct mlx4_ib_dev *dev, u32 port_num, u16 lid, u8 sl) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct ib_ah *new_ah; 19262306a36Sopenharmony_ci struct rdma_ah_attr ah_attr; 19362306a36Sopenharmony_ci unsigned long flags; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (!dev->send_agent[port_num - 1][0]) 19662306a36Sopenharmony_ci return; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci memset(&ah_attr, 0, sizeof ah_attr); 19962306a36Sopenharmony_ci ah_attr.type = rdma_ah_find_type(&dev->ib_dev, port_num); 20062306a36Sopenharmony_ci rdma_ah_set_dlid(&ah_attr, lid); 20162306a36Sopenharmony_ci rdma_ah_set_sl(&ah_attr, sl); 20262306a36Sopenharmony_ci rdma_ah_set_port_num(&ah_attr, port_num); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci new_ah = rdma_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, 20562306a36Sopenharmony_ci &ah_attr, 0); 20662306a36Sopenharmony_ci if (IS_ERR(new_ah)) 20762306a36Sopenharmony_ci return; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci spin_lock_irqsave(&dev->sm_lock, flags); 21062306a36Sopenharmony_ci if (dev->sm_ah[port_num - 1]) 21162306a36Sopenharmony_ci rdma_destroy_ah(dev->sm_ah[port_num - 1], 0); 21262306a36Sopenharmony_ci dev->sm_ah[port_num - 1] = new_ah; 21362306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sm_lock, flags); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* 21762306a36Sopenharmony_ci * Snoop SM MADs for port info, GUID info, and P_Key table sets, so we can 21862306a36Sopenharmony_ci * synthesize LID change, Client-Rereg, GID change, and P_Key change events. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_cistatic void smp_snoop(struct ib_device *ibdev, u32 port_num, 22162306a36Sopenharmony_ci const struct ib_mad *mad, u16 prev_lid) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct ib_port_info *pinfo; 22462306a36Sopenharmony_ci u16 lid; 22562306a36Sopenharmony_ci __be16 *base; 22662306a36Sopenharmony_ci u32 bn, pkey_change_bitmap; 22762306a36Sopenharmony_ci int i; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 23162306a36Sopenharmony_ci if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 23262306a36Sopenharmony_ci mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 23362306a36Sopenharmony_ci mad->mad_hdr.method == IB_MGMT_METHOD_SET) 23462306a36Sopenharmony_ci switch (mad->mad_hdr.attr_id) { 23562306a36Sopenharmony_ci case IB_SMP_ATTR_PORT_INFO: 23662306a36Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) 23762306a36Sopenharmony_ci return; 23862306a36Sopenharmony_ci pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data; 23962306a36Sopenharmony_ci lid = be16_to_cpu(pinfo->lid); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci update_sm_ah(dev, port_num, 24262306a36Sopenharmony_ci be16_to_cpu(pinfo->sm_lid), 24362306a36Sopenharmony_ci pinfo->neighbormtu_mastersmsl & 0xf); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (pinfo->clientrereg_resv_subnetto & 0x80) 24662306a36Sopenharmony_ci handle_client_rereg_event(dev, port_num); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (prev_lid != lid) 24962306a36Sopenharmony_ci handle_lid_change_event(dev, port_num); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci case IB_SMP_ATTR_PKEY_TABLE: 25362306a36Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) 25462306a36Sopenharmony_ci return; 25562306a36Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev)) { 25662306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, 25762306a36Sopenharmony_ci IB_EVENT_PKEY_CHANGE); 25862306a36Sopenharmony_ci break; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* at this point, we are running in the master. 26262306a36Sopenharmony_ci * Slaves do not receive SMPs. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci bn = be32_to_cpu(((struct ib_smp *)mad)->attr_mod) & 0xFFFF; 26562306a36Sopenharmony_ci base = (__be16 *) &(((struct ib_smp *)mad)->data[0]); 26662306a36Sopenharmony_ci pkey_change_bitmap = 0; 26762306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 26862306a36Sopenharmony_ci pr_debug("PKEY[%d] = x%x\n", 26962306a36Sopenharmony_ci i + bn*32, be16_to_cpu(base[i])); 27062306a36Sopenharmony_ci if (be16_to_cpu(base[i]) != 27162306a36Sopenharmony_ci dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32]) { 27262306a36Sopenharmony_ci pkey_change_bitmap |= (1 << i); 27362306a36Sopenharmony_ci dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32] = 27462306a36Sopenharmony_ci be16_to_cpu(base[i]); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci pr_debug("PKEY Change event: port=%u, " 27862306a36Sopenharmony_ci "block=0x%x, change_bitmap=0x%x\n", 27962306a36Sopenharmony_ci port_num, bn, pkey_change_bitmap); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (pkey_change_bitmap) { 28262306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, 28362306a36Sopenharmony_ci IB_EVENT_PKEY_CHANGE); 28462306a36Sopenharmony_ci if (!dev->sriov.is_going_down) 28562306a36Sopenharmony_ci __propagate_pkey_ev(dev, port_num, bn, 28662306a36Sopenharmony_ci pkey_change_bitmap); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci case IB_SMP_ATTR_GUID_INFO: 29162306a36Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) 29262306a36Sopenharmony_ci return; 29362306a36Sopenharmony_ci /* paravirtualized master's guid is guid 0 -- does not change */ 29462306a36Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 29562306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, 29662306a36Sopenharmony_ci IB_EVENT_GID_CHANGE); 29762306a36Sopenharmony_ci /*if master, notify relevant slaves*/ 29862306a36Sopenharmony_ci if (mlx4_is_master(dev->dev) && 29962306a36Sopenharmony_ci !dev->sriov.is_going_down) { 30062306a36Sopenharmony_ci bn = be32_to_cpu(((struct ib_smp *)mad)->attr_mod); 30162306a36Sopenharmony_ci mlx4_ib_update_cache_on_guid_change(dev, bn, port_num, 30262306a36Sopenharmony_ci (u8 *)(&((struct ib_smp *)mad)->data)); 30362306a36Sopenharmony_ci mlx4_ib_notify_slaves_on_guid_change(dev, bn, port_num, 30462306a36Sopenharmony_ci (u8 *)(&((struct ib_smp *)mad)->data)); 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci case IB_SMP_ATTR_SL_TO_VL_TABLE: 30962306a36Sopenharmony_ci /* cache sl to vl mapping changes for use in 31062306a36Sopenharmony_ci * filling QP1 LRH VL field when sending packets 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci if (dev->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV && 31362306a36Sopenharmony_ci dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT) 31462306a36Sopenharmony_ci return; 31562306a36Sopenharmony_ci if (!mlx4_is_slave(dev->dev)) { 31662306a36Sopenharmony_ci union sl2vl_tbl_to_u64 sl2vl64; 31762306a36Sopenharmony_ci int jj; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci for (jj = 0; jj < 8; jj++) { 32062306a36Sopenharmony_ci sl2vl64.sl8[jj] = ((struct ib_smp *)mad)->data[jj]; 32162306a36Sopenharmony_ci pr_debug("port %u, sl2vl[%d] = %02x\n", 32262306a36Sopenharmony_ci port_num, jj, sl2vl64.sl8[jj]); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci atomic64_set(&dev->sl2vl[port_num - 1], sl2vl64.sl64); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci default: 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic void __propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, 33462306a36Sopenharmony_ci int block, u32 change_bitmap) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int i, ix, slave, err; 33762306a36Sopenharmony_ci int have_event = 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci for (slave = 0; slave < dev->dev->caps.sqp_demux; slave++) { 34062306a36Sopenharmony_ci if (slave == mlx4_master_func_num(dev->dev)) 34162306a36Sopenharmony_ci continue; 34262306a36Sopenharmony_ci if (!mlx4_is_slave_active(dev->dev, slave)) 34362306a36Sopenharmony_ci continue; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci have_event = 0; 34662306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 34762306a36Sopenharmony_ci if (!(change_bitmap & (1 << i))) 34862306a36Sopenharmony_ci continue; 34962306a36Sopenharmony_ci for (ix = 0; 35062306a36Sopenharmony_ci ix < dev->dev->caps.pkey_table_len[port_num]; ix++) { 35162306a36Sopenharmony_ci if (dev->pkeys.virt2phys_pkey[slave][port_num - 1] 35262306a36Sopenharmony_ci [ix] == i + 32 * block) { 35362306a36Sopenharmony_ci err = mlx4_gen_pkey_eqe(dev->dev, slave, port_num); 35462306a36Sopenharmony_ci pr_debug("propagate_pkey_ev: slave %d," 35562306a36Sopenharmony_ci " port %d, ix %d (%d)\n", 35662306a36Sopenharmony_ci slave, port_num, ix, err); 35762306a36Sopenharmony_ci have_event = 1; 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci if (have_event) 36262306a36Sopenharmony_ci break; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic void node_desc_override(struct ib_device *dev, 36862306a36Sopenharmony_ci struct ib_mad *mad) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci unsigned long flags; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 37362306a36Sopenharmony_ci mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 37462306a36Sopenharmony_ci mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 37562306a36Sopenharmony_ci mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 37662306a36Sopenharmony_ci spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags); 37762306a36Sopenharmony_ci memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 37862306a36Sopenharmony_ci IB_DEVICE_NODE_DESC_MAX); 37962306a36Sopenharmony_ci spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic void forward_trap(struct mlx4_ib_dev *dev, u32 port_num, 38462306a36Sopenharmony_ci const struct ib_mad *mad) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 38762306a36Sopenharmony_ci struct ib_mad_send_buf *send_buf; 38862306a36Sopenharmony_ci struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 38962306a36Sopenharmony_ci int ret; 39062306a36Sopenharmony_ci unsigned long flags; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (agent) { 39362306a36Sopenharmony_ci send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 39462306a36Sopenharmony_ci IB_MGMT_MAD_DATA, GFP_ATOMIC, 39562306a36Sopenharmony_ci IB_MGMT_BASE_VERSION); 39662306a36Sopenharmony_ci if (IS_ERR(send_buf)) 39762306a36Sopenharmony_ci return; 39862306a36Sopenharmony_ci /* 39962306a36Sopenharmony_ci * We rely here on the fact that MLX QPs don't use the 40062306a36Sopenharmony_ci * address handle after the send is posted (this is 40162306a36Sopenharmony_ci * wrong following the IB spec strictly, but we know 40262306a36Sopenharmony_ci * it's OK for our devices). 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci spin_lock_irqsave(&dev->sm_lock, flags); 40562306a36Sopenharmony_ci memcpy(send_buf->mad, mad, sizeof *mad); 40662306a36Sopenharmony_ci if ((send_buf->ah = dev->sm_ah[port_num - 1])) 40762306a36Sopenharmony_ci ret = ib_post_send_mad(send_buf, NULL); 40862306a36Sopenharmony_ci else 40962306a36Sopenharmony_ci ret = -EINVAL; 41062306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sm_lock, flags); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (ret) 41362306a36Sopenharmony_ci ib_free_send_mad(send_buf); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic int mlx4_ib_demux_sa_handler(struct ib_device *ibdev, int port, int slave, 41862306a36Sopenharmony_ci struct ib_sa_mad *sa_mad) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci int ret = 0; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* dispatch to different sa handlers */ 42362306a36Sopenharmony_ci switch (be16_to_cpu(sa_mad->mad_hdr.attr_id)) { 42462306a36Sopenharmony_ci case IB_SA_ATTR_MC_MEMBER_REC: 42562306a36Sopenharmony_ci ret = mlx4_ib_mcg_demux_handler(ibdev, port, slave, sa_mad); 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci default: 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci return ret; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ciint mlx4_ib_find_real_gid(struct ib_device *ibdev, u32 port, __be64 guid) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 43662306a36Sopenharmony_ci int i; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 43962306a36Sopenharmony_ci if (dev->sriov.demux[port - 1].guid_cache[i] == guid) 44062306a36Sopenharmony_ci return i; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci return -1; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int find_slave_port_pkey_ix(struct mlx4_ib_dev *dev, int slave, 44762306a36Sopenharmony_ci u32 port, u16 pkey, u16 *ix) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci int i, ret; 45062306a36Sopenharmony_ci u8 unassigned_pkey_ix, pkey_ix, partial_ix = 0xFF; 45162306a36Sopenharmony_ci u16 slot_pkey; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (slave == mlx4_master_func_num(dev->dev)) 45462306a36Sopenharmony_ci return ib_find_cached_pkey(&dev->ib_dev, port, pkey, ix); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci unassigned_pkey_ix = dev->dev->phys_caps.pkey_phys_table_len[port] - 1; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci for (i = 0; i < dev->dev->caps.pkey_table_len[port]; i++) { 45962306a36Sopenharmony_ci if (dev->pkeys.virt2phys_pkey[slave][port - 1][i] == unassigned_pkey_ix) 46062306a36Sopenharmony_ci continue; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][i]; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci ret = ib_get_cached_pkey(&dev->ib_dev, port, pkey_ix, &slot_pkey); 46562306a36Sopenharmony_ci if (ret) 46662306a36Sopenharmony_ci continue; 46762306a36Sopenharmony_ci if ((slot_pkey & 0x7FFF) == (pkey & 0x7FFF)) { 46862306a36Sopenharmony_ci if (slot_pkey & 0x8000) { 46962306a36Sopenharmony_ci *ix = (u16) pkey_ix; 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci } else { 47262306a36Sopenharmony_ci /* take first partial pkey index found */ 47362306a36Sopenharmony_ci if (partial_ix == 0xFF) 47462306a36Sopenharmony_ci partial_ix = pkey_ix; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (partial_ix < 0xFF) { 48062306a36Sopenharmony_ci *ix = (u16) partial_ix; 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int get_gids_from_l3_hdr(struct ib_grh *grh, union ib_gid *sgid, 48862306a36Sopenharmony_ci union ib_gid *dgid) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci int version = ib_get_rdma_header_version((const union rdma_network_hdr *)grh); 49162306a36Sopenharmony_ci enum rdma_network_type net_type; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (version == 4) 49462306a36Sopenharmony_ci net_type = RDMA_NETWORK_IPV4; 49562306a36Sopenharmony_ci else if (version == 6) 49662306a36Sopenharmony_ci net_type = RDMA_NETWORK_IPV6; 49762306a36Sopenharmony_ci else 49862306a36Sopenharmony_ci return -EINVAL; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return ib_get_gids_from_rdma_hdr((union rdma_network_hdr *)grh, net_type, 50162306a36Sopenharmony_ci sgid, dgid); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci int proxy_start = dev->dev->phys_caps.base_proxy_sqpn + 8 * slave; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci return (qpn >= proxy_start && qpn <= proxy_start + 1); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ciint mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u32 port, 51262306a36Sopenharmony_ci enum ib_qp_type dest_qpt, struct ib_wc *wc, 51362306a36Sopenharmony_ci struct ib_grh *grh, struct ib_mad *mad) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct ib_sge list; 51662306a36Sopenharmony_ci struct ib_ud_wr wr; 51762306a36Sopenharmony_ci const struct ib_send_wr *bad_wr; 51862306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *tun_ctx; 51962306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 52062306a36Sopenharmony_ci struct mlx4_rcv_tunnel_mad *tun_mad; 52162306a36Sopenharmony_ci struct rdma_ah_attr attr; 52262306a36Sopenharmony_ci struct ib_ah *ah; 52362306a36Sopenharmony_ci struct ib_qp *src_qp = NULL; 52462306a36Sopenharmony_ci unsigned tun_tx_ix = 0; 52562306a36Sopenharmony_ci int dqpn; 52662306a36Sopenharmony_ci int ret = 0; 52762306a36Sopenharmony_ci u16 tun_pkey_ix; 52862306a36Sopenharmony_ci u16 cached_pkey; 52962306a36Sopenharmony_ci u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (dest_qpt > IB_QPT_GSI) { 53262306a36Sopenharmony_ci pr_debug("dest_qpt (%d) > IB_QPT_GSI\n", dest_qpt); 53362306a36Sopenharmony_ci return -EINVAL; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci tun_ctx = dev->sriov.demux[port-1].tun[slave]; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* check if proxy qp created */ 53962306a36Sopenharmony_ci if (!tun_ctx || tun_ctx->state != DEMUX_PV_STATE_ACTIVE) 54062306a36Sopenharmony_ci return -EAGAIN; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (!dest_qpt) 54362306a36Sopenharmony_ci tun_qp = &tun_ctx->qp[0]; 54462306a36Sopenharmony_ci else 54562306a36Sopenharmony_ci tun_qp = &tun_ctx->qp[1]; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* compute P_Key index to put in tunnel header for slave */ 54862306a36Sopenharmony_ci if (dest_qpt) { 54962306a36Sopenharmony_ci u16 pkey_ix; 55062306a36Sopenharmony_ci ret = ib_get_cached_pkey(&dev->ib_dev, port, wc->pkey_index, &cached_pkey); 55162306a36Sopenharmony_ci if (ret) { 55262306a36Sopenharmony_ci pr_debug("unable to get %s cached pkey for index %d, ret %d\n", 55362306a36Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 55462306a36Sopenharmony_ci wc->pkey_index, ret); 55562306a36Sopenharmony_ci return -EINVAL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci ret = find_slave_port_pkey_ix(dev, slave, port, cached_pkey, &pkey_ix); 55962306a36Sopenharmony_ci if (ret) { 56062306a36Sopenharmony_ci pr_debug("unable to get %s pkey ix for pkey 0x%x, ret %d\n", 56162306a36Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 56262306a36Sopenharmony_ci cached_pkey, ret); 56362306a36Sopenharmony_ci return -EINVAL; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci tun_pkey_ix = pkey_ix; 56662306a36Sopenharmony_ci } else 56762306a36Sopenharmony_ci tun_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][0]; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci dqpn = dev->dev->phys_caps.base_proxy_sqpn + 8 * slave + port + (dest_qpt * 2) - 1; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* get tunnel tx data buf for slave */ 57262306a36Sopenharmony_ci src_qp = tun_qp->qp; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* create ah. Just need an empty one with the port num for the post send. 57562306a36Sopenharmony_ci * The driver will set the force loopback bit in post_send */ 57662306a36Sopenharmony_ci memset(&attr, 0, sizeof attr); 57762306a36Sopenharmony_ci attr.type = rdma_ah_find_type(&dev->ib_dev, port); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci rdma_ah_set_port_num(&attr, port); 58062306a36Sopenharmony_ci if (is_eth) { 58162306a36Sopenharmony_ci union ib_gid sgid; 58262306a36Sopenharmony_ci union ib_gid dgid; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (get_gids_from_l3_hdr(grh, &sgid, &dgid)) 58562306a36Sopenharmony_ci return -EINVAL; 58662306a36Sopenharmony_ci rdma_ah_set_grh(&attr, &dgid, 0, 0, 0, 0); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci ah = rdma_create_ah(tun_ctx->pd, &attr, 0); 58962306a36Sopenharmony_ci if (IS_ERR(ah)) 59062306a36Sopenharmony_ci return -ENOMEM; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* allocate tunnel tx buf after pass failure returns */ 59362306a36Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 59462306a36Sopenharmony_ci if (tun_qp->tx_ix_head - tun_qp->tx_ix_tail >= 59562306a36Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)) 59662306a36Sopenharmony_ci ret = -EAGAIN; 59762306a36Sopenharmony_ci else 59862306a36Sopenharmony_ci tun_tx_ix = (++tun_qp->tx_ix_head) & (MLX4_NUM_TUNNEL_BUFS - 1); 59962306a36Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 60062306a36Sopenharmony_ci if (ret) 60162306a36Sopenharmony_ci goto end; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci tun_mad = (struct mlx4_rcv_tunnel_mad *) (tun_qp->tx_ring[tun_tx_ix].buf.addr); 60462306a36Sopenharmony_ci if (tun_qp->tx_ring[tun_tx_ix].ah) 60562306a36Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[tun_tx_ix].ah, 0); 60662306a36Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].ah = ah; 60762306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(&dev->ib_dev, 60862306a36Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].buf.map, 60962306a36Sopenharmony_ci sizeof (struct mlx4_rcv_tunnel_mad), 61062306a36Sopenharmony_ci DMA_TO_DEVICE); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* copy over to tunnel buffer */ 61362306a36Sopenharmony_ci if (grh) 61462306a36Sopenharmony_ci memcpy(&tun_mad->grh, grh, sizeof *grh); 61562306a36Sopenharmony_ci memcpy(&tun_mad->mad, mad, sizeof *mad); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* adjust tunnel data */ 61862306a36Sopenharmony_ci tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix); 61962306a36Sopenharmony_ci tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF); 62062306a36Sopenharmony_ci tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (is_eth) { 62362306a36Sopenharmony_ci u16 vlan = 0; 62462306a36Sopenharmony_ci if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan, 62562306a36Sopenharmony_ci NULL)) { 62662306a36Sopenharmony_ci /* VST mode */ 62762306a36Sopenharmony_ci if (vlan != wc->vlan_id) 62862306a36Sopenharmony_ci /* Packet vlan is not the VST-assigned vlan. 62962306a36Sopenharmony_ci * Drop the packet. 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_ci goto out; 63262306a36Sopenharmony_ci else 63362306a36Sopenharmony_ci /* Remove the vlan tag before forwarding 63462306a36Sopenharmony_ci * the packet to the VF. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci vlan = 0xffff; 63762306a36Sopenharmony_ci } else { 63862306a36Sopenharmony_ci vlan = wc->vlan_id; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci tun_mad->hdr.sl_vid = cpu_to_be16(vlan); 64262306a36Sopenharmony_ci memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4); 64362306a36Sopenharmony_ci memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2); 64462306a36Sopenharmony_ci } else { 64562306a36Sopenharmony_ci tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12); 64662306a36Sopenharmony_ci tun_mad->hdr.slid_mac_47_32 = ib_lid_be16(wc->slid); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci ib_dma_sync_single_for_device(&dev->ib_dev, 65062306a36Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].buf.map, 65162306a36Sopenharmony_ci sizeof (struct mlx4_rcv_tunnel_mad), 65262306a36Sopenharmony_ci DMA_TO_DEVICE); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci list.addr = tun_qp->tx_ring[tun_tx_ix].buf.map; 65562306a36Sopenharmony_ci list.length = sizeof (struct mlx4_rcv_tunnel_mad); 65662306a36Sopenharmony_ci list.lkey = tun_ctx->pd->local_dma_lkey; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci wr.ah = ah; 65962306a36Sopenharmony_ci wr.port_num = port; 66062306a36Sopenharmony_ci wr.remote_qkey = IB_QP_SET_QKEY; 66162306a36Sopenharmony_ci wr.remote_qpn = dqpn; 66262306a36Sopenharmony_ci wr.wr.next = NULL; 66362306a36Sopenharmony_ci wr.wr.wr_id = ((u64) tun_tx_ix) | MLX4_TUN_SET_WRID_QPN(dest_qpt); 66462306a36Sopenharmony_ci wr.wr.sg_list = &list; 66562306a36Sopenharmony_ci wr.wr.num_sge = 1; 66662306a36Sopenharmony_ci wr.wr.opcode = IB_WR_SEND; 66762306a36Sopenharmony_ci wr.wr.send_flags = IB_SEND_SIGNALED; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci ret = ib_post_send(src_qp, &wr.wr, &bad_wr); 67062306a36Sopenharmony_ci if (!ret) 67162306a36Sopenharmony_ci return 0; 67262306a36Sopenharmony_ci out: 67362306a36Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 67462306a36Sopenharmony_ci tun_qp->tx_ix_tail++; 67562306a36Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 67662306a36Sopenharmony_ci tun_qp->tx_ring[tun_tx_ix].ah = NULL; 67762306a36Sopenharmony_ciend: 67862306a36Sopenharmony_ci rdma_destroy_ah(ah, 0); 67962306a36Sopenharmony_ci return ret; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int mlx4_ib_demux_mad(struct ib_device *ibdev, u32 port, 68362306a36Sopenharmony_ci struct ib_wc *wc, struct ib_grh *grh, 68462306a36Sopenharmony_ci struct ib_mad *mad) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 68762306a36Sopenharmony_ci int err, other_port; 68862306a36Sopenharmony_ci int slave = -1; 68962306a36Sopenharmony_ci u8 *slave_id; 69062306a36Sopenharmony_ci int is_eth = 0; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) 69362306a36Sopenharmony_ci is_eth = 0; 69462306a36Sopenharmony_ci else 69562306a36Sopenharmony_ci is_eth = 1; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (is_eth) { 69862306a36Sopenharmony_ci union ib_gid dgid; 69962306a36Sopenharmony_ci union ib_gid sgid; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (get_gids_from_l3_hdr(grh, &sgid, &dgid)) 70262306a36Sopenharmony_ci return -EINVAL; 70362306a36Sopenharmony_ci if (!(wc->wc_flags & IB_WC_GRH)) { 70462306a36Sopenharmony_ci mlx4_ib_warn(ibdev, "RoCE grh not present.\n"); 70562306a36Sopenharmony_ci return -EINVAL; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) { 70862306a36Sopenharmony_ci mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n"); 70962306a36Sopenharmony_ci return -EINVAL; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci err = mlx4_get_slave_from_roce_gid(dev->dev, port, dgid.raw, &slave); 71262306a36Sopenharmony_ci if (err && mlx4_is_mf_bonded(dev->dev)) { 71362306a36Sopenharmony_ci other_port = (port == 1) ? 2 : 1; 71462306a36Sopenharmony_ci err = mlx4_get_slave_from_roce_gid(dev->dev, other_port, dgid.raw, &slave); 71562306a36Sopenharmony_ci if (!err) { 71662306a36Sopenharmony_ci port = other_port; 71762306a36Sopenharmony_ci pr_debug("resolved slave %d from gid %pI6 wire port %d other %d\n", 71862306a36Sopenharmony_ci slave, grh->dgid.raw, port, other_port); 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci if (err) { 72262306a36Sopenharmony_ci mlx4_ib_warn(ibdev, "failed matching grh\n"); 72362306a36Sopenharmony_ci return -ENOENT; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci if (slave >= dev->dev->caps.sqp_demux) { 72662306a36Sopenharmony_ci mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", 72762306a36Sopenharmony_ci slave, dev->dev->caps.sqp_demux); 72862306a36Sopenharmony_ci return -ENOENT; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (mlx4_ib_demux_cm_handler(ibdev, port, NULL, mad)) 73262306a36Sopenharmony_ci return 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); 73562306a36Sopenharmony_ci if (err) 73662306a36Sopenharmony_ci pr_debug("failed sending %s to slave %d via tunnel qp (%d)\n", 73762306a36Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 73862306a36Sopenharmony_ci slave, err); 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* Initially assume that this mad is for us */ 74362306a36Sopenharmony_ci slave = mlx4_master_func_num(dev->dev); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* See if the slave id is encoded in a response mad */ 74662306a36Sopenharmony_ci if (mad->mad_hdr.method & 0x80) { 74762306a36Sopenharmony_ci slave_id = (u8 *) &mad->mad_hdr.tid; 74862306a36Sopenharmony_ci slave = *slave_id; 74962306a36Sopenharmony_ci if (slave != 255) /*255 indicates the dom0*/ 75062306a36Sopenharmony_ci *slave_id = 0; /* remap tid */ 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* If a grh is present, we demux according to it */ 75462306a36Sopenharmony_ci if (wc->wc_flags & IB_WC_GRH) { 75562306a36Sopenharmony_ci if (grh->dgid.global.interface_id == 75662306a36Sopenharmony_ci cpu_to_be64(IB_SA_WELL_KNOWN_GUID) && 75762306a36Sopenharmony_ci grh->dgid.global.subnet_prefix == cpu_to_be64( 75862306a36Sopenharmony_ci atomic64_read(&dev->sriov.demux[port - 1].subnet_prefix))) { 75962306a36Sopenharmony_ci slave = 0; 76062306a36Sopenharmony_ci } else { 76162306a36Sopenharmony_ci slave = mlx4_ib_find_real_gid(ibdev, port, 76262306a36Sopenharmony_ci grh->dgid.global.interface_id); 76362306a36Sopenharmony_ci if (slave < 0) { 76462306a36Sopenharmony_ci mlx4_ib_warn(ibdev, "failed matching grh\n"); 76562306a36Sopenharmony_ci return -ENOENT; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci /* Class-specific handling */ 77062306a36Sopenharmony_ci switch (mad->mad_hdr.mgmt_class) { 77162306a36Sopenharmony_ci case IB_MGMT_CLASS_SUBN_LID_ROUTED: 77262306a36Sopenharmony_ci case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 77362306a36Sopenharmony_ci /* 255 indicates the dom0 */ 77462306a36Sopenharmony_ci if (slave != 255 && slave != mlx4_master_func_num(dev->dev)) { 77562306a36Sopenharmony_ci if (!mlx4_vf_smi_enabled(dev->dev, slave, port)) 77662306a36Sopenharmony_ci return -EPERM; 77762306a36Sopenharmony_ci /* for a VF. drop unsolicited MADs */ 77862306a36Sopenharmony_ci if (!(mad->mad_hdr.method & IB_MGMT_METHOD_RESP)) { 77962306a36Sopenharmony_ci mlx4_ib_warn(ibdev, "demux QP0. rejecting unsolicited mad for slave %d class 0x%x, method 0x%x\n", 78062306a36Sopenharmony_ci slave, mad->mad_hdr.mgmt_class, 78162306a36Sopenharmony_ci mad->mad_hdr.method); 78262306a36Sopenharmony_ci return -EINVAL; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci case IB_MGMT_CLASS_SUBN_ADM: 78762306a36Sopenharmony_ci if (mlx4_ib_demux_sa_handler(ibdev, port, slave, 78862306a36Sopenharmony_ci (struct ib_sa_mad *) mad)) 78962306a36Sopenharmony_ci return 0; 79062306a36Sopenharmony_ci break; 79162306a36Sopenharmony_ci case IB_MGMT_CLASS_CM: 79262306a36Sopenharmony_ci if (mlx4_ib_demux_cm_handler(ibdev, port, &slave, mad)) 79362306a36Sopenharmony_ci return 0; 79462306a36Sopenharmony_ci break; 79562306a36Sopenharmony_ci case IB_MGMT_CLASS_DEVICE_MGMT: 79662306a36Sopenharmony_ci if (mad->mad_hdr.method != IB_MGMT_METHOD_GET_RESP) 79762306a36Sopenharmony_ci return 0; 79862306a36Sopenharmony_ci break; 79962306a36Sopenharmony_ci default: 80062306a36Sopenharmony_ci /* Drop unsupported classes for slaves in tunnel mode */ 80162306a36Sopenharmony_ci if (slave != mlx4_master_func_num(dev->dev)) { 80262306a36Sopenharmony_ci pr_debug("dropping unsupported ingress mad from class:%d " 80362306a36Sopenharmony_ci "for slave:%d\n", mad->mad_hdr.mgmt_class, slave); 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci /*make sure that no slave==255 was not handled yet.*/ 80862306a36Sopenharmony_ci if (slave >= dev->dev->caps.sqp_demux) { 80962306a36Sopenharmony_ci mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", 81062306a36Sopenharmony_ci slave, dev->dev->caps.sqp_demux); 81162306a36Sopenharmony_ci return -ENOENT; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); 81562306a36Sopenharmony_ci if (err) 81662306a36Sopenharmony_ci pr_debug("failed sending %s to slave %d via tunnel qp (%d)\n", 81762306a36Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 81862306a36Sopenharmony_ci slave, err); 81962306a36Sopenharmony_ci return 0; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic int ib_process_mad(struct ib_device *ibdev, int mad_flags, u32 port_num, 82362306a36Sopenharmony_ci const struct ib_wc *in_wc, const struct ib_grh *in_grh, 82462306a36Sopenharmony_ci const struct ib_mad *in_mad, struct ib_mad *out_mad) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci u16 slid, prev_lid = 0; 82762306a36Sopenharmony_ci int err; 82862306a36Sopenharmony_ci struct ib_port_attr pattr; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci slid = in_wc ? ib_lid_cpu16(in_wc->slid) : be16_to_cpu(IB_LID_PERMISSIVE); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) { 83362306a36Sopenharmony_ci forward_trap(to_mdev(ibdev), port_num, in_mad); 83462306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 83862306a36Sopenharmony_ci in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 83962306a36Sopenharmony_ci if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 84062306a36Sopenharmony_ci in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 84162306a36Sopenharmony_ci in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 84262306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* 84562306a36Sopenharmony_ci * Don't process SMInfo queries -- the SMA can't handle them. 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_ci if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) 84862306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 84962306a36Sopenharmony_ci } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 85062306a36Sopenharmony_ci in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || 85162306a36Sopenharmony_ci in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2 || 85262306a36Sopenharmony_ci in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) { 85362306a36Sopenharmony_ci if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 85462306a36Sopenharmony_ci in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 85562306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 85662306a36Sopenharmony_ci } else 85762306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 86062306a36Sopenharmony_ci in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 86162306a36Sopenharmony_ci in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && 86262306a36Sopenharmony_ci in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 86362306a36Sopenharmony_ci !ib_query_port(ibdev, port_num, &pattr)) 86462306a36Sopenharmony_ci prev_lid = ib_lid_cpu16(pattr.lid); 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci err = mlx4_MAD_IFC(to_mdev(ibdev), 86762306a36Sopenharmony_ci (mad_flags & IB_MAD_IGNORE_MKEY ? MLX4_MAD_IFC_IGNORE_MKEY : 0) | 86862306a36Sopenharmony_ci (mad_flags & IB_MAD_IGNORE_BKEY ? MLX4_MAD_IFC_IGNORE_BKEY : 0) | 86962306a36Sopenharmony_ci MLX4_MAD_IFC_NET_VIEW, 87062306a36Sopenharmony_ci port_num, in_wc, in_grh, in_mad, out_mad); 87162306a36Sopenharmony_ci if (err) 87262306a36Sopenharmony_ci return IB_MAD_RESULT_FAILURE; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (!out_mad->mad_hdr.status) { 87562306a36Sopenharmony_ci smp_snoop(ibdev, port_num, in_mad, prev_lid); 87662306a36Sopenharmony_ci /* slaves get node desc from FW */ 87762306a36Sopenharmony_ci if (!mlx4_is_slave(to_mdev(ibdev)->dev)) 87862306a36Sopenharmony_ci node_desc_override(ibdev, out_mad); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci /* set return bit in status of directed route responses */ 88262306a36Sopenharmony_ci if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 88362306a36Sopenharmony_ci out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 88662306a36Sopenharmony_ci /* no response for trap repress */ 88762306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic void edit_counter(struct mlx4_counter *cnt, void *counters, 89362306a36Sopenharmony_ci __be16 attr_id) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci switch (attr_id) { 89662306a36Sopenharmony_ci case IB_PMA_PORT_COUNTERS: 89762306a36Sopenharmony_ci { 89862306a36Sopenharmony_ci struct ib_pma_portcounters *pma_cnt = 89962306a36Sopenharmony_ci (struct ib_pma_portcounters *)counters; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_data, 90262306a36Sopenharmony_ci (be64_to_cpu(cnt->tx_bytes) >> 2)); 90362306a36Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_data, 90462306a36Sopenharmony_ci (be64_to_cpu(cnt->rx_bytes) >> 2)); 90562306a36Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_xmit_packets, 90662306a36Sopenharmony_ci be64_to_cpu(cnt->tx_frames)); 90762306a36Sopenharmony_ci ASSIGN_32BIT_COUNTER(pma_cnt->port_rcv_packets, 90862306a36Sopenharmony_ci be64_to_cpu(cnt->rx_frames)); 90962306a36Sopenharmony_ci break; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci case IB_PMA_PORT_COUNTERS_EXT: 91262306a36Sopenharmony_ci { 91362306a36Sopenharmony_ci struct ib_pma_portcounters_ext *pma_cnt_ext = 91462306a36Sopenharmony_ci (struct ib_pma_portcounters_ext *)counters; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci pma_cnt_ext->port_xmit_data = 91762306a36Sopenharmony_ci cpu_to_be64(be64_to_cpu(cnt->tx_bytes) >> 2); 91862306a36Sopenharmony_ci pma_cnt_ext->port_rcv_data = 91962306a36Sopenharmony_ci cpu_to_be64(be64_to_cpu(cnt->rx_bytes) >> 2); 92062306a36Sopenharmony_ci pma_cnt_ext->port_xmit_packets = cnt->tx_frames; 92162306a36Sopenharmony_ci pma_cnt_ext->port_rcv_packets = cnt->rx_frames; 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic int iboe_process_mad_port_info(void *out_mad) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci struct ib_class_port_info cpi = {}; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci cpi.capability_mask = IB_PMA_CLASS_CAP_EXT_WIDTH; 93262306a36Sopenharmony_ci memcpy(out_mad, &cpi, sizeof(cpi)); 93362306a36Sopenharmony_ci return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic int iboe_process_mad(struct ib_device *ibdev, int mad_flags, 93762306a36Sopenharmony_ci u32 port_num, const struct ib_wc *in_wc, 93862306a36Sopenharmony_ci const struct ib_grh *in_grh, 93962306a36Sopenharmony_ci const struct ib_mad *in_mad, struct ib_mad *out_mad) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct mlx4_counter counter_stats; 94262306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 94362306a36Sopenharmony_ci struct counter_index *tmp_counter; 94462306a36Sopenharmony_ci int err = IB_MAD_RESULT_FAILURE, stats_avail = 0; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT) 94762306a36Sopenharmony_ci return -EINVAL; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (in_mad->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO) 95062306a36Sopenharmony_ci return iboe_process_mad_port_info((void *)(out_mad->data + 40)); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci memset(&counter_stats, 0, sizeof(counter_stats)); 95362306a36Sopenharmony_ci mutex_lock(&dev->counters_table[port_num - 1].mutex); 95462306a36Sopenharmony_ci list_for_each_entry(tmp_counter, 95562306a36Sopenharmony_ci &dev->counters_table[port_num - 1].counters_list, 95662306a36Sopenharmony_ci list) { 95762306a36Sopenharmony_ci err = mlx4_get_counter_stats(dev->dev, 95862306a36Sopenharmony_ci tmp_counter->index, 95962306a36Sopenharmony_ci &counter_stats, 0); 96062306a36Sopenharmony_ci if (err) { 96162306a36Sopenharmony_ci err = IB_MAD_RESULT_FAILURE; 96262306a36Sopenharmony_ci stats_avail = 0; 96362306a36Sopenharmony_ci break; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci stats_avail = 1; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci mutex_unlock(&dev->counters_table[port_num - 1].mutex); 96862306a36Sopenharmony_ci if (stats_avail) { 96962306a36Sopenharmony_ci switch (counter_stats.counter_mode & 0xf) { 97062306a36Sopenharmony_ci case 0: 97162306a36Sopenharmony_ci edit_counter(&counter_stats, 97262306a36Sopenharmony_ci (void *)(out_mad->data + 40), 97362306a36Sopenharmony_ci in_mad->mad_hdr.attr_id); 97462306a36Sopenharmony_ci err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci default: 97762306a36Sopenharmony_ci err = IB_MAD_RESULT_FAILURE; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci return err; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ciint mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u32 port_num, 98562306a36Sopenharmony_ci const struct ib_wc *in_wc, const struct ib_grh *in_grh, 98662306a36Sopenharmony_ci const struct ib_mad *in, struct ib_mad *out, 98762306a36Sopenharmony_ci size_t *out_mad_size, u16 *out_mad_pkey_index) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ibdev); 99062306a36Sopenharmony_ci enum rdma_link_layer link = rdma_port_get_link_layer(ibdev, port_num); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* iboe_process_mad() which uses the HCA flow-counters to implement IB PMA 99362306a36Sopenharmony_ci * queries, should be called only by VFs and for that specific purpose 99462306a36Sopenharmony_ci */ 99562306a36Sopenharmony_ci if (link == IB_LINK_LAYER_INFINIBAND) { 99662306a36Sopenharmony_ci if (mlx4_is_slave(dev->dev) && 99762306a36Sopenharmony_ci (in->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT && 99862306a36Sopenharmony_ci (in->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS || 99962306a36Sopenharmony_ci in->mad_hdr.attr_id == IB_PMA_PORT_COUNTERS_EXT || 100062306a36Sopenharmony_ci in->mad_hdr.attr_id == IB_PMA_CLASS_PORT_INFO))) 100162306a36Sopenharmony_ci return iboe_process_mad(ibdev, mad_flags, port_num, 100262306a36Sopenharmony_ci in_wc, in_grh, in, out); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci return ib_process_mad(ibdev, mad_flags, port_num, in_wc, in_grh, 100562306a36Sopenharmony_ci in, out); 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (link == IB_LINK_LAYER_ETHERNET) 100962306a36Sopenharmony_ci return iboe_process_mad(ibdev, mad_flags, port_num, in_wc, 101062306a36Sopenharmony_ci in_grh, in, out); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return -EINVAL; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic void send_handler(struct ib_mad_agent *agent, 101662306a36Sopenharmony_ci struct ib_mad_send_wc *mad_send_wc) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci if (mad_send_wc->send_buf->context[0]) 101962306a36Sopenharmony_ci rdma_destroy_ah(mad_send_wc->send_buf->context[0], 0); 102062306a36Sopenharmony_ci ib_free_send_mad(mad_send_wc->send_buf); 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ciint mlx4_ib_mad_init(struct mlx4_ib_dev *dev) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct ib_mad_agent *agent; 102662306a36Sopenharmony_ci int p, q; 102762306a36Sopenharmony_ci int ret; 102862306a36Sopenharmony_ci enum rdma_link_layer ll; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci for (p = 0; p < dev->num_ports; ++p) { 103162306a36Sopenharmony_ci ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1); 103262306a36Sopenharmony_ci for (q = 0; q <= 1; ++q) { 103362306a36Sopenharmony_ci if (ll == IB_LINK_LAYER_INFINIBAND) { 103462306a36Sopenharmony_ci agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 103562306a36Sopenharmony_ci q ? IB_QPT_GSI : IB_QPT_SMI, 103662306a36Sopenharmony_ci NULL, 0, send_handler, 103762306a36Sopenharmony_ci NULL, NULL, 0); 103862306a36Sopenharmony_ci if (IS_ERR(agent)) { 103962306a36Sopenharmony_ci ret = PTR_ERR(agent); 104062306a36Sopenharmony_ci goto err; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci dev->send_agent[p][q] = agent; 104362306a36Sopenharmony_ci } else 104462306a36Sopenharmony_ci dev->send_agent[p][q] = NULL; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci return 0; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cierr: 105162306a36Sopenharmony_ci for (p = 0; p < dev->num_ports; ++p) 105262306a36Sopenharmony_ci for (q = 0; q <= 1; ++q) 105362306a36Sopenharmony_ci if (dev->send_agent[p][q]) 105462306a36Sopenharmony_ci ib_unregister_mad_agent(dev->send_agent[p][q]); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci return ret; 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_civoid mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct ib_mad_agent *agent; 106262306a36Sopenharmony_ci int p, q; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci for (p = 0; p < dev->num_ports; ++p) { 106562306a36Sopenharmony_ci for (q = 0; q <= 1; ++q) { 106662306a36Sopenharmony_ci agent = dev->send_agent[p][q]; 106762306a36Sopenharmony_ci if (agent) { 106862306a36Sopenharmony_ci dev->send_agent[p][q] = NULL; 106962306a36Sopenharmony_ci ib_unregister_mad_agent(agent); 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (dev->sm_ah[p]) 107462306a36Sopenharmony_ci rdma_destroy_ah(dev->sm_ah[p], 0); 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic void handle_lid_change_event(struct mlx4_ib_dev *dev, u32 port_num) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_LID_CHANGE); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) 108362306a36Sopenharmony_ci mlx4_gen_slaves_port_mgt_ev(dev->dev, port_num, 108462306a36Sopenharmony_ci MLX4_EQ_PORT_INFO_LID_CHANGE_MASK); 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic void handle_client_rereg_event(struct mlx4_ib_dev *dev, u32 port_num) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci /* re-configure the alias-guid and mcg's */ 109062306a36Sopenharmony_ci if (mlx4_is_master(dev->dev)) { 109162306a36Sopenharmony_ci mlx4_ib_invalidate_all_guid_record(dev, port_num); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (!dev->sriov.is_going_down) { 109462306a36Sopenharmony_ci mlx4_ib_mcg_port_cleanup(&dev->sriov.demux[port_num - 1], 0); 109562306a36Sopenharmony_ci mlx4_gen_slaves_port_mgt_ev(dev->dev, port_num, 109662306a36Sopenharmony_ci MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci /* Update the sl to vl table from inside client rereg 110162306a36Sopenharmony_ci * only if in secure-host mode (snooping is not possible) 110262306a36Sopenharmony_ci * and the sl-to-vl change event is not generated by FW. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ci if (!mlx4_is_slave(dev->dev) && 110562306a36Sopenharmony_ci dev->dev->flags & MLX4_FLAG_SECURE_HOST && 110662306a36Sopenharmony_ci !(dev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT)) { 110762306a36Sopenharmony_ci if (mlx4_is_master(dev->dev)) 110862306a36Sopenharmony_ci /* already in work queue from mlx4_ib_event queueing 110962306a36Sopenharmony_ci * mlx4_handle_port_mgmt_change_event, which calls 111062306a36Sopenharmony_ci * this procedure. Therefore, call sl2vl_update directly. 111162306a36Sopenharmony_ci */ 111262306a36Sopenharmony_ci mlx4_ib_sl2vl_update(dev, port_num); 111362306a36Sopenharmony_ci else 111462306a36Sopenharmony_ci mlx4_sched_ib_sl2vl_update_work(dev, port_num); 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port_num, IB_EVENT_CLIENT_REREGISTER); 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_cistatic void propagate_pkey_ev(struct mlx4_ib_dev *dev, int port_num, 112062306a36Sopenharmony_ci struct mlx4_eqe *eqe) 112162306a36Sopenharmony_ci{ 112262306a36Sopenharmony_ci __propagate_pkey_ev(dev, port_num, GET_BLK_PTR_FROM_EQE(eqe), 112362306a36Sopenharmony_ci GET_MASK_FROM_EQE(eqe)); 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic void handle_slaves_guid_change(struct mlx4_ib_dev *dev, u32 port_num, 112762306a36Sopenharmony_ci u32 guid_tbl_blk_num, u32 change_bitmap) 112862306a36Sopenharmony_ci{ 112962306a36Sopenharmony_ci struct ib_smp *in_mad = NULL; 113062306a36Sopenharmony_ci struct ib_smp *out_mad = NULL; 113162306a36Sopenharmony_ci u16 i; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev) || !mlx4_is_master(dev->dev)) 113462306a36Sopenharmony_ci return; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); 113762306a36Sopenharmony_ci out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); 113862306a36Sopenharmony_ci if (!in_mad || !out_mad) 113962306a36Sopenharmony_ci goto out; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci guid_tbl_blk_num *= 4; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 114462306a36Sopenharmony_ci if (change_bitmap && (!((change_bitmap >> (8 * i)) & 0xff))) 114562306a36Sopenharmony_ci continue; 114662306a36Sopenharmony_ci memset(in_mad, 0, sizeof *in_mad); 114762306a36Sopenharmony_ci memset(out_mad, 0, sizeof *out_mad); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci in_mad->base_version = 1; 115062306a36Sopenharmony_ci in_mad->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; 115162306a36Sopenharmony_ci in_mad->class_version = 1; 115262306a36Sopenharmony_ci in_mad->method = IB_MGMT_METHOD_GET; 115362306a36Sopenharmony_ci in_mad->attr_id = IB_SMP_ATTR_GUID_INFO; 115462306a36Sopenharmony_ci in_mad->attr_mod = cpu_to_be32(guid_tbl_blk_num + i); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci if (mlx4_MAD_IFC(dev, 115762306a36Sopenharmony_ci MLX4_MAD_IFC_IGNORE_KEYS | MLX4_MAD_IFC_NET_VIEW, 115862306a36Sopenharmony_ci port_num, NULL, NULL, in_mad, out_mad)) { 115962306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "Failed in get GUID INFO MAD_IFC\n"); 116062306a36Sopenharmony_ci goto out; 116162306a36Sopenharmony_ci } 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci mlx4_ib_update_cache_on_guid_change(dev, guid_tbl_blk_num + i, 116462306a36Sopenharmony_ci port_num, 116562306a36Sopenharmony_ci (u8 *)(&((struct ib_smp *)out_mad)->data)); 116662306a36Sopenharmony_ci mlx4_ib_notify_slaves_on_guid_change(dev, guid_tbl_blk_num + i, 116762306a36Sopenharmony_ci port_num, 116862306a36Sopenharmony_ci (u8 *)(&((struct ib_smp *)out_mad)->data)); 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ciout: 117262306a36Sopenharmony_ci kfree(in_mad); 117362306a36Sopenharmony_ci kfree(out_mad); 117462306a36Sopenharmony_ci return; 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_civoid handle_port_mgmt_change_event(struct work_struct *work) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci struct ib_event_work *ew = container_of(work, struct ib_event_work, work); 118062306a36Sopenharmony_ci struct mlx4_ib_dev *dev = ew->ib_dev; 118162306a36Sopenharmony_ci struct mlx4_eqe *eqe = &(ew->ib_eqe); 118262306a36Sopenharmony_ci u32 port = eqe->event.port_mgmt_change.port; 118362306a36Sopenharmony_ci u32 changed_attr; 118462306a36Sopenharmony_ci u32 tbl_block; 118562306a36Sopenharmony_ci u32 change_bitmap; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci switch (eqe->subtype) { 118862306a36Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_PORT_INFO: 118962306a36Sopenharmony_ci changed_attr = be32_to_cpu(eqe->event.port_mgmt_change.params.port_info.changed_attr); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci /* Update the SM ah - This should be done before handling 119262306a36Sopenharmony_ci the other changed attributes so that MADs can be sent to the SM */ 119362306a36Sopenharmony_ci if (changed_attr & MSTR_SM_CHANGE_MASK) { 119462306a36Sopenharmony_ci u16 lid = be16_to_cpu(eqe->event.port_mgmt_change.params.port_info.mstr_sm_lid); 119562306a36Sopenharmony_ci u8 sl = eqe->event.port_mgmt_change.params.port_info.mstr_sm_sl & 0xf; 119662306a36Sopenharmony_ci update_sm_ah(dev, port, lid, sl); 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci /* Check if it is a lid change event */ 120062306a36Sopenharmony_ci if (changed_attr & MLX4_EQ_PORT_INFO_LID_CHANGE_MASK) 120162306a36Sopenharmony_ci handle_lid_change_event(dev, port); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* Generate GUID changed event */ 120462306a36Sopenharmony_ci if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK) { 120562306a36Sopenharmony_ci if (mlx4_is_master(dev->dev)) { 120662306a36Sopenharmony_ci union ib_gid gid; 120762306a36Sopenharmony_ci int err = 0; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (!eqe->event.port_mgmt_change.params.port_info.gid_prefix) 121062306a36Sopenharmony_ci err = __mlx4_ib_query_gid(&dev->ib_dev, port, 0, &gid, 1); 121162306a36Sopenharmony_ci else 121262306a36Sopenharmony_ci gid.global.subnet_prefix = 121362306a36Sopenharmony_ci eqe->event.port_mgmt_change.params.port_info.gid_prefix; 121462306a36Sopenharmony_ci if (err) { 121562306a36Sopenharmony_ci pr_warn("Could not change QP1 subnet prefix for port %d: query_gid error (%d)\n", 121662306a36Sopenharmony_ci port, err); 121762306a36Sopenharmony_ci } else { 121862306a36Sopenharmony_ci pr_debug("Changing QP1 subnet prefix for port %d. old=0x%llx. new=0x%llx\n", 121962306a36Sopenharmony_ci port, 122062306a36Sopenharmony_ci (u64)atomic64_read(&dev->sriov.demux[port - 1].subnet_prefix), 122162306a36Sopenharmony_ci be64_to_cpu(gid.global.subnet_prefix)); 122262306a36Sopenharmony_ci atomic64_set(&dev->sriov.demux[port - 1].subnet_prefix, 122362306a36Sopenharmony_ci be64_to_cpu(gid.global.subnet_prefix)); 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 122762306a36Sopenharmony_ci /*if master, notify all slaves*/ 122862306a36Sopenharmony_ci if (mlx4_is_master(dev->dev)) 122962306a36Sopenharmony_ci mlx4_gen_slaves_port_mgt_ev(dev->dev, port, 123062306a36Sopenharmony_ci MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK); 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (changed_attr & MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK) 123462306a36Sopenharmony_ci handle_client_rereg_event(dev, port); 123562306a36Sopenharmony_ci break; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE: 123862306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port, IB_EVENT_PKEY_CHANGE); 123962306a36Sopenharmony_ci if (mlx4_is_master(dev->dev) && !dev->sriov.is_going_down) 124062306a36Sopenharmony_ci propagate_pkey_ev(dev, port, eqe); 124162306a36Sopenharmony_ci break; 124262306a36Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_GUID_INFO: 124362306a36Sopenharmony_ci /* paravirtualized master's guid is guid 0 -- does not change */ 124462306a36Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 124562306a36Sopenharmony_ci mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 124662306a36Sopenharmony_ci /*if master, notify relevant slaves*/ 124762306a36Sopenharmony_ci else if (!dev->sriov.is_going_down) { 124862306a36Sopenharmony_ci tbl_block = GET_BLK_PTR_FROM_EQE(eqe); 124962306a36Sopenharmony_ci change_bitmap = GET_MASK_FROM_EQE(eqe); 125062306a36Sopenharmony_ci handle_slaves_guid_change(dev, port, tbl_block, change_bitmap); 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci break; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci case MLX4_DEV_PMC_SUBTYPE_SL_TO_VL_MAP: 125562306a36Sopenharmony_ci /* cache sl to vl mapping changes for use in 125662306a36Sopenharmony_ci * filling QP1 LRH VL field when sending packets 125762306a36Sopenharmony_ci */ 125862306a36Sopenharmony_ci if (!mlx4_is_slave(dev->dev)) { 125962306a36Sopenharmony_ci union sl2vl_tbl_to_u64 sl2vl64; 126062306a36Sopenharmony_ci int jj; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci for (jj = 0; jj < 8; jj++) { 126362306a36Sopenharmony_ci sl2vl64.sl8[jj] = 126462306a36Sopenharmony_ci eqe->event.port_mgmt_change.params.sl2vl_tbl_change_info.sl2vl_table[jj]; 126562306a36Sopenharmony_ci pr_debug("port %u, sl2vl[%d] = %02x\n", 126662306a36Sopenharmony_ci port, jj, sl2vl64.sl8[jj]); 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci atomic64_set(&dev->sl2vl[port - 1], sl2vl64.sl64); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci break; 127162306a36Sopenharmony_ci default: 127262306a36Sopenharmony_ci pr_warn("Unsupported subtype 0x%x for " 127362306a36Sopenharmony_ci "Port Management Change event\n", eqe->subtype); 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci kfree(ew); 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_civoid mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u32 port_num, 128062306a36Sopenharmony_ci enum ib_event_type type) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct ib_event event; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci event.device = &dev->ib_dev; 128562306a36Sopenharmony_ci event.element.port_num = port_num; 128662306a36Sopenharmony_ci event.event = type; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci ib_dispatch_event(&event); 128962306a36Sopenharmony_ci} 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_cistatic void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci unsigned long flags; 129462306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; 129562306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 129662306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 129762306a36Sopenharmony_ci if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) 129862306a36Sopenharmony_ci queue_work(ctx->wq, &ctx->work); 129962306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cistatic void mlx4_ib_wire_comp_handler(struct ib_cq *cq, void *arg) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci unsigned long flags; 130562306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; 130662306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 130962306a36Sopenharmony_ci if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) 131062306a36Sopenharmony_ci queue_work(ctx->wi_wq, &ctx->work); 131162306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 131262306a36Sopenharmony_ci} 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx, 131562306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp, 131662306a36Sopenharmony_ci int index) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci struct ib_sge sg_list; 131962306a36Sopenharmony_ci struct ib_recv_wr recv_wr; 132062306a36Sopenharmony_ci const struct ib_recv_wr *bad_recv_wr; 132162306a36Sopenharmony_ci int size; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci size = (tun_qp->qp->qp_type == IB_QPT_UD) ? 132462306a36Sopenharmony_ci sizeof (struct mlx4_tunnel_mad) : sizeof (struct mlx4_mad_rcv_buf); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci sg_list.addr = tun_qp->ring[index].map; 132762306a36Sopenharmony_ci sg_list.length = size; 132862306a36Sopenharmony_ci sg_list.lkey = ctx->pd->local_dma_lkey; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci recv_wr.next = NULL; 133162306a36Sopenharmony_ci recv_wr.sg_list = &sg_list; 133262306a36Sopenharmony_ci recv_wr.num_sge = 1; 133362306a36Sopenharmony_ci recv_wr.wr_id = (u64) index | MLX4_TUN_WRID_RECV | 133462306a36Sopenharmony_ci MLX4_TUN_SET_WRID_QPN(tun_qp->proxy_qpt); 133562306a36Sopenharmony_ci ib_dma_sync_single_for_device(ctx->ib_dev, tun_qp->ring[index].map, 133662306a36Sopenharmony_ci size, DMA_FROM_DEVICE); 133762306a36Sopenharmony_ci return ib_post_recv(tun_qp->qp, &recv_wr, &bad_recv_wr); 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic int mlx4_ib_multiplex_sa_handler(struct ib_device *ibdev, int port, 134162306a36Sopenharmony_ci int slave, struct ib_sa_mad *sa_mad) 134262306a36Sopenharmony_ci{ 134362306a36Sopenharmony_ci int ret = 0; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci /* dispatch to different sa handlers */ 134662306a36Sopenharmony_ci switch (be16_to_cpu(sa_mad->mad_hdr.attr_id)) { 134762306a36Sopenharmony_ci case IB_SA_ATTR_MC_MEMBER_REC: 134862306a36Sopenharmony_ci ret = mlx4_ib_mcg_multiplex_handler(ibdev, port, slave, sa_mad); 134962306a36Sopenharmony_ci break; 135062306a36Sopenharmony_ci default: 135162306a36Sopenharmony_ci break; 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci return ret; 135462306a36Sopenharmony_ci} 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ciint mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u32 port, 135762306a36Sopenharmony_ci enum ib_qp_type dest_qpt, u16 pkey_index, 135862306a36Sopenharmony_ci u32 remote_qpn, u32 qkey, struct rdma_ah_attr *attr, 135962306a36Sopenharmony_ci u8 *s_mac, u16 vlan_id, struct ib_mad *mad) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct ib_sge list; 136262306a36Sopenharmony_ci struct ib_ud_wr wr; 136362306a36Sopenharmony_ci const struct ib_send_wr *bad_wr; 136462306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *sqp_ctx; 136562306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *sqp; 136662306a36Sopenharmony_ci struct mlx4_mad_snd_buf *sqp_mad; 136762306a36Sopenharmony_ci struct ib_ah *ah; 136862306a36Sopenharmony_ci struct ib_qp *send_qp = NULL; 136962306a36Sopenharmony_ci unsigned wire_tx_ix = 0; 137062306a36Sopenharmony_ci u16 wire_pkey_ix; 137162306a36Sopenharmony_ci int src_qpnum; 137262306a36Sopenharmony_ci int ret; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci sqp_ctx = dev->sriov.sqps[port-1]; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* check if proxy qp created */ 137762306a36Sopenharmony_ci if (!sqp_ctx || sqp_ctx->state != DEMUX_PV_STATE_ACTIVE) 137862306a36Sopenharmony_ci return -EAGAIN; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci if (dest_qpt == IB_QPT_SMI) { 138162306a36Sopenharmony_ci src_qpnum = 0; 138262306a36Sopenharmony_ci sqp = &sqp_ctx->qp[0]; 138362306a36Sopenharmony_ci wire_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][0]; 138462306a36Sopenharmony_ci } else { 138562306a36Sopenharmony_ci src_qpnum = 1; 138662306a36Sopenharmony_ci sqp = &sqp_ctx->qp[1]; 138762306a36Sopenharmony_ci wire_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][pkey_index]; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci send_qp = sqp->qp; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci ah = rdma_zalloc_drv_obj(sqp_ctx->pd->device, ib_ah); 139362306a36Sopenharmony_ci if (!ah) 139462306a36Sopenharmony_ci return -ENOMEM; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci ah->device = sqp_ctx->pd->device; 139762306a36Sopenharmony_ci ah->pd = sqp_ctx->pd; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci /* create ah */ 140062306a36Sopenharmony_ci ret = mlx4_ib_create_ah_slave(ah, attr, 140162306a36Sopenharmony_ci rdma_ah_retrieve_grh(attr)->sgid_index, 140262306a36Sopenharmony_ci s_mac, vlan_id); 140362306a36Sopenharmony_ci if (ret) 140462306a36Sopenharmony_ci goto out; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci spin_lock(&sqp->tx_lock); 140762306a36Sopenharmony_ci if (sqp->tx_ix_head - sqp->tx_ix_tail >= 140862306a36Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)) 140962306a36Sopenharmony_ci ret = -EAGAIN; 141062306a36Sopenharmony_ci else 141162306a36Sopenharmony_ci wire_tx_ix = (++sqp->tx_ix_head) & (MLX4_NUM_WIRE_BUFS - 1); 141262306a36Sopenharmony_ci spin_unlock(&sqp->tx_lock); 141362306a36Sopenharmony_ci if (ret) 141462306a36Sopenharmony_ci goto out; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci sqp_mad = (struct mlx4_mad_snd_buf *) (sqp->tx_ring[wire_tx_ix].buf.addr); 141762306a36Sopenharmony_ci kfree(sqp->tx_ring[wire_tx_ix].ah); 141862306a36Sopenharmony_ci sqp->tx_ring[wire_tx_ix].ah = ah; 141962306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(&dev->ib_dev, 142062306a36Sopenharmony_ci sqp->tx_ring[wire_tx_ix].buf.map, 142162306a36Sopenharmony_ci sizeof (struct mlx4_mad_snd_buf), 142262306a36Sopenharmony_ci DMA_TO_DEVICE); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci memcpy(&sqp_mad->payload, mad, sizeof *mad); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci ib_dma_sync_single_for_device(&dev->ib_dev, 142762306a36Sopenharmony_ci sqp->tx_ring[wire_tx_ix].buf.map, 142862306a36Sopenharmony_ci sizeof (struct mlx4_mad_snd_buf), 142962306a36Sopenharmony_ci DMA_TO_DEVICE); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci list.addr = sqp->tx_ring[wire_tx_ix].buf.map; 143262306a36Sopenharmony_ci list.length = sizeof (struct mlx4_mad_snd_buf); 143362306a36Sopenharmony_ci list.lkey = sqp_ctx->pd->local_dma_lkey; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci wr.ah = ah; 143662306a36Sopenharmony_ci wr.port_num = port; 143762306a36Sopenharmony_ci wr.pkey_index = wire_pkey_ix; 143862306a36Sopenharmony_ci wr.remote_qkey = qkey; 143962306a36Sopenharmony_ci wr.remote_qpn = remote_qpn; 144062306a36Sopenharmony_ci wr.wr.next = NULL; 144162306a36Sopenharmony_ci wr.wr.wr_id = ((u64) wire_tx_ix) | MLX4_TUN_SET_WRID_QPN(src_qpnum); 144262306a36Sopenharmony_ci wr.wr.sg_list = &list; 144362306a36Sopenharmony_ci wr.wr.num_sge = 1; 144462306a36Sopenharmony_ci wr.wr.opcode = IB_WR_SEND; 144562306a36Sopenharmony_ci wr.wr.send_flags = IB_SEND_SIGNALED; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci ret = ib_post_send(send_qp, &wr.wr, &bad_wr); 144862306a36Sopenharmony_ci if (!ret) 144962306a36Sopenharmony_ci return 0; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci spin_lock(&sqp->tx_lock); 145262306a36Sopenharmony_ci sqp->tx_ix_tail++; 145362306a36Sopenharmony_ci spin_unlock(&sqp->tx_lock); 145462306a36Sopenharmony_ci sqp->tx_ring[wire_tx_ix].ah = NULL; 145562306a36Sopenharmony_ciout: 145662306a36Sopenharmony_ci kfree(ah); 145762306a36Sopenharmony_ci return ret; 145862306a36Sopenharmony_ci} 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_cistatic int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port) 146162306a36Sopenharmony_ci{ 146262306a36Sopenharmony_ci if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) 146362306a36Sopenharmony_ci return slave; 146462306a36Sopenharmony_ci return mlx4_get_base_gid_ix(dev->dev, slave, port); 146562306a36Sopenharmony_ci} 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic void fill_in_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port, 146862306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci struct ib_global_route *grh = rdma_ah_retrieve_grh(ah_attr); 147162306a36Sopenharmony_ci if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) 147262306a36Sopenharmony_ci grh->sgid_index = slave; 147362306a36Sopenharmony_ci else 147462306a36Sopenharmony_ci grh->sgid_index += get_slave_base_gid_ix(dev, slave, port); 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_cistatic void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 148062306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp = &ctx->qp[MLX4_TUN_WRID_QPN(wc->wr_id)]; 148162306a36Sopenharmony_ci int wr_ix = wc->wr_id & (MLX4_NUM_TUNNEL_BUFS - 1); 148262306a36Sopenharmony_ci struct mlx4_tunnel_mad *tunnel = tun_qp->ring[wr_ix].addr; 148362306a36Sopenharmony_ci struct mlx4_ib_ah ah; 148462306a36Sopenharmony_ci struct rdma_ah_attr ah_attr; 148562306a36Sopenharmony_ci u8 *slave_id; 148662306a36Sopenharmony_ci int slave; 148762306a36Sopenharmony_ci int port; 148862306a36Sopenharmony_ci u16 vlan_id; 148962306a36Sopenharmony_ci u8 qos; 149062306a36Sopenharmony_ci u8 *dmac; 149162306a36Sopenharmony_ci int sts; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* Get slave that sent this packet */ 149462306a36Sopenharmony_ci if (wc->src_qp < dev->dev->phys_caps.base_proxy_sqpn || 149562306a36Sopenharmony_ci wc->src_qp >= dev->dev->phys_caps.base_proxy_sqpn + 8 * MLX4_MFUNC_MAX || 149662306a36Sopenharmony_ci (wc->src_qp & 0x1) != ctx->port - 1 || 149762306a36Sopenharmony_ci wc->src_qp & 0x4) { 149862306a36Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d\n", wc->src_qp); 149962306a36Sopenharmony_ci return; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci slave = ((wc->src_qp & ~0x7) - dev->dev->phys_caps.base_proxy_sqpn) / 8; 150262306a36Sopenharmony_ci if (slave != ctx->slave) { 150362306a36Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "can't multiplex bad sqp:%d: " 150462306a36Sopenharmony_ci "belongs to another slave\n", wc->src_qp); 150562306a36Sopenharmony_ci return; 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* Map transaction ID */ 150962306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ctx->ib_dev, tun_qp->ring[wr_ix].map, 151062306a36Sopenharmony_ci sizeof (struct mlx4_tunnel_mad), 151162306a36Sopenharmony_ci DMA_FROM_DEVICE); 151262306a36Sopenharmony_ci switch (tunnel->mad.mad_hdr.method) { 151362306a36Sopenharmony_ci case IB_MGMT_METHOD_SET: 151462306a36Sopenharmony_ci case IB_MGMT_METHOD_GET: 151562306a36Sopenharmony_ci case IB_MGMT_METHOD_REPORT: 151662306a36Sopenharmony_ci case IB_SA_METHOD_GET_TABLE: 151762306a36Sopenharmony_ci case IB_SA_METHOD_DELETE: 151862306a36Sopenharmony_ci case IB_SA_METHOD_GET_MULTI: 151962306a36Sopenharmony_ci case IB_SA_METHOD_GET_TRACE_TBL: 152062306a36Sopenharmony_ci slave_id = (u8 *) &tunnel->mad.mad_hdr.tid; 152162306a36Sopenharmony_ci if (*slave_id) { 152262306a36Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "egress mad has non-null tid msb:%d " 152362306a36Sopenharmony_ci "class:%d slave:%d\n", *slave_id, 152462306a36Sopenharmony_ci tunnel->mad.mad_hdr.mgmt_class, slave); 152562306a36Sopenharmony_ci return; 152662306a36Sopenharmony_ci } else 152762306a36Sopenharmony_ci *slave_id = slave; 152862306a36Sopenharmony_ci break; 152962306a36Sopenharmony_ci default: 153062306a36Sopenharmony_ci /* nothing */; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci /* Class-specific handling */ 153462306a36Sopenharmony_ci switch (tunnel->mad.mad_hdr.mgmt_class) { 153562306a36Sopenharmony_ci case IB_MGMT_CLASS_SUBN_LID_ROUTED: 153662306a36Sopenharmony_ci case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: 153762306a36Sopenharmony_ci if (slave != mlx4_master_func_num(dev->dev) && 153862306a36Sopenharmony_ci !mlx4_vf_smi_enabled(dev->dev, slave, ctx->port)) 153962306a36Sopenharmony_ci return; 154062306a36Sopenharmony_ci break; 154162306a36Sopenharmony_ci case IB_MGMT_CLASS_SUBN_ADM: 154262306a36Sopenharmony_ci if (mlx4_ib_multiplex_sa_handler(ctx->ib_dev, ctx->port, slave, 154362306a36Sopenharmony_ci (struct ib_sa_mad *) &tunnel->mad)) 154462306a36Sopenharmony_ci return; 154562306a36Sopenharmony_ci break; 154662306a36Sopenharmony_ci case IB_MGMT_CLASS_CM: 154762306a36Sopenharmony_ci if (mlx4_ib_multiplex_cm_handler(ctx->ib_dev, ctx->port, slave, 154862306a36Sopenharmony_ci (struct ib_mad *) &tunnel->mad)) 154962306a36Sopenharmony_ci return; 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci case IB_MGMT_CLASS_DEVICE_MGMT: 155262306a36Sopenharmony_ci if (tunnel->mad.mad_hdr.method != IB_MGMT_METHOD_GET && 155362306a36Sopenharmony_ci tunnel->mad.mad_hdr.method != IB_MGMT_METHOD_SET) 155462306a36Sopenharmony_ci return; 155562306a36Sopenharmony_ci break; 155662306a36Sopenharmony_ci default: 155762306a36Sopenharmony_ci /* Drop unsupported classes for slaves in tunnel mode */ 155862306a36Sopenharmony_ci if (slave != mlx4_master_func_num(dev->dev)) { 155962306a36Sopenharmony_ci mlx4_ib_warn(ctx->ib_dev, "dropping unsupported egress mad from class:%d " 156062306a36Sopenharmony_ci "for slave:%d\n", tunnel->mad.mad_hdr.mgmt_class, slave); 156162306a36Sopenharmony_ci return; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci /* We are using standard ib_core services to send the mad, so generate a 156662306a36Sopenharmony_ci * stadard address handle by decoding the tunnelled mlx4_ah fields */ 156762306a36Sopenharmony_ci memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av)); 156862306a36Sopenharmony_ci ah.ibah.device = ctx->ib_dev; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci port = be32_to_cpu(ah.av.ib.port_pd) >> 24; 157162306a36Sopenharmony_ci port = mlx4_slave_convert_port(dev->dev, slave, port); 157262306a36Sopenharmony_ci if (port < 0) 157362306a36Sopenharmony_ci return; 157462306a36Sopenharmony_ci ah.av.ib.port_pd = cpu_to_be32(port << 24 | (be32_to_cpu(ah.av.ib.port_pd) & 0xffffff)); 157562306a36Sopenharmony_ci ah.ibah.type = rdma_ah_find_type(&dev->ib_dev, port); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci mlx4_ib_query_ah(&ah.ibah, &ah_attr); 157862306a36Sopenharmony_ci if (rdma_ah_get_ah_flags(&ah_attr) & IB_AH_GRH) 157962306a36Sopenharmony_ci fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr); 158062306a36Sopenharmony_ci dmac = rdma_ah_retrieve_dmac(&ah_attr); 158162306a36Sopenharmony_ci if (dmac) 158262306a36Sopenharmony_ci memcpy(dmac, tunnel->hdr.mac, ETH_ALEN); 158362306a36Sopenharmony_ci vlan_id = be16_to_cpu(tunnel->hdr.vlan); 158462306a36Sopenharmony_ci /* if slave have default vlan use it */ 158562306a36Sopenharmony_ci if (mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave, 158662306a36Sopenharmony_ci &vlan_id, &qos)) 158762306a36Sopenharmony_ci rdma_ah_set_sl(&ah_attr, qos); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci sts = mlx4_ib_send_to_wire(dev, slave, ctx->port, 159062306a36Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? 159162306a36Sopenharmony_ci IB_QPT_SMI : IB_QPT_GSI, 159262306a36Sopenharmony_ci be16_to_cpu(tunnel->hdr.pkey_index), 159362306a36Sopenharmony_ci be32_to_cpu(tunnel->hdr.remote_qpn), 159462306a36Sopenharmony_ci be32_to_cpu(tunnel->hdr.qkey), 159562306a36Sopenharmony_ci &ah_attr, wc->smac, vlan_id, &tunnel->mad); 159662306a36Sopenharmony_ci if (sts) 159762306a36Sopenharmony_ci pr_debug("failed sending %s to wire on behalf of slave %d (%d)\n", 159862306a36Sopenharmony_ci is_proxy_qp0(dev, wc->src_qp, slave) ? "SMI" : "GSI", 159962306a36Sopenharmony_ci slave, sts); 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 160362306a36Sopenharmony_ci enum ib_qp_type qp_type, int is_tun) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci int i; 160662306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 160762306a36Sopenharmony_ci int rx_buf_size, tx_buf_size; 160862306a36Sopenharmony_ci const int nmbr_bufs = is_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci if (qp_type > IB_QPT_GSI) 161162306a36Sopenharmony_ci return -EINVAL; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci tun_qp = &ctx->qp[qp_type]; 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci tun_qp->ring = kcalloc(nmbr_bufs, 161662306a36Sopenharmony_ci sizeof(struct mlx4_ib_buf), 161762306a36Sopenharmony_ci GFP_KERNEL); 161862306a36Sopenharmony_ci if (!tun_qp->ring) 161962306a36Sopenharmony_ci return -ENOMEM; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci tun_qp->tx_ring = kcalloc(nmbr_bufs, 162262306a36Sopenharmony_ci sizeof (struct mlx4_ib_tun_tx_buf), 162362306a36Sopenharmony_ci GFP_KERNEL); 162462306a36Sopenharmony_ci if (!tun_qp->tx_ring) { 162562306a36Sopenharmony_ci kfree(tun_qp->ring); 162662306a36Sopenharmony_ci tun_qp->ring = NULL; 162762306a36Sopenharmony_ci return -ENOMEM; 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci if (is_tun) { 163162306a36Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_tunnel_mad); 163262306a36Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 163362306a36Sopenharmony_ci } else { 163462306a36Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 163562306a36Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 163962306a36Sopenharmony_ci tun_qp->ring[i].addr = kmalloc(rx_buf_size, GFP_KERNEL); 164062306a36Sopenharmony_ci if (!tun_qp->ring[i].addr) 164162306a36Sopenharmony_ci goto err; 164262306a36Sopenharmony_ci tun_qp->ring[i].map = ib_dma_map_single(ctx->ib_dev, 164362306a36Sopenharmony_ci tun_qp->ring[i].addr, 164462306a36Sopenharmony_ci rx_buf_size, 164562306a36Sopenharmony_ci DMA_FROM_DEVICE); 164662306a36Sopenharmony_ci if (ib_dma_mapping_error(ctx->ib_dev, tun_qp->ring[i].map)) { 164762306a36Sopenharmony_ci kfree(tun_qp->ring[i].addr); 164862306a36Sopenharmony_ci goto err; 164962306a36Sopenharmony_ci } 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 165362306a36Sopenharmony_ci tun_qp->tx_ring[i].buf.addr = 165462306a36Sopenharmony_ci kmalloc(tx_buf_size, GFP_KERNEL); 165562306a36Sopenharmony_ci if (!tun_qp->tx_ring[i].buf.addr) 165662306a36Sopenharmony_ci goto tx_err; 165762306a36Sopenharmony_ci tun_qp->tx_ring[i].buf.map = 165862306a36Sopenharmony_ci ib_dma_map_single(ctx->ib_dev, 165962306a36Sopenharmony_ci tun_qp->tx_ring[i].buf.addr, 166062306a36Sopenharmony_ci tx_buf_size, 166162306a36Sopenharmony_ci DMA_TO_DEVICE); 166262306a36Sopenharmony_ci if (ib_dma_mapping_error(ctx->ib_dev, 166362306a36Sopenharmony_ci tun_qp->tx_ring[i].buf.map)) { 166462306a36Sopenharmony_ci kfree(tun_qp->tx_ring[i].buf.addr); 166562306a36Sopenharmony_ci goto tx_err; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci tun_qp->tx_ring[i].ah = NULL; 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci spin_lock_init(&tun_qp->tx_lock); 167062306a36Sopenharmony_ci tun_qp->tx_ix_head = 0; 167162306a36Sopenharmony_ci tun_qp->tx_ix_tail = 0; 167262306a36Sopenharmony_ci tun_qp->proxy_qpt = qp_type; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci return 0; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_citx_err: 167762306a36Sopenharmony_ci while (i > 0) { 167862306a36Sopenharmony_ci --i; 167962306a36Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 168062306a36Sopenharmony_ci tx_buf_size, DMA_TO_DEVICE); 168162306a36Sopenharmony_ci kfree(tun_qp->tx_ring[i].buf.addr); 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci i = nmbr_bufs; 168462306a36Sopenharmony_cierr: 168562306a36Sopenharmony_ci while (i > 0) { 168662306a36Sopenharmony_ci --i; 168762306a36Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 168862306a36Sopenharmony_ci rx_buf_size, DMA_FROM_DEVICE); 168962306a36Sopenharmony_ci kfree(tun_qp->ring[i].addr); 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci kfree(tun_qp->tx_ring); 169262306a36Sopenharmony_ci tun_qp->tx_ring = NULL; 169362306a36Sopenharmony_ci kfree(tun_qp->ring); 169462306a36Sopenharmony_ci tun_qp->ring = NULL; 169562306a36Sopenharmony_ci return -ENOMEM; 169662306a36Sopenharmony_ci} 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_cistatic void mlx4_ib_free_pv_qp_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 169962306a36Sopenharmony_ci enum ib_qp_type qp_type, int is_tun) 170062306a36Sopenharmony_ci{ 170162306a36Sopenharmony_ci int i; 170262306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 170362306a36Sopenharmony_ci int rx_buf_size, tx_buf_size; 170462306a36Sopenharmony_ci const int nmbr_bufs = is_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci if (qp_type > IB_QPT_GSI) 170762306a36Sopenharmony_ci return; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci tun_qp = &ctx->qp[qp_type]; 171062306a36Sopenharmony_ci if (is_tun) { 171162306a36Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_tunnel_mad); 171262306a36Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 171362306a36Sopenharmony_ci } else { 171462306a36Sopenharmony_ci rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 171562306a36Sopenharmony_ci tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 172062306a36Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 172162306a36Sopenharmony_ci rx_buf_size, DMA_FROM_DEVICE); 172262306a36Sopenharmony_ci kfree(tun_qp->ring[i].addr); 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 172662306a36Sopenharmony_ci ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 172762306a36Sopenharmony_ci tx_buf_size, DMA_TO_DEVICE); 172862306a36Sopenharmony_ci kfree(tun_qp->tx_ring[i].buf.addr); 172962306a36Sopenharmony_ci if (tun_qp->tx_ring[i].ah) 173062306a36Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[i].ah, 0); 173162306a36Sopenharmony_ci } 173262306a36Sopenharmony_ci kfree(tun_qp->tx_ring); 173362306a36Sopenharmony_ci kfree(tun_qp->ring); 173462306a36Sopenharmony_ci} 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cistatic void mlx4_ib_tunnel_comp_worker(struct work_struct *work) 173762306a36Sopenharmony_ci{ 173862306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx; 173962306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 174062306a36Sopenharmony_ci struct ib_wc wc; 174162306a36Sopenharmony_ci int ret; 174262306a36Sopenharmony_ci ctx = container_of(work, struct mlx4_ib_demux_pv_ctx, work); 174362306a36Sopenharmony_ci ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci while (ib_poll_cq(ctx->cq, 1, &wc) == 1) { 174662306a36Sopenharmony_ci tun_qp = &ctx->qp[MLX4_TUN_WRID_QPN(wc.wr_id)]; 174762306a36Sopenharmony_ci if (wc.status == IB_WC_SUCCESS) { 174862306a36Sopenharmony_ci switch (wc.opcode) { 174962306a36Sopenharmony_ci case IB_WC_RECV: 175062306a36Sopenharmony_ci mlx4_ib_multiplex_mad(ctx, &wc); 175162306a36Sopenharmony_ci ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, 175262306a36Sopenharmony_ci wc.wr_id & 175362306a36Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)); 175462306a36Sopenharmony_ci if (ret) 175562306a36Sopenharmony_ci pr_err("Failed reposting tunnel " 175662306a36Sopenharmony_ci "buf:%lld\n", wc.wr_id); 175762306a36Sopenharmony_ci break; 175862306a36Sopenharmony_ci case IB_WC_SEND: 175962306a36Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[wc.wr_id & 176062306a36Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)].ah, 0); 176162306a36Sopenharmony_ci tun_qp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah 176262306a36Sopenharmony_ci = NULL; 176362306a36Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 176462306a36Sopenharmony_ci tun_qp->tx_ix_tail++; 176562306a36Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci break; 176862306a36Sopenharmony_ci default: 176962306a36Sopenharmony_ci break; 177062306a36Sopenharmony_ci } 177162306a36Sopenharmony_ci } else { 177262306a36Sopenharmony_ci pr_debug("mlx4_ib: completion error in tunnel: %d." 177362306a36Sopenharmony_ci " status = %d, wrid = 0x%llx\n", 177462306a36Sopenharmony_ci ctx->slave, wc.status, wc.wr_id); 177562306a36Sopenharmony_ci if (!MLX4_TUN_IS_RECV(wc.wr_id)) { 177662306a36Sopenharmony_ci rdma_destroy_ah(tun_qp->tx_ring[wc.wr_id & 177762306a36Sopenharmony_ci (MLX4_NUM_TUNNEL_BUFS - 1)].ah, 0); 177862306a36Sopenharmony_ci tun_qp->tx_ring[wc.wr_id & (MLX4_NUM_TUNNEL_BUFS - 1)].ah 177962306a36Sopenharmony_ci = NULL; 178062306a36Sopenharmony_ci spin_lock(&tun_qp->tx_lock); 178162306a36Sopenharmony_ci tun_qp->tx_ix_tail++; 178262306a36Sopenharmony_ci spin_unlock(&tun_qp->tx_lock); 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci} 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_cistatic void pv_qp_event_handler(struct ib_event *event, void *qp_context) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *sqp = qp_context; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci /* It's worse than that! He's dead, Jim! */ 179362306a36Sopenharmony_ci pr_err("Fatal error (%d) on a MAD QP on port %d\n", 179462306a36Sopenharmony_ci event->event, sqp->port); 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cistatic int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx, 179862306a36Sopenharmony_ci enum ib_qp_type qp_type, int create_tun) 179962306a36Sopenharmony_ci{ 180062306a36Sopenharmony_ci int i, ret; 180162306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *tun_qp; 180262306a36Sopenharmony_ci struct mlx4_ib_qp_tunnel_init_attr qp_init_attr; 180362306a36Sopenharmony_ci struct ib_qp_attr attr; 180462306a36Sopenharmony_ci int qp_attr_mask_INIT; 180562306a36Sopenharmony_ci const int nmbr_bufs = create_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci if (qp_type > IB_QPT_GSI) 180862306a36Sopenharmony_ci return -EINVAL; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci tun_qp = &ctx->qp[qp_type]; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci memset(&qp_init_attr, 0, sizeof qp_init_attr); 181362306a36Sopenharmony_ci qp_init_attr.init_attr.send_cq = ctx->cq; 181462306a36Sopenharmony_ci qp_init_attr.init_attr.recv_cq = ctx->cq; 181562306a36Sopenharmony_ci qp_init_attr.init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; 181662306a36Sopenharmony_ci qp_init_attr.init_attr.cap.max_send_wr = nmbr_bufs; 181762306a36Sopenharmony_ci qp_init_attr.init_attr.cap.max_recv_wr = nmbr_bufs; 181862306a36Sopenharmony_ci qp_init_attr.init_attr.cap.max_send_sge = 1; 181962306a36Sopenharmony_ci qp_init_attr.init_attr.cap.max_recv_sge = 1; 182062306a36Sopenharmony_ci if (create_tun) { 182162306a36Sopenharmony_ci qp_init_attr.init_attr.qp_type = IB_QPT_UD; 182262306a36Sopenharmony_ci qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_TUNNEL_QP; 182362306a36Sopenharmony_ci qp_init_attr.port = ctx->port; 182462306a36Sopenharmony_ci qp_init_attr.slave = ctx->slave; 182562306a36Sopenharmony_ci qp_init_attr.proxy_qp_type = qp_type; 182662306a36Sopenharmony_ci qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | 182762306a36Sopenharmony_ci IB_QP_QKEY | IB_QP_PORT; 182862306a36Sopenharmony_ci } else { 182962306a36Sopenharmony_ci qp_init_attr.init_attr.qp_type = qp_type; 183062306a36Sopenharmony_ci qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_SQP; 183162306a36Sopenharmony_ci qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci qp_init_attr.init_attr.port_num = ctx->port; 183462306a36Sopenharmony_ci qp_init_attr.init_attr.qp_context = ctx; 183562306a36Sopenharmony_ci qp_init_attr.init_attr.event_handler = pv_qp_event_handler; 183662306a36Sopenharmony_ci tun_qp->qp = ib_create_qp(ctx->pd, &qp_init_attr.init_attr); 183762306a36Sopenharmony_ci if (IS_ERR(tun_qp->qp)) { 183862306a36Sopenharmony_ci ret = PTR_ERR(tun_qp->qp); 183962306a36Sopenharmony_ci tun_qp->qp = NULL; 184062306a36Sopenharmony_ci pr_err("Couldn't create %s QP (%d)\n", 184162306a36Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 184262306a36Sopenharmony_ci return ret; 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci memset(&attr, 0, sizeof attr); 184662306a36Sopenharmony_ci attr.qp_state = IB_QPS_INIT; 184762306a36Sopenharmony_ci ret = 0; 184862306a36Sopenharmony_ci if (create_tun) 184962306a36Sopenharmony_ci ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave, 185062306a36Sopenharmony_ci ctx->port, IB_DEFAULT_PKEY_FULL, 185162306a36Sopenharmony_ci &attr.pkey_index); 185262306a36Sopenharmony_ci if (ret || !create_tun) 185362306a36Sopenharmony_ci attr.pkey_index = 185462306a36Sopenharmony_ci to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0]; 185562306a36Sopenharmony_ci attr.qkey = IB_QP1_QKEY; 185662306a36Sopenharmony_ci attr.port_num = ctx->port; 185762306a36Sopenharmony_ci ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT); 185862306a36Sopenharmony_ci if (ret) { 185962306a36Sopenharmony_ci pr_err("Couldn't change %s qp state to INIT (%d)\n", 186062306a36Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 186162306a36Sopenharmony_ci goto err_qp; 186262306a36Sopenharmony_ci } 186362306a36Sopenharmony_ci attr.qp_state = IB_QPS_RTR; 186462306a36Sopenharmony_ci ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE); 186562306a36Sopenharmony_ci if (ret) { 186662306a36Sopenharmony_ci pr_err("Couldn't change %s qp state to RTR (%d)\n", 186762306a36Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 186862306a36Sopenharmony_ci goto err_qp; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci attr.qp_state = IB_QPS_RTS; 187162306a36Sopenharmony_ci attr.sq_psn = 0; 187262306a36Sopenharmony_ci ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN); 187362306a36Sopenharmony_ci if (ret) { 187462306a36Sopenharmony_ci pr_err("Couldn't change %s qp state to RTS (%d)\n", 187562306a36Sopenharmony_ci create_tun ? "tunnel" : "special", ret); 187662306a36Sopenharmony_ci goto err_qp; 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci for (i = 0; i < nmbr_bufs; i++) { 188062306a36Sopenharmony_ci ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, i); 188162306a36Sopenharmony_ci if (ret) { 188262306a36Sopenharmony_ci pr_err(" mlx4_ib_post_pv_buf error" 188362306a36Sopenharmony_ci " (err = %d, i = %d)\n", ret, i); 188462306a36Sopenharmony_ci goto err_qp; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci } 188762306a36Sopenharmony_ci return 0; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_cierr_qp: 189062306a36Sopenharmony_ci ib_destroy_qp(tun_qp->qp); 189162306a36Sopenharmony_ci tun_qp->qp = NULL; 189262306a36Sopenharmony_ci return ret; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci/* 189662306a36Sopenharmony_ci * IB MAD completion callback for real SQPs 189762306a36Sopenharmony_ci */ 189862306a36Sopenharmony_cistatic void mlx4_ib_sqp_comp_worker(struct work_struct *work) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx; 190162306a36Sopenharmony_ci struct mlx4_ib_demux_pv_qp *sqp; 190262306a36Sopenharmony_ci struct ib_wc wc; 190362306a36Sopenharmony_ci struct ib_grh *grh; 190462306a36Sopenharmony_ci struct ib_mad *mad; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci ctx = container_of(work, struct mlx4_ib_demux_pv_ctx, work); 190762306a36Sopenharmony_ci ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci while (mlx4_ib_poll_cq(ctx->cq, 1, &wc) == 1) { 191062306a36Sopenharmony_ci sqp = &ctx->qp[MLX4_TUN_WRID_QPN(wc.wr_id)]; 191162306a36Sopenharmony_ci if (wc.status == IB_WC_SUCCESS) { 191262306a36Sopenharmony_ci switch (wc.opcode) { 191362306a36Sopenharmony_ci case IB_WC_SEND: 191462306a36Sopenharmony_ci kfree(sqp->tx_ring[wc.wr_id & 191562306a36Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].ah); 191662306a36Sopenharmony_ci sqp->tx_ring[wc.wr_id & (MLX4_NUM_WIRE_BUFS - 1)].ah 191762306a36Sopenharmony_ci = NULL; 191862306a36Sopenharmony_ci spin_lock(&sqp->tx_lock); 191962306a36Sopenharmony_ci sqp->tx_ix_tail++; 192062306a36Sopenharmony_ci spin_unlock(&sqp->tx_lock); 192162306a36Sopenharmony_ci break; 192262306a36Sopenharmony_ci case IB_WC_RECV: 192362306a36Sopenharmony_ci mad = (struct ib_mad *) &(((struct mlx4_mad_rcv_buf *) 192462306a36Sopenharmony_ci (sqp->ring[wc.wr_id & 192562306a36Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].addr))->payload); 192662306a36Sopenharmony_ci grh = &(((struct mlx4_mad_rcv_buf *) 192762306a36Sopenharmony_ci (sqp->ring[wc.wr_id & 192862306a36Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].addr))->grh); 192962306a36Sopenharmony_ci mlx4_ib_demux_mad(ctx->ib_dev, ctx->port, &wc, grh, mad); 193062306a36Sopenharmony_ci if (mlx4_ib_post_pv_qp_buf(ctx, sqp, wc.wr_id & 193162306a36Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1))) 193262306a36Sopenharmony_ci pr_err("Failed reposting SQP " 193362306a36Sopenharmony_ci "buf:%lld\n", wc.wr_id); 193462306a36Sopenharmony_ci break; 193562306a36Sopenharmony_ci default: 193662306a36Sopenharmony_ci break; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci } else { 193962306a36Sopenharmony_ci pr_debug("mlx4_ib: completion error in tunnel: %d." 194062306a36Sopenharmony_ci " status = %d, wrid = 0x%llx\n", 194162306a36Sopenharmony_ci ctx->slave, wc.status, wc.wr_id); 194262306a36Sopenharmony_ci if (!MLX4_TUN_IS_RECV(wc.wr_id)) { 194362306a36Sopenharmony_ci kfree(sqp->tx_ring[wc.wr_id & 194462306a36Sopenharmony_ci (MLX4_NUM_WIRE_BUFS - 1)].ah); 194562306a36Sopenharmony_ci sqp->tx_ring[wc.wr_id & (MLX4_NUM_WIRE_BUFS - 1)].ah 194662306a36Sopenharmony_ci = NULL; 194762306a36Sopenharmony_ci spin_lock(&sqp->tx_lock); 194862306a36Sopenharmony_ci sqp->tx_ix_tail++; 194962306a36Sopenharmony_ci spin_unlock(&sqp->tx_lock); 195062306a36Sopenharmony_ci } 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci} 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_cistatic int alloc_pv_object(struct mlx4_ib_dev *dev, int slave, int port, 195662306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx **ret_ctx) 195762306a36Sopenharmony_ci{ 195862306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci *ret_ctx = NULL; 196162306a36Sopenharmony_ci ctx = kzalloc(sizeof (struct mlx4_ib_demux_pv_ctx), GFP_KERNEL); 196262306a36Sopenharmony_ci if (!ctx) 196362306a36Sopenharmony_ci return -ENOMEM; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci ctx->ib_dev = &dev->ib_dev; 196662306a36Sopenharmony_ci ctx->port = port; 196762306a36Sopenharmony_ci ctx->slave = slave; 196862306a36Sopenharmony_ci *ret_ctx = ctx; 196962306a36Sopenharmony_ci return 0; 197062306a36Sopenharmony_ci} 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_cistatic void free_pv_object(struct mlx4_ib_dev *dev, int slave, int port) 197362306a36Sopenharmony_ci{ 197462306a36Sopenharmony_ci if (dev->sriov.demux[port - 1].tun[slave]) { 197562306a36Sopenharmony_ci kfree(dev->sriov.demux[port - 1].tun[slave]); 197662306a36Sopenharmony_ci dev->sriov.demux[port - 1].tun[slave] = NULL; 197762306a36Sopenharmony_ci } 197862306a36Sopenharmony_ci} 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_cistatic int create_pv_resources(struct ib_device *ibdev, int slave, int port, 198162306a36Sopenharmony_ci int create_tun, struct mlx4_ib_demux_pv_ctx *ctx) 198262306a36Sopenharmony_ci{ 198362306a36Sopenharmony_ci int ret, cq_size; 198462306a36Sopenharmony_ci struct ib_cq_init_attr cq_attr = {}; 198562306a36Sopenharmony_ci const int nmbr_bufs = create_tun ? MLX4_NUM_TUNNEL_BUFS : MLX4_NUM_WIRE_BUFS; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci if (ctx->state != DEMUX_PV_STATE_DOWN) 198862306a36Sopenharmony_ci return -EEXIST; 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci ctx->state = DEMUX_PV_STATE_STARTING; 199162306a36Sopenharmony_ci /* have QP0 only if link layer is IB */ 199262306a36Sopenharmony_ci if (rdma_port_get_link_layer(ibdev, ctx->port) == 199362306a36Sopenharmony_ci IB_LINK_LAYER_INFINIBAND) 199462306a36Sopenharmony_ci ctx->has_smi = 1; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci if (ctx->has_smi) { 199762306a36Sopenharmony_ci ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_SMI, create_tun); 199862306a36Sopenharmony_ci if (ret) { 199962306a36Sopenharmony_ci pr_err("Failed allocating qp0 tunnel bufs (%d)\n", ret); 200062306a36Sopenharmony_ci goto err_out; 200162306a36Sopenharmony_ci } 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_GSI, create_tun); 200562306a36Sopenharmony_ci if (ret) { 200662306a36Sopenharmony_ci pr_err("Failed allocating qp1 tunnel bufs (%d)\n", ret); 200762306a36Sopenharmony_ci goto err_out_qp0; 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci cq_size = 2 * nmbr_bufs; 201162306a36Sopenharmony_ci if (ctx->has_smi) 201262306a36Sopenharmony_ci cq_size *= 2; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci cq_attr.cqe = cq_size; 201562306a36Sopenharmony_ci ctx->cq = ib_create_cq(ctx->ib_dev, 201662306a36Sopenharmony_ci create_tun ? mlx4_ib_tunnel_comp_handler : mlx4_ib_wire_comp_handler, 201762306a36Sopenharmony_ci NULL, ctx, &cq_attr); 201862306a36Sopenharmony_ci if (IS_ERR(ctx->cq)) { 201962306a36Sopenharmony_ci ret = PTR_ERR(ctx->cq); 202062306a36Sopenharmony_ci pr_err("Couldn't create tunnel CQ (%d)\n", ret); 202162306a36Sopenharmony_ci goto err_buf; 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci ctx->pd = ib_alloc_pd(ctx->ib_dev, 0); 202562306a36Sopenharmony_ci if (IS_ERR(ctx->pd)) { 202662306a36Sopenharmony_ci ret = PTR_ERR(ctx->pd); 202762306a36Sopenharmony_ci pr_err("Couldn't create tunnel PD (%d)\n", ret); 202862306a36Sopenharmony_ci goto err_cq; 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci if (ctx->has_smi) { 203262306a36Sopenharmony_ci ret = create_pv_sqp(ctx, IB_QPT_SMI, create_tun); 203362306a36Sopenharmony_ci if (ret) { 203462306a36Sopenharmony_ci pr_err("Couldn't create %s QP0 (%d)\n", 203562306a36Sopenharmony_ci create_tun ? "tunnel for" : "", ret); 203662306a36Sopenharmony_ci goto err_pd; 203762306a36Sopenharmony_ci } 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci ret = create_pv_sqp(ctx, IB_QPT_GSI, create_tun); 204162306a36Sopenharmony_ci if (ret) { 204262306a36Sopenharmony_ci pr_err("Couldn't create %s QP1 (%d)\n", 204362306a36Sopenharmony_ci create_tun ? "tunnel for" : "", ret); 204462306a36Sopenharmony_ci goto err_qp0; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (create_tun) 204862306a36Sopenharmony_ci INIT_WORK(&ctx->work, mlx4_ib_tunnel_comp_worker); 204962306a36Sopenharmony_ci else 205062306a36Sopenharmony_ci INIT_WORK(&ctx->work, mlx4_ib_sqp_comp_worker); 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci ctx->wq = to_mdev(ibdev)->sriov.demux[port - 1].wq; 205362306a36Sopenharmony_ci ctx->wi_wq = to_mdev(ibdev)->sriov.demux[port - 1].wi_wq; 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci ret = ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 205662306a36Sopenharmony_ci if (ret) { 205762306a36Sopenharmony_ci pr_err("Couldn't arm tunnel cq (%d)\n", ret); 205862306a36Sopenharmony_ci goto err_wq; 205962306a36Sopenharmony_ci } 206062306a36Sopenharmony_ci ctx->state = DEMUX_PV_STATE_ACTIVE; 206162306a36Sopenharmony_ci return 0; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_cierr_wq: 206462306a36Sopenharmony_ci ctx->wq = NULL; 206562306a36Sopenharmony_ci ib_destroy_qp(ctx->qp[1].qp); 206662306a36Sopenharmony_ci ctx->qp[1].qp = NULL; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_cierr_qp0: 207062306a36Sopenharmony_ci if (ctx->has_smi) 207162306a36Sopenharmony_ci ib_destroy_qp(ctx->qp[0].qp); 207262306a36Sopenharmony_ci ctx->qp[0].qp = NULL; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_cierr_pd: 207562306a36Sopenharmony_ci ib_dealloc_pd(ctx->pd); 207662306a36Sopenharmony_ci ctx->pd = NULL; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cierr_cq: 207962306a36Sopenharmony_ci ib_destroy_cq(ctx->cq); 208062306a36Sopenharmony_ci ctx->cq = NULL; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_cierr_buf: 208362306a36Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, create_tun); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_cierr_out_qp0: 208662306a36Sopenharmony_ci if (ctx->has_smi) 208762306a36Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, create_tun); 208862306a36Sopenharmony_cierr_out: 208962306a36Sopenharmony_ci ctx->state = DEMUX_PV_STATE_DOWN; 209062306a36Sopenharmony_ci return ret; 209162306a36Sopenharmony_ci} 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_cistatic void destroy_pv_resources(struct mlx4_ib_dev *dev, int slave, int port, 209462306a36Sopenharmony_ci struct mlx4_ib_demux_pv_ctx *ctx, int flush) 209562306a36Sopenharmony_ci{ 209662306a36Sopenharmony_ci if (!ctx) 209762306a36Sopenharmony_ci return; 209862306a36Sopenharmony_ci if (ctx->state > DEMUX_PV_STATE_DOWN) { 209962306a36Sopenharmony_ci ctx->state = DEMUX_PV_STATE_DOWNING; 210062306a36Sopenharmony_ci if (flush) 210162306a36Sopenharmony_ci flush_workqueue(ctx->wq); 210262306a36Sopenharmony_ci if (ctx->has_smi) { 210362306a36Sopenharmony_ci ib_destroy_qp(ctx->qp[0].qp); 210462306a36Sopenharmony_ci ctx->qp[0].qp = NULL; 210562306a36Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, 1); 210662306a36Sopenharmony_ci } 210762306a36Sopenharmony_ci ib_destroy_qp(ctx->qp[1].qp); 210862306a36Sopenharmony_ci ctx->qp[1].qp = NULL; 210962306a36Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, 1); 211062306a36Sopenharmony_ci ib_dealloc_pd(ctx->pd); 211162306a36Sopenharmony_ci ctx->pd = NULL; 211262306a36Sopenharmony_ci ib_destroy_cq(ctx->cq); 211362306a36Sopenharmony_ci ctx->cq = NULL; 211462306a36Sopenharmony_ci ctx->state = DEMUX_PV_STATE_DOWN; 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci} 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_cistatic int mlx4_ib_tunnels_update(struct mlx4_ib_dev *dev, int slave, 211962306a36Sopenharmony_ci int port, int do_init) 212062306a36Sopenharmony_ci{ 212162306a36Sopenharmony_ci int ret = 0; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci if (!do_init) { 212462306a36Sopenharmony_ci clean_vf_mcast(&dev->sriov.demux[port - 1], slave); 212562306a36Sopenharmony_ci /* for master, destroy real sqp resources */ 212662306a36Sopenharmony_ci if (slave == mlx4_master_func_num(dev->dev)) 212762306a36Sopenharmony_ci destroy_pv_resources(dev, slave, port, 212862306a36Sopenharmony_ci dev->sriov.sqps[port - 1], 1); 212962306a36Sopenharmony_ci /* destroy the tunnel qp resources */ 213062306a36Sopenharmony_ci destroy_pv_resources(dev, slave, port, 213162306a36Sopenharmony_ci dev->sriov.demux[port - 1].tun[slave], 1); 213262306a36Sopenharmony_ci return 0; 213362306a36Sopenharmony_ci } 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci /* create the tunnel qp resources */ 213662306a36Sopenharmony_ci ret = create_pv_resources(&dev->ib_dev, slave, port, 1, 213762306a36Sopenharmony_ci dev->sriov.demux[port - 1].tun[slave]); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci /* for master, create the real sqp resources */ 214062306a36Sopenharmony_ci if (!ret && slave == mlx4_master_func_num(dev->dev)) 214162306a36Sopenharmony_ci ret = create_pv_resources(&dev->ib_dev, slave, port, 0, 214262306a36Sopenharmony_ci dev->sriov.sqps[port - 1]); 214362306a36Sopenharmony_ci return ret; 214462306a36Sopenharmony_ci} 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_civoid mlx4_ib_tunnels_update_work(struct work_struct *work) 214762306a36Sopenharmony_ci{ 214862306a36Sopenharmony_ci struct mlx4_ib_demux_work *dmxw; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci dmxw = container_of(work, struct mlx4_ib_demux_work, work); 215162306a36Sopenharmony_ci mlx4_ib_tunnels_update(dmxw->dev, dmxw->slave, (int) dmxw->port, 215262306a36Sopenharmony_ci dmxw->do_init); 215362306a36Sopenharmony_ci kfree(dmxw); 215462306a36Sopenharmony_ci return; 215562306a36Sopenharmony_ci} 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_cistatic int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, 215862306a36Sopenharmony_ci struct mlx4_ib_demux_ctx *ctx, 215962306a36Sopenharmony_ci int port) 216062306a36Sopenharmony_ci{ 216162306a36Sopenharmony_ci char name[12]; 216262306a36Sopenharmony_ci int ret = 0; 216362306a36Sopenharmony_ci int i; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci ctx->tun = kcalloc(dev->dev->caps.sqp_demux, 216662306a36Sopenharmony_ci sizeof (struct mlx4_ib_demux_pv_ctx *), GFP_KERNEL); 216762306a36Sopenharmony_ci if (!ctx->tun) 216862306a36Sopenharmony_ci return -ENOMEM; 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci ctx->dev = dev; 217162306a36Sopenharmony_ci ctx->port = port; 217262306a36Sopenharmony_ci ctx->ib_dev = &dev->ib_dev; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci for (i = 0; 217562306a36Sopenharmony_ci i < min(dev->dev->caps.sqp_demux, 217662306a36Sopenharmony_ci (u16)(dev->dev->persist->num_vfs + 1)); 217762306a36Sopenharmony_ci i++) { 217862306a36Sopenharmony_ci struct mlx4_active_ports actv_ports = 217962306a36Sopenharmony_ci mlx4_get_active_ports(dev->dev, i); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci if (!test_bit(port - 1, actv_ports.ports)) 218262306a36Sopenharmony_ci continue; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci ret = alloc_pv_object(dev, i, port, &ctx->tun[i]); 218562306a36Sopenharmony_ci if (ret) { 218662306a36Sopenharmony_ci ret = -ENOMEM; 218762306a36Sopenharmony_ci goto err_mcg; 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci } 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci ret = mlx4_ib_mcg_port_init(ctx); 219262306a36Sopenharmony_ci if (ret) { 219362306a36Sopenharmony_ci pr_err("Failed initializing mcg para-virt (%d)\n", ret); 219462306a36Sopenharmony_ci goto err_mcg; 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci snprintf(name, sizeof(name), "mlx4_ibt%d", port); 219862306a36Sopenharmony_ci ctx->wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); 219962306a36Sopenharmony_ci if (!ctx->wq) { 220062306a36Sopenharmony_ci pr_err("Failed to create tunnelling WQ for port %d\n", port); 220162306a36Sopenharmony_ci ret = -ENOMEM; 220262306a36Sopenharmony_ci goto err_wq; 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci snprintf(name, sizeof(name), "mlx4_ibwi%d", port); 220662306a36Sopenharmony_ci ctx->wi_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); 220762306a36Sopenharmony_ci if (!ctx->wi_wq) { 220862306a36Sopenharmony_ci pr_err("Failed to create wire WQ for port %d\n", port); 220962306a36Sopenharmony_ci ret = -ENOMEM; 221062306a36Sopenharmony_ci goto err_wiwq; 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci snprintf(name, sizeof(name), "mlx4_ibud%d", port); 221462306a36Sopenharmony_ci ctx->ud_wq = alloc_ordered_workqueue(name, WQ_MEM_RECLAIM); 221562306a36Sopenharmony_ci if (!ctx->ud_wq) { 221662306a36Sopenharmony_ci pr_err("Failed to create up/down WQ for port %d\n", port); 221762306a36Sopenharmony_ci ret = -ENOMEM; 221862306a36Sopenharmony_ci goto err_udwq; 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci return 0; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_cierr_udwq: 222462306a36Sopenharmony_ci destroy_workqueue(ctx->wi_wq); 222562306a36Sopenharmony_ci ctx->wi_wq = NULL; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_cierr_wiwq: 222862306a36Sopenharmony_ci destroy_workqueue(ctx->wq); 222962306a36Sopenharmony_ci ctx->wq = NULL; 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_cierr_wq: 223262306a36Sopenharmony_ci mlx4_ib_mcg_port_cleanup(ctx, 1); 223362306a36Sopenharmony_cierr_mcg: 223462306a36Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) 223562306a36Sopenharmony_ci free_pv_object(dev, i, port); 223662306a36Sopenharmony_ci kfree(ctx->tun); 223762306a36Sopenharmony_ci ctx->tun = NULL; 223862306a36Sopenharmony_ci return ret; 223962306a36Sopenharmony_ci} 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_cistatic void mlx4_ib_free_sqp_ctx(struct mlx4_ib_demux_pv_ctx *sqp_ctx) 224262306a36Sopenharmony_ci{ 224362306a36Sopenharmony_ci if (sqp_ctx->state > DEMUX_PV_STATE_DOWN) { 224462306a36Sopenharmony_ci sqp_ctx->state = DEMUX_PV_STATE_DOWNING; 224562306a36Sopenharmony_ci flush_workqueue(sqp_ctx->wq); 224662306a36Sopenharmony_ci if (sqp_ctx->has_smi) { 224762306a36Sopenharmony_ci ib_destroy_qp(sqp_ctx->qp[0].qp); 224862306a36Sopenharmony_ci sqp_ctx->qp[0].qp = NULL; 224962306a36Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_SMI, 0); 225062306a36Sopenharmony_ci } 225162306a36Sopenharmony_ci ib_destroy_qp(sqp_ctx->qp[1].qp); 225262306a36Sopenharmony_ci sqp_ctx->qp[1].qp = NULL; 225362306a36Sopenharmony_ci mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_GSI, 0); 225462306a36Sopenharmony_ci ib_dealloc_pd(sqp_ctx->pd); 225562306a36Sopenharmony_ci sqp_ctx->pd = NULL; 225662306a36Sopenharmony_ci ib_destroy_cq(sqp_ctx->cq); 225762306a36Sopenharmony_ci sqp_ctx->cq = NULL; 225862306a36Sopenharmony_ci sqp_ctx->state = DEMUX_PV_STATE_DOWN; 225962306a36Sopenharmony_ci } 226062306a36Sopenharmony_ci} 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_cistatic void mlx4_ib_free_demux_ctx(struct mlx4_ib_demux_ctx *ctx) 226362306a36Sopenharmony_ci{ 226462306a36Sopenharmony_ci int i; 226562306a36Sopenharmony_ci if (ctx) { 226662306a36Sopenharmony_ci struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 226762306a36Sopenharmony_ci mlx4_ib_mcg_port_cleanup(ctx, 1); 226862306a36Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 226962306a36Sopenharmony_ci if (!ctx->tun[i]) 227062306a36Sopenharmony_ci continue; 227162306a36Sopenharmony_ci if (ctx->tun[i]->state > DEMUX_PV_STATE_DOWN) 227262306a36Sopenharmony_ci ctx->tun[i]->state = DEMUX_PV_STATE_DOWNING; 227362306a36Sopenharmony_ci } 227462306a36Sopenharmony_ci flush_workqueue(ctx->wq); 227562306a36Sopenharmony_ci flush_workqueue(ctx->wi_wq); 227662306a36Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 227762306a36Sopenharmony_ci destroy_pv_resources(dev, i, ctx->port, ctx->tun[i], 0); 227862306a36Sopenharmony_ci free_pv_object(dev, i, ctx->port); 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci kfree(ctx->tun); 228162306a36Sopenharmony_ci destroy_workqueue(ctx->ud_wq); 228262306a36Sopenharmony_ci destroy_workqueue(ctx->wi_wq); 228362306a36Sopenharmony_ci destroy_workqueue(ctx->wq); 228462306a36Sopenharmony_ci } 228562306a36Sopenharmony_ci} 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_cistatic void mlx4_ib_master_tunnels(struct mlx4_ib_dev *dev, int do_init) 228862306a36Sopenharmony_ci{ 228962306a36Sopenharmony_ci int i; 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci if (!mlx4_is_master(dev->dev)) 229262306a36Sopenharmony_ci return; 229362306a36Sopenharmony_ci /* initialize or tear down tunnel QPs for the master */ 229462306a36Sopenharmony_ci for (i = 0; i < dev->dev->caps.num_ports; i++) 229562306a36Sopenharmony_ci mlx4_ib_tunnels_update(dev, mlx4_master_func_num(dev->dev), i + 1, do_init); 229662306a36Sopenharmony_ci return; 229762306a36Sopenharmony_ci} 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ciint mlx4_ib_init_sriov(struct mlx4_ib_dev *dev) 230062306a36Sopenharmony_ci{ 230162306a36Sopenharmony_ci int i = 0; 230262306a36Sopenharmony_ci int err; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev)) 230562306a36Sopenharmony_ci return 0; 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci dev->sriov.is_going_down = 0; 230862306a36Sopenharmony_ci spin_lock_init(&dev->sriov.going_down_lock); 230962306a36Sopenharmony_ci mlx4_ib_cm_paravirt_init(dev); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "multi-function enabled\n"); 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci if (mlx4_is_slave(dev->dev)) { 231462306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "operating in qp1 tunnel mode\n"); 231562306a36Sopenharmony_ci return 0; 231662306a36Sopenharmony_ci } 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 231962306a36Sopenharmony_ci if (i == mlx4_master_func_num(dev->dev)) 232062306a36Sopenharmony_ci mlx4_put_slave_node_guid(dev->dev, i, dev->ib_dev.node_guid); 232162306a36Sopenharmony_ci else 232262306a36Sopenharmony_ci mlx4_put_slave_node_guid(dev->dev, i, mlx4_ib_gen_node_guid()); 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci err = mlx4_ib_init_alias_guid_service(dev); 232662306a36Sopenharmony_ci if (err) { 232762306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "Failed init alias guid process.\n"); 232862306a36Sopenharmony_ci goto paravirt_err; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci err = mlx4_ib_device_register_sysfs(dev); 233162306a36Sopenharmony_ci if (err) { 233262306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "Failed to register sysfs\n"); 233362306a36Sopenharmony_ci goto sysfs_err; 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n", 233762306a36Sopenharmony_ci dev->dev->caps.sqp_demux); 233862306a36Sopenharmony_ci for (i = 0; i < dev->num_ports; i++) { 233962306a36Sopenharmony_ci union ib_gid gid; 234062306a36Sopenharmony_ci err = __mlx4_ib_query_gid(&dev->ib_dev, i + 1, 0, &gid, 1); 234162306a36Sopenharmony_ci if (err) 234262306a36Sopenharmony_ci goto demux_err; 234362306a36Sopenharmony_ci dev->sriov.demux[i].guid_cache[0] = gid.global.interface_id; 234462306a36Sopenharmony_ci atomic64_set(&dev->sriov.demux[i].subnet_prefix, 234562306a36Sopenharmony_ci be64_to_cpu(gid.global.subnet_prefix)); 234662306a36Sopenharmony_ci err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1, 234762306a36Sopenharmony_ci &dev->sriov.sqps[i]); 234862306a36Sopenharmony_ci if (err) 234962306a36Sopenharmony_ci goto demux_err; 235062306a36Sopenharmony_ci err = mlx4_ib_alloc_demux_ctx(dev, &dev->sriov.demux[i], i + 1); 235162306a36Sopenharmony_ci if (err) 235262306a36Sopenharmony_ci goto free_pv; 235362306a36Sopenharmony_ci } 235462306a36Sopenharmony_ci mlx4_ib_master_tunnels(dev, 1); 235562306a36Sopenharmony_ci return 0; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_cifree_pv: 235862306a36Sopenharmony_ci free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1); 235962306a36Sopenharmony_cidemux_err: 236062306a36Sopenharmony_ci while (--i >= 0) { 236162306a36Sopenharmony_ci free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1); 236262306a36Sopenharmony_ci mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci mlx4_ib_device_unregister_sysfs(dev); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_cisysfs_err: 236762306a36Sopenharmony_ci mlx4_ib_destroy_alias_guid_service(dev); 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ciparavirt_err: 237062306a36Sopenharmony_ci mlx4_ib_cm_paravirt_clean(dev, -1); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci return err; 237362306a36Sopenharmony_ci} 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_civoid mlx4_ib_close_sriov(struct mlx4_ib_dev *dev) 237662306a36Sopenharmony_ci{ 237762306a36Sopenharmony_ci int i; 237862306a36Sopenharmony_ci unsigned long flags; 237962306a36Sopenharmony_ci 238062306a36Sopenharmony_ci if (!mlx4_is_mfunc(dev->dev)) 238162306a36Sopenharmony_ci return; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 238462306a36Sopenharmony_ci dev->sriov.is_going_down = 1; 238562306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 238662306a36Sopenharmony_ci if (mlx4_is_master(dev->dev)) { 238762306a36Sopenharmony_ci for (i = 0; i < dev->num_ports; i++) { 238862306a36Sopenharmony_ci flush_workqueue(dev->sriov.demux[i].ud_wq); 238962306a36Sopenharmony_ci mlx4_ib_free_sqp_ctx(dev->sriov.sqps[i]); 239062306a36Sopenharmony_ci kfree(dev->sriov.sqps[i]); 239162306a36Sopenharmony_ci dev->sriov.sqps[i] = NULL; 239262306a36Sopenharmony_ci mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 239362306a36Sopenharmony_ci } 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci mlx4_ib_cm_paravirt_clean(dev, -1); 239662306a36Sopenharmony_ci mlx4_ib_destroy_alias_guid_service(dev); 239762306a36Sopenharmony_ci mlx4_ib_device_unregister_sysfs(dev); 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci} 2400