mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 16:14:13 +08:00
RDMA/bnxt_re: Add bnxt_re RoCE driver
This patch introduces the RoCE driver for the Broadcom NetXtreme-E 10/25/40/50G RoCE HCAs. The RoCE driver is a two part driver that relies on the parent bnxt_en NIC driver to operate. The changes needed in the bnxt_en driver have already been incorporated via Dave Miller's net tree into the mainline kernel. The vendor official git repository for this driver is available on github as: https://github.com/Broadcom/linux-rdma-nxt/ Signed-off-by: Eddie Wai <eddie.wai@broadcom.com> Signed-off-by: Devesh Sharma <devesh.sharma@broadcom.com> Signed-off-by: Somnath Kotur <somnath.kotur@broadcom.com> Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com> Signed-off-by: Selvin Xavier <selvin.xavier@broadcom.com> Reviewed-by: Leon Romanovsky <leonro@mellanox.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
This commit is contained in:
parent
24dc831b77
commit
1ac5a40479
146
drivers/infiniband/hw/bnxt_re/bnxt_re.h
Normal file
146
drivers/infiniband/hw/bnxt_re/bnxt_re.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: Slow Path Operators (header)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BNXT_RE_H__
|
||||
#define __BNXT_RE_H__
|
||||
#define ROCE_DRV_MODULE_NAME "bnxt_re"
|
||||
#define ROCE_DRV_MODULE_VERSION "1.0.0"
|
||||
|
||||
#define BNXT_RE_DESC "Broadcom NetXtreme-C/E RoCE Driver"
|
||||
|
||||
#define BNXT_RE_PAGE_SIZE_4K BIT(12)
|
||||
#define BNXT_RE_PAGE_SIZE_8K BIT(13)
|
||||
#define BNXT_RE_PAGE_SIZE_64K BIT(16)
|
||||
#define BNXT_RE_PAGE_SIZE_2M BIT(21)
|
||||
#define BNXT_RE_PAGE_SIZE_8M BIT(23)
|
||||
#define BNXT_RE_PAGE_SIZE_1G BIT(30)
|
||||
|
||||
#define BNXT_RE_MAX_QPC_COUNT (64 * 1024)
|
||||
#define BNXT_RE_MAX_MRW_COUNT (64 * 1024)
|
||||
#define BNXT_RE_MAX_SRQC_COUNT (64 * 1024)
|
||||
#define BNXT_RE_MAX_CQ_COUNT (64 * 1024)
|
||||
|
||||
struct bnxt_re_work {
|
||||
struct work_struct work;
|
||||
unsigned long event;
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct net_device *vlan_dev;
|
||||
};
|
||||
|
||||
struct bnxt_re_sqp_entries {
|
||||
struct bnxt_qplib_sge sge;
|
||||
u64 wrid;
|
||||
/* For storing the actual qp1 cqe */
|
||||
struct bnxt_qplib_cqe cqe;
|
||||
struct bnxt_re_qp *qp1_qp;
|
||||
};
|
||||
|
||||
#define BNXT_RE_MIN_MSIX 2
|
||||
#define BNXT_RE_MAX_MSIX 16
|
||||
#define BNXT_RE_AEQ_IDX 0
|
||||
#define BNXT_RE_NQ_IDX 1
|
||||
|
||||
struct bnxt_re_dev {
|
||||
struct ib_device ibdev;
|
||||
struct list_head list;
|
||||
unsigned long flags;
|
||||
#define BNXT_RE_FLAG_NETDEV_REGISTERED 0
|
||||
#define BNXT_RE_FLAG_IBDEV_REGISTERED 1
|
||||
#define BNXT_RE_FLAG_GOT_MSIX 2
|
||||
#define BNXT_RE_FLAG_RCFW_CHANNEL_EN 8
|
||||
#define BNXT_RE_FLAG_QOS_WORK_REG 16
|
||||
struct net_device *netdev;
|
||||
unsigned int version, major, minor;
|
||||
struct bnxt_en_dev *en_dev;
|
||||
struct bnxt_msix_entry msix_entries[BNXT_RE_MAX_MSIX];
|
||||
int num_msix;
|
||||
|
||||
int id;
|
||||
|
||||
struct delayed_work worker;
|
||||
u8 cur_prio_map;
|
||||
|
||||
/* FP Notification Queue (CQ & SRQ) */
|
||||
struct tasklet_struct nq_task;
|
||||
|
||||
/* RCFW Channel */
|
||||
struct bnxt_qplib_rcfw rcfw;
|
||||
|
||||
/* NQ */
|
||||
struct bnxt_qplib_nq nq;
|
||||
|
||||
/* Device Resources */
|
||||
struct bnxt_qplib_dev_attr dev_attr;
|
||||
struct bnxt_qplib_ctx qplib_ctx;
|
||||
struct bnxt_qplib_res qplib_res;
|
||||
struct bnxt_qplib_dpi dpi_privileged;
|
||||
|
||||
atomic_t qp_count;
|
||||
struct mutex qp_lock; /* protect qp list */
|
||||
struct list_head qp_list;
|
||||
|
||||
atomic_t cq_count;
|
||||
atomic_t srq_count;
|
||||
atomic_t mr_count;
|
||||
atomic_t mw_count;
|
||||
/* Max of 2 lossless traffic class supported per port */
|
||||
u16 cosq[2];
|
||||
|
||||
/* QP for for handling QP1 packets */
|
||||
u32 sqp_id;
|
||||
struct bnxt_re_qp *qp1_sqp;
|
||||
struct bnxt_re_ah *sqp_ah;
|
||||
struct bnxt_re_sqp_entries sqp_tbl[1024];
|
||||
};
|
||||
|
||||
#define to_bnxt_re_dev(ptr, member) \
|
||||
container_of((ptr), struct bnxt_re_dev, member)
|
||||
|
||||
#define BNXT_RE_ROCE_V1_PACKET 0
|
||||
#define BNXT_RE_ROCEV2_IPV4_PACKET 2
|
||||
#define BNXT_RE_ROCEV2_IPV6_PACKET 3
|
||||
|
||||
static inline struct device *rdev_to_dev(struct bnxt_re_dev *rdev)
|
||||
{
|
||||
if (rdev)
|
||||
return &rdev->ibdev.dev;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
3202
drivers/infiniband/hw/bnxt_re/ib_verbs.c
Normal file
3202
drivers/infiniband/hw/bnxt_re/ib_verbs.c
Normal file
File diff suppressed because it is too large
Load Diff
197
drivers/infiniband/hw/bnxt_re/ib_verbs.h
Normal file
197
drivers/infiniband/hw/bnxt_re/ib_verbs.h
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: IB Verbs interpreter (header)
|
||||
*/
|
||||
|
||||
#ifndef __BNXT_RE_IB_VERBS_H__
|
||||
#define __BNXT_RE_IB_VERBS_H__
|
||||
|
||||
struct bnxt_re_gid_ctx {
|
||||
u32 idx;
|
||||
u32 refcnt;
|
||||
};
|
||||
|
||||
struct bnxt_re_pd {
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct ib_pd ib_pd;
|
||||
struct bnxt_qplib_pd qplib_pd;
|
||||
struct bnxt_qplib_dpi dpi;
|
||||
};
|
||||
|
||||
struct bnxt_re_ah {
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct ib_ah ib_ah;
|
||||
struct bnxt_qplib_ah qplib_ah;
|
||||
};
|
||||
|
||||
struct bnxt_re_qp {
|
||||
struct list_head list;
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct ib_qp ib_qp;
|
||||
spinlock_t sq_lock; /* protect sq */
|
||||
struct bnxt_qplib_qp qplib_qp;
|
||||
struct ib_umem *sumem;
|
||||
struct ib_umem *rumem;
|
||||
/* QP1 */
|
||||
u32 send_psn;
|
||||
struct ib_ud_header qp1_hdr;
|
||||
};
|
||||
|
||||
struct bnxt_re_cq {
|
||||
struct bnxt_re_dev *rdev;
|
||||
spinlock_t cq_lock; /* protect cq */
|
||||
u16 cq_count;
|
||||
u16 cq_period;
|
||||
struct ib_cq ib_cq;
|
||||
struct bnxt_qplib_cq qplib_cq;
|
||||
struct bnxt_qplib_cqe *cql;
|
||||
#define MAX_CQL_PER_POLL 1024
|
||||
u32 max_cql;
|
||||
struct ib_umem *umem;
|
||||
};
|
||||
|
||||
struct bnxt_re_mr {
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct ib_mr ib_mr;
|
||||
struct ib_umem *ib_umem;
|
||||
struct bnxt_qplib_mrw qplib_mr;
|
||||
u32 npages;
|
||||
u64 *pages;
|
||||
struct bnxt_qplib_frpl qplib_frpl;
|
||||
};
|
||||
|
||||
struct bnxt_re_frpl {
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct bnxt_qplib_frpl qplib_frpl;
|
||||
u64 *page_list;
|
||||
};
|
||||
|
||||
struct bnxt_re_fmr {
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct ib_fmr ib_fmr;
|
||||
struct bnxt_qplib_mrw qplib_fmr;
|
||||
};
|
||||
|
||||
struct bnxt_re_mw {
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct ib_mw ib_mw;
|
||||
struct bnxt_qplib_mrw qplib_mw;
|
||||
};
|
||||
|
||||
struct bnxt_re_ucontext {
|
||||
struct bnxt_re_dev *rdev;
|
||||
struct ib_ucontext ib_uctx;
|
||||
struct bnxt_qplib_dpi *dpi;
|
||||
void *shpg;
|
||||
spinlock_t sh_lock; /* protect shpg */
|
||||
};
|
||||
|
||||
struct net_device *bnxt_re_get_netdev(struct ib_device *ibdev, u8 port_num);
|
||||
|
||||
int bnxt_re_query_device(struct ib_device *ibdev,
|
||||
struct ib_device_attr *ib_attr,
|
||||
struct ib_udata *udata);
|
||||
int bnxt_re_modify_device(struct ib_device *ibdev,
|
||||
int device_modify_mask,
|
||||
struct ib_device_modify *device_modify);
|
||||
int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num,
|
||||
struct ib_port_attr *port_attr);
|
||||
int bnxt_re_modify_port(struct ib_device *ibdev, u8 port_num,
|
||||
int port_modify_mask,
|
||||
struct ib_port_modify *port_modify);
|
||||
int bnxt_re_get_port_immutable(struct ib_device *ibdev, u8 port_num,
|
||||
struct ib_port_immutable *immutable);
|
||||
int bnxt_re_query_pkey(struct ib_device *ibdev, u8 port_num,
|
||||
u16 index, u16 *pkey);
|
||||
int bnxt_re_del_gid(struct ib_device *ibdev, u8 port_num,
|
||||
unsigned int index, void **context);
|
||||
int bnxt_re_add_gid(struct ib_device *ibdev, u8 port_num,
|
||||
unsigned int index, const union ib_gid *gid,
|
||||
const struct ib_gid_attr *attr, void **context);
|
||||
int bnxt_re_query_gid(struct ib_device *ibdev, u8 port_num,
|
||||
int index, union ib_gid *gid);
|
||||
enum rdma_link_layer bnxt_re_get_link_layer(struct ib_device *ibdev,
|
||||
u8 port_num);
|
||||
struct ib_pd *bnxt_re_alloc_pd(struct ib_device *ibdev,
|
||||
struct ib_ucontext *context,
|
||||
struct ib_udata *udata);
|
||||
int bnxt_re_dealloc_pd(struct ib_pd *pd);
|
||||
struct ib_ah *bnxt_re_create_ah(struct ib_pd *pd,
|
||||
struct ib_ah_attr *ah_attr,
|
||||
struct ib_udata *udata);
|
||||
int bnxt_re_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
|
||||
int bnxt_re_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
|
||||
int bnxt_re_destroy_ah(struct ib_ah *ah);
|
||||
struct ib_qp *bnxt_re_create_qp(struct ib_pd *pd,
|
||||
struct ib_qp_init_attr *qp_init_attr,
|
||||
struct ib_udata *udata);
|
||||
int bnxt_re_modify_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
|
||||
int qp_attr_mask, struct ib_udata *udata);
|
||||
int bnxt_re_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
|
||||
int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
|
||||
int bnxt_re_destroy_qp(struct ib_qp *qp);
|
||||
int bnxt_re_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr,
|
||||
struct ib_send_wr **bad_send_wr);
|
||||
int bnxt_re_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
|
||||
struct ib_recv_wr **bad_recv_wr);
|
||||
struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
|
||||
const struct ib_cq_init_attr *attr,
|
||||
struct ib_ucontext *context,
|
||||
struct ib_udata *udata);
|
||||
int bnxt_re_destroy_cq(struct ib_cq *cq);
|
||||
int bnxt_re_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
|
||||
int bnxt_re_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
|
||||
struct ib_mr *bnxt_re_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
|
||||
|
||||
int bnxt_re_map_mr_sg(struct ib_mr *ib_mr, struct scatterlist *sg, int sg_nents,
|
||||
unsigned int *sg_offset);
|
||||
struct ib_mr *bnxt_re_alloc_mr(struct ib_pd *ib_pd, enum ib_mr_type mr_type,
|
||||
u32 max_num_sg);
|
||||
int bnxt_re_dereg_mr(struct ib_mr *mr);
|
||||
struct ib_fmr *bnxt_re_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
|
||||
struct ib_fmr_attr *fmr_attr);
|
||||
int bnxt_re_map_phys_fmr(struct ib_fmr *fmr, u64 *page_list, int list_len,
|
||||
u64 iova);
|
||||
int bnxt_re_unmap_fmr(struct list_head *fmr_list);
|
||||
int bnxt_re_dealloc_fmr(struct ib_fmr *fmr);
|
||||
struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
|
||||
u64 virt_addr, int mr_access_flags,
|
||||
struct ib_udata *udata);
|
||||
struct ib_ucontext *bnxt_re_alloc_ucontext(struct ib_device *ibdev,
|
||||
struct ib_udata *udata);
|
||||
int bnxt_re_dealloc_ucontext(struct ib_ucontext *context);
|
||||
int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
|
||||
#endif /* __BNXT_RE_IB_VERBS_H__ */
|
1315
drivers/infiniband/hw/bnxt_re/main.c
Normal file
1315
drivers/infiniband/hw/bnxt_re/main.c
Normal file
File diff suppressed because it is too large
Load Diff
2167
drivers/infiniband/hw/bnxt_re/qplib_fp.c
Normal file
2167
drivers/infiniband/hw/bnxt_re/qplib_fp.c
Normal file
File diff suppressed because it is too large
Load Diff
439
drivers/infiniband/hw/bnxt_re/qplib_fp.h
Normal file
439
drivers/infiniband/hw/bnxt_re/qplib_fp.h
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: Fast Path Operators (header)
|
||||
*/
|
||||
|
||||
#ifndef __BNXT_QPLIB_FP_H__
|
||||
#define __BNXT_QPLIB_FP_H__
|
||||
|
||||
struct bnxt_qplib_sge {
|
||||
u64 addr;
|
||||
u32 lkey;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
#define BNXT_QPLIB_MAX_SQE_ENTRY_SIZE sizeof(struct sq_send)
|
||||
|
||||
#define SQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_MAX_SQE_ENTRY_SIZE)
|
||||
#define SQE_MAX_IDX_PER_PG (SQE_CNT_PER_PG - 1)
|
||||
|
||||
static inline u32 get_sqe_pg(u32 val)
|
||||
{
|
||||
return ((val & ~SQE_MAX_IDX_PER_PG) / SQE_CNT_PER_PG);
|
||||
}
|
||||
|
||||
static inline u32 get_sqe_idx(u32 val)
|
||||
{
|
||||
return (val & SQE_MAX_IDX_PER_PG);
|
||||
}
|
||||
|
||||
#define BNXT_QPLIB_MAX_PSNE_ENTRY_SIZE sizeof(struct sq_psn_search)
|
||||
|
||||
#define PSNE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_MAX_PSNE_ENTRY_SIZE)
|
||||
#define PSNE_MAX_IDX_PER_PG (PSNE_CNT_PER_PG - 1)
|
||||
|
||||
static inline u32 get_psne_pg(u32 val)
|
||||
{
|
||||
return ((val & ~PSNE_MAX_IDX_PER_PG) / PSNE_CNT_PER_PG);
|
||||
}
|
||||
|
||||
static inline u32 get_psne_idx(u32 val)
|
||||
{
|
||||
return (val & PSNE_MAX_IDX_PER_PG);
|
||||
}
|
||||
|
||||
#define BNXT_QPLIB_QP_MAX_SGL 6
|
||||
|
||||
struct bnxt_qplib_swq {
|
||||
u64 wr_id;
|
||||
u8 type;
|
||||
u8 flags;
|
||||
u32 start_psn;
|
||||
u32 next_psn;
|
||||
struct sq_psn_search *psn_search;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_swqe {
|
||||
/* General */
|
||||
u64 wr_id;
|
||||
u8 reqs_type;
|
||||
u8 type;
|
||||
#define BNXT_QPLIB_SWQE_TYPE_SEND 0
|
||||
#define BNXT_QPLIB_SWQE_TYPE_SEND_WITH_IMM 1
|
||||
#define BNXT_QPLIB_SWQE_TYPE_SEND_WITH_INV 2
|
||||
#define BNXT_QPLIB_SWQE_TYPE_RDMA_WRITE 4
|
||||
#define BNXT_QPLIB_SWQE_TYPE_RDMA_WRITE_WITH_IMM 5
|
||||
#define BNXT_QPLIB_SWQE_TYPE_RDMA_READ 6
|
||||
#define BNXT_QPLIB_SWQE_TYPE_ATOMIC_CMP_AND_SWP 8
|
||||
#define BNXT_QPLIB_SWQE_TYPE_ATOMIC_FETCH_AND_ADD 11
|
||||
#define BNXT_QPLIB_SWQE_TYPE_LOCAL_INV 12
|
||||
#define BNXT_QPLIB_SWQE_TYPE_FAST_REG_MR 13
|
||||
#define BNXT_QPLIB_SWQE_TYPE_REG_MR 13
|
||||
#define BNXT_QPLIB_SWQE_TYPE_BIND_MW 14
|
||||
#define BNXT_QPLIB_SWQE_TYPE_RECV 128
|
||||
#define BNXT_QPLIB_SWQE_TYPE_RECV_RDMA_IMM 129
|
||||
u8 flags;
|
||||
#define BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP BIT(0)
|
||||
#define BNXT_QPLIB_SWQE_FLAGS_RD_ATOMIC_FENCE BIT(1)
|
||||
#define BNXT_QPLIB_SWQE_FLAGS_UC_FENCE BIT(2)
|
||||
#define BNXT_QPLIB_SWQE_FLAGS_SOLICIT_EVENT BIT(3)
|
||||
#define BNXT_QPLIB_SWQE_FLAGS_INLINE BIT(4)
|
||||
struct bnxt_qplib_sge sg_list[BNXT_QPLIB_QP_MAX_SGL];
|
||||
int num_sge;
|
||||
/* Max inline data is 96 bytes */
|
||||
u32 inline_len;
|
||||
#define BNXT_QPLIB_SWQE_MAX_INLINE_LENGTH 96
|
||||
u8 inline_data[BNXT_QPLIB_SWQE_MAX_INLINE_LENGTH];
|
||||
|
||||
union {
|
||||
/* Send, with imm, inval key */
|
||||
struct {
|
||||
union {
|
||||
__be32 imm_data;
|
||||
u32 inv_key;
|
||||
};
|
||||
u32 q_key;
|
||||
u32 dst_qp;
|
||||
u16 avid;
|
||||
} send;
|
||||
|
||||
/* Send Raw Ethernet and QP1 */
|
||||
struct {
|
||||
u16 lflags;
|
||||
u16 cfa_action;
|
||||
u32 cfa_meta;
|
||||
} rawqp1;
|
||||
|
||||
/* RDMA write, with imm, read */
|
||||
struct {
|
||||
union {
|
||||
__be32 imm_data;
|
||||
u32 inv_key;
|
||||
};
|
||||
u64 remote_va;
|
||||
u32 r_key;
|
||||
} rdma;
|
||||
|
||||
/* Atomic cmp/swap, fetch/add */
|
||||
struct {
|
||||
u64 remote_va;
|
||||
u32 r_key;
|
||||
u64 swap_data;
|
||||
u64 cmp_data;
|
||||
} atomic;
|
||||
|
||||
/* Local Invalidate */
|
||||
struct {
|
||||
u32 inv_l_key;
|
||||
} local_inv;
|
||||
|
||||
/* FR-PMR */
|
||||
struct {
|
||||
u8 access_cntl;
|
||||
u8 pg_sz_log;
|
||||
bool zero_based;
|
||||
u32 l_key;
|
||||
u32 length;
|
||||
u8 pbl_pg_sz_log;
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_4K 0
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_8K 1
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_64K 4
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_256K 6
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_1M 8
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_2M 9
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_4M 10
|
||||
#define BNXT_QPLIB_SWQE_PAGE_SIZE_1G 18
|
||||
u8 levels;
|
||||
#define PAGE_SHIFT_4K 12
|
||||
__le64 *pbl_ptr;
|
||||
dma_addr_t pbl_dma_ptr;
|
||||
u64 *page_list;
|
||||
u16 page_list_len;
|
||||
u64 va;
|
||||
} frmr;
|
||||
|
||||
/* Bind */
|
||||
struct {
|
||||
u8 access_cntl;
|
||||
#define BNXT_QPLIB_BIND_SWQE_ACCESS_LOCAL_WRITE BIT(0)
|
||||
#define BNXT_QPLIB_BIND_SWQE_ACCESS_REMOTE_READ BIT(1)
|
||||
#define BNXT_QPLIB_BIND_SWQE_ACCESS_REMOTE_WRITE BIT(2)
|
||||
#define BNXT_QPLIB_BIND_SWQE_ACCESS_REMOTE_ATOMIC BIT(3)
|
||||
#define BNXT_QPLIB_BIND_SWQE_ACCESS_WINDOW_BIND BIT(4)
|
||||
bool zero_based;
|
||||
u8 mw_type;
|
||||
u32 parent_l_key;
|
||||
u32 r_key;
|
||||
u64 va;
|
||||
u32 length;
|
||||
} bind;
|
||||
};
|
||||
};
|
||||
|
||||
#define BNXT_QPLIB_MAX_RQE_ENTRY_SIZE sizeof(struct rq_wqe)
|
||||
|
||||
#define RQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_MAX_RQE_ENTRY_SIZE)
|
||||
#define RQE_MAX_IDX_PER_PG (RQE_CNT_PER_PG - 1)
|
||||
#define RQE_PG(x) (((x) & ~RQE_MAX_IDX_PER_PG) / RQE_CNT_PER_PG)
|
||||
#define RQE_IDX(x) ((x) & RQE_MAX_IDX_PER_PG)
|
||||
|
||||
struct bnxt_qplib_q {
|
||||
struct bnxt_qplib_hwq hwq;
|
||||
struct bnxt_qplib_swq *swq;
|
||||
struct scatterlist *sglist;
|
||||
u32 nmap;
|
||||
u32 max_wqe;
|
||||
u16 max_sge;
|
||||
u32 psn;
|
||||
bool flush_in_progress;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_qp {
|
||||
struct bnxt_qplib_pd *pd;
|
||||
struct bnxt_qplib_dpi *dpi;
|
||||
u64 qp_handle;
|
||||
u32 id;
|
||||
u8 type;
|
||||
u8 sig_type;
|
||||
u32 modify_flags;
|
||||
u8 state;
|
||||
u8 cur_qp_state;
|
||||
u32 max_inline_data;
|
||||
u32 mtu;
|
||||
u8 path_mtu;
|
||||
bool en_sqd_async_notify;
|
||||
u16 pkey_index;
|
||||
u32 qkey;
|
||||
u32 dest_qp_id;
|
||||
u8 access;
|
||||
u8 timeout;
|
||||
u8 retry_cnt;
|
||||
u8 rnr_retry;
|
||||
u32 min_rnr_timer;
|
||||
u32 max_rd_atomic;
|
||||
u32 max_dest_rd_atomic;
|
||||
u32 dest_qpn;
|
||||
u8 smac[6];
|
||||
u16 vlan_id;
|
||||
u8 nw_type;
|
||||
struct bnxt_qplib_ah ah;
|
||||
|
||||
#define BTH_PSN_MASK ((1 << 24) - 1)
|
||||
/* SQ */
|
||||
struct bnxt_qplib_q sq;
|
||||
/* RQ */
|
||||
struct bnxt_qplib_q rq;
|
||||
/* SRQ */
|
||||
struct bnxt_qplib_srq *srq;
|
||||
/* CQ */
|
||||
struct bnxt_qplib_cq *scq;
|
||||
struct bnxt_qplib_cq *rcq;
|
||||
/* IRRQ and ORRQ */
|
||||
struct bnxt_qplib_hwq irrq;
|
||||
struct bnxt_qplib_hwq orrq;
|
||||
/* Header buffer for QP1 */
|
||||
int sq_hdr_buf_size;
|
||||
int rq_hdr_buf_size;
|
||||
/*
|
||||
* Buffer space for ETH(14), IP or GRH(40), UDP header(8)
|
||||
* and ib_bth + ib_deth (20).
|
||||
* Max required is 82 when RoCE V2 is enabled
|
||||
*/
|
||||
#define BNXT_QPLIB_MAX_QP1_SQ_HDR_SIZE_V2 86
|
||||
/* Ethernet header = 14 */
|
||||
/* ib_grh = 40 (provided by MAD) */
|
||||
/* ib_bth + ib_deth = 20 */
|
||||
/* MAD = 256 (provided by MAD) */
|
||||
/* iCRC = 4 */
|
||||
#define BNXT_QPLIB_MAX_QP1_RQ_ETH_HDR_SIZE 14
|
||||
#define BNXT_QPLIB_MAX_QP1_RQ_HDR_SIZE_V2 512
|
||||
#define BNXT_QPLIB_MAX_GRH_HDR_SIZE_IPV4 20
|
||||
#define BNXT_QPLIB_MAX_GRH_HDR_SIZE_IPV6 40
|
||||
#define BNXT_QPLIB_MAX_QP1_RQ_BDETH_HDR_SIZE 20
|
||||
void *sq_hdr_buf;
|
||||
dma_addr_t sq_hdr_buf_map;
|
||||
void *rq_hdr_buf;
|
||||
dma_addr_t rq_hdr_buf_map;
|
||||
};
|
||||
|
||||
#define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base)
|
||||
|
||||
#define CQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_MAX_CQE_ENTRY_SIZE)
|
||||
#define CQE_MAX_IDX_PER_PG (CQE_CNT_PER_PG - 1)
|
||||
#define CQE_PG(x) (((x) & ~CQE_MAX_IDX_PER_PG) / CQE_CNT_PER_PG)
|
||||
#define CQE_IDX(x) ((x) & CQE_MAX_IDX_PER_PG)
|
||||
|
||||
#define ROCE_CQE_CMP_V 0
|
||||
#define CQE_CMP_VALID(hdr, raw_cons, cp_bit) \
|
||||
(!!((hdr)->cqe_type_toggle & CQ_BASE_TOGGLE) == \
|
||||
!((raw_cons) & (cp_bit)))
|
||||
|
||||
struct bnxt_qplib_cqe {
|
||||
u8 status;
|
||||
u8 type;
|
||||
u8 opcode;
|
||||
u32 length;
|
||||
u64 wr_id;
|
||||
union {
|
||||
__be32 immdata;
|
||||
u32 invrkey;
|
||||
};
|
||||
u64 qp_handle;
|
||||
u64 mr_handle;
|
||||
u16 flags;
|
||||
u8 smac[6];
|
||||
u32 src_qp;
|
||||
u16 raweth_qp1_flags;
|
||||
u16 raweth_qp1_errors;
|
||||
u16 raweth_qp1_cfa_code;
|
||||
u32 raweth_qp1_flags2;
|
||||
u32 raweth_qp1_metadata;
|
||||
u8 raweth_qp1_payload_offset;
|
||||
u16 pkey_index;
|
||||
};
|
||||
|
||||
#define BNXT_QPLIB_QUEUE_START_PERIOD 0x01
|
||||
struct bnxt_qplib_cq {
|
||||
struct bnxt_qplib_dpi *dpi;
|
||||
void __iomem *dbr_base;
|
||||
u32 max_wqe;
|
||||
u32 id;
|
||||
u16 count;
|
||||
u16 period;
|
||||
struct bnxt_qplib_hwq hwq;
|
||||
u32 cnq_hw_ring_id;
|
||||
bool resize_in_progress;
|
||||
struct scatterlist *sghead;
|
||||
u32 nmap;
|
||||
u64 cq_handle;
|
||||
|
||||
#define CQ_RESIZE_WAIT_TIME_MS 500
|
||||
unsigned long flags;
|
||||
#define CQ_FLAGS_RESIZE_IN_PROG 1
|
||||
wait_queue_head_t waitq;
|
||||
};
|
||||
|
||||
#define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE sizeof(struct xrrq_irrq)
|
||||
#define BNXT_QPLIB_MAX_ORRQE_ENTRY_SIZE sizeof(struct xrrq_orrq)
|
||||
#define IRD_LIMIT_TO_IRRQ_SLOTS(x) (2 * (x) + 2)
|
||||
#define IRRQ_SLOTS_TO_IRD_LIMIT(s) (((s) >> 1) - 1)
|
||||
#define ORD_LIMIT_TO_ORRQ_SLOTS(x) ((x) + 1)
|
||||
#define ORRQ_SLOTS_TO_ORD_LIMIT(s) ((s) - 1)
|
||||
|
||||
#define BNXT_QPLIB_MAX_NQE_ENTRY_SIZE sizeof(struct nq_base)
|
||||
|
||||
#define NQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_MAX_NQE_ENTRY_SIZE)
|
||||
#define NQE_MAX_IDX_PER_PG (NQE_CNT_PER_PG - 1)
|
||||
#define NQE_PG(x) (((x) & ~NQE_MAX_IDX_PER_PG) / NQE_CNT_PER_PG)
|
||||
#define NQE_IDX(x) ((x) & NQE_MAX_IDX_PER_PG)
|
||||
|
||||
#define NQE_CMP_VALID(hdr, raw_cons, cp_bit) \
|
||||
(!!(le32_to_cpu((hdr)->info63_v[0]) & NQ_BASE_V) == \
|
||||
!((raw_cons) & (cp_bit)))
|
||||
|
||||
#define BNXT_QPLIB_NQE_MAX_CNT (128 * 1024)
|
||||
|
||||
#define NQ_CONS_PCI_BAR_REGION 2
|
||||
#define NQ_DB_KEY_CP (0x2 << CMPL_DOORBELL_KEY_SFT)
|
||||
#define NQ_DB_IDX_VALID CMPL_DOORBELL_IDX_VALID
|
||||
#define NQ_DB_IRQ_DIS CMPL_DOORBELL_MASK
|
||||
#define NQ_DB_CP_FLAGS_REARM (NQ_DB_KEY_CP | \
|
||||
NQ_DB_IDX_VALID)
|
||||
#define NQ_DB_CP_FLAGS (NQ_DB_KEY_CP | \
|
||||
NQ_DB_IDX_VALID | \
|
||||
NQ_DB_IRQ_DIS)
|
||||
#define NQ_DB_REARM(db, raw_cons, cp_bit) \
|
||||
writel(NQ_DB_CP_FLAGS_REARM | ((raw_cons) & ((cp_bit) - 1)), db)
|
||||
#define NQ_DB(db, raw_cons, cp_bit) \
|
||||
writel(NQ_DB_CP_FLAGS | ((raw_cons) & ((cp_bit) - 1)), db)
|
||||
|
||||
struct bnxt_qplib_nq {
|
||||
struct pci_dev *pdev;
|
||||
|
||||
int vector;
|
||||
int budget;
|
||||
bool requested;
|
||||
struct tasklet_struct worker;
|
||||
struct bnxt_qplib_hwq hwq;
|
||||
|
||||
u16 bar_reg;
|
||||
u16 bar_reg_off;
|
||||
u16 ring_id;
|
||||
void __iomem *bar_reg_iomem;
|
||||
|
||||
int (*cqn_handler)
|
||||
(struct bnxt_qplib_nq *nq,
|
||||
struct bnxt_qplib_cq *cq);
|
||||
int (*srqn_handler)
|
||||
(struct bnxt_qplib_nq *nq,
|
||||
void *srq,
|
||||
u8 event);
|
||||
};
|
||||
|
||||
void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq);
|
||||
int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
|
||||
int msix_vector, int bar_reg_offset,
|
||||
int (*cqn_handler)(struct bnxt_qplib_nq *nq,
|
||||
struct bnxt_qplib_cq *cq),
|
||||
int (*srqn_handler)(struct bnxt_qplib_nq *nq,
|
||||
void *srq,
|
||||
u8 event));
|
||||
int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
|
||||
int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
|
||||
int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
|
||||
int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
|
||||
int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
|
||||
void *bnxt_qplib_get_qp1_sq_buf(struct bnxt_qplib_qp *qp,
|
||||
struct bnxt_qplib_sge *sge);
|
||||
void *bnxt_qplib_get_qp1_rq_buf(struct bnxt_qplib_qp *qp,
|
||||
struct bnxt_qplib_sge *sge);
|
||||
u32 bnxt_qplib_get_rq_prod_index(struct bnxt_qplib_qp *qp);
|
||||
dma_addr_t bnxt_qplib_get_qp_buf_from_index(struct bnxt_qplib_qp *qp,
|
||||
u32 index);
|
||||
void bnxt_qplib_post_send_db(struct bnxt_qplib_qp *qp);
|
||||
int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
|
||||
struct bnxt_qplib_swqe *wqe);
|
||||
void bnxt_qplib_post_recv_db(struct bnxt_qplib_qp *qp);
|
||||
int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
|
||||
struct bnxt_qplib_swqe *wqe);
|
||||
int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq);
|
||||
int bnxt_qplib_destroy_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq);
|
||||
int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
|
||||
int num);
|
||||
void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
|
||||
void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
|
||||
int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
|
||||
#endif /* __BNXT_QPLIB_FP_H__ */
|
694
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
Normal file
694
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
Normal file
@ -0,0 +1,694 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: RDMA Controller HW interface
|
||||
*/
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include "roce_hsi.h"
|
||||
#include "qplib_res.h"
|
||||
#include "qplib_rcfw.h"
|
||||
static void bnxt_qplib_service_creq(unsigned long data);
|
||||
|
||||
/* Hardware communication channel */
|
||||
int bnxt_qplib_rcfw_wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
|
||||
{
|
||||
u16 cbit;
|
||||
int rc;
|
||||
|
||||
cookie &= RCFW_MAX_COOKIE_VALUE;
|
||||
cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
|
||||
if (!test_bit(cbit, rcfw->cmdq_bitmap))
|
||||
dev_warn(&rcfw->pdev->dev,
|
||||
"QPLIB: CMD bit %d for cookie 0x%x is not set?",
|
||||
cbit, cookie);
|
||||
|
||||
rc = wait_event_timeout(rcfw->waitq,
|
||||
!test_bit(cbit, rcfw->cmdq_bitmap),
|
||||
msecs_to_jiffies(RCFW_CMD_WAIT_TIME_MS));
|
||||
if (!rc) {
|
||||
dev_warn(&rcfw->pdev->dev,
|
||||
"QPLIB: Bono Error: timeout %d msec, msg {0x%x}\n",
|
||||
RCFW_CMD_WAIT_TIME_MS, cookie);
|
||||
}
|
||||
|
||||
return rc;
|
||||
};
|
||||
|
||||
int bnxt_qplib_rcfw_block_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
|
||||
{
|
||||
u32 count = -1;
|
||||
u16 cbit;
|
||||
|
||||
cookie &= RCFW_MAX_COOKIE_VALUE;
|
||||
cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
|
||||
if (!test_bit(cbit, rcfw->cmdq_bitmap))
|
||||
goto done;
|
||||
do {
|
||||
bnxt_qplib_service_creq((unsigned long)rcfw);
|
||||
} while (test_bit(cbit, rcfw->cmdq_bitmap) && --count);
|
||||
done:
|
||||
return count;
|
||||
};
|
||||
|
||||
void *bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct cmdq_base *req, void **crsbe,
|
||||
u8 is_block)
|
||||
{
|
||||
struct bnxt_qplib_crsq *crsq = &rcfw->crsq;
|
||||
struct bnxt_qplib_cmdqe *cmdqe, **cmdq_ptr;
|
||||
struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq;
|
||||
struct bnxt_qplib_hwq *crsb = &rcfw->crsb;
|
||||
struct bnxt_qplib_crsqe *crsqe = NULL;
|
||||
struct bnxt_qplib_crsbe **crsb_ptr;
|
||||
u32 sw_prod, cmdq_prod;
|
||||
u8 retry_cnt = 0xFF;
|
||||
dma_addr_t dma_addr;
|
||||
unsigned long flags;
|
||||
u32 size, opcode;
|
||||
u16 cookie, cbit;
|
||||
int pg, idx;
|
||||
u8 *preq;
|
||||
|
||||
retry:
|
||||
opcode = req->opcode;
|
||||
if (!test_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags) &&
|
||||
(opcode != CMDQ_BASE_OPCODE_QUERY_FUNC &&
|
||||
opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW)) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: RCFW not initialized, reject opcode 0x%x",
|
||||
opcode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (test_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags) &&
|
||||
opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: RCFW already initialized!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Cmdq are in 16-byte units, each request can consume 1 or more
|
||||
* cmdqe
|
||||
*/
|
||||
spin_lock_irqsave(&cmdq->lock, flags);
|
||||
if (req->cmd_size > cmdq->max_elements -
|
||||
((HWQ_CMP(cmdq->prod, cmdq) - HWQ_CMP(cmdq->cons, cmdq)) &
|
||||
(cmdq->max_elements - 1))) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: RCFW: CMDQ is full!");
|
||||
spin_unlock_irqrestore(&cmdq->lock, flags);
|
||||
|
||||
if (!retry_cnt--)
|
||||
return NULL;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
retry_cnt = 0xFF;
|
||||
|
||||
cookie = atomic_inc_return(&rcfw->seq_num) & RCFW_MAX_COOKIE_VALUE;
|
||||
cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
|
||||
if (is_block)
|
||||
cookie |= RCFW_CMD_IS_BLOCKING;
|
||||
req->cookie = cpu_to_le16(cookie);
|
||||
if (test_and_set_bit(cbit, rcfw->cmdq_bitmap)) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: RCFW MAX outstanding cmd reached!");
|
||||
atomic_dec(&rcfw->seq_num);
|
||||
spin_unlock_irqrestore(&cmdq->lock, flags);
|
||||
|
||||
if (!retry_cnt--)
|
||||
return NULL;
|
||||
goto retry;
|
||||
}
|
||||
/* Reserve a resp buffer slot if requested */
|
||||
if (req->resp_size && crsbe) {
|
||||
spin_lock(&crsb->lock);
|
||||
sw_prod = HWQ_CMP(crsb->prod, crsb);
|
||||
crsb_ptr = (struct bnxt_qplib_crsbe **)crsb->pbl_ptr;
|
||||
*crsbe = (void *)&crsb_ptr[get_crsb_pg(sw_prod)]
|
||||
[get_crsb_idx(sw_prod)];
|
||||
bnxt_qplib_crsb_dma_next(crsb->pbl_dma_ptr, sw_prod, &dma_addr);
|
||||
req->resp_addr = cpu_to_le64(dma_addr);
|
||||
crsb->prod++;
|
||||
spin_unlock(&crsb->lock);
|
||||
|
||||
req->resp_size = (sizeof(struct bnxt_qplib_crsbe) +
|
||||
BNXT_QPLIB_CMDQE_UNITS - 1) /
|
||||
BNXT_QPLIB_CMDQE_UNITS;
|
||||
}
|
||||
cmdq_ptr = (struct bnxt_qplib_cmdqe **)cmdq->pbl_ptr;
|
||||
preq = (u8 *)req;
|
||||
size = req->cmd_size * BNXT_QPLIB_CMDQE_UNITS;
|
||||
do {
|
||||
pg = 0;
|
||||
idx = 0;
|
||||
|
||||
/* Locate the next cmdq slot */
|
||||
sw_prod = HWQ_CMP(cmdq->prod, cmdq);
|
||||
cmdqe = &cmdq_ptr[get_cmdq_pg(sw_prod)][get_cmdq_idx(sw_prod)];
|
||||
if (!cmdqe) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: RCFW request failed with no cmdqe!");
|
||||
goto done;
|
||||
}
|
||||
/* Copy a segment of the req cmd to the cmdq */
|
||||
memset(cmdqe, 0, sizeof(*cmdqe));
|
||||
memcpy(cmdqe, preq, min_t(u32, size, sizeof(*cmdqe)));
|
||||
preq += min_t(u32, size, sizeof(*cmdqe));
|
||||
size -= min_t(u32, size, sizeof(*cmdqe));
|
||||
cmdq->prod++;
|
||||
} while (size > 0);
|
||||
|
||||
cmdq_prod = cmdq->prod;
|
||||
if (rcfw->flags & FIRMWARE_FIRST_FLAG) {
|
||||
/* The very first doorbell write is required to set this flag
|
||||
* which prompts the FW to reset its internal pointers
|
||||
*/
|
||||
cmdq_prod |= FIRMWARE_FIRST_FLAG;
|
||||
rcfw->flags &= ~FIRMWARE_FIRST_FLAG;
|
||||
}
|
||||
sw_prod = HWQ_CMP(crsq->prod, crsq);
|
||||
crsqe = &crsq->crsq[sw_prod];
|
||||
memset(crsqe, 0, sizeof(*crsqe));
|
||||
crsq->prod++;
|
||||
crsqe->req_size = req->cmd_size;
|
||||
|
||||
/* ring CMDQ DB */
|
||||
writel(cmdq_prod, rcfw->cmdq_bar_reg_iomem +
|
||||
rcfw->cmdq_bar_reg_prod_off);
|
||||
writel(RCFW_CMDQ_TRIG_VAL, rcfw->cmdq_bar_reg_iomem +
|
||||
rcfw->cmdq_bar_reg_trig_off);
|
||||
done:
|
||||
spin_unlock_irqrestore(&cmdq->lock, flags);
|
||||
/* Return the CREQ response pointer */
|
||||
return crsqe ? &crsqe->qp_event : NULL;
|
||||
}
|
||||
|
||||
/* Completions */
|
||||
static int bnxt_qplib_process_func_event(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct creq_func_event *func_event)
|
||||
{
|
||||
switch (func_event->event) {
|
||||
case CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_CQ_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_TQM_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_CFCS_ERROR:
|
||||
/* SRQ ctx error, call srq_handler??
|
||||
* But there's no SRQ handle!
|
||||
*/
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_CFCC_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_CFCM_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_TIM_ERROR:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_VF_COMM_REQUEST:
|
||||
break;
|
||||
case CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct creq_qp_event *qp_event)
|
||||
{
|
||||
struct bnxt_qplib_crsq *crsq = &rcfw->crsq;
|
||||
struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq;
|
||||
struct bnxt_qplib_crsqe *crsqe;
|
||||
u16 cbit, cookie, blocked = 0;
|
||||
unsigned long flags;
|
||||
u32 sw_cons;
|
||||
|
||||
switch (qp_event->event) {
|
||||
case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
|
||||
dev_dbg(&rcfw->pdev->dev,
|
||||
"QPLIB: Received QP error notification");
|
||||
break;
|
||||
default:
|
||||
/* Command Response */
|
||||
spin_lock_irqsave(&cmdq->lock, flags);
|
||||
sw_cons = HWQ_CMP(crsq->cons, crsq);
|
||||
crsqe = &crsq->crsq[sw_cons];
|
||||
crsq->cons++;
|
||||
memcpy(&crsqe->qp_event, qp_event, sizeof(crsqe->qp_event));
|
||||
|
||||
cookie = le16_to_cpu(crsqe->qp_event.cookie);
|
||||
blocked = cookie & RCFW_CMD_IS_BLOCKING;
|
||||
cookie &= RCFW_MAX_COOKIE_VALUE;
|
||||
cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
|
||||
if (!test_and_clear_bit(cbit, rcfw->cmdq_bitmap))
|
||||
dev_warn(&rcfw->pdev->dev,
|
||||
"QPLIB: CMD bit %d was not requested", cbit);
|
||||
|
||||
cmdq->cons += crsqe->req_size;
|
||||
spin_unlock_irqrestore(&cmdq->lock, flags);
|
||||
if (!blocked)
|
||||
wake_up(&rcfw->waitq);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SP - CREQ Completion handlers */
|
||||
static void bnxt_qplib_service_creq(unsigned long data)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = (struct bnxt_qplib_rcfw *)data;
|
||||
struct bnxt_qplib_hwq *creq = &rcfw->creq;
|
||||
struct creq_base *creqe, **creq_ptr;
|
||||
u32 sw_cons, raw_cons;
|
||||
unsigned long flags;
|
||||
u32 type;
|
||||
|
||||
/* Service the CREQ until empty */
|
||||
spin_lock_irqsave(&creq->lock, flags);
|
||||
raw_cons = creq->cons;
|
||||
while (1) {
|
||||
sw_cons = HWQ_CMP(raw_cons, creq);
|
||||
creq_ptr = (struct creq_base **)creq->pbl_ptr;
|
||||
creqe = &creq_ptr[get_creq_pg(sw_cons)][get_creq_idx(sw_cons)];
|
||||
if (!CREQ_CMP_VALID(creqe, raw_cons, creq->max_elements))
|
||||
break;
|
||||
|
||||
type = creqe->type & CREQ_BASE_TYPE_MASK;
|
||||
switch (type) {
|
||||
case CREQ_BASE_TYPE_QP_EVENT:
|
||||
if (!bnxt_qplib_process_qp_event
|
||||
(rcfw, (struct creq_qp_event *)creqe))
|
||||
rcfw->creq_qp_event_processed++;
|
||||
else {
|
||||
dev_warn(&rcfw->pdev->dev, "QPLIB: crsqe with");
|
||||
dev_warn(&rcfw->pdev->dev,
|
||||
"QPLIB: type = 0x%x not handled",
|
||||
type);
|
||||
}
|
||||
break;
|
||||
case CREQ_BASE_TYPE_FUNC_EVENT:
|
||||
if (!bnxt_qplib_process_func_event
|
||||
(rcfw, (struct creq_func_event *)creqe))
|
||||
rcfw->creq_func_event_processed++;
|
||||
else
|
||||
dev_warn
|
||||
(&rcfw->pdev->dev, "QPLIB:aeqe:%#x Not handled",
|
||||
type);
|
||||
break;
|
||||
default:
|
||||
dev_warn(&rcfw->pdev->dev, "QPLIB: creqe with ");
|
||||
dev_warn(&rcfw->pdev->dev,
|
||||
"QPLIB: op_event = 0x%x not handled", type);
|
||||
break;
|
||||
}
|
||||
raw_cons++;
|
||||
}
|
||||
if (creq->cons != raw_cons) {
|
||||
creq->cons = raw_cons;
|
||||
CREQ_DB_REARM(rcfw->creq_bar_reg_iomem, raw_cons,
|
||||
creq->max_elements);
|
||||
}
|
||||
spin_unlock_irqrestore(&creq->lock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t bnxt_qplib_creq_irq(int irq, void *dev_instance)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = dev_instance;
|
||||
struct bnxt_qplib_hwq *creq = &rcfw->creq;
|
||||
struct creq_base **creq_ptr;
|
||||
u32 sw_cons;
|
||||
|
||||
/* Prefetch the CREQ element */
|
||||
sw_cons = HWQ_CMP(creq->cons, creq);
|
||||
creq_ptr = (struct creq_base **)rcfw->creq.pbl_ptr;
|
||||
prefetch(&creq_ptr[get_creq_pg(sw_cons)][get_creq_idx(sw_cons)]);
|
||||
|
||||
tasklet_schedule(&rcfw->worker);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* RCFW */
|
||||
int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw)
|
||||
{
|
||||
struct creq_deinitialize_fw_resp *resp;
|
||||
struct cmdq_deinitialize_fw req;
|
||||
u16 cmd_flags = 0;
|
||||
|
||||
RCFW_CMD_PREP(req, DEINITIALIZE_FW, cmd_flags);
|
||||
resp = (struct creq_deinitialize_fw_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, 0);
|
||||
if (!resp)
|
||||
return -EINVAL;
|
||||
|
||||
if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie)))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie))
|
||||
return -EFAULT;
|
||||
|
||||
clear_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __get_pbl_pg_idx(struct bnxt_qplib_pbl *pbl)
|
||||
{
|
||||
return (pbl->pg_size == ROCE_PG_SIZE_4K ?
|
||||
CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_4K :
|
||||
pbl->pg_size == ROCE_PG_SIZE_8K ?
|
||||
CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_8K :
|
||||
pbl->pg_size == ROCE_PG_SIZE_64K ?
|
||||
CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_64K :
|
||||
pbl->pg_size == ROCE_PG_SIZE_2M ?
|
||||
CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_2M :
|
||||
pbl->pg_size == ROCE_PG_SIZE_8M ?
|
||||
CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_8M :
|
||||
pbl->pg_size == ROCE_PG_SIZE_1G ?
|
||||
CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_1G :
|
||||
CMDQ_INITIALIZE_FW_QPC_PG_SIZE_PG_4K);
|
||||
}
|
||||
|
||||
int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct bnxt_qplib_ctx *ctx, int is_virtfn)
|
||||
{
|
||||
struct creq_initialize_fw_resp *resp;
|
||||
struct cmdq_initialize_fw req;
|
||||
u16 cmd_flags = 0, level;
|
||||
|
||||
RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags);
|
||||
|
||||
/*
|
||||
* VFs need not setup the HW context area, PF
|
||||
* shall setup this area for VF. Skipping the
|
||||
* HW programming
|
||||
*/
|
||||
if (is_virtfn)
|
||||
goto skip_ctx_setup;
|
||||
|
||||
level = ctx->qpc_tbl.level;
|
||||
req.qpc_pg_size_qpc_lvl = (level << CMDQ_INITIALIZE_FW_QPC_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->qpc_tbl.pbl[level]);
|
||||
level = ctx->mrw_tbl.level;
|
||||
req.mrw_pg_size_mrw_lvl = (level << CMDQ_INITIALIZE_FW_MRW_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->mrw_tbl.pbl[level]);
|
||||
level = ctx->srqc_tbl.level;
|
||||
req.srq_pg_size_srq_lvl = (level << CMDQ_INITIALIZE_FW_SRQ_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->srqc_tbl.pbl[level]);
|
||||
level = ctx->cq_tbl.level;
|
||||
req.cq_pg_size_cq_lvl = (level << CMDQ_INITIALIZE_FW_CQ_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->cq_tbl.pbl[level]);
|
||||
level = ctx->srqc_tbl.level;
|
||||
req.srq_pg_size_srq_lvl = (level << CMDQ_INITIALIZE_FW_SRQ_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->srqc_tbl.pbl[level]);
|
||||
level = ctx->cq_tbl.level;
|
||||
req.cq_pg_size_cq_lvl = (level << CMDQ_INITIALIZE_FW_CQ_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->cq_tbl.pbl[level]);
|
||||
level = ctx->tim_tbl.level;
|
||||
req.tim_pg_size_tim_lvl = (level << CMDQ_INITIALIZE_FW_TIM_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->tim_tbl.pbl[level]);
|
||||
level = ctx->tqm_pde_level;
|
||||
req.tqm_pg_size_tqm_lvl = (level << CMDQ_INITIALIZE_FW_TQM_LVL_SFT) |
|
||||
__get_pbl_pg_idx(&ctx->tqm_pde.pbl[level]);
|
||||
|
||||
req.qpc_page_dir =
|
||||
cpu_to_le64(ctx->qpc_tbl.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
req.mrw_page_dir =
|
||||
cpu_to_le64(ctx->mrw_tbl.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
req.srq_page_dir =
|
||||
cpu_to_le64(ctx->srqc_tbl.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
req.cq_page_dir =
|
||||
cpu_to_le64(ctx->cq_tbl.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
req.tim_page_dir =
|
||||
cpu_to_le64(ctx->tim_tbl.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
req.tqm_page_dir =
|
||||
cpu_to_le64(ctx->tqm_pde.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
|
||||
req.number_of_qp = cpu_to_le32(ctx->qpc_tbl.max_elements);
|
||||
req.number_of_mrw = cpu_to_le32(ctx->mrw_tbl.max_elements);
|
||||
req.number_of_srq = cpu_to_le32(ctx->srqc_tbl.max_elements);
|
||||
req.number_of_cq = cpu_to_le32(ctx->cq_tbl.max_elements);
|
||||
|
||||
req.max_qp_per_vf = cpu_to_le32(ctx->vf_res.max_qp_per_vf);
|
||||
req.max_mrw_per_vf = cpu_to_le32(ctx->vf_res.max_mrw_per_vf);
|
||||
req.max_srq_per_vf = cpu_to_le32(ctx->vf_res.max_srq_per_vf);
|
||||
req.max_cq_per_vf = cpu_to_le32(ctx->vf_res.max_cq_per_vf);
|
||||
req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf);
|
||||
|
||||
skip_ctx_setup:
|
||||
req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id);
|
||||
resp = (struct creq_initialize_fw_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, 0);
|
||||
if (!resp) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: RCFW: INITIALIZE_FW send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: RCFW: INITIALIZE_FW timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: RCFW: INITIALIZE_FW failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
set_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
|
||||
{
|
||||
bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->crsb);
|
||||
kfree(rcfw->crsq.crsq);
|
||||
bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq);
|
||||
bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq);
|
||||
|
||||
rcfw->pdev = NULL;
|
||||
}
|
||||
|
||||
int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_rcfw *rcfw)
|
||||
{
|
||||
rcfw->pdev = pdev;
|
||||
rcfw->creq.max_elements = BNXT_QPLIB_CREQE_MAX_CNT;
|
||||
if (bnxt_qplib_alloc_init_hwq(rcfw->pdev, &rcfw->creq, NULL, 0,
|
||||
&rcfw->creq.max_elements,
|
||||
BNXT_QPLIB_CREQE_UNITS, 0, PAGE_SIZE,
|
||||
HWQ_TYPE_L2_CMPL)) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: HW channel CREQ allocation failed");
|
||||
goto fail;
|
||||
}
|
||||
rcfw->cmdq.max_elements = BNXT_QPLIB_CMDQE_MAX_CNT;
|
||||
if (bnxt_qplib_alloc_init_hwq(rcfw->pdev, &rcfw->cmdq, NULL, 0,
|
||||
&rcfw->cmdq.max_elements,
|
||||
BNXT_QPLIB_CMDQE_UNITS, 0, PAGE_SIZE,
|
||||
HWQ_TYPE_CTX)) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: HW channel CMDQ allocation failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rcfw->crsq.max_elements = rcfw->cmdq.max_elements;
|
||||
rcfw->crsq.crsq = kcalloc(rcfw->crsq.max_elements,
|
||||
sizeof(*rcfw->crsq.crsq), GFP_KERNEL);
|
||||
if (!rcfw->crsq.crsq)
|
||||
goto fail;
|
||||
|
||||
rcfw->crsb.max_elements = BNXT_QPLIB_CRSBE_MAX_CNT;
|
||||
if (bnxt_qplib_alloc_init_hwq(rcfw->pdev, &rcfw->crsb, NULL, 0,
|
||||
&rcfw->crsb.max_elements,
|
||||
BNXT_QPLIB_CRSBE_UNITS, 0, PAGE_SIZE,
|
||||
HWQ_TYPE_CTX)) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: HW channel CRSB allocation failed");
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
bnxt_qplib_free_rcfw_channel(rcfw);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
|
||||
{
|
||||
unsigned long indx;
|
||||
|
||||
/* Make sure the HW channel is stopped! */
|
||||
synchronize_irq(rcfw->vector);
|
||||
tasklet_disable(&rcfw->worker);
|
||||
tasklet_kill(&rcfw->worker);
|
||||
|
||||
if (rcfw->requested) {
|
||||
free_irq(rcfw->vector, rcfw);
|
||||
rcfw->requested = false;
|
||||
}
|
||||
if (rcfw->cmdq_bar_reg_iomem)
|
||||
iounmap(rcfw->cmdq_bar_reg_iomem);
|
||||
rcfw->cmdq_bar_reg_iomem = NULL;
|
||||
|
||||
if (rcfw->creq_bar_reg_iomem)
|
||||
iounmap(rcfw->creq_bar_reg_iomem);
|
||||
rcfw->creq_bar_reg_iomem = NULL;
|
||||
|
||||
indx = find_first_bit(rcfw->cmdq_bitmap, rcfw->bmap_size);
|
||||
if (indx != rcfw->bmap_size)
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: disabling RCFW with pending cmd-bit %lx", indx);
|
||||
kfree(rcfw->cmdq_bitmap);
|
||||
rcfw->bmap_size = 0;
|
||||
|
||||
rcfw->aeq_handler = NULL;
|
||||
rcfw->vector = 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_rcfw *rcfw,
|
||||
int msix_vector,
|
||||
int cp_bar_reg_off, int virt_fn,
|
||||
int (*aeq_handler)(struct bnxt_qplib_rcfw *,
|
||||
struct creq_func_event *))
|
||||
{
|
||||
resource_size_t res_base;
|
||||
struct cmdq_init init;
|
||||
u16 bmap_size;
|
||||
int rc;
|
||||
|
||||
/* General */
|
||||
atomic_set(&rcfw->seq_num, 0);
|
||||
rcfw->flags = FIRMWARE_FIRST_FLAG;
|
||||
bmap_size = BITS_TO_LONGS(RCFW_MAX_OUTSTANDING_CMD *
|
||||
sizeof(unsigned long));
|
||||
rcfw->cmdq_bitmap = kzalloc(bmap_size, GFP_KERNEL);
|
||||
if (!rcfw->cmdq_bitmap)
|
||||
return -ENOMEM;
|
||||
rcfw->bmap_size = bmap_size;
|
||||
|
||||
/* CMDQ */
|
||||
rcfw->cmdq_bar_reg = RCFW_COMM_PCI_BAR_REGION;
|
||||
res_base = pci_resource_start(pdev, rcfw->cmdq_bar_reg);
|
||||
if (!res_base)
|
||||
return -ENOMEM;
|
||||
|
||||
rcfw->cmdq_bar_reg_iomem = ioremap_nocache(res_base +
|
||||
RCFW_COMM_BASE_OFFSET,
|
||||
RCFW_COMM_SIZE);
|
||||
if (!rcfw->cmdq_bar_reg_iomem) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: CMDQ BAR region %d mapping failed",
|
||||
rcfw->cmdq_bar_reg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rcfw->cmdq_bar_reg_prod_off = virt_fn ? RCFW_VF_COMM_PROD_OFFSET :
|
||||
RCFW_PF_COMM_PROD_OFFSET;
|
||||
|
||||
rcfw->cmdq_bar_reg_trig_off = RCFW_COMM_TRIG_OFFSET;
|
||||
|
||||
/* CRSQ */
|
||||
rcfw->crsq.prod = 0;
|
||||
rcfw->crsq.cons = 0;
|
||||
|
||||
/* CREQ */
|
||||
rcfw->creq_bar_reg = RCFW_COMM_CONS_PCI_BAR_REGION;
|
||||
res_base = pci_resource_start(pdev, rcfw->creq_bar_reg);
|
||||
if (!res_base)
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: CREQ BAR region %d resc start is 0!",
|
||||
rcfw->creq_bar_reg);
|
||||
rcfw->creq_bar_reg_iomem = ioremap_nocache(res_base + cp_bar_reg_off,
|
||||
4);
|
||||
if (!rcfw->creq_bar_reg_iomem) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: CREQ BAR region %d mapping failed",
|
||||
rcfw->creq_bar_reg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
rcfw->creq_qp_event_processed = 0;
|
||||
rcfw->creq_func_event_processed = 0;
|
||||
|
||||
rcfw->vector = msix_vector;
|
||||
if (aeq_handler)
|
||||
rcfw->aeq_handler = aeq_handler;
|
||||
|
||||
tasklet_init(&rcfw->worker, bnxt_qplib_service_creq,
|
||||
(unsigned long)rcfw);
|
||||
|
||||
rcfw->requested = false;
|
||||
rc = request_irq(rcfw->vector, bnxt_qplib_creq_irq, 0,
|
||||
"bnxt_qplib_creq", rcfw);
|
||||
if (rc) {
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: Failed to request IRQ for CREQ rc = 0x%x", rc);
|
||||
bnxt_qplib_disable_rcfw_channel(rcfw);
|
||||
return rc;
|
||||
}
|
||||
rcfw->requested = true;
|
||||
|
||||
init_waitqueue_head(&rcfw->waitq);
|
||||
|
||||
CREQ_DB_REARM(rcfw->creq_bar_reg_iomem, 0, rcfw->creq.max_elements);
|
||||
|
||||
init.cmdq_pbl = cpu_to_le64(rcfw->cmdq.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
init.cmdq_size_cmdq_lvl = cpu_to_le16(
|
||||
((BNXT_QPLIB_CMDQE_MAX_CNT << CMDQ_INIT_CMDQ_SIZE_SFT) &
|
||||
CMDQ_INIT_CMDQ_SIZE_MASK) |
|
||||
((rcfw->cmdq.level << CMDQ_INIT_CMDQ_LVL_SFT) &
|
||||
CMDQ_INIT_CMDQ_LVL_MASK));
|
||||
init.creq_ring_id = cpu_to_le16(rcfw->creq_ring_id);
|
||||
|
||||
/* Write to the Bono mailbox register */
|
||||
__iowrite32_copy(rcfw->cmdq_bar_reg_iomem, &init, sizeof(init) / 4);
|
||||
return 0;
|
||||
}
|
231
drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
Normal file
231
drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: RDMA Controller HW interface (header)
|
||||
*/
|
||||
|
||||
#ifndef __BNXT_QPLIB_RCFW_H__
|
||||
#define __BNXT_QPLIB_RCFW_H__
|
||||
|
||||
#define RCFW_CMDQ_TRIG_VAL 1
|
||||
#define RCFW_COMM_PCI_BAR_REGION 0
|
||||
#define RCFW_COMM_CONS_PCI_BAR_REGION 2
|
||||
#define RCFW_COMM_BASE_OFFSET 0x600
|
||||
#define RCFW_PF_COMM_PROD_OFFSET 0xc
|
||||
#define RCFW_VF_COMM_PROD_OFFSET 0xc
|
||||
#define RCFW_COMM_TRIG_OFFSET 0x100
|
||||
#define RCFW_COMM_SIZE 0x104
|
||||
|
||||
#define RCFW_DBR_PCI_BAR_REGION 2
|
||||
|
||||
#define RCFW_CMD_PREP(req, CMD, cmd_flags) \
|
||||
do { \
|
||||
memset(&(req), 0, sizeof((req))); \
|
||||
(req).opcode = CMDQ_BASE_OPCODE_##CMD; \
|
||||
(req).cmd_size = (sizeof((req)) + \
|
||||
BNXT_QPLIB_CMDQE_UNITS - 1) / \
|
||||
BNXT_QPLIB_CMDQE_UNITS; \
|
||||
(req).flags = cpu_to_le16(cmd_flags); \
|
||||
} while (0)
|
||||
|
||||
#define RCFW_CMD_WAIT_TIME_MS 20000 /* 20 Seconds timeout */
|
||||
|
||||
/* CMDQ elements */
|
||||
#define BNXT_QPLIB_CMDQE_MAX_CNT 256
|
||||
#define BNXT_QPLIB_CMDQE_UNITS sizeof(struct bnxt_qplib_cmdqe)
|
||||
#define BNXT_QPLIB_CMDQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_CMDQE_UNITS)
|
||||
|
||||
#define MAX_CMDQ_IDX (BNXT_QPLIB_CMDQE_MAX_CNT - 1)
|
||||
#define MAX_CMDQ_IDX_PER_PG (BNXT_QPLIB_CMDQE_CNT_PER_PG - 1)
|
||||
|
||||
#define RCFW_MAX_OUTSTANDING_CMD BNXT_QPLIB_CMDQE_MAX_CNT
|
||||
#define RCFW_MAX_COOKIE_VALUE 0x7FFF
|
||||
#define RCFW_CMD_IS_BLOCKING 0x8000
|
||||
|
||||
/* Cmdq contains a fix number of a 16-Byte slots */
|
||||
struct bnxt_qplib_cmdqe {
|
||||
u8 data[16];
|
||||
};
|
||||
|
||||
static inline u32 get_cmdq_pg(u32 val)
|
||||
{
|
||||
return (val & ~MAX_CMDQ_IDX_PER_PG) / BNXT_QPLIB_CMDQE_CNT_PER_PG;
|
||||
}
|
||||
|
||||
static inline u32 get_cmdq_idx(u32 val)
|
||||
{
|
||||
return val & MAX_CMDQ_IDX_PER_PG;
|
||||
}
|
||||
|
||||
/* Crsq buf is 1024-Byte */
|
||||
struct bnxt_qplib_crsbe {
|
||||
u8 data[1024];
|
||||
};
|
||||
|
||||
/* CRSQ SB */
|
||||
#define BNXT_QPLIB_CRSBE_MAX_CNT 4
|
||||
#define BNXT_QPLIB_CRSBE_UNITS sizeof(struct bnxt_qplib_crsbe)
|
||||
#define BNXT_QPLIB_CRSBE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_CRSBE_UNITS)
|
||||
|
||||
#define MAX_CRSB_IDX (BNXT_QPLIB_CRSBE_MAX_CNT - 1)
|
||||
#define MAX_CRSB_IDX_PER_PG (BNXT_QPLIB_CRSBE_CNT_PER_PG - 1)
|
||||
|
||||
static inline u32 get_crsb_pg(u32 val)
|
||||
{
|
||||
return (val & ~MAX_CRSB_IDX_PER_PG) / BNXT_QPLIB_CRSBE_CNT_PER_PG;
|
||||
}
|
||||
|
||||
static inline u32 get_crsb_idx(u32 val)
|
||||
{
|
||||
return val & MAX_CRSB_IDX_PER_PG;
|
||||
}
|
||||
|
||||
static inline void bnxt_qplib_crsb_dma_next(dma_addr_t *pg_map_arr,
|
||||
u32 prod, dma_addr_t *dma_addr)
|
||||
{
|
||||
*dma_addr = pg_map_arr[(prod) / BNXT_QPLIB_CRSBE_CNT_PER_PG];
|
||||
*dma_addr += ((prod) % BNXT_QPLIB_CRSBE_CNT_PER_PG) *
|
||||
BNXT_QPLIB_CRSBE_UNITS;
|
||||
}
|
||||
|
||||
/* CREQ */
|
||||
/* Allocate 1 per QP for async error notification for now */
|
||||
#define BNXT_QPLIB_CREQE_MAX_CNT (64 * 1024)
|
||||
#define BNXT_QPLIB_CREQE_UNITS 16 /* 16-Bytes per prod unit */
|
||||
#define BNXT_QPLIB_CREQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_CREQE_UNITS)
|
||||
|
||||
#define MAX_CREQ_IDX (BNXT_QPLIB_CREQE_MAX_CNT - 1)
|
||||
#define MAX_CREQ_IDX_PER_PG (BNXT_QPLIB_CREQE_CNT_PER_PG - 1)
|
||||
|
||||
static inline u32 get_creq_pg(u32 val)
|
||||
{
|
||||
return (val & ~MAX_CREQ_IDX_PER_PG) / BNXT_QPLIB_CREQE_CNT_PER_PG;
|
||||
}
|
||||
|
||||
static inline u32 get_creq_idx(u32 val)
|
||||
{
|
||||
return val & MAX_CREQ_IDX_PER_PG;
|
||||
}
|
||||
|
||||
#define BNXT_QPLIB_CREQE_PER_PG (PAGE_SIZE / sizeof(struct creq_base))
|
||||
|
||||
#define CREQ_CMP_VALID(hdr, raw_cons, cp_bit) \
|
||||
(!!((hdr)->v & CREQ_BASE_V) == \
|
||||
!((raw_cons) & (cp_bit)))
|
||||
|
||||
#define CREQ_DB_KEY_CP (0x2 << CMPL_DOORBELL_KEY_SFT)
|
||||
#define CREQ_DB_IDX_VALID CMPL_DOORBELL_IDX_VALID
|
||||
#define CREQ_DB_IRQ_DIS CMPL_DOORBELL_MASK
|
||||
#define CREQ_DB_CP_FLAGS_REARM (CREQ_DB_KEY_CP | \
|
||||
CREQ_DB_IDX_VALID)
|
||||
#define CREQ_DB_CP_FLAGS (CREQ_DB_KEY_CP | \
|
||||
CREQ_DB_IDX_VALID | \
|
||||
CREQ_DB_IRQ_DIS)
|
||||
#define CREQ_DB_REARM(db, raw_cons, cp_bit) \
|
||||
writel(CREQ_DB_CP_FLAGS_REARM | ((raw_cons) & ((cp_bit) - 1)), db)
|
||||
#define CREQ_DB(db, raw_cons, cp_bit) \
|
||||
writel(CREQ_DB_CP_FLAGS | ((raw_cons) & ((cp_bit) - 1)), db)
|
||||
|
||||
/* HWQ */
|
||||
struct bnxt_qplib_crsqe {
|
||||
struct creq_qp_event qp_event;
|
||||
u32 req_size;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_crsq {
|
||||
struct bnxt_qplib_crsqe *crsq;
|
||||
u32 prod;
|
||||
u32 cons;
|
||||
u32 max_elements;
|
||||
};
|
||||
|
||||
/* RCFW Communication Channels */
|
||||
struct bnxt_qplib_rcfw {
|
||||
struct pci_dev *pdev;
|
||||
int vector;
|
||||
struct tasklet_struct worker;
|
||||
bool requested;
|
||||
unsigned long *cmdq_bitmap;
|
||||
u32 bmap_size;
|
||||
unsigned long flags;
|
||||
#define FIRMWARE_INITIALIZED_FLAG 1
|
||||
#define FIRMWARE_FIRST_FLAG BIT(31)
|
||||
wait_queue_head_t waitq;
|
||||
int (*aeq_handler)(struct bnxt_qplib_rcfw *,
|
||||
struct creq_func_event *);
|
||||
atomic_t seq_num;
|
||||
|
||||
/* Bar region info */
|
||||
void __iomem *cmdq_bar_reg_iomem;
|
||||
u16 cmdq_bar_reg;
|
||||
u16 cmdq_bar_reg_prod_off;
|
||||
u16 cmdq_bar_reg_trig_off;
|
||||
u16 creq_ring_id;
|
||||
u16 creq_bar_reg;
|
||||
void __iomem *creq_bar_reg_iomem;
|
||||
|
||||
/* Cmd-Resp and Async Event notification queue */
|
||||
struct bnxt_qplib_hwq creq;
|
||||
u64 creq_qp_event_processed;
|
||||
u64 creq_func_event_processed;
|
||||
|
||||
/* Actual Cmd and Resp Queues */
|
||||
struct bnxt_qplib_hwq cmdq;
|
||||
struct bnxt_qplib_crsq crsq;
|
||||
struct bnxt_qplib_hwq crsb;
|
||||
};
|
||||
|
||||
void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
|
||||
int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_rcfw *rcfw);
|
||||
void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
|
||||
int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_rcfw *rcfw,
|
||||
int msix_vector,
|
||||
int cp_bar_reg_off, int virt_fn,
|
||||
int (*aeq_handler)
|
||||
(struct bnxt_qplib_rcfw *,
|
||||
struct creq_func_event *));
|
||||
|
||||
int bnxt_qplib_rcfw_block_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie);
|
||||
int bnxt_qplib_rcfw_wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie);
|
||||
void *bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct cmdq_base *req, void **crsbe,
|
||||
u8 is_block);
|
||||
|
||||
int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw);
|
||||
int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct bnxt_qplib_ctx *ctx, int is_virtfn);
|
||||
#endif /* __BNXT_QPLIB_RCFW_H__ */
|
825
drivers/infiniband/hw/bnxt_re/qplib_res.c
Normal file
825
drivers/infiniband/hw/bnxt_re/qplib_res.c
Normal file
@ -0,0 +1,825 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: QPLib resource manager
|
||||
*/
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include "roce_hsi.h"
|
||||
#include "qplib_res.h"
|
||||
#include "qplib_sp.h"
|
||||
#include "qplib_rcfw.h"
|
||||
|
||||
static void bnxt_qplib_free_stats_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_stats *stats);
|
||||
static int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_stats *stats);
|
||||
|
||||
/* PBL */
|
||||
static void __free_pbl(struct pci_dev *pdev, struct bnxt_qplib_pbl *pbl,
|
||||
bool is_umem)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!is_umem) {
|
||||
for (i = 0; i < pbl->pg_count; i++) {
|
||||
if (pbl->pg_arr[i])
|
||||
dma_free_coherent(&pdev->dev, pbl->pg_size,
|
||||
(void *)((unsigned long)
|
||||
pbl->pg_arr[i] &
|
||||
PAGE_MASK),
|
||||
pbl->pg_map_arr[i]);
|
||||
else
|
||||
dev_warn(&pdev->dev,
|
||||
"QPLIB: PBL free pg_arr[%d] empty?!",
|
||||
i);
|
||||
pbl->pg_arr[i] = NULL;
|
||||
}
|
||||
}
|
||||
kfree(pbl->pg_arr);
|
||||
pbl->pg_arr = NULL;
|
||||
kfree(pbl->pg_map_arr);
|
||||
pbl->pg_map_arr = NULL;
|
||||
pbl->pg_count = 0;
|
||||
pbl->pg_size = 0;
|
||||
}
|
||||
|
||||
static int __alloc_pbl(struct pci_dev *pdev, struct bnxt_qplib_pbl *pbl,
|
||||
struct scatterlist *sghead, u32 pages, u32 pg_size)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
bool is_umem = false;
|
||||
int i;
|
||||
|
||||
/* page ptr arrays */
|
||||
pbl->pg_arr = kcalloc(pages, sizeof(void *), GFP_KERNEL);
|
||||
if (!pbl->pg_arr)
|
||||
return -ENOMEM;
|
||||
|
||||
pbl->pg_map_arr = kcalloc(pages, sizeof(dma_addr_t), GFP_KERNEL);
|
||||
if (!pbl->pg_map_arr) {
|
||||
kfree(pbl->pg_arr);
|
||||
pbl->pg_arr = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
pbl->pg_count = 0;
|
||||
pbl->pg_size = pg_size;
|
||||
|
||||
if (!sghead) {
|
||||
for (i = 0; i < pages; i++) {
|
||||
pbl->pg_arr[i] = dma_alloc_coherent(&pdev->dev,
|
||||
pbl->pg_size,
|
||||
&pbl->pg_map_arr[i],
|
||||
GFP_KERNEL);
|
||||
if (!pbl->pg_arr[i])
|
||||
goto fail;
|
||||
memset(pbl->pg_arr[i], 0, pbl->pg_size);
|
||||
pbl->pg_count++;
|
||||
}
|
||||
} else {
|
||||
i = 0;
|
||||
is_umem = true;
|
||||
for_each_sg(sghead, sg, pages, i) {
|
||||
pbl->pg_map_arr[i] = sg_dma_address(sg);
|
||||
pbl->pg_arr[i] = sg_virt(sg);
|
||||
if (!pbl->pg_arr[i])
|
||||
goto fail;
|
||||
|
||||
pbl->pg_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
__free_pbl(pdev, pbl, is_umem);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* HWQ */
|
||||
void bnxt_qplib_free_hwq(struct pci_dev *pdev, struct bnxt_qplib_hwq *hwq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hwq->max_elements)
|
||||
return;
|
||||
if (hwq->level >= PBL_LVL_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < hwq->level + 1; i++) {
|
||||
if (i == hwq->level)
|
||||
__free_pbl(pdev, &hwq->pbl[i], hwq->is_user);
|
||||
else
|
||||
__free_pbl(pdev, &hwq->pbl[i], false);
|
||||
}
|
||||
|
||||
hwq->level = PBL_LVL_MAX;
|
||||
hwq->max_elements = 0;
|
||||
hwq->element_size = 0;
|
||||
hwq->prod = 0;
|
||||
hwq->cons = 0;
|
||||
hwq->cp_bit = 0;
|
||||
}
|
||||
|
||||
/* All HWQs are power of 2 in size */
|
||||
int bnxt_qplib_alloc_init_hwq(struct pci_dev *pdev, struct bnxt_qplib_hwq *hwq,
|
||||
struct scatterlist *sghead, int nmap,
|
||||
u32 *elements, u32 element_size, u32 aux,
|
||||
u32 pg_size, enum bnxt_qplib_hwq_type hwq_type)
|
||||
{
|
||||
u32 pages, slots, size, aux_pages = 0, aux_size = 0;
|
||||
dma_addr_t *src_phys_ptr, **dst_virt_ptr;
|
||||
int i, rc;
|
||||
|
||||
hwq->level = PBL_LVL_MAX;
|
||||
|
||||
slots = roundup_pow_of_two(*elements);
|
||||
if (aux) {
|
||||
aux_size = roundup_pow_of_two(aux);
|
||||
aux_pages = (slots * aux_size) / pg_size;
|
||||
if ((slots * aux_size) % pg_size)
|
||||
aux_pages++;
|
||||
}
|
||||
size = roundup_pow_of_two(element_size);
|
||||
|
||||
if (!sghead) {
|
||||
hwq->is_user = false;
|
||||
pages = (slots * size) / pg_size + aux_pages;
|
||||
if ((slots * size) % pg_size)
|
||||
pages++;
|
||||
if (!pages)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
hwq->is_user = true;
|
||||
pages = nmap;
|
||||
}
|
||||
|
||||
/* Alloc the 1st memory block; can be a PDL/PTL/PBL */
|
||||
if (sghead && (pages == MAX_PBL_LVL_0_PGS))
|
||||
rc = __alloc_pbl(pdev, &hwq->pbl[PBL_LVL_0], sghead,
|
||||
pages, pg_size);
|
||||
else
|
||||
rc = __alloc_pbl(pdev, &hwq->pbl[PBL_LVL_0], NULL, 1, pg_size);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
hwq->level = PBL_LVL_0;
|
||||
|
||||
if (pages > MAX_PBL_LVL_0_PGS) {
|
||||
if (pages > MAX_PBL_LVL_1_PGS) {
|
||||
/* 2 levels of indirection */
|
||||
rc = __alloc_pbl(pdev, &hwq->pbl[PBL_LVL_1], NULL,
|
||||
MAX_PBL_LVL_1_PGS_FOR_LVL_2, pg_size);
|
||||
if (rc)
|
||||
goto fail;
|
||||
/* Fill in lvl0 PBL */
|
||||
dst_virt_ptr =
|
||||
(dma_addr_t **)hwq->pbl[PBL_LVL_0].pg_arr;
|
||||
src_phys_ptr = hwq->pbl[PBL_LVL_1].pg_map_arr;
|
||||
for (i = 0; i < hwq->pbl[PBL_LVL_1].pg_count; i++)
|
||||
dst_virt_ptr[PTR_PG(i)][PTR_IDX(i)] =
|
||||
src_phys_ptr[i] | PTU_PDE_VALID;
|
||||
hwq->level = PBL_LVL_1;
|
||||
|
||||
rc = __alloc_pbl(pdev, &hwq->pbl[PBL_LVL_2], sghead,
|
||||
pages, pg_size);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
/* Fill in lvl1 PBL */
|
||||
dst_virt_ptr =
|
||||
(dma_addr_t **)hwq->pbl[PBL_LVL_1].pg_arr;
|
||||
src_phys_ptr = hwq->pbl[PBL_LVL_2].pg_map_arr;
|
||||
for (i = 0; i < hwq->pbl[PBL_LVL_2].pg_count; i++) {
|
||||
dst_virt_ptr[PTR_PG(i)][PTR_IDX(i)] =
|
||||
src_phys_ptr[i] | PTU_PTE_VALID;
|
||||
}
|
||||
if (hwq_type == HWQ_TYPE_QUEUE) {
|
||||
/* Find the last pg of the size */
|
||||
i = hwq->pbl[PBL_LVL_2].pg_count;
|
||||
dst_virt_ptr[PTR_PG(i - 1)][PTR_IDX(i - 1)] |=
|
||||
PTU_PTE_LAST;
|
||||
if (i > 1)
|
||||
dst_virt_ptr[PTR_PG(i - 2)]
|
||||
[PTR_IDX(i - 2)] |=
|
||||
PTU_PTE_NEXT_TO_LAST;
|
||||
}
|
||||
hwq->level = PBL_LVL_2;
|
||||
} else {
|
||||
u32 flag = hwq_type == HWQ_TYPE_L2_CMPL ? 0 :
|
||||
PTU_PTE_VALID;
|
||||
|
||||
/* 1 level of indirection */
|
||||
rc = __alloc_pbl(pdev, &hwq->pbl[PBL_LVL_1], sghead,
|
||||
pages, pg_size);
|
||||
if (rc)
|
||||
goto fail;
|
||||
/* Fill in lvl0 PBL */
|
||||
dst_virt_ptr =
|
||||
(dma_addr_t **)hwq->pbl[PBL_LVL_0].pg_arr;
|
||||
src_phys_ptr = hwq->pbl[PBL_LVL_1].pg_map_arr;
|
||||
for (i = 0; i < hwq->pbl[PBL_LVL_1].pg_count; i++) {
|
||||
dst_virt_ptr[PTR_PG(i)][PTR_IDX(i)] =
|
||||
src_phys_ptr[i] | flag;
|
||||
}
|
||||
if (hwq_type == HWQ_TYPE_QUEUE) {
|
||||
/* Find the last pg of the size */
|
||||
i = hwq->pbl[PBL_LVL_1].pg_count;
|
||||
dst_virt_ptr[PTR_PG(i - 1)][PTR_IDX(i - 1)] |=
|
||||
PTU_PTE_LAST;
|
||||
if (i > 1)
|
||||
dst_virt_ptr[PTR_PG(i - 2)]
|
||||
[PTR_IDX(i - 2)] |=
|
||||
PTU_PTE_NEXT_TO_LAST;
|
||||
}
|
||||
hwq->level = PBL_LVL_1;
|
||||
}
|
||||
}
|
||||
hwq->pdev = pdev;
|
||||
spin_lock_init(&hwq->lock);
|
||||
hwq->prod = 0;
|
||||
hwq->cons = 0;
|
||||
*elements = hwq->max_elements = slots;
|
||||
hwq->element_size = size;
|
||||
|
||||
/* For direct access to the elements */
|
||||
hwq->pbl_ptr = hwq->pbl[hwq->level].pg_arr;
|
||||
hwq->pbl_dma_ptr = hwq->pbl[hwq->level].pg_map_arr;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
bnxt_qplib_free_hwq(pdev, hwq);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Context Tables */
|
||||
void bnxt_qplib_free_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_ctx *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
bnxt_qplib_free_hwq(pdev, &ctx->qpc_tbl);
|
||||
bnxt_qplib_free_hwq(pdev, &ctx->mrw_tbl);
|
||||
bnxt_qplib_free_hwq(pdev, &ctx->srqc_tbl);
|
||||
bnxt_qplib_free_hwq(pdev, &ctx->cq_tbl);
|
||||
bnxt_qplib_free_hwq(pdev, &ctx->tim_tbl);
|
||||
for (i = 0; i < MAX_TQM_ALLOC_REQ; i++)
|
||||
bnxt_qplib_free_hwq(pdev, &ctx->tqm_tbl[i]);
|
||||
bnxt_qplib_free_hwq(pdev, &ctx->tqm_pde);
|
||||
bnxt_qplib_free_stats_ctx(pdev, &ctx->stats);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine: bnxt_qplib_alloc_ctx
|
||||
* Description:
|
||||
* Context tables are memories which are used by the chip fw.
|
||||
* The 6 tables defined are:
|
||||
* QPC ctx - holds QP states
|
||||
* MRW ctx - holds memory region and window
|
||||
* SRQ ctx - holds shared RQ states
|
||||
* CQ ctx - holds completion queue states
|
||||
* TQM ctx - holds Tx Queue Manager context
|
||||
* TIM ctx - holds timer context
|
||||
* Depending on the size of the tbl requested, either a 1 Page Buffer List
|
||||
* or a 1-to-2-stage indirection Page Directory List + 1 PBL is used
|
||||
* instead.
|
||||
* Table might be employed as follows:
|
||||
* For 0 < ctx size <= 1 PAGE, 0 level of ind is used
|
||||
* For 1 PAGE < ctx size <= 512 entries size, 1 level of ind is used
|
||||
* For 512 < ctx size <= MAX, 2 levels of ind is used
|
||||
* Returns:
|
||||
* 0 if success, else -ERRORS
|
||||
*/
|
||||
int bnxt_qplib_alloc_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_ctx *ctx,
|
||||
bool virt_fn)
|
||||
{
|
||||
int i, j, k, rc = 0;
|
||||
int fnz_idx = -1;
|
||||
__le64 **pbl_ptr;
|
||||
|
||||
if (virt_fn)
|
||||
goto stats_alloc;
|
||||
|
||||
/* QPC Tables */
|
||||
ctx->qpc_tbl.max_elements = ctx->qpc_count;
|
||||
rc = bnxt_qplib_alloc_init_hwq(pdev, &ctx->qpc_tbl, NULL, 0,
|
||||
&ctx->qpc_tbl.max_elements,
|
||||
BNXT_QPLIB_MAX_QP_CTX_ENTRY_SIZE, 0,
|
||||
PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
/* MRW Tables */
|
||||
ctx->mrw_tbl.max_elements = ctx->mrw_count;
|
||||
rc = bnxt_qplib_alloc_init_hwq(pdev, &ctx->mrw_tbl, NULL, 0,
|
||||
&ctx->mrw_tbl.max_elements,
|
||||
BNXT_QPLIB_MAX_MRW_CTX_ENTRY_SIZE, 0,
|
||||
PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
/* SRQ Tables */
|
||||
ctx->srqc_tbl.max_elements = ctx->srqc_count;
|
||||
rc = bnxt_qplib_alloc_init_hwq(pdev, &ctx->srqc_tbl, NULL, 0,
|
||||
&ctx->srqc_tbl.max_elements,
|
||||
BNXT_QPLIB_MAX_SRQ_CTX_ENTRY_SIZE, 0,
|
||||
PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
/* CQ Tables */
|
||||
ctx->cq_tbl.max_elements = ctx->cq_count;
|
||||
rc = bnxt_qplib_alloc_init_hwq(pdev, &ctx->cq_tbl, NULL, 0,
|
||||
&ctx->cq_tbl.max_elements,
|
||||
BNXT_QPLIB_MAX_CQ_CTX_ENTRY_SIZE, 0,
|
||||
PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
/* TQM Buffer */
|
||||
ctx->tqm_pde.max_elements = 512;
|
||||
rc = bnxt_qplib_alloc_init_hwq(pdev, &ctx->tqm_pde, NULL, 0,
|
||||
&ctx->tqm_pde.max_elements, sizeof(u64),
|
||||
0, PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < MAX_TQM_ALLOC_REQ; i++) {
|
||||
if (!ctx->tqm_count[i])
|
||||
continue;
|
||||
ctx->tqm_tbl[i].max_elements = ctx->qpc_count *
|
||||
ctx->tqm_count[i];
|
||||
rc = bnxt_qplib_alloc_init_hwq(pdev, &ctx->tqm_tbl[i], NULL, 0,
|
||||
&ctx->tqm_tbl[i].max_elements, 1,
|
||||
0, PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (rc)
|
||||
goto fail;
|
||||
}
|
||||
pbl_ptr = (__le64 **)ctx->tqm_pde.pbl_ptr;
|
||||
for (i = 0, j = 0; i < MAX_TQM_ALLOC_REQ;
|
||||
i++, j += MAX_TQM_ALLOC_BLK_SIZE) {
|
||||
if (!ctx->tqm_tbl[i].max_elements)
|
||||
continue;
|
||||
if (fnz_idx == -1)
|
||||
fnz_idx = i;
|
||||
switch (ctx->tqm_tbl[i].level) {
|
||||
case PBL_LVL_2:
|
||||
for (k = 0; k < ctx->tqm_tbl[i].pbl[PBL_LVL_1].pg_count;
|
||||
k++)
|
||||
pbl_ptr[PTR_PG(j + k)][PTR_IDX(j + k)] =
|
||||
cpu_to_le64(
|
||||
ctx->tqm_tbl[i].pbl[PBL_LVL_1].pg_map_arr[k]
|
||||
| PTU_PTE_VALID);
|
||||
break;
|
||||
case PBL_LVL_1:
|
||||
case PBL_LVL_0:
|
||||
default:
|
||||
pbl_ptr[PTR_PG(j)][PTR_IDX(j)] = cpu_to_le64(
|
||||
ctx->tqm_tbl[i].pbl[PBL_LVL_0].pg_map_arr[0] |
|
||||
PTU_PTE_VALID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fnz_idx == -1)
|
||||
fnz_idx = 0;
|
||||
ctx->tqm_pde_level = ctx->tqm_tbl[fnz_idx].level == PBL_LVL_2 ?
|
||||
PBL_LVL_2 : ctx->tqm_tbl[fnz_idx].level + 1;
|
||||
|
||||
/* TIM Buffer */
|
||||
ctx->tim_tbl.max_elements = ctx->qpc_count * 16;
|
||||
rc = bnxt_qplib_alloc_init_hwq(pdev, &ctx->tim_tbl, NULL, 0,
|
||||
&ctx->tim_tbl.max_elements, 1,
|
||||
0, PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
stats_alloc:
|
||||
/* Stats */
|
||||
rc = bnxt_qplib_alloc_stats_ctx(pdev, &ctx->stats);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
bnxt_qplib_free_ctx(pdev, ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* GUID */
|
||||
void bnxt_qplib_get_guid(u8 *dev_addr, u8 *guid)
|
||||
{
|
||||
u8 mac[ETH_ALEN];
|
||||
|
||||
/* MAC-48 to EUI-64 mapping */
|
||||
memcpy(mac, dev_addr, ETH_ALEN);
|
||||
guid[0] = mac[0] ^ 2;
|
||||
guid[1] = mac[1];
|
||||
guid[2] = mac[2];
|
||||
guid[3] = 0xff;
|
||||
guid[4] = 0xfe;
|
||||
guid[5] = mac[3];
|
||||
guid[6] = mac[4];
|
||||
guid[7] = mac[5];
|
||||
}
|
||||
|
||||
static void bnxt_qplib_free_sgid_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_sgid_tbl *sgid_tbl)
|
||||
{
|
||||
kfree(sgid_tbl->tbl);
|
||||
kfree(sgid_tbl->hw_id);
|
||||
kfree(sgid_tbl->ctx);
|
||||
sgid_tbl->tbl = NULL;
|
||||
sgid_tbl->hw_id = NULL;
|
||||
sgid_tbl->ctx = NULL;
|
||||
sgid_tbl->max = 0;
|
||||
sgid_tbl->active = 0;
|
||||
}
|
||||
|
||||
static int bnxt_qplib_alloc_sgid_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_sgid_tbl *sgid_tbl,
|
||||
u16 max)
|
||||
{
|
||||
sgid_tbl->tbl = kcalloc(max, sizeof(struct bnxt_qplib_gid), GFP_KERNEL);
|
||||
if (!sgid_tbl->tbl)
|
||||
return -ENOMEM;
|
||||
|
||||
sgid_tbl->hw_id = kcalloc(max, sizeof(u16), GFP_KERNEL);
|
||||
if (!sgid_tbl->hw_id)
|
||||
goto out_free1;
|
||||
|
||||
sgid_tbl->ctx = kcalloc(max, sizeof(void *), GFP_KERNEL);
|
||||
if (!sgid_tbl->ctx)
|
||||
goto out_free2;
|
||||
|
||||
sgid_tbl->max = max;
|
||||
return 0;
|
||||
out_free2:
|
||||
kfree(sgid_tbl->hw_id);
|
||||
sgid_tbl->hw_id = NULL;
|
||||
out_free1:
|
||||
kfree(sgid_tbl->tbl);
|
||||
sgid_tbl->tbl = NULL;
|
||||
return -ENOMEM;
|
||||
};
|
||||
|
||||
static void bnxt_qplib_cleanup_sgid_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_sgid_tbl *sgid_tbl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sgid_tbl->max; i++) {
|
||||
if (memcmp(&sgid_tbl->tbl[i], &bnxt_qplib_gid_zero,
|
||||
sizeof(bnxt_qplib_gid_zero)))
|
||||
bnxt_qplib_del_sgid(sgid_tbl, &sgid_tbl->tbl[i], true);
|
||||
}
|
||||
memset(sgid_tbl->tbl, 0, sizeof(struct bnxt_qplib_gid) * sgid_tbl->max);
|
||||
memset(sgid_tbl->hw_id, -1, sizeof(u16) * sgid_tbl->max);
|
||||
sgid_tbl->active = 0;
|
||||
}
|
||||
|
||||
static void bnxt_qplib_init_sgid_tbl(struct bnxt_qplib_sgid_tbl *sgid_tbl,
|
||||
struct net_device *netdev)
|
||||
{
|
||||
memset(sgid_tbl->tbl, 0, sizeof(struct bnxt_qplib_gid) * sgid_tbl->max);
|
||||
memset(sgid_tbl->hw_id, -1, sizeof(u16) * sgid_tbl->max);
|
||||
}
|
||||
|
||||
static void bnxt_qplib_free_pkey_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl)
|
||||
{
|
||||
if (!pkey_tbl->tbl)
|
||||
dev_dbg(&res->pdev->dev, "QPLIB: PKEY tbl not present");
|
||||
else
|
||||
kfree(pkey_tbl->tbl);
|
||||
|
||||
pkey_tbl->tbl = NULL;
|
||||
pkey_tbl->max = 0;
|
||||
pkey_tbl->active = 0;
|
||||
}
|
||||
|
||||
static int bnxt_qplib_alloc_pkey_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl,
|
||||
u16 max)
|
||||
{
|
||||
pkey_tbl->tbl = kcalloc(max, sizeof(u16), GFP_KERNEL);
|
||||
if (!pkey_tbl->tbl)
|
||||
return -ENOMEM;
|
||||
|
||||
pkey_tbl->max = max;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/* PDs */
|
||||
int bnxt_qplib_alloc_pd(struct bnxt_qplib_pd_tbl *pdt, struct bnxt_qplib_pd *pd)
|
||||
{
|
||||
u32 bit_num;
|
||||
|
||||
bit_num = find_first_bit(pdt->tbl, pdt->max);
|
||||
if (bit_num == pdt->max)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Found unused PD */
|
||||
clear_bit(bit_num, pdt->tbl);
|
||||
pd->id = bit_num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_dealloc_pd(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pd_tbl *pdt,
|
||||
struct bnxt_qplib_pd *pd)
|
||||
{
|
||||
if (test_and_set_bit(pd->id, pdt->tbl)) {
|
||||
dev_warn(&res->pdev->dev, "Freeing an unused PD? pdn = %d",
|
||||
pd->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
pd->id = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bnxt_qplib_free_pd_tbl(struct bnxt_qplib_pd_tbl *pdt)
|
||||
{
|
||||
kfree(pdt->tbl);
|
||||
pdt->tbl = NULL;
|
||||
pdt->max = 0;
|
||||
}
|
||||
|
||||
static int bnxt_qplib_alloc_pd_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pd_tbl *pdt,
|
||||
u32 max)
|
||||
{
|
||||
u32 bytes;
|
||||
|
||||
bytes = max >> 3;
|
||||
if (!bytes)
|
||||
bytes = 1;
|
||||
pdt->tbl = kmalloc(bytes, GFP_KERNEL);
|
||||
if (!pdt->tbl)
|
||||
return -ENOMEM;
|
||||
|
||||
pdt->max = max;
|
||||
memset((u8 *)pdt->tbl, 0xFF, bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DPIs */
|
||||
int bnxt_qplib_alloc_dpi(struct bnxt_qplib_dpi_tbl *dpit,
|
||||
struct bnxt_qplib_dpi *dpi,
|
||||
void *app)
|
||||
{
|
||||
u32 bit_num;
|
||||
|
||||
bit_num = find_first_bit(dpit->tbl, dpit->max);
|
||||
if (bit_num == dpit->max)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Found unused DPI */
|
||||
clear_bit(bit_num, dpit->tbl);
|
||||
dpit->app_tbl[bit_num] = app;
|
||||
|
||||
dpi->dpi = bit_num;
|
||||
dpi->dbr = dpit->dbr_bar_reg_iomem + (bit_num * PAGE_SIZE);
|
||||
dpi->umdbr = dpit->unmapped_dbr + (bit_num * PAGE_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_dealloc_dpi(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_dpi_tbl *dpit,
|
||||
struct bnxt_qplib_dpi *dpi)
|
||||
{
|
||||
if (dpi->dpi >= dpit->max) {
|
||||
dev_warn(&res->pdev->dev, "Invalid DPI? dpi = %d", dpi->dpi);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (test_and_set_bit(dpi->dpi, dpit->tbl)) {
|
||||
dev_warn(&res->pdev->dev, "Freeing an unused DPI? dpi = %d",
|
||||
dpi->dpi);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (dpit->app_tbl)
|
||||
dpit->app_tbl[dpi->dpi] = NULL;
|
||||
memset(dpi, 0, sizeof(*dpi));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bnxt_qplib_free_dpi_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_dpi_tbl *dpit)
|
||||
{
|
||||
kfree(dpit->tbl);
|
||||
kfree(dpit->app_tbl);
|
||||
if (dpit->dbr_bar_reg_iomem)
|
||||
pci_iounmap(res->pdev, dpit->dbr_bar_reg_iomem);
|
||||
memset(dpit, 0, sizeof(*dpit));
|
||||
}
|
||||
|
||||
static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_dpi_tbl *dpit,
|
||||
u32 dbr_offset)
|
||||
{
|
||||
u32 dbr_bar_reg = RCFW_DBR_PCI_BAR_REGION;
|
||||
resource_size_t bar_reg_base;
|
||||
u32 dbr_len, bytes;
|
||||
|
||||
if (dpit->dbr_bar_reg_iomem) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: DBR BAR region %d already mapped", dbr_bar_reg);
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
bar_reg_base = pci_resource_start(res->pdev, dbr_bar_reg);
|
||||
if (!bar_reg_base) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: BAR region %d resc start failed", dbr_bar_reg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dbr_len = pci_resource_len(res->pdev, dbr_bar_reg) - dbr_offset;
|
||||
if (!dbr_len || ((dbr_len & (PAGE_SIZE - 1)) != 0)) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: Invalid DBR length %d",
|
||||
dbr_len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dpit->dbr_bar_reg_iomem = ioremap_nocache(bar_reg_base + dbr_offset,
|
||||
dbr_len);
|
||||
if (!dpit->dbr_bar_reg_iomem) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: FP: DBR BAR region %d mapping failed",
|
||||
dbr_bar_reg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dpit->unmapped_dbr = bar_reg_base + dbr_offset;
|
||||
dpit->max = dbr_len / PAGE_SIZE;
|
||||
|
||||
dpit->app_tbl = kcalloc(dpit->max, sizeof(void *), GFP_KERNEL);
|
||||
if (!dpit->app_tbl) {
|
||||
pci_iounmap(res->pdev, dpit->dbr_bar_reg_iomem);
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: DPI app tbl allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bytes = dpit->max >> 3;
|
||||
if (!bytes)
|
||||
bytes = 1;
|
||||
|
||||
dpit->tbl = kmalloc(bytes, GFP_KERNEL);
|
||||
if (!dpit->tbl) {
|
||||
pci_iounmap(res->pdev, dpit->dbr_bar_reg_iomem);
|
||||
kfree(dpit->app_tbl);
|
||||
dpit->app_tbl = NULL;
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: DPI tbl allocation failed for size = %d",
|
||||
bytes);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset((u8 *)dpit->tbl, 0xFF, bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PKEYs */
|
||||
static void bnxt_qplib_cleanup_pkey_tbl(struct bnxt_qplib_pkey_tbl *pkey_tbl)
|
||||
{
|
||||
memset(pkey_tbl->tbl, 0, sizeof(u16) * pkey_tbl->max);
|
||||
pkey_tbl->active = 0;
|
||||
}
|
||||
|
||||
static void bnxt_qplib_init_pkey_tbl(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl)
|
||||
{
|
||||
u16 pkey = 0xFFFF;
|
||||
|
||||
memset(pkey_tbl->tbl, 0, sizeof(u16) * pkey_tbl->max);
|
||||
|
||||
/* pkey default = 0xFFFF */
|
||||
bnxt_qplib_add_pkey(res, pkey_tbl, &pkey, false);
|
||||
}
|
||||
|
||||
/* Stats */
|
||||
static void bnxt_qplib_free_stats_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_stats *stats)
|
||||
{
|
||||
if (stats->dma) {
|
||||
dma_free_coherent(&pdev->dev, stats->size,
|
||||
stats->dma, stats->dma_map);
|
||||
}
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
stats->fw_id = -1;
|
||||
}
|
||||
|
||||
static int bnxt_qplib_alloc_stats_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_stats *stats)
|
||||
{
|
||||
memset(stats, 0, sizeof(*stats));
|
||||
stats->fw_id = -1;
|
||||
stats->size = sizeof(struct ctx_hw_stats);
|
||||
stats->dma = dma_alloc_coherent(&pdev->dev, stats->size,
|
||||
&stats->dma_map, GFP_KERNEL);
|
||||
if (!stats->dma) {
|
||||
dev_err(&pdev->dev, "QPLIB: Stats DMA allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bnxt_qplib_cleanup_res(struct bnxt_qplib_res *res)
|
||||
{
|
||||
bnxt_qplib_cleanup_pkey_tbl(&res->pkey_tbl);
|
||||
bnxt_qplib_cleanup_sgid_tbl(res, &res->sgid_tbl);
|
||||
}
|
||||
|
||||
int bnxt_qplib_init_res(struct bnxt_qplib_res *res)
|
||||
{
|
||||
bnxt_qplib_init_sgid_tbl(&res->sgid_tbl, res->netdev);
|
||||
bnxt_qplib_init_pkey_tbl(res, &res->pkey_tbl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bnxt_qplib_free_res(struct bnxt_qplib_res *res)
|
||||
{
|
||||
bnxt_qplib_free_pkey_tbl(res, &res->pkey_tbl);
|
||||
bnxt_qplib_free_sgid_tbl(res, &res->sgid_tbl);
|
||||
bnxt_qplib_free_pd_tbl(&res->pd_tbl);
|
||||
bnxt_qplib_free_dpi_tbl(res, &res->dpi_tbl);
|
||||
|
||||
res->netdev = NULL;
|
||||
res->pdev = NULL;
|
||||
}
|
||||
|
||||
int bnxt_qplib_alloc_res(struct bnxt_qplib_res *res, struct pci_dev *pdev,
|
||||
struct net_device *netdev,
|
||||
struct bnxt_qplib_dev_attr *dev_attr)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
res->pdev = pdev;
|
||||
res->netdev = netdev;
|
||||
|
||||
rc = bnxt_qplib_alloc_sgid_tbl(res, &res->sgid_tbl, dev_attr->max_sgid);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
rc = bnxt_qplib_alloc_pkey_tbl(res, &res->pkey_tbl, dev_attr->max_pkey);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
rc = bnxt_qplib_alloc_pd_tbl(res, &res->pd_tbl, dev_attr->max_pd);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
rc = bnxt_qplib_alloc_dpi_tbl(res, &res->dpi_tbl, dev_attr->l2_db_size);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
bnxt_qplib_free_res(res);
|
||||
return rc;
|
||||
}
|
223
drivers/infiniband/hw/bnxt_re/qplib_res.h
Normal file
223
drivers/infiniband/hw/bnxt_re/qplib_res.h
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: QPLib resource manager (header)
|
||||
*/
|
||||
|
||||
#ifndef __BNXT_QPLIB_RES_H__
|
||||
#define __BNXT_QPLIB_RES_H__
|
||||
|
||||
extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero;
|
||||
|
||||
#define PTR_CNT_PER_PG (PAGE_SIZE / sizeof(void *))
|
||||
#define PTR_MAX_IDX_PER_PG (PTR_CNT_PER_PG - 1)
|
||||
#define PTR_PG(x) (((x) & ~PTR_MAX_IDX_PER_PG) / PTR_CNT_PER_PG)
|
||||
#define PTR_IDX(x) ((x) & PTR_MAX_IDX_PER_PG)
|
||||
|
||||
#define HWQ_CMP(idx, hwq) ((idx) & ((hwq)->max_elements - 1))
|
||||
|
||||
enum bnxt_qplib_hwq_type {
|
||||
HWQ_TYPE_CTX,
|
||||
HWQ_TYPE_QUEUE,
|
||||
HWQ_TYPE_L2_CMPL
|
||||
};
|
||||
|
||||
#define MAX_PBL_LVL_0_PGS 1
|
||||
#define MAX_PBL_LVL_1_PGS 512
|
||||
#define MAX_PBL_LVL_1_PGS_SHIFT 9
|
||||
#define MAX_PBL_LVL_1_PGS_FOR_LVL_2 256
|
||||
#define MAX_PBL_LVL_2_PGS (256 * 512)
|
||||
|
||||
enum bnxt_qplib_pbl_lvl {
|
||||
PBL_LVL_0,
|
||||
PBL_LVL_1,
|
||||
PBL_LVL_2,
|
||||
PBL_LVL_MAX
|
||||
};
|
||||
|
||||
#define ROCE_PG_SIZE_4K (4 * 1024)
|
||||
#define ROCE_PG_SIZE_8K (8 * 1024)
|
||||
#define ROCE_PG_SIZE_64K (64 * 1024)
|
||||
#define ROCE_PG_SIZE_2M (2 * 1024 * 1024)
|
||||
#define ROCE_PG_SIZE_8M (8 * 1024 * 1024)
|
||||
#define ROCE_PG_SIZE_1G (1024 * 1024 * 1024)
|
||||
|
||||
struct bnxt_qplib_pbl {
|
||||
u32 pg_count;
|
||||
u32 pg_size;
|
||||
void **pg_arr;
|
||||
dma_addr_t *pg_map_arr;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_hwq {
|
||||
struct pci_dev *pdev;
|
||||
/* lock to protect qplib_hwq */
|
||||
spinlock_t lock;
|
||||
struct bnxt_qplib_pbl pbl[PBL_LVL_MAX];
|
||||
enum bnxt_qplib_pbl_lvl level; /* 0, 1, or 2 */
|
||||
/* ptr for easy access to the PBL entries */
|
||||
void **pbl_ptr;
|
||||
/* ptr for easy access to the dma_addr */
|
||||
dma_addr_t *pbl_dma_ptr;
|
||||
u32 max_elements;
|
||||
u16 element_size; /* Size of each entry */
|
||||
|
||||
u32 prod; /* raw */
|
||||
u32 cons; /* raw */
|
||||
u8 cp_bit;
|
||||
u8 is_user;
|
||||
};
|
||||
|
||||
/* Tables */
|
||||
struct bnxt_qplib_pd_tbl {
|
||||
unsigned long *tbl;
|
||||
u32 max;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_sgid_tbl {
|
||||
struct bnxt_qplib_gid *tbl;
|
||||
u16 *hw_id;
|
||||
u16 max;
|
||||
u16 active;
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_pkey_tbl {
|
||||
u16 *tbl;
|
||||
u16 max;
|
||||
u16 active;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_dpi {
|
||||
u32 dpi;
|
||||
void __iomem *dbr;
|
||||
u64 umdbr;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_dpi_tbl {
|
||||
void **app_tbl;
|
||||
unsigned long *tbl;
|
||||
u16 max;
|
||||
void __iomem *dbr_bar_reg_iomem;
|
||||
u64 unmapped_dbr;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_stats {
|
||||
dma_addr_t dma_map;
|
||||
void *dma;
|
||||
u32 size;
|
||||
u32 fw_id;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_vf_res {
|
||||
u32 max_qp_per_vf;
|
||||
u32 max_mrw_per_vf;
|
||||
u32 max_srq_per_vf;
|
||||
u32 max_cq_per_vf;
|
||||
u32 max_gid_per_vf;
|
||||
};
|
||||
|
||||
#define BNXT_QPLIB_MAX_QP_CTX_ENTRY_SIZE 448
|
||||
#define BNXT_QPLIB_MAX_SRQ_CTX_ENTRY_SIZE 64
|
||||
#define BNXT_QPLIB_MAX_CQ_CTX_ENTRY_SIZE 64
|
||||
#define BNXT_QPLIB_MAX_MRW_CTX_ENTRY_SIZE 128
|
||||
|
||||
struct bnxt_qplib_ctx {
|
||||
u32 qpc_count;
|
||||
struct bnxt_qplib_hwq qpc_tbl;
|
||||
u32 mrw_count;
|
||||
struct bnxt_qplib_hwq mrw_tbl;
|
||||
u32 srqc_count;
|
||||
struct bnxt_qplib_hwq srqc_tbl;
|
||||
u32 cq_count;
|
||||
struct bnxt_qplib_hwq cq_tbl;
|
||||
struct bnxt_qplib_hwq tim_tbl;
|
||||
#define MAX_TQM_ALLOC_REQ 32
|
||||
#define MAX_TQM_ALLOC_BLK_SIZE 8
|
||||
u8 tqm_count[MAX_TQM_ALLOC_REQ];
|
||||
struct bnxt_qplib_hwq tqm_pde;
|
||||
u32 tqm_pde_level;
|
||||
struct bnxt_qplib_hwq tqm_tbl[MAX_TQM_ALLOC_REQ];
|
||||
struct bnxt_qplib_stats stats;
|
||||
struct bnxt_qplib_vf_res vf_res;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_res {
|
||||
struct pci_dev *pdev;
|
||||
struct net_device *netdev;
|
||||
|
||||
struct bnxt_qplib_rcfw *rcfw;
|
||||
|
||||
struct bnxt_qplib_pd_tbl pd_tbl;
|
||||
struct bnxt_qplib_sgid_tbl sgid_tbl;
|
||||
struct bnxt_qplib_pkey_tbl pkey_tbl;
|
||||
struct bnxt_qplib_dpi_tbl dpi_tbl;
|
||||
};
|
||||
|
||||
#define to_bnxt_qplib(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
struct bnxt_qplib_pd;
|
||||
struct bnxt_qplib_dev_attr;
|
||||
|
||||
void bnxt_qplib_free_hwq(struct pci_dev *pdev, struct bnxt_qplib_hwq *hwq);
|
||||
int bnxt_qplib_alloc_init_hwq(struct pci_dev *pdev, struct bnxt_qplib_hwq *hwq,
|
||||
struct scatterlist *sl, int nmap, u32 *elements,
|
||||
u32 elements_per_page, u32 aux, u32 pg_size,
|
||||
enum bnxt_qplib_hwq_type hwq_type);
|
||||
void bnxt_qplib_get_guid(u8 *dev_addr, u8 *guid);
|
||||
int bnxt_qplib_alloc_pd(struct bnxt_qplib_pd_tbl *pd_tbl,
|
||||
struct bnxt_qplib_pd *pd);
|
||||
int bnxt_qplib_dealloc_pd(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pd_tbl *pd_tbl,
|
||||
struct bnxt_qplib_pd *pd);
|
||||
int bnxt_qplib_alloc_dpi(struct bnxt_qplib_dpi_tbl *dpit,
|
||||
struct bnxt_qplib_dpi *dpi,
|
||||
void *app);
|
||||
int bnxt_qplib_dealloc_dpi(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_dpi_tbl *dpi_tbl,
|
||||
struct bnxt_qplib_dpi *dpi);
|
||||
void bnxt_qplib_cleanup_res(struct bnxt_qplib_res *res);
|
||||
int bnxt_qplib_init_res(struct bnxt_qplib_res *res);
|
||||
void bnxt_qplib_free_res(struct bnxt_qplib_res *res);
|
||||
int bnxt_qplib_alloc_res(struct bnxt_qplib_res *res, struct pci_dev *pdev,
|
||||
struct net_device *netdev,
|
||||
struct bnxt_qplib_dev_attr *dev_attr);
|
||||
void bnxt_qplib_free_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_ctx *ctx);
|
||||
int bnxt_qplib_alloc_ctx(struct pci_dev *pdev,
|
||||
struct bnxt_qplib_ctx *ctx,
|
||||
bool virt_fn);
|
||||
#endif /* __BNXT_QPLIB_RES_H__ */
|
838
drivers/infiniband/hw/bnxt_re/qplib_sp.c
Normal file
838
drivers/infiniband/hw/bnxt_re/qplib_sp.c
Normal file
@ -0,0 +1,838 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: Slow Path Operators
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "roce_hsi.h"
|
||||
|
||||
#include "qplib_res.h"
|
||||
#include "qplib_rcfw.h"
|
||||
#include "qplib_sp.h"
|
||||
|
||||
const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0 } };
|
||||
|
||||
/* Device */
|
||||
int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct bnxt_qplib_dev_attr *attr)
|
||||
{
|
||||
struct cmdq_query_func req;
|
||||
struct creq_query_func_resp *resp;
|
||||
struct creq_query_func_resp_sb *sb;
|
||||
u16 cmd_flags = 0;
|
||||
u32 temp;
|
||||
u8 *tqm_alloc;
|
||||
int i;
|
||||
|
||||
RCFW_CMD_PREP(req, QUERY_FUNC, cmd_flags);
|
||||
|
||||
req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS;
|
||||
resp = (struct creq_query_func_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void **)&sb,
|
||||
0);
|
||||
if (!resp) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: QUERY_FUNC send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: QUERY_FUNC timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: QUERY_FUNC failed ");
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Extract the context from the side buffer */
|
||||
attr->max_qp = le32_to_cpu(sb->max_qp);
|
||||
attr->max_qp_rd_atom =
|
||||
sb->max_qp_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ?
|
||||
BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_rd_atom;
|
||||
attr->max_qp_init_rd_atom =
|
||||
sb->max_qp_init_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ?
|
||||
BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_init_rd_atom;
|
||||
attr->max_qp_wqes = le16_to_cpu(sb->max_qp_wr);
|
||||
attr->max_qp_sges = sb->max_sge;
|
||||
attr->max_cq = le32_to_cpu(sb->max_cq);
|
||||
attr->max_cq_wqes = le32_to_cpu(sb->max_cqe);
|
||||
attr->max_cq_sges = attr->max_qp_sges;
|
||||
attr->max_mr = le32_to_cpu(sb->max_mr);
|
||||
attr->max_mw = le32_to_cpu(sb->max_mw);
|
||||
|
||||
attr->max_mr_size = le64_to_cpu(sb->max_mr_size);
|
||||
attr->max_pd = 64 * 1024;
|
||||
attr->max_raw_ethy_qp = le32_to_cpu(sb->max_raw_eth_qp);
|
||||
attr->max_ah = le32_to_cpu(sb->max_ah);
|
||||
|
||||
attr->max_fmr = le32_to_cpu(sb->max_fmr);
|
||||
attr->max_map_per_fmr = sb->max_map_per_fmr;
|
||||
|
||||
attr->max_srq = le16_to_cpu(sb->max_srq);
|
||||
attr->max_srq_wqes = le32_to_cpu(sb->max_srq_wr) - 1;
|
||||
attr->max_srq_sges = sb->max_srq_sge;
|
||||
/* Bono only reports 1 PKEY for now, but it can support > 1 */
|
||||
attr->max_pkey = le32_to_cpu(sb->max_pkeys);
|
||||
|
||||
attr->max_inline_data = le32_to_cpu(sb->max_inline_data);
|
||||
attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE;
|
||||
attr->max_sgid = le32_to_cpu(sb->max_gid);
|
||||
|
||||
strlcpy(attr->fw_ver, "20.6.28.0", sizeof(attr->fw_ver));
|
||||
|
||||
for (i = 0; i < MAX_TQM_ALLOC_REQ / 4; i++) {
|
||||
temp = le32_to_cpu(sb->tqm_alloc_reqs[i]);
|
||||
tqm_alloc = (u8 *)&temp;
|
||||
attr->tqm_alloc_reqs[i * 4] = *tqm_alloc;
|
||||
attr->tqm_alloc_reqs[i * 4 + 1] = *(++tqm_alloc);
|
||||
attr->tqm_alloc_reqs[i * 4 + 2] = *(++tqm_alloc);
|
||||
attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SGID */
|
||||
int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_sgid_tbl *sgid_tbl, int index,
|
||||
struct bnxt_qplib_gid *gid)
|
||||
{
|
||||
if (index > sgid_tbl->max) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: Index %d exceeded SGID table max (%d)",
|
||||
index, sgid_tbl->max);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(gid, &sgid_tbl->tbl[index], sizeof(*gid));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
|
||||
struct bnxt_qplib_gid *gid, bool update)
|
||||
{
|
||||
struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl,
|
||||
struct bnxt_qplib_res,
|
||||
sgid_tbl);
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
int index;
|
||||
|
||||
if (!sgid_tbl) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Do we need a sgid_lock here? */
|
||||
if (!sgid_tbl->active) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: SGID table has no active entries");
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (index = 0; index < sgid_tbl->max; index++) {
|
||||
if (!memcmp(&sgid_tbl->tbl[index], gid, sizeof(*gid)))
|
||||
break;
|
||||
}
|
||||
if (index == sgid_tbl->max) {
|
||||
dev_warn(&res->pdev->dev, "GID not found in the SGID table");
|
||||
return 0;
|
||||
}
|
||||
/* Remove GID from the SGID table */
|
||||
if (update) {
|
||||
struct cmdq_delete_gid req;
|
||||
struct creq_delete_gid_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
|
||||
RCFW_CMD_PREP(req, DELETE_GID, cmd_flags);
|
||||
if (sgid_tbl->hw_id[index] == 0xFFFF) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: GID entry contains an invalid HW id");
|
||||
return -EINVAL;
|
||||
}
|
||||
req.gid_index = cpu_to_le16(sgid_tbl->hw_id[index]);
|
||||
resp = (struct creq_delete_gid_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, NULL,
|
||||
0);
|
||||
if (!resp) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: SP: DELETE_GID send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_wait_for_resp(rcfw,
|
||||
le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: SP: DELETE_GID timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: SP: DELETE_GID failed ");
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
memcpy(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero,
|
||||
sizeof(bnxt_qplib_gid_zero));
|
||||
sgid_tbl->active--;
|
||||
dev_dbg(&res->pdev->dev,
|
||||
"QPLIB: SGID deleted hw_id[0x%x] = 0x%x active = 0x%x",
|
||||
index, sgid_tbl->hw_id[index], sgid_tbl->active);
|
||||
sgid_tbl->hw_id[index] = (u16)-1;
|
||||
|
||||
/* unlock */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
|
||||
struct bnxt_qplib_gid *gid, u8 *smac, u16 vlan_id,
|
||||
bool update, u32 *index)
|
||||
{
|
||||
struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl,
|
||||
struct bnxt_qplib_res,
|
||||
sgid_tbl);
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
int i, free_idx, rc = 0;
|
||||
|
||||
if (!sgid_tbl) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SGID table not allocated");
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Do we need a sgid_lock here? */
|
||||
if (sgid_tbl->active == sgid_tbl->max) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SGID table is full");
|
||||
return -ENOMEM;
|
||||
}
|
||||
free_idx = sgid_tbl->max;
|
||||
for (i = 0; i < sgid_tbl->max; i++) {
|
||||
if (!memcmp(&sgid_tbl->tbl[i], gid, sizeof(*gid))) {
|
||||
dev_dbg(&res->pdev->dev,
|
||||
"QPLIB: SGID entry already exist in entry %d!",
|
||||
i);
|
||||
*index = i;
|
||||
return -EALREADY;
|
||||
} else if (!memcmp(&sgid_tbl->tbl[i], &bnxt_qplib_gid_zero,
|
||||
sizeof(bnxt_qplib_gid_zero)) &&
|
||||
free_idx == sgid_tbl->max) {
|
||||
free_idx = i;
|
||||
}
|
||||
}
|
||||
if (free_idx == sgid_tbl->max) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: SGID table is FULL but count is not MAX??");
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (update) {
|
||||
struct cmdq_add_gid req;
|
||||
struct creq_add_gid_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
u32 temp32[4];
|
||||
u16 temp16[3];
|
||||
|
||||
RCFW_CMD_PREP(req, ADD_GID, cmd_flags);
|
||||
|
||||
memcpy(temp32, gid->data, sizeof(struct bnxt_qplib_gid));
|
||||
req.gid[0] = cpu_to_be32(temp32[3]);
|
||||
req.gid[1] = cpu_to_be32(temp32[2]);
|
||||
req.gid[2] = cpu_to_be32(temp32[1]);
|
||||
req.gid[3] = cpu_to_be32(temp32[0]);
|
||||
if (vlan_id != 0xFFFF)
|
||||
req.vlan = cpu_to_le16((vlan_id &
|
||||
CMDQ_ADD_GID_VLAN_VLAN_ID_MASK) |
|
||||
CMDQ_ADD_GID_VLAN_TPID_TPID_8100 |
|
||||
CMDQ_ADD_GID_VLAN_VLAN_EN);
|
||||
|
||||
/* MAC in network format */
|
||||
memcpy(temp16, smac, 6);
|
||||
req.src_mac[0] = cpu_to_be16(temp16[0]);
|
||||
req.src_mac[1] = cpu_to_be16(temp16[1]);
|
||||
req.src_mac[2] = cpu_to_be16(temp16[2]);
|
||||
|
||||
resp = (struct creq_add_gid_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, 0);
|
||||
if (!resp) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: SP: ADD_GID send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_wait_for_resp(rcfw,
|
||||
le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPIB: SP: ADD_GID timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: ADD_GID failed ");
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
sgid_tbl->hw_id[free_idx] = le32_to_cpu(resp->xid);
|
||||
}
|
||||
/* Add GID to the sgid_tbl */
|
||||
memcpy(&sgid_tbl->tbl[free_idx], gid, sizeof(*gid));
|
||||
sgid_tbl->active++;
|
||||
dev_dbg(&res->pdev->dev,
|
||||
"QPLIB: SGID added hw_id[0x%x] = 0x%x active = 0x%x",
|
||||
free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active);
|
||||
|
||||
*index = free_idx;
|
||||
/* unlock */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pkeys */
|
||||
int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index,
|
||||
u16 *pkey)
|
||||
{
|
||||
if (index == 0xFFFF) {
|
||||
*pkey = 0xFFFF;
|
||||
return 0;
|
||||
}
|
||||
if (index > pkey_tbl->max) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: Index %d exceeded PKEY table max (%d)",
|
||||
index, pkey_tbl->max);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(pkey, &pkey_tbl->tbl[index], sizeof(*pkey));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey,
|
||||
bool update)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
if (!pkey_tbl) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Do we need a pkey_lock here? */
|
||||
if (!pkey_tbl->active) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: PKEY table has no active entries");
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (i = 0; i < pkey_tbl->max; i++) {
|
||||
if (!memcmp(&pkey_tbl->tbl[i], pkey, sizeof(*pkey)))
|
||||
break;
|
||||
}
|
||||
if (i == pkey_tbl->max) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: PKEY 0x%04x not found in the pkey table",
|
||||
*pkey);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(&pkey_tbl->tbl[i], 0, sizeof(*pkey));
|
||||
pkey_tbl->active--;
|
||||
|
||||
/* unlock */
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey,
|
||||
bool update)
|
||||
{
|
||||
int i, free_idx, rc = 0;
|
||||
|
||||
if (!pkey_tbl) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: PKEY table not allocated");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Do we need a pkey_lock here? */
|
||||
if (pkey_tbl->active == pkey_tbl->max) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: PKEY table is full");
|
||||
return -ENOMEM;
|
||||
}
|
||||
free_idx = pkey_tbl->max;
|
||||
for (i = 0; i < pkey_tbl->max; i++) {
|
||||
if (!memcmp(&pkey_tbl->tbl[i], pkey, sizeof(*pkey)))
|
||||
return -EALREADY;
|
||||
else if (!pkey_tbl->tbl[i] && free_idx == pkey_tbl->max)
|
||||
free_idx = i;
|
||||
}
|
||||
if (free_idx == pkey_tbl->max) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: PKEY table is FULL but count is not MAX??");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Add PKEY to the pkey_tbl */
|
||||
memcpy(&pkey_tbl->tbl[free_idx], pkey, sizeof(*pkey));
|
||||
pkey_tbl->active++;
|
||||
|
||||
/* unlock */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* AH */
|
||||
int bnxt_qplib_create_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
struct cmdq_create_ah req;
|
||||
struct creq_create_ah_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
u32 temp32[4];
|
||||
u16 temp16[3];
|
||||
|
||||
RCFW_CMD_PREP(req, CREATE_AH, cmd_flags);
|
||||
|
||||
memcpy(temp32, ah->dgid.data, sizeof(struct bnxt_qplib_gid));
|
||||
req.dgid[0] = cpu_to_le32(temp32[0]);
|
||||
req.dgid[1] = cpu_to_le32(temp32[1]);
|
||||
req.dgid[2] = cpu_to_le32(temp32[2]);
|
||||
req.dgid[3] = cpu_to_le32(temp32[3]);
|
||||
|
||||
req.type = ah->nw_type;
|
||||
req.hop_limit = ah->hop_limit;
|
||||
req.sgid_index = cpu_to_le16(res->sgid_tbl.hw_id[ah->sgid_index]);
|
||||
req.dest_vlan_id_flow_label = cpu_to_le32((ah->flow_label &
|
||||
CMDQ_CREATE_AH_FLOW_LABEL_MASK) |
|
||||
CMDQ_CREATE_AH_DEST_VLAN_ID_MASK);
|
||||
req.pd_id = cpu_to_le32(ah->pd->id);
|
||||
req.traffic_class = ah->traffic_class;
|
||||
|
||||
/* MAC in network format */
|
||||
memcpy(temp16, ah->dmac, 6);
|
||||
req.dest_mac[0] = cpu_to_le16(temp16[0]);
|
||||
req.dest_mac[1] = cpu_to_le16(temp16[1]);
|
||||
req.dest_mac[2] = cpu_to_le16(temp16[2]);
|
||||
|
||||
resp = (struct creq_create_ah_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, 1);
|
||||
if (!resp) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: CREATE_AH send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_block_for_resp(rcfw, le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: CREATE_AH timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: CREATE_AH failed ");
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
ah->id = le32_to_cpu(resp->xid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_destroy_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
struct cmdq_destroy_ah req;
|
||||
struct creq_destroy_ah_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
|
||||
/* Clean up the AH table in the device */
|
||||
RCFW_CMD_PREP(req, DESTROY_AH, cmd_flags);
|
||||
|
||||
req.ah_cid = cpu_to_le32(ah->id);
|
||||
|
||||
resp = (struct creq_destroy_ah_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, 1);
|
||||
if (!resp) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: DESTROY_AH send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_block_for_resp(rcfw, le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: DESTROY_AH timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: DESTROY_AH failed ");
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MRW */
|
||||
int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
struct cmdq_deallocate_key req;
|
||||
struct creq_deallocate_key_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
|
||||
if (mrw->lkey == 0xFFFFFFFF) {
|
||||
dev_info(&res->pdev->dev,
|
||||
"QPLIB: SP: Free a reserved lkey MRW");
|
||||
return 0;
|
||||
}
|
||||
|
||||
RCFW_CMD_PREP(req, DEALLOCATE_KEY, cmd_flags);
|
||||
|
||||
req.mrw_flags = mrw->type;
|
||||
|
||||
if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1) ||
|
||||
(mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A) ||
|
||||
(mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B))
|
||||
req.key = cpu_to_le32(mrw->rkey);
|
||||
else
|
||||
req.key = cpu_to_le32(mrw->lkey);
|
||||
|
||||
resp = (struct creq_deallocate_key_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, 0);
|
||||
if (!resp) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: FREE_MR send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: FREE_MR timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: FREE_MR failed ");
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Free the qplib's MRW memory */
|
||||
if (mrw->hwq.max_elements)
|
||||
bnxt_qplib_free_hwq(res->pdev, &mrw->hwq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_alloc_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
struct cmdq_allocate_mrw req;
|
||||
struct creq_allocate_mrw_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
unsigned long tmp;
|
||||
|
||||
RCFW_CMD_PREP(req, ALLOCATE_MRW, cmd_flags);
|
||||
|
||||
req.pd_id = cpu_to_le32(mrw->pd->id);
|
||||
req.mrw_flags = mrw->type;
|
||||
if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_PMR &&
|
||||
mrw->flags & BNXT_QPLIB_FR_PMR) ||
|
||||
mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A ||
|
||||
mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B)
|
||||
req.access = CMDQ_ALLOCATE_MRW_ACCESS_CONSUMER_OWNED_KEY;
|
||||
tmp = (unsigned long)mrw;
|
||||
req.mrw_handle = cpu_to_le64(tmp);
|
||||
|
||||
resp = (struct creq_allocate_mrw_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, 0);
|
||||
if (!resp) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: ALLOC_MRW send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: ALLOC_MRW timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: ALLOC_MRW failed ");
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE1) ||
|
||||
(mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2A) ||
|
||||
(mrw->type == CMDQ_ALLOCATE_MRW_MRW_FLAGS_MW_TYPE2B))
|
||||
mrw->rkey = le32_to_cpu(resp->xid);
|
||||
else
|
||||
mrw->lkey = le32_to_cpu(resp->xid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_dereg_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw,
|
||||
bool block)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
struct cmdq_deregister_mr req;
|
||||
struct creq_deregister_mr_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
int rc;
|
||||
|
||||
RCFW_CMD_PREP(req, DEREGISTER_MR, cmd_flags);
|
||||
|
||||
req.lkey = cpu_to_le32(mrw->lkey);
|
||||
resp = (struct creq_deregister_mr_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, block);
|
||||
if (!resp) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: DEREG_MR send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (block)
|
||||
rc = bnxt_qplib_rcfw_block_for_resp(rcfw,
|
||||
le16_to_cpu(req.cookie));
|
||||
else
|
||||
rc = bnxt_qplib_rcfw_wait_for_resp(rcfw,
|
||||
le16_to_cpu(req.cookie));
|
||||
if (!rc) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: DEREG_MR timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&rcfw->pdev->dev, "QPLIB: SP: DEREG_MR failed ");
|
||||
dev_err(&rcfw->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Free the qplib's MR memory */
|
||||
if (mrw->hwq.max_elements) {
|
||||
mrw->va = 0;
|
||||
mrw->total_size = 0;
|
||||
bnxt_qplib_free_hwq(res->pdev, &mrw->hwq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr,
|
||||
u64 *pbl_tbl, int num_pbls, bool block)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
struct cmdq_register_mr req;
|
||||
struct creq_register_mr_resp *resp;
|
||||
u16 cmd_flags = 0, level;
|
||||
int pg_ptrs, pages, i, rc;
|
||||
dma_addr_t **pbl_ptr;
|
||||
u32 pg_size;
|
||||
|
||||
if (num_pbls) {
|
||||
pg_ptrs = roundup_pow_of_two(num_pbls);
|
||||
pages = pg_ptrs >> MAX_PBL_LVL_1_PGS_SHIFT;
|
||||
if (!pages)
|
||||
pages++;
|
||||
|
||||
if (pages > MAX_PBL_LVL_1_PGS) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: Reg MR pages ");
|
||||
dev_err(&res->pdev->dev,
|
||||
"requested (0x%x) exceeded max (0x%x)",
|
||||
pages, MAX_PBL_LVL_1_PGS);
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Free the hwq if it already exist, must be a rereg */
|
||||
if (mr->hwq.max_elements)
|
||||
bnxt_qplib_free_hwq(res->pdev, &mr->hwq);
|
||||
|
||||
mr->hwq.max_elements = pages;
|
||||
rc = bnxt_qplib_alloc_init_hwq(res->pdev, &mr->hwq, NULL, 0,
|
||||
&mr->hwq.max_elements,
|
||||
PAGE_SIZE, 0, PAGE_SIZE,
|
||||
HWQ_TYPE_CTX);
|
||||
if (rc) {
|
||||
dev_err(&res->pdev->dev,
|
||||
"SP: Reg MR memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Write to the hwq */
|
||||
pbl_ptr = (dma_addr_t **)mr->hwq.pbl_ptr;
|
||||
for (i = 0; i < num_pbls; i++)
|
||||
pbl_ptr[PTR_PG(i)][PTR_IDX(i)] =
|
||||
(pbl_tbl[i] & PAGE_MASK) | PTU_PTE_VALID;
|
||||
}
|
||||
|
||||
RCFW_CMD_PREP(req, REGISTER_MR, cmd_flags);
|
||||
|
||||
/* Configure the request */
|
||||
if (mr->hwq.level == PBL_LVL_MAX) {
|
||||
level = 0;
|
||||
req.pbl = 0;
|
||||
pg_size = PAGE_SIZE;
|
||||
} else {
|
||||
level = mr->hwq.level + 1;
|
||||
req.pbl = cpu_to_le64(mr->hwq.pbl[PBL_LVL_0].pg_map_arr[0]);
|
||||
pg_size = mr->hwq.pbl[PBL_LVL_0].pg_size;
|
||||
}
|
||||
req.log2_pg_size_lvl = (level << CMDQ_REGISTER_MR_LVL_SFT) |
|
||||
((ilog2(pg_size) <<
|
||||
CMDQ_REGISTER_MR_LOG2_PG_SIZE_SFT) &
|
||||
CMDQ_REGISTER_MR_LOG2_PG_SIZE_MASK);
|
||||
req.access = (mr->flags & 0xFFFF);
|
||||
req.va = cpu_to_le64(mr->va);
|
||||
req.key = cpu_to_le32(mr->lkey);
|
||||
req.mr_size = cpu_to_le64(mr->total_size);
|
||||
|
||||
resp = (struct creq_register_mr_resp *)
|
||||
bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
|
||||
NULL, block);
|
||||
if (!resp) {
|
||||
dev_err(&res->pdev->dev, "SP: REG_MR send failed");
|
||||
rc = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (block)
|
||||
rc = bnxt_qplib_rcfw_block_for_resp(rcfw,
|
||||
le16_to_cpu(req.cookie));
|
||||
else
|
||||
rc = bnxt_qplib_rcfw_wait_for_resp(rcfw,
|
||||
le16_to_cpu(req.cookie));
|
||||
if (!rc) {
|
||||
/* Cmd timed out */
|
||||
dev_err(&res->pdev->dev, "SP: REG_MR timed out");
|
||||
rc = -ETIMEDOUT;
|
||||
goto fail;
|
||||
}
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: REG_MR failed ");
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: SP: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
rc = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (mr->hwq.max_elements)
|
||||
bnxt_qplib_free_hwq(res->pdev, &mr->hwq);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bnxt_qplib_alloc_fast_reg_page_list(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_frpl *frpl,
|
||||
int max_pg_ptrs)
|
||||
{
|
||||
int pg_ptrs, pages, rc;
|
||||
|
||||
/* Re-calculate the max to fit the HWQ allocation model */
|
||||
pg_ptrs = roundup_pow_of_two(max_pg_ptrs);
|
||||
pages = pg_ptrs >> MAX_PBL_LVL_1_PGS_SHIFT;
|
||||
if (!pages)
|
||||
pages++;
|
||||
|
||||
if (pages > MAX_PBL_LVL_1_PGS)
|
||||
return -ENOMEM;
|
||||
|
||||
frpl->hwq.max_elements = pages;
|
||||
rc = bnxt_qplib_alloc_init_hwq(res->pdev, &frpl->hwq, NULL, 0,
|
||||
&frpl->hwq.max_elements, PAGE_SIZE, 0,
|
||||
PAGE_SIZE, HWQ_TYPE_CTX);
|
||||
if (!rc)
|
||||
frpl->max_pg_ptrs = pg_ptrs;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int bnxt_qplib_free_fast_reg_page_list(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_frpl *frpl)
|
||||
{
|
||||
bnxt_qplib_free_hwq(res->pdev, &frpl->hwq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bnxt_qplib_map_tc2cos(struct bnxt_qplib_res *res, u16 *cids)
|
||||
{
|
||||
struct bnxt_qplib_rcfw *rcfw = res->rcfw;
|
||||
struct cmdq_map_tc_to_cos req;
|
||||
struct creq_map_tc_to_cos_resp *resp;
|
||||
u16 cmd_flags = 0;
|
||||
int tleft;
|
||||
|
||||
RCFW_CMD_PREP(req, MAP_TC_TO_COS, cmd_flags);
|
||||
req.cos0 = cpu_to_le16(cids[0]);
|
||||
req.cos1 = cpu_to_le16(cids[1]);
|
||||
|
||||
resp = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, NULL, 0);
|
||||
if (!resp) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: MAP_TC2COS send failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tleft = bnxt_qplib_rcfw_block_for_resp(rcfw, le16_to_cpu(req.cookie));
|
||||
if (!tleft) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: MAP_TC2COS timed out");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (resp->status ||
|
||||
le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
|
||||
dev_err(&res->pdev->dev, "QPLIB: SP: MAP_TC2COS failed ");
|
||||
dev_err(&res->pdev->dev,
|
||||
"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
|
||||
resp->status, le16_to_cpu(req.cookie),
|
||||
le16_to_cpu(resp->cookie));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
160
drivers/infiniband/hw/bnxt_re/qplib_sp.h
Normal file
160
drivers/infiniband/hw/bnxt_re/qplib_sp.h
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: Slow Path Operators (header)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BNXT_QPLIB_SP_H__
|
||||
#define __BNXT_QPLIB_SP_H__
|
||||
|
||||
struct bnxt_qplib_dev_attr {
|
||||
char fw_ver[32];
|
||||
u16 max_sgid;
|
||||
u16 max_mrw;
|
||||
u32 max_qp;
|
||||
#define BNXT_QPLIB_MAX_OUT_RD_ATOM 126
|
||||
u32 max_qp_rd_atom;
|
||||
u32 max_qp_init_rd_atom;
|
||||
u32 max_qp_wqes;
|
||||
u32 max_qp_sges;
|
||||
u32 max_cq;
|
||||
u32 max_cq_wqes;
|
||||
u32 max_cq_sges;
|
||||
u32 max_mr;
|
||||
u64 max_mr_size;
|
||||
u32 max_pd;
|
||||
u32 max_mw;
|
||||
u32 max_raw_ethy_qp;
|
||||
u32 max_ah;
|
||||
u32 max_fmr;
|
||||
u32 max_map_per_fmr;
|
||||
u32 max_srq;
|
||||
u32 max_srq_wqes;
|
||||
u32 max_srq_sges;
|
||||
u32 max_pkey;
|
||||
u32 max_inline_data;
|
||||
u32 l2_db_size;
|
||||
u8 tqm_alloc_reqs[MAX_TQM_ALLOC_REQ];
|
||||
};
|
||||
|
||||
struct bnxt_qplib_pd {
|
||||
u32 id;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_gid {
|
||||
u8 data[16];
|
||||
};
|
||||
|
||||
struct bnxt_qplib_ah {
|
||||
struct bnxt_qplib_gid dgid;
|
||||
struct bnxt_qplib_pd *pd;
|
||||
u32 id;
|
||||
u8 sgid_index;
|
||||
/* For Query AH if the hw table and SW table are differnt */
|
||||
u8 host_sgid_index;
|
||||
u8 traffic_class;
|
||||
u32 flow_label;
|
||||
u8 hop_limit;
|
||||
u8 sl;
|
||||
u8 dmac[6];
|
||||
u16 vlan_id;
|
||||
u8 nw_type;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_mrw {
|
||||
struct bnxt_qplib_pd *pd;
|
||||
int type;
|
||||
u32 flags;
|
||||
#define BNXT_QPLIB_FR_PMR 0x80000000
|
||||
u32 lkey;
|
||||
u32 rkey;
|
||||
#define BNXT_QPLIB_RSVD_LKEY 0xFFFFFFFF
|
||||
u64 va;
|
||||
u64 total_size;
|
||||
u32 npages;
|
||||
u64 mr_handle;
|
||||
struct bnxt_qplib_hwq hwq;
|
||||
};
|
||||
|
||||
struct bnxt_qplib_frpl {
|
||||
int max_pg_ptrs;
|
||||
struct bnxt_qplib_hwq hwq;
|
||||
};
|
||||
|
||||
#define BNXT_QPLIB_ACCESS_LOCAL_WRITE BIT(0)
|
||||
#define BNXT_QPLIB_ACCESS_REMOTE_READ BIT(1)
|
||||
#define BNXT_QPLIB_ACCESS_REMOTE_WRITE BIT(2)
|
||||
#define BNXT_QPLIB_ACCESS_REMOTE_ATOMIC BIT(3)
|
||||
#define BNXT_QPLIB_ACCESS_MW_BIND BIT(4)
|
||||
#define BNXT_QPLIB_ACCESS_ZERO_BASED BIT(5)
|
||||
#define BNXT_QPLIB_ACCESS_ON_DEMAND BIT(6)
|
||||
|
||||
int bnxt_qplib_get_sgid(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_sgid_tbl *sgid_tbl, int index,
|
||||
struct bnxt_qplib_gid *gid);
|
||||
int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
|
||||
struct bnxt_qplib_gid *gid, bool update);
|
||||
int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
|
||||
struct bnxt_qplib_gid *gid, u8 *mac, u16 vlan_id,
|
||||
bool update, u32 *index);
|
||||
int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index,
|
||||
u16 *pkey);
|
||||
int bnxt_qplib_del_pkey(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey,
|
||||
bool update);
|
||||
int bnxt_qplib_add_pkey(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 *pkey,
|
||||
bool update);
|
||||
int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
|
||||
struct bnxt_qplib_dev_attr *attr);
|
||||
int bnxt_qplib_create_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah);
|
||||
int bnxt_qplib_destroy_ah(struct bnxt_qplib_res *res, struct bnxt_qplib_ah *ah);
|
||||
int bnxt_qplib_alloc_mrw(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_mrw *mrw);
|
||||
int bnxt_qplib_dereg_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mrw,
|
||||
bool block);
|
||||
int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr,
|
||||
u64 *pbl_tbl, int num_pbls, bool block);
|
||||
int bnxt_qplib_free_mrw(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr);
|
||||
int bnxt_qplib_alloc_fast_reg_mr(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_mrw *mr, int max);
|
||||
int bnxt_qplib_alloc_fast_reg_page_list(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_frpl *frpl, int max);
|
||||
int bnxt_qplib_free_fast_reg_page_list(struct bnxt_qplib_res *res,
|
||||
struct bnxt_qplib_frpl *frpl);
|
||||
int bnxt_qplib_map_tc2cos(struct bnxt_qplib_res *res, u16 *cids);
|
||||
#endif /* __BNXT_QPLIB_SP_H__*/
|
2821
drivers/infiniband/hw/bnxt_re/roce_hsi.h
Normal file
2821
drivers/infiniband/hw/bnxt_re/roce_hsi.h
Normal file
File diff suppressed because it is too large
Load Diff
89
include/uapi/rdma/bnxt_re-abi.h
Normal file
89
include/uapi/rdma/bnxt_re-abi.h
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Broadcom NetXtreme-E RoCE driver.
|
||||
*
|
||||
* Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term
|
||||
* Broadcom refers to Broadcom Limited and/or its subsidiaries.
|
||||
*
|
||||
* 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
|
||||
* BSD license below:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Description: Uverbs ABI header file
|
||||
*/
|
||||
|
||||
#ifndef __BNXT_RE_UVERBS_ABI_H__
|
||||
#define __BNXT_RE_UVERBS_ABI_H__
|
||||
|
||||
#define BNXT_RE_ABI_VERSION 1
|
||||
|
||||
struct bnxt_re_uctx_resp {
|
||||
__u32 dev_id;
|
||||
__u32 max_qp;
|
||||
__u32 pg_size;
|
||||
__u32 cqe_sz;
|
||||
__u32 max_cqd;
|
||||
__u32 rsvd;
|
||||
};
|
||||
|
||||
struct bnxt_re_pd_resp {
|
||||
__u32 pdid;
|
||||
__u32 dpi;
|
||||
__u64 dbr;
|
||||
};
|
||||
|
||||
struct bnxt_re_cq_req {
|
||||
__u64 cq_va;
|
||||
__u64 cq_handle;
|
||||
};
|
||||
|
||||
struct bnxt_re_cq_resp {
|
||||
__u32 cqid;
|
||||
__u32 tail;
|
||||
__u32 phase;
|
||||
__u32 rsvd;
|
||||
};
|
||||
|
||||
struct bnxt_re_qp_req {
|
||||
__u64 qpsva;
|
||||
__u64 qprva;
|
||||
__u64 qp_handle;
|
||||
};
|
||||
|
||||
struct bnxt_re_qp_resp {
|
||||
__u32 qpid;
|
||||
__u32 rsvd;
|
||||
};
|
||||
|
||||
enum bnxt_re_shpg_offt {
|
||||
BNXT_RE_BEG_RESV_OFFT = 0x00,
|
||||
BNXT_RE_AVID_OFFT = 0x10,
|
||||
BNXT_RE_AVID_SIZE = 0x04,
|
||||
BNXT_RE_END_RESV_OFFT = 0xFF0
|
||||
};
|
||||
|
||||
#endif /* __BNXT_RE_UVERBS_ABI_H__*/
|
Loading…
Reference in New Issue
Block a user