1 | There are some bugfix for the HNS3 ethernet driver | 1 | There are some bugfix for the HNS3 ethernet driver |
---|---|---|---|
2 | 2 | ||
3 | Hao Lan (1): | 3 | --- |
4 | net: hns3: fix spelling mistake "reg_um" -> "reg_num" | 4 | changeLog: |
5 | v2 -> v3: | ||
6 | - Fix coding errors in "net: hns3: using user configure after hardware reset", suggested by Simon Horman | ||
7 | https://lore.kernel.org/all/20240426100045.1631295-1-shaojijie@huawei.com/ | ||
8 | v1 -> v2: | ||
9 | - Adjust the code sequence to completely eliminate the race window, suggested by Jiri Pirko | ||
10 | v1: https://lore.kernel.org/all/20240422134327.3160587-1-shaojijie@huawei.com/ | ||
11 | --- | ||
5 | 12 | ||
6 | Jian Shen (1): | 13 | Jian Shen (1): |
7 | net: hns3: store rx VLAN tag offload state for VF | 14 | net: hns3: direct return when receive a unknown mailbox message |
8 | 15 | ||
9 | Yonglong Liu (1): | 16 | Peiyang Wang (4): |
10 | net: hns3: fix a use of uninitialized variable problem | 17 | net: hns3: using user configure after hardware reset |
18 | net: hns3: change type of numa_node_mask as nodemask_t | ||
19 | net: hns3: release PTP resources if pf initialization failed | ||
20 | net: hns3: use appropriate barrier function after setting a bit value | ||
11 | 21 | ||
12 | .../hisilicon/hns3/hns3pf/hclge_main.c | 2 +- | 22 | Yonglong Liu (2): |
13 | .../hisilicon/hns3/hns3vf/hclgevf_main.c | 25 ++++++++++++----- | 23 | net: hns3: fix port vlan filter not disabled issue |
14 | .../hisilicon/hns3/hns3vf/hclgevf_main.h | 3 ++- | 24 | net: hns3: fix kernel crash when devlink reload during initialization |
15 | .../hisilicon/hns3/hns3vf/hclgevf_regs.c | 27 ++++++++++--------- | 25 | |
16 | 4 files changed, 36 insertions(+), 21 deletions(-) | 26 | drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 +- |
27 | .../hisilicon/hns3/hns3pf/hclge_main.c | 52 ++++++++++--------- | ||
28 | .../hisilicon/hns3/hns3pf/hclge_main.h | 5 +- | ||
29 | .../hisilicon/hns3/hns3pf/hclge_mbx.c | 7 +-- | ||
30 | .../hisilicon/hns3/hns3vf/hclgevf_main.c | 20 ++++--- | ||
31 | .../hisilicon/hns3/hns3vf/hclgevf_main.h | 2 +- | ||
32 | 6 files changed, 47 insertions(+), 41 deletions(-) | ||
17 | 33 | ||
18 | -- | 34 | -- |
19 | 2.33.0 | 35 | 2.30.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Peiyang Wang <wangpeiyang1@huawei.com> | ||
1 | 2 | ||
3 | When a reset occurring, it's supposed to recover user's configuration. | ||
4 | Currently, the port info(speed, duplex and autoneg) is stored in hclge_mac | ||
5 | and will be scheduled updated. Consider the case that reset was happened | ||
6 | consecutively. During the first reset, the port info is configured with | ||
7 | a temporary value cause the PHY is reset and looking for best link config. | ||
8 | Second reset start and use pervious configuration which is not the user's. | ||
9 | The specific process is as follows: | ||
10 | |||
11 | +------+ +----+ +----+ | ||
12 | | USER | | PF | | HW | | ||
13 | +---+--+ +-+--+ +-+--+ | ||
14 | | ethtool --reset | | | ||
15 | +------------------->| reset command | | ||
16 | | ethtool --reset +-------------------->| | ||
17 | +------------------->| +---+ | ||
18 | | +---+ | | | ||
19 | | | |reset currently | | HW RESET | ||
20 | | | |and wait to do | | | ||
21 | | |<--+ | | | ||
22 | | | send pervious cfg |<--+ | ||
23 | | | (1000M FULL AN_ON) | | ||
24 | | +-------------------->| | ||
25 | | | read cfg(time task) | | ||
26 | | | (10M HALF AN_OFF) +---+ | ||
27 | | |<--------------------+ | cfg take effect | ||
28 | | | reset command |<--+ | ||
29 | | +-------------------->| | ||
30 | | | +---+ | ||
31 | | | send pervious cfg | | HW RESET | ||
32 | | | (10M HALF AN_OFF) |<--+ | ||
33 | | +-------------------->| | ||
34 | | | read cfg(time task) | | ||
35 | | | (10M HALF AN_OFF) +---+ | ||
36 | | |<--------------------+ | cfg take effect | ||
37 | | | | | | ||
38 | | | read cfg(time task) |<--+ | ||
39 | | | (10M HALF AN_OFF) | | ||
40 | | |<--------------------+ | ||
41 | | | | | ||
42 | v v v | ||
43 | |||
44 | To avoid aboved situation, this patch introduced req_speed, req_duplex, | ||
45 | req_autoneg to store user's configuration and it only be used after | ||
46 | hardware reset and to recover user's configuration | ||
47 | |||
48 | Fixes: f5f2b3e4dcc0 ("net: hns3: add support for imp-controlled PHYs") | ||
49 | Signed-off-by: Peiyang Wang <wangpeiyang1@huawei.com> | ||
50 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> | ||
51 | --- | ||
52 | .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 15 +++++++++------ | ||
53 | .../ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 3 +++ | ||
54 | 2 files changed, 12 insertions(+), 6 deletions(-) | ||
55 | |||
56 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
57 | index XXXXXXX..XXXXXXX 100644 | ||
58 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
59 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
60 | @@ -XXX,XX +XXX,XX @@ static int hclge_configure(struct hclge_dev *hdev) | ||
61 | cfg.default_speed, ret); | ||
62 | return ret; | ||
63 | } | ||
64 | + hdev->hw.mac.req_speed = hdev->hw.mac.speed; | ||
65 | + hdev->hw.mac.req_autoneg = AUTONEG_ENABLE; | ||
66 | + hdev->hw.mac.req_duplex = DUPLEX_FULL; | ||
67 | |||
68 | hclge_parse_link_mode(hdev, cfg.speed_ability); | ||
69 | |||
70 | @@ -XXX,XX +XXX,XX @@ hclge_set_phy_link_ksettings(struct hnae3_handle *handle, | ||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | - hdev->hw.mac.autoneg = cmd->base.autoneg; | ||
75 | - hdev->hw.mac.speed = cmd->base.speed; | ||
76 | - hdev->hw.mac.duplex = cmd->base.duplex; | ||
77 | + hdev->hw.mac.req_autoneg = cmd->base.autoneg; | ||
78 | + hdev->hw.mac.req_speed = cmd->base.speed; | ||
79 | + hdev->hw.mac.req_duplex = cmd->base.duplex; | ||
80 | linkmode_copy(hdev->hw.mac.advertising, cmd->link_modes.advertising); | ||
81 | |||
82 | return 0; | ||
83 | @@ -XXX,XX +XXX,XX @@ static int hclge_tp_port_init(struct hclge_dev *hdev) | ||
84 | if (!hnae3_dev_phy_imp_supported(hdev)) | ||
85 | return 0; | ||
86 | |||
87 | - cmd.base.autoneg = hdev->hw.mac.autoneg; | ||
88 | - cmd.base.speed = hdev->hw.mac.speed; | ||
89 | - cmd.base.duplex = hdev->hw.mac.duplex; | ||
90 | + cmd.base.autoneg = hdev->hw.mac.req_autoneg; | ||
91 | + cmd.base.speed = hdev->hw.mac.req_speed; | ||
92 | + cmd.base.duplex = hdev->hw.mac.req_duplex; | ||
93 | linkmode_copy(cmd.link_modes.advertising, hdev->hw.mac.advertising); | ||
94 | |||
95 | return hclge_set_phy_link_ksettings(&hdev->vport->nic, &cmd); | ||
96 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | ||
97 | index XXXXXXX..XXXXXXX 100644 | ||
98 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | ||
99 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | ||
100 | @@ -XXX,XX +XXX,XX @@ struct hclge_mac { | ||
101 | u8 media_type; /* port media type, e.g. fibre/copper/backplane */ | ||
102 | u8 mac_addr[ETH_ALEN]; | ||
103 | u8 autoneg; | ||
104 | + u8 req_autoneg; | ||
105 | u8 duplex; | ||
106 | + u8 req_duplex; | ||
107 | u8 support_autoneg; | ||
108 | u8 speed_type; /* 0: sfp speed, 1: active speed */ | ||
109 | u8 lane_num; | ||
110 | u32 speed; | ||
111 | + u32 req_speed; | ||
112 | u32 max_speed; | ||
113 | u32 speed_ability; /* speed ability supported by current media */ | ||
114 | u32 module_type; /* sub media type, e.g. kr/cr/sr/lr */ | ||
115 | -- | ||
116 | 2.30.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Jian Shen <shenjian15@huawei.com> | ||
1 | 2 | ||
3 | Currently, the driver didn't return when receive a unknown | ||
4 | mailbox message, and continue checking whether need to | ||
5 | generate a response. It's unnecessary and may be incorrect. | ||
6 | |||
7 | Fixes: bb5790b71bad ("net: hns3: refactor mailbox response scheme between PF and VF") | ||
8 | Signed-off-by: Jian Shen <shenjian15@huawei.com> | ||
9 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> | ||
10 | Reviewed-by: Simon Horman <horms@kernel.org> | ||
11 | --- | ||
12 | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | 7 ++++--- | ||
13 | 1 file changed, 4 insertions(+), 3 deletions(-) | ||
14 | |||
15 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | ||
16 | index XXXXXXX..XXXXXXX 100644 | ||
17 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | ||
18 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_mbx.c | ||
19 | @@ -XXX,XX +XXX,XX @@ static void hclge_mbx_request_handling(struct hclge_mbx_ops_param *param) | ||
20 | |||
21 | hdev = param->vport->back; | ||
22 | cmd_func = hclge_mbx_ops_list[param->req->msg.code]; | ||
23 | - if (cmd_func) | ||
24 | - ret = cmd_func(param); | ||
25 | - else | ||
26 | + if (!cmd_func) { | ||
27 | dev_err(&hdev->pdev->dev, | ||
28 | "un-supported mailbox message, code = %u\n", | ||
29 | param->req->msg.code); | ||
30 | + return; | ||
31 | + } | ||
32 | + ret = cmd_func(param); | ||
33 | |||
34 | /* PF driver should not reply IMP */ | ||
35 | if (hnae3_get_bit(param->req->mbx_need_resp, HCLGE_MBX_NEED_RESP_B) && | ||
36 | -- | ||
37 | 2.30.0 | diff view generated by jsdifflib |
1 | From: Jian Shen <shenjian15@huawei.com> | 1 | From: Peiyang Wang <wangpeiyang1@huawei.com> |
---|---|---|---|
2 | 2 | ||
3 | The VF driver missed to store the rx VLAN tag strip state when | 3 | It provides nodemask_t to describe the numa node mask in kernel. To |
4 | user change the rx VLAN tag offload state. And it will default | 4 | improve transportability, change the type of numa_node_mask as nodemask_t. |
5 | to enable the rx vlan tag strip when re-init VF device after | ||
6 | reset. So if user disable rx VLAN tag offload, and trig reset, | ||
7 | then the HW will still strip the VLAN tag from packet nad fill | ||
8 | into RX BD, but the VF driver will ignore it for rx VLAN tag | ||
9 | offload disabled. It may cause the rx VLAN tag dropped. | ||
10 | 5 | ||
11 | Fixes: b2641e2ad456 ("net: hns3: Add support of hardware rx-vlan-offload to HNS3 VF driver") | 6 | Fixes: 38caee9d3ee8 ("net: hns3: Add support of the HNAE3 framework") |
12 | Signed-off-by: Jian Shen <shenjian15@huawei.com> | 7 | Signed-off-by: Peiyang Wang <wangpeiyang1@huawei.com> |
13 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> | 8 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> |
9 | Reviewed-by: Simon Horman <horms@kernel.org> | ||
14 | --- | 10 | --- |
15 | .../hisilicon/hns3/hns3vf/hclgevf_main.c | 25 ++++++++++++++----- | 11 | drivers/net/ethernet/hisilicon/hns3/hnae3.h | 2 +- |
16 | .../hisilicon/hns3/hns3vf/hclgevf_main.h | 3 ++- | 12 | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 6 ++++-- |
17 | 2 files changed, 21 insertions(+), 7 deletions(-) | 13 | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | 2 +- |
14 | drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 7 ++++--- | ||
15 | drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 2 +- | ||
16 | 5 files changed, 11 insertions(+), 8 deletions(-) | ||
18 | 17 | ||
18 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h | ||
21 | +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h | ||
22 | @@ -XXX,XX +XXX,XX @@ struct hnae3_handle { | ||
23 | struct hnae3_roce_private_info rinfo; | ||
24 | }; | ||
25 | |||
26 | - u32 numa_node_mask; /* for multi-chip support */ | ||
27 | + nodemask_t numa_node_mask; /* for multi-chip support */ | ||
28 | |||
29 | enum hnae3_port_base_vlan_state port_base_vlan_state; | ||
30 | |||
31 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
34 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
35 | @@ -XXX,XX +XXX,XX @@ static int hclge_vport_setup(struct hclge_vport *vport, u16 num_tqps) | ||
36 | |||
37 | nic->pdev = hdev->pdev; | ||
38 | nic->ae_algo = &ae_algo; | ||
39 | - nic->numa_node_mask = hdev->numa_node_mask; | ||
40 | + bitmap_copy(nic->numa_node_mask.bits, hdev->numa_node_mask.bits, | ||
41 | + MAX_NUMNODES); | ||
42 | nic->kinfo.io_base = hdev->hw.hw.io_base; | ||
43 | |||
44 | ret = hclge_knic_setup(vport, num_tqps, | ||
45 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_roce_base_info(struct hclge_vport *vport) | ||
46 | |||
47 | roce->pdev = nic->pdev; | ||
48 | roce->ae_algo = nic->ae_algo; | ||
49 | - roce->numa_node_mask = nic->numa_node_mask; | ||
50 | + bitmap_copy(roce->numa_node_mask.bits, nic->numa_node_mask.bits, | ||
51 | + MAX_NUMNODES); | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | ||
56 | index XXXXXXX..XXXXXXX 100644 | ||
57 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | ||
58 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h | ||
59 | @@ -XXX,XX +XXX,XX @@ struct hclge_dev { | ||
60 | |||
61 | u16 fdir_pf_filter_count; /* Num of guaranteed filters for this PF */ | ||
62 | u16 num_alloc_vport; /* Num vports this driver supports */ | ||
63 | - u32 numa_node_mask; | ||
64 | + nodemask_t numa_node_mask; | ||
65 | u16 rx_buf_len; | ||
66 | u16 num_tx_desc; /* desc num of per tx queue */ | ||
67 | u16 num_rx_desc; /* desc num of per rx queue */ | ||
19 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 68 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c |
20 | index XXXXXXX..XXXXXXX 100644 | 69 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 70 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c |
22 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 71 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c |
23 | @@ -XXX,XX +XXX,XX @@ static void hclgevf_sync_vlan_filter(struct hclgevf_dev *hdev) | 72 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_set_handle_info(struct hclgevf_dev *hdev) |
24 | rtnl_unlock(); | 73 | |
74 | nic->ae_algo = &ae_algovf; | ||
75 | nic->pdev = hdev->pdev; | ||
76 | - nic->numa_node_mask = hdev->numa_node_mask; | ||
77 | + bitmap_copy(nic->numa_node_mask.bits, hdev->numa_node_mask.bits, | ||
78 | + MAX_NUMNODES); | ||
79 | nic->flags |= HNAE3_SUPPORT_VF; | ||
80 | nic->kinfo.io_base = hdev->hw.hw.io_base; | ||
81 | |||
82 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_init_roce_base_info(struct hclgevf_dev *hdev) | ||
83 | |||
84 | roce->pdev = nic->pdev; | ||
85 | roce->ae_algo = nic->ae_algo; | ||
86 | - roce->numa_node_mask = nic->numa_node_mask; | ||
87 | - | ||
88 | + bitmap_copy(roce->numa_node_mask.bits, nic->numa_node_mask.bits, | ||
89 | + MAX_NUMNODES); | ||
90 | return 0; | ||
25 | } | 91 | } |
26 | 92 | ||
27 | -static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) | ||
28 | +static int hclgevf_en_hw_strip_rxvtag_cmd(struct hclgevf_dev *hdev, bool enable) | ||
29 | { | ||
30 | - struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); | ||
31 | struct hclge_vf_to_pf_msg send_msg; | ||
32 | |||
33 | hclgevf_build_send_msg(&send_msg, HCLGE_MBX_SET_VLAN, | ||
34 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) | ||
35 | return hclgevf_send_mbx_msg(hdev, &send_msg, false, NULL, 0); | ||
36 | } | ||
37 | |||
38 | +static int hclgevf_en_hw_strip_rxvtag(struct hnae3_handle *handle, bool enable) | ||
39 | +{ | ||
40 | + struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); | ||
41 | + int ret; | ||
42 | + | ||
43 | + ret = hclgevf_en_hw_strip_rxvtag_cmd(hdev, enable); | ||
44 | + if (ret) | ||
45 | + return ret; | ||
46 | + | ||
47 | + hdev->rxvtag_strip_en = enable; | ||
48 | + return 0; | ||
49 | +} | ||
50 | + | ||
51 | static int hclgevf_reset_tqp(struct hnae3_handle *handle) | ||
52 | { | ||
53 | #define HCLGEVF_RESET_ALL_QUEUE_DONE 1U | ||
54 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_rss_init_hw(struct hclgevf_dev *hdev) | ||
55 | tc_valid, tc_size); | ||
56 | } | ||
57 | |||
58 | -static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev) | ||
59 | +static int hclgevf_init_vlan_config(struct hclgevf_dev *hdev, | ||
60 | + bool rxvtag_strip_en) | ||
61 | { | ||
62 | struct hnae3_handle *nic = &hdev->nic; | ||
63 | int ret; | ||
64 | |||
65 | - ret = hclgevf_en_hw_strip_rxvtag(nic, true); | ||
66 | + ret = hclgevf_en_hw_strip_rxvtag(nic, rxvtag_strip_en); | ||
67 | if (ret) { | ||
68 | dev_err(&hdev->pdev->dev, | ||
69 | "failed to enable rx vlan offload, ret = %d\n", ret); | ||
70 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) | ||
71 | if (ret) | ||
72 | return ret; | ||
73 | |||
74 | - ret = hclgevf_init_vlan_config(hdev); | ||
75 | + ret = hclgevf_init_vlan_config(hdev, hdev->rxvtag_strip_en); | ||
76 | if (ret) { | ||
77 | dev_err(&hdev->pdev->dev, | ||
78 | "failed(%d) to initialize VLAN config\n", ret); | ||
79 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) | ||
80 | goto err_config; | ||
81 | } | ||
82 | |||
83 | - ret = hclgevf_init_vlan_config(hdev); | ||
84 | + ret = hclgevf_init_vlan_config(hdev, true); | ||
85 | if (ret) { | ||
86 | dev_err(&hdev->pdev->dev, | ||
87 | "failed(%d) to initialize VLAN config\n", ret); | ||
88 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 93 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h |
89 | index XXXXXXX..XXXXXXX 100644 | 94 | index XXXXXXX..XXXXXXX 100644 |
90 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 95 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h |
91 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h | 96 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h |
92 | @@ -XXX,XX +XXX,XX @@ struct hclgevf_dev { | 97 | @@ -XXX,XX +XXX,XX @@ struct hclgevf_dev { |
93 | u16 *vector_status; | 98 | u16 rss_size_max; /* HW defined max RSS task queue */ |
94 | int *vector_irq; | 99 | |
95 | 100 | u16 num_alloc_vport; /* num vports this driver supports */ | |
96 | - bool gro_en; | 101 | - u32 numa_node_mask; |
97 | + u32 gro_en :1; | 102 | + nodemask_t numa_node_mask; |
98 | + u32 rxvtag_strip_en :1; | 103 | u16 rx_buf_len; |
99 | 104 | u16 num_tx_desc; /* desc num of per tx queue */ | |
100 | unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)]; | 105 | u16 num_rx_desc; /* desc num of per rx queue */ |
101 | |||
102 | -- | 106 | -- |
103 | 2.33.0 | 107 | 2.30.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Peiyang Wang <wangpeiyang1@huawei.com> | ||
1 | 2 | ||
3 | During the PF initialization process, hclge_update_port_info may return an | ||
4 | error code for some reason. At this point, the ptp initialization has been | ||
5 | completed. To void memory leaks, the resources that are applied by ptp | ||
6 | should be released. Therefore, when hclge_update_port_info returns an error | ||
7 | code, hclge_ptp_uninit is called to release the corresponding resources. | ||
8 | |||
9 | Fixes: eaf83ae59e18 ("net: hns3: add querying fec ability from firmware") | ||
10 | Signed-off-by: Peiyang Wang <wangpeiyang1@huawei.com> | ||
11 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> | ||
12 | Reviewed-by: Hariprasad Kelam <hkelam@marvell.com> | ||
13 | --- | ||
14 | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 4 +++- | ||
15 | 1 file changed, 3 insertions(+), 1 deletion(-) | ||
16 | |||
17 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
18 | index XXXXXXX..XXXXXXX 100644 | ||
19 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
20 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
21 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) | ||
22 | |||
23 | ret = hclge_update_port_info(hdev); | ||
24 | if (ret) | ||
25 | - goto err_mdiobus_unreg; | ||
26 | + goto err_ptp_uninit; | ||
27 | |||
28 | INIT_KFIFO(hdev->mac_tnl_log); | ||
29 | |||
30 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) | ||
31 | devl_unlock(hdev->devlink); | ||
32 | return 0; | ||
33 | |||
34 | +err_ptp_uninit: | ||
35 | + hclge_ptp_uninit(hdev); | ||
36 | err_mdiobus_unreg: | ||
37 | if (hdev->hw.mac.phydev) | ||
38 | mdiobus_unregister(hdev->hw.mac.mdio_bus); | ||
39 | -- | ||
40 | 2.30.0 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Peiyang Wang <wangpeiyang1@huawei.com> | ||
1 | 2 | ||
3 | There is a memory barrier in followed case. When set the port down, | ||
4 | hclgevf_set_timmer will set DOWN in state. Meanwhile, the service task has | ||
5 | different behaviour based on whether the state is DOWN. Thus, to make sure | ||
6 | service task see DOWN, use smp_mb__after_atomic after calling set_bit(). | ||
7 | |||
8 | CPU0 CPU1 | ||
9 | ========================== =================================== | ||
10 | hclgevf_set_timer_task() hclgevf_periodic_service_task() | ||
11 | set_bit(DOWN,state) test_bit(DOWN,state) | ||
12 | |||
13 | pf also has this issue. | ||
14 | |||
15 | Fixes: ff200099d271 ("net: hns3: remove unnecessary work in hclgevf_main") | ||
16 | Fixes: 1c6dfe6fc6f7 ("net: hns3: remove mailbox and reset work in hclge_main") | ||
17 | Signed-off-by: Peiyang Wang <wangpeiyang1@huawei.com> | ||
18 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> | ||
19 | Reviewed-by: Simon Horman <horms@kernel.org> | ||
20 | --- | ||
21 | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 3 +-- | ||
22 | drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | 3 +-- | ||
23 | 2 files changed, 2 insertions(+), 4 deletions(-) | ||
24 | |||
25 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
26 | index XXXXXXX..XXXXXXX 100644 | ||
27 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
28 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | ||
29 | @@ -XXX,XX +XXX,XX @@ static void hclge_set_timer_task(struct hnae3_handle *handle, bool enable) | ||
30 | /* Set the DOWN flag here to disable link updating */ | ||
31 | set_bit(HCLGE_STATE_DOWN, &hdev->state); | ||
32 | |||
33 | - /* flush memory to make sure DOWN is seen by service task */ | ||
34 | - smp_mb__before_atomic(); | ||
35 | + smp_mb__after_atomic(); /* flush memory to make sure DOWN is seen by service task */ | ||
36 | hclge_flush_link_update(hdev); | ||
37 | } | ||
38 | } | ||
39 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | ||
40 | index XXXXXXX..XXXXXXX 100644 | ||
41 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | ||
42 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | ||
43 | @@ -XXX,XX +XXX,XX @@ static void hclgevf_set_timer_task(struct hnae3_handle *handle, bool enable) | ||
44 | } else { | ||
45 | set_bit(HCLGEVF_STATE_DOWN, &hdev->state); | ||
46 | |||
47 | - /* flush memory to make sure DOWN is seen by service task */ | ||
48 | - smp_mb__before_atomic(); | ||
49 | + smp_mb__after_atomic(); /* flush memory to make sure DOWN is seen by service task */ | ||
50 | hclgevf_flush_link_update(hdev); | ||
51 | } | ||
52 | } | ||
53 | -- | ||
54 | 2.30.0 | diff view generated by jsdifflib |
1 | From: Hao Lan <lanhao@huawei.com> | 1 | From: Yonglong Liu <liuyonglong@huawei.com> |
---|---|---|---|
2 | 2 | ||
3 | There are spelling mistakes in hclgevf_get_regs. Fix them. | 3 | According to hardware limitation, for device support modify |
4 | VLAN filter state but not support bypass port VLAN filter, | ||
5 | it should always disable the port VLAN filter. but the driver | ||
6 | enables port VLAN filter when initializing, if there is no | ||
7 | VLAN(except VLAN 0) id added, the driver will disable it | ||
8 | in service task. In most time, it works fine. But there is | ||
9 | a time window before the service task shceduled and net device | ||
10 | being registered. So if user adds VLAN at this time, the driver | ||
11 | will not update the VLAN filter state, and the port VLAN filter | ||
12 | remains enabled. | ||
4 | 13 | ||
5 | Signed-off-by: Hao Lan <lanhao@huawei.com> | 14 | To fix the problem, if support modify VLAN filter state but not |
15 | support bypass port VLAN filter, set the port vlan filter to "off". | ||
16 | |||
17 | Fixes: 184cd221a863 ("net: hns3: disable port VLAN filter when support function level VLAN filter control") | ||
18 | Fixes: 2ba306627f59 ("net: hns3: add support for modify VLAN filter state") | ||
19 | Signed-off-by: Yonglong Liu <liuyonglong@huawei.com> | ||
6 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> | 20 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> |
21 | Reviewed-by: Simon Horman <horms@kernel.org> | ||
7 | --- | 22 | --- |
8 | .../hisilicon/hns3/hns3vf/hclgevf_regs.c | 27 ++++++++++--------- | 23 | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 7 ++++++- |
9 | 1 file changed, 14 insertions(+), 13 deletions(-) | 24 | 1 file changed, 6 insertions(+), 1 deletion(-) |
10 | 25 | ||
11 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c | 26 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c |
12 | index XXXXXXX..XXXXXXX 100644 | 27 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c | 28 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c |
14 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_regs.c | 29 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c |
15 | @@ -XXX,XX +XXX,XX @@ void hclgevf_get_regs(struct hnae3_handle *handle, u32 *version, | 30 | @@ -XXX,XX +XXX,XX @@ static int hclge_set_vlan_protocol_type(struct hclge_dev *hdev) |
16 | 31 | static int hclge_init_vlan_filter(struct hclge_dev *hdev) | |
17 | struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); | 32 | { |
18 | struct hnae3_queue *tqp; | 33 | struct hclge_vport *vport; |
19 | - int i, j, reg_um; | 34 | + bool enable = true; |
20 | + int i, j, reg_num; | 35 | int ret; |
21 | u32 *reg = data; | 36 | int i; |
22 | 37 | ||
23 | *version = hdev->fw_version; | 38 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_vlan_filter(struct hclge_dev *hdev) |
24 | reg += hclgevf_reg_get_header(reg); | 39 | vport->cur_vlan_fltr_en = true; |
25 | |||
26 | /* fetching per-VF registers values from VF PCIe register space */ | ||
27 | - reg_um = ARRAY_SIZE(cmdq_reg_addr_list); | ||
28 | - reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_CMDQ, reg_um, reg); | ||
29 | - for (i = 0; i < reg_um; i++) | ||
30 | + reg_num = ARRAY_SIZE(cmdq_reg_addr_list); | ||
31 | + reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_CMDQ, reg_num, reg); | ||
32 | + for (i = 0; i < reg_num; i++) | ||
33 | *reg++ = hclgevf_read_dev(&hdev->hw, cmdq_reg_addr_list[i]); | ||
34 | |||
35 | - reg_um = ARRAY_SIZE(common_reg_addr_list); | ||
36 | - reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_COMMON, reg_um, reg); | ||
37 | - for (i = 0; i < reg_um; i++) | ||
38 | + reg_num = ARRAY_SIZE(common_reg_addr_list); | ||
39 | + reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_COMMON, reg_num, reg); | ||
40 | + for (i = 0; i < reg_num; i++) | ||
41 | *reg++ = hclgevf_read_dev(&hdev->hw, common_reg_addr_list[i]); | ||
42 | |||
43 | - reg_um = ARRAY_SIZE(ring_reg_addr_list); | ||
44 | + reg_num = ARRAY_SIZE(ring_reg_addr_list); | ||
45 | for (j = 0; j < hdev->num_tqps; j++) { | ||
46 | - reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_RING, reg_um, reg); | ||
47 | + reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_RING, reg_num, reg); | ||
48 | tqp = &hdev->htqp[j].q; | ||
49 | - for (i = 0; i < reg_um; i++) | ||
50 | + for (i = 0; i < reg_num; i++) | ||
51 | *reg++ = readl_relaxed(tqp->io_base - | ||
52 | HCLGEVF_TQP_REG_OFFSET + | ||
53 | ring_reg_addr_list[i]); | ||
54 | } | 40 | } |
55 | 41 | ||
56 | - reg_um = ARRAY_SIZE(tqp_intr_reg_addr_list); | 42 | + if (test_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, hdev->ae_dev->caps) && |
57 | + reg_num = ARRAY_SIZE(tqp_intr_reg_addr_list); | 43 | + !test_bit(HNAE3_DEV_SUPPORT_PORT_VLAN_BYPASS_B, hdev->ae_dev->caps)) |
58 | for (j = 0; j < hdev->num_msi_used - 1; j++) { | 44 | + enable = false; |
59 | - reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_TQP_INTR, reg_um, reg); | 45 | + |
60 | - for (i = 0; i < reg_um; i++) | 46 | return hclge_set_vlan_filter_ctrl(hdev, HCLGE_FILTER_TYPE_PORT, |
61 | + reg += hclgevf_reg_get_tlv(HCLGEVF_REG_TAG_TQP_INTR, | 47 | - HCLGE_FILTER_FE_INGRESS, true, 0); |
62 | + reg_num, reg); | 48 | + HCLGE_FILTER_FE_INGRESS, enable, 0); |
63 | + for (i = 0; i < reg_num; i++) | 49 | } |
64 | *reg++ = hclgevf_read_dev(&hdev->hw, | 50 | |
65 | tqp_intr_reg_addr_list[i] + | 51 | static int hclge_init_vlan_type(struct hclge_dev *hdev) |
66 | HCLGEVF_RING_INT_REG_OFFSET * j); | ||
67 | -- | 52 | -- |
68 | 2.33.0 | 53 | 2.30.0 | diff view generated by jsdifflib |
1 | From: Yonglong Liu <liuyonglong@huawei.com> | 1 | From: Yonglong Liu <liuyonglong@huawei.com> |
---|---|---|---|
2 | 2 | ||
3 | In hclge_add_fd_entry(), if the flow type is FLOW_EXT, and the data of | 3 | The devlink reload process will access the hardware resources, |
4 | m_ext is all zero, then some members of the local variable "info" are | 4 | but the register operation is done before the hardware is initialized. |
5 | not initialized. | 5 | So, processing the devlink reload during initialization may lead to kernel |
6 | crash. | ||
6 | 7 | ||
7 | Fixes: 67b0e1428e2f ("net: hns3: add support for user-def data of flow director") | 8 | This patch fixes this by registering the devlink after |
9 | hardware initialization. | ||
10 | |||
11 | Fixes: cd6242991d2e ("net: hns3: add support for registering devlink for VF") | ||
12 | Fixes: 93305b77ffcb ("net: hns3: fix kernel crash when devlink reload during pf initialization") | ||
8 | Signed-off-by: Yonglong Liu <liuyonglong@huawei.com> | 13 | Signed-off-by: Yonglong Liu <liuyonglong@huawei.com> |
9 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> | 14 | Signed-off-by: Jijie Shao <shaojijie@huawei.com> |
10 | --- | 15 | --- |
11 | drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 2 +- | 16 | .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 17 +++++------------ |
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | 17 | .../hisilicon/hns3/hns3vf/hclgevf_main.c | 10 ++++------ |
18 | 2 files changed, 9 insertions(+), 18 deletions(-) | ||
13 | 19 | ||
14 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 20 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c |
15 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 22 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c |
17 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 23 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c |
18 | @@ -XXX,XX +XXX,XX @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, | 24 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) |
19 | struct ethtool_rxnfc *cmd) | 25 | if (ret) |
20 | { | 26 | goto out; |
21 | struct hclge_vport *vport = hclge_get_vport(handle); | 27 | |
22 | + struct hclge_fd_user_def_info info = {0}; | 28 | - ret = hclge_devlink_init(hdev); |
23 | struct hclge_dev *hdev = vport->back; | 29 | - if (ret) |
24 | - struct hclge_fd_user_def_info info; | 30 | - goto err_pci_uninit; |
25 | u16 dst_vport_id = 0, q_index = 0; | 31 | - |
26 | struct ethtool_rx_flow_spec *fs; | 32 | - devl_lock(hdev->devlink); |
27 | struct hclge_fd_rule *rule; | 33 | - |
34 | /* Firmware command queue initialize */ | ||
35 | ret = hclge_comm_cmd_queue_init(hdev->pdev, &hdev->hw.hw); | ||
36 | if (ret) | ||
37 | - goto err_devlink_uninit; | ||
38 | + goto err_pci_uninit; | ||
39 | |||
40 | /* Firmware command initialize */ | ||
41 | ret = hclge_comm_cmd_init(hdev->ae_dev, &hdev->hw.hw, &hdev->fw_version, | ||
42 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) | ||
43 | dev_warn(&pdev->dev, | ||
44 | "failed to wake on lan init, ret = %d\n", ret); | ||
45 | |||
46 | + ret = hclge_devlink_init(hdev); | ||
47 | + if (ret) | ||
48 | + goto err_ptp_uninit; | ||
49 | + | ||
50 | hclge_state_init(hdev); | ||
51 | hdev->last_reset_time = jiffies; | ||
52 | |||
53 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) | ||
54 | HCLGE_DRIVER_NAME); | ||
55 | |||
56 | hclge_task_schedule(hdev, round_jiffies_relative(HZ)); | ||
57 | - | ||
58 | - devl_unlock(hdev->devlink); | ||
59 | return 0; | ||
60 | |||
61 | err_ptp_uninit: | ||
62 | @@ -XXX,XX +XXX,XX @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) | ||
63 | pci_free_irq_vectors(pdev); | ||
64 | err_cmd_uninit: | ||
65 | hclge_comm_cmd_uninit(hdev->ae_dev, &hdev->hw.hw); | ||
66 | -err_devlink_uninit: | ||
67 | - devl_unlock(hdev->devlink); | ||
68 | - hclge_devlink_uninit(hdev); | ||
69 | err_pci_uninit: | ||
70 | pcim_iounmap(pdev, hdev->hw.hw.io_base); | ||
71 | pci_release_regions(pdev); | ||
72 | diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | ||
73 | index XXXXXXX..XXXXXXX 100644 | ||
74 | --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | ||
75 | +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c | ||
76 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) | ||
77 | if (ret) | ||
78 | return ret; | ||
79 | |||
80 | - ret = hclgevf_devlink_init(hdev); | ||
81 | - if (ret) | ||
82 | - goto err_devlink_init; | ||
83 | - | ||
84 | ret = hclge_comm_cmd_queue_init(hdev->pdev, &hdev->hw.hw); | ||
85 | if (ret) | ||
86 | goto err_cmd_queue_init; | ||
87 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) | ||
88 | |||
89 | hclgevf_init_rxd_adv_layout(hdev); | ||
90 | |||
91 | + ret = hclgevf_devlink_init(hdev); | ||
92 | + if (ret) | ||
93 | + goto err_config; | ||
94 | + | ||
95 | set_bit(HCLGEVF_STATE_SERVICE_INITED, &hdev->state); | ||
96 | |||
97 | hdev->last_reset_time = jiffies; | ||
98 | @@ -XXX,XX +XXX,XX @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) | ||
99 | err_cmd_init: | ||
100 | hclge_comm_cmd_uninit(hdev->ae_dev, &hdev->hw.hw); | ||
101 | err_cmd_queue_init: | ||
102 | - hclgevf_devlink_uninit(hdev); | ||
103 | -err_devlink_init: | ||
104 | hclgevf_pci_uninit(hdev); | ||
105 | clear_bit(HCLGEVF_STATE_IRQ_INITED, &hdev->state); | ||
106 | return ret; | ||
28 | -- | 107 | -- |
29 | 2.33.0 | 108 | 2.30.0 | diff view generated by jsdifflib |