Shaozhengchao (1): net/hinic: Solve the problem that the network card hangs when receiving the skb which frag_size=0
Shengzui You (2): net: hns3: update hns3 version to 1.9.37.1 net: hns3: adds support for reading module eeprom info
drivers/net/ethernet/hisilicon/hns3/hnae3.h | 6 +- .../hisilicon/hns3/hns3_cae/hns3_cae_version.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 79 ++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 15 +++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 102 +++++++++++++++++++++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 +- .../ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 2 +- drivers/net/ethernet/hisilicon/hns3/kcompat.h | 10 ++ drivers/net/ethernet/huawei/hinic/hinic_ethtool.c | 1 + drivers/net/ethernet/huawei/hinic/hinic_tx.c | 65 ++++++++++--- drivers/net/ethernet/huawei/hinic/hinic_tx.h | 2 + 12 files changed, 269 insertions(+), 19 deletions(-)
From: Shengzui You youshengzui@huawei.com
driver inclusion category: feature bugzilla: NA CVE: NA
-------------------------
This patch is used to modify hns3 version to 1.9.37.1
Signed-off-by: Shengzui You youshengzui@huawei.com Reviewed-by: Weiwei Deng dengweiwei@huawei.com Reviewed-by: Zhaohui Zhong zhongzhaohui@huawei.com Reviewed-by: Junxing Chen chenjunxin1@huawei.com Reviewed-by: Zhong Zhaohui zhongzhaohui@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 6 +++++- drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3_enet.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 +- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 42d3795..855274b 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -30,7 +30,7 @@ #include <linux/pci.h> #include <linux/types.h>
-#define HNAE3_MOD_VERSION "1.9.37.0" +#define HNAE3_MOD_VERSION "1.9.37.1"
#define HNAE3_MIN_VECTOR_NUM 2 /* one for msi-x, another for IO */
@@ -372,6 +372,8 @@ struct hnae3_ae_dev { * Set the max tx rate of specified vf. * set_vf_mac * Configure the default MAC for specified VF + * get_module_eeprom + * Get the optical module eeprom info. */ struct hnae3_ae_ops { int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); @@ -556,6 +558,8 @@ struct hnae3_ae_ops { int (*set_vf_rate)(struct hnae3_handle *handle, int vf, int min_tx_rate, int max_tx_rate, bool force); int (*set_vf_mac)(struct hnae3_handle *handle, int vf, u8 *p); + int (*get_module_eeprom)(struct hnae3_handle *handle, u32 offset, + u32 len, u8 *data); };
struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h index d85a27d..b48627e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_cae/hns3_cae_version.h @@ -4,7 +4,7 @@ #ifndef __HNS3_CAE_VERSION_H__ #define __HNS3_CAE_VERSION_H__
-#define HNS3_CAE_MOD_VERSION "1.9.37.0" +#define HNS3_CAE_MOD_VERSION "1.9.37.1"
#define CMT_ID_LEN 8 #define RESV_LEN 3 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h index 87ab2fa..f5aa085 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.h @@ -8,7 +8,7 @@
#include "hnae3.h"
-#define HNS3_MOD_VERSION "1.9.37.0" +#define HNS3_MOD_VERSION "1.9.37.1"
extern char hns3_driver_version[];
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 0daef61..ff4d7d1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -12,7 +12,7 @@ #include "hclge_cmd.h" #include "hnae3.h"
-#define HCLGE_MOD_VERSION "1.9.37.0" +#define HCLGE_MOD_VERSION "1.9.37.1" #define HCLGE_DRIVER_NAME "hclge"
#define HCLGE_MAX_PF_NUM 8 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index 574b36b..e5a1450 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -10,7 +10,7 @@ #include "hclgevf_cmd.h" #include "hnae3.h"
-#define HCLGEVF_MOD_VERSION "1.9.37.0" +#define HCLGEVF_MOD_VERSION "1.9.37.1" #define HCLGEVF_DRIVER_NAME "hclgevf"
#define HCLGEVF_MAX_VLAN_ID 4095
From: Shengzui You youshengzui@huawei.com
driver inclusion category: feature bugzilla: NA CVE: NA
--------------------------------
This patch adds support for reading the optical module eeprom info via "ethtool -m".
Signed-off-by: Shengzui You youshengzui@huawei.com Reviewed-by: Weiwei Deng dengweiwei@huawei.com Reviewed-by: Zhaohui Zhong zhongzhaohui@huawei.com Reviewed-by: Junxing Chen chenjunxin1@huawei.com Reviewed-by: Zhong Zhaohui zhongzhaohui@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c | 79 ++++++++++++++++ .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 15 +++ .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 102 +++++++++++++++++++++ drivers/net/ethernet/hisilicon/hns3/kcompat.h | 10 ++ 4 files changed, 206 insertions(+)
diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index a75879e..5e7bf03 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -12,6 +12,16 @@ struct hns3_stats { int stats_offset; };
+#define HNS3_MODULE_TYPE_QSFP 0x0C +#define HNS3_MODULE_TYPE_QSFP_P 0x0D +#define HNS3_MODULE_TYPE_QSFP_28 0x11 +#define HNS3_MODULE_TYPE_SFP 0x03 + +struct hns3_sfp_type { + u8 type; + u8 ext_type; +}; + /* tqp related stats */ #define HNS3_TQP_STAT(_string, _member) { \ .stats_string = _string, \ @@ -1391,6 +1401,73 @@ static int hns3_set_fecparam(struct net_device *netdev, return ops->set_fec(handle, fec_mode); }
+static int hns3_get_module_info(struct net_device *netdev, + struct ethtool_modinfo *modinfo) +{ +#define HNS3_SFF_8636_V1_3 0x03 + + struct hnae3_handle *handle = hns3_get_handle(netdev); + const struct hnae3_ae_ops *ops = handle->ae_algo->ops; + struct hns3_sfp_type sfp_type; + int ret; + + if (handle->pdev->revision == 0x20 || !ops->get_module_eeprom) + return -EOPNOTSUPP; + + memset(&sfp_type, 0, sizeof(sfp_type)); + ret = ops->get_module_eeprom(handle, 0, sizeof(sfp_type) / sizeof(u8), + (u8 *)&sfp_type); + if (ret) + return ret; + + switch (sfp_type.type) { + case HNS3_MODULE_TYPE_SFP: + modinfo->type = ETH_MODULE_SFF_8472; + modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; + break; + case HNS3_MODULE_TYPE_QSFP: + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; + break; + case HNS3_MODULE_TYPE_QSFP_P: + if (sfp_type.ext_type < HNS3_SFF_8636_V1_3) { + modinfo->type = ETH_MODULE_SFF_8436; + modinfo->eeprom_len = ETH_MODULE_SFF_8436_MAX_LEN; + } else { + modinfo->type = ETH_MODULE_SFF_8636; + modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; + } + break; + case HNS3_MODULE_TYPE_QSFP_28: + modinfo->type = ETH_MODULE_SFF_8636; + modinfo->eeprom_len = ETH_MODULE_SFF_8636_MAX_LEN; + break; + default: + netdev_err(netdev, "Optical module unknown:%#x\n", + sfp_type.type); + return -EINVAL; + } + + return 0; +} + +static int hns3_get_module_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct hnae3_handle *handle = hns3_get_handle(netdev); + const struct hnae3_ae_ops *ops = handle->ae_algo->ops; + + if (handle->pdev->revision == 0x20 || !ops->get_module_eeprom) + return -EOPNOTSUPP; + + if (!ee->len) + return -EINVAL; + + memset(data, 0, ee->len); + + return ops->get_module_eeprom(handle, ee->offset, ee->len, data); +} + static const struct ethtool_ops hns3vf_ethtool_ops = { .get_drvinfo = hns3_get_drvinfo, .get_ringparam = hns3_get_ringparam, @@ -1447,6 +1524,8 @@ static int hns3_set_fecparam(struct net_device *netdev, .set_msglevel = hns3_set_msglevel, .get_fecparam = hns3_get_fecparam, .set_fecparam = hns3_set_fecparam, + .get_module_info = hns3_get_module_info, + .get_module_eeprom = hns3_get_module_eeprom, };
void hns3_ethtool_set_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 7c4a739..5bcc30d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -272,6 +272,8 @@ enum hclge_opcode_type { HCLGE_OPC_M7_COMPAT_CFG = 0x701A,
/* SFP command */ + HCLGE_OPC_GET_SFP_EEPROM = 0x7100, + HCLGE_OPC_GET_SFP_EXIST = 0x7101, HCLGE_OPC_GET_SFP_INFO = 0x7104,
/* Error INT commands */ @@ -1093,6 +1095,19 @@ struct hclge_firmware_compat_cmd { u8 rsv[20]; };
+#define HCLGE_SFP_INFO_CMD_NUM 6 +#define HCLGE_SFP_INFO_BD0_LEN 20 +#define HCLGE_SFP_INFO_BDX_LEN 24 +#define HCLGE_SFP_INFO_MAX_LEN \ + (HCLGE_SFP_INFO_BD0_LEN + \ + (HCLGE_SFP_INFO_CMD_NUM - 1) * HCLGE_SFP_INFO_BDX_LEN) + +struct hclge_sfp_info_bd0_cmd { + __le16 offset; + __le16 read_len; + u8 data[HCLGE_SFP_INFO_BD0_LEN]; +}; + int hclge_cmd_init(struct hclge_dev *hdev); static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value) { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 7af8711..aaf3512 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -11181,6 +11181,107 @@ static void hclge_sync_promisc_mode(struct hclge_dev *hdev) } }
+static bool hclge_module_existed(struct hclge_dev *hdev) +{ + struct hclge_desc desc; + u32 existed; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GET_SFP_EXIST, true); + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get SFP exist state, ret = %d\n", ret); + return false; + } + + existed = le32_to_cpu(desc.data[0]); + + return existed != 0; +} + +/* need 6 bds(total 140 bytes) in one reading + * return the number of bytes actually read, 0 means read failed. + */ +static u16 hclge_get_sfp_eeprom_info(struct hclge_dev *hdev, u32 offset, + u32 len, u8 *data) +{ + struct hclge_desc desc[HCLGE_SFP_INFO_CMD_NUM]; + struct hclge_sfp_info_bd0_cmd *sfp_info_bd0; + u16 read_len; + u16 copy_len; + int ret; + int i; + + /* setup all 6 bds to read module eeprom info. */ + for (i = 0; i < HCLGE_SFP_INFO_CMD_NUM; i++) { + hclge_cmd_setup_basic_desc(&desc[i], HCLGE_OPC_GET_SFP_EEPROM, + true); + + /* bd0~bd4 need next flag */ + if (i < HCLGE_SFP_INFO_CMD_NUM - 1) + desc[i].flag |= cpu_to_le16(HCLGE_CMD_FLAG_NEXT); + } + + /* setup bd0, this bd contains offset and read length. */ + sfp_info_bd0 = (struct hclge_sfp_info_bd0_cmd *)desc[0].data; + sfp_info_bd0->offset = cpu_to_le16((u16)offset); + read_len = min_t(u16, len, HCLGE_SFP_INFO_MAX_LEN); + sfp_info_bd0->read_len = cpu_to_le16(read_len); + + ret = hclge_cmd_send(&hdev->hw, desc, i); + if (ret) { + dev_err(&hdev->pdev->dev, + "failed to get SFP eeprom info, ret = %d\n", ret); + return 0; + } + + /* copy sfp info from bd0 to out buffer. */ + copy_len = min_t(u16, len, HCLGE_SFP_INFO_BD0_LEN); + memcpy(data, sfp_info_bd0->data, copy_len); + read_len = copy_len; + + /* copy sfp info from bd1~bd5 to out buffer if needed. */ + for (i = 1; i < HCLGE_SFP_INFO_CMD_NUM; i++) { + if (read_len >= len) + return read_len; + + copy_len = min_t(u16, len - read_len, HCLGE_SFP_INFO_BDX_LEN); + memcpy(data + read_len, desc[i].data, copy_len); + read_len += copy_len; + } + + return read_len; +} + +static int hclge_get_module_eeprom(struct hnae3_handle *handle, u32 offset, + u32 len, u8 *data) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + u32 read_len = 0; + u16 data_len; + + if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_FIBER) + return -EOPNOTSUPP; + + if (!hclge_module_existed(hdev)) + return -ENXIO; + + while (read_len < len) { + data_len = hclge_get_sfp_eeprom_info(hdev, + offset + read_len, + len - read_len, + data + read_len); + if (!data_len) + return -EIO; + + read_len += data_len; + } + + return 0; +} + struct hnae3_ae_ops hclge_ops = { .init_ae_dev = hclge_init_ae_dev, .uninit_ae_dev = hclge_uninit_ae_dev, @@ -11276,6 +11377,7 @@ struct hnae3_ae_ops hclge_ops = { .set_vf_mac = hclge_set_vf_mac, .set_vf_trust = hclge_set_vf_trust, .set_vf_rate = hclge_set_vf_rate, + .get_module_eeprom = hclge_get_module_eeprom, };
struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/kcompat.h b/drivers/net/ethernet/hisilicon/hns3/kcompat.h index 8dc067c..5cf3a35 100644 --- a/drivers/net/ethernet/hisilicon/hns3/kcompat.h +++ b/drivers/net/ethernet/hisilicon/hns3/kcompat.h @@ -409,6 +409,16 @@ static inline void linkmode_zero(unsigned long *dst)
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0)) +#ifndef ETH_MODULE_SFF_8636_MAX_LEN +#define ETH_MODULE_SFF_8636_MAX_LEN 640 +#endif + +#ifndef ETH_MODULE_SFF_8436_MAX_LEN +#define ETH_MODULE_SFF_8436_MAX_LEN 640 +#endif +#endif + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)) #ifndef dma_zalloc_coherent #define dma_zalloc_coherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
From: Shaozhengchao shaozhengchao@huawei.com
driver inclusion category:bugfix bugzilla:31091 CVE:NA
-----------------------------------------------------------------------
To solve the problem that the network card hangs when receiving the skb which frag_size=0
In order to solve this problem, hinic driver adds a judgment on the legality of frag_size in tx process. If size of lastest frags are all zero, hinic driver will ignore this frags. If size of some frags in the middle is zero, hinic driver will drop this skb.
Signed-off-by: Shaozhengchao shaozhengchao@huawei.com Reviewed-by: Luoshaokai luoshaokai@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/net/ethernet/huawei/hinic/hinic_ethtool.c | 1 + drivers/net/ethernet/huawei/hinic/hinic_tx.c | 65 ++++++++++++++++++----- drivers/net/ethernet/huawei/hinic/hinic_tx.h | 2 + 3 files changed, 54 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c index 711ea53..37d8d38 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c @@ -140,6 +140,7 @@ struct hinic_stats { HINIC_TXQ_STAT(alloc_cpy_frag_err), HINIC_TXQ_STAT(map_cpy_frag_err), HINIC_TXQ_STAT(map_frag_err), + HINIC_TXQ_STAT(frag_size_err), };/*lint -restore*/
#define HINIC_FUNC_STAT(_stat_item) { \ diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.c b/drivers/net/ethernet/huawei/hinic/hinic_tx.c index c1ea1e6..05291a5 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_tx.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.c @@ -92,6 +92,7 @@ void hinic_txq_clean_stats(struct hinic_txq_stats *txq_stats) txq_stats->alloc_cpy_frag_err = 0; txq_stats->map_cpy_frag_err = 0; txq_stats->map_frag_err = 0; + txq_stats->frag_size_err = 0; u64_stats_update_end(&txq_stats->syncp); }
@@ -113,7 +114,7 @@ inline void hinic_set_buf_desc(struct hinic_sq_bufdesc *buf_descs,
static int tx_map_skb(struct hinic_nic_dev *nic_dev, struct sk_buff *skb, struct hinic_txq *txq, struct hinic_tx_info *tx_info, - struct hinic_sq_bufdesc *buf_descs) + struct hinic_sq_bufdesc *buf_descs, u16 skb_nr_frags) { struct pci_dev *pdev = nic_dev->pdev; struct hinic_dma_len *dma_len = tx_info->dma_len; @@ -123,7 +124,6 @@ static int tx_map_skb(struct hinic_nic_dev *nic_dev, struct sk_buff *skb, int node, err = 0; u32 nsize, cpy_nsize = 0; u8 *vaddr, *cpy_buff = NULL; - u16 skb_nr_frags = skb_shinfo(skb)->nr_frags;
if (unlikely(skb_nr_frags > HINIC_MAX_SKB_NR_FRAGE)) { for (i = HINIC_MAX_SKB_NR_FRAGE; i <= skb_nr_frags; i++) @@ -152,7 +152,7 @@ static int tx_map_skb(struct hinic_nic_dev *nic_dev, struct sk_buff *skb,
for (i = HINIC_MAX_SKB_NR_FRAGE; i <= skb_nr_frags; i++) { frag = &skb_shinfo(skb)->frags[i - 1]; - nsize = skb_frag_size(&skb_shinfo(skb)->frags[i - 1]); + nsize = skb_frag_size(frag);
vaddr = _kc_kmap_atomic(skb_frag_page(frag)); memcpy(cpy_buff, vaddr + frag->page_offset, nsize); @@ -179,17 +179,17 @@ static int tx_map_skb(struct hinic_nic_dev *nic_dev, struct sk_buff *skb,
for (i = 0; i < base_nr_frags; ) { frag = &(skb_shinfo(skb)->frags[i]); + nsize = skb_frag_size(frag); i++; dma_len[i].dma = skb_frag_dma_map(&pdev->dev, frag, 0, - skb_frag_size(frag), - DMA_TO_DEVICE); + nsize, DMA_TO_DEVICE); if (dma_mapping_error(&pdev->dev, dma_len[i].dma)) { TXQ_STATS_INC(txq, map_frag_err); i--; err = -EFAULT; goto frag_map_err; } - dma_len[i].len = skb_frag_size(frag); + dma_len[i].len = nsize;
hinic_set_buf_desc(&buf_descs[i], dma_len[i].dma, dma_len[i].len); @@ -233,16 +233,15 @@ static int tx_map_skb(struct hinic_nic_dev *nic_dev, struct sk_buff *skb,
static inline void tx_unmap_skb(struct hinic_nic_dev *nic_dev, struct sk_buff *skb, - struct hinic_dma_len *dma_len) + struct hinic_dma_len *dma_len, + u16 valid_nr_frags) { struct pci_dev *pdev = nic_dev->pdev; - u16 nr_frags; int i; + u16 nr_frags = valid_nr_frags;
- if (skb_shinfo(skb)->nr_frags > HINIC_MAX_SKB_NR_FRAGE) + if (nr_frags > HINIC_MAX_SKB_NR_FRAGE) nr_frags = HINIC_MAX_SKB_NR_FRAGE; - else - nr_frags = skb_shinfo(skb)->nr_frags;
for (i = 0; i < nr_frags; ) { i++; @@ -767,6 +766,9 @@ static int hinic_ufo_avoidance(struct sk_buff *skb, struct sk_buff **ufo_skb, } #endif
+#define HINIC_FRAG_STATUS_OK 0 +#define HINIC_FRAG_STATUS_IGNORE 1 + static netdev_tx_t hinic_send_one_skb(struct sk_buff *skb, struct net_device *netdev, struct hinic_txq *txq, @@ -782,6 +784,10 @@ static netdev_tx_t hinic_send_one_skb(struct sk_buff *skb, u16 pi = 0; int err, wqebb_cnt; u16 num_sge = 0; + u16 original_nr_frags; + u16 new_nr_frags; + u16 i; + int frag_err = HINIC_FRAG_STATUS_OK;
/* skb->dev will not initialized when calling netdev_alloc_skb_ip_align * and parameter of length is largger then PAGE_SIZE(under redhat7.3), @@ -799,7 +805,36 @@ static netdev_tx_t hinic_send_one_skb(struct sk_buff *skb, skb->len = MIN_SKB_LEN; }
- num_sge = skb_shinfo(skb)->nr_frags + 1; + original_nr_frags = skb_shinfo(skb)->nr_frags; + new_nr_frags = original_nr_frags; + + /* If size of lastest frags are all zero, should ignore this frags. + * If size of some frag in the middle is zero, should drop this skb. + */ + for (i = 0; i < original_nr_frags; i++) { + if ((skb_frag_size(&skb_shinfo(skb)->frags[i])) && + frag_err == HINIC_FRAG_STATUS_OK) + continue; + + if ((!skb_frag_size(&skb_shinfo(skb)->frags[i])) && + frag_err == HINIC_FRAG_STATUS_OK) { + frag_err = HINIC_FRAG_STATUS_IGNORE; + new_nr_frags = i + 1; + continue; + } + + if ((!skb_frag_size(&skb_shinfo(skb)->frags[i])) && + frag_err == HINIC_FRAG_STATUS_IGNORE) + continue; + + if ((skb_frag_size(&skb_shinfo(skb)->frags[i])) && + frag_err == HINIC_FRAG_STATUS_IGNORE) { + TXQ_STATS_INC(txq, frag_size_err); + goto tx_drop_pkts; + } + } + + num_sge = new_nr_frags + 1;
/* if skb->len is more than 65536B but num_sge is 1, * driver will drop it @@ -838,6 +873,7 @@ static netdev_tx_t hinic_send_one_skb(struct sk_buff *skb, tx_info = &txq->tx_info[pi]; tx_info->skb = skb; tx_info->wqebb_cnt = wqebb_cnt; + tx_info->valid_nr_frags = new_nr_frags;
__get_pkt_stats(tx_info, skb);
@@ -848,7 +884,8 @@ static netdev_tx_t hinic_send_one_skb(struct sk_buff *skb, goto tx_drop_pkts; }
- err = tx_map_skb(nic_dev, skb, txq, tx_info, wqe->buf_descs); + err = tx_map_skb(nic_dev, skb, txq, tx_info, wqe->buf_descs, + new_nr_frags); if (err) { hinic_return_sq_wqe(nic_dev->hwdev, q_id, wqebb_cnt, owner); goto tx_drop_pkts; @@ -965,7 +1002,7 @@ static inline void tx_free_skb(struct hinic_nic_dev *nic_dev, struct sk_buff *skb, struct hinic_tx_info *tx_info) { - tx_unmap_skb(nic_dev, skb, tx_info->dma_len); + tx_unmap_skb(nic_dev, skb, tx_info->dma_len, tx_info->valid_nr_frags);
kfree(tx_info->cpy_buff); tx_info->cpy_buff = NULL; diff --git a/drivers/net/ethernet/huawei/hinic/hinic_tx.h b/drivers/net/ethernet/huawei/hinic/hinic_tx.h index 2a01fab..cfbd4de 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_tx.h +++ b/drivers/net/ethernet/huawei/hinic/hinic_tx.h @@ -42,6 +42,7 @@ struct hinic_txq_stats { u64 alloc_cpy_frag_err; u64 map_cpy_frag_err; u64 map_frag_err; + u64 frag_size_err;
#ifdef HAVE_NDO_GET_STATS64 struct u64_stats_sync syncp; @@ -65,6 +66,7 @@ struct hinic_tx_info { 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];