18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
38c2ecf20Sopenharmony_ci * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
68c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
78c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
88c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
98c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
128c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
138c2ecf20Sopenharmony_ci *     conditions are met:
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
168c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
178c2ecf20Sopenharmony_ci *        disclaimer.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
208c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
218c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
228c2ecf20Sopenharmony_ci *        provided with the distribution.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
258c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
268c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
278c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
298c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
308c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
318c2ecf20Sopenharmony_ci * SOFTWARE.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#include <linux/errno.h>
358c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
368c2ecf20Sopenharmony_ci#include <linux/pci.h>
378c2ecf20Sopenharmony_ci#include <linux/slab.h>
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci#include "mthca_dev.h"
408c2ecf20Sopenharmony_ci#include "mthca_cmd.h"
418c2ecf20Sopenharmony_ci#include "mthca_config_reg.h"
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cienum {
448c2ecf20Sopenharmony_ci	MTHCA_NUM_ASYNC_EQE = 0x80,
458c2ecf20Sopenharmony_ci	MTHCA_NUM_CMD_EQE   = 0x80,
468c2ecf20Sopenharmony_ci	MTHCA_NUM_SPARE_EQE = 0x80,
478c2ecf20Sopenharmony_ci	MTHCA_EQ_ENTRY_SIZE = 0x20
488c2ecf20Sopenharmony_ci};
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * Must be packed because start is 64 bits but only aligned to 32 bits.
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistruct mthca_eq_context {
548c2ecf20Sopenharmony_ci	__be32 flags;
558c2ecf20Sopenharmony_ci	__be64 start;
568c2ecf20Sopenharmony_ci	__be32 logsize_usrpage;
578c2ecf20Sopenharmony_ci	__be32 tavor_pd;	/* reserved for Arbel */
588c2ecf20Sopenharmony_ci	u8     reserved1[3];
598c2ecf20Sopenharmony_ci	u8     intr;
608c2ecf20Sopenharmony_ci	__be32 arbel_pd;	/* lost_count for Tavor */
618c2ecf20Sopenharmony_ci	__be32 lkey;
628c2ecf20Sopenharmony_ci	u32    reserved2[2];
638c2ecf20Sopenharmony_ci	__be32 consumer_index;
648c2ecf20Sopenharmony_ci	__be32 producer_index;
658c2ecf20Sopenharmony_ci	u32    reserved3[4];
668c2ecf20Sopenharmony_ci} __packed;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATUS_OK          ( 0 << 28)
698c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATUS_OVERFLOW    ( 9 << 28)
708c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATUS_WRITE_FAIL  (10 << 28)
718c2ecf20Sopenharmony_ci#define MTHCA_EQ_OWNER_SW           ( 0 << 24)
728c2ecf20Sopenharmony_ci#define MTHCA_EQ_OWNER_HW           ( 1 << 24)
738c2ecf20Sopenharmony_ci#define MTHCA_EQ_FLAG_TR            ( 1 << 18)
748c2ecf20Sopenharmony_ci#define MTHCA_EQ_FLAG_OI            ( 1 << 17)
758c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATE_ARMED        ( 1 <<  8)
768c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATE_FIRED        ( 2 <<  8)
778c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATE_ALWAYS_ARMED ( 3 <<  8)
788c2ecf20Sopenharmony_ci#define MTHCA_EQ_STATE_ARBEL        ( 8 <<  8)
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cienum {
818c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_COMP       	    = 0x00,
828c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_PATH_MIG   	    = 0x01,
838c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_COMM_EST   	    = 0x02,
848c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_SQ_DRAINED 	    = 0x03,
858c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE    = 0x13,
868c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_SRQ_LIMIT	    = 0x14,
878c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_CQ_ERROR   	    = 0x04,
888c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_WQ_CATAS_ERROR     = 0x05,
898c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_EEC_CATAS_ERROR    = 0x06,
908c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_PATH_MIG_FAILED    = 0x07,
918c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10,
928c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR    = 0x11,
938c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR    = 0x12,
948c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR  = 0x08,
958c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_PORT_CHANGE        = 0x09,
968c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_EQ_OVERFLOW        = 0x0f,
978c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_ECC_DETECT         = 0x0e,
988c2ecf20Sopenharmony_ci	MTHCA_EVENT_TYPE_CMD                = 0x0a
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci#define MTHCA_ASYNC_EVENT_MASK ((1ULL << MTHCA_EVENT_TYPE_PATH_MIG)           | \
1028c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_COMM_EST)           | \
1038c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_SQ_DRAINED)         | \
1048c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_CQ_ERROR)           | \
1058c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_WQ_CATAS_ERROR)     | \
1068c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_EEC_CATAS_ERROR)    | \
1078c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_PATH_MIG_FAILED)    | \
1088c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
1098c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR)    | \
1108c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR)  | \
1118c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_PORT_CHANGE)        | \
1128c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_ECC_DETECT))
1138c2ecf20Sopenharmony_ci#define MTHCA_SRQ_EVENT_MASK   ((1ULL << MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR)    | \
1148c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
1158c2ecf20Sopenharmony_ci				(1ULL << MTHCA_EVENT_TYPE_SRQ_LIMIT))
1168c2ecf20Sopenharmony_ci#define MTHCA_CMD_EVENT_MASK    (1ULL << MTHCA_EVENT_TYPE_CMD)
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define MTHCA_EQ_DB_INC_CI     (1 << 24)
1198c2ecf20Sopenharmony_ci#define MTHCA_EQ_DB_REQ_NOT    (2 << 24)
1208c2ecf20Sopenharmony_ci#define MTHCA_EQ_DB_DISARM_CQ  (3 << 24)
1218c2ecf20Sopenharmony_ci#define MTHCA_EQ_DB_SET_CI     (4 << 24)
1228c2ecf20Sopenharmony_ci#define MTHCA_EQ_DB_ALWAYS_ARM (5 << 24)
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistruct mthca_eqe {
1258c2ecf20Sopenharmony_ci	u8 reserved1;
1268c2ecf20Sopenharmony_ci	u8 type;
1278c2ecf20Sopenharmony_ci	u8 reserved2;
1288c2ecf20Sopenharmony_ci	u8 subtype;
1298c2ecf20Sopenharmony_ci	union {
1308c2ecf20Sopenharmony_ci		u32 raw[6];
1318c2ecf20Sopenharmony_ci		struct {
1328c2ecf20Sopenharmony_ci			__be32 cqn;
1338c2ecf20Sopenharmony_ci		} __packed comp;
1348c2ecf20Sopenharmony_ci		struct {
1358c2ecf20Sopenharmony_ci			u16    reserved1;
1368c2ecf20Sopenharmony_ci			__be16 token;
1378c2ecf20Sopenharmony_ci			u32    reserved2;
1388c2ecf20Sopenharmony_ci			u8     reserved3[3];
1398c2ecf20Sopenharmony_ci			u8     status;
1408c2ecf20Sopenharmony_ci			__be64 out_param;
1418c2ecf20Sopenharmony_ci		} __packed cmd;
1428c2ecf20Sopenharmony_ci		struct {
1438c2ecf20Sopenharmony_ci			__be32 qpn;
1448c2ecf20Sopenharmony_ci		} __packed qp;
1458c2ecf20Sopenharmony_ci		struct {
1468c2ecf20Sopenharmony_ci			__be32 srqn;
1478c2ecf20Sopenharmony_ci		} __packed srq;
1488c2ecf20Sopenharmony_ci		struct {
1498c2ecf20Sopenharmony_ci			__be32 cqn;
1508c2ecf20Sopenharmony_ci			u32    reserved1;
1518c2ecf20Sopenharmony_ci			u8     reserved2[3];
1528c2ecf20Sopenharmony_ci			u8     syndrome;
1538c2ecf20Sopenharmony_ci		} __packed cq_err;
1548c2ecf20Sopenharmony_ci		struct {
1558c2ecf20Sopenharmony_ci			u32    reserved1[2];
1568c2ecf20Sopenharmony_ci			__be32 port;
1578c2ecf20Sopenharmony_ci		} __packed port_change;
1588c2ecf20Sopenharmony_ci	} event;
1598c2ecf20Sopenharmony_ci	u8 reserved3[3];
1608c2ecf20Sopenharmony_ci	u8 owner;
1618c2ecf20Sopenharmony_ci} __packed;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci#define  MTHCA_EQ_ENTRY_OWNER_SW      (0 << 7)
1648c2ecf20Sopenharmony_ci#define  MTHCA_EQ_ENTRY_OWNER_HW      (1 << 7)
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic inline u64 async_mask(struct mthca_dev *dev)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return dev->mthca_flags & MTHCA_FLAG_SRQ ?
1698c2ecf20Sopenharmony_ci		MTHCA_ASYNC_EVENT_MASK | MTHCA_SRQ_EVENT_MASK :
1708c2ecf20Sopenharmony_ci		MTHCA_ASYNC_EVENT_MASK;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic inline void tavor_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	/*
1768c2ecf20Sopenharmony_ci	 * This barrier makes sure that all updates to ownership bits
1778c2ecf20Sopenharmony_ci	 * done by set_eqe_hw() hit memory before the consumer index
1788c2ecf20Sopenharmony_ci	 * is updated.  set_eq_ci() allows the HCA to possibly write
1798c2ecf20Sopenharmony_ci	 * more EQ entries, and we want to avoid the exceedingly
1808c2ecf20Sopenharmony_ci	 * unlikely possibility of the HCA writing an entry and then
1818c2ecf20Sopenharmony_ci	 * having set_eqe_hw() overwrite the owner field.
1828c2ecf20Sopenharmony_ci	 */
1838c2ecf20Sopenharmony_ci	wmb();
1848c2ecf20Sopenharmony_ci	mthca_write64(MTHCA_EQ_DB_SET_CI | eq->eqn, ci & (eq->nent - 1),
1858c2ecf20Sopenharmony_ci		      dev->kar + MTHCA_EQ_DOORBELL,
1868c2ecf20Sopenharmony_ci		      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic inline void arbel_set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	/* See comment in tavor_set_eq_ci() above. */
1928c2ecf20Sopenharmony_ci	wmb();
1938c2ecf20Sopenharmony_ci	__raw_writel((__force u32) cpu_to_be32(ci),
1948c2ecf20Sopenharmony_ci		     dev->eq_regs.arbel.eq_set_ci_base + eq->eqn * 8);
1958c2ecf20Sopenharmony_ci	/* We still want ordering, just not swabbing, so add a barrier */
1968c2ecf20Sopenharmony_ci	mb();
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic inline void set_eq_ci(struct mthca_dev *dev, struct mthca_eq *eq, u32 ci)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev))
2028c2ecf20Sopenharmony_ci		arbel_set_eq_ci(dev, eq, ci);
2038c2ecf20Sopenharmony_ci	else
2048c2ecf20Sopenharmony_ci		tavor_set_eq_ci(dev, eq, ci);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic inline void tavor_eq_req_not(struct mthca_dev *dev, int eqn)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	mthca_write64(MTHCA_EQ_DB_REQ_NOT | eqn, 0,
2108c2ecf20Sopenharmony_ci		      dev->kar + MTHCA_EQ_DOORBELL,
2118c2ecf20Sopenharmony_ci		      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic inline void arbel_eq_req_not(struct mthca_dev *dev, u32 eqn_mask)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	writel(eqn_mask, dev->eq_regs.arbel.eq_arm);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic inline void disarm_cq(struct mthca_dev *dev, int eqn, int cqn)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	if (!mthca_is_memfree(dev)) {
2228c2ecf20Sopenharmony_ci		mthca_write64(MTHCA_EQ_DB_DISARM_CQ | eqn, cqn,
2238c2ecf20Sopenharmony_ci			      dev->kar + MTHCA_EQ_DOORBELL,
2248c2ecf20Sopenharmony_ci			      MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic inline struct mthca_eqe *get_eqe(struct mthca_eq *eq, u32 entry)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	unsigned long off = (entry & (eq->nent - 1)) * MTHCA_EQ_ENTRY_SIZE;
2318c2ecf20Sopenharmony_ci	return eq->page_list[off / PAGE_SIZE].buf + off % PAGE_SIZE;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic inline struct mthca_eqe *next_eqe_sw(struct mthca_eq *eq)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	struct mthca_eqe *eqe;
2378c2ecf20Sopenharmony_ci	eqe = get_eqe(eq, eq->cons_index);
2388c2ecf20Sopenharmony_ci	return (MTHCA_EQ_ENTRY_OWNER_HW & eqe->owner) ? NULL : eqe;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic inline void set_eqe_hw(struct mthca_eqe *eqe)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	eqe->owner =  MTHCA_EQ_ENTRY_OWNER_HW;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic void port_change(struct mthca_dev *dev, int port, int active)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	struct ib_event record;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	mthca_dbg(dev, "Port change to %s for port %d\n",
2518c2ecf20Sopenharmony_ci		  active ? "active" : "down", port);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	record.device = &dev->ib_dev;
2548c2ecf20Sopenharmony_ci	record.event  = active ? IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
2558c2ecf20Sopenharmony_ci	record.element.port_num = port;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	ib_dispatch_event(&record);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct mthca_eqe *eqe;
2638c2ecf20Sopenharmony_ci	int disarm_cqn;
2648c2ecf20Sopenharmony_ci	int eqes_found = 0;
2658c2ecf20Sopenharmony_ci	int set_ci = 0;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	while ((eqe = next_eqe_sw(eq))) {
2688c2ecf20Sopenharmony_ci		/*
2698c2ecf20Sopenharmony_ci		 * Make sure we read EQ entry contents after we've
2708c2ecf20Sopenharmony_ci		 * checked the ownership bit.
2718c2ecf20Sopenharmony_ci		 */
2728c2ecf20Sopenharmony_ci		rmb();
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		switch (eqe->type) {
2758c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_COMP:
2768c2ecf20Sopenharmony_ci			disarm_cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff;
2778c2ecf20Sopenharmony_ci			disarm_cq(dev, eq->eqn, disarm_cqn);
2788c2ecf20Sopenharmony_ci			mthca_cq_completion(dev, disarm_cqn);
2798c2ecf20Sopenharmony_ci			break;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_PATH_MIG:
2828c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
2838c2ecf20Sopenharmony_ci				       IB_EVENT_PATH_MIG);
2848c2ecf20Sopenharmony_ci			break;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_COMM_EST:
2878c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
2888c2ecf20Sopenharmony_ci				       IB_EVENT_COMM_EST);
2898c2ecf20Sopenharmony_ci			break;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_SQ_DRAINED:
2928c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
2938c2ecf20Sopenharmony_ci				       IB_EVENT_SQ_DRAINED);
2948c2ecf20Sopenharmony_ci			break;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_SRQ_QP_LAST_WQE:
2978c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
2988c2ecf20Sopenharmony_ci				       IB_EVENT_QP_LAST_WQE_REACHED);
2998c2ecf20Sopenharmony_ci			break;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_SRQ_LIMIT:
3028c2ecf20Sopenharmony_ci			mthca_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff,
3038c2ecf20Sopenharmony_ci					IB_EVENT_SRQ_LIMIT_REACHED);
3048c2ecf20Sopenharmony_ci			break;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_WQ_CATAS_ERROR:
3078c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
3088c2ecf20Sopenharmony_ci				       IB_EVENT_QP_FATAL);
3098c2ecf20Sopenharmony_ci			break;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_PATH_MIG_FAILED:
3128c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
3138c2ecf20Sopenharmony_ci				       IB_EVENT_PATH_MIG_ERR);
3148c2ecf20Sopenharmony_ci			break;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_WQ_INVAL_REQ_ERROR:
3178c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
3188c2ecf20Sopenharmony_ci				       IB_EVENT_QP_REQ_ERR);
3198c2ecf20Sopenharmony_ci			break;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_WQ_ACCESS_ERROR:
3228c2ecf20Sopenharmony_ci			mthca_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff,
3238c2ecf20Sopenharmony_ci				       IB_EVENT_QP_ACCESS_ERR);
3248c2ecf20Sopenharmony_ci			break;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_CMD:
3278c2ecf20Sopenharmony_ci			mthca_cmd_event(dev,
3288c2ecf20Sopenharmony_ci					be16_to_cpu(eqe->event.cmd.token),
3298c2ecf20Sopenharmony_ci					eqe->event.cmd.status,
3308c2ecf20Sopenharmony_ci					be64_to_cpu(eqe->event.cmd.out_param));
3318c2ecf20Sopenharmony_ci			break;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_PORT_CHANGE:
3348c2ecf20Sopenharmony_ci			port_change(dev,
3358c2ecf20Sopenharmony_ci				    (be32_to_cpu(eqe->event.port_change.port) >> 28) & 3,
3368c2ecf20Sopenharmony_ci				    eqe->subtype == 0x4);
3378c2ecf20Sopenharmony_ci			break;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_CQ_ERROR:
3408c2ecf20Sopenharmony_ci			mthca_warn(dev, "CQ %s on CQN %06x\n",
3418c2ecf20Sopenharmony_ci				   eqe->event.cq_err.syndrome == 1 ?
3428c2ecf20Sopenharmony_ci				   "overrun" : "access violation",
3438c2ecf20Sopenharmony_ci				   be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff);
3448c2ecf20Sopenharmony_ci			mthca_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn),
3458c2ecf20Sopenharmony_ci				       IB_EVENT_CQ_ERR);
3468c2ecf20Sopenharmony_ci			break;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_EQ_OVERFLOW:
3498c2ecf20Sopenharmony_ci			mthca_warn(dev, "EQ overrun on EQN %d\n", eq->eqn);
3508c2ecf20Sopenharmony_ci			break;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_EEC_CATAS_ERROR:
3538c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_SRQ_CATAS_ERROR:
3548c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_LOCAL_CATAS_ERROR:
3558c2ecf20Sopenharmony_ci		case MTHCA_EVENT_TYPE_ECC_DETECT:
3568c2ecf20Sopenharmony_ci		default:
3578c2ecf20Sopenharmony_ci			mthca_warn(dev, "Unhandled event %02x(%02x) on EQ %d\n",
3588c2ecf20Sopenharmony_ci				   eqe->type, eqe->subtype, eq->eqn);
3598c2ecf20Sopenharmony_ci			break;
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci		set_eqe_hw(eqe);
3638c2ecf20Sopenharmony_ci		++eq->cons_index;
3648c2ecf20Sopenharmony_ci		eqes_found = 1;
3658c2ecf20Sopenharmony_ci		++set_ci;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		/*
3688c2ecf20Sopenharmony_ci		 * The HCA will think the queue has overflowed if we
3698c2ecf20Sopenharmony_ci		 * don't tell it we've been processing events.  We
3708c2ecf20Sopenharmony_ci		 * create our EQs with MTHCA_NUM_SPARE_EQE extra
3718c2ecf20Sopenharmony_ci		 * entries, so we must update our consumer index at
3728c2ecf20Sopenharmony_ci		 * least that often.
3738c2ecf20Sopenharmony_ci		 */
3748c2ecf20Sopenharmony_ci		if (unlikely(set_ci >= MTHCA_NUM_SPARE_EQE)) {
3758c2ecf20Sopenharmony_ci			/*
3768c2ecf20Sopenharmony_ci			 * Conditional on hca_type is OK here because
3778c2ecf20Sopenharmony_ci			 * this is a rare case, not the fast path.
3788c2ecf20Sopenharmony_ci			 */
3798c2ecf20Sopenharmony_ci			set_eq_ci(dev, eq, eq->cons_index);
3808c2ecf20Sopenharmony_ci			set_ci = 0;
3818c2ecf20Sopenharmony_ci		}
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/*
3858c2ecf20Sopenharmony_ci	 * Rely on caller to set consumer index so that we don't have
3868c2ecf20Sopenharmony_ci	 * to test hca_type in our interrupt handling fast path.
3878c2ecf20Sopenharmony_ci	 */
3888c2ecf20Sopenharmony_ci	return eqes_found;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	struct mthca_dev *dev = dev_ptr;
3948c2ecf20Sopenharmony_ci	u32 ecr;
3958c2ecf20Sopenharmony_ci	int i;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (dev->eq_table.clr_mask)
3988c2ecf20Sopenharmony_ci		writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	ecr = readl(dev->eq_regs.tavor.ecr_base + 4);
4018c2ecf20Sopenharmony_ci	if (!ecr)
4028c2ecf20Sopenharmony_ci		return IRQ_NONE;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	writel(ecr, dev->eq_regs.tavor.ecr_base +
4058c2ecf20Sopenharmony_ci	       MTHCA_ECR_CLR_BASE - MTHCA_ECR_BASE + 4);
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	for (i = 0; i < MTHCA_NUM_EQ; ++i)
4088c2ecf20Sopenharmony_ci		if (ecr & dev->eq_table.eq[i].eqn_mask) {
4098c2ecf20Sopenharmony_ci			if (mthca_eq_int(dev, &dev->eq_table.eq[i]))
4108c2ecf20Sopenharmony_ci				tavor_set_eq_ci(dev, &dev->eq_table.eq[i],
4118c2ecf20Sopenharmony_ci						dev->eq_table.eq[i].cons_index);
4128c2ecf20Sopenharmony_ci			tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct mthca_eq  *eq  = eq_ptr;
4218c2ecf20Sopenharmony_ci	struct mthca_dev *dev = eq->dev;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	mthca_eq_int(dev, eq);
4248c2ecf20Sopenharmony_ci	tavor_set_eq_ci(dev, eq, eq->cons_index);
4258c2ecf20Sopenharmony_ci	tavor_eq_req_not(dev, eq->eqn);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	/* MSI-X vectors always belong to us */
4288c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct mthca_dev *dev = dev_ptr;
4348c2ecf20Sopenharmony_ci	int work = 0;
4358c2ecf20Sopenharmony_ci	int i;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (dev->eq_table.clr_mask)
4388c2ecf20Sopenharmony_ci		writel(dev->eq_table.clr_mask, dev->eq_table.clr_int);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	for (i = 0; i < MTHCA_NUM_EQ; ++i)
4418c2ecf20Sopenharmony_ci		if (mthca_eq_int(dev, &dev->eq_table.eq[i])) {
4428c2ecf20Sopenharmony_ci			work = 1;
4438c2ecf20Sopenharmony_ci			arbel_set_eq_ci(dev, &dev->eq_table.eq[i],
4448c2ecf20Sopenharmony_ci					dev->eq_table.eq[i].cons_index);
4458c2ecf20Sopenharmony_ci		}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	arbel_eq_req_not(dev, dev->eq_table.arm_mask);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return IRQ_RETVAL(work);
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	struct mthca_eq  *eq  = eq_ptr;
4558c2ecf20Sopenharmony_ci	struct mthca_dev *dev = eq->dev;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	mthca_eq_int(dev, eq);
4588c2ecf20Sopenharmony_ci	arbel_set_eq_ci(dev, eq, eq->cons_index);
4598c2ecf20Sopenharmony_ci	arbel_eq_req_not(dev, eq->eqn_mask);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* MSI-X vectors always belong to us */
4628c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic int mthca_create_eq(struct mthca_dev *dev,
4668c2ecf20Sopenharmony_ci			   int nent,
4678c2ecf20Sopenharmony_ci			   u8 intr,
4688c2ecf20Sopenharmony_ci			   struct mthca_eq *eq)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	int npages;
4718c2ecf20Sopenharmony_ci	u64 *dma_list = NULL;
4728c2ecf20Sopenharmony_ci	dma_addr_t t;
4738c2ecf20Sopenharmony_ci	struct mthca_mailbox *mailbox;
4748c2ecf20Sopenharmony_ci	struct mthca_eq_context *eq_context;
4758c2ecf20Sopenharmony_ci	int err = -ENOMEM;
4768c2ecf20Sopenharmony_ci	int i;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	eq->dev  = dev;
4798c2ecf20Sopenharmony_ci	eq->nent = roundup_pow_of_two(max(nent, 2));
4808c2ecf20Sopenharmony_ci	npages = ALIGN(eq->nent * MTHCA_EQ_ENTRY_SIZE, PAGE_SIZE) / PAGE_SIZE;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	eq->page_list = kmalloc_array(npages, sizeof(*eq->page_list),
4838c2ecf20Sopenharmony_ci				      GFP_KERNEL);
4848c2ecf20Sopenharmony_ci	if (!eq->page_list)
4858c2ecf20Sopenharmony_ci		goto err_out;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	for (i = 0; i < npages; ++i)
4888c2ecf20Sopenharmony_ci		eq->page_list[i].buf = NULL;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	dma_list = kmalloc_array(npages, sizeof(*dma_list), GFP_KERNEL);
4918c2ecf20Sopenharmony_ci	if (!dma_list)
4928c2ecf20Sopenharmony_ci		goto err_out_free;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
4958c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
4968c2ecf20Sopenharmony_ci		goto err_out_free;
4978c2ecf20Sopenharmony_ci	eq_context = mailbox->buf;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	for (i = 0; i < npages; ++i) {
5008c2ecf20Sopenharmony_ci		eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
5018c2ecf20Sopenharmony_ci							  PAGE_SIZE, &t, GFP_KERNEL);
5028c2ecf20Sopenharmony_ci		if (!eq->page_list[i].buf)
5038c2ecf20Sopenharmony_ci			goto err_out_free_pages;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		dma_list[i] = t;
5068c2ecf20Sopenharmony_ci		dma_unmap_addr_set(&eq->page_list[i], mapping, t);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		clear_page(eq->page_list[i].buf);
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	for (i = 0; i < eq->nent; ++i)
5128c2ecf20Sopenharmony_ci		set_eqe_hw(get_eqe(eq, i));
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	eq->eqn = mthca_alloc(&dev->eq_table.alloc);
5158c2ecf20Sopenharmony_ci	if (eq->eqn == -1)
5168c2ecf20Sopenharmony_ci		goto err_out_free_pages;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
5198c2ecf20Sopenharmony_ci				  dma_list, PAGE_SHIFT, npages,
5208c2ecf20Sopenharmony_ci				  0, npages * PAGE_SIZE,
5218c2ecf20Sopenharmony_ci				  MTHCA_MPT_FLAG_LOCAL_WRITE |
5228c2ecf20Sopenharmony_ci				  MTHCA_MPT_FLAG_LOCAL_READ,
5238c2ecf20Sopenharmony_ci				  &eq->mr);
5248c2ecf20Sopenharmony_ci	if (err)
5258c2ecf20Sopenharmony_ci		goto err_out_free_eq;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	memset(eq_context, 0, sizeof *eq_context);
5288c2ecf20Sopenharmony_ci	eq_context->flags           = cpu_to_be32(MTHCA_EQ_STATUS_OK   |
5298c2ecf20Sopenharmony_ci						  MTHCA_EQ_OWNER_HW    |
5308c2ecf20Sopenharmony_ci						  MTHCA_EQ_STATE_ARMED |
5318c2ecf20Sopenharmony_ci						  MTHCA_EQ_FLAG_TR);
5328c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev))
5338c2ecf20Sopenharmony_ci		eq_context->flags  |= cpu_to_be32(MTHCA_EQ_STATE_ARBEL);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	eq_context->logsize_usrpage = cpu_to_be32((ffs(eq->nent) - 1) << 24);
5368c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
5378c2ecf20Sopenharmony_ci		eq_context->arbel_pd = cpu_to_be32(dev->driver_pd.pd_num);
5388c2ecf20Sopenharmony_ci	} else {
5398c2ecf20Sopenharmony_ci		eq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index);
5408c2ecf20Sopenharmony_ci		eq_context->tavor_pd         = cpu_to_be32(dev->driver_pd.pd_num);
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci	eq_context->intr            = intr;
5438c2ecf20Sopenharmony_ci	eq_context->lkey            = cpu_to_be32(eq->mr.ibmr.lkey);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn);
5468c2ecf20Sopenharmony_ci	if (err) {
5478c2ecf20Sopenharmony_ci		mthca_warn(dev, "SW2HW_EQ returned %d\n", err);
5488c2ecf20Sopenharmony_ci		goto err_out_free_mr;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	kfree(dma_list);
5528c2ecf20Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	eq->eqn_mask   = swab32(1 << eq->eqn);
5558c2ecf20Sopenharmony_ci	eq->cons_index = 0;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	dev->eq_table.arm_mask |= eq->eqn_mask;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	mthca_dbg(dev, "Allocated EQ %d with %d entries\n",
5608c2ecf20Sopenharmony_ci		  eq->eqn, eq->nent);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	return err;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci err_out_free_mr:
5658c2ecf20Sopenharmony_ci	mthca_free_mr(dev, &eq->mr);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci err_out_free_eq:
5688c2ecf20Sopenharmony_ci	mthca_free(&dev->eq_table.alloc, eq->eqn);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci err_out_free_pages:
5718c2ecf20Sopenharmony_ci	for (i = 0; i < npages; ++i)
5728c2ecf20Sopenharmony_ci		if (eq->page_list[i].buf)
5738c2ecf20Sopenharmony_ci			dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
5748c2ecf20Sopenharmony_ci					  eq->page_list[i].buf,
5758c2ecf20Sopenharmony_ci					  dma_unmap_addr(&eq->page_list[i],
5768c2ecf20Sopenharmony_ci							 mapping));
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci err_out_free:
5818c2ecf20Sopenharmony_ci	kfree(eq->page_list);
5828c2ecf20Sopenharmony_ci	kfree(dma_list);
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci err_out:
5858c2ecf20Sopenharmony_ci	return err;
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic void mthca_free_eq(struct mthca_dev *dev,
5898c2ecf20Sopenharmony_ci			  struct mthca_eq *eq)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	struct mthca_mailbox *mailbox;
5928c2ecf20Sopenharmony_ci	int err;
5938c2ecf20Sopenharmony_ci	int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
5948c2ecf20Sopenharmony_ci		PAGE_SIZE;
5958c2ecf20Sopenharmony_ci	int i;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
5988c2ecf20Sopenharmony_ci	if (IS_ERR(mailbox))
5998c2ecf20Sopenharmony_ci		return;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn);
6028c2ecf20Sopenharmony_ci	if (err)
6038c2ecf20Sopenharmony_ci		mthca_warn(dev, "HW2SW_EQ returned %d\n", err);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	dev->eq_table.arm_mask &= ~eq->eqn_mask;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	if (0) {
6088c2ecf20Sopenharmony_ci		mthca_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn);
6098c2ecf20Sopenharmony_ci		for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
6108c2ecf20Sopenharmony_ci			if (i % 4 == 0)
6118c2ecf20Sopenharmony_ci				printk("[%02x] ", i * 4);
6128c2ecf20Sopenharmony_ci			printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
6138c2ecf20Sopenharmony_ci			if ((i + 1) % 4 == 0)
6148c2ecf20Sopenharmony_ci				printk("\n");
6158c2ecf20Sopenharmony_ci		}
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	mthca_free_mr(dev, &eq->mr);
6198c2ecf20Sopenharmony_ci	for (i = 0; i < npages; ++i)
6208c2ecf20Sopenharmony_ci		pci_free_consistent(dev->pdev, PAGE_SIZE,
6218c2ecf20Sopenharmony_ci				    eq->page_list[i].buf,
6228c2ecf20Sopenharmony_ci				    dma_unmap_addr(&eq->page_list[i], mapping));
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	kfree(eq->page_list);
6258c2ecf20Sopenharmony_ci	mthca_free_mailbox(dev, mailbox);
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic void mthca_free_irqs(struct mthca_dev *dev)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	int i;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	if (dev->eq_table.have_irq)
6338c2ecf20Sopenharmony_ci		free_irq(dev->pdev->irq, dev);
6348c2ecf20Sopenharmony_ci	for (i = 0; i < MTHCA_NUM_EQ; ++i)
6358c2ecf20Sopenharmony_ci		if (dev->eq_table.eq[i].have_irq) {
6368c2ecf20Sopenharmony_ci			free_irq(dev->eq_table.eq[i].msi_x_vector,
6378c2ecf20Sopenharmony_ci				 dev->eq_table.eq + i);
6388c2ecf20Sopenharmony_ci			dev->eq_table.eq[i].have_irq = 0;
6398c2ecf20Sopenharmony_ci		}
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic int mthca_map_reg(struct mthca_dev *dev,
6438c2ecf20Sopenharmony_ci			 unsigned long offset, unsigned long size,
6448c2ecf20Sopenharmony_ci			 void __iomem **map)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	phys_addr_t base = pci_resource_start(dev->pdev, 0);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	*map = ioremap(base + offset, size);
6498c2ecf20Sopenharmony_ci	if (!*map)
6508c2ecf20Sopenharmony_ci		return -ENOMEM;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	return 0;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_cistatic int mthca_map_eq_regs(struct mthca_dev *dev)
6568c2ecf20Sopenharmony_ci{
6578c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
6588c2ecf20Sopenharmony_ci		/*
6598c2ecf20Sopenharmony_ci		 * We assume that the EQ arm and EQ set CI registers
6608c2ecf20Sopenharmony_ci		 * fall within the first BAR.  We can't trust the
6618c2ecf20Sopenharmony_ci		 * values firmware gives us, since those addresses are
6628c2ecf20Sopenharmony_ci		 * valid on the HCA's side of the PCI bus but not
6638c2ecf20Sopenharmony_ci		 * necessarily the host side.
6648c2ecf20Sopenharmony_ci		 */
6658c2ecf20Sopenharmony_ci		if (mthca_map_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
6668c2ecf20Sopenharmony_ci				  dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
6678c2ecf20Sopenharmony_ci				  &dev->clr_base)) {
6688c2ecf20Sopenharmony_ci			mthca_err(dev, "Couldn't map interrupt clear register, "
6698c2ecf20Sopenharmony_ci				  "aborting.\n");
6708c2ecf20Sopenharmony_ci			return -ENOMEM;
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci		/*
6748c2ecf20Sopenharmony_ci		 * Add 4 because we limit ourselves to EQs 0 ... 31,
6758c2ecf20Sopenharmony_ci		 * so we only need the low word of the register.
6768c2ecf20Sopenharmony_ci		 */
6778c2ecf20Sopenharmony_ci		if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
6788c2ecf20Sopenharmony_ci					dev->fw.arbel.eq_arm_base) + 4, 4,
6798c2ecf20Sopenharmony_ci				  &dev->eq_regs.arbel.eq_arm)) {
6808c2ecf20Sopenharmony_ci			mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
6818c2ecf20Sopenharmony_ci			iounmap(dev->clr_base);
6828c2ecf20Sopenharmony_ci			return -ENOMEM;
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		if (mthca_map_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
6868c2ecf20Sopenharmony_ci				  dev->fw.arbel.eq_set_ci_base,
6878c2ecf20Sopenharmony_ci				  MTHCA_EQ_SET_CI_SIZE,
6888c2ecf20Sopenharmony_ci				  &dev->eq_regs.arbel.eq_set_ci_base)) {
6898c2ecf20Sopenharmony_ci			mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
6908c2ecf20Sopenharmony_ci			iounmap(dev->eq_regs.arbel.eq_arm);
6918c2ecf20Sopenharmony_ci			iounmap(dev->clr_base);
6928c2ecf20Sopenharmony_ci			return -ENOMEM;
6938c2ecf20Sopenharmony_ci		}
6948c2ecf20Sopenharmony_ci	} else {
6958c2ecf20Sopenharmony_ci		if (mthca_map_reg(dev, MTHCA_CLR_INT_BASE, MTHCA_CLR_INT_SIZE,
6968c2ecf20Sopenharmony_ci				  &dev->clr_base)) {
6978c2ecf20Sopenharmony_ci			mthca_err(dev, "Couldn't map interrupt clear register, "
6988c2ecf20Sopenharmony_ci				  "aborting.\n");
6998c2ecf20Sopenharmony_ci			return -ENOMEM;
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci		if (mthca_map_reg(dev, MTHCA_ECR_BASE,
7038c2ecf20Sopenharmony_ci				  MTHCA_ECR_SIZE + MTHCA_ECR_CLR_SIZE,
7048c2ecf20Sopenharmony_ci				  &dev->eq_regs.tavor.ecr_base)) {
7058c2ecf20Sopenharmony_ci			mthca_err(dev, "Couldn't map ecr register, "
7068c2ecf20Sopenharmony_ci				  "aborting.\n");
7078c2ecf20Sopenharmony_ci			iounmap(dev->clr_base);
7088c2ecf20Sopenharmony_ci			return -ENOMEM;
7098c2ecf20Sopenharmony_ci		}
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	return 0;
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic void mthca_unmap_eq_regs(struct mthca_dev *dev)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	if (mthca_is_memfree(dev)) {
7198c2ecf20Sopenharmony_ci		iounmap(dev->eq_regs.arbel.eq_set_ci_base);
7208c2ecf20Sopenharmony_ci		iounmap(dev->eq_regs.arbel.eq_arm);
7218c2ecf20Sopenharmony_ci		iounmap(dev->clr_base);
7228c2ecf20Sopenharmony_ci	} else {
7238c2ecf20Sopenharmony_ci		iounmap(dev->eq_regs.tavor.ecr_base);
7248c2ecf20Sopenharmony_ci		iounmap(dev->clr_base);
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ciint mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	int ret;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	/*
7338c2ecf20Sopenharmony_ci	 * We assume that mapping one page is enough for the whole EQ
7348c2ecf20Sopenharmony_ci	 * context table.  This is fine with all current HCAs, because
7358c2ecf20Sopenharmony_ci	 * we only use 32 EQs and each EQ uses 32 bytes of context
7368c2ecf20Sopenharmony_ci	 * memory, or 1 KB total.
7378c2ecf20Sopenharmony_ci	 */
7388c2ecf20Sopenharmony_ci	dev->eq_table.icm_virt = icm_virt;
7398c2ecf20Sopenharmony_ci	dev->eq_table.icm_page = alloc_page(GFP_HIGHUSER);
7408c2ecf20Sopenharmony_ci	if (!dev->eq_table.icm_page)
7418c2ecf20Sopenharmony_ci		return -ENOMEM;
7428c2ecf20Sopenharmony_ci	dev->eq_table.icm_dma  = pci_map_page(dev->pdev, dev->eq_table.icm_page, 0,
7438c2ecf20Sopenharmony_ci					      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
7448c2ecf20Sopenharmony_ci	if (pci_dma_mapping_error(dev->pdev, dev->eq_table.icm_dma)) {
7458c2ecf20Sopenharmony_ci		__free_page(dev->eq_table.icm_page);
7468c2ecf20Sopenharmony_ci		return -ENOMEM;
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	ret = mthca_MAP_ICM_page(dev, dev->eq_table.icm_dma, icm_virt);
7508c2ecf20Sopenharmony_ci	if (ret) {
7518c2ecf20Sopenharmony_ci		pci_unmap_page(dev->pdev, dev->eq_table.icm_dma, PAGE_SIZE,
7528c2ecf20Sopenharmony_ci			       PCI_DMA_BIDIRECTIONAL);
7538c2ecf20Sopenharmony_ci		__free_page(dev->eq_table.icm_page);
7548c2ecf20Sopenharmony_ci	}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	return ret;
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_civoid mthca_unmap_eq_icm(struct mthca_dev *dev)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	mthca_UNMAP_ICM(dev, dev->eq_table.icm_virt, 1);
7628c2ecf20Sopenharmony_ci	pci_unmap_page(dev->pdev, dev->eq_table.icm_dma, PAGE_SIZE,
7638c2ecf20Sopenharmony_ci		       PCI_DMA_BIDIRECTIONAL);
7648c2ecf20Sopenharmony_ci	__free_page(dev->eq_table.icm_page);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ciint mthca_init_eq_table(struct mthca_dev *dev)
7688c2ecf20Sopenharmony_ci{
7698c2ecf20Sopenharmony_ci	int err;
7708c2ecf20Sopenharmony_ci	u8 intr;
7718c2ecf20Sopenharmony_ci	int i;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	err = mthca_alloc_init(&dev->eq_table.alloc,
7748c2ecf20Sopenharmony_ci			       dev->limits.num_eqs,
7758c2ecf20Sopenharmony_ci			       dev->limits.num_eqs - 1,
7768c2ecf20Sopenharmony_ci			       dev->limits.reserved_eqs);
7778c2ecf20Sopenharmony_ci	if (err)
7788c2ecf20Sopenharmony_ci		return err;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	err = mthca_map_eq_regs(dev);
7818c2ecf20Sopenharmony_ci	if (err)
7828c2ecf20Sopenharmony_ci		goto err_out_free;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
7858c2ecf20Sopenharmony_ci		dev->eq_table.clr_mask = 0;
7868c2ecf20Sopenharmony_ci	} else {
7878c2ecf20Sopenharmony_ci		dev->eq_table.clr_mask =
7888c2ecf20Sopenharmony_ci			swab32(1 << (dev->eq_table.inta_pin & 31));
7898c2ecf20Sopenharmony_ci		dev->eq_table.clr_int  = dev->clr_base +
7908c2ecf20Sopenharmony_ci			(dev->eq_table.inta_pin < 32 ? 4 : 0);
7918c2ecf20Sopenharmony_ci	}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	dev->eq_table.arm_mask = 0;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	intr = dev->eq_table.inta_pin;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE,
7988c2ecf20Sopenharmony_ci			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr,
7998c2ecf20Sopenharmony_ci			      &dev->eq_table.eq[MTHCA_EQ_COMP]);
8008c2ecf20Sopenharmony_ci	if (err)
8018c2ecf20Sopenharmony_ci		goto err_out_unmap;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	err = mthca_create_eq(dev, MTHCA_NUM_ASYNC_EQE + MTHCA_NUM_SPARE_EQE,
8048c2ecf20Sopenharmony_ci			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 129 : intr,
8058c2ecf20Sopenharmony_ci			      &dev->eq_table.eq[MTHCA_EQ_ASYNC]);
8068c2ecf20Sopenharmony_ci	if (err)
8078c2ecf20Sopenharmony_ci		goto err_out_comp;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	err = mthca_create_eq(dev, MTHCA_NUM_CMD_EQE + MTHCA_NUM_SPARE_EQE,
8108c2ecf20Sopenharmony_ci			      (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 130 : intr,
8118c2ecf20Sopenharmony_ci			      &dev->eq_table.eq[MTHCA_EQ_CMD]);
8128c2ecf20Sopenharmony_ci	if (err)
8138c2ecf20Sopenharmony_ci		goto err_out_async;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (dev->mthca_flags & MTHCA_FLAG_MSI_X) {
8168c2ecf20Sopenharmony_ci		static const char *eq_name[] = {
8178c2ecf20Sopenharmony_ci			[MTHCA_EQ_COMP]  = DRV_NAME "-comp",
8188c2ecf20Sopenharmony_ci			[MTHCA_EQ_ASYNC] = DRV_NAME "-async",
8198c2ecf20Sopenharmony_ci			[MTHCA_EQ_CMD]   = DRV_NAME "-cmd"
8208c2ecf20Sopenharmony_ci		};
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci		for (i = 0; i < MTHCA_NUM_EQ; ++i) {
8238c2ecf20Sopenharmony_ci			snprintf(dev->eq_table.eq[i].irq_name,
8248c2ecf20Sopenharmony_ci				 IB_DEVICE_NAME_MAX,
8258c2ecf20Sopenharmony_ci				 "%s@pci:%s", eq_name[i],
8268c2ecf20Sopenharmony_ci				 pci_name(dev->pdev));
8278c2ecf20Sopenharmony_ci			err = request_irq(dev->eq_table.eq[i].msi_x_vector,
8288c2ecf20Sopenharmony_ci					  mthca_is_memfree(dev) ?
8298c2ecf20Sopenharmony_ci					  mthca_arbel_msi_x_interrupt :
8308c2ecf20Sopenharmony_ci					  mthca_tavor_msi_x_interrupt,
8318c2ecf20Sopenharmony_ci					  0, dev->eq_table.eq[i].irq_name,
8328c2ecf20Sopenharmony_ci					  dev->eq_table.eq + i);
8338c2ecf20Sopenharmony_ci			if (err)
8348c2ecf20Sopenharmony_ci				goto err_out_cmd;
8358c2ecf20Sopenharmony_ci			dev->eq_table.eq[i].have_irq = 1;
8368c2ecf20Sopenharmony_ci		}
8378c2ecf20Sopenharmony_ci	} else {
8388c2ecf20Sopenharmony_ci		snprintf(dev->eq_table.eq[0].irq_name, IB_DEVICE_NAME_MAX,
8398c2ecf20Sopenharmony_ci			 DRV_NAME "@pci:%s", pci_name(dev->pdev));
8408c2ecf20Sopenharmony_ci		err = request_irq(dev->pdev->irq,
8418c2ecf20Sopenharmony_ci				  mthca_is_memfree(dev) ?
8428c2ecf20Sopenharmony_ci				  mthca_arbel_interrupt :
8438c2ecf20Sopenharmony_ci				  mthca_tavor_interrupt,
8448c2ecf20Sopenharmony_ci				  IRQF_SHARED, dev->eq_table.eq[0].irq_name, dev);
8458c2ecf20Sopenharmony_ci		if (err)
8468c2ecf20Sopenharmony_ci			goto err_out_cmd;
8478c2ecf20Sopenharmony_ci		dev->eq_table.have_irq = 1;
8488c2ecf20Sopenharmony_ci	}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	err = mthca_MAP_EQ(dev, async_mask(dev),
8518c2ecf20Sopenharmony_ci			   0, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
8528c2ecf20Sopenharmony_ci	if (err)
8538c2ecf20Sopenharmony_ci		mthca_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
8548c2ecf20Sopenharmony_ci			   dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn, err);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	err = mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,
8578c2ecf20Sopenharmony_ci			   0, dev->eq_table.eq[MTHCA_EQ_CMD].eqn);
8588c2ecf20Sopenharmony_ci	if (err)
8598c2ecf20Sopenharmony_ci		mthca_warn(dev, "MAP_EQ for cmd EQ %d failed (%d)\n",
8608c2ecf20Sopenharmony_ci			   dev->eq_table.eq[MTHCA_EQ_CMD].eqn, err);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	for (i = 0; i < MTHCA_NUM_EQ; ++i)
8638c2ecf20Sopenharmony_ci		if (mthca_is_memfree(dev))
8648c2ecf20Sopenharmony_ci			arbel_eq_req_not(dev, dev->eq_table.eq[i].eqn_mask);
8658c2ecf20Sopenharmony_ci		else
8668c2ecf20Sopenharmony_ci			tavor_eq_req_not(dev, dev->eq_table.eq[i].eqn);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	return 0;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_cierr_out_cmd:
8718c2ecf20Sopenharmony_ci	mthca_free_irqs(dev);
8728c2ecf20Sopenharmony_ci	mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_CMD]);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cierr_out_async:
8758c2ecf20Sopenharmony_ci	mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_ASYNC]);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cierr_out_comp:
8788c2ecf20Sopenharmony_ci	mthca_free_eq(dev, &dev->eq_table.eq[MTHCA_EQ_COMP]);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cierr_out_unmap:
8818c2ecf20Sopenharmony_ci	mthca_unmap_eq_regs(dev);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_cierr_out_free:
8848c2ecf20Sopenharmony_ci	mthca_alloc_cleanup(&dev->eq_table.alloc);
8858c2ecf20Sopenharmony_ci	return err;
8868c2ecf20Sopenharmony_ci}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_civoid mthca_cleanup_eq_table(struct mthca_dev *dev)
8898c2ecf20Sopenharmony_ci{
8908c2ecf20Sopenharmony_ci	int i;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	mthca_free_irqs(dev);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	mthca_MAP_EQ(dev, async_mask(dev),
8958c2ecf20Sopenharmony_ci		     1, dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
8968c2ecf20Sopenharmony_ci	mthca_MAP_EQ(dev, MTHCA_CMD_EVENT_MASK,
8978c2ecf20Sopenharmony_ci		     1, dev->eq_table.eq[MTHCA_EQ_CMD].eqn);
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	for (i = 0; i < MTHCA_NUM_EQ; ++i)
9008c2ecf20Sopenharmony_ci		mthca_free_eq(dev, &dev->eq_table.eq[i]);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	mthca_unmap_eq_regs(dev);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	mthca_alloc_cleanup(&dev->eq_table.alloc);
9058c2ecf20Sopenharmony_ci}
906