// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
/* QLogic qed NIC Driver
* Copyright (c) 2015-2017 QLogic Corporation
* Copyright (c) 2019-2020 Marvell International Ltd.
*/
#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/if_vlan.h>
#include "qed.h"
#include "qed_cxt.h"
#include "qed_dcbx.h"
#include "qed_hsi.h"
#include "qed_hw.h"
#include "qed_init_ops.h"
#include "qed_int.h"
#include "qed_ll2.h"
#include "qed_mcp.h"
#include "qed_reg_addr.h"
#include <linux/qed/qed_rdma_if.h>
#include "qed_rdma.h"
#include "qed_roce.h"
#include "qed_sp.h"
static void qed_roce_free_real_icid(struct qed_hwfn *p_hwfn, u16 icid);
static int
qed_roce_async_event(struct qed_hwfn *p_hwfn,
u8 fw_event_code,
u16 echo, union event_ring_data *data, u8 fw_return_code)
{
struct qed_rdma_events events = p_hwfn->p_rdma_info->events;
if (fw_event_code == ROCE_ASYNC_EVENT_DESTROY_QP_DONE) {
u16 icid =
(u16)le32_to_cpu(data->rdma_data.rdma_destroy_qp_data.cid);
/* icid release in this async event can occur only if the icid
* was offloaded to the FW. In case it wasn't offloaded this is
* handled in qed_roce_sp_destroy_qp.
*/
qed_roce_free_real_icid(p_hwfn, icid);
} else {
if (fw_event_code == ROCE_ASYNC_EVENT_SRQ_EMPTY ||
fw_event_code == ROCE_ASYNC_EVENT_SRQ_LIMIT) {
u16 srq_id = (u16)data->rdma_data.async_handle.lo;
events.affiliated_event(events.context, fw_event_code,
&srq_id);
} else {
union rdma_eqe_data rdata = data->rdma_data;
events.affiliated_event(events.context, fw_event_code,
(void *)&rdata.async_handle);
}
}
return 0;
}
void qed_roce_stop(struct qed_hwfn *p_hwfn)
{
struct qed_bmap *rcid_map = &p_hwfn->p_rdma_info->real_cid_map;
int wait_count = 0;
/* when destroying a_RoCE QP the control is returned to the user after
* the synchronous part. The asynchronous part may take a little longer.
* We delay for a short while if an async destroy QP is still expected.
* Beyond the added delay we clear the bitmap anyway.
*/
while (bitmap_weight(rcid_map->bitmap, rcid_map->max_count)) {
msleep(100);
if (wait_count++ > 20) {
DP_NOTICE(p_hwfn, "cid bitmap wait timed out\n");
break;
}
}
}
static void qed_rdma_copy_gids(struct qed_rdma_qp *qp, __le32 *src_gid,
__le32 *dst_gid)
{
u32 i;
if (qp->roce_mode == ROCE_V2_IPV4) {
/* The IPv4 addresses shall be aligned to the highest word.
* The lower words must be zero.
*/
memset(src_gid, 0, sizeof(union qed_gid));
memset(dst_gid, 0, sizeof(union qed_gid));
src_gid[3] = cpu_to_le32(qp->sgid.ipv4_addr);
dst_gid[3] = cpu_to_le32(qp->dgid.ipv4_addr);
} else {
/* GIDs and IPv6 addresses coincide in location and size */
for (i =