1225c7b1fSRoland Dreier /* 2225c7b1fSRoland Dreier * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved. 3225c7b1fSRoland Dreier * 4225c7b1fSRoland Dreier * This software is available to you under a choice of one of two 5225c7b1fSRoland Dreier * licenses. You may choose to be licensed under the terms of the GNU 6225c7b1fSRoland Dreier * General Public License (GPL) Version 2, available from the file 7225c7b1fSRoland Dreier * COPYING in the main directory of this source tree, or the 8225c7b1fSRoland Dreier * OpenIB.org BSD license below: 9225c7b1fSRoland Dreier * 10225c7b1fSRoland Dreier * Redistribution and use in source and binary forms, with or 11225c7b1fSRoland Dreier * without modification, are permitted provided that the following 12225c7b1fSRoland Dreier * conditions are met: 13225c7b1fSRoland Dreier * 14225c7b1fSRoland Dreier * - Redistributions of source code must retain the above 15225c7b1fSRoland Dreier * copyright notice, this list of conditions and the following 16225c7b1fSRoland Dreier * disclaimer. 17225c7b1fSRoland Dreier * 18225c7b1fSRoland Dreier * - Redistributions in binary form must reproduce the above 19225c7b1fSRoland Dreier * copyright notice, this list of conditions and the following 20225c7b1fSRoland Dreier * disclaimer in the documentation and/or other materials 21225c7b1fSRoland Dreier * provided with the distribution. 22225c7b1fSRoland Dreier * 23225c7b1fSRoland Dreier * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24225c7b1fSRoland Dreier * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25225c7b1fSRoland Dreier * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26225c7b1fSRoland Dreier * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27225c7b1fSRoland Dreier * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28225c7b1fSRoland Dreier * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29225c7b1fSRoland Dreier * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30225c7b1fSRoland Dreier * SOFTWARE. 31225c7b1fSRoland Dreier */ 32225c7b1fSRoland Dreier 33225c7b1fSRoland Dreier #include <rdma/ib_mad.h> 34225c7b1fSRoland Dreier #include <rdma/ib_smi.h> 35225c7b1fSRoland Dreier 36225c7b1fSRoland Dreier #include <linux/mlx4/cmd.h> 375a0e3ad6STejun Heo #include <linux/gfp.h> 38c3779134SOr Gerlitz #include <rdma/ib_pma.h> 39225c7b1fSRoland Dreier 40225c7b1fSRoland Dreier #include "mlx4_ib.h" 41225c7b1fSRoland Dreier 42225c7b1fSRoland Dreier enum { 43225c7b1fSRoland Dreier MLX4_IB_VENDOR_CLASS1 = 0x9, 44225c7b1fSRoland Dreier MLX4_IB_VENDOR_CLASS2 = 0xa 45225c7b1fSRoland Dreier }; 46225c7b1fSRoland Dreier 47*fc06573dSJack Morgenstein #define MLX4_TUN_SEND_WRID_SHIFT 34 48*fc06573dSJack Morgenstein #define MLX4_TUN_QPN_SHIFT 32 49*fc06573dSJack Morgenstein #define MLX4_TUN_WRID_RECV (((u64) 1) << MLX4_TUN_SEND_WRID_SHIFT) 50*fc06573dSJack Morgenstein #define MLX4_TUN_SET_WRID_QPN(a) (((u64) ((a) & 0x3)) << MLX4_TUN_QPN_SHIFT) 51*fc06573dSJack Morgenstein 52*fc06573dSJack Morgenstein #define MLX4_TUN_IS_RECV(a) (((a) >> MLX4_TUN_SEND_WRID_SHIFT) & 0x1) 53*fc06573dSJack Morgenstein #define MLX4_TUN_WRID_QPN(a) (((a) >> MLX4_TUN_QPN_SHIFT) & 0x3) 54*fc06573dSJack Morgenstein 55*fc06573dSJack Morgenstein struct mlx4_mad_rcv_buf { 56*fc06573dSJack Morgenstein struct ib_grh grh; 57*fc06573dSJack Morgenstein u8 payload[256]; 58*fc06573dSJack Morgenstein } __packed; 59*fc06573dSJack Morgenstein 60*fc06573dSJack Morgenstein struct mlx4_mad_snd_buf { 61*fc06573dSJack Morgenstein u8 payload[256]; 62*fc06573dSJack Morgenstein } __packed; 63*fc06573dSJack Morgenstein 64*fc06573dSJack Morgenstein struct mlx4_tunnel_mad { 65*fc06573dSJack Morgenstein struct ib_grh grh; 66*fc06573dSJack Morgenstein struct mlx4_ib_tunnel_header hdr; 67*fc06573dSJack Morgenstein struct ib_mad mad; 68*fc06573dSJack Morgenstein } __packed; 69*fc06573dSJack Morgenstein 70*fc06573dSJack Morgenstein struct mlx4_rcv_tunnel_mad { 71*fc06573dSJack Morgenstein struct mlx4_rcv_tunnel_hdr hdr; 72*fc06573dSJack Morgenstein struct ib_grh grh; 73*fc06573dSJack Morgenstein struct ib_mad mad; 74*fc06573dSJack Morgenstein } __packed; 75*fc06573dSJack Morgenstein 76225c7b1fSRoland Dreier int mlx4_MAD_IFC(struct mlx4_ib_dev *dev, int ignore_mkey, int ignore_bkey, 77225c7b1fSRoland Dreier int port, struct ib_wc *in_wc, struct ib_grh *in_grh, 78225c7b1fSRoland Dreier void *in_mad, void *response_mad) 79225c7b1fSRoland Dreier { 80225c7b1fSRoland Dreier struct mlx4_cmd_mailbox *inmailbox, *outmailbox; 81225c7b1fSRoland Dreier void *inbox; 82225c7b1fSRoland Dreier int err; 83225c7b1fSRoland Dreier u32 in_modifier = port; 84225c7b1fSRoland Dreier u8 op_modifier = 0; 85225c7b1fSRoland Dreier 86225c7b1fSRoland Dreier inmailbox = mlx4_alloc_cmd_mailbox(dev->dev); 87225c7b1fSRoland Dreier if (IS_ERR(inmailbox)) 88225c7b1fSRoland Dreier return PTR_ERR(inmailbox); 89225c7b1fSRoland Dreier inbox = inmailbox->buf; 90225c7b1fSRoland Dreier 91225c7b1fSRoland Dreier outmailbox = mlx4_alloc_cmd_mailbox(dev->dev); 92225c7b1fSRoland Dreier if (IS_ERR(outmailbox)) { 93225c7b1fSRoland Dreier mlx4_free_cmd_mailbox(dev->dev, inmailbox); 94225c7b1fSRoland Dreier return PTR_ERR(outmailbox); 95225c7b1fSRoland Dreier } 96225c7b1fSRoland Dreier 97225c7b1fSRoland Dreier memcpy(inbox, in_mad, 256); 98225c7b1fSRoland Dreier 99225c7b1fSRoland Dreier /* 100225c7b1fSRoland Dreier * Key check traps can't be generated unless we have in_wc to 101225c7b1fSRoland Dreier * tell us where to send the trap. 102225c7b1fSRoland Dreier */ 103225c7b1fSRoland Dreier if (ignore_mkey || !in_wc) 104225c7b1fSRoland Dreier op_modifier |= 0x1; 105225c7b1fSRoland Dreier if (ignore_bkey || !in_wc) 106225c7b1fSRoland Dreier op_modifier |= 0x2; 107225c7b1fSRoland Dreier 108225c7b1fSRoland Dreier if (in_wc) { 109225c7b1fSRoland Dreier struct { 110225c7b1fSRoland Dreier __be32 my_qpn; 111225c7b1fSRoland Dreier u32 reserved1; 112225c7b1fSRoland Dreier __be32 rqpn; 113225c7b1fSRoland Dreier u8 sl; 114225c7b1fSRoland Dreier u8 g_path; 115225c7b1fSRoland Dreier u16 reserved2[2]; 116225c7b1fSRoland Dreier __be16 pkey; 117225c7b1fSRoland Dreier u32 reserved3[11]; 118225c7b1fSRoland Dreier u8 grh[40]; 119225c7b1fSRoland Dreier } *ext_info; 120225c7b1fSRoland Dreier 121225c7b1fSRoland Dreier memset(inbox + 256, 0, 256); 122225c7b1fSRoland Dreier ext_info = inbox + 256; 123225c7b1fSRoland Dreier 124225c7b1fSRoland Dreier ext_info->my_qpn = cpu_to_be32(in_wc->qp->qp_num); 125225c7b1fSRoland Dreier ext_info->rqpn = cpu_to_be32(in_wc->src_qp); 126225c7b1fSRoland Dreier ext_info->sl = in_wc->sl << 4; 127225c7b1fSRoland Dreier ext_info->g_path = in_wc->dlid_path_bits | 128225c7b1fSRoland Dreier (in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0); 129225c7b1fSRoland Dreier ext_info->pkey = cpu_to_be16(in_wc->pkey_index); 130225c7b1fSRoland Dreier 131225c7b1fSRoland Dreier if (in_grh) 132225c7b1fSRoland Dreier memcpy(ext_info->grh, in_grh, 40); 133225c7b1fSRoland Dreier 134225c7b1fSRoland Dreier op_modifier |= 0x4; 135225c7b1fSRoland Dreier 136225c7b1fSRoland Dreier in_modifier |= in_wc->slid << 16; 137225c7b1fSRoland Dreier } 138225c7b1fSRoland Dreier 139225c7b1fSRoland Dreier err = mlx4_cmd_box(dev->dev, inmailbox->dma, outmailbox->dma, 140225c7b1fSRoland Dreier in_modifier, op_modifier, 141f9baff50SJack Morgenstein MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, 142f9baff50SJack Morgenstein MLX4_CMD_NATIVE); 143225c7b1fSRoland Dreier 144fe11cb6bSIlpo Järvinen if (!err) 145225c7b1fSRoland Dreier memcpy(response_mad, outmailbox->buf, 256); 146225c7b1fSRoland Dreier 147225c7b1fSRoland Dreier mlx4_free_cmd_mailbox(dev->dev, inmailbox); 148225c7b1fSRoland Dreier mlx4_free_cmd_mailbox(dev->dev, outmailbox); 149225c7b1fSRoland Dreier 150225c7b1fSRoland Dreier return err; 151225c7b1fSRoland Dreier } 152225c7b1fSRoland Dreier 153225c7b1fSRoland Dreier static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl) 154225c7b1fSRoland Dreier { 155225c7b1fSRoland Dreier struct ib_ah *new_ah; 156225c7b1fSRoland Dreier struct ib_ah_attr ah_attr; 157df7fba66SJack Morgenstein unsigned long flags; 158225c7b1fSRoland Dreier 159225c7b1fSRoland Dreier if (!dev->send_agent[port_num - 1][0]) 160225c7b1fSRoland Dreier return; 161225c7b1fSRoland Dreier 162225c7b1fSRoland Dreier memset(&ah_attr, 0, sizeof ah_attr); 163225c7b1fSRoland Dreier ah_attr.dlid = lid; 164225c7b1fSRoland Dreier ah_attr.sl = sl; 165225c7b1fSRoland Dreier ah_attr.port_num = port_num; 166225c7b1fSRoland Dreier 167225c7b1fSRoland Dreier new_ah = ib_create_ah(dev->send_agent[port_num - 1][0]->qp->pd, 168225c7b1fSRoland Dreier &ah_attr); 169225c7b1fSRoland Dreier if (IS_ERR(new_ah)) 170225c7b1fSRoland Dreier return; 171225c7b1fSRoland Dreier 172df7fba66SJack Morgenstein spin_lock_irqsave(&dev->sm_lock, flags); 173225c7b1fSRoland Dreier if (dev->sm_ah[port_num - 1]) 174225c7b1fSRoland Dreier ib_destroy_ah(dev->sm_ah[port_num - 1]); 175225c7b1fSRoland Dreier dev->sm_ah[port_num - 1] = new_ah; 176df7fba66SJack Morgenstein spin_unlock_irqrestore(&dev->sm_lock, flags); 177225c7b1fSRoland Dreier } 178225c7b1fSRoland Dreier 179225c7b1fSRoland Dreier /* 18000f5ce99SJack Morgenstein * Snoop SM MADs for port info, GUID info, and P_Key table sets, so we can 18100f5ce99SJack Morgenstein * synthesize LID change, Client-Rereg, GID change, and P_Key change events. 182225c7b1fSRoland Dreier */ 183f0f6f346SMoni Shoua static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad, 184f0f6f346SMoni Shoua u16 prev_lid) 185225c7b1fSRoland Dreier { 18600f5ce99SJack Morgenstein struct ib_port_info *pinfo; 18700f5ce99SJack Morgenstein u16 lid; 188225c7b1fSRoland Dreier 18900f5ce99SJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ibdev); 190225c7b1fSRoland Dreier if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 191225c7b1fSRoland Dreier mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 19200f5ce99SJack Morgenstein mad->mad_hdr.method == IB_MGMT_METHOD_SET) 19300f5ce99SJack Morgenstein switch (mad->mad_hdr.attr_id) { 19400f5ce99SJack Morgenstein case IB_SMP_ATTR_PORT_INFO: 19500f5ce99SJack Morgenstein pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data; 19600f5ce99SJack Morgenstein lid = be16_to_cpu(pinfo->lid); 197225c7b1fSRoland Dreier 19800f5ce99SJack Morgenstein update_sm_ah(dev, port_num, 199225c7b1fSRoland Dreier be16_to_cpu(pinfo->sm_lid), 200225c7b1fSRoland Dreier pinfo->neighbormtu_mastersmsl & 0xf); 201225c7b1fSRoland Dreier 20200f5ce99SJack Morgenstein if (pinfo->clientrereg_resv_subnetto & 0x80) 20300f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 20400f5ce99SJack Morgenstein IB_EVENT_CLIENT_REREGISTER); 205225c7b1fSRoland Dreier 20600f5ce99SJack Morgenstein if (prev_lid != lid) 20700f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 20800f5ce99SJack Morgenstein IB_EVENT_LID_CHANGE); 20900f5ce99SJack Morgenstein break; 210225c7b1fSRoland Dreier 21100f5ce99SJack Morgenstein case IB_SMP_ATTR_PKEY_TABLE: 21200f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 21300f5ce99SJack Morgenstein IB_EVENT_PKEY_CHANGE); 21400f5ce99SJack Morgenstein break; 215f0f6f346SMoni Shoua 21600f5ce99SJack Morgenstein case IB_SMP_ATTR_GUID_INFO: 2176634961cSJack Morgenstein /* paravirtualized master's guid is guid 0 -- does not change */ 2186634961cSJack Morgenstein if (!mlx4_is_master(dev->dev)) 21900f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 22000f5ce99SJack Morgenstein IB_EVENT_GID_CHANGE); 22100f5ce99SJack Morgenstein break; 22200f5ce99SJack Morgenstein default: 22300f5ce99SJack Morgenstein break; 224225c7b1fSRoland Dreier } 225225c7b1fSRoland Dreier } 226225c7b1fSRoland Dreier 227225c7b1fSRoland Dreier static void node_desc_override(struct ib_device *dev, 228225c7b1fSRoland Dreier struct ib_mad *mad) 229225c7b1fSRoland Dreier { 230df7fba66SJack Morgenstein unsigned long flags; 231df7fba66SJack Morgenstein 232225c7b1fSRoland Dreier if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 233225c7b1fSRoland Dreier mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 234225c7b1fSRoland Dreier mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 235225c7b1fSRoland Dreier mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 236df7fba66SJack Morgenstein spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags); 237225c7b1fSRoland Dreier memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); 238df7fba66SJack Morgenstein spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags); 239225c7b1fSRoland Dreier } 240225c7b1fSRoland Dreier } 241225c7b1fSRoland Dreier 242225c7b1fSRoland Dreier static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *mad) 243225c7b1fSRoland Dreier { 244225c7b1fSRoland Dreier int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 245225c7b1fSRoland Dreier struct ib_mad_send_buf *send_buf; 246225c7b1fSRoland Dreier struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 247225c7b1fSRoland Dreier int ret; 248df7fba66SJack Morgenstein unsigned long flags; 249225c7b1fSRoland Dreier 250225c7b1fSRoland Dreier if (agent) { 251225c7b1fSRoland Dreier send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 252225c7b1fSRoland Dreier IB_MGMT_MAD_DATA, GFP_ATOMIC); 25313974909SDan Carpenter if (IS_ERR(send_buf)) 25413974909SDan Carpenter return; 255225c7b1fSRoland Dreier /* 256225c7b1fSRoland Dreier * We rely here on the fact that MLX QPs don't use the 257225c7b1fSRoland Dreier * address handle after the send is posted (this is 258225c7b1fSRoland Dreier * wrong following the IB spec strictly, but we know 259225c7b1fSRoland Dreier * it's OK for our devices). 260225c7b1fSRoland Dreier */ 261df7fba66SJack Morgenstein spin_lock_irqsave(&dev->sm_lock, flags); 262225c7b1fSRoland Dreier memcpy(send_buf->mad, mad, sizeof *mad); 263225c7b1fSRoland Dreier if ((send_buf->ah = dev->sm_ah[port_num - 1])) 264225c7b1fSRoland Dreier ret = ib_post_send_mad(send_buf, NULL); 265225c7b1fSRoland Dreier else 266225c7b1fSRoland Dreier ret = -EINVAL; 267df7fba66SJack Morgenstein spin_unlock_irqrestore(&dev->sm_lock, flags); 268225c7b1fSRoland Dreier 269225c7b1fSRoland Dreier if (ret) 270225c7b1fSRoland Dreier ib_free_send_mad(send_buf); 271225c7b1fSRoland Dreier } 272225c7b1fSRoland Dreier } 273225c7b1fSRoland Dreier 274c3779134SOr Gerlitz static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 275225c7b1fSRoland Dreier struct ib_wc *in_wc, struct ib_grh *in_grh, 276225c7b1fSRoland Dreier struct ib_mad *in_mad, struct ib_mad *out_mad) 277225c7b1fSRoland Dreier { 278f0f6f346SMoni Shoua u16 slid, prev_lid = 0; 279225c7b1fSRoland Dreier int err; 280f0f6f346SMoni Shoua struct ib_port_attr pattr; 281225c7b1fSRoland Dreier 282b1d8eb5aSJack Morgenstein if (in_wc && in_wc->qp->qp_num) { 283b1d8eb5aSJack Morgenstein pr_debug("received MAD: slid:%d sqpn:%d " 284b1d8eb5aSJack Morgenstein "dlid_bits:%d dqpn:%d wc_flags:0x%x, cls %x, mtd %x, atr %x\n", 285b1d8eb5aSJack Morgenstein in_wc->slid, in_wc->src_qp, 286b1d8eb5aSJack Morgenstein in_wc->dlid_path_bits, 287b1d8eb5aSJack Morgenstein in_wc->qp->qp_num, 288b1d8eb5aSJack Morgenstein in_wc->wc_flags, 289b1d8eb5aSJack Morgenstein in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method, 290b1d8eb5aSJack Morgenstein be16_to_cpu(in_mad->mad_hdr.attr_id)); 291b1d8eb5aSJack Morgenstein if (in_wc->wc_flags & IB_WC_GRH) { 292b1d8eb5aSJack Morgenstein pr_debug("sgid_hi:0x%016llx sgid_lo:0x%016llx\n", 293b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->sgid.global.subnet_prefix), 294b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->sgid.global.interface_id)); 295b1d8eb5aSJack Morgenstein pr_debug("dgid_hi:0x%016llx dgid_lo:0x%016llx\n", 296b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->dgid.global.subnet_prefix), 297b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->dgid.global.interface_id)); 298b1d8eb5aSJack Morgenstein } 299b1d8eb5aSJack Morgenstein } 300b1d8eb5aSJack Morgenstein 301225c7b1fSRoland Dreier slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); 302225c7b1fSRoland Dreier 303225c7b1fSRoland Dreier if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) { 304225c7b1fSRoland Dreier forward_trap(to_mdev(ibdev), port_num, in_mad); 305225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 306225c7b1fSRoland Dreier } 307225c7b1fSRoland Dreier 308225c7b1fSRoland Dreier if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 309225c7b1fSRoland Dreier in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 310225c7b1fSRoland Dreier if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 311225c7b1fSRoland Dreier in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 312225c7b1fSRoland Dreier in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 313225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 314225c7b1fSRoland Dreier 315225c7b1fSRoland Dreier /* 316a6f7feaeSJack Morgenstein * Don't process SMInfo queries -- the SMA can't handle them. 317225c7b1fSRoland Dreier */ 318a6f7feaeSJack Morgenstein if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) 319225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 320225c7b1fSRoland Dreier } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 321225c7b1fSRoland Dreier in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || 3226578cf33SEli Cohen in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2 || 3236578cf33SEli Cohen in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) { 324225c7b1fSRoland Dreier if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 325225c7b1fSRoland Dreier in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 326225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 327225c7b1fSRoland Dreier } else 328225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 329225c7b1fSRoland Dreier 330f0f6f346SMoni Shoua if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 331f0f6f346SMoni Shoua in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 332f0f6f346SMoni Shoua in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && 333f0f6f346SMoni Shoua in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 334f0f6f346SMoni Shoua !ib_query_port(ibdev, port_num, &pattr)) 335f0f6f346SMoni Shoua prev_lid = pattr.lid; 336f0f6f346SMoni Shoua 337225c7b1fSRoland Dreier err = mlx4_MAD_IFC(to_mdev(ibdev), 338225c7b1fSRoland Dreier mad_flags & IB_MAD_IGNORE_MKEY, 339225c7b1fSRoland Dreier mad_flags & IB_MAD_IGNORE_BKEY, 340225c7b1fSRoland Dreier port_num, in_wc, in_grh, in_mad, out_mad); 341225c7b1fSRoland Dreier if (err) 342225c7b1fSRoland Dreier return IB_MAD_RESULT_FAILURE; 343225c7b1fSRoland Dreier 344225c7b1fSRoland Dreier if (!out_mad->mad_hdr.status) { 34500f5ce99SJack Morgenstein if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)) 346f0f6f346SMoni Shoua smp_snoop(ibdev, port_num, in_mad, prev_lid); 347225c7b1fSRoland Dreier node_desc_override(ibdev, out_mad); 348225c7b1fSRoland Dreier } 349225c7b1fSRoland Dreier 350225c7b1fSRoland Dreier /* set return bit in status of directed route responses */ 351225c7b1fSRoland Dreier if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 352225c7b1fSRoland Dreier out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 353225c7b1fSRoland Dreier 354225c7b1fSRoland Dreier if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 355225c7b1fSRoland Dreier /* no response for trap repress */ 356225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 357225c7b1fSRoland Dreier 358225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 359225c7b1fSRoland Dreier } 360225c7b1fSRoland Dreier 361c3779134SOr Gerlitz static void edit_counter(struct mlx4_counter *cnt, 362c3779134SOr Gerlitz struct ib_pma_portcounters *pma_cnt) 363c3779134SOr Gerlitz { 364c3779134SOr Gerlitz pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2)); 365c3779134SOr Gerlitz pma_cnt->port_rcv_data = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2)); 366c3779134SOr Gerlitz pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames)); 367c3779134SOr Gerlitz pma_cnt->port_rcv_packets = cpu_to_be32(be64_to_cpu(cnt->rx_frames)); 368c3779134SOr Gerlitz } 369c3779134SOr Gerlitz 370c3779134SOr Gerlitz static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 371c3779134SOr Gerlitz struct ib_wc *in_wc, struct ib_grh *in_grh, 372c3779134SOr Gerlitz struct ib_mad *in_mad, struct ib_mad *out_mad) 373c3779134SOr Gerlitz { 374c3779134SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 375c3779134SOr Gerlitz struct mlx4_ib_dev *dev = to_mdev(ibdev); 376c3779134SOr Gerlitz int err; 377c3779134SOr Gerlitz u32 inmod = dev->counters[port_num - 1] & 0xffff; 378c3779134SOr Gerlitz u8 mode; 379c3779134SOr Gerlitz 380c3779134SOr Gerlitz if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT) 381c3779134SOr Gerlitz return -EINVAL; 382c3779134SOr Gerlitz 383c3779134SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev->dev); 384c3779134SOr Gerlitz if (IS_ERR(mailbox)) 385c3779134SOr Gerlitz return IB_MAD_RESULT_FAILURE; 386c3779134SOr Gerlitz 387c3779134SOr Gerlitz err = mlx4_cmd_box(dev->dev, 0, mailbox->dma, inmod, 0, 388f9baff50SJack Morgenstein MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C, 389f9baff50SJack Morgenstein MLX4_CMD_WRAPPED); 390c3779134SOr Gerlitz if (err) 391c3779134SOr Gerlitz err = IB_MAD_RESULT_FAILURE; 392c3779134SOr Gerlitz else { 393c3779134SOr Gerlitz memset(out_mad->data, 0, sizeof out_mad->data); 394c3779134SOr Gerlitz mode = ((struct mlx4_counter *)mailbox->buf)->counter_mode; 395c3779134SOr Gerlitz switch (mode & 0xf) { 396c3779134SOr Gerlitz case 0: 397c3779134SOr Gerlitz edit_counter(mailbox->buf, 398c3779134SOr Gerlitz (void *)(out_mad->data + 40)); 399c3779134SOr Gerlitz err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 400c3779134SOr Gerlitz break; 401c3779134SOr Gerlitz default: 402c3779134SOr Gerlitz err = IB_MAD_RESULT_FAILURE; 403c3779134SOr Gerlitz } 404c3779134SOr Gerlitz } 405c3779134SOr Gerlitz 406c3779134SOr Gerlitz mlx4_free_cmd_mailbox(dev->dev, mailbox); 407c3779134SOr Gerlitz 408c3779134SOr Gerlitz return err; 409c3779134SOr Gerlitz } 410c3779134SOr Gerlitz 411c3779134SOr Gerlitz int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 412c3779134SOr Gerlitz struct ib_wc *in_wc, struct ib_grh *in_grh, 413c3779134SOr Gerlitz struct ib_mad *in_mad, struct ib_mad *out_mad) 414c3779134SOr Gerlitz { 415c3779134SOr Gerlitz switch (rdma_port_get_link_layer(ibdev, port_num)) { 416c3779134SOr Gerlitz case IB_LINK_LAYER_INFINIBAND: 417c3779134SOr Gerlitz return ib_process_mad(ibdev, mad_flags, port_num, in_wc, 418c3779134SOr Gerlitz in_grh, in_mad, out_mad); 419c3779134SOr Gerlitz case IB_LINK_LAYER_ETHERNET: 420c3779134SOr Gerlitz return iboe_process_mad(ibdev, mad_flags, port_num, in_wc, 421c3779134SOr Gerlitz in_grh, in_mad, out_mad); 422c3779134SOr Gerlitz default: 423c3779134SOr Gerlitz return -EINVAL; 424c3779134SOr Gerlitz } 425c3779134SOr Gerlitz } 426c3779134SOr Gerlitz 427225c7b1fSRoland Dreier static void send_handler(struct ib_mad_agent *agent, 428225c7b1fSRoland Dreier struct ib_mad_send_wc *mad_send_wc) 429225c7b1fSRoland Dreier { 430225c7b1fSRoland Dreier ib_free_send_mad(mad_send_wc->send_buf); 431225c7b1fSRoland Dreier } 432225c7b1fSRoland Dreier 433225c7b1fSRoland Dreier int mlx4_ib_mad_init(struct mlx4_ib_dev *dev) 434225c7b1fSRoland Dreier { 435225c7b1fSRoland Dreier struct ib_mad_agent *agent; 436225c7b1fSRoland Dreier int p, q; 437225c7b1fSRoland Dreier int ret; 438fa417f7bSEli Cohen enum rdma_link_layer ll; 439225c7b1fSRoland Dreier 440fa417f7bSEli Cohen for (p = 0; p < dev->num_ports; ++p) { 441fa417f7bSEli Cohen ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1); 442225c7b1fSRoland Dreier for (q = 0; q <= 1; ++q) { 443fa417f7bSEli Cohen if (ll == IB_LINK_LAYER_INFINIBAND) { 444225c7b1fSRoland Dreier agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 445225c7b1fSRoland Dreier q ? IB_QPT_GSI : IB_QPT_SMI, 446225c7b1fSRoland Dreier NULL, 0, send_handler, 447225c7b1fSRoland Dreier NULL, NULL); 448225c7b1fSRoland Dreier if (IS_ERR(agent)) { 449225c7b1fSRoland Dreier ret = PTR_ERR(agent); 450225c7b1fSRoland Dreier goto err; 451225c7b1fSRoland Dreier } 452225c7b1fSRoland Dreier dev->send_agent[p][q] = agent; 453fa417f7bSEli Cohen } else 454fa417f7bSEli Cohen dev->send_agent[p][q] = NULL; 455fa417f7bSEli Cohen } 456225c7b1fSRoland Dreier } 457225c7b1fSRoland Dreier 458225c7b1fSRoland Dreier return 0; 459225c7b1fSRoland Dreier 460225c7b1fSRoland Dreier err: 4617ff93f8bSYevgeny Petrilin for (p = 0; p < dev->num_ports; ++p) 462225c7b1fSRoland Dreier for (q = 0; q <= 1; ++q) 463225c7b1fSRoland Dreier if (dev->send_agent[p][q]) 464225c7b1fSRoland Dreier ib_unregister_mad_agent(dev->send_agent[p][q]); 465225c7b1fSRoland Dreier 466225c7b1fSRoland Dreier return ret; 467225c7b1fSRoland Dreier } 468225c7b1fSRoland Dreier 469225c7b1fSRoland Dreier void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev) 470225c7b1fSRoland Dreier { 471225c7b1fSRoland Dreier struct ib_mad_agent *agent; 472225c7b1fSRoland Dreier int p, q; 473225c7b1fSRoland Dreier 4747ff93f8bSYevgeny Petrilin for (p = 0; p < dev->num_ports; ++p) { 475225c7b1fSRoland Dreier for (q = 0; q <= 1; ++q) { 476225c7b1fSRoland Dreier agent = dev->send_agent[p][q]; 477fa417f7bSEli Cohen if (agent) { 478225c7b1fSRoland Dreier dev->send_agent[p][q] = NULL; 479225c7b1fSRoland Dreier ib_unregister_mad_agent(agent); 480225c7b1fSRoland Dreier } 481fa417f7bSEli Cohen } 482225c7b1fSRoland Dreier 483225c7b1fSRoland Dreier if (dev->sm_ah[p]) 484225c7b1fSRoland Dreier ib_destroy_ah(dev->sm_ah[p]); 485225c7b1fSRoland Dreier } 486225c7b1fSRoland Dreier } 48700f5ce99SJack Morgenstein 48800f5ce99SJack Morgenstein void handle_port_mgmt_change_event(struct work_struct *work) 48900f5ce99SJack Morgenstein { 49000f5ce99SJack Morgenstein struct ib_event_work *ew = container_of(work, struct ib_event_work, work); 49100f5ce99SJack Morgenstein struct mlx4_ib_dev *dev = ew->ib_dev; 49200f5ce99SJack Morgenstein struct mlx4_eqe *eqe = &(ew->ib_eqe); 49300f5ce99SJack Morgenstein u8 port = eqe->event.port_mgmt_change.port; 49400f5ce99SJack Morgenstein u32 changed_attr; 49500f5ce99SJack Morgenstein 49600f5ce99SJack Morgenstein switch (eqe->subtype) { 49700f5ce99SJack Morgenstein case MLX4_DEV_PMC_SUBTYPE_PORT_INFO: 49800f5ce99SJack Morgenstein changed_attr = be32_to_cpu(eqe->event.port_mgmt_change.params.port_info.changed_attr); 49900f5ce99SJack Morgenstein 50000f5ce99SJack Morgenstein /* Update the SM ah - This should be done before handling 50100f5ce99SJack Morgenstein the other changed attributes so that MADs can be sent to the SM */ 50200f5ce99SJack Morgenstein if (changed_attr & MSTR_SM_CHANGE_MASK) { 50300f5ce99SJack Morgenstein u16 lid = be16_to_cpu(eqe->event.port_mgmt_change.params.port_info.mstr_sm_lid); 50400f5ce99SJack Morgenstein u8 sl = eqe->event.port_mgmt_change.params.port_info.mstr_sm_sl & 0xf; 50500f5ce99SJack Morgenstein update_sm_ah(dev, port, lid, sl); 50600f5ce99SJack Morgenstein } 50700f5ce99SJack Morgenstein 50800f5ce99SJack Morgenstein /* Check if it is a lid change event */ 50900f5ce99SJack Morgenstein if (changed_attr & MLX4_EQ_PORT_INFO_LID_CHANGE_MASK) 51000f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_LID_CHANGE); 51100f5ce99SJack Morgenstein 51200f5ce99SJack Morgenstein /* Generate GUID changed event */ 51300f5ce99SJack Morgenstein if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK) 51400f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 51500f5ce99SJack Morgenstein 51600f5ce99SJack Morgenstein if (changed_attr & MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK) 51700f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, 51800f5ce99SJack Morgenstein IB_EVENT_CLIENT_REREGISTER); 51900f5ce99SJack Morgenstein break; 52000f5ce99SJack Morgenstein 52100f5ce99SJack Morgenstein case MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE: 52200f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_PKEY_CHANGE); 52300f5ce99SJack Morgenstein break; 52400f5ce99SJack Morgenstein case MLX4_DEV_PMC_SUBTYPE_GUID_INFO: 5256634961cSJack Morgenstein /* paravirtualized master's guid is guid 0 -- does not change */ 5266634961cSJack Morgenstein if (!mlx4_is_master(dev->dev)) 52700f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 52800f5ce99SJack Morgenstein break; 52900f5ce99SJack Morgenstein default: 53000f5ce99SJack Morgenstein pr_warn("Unsupported subtype 0x%x for " 53100f5ce99SJack Morgenstein "Port Management Change event\n", eqe->subtype); 53200f5ce99SJack Morgenstein } 53300f5ce99SJack Morgenstein 53400f5ce99SJack Morgenstein kfree(ew); 53500f5ce99SJack Morgenstein } 53600f5ce99SJack Morgenstein 53700f5ce99SJack Morgenstein void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num, 53800f5ce99SJack Morgenstein enum ib_event_type type) 53900f5ce99SJack Morgenstein { 54000f5ce99SJack Morgenstein struct ib_event event; 54100f5ce99SJack Morgenstein 54200f5ce99SJack Morgenstein event.device = &dev->ib_dev; 54300f5ce99SJack Morgenstein event.element.port_num = port_num; 54400f5ce99SJack Morgenstein event.event = type; 54500f5ce99SJack Morgenstein 54600f5ce99SJack Morgenstein ib_dispatch_event(&event); 54700f5ce99SJack Morgenstein } 548*fc06573dSJack Morgenstein 549*fc06573dSJack Morgenstein static void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg) 550*fc06573dSJack Morgenstein { 551*fc06573dSJack Morgenstein unsigned long flags; 552*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; 553*fc06573dSJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 554*fc06573dSJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 555*fc06573dSJack Morgenstein if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) 556*fc06573dSJack Morgenstein queue_work(ctx->wq, &ctx->work); 557*fc06573dSJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 558*fc06573dSJack Morgenstein } 559*fc06573dSJack Morgenstein 560*fc06573dSJack Morgenstein static int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx, 561*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp, 562*fc06573dSJack Morgenstein int index) 563*fc06573dSJack Morgenstein { 564*fc06573dSJack Morgenstein struct ib_sge sg_list; 565*fc06573dSJack Morgenstein struct ib_recv_wr recv_wr, *bad_recv_wr; 566*fc06573dSJack Morgenstein int size; 567*fc06573dSJack Morgenstein 568*fc06573dSJack Morgenstein size = (tun_qp->qp->qp_type == IB_QPT_UD) ? 569*fc06573dSJack Morgenstein sizeof (struct mlx4_tunnel_mad) : sizeof (struct mlx4_mad_rcv_buf); 570*fc06573dSJack Morgenstein 571*fc06573dSJack Morgenstein sg_list.addr = tun_qp->ring[index].map; 572*fc06573dSJack Morgenstein sg_list.length = size; 573*fc06573dSJack Morgenstein sg_list.lkey = ctx->mr->lkey; 574*fc06573dSJack Morgenstein 575*fc06573dSJack Morgenstein recv_wr.next = NULL; 576*fc06573dSJack Morgenstein recv_wr.sg_list = &sg_list; 577*fc06573dSJack Morgenstein recv_wr.num_sge = 1; 578*fc06573dSJack Morgenstein recv_wr.wr_id = (u64) index | MLX4_TUN_WRID_RECV | 579*fc06573dSJack Morgenstein MLX4_TUN_SET_WRID_QPN(tun_qp->proxy_qpt); 580*fc06573dSJack Morgenstein ib_dma_sync_single_for_device(ctx->ib_dev, tun_qp->ring[index].map, 581*fc06573dSJack Morgenstein size, DMA_FROM_DEVICE); 582*fc06573dSJack Morgenstein return ib_post_recv(tun_qp->qp, &recv_wr, &bad_recv_wr); 583*fc06573dSJack Morgenstein } 584*fc06573dSJack Morgenstein 585*fc06573dSJack Morgenstein static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 586*fc06573dSJack Morgenstein enum ib_qp_type qp_type, int is_tun) 587*fc06573dSJack Morgenstein { 588*fc06573dSJack Morgenstein int i; 589*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp; 590*fc06573dSJack Morgenstein int rx_buf_size, tx_buf_size; 591*fc06573dSJack Morgenstein 592*fc06573dSJack Morgenstein if (qp_type > IB_QPT_GSI) 593*fc06573dSJack Morgenstein return -EINVAL; 594*fc06573dSJack Morgenstein 595*fc06573dSJack Morgenstein tun_qp = &ctx->qp[qp_type]; 596*fc06573dSJack Morgenstein 597*fc06573dSJack Morgenstein tun_qp->ring = kzalloc(sizeof (struct mlx4_ib_buf) * MLX4_NUM_TUNNEL_BUFS, 598*fc06573dSJack Morgenstein GFP_KERNEL); 599*fc06573dSJack Morgenstein if (!tun_qp->ring) 600*fc06573dSJack Morgenstein return -ENOMEM; 601*fc06573dSJack Morgenstein 602*fc06573dSJack Morgenstein tun_qp->tx_ring = kcalloc(MLX4_NUM_TUNNEL_BUFS, 603*fc06573dSJack Morgenstein sizeof (struct mlx4_ib_tun_tx_buf), 604*fc06573dSJack Morgenstein GFP_KERNEL); 605*fc06573dSJack Morgenstein if (!tun_qp->tx_ring) { 606*fc06573dSJack Morgenstein kfree(tun_qp->ring); 607*fc06573dSJack Morgenstein tun_qp->ring = NULL; 608*fc06573dSJack Morgenstein return -ENOMEM; 609*fc06573dSJack Morgenstein } 610*fc06573dSJack Morgenstein 611*fc06573dSJack Morgenstein if (is_tun) { 612*fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_tunnel_mad); 613*fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 614*fc06573dSJack Morgenstein } else { 615*fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 616*fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 617*fc06573dSJack Morgenstein } 618*fc06573dSJack Morgenstein 619*fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 620*fc06573dSJack Morgenstein tun_qp->ring[i].addr = kmalloc(rx_buf_size, GFP_KERNEL); 621*fc06573dSJack Morgenstein if (!tun_qp->ring[i].addr) 622*fc06573dSJack Morgenstein goto err; 623*fc06573dSJack Morgenstein tun_qp->ring[i].map = ib_dma_map_single(ctx->ib_dev, 624*fc06573dSJack Morgenstein tun_qp->ring[i].addr, 625*fc06573dSJack Morgenstein rx_buf_size, 626*fc06573dSJack Morgenstein DMA_FROM_DEVICE); 627*fc06573dSJack Morgenstein } 628*fc06573dSJack Morgenstein 629*fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 630*fc06573dSJack Morgenstein tun_qp->tx_ring[i].buf.addr = 631*fc06573dSJack Morgenstein kmalloc(tx_buf_size, GFP_KERNEL); 632*fc06573dSJack Morgenstein if (!tun_qp->tx_ring[i].buf.addr) 633*fc06573dSJack Morgenstein goto tx_err; 634*fc06573dSJack Morgenstein tun_qp->tx_ring[i].buf.map = 635*fc06573dSJack Morgenstein ib_dma_map_single(ctx->ib_dev, 636*fc06573dSJack Morgenstein tun_qp->tx_ring[i].buf.addr, 637*fc06573dSJack Morgenstein tx_buf_size, 638*fc06573dSJack Morgenstein DMA_TO_DEVICE); 639*fc06573dSJack Morgenstein tun_qp->tx_ring[i].ah = NULL; 640*fc06573dSJack Morgenstein } 641*fc06573dSJack Morgenstein spin_lock_init(&tun_qp->tx_lock); 642*fc06573dSJack Morgenstein tun_qp->tx_ix_head = 0; 643*fc06573dSJack Morgenstein tun_qp->tx_ix_tail = 0; 644*fc06573dSJack Morgenstein tun_qp->proxy_qpt = qp_type; 645*fc06573dSJack Morgenstein 646*fc06573dSJack Morgenstein return 0; 647*fc06573dSJack Morgenstein 648*fc06573dSJack Morgenstein tx_err: 649*fc06573dSJack Morgenstein while (i > 0) { 650*fc06573dSJack Morgenstein --i; 651*fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 652*fc06573dSJack Morgenstein tx_buf_size, DMA_TO_DEVICE); 653*fc06573dSJack Morgenstein kfree(tun_qp->tx_ring[i].buf.addr); 654*fc06573dSJack Morgenstein } 655*fc06573dSJack Morgenstein kfree(tun_qp->tx_ring); 656*fc06573dSJack Morgenstein tun_qp->tx_ring = NULL; 657*fc06573dSJack Morgenstein i = MLX4_NUM_TUNNEL_BUFS; 658*fc06573dSJack Morgenstein err: 659*fc06573dSJack Morgenstein while (i > 0) { 660*fc06573dSJack Morgenstein --i; 661*fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 662*fc06573dSJack Morgenstein rx_buf_size, DMA_FROM_DEVICE); 663*fc06573dSJack Morgenstein kfree(tun_qp->ring[i].addr); 664*fc06573dSJack Morgenstein } 665*fc06573dSJack Morgenstein kfree(tun_qp->ring); 666*fc06573dSJack Morgenstein tun_qp->ring = NULL; 667*fc06573dSJack Morgenstein return -ENOMEM; 668*fc06573dSJack Morgenstein } 669*fc06573dSJack Morgenstein 670*fc06573dSJack Morgenstein static void mlx4_ib_free_pv_qp_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 671*fc06573dSJack Morgenstein enum ib_qp_type qp_type, int is_tun) 672*fc06573dSJack Morgenstein { 673*fc06573dSJack Morgenstein int i; 674*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp; 675*fc06573dSJack Morgenstein int rx_buf_size, tx_buf_size; 676*fc06573dSJack Morgenstein 677*fc06573dSJack Morgenstein if (qp_type > IB_QPT_GSI) 678*fc06573dSJack Morgenstein return; 679*fc06573dSJack Morgenstein 680*fc06573dSJack Morgenstein tun_qp = &ctx->qp[qp_type]; 681*fc06573dSJack Morgenstein if (is_tun) { 682*fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_tunnel_mad); 683*fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 684*fc06573dSJack Morgenstein } else { 685*fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 686*fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 687*fc06573dSJack Morgenstein } 688*fc06573dSJack Morgenstein 689*fc06573dSJack Morgenstein 690*fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 691*fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 692*fc06573dSJack Morgenstein rx_buf_size, DMA_FROM_DEVICE); 693*fc06573dSJack Morgenstein kfree(tun_qp->ring[i].addr); 694*fc06573dSJack Morgenstein } 695*fc06573dSJack Morgenstein 696*fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 697*fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 698*fc06573dSJack Morgenstein tx_buf_size, DMA_TO_DEVICE); 699*fc06573dSJack Morgenstein kfree(tun_qp->tx_ring[i].buf.addr); 700*fc06573dSJack Morgenstein if (tun_qp->tx_ring[i].ah) 701*fc06573dSJack Morgenstein ib_destroy_ah(tun_qp->tx_ring[i].ah); 702*fc06573dSJack Morgenstein } 703*fc06573dSJack Morgenstein kfree(tun_qp->tx_ring); 704*fc06573dSJack Morgenstein kfree(tun_qp->ring); 705*fc06573dSJack Morgenstein } 706*fc06573dSJack Morgenstein 707*fc06573dSJack Morgenstein static void mlx4_ib_tunnel_comp_worker(struct work_struct *work) 708*fc06573dSJack Morgenstein { 709*fc06573dSJack Morgenstein /* dummy until next patch in series */ 710*fc06573dSJack Morgenstein } 711*fc06573dSJack Morgenstein 712*fc06573dSJack Morgenstein static void pv_qp_event_handler(struct ib_event *event, void *qp_context) 713*fc06573dSJack Morgenstein { 714*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *sqp = qp_context; 715*fc06573dSJack Morgenstein 716*fc06573dSJack Morgenstein /* It's worse than that! He's dead, Jim! */ 717*fc06573dSJack Morgenstein pr_err("Fatal error (%d) on a MAD QP on port %d\n", 718*fc06573dSJack Morgenstein event->event, sqp->port); 719*fc06573dSJack Morgenstein } 720*fc06573dSJack Morgenstein 721*fc06573dSJack Morgenstein static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx, 722*fc06573dSJack Morgenstein enum ib_qp_type qp_type, int create_tun) 723*fc06573dSJack Morgenstein { 724*fc06573dSJack Morgenstein int i, ret; 725*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp; 726*fc06573dSJack Morgenstein struct mlx4_ib_qp_tunnel_init_attr qp_init_attr; 727*fc06573dSJack Morgenstein struct ib_qp_attr attr; 728*fc06573dSJack Morgenstein int qp_attr_mask_INIT; 729*fc06573dSJack Morgenstein 730*fc06573dSJack Morgenstein if (qp_type > IB_QPT_GSI) 731*fc06573dSJack Morgenstein return -EINVAL; 732*fc06573dSJack Morgenstein 733*fc06573dSJack Morgenstein tun_qp = &ctx->qp[qp_type]; 734*fc06573dSJack Morgenstein 735*fc06573dSJack Morgenstein memset(&qp_init_attr, 0, sizeof qp_init_attr); 736*fc06573dSJack Morgenstein qp_init_attr.init_attr.send_cq = ctx->cq; 737*fc06573dSJack Morgenstein qp_init_attr.init_attr.recv_cq = ctx->cq; 738*fc06573dSJack Morgenstein qp_init_attr.init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; 739*fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_send_wr = MLX4_NUM_TUNNEL_BUFS; 740*fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_recv_wr = MLX4_NUM_TUNNEL_BUFS; 741*fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_send_sge = 1; 742*fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_recv_sge = 1; 743*fc06573dSJack Morgenstein if (create_tun) { 744*fc06573dSJack Morgenstein qp_init_attr.init_attr.qp_type = IB_QPT_UD; 745*fc06573dSJack Morgenstein qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_TUNNEL_QP; 746*fc06573dSJack Morgenstein qp_init_attr.port = ctx->port; 747*fc06573dSJack Morgenstein qp_init_attr.slave = ctx->slave; 748*fc06573dSJack Morgenstein qp_init_attr.proxy_qp_type = qp_type; 749*fc06573dSJack Morgenstein qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | 750*fc06573dSJack Morgenstein IB_QP_QKEY | IB_QP_PORT; 751*fc06573dSJack Morgenstein } else { 752*fc06573dSJack Morgenstein qp_init_attr.init_attr.qp_type = qp_type; 753*fc06573dSJack Morgenstein qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_SQP; 754*fc06573dSJack Morgenstein qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY; 755*fc06573dSJack Morgenstein } 756*fc06573dSJack Morgenstein qp_init_attr.init_attr.port_num = ctx->port; 757*fc06573dSJack Morgenstein qp_init_attr.init_attr.qp_context = ctx; 758*fc06573dSJack Morgenstein qp_init_attr.init_attr.event_handler = pv_qp_event_handler; 759*fc06573dSJack Morgenstein tun_qp->qp = ib_create_qp(ctx->pd, &qp_init_attr.init_attr); 760*fc06573dSJack Morgenstein if (IS_ERR(tun_qp->qp)) { 761*fc06573dSJack Morgenstein ret = PTR_ERR(tun_qp->qp); 762*fc06573dSJack Morgenstein tun_qp->qp = NULL; 763*fc06573dSJack Morgenstein pr_err("Couldn't create %s QP (%d)\n", 764*fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 765*fc06573dSJack Morgenstein return ret; 766*fc06573dSJack Morgenstein } 767*fc06573dSJack Morgenstein 768*fc06573dSJack Morgenstein memset(&attr, 0, sizeof attr); 769*fc06573dSJack Morgenstein attr.qp_state = IB_QPS_INIT; 770*fc06573dSJack Morgenstein attr.pkey_index = 771*fc06573dSJack Morgenstein to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0]; 772*fc06573dSJack Morgenstein attr.qkey = IB_QP1_QKEY; 773*fc06573dSJack Morgenstein attr.port_num = ctx->port; 774*fc06573dSJack Morgenstein ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT); 775*fc06573dSJack Morgenstein if (ret) { 776*fc06573dSJack Morgenstein pr_err("Couldn't change %s qp state to INIT (%d)\n", 777*fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 778*fc06573dSJack Morgenstein goto err_qp; 779*fc06573dSJack Morgenstein } 780*fc06573dSJack Morgenstein attr.qp_state = IB_QPS_RTR; 781*fc06573dSJack Morgenstein ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE); 782*fc06573dSJack Morgenstein if (ret) { 783*fc06573dSJack Morgenstein pr_err("Couldn't change %s qp state to RTR (%d)\n", 784*fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 785*fc06573dSJack Morgenstein goto err_qp; 786*fc06573dSJack Morgenstein } 787*fc06573dSJack Morgenstein attr.qp_state = IB_QPS_RTS; 788*fc06573dSJack Morgenstein attr.sq_psn = 0; 789*fc06573dSJack Morgenstein ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN); 790*fc06573dSJack Morgenstein if (ret) { 791*fc06573dSJack Morgenstein pr_err("Couldn't change %s qp state to RTS (%d)\n", 792*fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 793*fc06573dSJack Morgenstein goto err_qp; 794*fc06573dSJack Morgenstein } 795*fc06573dSJack Morgenstein 796*fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 797*fc06573dSJack Morgenstein ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, i); 798*fc06573dSJack Morgenstein if (ret) { 799*fc06573dSJack Morgenstein pr_err(" mlx4_ib_post_pv_buf error" 800*fc06573dSJack Morgenstein " (err = %d, i = %d)\n", ret, i); 801*fc06573dSJack Morgenstein goto err_qp; 802*fc06573dSJack Morgenstein } 803*fc06573dSJack Morgenstein } 804*fc06573dSJack Morgenstein return 0; 805*fc06573dSJack Morgenstein 806*fc06573dSJack Morgenstein err_qp: 807*fc06573dSJack Morgenstein ib_destroy_qp(tun_qp->qp); 808*fc06573dSJack Morgenstein tun_qp->qp = NULL; 809*fc06573dSJack Morgenstein return ret; 810*fc06573dSJack Morgenstein } 811*fc06573dSJack Morgenstein 812*fc06573dSJack Morgenstein /* 813*fc06573dSJack Morgenstein * IB MAD completion callback for real SQPs 814*fc06573dSJack Morgenstein */ 815*fc06573dSJack Morgenstein static void mlx4_ib_sqp_comp_worker(struct work_struct *work) 816*fc06573dSJack Morgenstein { 817*fc06573dSJack Morgenstein /* dummy until next patch in series */ 818*fc06573dSJack Morgenstein } 819*fc06573dSJack Morgenstein 820*fc06573dSJack Morgenstein static int alloc_pv_object(struct mlx4_ib_dev *dev, int slave, int port, 821*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx **ret_ctx) 822*fc06573dSJack Morgenstein { 823*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *ctx; 824*fc06573dSJack Morgenstein 825*fc06573dSJack Morgenstein *ret_ctx = NULL; 826*fc06573dSJack Morgenstein ctx = kzalloc(sizeof (struct mlx4_ib_demux_pv_ctx), GFP_KERNEL); 827*fc06573dSJack Morgenstein if (!ctx) { 828*fc06573dSJack Morgenstein pr_err("failed allocating pv resource context " 829*fc06573dSJack Morgenstein "for port %d, slave %d\n", port, slave); 830*fc06573dSJack Morgenstein return -ENOMEM; 831*fc06573dSJack Morgenstein } 832*fc06573dSJack Morgenstein 833*fc06573dSJack Morgenstein ctx->ib_dev = &dev->ib_dev; 834*fc06573dSJack Morgenstein ctx->port = port; 835*fc06573dSJack Morgenstein ctx->slave = slave; 836*fc06573dSJack Morgenstein *ret_ctx = ctx; 837*fc06573dSJack Morgenstein return 0; 838*fc06573dSJack Morgenstein } 839*fc06573dSJack Morgenstein 840*fc06573dSJack Morgenstein static void free_pv_object(struct mlx4_ib_dev *dev, int slave, int port) 841*fc06573dSJack Morgenstein { 842*fc06573dSJack Morgenstein if (dev->sriov.demux[port - 1].tun[slave]) { 843*fc06573dSJack Morgenstein kfree(dev->sriov.demux[port - 1].tun[slave]); 844*fc06573dSJack Morgenstein dev->sriov.demux[port - 1].tun[slave] = NULL; 845*fc06573dSJack Morgenstein } 846*fc06573dSJack Morgenstein } 847*fc06573dSJack Morgenstein 848*fc06573dSJack Morgenstein static int create_pv_resources(struct ib_device *ibdev, int slave, int port, 849*fc06573dSJack Morgenstein int create_tun, struct mlx4_ib_demux_pv_ctx *ctx) 850*fc06573dSJack Morgenstein { 851*fc06573dSJack Morgenstein int ret, cq_size; 852*fc06573dSJack Morgenstein 853*fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_STARTING; 854*fc06573dSJack Morgenstein /* have QP0 only on port owner, and only if link layer is IB */ 855*fc06573dSJack Morgenstein if (ctx->slave == mlx4_master_func_num(to_mdev(ctx->ib_dev)->dev) && 856*fc06573dSJack Morgenstein rdma_port_get_link_layer(ibdev, ctx->port) == IB_LINK_LAYER_INFINIBAND) 857*fc06573dSJack Morgenstein ctx->has_smi = 1; 858*fc06573dSJack Morgenstein 859*fc06573dSJack Morgenstein if (ctx->has_smi) { 860*fc06573dSJack Morgenstein ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_SMI, create_tun); 861*fc06573dSJack Morgenstein if (ret) { 862*fc06573dSJack Morgenstein pr_err("Failed allocating qp0 tunnel bufs (%d)\n", ret); 863*fc06573dSJack Morgenstein goto err_out; 864*fc06573dSJack Morgenstein } 865*fc06573dSJack Morgenstein } 866*fc06573dSJack Morgenstein 867*fc06573dSJack Morgenstein ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_GSI, create_tun); 868*fc06573dSJack Morgenstein if (ret) { 869*fc06573dSJack Morgenstein pr_err("Failed allocating qp1 tunnel bufs (%d)\n", ret); 870*fc06573dSJack Morgenstein goto err_out_qp0; 871*fc06573dSJack Morgenstein } 872*fc06573dSJack Morgenstein 873*fc06573dSJack Morgenstein cq_size = 2 * MLX4_NUM_TUNNEL_BUFS; 874*fc06573dSJack Morgenstein if (ctx->has_smi) 875*fc06573dSJack Morgenstein cq_size *= 2; 876*fc06573dSJack Morgenstein 877*fc06573dSJack Morgenstein ctx->cq = ib_create_cq(ctx->ib_dev, mlx4_ib_tunnel_comp_handler, 878*fc06573dSJack Morgenstein NULL, ctx, cq_size, 0); 879*fc06573dSJack Morgenstein if (IS_ERR(ctx->cq)) { 880*fc06573dSJack Morgenstein ret = PTR_ERR(ctx->cq); 881*fc06573dSJack Morgenstein pr_err("Couldn't create tunnel CQ (%d)\n", ret); 882*fc06573dSJack Morgenstein goto err_buf; 883*fc06573dSJack Morgenstein } 884*fc06573dSJack Morgenstein 885*fc06573dSJack Morgenstein ctx->pd = ib_alloc_pd(ctx->ib_dev); 886*fc06573dSJack Morgenstein if (IS_ERR(ctx->pd)) { 887*fc06573dSJack Morgenstein ret = PTR_ERR(ctx->pd); 888*fc06573dSJack Morgenstein pr_err("Couldn't create tunnel PD (%d)\n", ret); 889*fc06573dSJack Morgenstein goto err_cq; 890*fc06573dSJack Morgenstein } 891*fc06573dSJack Morgenstein 892*fc06573dSJack Morgenstein ctx->mr = ib_get_dma_mr(ctx->pd, IB_ACCESS_LOCAL_WRITE); 893*fc06573dSJack Morgenstein if (IS_ERR(ctx->mr)) { 894*fc06573dSJack Morgenstein ret = PTR_ERR(ctx->mr); 895*fc06573dSJack Morgenstein pr_err("Couldn't get tunnel DMA MR (%d)\n", ret); 896*fc06573dSJack Morgenstein goto err_pd; 897*fc06573dSJack Morgenstein } 898*fc06573dSJack Morgenstein 899*fc06573dSJack Morgenstein if (ctx->has_smi) { 900*fc06573dSJack Morgenstein ret = create_pv_sqp(ctx, IB_QPT_SMI, create_tun); 901*fc06573dSJack Morgenstein if (ret) { 902*fc06573dSJack Morgenstein pr_err("Couldn't create %s QP0 (%d)\n", 903*fc06573dSJack Morgenstein create_tun ? "tunnel for" : "", ret); 904*fc06573dSJack Morgenstein goto err_mr; 905*fc06573dSJack Morgenstein } 906*fc06573dSJack Morgenstein } 907*fc06573dSJack Morgenstein 908*fc06573dSJack Morgenstein ret = create_pv_sqp(ctx, IB_QPT_GSI, create_tun); 909*fc06573dSJack Morgenstein if (ret) { 910*fc06573dSJack Morgenstein pr_err("Couldn't create %s QP1 (%d)\n", 911*fc06573dSJack Morgenstein create_tun ? "tunnel for" : "", ret); 912*fc06573dSJack Morgenstein goto err_qp0; 913*fc06573dSJack Morgenstein } 914*fc06573dSJack Morgenstein 915*fc06573dSJack Morgenstein if (create_tun) 916*fc06573dSJack Morgenstein INIT_WORK(&ctx->work, mlx4_ib_tunnel_comp_worker); 917*fc06573dSJack Morgenstein else 918*fc06573dSJack Morgenstein INIT_WORK(&ctx->work, mlx4_ib_sqp_comp_worker); 919*fc06573dSJack Morgenstein 920*fc06573dSJack Morgenstein ctx->wq = to_mdev(ibdev)->sriov.demux[port - 1].wq; 921*fc06573dSJack Morgenstein 922*fc06573dSJack Morgenstein ret = ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 923*fc06573dSJack Morgenstein if (ret) { 924*fc06573dSJack Morgenstein pr_err("Couldn't arm tunnel cq (%d)\n", ret); 925*fc06573dSJack Morgenstein goto err_wq; 926*fc06573dSJack Morgenstein } 927*fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_ACTIVE; 928*fc06573dSJack Morgenstein return 0; 929*fc06573dSJack Morgenstein 930*fc06573dSJack Morgenstein err_wq: 931*fc06573dSJack Morgenstein ctx->wq = NULL; 932*fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[1].qp); 933*fc06573dSJack Morgenstein ctx->qp[1].qp = NULL; 934*fc06573dSJack Morgenstein 935*fc06573dSJack Morgenstein 936*fc06573dSJack Morgenstein err_qp0: 937*fc06573dSJack Morgenstein if (ctx->has_smi) 938*fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[0].qp); 939*fc06573dSJack Morgenstein ctx->qp[0].qp = NULL; 940*fc06573dSJack Morgenstein 941*fc06573dSJack Morgenstein err_mr: 942*fc06573dSJack Morgenstein ib_dereg_mr(ctx->mr); 943*fc06573dSJack Morgenstein ctx->mr = NULL; 944*fc06573dSJack Morgenstein 945*fc06573dSJack Morgenstein err_pd: 946*fc06573dSJack Morgenstein ib_dealloc_pd(ctx->pd); 947*fc06573dSJack Morgenstein ctx->pd = NULL; 948*fc06573dSJack Morgenstein 949*fc06573dSJack Morgenstein err_cq: 950*fc06573dSJack Morgenstein ib_destroy_cq(ctx->cq); 951*fc06573dSJack Morgenstein ctx->cq = NULL; 952*fc06573dSJack Morgenstein 953*fc06573dSJack Morgenstein err_buf: 954*fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, create_tun); 955*fc06573dSJack Morgenstein 956*fc06573dSJack Morgenstein err_out_qp0: 957*fc06573dSJack Morgenstein if (ctx->has_smi) 958*fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, create_tun); 959*fc06573dSJack Morgenstein err_out: 960*fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_DOWN; 961*fc06573dSJack Morgenstein return ret; 962*fc06573dSJack Morgenstein } 963*fc06573dSJack Morgenstein 964*fc06573dSJack Morgenstein static void destroy_pv_resources(struct mlx4_ib_dev *dev, int slave, int port, 965*fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *ctx, int flush) 966*fc06573dSJack Morgenstein { 967*fc06573dSJack Morgenstein if (!ctx) 968*fc06573dSJack Morgenstein return; 969*fc06573dSJack Morgenstein if (ctx->state > DEMUX_PV_STATE_DOWN) { 970*fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_DOWNING; 971*fc06573dSJack Morgenstein if (flush) 972*fc06573dSJack Morgenstein flush_workqueue(ctx->wq); 973*fc06573dSJack Morgenstein if (ctx->has_smi) { 974*fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[0].qp); 975*fc06573dSJack Morgenstein ctx->qp[0].qp = NULL; 976*fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, 1); 977*fc06573dSJack Morgenstein } 978*fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[1].qp); 979*fc06573dSJack Morgenstein ctx->qp[1].qp = NULL; 980*fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, 1); 981*fc06573dSJack Morgenstein ib_dereg_mr(ctx->mr); 982*fc06573dSJack Morgenstein ctx->mr = NULL; 983*fc06573dSJack Morgenstein ib_dealloc_pd(ctx->pd); 984*fc06573dSJack Morgenstein ctx->pd = NULL; 985*fc06573dSJack Morgenstein ib_destroy_cq(ctx->cq); 986*fc06573dSJack Morgenstein ctx->cq = NULL; 987*fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_DOWN; 988*fc06573dSJack Morgenstein } 989*fc06573dSJack Morgenstein } 990*fc06573dSJack Morgenstein 991*fc06573dSJack Morgenstein static int mlx4_ib_tunnels_update(struct mlx4_ib_dev *dev, int slave, 992*fc06573dSJack Morgenstein int port, int do_init) 993*fc06573dSJack Morgenstein { 994*fc06573dSJack Morgenstein int ret = 0; 995*fc06573dSJack Morgenstein 996*fc06573dSJack Morgenstein if (!do_init) { 997*fc06573dSJack Morgenstein /* for master, destroy real sqp resources */ 998*fc06573dSJack Morgenstein if (slave == mlx4_master_func_num(dev->dev)) 999*fc06573dSJack Morgenstein destroy_pv_resources(dev, slave, port, 1000*fc06573dSJack Morgenstein dev->sriov.sqps[port - 1], 1); 1001*fc06573dSJack Morgenstein /* destroy the tunnel qp resources */ 1002*fc06573dSJack Morgenstein destroy_pv_resources(dev, slave, port, 1003*fc06573dSJack Morgenstein dev->sriov.demux[port - 1].tun[slave], 1); 1004*fc06573dSJack Morgenstein return 0; 1005*fc06573dSJack Morgenstein } 1006*fc06573dSJack Morgenstein 1007*fc06573dSJack Morgenstein /* create the tunnel qp resources */ 1008*fc06573dSJack Morgenstein ret = create_pv_resources(&dev->ib_dev, slave, port, 1, 1009*fc06573dSJack Morgenstein dev->sriov.demux[port - 1].tun[slave]); 1010*fc06573dSJack Morgenstein 1011*fc06573dSJack Morgenstein /* for master, create the real sqp resources */ 1012*fc06573dSJack Morgenstein if (!ret && slave == mlx4_master_func_num(dev->dev)) 1013*fc06573dSJack Morgenstein ret = create_pv_resources(&dev->ib_dev, slave, port, 0, 1014*fc06573dSJack Morgenstein dev->sriov.sqps[port - 1]); 1015*fc06573dSJack Morgenstein return ret; 1016*fc06573dSJack Morgenstein } 1017*fc06573dSJack Morgenstein 1018*fc06573dSJack Morgenstein void mlx4_ib_tunnels_update_work(struct work_struct *work) 1019*fc06573dSJack Morgenstein { 1020*fc06573dSJack Morgenstein struct mlx4_ib_demux_work *dmxw; 1021*fc06573dSJack Morgenstein 1022*fc06573dSJack Morgenstein dmxw = container_of(work, struct mlx4_ib_demux_work, work); 1023*fc06573dSJack Morgenstein mlx4_ib_tunnels_update(dmxw->dev, dmxw->slave, (int) dmxw->port, 1024*fc06573dSJack Morgenstein dmxw->do_init); 1025*fc06573dSJack Morgenstein kfree(dmxw); 1026*fc06573dSJack Morgenstein return; 1027*fc06573dSJack Morgenstein } 1028*fc06573dSJack Morgenstein 1029*fc06573dSJack Morgenstein static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, 1030*fc06573dSJack Morgenstein struct mlx4_ib_demux_ctx *ctx, 1031*fc06573dSJack Morgenstein int port) 1032*fc06573dSJack Morgenstein { 1033*fc06573dSJack Morgenstein char name[12]; 1034*fc06573dSJack Morgenstein int ret = 0; 1035*fc06573dSJack Morgenstein int i; 1036*fc06573dSJack Morgenstein 1037*fc06573dSJack Morgenstein ctx->tun = kcalloc(dev->dev->caps.sqp_demux, 1038*fc06573dSJack Morgenstein sizeof (struct mlx4_ib_demux_pv_ctx *), GFP_KERNEL); 1039*fc06573dSJack Morgenstein if (!ctx->tun) 1040*fc06573dSJack Morgenstein return -ENOMEM; 1041*fc06573dSJack Morgenstein 1042*fc06573dSJack Morgenstein ctx->dev = dev; 1043*fc06573dSJack Morgenstein ctx->port = port; 1044*fc06573dSJack Morgenstein ctx->ib_dev = &dev->ib_dev; 1045*fc06573dSJack Morgenstein 1046*fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 1047*fc06573dSJack Morgenstein ret = alloc_pv_object(dev, i, port, &ctx->tun[i]); 1048*fc06573dSJack Morgenstein if (ret) { 1049*fc06573dSJack Morgenstein ret = -ENOMEM; 1050*fc06573dSJack Morgenstein goto err_wq; 1051*fc06573dSJack Morgenstein } 1052*fc06573dSJack Morgenstein } 1053*fc06573dSJack Morgenstein 1054*fc06573dSJack Morgenstein snprintf(name, sizeof name, "mlx4_ibt%d", port); 1055*fc06573dSJack Morgenstein ctx->wq = create_singlethread_workqueue(name); 1056*fc06573dSJack Morgenstein if (!ctx->wq) { 1057*fc06573dSJack Morgenstein pr_err("Failed to create tunnelling WQ for port %d\n", port); 1058*fc06573dSJack Morgenstein ret = -ENOMEM; 1059*fc06573dSJack Morgenstein goto err_wq; 1060*fc06573dSJack Morgenstein } 1061*fc06573dSJack Morgenstein 1062*fc06573dSJack Morgenstein snprintf(name, sizeof name, "mlx4_ibud%d", port); 1063*fc06573dSJack Morgenstein ctx->ud_wq = create_singlethread_workqueue(name); 1064*fc06573dSJack Morgenstein if (!ctx->ud_wq) { 1065*fc06573dSJack Morgenstein pr_err("Failed to create up/down WQ for port %d\n", port); 1066*fc06573dSJack Morgenstein ret = -ENOMEM; 1067*fc06573dSJack Morgenstein goto err_udwq; 1068*fc06573dSJack Morgenstein } 1069*fc06573dSJack Morgenstein 1070*fc06573dSJack Morgenstein return 0; 1071*fc06573dSJack Morgenstein 1072*fc06573dSJack Morgenstein err_udwq: 1073*fc06573dSJack Morgenstein destroy_workqueue(ctx->wq); 1074*fc06573dSJack Morgenstein ctx->wq = NULL; 1075*fc06573dSJack Morgenstein 1076*fc06573dSJack Morgenstein err_wq: 1077*fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) 1078*fc06573dSJack Morgenstein free_pv_object(dev, i, port); 1079*fc06573dSJack Morgenstein kfree(ctx->tun); 1080*fc06573dSJack Morgenstein ctx->tun = NULL; 1081*fc06573dSJack Morgenstein return ret; 1082*fc06573dSJack Morgenstein } 1083*fc06573dSJack Morgenstein 1084*fc06573dSJack Morgenstein static void mlx4_ib_free_sqp_ctx(struct mlx4_ib_demux_pv_ctx *sqp_ctx) 1085*fc06573dSJack Morgenstein { 1086*fc06573dSJack Morgenstein if (sqp_ctx->state > DEMUX_PV_STATE_DOWN) { 1087*fc06573dSJack Morgenstein sqp_ctx->state = DEMUX_PV_STATE_DOWNING; 1088*fc06573dSJack Morgenstein flush_workqueue(sqp_ctx->wq); 1089*fc06573dSJack Morgenstein if (sqp_ctx->has_smi) { 1090*fc06573dSJack Morgenstein ib_destroy_qp(sqp_ctx->qp[0].qp); 1091*fc06573dSJack Morgenstein sqp_ctx->qp[0].qp = NULL; 1092*fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_SMI, 0); 1093*fc06573dSJack Morgenstein } 1094*fc06573dSJack Morgenstein ib_destroy_qp(sqp_ctx->qp[1].qp); 1095*fc06573dSJack Morgenstein sqp_ctx->qp[1].qp = NULL; 1096*fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_GSI, 0); 1097*fc06573dSJack Morgenstein ib_dereg_mr(sqp_ctx->mr); 1098*fc06573dSJack Morgenstein sqp_ctx->mr = NULL; 1099*fc06573dSJack Morgenstein ib_dealloc_pd(sqp_ctx->pd); 1100*fc06573dSJack Morgenstein sqp_ctx->pd = NULL; 1101*fc06573dSJack Morgenstein ib_destroy_cq(sqp_ctx->cq); 1102*fc06573dSJack Morgenstein sqp_ctx->cq = NULL; 1103*fc06573dSJack Morgenstein sqp_ctx->state = DEMUX_PV_STATE_DOWN; 1104*fc06573dSJack Morgenstein } 1105*fc06573dSJack Morgenstein } 1106*fc06573dSJack Morgenstein 1107*fc06573dSJack Morgenstein static void mlx4_ib_free_demux_ctx(struct mlx4_ib_demux_ctx *ctx) 1108*fc06573dSJack Morgenstein { 1109*fc06573dSJack Morgenstein int i; 1110*fc06573dSJack Morgenstein if (ctx) { 1111*fc06573dSJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 1112*fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 1113*fc06573dSJack Morgenstein if (!ctx->tun[i]) 1114*fc06573dSJack Morgenstein continue; 1115*fc06573dSJack Morgenstein if (ctx->tun[i]->state > DEMUX_PV_STATE_DOWN) 1116*fc06573dSJack Morgenstein ctx->tun[i]->state = DEMUX_PV_STATE_DOWNING; 1117*fc06573dSJack Morgenstein } 1118*fc06573dSJack Morgenstein flush_workqueue(ctx->wq); 1119*fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 1120*fc06573dSJack Morgenstein destroy_pv_resources(dev, i, ctx->port, ctx->tun[i], 0); 1121*fc06573dSJack Morgenstein free_pv_object(dev, i, ctx->port); 1122*fc06573dSJack Morgenstein } 1123*fc06573dSJack Morgenstein kfree(ctx->tun); 1124*fc06573dSJack Morgenstein destroy_workqueue(ctx->ud_wq); 1125*fc06573dSJack Morgenstein destroy_workqueue(ctx->wq); 1126*fc06573dSJack Morgenstein } 1127*fc06573dSJack Morgenstein } 1128*fc06573dSJack Morgenstein 1129*fc06573dSJack Morgenstein static void mlx4_ib_master_tunnels(struct mlx4_ib_dev *dev, int do_init) 1130*fc06573dSJack Morgenstein { 1131*fc06573dSJack Morgenstein int i; 1132*fc06573dSJack Morgenstein 1133*fc06573dSJack Morgenstein if (!mlx4_is_master(dev->dev)) 1134*fc06573dSJack Morgenstein return; 1135*fc06573dSJack Morgenstein /* initialize or tear down tunnel QPs for the master */ 1136*fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.num_ports; i++) 1137*fc06573dSJack Morgenstein mlx4_ib_tunnels_update(dev, mlx4_master_func_num(dev->dev), i + 1, do_init); 1138*fc06573dSJack Morgenstein return; 1139*fc06573dSJack Morgenstein } 1140*fc06573dSJack Morgenstein 1141*fc06573dSJack Morgenstein int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev) 1142*fc06573dSJack Morgenstein { 1143*fc06573dSJack Morgenstein int i = 0; 1144*fc06573dSJack Morgenstein int err; 1145*fc06573dSJack Morgenstein 1146*fc06573dSJack Morgenstein if (!mlx4_is_mfunc(dev->dev)) 1147*fc06573dSJack Morgenstein return 0; 1148*fc06573dSJack Morgenstein 1149*fc06573dSJack Morgenstein dev->sriov.is_going_down = 0; 1150*fc06573dSJack Morgenstein spin_lock_init(&dev->sriov.going_down_lock); 1151*fc06573dSJack Morgenstein 1152*fc06573dSJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "multi-function enabled\n"); 1153*fc06573dSJack Morgenstein 1154*fc06573dSJack Morgenstein if (mlx4_is_slave(dev->dev)) { 1155*fc06573dSJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "operating in qp1 tunnel mode\n"); 1156*fc06573dSJack Morgenstein return 0; 1157*fc06573dSJack Morgenstein } 1158*fc06573dSJack Morgenstein 1159*fc06573dSJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n", 1160*fc06573dSJack Morgenstein dev->dev->caps.sqp_demux); 1161*fc06573dSJack Morgenstein for (i = 0; i < dev->num_ports; i++) { 1162*fc06573dSJack Morgenstein err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1, 1163*fc06573dSJack Morgenstein &dev->sriov.sqps[i]); 1164*fc06573dSJack Morgenstein if (err) 1165*fc06573dSJack Morgenstein goto demux_err; 1166*fc06573dSJack Morgenstein err = mlx4_ib_alloc_demux_ctx(dev, &dev->sriov.demux[i], i + 1); 1167*fc06573dSJack Morgenstein if (err) 1168*fc06573dSJack Morgenstein goto demux_err; 1169*fc06573dSJack Morgenstein } 1170*fc06573dSJack Morgenstein mlx4_ib_master_tunnels(dev, 1); 1171*fc06573dSJack Morgenstein return 0; 1172*fc06573dSJack Morgenstein 1173*fc06573dSJack Morgenstein demux_err: 1174*fc06573dSJack Morgenstein while (i > 0) { 1175*fc06573dSJack Morgenstein free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1); 1176*fc06573dSJack Morgenstein mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 1177*fc06573dSJack Morgenstein --i; 1178*fc06573dSJack Morgenstein } 1179*fc06573dSJack Morgenstein 1180*fc06573dSJack Morgenstein return err; 1181*fc06573dSJack Morgenstein } 1182*fc06573dSJack Morgenstein 1183*fc06573dSJack Morgenstein void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev) 1184*fc06573dSJack Morgenstein { 1185*fc06573dSJack Morgenstein int i; 1186*fc06573dSJack Morgenstein unsigned long flags; 1187*fc06573dSJack Morgenstein 1188*fc06573dSJack Morgenstein if (!mlx4_is_mfunc(dev->dev)) 1189*fc06573dSJack Morgenstein return; 1190*fc06573dSJack Morgenstein 1191*fc06573dSJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 1192*fc06573dSJack Morgenstein dev->sriov.is_going_down = 1; 1193*fc06573dSJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 1194*fc06573dSJack Morgenstein if (mlx4_is_master(dev->dev)) 1195*fc06573dSJack Morgenstein for (i = 0; i < dev->num_ports; i++) { 1196*fc06573dSJack Morgenstein flush_workqueue(dev->sriov.demux[i].ud_wq); 1197*fc06573dSJack Morgenstein mlx4_ib_free_sqp_ctx(dev->sriov.sqps[i]); 1198*fc06573dSJack Morgenstein kfree(dev->sriov.sqps[i]); 1199*fc06573dSJack Morgenstein dev->sriov.sqps[i] = NULL; 1200*fc06573dSJack Morgenstein mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 1201*fc06573dSJack Morgenstein } 1202*fc06573dSJack Morgenstein } 1203