2026-01-21 18:59:54 +08:00

1011 lines
22 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Huawei Hifc PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": [COMM]" fmt
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <net/sock.h>
#include "hifc_knl_adp.h"
#include "hifc_hw.h"
#include "hifc_hwdev.h"
#include "hifc_hwif.h"
#include "hifc_api_cmd.h"
#include "hifc_mgmt.h"
#include "hifc_cfg.h"
#include "hifc_lld.h"
#include "hifc_sml.h"
#include "hifc_tool.h"
static atomic_t tool_used_cnt;
typedef int (*hw_driv_module)(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size);
struct hw_drv_module_handle {
enum driver_cmd_type driv_cmd_name;
hw_driv_module driv_func;
};
u8 hifc_physical_port_id(void *hwdev)
{
struct hifc_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;
}
int hifc_clp_to_mgmt(void *hwdev, enum hifc_mod_type mod, u8 cmd,
void *buf_in, u16 in_size,
void *buf_out, u16 *out_size)
{
struct hifc_hwdev *dev = hwdev;
int err;
if (!dev)
return -EINVAL;
if (!dev->chip_present_flag)
return -EPERM;
if (!hifc_is_hwdev_mod_inited(hwdev, HIFC_HWDEV_CLP_INITED))
return -EPERM;
err = hifc_pf_clp_to_mgmt(dev, mod, cmd, buf_in,
in_size, buf_out, out_size);
return err;
}
static int get_func_type(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
u16 func_typ;
func_typ = hifc_func_type(hwdev);
if (!buf_out || *out_size != sizeof(u16)) {
pr_err("Unexpect out buf size from user :%d, expect: %lu\n",
*out_size, sizeof(u16));
return -EFAULT;
}
*(u16 *)buf_out = func_typ;
return 0;
}
static int get_func_id(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
u16 func_id;
if (!buf_out || *out_size != sizeof(u16)) {
pr_err("Unexpect out buf size from user :%d, expect: %lu\n",
*out_size, sizeof(u16));
return -EFAULT;
}
func_id = hifc_global_func_id_hw(hwdev);
*(u16 *)buf_out = func_id;
*out_size = sizeof(u16);
return 0;
}
static int get_drv_version(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
struct drv_version_info *ver_info;
char ver_str[MAX_VER_INFO_LEN] = {0};
if (*out_size != sizeof(*ver_info)) {
pr_err("Unexpect out buf size from user :%d, expect: %lu\n",
*out_size, sizeof(*ver_info));
return -EFAULT;
}
snprintf(ver_str, sizeof(ver_str), "%s %s",
HIFC_DRV_VERSION, __TIME_STR__);
ver_info = (struct drv_version_info *)buf_out;
memcpy(ver_info->ver, ver_str, sizeof(ver_str));
return 0;
}
static int clear_hw_stats(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
return 0;
}
static int get_hw_stats(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
return 0;
}
static void hifc_get_chip_fault_stats(const void *hwdev,
u8 *chip_fault_stats, int offset)
{
int copy_len = offset + MAX_DRV_BUF_SIZE - HIFC_CHIP_FAULT_SIZE;
if (offset < 0 || offset > HIFC_CHIP_FAULT_SIZE) {
pr_err("Invalid chip offset value: %d\n",
offset);
return;
}
if (offset + MAX_DRV_BUF_SIZE <= HIFC_CHIP_FAULT_SIZE)
memcpy(chip_fault_stats,
((struct hifc_hwdev *)hwdev)->chip_fault_stats + offset,
MAX_DRV_BUF_SIZE);
else
memcpy(chip_fault_stats,
((struct hifc_hwdev *)hwdev)->chip_fault_stats + offset,
copy_len);
}
static int get_chip_faults_stats(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
int offset = 0;
struct chip_fault_stats *fault_info;
if (!buf_in || !buf_out || *out_size != sizeof(*fault_info) ||
in_size != sizeof(*fault_info)) {
pr_err("Unexpect out buf size from user :%d, expect: %lu\n",
*out_size, sizeof(*fault_info));
return -EFAULT;
}
fault_info = (struct chip_fault_stats *)buf_in;
offset = fault_info->offset;
fault_info = (struct chip_fault_stats *)buf_out;
hifc_get_chip_fault_stats(hwdev, fault_info->chip_faults, offset);
return 0;
}
static int get_chip_id_test(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
return 0;
}
static int get_single_card_info(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
if (!buf_in || !buf_out || in_size != sizeof(struct card_info) ||
*out_size != sizeof(struct card_info)) {
pr_err("Unexpect out buf size from user :%d, expect: %lu\n",
*out_size, sizeof(struct card_info));
return -EFAULT;
}
hifc_get_card_info(hwdev, buf_out);
*out_size = in_size;
return 0;
}
#define GET_FIRMWARE_ACTIVE_STATUS_TIMEOUT 30
static int get_firmware_active_status(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
u32 loop_cnt = 0;
while (loop_cnt < GET_FIRMWARE_ACTIVE_STATUS_TIMEOUT) {
if (!hifc_get_mgmt_channel_status(hwdev))
return 0;
msleep(1000);
loop_cnt++;
}
if (loop_cnt == GET_FIRMWARE_ACTIVE_STATUS_TIMEOUT)
return -ETIMEDOUT;
return 0;
}
static int get_device_id(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
u16 dev_id;
int err;
if (!buf_out || !buf_in || *out_size != sizeof(u16) ||
in_size != sizeof(u16)) {
pr_err("Unexpect out buf size from user :%d, expect: %lu\n",
*out_size, sizeof(u16));
return -EFAULT;
}
err = hifc_get_device_id(hwdev, &dev_id);
if (err)
return err;
*((u32 *)buf_out) = dev_id;
*out_size = in_size;
return 0;
}
bool hifc_is_in_host(void)
{
struct card_node *chip_node;
struct hifc_pcidev *dev;
lld_dev_hold();
list_for_each_entry(chip_node, &g_hinic_chip_list, node) {
list_for_each_entry(dev, &chip_node->func_list, node) {
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
continue;
if (dev->init_state > HIFC_INIT_STATE_PCI_INITED) {
lld_dev_put();
return true;
}
}
}
lld_dev_put();
return false;
}
static int is_driver_in_vm(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
bool in_host;
if (!buf_out || (*out_size != sizeof(u8)))
return -EINVAL;
in_host = hifc_is_in_host();
if (in_host)
*((u8 *)buf_out) = 0;
else
*((u8 *)buf_out) = 1;
return 0;
}
static int get_pf_id(void *hwdev, void *buf_in, u32 in_size,
void *buf_out, u32 *out_size)
{
struct hifc_pf_info *pf_info;
u32 port_id = 0;
int err;
if (!buf_out || (*out_size != sizeof(*pf_info)) ||
!buf_in || in_size != sizeof(u32))
return -EINVAL;
port_id = *((u32 *)buf_in);
pf_info = (struct hifc_pf_info *)buf_out;
err = hifc_get_pf_id(hwdev, port_id, &pf_info->pf_id,
&pf_info->isvalid);
if (err)
return err;
*out_size = sizeof(*pf_info);
return 0;
}
static struct hw_drv_module_handle hw_driv_module_cmd_handle[] = {
{FUNC_TYPE, get_func_type},
{GET_FUNC_IDX, get_func_id},
{GET_DRV_VERSION, get_drv_version},
{GET_HW_STATS, get_hw_stats},
{CLEAR_HW_STATS, clear_hw_stats},
{GET_CHIP_FAULT_STATS, get_chip_faults_stats},
{GET_CHIP_ID, get_chip_id_test},
{GET_SINGLE_CARD_INFO, get_single_card_info},
{GET_FIRMWARE_ACTIVE_STATUS, get_firmware_active_status},
{GET_DEVICE_ID, get_device_id},
{IS_DRV_IN_VM, is_driver_in_vm},
{GET_PF_ID, get_pf_id},
};
int send_to_hw_driver(void *hwdev, struct msg_module *nt_msg,
void *buf_in, u32 in_size, void *buf_out, u32 *out_size)
{
int index, num_cmds = sizeof(hw_driv_module_cmd_handle) /
sizeof(hw_driv_module_cmd_handle[0]);
enum driver_cmd_type cmd_type;
int err = 0;
if (!nt_msg) {
pr_err("Input param invalid!\n");
return -EINVAL;
}
cmd_type = (enum driver_cmd_type)(nt_msg->msg_formate);
for (index = 0; index < num_cmds; index++) {
if (cmd_type ==
hw_driv_module_cmd_handle[index].driv_cmd_name) {
err = hw_driv_module_cmd_handle[index].driv_func
(hwdev, buf_in,
in_size, buf_out, out_size);
break;
}
}
if (index == num_cmds)
return -EINVAL;
return err;
}
typedef int (*sm_module)(void *hwdev, u32 id, u8 instance,
u8 node, struct sm_out_st *buf_out);
static int sm_rd32(void *hwdev, u32 id, u8 instance,
u8 node, struct sm_out_st *buf_out)
{
u32 val1;
int ret;
ret = hifc_sm_ctr_rd32(hwdev, node, instance, id, &val1);
if (ret) {
pr_err("Get sm ctr information (32 bits)failed!\n");
val1 = 0xffffffff;
}
buf_out->val1 = val1;
return ret;
}
static int sm_rd64_pair(void *hwdev, u32 id, u8 instance,
u8 node, struct sm_out_st *buf_out)
{
u64 val1 = 0, val2 = 0;
int ret;
ret = hifc_sm_ctr_rd64_pair(hwdev, node, instance, id, &val1, &val2);
if (ret) {
pr_err("Get sm ctr information (64 bits pair)failed!\n");
val1 = 0xffffffff;
}
buf_out->val1 = val1;
buf_out->val2 = val2;
return ret;
}
static int sm_rd64(void *hwdev, u32 id, u8 instance,
u8 node, struct sm_out_st *buf_out)
{
u64 val1;
int ret;
ret = hifc_sm_ctr_rd64(hwdev, node, instance, id, &val1);
if (ret) {
pr_err("Get sm ctr information (64 bits)failed!\n");
val1 = 0xffffffff;
}
buf_out->val1 = val1;
return ret;
}
struct sm_module_handle {
enum sm_cmd_type sm_cmd_name;
sm_module sm_func;
};
struct sm_module_handle sm_module_cmd_handle[] = {
{SM_CTR_RD32, sm_rd32},
{SM_CTR_RD64_PAIR, sm_rd64_pair},
{SM_CTR_RD64, sm_rd64}
};
int send_to_sm(void *hwdev, struct msg_module *nt_msg, void *buf_in,
u32 in_size, void *buf_out, u32 *out_size)
{
struct sm_in_st *sm_in = buf_in;
struct sm_out_st *sm_out = buf_out;
u32 msg_formate;
int index, num_cmds = sizeof(sm_module_cmd_handle) /
sizeof(sm_module_cmd_handle[0]);
int ret = 0;
if ((!nt_msg) || (!buf_in) || (!buf_out) ||
(in_size != sizeof(*sm_in)) ||
(*out_size != sizeof(*sm_out))) {
pr_err("Input param invalid!\n");
return -EINVAL;
}
msg_formate = nt_msg->msg_formate;
for (index = 0; index < num_cmds; index++) {
if (msg_formate == sm_module_cmd_handle[index].sm_cmd_name)
ret = sm_module_cmd_handle[index].sm_func(hwdev,
(u32)sm_in->id,
(u8)sm_in->instance,
(u8)sm_in->node, sm_out);
}
if (ret)
pr_err("Get sm information fail!\n");
*out_size = sizeof(struct sm_out_st);
return ret;
}
static u32 get_up_timeout_val(enum hifc_mod_type mod, u8 cmd)
{
#define UP_UPDATEFW_TIME_OUT_VAL 20000U
if (mod == HIFC_MOD_L2NIC && cmd == NIC_UP_CMD_UPDATE_FW)
return UP_UPDATEFW_TIME_OUT_VAL;
else
return UP_COMP_TIME_OUT_VAL;
}
static int api_csr_write(void *hwdev, struct msg_module *nt_msg,
void *buf_in, u32 in_size, void *buf_out,
u32 *out_size)
{
struct csr_write_st *csr_write_msg = (struct csr_write_st *)buf_in;
int ret = 0;
u32 rd_len;
u32 rd_addr;
u32 rd_cnt = 0;
u32 offset = 0;
u8 node_id;
u32 i;
u8 *data;
if (!buf_in || in_size != sizeof(*csr_write_msg))
return -EINVAL;
rd_len = csr_write_msg->rd_len;
rd_addr = csr_write_msg->addr;
node_id = (u8)nt_msg->up_cmd.up_db.comm_mod_type;
if (rd_len % 4) {
pr_err("Csr length must be a multiple of 4\n");
return -EFAULT;
}
rd_cnt = rd_len / 4;
data = kzalloc(rd_len, GFP_KERNEL);
if (!data) {
pr_err("No more memory\n");
return -EFAULT;
}
if (copy_from_user(data, (void *)csr_write_msg->data, rd_len)) {
pr_err("Copy information from user failed\n");
kfree(data);
return -EFAULT;
}
for (i = 0; i < rd_cnt; i++) {
ret = hifc_api_csr_wr32(hwdev, node_id,
rd_addr + offset,
*((u32 *)(data + offset)));
if (ret) {
pr_err("Csr wr fail, ret: %d, node_id: %d, csr addr: 0x%08x\n",
ret, rd_addr + offset, node_id);
kfree(data);
return ret;
}
offset += 4;
}
*out_size = 0;
kfree(data);
return ret;
}
static int api_csr_read(void *hwdev, struct msg_module *nt_msg,
void *buf_in, u32 in_size, void *buf_out, u32 *out_size)
{
struct up_log_msg_st *up_log_msg = (struct up_log_msg_st *)buf_in;
int ret = 0;
u32 rd_len;
u32 rd_addr;
u32 rd_cnt = 0;
u32 offset = 0;
u8 node_id;
u32 i;
if (!buf_in || !buf_out || in_size != sizeof(*up_log_msg) ||
*out_size != up_log_msg->rd_len)
return -EINVAL;
rd_len = up_log_msg->rd_len;
rd_addr = up_log_msg->addr;
node_id = (u8)nt_msg->up_cmd.up_db.comm_mod_type;
rd_cnt = rd_len / 4;
if (rd_len % 4)
rd_cnt++;
for (i = 0; i < rd_cnt; i++) {
ret = hifc_api_csr_rd32(hwdev, node_id,
rd_addr + offset,
(u32 *)(((u8 *)buf_out) + offset));
if (ret) {
pr_err("Csr rd fail, err: %d, node_id: %d, csr addr: 0x%08x\n",
ret, node_id, rd_addr + offset);
return ret;
}
offset += 4;
}
*out_size = rd_len;
return ret;
}
int send_to_up(void *hwdev, struct msg_module *nt_msg, void *buf_in,
u32 in_size, void *buf_out, u32 *out_size)
{
int ret = 0;
if ((!nt_msg) || (!hwdev) || (!buf_in) || (!buf_out)) {
pr_err("Input param invalid!\n");
return -EINVAL;
}
if ((nt_msg->up_cmd.up_db.up_api_type == API_CMD) ||
(nt_msg->up_cmd.up_db.up_api_type == API_CLP)) {
enum hifc_mod_type mod;
u8 cmd;
u32 timeout;
mod = (enum hifc_mod_type)nt_msg->up_cmd.up_db.comm_mod_type;
cmd = nt_msg->up_cmd.up_db.chipif_cmd;
timeout = get_up_timeout_val(mod, cmd);
if (nt_msg->up_cmd.up_db.up_api_type == API_CMD)
ret = hifc_msg_to_mgmt_sync(hwdev, mod, cmd,
buf_in, (u16)in_size,
buf_out, (u16 *)out_size,
timeout);
else
ret = hifc_clp_to_mgmt(hwdev, mod, cmd,
buf_in, (u16)in_size,
buf_out, (u16 *)out_size);
if (ret) {
pr_err("Message to mgmt cpu return fail, mod: %d, cmd: %d\n",
mod, cmd);
return ret;
}
} else if (nt_msg->up_cmd.up_db.up_api_type == API_CHAIN) {
if (nt_msg->up_cmd.up_db.chipif_cmd == API_CSR_WRITE) {
ret = api_csr_write(hwdev, nt_msg, buf_in,
in_size, buf_out, out_size);
return ret;
}
ret = api_csr_read(hwdev, nt_msg, buf_in,
in_size, buf_out, out_size);
}
return ret;
}
int send_to_ucode(void *hwdev, struct msg_module *nt_msg, void *buf_in,
u32 in_size, void *buf_out, u32 *out_size)
{
int ret = 0;
if ((!nt_msg) || (!hwdev) || (!buf_in)) {
pr_err("Input param invalid!\n");
return -EINVAL;
}
if (nt_msg->ucode_cmd.ucode_db.ucode_imm) {
ret = hifc_cmdq_direct_resp
(hwdev, nt_msg->ucode_cmd.ucode_db.cmdq_ack_type,
nt_msg->ucode_cmd.ucode_db.comm_mod_type,
nt_msg->ucode_cmd.ucode_db.ucode_cmd_type,
buf_in, buf_out, 0);
if (ret)
pr_err("Send direct cmdq err: %d!\n", ret);
} else {
ret = hifc_cmdq_detail_resp
(hwdev, nt_msg->ucode_cmd.ucode_db.cmdq_ack_type,
nt_msg->ucode_cmd.ucode_db.comm_mod_type,
nt_msg->ucode_cmd.ucode_db.ucode_cmd_type,
buf_in, buf_out, 0);
if (ret)
pr_err("Send detail cmdq err: %d!\n", ret);
}
return ret;
}
void hifc_tool_cnt_inc(void)
{
atomic_inc(&tool_used_cnt);
}
void hifc_tool_cnt_dec(void)
{
atomic_dec(&tool_used_cnt);
}
static bool __is_pcidev_match_chip_name(const char *ifname,
struct hifc_pcidev *dev,
struct card_node *chip_node,
enum func_type type)
{
if (!strncmp(chip_node->chip_name, ifname, IFNAMSIZ)) {
if (type == TYPE_UNKNOWN) {
if (dev->init_state < HIFC_INIT_STATE_HW_PART_INITED)
return false;
} else {
if (dev->init_state >=
HIFC_INIT_STATE_HW_PART_INITED &&
hifc_func_type(dev->hwdev) != type)
return false;
}
return true;
}
return false;
}
static struct hifc_pcidev *_get_pcidev_by_chip_name(char *ifname,
enum func_type type)
{
struct card_node *chip_node;
struct hifc_pcidev *dev;
lld_dev_hold();
list_for_each_entry(chip_node, &g_hinic_chip_list, node) {
list_for_each_entry(dev, &chip_node->func_list, node) {
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
continue;
if (__is_pcidev_match_chip_name(ifname, dev, chip_node,
type)) {
lld_dev_put();
return dev;
}
}
}
lld_dev_put();
return NULL;
}
static struct hifc_pcidev *hifc_get_pcidev_by_chip_name(char *ifname)
{
struct hifc_pcidev *dev, *dev_hw_init;
/* find hw init device first */
dev_hw_init = _get_pcidev_by_chip_name(ifname, TYPE_UNKNOWN);
if (dev_hw_init) {
if (hifc_func_type(dev_hw_init->hwdev) == TYPE_PPF)
return dev_hw_init;
}
dev = _get_pcidev_by_chip_name(ifname, TYPE_PPF);
if (dev) {
if (dev_hw_init && (dev_hw_init->init_state >= dev->init_state))
return dev_hw_init;
return dev;
}
dev = _get_pcidev_by_chip_name(ifname, TYPE_PF);
if (dev) {
if (dev_hw_init && (dev_hw_init->init_state >= dev->init_state))
return dev_hw_init;
return dev;
}
return NULL;
}
static struct hifc_pcidev *hifc_get_pcidev_by_ifname(char *ifname)
{
struct hifc_pcidev *dev;
/* support search hwdev by chip name, net device name,
* or fc device name
*/
/* Find pcidev by chip_name first */
dev = hifc_get_pcidev_by_chip_name(ifname);
if (dev)
return dev;
/* If ifname not a chip name,
* find pcidev by FC name or netdevice name
*/
return hifc_get_pcidev_by_dev_name(ifname);
}
void *hifc_get_hwdev_by_ifname(char *ifname)
{
struct hifc_pcidev *dev;
if (!ifname) {
pr_err("Input param invalid!\n");
return NULL;
}
dev = hifc_get_pcidev_by_ifname(ifname);
if (dev)
return dev->hwdev;
return NULL;
}
enum hifc_init_state hifc_get_init_state_by_ifname(char *ifname)
{
struct hifc_pcidev *dev;
if (!ifname) {
pr_err("Input param invalid!\n");
return HIFC_INIT_STATE_NONE;
}
dev = hifc_get_pcidev_by_ifname(ifname);
if (dev)
return dev->init_state;
pr_err("Can not get device %s\n", ifname);
return HIFC_INIT_STATE_NONE;
}
void get_fc_devname(char *devname)
{
struct card_node *chip_node;
struct hifc_pcidev *dev;
if (!devname) {
pr_err("Input param invalid!\n");
return;
}
lld_dev_hold();
list_for_each_entry(chip_node, &g_hinic_chip_list, node) {
list_for_each_entry(dev, &chip_node->func_list, node) {
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
continue;
if (dev->init_state < HIFC_INIT_STATE_ALL_INITED)
continue;
if (dev->uld_dev) {
strlcpy(devname, (char *)dev->uld_dev_name,
IFNAMSIZ);
lld_dev_put();
return;
}
}
}
lld_dev_put();
}
void hifc_get_all_chip_id(void *id_info)
{
struct nic_card_id *card_id = (struct nic_card_id *)id_info;
struct card_node *chip_node;
int i = 0;
int id, err;
if (!card_id) {
pr_err("Input param invalid!\n");
return;
}
lld_dev_hold();
list_for_each_entry(chip_node, &g_hinic_chip_list, node) {
err = sscanf(chip_node->chip_name, HIFC_CHIP_NAME "%d", &id);
if (err < 0)
pr_err("Failed to get hifc id\n");
card_id->id[i] = id;
i++;
}
lld_dev_put();
card_id->num = i;
}
static struct card_node *hifc_get_chip_node_by_hwdev(const void *hwdev)
{
struct card_node *chip_node = NULL;
struct card_node *node_tmp = NULL;
struct hifc_pcidev *dev;
if (!hwdev)
return NULL;
lld_dev_hold();
list_for_each_entry(node_tmp, &g_hinic_chip_list, node) {
if (!chip_node) {
list_for_each_entry(dev, &node_tmp->func_list, node) {
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
continue;
if (dev->hwdev == hwdev) {
chip_node = node_tmp;
break;
}
}
}
}
lld_dev_put();
return chip_node;
}
int hifc_get_device_id(void *hwdev, u16 *dev_id)
{
struct card_node *chip_node = NULL;
struct hifc_pcidev *dev;
u16 vendor_id = 0;
u16 device_id = 0;
if ((!dev_id) || (!hwdev)) {
pr_err("Input param invalid!\n");
return -ENODEV;
}
chip_node = hifc_get_chip_node_by_hwdev(hwdev);
if (!chip_node)
return -ENODEV;
lld_dev_hold();
list_for_each_entry(dev, &chip_node->func_list, node) {
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
continue;
pci_read_config_word(dev->pcidev, 0, &vendor_id);
if (vendor_id == HIFC_PCI_VENDOR_ID) {
pci_read_config_word(dev->pcidev, 2, &device_id);
break;
}
}
lld_dev_put();
*dev_id = device_id;
return 0;
}
int hifc_get_pf_id(void *hwdev, u32 port_id, u32 *pf_id, u32 *isvalid)
{
struct card_node *chip_node = NULL;
struct hifc_pcidev *dev;
if ((!isvalid) || (!pf_id) || (!hwdev)) {
pr_err("Input param invalid!\n");
return -ENODEV;
}
chip_node = hifc_get_chip_node_by_hwdev(hwdev);
if (!chip_node)
return -ENODEV;
lld_dev_hold();
list_for_each_entry(dev, &chip_node->func_list, node) {
if (hifc_physical_port_id(dev->hwdev) == port_id) {
*pf_id = hifc_global_func_id(dev->hwdev);
*isvalid = 1;
break;
}
}
lld_dev_put();
return 0;
}
bool hifc_is_valid_bar_addr(u64 offset)
{
struct card_node *chip_node = NULL;
struct hifc_pcidev *dev;
lld_dev_hold();
list_for_each_entry(chip_node, &g_hinic_chip_list, node) {
list_for_each_entry(dev, &chip_node->func_list, node) {
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
continue;
if (offset == pci_resource_start(dev->pcidev, 0)) {
lld_dev_put();
return true;
}
}
}
lld_dev_put();
return false;
}
void hifc_get_card_func_info_by_card_name(
const char *chip_name, struct hifc_card_func_info *card_func)
{
struct card_node *chip_node = NULL;
struct hifc_pcidev *dev;
struct func_pdev_info *pdev_info;
if ((!card_func) || (!chip_name)) {
pr_err("Input param invalid!\n");
return;
}
card_func->num_pf = 0;
lld_dev_hold();
list_for_each_entry(chip_node, &g_hinic_chip_list, node) {
if (strncmp(chip_node->chip_name, chip_name, IFNAMSIZ))
continue;
list_for_each_entry(dev, &chip_node->func_list, node) {
if (hifc_func_type(dev->hwdev) == TYPE_VF)
continue;
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
continue;
pdev_info = &card_func->pdev_info[card_func->num_pf];
pdev_info->bar0_size = pci_resource_len(dev->pcidev, 0);
pdev_info->bar0_phy_addr =
pci_resource_start(dev->pcidev, 0);
card_func->num_pf++;
if (card_func->num_pf >= MAX_SIZE)
break;
}
}
lld_dev_put();
}
static bool __is_func_valid(struct hifc_pcidev *dev)
{
if (test_bit(HIFC_FUNC_IN_REMOVE, &dev->flag))
return false;
if (dev->init_state < HIFC_INIT_STATE_HWDEV_INITED)
return false;
return true;
}
void hifc_get_card_info(void *hwdev, void *bufin)
{
struct card_node *chip_node = NULL;
struct card_info *info = (struct card_info *)bufin;
struct hifc_pcidev *dev;
u32 idx = 0;
if ((!bufin) || (!hwdev)) {
pr_err("Input param invalid!\n");
return;
}
info->pf_num = 0;
chip_node = hifc_get_chip_node_by_hwdev(hwdev);
if (!chip_node)
return;
lld_dev_hold();
list_for_each_entry(dev, &chip_node->func_list, node) {
if (!__is_func_valid(dev))
continue;
strlcpy(info->pf[idx].name, dev->uld_dev_name, IFNAMSIZ);
info->pf[idx].pf_type = (u32)BIT(SERVICE_T_FC);
strlcpy(info->pf[idx].bus_info, pci_name(dev->pcidev),
sizeof(info->pf[idx].bus_info));
info->pf_num++;
idx++;
}
lld_dev_put();
}