Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-only
config INFINIBAND_CXGB4
tristate "Chelsio T4/T5 RDMA Driver"
depends on CHELSIO_T4 && INET
depends on INFINIBAND_ADDR_TRANS
select CHELSIO_LIB
select GENERIC_ALLOCATOR
help
This is an iWARP/RDMA driver for the Chelsio T4 and T5
1GbE, 10GbE adapters and T5 40GbE adapter.
For general information about Chelsio and our products, visit
our website at <http://www.chelsio.com>.
For customer support, please visit our customer support page at
<http://www.chelsio.com/support.html>.
Please send feedback to <linux-bugs@chelsio.com>.
To compile this driver as a module, choose M here: the module
will be called iw_cxgb4.
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
ccflags-y := -I $(srctree)/drivers/net/ethernet/chelsio/cxgb4
ccflags-y += -I $(srctree)/drivers/net/ethernet/chelsio/libcxgb
obj-$(CONFIG_INFINIBAND_CXGB4) += iw_cxgb4.o
iw_cxgb4-y := device.o cm.o provider.o mem.o cq.o qp.o resource.o ev.o id_table.o \
restrack.o
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,242 @@
/*
* Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/slab.h>
#include <linux/mman.h>
#include <net/sock.h>
#include "iw_cxgb4.h"
static void print_tpte(struct c4iw_dev *dev, u32 stag)
{
int ret;
struct fw_ri_tpte tpte;
ret = cxgb4_read_tpte(dev->rdev.lldi.ports[0], stag,
(__be32 *)&tpte);
if (ret) {
dev_err(&dev->rdev.lldi.pdev->dev,
"%s cxgb4_read_tpte err %d\n", __func__, ret);
return;
}
pr_debug("stag idx 0x%x valid %d key 0x%x state %d pdid %d perm 0x%x ps %d len 0x%llx va 0x%llx\n",
stag & 0xffffff00,
FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid)),
FW_RI_TPTE_STAGKEY_G(ntohl(tpte.valid_to_pdid)),
FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid)),
FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid)),
FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid)),
FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid)),
((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo),
((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo));
}
static void dump_err_cqe(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
{
__be64 *p = (void *)err_cqe;
dev_err(&dev->rdev.lldi.pdev->dev,
"AE qpid %d opcode %d status 0x%x "
"type %d len 0x%x wrid.hi 0x%x wrid.lo 0x%x\n",
CQE_QPID(err_cqe), CQE_OPCODE(err_cqe),
CQE_STATUS(err_cqe), CQE_TYPE(err_cqe), ntohl(err_cqe->len),
CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe));
pr_debug("%016llx %016llx %016llx %016llx - %016llx %016llx %016llx %016llx\n",
be64_to_cpu(p[0]), be64_to_cpu(p[1]), be64_to_cpu(p[2]),
be64_to_cpu(p[3]), be64_to_cpu(p[4]), be64_to_cpu(p[5]),
be64_to_cpu(p[6]), be64_to_cpu(p[7]));
/*
* Ingress WRITE and READ_RESP errors provide
* the offending stag, so parse and log it.
*/
if (RQ_TYPE(err_cqe) && (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE ||
CQE_OPCODE(err_cqe) == FW_RI_READ_RESP))
print_tpte(dev, CQE_WRID_STAG(err_cqe));
}
static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
struct c4iw_qp *qhp,
struct t4_cqe *err_cqe,
enum ib_event_type ib_event)
{
struct ib_event event;
struct c4iw_qp_attributes attrs;
unsigned long flag;
dump_err_cqe(dev, err_cqe);
if (qhp->attr.state == C4IW_QP_STATE_RTS) {
attrs.next_state = C4IW_QP_STATE_TERMINATE;
c4iw_modify_qp(qhp->rhp, qhp, C4IW_QP_ATTR_NEXT_STATE,
&attrs, 0);
}
event.event = ib_event;
event.device = chp->ibcq.device;
if (ib_event == IB_EVENT_CQ_ERR)
event.element.cq = &chp->ibcq;
else
event.element.qp = &qhp->ibqp;
if (qhp->ibqp.event_handler)
(*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
if (t4_clear_cq_armed(&chp->cq)) {
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
}
}
void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
{
struct c4iw_cq *chp;
struct c4iw_qp *qhp;
u32 cqid;
xa_lock_irq(&dev->qps);
qhp = xa_load(&dev->qps, CQE_QPID(err_cqe));
if (!qhp) {
pr_err("BAD AE qpid 0x%x opcode %d status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n",
CQE_QPID(err_cqe),
CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
CQE_WRID_LOW(err_cqe));
xa_unlock_irq(&dev->qps);
goto out;
}
if (SQ_TYPE(err_cqe))
cqid = qhp->attr.scq;
else
cqid = qhp->attr.rcq;
chp = get_chp(dev, cqid);
if (!chp) {
pr_err("BAD AE cqid 0x%x qpid 0x%x opcode %d status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n",
cqid, CQE_QPID(err_cqe),
CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
CQE_WRID_LOW(err_cqe));
xa_unlock_irq(&dev->qps);
goto out;
}
c4iw_qp_add_ref(&qhp->ibqp);
refcount_inc(&chp->refcnt);
xa_unlock_irq(&dev->qps);
/* Bad incoming write */
if (RQ_TYPE(err_cqe) &&
(CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE)) {
post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_REQ_ERR);
goto done;
}
switch (CQE_STATUS(err_cqe)) {
/* Completion Events */
case T4_ERR_SUCCESS:
pr_err("AE with status 0!\n");
break;
case T4_ERR_STAG:
case T4_ERR_PDID:
case T4_ERR_QPID:
case T4_ERR_ACCESS:
case T4_ERR_WRAP:
case T4_ERR_BOUND:
case T4_ERR_INVALIDATE_SHARED_MR:
case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND:
post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_ACCESS_ERR);
break;
/* Device Fatal Errors */
case T4_ERR_ECC:
case T4_ERR_ECC_PSTAG:
case T4_ERR_INTERNAL_ERR:
post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_DEVICE_FATAL);
break;
/* QP Fatal Errors */
case T4_ERR_OUT_OF_RQE:
case T4_ERR_PBL_ADDR_BOUND:
case T4_ERR_CRC:
case T4_ERR_MARKER:
case T4_ERR_PDU_LEN_ERR:
case T4_ERR_DDP_VERSION:
case T4_ERR_RDMA_VERSION:
case T4_ERR_OPCODE:
case T4_ERR_DDP_QUEUE_NUM:
case T4_ERR_MSN:
case T4_ERR_TBIT:
case T4_ERR_MO:
case T4_ERR_MSN_GAP:
case T4_ERR_MSN_RANGE:
case T4_ERR_RQE_ADDR_BOUND:
case T4_ERR_IRD_OVERFLOW:
post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL);
break;
default:
pr_err("Unknown T4 status 0x%x QPID 0x%x\n",
CQE_STATUS(err_cqe), qhp->wq.sq.qid);
post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL);
break;
}
done:
c4iw_cq_rem_ref(chp);
c4iw_qp_rem_ref(&qhp->ibqp);
out:
return;
}
int c4iw_ev_handler(struct c4iw_dev *dev, u32 qid)
{
struct c4iw_cq *chp;
unsigned long flag;
xa_lock_irqsave(&dev->cqs, flag);
chp = xa_load(&dev->cqs, qid);
if (chp) {
refcount_inc(&chp->refcnt);
xa_unlock_irqrestore(&dev->cqs, flag);
t4_clear_cq_armed(&chp->cq);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
c4iw_cq_rem_ref(chp);
} else {
pr_debug("unknown cqid 0x%x\n", qid);
xa_unlock_irqrestore(&dev->cqs, flag);
}
return 0;
}
@@ -0,0 +1,106 @@
/*
* Copyright (c) 2011 Chelsio Communications. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/random.h>
#include "iw_cxgb4.h"
#define RANDOM_SKIP 16
/*
* Trivial bitmap-based allocator. If the random flag is set, the
* allocator is designed to:
* - pseudo-randomize the id returned such that it is not trivially predictable.
* - avoid reuse of recently used id (at the expense of predictability)
*/
u32 c4iw_id_alloc(struct c4iw_id_table *alloc)
{
unsigned long flags;
u32 obj;
spin_lock_irqsave(&alloc->lock, flags);
obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last);
if (obj >= alloc->max)
obj = find_first_zero_bit(alloc->table, alloc->max);
if (obj < alloc->max) {
if (alloc->flags & C4IW_ID_TABLE_F_RANDOM)
alloc->last += get_random_u32_below(RANDOM_SKIP);
else
alloc->last = obj + 1;
if (alloc->last >= alloc->max)
alloc->last = 0;
__set_bit(obj, alloc->table);
obj += alloc->start;
} else
obj = -1;
spin_unlock_irqrestore(&alloc->lock, flags);
return obj;
}
void c4iw_id_free(struct c4iw_id_table *alloc, u32 obj)
{
unsigned long flags;
obj -= alloc->start;
spin_lock_irqsave(&alloc->lock, flags);
__clear_bit(obj, alloc->table);
spin_unlock_irqrestore(&alloc->lock, flags);
}
int c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num,
u32 reserved, u32 flags)
{
alloc->start = start;
alloc->flags = flags;
if (flags & C4IW_ID_TABLE_F_RANDOM)
alloc->last = get_random_u32_below(RANDOM_SKIP);
else
alloc->last = 0;
alloc->max = num;
spin_lock_init(&alloc->lock);
alloc->table = bitmap_zalloc(num, GFP_KERNEL);
if (!alloc->table)
return -ENOMEM;
if (!(alloc->flags & C4IW_ID_TABLE_F_EMPTY))
bitmap_set(alloc->table, 0, reserved);
return 0;
}
void c4iw_id_table_free(struct c4iw_id_table *alloc)
{
bitmap_free(alloc->table);
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,743 @@
/*
* Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/atomic.h>
#include <rdma/ib_user_verbs.h>
#include <rdma/iter.h>
#include "iw_cxgb4.h"
int use_dsgl = 1;
module_param(use_dsgl, int, 0644);
MODULE_PARM_DESC(use_dsgl, "Use DSGL for PBL/FastReg (default=1) (DEPRECATED)");
#define T4_ULPTX_MIN_IO 32
#define C4IW_MAX_INLINE_SIZE 96
#define T4_ULPTX_MAX_DMA 1024
#define C4IW_INLINE_THRESHOLD 128
static int inline_threshold = C4IW_INLINE_THRESHOLD;
module_param(inline_threshold, int, 0644);
MODULE_PARM_DESC(inline_threshold, "inline vs dsgl threshold (default=128)");
static int mr_exceeds_hw_limits(struct c4iw_dev *dev, u64 length)
{
return (is_t4(dev->rdev.lldi.adapter_type) ||
is_t5(dev->rdev.lldi.adapter_type)) &&
length >= 8*1024*1024*1024ULL;
}
static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
u32 len, dma_addr_t data,
struct sk_buff *skb,
struct c4iw_wr_wait *wr_waitp)
{
struct ulp_mem_io *req;
struct ulptx_sgl *sgl;
u8 wr_len;
int ret = 0;
addr &= 0x7FFFFFF;
if (wr_waitp)
c4iw_init_wr_wait(wr_waitp);
wr_len = roundup(sizeof(*req) + sizeof(*sgl), 16);
if (!skb) {
skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
if (!skb)
return -ENOMEM;
}
set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
req = __skb_put_zero(skb, wr_len);
INIT_ULPTX_WR(req, wr_len, 0, 0);
req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
(wr_waitp ? FW_WR_COMPL_F : 0));
req->wr.wr_lo = wr_waitp ? (__force __be64)(unsigned long)wr_waitp : 0L;
req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
req->cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE) |
T5_ULP_MEMIO_ORDER_V(1) |
T5_ULP_MEMIO_FID_V(rdev->lldi.rxq_ids[0]));
req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(len>>5));
req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 16));
req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr));
sgl = (struct ulptx_sgl *)(req + 1);
sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
ULPTX_NSGE_V(1));
sgl->len0 = cpu_to_be32(len);
sgl->addr0 = cpu_to_be64(data);
if (wr_waitp)
ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
else
ret = c4iw_ofld_send(rdev, skb);
return ret;
}
static int _c4iw_write_mem_inline(struct c4iw_rdev *rdev, u32 addr, u32 len,
void *data, struct sk_buff *skb,
struct c4iw_wr_wait *wr_waitp)
{
struct ulp_mem_io *req;
struct ulptx_idata *sc;
u8 wr_len, *to_dp, *from_dp;
int copy_len, num_wqe, i, ret = 0;
__be32 cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE));
if (is_t4(rdev->lldi.adapter_type))
cmd |= cpu_to_be32(ULP_MEMIO_ORDER_F);
else
cmd |= cpu_to_be32(T5_ULP_MEMIO_IMM_F);
addr &= 0x7FFFFFF;
pr_debug("addr 0x%x len %u\n", addr, len);
num_wqe = DIV_ROUND_UP(len, C4IW_MAX_INLINE_SIZE);
c4iw_init_wr_wait(wr_waitp);
for (i = 0; i < num_wqe; i++) {
copy_len = len > C4IW_MAX_INLINE_SIZE ? C4IW_MAX_INLINE_SIZE :
len;
wr_len = roundup(sizeof(*req) + sizeof(*sc) +
roundup(copy_len, T4_ULPTX_MIN_IO),
16);
if (!skb) {
skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
if (!skb)
return -ENOMEM;
}
set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
req = __skb_put_zero(skb, wr_len);
INIT_ULPTX_WR(req, wr_len, 0, 0);
if (i == (num_wqe-1)) {
req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) |
FW_WR_COMPL_F);
req->wr.wr_lo = (__force __be64)(unsigned long)wr_waitp;
} else
req->wr.wr_hi = cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR));
req->wr.wr_mid = cpu_to_be32(
FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
req->cmd = cmd;
req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(
DIV_ROUND_UP(copy_len, T4_ULPTX_MIN_IO)));
req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr),
16));
req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr + i * 3));
sc = (struct ulptx_idata *)(req + 1);
sc->cmd_more = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_IMM));
sc->len = cpu_to_be32(roundup(copy_len, T4_ULPTX_MIN_IO));
to_dp = (u8 *)(sc + 1);
from_dp = (u8 *)data + i * C4IW_MAX_INLINE_SIZE;
if (data)
memcpy(to_dp, from_dp, copy_len);
else
memset(to_dp, 0, copy_len);
if (copy_len % T4_ULPTX_MIN_IO)
memset(to_dp + copy_len, 0, T4_ULPTX_MIN_IO -
(copy_len % T4_ULPTX_MIN_IO));
if (i == (num_wqe-1))
ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0,
__func__);
else
ret = c4iw_ofld_send(rdev, skb);
if (ret)
break;
skb = NULL;
len -= C4IW_MAX_INLINE_SIZE;
}
return ret;
}
static int _c4iw_write_mem_dma(struct c4iw_rdev *rdev, u32 addr, u32 len,
void *data, struct sk_buff *skb,
struct c4iw_wr_wait *wr_waitp)
{
u32 remain = len;
u32 dmalen;
int ret = 0;
dma_addr_t daddr;
dma_addr_t save;
daddr = dma_map_single(&rdev->lldi.pdev->dev, data, len, DMA_TO_DEVICE);
if (dma_mapping_error(&rdev->lldi.pdev->dev, daddr))
return -1;
save = daddr;
while (remain > inline_threshold) {
if (remain < T4_ULPTX_MAX_DMA) {
if (remain & ~T4_ULPTX_MIN_IO)
dmalen = remain & ~(T4_ULPTX_MIN_IO-1);
else
dmalen = remain;
} else
dmalen = T4_ULPTX_MAX_DMA;
remain -= dmalen;
ret = _c4iw_write_mem_dma_aligned(rdev, addr, dmalen, daddr,
skb, remain ? NULL : wr_waitp);
if (ret)
goto out;
addr += dmalen >> 5;
data += dmalen;
daddr += dmalen;
}
if (remain)
ret = _c4iw_write_mem_inline(rdev, addr, remain, data, skb,
wr_waitp);
out:
dma_unmap_single(&rdev->lldi.pdev->dev, save, len, DMA_TO_DEVICE);
return ret;
}
/*
* write len bytes of data into addr (32B aligned address)
* If data is NULL, clear len byte of memory to zero.
*/
static int write_adapter_mem(struct c4iw_rdev *rdev, u32 addr, u32 len,
void *data, struct sk_buff *skb,
struct c4iw_wr_wait *wr_waitp)
{
int ret;
if (!rdev->lldi.ulptx_memwrite_dsgl || !use_dsgl) {
ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
wr_waitp);
goto out;
}
if (len <= inline_threshold) {
ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
wr_waitp);
goto out;
}
ret = _c4iw_write_mem_dma(rdev, addr, len, data, skb, wr_waitp);
if (ret) {
pr_warn_ratelimited("%s: dma map failure (non fatal)\n",
pci_name(rdev->lldi.pdev));
ret = _c4iw_write_mem_inline(rdev, addr, len, data, skb,
wr_waitp);
}
out:
return ret;
}
/*
* Build and write a TPT entry.
* IN: stag key, pdid, perm, bind_enabled, zbva, to, len, page_size,
* pbl_size and pbl_addr
* OUT: stag index
*/
static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
u32 *stag, u8 stag_state, u32 pdid,
enum fw_ri_stag_type type, enum fw_ri_mem_perms perm,
int bind_enabled, u32 zbva, u64 to,
u64 len, u8 page_size, u32 pbl_size, u32 pbl_addr,
struct sk_buff *skb, struct c4iw_wr_wait *wr_waitp)
{
int err;
struct fw_ri_tpte *tpt;
u32 stag_idx;
static atomic_t key;
if (c4iw_fatal_error(rdev))
return -EIO;
tpt = kmalloc_obj(*tpt);
if (!tpt)
return -ENOMEM;
stag_state = stag_state > 0;
stag_idx = (*stag) >> 8;
if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) {
stag_idx = c4iw_get_resource(&rdev->resource.tpt_table);
if (!stag_idx) {
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.fail++;
mutex_unlock(&rdev->stats.lock);
kfree(tpt);
return -ENOMEM;
}
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.cur += 32;
if (rdev->stats.stag.cur > rdev->stats.stag.max)
rdev->stats.stag.max = rdev->stats.stag.cur;
mutex_unlock(&rdev->stats.lock);
*stag = (stag_idx << 8) | (atomic_inc_return(&key) & 0xff);
}
pr_debug("stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
stag_state, type, pdid, stag_idx);
/* write TPT entry */
if (reset_tpt_entry)
memset(tpt, 0, sizeof(*tpt));
else {
tpt->valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
FW_RI_TPTE_STAGKEY_V((*stag & FW_RI_TPTE_STAGKEY_M)) |
FW_RI_TPTE_STAGSTATE_V(stag_state) |
FW_RI_TPTE_STAGTYPE_V(type) | FW_RI_TPTE_PDID_V(pdid));
tpt->locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) |
(bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0) |
FW_RI_TPTE_ADDRTYPE_V((zbva ? FW_RI_ZERO_BASED_TO :
FW_RI_VA_BASED_TO))|
FW_RI_TPTE_PS_V(page_size));
tpt->nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
FW_RI_TPTE_PBLADDR_V(PBL_OFF(rdev, pbl_addr)>>3));
tpt->len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
tpt->va_hi = cpu_to_be32((u32)(to >> 32));
tpt->va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
tpt->dca_mwbcnt_pstag = cpu_to_be32(0);
tpt->len_hi = cpu_to_be32((u32)(len >> 32));
}
err = write_adapter_mem(rdev, stag_idx +
(rdev->lldi.vr->stag.start >> 5),
sizeof(*tpt), tpt, skb, wr_waitp);
if (reset_tpt_entry) {
c4iw_put_resource(&rdev->resource.tpt_table, stag_idx);
mutex_lock(&rdev->stats.lock);
rdev->stats.stag.cur -= 32;
mutex_unlock(&rdev->stats.lock);
}
kfree(tpt);
return err;
}
static int write_pbl(struct c4iw_rdev *rdev, __be64 *pbl,
u32 pbl_addr, u32 pbl_size, struct c4iw_wr_wait *wr_waitp)
{
int err;
pr_debug("*pbl_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
pbl_addr, rdev->lldi.vr->pbl.start,
pbl_size);
err = write_adapter_mem(rdev, pbl_addr >> 5, pbl_size << 3, pbl, NULL,
wr_waitp);
return err;
}
static int dereg_mem(struct c4iw_rdev *rdev, u32 stag, u32 pbl_size,
u32 pbl_addr, struct sk_buff *skb,
struct c4iw_wr_wait *wr_waitp)
{
return write_tpt_entry(rdev, 1, &stag, 0, 0, 0, 0, 0, 0, 0UL, 0, 0,
pbl_size, pbl_addr, skb, wr_waitp);
}
static int allocate_stag(struct c4iw_rdev *rdev, u32 *stag, u32 pdid,
u32 pbl_size, u32 pbl_addr,
struct c4iw_wr_wait *wr_waitp)
{
*stag = T4_STAG_UNSET;
return write_tpt_entry(rdev, 0, stag, 0, pdid, FW_RI_STAG_NSMR, 0, 0, 0,
0UL, 0, 0, pbl_size, pbl_addr, NULL, wr_waitp);
}
static int finish_mem_reg(struct c4iw_mr *mhp, u32 stag)
{
u32 mmid;
mhp->attr.state = 1;
mhp->attr.stag = stag;
mmid = stag >> 8;
mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
mhp->ibmr.length = mhp->attr.len;
mhp->ibmr.page_size = 1U << (mhp->attr.page_size + 12);
pr_debug("mmid 0x%x mhp %p\n", mmid, mhp);
return xa_insert_irq(&mhp->rhp->mrs, mmid, mhp, GFP_KERNEL);
}
static int register_mem(struct c4iw_dev *rhp, struct c4iw_pd *php,
struct c4iw_mr *mhp, int shift)
{
u32 stag = T4_STAG_UNSET;
int ret;
ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, mhp->attr.pdid,
FW_RI_STAG_NSMR, mhp->attr.len ?
mhp->attr.perms : 0,
mhp->attr.mw_bind_enable, mhp->attr.zbva,
mhp->attr.va_fbo, mhp->attr.len ?
mhp->attr.len : -1, shift - 12,
mhp->attr.pbl_size, mhp->attr.pbl_addr, NULL,
mhp->wr_waitp);
if (ret)
return ret;
ret = finish_mem_reg(mhp, stag);
if (ret) {
dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
mhp->dereg_skb = NULL;
}
return ret;
}
static int alloc_pbl(struct c4iw_mr *mhp, int npages)
{
mhp->attr.pbl_addr = c4iw_pblpool_alloc(&mhp->rhp->rdev,
npages << 3);
if (!mhp->attr.pbl_addr)
return -ENOMEM;
mhp->attr.pbl_size = npages;
return 0;
}
struct ib_mr *c4iw_get_dma_mr(struct ib_pd *pd, int acc)
{
struct c4iw_dev *rhp;
struct c4iw_pd *php;
struct c4iw_mr *mhp;
int ret;
u32 stag = T4_STAG_UNSET;
pr_debug("ib_pd %p\n", pd);
php = to_c4iw_pd(pd);
rhp = php->rhp;
mhp = kzalloc_obj(*mhp);
if (!mhp)
return ERR_PTR(-ENOMEM);
mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
if (!mhp->wr_waitp) {
ret = -ENOMEM;
goto err_free_mhp;
}
c4iw_init_wr_wait(mhp->wr_waitp);
mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
if (!mhp->dereg_skb) {
ret = -ENOMEM;
goto err_free_wr_wait;
}
mhp->rhp = rhp;
mhp->attr.pdid = php->pdid;
mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
mhp->attr.mw_bind_enable = (acc&IB_ACCESS_MW_BIND) == IB_ACCESS_MW_BIND;
mhp->attr.zbva = 0;
mhp->attr.va_fbo = 0;
mhp->attr.page_size = 0;
mhp->attr.len = ~0ULL;
mhp->attr.pbl_size = 0;
ret = write_tpt_entry(&rhp->rdev, 0, &stag, 1, php->pdid,
FW_RI_STAG_NSMR, mhp->attr.perms,
mhp->attr.mw_bind_enable, 0, 0, ~0ULL, 0, 0, 0,
NULL, mhp->wr_waitp);
if (ret)
goto err_free_skb;
ret = finish_mem_reg(mhp, stag);
if (ret)
goto err_dereg_mem;
return &mhp->ibmr;
err_dereg_mem:
dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
err_free_skb:
kfree_skb(mhp->dereg_skb);
err_free_wr_wait:
c4iw_put_wr_wait(mhp->wr_waitp);
err_free_mhp:
kfree(mhp);
return ERR_PTR(ret);
}
struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
u64 virt, int acc, struct ib_dmah *dmah,
struct ib_udata *udata)
{
__be64 *pages;
int shift, n, i;
int err = -ENOMEM;
struct ib_block_iter biter;
struct c4iw_dev *rhp;
struct c4iw_pd *php;
struct c4iw_mr *mhp;
pr_debug("ib_pd %p\n", pd);
if (dmah)
return ERR_PTR(-EOPNOTSUPP);
if (length == ~0ULL)
return ERR_PTR(-EINVAL);
if ((length + start) < start)
return ERR_PTR(-EINVAL);
php = to_c4iw_pd(pd);
rhp = php->rhp;
if (mr_exceeds_hw_limits(rhp, length))
return ERR_PTR(-EINVAL);
mhp = kzalloc_obj(*mhp);
if (!mhp)
return ERR_PTR(-ENOMEM);
mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
if (!mhp->wr_waitp)
goto err_free_mhp;
mhp->dereg_skb = alloc_skb(SGE_MAX_WR_LEN, GFP_KERNEL);
if (!mhp->dereg_skb)
goto err_free_wr_wait;
mhp->rhp = rhp;
mhp->umem = ib_umem_get_va(pd->device, start, length, acc);
if (IS_ERR(mhp->umem))
goto err_free_skb;
shift = PAGE_SHIFT;
n = ib_umem_num_dma_blocks(mhp->umem, 1 << shift);
err = alloc_pbl(mhp, n);
if (err)
goto err_umem_release;
pages = (__be64 *) __get_free_page(GFP_KERNEL);
if (!pages) {
err = -ENOMEM;
goto err_pbl_free;
}
i = n = 0;
rdma_umem_for_each_dma_block(mhp->umem, &biter, 1 << shift) {
pages[i++] = cpu_to_be64(rdma_block_iter_dma_address(&biter));
if (i == PAGE_SIZE / sizeof(*pages)) {
err = write_pbl(&mhp->rhp->rdev, pages,
mhp->attr.pbl_addr + (n << 3), i,
mhp->wr_waitp);
if (err)
goto pbl_done;
n += i;
i = 0;
}
}
if (i)
err = write_pbl(&mhp->rhp->rdev, pages,
mhp->attr.pbl_addr + (n << 3), i,
mhp->wr_waitp);
pbl_done:
free_page((unsigned long) pages);
if (err)
goto err_pbl_free;
mhp->attr.pdid = php->pdid;
mhp->attr.zbva = 0;
mhp->attr.perms = c4iw_ib_to_tpt_access(acc);
mhp->attr.va_fbo = virt;
mhp->attr.page_size = shift - 12;
mhp->attr.len = length;
err = register_mem(rhp, php, mhp, shift);
if (err)
goto err_pbl_free;
return &mhp->ibmr;
err_pbl_free:
c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
mhp->attr.pbl_size << 3);
err_umem_release:
ib_umem_release(mhp->umem);
err_free_skb:
kfree_skb(mhp->dereg_skb);
err_free_wr_wait:
c4iw_put_wr_wait(mhp->wr_waitp);
err_free_mhp:
kfree(mhp);
return ERR_PTR(err);
}
struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type,
u32 max_num_sg)
{
struct c4iw_dev *rhp;
struct c4iw_pd *php;
struct c4iw_mr *mhp;
u32 mmid;
u32 stag = 0;
int ret = 0;
int length = roundup(max_num_sg * sizeof(u64), 32);
php = to_c4iw_pd(pd);
rhp = php->rhp;
if (mr_type != IB_MR_TYPE_MEM_REG ||
max_num_sg > t4_max_fr_depth(rhp->rdev.lldi.ulptx_memwrite_dsgl &&
use_dsgl))
return ERR_PTR(-EINVAL);
mhp = kzalloc_obj(*mhp);
if (!mhp) {
ret = -ENOMEM;
goto err;
}
mhp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
if (!mhp->wr_waitp) {
ret = -ENOMEM;
goto err_free_mhp;
}
c4iw_init_wr_wait(mhp->wr_waitp);
mhp->mpl = dma_alloc_coherent(&rhp->rdev.lldi.pdev->dev,
length, &mhp->mpl_addr, GFP_KERNEL);
if (!mhp->mpl) {
ret = -ENOMEM;
goto err_free_wr_wait;
}
mhp->max_mpl_len = length;
mhp->rhp = rhp;
ret = alloc_pbl(mhp, max_num_sg);
if (ret)
goto err_free_dma;
mhp->attr.pbl_size = max_num_sg;
ret = allocate_stag(&rhp->rdev, &stag, php->pdid,
mhp->attr.pbl_size, mhp->attr.pbl_addr,
mhp->wr_waitp);
if (ret)
goto err_free_pbl;
mhp->attr.pdid = php->pdid;
mhp->attr.type = FW_RI_STAG_NSMR;
mhp->attr.stag = stag;
mhp->attr.state = 0;
mmid = (stag) >> 8;
mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
if (xa_insert_irq(&rhp->mrs, mmid, mhp, GFP_KERNEL)) {
ret = -ENOMEM;
goto err_dereg;
}
pr_debug("mmid 0x%x mhp %p stag 0x%x\n", mmid, mhp, stag);
return &(mhp->ibmr);
err_dereg:
dereg_mem(&rhp->rdev, stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
err_free_pbl:
c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
mhp->attr.pbl_size << 3);
err_free_dma:
dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
err_free_wr_wait:
c4iw_put_wr_wait(mhp->wr_waitp);
err_free_mhp:
kfree(mhp);
err:
return ERR_PTR(ret);
}
static int c4iw_set_page(struct ib_mr *ibmr, u64 addr)
{
struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
if (unlikely(mhp->mpl_len == mhp->attr.pbl_size))
return -ENOMEM;
mhp->mpl[mhp->mpl_len++] = addr;
return 0;
}
int c4iw_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents,
unsigned int *sg_offset)
{
struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
mhp->mpl_len = 0;
return ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, c4iw_set_page);
}
int c4iw_dereg_mr(struct ib_mr *ib_mr, struct ib_udata *udata)
{
struct c4iw_dev *rhp;
struct c4iw_mr *mhp;
u32 mmid;
pr_debug("ib_mr %p\n", ib_mr);
mhp = to_c4iw_mr(ib_mr);
rhp = mhp->rhp;
mmid = mhp->attr.stag >> 8;
xa_erase_irq(&rhp->mrs, mmid);
if (mhp->mpl)
dma_free_coherent(&mhp->rhp->rdev.lldi.pdev->dev,
mhp->max_mpl_len, mhp->mpl, mhp->mpl_addr);
dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr, mhp->dereg_skb, mhp->wr_waitp);
if (mhp->attr.pbl_size)
c4iw_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
mhp->attr.pbl_size << 3);
if (mhp->kva)
kfree((void *) (unsigned long) mhp->kva);
ib_umem_release(mhp->umem);
pr_debug("mmid 0x%x ptr %p\n", mmid, mhp);
c4iw_put_wr_wait(mhp->wr_waitp);
kfree(mhp);
return 0;
}
void c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey)
{
struct c4iw_mr *mhp;
unsigned long flags;
xa_lock_irqsave(&rhp->mrs, flags);
mhp = xa_load(&rhp->mrs, rkey >> 8);
if (mhp)
mhp->attr.state = 0;
xa_unlock_irqrestore(&rhp->mrs, flags);
}
@@ -0,0 +1,573 @@
/*
* Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include <linux/inetdevice.h>
#include <net/addrconf.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
#include <rdma/iw_cm.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_smi.h>
#include <rdma/ib_umem.h>
#include <rdma/ib_user_verbs.h>
#include <rdma/uverbs_ioctl.h>
#include "iw_cxgb4.h"
static int fastreg_support = 1;
module_param(fastreg_support, int, 0644);
MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=1)");
static void c4iw_dealloc_ucontext(struct ib_ucontext *context)
{
struct c4iw_ucontext *ucontext = to_c4iw_ucontext(context);
struct c4iw_dev *rhp;
struct c4iw_mm_entry *mm, *tmp;
pr_debug("context %p\n", context);
rhp = to_c4iw_dev(ucontext->ibucontext.device);
list_for_each_entry_safe(mm, tmp, &ucontext->mmaps, entry)
kfree(mm);
c4iw_release_dev_ucontext(&rhp->rdev, &ucontext->uctx);
}
static int c4iw_alloc_ucontext(struct ib_ucontext *ucontext,
struct ib_udata *udata)
{
struct ib_device *ibdev = ucontext->device;
struct c4iw_ucontext *context = to_c4iw_ucontext(ucontext);
struct c4iw_dev *rhp = to_c4iw_dev(ibdev);
struct c4iw_alloc_ucontext_resp uresp = {};
int ret = 0;
struct c4iw_mm_entry *mm = NULL;
pr_debug("ibdev %p\n", ibdev);
c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx);
INIT_LIST_HEAD(&context->mmaps);
spin_lock_init(&context->mmap_lock);
if (udata->outlen < sizeof(uresp) - sizeof(uresp.reserved)) {
pr_err_once("Warning - downlevel libcxgb4 (non-fatal), device status page disabled\n");
rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
} else {
mm = kmalloc_obj(*mm);
if (!mm) {
ret = -ENOMEM;
goto err;
}
uresp.status_page_size = PAGE_SIZE;
spin_lock(&context->mmap_lock);
uresp.status_page_key = context->key;
context->key += PAGE_SIZE;
spin_unlock(&context->mmap_lock);
ret = ib_respond_udata(udata, uresp);
if (ret)
goto err_mm;
mm->key = uresp.status_page_key;
mm->addr = virt_to_phys(rhp->rdev.status_page);
mm->len = PAGE_SIZE;
mm->vaddr = NULL;
mm->dma_addr = 0;
insert_flag_to_mmap(&rhp->rdev, mm, mm->addr);
insert_mmap(context, mm);
}
return 0;
err_mm:
kfree(mm);
err:
return ret;
}
static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
{
int len = vma->vm_end - vma->vm_start;
u32 key = vma->vm_pgoff << PAGE_SHIFT;
struct c4iw_rdev *rdev;
int ret = 0;
struct c4iw_mm_entry *mm;
struct c4iw_ucontext *ucontext;
u64 addr;
u8 mmap_flag;
size_t size;
void *vaddr;
unsigned long vm_pgoff;
dma_addr_t dma_addr;
pr_debug("pgoff 0x%lx key 0x%x len %d\n", vma->vm_pgoff,
key, len);
if (vma->vm_start & (PAGE_SIZE-1))
return -EINVAL;
rdev = &(to_c4iw_dev(context->device)->rdev);
ucontext = to_c4iw_ucontext(context);
mm = remove_mmap(ucontext, key, len);
if (!mm)
return -EINVAL;
addr = mm->addr;
vaddr = mm->vaddr;
dma_addr = mm->dma_addr;
size = mm->len;
mmap_flag = mm->mmap_flag;
kfree(mm);
switch (mmap_flag) {
case CXGB4_MMAP_BAR:
ret = io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
len,
pgprot_noncached(vma->vm_page_prot));
break;
case CXGB4_MMAP_BAR_WC:
ret = io_remap_pfn_range(vma, vma->vm_start,
addr >> PAGE_SHIFT,
len, t4_pgprot_wc(vma->vm_page_prot));
break;
case CXGB4_MMAP_CONTIG:
ret = io_remap_pfn_range(vma, vma->vm_start,
addr >> PAGE_SHIFT,
len, vma->vm_page_prot);
break;
case CXGB4_MMAP_NON_CONTIG:
vm_pgoff = vma->vm_pgoff;
vma->vm_pgoff = 0;
ret = dma_mmap_coherent(&rdev->lldi.pdev->dev, vma,
vaddr, dma_addr, size);
vma->vm_pgoff = vm_pgoff;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static int c4iw_deallocate_pd(struct ib_pd *pd, struct ib_udata *udata)
{
struct c4iw_dev *rhp;
struct c4iw_pd *php;
php = to_c4iw_pd(pd);
rhp = php->rhp;
pr_debug("ibpd %p pdid 0x%x\n", pd, php->pdid);
c4iw_put_resource(&rhp->rdev.resource.pdid_table, php->pdid);
mutex_lock(&rhp->rdev.stats.lock);
rhp->rdev.stats.pd.cur--;
mutex_unlock(&rhp->rdev.stats.lock);
return 0;
}
static int c4iw_allocate_pd(struct ib_pd *pd, struct ib_udata *udata)
{
struct c4iw_pd *php = to_c4iw_pd(pd);
struct ib_device *ibdev = pd->device;
struct c4iw_dev *rhp;
u32 pdid;
int ret;
pr_debug("ibdev %p\n", ibdev);
rhp = (struct c4iw_dev *) ibdev;
pdid = c4iw_get_resource(&rhp->rdev.resource.pdid_table);
if (!pdid)
return -EINVAL;
php->pdid = pdid;
php->rhp = rhp;
if (udata) {
struct c4iw_alloc_pd_resp uresp = {.pdid = php->pdid};
ret = ib_respond_udata(udata, uresp);
if (ret) {
c4iw_deallocate_pd(&php->ibpd, udata);
return ret;
}
}
mutex_lock(&rhp->rdev.stats.lock);
rhp->rdev.stats.pd.cur++;
if (rhp->rdev.stats.pd.cur > rhp->rdev.stats.pd.max)
rhp->rdev.stats.pd.max = rhp->rdev.stats.pd.cur;
mutex_unlock(&rhp->rdev.stats.lock);
pr_debug("pdid 0x%0x ptr 0x%p\n", pdid, php);
return 0;
}
static int c4iw_query_gid(struct ib_device *ibdev, u32 port, int index,
union ib_gid *gid)
{
struct c4iw_dev *dev;
pr_debug("ibdev %p, port %u, index %d, gid %p\n",
ibdev, port, index, gid);
if (!port)
return -EINVAL;
dev = to_c4iw_dev(ibdev);
memset(&(gid->raw[0]), 0, sizeof(gid->raw));
memcpy(&(gid->raw[0]), dev->rdev.lldi.ports[port-1]->dev_addr, 6);
return 0;
}
static int c4iw_query_device(struct ib_device *ibdev, struct ib_device_attr *props,
struct ib_udata *uhw)
{
struct c4iw_dev *dev;
int err;
pr_debug("ibdev %p\n", ibdev);
err = ib_is_udata_in_empty(uhw);
if (err)
return err;
dev = to_c4iw_dev(ibdev);
addrconf_addr_eui48((u8 *)&props->sys_image_guid,
dev->rdev.lldi.ports[0]->dev_addr);
props->hw_ver = CHELSIO_CHIP_RELEASE(dev->rdev.lldi.adapter_type);
props->fw_ver = dev->rdev.lldi.fw_vers;
props->device_cap_flags = IB_DEVICE_MEM_WINDOW;
props->kernel_cap_flags = IBK_LOCAL_DMA_LKEY;
if (fastreg_support)
props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
props->page_size_cap = T4_PAGESIZE_MASK;
props->vendor_id = (u32)dev->rdev.lldi.pdev->vendor;
props->vendor_part_id = (u32)dev->rdev.lldi.pdev->device;
props->max_mr_size = T4_MAX_MR_SIZE;
props->max_qp = dev->rdev.lldi.vr->qp.size / 2;
props->max_srq = dev->rdev.lldi.vr->srq.size;
props->max_qp_wr = dev->rdev.hw_queue.t4_max_qp_depth;
props->max_srq_wr = dev->rdev.hw_queue.t4_max_qp_depth;
props->max_send_sge = min(T4_MAX_SEND_SGE, T4_MAX_WRITE_SGE);
props->max_recv_sge = T4_MAX_RECV_SGE;
props->max_srq_sge = T4_MAX_RECV_SGE;
props->max_sge_rd = 1;
props->max_res_rd_atom = dev->rdev.lldi.max_ird_adapter;
props->max_qp_rd_atom = min(dev->rdev.lldi.max_ordird_qp,
c4iw_max_read_depth);
props->max_qp_init_rd_atom = props->max_qp_rd_atom;
props->max_cq = dev->rdev.lldi.vr->qp.size;
props->max_cqe = dev->rdev.hw_queue.t4_max_cq_depth;
props->max_mr = c4iw_num_stags(&dev->rdev);
props->max_pd = T4_MAX_NUM_PD;
props->local_ca_ack_delay = 0;
props->max_fast_reg_page_list_len =
t4_max_fr_depth(dev->rdev.lldi.ulptx_memwrite_dsgl && use_dsgl);
return ib_respond_empty_udata(uhw);
}
static int c4iw_query_port(struct ib_device *ibdev, u32 port,
struct ib_port_attr *props)
{
int ret = 0;
pr_debug("ibdev %p\n", ibdev);
ret = ib_get_eth_speed(ibdev, port, &props->active_speed,
&props->active_width);
props->port_cap_flags =
IB_PORT_CM_SUP |
IB_PORT_SNMP_TUNNEL_SUP |
IB_PORT_REINIT_SUP |
IB_PORT_DEVICE_MGMT_SUP |
IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
props->gid_tbl_len = 1;
props->max_msg_sz = -1;
return ret;
}
static ssize_t hw_rev_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct c4iw_dev *c4iw_dev =
rdma_device_to_drv_device(dev, struct c4iw_dev, ibdev);
pr_debug("dev 0x%p\n", dev);
return sysfs_emit(
buf, "%d\n",
CHELSIO_CHIP_RELEASE(c4iw_dev->rdev.lldi.adapter_type));
}
static DEVICE_ATTR_RO(hw_rev);
static ssize_t hca_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct c4iw_dev *c4iw_dev =
rdma_device_to_drv_device(dev, struct c4iw_dev, ibdev);
struct ethtool_drvinfo info;
struct net_device *lldev = c4iw_dev->rdev.lldi.ports[0];
pr_debug("dev 0x%p\n", dev);
lldev->ethtool_ops->get_drvinfo(lldev, &info);
return sysfs_emit(buf, "%s\n", info.driver);
}
static DEVICE_ATTR_RO(hca_type);
static ssize_t board_id_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct c4iw_dev *c4iw_dev =
rdma_device_to_drv_device(dev, struct c4iw_dev, ibdev);
pr_debug("dev 0x%p\n", dev);
return sysfs_emit(buf, "%x.%x\n", c4iw_dev->rdev.lldi.pdev->vendor,
c4iw_dev->rdev.lldi.pdev->device);
}
static DEVICE_ATTR_RO(board_id);
enum counters {
IP4INSEGS,
IP4OUTSEGS,
IP4RETRANSSEGS,
IP4OUTRSTS,
IP6INSEGS,
IP6OUTSEGS,
IP6RETRANSSEGS,
IP6OUTRSTS,
NR_COUNTERS
};
static const struct rdma_stat_desc cxgb4_descs[] = {
[IP4INSEGS].name = "ip4InSegs",
[IP4OUTSEGS].name = "ip4OutSegs",
[IP4RETRANSSEGS].name = "ip4RetransSegs",
[IP4OUTRSTS].name = "ip4OutRsts",
[IP6INSEGS].name = "ip6InSegs",
[IP6OUTSEGS].name = "ip6OutSegs",
[IP6RETRANSSEGS].name = "ip6RetransSegs",
[IP6OUTRSTS].name = "ip6OutRsts"
};
static struct rdma_hw_stats *c4iw_alloc_device_stats(struct ib_device *ibdev)
{
BUILD_BUG_ON(ARRAY_SIZE(cxgb4_descs) != NR_COUNTERS);
/* FIXME: these look like port stats */
return rdma_alloc_hw_stats_struct(cxgb4_descs, NR_COUNTERS,
RDMA_HW_STATS_DEFAULT_LIFESPAN);
}
static int c4iw_get_mib(struct ib_device *ibdev,
struct rdma_hw_stats *stats,
u32 port, int index)
{
struct tp_tcp_stats v4, v6;
struct c4iw_dev *c4iw_dev = to_c4iw_dev(ibdev);
cxgb4_get_tcp_stats(c4iw_dev->rdev.lldi.pdev, &v4, &v6);
stats->value[IP4INSEGS] = v4.tcp_in_segs;
stats->value[IP4OUTSEGS] = v4.tcp_out_segs;
stats->value[IP4RETRANSSEGS] = v4.tcp_retrans_segs;
stats->value[IP4OUTRSTS] = v4.tcp_out_rsts;
stats->value[IP6INSEGS] = v6.tcp_in_segs;
stats->value[IP6OUTSEGS] = v6.tcp_out_segs;
stats->value[IP6RETRANSSEGS] = v6.tcp_retrans_segs;
stats->value[IP6OUTRSTS] = v6.tcp_out_rsts;
return stats->num_counters;
}
static struct attribute *c4iw_class_attributes[] = {
&dev_attr_hw_rev.attr,
&dev_attr_hca_type.attr,
&dev_attr_board_id.attr,
NULL
};
static const struct attribute_group c4iw_attr_group = {
.attrs = c4iw_class_attributes,
};
static int c4iw_port_immutable(struct ib_device *ibdev, u32 port_num,
struct ib_port_immutable *immutable)
{
struct ib_port_attr attr;
int err;
immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
err = ib_query_port(ibdev, port_num, &attr);
if (err)
return err;
immutable->gid_tbl_len = attr.gid_tbl_len;
return 0;
}
static void get_dev_fw_str(struct ib_device *dev, char *str)
{
struct c4iw_dev *c4iw_dev = container_of(dev, struct c4iw_dev,
ibdev);
pr_debug("dev 0x%p\n", dev);
snprintf(str, IB_FW_VERSION_NAME_MAX, "%u.%u.%u.%u",
FW_HDR_FW_VER_MAJOR_G(c4iw_dev->rdev.lldi.fw_vers),
FW_HDR_FW_VER_MINOR_G(c4iw_dev->rdev.lldi.fw_vers),
FW_HDR_FW_VER_MICRO_G(c4iw_dev->rdev.lldi.fw_vers),
FW_HDR_FW_VER_BUILD_G(c4iw_dev->rdev.lldi.fw_vers));
}
static const struct ib_device_ops c4iw_dev_ops = {
.owner = THIS_MODULE,
.driver_id = RDMA_DRIVER_CXGB4,
.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION,
.alloc_hw_device_stats = c4iw_alloc_device_stats,
.alloc_mr = c4iw_alloc_mr,
.alloc_pd = c4iw_allocate_pd,
.alloc_ucontext = c4iw_alloc_ucontext,
.create_cq = c4iw_create_cq,
.create_qp = c4iw_create_qp,
.create_srq = c4iw_create_srq,
.dealloc_pd = c4iw_deallocate_pd,
.dealloc_ucontext = c4iw_dealloc_ucontext,
.dereg_mr = c4iw_dereg_mr,
.destroy_cq = c4iw_destroy_cq,
.destroy_qp = c4iw_destroy_qp,
.destroy_srq = c4iw_destroy_srq,
.device_group = &c4iw_attr_group,
.fill_res_cq_entry = c4iw_fill_res_cq_entry,
.fill_res_cm_id_entry = c4iw_fill_res_cm_id_entry,
.fill_res_mr_entry = c4iw_fill_res_mr_entry,
.fill_res_qp_entry = c4iw_fill_res_qp_entry,
.get_dev_fw_str = get_dev_fw_str,
.get_dma_mr = c4iw_get_dma_mr,
.get_hw_stats = c4iw_get_mib,
.get_port_immutable = c4iw_port_immutable,
.iw_accept = c4iw_accept_cr,
.iw_add_ref = c4iw_qp_add_ref,
.iw_connect = c4iw_connect,
.iw_create_listen = c4iw_create_listen,
.iw_destroy_listen = c4iw_destroy_listen,
.iw_get_qp = c4iw_get_qp,
.iw_reject = c4iw_reject_cr,
.iw_rem_ref = c4iw_qp_rem_ref,
.map_mr_sg = c4iw_map_mr_sg,
.mmap = c4iw_mmap,
.modify_qp = c4iw_ib_modify_qp,
.modify_srq = c4iw_modify_srq,
.poll_cq = c4iw_poll_cq,
.post_recv = c4iw_post_receive,
.post_send = c4iw_post_send,
.post_srq_recv = c4iw_post_srq_recv,
.query_device = c4iw_query_device,
.query_gid = c4iw_query_gid,
.query_port = c4iw_query_port,
.query_qp = c4iw_ib_query_qp,
.reg_user_mr = c4iw_reg_user_mr,
.req_notify_cq = c4iw_arm_cq,
INIT_RDMA_OBJ_SIZE(ib_cq, c4iw_cq, ibcq),
INIT_RDMA_OBJ_SIZE(ib_mw, c4iw_mw, ibmw),
INIT_RDMA_OBJ_SIZE(ib_pd, c4iw_pd, ibpd),
INIT_RDMA_OBJ_SIZE(ib_qp, c4iw_qp, ibqp),
INIT_RDMA_OBJ_SIZE(ib_srq, c4iw_srq, ibsrq),
INIT_RDMA_OBJ_SIZE(ib_ucontext, c4iw_ucontext, ibucontext),
};
static int set_netdevs(struct ib_device *ib_dev, struct c4iw_rdev *rdev)
{
int ret;
int i;
for (i = 0; i < rdev->lldi.nports; i++) {
ret = ib_device_set_netdev(ib_dev, rdev->lldi.ports[i],
i + 1);
if (ret)
return ret;
}
return 0;
}
void c4iw_register_device(struct work_struct *work)
{
int ret;
struct uld_ctx *ctx = container_of(work, struct uld_ctx, reg_work);
struct c4iw_dev *dev = ctx->dev;
pr_debug("c4iw_dev %p\n", dev);
addrconf_addr_eui48((u8 *)&dev->ibdev.node_guid,
dev->rdev.lldi.ports[0]->dev_addr);
dev->ibdev.local_dma_lkey = 0;
dev->ibdev.node_type = RDMA_NODE_RNIC;
BUILD_BUG_ON(sizeof(C4IW_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX);
memcpy(dev->ibdev.node_desc, C4IW_NODE_DESC, sizeof(C4IW_NODE_DESC));
dev->ibdev.phys_port_cnt = dev->rdev.lldi.nports;
dev->ibdev.num_comp_vectors = dev->rdev.lldi.nciq;
dev->ibdev.dev.parent = &dev->rdev.lldi.pdev->dev;
memcpy(dev->ibdev.iw_ifname, dev->rdev.lldi.ports[0]->name,
sizeof(dev->ibdev.iw_ifname));
ib_set_device_ops(&dev->ibdev, &c4iw_dev_ops);
ret = set_netdevs(&dev->ibdev, &dev->rdev);
if (ret)
goto err_dealloc_ctx;
dma_set_max_seg_size(&dev->rdev.lldi.pdev->dev, UINT_MAX);
ret = ib_register_device(&dev->ibdev, "cxgb4_%d",
&dev->rdev.lldi.pdev->dev);
if (ret)
goto err_dealloc_ctx;
return;
err_dealloc_ctx:
pr_err("%s - Failed registering iwarp device: %d\n",
pci_name(ctx->lldi.pdev), ret);
c4iw_dealloc(ctx);
return;
}
void c4iw_unregister_device(struct c4iw_dev *dev)
{
pr_debug("c4iw_dev %p\n", dev);
ib_unregister_device(&dev->ibdev);
return;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,516 @@
/*
* Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* Crude resource management */
#include <linux/spinlock.h>
#include <linux/genalloc.h>
#include <linux/ratelimit.h>
#include "iw_cxgb4.h"
static int c4iw_init_qid_table(struct c4iw_rdev *rdev)
{
u32 i;
if (c4iw_id_table_alloc(&rdev->resource.qid_table,
rdev->lldi.vr->qp.start,
rdev->lldi.vr->qp.size,
rdev->lldi.vr->qp.size, 0))
return -ENOMEM;
for (i = rdev->lldi.vr->qp.start;
i < rdev->lldi.vr->qp.start + rdev->lldi.vr->qp.size; i++)
if (!(i & rdev->qpmask))
c4iw_id_free(&rdev->resource.qid_table, i);
return 0;
}
/* nr_* must be power of 2 */
int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt,
u32 nr_pdid, u32 nr_srqt)
{
int err = 0;
err = c4iw_id_table_alloc(&rdev->resource.tpt_table, 0, nr_tpt, 1,
C4IW_ID_TABLE_F_RANDOM);
if (err)
goto tpt_err;
err = c4iw_init_qid_table(rdev);
if (err)
goto qid_err;
err = c4iw_id_table_alloc(&rdev->resource.pdid_table, 0,
nr_pdid, 1, 0);
if (err)
goto pdid_err;
if (!nr_srqt)
err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
1, 1, 0);
else
err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
nr_srqt, 0, 0);
if (err)
goto srq_err;
return 0;
srq_err:
c4iw_id_table_free(&rdev->resource.pdid_table);
pdid_err:
c4iw_id_table_free(&rdev->resource.qid_table);
qid_err:
c4iw_id_table_free(&rdev->resource.tpt_table);
tpt_err:
return -ENOMEM;
}
/*
* returns 0 if no resource available
*/
u32 c4iw_get_resource(struct c4iw_id_table *id_table)
{
u32 entry;
entry = c4iw_id_alloc(id_table);
if (entry == (u32)(-1))
return 0;
return entry;
}
void c4iw_put_resource(struct c4iw_id_table *id_table, u32 entry)
{
pr_debug("entry 0x%x\n", entry);
c4iw_id_free(id_table, entry);
}
u32 c4iw_get_cqid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
{
struct c4iw_qid_list *entry;
u32 qid;
int i;
mutex_lock(&uctx->lock);
if (!list_empty(&uctx->cqids)) {
entry = list_entry(uctx->cqids.next, struct c4iw_qid_list,
entry);
list_del(&entry->entry);
qid = entry->qid;
kfree(entry);
} else {
qid = c4iw_get_resource(&rdev->resource.qid_table);
if (!qid)
goto out;
mutex_lock(&rdev->stats.lock);
rdev->stats.qid.cur += rdev->qpmask + 1;
mutex_unlock(&rdev->stats.lock);
for (i = qid+1; i & rdev->qpmask; i++) {
entry = kmalloc_obj(*entry);
if (!entry)
goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->cqids);
}
/*
* now put the same ids on the qp list since they all
* map to the same db/gts page.
*/
entry = kmalloc_obj(*entry);
if (!entry)
goto out;
entry->qid = qid;
list_add_tail(&entry->entry, &uctx->qpids);
for (i = qid+1; i & rdev->qpmask; i++) {
entry = kmalloc_obj(*entry);
if (!entry)
goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->qpids);
}
}
out:
mutex_unlock(&uctx->lock);
pr_debug("qid 0x%x\n", qid);
mutex_lock(&rdev->stats.lock);
if (rdev->stats.qid.cur > rdev->stats.qid.max)
rdev->stats.qid.max = rdev->stats.qid.cur;
mutex_unlock(&rdev->stats.lock);
return qid;
}
void c4iw_put_cqid(struct c4iw_rdev *rdev, u32 qid,
struct c4iw_dev_ucontext *uctx)
{
struct c4iw_qid_list *entry;
entry = kmalloc_obj(*entry);
if (!entry)
return;
pr_debug("qid 0x%x\n", qid);
entry->qid = qid;
mutex_lock(&uctx->lock);
list_add_tail(&entry->entry, &uctx->cqids);
mutex_unlock(&uctx->lock);
}
u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx)
{
struct c4iw_qid_list *entry;
u32 qid;
int i;
mutex_lock(&uctx->lock);
if (!list_empty(&uctx->qpids)) {
entry = list_entry(uctx->qpids.next, struct c4iw_qid_list,
entry);
list_del(&entry->entry);
qid = entry->qid;
kfree(entry);
} else {
qid = c4iw_get_resource(&rdev->resource.qid_table);
if (!qid) {
mutex_lock(&rdev->stats.lock);
rdev->stats.qid.fail++;
mutex_unlock(&rdev->stats.lock);
goto out;
}
mutex_lock(&rdev->stats.lock);
rdev->stats.qid.cur += rdev->qpmask + 1;
mutex_unlock(&rdev->stats.lock);
for (i = qid+1; i & rdev->qpmask; i++) {
entry = kmalloc_obj(*entry);
if (!entry)
goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->qpids);
}
/*
* now put the same ids on the cq list since they all
* map to the same db/gts page.
*/
entry = kmalloc_obj(*entry);
if (!entry)
goto out;
entry->qid = qid;
list_add_tail(&entry->entry, &uctx->cqids);
for (i = qid + 1; i & rdev->qpmask; i++) {
entry = kmalloc_obj(*entry);
if (!entry)
goto out;
entry->qid = i;
list_add_tail(&entry->entry, &uctx->cqids);
}
}
out:
mutex_unlock(&uctx->lock);
pr_debug("qid 0x%x\n", qid);
mutex_lock(&rdev->stats.lock);
if (rdev->stats.qid.cur > rdev->stats.qid.max)
rdev->stats.qid.max = rdev->stats.qid.cur;
mutex_unlock(&rdev->stats.lock);
return qid;
}
void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qid,
struct c4iw_dev_ucontext *uctx)
{
struct c4iw_qid_list *entry;
entry = kmalloc_obj(*entry);
if (!entry)
return;
pr_debug("qid 0x%x\n", qid);
entry->qid = qid;
mutex_lock(&uctx->lock);
list_add_tail(&entry->entry, &uctx->qpids);
mutex_unlock(&uctx->lock);
}
void c4iw_destroy_resource(struct c4iw_resource *rscp)
{
c4iw_id_table_free(&rscp->tpt_table);
c4iw_id_table_free(&rscp->qid_table);
c4iw_id_table_free(&rscp->pdid_table);
}
/*
* PBL Memory Manager. Uses Linux generic allocator.
*/
#define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */
u32 c4iw_pblpool_alloc(struct c4iw_rdev *rdev, int size)
{
unsigned long addr = gen_pool_alloc(rdev->pbl_pool, size);
pr_debug("addr 0x%x size %d\n", (u32)addr, size);
mutex_lock(&rdev->stats.lock);
if (addr) {
rdev->stats.pbl.cur += roundup(size, 1 << MIN_PBL_SHIFT);
if (rdev->stats.pbl.cur > rdev->stats.pbl.max)
rdev->stats.pbl.max = rdev->stats.pbl.cur;
kref_get(&rdev->pbl_kref);
} else
rdev->stats.pbl.fail++;
mutex_unlock(&rdev->stats.lock);
return (u32)addr;
}
static void destroy_pblpool(struct kref *kref)
{
struct c4iw_rdev *rdev;
rdev = container_of(kref, struct c4iw_rdev, pbl_kref);
gen_pool_destroy(rdev->pbl_pool);
complete(&rdev->pbl_compl);
}
void c4iw_pblpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
{
pr_debug("addr 0x%x size %d\n", addr, size);
mutex_lock(&rdev->stats.lock);
rdev->stats.pbl.cur -= roundup(size, 1 << MIN_PBL_SHIFT);
mutex_unlock(&rdev->stats.lock);
gen_pool_free(rdev->pbl_pool, (unsigned long)addr, size);
kref_put(&rdev->pbl_kref, destroy_pblpool);
}
int c4iw_pblpool_create(struct c4iw_rdev *rdev)
{
unsigned pbl_start, pbl_chunk, pbl_top;
rdev->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
if (!rdev->pbl_pool)
return -ENOMEM;
pbl_start = rdev->lldi.vr->pbl.start;
pbl_chunk = rdev->lldi.vr->pbl.size;
pbl_top = pbl_start + pbl_chunk;
while (pbl_start < pbl_top) {
pbl_chunk = min(pbl_top - pbl_start + 1, pbl_chunk);
if (gen_pool_add(rdev->pbl_pool, pbl_start, pbl_chunk, -1)) {
pr_debug("failed to add PBL chunk (%x/%x)\n",
pbl_start, pbl_chunk);
if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
pr_warn("Failed to add all PBL chunks (%x/%x)\n",
pbl_start, pbl_top - pbl_start);
return 0;
}
pbl_chunk >>= 1;
} else {
pr_debug("added PBL chunk (%x/%x)\n",
pbl_start, pbl_chunk);
pbl_start += pbl_chunk;
}
}
return 0;
}
void c4iw_pblpool_destroy(struct c4iw_rdev *rdev)
{
kref_put(&rdev->pbl_kref, destroy_pblpool);
}
/*
* RQT Memory Manager. Uses Linux generic allocator.
*/
#define MIN_RQT_SHIFT 10 /* 1KB == min RQT size (16 entries) */
u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size)
{
unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6);
pr_debug("addr 0x%x size %d\n", (u32)addr, size << 6);
if (!addr)
pr_warn_ratelimited("%s: Out of RQT memory\n",
pci_name(rdev->lldi.pdev));
mutex_lock(&rdev->stats.lock);
if (addr) {
rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT);
if (rdev->stats.rqt.cur > rdev->stats.rqt.max)
rdev->stats.rqt.max = rdev->stats.rqt.cur;
kref_get(&rdev->rqt_kref);
} else
rdev->stats.rqt.fail++;
mutex_unlock(&rdev->stats.lock);
return (u32)addr;
}
static void destroy_rqtpool(struct kref *kref)
{
struct c4iw_rdev *rdev;
rdev = container_of(kref, struct c4iw_rdev, rqt_kref);
gen_pool_destroy(rdev->rqt_pool);
complete(&rdev->rqt_compl);
}
void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
{
pr_debug("addr 0x%x size %d\n", addr, size << 6);
mutex_lock(&rdev->stats.lock);
rdev->stats.rqt.cur -= roundup(size << 6, 1 << MIN_RQT_SHIFT);
mutex_unlock(&rdev->stats.lock);
gen_pool_free(rdev->rqt_pool, (unsigned long)addr, size << 6);
kref_put(&rdev->rqt_kref, destroy_rqtpool);
}
int c4iw_rqtpool_create(struct c4iw_rdev *rdev)
{
unsigned rqt_start, rqt_chunk, rqt_top;
int skip = 0;
rdev->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1);
if (!rdev->rqt_pool)
return -ENOMEM;
/*
* If SRQs are supported, then never use the first RQE from
* the RQT region. This is because HW uses RQT index 0 as NULL.
*/
if (rdev->lldi.vr->srq.size)
skip = T4_RQT_ENTRY_SIZE;
rqt_start = rdev->lldi.vr->rq.start + skip;
rqt_chunk = rdev->lldi.vr->rq.size - skip;
rqt_top = rqt_start + rqt_chunk;
while (rqt_start < rqt_top) {
rqt_chunk = min(rqt_top - rqt_start + 1, rqt_chunk);
if (gen_pool_add(rdev->rqt_pool, rqt_start, rqt_chunk, -1)) {
pr_debug("failed to add RQT chunk (%x/%x)\n",
rqt_start, rqt_chunk);
if (rqt_chunk <= 1024 << MIN_RQT_SHIFT) {
pr_warn("Failed to add all RQT chunks (%x/%x)\n",
rqt_start, rqt_top - rqt_start);
return 0;
}
rqt_chunk >>= 1;
} else {
pr_debug("added RQT chunk (%x/%x)\n",
rqt_start, rqt_chunk);
rqt_start += rqt_chunk;
}
}
return 0;
}
void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev)
{
kref_put(&rdev->rqt_kref, destroy_rqtpool);
}
int c4iw_alloc_srq_idx(struct c4iw_rdev *rdev)
{
int idx;
idx = c4iw_id_alloc(&rdev->resource.srq_table);
mutex_lock(&rdev->stats.lock);
if (idx == -1) {
rdev->stats.srqt.fail++;
mutex_unlock(&rdev->stats.lock);
return -ENOMEM;
}
rdev->stats.srqt.cur++;
if (rdev->stats.srqt.cur > rdev->stats.srqt.max)
rdev->stats.srqt.max = rdev->stats.srqt.cur;
mutex_unlock(&rdev->stats.lock);
return idx;
}
void c4iw_free_srq_idx(struct c4iw_rdev *rdev, int idx)
{
c4iw_id_free(&rdev->resource.srq_table, idx);
mutex_lock(&rdev->stats.lock);
rdev->stats.srqt.cur--;
mutex_unlock(&rdev->stats.lock);
}
/*
* On-Chip QP Memory.
*/
#define MIN_OCQP_SHIFT 12 /* 4KB == min ocqp size */
u32 c4iw_ocqp_pool_alloc(struct c4iw_rdev *rdev, int size)
{
unsigned long addr = gen_pool_alloc(rdev->ocqp_pool, size);
pr_debug("addr 0x%x size %d\n", (u32)addr, size);
if (addr) {
mutex_lock(&rdev->stats.lock);
rdev->stats.ocqp.cur += roundup(size, 1 << MIN_OCQP_SHIFT);
if (rdev->stats.ocqp.cur > rdev->stats.ocqp.max)
rdev->stats.ocqp.max = rdev->stats.ocqp.cur;
mutex_unlock(&rdev->stats.lock);
}
return (u32)addr;
}
void c4iw_ocqp_pool_free(struct c4iw_rdev *rdev, u32 addr, int size)
{
pr_debug("addr 0x%x size %d\n", addr, size);
mutex_lock(&rdev->stats.lock);
rdev->stats.ocqp.cur -= roundup(size, 1 << MIN_OCQP_SHIFT);
mutex_unlock(&rdev->stats.lock);
gen_pool_free(rdev->ocqp_pool, (unsigned long)addr, size);
}
int c4iw_ocqp_pool_create(struct c4iw_rdev *rdev)
{
unsigned start, chunk, top;
rdev->ocqp_pool = gen_pool_create(MIN_OCQP_SHIFT, -1);
if (!rdev->ocqp_pool)
return -ENOMEM;
start = rdev->lldi.vr->ocq.start;
chunk = rdev->lldi.vr->ocq.size;
top = start + chunk;
while (start < top) {
chunk = min(top - start + 1, chunk);
if (gen_pool_add(rdev->ocqp_pool, start, chunk, -1)) {
pr_debug("failed to add OCQP chunk (%x/%x)\n",
start, chunk);
if (chunk <= 1024 << MIN_OCQP_SHIFT) {
pr_warn("Failed to add all OCQP chunks (%x/%x)\n",
start, top - start);
return 0;
}
chunk >>= 1;
} else {
pr_debug("added OCQP chunk (%x/%x)\n",
start, chunk);
start += chunk;
}
}
return 0;
}
void c4iw_ocqp_pool_destroy(struct c4iw_rdev *rdev)
{
gen_pool_destroy(rdev->ocqp_pool);
}
@@ -0,0 +1,487 @@
/*
* Copyright (c) 2018 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <rdma/rdma_cm.h>
#include "iw_cxgb4.h"
#include <rdma/restrack.h>
#include <uapi/rdma/rdma_netlink.h>
static int fill_sq(struct sk_buff *msg, struct t4_wq *wq)
{
/* WQ+SQ */
if (rdma_nl_put_driver_u32(msg, "sqid", wq->sq.qid))
goto err;
if (rdma_nl_put_driver_u32(msg, "flushed", wq->flushed))
goto err;
if (rdma_nl_put_driver_u32(msg, "memsize", wq->sq.memsize))
goto err;
if (rdma_nl_put_driver_u32(msg, "cidx", wq->sq.cidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "pidx", wq->sq.pidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "wq_pidx", wq->sq.wq_pidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "flush_cidx", wq->sq.flush_cidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "in_use", wq->sq.in_use))
goto err;
if (rdma_nl_put_driver_u32(msg, "size", wq->sq.size))
goto err;
if (rdma_nl_put_driver_u32_hex(msg, "flags", wq->sq.flags))
goto err;
return 0;
err:
return -EMSGSIZE;
}
static int fill_rq(struct sk_buff *msg, struct t4_wq *wq)
{
/* RQ */
if (rdma_nl_put_driver_u32(msg, "rqid", wq->rq.qid))
goto err;
if (rdma_nl_put_driver_u32(msg, "memsize", wq->rq.memsize))
goto err;
if (rdma_nl_put_driver_u32(msg, "cidx", wq->rq.cidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "pidx", wq->rq.pidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "wq_pidx", wq->rq.wq_pidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "msn", wq->rq.msn))
goto err;
if (rdma_nl_put_driver_u32_hex(msg, "rqt_hwaddr", wq->rq.rqt_hwaddr))
goto err;
if (rdma_nl_put_driver_u32(msg, "rqt_size", wq->rq.rqt_size))
goto err;
if (rdma_nl_put_driver_u32(msg, "in_use", wq->rq.in_use))
goto err;
if (rdma_nl_put_driver_u32(msg, "size", wq->rq.size))
goto err;
return 0;
err:
return -EMSGSIZE;
}
static int fill_swsqe(struct sk_buff *msg, struct t4_sq *sq, u16 idx,
struct t4_swsqe *sqe)
{
if (rdma_nl_put_driver_u32(msg, "idx", idx))
goto err;
if (rdma_nl_put_driver_u32(msg, "opcode", sqe->opcode))
goto err;
if (rdma_nl_put_driver_u32(msg, "complete", sqe->complete))
goto err;
if (sqe->complete &&
rdma_nl_put_driver_u32(msg, "cqe_status", CQE_STATUS(&sqe->cqe)))
goto err;
if (rdma_nl_put_driver_u32(msg, "signaled", sqe->signaled))
goto err;
if (rdma_nl_put_driver_u32(msg, "flushed", sqe->flushed))
goto err;
return 0;
err:
return -EMSGSIZE;
}
/*
* Dump the first and last pending sqes.
*/
static int fill_swsqes(struct sk_buff *msg, struct t4_sq *sq,
u16 first_idx, struct t4_swsqe *first_sqe,
u16 last_idx, struct t4_swsqe *last_sqe)
{
if (!first_sqe)
goto out;
if (fill_swsqe(msg, sq, first_idx, first_sqe))
goto err;
if (!last_sqe)
goto out;
if (fill_swsqe(msg, sq, last_idx, last_sqe))
goto err;
out:
return 0;
err:
return -EMSGSIZE;
}
int c4iw_fill_res_qp_entry(struct sk_buff *msg, struct ib_qp *ibqp)
{
struct t4_swsqe *fsp = NULL, *lsp = NULL;
struct c4iw_qp *qhp = to_c4iw_qp(ibqp);
u16 first_sq_idx = 0, last_sq_idx = 0;
struct t4_swsqe first_sqe, last_sqe;
struct nlattr *table_attr;
struct t4_wq wq;
/* User qp state is not available, so don't dump user qps */
if (qhp->ucontext)
return 0;
table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);
if (!table_attr)
goto err;
/* Get a consistent snapshot */
spin_lock_irq(&qhp->lock);
wq = qhp->wq;
/* If there are any pending sqes, copy the first and last */
if (wq.sq.cidx != wq.sq.pidx) {
first_sq_idx = wq.sq.cidx;
first_sqe = qhp->wq.sq.sw_sq[first_sq_idx];
fsp = &first_sqe;
last_sq_idx = wq.sq.pidx;
if (last_sq_idx-- == 0)
last_sq_idx = wq.sq.size - 1;
if (last_sq_idx != first_sq_idx) {
last_sqe = qhp->wq.sq.sw_sq[last_sq_idx];
lsp = &last_sqe;
}
}
spin_unlock_irq(&qhp->lock);
if (fill_sq(msg, &wq))
goto err_cancel_table;
if (fill_swsqes(msg, &wq.sq, first_sq_idx, fsp, last_sq_idx, lsp))
goto err_cancel_table;
if (fill_rq(msg, &wq))
goto err_cancel_table;
nla_nest_end(msg, table_attr);
return 0;
err_cancel_table:
nla_nest_cancel(msg, table_attr);
err:
return -EMSGSIZE;
}
union union_ep {
struct c4iw_listen_ep lep;
struct c4iw_ep ep;
};
int c4iw_fill_res_cm_id_entry(struct sk_buff *msg,
struct rdma_cm_id *cm_id)
{
struct nlattr *table_attr;
struct c4iw_ep_common *epcp;
struct c4iw_listen_ep *listen_ep = NULL;
struct c4iw_ep *ep = NULL;
struct iw_cm_id *iw_cm_id;
union union_ep *uep;
iw_cm_id = rdma_iw_cm_id(cm_id);
if (!iw_cm_id)
return 0;
epcp = (struct c4iw_ep_common *)iw_cm_id->provider_data;
if (!epcp)
return 0;
uep = kzalloc_obj(*uep);
if (!uep)
return 0;
table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);
if (!table_attr)
goto err_free_uep;
/* Get a consistent snapshot */
mutex_lock(&epcp->mutex);
if (epcp->state == LISTEN) {
uep->lep = *(struct c4iw_listen_ep *)epcp;
mutex_unlock(&epcp->mutex);
listen_ep = &uep->lep;
epcp = &listen_ep->com;
} else {
uep->ep = *(struct c4iw_ep *)epcp;
mutex_unlock(&epcp->mutex);
ep = &uep->ep;
epcp = &ep->com;
}
if (rdma_nl_put_driver_u32(msg, "state", epcp->state))
goto err_cancel_table;
if (rdma_nl_put_driver_u64_hex(msg, "flags", epcp->flags))
goto err_cancel_table;
if (rdma_nl_put_driver_u64_hex(msg, "history", epcp->history))
goto err_cancel_table;
if (listen_ep) {
if (rdma_nl_put_driver_u32(msg, "stid", listen_ep->stid))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "backlog", listen_ep->backlog))
goto err_cancel_table;
} else {
if (rdma_nl_put_driver_u32(msg, "hwtid", ep->hwtid))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "ord", ep->ord))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "ird", ep->ird))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "emss", ep->emss))
goto err_cancel_table;
if (!ep->parent_ep && rdma_nl_put_driver_u32(msg, "atid",
ep->atid))
goto err_cancel_table;
}
nla_nest_end(msg, table_attr);
kfree(uep);
return 0;
err_cancel_table:
nla_nest_cancel(msg, table_attr);
err_free_uep:
kfree(uep);
return -EMSGSIZE;
}
static int fill_cq(struct sk_buff *msg, struct t4_cq *cq)
{
if (rdma_nl_put_driver_u32(msg, "cqid", cq->cqid))
goto err;
if (rdma_nl_put_driver_u32(msg, "memsize", cq->memsize))
goto err;
if (rdma_nl_put_driver_u32(msg, "size", cq->size))
goto err;
if (rdma_nl_put_driver_u32(msg, "cidx", cq->cidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "cidx_inc", cq->cidx_inc))
goto err;
if (rdma_nl_put_driver_u32(msg, "sw_cidx", cq->sw_cidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "sw_pidx", cq->sw_pidx))
goto err;
if (rdma_nl_put_driver_u32(msg, "sw_in_use", cq->sw_in_use))
goto err;
if (rdma_nl_put_driver_u32(msg, "vector", cq->vector))
goto err;
if (rdma_nl_put_driver_u32(msg, "gen", cq->gen))
goto err;
if (rdma_nl_put_driver_u32(msg, "error", cq->error))
goto err;
if (rdma_nl_put_driver_u64_hex(msg, "bits_type_ts",
be64_to_cpu(cq->bits_type_ts)))
goto err;
if (rdma_nl_put_driver_u64_hex(msg, "flags", cq->flags))
goto err;
return 0;
err:
return -EMSGSIZE;
}
static int fill_cqe(struct sk_buff *msg, struct t4_cqe *cqe, u16 idx,
const char *qstr)
{
if (rdma_nl_put_driver_u32(msg, qstr, idx))
goto err;
if (rdma_nl_put_driver_u32_hex(msg, "header",
be32_to_cpu(cqe->header)))
goto err;
if (rdma_nl_put_driver_u32(msg, "len", be32_to_cpu(cqe->len)))
goto err;
if (rdma_nl_put_driver_u32_hex(msg, "wrid_hi",
be32_to_cpu(cqe->u.gen.wrid_hi)))
goto err;
if (rdma_nl_put_driver_u32_hex(msg, "wrid_low",
be32_to_cpu(cqe->u.gen.wrid_low)))
goto err;
if (rdma_nl_put_driver_u64_hex(msg, "bits_type_ts",
be64_to_cpu(cqe->bits_type_ts)))
goto err;
return 0;
err:
return -EMSGSIZE;
}
static int fill_hwcqes(struct sk_buff *msg, struct t4_cq *cq,
struct t4_cqe *cqes)
{
u16 idx;
idx = (cq->cidx > 0) ? cq->cidx - 1 : cq->size - 1;
if (fill_cqe(msg, cqes, idx, "hwcq_idx"))
goto err;
idx = cq->cidx;
if (fill_cqe(msg, cqes + 1, idx, "hwcq_idx"))
goto err;
return 0;
err:
return -EMSGSIZE;
}
static int fill_swcqes(struct sk_buff *msg, struct t4_cq *cq,
struct t4_cqe *cqes)
{
u16 idx;
if (!cq->sw_in_use)
return 0;
idx = cq->sw_cidx;
if (fill_cqe(msg, cqes, idx, "swcq_idx"))
goto err;
if (cq->sw_in_use == 1)
goto out;
idx = (cq->sw_pidx > 0) ? cq->sw_pidx - 1 : cq->size - 1;
if (fill_cqe(msg, cqes + 1, idx, "swcq_idx"))
goto err;
out:
return 0;
err:
return -EMSGSIZE;
}
int c4iw_fill_res_cq_entry(struct sk_buff *msg, struct ib_cq *ibcq)
{
struct c4iw_cq *chp = to_c4iw_cq(ibcq);
struct nlattr *table_attr;
struct t4_cqe hwcqes[2];
struct t4_cqe swcqes[2];
struct t4_cq cq;
u16 idx;
/* User cq state is not available, so don't dump user cqs */
if (ibcq->uobject)
return 0;
table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);
if (!table_attr)
goto err;
/* Get a consistent snapshot */
spin_lock_irq(&chp->lock);
/* t4_cq struct */
cq = chp->cq;
/* get 2 hw cqes: cidx-1, and cidx */
idx = (cq.cidx > 0) ? cq.cidx - 1 : cq.size - 1;
hwcqes[0] = chp->cq.queue[idx];
idx = cq.cidx;
hwcqes[1] = chp->cq.queue[idx];
/* get first and last sw cqes */
if (cq.sw_in_use) {
swcqes[0] = chp->cq.sw_queue[cq.sw_cidx];
if (cq.sw_in_use > 1) {
idx = (cq.sw_pidx > 0) ? cq.sw_pidx - 1 : cq.size - 1;
swcqes[1] = chp->cq.sw_queue[idx];
}
}
spin_unlock_irq(&chp->lock);
if (fill_cq(msg, &cq))
goto err_cancel_table;
if (fill_swcqes(msg, &cq, swcqes))
goto err_cancel_table;
if (fill_hwcqes(msg, &cq, hwcqes))
goto err_cancel_table;
nla_nest_end(msg, table_attr);
return 0;
err_cancel_table:
nla_nest_cancel(msg, table_attr);
err:
return -EMSGSIZE;
}
int c4iw_fill_res_mr_entry(struct sk_buff *msg, struct ib_mr *ibmr)
{
struct c4iw_mr *mhp = to_c4iw_mr(ibmr);
struct c4iw_dev *dev = mhp->rhp;
u32 stag = mhp->attr.stag;
struct nlattr *table_attr;
struct fw_ri_tpte tpte;
int ret;
if (!stag)
return 0;
table_attr = nla_nest_start_noflag(msg, RDMA_NLDEV_ATTR_DRIVER);
if (!table_attr)
goto err;
ret = cxgb4_read_tpte(dev->rdev.lldi.ports[0], stag, (__be32 *)&tpte);
if (ret) {
dev_err(&dev->rdev.lldi.pdev->dev,
"%s cxgb4_read_tpte err %d\n", __func__, ret);
return 0;
}
if (rdma_nl_put_driver_u32_hex(msg, "idx", stag >> 8))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "valid",
FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid))))
goto err_cancel_table;
if (rdma_nl_put_driver_u32_hex(msg, "key", stag & 0xff))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "state",
FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid))))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "pdid",
FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid))))
goto err_cancel_table;
if (rdma_nl_put_driver_u32_hex(msg, "perm",
FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid))))
goto err_cancel_table;
if (rdma_nl_put_driver_u32(msg, "ps",
FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid))))
goto err_cancel_table;
if (rdma_nl_put_driver_u64(msg, "len",
((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo)))
goto err_cancel_table;
if (rdma_nl_put_driver_u32_hex(msg, "pbl_addr",
FW_RI_TPTE_PBLADDR_G(ntohl(tpte.nosnoop_pbladdr))))
goto err_cancel_table;
nla_nest_end(msg, table_attr);
return 0;
err_cancel_table:
nla_nest_cancel(msg, table_attr);
err:
return -EMSGSIZE;
}
@@ -0,0 +1,833 @@
/*
* Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __T4_H__
#define __T4_H__
#include "t4_hw.h"
#include "t4_regs.h"
#include "t4_values.h"
#include "t4_msg.h"
#include "t4_tcb.h"
#include "t4fw_ri_api.h"
#define T4_MAX_NUM_PD 65536
#define T4_MAX_MR_SIZE (~0ULL)
#define T4_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */
#define T4_STAG_UNSET 0xffffffff
#define T4_FW_MAJ 0
#define PCIE_MA_SYNC_A 0x30b4
struct t4_status_page {
__be32 rsvd1; /* flit 0 - hw owns */
__be16 rsvd2;
__be16 qid;
__be16 cidx;
__be16 pidx;
u8 qp_err; /* flit 1 - sw owns */
u8 db_off;
u8 pad[2];
u16 host_wq_pidx;
u16 host_cidx;
u16 host_pidx;
u16 pad2;
u32 srqidx;
};
#define T4_RQT_ENTRY_SHIFT 6
#define T4_RQT_ENTRY_SIZE BIT(T4_RQT_ENTRY_SHIFT)
#define T4_EQ_ENTRY_SIZE 64
#define T4_SQ_NUM_SLOTS 5
#define T4_SQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_SQ_NUM_SLOTS)
#define T4_MAX_SEND_SGE ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_send_wr) - \
sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
#define T4_MAX_SEND_INLINE ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_send_wr) - \
sizeof(struct fw_ri_immd)))
#define T4_MAX_WRITE_INLINE ((T4_SQ_NUM_BYTES - \
sizeof(struct fw_ri_rdma_write_wr) - \
sizeof(struct fw_ri_immd)))
#define T4_MAX_WRITE_SGE ((T4_SQ_NUM_BYTES - \
sizeof(struct fw_ri_rdma_write_wr) - \
sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge))
#define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \
sizeof(struct fw_ri_immd)) & ~31UL)
#define T4_MAX_FR_IMMD_DEPTH (T4_MAX_FR_IMMD / sizeof(u64))
#define T4_MAX_FR_DSGL 1024
#define T4_MAX_FR_DSGL_DEPTH (T4_MAX_FR_DSGL / sizeof(u64))
static inline int t4_max_fr_depth(int use_dsgl)
{
return use_dsgl ? T4_MAX_FR_DSGL_DEPTH : T4_MAX_FR_IMMD_DEPTH;
}
#define T4_RQ_NUM_SLOTS 2
#define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS)
#define T4_MAX_RECV_SGE 4
#define T4_WRITE_CMPL_MAX_SGL 4
#define T4_WRITE_CMPL_MAX_CQE 16
union t4_wr {
struct fw_ri_res_wr res;
struct fw_ri_wr ri;
struct fw_ri_rdma_write_wr write;
struct fw_ri_send_wr send;
struct fw_ri_rdma_read_wr read;
struct fw_ri_bind_mw_wr bind;
struct fw_ri_fr_nsmr_wr fr;
struct fw_ri_fr_nsmr_tpte_wr fr_tpte;
struct fw_ri_inv_lstag_wr inv;
struct fw_ri_rdma_write_cmpl_wr write_cmpl;
struct t4_status_page status;
__be64 flits[T4_EQ_ENTRY_SIZE / sizeof(__be64) * T4_SQ_NUM_SLOTS];
};
union t4_recv_wr {
struct fw_ri_recv_wr recv;
struct t4_status_page status;
__be64 flits[T4_EQ_ENTRY_SIZE / sizeof(__be64) * T4_RQ_NUM_SLOTS];
};
static inline void init_wr_hdr(union t4_wr *wqe, u16 wrid,
enum fw_wr_opcodes opcode, u8 flags, u8 len16)
{
wqe->send.opcode = (u8)opcode;
wqe->send.flags = flags;
wqe->send.wrid = wrid;
wqe->send.r1[0] = 0;
wqe->send.r1[1] = 0;
wqe->send.r1[2] = 0;
wqe->send.len16 = len16;
}
/* CQE/AE status codes */
#define T4_ERR_SUCCESS 0x0
#define T4_ERR_STAG 0x1 /* STAG invalid: either the */
/* STAG is offlimt, being 0, */
/* or STAG_key mismatch */
#define T4_ERR_PDID 0x2 /* PDID mismatch */
#define T4_ERR_QPID 0x3 /* QPID mismatch */
#define T4_ERR_ACCESS 0x4 /* Invalid access right */
#define T4_ERR_WRAP 0x5 /* Wrap error */
#define T4_ERR_BOUND 0x6 /* base and bounds voilation */
#define T4_ERR_INVALIDATE_SHARED_MR 0x7 /* attempt to invalidate a */
/* shared memory region */
#define T4_ERR_INVALIDATE_MR_WITH_MW_BOUND 0x8 /* attempt to invalidate a */
/* shared memory region */
#define T4_ERR_ECC 0x9 /* ECC error detected */
#define T4_ERR_ECC_PSTAG 0xA /* ECC error detected when */
/* reading PSTAG for a MW */
/* Invalidate */
#define T4_ERR_PBL_ADDR_BOUND 0xB /* pbl addr out of bounds: */
/* software error */
#define T4_ERR_SWFLUSH 0xC /* SW FLUSHED */
#define T4_ERR_CRC 0x10 /* CRC error */
#define T4_ERR_MARKER 0x11 /* Marker error */
#define T4_ERR_PDU_LEN_ERR 0x12 /* invalid PDU length */
#define T4_ERR_OUT_OF_RQE 0x13 /* out of RQE */
#define T4_ERR_DDP_VERSION 0x14 /* wrong DDP version */
#define T4_ERR_RDMA_VERSION 0x15 /* wrong RDMA version */
#define T4_ERR_OPCODE 0x16 /* invalid rdma opcode */
#define T4_ERR_DDP_QUEUE_NUM 0x17 /* invalid ddp queue number */
#define T4_ERR_MSN 0x18 /* MSN error */
#define T4_ERR_TBIT 0x19 /* tag bit not set correctly */
#define T4_ERR_MO 0x1A /* MO not 0 for TERMINATE */
/* or READ_REQ */
#define T4_ERR_MSN_GAP 0x1B
#define T4_ERR_MSN_RANGE 0x1C
#define T4_ERR_IRD_OVERFLOW 0x1D
#define T4_ERR_RQE_ADDR_BOUND 0x1E /* RQE addr out of bounds: */
/* software error */
#define T4_ERR_INTERNAL_ERR 0x1F /* internal error (opcode */
/* mismatch) */
/*
* CQE defs
*/
struct t4_cqe {
__be32 header;
__be32 len;
union {
struct {
__be32 stag;
__be32 msn;
} rcqe;
struct {
__be32 stag;
u16 nada2;
u16 cidx;
} scqe;
struct {
__be32 wrid_hi;
__be32 wrid_low;
} gen;
struct {
__be32 stag;
__be32 msn;
__be32 reserved;
__be32 abs_rqe_idx;
} srcqe;
struct {
__be32 mo;
__be32 msn;
/*
* Use union for immediate data to be consistent with
* stack's 32 bit data and iWARP spec's 64 bit data.
*/
union {
struct {
__be32 imm_data32;
u32 reserved;
} ib_imm_data;
__be64 imm_data64;
} iw_imm_data;
} imm_data_rcqe;
u64 drain_cookie;
__be64 flits[3];
} u;
__be64 reserved[3];
__be64 bits_type_ts;
};
/* macros for flit 0 of the cqe */
#define CQE_QPID_S 12
#define CQE_QPID_M 0xFFFFF
#define CQE_QPID_G(x) ((((x) >> CQE_QPID_S)) & CQE_QPID_M)
#define CQE_QPID_V(x) ((x)<<CQE_QPID_S)
#define CQE_SWCQE_S 11
#define CQE_SWCQE_M 0x1
#define CQE_SWCQE_G(x) ((((x) >> CQE_SWCQE_S)) & CQE_SWCQE_M)
#define CQE_SWCQE_V(x) ((x)<<CQE_SWCQE_S)
#define CQE_DRAIN_S 10
#define CQE_DRAIN_M 0x1
#define CQE_DRAIN_G(x) ((((x) >> CQE_DRAIN_S)) & CQE_DRAIN_M)
#define CQE_DRAIN_V(x) ((x)<<CQE_DRAIN_S)
#define CQE_STATUS_S 5
#define CQE_STATUS_M 0x1F
#define CQE_STATUS_G(x) ((((x) >> CQE_STATUS_S)) & CQE_STATUS_M)
#define CQE_STATUS_V(x) ((x)<<CQE_STATUS_S)
#define CQE_TYPE_S 4
#define CQE_TYPE_M 0x1
#define CQE_TYPE_G(x) ((((x) >> CQE_TYPE_S)) & CQE_TYPE_M)
#define CQE_TYPE_V(x) ((x)<<CQE_TYPE_S)
#define CQE_OPCODE_S 0
#define CQE_OPCODE_M 0xF
#define CQE_OPCODE_G(x) ((((x) >> CQE_OPCODE_S)) & CQE_OPCODE_M)
#define CQE_OPCODE_V(x) ((x)<<CQE_OPCODE_S)
#define SW_CQE(x) (CQE_SWCQE_G(be32_to_cpu((x)->header)))
#define DRAIN_CQE(x) (CQE_DRAIN_G(be32_to_cpu((x)->header)))
#define CQE_QPID(x) (CQE_QPID_G(be32_to_cpu((x)->header)))
#define CQE_TYPE(x) (CQE_TYPE_G(be32_to_cpu((x)->header)))
#define SQ_TYPE(x) (CQE_TYPE((x)))
#define RQ_TYPE(x) (!CQE_TYPE((x)))
#define CQE_STATUS(x) (CQE_STATUS_G(be32_to_cpu((x)->header)))
#define CQE_OPCODE(x) (CQE_OPCODE_G(be32_to_cpu((x)->header)))
#define CQE_SEND_OPCODE(x)( \
(CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND) || \
(CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE) || \
(CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_INV) || \
(CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE_INV))
#define CQE_LEN(x) (be32_to_cpu((x)->len))
/* used for RQ completion processing */
#define CQE_WRID_STAG(x) (be32_to_cpu((x)->u.rcqe.stag))
#define CQE_WRID_MSN(x) (be32_to_cpu((x)->u.rcqe.msn))
#define CQE_ABS_RQE_IDX(x) (be32_to_cpu((x)->u.srcqe.abs_rqe_idx))
#define CQE_IMM_DATA(x)( \
(x)->u.imm_data_rcqe.iw_imm_data.ib_imm_data.imm_data32)
/* used for SQ completion processing */
#define CQE_WRID_SQ_IDX(x) ((x)->u.scqe.cidx)
#define CQE_WRID_FR_STAG(x) (be32_to_cpu((x)->u.scqe.stag))
/* generic accessor macros */
#define CQE_WRID_HI(x) (be32_to_cpu((x)->u.gen.wrid_hi))
#define CQE_WRID_LOW(x) (be32_to_cpu((x)->u.gen.wrid_low))
#define CQE_DRAIN_COOKIE(x) ((x)->u.drain_cookie)
/* macros for flit 3 of the cqe */
#define CQE_GENBIT_S 63
#define CQE_GENBIT_M 0x1
#define CQE_GENBIT_G(x) (((x) >> CQE_GENBIT_S) & CQE_GENBIT_M)
#define CQE_GENBIT_V(x) ((x)<<CQE_GENBIT_S)
#define CQE_OVFBIT_S 62
#define CQE_OVFBIT_M 0x1
#define CQE_OVFBIT_G(x) ((((x) >> CQE_OVFBIT_S)) & CQE_OVFBIT_M)
#define CQE_IQTYPE_S 60
#define CQE_IQTYPE_M 0x3
#define CQE_IQTYPE_G(x) ((((x) >> CQE_IQTYPE_S)) & CQE_IQTYPE_M)
#define CQE_TS_M 0x0fffffffffffffffULL
#define CQE_TS_G(x) ((x) & CQE_TS_M)
#define CQE_OVFBIT(x) ((unsigned)CQE_OVFBIT_G(be64_to_cpu((x)->bits_type_ts)))
#define CQE_GENBIT(x) ((unsigned)CQE_GENBIT_G(be64_to_cpu((x)->bits_type_ts)))
#define CQE_TS(x) (CQE_TS_G(be64_to_cpu((x)->bits_type_ts)))
struct t4_swsqe {
u64 wr_id;
struct t4_cqe cqe;
int read_len;
int opcode;
int complete;
int signaled;
u16 idx;
int flushed;
ktime_t host_time;
u64 sge_ts;
};
static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
{
#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
return pgprot_writecombine(prot);
#else
return pgprot_noncached(prot);
#endif
}
enum {
T4_SQ_ONCHIP = (1<<0),
};
struct t4_sq {
union t4_wr *queue;
dma_addr_t dma_addr;
DEFINE_DMA_UNMAP_ADDR(mapping);
unsigned long phys_addr;
struct t4_swsqe *sw_sq;
struct t4_swsqe *oldest_read;
void __iomem *bar2_va;
u64 bar2_pa;
size_t memsize;
u32 bar2_qid;
u32 qid;
u16 in_use;
u16 size;
u16 cidx;
u16 pidx;
u16 wq_pidx;
u16 wq_pidx_inc;
u16 flags;
short flush_cidx;
};
struct t4_swrqe {
u64 wr_id;
ktime_t host_time;
u64 sge_ts;
int valid;
};
struct t4_rq {
union t4_recv_wr *queue;
dma_addr_t dma_addr;
DEFINE_DMA_UNMAP_ADDR(mapping);
struct t4_swrqe *sw_rq;
void __iomem *bar2_va;
u64 bar2_pa;
size_t memsize;
u32 bar2_qid;
u32 qid;
u32 msn;
u32 rqt_hwaddr;
u16 rqt_size;
u16 in_use;
u16 size;
u16 cidx;
u16 pidx;
u16 wq_pidx;
u16 wq_pidx_inc;
};
struct t4_wq {
struct t4_sq sq;
struct t4_rq rq;
void __iomem *db;
struct c4iw_rdev *rdev;
int flushed;
u8 *qp_errp;
u32 *srqidxp;
};
struct t4_srq_pending_wr {
u64 wr_id;
union t4_recv_wr wqe;
u8 len16;
};
struct t4_srq {
union t4_recv_wr *queue;
dma_addr_t dma_addr;
DEFINE_DMA_UNMAP_ADDR(mapping);
struct t4_swrqe *sw_rq;
void __iomem *bar2_va;
u64 bar2_pa;
size_t memsize;
u32 bar2_qid;
u32 qid;
u32 msn;
u32 rqt_hwaddr;
u32 rqt_abs_idx;
u16 rqt_size;
u16 size;
u16 cidx;
u16 pidx;
u16 wq_pidx;
u16 wq_pidx_inc;
u16 in_use;
struct t4_srq_pending_wr *pending_wrs;
u16 pending_cidx;
u16 pending_pidx;
u16 pending_in_use;
u16 ooo_count;
};
static inline u32 t4_srq_avail(struct t4_srq *srq)
{
return srq->size - 1 - srq->in_use;
}
static inline void t4_srq_produce(struct t4_srq *srq, u8 len16)
{
srq->in_use++;
if (++srq->pidx == srq->size)
srq->pidx = 0;
srq->wq_pidx += DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE);
if (srq->wq_pidx >= srq->size * T4_RQ_NUM_SLOTS)
srq->wq_pidx %= srq->size * T4_RQ_NUM_SLOTS;
srq->queue[srq->size].status.host_pidx = srq->pidx;
}
static inline void t4_srq_produce_pending_wr(struct t4_srq *srq)
{
srq->pending_in_use++;
srq->in_use++;
if (++srq->pending_pidx == srq->size)
srq->pending_pidx = 0;
}
static inline void t4_srq_consume_pending_wr(struct t4_srq *srq)
{
srq->pending_in_use--;
srq->in_use--;
if (++srq->pending_cidx == srq->size)
srq->pending_cidx = 0;
}
static inline void t4_srq_produce_ooo(struct t4_srq *srq)
{
srq->in_use--;
srq->ooo_count++;
}
static inline void t4_srq_consume_ooo(struct t4_srq *srq)
{
srq->cidx++;
if (srq->cidx == srq->size)
srq->cidx = 0;
srq->queue[srq->size].status.host_cidx = srq->cidx;
srq->ooo_count--;
}
static inline void t4_srq_consume(struct t4_srq *srq)
{
srq->in_use--;
if (++srq->cidx == srq->size)
srq->cidx = 0;
srq->queue[srq->size].status.host_cidx = srq->cidx;
}
static inline int t4_rqes_posted(struct t4_wq *wq)
{
return wq->rq.in_use;
}
static inline int t4_rq_empty(struct t4_wq *wq)
{
return wq->rq.in_use == 0;
}
static inline u32 t4_rq_avail(struct t4_wq *wq)
{
return wq->rq.size - 1 - wq->rq.in_use;
}
static inline void t4_rq_produce(struct t4_wq *wq, u8 len16)
{
wq->rq.in_use++;
if (++wq->rq.pidx == wq->rq.size)
wq->rq.pidx = 0;
wq->rq.wq_pidx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
if (wq->rq.wq_pidx >= wq->rq.size * T4_RQ_NUM_SLOTS)
wq->rq.wq_pidx %= wq->rq.size * T4_RQ_NUM_SLOTS;
}
static inline void t4_rq_consume(struct t4_wq *wq)
{
wq->rq.in_use--;
if (++wq->rq.cidx == wq->rq.size)
wq->rq.cidx = 0;
}
static inline u16 t4_rq_host_wq_pidx(struct t4_wq *wq)
{
return wq->rq.queue[wq->rq.size].status.host_wq_pidx;
}
static inline u16 t4_rq_wq_size(struct t4_wq *wq)
{
return wq->rq.size * T4_RQ_NUM_SLOTS;
}
static inline int t4_sq_onchip(struct t4_sq *sq)
{
return sq->flags & T4_SQ_ONCHIP;
}
static inline int t4_sq_empty(struct t4_wq *wq)
{
return wq->sq.in_use == 0;
}
static inline u32 t4_sq_avail(struct t4_wq *wq)
{
return wq->sq.size - 1 - wq->sq.in_use;
}
static inline void t4_sq_produce(struct t4_wq *wq, u8 len16)
{
wq->sq.in_use++;
if (++wq->sq.pidx == wq->sq.size)
wq->sq.pidx = 0;
wq->sq.wq_pidx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
if (wq->sq.wq_pidx >= wq->sq.size * T4_SQ_NUM_SLOTS)
wq->sq.wq_pidx %= wq->sq.size * T4_SQ_NUM_SLOTS;
}
static inline void t4_sq_consume(struct t4_wq *wq)
{
if (wq->sq.cidx == wq->sq.flush_cidx)
wq->sq.flush_cidx = -1;
wq->sq.in_use--;
if (++wq->sq.cidx == wq->sq.size)
wq->sq.cidx = 0;
}
static inline u16 t4_sq_host_wq_pidx(struct t4_wq *wq)
{
return wq->sq.queue[wq->sq.size].status.host_wq_pidx;
}
static inline u16 t4_sq_wq_size(struct t4_wq *wq)
{
return wq->sq.size * T4_SQ_NUM_SLOTS;
}
/* This function copies 64 byte coalesced work request to memory
* mapped BAR2 space. For coalesced WRs, the SGE fetches data
* from the FIFO instead of from Host.
*/
static inline void pio_copy(u64 __iomem *dst, u64 *src)
{
int count = 8;
while (count) {
writeq(*src, dst);
src++;
dst++;
count--;
}
}
static inline void t4_ring_srq_db(struct t4_srq *srq, u16 inc, u8 len16,
union t4_recv_wr *wqe)
{
/* Flush host queue memory writes. */
wmb();
if (inc == 1 && srq->bar2_qid == 0 && wqe) {
pr_debug("%s : WC srq->pidx = %d; len16=%d\n",
__func__, srq->pidx, len16);
pio_copy(srq->bar2_va + SGE_UDB_WCDOORBELL, (u64 *)wqe);
} else {
pr_debug("%s: DB srq->pidx = %d; len16=%d\n",
__func__, srq->pidx, len16);
writel(PIDX_T5_V(inc) | QID_V(srq->bar2_qid),
srq->bar2_va + SGE_UDB_KDOORBELL);
}
/* Flush user doorbell area writes. */
wmb();
}
static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, union t4_wr *wqe)
{
/* Flush host queue memory writes. */
wmb();
if (wq->sq.bar2_va) {
if (inc == 1 && wq->sq.bar2_qid == 0 && wqe) {
pr_debug("WC wq->sq.pidx = %d\n", wq->sq.pidx);
pio_copy((u64 __iomem *)
(wq->sq.bar2_va + SGE_UDB_WCDOORBELL),
(u64 *)wqe);
} else {
pr_debug("DB wq->sq.pidx = %d\n", wq->sq.pidx);
writel(PIDX_T5_V(inc) | QID_V(wq->sq.bar2_qid),
wq->sq.bar2_va + SGE_UDB_KDOORBELL);
}
/* Flush user doorbell area writes. */
wmb();
return;
}
writel(QID_V(wq->sq.qid) | PIDX_V(inc), wq->db);
}
static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc,
union t4_recv_wr *wqe)
{
/* Flush host queue memory writes. */
wmb();
if (wq->rq.bar2_va) {
if (inc == 1 && wq->rq.bar2_qid == 0 && wqe) {
pr_debug("WC wq->rq.pidx = %d\n", wq->rq.pidx);
pio_copy((u64 __iomem *)
(wq->rq.bar2_va + SGE_UDB_WCDOORBELL),
(void *)wqe);
} else {
pr_debug("DB wq->rq.pidx = %d\n", wq->rq.pidx);
writel(PIDX_T5_V(inc) | QID_V(wq->rq.bar2_qid),
wq->rq.bar2_va + SGE_UDB_KDOORBELL);
}
/* Flush user doorbell area writes. */
wmb();
return;
}
writel(QID_V(wq->rq.qid) | PIDX_V(inc), wq->db);
}
static inline int t4_wq_in_error(struct t4_wq *wq)
{
return *wq->qp_errp;
}
static inline void t4_set_wq_in_error(struct t4_wq *wq, u32 srqidx)
{
if (srqidx)
*wq->srqidxp = srqidx;
*wq->qp_errp = 1;
}
static inline void t4_disable_wq_db(struct t4_wq *wq)
{
wq->rq.queue[wq->rq.size].status.db_off = 1;
}
static inline void t4_enable_wq_db(struct t4_wq *wq)
{
wq->rq.queue[wq->rq.size].status.db_off = 0;
}
enum t4_cq_flags {
CQ_ARMED = 1,
};
struct t4_cq {
struct t4_cqe *queue;
dma_addr_t dma_addr;
DEFINE_DMA_UNMAP_ADDR(mapping);
struct t4_cqe *sw_queue;
void __iomem *gts;
void __iomem *bar2_va;
u64 bar2_pa;
u32 bar2_qid;
struct c4iw_rdev *rdev;
size_t memsize;
__be64 bits_type_ts;
u32 cqid;
u32 qid_mask;
int vector;
u16 size; /* including status page */
u16 cidx;
u16 sw_pidx;
u16 sw_cidx;
u16 sw_in_use;
u16 cidx_inc;
u8 gen;
u8 error;
u8 *qp_errp;
unsigned long flags;
};
static inline void write_gts(struct t4_cq *cq, u32 val)
{
if (cq->bar2_va)
writel(val | INGRESSQID_V(cq->bar2_qid),
cq->bar2_va + SGE_UDB_GTS);
else
writel(val | INGRESSQID_V(cq->cqid), cq->gts);
}
static inline int t4_clear_cq_armed(struct t4_cq *cq)
{
return test_and_clear_bit(CQ_ARMED, &cq->flags);
}
static inline int t4_arm_cq(struct t4_cq *cq, int se)
{
u32 val;
set_bit(CQ_ARMED, &cq->flags);
while (cq->cidx_inc > CIDXINC_M) {
val = SEINTARM_V(0) | CIDXINC_V(CIDXINC_M) | TIMERREG_V(7);
write_gts(cq, val);
cq->cidx_inc -= CIDXINC_M;
}
val = SEINTARM_V(se) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(6);
write_gts(cq, val);
cq->cidx_inc = 0;
return 0;
}
static inline void t4_swcq_produce(struct t4_cq *cq)
{
cq->sw_in_use++;
if (cq->sw_in_use == cq->size) {
pr_warn("%s cxgb4 sw cq overflow cqid %u\n",
__func__, cq->cqid);
cq->error = 1;
cq->sw_in_use--;
return;
}
if (++cq->sw_pidx == cq->size)
cq->sw_pidx = 0;
}
static inline void t4_swcq_consume(struct t4_cq *cq)
{
cq->sw_in_use--;
if (++cq->sw_cidx == cq->size)
cq->sw_cidx = 0;
}
static inline void t4_hwcq_consume(struct t4_cq *cq)
{
cq->bits_type_ts = cq->queue[cq->cidx].bits_type_ts;
if (++cq->cidx_inc == (cq->size >> 4) || cq->cidx_inc == CIDXINC_M) {
u32 val;
val = SEINTARM_V(0) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(7);
write_gts(cq, val);
cq->cidx_inc = 0;
}
if (++cq->cidx == cq->size) {
cq->cidx = 0;
cq->gen ^= 1;
}
}
static inline int t4_valid_cqe(struct t4_cq *cq, struct t4_cqe *cqe)
{
return (CQE_GENBIT(cqe) == cq->gen);
}
static inline int t4_cq_notempty(struct t4_cq *cq)
{
return cq->sw_in_use || t4_valid_cqe(cq, &cq->queue[cq->cidx]);
}
static inline int t4_next_hw_cqe(struct t4_cq *cq, struct t4_cqe **cqe)
{
int ret;
u16 prev_cidx;
if (cq->cidx == 0)
prev_cidx = cq->size - 1;
else
prev_cidx = cq->cidx - 1;
if (cq->queue[prev_cidx].bits_type_ts != cq->bits_type_ts) {
ret = -EOVERFLOW;
cq->error = 1;
pr_err("cq overflow cqid %u\n", cq->cqid);
} else if (t4_valid_cqe(cq, &cq->queue[cq->cidx])) {
/* Ensure CQE is flushed to memory */
rmb();
*cqe = &cq->queue[cq->cidx];
ret = 0;
} else
ret = -ENODATA;
return ret;
}
static inline int t4_next_cqe(struct t4_cq *cq, struct t4_cqe **cqe)
{
int ret = 0;
if (cq->error)
ret = -ENODATA;
else if (cq->sw_in_use)
*cqe = &cq->sw_queue[cq->sw_cidx];
else
ret = t4_next_hw_cqe(cq, cqe);
return ret;
}
static inline void t4_set_cq_in_error(struct t4_cq *cq)
{
*cq->qp_errp = 1;
}
#endif
struct t4_dev_status_page {
u8 db_off;
u8 write_cmpl_supported;
u16 pad2;
u32 pad3;
u64 qp_start;
u64 qp_size;
u64 cq_start;
u64 cq_size;
};
@@ -0,0 +1,816 @@
/*
* Copyright (c) 2009-2010 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _T4FW_RI_API_H_
#define _T4FW_RI_API_H_
#include "t4fw_api.h"
enum fw_ri_wr_opcode {
FW_RI_RDMA_WRITE = 0x0, /* IETF RDMAP v1.0 ... */
FW_RI_READ_REQ = 0x1,
FW_RI_READ_RESP = 0x2,
FW_RI_SEND = 0x3,
FW_RI_SEND_WITH_INV = 0x4,
FW_RI_SEND_WITH_SE = 0x5,
FW_RI_SEND_WITH_SE_INV = 0x6,
FW_RI_TERMINATE = 0x7,
FW_RI_RDMA_INIT = 0x8, /* CHELSIO RI specific ... */
FW_RI_BIND_MW = 0x9,
FW_RI_FAST_REGISTER = 0xa,
FW_RI_LOCAL_INV = 0xb,
FW_RI_QP_MODIFY = 0xc,
FW_RI_BYPASS = 0xd,
FW_RI_RECEIVE = 0xe,
FW_RI_SGE_EC_CR_RETURN = 0xf,
FW_RI_WRITE_IMMEDIATE = FW_RI_RDMA_INIT
};
enum fw_ri_wr_flags {
FW_RI_COMPLETION_FLAG = 0x01,
FW_RI_NOTIFICATION_FLAG = 0x02,
FW_RI_SOLICITED_EVENT_FLAG = 0x04,
FW_RI_READ_FENCE_FLAG = 0x08,
FW_RI_LOCAL_FENCE_FLAG = 0x10,
FW_RI_RDMA_READ_INVALIDATE = 0x20,
FW_RI_RDMA_WRITE_WITH_IMMEDIATE = 0x40
};
enum fw_ri_mpa_attrs {
FW_RI_MPA_RX_MARKER_ENABLE = 0x01,
FW_RI_MPA_TX_MARKER_ENABLE = 0x02,
FW_RI_MPA_CRC_ENABLE = 0x04,
FW_RI_MPA_IETF_ENABLE = 0x08
};
enum fw_ri_qp_caps {
FW_RI_QP_RDMA_READ_ENABLE = 0x01,
FW_RI_QP_RDMA_WRITE_ENABLE = 0x02,
FW_RI_QP_BIND_ENABLE = 0x04,
FW_RI_QP_FAST_REGISTER_ENABLE = 0x08,
FW_RI_QP_STAG0_ENABLE = 0x10
};
enum fw_ri_addr_type {
FW_RI_ZERO_BASED_TO = 0x00,
FW_RI_VA_BASED_TO = 0x01
};
enum fw_ri_mem_perms {
FW_RI_MEM_ACCESS_REM_WRITE = 0x01,
FW_RI_MEM_ACCESS_REM_READ = 0x02,
FW_RI_MEM_ACCESS_REM = 0x03,
FW_RI_MEM_ACCESS_LOCAL_WRITE = 0x04,
FW_RI_MEM_ACCESS_LOCAL_READ = 0x08,
FW_RI_MEM_ACCESS_LOCAL = 0x0C
};
enum fw_ri_stag_type {
FW_RI_STAG_NSMR = 0x00,
FW_RI_STAG_SMR = 0x01,
FW_RI_STAG_MW = 0x02,
FW_RI_STAG_MW_RELAXED = 0x03
};
enum fw_ri_data_op {
FW_RI_DATA_IMMD = 0x81,
FW_RI_DATA_DSGL = 0x82,
FW_RI_DATA_ISGL = 0x83
};
enum fw_ri_sgl_depth {
FW_RI_SGL_DEPTH_MAX_SQ = 16,
FW_RI_SGL_DEPTH_MAX_RQ = 4
};
struct fw_ri_dsge_pair {
__be32 len[2];
__be64 addr[2];
};
struct fw_ri_dsgl {
__u8 op;
__u8 r1;
__be16 nsge;
__be32 len0;
__be64 addr0;
struct fw_ri_dsge_pair sge[];
};
struct fw_ri_sge {
__be32 stag;
__be32 len;
__be64 to;
};
struct fw_ri_isgl {
__u8 op;
__u8 r1;
__be16 nsge;
__be32 r2;
struct fw_ri_sge sge[];
};
struct fw_ri_immd {
__u8 op;
__u8 r1;
__be16 r2;
__be32 immdlen;
__u8 data[];
};
struct fw_ri_tpte {
__be32 valid_to_pdid;
__be32 locread_to_qpid;
__be32 nosnoop_pbladdr;
__be32 len_lo;
__be32 va_hi;
__be32 va_lo_fbo;
__be32 dca_mwbcnt_pstag;
__be32 len_hi;
};
#define FW_RI_TPTE_VALID_S 31
#define FW_RI_TPTE_VALID_M 0x1
#define FW_RI_TPTE_VALID_V(x) ((x) << FW_RI_TPTE_VALID_S)
#define FW_RI_TPTE_VALID_G(x) \
(((x) >> FW_RI_TPTE_VALID_S) & FW_RI_TPTE_VALID_M)
#define FW_RI_TPTE_VALID_F FW_RI_TPTE_VALID_V(1U)
#define FW_RI_TPTE_STAGKEY_S 23
#define FW_RI_TPTE_STAGKEY_M 0xff
#define FW_RI_TPTE_STAGKEY_V(x) ((x) << FW_RI_TPTE_STAGKEY_S)
#define FW_RI_TPTE_STAGKEY_G(x) \
(((x) >> FW_RI_TPTE_STAGKEY_S) & FW_RI_TPTE_STAGKEY_M)
#define FW_RI_TPTE_STAGSTATE_S 22
#define FW_RI_TPTE_STAGSTATE_M 0x1
#define FW_RI_TPTE_STAGSTATE_V(x) ((x) << FW_RI_TPTE_STAGSTATE_S)
#define FW_RI_TPTE_STAGSTATE_G(x) \
(((x) >> FW_RI_TPTE_STAGSTATE_S) & FW_RI_TPTE_STAGSTATE_M)
#define FW_RI_TPTE_STAGSTATE_F FW_RI_TPTE_STAGSTATE_V(1U)
#define FW_RI_TPTE_STAGTYPE_S 20
#define FW_RI_TPTE_STAGTYPE_M 0x3
#define FW_RI_TPTE_STAGTYPE_V(x) ((x) << FW_RI_TPTE_STAGTYPE_S)
#define FW_RI_TPTE_STAGTYPE_G(x) \
(((x) >> FW_RI_TPTE_STAGTYPE_S) & FW_RI_TPTE_STAGTYPE_M)
#define FW_RI_TPTE_PDID_S 0
#define FW_RI_TPTE_PDID_M 0xfffff
#define FW_RI_TPTE_PDID_V(x) ((x) << FW_RI_TPTE_PDID_S)
#define FW_RI_TPTE_PDID_G(x) \
(((x) >> FW_RI_TPTE_PDID_S) & FW_RI_TPTE_PDID_M)
#define FW_RI_TPTE_PERM_S 28
#define FW_RI_TPTE_PERM_M 0xf
#define FW_RI_TPTE_PERM_V(x) ((x) << FW_RI_TPTE_PERM_S)
#define FW_RI_TPTE_PERM_G(x) \
(((x) >> FW_RI_TPTE_PERM_S) & FW_RI_TPTE_PERM_M)
#define FW_RI_TPTE_REMINVDIS_S 27
#define FW_RI_TPTE_REMINVDIS_M 0x1
#define FW_RI_TPTE_REMINVDIS_V(x) ((x) << FW_RI_TPTE_REMINVDIS_S)
#define FW_RI_TPTE_REMINVDIS_G(x) \
(((x) >> FW_RI_TPTE_REMINVDIS_S) & FW_RI_TPTE_REMINVDIS_M)
#define FW_RI_TPTE_REMINVDIS_F FW_RI_TPTE_REMINVDIS_V(1U)
#define FW_RI_TPTE_ADDRTYPE_S 26
#define FW_RI_TPTE_ADDRTYPE_M 1
#define FW_RI_TPTE_ADDRTYPE_V(x) ((x) << FW_RI_TPTE_ADDRTYPE_S)
#define FW_RI_TPTE_ADDRTYPE_G(x) \
(((x) >> FW_RI_TPTE_ADDRTYPE_S) & FW_RI_TPTE_ADDRTYPE_M)
#define FW_RI_TPTE_ADDRTYPE_F FW_RI_TPTE_ADDRTYPE_V(1U)
#define FW_RI_TPTE_MWBINDEN_S 25
#define FW_RI_TPTE_MWBINDEN_M 0x1
#define FW_RI_TPTE_MWBINDEN_V(x) ((x) << FW_RI_TPTE_MWBINDEN_S)
#define FW_RI_TPTE_MWBINDEN_G(x) \
(((x) >> FW_RI_TPTE_MWBINDEN_S) & FW_RI_TPTE_MWBINDEN_M)
#define FW_RI_TPTE_MWBINDEN_F FW_RI_TPTE_MWBINDEN_V(1U)
#define FW_RI_TPTE_PS_S 20
#define FW_RI_TPTE_PS_M 0x1f
#define FW_RI_TPTE_PS_V(x) ((x) << FW_RI_TPTE_PS_S)
#define FW_RI_TPTE_PS_G(x) \
(((x) >> FW_RI_TPTE_PS_S) & FW_RI_TPTE_PS_M)
#define FW_RI_TPTE_QPID_S 0
#define FW_RI_TPTE_QPID_M 0xfffff
#define FW_RI_TPTE_QPID_V(x) ((x) << FW_RI_TPTE_QPID_S)
#define FW_RI_TPTE_QPID_G(x) \
(((x) >> FW_RI_TPTE_QPID_S) & FW_RI_TPTE_QPID_M)
#define FW_RI_TPTE_NOSNOOP_S 30
#define FW_RI_TPTE_NOSNOOP_M 0x1
#define FW_RI_TPTE_NOSNOOP_V(x) ((x) << FW_RI_TPTE_NOSNOOP_S)
#define FW_RI_TPTE_NOSNOOP_G(x) \
(((x) >> FW_RI_TPTE_NOSNOOP_S) & FW_RI_TPTE_NOSNOOP_M)
#define FW_RI_TPTE_NOSNOOP_F FW_RI_TPTE_NOSNOOP_V(1U)
#define FW_RI_TPTE_PBLADDR_S 0
#define FW_RI_TPTE_PBLADDR_M 0x1fffffff
#define FW_RI_TPTE_PBLADDR_V(x) ((x) << FW_RI_TPTE_PBLADDR_S)
#define FW_RI_TPTE_PBLADDR_G(x) \
(((x) >> FW_RI_TPTE_PBLADDR_S) & FW_RI_TPTE_PBLADDR_M)
#define FW_RI_TPTE_DCA_S 24
#define FW_RI_TPTE_DCA_M 0x1f
#define FW_RI_TPTE_DCA_V(x) ((x) << FW_RI_TPTE_DCA_S)
#define FW_RI_TPTE_DCA_G(x) \
(((x) >> FW_RI_TPTE_DCA_S) & FW_RI_TPTE_DCA_M)
#define FW_RI_TPTE_MWBCNT_PSTAG_S 0
#define FW_RI_TPTE_MWBCNT_PSTAG_M 0xffffff
#define FW_RI_TPTE_MWBCNT_PSTAT_V(x) \
((x) << FW_RI_TPTE_MWBCNT_PSTAG_S)
#define FW_RI_TPTE_MWBCNT_PSTAG_G(x) \
(((x) >> FW_RI_TPTE_MWBCNT_PSTAG_S) & FW_RI_TPTE_MWBCNT_PSTAG_M)
enum fw_ri_res_type {
FW_RI_RES_TYPE_SQ,
FW_RI_RES_TYPE_RQ,
FW_RI_RES_TYPE_CQ,
FW_RI_RES_TYPE_SRQ,
};
enum fw_ri_res_op {
FW_RI_RES_OP_WRITE,
FW_RI_RES_OP_RESET,
};
struct fw_ri_res {
union fw_ri_restype {
struct fw_ri_res_sqrq {
__u8 restype;
__u8 op;
__be16 r3;
__be32 eqid;
__be32 r4[2];
__be32 fetchszm_to_iqid;
__be32 dcaen_to_eqsize;
__be64 eqaddr;
} sqrq;
struct fw_ri_res_cq {
__u8 restype;
__u8 op;
__be16 r3;
__be32 iqid;
__be32 r4[2];
__be32 iqandst_to_iqandstindex;
__be16 iqdroprss_to_iqesize;
__be16 iqsize;
__be64 iqaddr;
__be32 iqns_iqro;
__be32 r6_lo;
__be64 r7;
} cq;
struct fw_ri_res_srq {
__u8 restype;
__u8 op;
__be16 r3;
__be32 eqid;
__be32 r4[2];
__be32 fetchszm_to_iqid;
__be32 dcaen_to_eqsize;
__be64 eqaddr;
__be32 srqid;
__be32 pdid;
__be32 hwsrqsize;
__be32 hwsrqaddr;
} srq;
} u;
};
struct fw_ri_res_wr {
__be32 op_nres;
__be32 len16_pkd;
__u64 cookie;
struct fw_ri_res res[];
};
#define FW_RI_RES_WR_NRES_S 0
#define FW_RI_RES_WR_NRES_M 0xff
#define FW_RI_RES_WR_NRES_V(x) ((x) << FW_RI_RES_WR_NRES_S)
#define FW_RI_RES_WR_NRES_G(x) \
(((x) >> FW_RI_RES_WR_NRES_S) & FW_RI_RES_WR_NRES_M)
#define FW_RI_RES_WR_FETCHSZM_S 26
#define FW_RI_RES_WR_FETCHSZM_M 0x1
#define FW_RI_RES_WR_FETCHSZM_V(x) ((x) << FW_RI_RES_WR_FETCHSZM_S)
#define FW_RI_RES_WR_FETCHSZM_G(x) \
(((x) >> FW_RI_RES_WR_FETCHSZM_S) & FW_RI_RES_WR_FETCHSZM_M)
#define FW_RI_RES_WR_FETCHSZM_F FW_RI_RES_WR_FETCHSZM_V(1U)
#define FW_RI_RES_WR_STATUSPGNS_S 25
#define FW_RI_RES_WR_STATUSPGNS_M 0x1
#define FW_RI_RES_WR_STATUSPGNS_V(x) ((x) << FW_RI_RES_WR_STATUSPGNS_S)
#define FW_RI_RES_WR_STATUSPGNS_G(x) \
(((x) >> FW_RI_RES_WR_STATUSPGNS_S) & FW_RI_RES_WR_STATUSPGNS_M)
#define FW_RI_RES_WR_STATUSPGNS_F FW_RI_RES_WR_STATUSPGNS_V(1U)
#define FW_RI_RES_WR_STATUSPGRO_S 24
#define FW_RI_RES_WR_STATUSPGRO_M 0x1
#define FW_RI_RES_WR_STATUSPGRO_V(x) ((x) << FW_RI_RES_WR_STATUSPGRO_S)
#define FW_RI_RES_WR_STATUSPGRO_G(x) \
(((x) >> FW_RI_RES_WR_STATUSPGRO_S) & FW_RI_RES_WR_STATUSPGRO_M)
#define FW_RI_RES_WR_STATUSPGRO_F FW_RI_RES_WR_STATUSPGRO_V(1U)
#define FW_RI_RES_WR_FETCHNS_S 23
#define FW_RI_RES_WR_FETCHNS_M 0x1
#define FW_RI_RES_WR_FETCHNS_V(x) ((x) << FW_RI_RES_WR_FETCHNS_S)
#define FW_RI_RES_WR_FETCHNS_G(x) \
(((x) >> FW_RI_RES_WR_FETCHNS_S) & FW_RI_RES_WR_FETCHNS_M)
#define FW_RI_RES_WR_FETCHNS_F FW_RI_RES_WR_FETCHNS_V(1U)
#define FW_RI_RES_WR_FETCHRO_S 22
#define FW_RI_RES_WR_FETCHRO_M 0x1
#define FW_RI_RES_WR_FETCHRO_V(x) ((x) << FW_RI_RES_WR_FETCHRO_S)
#define FW_RI_RES_WR_FETCHRO_G(x) \
(((x) >> FW_RI_RES_WR_FETCHRO_S) & FW_RI_RES_WR_FETCHRO_M)
#define FW_RI_RES_WR_FETCHRO_F FW_RI_RES_WR_FETCHRO_V(1U)
#define FW_RI_RES_WR_HOSTFCMODE_S 20
#define FW_RI_RES_WR_HOSTFCMODE_M 0x3
#define FW_RI_RES_WR_HOSTFCMODE_V(x) ((x) << FW_RI_RES_WR_HOSTFCMODE_S)
#define FW_RI_RES_WR_HOSTFCMODE_G(x) \
(((x) >> FW_RI_RES_WR_HOSTFCMODE_S) & FW_RI_RES_WR_HOSTFCMODE_M)
#define FW_RI_RES_WR_CPRIO_S 19
#define FW_RI_RES_WR_CPRIO_M 0x1
#define FW_RI_RES_WR_CPRIO_V(x) ((x) << FW_RI_RES_WR_CPRIO_S)
#define FW_RI_RES_WR_CPRIO_G(x) \
(((x) >> FW_RI_RES_WR_CPRIO_S) & FW_RI_RES_WR_CPRIO_M)
#define FW_RI_RES_WR_CPRIO_F FW_RI_RES_WR_CPRIO_V(1U)
#define FW_RI_RES_WR_ONCHIP_S 18
#define FW_RI_RES_WR_ONCHIP_M 0x1
#define FW_RI_RES_WR_ONCHIP_V(x) ((x) << FW_RI_RES_WR_ONCHIP_S)
#define FW_RI_RES_WR_ONCHIP_G(x) \
(((x) >> FW_RI_RES_WR_ONCHIP_S) & FW_RI_RES_WR_ONCHIP_M)
#define FW_RI_RES_WR_ONCHIP_F FW_RI_RES_WR_ONCHIP_V(1U)
#define FW_RI_RES_WR_PCIECHN_S 16
#define FW_RI_RES_WR_PCIECHN_M 0x3
#define FW_RI_RES_WR_PCIECHN_V(x) ((x) << FW_RI_RES_WR_PCIECHN_S)
#define FW_RI_RES_WR_PCIECHN_G(x) \
(((x) >> FW_RI_RES_WR_PCIECHN_S) & FW_RI_RES_WR_PCIECHN_M)
#define FW_RI_RES_WR_IQID_S 0
#define FW_RI_RES_WR_IQID_M 0xffff
#define FW_RI_RES_WR_IQID_V(x) ((x) << FW_RI_RES_WR_IQID_S)
#define FW_RI_RES_WR_IQID_G(x) \
(((x) >> FW_RI_RES_WR_IQID_S) & FW_RI_RES_WR_IQID_M)
#define FW_RI_RES_WR_DCAEN_S 31
#define FW_RI_RES_WR_DCAEN_M 0x1
#define FW_RI_RES_WR_DCAEN_V(x) ((x) << FW_RI_RES_WR_DCAEN_S)
#define FW_RI_RES_WR_DCAEN_G(x) \
(((x) >> FW_RI_RES_WR_DCAEN_S) & FW_RI_RES_WR_DCAEN_M)
#define FW_RI_RES_WR_DCAEN_F FW_RI_RES_WR_DCAEN_V(1U)
#define FW_RI_RES_WR_DCACPU_S 26
#define FW_RI_RES_WR_DCACPU_M 0x1f
#define FW_RI_RES_WR_DCACPU_V(x) ((x) << FW_RI_RES_WR_DCACPU_S)
#define FW_RI_RES_WR_DCACPU_G(x) \
(((x) >> FW_RI_RES_WR_DCACPU_S) & FW_RI_RES_WR_DCACPU_M)
#define FW_RI_RES_WR_FBMIN_S 23
#define FW_RI_RES_WR_FBMIN_M 0x7
#define FW_RI_RES_WR_FBMIN_V(x) ((x) << FW_RI_RES_WR_FBMIN_S)
#define FW_RI_RES_WR_FBMIN_G(x) \
(((x) >> FW_RI_RES_WR_FBMIN_S) & FW_RI_RES_WR_FBMIN_M)
#define FW_RI_RES_WR_FBMAX_S 20
#define FW_RI_RES_WR_FBMAX_M 0x7
#define FW_RI_RES_WR_FBMAX_V(x) ((x) << FW_RI_RES_WR_FBMAX_S)
#define FW_RI_RES_WR_FBMAX_G(x) \
(((x) >> FW_RI_RES_WR_FBMAX_S) & FW_RI_RES_WR_FBMAX_M)
#define FW_RI_RES_WR_CIDXFTHRESHO_S 19
#define FW_RI_RES_WR_CIDXFTHRESHO_M 0x1
#define FW_RI_RES_WR_CIDXFTHRESHO_V(x) ((x) << FW_RI_RES_WR_CIDXFTHRESHO_S)
#define FW_RI_RES_WR_CIDXFTHRESHO_G(x) \
(((x) >> FW_RI_RES_WR_CIDXFTHRESHO_S) & FW_RI_RES_WR_CIDXFTHRESHO_M)
#define FW_RI_RES_WR_CIDXFTHRESHO_F FW_RI_RES_WR_CIDXFTHRESHO_V(1U)
#define FW_RI_RES_WR_CIDXFTHRESH_S 16
#define FW_RI_RES_WR_CIDXFTHRESH_M 0x7
#define FW_RI_RES_WR_CIDXFTHRESH_V(x) ((x) << FW_RI_RES_WR_CIDXFTHRESH_S)
#define FW_RI_RES_WR_CIDXFTHRESH_G(x) \
(((x) >> FW_RI_RES_WR_CIDXFTHRESH_S) & FW_RI_RES_WR_CIDXFTHRESH_M)
#define FW_RI_RES_WR_EQSIZE_S 0
#define FW_RI_RES_WR_EQSIZE_M 0xffff
#define FW_RI_RES_WR_EQSIZE_V(x) ((x) << FW_RI_RES_WR_EQSIZE_S)
#define FW_RI_RES_WR_EQSIZE_G(x) \
(((x) >> FW_RI_RES_WR_EQSIZE_S) & FW_RI_RES_WR_EQSIZE_M)
#define FW_RI_RES_WR_IQANDST_S 15
#define FW_RI_RES_WR_IQANDST_M 0x1
#define FW_RI_RES_WR_IQANDST_V(x) ((x) << FW_RI_RES_WR_IQANDST_S)
#define FW_RI_RES_WR_IQANDST_G(x) \
(((x) >> FW_RI_RES_WR_IQANDST_S) & FW_RI_RES_WR_IQANDST_M)
#define FW_RI_RES_WR_IQANDST_F FW_RI_RES_WR_IQANDST_V(1U)
#define FW_RI_RES_WR_IQANUS_S 14
#define FW_RI_RES_WR_IQANUS_M 0x1
#define FW_RI_RES_WR_IQANUS_V(x) ((x) << FW_RI_RES_WR_IQANUS_S)
#define FW_RI_RES_WR_IQANUS_G(x) \
(((x) >> FW_RI_RES_WR_IQANUS_S) & FW_RI_RES_WR_IQANUS_M)
#define FW_RI_RES_WR_IQANUS_F FW_RI_RES_WR_IQANUS_V(1U)
#define FW_RI_RES_WR_IQANUD_S 12
#define FW_RI_RES_WR_IQANUD_M 0x3
#define FW_RI_RES_WR_IQANUD_V(x) ((x) << FW_RI_RES_WR_IQANUD_S)
#define FW_RI_RES_WR_IQANUD_G(x) \
(((x) >> FW_RI_RES_WR_IQANUD_S) & FW_RI_RES_WR_IQANUD_M)
#define FW_RI_RES_WR_IQANDSTINDEX_S 0
#define FW_RI_RES_WR_IQANDSTINDEX_M 0xfff
#define FW_RI_RES_WR_IQANDSTINDEX_V(x) ((x) << FW_RI_RES_WR_IQANDSTINDEX_S)
#define FW_RI_RES_WR_IQANDSTINDEX_G(x) \
(((x) >> FW_RI_RES_WR_IQANDSTINDEX_S) & FW_RI_RES_WR_IQANDSTINDEX_M)
#define FW_RI_RES_WR_IQDROPRSS_S 15
#define FW_RI_RES_WR_IQDROPRSS_M 0x1
#define FW_RI_RES_WR_IQDROPRSS_V(x) ((x) << FW_RI_RES_WR_IQDROPRSS_S)
#define FW_RI_RES_WR_IQDROPRSS_G(x) \
(((x) >> FW_RI_RES_WR_IQDROPRSS_S) & FW_RI_RES_WR_IQDROPRSS_M)
#define FW_RI_RES_WR_IQDROPRSS_F FW_RI_RES_WR_IQDROPRSS_V(1U)
#define FW_RI_RES_WR_IQGTSMODE_S 14
#define FW_RI_RES_WR_IQGTSMODE_M 0x1
#define FW_RI_RES_WR_IQGTSMODE_V(x) ((x) << FW_RI_RES_WR_IQGTSMODE_S)
#define FW_RI_RES_WR_IQGTSMODE_G(x) \
(((x) >> FW_RI_RES_WR_IQGTSMODE_S) & FW_RI_RES_WR_IQGTSMODE_M)
#define FW_RI_RES_WR_IQGTSMODE_F FW_RI_RES_WR_IQGTSMODE_V(1U)
#define FW_RI_RES_WR_IQPCIECH_S 12
#define FW_RI_RES_WR_IQPCIECH_M 0x3
#define FW_RI_RES_WR_IQPCIECH_V(x) ((x) << FW_RI_RES_WR_IQPCIECH_S)
#define FW_RI_RES_WR_IQPCIECH_G(x) \
(((x) >> FW_RI_RES_WR_IQPCIECH_S) & FW_RI_RES_WR_IQPCIECH_M)
#define FW_RI_RES_WR_IQDCAEN_S 11
#define FW_RI_RES_WR_IQDCAEN_M 0x1
#define FW_RI_RES_WR_IQDCAEN_V(x) ((x) << FW_RI_RES_WR_IQDCAEN_S)
#define FW_RI_RES_WR_IQDCAEN_G(x) \
(((x) >> FW_RI_RES_WR_IQDCAEN_S) & FW_RI_RES_WR_IQDCAEN_M)
#define FW_RI_RES_WR_IQDCAEN_F FW_RI_RES_WR_IQDCAEN_V(1U)
#define FW_RI_RES_WR_IQDCACPU_S 6
#define FW_RI_RES_WR_IQDCACPU_M 0x1f
#define FW_RI_RES_WR_IQDCACPU_V(x) ((x) << FW_RI_RES_WR_IQDCACPU_S)
#define FW_RI_RES_WR_IQDCACPU_G(x) \
(((x) >> FW_RI_RES_WR_IQDCACPU_S) & FW_RI_RES_WR_IQDCACPU_M)
#define FW_RI_RES_WR_IQINTCNTTHRESH_S 4
#define FW_RI_RES_WR_IQINTCNTTHRESH_M 0x3
#define FW_RI_RES_WR_IQINTCNTTHRESH_V(x) \
((x) << FW_RI_RES_WR_IQINTCNTTHRESH_S)
#define FW_RI_RES_WR_IQINTCNTTHRESH_G(x) \
(((x) >> FW_RI_RES_WR_IQINTCNTTHRESH_S) & FW_RI_RES_WR_IQINTCNTTHRESH_M)
#define FW_RI_RES_WR_IQO_S 3
#define FW_RI_RES_WR_IQO_M 0x1
#define FW_RI_RES_WR_IQO_V(x) ((x) << FW_RI_RES_WR_IQO_S)
#define FW_RI_RES_WR_IQO_G(x) \
(((x) >> FW_RI_RES_WR_IQO_S) & FW_RI_RES_WR_IQO_M)
#define FW_RI_RES_WR_IQO_F FW_RI_RES_WR_IQO_V(1U)
#define FW_RI_RES_WR_IQCPRIO_S 2
#define FW_RI_RES_WR_IQCPRIO_M 0x1
#define FW_RI_RES_WR_IQCPRIO_V(x) ((x) << FW_RI_RES_WR_IQCPRIO_S)
#define FW_RI_RES_WR_IQCPRIO_G(x) \
(((x) >> FW_RI_RES_WR_IQCPRIO_S) & FW_RI_RES_WR_IQCPRIO_M)
#define FW_RI_RES_WR_IQCPRIO_F FW_RI_RES_WR_IQCPRIO_V(1U)
#define FW_RI_RES_WR_IQESIZE_S 0
#define FW_RI_RES_WR_IQESIZE_M 0x3
#define FW_RI_RES_WR_IQESIZE_V(x) ((x) << FW_RI_RES_WR_IQESIZE_S)
#define FW_RI_RES_WR_IQESIZE_G(x) \
(((x) >> FW_RI_RES_WR_IQESIZE_S) & FW_RI_RES_WR_IQESIZE_M)
#define FW_RI_RES_WR_IQNS_S 31
#define FW_RI_RES_WR_IQNS_M 0x1
#define FW_RI_RES_WR_IQNS_V(x) ((x) << FW_RI_RES_WR_IQNS_S)
#define FW_RI_RES_WR_IQNS_G(x) \
(((x) >> FW_RI_RES_WR_IQNS_S) & FW_RI_RES_WR_IQNS_M)
#define FW_RI_RES_WR_IQNS_F FW_RI_RES_WR_IQNS_V(1U)
#define FW_RI_RES_WR_IQRO_S 30
#define FW_RI_RES_WR_IQRO_M 0x1
#define FW_RI_RES_WR_IQRO_V(x) ((x) << FW_RI_RES_WR_IQRO_S)
#define FW_RI_RES_WR_IQRO_G(x) \
(((x) >> FW_RI_RES_WR_IQRO_S) & FW_RI_RES_WR_IQRO_M)
#define FW_RI_RES_WR_IQRO_F FW_RI_RES_WR_IQRO_V(1U)
struct fw_ri_rdma_write_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
/*
* Use union for immediate data to be consistent with stack's 32 bit
* data and iWARP spec's 64 bit data.
*/
union {
struct {
__be32 imm_data32;
u32 reserved;
} ib_imm_data;
__be64 imm_data64;
} iw_imm_data;
__be32 plen;
__be32 stag_sink;
__be64 to_sink;
union {
DECLARE_FLEX_ARRAY(struct fw_ri_immd, immd_src);
DECLARE_FLEX_ARRAY(struct fw_ri_isgl, isgl_src);
} u;
};
struct fw_ri_send_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
__be32 sendop_pkd;
__be32 stag_inv;
__be32 plen;
__be32 r3;
__be64 r4;
union {
DECLARE_FLEX_ARRAY(struct fw_ri_immd, immd_src);
DECLARE_FLEX_ARRAY(struct fw_ri_isgl, isgl_src);
} u;
};
#define FW_RI_SEND_WR_SENDOP_S 0
#define FW_RI_SEND_WR_SENDOP_M 0xf
#define FW_RI_SEND_WR_SENDOP_V(x) ((x) << FW_RI_SEND_WR_SENDOP_S)
#define FW_RI_SEND_WR_SENDOP_G(x) \
(((x) >> FW_RI_SEND_WR_SENDOP_S) & FW_RI_SEND_WR_SENDOP_M)
struct fw_ri_rdma_write_cmpl_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
__u8 r2;
__u8 flags_send;
__u16 wrid_send;
__be32 stag_inv;
__be32 plen;
__be32 stag_sink;
__be64 to_sink;
union fw_ri_cmpl {
struct fw_ri_immd_cmpl {
__u8 op;
__u8 r1[6];
__u8 immdlen;
__u8 data[16];
} immd_src;
struct fw_ri_isgl isgl_src;
} u_cmpl;
__be64 r3;
union fw_ri_write {
DECLARE_FLEX_ARRAY(struct fw_ri_immd, immd_src);
DECLARE_FLEX_ARRAY(struct fw_ri_isgl, isgl_src);
} u;
};
struct fw_ri_rdma_read_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
__be64 r2;
__be32 stag_sink;
__be32 to_sink_hi;
__be32 to_sink_lo;
__be32 plen;
__be32 stag_src;
__be32 to_src_hi;
__be32 to_src_lo;
__be32 r5;
};
struct fw_ri_recv_wr {
__u8 opcode;
__u8 r1;
__u16 wrid;
__u8 r2[3];
__u8 len16;
struct fw_ri_isgl isgl;
};
struct fw_ri_bind_mw_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
__u8 qpbinde_to_dcacpu;
__u8 pgsz_shift;
__u8 addr_type;
__u8 mem_perms;
__be32 stag_mr;
__be32 stag_mw;
__be32 r3;
__be64 len_mw;
__be64 va_fbo;
__be64 r4;
};
#define FW_RI_BIND_MW_WR_QPBINDE_S 6
#define FW_RI_BIND_MW_WR_QPBINDE_M 0x1
#define FW_RI_BIND_MW_WR_QPBINDE_V(x) ((x) << FW_RI_BIND_MW_WR_QPBINDE_S)
#define FW_RI_BIND_MW_WR_QPBINDE_G(x) \
(((x) >> FW_RI_BIND_MW_WR_QPBINDE_S) & FW_RI_BIND_MW_WR_QPBINDE_M)
#define FW_RI_BIND_MW_WR_QPBINDE_F FW_RI_BIND_MW_WR_QPBINDE_V(1U)
#define FW_RI_BIND_MW_WR_NS_S 5
#define FW_RI_BIND_MW_WR_NS_M 0x1
#define FW_RI_BIND_MW_WR_NS_V(x) ((x) << FW_RI_BIND_MW_WR_NS_S)
#define FW_RI_BIND_MW_WR_NS_G(x) \
(((x) >> FW_RI_BIND_MW_WR_NS_S) & FW_RI_BIND_MW_WR_NS_M)
#define FW_RI_BIND_MW_WR_NS_F FW_RI_BIND_MW_WR_NS_V(1U)
#define FW_RI_BIND_MW_WR_DCACPU_S 0
#define FW_RI_BIND_MW_WR_DCACPU_M 0x1f
#define FW_RI_BIND_MW_WR_DCACPU_V(x) ((x) << FW_RI_BIND_MW_WR_DCACPU_S)
#define FW_RI_BIND_MW_WR_DCACPU_G(x) \
(((x) >> FW_RI_BIND_MW_WR_DCACPU_S) & FW_RI_BIND_MW_WR_DCACPU_M)
struct fw_ri_fr_nsmr_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
__u8 qpbinde_to_dcacpu;
__u8 pgsz_shift;
__u8 addr_type;
__u8 mem_perms;
__be32 stag;
__be32 len_hi;
__be32 len_lo;
__be32 va_hi;
__be32 va_lo_fbo;
};
#define FW_RI_FR_NSMR_WR_QPBINDE_S 6
#define FW_RI_FR_NSMR_WR_QPBINDE_M 0x1
#define FW_RI_FR_NSMR_WR_QPBINDE_V(x) ((x) << FW_RI_FR_NSMR_WR_QPBINDE_S)
#define FW_RI_FR_NSMR_WR_QPBINDE_G(x) \
(((x) >> FW_RI_FR_NSMR_WR_QPBINDE_S) & FW_RI_FR_NSMR_WR_QPBINDE_M)
#define FW_RI_FR_NSMR_WR_QPBINDE_F FW_RI_FR_NSMR_WR_QPBINDE_V(1U)
#define FW_RI_FR_NSMR_WR_NS_S 5
#define FW_RI_FR_NSMR_WR_NS_M 0x1
#define FW_RI_FR_NSMR_WR_NS_V(x) ((x) << FW_RI_FR_NSMR_WR_NS_S)
#define FW_RI_FR_NSMR_WR_NS_G(x) \
(((x) >> FW_RI_FR_NSMR_WR_NS_S) & FW_RI_FR_NSMR_WR_NS_M)
#define FW_RI_FR_NSMR_WR_NS_F FW_RI_FR_NSMR_WR_NS_V(1U)
#define FW_RI_FR_NSMR_WR_DCACPU_S 0
#define FW_RI_FR_NSMR_WR_DCACPU_M 0x1f
#define FW_RI_FR_NSMR_WR_DCACPU_V(x) ((x) << FW_RI_FR_NSMR_WR_DCACPU_S)
#define FW_RI_FR_NSMR_WR_DCACPU_G(x) \
(((x) >> FW_RI_FR_NSMR_WR_DCACPU_S) & FW_RI_FR_NSMR_WR_DCACPU_M)
struct fw_ri_fr_nsmr_tpte_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
__be32 r2;
__be32 stag;
struct fw_ri_tpte tpte;
__u64 pbl[2];
};
struct fw_ri_inv_lstag_wr {
__u8 opcode;
__u8 flags;
__u16 wrid;
__u8 r1[3];
__u8 len16;
__be32 r2;
__be32 stag_inv;
};
enum fw_ri_type {
FW_RI_TYPE_INIT,
FW_RI_TYPE_FINI,
FW_RI_TYPE_TERMINATE
};
enum fw_ri_init_p2ptype {
FW_RI_INIT_P2PTYPE_RDMA_WRITE = FW_RI_RDMA_WRITE,
FW_RI_INIT_P2PTYPE_READ_REQ = FW_RI_READ_REQ,
FW_RI_INIT_P2PTYPE_SEND = FW_RI_SEND,
FW_RI_INIT_P2PTYPE_SEND_WITH_INV = FW_RI_SEND_WITH_INV,
FW_RI_INIT_P2PTYPE_SEND_WITH_SE = FW_RI_SEND_WITH_SE,
FW_RI_INIT_P2PTYPE_SEND_WITH_SE_INV = FW_RI_SEND_WITH_SE_INV,
FW_RI_INIT_P2PTYPE_DISABLED = 0xf,
};
enum fw_ri_init_rqeqid_srq {
FW_RI_INIT_RQEQID_SRQ = 1 << 31,
};
struct fw_ri_wr {
__be32 op_compl;
__be32 flowid_len16;
__u64 cookie;
union fw_ri {
struct fw_ri_init {
__u8 type;
__u8 mpareqbit_p2ptype;
__u8 r4[2];
__u8 mpa_attrs;
__u8 qp_caps;
__be16 nrqe;
__be32 pdid;
__be32 qpid;
__be32 sq_eqid;
__be32 rq_eqid;
__be32 scqid;
__be32 rcqid;
__be32 ord_max;
__be32 ird_max;
__be32 iss;
__be32 irs;
__be32 hwrqsize;
__be32 hwrqaddr;
__be64 r5;
union fw_ri_init_p2p {
struct fw_ri_rdma_write_wr write;
struct fw_ri_rdma_read_wr read;
struct fw_ri_send_wr send;
} u;
} init;
struct fw_ri_fini {
__u8 type;
__u8 r3[7];
__be64 r4;
} fini;
struct fw_ri_terminate {
__u8 type;
__u8 r3[3];
__be32 immdlen;
__u8 termmsg[40];
} terminate;
} u;
};
#define FW_RI_WR_MPAREQBIT_S 7
#define FW_RI_WR_MPAREQBIT_M 0x1
#define FW_RI_WR_MPAREQBIT_V(x) ((x) << FW_RI_WR_MPAREQBIT_S)
#define FW_RI_WR_MPAREQBIT_G(x) \
(((x) >> FW_RI_WR_MPAREQBIT_S) & FW_RI_WR_MPAREQBIT_M)
#define FW_RI_WR_MPAREQBIT_F FW_RI_WR_MPAREQBIT_V(1U)
#define FW_RI_WR_P2PTYPE_S 0
#define FW_RI_WR_P2PTYPE_M 0xf
#define FW_RI_WR_P2PTYPE_V(x) ((x) << FW_RI_WR_P2PTYPE_S)
#define FW_RI_WR_P2PTYPE_G(x) \
(((x) >> FW_RI_WR_P2PTYPE_S) & FW_RI_WR_P2PTYPE_M)
#endif /* _T4FW_RI_API_H_ */