171ee6730SDevesh Sharma /* This file is part of the Emulex RoCE Device Driver for 271ee6730SDevesh Sharma * RoCE (RDMA over Converged Ethernet) adapters. 371ee6730SDevesh Sharma * Copyright (C) 2012-2015 Emulex. All rights reserved. 471ee6730SDevesh Sharma * EMULEX and SLI are trademarks of Emulex. 571ee6730SDevesh Sharma * www.emulex.com 671ee6730SDevesh Sharma * 771ee6730SDevesh Sharma * This software is available to you under a choice of one of two licenses. 871ee6730SDevesh Sharma * You may choose to be licensed under the terms of the GNU General Public 971ee6730SDevesh Sharma * License (GPL) Version 2, available from the file COPYING in the main 1071ee6730SDevesh Sharma * directory of this source tree, or the BSD license below: 1171ee6730SDevesh Sharma * 1271ee6730SDevesh Sharma * Redistribution and use in source and binary forms, with or without 1371ee6730SDevesh Sharma * modification, are permitted provided that the following conditions 1471ee6730SDevesh Sharma * are met: 1571ee6730SDevesh Sharma * 1671ee6730SDevesh Sharma * - Redistributions of source code must retain the above copyright notice, 1771ee6730SDevesh Sharma * this list of conditions and the following disclaimer. 1871ee6730SDevesh Sharma * 1971ee6730SDevesh Sharma * - Redistributions in binary form must reproduce the above copyright 2071ee6730SDevesh Sharma * notice, this list of conditions and the following disclaimer in 2171ee6730SDevesh Sharma * the documentation and/or other materials provided with the distribution. 2271ee6730SDevesh Sharma * 2371ee6730SDevesh Sharma * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2471ee6730SDevesh Sharma * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,THE 2571ee6730SDevesh Sharma * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2671ee6730SDevesh Sharma * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2771ee6730SDevesh Sharma * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2871ee6730SDevesh Sharma * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2971ee6730SDevesh Sharma * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 3071ee6730SDevesh Sharma * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3171ee6730SDevesh Sharma * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3271ee6730SDevesh Sharma * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3371ee6730SDevesh Sharma * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34fe2caefcSParav Pandit * 35fe2caefcSParav Pandit * Contact Information: 36fe2caefcSParav Pandit * linux-drivers@emulex.com 37fe2caefcSParav Pandit * 38fe2caefcSParav Pandit * Emulex 39fe2caefcSParav Pandit * 3333 Susan Street 40fe2caefcSParav Pandit * Costa Mesa, CA 92626 4171ee6730SDevesh Sharma */ 42fe2caefcSParav Pandit 43fe2caefcSParav Pandit #include <net/neighbour.h> 44fe2caefcSParav Pandit #include <net/netevent.h> 45fe2caefcSParav Pandit 46fe2caefcSParav Pandit #include <rdma/ib_addr.h> 47cad1fbb0SMitesh Ahuja #include <rdma/ib_mad.h> 48dbf727deSMatan Barak #include <rdma/ib_cache.h> 49fe2caefcSParav Pandit 50fe2caefcSParav Pandit #include "ocrdma.h" 51fe2caefcSParav Pandit #include "ocrdma_verbs.h" 52fe2caefcSParav Pandit #include "ocrdma_ah.h" 53fe2caefcSParav Pandit #include "ocrdma_hw.h" 54cad1fbb0SMitesh Ahuja #include "ocrdma_stats.h" 55fe2caefcSParav Pandit 560ea87262SDevesh Sharma #define OCRDMA_VID_PCP_SHIFT 0xD 570ea87262SDevesh Sharma 586b062667SDevesh Sharma static u16 ocrdma_hdr_type_to_proto_num(int devid, u8 hdr_type) 596b062667SDevesh Sharma { 606b062667SDevesh Sharma switch (hdr_type) { 616b062667SDevesh Sharma case OCRDMA_L3_TYPE_IB_GRH: 6269ae5439SSelvin Xavier return (u16)ETH_P_IBOE; 636b062667SDevesh Sharma case OCRDMA_L3_TYPE_IPV4: 646b062667SDevesh Sharma return (u16)0x0800; 656b062667SDevesh Sharma case OCRDMA_L3_TYPE_IPV6: 666b062667SDevesh Sharma return (u16)0x86dd; 676b062667SDevesh Sharma default: 686b062667SDevesh Sharma pr_err("ocrdma%d: Invalid network header\n", devid); 696b062667SDevesh Sharma return 0; 706b062667SDevesh Sharma } 716b062667SDevesh Sharma } 726b062667SDevesh Sharma 731afc0454SNaresh Gottumukkala static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah, 7447ec3866SParav Pandit struct rdma_ah_attr *attr, const union ib_gid *sgid, 75dbf727deSMatan Barak int pdid, bool *isvlan, u16 vlan_tag) 76fe2caefcSParav Pandit { 770ca4c39fSMarkus Elfring int status; 78fe2caefcSParav Pandit struct ocrdma_eth_vlan eth; 79fe2caefcSParav Pandit struct ocrdma_grh grh; 80fe2caefcSParav Pandit int eth_sz; 816b062667SDevesh Sharma u16 proto_num = 0; 826b062667SDevesh Sharma u8 nxthdr = 0x11; 836b062667SDevesh Sharma struct iphdr ipv4; 84d8966fcdSDasaratharaman Chandramouli const struct ib_global_route *ib_grh; 856b062667SDevesh Sharma union { 866b062667SDevesh Sharma struct sockaddr_in _sockaddr_in; 876b062667SDevesh Sharma struct sockaddr_in6 _sockaddr_in6; 886b062667SDevesh Sharma } sgid_addr, dgid_addr; 89fe2caefcSParav Pandit 90fe2caefcSParav Pandit memset(ð, 0, sizeof(eth)); 91fe2caefcSParav Pandit memset(&grh, 0, sizeof(grh)); 92fe2caefcSParav Pandit 936b062667SDevesh Sharma /* Protocol Number */ 946b062667SDevesh Sharma proto_num = ocrdma_hdr_type_to_proto_num(dev->id, ah->hdr_type); 956b062667SDevesh Sharma if (!proto_num) 966b062667SDevesh Sharma return -EINVAL; 9769ae5439SSelvin Xavier nxthdr = (proto_num == ETH_P_IBOE) ? 0x1b : 0x11; 981be528bcSdevesh.sharma@emulex.com /* VLAN */ 9984b105dbSNaresh Gottumukkala if (!vlan_tag || (vlan_tag > 0xFFF)) 10084b105dbSNaresh Gottumukkala vlan_tag = dev->pvid; 1016f5deab0SDevesh Sharma if (vlan_tag || dev->pfc_state) { 1026f5deab0SDevesh Sharma if (!vlan_tag) { 1036f5deab0SDevesh Sharma pr_err("ocrdma%d:Using VLAN with PFC is recommended\n", 1046f5deab0SDevesh Sharma dev->id); 1056f5deab0SDevesh Sharma pr_err("ocrdma%d:Using VLAN 0 for this connection\n", 1066f5deab0SDevesh Sharma dev->id); 1076f5deab0SDevesh Sharma } 108fe2caefcSParav Pandit eth.eth_type = cpu_to_be16(0x8100); 1096b062667SDevesh Sharma eth.roce_eth_type = cpu_to_be16(proto_num); 1100ea87262SDevesh Sharma vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT; 111fe2caefcSParav Pandit eth.vlan_tag = cpu_to_be16(vlan_tag); 112fe2caefcSParav Pandit eth_sz = sizeof(struct ocrdma_eth_vlan); 11329565f2fSDevesh Sharma *isvlan = true; 114fe2caefcSParav Pandit } else { 1156b062667SDevesh Sharma eth.eth_type = cpu_to_be16(proto_num); 116fe2caefcSParav Pandit eth_sz = sizeof(struct ocrdma_eth_basic); 117fe2caefcSParav Pandit } 1181be528bcSdevesh.sharma@emulex.com /* MAC */ 119fe2caefcSParav Pandit memcpy(ð.smac[0], &dev->nic_info.mac_addr[0], ETH_ALEN); 12040aca6ffSMoni Shoua status = ocrdma_resolve_dmac(dev, attr, ð.dmac[0]); 121fe2caefcSParav Pandit if (status) 122fe2caefcSParav Pandit return status; 123d8966fcdSDasaratharaman Chandramouli ib_grh = rdma_ah_read_grh(attr); 124d8966fcdSDasaratharaman Chandramouli ah->sgid_index = ib_grh->sgid_index; 1256b062667SDevesh Sharma /* Eth HDR */ 1266b062667SDevesh Sharma memcpy(&ah->av->eth_hdr, ð, eth_sz); 1276b062667SDevesh Sharma if (ah->hdr_type == RDMA_NETWORK_IPV4) { 1286b062667SDevesh Sharma *((__be16 *)&ipv4) = htons((4 << 12) | (5 << 8) | 129d8966fcdSDasaratharaman Chandramouli ib_grh->traffic_class); 1306b062667SDevesh Sharma ipv4.id = cpu_to_be16(pdid); 1316b062667SDevesh Sharma ipv4.frag_off = htons(IP_DF); 1326b062667SDevesh Sharma ipv4.tot_len = htons(0); 133d8966fcdSDasaratharaman Chandramouli ipv4.ttl = ib_grh->hop_limit; 1346b062667SDevesh Sharma ipv4.protocol = nxthdr; 135641114d2SJason Gunthorpe rdma_gid2ip((struct sockaddr *)&sgid_addr, sgid); 1366b062667SDevesh Sharma ipv4.saddr = sgid_addr._sockaddr_in.sin_addr.s_addr; 137641114d2SJason Gunthorpe rdma_gid2ip((struct sockaddr*)&dgid_addr, &ib_grh->dgid); 1386b062667SDevesh Sharma ipv4.daddr = dgid_addr._sockaddr_in.sin_addr.s_addr; 1396b062667SDevesh Sharma memcpy((u8 *)ah->av + eth_sz, &ipv4, sizeof(struct iphdr)); 1406b062667SDevesh Sharma } else { 1411be528bcSdevesh.sharma@emulex.com memcpy(&grh.sgid[0], sgid->raw, sizeof(union ib_gid)); 142fe2caefcSParav Pandit grh.tclass_flow = cpu_to_be32((6 << 28) | 143d8966fcdSDasaratharaman Chandramouli (ib_grh->traffic_class << 24) | 144d8966fcdSDasaratharaman Chandramouli ib_grh->flow_label); 145d8966fcdSDasaratharaman Chandramouli memcpy(&grh.dgid[0], ib_grh->dgid.raw, 146d8966fcdSDasaratharaman Chandramouli sizeof(ib_grh->dgid.raw)); 147fe2caefcSParav Pandit grh.pdid_hoplimit = cpu_to_be32((pdid << 16) | 1486b062667SDevesh Sharma (nxthdr << 8) | 149d8966fcdSDasaratharaman Chandramouli ib_grh->hop_limit); 150fe2caefcSParav Pandit memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh)); 1516b062667SDevesh Sharma } 15229565f2fSDevesh Sharma if (*isvlan) 153fe2caefcSParav Pandit ah->av->valid |= OCRDMA_AV_VLAN_VALID; 154fe5e8a1aSDevesh Sharma ah->av->valid = cpu_to_le32(ah->av->valid); 155fe2caefcSParav Pandit return status; 156fe2caefcSParav Pandit } 157fe2caefcSParav Pandit 158fa5d010cSMaor Gottlieb int ocrdma_create_ah(struct ib_ah *ibah, struct rdma_ah_init_attr *init_attr, 159d3456914SLeon Romanovsky struct ib_udata *udata) 160fe2caefcSParav Pandit { 161fe2caefcSParav Pandit u32 *ahid_addr; 162fe2caefcSParav Pandit int status; 163d3456914SLeon Romanovsky struct ocrdma_ah *ah = get_ocrdma_ah(ibah); 164dbf727deSMatan Barak bool isvlan = false; 165dbf727deSMatan Barak u16 vlan_tag = 0xffff; 16647ec3866SParav Pandit const struct ib_gid_attr *sgid_attr; 167d3456914SLeon Romanovsky struct ocrdma_pd *pd = get_ocrdma_pd(ibah->pd); 168fa5d010cSMaor Gottlieb struct rdma_ah_attr *attr = init_attr->ah_attr; 169d3456914SLeon Romanovsky struct ocrdma_dev *dev = get_ocrdma_dev(ibah->device); 170fe2caefcSParav Pandit 17144c58487SDasaratharaman Chandramouli if ((attr->type != RDMA_AH_ATTR_TYPE_ROCE) || 17244c58487SDasaratharaman Chandramouli !(rdma_ah_get_ah_flags(attr) & IB_AH_GRH)) 173d3456914SLeon Romanovsky return -EINVAL; 174fe2caefcSParav Pandit 17531dbdd9aSSelvin Xavier if (atomic_cmpxchg(&dev->update_sl, 1, 0)) 17631dbdd9aSSelvin Xavier ocrdma_init_service_level(dev); 1776b062667SDevesh Sharma 178a70c0739SParav Pandit sgid_attr = attr->grh.sgid_attr; 179a70c0739SParav Pandit status = rdma_read_gid_l2_fields(sgid_attr, &vlan_tag, NULL); 180a70c0739SParav Pandit if (status) 181a70c0739SParav Pandit return status; 182a70c0739SParav Pandit 183fe2caefcSParav Pandit status = ocrdma_alloc_av(dev, ah); 184fe2caefcSParav Pandit if (status) 185fe2caefcSParav Pandit goto av_err; 1861be528bcSdevesh.sharma@emulex.com 18747ec3866SParav Pandit /* Get network header type for this GID */ 18847ec3866SParav Pandit ah->hdr_type = rdma_gid_attr_network_type(sgid_attr); 18947ec3866SParav Pandit 19047ec3866SParav Pandit status = set_av_attr(dev, ah, attr, &sgid_attr->gid, pd->id, 19147ec3866SParav Pandit &isvlan, vlan_tag); 192fe2caefcSParav Pandit if (status) 193fe2caefcSParav Pandit goto av_conf_err; 194fe2caefcSParav Pandit 195fe2caefcSParav Pandit /* if pd is for the user process, pass the ah_id to user space */ 196fe2caefcSParav Pandit if ((pd->uctx) && (pd->uctx->ah_tbl.va)) { 197d8966fcdSDasaratharaman Chandramouli ahid_addr = pd->uctx->ah_tbl.va + rdma_ah_get_dlid(attr); 19829565f2fSDevesh Sharma *ahid_addr = 0; 19929565f2fSDevesh Sharma *ahid_addr |= ah->id & OCRDMA_AH_ID_MASK; 200834d16d6SDevesh Sharma if (ocrdma_is_udp_encap_supported(dev)) { 201834d16d6SDevesh Sharma *ahid_addr |= ((u32)ah->hdr_type & 202834d16d6SDevesh Sharma OCRDMA_AH_L3_TYPE_MASK) << 203834d16d6SDevesh Sharma OCRDMA_AH_L3_TYPE_SHIFT; 204834d16d6SDevesh Sharma } 20529565f2fSDevesh Sharma if (isvlan) 20629565f2fSDevesh Sharma *ahid_addr |= (OCRDMA_AH_VLAN_VALID_MASK << 20729565f2fSDevesh Sharma OCRDMA_AH_VLAN_VALID_SHIFT); 208fe2caefcSParav Pandit } 20929565f2fSDevesh Sharma 210d3456914SLeon Romanovsky return 0; 211fe2caefcSParav Pandit 212fe2caefcSParav Pandit av_conf_err: 213fe2caefcSParav Pandit ocrdma_free_av(dev, ah); 214fe2caefcSParav Pandit av_err: 215d3456914SLeon Romanovsky return status; 216fe2caefcSParav Pandit } 217fe2caefcSParav Pandit 2189a9ebf8cSLeon Romanovsky int ocrdma_destroy_ah(struct ib_ah *ibah, u32 flags) 219fe2caefcSParav Pandit { 220fe2caefcSParav Pandit struct ocrdma_ah *ah = get_ocrdma_ah(ibah); 2211afc0454SNaresh Gottumukkala struct ocrdma_dev *dev = get_ocrdma_dev(ibah->device); 2221afc0454SNaresh Gottumukkala 2231afc0454SNaresh Gottumukkala ocrdma_free_av(dev, ah); 2249a9ebf8cSLeon Romanovsky return 0; 225fe2caefcSParav Pandit } 226fe2caefcSParav Pandit 22790898850SDasaratharaman Chandramouli int ocrdma_query_ah(struct ib_ah *ibah, struct rdma_ah_attr *attr) 228fe2caefcSParav Pandit { 229fe2caefcSParav Pandit struct ocrdma_ah *ah = get_ocrdma_ah(ibah); 230fe2caefcSParav Pandit struct ocrdma_av *av = ah->av; 231fe2caefcSParav Pandit struct ocrdma_grh *grh; 232d8966fcdSDasaratharaman Chandramouli 23344c58487SDasaratharaman Chandramouli attr->type = ibah->type; 234f0c2c225Sdevesh.sharma@emulex.com if (ah->av->valid & OCRDMA_AV_VALID) { 235fe2caefcSParav Pandit grh = (struct ocrdma_grh *)((u8 *)ah->av + 236fe2caefcSParav Pandit sizeof(struct ocrdma_eth_vlan)); 237d8966fcdSDasaratharaman Chandramouli rdma_ah_set_sl(attr, be16_to_cpu(av->eth_hdr.vlan_tag) >> 13); 238fe2caefcSParav Pandit } else { 239fe2caefcSParav Pandit grh = (struct ocrdma_grh *)((u8 *)ah->av + 240fe2caefcSParav Pandit sizeof(struct ocrdma_eth_basic)); 241d8966fcdSDasaratharaman Chandramouli rdma_ah_set_sl(attr, 0); 242fe2caefcSParav Pandit } 243d8966fcdSDasaratharaman Chandramouli rdma_ah_set_grh(attr, NULL, 244d8966fcdSDasaratharaman Chandramouli be32_to_cpu(grh->tclass_flow) & 0xffffffff, 245d8966fcdSDasaratharaman Chandramouli ah->sgid_index, 246d8966fcdSDasaratharaman Chandramouli be32_to_cpu(grh->pdid_hoplimit) & 0xff, 247d8966fcdSDasaratharaman Chandramouli be32_to_cpu(grh->tclass_flow) >> 24); 248d8966fcdSDasaratharaman Chandramouli rdma_ah_set_dgid_raw(attr, &grh->dgid[0]); 249fe2caefcSParav Pandit return 0; 250fe2caefcSParav Pandit } 251fe2caefcSParav Pandit 252e26e7b88SLeon Romanovsky int ocrdma_process_mad(struct ib_device *ibdev, int process_mad_flags, 253*1fb7f897SMark Bloch u32 port_num, const struct ib_wc *in_wc, 254e26e7b88SLeon Romanovsky const struct ib_grh *in_grh, const struct ib_mad *in, 255e26e7b88SLeon Romanovsky struct ib_mad *out, size_t *out_mad_size, 2564cd7c947SIra Weiny u16 *out_mad_pkey_index) 257fe2caefcSParav Pandit { 25884b56d57SLeon Romanovsky int status = IB_MAD_RESULT_SUCCESS; 259cad1fbb0SMitesh Ahuja struct ocrdma_dev *dev; 2604cd7c947SIra Weiny 261e26e7b88SLeon Romanovsky if (in->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT) { 262cad1fbb0SMitesh Ahuja dev = get_ocrdma_dev(ibdev); 263e26e7b88SLeon Romanovsky ocrdma_pma_counters(dev, out); 26484b56d57SLeon Romanovsky status |= IB_MAD_RESULT_REPLY; 265cad1fbb0SMitesh Ahuja } 26684b56d57SLeon Romanovsky 267cad1fbb0SMitesh Ahuja return status; 268fe2caefcSParav Pandit } 269