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:
Paolo Abeni 2026-03-12 12:13:50 +01:00
commit 52e4d5da6d
30 changed files with 1146 additions and 30 deletions

View File

@ -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 \

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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 {

View File

@ -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)

View File

@ -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));
}
}

View File

@ -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

View 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;
}

View File

@ -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)

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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

View File

@ -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).

View File

@ -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)) {

View File

@ -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 {

View File

@ -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");

View File

@ -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}

View File

@ -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)

View File

@ -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,

View File

@ -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;

View File

@ -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 */

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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) \