2026-01-29 22:25:33 +08:00

2479 lines
62 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": [COMM]" fmt
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/completion.h>
#include <linux/semaphore.h>
#include <linux/vmalloc.h>
#include "ossl_knl.h"
#include "hinic_hw.h"
#include "hinic_hwdev.h"
#include "hinic_hw_mgmt.h"
#include "hinic_hwif.h"
#include "hinic_mbox.h"
#include "hinic_cfg.h"
#include "hinic_nic_cfg.h"
#include "hinic_mgmt_interface.h"
#include "hinic_multi_host_mgmt.h"
uint g_rdma_mtts_num;
uint g_rdma_qps_num;
uint g_rdma_mpts_num;
uint g_vfs_num;
module_param(g_rdma_mtts_num, uint, 0444);
MODULE_PARM_DESC(g_rdma_mtts_num, "number of roce used mtts, use default value when pass 0");
module_param(g_rdma_qps_num, uint, 0444);
MODULE_PARM_DESC(g_rdma_qps_num, "number of roce used qps, use default value when pass 0");
module_param(g_rdma_mpts_num, uint, 0444);
MODULE_PARM_DESC(g_rdma_mpts_num, "number of roce used mpts, use default value when pass 0");
module_param(g_vfs_num, uint, 0444);
MODULE_PARM_DESC(g_vfs_num, "number of used vfs, use default value when pass 0 ");
static uint intr_mode;
uint timer_enable = 1;
uint bloomfilter_enable;
uint g_test_qpc_num;
uint g_test_qpc_resvd_num;
uint g_test_pagesize_reorder;
uint g_test_xid_alloc_mode = 1;
uint g_test_gpa_check_enable = 1;
uint g_test_qpc_alloc_mode = 2;
uint g_test_scqc_alloc_mode = 2;
uint g_test_max_conn;
uint g_test_max_cache_conn;
uint g_test_scqc_num;
uint g_test_mpt_num;
uint g_test_mpt_resvd;
uint g_test_scq_resvd;
uint g_test_hash_num;
uint g_test_reorder_num;
static void set_cfg_test_param(struct cfg_mgmt_info *cfg_mgmt)
{
cfg_mgmt->svc_cap.timer_en = (u8)timer_enable;
cfg_mgmt->svc_cap.bloomfilter_en = (u8)bloomfilter_enable;
cfg_mgmt->svc_cap.test_qpc_num = g_test_qpc_num;
cfg_mgmt->svc_cap.test_qpc_resvd_num = g_test_qpc_resvd_num;
cfg_mgmt->svc_cap.test_page_size_reorder = g_test_pagesize_reorder;
cfg_mgmt->svc_cap.test_xid_alloc_mode = (bool)g_test_xid_alloc_mode;
cfg_mgmt->svc_cap.test_gpa_check_enable = (bool)g_test_gpa_check_enable;
cfg_mgmt->svc_cap.test_qpc_alloc_mode = (u8)g_test_qpc_alloc_mode;
cfg_mgmt->svc_cap.test_scqc_alloc_mode = (u8)g_test_scqc_alloc_mode;
cfg_mgmt->svc_cap.test_max_conn_num = g_test_max_conn;
cfg_mgmt->svc_cap.test_max_cache_conn_num = g_test_max_cache_conn;
cfg_mgmt->svc_cap.test_scqc_num = g_test_scqc_num;
cfg_mgmt->svc_cap.test_mpt_num = g_test_mpt_num;
cfg_mgmt->svc_cap.test_scq_resvd_num = g_test_scq_resvd;
cfg_mgmt->svc_cap.test_mpt_recvd_num = g_test_mpt_resvd;
cfg_mgmt->svc_cap.test_hash_num = g_test_hash_num;
cfg_mgmt->svc_cap.test_reorder_num = g_test_reorder_num;
}
int hinic_sync_time(void *hwdev, u64 time)
{
struct hinic_sync_time_info time_info = {0};
u16 out_size = sizeof(time_info);
int err;
time_info.mstime = time;
err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_COMM,
HINIC_MGMT_CMD_SYNC_TIME, &time_info,
sizeof(time_info), &time_info, &out_size,
0);
if (err || time_info.status || !out_size) {
sdk_err(((struct hinic_hwdev *)hwdev)->dev_hdl,
"Failed to sync time to mgmt, err: %d, status: 0x%x, out size: 0x%x\n",
err, time_info.status, out_size);
return -EFAULT;
}
return err;
}
void hinic_sync_time_async(void *hwdev, u64 time)
{
struct hinic_sync_time_info time_info = { 0 };
time_info.mstime = time;
hinic_msg_to_mgmt_async(hwdev, HINIC_MOD_COMM,
HINIC_MGMT_CMD_SYNC_TIME, &time_info,
sizeof(time_info));
}
static void parse_sf_en_cap(struct service_cap *cap,
struct hinic_dev_cap *dev_cap, enum func_type type)
{
struct dev_sf_svc_attr *attr = &cap->sf_svc_attr;
if (type == TYPE_PPF) {
/* For PPF's SF EN flag, we assign it in get_dynamic_res_cap().
* we only save its VF's flag.
*/
attr->sf_en_vf = dev_cap->sf_en_vf;
} else if (type == TYPE_PF) {
if (dev_cap->sf_en_pf)
cap->sf_en = true;
else
cap->sf_en = false;
attr->sf_en_vf = dev_cap->sf_en_vf;
} else {
/* VF gets SF_EN_VF from PPF/PF */
if (dev_cap->sf_en_vf)
cap->sf_en = true;
else
cap->sf_en = false;
attr->sf_en_vf = 0;
}
}
static void parse_pub_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct dev_sf_svc_attr *attr = &cap->sf_svc_attr;
cap->svc_type = dev_cap->svc_cap_en;
cap->chip_svc_type = cap->svc_type;
if (dev_cap->sf_svc_attr & SF_SVC_FT_BIT)
attr->ft_en = true;
else
attr->ft_en = false;
if (dev_cap->sf_svc_attr & SF_SVC_RDMA_BIT)
attr->rdma_en = true;
else
attr->rdma_en = false;
cap->host_id = dev_cap->host_id;
cap->ep_id = dev_cap->ep_id;
cap->max_cos_id = dev_cap->max_cos_id;
cap->cos_valid_bitmap = dev_cap->valid_cos_bitmap;
cap->er_id = dev_cap->er_id;
cap->port_id = dev_cap->port_id;
cap->force_up = dev_cap->force_up;
parse_sf_en_cap(cap, dev_cap, type);
/* PF/PPF */
if (type == TYPE_PF || type == TYPE_PPF) {
cap->max_vf = dev_cap->max_vf;
cap->pf_num = dev_cap->pf_num;
cap->pf_id_start = dev_cap->pf_id_start;
cap->vf_num = dev_cap->vf_num;
cap->vf_id_start = dev_cap->vf_id_start;
/* FC need max queue number, but max queue number info is in
* l2nic cap, we also put max queue num info in public cap, so
* FC can get correct max queue number info.
*/
cap->max_sqs = dev_cap->nic_max_sq + 1;
cap->max_rqs = dev_cap->nic_max_rq + 1;
} else {
cap->max_vf = 0;
cap->max_sqs = dev_cap->nic_max_sq;
cap->max_rqs = dev_cap->nic_max_rq;
}
cap->host_total_function = dev_cap->host_total_func;
cap->host_oq_id_mask_val = dev_cap->host_oq_id_mask_val;
cap->max_connect_num = dev_cap->max_conn_num;
cap->max_stick2cache_num = dev_cap->max_stick2cache_num;
cap->bfilter_start_addr = dev_cap->max_bfilter_start_addr;
cap->bfilter_len = dev_cap->bfilter_len;
cap->hash_bucket_num = dev_cap->hash_bucket_num;
cap->dev_ver_info.cfg_file_ver = dev_cap->cfg_file_ver;
cap->net_port_mode = dev_cap->net_port_mode;
/* FC does not use VF */
if (cap->net_port_mode == CFG_NET_MODE_FC)
cap->max_vf = 0;
sdk_info(hwdev->dev_hdl, "Get public resource capbility, svc_cap_en: 0x%x\n",
dev_cap->svc_cap_en);
sdk_info(hwdev->dev_hdl, "Host_id=0x%x, ep_id=0x%x, max_cos_id=0x%x, cos_bitmap=0x%x, er_id=0x%x, port_id=0x%x\n",
cap->host_id, cap->ep_id,
cap->max_cos_id, cap->cos_valid_bitmap,
cap->er_id, cap->port_id);
sdk_info(hwdev->dev_hdl, "Host_total_function=0x%x, host_oq_id_mask_val=0x%x, net_port_mode=0x%x, max_vf=0x%x\n",
cap->host_total_function, cap->host_oq_id_mask_val,
cap->net_port_mode, cap->max_vf);
sdk_info(hwdev->dev_hdl, "Pf_num=0x%x, pf_id_start=0x%x, vf_num=0x%x, vf_id_start=0x%x\n",
cap->pf_num, cap->pf_id_start,
cap->vf_num, cap->vf_id_start);
/* Check parameters from firmware */
if (cap->max_sqs > HINIC_CFG_MAX_QP ||
cap->max_rqs > HINIC_CFG_MAX_QP) {
sdk_info(hwdev->dev_hdl, "Number of qp exceed limit[1-%d]: sq: %d, rq: %d\n",
HINIC_CFG_MAX_QP, cap->max_sqs, cap->max_rqs);
cap->max_sqs = HINIC_CFG_MAX_QP;
cap->max_rqs = HINIC_CFG_MAX_QP;
}
}
static void parse_dynamic_share_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct host_shared_resource_cap *shared_cap = &cap->shared_res_cap;
shared_cap->host_pctxs = dev_cap->host_pctx_num;
if (dev_cap->host_sf_en)
cap->sf_en = true;
else
cap->sf_en = false;
shared_cap->host_cctxs = dev_cap->host_ccxt_num;
shared_cap->host_scqs = dev_cap->host_scq_num;
shared_cap->host_srqs = dev_cap->host_srq_num;
shared_cap->host_mpts = dev_cap->host_mpt_num;
sdk_info(hwdev->dev_hdl, "Dynamic share resource capbility, host_pctxs=0x%x, host_cctxs=0x%x, host_scqs=0x%x, host_srqs=0x%x, host_mpts=0x%x\n",
shared_cap->host_pctxs, shared_cap->host_cctxs,
shared_cap->host_scqs, shared_cap->host_srqs,
shared_cap->host_mpts);
}
static void parse_l2nic_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct nic_service_cap *nic_cap = &cap->nic_cap;
/* PF/PPF */
if (type == TYPE_PF || type == TYPE_PPF) {
nic_cap->max_sqs = dev_cap->nic_max_sq + 1;
nic_cap->max_rqs = dev_cap->nic_max_rq + 1;
nic_cap->vf_max_sqs = dev_cap->nic_vf_max_sq + 1;
nic_cap->vf_max_rqs = dev_cap->nic_vf_max_rq + 1;
nic_cap->max_queue_allowed = 0;
nic_cap->dynamic_qp = 0;
} else {
nic_cap->max_sqs = dev_cap->nic_max_sq;
nic_cap->max_rqs = dev_cap->nic_max_rq;
nic_cap->vf_max_sqs = 0;
nic_cap->vf_max_rqs = 0;
nic_cap->max_queue_allowed = dev_cap->max_queue_allowed;
nic_cap->dynamic_qp = dev_cap->ovs_dq_en;
}
if (dev_cap->nic_lro_en)
nic_cap->lro_en = true;
else
nic_cap->lro_en = false;
nic_cap->lro_sz = dev_cap->nic_lro_sz;
nic_cap->tso_sz = dev_cap->nic_tso_sz;
sdk_info(hwdev->dev_hdl, "L2nic resource capbility, max_sqs=0x%x, max_rqs=0x%x, vf_max_sqs=0x%x, vf_max_rqs=0x%x, max_queue_allowed=0x%x\n",
nic_cap->max_sqs, nic_cap->max_rqs,
nic_cap->vf_max_sqs, nic_cap->vf_max_rqs,
nic_cap->max_queue_allowed);
/* Check parameters from firmware */
if (nic_cap->max_sqs > HINIC_CFG_MAX_QP ||
nic_cap->max_rqs > HINIC_CFG_MAX_QP) {
sdk_info(hwdev->dev_hdl, "Number of qp exceed limit[1-%d]: sq: %d, rq: %d\n",
HINIC_CFG_MAX_QP, nic_cap->max_sqs, nic_cap->max_rqs);
nic_cap->max_sqs = HINIC_CFG_MAX_QP;
nic_cap->max_rqs = HINIC_CFG_MAX_QP;
}
}
static void parse_roce_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct dev_roce_svc_own_cap *roce_cap =
&cap->rdma_cap.dev_rdma_cap.roce_own_cap;
roce_cap->max_qps = dev_cap->roce_max_qp;
roce_cap->max_cqs = dev_cap->roce_max_cq;
roce_cap->max_srqs = dev_cap->roce_max_srq;
roce_cap->max_mpts = dev_cap->roce_max_mpt;
roce_cap->num_cos = dev_cap->max_cos_id + 1;
/* PF/PPF */
if (type == TYPE_PF || type == TYPE_PPF) {
roce_cap->vf_max_qps = dev_cap->roce_vf_max_qp;
roce_cap->vf_max_cqs = dev_cap->roce_vf_max_cq;
roce_cap->vf_max_srqs = dev_cap->roce_vf_max_srq;
roce_cap->vf_max_mpts = dev_cap->roce_vf_max_mpt;
} else {
roce_cap->vf_max_qps = 0;
roce_cap->vf_max_cqs = 0;
roce_cap->vf_max_srqs = 0;
roce_cap->vf_max_mpts = 0;
}
roce_cap->cmtt_cl_start = dev_cap->roce_cmtt_cl_start;
roce_cap->cmtt_cl_end = dev_cap->roce_cmtt_cl_end;
roce_cap->cmtt_cl_sz = dev_cap->roce_cmtt_cl_size;
roce_cap->dmtt_cl_start = dev_cap->roce_dmtt_cl_start;
roce_cap->dmtt_cl_end = dev_cap->roce_dmtt_cl_end;
roce_cap->dmtt_cl_sz = dev_cap->roce_dmtt_cl_size;
roce_cap->wqe_cl_start = dev_cap->roce_wqe_cl_start;
roce_cap->wqe_cl_end = dev_cap->roce_wqe_cl_end;
roce_cap->wqe_cl_sz = dev_cap->roce_wqe_cl_size;
sdk_info(hwdev->dev_hdl, "Get roce resource capbility\n");
sdk_info(hwdev->dev_hdl, "Max_qps=0x%x, max_cqs=0x%x, max_srqs=0x%x, max_mpts=0x%x\n",
roce_cap->max_qps, roce_cap->max_cqs,
roce_cap->max_srqs, roce_cap->max_mpts);
sdk_info(hwdev->dev_hdl, "Vf_max_qps=0x%x, vf_max_cqs=0x%x, vf_max_srqs= 0x%x, vf_max_mpts= 0x%x\n",
roce_cap->vf_max_qps, roce_cap->vf_max_cqs,
roce_cap->vf_max_srqs, roce_cap->vf_max_mpts);
sdk_info(hwdev->dev_hdl, "Cmtt_start=0x%x, cmtt_end=0x%x, cmtt_sz=0x%x\n",
roce_cap->cmtt_cl_start, roce_cap->cmtt_cl_end,
roce_cap->cmtt_cl_sz);
sdk_info(hwdev->dev_hdl, "Dmtt_start=0x%x, dmtt_end=0x%x, dmtt_sz=0x%x\n",
roce_cap->dmtt_cl_start, roce_cap->dmtt_cl_end,
roce_cap->dmtt_cl_sz);
sdk_info(hwdev->dev_hdl, "Wqe_start=0x%x, wqe_end=0x%x, wqe_sz=0x%x\n",
roce_cap->wqe_cl_start, roce_cap->wqe_cl_end,
roce_cap->wqe_cl_sz);
if (roce_cap->max_qps == 0) {
roce_cap->max_qps = 1024;
roce_cap->max_cqs = 2048;
roce_cap->max_srqs = 1024;
roce_cap->max_mpts = 1024;
if (type == TYPE_PF || type == TYPE_PPF) {
roce_cap->vf_max_qps = 512;
roce_cap->vf_max_cqs = 1024;
roce_cap->vf_max_srqs = 512;
roce_cap->vf_max_mpts = 512;
}
}
}
static void parse_iwarp_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct dev_iwarp_svc_own_cap *iwarp_cap =
&cap->rdma_cap.dev_rdma_cap.iwarp_own_cap;
iwarp_cap->max_qps = dev_cap->iwarp_max_qp;
iwarp_cap->max_cqs = dev_cap->iwarp_max_cq;
iwarp_cap->max_mpts = dev_cap->iwarp_max_mpt;
iwarp_cap->num_cos = dev_cap->max_cos_id + 1;
/* PF/PPF */
if (type == TYPE_PF || type == TYPE_PPF) {
iwarp_cap->vf_max_qps = dev_cap->iwarp_vf_max_qp;
iwarp_cap->vf_max_cqs = dev_cap->iwarp_vf_max_cq;
iwarp_cap->vf_max_mpts = dev_cap->iwarp_vf_max_mpt;
} else {
iwarp_cap->vf_max_qps = 0;
iwarp_cap->vf_max_cqs = 0;
iwarp_cap->vf_max_mpts = 0;
}
iwarp_cap->cmtt_cl_start = dev_cap->iwarp_cmtt_cl_start;
iwarp_cap->cmtt_cl_end = dev_cap->iwarp_cmtt_cl_end;
iwarp_cap->cmtt_cl_sz = dev_cap->iwarp_cmtt_cl_size;
iwarp_cap->dmtt_cl_start = dev_cap->iwarp_dmtt_cl_start;
iwarp_cap->dmtt_cl_end = dev_cap->iwarp_dmtt_cl_end;
iwarp_cap->dmtt_cl_sz = dev_cap->iwarp_dmtt_cl_size;
iwarp_cap->wqe_cl_start = dev_cap->iwarp_wqe_cl_start;
iwarp_cap->wqe_cl_end = dev_cap->iwarp_wqe_cl_end;
iwarp_cap->wqe_cl_sz = dev_cap->iwarp_wqe_cl_size;
sdk_info(hwdev->dev_hdl, "Get iwrap resource capbility\n");
sdk_info(hwdev->dev_hdl, "Max_qps=0x%x, max_cqs=0x%x, max_mpts=0x%x\n",
iwarp_cap->max_qps, iwarp_cap->max_cqs,
iwarp_cap->max_mpts);
sdk_info(hwdev->dev_hdl, "Vf_max_qps=0x%x, vf_max_cqs=0x%x, vf_max_mpts=0x%x\n",
iwarp_cap->vf_max_qps, iwarp_cap->vf_max_cqs,
iwarp_cap->vf_max_mpts);
sdk_info(hwdev->dev_hdl, "Cmtt_start=0x%x, cmtt_end=0x%x, cmtt_sz=0x%x\n",
iwarp_cap->cmtt_cl_start, iwarp_cap->cmtt_cl_end,
iwarp_cap->cmtt_cl_sz);
sdk_info(hwdev->dev_hdl, "Dmtt_start=0x%x, dmtt_end=0x%x, dmtt_sz=0x%x\n",
iwarp_cap->dmtt_cl_start, iwarp_cap->dmtt_cl_end,
iwarp_cap->dmtt_cl_sz);
sdk_info(hwdev->dev_hdl, "Wqe_start=0x%x, wqe_end=0x%x, wqe_sz=0x%x\n",
iwarp_cap->wqe_cl_start, iwarp_cap->wqe_cl_end,
iwarp_cap->wqe_cl_sz);
if (iwarp_cap->max_qps == 0) {
iwarp_cap->max_qps = 8;
iwarp_cap->max_cqs = 16;
iwarp_cap->max_mpts = 8;
if (type == TYPE_PF || type == TYPE_PPF) {
iwarp_cap->vf_max_qps = 8;
iwarp_cap->vf_max_cqs = 16;
iwarp_cap->vf_max_mpts = 8;
}
}
}
static void parse_fcoe_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct dev_fcoe_svc_cap *fcoe_cap = &cap->fcoe_cap.dev_fcoe_cap;
fcoe_cap->max_qps = dev_cap->fcoe_max_qp;
fcoe_cap->max_cqs = dev_cap->fcoe_max_cq;
fcoe_cap->max_srqs = dev_cap->fcoe_max_srq;
fcoe_cap->max_cctxs = dev_cap->fcoe_max_cctx;
fcoe_cap->cctxs_id_start = dev_cap->fcoe_cctx_id_start;
fcoe_cap->vp_id_start = dev_cap->fcoe_vp_id_start;
fcoe_cap->vp_id_end = dev_cap->fcoe_vp_id_end;
sdk_info(hwdev->dev_hdl, "Get fcoe resource capbility\n");
sdk_info(hwdev->dev_hdl, "Max_qps=0x%x, max_cqs=0x%x, max_srqs=0x%x, max_cctxs=0x%x, cctxs_id_start=0x%x\n",
fcoe_cap->max_qps, fcoe_cap->max_cqs, fcoe_cap->max_srqs,
fcoe_cap->max_cctxs, fcoe_cap->cctxs_id_start);
sdk_info(hwdev->dev_hdl, "Vp_id_start=0x%x, vp_id_end=0x%x\n",
fcoe_cap->vp_id_start, fcoe_cap->vp_id_end);
}
static void parse_toe_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct dev_toe_svc_cap *toe_cap = &cap->toe_cap.dev_toe_cap;
toe_cap->max_pctxs = dev_cap->toe_max_pctx;
toe_cap->max_cqs = dev_cap->toe_max_cq;
toe_cap->max_srqs = dev_cap->toe_max_srq;
toe_cap->srq_id_start = dev_cap->toe_srq_id_start;
toe_cap->num_cos = dev_cap->max_cos_id + 1;
sdk_info(hwdev->dev_hdl, "Get toe resource capbility, max_pctxs=0x%x, max_cqs=0x%x, max_srqs=0x%x, srq_id_start=0x%x\n",
toe_cap->max_pctxs, toe_cap->max_cqs, toe_cap->max_srqs,
toe_cap->srq_id_start);
}
static void parse_fc_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct dev_fc_svc_cap *fc_cap = &cap->fc_cap.dev_fc_cap;
fc_cap->max_parent_qpc_num = dev_cap->fc_max_pctx;
fc_cap->scq_num = dev_cap->fc_max_scq;
fc_cap->srq_num = dev_cap->fc_max_srq;
fc_cap->max_child_qpc_num = dev_cap->fc_max_cctx;
fc_cap->child_qpc_id_start = dev_cap->fc_cctx_id_start;
fc_cap->vp_id_start = dev_cap->fc_vp_id_start;
fc_cap->vp_id_end = dev_cap->fc_vp_id_end;
sdk_info(hwdev->dev_hdl, "Get fc resource capbility\n");
sdk_info(hwdev->dev_hdl, "Max_parent_qpc_num=0x%x, scq_num=0x%x, srq_num=0x%x, max_child_qpc_num=0x%x, child_qpc_id_start=0x%x\n",
fc_cap->max_parent_qpc_num, fc_cap->scq_num, fc_cap->srq_num,
fc_cap->max_child_qpc_num, fc_cap->child_qpc_id_start);
sdk_info(hwdev->dev_hdl, "Vp_id_start=0x%x, vp_id_end=0x%x\n",
fc_cap->vp_id_start, fc_cap->vp_id_end);
}
static void parse_ovs_res_cap(struct hinic_hwdev *hwdev,
struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct ovs_service_cap *ovs_cap = &cap->ovs_cap;
ovs_cap->dev_ovs_cap.max_pctxs = dev_cap->ovs_max_qpc;
ovs_cap->dev_ovs_cap.max_cqs = 0;
if (type == TYPE_PF || type == TYPE_PPF)
ovs_cap->dev_ovs_cap.dynamic_qp_en = dev_cap->ovs_dq_en;
sdk_info(hwdev->dev_hdl, "Get ovs resource capbility, max_qpc: 0x%x\n",
ovs_cap->dev_ovs_cap.max_pctxs);
}
static void parse_acl_res_cap(struct service_cap *cap,
struct hinic_dev_cap *dev_cap,
enum func_type type)
{
struct acl_service_cap *acl_cap = &cap->acl_cap;
acl_cap->dev_acl_cap.max_pctxs = 1024 * 1024;
acl_cap->dev_acl_cap.max_cqs = 8;
}
static void parse_dev_cap(struct hinic_hwdev *dev,
struct hinic_dev_cap *dev_cap, enum func_type type)
{
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
/* Public resource */
parse_pub_res_cap(dev, cap, dev_cap, type);
/* PPF managed dynamic resource */
if (type == TYPE_PPF)
parse_dynamic_share_res_cap(dev, cap, dev_cap, type);
/* L2 NIC resource */
if (IS_NIC_TYPE(dev))
parse_l2nic_res_cap(dev, cap, dev_cap, type);
/* FCoE/IOE/TOE/FC without virtulization */
if (type == TYPE_PF || type == TYPE_PPF) {
if (IS_FC_TYPE(dev))
parse_fc_res_cap(dev, cap, dev_cap, type);
if (IS_FCOE_TYPE(dev))
parse_fcoe_res_cap(dev, cap, dev_cap, type);
if (IS_TOE_TYPE(dev))
parse_toe_res_cap(dev, cap, dev_cap, type);
}
/* RoCE resource */
if (IS_ROCE_TYPE(dev))
parse_roce_res_cap(dev, cap, dev_cap, type);
/* iWARP resource */
if (IS_IWARP_TYPE(dev))
parse_iwarp_res_cap(dev, cap, dev_cap, type);
if (IS_OVS_TYPE(dev))
parse_ovs_res_cap(dev, cap, dev_cap, type);
if (IS_ACL_TYPE(dev))
parse_acl_res_cap(cap, dev_cap, type);
}
static int get_cap_from_fw(struct hinic_hwdev *dev, enum func_type type)
{
struct hinic_dev_cap dev_cap = {0};
u16 out_len = sizeof(dev_cap);
int err;
dev_cap.version = HINIC_CMD_VER_FUNC_ID;
err = hinic_global_func_id_get(dev, &dev_cap.func_id);
if (err)
return err;
sdk_info(dev->dev_hdl, "Get cap from fw, func_idx: %d\n",
dev_cap.func_id);
err = hinic_msg_to_mgmt_sync(dev, HINIC_MOD_CFGM, HINIC_CFG_NIC_CAP,
&dev_cap, sizeof(dev_cap),
&dev_cap, &out_len, 0);
if (err || dev_cap.status || !out_len) {
sdk_err(dev->dev_hdl,
"Failed to get capability from FW, err: %d, status: 0x%x, out size: 0x%x\n",
err, dev_cap.status, out_len);
return -EFAULT;
}
parse_dev_cap(dev, &dev_cap, type);
return 0;
}
static int get_cap_from_pf(struct hinic_hwdev *dev, enum func_type type)
{
struct hinic_dev_cap dev_cap = {0};
u16 in_len, out_len;
int err;
in_len = sizeof(dev_cap);
out_len = in_len;
err = hinic_msg_to_mgmt_sync(dev, HINIC_MOD_CFGM, HINIC_CFG_MBOX_CAP,
&dev_cap, in_len, &dev_cap, &out_len, 0);
if (err || dev_cap.status || !out_len) {
sdk_err(dev->dev_hdl, "Failed to get capability from PF, err: %d, status: 0x%x, out size: 0x%x\n",
err, dev_cap.status, out_len);
return -EFAULT;
}
parse_dev_cap(dev, &dev_cap, type);
return 0;
}
static int get_dev_cap(struct hinic_hwdev *dev)
{
int err;
enum func_type type = HINIC_FUNC_TYPE(dev);
switch (type) {
case TYPE_PF:
case TYPE_PPF:
err = get_cap_from_fw(dev, type);
if (err) {
sdk_err(dev->dev_hdl, "Failed to get PF/PPF capability\n");
return err;
}
break;
case TYPE_VF:
err = get_cap_from_pf(dev, type);
if (err) {
sdk_err(dev->dev_hdl, "Failed to get VF capability\n");
return err;
}
break;
default:
sdk_err(dev->dev_hdl, "Unsupported PCI Function type: %d\n",
type);
return -EINVAL;
}
return 0;
}
static void nic_param_fix(struct hinic_hwdev *dev)
{
struct nic_service_cap *nic_cap = &dev->cfg_mgmt->svc_cap.nic_cap;
if ((hinic_func_type(dev) == TYPE_VF) &&
nic_cap->max_queue_allowed != 0) {
nic_cap->max_rqs = nic_cap->max_queue_allowed;
nic_cap->max_sqs = nic_cap->max_queue_allowed;
}
}
static void rdma_param_fix(struct hinic_hwdev *dev)
{
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
struct rdma_service_cap *rdma_cap = &cap->rdma_cap;
struct dev_roce_svc_own_cap *roce_cap =
&rdma_cap->dev_rdma_cap.roce_own_cap;
struct dev_iwarp_svc_own_cap *iwarp_cap =
&rdma_cap->dev_rdma_cap.iwarp_own_cap;
rdma_cap->log_mtt = LOG_MTT_SEG;
rdma_cap->log_rdmarc = LOG_RDMARC_SEG;
rdma_cap->reserved_qps = RDMA_RSVD_QPS;
rdma_cap->max_sq_sg = RDMA_MAX_SQ_SGE;
/* RoCE */
if (IS_ROCE_TYPE(dev)) {
roce_cap->qpc_entry_sz = ROCE_QPC_ENTRY_SZ;
roce_cap->max_wqes = ROCE_MAX_WQES;
roce_cap->max_rq_sg = ROCE_MAX_RQ_SGE;
roce_cap->max_sq_inline_data_sz = ROCE_MAX_SQ_INLINE_DATA_SZ;
roce_cap->max_rq_desc_sz = ROCE_MAX_RQ_DESC_SZ;
roce_cap->rdmarc_entry_sz = ROCE_RDMARC_ENTRY_SZ;
roce_cap->max_qp_init_rdma = ROCE_MAX_QP_INIT_RDMA;
roce_cap->max_qp_dest_rdma = ROCE_MAX_QP_DEST_RDMA;
roce_cap->max_srq_wqes = ROCE_MAX_SRQ_WQES;
roce_cap->reserved_srqs = ROCE_RSVD_SRQS;
roce_cap->max_srq_sge = ROCE_MAX_SRQ_SGE;
roce_cap->srqc_entry_sz = ROCE_SRQC_ENTERY_SZ;
roce_cap->max_msg_sz = ROCE_MAX_MSG_SZ;
} else {
iwarp_cap->qpc_entry_sz = IWARP_QPC_ENTRY_SZ;
iwarp_cap->max_wqes = IWARP_MAX_WQES;
iwarp_cap->max_rq_sg = IWARP_MAX_RQ_SGE;
iwarp_cap->max_sq_inline_data_sz = IWARP_MAX_SQ_INLINE_DATA_SZ;
iwarp_cap->max_rq_desc_sz = IWARP_MAX_RQ_DESC_SZ;
iwarp_cap->max_irq_depth = IWARP_MAX_IRQ_DEPTH;
iwarp_cap->irq_entry_size = IWARP_IRQ_ENTRY_SZ;
iwarp_cap->max_orq_depth = IWARP_MAX_ORQ_DEPTH;
iwarp_cap->orq_entry_size = IWARP_ORQ_ENTRY_SZ;
iwarp_cap->max_rtoq_depth = IWARP_MAX_RTOQ_DEPTH;
iwarp_cap->rtoq_entry_size = IWARP_RTOQ_ENTRY_SZ;
iwarp_cap->max_ackq_depth = IWARP_MAX_ACKQ_DEPTH;
iwarp_cap->ackq_entry_size = IWARP_ACKQ_ENTRY_SZ;
iwarp_cap->max_msg_sz = IWARP_MAX_MSG_SZ;
}
rdma_cap->max_sq_desc_sz = RDMA_MAX_SQ_DESC_SZ;
rdma_cap->wqebb_size = WQEBB_SZ;
rdma_cap->max_cqes = RDMA_MAX_CQES;
rdma_cap->reserved_cqs = RDMA_RSVD_CQS;
rdma_cap->cqc_entry_sz = RDMA_CQC_ENTRY_SZ;
rdma_cap->cqe_size = RDMA_CQE_SZ;
rdma_cap->reserved_mrws = RDMA_RSVD_MRWS;
rdma_cap->mpt_entry_sz = RDMA_MPT_ENTRY_SZ;
/* 2^8 - 1
* +------------------------+-----------+
* | 4B | 1M(20b) | Key(8b) |
* +------------------------+-----------+
* key = 8bit key + 24bit index,
* now Lkey of SGE uses 2bit(bit31 and bit30), so key only have 10bit,
* we use original 8bits directly for simpilification
*/
rdma_cap->max_fmr_maps = 255;
rdma_cap->num_mtts = (g_rdma_mtts_num > 0 ?
g_rdma_mtts_num : RDMA_NUM_MTTS);
rdma_cap->log_mtt_seg = LOG_MTT_SEG;
rdma_cap->mtt_entry_sz = MTT_ENTRY_SZ;
rdma_cap->log_rdmarc_seg = LOG_RDMARC_SEG;
rdma_cap->local_ca_ack_delay = LOCAL_ACK_DELAY;
rdma_cap->num_ports = RDMA_NUM_PORTS;
rdma_cap->db_page_size = DB_PAGE_SZ;
rdma_cap->direct_wqe_size = DWQE_SZ;
rdma_cap->num_pds = NUM_PD;
rdma_cap->reserved_pds = RSVD_PD;
rdma_cap->max_xrcds = MAX_XRCDS;
rdma_cap->reserved_xrcds = RSVD_XRCDS;
rdma_cap->max_gid_per_port = MAX_GID_PER_PORT;
rdma_cap->gid_entry_sz = GID_ENTRY_SZ;
rdma_cap->reserved_lkey = RSVD_LKEY;
rdma_cap->num_comp_vectors = (u32)dev->cfg_mgmt->eq_info.num_ceq;
rdma_cap->page_size_cap = PAGE_SZ_CAP;
rdma_cap->flags = (RDMA_BMME_FLAG_LOCAL_INV |
RDMA_BMME_FLAG_REMOTE_INV |
RDMA_BMME_FLAG_FAST_REG_WR |
RDMA_DEV_CAP_FLAG_XRC |
RDMA_DEV_CAP_FLAG_MEM_WINDOW |
RDMA_BMME_FLAG_TYPE_2_WIN |
RDMA_BMME_FLAG_WIN_TYPE_2B |
RDMA_DEV_CAP_FLAG_ATOMIC);
rdma_cap->max_frpl_len = MAX_FRPL_LEN;
rdma_cap->max_pkeys = MAX_PKEYS;
}
static void fcoe_param_fix(struct hinic_hwdev *dev)
{
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
struct fcoe_service_cap *fcoe_cap = &cap->fcoe_cap;
fcoe_cap->qpc_basic_size = FCOE_PCTX_SZ;
fcoe_cap->childc_basic_size = FCOE_CCTX_SZ;
fcoe_cap->sqe_size = FCOE_SQE_SZ;
fcoe_cap->scqc_basic_size = FCOE_SCQC_SZ;
fcoe_cap->scqe_size = FCOE_SCQE_SZ;
fcoe_cap->srqc_size = FCOE_SRQC_SZ;
fcoe_cap->srqe_size = FCOE_SRQE_SZ;
}
static void toe_param_fix(struct hinic_hwdev *dev)
{
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
struct toe_service_cap *toe_cap = &cap->toe_cap;
toe_cap->pctx_sz = TOE_PCTX_SZ;
toe_cap->scqc_sz = TOE_CQC_SZ;
}
static void fc_param_fix(struct hinic_hwdev *dev)
{
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
struct fc_service_cap *fc_cap = &cap->fc_cap;
fc_cap->parent_qpc_size = FC_PCTX_SZ;
fc_cap->child_qpc_size = FC_CCTX_SZ;
fc_cap->sqe_size = FC_SQE_SZ;
fc_cap->scqc_size = FC_SCQC_SZ;
fc_cap->scqe_size = FC_SCQE_SZ;
fc_cap->srqc_size = FC_SRQC_SZ;
fc_cap->srqe_size = FC_SRQE_SZ;
}
static void ovs_param_fix(struct hinic_hwdev *dev)
{
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
struct ovs_service_cap *ovs_cap = &cap->ovs_cap;
ovs_cap->pctx_sz = OVS_PCTX_SZ;
ovs_cap->scqc_sz = OVS_SCQC_SZ;
}
static void acl_param_fix(struct hinic_hwdev *dev)
{
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
struct acl_service_cap *acl_cap = &cap->acl_cap;
acl_cap->pctx_sz = ACL_PCTX_SZ;
acl_cap->scqc_sz = ACL_SCQC_SZ;
}
static void init_service_param(struct hinic_hwdev *dev)
{
if (IS_NIC_TYPE(dev))
nic_param_fix(dev);
if (IS_RDMA_TYPE(dev))
rdma_param_fix(dev);
if (IS_FCOE_TYPE(dev))
fcoe_param_fix(dev);
if (IS_TOE_TYPE(dev))
toe_param_fix(dev);
if (IS_FC_TYPE(dev))
fc_param_fix(dev);
if (IS_OVS_TYPE(dev))
ovs_param_fix(dev);
if (IS_ACL_TYPE(dev))
acl_param_fix(dev);
}
static void cfg_get_eq_num(struct hinic_hwdev *dev)
{
struct cfg_eq_info *eq_info = &dev->cfg_mgmt->eq_info;
eq_info->num_ceq = dev->hwif->attr.num_ceqs;
eq_info->num_ceq_remain = eq_info->num_ceq;
}
static int cfg_init_eq(struct hinic_hwdev *dev)
{
struct cfg_mgmt_info *cfg_mgmt = dev->cfg_mgmt;
struct cfg_eq *eq;
u8 num_ceq, i = 0;
cfg_get_eq_num(dev);
num_ceq = cfg_mgmt->eq_info.num_ceq;
sdk_info(dev->dev_hdl, "Cfg mgmt: ceqs=0x%x, remain=0x%x\n",
cfg_mgmt->eq_info.num_ceq, cfg_mgmt->eq_info.num_ceq_remain);
if (!num_ceq) {
sdk_err(dev->dev_hdl, "Ceq num cfg in fw is zero\n");
return -EFAULT;
}
eq = kcalloc(num_ceq, sizeof(*eq), GFP_KERNEL);
if (!eq)
return -ENOMEM;
for (i = 0; i < num_ceq; ++i) {
eq[i].eqn = i;
eq[i].free = CFG_FREE;
eq[i].type = SERVICE_T_MAX;
}
cfg_mgmt->eq_info.eq = eq;
mutex_init(&cfg_mgmt->eq_info.eq_mutex);
return 0;
}
int hinic_dev_ver_info(void *hwdev, struct dev_version_info *ver)
{
struct hinic_hwdev *dev = hwdev;
struct cfg_mgmt_info *cfg_mgmt;
if (!hwdev || !ver)
return -EINVAL;
cfg_mgmt = dev->cfg_mgmt;
memcpy(ver, &cfg_mgmt->svc_cap.dev_ver_info, sizeof(*ver));
return 0;
}
EXPORT_SYMBOL(hinic_dev_ver_info);
int hinic_vector_to_eqn(void *hwdev, enum hinic_service_type type, int vector)
{
struct hinic_hwdev *dev = hwdev;
struct cfg_mgmt_info *cfg_mgmt;
struct cfg_eq *eq;
int eqn = -EINVAL;
if (!hwdev || vector < 0)
return -EINVAL;
if (type != SERVICE_T_ROCE && type != SERVICE_T_IWARP) {
sdk_err(dev->dev_hdl,
"Service type: %d, only RDMA service could get eqn by vector\n",
type);
return -EINVAL;
}
cfg_mgmt = dev->cfg_mgmt;
vector = (vector % cfg_mgmt->eq_info.num_ceq) + CFG_RDMA_CEQ_BASE;
eq = cfg_mgmt->eq_info.eq;
if ((eq[vector].type == SERVICE_T_ROCE ||
eq[vector].type == SERVICE_T_IWARP) &&
eq[vector].free == CFG_BUSY)
eqn = eq[vector].eqn;
return eqn;
}
EXPORT_SYMBOL(hinic_vector_to_eqn);
static int cfg_init_interrupt(struct hinic_hwdev *dev)
{
struct cfg_mgmt_info *cfg_mgmt = dev->cfg_mgmt;
struct cfg_irq_info *irq_info = &cfg_mgmt->irq_param_info;
u16 intr_num = dev->hwif->attr.num_irqs;
if (!intr_num) {
sdk_err(dev->dev_hdl, "Irq num cfg in fw is zero\n");
return -EFAULT;
}
irq_info->alloc_info = kcalloc(intr_num, sizeof(*irq_info->alloc_info),
GFP_KERNEL);
if (!irq_info->alloc_info)
return -ENOMEM;
irq_info->num_irq_hw = intr_num;
/* Production requires VF only surppots MSI-X */
if (HINIC_FUNC_TYPE(dev) == TYPE_VF)
cfg_mgmt->svc_cap.interrupt_type = INTR_TYPE_MSIX;
else
cfg_mgmt->svc_cap.interrupt_type = intr_mode;
mutex_init(&irq_info->irq_mutex);
return 0;
}
static int cfg_enable_interrupt(struct hinic_hwdev *dev)
{
struct cfg_mgmt_info *cfg_mgmt = dev->cfg_mgmt;
u16 nreq = cfg_mgmt->irq_param_info.num_irq_hw;
void *pcidev = dev->pcidev_hdl;
struct irq_alloc_info_st *irq_info;
struct msix_entry *entry;
u16 i = 0;
int actual_irq;
irq_info = cfg_mgmt->irq_param_info.alloc_info;
sdk_info(dev->dev_hdl, "Interrupt type: %d, irq num: %d\n",
cfg_mgmt->svc_cap.interrupt_type, nreq);
switch (cfg_mgmt->svc_cap.interrupt_type) {
case INTR_TYPE_MSIX:
if (!nreq) {
sdk_err(dev->dev_hdl, "Interrupt number cannot be zero\n");
return -EINVAL;
}
entry = kcalloc(nreq, sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
for (i = 0; i < nreq; i++)
entry[i].entry = i;
actual_irq = pci_enable_msix_range(pcidev, entry,
VECTOR_THRESHOLD, nreq);
if (actual_irq < 0) {
sdk_err(dev->dev_hdl, "Alloc msix entries with threshold 2 failed\n");
kfree(entry);
return -ENOMEM;
}
nreq = (u16)actual_irq;
cfg_mgmt->irq_param_info.num_total = nreq;
cfg_mgmt->irq_param_info.num_irq_remain = nreq;
sdk_info(dev->dev_hdl, "Request %d msix vector success\n",
nreq);
for (i = 0; i < nreq; ++i) {
/* u16 driver uses to specify entry, OS writes */
irq_info[i].info.msix_entry_idx = entry[i].entry;
/* u32 kernel uses to write allocated vector */
irq_info[i].info.irq_id = entry[i].vector;
irq_info[i].type = SERVICE_T_MAX;
irq_info[i].free = CFG_FREE;
}
kfree(entry);
break;
default:
sdk_err(dev->dev_hdl, "Unsupport interrupt type %d\n",
cfg_mgmt->svc_cap.interrupt_type);
break;
}
return 0;
}
int hinic_alloc_irqs(void *hwdev, enum hinic_service_type type, u16 num,
struct irq_info *irq_info_array, u16 *act_num)
{
struct hinic_hwdev *dev = hwdev;
struct cfg_mgmt_info *cfg_mgmt;
struct cfg_irq_info *irq_info;
struct irq_alloc_info_st *alloc_info;
int max_num_irq;
u16 free_num_irq;
int i, j;
if (!hwdev || !irq_info_array || !act_num)
return -EINVAL;
cfg_mgmt = dev->cfg_mgmt;
irq_info = &cfg_mgmt->irq_param_info;
alloc_info = irq_info->alloc_info;
max_num_irq = irq_info->num_total;
free_num_irq = irq_info->num_irq_remain;
mutex_lock(&irq_info->irq_mutex);
if (num > free_num_irq) {
if (free_num_irq == 0) {
sdk_err(dev->dev_hdl,
"no free irq resource in cfg mgmt\n");
mutex_unlock(&irq_info->irq_mutex);
return -ENOMEM;
}
sdk_warn(dev->dev_hdl, "only %d irq resource in cfg mgmt\n",
free_num_irq);
num = free_num_irq;
}
*act_num = 0;
for (i = 0; i < num; i++) {
for (j = 0; j < max_num_irq; j++) {
if (alloc_info[j].free == CFG_FREE) {
if (irq_info->num_irq_remain == 0) {
sdk_err(dev->dev_hdl, "No free irq resource in cfg mgmt\n");
mutex_unlock(&irq_info->irq_mutex);
return -EINVAL;
}
alloc_info[j].type = type;
alloc_info[j].free = CFG_BUSY;
irq_info_array[i].msix_entry_idx =
alloc_info[j].info.msix_entry_idx;
irq_info_array[i].irq_id =
alloc_info[j].info.irq_id;
(*act_num)++;
irq_info->num_irq_remain--;
break;
}
}
}
mutex_unlock(&irq_info->irq_mutex);
return 0;
}
EXPORT_SYMBOL(hinic_alloc_irqs);
void hinic_free_irq(void *hwdev, enum hinic_service_type type, u32 irq_id)
{
struct hinic_hwdev *dev = hwdev;
struct cfg_mgmt_info *cfg_mgmt;
struct cfg_irq_info *irq_info;
struct irq_alloc_info_st *alloc_info;
int max_num_irq;
int i;
if (!hwdev)
return;
cfg_mgmt = dev->cfg_mgmt;
irq_info = &cfg_mgmt->irq_param_info;
alloc_info = irq_info->alloc_info;
max_num_irq = irq_info->num_total;
mutex_lock(&irq_info->irq_mutex);
for (i = 0; i < max_num_irq; i++) {
if (irq_id == alloc_info[i].info.irq_id &&
type == alloc_info[i].type) {
if (alloc_info[i].free == CFG_BUSY) {
alloc_info[i].free = CFG_FREE;
irq_info->num_irq_remain++;
if (irq_info->num_irq_remain > max_num_irq) {
sdk_err(dev->dev_hdl, "Find target, but over range\n");
mutex_unlock(&irq_info->irq_mutex);
return;
}
break;
}
}
}
if (i >= max_num_irq)
sdk_warn(dev->dev_hdl, "Irq %d don't need to free\n", irq_id);
mutex_unlock(&irq_info->irq_mutex);
}
EXPORT_SYMBOL(hinic_free_irq);
int hinic_vector_to_irq(void *hwdev, enum hinic_service_type type, int vector)
{
struct hinic_hwdev *dev = hwdev;
struct cfg_mgmt_info *cfg_mgmt;
struct irq_alloc_info_st *irq_info;
int irq = -EINVAL;
if (!hwdev)
return -EINVAL;
cfg_mgmt = dev->cfg_mgmt;
if (type != SERVICE_T_ROCE && type != SERVICE_T_IWARP) {
sdk_err(dev->dev_hdl,
"Service type: %u, only RDMA service could get eqn by vector\n",
type);
return -EINVAL;
}
/* Current RDMA CEQ are 2 - 31, will change in the future */
vector = ((vector % cfg_mgmt->eq_info.num_ceq) + CFG_RDMA_CEQ_BASE);
irq_info = cfg_mgmt->irq_param_info.alloc_info;
if (irq_info[vector].type == SERVICE_T_ROCE ||
irq_info[vector].type == SERVICE_T_IWARP)
if (irq_info[vector].free == CFG_BUSY)
irq = (int)irq_info[vector].info.irq_id;
return irq;
}
EXPORT_SYMBOL(hinic_vector_to_irq);
int hinic_alloc_ceqs(void *hwdev, enum hinic_service_type type, int num,
int *ceq_id_array, int *act_num)
{
struct hinic_hwdev *dev = hwdev;
struct cfg_mgmt_info *cfg_mgmt;
struct cfg_eq_info *eq;
int free_ceq;
int i, j;
if (!hwdev || !ceq_id_array || !act_num)
return -EINVAL;
cfg_mgmt = dev->cfg_mgmt;
eq = &cfg_mgmt->eq_info;
free_ceq = eq->num_ceq_remain;
mutex_lock(&eq->eq_mutex);
if (num > free_ceq) {
if (free_ceq <= 0) {
sdk_err(dev->dev_hdl, "No free ceq resource in cfg mgmt\n");
mutex_unlock(&eq->eq_mutex);
return -ENOMEM;
}
sdk_warn(dev->dev_hdl, "Only %d ceq resource in cfg mgmt\n",
free_ceq);
}
*act_num = 0;
num = min(num, eq->num_ceq - CFG_RDMA_CEQ_BASE);
for (i = 0; i < num; i++) {
if (eq->num_ceq_remain == 0) {
sdk_warn(dev->dev_hdl, "Alloc %d ceqs, less than required %d ceqs\n",
*act_num, num);
mutex_unlock(&eq->eq_mutex);
return 0;
}
for (j = CFG_RDMA_CEQ_BASE; j < eq->num_ceq; j++) {
if (eq->eq[j].free == CFG_FREE) {
eq->eq[j].type = type;
eq->eq[j].free = CFG_BUSY;
eq->num_ceq_remain--;
ceq_id_array[i] = eq->eq[j].eqn;
(*act_num)++;
break;
}
}
}
mutex_unlock(&eq->eq_mutex);
return 0;
}
EXPORT_SYMBOL(hinic_alloc_ceqs);
void hinic_free_ceq(void *hwdev, enum hinic_service_type type, int ceq_id)
{
struct hinic_hwdev *dev = hwdev;
struct cfg_mgmt_info *cfg_mgmt;
struct cfg_eq_info *eq;
u8 num_ceq;
u8 i = 0;
if (!hwdev)
return;
cfg_mgmt = dev->cfg_mgmt;
eq = &cfg_mgmt->eq_info;
num_ceq = eq->num_ceq;
mutex_lock(&eq->eq_mutex);
for (i = 0; i < num_ceq; i++) {
if (ceq_id == eq->eq[i].eqn &&
type == cfg_mgmt->eq_info.eq[i].type) {
if (eq->eq[i].free == CFG_BUSY) {
eq->eq[i].free = CFG_FREE;
eq->num_ceq_remain++;
if (eq->num_ceq_remain > num_ceq)
eq->num_ceq_remain %= num_ceq;
mutex_unlock(&eq->eq_mutex);
return;
}
}
}
if (i >= num_ceq)
sdk_warn(dev->dev_hdl, "ceq %d don't need to free\n", ceq_id);
mutex_unlock(&eq->eq_mutex);
}
EXPORT_SYMBOL(hinic_free_ceq);
static int cfg_mbx_pf_proc_vf_msg(void *hwdev, u16 vf_id, u8 cmd, void *buf_in,
u16 in_size, void *buf_out, u16 *out_size)
{
struct hinic_hwdev *dev = hwdev;
struct hinic_dev_cap *dev_cap = buf_out;
struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
struct nic_service_cap *nic_cap = &cap->nic_cap;
struct dev_roce_svc_own_cap *roce_cap =
&cap->rdma_cap.dev_rdma_cap.roce_own_cap;
struct dev_iwarp_svc_own_cap *iwarp_cap =
&cap->rdma_cap.dev_rdma_cap.iwarp_own_cap;
struct dev_ovs_svc_cap *ovs_cap = &cap->ovs_cap.dev_ovs_cap;
struct hinic_dev_cap dev_cap_tmp = {0};
u16 out_len = 0;
u16 func_id;
int err;
memset(dev_cap, 0, sizeof(*dev_cap));
if (cap->sf_svc_attr.ft_en)
dev_cap->sf_svc_attr |= SF_SVC_FT_BIT;
else
dev_cap->sf_svc_attr &= ~SF_SVC_FT_BIT;
if (cap->sf_svc_attr.rdma_en)
dev_cap->sf_svc_attr |= SF_SVC_RDMA_BIT;
else
dev_cap->sf_svc_attr &= ~SF_SVC_RDMA_BIT;
dev_cap->sf_en_vf = cap->sf_svc_attr.sf_en_vf;
dev_cap->host_id = cap->host_id;
dev_cap->ep_id = cap->ep_id;
dev_cap->intr_type = cap->interrupt_type;
dev_cap->max_cos_id = cap->max_cos_id;
dev_cap->er_id = cap->er_id;
dev_cap->port_id = cap->port_id;
dev_cap->max_vf = cap->max_vf;
dev_cap->svc_cap_en = cap->chip_svc_type;
dev_cap->host_total_func = cap->host_total_function;
dev_cap->host_oq_id_mask_val = cap->host_oq_id_mask_val;
dev_cap->net_port_mode = cap->net_port_mode;
/* Parameters below is uninitialized because NIC and ROCE not use it
* max_connect_num
* max_stick2cache_num
* bfilter_start_addr
* bfilter_len
* hash_bucket_num
* cfg_file_ver
*/
/* NIC VF resources */
dev_cap->nic_max_sq = nic_cap->vf_max_sqs;
dev_cap->nic_max_rq = nic_cap->vf_max_rqs;
/* ROCE VF resources */
dev_cap->roce_max_qp = roce_cap->vf_max_qps;
dev_cap->roce_max_cq = roce_cap->vf_max_cqs;
dev_cap->roce_max_srq = roce_cap->vf_max_srqs;
dev_cap->roce_max_mpt = roce_cap->vf_max_mpts;
dev_cap->roce_cmtt_cl_start = roce_cap->cmtt_cl_start;
dev_cap->roce_cmtt_cl_end = roce_cap->cmtt_cl_end;
dev_cap->roce_cmtt_cl_size = roce_cap->cmtt_cl_sz;
dev_cap->roce_dmtt_cl_start = roce_cap->dmtt_cl_start;
dev_cap->roce_dmtt_cl_end = roce_cap->dmtt_cl_end;
dev_cap->roce_dmtt_cl_size = roce_cap->dmtt_cl_sz;
dev_cap->roce_wqe_cl_start = roce_cap->wqe_cl_start;
dev_cap->roce_wqe_cl_end = roce_cap->wqe_cl_end;
dev_cap->roce_wqe_cl_size = roce_cap->wqe_cl_sz;
/* Iwarp VF resources */
dev_cap->iwarp_max_qp = iwarp_cap->vf_max_qps;
dev_cap->iwarp_max_cq = iwarp_cap->vf_max_cqs;
dev_cap->iwarp_max_mpt = iwarp_cap->vf_max_mpts;
/* OVS VF resources */
dev_cap->ovs_max_qpc = ovs_cap->max_pctxs;
dev_cap->ovs_dq_en = ovs_cap->dynamic_qp_en;
*out_size = sizeof(*dev_cap);
if (!IS_OVS_TYPE(dev))
return 0;
out_len = sizeof(dev_cap_tmp);
/* fixed qnum in ovs mode */
func_id = vf_id + hinic_glb_pf_vf_offset(hwdev);
dev_cap_tmp.func_id = func_id;
err = hinic_pf_msg_to_mgmt_sync(dev, HINIC_MOD_CFGM, HINIC_CFG_FUNC_CAP,
&dev_cap_tmp, sizeof(dev_cap_tmp),
&dev_cap_tmp, &out_len, 0);
if (err && err != HINIC_DEV_BUSY_ACTIVE_FW &&
err != HINIC_MBOX_PF_BUSY_ACTIVE_FW) {
sdk_err(dev->dev_hdl,
"Get func_id: %u capability from FW failed, err: %d, status: 0x%x, out_size: 0x%x\n",
func_id, err, dev_cap_tmp.status, out_len);
return -EFAULT;
} else if (err) {
return err;
}
dev_cap->nic_max_sq = dev_cap_tmp.nic_max_sq + 1;
dev_cap->nic_max_rq = dev_cap_tmp.nic_max_rq + 1;
dev_cap->max_queue_allowed = dev_cap_tmp.max_queue_allowed;
sdk_info(dev->dev_hdl, "func_id(%u) %s qnum %u max_queue_allowed %u\n",
func_id, (ovs_cap->dynamic_qp_en ? "dynamic" : "fixed"),
dev_cap->nic_max_sq, dev_cap->max_queue_allowed);
return 0;
}
static int cfg_mbx_ppf_proc_msg(void *hwdev, u16 pf_id, u16 vf_id, u8 cmd,
void *buf_in, u16 in_size, void *buf_out,
u16 *out_size)
{
struct hinic_hwdev *dev = hwdev;
sdk_info(dev->dev_hdl, "ppf receive other pf cfgmgmt cmd %d mbox msg\n",
cmd);
return hinic_ppf_process_mbox_msg(hwdev, pf_id, vf_id, HINIC_MOD_CFGM,
cmd, buf_in, in_size, buf_out,
out_size);
}
static int cfg_mbx_vf_proc_msg(void *hwdev, u8 cmd, void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hinic_hwdev *dev = hwdev;
*out_size = 0;
sdk_err(dev->dev_hdl, "VF msg callback not supported\n");
return -EOPNOTSUPP;
}
static int cfg_mbx_init(struct hinic_hwdev *dev, struct cfg_mgmt_info *cfg_mgmt)
{
int err;
enum func_type type = dev->hwif->attr.func_type;
if (type == TYPE_PF) {
err = hinic_register_pf_mbox_cb(dev, HINIC_MOD_CFGM,
cfg_mbx_pf_proc_vf_msg);
if (err) {
sdk_err(dev->dev_hdl,
"PF: Register PF mailbox callback failed\n");
return err;
}
} else if (type == TYPE_PPF) {
err = hinic_register_ppf_mbox_cb(dev, HINIC_MOD_CFGM,
cfg_mbx_ppf_proc_msg);
if (err) {
sdk_err(dev->dev_hdl,
"PPF: Register PPF mailbox callback failed\n");
return err;
}
err = hinic_register_pf_mbox_cb(dev, HINIC_MOD_CFGM,
cfg_mbx_pf_proc_vf_msg);
if (err) {
sdk_err(dev->dev_hdl,
"PPF: Register PF mailbox callback failed\n");
hinic_unregister_ppf_mbox_cb(dev, HINIC_MOD_CFGM);
return err;
}
} else if (type == TYPE_VF) {
err = hinic_register_vf_mbox_cb(dev, HINIC_MOD_CFGM,
cfg_mbx_vf_proc_msg);
if (err) {
sdk_err(dev->dev_hdl,
"VF: Register VF mailbox callback failed\n");
return err;
}
} else {
sdk_err(dev->dev_hdl, "Invalid func_type: %d, not supported\n",
type);
return -EINVAL;
}
return 0;
}
static void cfg_mbx_cleanup(struct hinic_hwdev *dev)
{
hinic_unregister_ppf_mbox_cb(dev, HINIC_MOD_CFGM);
hinic_unregister_pf_mbox_cb(dev, HINIC_MOD_CFGM);
hinic_unregister_vf_mbox_cb(dev, HINIC_MOD_CFGM);
}
static int init_cfg_mgmt(struct hinic_hwdev *dev)
{
int err;
struct cfg_mgmt_info *cfg_mgmt;
cfg_mgmt = kzalloc(sizeof(*cfg_mgmt), GFP_KERNEL);
if (!cfg_mgmt)
return -ENOMEM;
dev->cfg_mgmt = cfg_mgmt;
cfg_mgmt->hwdev = dev;
err = cfg_init_eq(dev);
if (err) {
sdk_err(dev->dev_hdl, "Failed to init cfg event queue, err: %d\n",
err);
goto free_mgmt_mem;
}
err = cfg_init_interrupt(dev);
if (err) {
sdk_err(dev->dev_hdl, "Failed to init cfg interrupt, err: %d\n",
err);
goto free_eq_mem;
}
err = cfg_enable_interrupt(dev);
if (err) {
sdk_err(dev->dev_hdl, "Failed to enable cfg interrupt, err: %d\n",
err);
goto free_interrupt_mem;
}
return 0;
free_interrupt_mem:
kfree(cfg_mgmt->irq_param_info.alloc_info);
cfg_mgmt->irq_param_info.alloc_info = NULL;
free_eq_mem:
kfree(cfg_mgmt->eq_info.eq);
cfg_mgmt->eq_info.eq = NULL;
free_mgmt_mem:
kfree(cfg_mgmt);
return err;
}
static void free_cfg_mgmt(struct hinic_hwdev *dev)
{
struct cfg_mgmt_info *cfg_mgmt = dev->cfg_mgmt;
/* if the allocated resource were recycled */
if (cfg_mgmt->irq_param_info.num_irq_remain !=
cfg_mgmt->irq_param_info.num_total ||
cfg_mgmt->eq_info.num_ceq_remain != cfg_mgmt->eq_info.num_ceq)
sdk_err(dev->dev_hdl, "Can't reclaim all irq and event queue, please check\n");
switch (cfg_mgmt->svc_cap.interrupt_type) {
case INTR_TYPE_MSIX:
pci_disable_msix(dev->pcidev_hdl);
break;
case INTR_TYPE_MSI:
pci_disable_msi(dev->pcidev_hdl);
break;
case INTR_TYPE_INT:
default:
break;
}
kfree(cfg_mgmt->irq_param_info.alloc_info);
cfg_mgmt->irq_param_info.alloc_info = NULL;
kfree(cfg_mgmt->eq_info.eq);
cfg_mgmt->eq_info.eq = NULL;
kfree(cfg_mgmt);
}
static int init_capability(struct hinic_hwdev *dev)
{
struct cfg_mgmt_info *cfg_mgmt = dev->cfg_mgmt;
int err;
set_cfg_test_param(cfg_mgmt);
err = cfg_mbx_init(dev, cfg_mgmt);
if (err) {
sdk_err(dev->dev_hdl, "Configure mailbox init failed, err: %d\n",
err);
return err;
}
cfg_mgmt->svc_cap.sf_svc_attr.ft_pf_en = false;
cfg_mgmt->svc_cap.sf_svc_attr.rdma_pf_en = false;
err = get_dev_cap(dev);
if (err) {
cfg_mbx_cleanup(dev);
return err;
}
init_service_param(dev);
sdk_info(dev->dev_hdl, "Init capability success\n");
return 0;
}
static void free_capability(struct hinic_hwdev *dev)
{
cfg_mbx_cleanup(dev);
sdk_info(dev->dev_hdl, "Free capability success");
}
/* 0 - MSIx, 1 - MSI, 2 - INTx */
enum intr_type hinic_intr_type(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return INTR_TYPE_NONE;
return dev->cfg_mgmt->svc_cap.interrupt_type;
}
EXPORT_SYMBOL(hinic_intr_type);
bool hinic_support_nic(void *hwdev, struct nic_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_NIC_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.nic_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_nic);
bool hinic_support_roce(void *hwdev, struct rdma_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_ROCE_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.rdma_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_roce);
bool hinic_support_fcoe(void *hwdev, struct fcoe_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_FCOE_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.fcoe_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_fcoe);
/* Only PPF support it, PF is not */
bool hinic_support_toe(void *hwdev, struct toe_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_TOE_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.toe_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_toe);
bool hinic_support_iwarp(void *hwdev, struct rdma_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_IWARP_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.rdma_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_iwarp);
bool hinic_support_fc(void *hwdev, struct fc_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_FC_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.fc_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_fc);
bool hinic_support_fic(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_FIC_TYPE(dev))
return false;
return true;
}
EXPORT_SYMBOL(hinic_support_fic);
bool hinic_support_ovs(void *hwdev, struct ovs_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_OVS_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.ovs_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_ovs);
bool hinic_support_acl(void *hwdev, struct acl_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_ACL_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.acl_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_acl);
bool hinic_support_rdma(void *hwdev, struct rdma_service_cap *cap)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_RDMA_TYPE(dev))
return false;
if (cap)
memcpy(cap, &dev->cfg_mgmt->svc_cap.rdma_cap, sizeof(*cap));
return true;
}
EXPORT_SYMBOL(hinic_support_rdma);
bool hinic_support_ft(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (!IS_FT_TYPE(dev))
return false;
return true;
}
EXPORT_SYMBOL(hinic_support_ft);
bool hinic_support_dynamic_q(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
return dev->cfg_mgmt->svc_cap.nic_cap.dynamic_qp ? true : false;
}
bool hinic_func_for_mgmt(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (dev->cfg_mgmt->svc_cap.chip_svc_type >= CFG_SVC_NIC_BIT0)
return false;
else
return true;
}
bool hinic_func_for_hwpt(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (IS_HWPT_TYPE(dev))
return true;
else
return false;
}
bool hinic_func_for_pt(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
if (dev->cfg_mgmt->svc_cap.force_up)
return true;
else
return false;
}
int cfg_set_func_sf_en(void *hwdev, u32 enbits, u32 enmask)
{
struct hinic_hwdev *dev = hwdev;
struct nic_misc_func_sf_enbits *func_sf_enbits;
u16 out_size = sizeof(*func_sf_enbits);
u16 glb_func_idx;
u16 api_info_len;
int err;
api_info_len = sizeof(struct nic_misc_func_sf_enbits);
func_sf_enbits = kzalloc(api_info_len, GFP_KERNEL);
if (!func_sf_enbits) {
sdk_err(dev->dev_hdl, "Alloc cfg api info failed\n");
return -ENOMEM;
}
err = hinic_global_func_id_get(dev, &glb_func_idx);
if (err) {
kfree(func_sf_enbits);
return err;
}
func_sf_enbits->stateful_enbits = enbits;
func_sf_enbits->stateful_enmask = enmask;
func_sf_enbits->function_id = glb_func_idx;
err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC,
HINIC_MISC_SET_FUNC_SF_ENBITS,
(void *)func_sf_enbits, api_info_len,
(void *)func_sf_enbits, &out_size,
VSW_UP_CFG_TIMEOUT);
if (err || !out_size || func_sf_enbits->status) {
sdk_err(dev->dev_hdl,
"Failed to set stateful enable, err: %d, status: 0x%x, out_size: 0x%x\n",
err, func_sf_enbits->status, out_size);
kfree(func_sf_enbits);
return -EFAULT;
}
kfree(func_sf_enbits);
return 0;
}
int cfg_get_func_sf_en(void *hwdev, u32 *enbits)
{
struct nic_misc_func_sf_enbits *func_sf_enbits;
struct hinic_hwdev *dev = hwdev;
u16 out_size = sizeof(*func_sf_enbits);
u16 glb_func_idx;
u16 api_info_len;
int err;
api_info_len = sizeof(struct nic_misc_func_sf_enbits);
func_sf_enbits = kzalloc(api_info_len, GFP_KERNEL);
if (!func_sf_enbits) {
sdk_err(dev->dev_hdl, "Alloc cfg api info failed\n");
return -ENOMEM;
}
err = hinic_global_func_id_get(dev, &glb_func_idx);
if (err) {
kfree(func_sf_enbits);
return err;
}
func_sf_enbits->function_id = glb_func_idx;
err = hinic_msg_to_mgmt_sync(hwdev, HINIC_MOD_L2NIC,
HINIC_MISC_GET_FUNC_SF_ENBITS,
(void *)func_sf_enbits, api_info_len,
(void *)func_sf_enbits, &out_size,
VSW_UP_CFG_TIMEOUT);
if (err || !out_size || func_sf_enbits->status) {
sdk_err(dev->dev_hdl, "Failed to get stateful enable, err: %d, status: 0x%x, out_size: 0x%x\n",
err, func_sf_enbits->status, out_size);
kfree(func_sf_enbits);
return -EFAULT;
}
*enbits = func_sf_enbits->stateful_enbits;
kfree(func_sf_enbits);
return 0;
}
int hinic_set_toe_enable(void *hwdev, bool enable)
{
u32 enbits;
u32 enmask;
if (!hwdev)
return -EINVAL;
enbits = VSW_SET_STATEFUL_BITS_TOE((u16)enable);
enmask = VSW_SET_STATEFUL_BITS_TOE(0x1U);
return cfg_set_func_sf_en(hwdev, enbits, enmask);
}
EXPORT_SYMBOL(hinic_set_toe_enable);
bool hinic_get_toe_enable(void *hwdev)
{
int err;
u32 enbits;
if (!hwdev)
return false;
err = cfg_get_func_sf_en(hwdev, &enbits);
if (err)
return false;
return VSW_GET_STATEFUL_BITS_TOE(enbits);
}
EXPORT_SYMBOL(hinic_get_toe_enable);
int hinic_set_fcoe_enable(void *hwdev, bool enable)
{
u32 enbits;
u32 enmask;
if (!hwdev)
return -EINVAL;
enbits = VSW_SET_STATEFUL_BITS_FCOE((u16)enable);
enmask = VSW_SET_STATEFUL_BITS_FCOE(0x1U);
return cfg_set_func_sf_en(hwdev, enbits, enmask);
}
EXPORT_SYMBOL(hinic_set_fcoe_enable);
bool hinic_get_fcoe_enable(void *hwdev)
{
int err;
u32 enbits;
if (!hwdev)
return false;
err = cfg_get_func_sf_en(hwdev, &enbits);
if (err)
return false;
return VSW_GET_STATEFUL_BITS_FCOE(enbits);
}
EXPORT_SYMBOL(hinic_get_fcoe_enable);
bool hinic_get_stateful_enable(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return false;
return dev->cfg_mgmt->svc_cap.sf_en;
}
EXPORT_SYMBOL(hinic_get_stateful_enable);
u8 hinic_host_oq_id_mask(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting host oq id mask\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.host_oq_id_mask_val;
}
EXPORT_SYMBOL(hinic_host_oq_id_mask);
u8 hinic_host_id(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting host id\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.host_id;
}
EXPORT_SYMBOL(hinic_host_id);
u16 hinic_host_total_func(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting host total function number\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.host_total_function;
}
EXPORT_SYMBOL(hinic_host_total_func);
u16 hinic_func_max_qnum(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting function max queue number\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.max_sqs;
}
EXPORT_SYMBOL(hinic_func_max_qnum);
u16 hinic_func_max_nic_qnum(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting function max queue number\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.nic_cap.max_sqs;
}
EXPORT_SYMBOL(hinic_func_max_nic_qnum);
u8 hinic_ep_id(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting ep id\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.ep_id;
}
EXPORT_SYMBOL(hinic_ep_id);
u8 hinic_er_id(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting er id\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.er_id;
}
EXPORT_SYMBOL(hinic_er_id);
u8 hinic_physical_port_id(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting physical port id\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.port_id;
}
EXPORT_SYMBOL(hinic_physical_port_id);
u8 hinic_func_max_vf(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting max vf number\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.max_vf;
}
EXPORT_SYMBOL(hinic_func_max_vf);
u8 hinic_max_num_cos(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting max cos number\n");
return 0;
}
return (u8)(dev->cfg_mgmt->svc_cap.max_cos_id + 1);
}
EXPORT_SYMBOL(hinic_max_num_cos);
u8 hinic_cos_valid_bitmap(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting cos valid bitmap\n");
return 0;
}
return (u8)(dev->cfg_mgmt->svc_cap.cos_valid_bitmap);
}
EXPORT_SYMBOL(hinic_cos_valid_bitmap);
u8 hinic_net_port_mode(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting net port mode\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.net_port_mode;
}
EXPORT_SYMBOL(hinic_net_port_mode);
bool hinic_is_hwdev_mod_inited(void *hwdev, enum hinic_hwdev_init_state state)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev || state >= HINIC_HWDEV_MAX_INVAL_INITED)
return false;
return !!test_bit(state, &dev->func_state);
}
static int hinic_os_dep_init(struct hinic_hwdev *hwdev)
{
hwdev->workq = create_singlethread_workqueue(HINIC_HW_WQ_NAME);
if (!hwdev->workq) {
sdk_err(hwdev->dev_hdl, "Failed to initialize hardware workqueue\n");
return -EFAULT;
}
return 0;
}
static void hinic_os_dep_deinit(struct hinic_hwdev *hwdev)
{
destroy_workqueue(hwdev->workq);
}
void hinic_ppf_hwdev_unreg(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return;
down(&dev->ppf_sem);
dev->ppf_hwdev = NULL;
up(&dev->ppf_sem);
sdk_info(dev->dev_hdl, "Unregister PPF hwdev\n");
}
void hinic_ppf_hwdev_reg(void *hwdev, void *ppf_hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return;
down(&dev->ppf_sem);
dev->ppf_hwdev = ppf_hwdev;
up(&dev->ppf_sem);
sdk_info(dev->dev_hdl, "Register PPF hwdev\n");
}
static int __vf_func_init(struct hinic_hwdev *hwdev)
{
int err;
err = hinic_vf_mbox_random_id_init(hwdev);
if (err) {
sdk_err(hwdev->dev_hdl, "Failed to init vf mbox random id\n");
return err;
}
err = hinic_vf_func_init(hwdev);
if (err)
nic_err(hwdev->dev_hdl, "Failed to init nic mbox\n");
return err;
}
static int __hilink_phy_init(struct hinic_hwdev *hwdev)
{
int err;
if (!HINIC_IS_VF(hwdev)) {
err = hinic_phy_init_status_judge(hwdev);
if (err) {
sdk_info(hwdev->dev_hdl, "Phy init failed\n");
return err;
}
if (hinic_support_nic(hwdev, NULL))
hinic_hilink_info_show(hwdev);
}
return 0;
}
/* Return:
* 0: all success
* >0: partitial success
* <0: all failed
*/
int hinic_init_hwdev(struct hinic_init_para *para)
{
struct hinic_hwdev *hwdev;
int err;
if (!(*para->hwdev)) {
hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL);
if (!hwdev)
return -ENOMEM;
*para->hwdev = hwdev;
hwdev->adapter_hdl = para->adapter_hdl;
hwdev->pcidev_hdl = para->pcidev_hdl;
hwdev->dev_hdl = para->dev_hdl;
hwdev->chip_node = para->chip_node;
hwdev->ppf_hwdev = para->ppf_hwdev;
sema_init(&hwdev->ppf_sem, 1);
sema_init(&hwdev->func_sem, 1);
hwdev->func_ref = 0;
hwdev->chip_fault_stats = vzalloc(HINIC_CHIP_FAULT_SIZE);
if (!hwdev->chip_fault_stats)
goto alloc_chip_fault_stats_err;
err = hinic_init_hwif(hwdev, para->cfg_reg_base,
para->intr_reg_base,
para->db_base_phy, para->db_base,
para->dwqe_mapping);
if (err) {
sdk_err(hwdev->dev_hdl, "Failed to init hwif\n");
goto init_hwif_err;
}
} else {
hwdev = *para->hwdev;
}
/* detect slave host according to BAR reg */
detect_host_mode_pre(hwdev);
if (IS_BMGW_SLAVE_HOST(hwdev) &&
(!hinic_get_master_host_mbox_enable(hwdev))) {
set_bit(HINIC_HWDEV_NONE_INITED, &hwdev->func_state);
sdk_info(hwdev->dev_hdl, "Master host not ready, init hwdev later\n");
return (1 << HINIC_HWDEV_ALL_INITED);
}
err = hinic_os_dep_init(hwdev);
if (err) {
sdk_err(hwdev->dev_hdl, "Failed to init os dependent\n");
goto os_dep_init_err;
}
hinic_set_chip_present(hwdev);
hinic_init_heartbeat(hwdev);
err = init_cfg_mgmt(hwdev);
if (err) {
sdk_err(hwdev->dev_hdl, "Failed to init config mgmt\n");
goto init_cfg_mgmt_err;
}
err = hinic_init_comm_ch(hwdev);
if (err) {
if (!(hwdev->func_state & HINIC_HWDEV_INIT_MODES_MASK)) {
sdk_err(hwdev->dev_hdl, "Failed to init communication channel\n");
goto init_comm_ch_err;
} else {
sdk_err(hwdev->dev_hdl, "Init communication channel partitail failed\n");
return hwdev->func_state & HINIC_HWDEV_INIT_MODES_MASK;
}
}
err = init_capability(hwdev);
if (err) {
sdk_err(hwdev->dev_hdl, "Failed to init capability\n");
goto init_cap_err;
}
if (hwdev->cfg_mgmt->svc_cap.force_up)
hwdev->feature_cap |= HINIC_FUNC_FORCE_LINK_UP;
err = __vf_func_init(hwdev);
if (err)
goto vf_func_init_err;
err = __hilink_phy_init(hwdev);
if (err)
goto hilink_phy_init_err;
set_bit(HINIC_HWDEV_ALL_INITED, &hwdev->func_state);
sdk_info(hwdev->dev_hdl, "Init hwdev success\n");
return 0;
hilink_phy_init_err:
hinic_vf_func_free(hwdev);
vf_func_init_err:
free_capability(hwdev);
init_cap_err:
return (hwdev->func_state & HINIC_HWDEV_INIT_MODES_MASK);
init_comm_ch_err:
free_cfg_mgmt(hwdev);
init_cfg_mgmt_err:
hinic_destroy_heartbeat(hwdev);
hinic_os_dep_deinit(hwdev);
os_dep_init_err:
hinic_free_hwif(hwdev);
init_hwif_err:
vfree(hwdev->chip_fault_stats);
alloc_chip_fault_stats_err:
kfree(hwdev);
*para->hwdev = NULL;
return -EFAULT;
}
/**
* hinic_set_vf_dev_cap - Set max queue num for VF
* @hwdev: the HW device for VF
*/
int hinic_set_vf_dev_cap(void *hwdev)
{
int err;
struct hinic_hwdev *dev;
enum func_type type;
if (!hwdev)
return -EFAULT;
dev = (struct hinic_hwdev *)hwdev;
type = HINIC_FUNC_TYPE(dev);
if (type != TYPE_VF)
return -EPERM;
err = get_dev_cap(dev);
if (err)
return err;
nic_param_fix(dev);
return 0;
}
void hinic_free_hwdev(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
enum hinic_hwdev_init_state state = HINIC_HWDEV_ALL_INITED;
int flag = 0;
if (!hwdev)
return;
if (test_bit(HINIC_HWDEV_ALL_INITED, &dev->func_state)) {
clear_bit(HINIC_HWDEV_ALL_INITED, &dev->func_state);
/* BM slave function not need to exec rx_tx_flush */
if (dev->func_mode != FUNC_MOD_MULTI_BM_SLAVE)
hinic_func_rx_tx_flush(hwdev);
hinic_vf_func_free(hwdev);
free_capability(dev);
}
while (state > HINIC_HWDEV_NONE_INITED) {
if (test_bit(state, &dev->func_state)) {
flag = 1;
break;
}
state--;
}
if (flag) {
hinic_uninit_comm_ch(dev);
free_cfg_mgmt(dev);
hinic_destroy_heartbeat(dev);
hinic_os_dep_deinit(dev);
}
clear_bit(HINIC_HWDEV_NONE_INITED, &dev->func_state);
hinic_free_hwif(dev);
vfree(dev->chip_fault_stats);
kfree(dev);
}
void hinic_set_api_stop(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return;
dev->chip_present_flag = HINIC_CHIP_ABSENT;
sdk_info(dev->dev_hdl, "Set card absent\n");
hinic_force_complete_all(dev);
sdk_info(dev->dev_hdl, "All messages interacting with the chip will stop\n");
}
void hinic_shutdown_hwdev(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!hwdev)
return;
if (IS_SLAVE_HOST(dev))
set_slave_host_enable(hwdev, hinic_pcie_itf_id(hwdev), false);
}
u32 hinic_func_pf_num(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting pf number capability\n");
return 0;
}
return dev->cfg_mgmt->svc_cap.pf_num;
}
u64 hinic_get_func_feature_cap(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting function feature capability\n");
return 0;
}
return dev->feature_cap;
}
enum hinic_func_mode hinic_get_func_mode(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting function mode\n");
return 0;
}
return dev->func_mode;
}
EXPORT_SYMBOL(hinic_get_func_mode);
enum hinic_service_mode hinic_get_service_mode(void *hwdev)
{
struct hinic_hwdev *dev = hwdev;
if (!dev) {
pr_err("Hwdev pointer is NULL for getting service mode\n");
return HINIC_WORK_MODE_INVALID;
}
return dev->board_info.service_mode;
}