162306a36Sopenharmony_ci/* QLogic qedr NIC Driver 262306a36Sopenharmony_ci * Copyright (c) 2015-2016 QLogic Corporation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and /or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3362306a36Sopenharmony_ci#include <linux/crc32.h> 3462306a36Sopenharmony_ci#include <linux/iommu.h> 3562306a36Sopenharmony_ci#include <net/ip.h> 3662306a36Sopenharmony_ci#include <net/ipv6.h> 3762306a36Sopenharmony_ci#include <net/udp.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 4062306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 4162306a36Sopenharmony_ci#include <rdma/iw_cm.h> 4262306a36Sopenharmony_ci#include <rdma/ib_umem.h> 4362306a36Sopenharmony_ci#include <rdma/ib_addr.h> 4462306a36Sopenharmony_ci#include <rdma/ib_cache.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <linux/qed/qed_if.h> 4762306a36Sopenharmony_ci#include <linux/qed/qed_rdma_if.h> 4862306a36Sopenharmony_ci#include "qedr.h" 4962306a36Sopenharmony_ci#include "verbs.h" 5062306a36Sopenharmony_ci#include <rdma/qedr-abi.h> 5162306a36Sopenharmony_ci#include "qedr_roce_cm.h" 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_civoid qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci info->gsi_cons = (info->gsi_cons + 1) % info->max_wr; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_civoid qedr_store_gsi_qp_cq(struct qedr_dev *dev, struct qedr_qp *qp, 5962306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci dev->gsi_qp_created = 1; 6262306a36Sopenharmony_ci dev->gsi_sqcq = get_qedr_cq(attrs->send_cq); 6362306a36Sopenharmony_ci dev->gsi_rqcq = get_qedr_cq(attrs->recv_cq); 6462306a36Sopenharmony_ci dev->gsi_qp = qp; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic void qedr_ll2_complete_tx_packet(void *cxt, u8 connection_handle, 6862306a36Sopenharmony_ci void *cookie, 6962306a36Sopenharmony_ci dma_addr_t first_frag_addr, 7062306a36Sopenharmony_ci bool b_last_fragment, 7162306a36Sopenharmony_ci bool b_last_packet) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct qedr_dev *dev = (struct qedr_dev *)cxt; 7462306a36Sopenharmony_ci struct qed_roce_ll2_packet *pkt = cookie; 7562306a36Sopenharmony_ci struct qedr_cq *cq = dev->gsi_sqcq; 7662306a36Sopenharmony_ci struct qedr_qp *qp = dev->gsi_qp; 7762306a36Sopenharmony_ci unsigned long flags; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_GSI, 8062306a36Sopenharmony_ci "LL2 TX CB: gsi_sqcq=%p, gsi_rqcq=%p, gsi_cons=%d, ibcq_comp=%s\n", 8162306a36Sopenharmony_ci dev->gsi_sqcq, dev->gsi_rqcq, qp->sq.gsi_cons, 8262306a36Sopenharmony_ci cq->ibcq.comp_handler ? "Yes" : "No"); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, pkt->header.len, pkt->header.vaddr, 8562306a36Sopenharmony_ci pkt->header.baddr); 8662306a36Sopenharmony_ci kfree(pkt); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 8962306a36Sopenharmony_ci qedr_inc_sw_gsi_cons(&qp->sq); 9062306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (cq->ibcq.comp_handler) 9362306a36Sopenharmony_ci (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic void qedr_ll2_complete_rx_packet(void *cxt, 9762306a36Sopenharmony_ci struct qed_ll2_comp_rx_data *data) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct qedr_dev *dev = (struct qedr_dev *)cxt; 10062306a36Sopenharmony_ci struct qedr_cq *cq = dev->gsi_rqcq; 10162306a36Sopenharmony_ci struct qedr_qp *qp = dev->gsi_qp; 10262306a36Sopenharmony_ci unsigned long flags; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci qp->rqe_wr_id[qp->rq.gsi_cons].rc = data->u.data_length_error ? 10762306a36Sopenharmony_ci -EINVAL : 0; 10862306a36Sopenharmony_ci qp->rqe_wr_id[qp->rq.gsi_cons].vlan = data->vlan; 10962306a36Sopenharmony_ci /* note: length stands for data length i.e. GRH is excluded */ 11062306a36Sopenharmony_ci qp->rqe_wr_id[qp->rq.gsi_cons].sg_list[0].length = 11162306a36Sopenharmony_ci data->length.data_length; 11262306a36Sopenharmony_ci *((u32 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[0]) = 11362306a36Sopenharmony_ci ntohl(data->opaque_data_0); 11462306a36Sopenharmony_ci *((u16 *)&qp->rqe_wr_id[qp->rq.gsi_cons].smac[4]) = 11562306a36Sopenharmony_ci ntohs((u16)data->opaque_data_1); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci qedr_inc_sw_gsi_cons(&qp->rq); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (cq->ibcq.comp_handler) 12262306a36Sopenharmony_ci (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void qedr_ll2_release_rx_packet(void *cxt, u8 connection_handle, 12662306a36Sopenharmony_ci void *cookie, dma_addr_t rx_buf_addr, 12762306a36Sopenharmony_ci bool b_last_packet) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci /* Do nothing... */ 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic void qedr_destroy_gsi_cq(struct qedr_dev *dev, 13362306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct qed_rdma_destroy_cq_in_params iparams; 13662306a36Sopenharmony_ci struct qed_rdma_destroy_cq_out_params oparams; 13762306a36Sopenharmony_ci struct qedr_cq *cq; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci cq = get_qedr_cq(attrs->send_cq); 14062306a36Sopenharmony_ci iparams.icid = cq->icid; 14162306a36Sopenharmony_ci dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); 14262306a36Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &cq->pbl); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci cq = get_qedr_cq(attrs->recv_cq); 14562306a36Sopenharmony_ci /* if a dedicated recv_cq was used, delete it too */ 14662306a36Sopenharmony_ci if (iparams.icid != cq->icid) { 14762306a36Sopenharmony_ci iparams.icid = cq->icid; 14862306a36Sopenharmony_ci dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); 14962306a36Sopenharmony_ci dev->ops->common->chain_free(dev->cdev, &cq->pbl); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline int qedr_check_gsi_qp_attrs(struct qedr_dev *dev, 15462306a36Sopenharmony_ci struct ib_qp_init_attr *attrs) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci if (attrs->cap.max_recv_sge > QEDR_GSI_MAX_RECV_SGE) { 15762306a36Sopenharmony_ci DP_ERR(dev, 15862306a36Sopenharmony_ci " create gsi qp: failed. max_recv_sge is larger the max %d>%d\n", 15962306a36Sopenharmony_ci attrs->cap.max_recv_sge, QEDR_GSI_MAX_RECV_SGE); 16062306a36Sopenharmony_ci return -EINVAL; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (attrs->cap.max_recv_wr > QEDR_GSI_MAX_RECV_WR) { 16462306a36Sopenharmony_ci DP_ERR(dev, 16562306a36Sopenharmony_ci " create gsi qp: failed. max_recv_wr is too large %d>%d\n", 16662306a36Sopenharmony_ci attrs->cap.max_recv_wr, QEDR_GSI_MAX_RECV_WR); 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (attrs->cap.max_send_wr > QEDR_GSI_MAX_SEND_WR) { 17162306a36Sopenharmony_ci DP_ERR(dev, 17262306a36Sopenharmony_ci " create gsi qp: failed. max_send_wr is too large %d>%d\n", 17362306a36Sopenharmony_ci attrs->cap.max_send_wr, QEDR_GSI_MAX_SEND_WR); 17462306a36Sopenharmony_ci return -EINVAL; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int qedr_ll2_post_tx(struct qedr_dev *dev, 18162306a36Sopenharmony_ci struct qed_roce_ll2_packet *pkt) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci enum qed_ll2_roce_flavor_type roce_flavor; 18462306a36Sopenharmony_ci struct qed_ll2_tx_pkt_info ll2_tx_pkt; 18562306a36Sopenharmony_ci int rc; 18662306a36Sopenharmony_ci int i; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci memset(&ll2_tx_pkt, 0, sizeof(ll2_tx_pkt)); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci roce_flavor = (pkt->roce_mode == ROCE_V1) ? 19162306a36Sopenharmony_ci QED_LL2_ROCE : QED_LL2_RROCE; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (pkt->roce_mode == ROCE_V2_IPV4) 19462306a36Sopenharmony_ci ll2_tx_pkt.enable_ip_cksum = 1; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci ll2_tx_pkt.num_of_bds = 1 /* hdr */ + pkt->n_seg; 19762306a36Sopenharmony_ci ll2_tx_pkt.vlan = 0; 19862306a36Sopenharmony_ci ll2_tx_pkt.tx_dest = pkt->tx_dest; 19962306a36Sopenharmony_ci ll2_tx_pkt.qed_roce_flavor = roce_flavor; 20062306a36Sopenharmony_ci ll2_tx_pkt.first_frag = pkt->header.baddr; 20162306a36Sopenharmony_ci ll2_tx_pkt.first_frag_len = pkt->header.len; 20262306a36Sopenharmony_ci ll2_tx_pkt.cookie = pkt; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* tx header */ 20562306a36Sopenharmony_ci rc = dev->ops->ll2_prepare_tx_packet(dev->rdma_ctx, 20662306a36Sopenharmony_ci dev->gsi_ll2_handle, 20762306a36Sopenharmony_ci &ll2_tx_pkt, 1); 20862306a36Sopenharmony_ci if (rc) { 20962306a36Sopenharmony_ci /* TX failed while posting header - release resources */ 21062306a36Sopenharmony_ci dma_free_coherent(&dev->pdev->dev, pkt->header.len, 21162306a36Sopenharmony_ci pkt->header.vaddr, pkt->header.baddr); 21262306a36Sopenharmony_ci kfree(pkt); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci DP_ERR(dev, "roce ll2 tx: header failed (rc=%d)\n", rc); 21562306a36Sopenharmony_ci return rc; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* tx payload */ 21962306a36Sopenharmony_ci for (i = 0; i < pkt->n_seg; i++) { 22062306a36Sopenharmony_ci rc = dev->ops->ll2_set_fragment_of_tx_packet( 22162306a36Sopenharmony_ci dev->rdma_ctx, 22262306a36Sopenharmony_ci dev->gsi_ll2_handle, 22362306a36Sopenharmony_ci pkt->payload[i].baddr, 22462306a36Sopenharmony_ci pkt->payload[i].len); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (rc) { 22762306a36Sopenharmony_ci /* if failed not much to do here, partial packet has 22862306a36Sopenharmony_ci * been posted we can't free memory, will need to wait 22962306a36Sopenharmony_ci * for completion 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci DP_ERR(dev, "ll2 tx: payload failed (rc=%d)\n", rc); 23262306a36Sopenharmony_ci return rc; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int qedr_ll2_stop(struct qedr_dev *dev) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci int rc; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (dev->gsi_ll2_handle == QED_LL2_UNUSED_HANDLE) 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* remove LL2 MAC address filter */ 24762306a36Sopenharmony_ci rc = dev->ops->ll2_set_mac_filter(dev->cdev, 24862306a36Sopenharmony_ci dev->gsi_ll2_mac_address, NULL); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci rc = dev->ops->ll2_terminate_connection(dev->rdma_ctx, 25162306a36Sopenharmony_ci dev->gsi_ll2_handle); 25262306a36Sopenharmony_ci if (rc) 25362306a36Sopenharmony_ci DP_ERR(dev, "Failed to terminate LL2 connection (rc=%d)\n", rc); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci dev->ops->ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci dev->gsi_ll2_handle = QED_LL2_UNUSED_HANDLE; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci return rc; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int qedr_ll2_start(struct qedr_dev *dev, 26362306a36Sopenharmony_ci struct ib_qp_init_attr *attrs, struct qedr_qp *qp) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct qed_ll2_acquire_data data; 26662306a36Sopenharmony_ci struct qed_ll2_cbs cbs; 26762306a36Sopenharmony_ci int rc; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* configure and start LL2 */ 27062306a36Sopenharmony_ci cbs.rx_comp_cb = qedr_ll2_complete_rx_packet; 27162306a36Sopenharmony_ci cbs.tx_comp_cb = qedr_ll2_complete_tx_packet; 27262306a36Sopenharmony_ci cbs.rx_release_cb = qedr_ll2_release_rx_packet; 27362306a36Sopenharmony_ci cbs.tx_release_cb = qedr_ll2_complete_tx_packet; 27462306a36Sopenharmony_ci cbs.cookie = dev; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci memset(&data, 0, sizeof(data)); 27762306a36Sopenharmony_ci data.input.conn_type = QED_LL2_TYPE_ROCE; 27862306a36Sopenharmony_ci data.input.mtu = dev->ndev->mtu; 27962306a36Sopenharmony_ci data.input.rx_num_desc = attrs->cap.max_recv_wr; 28062306a36Sopenharmony_ci data.input.rx_drop_ttl0_flg = true; 28162306a36Sopenharmony_ci data.input.rx_vlan_removal_en = false; 28262306a36Sopenharmony_ci data.input.tx_num_desc = attrs->cap.max_send_wr; 28362306a36Sopenharmony_ci data.input.tx_tc = 0; 28462306a36Sopenharmony_ci data.input.tx_dest = QED_LL2_TX_DEST_NW; 28562306a36Sopenharmony_ci data.input.ai_err_packet_too_big = QED_LL2_DROP_PACKET; 28662306a36Sopenharmony_ci data.input.ai_err_no_buf = QED_LL2_DROP_PACKET; 28762306a36Sopenharmony_ci data.input.gsi_enable = 1; 28862306a36Sopenharmony_ci data.p_connection_handle = &dev->gsi_ll2_handle; 28962306a36Sopenharmony_ci data.cbs = &cbs; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci rc = dev->ops->ll2_acquire_connection(dev->rdma_ctx, &data); 29262306a36Sopenharmony_ci if (rc) { 29362306a36Sopenharmony_ci DP_ERR(dev, 29462306a36Sopenharmony_ci "ll2 start: failed to acquire LL2 connection (rc=%d)\n", 29562306a36Sopenharmony_ci rc); 29662306a36Sopenharmony_ci return rc; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci rc = dev->ops->ll2_establish_connection(dev->rdma_ctx, 30062306a36Sopenharmony_ci dev->gsi_ll2_handle); 30162306a36Sopenharmony_ci if (rc) { 30262306a36Sopenharmony_ci DP_ERR(dev, 30362306a36Sopenharmony_ci "ll2 start: failed to establish LL2 connection (rc=%d)\n", 30462306a36Sopenharmony_ci rc); 30562306a36Sopenharmony_ci goto err1; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci rc = dev->ops->ll2_set_mac_filter(dev->cdev, NULL, dev->ndev->dev_addr); 30962306a36Sopenharmony_ci if (rc) 31062306a36Sopenharmony_ci goto err2; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cierr2: 31562306a36Sopenharmony_ci dev->ops->ll2_terminate_connection(dev->rdma_ctx, dev->gsi_ll2_handle); 31662306a36Sopenharmony_cierr1: 31762306a36Sopenharmony_ci dev->ops->ll2_release_connection(dev->rdma_ctx, dev->gsi_ll2_handle); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return rc; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ciint qedr_create_gsi_qp(struct qedr_dev *dev, struct ib_qp_init_attr *attrs, 32362306a36Sopenharmony_ci struct qedr_qp *qp) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci int rc; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci rc = qedr_check_gsi_qp_attrs(dev, attrs); 32862306a36Sopenharmony_ci if (rc) 32962306a36Sopenharmony_ci return rc; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci rc = qedr_ll2_start(dev, attrs, qp); 33262306a36Sopenharmony_ci if (rc) { 33362306a36Sopenharmony_ci DP_ERR(dev, "create gsi qp: failed on ll2 start. rc=%d\n", rc); 33462306a36Sopenharmony_ci return rc; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* create QP */ 33862306a36Sopenharmony_ci qp->ibqp.qp_num = 1; 33962306a36Sopenharmony_ci qp->rq.max_wr = attrs->cap.max_recv_wr; 34062306a36Sopenharmony_ci qp->sq.max_wr = attrs->cap.max_send_wr; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci qp->rqe_wr_id = kcalloc(qp->rq.max_wr, sizeof(*qp->rqe_wr_id), 34362306a36Sopenharmony_ci GFP_KERNEL); 34462306a36Sopenharmony_ci if (!qp->rqe_wr_id) 34562306a36Sopenharmony_ci goto err; 34662306a36Sopenharmony_ci qp->wqe_wr_id = kcalloc(qp->sq.max_wr, sizeof(*qp->wqe_wr_id), 34762306a36Sopenharmony_ci GFP_KERNEL); 34862306a36Sopenharmony_ci if (!qp->wqe_wr_id) 34962306a36Sopenharmony_ci goto err; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci qedr_store_gsi_qp_cq(dev, qp, attrs); 35262306a36Sopenharmony_ci ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* the GSI CQ is handled by the driver so remove it from the FW */ 35562306a36Sopenharmony_ci qedr_destroy_gsi_cq(dev, attrs); 35662306a36Sopenharmony_ci dev->gsi_rqcq->cq_type = QEDR_CQ_TYPE_GSI; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_GSI, "created GSI QP %p\n", qp); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cierr: 36362306a36Sopenharmony_ci kfree(qp->rqe_wr_id); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci rc = qedr_ll2_stop(dev); 36662306a36Sopenharmony_ci if (rc) 36762306a36Sopenharmony_ci DP_ERR(dev, "create gsi qp: failed destroy on create\n"); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return -ENOMEM; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciint qedr_destroy_gsi_qp(struct qedr_dev *dev) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci return qedr_ll2_stop(dev); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci#define QEDR_MAX_UD_HEADER_SIZE (100) 37862306a36Sopenharmony_ci#define QEDR_GSI_QPN (1) 37962306a36Sopenharmony_cistatic inline int qedr_gsi_build_header(struct qedr_dev *dev, 38062306a36Sopenharmony_ci struct qedr_qp *qp, 38162306a36Sopenharmony_ci const struct ib_send_wr *swr, 38262306a36Sopenharmony_ci struct ib_ud_header *udh, 38362306a36Sopenharmony_ci int *roce_mode) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci bool has_vlan = false, has_grh_ipv6 = true; 38662306a36Sopenharmony_ci struct rdma_ah_attr *ah_attr = &get_qedr_ah(ud_wr(swr)->ah)->attr; 38762306a36Sopenharmony_ci const struct ib_global_route *grh = rdma_ah_read_grh(ah_attr); 38862306a36Sopenharmony_ci const struct ib_gid_attr *sgid_attr = grh->sgid_attr; 38962306a36Sopenharmony_ci int send_size = 0; 39062306a36Sopenharmony_ci u16 vlan_id = 0; 39162306a36Sopenharmony_ci u16 ether_type; 39262306a36Sopenharmony_ci int rc; 39362306a36Sopenharmony_ci int ip_ver = 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci bool has_udp = false; 39662306a36Sopenharmony_ci int i; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci rc = rdma_read_gid_l2_fields(sgid_attr, &vlan_id, NULL); 39962306a36Sopenharmony_ci if (rc) 40062306a36Sopenharmony_ci return rc; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (vlan_id < VLAN_CFI_MASK) 40362306a36Sopenharmony_ci has_vlan = true; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci send_size = 0; 40662306a36Sopenharmony_ci for (i = 0; i < swr->num_sge; ++i) 40762306a36Sopenharmony_ci send_size += swr->sg_list[i].length; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci has_udp = (sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP); 41062306a36Sopenharmony_ci if (!has_udp) { 41162306a36Sopenharmony_ci /* RoCE v1 */ 41262306a36Sopenharmony_ci ether_type = ETH_P_IBOE; 41362306a36Sopenharmony_ci *roce_mode = ROCE_V1; 41462306a36Sopenharmony_ci } else if (ipv6_addr_v4mapped((struct in6_addr *)&sgid_attr->gid)) { 41562306a36Sopenharmony_ci /* RoCE v2 IPv4 */ 41662306a36Sopenharmony_ci ip_ver = 4; 41762306a36Sopenharmony_ci ether_type = ETH_P_IP; 41862306a36Sopenharmony_ci has_grh_ipv6 = false; 41962306a36Sopenharmony_ci *roce_mode = ROCE_V2_IPV4; 42062306a36Sopenharmony_ci } else { 42162306a36Sopenharmony_ci /* RoCE v2 IPv6 */ 42262306a36Sopenharmony_ci ip_ver = 6; 42362306a36Sopenharmony_ci ether_type = ETH_P_IPV6; 42462306a36Sopenharmony_ci *roce_mode = ROCE_V2_IPV6; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci rc = ib_ud_header_init(send_size, false, true, has_vlan, 42862306a36Sopenharmony_ci has_grh_ipv6, ip_ver, has_udp, 0, udh); 42962306a36Sopenharmony_ci if (rc) { 43062306a36Sopenharmony_ci DP_ERR(dev, "gsi post send: failed to init header\n"); 43162306a36Sopenharmony_ci return rc; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* ENET + VLAN headers */ 43562306a36Sopenharmony_ci ether_addr_copy(udh->eth.dmac_h, ah_attr->roce.dmac); 43662306a36Sopenharmony_ci ether_addr_copy(udh->eth.smac_h, dev->ndev->dev_addr); 43762306a36Sopenharmony_ci if (has_vlan) { 43862306a36Sopenharmony_ci udh->eth.type = htons(ETH_P_8021Q); 43962306a36Sopenharmony_ci udh->vlan.tag = htons(vlan_id); 44062306a36Sopenharmony_ci udh->vlan.type = htons(ether_type); 44162306a36Sopenharmony_ci } else { 44262306a36Sopenharmony_ci udh->eth.type = htons(ether_type); 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* BTH */ 44662306a36Sopenharmony_ci udh->bth.solicited_event = !!(swr->send_flags & IB_SEND_SOLICITED); 44762306a36Sopenharmony_ci udh->bth.pkey = QEDR_ROCE_PKEY_DEFAULT; 44862306a36Sopenharmony_ci udh->bth.destination_qpn = htonl(ud_wr(swr)->remote_qpn); 44962306a36Sopenharmony_ci udh->bth.psn = htonl((qp->sq_psn++) & ((1 << 24) - 1)); 45062306a36Sopenharmony_ci udh->bth.opcode = IB_OPCODE_UD_SEND_ONLY; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* DETH */ 45362306a36Sopenharmony_ci udh->deth.qkey = htonl(0x80010000); 45462306a36Sopenharmony_ci udh->deth.source_qpn = htonl(QEDR_GSI_QPN); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (has_grh_ipv6) { 45762306a36Sopenharmony_ci /* GRH / IPv6 header */ 45862306a36Sopenharmony_ci udh->grh.traffic_class = grh->traffic_class; 45962306a36Sopenharmony_ci udh->grh.flow_label = grh->flow_label; 46062306a36Sopenharmony_ci udh->grh.hop_limit = grh->hop_limit; 46162306a36Sopenharmony_ci udh->grh.destination_gid = grh->dgid; 46262306a36Sopenharmony_ci memcpy(&udh->grh.source_gid.raw, sgid_attr->gid.raw, 46362306a36Sopenharmony_ci sizeof(udh->grh.source_gid.raw)); 46462306a36Sopenharmony_ci } else { 46562306a36Sopenharmony_ci /* IPv4 header */ 46662306a36Sopenharmony_ci u32 ipv4_addr; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci udh->ip4.protocol = IPPROTO_UDP; 46962306a36Sopenharmony_ci udh->ip4.tos = htonl(grh->flow_label); 47062306a36Sopenharmony_ci udh->ip4.frag_off = htons(IP_DF); 47162306a36Sopenharmony_ci udh->ip4.ttl = grh->hop_limit; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci ipv4_addr = qedr_get_ipv4_from_gid(sgid_attr->gid.raw); 47462306a36Sopenharmony_ci udh->ip4.saddr = ipv4_addr; 47562306a36Sopenharmony_ci ipv4_addr = qedr_get_ipv4_from_gid(grh->dgid.raw); 47662306a36Sopenharmony_ci udh->ip4.daddr = ipv4_addr; 47762306a36Sopenharmony_ci /* note: checksum is calculated by the device */ 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* UDP */ 48162306a36Sopenharmony_ci if (has_udp) { 48262306a36Sopenharmony_ci udh->udp.sport = htons(QEDR_ROCE_V2_UDP_SPORT); 48362306a36Sopenharmony_ci udh->udp.dport = htons(ROCE_V2_UDP_DPORT); 48462306a36Sopenharmony_ci udh->udp.csum = 0; 48562306a36Sopenharmony_ci /* UDP length is untouched hence is zero */ 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci return 0; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic inline int qedr_gsi_build_packet(struct qedr_dev *dev, 49162306a36Sopenharmony_ci struct qedr_qp *qp, 49262306a36Sopenharmony_ci const struct ib_send_wr *swr, 49362306a36Sopenharmony_ci struct qed_roce_ll2_packet **p_packet) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci u8 ud_header_buffer[QEDR_MAX_UD_HEADER_SIZE]; 49662306a36Sopenharmony_ci struct qed_roce_ll2_packet *packet; 49762306a36Sopenharmony_ci struct pci_dev *pdev = dev->pdev; 49862306a36Sopenharmony_ci int roce_mode, header_size; 49962306a36Sopenharmony_ci struct ib_ud_header udh; 50062306a36Sopenharmony_ci int i, rc; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci *p_packet = NULL; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci rc = qedr_gsi_build_header(dev, qp, swr, &udh, &roce_mode); 50562306a36Sopenharmony_ci if (rc) 50662306a36Sopenharmony_ci return rc; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci header_size = ib_ud_header_pack(&udh, &ud_header_buffer); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci packet = kzalloc(sizeof(*packet), GFP_ATOMIC); 51162306a36Sopenharmony_ci if (!packet) 51262306a36Sopenharmony_ci return -ENOMEM; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci packet->header.vaddr = dma_alloc_coherent(&pdev->dev, header_size, 51562306a36Sopenharmony_ci &packet->header.baddr, 51662306a36Sopenharmony_ci GFP_ATOMIC); 51762306a36Sopenharmony_ci if (!packet->header.vaddr) { 51862306a36Sopenharmony_ci kfree(packet); 51962306a36Sopenharmony_ci return -ENOMEM; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h)) 52362306a36Sopenharmony_ci packet->tx_dest = QED_LL2_TX_DEST_LB; 52462306a36Sopenharmony_ci else 52562306a36Sopenharmony_ci packet->tx_dest = QED_LL2_TX_DEST_NW; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci packet->roce_mode = roce_mode; 52862306a36Sopenharmony_ci memcpy(packet->header.vaddr, ud_header_buffer, header_size); 52962306a36Sopenharmony_ci packet->header.len = header_size; 53062306a36Sopenharmony_ci packet->n_seg = swr->num_sge; 53162306a36Sopenharmony_ci for (i = 0; i < packet->n_seg; i++) { 53262306a36Sopenharmony_ci packet->payload[i].baddr = swr->sg_list[i].addr; 53362306a36Sopenharmony_ci packet->payload[i].len = swr->sg_list[i].length; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci *p_packet = packet; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ciint qedr_gsi_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr, 54262306a36Sopenharmony_ci const struct ib_send_wr **bad_wr) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct qed_roce_ll2_packet *pkt = NULL; 54562306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 54662306a36Sopenharmony_ci struct qedr_dev *dev = qp->dev; 54762306a36Sopenharmony_ci unsigned long flags; 54862306a36Sopenharmony_ci int rc; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (qp->state != QED_ROCE_QP_STATE_RTS) { 55162306a36Sopenharmony_ci *bad_wr = wr; 55262306a36Sopenharmony_ci DP_ERR(dev, 55362306a36Sopenharmony_ci "gsi post recv: failed to post rx buffer. state is %d and not QED_ROCE_QP_STATE_RTS\n", 55462306a36Sopenharmony_ci qp->state); 55562306a36Sopenharmony_ci return -EINVAL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (wr->num_sge > RDMA_MAX_SGE_PER_SQ_WQE) { 55962306a36Sopenharmony_ci DP_ERR(dev, "gsi post send: num_sge is too large (%d>%d)\n", 56062306a36Sopenharmony_ci wr->num_sge, RDMA_MAX_SGE_PER_SQ_WQE); 56162306a36Sopenharmony_ci rc = -EINVAL; 56262306a36Sopenharmony_ci goto err; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (wr->opcode != IB_WR_SEND) { 56662306a36Sopenharmony_ci DP_ERR(dev, 56762306a36Sopenharmony_ci "gsi post send: failed due to unsupported opcode %d\n", 56862306a36Sopenharmony_ci wr->opcode); 56962306a36Sopenharmony_ci rc = -EINVAL; 57062306a36Sopenharmony_ci goto err; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci rc = qedr_gsi_build_packet(dev, qp, wr, &pkt); 57662306a36Sopenharmony_ci if (rc) { 57762306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 57862306a36Sopenharmony_ci goto err; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci rc = qedr_ll2_post_tx(dev, pkt); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (!rc) { 58462306a36Sopenharmony_ci qp->wqe_wr_id[qp->sq.prod].wr_id = wr->wr_id; 58562306a36Sopenharmony_ci qedr_inc_sw_prod(&qp->sq); 58662306a36Sopenharmony_ci DP_DEBUG(qp->dev, QEDR_MSG_GSI, 58762306a36Sopenharmony_ci "gsi post send: opcode=%d, wr_id=%llx\n", wr->opcode, 58862306a36Sopenharmony_ci wr->wr_id); 58962306a36Sopenharmony_ci } else { 59062306a36Sopenharmony_ci DP_ERR(dev, "gsi post send: failed to transmit (rc=%d)\n", rc); 59162306a36Sopenharmony_ci rc = -EAGAIN; 59262306a36Sopenharmony_ci *bad_wr = wr; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci if (wr->next) { 59862306a36Sopenharmony_ci DP_ERR(dev, 59962306a36Sopenharmony_ci "gsi post send: failed second WR. Only one WR may be passed at a time\n"); 60062306a36Sopenharmony_ci *bad_wr = wr->next; 60162306a36Sopenharmony_ci rc = -EINVAL; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return rc; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cierr: 60762306a36Sopenharmony_ci *bad_wr = wr; 60862306a36Sopenharmony_ci return rc; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ciint qedr_gsi_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr, 61262306a36Sopenharmony_ci const struct ib_recv_wr **bad_wr) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibqp->device); 61562306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 61662306a36Sopenharmony_ci unsigned long flags; 61762306a36Sopenharmony_ci int rc = 0; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if ((qp->state != QED_ROCE_QP_STATE_RTR) && 62062306a36Sopenharmony_ci (qp->state != QED_ROCE_QP_STATE_RTS)) { 62162306a36Sopenharmony_ci *bad_wr = wr; 62262306a36Sopenharmony_ci DP_ERR(dev, 62362306a36Sopenharmony_ci "gsi post recv: failed to post rx buffer. state is %d and not QED_ROCE_QP_STATE_RTR/S\n", 62462306a36Sopenharmony_ci qp->state); 62562306a36Sopenharmony_ci return -EINVAL; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci spin_lock_irqsave(&qp->q_lock, flags); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci while (wr) { 63162306a36Sopenharmony_ci if (wr->num_sge > QEDR_GSI_MAX_RECV_SGE) { 63262306a36Sopenharmony_ci DP_ERR(dev, 63362306a36Sopenharmony_ci "gsi post recv: failed to post rx buffer. too many sges %d>%d\n", 63462306a36Sopenharmony_ci wr->num_sge, QEDR_GSI_MAX_RECV_SGE); 63562306a36Sopenharmony_ci goto err; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci rc = dev->ops->ll2_post_rx_buffer(dev->rdma_ctx, 63962306a36Sopenharmony_ci dev->gsi_ll2_handle, 64062306a36Sopenharmony_ci wr->sg_list[0].addr, 64162306a36Sopenharmony_ci wr->sg_list[0].length, 64262306a36Sopenharmony_ci NULL /* cookie */, 64362306a36Sopenharmony_ci 1 /* notify_fw */); 64462306a36Sopenharmony_ci if (rc) { 64562306a36Sopenharmony_ci DP_ERR(dev, 64662306a36Sopenharmony_ci "gsi post recv: failed to post rx buffer (rc=%d)\n", 64762306a36Sopenharmony_ci rc); 64862306a36Sopenharmony_ci goto err; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci memset(&qp->rqe_wr_id[qp->rq.prod], 0, 65262306a36Sopenharmony_ci sizeof(qp->rqe_wr_id[qp->rq.prod])); 65362306a36Sopenharmony_ci qp->rqe_wr_id[qp->rq.prod].sg_list[0] = wr->sg_list[0]; 65462306a36Sopenharmony_ci qp->rqe_wr_id[qp->rq.prod].wr_id = wr->wr_id; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci qedr_inc_sw_prod(&qp->rq); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci wr = wr->next; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci return rc; 66462306a36Sopenharmony_cierr: 66562306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->q_lock, flags); 66662306a36Sopenharmony_ci *bad_wr = wr; 66762306a36Sopenharmony_ci return -ENOMEM; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ciint qedr_gsi_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibcq->device); 67362306a36Sopenharmony_ci struct qedr_cq *cq = get_qedr_cq(ibcq); 67462306a36Sopenharmony_ci struct qedr_qp *qp = dev->gsi_qp; 67562306a36Sopenharmony_ci unsigned long flags; 67662306a36Sopenharmony_ci u16 vlan_id; 67762306a36Sopenharmony_ci int i = 0; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, flags); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci while (i < num_entries && qp->rq.cons != qp->rq.gsi_cons) { 68262306a36Sopenharmony_ci memset(&wc[i], 0, sizeof(*wc)); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci wc[i].qp = &qp->ibqp; 68562306a36Sopenharmony_ci wc[i].wr_id = qp->rqe_wr_id[qp->rq.cons].wr_id; 68662306a36Sopenharmony_ci wc[i].opcode = IB_WC_RECV; 68762306a36Sopenharmony_ci wc[i].pkey_index = 0; 68862306a36Sopenharmony_ci wc[i].status = (qp->rqe_wr_id[qp->rq.cons].rc) ? 68962306a36Sopenharmony_ci IB_WC_GENERAL_ERR : IB_WC_SUCCESS; 69062306a36Sopenharmony_ci /* 0 - currently only one recv sg is supported */ 69162306a36Sopenharmony_ci wc[i].byte_len = qp->rqe_wr_id[qp->rq.cons].sg_list[0].length; 69262306a36Sopenharmony_ci wc[i].wc_flags |= IB_WC_GRH | IB_WC_IP_CSUM_OK; 69362306a36Sopenharmony_ci ether_addr_copy(wc[i].smac, qp->rqe_wr_id[qp->rq.cons].smac); 69462306a36Sopenharmony_ci wc[i].wc_flags |= IB_WC_WITH_SMAC; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci vlan_id = qp->rqe_wr_id[qp->rq.cons].vlan & 69762306a36Sopenharmony_ci VLAN_VID_MASK; 69862306a36Sopenharmony_ci if (vlan_id) { 69962306a36Sopenharmony_ci wc[i].wc_flags |= IB_WC_WITH_VLAN; 70062306a36Sopenharmony_ci wc[i].vlan_id = vlan_id; 70162306a36Sopenharmony_ci wc[i].sl = (qp->rqe_wr_id[qp->rq.cons].vlan & 70262306a36Sopenharmony_ci VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci qedr_inc_sw_cons(&qp->rq); 70662306a36Sopenharmony_ci i++; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci while (i < num_entries && qp->sq.cons != qp->sq.gsi_cons) { 71062306a36Sopenharmony_ci memset(&wc[i], 0, sizeof(*wc)); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci wc[i].qp = &qp->ibqp; 71362306a36Sopenharmony_ci wc[i].wr_id = qp->wqe_wr_id[qp->sq.cons].wr_id; 71462306a36Sopenharmony_ci wc[i].opcode = IB_WC_SEND; 71562306a36Sopenharmony_ci wc[i].status = IB_WC_SUCCESS; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci qedr_inc_sw_cons(&qp->sq); 71862306a36Sopenharmony_ci i++; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_GSI, 72462306a36Sopenharmony_ci "gsi poll_cq: requested entries=%d, actual=%d, qp->rq.cons=%d, qp->rq.gsi_cons=%x, qp->sq.cons=%d, qp->sq.gsi_cons=%d, qp_num=%d\n", 72562306a36Sopenharmony_ci num_entries, i, qp->rq.cons, qp->rq.gsi_cons, qp->sq.cons, 72662306a36Sopenharmony_ci qp->sq.gsi_cons, qp->ibqp.qp_num); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return i; 72962306a36Sopenharmony_ci} 730