Path: blob/master/drivers/infiniband/hw/cxgb3/iwch_qp.c
15112 views
/*1* Copyright (c) 2006 Chelsio, Inc. All rights reserved.2*3* This software is available to you under a choice of one of two4* licenses. You may choose to be licensed under the terms of the GNU5* General Public License (GPL) Version 2, available from the file6* COPYING in the main directory of this source tree, or the7* OpenIB.org BSD license below:8*9* Redistribution and use in source and binary forms, with or10* without modification, are permitted provided that the following11* conditions are met:12*13* - Redistributions of source code must retain the above14* copyright notice, this list of conditions and the following15* disclaimer.16*17* - Redistributions in binary form must reproduce the above18* copyright notice, this list of conditions and the following19* disclaimer in the documentation and/or other materials20* provided with the distribution.21*22* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,23* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF24* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND25* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS26* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN27* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN28* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE29* SOFTWARE.30*/31#include <linux/sched.h>32#include <linux/gfp.h>33#include "iwch_provider.h"34#include "iwch.h"35#include "iwch_cm.h"36#include "cxio_hal.h"37#include "cxio_resource.h"3839#define NO_SUPPORT -14041static int build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr,42u8 * flit_cnt)43{44int i;45u32 plen;4647switch (wr->opcode) {48case IB_WR_SEND:49if (wr->send_flags & IB_SEND_SOLICITED)50wqe->send.rdmaop = T3_SEND_WITH_SE;51else52wqe->send.rdmaop = T3_SEND;53wqe->send.rem_stag = 0;54break;55case IB_WR_SEND_WITH_INV:56if (wr->send_flags & IB_SEND_SOLICITED)57wqe->send.rdmaop = T3_SEND_WITH_SE_INV;58else59wqe->send.rdmaop = T3_SEND_WITH_INV;60wqe->send.rem_stag = cpu_to_be32(wr->ex.invalidate_rkey);61break;62default:63return -EINVAL;64}65if (wr->num_sge > T3_MAX_SGE)66return -EINVAL;67wqe->send.reserved[0] = 0;68wqe->send.reserved[1] = 0;69wqe->send.reserved[2] = 0;70plen = 0;71for (i = 0; i < wr->num_sge; i++) {72if ((plen + wr->sg_list[i].length) < plen)73return -EMSGSIZE;7475plen += wr->sg_list[i].length;76wqe->send.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);77wqe->send.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);78wqe->send.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);79}80wqe->send.num_sgle = cpu_to_be32(wr->num_sge);81*flit_cnt = 4 + ((wr->num_sge) << 1);82wqe->send.plen = cpu_to_be32(plen);83return 0;84}8586static int build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr,87u8 *flit_cnt)88{89int i;90u32 plen;91if (wr->num_sge > T3_MAX_SGE)92return -EINVAL;93wqe->write.rdmaop = T3_RDMA_WRITE;94wqe->write.reserved[0] = 0;95wqe->write.reserved[1] = 0;96wqe->write.reserved[2] = 0;97wqe->write.stag_sink = cpu_to_be32(wr->wr.rdma.rkey);98wqe->write.to_sink = cpu_to_be64(wr->wr.rdma.remote_addr);99100if (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {101plen = 4;102wqe->write.sgl[0].stag = wr->ex.imm_data;103wqe->write.sgl[0].len = cpu_to_be32(0);104wqe->write.num_sgle = cpu_to_be32(0);105*flit_cnt = 6;106} else {107plen = 0;108for (i = 0; i < wr->num_sge; i++) {109if ((plen + wr->sg_list[i].length) < plen) {110return -EMSGSIZE;111}112plen += wr->sg_list[i].length;113wqe->write.sgl[i].stag =114cpu_to_be32(wr->sg_list[i].lkey);115wqe->write.sgl[i].len =116cpu_to_be32(wr->sg_list[i].length);117wqe->write.sgl[i].to =118cpu_to_be64(wr->sg_list[i].addr);119}120wqe->write.num_sgle = cpu_to_be32(wr->num_sge);121*flit_cnt = 5 + ((wr->num_sge) << 1);122}123wqe->write.plen = cpu_to_be32(plen);124return 0;125}126127static int build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr,128u8 *flit_cnt)129{130if (wr->num_sge > 1)131return -EINVAL;132wqe->read.rdmaop = T3_READ_REQ;133if (wr->opcode == IB_WR_RDMA_READ_WITH_INV)134wqe->read.local_inv = 1;135else136wqe->read.local_inv = 0;137wqe->read.reserved[0] = 0;138wqe->read.reserved[1] = 0;139wqe->read.rem_stag = cpu_to_be32(wr->wr.rdma.rkey);140wqe->read.rem_to = cpu_to_be64(wr->wr.rdma.remote_addr);141wqe->read.local_stag = cpu_to_be32(wr->sg_list[0].lkey);142wqe->read.local_len = cpu_to_be32(wr->sg_list[0].length);143wqe->read.local_to = cpu_to_be64(wr->sg_list[0].addr);144*flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3;145return 0;146}147148static int build_fastreg(union t3_wr *wqe, struct ib_send_wr *wr,149u8 *flit_cnt, int *wr_cnt, struct t3_wq *wq)150{151int i;152__be64 *p;153154if (wr->wr.fast_reg.page_list_len > T3_MAX_FASTREG_DEPTH)155return -EINVAL;156*wr_cnt = 1;157wqe->fastreg.stag = cpu_to_be32(wr->wr.fast_reg.rkey);158wqe->fastreg.len = cpu_to_be32(wr->wr.fast_reg.length);159wqe->fastreg.va_base_hi = cpu_to_be32(wr->wr.fast_reg.iova_start >> 32);160wqe->fastreg.va_base_lo_fbo =161cpu_to_be32(wr->wr.fast_reg.iova_start & 0xffffffff);162wqe->fastreg.page_type_perms = cpu_to_be32(163V_FR_PAGE_COUNT(wr->wr.fast_reg.page_list_len) |164V_FR_PAGE_SIZE(wr->wr.fast_reg.page_shift-12) |165V_FR_TYPE(TPT_VATO) |166V_FR_PERMS(iwch_ib_to_tpt_access(wr->wr.fast_reg.access_flags)));167p = &wqe->fastreg.pbl_addrs[0];168for (i = 0; i < wr->wr.fast_reg.page_list_len; i++, p++) {169170/* If we need a 2nd WR, then set it up */171if (i == T3_MAX_FASTREG_FRAG) {172*wr_cnt = 2;173wqe = (union t3_wr *)(wq->queue +174Q_PTR2IDX((wq->wptr+1), wq->size_log2));175build_fw_riwrh((void *)wqe, T3_WR_FASTREG, 0,176Q_GENBIT(wq->wptr + 1, wq->size_log2),1770, 1 + wr->wr.fast_reg.page_list_len - T3_MAX_FASTREG_FRAG,178T3_EOP);179180p = &wqe->pbl_frag.pbl_addrs[0];181}182*p = cpu_to_be64((u64)wr->wr.fast_reg.page_list->page_list[i]);183}184*flit_cnt = 5 + wr->wr.fast_reg.page_list_len;185if (*flit_cnt > 15)186*flit_cnt = 15;187return 0;188}189190static int build_inv_stag(union t3_wr *wqe, struct ib_send_wr *wr,191u8 *flit_cnt)192{193wqe->local_inv.stag = cpu_to_be32(wr->ex.invalidate_rkey);194wqe->local_inv.reserved = 0;195*flit_cnt = sizeof(struct t3_local_inv_wr) >> 3;196return 0;197}198199static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list,200u32 num_sgle, u32 * pbl_addr, u8 * page_size)201{202int i;203struct iwch_mr *mhp;204u64 offset;205for (i = 0; i < num_sgle; i++) {206207mhp = get_mhp(rhp, (sg_list[i].lkey) >> 8);208if (!mhp) {209PDBG("%s %d\n", __func__, __LINE__);210return -EIO;211}212if (!mhp->attr.state) {213PDBG("%s %d\n", __func__, __LINE__);214return -EIO;215}216if (mhp->attr.zbva) {217PDBG("%s %d\n", __func__, __LINE__);218return -EIO;219}220221if (sg_list[i].addr < mhp->attr.va_fbo) {222PDBG("%s %d\n", __func__, __LINE__);223return -EINVAL;224}225if (sg_list[i].addr + ((u64) sg_list[i].length) <226sg_list[i].addr) {227PDBG("%s %d\n", __func__, __LINE__);228return -EINVAL;229}230if (sg_list[i].addr + ((u64) sg_list[i].length) >231mhp->attr.va_fbo + ((u64) mhp->attr.len)) {232PDBG("%s %d\n", __func__, __LINE__);233return -EINVAL;234}235offset = sg_list[i].addr - mhp->attr.va_fbo;236offset += mhp->attr.va_fbo &237((1UL << (12 + mhp->attr.page_size)) - 1);238pbl_addr[i] = ((mhp->attr.pbl_addr -239rhp->rdev.rnic_info.pbl_base) >> 3) +240(offset >> (12 + mhp->attr.page_size));241page_size[i] = mhp->attr.page_size;242}243return 0;244}245246static int build_rdma_recv(struct iwch_qp *qhp, union t3_wr *wqe,247struct ib_recv_wr *wr)248{249int i, err = 0;250u32 pbl_addr[T3_MAX_SGE];251u8 page_size[T3_MAX_SGE];252253err = iwch_sgl2pbl_map(qhp->rhp, wr->sg_list, wr->num_sge, pbl_addr,254page_size);255if (err)256return err;257wqe->recv.pagesz[0] = page_size[0];258wqe->recv.pagesz[1] = page_size[1];259wqe->recv.pagesz[2] = page_size[2];260wqe->recv.pagesz[3] = page_size[3];261wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);262for (i = 0; i < wr->num_sge; i++) {263wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey);264wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);265266/* to in the WQE == the offset into the page */267wqe->recv.sgl[i].to = cpu_to_be64(((u32)wr->sg_list[i].addr) &268((1UL << (12 + page_size[i])) - 1));269270/* pbl_addr is the adapters address in the PBL */271wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]);272}273for (; i < T3_MAX_SGE; i++) {274wqe->recv.sgl[i].stag = 0;275wqe->recv.sgl[i].len = 0;276wqe->recv.sgl[i].to = 0;277wqe->recv.pbl_addr[i] = 0;278}279qhp->wq.rq[Q_PTR2IDX(qhp->wq.rq_wptr,280qhp->wq.rq_size_log2)].wr_id = wr->wr_id;281qhp->wq.rq[Q_PTR2IDX(qhp->wq.rq_wptr,282qhp->wq.rq_size_log2)].pbl_addr = 0;283return 0;284}285286static int build_zero_stag_recv(struct iwch_qp *qhp, union t3_wr *wqe,287struct ib_recv_wr *wr)288{289int i;290u32 pbl_addr;291u32 pbl_offset;292293294/*295* The T3 HW requires the PBL in the HW recv descriptor to reference296* a PBL entry. So we allocate the max needed PBL memory here and pass297* it to the uP in the recv WR. The uP will build the PBL and setup298* the HW recv descriptor.299*/300pbl_addr = cxio_hal_pblpool_alloc(&qhp->rhp->rdev, T3_STAG0_PBL_SIZE);301if (!pbl_addr)302return -ENOMEM;303304/*305* Compute the 8B aligned offset.306*/307pbl_offset = (pbl_addr - qhp->rhp->rdev.rnic_info.pbl_base) >> 3;308309wqe->recv.num_sgle = cpu_to_be32(wr->num_sge);310311for (i = 0; i < wr->num_sge; i++) {312313/*314* Use a 128MB page size. This and an imposed 128MB315* sge length limit allows us to require only a 2-entry HW316* PBL for each SGE. This restriction is acceptable since317* since it is not possible to allocate 128MB of contiguous318* DMA coherent memory!319*/320if (wr->sg_list[i].length > T3_STAG0_MAX_PBE_LEN)321return -EINVAL;322wqe->recv.pagesz[i] = T3_STAG0_PAGE_SHIFT;323324/*325* T3 restricts a recv to all zero-stag or all non-zero-stag.326*/327if (wr->sg_list[i].lkey != 0)328return -EINVAL;329wqe->recv.sgl[i].stag = 0;330wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length);331wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr);332wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_offset);333pbl_offset += 2;334}335for (; i < T3_MAX_SGE; i++) {336wqe->recv.pagesz[i] = 0;337wqe->recv.sgl[i].stag = 0;338wqe->recv.sgl[i].len = 0;339wqe->recv.sgl[i].to = 0;340wqe->recv.pbl_addr[i] = 0;341}342qhp->wq.rq[Q_PTR2IDX(qhp->wq.rq_wptr,343qhp->wq.rq_size_log2)].wr_id = wr->wr_id;344qhp->wq.rq[Q_PTR2IDX(qhp->wq.rq_wptr,345qhp->wq.rq_size_log2)].pbl_addr = pbl_addr;346return 0;347}348349int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,350struct ib_send_wr **bad_wr)351{352int err = 0;353u8 uninitialized_var(t3_wr_flit_cnt);354enum t3_wr_opcode t3_wr_opcode = 0;355enum t3_wr_flags t3_wr_flags;356struct iwch_qp *qhp;357u32 idx;358union t3_wr *wqe;359u32 num_wrs;360unsigned long flag;361struct t3_swsq *sqp;362int wr_cnt = 1;363364qhp = to_iwch_qp(ibqp);365spin_lock_irqsave(&qhp->lock, flag);366if (qhp->attr.state > IWCH_QP_STATE_RTS) {367spin_unlock_irqrestore(&qhp->lock, flag);368err = -EINVAL;369goto out;370}371num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr,372qhp->wq.sq_size_log2);373if (num_wrs == 0) {374spin_unlock_irqrestore(&qhp->lock, flag);375err = -ENOMEM;376goto out;377}378while (wr) {379if (num_wrs == 0) {380err = -ENOMEM;381break;382}383idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2);384wqe = (union t3_wr *) (qhp->wq.queue + idx);385t3_wr_flags = 0;386if (wr->send_flags & IB_SEND_SOLICITED)387t3_wr_flags |= T3_SOLICITED_EVENT_FLAG;388if (wr->send_flags & IB_SEND_SIGNALED)389t3_wr_flags |= T3_COMPLETION_FLAG;390sqp = qhp->wq.sq +391Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2);392switch (wr->opcode) {393case IB_WR_SEND:394case IB_WR_SEND_WITH_INV:395if (wr->send_flags & IB_SEND_FENCE)396t3_wr_flags |= T3_READ_FENCE_FLAG;397t3_wr_opcode = T3_WR_SEND;398err = build_rdma_send(wqe, wr, &t3_wr_flit_cnt);399break;400case IB_WR_RDMA_WRITE:401case IB_WR_RDMA_WRITE_WITH_IMM:402t3_wr_opcode = T3_WR_WRITE;403err = build_rdma_write(wqe, wr, &t3_wr_flit_cnt);404break;405case IB_WR_RDMA_READ:406case IB_WR_RDMA_READ_WITH_INV:407t3_wr_opcode = T3_WR_READ;408t3_wr_flags = 0; /* T3 reads are always signaled */409err = build_rdma_read(wqe, wr, &t3_wr_flit_cnt);410if (err)411break;412sqp->read_len = wqe->read.local_len;413if (!qhp->wq.oldest_read)414qhp->wq.oldest_read = sqp;415break;416case IB_WR_FAST_REG_MR:417t3_wr_opcode = T3_WR_FASTREG;418err = build_fastreg(wqe, wr, &t3_wr_flit_cnt,419&wr_cnt, &qhp->wq);420break;421case IB_WR_LOCAL_INV:422if (wr->send_flags & IB_SEND_FENCE)423t3_wr_flags |= T3_LOCAL_FENCE_FLAG;424t3_wr_opcode = T3_WR_INV_STAG;425err = build_inv_stag(wqe, wr, &t3_wr_flit_cnt);426break;427default:428PDBG("%s post of type=%d TBD!\n", __func__,429wr->opcode);430err = -EINVAL;431}432if (err)433break;434wqe->send.wrid.id0.hi = qhp->wq.sq_wptr;435sqp->wr_id = wr->wr_id;436sqp->opcode = wr2opcode(t3_wr_opcode);437sqp->sq_wptr = qhp->wq.sq_wptr;438sqp->complete = 0;439sqp->signaled = (wr->send_flags & IB_SEND_SIGNALED);440441build_fw_riwrh((void *) wqe, t3_wr_opcode, t3_wr_flags,442Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2),4430, t3_wr_flit_cnt,444(wr_cnt == 1) ? T3_SOPEOP : T3_SOP);445PDBG("%s cookie 0x%llx wq idx 0x%x swsq idx %ld opcode %d\n",446__func__, (unsigned long long) wr->wr_id, idx,447Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2),448sqp->opcode);449wr = wr->next;450num_wrs--;451qhp->wq.wptr += wr_cnt;452++(qhp->wq.sq_wptr);453}454spin_unlock_irqrestore(&qhp->lock, flag);455if (cxio_wq_db_enabled(&qhp->wq))456ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);457458out:459if (err)460*bad_wr = wr;461return err;462}463464int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,465struct ib_recv_wr **bad_wr)466{467int err = 0;468struct iwch_qp *qhp;469u32 idx;470union t3_wr *wqe;471u32 num_wrs;472unsigned long flag;473474qhp = to_iwch_qp(ibqp);475spin_lock_irqsave(&qhp->lock, flag);476if (qhp->attr.state > IWCH_QP_STATE_RTS) {477spin_unlock_irqrestore(&qhp->lock, flag);478err = -EINVAL;479goto out;480}481num_wrs = Q_FREECNT(qhp->wq.rq_rptr, qhp->wq.rq_wptr,482qhp->wq.rq_size_log2) - 1;483if (!wr) {484spin_unlock_irqrestore(&qhp->lock, flag);485err = -ENOMEM;486goto out;487}488while (wr) {489if (wr->num_sge > T3_MAX_SGE) {490err = -EINVAL;491break;492}493idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2);494wqe = (union t3_wr *) (qhp->wq.queue + idx);495if (num_wrs)496if (wr->sg_list[0].lkey)497err = build_rdma_recv(qhp, wqe, wr);498else499err = build_zero_stag_recv(qhp, wqe, wr);500else501err = -ENOMEM;502503if (err)504break;505506build_fw_riwrh((void *) wqe, T3_WR_RCV, T3_COMPLETION_FLAG,507Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2),5080, sizeof(struct t3_receive_wr) >> 3, T3_SOPEOP);509PDBG("%s cookie 0x%llx idx 0x%x rq_wptr 0x%x rw_rptr 0x%x "510"wqe %p \n", __func__, (unsigned long long) wr->wr_id,511idx, qhp->wq.rq_wptr, qhp->wq.rq_rptr, wqe);512++(qhp->wq.rq_wptr);513++(qhp->wq.wptr);514wr = wr->next;515num_wrs--;516}517spin_unlock_irqrestore(&qhp->lock, flag);518if (cxio_wq_db_enabled(&qhp->wq))519ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);520521out:522if (err)523*bad_wr = wr;524return err;525}526527int iwch_bind_mw(struct ib_qp *qp,528struct ib_mw *mw,529struct ib_mw_bind *mw_bind)530{531struct iwch_dev *rhp;532struct iwch_mw *mhp;533struct iwch_qp *qhp;534union t3_wr *wqe;535u32 pbl_addr;536u8 page_size;537u32 num_wrs;538unsigned long flag;539struct ib_sge sgl;540int err=0;541enum t3_wr_flags t3_wr_flags;542u32 idx;543struct t3_swsq *sqp;544545qhp = to_iwch_qp(qp);546mhp = to_iwch_mw(mw);547rhp = qhp->rhp;548549spin_lock_irqsave(&qhp->lock, flag);550if (qhp->attr.state > IWCH_QP_STATE_RTS) {551spin_unlock_irqrestore(&qhp->lock, flag);552return -EINVAL;553}554num_wrs = Q_FREECNT(qhp->wq.sq_rptr, qhp->wq.sq_wptr,555qhp->wq.sq_size_log2);556if (num_wrs == 0) {557spin_unlock_irqrestore(&qhp->lock, flag);558return -ENOMEM;559}560idx = Q_PTR2IDX(qhp->wq.wptr, qhp->wq.size_log2);561PDBG("%s: idx 0x%0x, mw 0x%p, mw_bind 0x%p\n", __func__, idx,562mw, mw_bind);563wqe = (union t3_wr *) (qhp->wq.queue + idx);564565t3_wr_flags = 0;566if (mw_bind->send_flags & IB_SEND_SIGNALED)567t3_wr_flags = T3_COMPLETION_FLAG;568569sgl.addr = mw_bind->addr;570sgl.lkey = mw_bind->mr->lkey;571sgl.length = mw_bind->length;572wqe->bind.reserved = 0;573wqe->bind.type = TPT_VATO;574575/* TBD: check perms */576wqe->bind.perms = iwch_ib_to_tpt_bind_access(mw_bind->mw_access_flags);577wqe->bind.mr_stag = cpu_to_be32(mw_bind->mr->lkey);578wqe->bind.mw_stag = cpu_to_be32(mw->rkey);579wqe->bind.mw_len = cpu_to_be32(mw_bind->length);580wqe->bind.mw_va = cpu_to_be64(mw_bind->addr);581err = iwch_sgl2pbl_map(rhp, &sgl, 1, &pbl_addr, &page_size);582if (err) {583spin_unlock_irqrestore(&qhp->lock, flag);584return err;585}586wqe->send.wrid.id0.hi = qhp->wq.sq_wptr;587sqp = qhp->wq.sq + Q_PTR2IDX(qhp->wq.sq_wptr, qhp->wq.sq_size_log2);588sqp->wr_id = mw_bind->wr_id;589sqp->opcode = T3_BIND_MW;590sqp->sq_wptr = qhp->wq.sq_wptr;591sqp->complete = 0;592sqp->signaled = (mw_bind->send_flags & IB_SEND_SIGNALED);593wqe->bind.mr_pbl_addr = cpu_to_be32(pbl_addr);594wqe->bind.mr_pagesz = page_size;595build_fw_riwrh((void *)wqe, T3_WR_BIND, t3_wr_flags,596Q_GENBIT(qhp->wq.wptr, qhp->wq.size_log2), 0,597sizeof(struct t3_bind_mw_wr) >> 3, T3_SOPEOP);598++(qhp->wq.wptr);599++(qhp->wq.sq_wptr);600spin_unlock_irqrestore(&qhp->lock, flag);601602if (cxio_wq_db_enabled(&qhp->wq))603ring_doorbell(qhp->wq.doorbell, qhp->wq.qpid);604605return err;606}607608static inline void build_term_codes(struct respQ_msg_t *rsp_msg,609u8 *layer_type, u8 *ecode)610{611int status = TPT_ERR_INTERNAL_ERR;612int tagged = 0;613int opcode = -1;614int rqtype = 0;615int send_inv = 0;616617if (rsp_msg) {618status = CQE_STATUS(rsp_msg->cqe);619opcode = CQE_OPCODE(rsp_msg->cqe);620rqtype = RQ_TYPE(rsp_msg->cqe);621send_inv = (opcode == T3_SEND_WITH_INV) ||622(opcode == T3_SEND_WITH_SE_INV);623tagged = (opcode == T3_RDMA_WRITE) ||624(rqtype && (opcode == T3_READ_RESP));625}626627switch (status) {628case TPT_ERR_STAG:629if (send_inv) {630*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;631*ecode = RDMAP_CANT_INV_STAG;632} else {633*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;634*ecode = RDMAP_INV_STAG;635}636break;637case TPT_ERR_PDID:638*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;639if ((opcode == T3_SEND_WITH_INV) ||640(opcode == T3_SEND_WITH_SE_INV))641*ecode = RDMAP_CANT_INV_STAG;642else643*ecode = RDMAP_STAG_NOT_ASSOC;644break;645case TPT_ERR_QPID:646*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;647*ecode = RDMAP_STAG_NOT_ASSOC;648break;649case TPT_ERR_ACCESS:650*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;651*ecode = RDMAP_ACC_VIOL;652break;653case TPT_ERR_WRAP:654*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;655*ecode = RDMAP_TO_WRAP;656break;657case TPT_ERR_BOUND:658if (tagged) {659*layer_type = LAYER_DDP|DDP_TAGGED_ERR;660*ecode = DDPT_BASE_BOUNDS;661} else {662*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;663*ecode = RDMAP_BASE_BOUNDS;664}665break;666case TPT_ERR_INVALIDATE_SHARED_MR:667case TPT_ERR_INVALIDATE_MR_WITH_MW_BOUND:668*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;669*ecode = RDMAP_CANT_INV_STAG;670break;671case TPT_ERR_ECC:672case TPT_ERR_ECC_PSTAG:673case TPT_ERR_INTERNAL_ERR:674*layer_type = LAYER_RDMAP|RDMAP_LOCAL_CATA;675*ecode = 0;676break;677case TPT_ERR_OUT_OF_RQE:678*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;679*ecode = DDPU_INV_MSN_NOBUF;680break;681case TPT_ERR_PBL_ADDR_BOUND:682*layer_type = LAYER_DDP|DDP_TAGGED_ERR;683*ecode = DDPT_BASE_BOUNDS;684break;685case TPT_ERR_CRC:686*layer_type = LAYER_MPA|DDP_LLP;687*ecode = MPA_CRC_ERR;688break;689case TPT_ERR_MARKER:690*layer_type = LAYER_MPA|DDP_LLP;691*ecode = MPA_MARKER_ERR;692break;693case TPT_ERR_PDU_LEN_ERR:694*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;695*ecode = DDPU_MSG_TOOBIG;696break;697case TPT_ERR_DDP_VERSION:698if (tagged) {699*layer_type = LAYER_DDP|DDP_TAGGED_ERR;700*ecode = DDPT_INV_VERS;701} else {702*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;703*ecode = DDPU_INV_VERS;704}705break;706case TPT_ERR_RDMA_VERSION:707*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;708*ecode = RDMAP_INV_VERS;709break;710case TPT_ERR_OPCODE:711*layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;712*ecode = RDMAP_INV_OPCODE;713break;714case TPT_ERR_DDP_QUEUE_NUM:715*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;716*ecode = DDPU_INV_QN;717break;718case TPT_ERR_MSN:719case TPT_ERR_MSN_GAP:720case TPT_ERR_MSN_RANGE:721case TPT_ERR_IRD_OVERFLOW:722*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;723*ecode = DDPU_INV_MSN_RANGE;724break;725case TPT_ERR_TBIT:726*layer_type = LAYER_DDP|DDP_LOCAL_CATA;727*ecode = 0;728break;729case TPT_ERR_MO:730*layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;731*ecode = DDPU_INV_MO;732break;733default:734*layer_type = LAYER_RDMAP|DDP_LOCAL_CATA;735*ecode = 0;736break;737}738}739740int iwch_post_zb_read(struct iwch_ep *ep)741{742union t3_wr *wqe;743struct sk_buff *skb;744u8 flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3;745746PDBG("%s enter\n", __func__);747skb = alloc_skb(40, GFP_KERNEL);748if (!skb) {749printk(KERN_ERR "%s cannot send zb_read!!\n", __func__);750return -ENOMEM;751}752wqe = (union t3_wr *)skb_put(skb, sizeof(struct t3_rdma_read_wr));753memset(wqe, 0, sizeof(struct t3_rdma_read_wr));754wqe->read.rdmaop = T3_READ_REQ;755wqe->read.reserved[0] = 0;756wqe->read.reserved[1] = 0;757wqe->read.rem_stag = cpu_to_be32(1);758wqe->read.rem_to = cpu_to_be64(1);759wqe->read.local_stag = cpu_to_be32(1);760wqe->read.local_len = cpu_to_be32(0);761wqe->read.local_to = cpu_to_be64(1);762wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ));763wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(ep->hwtid)|764V_FW_RIWR_LEN(flit_cnt));765skb->priority = CPL_PRIORITY_DATA;766return iwch_cxgb3_ofld_send(ep->com.qp->rhp->rdev.t3cdev_p, skb);767}768769/*770* This posts a TERMINATE with layer=RDMA, type=catastrophic.771*/772int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)773{774union t3_wr *wqe;775struct terminate_message *term;776struct sk_buff *skb;777778PDBG("%s %d\n", __func__, __LINE__);779skb = alloc_skb(40, GFP_ATOMIC);780if (!skb) {781printk(KERN_ERR "%s cannot send TERMINATE!\n", __func__);782return -ENOMEM;783}784wqe = (union t3_wr *)skb_put(skb, 40);785memset(wqe, 0, 40);786wqe->send.rdmaop = T3_TERMINATE;787788/* immediate data length */789wqe->send.plen = htonl(4);790791/* immediate data starts here. */792term = (struct terminate_message *)wqe->send.sgl;793build_term_codes(rsp_msg, &term->layer_etype, &term->ecode);794wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_SEND) |795V_FW_RIWR_FLAGS(T3_COMPLETION_FLAG | T3_NOTIFY_FLAG));796wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid));797skb->priority = CPL_PRIORITY_DATA;798return iwch_cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb);799}800801/*802* Assumes qhp lock is held.803*/804static void __flush_qp(struct iwch_qp *qhp, struct iwch_cq *rchp,805struct iwch_cq *schp, unsigned long *flag)806{807int count;808int flushed;809810811PDBG("%s qhp %p rchp %p schp %p\n", __func__, qhp, rchp, schp);812/* take a ref on the qhp since we must release the lock */813atomic_inc(&qhp->refcnt);814spin_unlock_irqrestore(&qhp->lock, *flag);815816/* locking hierarchy: cq lock first, then qp lock. */817spin_lock_irqsave(&rchp->lock, *flag);818spin_lock(&qhp->lock);819cxio_flush_hw_cq(&rchp->cq);820cxio_count_rcqes(&rchp->cq, &qhp->wq, &count);821flushed = cxio_flush_rq(&qhp->wq, &rchp->cq, count);822spin_unlock(&qhp->lock);823spin_unlock_irqrestore(&rchp->lock, *flag);824if (flushed)825(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);826827/* locking hierarchy: cq lock first, then qp lock. */828spin_lock_irqsave(&schp->lock, *flag);829spin_lock(&qhp->lock);830cxio_flush_hw_cq(&schp->cq);831cxio_count_scqes(&schp->cq, &qhp->wq, &count);832flushed = cxio_flush_sq(&qhp->wq, &schp->cq, count);833spin_unlock(&qhp->lock);834spin_unlock_irqrestore(&schp->lock, *flag);835if (flushed)836(*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context);837838/* deref */839if (atomic_dec_and_test(&qhp->refcnt))840wake_up(&qhp->wait);841842spin_lock_irqsave(&qhp->lock, *flag);843}844845static void flush_qp(struct iwch_qp *qhp, unsigned long *flag)846{847struct iwch_cq *rchp, *schp;848849rchp = get_chp(qhp->rhp, qhp->attr.rcq);850schp = get_chp(qhp->rhp, qhp->attr.scq);851852if (qhp->ibqp.uobject) {853cxio_set_wq_in_error(&qhp->wq);854cxio_set_cq_in_error(&rchp->cq);855(*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);856if (schp != rchp) {857cxio_set_cq_in_error(&schp->cq);858(*schp->ibcq.comp_handler)(&schp->ibcq,859schp->ibcq.cq_context);860}861return;862}863__flush_qp(qhp, rchp, schp, flag);864}865866867/*868* Return count of RECV WRs posted869*/870u16 iwch_rqes_posted(struct iwch_qp *qhp)871{872union t3_wr *wqe = qhp->wq.queue;873u16 count = 0;874while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) {875count++;876wqe++;877}878PDBG("%s qhp %p count %u\n", __func__, qhp, count);879return count;880}881882static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,883enum iwch_qp_attr_mask mask,884struct iwch_qp_attributes *attrs)885{886struct t3_rdma_init_attr init_attr;887int ret;888889init_attr.tid = qhp->ep->hwtid;890init_attr.qpid = qhp->wq.qpid;891init_attr.pdid = qhp->attr.pd;892init_attr.scqid = qhp->attr.scq;893init_attr.rcqid = qhp->attr.rcq;894init_attr.rq_addr = qhp->wq.rq_addr;895init_attr.rq_size = 1 << qhp->wq.rq_size_log2;896init_attr.mpaattrs = uP_RI_MPA_IETF_ENABLE |897qhp->attr.mpa_attr.recv_marker_enabled |898(qhp->attr.mpa_attr.xmit_marker_enabled << 1) |899(qhp->attr.mpa_attr.crc_enabled << 2);900901init_attr.qpcaps = uP_RI_QP_RDMA_READ_ENABLE |902uP_RI_QP_RDMA_WRITE_ENABLE |903uP_RI_QP_BIND_ENABLE;904if (!qhp->ibqp.uobject)905init_attr.qpcaps |= uP_RI_QP_STAG0_ENABLE |906uP_RI_QP_FAST_REGISTER_ENABLE;907908init_attr.tcp_emss = qhp->ep->emss;909init_attr.ord = qhp->attr.max_ord;910init_attr.ird = qhp->attr.max_ird;911init_attr.qp_dma_addr = qhp->wq.dma_addr;912init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);913init_attr.rqe_count = iwch_rqes_posted(qhp);914init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0;915init_attr.chan = qhp->ep->l2t->smt_idx;916if (peer2peer) {917init_attr.rtr_type = RTR_READ;918if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator)919init_attr.ord = 1;920if (init_attr.ird == 0 && !qhp->attr.mpa_attr.initiator)921init_attr.ird = 1;922} else923init_attr.rtr_type = 0;924init_attr.irs = qhp->ep->rcv_seq;925PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "926"flags 0x%x qpcaps 0x%x\n", __func__,927init_attr.rq_addr, init_attr.rq_size,928init_attr.flags, init_attr.qpcaps);929ret = cxio_rdma_init(&rhp->rdev, &init_attr);930PDBG("%s ret %d\n", __func__, ret);931return ret;932}933934int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp,935enum iwch_qp_attr_mask mask,936struct iwch_qp_attributes *attrs,937int internal)938{939int ret = 0;940struct iwch_qp_attributes newattr = qhp->attr;941unsigned long flag;942int disconnect = 0;943int terminate = 0;944int abort = 0;945int free = 0;946struct iwch_ep *ep = NULL;947948PDBG("%s qhp %p qpid 0x%x ep %p state %d -> %d\n", __func__,949qhp, qhp->wq.qpid, qhp->ep, qhp->attr.state,950(mask & IWCH_QP_ATTR_NEXT_STATE) ? attrs->next_state : -1);951952spin_lock_irqsave(&qhp->lock, flag);953954/* Process attr changes if in IDLE */955if (mask & IWCH_QP_ATTR_VALID_MODIFY) {956if (qhp->attr.state != IWCH_QP_STATE_IDLE) {957ret = -EIO;958goto out;959}960if (mask & IWCH_QP_ATTR_ENABLE_RDMA_READ)961newattr.enable_rdma_read = attrs->enable_rdma_read;962if (mask & IWCH_QP_ATTR_ENABLE_RDMA_WRITE)963newattr.enable_rdma_write = attrs->enable_rdma_write;964if (mask & IWCH_QP_ATTR_ENABLE_RDMA_BIND)965newattr.enable_bind = attrs->enable_bind;966if (mask & IWCH_QP_ATTR_MAX_ORD) {967if (attrs->max_ord >968rhp->attr.max_rdma_read_qp_depth) {969ret = -EINVAL;970goto out;971}972newattr.max_ord = attrs->max_ord;973}974if (mask & IWCH_QP_ATTR_MAX_IRD) {975if (attrs->max_ird >976rhp->attr.max_rdma_reads_per_qp) {977ret = -EINVAL;978goto out;979}980newattr.max_ird = attrs->max_ird;981}982qhp->attr = newattr;983}984985if (!(mask & IWCH_QP_ATTR_NEXT_STATE))986goto out;987if (qhp->attr.state == attrs->next_state)988goto out;989990switch (qhp->attr.state) {991case IWCH_QP_STATE_IDLE:992switch (attrs->next_state) {993case IWCH_QP_STATE_RTS:994if (!(mask & IWCH_QP_ATTR_LLP_STREAM_HANDLE)) {995ret = -EINVAL;996goto out;997}998if (!(mask & IWCH_QP_ATTR_MPA_ATTR)) {999ret = -EINVAL;1000goto out;1001}1002qhp->attr.mpa_attr = attrs->mpa_attr;1003qhp->attr.llp_stream_handle = attrs->llp_stream_handle;1004qhp->ep = qhp->attr.llp_stream_handle;1005qhp->attr.state = IWCH_QP_STATE_RTS;10061007/*1008* Ref the endpoint here and deref when we1009* disassociate the endpoint from the QP. This1010* happens in CLOSING->IDLE transition or *->ERROR1011* transition.1012*/1013get_ep(&qhp->ep->com);1014spin_unlock_irqrestore(&qhp->lock, flag);1015ret = rdma_init(rhp, qhp, mask, attrs);1016spin_lock_irqsave(&qhp->lock, flag);1017if (ret)1018goto err;1019break;1020case IWCH_QP_STATE_ERROR:1021qhp->attr.state = IWCH_QP_STATE_ERROR;1022flush_qp(qhp, &flag);1023break;1024default:1025ret = -EINVAL;1026goto out;1027}1028break;1029case IWCH_QP_STATE_RTS:1030switch (attrs->next_state) {1031case IWCH_QP_STATE_CLOSING:1032BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2);1033qhp->attr.state = IWCH_QP_STATE_CLOSING;1034if (!internal) {1035abort=0;1036disconnect = 1;1037ep = qhp->ep;1038get_ep(&ep->com);1039}1040break;1041case IWCH_QP_STATE_TERMINATE:1042qhp->attr.state = IWCH_QP_STATE_TERMINATE;1043if (qhp->ibqp.uobject)1044cxio_set_wq_in_error(&qhp->wq);1045if (!internal)1046terminate = 1;1047break;1048case IWCH_QP_STATE_ERROR:1049qhp->attr.state = IWCH_QP_STATE_ERROR;1050if (!internal) {1051abort=1;1052disconnect = 1;1053ep = qhp->ep;1054get_ep(&ep->com);1055}1056goto err;1057break;1058default:1059ret = -EINVAL;1060goto out;1061}1062break;1063case IWCH_QP_STATE_CLOSING:1064if (!internal) {1065ret = -EINVAL;1066goto out;1067}1068switch (attrs->next_state) {1069case IWCH_QP_STATE_IDLE:1070flush_qp(qhp, &flag);1071qhp->attr.state = IWCH_QP_STATE_IDLE;1072qhp->attr.llp_stream_handle = NULL;1073put_ep(&qhp->ep->com);1074qhp->ep = NULL;1075wake_up(&qhp->wait);1076break;1077case IWCH_QP_STATE_ERROR:1078goto err;1079default:1080ret = -EINVAL;1081goto err;1082}1083break;1084case IWCH_QP_STATE_ERROR:1085if (attrs->next_state != IWCH_QP_STATE_IDLE) {1086ret = -EINVAL;1087goto out;1088}10891090if (!Q_EMPTY(qhp->wq.sq_rptr, qhp->wq.sq_wptr) ||1091!Q_EMPTY(qhp->wq.rq_rptr, qhp->wq.rq_wptr)) {1092ret = -EINVAL;1093goto out;1094}1095qhp->attr.state = IWCH_QP_STATE_IDLE;1096break;1097case IWCH_QP_STATE_TERMINATE:1098if (!internal) {1099ret = -EINVAL;1100goto out;1101}1102goto err;1103break;1104default:1105printk(KERN_ERR "%s in a bad state %d\n",1106__func__, qhp->attr.state);1107ret = -EINVAL;1108goto err;1109break;1110}1111goto out;1112err:1113PDBG("%s disassociating ep %p qpid 0x%x\n", __func__, qhp->ep,1114qhp->wq.qpid);11151116/* disassociate the LLP connection */1117qhp->attr.llp_stream_handle = NULL;1118ep = qhp->ep;1119qhp->ep = NULL;1120qhp->attr.state = IWCH_QP_STATE_ERROR;1121free=1;1122wake_up(&qhp->wait);1123BUG_ON(!ep);1124flush_qp(qhp, &flag);1125out:1126spin_unlock_irqrestore(&qhp->lock, flag);11271128if (terminate)1129iwch_post_terminate(qhp, NULL);11301131/*1132* If disconnect is 1, then we need to initiate a disconnect1133* on the EP. This can be a normal close (RTS->CLOSING) or1134* an abnormal close (RTS/CLOSING->ERROR).1135*/1136if (disconnect) {1137iwch_ep_disconnect(ep, abort, GFP_KERNEL);1138put_ep(&ep->com);1139}11401141/*1142* If free is 1, then we've disassociated the EP from the QP1143* and we need to dereference the EP.1144*/1145if (free)1146put_ep(&ep->com);11471148PDBG("%s exit state %d\n", __func__, qhp->attr.state);1149return ret;1150}115111521153