1fa790ea9SDavid C Somayajulu /* 2fa790ea9SDavid C Somayajulu * Copyright (c) 2018-2019 Cavium, Inc. 3fa790ea9SDavid C Somayajulu * All rights reserved. 4fa790ea9SDavid C Somayajulu * 5fa790ea9SDavid C Somayajulu * Redistribution and use in source and binary forms, with or without 6fa790ea9SDavid C Somayajulu * modification, are permitted provided that the following conditions 7fa790ea9SDavid C Somayajulu * are met: 8fa790ea9SDavid C Somayajulu * 9fa790ea9SDavid C Somayajulu * 1. Redistributions of source code must retain the above copyright 10fa790ea9SDavid C Somayajulu * notice, this list of conditions and the following disclaimer. 11fa790ea9SDavid C Somayajulu * 2. Redistributions in binary form must reproduce the above copyright 12fa790ea9SDavid C Somayajulu * notice, this list of conditions and the following disclaimer in the 13fa790ea9SDavid C Somayajulu * documentation and/or other materials provided with the distribution. 14fa790ea9SDavid C Somayajulu * 15fa790ea9SDavid C Somayajulu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16fa790ea9SDavid C Somayajulu * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17fa790ea9SDavid C Somayajulu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18fa790ea9SDavid C Somayajulu * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19fa790ea9SDavid C Somayajulu * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20fa790ea9SDavid C Somayajulu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21fa790ea9SDavid C Somayajulu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22fa790ea9SDavid C Somayajulu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23fa790ea9SDavid C Somayajulu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24fa790ea9SDavid C Somayajulu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25fa790ea9SDavid C Somayajulu * POSSIBILITY OF SUCH DAMAGE. 26fa790ea9SDavid C Somayajulu */ 27fa790ea9SDavid C Somayajulu 28fa790ea9SDavid C Somayajulu #include <sys/cdefs.h> 29fa790ea9SDavid C Somayajulu __FBSDID("$FreeBSD$"); 30fa790ea9SDavid C Somayajulu 31fa790ea9SDavid C Somayajulu #include "qlnxr_def.h" 32fa790ea9SDavid C Somayajulu #include "rdma_common.h" 33fa790ea9SDavid C Somayajulu #include "qlnxr_cm.h" 34fa790ea9SDavid C Somayajulu 35fa790ea9SDavid C Somayajulu void 36fa790ea9SDavid C Somayajulu qlnxr_inc_sw_gsi_cons(struct qlnxr_qp_hwq_info *info) 37fa790ea9SDavid C Somayajulu { 38fa790ea9SDavid C Somayajulu info->gsi_cons = (info->gsi_cons + 1) % info->max_wr; 39fa790ea9SDavid C Somayajulu } 40fa790ea9SDavid C Somayajulu 41fa790ea9SDavid C Somayajulu void 42fa790ea9SDavid C Somayajulu qlnxr_store_gsi_qp_cq(struct qlnxr_dev *dev, 43fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp, 44fa790ea9SDavid C Somayajulu struct ib_qp_init_attr *attrs) 45fa790ea9SDavid C Somayajulu { 46fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 47fa790ea9SDavid C Somayajulu 48fa790ea9SDavid C Somayajulu dev->gsi_qp_created = 1; 49fa790ea9SDavid C Somayajulu dev->gsi_sqcq = get_qlnxr_cq((attrs->send_cq)); 50fa790ea9SDavid C Somayajulu dev->gsi_rqcq = get_qlnxr_cq((attrs->recv_cq)); 51fa790ea9SDavid C Somayajulu dev->gsi_qp = qp; 52fa790ea9SDavid C Somayajulu 53fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 54fa790ea9SDavid C Somayajulu 55fa790ea9SDavid C Somayajulu return; 56fa790ea9SDavid C Somayajulu } 57fa790ea9SDavid C Somayajulu 58fa790ea9SDavid C Somayajulu void 59fa790ea9SDavid C Somayajulu qlnxr_ll2_complete_tx_packet(void *cxt, 60fa790ea9SDavid C Somayajulu uint8_t connection_handle, 61fa790ea9SDavid C Somayajulu void *cookie, 62fa790ea9SDavid C Somayajulu dma_addr_t first_frag_addr, 63fa790ea9SDavid C Somayajulu bool b_last_fragment, 64fa790ea9SDavid C Somayajulu bool b_last_packet) 65fa790ea9SDavid C Somayajulu { 66fa790ea9SDavid C Somayajulu struct qlnxr_dev *dev = (struct qlnxr_dev *)cxt; 67fa790ea9SDavid C Somayajulu struct ecore_roce_ll2_packet *pkt = cookie; 68fa790ea9SDavid C Somayajulu struct qlnxr_cq *cq = dev->gsi_sqcq; 69fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp = dev->gsi_qp; 70fa790ea9SDavid C Somayajulu unsigned long flags; 71fa790ea9SDavid C Somayajulu 72fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 73fa790ea9SDavid C Somayajulu 74fa790ea9SDavid C Somayajulu qlnx_dma_free_coherent(&dev->ha->cdev, pkt->header.vaddr, 75fa790ea9SDavid C Somayajulu pkt->header.baddr, pkt->header.len); 76fa790ea9SDavid C Somayajulu kfree(pkt); 77fa790ea9SDavid C Somayajulu 78fa790ea9SDavid C Somayajulu spin_lock_irqsave(&qp->q_lock, flags); 79fa790ea9SDavid C Somayajulu 80fa790ea9SDavid C Somayajulu qlnxr_inc_sw_gsi_cons(&qp->sq); 81fa790ea9SDavid C Somayajulu 82fa790ea9SDavid C Somayajulu spin_unlock_irqrestore(&qp->q_lock, flags); 83fa790ea9SDavid C Somayajulu 84fa790ea9SDavid C Somayajulu if (cq->ibcq.comp_handler) 85fa790ea9SDavid C Somayajulu (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); 86fa790ea9SDavid C Somayajulu 87fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 88fa790ea9SDavid C Somayajulu 89fa790ea9SDavid C Somayajulu return; 90fa790ea9SDavid C Somayajulu } 91fa790ea9SDavid C Somayajulu 92fa790ea9SDavid C Somayajulu void 93fa790ea9SDavid C Somayajulu qlnxr_ll2_complete_rx_packet(void *cxt, 94fa790ea9SDavid C Somayajulu struct ecore_ll2_comp_rx_data *data) 95fa790ea9SDavid C Somayajulu { 96fa790ea9SDavid C Somayajulu struct qlnxr_dev *dev = (struct qlnxr_dev *)cxt; 97fa790ea9SDavid C Somayajulu struct qlnxr_cq *cq = dev->gsi_rqcq; 98fa790ea9SDavid C Somayajulu // struct qlnxr_qp *qp = dev->gsi_qp; 99fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp = NULL; 100fa790ea9SDavid C Somayajulu unsigned long flags; 101fa790ea9SDavid C Somayajulu // uint32_t delay_count = 0, gsi_cons = 0; 102fa790ea9SDavid C Somayajulu //void * dest_va; 103fa790ea9SDavid C Somayajulu 104fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 105fa790ea9SDavid C Somayajulu 106fa790ea9SDavid C Somayajulu if (data->u.data_length_error) { 107fa790ea9SDavid C Somayajulu /* TODO: add statistic */ 108fa790ea9SDavid C Somayajulu } 109fa790ea9SDavid C Somayajulu 110fa790ea9SDavid C Somayajulu if (data->cookie == NULL) { 111fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "cookie is NULL, bad sign\n"); 112fa790ea9SDavid C Somayajulu } 113fa790ea9SDavid C Somayajulu 114fa790ea9SDavid C Somayajulu if (data->qp_id == 1) { 115fa790ea9SDavid C Somayajulu qp = dev->gsi_qp; 116fa790ea9SDavid C Somayajulu } else { 117fa790ea9SDavid C Somayajulu /* TODO: This will be needed for UD QP support */ 118fa790ea9SDavid C Somayajulu /* For RoCEv1 this is invalid */ 119fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "invalid QP\n"); 120fa790ea9SDavid C Somayajulu return; 121fa790ea9SDavid C Somayajulu } 122fa790ea9SDavid C Somayajulu /* note: currently only one recv sg is supported */ 123fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "MAD received on QP : %x\n", data->rx_buf_addr); 124fa790ea9SDavid C Somayajulu 125fa790ea9SDavid C Somayajulu spin_lock_irqsave(&qp->q_lock, flags); 126fa790ea9SDavid C Somayajulu 127fa790ea9SDavid C Somayajulu qp->rqe_wr_id[qp->rq.gsi_cons].rc = 128fa790ea9SDavid C Somayajulu data->u.data_length_error ? -EINVAL : 0; 129fa790ea9SDavid C Somayajulu qp->rqe_wr_id[qp->rq.gsi_cons].vlan_id = data->vlan; 130fa790ea9SDavid C Somayajulu /* note: length stands for data length i.e. GRH is excluded */ 131fa790ea9SDavid C Somayajulu qp->rqe_wr_id[qp->rq.gsi_cons].sg_list[0].length = 132fa790ea9SDavid C Somayajulu data->length.data_length; 133fa790ea9SDavid C Somayajulu *((u32 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[0]) = 134fa790ea9SDavid C Somayajulu ntohl(data->opaque_data_0); 135fa790ea9SDavid C Somayajulu *((u16 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[4]) = 136fa790ea9SDavid C Somayajulu ntohs((u16)data->opaque_data_1); 137fa790ea9SDavid C Somayajulu 138fa790ea9SDavid C Somayajulu qlnxr_inc_sw_gsi_cons(&qp->rq); 139fa790ea9SDavid C Somayajulu 140fa790ea9SDavid C Somayajulu spin_unlock_irqrestore(&qp->q_lock, flags); 141fa790ea9SDavid C Somayajulu 142fa790ea9SDavid C Somayajulu if (cq->ibcq.comp_handler) 143fa790ea9SDavid C Somayajulu (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); 144fa790ea9SDavid C Somayajulu 145fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 146fa790ea9SDavid C Somayajulu 147fa790ea9SDavid C Somayajulu return; 148fa790ea9SDavid C Somayajulu } 149fa790ea9SDavid C Somayajulu 150fa790ea9SDavid C Somayajulu void qlnxr_ll2_release_rx_packet(void *cxt, 151fa790ea9SDavid C Somayajulu u8 connection_handle, 152fa790ea9SDavid C Somayajulu void *cookie, 153fa790ea9SDavid C Somayajulu dma_addr_t rx_buf_addr, 154fa790ea9SDavid C Somayajulu bool b_last_packet) 155fa790ea9SDavid C Somayajulu { 156fa790ea9SDavid C Somayajulu /* Do nothing... */ 157fa790ea9SDavid C Somayajulu } 158fa790ea9SDavid C Somayajulu 159fa790ea9SDavid C Somayajulu static void 160fa790ea9SDavid C Somayajulu qlnxr_destroy_gsi_cq(struct qlnxr_dev *dev, 161fa790ea9SDavid C Somayajulu struct ib_qp_init_attr *attrs) 162fa790ea9SDavid C Somayajulu { 163fa790ea9SDavid C Somayajulu struct ecore_rdma_destroy_cq_in_params iparams; 164fa790ea9SDavid C Somayajulu struct ecore_rdma_destroy_cq_out_params oparams; 165fa790ea9SDavid C Somayajulu struct qlnxr_cq *cq; 166fa790ea9SDavid C Somayajulu 167fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 168fa790ea9SDavid C Somayajulu 169fa790ea9SDavid C Somayajulu cq = get_qlnxr_cq((attrs->send_cq)); 170fa790ea9SDavid C Somayajulu iparams.icid = cq->icid; 171fa790ea9SDavid C Somayajulu ecore_rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); 172fa790ea9SDavid C Somayajulu ecore_chain_free(&dev->ha->cdev, &cq->pbl); 173fa790ea9SDavid C Somayajulu 174fa790ea9SDavid C Somayajulu cq = get_qlnxr_cq((attrs->recv_cq)); 175fa790ea9SDavid C Somayajulu /* if a dedicated recv_cq was used, delete it too */ 176fa790ea9SDavid C Somayajulu if (iparams.icid != cq->icid) { 177fa790ea9SDavid C Somayajulu iparams.icid = cq->icid; 178fa790ea9SDavid C Somayajulu ecore_rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); 179fa790ea9SDavid C Somayajulu ecore_chain_free(&dev->ha->cdev, &cq->pbl); 180fa790ea9SDavid C Somayajulu } 181fa790ea9SDavid C Somayajulu 182fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 183fa790ea9SDavid C Somayajulu 184fa790ea9SDavid C Somayajulu return; 185fa790ea9SDavid C Somayajulu } 186fa790ea9SDavid C Somayajulu 187fa790ea9SDavid C Somayajulu static inline int 188fa790ea9SDavid C Somayajulu qlnxr_check_gsi_qp_attrs(struct qlnxr_dev *dev, 189fa790ea9SDavid C Somayajulu struct ib_qp_init_attr *attrs) 190fa790ea9SDavid C Somayajulu { 191fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 192fa790ea9SDavid C Somayajulu 193fa790ea9SDavid C Somayajulu if (attrs->cap.max_recv_sge > QLNXR_GSI_MAX_RECV_SGE) { 194fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 195fa790ea9SDavid C Somayajulu "(attrs->cap.max_recv_sge > QLNXR_GSI_MAX_RECV_SGE)\n"); 196fa790ea9SDavid C Somayajulu return -EINVAL; 197fa790ea9SDavid C Somayajulu } 198fa790ea9SDavid C Somayajulu 199fa790ea9SDavid C Somayajulu if (attrs->cap.max_recv_wr > QLNXR_GSI_MAX_RECV_WR) { 200fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 201fa790ea9SDavid C Somayajulu "(attrs->cap.max_recv_wr > QLNXR_GSI_MAX_RECV_WR)\n"); 202fa790ea9SDavid C Somayajulu return -EINVAL; 203fa790ea9SDavid C Somayajulu } 204fa790ea9SDavid C Somayajulu 205fa790ea9SDavid C Somayajulu if (attrs->cap.max_send_wr > QLNXR_GSI_MAX_SEND_WR) { 206fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 207fa790ea9SDavid C Somayajulu "(attrs->cap.max_send_wr > QLNXR_GSI_MAX_SEND_WR)\n"); 208fa790ea9SDavid C Somayajulu return -EINVAL; 209fa790ea9SDavid C Somayajulu } 210fa790ea9SDavid C Somayajulu 211fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 212fa790ea9SDavid C Somayajulu 213fa790ea9SDavid C Somayajulu return 0; 214fa790ea9SDavid C Somayajulu } 215fa790ea9SDavid C Somayajulu 216fa790ea9SDavid C Somayajulu static int 217fa790ea9SDavid C Somayajulu qlnxr_ll2_post_tx(struct qlnxr_dev *dev, struct ecore_roce_ll2_packet *pkt) 218fa790ea9SDavid C Somayajulu { 219fa790ea9SDavid C Somayajulu enum ecore_ll2_roce_flavor_type roce_flavor; 220fa790ea9SDavid C Somayajulu struct ecore_ll2_tx_pkt_info ll2_tx_pkt; 221fa790ea9SDavid C Somayajulu int rc; 222fa790ea9SDavid C Somayajulu int i; 223fa790ea9SDavid C Somayajulu 224fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 225fa790ea9SDavid C Somayajulu 226fa790ea9SDavid C Somayajulu memset(&ll2_tx_pkt, 0, sizeof(ll2_tx_pkt)); 227fa790ea9SDavid C Somayajulu 228fa790ea9SDavid C Somayajulu if (pkt->roce_mode != ROCE_V1) { 229fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "roce_mode != ROCE_V1\n"); 230fa790ea9SDavid C Somayajulu return (-1); 231fa790ea9SDavid C Somayajulu } 232fa790ea9SDavid C Somayajulu 233fa790ea9SDavid C Somayajulu roce_flavor = (pkt->roce_mode == ROCE_V1) ? 234fa790ea9SDavid C Somayajulu ECORE_LL2_ROCE : ECORE_LL2_RROCE; 235fa790ea9SDavid C Somayajulu 236fa790ea9SDavid C Somayajulu ll2_tx_pkt.num_of_bds = 1 /* hdr */ + pkt->n_seg; 237fa790ea9SDavid C Somayajulu ll2_tx_pkt.vlan = 0; /* ??? */ 238fa790ea9SDavid C Somayajulu ll2_tx_pkt.tx_dest = ECORE_LL2_TX_DEST_NW; 239fa790ea9SDavid C Somayajulu ll2_tx_pkt.ecore_roce_flavor = roce_flavor; 240fa790ea9SDavid C Somayajulu ll2_tx_pkt.first_frag = pkt->header.baddr; 241fa790ea9SDavid C Somayajulu ll2_tx_pkt.first_frag_len = pkt->header.len; 242fa790ea9SDavid C Somayajulu ll2_tx_pkt.cookie = pkt; 243fa790ea9SDavid C Somayajulu ll2_tx_pkt.enable_ip_cksum = 1; // Only for RoCEv2:IPv4 244fa790ea9SDavid C Somayajulu 245fa790ea9SDavid C Somayajulu /* tx header */ 246fa790ea9SDavid C Somayajulu rc = ecore_ll2_prepare_tx_packet(dev->rdma_ctx, 247fa790ea9SDavid C Somayajulu dev->gsi_ll2_handle, 248fa790ea9SDavid C Somayajulu &ll2_tx_pkt, 249fa790ea9SDavid C Somayajulu 1); 250fa790ea9SDavid C Somayajulu if (rc) { 251fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "ecore_ll2_prepare_tx_packet failed\n"); 252fa790ea9SDavid C Somayajulu 253fa790ea9SDavid C Somayajulu /* TX failed while posting header - release resources*/ 254fa790ea9SDavid C Somayajulu qlnx_dma_free_coherent(&dev->ha->cdev, 255fa790ea9SDavid C Somayajulu pkt->header.vaddr, 256fa790ea9SDavid C Somayajulu pkt->header.baddr, 257fa790ea9SDavid C Somayajulu pkt->header.len); 258fa790ea9SDavid C Somayajulu 259fa790ea9SDavid C Somayajulu kfree(pkt); 260fa790ea9SDavid C Somayajulu 261fa790ea9SDavid C Somayajulu return rc; 262fa790ea9SDavid C Somayajulu } 263fa790ea9SDavid C Somayajulu 264fa790ea9SDavid C Somayajulu /* tx payload */ 265fa790ea9SDavid C Somayajulu for (i = 0; i < pkt->n_seg; i++) { 266fa790ea9SDavid C Somayajulu rc = ecore_ll2_set_fragment_of_tx_packet(dev->rdma_ctx, 267fa790ea9SDavid C Somayajulu dev->gsi_ll2_handle, 268fa790ea9SDavid C Somayajulu pkt->payload[i].baddr, 269fa790ea9SDavid C Somayajulu pkt->payload[i].len); 270fa790ea9SDavid C Somayajulu if (rc) { 271fa790ea9SDavid C Somayajulu /* if failed not much to do here, partial packet has 272fa790ea9SDavid C Somayajulu * been posted we can't free memory, will need to wait 273fa790ea9SDavid C Somayajulu * for completion 274fa790ea9SDavid C Somayajulu */ 275fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 276fa790ea9SDavid C Somayajulu "ecore_ll2_set_fragment_of_tx_packet failed\n"); 277fa790ea9SDavid C Somayajulu return rc; 278fa790ea9SDavid C Somayajulu } 279fa790ea9SDavid C Somayajulu } 280fa790ea9SDavid C Somayajulu struct ecore_ll2_stats stats = {0}; 281fa790ea9SDavid C Somayajulu rc = ecore_ll2_get_stats(dev->rdma_ctx, dev->gsi_ll2_handle, &stats); 282fa790ea9SDavid C Somayajulu if (rc) { 283fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "failed to obtain ll2 stats\n"); 284fa790ea9SDavid C Somayajulu } 285fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 286fa790ea9SDavid C Somayajulu 287fa790ea9SDavid C Somayajulu return 0; 288fa790ea9SDavid C Somayajulu } 289fa790ea9SDavid C Somayajulu 290fa790ea9SDavid C Somayajulu int 291fa790ea9SDavid C Somayajulu qlnxr_ll2_stop(struct qlnxr_dev *dev) 292fa790ea9SDavid C Somayajulu { 293fa790ea9SDavid C Somayajulu int rc; 294fa790ea9SDavid C Somayajulu 295fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 296fa790ea9SDavid C Somayajulu 297fa790ea9SDavid C Somayajulu if (dev->gsi_ll2_handle == 0xFF) 298fa790ea9SDavid C Somayajulu return 0; 299fa790ea9SDavid C Somayajulu 300fa790ea9SDavid C Somayajulu /* remove LL2 MAC address filter */ 301fa790ea9SDavid C Somayajulu rc = qlnx_rdma_ll2_set_mac_filter(dev->rdma_ctx, 302fa790ea9SDavid C Somayajulu dev->gsi_ll2_mac_address, NULL); 303fa790ea9SDavid C Somayajulu 304fa790ea9SDavid C Somayajulu rc = ecore_ll2_terminate_connection(dev->rdma_ctx, 305fa790ea9SDavid C Somayajulu dev->gsi_ll2_handle); 306fa790ea9SDavid C Somayajulu 307fa790ea9SDavid C Somayajulu ecore_ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle); 308fa790ea9SDavid C Somayajulu 309fa790ea9SDavid C Somayajulu dev->gsi_ll2_handle = 0xFF; 310fa790ea9SDavid C Somayajulu 311fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit rc = %d\n", rc); 312fa790ea9SDavid C Somayajulu return rc; 313fa790ea9SDavid C Somayajulu } 314fa790ea9SDavid C Somayajulu 315fa790ea9SDavid C Somayajulu int qlnxr_ll2_start(struct qlnxr_dev *dev, 316fa790ea9SDavid C Somayajulu struct ib_qp_init_attr *attrs, 317fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp) 318fa790ea9SDavid C Somayajulu { 319fa790ea9SDavid C Somayajulu struct ecore_ll2_acquire_data data; 320fa790ea9SDavid C Somayajulu struct ecore_ll2_cbs cbs; 321fa790ea9SDavid C Somayajulu int rc; 322fa790ea9SDavid C Somayajulu 323fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 324fa790ea9SDavid C Somayajulu 325fa790ea9SDavid C Somayajulu /* configure and start LL2 */ 326fa790ea9SDavid C Somayajulu cbs.rx_comp_cb = qlnxr_ll2_complete_rx_packet; 327fa790ea9SDavid C Somayajulu cbs.tx_comp_cb = qlnxr_ll2_complete_tx_packet; 328fa790ea9SDavid C Somayajulu cbs.rx_release_cb = qlnxr_ll2_release_rx_packet; 329fa790ea9SDavid C Somayajulu cbs.tx_release_cb = qlnxr_ll2_complete_tx_packet; 330fa790ea9SDavid C Somayajulu cbs.cookie = dev; 331fa790ea9SDavid C Somayajulu dev->gsi_ll2_handle = 0xFF; 332fa790ea9SDavid C Somayajulu 333fa790ea9SDavid C Somayajulu memset(&data, 0, sizeof(data)); 334fa790ea9SDavid C Somayajulu data.input.conn_type = ECORE_LL2_TYPE_ROCE; 335*727bfe38SJustin Hibbits data.input.mtu = if_getmtu(dev->ha->ifp); 336fa790ea9SDavid C Somayajulu data.input.rx_num_desc = 8 * 1024; 337fa790ea9SDavid C Somayajulu data.input.rx_drop_ttl0_flg = 1; 338fa790ea9SDavid C Somayajulu data.input.rx_vlan_removal_en = 0; 339fa790ea9SDavid C Somayajulu data.input.tx_num_desc = 8 * 1024; 340fa790ea9SDavid C Somayajulu data.input.tx_tc = 0; 341fa790ea9SDavid C Somayajulu data.input.tx_dest = ECORE_LL2_TX_DEST_NW; 342fa790ea9SDavid C Somayajulu data.input.ai_err_packet_too_big = ECORE_LL2_DROP_PACKET; 343fa790ea9SDavid C Somayajulu data.input.ai_err_no_buf = ECORE_LL2_DROP_PACKET; 344fa790ea9SDavid C Somayajulu data.input.gsi_enable = 1; 345fa790ea9SDavid C Somayajulu data.p_connection_handle = &dev->gsi_ll2_handle; 346fa790ea9SDavid C Somayajulu data.cbs = &cbs; 347fa790ea9SDavid C Somayajulu 348fa790ea9SDavid C Somayajulu rc = ecore_ll2_acquire_connection(dev->rdma_ctx, &data); 349fa790ea9SDavid C Somayajulu 350fa790ea9SDavid C Somayajulu if (rc) { 351fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 352fa790ea9SDavid C Somayajulu "ecore_ll2_acquire_connection failed: %d\n", 353fa790ea9SDavid C Somayajulu rc); 354fa790ea9SDavid C Somayajulu return rc; 355fa790ea9SDavid C Somayajulu } 356fa790ea9SDavid C Somayajulu 357fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 358fa790ea9SDavid C Somayajulu "ll2 connection acquired successfully\n"); 359fa790ea9SDavid C Somayajulu rc = ecore_ll2_establish_connection(dev->rdma_ctx, 360fa790ea9SDavid C Somayajulu dev->gsi_ll2_handle); 361fa790ea9SDavid C Somayajulu 362fa790ea9SDavid C Somayajulu if (rc) { 363fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 364fa790ea9SDavid C Somayajulu "ecore_ll2_establish_connection failed\n", rc); 365fa790ea9SDavid C Somayajulu goto err1; 366fa790ea9SDavid C Somayajulu } 367fa790ea9SDavid C Somayajulu 368fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 369fa790ea9SDavid C Somayajulu "ll2 connection established successfully\n"); 370fa790ea9SDavid C Somayajulu rc = qlnx_rdma_ll2_set_mac_filter(dev->rdma_ctx, NULL, 371fa790ea9SDavid C Somayajulu dev->ha->primary_mac); 372fa790ea9SDavid C Somayajulu if (rc) { 373fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "qlnx_rdma_ll2_set_mac_filter failed\n", rc); 374fa790ea9SDavid C Somayajulu goto err2; 375fa790ea9SDavid C Somayajulu } 376fa790ea9SDavid C Somayajulu 377fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit rc = %d\n", rc); 378fa790ea9SDavid C Somayajulu return 0; 379fa790ea9SDavid C Somayajulu 380fa790ea9SDavid C Somayajulu err2: 381fa790ea9SDavid C Somayajulu ecore_ll2_terminate_connection(dev->rdma_ctx, dev->gsi_ll2_handle); 382fa790ea9SDavid C Somayajulu err1: 383fa790ea9SDavid C Somayajulu ecore_ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle); 384fa790ea9SDavid C Somayajulu 385fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit rc = %d\n", rc); 386fa790ea9SDavid C Somayajulu return rc; 387fa790ea9SDavid C Somayajulu } 388fa790ea9SDavid C Somayajulu 389fa790ea9SDavid C Somayajulu struct ib_qp* 390fa790ea9SDavid C Somayajulu qlnxr_create_gsi_qp(struct qlnxr_dev *dev, 391fa790ea9SDavid C Somayajulu struct ib_qp_init_attr *attrs, 392fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp) 393fa790ea9SDavid C Somayajulu { 394fa790ea9SDavid C Somayajulu int rc; 395fa790ea9SDavid C Somayajulu 396fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 397fa790ea9SDavid C Somayajulu 398fa790ea9SDavid C Somayajulu rc = qlnxr_check_gsi_qp_attrs(dev, attrs); 399fa790ea9SDavid C Somayajulu 400fa790ea9SDavid C Somayajulu if (rc) { 401fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "qlnxr_check_gsi_qp_attrs failed\n"); 402fa790ea9SDavid C Somayajulu return ERR_PTR(rc); 403fa790ea9SDavid C Somayajulu } 404fa790ea9SDavid C Somayajulu 405fa790ea9SDavid C Somayajulu rc = qlnxr_ll2_start(dev, attrs, qp); 406fa790ea9SDavid C Somayajulu if (rc) { 407fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "qlnxr_ll2_start failed\n"); 408fa790ea9SDavid C Somayajulu return ERR_PTR(rc); 409fa790ea9SDavid C Somayajulu } 410fa790ea9SDavid C Somayajulu 411fa790ea9SDavid C Somayajulu /* create QP */ 412fa790ea9SDavid C Somayajulu qp->ibqp.qp_num = 1; 413fa790ea9SDavid C Somayajulu qp->rq.max_wr = attrs->cap.max_recv_wr; 414fa790ea9SDavid C Somayajulu qp->sq.max_wr = attrs->cap.max_send_wr; 415fa790ea9SDavid C Somayajulu 416fa790ea9SDavid C Somayajulu qp->rqe_wr_id = kzalloc(qp->rq.max_wr * sizeof(*qp->rqe_wr_id), 417fa790ea9SDavid C Somayajulu GFP_KERNEL); 418fa790ea9SDavid C Somayajulu if (!qp->rqe_wr_id) { 419fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "(!qp->rqe_wr_id)\n"); 420fa790ea9SDavid C Somayajulu goto err; 421fa790ea9SDavid C Somayajulu } 422fa790ea9SDavid C Somayajulu 423fa790ea9SDavid C Somayajulu qp->wqe_wr_id = kzalloc(qp->sq.max_wr * sizeof(*qp->wqe_wr_id), 424fa790ea9SDavid C Somayajulu GFP_KERNEL); 425fa790ea9SDavid C Somayajulu if (!qp->wqe_wr_id) { 426fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "(!qp->wqe_wr_id)\n"); 427fa790ea9SDavid C Somayajulu goto err; 428fa790ea9SDavid C Somayajulu } 429fa790ea9SDavid C Somayajulu 430fa790ea9SDavid C Somayajulu qlnxr_store_gsi_qp_cq(dev, qp, attrs); 431fa790ea9SDavid C Somayajulu memcpy(dev->gsi_ll2_mac_address, dev->ha->primary_mac, ETH_ALEN); 432fa790ea9SDavid C Somayajulu 433fa790ea9SDavid C Somayajulu /* the GSI CQ is handled by the driver so remove it from the FW */ 434fa790ea9SDavid C Somayajulu qlnxr_destroy_gsi_cq(dev, attrs); 435fa790ea9SDavid C Somayajulu dev->gsi_rqcq->cq_type = QLNXR_CQ_TYPE_GSI; 436fa790ea9SDavid C Somayajulu dev->gsi_rqcq->cq_type = QLNXR_CQ_TYPE_GSI; 437fa790ea9SDavid C Somayajulu 438fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit &qp->ibqp = %p\n", &qp->ibqp); 439fa790ea9SDavid C Somayajulu 440fa790ea9SDavid C Somayajulu return &qp->ibqp; 441fa790ea9SDavid C Somayajulu err: 442fa790ea9SDavid C Somayajulu kfree(qp->rqe_wr_id); 443fa790ea9SDavid C Somayajulu 444fa790ea9SDavid C Somayajulu rc = qlnxr_ll2_stop(dev); 445fa790ea9SDavid C Somayajulu 446fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit with error\n"); 447fa790ea9SDavid C Somayajulu 448fa790ea9SDavid C Somayajulu return ERR_PTR(-ENOMEM); 449fa790ea9SDavid C Somayajulu } 450fa790ea9SDavid C Somayajulu 451fa790ea9SDavid C Somayajulu int 452fa790ea9SDavid C Somayajulu qlnxr_destroy_gsi_qp(struct qlnxr_dev *dev) 453fa790ea9SDavid C Somayajulu { 454fa790ea9SDavid C Somayajulu int rc = 0; 455fa790ea9SDavid C Somayajulu 456fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 457fa790ea9SDavid C Somayajulu 458fa790ea9SDavid C Somayajulu rc = qlnxr_ll2_stop(dev); 459fa790ea9SDavid C Somayajulu 460fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit rc = %d\n", rc); 461fa790ea9SDavid C Somayajulu return (rc); 462fa790ea9SDavid C Somayajulu } 463fa790ea9SDavid C Somayajulu 464fa790ea9SDavid C Somayajulu static inline bool 465fa790ea9SDavid C Somayajulu qlnxr_get_vlan_id_gsi(struct ib_ah_attr *ah_attr, u16 *vlan_id) 466fa790ea9SDavid C Somayajulu { 467fa790ea9SDavid C Somayajulu u16 tmp_vlan_id; 468fa790ea9SDavid C Somayajulu union ib_gid *dgid = &ah_attr->grh.dgid; 469fa790ea9SDavid C Somayajulu 470fa790ea9SDavid C Somayajulu tmp_vlan_id = (dgid->raw[11] << 8) | dgid->raw[12]; 471fa790ea9SDavid C Somayajulu if (tmp_vlan_id < 0x1000) { 472fa790ea9SDavid C Somayajulu *vlan_id = tmp_vlan_id; 473fa790ea9SDavid C Somayajulu return true; 474fa790ea9SDavid C Somayajulu } else { 475fa790ea9SDavid C Somayajulu *vlan_id = 0; 476fa790ea9SDavid C Somayajulu return false; 477fa790ea9SDavid C Somayajulu } 478fa790ea9SDavid C Somayajulu } 479fa790ea9SDavid C Somayajulu 480fa790ea9SDavid C Somayajulu #define QLNXR_MAX_UD_HEADER_SIZE (100) 481fa790ea9SDavid C Somayajulu #define QLNXR_GSI_QPN (1) 482fa790ea9SDavid C Somayajulu static inline int 483fa790ea9SDavid C Somayajulu qlnxr_gsi_build_header(struct qlnxr_dev *dev, 484fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp, 485c3987b8eSHans Petter Selasky const struct ib_send_wr *swr, 486fa790ea9SDavid C Somayajulu struct ib_ud_header *udh, 487fa790ea9SDavid C Somayajulu int *roce_mode) 488fa790ea9SDavid C Somayajulu { 489fa790ea9SDavid C Somayajulu bool has_vlan = false, has_grh_ipv6 = true; 490fa790ea9SDavid C Somayajulu struct ib_ah_attr *ah_attr = &get_qlnxr_ah((ud_wr(swr)->ah))->attr; 491fa790ea9SDavid C Somayajulu struct ib_global_route *grh = &ah_attr->grh; 492fa790ea9SDavid C Somayajulu union ib_gid sgid; 493fa790ea9SDavid C Somayajulu int send_size = 0; 494fa790ea9SDavid C Somayajulu u16 vlan_id = 0; 495fa790ea9SDavid C Somayajulu u16 ether_type; 496fa790ea9SDavid C Somayajulu 497fa790ea9SDavid C Somayajulu int rc = 0; 498fa790ea9SDavid C Somayajulu int ip_ver = 0; 499fa790ea9SDavid C Somayajulu bool has_udp = false; 500fa790ea9SDavid C Somayajulu 501fa790ea9SDavid C Somayajulu int i; 502fa790ea9SDavid C Somayajulu 503fa790ea9SDavid C Somayajulu send_size = 0; 504fa790ea9SDavid C Somayajulu for (i = 0; i < swr->num_sge; ++i) 505fa790ea9SDavid C Somayajulu send_size += swr->sg_list[i].length; 506fa790ea9SDavid C Somayajulu 507fa790ea9SDavid C Somayajulu has_vlan = qlnxr_get_vlan_id_gsi(ah_attr, &vlan_id); 508fa790ea9SDavid C Somayajulu ether_type = ETH_P_ROCE; 509fa790ea9SDavid C Somayajulu *roce_mode = ROCE_V1; 510fa790ea9SDavid C Somayajulu if (grh->sgid_index < QLNXR_MAX_SGID) 511fa790ea9SDavid C Somayajulu sgid = dev->sgid_tbl[grh->sgid_index]; 512fa790ea9SDavid C Somayajulu else 513fa790ea9SDavid C Somayajulu sgid = dev->sgid_tbl[0]; 514fa790ea9SDavid C Somayajulu 515fa790ea9SDavid C Somayajulu rc = ib_ud_header_init(send_size, false /* LRH */, true /* ETH */, 516fa790ea9SDavid C Somayajulu has_vlan, has_grh_ipv6, ip_ver, has_udp, 517fa790ea9SDavid C Somayajulu 0 /* immediate */, udh); 518fa790ea9SDavid C Somayajulu 519fa790ea9SDavid C Somayajulu if (rc) { 520fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "gsi post send: failed to init header\n"); 521fa790ea9SDavid C Somayajulu return rc; 522fa790ea9SDavid C Somayajulu } 523fa790ea9SDavid C Somayajulu 524fa790ea9SDavid C Somayajulu /* ENET + VLAN headers*/ 525fa790ea9SDavid C Somayajulu memcpy(udh->eth.dmac_h, ah_attr->dmac, ETH_ALEN); 526fa790ea9SDavid C Somayajulu memcpy(udh->eth.smac_h, dev->ha->primary_mac, ETH_ALEN); 527fa790ea9SDavid C Somayajulu if (has_vlan) { 528fa790ea9SDavid C Somayajulu udh->eth.type = htons(ETH_P_8021Q); 529fa790ea9SDavid C Somayajulu udh->vlan.tag = htons(vlan_id); 530fa790ea9SDavid C Somayajulu udh->vlan.type = htons(ether_type); 531fa790ea9SDavid C Somayajulu } else { 532fa790ea9SDavid C Somayajulu udh->eth.type = htons(ether_type); 533fa790ea9SDavid C Somayajulu } 534fa790ea9SDavid C Somayajulu 535fa790ea9SDavid C Somayajulu for (int j = 0; j < 4; j++) { 536fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "destination mac: %x\n", 537fa790ea9SDavid C Somayajulu udh->eth.dmac_h[j]); 538fa790ea9SDavid C Somayajulu } 539fa790ea9SDavid C Somayajulu for (int j = 0; j < 4; j++) { 540fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "source mac: %x\n", 541fa790ea9SDavid C Somayajulu udh->eth.smac_h[j]); 542fa790ea9SDavid C Somayajulu } 543fa790ea9SDavid C Somayajulu 544fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "QP: %p, opcode: %d, wq: %lx, roce: %x, hops:%d," 545fa790ea9SDavid C Somayajulu "imm : %d, vlan :%d, AH: %p\n", 546fa790ea9SDavid C Somayajulu qp, swr->opcode, swr->wr_id, *roce_mode, grh->hop_limit, 547fa790ea9SDavid C Somayajulu 0, has_vlan, get_qlnxr_ah((ud_wr(swr)->ah))); 548fa790ea9SDavid C Somayajulu 549fa790ea9SDavid C Somayajulu if (has_grh_ipv6) { 550fa790ea9SDavid C Somayajulu /* GRH / IPv6 header */ 551fa790ea9SDavid C Somayajulu udh->grh.traffic_class = grh->traffic_class; 552fa790ea9SDavid C Somayajulu udh->grh.flow_label = grh->flow_label; 553fa790ea9SDavid C Somayajulu udh->grh.hop_limit = grh->hop_limit; 554fa790ea9SDavid C Somayajulu udh->grh.destination_gid = grh->dgid; 555fa790ea9SDavid C Somayajulu memcpy(&udh->grh.source_gid.raw, &sgid.raw, 556fa790ea9SDavid C Somayajulu sizeof(udh->grh.source_gid.raw)); 557fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "header: tc: %x, flow_label : %x, " 558fa790ea9SDavid C Somayajulu "hop_limit: %x \n", udh->grh.traffic_class, 559fa790ea9SDavid C Somayajulu udh->grh.flow_label, udh->grh.hop_limit); 560fa790ea9SDavid C Somayajulu for (i = 0; i < 16; i++) { 561fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "udh dgid = %x\n", udh->grh.destination_gid.raw[i]); 562fa790ea9SDavid C Somayajulu } 563fa790ea9SDavid C Somayajulu for (i = 0; i < 16; i++) { 564fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "udh sgid = %x\n", udh->grh.source_gid.raw[i]); 565fa790ea9SDavid C Somayajulu } 566fa790ea9SDavid C Somayajulu udh->grh.next_header = 0x1b; 567fa790ea9SDavid C Somayajulu } 568fa790ea9SDavid C Somayajulu #ifdef DEFINE_IB_UD_HEADER_INIT_UDP_PRESENT 569fa790ea9SDavid C Somayajulu /* This is for RoCEv2 */ 570fa790ea9SDavid C Somayajulu else { 571fa790ea9SDavid C Somayajulu /* IPv4 header */ 572fa790ea9SDavid C Somayajulu u32 ipv4_addr; 573fa790ea9SDavid C Somayajulu 574fa790ea9SDavid C Somayajulu udh->ip4.protocol = IPPROTO_UDP; 575fa790ea9SDavid C Somayajulu udh->ip4.tos = htonl(grh->flow_label); 576fa790ea9SDavid C Somayajulu udh->ip4.frag_off = htons(IP_DF); 577fa790ea9SDavid C Somayajulu udh->ip4.ttl = grh->hop_limit; 578fa790ea9SDavid C Somayajulu 579fa790ea9SDavid C Somayajulu ipv4_addr = qedr_get_ipv4_from_gid(sgid.raw); 580fa790ea9SDavid C Somayajulu udh->ip4.saddr = ipv4_addr; 581fa790ea9SDavid C Somayajulu ipv4_addr = qedr_get_ipv4_from_gid(grh->dgid.raw); 582fa790ea9SDavid C Somayajulu udh->ip4.daddr = ipv4_addr; 583fa790ea9SDavid C Somayajulu /* note: checksum is calculated by the device */ 584fa790ea9SDavid C Somayajulu } 585fa790ea9SDavid C Somayajulu #endif 586fa790ea9SDavid C Somayajulu 587fa790ea9SDavid C Somayajulu /* BTH */ 588fa790ea9SDavid C Somayajulu udh->bth.solicited_event = !!(swr->send_flags & IB_SEND_SOLICITED); 589fa790ea9SDavid C Somayajulu udh->bth.pkey = QLNXR_ROCE_PKEY_DEFAULT;/* TODO: ib_get_cahced_pkey?! */ 590fa790ea9SDavid C Somayajulu //udh->bth.destination_qpn = htonl(ud_wr(swr)->remote_qpn); 591fa790ea9SDavid C Somayajulu udh->bth.destination_qpn = OSAL_CPU_TO_BE32(ud_wr(swr)->remote_qpn); 592fa790ea9SDavid C Somayajulu //udh->bth.psn = htonl((qp->sq_psn++) & ((1 << 24) - 1)); 593fa790ea9SDavid C Somayajulu udh->bth.psn = OSAL_CPU_TO_BE32((qp->sq_psn++) & ((1 << 24) - 1)); 594fa790ea9SDavid C Somayajulu udh->bth.opcode = IB_OPCODE_UD_SEND_ONLY; 595fa790ea9SDavid C Somayajulu 596fa790ea9SDavid C Somayajulu /* DETH */ 597fa790ea9SDavid C Somayajulu //udh->deth.qkey = htonl(0x80010000); /* qp->qkey */ /* TODO: what is?! */ 598fa790ea9SDavid C Somayajulu //udh->deth.source_qpn = htonl(QLNXR_GSI_QPN); 599fa790ea9SDavid C Somayajulu udh->deth.qkey = OSAL_CPU_TO_BE32(0x80010000); /* qp->qkey */ /* TODO: what is?! */ 600fa790ea9SDavid C Somayajulu udh->deth.source_qpn = OSAL_CPU_TO_BE32(QLNXR_GSI_QPN); 601fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 602fa790ea9SDavid C Somayajulu return 0; 603fa790ea9SDavid C Somayajulu } 604fa790ea9SDavid C Somayajulu 605fa790ea9SDavid C Somayajulu static inline int 606fa790ea9SDavid C Somayajulu qlnxr_gsi_build_packet(struct qlnxr_dev *dev, 607c3987b8eSHans Petter Selasky struct qlnxr_qp *qp, const struct ib_send_wr *swr, 608fa790ea9SDavid C Somayajulu struct ecore_roce_ll2_packet **p_packet) 609fa790ea9SDavid C Somayajulu { 610fa790ea9SDavid C Somayajulu u8 ud_header_buffer[QLNXR_MAX_UD_HEADER_SIZE]; 611fa790ea9SDavid C Somayajulu struct ecore_roce_ll2_packet *packet; 612fa790ea9SDavid C Somayajulu int roce_mode, header_size; 613fa790ea9SDavid C Somayajulu struct ib_ud_header udh; 614fa790ea9SDavid C Somayajulu int i, rc; 615fa790ea9SDavid C Somayajulu 616fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 617fa790ea9SDavid C Somayajulu 618fa790ea9SDavid C Somayajulu *p_packet = NULL; 619fa790ea9SDavid C Somayajulu 620fa790ea9SDavid C Somayajulu rc = qlnxr_gsi_build_header(dev, qp, swr, &udh, &roce_mode); 621fa790ea9SDavid C Somayajulu if (rc) { 622fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 623fa790ea9SDavid C Somayajulu "qlnxr_gsi_build_header failed rc = %d\n", rc); 624fa790ea9SDavid C Somayajulu return rc; 625fa790ea9SDavid C Somayajulu } 626fa790ea9SDavid C Somayajulu 627fa790ea9SDavid C Somayajulu header_size = ib_ud_header_pack(&udh, &ud_header_buffer); 628fa790ea9SDavid C Somayajulu 629fa790ea9SDavid C Somayajulu packet = kzalloc(sizeof(*packet), GFP_ATOMIC); 630fa790ea9SDavid C Somayajulu if (!packet) { 631fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "packet == NULL\n"); 632fa790ea9SDavid C Somayajulu return -ENOMEM; 633fa790ea9SDavid C Somayajulu } 634fa790ea9SDavid C Somayajulu 635fa790ea9SDavid C Somayajulu packet->header.vaddr = qlnx_dma_alloc_coherent(&dev->ha->cdev, 636fa790ea9SDavid C Somayajulu &packet->header.baddr, 637fa790ea9SDavid C Somayajulu header_size); 638fa790ea9SDavid C Somayajulu if (!packet->header.vaddr) { 639fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "packet->header.vaddr == NULL\n"); 640fa790ea9SDavid C Somayajulu kfree(packet); 641fa790ea9SDavid C Somayajulu return -ENOMEM; 642fa790ea9SDavid C Somayajulu } 643fa790ea9SDavid C Somayajulu 644fa790ea9SDavid C Somayajulu if (memcmp(udh.eth.smac_h, udh.eth.dmac_h, ETH_ALEN)) 645fa790ea9SDavid C Somayajulu packet->tx_dest = ECORE_ROCE_LL2_TX_DEST_NW; 646fa790ea9SDavid C Somayajulu else 647fa790ea9SDavid C Somayajulu packet->tx_dest = ECORE_ROCE_LL2_TX_DEST_LB; 648fa790ea9SDavid C Somayajulu 649fa790ea9SDavid C Somayajulu packet->roce_mode = roce_mode; 650fa790ea9SDavid C Somayajulu memcpy(packet->header.vaddr, ud_header_buffer, header_size); 651fa790ea9SDavid C Somayajulu packet->header.len = header_size; 652fa790ea9SDavid C Somayajulu packet->n_seg = swr->num_sge; 653fa790ea9SDavid C Somayajulu qp->wqe_wr_id[qp->sq.prod].bytes_len = IB_GRH_BYTES; //RDMA_GRH_BYTES 654fa790ea9SDavid C Somayajulu for (i = 0; i < packet->n_seg; i++) { 655fa790ea9SDavid C Somayajulu packet->payload[i].baddr = swr->sg_list[i].addr; 656fa790ea9SDavid C Somayajulu packet->payload[i].len = swr->sg_list[i].length; 657fa790ea9SDavid C Somayajulu qp->wqe_wr_id[qp->sq.prod].bytes_len += 658fa790ea9SDavid C Somayajulu packet->payload[i].len; 659fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "baddr: %p, len: %d\n", 660fa790ea9SDavid C Somayajulu packet->payload[i].baddr, 661fa790ea9SDavid C Somayajulu packet->payload[i].len); 662fa790ea9SDavid C Somayajulu } 663fa790ea9SDavid C Somayajulu 664fa790ea9SDavid C Somayajulu *p_packet = packet; 665fa790ea9SDavid C Somayajulu 666fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit, packet->n_seg: %d\n", packet->n_seg); 667fa790ea9SDavid C Somayajulu return 0; 668fa790ea9SDavid C Somayajulu } 669fa790ea9SDavid C Somayajulu 670fa790ea9SDavid C Somayajulu int 671fa790ea9SDavid C Somayajulu qlnxr_gsi_post_send(struct ib_qp *ibqp, 672c3987b8eSHans Petter Selasky const struct ib_send_wr *wr, 673c3987b8eSHans Petter Selasky const struct ib_send_wr **bad_wr) 674fa790ea9SDavid C Somayajulu { 675fa790ea9SDavid C Somayajulu struct ecore_roce_ll2_packet *pkt = NULL; 676fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp = get_qlnxr_qp(ibqp); 677fa790ea9SDavid C Somayajulu struct qlnxr_dev *dev = qp->dev; 678fa790ea9SDavid C Somayajulu unsigned long flags; 679fa790ea9SDavid C Somayajulu int rc; 680fa790ea9SDavid C Somayajulu 681fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 682fa790ea9SDavid C Somayajulu 683fa790ea9SDavid C Somayajulu if (qp->state != ECORE_ROCE_QP_STATE_RTS) { 684fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 685fa790ea9SDavid C Somayajulu "(qp->state != ECORE_ROCE_QP_STATE_RTS)\n"); 686fa790ea9SDavid C Somayajulu *bad_wr = wr; 687fa790ea9SDavid C Somayajulu return -EINVAL; 688fa790ea9SDavid C Somayajulu } 689fa790ea9SDavid C Somayajulu 690fa790ea9SDavid C Somayajulu if (wr->num_sge > RDMA_MAX_SGE_PER_SQ_WQE) { 691fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, 692fa790ea9SDavid C Somayajulu "(wr->num_sge > RDMA_MAX_SGE_PER_SQ_WQE)\n"); 693fa790ea9SDavid C Somayajulu rc = -EINVAL; 694fa790ea9SDavid C Somayajulu goto err; 695fa790ea9SDavid C Somayajulu } 696fa790ea9SDavid C Somayajulu 697fa790ea9SDavid C Somayajulu if (wr->opcode != IB_WR_SEND) { 698fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "(wr->opcode > IB_WR_SEND)\n"); 699fa790ea9SDavid C Somayajulu rc = -EINVAL; 700fa790ea9SDavid C Somayajulu goto err; 701fa790ea9SDavid C Somayajulu } 702fa790ea9SDavid C Somayajulu 703fa790ea9SDavid C Somayajulu spin_lock_irqsave(&qp->q_lock, flags); 704fa790ea9SDavid C Somayajulu 705fa790ea9SDavid C Somayajulu rc = qlnxr_gsi_build_packet(dev, qp, wr, &pkt); 706fa790ea9SDavid C Somayajulu if(rc) { 707fa790ea9SDavid C Somayajulu spin_unlock_irqrestore(&qp->q_lock, flags); 708fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "qlnxr_gsi_build_packet failed\n"); 709fa790ea9SDavid C Somayajulu goto err; 710fa790ea9SDavid C Somayajulu } 711fa790ea9SDavid C Somayajulu 712fa790ea9SDavid C Somayajulu rc = qlnxr_ll2_post_tx(dev, pkt); 713fa790ea9SDavid C Somayajulu 714fa790ea9SDavid C Somayajulu if (!rc) { 715fa790ea9SDavid C Somayajulu qp->wqe_wr_id[qp->sq.prod].wr_id = wr->wr_id; 716fa790ea9SDavid C Somayajulu qp->wqe_wr_id[qp->sq.prod].signaled = 717fa790ea9SDavid C Somayajulu !!(wr->send_flags & IB_SEND_SIGNALED); 718fa790ea9SDavid C Somayajulu qp->wqe_wr_id[qp->sq.prod].opcode = IB_WC_SEND; 719fa790ea9SDavid C Somayajulu qlnxr_inc_sw_prod(&qp->sq); 720fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "packet sent over gsi qp\n"); 721fa790ea9SDavid C Somayajulu } else { 722fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "qlnxr_ll2_post_tx failed\n"); 723fa790ea9SDavid C Somayajulu rc = -EAGAIN; 724fa790ea9SDavid C Somayajulu *bad_wr = wr; 725fa790ea9SDavid C Somayajulu } 726fa790ea9SDavid C Somayajulu 727fa790ea9SDavid C Somayajulu spin_unlock_irqrestore(&qp->q_lock, flags); 728fa790ea9SDavid C Somayajulu 729fa790ea9SDavid C Somayajulu if (wr->next != NULL) { 730fa790ea9SDavid C Somayajulu *bad_wr = wr->next; 731fa790ea9SDavid C Somayajulu rc=-EINVAL; 732fa790ea9SDavid C Somayajulu } 733fa790ea9SDavid C Somayajulu 734fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit\n"); 735fa790ea9SDavid C Somayajulu return rc; 736fa790ea9SDavid C Somayajulu 737fa790ea9SDavid C Somayajulu err: 738fa790ea9SDavid C Somayajulu *bad_wr = wr; 739fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit error\n"); 740fa790ea9SDavid C Somayajulu return rc; 741fa790ea9SDavid C Somayajulu } 742fa790ea9SDavid C Somayajulu 743fa790ea9SDavid C Somayajulu #define QLNXR_LL2_RX_BUFFER_SIZE (4 * 1024) 744fa790ea9SDavid C Somayajulu int 745fa790ea9SDavid C Somayajulu qlnxr_gsi_post_recv(struct ib_qp *ibqp, 746c3987b8eSHans Petter Selasky const struct ib_recv_wr *wr, 747c3987b8eSHans Petter Selasky const struct ib_recv_wr **bad_wr) 748fa790ea9SDavid C Somayajulu { 749fa790ea9SDavid C Somayajulu struct qlnxr_dev *dev = get_qlnxr_dev((ibqp->device)); 750fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp = get_qlnxr_qp(ibqp); 751fa790ea9SDavid C Somayajulu unsigned long flags; 752fa790ea9SDavid C Somayajulu int rc = 0; 753fa790ea9SDavid C Somayajulu 754fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter, wr: %p\n", wr); 755fa790ea9SDavid C Somayajulu 756fa790ea9SDavid C Somayajulu if ((qp->state != ECORE_ROCE_QP_STATE_RTR) && 757fa790ea9SDavid C Somayajulu (qp->state != ECORE_ROCE_QP_STATE_RTS)) { 758fa790ea9SDavid C Somayajulu *bad_wr = wr; 759fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "exit 0\n"); 760fa790ea9SDavid C Somayajulu return -EINVAL; 761fa790ea9SDavid C Somayajulu } 762fa790ea9SDavid C Somayajulu 763fa790ea9SDavid C Somayajulu spin_lock_irqsave(&qp->q_lock, flags); 764fa790ea9SDavid C Somayajulu 765fa790ea9SDavid C Somayajulu while (wr) { 766fa790ea9SDavid C Somayajulu if (wr->num_sge > QLNXR_GSI_MAX_RECV_SGE) { 767fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "exit 1\n"); 768fa790ea9SDavid C Somayajulu goto err; 769fa790ea9SDavid C Somayajulu } 770fa790ea9SDavid C Somayajulu 771fa790ea9SDavid C Somayajulu rc = ecore_ll2_post_rx_buffer(dev->rdma_ctx, 772fa790ea9SDavid C Somayajulu dev->gsi_ll2_handle, 773fa790ea9SDavid C Somayajulu wr->sg_list[0].addr, 774fa790ea9SDavid C Somayajulu wr->sg_list[0].length, 775fa790ea9SDavid C Somayajulu 0 /* cookie */, 776fa790ea9SDavid C Somayajulu 1 /* notify_fw */); 777fa790ea9SDavid C Somayajulu if (rc) { 778fa790ea9SDavid C Somayajulu QL_DPRINT11(dev->ha, "exit 2\n"); 779fa790ea9SDavid C Somayajulu goto err; 780fa790ea9SDavid C Somayajulu } 781fa790ea9SDavid C Somayajulu 782fa790ea9SDavid C Somayajulu memset(&qp->rqe_wr_id[qp->rq.prod], 0, 783fa790ea9SDavid C Somayajulu sizeof(qp->rqe_wr_id[qp->rq.prod])); 784fa790ea9SDavid C Somayajulu qp->rqe_wr_id[qp->rq.prod].sg_list[0] = wr->sg_list[0]; 785fa790ea9SDavid C Somayajulu qp->rqe_wr_id[qp->rq.prod].wr_id = wr->wr_id; 786fa790ea9SDavid C Somayajulu 787fa790ea9SDavid C Somayajulu qlnxr_inc_sw_prod(&qp->rq); 788fa790ea9SDavid C Somayajulu 789fa790ea9SDavid C Somayajulu wr = wr->next; 790fa790ea9SDavid C Somayajulu } 791fa790ea9SDavid C Somayajulu 792fa790ea9SDavid C Somayajulu spin_unlock_irqrestore(&qp->q_lock, flags); 793fa790ea9SDavid C Somayajulu 794fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit rc = %d\n", rc); 795fa790ea9SDavid C Somayajulu return rc; 796fa790ea9SDavid C Somayajulu err: 797fa790ea9SDavid C Somayajulu 798fa790ea9SDavid C Somayajulu spin_unlock_irqrestore(&qp->q_lock, flags); 799fa790ea9SDavid C Somayajulu *bad_wr = wr; 800fa790ea9SDavid C Somayajulu 801fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit with -ENOMEM\n"); 802fa790ea9SDavid C Somayajulu return -ENOMEM; 803fa790ea9SDavid C Somayajulu } 804fa790ea9SDavid C Somayajulu 805fa790ea9SDavid C Somayajulu int 806fa790ea9SDavid C Somayajulu qlnxr_gsi_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 807fa790ea9SDavid C Somayajulu { 808fa790ea9SDavid C Somayajulu struct qlnxr_dev *dev = get_qlnxr_dev((ibcq->device)); 809fa790ea9SDavid C Somayajulu struct qlnxr_cq *cq = get_qlnxr_cq(ibcq); 810fa790ea9SDavid C Somayajulu struct qlnxr_qp *qp = dev->gsi_qp; 811fa790ea9SDavid C Somayajulu unsigned long flags; 812fa790ea9SDavid C Somayajulu int i = 0; 813fa790ea9SDavid C Somayajulu 814fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "enter\n"); 815fa790ea9SDavid C Somayajulu 816fa790ea9SDavid C Somayajulu spin_lock_irqsave(&cq->cq_lock, flags); 817fa790ea9SDavid C Somayajulu 818fa790ea9SDavid C Somayajulu while (i < num_entries && qp->rq.cons != qp->rq.gsi_cons) { 819fa790ea9SDavid C Somayajulu memset(&wc[i], 0, sizeof(*wc)); 820fa790ea9SDavid C Somayajulu 821fa790ea9SDavid C Somayajulu wc[i].qp = &qp->ibqp; 822fa790ea9SDavid C Somayajulu wc[i].wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id; 823fa790ea9SDavid C Somayajulu wc[i].opcode = IB_WC_RECV; 824fa790ea9SDavid C Somayajulu wc[i].pkey_index = 0; 825fa790ea9SDavid C Somayajulu wc[i].status = (qp->rqe_wr_id[qp->rq.cons].rc)? 826fa790ea9SDavid C Somayajulu IB_WC_GENERAL_ERR:IB_WC_SUCCESS; 827fa790ea9SDavid C Somayajulu /* 0 - currently only one recv sg is supported */ 828fa790ea9SDavid C Somayajulu wc[i].byte_len = qp->rqe_wr_id[qp->rq.cons].sg_list[0].length; 829fa790ea9SDavid C Somayajulu wc[i].wc_flags |= IB_WC_GRH | IB_WC_IP_CSUM_OK; 830fa790ea9SDavid C Somayajulu 831fa790ea9SDavid C Somayajulu memcpy(&wc[i].smac, qp->rqe_wr_id[qp->rq.cons].smac, ETH_ALEN); 832fa790ea9SDavid C Somayajulu wc[i].wc_flags |= IB_WC_WITH_SMAC; 833fa790ea9SDavid C Somayajulu 834fa790ea9SDavid C Somayajulu if (qp->rqe_wr_id[qp->rq.cons].vlan_id) { 835fa790ea9SDavid C Somayajulu wc[i].wc_flags |= IB_WC_WITH_VLAN; 836fa790ea9SDavid C Somayajulu wc[i].vlan_id = qp->rqe_wr_id[qp->rq.cons].vlan_id; 837fa790ea9SDavid C Somayajulu } 838fa790ea9SDavid C Somayajulu 839fa790ea9SDavid C Somayajulu qlnxr_inc_sw_cons(&qp->rq); 840fa790ea9SDavid C Somayajulu i++; 841fa790ea9SDavid C Somayajulu } 842fa790ea9SDavid C Somayajulu 843fa790ea9SDavid C Somayajulu while (i < num_entries && qp->sq.cons != qp->sq.gsi_cons) { 844fa790ea9SDavid C Somayajulu memset(&wc[i], 0, sizeof(*wc)); 845fa790ea9SDavid C Somayajulu 846fa790ea9SDavid C Somayajulu wc[i].qp = &qp->ibqp; 847fa790ea9SDavid C Somayajulu wc[i].wr_id = qp->wqe_wr_id[qp->sq.cons].wr_id; 848fa790ea9SDavid C Somayajulu wc[i].opcode = IB_WC_SEND; 849fa790ea9SDavid C Somayajulu wc[i].status = IB_WC_SUCCESS; 850fa790ea9SDavid C Somayajulu 851fa790ea9SDavid C Somayajulu qlnxr_inc_sw_cons(&qp->sq); 852fa790ea9SDavid C Somayajulu i++; 853fa790ea9SDavid C Somayajulu } 854fa790ea9SDavid C Somayajulu 855fa790ea9SDavid C Somayajulu spin_unlock_irqrestore(&cq->cq_lock, flags); 856fa790ea9SDavid C Somayajulu 857fa790ea9SDavid C Somayajulu QL_DPRINT12(dev->ha, "exit i = %d\n", i); 858fa790ea9SDavid C Somayajulu return i; 859fa790ea9SDavid C Somayajulu } 860