Skip to content

Commit c39c4d9

Browse files
Yunsheng Lindavem330
authored andcommitted
net: hns3: Add mac loopback selftest support in hns3 driver
This patch adds mac loopback selftest support for ethtool cmd by checking if a transmitted packet can be received correctly when mac loopback is enabled. Signed-off-by: Yunsheng Lin <linyunsheng@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent d43e5ac commit c39c4d9

File tree

2 files changed

+327
-0
lines changed

2 files changed

+327
-0
lines changed

drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3149,6 +3149,59 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable)
31493149
"mac enable fail, ret =%d.\n", ret);
31503150
}
31513151

3152+
static int hclge_set_loopback(struct hnae3_handle *handle,
3153+
enum hnae3_loop loop_mode, bool en)
3154+
{
3155+
struct hclge_vport *vport = hclge_get_vport(handle);
3156+
struct hclge_config_mac_mode_cmd *req;
3157+
struct hclge_dev *hdev = vport->back;
3158+
struct hclge_desc desc;
3159+
u32 loop_en;
3160+
int ret;
3161+
3162+
switch (loop_mode) {
3163+
case HNAE3_MAC_INTER_LOOP_MAC:
3164+
req = (struct hclge_config_mac_mode_cmd *)&desc.data[0];
3165+
/* 1 Read out the MAC mode config at first */
3166+
hclge_cmd_setup_basic_desc(&desc,
3167+
HCLGE_OPC_CONFIG_MAC_MODE,
3168+
true);
3169+
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
3170+
if (ret) {
3171+
dev_err(&hdev->pdev->dev,
3172+
"mac loopback get fail, ret =%d.\n",
3173+
ret);
3174+
return ret;
3175+
}
3176+
3177+
/* 2 Then setup the loopback flag */
3178+
loop_en = le32_to_cpu(req->txrx_pad_fcs_loop_en);
3179+
if (en)
3180+
hnae_set_bit(loop_en, HCLGE_MAC_APP_LP_B, 1);
3181+
else
3182+
hnae_set_bit(loop_en, HCLGE_MAC_APP_LP_B, 0);
3183+
3184+
req->txrx_pad_fcs_loop_en = cpu_to_le32(loop_en);
3185+
3186+
/* 3 Config mac work mode with loopback flag
3187+
* and its original configure parameters
3188+
*/
3189+
hclge_cmd_reuse_desc(&desc, false);
3190+
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
3191+
if (ret)
3192+
dev_err(&hdev->pdev->dev,
3193+
"mac loopback set fail, ret =%d.\n", ret);
3194+
break;
3195+
default:
3196+
ret = -ENOTSUPP;
3197+
dev_err(&hdev->pdev->dev,
3198+
"loop_mode %d is not supported\n", loop_mode);
3199+
break;
3200+
}
3201+
3202+
return ret;
3203+
}
3204+
31523205
static int hclge_tqp_enable(struct hclge_dev *hdev, int tqp_id,
31533206
int stream_id, bool enable)
31543207
{
@@ -4485,6 +4538,7 @@ static const struct hnae3_ae_ops hclge_ops = {
44854538
.unmap_ring_from_vector = hclge_unmap_ring_from_vector,
44864539
.get_vector = hclge_get_vector,
44874540
.set_promisc_mode = hclge_set_promisc_mode,
4541+
.set_loopback = hclge_set_loopback,
44884542
.start = hclge_ae_start,
44894543
.stop = hclge_ae_stop,
44904544
.get_status = hclge_get_status,

drivers/net/ethernet/hisilicon/hns3/hns3pf/hns3_ethtool.c

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ static const struct hns3_stats hns3_rxq_stats[] = {
5959

6060
#define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT)
6161

62+
#define HNS3_SELF_TEST_TPYE_NUM 1
63+
#define HNS3_NIC_LB_TEST_PKT_NUM 1
64+
#define HNS3_NIC_LB_TEST_RING_ID 0
65+
#define HNS3_NIC_LB_TEST_PACKET_SIZE 128
66+
67+
/* Nic loopback test err */
68+
#define HNS3_NIC_LB_TEST_NO_MEM_ERR 1
69+
#define HNS3_NIC_LB_TEST_TX_CNT_ERR 2
70+
#define HNS3_NIC_LB_TEST_RX_CNT_ERR 3
71+
6272
struct hns3_link_mode_mapping {
6373
u32 hns3_link_mode;
6474
u32 ethtool_link_mode;
@@ -77,6 +87,268 @@ static const struct hns3_link_mode_mapping hns3_lm_map[] = {
7787
{HNS3_LM_1000BASET_FULL_BIT, ETHTOOL_LINK_MODE_1000baseT_Full_BIT},
7888
};
7989

90+
static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop)
91+
{
92+
struct hnae3_handle *h = hns3_get_handle(ndev);
93+
int ret;
94+
95+
if (!h->ae_algo->ops->set_loopback ||
96+
!h->ae_algo->ops->set_promisc_mode)
97+
return -EOPNOTSUPP;
98+
99+
switch (loop) {
100+
case HNAE3_MAC_INTER_LOOP_MAC:
101+
ret = h->ae_algo->ops->set_loopback(h, loop, true);
102+
break;
103+
case HNAE3_MAC_LOOP_NONE:
104+
ret = h->ae_algo->ops->set_loopback(h,
105+
HNAE3_MAC_INTER_LOOP_MAC, false);
106+
break;
107+
default:
108+
ret = -ENOTSUPP;
109+
break;
110+
}
111+
112+
if (ret)
113+
return ret;
114+
115+
if (loop == HNAE3_MAC_LOOP_NONE)
116+
h->ae_algo->ops->set_promisc_mode(h, ndev->flags & IFF_PROMISC);
117+
else
118+
h->ae_algo->ops->set_promisc_mode(h, 1);
119+
120+
return ret;
121+
}
122+
123+
static int hns3_lp_up(struct net_device *ndev, enum hnae3_loop loop_mode)
124+
{
125+
struct hnae3_handle *h = hns3_get_handle(ndev);
126+
int ret;
127+
128+
if (!h->ae_algo->ops->start)
129+
return -EOPNOTSUPP;
130+
131+
ret = h->ae_algo->ops->start(h);
132+
if (ret) {
133+
netdev_err(ndev,
134+
"hns3_lb_up ae start return error: %d\n", ret);
135+
return ret;
136+
}
137+
138+
ret = hns3_lp_setup(ndev, loop_mode);
139+
usleep_range(10000, 20000);
140+
141+
return ret;
142+
}
143+
144+
static int hns3_lp_down(struct net_device *ndev)
145+
{
146+
struct hnae3_handle *h = hns3_get_handle(ndev);
147+
int ret;
148+
149+
if (!h->ae_algo->ops->stop)
150+
return -EOPNOTSUPP;
151+
152+
ret = hns3_lp_setup(ndev, HNAE3_MAC_LOOP_NONE);
153+
if (ret) {
154+
netdev_err(ndev, "lb_setup return error: %d\n", ret);
155+
return ret;
156+
}
157+
158+
h->ae_algo->ops->stop(h);
159+
usleep_range(10000, 20000);
160+
161+
return 0;
162+
}
163+
164+
static void hns3_lp_setup_skb(struct sk_buff *skb)
165+
{
166+
struct net_device *ndev = skb->dev;
167+
unsigned char *packet;
168+
struct ethhdr *ethh;
169+
unsigned int i;
170+
171+
skb_reserve(skb, NET_IP_ALIGN);
172+
ethh = skb_put(skb, sizeof(struct ethhdr));
173+
packet = skb_put(skb, HNS3_NIC_LB_TEST_PACKET_SIZE);
174+
175+
memcpy(ethh->h_dest, ndev->dev_addr, ETH_ALEN);
176+
eth_zero_addr(ethh->h_source);
177+
ethh->h_proto = htons(ETH_P_ARP);
178+
skb_reset_mac_header(skb);
179+
180+
for (i = 0; i < HNS3_NIC_LB_TEST_PACKET_SIZE; i++)
181+
packet[i] = (unsigned char)(i & 0xff);
182+
}
183+
184+
static void hns3_lb_check_skb_data(struct hns3_enet_ring *ring,
185+
struct sk_buff *skb)
186+
{
187+
struct hns3_enet_tqp_vector *tqp_vector = ring->tqp_vector;
188+
unsigned char *packet = skb->data;
189+
u32 i;
190+
191+
for (i = 0; i < skb->len; i++)
192+
if (packet[i] != (unsigned char)(i & 0xff))
193+
break;
194+
195+
/* The packet is correctly received */
196+
if (i == skb->len)
197+
tqp_vector->rx_group.total_packets++;
198+
else
199+
print_hex_dump(KERN_ERR, "selftest:", DUMP_PREFIX_OFFSET, 16, 1,
200+
skb->data, skb->len, true);
201+
202+
dev_kfree_skb_any(skb);
203+
}
204+
205+
static u32 hns3_lb_check_rx_ring(struct hns3_nic_priv *priv, u32 budget)
206+
{
207+
struct hnae3_handle *h = priv->ae_handle;
208+
struct hnae3_knic_private_info *kinfo;
209+
u32 i, rcv_good_pkt_total = 0;
210+
211+
kinfo = &h->kinfo;
212+
for (i = kinfo->num_tqps; i < kinfo->num_tqps * 2; i++) {
213+
struct hns3_enet_ring *ring = priv->ring_data[i].ring;
214+
struct hns3_enet_ring_group *rx_group;
215+
u64 pre_rx_pkt;
216+
217+
rx_group = &ring->tqp_vector->rx_group;
218+
pre_rx_pkt = rx_group->total_packets;
219+
220+
hns3_clean_rx_ring(ring, budget, hns3_lb_check_skb_data);
221+
222+
rcv_good_pkt_total += (rx_group->total_packets - pre_rx_pkt);
223+
rx_group->total_packets = pre_rx_pkt;
224+
}
225+
return rcv_good_pkt_total;
226+
}
227+
228+
static void hns3_lb_clear_tx_ring(struct hns3_nic_priv *priv, u32 start_ringid,
229+
u32 end_ringid, u32 budget)
230+
{
231+
u32 i;
232+
233+
for (i = start_ringid; i <= end_ringid; i++) {
234+
struct hns3_enet_ring *ring = priv->ring_data[i].ring;
235+
236+
hns3_clean_tx_ring(ring, budget);
237+
}
238+
}
239+
240+
/**
241+
* hns3_lp_run_test - run loopback test
242+
* @ndev: net device
243+
* @mode: loopback type
244+
*/
245+
static int hns3_lp_run_test(struct net_device *ndev, enum hnae3_loop mode)
246+
{
247+
struct hns3_nic_priv *priv = netdev_priv(ndev);
248+
struct sk_buff *skb;
249+
u32 i, good_cnt;
250+
int ret_val = 0;
251+
252+
skb = alloc_skb(HNS3_NIC_LB_TEST_PACKET_SIZE + ETH_HLEN + NET_IP_ALIGN,
253+
GFP_KERNEL);
254+
if (!skb)
255+
return HNS3_NIC_LB_TEST_NO_MEM_ERR;
256+
257+
skb->dev = ndev;
258+
hns3_lp_setup_skb(skb);
259+
skb->queue_mapping = HNS3_NIC_LB_TEST_RING_ID;
260+
261+
good_cnt = 0;
262+
for (i = 0; i < HNS3_NIC_LB_TEST_PKT_NUM; i++) {
263+
netdev_tx_t tx_ret;
264+
265+
skb_get(skb);
266+
tx_ret = hns3_nic_net_xmit(skb, ndev);
267+
if (tx_ret == NETDEV_TX_OK)
268+
good_cnt++;
269+
else
270+
netdev_err(ndev, "hns3_lb_run_test xmit failed: %d\n",
271+
tx_ret);
272+
}
273+
if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
274+
ret_val = HNS3_NIC_LB_TEST_TX_CNT_ERR;
275+
netdev_err(ndev, "mode %d sent fail, cnt=0x%x, budget=0x%x\n",
276+
mode, good_cnt, HNS3_NIC_LB_TEST_PKT_NUM);
277+
goto out;
278+
}
279+
280+
/* Allow 200 milliseconds for packets to go from Tx to Rx */
281+
msleep(200);
282+
283+
good_cnt = hns3_lb_check_rx_ring(priv, HNS3_NIC_LB_TEST_PKT_NUM);
284+
if (good_cnt != HNS3_NIC_LB_TEST_PKT_NUM) {
285+
ret_val = HNS3_NIC_LB_TEST_RX_CNT_ERR;
286+
netdev_err(ndev, "mode %d recv fail, cnt=0x%x, budget=0x%x\n",
287+
mode, good_cnt, HNS3_NIC_LB_TEST_PKT_NUM);
288+
}
289+
290+
out:
291+
hns3_lb_clear_tx_ring(priv, HNS3_NIC_LB_TEST_RING_ID,
292+
HNS3_NIC_LB_TEST_RING_ID,
293+
HNS3_NIC_LB_TEST_PKT_NUM);
294+
295+
kfree_skb(skb);
296+
return ret_val;
297+
}
298+
299+
/**
300+
* hns3_nic_self_test - self test
301+
* @ndev: net device
302+
* @eth_test: test cmd
303+
* @data: test result
304+
*/
305+
static void hns3_self_test(struct net_device *ndev,
306+
struct ethtool_test *eth_test, u64 *data)
307+
{
308+
struct hns3_nic_priv *priv = netdev_priv(ndev);
309+
struct hnae3_handle *h = priv->ae_handle;
310+
int st_param[HNS3_SELF_TEST_TPYE_NUM][2];
311+
bool if_running = netif_running(ndev);
312+
int test_index = 0;
313+
u32 i;
314+
315+
/* Only do offline selftest, or pass by default */
316+
if (eth_test->flags != ETH_TEST_FL_OFFLINE)
317+
return;
318+
319+
st_param[HNAE3_MAC_INTER_LOOP_MAC][0] = HNAE3_MAC_INTER_LOOP_MAC;
320+
st_param[HNAE3_MAC_INTER_LOOP_MAC][1] =
321+
h->flags & HNAE3_SUPPORT_MAC_LOOPBACK;
322+
323+
if (if_running)
324+
dev_close(ndev);
325+
326+
set_bit(HNS3_NIC_STATE_TESTING, &priv->state);
327+
328+
for (i = 0; i < HNS3_SELF_TEST_TPYE_NUM; i++) {
329+
enum hnae3_loop loop_type = (enum hnae3_loop)st_param[i][0];
330+
331+
if (!st_param[i][1])
332+
continue;
333+
334+
data[test_index] = hns3_lp_up(ndev, loop_type);
335+
if (!data[test_index]) {
336+
data[test_index] = hns3_lp_run_test(ndev, loop_type);
337+
hns3_lp_down(ndev);
338+
}
339+
340+
if (data[test_index])
341+
eth_test->flags |= ETH_TEST_FL_FAILED;
342+
343+
test_index++;
344+
}
345+
346+
clear_bit(HNS3_NIC_STATE_TESTING, &priv->state);
347+
348+
if (if_running)
349+
dev_open(ndev);
350+
}
351+
80352
static void hns3_driv_to_eth_caps(u32 caps, struct ethtool_link_ksettings *cmd,
81353
bool is_advertised)
82354
{
@@ -553,6 +825,7 @@ static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
553825
}
554826

555827
static const struct ethtool_ops hns3_ethtool_ops = {
828+
.self_test = hns3_self_test,
556829
.get_drvinfo = hns3_get_drvinfo,
557830
.get_link = hns3_get_link,
558831
.get_ringparam = hns3_get_ringparam,

0 commit comments

Comments
 (0)