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 47fc06573dSJack Morgenstein #define MLX4_TUN_SEND_WRID_SHIFT 34 48fc06573dSJack Morgenstein #define MLX4_TUN_QPN_SHIFT 32 49fc06573dSJack Morgenstein #define MLX4_TUN_WRID_RECV (((u64) 1) << MLX4_TUN_SEND_WRID_SHIFT) 50fc06573dSJack Morgenstein #define MLX4_TUN_SET_WRID_QPN(a) (((u64) ((a) & 0x3)) << MLX4_TUN_QPN_SHIFT) 51fc06573dSJack Morgenstein 52fc06573dSJack Morgenstein #define MLX4_TUN_IS_RECV(a) (((a) >> MLX4_TUN_SEND_WRID_SHIFT) & 0x1) 53fc06573dSJack Morgenstein #define MLX4_TUN_WRID_QPN(a) (((a) >> MLX4_TUN_QPN_SHIFT) & 0x3) 54fc06573dSJack Morgenstein 55fc06573dSJack Morgenstein struct mlx4_mad_rcv_buf { 56fc06573dSJack Morgenstein struct ib_grh grh; 57fc06573dSJack Morgenstein u8 payload[256]; 58fc06573dSJack Morgenstein } __packed; 59fc06573dSJack Morgenstein 60fc06573dSJack Morgenstein struct mlx4_mad_snd_buf { 61fc06573dSJack Morgenstein u8 payload[256]; 62fc06573dSJack Morgenstein } __packed; 63fc06573dSJack Morgenstein 64fc06573dSJack Morgenstein struct mlx4_tunnel_mad { 65fc06573dSJack Morgenstein struct ib_grh grh; 66fc06573dSJack Morgenstein struct mlx4_ib_tunnel_header hdr; 67fc06573dSJack Morgenstein struct ib_mad mad; 68fc06573dSJack Morgenstein } __packed; 69fc06573dSJack Morgenstein 70fc06573dSJack Morgenstein struct mlx4_rcv_tunnel_mad { 71fc06573dSJack Morgenstein struct mlx4_rcv_tunnel_hdr hdr; 72fc06573dSJack Morgenstein struct ib_grh grh; 73fc06573dSJack Morgenstein struct ib_mad mad; 74fc06573dSJack Morgenstein } __packed; 75fc06573dSJack 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; 188*54679e14SJack Morgenstein __be16 *base; 189*54679e14SJack Morgenstein u32 bn, pkey_change_bitmap; 190*54679e14SJack Morgenstein int i; 191*54679e14SJack Morgenstein 192225c7b1fSRoland Dreier 19300f5ce99SJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ibdev); 194225c7b1fSRoland Dreier if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 195225c7b1fSRoland Dreier mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 19600f5ce99SJack Morgenstein mad->mad_hdr.method == IB_MGMT_METHOD_SET) 19700f5ce99SJack Morgenstein switch (mad->mad_hdr.attr_id) { 19800f5ce99SJack Morgenstein case IB_SMP_ATTR_PORT_INFO: 19900f5ce99SJack Morgenstein pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data; 20000f5ce99SJack Morgenstein lid = be16_to_cpu(pinfo->lid); 201225c7b1fSRoland Dreier 20200f5ce99SJack Morgenstein update_sm_ah(dev, port_num, 203225c7b1fSRoland Dreier be16_to_cpu(pinfo->sm_lid), 204225c7b1fSRoland Dreier pinfo->neighbormtu_mastersmsl & 0xf); 205225c7b1fSRoland Dreier 20600f5ce99SJack Morgenstein if (pinfo->clientrereg_resv_subnetto & 0x80) 20700f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 20800f5ce99SJack Morgenstein IB_EVENT_CLIENT_REREGISTER); 209225c7b1fSRoland Dreier 21000f5ce99SJack Morgenstein if (prev_lid != lid) 21100f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 21200f5ce99SJack Morgenstein IB_EVENT_LID_CHANGE); 21300f5ce99SJack Morgenstein break; 214225c7b1fSRoland Dreier 21500f5ce99SJack Morgenstein case IB_SMP_ATTR_PKEY_TABLE: 216*54679e14SJack Morgenstein if (!mlx4_is_mfunc(dev->dev)) { 21700f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 21800f5ce99SJack Morgenstein IB_EVENT_PKEY_CHANGE); 21900f5ce99SJack Morgenstein break; 220*54679e14SJack Morgenstein } 221*54679e14SJack Morgenstein 222*54679e14SJack Morgenstein bn = be32_to_cpu(((struct ib_smp *)mad)->attr_mod) & 0xFFFF; 223*54679e14SJack Morgenstein base = (__be16 *) &(((struct ib_smp *)mad)->data[0]); 224*54679e14SJack Morgenstein pkey_change_bitmap = 0; 225*54679e14SJack Morgenstein for (i = 0; i < 32; i++) { 226*54679e14SJack Morgenstein pr_debug("PKEY[%d] = x%x\n", 227*54679e14SJack Morgenstein i + bn*32, be16_to_cpu(base[i])); 228*54679e14SJack Morgenstein if (be16_to_cpu(base[i]) != 229*54679e14SJack Morgenstein dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32]) { 230*54679e14SJack Morgenstein pkey_change_bitmap |= (1 << i); 231*54679e14SJack Morgenstein dev->pkeys.phys_pkey_cache[port_num - 1][i + bn*32] = 232*54679e14SJack Morgenstein be16_to_cpu(base[i]); 233*54679e14SJack Morgenstein } 234*54679e14SJack Morgenstein } 235*54679e14SJack Morgenstein pr_debug("PKEY Change event: port=%d, " 236*54679e14SJack Morgenstein "block=0x%x, change_bitmap=0x%x\n", 237*54679e14SJack Morgenstein port_num, bn, pkey_change_bitmap); 238*54679e14SJack Morgenstein 239*54679e14SJack Morgenstein if (pkey_change_bitmap) 240*54679e14SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 241*54679e14SJack Morgenstein IB_EVENT_PKEY_CHANGE); 242*54679e14SJack Morgenstein 243*54679e14SJack Morgenstein break; 244f0f6f346SMoni Shoua 24500f5ce99SJack Morgenstein case IB_SMP_ATTR_GUID_INFO: 2466634961cSJack Morgenstein /* paravirtualized master's guid is guid 0 -- does not change */ 2476634961cSJack Morgenstein if (!mlx4_is_master(dev->dev)) 24800f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port_num, 24900f5ce99SJack Morgenstein IB_EVENT_GID_CHANGE); 25000f5ce99SJack Morgenstein break; 25100f5ce99SJack Morgenstein default: 25200f5ce99SJack Morgenstein break; 253225c7b1fSRoland Dreier } 254225c7b1fSRoland Dreier } 255225c7b1fSRoland Dreier 256225c7b1fSRoland Dreier static void node_desc_override(struct ib_device *dev, 257225c7b1fSRoland Dreier struct ib_mad *mad) 258225c7b1fSRoland Dreier { 259df7fba66SJack Morgenstein unsigned long flags; 260df7fba66SJack Morgenstein 261225c7b1fSRoland Dreier if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 262225c7b1fSRoland Dreier mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 263225c7b1fSRoland Dreier mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP && 264225c7b1fSRoland Dreier mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) { 265df7fba66SJack Morgenstein spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags); 266225c7b1fSRoland Dreier memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64); 267df7fba66SJack Morgenstein spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags); 268225c7b1fSRoland Dreier } 269225c7b1fSRoland Dreier } 270225c7b1fSRoland Dreier 271225c7b1fSRoland Dreier static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *mad) 272225c7b1fSRoland Dreier { 273225c7b1fSRoland Dreier int qpn = mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED; 274225c7b1fSRoland Dreier struct ib_mad_send_buf *send_buf; 275225c7b1fSRoland Dreier struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn]; 276225c7b1fSRoland Dreier int ret; 277df7fba66SJack Morgenstein unsigned long flags; 278225c7b1fSRoland Dreier 279225c7b1fSRoland Dreier if (agent) { 280225c7b1fSRoland Dreier send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR, 281225c7b1fSRoland Dreier IB_MGMT_MAD_DATA, GFP_ATOMIC); 28213974909SDan Carpenter if (IS_ERR(send_buf)) 28313974909SDan Carpenter return; 284225c7b1fSRoland Dreier /* 285225c7b1fSRoland Dreier * We rely here on the fact that MLX QPs don't use the 286225c7b1fSRoland Dreier * address handle after the send is posted (this is 287225c7b1fSRoland Dreier * wrong following the IB spec strictly, but we know 288225c7b1fSRoland Dreier * it's OK for our devices). 289225c7b1fSRoland Dreier */ 290df7fba66SJack Morgenstein spin_lock_irqsave(&dev->sm_lock, flags); 291225c7b1fSRoland Dreier memcpy(send_buf->mad, mad, sizeof *mad); 292225c7b1fSRoland Dreier if ((send_buf->ah = dev->sm_ah[port_num - 1])) 293225c7b1fSRoland Dreier ret = ib_post_send_mad(send_buf, NULL); 294225c7b1fSRoland Dreier else 295225c7b1fSRoland Dreier ret = -EINVAL; 296df7fba66SJack Morgenstein spin_unlock_irqrestore(&dev->sm_lock, flags); 297225c7b1fSRoland Dreier 298225c7b1fSRoland Dreier if (ret) 299225c7b1fSRoland Dreier ib_free_send_mad(send_buf); 300225c7b1fSRoland Dreier } 301225c7b1fSRoland Dreier } 302225c7b1fSRoland Dreier 303c3779134SOr Gerlitz static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 304225c7b1fSRoland Dreier struct ib_wc *in_wc, struct ib_grh *in_grh, 305225c7b1fSRoland Dreier struct ib_mad *in_mad, struct ib_mad *out_mad) 306225c7b1fSRoland Dreier { 307f0f6f346SMoni Shoua u16 slid, prev_lid = 0; 308225c7b1fSRoland Dreier int err; 309f0f6f346SMoni Shoua struct ib_port_attr pattr; 310225c7b1fSRoland Dreier 311b1d8eb5aSJack Morgenstein if (in_wc && in_wc->qp->qp_num) { 312b1d8eb5aSJack Morgenstein pr_debug("received MAD: slid:%d sqpn:%d " 313b1d8eb5aSJack Morgenstein "dlid_bits:%d dqpn:%d wc_flags:0x%x, cls %x, mtd %x, atr %x\n", 314b1d8eb5aSJack Morgenstein in_wc->slid, in_wc->src_qp, 315b1d8eb5aSJack Morgenstein in_wc->dlid_path_bits, 316b1d8eb5aSJack Morgenstein in_wc->qp->qp_num, 317b1d8eb5aSJack Morgenstein in_wc->wc_flags, 318b1d8eb5aSJack Morgenstein in_mad->mad_hdr.mgmt_class, in_mad->mad_hdr.method, 319b1d8eb5aSJack Morgenstein be16_to_cpu(in_mad->mad_hdr.attr_id)); 320b1d8eb5aSJack Morgenstein if (in_wc->wc_flags & IB_WC_GRH) { 321b1d8eb5aSJack Morgenstein pr_debug("sgid_hi:0x%016llx sgid_lo:0x%016llx\n", 322b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->sgid.global.subnet_prefix), 323b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->sgid.global.interface_id)); 324b1d8eb5aSJack Morgenstein pr_debug("dgid_hi:0x%016llx dgid_lo:0x%016llx\n", 325b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->dgid.global.subnet_prefix), 326b1d8eb5aSJack Morgenstein be64_to_cpu(in_grh->dgid.global.interface_id)); 327b1d8eb5aSJack Morgenstein } 328b1d8eb5aSJack Morgenstein } 329b1d8eb5aSJack Morgenstein 330225c7b1fSRoland Dreier slid = in_wc ? in_wc->slid : be16_to_cpu(IB_LID_PERMISSIVE); 331225c7b1fSRoland Dreier 332225c7b1fSRoland Dreier if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP && slid == 0) { 333225c7b1fSRoland Dreier forward_trap(to_mdev(ibdev), port_num, in_mad); 334225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 335225c7b1fSRoland Dreier } 336225c7b1fSRoland Dreier 337225c7b1fSRoland Dreier if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 338225c7b1fSRoland Dreier in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { 339225c7b1fSRoland Dreier if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 340225c7b1fSRoland Dreier in_mad->mad_hdr.method != IB_MGMT_METHOD_SET && 341225c7b1fSRoland Dreier in_mad->mad_hdr.method != IB_MGMT_METHOD_TRAP_REPRESS) 342225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 343225c7b1fSRoland Dreier 344225c7b1fSRoland Dreier /* 345a6f7feaeSJack Morgenstein * Don't process SMInfo queries -- the SMA can't handle them. 346225c7b1fSRoland Dreier */ 347a6f7feaeSJack Morgenstein if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) 348225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 349225c7b1fSRoland Dreier } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || 350225c7b1fSRoland Dreier in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || 3516578cf33SEli Cohen in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS2 || 3526578cf33SEli Cohen in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_CONG_MGMT) { 353225c7b1fSRoland Dreier if (in_mad->mad_hdr.method != IB_MGMT_METHOD_GET && 354225c7b1fSRoland Dreier in_mad->mad_hdr.method != IB_MGMT_METHOD_SET) 355225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 356225c7b1fSRoland Dreier } else 357225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS; 358225c7b1fSRoland Dreier 359f0f6f346SMoni Shoua if ((in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 360f0f6f346SMoni Shoua in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 361f0f6f346SMoni Shoua in_mad->mad_hdr.method == IB_MGMT_METHOD_SET && 362f0f6f346SMoni Shoua in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && 363f0f6f346SMoni Shoua !ib_query_port(ibdev, port_num, &pattr)) 364f0f6f346SMoni Shoua prev_lid = pattr.lid; 365f0f6f346SMoni Shoua 366225c7b1fSRoland Dreier err = mlx4_MAD_IFC(to_mdev(ibdev), 367225c7b1fSRoland Dreier mad_flags & IB_MAD_IGNORE_MKEY, 368225c7b1fSRoland Dreier mad_flags & IB_MAD_IGNORE_BKEY, 369225c7b1fSRoland Dreier port_num, in_wc, in_grh, in_mad, out_mad); 370225c7b1fSRoland Dreier if (err) 371225c7b1fSRoland Dreier return IB_MAD_RESULT_FAILURE; 372225c7b1fSRoland Dreier 373225c7b1fSRoland Dreier if (!out_mad->mad_hdr.status) { 37400f5ce99SJack Morgenstein if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)) 375f0f6f346SMoni Shoua smp_snoop(ibdev, port_num, in_mad, prev_lid); 376225c7b1fSRoland Dreier node_desc_override(ibdev, out_mad); 377225c7b1fSRoland Dreier } 378225c7b1fSRoland Dreier 379225c7b1fSRoland Dreier /* set return bit in status of directed route responses */ 380225c7b1fSRoland Dreier if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) 381225c7b1fSRoland Dreier out_mad->mad_hdr.status |= cpu_to_be16(1 << 15); 382225c7b1fSRoland Dreier 383225c7b1fSRoland Dreier if (in_mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) 384225c7b1fSRoland Dreier /* no response for trap repress */ 385225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; 386225c7b1fSRoland Dreier 387225c7b1fSRoland Dreier return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 388225c7b1fSRoland Dreier } 389225c7b1fSRoland Dreier 390c3779134SOr Gerlitz static void edit_counter(struct mlx4_counter *cnt, 391c3779134SOr Gerlitz struct ib_pma_portcounters *pma_cnt) 392c3779134SOr Gerlitz { 393c3779134SOr Gerlitz pma_cnt->port_xmit_data = cpu_to_be32((be64_to_cpu(cnt->tx_bytes)>>2)); 394c3779134SOr Gerlitz pma_cnt->port_rcv_data = cpu_to_be32((be64_to_cpu(cnt->rx_bytes)>>2)); 395c3779134SOr Gerlitz pma_cnt->port_xmit_packets = cpu_to_be32(be64_to_cpu(cnt->tx_frames)); 396c3779134SOr Gerlitz pma_cnt->port_rcv_packets = cpu_to_be32(be64_to_cpu(cnt->rx_frames)); 397c3779134SOr Gerlitz } 398c3779134SOr Gerlitz 399c3779134SOr Gerlitz static int iboe_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 400c3779134SOr Gerlitz struct ib_wc *in_wc, struct ib_grh *in_grh, 401c3779134SOr Gerlitz struct ib_mad *in_mad, struct ib_mad *out_mad) 402c3779134SOr Gerlitz { 403c3779134SOr Gerlitz struct mlx4_cmd_mailbox *mailbox; 404c3779134SOr Gerlitz struct mlx4_ib_dev *dev = to_mdev(ibdev); 405c3779134SOr Gerlitz int err; 406c3779134SOr Gerlitz u32 inmod = dev->counters[port_num - 1] & 0xffff; 407c3779134SOr Gerlitz u8 mode; 408c3779134SOr Gerlitz 409c3779134SOr Gerlitz if (in_mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_PERF_MGMT) 410c3779134SOr Gerlitz return -EINVAL; 411c3779134SOr Gerlitz 412c3779134SOr Gerlitz mailbox = mlx4_alloc_cmd_mailbox(dev->dev); 413c3779134SOr Gerlitz if (IS_ERR(mailbox)) 414c3779134SOr Gerlitz return IB_MAD_RESULT_FAILURE; 415c3779134SOr Gerlitz 416c3779134SOr Gerlitz err = mlx4_cmd_box(dev->dev, 0, mailbox->dma, inmod, 0, 417f9baff50SJack Morgenstein MLX4_CMD_QUERY_IF_STAT, MLX4_CMD_TIME_CLASS_C, 418f9baff50SJack Morgenstein MLX4_CMD_WRAPPED); 419c3779134SOr Gerlitz if (err) 420c3779134SOr Gerlitz err = IB_MAD_RESULT_FAILURE; 421c3779134SOr Gerlitz else { 422c3779134SOr Gerlitz memset(out_mad->data, 0, sizeof out_mad->data); 423c3779134SOr Gerlitz mode = ((struct mlx4_counter *)mailbox->buf)->counter_mode; 424c3779134SOr Gerlitz switch (mode & 0xf) { 425c3779134SOr Gerlitz case 0: 426c3779134SOr Gerlitz edit_counter(mailbox->buf, 427c3779134SOr Gerlitz (void *)(out_mad->data + 40)); 428c3779134SOr Gerlitz err = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; 429c3779134SOr Gerlitz break; 430c3779134SOr Gerlitz default: 431c3779134SOr Gerlitz err = IB_MAD_RESULT_FAILURE; 432c3779134SOr Gerlitz } 433c3779134SOr Gerlitz } 434c3779134SOr Gerlitz 435c3779134SOr Gerlitz mlx4_free_cmd_mailbox(dev->dev, mailbox); 436c3779134SOr Gerlitz 437c3779134SOr Gerlitz return err; 438c3779134SOr Gerlitz } 439c3779134SOr Gerlitz 440c3779134SOr Gerlitz int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, 441c3779134SOr Gerlitz struct ib_wc *in_wc, struct ib_grh *in_grh, 442c3779134SOr Gerlitz struct ib_mad *in_mad, struct ib_mad *out_mad) 443c3779134SOr Gerlitz { 444c3779134SOr Gerlitz switch (rdma_port_get_link_layer(ibdev, port_num)) { 445c3779134SOr Gerlitz case IB_LINK_LAYER_INFINIBAND: 446c3779134SOr Gerlitz return ib_process_mad(ibdev, mad_flags, port_num, in_wc, 447c3779134SOr Gerlitz in_grh, in_mad, out_mad); 448c3779134SOr Gerlitz case IB_LINK_LAYER_ETHERNET: 449c3779134SOr Gerlitz return iboe_process_mad(ibdev, mad_flags, port_num, in_wc, 450c3779134SOr Gerlitz in_grh, in_mad, out_mad); 451c3779134SOr Gerlitz default: 452c3779134SOr Gerlitz return -EINVAL; 453c3779134SOr Gerlitz } 454c3779134SOr Gerlitz } 455c3779134SOr Gerlitz 456225c7b1fSRoland Dreier static void send_handler(struct ib_mad_agent *agent, 457225c7b1fSRoland Dreier struct ib_mad_send_wc *mad_send_wc) 458225c7b1fSRoland Dreier { 459225c7b1fSRoland Dreier ib_free_send_mad(mad_send_wc->send_buf); 460225c7b1fSRoland Dreier } 461225c7b1fSRoland Dreier 462225c7b1fSRoland Dreier int mlx4_ib_mad_init(struct mlx4_ib_dev *dev) 463225c7b1fSRoland Dreier { 464225c7b1fSRoland Dreier struct ib_mad_agent *agent; 465225c7b1fSRoland Dreier int p, q; 466225c7b1fSRoland Dreier int ret; 467fa417f7bSEli Cohen enum rdma_link_layer ll; 468225c7b1fSRoland Dreier 469fa417f7bSEli Cohen for (p = 0; p < dev->num_ports; ++p) { 470fa417f7bSEli Cohen ll = rdma_port_get_link_layer(&dev->ib_dev, p + 1); 471225c7b1fSRoland Dreier for (q = 0; q <= 1; ++q) { 472fa417f7bSEli Cohen if (ll == IB_LINK_LAYER_INFINIBAND) { 473225c7b1fSRoland Dreier agent = ib_register_mad_agent(&dev->ib_dev, p + 1, 474225c7b1fSRoland Dreier q ? IB_QPT_GSI : IB_QPT_SMI, 475225c7b1fSRoland Dreier NULL, 0, send_handler, 476225c7b1fSRoland Dreier NULL, NULL); 477225c7b1fSRoland Dreier if (IS_ERR(agent)) { 478225c7b1fSRoland Dreier ret = PTR_ERR(agent); 479225c7b1fSRoland Dreier goto err; 480225c7b1fSRoland Dreier } 481225c7b1fSRoland Dreier dev->send_agent[p][q] = agent; 482fa417f7bSEli Cohen } else 483fa417f7bSEli Cohen dev->send_agent[p][q] = NULL; 484fa417f7bSEli Cohen } 485225c7b1fSRoland Dreier } 486225c7b1fSRoland Dreier 487225c7b1fSRoland Dreier return 0; 488225c7b1fSRoland Dreier 489225c7b1fSRoland Dreier err: 4907ff93f8bSYevgeny Petrilin for (p = 0; p < dev->num_ports; ++p) 491225c7b1fSRoland Dreier for (q = 0; q <= 1; ++q) 492225c7b1fSRoland Dreier if (dev->send_agent[p][q]) 493225c7b1fSRoland Dreier ib_unregister_mad_agent(dev->send_agent[p][q]); 494225c7b1fSRoland Dreier 495225c7b1fSRoland Dreier return ret; 496225c7b1fSRoland Dreier } 497225c7b1fSRoland Dreier 498225c7b1fSRoland Dreier void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev) 499225c7b1fSRoland Dreier { 500225c7b1fSRoland Dreier struct ib_mad_agent *agent; 501225c7b1fSRoland Dreier int p, q; 502225c7b1fSRoland Dreier 5037ff93f8bSYevgeny Petrilin for (p = 0; p < dev->num_ports; ++p) { 504225c7b1fSRoland Dreier for (q = 0; q <= 1; ++q) { 505225c7b1fSRoland Dreier agent = dev->send_agent[p][q]; 506fa417f7bSEli Cohen if (agent) { 507225c7b1fSRoland Dreier dev->send_agent[p][q] = NULL; 508225c7b1fSRoland Dreier ib_unregister_mad_agent(agent); 509225c7b1fSRoland Dreier } 510fa417f7bSEli Cohen } 511225c7b1fSRoland Dreier 512225c7b1fSRoland Dreier if (dev->sm_ah[p]) 513225c7b1fSRoland Dreier ib_destroy_ah(dev->sm_ah[p]); 514225c7b1fSRoland Dreier } 515225c7b1fSRoland Dreier } 51600f5ce99SJack Morgenstein 51700f5ce99SJack Morgenstein void handle_port_mgmt_change_event(struct work_struct *work) 51800f5ce99SJack Morgenstein { 51900f5ce99SJack Morgenstein struct ib_event_work *ew = container_of(work, struct ib_event_work, work); 52000f5ce99SJack Morgenstein struct mlx4_ib_dev *dev = ew->ib_dev; 52100f5ce99SJack Morgenstein struct mlx4_eqe *eqe = &(ew->ib_eqe); 52200f5ce99SJack Morgenstein u8 port = eqe->event.port_mgmt_change.port; 52300f5ce99SJack Morgenstein u32 changed_attr; 52400f5ce99SJack Morgenstein 52500f5ce99SJack Morgenstein switch (eqe->subtype) { 52600f5ce99SJack Morgenstein case MLX4_DEV_PMC_SUBTYPE_PORT_INFO: 52700f5ce99SJack Morgenstein changed_attr = be32_to_cpu(eqe->event.port_mgmt_change.params.port_info.changed_attr); 52800f5ce99SJack Morgenstein 52900f5ce99SJack Morgenstein /* Update the SM ah - This should be done before handling 53000f5ce99SJack Morgenstein the other changed attributes so that MADs can be sent to the SM */ 53100f5ce99SJack Morgenstein if (changed_attr & MSTR_SM_CHANGE_MASK) { 53200f5ce99SJack Morgenstein u16 lid = be16_to_cpu(eqe->event.port_mgmt_change.params.port_info.mstr_sm_lid); 53300f5ce99SJack Morgenstein u8 sl = eqe->event.port_mgmt_change.params.port_info.mstr_sm_sl & 0xf; 53400f5ce99SJack Morgenstein update_sm_ah(dev, port, lid, sl); 53500f5ce99SJack Morgenstein } 53600f5ce99SJack Morgenstein 53700f5ce99SJack Morgenstein /* Check if it is a lid change event */ 53800f5ce99SJack Morgenstein if (changed_attr & MLX4_EQ_PORT_INFO_LID_CHANGE_MASK) 53900f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_LID_CHANGE); 54000f5ce99SJack Morgenstein 54100f5ce99SJack Morgenstein /* Generate GUID changed event */ 54200f5ce99SJack Morgenstein if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK) 54300f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 54400f5ce99SJack Morgenstein 54500f5ce99SJack Morgenstein if (changed_attr & MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK) 54600f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, 54700f5ce99SJack Morgenstein IB_EVENT_CLIENT_REREGISTER); 54800f5ce99SJack Morgenstein break; 54900f5ce99SJack Morgenstein 55000f5ce99SJack Morgenstein case MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE: 55100f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_PKEY_CHANGE); 55200f5ce99SJack Morgenstein break; 55300f5ce99SJack Morgenstein case MLX4_DEV_PMC_SUBTYPE_GUID_INFO: 5546634961cSJack Morgenstein /* paravirtualized master's guid is guid 0 -- does not change */ 5556634961cSJack Morgenstein if (!mlx4_is_master(dev->dev)) 55600f5ce99SJack Morgenstein mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE); 55700f5ce99SJack Morgenstein break; 55800f5ce99SJack Morgenstein default: 55900f5ce99SJack Morgenstein pr_warn("Unsupported subtype 0x%x for " 56000f5ce99SJack Morgenstein "Port Management Change event\n", eqe->subtype); 56100f5ce99SJack Morgenstein } 56200f5ce99SJack Morgenstein 56300f5ce99SJack Morgenstein kfree(ew); 56400f5ce99SJack Morgenstein } 56500f5ce99SJack Morgenstein 56600f5ce99SJack Morgenstein void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num, 56700f5ce99SJack Morgenstein enum ib_event_type type) 56800f5ce99SJack Morgenstein { 56900f5ce99SJack Morgenstein struct ib_event event; 57000f5ce99SJack Morgenstein 57100f5ce99SJack Morgenstein event.device = &dev->ib_dev; 57200f5ce99SJack Morgenstein event.element.port_num = port_num; 57300f5ce99SJack Morgenstein event.event = type; 57400f5ce99SJack Morgenstein 57500f5ce99SJack Morgenstein ib_dispatch_event(&event); 57600f5ce99SJack Morgenstein } 577fc06573dSJack Morgenstein 578fc06573dSJack Morgenstein static void mlx4_ib_tunnel_comp_handler(struct ib_cq *cq, void *arg) 579fc06573dSJack Morgenstein { 580fc06573dSJack Morgenstein unsigned long flags; 581fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *ctx = cq->cq_context; 582fc06573dSJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 583fc06573dSJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 584fc06573dSJack Morgenstein if (!dev->sriov.is_going_down && ctx->state == DEMUX_PV_STATE_ACTIVE) 585fc06573dSJack Morgenstein queue_work(ctx->wq, &ctx->work); 586fc06573dSJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 587fc06573dSJack Morgenstein } 588fc06573dSJack Morgenstein 589fc06573dSJack Morgenstein static int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx, 590fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp, 591fc06573dSJack Morgenstein int index) 592fc06573dSJack Morgenstein { 593fc06573dSJack Morgenstein struct ib_sge sg_list; 594fc06573dSJack Morgenstein struct ib_recv_wr recv_wr, *bad_recv_wr; 595fc06573dSJack Morgenstein int size; 596fc06573dSJack Morgenstein 597fc06573dSJack Morgenstein size = (tun_qp->qp->qp_type == IB_QPT_UD) ? 598fc06573dSJack Morgenstein sizeof (struct mlx4_tunnel_mad) : sizeof (struct mlx4_mad_rcv_buf); 599fc06573dSJack Morgenstein 600fc06573dSJack Morgenstein sg_list.addr = tun_qp->ring[index].map; 601fc06573dSJack Morgenstein sg_list.length = size; 602fc06573dSJack Morgenstein sg_list.lkey = ctx->mr->lkey; 603fc06573dSJack Morgenstein 604fc06573dSJack Morgenstein recv_wr.next = NULL; 605fc06573dSJack Morgenstein recv_wr.sg_list = &sg_list; 606fc06573dSJack Morgenstein recv_wr.num_sge = 1; 607fc06573dSJack Morgenstein recv_wr.wr_id = (u64) index | MLX4_TUN_WRID_RECV | 608fc06573dSJack Morgenstein MLX4_TUN_SET_WRID_QPN(tun_qp->proxy_qpt); 609fc06573dSJack Morgenstein ib_dma_sync_single_for_device(ctx->ib_dev, tun_qp->ring[index].map, 610fc06573dSJack Morgenstein size, DMA_FROM_DEVICE); 611fc06573dSJack Morgenstein return ib_post_recv(tun_qp->qp, &recv_wr, &bad_recv_wr); 612fc06573dSJack Morgenstein } 613fc06573dSJack Morgenstein 614fc06573dSJack Morgenstein static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 615fc06573dSJack Morgenstein enum ib_qp_type qp_type, int is_tun) 616fc06573dSJack Morgenstein { 617fc06573dSJack Morgenstein int i; 618fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp; 619fc06573dSJack Morgenstein int rx_buf_size, tx_buf_size; 620fc06573dSJack Morgenstein 621fc06573dSJack Morgenstein if (qp_type > IB_QPT_GSI) 622fc06573dSJack Morgenstein return -EINVAL; 623fc06573dSJack Morgenstein 624fc06573dSJack Morgenstein tun_qp = &ctx->qp[qp_type]; 625fc06573dSJack Morgenstein 626fc06573dSJack Morgenstein tun_qp->ring = kzalloc(sizeof (struct mlx4_ib_buf) * MLX4_NUM_TUNNEL_BUFS, 627fc06573dSJack Morgenstein GFP_KERNEL); 628fc06573dSJack Morgenstein if (!tun_qp->ring) 629fc06573dSJack Morgenstein return -ENOMEM; 630fc06573dSJack Morgenstein 631fc06573dSJack Morgenstein tun_qp->tx_ring = kcalloc(MLX4_NUM_TUNNEL_BUFS, 632fc06573dSJack Morgenstein sizeof (struct mlx4_ib_tun_tx_buf), 633fc06573dSJack Morgenstein GFP_KERNEL); 634fc06573dSJack Morgenstein if (!tun_qp->tx_ring) { 635fc06573dSJack Morgenstein kfree(tun_qp->ring); 636fc06573dSJack Morgenstein tun_qp->ring = NULL; 637fc06573dSJack Morgenstein return -ENOMEM; 638fc06573dSJack Morgenstein } 639fc06573dSJack Morgenstein 640fc06573dSJack Morgenstein if (is_tun) { 641fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_tunnel_mad); 642fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 643fc06573dSJack Morgenstein } else { 644fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 645fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 646fc06573dSJack Morgenstein } 647fc06573dSJack Morgenstein 648fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 649fc06573dSJack Morgenstein tun_qp->ring[i].addr = kmalloc(rx_buf_size, GFP_KERNEL); 650fc06573dSJack Morgenstein if (!tun_qp->ring[i].addr) 651fc06573dSJack Morgenstein goto err; 652fc06573dSJack Morgenstein tun_qp->ring[i].map = ib_dma_map_single(ctx->ib_dev, 653fc06573dSJack Morgenstein tun_qp->ring[i].addr, 654fc06573dSJack Morgenstein rx_buf_size, 655fc06573dSJack Morgenstein DMA_FROM_DEVICE); 656fc06573dSJack Morgenstein } 657fc06573dSJack Morgenstein 658fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 659fc06573dSJack Morgenstein tun_qp->tx_ring[i].buf.addr = 660fc06573dSJack Morgenstein kmalloc(tx_buf_size, GFP_KERNEL); 661fc06573dSJack Morgenstein if (!tun_qp->tx_ring[i].buf.addr) 662fc06573dSJack Morgenstein goto tx_err; 663fc06573dSJack Morgenstein tun_qp->tx_ring[i].buf.map = 664fc06573dSJack Morgenstein ib_dma_map_single(ctx->ib_dev, 665fc06573dSJack Morgenstein tun_qp->tx_ring[i].buf.addr, 666fc06573dSJack Morgenstein tx_buf_size, 667fc06573dSJack Morgenstein DMA_TO_DEVICE); 668fc06573dSJack Morgenstein tun_qp->tx_ring[i].ah = NULL; 669fc06573dSJack Morgenstein } 670fc06573dSJack Morgenstein spin_lock_init(&tun_qp->tx_lock); 671fc06573dSJack Morgenstein tun_qp->tx_ix_head = 0; 672fc06573dSJack Morgenstein tun_qp->tx_ix_tail = 0; 673fc06573dSJack Morgenstein tun_qp->proxy_qpt = qp_type; 674fc06573dSJack Morgenstein 675fc06573dSJack Morgenstein return 0; 676fc06573dSJack Morgenstein 677fc06573dSJack Morgenstein tx_err: 678fc06573dSJack Morgenstein while (i > 0) { 679fc06573dSJack Morgenstein --i; 680fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 681fc06573dSJack Morgenstein tx_buf_size, DMA_TO_DEVICE); 682fc06573dSJack Morgenstein kfree(tun_qp->tx_ring[i].buf.addr); 683fc06573dSJack Morgenstein } 684fc06573dSJack Morgenstein kfree(tun_qp->tx_ring); 685fc06573dSJack Morgenstein tun_qp->tx_ring = NULL; 686fc06573dSJack Morgenstein i = MLX4_NUM_TUNNEL_BUFS; 687fc06573dSJack Morgenstein err: 688fc06573dSJack Morgenstein while (i > 0) { 689fc06573dSJack Morgenstein --i; 690fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 691fc06573dSJack Morgenstein rx_buf_size, DMA_FROM_DEVICE); 692fc06573dSJack Morgenstein kfree(tun_qp->ring[i].addr); 693fc06573dSJack Morgenstein } 694fc06573dSJack Morgenstein kfree(tun_qp->ring); 695fc06573dSJack Morgenstein tun_qp->ring = NULL; 696fc06573dSJack Morgenstein return -ENOMEM; 697fc06573dSJack Morgenstein } 698fc06573dSJack Morgenstein 699fc06573dSJack Morgenstein static void mlx4_ib_free_pv_qp_bufs(struct mlx4_ib_demux_pv_ctx *ctx, 700fc06573dSJack Morgenstein enum ib_qp_type qp_type, int is_tun) 701fc06573dSJack Morgenstein { 702fc06573dSJack Morgenstein int i; 703fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp; 704fc06573dSJack Morgenstein int rx_buf_size, tx_buf_size; 705fc06573dSJack Morgenstein 706fc06573dSJack Morgenstein if (qp_type > IB_QPT_GSI) 707fc06573dSJack Morgenstein return; 708fc06573dSJack Morgenstein 709fc06573dSJack Morgenstein tun_qp = &ctx->qp[qp_type]; 710fc06573dSJack Morgenstein if (is_tun) { 711fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_tunnel_mad); 712fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_rcv_tunnel_mad); 713fc06573dSJack Morgenstein } else { 714fc06573dSJack Morgenstein rx_buf_size = sizeof (struct mlx4_mad_rcv_buf); 715fc06573dSJack Morgenstein tx_buf_size = sizeof (struct mlx4_mad_snd_buf); 716fc06573dSJack Morgenstein } 717fc06573dSJack Morgenstein 718fc06573dSJack Morgenstein 719fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 720fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->ring[i].map, 721fc06573dSJack Morgenstein rx_buf_size, DMA_FROM_DEVICE); 722fc06573dSJack Morgenstein kfree(tun_qp->ring[i].addr); 723fc06573dSJack Morgenstein } 724fc06573dSJack Morgenstein 725fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 726fc06573dSJack Morgenstein ib_dma_unmap_single(ctx->ib_dev, tun_qp->tx_ring[i].buf.map, 727fc06573dSJack Morgenstein tx_buf_size, DMA_TO_DEVICE); 728fc06573dSJack Morgenstein kfree(tun_qp->tx_ring[i].buf.addr); 729fc06573dSJack Morgenstein if (tun_qp->tx_ring[i].ah) 730fc06573dSJack Morgenstein ib_destroy_ah(tun_qp->tx_ring[i].ah); 731fc06573dSJack Morgenstein } 732fc06573dSJack Morgenstein kfree(tun_qp->tx_ring); 733fc06573dSJack Morgenstein kfree(tun_qp->ring); 734fc06573dSJack Morgenstein } 735fc06573dSJack Morgenstein 736fc06573dSJack Morgenstein static void mlx4_ib_tunnel_comp_worker(struct work_struct *work) 737fc06573dSJack Morgenstein { 738fc06573dSJack Morgenstein /* dummy until next patch in series */ 739fc06573dSJack Morgenstein } 740fc06573dSJack Morgenstein 741fc06573dSJack Morgenstein static void pv_qp_event_handler(struct ib_event *event, void *qp_context) 742fc06573dSJack Morgenstein { 743fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *sqp = qp_context; 744fc06573dSJack Morgenstein 745fc06573dSJack Morgenstein /* It's worse than that! He's dead, Jim! */ 746fc06573dSJack Morgenstein pr_err("Fatal error (%d) on a MAD QP on port %d\n", 747fc06573dSJack Morgenstein event->event, sqp->port); 748fc06573dSJack Morgenstein } 749fc06573dSJack Morgenstein 750fc06573dSJack Morgenstein static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx, 751fc06573dSJack Morgenstein enum ib_qp_type qp_type, int create_tun) 752fc06573dSJack Morgenstein { 753fc06573dSJack Morgenstein int i, ret; 754fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_qp *tun_qp; 755fc06573dSJack Morgenstein struct mlx4_ib_qp_tunnel_init_attr qp_init_attr; 756fc06573dSJack Morgenstein struct ib_qp_attr attr; 757fc06573dSJack Morgenstein int qp_attr_mask_INIT; 758fc06573dSJack Morgenstein 759fc06573dSJack Morgenstein if (qp_type > IB_QPT_GSI) 760fc06573dSJack Morgenstein return -EINVAL; 761fc06573dSJack Morgenstein 762fc06573dSJack Morgenstein tun_qp = &ctx->qp[qp_type]; 763fc06573dSJack Morgenstein 764fc06573dSJack Morgenstein memset(&qp_init_attr, 0, sizeof qp_init_attr); 765fc06573dSJack Morgenstein qp_init_attr.init_attr.send_cq = ctx->cq; 766fc06573dSJack Morgenstein qp_init_attr.init_attr.recv_cq = ctx->cq; 767fc06573dSJack Morgenstein qp_init_attr.init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; 768fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_send_wr = MLX4_NUM_TUNNEL_BUFS; 769fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_recv_wr = MLX4_NUM_TUNNEL_BUFS; 770fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_send_sge = 1; 771fc06573dSJack Morgenstein qp_init_attr.init_attr.cap.max_recv_sge = 1; 772fc06573dSJack Morgenstein if (create_tun) { 773fc06573dSJack Morgenstein qp_init_attr.init_attr.qp_type = IB_QPT_UD; 774fc06573dSJack Morgenstein qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_TUNNEL_QP; 775fc06573dSJack Morgenstein qp_init_attr.port = ctx->port; 776fc06573dSJack Morgenstein qp_init_attr.slave = ctx->slave; 777fc06573dSJack Morgenstein qp_init_attr.proxy_qp_type = qp_type; 778fc06573dSJack Morgenstein qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | 779fc06573dSJack Morgenstein IB_QP_QKEY | IB_QP_PORT; 780fc06573dSJack Morgenstein } else { 781fc06573dSJack Morgenstein qp_init_attr.init_attr.qp_type = qp_type; 782fc06573dSJack Morgenstein qp_init_attr.init_attr.create_flags = MLX4_IB_SRIOV_SQP; 783fc06573dSJack Morgenstein qp_attr_mask_INIT = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_QKEY; 784fc06573dSJack Morgenstein } 785fc06573dSJack Morgenstein qp_init_attr.init_attr.port_num = ctx->port; 786fc06573dSJack Morgenstein qp_init_attr.init_attr.qp_context = ctx; 787fc06573dSJack Morgenstein qp_init_attr.init_attr.event_handler = pv_qp_event_handler; 788fc06573dSJack Morgenstein tun_qp->qp = ib_create_qp(ctx->pd, &qp_init_attr.init_attr); 789fc06573dSJack Morgenstein if (IS_ERR(tun_qp->qp)) { 790fc06573dSJack Morgenstein ret = PTR_ERR(tun_qp->qp); 791fc06573dSJack Morgenstein tun_qp->qp = NULL; 792fc06573dSJack Morgenstein pr_err("Couldn't create %s QP (%d)\n", 793fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 794fc06573dSJack Morgenstein return ret; 795fc06573dSJack Morgenstein } 796fc06573dSJack Morgenstein 797fc06573dSJack Morgenstein memset(&attr, 0, sizeof attr); 798fc06573dSJack Morgenstein attr.qp_state = IB_QPS_INIT; 799fc06573dSJack Morgenstein attr.pkey_index = 800fc06573dSJack Morgenstein to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0]; 801fc06573dSJack Morgenstein attr.qkey = IB_QP1_QKEY; 802fc06573dSJack Morgenstein attr.port_num = ctx->port; 803fc06573dSJack Morgenstein ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT); 804fc06573dSJack Morgenstein if (ret) { 805fc06573dSJack Morgenstein pr_err("Couldn't change %s qp state to INIT (%d)\n", 806fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 807fc06573dSJack Morgenstein goto err_qp; 808fc06573dSJack Morgenstein } 809fc06573dSJack Morgenstein attr.qp_state = IB_QPS_RTR; 810fc06573dSJack Morgenstein ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE); 811fc06573dSJack Morgenstein if (ret) { 812fc06573dSJack Morgenstein pr_err("Couldn't change %s qp state to RTR (%d)\n", 813fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 814fc06573dSJack Morgenstein goto err_qp; 815fc06573dSJack Morgenstein } 816fc06573dSJack Morgenstein attr.qp_state = IB_QPS_RTS; 817fc06573dSJack Morgenstein attr.sq_psn = 0; 818fc06573dSJack Morgenstein ret = ib_modify_qp(tun_qp->qp, &attr, IB_QP_STATE | IB_QP_SQ_PSN); 819fc06573dSJack Morgenstein if (ret) { 820fc06573dSJack Morgenstein pr_err("Couldn't change %s qp state to RTS (%d)\n", 821fc06573dSJack Morgenstein create_tun ? "tunnel" : "special", ret); 822fc06573dSJack Morgenstein goto err_qp; 823fc06573dSJack Morgenstein } 824fc06573dSJack Morgenstein 825fc06573dSJack Morgenstein for (i = 0; i < MLX4_NUM_TUNNEL_BUFS; i++) { 826fc06573dSJack Morgenstein ret = mlx4_ib_post_pv_qp_buf(ctx, tun_qp, i); 827fc06573dSJack Morgenstein if (ret) { 828fc06573dSJack Morgenstein pr_err(" mlx4_ib_post_pv_buf error" 829fc06573dSJack Morgenstein " (err = %d, i = %d)\n", ret, i); 830fc06573dSJack Morgenstein goto err_qp; 831fc06573dSJack Morgenstein } 832fc06573dSJack Morgenstein } 833fc06573dSJack Morgenstein return 0; 834fc06573dSJack Morgenstein 835fc06573dSJack Morgenstein err_qp: 836fc06573dSJack Morgenstein ib_destroy_qp(tun_qp->qp); 837fc06573dSJack Morgenstein tun_qp->qp = NULL; 838fc06573dSJack Morgenstein return ret; 839fc06573dSJack Morgenstein } 840fc06573dSJack Morgenstein 841fc06573dSJack Morgenstein /* 842fc06573dSJack Morgenstein * IB MAD completion callback for real SQPs 843fc06573dSJack Morgenstein */ 844fc06573dSJack Morgenstein static void mlx4_ib_sqp_comp_worker(struct work_struct *work) 845fc06573dSJack Morgenstein { 846fc06573dSJack Morgenstein /* dummy until next patch in series */ 847fc06573dSJack Morgenstein } 848fc06573dSJack Morgenstein 849fc06573dSJack Morgenstein static int alloc_pv_object(struct mlx4_ib_dev *dev, int slave, int port, 850fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx **ret_ctx) 851fc06573dSJack Morgenstein { 852fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *ctx; 853fc06573dSJack Morgenstein 854fc06573dSJack Morgenstein *ret_ctx = NULL; 855fc06573dSJack Morgenstein ctx = kzalloc(sizeof (struct mlx4_ib_demux_pv_ctx), GFP_KERNEL); 856fc06573dSJack Morgenstein if (!ctx) { 857fc06573dSJack Morgenstein pr_err("failed allocating pv resource context " 858fc06573dSJack Morgenstein "for port %d, slave %d\n", port, slave); 859fc06573dSJack Morgenstein return -ENOMEM; 860fc06573dSJack Morgenstein } 861fc06573dSJack Morgenstein 862fc06573dSJack Morgenstein ctx->ib_dev = &dev->ib_dev; 863fc06573dSJack Morgenstein ctx->port = port; 864fc06573dSJack Morgenstein ctx->slave = slave; 865fc06573dSJack Morgenstein *ret_ctx = ctx; 866fc06573dSJack Morgenstein return 0; 867fc06573dSJack Morgenstein } 868fc06573dSJack Morgenstein 869fc06573dSJack Morgenstein static void free_pv_object(struct mlx4_ib_dev *dev, int slave, int port) 870fc06573dSJack Morgenstein { 871fc06573dSJack Morgenstein if (dev->sriov.demux[port - 1].tun[slave]) { 872fc06573dSJack Morgenstein kfree(dev->sriov.demux[port - 1].tun[slave]); 873fc06573dSJack Morgenstein dev->sriov.demux[port - 1].tun[slave] = NULL; 874fc06573dSJack Morgenstein } 875fc06573dSJack Morgenstein } 876fc06573dSJack Morgenstein 877fc06573dSJack Morgenstein static int create_pv_resources(struct ib_device *ibdev, int slave, int port, 878fc06573dSJack Morgenstein int create_tun, struct mlx4_ib_demux_pv_ctx *ctx) 879fc06573dSJack Morgenstein { 880fc06573dSJack Morgenstein int ret, cq_size; 881fc06573dSJack Morgenstein 882fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_STARTING; 883fc06573dSJack Morgenstein /* have QP0 only on port owner, and only if link layer is IB */ 884fc06573dSJack Morgenstein if (ctx->slave == mlx4_master_func_num(to_mdev(ctx->ib_dev)->dev) && 885fc06573dSJack Morgenstein rdma_port_get_link_layer(ibdev, ctx->port) == IB_LINK_LAYER_INFINIBAND) 886fc06573dSJack Morgenstein ctx->has_smi = 1; 887fc06573dSJack Morgenstein 888fc06573dSJack Morgenstein if (ctx->has_smi) { 889fc06573dSJack Morgenstein ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_SMI, create_tun); 890fc06573dSJack Morgenstein if (ret) { 891fc06573dSJack Morgenstein pr_err("Failed allocating qp0 tunnel bufs (%d)\n", ret); 892fc06573dSJack Morgenstein goto err_out; 893fc06573dSJack Morgenstein } 894fc06573dSJack Morgenstein } 895fc06573dSJack Morgenstein 896fc06573dSJack Morgenstein ret = mlx4_ib_alloc_pv_bufs(ctx, IB_QPT_GSI, create_tun); 897fc06573dSJack Morgenstein if (ret) { 898fc06573dSJack Morgenstein pr_err("Failed allocating qp1 tunnel bufs (%d)\n", ret); 899fc06573dSJack Morgenstein goto err_out_qp0; 900fc06573dSJack Morgenstein } 901fc06573dSJack Morgenstein 902fc06573dSJack Morgenstein cq_size = 2 * MLX4_NUM_TUNNEL_BUFS; 903fc06573dSJack Morgenstein if (ctx->has_smi) 904fc06573dSJack Morgenstein cq_size *= 2; 905fc06573dSJack Morgenstein 906fc06573dSJack Morgenstein ctx->cq = ib_create_cq(ctx->ib_dev, mlx4_ib_tunnel_comp_handler, 907fc06573dSJack Morgenstein NULL, ctx, cq_size, 0); 908fc06573dSJack Morgenstein if (IS_ERR(ctx->cq)) { 909fc06573dSJack Morgenstein ret = PTR_ERR(ctx->cq); 910fc06573dSJack Morgenstein pr_err("Couldn't create tunnel CQ (%d)\n", ret); 911fc06573dSJack Morgenstein goto err_buf; 912fc06573dSJack Morgenstein } 913fc06573dSJack Morgenstein 914fc06573dSJack Morgenstein ctx->pd = ib_alloc_pd(ctx->ib_dev); 915fc06573dSJack Morgenstein if (IS_ERR(ctx->pd)) { 916fc06573dSJack Morgenstein ret = PTR_ERR(ctx->pd); 917fc06573dSJack Morgenstein pr_err("Couldn't create tunnel PD (%d)\n", ret); 918fc06573dSJack Morgenstein goto err_cq; 919fc06573dSJack Morgenstein } 920fc06573dSJack Morgenstein 921fc06573dSJack Morgenstein ctx->mr = ib_get_dma_mr(ctx->pd, IB_ACCESS_LOCAL_WRITE); 922fc06573dSJack Morgenstein if (IS_ERR(ctx->mr)) { 923fc06573dSJack Morgenstein ret = PTR_ERR(ctx->mr); 924fc06573dSJack Morgenstein pr_err("Couldn't get tunnel DMA MR (%d)\n", ret); 925fc06573dSJack Morgenstein goto err_pd; 926fc06573dSJack Morgenstein } 927fc06573dSJack Morgenstein 928fc06573dSJack Morgenstein if (ctx->has_smi) { 929fc06573dSJack Morgenstein ret = create_pv_sqp(ctx, IB_QPT_SMI, create_tun); 930fc06573dSJack Morgenstein if (ret) { 931fc06573dSJack Morgenstein pr_err("Couldn't create %s QP0 (%d)\n", 932fc06573dSJack Morgenstein create_tun ? "tunnel for" : "", ret); 933fc06573dSJack Morgenstein goto err_mr; 934fc06573dSJack Morgenstein } 935fc06573dSJack Morgenstein } 936fc06573dSJack Morgenstein 937fc06573dSJack Morgenstein ret = create_pv_sqp(ctx, IB_QPT_GSI, create_tun); 938fc06573dSJack Morgenstein if (ret) { 939fc06573dSJack Morgenstein pr_err("Couldn't create %s QP1 (%d)\n", 940fc06573dSJack Morgenstein create_tun ? "tunnel for" : "", ret); 941fc06573dSJack Morgenstein goto err_qp0; 942fc06573dSJack Morgenstein } 943fc06573dSJack Morgenstein 944fc06573dSJack Morgenstein if (create_tun) 945fc06573dSJack Morgenstein INIT_WORK(&ctx->work, mlx4_ib_tunnel_comp_worker); 946fc06573dSJack Morgenstein else 947fc06573dSJack Morgenstein INIT_WORK(&ctx->work, mlx4_ib_sqp_comp_worker); 948fc06573dSJack Morgenstein 949fc06573dSJack Morgenstein ctx->wq = to_mdev(ibdev)->sriov.demux[port - 1].wq; 950fc06573dSJack Morgenstein 951fc06573dSJack Morgenstein ret = ib_req_notify_cq(ctx->cq, IB_CQ_NEXT_COMP); 952fc06573dSJack Morgenstein if (ret) { 953fc06573dSJack Morgenstein pr_err("Couldn't arm tunnel cq (%d)\n", ret); 954fc06573dSJack Morgenstein goto err_wq; 955fc06573dSJack Morgenstein } 956fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_ACTIVE; 957fc06573dSJack Morgenstein return 0; 958fc06573dSJack Morgenstein 959fc06573dSJack Morgenstein err_wq: 960fc06573dSJack Morgenstein ctx->wq = NULL; 961fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[1].qp); 962fc06573dSJack Morgenstein ctx->qp[1].qp = NULL; 963fc06573dSJack Morgenstein 964fc06573dSJack Morgenstein 965fc06573dSJack Morgenstein err_qp0: 966fc06573dSJack Morgenstein if (ctx->has_smi) 967fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[0].qp); 968fc06573dSJack Morgenstein ctx->qp[0].qp = NULL; 969fc06573dSJack Morgenstein 970fc06573dSJack Morgenstein err_mr: 971fc06573dSJack Morgenstein ib_dereg_mr(ctx->mr); 972fc06573dSJack Morgenstein ctx->mr = NULL; 973fc06573dSJack Morgenstein 974fc06573dSJack Morgenstein err_pd: 975fc06573dSJack Morgenstein ib_dealloc_pd(ctx->pd); 976fc06573dSJack Morgenstein ctx->pd = NULL; 977fc06573dSJack Morgenstein 978fc06573dSJack Morgenstein err_cq: 979fc06573dSJack Morgenstein ib_destroy_cq(ctx->cq); 980fc06573dSJack Morgenstein ctx->cq = NULL; 981fc06573dSJack Morgenstein 982fc06573dSJack Morgenstein err_buf: 983fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, create_tun); 984fc06573dSJack Morgenstein 985fc06573dSJack Morgenstein err_out_qp0: 986fc06573dSJack Morgenstein if (ctx->has_smi) 987fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, create_tun); 988fc06573dSJack Morgenstein err_out: 989fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_DOWN; 990fc06573dSJack Morgenstein return ret; 991fc06573dSJack Morgenstein } 992fc06573dSJack Morgenstein 993fc06573dSJack Morgenstein static void destroy_pv_resources(struct mlx4_ib_dev *dev, int slave, int port, 994fc06573dSJack Morgenstein struct mlx4_ib_demux_pv_ctx *ctx, int flush) 995fc06573dSJack Morgenstein { 996fc06573dSJack Morgenstein if (!ctx) 997fc06573dSJack Morgenstein return; 998fc06573dSJack Morgenstein if (ctx->state > DEMUX_PV_STATE_DOWN) { 999fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_DOWNING; 1000fc06573dSJack Morgenstein if (flush) 1001fc06573dSJack Morgenstein flush_workqueue(ctx->wq); 1002fc06573dSJack Morgenstein if (ctx->has_smi) { 1003fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[0].qp); 1004fc06573dSJack Morgenstein ctx->qp[0].qp = NULL; 1005fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_SMI, 1); 1006fc06573dSJack Morgenstein } 1007fc06573dSJack Morgenstein ib_destroy_qp(ctx->qp[1].qp); 1008fc06573dSJack Morgenstein ctx->qp[1].qp = NULL; 1009fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, 1); 1010fc06573dSJack Morgenstein ib_dereg_mr(ctx->mr); 1011fc06573dSJack Morgenstein ctx->mr = NULL; 1012fc06573dSJack Morgenstein ib_dealloc_pd(ctx->pd); 1013fc06573dSJack Morgenstein ctx->pd = NULL; 1014fc06573dSJack Morgenstein ib_destroy_cq(ctx->cq); 1015fc06573dSJack Morgenstein ctx->cq = NULL; 1016fc06573dSJack Morgenstein ctx->state = DEMUX_PV_STATE_DOWN; 1017fc06573dSJack Morgenstein } 1018fc06573dSJack Morgenstein } 1019fc06573dSJack Morgenstein 1020fc06573dSJack Morgenstein static int mlx4_ib_tunnels_update(struct mlx4_ib_dev *dev, int slave, 1021fc06573dSJack Morgenstein int port, int do_init) 1022fc06573dSJack Morgenstein { 1023fc06573dSJack Morgenstein int ret = 0; 1024fc06573dSJack Morgenstein 1025fc06573dSJack Morgenstein if (!do_init) { 1026fc06573dSJack Morgenstein /* for master, destroy real sqp resources */ 1027fc06573dSJack Morgenstein if (slave == mlx4_master_func_num(dev->dev)) 1028fc06573dSJack Morgenstein destroy_pv_resources(dev, slave, port, 1029fc06573dSJack Morgenstein dev->sriov.sqps[port - 1], 1); 1030fc06573dSJack Morgenstein /* destroy the tunnel qp resources */ 1031fc06573dSJack Morgenstein destroy_pv_resources(dev, slave, port, 1032fc06573dSJack Morgenstein dev->sriov.demux[port - 1].tun[slave], 1); 1033fc06573dSJack Morgenstein return 0; 1034fc06573dSJack Morgenstein } 1035fc06573dSJack Morgenstein 1036fc06573dSJack Morgenstein /* create the tunnel qp resources */ 1037fc06573dSJack Morgenstein ret = create_pv_resources(&dev->ib_dev, slave, port, 1, 1038fc06573dSJack Morgenstein dev->sriov.demux[port - 1].tun[slave]); 1039fc06573dSJack Morgenstein 1040fc06573dSJack Morgenstein /* for master, create the real sqp resources */ 1041fc06573dSJack Morgenstein if (!ret && slave == mlx4_master_func_num(dev->dev)) 1042fc06573dSJack Morgenstein ret = create_pv_resources(&dev->ib_dev, slave, port, 0, 1043fc06573dSJack Morgenstein dev->sriov.sqps[port - 1]); 1044fc06573dSJack Morgenstein return ret; 1045fc06573dSJack Morgenstein } 1046fc06573dSJack Morgenstein 1047fc06573dSJack Morgenstein void mlx4_ib_tunnels_update_work(struct work_struct *work) 1048fc06573dSJack Morgenstein { 1049fc06573dSJack Morgenstein struct mlx4_ib_demux_work *dmxw; 1050fc06573dSJack Morgenstein 1051fc06573dSJack Morgenstein dmxw = container_of(work, struct mlx4_ib_demux_work, work); 1052fc06573dSJack Morgenstein mlx4_ib_tunnels_update(dmxw->dev, dmxw->slave, (int) dmxw->port, 1053fc06573dSJack Morgenstein dmxw->do_init); 1054fc06573dSJack Morgenstein kfree(dmxw); 1055fc06573dSJack Morgenstein return; 1056fc06573dSJack Morgenstein } 1057fc06573dSJack Morgenstein 1058fc06573dSJack Morgenstein static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev, 1059fc06573dSJack Morgenstein struct mlx4_ib_demux_ctx *ctx, 1060fc06573dSJack Morgenstein int port) 1061fc06573dSJack Morgenstein { 1062fc06573dSJack Morgenstein char name[12]; 1063fc06573dSJack Morgenstein int ret = 0; 1064fc06573dSJack Morgenstein int i; 1065fc06573dSJack Morgenstein 1066fc06573dSJack Morgenstein ctx->tun = kcalloc(dev->dev->caps.sqp_demux, 1067fc06573dSJack Morgenstein sizeof (struct mlx4_ib_demux_pv_ctx *), GFP_KERNEL); 1068fc06573dSJack Morgenstein if (!ctx->tun) 1069fc06573dSJack Morgenstein return -ENOMEM; 1070fc06573dSJack Morgenstein 1071fc06573dSJack Morgenstein ctx->dev = dev; 1072fc06573dSJack Morgenstein ctx->port = port; 1073fc06573dSJack Morgenstein ctx->ib_dev = &dev->ib_dev; 1074fc06573dSJack Morgenstein 1075fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 1076fc06573dSJack Morgenstein ret = alloc_pv_object(dev, i, port, &ctx->tun[i]); 1077fc06573dSJack Morgenstein if (ret) { 1078fc06573dSJack Morgenstein ret = -ENOMEM; 1079fc06573dSJack Morgenstein goto err_wq; 1080fc06573dSJack Morgenstein } 1081fc06573dSJack Morgenstein } 1082fc06573dSJack Morgenstein 1083fc06573dSJack Morgenstein snprintf(name, sizeof name, "mlx4_ibt%d", port); 1084fc06573dSJack Morgenstein ctx->wq = create_singlethread_workqueue(name); 1085fc06573dSJack Morgenstein if (!ctx->wq) { 1086fc06573dSJack Morgenstein pr_err("Failed to create tunnelling WQ for port %d\n", port); 1087fc06573dSJack Morgenstein ret = -ENOMEM; 1088fc06573dSJack Morgenstein goto err_wq; 1089fc06573dSJack Morgenstein } 1090fc06573dSJack Morgenstein 1091fc06573dSJack Morgenstein snprintf(name, sizeof name, "mlx4_ibud%d", port); 1092fc06573dSJack Morgenstein ctx->ud_wq = create_singlethread_workqueue(name); 1093fc06573dSJack Morgenstein if (!ctx->ud_wq) { 1094fc06573dSJack Morgenstein pr_err("Failed to create up/down WQ for port %d\n", port); 1095fc06573dSJack Morgenstein ret = -ENOMEM; 1096fc06573dSJack Morgenstein goto err_udwq; 1097fc06573dSJack Morgenstein } 1098fc06573dSJack Morgenstein 1099fc06573dSJack Morgenstein return 0; 1100fc06573dSJack Morgenstein 1101fc06573dSJack Morgenstein err_udwq: 1102fc06573dSJack Morgenstein destroy_workqueue(ctx->wq); 1103fc06573dSJack Morgenstein ctx->wq = NULL; 1104fc06573dSJack Morgenstein 1105fc06573dSJack Morgenstein err_wq: 1106fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) 1107fc06573dSJack Morgenstein free_pv_object(dev, i, port); 1108fc06573dSJack Morgenstein kfree(ctx->tun); 1109fc06573dSJack Morgenstein ctx->tun = NULL; 1110fc06573dSJack Morgenstein return ret; 1111fc06573dSJack Morgenstein } 1112fc06573dSJack Morgenstein 1113fc06573dSJack Morgenstein static void mlx4_ib_free_sqp_ctx(struct mlx4_ib_demux_pv_ctx *sqp_ctx) 1114fc06573dSJack Morgenstein { 1115fc06573dSJack Morgenstein if (sqp_ctx->state > DEMUX_PV_STATE_DOWN) { 1116fc06573dSJack Morgenstein sqp_ctx->state = DEMUX_PV_STATE_DOWNING; 1117fc06573dSJack Morgenstein flush_workqueue(sqp_ctx->wq); 1118fc06573dSJack Morgenstein if (sqp_ctx->has_smi) { 1119fc06573dSJack Morgenstein ib_destroy_qp(sqp_ctx->qp[0].qp); 1120fc06573dSJack Morgenstein sqp_ctx->qp[0].qp = NULL; 1121fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_SMI, 0); 1122fc06573dSJack Morgenstein } 1123fc06573dSJack Morgenstein ib_destroy_qp(sqp_ctx->qp[1].qp); 1124fc06573dSJack Morgenstein sqp_ctx->qp[1].qp = NULL; 1125fc06573dSJack Morgenstein mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_GSI, 0); 1126fc06573dSJack Morgenstein ib_dereg_mr(sqp_ctx->mr); 1127fc06573dSJack Morgenstein sqp_ctx->mr = NULL; 1128fc06573dSJack Morgenstein ib_dealloc_pd(sqp_ctx->pd); 1129fc06573dSJack Morgenstein sqp_ctx->pd = NULL; 1130fc06573dSJack Morgenstein ib_destroy_cq(sqp_ctx->cq); 1131fc06573dSJack Morgenstein sqp_ctx->cq = NULL; 1132fc06573dSJack Morgenstein sqp_ctx->state = DEMUX_PV_STATE_DOWN; 1133fc06573dSJack Morgenstein } 1134fc06573dSJack Morgenstein } 1135fc06573dSJack Morgenstein 1136fc06573dSJack Morgenstein static void mlx4_ib_free_demux_ctx(struct mlx4_ib_demux_ctx *ctx) 1137fc06573dSJack Morgenstein { 1138fc06573dSJack Morgenstein int i; 1139fc06573dSJack Morgenstein if (ctx) { 1140fc06573dSJack Morgenstein struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); 1141fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 1142fc06573dSJack Morgenstein if (!ctx->tun[i]) 1143fc06573dSJack Morgenstein continue; 1144fc06573dSJack Morgenstein if (ctx->tun[i]->state > DEMUX_PV_STATE_DOWN) 1145fc06573dSJack Morgenstein ctx->tun[i]->state = DEMUX_PV_STATE_DOWNING; 1146fc06573dSJack Morgenstein } 1147fc06573dSJack Morgenstein flush_workqueue(ctx->wq); 1148fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.sqp_demux; i++) { 1149fc06573dSJack Morgenstein destroy_pv_resources(dev, i, ctx->port, ctx->tun[i], 0); 1150fc06573dSJack Morgenstein free_pv_object(dev, i, ctx->port); 1151fc06573dSJack Morgenstein } 1152fc06573dSJack Morgenstein kfree(ctx->tun); 1153fc06573dSJack Morgenstein destroy_workqueue(ctx->ud_wq); 1154fc06573dSJack Morgenstein destroy_workqueue(ctx->wq); 1155fc06573dSJack Morgenstein } 1156fc06573dSJack Morgenstein } 1157fc06573dSJack Morgenstein 1158fc06573dSJack Morgenstein static void mlx4_ib_master_tunnels(struct mlx4_ib_dev *dev, int do_init) 1159fc06573dSJack Morgenstein { 1160fc06573dSJack Morgenstein int i; 1161fc06573dSJack Morgenstein 1162fc06573dSJack Morgenstein if (!mlx4_is_master(dev->dev)) 1163fc06573dSJack Morgenstein return; 1164fc06573dSJack Morgenstein /* initialize or tear down tunnel QPs for the master */ 1165fc06573dSJack Morgenstein for (i = 0; i < dev->dev->caps.num_ports; i++) 1166fc06573dSJack Morgenstein mlx4_ib_tunnels_update(dev, mlx4_master_func_num(dev->dev), i + 1, do_init); 1167fc06573dSJack Morgenstein return; 1168fc06573dSJack Morgenstein } 1169fc06573dSJack Morgenstein 1170fc06573dSJack Morgenstein int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev) 1171fc06573dSJack Morgenstein { 1172fc06573dSJack Morgenstein int i = 0; 1173fc06573dSJack Morgenstein int err; 1174fc06573dSJack Morgenstein 1175fc06573dSJack Morgenstein if (!mlx4_is_mfunc(dev->dev)) 1176fc06573dSJack Morgenstein return 0; 1177fc06573dSJack Morgenstein 1178fc06573dSJack Morgenstein dev->sriov.is_going_down = 0; 1179fc06573dSJack Morgenstein spin_lock_init(&dev->sriov.going_down_lock); 1180fc06573dSJack Morgenstein 1181fc06573dSJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "multi-function enabled\n"); 1182fc06573dSJack Morgenstein 1183fc06573dSJack Morgenstein if (mlx4_is_slave(dev->dev)) { 1184fc06573dSJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "operating in qp1 tunnel mode\n"); 1185fc06573dSJack Morgenstein return 0; 1186fc06573dSJack Morgenstein } 1187fc06573dSJack Morgenstein 1188fc06573dSJack Morgenstein mlx4_ib_warn(&dev->ib_dev, "initializing demux service for %d qp1 clients\n", 1189fc06573dSJack Morgenstein dev->dev->caps.sqp_demux); 1190fc06573dSJack Morgenstein for (i = 0; i < dev->num_ports; i++) { 1191fc06573dSJack Morgenstein err = alloc_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1, 1192fc06573dSJack Morgenstein &dev->sriov.sqps[i]); 1193fc06573dSJack Morgenstein if (err) 1194fc06573dSJack Morgenstein goto demux_err; 1195fc06573dSJack Morgenstein err = mlx4_ib_alloc_demux_ctx(dev, &dev->sriov.demux[i], i + 1); 1196fc06573dSJack Morgenstein if (err) 1197fc06573dSJack Morgenstein goto demux_err; 1198fc06573dSJack Morgenstein } 1199fc06573dSJack Morgenstein mlx4_ib_master_tunnels(dev, 1); 1200fc06573dSJack Morgenstein return 0; 1201fc06573dSJack Morgenstein 1202fc06573dSJack Morgenstein demux_err: 1203fc06573dSJack Morgenstein while (i > 0) { 1204fc06573dSJack Morgenstein free_pv_object(dev, mlx4_master_func_num(dev->dev), i + 1); 1205fc06573dSJack Morgenstein mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 1206fc06573dSJack Morgenstein --i; 1207fc06573dSJack Morgenstein } 1208fc06573dSJack Morgenstein 1209fc06573dSJack Morgenstein return err; 1210fc06573dSJack Morgenstein } 1211fc06573dSJack Morgenstein 1212fc06573dSJack Morgenstein void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev) 1213fc06573dSJack Morgenstein { 1214fc06573dSJack Morgenstein int i; 1215fc06573dSJack Morgenstein unsigned long flags; 1216fc06573dSJack Morgenstein 1217fc06573dSJack Morgenstein if (!mlx4_is_mfunc(dev->dev)) 1218fc06573dSJack Morgenstein return; 1219fc06573dSJack Morgenstein 1220fc06573dSJack Morgenstein spin_lock_irqsave(&dev->sriov.going_down_lock, flags); 1221fc06573dSJack Morgenstein dev->sriov.is_going_down = 1; 1222fc06573dSJack Morgenstein spin_unlock_irqrestore(&dev->sriov.going_down_lock, flags); 1223fc06573dSJack Morgenstein if (mlx4_is_master(dev->dev)) 1224fc06573dSJack Morgenstein for (i = 0; i < dev->num_ports; i++) { 1225fc06573dSJack Morgenstein flush_workqueue(dev->sriov.demux[i].ud_wq); 1226fc06573dSJack Morgenstein mlx4_ib_free_sqp_ctx(dev->sriov.sqps[i]); 1227fc06573dSJack Morgenstein kfree(dev->sriov.sqps[i]); 1228fc06573dSJack Morgenstein dev->sriov.sqps[i] = NULL; 1229fc06573dSJack Morgenstein mlx4_ib_free_demux_ctx(&dev->sriov.demux[i]); 1230fc06573dSJack Morgenstein } 1231fc06573dSJack Morgenstein } 1232