162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/* Qualcomm Technologies, Inc. EMAC Ethernet Controller MAC layer support
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/tcp.h>
962306a36Sopenharmony_ci#include <linux/ip.h>
1062306a36Sopenharmony_ci#include <linux/ipv6.h>
1162306a36Sopenharmony_ci#include <linux/crc32.h>
1262306a36Sopenharmony_ci#include <linux/if_vlan.h>
1362306a36Sopenharmony_ci#include <linux/jiffies.h>
1462306a36Sopenharmony_ci#include <linux/phy.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <net/ip6_checksum.h>
1762306a36Sopenharmony_ci#include "emac.h"
1862306a36Sopenharmony_ci#include "emac-sgmii.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* EMAC_MAC_CTRL */
2162306a36Sopenharmony_ci#define SINGLE_PAUSE_MODE       	0x10000000
2262306a36Sopenharmony_ci#define DEBUG_MODE                      0x08000000
2362306a36Sopenharmony_ci#define BROAD_EN                        0x04000000
2462306a36Sopenharmony_ci#define MULTI_ALL                       0x02000000
2562306a36Sopenharmony_ci#define RX_CHKSUM_EN                    0x01000000
2662306a36Sopenharmony_ci#define HUGE                            0x00800000
2762306a36Sopenharmony_ci#define SPEED(x)			(((x) & 0x3) << 20)
2862306a36Sopenharmony_ci#define SPEED_MASK			SPEED(0x3)
2962306a36Sopenharmony_ci#define SIMR                            0x00080000
3062306a36Sopenharmony_ci#define TPAUSE                          0x00010000
3162306a36Sopenharmony_ci#define PROM_MODE                       0x00008000
3262306a36Sopenharmony_ci#define VLAN_STRIP                      0x00004000
3362306a36Sopenharmony_ci#define PRLEN_BMSK                      0x00003c00
3462306a36Sopenharmony_ci#define PRLEN_SHFT                      10
3562306a36Sopenharmony_ci#define HUGEN                           0x00000200
3662306a36Sopenharmony_ci#define FLCHK                           0x00000100
3762306a36Sopenharmony_ci#define PCRCE                           0x00000080
3862306a36Sopenharmony_ci#define CRCE                            0x00000040
3962306a36Sopenharmony_ci#define FULLD                           0x00000020
4062306a36Sopenharmony_ci#define MAC_LP_EN                       0x00000010
4162306a36Sopenharmony_ci#define RXFC                            0x00000008
4262306a36Sopenharmony_ci#define TXFC                            0x00000004
4362306a36Sopenharmony_ci#define RXEN                            0x00000002
4462306a36Sopenharmony_ci#define TXEN                            0x00000001
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/* EMAC_DESC_CTRL_3 */
4762306a36Sopenharmony_ci#define RFD_RING_SIZE_BMSK                                       0xfff
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* EMAC_DESC_CTRL_4 */
5062306a36Sopenharmony_ci#define RX_BUFFER_SIZE_BMSK                                     0xffff
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* EMAC_DESC_CTRL_6 */
5362306a36Sopenharmony_ci#define RRD_RING_SIZE_BMSK                                       0xfff
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* EMAC_DESC_CTRL_9 */
5662306a36Sopenharmony_ci#define TPD_RING_SIZE_BMSK                                      0xffff
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* EMAC_TXQ_CTRL_0 */
5962306a36Sopenharmony_ci#define NUM_TXF_BURST_PREF_BMSK                             0xffff0000
6062306a36Sopenharmony_ci#define NUM_TXF_BURST_PREF_SHFT                                     16
6162306a36Sopenharmony_ci#define LS_8023_SP                                                0x80
6262306a36Sopenharmony_ci#define TXQ_MODE                                                  0x40
6362306a36Sopenharmony_ci#define TXQ_EN                                                    0x20
6462306a36Sopenharmony_ci#define IP_OP_SP                                                  0x10
6562306a36Sopenharmony_ci#define NUM_TPD_BURST_PREF_BMSK                                    0xf
6662306a36Sopenharmony_ci#define NUM_TPD_BURST_PREF_SHFT                                      0
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* EMAC_TXQ_CTRL_1 */
6962306a36Sopenharmony_ci#define JUMBO_TASK_OFFLOAD_THRESHOLD_BMSK                        0x7ff
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* EMAC_TXQ_CTRL_2 */
7262306a36Sopenharmony_ci#define TXF_HWM_BMSK                                         0xfff0000
7362306a36Sopenharmony_ci#define TXF_LWM_BMSK                                             0xfff
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* EMAC_RXQ_CTRL_0 */
7662306a36Sopenharmony_ci#define RXQ_EN                                                 BIT(31)
7762306a36Sopenharmony_ci#define CUT_THRU_EN                                            BIT(30)
7862306a36Sopenharmony_ci#define RSS_HASH_EN                                            BIT(29)
7962306a36Sopenharmony_ci#define NUM_RFD_BURST_PREF_BMSK                              0x3f00000
8062306a36Sopenharmony_ci#define NUM_RFD_BURST_PREF_SHFT                                     20
8162306a36Sopenharmony_ci#define IDT_TABLE_SIZE_BMSK                                    0x1ff00
8262306a36Sopenharmony_ci#define IDT_TABLE_SIZE_SHFT                                          8
8362306a36Sopenharmony_ci#define SP_IPV6                                                   0x80
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* EMAC_RXQ_CTRL_1 */
8662306a36Sopenharmony_ci#define JUMBO_1KAH_BMSK                                         0xf000
8762306a36Sopenharmony_ci#define JUMBO_1KAH_SHFT                                             12
8862306a36Sopenharmony_ci#define RFD_PREF_LOW_TH                                           0x10
8962306a36Sopenharmony_ci#define RFD_PREF_LOW_THRESHOLD_BMSK                              0xfc0
9062306a36Sopenharmony_ci#define RFD_PREF_LOW_THRESHOLD_SHFT                                  6
9162306a36Sopenharmony_ci#define RFD_PREF_UP_TH                                            0x10
9262306a36Sopenharmony_ci#define RFD_PREF_UP_THRESHOLD_BMSK                                0x3f
9362306a36Sopenharmony_ci#define RFD_PREF_UP_THRESHOLD_SHFT                                   0
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* EMAC_RXQ_CTRL_2 */
9662306a36Sopenharmony_ci#define RXF_DOF_THRESFHOLD                                       0x1a0
9762306a36Sopenharmony_ci#define RXF_DOF_THRESHOLD_BMSK                               0xfff0000
9862306a36Sopenharmony_ci#define RXF_DOF_THRESHOLD_SHFT                                      16
9962306a36Sopenharmony_ci#define RXF_UOF_THRESFHOLD                                        0xbe
10062306a36Sopenharmony_ci#define RXF_UOF_THRESHOLD_BMSK                                   0xfff
10162306a36Sopenharmony_ci#define RXF_UOF_THRESHOLD_SHFT                                       0
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* EMAC_RXQ_CTRL_3 */
10462306a36Sopenharmony_ci#define RXD_TIMER_BMSK                                      0xffff0000
10562306a36Sopenharmony_ci#define RXD_THRESHOLD_BMSK                                       0xfff
10662306a36Sopenharmony_ci#define RXD_THRESHOLD_SHFT                                           0
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/* EMAC_DMA_CTRL */
10962306a36Sopenharmony_ci#define DMAW_DLY_CNT_BMSK                                      0xf0000
11062306a36Sopenharmony_ci#define DMAW_DLY_CNT_SHFT                                           16
11162306a36Sopenharmony_ci#define DMAR_DLY_CNT_BMSK                                       0xf800
11262306a36Sopenharmony_ci#define DMAR_DLY_CNT_SHFT                                           11
11362306a36Sopenharmony_ci#define DMAR_REQ_PRI                                             0x400
11462306a36Sopenharmony_ci#define REGWRBLEN_BMSK                                           0x380
11562306a36Sopenharmony_ci#define REGWRBLEN_SHFT                                               7
11662306a36Sopenharmony_ci#define REGRDBLEN_BMSK                                            0x70
11762306a36Sopenharmony_ci#define REGRDBLEN_SHFT                                               4
11862306a36Sopenharmony_ci#define OUT_ORDER_MODE                                             0x4
11962306a36Sopenharmony_ci#define ENH_ORDER_MODE                                             0x2
12062306a36Sopenharmony_ci#define IN_ORDER_MODE                                              0x1
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* EMAC_MAILBOX_13 */
12362306a36Sopenharmony_ci#define RFD3_PROC_IDX_BMSK                                   0xfff0000
12462306a36Sopenharmony_ci#define RFD3_PROC_IDX_SHFT                                          16
12562306a36Sopenharmony_ci#define RFD3_PROD_IDX_BMSK                                       0xfff
12662306a36Sopenharmony_ci#define RFD3_PROD_IDX_SHFT                                           0
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* EMAC_MAILBOX_2 */
12962306a36Sopenharmony_ci#define NTPD_CONS_IDX_BMSK                                  0xffff0000
13062306a36Sopenharmony_ci#define NTPD_CONS_IDX_SHFT                                          16
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/* EMAC_MAILBOX_3 */
13362306a36Sopenharmony_ci#define RFD0_CONS_IDX_BMSK                                       0xfff
13462306a36Sopenharmony_ci#define RFD0_CONS_IDX_SHFT                                           0
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* EMAC_MAILBOX_11 */
13762306a36Sopenharmony_ci#define H3TPD_PROD_IDX_BMSK                                 0xffff0000
13862306a36Sopenharmony_ci#define H3TPD_PROD_IDX_SHFT                                         16
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* EMAC_AXI_MAST_CTRL */
14162306a36Sopenharmony_ci#define DATA_BYTE_SWAP                                             0x8
14262306a36Sopenharmony_ci#define MAX_BOUND                                                  0x2
14362306a36Sopenharmony_ci#define MAX_BTYPE                                                  0x1
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci/* EMAC_MAILBOX_12 */
14662306a36Sopenharmony_ci#define H3TPD_CONS_IDX_BMSK                                 0xffff0000
14762306a36Sopenharmony_ci#define H3TPD_CONS_IDX_SHFT                                         16
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/* EMAC_MAILBOX_9 */
15062306a36Sopenharmony_ci#define H2TPD_PROD_IDX_BMSK                                     0xffff
15162306a36Sopenharmony_ci#define H2TPD_PROD_IDX_SHFT                                          0
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci/* EMAC_MAILBOX_10 */
15462306a36Sopenharmony_ci#define H1TPD_CONS_IDX_BMSK                                 0xffff0000
15562306a36Sopenharmony_ci#define H1TPD_CONS_IDX_SHFT                                         16
15662306a36Sopenharmony_ci#define H2TPD_CONS_IDX_BMSK                                     0xffff
15762306a36Sopenharmony_ci#define H2TPD_CONS_IDX_SHFT                                          0
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/* EMAC_ATHR_HEADER_CTRL */
16062306a36Sopenharmony_ci#define HEADER_CNT_EN                                              0x2
16162306a36Sopenharmony_ci#define HEADER_ENABLE                                              0x1
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/* EMAC_MAILBOX_0 */
16462306a36Sopenharmony_ci#define RFD0_PROC_IDX_BMSK                                   0xfff0000
16562306a36Sopenharmony_ci#define RFD0_PROC_IDX_SHFT                                          16
16662306a36Sopenharmony_ci#define RFD0_PROD_IDX_BMSK                                       0xfff
16762306a36Sopenharmony_ci#define RFD0_PROD_IDX_SHFT                                           0
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/* EMAC_MAILBOX_5 */
17062306a36Sopenharmony_ci#define RFD1_PROC_IDX_BMSK                                   0xfff0000
17162306a36Sopenharmony_ci#define RFD1_PROC_IDX_SHFT                                          16
17262306a36Sopenharmony_ci#define RFD1_PROD_IDX_BMSK                                       0xfff
17362306a36Sopenharmony_ci#define RFD1_PROD_IDX_SHFT                                           0
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/* EMAC_MISC_CTRL */
17662306a36Sopenharmony_ci#define RX_UNCPL_INT_EN                                            0x1
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/* EMAC_MAILBOX_7 */
17962306a36Sopenharmony_ci#define RFD2_CONS_IDX_BMSK                                   0xfff0000
18062306a36Sopenharmony_ci#define RFD2_CONS_IDX_SHFT                                          16
18162306a36Sopenharmony_ci#define RFD1_CONS_IDX_BMSK                                       0xfff
18262306a36Sopenharmony_ci#define RFD1_CONS_IDX_SHFT                                           0
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/* EMAC_MAILBOX_8 */
18562306a36Sopenharmony_ci#define RFD3_CONS_IDX_BMSK                                       0xfff
18662306a36Sopenharmony_ci#define RFD3_CONS_IDX_SHFT                                           0
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/* EMAC_MAILBOX_15 */
18962306a36Sopenharmony_ci#define NTPD_PROD_IDX_BMSK                                      0xffff
19062306a36Sopenharmony_ci#define NTPD_PROD_IDX_SHFT                                           0
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/* EMAC_MAILBOX_16 */
19362306a36Sopenharmony_ci#define H1TPD_PROD_IDX_BMSK                                     0xffff
19462306a36Sopenharmony_ci#define H1TPD_PROD_IDX_SHFT                                          0
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci#define RXQ0_RSS_HSTYP_IPV6_TCP_EN                                0x20
19762306a36Sopenharmony_ci#define RXQ0_RSS_HSTYP_IPV6_EN                                    0x10
19862306a36Sopenharmony_ci#define RXQ0_RSS_HSTYP_IPV4_TCP_EN                                 0x8
19962306a36Sopenharmony_ci#define RXQ0_RSS_HSTYP_IPV4_EN                                     0x4
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* EMAC_EMAC_WRAPPER_TX_TS_INX */
20262306a36Sopenharmony_ci#define EMAC_WRAPPER_TX_TS_EMPTY                               BIT(31)
20362306a36Sopenharmony_ci#define EMAC_WRAPPER_TX_TS_INX_BMSK                             0xffff
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistruct emac_skb_cb {
20662306a36Sopenharmony_ci	u32           tpd_idx;
20762306a36Sopenharmony_ci	unsigned long jiffies;
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci#define EMAC_SKB_CB(skb)	((struct emac_skb_cb *)(skb)->cb)
21162306a36Sopenharmony_ci#define EMAC_RSS_IDT_SIZE	256
21262306a36Sopenharmony_ci#define JUMBO_1KAH		0x4
21362306a36Sopenharmony_ci#define RXD_TH			0x100
21462306a36Sopenharmony_ci#define EMAC_TPD_LAST_FRAGMENT	0x80000000
21562306a36Sopenharmony_ci#define EMAC_TPD_TSTAMP_SAVE	0x80000000
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/* EMAC Errors in emac_rrd.word[3] */
21862306a36Sopenharmony_ci#define EMAC_RRD_L4F		BIT(14)
21962306a36Sopenharmony_ci#define EMAC_RRD_IPF		BIT(15)
22062306a36Sopenharmony_ci#define EMAC_RRD_CRC		BIT(21)
22162306a36Sopenharmony_ci#define EMAC_RRD_FAE		BIT(22)
22262306a36Sopenharmony_ci#define EMAC_RRD_TRN		BIT(23)
22362306a36Sopenharmony_ci#define EMAC_RRD_RNT		BIT(24)
22462306a36Sopenharmony_ci#define EMAC_RRD_INC		BIT(25)
22562306a36Sopenharmony_ci#define EMAC_RRD_FOV		BIT(29)
22662306a36Sopenharmony_ci#define EMAC_RRD_LEN		BIT(30)
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/* Error bits that will result in a received frame being discarded */
22962306a36Sopenharmony_ci#define EMAC_RRD_ERROR (EMAC_RRD_IPF | EMAC_RRD_CRC | EMAC_RRD_FAE | \
23062306a36Sopenharmony_ci			EMAC_RRD_TRN | EMAC_RRD_RNT | EMAC_RRD_INC | \
23162306a36Sopenharmony_ci			EMAC_RRD_FOV | EMAC_RRD_LEN)
23262306a36Sopenharmony_ci#define EMAC_RRD_STATS_DW_IDX 3
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci#define EMAC_RRD(RXQ, SIZE, IDX)	((RXQ)->rrd.v_addr + (SIZE * (IDX)))
23562306a36Sopenharmony_ci#define EMAC_RFD(RXQ, SIZE, IDX)	((RXQ)->rfd.v_addr + (SIZE * (IDX)))
23662306a36Sopenharmony_ci#define EMAC_TPD(TXQ, SIZE, IDX)	((TXQ)->tpd.v_addr + (SIZE * (IDX)))
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#define GET_RFD_BUFFER(RXQ, IDX)	(&((RXQ)->rfd.rfbuff[(IDX)]))
23962306a36Sopenharmony_ci#define GET_TPD_BUFFER(RTQ, IDX)	(&((RTQ)->tpd.tpbuff[(IDX)]))
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#define EMAC_TX_POLL_HWTXTSTAMP_THRESHOLD	8
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci#define ISR_RX_PKT      (\
24462306a36Sopenharmony_ci	RX_PKT_INT0     |\
24562306a36Sopenharmony_ci	RX_PKT_INT1     |\
24662306a36Sopenharmony_ci	RX_PKT_INT2     |\
24762306a36Sopenharmony_ci	RX_PKT_INT3)
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_civoid emac_mac_multicast_addr_set(struct emac_adapter *adpt, u8 *addr)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	u32 crc32, bit, reg, mta;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Calculate the CRC of the MAC address */
25462306a36Sopenharmony_ci	crc32 = ether_crc(ETH_ALEN, addr);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/* The HASH Table is an array of 2 32-bit registers. It is
25762306a36Sopenharmony_ci	 * treated like an array of 64 bits (BitArray[hash_value]).
25862306a36Sopenharmony_ci	 * Use the upper 6 bits of the above CRC as the hash value.
25962306a36Sopenharmony_ci	 */
26062306a36Sopenharmony_ci	reg = (crc32 >> 31) & 0x1;
26162306a36Sopenharmony_ci	bit = (crc32 >> 26) & 0x1F;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	mta = readl(adpt->base + EMAC_HASH_TAB_REG0 + (reg << 2));
26462306a36Sopenharmony_ci	mta |= BIT(bit);
26562306a36Sopenharmony_ci	writel(mta, adpt->base + EMAC_HASH_TAB_REG0 + (reg << 2));
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_civoid emac_mac_multicast_addr_clear(struct emac_adapter *adpt)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	writel(0, adpt->base + EMAC_HASH_TAB_REG0);
27162306a36Sopenharmony_ci	writel(0, adpt->base + EMAC_HASH_TAB_REG1);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/* definitions for RSS */
27562306a36Sopenharmony_ci#define EMAC_RSS_KEY(_i, _type) \
27662306a36Sopenharmony_ci		(EMAC_RSS_KEY0 + ((_i) * sizeof(_type)))
27762306a36Sopenharmony_ci#define EMAC_RSS_TBL(_i, _type) \
27862306a36Sopenharmony_ci		(EMAC_IDT_TABLE0 + ((_i) * sizeof(_type)))
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci/* Config MAC modes */
28162306a36Sopenharmony_civoid emac_mac_mode_config(struct emac_adapter *adpt)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct net_device *netdev = adpt->netdev;
28462306a36Sopenharmony_ci	u32 mac;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	mac = readl(adpt->base + EMAC_MAC_CTRL);
28762306a36Sopenharmony_ci	mac &= ~(VLAN_STRIP | PROM_MODE | MULTI_ALL | MAC_LP_EN);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
29062306a36Sopenharmony_ci		mac |= VLAN_STRIP;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (netdev->flags & IFF_PROMISC)
29362306a36Sopenharmony_ci		mac |= PROM_MODE;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (netdev->flags & IFF_ALLMULTI)
29662306a36Sopenharmony_ci		mac |= MULTI_ALL;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	writel(mac, adpt->base + EMAC_MAC_CTRL);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci/* Config descriptor rings */
30262306a36Sopenharmony_cistatic void emac_mac_dma_rings_config(struct emac_adapter *adpt)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	/* TPD (Transmit Packet Descriptor) */
30562306a36Sopenharmony_ci	writel(upper_32_bits(adpt->tx_q.tpd.dma_addr),
30662306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_1);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	writel(lower_32_bits(adpt->tx_q.tpd.dma_addr),
30962306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_8);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	writel(adpt->tx_q.tpd.count & TPD_RING_SIZE_BMSK,
31262306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_9);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* RFD (Receive Free Descriptor) & RRD (Receive Return Descriptor) */
31562306a36Sopenharmony_ci	writel(upper_32_bits(adpt->rx_q.rfd.dma_addr),
31662306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_0);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	writel(lower_32_bits(adpt->rx_q.rfd.dma_addr),
31962306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_2);
32062306a36Sopenharmony_ci	writel(lower_32_bits(adpt->rx_q.rrd.dma_addr),
32162306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_5);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	writel(adpt->rx_q.rfd.count & RFD_RING_SIZE_BMSK,
32462306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_3);
32562306a36Sopenharmony_ci	writel(adpt->rx_q.rrd.count & RRD_RING_SIZE_BMSK,
32662306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_6);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	writel(adpt->rxbuf_size & RX_BUFFER_SIZE_BMSK,
32962306a36Sopenharmony_ci	       adpt->base + EMAC_DESC_CTRL_4);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	writel(0, adpt->base + EMAC_DESC_CTRL_11);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Load all of the base addresses above and ensure that triggering HW to
33462306a36Sopenharmony_ci	 * read ring pointers is flushed
33562306a36Sopenharmony_ci	 */
33662306a36Sopenharmony_ci	writel(1, adpt->base + EMAC_INTER_SRAM_PART9);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci/* Config transmit parameters */
34062306a36Sopenharmony_cistatic void emac_mac_tx_config(struct emac_adapter *adpt)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	u32 val;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	writel((EMAC_MAX_TX_OFFLOAD_THRESH >> 3) &
34562306a36Sopenharmony_ci	       JUMBO_TASK_OFFLOAD_THRESHOLD_BMSK, adpt->base + EMAC_TXQ_CTRL_1);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	val = (adpt->tpd_burst << NUM_TPD_BURST_PREF_SHFT) &
34862306a36Sopenharmony_ci	       NUM_TPD_BURST_PREF_BMSK;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	val |= TXQ_MODE | LS_8023_SP;
35162306a36Sopenharmony_ci	val |= (0x0100 << NUM_TXF_BURST_PREF_SHFT) &
35262306a36Sopenharmony_ci		NUM_TXF_BURST_PREF_BMSK;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	writel(val, adpt->base + EMAC_TXQ_CTRL_0);
35562306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_TXQ_CTRL_2,
35662306a36Sopenharmony_ci			  (TXF_HWM_BMSK | TXF_LWM_BMSK), 0);
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci/* Config receive parameters */
36062306a36Sopenharmony_cistatic void emac_mac_rx_config(struct emac_adapter *adpt)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	u32 val;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	val = (adpt->rfd_burst << NUM_RFD_BURST_PREF_SHFT) &
36562306a36Sopenharmony_ci	       NUM_RFD_BURST_PREF_BMSK;
36662306a36Sopenharmony_ci	val |= (SP_IPV6 | CUT_THRU_EN);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	writel(val, adpt->base + EMAC_RXQ_CTRL_0);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	val = readl(adpt->base + EMAC_RXQ_CTRL_1);
37162306a36Sopenharmony_ci	val &= ~(JUMBO_1KAH_BMSK | RFD_PREF_LOW_THRESHOLD_BMSK |
37262306a36Sopenharmony_ci		 RFD_PREF_UP_THRESHOLD_BMSK);
37362306a36Sopenharmony_ci	val |= (JUMBO_1KAH << JUMBO_1KAH_SHFT) |
37462306a36Sopenharmony_ci		(RFD_PREF_LOW_TH << RFD_PREF_LOW_THRESHOLD_SHFT) |
37562306a36Sopenharmony_ci		(RFD_PREF_UP_TH  << RFD_PREF_UP_THRESHOLD_SHFT);
37662306a36Sopenharmony_ci	writel(val, adpt->base + EMAC_RXQ_CTRL_1);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	val = readl(adpt->base + EMAC_RXQ_CTRL_2);
37962306a36Sopenharmony_ci	val &= ~(RXF_DOF_THRESHOLD_BMSK | RXF_UOF_THRESHOLD_BMSK);
38062306a36Sopenharmony_ci	val |= (RXF_DOF_THRESFHOLD  << RXF_DOF_THRESHOLD_SHFT) |
38162306a36Sopenharmony_ci		(RXF_UOF_THRESFHOLD << RXF_UOF_THRESHOLD_SHFT);
38262306a36Sopenharmony_ci	writel(val, adpt->base + EMAC_RXQ_CTRL_2);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	val = readl(adpt->base + EMAC_RXQ_CTRL_3);
38562306a36Sopenharmony_ci	val &= ~(RXD_TIMER_BMSK | RXD_THRESHOLD_BMSK);
38662306a36Sopenharmony_ci	val |= RXD_TH << RXD_THRESHOLD_SHFT;
38762306a36Sopenharmony_ci	writel(val, adpt->base + EMAC_RXQ_CTRL_3);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci/* Config dma */
39162306a36Sopenharmony_cistatic void emac_mac_dma_config(struct emac_adapter *adpt)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	u32 dma_ctrl = DMAR_REQ_PRI;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	switch (adpt->dma_order) {
39662306a36Sopenharmony_ci	case emac_dma_ord_in:
39762306a36Sopenharmony_ci		dma_ctrl |= IN_ORDER_MODE;
39862306a36Sopenharmony_ci		break;
39962306a36Sopenharmony_ci	case emac_dma_ord_enh:
40062306a36Sopenharmony_ci		dma_ctrl |= ENH_ORDER_MODE;
40162306a36Sopenharmony_ci		break;
40262306a36Sopenharmony_ci	case emac_dma_ord_out:
40362306a36Sopenharmony_ci		dma_ctrl |= OUT_ORDER_MODE;
40462306a36Sopenharmony_ci		break;
40562306a36Sopenharmony_ci	default:
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	dma_ctrl |= (((u32)adpt->dmar_block) << REGRDBLEN_SHFT) &
41062306a36Sopenharmony_ci						REGRDBLEN_BMSK;
41162306a36Sopenharmony_ci	dma_ctrl |= (((u32)adpt->dmaw_block) << REGWRBLEN_SHFT) &
41262306a36Sopenharmony_ci						REGWRBLEN_BMSK;
41362306a36Sopenharmony_ci	dma_ctrl |= (((u32)adpt->dmar_dly_cnt) << DMAR_DLY_CNT_SHFT) &
41462306a36Sopenharmony_ci						DMAR_DLY_CNT_BMSK;
41562306a36Sopenharmony_ci	dma_ctrl |= (((u32)adpt->dmaw_dly_cnt) << DMAW_DLY_CNT_SHFT) &
41662306a36Sopenharmony_ci						DMAW_DLY_CNT_BMSK;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* config DMA and ensure that configuration is flushed to HW */
41962306a36Sopenharmony_ci	writel(dma_ctrl, adpt->base + EMAC_DMA_CTRL);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/* set MAC address */
42362306a36Sopenharmony_cistatic void emac_set_mac_address(struct emac_adapter *adpt, const u8 *addr)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	u32 sta;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* for example: 00-A0-C6-11-22-33
42862306a36Sopenharmony_ci	 * 0<-->C6112233, 1<-->00A0.
42962306a36Sopenharmony_ci	 */
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/* low 32bit word */
43262306a36Sopenharmony_ci	sta = (((u32)addr[2]) << 24) | (((u32)addr[3]) << 16) |
43362306a36Sopenharmony_ci	      (((u32)addr[4]) << 8)  | (((u32)addr[5]));
43462306a36Sopenharmony_ci	writel(sta, adpt->base + EMAC_MAC_STA_ADDR0);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* hight 32bit word */
43762306a36Sopenharmony_ci	sta = (((u32)addr[0]) << 8) | (u32)addr[1];
43862306a36Sopenharmony_ci	writel(sta, adpt->base + EMAC_MAC_STA_ADDR1);
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic void emac_mac_config(struct emac_adapter *adpt)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct net_device *netdev = adpt->netdev;
44462306a36Sopenharmony_ci	unsigned int max_frame;
44562306a36Sopenharmony_ci	u32 val;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	emac_set_mac_address(adpt, netdev->dev_addr);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
45062306a36Sopenharmony_ci	adpt->rxbuf_size = netdev->mtu > EMAC_DEF_RX_BUF_SIZE ?
45162306a36Sopenharmony_ci		ALIGN(max_frame, 8) : EMAC_DEF_RX_BUF_SIZE;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	emac_mac_dma_rings_config(adpt);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	writel(netdev->mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN,
45662306a36Sopenharmony_ci	       adpt->base + EMAC_MAX_FRAM_LEN_CTRL);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	emac_mac_tx_config(adpt);
45962306a36Sopenharmony_ci	emac_mac_rx_config(adpt);
46062306a36Sopenharmony_ci	emac_mac_dma_config(adpt);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	val = readl(adpt->base + EMAC_AXI_MAST_CTRL);
46362306a36Sopenharmony_ci	val &= ~(DATA_BYTE_SWAP | MAX_BOUND);
46462306a36Sopenharmony_ci	val |= MAX_BTYPE;
46562306a36Sopenharmony_ci	writel(val, adpt->base + EMAC_AXI_MAST_CTRL);
46662306a36Sopenharmony_ci	writel(0, adpt->base + EMAC_CLK_GATE_CTRL);
46762306a36Sopenharmony_ci	writel(RX_UNCPL_INT_EN, adpt->base + EMAC_MISC_CTRL);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_civoid emac_mac_reset(struct emac_adapter *adpt)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	emac_mac_stop(adpt);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_DMA_MAS_CTRL, 0, SOFT_RST);
47562306a36Sopenharmony_ci	usleep_range(100, 150); /* reset may take up to 100usec */
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* interrupt clear-on-read */
47862306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_DMA_MAS_CTRL, 0, INT_RD_CLR_EN);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic void emac_mac_start(struct emac_adapter *adpt)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct phy_device *phydev = adpt->phydev;
48462306a36Sopenharmony_ci	u32 mac, csr1;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	/* enable tx queue */
48762306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_TXQ_CTRL_0, 0, TXQ_EN);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* enable rx queue */
49062306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_RXQ_CTRL_0, 0, RXQ_EN);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* enable mac control */
49362306a36Sopenharmony_ci	mac = readl(adpt->base + EMAC_MAC_CTRL);
49462306a36Sopenharmony_ci	csr1 = readl(adpt->csr + EMAC_EMAC_WRAPPER_CSR1);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	mac |= TXEN | RXEN;     /* enable RX/TX */
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	/* Configure MAC flow control. If set to automatic, then match
49962306a36Sopenharmony_ci	 * whatever the PHY does. Otherwise, enable or disable it, depending
50062306a36Sopenharmony_ci	 * on what the user configured via ethtool.
50162306a36Sopenharmony_ci	 */
50262306a36Sopenharmony_ci	mac &= ~(RXFC | TXFC);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (adpt->automatic) {
50562306a36Sopenharmony_ci		/* If it's set to automatic, then update our local values */
50662306a36Sopenharmony_ci		adpt->rx_flow_control = phydev->pause;
50762306a36Sopenharmony_ci		adpt->tx_flow_control = phydev->pause != phydev->asym_pause;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	mac |= adpt->rx_flow_control ? RXFC : 0;
51062306a36Sopenharmony_ci	mac |= adpt->tx_flow_control ? TXFC : 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* setup link speed */
51362306a36Sopenharmony_ci	mac &= ~SPEED_MASK;
51462306a36Sopenharmony_ci	if (phydev->speed == SPEED_1000) {
51562306a36Sopenharmony_ci		mac |= SPEED(2);
51662306a36Sopenharmony_ci		csr1 |= FREQ_MODE;
51762306a36Sopenharmony_ci	} else {
51862306a36Sopenharmony_ci		mac |= SPEED(1);
51962306a36Sopenharmony_ci		csr1 &= ~FREQ_MODE;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	if (phydev->duplex == DUPLEX_FULL)
52362306a36Sopenharmony_ci		mac |= FULLD;
52462306a36Sopenharmony_ci	else
52562306a36Sopenharmony_ci		mac &= ~FULLD;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	/* other parameters */
52862306a36Sopenharmony_ci	mac |= (CRCE | PCRCE);
52962306a36Sopenharmony_ci	mac |= ((adpt->preamble << PRLEN_SHFT) & PRLEN_BMSK);
53062306a36Sopenharmony_ci	mac |= BROAD_EN;
53162306a36Sopenharmony_ci	mac |= FLCHK;
53262306a36Sopenharmony_ci	mac &= ~RX_CHKSUM_EN;
53362306a36Sopenharmony_ci	mac &= ~(HUGEN | VLAN_STRIP | TPAUSE | SIMR | HUGE | MULTI_ALL |
53462306a36Sopenharmony_ci		 DEBUG_MODE | SINGLE_PAUSE_MODE);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Enable single-pause-frame mode if requested.
53762306a36Sopenharmony_ci	 *
53862306a36Sopenharmony_ci	 * If enabled, the EMAC will send a single pause frame when the RX
53962306a36Sopenharmony_ci	 * queue is full.  This normally leads to packet loss because
54062306a36Sopenharmony_ci	 * the pause frame disables the remote MAC only for 33ms (the quanta),
54162306a36Sopenharmony_ci	 * and then the remote MAC continues sending packets even though
54262306a36Sopenharmony_ci	 * the RX queue is still full.
54362306a36Sopenharmony_ci	 *
54462306a36Sopenharmony_ci	 * If disabled, the EMAC sends a pause frame every 31ms until the RX
54562306a36Sopenharmony_ci	 * queue is no longer full.  Normally, this is the preferred
54662306a36Sopenharmony_ci	 * method of operation.  However, when the system is hung (e.g.
54762306a36Sopenharmony_ci	 * cores are halted), the EMAC interrupt handler is never called
54862306a36Sopenharmony_ci	 * and so the RX queue fills up quickly and stays full.  The resuling
54962306a36Sopenharmony_ci	 * non-stop "flood" of pause frames sometimes has the effect of
55062306a36Sopenharmony_ci	 * disabling nearby switches.  In some cases, other nearby switches
55162306a36Sopenharmony_ci	 * are also affected, shutting down the entire network.
55262306a36Sopenharmony_ci	 *
55362306a36Sopenharmony_ci	 * The user can enable or disable single-pause-frame mode
55462306a36Sopenharmony_ci	 * via ethtool.
55562306a36Sopenharmony_ci	 */
55662306a36Sopenharmony_ci	mac |= adpt->single_pause_mode ? SINGLE_PAUSE_MODE : 0;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	writel_relaxed(csr1, adpt->csr + EMAC_EMAC_WRAPPER_CSR1);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	writel_relaxed(mac, adpt->base + EMAC_MAC_CTRL);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* enable interrupt read clear, low power sleep mode and
56362306a36Sopenharmony_ci	 * the irq moderators
56462306a36Sopenharmony_ci	 */
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	writel_relaxed(adpt->irq_mod, adpt->base + EMAC_IRQ_MOD_TIM_INIT);
56762306a36Sopenharmony_ci	writel_relaxed(INT_RD_CLR_EN | LPW_MODE | IRQ_MODERATOR_EN |
56862306a36Sopenharmony_ci			IRQ_MODERATOR2_EN, adpt->base + EMAC_DMA_MAS_CTRL);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	emac_mac_mode_config(adpt);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_ATHR_HEADER_CTRL,
57362306a36Sopenharmony_ci			  (HEADER_ENABLE | HEADER_CNT_EN), 0);
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_civoid emac_mac_stop(struct emac_adapter *adpt)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_RXQ_CTRL_0, RXQ_EN, 0);
57962306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_TXQ_CTRL_0, TXQ_EN, 0);
58062306a36Sopenharmony_ci	emac_reg_update32(adpt->base + EMAC_MAC_CTRL, TXEN | RXEN, 0);
58162306a36Sopenharmony_ci	usleep_range(1000, 1050); /* stopping mac may take upto 1msec */
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci/* Free all descriptors of given transmit queue */
58562306a36Sopenharmony_cistatic void emac_tx_q_descs_free(struct emac_adapter *adpt)
58662306a36Sopenharmony_ci{
58762306a36Sopenharmony_ci	struct emac_tx_queue *tx_q = &adpt->tx_q;
58862306a36Sopenharmony_ci	unsigned int i;
58962306a36Sopenharmony_ci	size_t size;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* ring already cleared, nothing to do */
59262306a36Sopenharmony_ci	if (!tx_q->tpd.tpbuff)
59362306a36Sopenharmony_ci		return;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	for (i = 0; i < tx_q->tpd.count; i++) {
59662306a36Sopenharmony_ci		struct emac_buffer *tpbuf = GET_TPD_BUFFER(tx_q, i);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		if (tpbuf->dma_addr) {
59962306a36Sopenharmony_ci			dma_unmap_single(adpt->netdev->dev.parent,
60062306a36Sopenharmony_ci					 tpbuf->dma_addr, tpbuf->length,
60162306a36Sopenharmony_ci					 DMA_TO_DEVICE);
60262306a36Sopenharmony_ci			tpbuf->dma_addr = 0;
60362306a36Sopenharmony_ci		}
60462306a36Sopenharmony_ci		if (tpbuf->skb) {
60562306a36Sopenharmony_ci			dev_kfree_skb_any(tpbuf->skb);
60662306a36Sopenharmony_ci			tpbuf->skb = NULL;
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	size = sizeof(struct emac_buffer) * tx_q->tpd.count;
61162306a36Sopenharmony_ci	memset(tx_q->tpd.tpbuff, 0, size);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* clear the descriptor ring */
61462306a36Sopenharmony_ci	memset(tx_q->tpd.v_addr, 0, tx_q->tpd.size);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	tx_q->tpd.consume_idx = 0;
61762306a36Sopenharmony_ci	tx_q->tpd.produce_idx = 0;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci/* Free all descriptors of given receive queue */
62162306a36Sopenharmony_cistatic void emac_rx_q_free_descs(struct emac_adapter *adpt)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	struct device *dev = adpt->netdev->dev.parent;
62462306a36Sopenharmony_ci	struct emac_rx_queue *rx_q = &adpt->rx_q;
62562306a36Sopenharmony_ci	unsigned int i;
62662306a36Sopenharmony_ci	size_t size;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* ring already cleared, nothing to do */
62962306a36Sopenharmony_ci	if (!rx_q->rfd.rfbuff)
63062306a36Sopenharmony_ci		return;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	for (i = 0; i < rx_q->rfd.count; i++) {
63362306a36Sopenharmony_ci		struct emac_buffer *rfbuf = GET_RFD_BUFFER(rx_q, i);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		if (rfbuf->dma_addr) {
63662306a36Sopenharmony_ci			dma_unmap_single(dev, rfbuf->dma_addr, rfbuf->length,
63762306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
63862306a36Sopenharmony_ci			rfbuf->dma_addr = 0;
63962306a36Sopenharmony_ci		}
64062306a36Sopenharmony_ci		if (rfbuf->skb) {
64162306a36Sopenharmony_ci			dev_kfree_skb(rfbuf->skb);
64262306a36Sopenharmony_ci			rfbuf->skb = NULL;
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	size =  sizeof(struct emac_buffer) * rx_q->rfd.count;
64762306a36Sopenharmony_ci	memset(rx_q->rfd.rfbuff, 0, size);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/* clear the descriptor rings */
65062306a36Sopenharmony_ci	memset(rx_q->rrd.v_addr, 0, rx_q->rrd.size);
65162306a36Sopenharmony_ci	rx_q->rrd.produce_idx = 0;
65262306a36Sopenharmony_ci	rx_q->rrd.consume_idx = 0;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	memset(rx_q->rfd.v_addr, 0, rx_q->rfd.size);
65562306a36Sopenharmony_ci	rx_q->rfd.produce_idx = 0;
65662306a36Sopenharmony_ci	rx_q->rfd.consume_idx = 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/* Free all buffers associated with given transmit queue */
66062306a36Sopenharmony_cistatic void emac_tx_q_bufs_free(struct emac_adapter *adpt)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	struct emac_tx_queue *tx_q = &adpt->tx_q;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	emac_tx_q_descs_free(adpt);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	kfree(tx_q->tpd.tpbuff);
66762306a36Sopenharmony_ci	tx_q->tpd.tpbuff = NULL;
66862306a36Sopenharmony_ci	tx_q->tpd.v_addr = NULL;
66962306a36Sopenharmony_ci	tx_q->tpd.dma_addr = 0;
67062306a36Sopenharmony_ci	tx_q->tpd.size = 0;
67162306a36Sopenharmony_ci}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci/* Allocate TX descriptor ring for the given transmit queue */
67462306a36Sopenharmony_cistatic int emac_tx_q_desc_alloc(struct emac_adapter *adpt,
67562306a36Sopenharmony_ci				struct emac_tx_queue *tx_q)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct emac_ring_header *ring_header = &adpt->ring_header;
67862306a36Sopenharmony_ci	int node = dev_to_node(adpt->netdev->dev.parent);
67962306a36Sopenharmony_ci	size_t size;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	size = sizeof(struct emac_buffer) * tx_q->tpd.count;
68262306a36Sopenharmony_ci	tx_q->tpd.tpbuff = kzalloc_node(size, GFP_KERNEL, node);
68362306a36Sopenharmony_ci	if (!tx_q->tpd.tpbuff)
68462306a36Sopenharmony_ci		return -ENOMEM;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	tx_q->tpd.size = tx_q->tpd.count * (adpt->tpd_size * 4);
68762306a36Sopenharmony_ci	tx_q->tpd.dma_addr = ring_header->dma_addr + ring_header->used;
68862306a36Sopenharmony_ci	tx_q->tpd.v_addr = ring_header->v_addr + ring_header->used;
68962306a36Sopenharmony_ci	ring_header->used += ALIGN(tx_q->tpd.size, 8);
69062306a36Sopenharmony_ci	tx_q->tpd.produce_idx = 0;
69162306a36Sopenharmony_ci	tx_q->tpd.consume_idx = 0;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/* Free all buffers associated with given transmit queue */
69762306a36Sopenharmony_cistatic void emac_rx_q_bufs_free(struct emac_adapter *adpt)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	struct emac_rx_queue *rx_q = &adpt->rx_q;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	emac_rx_q_free_descs(adpt);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	kfree(rx_q->rfd.rfbuff);
70462306a36Sopenharmony_ci	rx_q->rfd.rfbuff   = NULL;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	rx_q->rfd.v_addr   = NULL;
70762306a36Sopenharmony_ci	rx_q->rfd.dma_addr = 0;
70862306a36Sopenharmony_ci	rx_q->rfd.size     = 0;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	rx_q->rrd.v_addr   = NULL;
71162306a36Sopenharmony_ci	rx_q->rrd.dma_addr = 0;
71262306a36Sopenharmony_ci	rx_q->rrd.size     = 0;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/* Allocate RX descriptor rings for the given receive queue */
71662306a36Sopenharmony_cistatic int emac_rx_descs_alloc(struct emac_adapter *adpt)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct emac_ring_header *ring_header = &adpt->ring_header;
71962306a36Sopenharmony_ci	int node = dev_to_node(adpt->netdev->dev.parent);
72062306a36Sopenharmony_ci	struct emac_rx_queue *rx_q = &adpt->rx_q;
72162306a36Sopenharmony_ci	size_t size;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	size = sizeof(struct emac_buffer) * rx_q->rfd.count;
72462306a36Sopenharmony_ci	rx_q->rfd.rfbuff = kzalloc_node(size, GFP_KERNEL, node);
72562306a36Sopenharmony_ci	if (!rx_q->rfd.rfbuff)
72662306a36Sopenharmony_ci		return -ENOMEM;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	rx_q->rrd.size = rx_q->rrd.count * (adpt->rrd_size * 4);
72962306a36Sopenharmony_ci	rx_q->rfd.size = rx_q->rfd.count * (adpt->rfd_size * 4);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	rx_q->rrd.dma_addr = ring_header->dma_addr + ring_header->used;
73262306a36Sopenharmony_ci	rx_q->rrd.v_addr   = ring_header->v_addr + ring_header->used;
73362306a36Sopenharmony_ci	ring_header->used += ALIGN(rx_q->rrd.size, 8);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	rx_q->rfd.dma_addr = ring_header->dma_addr + ring_header->used;
73662306a36Sopenharmony_ci	rx_q->rfd.v_addr   = ring_header->v_addr + ring_header->used;
73762306a36Sopenharmony_ci	ring_header->used += ALIGN(rx_q->rfd.size, 8);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	rx_q->rrd.produce_idx = 0;
74062306a36Sopenharmony_ci	rx_q->rrd.consume_idx = 0;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	rx_q->rfd.produce_idx = 0;
74362306a36Sopenharmony_ci	rx_q->rfd.consume_idx = 0;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	return 0;
74662306a36Sopenharmony_ci}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci/* Allocate all TX and RX descriptor rings */
74962306a36Sopenharmony_ciint emac_mac_rx_tx_rings_alloc_all(struct emac_adapter *adpt)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	struct emac_ring_header *ring_header = &adpt->ring_header;
75262306a36Sopenharmony_ci	struct device *dev = adpt->netdev->dev.parent;
75362306a36Sopenharmony_ci	unsigned int num_tx_descs = adpt->tx_desc_cnt;
75462306a36Sopenharmony_ci	unsigned int num_rx_descs = adpt->rx_desc_cnt;
75562306a36Sopenharmony_ci	int ret;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	adpt->tx_q.tpd.count = adpt->tx_desc_cnt;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	adpt->rx_q.rrd.count = adpt->rx_desc_cnt;
76062306a36Sopenharmony_ci	adpt->rx_q.rfd.count = adpt->rx_desc_cnt;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	/* Ring DMA buffer. Each ring may need up to 8 bytes for alignment,
76362306a36Sopenharmony_ci	 * hence the additional padding bytes are allocated.
76462306a36Sopenharmony_ci	 */
76562306a36Sopenharmony_ci	ring_header->size = num_tx_descs * (adpt->tpd_size * 4) +
76662306a36Sopenharmony_ci			    num_rx_descs * (adpt->rfd_size * 4) +
76762306a36Sopenharmony_ci			    num_rx_descs * (adpt->rrd_size * 4) +
76862306a36Sopenharmony_ci			    8 + 2 * 8; /* 8 byte per one Tx and two Rx rings */
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	ring_header->used = 0;
77162306a36Sopenharmony_ci	ring_header->v_addr = dma_alloc_coherent(dev, ring_header->size,
77262306a36Sopenharmony_ci						 &ring_header->dma_addr,
77362306a36Sopenharmony_ci						 GFP_KERNEL);
77462306a36Sopenharmony_ci	if (!ring_header->v_addr)
77562306a36Sopenharmony_ci		return -ENOMEM;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	ring_header->used = ALIGN(ring_header->dma_addr, 8) -
77862306a36Sopenharmony_ci							ring_header->dma_addr;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	ret = emac_tx_q_desc_alloc(adpt, &adpt->tx_q);
78162306a36Sopenharmony_ci	if (ret) {
78262306a36Sopenharmony_ci		netdev_err(adpt->netdev, "error: Tx Queue alloc failed\n");
78362306a36Sopenharmony_ci		goto err_alloc_tx;
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	ret = emac_rx_descs_alloc(adpt);
78762306a36Sopenharmony_ci	if (ret) {
78862306a36Sopenharmony_ci		netdev_err(adpt->netdev, "error: Rx Queue alloc failed\n");
78962306a36Sopenharmony_ci		goto err_alloc_rx;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	return 0;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_cierr_alloc_rx:
79562306a36Sopenharmony_ci	emac_tx_q_bufs_free(adpt);
79662306a36Sopenharmony_cierr_alloc_tx:
79762306a36Sopenharmony_ci	dma_free_coherent(dev, ring_header->size,
79862306a36Sopenharmony_ci			  ring_header->v_addr, ring_header->dma_addr);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	ring_header->v_addr   = NULL;
80162306a36Sopenharmony_ci	ring_header->dma_addr = 0;
80262306a36Sopenharmony_ci	ring_header->size     = 0;
80362306a36Sopenharmony_ci	ring_header->used     = 0;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return ret;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci/* Free all TX and RX descriptor rings */
80962306a36Sopenharmony_civoid emac_mac_rx_tx_rings_free_all(struct emac_adapter *adpt)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct emac_ring_header *ring_header = &adpt->ring_header;
81262306a36Sopenharmony_ci	struct device *dev = adpt->netdev->dev.parent;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	emac_tx_q_bufs_free(adpt);
81562306a36Sopenharmony_ci	emac_rx_q_bufs_free(adpt);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	dma_free_coherent(dev, ring_header->size,
81862306a36Sopenharmony_ci			  ring_header->v_addr, ring_header->dma_addr);
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	ring_header->v_addr   = NULL;
82162306a36Sopenharmony_ci	ring_header->dma_addr = 0;
82262306a36Sopenharmony_ci	ring_header->size     = 0;
82362306a36Sopenharmony_ci	ring_header->used     = 0;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci/* Initialize descriptor rings */
82762306a36Sopenharmony_cistatic void emac_mac_rx_tx_ring_reset_all(struct emac_adapter *adpt)
82862306a36Sopenharmony_ci{
82962306a36Sopenharmony_ci	unsigned int i;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	adpt->tx_q.tpd.produce_idx = 0;
83262306a36Sopenharmony_ci	adpt->tx_q.tpd.consume_idx = 0;
83362306a36Sopenharmony_ci	for (i = 0; i < adpt->tx_q.tpd.count; i++)
83462306a36Sopenharmony_ci		adpt->tx_q.tpd.tpbuff[i].dma_addr = 0;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	adpt->rx_q.rrd.produce_idx = 0;
83762306a36Sopenharmony_ci	adpt->rx_q.rrd.consume_idx = 0;
83862306a36Sopenharmony_ci	adpt->rx_q.rfd.produce_idx = 0;
83962306a36Sopenharmony_ci	adpt->rx_q.rfd.consume_idx = 0;
84062306a36Sopenharmony_ci	for (i = 0; i < adpt->rx_q.rfd.count; i++)
84162306a36Sopenharmony_ci		adpt->rx_q.rfd.rfbuff[i].dma_addr = 0;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci/* Produce new receive free descriptor */
84562306a36Sopenharmony_cistatic void emac_mac_rx_rfd_create(struct emac_adapter *adpt,
84662306a36Sopenharmony_ci				   struct emac_rx_queue *rx_q,
84762306a36Sopenharmony_ci				   dma_addr_t addr)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	u32 *hw_rfd = EMAC_RFD(rx_q, adpt->rfd_size, rx_q->rfd.produce_idx);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	*(hw_rfd++) = lower_32_bits(addr);
85262306a36Sopenharmony_ci	*hw_rfd = upper_32_bits(addr);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	if (++rx_q->rfd.produce_idx == rx_q->rfd.count)
85562306a36Sopenharmony_ci		rx_q->rfd.produce_idx = 0;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/* Fill up receive queue's RFD with preallocated receive buffers */
85962306a36Sopenharmony_cistatic void emac_mac_rx_descs_refill(struct emac_adapter *adpt,
86062306a36Sopenharmony_ci				    struct emac_rx_queue *rx_q)
86162306a36Sopenharmony_ci{
86262306a36Sopenharmony_ci	struct emac_buffer *curr_rxbuf;
86362306a36Sopenharmony_ci	struct emac_buffer *next_rxbuf;
86462306a36Sopenharmony_ci	unsigned int count = 0;
86562306a36Sopenharmony_ci	u32 next_produce_idx;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	next_produce_idx = rx_q->rfd.produce_idx + 1;
86862306a36Sopenharmony_ci	if (next_produce_idx == rx_q->rfd.count)
86962306a36Sopenharmony_ci		next_produce_idx = 0;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	curr_rxbuf = GET_RFD_BUFFER(rx_q, rx_q->rfd.produce_idx);
87262306a36Sopenharmony_ci	next_rxbuf = GET_RFD_BUFFER(rx_q, next_produce_idx);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	/* this always has a blank rx_buffer*/
87562306a36Sopenharmony_ci	while (!next_rxbuf->dma_addr) {
87662306a36Sopenharmony_ci		struct sk_buff *skb;
87762306a36Sopenharmony_ci		int ret;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci		skb = netdev_alloc_skb_ip_align(adpt->netdev, adpt->rxbuf_size);
88062306a36Sopenharmony_ci		if (!skb)
88162306a36Sopenharmony_ci			break;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci		curr_rxbuf->dma_addr =
88462306a36Sopenharmony_ci			dma_map_single(adpt->netdev->dev.parent, skb->data,
88562306a36Sopenharmony_ci				       adpt->rxbuf_size, DMA_FROM_DEVICE);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci		ret = dma_mapping_error(adpt->netdev->dev.parent,
88862306a36Sopenharmony_ci					curr_rxbuf->dma_addr);
88962306a36Sopenharmony_ci		if (ret) {
89062306a36Sopenharmony_ci			dev_kfree_skb(skb);
89162306a36Sopenharmony_ci			break;
89262306a36Sopenharmony_ci		}
89362306a36Sopenharmony_ci		curr_rxbuf->skb = skb;
89462306a36Sopenharmony_ci		curr_rxbuf->length = adpt->rxbuf_size;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		emac_mac_rx_rfd_create(adpt, rx_q, curr_rxbuf->dma_addr);
89762306a36Sopenharmony_ci		next_produce_idx = rx_q->rfd.produce_idx + 1;
89862306a36Sopenharmony_ci		if (next_produce_idx == rx_q->rfd.count)
89962306a36Sopenharmony_ci			next_produce_idx = 0;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		curr_rxbuf = GET_RFD_BUFFER(rx_q, rx_q->rfd.produce_idx);
90262306a36Sopenharmony_ci		next_rxbuf = GET_RFD_BUFFER(rx_q, next_produce_idx);
90362306a36Sopenharmony_ci		count++;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	if (count) {
90762306a36Sopenharmony_ci		u32 prod_idx = (rx_q->rfd.produce_idx << rx_q->produce_shift) &
90862306a36Sopenharmony_ci				rx_q->produce_mask;
90962306a36Sopenharmony_ci		emac_reg_update32(adpt->base + rx_q->produce_reg,
91062306a36Sopenharmony_ci				  rx_q->produce_mask, prod_idx);
91162306a36Sopenharmony_ci	}
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic void emac_adjust_link(struct net_device *netdev)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	struct emac_adapter *adpt = netdev_priv(netdev);
91762306a36Sopenharmony_ci	struct phy_device *phydev = netdev->phydev;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	if (phydev->link) {
92062306a36Sopenharmony_ci		emac_mac_start(adpt);
92162306a36Sopenharmony_ci		emac_sgmii_link_change(adpt, true);
92262306a36Sopenharmony_ci	} else {
92362306a36Sopenharmony_ci		emac_sgmii_link_change(adpt, false);
92462306a36Sopenharmony_ci		emac_mac_stop(adpt);
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	phy_print_status(phydev);
92862306a36Sopenharmony_ci}
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci/* Bringup the interface/HW */
93162306a36Sopenharmony_ciint emac_mac_up(struct emac_adapter *adpt)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	struct net_device *netdev = adpt->netdev;
93462306a36Sopenharmony_ci	int ret;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	emac_mac_rx_tx_ring_reset_all(adpt);
93762306a36Sopenharmony_ci	emac_mac_config(adpt);
93862306a36Sopenharmony_ci	emac_mac_rx_descs_refill(adpt, &adpt->rx_q);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	adpt->phydev->irq = PHY_POLL;
94162306a36Sopenharmony_ci	ret = phy_connect_direct(netdev, adpt->phydev, emac_adjust_link,
94262306a36Sopenharmony_ci				 PHY_INTERFACE_MODE_SGMII);
94362306a36Sopenharmony_ci	if (ret) {
94462306a36Sopenharmony_ci		netdev_err(adpt->netdev, "could not connect phy\n");
94562306a36Sopenharmony_ci		return ret;
94662306a36Sopenharmony_ci	}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	phy_attached_print(adpt->phydev, NULL);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	/* enable mac irq */
95162306a36Sopenharmony_ci	writel((u32)~DIS_INT, adpt->base + EMAC_INT_STATUS);
95262306a36Sopenharmony_ci	writel(adpt->irq.mask, adpt->base + EMAC_INT_MASK);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	phy_start(adpt->phydev);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	napi_enable(&adpt->rx_q.napi);
95762306a36Sopenharmony_ci	netif_start_queue(netdev);
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	return 0;
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci/* Bring down the interface/HW */
96362306a36Sopenharmony_civoid emac_mac_down(struct emac_adapter *adpt)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct net_device *netdev = adpt->netdev;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	netif_stop_queue(netdev);
96862306a36Sopenharmony_ci	napi_disable(&adpt->rx_q.napi);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	phy_stop(adpt->phydev);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	/* Interrupts must be disabled before the PHY is disconnected, to
97362306a36Sopenharmony_ci	 * avoid a race condition where adjust_link is null when we get
97462306a36Sopenharmony_ci	 * an interrupt.
97562306a36Sopenharmony_ci	 */
97662306a36Sopenharmony_ci	writel(DIS_INT, adpt->base + EMAC_INT_STATUS);
97762306a36Sopenharmony_ci	writel(0, adpt->base + EMAC_INT_MASK);
97862306a36Sopenharmony_ci	synchronize_irq(adpt->irq.irq);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	phy_disconnect(adpt->phydev);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	emac_mac_reset(adpt);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	emac_tx_q_descs_free(adpt);
98562306a36Sopenharmony_ci	netdev_reset_queue(adpt->netdev);
98662306a36Sopenharmony_ci	emac_rx_q_free_descs(adpt);
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci/* Consume next received packet descriptor */
99062306a36Sopenharmony_cistatic bool emac_rx_process_rrd(struct emac_adapter *adpt,
99162306a36Sopenharmony_ci				struct emac_rx_queue *rx_q,
99262306a36Sopenharmony_ci				struct emac_rrd *rrd)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	u32 *hw_rrd = EMAC_RRD(rx_q, adpt->rrd_size, rx_q->rrd.consume_idx);
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	rrd->word[3] = *(hw_rrd + 3);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	if (!RRD_UPDT(rrd))
99962306a36Sopenharmony_ci		return false;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	rrd->word[4] = 0;
100262306a36Sopenharmony_ci	rrd->word[5] = 0;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	rrd->word[0] = *(hw_rrd++);
100562306a36Sopenharmony_ci	rrd->word[1] = *(hw_rrd++);
100662306a36Sopenharmony_ci	rrd->word[2] = *(hw_rrd++);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (unlikely(RRD_NOR(rrd) != 1)) {
100962306a36Sopenharmony_ci		netdev_err(adpt->netdev,
101062306a36Sopenharmony_ci			   "error: multi-RFD not support yet! nor:%lu\n",
101162306a36Sopenharmony_ci			   RRD_NOR(rrd));
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/* mark rrd as processed */
101562306a36Sopenharmony_ci	RRD_UPDT_SET(rrd, 0);
101662306a36Sopenharmony_ci	*hw_rrd = rrd->word[3];
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	if (++rx_q->rrd.consume_idx == rx_q->rrd.count)
101962306a36Sopenharmony_ci		rx_q->rrd.consume_idx = 0;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	return true;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci/* Produce new transmit descriptor */
102562306a36Sopenharmony_cistatic void emac_tx_tpd_create(struct emac_adapter *adpt,
102662306a36Sopenharmony_ci			       struct emac_tx_queue *tx_q, struct emac_tpd *tpd)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	u32 *hw_tpd;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	tx_q->tpd.last_produce_idx = tx_q->tpd.produce_idx;
103162306a36Sopenharmony_ci	hw_tpd = EMAC_TPD(tx_q, adpt->tpd_size, tx_q->tpd.produce_idx);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	if (++tx_q->tpd.produce_idx == tx_q->tpd.count)
103462306a36Sopenharmony_ci		tx_q->tpd.produce_idx = 0;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	*(hw_tpd++) = tpd->word[0];
103762306a36Sopenharmony_ci	*(hw_tpd++) = tpd->word[1];
103862306a36Sopenharmony_ci	*(hw_tpd++) = tpd->word[2];
103962306a36Sopenharmony_ci	*hw_tpd = tpd->word[3];
104062306a36Sopenharmony_ci}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci/* Mark the last transmit descriptor as such (for the transmit packet) */
104362306a36Sopenharmony_cistatic void emac_tx_tpd_mark_last(struct emac_adapter *adpt,
104462306a36Sopenharmony_ci				  struct emac_tx_queue *tx_q)
104562306a36Sopenharmony_ci{
104662306a36Sopenharmony_ci	u32 *hw_tpd =
104762306a36Sopenharmony_ci		EMAC_TPD(tx_q, adpt->tpd_size, tx_q->tpd.last_produce_idx);
104862306a36Sopenharmony_ci	u32 tmp_tpd;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	tmp_tpd = *(hw_tpd + 1);
105162306a36Sopenharmony_ci	tmp_tpd |= EMAC_TPD_LAST_FRAGMENT;
105262306a36Sopenharmony_ci	*(hw_tpd + 1) = tmp_tpd;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic void emac_rx_rfd_clean(struct emac_rx_queue *rx_q, struct emac_rrd *rrd)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	struct emac_buffer *rfbuf = rx_q->rfd.rfbuff;
105862306a36Sopenharmony_ci	u32 consume_idx = RRD_SI(rrd);
105962306a36Sopenharmony_ci	unsigned int i;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	for (i = 0; i < RRD_NOR(rrd); i++) {
106262306a36Sopenharmony_ci		rfbuf[consume_idx].skb = NULL;
106362306a36Sopenharmony_ci		if (++consume_idx == rx_q->rfd.count)
106462306a36Sopenharmony_ci			consume_idx = 0;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	rx_q->rfd.consume_idx = consume_idx;
106862306a36Sopenharmony_ci	rx_q->rfd.process_idx = consume_idx;
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci/* Push the received skb to upper layers */
107262306a36Sopenharmony_cistatic void emac_receive_skb(struct emac_rx_queue *rx_q,
107362306a36Sopenharmony_ci			     struct sk_buff *skb,
107462306a36Sopenharmony_ci			     u16 vlan_tag, bool vlan_flag)
107562306a36Sopenharmony_ci{
107662306a36Sopenharmony_ci	if (vlan_flag) {
107762306a36Sopenharmony_ci		u16 vlan;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		EMAC_TAG_TO_VLAN(vlan_tag, vlan);
108062306a36Sopenharmony_ci		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan);
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	napi_gro_receive(&rx_q->napi, skb);
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci/* Process receive event */
108762306a36Sopenharmony_civoid emac_mac_rx_process(struct emac_adapter *adpt, struct emac_rx_queue *rx_q,
108862306a36Sopenharmony_ci			 int *num_pkts, int max_pkts)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	u32 proc_idx, hw_consume_idx, num_consume_pkts;
109162306a36Sopenharmony_ci	struct net_device *netdev  = adpt->netdev;
109262306a36Sopenharmony_ci	struct emac_buffer *rfbuf;
109362306a36Sopenharmony_ci	unsigned int count = 0;
109462306a36Sopenharmony_ci	struct emac_rrd rrd;
109562306a36Sopenharmony_ci	struct sk_buff *skb;
109662306a36Sopenharmony_ci	u32 reg;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	reg = readl_relaxed(adpt->base + rx_q->consume_reg);
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	hw_consume_idx = (reg & rx_q->consume_mask) >> rx_q->consume_shift;
110162306a36Sopenharmony_ci	num_consume_pkts = (hw_consume_idx >= rx_q->rrd.consume_idx) ?
110262306a36Sopenharmony_ci		(hw_consume_idx -  rx_q->rrd.consume_idx) :
110362306a36Sopenharmony_ci		(hw_consume_idx + rx_q->rrd.count - rx_q->rrd.consume_idx);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	do {
110662306a36Sopenharmony_ci		if (!num_consume_pkts)
110762306a36Sopenharmony_ci			break;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci		if (!emac_rx_process_rrd(adpt, rx_q, &rrd))
111062306a36Sopenharmony_ci			break;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci		if (likely(RRD_NOR(&rrd) == 1)) {
111362306a36Sopenharmony_ci			/* good receive */
111462306a36Sopenharmony_ci			rfbuf = GET_RFD_BUFFER(rx_q, RRD_SI(&rrd));
111562306a36Sopenharmony_ci			dma_unmap_single(adpt->netdev->dev.parent,
111662306a36Sopenharmony_ci					 rfbuf->dma_addr, rfbuf->length,
111762306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
111862306a36Sopenharmony_ci			rfbuf->dma_addr = 0;
111962306a36Sopenharmony_ci			skb = rfbuf->skb;
112062306a36Sopenharmony_ci		} else {
112162306a36Sopenharmony_ci			netdev_err(adpt->netdev,
112262306a36Sopenharmony_ci				   "error: multi-RFD not support yet!\n");
112362306a36Sopenharmony_ci			break;
112462306a36Sopenharmony_ci		}
112562306a36Sopenharmony_ci		emac_rx_rfd_clean(rx_q, &rrd);
112662306a36Sopenharmony_ci		num_consume_pkts--;
112762306a36Sopenharmony_ci		count++;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci		/* Due to a HW issue in L4 check sum detection (UDP/TCP frags
113062306a36Sopenharmony_ci		 * with DF set are marked as error), drop packets based on the
113162306a36Sopenharmony_ci		 * error mask rather than the summary bit (ignoring L4F errors)
113262306a36Sopenharmony_ci		 */
113362306a36Sopenharmony_ci		if (rrd.word[EMAC_RRD_STATS_DW_IDX] & EMAC_RRD_ERROR) {
113462306a36Sopenharmony_ci			netif_dbg(adpt, rx_status, adpt->netdev,
113562306a36Sopenharmony_ci				  "Drop error packet[RRD: 0x%x:0x%x:0x%x:0x%x]\n",
113662306a36Sopenharmony_ci				  rrd.word[0], rrd.word[1],
113762306a36Sopenharmony_ci				  rrd.word[2], rrd.word[3]);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci			dev_kfree_skb(skb);
114062306a36Sopenharmony_ci			continue;
114162306a36Sopenharmony_ci		}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci		skb_put(skb, RRD_PKT_SIZE(&rrd) - ETH_FCS_LEN);
114462306a36Sopenharmony_ci		skb->dev = netdev;
114562306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, skb->dev);
114662306a36Sopenharmony_ci		if (netdev->features & NETIF_F_RXCSUM)
114762306a36Sopenharmony_ci			skb->ip_summed = RRD_L4F(&rrd) ?
114862306a36Sopenharmony_ci					  CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
114962306a36Sopenharmony_ci		else
115062306a36Sopenharmony_ci			skb_checksum_none_assert(skb);
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci		emac_receive_skb(rx_q, skb, (u16)RRD_CVALN_TAG(&rrd),
115362306a36Sopenharmony_ci				 (bool)RRD_CVTAG(&rrd));
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci		(*num_pkts)++;
115662306a36Sopenharmony_ci	} while (*num_pkts < max_pkts);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (count) {
115962306a36Sopenharmony_ci		proc_idx = (rx_q->rfd.process_idx << rx_q->process_shft) &
116062306a36Sopenharmony_ci				rx_q->process_mask;
116162306a36Sopenharmony_ci		emac_reg_update32(adpt->base + rx_q->process_reg,
116262306a36Sopenharmony_ci				  rx_q->process_mask, proc_idx);
116362306a36Sopenharmony_ci		emac_mac_rx_descs_refill(adpt, rx_q);
116462306a36Sopenharmony_ci	}
116562306a36Sopenharmony_ci}
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci/* get the number of free transmit descriptors */
116862306a36Sopenharmony_cistatic unsigned int emac_tpd_num_free_descs(struct emac_tx_queue *tx_q)
116962306a36Sopenharmony_ci{
117062306a36Sopenharmony_ci	u32 produce_idx = tx_q->tpd.produce_idx;
117162306a36Sopenharmony_ci	u32 consume_idx = tx_q->tpd.consume_idx;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	return (consume_idx > produce_idx) ?
117462306a36Sopenharmony_ci		(consume_idx - produce_idx - 1) :
117562306a36Sopenharmony_ci		(tx_q->tpd.count + consume_idx - produce_idx - 1);
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci/* Process transmit event */
117962306a36Sopenharmony_civoid emac_mac_tx_process(struct emac_adapter *adpt, struct emac_tx_queue *tx_q)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	u32 reg = readl_relaxed(adpt->base + tx_q->consume_reg);
118262306a36Sopenharmony_ci	u32 hw_consume_idx, pkts_compl = 0, bytes_compl = 0;
118362306a36Sopenharmony_ci	struct emac_buffer *tpbuf;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	hw_consume_idx = (reg & tx_q->consume_mask) >> tx_q->consume_shift;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	while (tx_q->tpd.consume_idx != hw_consume_idx) {
118862306a36Sopenharmony_ci		tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.consume_idx);
118962306a36Sopenharmony_ci		if (tpbuf->dma_addr) {
119062306a36Sopenharmony_ci			dma_unmap_page(adpt->netdev->dev.parent,
119162306a36Sopenharmony_ci				       tpbuf->dma_addr, tpbuf->length,
119262306a36Sopenharmony_ci				       DMA_TO_DEVICE);
119362306a36Sopenharmony_ci			tpbuf->dma_addr = 0;
119462306a36Sopenharmony_ci		}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		if (tpbuf->skb) {
119762306a36Sopenharmony_ci			pkts_compl++;
119862306a36Sopenharmony_ci			bytes_compl += tpbuf->skb->len;
119962306a36Sopenharmony_ci			dev_consume_skb_irq(tpbuf->skb);
120062306a36Sopenharmony_ci			tpbuf->skb = NULL;
120162306a36Sopenharmony_ci		}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci		if (++tx_q->tpd.consume_idx == tx_q->tpd.count)
120462306a36Sopenharmony_ci			tx_q->tpd.consume_idx = 0;
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	netdev_completed_queue(adpt->netdev, pkts_compl, bytes_compl);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	if (netif_queue_stopped(adpt->netdev))
121062306a36Sopenharmony_ci		if (emac_tpd_num_free_descs(tx_q) > (MAX_SKB_FRAGS + 1))
121162306a36Sopenharmony_ci			netif_wake_queue(adpt->netdev);
121262306a36Sopenharmony_ci}
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci/* Initialize all queue data structures */
121562306a36Sopenharmony_civoid emac_mac_rx_tx_ring_init_all(struct platform_device *pdev,
121662306a36Sopenharmony_ci				  struct emac_adapter *adpt)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	adpt->rx_q.netdev = adpt->netdev;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	adpt->rx_q.produce_reg  = EMAC_MAILBOX_0;
122162306a36Sopenharmony_ci	adpt->rx_q.produce_mask = RFD0_PROD_IDX_BMSK;
122262306a36Sopenharmony_ci	adpt->rx_q.produce_shift = RFD0_PROD_IDX_SHFT;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	adpt->rx_q.process_reg  = EMAC_MAILBOX_0;
122562306a36Sopenharmony_ci	adpt->rx_q.process_mask = RFD0_PROC_IDX_BMSK;
122662306a36Sopenharmony_ci	adpt->rx_q.process_shft = RFD0_PROC_IDX_SHFT;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	adpt->rx_q.consume_reg  = EMAC_MAILBOX_3;
122962306a36Sopenharmony_ci	adpt->rx_q.consume_mask = RFD0_CONS_IDX_BMSK;
123062306a36Sopenharmony_ci	adpt->rx_q.consume_shift = RFD0_CONS_IDX_SHFT;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	adpt->rx_q.irq          = &adpt->irq;
123362306a36Sopenharmony_ci	adpt->rx_q.intr         = adpt->irq.mask & ISR_RX_PKT;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	adpt->tx_q.produce_reg  = EMAC_MAILBOX_15;
123662306a36Sopenharmony_ci	adpt->tx_q.produce_mask = NTPD_PROD_IDX_BMSK;
123762306a36Sopenharmony_ci	adpt->tx_q.produce_shift = NTPD_PROD_IDX_SHFT;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	adpt->tx_q.consume_reg  = EMAC_MAILBOX_2;
124062306a36Sopenharmony_ci	adpt->tx_q.consume_mask = NTPD_CONS_IDX_BMSK;
124162306a36Sopenharmony_ci	adpt->tx_q.consume_shift = NTPD_CONS_IDX_SHFT;
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci/* Fill up transmit descriptors with TSO and Checksum offload information */
124562306a36Sopenharmony_cistatic int emac_tso_csum(struct emac_adapter *adpt,
124662306a36Sopenharmony_ci			 struct emac_tx_queue *tx_q,
124762306a36Sopenharmony_ci			 struct sk_buff *skb,
124862306a36Sopenharmony_ci			 struct emac_tpd *tpd)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci	unsigned int hdr_len;
125162306a36Sopenharmony_ci	int ret;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (skb_is_gso(skb)) {
125462306a36Sopenharmony_ci		if (skb_header_cloned(skb)) {
125562306a36Sopenharmony_ci			ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
125662306a36Sopenharmony_ci			if (unlikely(ret))
125762306a36Sopenharmony_ci				return ret;
125862306a36Sopenharmony_ci		}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci		if (skb->protocol == htons(ETH_P_IP)) {
126162306a36Sopenharmony_ci			u32 pkt_len = ((unsigned char *)ip_hdr(skb) - skb->data)
126262306a36Sopenharmony_ci				       + ntohs(ip_hdr(skb)->tot_len);
126362306a36Sopenharmony_ci			if (skb->len > pkt_len) {
126462306a36Sopenharmony_ci				ret = pskb_trim(skb, pkt_len);
126562306a36Sopenharmony_ci				if (unlikely(ret))
126662306a36Sopenharmony_ci					return ret;
126762306a36Sopenharmony_ci			}
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		hdr_len = skb_tcp_all_headers(skb);
127162306a36Sopenharmony_ci		if (unlikely(skb->len == hdr_len)) {
127262306a36Sopenharmony_ci			/* we only need to do csum */
127362306a36Sopenharmony_ci			netif_warn(adpt, tx_err, adpt->netdev,
127462306a36Sopenharmony_ci				   "tso not needed for packet with 0 data\n");
127562306a36Sopenharmony_ci			goto do_csum;
127662306a36Sopenharmony_ci		}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
127962306a36Sopenharmony_ci			ip_hdr(skb)->check = 0;
128062306a36Sopenharmony_ci			tcp_hdr(skb)->check =
128162306a36Sopenharmony_ci				~csum_tcpudp_magic(ip_hdr(skb)->saddr,
128262306a36Sopenharmony_ci						   ip_hdr(skb)->daddr,
128362306a36Sopenharmony_ci						   0, IPPROTO_TCP, 0);
128462306a36Sopenharmony_ci			TPD_IPV4_SET(tpd, 1);
128562306a36Sopenharmony_ci		}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
128862306a36Sopenharmony_ci			/* ipv6 tso need an extra tpd */
128962306a36Sopenharmony_ci			struct emac_tpd extra_tpd;
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci			memset(tpd, 0, sizeof(*tpd));
129262306a36Sopenharmony_ci			memset(&extra_tpd, 0, sizeof(extra_tpd));
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci			tcp_v6_gso_csum_prep(skb);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci			TPD_PKT_LEN_SET(&extra_tpd, skb->len);
129762306a36Sopenharmony_ci			TPD_LSO_SET(&extra_tpd, 1);
129862306a36Sopenharmony_ci			TPD_LSOV_SET(&extra_tpd, 1);
129962306a36Sopenharmony_ci			emac_tx_tpd_create(adpt, tx_q, &extra_tpd);
130062306a36Sopenharmony_ci			TPD_LSOV_SET(tpd, 1);
130162306a36Sopenharmony_ci		}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci		TPD_LSO_SET(tpd, 1);
130462306a36Sopenharmony_ci		TPD_TCPHDR_OFFSET_SET(tpd, skb_transport_offset(skb));
130562306a36Sopenharmony_ci		TPD_MSS_SET(tpd, skb_shinfo(skb)->gso_size);
130662306a36Sopenharmony_ci		return 0;
130762306a36Sopenharmony_ci	}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_cido_csum:
131062306a36Sopenharmony_ci	if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
131162306a36Sopenharmony_ci		unsigned int css, cso;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci		cso = skb_transport_offset(skb);
131462306a36Sopenharmony_ci		if (unlikely(cso & 0x1)) {
131562306a36Sopenharmony_ci			netdev_err(adpt->netdev,
131662306a36Sopenharmony_ci				   "error: payload offset should be even\n");
131762306a36Sopenharmony_ci			return -EINVAL;
131862306a36Sopenharmony_ci		}
131962306a36Sopenharmony_ci		css = cso + skb->csum_offset;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci		TPD_PAYLOAD_OFFSET_SET(tpd, cso >> 1);
132262306a36Sopenharmony_ci		TPD_CXSUM_OFFSET_SET(tpd, css >> 1);
132362306a36Sopenharmony_ci		TPD_CSX_SET(tpd, 1);
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	return 0;
132762306a36Sopenharmony_ci}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci/* Fill up transmit descriptors */
133062306a36Sopenharmony_cistatic void emac_tx_fill_tpd(struct emac_adapter *adpt,
133162306a36Sopenharmony_ci			     struct emac_tx_queue *tx_q, struct sk_buff *skb,
133262306a36Sopenharmony_ci			     struct emac_tpd *tpd)
133362306a36Sopenharmony_ci{
133462306a36Sopenharmony_ci	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
133562306a36Sopenharmony_ci	unsigned int first = tx_q->tpd.produce_idx;
133662306a36Sopenharmony_ci	unsigned int len = skb_headlen(skb);
133762306a36Sopenharmony_ci	struct emac_buffer *tpbuf = NULL;
133862306a36Sopenharmony_ci	unsigned int mapped_len = 0;
133962306a36Sopenharmony_ci	unsigned int i;
134062306a36Sopenharmony_ci	int count = 0;
134162306a36Sopenharmony_ci	int ret;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	/* if Large Segment Offload is (in TCP Segmentation Offload struct) */
134462306a36Sopenharmony_ci	if (TPD_LSO(tpd)) {
134562306a36Sopenharmony_ci		mapped_len = skb_tcp_all_headers(skb);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci		tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx);
134862306a36Sopenharmony_ci		tpbuf->length = mapped_len;
134962306a36Sopenharmony_ci		tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent,
135062306a36Sopenharmony_ci					       virt_to_page(skb->data),
135162306a36Sopenharmony_ci					       offset_in_page(skb->data),
135262306a36Sopenharmony_ci					       tpbuf->length,
135362306a36Sopenharmony_ci					       DMA_TO_DEVICE);
135462306a36Sopenharmony_ci		ret = dma_mapping_error(adpt->netdev->dev.parent,
135562306a36Sopenharmony_ci					tpbuf->dma_addr);
135662306a36Sopenharmony_ci		if (ret)
135762306a36Sopenharmony_ci			goto error;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci		TPD_BUFFER_ADDR_L_SET(tpd, lower_32_bits(tpbuf->dma_addr));
136062306a36Sopenharmony_ci		TPD_BUFFER_ADDR_H_SET(tpd, upper_32_bits(tpbuf->dma_addr));
136162306a36Sopenharmony_ci		TPD_BUF_LEN_SET(tpd, tpbuf->length);
136262306a36Sopenharmony_ci		emac_tx_tpd_create(adpt, tx_q, tpd);
136362306a36Sopenharmony_ci		count++;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	if (mapped_len < len) {
136762306a36Sopenharmony_ci		tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx);
136862306a36Sopenharmony_ci		tpbuf->length = len - mapped_len;
136962306a36Sopenharmony_ci		tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent,
137062306a36Sopenharmony_ci					       virt_to_page(skb->data +
137162306a36Sopenharmony_ci							    mapped_len),
137262306a36Sopenharmony_ci					       offset_in_page(skb->data +
137362306a36Sopenharmony_ci							      mapped_len),
137462306a36Sopenharmony_ci					       tpbuf->length, DMA_TO_DEVICE);
137562306a36Sopenharmony_ci		ret = dma_mapping_error(adpt->netdev->dev.parent,
137662306a36Sopenharmony_ci					tpbuf->dma_addr);
137762306a36Sopenharmony_ci		if (ret)
137862306a36Sopenharmony_ci			goto error;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci		TPD_BUFFER_ADDR_L_SET(tpd, lower_32_bits(tpbuf->dma_addr));
138162306a36Sopenharmony_ci		TPD_BUFFER_ADDR_H_SET(tpd, upper_32_bits(tpbuf->dma_addr));
138262306a36Sopenharmony_ci		TPD_BUF_LEN_SET(tpd, tpbuf->length);
138362306a36Sopenharmony_ci		emac_tx_tpd_create(adpt, tx_q, tpd);
138462306a36Sopenharmony_ci		count++;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	for (i = 0; i < nr_frags; i++) {
138862306a36Sopenharmony_ci		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci		tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx);
139162306a36Sopenharmony_ci		tpbuf->length = skb_frag_size(frag);
139262306a36Sopenharmony_ci		tpbuf->dma_addr = skb_frag_dma_map(adpt->netdev->dev.parent,
139362306a36Sopenharmony_ci						   frag, 0, tpbuf->length,
139462306a36Sopenharmony_ci						   DMA_TO_DEVICE);
139562306a36Sopenharmony_ci		ret = dma_mapping_error(adpt->netdev->dev.parent,
139662306a36Sopenharmony_ci					tpbuf->dma_addr);
139762306a36Sopenharmony_ci		if (ret)
139862306a36Sopenharmony_ci			goto error;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		TPD_BUFFER_ADDR_L_SET(tpd, lower_32_bits(tpbuf->dma_addr));
140162306a36Sopenharmony_ci		TPD_BUFFER_ADDR_H_SET(tpd, upper_32_bits(tpbuf->dma_addr));
140262306a36Sopenharmony_ci		TPD_BUF_LEN_SET(tpd, tpbuf->length);
140362306a36Sopenharmony_ci		emac_tx_tpd_create(adpt, tx_q, tpd);
140462306a36Sopenharmony_ci		count++;
140562306a36Sopenharmony_ci	}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	/* The last tpd */
140862306a36Sopenharmony_ci	wmb();
140962306a36Sopenharmony_ci	emac_tx_tpd_mark_last(adpt, tx_q);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/* The last buffer info contain the skb address,
141262306a36Sopenharmony_ci	 * so it will be freed after unmap
141362306a36Sopenharmony_ci	 */
141462306a36Sopenharmony_ci	tpbuf->skb = skb;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	return;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_cierror:
141962306a36Sopenharmony_ci	/* One of the memory mappings failed, so undo everything */
142062306a36Sopenharmony_ci	tx_q->tpd.produce_idx = first;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci	while (count--) {
142362306a36Sopenharmony_ci		tpbuf = GET_TPD_BUFFER(tx_q, first);
142462306a36Sopenharmony_ci		dma_unmap_page(adpt->netdev->dev.parent, tpbuf->dma_addr,
142562306a36Sopenharmony_ci			       tpbuf->length, DMA_TO_DEVICE);
142662306a36Sopenharmony_ci		tpbuf->dma_addr = 0;
142762306a36Sopenharmony_ci		tpbuf->length = 0;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci		if (++first == tx_q->tpd.count)
143062306a36Sopenharmony_ci			first = 0;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	dev_kfree_skb(skb);
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci/* Transmit the packet using specified transmit queue */
143762306a36Sopenharmony_cinetdev_tx_t emac_mac_tx_buf_send(struct emac_adapter *adpt,
143862306a36Sopenharmony_ci				 struct emac_tx_queue *tx_q,
143962306a36Sopenharmony_ci				 struct sk_buff *skb)
144062306a36Sopenharmony_ci{
144162306a36Sopenharmony_ci	struct emac_tpd tpd;
144262306a36Sopenharmony_ci	u32 prod_idx;
144362306a36Sopenharmony_ci	int len;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	memset(&tpd, 0, sizeof(tpd));
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	if (emac_tso_csum(adpt, tx_q, skb, &tpd) != 0) {
144862306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
144962306a36Sopenharmony_ci		return NETDEV_TX_OK;
145062306a36Sopenharmony_ci	}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
145362306a36Sopenharmony_ci		u16 tag;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		EMAC_VLAN_TO_TAG(skb_vlan_tag_get(skb), tag);
145662306a36Sopenharmony_ci		TPD_CVLAN_TAG_SET(&tpd, tag);
145762306a36Sopenharmony_ci		TPD_INSTC_SET(&tpd, 1);
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	if (skb_network_offset(skb) != ETH_HLEN)
146162306a36Sopenharmony_ci		TPD_TYP_SET(&tpd, 1);
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	len = skb->len;
146462306a36Sopenharmony_ci	emac_tx_fill_tpd(adpt, tx_q, skb, &tpd);
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	netdev_sent_queue(adpt->netdev, len);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	/* Make sure the are enough free descriptors to hold one
146962306a36Sopenharmony_ci	 * maximum-sized SKB.  We need one desc for each fragment,
147062306a36Sopenharmony_ci	 * one for the checksum (emac_tso_csum), one for TSO, and
147162306a36Sopenharmony_ci	 * one for the SKB header.
147262306a36Sopenharmony_ci	 */
147362306a36Sopenharmony_ci	if (emac_tpd_num_free_descs(tx_q) < (MAX_SKB_FRAGS + 3))
147462306a36Sopenharmony_ci		netif_stop_queue(adpt->netdev);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	/* update produce idx */
147762306a36Sopenharmony_ci	prod_idx = (tx_q->tpd.produce_idx << tx_q->produce_shift) &
147862306a36Sopenharmony_ci		    tx_q->produce_mask;
147962306a36Sopenharmony_ci	emac_reg_update32(adpt->base + tx_q->produce_reg,
148062306a36Sopenharmony_ci			  tx_q->produce_mask, prod_idx);
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	return NETDEV_TX_OK;
148362306a36Sopenharmony_ci}
1484