18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2014-2015 Hisilicon Limited.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/clk.h>
78c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
88c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
98c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/io.h>
128c2ecf20Sopenharmony_ci#include <linux/ip.h>
138c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
148c2ecf20Sopenharmony_ci#include <linux/irq.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/phy.h>
178c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
188c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "hnae.h"
218c2ecf20Sopenharmony_ci#include "hns_enet.h"
228c2ecf20Sopenharmony_ci#include "hns_dsaf_mac.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define NIC_MAX_Q_PER_VF 16
258c2ecf20Sopenharmony_ci#define HNS_NIC_TX_TIMEOUT (5 * HZ)
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define SERVICE_TIMER_HZ (1 * HZ)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define RCB_IRQ_NOT_INITED 0
308c2ecf20Sopenharmony_ci#define RCB_IRQ_INITED 1
318c2ecf20Sopenharmony_ci#define HNS_BUFFER_SIZE_2048 2048
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define BD_MAX_SEND_SIZE 8191
348c2ecf20Sopenharmony_ci#define SKB_TMP_LEN(SKB) \
358c2ecf20Sopenharmony_ci	(((SKB)->transport_header - (SKB)->mac_header) + tcp_hdrlen(SKB))
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void fill_v2_desc_hw(struct hnae_ring *ring, void *priv, int size,
388c2ecf20Sopenharmony_ci			    int send_sz, dma_addr_t dma, int frag_end,
398c2ecf20Sopenharmony_ci			    int buf_num, enum hns_desc_type type, int mtu)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct hnae_desc *desc = &ring->desc[ring->next_to_use];
428c2ecf20Sopenharmony_ci	struct hnae_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
438c2ecf20Sopenharmony_ci	struct iphdr *iphdr;
448c2ecf20Sopenharmony_ci	struct ipv6hdr *ipv6hdr;
458c2ecf20Sopenharmony_ci	struct sk_buff *skb;
468c2ecf20Sopenharmony_ci	__be16 protocol;
478c2ecf20Sopenharmony_ci	u8 bn_pid = 0;
488c2ecf20Sopenharmony_ci	u8 rrcfv = 0;
498c2ecf20Sopenharmony_ci	u8 ip_offset = 0;
508c2ecf20Sopenharmony_ci	u8 tvsvsn = 0;
518c2ecf20Sopenharmony_ci	u16 mss = 0;
528c2ecf20Sopenharmony_ci	u8 l4_len = 0;
538c2ecf20Sopenharmony_ci	u16 paylen = 0;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	desc_cb->priv = priv;
568c2ecf20Sopenharmony_ci	desc_cb->length = size;
578c2ecf20Sopenharmony_ci	desc_cb->dma = dma;
588c2ecf20Sopenharmony_ci	desc_cb->type = type;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	desc->addr = cpu_to_le64(dma);
618c2ecf20Sopenharmony_ci	desc->tx.send_size = cpu_to_le16((u16)send_sz);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* config bd buffer end */
648c2ecf20Sopenharmony_ci	hnae_set_bit(rrcfv, HNSV2_TXD_VLD_B, 1);
658c2ecf20Sopenharmony_ci	hnae_set_field(bn_pid, HNSV2_TXD_BUFNUM_M, 0, buf_num - 1);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* fill port_id in the tx bd for sending management pkts */
688c2ecf20Sopenharmony_ci	hnae_set_field(bn_pid, HNSV2_TXD_PORTID_M,
698c2ecf20Sopenharmony_ci		       HNSV2_TXD_PORTID_S, ring->q->handle->dport_id);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	if (type == DESC_TYPE_SKB) {
728c2ecf20Sopenharmony_ci		skb = (struct sk_buff *)priv;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_PARTIAL) {
758c2ecf20Sopenharmony_ci			skb_reset_mac_len(skb);
768c2ecf20Sopenharmony_ci			protocol = skb->protocol;
778c2ecf20Sopenharmony_ci			ip_offset = ETH_HLEN;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci			if (protocol == htons(ETH_P_8021Q)) {
808c2ecf20Sopenharmony_ci				ip_offset += VLAN_HLEN;
818c2ecf20Sopenharmony_ci				protocol = vlan_get_protocol(skb);
828c2ecf20Sopenharmony_ci				skb->protocol = protocol;
838c2ecf20Sopenharmony_ci			}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci			if (skb->protocol == htons(ETH_P_IP)) {
868c2ecf20Sopenharmony_ci				iphdr = ip_hdr(skb);
878c2ecf20Sopenharmony_ci				hnae_set_bit(rrcfv, HNSV2_TXD_L3CS_B, 1);
888c2ecf20Sopenharmony_ci				hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci				/* check for tcp/udp header */
918c2ecf20Sopenharmony_ci				if (iphdr->protocol == IPPROTO_TCP &&
928c2ecf20Sopenharmony_ci				    skb_is_gso(skb)) {
938c2ecf20Sopenharmony_ci					hnae_set_bit(tvsvsn,
948c2ecf20Sopenharmony_ci						     HNSV2_TXD_TSE_B, 1);
958c2ecf20Sopenharmony_ci					l4_len = tcp_hdrlen(skb);
968c2ecf20Sopenharmony_ci					mss = skb_shinfo(skb)->gso_size;
978c2ecf20Sopenharmony_ci					paylen = skb->len - SKB_TMP_LEN(skb);
988c2ecf20Sopenharmony_ci				}
998c2ecf20Sopenharmony_ci			} else if (skb->protocol == htons(ETH_P_IPV6)) {
1008c2ecf20Sopenharmony_ci				hnae_set_bit(tvsvsn, HNSV2_TXD_IPV6_B, 1);
1018c2ecf20Sopenharmony_ci				ipv6hdr = ipv6_hdr(skb);
1028c2ecf20Sopenharmony_ci				hnae_set_bit(rrcfv, HNSV2_TXD_L4CS_B, 1);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci				/* check for tcp/udp header */
1058c2ecf20Sopenharmony_ci				if (ipv6hdr->nexthdr == IPPROTO_TCP &&
1068c2ecf20Sopenharmony_ci				    skb_is_gso(skb) && skb_is_gso_v6(skb)) {
1078c2ecf20Sopenharmony_ci					hnae_set_bit(tvsvsn,
1088c2ecf20Sopenharmony_ci						     HNSV2_TXD_TSE_B, 1);
1098c2ecf20Sopenharmony_ci					l4_len = tcp_hdrlen(skb);
1108c2ecf20Sopenharmony_ci					mss = skb_shinfo(skb)->gso_size;
1118c2ecf20Sopenharmony_ci					paylen = skb->len - SKB_TMP_LEN(skb);
1128c2ecf20Sopenharmony_ci				}
1138c2ecf20Sopenharmony_ci			}
1148c2ecf20Sopenharmony_ci			desc->tx.ip_offset = ip_offset;
1158c2ecf20Sopenharmony_ci			desc->tx.tse_vlan_snap_v6_sctp_nth = tvsvsn;
1168c2ecf20Sopenharmony_ci			desc->tx.mss = cpu_to_le16(mss);
1178c2ecf20Sopenharmony_ci			desc->tx.l4_len = l4_len;
1188c2ecf20Sopenharmony_ci			desc->tx.paylen = cpu_to_le16(paylen);
1198c2ecf20Sopenharmony_ci		}
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	hnae_set_bit(rrcfv, HNSV2_TXD_FE_B, frag_end);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	desc->tx.bn_pid = bn_pid;
1258c2ecf20Sopenharmony_ci	desc->tx.ra_ri_cs_fe_vld = rrcfv;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	ring_ptr_move_fw(ring, next_to_use);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void fill_v2_desc(struct hnae_ring *ring, void *priv,
1318c2ecf20Sopenharmony_ci			 int size, dma_addr_t dma, int frag_end,
1328c2ecf20Sopenharmony_ci			 int buf_num, enum hns_desc_type type, int mtu)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	fill_v2_desc_hw(ring, priv, size, size, dma, frag_end,
1358c2ecf20Sopenharmony_ci			buf_num, type, mtu);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic const struct acpi_device_id hns_enet_acpi_match[] = {
1398c2ecf20Sopenharmony_ci	{ "HISI00C1", 0 },
1408c2ecf20Sopenharmony_ci	{ "HISI00C2", 0 },
1418c2ecf20Sopenharmony_ci	{ },
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, hns_enet_acpi_match);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic void fill_desc(struct hnae_ring *ring, void *priv,
1468c2ecf20Sopenharmony_ci		      int size, dma_addr_t dma, int frag_end,
1478c2ecf20Sopenharmony_ci		      int buf_num, enum hns_desc_type type, int mtu)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	struct hnae_desc *desc = &ring->desc[ring->next_to_use];
1508c2ecf20Sopenharmony_ci	struct hnae_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_use];
1518c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1528c2ecf20Sopenharmony_ci	__be16 protocol;
1538c2ecf20Sopenharmony_ci	u32 ip_offset;
1548c2ecf20Sopenharmony_ci	u32 asid_bufnum_pid = 0;
1558c2ecf20Sopenharmony_ci	u32 flag_ipoffset = 0;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	desc_cb->priv = priv;
1588c2ecf20Sopenharmony_ci	desc_cb->length = size;
1598c2ecf20Sopenharmony_ci	desc_cb->dma = dma;
1608c2ecf20Sopenharmony_ci	desc_cb->type = type;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	desc->addr = cpu_to_le64(dma);
1638c2ecf20Sopenharmony_ci	desc->tx.send_size = cpu_to_le16((u16)size);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/*config bd buffer end */
1668c2ecf20Sopenharmony_ci	flag_ipoffset |= 1 << HNS_TXD_VLD_B;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	asid_bufnum_pid |= buf_num << HNS_TXD_BUFNUM_S;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	if (type == DESC_TYPE_SKB) {
1718c2ecf20Sopenharmony_ci		skb = (struct sk_buff *)priv;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_PARTIAL) {
1748c2ecf20Sopenharmony_ci			protocol = skb->protocol;
1758c2ecf20Sopenharmony_ci			ip_offset = ETH_HLEN;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci			/*if it is a SW VLAN check the next protocol*/
1788c2ecf20Sopenharmony_ci			if (protocol == htons(ETH_P_8021Q)) {
1798c2ecf20Sopenharmony_ci				ip_offset += VLAN_HLEN;
1808c2ecf20Sopenharmony_ci				protocol = vlan_get_protocol(skb);
1818c2ecf20Sopenharmony_ci				skb->protocol = protocol;
1828c2ecf20Sopenharmony_ci			}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci			if (skb->protocol == htons(ETH_P_IP)) {
1858c2ecf20Sopenharmony_ci				flag_ipoffset |= 1 << HNS_TXD_L3CS_B;
1868c2ecf20Sopenharmony_ci				/* check for tcp/udp header */
1878c2ecf20Sopenharmony_ci				flag_ipoffset |= 1 << HNS_TXD_L4CS_B;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci			} else if (skb->protocol == htons(ETH_P_IPV6)) {
1908c2ecf20Sopenharmony_ci				/* ipv6 has not l3 cs, check for L4 header */
1918c2ecf20Sopenharmony_ci				flag_ipoffset |= 1 << HNS_TXD_L4CS_B;
1928c2ecf20Sopenharmony_ci			}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci			flag_ipoffset |= ip_offset << HNS_TXD_IPOFFSET_S;
1958c2ecf20Sopenharmony_ci		}
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	flag_ipoffset |= frag_end << HNS_TXD_FE_B;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	desc->tx.asid_bufnum_pid = cpu_to_le16(asid_bufnum_pid);
2018c2ecf20Sopenharmony_ci	desc->tx.flag_ipoffset = cpu_to_le32(flag_ipoffset);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ring_ptr_move_fw(ring, next_to_use);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic void unfill_desc(struct hnae_ring *ring)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	ring_ptr_move_bw(ring, next_to_use);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int hns_nic_maybe_stop_tx(
2128c2ecf20Sopenharmony_ci	struct sk_buff **out_skb, int *bnum, struct hnae_ring *ring)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct sk_buff *skb = *out_skb;
2158c2ecf20Sopenharmony_ci	struct sk_buff *new_skb = NULL;
2168c2ecf20Sopenharmony_ci	int buf_num;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* no. of segments (plus a header) */
2198c2ecf20Sopenharmony_ci	buf_num = skb_shinfo(skb)->nr_frags + 1;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (unlikely(buf_num > ring->max_desc_num_per_pkt)) {
2228c2ecf20Sopenharmony_ci		if (ring_space(ring) < 1)
2238c2ecf20Sopenharmony_ci			return -EBUSY;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci		new_skb = skb_copy(skb, GFP_ATOMIC);
2268c2ecf20Sopenharmony_ci		if (!new_skb)
2278c2ecf20Sopenharmony_ci			return -ENOMEM;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
2308c2ecf20Sopenharmony_ci		*out_skb = new_skb;
2318c2ecf20Sopenharmony_ci		buf_num = 1;
2328c2ecf20Sopenharmony_ci	} else if (buf_num > ring_space(ring)) {
2338c2ecf20Sopenharmony_ci		return -EBUSY;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	*bnum = buf_num;
2378c2ecf20Sopenharmony_ci	return 0;
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int hns_nic_maybe_stop_tso(
2418c2ecf20Sopenharmony_ci	struct sk_buff **out_skb, int *bnum, struct hnae_ring *ring)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	int i;
2448c2ecf20Sopenharmony_ci	int size;
2458c2ecf20Sopenharmony_ci	int buf_num;
2468c2ecf20Sopenharmony_ci	int frag_num;
2478c2ecf20Sopenharmony_ci	struct sk_buff *skb = *out_skb;
2488c2ecf20Sopenharmony_ci	struct sk_buff *new_skb = NULL;
2498c2ecf20Sopenharmony_ci	skb_frag_t *frag;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	size = skb_headlen(skb);
2528c2ecf20Sopenharmony_ci	buf_num = (size + BD_MAX_SEND_SIZE - 1) / BD_MAX_SEND_SIZE;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	frag_num = skb_shinfo(skb)->nr_frags;
2558c2ecf20Sopenharmony_ci	for (i = 0; i < frag_num; i++) {
2568c2ecf20Sopenharmony_ci		frag = &skb_shinfo(skb)->frags[i];
2578c2ecf20Sopenharmony_ci		size = skb_frag_size(frag);
2588c2ecf20Sopenharmony_ci		buf_num += (size + BD_MAX_SEND_SIZE - 1) / BD_MAX_SEND_SIZE;
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (unlikely(buf_num > ring->max_desc_num_per_pkt)) {
2628c2ecf20Sopenharmony_ci		buf_num = (skb->len + BD_MAX_SEND_SIZE - 1) / BD_MAX_SEND_SIZE;
2638c2ecf20Sopenharmony_ci		if (ring_space(ring) < buf_num)
2648c2ecf20Sopenharmony_ci			return -EBUSY;
2658c2ecf20Sopenharmony_ci		/* manual split the send packet */
2668c2ecf20Sopenharmony_ci		new_skb = skb_copy(skb, GFP_ATOMIC);
2678c2ecf20Sopenharmony_ci		if (!new_skb)
2688c2ecf20Sopenharmony_ci			return -ENOMEM;
2698c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
2708c2ecf20Sopenharmony_ci		*out_skb = new_skb;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	} else if (ring_space(ring) < buf_num) {
2738c2ecf20Sopenharmony_ci		return -EBUSY;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	*bnum = buf_num;
2778c2ecf20Sopenharmony_ci	return 0;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic void fill_tso_desc(struct hnae_ring *ring, void *priv,
2818c2ecf20Sopenharmony_ci			  int size, dma_addr_t dma, int frag_end,
2828c2ecf20Sopenharmony_ci			  int buf_num, enum hns_desc_type type, int mtu)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	int frag_buf_num;
2858c2ecf20Sopenharmony_ci	int sizeoflast;
2868c2ecf20Sopenharmony_ci	int k;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	frag_buf_num = (size + BD_MAX_SEND_SIZE - 1) / BD_MAX_SEND_SIZE;
2898c2ecf20Sopenharmony_ci	sizeoflast = size % BD_MAX_SEND_SIZE;
2908c2ecf20Sopenharmony_ci	sizeoflast = sizeoflast ? sizeoflast : BD_MAX_SEND_SIZE;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* when the frag size is bigger than hardware, split this frag */
2938c2ecf20Sopenharmony_ci	for (k = 0; k < frag_buf_num; k++)
2948c2ecf20Sopenharmony_ci		fill_v2_desc_hw(ring, priv, k == 0 ? size : 0,
2958c2ecf20Sopenharmony_ci				(k == frag_buf_num - 1) ?
2968c2ecf20Sopenharmony_ci					sizeoflast : BD_MAX_SEND_SIZE,
2978c2ecf20Sopenharmony_ci				dma + BD_MAX_SEND_SIZE * k,
2988c2ecf20Sopenharmony_ci				frag_end && (k == frag_buf_num - 1) ? 1 : 0,
2998c2ecf20Sopenharmony_ci				buf_num,
3008c2ecf20Sopenharmony_ci				(type == DESC_TYPE_SKB && !k) ?
3018c2ecf20Sopenharmony_ci					DESC_TYPE_SKB : DESC_TYPE_PAGE,
3028c2ecf20Sopenharmony_ci				mtu);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cinetdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev,
3068c2ecf20Sopenharmony_ci				struct sk_buff *skb,
3078c2ecf20Sopenharmony_ci				struct hns_nic_ring_data *ring_data)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
3108c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
3118c2ecf20Sopenharmony_ci	struct device *dev = ring_to_dev(ring);
3128c2ecf20Sopenharmony_ci	struct netdev_queue *dev_queue;
3138c2ecf20Sopenharmony_ci	skb_frag_t *frag;
3148c2ecf20Sopenharmony_ci	int buf_num;
3158c2ecf20Sopenharmony_ci	int seg_num;
3168c2ecf20Sopenharmony_ci	dma_addr_t dma;
3178c2ecf20Sopenharmony_ci	int size, next_to_use;
3188c2ecf20Sopenharmony_ci	int i;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	switch (priv->ops.maybe_stop_tx(&skb, &buf_num, ring)) {
3218c2ecf20Sopenharmony_ci	case -EBUSY:
3228c2ecf20Sopenharmony_ci		ring->stats.tx_busy++;
3238c2ecf20Sopenharmony_ci		goto out_net_tx_busy;
3248c2ecf20Sopenharmony_ci	case -ENOMEM:
3258c2ecf20Sopenharmony_ci		ring->stats.sw_err_cnt++;
3268c2ecf20Sopenharmony_ci		netdev_err(ndev, "no memory to xmit!\n");
3278c2ecf20Sopenharmony_ci		goto out_err_tx_ok;
3288c2ecf20Sopenharmony_ci	default:
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* no. of segments (plus a header) */
3338c2ecf20Sopenharmony_ci	seg_num = skb_shinfo(skb)->nr_frags + 1;
3348c2ecf20Sopenharmony_ci	next_to_use = ring->next_to_use;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	/* fill the first part */
3378c2ecf20Sopenharmony_ci	size = skb_headlen(skb);
3388c2ecf20Sopenharmony_ci	dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
3398c2ecf20Sopenharmony_ci	if (dma_mapping_error(dev, dma)) {
3408c2ecf20Sopenharmony_ci		netdev_err(ndev, "TX head DMA map failed\n");
3418c2ecf20Sopenharmony_ci		ring->stats.sw_err_cnt++;
3428c2ecf20Sopenharmony_ci		goto out_err_tx_ok;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	priv->ops.fill_desc(ring, skb, size, dma, seg_num == 1 ? 1 : 0,
3458c2ecf20Sopenharmony_ci			    buf_num, DESC_TYPE_SKB, ndev->mtu);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* fill the fragments */
3488c2ecf20Sopenharmony_ci	for (i = 1; i < seg_num; i++) {
3498c2ecf20Sopenharmony_ci		frag = &skb_shinfo(skb)->frags[i - 1];
3508c2ecf20Sopenharmony_ci		size = skb_frag_size(frag);
3518c2ecf20Sopenharmony_ci		dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
3528c2ecf20Sopenharmony_ci		if (dma_mapping_error(dev, dma)) {
3538c2ecf20Sopenharmony_ci			netdev_err(ndev, "TX frag(%d) DMA map failed\n", i);
3548c2ecf20Sopenharmony_ci			ring->stats.sw_err_cnt++;
3558c2ecf20Sopenharmony_ci			goto out_map_frag_fail;
3568c2ecf20Sopenharmony_ci		}
3578c2ecf20Sopenharmony_ci		priv->ops.fill_desc(ring, skb_frag_page(frag), size, dma,
3588c2ecf20Sopenharmony_ci				    seg_num - 1 == i ? 1 : 0, buf_num,
3598c2ecf20Sopenharmony_ci				    DESC_TYPE_PAGE, ndev->mtu);
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	/*complete translate all packets*/
3638c2ecf20Sopenharmony_ci	dev_queue = netdev_get_tx_queue(ndev, skb->queue_mapping);
3648c2ecf20Sopenharmony_ci	netdev_tx_sent_queue(dev_queue, skb->len);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	netif_trans_update(ndev);
3678c2ecf20Sopenharmony_ci	ndev->stats.tx_bytes += skb->len;
3688c2ecf20Sopenharmony_ci	ndev->stats.tx_packets++;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	wmb(); /* commit all data before submit */
3718c2ecf20Sopenharmony_ci	assert(skb->queue_mapping < priv->ae_handle->q_num);
3728c2ecf20Sopenharmony_ci	hnae_queue_xmit(priv->ae_handle->qs[skb->queue_mapping], buf_num);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ciout_map_frag_fail:
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	while (ring->next_to_use != next_to_use) {
3798c2ecf20Sopenharmony_ci		unfill_desc(ring);
3808c2ecf20Sopenharmony_ci		if (ring->next_to_use != next_to_use)
3818c2ecf20Sopenharmony_ci			dma_unmap_page(dev,
3828c2ecf20Sopenharmony_ci				       ring->desc_cb[ring->next_to_use].dma,
3838c2ecf20Sopenharmony_ci				       ring->desc_cb[ring->next_to_use].length,
3848c2ecf20Sopenharmony_ci				       DMA_TO_DEVICE);
3858c2ecf20Sopenharmony_ci		else
3868c2ecf20Sopenharmony_ci			dma_unmap_single(dev,
3878c2ecf20Sopenharmony_ci					 ring->desc_cb[next_to_use].dma,
3888c2ecf20Sopenharmony_ci					 ring->desc_cb[next_to_use].length,
3898c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
3908c2ecf20Sopenharmony_ci	}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ciout_err_tx_ok:
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
3958c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ciout_net_tx_busy:
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	netif_stop_subqueue(ndev, skb->queue_mapping);
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	/* Herbert's original patch had:
4028c2ecf20Sopenharmony_ci	 *  smp_mb__after_netif_stop_queue();
4038c2ecf20Sopenharmony_ci	 * but since that doesn't exist yet, just open code it.
4048c2ecf20Sopenharmony_ci	 */
4058c2ecf20Sopenharmony_ci	smp_mb();
4068c2ecf20Sopenharmony_ci	return NETDEV_TX_BUSY;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic void hns_nic_reuse_page(struct sk_buff *skb, int i,
4108c2ecf20Sopenharmony_ci			       struct hnae_ring *ring, int pull_len,
4118c2ecf20Sopenharmony_ci			       struct hnae_desc_cb *desc_cb)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	struct hnae_desc *desc;
4148c2ecf20Sopenharmony_ci	u32 truesize;
4158c2ecf20Sopenharmony_ci	int size;
4168c2ecf20Sopenharmony_ci	int last_offset;
4178c2ecf20Sopenharmony_ci	bool twobufs;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	twobufs = ((PAGE_SIZE < 8192) &&
4208c2ecf20Sopenharmony_ci		hnae_buf_size(ring) == HNS_BUFFER_SIZE_2048);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	desc = &ring->desc[ring->next_to_clean];
4238c2ecf20Sopenharmony_ci	size = le16_to_cpu(desc->rx.size);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (twobufs) {
4268c2ecf20Sopenharmony_ci		truesize = hnae_buf_size(ring);
4278c2ecf20Sopenharmony_ci	} else {
4288c2ecf20Sopenharmony_ci		truesize = ALIGN(size, L1_CACHE_BYTES);
4298c2ecf20Sopenharmony_ci		last_offset = hnae_page_size(ring) - hnae_buf_size(ring);
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	skb_add_rx_frag(skb, i, desc_cb->priv, desc_cb->page_offset + pull_len,
4338c2ecf20Sopenharmony_ci			size - pull_len, truesize);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	 /* avoid re-using remote pages,flag default unreuse */
4368c2ecf20Sopenharmony_ci	if (unlikely(page_to_nid(desc_cb->priv) != numa_node_id()))
4378c2ecf20Sopenharmony_ci		return;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (twobufs) {
4408c2ecf20Sopenharmony_ci		/* if we are only owner of page we can reuse it */
4418c2ecf20Sopenharmony_ci		if (likely(page_count(desc_cb->priv) == 1)) {
4428c2ecf20Sopenharmony_ci			/* flip page offset to other buffer */
4438c2ecf20Sopenharmony_ci			desc_cb->page_offset ^= truesize;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci			desc_cb->reuse_flag = 1;
4468c2ecf20Sopenharmony_ci			/* bump ref count on page before it is given*/
4478c2ecf20Sopenharmony_ci			get_page(desc_cb->priv);
4488c2ecf20Sopenharmony_ci		}
4498c2ecf20Sopenharmony_ci		return;
4508c2ecf20Sopenharmony_ci	}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* move offset up to the next cache line */
4538c2ecf20Sopenharmony_ci	desc_cb->page_offset += truesize;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (desc_cb->page_offset <= last_offset) {
4568c2ecf20Sopenharmony_ci		desc_cb->reuse_flag = 1;
4578c2ecf20Sopenharmony_ci		/* bump ref count on page before it is given*/
4588c2ecf20Sopenharmony_ci		get_page(desc_cb->priv);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic void get_v2rx_desc_bnum(u32 bnum_flag, int *out_bnum)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	*out_bnum = hnae_get_field(bnum_flag,
4658c2ecf20Sopenharmony_ci				   HNS_RXD_BUFNUM_M, HNS_RXD_BUFNUM_S) + 1;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic void get_rx_desc_bnum(u32 bnum_flag, int *out_bnum)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	*out_bnum = hnae_get_field(bnum_flag,
4718c2ecf20Sopenharmony_ci				   HNS_RXD_BUFNUM_M, HNS_RXD_BUFNUM_S);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic void hns_nic_rx_checksum(struct hns_nic_ring_data *ring_data,
4758c2ecf20Sopenharmony_ci				struct sk_buff *skb, u32 flag)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct net_device *netdev = ring_data->napi.dev;
4788c2ecf20Sopenharmony_ci	u32 l3id;
4798c2ecf20Sopenharmony_ci	u32 l4id;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	/* check if RX checksum offload is enabled */
4828c2ecf20Sopenharmony_ci	if (unlikely(!(netdev->features & NETIF_F_RXCSUM)))
4838c2ecf20Sopenharmony_ci		return;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	/* In hardware, we only support checksum for the following protocols:
4868c2ecf20Sopenharmony_ci	 * 1) IPv4,
4878c2ecf20Sopenharmony_ci	 * 2) TCP(over IPv4 or IPv6),
4888c2ecf20Sopenharmony_ci	 * 3) UDP(over IPv4 or IPv6),
4898c2ecf20Sopenharmony_ci	 * 4) SCTP(over IPv4 or IPv6)
4908c2ecf20Sopenharmony_ci	 * but we support many L3(IPv4, IPv6, MPLS, PPPoE etc) and L4(TCP,
4918c2ecf20Sopenharmony_ci	 * UDP, GRE, SCTP, IGMP, ICMP etc.) protocols.
4928c2ecf20Sopenharmony_ci	 *
4938c2ecf20Sopenharmony_ci	 * Hardware limitation:
4948c2ecf20Sopenharmony_ci	 * Our present hardware RX Descriptor lacks L3/L4 checksum "Status &
4958c2ecf20Sopenharmony_ci	 * Error" bit (which usually can be used to indicate whether checksum
4968c2ecf20Sopenharmony_ci	 * was calculated by the hardware and if there was any error encountered
4978c2ecf20Sopenharmony_ci	 * during checksum calculation).
4988c2ecf20Sopenharmony_ci	 *
4998c2ecf20Sopenharmony_ci	 * Software workaround:
5008c2ecf20Sopenharmony_ci	 * We do get info within the RX descriptor about the kind of L3/L4
5018c2ecf20Sopenharmony_ci	 * protocol coming in the packet and the error status. These errors
5028c2ecf20Sopenharmony_ci	 * might not just be checksum errors but could be related to version,
5038c2ecf20Sopenharmony_ci	 * length of IPv4, UDP, TCP etc.
5048c2ecf20Sopenharmony_ci	 * Because there is no-way of knowing if it is a L3/L4 error due to bad
5058c2ecf20Sopenharmony_ci	 * checksum or any other L3/L4 error, we will not (cannot) convey
5068c2ecf20Sopenharmony_ci	 * checksum status for such cases to upper stack and will not maintain
5078c2ecf20Sopenharmony_ci	 * the RX L3/L4 checksum counters as well.
5088c2ecf20Sopenharmony_ci	 */
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	l3id = hnae_get_field(flag, HNS_RXD_L3ID_M, HNS_RXD_L3ID_S);
5118c2ecf20Sopenharmony_ci	l4id = hnae_get_field(flag, HNS_RXD_L4ID_M, HNS_RXD_L4ID_S);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci	/*  check L3 protocol for which checksum is supported */
5148c2ecf20Sopenharmony_ci	if ((l3id != HNS_RX_FLAG_L3ID_IPV4) && (l3id != HNS_RX_FLAG_L3ID_IPV6))
5158c2ecf20Sopenharmony_ci		return;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* check for any(not just checksum)flagged L3 protocol errors */
5188c2ecf20Sopenharmony_ci	if (unlikely(hnae_get_bit(flag, HNS_RXD_L3E_B)))
5198c2ecf20Sopenharmony_ci		return;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* we do not support checksum of fragmented packets */
5228c2ecf20Sopenharmony_ci	if (unlikely(hnae_get_bit(flag, HNS_RXD_FRAG_B)))
5238c2ecf20Sopenharmony_ci		return;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	/*  check L4 protocol for which checksum is supported */
5268c2ecf20Sopenharmony_ci	if ((l4id != HNS_RX_FLAG_L4ID_TCP) &&
5278c2ecf20Sopenharmony_ci	    (l4id != HNS_RX_FLAG_L4ID_UDP) &&
5288c2ecf20Sopenharmony_ci	    (l4id != HNS_RX_FLAG_L4ID_SCTP))
5298c2ecf20Sopenharmony_ci		return;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	/* check for any(not just checksum)flagged L4 protocol errors */
5328c2ecf20Sopenharmony_ci	if (unlikely(hnae_get_bit(flag, HNS_RXD_L4E_B)))
5338c2ecf20Sopenharmony_ci		return;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* now, this has to be a packet with valid RX checksum */
5368c2ecf20Sopenharmony_ci	skb->ip_summed = CHECKSUM_UNNECESSARY;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic int hns_nic_poll_rx_skb(struct hns_nic_ring_data *ring_data,
5408c2ecf20Sopenharmony_ci			       struct sk_buff **out_skb, int *out_bnum)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
5438c2ecf20Sopenharmony_ci	struct net_device *ndev = ring_data->napi.dev;
5448c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
5458c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5468c2ecf20Sopenharmony_ci	struct hnae_desc *desc;
5478c2ecf20Sopenharmony_ci	struct hnae_desc_cb *desc_cb;
5488c2ecf20Sopenharmony_ci	unsigned char *va;
5498c2ecf20Sopenharmony_ci	int bnum, length, i;
5508c2ecf20Sopenharmony_ci	int pull_len;
5518c2ecf20Sopenharmony_ci	u32 bnum_flag;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	desc = &ring->desc[ring->next_to_clean];
5548c2ecf20Sopenharmony_ci	desc_cb = &ring->desc_cb[ring->next_to_clean];
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	prefetch(desc);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	va = (unsigned char *)desc_cb->buf + desc_cb->page_offset;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/* prefetch first cache line of first page */
5618c2ecf20Sopenharmony_ci	net_prefetch(va);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	skb = *out_skb = napi_alloc_skb(&ring_data->napi,
5648c2ecf20Sopenharmony_ci					HNS_RX_HEAD_SIZE);
5658c2ecf20Sopenharmony_ci	if (unlikely(!skb)) {
5668c2ecf20Sopenharmony_ci		ring->stats.sw_err_cnt++;
5678c2ecf20Sopenharmony_ci		return -ENOMEM;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	prefetchw(skb->data);
5718c2ecf20Sopenharmony_ci	length = le16_to_cpu(desc->rx.pkt_len);
5728c2ecf20Sopenharmony_ci	bnum_flag = le32_to_cpu(desc->rx.ipoff_bnum_pid_flag);
5738c2ecf20Sopenharmony_ci	priv->ops.get_rxd_bnum(bnum_flag, &bnum);
5748c2ecf20Sopenharmony_ci	*out_bnum = bnum;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (length <= HNS_RX_HEAD_SIZE) {
5778c2ecf20Sopenharmony_ci		memcpy(__skb_put(skb, length), va, ALIGN(length, sizeof(long)));
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		/* we can reuse buffer as-is, just make sure it is local */
5808c2ecf20Sopenharmony_ci		if (likely(page_to_nid(desc_cb->priv) == numa_node_id()))
5818c2ecf20Sopenharmony_ci			desc_cb->reuse_flag = 1;
5828c2ecf20Sopenharmony_ci		else /* this page cannot be reused so discard it */
5838c2ecf20Sopenharmony_ci			put_page(desc_cb->priv);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		ring_ptr_move_fw(ring, next_to_clean);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		if (unlikely(bnum != 1)) { /* check err*/
5888c2ecf20Sopenharmony_ci			*out_bnum = 1;
5898c2ecf20Sopenharmony_ci			goto out_bnum_err;
5908c2ecf20Sopenharmony_ci		}
5918c2ecf20Sopenharmony_ci	} else {
5928c2ecf20Sopenharmony_ci		ring->stats.seg_pkt_cnt++;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci		pull_len = eth_get_headlen(ndev, va, HNS_RX_HEAD_SIZE);
5958c2ecf20Sopenharmony_ci		memcpy(__skb_put(skb, pull_len), va,
5968c2ecf20Sopenharmony_ci		       ALIGN(pull_len, sizeof(long)));
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci		hns_nic_reuse_page(skb, 0, ring, pull_len, desc_cb);
5998c2ecf20Sopenharmony_ci		ring_ptr_move_fw(ring, next_to_clean);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci		if (unlikely(bnum >= (int)MAX_SKB_FRAGS)) { /* check err*/
6028c2ecf20Sopenharmony_ci			*out_bnum = 1;
6038c2ecf20Sopenharmony_ci			goto out_bnum_err;
6048c2ecf20Sopenharmony_ci		}
6058c2ecf20Sopenharmony_ci		for (i = 1; i < bnum; i++) {
6068c2ecf20Sopenharmony_ci			desc = &ring->desc[ring->next_to_clean];
6078c2ecf20Sopenharmony_ci			desc_cb = &ring->desc_cb[ring->next_to_clean];
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci			hns_nic_reuse_page(skb, i, ring, 0, desc_cb);
6108c2ecf20Sopenharmony_ci			ring_ptr_move_fw(ring, next_to_clean);
6118c2ecf20Sopenharmony_ci		}
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	/* check except process, free skb and jump the desc */
6158c2ecf20Sopenharmony_ci	if (unlikely((!bnum) || (bnum > ring->max_desc_num_per_pkt))) {
6168c2ecf20Sopenharmony_ciout_bnum_err:
6178c2ecf20Sopenharmony_ci		*out_bnum = *out_bnum ? *out_bnum : 1; /* ntc moved,cannot 0*/
6188c2ecf20Sopenharmony_ci		netdev_err(ndev, "invalid bnum(%d,%d,%d,%d),%016llx,%016llx\n",
6198c2ecf20Sopenharmony_ci			   bnum, ring->max_desc_num_per_pkt,
6208c2ecf20Sopenharmony_ci			   length, (int)MAX_SKB_FRAGS,
6218c2ecf20Sopenharmony_ci			   ((u64 *)desc)[0], ((u64 *)desc)[1]);
6228c2ecf20Sopenharmony_ci		ring->stats.err_bd_num++;
6238c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
6248c2ecf20Sopenharmony_ci		return -EDOM;
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	bnum_flag = le32_to_cpu(desc->rx.ipoff_bnum_pid_flag);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (unlikely(!hnae_get_bit(bnum_flag, HNS_RXD_VLD_B))) {
6308c2ecf20Sopenharmony_ci		netdev_err(ndev, "no valid bd,%016llx,%016llx\n",
6318c2ecf20Sopenharmony_ci			   ((u64 *)desc)[0], ((u64 *)desc)[1]);
6328c2ecf20Sopenharmony_ci		ring->stats.non_vld_descs++;
6338c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
6348c2ecf20Sopenharmony_ci		return -EINVAL;
6358c2ecf20Sopenharmony_ci	}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	if (unlikely((!desc->rx.pkt_len) ||
6388c2ecf20Sopenharmony_ci		     hnae_get_bit(bnum_flag, HNS_RXD_DROP_B))) {
6398c2ecf20Sopenharmony_ci		ring->stats.err_pkt_len++;
6408c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
6418c2ecf20Sopenharmony_ci		return -EFAULT;
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	if (unlikely(hnae_get_bit(bnum_flag, HNS_RXD_L2E_B))) {
6458c2ecf20Sopenharmony_ci		ring->stats.l2_err++;
6468c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
6478c2ecf20Sopenharmony_ci		return -EFAULT;
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	ring->stats.rx_pkts++;
6518c2ecf20Sopenharmony_ci	ring->stats.rx_bytes += skb->len;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	/* indicate to upper stack if our hardware has already calculated
6548c2ecf20Sopenharmony_ci	 * the RX checksum
6558c2ecf20Sopenharmony_ci	 */
6568c2ecf20Sopenharmony_ci	hns_nic_rx_checksum(ring_data, skb, bnum_flag);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	return 0;
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic void
6628c2ecf20Sopenharmony_cihns_nic_alloc_rx_buffers(struct hns_nic_ring_data *ring_data, int cleand_count)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	int i, ret;
6658c2ecf20Sopenharmony_ci	struct hnae_desc_cb res_cbs;
6668c2ecf20Sopenharmony_ci	struct hnae_desc_cb *desc_cb;
6678c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
6688c2ecf20Sopenharmony_ci	struct net_device *ndev = ring_data->napi.dev;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	for (i = 0; i < cleand_count; i++) {
6718c2ecf20Sopenharmony_ci		desc_cb = &ring->desc_cb[ring->next_to_use];
6728c2ecf20Sopenharmony_ci		if (desc_cb->reuse_flag) {
6738c2ecf20Sopenharmony_ci			ring->stats.reuse_pg_cnt++;
6748c2ecf20Sopenharmony_ci			hnae_reuse_buffer(ring, ring->next_to_use);
6758c2ecf20Sopenharmony_ci		} else {
6768c2ecf20Sopenharmony_ci			ret = hnae_reserve_buffer_map(ring, &res_cbs);
6778c2ecf20Sopenharmony_ci			if (ret) {
6788c2ecf20Sopenharmony_ci				ring->stats.sw_err_cnt++;
6798c2ecf20Sopenharmony_ci				netdev_err(ndev, "hnae reserve buffer map failed.\n");
6808c2ecf20Sopenharmony_ci				break;
6818c2ecf20Sopenharmony_ci			}
6828c2ecf20Sopenharmony_ci			hnae_replace_buffer(ring, ring->next_to_use, &res_cbs);
6838c2ecf20Sopenharmony_ci		}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		ring_ptr_move_fw(ring, next_to_use);
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	wmb(); /* make all data has been write before submit */
6898c2ecf20Sopenharmony_ci	writel_relaxed(i, ring->io_base + RCB_REG_HEAD);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci/* return error number for error or number of desc left to take
6938c2ecf20Sopenharmony_ci */
6948c2ecf20Sopenharmony_cistatic void hns_nic_rx_up_pro(struct hns_nic_ring_data *ring_data,
6958c2ecf20Sopenharmony_ci			      struct sk_buff *skb)
6968c2ecf20Sopenharmony_ci{
6978c2ecf20Sopenharmony_ci	struct net_device *ndev = ring_data->napi.dev;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	skb->protocol = eth_type_trans(skb, ndev);
7008c2ecf20Sopenharmony_ci	napi_gro_receive(&ring_data->napi, skb);
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic int hns_desc_unused(struct hnae_ring *ring)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	int ntc = ring->next_to_clean;
7068c2ecf20Sopenharmony_ci	int ntu = ring->next_to_use;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	return ((ntc >= ntu) ? 0 : ring->desc_num) + ntc - ntu;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci#define HNS_LOWEST_LATENCY_RATE		27	/* 27 MB/s */
7128c2ecf20Sopenharmony_ci#define HNS_LOW_LATENCY_RATE			80	/* 80 MB/s */
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci#define HNS_COAL_BDNUM			3
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic u32 hns_coal_rx_bdnum(struct hnae_ring *ring)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	bool coal_enable = ring->q->handle->coal_adapt_en;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (coal_enable &&
7218c2ecf20Sopenharmony_ci	    ring->coal_last_rx_bytes > HNS_LOWEST_LATENCY_RATE)
7228c2ecf20Sopenharmony_ci		return HNS_COAL_BDNUM;
7238c2ecf20Sopenharmony_ci	else
7248c2ecf20Sopenharmony_ci		return 0;
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic void hns_update_rx_rate(struct hnae_ring *ring)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	bool coal_enable = ring->q->handle->coal_adapt_en;
7308c2ecf20Sopenharmony_ci	u32 time_passed_ms;
7318c2ecf20Sopenharmony_ci	u64 total_bytes;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	if (!coal_enable ||
7348c2ecf20Sopenharmony_ci	    time_before(jiffies, ring->coal_last_jiffies + (HZ >> 4)))
7358c2ecf20Sopenharmony_ci		return;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	/* ring->stats.rx_bytes overflowed */
7388c2ecf20Sopenharmony_ci	if (ring->coal_last_rx_bytes > ring->stats.rx_bytes) {
7398c2ecf20Sopenharmony_ci		ring->coal_last_rx_bytes = ring->stats.rx_bytes;
7408c2ecf20Sopenharmony_ci		ring->coal_last_jiffies = jiffies;
7418c2ecf20Sopenharmony_ci		return;
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	total_bytes = ring->stats.rx_bytes - ring->coal_last_rx_bytes;
7458c2ecf20Sopenharmony_ci	time_passed_ms = jiffies_to_msecs(jiffies - ring->coal_last_jiffies);
7468c2ecf20Sopenharmony_ci	do_div(total_bytes, time_passed_ms);
7478c2ecf20Sopenharmony_ci	ring->coal_rx_rate = total_bytes >> 10;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	ring->coal_last_rx_bytes = ring->stats.rx_bytes;
7508c2ecf20Sopenharmony_ci	ring->coal_last_jiffies = jiffies;
7518c2ecf20Sopenharmony_ci}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci/**
7548c2ecf20Sopenharmony_ci * smooth_alg - smoothing algrithm for adjusting coalesce parameter
7558c2ecf20Sopenharmony_ci * @new_param: new value
7568c2ecf20Sopenharmony_ci * @old_param: old value
7578c2ecf20Sopenharmony_ci **/
7588c2ecf20Sopenharmony_cistatic u32 smooth_alg(u32 new_param, u32 old_param)
7598c2ecf20Sopenharmony_ci{
7608c2ecf20Sopenharmony_ci	u32 gap = (new_param > old_param) ? new_param - old_param
7618c2ecf20Sopenharmony_ci					  : old_param - new_param;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	if (gap > 8)
7648c2ecf20Sopenharmony_ci		gap >>= 3;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	if (new_param > old_param)
7678c2ecf20Sopenharmony_ci		return old_param + gap;
7688c2ecf20Sopenharmony_ci	else
7698c2ecf20Sopenharmony_ci		return old_param - gap;
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci/**
7738c2ecf20Sopenharmony_ci * hns_nic_adp_coalesce - self adapte coalesce according to rx rate
7748c2ecf20Sopenharmony_ci * @ring_data: pointer to hns_nic_ring_data
7758c2ecf20Sopenharmony_ci **/
7768c2ecf20Sopenharmony_cistatic void hns_nic_adpt_coalesce(struct hns_nic_ring_data *ring_data)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
7798c2ecf20Sopenharmony_ci	struct hnae_handle *handle = ring->q->handle;
7808c2ecf20Sopenharmony_ci	u32 new_coal_param, old_coal_param = ring->coal_param;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (ring->coal_rx_rate < HNS_LOWEST_LATENCY_RATE)
7838c2ecf20Sopenharmony_ci		new_coal_param = HNAE_LOWEST_LATENCY_COAL_PARAM;
7848c2ecf20Sopenharmony_ci	else if (ring->coal_rx_rate < HNS_LOW_LATENCY_RATE)
7858c2ecf20Sopenharmony_ci		new_coal_param = HNAE_LOW_LATENCY_COAL_PARAM;
7868c2ecf20Sopenharmony_ci	else
7878c2ecf20Sopenharmony_ci		new_coal_param = HNAE_BULK_LATENCY_COAL_PARAM;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	if (new_coal_param == old_coal_param &&
7908c2ecf20Sopenharmony_ci	    new_coal_param == handle->coal_param)
7918c2ecf20Sopenharmony_ci		return;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	new_coal_param = smooth_alg(new_coal_param, old_coal_param);
7948c2ecf20Sopenharmony_ci	ring->coal_param = new_coal_param;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/**
7978c2ecf20Sopenharmony_ci	 * Because all ring in one port has one coalesce param, when one ring
7988c2ecf20Sopenharmony_ci	 * calculate its own coalesce param, it cannot write to hardware at
7998c2ecf20Sopenharmony_ci	 * once. There are three conditions as follows:
8008c2ecf20Sopenharmony_ci	 *       1. current ring's coalesce param is larger than the hardware.
8018c2ecf20Sopenharmony_ci	 *       2. or ring which adapt last time can change again.
8028c2ecf20Sopenharmony_ci	 *       3. timeout.
8038c2ecf20Sopenharmony_ci	 */
8048c2ecf20Sopenharmony_ci	if (new_coal_param == handle->coal_param) {
8058c2ecf20Sopenharmony_ci		handle->coal_last_jiffies = jiffies;
8068c2ecf20Sopenharmony_ci		handle->coal_ring_idx = ring_data->queue_index;
8078c2ecf20Sopenharmony_ci	} else if (new_coal_param > handle->coal_param ||
8088c2ecf20Sopenharmony_ci		   handle->coal_ring_idx == ring_data->queue_index ||
8098c2ecf20Sopenharmony_ci		   time_after(jiffies, handle->coal_last_jiffies + (HZ >> 4))) {
8108c2ecf20Sopenharmony_ci		handle->dev->ops->set_coalesce_usecs(handle,
8118c2ecf20Sopenharmony_ci					new_coal_param);
8128c2ecf20Sopenharmony_ci		handle->dev->ops->set_coalesce_frames(handle,
8138c2ecf20Sopenharmony_ci					1, new_coal_param);
8148c2ecf20Sopenharmony_ci		handle->coal_param = new_coal_param;
8158c2ecf20Sopenharmony_ci		handle->coal_ring_idx = ring_data->queue_index;
8168c2ecf20Sopenharmony_ci		handle->coal_last_jiffies = jiffies;
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic int hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data,
8218c2ecf20Sopenharmony_ci			       int budget, void *v)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
8248c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8258c2ecf20Sopenharmony_ci	int num, bnum;
8268c2ecf20Sopenharmony_ci#define RCB_NOF_ALLOC_RX_BUFF_ONCE 16
8278c2ecf20Sopenharmony_ci	int recv_pkts, recv_bds, clean_count, err;
8288c2ecf20Sopenharmony_ci	int unused_count = hns_desc_unused(ring);
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
8318c2ecf20Sopenharmony_ci	rmb(); /* make sure num taken effect before the other data is touched */
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	recv_pkts = 0, recv_bds = 0, clean_count = 0;
8348c2ecf20Sopenharmony_ci	num -= unused_count;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	while (recv_pkts < budget && recv_bds < num) {
8378c2ecf20Sopenharmony_ci		/* reuse or realloc buffers */
8388c2ecf20Sopenharmony_ci		if (clean_count + unused_count >= RCB_NOF_ALLOC_RX_BUFF_ONCE) {
8398c2ecf20Sopenharmony_ci			hns_nic_alloc_rx_buffers(ring_data,
8408c2ecf20Sopenharmony_ci						 clean_count + unused_count);
8418c2ecf20Sopenharmony_ci			clean_count = 0;
8428c2ecf20Sopenharmony_ci			unused_count = hns_desc_unused(ring);
8438c2ecf20Sopenharmony_ci		}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		/* poll one pkt */
8468c2ecf20Sopenharmony_ci		err = hns_nic_poll_rx_skb(ring_data, &skb, &bnum);
8478c2ecf20Sopenharmony_ci		if (unlikely(!skb)) /* this fault cannot be repaired */
8488c2ecf20Sopenharmony_ci			goto out;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci		recv_bds += bnum;
8518c2ecf20Sopenharmony_ci		clean_count += bnum;
8528c2ecf20Sopenharmony_ci		if (unlikely(err)) {  /* do jump the err */
8538c2ecf20Sopenharmony_ci			recv_pkts++;
8548c2ecf20Sopenharmony_ci			continue;
8558c2ecf20Sopenharmony_ci		}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci		/* do update ip stack process*/
8588c2ecf20Sopenharmony_ci		((void (*)(struct hns_nic_ring_data *, struct sk_buff *))v)(
8598c2ecf20Sopenharmony_ci							ring_data, skb);
8608c2ecf20Sopenharmony_ci		recv_pkts++;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ciout:
8648c2ecf20Sopenharmony_ci	/* make all data has been write before submit */
8658c2ecf20Sopenharmony_ci	if (clean_count + unused_count > 0)
8668c2ecf20Sopenharmony_ci		hns_nic_alloc_rx_buffers(ring_data,
8678c2ecf20Sopenharmony_ci					 clean_count + unused_count);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	return recv_pkts;
8708c2ecf20Sopenharmony_ci}
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_cistatic bool hns_nic_rx_fini_pro(struct hns_nic_ring_data *ring_data)
8738c2ecf20Sopenharmony_ci{
8748c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
8758c2ecf20Sopenharmony_ci	int num = 0;
8768c2ecf20Sopenharmony_ci	bool rx_stopped;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	hns_update_rx_rate(ring);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	/* for hardware bug fixed */
8818c2ecf20Sopenharmony_ci	ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
8828c2ecf20Sopenharmony_ci	num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	if (num <= hns_coal_rx_bdnum(ring)) {
8858c2ecf20Sopenharmony_ci		if (ring->q->handle->coal_adapt_en)
8868c2ecf20Sopenharmony_ci			hns_nic_adpt_coalesce(ring_data);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci		rx_stopped = true;
8898c2ecf20Sopenharmony_ci	} else {
8908c2ecf20Sopenharmony_ci		ring_data->ring->q->handle->dev->ops->toggle_ring_irq(
8918c2ecf20Sopenharmony_ci			ring_data->ring, 1);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		rx_stopped = false;
8948c2ecf20Sopenharmony_ci	}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	return rx_stopped;
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic bool hns_nic_rx_fini_pro_v2(struct hns_nic_ring_data *ring_data)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
9028c2ecf20Sopenharmony_ci	int num;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	hns_update_rx_rate(ring);
9058c2ecf20Sopenharmony_ci	num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	if (num <= hns_coal_rx_bdnum(ring)) {
9088c2ecf20Sopenharmony_ci		if (ring->q->handle->coal_adapt_en)
9098c2ecf20Sopenharmony_ci			hns_nic_adpt_coalesce(ring_data);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci		return true;
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return false;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic inline void hns_nic_reclaim_one_desc(struct hnae_ring *ring,
9188c2ecf20Sopenharmony_ci					    int *bytes, int *pkts)
9198c2ecf20Sopenharmony_ci{
9208c2ecf20Sopenharmony_ci	struct hnae_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_clean];
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	(*pkts) += (desc_cb->type == DESC_TYPE_SKB);
9238c2ecf20Sopenharmony_ci	(*bytes) += desc_cb->length;
9248c2ecf20Sopenharmony_ci	/* desc_cb will be cleaned, after hnae_free_buffer_detach*/
9258c2ecf20Sopenharmony_ci	hnae_free_buffer_detach(ring, ring->next_to_clean);
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	ring_ptr_move_fw(ring, next_to_clean);
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_cistatic int is_valid_clean_head(struct hnae_ring *ring, int h)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	int u = ring->next_to_use;
9338c2ecf20Sopenharmony_ci	int c = ring->next_to_clean;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	if (unlikely(h > ring->desc_num))
9368c2ecf20Sopenharmony_ci		return 0;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	assert(u > 0 && u < ring->desc_num);
9398c2ecf20Sopenharmony_ci	assert(c > 0 && c < ring->desc_num);
9408c2ecf20Sopenharmony_ci	assert(u != c && h != c); /* must be checked before call this func */
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	return u > c ? (h > c && h <= u) : (h > c || h <= u);
9438c2ecf20Sopenharmony_ci}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci/* reclaim all desc in one budget
9468c2ecf20Sopenharmony_ci * return error or number of desc left
9478c2ecf20Sopenharmony_ci */
9488c2ecf20Sopenharmony_cistatic int hns_nic_tx_poll_one(struct hns_nic_ring_data *ring_data,
9498c2ecf20Sopenharmony_ci			       int budget, void *v)
9508c2ecf20Sopenharmony_ci{
9518c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
9528c2ecf20Sopenharmony_ci	struct net_device *ndev = ring_data->napi.dev;
9538c2ecf20Sopenharmony_ci	struct netdev_queue *dev_queue;
9548c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
9558c2ecf20Sopenharmony_ci	int head;
9568c2ecf20Sopenharmony_ci	int bytes, pkts;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	head = readl_relaxed(ring->io_base + RCB_REG_HEAD);
9598c2ecf20Sopenharmony_ci	rmb(); /* make sure head is ready before touch any data */
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (is_ring_empty(ring) || head == ring->next_to_clean)
9628c2ecf20Sopenharmony_ci		return 0; /* no data to poll */
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	if (!is_valid_clean_head(ring, head)) {
9658c2ecf20Sopenharmony_ci		netdev_err(ndev, "wrong head (%d, %d-%d)\n", head,
9668c2ecf20Sopenharmony_ci			   ring->next_to_use, ring->next_to_clean);
9678c2ecf20Sopenharmony_ci		ring->stats.io_err_cnt++;
9688c2ecf20Sopenharmony_ci		return -EIO;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	bytes = 0;
9728c2ecf20Sopenharmony_ci	pkts = 0;
9738c2ecf20Sopenharmony_ci	while (head != ring->next_to_clean) {
9748c2ecf20Sopenharmony_ci		hns_nic_reclaim_one_desc(ring, &bytes, &pkts);
9758c2ecf20Sopenharmony_ci		/* issue prefetch for next Tx descriptor */
9768c2ecf20Sopenharmony_ci		prefetch(&ring->desc_cb[ring->next_to_clean]);
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci	/* update tx ring statistics. */
9798c2ecf20Sopenharmony_ci	ring->stats.tx_pkts += pkts;
9808c2ecf20Sopenharmony_ci	ring->stats.tx_bytes += bytes;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	dev_queue = netdev_get_tx_queue(ndev, ring_data->queue_index);
9838c2ecf20Sopenharmony_ci	netdev_tx_completed_queue(dev_queue, pkts, bytes);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (unlikely(priv->link && !netif_carrier_ok(ndev)))
9868c2ecf20Sopenharmony_ci		netif_carrier_on(ndev);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	if (unlikely(pkts && netif_carrier_ok(ndev) &&
9898c2ecf20Sopenharmony_ci		     (ring_space(ring) >= ring->max_desc_num_per_pkt * 2))) {
9908c2ecf20Sopenharmony_ci		/* Make sure that anybody stopping the queue after this
9918c2ecf20Sopenharmony_ci		 * sees the new next_to_clean.
9928c2ecf20Sopenharmony_ci		 */
9938c2ecf20Sopenharmony_ci		smp_mb();
9948c2ecf20Sopenharmony_ci		if (netif_tx_queue_stopped(dev_queue) &&
9958c2ecf20Sopenharmony_ci		    !test_bit(NIC_STATE_DOWN, &priv->state)) {
9968c2ecf20Sopenharmony_ci			netif_tx_wake_queue(dev_queue);
9978c2ecf20Sopenharmony_ci			ring->stats.restart_queue++;
9988c2ecf20Sopenharmony_ci		}
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci	return 0;
10018c2ecf20Sopenharmony_ci}
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic bool hns_nic_tx_fini_pro(struct hns_nic_ring_data *ring_data)
10048c2ecf20Sopenharmony_ci{
10058c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
10068c2ecf20Sopenharmony_ci	int head;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	ring_data->ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	head = readl_relaxed(ring->io_base + RCB_REG_HEAD);
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	if (head != ring->next_to_clean) {
10138c2ecf20Sopenharmony_ci		ring_data->ring->q->handle->dev->ops->toggle_ring_irq(
10148c2ecf20Sopenharmony_ci			ring_data->ring, 1);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci		return false;
10178c2ecf20Sopenharmony_ci	} else {
10188c2ecf20Sopenharmony_ci		return true;
10198c2ecf20Sopenharmony_ci	}
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic bool hns_nic_tx_fini_pro_v2(struct hns_nic_ring_data *ring_data)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
10258c2ecf20Sopenharmony_ci	int head = readl_relaxed(ring->io_base + RCB_REG_HEAD);
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci	if (head == ring->next_to_clean)
10288c2ecf20Sopenharmony_ci		return true;
10298c2ecf20Sopenharmony_ci	else
10308c2ecf20Sopenharmony_ci		return false;
10318c2ecf20Sopenharmony_ci}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_cistatic void hns_nic_tx_clr_all_bufs(struct hns_nic_ring_data *ring_data)
10348c2ecf20Sopenharmony_ci{
10358c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
10368c2ecf20Sopenharmony_ci	struct net_device *ndev = ring_data->napi.dev;
10378c2ecf20Sopenharmony_ci	struct netdev_queue *dev_queue;
10388c2ecf20Sopenharmony_ci	int head;
10398c2ecf20Sopenharmony_ci	int bytes, pkts;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	head = ring->next_to_use; /* ntu :soft setted ring position*/
10428c2ecf20Sopenharmony_ci	bytes = 0;
10438c2ecf20Sopenharmony_ci	pkts = 0;
10448c2ecf20Sopenharmony_ci	while (head != ring->next_to_clean)
10458c2ecf20Sopenharmony_ci		hns_nic_reclaim_one_desc(ring, &bytes, &pkts);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	dev_queue = netdev_get_tx_queue(ndev, ring_data->queue_index);
10488c2ecf20Sopenharmony_ci	netdev_tx_reset_queue(dev_queue);
10498c2ecf20Sopenharmony_ci}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_cistatic int hns_nic_common_poll(struct napi_struct *napi, int budget)
10528c2ecf20Sopenharmony_ci{
10538c2ecf20Sopenharmony_ci	int clean_complete = 0;
10548c2ecf20Sopenharmony_ci	struct hns_nic_ring_data *ring_data =
10558c2ecf20Sopenharmony_ci		container_of(napi, struct hns_nic_ring_data, napi);
10568c2ecf20Sopenharmony_ci	struct hnae_ring *ring = ring_data->ring;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	clean_complete += ring_data->poll_one(
10598c2ecf20Sopenharmony_ci				ring_data, budget - clean_complete,
10608c2ecf20Sopenharmony_ci				ring_data->ex_process);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	if (clean_complete < budget) {
10638c2ecf20Sopenharmony_ci		if (ring_data->fini_process(ring_data)) {
10648c2ecf20Sopenharmony_ci			napi_complete(napi);
10658c2ecf20Sopenharmony_ci			ring->q->handle->dev->ops->toggle_ring_irq(ring, 0);
10668c2ecf20Sopenharmony_ci		} else {
10678c2ecf20Sopenharmony_ci			return budget;
10688c2ecf20Sopenharmony_ci		}
10698c2ecf20Sopenharmony_ci	}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	return clean_complete;
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_cistatic irqreturn_t hns_irq_handle(int irq, void *dev)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	struct hns_nic_ring_data *ring_data = (struct hns_nic_ring_data *)dev;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	ring_data->ring->q->handle->dev->ops->toggle_ring_irq(
10798c2ecf20Sopenharmony_ci		ring_data->ring, 1);
10808c2ecf20Sopenharmony_ci	napi_schedule(&ring_data->napi);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
10838c2ecf20Sopenharmony_ci}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci/**
10868c2ecf20Sopenharmony_ci *hns_nic_adjust_link - adjust net work mode by the phy stat or new param
10878c2ecf20Sopenharmony_ci *@ndev: net device
10888c2ecf20Sopenharmony_ci */
10898c2ecf20Sopenharmony_cistatic void hns_nic_adjust_link(struct net_device *ndev)
10908c2ecf20Sopenharmony_ci{
10918c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
10928c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
10938c2ecf20Sopenharmony_ci	int state = 1;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	/* If there is no phy, do not need adjust link */
10968c2ecf20Sopenharmony_ci	if (ndev->phydev) {
10978c2ecf20Sopenharmony_ci		/* When phy link down, do nothing */
10988c2ecf20Sopenharmony_ci		if (ndev->phydev->link == 0)
10998c2ecf20Sopenharmony_ci			return;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci		if (h->dev->ops->need_adjust_link(h, ndev->phydev->speed,
11028c2ecf20Sopenharmony_ci						  ndev->phydev->duplex)) {
11038c2ecf20Sopenharmony_ci			/* because Hi161X chip don't support to change gmac
11048c2ecf20Sopenharmony_ci			 * speed and duplex with traffic. Delay 200ms to
11058c2ecf20Sopenharmony_ci			 * make sure there is no more data in chip FIFO.
11068c2ecf20Sopenharmony_ci			 */
11078c2ecf20Sopenharmony_ci			netif_carrier_off(ndev);
11088c2ecf20Sopenharmony_ci			msleep(200);
11098c2ecf20Sopenharmony_ci			h->dev->ops->adjust_link(h, ndev->phydev->speed,
11108c2ecf20Sopenharmony_ci						 ndev->phydev->duplex);
11118c2ecf20Sopenharmony_ci			netif_carrier_on(ndev);
11128c2ecf20Sopenharmony_ci		}
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	state = state && h->dev->ops->get_status(h);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	if (state != priv->link) {
11188c2ecf20Sopenharmony_ci		if (state) {
11198c2ecf20Sopenharmony_ci			netif_carrier_on(ndev);
11208c2ecf20Sopenharmony_ci			netif_tx_wake_all_queues(ndev);
11218c2ecf20Sopenharmony_ci			netdev_info(ndev, "link up\n");
11228c2ecf20Sopenharmony_ci		} else {
11238c2ecf20Sopenharmony_ci			netif_carrier_off(ndev);
11248c2ecf20Sopenharmony_ci			netdev_info(ndev, "link down\n");
11258c2ecf20Sopenharmony_ci		}
11268c2ecf20Sopenharmony_ci		priv->link = state;
11278c2ecf20Sopenharmony_ci	}
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci/**
11318c2ecf20Sopenharmony_ci *hns_nic_init_phy - init phy
11328c2ecf20Sopenharmony_ci *@ndev: net device
11338c2ecf20Sopenharmony_ci *@h: ae handle
11348c2ecf20Sopenharmony_ci * Return 0 on success, negative on failure
11358c2ecf20Sopenharmony_ci */
11368c2ecf20Sopenharmony_ciint hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h)
11378c2ecf20Sopenharmony_ci{
11388c2ecf20Sopenharmony_ci	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
11398c2ecf20Sopenharmony_ci	struct phy_device *phy_dev = h->phy_dev;
11408c2ecf20Sopenharmony_ci	int ret;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	if (!h->phy_dev)
11438c2ecf20Sopenharmony_ci		return 0;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	ethtool_convert_legacy_u32_to_link_mode(supported, h->if_support);
11468c2ecf20Sopenharmony_ci	linkmode_and(phy_dev->supported, phy_dev->supported, supported);
11478c2ecf20Sopenharmony_ci	linkmode_copy(phy_dev->advertising, phy_dev->supported);
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	if (h->phy_if == PHY_INTERFACE_MODE_XGMII)
11508c2ecf20Sopenharmony_ci		phy_dev->autoneg = false;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (h->phy_if != PHY_INTERFACE_MODE_XGMII) {
11538c2ecf20Sopenharmony_ci		phy_dev->dev_flags = 0;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		ret = phy_connect_direct(ndev, phy_dev, hns_nic_adjust_link,
11568c2ecf20Sopenharmony_ci					 h->phy_if);
11578c2ecf20Sopenharmony_ci	} else {
11588c2ecf20Sopenharmony_ci		ret = phy_attach_direct(ndev, phy_dev, 0, h->phy_if);
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci	if (unlikely(ret))
11618c2ecf20Sopenharmony_ci		return -ENODEV;
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	phy_attached_info(phy_dev);
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic int hns_nic_ring_open(struct net_device *netdev, int idx)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
11718c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	napi_enable(&priv->ring_data[idx].napi);
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	enable_irq(priv->ring_data[idx].ring->irq);
11768c2ecf20Sopenharmony_ci	h->dev->ops->toggle_ring_irq(priv->ring_data[idx].ring, 0);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	return 0;
11798c2ecf20Sopenharmony_ci}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_cistatic int hns_nic_net_set_mac_address(struct net_device *ndev, void *p)
11828c2ecf20Sopenharmony_ci{
11838c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
11848c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
11858c2ecf20Sopenharmony_ci	struct sockaddr *mac_addr = p;
11868c2ecf20Sopenharmony_ci	int ret;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (!mac_addr || !is_valid_ether_addr((const u8 *)mac_addr->sa_data))
11898c2ecf20Sopenharmony_ci		return -EADDRNOTAVAIL;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	ret = h->dev->ops->set_mac_addr(h, mac_addr->sa_data);
11928c2ecf20Sopenharmony_ci	if (ret) {
11938c2ecf20Sopenharmony_ci		netdev_err(ndev, "set_mac_address fail, ret=%d!\n", ret);
11948c2ecf20Sopenharmony_ci		return ret;
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	memcpy(ndev->dev_addr, mac_addr->sa_data, ndev->addr_len);
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci	return 0;
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic void hns_nic_update_stats(struct net_device *netdev)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
12058c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	h->dev->ops->update_stats(h, &netdev->stats);
12088c2ecf20Sopenharmony_ci}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci/* set mac addr if it is configed. or leave it to the AE driver */
12118c2ecf20Sopenharmony_cistatic void hns_init_mac_addr(struct net_device *ndev)
12128c2ecf20Sopenharmony_ci{
12138c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	if (!device_get_mac_address(priv->dev, ndev->dev_addr, ETH_ALEN)) {
12168c2ecf20Sopenharmony_ci		eth_hw_addr_random(ndev);
12178c2ecf20Sopenharmony_ci		dev_warn(priv->dev, "No valid mac, use random mac %pM",
12188c2ecf20Sopenharmony_ci			 ndev->dev_addr);
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_cistatic void hns_nic_ring_close(struct net_device *netdev, int idx)
12238c2ecf20Sopenharmony_ci{
12248c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
12258c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	h->dev->ops->toggle_ring_irq(priv->ring_data[idx].ring, 1);
12288c2ecf20Sopenharmony_ci	disable_irq(priv->ring_data[idx].ring->irq);
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	napi_disable(&priv->ring_data[idx].napi);
12318c2ecf20Sopenharmony_ci}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_cistatic int hns_nic_init_affinity_mask(int q_num, int ring_idx,
12348c2ecf20Sopenharmony_ci				      struct hnae_ring *ring, cpumask_t *mask)
12358c2ecf20Sopenharmony_ci{
12368c2ecf20Sopenharmony_ci	int cpu;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	/* Diffrent irq banlance between 16core and 32core.
12398c2ecf20Sopenharmony_ci	 * The cpu mask set by ring index according to the ring flag
12408c2ecf20Sopenharmony_ci	 * which indicate the ring is tx or rx.
12418c2ecf20Sopenharmony_ci	 */
12428c2ecf20Sopenharmony_ci	if (q_num == num_possible_cpus()) {
12438c2ecf20Sopenharmony_ci		if (is_tx_ring(ring))
12448c2ecf20Sopenharmony_ci			cpu = ring_idx;
12458c2ecf20Sopenharmony_ci		else
12468c2ecf20Sopenharmony_ci			cpu = ring_idx - q_num;
12478c2ecf20Sopenharmony_ci	} else {
12488c2ecf20Sopenharmony_ci		if (is_tx_ring(ring))
12498c2ecf20Sopenharmony_ci			cpu = ring_idx * 2;
12508c2ecf20Sopenharmony_ci		else
12518c2ecf20Sopenharmony_ci			cpu = (ring_idx - q_num) * 2 + 1;
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	cpumask_clear(mask);
12558c2ecf20Sopenharmony_ci	cpumask_set_cpu(cpu, mask);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	return cpu;
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic void hns_nic_free_irq(int q_num, struct hns_nic_priv *priv)
12618c2ecf20Sopenharmony_ci{
12628c2ecf20Sopenharmony_ci	int i;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	for (i = 0; i < q_num * 2; i++) {
12658c2ecf20Sopenharmony_ci		if (priv->ring_data[i].ring->irq_init_flag == RCB_IRQ_INITED) {
12668c2ecf20Sopenharmony_ci			irq_set_affinity_hint(priv->ring_data[i].ring->irq,
12678c2ecf20Sopenharmony_ci					      NULL);
12688c2ecf20Sopenharmony_ci			free_irq(priv->ring_data[i].ring->irq,
12698c2ecf20Sopenharmony_ci				 &priv->ring_data[i]);
12708c2ecf20Sopenharmony_ci			priv->ring_data[i].ring->irq_init_flag =
12718c2ecf20Sopenharmony_ci				RCB_IRQ_NOT_INITED;
12728c2ecf20Sopenharmony_ci		}
12738c2ecf20Sopenharmony_ci	}
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic int hns_nic_init_irq(struct hns_nic_priv *priv)
12778c2ecf20Sopenharmony_ci{
12788c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
12798c2ecf20Sopenharmony_ci	struct hns_nic_ring_data *rd;
12808c2ecf20Sopenharmony_ci	int i;
12818c2ecf20Sopenharmony_ci	int ret;
12828c2ecf20Sopenharmony_ci	int cpu;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	for (i = 0; i < h->q_num * 2; i++) {
12858c2ecf20Sopenharmony_ci		rd = &priv->ring_data[i];
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci		if (rd->ring->irq_init_flag == RCB_IRQ_INITED)
12888c2ecf20Sopenharmony_ci			break;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci		snprintf(rd->ring->ring_name, RCB_RING_NAME_LEN,
12918c2ecf20Sopenharmony_ci			 "%s-%s%d", priv->netdev->name,
12928c2ecf20Sopenharmony_ci			 (is_tx_ring(rd->ring) ? "tx" : "rx"), rd->queue_index);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		rd->ring->ring_name[RCB_RING_NAME_LEN - 1] = '\0';
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci		irq_set_status_flags(rd->ring->irq, IRQ_NOAUTOEN);
12978c2ecf20Sopenharmony_ci		ret = request_irq(rd->ring->irq,
12988c2ecf20Sopenharmony_ci				  hns_irq_handle, 0, rd->ring->ring_name, rd);
12998c2ecf20Sopenharmony_ci		if (ret) {
13008c2ecf20Sopenharmony_ci			netdev_err(priv->netdev, "request irq(%d) fail\n",
13018c2ecf20Sopenharmony_ci				   rd->ring->irq);
13028c2ecf20Sopenharmony_ci			goto out_free_irq;
13038c2ecf20Sopenharmony_ci		}
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci		cpu = hns_nic_init_affinity_mask(h->q_num, i,
13068c2ecf20Sopenharmony_ci						 rd->ring, &rd->mask);
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci		if (cpu_online(cpu))
13098c2ecf20Sopenharmony_ci			irq_set_affinity_hint(rd->ring->irq,
13108c2ecf20Sopenharmony_ci					      &rd->mask);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		rd->ring->irq_init_flag = RCB_IRQ_INITED;
13138c2ecf20Sopenharmony_ci	}
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	return 0;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ciout_free_irq:
13188c2ecf20Sopenharmony_ci	hns_nic_free_irq(h->q_num, priv);
13198c2ecf20Sopenharmony_ci	return ret;
13208c2ecf20Sopenharmony_ci}
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_cistatic int hns_nic_net_up(struct net_device *ndev)
13238c2ecf20Sopenharmony_ci{
13248c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
13258c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
13268c2ecf20Sopenharmony_ci	int i, j;
13278c2ecf20Sopenharmony_ci	int ret;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	if (!test_bit(NIC_STATE_DOWN, &priv->state))
13308c2ecf20Sopenharmony_ci		return 0;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	ret = hns_nic_init_irq(priv);
13338c2ecf20Sopenharmony_ci	if (ret != 0) {
13348c2ecf20Sopenharmony_ci		netdev_err(ndev, "hns init irq failed! ret=%d\n", ret);
13358c2ecf20Sopenharmony_ci		return ret;
13368c2ecf20Sopenharmony_ci	}
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	for (i = 0; i < h->q_num * 2; i++) {
13398c2ecf20Sopenharmony_ci		ret = hns_nic_ring_open(ndev, i);
13408c2ecf20Sopenharmony_ci		if (ret)
13418c2ecf20Sopenharmony_ci			goto out_has_some_queues;
13428c2ecf20Sopenharmony_ci	}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	ret = h->dev->ops->set_mac_addr(h, ndev->dev_addr);
13458c2ecf20Sopenharmony_ci	if (ret)
13468c2ecf20Sopenharmony_ci		goto out_set_mac_addr_err;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	ret = h->dev->ops->start ? h->dev->ops->start(h) : 0;
13498c2ecf20Sopenharmony_ci	if (ret)
13508c2ecf20Sopenharmony_ci		goto out_start_err;
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	if (ndev->phydev)
13538c2ecf20Sopenharmony_ci		phy_start(ndev->phydev);
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	clear_bit(NIC_STATE_DOWN, &priv->state);
13568c2ecf20Sopenharmony_ci	(void)mod_timer(&priv->service_timer, jiffies + SERVICE_TIMER_HZ);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	return 0;
13598c2ecf20Sopenharmony_ci
13608c2ecf20Sopenharmony_ciout_start_err:
13618c2ecf20Sopenharmony_ci	netif_stop_queue(ndev);
13628c2ecf20Sopenharmony_ciout_set_mac_addr_err:
13638c2ecf20Sopenharmony_ciout_has_some_queues:
13648c2ecf20Sopenharmony_ci	for (j = i - 1; j >= 0; j--)
13658c2ecf20Sopenharmony_ci		hns_nic_ring_close(ndev, j);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	hns_nic_free_irq(h->q_num, priv);
13688c2ecf20Sopenharmony_ci	set_bit(NIC_STATE_DOWN, &priv->state);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	return ret;
13718c2ecf20Sopenharmony_ci}
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_cistatic void hns_nic_net_down(struct net_device *ndev)
13748c2ecf20Sopenharmony_ci{
13758c2ecf20Sopenharmony_ci	int i;
13768c2ecf20Sopenharmony_ci	struct hnae_ae_ops *ops;
13778c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	if (test_and_set_bit(NIC_STATE_DOWN, &priv->state))
13808c2ecf20Sopenharmony_ci		return;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	(void)del_timer_sync(&priv->service_timer);
13838c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(ndev);
13848c2ecf20Sopenharmony_ci	netif_carrier_off(ndev);
13858c2ecf20Sopenharmony_ci	netif_tx_disable(ndev);
13868c2ecf20Sopenharmony_ci	priv->link = 0;
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	if (ndev->phydev)
13898c2ecf20Sopenharmony_ci		phy_stop(ndev->phydev);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	ops = priv->ae_handle->dev->ops;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	if (ops->stop)
13948c2ecf20Sopenharmony_ci		ops->stop(priv->ae_handle);
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	netif_tx_stop_all_queues(ndev);
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	for (i = priv->ae_handle->q_num - 1; i >= 0; i--) {
13998c2ecf20Sopenharmony_ci		hns_nic_ring_close(ndev, i);
14008c2ecf20Sopenharmony_ci		hns_nic_ring_close(ndev, i + priv->ae_handle->q_num);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci		/* clean tx buffers*/
14038c2ecf20Sopenharmony_ci		hns_nic_tx_clr_all_bufs(priv->ring_data + i);
14048c2ecf20Sopenharmony_ci	}
14058c2ecf20Sopenharmony_ci}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_civoid hns_nic_net_reset(struct net_device *ndev)
14088c2ecf20Sopenharmony_ci{
14098c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
14108c2ecf20Sopenharmony_ci	struct hnae_handle *handle = priv->ae_handle;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	while (test_and_set_bit(NIC_STATE_RESETTING, &priv->state))
14138c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	(void)hnae_reinit_handle(handle);
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	clear_bit(NIC_STATE_RESETTING, &priv->state);
14188c2ecf20Sopenharmony_ci}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_civoid hns_nic_net_reinit(struct net_device *netdev)
14218c2ecf20Sopenharmony_ci{
14228c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
14238c2ecf20Sopenharmony_ci	enum hnae_port_type type = priv->ae_handle->port_type;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	netif_trans_update(priv->netdev);
14268c2ecf20Sopenharmony_ci	while (test_and_set_bit(NIC_STATE_REINITING, &priv->state))
14278c2ecf20Sopenharmony_ci		usleep_range(1000, 2000);
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	hns_nic_net_down(netdev);
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	/* Only do hns_nic_net_reset in debug mode
14328c2ecf20Sopenharmony_ci	 * because of hardware limitation.
14338c2ecf20Sopenharmony_ci	 */
14348c2ecf20Sopenharmony_ci	if (type == HNAE_PORT_DEBUG)
14358c2ecf20Sopenharmony_ci		hns_nic_net_reset(netdev);
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci	(void)hns_nic_net_up(netdev);
14388c2ecf20Sopenharmony_ci	clear_bit(NIC_STATE_REINITING, &priv->state);
14398c2ecf20Sopenharmony_ci}
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_cistatic int hns_nic_net_open(struct net_device *ndev)
14428c2ecf20Sopenharmony_ci{
14438c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
14448c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
14458c2ecf20Sopenharmony_ci	int ret;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	if (test_bit(NIC_STATE_TESTING, &priv->state))
14488c2ecf20Sopenharmony_ci		return -EBUSY;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	priv->link = 0;
14518c2ecf20Sopenharmony_ci	netif_carrier_off(ndev);
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	ret = netif_set_real_num_tx_queues(ndev, h->q_num);
14548c2ecf20Sopenharmony_ci	if (ret < 0) {
14558c2ecf20Sopenharmony_ci		netdev_err(ndev, "netif_set_real_num_tx_queues fail, ret=%d!\n",
14568c2ecf20Sopenharmony_ci			   ret);
14578c2ecf20Sopenharmony_ci		return ret;
14588c2ecf20Sopenharmony_ci	}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	ret = netif_set_real_num_rx_queues(ndev, h->q_num);
14618c2ecf20Sopenharmony_ci	if (ret < 0) {
14628c2ecf20Sopenharmony_ci		netdev_err(ndev,
14638c2ecf20Sopenharmony_ci			   "netif_set_real_num_rx_queues fail, ret=%d!\n", ret);
14648c2ecf20Sopenharmony_ci		return ret;
14658c2ecf20Sopenharmony_ci	}
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	ret = hns_nic_net_up(ndev);
14688c2ecf20Sopenharmony_ci	if (ret) {
14698c2ecf20Sopenharmony_ci		netdev_err(ndev,
14708c2ecf20Sopenharmony_ci			   "hns net up fail, ret=%d!\n", ret);
14718c2ecf20Sopenharmony_ci		return ret;
14728c2ecf20Sopenharmony_ci	}
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	return 0;
14758c2ecf20Sopenharmony_ci}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_cistatic int hns_nic_net_stop(struct net_device *ndev)
14788c2ecf20Sopenharmony_ci{
14798c2ecf20Sopenharmony_ci	hns_nic_net_down(ndev);
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	return 0;
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_cistatic void hns_tx_timeout_reset(struct hns_nic_priv *priv);
14858c2ecf20Sopenharmony_ci#define HNS_TX_TIMEO_LIMIT (40 * HZ)
14868c2ecf20Sopenharmony_cistatic void hns_nic_net_timeout(struct net_device *ndev, unsigned int txqueue)
14878c2ecf20Sopenharmony_ci{
14888c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	if (ndev->watchdog_timeo < HNS_TX_TIMEO_LIMIT) {
14918c2ecf20Sopenharmony_ci		ndev->watchdog_timeo *= 2;
14928c2ecf20Sopenharmony_ci		netdev_info(ndev, "watchdog_timo changed to %d.\n",
14938c2ecf20Sopenharmony_ci			    ndev->watchdog_timeo);
14948c2ecf20Sopenharmony_ci	} else {
14958c2ecf20Sopenharmony_ci		ndev->watchdog_timeo = HNS_NIC_TX_TIMEOUT;
14968c2ecf20Sopenharmony_ci		hns_tx_timeout_reset(priv);
14978c2ecf20Sopenharmony_ci	}
14988c2ecf20Sopenharmony_ci}
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_cistatic netdev_tx_t hns_nic_net_xmit(struct sk_buff *skb,
15018c2ecf20Sopenharmony_ci				    struct net_device *ndev)
15028c2ecf20Sopenharmony_ci{
15038c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	assert(skb->queue_mapping < ndev->ae_handle->q_num);
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	return hns_nic_net_xmit_hw(ndev, skb,
15088c2ecf20Sopenharmony_ci				   &tx_ring_data(priv, skb->queue_mapping));
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_cistatic void hns_nic_drop_rx_fetch(struct hns_nic_ring_data *ring_data,
15128c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
15138c2ecf20Sopenharmony_ci{
15148c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
15158c2ecf20Sopenharmony_ci}
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci#define HNS_LB_TX_RING	0
15188c2ecf20Sopenharmony_cistatic struct sk_buff *hns_assemble_skb(struct net_device *ndev)
15198c2ecf20Sopenharmony_ci{
15208c2ecf20Sopenharmony_ci	struct sk_buff *skb;
15218c2ecf20Sopenharmony_ci	struct ethhdr *ethhdr;
15228c2ecf20Sopenharmony_ci	int frame_len;
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci	/* allocate test skb */
15258c2ecf20Sopenharmony_ci	skb = alloc_skb(64, GFP_KERNEL);
15268c2ecf20Sopenharmony_ci	if (!skb)
15278c2ecf20Sopenharmony_ci		return NULL;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	skb_put(skb, 64);
15308c2ecf20Sopenharmony_ci	skb->dev = ndev;
15318c2ecf20Sopenharmony_ci	memset(skb->data, 0xFF, skb->len);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	/* must be tcp/ip package */
15348c2ecf20Sopenharmony_ci	ethhdr = (struct ethhdr *)skb->data;
15358c2ecf20Sopenharmony_ci	ethhdr->h_proto = htons(ETH_P_IP);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	frame_len = skb->len & (~1ul);
15388c2ecf20Sopenharmony_ci	memset(&skb->data[frame_len / 2], 0xAA,
15398c2ecf20Sopenharmony_ci	       frame_len / 2 - 1);
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	skb->queue_mapping = HNS_LB_TX_RING;
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci	return skb;
15448c2ecf20Sopenharmony_ci}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_cistatic int hns_enable_serdes_lb(struct net_device *ndev)
15478c2ecf20Sopenharmony_ci{
15488c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
15498c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
15508c2ecf20Sopenharmony_ci	struct hnae_ae_ops *ops = h->dev->ops;
15518c2ecf20Sopenharmony_ci	int speed, duplex;
15528c2ecf20Sopenharmony_ci	int ret;
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	ret = ops->set_loopback(h, MAC_INTERNALLOOP_SERDES, 1);
15558c2ecf20Sopenharmony_ci	if (ret)
15568c2ecf20Sopenharmony_ci		return ret;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci	ret = ops->start ? ops->start(h) : 0;
15598c2ecf20Sopenharmony_ci	if (ret)
15608c2ecf20Sopenharmony_ci		return ret;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	/* link adjust duplex*/
15638c2ecf20Sopenharmony_ci	if (h->phy_if != PHY_INTERFACE_MODE_XGMII)
15648c2ecf20Sopenharmony_ci		speed = 1000;
15658c2ecf20Sopenharmony_ci	else
15668c2ecf20Sopenharmony_ci		speed = 10000;
15678c2ecf20Sopenharmony_ci	duplex = 1;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	ops->adjust_link(h, speed, duplex);
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	/* wait h/w ready */
15728c2ecf20Sopenharmony_ci	mdelay(300);
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci	return 0;
15758c2ecf20Sopenharmony_ci}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_cistatic void hns_disable_serdes_lb(struct net_device *ndev)
15788c2ecf20Sopenharmony_ci{
15798c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
15808c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
15818c2ecf20Sopenharmony_ci	struct hnae_ae_ops *ops = h->dev->ops;
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	ops->stop(h);
15848c2ecf20Sopenharmony_ci	ops->set_loopback(h, MAC_INTERNALLOOP_SERDES, 0);
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci/**
15888c2ecf20Sopenharmony_ci *hns_nic_clear_all_rx_fetch - clear the chip fetched descriptions. The
15898c2ecf20Sopenharmony_ci *function as follows:
15908c2ecf20Sopenharmony_ci *    1. if one rx ring has found the page_offset is not equal 0 between head
15918c2ecf20Sopenharmony_ci *       and tail, it means that the chip fetched the wrong descs for the ring
15928c2ecf20Sopenharmony_ci *       which buffer size is 4096.
15938c2ecf20Sopenharmony_ci *    2. we set the chip serdes loopback and set rss indirection to the ring.
15948c2ecf20Sopenharmony_ci *    3. construct 64-bytes ip broadcast packages, wait the associated rx ring
15958c2ecf20Sopenharmony_ci *       recieving all packages and it will fetch new descriptions.
15968c2ecf20Sopenharmony_ci *    4. recover to the original state.
15978c2ecf20Sopenharmony_ci *
15988c2ecf20Sopenharmony_ci *@ndev: net device
15998c2ecf20Sopenharmony_ci */
16008c2ecf20Sopenharmony_cistatic int hns_nic_clear_all_rx_fetch(struct net_device *ndev)
16018c2ecf20Sopenharmony_ci{
16028c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
16038c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
16048c2ecf20Sopenharmony_ci	struct hnae_ae_ops *ops = h->dev->ops;
16058c2ecf20Sopenharmony_ci	struct hns_nic_ring_data *rd;
16068c2ecf20Sopenharmony_ci	struct hnae_ring *ring;
16078c2ecf20Sopenharmony_ci	struct sk_buff *skb;
16088c2ecf20Sopenharmony_ci	u32 *org_indir;
16098c2ecf20Sopenharmony_ci	u32 *cur_indir;
16108c2ecf20Sopenharmony_ci	int indir_size;
16118c2ecf20Sopenharmony_ci	int head, tail;
16128c2ecf20Sopenharmony_ci	int fetch_num;
16138c2ecf20Sopenharmony_ci	int i, j;
16148c2ecf20Sopenharmony_ci	bool found;
16158c2ecf20Sopenharmony_ci	int retry_times;
16168c2ecf20Sopenharmony_ci	int ret = 0;
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	/* alloc indir memory */
16198c2ecf20Sopenharmony_ci	indir_size = ops->get_rss_indir_size(h) * sizeof(*org_indir);
16208c2ecf20Sopenharmony_ci	org_indir = kzalloc(indir_size, GFP_KERNEL);
16218c2ecf20Sopenharmony_ci	if (!org_indir)
16228c2ecf20Sopenharmony_ci		return -ENOMEM;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	/* store the orginal indirection */
16258c2ecf20Sopenharmony_ci	ops->get_rss(h, org_indir, NULL, NULL);
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	cur_indir = kzalloc(indir_size, GFP_KERNEL);
16288c2ecf20Sopenharmony_ci	if (!cur_indir) {
16298c2ecf20Sopenharmony_ci		ret = -ENOMEM;
16308c2ecf20Sopenharmony_ci		goto cur_indir_alloc_err;
16318c2ecf20Sopenharmony_ci	}
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	/* set loopback */
16348c2ecf20Sopenharmony_ci	if (hns_enable_serdes_lb(ndev)) {
16358c2ecf20Sopenharmony_ci		ret = -EINVAL;
16368c2ecf20Sopenharmony_ci		goto enable_serdes_lb_err;
16378c2ecf20Sopenharmony_ci	}
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci	/* foreach every rx ring to clear fetch desc */
16408c2ecf20Sopenharmony_ci	for (i = 0; i < h->q_num; i++) {
16418c2ecf20Sopenharmony_ci		ring = &h->qs[i]->rx_ring;
16428c2ecf20Sopenharmony_ci		head = readl_relaxed(ring->io_base + RCB_REG_HEAD);
16438c2ecf20Sopenharmony_ci		tail = readl_relaxed(ring->io_base + RCB_REG_TAIL);
16448c2ecf20Sopenharmony_ci		found = false;
16458c2ecf20Sopenharmony_ci		fetch_num = ring_dist(ring, head, tail);
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci		while (head != tail) {
16488c2ecf20Sopenharmony_ci			if (ring->desc_cb[head].page_offset != 0) {
16498c2ecf20Sopenharmony_ci				found = true;
16508c2ecf20Sopenharmony_ci				break;
16518c2ecf20Sopenharmony_ci			}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci			head++;
16548c2ecf20Sopenharmony_ci			if (head == ring->desc_num)
16558c2ecf20Sopenharmony_ci				head = 0;
16568c2ecf20Sopenharmony_ci		}
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci		if (found) {
16598c2ecf20Sopenharmony_ci			for (j = 0; j < indir_size / sizeof(*org_indir); j++)
16608c2ecf20Sopenharmony_ci				cur_indir[j] = i;
16618c2ecf20Sopenharmony_ci			ops->set_rss(h, cur_indir, NULL, 0);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci			for (j = 0; j < fetch_num; j++) {
16648c2ecf20Sopenharmony_ci				/* alloc one skb and init */
16658c2ecf20Sopenharmony_ci				skb = hns_assemble_skb(ndev);
16668c2ecf20Sopenharmony_ci				if (!skb) {
16678c2ecf20Sopenharmony_ci					ret = -ENOMEM;
16688c2ecf20Sopenharmony_ci					goto out;
16698c2ecf20Sopenharmony_ci				}
16708c2ecf20Sopenharmony_ci				rd = &tx_ring_data(priv, skb->queue_mapping);
16718c2ecf20Sopenharmony_ci				hns_nic_net_xmit_hw(ndev, skb, rd);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci				retry_times = 0;
16748c2ecf20Sopenharmony_ci				while (retry_times++ < 10) {
16758c2ecf20Sopenharmony_ci					mdelay(10);
16768c2ecf20Sopenharmony_ci					/* clean rx */
16778c2ecf20Sopenharmony_ci					rd = &rx_ring_data(priv, i);
16788c2ecf20Sopenharmony_ci					if (rd->poll_one(rd, fetch_num,
16798c2ecf20Sopenharmony_ci							 hns_nic_drop_rx_fetch))
16808c2ecf20Sopenharmony_ci						break;
16818c2ecf20Sopenharmony_ci				}
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci				retry_times = 0;
16848c2ecf20Sopenharmony_ci				while (retry_times++ < 10) {
16858c2ecf20Sopenharmony_ci					mdelay(10);
16868c2ecf20Sopenharmony_ci					/* clean tx ring 0 send package */
16878c2ecf20Sopenharmony_ci					rd = &tx_ring_data(priv,
16888c2ecf20Sopenharmony_ci							   HNS_LB_TX_RING);
16898c2ecf20Sopenharmony_ci					if (rd->poll_one(rd, fetch_num, NULL))
16908c2ecf20Sopenharmony_ci						break;
16918c2ecf20Sopenharmony_ci				}
16928c2ecf20Sopenharmony_ci			}
16938c2ecf20Sopenharmony_ci		}
16948c2ecf20Sopenharmony_ci	}
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ciout:
16978c2ecf20Sopenharmony_ci	/* restore everything */
16988c2ecf20Sopenharmony_ci	ops->set_rss(h, org_indir, NULL, 0);
16998c2ecf20Sopenharmony_ci	hns_disable_serdes_lb(ndev);
17008c2ecf20Sopenharmony_cienable_serdes_lb_err:
17018c2ecf20Sopenharmony_ci	kfree(cur_indir);
17028c2ecf20Sopenharmony_cicur_indir_alloc_err:
17038c2ecf20Sopenharmony_ci	kfree(org_indir);
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_ci	return ret;
17068c2ecf20Sopenharmony_ci}
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_cistatic int hns_nic_change_mtu(struct net_device *ndev, int new_mtu)
17098c2ecf20Sopenharmony_ci{
17108c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
17118c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
17128c2ecf20Sopenharmony_ci	bool if_running = netif_running(ndev);
17138c2ecf20Sopenharmony_ci	int ret;
17148c2ecf20Sopenharmony_ci
17158c2ecf20Sopenharmony_ci	/* MTU < 68 is an error and causes problems on some kernels */
17168c2ecf20Sopenharmony_ci	if (new_mtu < 68)
17178c2ecf20Sopenharmony_ci		return -EINVAL;
17188c2ecf20Sopenharmony_ci
17198c2ecf20Sopenharmony_ci	/* MTU no change */
17208c2ecf20Sopenharmony_ci	if (new_mtu == ndev->mtu)
17218c2ecf20Sopenharmony_ci		return 0;
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	if (!h->dev->ops->set_mtu)
17248c2ecf20Sopenharmony_ci		return -ENOTSUPP;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	if (if_running) {
17278c2ecf20Sopenharmony_ci		(void)hns_nic_net_stop(ndev);
17288c2ecf20Sopenharmony_ci		msleep(100);
17298c2ecf20Sopenharmony_ci	}
17308c2ecf20Sopenharmony_ci
17318c2ecf20Sopenharmony_ci	if (priv->enet_ver != AE_VERSION_1 &&
17328c2ecf20Sopenharmony_ci	    ndev->mtu <= BD_SIZE_2048_MAX_MTU &&
17338c2ecf20Sopenharmony_ci	    new_mtu > BD_SIZE_2048_MAX_MTU) {
17348c2ecf20Sopenharmony_ci		/* update desc */
17358c2ecf20Sopenharmony_ci		hnae_reinit_all_ring_desc(h);
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci		/* clear the package which the chip has fetched */
17388c2ecf20Sopenharmony_ci		ret = hns_nic_clear_all_rx_fetch(ndev);
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci		/* the page offset must be consist with desc */
17418c2ecf20Sopenharmony_ci		hnae_reinit_all_ring_page_off(h);
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci		if (ret) {
17448c2ecf20Sopenharmony_ci			netdev_err(ndev, "clear the fetched desc fail\n");
17458c2ecf20Sopenharmony_ci			goto out;
17468c2ecf20Sopenharmony_ci		}
17478c2ecf20Sopenharmony_ci	}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	ret = h->dev->ops->set_mtu(h, new_mtu);
17508c2ecf20Sopenharmony_ci	if (ret) {
17518c2ecf20Sopenharmony_ci		netdev_err(ndev, "set mtu fail, return value %d\n",
17528c2ecf20Sopenharmony_ci			   ret);
17538c2ecf20Sopenharmony_ci		goto out;
17548c2ecf20Sopenharmony_ci	}
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	/* finally, set new mtu to netdevice */
17578c2ecf20Sopenharmony_ci	ndev->mtu = new_mtu;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ciout:
17608c2ecf20Sopenharmony_ci	if (if_running) {
17618c2ecf20Sopenharmony_ci		if (hns_nic_net_open(ndev)) {
17628c2ecf20Sopenharmony_ci			netdev_err(ndev, "hns net open fail\n");
17638c2ecf20Sopenharmony_ci			ret = -EINVAL;
17648c2ecf20Sopenharmony_ci		}
17658c2ecf20Sopenharmony_ci	}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	return ret;
17688c2ecf20Sopenharmony_ci}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_cistatic int hns_nic_set_features(struct net_device *netdev,
17718c2ecf20Sopenharmony_ci				netdev_features_t features)
17728c2ecf20Sopenharmony_ci{
17738c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	switch (priv->enet_ver) {
17768c2ecf20Sopenharmony_ci	case AE_VERSION_1:
17778c2ecf20Sopenharmony_ci		if (features & (NETIF_F_TSO | NETIF_F_TSO6))
17788c2ecf20Sopenharmony_ci			netdev_info(netdev, "enet v1 do not support tso!\n");
17798c2ecf20Sopenharmony_ci		break;
17808c2ecf20Sopenharmony_ci	default:
17818c2ecf20Sopenharmony_ci		if (features & (NETIF_F_TSO | NETIF_F_TSO6)) {
17828c2ecf20Sopenharmony_ci			priv->ops.fill_desc = fill_tso_desc;
17838c2ecf20Sopenharmony_ci			priv->ops.maybe_stop_tx = hns_nic_maybe_stop_tso;
17848c2ecf20Sopenharmony_ci			/* The chip only support 7*4096 */
17858c2ecf20Sopenharmony_ci			netif_set_gso_max_size(netdev, 7 * 4096);
17868c2ecf20Sopenharmony_ci		} else {
17878c2ecf20Sopenharmony_ci			priv->ops.fill_desc = fill_v2_desc;
17888c2ecf20Sopenharmony_ci			priv->ops.maybe_stop_tx = hns_nic_maybe_stop_tx;
17898c2ecf20Sopenharmony_ci		}
17908c2ecf20Sopenharmony_ci		break;
17918c2ecf20Sopenharmony_ci	}
17928c2ecf20Sopenharmony_ci	netdev->features = features;
17938c2ecf20Sopenharmony_ci	return 0;
17948c2ecf20Sopenharmony_ci}
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_cistatic netdev_features_t hns_nic_fix_features(
17978c2ecf20Sopenharmony_ci		struct net_device *netdev, netdev_features_t features)
17988c2ecf20Sopenharmony_ci{
17998c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
18008c2ecf20Sopenharmony_ci
18018c2ecf20Sopenharmony_ci	switch (priv->enet_ver) {
18028c2ecf20Sopenharmony_ci	case AE_VERSION_1:
18038c2ecf20Sopenharmony_ci		features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
18048c2ecf20Sopenharmony_ci				NETIF_F_HW_VLAN_CTAG_FILTER);
18058c2ecf20Sopenharmony_ci		break;
18068c2ecf20Sopenharmony_ci	default:
18078c2ecf20Sopenharmony_ci		break;
18088c2ecf20Sopenharmony_ci	}
18098c2ecf20Sopenharmony_ci	return features;
18108c2ecf20Sopenharmony_ci}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_cistatic int hns_nic_uc_sync(struct net_device *netdev, const unsigned char *addr)
18138c2ecf20Sopenharmony_ci{
18148c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
18158c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	if (h->dev->ops->add_uc_addr)
18188c2ecf20Sopenharmony_ci		return h->dev->ops->add_uc_addr(h, addr);
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	return 0;
18218c2ecf20Sopenharmony_ci}
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_cistatic int hns_nic_uc_unsync(struct net_device *netdev,
18248c2ecf20Sopenharmony_ci			     const unsigned char *addr)
18258c2ecf20Sopenharmony_ci{
18268c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
18278c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	if (h->dev->ops->rm_uc_addr)
18308c2ecf20Sopenharmony_ci		return h->dev->ops->rm_uc_addr(h, addr);
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	return 0;
18338c2ecf20Sopenharmony_ci}
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci/**
18368c2ecf20Sopenharmony_ci * hns_set_multicast_list - set mutl mac address
18378c2ecf20Sopenharmony_ci * @ndev: net device
18388c2ecf20Sopenharmony_ci *
18398c2ecf20Sopenharmony_ci * return void
18408c2ecf20Sopenharmony_ci */
18418c2ecf20Sopenharmony_cistatic void hns_set_multicast_list(struct net_device *ndev)
18428c2ecf20Sopenharmony_ci{
18438c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
18448c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
18458c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha = NULL;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	if (!h)	{
18488c2ecf20Sopenharmony_ci		netdev_err(ndev, "hnae handle is null\n");
18498c2ecf20Sopenharmony_ci		return;
18508c2ecf20Sopenharmony_ci	}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	if (h->dev->ops->clr_mc_addr)
18538c2ecf20Sopenharmony_ci		if (h->dev->ops->clr_mc_addr(h))
18548c2ecf20Sopenharmony_ci			netdev_err(ndev, "clear multicast address fail\n");
18558c2ecf20Sopenharmony_ci
18568c2ecf20Sopenharmony_ci	if (h->dev->ops->set_mc_addr) {
18578c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, ndev)
18588c2ecf20Sopenharmony_ci			if (h->dev->ops->set_mc_addr(h, ha->addr))
18598c2ecf20Sopenharmony_ci				netdev_err(ndev, "set multicast fail\n");
18608c2ecf20Sopenharmony_ci	}
18618c2ecf20Sopenharmony_ci}
18628c2ecf20Sopenharmony_ci
18638c2ecf20Sopenharmony_cistatic void hns_nic_set_rx_mode(struct net_device *ndev)
18648c2ecf20Sopenharmony_ci{
18658c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
18668c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
18678c2ecf20Sopenharmony_ci
18688c2ecf20Sopenharmony_ci	if (h->dev->ops->set_promisc_mode) {
18698c2ecf20Sopenharmony_ci		if (ndev->flags & IFF_PROMISC)
18708c2ecf20Sopenharmony_ci			h->dev->ops->set_promisc_mode(h, 1);
18718c2ecf20Sopenharmony_ci		else
18728c2ecf20Sopenharmony_ci			h->dev->ops->set_promisc_mode(h, 0);
18738c2ecf20Sopenharmony_ci	}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ci	hns_set_multicast_list(ndev);
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	if (__dev_uc_sync(ndev, hns_nic_uc_sync, hns_nic_uc_unsync))
18788c2ecf20Sopenharmony_ci		netdev_err(ndev, "sync uc address fail\n");
18798c2ecf20Sopenharmony_ci}
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_cistatic void hns_nic_get_stats64(struct net_device *ndev,
18828c2ecf20Sopenharmony_ci				struct rtnl_link_stats64 *stats)
18838c2ecf20Sopenharmony_ci{
18848c2ecf20Sopenharmony_ci	int idx = 0;
18858c2ecf20Sopenharmony_ci	u64 tx_bytes = 0;
18868c2ecf20Sopenharmony_ci	u64 rx_bytes = 0;
18878c2ecf20Sopenharmony_ci	u64 tx_pkts = 0;
18888c2ecf20Sopenharmony_ci	u64 rx_pkts = 0;
18898c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
18908c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	for (idx = 0; idx < h->q_num; idx++) {
18938c2ecf20Sopenharmony_ci		tx_bytes += h->qs[idx]->tx_ring.stats.tx_bytes;
18948c2ecf20Sopenharmony_ci		tx_pkts += h->qs[idx]->tx_ring.stats.tx_pkts;
18958c2ecf20Sopenharmony_ci		rx_bytes += h->qs[idx]->rx_ring.stats.rx_bytes;
18968c2ecf20Sopenharmony_ci		rx_pkts += h->qs[idx]->rx_ring.stats.rx_pkts;
18978c2ecf20Sopenharmony_ci	}
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	stats->tx_bytes = tx_bytes;
19008c2ecf20Sopenharmony_ci	stats->tx_packets = tx_pkts;
19018c2ecf20Sopenharmony_ci	stats->rx_bytes = rx_bytes;
19028c2ecf20Sopenharmony_ci	stats->rx_packets = rx_pkts;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	stats->rx_errors = ndev->stats.rx_errors;
19058c2ecf20Sopenharmony_ci	stats->multicast = ndev->stats.multicast;
19068c2ecf20Sopenharmony_ci	stats->rx_length_errors = ndev->stats.rx_length_errors;
19078c2ecf20Sopenharmony_ci	stats->rx_crc_errors = ndev->stats.rx_crc_errors;
19088c2ecf20Sopenharmony_ci	stats->rx_missed_errors = ndev->stats.rx_missed_errors;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	stats->tx_errors = ndev->stats.tx_errors;
19118c2ecf20Sopenharmony_ci	stats->rx_dropped = ndev->stats.rx_dropped;
19128c2ecf20Sopenharmony_ci	stats->tx_dropped = ndev->stats.tx_dropped;
19138c2ecf20Sopenharmony_ci	stats->collisions = ndev->stats.collisions;
19148c2ecf20Sopenharmony_ci	stats->rx_over_errors = ndev->stats.rx_over_errors;
19158c2ecf20Sopenharmony_ci	stats->rx_frame_errors = ndev->stats.rx_frame_errors;
19168c2ecf20Sopenharmony_ci	stats->rx_fifo_errors = ndev->stats.rx_fifo_errors;
19178c2ecf20Sopenharmony_ci	stats->tx_aborted_errors = ndev->stats.tx_aborted_errors;
19188c2ecf20Sopenharmony_ci	stats->tx_carrier_errors = ndev->stats.tx_carrier_errors;
19198c2ecf20Sopenharmony_ci	stats->tx_fifo_errors = ndev->stats.tx_fifo_errors;
19208c2ecf20Sopenharmony_ci	stats->tx_heartbeat_errors = ndev->stats.tx_heartbeat_errors;
19218c2ecf20Sopenharmony_ci	stats->tx_window_errors = ndev->stats.tx_window_errors;
19228c2ecf20Sopenharmony_ci	stats->rx_compressed = ndev->stats.rx_compressed;
19238c2ecf20Sopenharmony_ci	stats->tx_compressed = ndev->stats.tx_compressed;
19248c2ecf20Sopenharmony_ci}
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_cistatic u16
19278c2ecf20Sopenharmony_cihns_nic_select_queue(struct net_device *ndev, struct sk_buff *skb,
19288c2ecf20Sopenharmony_ci		     struct net_device *sb_dev)
19298c2ecf20Sopenharmony_ci{
19308c2ecf20Sopenharmony_ci	struct ethhdr *eth_hdr = (struct ethhdr *)skb->data;
19318c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	/* fix hardware broadcast/multicast packets queue loopback */
19348c2ecf20Sopenharmony_ci	if (!AE_IS_VER1(priv->enet_ver) &&
19358c2ecf20Sopenharmony_ci	    is_multicast_ether_addr(eth_hdr->h_dest))
19368c2ecf20Sopenharmony_ci		return 0;
19378c2ecf20Sopenharmony_ci	else
19388c2ecf20Sopenharmony_ci		return netdev_pick_tx(ndev, skb, NULL);
19398c2ecf20Sopenharmony_ci}
19408c2ecf20Sopenharmony_ci
19418c2ecf20Sopenharmony_cistatic const struct net_device_ops hns_nic_netdev_ops = {
19428c2ecf20Sopenharmony_ci	.ndo_open = hns_nic_net_open,
19438c2ecf20Sopenharmony_ci	.ndo_stop = hns_nic_net_stop,
19448c2ecf20Sopenharmony_ci	.ndo_start_xmit = hns_nic_net_xmit,
19458c2ecf20Sopenharmony_ci	.ndo_tx_timeout = hns_nic_net_timeout,
19468c2ecf20Sopenharmony_ci	.ndo_set_mac_address = hns_nic_net_set_mac_address,
19478c2ecf20Sopenharmony_ci	.ndo_change_mtu = hns_nic_change_mtu,
19488c2ecf20Sopenharmony_ci	.ndo_do_ioctl = phy_do_ioctl_running,
19498c2ecf20Sopenharmony_ci	.ndo_set_features = hns_nic_set_features,
19508c2ecf20Sopenharmony_ci	.ndo_fix_features = hns_nic_fix_features,
19518c2ecf20Sopenharmony_ci	.ndo_get_stats64 = hns_nic_get_stats64,
19528c2ecf20Sopenharmony_ci	.ndo_set_rx_mode = hns_nic_set_rx_mode,
19538c2ecf20Sopenharmony_ci	.ndo_select_queue = hns_nic_select_queue,
19548c2ecf20Sopenharmony_ci};
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_cistatic void hns_nic_update_link_status(struct net_device *netdev)
19578c2ecf20Sopenharmony_ci{
19588c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci	if (h->phy_dev) {
19638c2ecf20Sopenharmony_ci		if (h->phy_if != PHY_INTERFACE_MODE_XGMII)
19648c2ecf20Sopenharmony_ci			return;
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci		(void)genphy_read_status(h->phy_dev);
19678c2ecf20Sopenharmony_ci	}
19688c2ecf20Sopenharmony_ci	hns_nic_adjust_link(netdev);
19698c2ecf20Sopenharmony_ci}
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci/* for dumping key regs*/
19728c2ecf20Sopenharmony_cistatic void hns_nic_dump(struct hns_nic_priv *priv)
19738c2ecf20Sopenharmony_ci{
19748c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
19758c2ecf20Sopenharmony_ci	struct hnae_ae_ops *ops = h->dev->ops;
19768c2ecf20Sopenharmony_ci	u32 *data, reg_num, i;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	if (ops->get_regs_len && ops->get_regs) {
19798c2ecf20Sopenharmony_ci		reg_num = ops->get_regs_len(priv->ae_handle);
19808c2ecf20Sopenharmony_ci		reg_num = (reg_num + 3ul) & ~3ul;
19818c2ecf20Sopenharmony_ci		data = kcalloc(reg_num, sizeof(u32), GFP_KERNEL);
19828c2ecf20Sopenharmony_ci		if (data) {
19838c2ecf20Sopenharmony_ci			ops->get_regs(priv->ae_handle, data);
19848c2ecf20Sopenharmony_ci			for (i = 0; i < reg_num; i += 4)
19858c2ecf20Sopenharmony_ci				pr_info("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
19868c2ecf20Sopenharmony_ci					i, data[i], data[i + 1],
19878c2ecf20Sopenharmony_ci					data[i + 2], data[i + 3]);
19888c2ecf20Sopenharmony_ci			kfree(data);
19898c2ecf20Sopenharmony_ci		}
19908c2ecf20Sopenharmony_ci	}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_ci	for (i = 0; i < h->q_num; i++) {
19938c2ecf20Sopenharmony_ci		pr_info("tx_queue%d_next_to_clean:%d\n",
19948c2ecf20Sopenharmony_ci			i, h->qs[i]->tx_ring.next_to_clean);
19958c2ecf20Sopenharmony_ci		pr_info("tx_queue%d_next_to_use:%d\n",
19968c2ecf20Sopenharmony_ci			i, h->qs[i]->tx_ring.next_to_use);
19978c2ecf20Sopenharmony_ci		pr_info("rx_queue%d_next_to_clean:%d\n",
19988c2ecf20Sopenharmony_ci			i, h->qs[i]->rx_ring.next_to_clean);
19998c2ecf20Sopenharmony_ci		pr_info("rx_queue%d_next_to_use:%d\n",
20008c2ecf20Sopenharmony_ci			i, h->qs[i]->rx_ring.next_to_use);
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci/* for resetting subtask */
20058c2ecf20Sopenharmony_cistatic void hns_nic_reset_subtask(struct hns_nic_priv *priv)
20068c2ecf20Sopenharmony_ci{
20078c2ecf20Sopenharmony_ci	enum hnae_port_type type = priv->ae_handle->port_type;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	if (!test_bit(NIC_STATE2_RESET_REQUESTED, &priv->state))
20108c2ecf20Sopenharmony_ci		return;
20118c2ecf20Sopenharmony_ci	clear_bit(NIC_STATE2_RESET_REQUESTED, &priv->state);
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	/* If we're already down, removing or resetting, just bail */
20148c2ecf20Sopenharmony_ci	if (test_bit(NIC_STATE_DOWN, &priv->state) ||
20158c2ecf20Sopenharmony_ci	    test_bit(NIC_STATE_REMOVING, &priv->state) ||
20168c2ecf20Sopenharmony_ci	    test_bit(NIC_STATE_RESETTING, &priv->state))
20178c2ecf20Sopenharmony_ci		return;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	hns_nic_dump(priv);
20208c2ecf20Sopenharmony_ci	netdev_info(priv->netdev, "try to reset %s port!\n",
20218c2ecf20Sopenharmony_ci		    (type == HNAE_PORT_DEBUG ? "debug" : "service"));
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	rtnl_lock();
20248c2ecf20Sopenharmony_ci	/* put off any impending NetWatchDogTimeout */
20258c2ecf20Sopenharmony_ci	netif_trans_update(priv->netdev);
20268c2ecf20Sopenharmony_ci	hns_nic_net_reinit(priv->netdev);
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci	rtnl_unlock();
20298c2ecf20Sopenharmony_ci}
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci/* for doing service complete*/
20328c2ecf20Sopenharmony_cistatic void hns_nic_service_event_complete(struct hns_nic_priv *priv)
20338c2ecf20Sopenharmony_ci{
20348c2ecf20Sopenharmony_ci	WARN_ON(!test_bit(NIC_STATE_SERVICE_SCHED, &priv->state));
20358c2ecf20Sopenharmony_ci	/* make sure to commit the things */
20368c2ecf20Sopenharmony_ci	smp_mb__before_atomic();
20378c2ecf20Sopenharmony_ci	clear_bit(NIC_STATE_SERVICE_SCHED, &priv->state);
20388c2ecf20Sopenharmony_ci}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_cistatic void hns_nic_service_task(struct work_struct *work)
20418c2ecf20Sopenharmony_ci{
20428c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv
20438c2ecf20Sopenharmony_ci		= container_of(work, struct hns_nic_priv, service_task);
20448c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	hns_nic_reset_subtask(priv);
20478c2ecf20Sopenharmony_ci	hns_nic_update_link_status(priv->netdev);
20488c2ecf20Sopenharmony_ci	h->dev->ops->update_led_status(h);
20498c2ecf20Sopenharmony_ci	hns_nic_update_stats(priv->netdev);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	hns_nic_service_event_complete(priv);
20528c2ecf20Sopenharmony_ci}
20538c2ecf20Sopenharmony_ci
20548c2ecf20Sopenharmony_cistatic void hns_nic_task_schedule(struct hns_nic_priv *priv)
20558c2ecf20Sopenharmony_ci{
20568c2ecf20Sopenharmony_ci	if (!test_bit(NIC_STATE_DOWN, &priv->state) &&
20578c2ecf20Sopenharmony_ci	    !test_bit(NIC_STATE_REMOVING, &priv->state) &&
20588c2ecf20Sopenharmony_ci	    !test_and_set_bit(NIC_STATE_SERVICE_SCHED, &priv->state))
20598c2ecf20Sopenharmony_ci		(void)schedule_work(&priv->service_task);
20608c2ecf20Sopenharmony_ci}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_cistatic void hns_nic_service_timer(struct timer_list *t)
20638c2ecf20Sopenharmony_ci{
20648c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = from_timer(priv, t, service_timer);
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	(void)mod_timer(&priv->service_timer, jiffies + SERVICE_TIMER_HZ);
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	hns_nic_task_schedule(priv);
20698c2ecf20Sopenharmony_ci}
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci/**
20728c2ecf20Sopenharmony_ci * hns_tx_timeout_reset - initiate reset due to Tx timeout
20738c2ecf20Sopenharmony_ci * @priv: driver private struct
20748c2ecf20Sopenharmony_ci **/
20758c2ecf20Sopenharmony_cistatic void hns_tx_timeout_reset(struct hns_nic_priv *priv)
20768c2ecf20Sopenharmony_ci{
20778c2ecf20Sopenharmony_ci	/* Do the reset outside of interrupt context */
20788c2ecf20Sopenharmony_ci	if (!test_bit(NIC_STATE_DOWN, &priv->state)) {
20798c2ecf20Sopenharmony_ci		set_bit(NIC_STATE2_RESET_REQUESTED, &priv->state);
20808c2ecf20Sopenharmony_ci		netdev_warn(priv->netdev,
20818c2ecf20Sopenharmony_ci			    "initiating reset due to tx timeout(%llu,0x%lx)\n",
20828c2ecf20Sopenharmony_ci			    priv->tx_timeout_count, priv->state);
20838c2ecf20Sopenharmony_ci		priv->tx_timeout_count++;
20848c2ecf20Sopenharmony_ci		hns_nic_task_schedule(priv);
20858c2ecf20Sopenharmony_ci	}
20868c2ecf20Sopenharmony_ci}
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_cistatic int hns_nic_init_ring_data(struct hns_nic_priv *priv)
20898c2ecf20Sopenharmony_ci{
20908c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
20918c2ecf20Sopenharmony_ci	struct hns_nic_ring_data *rd;
20928c2ecf20Sopenharmony_ci	bool is_ver1 = AE_IS_VER1(priv->enet_ver);
20938c2ecf20Sopenharmony_ci	int i;
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	if (h->q_num > NIC_MAX_Q_PER_VF) {
20968c2ecf20Sopenharmony_ci		netdev_err(priv->netdev, "too much queue (%d)\n", h->q_num);
20978c2ecf20Sopenharmony_ci		return -EINVAL;
20988c2ecf20Sopenharmony_ci	}
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci	priv->ring_data = kzalloc(array3_size(h->q_num,
21018c2ecf20Sopenharmony_ci					      sizeof(*priv->ring_data), 2),
21028c2ecf20Sopenharmony_ci				  GFP_KERNEL);
21038c2ecf20Sopenharmony_ci	if (!priv->ring_data)
21048c2ecf20Sopenharmony_ci		return -ENOMEM;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	for (i = 0; i < h->q_num; i++) {
21078c2ecf20Sopenharmony_ci		rd = &priv->ring_data[i];
21088c2ecf20Sopenharmony_ci		rd->queue_index = i;
21098c2ecf20Sopenharmony_ci		rd->ring = &h->qs[i]->tx_ring;
21108c2ecf20Sopenharmony_ci		rd->poll_one = hns_nic_tx_poll_one;
21118c2ecf20Sopenharmony_ci		rd->fini_process = is_ver1 ? hns_nic_tx_fini_pro :
21128c2ecf20Sopenharmony_ci			hns_nic_tx_fini_pro_v2;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci		netif_napi_add(priv->netdev, &rd->napi,
21158c2ecf20Sopenharmony_ci			       hns_nic_common_poll, NAPI_POLL_WEIGHT);
21168c2ecf20Sopenharmony_ci		rd->ring->irq_init_flag = RCB_IRQ_NOT_INITED;
21178c2ecf20Sopenharmony_ci	}
21188c2ecf20Sopenharmony_ci	for (i = h->q_num; i < h->q_num * 2; i++) {
21198c2ecf20Sopenharmony_ci		rd = &priv->ring_data[i];
21208c2ecf20Sopenharmony_ci		rd->queue_index = i - h->q_num;
21218c2ecf20Sopenharmony_ci		rd->ring = &h->qs[i - h->q_num]->rx_ring;
21228c2ecf20Sopenharmony_ci		rd->poll_one = hns_nic_rx_poll_one;
21238c2ecf20Sopenharmony_ci		rd->ex_process = hns_nic_rx_up_pro;
21248c2ecf20Sopenharmony_ci		rd->fini_process = is_ver1 ? hns_nic_rx_fini_pro :
21258c2ecf20Sopenharmony_ci			hns_nic_rx_fini_pro_v2;
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci		netif_napi_add(priv->netdev, &rd->napi,
21288c2ecf20Sopenharmony_ci			       hns_nic_common_poll, NAPI_POLL_WEIGHT);
21298c2ecf20Sopenharmony_ci		rd->ring->irq_init_flag = RCB_IRQ_NOT_INITED;
21308c2ecf20Sopenharmony_ci	}
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_ci	return 0;
21338c2ecf20Sopenharmony_ci}
21348c2ecf20Sopenharmony_ci
21358c2ecf20Sopenharmony_cistatic void hns_nic_uninit_ring_data(struct hns_nic_priv *priv)
21368c2ecf20Sopenharmony_ci{
21378c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
21388c2ecf20Sopenharmony_ci	int i;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	for (i = 0; i < h->q_num * 2; i++) {
21418c2ecf20Sopenharmony_ci		netif_napi_del(&priv->ring_data[i].napi);
21428c2ecf20Sopenharmony_ci		if (priv->ring_data[i].ring->irq_init_flag == RCB_IRQ_INITED) {
21438c2ecf20Sopenharmony_ci			(void)irq_set_affinity_hint(
21448c2ecf20Sopenharmony_ci				priv->ring_data[i].ring->irq,
21458c2ecf20Sopenharmony_ci				NULL);
21468c2ecf20Sopenharmony_ci			free_irq(priv->ring_data[i].ring->irq,
21478c2ecf20Sopenharmony_ci				 &priv->ring_data[i]);
21488c2ecf20Sopenharmony_ci		}
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci		priv->ring_data[i].ring->irq_init_flag = RCB_IRQ_NOT_INITED;
21518c2ecf20Sopenharmony_ci	}
21528c2ecf20Sopenharmony_ci	kfree(priv->ring_data);
21538c2ecf20Sopenharmony_ci}
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_cistatic void hns_nic_set_priv_ops(struct net_device *netdev)
21568c2ecf20Sopenharmony_ci{
21578c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(netdev);
21588c2ecf20Sopenharmony_ci	struct hnae_handle *h = priv->ae_handle;
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci	if (AE_IS_VER1(priv->enet_ver)) {
21618c2ecf20Sopenharmony_ci		priv->ops.fill_desc = fill_desc;
21628c2ecf20Sopenharmony_ci		priv->ops.get_rxd_bnum = get_rx_desc_bnum;
21638c2ecf20Sopenharmony_ci		priv->ops.maybe_stop_tx = hns_nic_maybe_stop_tx;
21648c2ecf20Sopenharmony_ci	} else {
21658c2ecf20Sopenharmony_ci		priv->ops.get_rxd_bnum = get_v2rx_desc_bnum;
21668c2ecf20Sopenharmony_ci		if ((netdev->features & NETIF_F_TSO) ||
21678c2ecf20Sopenharmony_ci		    (netdev->features & NETIF_F_TSO6)) {
21688c2ecf20Sopenharmony_ci			priv->ops.fill_desc = fill_tso_desc;
21698c2ecf20Sopenharmony_ci			priv->ops.maybe_stop_tx = hns_nic_maybe_stop_tso;
21708c2ecf20Sopenharmony_ci			/* This chip only support 7*4096 */
21718c2ecf20Sopenharmony_ci			netif_set_gso_max_size(netdev, 7 * 4096);
21728c2ecf20Sopenharmony_ci		} else {
21738c2ecf20Sopenharmony_ci			priv->ops.fill_desc = fill_v2_desc;
21748c2ecf20Sopenharmony_ci			priv->ops.maybe_stop_tx = hns_nic_maybe_stop_tx;
21758c2ecf20Sopenharmony_ci		}
21768c2ecf20Sopenharmony_ci		/* enable tso when init
21778c2ecf20Sopenharmony_ci		 * control tso on/off through TSE bit in bd
21788c2ecf20Sopenharmony_ci		 */
21798c2ecf20Sopenharmony_ci		h->dev->ops->set_tso_stats(h, 1);
21808c2ecf20Sopenharmony_ci	}
21818c2ecf20Sopenharmony_ci}
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_cistatic int hns_nic_try_get_ae(struct net_device *ndev)
21848c2ecf20Sopenharmony_ci{
21858c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
21868c2ecf20Sopenharmony_ci	struct hnae_handle *h;
21878c2ecf20Sopenharmony_ci	int ret;
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	h = hnae_get_handle(&priv->netdev->dev,
21908c2ecf20Sopenharmony_ci			    priv->fwnode, priv->port_id, NULL);
21918c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(h)) {
21928c2ecf20Sopenharmony_ci		ret = -ENODEV;
21938c2ecf20Sopenharmony_ci		dev_dbg(priv->dev, "has not handle, register notifier!\n");
21948c2ecf20Sopenharmony_ci		goto out;
21958c2ecf20Sopenharmony_ci	}
21968c2ecf20Sopenharmony_ci	priv->ae_handle = h;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	ret = hns_nic_init_phy(ndev, h);
21998c2ecf20Sopenharmony_ci	if (ret) {
22008c2ecf20Sopenharmony_ci		dev_err(priv->dev, "probe phy device fail!\n");
22018c2ecf20Sopenharmony_ci		goto out_init_phy;
22028c2ecf20Sopenharmony_ci	}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	ret = hns_nic_init_ring_data(priv);
22058c2ecf20Sopenharmony_ci	if (ret) {
22068c2ecf20Sopenharmony_ci		ret = -ENOMEM;
22078c2ecf20Sopenharmony_ci		goto out_init_ring_data;
22088c2ecf20Sopenharmony_ci	}
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci	hns_nic_set_priv_ops(ndev);
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	ret = register_netdev(ndev);
22138c2ecf20Sopenharmony_ci	if (ret) {
22148c2ecf20Sopenharmony_ci		dev_err(priv->dev, "probe register netdev fail!\n");
22158c2ecf20Sopenharmony_ci		goto out_reg_ndev_fail;
22168c2ecf20Sopenharmony_ci	}
22178c2ecf20Sopenharmony_ci	return 0;
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ciout_reg_ndev_fail:
22208c2ecf20Sopenharmony_ci	hns_nic_uninit_ring_data(priv);
22218c2ecf20Sopenharmony_ci	priv->ring_data = NULL;
22228c2ecf20Sopenharmony_ciout_init_phy:
22238c2ecf20Sopenharmony_ciout_init_ring_data:
22248c2ecf20Sopenharmony_ci	hnae_put_handle(priv->ae_handle);
22258c2ecf20Sopenharmony_ci	priv->ae_handle = NULL;
22268c2ecf20Sopenharmony_ciout:
22278c2ecf20Sopenharmony_ci	return ret;
22288c2ecf20Sopenharmony_ci}
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_cistatic int hns_nic_notifier_action(struct notifier_block *nb,
22318c2ecf20Sopenharmony_ci				   unsigned long action, void *data)
22328c2ecf20Sopenharmony_ci{
22338c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv =
22348c2ecf20Sopenharmony_ci		container_of(nb, struct hns_nic_priv, notifier_block);
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	assert(action == HNAE_AE_REGISTER);
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci	if (!hns_nic_try_get_ae(priv->netdev)) {
22398c2ecf20Sopenharmony_ci		hnae_unregister_notifier(&priv->notifier_block);
22408c2ecf20Sopenharmony_ci		priv->notifier_block.notifier_call = NULL;
22418c2ecf20Sopenharmony_ci	}
22428c2ecf20Sopenharmony_ci	return 0;
22438c2ecf20Sopenharmony_ci}
22448c2ecf20Sopenharmony_ci
22458c2ecf20Sopenharmony_cistatic int hns_nic_dev_probe(struct platform_device *pdev)
22468c2ecf20Sopenharmony_ci{
22478c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
22488c2ecf20Sopenharmony_ci	struct net_device *ndev;
22498c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv;
22508c2ecf20Sopenharmony_ci	u32 port_id;
22518c2ecf20Sopenharmony_ci	int ret;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	ndev = alloc_etherdev_mq(sizeof(struct hns_nic_priv), NIC_MAX_Q_PER_VF);
22548c2ecf20Sopenharmony_ci	if (!ndev)
22558c2ecf20Sopenharmony_ci		return -ENOMEM;
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, ndev);
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	priv = netdev_priv(ndev);
22608c2ecf20Sopenharmony_ci	priv->dev = dev;
22618c2ecf20Sopenharmony_ci	priv->netdev = ndev;
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	if (dev_of_node(dev)) {
22648c2ecf20Sopenharmony_ci		struct device_node *ae_node;
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci		if (of_device_is_compatible(dev->of_node,
22678c2ecf20Sopenharmony_ci					    "hisilicon,hns-nic-v1"))
22688c2ecf20Sopenharmony_ci			priv->enet_ver = AE_VERSION_1;
22698c2ecf20Sopenharmony_ci		else
22708c2ecf20Sopenharmony_ci			priv->enet_ver = AE_VERSION_2;
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci		ae_node = of_parse_phandle(dev->of_node, "ae-handle", 0);
22738c2ecf20Sopenharmony_ci		if (!ae_node) {
22748c2ecf20Sopenharmony_ci			ret = -ENODEV;
22758c2ecf20Sopenharmony_ci			dev_err(dev, "not find ae-handle\n");
22768c2ecf20Sopenharmony_ci			goto out_read_prop_fail;
22778c2ecf20Sopenharmony_ci		}
22788c2ecf20Sopenharmony_ci		priv->fwnode = &ae_node->fwnode;
22798c2ecf20Sopenharmony_ci	} else if (is_acpi_node(dev->fwnode)) {
22808c2ecf20Sopenharmony_ci		struct fwnode_reference_args args;
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci		if (acpi_dev_found(hns_enet_acpi_match[0].id))
22838c2ecf20Sopenharmony_ci			priv->enet_ver = AE_VERSION_1;
22848c2ecf20Sopenharmony_ci		else if (acpi_dev_found(hns_enet_acpi_match[1].id))
22858c2ecf20Sopenharmony_ci			priv->enet_ver = AE_VERSION_2;
22868c2ecf20Sopenharmony_ci		else {
22878c2ecf20Sopenharmony_ci			ret = -ENXIO;
22888c2ecf20Sopenharmony_ci			goto out_read_prop_fail;
22898c2ecf20Sopenharmony_ci		}
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci		/* try to find port-idx-in-ae first */
22928c2ecf20Sopenharmony_ci		ret = acpi_node_get_property_reference(dev->fwnode,
22938c2ecf20Sopenharmony_ci						       "ae-handle", 0, &args);
22948c2ecf20Sopenharmony_ci		if (ret) {
22958c2ecf20Sopenharmony_ci			dev_err(dev, "not find ae-handle\n");
22968c2ecf20Sopenharmony_ci			goto out_read_prop_fail;
22978c2ecf20Sopenharmony_ci		}
22988c2ecf20Sopenharmony_ci		if (!is_acpi_device_node(args.fwnode)) {
22998c2ecf20Sopenharmony_ci			ret = -EINVAL;
23008c2ecf20Sopenharmony_ci			goto out_read_prop_fail;
23018c2ecf20Sopenharmony_ci		}
23028c2ecf20Sopenharmony_ci		priv->fwnode = args.fwnode;
23038c2ecf20Sopenharmony_ci	} else {
23048c2ecf20Sopenharmony_ci		dev_err(dev, "cannot read cfg data from OF or acpi\n");
23058c2ecf20Sopenharmony_ci		ret = -ENXIO;
23068c2ecf20Sopenharmony_ci		goto out_read_prop_fail;
23078c2ecf20Sopenharmony_ci	}
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	ret = device_property_read_u32(dev, "port-idx-in-ae", &port_id);
23108c2ecf20Sopenharmony_ci	if (ret) {
23118c2ecf20Sopenharmony_ci		/* only for old code compatible */
23128c2ecf20Sopenharmony_ci		ret = device_property_read_u32(dev, "port-id", &port_id);
23138c2ecf20Sopenharmony_ci		if (ret)
23148c2ecf20Sopenharmony_ci			goto out_read_prop_fail;
23158c2ecf20Sopenharmony_ci		/* for old dts, we need to caculate the port offset */
23168c2ecf20Sopenharmony_ci		port_id = port_id < HNS_SRV_OFFSET ? port_id + HNS_DEBUG_OFFSET
23178c2ecf20Sopenharmony_ci			: port_id - HNS_SRV_OFFSET;
23188c2ecf20Sopenharmony_ci	}
23198c2ecf20Sopenharmony_ci	priv->port_id = port_id;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	hns_init_mac_addr(ndev);
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	ndev->watchdog_timeo = HNS_NIC_TX_TIMEOUT;
23248c2ecf20Sopenharmony_ci	ndev->priv_flags |= IFF_UNICAST_FLT;
23258c2ecf20Sopenharmony_ci	ndev->netdev_ops = &hns_nic_netdev_ops;
23268c2ecf20Sopenharmony_ci	hns_ethtool_set_ops(ndev);
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_ci	ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
23298c2ecf20Sopenharmony_ci		NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
23308c2ecf20Sopenharmony_ci		NETIF_F_GRO;
23318c2ecf20Sopenharmony_ci	ndev->vlan_features |=
23328c2ecf20Sopenharmony_ci		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
23338c2ecf20Sopenharmony_ci	ndev->vlan_features |= NETIF_F_SG | NETIF_F_GSO | NETIF_F_GRO;
23348c2ecf20Sopenharmony_ci
23358c2ecf20Sopenharmony_ci	/* MTU range: 68 - 9578 (v1) or 9706 (v2) */
23368c2ecf20Sopenharmony_ci	ndev->min_mtu = MAC_MIN_MTU;
23378c2ecf20Sopenharmony_ci	switch (priv->enet_ver) {
23388c2ecf20Sopenharmony_ci	case AE_VERSION_2:
23398c2ecf20Sopenharmony_ci		ndev->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_NTUPLE;
23408c2ecf20Sopenharmony_ci		ndev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
23418c2ecf20Sopenharmony_ci			NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
23428c2ecf20Sopenharmony_ci			NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6;
23438c2ecf20Sopenharmony_ci		ndev->vlan_features |= NETIF_F_TSO | NETIF_F_TSO6;
23448c2ecf20Sopenharmony_ci		ndev->max_mtu = MAC_MAX_MTU_V2 -
23458c2ecf20Sopenharmony_ci				(ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
23468c2ecf20Sopenharmony_ci		break;
23478c2ecf20Sopenharmony_ci	default:
23488c2ecf20Sopenharmony_ci		ndev->max_mtu = MAC_MAX_MTU -
23498c2ecf20Sopenharmony_ci				(ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
23508c2ecf20Sopenharmony_ci		break;
23518c2ecf20Sopenharmony_ci	}
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(ndev, dev);
23548c2ecf20Sopenharmony_ci
23558c2ecf20Sopenharmony_ci	if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)))
23568c2ecf20Sopenharmony_ci		dev_dbg(dev, "set mask to 64bit\n");
23578c2ecf20Sopenharmony_ci	else
23588c2ecf20Sopenharmony_ci		dev_err(dev, "set mask to 64bit fail!\n");
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	/* carrier off reporting is important to ethtool even BEFORE open */
23618c2ecf20Sopenharmony_ci	netif_carrier_off(ndev);
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci	timer_setup(&priv->service_timer, hns_nic_service_timer, 0);
23648c2ecf20Sopenharmony_ci	INIT_WORK(&priv->service_task, hns_nic_service_task);
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci	set_bit(NIC_STATE_SERVICE_INITED, &priv->state);
23678c2ecf20Sopenharmony_ci	clear_bit(NIC_STATE_SERVICE_SCHED, &priv->state);
23688c2ecf20Sopenharmony_ci	set_bit(NIC_STATE_DOWN, &priv->state);
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci	if (hns_nic_try_get_ae(priv->netdev)) {
23718c2ecf20Sopenharmony_ci		priv->notifier_block.notifier_call = hns_nic_notifier_action;
23728c2ecf20Sopenharmony_ci		ret = hnae_register_notifier(&priv->notifier_block);
23738c2ecf20Sopenharmony_ci		if (ret) {
23748c2ecf20Sopenharmony_ci			dev_err(dev, "register notifier fail!\n");
23758c2ecf20Sopenharmony_ci			goto out_notify_fail;
23768c2ecf20Sopenharmony_ci		}
23778c2ecf20Sopenharmony_ci		dev_dbg(dev, "has not handle, register notifier!\n");
23788c2ecf20Sopenharmony_ci	}
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci	return 0;
23818c2ecf20Sopenharmony_ci
23828c2ecf20Sopenharmony_ciout_notify_fail:
23838c2ecf20Sopenharmony_ci	(void)cancel_work_sync(&priv->service_task);
23848c2ecf20Sopenharmony_ciout_read_prop_fail:
23858c2ecf20Sopenharmony_ci	/* safe for ACPI FW */
23868c2ecf20Sopenharmony_ci	of_node_put(to_of_node(priv->fwnode));
23878c2ecf20Sopenharmony_ci	free_netdev(ndev);
23888c2ecf20Sopenharmony_ci	return ret;
23898c2ecf20Sopenharmony_ci}
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_cistatic int hns_nic_dev_remove(struct platform_device *pdev)
23928c2ecf20Sopenharmony_ci{
23938c2ecf20Sopenharmony_ci	struct net_device *ndev = platform_get_drvdata(pdev);
23948c2ecf20Sopenharmony_ci	struct hns_nic_priv *priv = netdev_priv(ndev);
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	if (ndev->reg_state != NETREG_UNINITIALIZED)
23978c2ecf20Sopenharmony_ci		unregister_netdev(ndev);
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	if (priv->ring_data)
24008c2ecf20Sopenharmony_ci		hns_nic_uninit_ring_data(priv);
24018c2ecf20Sopenharmony_ci	priv->ring_data = NULL;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci	if (ndev->phydev)
24048c2ecf20Sopenharmony_ci		phy_disconnect(ndev->phydev);
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(priv->ae_handle))
24078c2ecf20Sopenharmony_ci		hnae_put_handle(priv->ae_handle);
24088c2ecf20Sopenharmony_ci	priv->ae_handle = NULL;
24098c2ecf20Sopenharmony_ci	if (priv->notifier_block.notifier_call)
24108c2ecf20Sopenharmony_ci		hnae_unregister_notifier(&priv->notifier_block);
24118c2ecf20Sopenharmony_ci	priv->notifier_block.notifier_call = NULL;
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	set_bit(NIC_STATE_REMOVING, &priv->state);
24148c2ecf20Sopenharmony_ci	(void)cancel_work_sync(&priv->service_task);
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	/* safe for ACPI FW */
24178c2ecf20Sopenharmony_ci	of_node_put(to_of_node(priv->fwnode));
24188c2ecf20Sopenharmony_ci
24198c2ecf20Sopenharmony_ci	free_netdev(ndev);
24208c2ecf20Sopenharmony_ci	return 0;
24218c2ecf20Sopenharmony_ci}
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_cistatic const struct of_device_id hns_enet_of_match[] = {
24248c2ecf20Sopenharmony_ci	{.compatible = "hisilicon,hns-nic-v1",},
24258c2ecf20Sopenharmony_ci	{.compatible = "hisilicon,hns-nic-v2",},
24268c2ecf20Sopenharmony_ci	{},
24278c2ecf20Sopenharmony_ci};
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, hns_enet_of_match);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_cistatic struct platform_driver hns_nic_dev_driver = {
24328c2ecf20Sopenharmony_ci	.driver = {
24338c2ecf20Sopenharmony_ci		.name = "hns-nic",
24348c2ecf20Sopenharmony_ci		.of_match_table = hns_enet_of_match,
24358c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(hns_enet_acpi_match),
24368c2ecf20Sopenharmony_ci	},
24378c2ecf20Sopenharmony_ci	.probe = hns_nic_dev_probe,
24388c2ecf20Sopenharmony_ci	.remove = hns_nic_dev_remove,
24398c2ecf20Sopenharmony_ci};
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_cimodule_platform_driver(hns_nic_dev_driver);
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HISILICON HNS Ethernet driver");
24448c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hisilicon, Inc.");
24458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
24468c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:hns-nic");
2447