Path: blob/master/drivers/infiniband/hw/amso1100/c2_qp.c
15112 views
/*1* Copyright (c) 2004 Topspin Communications. All rights reserved.2* Copyright (c) 2005 Cisco Systems. All rights reserved.3* Copyright (c) 2005 Mellanox Technologies. All rights reserved.4* Copyright (c) 2004 Voltaire, Inc. All rights reserved.5* Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.6*7* This software is available to you under a choice of one of two8* licenses. You may choose to be licensed under the terms of the GNU9* General Public License (GPL) Version 2, available from the file10* COPYING in the main directory of this source tree, or the11* OpenIB.org BSD license below:12*13* Redistribution and use in source and binary forms, with or14* without modification, are permitted provided that the following15* conditions are met:16*17* - Redistributions of source code must retain the above18* copyright notice, this list of conditions and the following19* disclaimer.20*21* - Redistributions in binary form must reproduce the above22* copyright notice, this list of conditions and the following23* disclaimer in the documentation and/or other materials24* provided with the distribution.25*26* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,27* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF28* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND29* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS30* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN31* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN32* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE33* SOFTWARE.34*35*/3637#include <linux/delay.h>38#include <linux/gfp.h>3940#include "c2.h"41#include "c2_vq.h"42#include "c2_status.h"4344#define C2_MAX_ORD_PER_QP 12845#define C2_MAX_IRD_PER_QP 1284647#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)48#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)49#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)5051#define NO_SUPPORT -152static const u8 c2_opcode[] = {53[IB_WR_SEND] = C2_WR_TYPE_SEND,54[IB_WR_SEND_WITH_IMM] = NO_SUPPORT,55[IB_WR_RDMA_WRITE] = C2_WR_TYPE_RDMA_WRITE,56[IB_WR_RDMA_WRITE_WITH_IMM] = NO_SUPPORT,57[IB_WR_RDMA_READ] = C2_WR_TYPE_RDMA_READ,58[IB_WR_ATOMIC_CMP_AND_SWP] = NO_SUPPORT,59[IB_WR_ATOMIC_FETCH_AND_ADD] = NO_SUPPORT,60};6162static int to_c2_state(enum ib_qp_state ib_state)63{64switch (ib_state) {65case IB_QPS_RESET:66return C2_QP_STATE_IDLE;67case IB_QPS_RTS:68return C2_QP_STATE_RTS;69case IB_QPS_SQD:70return C2_QP_STATE_CLOSING;71case IB_QPS_SQE:72return C2_QP_STATE_CLOSING;73case IB_QPS_ERR:74return C2_QP_STATE_ERROR;75default:76return -1;77}78}7980static int to_ib_state(enum c2_qp_state c2_state)81{82switch (c2_state) {83case C2_QP_STATE_IDLE:84return IB_QPS_RESET;85case C2_QP_STATE_CONNECTING:86return IB_QPS_RTR;87case C2_QP_STATE_RTS:88return IB_QPS_RTS;89case C2_QP_STATE_CLOSING:90return IB_QPS_SQD;91case C2_QP_STATE_ERROR:92return IB_QPS_ERR;93case C2_QP_STATE_TERMINATE:94return IB_QPS_SQE;95default:96return -1;97}98}99100static const char *to_ib_state_str(int ib_state)101{102static const char *state_str[] = {103"IB_QPS_RESET",104"IB_QPS_INIT",105"IB_QPS_RTR",106"IB_QPS_RTS",107"IB_QPS_SQD",108"IB_QPS_SQE",109"IB_QPS_ERR"110};111if (ib_state < IB_QPS_RESET ||112ib_state > IB_QPS_ERR)113return "<invalid IB QP state>";114115ib_state -= IB_QPS_RESET;116return state_str[ib_state];117}118119void c2_set_qp_state(struct c2_qp *qp, int c2_state)120{121int new_state = to_ib_state(c2_state);122123pr_debug("%s: qp[%p] state modify %s --> %s\n",124__func__,125qp,126to_ib_state_str(qp->state),127to_ib_state_str(new_state));128qp->state = new_state;129}130131#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF132133int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,134struct ib_qp_attr *attr, int attr_mask)135{136struct c2wr_qp_modify_req wr;137struct c2wr_qp_modify_rep *reply;138struct c2_vq_req *vq_req;139unsigned long flags;140u8 next_state;141int err;142143pr_debug("%s:%d qp=%p, %s --> %s\n",144__func__, __LINE__,145qp,146to_ib_state_str(qp->state),147to_ib_state_str(attr->qp_state));148149vq_req = vq_req_alloc(c2dev);150if (!vq_req)151return -ENOMEM;152153c2_wr_set_id(&wr, CCWR_QP_MODIFY);154wr.hdr.context = (unsigned long) vq_req;155wr.rnic_handle = c2dev->adapter_handle;156wr.qp_handle = qp->adapter_handle;157wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);158wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);159wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);160wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);161162if (attr_mask & IB_QP_STATE) {163/* Ensure the state is valid */164if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR) {165err = -EINVAL;166goto bail0;167}168169wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state));170171if (attr->qp_state == IB_QPS_ERR) {172spin_lock_irqsave(&qp->lock, flags);173if (qp->cm_id && qp->state == IB_QPS_RTS) {174pr_debug("Generating CLOSE event for QP-->ERR, "175"qp=%p, cm_id=%p\n",qp,qp->cm_id);176/* Generate an CLOSE event */177vq_req->cm_id = qp->cm_id;178vq_req->event = IW_CM_EVENT_CLOSE;179}180spin_unlock_irqrestore(&qp->lock, flags);181}182next_state = attr->qp_state;183184} else if (attr_mask & IB_QP_CUR_STATE) {185186if (attr->cur_qp_state != IB_QPS_RTR &&187attr->cur_qp_state != IB_QPS_RTS &&188attr->cur_qp_state != IB_QPS_SQD &&189attr->cur_qp_state != IB_QPS_SQE) {190err = -EINVAL;191goto bail0;192} else193wr.next_qp_state =194cpu_to_be32(to_c2_state(attr->cur_qp_state));195196next_state = attr->cur_qp_state;197198} else {199err = 0;200goto bail0;201}202203/* reference the request struct */204vq_req_get(c2dev, vq_req);205206err = vq_send_wr(c2dev, (union c2wr *) & wr);207if (err) {208vq_req_put(c2dev, vq_req);209goto bail0;210}211212err = vq_wait_for_reply(c2dev, vq_req);213if (err)214goto bail0;215216reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg;217if (!reply) {218err = -ENOMEM;219goto bail0;220}221222err = c2_errno(reply);223if (!err)224qp->state = next_state;225#ifdef DEBUG226else227pr_debug("%s: c2_errno=%d\n", __func__, err);228#endif229/*230* If we're going to error and generating the event here, then231* we need to remove the reference because there will be no232* close event generated by the adapter233*/234spin_lock_irqsave(&qp->lock, flags);235if (vq_req->event==IW_CM_EVENT_CLOSE && qp->cm_id) {236qp->cm_id->rem_ref(qp->cm_id);237qp->cm_id = NULL;238}239spin_unlock_irqrestore(&qp->lock, flags);240241vq_repbuf_free(c2dev, reply);242bail0:243vq_req_free(c2dev, vq_req);244245pr_debug("%s:%d qp=%p, cur_state=%s\n",246__func__, __LINE__,247qp,248to_ib_state_str(qp->state));249return err;250}251252int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,253int ord, int ird)254{255struct c2wr_qp_modify_req wr;256struct c2wr_qp_modify_rep *reply;257struct c2_vq_req *vq_req;258int err;259260vq_req = vq_req_alloc(c2dev);261if (!vq_req)262return -ENOMEM;263264c2_wr_set_id(&wr, CCWR_QP_MODIFY);265wr.hdr.context = (unsigned long) vq_req;266wr.rnic_handle = c2dev->adapter_handle;267wr.qp_handle = qp->adapter_handle;268wr.ord = cpu_to_be32(ord);269wr.ird = cpu_to_be32(ird);270wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);271wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);272wr.next_qp_state = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);273274/* reference the request struct */275vq_req_get(c2dev, vq_req);276277err = vq_send_wr(c2dev, (union c2wr *) & wr);278if (err) {279vq_req_put(c2dev, vq_req);280goto bail0;281}282283err = vq_wait_for_reply(c2dev, vq_req);284if (err)285goto bail0;286287reply = (struct c2wr_qp_modify_rep *) (unsigned long)288vq_req->reply_msg;289if (!reply) {290err = -ENOMEM;291goto bail0;292}293294err = c2_errno(reply);295vq_repbuf_free(c2dev, reply);296bail0:297vq_req_free(c2dev, vq_req);298return err;299}300301static int destroy_qp(struct c2_dev *c2dev, struct c2_qp *qp)302{303struct c2_vq_req *vq_req;304struct c2wr_qp_destroy_req wr;305struct c2wr_qp_destroy_rep *reply;306unsigned long flags;307int err;308309/*310* Allocate a verb request message311*/312vq_req = vq_req_alloc(c2dev);313if (!vq_req) {314return -ENOMEM;315}316317/*318* Initialize the WR319*/320c2_wr_set_id(&wr, CCWR_QP_DESTROY);321wr.hdr.context = (unsigned long) vq_req;322wr.rnic_handle = c2dev->adapter_handle;323wr.qp_handle = qp->adapter_handle;324325/*326* reference the request struct. dereferenced in the int handler.327*/328vq_req_get(c2dev, vq_req);329330spin_lock_irqsave(&qp->lock, flags);331if (qp->cm_id && qp->state == IB_QPS_RTS) {332pr_debug("destroy_qp: generating CLOSE event for QP-->ERR, "333"qp=%p, cm_id=%p\n",qp,qp->cm_id);334/* Generate an CLOSE event */335vq_req->qp = qp;336vq_req->cm_id = qp->cm_id;337vq_req->event = IW_CM_EVENT_CLOSE;338}339spin_unlock_irqrestore(&qp->lock, flags);340341/*342* Send WR to adapter343*/344err = vq_send_wr(c2dev, (union c2wr *) & wr);345if (err) {346vq_req_put(c2dev, vq_req);347goto bail0;348}349350/*351* Wait for reply from adapter352*/353err = vq_wait_for_reply(c2dev, vq_req);354if (err) {355goto bail0;356}357358/*359* Process reply360*/361reply = (struct c2wr_qp_destroy_rep *) (unsigned long) (vq_req->reply_msg);362if (!reply) {363err = -ENOMEM;364goto bail0;365}366367spin_lock_irqsave(&qp->lock, flags);368if (qp->cm_id) {369qp->cm_id->rem_ref(qp->cm_id);370qp->cm_id = NULL;371}372spin_unlock_irqrestore(&qp->lock, flags);373374vq_repbuf_free(c2dev, reply);375bail0:376vq_req_free(c2dev, vq_req);377return err;378}379380static int c2_alloc_qpn(struct c2_dev *c2dev, struct c2_qp *qp)381{382int ret;383384do {385spin_lock_irq(&c2dev->qp_table.lock);386ret = idr_get_new_above(&c2dev->qp_table.idr, qp,387c2dev->qp_table.last++, &qp->qpn);388spin_unlock_irq(&c2dev->qp_table.lock);389} while ((ret == -EAGAIN) &&390idr_pre_get(&c2dev->qp_table.idr, GFP_KERNEL));391return ret;392}393394static void c2_free_qpn(struct c2_dev *c2dev, int qpn)395{396spin_lock_irq(&c2dev->qp_table.lock);397idr_remove(&c2dev->qp_table.idr, qpn);398spin_unlock_irq(&c2dev->qp_table.lock);399}400401struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn)402{403unsigned long flags;404struct c2_qp *qp;405406spin_lock_irqsave(&c2dev->qp_table.lock, flags);407qp = idr_find(&c2dev->qp_table.idr, qpn);408spin_unlock_irqrestore(&c2dev->qp_table.lock, flags);409return qp;410}411412int c2_alloc_qp(struct c2_dev *c2dev,413struct c2_pd *pd,414struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp)415{416struct c2wr_qp_create_req wr;417struct c2wr_qp_create_rep *reply;418struct c2_vq_req *vq_req;419struct c2_cq *send_cq = to_c2cq(qp_attrs->send_cq);420struct c2_cq *recv_cq = to_c2cq(qp_attrs->recv_cq);421unsigned long peer_pa;422u32 q_size, msg_size, mmap_size;423void __iomem *mmap;424int err;425426err = c2_alloc_qpn(c2dev, qp);427if (err)428return err;429qp->ibqp.qp_num = qp->qpn;430qp->ibqp.qp_type = IB_QPT_RC;431432/* Allocate the SQ and RQ shared pointers */433qp->sq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,434&qp->sq_mq.shared_dma, GFP_KERNEL);435if (!qp->sq_mq.shared) {436err = -ENOMEM;437goto bail0;438}439440qp->rq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,441&qp->rq_mq.shared_dma, GFP_KERNEL);442if (!qp->rq_mq.shared) {443err = -ENOMEM;444goto bail1;445}446447/* Allocate the verbs request */448vq_req = vq_req_alloc(c2dev);449if (vq_req == NULL) {450err = -ENOMEM;451goto bail2;452}453454/* Initialize the work request */455memset(&wr, 0, sizeof(wr));456c2_wr_set_id(&wr, CCWR_QP_CREATE);457wr.hdr.context = (unsigned long) vq_req;458wr.rnic_handle = c2dev->adapter_handle;459wr.sq_cq_handle = send_cq->adapter_handle;460wr.rq_cq_handle = recv_cq->adapter_handle;461wr.sq_depth = cpu_to_be32(qp_attrs->cap.max_send_wr + 1);462wr.rq_depth = cpu_to_be32(qp_attrs->cap.max_recv_wr + 1);463wr.srq_handle = 0;464wr.flags = cpu_to_be32(QP_RDMA_READ | QP_RDMA_WRITE | QP_MW_BIND |465QP_ZERO_STAG | QP_RDMA_READ_RESPONSE);466wr.send_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);467wr.recv_sgl_depth = cpu_to_be32(qp_attrs->cap.max_recv_sge);468wr.rdma_write_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);469wr.shared_sq_ht = cpu_to_be64(qp->sq_mq.shared_dma);470wr.shared_rq_ht = cpu_to_be64(qp->rq_mq.shared_dma);471wr.ord = cpu_to_be32(C2_MAX_ORD_PER_QP);472wr.ird = cpu_to_be32(C2_MAX_IRD_PER_QP);473wr.pd_id = pd->pd_id;474wr.user_context = (unsigned long) qp;475476vq_req_get(c2dev, vq_req);477478/* Send the WR to the adapter */479err = vq_send_wr(c2dev, (union c2wr *) & wr);480if (err) {481vq_req_put(c2dev, vq_req);482goto bail3;483}484485/* Wait for the verb reply */486err = vq_wait_for_reply(c2dev, vq_req);487if (err) {488goto bail3;489}490491/* Process the reply */492reply = (struct c2wr_qp_create_rep *) (unsigned long) (vq_req->reply_msg);493if (!reply) {494err = -ENOMEM;495goto bail3;496}497498if ((err = c2_wr_get_result(reply)) != 0) {499goto bail4;500}501502/* Fill in the kernel QP struct */503atomic_set(&qp->refcount, 1);504qp->adapter_handle = reply->qp_handle;505qp->state = IB_QPS_RESET;506qp->send_sgl_depth = qp_attrs->cap.max_send_sge;507qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge;508qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge;509init_waitqueue_head(&qp->wait);510511/* Initialize the SQ MQ */512q_size = be32_to_cpu(reply->sq_depth);513msg_size = be32_to_cpu(reply->sq_msg_size);514peer_pa = c2dev->pa + be32_to_cpu(reply->sq_mq_start);515mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);516mmap = ioremap_nocache(peer_pa, mmap_size);517if (!mmap) {518err = -ENOMEM;519goto bail5;520}521522c2_mq_req_init(&qp->sq_mq,523be32_to_cpu(reply->sq_mq_index),524q_size,525msg_size,526mmap + sizeof(struct c2_mq_shared), /* pool start */527mmap, /* peer */528C2_MQ_ADAPTER_TARGET);529530/* Initialize the RQ mq */531q_size = be32_to_cpu(reply->rq_depth);532msg_size = be32_to_cpu(reply->rq_msg_size);533peer_pa = c2dev->pa + be32_to_cpu(reply->rq_mq_start);534mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);535mmap = ioremap_nocache(peer_pa, mmap_size);536if (!mmap) {537err = -ENOMEM;538goto bail6;539}540541c2_mq_req_init(&qp->rq_mq,542be32_to_cpu(reply->rq_mq_index),543q_size,544msg_size,545mmap + sizeof(struct c2_mq_shared), /* pool start */546mmap, /* peer */547C2_MQ_ADAPTER_TARGET);548549vq_repbuf_free(c2dev, reply);550vq_req_free(c2dev, vq_req);551552return 0;553554bail6:555iounmap(qp->sq_mq.peer);556bail5:557destroy_qp(c2dev, qp);558bail4:559vq_repbuf_free(c2dev, reply);560bail3:561vq_req_free(c2dev, vq_req);562bail2:563c2_free_mqsp(qp->rq_mq.shared);564bail1:565c2_free_mqsp(qp->sq_mq.shared);566bail0:567c2_free_qpn(c2dev, qp->qpn);568return err;569}570571static inline void c2_lock_cqs(struct c2_cq *send_cq, struct c2_cq *recv_cq)572{573if (send_cq == recv_cq)574spin_lock_irq(&send_cq->lock);575else if (send_cq > recv_cq) {576spin_lock_irq(&send_cq->lock);577spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);578} else {579spin_lock_irq(&recv_cq->lock);580spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);581}582}583584static inline void c2_unlock_cqs(struct c2_cq *send_cq, struct c2_cq *recv_cq)585{586if (send_cq == recv_cq)587spin_unlock_irq(&send_cq->lock);588else if (send_cq > recv_cq) {589spin_unlock(&recv_cq->lock);590spin_unlock_irq(&send_cq->lock);591} else {592spin_unlock(&send_cq->lock);593spin_unlock_irq(&recv_cq->lock);594}595}596597void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp)598{599struct c2_cq *send_cq;600struct c2_cq *recv_cq;601602send_cq = to_c2cq(qp->ibqp.send_cq);603recv_cq = to_c2cq(qp->ibqp.recv_cq);604605/*606* Lock CQs here, so that CQ polling code can do QP lookup607* without taking a lock.608*/609c2_lock_cqs(send_cq, recv_cq);610c2_free_qpn(c2dev, qp->qpn);611c2_unlock_cqs(send_cq, recv_cq);612613/*614* Destroy qp in the rnic...615*/616destroy_qp(c2dev, qp);617618/*619* Mark any unreaped CQEs as null and void.620*/621c2_cq_clean(c2dev, qp, send_cq->cqn);622if (send_cq != recv_cq)623c2_cq_clean(c2dev, qp, recv_cq->cqn);624/*625* Unmap the MQs and return the shared pointers626* to the message pool.627*/628iounmap(qp->sq_mq.peer);629iounmap(qp->rq_mq.peer);630c2_free_mqsp(qp->sq_mq.shared);631c2_free_mqsp(qp->rq_mq.shared);632633atomic_dec(&qp->refcount);634wait_event(qp->wait, !atomic_read(&qp->refcount));635}636637/*638* Function: move_sgl639*640* Description:641* Move an SGL from the user's work request struct into a CCIL Work Request642* message, swapping to WR byte order and ensure the total length doesn't643* overflow.644*645* IN:646* dst - ptr to CCIL Work Request message SGL memory.647* src - ptr to the consumers SGL memory.648*649* OUT: none650*651* Return:652* CCIL status codes.653*/654static int655move_sgl(struct c2_data_addr * dst, struct ib_sge *src, int count, u32 * p_len,656u8 * actual_count)657{658u32 tot = 0; /* running total */659u8 acount = 0; /* running total non-0 len sge's */660661while (count > 0) {662/*663* If the addition of this SGE causes the664* total SGL length to exceed 2^32-1, then665* fail-n-bail.666*667* If the current total plus the next element length668* wraps, then it will go negative and be less than the669* current total...670*/671if ((tot + src->length) < tot) {672return -EINVAL;673}674/*675* Bug: 1456 (as well as 1498 & 1643)676* Skip over any sge's supplied with len=0677*/678if (src->length) {679tot += src->length;680dst->stag = cpu_to_be32(src->lkey);681dst->to = cpu_to_be64(src->addr);682dst->length = cpu_to_be32(src->length);683dst++;684acount++;685}686src++;687count--;688}689690if (acount == 0) {691/*692* Bug: 1476 (as well as 1498, 1456 and 1643)693* Setup the SGL in the WR to make it easier for the RNIC.694* This way, the FW doesn't have to deal with special cases.695* Setting length=0 should be sufficient.696*/697dst->stag = 0;698dst->to = 0;699dst->length = 0;700}701702*p_len = tot;703*actual_count = acount;704return 0;705}706707/*708* Function: c2_activity (private function)709*710* Description:711* Post an mq index to the host->adapter activity fifo.712*713* IN:714* c2dev - ptr to c2dev structure715* mq_index - mq index to post716* shared - value most recently written to shared717*718* OUT:719*720* Return:721* none722*/723static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared)724{725/*726* First read the register to see if the FIFO is full, and if so,727* spin until it's not. This isn't perfect -- there is no728* synchronization among the clients of the register, but in729* practice it prevents multiple CPU from hammering the bus730* with PCI RETRY. Note that when this does happen, the card731* cannot get on the bus and the card and system hang in a732* deadlock -- thus the need for this code. [TOT]733*/734while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000)735udelay(10);736737__raw_writel(C2_HINT_MAKE(mq_index, shared),738c2dev->regs + PCI_BAR0_ADAPTER_HINT);739}740741/*742* Function: qp_wr_post743*744* Description:745* This in-line function allocates a MQ msg, then moves the host-copy of746* the completed WR into msg. Then it posts the message.747*748* IN:749* q - ptr to user MQ.750* wr - ptr to host-copy of the WR.751* qp - ptr to user qp752* size - Number of bytes to post. Assumed to be divisible by 4.753*754* OUT: none755*756* Return:757* CCIL status codes.758*/759static int qp_wr_post(struct c2_mq *q, union c2wr * wr, struct c2_qp *qp, u32 size)760{761union c2wr *msg;762763msg = c2_mq_alloc(q);764if (msg == NULL) {765return -EINVAL;766}767#ifdef CCMSGMAGIC768((c2wr_hdr_t *) wr)->magic = cpu_to_be32(CCWR_MAGIC);769#endif770771/*772* Since all header fields in the WR are the same as the773* CQE, set the following so the adapter need not.774*/775c2_wr_set_result(wr, CCERR_PENDING);776777/*778* Copy the wr down to the adapter779*/780memcpy((void *) msg, (void *) wr, size);781782c2_mq_produce(q);783return 0;784}785786787int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,788struct ib_send_wr **bad_wr)789{790struct c2_dev *c2dev = to_c2dev(ibqp->device);791struct c2_qp *qp = to_c2qp(ibqp);792union c2wr wr;793unsigned long lock_flags;794int err = 0;795796u32 flags;797u32 tot_len;798u8 actual_sge_count;799u32 msg_size;800801if (qp->state > IB_QPS_RTS) {802err = -EINVAL;803goto out;804}805806while (ib_wr) {807808flags = 0;809wr.sqwr.sq_hdr.user_hdr.hdr.context = ib_wr->wr_id;810if (ib_wr->send_flags & IB_SEND_SIGNALED) {811flags |= SQ_SIGNALED;812}813814switch (ib_wr->opcode) {815case IB_WR_SEND:816case IB_WR_SEND_WITH_INV:817if (ib_wr->opcode == IB_WR_SEND) {818if (ib_wr->send_flags & IB_SEND_SOLICITED)819c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE);820else821c2_wr_set_id(&wr, C2_WR_TYPE_SEND);822wr.sqwr.send.remote_stag = 0;823} else {824if (ib_wr->send_flags & IB_SEND_SOLICITED)825c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE_INV);826else827c2_wr_set_id(&wr, C2_WR_TYPE_SEND_INV);828wr.sqwr.send.remote_stag =829cpu_to_be32(ib_wr->ex.invalidate_rkey);830}831832msg_size = sizeof(struct c2wr_send_req) +833sizeof(struct c2_data_addr) * ib_wr->num_sge;834if (ib_wr->num_sge > qp->send_sgl_depth) {835err = -EINVAL;836break;837}838if (ib_wr->send_flags & IB_SEND_FENCE) {839flags |= SQ_READ_FENCE;840}841err = move_sgl((struct c2_data_addr *) & (wr.sqwr.send.data),842ib_wr->sg_list,843ib_wr->num_sge,844&tot_len, &actual_sge_count);845wr.sqwr.send.sge_len = cpu_to_be32(tot_len);846c2_wr_set_sge_count(&wr, actual_sge_count);847break;848case IB_WR_RDMA_WRITE:849c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_WRITE);850msg_size = sizeof(struct c2wr_rdma_write_req) +851(sizeof(struct c2_data_addr) * ib_wr->num_sge);852if (ib_wr->num_sge > qp->rdma_write_sgl_depth) {853err = -EINVAL;854break;855}856if (ib_wr->send_flags & IB_SEND_FENCE) {857flags |= SQ_READ_FENCE;858}859wr.sqwr.rdma_write.remote_stag =860cpu_to_be32(ib_wr->wr.rdma.rkey);861wr.sqwr.rdma_write.remote_to =862cpu_to_be64(ib_wr->wr.rdma.remote_addr);863err = move_sgl((struct c2_data_addr *)864& (wr.sqwr.rdma_write.data),865ib_wr->sg_list,866ib_wr->num_sge,867&tot_len, &actual_sge_count);868wr.sqwr.rdma_write.sge_len = cpu_to_be32(tot_len);869c2_wr_set_sge_count(&wr, actual_sge_count);870break;871case IB_WR_RDMA_READ:872c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_READ);873msg_size = sizeof(struct c2wr_rdma_read_req);874875/* IWarp only suppots 1 sge for RDMA reads */876if (ib_wr->num_sge > 1) {877err = -EINVAL;878break;879}880881/*882* Move the local and remote stag/to/len into the WR.883*/884wr.sqwr.rdma_read.local_stag =885cpu_to_be32(ib_wr->sg_list->lkey);886wr.sqwr.rdma_read.local_to =887cpu_to_be64(ib_wr->sg_list->addr);888wr.sqwr.rdma_read.remote_stag =889cpu_to_be32(ib_wr->wr.rdma.rkey);890wr.sqwr.rdma_read.remote_to =891cpu_to_be64(ib_wr->wr.rdma.remote_addr);892wr.sqwr.rdma_read.length =893cpu_to_be32(ib_wr->sg_list->length);894break;895default:896/* error */897msg_size = 0;898err = -EINVAL;899break;900}901902/*903* If we had an error on the last wr build, then904* break out. Possible errors include bogus WR905* type, and a bogus SGL length...906*/907if (err) {908break;909}910911/*912* Store flags913*/914c2_wr_set_flags(&wr, flags);915916/*917* Post the puppy!918*/919spin_lock_irqsave(&qp->lock, lock_flags);920err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size);921if (err) {922spin_unlock_irqrestore(&qp->lock, lock_flags);923break;924}925926/*927* Enqueue mq index to activity FIFO.928*/929c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count);930spin_unlock_irqrestore(&qp->lock, lock_flags);931932ib_wr = ib_wr->next;933}934935out:936if (err)937*bad_wr = ib_wr;938return err;939}940941int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,942struct ib_recv_wr **bad_wr)943{944struct c2_dev *c2dev = to_c2dev(ibqp->device);945struct c2_qp *qp = to_c2qp(ibqp);946union c2wr wr;947unsigned long lock_flags;948int err = 0;949950if (qp->state > IB_QPS_RTS) {951err = -EINVAL;952goto out;953}954955/*956* Try and post each work request957*/958while (ib_wr) {959u32 tot_len;960u8 actual_sge_count;961962if (ib_wr->num_sge > qp->recv_sgl_depth) {963err = -EINVAL;964break;965}966967/*968* Create local host-copy of the WR969*/970wr.rqwr.rq_hdr.user_hdr.hdr.context = ib_wr->wr_id;971c2_wr_set_id(&wr, CCWR_RECV);972c2_wr_set_flags(&wr, 0);973974/* sge_count is limited to eight bits. */975BUG_ON(ib_wr->num_sge >= 256);976err = move_sgl((struct c2_data_addr *) & (wr.rqwr.data),977ib_wr->sg_list,978ib_wr->num_sge, &tot_len, &actual_sge_count);979c2_wr_set_sge_count(&wr, actual_sge_count);980981/*982* If we had an error on the last wr build, then983* break out. Possible errors include bogus WR984* type, and a bogus SGL length...985*/986if (err) {987break;988}989990spin_lock_irqsave(&qp->lock, lock_flags);991err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size);992if (err) {993spin_unlock_irqrestore(&qp->lock, lock_flags);994break;995}996997/*998* Enqueue mq index to activity FIFO999*/1000c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count);1001spin_unlock_irqrestore(&qp->lock, lock_flags);10021003ib_wr = ib_wr->next;1004}10051006out:1007if (err)1008*bad_wr = ib_wr;1009return err;1010}10111012void __devinit c2_init_qp_table(struct c2_dev *c2dev)1013{1014spin_lock_init(&c2dev->qp_table.lock);1015idr_init(&c2dev->qp_table.idr);1016}10171018void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev)1019{1020idr_destroy(&c2dev->qp_table.idr);1021}102210231024