mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
Merge branch 'net-hinic3-pf-initialization'
Fan Gong says: ==================== net: hinic3: PF initialization This is [2/3] part of hinic3 Ethernet driver second submission. With this patch hinic3 becomes a complete Ethernet driver with pf and vf. Add cmdq detailed-response interfaces. Add dump interfaces for cmdq, aeq, ceq and mailbox. Add msg_send_lock for message sending concurrency. Add PF device support and chip_present_flag to check cards. Add rx vlan offload support. Add PF FLR wait and timeout handling. Add 5 ethtool ops for information of driver and link. v1: https://lore.kernel.org/netdev/cover.1771916043.git.zhuyikai1@h-partners.com/ v2: https://lore.kernel.org/netdev/cover.1772697509.git.zhuyikai1@h-partners.com/ ==================== Link: https://patch.msgid.link/cover.1773062356.git.zhuyikai1@h-partners.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
52e4d5da6d
|
|
@ -6,6 +6,7 @@ obj-$(CONFIG_HINIC3) += hinic3.o
|
|||
hinic3-objs := hinic3_cmdq.o \
|
||||
hinic3_common.o \
|
||||
hinic3_eqs.o \
|
||||
hinic3_ethtool.o \
|
||||
hinic3_filter.o \
|
||||
hinic3_hw_cfg.o \
|
||||
hinic3_hw_comm.o \
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "hinic3_cmdq.h"
|
||||
#include "hinic3_eqs.h"
|
||||
#include "hinic3_hwdev.h"
|
||||
#include "hinic3_hwif.h"
|
||||
#include "hinic3_mbox.h"
|
||||
|
||||
#define CMDQ_BUF_SIZE 2048
|
||||
#define CMDQ_WQEBB_SIZE 64
|
||||
#define CMDQ_WQE_HEAD_LEN 32
|
||||
|
||||
#define CMDQ_CMD_TIMEOUT 5000
|
||||
#define CMDQ_ENABLE_WAIT_TIMEOUT 300
|
||||
|
|
@ -61,6 +63,10 @@
|
|||
#define CMDQ_DB_HEAD_SET(val, member) \
|
||||
FIELD_PREP(CMDQ_DB_HEAD_##member##_MASK, val)
|
||||
|
||||
#define SAVED_DATA_ARM_MASK BIT(31)
|
||||
#define SAVED_DATA_SET(val, member) \
|
||||
FIELD_PREP(SAVED_DATA_##member##_MASK, val)
|
||||
|
||||
#define CMDQ_CEQE_TYPE_MASK GENMASK(2, 0)
|
||||
#define CMDQ_CEQE_GET(val, member) \
|
||||
FIELD_GET(CMDQ_CEQE_##member##_MASK, le32_to_cpu(val))
|
||||
|
|
@ -84,6 +90,10 @@ enum cmdq_data_format {
|
|||
CMDQ_DATA_DIRECT = 1,
|
||||
};
|
||||
|
||||
enum cmdq_scmd_type {
|
||||
CMDQ_SET_ARM_CMD = 2,
|
||||
};
|
||||
|
||||
enum cmdq_ctrl_sect_len {
|
||||
CMDQ_CTRL_SECT_LEN = 1,
|
||||
CMDQ_CTRL_DIRECT_SECT_LEN = 2,
|
||||
|
|
@ -106,6 +116,20 @@ enum cmdq_cmd_type {
|
|||
|
||||
#define CMDQ_WQE_NUM_WQEBBS 1
|
||||
|
||||
static void hinic3_dump_cmdq_wqe_head(struct hinic3_hwdev *hwdev,
|
||||
struct cmdq_wqe *wqe)
|
||||
{
|
||||
u32 *data = (u32 *)wqe;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < (CMDQ_WQE_HEAD_LEN / sizeof(u32)); i += 0x4) {
|
||||
dev_dbg(hwdev->dev,
|
||||
"wqe data: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
|
||||
*(data + i), *(data + i + 0x1), *(data + i + 0x2),
|
||||
*(data + i + 0x3));
|
||||
}
|
||||
}
|
||||
|
||||
static struct cmdq_wqe *cmdq_read_wqe(struct hinic3_wq *wq, u16 *ci)
|
||||
{
|
||||
if (hinic3_wq_get_used(wq) == 0)
|
||||
|
|
@ -166,6 +190,11 @@ static void cmdq_clear_cmd_buf(struct hinic3_cmdq_cmd_info *cmd_info,
|
|||
hinic3_free_cmd_buf(hwdev, cmd_info->buf_in);
|
||||
cmd_info->buf_in = NULL;
|
||||
}
|
||||
|
||||
if (cmd_info->buf_out) {
|
||||
hinic3_free_cmd_buf(hwdev, cmd_info->buf_out);
|
||||
cmd_info->buf_out = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_wqe_complete_bit(struct hinic3_cmdq *cmdq,
|
||||
|
|
@ -189,6 +218,20 @@ static void clear_wqe_complete_bit(struct hinic3_cmdq *cmdq,
|
|||
hinic3_wq_put_wqebbs(&cmdq->wq, CMDQ_WQE_NUM_WQEBBS);
|
||||
}
|
||||
|
||||
static int cmdq_arm_ceq_handler(struct hinic3_cmdq *cmdq,
|
||||
struct cmdq_wqe *wqe, u16 ci)
|
||||
{
|
||||
struct cmdq_ctrl *ctrl = &wqe->wqe_scmd.ctrl;
|
||||
__le32 ctrl_info = ctrl->ctrl_info;
|
||||
|
||||
if (!CMDQ_WQE_COMPLETED(ctrl_info))
|
||||
return -EBUSY;
|
||||
|
||||
clear_wqe_complete_bit(cmdq, wqe, ci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cmdq_update_cmd_status(struct hinic3_cmdq *cmdq, u16 prod_idx,
|
||||
struct cmdq_wqe *wqe)
|
||||
{
|
||||
|
|
@ -252,11 +295,17 @@ void hinic3_cmdq_ceq_handler(struct hinic3_hwdev *hwdev, __le32 ceqe_data)
|
|||
case HINIC3_CMD_TYPE_TIMEOUT:
|
||||
dev_warn(hwdev->dev, "Cmdq timeout, q_id: %u, ci: %u\n",
|
||||
cmdq_type, ci);
|
||||
hinic3_dump_cmdq_wqe_head(hwdev, wqe);
|
||||
fallthrough;
|
||||
case HINIC3_CMD_TYPE_FAKE_TIMEOUT:
|
||||
cmdq_clear_cmd_buf(cmd_info, hwdev);
|
||||
clear_wqe_complete_bit(cmdq, wqe, ci);
|
||||
break;
|
||||
case HINIC3_CMD_TYPE_SET_ARM:
|
||||
/* arm_bit was set until here */
|
||||
if (cmdq_arm_ceq_handler(cmdq, wqe, ci))
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
/* only arm bit is using scmd wqe,
|
||||
* the other wqe is lcmd
|
||||
|
|
@ -283,6 +332,18 @@ void hinic3_cmdq_ceq_handler(struct hinic3_hwdev *hwdev, __le32 ceqe_data)
|
|||
}
|
||||
}
|
||||
|
||||
static int cmdq_params_valid(const struct hinic3_hwdev *hwdev,
|
||||
const struct hinic3_cmd_buf *buf_in)
|
||||
{
|
||||
if (le16_to_cpu(buf_in->size) > CMDQ_BUF_SIZE) {
|
||||
dev_err(hwdev->dev, "Invalid CMDQ buffer size: 0x%x\n",
|
||||
le16_to_cpu(buf_in->size));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wait_cmdqs_enable(struct hinic3_cmdqs *cmdqs)
|
||||
{
|
||||
unsigned long end;
|
||||
|
|
@ -292,7 +353,8 @@ static int wait_cmdqs_enable(struct hinic3_cmdqs *cmdqs)
|
|||
if (cmdqs->status & HINIC3_CMDQ_ENABLE)
|
||||
return 0;
|
||||
usleep_range(1000, 2000);
|
||||
} while (time_before(jiffies, end) && !cmdqs->disable_flag);
|
||||
} while (time_before(jiffies, end) && !cmdqs->disable_flag &&
|
||||
cmdqs->hwdev->chip_present_flag);
|
||||
|
||||
cmdqs->disable_flag = 1;
|
||||
|
||||
|
|
@ -356,6 +418,7 @@ static void cmdq_prepare_wqe_ctrl(struct cmdq_wqe *wqe, u8 wrapped,
|
|||
enum cmdq_bufdesc_len buf_len)
|
||||
{
|
||||
struct cmdq_header *hdr = CMDQ_WQE_HEADER(wqe);
|
||||
__le32 saved_data = hdr->saved_data;
|
||||
enum cmdq_ctrl_sect_len ctrl_len;
|
||||
struct cmdq_wqe_lcmd *wqe_lcmd;
|
||||
struct cmdq_wqe_scmd *wqe_scmd;
|
||||
|
|
@ -386,6 +449,11 @@ static void cmdq_prepare_wqe_ctrl(struct cmdq_wqe *wqe, u8 wrapped,
|
|||
CMDQ_WQE_HDR_SET(3, COMPLETE_SECT_LEN) |
|
||||
CMDQ_WQE_HDR_SET(ctrl_len, CTRL_LEN) |
|
||||
CMDQ_WQE_HDR_SET(wrapped, HW_BUSY_BIT));
|
||||
|
||||
saved_data &= ~cpu_to_le32(SAVED_DATA_ARM_MASK);
|
||||
if (cmd == CMDQ_SET_ARM_CMD && mod == MGMT_MOD_COMM)
|
||||
saved_data |= cpu_to_le32(SAVED_DATA_SET(1, ARM));
|
||||
hdr->saved_data = saved_data;
|
||||
}
|
||||
|
||||
static void cmdq_set_lcmd_wqe(struct cmdq_wqe *wqe,
|
||||
|
|
@ -485,12 +553,15 @@ static int wait_cmdq_sync_cmd_completion(struct hinic3_cmdq *cmdq,
|
|||
clear_cmd_info(cmd_info, saved_cmd_info);
|
||||
spin_unlock_bh(&cmdq->cmdq_lock);
|
||||
|
||||
hinic3_dump_ceq_info(cmdq->hwdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cmdq_sync_cmd_direct_resp(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in,
|
||||
__le64 *out_param)
|
||||
static int cmdq_sync_cmd_exec(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in,
|
||||
struct hinic3_cmd_buf *buf_out,
|
||||
__le64 *out_param, u8 cmd_type, u8 wqe_cmd)
|
||||
{
|
||||
struct hinic3_cmdq_cmd_info *cmd_info, saved_cmd_info;
|
||||
int cmpt_code = CMDQ_SEND_CMPT_CODE;
|
||||
|
|
@ -520,31 +591,35 @@ static int cmdq_sync_cmd_direct_resp(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
|
|||
cmd_info = &cmdq->cmd_infos[curr_prod_idx];
|
||||
init_completion(&done);
|
||||
refcount_inc(&buf_in->ref_cnt);
|
||||
cmd_info->cmd_type = HINIC3_CMD_TYPE_DIRECT_RESP;
|
||||
if (buf_out)
|
||||
refcount_inc(&buf_out->ref_cnt);
|
||||
|
||||
cmd_info->cmd_type = cmd_type;
|
||||
cmd_info->done = &done;
|
||||
cmd_info->errcode = &errcode;
|
||||
cmd_info->direct_resp = out_param;
|
||||
cmd_info->cmpt_code = &cmpt_code;
|
||||
cmd_info->buf_in = buf_in;
|
||||
if (buf_out)
|
||||
cmd_info->buf_out = buf_out;
|
||||
|
||||
saved_cmd_info = *cmd_info;
|
||||
cmdq_set_lcmd_wqe(&wqe, CMDQ_CMD_DIRECT_RESP, buf_in, NULL,
|
||||
cmdq_set_lcmd_wqe(&wqe, wqe_cmd, buf_in, buf_out,
|
||||
wrapped, mod, cmd, curr_prod_idx);
|
||||
|
||||
cmdq_wqe_fill(curr_wqe, &wqe);
|
||||
(cmd_info->cmdq_msg_id)++;
|
||||
curr_msg_id = cmd_info->cmdq_msg_id;
|
||||
cmdq_set_db(cmdq, HINIC3_CMDQ_SYNC, next_prod_idx);
|
||||
cmdq_set_db(cmdq, cmdq->cmdq_type, next_prod_idx);
|
||||
spin_unlock_bh(&cmdq->cmdq_lock);
|
||||
|
||||
err = wait_cmdq_sync_cmd_completion(cmdq, cmd_info, &saved_cmd_info,
|
||||
curr_msg_id, curr_prod_idx,
|
||||
curr_wqe, CMDQ_CMD_TIMEOUT);
|
||||
if (err) {
|
||||
if (err)
|
||||
dev_err(cmdq->hwdev->dev,
|
||||
"Cmdq sync command timeout, mod: %u, cmd: %u, prod idx: 0x%x\n",
|
||||
mod, cmd, curr_prod_idx);
|
||||
err = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (cmpt_code == CMDQ_FORCE_STOP_CMPT_CODE) {
|
||||
dev_dbg(cmdq->hwdev->dev,
|
||||
|
|
@ -557,22 +632,114 @@ static int cmdq_sync_cmd_direct_resp(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
|
|||
return err ? err : errcode;
|
||||
}
|
||||
|
||||
static int cmdq_sync_cmd_direct_resp(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in,
|
||||
__le64 *out_param)
|
||||
{
|
||||
return cmdq_sync_cmd_exec(cmdq, mod, cmd, buf_in, NULL, out_param,
|
||||
HINIC3_CMD_TYPE_DIRECT_RESP,
|
||||
CMDQ_CMD_DIRECT_RESP);
|
||||
}
|
||||
|
||||
static int cmdq_sync_cmd_detail_resp(struct hinic3_cmdq *cmdq, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in,
|
||||
struct hinic3_cmd_buf *buf_out,
|
||||
__le64 *out_param)
|
||||
{
|
||||
return cmdq_sync_cmd_exec(cmdq, mod, cmd, buf_in, buf_out, out_param,
|
||||
HINIC3_CMD_TYPE_SGE_RESP,
|
||||
CMDQ_CMD_SGE_RESP);
|
||||
}
|
||||
|
||||
int hinic3_cmd_buf_pair_init(struct hinic3_hwdev *hwdev,
|
||||
struct hinic3_cmd_buf_pair *pair)
|
||||
{
|
||||
pair->in = hinic3_alloc_cmd_buf(hwdev);
|
||||
if (!pair->in)
|
||||
goto err_out;
|
||||
|
||||
pair->out = hinic3_alloc_cmd_buf(hwdev);
|
||||
if (!pair->out)
|
||||
goto err_free_cmd_buf_in;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_cmd_buf_in:
|
||||
hinic3_free_cmd_buf(hwdev, pair->in);
|
||||
err_out:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void hinic3_cmd_buf_pair_uninit(struct hinic3_hwdev *hwdev,
|
||||
struct hinic3_cmd_buf_pair *pair)
|
||||
{
|
||||
hinic3_free_cmd_buf(hwdev, pair->in);
|
||||
hinic3_free_cmd_buf(hwdev, pair->out);
|
||||
}
|
||||
|
||||
int hinic3_cmdq_direct_resp(struct hinic3_hwdev *hwdev, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in, __le64 *out_param)
|
||||
{
|
||||
struct hinic3_cmdqs *cmdqs;
|
||||
int err;
|
||||
|
||||
if (!hwdev->chip_present_flag)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
err = cmdq_params_valid(hwdev, buf_in);
|
||||
if (err) {
|
||||
dev_err(hwdev->dev, "Invalid CMDQ parameters\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
cmdqs = hwdev->cmdqs;
|
||||
err = wait_cmdqs_enable(cmdqs);
|
||||
if (err) {
|
||||
dev_err(hwdev->dev, "Cmdq is disabled\n");
|
||||
return err;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = cmdq_sync_cmd_direct_resp(&cmdqs->cmdq[HINIC3_CMDQ_SYNC],
|
||||
mod, cmd, buf_in, out_param);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int hinic3_cmdq_detail_resp(struct hinic3_hwdev *hwdev, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in,
|
||||
struct hinic3_cmd_buf *buf_out, __le64 *out_param)
|
||||
{
|
||||
struct hinic3_cmdqs *cmdqs;
|
||||
int err;
|
||||
|
||||
if (!hwdev->chip_present_flag)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
err = cmdq_params_valid(hwdev, buf_in);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
cmdqs = hwdev->cmdqs;
|
||||
|
||||
err = wait_cmdqs_enable(cmdqs);
|
||||
if (err) {
|
||||
dev_err(hwdev->dev, "Cmdq is disabled\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
err = cmdq_sync_cmd_detail_resp(&cmdqs->cmdq[HINIC3_CMDQ_SYNC],
|
||||
mod, cmd, buf_in, buf_out, out_param);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -758,7 +925,8 @@ static int init_cmdqs(struct hinic3_hwdev *hwdev)
|
|||
|
||||
static void cmdq_flush_sync_cmd(struct hinic3_cmdq_cmd_info *cmd_info)
|
||||
{
|
||||
if (cmd_info->cmd_type != HINIC3_CMD_TYPE_DIRECT_RESP)
|
||||
if (cmd_info->cmd_type != HINIC3_CMD_TYPE_DIRECT_RESP &&
|
||||
cmd_info->cmd_type != HINIC3_CMD_TYPE_SGE_RESP)
|
||||
return;
|
||||
|
||||
cmd_info->cmd_type = HINIC3_CMD_TYPE_FORCE_STOP;
|
||||
|
|
@ -785,7 +953,8 @@ static void hinic3_cmdq_flush_cmd(struct hinic3_cmdq *cmdq)
|
|||
while (cmdq_read_wqe(&cmdq->wq, &ci)) {
|
||||
hinic3_wq_put_wqebbs(&cmdq->wq, CMDQ_WQE_NUM_WQEBBS);
|
||||
cmd_info = &cmdq->cmd_infos[ci];
|
||||
if (cmd_info->cmd_type == HINIC3_CMD_TYPE_DIRECT_RESP)
|
||||
if (cmd_info->cmd_type == HINIC3_CMD_TYPE_DIRECT_RESP ||
|
||||
cmd_info->cmd_type == HINIC3_CMD_TYPE_SGE_RESP)
|
||||
cmdq_flush_sync_cmd(cmd_info);
|
||||
}
|
||||
spin_unlock_bh(&cmdq->cmdq_lock);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,9 @@ enum hinic3_cmdq_status {
|
|||
|
||||
enum hinic3_cmdq_cmd_type {
|
||||
HINIC3_CMD_TYPE_NONE,
|
||||
HINIC3_CMD_TYPE_SET_ARM,
|
||||
HINIC3_CMD_TYPE_DIRECT_RESP,
|
||||
HINIC3_CMD_TYPE_SGE_RESP,
|
||||
HINIC3_CMD_TYPE_FAKE_TIMEOUT,
|
||||
HINIC3_CMD_TYPE_TIMEOUT,
|
||||
HINIC3_CMD_TYPE_FORCE_STOP,
|
||||
|
|
@ -98,6 +100,11 @@ struct hinic3_cmd_buf {
|
|||
refcount_t ref_cnt;
|
||||
};
|
||||
|
||||
struct hinic3_cmd_buf_pair {
|
||||
struct hinic3_cmd_buf *in;
|
||||
struct hinic3_cmd_buf *out;
|
||||
};
|
||||
|
||||
struct hinic3_cmdq_cmd_info {
|
||||
enum hinic3_cmdq_cmd_type cmd_type;
|
||||
struct completion *done;
|
||||
|
|
@ -107,6 +114,7 @@ struct hinic3_cmdq_cmd_info {
|
|||
__le64 *direct_resp;
|
||||
u64 cmdq_msg_id;
|
||||
struct hinic3_cmd_buf *buf_in;
|
||||
struct hinic3_cmd_buf *buf_out;
|
||||
};
|
||||
|
||||
struct hinic3_cmdq {
|
||||
|
|
@ -146,8 +154,15 @@ void hinic3_free_cmd_buf(struct hinic3_hwdev *hwdev,
|
|||
struct hinic3_cmd_buf *cmd_buf);
|
||||
void hinic3_cmdq_ceq_handler(struct hinic3_hwdev *hwdev, __le32 ceqe_data);
|
||||
|
||||
int hinic3_cmd_buf_pair_init(struct hinic3_hwdev *hwdev,
|
||||
struct hinic3_cmd_buf_pair *pair);
|
||||
void hinic3_cmd_buf_pair_uninit(struct hinic3_hwdev *hwdev,
|
||||
struct hinic3_cmd_buf_pair *pair);
|
||||
int hinic3_cmdq_direct_resp(struct hinic3_hwdev *hwdev, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in, __le64 *out_param);
|
||||
int hinic3_cmdq_detail_resp(struct hinic3_hwdev *hwdev, u8 mod, u8 cmd,
|
||||
struct hinic3_cmd_buf *buf_in,
|
||||
struct hinic3_cmd_buf *buf_out, __le64 *out_param);
|
||||
|
||||
void hinic3_cmdq_flush_sync_cmd(struct hinic3_hwdev *hwdev);
|
||||
int hinic3_reinit_cmdq_ctxts(struct hinic3_hwdev *hwdev);
|
||||
|
|
|
|||
|
|
@ -59,10 +59,14 @@ int hinic3_wait_for_timeout(void *priv_data, wait_cpl_handler handler,
|
|||
enum hinic3_wait_return ret;
|
||||
int err;
|
||||
|
||||
err = read_poll_timeout(handler, ret, ret == HINIC3_WAIT_PROCESS_CPL,
|
||||
err = read_poll_timeout(handler, ret,
|
||||
!(ret & HINIC3_WAIT_PROCESS_WAITING),
|
||||
wait_once_us, wait_total_ms * USEC_PER_MSEC,
|
||||
false, priv_data);
|
||||
|
||||
if (ret == HINIC3_WAIT_PROCESS_ERR)
|
||||
return -EIO;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ struct hinic3_dma_addr_align {
|
|||
enum hinic3_wait_return {
|
||||
HINIC3_WAIT_PROCESS_CPL = 0,
|
||||
HINIC3_WAIT_PROCESS_WAITING = 1,
|
||||
HINIC3_WAIT_PROCESS_ERR = 2,
|
||||
};
|
||||
|
||||
struct hinic3_sge {
|
||||
|
|
|
|||
|
|
@ -76,9 +76,11 @@
|
|||
|
||||
#define HINIC3_CSR_AEQ_CTRL_0_ADDR (HINIC3_CFG_REGS_FLAG + 0x200)
|
||||
#define HINIC3_CSR_AEQ_CTRL_1_ADDR (HINIC3_CFG_REGS_FLAG + 0x204)
|
||||
#define HINIC3_CSR_AEQ_CONS_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x208)
|
||||
#define HINIC3_CSR_AEQ_PROD_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x20C)
|
||||
#define HINIC3_CSR_AEQ_CI_SIMPLE_INDIR_ADDR (HINIC3_CFG_REGS_FLAG + 0x50)
|
||||
|
||||
#define HINIC3_CSR_CEQ_CONS_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x288)
|
||||
#define HINIC3_CSR_CEQ_PROD_IDX_ADDR (HINIC3_CFG_REGS_FLAG + 0x28c)
|
||||
#define HINIC3_CSR_CEQ_CI_SIMPLE_INDIR_ADDR (HINIC3_CFG_REGS_FLAG + 0x54)
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@
|
|||
#define EQ_CI_SIMPLE_INDIR_SET(val, member) \
|
||||
FIELD_PREP(EQ_CI_SIMPLE_INDIR_##member##_MASK, val)
|
||||
|
||||
#define EQ_CONS_IDX_REG_ADDR(eq) \
|
||||
(((eq)->type == HINIC3_AEQ) ? \
|
||||
HINIC3_CSR_AEQ_CONS_IDX_ADDR : HINIC3_CSR_CEQ_CONS_IDX_ADDR)
|
||||
|
||||
#define EQ_CI_SIMPLE_INDIR_REG_ADDR(eq) \
|
||||
(((eq)->type == HINIC3_AEQ) ? \
|
||||
HINIC3_CSR_AEQ_CI_SIMPLE_INDIR_ADDR : \
|
||||
|
|
@ -353,6 +357,7 @@ static irqreturn_t ceq_interrupt(int irq, void *data)
|
|||
struct hinic3_eq *ceq = data;
|
||||
int err;
|
||||
|
||||
ceq->soft_intr_jif = jiffies;
|
||||
/* clear resend timer counters */
|
||||
hinic3_msix_intr_clear_resend_bit(ceq->hwdev, ceq->msix_entry_idx,
|
||||
EQ_MSIX_RESEND_TIMER_CLEAR);
|
||||
|
|
@ -713,6 +718,39 @@ void hinic3_aeqs_free(struct hinic3_hwdev *hwdev)
|
|||
kfree(aeqs);
|
||||
}
|
||||
|
||||
void hinic3_dump_aeq_info(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
const struct hinic3_aeq_elem *aeqe_pos;
|
||||
u32 addr, ci, pi, ctrl0, idx;
|
||||
struct hinic3_eq *eq;
|
||||
int q_id;
|
||||
|
||||
for (q_id = 0; q_id < hwdev->aeqs->num_aeqs; q_id++) {
|
||||
eq = &hwdev->aeqs->aeq[q_id];
|
||||
/* Indirect access should set q_id first */
|
||||
hinic3_hwif_write_reg(eq->hwdev->hwif,
|
||||
HINIC3_EQ_INDIR_IDX_ADDR(eq->type),
|
||||
eq->q_id);
|
||||
|
||||
addr = HINIC3_CSR_AEQ_CTRL_0_ADDR;
|
||||
|
||||
ctrl0 = hinic3_hwif_read_reg(hwdev->hwif, addr);
|
||||
|
||||
idx = hinic3_hwif_read_reg(hwdev->hwif,
|
||||
HINIC3_EQ_INDIR_IDX_ADDR(eq->type));
|
||||
|
||||
addr = EQ_CONS_IDX_REG_ADDR(eq);
|
||||
ci = hinic3_hwif_read_reg(hwdev->hwif, addr);
|
||||
addr = EQ_PROD_IDX_REG_ADDR(eq);
|
||||
pi = hinic3_hwif_read_reg(hwdev->hwif, addr);
|
||||
aeqe_pos = get_curr_aeq_elem(eq);
|
||||
dev_err(hwdev->dev,
|
||||
"Aeq id: %d, idx: %u, ctrl0: 0x%08x, ci: 0x%08x, pi: 0x%x, work_state: 0x%x, wrap: %u, desc: 0x%x swci:0x%x\n",
|
||||
q_id, idx, ctrl0, ci, pi, work_busy(&eq->aeq_work),
|
||||
eq->wrapped, be32_to_cpu(aeqe_pos->desc), eq->cons_idx);
|
||||
}
|
||||
}
|
||||
|
||||
int hinic3_ceqs_init(struct hinic3_hwdev *hwdev, u16 num_ceqs,
|
||||
struct msix_entry *msix_entries)
|
||||
{
|
||||
|
|
@ -773,3 +811,30 @@ void hinic3_ceqs_free(struct hinic3_hwdev *hwdev)
|
|||
|
||||
kfree(ceqs);
|
||||
}
|
||||
|
||||
void hinic3_dump_ceq_info(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
struct hinic3_eq *eq;
|
||||
u32 addr, ci, pi;
|
||||
int q_id;
|
||||
|
||||
for (q_id = 0; q_id < hwdev->ceqs->num_ceqs; q_id++) {
|
||||
eq = &hwdev->ceqs->ceq[q_id];
|
||||
/* Indirect access should set q_id first */
|
||||
hinic3_hwif_write_reg(eq->hwdev->hwif,
|
||||
HINIC3_EQ_INDIR_IDX_ADDR(eq->type),
|
||||
eq->q_id);
|
||||
|
||||
addr = EQ_CONS_IDX_REG_ADDR(eq);
|
||||
ci = hinic3_hwif_read_reg(hwdev->hwif, addr);
|
||||
addr = EQ_PROD_IDX_REG_ADDR(eq);
|
||||
pi = hinic3_hwif_read_reg(hwdev->hwif, addr);
|
||||
dev_err(hwdev->dev,
|
||||
"Ceq id: %d, ci: 0x%08x, sw_ci: 0x%08x, pi: 0x%x, wrap: %u, ceqe: 0x%x\n",
|
||||
q_id, ci, eq->cons_idx, pi,
|
||||
eq->wrapped, be32_to_cpu(*get_curr_ceq_elem(eq)));
|
||||
|
||||
dev_err(hwdev->dev, "Ceq last response soft interrupt time: %u\n",
|
||||
jiffies_to_msecs(jiffies - eq->soft_intr_jif));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ struct hinic3_eq {
|
|||
u16 msix_entry_idx;
|
||||
char irq_name[HINIC3_EQ_IRQ_NAME_LEN];
|
||||
struct work_struct aeq_work;
|
||||
|
||||
u64 soft_intr_jif;
|
||||
};
|
||||
|
||||
struct hinic3_aeq_elem {
|
||||
|
|
@ -110,6 +112,8 @@ int hinic3_aeq_register_cb(struct hinic3_hwdev *hwdev,
|
|||
hinic3_aeq_event_cb hwe_cb);
|
||||
void hinic3_aeq_unregister_cb(struct hinic3_hwdev *hwdev,
|
||||
enum hinic3_aeq_type event);
|
||||
void hinic3_dump_aeq_info(struct hinic3_hwdev *hwdev);
|
||||
|
||||
int hinic3_ceqs_init(struct hinic3_hwdev *hwdev, u16 num_ceqs,
|
||||
struct msix_entry *msix_entries);
|
||||
void hinic3_ceqs_free(struct hinic3_hwdev *hwdev);
|
||||
|
|
@ -118,5 +122,6 @@ int hinic3_ceq_register_cb(struct hinic3_hwdev *hwdev,
|
|||
hinic3_ceq_event_cb callback);
|
||||
void hinic3_ceq_unregister_cb(struct hinic3_hwdev *hwdev,
|
||||
enum hinic3_ceq_event event);
|
||||
void hinic3_dump_ceq_info(struct hinic3_hwdev *hwdev);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
425
drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
Normal file
425
drivers/net/ethernet/huawei/hinic3/hinic3_ethtool.c
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include "hinic3_lld.h"
|
||||
#include "hinic3_hw_comm.h"
|
||||
#include "hinic3_nic_dev.h"
|
||||
#include "hinic3_nic_cfg.h"
|
||||
|
||||
#define HINIC3_MGMT_VERSION_MAX_LEN 32
|
||||
|
||||
static void hinic3_get_drvinfo(struct net_device *netdev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
|
||||
u8 mgmt_ver[HINIC3_MGMT_VERSION_MAX_LEN];
|
||||
struct pci_dev *pdev = nic_dev->pdev;
|
||||
int err;
|
||||
|
||||
strscpy(info->driver, HINIC3_NIC_DRV_NAME, sizeof(info->driver));
|
||||
strscpy(info->bus_info, pci_name(pdev), sizeof(info->bus_info));
|
||||
|
||||
err = hinic3_get_mgmt_version(nic_dev->hwdev, mgmt_ver,
|
||||
HINIC3_MGMT_VERSION_MAX_LEN);
|
||||
if (err) {
|
||||
netdev_err(netdev, "Failed to get fw version\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(info->fw_version, sizeof(info->fw_version), "%s", mgmt_ver);
|
||||
}
|
||||
|
||||
static u32 hinic3_get_msglevel(struct net_device *netdev)
|
||||
{
|
||||
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
|
||||
|
||||
return nic_dev->msg_enable;
|
||||
}
|
||||
|
||||
static void hinic3_set_msglevel(struct net_device *netdev, u32 data)
|
||||
{
|
||||
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
|
||||
|
||||
nic_dev->msg_enable = data;
|
||||
|
||||
netdev_dbg(netdev, "Set message level: 0x%x\n", data);
|
||||
}
|
||||
|
||||
static const u32 hinic3_link_mode_ge[] = {
|
||||
ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_10ge_base_r[] = {
|
||||
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_25ge_base_r[] = {
|
||||
ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_40ge_base_r4[] = {
|
||||
ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_50ge_base_r[] = {
|
||||
ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_50ge_base_r2[] = {
|
||||
ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_100ge_base_r[] = {
|
||||
ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_100ge_base_r2[] = {
|
||||
ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_100ge_base_r4[] = {
|
||||
ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_200ge_base_r2[] = {
|
||||
ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
|
||||
};
|
||||
|
||||
static const u32 hinic3_link_mode_200ge_base_r4[] = {
|
||||
ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
|
||||
ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
|
||||
};
|
||||
|
||||
struct hw2ethtool_link_mode {
|
||||
const u32 *link_mode_bit_arr;
|
||||
u32 arr_size;
|
||||
u32 speed;
|
||||
};
|
||||
|
||||
static const struct hw2ethtool_link_mode
|
||||
hw2ethtool_link_mode_table[LINK_MODE_MAX_NUMBERS] = {
|
||||
[LINK_MODE_GE] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_ge,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_ge),
|
||||
.speed = SPEED_1000,
|
||||
},
|
||||
[LINK_MODE_10GE_BASE_R] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_10ge_base_r,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_10ge_base_r),
|
||||
.speed = SPEED_10000,
|
||||
},
|
||||
[LINK_MODE_25GE_BASE_R] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_25ge_base_r,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_25ge_base_r),
|
||||
.speed = SPEED_25000,
|
||||
},
|
||||
[LINK_MODE_40GE_BASE_R4] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_40ge_base_r4,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_40ge_base_r4),
|
||||
.speed = SPEED_40000,
|
||||
},
|
||||
[LINK_MODE_50GE_BASE_R] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_50ge_base_r,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_50ge_base_r),
|
||||
.speed = SPEED_50000,
|
||||
},
|
||||
[LINK_MODE_50GE_BASE_R2] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_50ge_base_r2,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_50ge_base_r2),
|
||||
.speed = SPEED_50000,
|
||||
},
|
||||
[LINK_MODE_100GE_BASE_R] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_100ge_base_r,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_100ge_base_r),
|
||||
.speed = SPEED_100000,
|
||||
},
|
||||
[LINK_MODE_100GE_BASE_R2] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_100ge_base_r2,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_100ge_base_r2),
|
||||
.speed = SPEED_100000,
|
||||
},
|
||||
[LINK_MODE_100GE_BASE_R4] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_100ge_base_r4,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_100ge_base_r4),
|
||||
.speed = SPEED_100000,
|
||||
},
|
||||
[LINK_MODE_200GE_BASE_R2] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_200ge_base_r2,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_200ge_base_r2),
|
||||
.speed = SPEED_200000,
|
||||
},
|
||||
[LINK_MODE_200GE_BASE_R4] = {
|
||||
.link_mode_bit_arr = hinic3_link_mode_200ge_base_r4,
|
||||
.arr_size = ARRAY_SIZE(hinic3_link_mode_200ge_base_r4),
|
||||
.speed = SPEED_200000,
|
||||
},
|
||||
};
|
||||
|
||||
#define GET_SUPPORTED_MODE 0
|
||||
#define GET_ADVERTISED_MODE 1
|
||||
|
||||
struct hinic3_link_settings {
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
|
||||
|
||||
u32 speed;
|
||||
u8 duplex;
|
||||
u8 port;
|
||||
u8 autoneg;
|
||||
};
|
||||
|
||||
#define HINIC3_ADD_SUPPORTED_LINK_MODE(ecmd, mode) \
|
||||
set_bit(ETHTOOL_LINK_##mode##_BIT, (ecmd)->supported)
|
||||
#define HINIC3_ADD_ADVERTISED_LINK_MODE(ecmd, mode) \
|
||||
set_bit(ETHTOOL_LINK_##mode##_BIT, (ecmd)->advertising)
|
||||
|
||||
static void hinic3_add_speed_link_mode(unsigned long *bitmap, u32 mode)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < hw2ethtool_link_mode_table[mode].arr_size; i++) {
|
||||
if (hw2ethtool_link_mode_table[mode].link_mode_bit_arr[i] >=
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS)
|
||||
continue;
|
||||
|
||||
set_bit(hw2ethtool_link_mode_table[mode].link_mode_bit_arr[i],
|
||||
bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Related to enum mag_cmd_port_speed */
|
||||
static const u32 hw_to_ethtool_speed[] = {
|
||||
(u32)SPEED_UNKNOWN, SPEED_10, SPEED_100, SPEED_1000, SPEED_10000,
|
||||
SPEED_25000, SPEED_40000, SPEED_50000, SPEED_100000, SPEED_200000
|
||||
};
|
||||
|
||||
static void
|
||||
hinic3_add_ethtool_link_mode(struct hinic3_link_settings *link_settings,
|
||||
u32 hw_link_mode, u32 name)
|
||||
{
|
||||
unsigned long *advertising_mask = link_settings->advertising;
|
||||
unsigned long *supported_mask = link_settings->supported;
|
||||
u32 link_mode;
|
||||
|
||||
for (link_mode = 0; link_mode < LINK_MODE_MAX_NUMBERS; link_mode++) {
|
||||
if (hw_link_mode & BIT(link_mode)) {
|
||||
if (name == GET_SUPPORTED_MODE)
|
||||
hinic3_add_speed_link_mode(supported_mask,
|
||||
link_mode);
|
||||
else
|
||||
hinic3_add_speed_link_mode(advertising_mask,
|
||||
link_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hinic3_link_speed_set(struct net_device *netdev,
|
||||
struct hinic3_link_settings *link_settings,
|
||||
struct hinic3_nic_port_info *port_info)
|
||||
{
|
||||
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
|
||||
bool link_status_up;
|
||||
int err;
|
||||
|
||||
if (port_info->supported_mode != LINK_MODE_UNKNOWN)
|
||||
hinic3_add_ethtool_link_mode(link_settings,
|
||||
port_info->supported_mode,
|
||||
GET_SUPPORTED_MODE);
|
||||
if (port_info->advertised_mode != LINK_MODE_UNKNOWN)
|
||||
hinic3_add_ethtool_link_mode(link_settings,
|
||||
port_info->advertised_mode,
|
||||
GET_ADVERTISED_MODE);
|
||||
|
||||
err = hinic3_get_link_status(nic_dev->hwdev, &link_status_up);
|
||||
if (!err && link_status_up) {
|
||||
link_settings->speed =
|
||||
port_info->speed < ARRAY_SIZE(hw_to_ethtool_speed) ?
|
||||
hw_to_ethtool_speed[port_info->speed] :
|
||||
(u32)SPEED_UNKNOWN;
|
||||
|
||||
link_settings->duplex = port_info->duplex;
|
||||
} else {
|
||||
link_settings->speed = (u32)SPEED_UNKNOWN;
|
||||
link_settings->duplex = DUPLEX_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hinic3_link_port_type_set(struct hinic3_link_settings *link_settings,
|
||||
u8 port_type)
|
||||
{
|
||||
switch (port_type) {
|
||||
case MAG_CMD_WIRE_TYPE_ELECTRIC:
|
||||
HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_TP);
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_TP);
|
||||
link_settings->port = PORT_TP;
|
||||
break;
|
||||
|
||||
case MAG_CMD_WIRE_TYPE_AOC:
|
||||
case MAG_CMD_WIRE_TYPE_MM:
|
||||
case MAG_CMD_WIRE_TYPE_SM:
|
||||
HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_FIBRE);
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_FIBRE);
|
||||
link_settings->port = PORT_FIBRE;
|
||||
break;
|
||||
|
||||
case MAG_CMD_WIRE_TYPE_COPPER:
|
||||
HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_FIBRE);
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_FIBRE);
|
||||
link_settings->port = PORT_DA;
|
||||
break;
|
||||
|
||||
case MAG_CMD_WIRE_TYPE_BACKPLANE:
|
||||
HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_Backplane);
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Backplane);
|
||||
link_settings->port = PORT_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
link_settings->port = PORT_OTHER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
hinic3_get_link_pause_settings(struct net_device *netdev,
|
||||
struct hinic3_link_settings *link_settings)
|
||||
{
|
||||
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
|
||||
struct hinic3_nic_pause_config nic_pause = {};
|
||||
int err;
|
||||
|
||||
err = hinic3_get_pause_info(nic_dev, &nic_pause);
|
||||
if (err) {
|
||||
netdev_err(netdev, "Failed to get pause param from hw\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_Pause);
|
||||
if (nic_pause.rx_pause && nic_pause.tx_pause) {
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Pause);
|
||||
} else if (nic_pause.tx_pause) {
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings,
|
||||
MODE_Asym_Pause);
|
||||
} else if (nic_pause.rx_pause) {
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Pause);
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings,
|
||||
MODE_Asym_Pause);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hinic3_get_link_settings(struct net_device *netdev,
|
||||
struct hinic3_link_settings *link_settings)
|
||||
{
|
||||
struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
|
||||
struct hinic3_nic_port_info port_info = {};
|
||||
int err;
|
||||
|
||||
err = hinic3_get_port_info(nic_dev->hwdev, &port_info);
|
||||
if (err) {
|
||||
netdev_err(netdev, "Failed to get port info\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
hinic3_link_speed_set(netdev, link_settings, &port_info);
|
||||
|
||||
hinic3_link_port_type_set(link_settings, port_info.port_type);
|
||||
|
||||
link_settings->autoneg = port_info.autoneg_state == PORT_CFG_AN_ON ?
|
||||
AUTONEG_ENABLE : AUTONEG_DISABLE;
|
||||
if (port_info.autoneg_cap)
|
||||
HINIC3_ADD_SUPPORTED_LINK_MODE(link_settings, MODE_Autoneg);
|
||||
if (port_info.autoneg_state == PORT_CFG_AN_ON)
|
||||
HINIC3_ADD_ADVERTISED_LINK_MODE(link_settings, MODE_Autoneg);
|
||||
|
||||
if (!HINIC3_IS_VF(nic_dev->hwdev)) {
|
||||
err = hinic3_get_link_pause_settings(netdev, link_settings);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hinic3_get_link_ksettings(struct net_device *netdev,
|
||||
struct ethtool_link_ksettings *link_settings)
|
||||
{
|
||||
struct ethtool_link_settings *base = &link_settings->base;
|
||||
struct hinic3_link_settings settings = {};
|
||||
int err;
|
||||
|
||||
ethtool_link_ksettings_zero_link_mode(link_settings, supported);
|
||||
ethtool_link_ksettings_zero_link_mode(link_settings, advertising);
|
||||
|
||||
err = hinic3_get_link_settings(netdev, &settings);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bitmap_copy(link_settings->link_modes.supported, settings.supported,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
bitmap_copy(link_settings->link_modes.advertising, settings.advertising,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
|
||||
base->autoneg = settings.autoneg;
|
||||
base->speed = settings.speed;
|
||||
base->duplex = settings.duplex;
|
||||
base->port = settings.port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ethtool_ops hinic3_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
||||
ETHTOOL_COALESCE_PKT_RATE_RX_USECS,
|
||||
.get_link_ksettings = hinic3_get_link_ksettings,
|
||||
.get_drvinfo = hinic3_get_drvinfo,
|
||||
.get_msglevel = hinic3_get_msglevel,
|
||||
.set_msglevel = hinic3_set_msglevel,
|
||||
.get_link = ethtool_op_get_link,
|
||||
};
|
||||
|
||||
void hinic3_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
netdev->ethtool_ops = &hinic3_ethtool_ops;
|
||||
}
|
||||
|
|
@ -17,6 +17,17 @@ static void hinic3_parse_pub_res_cap(struct hinic3_hwdev *hwdev,
|
|||
{
|
||||
cap->port_id = dev_cap->port_id;
|
||||
cap->supp_svcs_bitmap = dev_cap->svc_cap_en;
|
||||
|
||||
cap->cos_valid_bitmap = dev_cap->valid_cos_bitmap;
|
||||
cap->port_cos_valid_bitmap = dev_cap->port_cos_valid_bitmap;
|
||||
|
||||
if (type != HINIC3_FUNC_TYPE_VF)
|
||||
cap->max_vf = dev_cap->max_vf;
|
||||
else
|
||||
cap->max_vf = 0;
|
||||
|
||||
dev_dbg(hwdev->dev, "Port_id: 0x%x, cos_bitmap: 0x%x, Max_vf: 0x%x\n",
|
||||
cap->port_id, cap->cos_valid_bitmap, cap->max_vf);
|
||||
}
|
||||
|
||||
static void hinic3_parse_l2nic_res_cap(struct hinic3_hwdev *hwdev,
|
||||
|
|
@ -28,6 +39,13 @@ static void hinic3_parse_l2nic_res_cap(struct hinic3_hwdev *hwdev,
|
|||
|
||||
nic_svc_cap->max_sqs = min(dev_cap->nic_max_sq_id + 1,
|
||||
HINIC3_CFG_MAX_QP);
|
||||
|
||||
nic_svc_cap->max_rqs = min(dev_cap->nic_max_rq_id + 1,
|
||||
HINIC3_CFG_MAX_QP);
|
||||
nic_svc_cap->default_num_queues = dev_cap->nic_default_num_queues;
|
||||
|
||||
dev_dbg(hwdev->dev, "L2nic resource capbility, max_sqs: 0x%x, max_rqs: 0x%x\n",
|
||||
nic_svc_cap->max_sqs, nic_svc_cap->max_rqs);
|
||||
}
|
||||
|
||||
static void hinic3_parse_dev_cap(struct hinic3_hwdev *hwdev,
|
||||
|
|
@ -44,8 +62,8 @@ static void hinic3_parse_dev_cap(struct hinic3_hwdev *hwdev,
|
|||
hinic3_parse_l2nic_res_cap(hwdev, cap, dev_cap, type);
|
||||
}
|
||||
|
||||
static int get_cap_from_fw(struct hinic3_hwdev *hwdev,
|
||||
enum hinic3_func_type type)
|
||||
static int hinic3_get_cap_from_fw(struct hinic3_hwdev *hwdev,
|
||||
enum hinic3_func_type type)
|
||||
{
|
||||
struct mgmt_msg_params msg_params = {};
|
||||
struct cfg_cmd_dev_cap dev_cap = {};
|
||||
|
|
@ -69,6 +87,29 @@ static int get_cap_from_fw(struct hinic3_hwdev *hwdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hinic3_get_dev_cap(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
enum hinic3_func_type type = HINIC3_FUNC_TYPE(hwdev);
|
||||
int err;
|
||||
|
||||
switch (type) {
|
||||
case HINIC3_FUNC_TYPE_PF:
|
||||
case HINIC3_FUNC_TYPE_VF:
|
||||
err = hinic3_get_cap_from_fw(hwdev, type);
|
||||
if (err) {
|
||||
dev_err(hwdev->dev, "Failed to get FW capability\n");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(hwdev->dev, "Unsupported PCI Function type: %d\n",
|
||||
type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hinic3_init_irq_info(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
struct hinic3_cfg_mgmt_info *cfg_mgmt = hwdev->cfg_mgmt;
|
||||
|
|
@ -215,7 +256,7 @@ void hinic3_free_irq(struct hinic3_hwdev *hwdev, u32 irq_id)
|
|||
|
||||
int hinic3_init_capability(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
return get_cap_from_fw(hwdev, HINIC3_FUNC_TYPE_VF);
|
||||
return hinic3_get_dev_cap(hwdev);
|
||||
}
|
||||
|
||||
bool hinic3_support_nic(struct hinic3_hwdev *hwdev)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ struct hinic3_irq_info {
|
|||
|
||||
struct hinic3_nic_service_cap {
|
||||
u16 max_sqs;
|
||||
u16 max_rqs;
|
||||
u16 default_num_queues;
|
||||
};
|
||||
|
||||
/* Device capabilities */
|
||||
|
|
@ -34,6 +36,12 @@ struct hinic3_dev_cap {
|
|||
u16 supp_svcs_bitmap;
|
||||
/* Physical port */
|
||||
u8 port_id;
|
||||
|
||||
u8 cos_valid_bitmap;
|
||||
u8 port_cos_valid_bitmap;
|
||||
/* max number of VFs that PF supports */
|
||||
u16 max_vf;
|
||||
|
||||
struct hinic3_nic_service_cap nic_svc_cap;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -292,6 +292,32 @@ int hinic3_set_cmdq_depth(struct hinic3_hwdev *hwdev, u16 cmdq_depth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define HINIC3_FLR_TIMEOUT 1000
|
||||
|
||||
static enum hinic3_wait_return hinic3_check_flr_finish_handler(void *priv_data)
|
||||
{
|
||||
struct hinic3_hwdev *hwdev = priv_data;
|
||||
struct hinic3_hwif *hwif = hwdev->hwif;
|
||||
enum hinic3_pf_status status;
|
||||
|
||||
if (!hwdev->chip_present_flag)
|
||||
return HINIC3_WAIT_PROCESS_ERR;
|
||||
|
||||
status = hinic3_get_pf_status(hwif);
|
||||
if (status == HINIC3_PF_STATUS_FLR_FINISH_FLAG) {
|
||||
hinic3_set_pf_status(hwif, HINIC3_PF_STATUS_ACTIVE_FLAG);
|
||||
return HINIC3_WAIT_PROCESS_CPL;
|
||||
}
|
||||
|
||||
return HINIC3_WAIT_PROCESS_WAITING;
|
||||
}
|
||||
|
||||
static int hinic3_wait_for_flr_finish(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
return hinic3_wait_for_timeout(hwdev, hinic3_check_flr_finish_handler,
|
||||
HINIC3_FLR_TIMEOUT, 0xa * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
#define HINIC3_WAIT_CMDQ_IDLE_TIMEOUT 5000
|
||||
|
||||
static enum hinic3_wait_return check_cmdq_stop_handler(void *priv_data)
|
||||
|
|
@ -300,6 +326,10 @@ static enum hinic3_wait_return check_cmdq_stop_handler(void *priv_data)
|
|||
enum hinic3_cmdq_type cmdq_type;
|
||||
struct hinic3_cmdqs *cmdqs;
|
||||
|
||||
/* Stop waiting when card unpresent */
|
||||
if (!hwdev->chip_present_flag)
|
||||
return HINIC3_WAIT_PROCESS_ERR;
|
||||
|
||||
cmdqs = hwdev->cmdqs;
|
||||
for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) {
|
||||
if (!hinic3_cmdq_idle(&cmdqs->cmdq[cmdq_type]))
|
||||
|
|
@ -347,6 +377,9 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
|
|||
int ret = 0;
|
||||
int err;
|
||||
|
||||
if (!hwdev->chip_present_flag)
|
||||
return 0;
|
||||
|
||||
err = wait_cmdq_stop(hwdev);
|
||||
if (err) {
|
||||
dev_warn(hwdev->dev, "CMDQ is still working, CMDQ timeout value is unreasonable\n");
|
||||
|
|
@ -382,6 +415,14 @@ int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev)
|
|||
ret = err;
|
||||
}
|
||||
|
||||
if (HINIC3_FUNC_TYPE(hwdev) != HINIC3_FUNC_TYPE_VF) {
|
||||
err = hinic3_wait_for_flr_finish(hwdev);
|
||||
if (err) {
|
||||
dev_warn(hwdev->dev, "Wait firmware FLR timeout\n");
|
||||
ret = err;
|
||||
}
|
||||
}
|
||||
|
||||
hinic3_toggle_doorbell(hwif, ENABLE_DOORBELL);
|
||||
|
||||
err = hinic3_reinit_cmdq_ctxts(hwdev);
|
||||
|
|
@ -539,3 +580,31 @@ int hinic3_clean_root_ctxt(struct hinic3_hwdev *hwdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HINIC3_FW_VER_TYPE_MPU 1
|
||||
|
||||
int hinic3_get_mgmt_version(struct hinic3_hwdev *hwdev, u8 *mgmt_ver,
|
||||
u8 version_size)
|
||||
{
|
||||
struct comm_cmd_get_fw_version fw_ver = {};
|
||||
struct mgmt_msg_params msg_params = {};
|
||||
int err;
|
||||
|
||||
fw_ver.fw_type = HINIC3_FW_VER_TYPE_MPU;
|
||||
|
||||
mgmt_msg_params_init_default(&msg_params, &fw_ver, sizeof(fw_ver));
|
||||
|
||||
err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM,
|
||||
COMM_CMD_GET_FW_VERSION, &msg_params);
|
||||
|
||||
if (err || fw_ver.head.status) {
|
||||
dev_err(hwdev->dev,
|
||||
"Failed to get fw version, err: %d, status: 0x%x\n",
|
||||
err, fw_ver.head.status);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
snprintf(mgmt_ver, version_size, "%s", fw_ver.ver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,5 +49,7 @@ void hinic3_sync_time_to_fw(struct hinic3_hwdev *hwdev);
|
|||
int hinic3_set_root_ctxt(struct hinic3_hwdev *hwdev, u32 rq_depth, u32 sq_depth,
|
||||
int rx_buf_sz);
|
||||
int hinic3_clean_root_ctxt(struct hinic3_hwdev *hwdev);
|
||||
int hinic3_get_mgmt_version(struct hinic3_hwdev *hwdev, u8 *mgmt_ver,
|
||||
u8 version_size);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ enum comm_cmd {
|
|||
COMM_CMD_SET_DMA_ATTR = 25,
|
||||
|
||||
/* Commands for obtaining information */
|
||||
COMM_CMD_GET_FW_VERSION = 60,
|
||||
COMM_CMD_SYNC_TIME = 62,
|
||||
COMM_CMD_SEND_BDF_INFO = 64,
|
||||
};
|
||||
|
|
@ -275,6 +276,17 @@ struct comm_cmd_bdf_info {
|
|||
u8 rsvd2[5];
|
||||
};
|
||||
|
||||
#define COMM_FW_VERSION_LEN 16
|
||||
#define COMM_FW_COMPILE_TIME_LEN 20
|
||||
struct comm_cmd_get_fw_version {
|
||||
struct mgmt_msg_head head;
|
||||
|
||||
u16 fw_type;
|
||||
u16 rsvd1;
|
||||
u8 ver[COMM_FW_VERSION_LEN];
|
||||
u8 time[COMM_FW_COMPILE_TIME_LEN];
|
||||
};
|
||||
|
||||
/* Services supported by HW. HW uses these values when delivering events.
|
||||
* HW supports multiple services that are not yet supported by driver
|
||||
* (e.g. RoCE).
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
#define HINIC3_PCIE_PH_DISABLE 0
|
||||
#define HINIC3_PCIE_MSIX_ATTR_ENTRY 0
|
||||
|
||||
#define HINIC3_CHIP_PRESENT 1
|
||||
#define HINIC3_CHIP_ABSENT 0
|
||||
|
||||
#define HINIC3_DEFAULT_EQ_MSIX_PENDING_LIMIT 0
|
||||
#define HINIC3_DEFAULT_EQ_MSIX_COALESC_TIMER_CFG 0xFF
|
||||
#define HINIC3_DEFAULT_EQ_MSIX_RESEND_TIMER_CFG 7
|
||||
|
|
@ -431,6 +434,10 @@ static int init_cmdqs_channel(struct hinic3_hwdev *hwdev)
|
|||
static void hinic3_free_cmdqs_channel(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
hinic3_comm_cmdqs_free(hwdev);
|
||||
|
||||
hinic3_set_wq_page_size(hwdev, hinic3_global_func_id(hwdev),
|
||||
HINIC3_MIN_PAGE_SIZE);
|
||||
|
||||
hinic3_ceqs_free(hwdev);
|
||||
}
|
||||
|
||||
|
|
@ -545,6 +552,7 @@ int hinic3_init_hwdev(struct pci_dev *pdev)
|
|||
dev_err(hwdev->dev, "Failed to init hwif\n");
|
||||
goto err_free_hwdev;
|
||||
}
|
||||
hwdev->chip_present_flag = HINIC3_CHIP_PRESENT;
|
||||
|
||||
hwdev->workq = alloc_workqueue(HINIC3_HWDEV_WQ_NAME, WQ_MEM_RECLAIM | WQ_PERCPU,
|
||||
HINIC3_WQ_MAX_REQ);
|
||||
|
|
@ -621,6 +629,7 @@ void hinic3_set_api_stop(struct hinic3_hwdev *hwdev)
|
|||
struct hinic3_recv_msg *recv_resp_msg;
|
||||
struct hinic3_mbox *mbox;
|
||||
|
||||
hwdev->chip_present_flag = HINIC3_CHIP_ABSENT;
|
||||
spin_lock_bh(&hwdev->channel_lock);
|
||||
if (HINIC3_IS_PF(hwdev) &&
|
||||
test_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state)) {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ struct hinic3_hwdev {
|
|||
u32 wq_page_size;
|
||||
u8 max_cmdq;
|
||||
ulong func_state;
|
||||
int chip_present_flag;
|
||||
};
|
||||
|
||||
struct hinic3_event_info {
|
||||
|
|
|
|||
|
|
@ -70,11 +70,19 @@
|
|||
#define HINIC3_PPF_ELECTION_GET(val, member) \
|
||||
FIELD_GET(HINIC3_PPF_ELECTION_##member##_MASK, val)
|
||||
|
||||
#define HINIC3_GET_REG_FLAG(reg) ((reg) & (~(HINIC3_REGS_FLAG_MASK)))
|
||||
#define HINIC3_GET_REG_ADDR(reg) ((reg) & (HINIC3_REGS_FLAG_MASK))
|
||||
|
||||
static void __iomem *hinic3_reg_addr(struct hinic3_hwif *hwif, u32 reg)
|
||||
{
|
||||
return hwif->cfg_regs_base + HINIC3_GET_REG_ADDR(reg);
|
||||
void __iomem *addr;
|
||||
|
||||
if (HINIC3_GET_REG_FLAG(reg) == HINIC3_MGMT_REGS_FLAG)
|
||||
addr = hwif->mgmt_regs_base + HINIC3_GET_REG_ADDR(reg);
|
||||
else
|
||||
addr = hwif->cfg_regs_base + HINIC3_GET_REG_ADDR(reg);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
u32 hinic3_hwif_read_reg(struct hinic3_hwif *hwif, u32 reg)
|
||||
|
|
@ -97,6 +105,8 @@ static enum hinic3_wait_return check_hwif_ready_handler(void *priv_data)
|
|||
u32 attr1;
|
||||
|
||||
attr1 = hinic3_hwif_read_reg(hwdev->hwif, HINIC3_CSR_FUNC_ATTR1_ADDR);
|
||||
if (attr1 == HINIC3_PCIE_LINK_DOWN)
|
||||
return HINIC3_WAIT_PROCESS_ERR;
|
||||
|
||||
return HINIC3_AF1_GET(attr1, MGMT_INIT_STATUS) ?
|
||||
HINIC3_WAIT_PROCESS_CPL : HINIC3_WAIT_PROCESS_WAITING;
|
||||
|
|
@ -135,6 +145,7 @@ static void set_hwif_attr(struct hinic3_func_attr *attr, u32 attr0, u32 attr1,
|
|||
static int init_hwif_attr(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
u32 attr0, attr1, attr2, attr3, attr6;
|
||||
struct hinic3_func_attr *attr;
|
||||
struct hinic3_hwif *hwif;
|
||||
|
||||
hwif = hwdev->hwif;
|
||||
|
|
@ -158,7 +169,15 @@ static int init_hwif_attr(struct hinic3_hwdev *hwdev)
|
|||
if (attr6 == HINIC3_PCIE_LINK_DOWN)
|
||||
return -EFAULT;
|
||||
|
||||
set_hwif_attr(&hwif->attr, attr0, attr1, attr2, attr3, attr6);
|
||||
attr = &hwif->attr;
|
||||
set_hwif_attr(attr, attr0, attr1, attr2, attr3, attr6);
|
||||
|
||||
if (attr->func_type != HINIC3_FUNC_TYPE_VF &&
|
||||
attr->func_type != HINIC3_FUNC_TYPE_PF) {
|
||||
dev_err(hwdev->dev, "unexpected func_type %u\n",
|
||||
attr->func_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!hwif->attr.num_ceqs) {
|
||||
dev_err(hwdev->dev, "Ceq num cfg in fw is zero\n");
|
||||
|
|
|
|||
|
|
@ -426,6 +426,7 @@ static void hinic3_remove(struct pci_dev *pdev)
|
|||
}
|
||||
|
||||
static const struct pci_device_id hinic3_pci_table[] = {
|
||||
{PCI_VDEVICE(HUAWEI, PCI_DEV_ID_HINIC3_PF), 0},
|
||||
{PCI_VDEVICE(HUAWEI, PCI_DEV_ID_HINIC3_VF), 0},
|
||||
{0, 0}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#define HINIC3_NIC_DRV_DESC "Intelligent Network Interface Card Driver"
|
||||
|
||||
#define HINIC3_DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_LINK)
|
||||
#define HINIC3_RX_BUF_LEN 2048
|
||||
#define HINIC3_LRO_REPLENISH_THLD 256
|
||||
#define HINIC3_NIC_DEV_WQ_NAME "hinic3_nic_dev_wq"
|
||||
|
|
@ -143,6 +144,7 @@ static int hinic3_init_nic_dev(struct net_device *netdev,
|
|||
nic_dev->hwdev = hwdev;
|
||||
nic_dev->pdev = pdev;
|
||||
|
||||
nic_dev->msg_enable = HINIC3_DEFAULT_MSG_ENABLE;
|
||||
nic_dev->rx_buf_len = HINIC3_RX_BUF_LEN;
|
||||
nic_dev->lro_replenish_thld = HINIC3_LRO_REPLENISH_THLD;
|
||||
nic_dev->vlan_bitmap = kzalloc(HINIC3_VLAN_BITMAP_SIZE(nic_dev),
|
||||
|
|
@ -241,6 +243,7 @@ static void hinic3_sw_uninit(struct net_device *netdev)
|
|||
static void hinic3_assign_netdev_ops(struct net_device *netdev)
|
||||
{
|
||||
hinic3_set_netdev_ops(netdev);
|
||||
hinic3_set_ethtool_ops(netdev);
|
||||
}
|
||||
|
||||
static void netdev_feature_init(struct net_device *netdev)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "hinic3_common.h"
|
||||
#include "hinic3_csr.h"
|
||||
#include "hinic3_eqs.h"
|
||||
#include "hinic3_hwdev.h"
|
||||
#include "hinic3_hwif.h"
|
||||
#include "hinic3_mbox.h"
|
||||
|
|
@ -50,9 +51,9 @@
|
|||
#define MBOX_WB_STATUS_NOT_FINISHED 0x00
|
||||
|
||||
#define MBOX_STATUS_FINISHED(wb) \
|
||||
((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) != MBOX_WB_STATUS_NOT_FINISHED)
|
||||
((FIELD_GET(MBOX_WB_STATUS_MASK, (wb))) != MBOX_WB_STATUS_NOT_FINISHED)
|
||||
#define MBOX_STATUS_SUCCESS(wb) \
|
||||
((FIELD_PREP(MBOX_WB_STATUS_MASK, (wb))) == \
|
||||
((FIELD_GET(MBOX_WB_STATUS_MASK, (wb))) == \
|
||||
MBOX_WB_STATUS_FINISHED_SUCCESS)
|
||||
#define MBOX_STATUS_ERRCODE(wb) \
|
||||
((wb) & MBOX_WB_ERROR_CODE_MASK)
|
||||
|
|
@ -395,6 +396,7 @@ static int hinic3_mbox_pre_init(struct hinic3_hwdev *hwdev,
|
|||
{
|
||||
mbox->hwdev = hwdev;
|
||||
mutex_init(&mbox->mbox_send_lock);
|
||||
mutex_init(&mbox->mbox_seg_send_lock);
|
||||
spin_lock_init(&mbox->mbox_lock);
|
||||
|
||||
mbox->workq = create_singlethread_workqueue(HINIC3_MBOX_WQ_NAME);
|
||||
|
|
@ -460,7 +462,8 @@ void hinic3_free_mbox(struct hinic3_hwdev *hwdev)
|
|||
|
||||
destroy_workqueue(mbox->workq);
|
||||
free_mbox_wb_status(mbox);
|
||||
hinic3_uninit_func_mbox_msg_channel(hwdev);
|
||||
if (HINIC3_IS_VF(hwdev))
|
||||
hinic3_uninit_func_mbox_msg_channel(hwdev);
|
||||
uninit_mgmt_msg_channel(mbox);
|
||||
kfree(mbox);
|
||||
}
|
||||
|
|
@ -616,6 +619,18 @@ static void write_mbox_msg_attr(struct hinic3_mbox *mbox,
|
|||
mbox_ctrl);
|
||||
}
|
||||
|
||||
static void hinic3_dump_mbox_reg(struct hinic3_hwdev *hwdev)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = hinic3_hwif_read_reg(hwdev->hwif,
|
||||
HINIC3_FUNC_CSR_MAILBOX_CONTROL_OFF);
|
||||
dev_err(hwdev->dev, "Mailbox control reg: 0x%x\n", val);
|
||||
val = hinic3_hwif_read_reg(hwdev->hwif,
|
||||
HINIC3_FUNC_CSR_MAILBOX_INT_OFF);
|
||||
dev_err(hwdev->dev, "Mailbox interrupt offset: 0x%x\n", val);
|
||||
}
|
||||
|
||||
static u16 get_mbox_status(const struct hinic3_send_mbox *mbox)
|
||||
{
|
||||
__be64 *wb_status = mbox->wb_vaddr;
|
||||
|
|
@ -633,6 +648,9 @@ static enum hinic3_wait_return check_mbox_wb_status(void *priv_data)
|
|||
struct hinic3_mbox *mbox = priv_data;
|
||||
u16 wb_status;
|
||||
|
||||
if (!mbox->hwdev->chip_present_flag)
|
||||
return HINIC3_WAIT_PROCESS_ERR;
|
||||
|
||||
wb_status = get_mbox_status(&mbox->send_mbox);
|
||||
|
||||
return MBOX_STATUS_FINISHED(wb_status) ?
|
||||
|
|
@ -670,6 +688,7 @@ static int send_mbox_seg(struct hinic3_mbox *mbox, __le64 header,
|
|||
if (err) {
|
||||
dev_err(hwdev->dev, "Send mailbox segment timeout, wb status: 0x%x\n",
|
||||
wb_status);
|
||||
hinic3_dump_mbox_reg(hwdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -706,6 +725,8 @@ static int send_mbox_msg(struct hinic3_mbox *mbox, u8 mod, u16 cmd,
|
|||
else
|
||||
rsp_aeq_id = 0;
|
||||
|
||||
mutex_lock(&mbox->mbox_seg_send_lock);
|
||||
|
||||
if (dst_func == MBOX_MGMT_FUNC_ID &&
|
||||
!(hwdev->features[0] & MBOX_COMM_F_MBOX_SEGMENT)) {
|
||||
err = mbox_prepare_dma_msg(mbox, ack_type, &dma_msg,
|
||||
|
|
@ -759,6 +780,8 @@ static int send_mbox_msg(struct hinic3_mbox *mbox, u8 mod, u16 cmd,
|
|||
}
|
||||
|
||||
err_send:
|
||||
mutex_unlock(&mbox->mbox_seg_send_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -774,6 +797,9 @@ static enum hinic3_wait_return check_mbox_msg_finish(void *priv_data)
|
|||
{
|
||||
struct hinic3_mbox *mbox = priv_data;
|
||||
|
||||
if (!mbox->hwdev->chip_present_flag)
|
||||
return HINIC3_WAIT_PROCESS_ERR;
|
||||
|
||||
return (mbox->event_flag == MBOX_EVENT_SUCCESS) ?
|
||||
HINIC3_WAIT_PROCESS_CPL : HINIC3_WAIT_PROCESS_WAITING;
|
||||
}
|
||||
|
|
@ -805,6 +831,9 @@ int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
|
|||
u32 msg_len;
|
||||
int err;
|
||||
|
||||
if (!hwdev->chip_present_flag)
|
||||
return -EPERM;
|
||||
|
||||
/* expect response message */
|
||||
msg_desc = get_mbox_msg_desc(mbox, MBOX_MSG_RESP, MBOX_MGMT_FUNC_ID);
|
||||
mutex_lock(&mbox->mbox_send_lock);
|
||||
|
|
@ -825,6 +854,7 @@ int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
|
|||
if (wait_mbox_msg_completion(mbox, msg_params->timeout_ms)) {
|
||||
dev_err(hwdev->dev,
|
||||
"Send mbox msg timeout, msg_id: %u\n", msg_info.msg_id);
|
||||
hinic3_dump_aeq_info(mbox->hwdev);
|
||||
err = -ETIMEDOUT;
|
||||
goto err_send;
|
||||
}
|
||||
|
|
@ -882,6 +912,9 @@ int hinic3_send_mbox_to_mgmt_no_ack(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd,
|
|||
struct mbox_msg_info msg_info = {};
|
||||
int err;
|
||||
|
||||
if (!hwdev->chip_present_flag)
|
||||
return -EPERM;
|
||||
|
||||
mutex_lock(&mbox->mbox_send_lock);
|
||||
err = send_mbox_msg(mbox, mod, cmd, msg_params->buf_in,
|
||||
msg_params->in_size, MBOX_MGMT_FUNC_ID,
|
||||
|
|
|
|||
|
|
@ -114,6 +114,10 @@ struct hinic3_mbox {
|
|||
struct hinic3_hwdev *hwdev;
|
||||
/* lock for send mbox message and ack message */
|
||||
struct mutex mbox_send_lock;
|
||||
/* lock for send message transmission.
|
||||
* The lock hierarchy is mbox_send_lock -> mbox_seg_send_lock.
|
||||
*/
|
||||
struct mutex mbox_seg_send_lock;
|
||||
struct hinic3_send_mbox send_mbox;
|
||||
struct mbox_dma_queue sync_msg_queue;
|
||||
struct mbox_dma_queue async_msg_queue;
|
||||
|
|
|
|||
|
|
@ -183,7 +183,18 @@ struct l2nic_cmd_lro_timer {
|
|||
/* IEEE 802.1Qaz std */
|
||||
#define L2NIC_DCB_COS_MAX 0x8
|
||||
|
||||
struct l2nic_cmd_set_rss_ctx_tbl {
|
||||
struct l2nic_cmd_pause_config {
|
||||
struct mgmt_msg_head msg_head;
|
||||
u8 port_id;
|
||||
u8 opcode;
|
||||
u16 rsvd1;
|
||||
u8 auto_neg;
|
||||
u8 rx_pause;
|
||||
u8 tx_pause;
|
||||
u8 rsvd2[5];
|
||||
};
|
||||
|
||||
struct l2nic_cmd_rss_ctx_tbl {
|
||||
struct mgmt_msg_head msg_head;
|
||||
u16 func_id;
|
||||
u16 rsvd1;
|
||||
|
|
@ -238,6 +249,7 @@ enum l2nic_cmd {
|
|||
L2NIC_CMD_CFG_RSS_HASH_KEY = 63,
|
||||
L2NIC_CMD_CFG_RSS_HASH_ENGINE = 64,
|
||||
L2NIC_CMD_SET_RSS_CTX_TBL = 65,
|
||||
L2NIC_CMD_CFG_PAUSE_INFO = 101,
|
||||
L2NIC_CMD_QOS_DCB_STATE = 110,
|
||||
L2NIC_CMD_FORCE_PKT_DROP = 113,
|
||||
L2NIC_CMD_MAX = 256,
|
||||
|
|
@ -259,6 +271,8 @@ enum l2nic_ucode_cmd {
|
|||
enum mag_cmd {
|
||||
MAG_CMD_SET_PORT_ENABLE = 6,
|
||||
MAG_CMD_GET_LINK_STATUS = 7,
|
||||
|
||||
MAG_CMD_GET_PORT_INFO = 153,
|
||||
};
|
||||
|
||||
/* firmware also use this cmd report link event to driver */
|
||||
|
|
|
|||
|
|
@ -415,13 +415,17 @@ static void hinic3_vport_down(struct net_device *netdev)
|
|||
netif_carrier_off(netdev);
|
||||
netif_tx_disable(netdev);
|
||||
|
||||
glb_func_id = hinic3_global_func_id(nic_dev->hwdev);
|
||||
hinic3_set_vport_enable(nic_dev->hwdev, glb_func_id, false);
|
||||
if (nic_dev->hwdev->chip_present_flag) {
|
||||
hinic3_maybe_set_port_state(netdev, false);
|
||||
|
||||
hinic3_flush_txqs(netdev);
|
||||
/* wait to guarantee that no packets will be sent to host */
|
||||
msleep(100);
|
||||
hinic3_flush_qps_res(nic_dev->hwdev);
|
||||
glb_func_id = hinic3_global_func_id(nic_dev->hwdev);
|
||||
hinic3_set_vport_enable(nic_dev->hwdev, glb_func_id, false);
|
||||
|
||||
hinic3_flush_txqs(netdev);
|
||||
/* wait to guarantee that no packets will be sent to host */
|
||||
msleep(100);
|
||||
hinic3_flush_qps_res(nic_dev->hwdev);
|
||||
}
|
||||
}
|
||||
|
||||
static int hinic3_open(struct net_device *netdev)
|
||||
|
|
|
|||
|
|
@ -639,6 +639,39 @@ int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_up)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hinic3_get_port_info(struct hinic3_hwdev *hwdev,
|
||||
struct hinic3_nic_port_info *port_info)
|
||||
{
|
||||
struct mag_cmd_get_port_info port_msg = {};
|
||||
struct mgmt_msg_params msg_params = {};
|
||||
int err;
|
||||
|
||||
port_msg.port_id = hinic3_physical_port_id(hwdev);
|
||||
|
||||
mgmt_msg_params_init_default(&msg_params, &port_msg, sizeof(port_msg));
|
||||
|
||||
err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_HILINK,
|
||||
MAG_CMD_GET_PORT_INFO, &msg_params);
|
||||
|
||||
if (err || port_msg.head.status) {
|
||||
dev_err(hwdev->dev,
|
||||
"Failed to get port info, err: %d, status: 0x%x\n",
|
||||
err, port_msg.head.status);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
port_info->autoneg_cap = port_msg.an_support;
|
||||
port_info->autoneg_state = port_msg.an_en;
|
||||
port_info->duplex = port_msg.duplex;
|
||||
port_info->port_type = port_msg.wire_type;
|
||||
port_info->speed = port_msg.speed;
|
||||
port_info->fec = port_msg.fec;
|
||||
port_info->supported_mode = port_msg.supported_mode;
|
||||
port_info->advertised_mode = port_msg.advertised_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id,
|
||||
bool enable)
|
||||
{
|
||||
|
|
@ -661,3 +694,47 @@ int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hinic3_cfg_hw_pause(struct hinic3_hwdev *hwdev, u8 opcode,
|
||||
struct hinic3_nic_pause_config *nic_pause)
|
||||
{
|
||||
struct l2nic_cmd_pause_config pause_info = {};
|
||||
struct mgmt_msg_params msg_params = {};
|
||||
int err;
|
||||
|
||||
pause_info.port_id = hinic3_physical_port_id(hwdev);
|
||||
pause_info.opcode = opcode;
|
||||
if (opcode == MGMT_MSG_CMD_OP_SET) {
|
||||
pause_info.auto_neg = nic_pause->auto_neg;
|
||||
pause_info.rx_pause = nic_pause->rx_pause;
|
||||
pause_info.tx_pause = nic_pause->tx_pause;
|
||||
}
|
||||
|
||||
mgmt_msg_params_init_default(&msg_params, &pause_info,
|
||||
sizeof(pause_info));
|
||||
|
||||
err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_L2NIC,
|
||||
L2NIC_CMD_CFG_PAUSE_INFO, &msg_params);
|
||||
|
||||
if (err || pause_info.msg_head.status) {
|
||||
dev_err(hwdev->dev, "Failed to %s pause info, err: %d, status: 0x%x\n",
|
||||
opcode == MGMT_MSG_CMD_OP_SET ? "set" : "get",
|
||||
err, pause_info.msg_head.status);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (opcode == MGMT_MSG_CMD_OP_GET) {
|
||||
nic_pause->auto_neg = pause_info.auto_neg;
|
||||
nic_pause->rx_pause = pause_info.rx_pause;
|
||||
nic_pause->tx_pause = pause_info.tx_pause;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hinic3_get_pause_info(struct hinic3_nic_dev *nic_dev,
|
||||
struct hinic3_nic_pause_config *nic_pause)
|
||||
{
|
||||
return hinic3_cfg_hw_pause(nic_dev->hwdev, MGMT_MSG_CMD_OP_GET,
|
||||
nic_pause);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "hinic3_hwif.h"
|
||||
#include "hinic3_hw_intf.h"
|
||||
#include "hinic3_mgmt_interface.h"
|
||||
|
||||
|
|
@ -35,6 +36,49 @@ struct hinic3_sq_attr {
|
|||
u64 ci_dma_base;
|
||||
};
|
||||
|
||||
enum mag_cmd_port_an {
|
||||
PORT_CFG_AN_ON = 1,
|
||||
};
|
||||
|
||||
/* mag supported/advertised link mode bitmap */
|
||||
enum mag_cmd_link_mode {
|
||||
LINK_MODE_GE = 0,
|
||||
LINK_MODE_10GE_BASE_R = 1,
|
||||
LINK_MODE_25GE_BASE_R = 2,
|
||||
LINK_MODE_40GE_BASE_R4 = 3,
|
||||
LINK_MODE_50GE_BASE_R = 4,
|
||||
LINK_MODE_50GE_BASE_R2 = 5,
|
||||
LINK_MODE_100GE_BASE_R = 6,
|
||||
LINK_MODE_100GE_BASE_R2 = 7,
|
||||
LINK_MODE_100GE_BASE_R4 = 8,
|
||||
LINK_MODE_200GE_BASE_R2 = 9,
|
||||
LINK_MODE_200GE_BASE_R4 = 10,
|
||||
LINK_MODE_MAX_NUMBERS,
|
||||
|
||||
LINK_MODE_UNKNOWN = 0xFFFF
|
||||
};
|
||||
|
||||
struct mag_cmd_get_port_info {
|
||||
struct mgmt_msg_head head;
|
||||
|
||||
u8 port_id;
|
||||
u8 rsvd0[3];
|
||||
|
||||
u8 wire_type;
|
||||
u8 an_support;
|
||||
u8 an_en;
|
||||
u8 duplex;
|
||||
|
||||
u8 speed;
|
||||
u8 fec;
|
||||
u8 lanes;
|
||||
u8 rsvd1;
|
||||
|
||||
u32 supported_mode;
|
||||
u32 advertised_mode;
|
||||
u8 rsvd2[8];
|
||||
};
|
||||
|
||||
#define MAG_CMD_PORT_DISABLE 0x0
|
||||
#define MAG_CMD_TX_ENABLE 0x1
|
||||
#define MAG_CMD_RX_ENABLE 0x2
|
||||
|
|
@ -52,6 +96,39 @@ struct mag_cmd_set_port_enable {
|
|||
u8 rsvd1[3];
|
||||
};
|
||||
|
||||
/* xsfp wire type, refers to cmis protocol definition */
|
||||
enum mag_wire_type {
|
||||
MAG_CMD_WIRE_TYPE_UNKNOWN = 0x0,
|
||||
MAG_CMD_WIRE_TYPE_MM = 0x1,
|
||||
MAG_CMD_WIRE_TYPE_SM = 0x2,
|
||||
MAG_CMD_WIRE_TYPE_COPPER = 0x3,
|
||||
MAG_CMD_WIRE_TYPE_ACC = 0x4,
|
||||
MAG_CMD_WIRE_TYPE_BASET = 0x5,
|
||||
MAG_CMD_WIRE_TYPE_AOC = 0x40,
|
||||
MAG_CMD_WIRE_TYPE_ELECTRIC = 0x41,
|
||||
MAG_CMD_WIRE_TYPE_BACKPLANE = 0x42
|
||||
};
|
||||
|
||||
#define XSFP_INFO_MAX_SIZE 640
|
||||
struct mag_cmd_get_xsfp_info {
|
||||
struct mgmt_msg_head head;
|
||||
|
||||
u8 port_id;
|
||||
u8 wire_type;
|
||||
u16 out_len;
|
||||
u32 rsvd;
|
||||
u8 sfp_info[XSFP_INFO_MAX_SIZE];
|
||||
};
|
||||
|
||||
struct mag_cmd_get_xsfp_present {
|
||||
struct mgmt_msg_head head;
|
||||
|
||||
u8 port_id;
|
||||
/* 0:present, 1:absent */
|
||||
u8 abs_status;
|
||||
u8 rsvd[2];
|
||||
};
|
||||
|
||||
enum link_err_type {
|
||||
LINK_ERR_MODULE_UNRECOGENIZED,
|
||||
LINK_ERR_NUM,
|
||||
|
|
@ -69,6 +146,34 @@ struct hinic3_port_module_event {
|
|||
enum link_err_type err_type;
|
||||
};
|
||||
|
||||
struct hinic3_nic_port_info {
|
||||
u8 port_type;
|
||||
u8 autoneg_cap;
|
||||
u8 autoneg_state;
|
||||
u8 duplex;
|
||||
u8 speed;
|
||||
u8 fec;
|
||||
u32 supported_mode;
|
||||
u32 advertised_mode;
|
||||
};
|
||||
|
||||
struct hinic3_nic_pause_config {
|
||||
u8 auto_neg;
|
||||
u8 rx_pause;
|
||||
u8 tx_pause;
|
||||
};
|
||||
|
||||
struct hinic3_nic_cfg {
|
||||
/* Valid when pfc is disabled */
|
||||
bool pause_set;
|
||||
struct hinic3_nic_pause_config nic_pause;
|
||||
|
||||
u8 pfc_en;
|
||||
u8 pfc_bitmap;
|
||||
|
||||
struct hinic3_nic_port_info port_info;
|
||||
};
|
||||
|
||||
int hinic3_get_nic_feature_from_hw(struct hinic3_nic_dev *nic_dev);
|
||||
int hinic3_set_nic_feature_to_hw(struct hinic3_nic_dev *nic_dev);
|
||||
bool hinic3_test_support(struct hinic3_nic_dev *nic_dev,
|
||||
|
|
@ -100,9 +205,14 @@ int hinic3_set_rx_mode(struct hinic3_hwdev *hwdev, u32 rx_mode);
|
|||
int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state);
|
||||
int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable);
|
||||
int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_up);
|
||||
int hinic3_get_port_info(struct hinic3_hwdev *hwdev,
|
||||
struct hinic3_nic_port_info *port_info);
|
||||
int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id,
|
||||
bool enable);
|
||||
int hinic3_add_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id);
|
||||
int hinic3_del_vlan(struct hinic3_hwdev *hwdev, u16 vlan_id, u16 func_id);
|
||||
|
||||
int hinic3_get_pause_info(struct hinic3_nic_dev *nic_dev,
|
||||
struct hinic3_nic_pause_config *nic_pause);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ struct hinic3_nic_dev {
|
|||
struct hinic3_hwdev *hwdev;
|
||||
struct hinic3_nic_io *nic_io;
|
||||
|
||||
u32 msg_enable;
|
||||
u16 max_qps;
|
||||
u16 rx_buf_len;
|
||||
u32 lro_replenish_thld;
|
||||
|
|
@ -148,4 +149,6 @@ void hinic3_qps_irq_uninit(struct net_device *netdev);
|
|||
void hinic3_set_rx_mode_work(struct work_struct *work);
|
||||
void hinic3_clean_mac_list_filter(struct net_device *netdev);
|
||||
|
||||
void hinic3_set_ethtool_ops(struct net_device *netdev);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#ifndef _HINIC3_PCI_ID_TBL_H_
|
||||
#define _HINIC3_PCI_ID_TBL_H_
|
||||
|
||||
#define PCI_DEV_ID_HINIC3_PF 0x0222
|
||||
#define PCI_DEV_ID_HINIC3_VF 0x375F
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ static int hinic3_rss_set_indir_tbl(struct hinic3_hwdev *hwdev,
|
|||
static int hinic3_set_rss_type(struct hinic3_hwdev *hwdev,
|
||||
struct hinic3_rss_type rss_type)
|
||||
{
|
||||
struct l2nic_cmd_set_rss_ctx_tbl ctx_tbl = {};
|
||||
struct l2nic_cmd_rss_ctx_tbl ctx_tbl = {};
|
||||
struct mgmt_msg_params msg_params = {};
|
||||
u32 ctx;
|
||||
int err;
|
||||
|
|
|
|||
|
|
@ -328,6 +328,7 @@ static void hinic3_rx_csum(struct hinic3_rxq *rxq, u32 offload_type,
|
|||
u32 ip_type = RQ_CQE_OFFOLAD_TYPE_GET(offload_type, IP_TYPE);
|
||||
u32 csum_err = RQ_CQE_STATUS_GET(status, CSUM_ERR);
|
||||
struct net_device *netdev = rxq->netdev;
|
||||
bool l2_tunnel;
|
||||
|
||||
if (!(netdev->features & NETIF_F_RXCSUM))
|
||||
return;
|
||||
|
|
@ -350,6 +351,12 @@ static void hinic3_rx_csum(struct hinic3_rxq *rxq, u32 offload_type,
|
|||
case HINIC3_RX_UDP_PKT:
|
||||
case HINIC3_RX_SCTP_PKT:
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
l2_tunnel = HINIC3_GET_RX_TUNNEL_PKT_FORMAT(offload_type) ==
|
||||
HINIC3_RX_PKT_FORMAT_VXLAN ? 1 : 0;
|
||||
if (l2_tunnel) {
|
||||
/* If we checked the outer header let the stack know */
|
||||
skb->csum_level = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
|
|
@ -390,6 +397,14 @@ static int recv_one_pkt(struct hinic3_rxq *rxq, struct hinic3_rq_cqe *rx_cqe,
|
|||
offload_type = le32_to_cpu(rx_cqe->offload_type);
|
||||
hinic3_rx_csum(rxq, offload_type, status, skb);
|
||||
|
||||
if ((netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
|
||||
RQ_CQE_OFFOLAD_TYPE_GET(offload_type, VLAN_EN)) {
|
||||
u16 vid = RQ_CQE_SGE_GET(vlan_len, VLAN);
|
||||
|
||||
/* if the packet is a vlan pkt, the vid may be 0 */
|
||||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
|
||||
}
|
||||
|
||||
num_lro = RQ_CQE_STATUS_GET(status, NUM_LRO);
|
||||
if (num_lro)
|
||||
hinic3_lro_set_gso_params(skb, num_lro);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#define RQ_CQE_OFFOLAD_TYPE_GET(val, member) \
|
||||
FIELD_GET(RQ_CQE_OFFOLAD_TYPE_##member##_MASK, val)
|
||||
|
||||
#define HINIC3_GET_RX_TUNNEL_PKT_FORMAT(offload_type) \
|
||||
RQ_CQE_OFFOLAD_TYPE_GET(offload_type, TUNNEL_PKT_FORMAT)
|
||||
|
||||
#define RQ_CQE_SGE_VLAN_MASK GENMASK(15, 0)
|
||||
#define RQ_CQE_SGE_LEN_MASK GENMASK(31, 16)
|
||||
#define RQ_CQE_SGE_GET(val, member) \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user