From 8cdb992f0dc36d6382840b1a6320e0c327a7d644 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 20 Dec 2018 11:51:58 +0800 Subject: [PATCH 1/9] net: hns3: refine the handle for hns3_nic_net_open/stop() When triggering nic down, there is a time window between bringing down the protocol stack and stopping the work task. If the net is up in the time window, it may bring up the protocol stack again. This patch fixes it by stop the work task at the beginning of hns3_nic_net_stop(). To keep symmetrical, start the work task at the end of hns3_nic_net_open(). Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hnae3.h | 1 + .../net/ethernet/hisilicon/hns3/hns3_enet.c | 8 +++++++ .../hisilicon/hns3/hns3pf/hclge_main.c | 22 +++++++++++++------ .../hisilicon/hns3/hns3vf/hclgevf_main.c | 18 +++++++++++---- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 845d43d3a920..36eab37d8a40 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -461,6 +461,7 @@ struct hnae3_ae_ops { unsigned long (*ae_dev_reset_cnt)(struct hnae3_handle *handle); int (*set_gro_en)(struct hnae3_handle *handle, int enable); u16 (*get_global_queue_id)(struct hnae3_handle *handle, u16 queue_id); + void (*set_timer_task)(struct hnae3_handle *handle, bool enable); }; struct hnae3_dcb_ops { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index d060029ce142..becbf866e21f 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -379,6 +379,7 @@ out_start_err: static int hns3_nic_net_open(struct net_device *netdev) { + struct hns3_nic_priv *priv = netdev_priv(netdev); struct hnae3_handle *h = hns3_get_handle(netdev); struct hnae3_knic_private_info *kinfo; int i, ret; @@ -405,6 +406,9 @@ static int hns3_nic_net_open(struct net_device *netdev) kinfo->prio_tc[i]); } + if (h->ae_algo->ops->set_timer_task) + h->ae_algo->ops->set_timer_task(priv->ae_handle, true); + return 0; } @@ -437,10 +441,14 @@ static void hns3_nic_net_down(struct net_device *netdev) static int hns3_nic_net_stop(struct net_device *netdev) { struct hns3_nic_priv *priv = netdev_priv(netdev); + struct hnae3_handle *h = hns3_get_handle(netdev); if (test_and_set_bit(HNS3_NIC_STATE_DOWN, &priv->state)) return 0; + if (h->ae_algo->ops->set_timer_task) + h->ae_algo->ops->set_timer_task(priv->ae_handle, false); + netif_tx_stop_all_queues(netdev); netif_carrier_off(netdev); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index d0e84de39fa3..a12cb1452651 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5295,6 +5295,20 @@ static void hclge_reset_tqp_stats(struct hnae3_handle *handle) } } +static void hclge_set_timer_task(struct hnae3_handle *handle, bool enable) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + if (enable) { + mod_timer(&hdev->service_timer, jiffies + HZ); + } else { + del_timer_sync(&hdev->service_timer); + cancel_work_sync(&hdev->service_task); + clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state); + } +} + static int hclge_ae_start(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); @@ -5303,7 +5317,6 @@ static int hclge_ae_start(struct hnae3_handle *handle) /* mac enable */ hclge_cfg_mac_mode(hdev, true); clear_bit(HCLGE_STATE_DOWN, &hdev->state); - mod_timer(&hdev->service_timer, jiffies + HZ); hdev->hw.mac.link = 0; /* reset tqp stats */ @@ -5321,10 +5334,6 @@ static void hclge_ae_stop(struct hnae3_handle *handle) set_bit(HCLGE_STATE_DOWN, &hdev->state); - del_timer_sync(&hdev->service_timer); - cancel_work_sync(&hdev->service_task); - clear_bit(HCLGE_STATE_SERVICE_SCHED, &hdev->state); - /* If it is not PF reset, the firmware will disable the MAC, * so it only need to stop phy here. */ @@ -5341,8 +5350,6 @@ static void hclge_ae_stop(struct hnae3_handle *handle) /* reset tqp stats */ hclge_reset_tqp_stats(handle); - del_timer_sync(&hdev->service_timer); - cancel_work_sync(&hdev->service_task); hclge_update_link_status(hdev); } @@ -7996,6 +8003,7 @@ static const struct hnae3_ae_ops hclge_ops = { .ae_dev_reset_cnt = hclge_ae_dev_reset_cnt, .set_gro_en = hclge_gro_en, .get_global_queue_id = hclge_covert_handle_qid_global, + .set_timer_task = hclge_set_timer_task, }; static struct hnae3_ae_algo ae_algo = { diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 54ba93ac24dd..919c3aa87228 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1840,6 +1840,19 @@ static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev) false); } +static void hclgevf_set_timer_task(struct hnae3_handle *handle, bool enable) +{ + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + + if (enable) { + mod_timer(&hdev->service_timer, jiffies + HZ); + } else { + del_timer_sync(&hdev->service_timer); + cancel_work_sync(&hdev->service_task); + clear_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state); + } +} + static int hclgevf_ae_start(struct hnae3_handle *handle) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); @@ -1850,7 +1863,6 @@ static int hclgevf_ae_start(struct hnae3_handle *handle) hclgevf_request_link_info(hdev); clear_bit(HCLGEVF_STATE_DOWN, &hdev->state); - mod_timer(&hdev->service_timer, jiffies + HZ); return 0; } @@ -1863,9 +1875,6 @@ static void hclgevf_ae_stop(struct hnae3_handle *handle) /* reset tqp stats */ hclgevf_reset_tqp_stats(handle); - del_timer_sync(&hdev->service_timer); - cancel_work_sync(&hdev->service_task); - clear_bit(HCLGEVF_STATE_SERVICE_SCHED, &hdev->state); hclgevf_update_link_status(hdev, 0); } @@ -2663,6 +2672,7 @@ static const struct hnae3_ae_ops hclgevf_ops = { .set_gro_en = hclgevf_gro_en, .set_mtu = hclgevf_set_mtu, .get_global_queue_id = hclgevf_get_qid_global, + .set_timer_task = hclgevf_set_timer_task, }; static struct hnae3_ae_algo ae_algovf = { From a298797532d9dc244abf349d7c2ed063732c6ba3 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 20 Dec 2018 11:51:59 +0800 Subject: [PATCH 2/9] net: hns3: change default tc state to close In original codes, default tc value is set to the max tc. It's more reasonable to close tc by changing default tc value to 1. Users can enable it with lldp tool when they want to use tc. Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index a12cb1452651..0b04d0426332 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -960,7 +960,7 @@ static int hclge_configure(struct hclge_dev *hdev) hdev->pfc_max = hdev->tc_max; } - hdev->tm_info.num_tc = hdev->tc_max; + hdev->tm_info.num_tc = 1; /* Currently not support uncontiuous tc */ for (i = 0; i < hdev->tm_info.num_tc; i++) From 1b7d7b0581173219b82abbd81c88cf8aa7d402c2 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Thu, 20 Dec 2018 11:52:00 +0800 Subject: [PATCH 3/9] net: hns3: fix a bug caused by udelay udelay() in driver may always occupancy processor. If there is only one cpu in system, the VF driver may initialize fail when insmod PF and VF driver in the same system. This patch use msleep() to free cpu when VF wait PF message. Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index ef9c8e6eca28..84653f58b2d1 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -26,7 +26,7 @@ static int hclgevf_get_mbx_resp(struct hclgevf_dev *hdev, u16 code0, u16 code1, u8 *resp_data, u16 resp_len) { #define HCLGEVF_MAX_TRY_TIMES 500 -#define HCLGEVF_SLEEP_USCOEND 1000 +#define HCLGEVF_SLEEP_USECOND 1000 struct hclgevf_mbx_resp_status *mbx_resp; u16 r_code0, r_code1; int i = 0; @@ -43,7 +43,7 @@ static int hclgevf_get_mbx_resp(struct hclgevf_dev *hdev, u16 code0, u16 code1, if (test_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state)) return -EIO; - udelay(HCLGEVF_SLEEP_USCOEND); + usleep_range(HCLGEVF_SLEEP_USECOND, HCLGEVF_SLEEP_USECOND * 2); i++; } From 75edb610860fda65ceedb017fc69afabd2806b8b Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 20 Dec 2018 11:52:01 +0800 Subject: [PATCH 4/9] net: hns3: add max vector number check for pf Each pf supports max 64 vectors and 128 tqps. For 2p/4p core scenario, there may be more than 64 cpus online. So the result of min_t(u16, num_Online_cpus(), tqp_num) may be more than 64. This patch adds check for the vector number. Fixes: dd38c72604dc ("net: hns3: fix for coalesce configuration lost during reset") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index becbf866e21f..624b8a733db5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3118,6 +3118,8 @@ map_ring_fail: static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv) { +#define HNS3_VECTOR_PF_MAX_NUM 64 + struct hnae3_handle *h = priv->ae_handle; struct hns3_enet_tqp_vector *tqp_vector; struct hnae3_vector_info *vector; @@ -3130,6 +3132,8 @@ static int hns3_nic_alloc_vector_data(struct hns3_nic_priv *priv) /* RSS size, cpu online and vector_num should be the same */ /* Should consider 2p/4p later */ vector_num = min_t(u16, num_online_cpus(), tqp_num); + vector_num = min_t(u16, vector_num, HNS3_VECTOR_PF_MAX_NUM); + vector = devm_kcalloc(&pdev->dev, vector_num, sizeof(*vector), GFP_KERNEL); if (!vector) From 39cfbc9c4fc4a2888548c2624789e42e3f775721 Mon Sep 17 00:00:00 2001 From: Huazhong Tan Date: Thu, 20 Dec 2018 11:52:02 +0800 Subject: [PATCH 5/9] net: hns3: reset tqp while doing DOWN operation While doing DOWN operation, the driver will reclaim the memory which has already used for TX. If the hardware is processing this memory, it will cause a RCB error to the hardware. According the hardware's description, the driver should reset the tqp before reclaim the memory during DOWN. Signed-off-by: Huazhong Tan Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 ++++ drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 0b04d0426332..98ae2820e001 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -5331,6 +5331,7 @@ static void hclge_ae_stop(struct hnae3_handle *handle) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + int i; set_bit(HCLGE_STATE_DOWN, &hdev->state); @@ -5343,6 +5344,9 @@ static void hclge_ae_stop(struct hnae3_handle *handle) return; } + for (i = 0; i < handle->kinfo.num_tqps; i++) + hclge_reset_tqp(handle, i); + /* Mac disable */ hclge_cfg_mac_mode(hdev, false); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 919c3aa87228..156242f96a8e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1870,9 +1870,13 @@ static int hclgevf_ae_start(struct hnae3_handle *handle) static void hclgevf_ae_stop(struct hnae3_handle *handle) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + int i; set_bit(HCLGEVF_STATE_DOWN, &hdev->state); + for (i = 0; i < handle->kinfo.num_tqps; i++) + hclgevf_reset_tqp(handle, i); + /* reset tqp stats */ hclgevf_reset_tqp_stats(handle); hclgevf_update_link_status(hdev, 0); From 0285dbae5db842862d49f148cdcedad986447f34 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 20 Dec 2018 11:52:03 +0800 Subject: [PATCH 6/9] net: hns3: fix vf id check issue when add flow director rule When add flow director fule for vf, the vf id is used as array subscript before valid checking, which may cause memory overflow. Fixes: dd74f815dd41 ("net: hns3: Add support for rule add/delete for flow director") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller --- .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 98ae2820e001..9f8985862ae7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4677,6 +4677,13 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); u16 tqps; + if (vf > hdev->num_req_vfs) { + dev_err(&hdev->pdev->dev, + "Error: vf id (%d) > max vf num (%d)\n", + vf, hdev->num_req_vfs); + return -EINVAL; + } + dst_vport_id = vf ? hdev->vport[vf].vport_id : vport->vport_id; tqps = vf ? hdev->vport[vf].alloc_tqps : vport->alloc_tqps; @@ -4687,13 +4694,6 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, return -EINVAL; } - if (vf > hdev->num_req_vfs) { - dev_err(&hdev->pdev->dev, - "Error: vf id (%d) > max vf num (%d)\n", - vf, hdev->num_req_vfs); - return -EINVAL; - } - action = HCLGE_FD_ACTION_ACCEPT_PACKET; q_index = ring; } From 8edc2285b7285c5fbffe438dc8113260d3e76656 Mon Sep 17 00:00:00 2001 From: Jian Shen Date: Thu, 20 Dec 2018 11:52:04 +0800 Subject: [PATCH 7/9] net: hns3: don't restore rules when flow director is disabled When user disables flow director, all the rules will be disabled. But when reset happens, it will restore all the rules again. It's not reasonable. This patch fixes it by add flow director status check before restore fules. Fixes: 6871af29b3ab ("net: hns3: Add reset handle for flow director") Fixes: c17852a8932f ("net: hns3: Add support for enable/disable flow director") Signed-off-by: Jian Shen Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 9f8985862ae7..f7637c08bb3a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -4808,6 +4808,10 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle) if (!hnae3_dev_fd_supported(hdev)) return 0; + /* if fd is disabled, should not restore it when reset */ + if (!hdev->fd_cfg.fd_en) + return 0; + hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule); if (!ret) From 31a16f99e02c2e0b40a5fb05d66f5e56721027e2 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Thu, 20 Dec 2018 11:52:05 +0800 Subject: [PATCH 8/9] net: hns3: fix the descriptor index when get rss type Driver gets rss information from the last descriptor of the packet. When driver handle the rss type, ring->next_to_clean indicates the first descriptor of next packet. This patch fix the descriptor index with "ring->next_to_clean - 1". Fixes: 232fc64b6e62 ("net: hns3: Add HW RSS hash information to RX skb") Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3_enet.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 624b8a733db5..d3b9aaf96c1c 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -2550,9 +2550,16 @@ static void hns3_set_gro_param(struct sk_buff *skb, u32 l234info, static void hns3_set_rx_skb_rss_type(struct hns3_enet_ring *ring, struct sk_buff *skb) { - struct hns3_desc *desc = &ring->desc[ring->next_to_clean]; struct hnae3_handle *handle = ring->tqp->handle; enum pkt_hash_types rss_type; + struct hns3_desc *desc; + int last_bd; + + /* When driver handle the rss type, ring->next_to_clean indicates the + * first descriptor of next packet, need -1 here. + */ + last_bd = (ring->next_to_clean - 1 + ring->desc_num) % ring->desc_num; + desc = &ring->desc[last_bd]; if (le32_to_cpu(desc->rx.rss_hash)) rss_type = handle->kinfo.rss_type; From 1154bb26c879fea51c20aee167ddce4345caa255 Mon Sep 17 00:00:00 2001 From: Peng Li Date: Thu, 20 Dec 2018 11:52:06 +0800 Subject: [PATCH 9/9] net: hns3: remove redundant variable initialization This patch removes the redundant variable initialization, as driver will devm_kzalloc to set value to hdev soon. Signed-off-by: Peng Li Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 156242f96a8e..82103d5fa815 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1721,7 +1721,7 @@ static int hclgevf_configure(struct hclgevf_dev *hdev) static int hclgevf_alloc_hdev(struct hnae3_ae_dev *ae_dev) { struct pci_dev *pdev = ae_dev->pdev; - struct hclgevf_dev *hdev = ae_dev->priv; + struct hclgevf_dev *hdev; hdev = devm_kzalloc(&pdev->dev, sizeof(*hdev), GFP_KERNEL); if (!hdev)