提交 b2f43d83 编写于 作者: C Chiqijun 提交者: Zheng Zengkai

net/hinic: Add NIC Layer

driver inclusion
category: feature
bugzilla: 47993

-----------------------------------------------------------------------

Add NIC Layer support, include:
1. register net device to the kernel
2. implement the hooks of the 'struct net_device_ops' and
    'struct ethtool_ops'
3. etc.
Signed-off-by: NChiqijun <chiqijun@huawei.com>
Reviewed-by: NWangxiaoyun <cloud.wangxiaoyun@huawei.com>
Acked-by: NXie XiuQi <xiexiuqi@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 f1168d29
...@@ -6,4 +6,7 @@ hinic-y := hinic_nic_cfg.o hinic_nic_io.o hinic_nic_dbg.o \ ...@@ -6,4 +6,7 @@ hinic-y := hinic_nic_cfg.o hinic_nic_io.o hinic_nic_dbg.o \
hinic_mbox.o hinic_api_cmd.o hinic_mgmt.o \ hinic_mbox.o hinic_api_cmd.o hinic_mgmt.o \
hinic_wq.o hinic_cmdq.o hinic_hwdev.o hinic_cfg.o \ hinic_wq.o hinic_cmdq.o hinic_hwdev.o hinic_cfg.o \
hinic_sml_counter.o hinic_sml_lt.o \ hinic_sml_counter.o hinic_sml_lt.o \
hinic_multi_host_mgmt.o \ hinic_multi_host_mgmt.o hinic_main.o hinic_lld.o \
hinic_qp.o hinic_rx.o hinic_tx.o hinic_dbgtool_knl.o \
hinic_nictool.o hinic_sriov.o hinic_dcb.o\
hinic_ethtool.o
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef __DBGTOOL_KNL_H__
#define __DBGTOOL_KNL_H__
#define DBG_TOOL_MAGIC 'w'
/* dbgtool command type */
/* You can add the required dbgtool through these commands
* can invoke all X86 kernel mode driver interface
*/
enum dbgtool_cmd {
DBGTOOL_CMD_API_RD = 0,
DBGTOOL_CMD_API_WR,
DBGTOOL_CMD_FFM_RD,
DBGTOOL_CMD_FFM_CLR,
DBGTOOL_CMD_PF_DEV_INFO_GET,
DBGTOOL_CMD_MSG_2_UP,
DBGTOOL_CMD_FREE_MEM,
DBGTOOL_CMD_NUM
};
struct api_cmd_rd {
u32 pf_id;
u8 dest;
u8 *cmd;
u16 size;
void *ack;
u16 ack_size;
};
struct api_cmd_wr {
u32 pf_id;
u8 dest;
u8 *cmd;
u16 size;
};
struct pf_dev_info {
u64 bar0_size;
u8 bus;
u8 slot;
u8 func;
u64 phy_addr;
};
/* Interrupt at most records, interrupt will be recorded in the FFM */
#define FFM_RECORD_NUM_MAX 64
struct ffm_intr_tm_info {
u8 node_id;
/* error level of the interrupt source */
u8 err_level;
/* Classification by interrupt source properties */
u16 err_type;
u32 err_csr_addr;
u32 err_csr_value;
u8 sec; /* second*/
u8 min; /* minute */
u8 hour; /* hour */
u8 mday; /* day */
u8 mon; /* month */
u16 year; /* year */
};
struct ffm_record_info {
u32 ffm_num;
struct ffm_intr_tm_info ffm[FFM_RECORD_NUM_MAX];
};
struct msg_2_up {
u8 pf_id; /* which pf sends messages to the up */
u8 mod;
u8 cmd;
void *buf_in;
u16 in_size;
void *buf_out;
u16 *out_size;
};
struct dbgtool_param {
union {
struct api_cmd_rd api_rd;
struct api_cmd_wr api_wr;
struct pf_dev_info *dev_info;
struct ffm_record_info *ffm_rd;
struct msg_2_up msg2up;
} param;
char chip_name[16];
};
#define MAX_CARD_NUM 64
#define DBGTOOL_PAGE_ORDER 10
int dbgtool_knl_init(void *vhwdev, void *chip_node);
void dbgtool_knl_deinit(void *vhwdev, void *chip_node);
int hinic_mem_mmap(struct file *filp, struct vm_area_struct *vma);
void chipif_get_all_pf_dev_info(struct pf_dev_info *dev_info, int card_id,
void **g_func_handle_array);
long dbgtool_knl_free_mem(int id);
#endif
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_DCB_H_
#define HINIC_DCB_H_
#define HINIC_DCB_CFG_TX 0
#define HINIC_DCB_CFG_RX 1
/* IEEE8021QAZ Transmission selection algorithm identifiers */
#define IEEE8021Q_TSA_STRICT 0x0
#define IEEE8021Q_TSA_CBSHAPER 0x1
#define IEEE8021Q_TSA_ETS 0x2
#define IEEE8021Q_TSA_VENDOR 0xFF
enum HINIC_DCB_FLAGS {
HINIC_DCB_UP_COS_SETTING,
HINIC_DCB_TRAFFIC_STOPPED,
};
extern const struct dcbnl_rtnl_ops hinic_dcbnl_ops;
u8 hinic_dcb_get_tc(struct hinic_dcb_config *dcb_cfg, int dir, u8 up);
int hinic_dcb_init(struct hinic_nic_dev *nic_dev);
int hinic_dcb_reset_hw_config(struct hinic_nic_dev *nic_dev);
int hinic_setup_tc(struct net_device *netdev, u8 tc);
void hinic_configure_dcb(struct net_device *netdev);
int hinic_set_cos_up_map(struct hinic_nic_dev *nic_dev, u8 *cos_up);
int hinic_get_num_cos(struct hinic_nic_dev *nic_dev, u8 *num_cos);
int hinic_get_cos_up_map(struct hinic_nic_dev *nic_dev,
u8 *num_cos, u8 *cos_up);
u8 hinic_setup_dcb_tool(struct net_device *netdev, u8 *dcb_en, bool wr_flag);
void hinic_dcbnl_set_pfc_en_tool(struct net_device *netdev,
u8 *value, bool flag);
void hinic_dcbnl_set_pfc_cfg_tool(struct net_device *netdev, u8 setting);
void hinic_dcbnl_get_pfc_cfg_tool(struct net_device *netdev, u8 *setting);
u8 hinic_dcbnl_set_pfc_tool(struct net_device *netdev);
void hinic_dcbnl_get_tc_num_tool(struct net_device *netdev, u8 *tc_num);
void hinic_dcbnl_set_ets_tc_tool(struct net_device *netdev, u8 tc[], bool flag);
void hinic_dcbnl_set_ets_pecent_tool(struct net_device *netdev,
u8 percent[], bool flag);
void hinic_dcbnl_set_ets_en_tool(struct net_device *netdev,
u8 *value, bool flag);
void hinic_dcbnl_set_ets_strict_tool(struct net_device *netdev,
u8 *setting, bool flag);
u8 hinic_dcbnl_set_ets_tool(struct net_device *netdev);
#endif
此差异已折叠。
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_LLD_H_
#define HINIC_LLD_H_
#define HINIC_SLAVE_NIC_DELAY "hinic_slave_nic_delay"
#define HINIC_SLAVE_NIC_DELAY_TIME (5 * HZ)
struct hinic_lld_dev {
struct pci_dev *pdev;
void *hwdev;
};
enum hinic_init_state {
HINIC_INIT_STATE_NONE,
HINIC_INIT_STATE_PCI_INITED,
HINIC_INIT_STATE_HW_IF_INITED,
HINIC_INIT_STATE_HW_PART_INITED,
HINIC_INIT_STATE_HWDEV_INITED,
HINIC_INIT_STATE_DBGTOOL_INITED,
HINIC_INIT_STATE_NIC_INITED,
HINIC_INIT_STATE_ALL_INITED,
};
struct hinic_uld_info {
/* uld_dev: should not return null even the function capability
* is not support the up layer driver
* uld_dev_name: NIC driver should copy net device name.
* FC driver could copy fc device name.
* other up layer driver don`t need copy anything
*/
int (*probe)(struct hinic_lld_dev *lld_dev,
void **uld_dev, char *uld_dev_name);
void (*remove)(struct hinic_lld_dev *lld_dev, void *uld_dev);
int (*suspend)(struct hinic_lld_dev *lld_dev,
void *uld_dev, pm_message_t state);
int (*resume)(struct hinic_lld_dev *lld_dev, void *uld_dev);
void (*event)(struct hinic_lld_dev *lld_dev, void *uld_dev,
struct hinic_event_info *event);
int (*ioctl)(void *uld_dev, u32 cmd, void *buf_in,
u32 in_size, void *buf_out, u32 *out_size);
};
/* Used for the ULD HiNIC PCIe driver registration interface,
* the original interface is service_register_interface
*/
int hinic_register_uld(enum hinic_service_type uld_type,
struct hinic_uld_info *uld_info);
/* Used for the ULD HiNIC PCIe driver unregistration interface,
* the original interface is service_unregister_interface
*/
void hinic_unregister_uld(enum hinic_service_type uld_type);
void *hinic_get_ppf_uld_by_pdev(struct pci_dev *pdev,
enum hinic_service_type type);
/* used for TOE/IWARP */
struct net_device *hinic_get_netdev_by_lld(struct hinic_lld_dev *lld_dev);
/* used for TOE/IWARP */
void *hinic_get_hwdev_by_netdev(struct net_device *netdev);
struct net_device *hinic_get_netdev_by_pcidev(struct pci_dev *pdev);
void *hinic_get_hwdev_by_ifname(char *ifname);
int hinic_get_chip_name_by_hwdev(void *hwdev, char *ifname);
void *hinic_get_uld_dev_by_ifname(char *ifname, enum hinic_service_type type);
void *hinic_get_uld_by_chip_name(char *ifname, enum hinic_service_type type);
int hinic_get_pf_uld_array(struct pci_dev *pdev, u32 *dev_cnt, void *array[]);
int hinic_set_chip_cos_up_map(struct pci_dev *pdev, u8 *cos_up);
int hinic_get_chip_cos_up_map(struct pci_dev *pdev, bool *is_setted,
u8 *cos_up);
void hinic_get_all_chip_id(void *card_id);
void hinic_get_card_info(void *hwdev, void *bufin);
int hinic_get_device_id(void *hwdev, u16 *dev_id);
void get_fc_devname(char *devname);
int hinic_get_pf_id(void *hwdev, u32 port_id, u32 *pf_id, u32 *isvalid);
void hinic_tool_cnt_inc(void);
void hinic_tool_cnt_dec(void);
struct hinic_sriov_info;
struct hinic_sriov_info *hinic_get_sriov_info_by_pcidev(struct pci_dev *pdev);
/* for dpdk */
void *hinic_get_pci_dev(u16 bdf);
void hinic_dpdk_pcie_remove(void *pdev);
int hinic_dpdk_pcie_probe(void *pdev);
int hinic_attach_nic(struct hinic_lld_dev *lld_dev);
void hinic_detach_nic(struct hinic_lld_dev *lld_dev);
int hinic_attach_roce(struct hinic_lld_dev *lld_dev);
void hinic_detach_roce(struct hinic_lld_dev *lld_dev);
int hinic_disable_nic_rss(struct hinic_lld_dev *lld_dev);
int hinic_enable_nic_rss(struct hinic_lld_dev *lld_dev);
int hinic_ovs_set_vf_nic_state(struct hinic_lld_dev *lld_dev,
u16 vf_func_id, bool en);
int hinic_ovs_set_vf_load_state(struct pci_dev *pdev);
int hinic_get_self_test_result(char *ifname, u32 *result);
enum hinic_init_state hinic_get_init_state_by_ifname(char *ifname);
enum hinic_init_state hinic_get_init_state(struct pci_dev *pdev);
extern struct hinic_uld_info g_uld_info[SERVICE_T_MAX];
struct pci_device_id *hinic_get_pci_device_id(struct pci_dev *pdev);
bool hinic_is_in_host(void);
bool hinic_is_valid_bar_addr(u64 offset);
#endif
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_NIC_DEV_H
#define HINIC_NIC_DEV_H
#include <linux/netdevice.h>
#include <linux/semaphore.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include "ossl_knl.h"
#include "hinic_nic_io.h"
#include "hinic_nic_cfg.h"
#include "hinic_tx.h"
#include "hinic_rx.h"
#define HINIC_DRV_NAME "hinic"
#define HINIC_CHIP_NAME "hinic"
#define HINIC_DRV_VERSION "2.3.2.17"
struct vf_data_storage;
#define HINIC_FUNC_IS_VF(hwdev) (hinic_func_type(hwdev) == TYPE_VF)
enum hinic_flags {
HINIC_INTF_UP,
HINIC_MAC_FILTER_CHANGED,
HINIC_LP_TEST,
HINIC_RSS_ENABLE,
HINIC_DCB_ENABLE,
HINIC_SAME_RXTX,
HINIC_INTR_ADAPT,
HINIC_UPDATE_MAC_FILTER,
HINIC_ETS_ENABLE,
};
#define RX_BUFF_NUM_PER_PAGE 2
#define HINIC_MAX_MAC_NUM 3
#define LP_PKT_CNT 64
struct hinic_mac_addr {
u8 addr[ETH_ALEN];
u16 state;
};
enum hinic_rx_mode_state {
HINIC_HW_PROMISC_ON,
HINIC_HW_ALLMULTI_ON,
HINIC_PROMISC_FORCE_ON,
HINIC_ALLMULTI_FORCE_ON,
};
enum mac_filter_state {
HINIC_MAC_WAIT_HW_SYNC,
HINIC_MAC_HW_SYNCED,
HINIC_MAC_WAIT_HW_UNSYNC,
HINIC_MAC_HW_UNSYNCED,
};
struct hinic_mac_filter {
struct list_head list;
u8 addr[ETH_ALEN];
unsigned long state;
};
/* TC bandwidth allocation per direction */
struct hinic_tc_attr {
u8 pg_id; /* Priority Group(PG) ID */
u8 bw_pct; /* % of PG's bandwidth */
u8 up_map; /* User Priority to Traffic Class mapping */
u8 prio_type;
};
/* User priority configuration */
struct hinic_tc_cfg {
struct hinic_tc_attr path[2]; /* One each for Tx/Rx */
bool pfc_en;
};
struct hinic_dcb_config {
u8 pg_tcs;
u8 pfc_tcs;
bool pfc_state;
struct hinic_tc_cfg tc_cfg[HINIC_DCB_TC_MAX];
u8 bw_pct[2][HINIC_DCB_PG_MAX]; /* One each for Tx/Rx */
};
enum hinic_intr_flags {
HINIC_INTR_ON,
HINIC_RESEND_ON,
};
struct hinic_irq {
struct net_device *netdev;
/* IRQ corresponding index number */
u16 msix_entry_idx;
u32 irq_id; /* The IRQ number from OS */
char irq_name[IFNAMSIZ + 16];
struct napi_struct napi;
cpumask_t affinity_mask;
struct hinic_txq *txq;
struct hinic_rxq *rxq;
unsigned long intr_flag;
};
struct hinic_intr_coal_info {
u8 pending_limt;
u8 coalesce_timer_cfg;
u8 resend_timer_cfg;
u64 pkt_rate_low;
u8 rx_usecs_low;
u8 rx_pending_limt_low;
u64 pkt_rate_high;
u8 rx_usecs_high;
u8 rx_pending_limt_high;
u8 user_set_intr_coal_flag;
};
#define HINIC_NIC_STATS_INC(nic_dev, field) \
{ \
u64_stats_update_begin(&(nic_dev)->stats.syncp); \
(nic_dev)->stats.field++; \
u64_stats_update_end(&(nic_dev)->stats.syncp); \
}
struct hinic_nic_stats {
u64 netdev_tx_timeout;
/* Subdivision statistics show in private tool */
u64 tx_carrier_off_drop;
u64 tx_invalid_qid;
struct u64_stats_sync syncp;
};
struct hinic_nic_dev {
struct pci_dev *pdev;
struct net_device *netdev;
void *hwdev;
int poll_weight;
unsigned long *vlan_bitmap;
u16 num_qps;
u16 max_qps;
u32 msg_enable;
unsigned long flags;
u16 sq_depth;
u16 rq_depth;
/* mapping from priority */
u8 sq_cos_mapping[HINIC_DCB_UP_MAX];
u8 default_cos_id;
struct hinic_txq *txqs;
struct hinic_rxq *rxqs;
struct nic_service_cap nic_cap;
struct irq_info *qps_irq_info;
struct hinic_irq *irq_cfg;
struct work_struct rx_mode_work;
struct delayed_work moderation_task;
struct workqueue_struct *workq;
struct list_head uc_filter_list;
struct list_head mc_filter_list;
unsigned long rx_mod_state;
int netdev_uc_cnt;
int netdev_mc_cnt;
int lb_test_rx_idx;
int lb_pkt_len;
u8 *lb_test_rx_buf;
u8 rss_tmpl_idx;
u16 num_rss;
u16 rss_limit;
u8 rss_hash_engine;
struct nic_rss_type rss_type;
u8 *rss_hkey_user;
/* hkey in big endian */
u32 *rss_hkey_user_be;
u32 *rss_indir_user;
u8 dcbx_cap;
u32 dcb_changes;
u8 max_cos;
u8 up_valid_bitmap;
u8 up_cos[HINIC_DCB_UP_MAX];
struct ieee_ets hinic_ieee_ets_default;
struct ieee_ets hinic_ieee_ets;
struct ieee_pfc hinic_ieee_pfc;
struct hinic_dcb_config dcb_cfg;
struct hinic_dcb_config tmp_dcb_cfg;
struct hinic_dcb_config save_dcb_cfg;
unsigned long dcb_flags;
int disable_port_cnt;
/* lock for disable or enable traffic flow */
struct semaphore dcb_sem;
bool heart_status;
struct hinic_intr_coal_info *intr_coalesce;
unsigned long last_moder_jiffies;
u32 adaptive_rx_coal;
u8 intr_coal_set_flag;
u32 his_link_speed;
/* interrupt coalesce must be different in virtual machine */
bool in_vm;
bool is_vm_slave;
int is_bm_slave;
struct hinic_nic_stats stats;
/* lock for nic resource */
struct mutex nic_mutex;
bool force_port_disable;
struct semaphore port_state_sem;
u8 link_status;
struct hinic_environment_info env_info;
struct hinic_adaptive_cfg adaptive_cfg;
/* pangea cpu affinity setting */
bool force_affinity;
cpumask_t affinity_mask;
u32 lro_replenish_thld;
u16 rx_buff_len;
u32 page_order;
};
extern struct hinic_uld_info nic_uld_info;
int hinic_open(struct net_device *netdev);
int hinic_close(struct net_device *netdev);
void hinic_set_ethtool_ops(struct net_device *netdev);
void hinicvf_set_ethtool_ops(struct net_device *netdev);
void hinic_update_num_qps(struct net_device *netdev);
int nic_ioctl(void *uld_dev, u32 cmd, void *buf_in,
u32 in_size, void *buf_out, u32 *out_size);
int hinic_force_port_disable(struct hinic_nic_dev *nic_dev);
int hinic_force_set_port_state(struct hinic_nic_dev *nic_dev, bool enable);
int hinic_maybe_set_port_state(struct hinic_nic_dev *nic_dev, bool enable);
void hinic_link_status_change(struct hinic_nic_dev *nic_dev, bool status);
int hinic_disable_func_rss(struct hinic_nic_dev *nic_dev);
int hinic_enable_func_rss(struct hinic_nic_dev *nic_dev);
#define hinic_msg(level, nic_dev, msglvl, format, arg...) \
do { \
if ((nic_dev)->netdev && (nic_dev)->netdev->reg_state \
== NETREG_REGISTERED) \
nicif_##level((nic_dev), msglvl, (nic_dev)->netdev, \
format, ## arg); \
else \
nic_##level(&(nic_dev)->pdev->dev, \
format, ## arg); \
} while (0)
#define hinic_info(nic_dev, msglvl, format, arg...) \
hinic_msg(info, nic_dev, msglvl, format, ## arg)
#define hinic_warn(nic_dev, msglvl, format, arg...) \
hinic_msg(warn, nic_dev, msglvl, format, ## arg)
#define hinic_err(nic_dev, msglvl, format, arg...) \
hinic_msg(err, nic_dev, msglvl, format, ## arg)
#endif
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_NICTOOL_H_
#define HINIC_NICTOOL_H_
#include "hinic_dfx_def.h"
/* completion timeout interval, unit is jiffies*/
#define UP_COMP_TIME_OUT_VAL 10000U
struct sm_in_st {
int node;
int id;
int instance;
};
struct sm_out_st {
u64 val1;
u64 val2;
};
struct up_log_msg_st {
u32 rd_len;
u32 addr;
};
struct csr_write_st {
u32 rd_len;
u32 addr;
u8 *data;
};
struct ipsurx_stats_info {
u32 addr;
u32 rd_cnt;
};
struct ucode_cmd_st {
union {
struct {
u32 comm_mod_type : 8;
u32 ucode_cmd_type : 4;
u32 cmdq_ack_type : 3;
u32 ucode_imm : 1;
u32 len : 16;
} ucode_db;
u32 value;
};
};
struct up_cmd_st {
union {
struct {
u32 comm_mod_type : 8;
u32 chipif_cmd : 8;
u32 up_api_type : 16;
} up_db;
u32 value;
};
};
struct _dcb_data {
u8 wr_flag;
u8 dcb_en;
u8 err;
u8 rsvd;
};
union _dcb_ctl {
struct _dcb_data dcb_data;
u32 data;
};
struct _pfc_data {
u8 pfc_en;
u8 pfc_priority;
u8 num_of_tc;
u8 err;
};
union _pfc {
struct _pfc_data pfc_data;
u32 data;
};
union _flag_com {
struct _ets_flag {
u8 flag_ets_enable : 1;
u8 flag_ets_percent : 1;
u8 flag_ets_cos : 1;
u8 flag_ets_strict : 1;
u8 rev : 4;
} ets_flag;
u8 data;
};
struct _ets {
u8 ets_en;
u8 err;
u8 strict;
u8 tc[8];
u8 ets_percent[8];
union _flag_com flag_com;
};
#define API_CMD 0x1
#define API_CHAIN 0x2
#define API_CLP 0x3
struct msg_module {
char device_name[IFNAMSIZ];
unsigned int module;
union {
u32 msg_formate;
struct ucode_cmd_st ucode_cmd;
struct up_cmd_st up_cmd;
};
struct {
u32 in_buff_len;
u32 out_buff_len;
} len_info;
u32 res;
void *in_buff;
void *out_buf;
};
#define MAX_VER_INFO_LEN 128
struct drv_version_info {
char ver[MAX_VER_INFO_LEN];
};
struct chip_fault_stats {
int offset;
u8 chip_faults[MAX_DRV_BUF_SIZE];
};
struct hinic_wqe_info {
int q_id;
void *slq_handle;
unsigned int wqe_id;
};
struct hinic_cos_up_map {
u8 cos_up[HINIC_DCB_UP_MAX];
u8 num_cos;
};
struct hinic_tx_hw_page {
u64 phy_addr;
u64 *map_addr;
};
struct hinic_dbg_sq_info {
u16 q_id;
u16 pi;
u16 ci; /* sw_ci */
u16 fi; /* hw_ci */
u32 q_depth;
u16 pi_reverse;
u16 weqbb_size;
u8 priority;
u16 *ci_addr;
u64 cla_addr;
void *slq_handle;
struct hinic_tx_hw_page direct_wqe;
struct hinic_tx_hw_page db_addr;
u32 pg_idx;
u32 glb_sq_id;
};
struct hinic_dbg_rq_info {
u16 q_id;
u16 glb_rq_id;
u16 hw_pi;
u16 ci; /* sw_ci */
u16 sw_pi;
u16 wqebb_size;
u16 q_depth;
u16 buf_len;
void *slq_handle;
u64 ci_wqe_page_addr;
u64 ci_cla_tbl_addr;
u16 msix_idx;
u32 msix_vector;
};
#define BUSINFO_LEN 32
struct pf_info {
char name[IFNAMSIZ];
char bus_info[BUSINFO_LEN];
u32 pf_type;
};
#define MAX_SIZE 16
struct card_info {
struct pf_info pf[MAX_SIZE];
u32 pf_num;
};
struct nic_card_id {
u32 id[MAX_SIZE];
u32 num;
};
struct func_pdev_info {
u64 bar0_phy_addr;
u64 bar0_size;
u64 rsvd1[4];
};
struct hinic_card_func_info {
u32 num_pf;
u32 rsvd0;
u64 usr_api_phy_addr;
struct func_pdev_info pdev_info[MAX_SIZE];
};
#define MAX_CARD_NUM 64
extern void *g_card_node_array[MAX_CARD_NUM];
extern void *g_card_vir_addr[MAX_CARD_NUM];
extern u64 g_card_phy_addr[MAX_CARD_NUM];
extern struct mutex g_addr_lock;
extern int card_id;
struct hinic_nic_loop_mode {
u32 loop_mode;
u32 loop_ctrl;
};
struct hinic_nic_poll_weight {
int poll_weight;
};
enum hinic_homologues_state {
HINIC_HOMOLOGUES_OFF = 0,
HINIC_HOMOLOGUES_ON = 1,
};
struct hinic_homologues {
enum hinic_homologues_state homo_state;
};
struct hinic_pf_info {
u32 isvalid;
u32 pf_id;
};
int nictool_k_init(void);
void nictool_k_uninit(void);
u32 hinic_get_io_stats_size(struct hinic_nic_dev *nic_dev);
void hinic_get_io_stats(struct hinic_nic_dev *nic_dev,
struct hinic_show_item *items);
#define TOOL_COUNTER_MAX_LEN 512
#endif
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_PCI_ID_TBL_H
#define HINIC_PCI_ID_TBL_H
#define PCI_VENDOR_ID_HUAWEI 0x19e5
#define HINIC_DEV_ID_1822_PF 0x1822
#define HINIC_DEV_ID_1822_VF 0x375E
#define HINIC_DEV_ID_1822_VF_HV 0x379E
#define HINIC_DEV_ID_1822_SMTIO 0x020B
#define HINIC_DEV_ID_1822_PANGEA_100GE 0x0208
#define HINIC_DEV_ID_1822_PANGEA_TP_10GE 0x0204
#define HINIC_DEV_ID_1822_KR_40GE 0x020D
#define HINIC_DEV_ID_1822_KR_100GE 0x0205
#define HINIC_DEV_ID_1822_DUAL_25GE 0x0206
#define HINIC_DEV_ID_1822_KR_25GE 0x0210
#define HINIC_DEV_ID_1822_MULTI_HOST 0x0211
#define HINIC_DEV_ID_1822_100GE 0x0200
#define HINIC_DEV_ID_1822_100GE_MULTI_HOST 0x0201
#define HIFC_DEV_ID_1822_8G 0x0212
#define HIFC_DEV_ID_1822_16G 0x0203
#define HIFC_DEV_ID_1822_32G 0x0202
#define HIFC_DEV_ID_1822_SMTIO 0x020C
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": [NIC]" fmt
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include "hinic_nic_io.h"
#include "hinic_qp.h"
#define BUF_DESC_SHIFT 1
#define BUF_DESC_SIZE(nr_descs) (((u32)nr_descs) << BUF_DESC_SHIFT)
void hinic_prepare_sq_ctrl(struct hinic_sq_ctrl *ctrl, u32 queue_info,
int nr_descs, u8 owner)
{
u32 ctrl_size, task_size, bufdesc_size;
ctrl_size = SIZE_8BYTES(sizeof(struct hinic_sq_ctrl));
task_size = SIZE_8BYTES(sizeof(struct hinic_sq_task));
bufdesc_size = BUF_DESC_SIZE(nr_descs);
ctrl->ctrl_fmt = SQ_CTRL_SET(bufdesc_size, BUFDESC_SECT_LEN) |
SQ_CTRL_SET(task_size, TASKSECT_LEN) |
SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) |
SQ_CTRL_SET(ctrl_size, LEN) |
SQ_CTRL_SET(owner, OWNER);
ctrl->ctrl_fmt = be32_to_cpu(ctrl->ctrl_fmt);
ctrl->queue_info = queue_info;
ctrl->queue_info |= SQ_CTRL_QUEUE_INFO_SET(1U, UC);
if (!SQ_CTRL_QUEUE_INFO_GET(ctrl->queue_info, MSS)) {
ctrl->queue_info |= SQ_CTRL_QUEUE_INFO_SET(TX_MSS_DEFAULT, MSS);
} else if (SQ_CTRL_QUEUE_INFO_GET(ctrl->queue_info, MSS) < TX_MSS_MIN) {
/* mss should not less than 80 */
ctrl->queue_info = SQ_CTRL_QUEUE_INFO_CLEAR(ctrl->queue_info,
MSS);
ctrl->queue_info |= SQ_CTRL_QUEUE_INFO_SET(TX_MSS_MIN, MSS);
}
ctrl->queue_info = be32_to_cpu(ctrl->queue_info);
}
int hinic_get_rx_done(struct hinic_rq_cqe *cqe)
{
u32 status;
int rx_done;
status = be32_to_cpu(cqe->status);
rx_done = RQ_CQE_STATUS_GET(status, RXDONE);
if (!rx_done)
return 0;
return 1;
}
void hinic_clear_rx_done(struct hinic_rq_cqe *cqe, u32 status_old)
{
u32 status;
status = RQ_CQE_STATUS_CLEAR(status_old, RXDONE);
cqe->status = cpu_to_be32(status);
/* Make sure Rxdone has been set */
wmb();
}
int hinic_get_super_cqe_en(struct hinic_rq_cqe *cqe)
{
u32 pkt_info;
int super_cqe_en;
pkt_info = be32_to_cpu(cqe->pkt_info);
super_cqe_en = RQ_CQE_SUPER_CQE_EN_GET(pkt_info, SUPER_CQE_EN);
if (!super_cqe_en)
return 0;
return 1;
}
u32 hinic_get_pkt_len(struct hinic_rq_cqe *cqe)
{
u32 vlan_len = be32_to_cpu(cqe->vlan_len);
return RQ_CQE_SGE_GET(vlan_len, LEN);
}
u32 hinic_get_pkt_num(struct hinic_rq_cqe *cqe)
{
u32 pkt_num = be32_to_cpu(cqe->pkt_info);
return RQ_CQE_PKT_NUM_GET(pkt_num, NUM);
}
u32 hinic_get_pkt_len_for_super_cqe(struct hinic_rq_cqe *cqe,
bool last)
{
u32 pkt_len = be32_to_cpu(cqe->pkt_info);
if (!last)
return RQ_CQE_PKT_LEN_GET(pkt_len, FIRST_LEN);
else
return RQ_CQE_PKT_LEN_GET(pkt_len, LAST_LEN);
}
void hinic_prepare_rq_wqe(void *wqe, u16 pi, dma_addr_t buf_addr,
dma_addr_t cqe_dma)
{
struct hinic_rq_wqe *rq_wqe = (struct hinic_rq_wqe *)wqe;
struct hinic_rq_ctrl *ctrl = &rq_wqe->ctrl;
struct hinic_rq_cqe_sect *cqe_sect = &rq_wqe->cqe_sect;
struct hinic_rq_bufdesc *buf_desc = &rq_wqe->buf_desc;
u32 rq_ceq_len = sizeof(struct hinic_rq_cqe);
ctrl->ctrl_fmt =
RQ_CTRL_SET(SIZE_8BYTES(sizeof(*ctrl)), LEN) |
RQ_CTRL_SET(SIZE_8BYTES(sizeof(*cqe_sect)), COMPLETE_LEN) |
RQ_CTRL_SET(SIZE_8BYTES(sizeof(*buf_desc)), BUFDESC_SECT_LEN) |
RQ_CTRL_SET(RQ_COMPLETE_SGE, COMPLETE_FORMAT);
hinic_set_sge(&cqe_sect->sge, cqe_dma, rq_ceq_len);
buf_desc->addr_high = upper_32_bits(buf_addr);
buf_desc->addr_low = lower_32_bits(buf_addr);
}
void hinic_set_cs_inner_l4(struct hinic_sq_task *task,
u32 *queue_info,
enum sq_l4offload_type l4_offload,
u32 l4_len, u32 offset)
{
u32 tcp_udp_cs = 0, sctp = 0;
u32 mss = TX_MSS_DEFAULT;
/* tcp_udp_cs should be setted to calculate outter checksum when vxlan
* packets without inner l3 and l4
*/
if (unlikely(l4_offload == SCTP_OFFLOAD_ENABLE))
sctp = 1;
else
tcp_udp_cs = 1;
task->pkt_info0 |= SQ_TASK_INFO0_SET(l4_offload, L4OFFLOAD);
task->pkt_info1 |= SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
*queue_info |= SQ_CTRL_QUEUE_INFO_SET(offset, PLDOFF) |
SQ_CTRL_QUEUE_INFO_SET(tcp_udp_cs, TCPUDP_CS) |
SQ_CTRL_QUEUE_INFO_SET(sctp, SCTP);
*queue_info = SQ_CTRL_QUEUE_INFO_CLEAR(*queue_info, MSS);
*queue_info |= SQ_CTRL_QUEUE_INFO_SET(mss, MSS);
}
void hinic_set_tso_inner_l4(struct hinic_sq_task *task,
u32 *queue_info,
enum sq_l4offload_type l4_offload,
u32 l4_len,
u32 offset, u32 ip_ident, u32 mss)
{
u32 tso = 0, ufo = 0;
if (l4_offload == TCP_OFFLOAD_ENABLE)
tso = 1;
else if (l4_offload == UDP_OFFLOAD_ENABLE)
ufo = 1;
task->ufo_v6_identify = be32_to_cpu(ip_ident);
/* just keep the same code style here */
task->pkt_info0 |= SQ_TASK_INFO0_SET(l4_offload, L4OFFLOAD);
task->pkt_info0 |= SQ_TASK_INFO0_SET(tso || ufo, TSO_UFO);
task->pkt_info1 |= SQ_TASK_INFO1_SET(l4_len, INNER_L4LEN);
*queue_info |= SQ_CTRL_QUEUE_INFO_SET(offset, PLDOFF) |
SQ_CTRL_QUEUE_INFO_SET(tso, TSO) |
SQ_CTRL_QUEUE_INFO_SET(ufo, UFO) |
SQ_CTRL_QUEUE_INFO_SET(!!l4_offload, TCPUDP_CS);
/* cs must be calculate by hw if tso is enable */
*queue_info = SQ_CTRL_QUEUE_INFO_CLEAR(*queue_info, MSS);
/* qsf was initialized in prepare_sq_wqe */
*queue_info |= SQ_CTRL_QUEUE_INFO_SET(mss, MSS);
}
void hinic_set_vlan_tx_offload(struct hinic_sq_task *task,
u32 *queue_info,
u16 vlan_tag, u16 vlan_pri)
{
task->pkt_info0 |= SQ_TASK_INFO0_SET(vlan_tag, VLAN_TAG) |
SQ_TASK_INFO0_SET(1U, VLAN_OFFLOAD);
*queue_info |= SQ_CTRL_QUEUE_INFO_SET(vlan_pri, PRI);
}
void hinic_task_set_tx_offload_valid(struct hinic_sq_task *task, u32 l2hdr_len)
{
task->pkt_info0 |= SQ_TASK_INFO0_SET(l2hdr_len, L2HDR_LEN);
}
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_QP_H
#define HINIC_QP_H
#include "hinic_qe_def.h"
#include "hinic_port_cmd.h"
/* frags and linner */
#define HINIC_MAX_SQ_BUFDESCS (MAX_SKB_FRAGS + 1)
#define HINIC_MAX_SQ_SGE 17
#define HINIC_MAX_SKB_NR_FRAGE (HINIC_MAX_SQ_SGE - 1)
#define HINIC_GSO_MAX_SIZE 65536
struct hinic_sq_ctrl {
u32 ctrl_fmt;
u32 queue_info;
};
struct hinic_sq_task {
u32 pkt_info0;
u32 pkt_info1;
u32 pkt_info2;
u32 ufo_v6_identify;
u32 pkt_info4;
u32 rsvd5;
};
struct hinic_sq_bufdesc {
u32 hi_addr;
u32 lo_addr;
u32 len;
u32 rsvd;
};
struct hinic_sq_wqe {
struct hinic_sq_ctrl ctrl;
struct hinic_sq_task task;
struct hinic_sq_bufdesc buf_descs[HINIC_MAX_SQ_BUFDESCS];
};
struct hinic_rq_ctrl {
u32 ctrl_fmt;
};
struct hinic_rq_cqe {
u32 status;
u32 vlan_len;
u32 offload_type;
u32 hash_val;
u32 rsvd4;
u32 rsvd5;
u32 rsvd6;
u32 pkt_info;
};
struct hinic_rq_cqe_sect {
struct hinic_sge sge;
u32 rsvd;
};
struct hinic_rq_bufdesc {
u32 addr_high;
u32 addr_low;
};
struct hinic_rq_wqe {
struct hinic_rq_ctrl ctrl;
u32 rsvd;
struct hinic_rq_cqe_sect cqe_sect;
struct hinic_rq_bufdesc buf_desc;
};
void hinic_prepare_sq_ctrl(struct hinic_sq_ctrl *ctrl, u32 queue_info,
int nr_descs, u8 owner);
u32 hinic_get_pkt_len(struct hinic_rq_cqe *cqe);
int hinic_get_super_cqe_en(struct hinic_rq_cqe *cqe);
u32 hinic_get_pkt_len_for_super_cqe(struct hinic_rq_cqe *cqe, bool last);
u32 hinic_get_pkt_num(struct hinic_rq_cqe *cqe);
int hinic_get_rx_done(struct hinic_rq_cqe *cqe);
void hinic_clear_rx_done(struct hinic_rq_cqe *cqe, u32 status_old);
void hinic_prepare_rq_wqe(void *wqe, u16 pi, dma_addr_t buf_addr,
dma_addr_t cqe_dma);
static inline void hinic_task_set_outter_l3(struct hinic_sq_task *task,
enum sq_l3_type l3_type,
u32 network_len)
{
task->pkt_info2 |= SQ_TASK_INFO2_SET(l3_type, OUTER_L3TYPE) |
SQ_TASK_INFO2_SET(network_len, OUTER_L3LEN);
}
static inline void hinic_task_set_tunnel_l4(struct hinic_sq_task *task,
enum sq_tunnel_l4_type l4_type,
u32 tunnel_len)
{
task->pkt_info2 |= SQ_TASK_INFO2_SET(l4_type, TUNNEL_L4TYPE) |
SQ_TASK_INFO2_SET(tunnel_len, TUNNEL_L4LEN);
}
static inline void hinic_task_set_inner_l3(struct hinic_sq_task *task,
enum sq_l3_type l3_type,
u32 network_len)
{
task->pkt_info0 |= SQ_TASK_INFO0_SET(l3_type, INNER_L3TYPE);
task->pkt_info1 |= SQ_TASK_INFO1_SET(network_len, INNER_L3LEN);
}
void hinic_set_cs_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
enum sq_l4offload_type l4_offload,
u32 l4_len, u32 offset);
void hinic_set_tso_inner_l4(struct hinic_sq_task *task, u32 *queue_info,
enum sq_l4offload_type l4_offload, u32 l4_len,
u32 offset, u32 ip_ident, u32 mss);
void hinic_set_vlan_tx_offload(struct hinic_sq_task *task, u32 *queue_info,
u16 vlan_tag, u16 vlan_pri);
void hinic_task_set_tx_offload_valid(struct hinic_sq_task *task, u32 l2hdr_len);
#endif
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_RX_H
#define HINIC_RX_H
/* rx cqe checksum err */
#define HINIC_RX_CSUM_IP_CSUM_ERR BIT(0)
#define HINIC_RX_CSUM_TCP_CSUM_ERR BIT(1)
#define HINIC_RX_CSUM_UDP_CSUM_ERR BIT(2)
#define HINIC_RX_CSUM_IGMP_CSUM_ERR BIT(3)
#define HINIC_RX_CSUM_ICMPV4_CSUM_ERR BIT(4)
#define HINIC_RX_CSUM_ICMPV6_CSUM_ERR BIT(5)
#define HINIC_RX_CSUM_SCTP_CRC_ERR BIT(6)
#define HINIC_RX_CSUM_HW_CHECK_NONE BIT(7)
#define HINIC_RX_CSUM_IPSU_OTHER_ERR BIT(8)
#define HINIC_SUPPORT_LRO_ADAP_QPS_MAX 16
#define HINIC_RX_BUFFER_WRITE 16
struct hinic_rxq_stats {
u64 packets;
u64 bytes;
u64 errors;
u64 csum_errors;
u64 other_errors;
u64 dropped;
u64 rx_buf_empty;
u64 alloc_skb_err;
u64 alloc_rx_buf_err;
u64 map_rx_buf_err;
struct u64_stats_sync syncp;
};
struct hinic_rx_info {
dma_addr_t buf_dma_addr;
struct hinic_rq_cqe *cqe;
dma_addr_t cqe_dma;
struct page *page;
u32 page_offset;
struct hinic_rq_wqe *rq_wqe;
};
struct hinic_rxq {
struct net_device *netdev;
u16 q_id;
u16 q_depth;
u16 q_mask;
u16 buf_len;
u32 rx_buff_shift;
u32 dma_rx_buff_size;
struct hinic_rxq_stats rxq_stats;
u16 cons_idx;
u16 delta;
u32 irq_id;
u16 msix_entry_idx;
struct hinic_rx_info *rx_info;
struct hinic_irq *irq_cfg;
u16 next_to_alloc;
u16 next_to_update;
struct device *dev; /* device for DMA mapping */
unsigned long status;
dma_addr_t cqe_start_paddr;
void *cqe_start_vaddr;
u64 last_moder_packets;
u64 last_moder_bytes;
u8 last_coalesc_timer_cfg;
u8 last_pending_limt;
};
void hinic_rxq_clean_stats(struct hinic_rxq_stats *rxq_stats);
void hinic_rxq_get_stats(struct hinic_rxq *rxq,
struct hinic_rxq_stats *stats);
int hinic_alloc_rxqs(struct net_device *netdev);
void hinic_free_rxqs(struct net_device *netdev);
void hinic_init_rss_parameters(struct net_device *netdev);
void hinic_set_default_rss_indir(struct net_device *netdev);
int hinic_setup_all_rx_resources(struct net_device *netdev,
struct irq_info *msix_entries);
void hinic_free_all_rx_resources(struct net_device *netdev);
void hinic_rx_remove_configure(struct net_device *netdev);
int hinic_rx_configure(struct net_device *netdev);
int hinic_set_hw_rss_parameters(struct net_device *netdev, u8 rss_en, u8 num_tc,
u8 *prio_tc);
int hinic_update_hw_tc_map(struct net_device *netdev, u8 num_tc, u8 *prio_tc);
int hinic_rx_poll(struct hinic_rxq *rxq, int budget);
#endif
// SPDX-License-Identifier: GPL-2.0
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": [NIC]" fmt
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include "ossl_knl.h"
#include "hinic_hw.h"
#include "hinic_nic_cfg.h"
#include "hinic_nic_dev.h"
#include "hinic_sriov.h"
#include "hinic_lld.h"
int hinic_pci_sriov_disable(struct pci_dev *dev)
{
#ifdef CONFIG_PCI_IOV
struct hinic_sriov_info *sriov_info;
u16 tmp_vfs;
sriov_info = hinic_get_sriov_info_by_pcidev(dev);
/* if SR-IOV is already disabled then nothing will be done */
if (!sriov_info->sriov_enabled)
return 0;
if (test_and_set_bit(HINIC_SRIOV_DISABLE, &sriov_info->state)) {
nic_err(&sriov_info->pdev->dev,
"SR-IOV disable in process, please wait\n");
return -EPERM;
}
/* If our VFs are assigned we cannot shut down SR-IOV
* without causing issues, so just leave the hardware
* available but disabled
*/
if (pci_vfs_assigned(sriov_info->pdev)) {
clear_bit(HINIC_SRIOV_DISABLE, &sriov_info->state);
nic_warn(&sriov_info->pdev->dev, "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
return -EPERM;
}
sriov_info->sriov_enabled = false;
/* disable iov and allow time for transactions to clear */
pci_disable_sriov(sriov_info->pdev);
tmp_vfs = (u16)sriov_info->num_vfs;
sriov_info->num_vfs = 0;
hinic_deinit_vf_hw(sriov_info->hwdev, OS_VF_ID_TO_HW(0),
OS_VF_ID_TO_HW(tmp_vfs - 1));
clear_bit(HINIC_SRIOV_DISABLE, &sriov_info->state);
#endif
return 0;
}
int hinic_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
{
#ifdef CONFIG_PCI_IOV
struct hinic_sriov_info *sriov_info;
int err = 0;
int pre_existing_vfs = 0;
sriov_info = hinic_get_sriov_info_by_pcidev(dev);
if (test_and_set_bit(HINIC_SRIOV_ENABLE, &sriov_info->state)) {
nic_err(&sriov_info->pdev->dev,
"SR-IOV enable in process, please wait, num_vfs %d\n",
num_vfs);
return -EPERM;
}
pre_existing_vfs = pci_num_vf(sriov_info->pdev);
if (num_vfs > pci_sriov_get_totalvfs(sriov_info->pdev)) {
clear_bit(HINIC_SRIOV_ENABLE, &sriov_info->state);
return -ERANGE;
}
if (pre_existing_vfs && pre_existing_vfs != num_vfs) {
err = hinic_pci_sriov_disable(sriov_info->pdev);
if (err) {
clear_bit(HINIC_SRIOV_ENABLE, &sriov_info->state);
return err;
}
} else if (pre_existing_vfs == num_vfs) {
clear_bit(HINIC_SRIOV_ENABLE, &sriov_info->state);
return num_vfs;
}
err = hinic_init_vf_hw(sriov_info->hwdev, OS_VF_ID_TO_HW(0),
OS_VF_ID_TO_HW((u16)num_vfs - 1));
if (err) {
nic_err(&sriov_info->pdev->dev,
"Failed to init vf in hardware before enable sriov, error %d\n",
err);
clear_bit(HINIC_SRIOV_ENABLE, &sriov_info->state);
return err;
}
err = pci_enable_sriov(sriov_info->pdev, num_vfs);
if (err) {
nic_err(&sriov_info->pdev->dev,
"Failed to enable SR-IOV, error %d\n", err);
clear_bit(HINIC_SRIOV_ENABLE, &sriov_info->state);
return err;
}
sriov_info->sriov_enabled = true;
sriov_info->num_vfs = num_vfs;
clear_bit(HINIC_SRIOV_ENABLE, &sriov_info->state);
return num_vfs;
#else
return 0;
#endif
}
static bool hinic_is_support_sriov_configure(struct pci_dev *pdev)
{
enum hinic_init_state state = hinic_get_init_state(pdev);
struct hinic_sriov_info *sriov_info;
if (state < HINIC_INIT_STATE_NIC_INITED) {
nic_err(&pdev->dev, "NIC device not initialized, don't support to configure sriov\n");
return false;
}
sriov_info = hinic_get_sriov_info_by_pcidev(pdev);
if (FUNC_SRIOV_FIX_NUM_VF(sriov_info->hwdev)) {
nic_err(&pdev->dev, "Don't support to changed sriov configuration\n");
return false;
}
return true;
}
int hinic_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
{
struct hinic_sriov_info *sriov_info;
if (!hinic_is_support_sriov_configure(dev))
return -EFAULT;
sriov_info = hinic_get_sriov_info_by_pcidev(dev);
if (test_bit(HINIC_FUNC_REMOVE, &sriov_info->state))
return -EFAULT;
if (!num_vfs)
return hinic_pci_sriov_disable(dev);
else
return hinic_pci_sriov_enable(dev, num_vfs);
}
int hinic_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
{
struct hinic_nic_dev *adapter = netdev_priv(netdev);
struct hinic_sriov_info *sriov_info;
int err;
if (!FUNC_SUPPORT_SET_VF_MAC_VLAN(adapter->hwdev)) {
nicif_err(adapter, drv, netdev,
"Current function don't support to set vf mac\n");
return -EOPNOTSUPP;
}
sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev);
if (is_multicast_ether_addr(mac) || /*lint !e574*/
vf >= sriov_info->num_vfs) /*lint !e574*/
return -EINVAL;
err = hinic_set_vf_mac(sriov_info->hwdev, OS_VF_ID_TO_HW(vf), mac);
if (err) {
nicif_info(adapter, drv, netdev, "Failed to set MAC %pM on VF %d\n",
mac, vf);
return err;
}
if (is_zero_ether_addr(mac))
nicif_info(adapter, drv, netdev, "Removing MAC on VF %d\n", vf);
else
nicif_info(adapter, drv, netdev, "Setting MAC %pM on VF %d\n",
mac, vf);
nicif_info(adapter, drv, netdev, "Reload the VF driver to make this change effective\n");
return 0;
}
/*lint -save -e574 -e734*/
static int set_hw_vf_vlan(struct hinic_sriov_info *sriov_info,
u16 cur_vlanprio, int vf, u16 vlan, u8 qos)
{
int err = 0;
u16 old_vlan = cur_vlanprio & VLAN_VID_MASK;
if (vlan || qos) {
if (cur_vlanprio) {
err = hinic_kill_vf_vlan(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf));
if (err) {
nic_err(&sriov_info->pdev->dev, "Failed to delete vf %d old vlan %d\n",
vf, old_vlan);
return err;
}
}
err = hinic_add_vf_vlan(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf), vlan, qos);
if (err) {
nic_err(&sriov_info->pdev->dev, "Failed to add vf %d new vlan %d\n",
vf, vlan);
return err;
}
} else {
err = hinic_kill_vf_vlan(sriov_info->hwdev, OS_VF_ID_TO_HW(vf));
if (err) {
nic_err(&sriov_info->pdev->dev, "Failed to delete vf %d vlan %d\n",
vf, old_vlan);
return err;
}
}
return hinic_update_mac_vlan(sriov_info->hwdev, old_vlan, vlan,
OS_VF_ID_TO_HW(vf));
}
int hinic_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,
__be16 vlan_proto)
{
struct hinic_nic_dev *adapter = netdev_priv(netdev);
struct hinic_sriov_info *sriov_info;
u16 vlanprio, cur_vlanprio;
if (!FUNC_SUPPORT_SET_VF_MAC_VLAN(adapter->hwdev)) {
nicif_err(adapter, drv, netdev,
"Current function don't support to set vf vlan\n");
return -EOPNOTSUPP;
}
sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev);
if (vf >= sriov_info->num_vfs || vlan > 4095 || qos > 7)
return -EINVAL;
if (vlan_proto != htons(ETH_P_8021Q))
return -EPROTONOSUPPORT;
vlanprio = vlan | qos << HINIC_VLAN_PRIORITY_SHIFT;
cur_vlanprio = hinic_vf_info_vlanprio(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf));
/* duplicate request, so just return success */
if (vlanprio == cur_vlanprio)
return 0;
return set_hw_vf_vlan(sriov_info, cur_vlanprio, vf, vlan, qos);
}
int hinic_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting)
{
struct hinic_nic_dev *adapter = netdev_priv(netdev);
struct hinic_sriov_info *sriov_info;
int err = 0;
bool cur_spoofchk;
sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev);
if (vf >= sriov_info->num_vfs)
return -EINVAL;
cur_spoofchk = hinic_vf_info_spoofchk(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf));
/* same request, so just return success */
if ((setting && cur_spoofchk) || (!setting && !cur_spoofchk))
return 0;
err = hinic_set_vf_spoofchk(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf), setting);
if (!err) {
nicif_info(adapter, drv, netdev, "Set VF %d spoofchk %s\n",
vf, setting ? "on" : "off");
} else if (err == HINIC_MGMT_CMD_UNSUPPORTED) {
nicif_err(adapter, drv, netdev,
"Current firmware doesn't support to set vf spoofchk, need to upgrade latest firmware version\n");
err = -EOPNOTSUPP;
}
return err;
}
int hinic_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting)
{
struct hinic_nic_dev *adapter = netdev_priv(netdev);
struct hinic_sriov_info *sriov_info;
int err = 0;
bool cur_trust;
sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev);
if (vf >= sriov_info->num_vfs)
return -EINVAL;
cur_trust = hinic_vf_info_trust(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf));
/* same request, so just return success */
if ((setting && cur_trust) || (!setting && !cur_trust))
return 0;
err = hinic_set_vf_trust(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf), setting);
if (!err)
nicif_info(adapter, drv, netdev, "Set VF %d trusted %s succeed\n",
vf, setting ? "on" : "off");
else
nicif_err(adapter, drv, netdev, "Failed set VF %d trusted %s\n",
vf, setting ? "on" : "off");
return err;
}
int hinic_ndo_get_vf_config(struct net_device *netdev,
int vf, struct ifla_vf_info *ivi)
{
struct hinic_nic_dev *adapter = netdev_priv(netdev);
struct hinic_sriov_info *sriov_info;
sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev);
if (vf >= sriov_info->num_vfs)
return -EINVAL;
hinic_get_vf_config(sriov_info->hwdev, OS_VF_ID_TO_HW(vf), ivi);
return 0;
}
/**
* hinic_ndo_set_vf_link_state
* @netdev: network interface device structure
* @vf_id: VF identifier
* @link: required link state
* Return: 0 - success, negative - failure
* Set the link state of a specified VF, regardless of physical link state
*/
int hinic_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
{
struct hinic_nic_dev *adapter = netdev_priv(netdev);
struct hinic_sriov_info *sriov_info;
static const char * const vf_link[] = {"auto", "enable", "disable"};
int err;
if (FUNC_FORCE_LINK_UP(adapter->hwdev)) {
nicif_err(adapter, drv, netdev,
"Current function don't support to set vf link state\n");
return -EOPNOTSUPP;
}
sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev);
/* validate the request */
if (vf_id >= sriov_info->num_vfs) {
nicif_err(adapter, drv, netdev,
"Invalid VF Identifier %d\n", vf_id);
return -EINVAL;
}
err = hinic_set_vf_link_state(sriov_info->hwdev,
OS_VF_ID_TO_HW(vf_id), link);
if (!err)
nicif_info(adapter, drv, netdev, "Set VF %d link state: %s\n",
vf_id, vf_link[link]);
return err;
}
#define HINIC_TX_RATE_TABLE_FULL 12
int hinic_ndo_set_vf_bw(struct net_device *netdev,
int vf, int min_tx_rate, int max_tx_rate)
{
struct hinic_nic_dev *adapter = netdev_priv(netdev);
struct nic_port_info port_info = {0};
struct hinic_sriov_info *sriov_info;
u8 link_status = 0;
u32 speeds[] = {SPEED_10, SPEED_100, SPEED_1000, SPEED_10000,
SPEED_25000, SPEED_40000, SPEED_100000};
int err = 0;
if (!FUNC_SUPPORT_RATE_LIMIT(adapter->hwdev)) {
nicif_err(adapter, drv, netdev,
"Current function don't support to set vf rate limit\n");
return -EOPNOTSUPP;
}
sriov_info = hinic_get_sriov_info_by_pcidev(adapter->pdev);
/* verify VF is active */
if (vf >= sriov_info->num_vfs) {
nicif_err(adapter, drv, netdev, "VF number must be less than %d\n",
sriov_info->num_vfs);
return -EINVAL;
}
if (max_tx_rate < min_tx_rate) {
nicif_err(adapter, drv, netdev, "Invalid rate, max rate %d must greater than min rate %d\n",
max_tx_rate, min_tx_rate);
return -EINVAL;
}
err = hinic_get_link_state(adapter->hwdev, &link_status);
if (err) {
nicif_err(adapter, drv, netdev,
"Get link status failed when set vf tx rate\n");
return -EIO;
}
if (!link_status) {
nicif_err(adapter, drv, netdev,
"Link status must be up when set vf tx rate\n");
return -EINVAL;
}
err = hinic_get_port_info(adapter->hwdev, &port_info);
if (err || port_info.speed > LINK_SPEED_100GB)
return -EIO;
/* rate limit cannot be less than 0 and greater than link speed */
if (max_tx_rate < 0 || max_tx_rate > speeds[port_info.speed]) {
nicif_err(adapter, drv, netdev, "Set vf max tx rate must be in [0 - %d]\n",
speeds[port_info.speed]);
return -EINVAL;
}
err = hinic_set_vf_tx_rate(adapter->hwdev, OS_VF_ID_TO_HW(vf),
max_tx_rate, min_tx_rate);
if (err) {
nicif_err(adapter, drv, netdev,
"Unable to set VF %d max rate %d min rate %d%s\n",
vf, max_tx_rate, min_tx_rate,
err == HINIC_TX_RATE_TABLE_FULL ?
", tx rate profile is full" : "");
return -EIO;
}
nicif_info(adapter, drv, netdev,
"Set VF %d max tx rate %d min tx rate %d successfully\n",
vf, max_tx_rate, min_tx_rate);
return 0;
}
/*lint -restore*/
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_SRIOV_H
#define HINIC_SRIOV_H
enum hinic_sriov_state {
HINIC_SRIOV_DISABLE,
HINIC_SRIOV_ENABLE,
HINIC_FUNC_REMOVE,
};
struct hinic_sriov_info {
struct pci_dev *pdev;
void *hwdev;
bool sriov_enabled;
unsigned int num_vfs;
unsigned long state;
};
int hinic_pci_sriov_disable(struct pci_dev *dev);
int hinic_pci_sriov_enable(struct pci_dev *dev, int num_vfs);
int hinic_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
int hinic_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac);
int hinic_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos,
__be16 vlan_proto);
int hinic_ndo_get_vf_config(struct net_device *netdev, int vf,
struct ifla_vf_info *ivi);
int hinic_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting);
int hinic_ndo_set_vf_trust(struct net_device *netdev, int vf, bool setting);
int hinic_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
int hinic_ndo_set_vf_bw(struct net_device *netdev,
int vf, int min_tx_rate, int max_tx_rate);
#endif
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0*/
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#ifndef HINIC_TX_H
#define HINIC_TX_H
enum tx_offload_type {
TX_OFFLOAD_TSO = BIT(0),
TX_OFFLOAD_CSUM = BIT(1),
TX_OFFLOAD_VLAN = BIT(2),
TX_OFFLOAD_INVALID = BIT(3),
};
struct hinic_txq_stats {
u64 packets;
u64 bytes;
u64 busy;
u64 wake;
u64 dropped;
u64 big_frags_pkts;
u64 big_udp_pkts;
/* Subdivision statistics show in private tool */
u64 ufo_pkt_unsupport;
u64 ufo_linearize_err;
u64 ufo_alloc_skb_err;
u64 skb_pad_err;
u64 frag_len_overflow;
u64 offload_cow_skb_err;
u64 alloc_cpy_frag_err;
u64 map_cpy_frag_err;
u64 map_frag_err;
u64 frag_size_err;
u64 unknown_tunnel_pkt;
struct u64_stats_sync syncp;
};
struct hinic_dma_len {
dma_addr_t dma;
u32 len;
};
#define MAX_SGE_NUM_PER_WQE 17
struct hinic_tx_info {
struct sk_buff *skb;
int wqebb_cnt;
int num_sge;
void *wqe;
u8 *cpy_buff;
u16 valid_nr_frags;
u16 num_pkts;
u64 num_bytes;
struct hinic_dma_len dma_len[MAX_SGE_NUM_PER_WQE];
};
struct hinic_txq {
struct net_device *netdev;
u16 q_id;
u16 q_depth;
u16 q_mask;
struct hinic_txq_stats txq_stats;
u64 last_moder_packets;
u64 last_moder_bytes;
struct hinic_tx_info *tx_info;
};
enum hinic_tx_xmit_status {
HINIC_TX_OK = 0,
HINIC_TX_DROPPED = 1,
HINIC_TX_BUSY = 2,
};
enum hinic_tx_avd_type {
HINIC_TX_NON_AVD = 0,
HINIC_TX_UFO_AVD = 1,
};
void hinic_txq_clean_stats(struct hinic_txq_stats *txq_stats);
void hinic_txq_get_stats(struct hinic_txq *txq,
struct hinic_txq_stats *stats);
netdev_tx_t hinic_lb_xmit_frame(struct sk_buff *skb,
struct net_device *netdev);
netdev_tx_t hinic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
int hinic_setup_all_tx_resources(struct net_device *netdev);
void hinic_free_all_tx_resources(struct net_device *netdev);
void hinic_set_sq_default_cos(struct net_device *netdev, u8 cos_id);
int hinic_sq_cos_mapping(struct net_device *netdev);
int hinic_alloc_txqs(struct net_device *netdev);
void hinic_free_txqs(struct net_device *netdev);
int hinic_tx_poll(struct hinic_txq *txq, int budget);
u8 hinic_get_vlan_pri(struct sk_buff *skb);
void hinic_flush_txqs(struct net_device *netdev);
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册