/drivers/infiniband/hw/cxgb4/qp.c
C | 1576 lines | 1374 code | 131 blank | 71 comment | 166 complexity | e02589e953864a5e800e7058789df52b MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
- /*
- * Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
- #include "iw_cxgb4.h"
- static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
- struct c4iw_dev_ucontext *uctx)
- {
- /*
- * uP clears EQ contexts when the connection exits rdma mode,
- * so no need to post a RESET WR for these EQs.
- */
- dma_free_coherent(&(rdev->lldi.pdev->dev),
- wq->rq.memsize, wq->rq.queue,
- dma_unmap_addr(&wq->rq, mapping));
- dma_free_coherent(&(rdev->lldi.pdev->dev),
- wq->sq.memsize, wq->sq.queue,
- dma_unmap_addr(&wq->sq, mapping));
- c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
- kfree(wq->rq.sw_rq);
- kfree(wq->sq.sw_sq);
- c4iw_put_qpid(rdev, wq->rq.qid, uctx);
- c4iw_put_qpid(rdev, wq->sq.qid, uctx);
- return 0;
- }
- static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
- struct t4_cq *rcq, struct t4_cq *scq,
- struct c4iw_dev_ucontext *uctx)
- {
- int user = (uctx != &rdev->uctx);
- struct fw_ri_res_wr *res_wr;
- struct fw_ri_res *res;
- int wr_len;
- struct c4iw_wr_wait wr_wait;
- struct sk_buff *skb;
- int ret;
- int eqsize;
- wq->sq.qid = c4iw_get_qpid(rdev, uctx);
- if (!wq->sq.qid)
- return -ENOMEM;
- wq->rq.qid = c4iw_get_qpid(rdev, uctx);
- if (!wq->rq.qid)
- goto err1;
- if (!user) {
- wq->sq.sw_sq = kzalloc(wq->sq.size * sizeof *wq->sq.sw_sq,
- GFP_KERNEL);
- if (!wq->sq.sw_sq)
- goto err2;
- wq->rq.sw_rq = kzalloc(wq->rq.size * sizeof *wq->rq.sw_rq,
- GFP_KERNEL);
- if (!wq->rq.sw_rq)
- goto err3;
- }
- /*
- * RQT must be a power of 2.
- */
- wq->rq.rqt_size = roundup_pow_of_two(wq->rq.size);
- wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size);
- if (!wq->rq.rqt_hwaddr)
- goto err4;
- wq->sq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
- wq->sq.memsize, &(wq->sq.dma_addr),
- GFP_KERNEL);
- if (!wq->sq.queue)
- goto err5;
- memset(wq->sq.queue, 0, wq->sq.memsize);
- dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
- wq->rq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
- wq->rq.memsize, &(wq->rq.dma_addr),
- GFP_KERNEL);
- if (!wq->rq.queue)
- goto err6;
- PDBG("%s sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
- __func__, wq->sq.queue,
- (unsigned long long)virt_to_phys(wq->sq.queue),
- wq->rq.queue,
- (unsigned long long)virt_to_phys(wq->rq.queue));
- memset(wq->rq.queue, 0, wq->rq.memsize);
- dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr);
- wq->db = rdev->lldi.db_reg;
- wq->gts = rdev->lldi.gts_reg;
- if (user) {
- wq->sq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) +
- (wq->sq.qid << rdev->qpshift);
- wq->sq.udb &= PAGE_MASK;
- wq->rq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) +
- (wq->rq.qid << rdev->qpshift);
- wq->rq.udb &= PAGE_MASK;
- }
- wq->rdev = rdev;
- wq->rq.msn = 1;
- /* build fw_ri_res_wr */
- wr_len = sizeof *res_wr + 2 * sizeof *res;
- skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
- if (!skb) {
- ret = -ENOMEM;
- goto err7;
- }
- set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
- res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
- memset(res_wr, 0, wr_len);
- res_wr->op_nres = cpu_to_be32(
- FW_WR_OP(FW_RI_RES_WR) |
- V_FW_RI_RES_WR_NRES(2) |
- FW_WR_COMPL(1));
- res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
- res_wr->cookie = (u64)&wr_wait;
- res = res_wr->res;
- res->u.sqrq.restype = FW_RI_RES_TYPE_SQ;
- res->u.sqrq.op = FW_RI_RES_OP_WRITE;
- /*
- * eqsize is the number of 64B entries plus the status page size.
- */
- eqsize = wq->sq.size * T4_SQ_NUM_SLOTS + T4_EQ_STATUS_ENTRIES;
- res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
- V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */
- V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */
- V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */
- V_FW_RI_RES_WR_IQID(scq->cqid));
- res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
- V_FW_RI_RES_WR_DCAEN(0) |
- V_FW_RI_RES_WR_DCACPU(0) |
- V_FW_RI_RES_WR_FBMIN(3) |
- V_FW_RI_RES_WR_FBMAX(3) |
- V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
- V_FW_RI_RES_WR_CIDXFTHRESH(0) |
- V_FW_RI_RES_WR_EQSIZE(eqsize));
- res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid);
- res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr);
- res++;
- res->u.sqrq.restype = FW_RI_RES_TYPE_RQ;
- res->u.sqrq.op = FW_RI_RES_OP_WRITE;
- /*
- * eqsize is the number of 64B entries plus the status page size.
- */
- eqsize = wq->rq.size * T4_RQ_NUM_SLOTS + T4_EQ_STATUS_ENTRIES;
- res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
- V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */
- V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */
- V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */
- V_FW_RI_RES_WR_IQID(rcq->cqid));
- res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
- V_FW_RI_RES_WR_DCAEN(0) |
- V_FW_RI_RES_WR_DCACPU(0) |
- V_FW_RI_RES_WR_FBMIN(3) |
- V_FW_RI_RES_WR_FBMAX(3) |
- V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
- V_FW_RI_RES_WR_CIDXFTHRESH(0) |
- V_FW_RI_RES_WR_EQSIZE(eqsize));
- res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid);
- res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
- c4iw_init_wr_wait(&wr_wait);
- ret = c4iw_ofld_send(rdev, skb);
- if (ret)
- goto err7;
- wait_event_timeout(wr_wait.wait, wr_wait.done, C4IW_WR_TO);
- if (!wr_wait.done) {
- printk(KERN_ERR MOD "Device %s not responding!\n",
- pci_name(rdev->lldi.pdev));
- rdev->flags = T4_FATAL_ERROR;
- ret = -EIO;
- } else
- ret = wr_wait.ret;
- if (ret)
- goto err7;
- PDBG("%s sqid 0x%x rqid 0x%x kdb 0x%p squdb 0x%llx rqudb 0x%llx\n",
- __func__, wq->sq.qid, wq->rq.qid, wq->db,
- (unsigned long long)wq->sq.udb, (unsigned long long)wq->rq.udb);
- return 0;
- err7:
- dma_free_coherent(&(rdev->lldi.pdev->dev),
- wq->rq.memsize, wq->rq.queue,
- dma_unmap_addr(&wq->rq, mapping));
- err6:
- dma_free_coherent(&(rdev->lldi.pdev->dev),
- wq->sq.memsize, wq->sq.queue,
- dma_unmap_addr(&wq->sq, mapping));
- err5:
- c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
- err4:
- kfree(wq->rq.sw_rq);
- err3:
- kfree(wq->sq.sw_sq);
- err2:
- c4iw_put_qpid(rdev, wq->rq.qid, uctx);
- err1:
- c4iw_put_qpid(rdev, wq->sq.qid, uctx);
- return -ENOMEM;
- }
- static int build_rdma_send(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16)
- {
- int i;
- u32 plen;
- int size;
- u8 *datap;
- if (wr->num_sge > T4_MAX_SEND_SGE)
- return -EINVAL;
- switch (wr->opcode) {
-