18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
48c2ecf20Sopenharmony_ci * Copyright (c) 2005, 2006 Cisco Systems, Inc. All rights reserved.
58c2ecf20Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
68c2ecf20Sopenharmony_ci * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
98c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
108c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
118c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
128c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
158c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
168c2ecf20Sopenharmony_ci *     conditions are met:
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
238c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
248c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
258c2ecf20Sopenharmony_ci *        provided with the distribution.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
288c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
298c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
308c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
318c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
328c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
338c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
348c2ecf20Sopenharmony_ci * SOFTWARE.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <linux/gfp.h>
388c2ecf20Sopenharmony_ci#include <linux/hardirq.h>
398c2ecf20Sopenharmony_ci#include <linux/sched.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include <asm/io.h>
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#include <rdma/ib_pack.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#include "mthca_dev.h"
468c2ecf20Sopenharmony_ci#include "mthca_cmd.h"
478c2ecf20Sopenharmony_ci#include "mthca_memfree.h"
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cienum {
508c2ecf20Sopenharmony_ci	MTHCA_MAX_DIRECT_CQ_SIZE = 4 * PAGE_SIZE
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cienum {
548c2ecf20Sopenharmony_ci	MTHCA_CQ_ENTRY_SIZE = 0x20
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cienum {
588c2ecf20Sopenharmony_ci	MTHCA_ATOMIC_BYTE_LEN = 8
598c2ecf20Sopenharmony_ci};
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * Must be packed because start is 64 bits but only aligned to 32 bits.
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_cistruct mthca_cq_context {
658c2ecf20Sopenharmony_ci	__be32 flags;
668c2ecf20Sopenharmony_ci	__be64 start;
678c2ecf20Sopenharmony_ci	__be32 logsize_usrpage;
688c2ecf20Sopenharmony_ci	__be32 error_eqn;	/* Tavor only */
698c2ecf20Sopenharmony_ci	__be32 comp_eqn;
708c2ecf20Sopenharmony_ci	__be32 pd;
718c2ecf20Sopenharmony_ci	__be32 lkey;
728c2ecf20Sopenharmony_ci	__be32 last_notified_index;
738c2ecf20Sopenharmony_ci	__be32 solicit_producer_index;
748c2ecf20Sopenharmony_ci	__be32 consumer_index;
758c2ecf20Sopenharmony_ci	__be32 producer_index;
768c2ecf20Sopenharmony_ci	__be32 cqn;
778c2ecf20Sopenharmony_ci	__be32 ci_db;		/* Arbel only */
788c2ecf20Sopenharmony_ci	__be32 state_db;	/* Arbel only */
798c2ecf20Sopenharmony_ci	u32    reserved;
808c2ecf20Sopenharmony_ci} __packed;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define MTHCA_CQ_STATUS_OK          ( 0 << 28)
838c2ecf20Sopenharmony_ci#define MTHCA_CQ_STATUS_OVERFLOW    ( 9 << 28)
848c2ecf20Sopenharmony_ci#define MTHCA_CQ_STATUS_WRITE_FAIL  (10 << 28)
858c2ecf20Sopenharmony_ci#define MTHCA_CQ_FLAG_TR            ( 1 << 18)
868c2ecf20Sopenharmony_ci#define MTHCA_CQ_FLAG_OI            ( 1 << 17)
878c2ecf20Sopenharmony_ci#define MTHCA_CQ_STATE_DISARMED     ( 0 <<  8)
888c2ecf20Sopenharmony_ci#define MTHCA_CQ_STATE_ARMED        ( 1 <<  8)
898c2ecf20Sopenharmony_ci#define MTHCA_CQ_STATE_ARMED_SOL    ( 4 <<  8)
908c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATE_FIRED        (10 <<  8)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cienum {
938c2ecf20Sopenharmony_ci	MTHCA_ERROR_CQE_OPCODE_MASK = 0xfe
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cienum {
978c2ecf20Sopenharmony_ci	SYNDROME_LOCAL_LENGTH_ERR 	 = 0x01,
988c2ecf20Sopenharmony_ci	SYNDROME_LOCAL_QP_OP_ERR  	 = 0x02,
998c2ecf20Sopenharmony_ci	SYNDROME_LOCAL_EEC_OP_ERR 	 = 0x03,
1008c2ecf20Sopenharmony_ci	SYNDROME_LOCAL_PROT_ERR   	 = 0x04,
1018c2ecf20Sopenharmony_ci	SYNDROME_WR_FLUSH_ERR     	 = 0x05,
1028c2ecf20Sopenharmony_ci	SYNDROME_MW_BIND_ERR      	 = 0x06,
1038c2ecf20Sopenharmony_ci	SYNDROME_BAD_RESP_ERR     	 = 0x10,
1048c2ecf20Sopenharmony_ci	SYNDROME_LOCAL_ACCESS_ERR 	 = 0x11,
1058c2ecf20Sopenharmony_ci	SYNDROME_REMOTE_INVAL_REQ_ERR 	 = 0x12,
1068c2ecf20Sopenharmony_ci	SYNDROME_REMOTE_ACCESS_ERR 	 = 0x13,
1078c2ecf20Sopenharmony_ci	SYNDROME_REMOTE_OP_ERR     	 = 0x14,
1088c2ecf20Sopenharmony_ci	SYNDROME_RETRY_EXC_ERR 		 = 0x15,
1098c2ecf20Sopenharmony_ci	SYNDROME_RNR_RETRY_EXC_ERR 	 = 0x16,
1108c2ecf20Sopenharmony_ci	SYNDROME_LOCAL_RDD_VIOL_ERR 	 = 0x20,
1118c2ecf20Sopenharmony_ci	SYNDROME_REMOTE_INVAL_RD_REQ_ERR = 0x21,
1128c2ecf20Sopenharmony_ci	SYNDROME_REMOTE_ABORTED_ERR 	 = 0x22,
1138c2ecf20Sopenharmony_ci	SYNDROME_INVAL_EECN_ERR 	 = 0x23,
1148c2ecf20Sopenharmony_ci	SYNDROME_INVAL_EEC_STATE_ERR 	 = 0x24
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistruct mthca_cqe {
1188c2ecf20Sopenharmony_ci	__be32 my_qpn;
1198c2ecf20Sopenharmony_ci	__be32 my_ee;
1208c2ecf20Sopenharmony_ci	__be32 rqpn;
1218c2ecf20Sopenharmony_ci	u8     sl_ipok;
1228c2ecf20Sopenharmony_ci	u8     g_mlpath;
1238c2ecf20Sopenharmony_ci	__be16 rlid;
1248c2ecf20Sopenharmony_ci	__be32 imm_etype_pkey_eec;
1258c2ecf20Sopenharmony_ci	__be32 byte_cnt;
1268c2ecf20Sopenharmony_ci	__be32 wqe;
1278c2ecf20Sopenharmony_ci	u8     opcode;
1288c2ecf20Sopenharmony_ci	u8     is_send;
1298c2ecf20Sopenharmony_ci	u8     reserved;
1308c2ecf20Sopenharmony_ci	u8     owner;
1318c2ecf20Sopenharmony_ci};
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistruct mthca_err_cqe {
1348c2ecf20Sopenharmony_ci	__be32 my_qpn;
1358c2ecf20Sopenharmony_ci	u32    reserved1[3];
1368c2ecf20Sopenharmony_ci	u8     syndrome;
1378c2ecf20Sopenharmony_ci	u8     vendor_err;
1388c2ecf20Sopenharmony_ci	__be16 db_cnt;
1398c2ecf20Sopenharmony_ci	u32    reserved2;
1408c2ecf20Sopenharmony_ci	__be32 wqe;
1418c2ecf20Sopenharmony_ci	u8     opcode;
1428c2ecf20Sopenharmony_ci	u8     reserved3[2];
1438c2ecf20Sopenharmony_ci	u8     owner;
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#define MTHCA_CQ_ENTRY_OWNER_SW      (0 << 7)
1478c2ecf20Sopenharmony_ci#define MTHCA_CQ_ENTRY_OWNER_HW      (1 << 7)
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci#define MTHCA_TAVOR_CQ_DB_INC_CI       (1 << 24)
1508c2ecf20Sopenharmony_ci#define MTHCA_TAVOR_CQ_DB_REQ_NOT      (2 << 24)
1518c2ecf20Sopenharmony_ci#define MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL  (3 << 24)
1528c2ecf20Sopenharmony_ci#define MTHCA_TAVOR_CQ_DB_SET_CI       (4 << 24)
1538c2ecf20Sopenharmony_ci#define MTHCA_TAVOR_CQ_DB_REQ_NOT_MULT (5 << 24)
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#define MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL  (1 << 24)
1568c2ecf20Sopenharmony_ci#define MTHCA_ARBEL_CQ_DB_REQ_NOT      (2 << 24)
1578c2ecf20Sopenharmony_ci#define MTHCA_ARBEL_CQ_DB_REQ_NOT_MULT (3 << 24)
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic inline struct mthca_cqe *get_cqe_from_buf(struct mthca_cq_buf *buf,
1608c2ecf20Sopenharmony_ci						 int entry)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	if (buf->is_direct)
1638c2ecf20Sopenharmony_ci		return buf->queue.direct.buf + (entry * MTHCA_CQ_ENTRY_SIZE);
1648c2ecf20Sopenharmony_ci	else
1658c2ecf20Sopenharmony_ci		return buf->queue.page_list[entry * MTHCA_CQ_ENTRY_SIZE / PAGE_SIZE].buf
1668c2ecf20Sopenharmony_ci			+ (entry * MTHCA_CQ_ENTRY_SIZE) % PAGE_SIZE;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic inline struct mthca_cqe *get_cqe(struct mthca_cq *cq, int entry)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	return get_cqe_from_buf(&cq->buf, entry);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic inline struct mthca_cqe *cqe_sw(struct mthca_cqe *cqe)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	return MTHCA_CQ_ENTRY_OWNER_HW & cqe->owner ? NULL : cqe;
1778c2ecf20Sopenharmony_ci}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistatic inline struct mthca_cqe *next_cqe_sw(struct mthca_cq *cq)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	return cqe_sw(get_cqe(cq, cq->cons_index & cq->ibcq.cqe));
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic inline void set_cqe_hw(struct mthca_cqe *cqe)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	__be32 *cqe = cqe_ptr;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	(void) cqe;	/* avoid warning if mthca_dbg compiled away... */
1948c2ecf20Sopenharmony_ci	mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
1958c2ecf20Sopenharmony_ci		  be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]),
1968c2ecf20Sopenharmony_ci		  be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]),
1978c2ecf20Sopenharmony_ci		  be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7]));
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/*
2018c2ecf20Sopenharmony_ci * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
2028c2ecf20Sopenharmony_ci * should be correct before calling update_cons_index().
2038c2ecf20Sopenharmony_ci */
2048c2ecf20Sopenharmony_cistatic inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
2058c2ecf20Sopenharmony_ci				     int incr)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
2088c2ecf20Sopenharmony_ci		*cq->set_ci_db = cpu_to_be32(cq->cons_index);
2098c2ecf20Sopenharmony_ci		wmb();
2108c2ecf20Sopenharmony_ci	} else {
2118c2ecf20Sopenharmony_ci		mthca_write64(MTHCA_TAVOR_CQ_DB_INC_CI | cq->cqn, incr - 1,
2128c2ecf20Sopenharmony_ci			      dev->kar + MTHCA_CQ_DOORBELL,
2138c2ecf20Sopenharmony_ci			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_civoid mthca_cq_completion(struct mthca_dev *dev, u32 cqn)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct mthca_cq *cq;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1));
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (!cq) {
2248c2ecf20Sopenharmony_ci		mthca_warn(dev, "Completion event for bogus CQ %08x\n", cqn);
2258c2ecf20Sopenharmony_ci		return;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	++cq->arm_sn;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_civoid mthca_cq_event(struct mthca_dev *dev, u32 cqn,
2348c2ecf20Sopenharmony_ci		    enum ib_event_type event_type)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct mthca_cq *cq;
2378c2ecf20Sopenharmony_ci	struct ib_event event;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	spin_lock(&dev->cq_table.lock);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	cq = mthca_array_get(&dev->cq_table.cq, cqn & (dev->limits.num_cqs - 1));
2428c2ecf20Sopenharmony_ci	if (cq)
2438c2ecf20Sopenharmony_ci		++cq->refcount;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	spin_unlock(&dev->cq_table.lock);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (!cq) {
2488c2ecf20Sopenharmony_ci		mthca_warn(dev, "Async event for bogus CQ %08x\n", cqn);
2498c2ecf20Sopenharmony_ci		return;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	event.device      = &dev->ib_dev;
2538c2ecf20Sopenharmony_ci	event.event       = event_type;
2548c2ecf20Sopenharmony_ci	event.element.cq  = &cq->ibcq;
2558c2ecf20Sopenharmony_ci	if (cq->ibcq.event_handler)
2568c2ecf20Sopenharmony_ci		cq->ibcq.event_handler(&event, cq->ibcq.cq_context);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	spin_lock(&dev->cq_table.lock);
2598c2ecf20Sopenharmony_ci	if (!--cq->refcount)
2608c2ecf20Sopenharmony_ci		wake_up(&cq->wait);
2618c2ecf20Sopenharmony_ci	spin_unlock(&dev->cq_table.lock);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic inline int is_recv_cqe(struct mthca_cqe *cqe)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	if ((cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
2678c2ecf20Sopenharmony_ci	    MTHCA_ERROR_CQE_OPCODE_MASK)
2688c2ecf20Sopenharmony_ci		return !(cqe->opcode & 0x01);
2698c2ecf20Sopenharmony_ci	else
2708c2ecf20Sopenharmony_ci		return !(cqe->is_send & 0x80);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_civoid mthca_cq_clean(struct mthca_dev *dev, struct mthca_cq *cq, u32 qpn,
2748c2ecf20Sopenharmony_ci		    struct mthca_srq *srq)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct mthca_cqe *cqe;
2778c2ecf20Sopenharmony_ci	u32 prod_index;
2788c2ecf20Sopenharmony_ci	int i, nfreed = 0;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	spin_lock_irq(&cq->lock);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/*
2838c2ecf20Sopenharmony_ci	 * First we need to find the current producer index, so we
2848c2ecf20Sopenharmony_ci	 * know where to start cleaning from.  It doesn't matter if HW
2858c2ecf20Sopenharmony_ci	 * adds new entries after this loop -- the QP we're worried
2868c2ecf20Sopenharmony_ci	 * about is already in RESET, so the new entries won't come
2878c2ecf20Sopenharmony_ci	 * from our QP and therefore don't need to be checked.
2888c2ecf20Sopenharmony_ci	 */
2898c2ecf20Sopenharmony_ci	for (prod_index = cq->cons_index;
2908c2ecf20Sopenharmony_ci	     cqe_sw(get_cqe(cq, prod_index & cq->ibcq.cqe));
2918c2ecf20Sopenharmony_ci	     ++prod_index)
2928c2ecf20Sopenharmony_ci		if (prod_index == cq->cons_index + cq->ibcq.cqe)
2938c2ecf20Sopenharmony_ci			break;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (0)
2968c2ecf20Sopenharmony_ci		mthca_dbg(dev, "Cleaning QPN %06x from CQN %06x; ci %d, pi %d\n",
2978c2ecf20Sopenharmony_ci			  qpn, cq->cqn, cq->cons_index, prod_index);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/*
3008c2ecf20Sopenharmony_ci	 * Now sweep backwards through the CQ, removing CQ entries
3018c2ecf20Sopenharmony_ci	 * that match our QP by copying older entries on top of them.
3028c2ecf20Sopenharmony_ci	 */
3038c2ecf20Sopenharmony_ci	while ((int) --prod_index - (int) cq->cons_index >= 0) {
3048c2ecf20Sopenharmony_ci		cqe = get_cqe(cq, prod_index & cq->ibcq.cqe);
3058c2ecf20Sopenharmony_ci		if (cqe->my_qpn == cpu_to_be32(qpn)) {
3068c2ecf20Sopenharmony_ci			if (srq && is_recv_cqe(cqe))
3078c2ecf20Sopenharmony_ci				mthca_free_srq_wqe(srq, be32_to_cpu(cqe->wqe));
3088c2ecf20Sopenharmony_ci			++nfreed;
3098c2ecf20Sopenharmony_ci		} else if (nfreed)
3108c2ecf20Sopenharmony_ci			memcpy(get_cqe(cq, (prod_index + nfreed) & cq->ibcq.cqe),
3118c2ecf20Sopenharmony_ci			       cqe, MTHCA_CQ_ENTRY_SIZE);
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (nfreed) {
3158c2ecf20Sopenharmony_ci		for (i = 0; i < nfreed; ++i)
3168c2ecf20Sopenharmony_ci			set_cqe_hw(get_cqe(cq, (cq->cons_index + i) & cq->ibcq.cqe));
3178c2ecf20Sopenharmony_ci		wmb();
3188c2ecf20Sopenharmony_ci		cq->cons_index += nfreed;
3198c2ecf20Sopenharmony_ci		update_cons_index(dev, cq, nfreed);
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	spin_unlock_irq(&cq->lock);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_civoid mthca_cq_resize_copy_cqes(struct mthca_cq *cq)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	int i;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * In Tavor mode, the hardware keeps the consumer and producer
3318c2ecf20Sopenharmony_ci	 * indices mod the CQ size.  Since we might be making the CQ
3328c2ecf20Sopenharmony_ci	 * bigger, we need to deal with the case where the producer
3338c2ecf20Sopenharmony_ci	 * index wrapped around before the CQ was resized.
3348c2ecf20Sopenharmony_ci	 */
3358c2ecf20Sopenharmony_ci	if (!mthca_is_memfree(to_mdev(cq->ibcq.device)) &&
3368c2ecf20Sopenharmony_ci	    cq->ibcq.cqe < cq->resize_buf->cqe) {
3378c2ecf20Sopenharmony_ci		cq->cons_index &= cq->ibcq.cqe;
3388c2ecf20Sopenharmony_ci		if (cqe_sw(get_cqe(cq, cq->ibcq.cqe)))
3398c2ecf20Sopenharmony_ci			cq->cons_index -= cq->ibcq.cqe + 1;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	for (i = cq->cons_index; cqe_sw(get_cqe(cq, i & cq->ibcq.cqe)); ++i)
3438c2ecf20Sopenharmony_ci		memcpy(get_cqe_from_buf(&cq->resize_buf->buf,
3448c2ecf20Sopenharmony_ci					i & cq->resize_buf->cqe),
3458c2ecf20Sopenharmony_ci		       get_cqe(cq, i & cq->ibcq.cqe), MTHCA_CQ_ENTRY_SIZE);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ciint mthca_alloc_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int nent)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	int ret;
3518c2ecf20Sopenharmony_ci	int i;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	ret = mthca_buf_alloc(dev, nent * MTHCA_CQ_ENTRY_SIZE,
3548c2ecf20Sopenharmony_ci			      MTHCA_MAX_DIRECT_CQ_SIZE,
3558c2ecf20Sopenharmony_ci			      &buf->queue, &buf->is_direct,
3568c2ecf20Sopenharmony_ci			      &dev->driver_pd, 1, &buf->mr);
3578c2ecf20Sopenharmony_ci	if (ret)
3588c2ecf20Sopenharmony_ci		return ret;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	for (i = 0; i < nent; ++i)
3618c2ecf20Sopenharmony_ci		set_cqe_hw(get_cqe_from_buf(buf, i));
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return 0;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_civoid mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq_buf *buf, int cqe)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	mthca_buf_free(dev, (cqe + 1) * MTHCA_CQ_ENTRY_SIZE, &buf->queue,
3698c2ecf20Sopenharmony_ci		       buf->is_direct, &buf->mr);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
3738c2ecf20Sopenharmony_ci			     struct mthca_qp *qp, int wqe_index, int is_send,
3748c2ecf20Sopenharmony_ci			     struct mthca_err_cqe *cqe,
3758c2ecf20Sopenharmony_ci			     struct ib_wc *entry, int *free_cqe)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	int dbd;
3788c2ecf20Sopenharmony_ci	__be32 new_wqe;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
3818c2ecf20Sopenharmony_ci		mthca_dbg(dev, "local QP operation err "
3828c2ecf20Sopenharmony_ci			  "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n",
3838c2ecf20Sopenharmony_ci			  be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe),
3848c2ecf20Sopenharmony_ci			  cq->cqn, cq->cons_index);
3858c2ecf20Sopenharmony_ci		dump_cqe(dev, cqe);
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/*
3898c2ecf20Sopenharmony_ci	 * For completions in error, only work request ID, status, vendor error
3908c2ecf20Sopenharmony_ci	 * (and freed resource count for RD) have to be set.
3918c2ecf20Sopenharmony_ci	 */
3928c2ecf20Sopenharmony_ci	switch (cqe->syndrome) {
3938c2ecf20Sopenharmony_ci	case SYNDROME_LOCAL_LENGTH_ERR:
3948c2ecf20Sopenharmony_ci		entry->status = IB_WC_LOC_LEN_ERR;
3958c2ecf20Sopenharmony_ci		break;
3968c2ecf20Sopenharmony_ci	case SYNDROME_LOCAL_QP_OP_ERR:
3978c2ecf20Sopenharmony_ci		entry->status = IB_WC_LOC_QP_OP_ERR;
3988c2ecf20Sopenharmony_ci		break;
3998c2ecf20Sopenharmony_ci	case SYNDROME_LOCAL_EEC_OP_ERR:
4008c2ecf20Sopenharmony_ci		entry->status = IB_WC_LOC_EEC_OP_ERR;
4018c2ecf20Sopenharmony_ci		break;
4028c2ecf20Sopenharmony_ci	case SYNDROME_LOCAL_PROT_ERR:
4038c2ecf20Sopenharmony_ci		entry->status = IB_WC_LOC_PROT_ERR;
4048c2ecf20Sopenharmony_ci		break;
4058c2ecf20Sopenharmony_ci	case SYNDROME_WR_FLUSH_ERR:
4068c2ecf20Sopenharmony_ci		entry->status = IB_WC_WR_FLUSH_ERR;
4078c2ecf20Sopenharmony_ci		break;
4088c2ecf20Sopenharmony_ci	case SYNDROME_MW_BIND_ERR:
4098c2ecf20Sopenharmony_ci		entry->status = IB_WC_MW_BIND_ERR;
4108c2ecf20Sopenharmony_ci		break;
4118c2ecf20Sopenharmony_ci	case SYNDROME_BAD_RESP_ERR:
4128c2ecf20Sopenharmony_ci		entry->status = IB_WC_BAD_RESP_ERR;
4138c2ecf20Sopenharmony_ci		break;
4148c2ecf20Sopenharmony_ci	case SYNDROME_LOCAL_ACCESS_ERR:
4158c2ecf20Sopenharmony_ci		entry->status = IB_WC_LOC_ACCESS_ERR;
4168c2ecf20Sopenharmony_ci		break;
4178c2ecf20Sopenharmony_ci	case SYNDROME_REMOTE_INVAL_REQ_ERR:
4188c2ecf20Sopenharmony_ci		entry->status = IB_WC_REM_INV_REQ_ERR;
4198c2ecf20Sopenharmony_ci		break;
4208c2ecf20Sopenharmony_ci	case SYNDROME_REMOTE_ACCESS_ERR:
4218c2ecf20Sopenharmony_ci		entry->status = IB_WC_REM_ACCESS_ERR;
4228c2ecf20Sopenharmony_ci		break;
4238c2ecf20Sopenharmony_ci	case SYNDROME_REMOTE_OP_ERR:
4248c2ecf20Sopenharmony_ci		entry->status = IB_WC_REM_OP_ERR;
4258c2ecf20Sopenharmony_ci		break;
4268c2ecf20Sopenharmony_ci	case SYNDROME_RETRY_EXC_ERR:
4278c2ecf20Sopenharmony_ci		entry->status = IB_WC_RETRY_EXC_ERR;
4288c2ecf20Sopenharmony_ci		break;
4298c2ecf20Sopenharmony_ci	case SYNDROME_RNR_RETRY_EXC_ERR:
4308c2ecf20Sopenharmony_ci		entry->status = IB_WC_RNR_RETRY_EXC_ERR;
4318c2ecf20Sopenharmony_ci		break;
4328c2ecf20Sopenharmony_ci	case SYNDROME_LOCAL_RDD_VIOL_ERR:
4338c2ecf20Sopenharmony_ci		entry->status = IB_WC_LOC_RDD_VIOL_ERR;
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci	case SYNDROME_REMOTE_INVAL_RD_REQ_ERR:
4368c2ecf20Sopenharmony_ci		entry->status = IB_WC_REM_INV_RD_REQ_ERR;
4378c2ecf20Sopenharmony_ci		break;
4388c2ecf20Sopenharmony_ci	case SYNDROME_REMOTE_ABORTED_ERR:
4398c2ecf20Sopenharmony_ci		entry->status = IB_WC_REM_ABORT_ERR;
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	case SYNDROME_INVAL_EECN_ERR:
4428c2ecf20Sopenharmony_ci		entry->status = IB_WC_INV_EECN_ERR;
4438c2ecf20Sopenharmony_ci		break;
4448c2ecf20Sopenharmony_ci	case SYNDROME_INVAL_EEC_STATE_ERR:
4458c2ecf20Sopenharmony_ci		entry->status = IB_WC_INV_EEC_STATE_ERR;
4468c2ecf20Sopenharmony_ci		break;
4478c2ecf20Sopenharmony_ci	default:
4488c2ecf20Sopenharmony_ci		entry->status = IB_WC_GENERAL_ERR;
4498c2ecf20Sopenharmony_ci		break;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	entry->vendor_err = cqe->vendor_err;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/*
4558c2ecf20Sopenharmony_ci	 * Mem-free HCAs always generate one CQE per WQE, even in the
4568c2ecf20Sopenharmony_ci	 * error case, so we don't have to check the doorbell count, etc.
4578c2ecf20Sopenharmony_ci	 */
4588c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev))
4598c2ecf20Sopenharmony_ci		return;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	mthca_free_err_wqe(dev, qp, is_send, wqe_index, &dbd, &new_wqe);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/*
4648c2ecf20Sopenharmony_ci	 * If we're at the end of the WQE chain, or we've used up our
4658c2ecf20Sopenharmony_ci	 * doorbell count, free the CQE.  Otherwise just update it for
4668c2ecf20Sopenharmony_ci	 * the next poll operation.
4678c2ecf20Sopenharmony_ci	 */
4688c2ecf20Sopenharmony_ci	if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd))
4698c2ecf20Sopenharmony_ci		return;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	be16_add_cpu(&cqe->db_cnt, -dbd);
4728c2ecf20Sopenharmony_ci	cqe->wqe      = new_wqe;
4738c2ecf20Sopenharmony_ci	cqe->syndrome = SYNDROME_WR_FLUSH_ERR;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	*free_cqe = 0;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic inline int mthca_poll_one(struct mthca_dev *dev,
4798c2ecf20Sopenharmony_ci				 struct mthca_cq *cq,
4808c2ecf20Sopenharmony_ci				 struct mthca_qp **cur_qp,
4818c2ecf20Sopenharmony_ci				 int *freed,
4828c2ecf20Sopenharmony_ci				 struct ib_wc *entry)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct mthca_wq *wq;
4858c2ecf20Sopenharmony_ci	struct mthca_cqe *cqe;
4868c2ecf20Sopenharmony_ci	int wqe_index;
4878c2ecf20Sopenharmony_ci	int is_error;
4888c2ecf20Sopenharmony_ci	int is_send;
4898c2ecf20Sopenharmony_ci	int free_cqe = 1;
4908c2ecf20Sopenharmony_ci	int err = 0;
4918c2ecf20Sopenharmony_ci	u16 checksum;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	cqe = next_cqe_sw(cq);
4948c2ecf20Sopenharmony_ci	if (!cqe)
4958c2ecf20Sopenharmony_ci		return -EAGAIN;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/*
4988c2ecf20Sopenharmony_ci	 * Make sure we read CQ entry contents after we've checked the
4998c2ecf20Sopenharmony_ci	 * ownership bit.
5008c2ecf20Sopenharmony_ci	 */
5018c2ecf20Sopenharmony_ci	rmb();
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (0) {
5048c2ecf20Sopenharmony_ci		mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
5058c2ecf20Sopenharmony_ci			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
5068c2ecf20Sopenharmony_ci			  be32_to_cpu(cqe->wqe));
5078c2ecf20Sopenharmony_ci		dump_cqe(dev, cqe);
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
5118c2ecf20Sopenharmony_ci		MTHCA_ERROR_CQE_OPCODE_MASK;
5128c2ecf20Sopenharmony_ci	is_send  = is_error ? cqe->opcode & 0x01 : cqe->is_send & 0x80;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	if (!*cur_qp || be32_to_cpu(cqe->my_qpn) != (*cur_qp)->qpn) {
5158c2ecf20Sopenharmony_ci		/*
5168c2ecf20Sopenharmony_ci		 * We do not have to take the QP table lock here,
5178c2ecf20Sopenharmony_ci		 * because CQs will be locked while QPs are removed
5188c2ecf20Sopenharmony_ci		 * from the table.
5198c2ecf20Sopenharmony_ci		 */
5208c2ecf20Sopenharmony_ci		*cur_qp = mthca_array_get(&dev->qp_table.qp,
5218c2ecf20Sopenharmony_ci					  be32_to_cpu(cqe->my_qpn) &
5228c2ecf20Sopenharmony_ci					  (dev->limits.num_qps - 1));
5238c2ecf20Sopenharmony_ci		if (!*cur_qp) {
5248c2ecf20Sopenharmony_ci			mthca_warn(dev, "CQ entry for unknown QP %06x\n",
5258c2ecf20Sopenharmony_ci				   be32_to_cpu(cqe->my_qpn) & 0xffffff);
5268c2ecf20Sopenharmony_ci			err = -EINVAL;
5278c2ecf20Sopenharmony_ci			goto out;
5288c2ecf20Sopenharmony_ci		}
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	entry->qp = &(*cur_qp)->ibqp;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (is_send) {
5348c2ecf20Sopenharmony_ci		wq = &(*cur_qp)->sq;
5358c2ecf20Sopenharmony_ci		wqe_index = ((be32_to_cpu(cqe->wqe) - (*cur_qp)->send_wqe_offset)
5368c2ecf20Sopenharmony_ci			     >> wq->wqe_shift);
5378c2ecf20Sopenharmony_ci		entry->wr_id = (*cur_qp)->wrid[wqe_index +
5388c2ecf20Sopenharmony_ci					       (*cur_qp)->rq.max];
5398c2ecf20Sopenharmony_ci	} else if ((*cur_qp)->ibqp.srq) {
5408c2ecf20Sopenharmony_ci		struct mthca_srq *srq = to_msrq((*cur_qp)->ibqp.srq);
5418c2ecf20Sopenharmony_ci		u32 wqe = be32_to_cpu(cqe->wqe);
5428c2ecf20Sopenharmony_ci		wq = NULL;
5438c2ecf20Sopenharmony_ci		wqe_index = wqe >> srq->wqe_shift;
5448c2ecf20Sopenharmony_ci		entry->wr_id = srq->wrid[wqe_index];
5458c2ecf20Sopenharmony_ci		mthca_free_srq_wqe(srq, wqe);
5468c2ecf20Sopenharmony_ci	} else {
5478c2ecf20Sopenharmony_ci		s32 wqe;
5488c2ecf20Sopenharmony_ci		wq = &(*cur_qp)->rq;
5498c2ecf20Sopenharmony_ci		wqe = be32_to_cpu(cqe->wqe);
5508c2ecf20Sopenharmony_ci		wqe_index = wqe >> wq->wqe_shift;
5518c2ecf20Sopenharmony_ci		/*
5528c2ecf20Sopenharmony_ci		 * WQE addr == base - 1 might be reported in receive completion
5538c2ecf20Sopenharmony_ci		 * with error instead of (rq size - 1) by Sinai FW 1.0.800 and
5548c2ecf20Sopenharmony_ci		 * Arbel FW 5.1.400.  This bug should be fixed in later FW revs.
5558c2ecf20Sopenharmony_ci		 */
5568c2ecf20Sopenharmony_ci		if (unlikely(wqe_index < 0))
5578c2ecf20Sopenharmony_ci			wqe_index = wq->max - 1;
5588c2ecf20Sopenharmony_ci		entry->wr_id = (*cur_qp)->wrid[wqe_index];
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (wq) {
5628c2ecf20Sopenharmony_ci		if (wq->last_comp < wqe_index)
5638c2ecf20Sopenharmony_ci			wq->tail += wqe_index - wq->last_comp;
5648c2ecf20Sopenharmony_ci		else
5658c2ecf20Sopenharmony_ci			wq->tail += wqe_index + wq->max - wq->last_comp;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci		wq->last_comp = wqe_index;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (is_error) {
5718c2ecf20Sopenharmony_ci		handle_error_cqe(dev, cq, *cur_qp, wqe_index, is_send,
5728c2ecf20Sopenharmony_ci				 (struct mthca_err_cqe *) cqe,
5738c2ecf20Sopenharmony_ci				 entry, &free_cqe);
5748c2ecf20Sopenharmony_ci		goto out;
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (is_send) {
5788c2ecf20Sopenharmony_ci		entry->wc_flags = 0;
5798c2ecf20Sopenharmony_ci		switch (cqe->opcode) {
5808c2ecf20Sopenharmony_ci		case MTHCA_OPCODE_RDMA_WRITE:
5818c2ecf20Sopenharmony_ci			entry->opcode    = IB_WC_RDMA_WRITE;
5828c2ecf20Sopenharmony_ci			break;
5838c2ecf20Sopenharmony_ci		case MTHCA_OPCODE_RDMA_WRITE_IMM:
5848c2ecf20Sopenharmony_ci			entry->opcode    = IB_WC_RDMA_WRITE;
5858c2ecf20Sopenharmony_ci			entry->wc_flags |= IB_WC_WITH_IMM;
5868c2ecf20Sopenharmony_ci			break;
5878c2ecf20Sopenharmony_ci		case MTHCA_OPCODE_SEND:
5888c2ecf20Sopenharmony_ci			entry->opcode    = IB_WC_SEND;
5898c2ecf20Sopenharmony_ci			break;
5908c2ecf20Sopenharmony_ci		case MTHCA_OPCODE_SEND_IMM:
5918c2ecf20Sopenharmony_ci			entry->opcode    = IB_WC_SEND;
5928c2ecf20Sopenharmony_ci			entry->wc_flags |= IB_WC_WITH_IMM;
5938c2ecf20Sopenharmony_ci			break;
5948c2ecf20Sopenharmony_ci		case MTHCA_OPCODE_RDMA_READ:
5958c2ecf20Sopenharmony_ci			entry->opcode    = IB_WC_RDMA_READ;
5968c2ecf20Sopenharmony_ci			entry->byte_len  = be32_to_cpu(cqe->byte_cnt);
5978c2ecf20Sopenharmony_ci			break;
5988c2ecf20Sopenharmony_ci		case MTHCA_OPCODE_ATOMIC_CS:
5998c2ecf20Sopenharmony_ci			entry->opcode    = IB_WC_COMP_SWAP;
6008c2ecf20Sopenharmony_ci			entry->byte_len  = MTHCA_ATOMIC_BYTE_LEN;
6018c2ecf20Sopenharmony_ci			break;
6028c2ecf20Sopenharmony_ci		case MTHCA_OPCODE_ATOMIC_FA:
6038c2ecf20Sopenharmony_ci			entry->opcode    = IB_WC_FETCH_ADD;
6048c2ecf20Sopenharmony_ci			entry->byte_len  = MTHCA_ATOMIC_BYTE_LEN;
6058c2ecf20Sopenharmony_ci			break;
6068c2ecf20Sopenharmony_ci		default:
6078c2ecf20Sopenharmony_ci			entry->opcode = 0xFF;
6088c2ecf20Sopenharmony_ci			break;
6098c2ecf20Sopenharmony_ci		}
6108c2ecf20Sopenharmony_ci	} else {
6118c2ecf20Sopenharmony_ci		entry->byte_len = be32_to_cpu(cqe->byte_cnt);
6128c2ecf20Sopenharmony_ci		switch (cqe->opcode & 0x1f) {
6138c2ecf20Sopenharmony_ci		case IB_OPCODE_SEND_LAST_WITH_IMMEDIATE:
6148c2ecf20Sopenharmony_ci		case IB_OPCODE_SEND_ONLY_WITH_IMMEDIATE:
6158c2ecf20Sopenharmony_ci			entry->wc_flags = IB_WC_WITH_IMM;
6168c2ecf20Sopenharmony_ci			entry->ex.imm_data = cqe->imm_etype_pkey_eec;
6178c2ecf20Sopenharmony_ci			entry->opcode = IB_WC_RECV;
6188c2ecf20Sopenharmony_ci			break;
6198c2ecf20Sopenharmony_ci		case IB_OPCODE_RDMA_WRITE_LAST_WITH_IMMEDIATE:
6208c2ecf20Sopenharmony_ci		case IB_OPCODE_RDMA_WRITE_ONLY_WITH_IMMEDIATE:
6218c2ecf20Sopenharmony_ci			entry->wc_flags = IB_WC_WITH_IMM;
6228c2ecf20Sopenharmony_ci			entry->ex.imm_data = cqe->imm_etype_pkey_eec;
6238c2ecf20Sopenharmony_ci			entry->opcode = IB_WC_RECV_RDMA_WITH_IMM;
6248c2ecf20Sopenharmony_ci			break;
6258c2ecf20Sopenharmony_ci		default:
6268c2ecf20Sopenharmony_ci			entry->wc_flags = 0;
6278c2ecf20Sopenharmony_ci			entry->opcode = IB_WC_RECV;
6288c2ecf20Sopenharmony_ci			break;
6298c2ecf20Sopenharmony_ci		}
6308c2ecf20Sopenharmony_ci		entry->slid 	   = be16_to_cpu(cqe->rlid);
6318c2ecf20Sopenharmony_ci		entry->sl   	   = cqe->sl_ipok >> 4;
6328c2ecf20Sopenharmony_ci		entry->src_qp 	   = be32_to_cpu(cqe->rqpn) & 0xffffff;
6338c2ecf20Sopenharmony_ci		entry->dlid_path_bits = cqe->g_mlpath & 0x7f;
6348c2ecf20Sopenharmony_ci		entry->pkey_index  = be32_to_cpu(cqe->imm_etype_pkey_eec) >> 16;
6358c2ecf20Sopenharmony_ci		entry->wc_flags   |= cqe->g_mlpath & 0x80 ? IB_WC_GRH : 0;
6368c2ecf20Sopenharmony_ci		checksum = (be32_to_cpu(cqe->rqpn) >> 24) |
6378c2ecf20Sopenharmony_ci				((be32_to_cpu(cqe->my_ee) >> 16) & 0xff00);
6388c2ecf20Sopenharmony_ci		entry->wc_flags	  |=  (cqe->sl_ipok & 1 && checksum == 0xffff) ?
6398c2ecf20Sopenharmony_ci							IB_WC_IP_CSUM_OK : 0;
6408c2ecf20Sopenharmony_ci	}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	entry->status = IB_WC_SUCCESS;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci out:
6458c2ecf20Sopenharmony_ci	if (likely(free_cqe)) {
6468c2ecf20Sopenharmony_ci		set_cqe_hw(cqe);
6478c2ecf20Sopenharmony_ci		++(*freed);
6488c2ecf20Sopenharmony_ci		++cq->cons_index;
6498c2ecf20Sopenharmony_ci	}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	return err;
6528c2ecf20Sopenharmony_ci}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ciint mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
6558c2ecf20Sopenharmony_ci		  struct ib_wc *entry)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	struct mthca_dev *dev = to_mdev(ibcq->device);
6588c2ecf20Sopenharmony_ci	struct mthca_cq *cq = to_mcq(ibcq);
6598c2ecf20Sopenharmony_ci	struct mthca_qp *qp = NULL;
6608c2ecf20Sopenharmony_ci	unsigned long flags;
6618c2ecf20Sopenharmony_ci	int err = 0;
6628c2ecf20Sopenharmony_ci	int freed = 0;
6638c2ecf20Sopenharmony_ci	int npolled;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&cq->lock, flags);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	npolled = 0;
6688c2ecf20Sopenharmony_cirepoll:
6698c2ecf20Sopenharmony_ci	while (npolled < num_entries) {
6708c2ecf20Sopenharmony_ci		err = mthca_poll_one(dev, cq, &qp,
6718c2ecf20Sopenharmony_ci				     &freed, entry + npolled);
6728c2ecf20Sopenharmony_ci		if (err)
6738c2ecf20Sopenharmony_ci			break;
6748c2ecf20Sopenharmony_ci		++npolled;
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (freed) {
6788c2ecf20Sopenharmony_ci		wmb();
6798c2ecf20Sopenharmony_ci		update_cons_index(dev, cq, freed);
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	/*
6838c2ecf20Sopenharmony_ci	 * If a CQ resize is in progress and we discovered that the
6848c2ecf20Sopenharmony_ci	 * old buffer is empty, then peek in the new buffer, and if
6858c2ecf20Sopenharmony_ci	 * it's not empty, switch to the new buffer and continue
6868c2ecf20Sopenharmony_ci	 * polling there.
6878c2ecf20Sopenharmony_ci	 */
6888c2ecf20Sopenharmony_ci	if (unlikely(err == -EAGAIN && cq->resize_buf &&
6898c2ecf20Sopenharmony_ci		     cq->resize_buf->state == CQ_RESIZE_READY)) {
6908c2ecf20Sopenharmony_ci		/*
6918c2ecf20Sopenharmony_ci		 * In Tavor mode, the hardware keeps the producer
6928c2ecf20Sopenharmony_ci		 * index modulo the CQ size.  Since we might be making
6938c2ecf20Sopenharmony_ci		 * the CQ bigger, we need to mask our consumer index
6948c2ecf20Sopenharmony_ci		 * using the size of the old CQ buffer before looking
6958c2ecf20Sopenharmony_ci		 * in the new CQ buffer.
6968c2ecf20Sopenharmony_ci		 */
6978c2ecf20Sopenharmony_ci		if (!mthca_is_memfree(dev))
6988c2ecf20Sopenharmony_ci			cq->cons_index &= cq->ibcq.cqe;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		if (cqe_sw(get_cqe_from_buf(&cq->resize_buf->buf,
7018c2ecf20Sopenharmony_ci					    cq->cons_index & cq->resize_buf->cqe))) {
7028c2ecf20Sopenharmony_ci			struct mthca_cq_buf tbuf;
7038c2ecf20Sopenharmony_ci			int tcqe;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci			tbuf         = cq->buf;
7068c2ecf20Sopenharmony_ci			tcqe         = cq->ibcq.cqe;
7078c2ecf20Sopenharmony_ci			cq->buf      = cq->resize_buf->buf;
7088c2ecf20Sopenharmony_ci			cq->ibcq.cqe = cq->resize_buf->cqe;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci			cq->resize_buf->buf   = tbuf;
7118c2ecf20Sopenharmony_ci			cq->resize_buf->cqe   = tcqe;
7128c2ecf20Sopenharmony_ci			cq->resize_buf->state = CQ_RESIZE_SWAPPED;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci			goto repoll;
7158c2ecf20Sopenharmony_ci		}
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&cq->lock, flags);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	return err == 0 || err == -EAGAIN ? npolled : err;
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ciint mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	u32 dbhi = ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
7268c2ecf20Sopenharmony_ci		    MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
7278c2ecf20Sopenharmony_ci		    MTHCA_TAVOR_CQ_DB_REQ_NOT) |
7288c2ecf20Sopenharmony_ci		to_mcq(cq)->cqn;
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	mthca_write64(dbhi, 0xffffffff, to_mdev(cq->device)->kar + MTHCA_CQ_DOORBELL,
7318c2ecf20Sopenharmony_ci		      MTHCA_GET_DOORBELL_LOCK(&to_mdev(cq->device)->doorbell_lock));
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	return 0;
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ciint mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	struct mthca_cq *cq = to_mcq(ibcq);
7398c2ecf20Sopenharmony_ci	__be32 db_rec[2];
7408c2ecf20Sopenharmony_ci	u32 dbhi;
7418c2ecf20Sopenharmony_ci	u32 sn = cq->arm_sn & 3;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	db_rec[0] = cpu_to_be32(cq->cons_index);
7448c2ecf20Sopenharmony_ci	db_rec[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
7458c2ecf20Sopenharmony_ci				((flags & IB_CQ_SOLICITED_MASK) ==
7468c2ecf20Sopenharmony_ci				 IB_CQ_SOLICITED ? 1 : 2));
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	mthca_write_db_rec(db_rec, cq->arm_db);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	/*
7518c2ecf20Sopenharmony_ci	 * Make sure that the doorbell record in host memory is
7528c2ecf20Sopenharmony_ci	 * written before ringing the doorbell via PCI MMIO.
7538c2ecf20Sopenharmony_ci	 */
7548c2ecf20Sopenharmony_ci	wmb();
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	dbhi = (sn << 28) |
7578c2ecf20Sopenharmony_ci		((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
7588c2ecf20Sopenharmony_ci		 MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
7598c2ecf20Sopenharmony_ci		 MTHCA_ARBEL_CQ_DB_REQ_NOT) | cq->cqn;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	mthca_write64(dbhi, cq->cons_index,
7628c2ecf20Sopenharmony_ci		      to_mdev(ibcq->device)->kar + MTHCA_CQ_DOORBELL,
7638c2ecf20Sopenharmony_ci		      MTHCA_GET_DOORBELL_LOCK(&to_mdev(ibcq->device)->doorbell_lock));
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	return 0;
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ciint mthca_init_cq(struct mthca_dev *dev, int nent,
7698c2ecf20Sopenharmony_ci		  struct mthca_ucontext *ctx, u32 pdn,
7708c2ecf20Sopenharmony_ci		  struct mthca_cq *cq)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct mthca_mailbox *mailbox;
7738c2ecf20Sopenharmony_ci	struct mthca_cq_context *cq_context;
7748c2ecf20Sopenharmony_ci	int err = -ENOMEM;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	cq->ibcq.cqe  = nent - 1;
7778c2ecf20Sopenharmony_ci	cq->is_kernel = !ctx;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	cq->cqn = mthca_alloc(&dev->cq_table.alloc);
7808c2ecf20Sopenharmony_ci	if (cq->cqn == -1)
7818c2ecf20Sopenharmony_ci		return -ENOMEM;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
7848c2ecf20Sopenharmony_ci		err = mthca_table_get(dev, dev->cq_table.table, cq->cqn);
7858c2ecf20Sopenharmony_ci		if (err)
7868c2ecf20Sopenharmony_ci			goto err_out;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci		if (cq->is_kernel) {
7898c2ecf20Sopenharmony_ci			cq->arm_sn = 1;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci			err = -ENOMEM;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci			cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
7948c2ecf20Sopenharmony_ci							     cq->cqn, &cq->set_ci_db);
7958c2ecf20Sopenharmony_ci			if (cq->set_ci_db_index < 0)
7968c2ecf20Sopenharmony_ci				goto err_out_icm;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci			cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
7998c2ecf20Sopenharmony_ci							  cq->cqn, &cq->arm_db);
8008c2ecf20Sopenharmony_ci			if (cq->arm_db_index < 0)
8018c2ecf20Sopenharmony_ci				goto err_out_ci;
8028c2ecf20Sopenharmony_ci		}
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
8068c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox)) {
8078c2ecf20Sopenharmony_ci		err = PTR_ERR(mailbox);
8088c2ecf20Sopenharmony_ci		goto err_out_arm;
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	cq_context = mailbox->buf;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (cq->is_kernel) {
8148c2ecf20Sopenharmony_ci		err = mthca_alloc_cq_buf(dev, &cq->buf, nent);
8158c2ecf20Sopenharmony_ci		if (err)
8168c2ecf20Sopenharmony_ci			goto err_out_mailbox;
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	spin_lock_init(&cq->lock);
8208c2ecf20Sopenharmony_ci	cq->refcount = 1;
8218c2ecf20Sopenharmony_ci	init_waitqueue_head(&cq->wait);
8228c2ecf20Sopenharmony_ci	mutex_init(&cq->mutex);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	memset(cq_context, 0, sizeof *cq_context);
8258c2ecf20Sopenharmony_ci	cq_context->flags           = cpu_to_be32(MTHCA_CQ_STATUS_OK      |
8268c2ecf20Sopenharmony_ci						  MTHCA_CQ_STATE_DISARMED |
8278c2ecf20Sopenharmony_ci						  MTHCA_CQ_FLAG_TR);
8288c2ecf20Sopenharmony_ci	cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24);
8298c2ecf20Sopenharmony_ci	if (ctx)
8308c2ecf20Sopenharmony_ci		cq_context->logsize_usrpage |= cpu_to_be32(ctx->uar.index);
8318c2ecf20Sopenharmony_ci	else
8328c2ecf20Sopenharmony_ci		cq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index);
8338c2ecf20Sopenharmony_ci	cq_context->error_eqn       = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
8348c2ecf20Sopenharmony_ci	cq_context->comp_eqn        = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
8358c2ecf20Sopenharmony_ci	cq_context->pd              = cpu_to_be32(pdn);
8368c2ecf20Sopenharmony_ci	cq_context->lkey            = cpu_to_be32(cq->buf.mr.ibmr.lkey);
8378c2ecf20Sopenharmony_ci	cq_context->cqn             = cpu_to_be32(cq->cqn);
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
8408c2ecf20Sopenharmony_ci		cq_context->ci_db    = cpu_to_be32(cq->set_ci_db_index);
8418c2ecf20Sopenharmony_ci		cq_context->state_db = cpu_to_be32(cq->arm_db_index);
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn);
8458c2ecf20Sopenharmony_ci	if (err) {
8468c2ecf20Sopenharmony_ci		mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
8478c2ecf20Sopenharmony_ci		goto err_out_free_mr;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	spin_lock_irq(&dev->cq_table.lock);
8518c2ecf20Sopenharmony_ci	err = mthca_array_set(&dev->cq_table.cq,
8528c2ecf20Sopenharmony_ci			      cq->cqn & (dev->limits.num_cqs - 1), cq);
8538c2ecf20Sopenharmony_ci	if (err) {
8548c2ecf20Sopenharmony_ci		spin_unlock_irq(&dev->cq_table.lock);
8558c2ecf20Sopenharmony_ci		goto err_out_free_mr;
8568c2ecf20Sopenharmony_ci	}
8578c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev->cq_table.lock);
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	cq->cons_index = 0;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	return 0;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cierr_out_free_mr:
8668c2ecf20Sopenharmony_ci	if (cq->is_kernel)
8678c2ecf20Sopenharmony_ci		mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cierr_out_mailbox:
8708c2ecf20Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_cierr_out_arm:
8738c2ecf20Sopenharmony_ci	if (cq->is_kernel && mthca_is_memfree(dev))
8748c2ecf20Sopenharmony_ci		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cierr_out_ci:
8778c2ecf20Sopenharmony_ci	if (cq->is_kernel && mthca_is_memfree(dev))
8788c2ecf20Sopenharmony_ci		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cierr_out_icm:
8818c2ecf20Sopenharmony_ci	mthca_table_put(dev, dev->cq_table.table, cq->cqn);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cierr_out:
8848c2ecf20Sopenharmony_ci	mthca_free(&dev->cq_table.alloc, cq->cqn);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	return err;
8878c2ecf20Sopenharmony_ci}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_cistatic inline int get_cq_refcount(struct mthca_dev *dev, struct mthca_cq *cq)
8908c2ecf20Sopenharmony_ci{
8918c2ecf20Sopenharmony_ci	int c;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	spin_lock_irq(&dev->cq_table.lock);
8948c2ecf20Sopenharmony_ci	c = cq->refcount;
8958c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev->cq_table.lock);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	return c;
8988c2ecf20Sopenharmony_ci}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_civoid mthca_free_cq(struct mthca_dev *dev,
9018c2ecf20Sopenharmony_ci		   struct mthca_cq *cq)
9028c2ecf20Sopenharmony_ci{
9038c2ecf20Sopenharmony_ci	struct mthca_mailbox *mailbox;
9048c2ecf20Sopenharmony_ci	int err;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
9078c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox)) {
9088c2ecf20Sopenharmony_ci		mthca_warn(dev, "No memory for mailbox to free CQ.\n");
9098c2ecf20Sopenharmony_ci		return;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn);
9138c2ecf20Sopenharmony_ci	if (err)
9148c2ecf20Sopenharmony_ci		mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	if (0) {
9178c2ecf20Sopenharmony_ci		__be32 *ctx = mailbox->buf;
9188c2ecf20Sopenharmony_ci		int j;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci		printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
9218c2ecf20Sopenharmony_ci		       cq->cqn, cq->cons_index,
9228c2ecf20Sopenharmony_ci		       cq->is_kernel ? !!next_cqe_sw(cq) : 0);
9238c2ecf20Sopenharmony_ci		for (j = 0; j < 16; ++j)
9248c2ecf20Sopenharmony_ci			printk(KERN_ERR "[%2x] %08x\n", j * 4, be32_to_cpu(ctx[j]));
9258c2ecf20Sopenharmony_ci	}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	spin_lock_irq(&dev->cq_table.lock);
9288c2ecf20Sopenharmony_ci	mthca_array_clear(&dev->cq_table.cq,
9298c2ecf20Sopenharmony_ci			  cq->cqn & (dev->limits.num_cqs - 1));
9308c2ecf20Sopenharmony_ci	--cq->refcount;
9318c2ecf20Sopenharmony_ci	spin_unlock_irq(&dev->cq_table.lock);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	if (dev->mthca_flags & MTHCA_FLAG_MSI_X)
9348c2ecf20Sopenharmony_ci		synchronize_irq(dev->eq_table.eq[MTHCA_EQ_COMP].msi_x_vector);
9358c2ecf20Sopenharmony_ci	else
9368c2ecf20Sopenharmony_ci		synchronize_irq(dev->pdev->irq);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	wait_event(cq->wait, !get_cq_refcount(dev, cq));
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	if (cq->is_kernel) {
9418c2ecf20Sopenharmony_ci		mthca_free_cq_buf(dev, &cq->buf, cq->ibcq.cqe);
9428c2ecf20Sopenharmony_ci		if (mthca_is_memfree(dev)) {
9438c2ecf20Sopenharmony_ci			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
9448c2ecf20Sopenharmony_ci			mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
9458c2ecf20Sopenharmony_ci		}
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	mthca_table_put(dev, dev->cq_table.table, cq->cqn);
9498c2ecf20Sopenharmony_ci	mthca_free(&dev->cq_table.alloc, cq->cqn);
9508c2ecf20Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
9518c2ecf20Sopenharmony_ci}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ciint mthca_init_cq_table(struct mthca_dev *dev)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	int err;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	spin_lock_init(&dev->cq_table.lock);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	err = mthca_alloc_init(&dev->cq_table.alloc,
9608c2ecf20Sopenharmony_ci			       dev->limits.num_cqs,
9618c2ecf20Sopenharmony_ci			       (1 << 24) - 1,
9628c2ecf20Sopenharmony_ci			       dev->limits.reserved_cqs);
9638c2ecf20Sopenharmony_ci	if (err)
9648c2ecf20Sopenharmony_ci		return err;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	err = mthca_array_init(&dev->cq_table.cq,
9678c2ecf20Sopenharmony_ci			       dev->limits.num_cqs);
9688c2ecf20Sopenharmony_ci	if (err)
9698c2ecf20Sopenharmony_ci		mthca_alloc_cleanup(&dev->cq_table.alloc);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	return err;
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_civoid mthca_cleanup_cq_table(struct mthca_dev *dev)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	mthca_array_cleanup(&dev->cq_table.cq, dev->limits.num_cqs);
9778c2ecf20Sopenharmony_ci	mthca_alloc_cleanup(&dev->cq_table.alloc);
9788c2ecf20Sopenharmony_ci}
979