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