xref: /linux/drivers/net/ethernet/microchip/lan743x_main.c (revision 9410645520e9b820069761f3450ef6661418e279)
123f0703cSBryan Whitehead /* SPDX-License-Identifier: GPL-2.0+ */
223f0703cSBryan Whitehead /* Copyright (C) 2018 Microchip Technology Inc. */
323f0703cSBryan Whitehead 
423f0703cSBryan Whitehead #include <linux/module.h>
523f0703cSBryan Whitehead #include <linux/pci.h>
623f0703cSBryan Whitehead #include <linux/netdevice.h>
723f0703cSBryan Whitehead #include <linux/etherdevice.h>
823f0703cSBryan Whitehead #include <linux/crc32.h>
923f0703cSBryan Whitehead #include <linux/microchipphy.h>
1023f0703cSBryan Whitehead #include <linux/net_tstamp.h>
116f197fb6SRoelof Berg #include <linux/of_mdio.h>
126f197fb6SRoelof Berg #include <linux/of_net.h>
1323f0703cSBryan Whitehead #include <linux/phy.h>
146f197fb6SRoelof Berg #include <linux/phy_fixed.h>
1523f0703cSBryan Whitehead #include <linux/rtnetlink.h>
1623f0703cSBryan Whitehead #include <linux/iopoll.h>
174d94282aSBryan Whitehead #include <linux/crc16.h>
18a5f199a8SRaju Lakkaraju #include <linux/phylink.h>
1923f0703cSBryan Whitehead #include "lan743x_main.h"
200cf63226SBryan Whitehead #include "lan743x_ethtool.h"
2123f0703cSBryan Whitehead 
22a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_ADDRESS	0
23a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_WRITE	1
24a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_READ		2
25a2ab95a3SRaju Lakkaraju #define MMD_ACCESS_READ_INC	3
2646b777adSRaju Lakkaraju #define PCS_POWER_STATE_DOWN	0x6
2746b777adSRaju Lakkaraju #define PCS_POWER_STATE_UP	0x4
28a2ab95a3SRaju Lakkaraju 
29e4a58989SRaju Lakkaraju #define RFE_RD_FIFO_TH_3_DWORDS	0x3
30e4a58989SRaju Lakkaraju 
pci11x1x_strap_get_status(struct lan743x_adapter * adapter)31a46d9d37SRaju Lakkaraju static void pci11x1x_strap_get_status(struct lan743x_adapter *adapter)
32a46d9d37SRaju Lakkaraju {
33a46d9d37SRaju Lakkaraju 	u32 chip_rev;
3446b777adSRaju Lakkaraju 	u32 cfg_load;
3546b777adSRaju Lakkaraju 	u32 hw_cfg;
36a46d9d37SRaju Lakkaraju 	u32 strap;
3746b777adSRaju Lakkaraju 	int ret;
38a46d9d37SRaju Lakkaraju 
3946b777adSRaju Lakkaraju 	/* Timeout = 100 (i.e. 1 sec (10 msce * 100)) */
4046b777adSRaju Lakkaraju 	ret = lan743x_hs_syslock_acquire(adapter, 100);
4146b777adSRaju Lakkaraju 	if (ret < 0) {
4246b777adSRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
4346b777adSRaju Lakkaraju 			  "Sys Lock acquire failed ret:%d\n", ret);
4446b777adSRaju Lakkaraju 		return;
4546b777adSRaju Lakkaraju 	}
4646b777adSRaju Lakkaraju 
4746b777adSRaju Lakkaraju 	cfg_load = lan743x_csr_read(adapter, ETH_SYS_CONFIG_LOAD_STARTED_REG);
4846b777adSRaju Lakkaraju 	lan743x_hs_syslock_release(adapter);
4946b777adSRaju Lakkaraju 	hw_cfg = lan743x_csr_read(adapter, HW_CFG);
5046b777adSRaju Lakkaraju 
5146b777adSRaju Lakkaraju 	if (cfg_load & GEN_SYS_LOAD_STARTED_REG_ETH_ ||
5246b777adSRaju Lakkaraju 	    hw_cfg & HW_CFG_RST_PROTECT_) {
53a46d9d37SRaju Lakkaraju 		strap = lan743x_csr_read(adapter, STRAP_READ);
54a46d9d37SRaju Lakkaraju 		if (strap & STRAP_READ_SGMII_EN_)
55a46d9d37SRaju Lakkaraju 			adapter->is_sgmii_en = true;
56a46d9d37SRaju Lakkaraju 		else
57a46d9d37SRaju Lakkaraju 			adapter->is_sgmii_en = false;
58a46d9d37SRaju Lakkaraju 	} else {
59a46d9d37SRaju Lakkaraju 		chip_rev = lan743x_csr_read(adapter, FPGA_REV);
60a46d9d37SRaju Lakkaraju 		if (chip_rev) {
61a46d9d37SRaju Lakkaraju 			if (chip_rev & FPGA_SGMII_OP)
62a46d9d37SRaju Lakkaraju 				adapter->is_sgmii_en = true;
63a46d9d37SRaju Lakkaraju 			else
64a46d9d37SRaju Lakkaraju 				adapter->is_sgmii_en = false;
65a46d9d37SRaju Lakkaraju 		} else {
66a46d9d37SRaju Lakkaraju 			adapter->is_sgmii_en = false;
67a46d9d37SRaju Lakkaraju 		}
68a46d9d37SRaju Lakkaraju 	}
6946b777adSRaju Lakkaraju 	netif_dbg(adapter, drv, adapter->netdev,
7046b777adSRaju Lakkaraju 		  "SGMII I/F %sable\n", adapter->is_sgmii_en ? "En" : "Dis");
71a46d9d37SRaju Lakkaraju }
72a46d9d37SRaju Lakkaraju 
is_pci11x1x_chip(struct lan743x_adapter * adapter)73cf9aaea8SRaju Lakkaraju static bool is_pci11x1x_chip(struct lan743x_adapter *adapter)
74cf9aaea8SRaju Lakkaraju {
75cf9aaea8SRaju Lakkaraju 	struct lan743x_csr *csr = &adapter->csr;
76cf9aaea8SRaju Lakkaraju 	u32 id_rev = csr->id_rev;
77cf9aaea8SRaju Lakkaraju 
78cf9aaea8SRaju Lakkaraju 	if (((id_rev & 0xFFFF0000) == ID_REV_ID_A011_) ||
79cf9aaea8SRaju Lakkaraju 	    ((id_rev & 0xFFFF0000) == ID_REV_ID_A041_)) {
80cf9aaea8SRaju Lakkaraju 		return true;
81cf9aaea8SRaju Lakkaraju 	}
82cf9aaea8SRaju Lakkaraju 	return false;
83cf9aaea8SRaju Lakkaraju }
84cf9aaea8SRaju Lakkaraju 
lan743x_pci_cleanup(struct lan743x_adapter * adapter)8523f0703cSBryan Whitehead static void lan743x_pci_cleanup(struct lan743x_adapter *adapter)
8623f0703cSBryan Whitehead {
8723f0703cSBryan Whitehead 	pci_release_selected_regions(adapter->pdev,
8823f0703cSBryan Whitehead 				     pci_select_bars(adapter->pdev,
8923f0703cSBryan Whitehead 						     IORESOURCE_MEM));
9023f0703cSBryan Whitehead 	pci_disable_device(adapter->pdev);
9123f0703cSBryan Whitehead }
9223f0703cSBryan Whitehead 
lan743x_pci_init(struct lan743x_adapter * adapter,struct pci_dev * pdev)9323f0703cSBryan Whitehead static int lan743x_pci_init(struct lan743x_adapter *adapter,
9423f0703cSBryan Whitehead 			    struct pci_dev *pdev)
9523f0703cSBryan Whitehead {
9623f0703cSBryan Whitehead 	unsigned long bars = 0;
9723f0703cSBryan Whitehead 	int ret;
9823f0703cSBryan Whitehead 
9923f0703cSBryan Whitehead 	adapter->pdev = pdev;
10023f0703cSBryan Whitehead 	ret = pci_enable_device_mem(pdev);
10123f0703cSBryan Whitehead 	if (ret)
10223f0703cSBryan Whitehead 		goto return_error;
10323f0703cSBryan Whitehead 
10423f0703cSBryan Whitehead 	netif_info(adapter, probe, adapter->netdev,
10523f0703cSBryan Whitehead 		   "PCI: Vendor ID = 0x%04X, Device ID = 0x%04X\n",
10623f0703cSBryan Whitehead 		   pdev->vendor, pdev->device);
10723f0703cSBryan Whitehead 	bars = pci_select_bars(pdev, IORESOURCE_MEM);
10823f0703cSBryan Whitehead 	if (!test_bit(0, &bars))
10923f0703cSBryan Whitehead 		goto disable_device;
11023f0703cSBryan Whitehead 
11123f0703cSBryan Whitehead 	ret = pci_request_selected_regions(pdev, bars, DRIVER_NAME);
11223f0703cSBryan Whitehead 	if (ret)
11323f0703cSBryan Whitehead 		goto disable_device;
11423f0703cSBryan Whitehead 
11523f0703cSBryan Whitehead 	pci_set_master(pdev);
11623f0703cSBryan Whitehead 	return 0;
11723f0703cSBryan Whitehead 
11823f0703cSBryan Whitehead disable_device:
11923f0703cSBryan Whitehead 	pci_disable_device(adapter->pdev);
12023f0703cSBryan Whitehead 
12123f0703cSBryan Whitehead return_error:
12223f0703cSBryan Whitehead 	return ret;
12323f0703cSBryan Whitehead }
12423f0703cSBryan Whitehead 
lan743x_csr_read(struct lan743x_adapter * adapter,int offset)1258114e8a2SBryan Whitehead u32 lan743x_csr_read(struct lan743x_adapter *adapter, int offset)
12623f0703cSBryan Whitehead {
12723f0703cSBryan Whitehead 	return ioread32(&adapter->csr.csr_address[offset]);
12823f0703cSBryan Whitehead }
12923f0703cSBryan Whitehead 
lan743x_csr_write(struct lan743x_adapter * adapter,int offset,u32 data)1308114e8a2SBryan Whitehead void lan743x_csr_write(struct lan743x_adapter *adapter, int offset,
131c16b1a9cSColin Ian King 		       u32 data)
13223f0703cSBryan Whitehead {
13323f0703cSBryan Whitehead 	iowrite32(data, &adapter->csr.csr_address[offset]);
13423f0703cSBryan Whitehead }
13523f0703cSBryan Whitehead 
13623f0703cSBryan Whitehead #define LAN743X_CSR_READ_OP(offset)	lan743x_csr_read(adapter, offset)
13723f0703cSBryan Whitehead 
lan743x_csr_light_reset(struct lan743x_adapter * adapter)13823f0703cSBryan Whitehead static int lan743x_csr_light_reset(struct lan743x_adapter *adapter)
13923f0703cSBryan Whitehead {
14023f0703cSBryan Whitehead 	u32 data;
14123f0703cSBryan Whitehead 
14223f0703cSBryan Whitehead 	data = lan743x_csr_read(adapter, HW_CFG);
14323f0703cSBryan Whitehead 	data |= HW_CFG_LRST_;
14423f0703cSBryan Whitehead 	lan743x_csr_write(adapter, HW_CFG, data);
14523f0703cSBryan Whitehead 
14623f0703cSBryan Whitehead 	return readx_poll_timeout(LAN743X_CSR_READ_OP, HW_CFG, data,
14723f0703cSBryan Whitehead 				  !(data & HW_CFG_LRST_), 100000, 10000000);
14823f0703cSBryan Whitehead }
14923f0703cSBryan Whitehead 
lan743x_csr_wait_for_bit_atomic(struct lan743x_adapter * adapter,int offset,u32 bit_mask,int target_value,int udelay_min,int udelay_max,int count)1507a8227b2SMoritz Fischer static int lan743x_csr_wait_for_bit_atomic(struct lan743x_adapter *adapter,
1517a8227b2SMoritz Fischer 					   int offset, u32 bit_mask,
1527a8227b2SMoritz Fischer 					   int target_value, int udelay_min,
1537a8227b2SMoritz Fischer 					   int udelay_max, int count)
1547a8227b2SMoritz Fischer {
1557a8227b2SMoritz Fischer 	u32 data;
1567a8227b2SMoritz Fischer 
1577a8227b2SMoritz Fischer 	return readx_poll_timeout_atomic(LAN743X_CSR_READ_OP, offset, data,
1587a8227b2SMoritz Fischer 					 target_value == !!(data & bit_mask),
1597a8227b2SMoritz Fischer 					 udelay_max, udelay_min * count);
1607a8227b2SMoritz Fischer }
1617a8227b2SMoritz Fischer 
lan743x_csr_wait_for_bit(struct lan743x_adapter * adapter,int offset,u32 bit_mask,int target_value,int usleep_min,int usleep_max,int count)16223f0703cSBryan Whitehead static int lan743x_csr_wait_for_bit(struct lan743x_adapter *adapter,
16323f0703cSBryan Whitehead 				    int offset, u32 bit_mask,
16423f0703cSBryan Whitehead 				    int target_value, int usleep_min,
16523f0703cSBryan Whitehead 				    int usleep_max, int count)
16623f0703cSBryan Whitehead {
16723f0703cSBryan Whitehead 	u32 data;
16823f0703cSBryan Whitehead 
16923f0703cSBryan Whitehead 	return readx_poll_timeout(LAN743X_CSR_READ_OP, offset, data,
17030ac666aSMoritz Fischer 				  target_value == !!(data & bit_mask),
17123f0703cSBryan Whitehead 				  usleep_max, usleep_min * count);
17223f0703cSBryan Whitehead }
17323f0703cSBryan Whitehead 
lan743x_csr_init(struct lan743x_adapter * adapter)17423f0703cSBryan Whitehead static int lan743x_csr_init(struct lan743x_adapter *adapter)
17523f0703cSBryan Whitehead {
17623f0703cSBryan Whitehead 	struct lan743x_csr *csr = &adapter->csr;
17723f0703cSBryan Whitehead 	resource_size_t bar_start, bar_length;
17823f0703cSBryan Whitehead 
17923f0703cSBryan Whitehead 	bar_start = pci_resource_start(adapter->pdev, 0);
18023f0703cSBryan Whitehead 	bar_length = pci_resource_len(adapter->pdev, 0);
18123f0703cSBryan Whitehead 	csr->csr_address = devm_ioremap(&adapter->pdev->dev,
18223f0703cSBryan Whitehead 					bar_start, bar_length);
1830f0f5868SMoritz Fischer 	if (!csr->csr_address)
1840f0f5868SMoritz Fischer 		return -ENOMEM;
18523f0703cSBryan Whitehead 
18623f0703cSBryan Whitehead 	csr->id_rev = lan743x_csr_read(adapter, ID_REV);
18723f0703cSBryan Whitehead 	csr->fpga_rev = lan743x_csr_read(adapter, FPGA_REV);
18823f0703cSBryan Whitehead 	netif_info(adapter, probe, adapter->netdev,
18923f0703cSBryan Whitehead 		   "ID_REV = 0x%08X, FPGA_REV = %d.%d\n",
19023f0703cSBryan Whitehead 		   csr->id_rev,	FPGA_REV_GET_MAJOR_(csr->fpga_rev),
19123f0703cSBryan Whitehead 		   FPGA_REV_GET_MINOR_(csr->fpga_rev));
1920f0f5868SMoritz Fischer 	if (!ID_REV_IS_VALID_CHIP_ID_(csr->id_rev))
1930f0f5868SMoritz Fischer 		return -ENODEV;
19423f0703cSBryan Whitehead 
19523f0703cSBryan Whitehead 	csr->flags = LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR;
19623f0703cSBryan Whitehead 	switch (csr->id_rev & ID_REV_CHIP_REV_MASK_) {
19723f0703cSBryan Whitehead 	case ID_REV_CHIP_REV_A0_:
19823f0703cSBryan Whitehead 		csr->flags |= LAN743X_CSR_FLAG_IS_A0;
19923f0703cSBryan Whitehead 		csr->flags &= ~LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR;
20023f0703cSBryan Whitehead 		break;
20123f0703cSBryan Whitehead 	case ID_REV_CHIP_REV_B0_:
20223f0703cSBryan Whitehead 		csr->flags |= LAN743X_CSR_FLAG_IS_B0;
20323f0703cSBryan Whitehead 		break;
20423f0703cSBryan Whitehead 	}
20523f0703cSBryan Whitehead 
2060f0f5868SMoritz Fischer 	return lan743x_csr_light_reset(adapter);
20723f0703cSBryan Whitehead }
20823f0703cSBryan Whitehead 
lan743x_intr_software_isr(struct lan743x_adapter * adapter)209c31799baSSven Van Asbroeck static void lan743x_intr_software_isr(struct lan743x_adapter *adapter)
21023f0703cSBryan Whitehead {
21123f0703cSBryan Whitehead 	struct lan743x_intr *intr = &adapter->intr;
21223f0703cSBryan Whitehead 
213796a2665SSven Van Asbroeck 	/* disable the interrupt to prevent repeated re-triggering */
214796a2665SSven Van Asbroeck 	lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_);
215470dfd80SSven Van Asbroeck 	intr->software_isr_flag = true;
216470dfd80SSven Van Asbroeck 	wake_up(&intr->software_isr_wq);
21723f0703cSBryan Whitehead }
21823f0703cSBryan Whitehead 
lan743x_tx_isr(void * context,u32 int_sts,u32 flags)21923f0703cSBryan Whitehead static void lan743x_tx_isr(void *context, u32 int_sts, u32 flags)
22023f0703cSBryan Whitehead {
22123f0703cSBryan Whitehead 	struct lan743x_tx *tx = context;
22223f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = tx->adapter;
22323f0703cSBryan Whitehead 	bool enable_flag = true;
22423f0703cSBryan Whitehead 
2257c8c0291SJesse Brandeburg 	lan743x_csr_read(adapter, INT_EN_SET);
22623f0703cSBryan Whitehead 	if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) {
22723f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_CLR,
22823f0703cSBryan Whitehead 				  INT_BIT_DMA_TX_(tx->channel_number));
22923f0703cSBryan Whitehead 	}
23023f0703cSBryan Whitehead 
23123f0703cSBryan Whitehead 	if (int_sts & INT_BIT_DMA_TX_(tx->channel_number)) {
23223f0703cSBryan Whitehead 		u32 ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number);
23323f0703cSBryan Whitehead 		u32 dmac_int_sts;
23423f0703cSBryan Whitehead 		u32 dmac_int_en;
23523f0703cSBryan Whitehead 
23623f0703cSBryan Whitehead 		if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ)
23723f0703cSBryan Whitehead 			dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
23823f0703cSBryan Whitehead 		else
23923f0703cSBryan Whitehead 			dmac_int_sts = ioc_bit;
24023f0703cSBryan Whitehead 		if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK)
24123f0703cSBryan Whitehead 			dmac_int_en = lan743x_csr_read(adapter,
24223f0703cSBryan Whitehead 						       DMAC_INT_EN_SET);
24323f0703cSBryan Whitehead 		else
24423f0703cSBryan Whitehead 			dmac_int_en = ioc_bit;
24523f0703cSBryan Whitehead 
24623f0703cSBryan Whitehead 		dmac_int_en &= ioc_bit;
24723f0703cSBryan Whitehead 		dmac_int_sts &= dmac_int_en;
24823f0703cSBryan Whitehead 		if (dmac_int_sts & ioc_bit) {
24923f0703cSBryan Whitehead 			napi_schedule(&tx->napi);
25023f0703cSBryan Whitehead 			enable_flag = false;/* poll func will enable later */
25123f0703cSBryan Whitehead 		}
25223f0703cSBryan Whitehead 	}
25323f0703cSBryan Whitehead 
25423f0703cSBryan Whitehead 	if (enable_flag)
25523f0703cSBryan Whitehead 		/* enable isr */
25623f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_SET,
25723f0703cSBryan Whitehead 				  INT_BIT_DMA_TX_(tx->channel_number));
25823f0703cSBryan Whitehead }
25923f0703cSBryan Whitehead 
lan743x_rx_isr(void * context,u32 int_sts,u32 flags)26023f0703cSBryan Whitehead static void lan743x_rx_isr(void *context, u32 int_sts, u32 flags)
26123f0703cSBryan Whitehead {
26223f0703cSBryan Whitehead 	struct lan743x_rx *rx = context;
26323f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = rx->adapter;
26423f0703cSBryan Whitehead 	bool enable_flag = true;
26523f0703cSBryan Whitehead 
26623f0703cSBryan Whitehead 	if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR) {
26723f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_CLR,
26823f0703cSBryan Whitehead 				  INT_BIT_DMA_RX_(rx->channel_number));
26923f0703cSBryan Whitehead 	}
27023f0703cSBryan Whitehead 
27123f0703cSBryan Whitehead 	if (int_sts & INT_BIT_DMA_RX_(rx->channel_number)) {
27223f0703cSBryan Whitehead 		u32 rx_frame_bit = DMAC_INT_BIT_RXFRM_(rx->channel_number);
27323f0703cSBryan Whitehead 		u32 dmac_int_sts;
27423f0703cSBryan Whitehead 		u32 dmac_int_en;
27523f0703cSBryan Whitehead 
27623f0703cSBryan Whitehead 		if (flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ)
27723f0703cSBryan Whitehead 			dmac_int_sts = lan743x_csr_read(adapter, DMAC_INT_STS);
27823f0703cSBryan Whitehead 		else
27923f0703cSBryan Whitehead 			dmac_int_sts = rx_frame_bit;
28023f0703cSBryan Whitehead 		if (flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK)
28123f0703cSBryan Whitehead 			dmac_int_en = lan743x_csr_read(adapter,
28223f0703cSBryan Whitehead 						       DMAC_INT_EN_SET);
28323f0703cSBryan Whitehead 		else
28423f0703cSBryan Whitehead 			dmac_int_en = rx_frame_bit;
28523f0703cSBryan Whitehead 
28623f0703cSBryan Whitehead 		dmac_int_en &= rx_frame_bit;
28723f0703cSBryan Whitehead 		dmac_int_sts &= dmac_int_en;
28823f0703cSBryan Whitehead 		if (dmac_int_sts & rx_frame_bit) {
28923f0703cSBryan Whitehead 			napi_schedule(&rx->napi);
29023f0703cSBryan Whitehead 			enable_flag = false;/* poll funct will enable later */
29123f0703cSBryan Whitehead 		}
29223f0703cSBryan Whitehead 	}
29323f0703cSBryan Whitehead 
29423f0703cSBryan Whitehead 	if (enable_flag) {
29523f0703cSBryan Whitehead 		/* enable isr */
29623f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_SET,
29723f0703cSBryan Whitehead 				  INT_BIT_DMA_RX_(rx->channel_number));
29823f0703cSBryan Whitehead 	}
29923f0703cSBryan Whitehead }
30023f0703cSBryan Whitehead 
lan743x_intr_shared_isr(void * context,u32 int_sts,u32 flags)30123f0703cSBryan Whitehead static void lan743x_intr_shared_isr(void *context, u32 int_sts, u32 flags)
30223f0703cSBryan Whitehead {
30323f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = context;
30423f0703cSBryan Whitehead 	unsigned int channel;
30523f0703cSBryan Whitehead 
30623f0703cSBryan Whitehead 	if (int_sts & INT_BIT_ALL_RX_) {
30723f0703cSBryan Whitehead 		for (channel = 0; channel < LAN743X_USED_RX_CHANNELS;
30823f0703cSBryan Whitehead 			channel++) {
30923f0703cSBryan Whitehead 			u32 int_bit = INT_BIT_DMA_RX_(channel);
31023f0703cSBryan Whitehead 
31123f0703cSBryan Whitehead 			if (int_sts & int_bit) {
31223f0703cSBryan Whitehead 				lan743x_rx_isr(&adapter->rx[channel],
31323f0703cSBryan Whitehead 					       int_bit, flags);
31423f0703cSBryan Whitehead 				int_sts &= ~int_bit;
31523f0703cSBryan Whitehead 			}
31623f0703cSBryan Whitehead 		}
31723f0703cSBryan Whitehead 	}
31823f0703cSBryan Whitehead 	if (int_sts & INT_BIT_ALL_TX_) {
319cf9aaea8SRaju Lakkaraju 		for (channel = 0; channel < adapter->used_tx_channels;
32023f0703cSBryan Whitehead 			channel++) {
32123f0703cSBryan Whitehead 			u32 int_bit = INT_BIT_DMA_TX_(channel);
32223f0703cSBryan Whitehead 
32323f0703cSBryan Whitehead 			if (int_sts & int_bit) {
32423f0703cSBryan Whitehead 				lan743x_tx_isr(&adapter->tx[channel],
32523f0703cSBryan Whitehead 					       int_bit, flags);
32623f0703cSBryan Whitehead 				int_sts &= ~int_bit;
32723f0703cSBryan Whitehead 			}
32823f0703cSBryan Whitehead 		}
32923f0703cSBryan Whitehead 	}
33023f0703cSBryan Whitehead 	if (int_sts & INT_BIT_ALL_OTHER_) {
33123f0703cSBryan Whitehead 		if (int_sts & INT_BIT_SW_GP_) {
33223f0703cSBryan Whitehead 			lan743x_intr_software_isr(adapter);
33323f0703cSBryan Whitehead 			int_sts &= ~INT_BIT_SW_GP_;
33423f0703cSBryan Whitehead 		}
33507624df1SBryan Whitehead 		if (int_sts & INT_BIT_1588_) {
33607624df1SBryan Whitehead 			lan743x_ptp_isr(adapter);
33707624df1SBryan Whitehead 			int_sts &= ~INT_BIT_1588_;
33807624df1SBryan Whitehead 		}
33923f0703cSBryan Whitehead 	}
34023f0703cSBryan Whitehead 	if (int_sts)
34123f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_CLR, int_sts);
34223f0703cSBryan Whitehead }
34323f0703cSBryan Whitehead 
lan743x_intr_entry_isr(int irq,void * ptr)34423f0703cSBryan Whitehead static irqreturn_t lan743x_intr_entry_isr(int irq, void *ptr)
34523f0703cSBryan Whitehead {
34623f0703cSBryan Whitehead 	struct lan743x_vector *vector = ptr;
34723f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = vector->adapter;
34823f0703cSBryan Whitehead 	irqreturn_t result = IRQ_NONE;
34923f0703cSBryan Whitehead 	u32 int_enables;
35023f0703cSBryan Whitehead 	u32 int_sts;
35123f0703cSBryan Whitehead 
35223f0703cSBryan Whitehead 	if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ) {
35323f0703cSBryan Whitehead 		int_sts = lan743x_csr_read(adapter, INT_STS);
35423f0703cSBryan Whitehead 	} else if (vector->flags &
35523f0703cSBryan Whitehead 		   (LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C |
35623f0703cSBryan Whitehead 		   LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)) {
35723f0703cSBryan Whitehead 		int_sts = lan743x_csr_read(adapter, INT_STS_R2C);
35823f0703cSBryan Whitehead 	} else {
35923f0703cSBryan Whitehead 		/* use mask as implied status */
36023f0703cSBryan Whitehead 		int_sts = vector->int_mask | INT_BIT_MAS_;
36123f0703cSBryan Whitehead 	}
36223f0703cSBryan Whitehead 
36323f0703cSBryan Whitehead 	if (!(int_sts & INT_BIT_MAS_))
36423f0703cSBryan Whitehead 		goto irq_done;
36523f0703cSBryan Whitehead 
36623f0703cSBryan Whitehead 	if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR)
36723f0703cSBryan Whitehead 		/* disable vector interrupt */
36823f0703cSBryan Whitehead 		lan743x_csr_write(adapter,
36923f0703cSBryan Whitehead 				  INT_VEC_EN_CLR,
37023f0703cSBryan Whitehead 				  INT_VEC_EN_(vector->vector_index));
37123f0703cSBryan Whitehead 
37223f0703cSBryan Whitehead 	if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR)
37323f0703cSBryan Whitehead 		/* disable master interrupt */
37423f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_);
37523f0703cSBryan Whitehead 
37623f0703cSBryan Whitehead 	if (vector->flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK) {
37723f0703cSBryan Whitehead 		int_enables = lan743x_csr_read(adapter, INT_EN_SET);
37823f0703cSBryan Whitehead 	} else {
37923f0703cSBryan Whitehead 		/*  use vector mask as implied enable mask */
38023f0703cSBryan Whitehead 		int_enables = vector->int_mask;
38123f0703cSBryan Whitehead 	}
38223f0703cSBryan Whitehead 
38323f0703cSBryan Whitehead 	int_sts &= int_enables;
38423f0703cSBryan Whitehead 	int_sts &= vector->int_mask;
38523f0703cSBryan Whitehead 	if (int_sts) {
38623f0703cSBryan Whitehead 		if (vector->handler) {
38723f0703cSBryan Whitehead 			vector->handler(vector->context,
38823f0703cSBryan Whitehead 					int_sts, vector->flags);
38923f0703cSBryan Whitehead 		} else {
39023f0703cSBryan Whitehead 			/* disable interrupts on this vector */
39123f0703cSBryan Whitehead 			lan743x_csr_write(adapter, INT_EN_CLR,
39223f0703cSBryan Whitehead 					  vector->int_mask);
39323f0703cSBryan Whitehead 		}
39423f0703cSBryan Whitehead 		result = IRQ_HANDLED;
39523f0703cSBryan Whitehead 	}
39623f0703cSBryan Whitehead 
39723f0703cSBryan Whitehead 	if (vector->flags & LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET)
39823f0703cSBryan Whitehead 		/* enable master interrupt */
39923f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
40023f0703cSBryan Whitehead 
40123f0703cSBryan Whitehead 	if (vector->flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET)
40223f0703cSBryan Whitehead 		/* enable vector interrupt */
40323f0703cSBryan Whitehead 		lan743x_csr_write(adapter,
40423f0703cSBryan Whitehead 				  INT_VEC_EN_SET,
40523f0703cSBryan Whitehead 				  INT_VEC_EN_(vector->vector_index));
40623f0703cSBryan Whitehead irq_done:
40723f0703cSBryan Whitehead 	return result;
40823f0703cSBryan Whitehead }
40923f0703cSBryan Whitehead 
lan743x_intr_test_isr(struct lan743x_adapter * adapter)41023f0703cSBryan Whitehead static int lan743x_intr_test_isr(struct lan743x_adapter *adapter)
41123f0703cSBryan Whitehead {
41223f0703cSBryan Whitehead 	struct lan743x_intr *intr = &adapter->intr;
413470dfd80SSven Van Asbroeck 	int ret;
41423f0703cSBryan Whitehead 
415470dfd80SSven Van Asbroeck 	intr->software_isr_flag = false;
41623f0703cSBryan Whitehead 
417470dfd80SSven Van Asbroeck 	/* enable and activate test interrupt */
41823f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_SW_GP_);
41923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_SET, INT_BIT_SW_GP_);
42023f0703cSBryan Whitehead 
421470dfd80SSven Van Asbroeck 	ret = wait_event_timeout(intr->software_isr_wq,
422470dfd80SSven Van Asbroeck 				 intr->software_isr_flag,
423470dfd80SSven Van Asbroeck 				 msecs_to_jiffies(200));
42423f0703cSBryan Whitehead 
425470dfd80SSven Van Asbroeck 	/* disable test interrupt */
42623f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_SW_GP_);
427470dfd80SSven Van Asbroeck 
428470dfd80SSven Van Asbroeck 	return ret > 0 ? 0 : -ENODEV;
42923f0703cSBryan Whitehead }
43023f0703cSBryan Whitehead 
lan743x_intr_register_isr(struct lan743x_adapter * adapter,int vector_index,u32 flags,u32 int_mask,lan743x_vector_handler handler,void * context)43123f0703cSBryan Whitehead static int lan743x_intr_register_isr(struct lan743x_adapter *adapter,
43223f0703cSBryan Whitehead 				     int vector_index, u32 flags,
43323f0703cSBryan Whitehead 				     u32 int_mask,
43423f0703cSBryan Whitehead 				     lan743x_vector_handler handler,
43523f0703cSBryan Whitehead 				     void *context)
43623f0703cSBryan Whitehead {
43723f0703cSBryan Whitehead 	struct lan743x_vector *vector = &adapter->intr.vector_list
43823f0703cSBryan Whitehead 					[vector_index];
43923f0703cSBryan Whitehead 	int ret;
44023f0703cSBryan Whitehead 
44123f0703cSBryan Whitehead 	vector->adapter = adapter;
44223f0703cSBryan Whitehead 	vector->flags = flags;
44323f0703cSBryan Whitehead 	vector->vector_index = vector_index;
44423f0703cSBryan Whitehead 	vector->int_mask = int_mask;
44523f0703cSBryan Whitehead 	vector->handler = handler;
44623f0703cSBryan Whitehead 	vector->context = context;
44723f0703cSBryan Whitehead 
44823f0703cSBryan Whitehead 	ret = request_irq(vector->irq,
44923f0703cSBryan Whitehead 			  lan743x_intr_entry_isr,
45023f0703cSBryan Whitehead 			  (flags & LAN743X_VECTOR_FLAG_IRQ_SHARED) ?
45123f0703cSBryan Whitehead 			  IRQF_SHARED : 0, DRIVER_NAME, vector);
45223f0703cSBryan Whitehead 	if (ret) {
45323f0703cSBryan Whitehead 		vector->handler = NULL;
45423f0703cSBryan Whitehead 		vector->context = NULL;
45523f0703cSBryan Whitehead 		vector->int_mask = 0;
45623f0703cSBryan Whitehead 		vector->flags = 0;
45723f0703cSBryan Whitehead 	}
45823f0703cSBryan Whitehead 	return ret;
45923f0703cSBryan Whitehead }
46023f0703cSBryan Whitehead 
lan743x_intr_unregister_isr(struct lan743x_adapter * adapter,int vector_index)46123f0703cSBryan Whitehead static void lan743x_intr_unregister_isr(struct lan743x_adapter *adapter,
46223f0703cSBryan Whitehead 					int vector_index)
46323f0703cSBryan Whitehead {
46423f0703cSBryan Whitehead 	struct lan743x_vector *vector = &adapter->intr.vector_list
46523f0703cSBryan Whitehead 					[vector_index];
46623f0703cSBryan Whitehead 
46723f0703cSBryan Whitehead 	free_irq(vector->irq, vector);
46823f0703cSBryan Whitehead 	vector->handler = NULL;
46923f0703cSBryan Whitehead 	vector->context = NULL;
47023f0703cSBryan Whitehead 	vector->int_mask = 0;
47123f0703cSBryan Whitehead 	vector->flags = 0;
47223f0703cSBryan Whitehead }
47323f0703cSBryan Whitehead 
lan743x_intr_get_vector_flags(struct lan743x_adapter * adapter,u32 int_mask)47423f0703cSBryan Whitehead static u32 lan743x_intr_get_vector_flags(struct lan743x_adapter *adapter,
47523f0703cSBryan Whitehead 					 u32 int_mask)
47623f0703cSBryan Whitehead {
47723f0703cSBryan Whitehead 	int index;
47823f0703cSBryan Whitehead 
479ac16b6ebSRaju Lakkaraju 	for (index = 0; index < adapter->max_vector_count; index++) {
48023f0703cSBryan Whitehead 		if (adapter->intr.vector_list[index].int_mask & int_mask)
48123f0703cSBryan Whitehead 			return adapter->intr.vector_list[index].flags;
48223f0703cSBryan Whitehead 	}
48323f0703cSBryan Whitehead 	return 0;
48423f0703cSBryan Whitehead }
48523f0703cSBryan Whitehead 
lan743x_intr_close(struct lan743x_adapter * adapter)48623f0703cSBryan Whitehead static void lan743x_intr_close(struct lan743x_adapter *adapter)
48723f0703cSBryan Whitehead {
48823f0703cSBryan Whitehead 	struct lan743x_intr *intr = &adapter->intr;
48923f0703cSBryan Whitehead 	int index = 0;
49023f0703cSBryan Whitehead 
49123f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_CLR, INT_BIT_MAS_);
492ac16b6ebSRaju Lakkaraju 	if (adapter->is_pci11x1x)
493ac16b6ebSRaju Lakkaraju 		lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x0000FFFF);
494ac16b6ebSRaju Lakkaraju 	else
49523f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0x000000FF);
49623f0703cSBryan Whitehead 
497ac16b6ebSRaju Lakkaraju 	for (index = 0; index < intr->number_of_vectors; index++) {
49823f0703cSBryan Whitehead 		if (intr->flags & INTR_FLAG_IRQ_REQUESTED(index)) {
49923f0703cSBryan Whitehead 			lan743x_intr_unregister_isr(adapter, index);
50023f0703cSBryan Whitehead 			intr->flags &= ~INTR_FLAG_IRQ_REQUESTED(index);
50123f0703cSBryan Whitehead 		}
50223f0703cSBryan Whitehead 	}
50323f0703cSBryan Whitehead 
50423f0703cSBryan Whitehead 	if (intr->flags & INTR_FLAG_MSI_ENABLED) {
50523f0703cSBryan Whitehead 		pci_disable_msi(adapter->pdev);
50623f0703cSBryan Whitehead 		intr->flags &= ~INTR_FLAG_MSI_ENABLED;
50723f0703cSBryan Whitehead 	}
50823f0703cSBryan Whitehead 
50923f0703cSBryan Whitehead 	if (intr->flags & INTR_FLAG_MSIX_ENABLED) {
51023f0703cSBryan Whitehead 		pci_disable_msix(adapter->pdev);
51123f0703cSBryan Whitehead 		intr->flags &= ~INTR_FLAG_MSIX_ENABLED;
51223f0703cSBryan Whitehead 	}
51323f0703cSBryan Whitehead }
51423f0703cSBryan Whitehead 
lan743x_intr_open(struct lan743x_adapter * adapter)51523f0703cSBryan Whitehead static int lan743x_intr_open(struct lan743x_adapter *adapter)
51623f0703cSBryan Whitehead {
517ac16b6ebSRaju Lakkaraju 	struct msix_entry msix_entries[PCI11X1X_MAX_VECTOR_COUNT];
51823f0703cSBryan Whitehead 	struct lan743x_intr *intr = &adapter->intr;
519cf9aaea8SRaju Lakkaraju 	unsigned int used_tx_channels;
52023f0703cSBryan Whitehead 	u32 int_vec_en_auto_clr = 0;
521ac16b6ebSRaju Lakkaraju 	u8 max_vector_count;
52223f0703cSBryan Whitehead 	u32 int_vec_map0 = 0;
52323f0703cSBryan Whitehead 	u32 int_vec_map1 = 0;
52423f0703cSBryan Whitehead 	int ret = -ENODEV;
52523f0703cSBryan Whitehead 	int index = 0;
52623f0703cSBryan Whitehead 	u32 flags = 0;
52723f0703cSBryan Whitehead 
52823f0703cSBryan Whitehead 	intr->number_of_vectors = 0;
52923f0703cSBryan Whitehead 
53023f0703cSBryan Whitehead 	/* Try to set up MSIX interrupts */
531ac16b6ebSRaju Lakkaraju 	max_vector_count = adapter->max_vector_count;
53223f0703cSBryan Whitehead 	memset(&msix_entries[0], 0,
533ac16b6ebSRaju Lakkaraju 	       sizeof(struct msix_entry) * max_vector_count);
534ac16b6ebSRaju Lakkaraju 	for (index = 0; index < max_vector_count; index++)
53523f0703cSBryan Whitehead 		msix_entries[index].entry = index;
536cf9aaea8SRaju Lakkaraju 	used_tx_channels = adapter->used_tx_channels;
53723f0703cSBryan Whitehead 	ret = pci_enable_msix_range(adapter->pdev,
53823f0703cSBryan Whitehead 				    msix_entries, 1,
539cf9aaea8SRaju Lakkaraju 				    1 + used_tx_channels +
54023f0703cSBryan Whitehead 				    LAN743X_USED_RX_CHANNELS);
54123f0703cSBryan Whitehead 
54223f0703cSBryan Whitehead 	if (ret > 0) {
54323f0703cSBryan Whitehead 		intr->flags |= INTR_FLAG_MSIX_ENABLED;
54423f0703cSBryan Whitehead 		intr->number_of_vectors = ret;
54523f0703cSBryan Whitehead 		intr->using_vectors = true;
54623f0703cSBryan Whitehead 		for (index = 0; index < intr->number_of_vectors; index++)
54723f0703cSBryan Whitehead 			intr->vector_list[index].irq = msix_entries
54823f0703cSBryan Whitehead 						       [index].vector;
54923f0703cSBryan Whitehead 		netif_info(adapter, ifup, adapter->netdev,
55023f0703cSBryan Whitehead 			   "using MSIX interrupts, number of vectors = %d\n",
55123f0703cSBryan Whitehead 			   intr->number_of_vectors);
55223f0703cSBryan Whitehead 	}
55323f0703cSBryan Whitehead 
55423f0703cSBryan Whitehead 	/* If MSIX failed try to setup using MSI interrupts */
55523f0703cSBryan Whitehead 	if (!intr->number_of_vectors) {
55623f0703cSBryan Whitehead 		if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
55723f0703cSBryan Whitehead 			if (!pci_enable_msi(adapter->pdev)) {
55823f0703cSBryan Whitehead 				intr->flags |= INTR_FLAG_MSI_ENABLED;
55923f0703cSBryan Whitehead 				intr->number_of_vectors = 1;
56023f0703cSBryan Whitehead 				intr->using_vectors = true;
56123f0703cSBryan Whitehead 				intr->vector_list[0].irq =
56223f0703cSBryan Whitehead 					adapter->pdev->irq;
56323f0703cSBryan Whitehead 				netif_info(adapter, ifup, adapter->netdev,
56423f0703cSBryan Whitehead 					   "using MSI interrupts, number of vectors = %d\n",
56523f0703cSBryan Whitehead 					   intr->number_of_vectors);
56623f0703cSBryan Whitehead 			}
56723f0703cSBryan Whitehead 		}
56823f0703cSBryan Whitehead 	}
56923f0703cSBryan Whitehead 
57023f0703cSBryan Whitehead 	/* If MSIX, and MSI failed, setup using legacy interrupt */
57123f0703cSBryan Whitehead 	if (!intr->number_of_vectors) {
57223f0703cSBryan Whitehead 		intr->number_of_vectors = 1;
57323f0703cSBryan Whitehead 		intr->using_vectors = false;
57423f0703cSBryan Whitehead 		intr->vector_list[0].irq = intr->irq;
57523f0703cSBryan Whitehead 		netif_info(adapter, ifup, adapter->netdev,
57623f0703cSBryan Whitehead 			   "using legacy interrupts\n");
57723f0703cSBryan Whitehead 	}
57823f0703cSBryan Whitehead 
57923f0703cSBryan Whitehead 	/* At this point we must have at least one irq */
58023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_VEC_EN_CLR, 0xFFFFFFFF);
58123f0703cSBryan Whitehead 
58223f0703cSBryan Whitehead 	/* map all interrupts to vector 0 */
58323f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_VEC_MAP0, 0x00000000);
58423f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_VEC_MAP1, 0x00000000);
58523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_VEC_MAP2, 0x00000000);
58623f0703cSBryan Whitehead 	flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ |
58723f0703cSBryan Whitehead 		LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C |
58823f0703cSBryan Whitehead 		LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK |
58923f0703cSBryan Whitehead 		LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR;
59023f0703cSBryan Whitehead 
59123f0703cSBryan Whitehead 	if (intr->using_vectors) {
59223f0703cSBryan Whitehead 		flags |= LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR |
59323f0703cSBryan Whitehead 			 LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET;
59423f0703cSBryan Whitehead 	} else {
59523f0703cSBryan Whitehead 		flags |= LAN743X_VECTOR_FLAG_MASTER_ENABLE_CLEAR |
59623f0703cSBryan Whitehead 			 LAN743X_VECTOR_FLAG_MASTER_ENABLE_SET |
59723f0703cSBryan Whitehead 			 LAN743X_VECTOR_FLAG_IRQ_SHARED;
59823f0703cSBryan Whitehead 	}
59923f0703cSBryan Whitehead 
60023f0703cSBryan Whitehead 	if (adapter->csr.flags & LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) {
60123f0703cSBryan Whitehead 		flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ;
60223f0703cSBryan Whitehead 		flags &= ~LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C;
60323f0703cSBryan Whitehead 		flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR;
60423f0703cSBryan Whitehead 		flags &= ~LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK;
60523f0703cSBryan Whitehead 		flags |= LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C;
60623f0703cSBryan Whitehead 		flags |= LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C;
60723f0703cSBryan Whitehead 	}
60823f0703cSBryan Whitehead 
609470dfd80SSven Van Asbroeck 	init_waitqueue_head(&intr->software_isr_wq);
610470dfd80SSven Van Asbroeck 
61123f0703cSBryan Whitehead 	ret = lan743x_intr_register_isr(adapter, 0, flags,
61223f0703cSBryan Whitehead 					INT_BIT_ALL_RX_ | INT_BIT_ALL_TX_ |
61323f0703cSBryan Whitehead 					INT_BIT_ALL_OTHER_,
61423f0703cSBryan Whitehead 					lan743x_intr_shared_isr, adapter);
61523f0703cSBryan Whitehead 	if (ret)
61623f0703cSBryan Whitehead 		goto clean_up;
61723f0703cSBryan Whitehead 	intr->flags |= INTR_FLAG_IRQ_REQUESTED(0);
61823f0703cSBryan Whitehead 
61923f0703cSBryan Whitehead 	if (intr->using_vectors)
62023f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_VEC_EN_SET,
62123f0703cSBryan Whitehead 				  INT_VEC_EN_(0));
62223f0703cSBryan Whitehead 
62323f0703cSBryan Whitehead 	if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
62423f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG0, LAN743X_INT_MOD);
62523f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG1, LAN743X_INT_MOD);
62623f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG2, LAN743X_INT_MOD);
62723f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG3, LAN743X_INT_MOD);
62823f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG4, LAN743X_INT_MOD);
62923f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG5, LAN743X_INT_MOD);
63023f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG6, LAN743X_INT_MOD);
63123f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_CFG7, LAN743X_INT_MOD);
632ac16b6ebSRaju Lakkaraju 		if (adapter->is_pci11x1x) {
633ac16b6ebSRaju Lakkaraju 			lan743x_csr_write(adapter, INT_MOD_CFG8, LAN743X_INT_MOD);
634ac16b6ebSRaju Lakkaraju 			lan743x_csr_write(adapter, INT_MOD_CFG9, LAN743X_INT_MOD);
635ac16b6ebSRaju Lakkaraju 			lan743x_csr_write(adapter, INT_MOD_MAP0, 0x00007654);
636ac16b6ebSRaju Lakkaraju 			lan743x_csr_write(adapter, INT_MOD_MAP1, 0x00003210);
637ac16b6ebSRaju Lakkaraju 		} else {
63823f0703cSBryan Whitehead 			lan743x_csr_write(adapter, INT_MOD_MAP0, 0x00005432);
63923f0703cSBryan Whitehead 			lan743x_csr_write(adapter, INT_MOD_MAP1, 0x00000001);
640ac16b6ebSRaju Lakkaraju 		}
64123f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_MOD_MAP2, 0x00FFFFFF);
64223f0703cSBryan Whitehead 	}
64323f0703cSBryan Whitehead 
64423f0703cSBryan Whitehead 	/* enable interrupts */
64523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_SET, INT_BIT_MAS_);
64623f0703cSBryan Whitehead 	ret = lan743x_intr_test_isr(adapter);
64723f0703cSBryan Whitehead 	if (ret)
64823f0703cSBryan Whitehead 		goto clean_up;
64923f0703cSBryan Whitehead 
65023f0703cSBryan Whitehead 	if (intr->number_of_vectors > 1) {
65123f0703cSBryan Whitehead 		int number_of_tx_vectors = intr->number_of_vectors - 1;
65223f0703cSBryan Whitehead 
653cf9aaea8SRaju Lakkaraju 		if (number_of_tx_vectors > used_tx_channels)
654cf9aaea8SRaju Lakkaraju 			number_of_tx_vectors = used_tx_channels;
65523f0703cSBryan Whitehead 		flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ |
65623f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C |
65723f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK |
65823f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR |
65923f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR |
66023f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET;
66123f0703cSBryan Whitehead 
66223f0703cSBryan Whitehead 		if (adapter->csr.flags &
66323f0703cSBryan Whitehead 		   LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) {
664deb6bfabSBryan Whitehead 			flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET |
66523f0703cSBryan Whitehead 				LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET |
66623f0703cSBryan Whitehead 				LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR |
66723f0703cSBryan Whitehead 				LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR;
66823f0703cSBryan Whitehead 		}
66923f0703cSBryan Whitehead 
67023f0703cSBryan Whitehead 		for (index = 0; index < number_of_tx_vectors; index++) {
67123f0703cSBryan Whitehead 			u32 int_bit = INT_BIT_DMA_TX_(index);
67223f0703cSBryan Whitehead 			int vector = index + 1;
67323f0703cSBryan Whitehead 
67423f0703cSBryan Whitehead 			/* map TX interrupt to vector */
67523f0703cSBryan Whitehead 			int_vec_map1 |= INT_VEC_MAP1_TX_VEC_(index, vector);
67623f0703cSBryan Whitehead 			lan743x_csr_write(adapter, INT_VEC_MAP1, int_vec_map1);
67723f0703cSBryan Whitehead 
67823f0703cSBryan Whitehead 			/* Remove TX interrupt from shared mask */
67923f0703cSBryan Whitehead 			intr->vector_list[0].int_mask &= ~int_bit;
68023f0703cSBryan Whitehead 			ret = lan743x_intr_register_isr(adapter, vector, flags,
68123f0703cSBryan Whitehead 							int_bit, lan743x_tx_isr,
68223f0703cSBryan Whitehead 							&adapter->tx[index]);
68323f0703cSBryan Whitehead 			if (ret)
68423f0703cSBryan Whitehead 				goto clean_up;
68523f0703cSBryan Whitehead 			intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector);
68623f0703cSBryan Whitehead 			if (!(flags &
68723f0703cSBryan Whitehead 			    LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET))
68823f0703cSBryan Whitehead 				lan743x_csr_write(adapter, INT_VEC_EN_SET,
68923f0703cSBryan Whitehead 						  INT_VEC_EN_(vector));
69023f0703cSBryan Whitehead 		}
69123f0703cSBryan Whitehead 	}
692cf9aaea8SRaju Lakkaraju 	if ((intr->number_of_vectors - used_tx_channels) > 1) {
69323f0703cSBryan Whitehead 		int number_of_rx_vectors = intr->number_of_vectors -
694cf9aaea8SRaju Lakkaraju 						used_tx_channels - 1;
69523f0703cSBryan Whitehead 
69623f0703cSBryan Whitehead 		if (number_of_rx_vectors > LAN743X_USED_RX_CHANNELS)
69723f0703cSBryan Whitehead 			number_of_rx_vectors = LAN743X_USED_RX_CHANNELS;
69823f0703cSBryan Whitehead 
69923f0703cSBryan Whitehead 		flags = LAN743X_VECTOR_FLAG_SOURCE_STATUS_READ |
70023f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C |
70123f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CHECK |
70223f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_SOURCE_ENABLE_CLEAR |
70323f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_CLEAR |
70423f0703cSBryan Whitehead 			LAN743X_VECTOR_FLAG_VECTOR_ENABLE_ISR_SET;
70523f0703cSBryan Whitehead 
70623f0703cSBryan Whitehead 		if (adapter->csr.flags &
70723f0703cSBryan Whitehead 		    LAN743X_CSR_FLAG_SUPPORTS_INTR_AUTO_SET_CLR) {
70823f0703cSBryan Whitehead 			flags = LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR |
70923f0703cSBryan Whitehead 				LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET |
71023f0703cSBryan Whitehead 				LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET |
71123f0703cSBryan Whitehead 				LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR |
71223f0703cSBryan Whitehead 				LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR;
71323f0703cSBryan Whitehead 		}
71423f0703cSBryan Whitehead 		for (index = 0; index < number_of_rx_vectors; index++) {
715ac16b6ebSRaju Lakkaraju 			int vector = index + 1 + used_tx_channels;
71623f0703cSBryan Whitehead 			u32 int_bit = INT_BIT_DMA_RX_(index);
71723f0703cSBryan Whitehead 
71823f0703cSBryan Whitehead 			/* map RX interrupt to vector */
71923f0703cSBryan Whitehead 			int_vec_map0 |= INT_VEC_MAP0_RX_VEC_(index, vector);
72023f0703cSBryan Whitehead 			lan743x_csr_write(adapter, INT_VEC_MAP0, int_vec_map0);
72123f0703cSBryan Whitehead 			if (flags &
72223f0703cSBryan Whitehead 			    LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_CLEAR) {
72323f0703cSBryan Whitehead 				int_vec_en_auto_clr |= INT_VEC_EN_(vector);
72423f0703cSBryan Whitehead 				lan743x_csr_write(adapter, INT_VEC_EN_AUTO_CLR,
72523f0703cSBryan Whitehead 						  int_vec_en_auto_clr);
72623f0703cSBryan Whitehead 			}
72723f0703cSBryan Whitehead 
72823f0703cSBryan Whitehead 			/* Remove RX interrupt from shared mask */
72923f0703cSBryan Whitehead 			intr->vector_list[0].int_mask &= ~int_bit;
73023f0703cSBryan Whitehead 			ret = lan743x_intr_register_isr(adapter, vector, flags,
73123f0703cSBryan Whitehead 							int_bit, lan743x_rx_isr,
73223f0703cSBryan Whitehead 							&adapter->rx[index]);
73323f0703cSBryan Whitehead 			if (ret)
73423f0703cSBryan Whitehead 				goto clean_up;
73523f0703cSBryan Whitehead 			intr->flags |= INTR_FLAG_IRQ_REQUESTED(vector);
73623f0703cSBryan Whitehead 
73723f0703cSBryan Whitehead 			lan743x_csr_write(adapter, INT_VEC_EN_SET,
73823f0703cSBryan Whitehead 					  INT_VEC_EN_(vector));
73923f0703cSBryan Whitehead 		}
74023f0703cSBryan Whitehead 	}
74123f0703cSBryan Whitehead 	return 0;
74223f0703cSBryan Whitehead 
74323f0703cSBryan Whitehead clean_up:
74423f0703cSBryan Whitehead 	lan743x_intr_close(adapter);
74523f0703cSBryan Whitehead 	return ret;
74623f0703cSBryan Whitehead }
74723f0703cSBryan Whitehead 
lan743x_dp_write(struct lan743x_adapter * adapter,u32 select,u32 addr,u32 length,u32 * buf)74823f0703cSBryan Whitehead static int lan743x_dp_write(struct lan743x_adapter *adapter,
74923f0703cSBryan Whitehead 			    u32 select, u32 addr, u32 length, u32 *buf)
75023f0703cSBryan Whitehead {
75123f0703cSBryan Whitehead 	u32 dp_sel;
75223f0703cSBryan Whitehead 	int i;
75323f0703cSBryan Whitehead 
7547a8227b2SMoritz Fischer 	if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL, DP_SEL_DPRDY_,
75523f0703cSBryan Whitehead 					    1, 40, 100, 100))
7562b52a4b6SSven Van Asbroeck 		return -EIO;
75723f0703cSBryan Whitehead 	dp_sel = lan743x_csr_read(adapter, DP_SEL);
75823f0703cSBryan Whitehead 	dp_sel &= ~DP_SEL_MASK_;
75923f0703cSBryan Whitehead 	dp_sel |= select;
76023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DP_SEL, dp_sel);
76123f0703cSBryan Whitehead 
76223f0703cSBryan Whitehead 	for (i = 0; i < length; i++) {
76323f0703cSBryan Whitehead 		lan743x_csr_write(adapter, DP_ADDR, addr + i);
76423f0703cSBryan Whitehead 		lan743x_csr_write(adapter, DP_DATA_0, buf[i]);
76523f0703cSBryan Whitehead 		lan743x_csr_write(adapter, DP_CMD, DP_CMD_WRITE_);
7667a8227b2SMoritz Fischer 		if (lan743x_csr_wait_for_bit_atomic(adapter, DP_SEL,
7677a8227b2SMoritz Fischer 						    DP_SEL_DPRDY_,
76823f0703cSBryan Whitehead 						    1, 40, 100, 100))
7692b52a4b6SSven Van Asbroeck 			return -EIO;
77023f0703cSBryan Whitehead 	}
77123f0703cSBryan Whitehead 
7722b52a4b6SSven Van Asbroeck 	return 0;
77323f0703cSBryan Whitehead }
77423f0703cSBryan Whitehead 
lan743x_mac_mii_access(u16 id,u16 index,int read)77523f0703cSBryan Whitehead static u32 lan743x_mac_mii_access(u16 id, u16 index, int read)
77623f0703cSBryan Whitehead {
77723f0703cSBryan Whitehead 	u32 ret;
77823f0703cSBryan Whitehead 
77923f0703cSBryan Whitehead 	ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) &
78023f0703cSBryan Whitehead 		MAC_MII_ACC_PHY_ADDR_MASK_;
78123f0703cSBryan Whitehead 	ret |= (index << MAC_MII_ACC_MIIRINDA_SHIFT_) &
78223f0703cSBryan Whitehead 		MAC_MII_ACC_MIIRINDA_MASK_;
78323f0703cSBryan Whitehead 
78423f0703cSBryan Whitehead 	if (read)
78523f0703cSBryan Whitehead 		ret |= MAC_MII_ACC_MII_READ_;
78623f0703cSBryan Whitehead 	else
78723f0703cSBryan Whitehead 		ret |= MAC_MII_ACC_MII_WRITE_;
78823f0703cSBryan Whitehead 	ret |= MAC_MII_ACC_MII_BUSY_;
78923f0703cSBryan Whitehead 
79023f0703cSBryan Whitehead 	return ret;
79123f0703cSBryan Whitehead }
79223f0703cSBryan Whitehead 
lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter * adapter)79323f0703cSBryan Whitehead static int lan743x_mac_mii_wait_till_not_busy(struct lan743x_adapter *adapter)
79423f0703cSBryan Whitehead {
79523f0703cSBryan Whitehead 	u32 data;
79623f0703cSBryan Whitehead 
79723f0703cSBryan Whitehead 	return readx_poll_timeout(LAN743X_CSR_READ_OP, MAC_MII_ACC, data,
79823f0703cSBryan Whitehead 				  !(data & MAC_MII_ACC_MII_BUSY_), 0, 1000000);
79923f0703cSBryan Whitehead }
80023f0703cSBryan Whitehead 
lan743x_mdiobus_read_c22(struct mii_bus * bus,int phy_id,int index)8013d90c03cSAndrew Lunn static int lan743x_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int index)
80223f0703cSBryan Whitehead {
80323f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = bus->priv;
80423f0703cSBryan Whitehead 	u32 val, mii_access;
80523f0703cSBryan Whitehead 	int ret;
80623f0703cSBryan Whitehead 
807632c9550SSimon Horman 	/* confirm MII not busy */
80823f0703cSBryan Whitehead 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
80923f0703cSBryan Whitehead 	if (ret < 0)
81023f0703cSBryan Whitehead 		return ret;
81123f0703cSBryan Whitehead 
81223f0703cSBryan Whitehead 	/* set the address, index & direction (read from PHY) */
81323f0703cSBryan Whitehead 	mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_READ);
81423f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_MII_ACC, mii_access);
81523f0703cSBryan Whitehead 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
81623f0703cSBryan Whitehead 	if (ret < 0)
81723f0703cSBryan Whitehead 		return ret;
81823f0703cSBryan Whitehead 
81923f0703cSBryan Whitehead 	val = lan743x_csr_read(adapter, MAC_MII_DATA);
82023f0703cSBryan Whitehead 	return (int)(val & 0xFFFF);
82123f0703cSBryan Whitehead }
82223f0703cSBryan Whitehead 
lan743x_mdiobus_write_c22(struct mii_bus * bus,int phy_id,int index,u16 regval)8233d90c03cSAndrew Lunn static int lan743x_mdiobus_write_c22(struct mii_bus *bus,
82423f0703cSBryan Whitehead 				     int phy_id, int index, u16 regval)
82523f0703cSBryan Whitehead {
82623f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = bus->priv;
82723f0703cSBryan Whitehead 	u32 val, mii_access;
82823f0703cSBryan Whitehead 	int ret;
82923f0703cSBryan Whitehead 
83023f0703cSBryan Whitehead 	/* confirm MII not busy */
83123f0703cSBryan Whitehead 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
83223f0703cSBryan Whitehead 	if (ret < 0)
83323f0703cSBryan Whitehead 		return ret;
83423f0703cSBryan Whitehead 	val = (u32)regval;
83523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_MII_DATA, val);
83623f0703cSBryan Whitehead 
83723f0703cSBryan Whitehead 	/* set the address, index & direction (write to PHY) */
83823f0703cSBryan Whitehead 	mii_access = lan743x_mac_mii_access(phy_id, index, MAC_MII_WRITE);
83923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_MII_ACC, mii_access);
84023f0703cSBryan Whitehead 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
84123f0703cSBryan Whitehead 	return ret;
84223f0703cSBryan Whitehead }
84323f0703cSBryan Whitehead 
lan743x_mac_mmd_access(int id,int dev_addr,int op)8443d90c03cSAndrew Lunn static u32 lan743x_mac_mmd_access(int id, int dev_addr, int op)
845a2ab95a3SRaju Lakkaraju {
846a2ab95a3SRaju Lakkaraju 	u32 ret;
847a2ab95a3SRaju Lakkaraju 
848a2ab95a3SRaju Lakkaraju 	ret = (id << MAC_MII_ACC_PHY_ADDR_SHIFT_) &
849a2ab95a3SRaju Lakkaraju 		MAC_MII_ACC_PHY_ADDR_MASK_;
850a2ab95a3SRaju Lakkaraju 	ret |= (dev_addr << MAC_MII_ACC_MIIMMD_SHIFT_) &
851a2ab95a3SRaju Lakkaraju 		MAC_MII_ACC_MIIMMD_MASK_;
852a2ab95a3SRaju Lakkaraju 	if (op == MMD_ACCESS_WRITE)
853a2ab95a3SRaju Lakkaraju 		ret |= MAC_MII_ACC_MIICMD_WRITE_;
854a2ab95a3SRaju Lakkaraju 	else if (op == MMD_ACCESS_READ)
855a2ab95a3SRaju Lakkaraju 		ret |= MAC_MII_ACC_MIICMD_READ_;
856a2ab95a3SRaju Lakkaraju 	else if (op == MMD_ACCESS_READ_INC)
857a2ab95a3SRaju Lakkaraju 		ret |= MAC_MII_ACC_MIICMD_READ_INC_;
858a2ab95a3SRaju Lakkaraju 	else
859a2ab95a3SRaju Lakkaraju 		ret |= MAC_MII_ACC_MIICMD_ADDR_;
860a2ab95a3SRaju Lakkaraju 	ret |= (MAC_MII_ACC_MII_BUSY_ | MAC_MII_ACC_MIICL45_);
861a2ab95a3SRaju Lakkaraju 
862a2ab95a3SRaju Lakkaraju 	return ret;
863a2ab95a3SRaju Lakkaraju }
864a2ab95a3SRaju Lakkaraju 
lan743x_mdiobus_read_c45(struct mii_bus * bus,int phy_id,int dev_addr,int index)8653d90c03cSAndrew Lunn static int lan743x_mdiobus_read_c45(struct mii_bus *bus, int phy_id,
8663d90c03cSAndrew Lunn 				    int dev_addr, int index)
867a2ab95a3SRaju Lakkaraju {
868a2ab95a3SRaju Lakkaraju 	struct lan743x_adapter *adapter = bus->priv;
869a2ab95a3SRaju Lakkaraju 	u32 mmd_access;
870a2ab95a3SRaju Lakkaraju 	int ret;
871a2ab95a3SRaju Lakkaraju 
872632c9550SSimon Horman 	/* confirm MII not busy */
873a2ab95a3SRaju Lakkaraju 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
874a2ab95a3SRaju Lakkaraju 	if (ret < 0)
875a2ab95a3SRaju Lakkaraju 		return ret;
8763d90c03cSAndrew Lunn 
877a2ab95a3SRaju Lakkaraju 	/* Load Register Address */
8783d90c03cSAndrew Lunn 	lan743x_csr_write(adapter, MAC_MII_DATA, index);
8793d90c03cSAndrew Lunn 	mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
880a2ab95a3SRaju Lakkaraju 					    MMD_ACCESS_ADDRESS);
881a2ab95a3SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
882a2ab95a3SRaju Lakkaraju 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
883a2ab95a3SRaju Lakkaraju 	if (ret < 0)
884a2ab95a3SRaju Lakkaraju 		return ret;
8853d90c03cSAndrew Lunn 
886a2ab95a3SRaju Lakkaraju 	/* Read Data */
8873d90c03cSAndrew Lunn 	mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
888a2ab95a3SRaju Lakkaraju 					    MMD_ACCESS_READ);
889a2ab95a3SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
890a2ab95a3SRaju Lakkaraju 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
891a2ab95a3SRaju Lakkaraju 	if (ret < 0)
892a2ab95a3SRaju Lakkaraju 		return ret;
8933d90c03cSAndrew Lunn 
894a2ab95a3SRaju Lakkaraju 	ret = lan743x_csr_read(adapter, MAC_MII_DATA);
895a2ab95a3SRaju Lakkaraju 	return (int)(ret & 0xFFFF);
896a2ab95a3SRaju Lakkaraju }
897a2ab95a3SRaju Lakkaraju 
lan743x_mdiobus_write_c45(struct mii_bus * bus,int phy_id,int dev_addr,int index,u16 regval)8983d90c03cSAndrew Lunn static int lan743x_mdiobus_write_c45(struct mii_bus *bus, int phy_id,
8993d90c03cSAndrew Lunn 				     int dev_addr, int index, u16 regval)
900a2ab95a3SRaju Lakkaraju {
901a2ab95a3SRaju Lakkaraju 	struct lan743x_adapter *adapter = bus->priv;
902a2ab95a3SRaju Lakkaraju 	u32 mmd_access;
903a2ab95a3SRaju Lakkaraju 	int ret;
904a2ab95a3SRaju Lakkaraju 
905a2ab95a3SRaju Lakkaraju 	/* confirm MII not busy */
906a2ab95a3SRaju Lakkaraju 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
907a2ab95a3SRaju Lakkaraju 	if (ret < 0)
908a2ab95a3SRaju Lakkaraju 		return ret;
9093d90c03cSAndrew Lunn 
910a2ab95a3SRaju Lakkaraju 	/* Load Register Address */
9113d90c03cSAndrew Lunn 	lan743x_csr_write(adapter, MAC_MII_DATA, (u32)index);
9123d90c03cSAndrew Lunn 	mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
913a2ab95a3SRaju Lakkaraju 					    MMD_ACCESS_ADDRESS);
914a2ab95a3SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
915a2ab95a3SRaju Lakkaraju 	ret = lan743x_mac_mii_wait_till_not_busy(adapter);
916a2ab95a3SRaju Lakkaraju 	if (ret < 0)
917a2ab95a3SRaju Lakkaraju 		return ret;
9183d90c03cSAndrew Lunn 
919a2ab95a3SRaju Lakkaraju 	/* Write Data */
920a2ab95a3SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_MII_DATA, (u32)regval);
9213d90c03cSAndrew Lunn 	mmd_access = lan743x_mac_mmd_access(phy_id, dev_addr,
922a2ab95a3SRaju Lakkaraju 					    MMD_ACCESS_WRITE);
923a2ab95a3SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_MII_ACC, mmd_access);
924a2ab95a3SRaju Lakkaraju 
9253d90c03cSAndrew Lunn 	return lan743x_mac_mii_wait_till_not_busy(adapter);
926a2ab95a3SRaju Lakkaraju }
927a2ab95a3SRaju Lakkaraju 
lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter * adapter)92846b777adSRaju Lakkaraju static int lan743x_sgmii_wait_till_not_busy(struct lan743x_adapter *adapter)
92946b777adSRaju Lakkaraju {
93046b777adSRaju Lakkaraju 	u32 data;
93146b777adSRaju Lakkaraju 	int ret;
93246b777adSRaju Lakkaraju 
93346b777adSRaju Lakkaraju 	ret = readx_poll_timeout(LAN743X_CSR_READ_OP, SGMII_ACC, data,
93446b777adSRaju Lakkaraju 				 !(data & SGMII_ACC_SGMII_BZY_), 100, 1000000);
93546b777adSRaju Lakkaraju 	if (ret < 0)
93646b777adSRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
93746b777adSRaju Lakkaraju 			  "%s: error %d sgmii wait timeout\n", __func__, ret);
93846b777adSRaju Lakkaraju 
93946b777adSRaju Lakkaraju 	return ret;
94046b777adSRaju Lakkaraju }
94146b777adSRaju Lakkaraju 
lan743x_sgmii_read(struct lan743x_adapter * adapter,u8 mmd,u16 addr)94290452205SRaju Lakkaraju int lan743x_sgmii_read(struct lan743x_adapter *adapter, u8 mmd, u16 addr)
94346b777adSRaju Lakkaraju {
94446b777adSRaju Lakkaraju 	u32 mmd_access;
94546b777adSRaju Lakkaraju 	int ret;
94646b777adSRaju Lakkaraju 	u32 val;
94746b777adSRaju Lakkaraju 
94846b777adSRaju Lakkaraju 	if (mmd > 31) {
94946b777adSRaju Lakkaraju 		netif_err(adapter, probe, adapter->netdev,
95046b777adSRaju Lakkaraju 			  "%s mmd should <= 31\n", __func__);
95146b777adSRaju Lakkaraju 		return -EINVAL;
95246b777adSRaju Lakkaraju 	}
95346b777adSRaju Lakkaraju 
95446b777adSRaju Lakkaraju 	mutex_lock(&adapter->sgmii_rw_lock);
95546b777adSRaju Lakkaraju 	/* Load Register Address */
95646b777adSRaju Lakkaraju 	mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
95746b777adSRaju Lakkaraju 	mmd_access |= (addr | SGMII_ACC_SGMII_BZY_);
95846b777adSRaju Lakkaraju 	lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
95946b777adSRaju Lakkaraju 	ret = lan743x_sgmii_wait_till_not_busy(adapter);
96046b777adSRaju Lakkaraju 	if (ret < 0)
96146b777adSRaju Lakkaraju 		goto sgmii_unlock;
96246b777adSRaju Lakkaraju 
96346b777adSRaju Lakkaraju 	val = lan743x_csr_read(adapter, SGMII_DATA);
96446b777adSRaju Lakkaraju 	ret = (int)(val & SGMII_DATA_MASK_);
96546b777adSRaju Lakkaraju 
96646b777adSRaju Lakkaraju sgmii_unlock:
96746b777adSRaju Lakkaraju 	mutex_unlock(&adapter->sgmii_rw_lock);
96846b777adSRaju Lakkaraju 
96946b777adSRaju Lakkaraju 	return ret;
97046b777adSRaju Lakkaraju }
97146b777adSRaju Lakkaraju 
lan743x_sgmii_write(struct lan743x_adapter * adapter,u8 mmd,u16 addr,u16 val)97246b777adSRaju Lakkaraju static int lan743x_sgmii_write(struct lan743x_adapter *adapter,
97346b777adSRaju Lakkaraju 			       u8 mmd, u16 addr, u16 val)
97446b777adSRaju Lakkaraju {
97546b777adSRaju Lakkaraju 	u32 mmd_access;
97646b777adSRaju Lakkaraju 	int ret;
97746b777adSRaju Lakkaraju 
97846b777adSRaju Lakkaraju 	if (mmd > 31) {
97946b777adSRaju Lakkaraju 		netif_err(adapter, probe, adapter->netdev,
98046b777adSRaju Lakkaraju 			  "%s mmd should <= 31\n", __func__);
98146b777adSRaju Lakkaraju 		return -EINVAL;
98246b777adSRaju Lakkaraju 	}
98346b777adSRaju Lakkaraju 	mutex_lock(&adapter->sgmii_rw_lock);
98446b777adSRaju Lakkaraju 	/* Load Register Data */
98546b777adSRaju Lakkaraju 	lan743x_csr_write(adapter, SGMII_DATA, (u32)(val & SGMII_DATA_MASK_));
98646b777adSRaju Lakkaraju 	/* Load Register Address */
98746b777adSRaju Lakkaraju 	mmd_access = mmd << SGMII_ACC_SGMII_MMD_SHIFT_;
98846b777adSRaju Lakkaraju 	mmd_access |= (addr | SGMII_ACC_SGMII_BZY_ | SGMII_ACC_SGMII_WR_);
98946b777adSRaju Lakkaraju 	lan743x_csr_write(adapter, SGMII_ACC, mmd_access);
99046b777adSRaju Lakkaraju 	ret = lan743x_sgmii_wait_till_not_busy(adapter);
99146b777adSRaju Lakkaraju 	mutex_unlock(&adapter->sgmii_rw_lock);
99246b777adSRaju Lakkaraju 
99346b777adSRaju Lakkaraju 	return ret;
99446b777adSRaju Lakkaraju }
99546b777adSRaju Lakkaraju 
lan743x_get_lsd(int speed,int duplex,u8 mss)99692b740a4SRaju Lakkaraju static int lan743x_get_lsd(int speed, int duplex, u8 mss)
99792b740a4SRaju Lakkaraju {
99892b740a4SRaju Lakkaraju 	int lsd;
99992b740a4SRaju Lakkaraju 
100092b740a4SRaju Lakkaraju 	switch (speed) {
100192b740a4SRaju Lakkaraju 	case SPEED_2500:
100292b740a4SRaju Lakkaraju 		if (mss == MASTER_SLAVE_STATE_SLAVE)
100392b740a4SRaju Lakkaraju 			lsd = LINK_2500_SLAVE;
100492b740a4SRaju Lakkaraju 		else
100592b740a4SRaju Lakkaraju 			lsd = LINK_2500_MASTER;
100692b740a4SRaju Lakkaraju 		break;
100792b740a4SRaju Lakkaraju 	case SPEED_1000:
100892b740a4SRaju Lakkaraju 		if (mss == MASTER_SLAVE_STATE_SLAVE)
100992b740a4SRaju Lakkaraju 			lsd = LINK_1000_SLAVE;
101092b740a4SRaju Lakkaraju 		else
101192b740a4SRaju Lakkaraju 			lsd = LINK_1000_MASTER;
101292b740a4SRaju Lakkaraju 		break;
101392b740a4SRaju Lakkaraju 	case SPEED_100:
101492b740a4SRaju Lakkaraju 		if (duplex == DUPLEX_FULL)
101592b740a4SRaju Lakkaraju 			lsd = LINK_100FD;
101692b740a4SRaju Lakkaraju 		else
101792b740a4SRaju Lakkaraju 			lsd = LINK_100HD;
101892b740a4SRaju Lakkaraju 		break;
101992b740a4SRaju Lakkaraju 	case SPEED_10:
102092b740a4SRaju Lakkaraju 		if (duplex == DUPLEX_FULL)
102192b740a4SRaju Lakkaraju 			lsd = LINK_10FD;
102292b740a4SRaju Lakkaraju 		else
102392b740a4SRaju Lakkaraju 			lsd = LINK_10HD;
102492b740a4SRaju Lakkaraju 		break;
102592b740a4SRaju Lakkaraju 	default:
102692b740a4SRaju Lakkaraju 		lsd = -EINVAL;
102792b740a4SRaju Lakkaraju 	}
102892b740a4SRaju Lakkaraju 
102992b740a4SRaju Lakkaraju 	return lsd;
103092b740a4SRaju Lakkaraju }
103192b740a4SRaju Lakkaraju 
lan743x_sgmii_mpll_set(struct lan743x_adapter * adapter,u16 baud)103246b777adSRaju Lakkaraju static int lan743x_sgmii_mpll_set(struct lan743x_adapter *adapter,
103346b777adSRaju Lakkaraju 				  u16 baud)
103446b777adSRaju Lakkaraju {
103546b777adSRaju Lakkaraju 	int mpllctrl0;
103646b777adSRaju Lakkaraju 	int mpllctrl1;
103746b777adSRaju Lakkaraju 	int miscctrl1;
103846b777adSRaju Lakkaraju 	int ret;
103946b777adSRaju Lakkaraju 
104046b777adSRaju Lakkaraju 	mpllctrl0 = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
104146b777adSRaju Lakkaraju 				       VR_MII_GEN2_4_MPLL_CTRL0);
104246b777adSRaju Lakkaraju 	if (mpllctrl0 < 0)
104346b777adSRaju Lakkaraju 		return mpllctrl0;
104446b777adSRaju Lakkaraju 
104546b777adSRaju Lakkaraju 	mpllctrl0 &= ~VR_MII_MPLL_CTRL0_USE_REFCLK_PAD_;
104646b777adSRaju Lakkaraju 	if (baud == VR_MII_BAUD_RATE_1P25GBPS) {
104746b777adSRaju Lakkaraju 		mpllctrl1 = VR_MII_MPLL_MULTIPLIER_100;
104846b777adSRaju Lakkaraju 		/* mpll_baud_clk/4 */
104946b777adSRaju Lakkaraju 		miscctrl1 = 0xA;
105046b777adSRaju Lakkaraju 	} else {
105146b777adSRaju Lakkaraju 		mpllctrl1 = VR_MII_MPLL_MULTIPLIER_125;
105246b777adSRaju Lakkaraju 		/* mpll_baud_clk/2 */
105346b777adSRaju Lakkaraju 		miscctrl1 = 0x5;
105446b777adSRaju Lakkaraju 	}
105546b777adSRaju Lakkaraju 
105646b777adSRaju Lakkaraju 	ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
105746b777adSRaju Lakkaraju 				  VR_MII_GEN2_4_MPLL_CTRL0, mpllctrl0);
105846b777adSRaju Lakkaraju 	if (ret < 0)
105946b777adSRaju Lakkaraju 		return ret;
106046b777adSRaju Lakkaraju 
106146b777adSRaju Lakkaraju 	ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
106246b777adSRaju Lakkaraju 				  VR_MII_GEN2_4_MPLL_CTRL1, mpllctrl1);
106346b777adSRaju Lakkaraju 	if (ret < 0)
106446b777adSRaju Lakkaraju 		return ret;
106546b777adSRaju Lakkaraju 
106646b777adSRaju Lakkaraju 	return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
106746b777adSRaju Lakkaraju 				  VR_MII_GEN2_4_MISC_CTRL1, miscctrl1);
106846b777adSRaju Lakkaraju }
106946b777adSRaju Lakkaraju 
lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter * adapter,bool enable)107046b777adSRaju Lakkaraju static int lan743x_sgmii_2_5G_mode_set(struct lan743x_adapter *adapter,
107146b777adSRaju Lakkaraju 				       bool enable)
107246b777adSRaju Lakkaraju {
107346b777adSRaju Lakkaraju 	if (enable)
107446b777adSRaju Lakkaraju 		return lan743x_sgmii_mpll_set(adapter,
107546b777adSRaju Lakkaraju 					      VR_MII_BAUD_RATE_3P125GBPS);
107646b777adSRaju Lakkaraju 	else
107746b777adSRaju Lakkaraju 		return lan743x_sgmii_mpll_set(adapter,
107846b777adSRaju Lakkaraju 					      VR_MII_BAUD_RATE_1P25GBPS);
107946b777adSRaju Lakkaraju }
108046b777adSRaju Lakkaraju 
lan743x_serdes_clock_and_aneg_update(struct lan743x_adapter * adapter)1081a5f199a8SRaju Lakkaraju static int lan743x_serdes_clock_and_aneg_update(struct lan743x_adapter *adapter)
108246b777adSRaju Lakkaraju {
108346b777adSRaju Lakkaraju 	enum lan743x_sgmii_lsd lsd = adapter->sgmii_lsd;
108446b777adSRaju Lakkaraju 	int mii_ctrl;
108546b777adSRaju Lakkaraju 	int dgt_ctrl;
108646b777adSRaju Lakkaraju 	int an_ctrl;
108746b777adSRaju Lakkaraju 	int ret;
108846b777adSRaju Lakkaraju 
108946b777adSRaju Lakkaraju 	if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE)
109046b777adSRaju Lakkaraju 		/* Switch to 2.5 Gbps */
109146b777adSRaju Lakkaraju 		ret = lan743x_sgmii_2_5G_mode_set(adapter, true);
109246b777adSRaju Lakkaraju 	else
109346b777adSRaju Lakkaraju 		/* Switch to 10/100/1000 Mbps clock */
109446b777adSRaju Lakkaraju 		ret = lan743x_sgmii_2_5G_mode_set(adapter, false);
109546b777adSRaju Lakkaraju 	if (ret < 0)
109646b777adSRaju Lakkaraju 		return ret;
109746b777adSRaju Lakkaraju 
109846b777adSRaju Lakkaraju 	/* Enable SGMII Auto NEG */
109946b777adSRaju Lakkaraju 	mii_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
110046b777adSRaju Lakkaraju 	if (mii_ctrl < 0)
110146b777adSRaju Lakkaraju 		return mii_ctrl;
110246b777adSRaju Lakkaraju 
110346b777adSRaju Lakkaraju 	an_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, VR_MII_AN_CTRL);
110446b777adSRaju Lakkaraju 	if (an_ctrl < 0)
110546b777adSRaju Lakkaraju 		return an_ctrl;
110646b777adSRaju Lakkaraju 
110746b777adSRaju Lakkaraju 	dgt_ctrl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
110846b777adSRaju Lakkaraju 				      VR_MII_DIG_CTRL1);
110946b777adSRaju Lakkaraju 	if (dgt_ctrl < 0)
111046b777adSRaju Lakkaraju 		return dgt_ctrl;
111146b777adSRaju Lakkaraju 
111246b777adSRaju Lakkaraju 	if (lsd == LINK_2500_MASTER || lsd == LINK_2500_SLAVE) {
111346b777adSRaju Lakkaraju 		mii_ctrl &= ~(BMCR_ANENABLE | BMCR_ANRESTART | BMCR_SPEED100);
111446b777adSRaju Lakkaraju 		mii_ctrl |= BMCR_SPEED1000;
111546b777adSRaju Lakkaraju 		dgt_ctrl |= VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
111646b777adSRaju Lakkaraju 		dgt_ctrl &= ~VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
111746b777adSRaju Lakkaraju 		/* In order for Auto-Negotiation to operate properly at
111846b777adSRaju Lakkaraju 		 * 2.5 Gbps the 1.6ms link timer values must be adjusted
111946b777adSRaju Lakkaraju 		 * The VR_MII_LINK_TIMER_CTRL Register must be set to
112046b777adSRaju Lakkaraju 		 * 16'h7A1 and The CL37_TMR_OVR_RIDE bit of the
112146b777adSRaju Lakkaraju 		 * VR_MII_DIG_CTRL1 Register set to 1
112246b777adSRaju Lakkaraju 		 */
112346b777adSRaju Lakkaraju 		ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
112446b777adSRaju Lakkaraju 					  VR_MII_LINK_TIMER_CTRL, 0x7A1);
112546b777adSRaju Lakkaraju 		if (ret < 0)
112646b777adSRaju Lakkaraju 			return ret;
112746b777adSRaju Lakkaraju 	} else {
112846b777adSRaju Lakkaraju 		mii_ctrl |= (BMCR_ANENABLE | BMCR_ANRESTART);
112946b777adSRaju Lakkaraju 		an_ctrl &= ~VR_MII_AN_CTRL_SGMII_LINK_STS_;
113046b777adSRaju Lakkaraju 		dgt_ctrl &= ~VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE_;
113146b777adSRaju Lakkaraju 		dgt_ctrl |= VR_MII_DIG_CTRL1_MAC_AUTO_SW_;
113246b777adSRaju Lakkaraju 	}
113346b777adSRaju Lakkaraju 
113446b777adSRaju Lakkaraju 	ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR,
113546b777adSRaju Lakkaraju 				  mii_ctrl);
113646b777adSRaju Lakkaraju 	if (ret < 0)
113746b777adSRaju Lakkaraju 		return ret;
113846b777adSRaju Lakkaraju 
113946b777adSRaju Lakkaraju 	ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
114046b777adSRaju Lakkaraju 				  VR_MII_DIG_CTRL1, dgt_ctrl);
114146b777adSRaju Lakkaraju 	if (ret < 0)
114246b777adSRaju Lakkaraju 		return ret;
114346b777adSRaju Lakkaraju 
114446b777adSRaju Lakkaraju 	return lan743x_sgmii_write(adapter, MDIO_MMD_VEND2,
114546b777adSRaju Lakkaraju 				  VR_MII_AN_CTRL, an_ctrl);
114646b777adSRaju Lakkaraju }
114746b777adSRaju Lakkaraju 
lan743x_pcs_seq_state(struct lan743x_adapter * adapter,u8 state)114846b777adSRaju Lakkaraju static int lan743x_pcs_seq_state(struct lan743x_adapter *adapter, u8 state)
114946b777adSRaju Lakkaraju {
115046b777adSRaju Lakkaraju 	u8 wait_cnt = 0;
115146b777adSRaju Lakkaraju 	u32 dig_sts;
115246b777adSRaju Lakkaraju 
115346b777adSRaju Lakkaraju 	do {
115446b777adSRaju Lakkaraju 		dig_sts = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2,
115546b777adSRaju Lakkaraju 					     VR_MII_DIG_STS);
115646b777adSRaju Lakkaraju 		if (((dig_sts & VR_MII_DIG_STS_PSEQ_STATE_MASK_) >>
115746b777adSRaju Lakkaraju 		      VR_MII_DIG_STS_PSEQ_STATE_POS_) == state)
115846b777adSRaju Lakkaraju 			break;
115946b777adSRaju Lakkaraju 		usleep_range(1000, 2000);
116046b777adSRaju Lakkaraju 	} while (wait_cnt++ < 10);
116146b777adSRaju Lakkaraju 
116246b777adSRaju Lakkaraju 	if (wait_cnt >= 10)
116346b777adSRaju Lakkaraju 		return -ETIMEDOUT;
116446b777adSRaju Lakkaraju 
116546b777adSRaju Lakkaraju 	return 0;
116646b777adSRaju Lakkaraju }
116746b777adSRaju Lakkaraju 
lan743x_pcs_power_reset(struct lan743x_adapter * adapter)1168ef025045SRaju Lakkaraju static int lan743x_pcs_power_reset(struct lan743x_adapter *adapter)
1169ef025045SRaju Lakkaraju {
1170ef025045SRaju Lakkaraju 	int mii_ctl;
1171ef025045SRaju Lakkaraju 	int ret;
1172ef025045SRaju Lakkaraju 
1173ef025045SRaju Lakkaraju 	/* SGMII/1000/2500BASE-X PCS power down */
1174ef025045SRaju Lakkaraju 	mii_ctl = lan743x_sgmii_read(adapter, MDIO_MMD_VEND2, MII_BMCR);
1175ef025045SRaju Lakkaraju 	if (mii_ctl < 0)
1176ef025045SRaju Lakkaraju 		return mii_ctl;
1177ef025045SRaju Lakkaraju 
1178ef025045SRaju Lakkaraju 	mii_ctl |= BMCR_PDOWN;
1179ef025045SRaju Lakkaraju 	ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
1180ef025045SRaju Lakkaraju 	if (ret < 0)
1181ef025045SRaju Lakkaraju 		return ret;
1182ef025045SRaju Lakkaraju 
1183ef025045SRaju Lakkaraju 	ret = lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_DOWN);
1184ef025045SRaju Lakkaraju 	if (ret < 0)
1185ef025045SRaju Lakkaraju 		return ret;
1186ef025045SRaju Lakkaraju 
1187ef025045SRaju Lakkaraju 	/* SGMII/1000/2500BASE-X PCS power up */
1188ef025045SRaju Lakkaraju 	mii_ctl &= ~BMCR_PDOWN;
1189ef025045SRaju Lakkaraju 	ret = lan743x_sgmii_write(adapter, MDIO_MMD_VEND2, MII_BMCR, mii_ctl);
1190ef025045SRaju Lakkaraju 	if (ret < 0)
1191ef025045SRaju Lakkaraju 		return ret;
1192ef025045SRaju Lakkaraju 
1193ef025045SRaju Lakkaraju 	return lan743x_pcs_seq_state(adapter, PCS_POWER_STATE_UP);
1194ef025045SRaju Lakkaraju }
1195ef025045SRaju Lakkaraju 
lan743x_mac_set_address(struct lan743x_adapter * adapter,u8 * addr)119623f0703cSBryan Whitehead static void lan743x_mac_set_address(struct lan743x_adapter *adapter,
119723f0703cSBryan Whitehead 				    u8 *addr)
119823f0703cSBryan Whitehead {
119923f0703cSBryan Whitehead 	u32 addr_lo, addr_hi;
120023f0703cSBryan Whitehead 
120123f0703cSBryan Whitehead 	addr_lo = addr[0] |
120223f0703cSBryan Whitehead 		addr[1] << 8 |
120323f0703cSBryan Whitehead 		addr[2] << 16 |
120423f0703cSBryan Whitehead 		addr[3] << 24;
120523f0703cSBryan Whitehead 	addr_hi = addr[4] |
120623f0703cSBryan Whitehead 		addr[5] << 8;
120723f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_RX_ADDRL, addr_lo);
120823f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_RX_ADDRH, addr_hi);
120923f0703cSBryan Whitehead 
121023f0703cSBryan Whitehead 	ether_addr_copy(adapter->mac_address, addr);
121123f0703cSBryan Whitehead 	netif_info(adapter, drv, adapter->netdev,
121223f0703cSBryan Whitehead 		   "MAC address set to %pM\n", addr);
121323f0703cSBryan Whitehead }
121423f0703cSBryan Whitehead 
lan743x_mac_init(struct lan743x_adapter * adapter)121523f0703cSBryan Whitehead static int lan743x_mac_init(struct lan743x_adapter *adapter)
121623f0703cSBryan Whitehead {
121723f0703cSBryan Whitehead 	bool mac_address_valid = true;
121823f0703cSBryan Whitehead 	struct net_device *netdev;
121923f0703cSBryan Whitehead 	u32 mac_addr_hi = 0;
122023f0703cSBryan Whitehead 	u32 mac_addr_lo = 0;
122123f0703cSBryan Whitehead 	u32 data;
122223f0703cSBryan Whitehead 
122323f0703cSBryan Whitehead 	netdev = adapter->netdev;
122423f0703cSBryan Whitehead 
12256f197fb6SRoelof Berg 	/* disable auto duplex, and speed detection. Phylib does that */
122623f0703cSBryan Whitehead 	data = lan743x_csr_read(adapter, MAC_CR);
12276f197fb6SRoelof Berg 	data &= ~(MAC_CR_ADD_ | MAC_CR_ASD_);
122823f0703cSBryan Whitehead 	data |= MAC_CR_CNTR_RST_;
122923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_CR, data);
123023f0703cSBryan Whitehead 
1231c90834cdSTim Harvey 	if (!is_valid_ether_addr(adapter->mac_address)) {
123223f0703cSBryan Whitehead 		mac_addr_hi = lan743x_csr_read(adapter, MAC_RX_ADDRH);
123323f0703cSBryan Whitehead 		mac_addr_lo = lan743x_csr_read(adapter, MAC_RX_ADDRL);
123423f0703cSBryan Whitehead 		adapter->mac_address[0] = mac_addr_lo & 0xFF;
123523f0703cSBryan Whitehead 		adapter->mac_address[1] = (mac_addr_lo >> 8) & 0xFF;
123623f0703cSBryan Whitehead 		adapter->mac_address[2] = (mac_addr_lo >> 16) & 0xFF;
123723f0703cSBryan Whitehead 		adapter->mac_address[3] = (mac_addr_lo >> 24) & 0xFF;
123823f0703cSBryan Whitehead 		adapter->mac_address[4] = mac_addr_hi & 0xFF;
123923f0703cSBryan Whitehead 		adapter->mac_address[5] = (mac_addr_hi >> 8) & 0xFF;
124023f0703cSBryan Whitehead 
124123f0703cSBryan Whitehead 		if (((mac_addr_hi & 0x0000FFFF) == 0x0000FFFF) &&
124223f0703cSBryan Whitehead 		    mac_addr_lo == 0xFFFFFFFF) {
124323f0703cSBryan Whitehead 			mac_address_valid = false;
124423f0703cSBryan Whitehead 		} else if (!is_valid_ether_addr(adapter->mac_address)) {
124523f0703cSBryan Whitehead 			mac_address_valid = false;
124623f0703cSBryan Whitehead 		}
124723f0703cSBryan Whitehead 
124823f0703cSBryan Whitehead 		if (!mac_address_valid)
12496c1f0a1fSJoe Perches 			eth_random_addr(adapter->mac_address);
1250c90834cdSTim Harvey 	}
125123f0703cSBryan Whitehead 	lan743x_mac_set_address(adapter, adapter->mac_address);
1252f3956ebbSJakub Kicinski 	eth_hw_addr_set(netdev, adapter->mac_address);
1253c90834cdSTim Harvey 
125423f0703cSBryan Whitehead 	return 0;
125523f0703cSBryan Whitehead }
125623f0703cSBryan Whitehead 
lan743x_mac_open(struct lan743x_adapter * adapter)125723f0703cSBryan Whitehead static int lan743x_mac_open(struct lan743x_adapter *adapter)
125823f0703cSBryan Whitehead {
125923f0703cSBryan Whitehead 	u32 temp;
126023f0703cSBryan Whitehead 
126123f0703cSBryan Whitehead 	temp = lan743x_csr_read(adapter, MAC_RX);
126223f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_RX, temp | MAC_RX_RXEN_);
126323f0703cSBryan Whitehead 	temp = lan743x_csr_read(adapter, MAC_TX);
126423f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_TX, temp | MAC_TX_TXEN_);
1265585bd812SXu Wang 	return 0;
126623f0703cSBryan Whitehead }
126723f0703cSBryan Whitehead 
lan743x_mac_close(struct lan743x_adapter * adapter)126823f0703cSBryan Whitehead static void lan743x_mac_close(struct lan743x_adapter *adapter)
126923f0703cSBryan Whitehead {
127023f0703cSBryan Whitehead 	u32 temp;
127123f0703cSBryan Whitehead 
127223f0703cSBryan Whitehead 	temp = lan743x_csr_read(adapter, MAC_TX);
127323f0703cSBryan Whitehead 	temp &= ~MAC_TX_TXEN_;
127423f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_TX, temp);
127523f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, MAC_TX, MAC_TX_TXD_,
127623f0703cSBryan Whitehead 				 1, 1000, 20000, 100);
127723f0703cSBryan Whitehead 
127823f0703cSBryan Whitehead 	temp = lan743x_csr_read(adapter, MAC_RX);
127923f0703cSBryan Whitehead 	temp &= ~MAC_RX_RXEN_;
128023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_RX, temp);
128123f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_,
128223f0703cSBryan Whitehead 				 1, 1000, 20000, 100);
128323f0703cSBryan Whitehead }
128423f0703cSBryan Whitehead 
lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter * adapter,bool tx_enable,bool rx_enable)1285cdc04540SRaju Lakkaraju void lan743x_mac_flow_ctrl_set_enables(struct lan743x_adapter *adapter,
128623f0703cSBryan Whitehead 				       bool tx_enable, bool rx_enable)
128723f0703cSBryan Whitehead {
128823f0703cSBryan Whitehead 	u32 flow_setting = 0;
128923f0703cSBryan Whitehead 
129023f0703cSBryan Whitehead 	/* set maximum pause time because when fifo space frees
129123f0703cSBryan Whitehead 	 * up a zero value pause frame will be sent to release the pause
129223f0703cSBryan Whitehead 	 */
129323f0703cSBryan Whitehead 	flow_setting = MAC_FLOW_CR_FCPT_MASK_;
129423f0703cSBryan Whitehead 	if (tx_enable)
129523f0703cSBryan Whitehead 		flow_setting |= MAC_FLOW_CR_TX_FCEN_;
129623f0703cSBryan Whitehead 	if (rx_enable)
129723f0703cSBryan Whitehead 		flow_setting |= MAC_FLOW_CR_RX_FCEN_;
129823f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_FLOW, flow_setting);
129923f0703cSBryan Whitehead }
130023f0703cSBryan Whitehead 
lan743x_mac_set_mtu(struct lan743x_adapter * adapter,int new_mtu)130123f0703cSBryan Whitehead static int lan743x_mac_set_mtu(struct lan743x_adapter *adapter, int new_mtu)
130223f0703cSBryan Whitehead {
130323f0703cSBryan Whitehead 	int enabled = 0;
130423f0703cSBryan Whitehead 	u32 mac_rx = 0;
130523f0703cSBryan Whitehead 
130623f0703cSBryan Whitehead 	mac_rx = lan743x_csr_read(adapter, MAC_RX);
130723f0703cSBryan Whitehead 	if (mac_rx & MAC_RX_RXEN_) {
130823f0703cSBryan Whitehead 		enabled = 1;
130923f0703cSBryan Whitehead 		if (mac_rx & MAC_RX_RXD_) {
131023f0703cSBryan Whitehead 			lan743x_csr_write(adapter, MAC_RX, mac_rx);
131123f0703cSBryan Whitehead 			mac_rx &= ~MAC_RX_RXD_;
131223f0703cSBryan Whitehead 		}
131323f0703cSBryan Whitehead 		mac_rx &= ~MAC_RX_RXEN_;
131423f0703cSBryan Whitehead 		lan743x_csr_write(adapter, MAC_RX, mac_rx);
131523f0703cSBryan Whitehead 		lan743x_csr_wait_for_bit(adapter, MAC_RX, MAC_RX_RXD_,
131623f0703cSBryan Whitehead 					 1, 1000, 20000, 100);
131723f0703cSBryan Whitehead 		lan743x_csr_write(adapter, MAC_RX, mac_rx | MAC_RX_RXD_);
131823f0703cSBryan Whitehead 	}
131923f0703cSBryan Whitehead 
132023f0703cSBryan Whitehead 	mac_rx &= ~(MAC_RX_MAX_SIZE_MASK_);
13213bc41d6dSSven Van Asbroeck 	mac_rx |= (((new_mtu + ETH_HLEN + ETH_FCS_LEN)
13223bc41d6dSSven Van Asbroeck 		  << MAC_RX_MAX_SIZE_SHIFT_) & MAC_RX_MAX_SIZE_MASK_);
132323f0703cSBryan Whitehead 	lan743x_csr_write(adapter, MAC_RX, mac_rx);
132423f0703cSBryan Whitehead 
132523f0703cSBryan Whitehead 	if (enabled) {
132623f0703cSBryan Whitehead 		mac_rx |= MAC_RX_RXEN_;
132723f0703cSBryan Whitehead 		lan743x_csr_write(adapter, MAC_RX, mac_rx);
132823f0703cSBryan Whitehead 	}
132923f0703cSBryan Whitehead 	return 0;
133023f0703cSBryan Whitehead }
133123f0703cSBryan Whitehead 
133223f0703cSBryan Whitehead /* PHY */
lan743x_phy_reset(struct lan743x_adapter * adapter)133323f0703cSBryan Whitehead static int lan743x_phy_reset(struct lan743x_adapter *adapter)
133423f0703cSBryan Whitehead {
133523f0703cSBryan Whitehead 	u32 data;
133623f0703cSBryan Whitehead 
133723f0703cSBryan Whitehead 	/* Only called with in probe, and before mdiobus_register */
133823f0703cSBryan Whitehead 
133923f0703cSBryan Whitehead 	data = lan743x_csr_read(adapter, PMT_CTL);
134023f0703cSBryan Whitehead 	data |= PMT_CTL_ETH_PHY_RST_;
134123f0703cSBryan Whitehead 	lan743x_csr_write(adapter, PMT_CTL, data);
134223f0703cSBryan Whitehead 
134323f0703cSBryan Whitehead 	return readx_poll_timeout(LAN743X_CSR_READ_OP, PMT_CTL, data,
134423f0703cSBryan Whitehead 				  (!(data & PMT_CTL_ETH_PHY_RST_) &&
134523f0703cSBryan Whitehead 				  (data & PMT_CTL_READY_)),
134623f0703cSBryan Whitehead 				  50000, 1000000);
134723f0703cSBryan Whitehead }
134823f0703cSBryan Whitehead 
lan743x_phy_init(struct lan743x_adapter * adapter)134923f0703cSBryan Whitehead static int lan743x_phy_init(struct lan743x_adapter *adapter)
135023f0703cSBryan Whitehead {
13518e8af97aSColin Ian King 	return lan743x_phy_reset(adapter);
135223f0703cSBryan Whitehead }
135323f0703cSBryan Whitehead 
lan743x_phy_interface_select(struct lan743x_adapter * adapter)1354e86c7210SPavithra Sathyanarayanan static void lan743x_phy_interface_select(struct lan743x_adapter *adapter)
1355e86c7210SPavithra Sathyanarayanan {
1356e86c7210SPavithra Sathyanarayanan 	u32 id_rev;
1357e86c7210SPavithra Sathyanarayanan 	u32 data;
1358e86c7210SPavithra Sathyanarayanan 
1359e86c7210SPavithra Sathyanarayanan 	data = lan743x_csr_read(adapter, MAC_CR);
1360e86c7210SPavithra Sathyanarayanan 	id_rev = adapter->csr.id_rev & ID_REV_ID_MASK_;
1361e86c7210SPavithra Sathyanarayanan 
1362e86c7210SPavithra Sathyanarayanan 	if (adapter->is_pci11x1x && adapter->is_sgmii_en)
1363e86c7210SPavithra Sathyanarayanan 		adapter->phy_interface = PHY_INTERFACE_MODE_SGMII;
1364e86c7210SPavithra Sathyanarayanan 	else if (id_rev == ID_REV_ID_LAN7430_)
1365e86c7210SPavithra Sathyanarayanan 		adapter->phy_interface = PHY_INTERFACE_MODE_GMII;
1366e86c7210SPavithra Sathyanarayanan 	else if ((id_rev == ID_REV_ID_LAN7431_) && (data & MAC_CR_MII_EN_))
1367e86c7210SPavithra Sathyanarayanan 		adapter->phy_interface = PHY_INTERFACE_MODE_MII;
1368e86c7210SPavithra Sathyanarayanan 	else
1369e86c7210SPavithra Sathyanarayanan 		adapter->phy_interface = PHY_INTERFACE_MODE_RGMII;
1370e86c7210SPavithra Sathyanarayanan 
1371a5f199a8SRaju Lakkaraju 	netif_dbg(adapter, drv, adapter->netdev,
1372a5f199a8SRaju Lakkaraju 		  "selected phy interface: 0x%X\n", adapter->phy_interface);
137323f0703cSBryan Whitehead }
137423f0703cSBryan Whitehead 
lan743x_rfe_open(struct lan743x_adapter * adapter)137543e8fe9bSBryan Whitehead static void lan743x_rfe_open(struct lan743x_adapter *adapter)
137643e8fe9bSBryan Whitehead {
137743e8fe9bSBryan Whitehead 	lan743x_csr_write(adapter, RFE_RSS_CFG,
137843e8fe9bSBryan Whitehead 		RFE_RSS_CFG_UDP_IPV6_EX_ |
137943e8fe9bSBryan Whitehead 		RFE_RSS_CFG_TCP_IPV6_EX_ |
138043e8fe9bSBryan Whitehead 		RFE_RSS_CFG_IPV6_EX_ |
138143e8fe9bSBryan Whitehead 		RFE_RSS_CFG_UDP_IPV6_ |
138243e8fe9bSBryan Whitehead 		RFE_RSS_CFG_TCP_IPV6_ |
138343e8fe9bSBryan Whitehead 		RFE_RSS_CFG_IPV6_ |
138443e8fe9bSBryan Whitehead 		RFE_RSS_CFG_UDP_IPV4_ |
138543e8fe9bSBryan Whitehead 		RFE_RSS_CFG_TCP_IPV4_ |
138643e8fe9bSBryan Whitehead 		RFE_RSS_CFG_IPV4_ |
138743e8fe9bSBryan Whitehead 		RFE_RSS_CFG_VALID_HASH_BITS_ |
138843e8fe9bSBryan Whitehead 		RFE_RSS_CFG_RSS_QUEUE_ENABLE_ |
138943e8fe9bSBryan Whitehead 		RFE_RSS_CFG_RSS_HASH_STORE_ |
139043e8fe9bSBryan Whitehead 		RFE_RSS_CFG_RSS_ENABLE_);
139143e8fe9bSBryan Whitehead }
139243e8fe9bSBryan Whitehead 
lan743x_rfe_update_mac_address(struct lan743x_adapter * adapter)139323f0703cSBryan Whitehead static void lan743x_rfe_update_mac_address(struct lan743x_adapter *adapter)
139423f0703cSBryan Whitehead {
139523f0703cSBryan Whitehead 	u8 *mac_addr;
139623f0703cSBryan Whitehead 	u32 mac_addr_hi = 0;
139723f0703cSBryan Whitehead 	u32 mac_addr_lo = 0;
139823f0703cSBryan Whitehead 
139923f0703cSBryan Whitehead 	/* Add mac address to perfect Filter */
140023f0703cSBryan Whitehead 	mac_addr = adapter->mac_address;
140123f0703cSBryan Whitehead 	mac_addr_lo = ((((u32)(mac_addr[0])) << 0) |
140223f0703cSBryan Whitehead 		      (((u32)(mac_addr[1])) << 8) |
140323f0703cSBryan Whitehead 		      (((u32)(mac_addr[2])) << 16) |
140423f0703cSBryan Whitehead 		      (((u32)(mac_addr[3])) << 24));
140523f0703cSBryan Whitehead 	mac_addr_hi = ((((u32)(mac_addr[4])) << 0) |
140623f0703cSBryan Whitehead 		      (((u32)(mac_addr[5])) << 8));
140723f0703cSBryan Whitehead 
140823f0703cSBryan Whitehead 	lan743x_csr_write(adapter, RFE_ADDR_FILT_LO(0), mac_addr_lo);
140923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, RFE_ADDR_FILT_HI(0),
141023f0703cSBryan Whitehead 			  mac_addr_hi | RFE_ADDR_FILT_HI_VALID_);
141123f0703cSBryan Whitehead }
141223f0703cSBryan Whitehead 
lan743x_rfe_set_multicast(struct lan743x_adapter * adapter)141323f0703cSBryan Whitehead static void lan743x_rfe_set_multicast(struct lan743x_adapter *adapter)
141423f0703cSBryan Whitehead {
141523f0703cSBryan Whitehead 	struct net_device *netdev = adapter->netdev;
141623f0703cSBryan Whitehead 	u32 hash_table[DP_SEL_VHF_HASH_LEN];
141723f0703cSBryan Whitehead 	u32 rfctl;
141823f0703cSBryan Whitehead 	u32 data;
141923f0703cSBryan Whitehead 
142023f0703cSBryan Whitehead 	rfctl = lan743x_csr_read(adapter, RFE_CTL);
142123f0703cSBryan Whitehead 	rfctl &= ~(RFE_CTL_AU_ | RFE_CTL_AM_ |
142223f0703cSBryan Whitehead 		 RFE_CTL_DA_PERFECT_ | RFE_CTL_MCAST_HASH_);
142323f0703cSBryan Whitehead 	rfctl |= RFE_CTL_AB_;
142423f0703cSBryan Whitehead 	if (netdev->flags & IFF_PROMISC) {
142523f0703cSBryan Whitehead 		rfctl |= RFE_CTL_AM_ | RFE_CTL_AU_;
142623f0703cSBryan Whitehead 	} else {
142723f0703cSBryan Whitehead 		if (netdev->flags & IFF_ALLMULTI)
142823f0703cSBryan Whitehead 			rfctl |= RFE_CTL_AM_;
142923f0703cSBryan Whitehead 	}
143023f0703cSBryan Whitehead 
1431cd691050SRaju Lakkaraju 	if (netdev->features & NETIF_F_RXCSUM)
1432cd691050SRaju Lakkaraju 		rfctl |= RFE_CTL_IP_COE_ | RFE_CTL_TCP_UDP_COE_;
1433cd691050SRaju Lakkaraju 
143423f0703cSBryan Whitehead 	memset(hash_table, 0, DP_SEL_VHF_HASH_LEN * sizeof(u32));
143523f0703cSBryan Whitehead 	if (netdev_mc_count(netdev)) {
143623f0703cSBryan Whitehead 		struct netdev_hw_addr *ha;
143723f0703cSBryan Whitehead 		int i;
143823f0703cSBryan Whitehead 
143923f0703cSBryan Whitehead 		rfctl |= RFE_CTL_DA_PERFECT_;
144023f0703cSBryan Whitehead 		i = 1;
144123f0703cSBryan Whitehead 		netdev_for_each_mc_addr(ha, netdev) {
144223f0703cSBryan Whitehead 			/* set first 32 into Perfect Filter */
144323f0703cSBryan Whitehead 			if (i < 33) {
144423f0703cSBryan Whitehead 				lan743x_csr_write(adapter,
144523f0703cSBryan Whitehead 						  RFE_ADDR_FILT_HI(i), 0);
144623f0703cSBryan Whitehead 				data = ha->addr[3];
144723f0703cSBryan Whitehead 				data = ha->addr[2] | (data << 8);
144823f0703cSBryan Whitehead 				data = ha->addr[1] | (data << 8);
144923f0703cSBryan Whitehead 				data = ha->addr[0] | (data << 8);
145023f0703cSBryan Whitehead 				lan743x_csr_write(adapter,
145123f0703cSBryan Whitehead 						  RFE_ADDR_FILT_LO(i), data);
145223f0703cSBryan Whitehead 				data = ha->addr[5];
145323f0703cSBryan Whitehead 				data = ha->addr[4] | (data << 8);
145423f0703cSBryan Whitehead 				data |= RFE_ADDR_FILT_HI_VALID_;
145523f0703cSBryan Whitehead 				lan743x_csr_write(adapter,
145623f0703cSBryan Whitehead 						  RFE_ADDR_FILT_HI(i), data);
145723f0703cSBryan Whitehead 			} else {
145823f0703cSBryan Whitehead 				u32 bitnum = (ether_crc(ETH_ALEN, ha->addr) >>
145923f0703cSBryan Whitehead 					     23) & 0x1FF;
146023f0703cSBryan Whitehead 				hash_table[bitnum / 32] |= (1 << (bitnum % 32));
146123f0703cSBryan Whitehead 				rfctl |= RFE_CTL_MCAST_HASH_;
146223f0703cSBryan Whitehead 			}
146323f0703cSBryan Whitehead 			i++;
146423f0703cSBryan Whitehead 		}
146523f0703cSBryan Whitehead 	}
146623f0703cSBryan Whitehead 
146723f0703cSBryan Whitehead 	lan743x_dp_write(adapter, DP_SEL_RFE_RAM,
146823f0703cSBryan Whitehead 			 DP_SEL_VHF_VLAN_LEN,
146923f0703cSBryan Whitehead 			 DP_SEL_VHF_HASH_LEN, hash_table);
147023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, RFE_CTL, rfctl);
147123f0703cSBryan Whitehead }
147223f0703cSBryan Whitehead 
lan743x_dmac_init(struct lan743x_adapter * adapter)147323f0703cSBryan Whitehead static int lan743x_dmac_init(struct lan743x_adapter *adapter)
147423f0703cSBryan Whitehead {
147523f0703cSBryan Whitehead 	u32 data = 0;
147623f0703cSBryan Whitehead 
147723f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_CMD, DMAC_CMD_SWR_);
147823f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, DMAC_CMD, DMAC_CMD_SWR_,
147923f0703cSBryan Whitehead 				 0, 1000, 20000, 100);
148023f0703cSBryan Whitehead 	switch (DEFAULT_DMA_DESCRIPTOR_SPACING) {
148123f0703cSBryan Whitehead 	case DMA_DESCRIPTOR_SPACING_16:
148223f0703cSBryan Whitehead 		data = DMAC_CFG_MAX_DSPACE_16_;
148323f0703cSBryan Whitehead 		break;
148423f0703cSBryan Whitehead 	case DMA_DESCRIPTOR_SPACING_32:
148523f0703cSBryan Whitehead 		data = DMAC_CFG_MAX_DSPACE_32_;
148623f0703cSBryan Whitehead 		break;
148723f0703cSBryan Whitehead 	case DMA_DESCRIPTOR_SPACING_64:
148823f0703cSBryan Whitehead 		data = DMAC_CFG_MAX_DSPACE_64_;
148923f0703cSBryan Whitehead 		break;
149023f0703cSBryan Whitehead 	case DMA_DESCRIPTOR_SPACING_128:
149123f0703cSBryan Whitehead 		data = DMAC_CFG_MAX_DSPACE_128_;
149223f0703cSBryan Whitehead 		break;
149323f0703cSBryan Whitehead 	default:
149423f0703cSBryan Whitehead 		return -EPERM;
149523f0703cSBryan Whitehead 	}
149623f0703cSBryan Whitehead 	if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0))
149723f0703cSBryan Whitehead 		data |= DMAC_CFG_COAL_EN_;
149823f0703cSBryan Whitehead 	data |= DMAC_CFG_CH_ARB_SEL_RX_HIGH_;
149923f0703cSBryan Whitehead 	data |= DMAC_CFG_MAX_READ_REQ_SET_(6);
150023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_CFG, data);
150123f0703cSBryan Whitehead 	data = DMAC_COAL_CFG_TIMER_LIMIT_SET_(1);
150223f0703cSBryan Whitehead 	data |= DMAC_COAL_CFG_TIMER_TX_START_;
150323f0703cSBryan Whitehead 	data |= DMAC_COAL_CFG_FLUSH_INTS_;
150423f0703cSBryan Whitehead 	data |= DMAC_COAL_CFG_INT_EXIT_COAL_;
150523f0703cSBryan Whitehead 	data |= DMAC_COAL_CFG_CSR_EXIT_COAL_;
150623f0703cSBryan Whitehead 	data |= DMAC_COAL_CFG_TX_THRES_SET_(0x0A);
150723f0703cSBryan Whitehead 	data |= DMAC_COAL_CFG_RX_THRES_SET_(0x0C);
150823f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_COAL_CFG, data);
150923f0703cSBryan Whitehead 	data = DMAC_OBFF_TX_THRES_SET_(0x08);
151023f0703cSBryan Whitehead 	data |= DMAC_OBFF_RX_THRES_SET_(0x0A);
151123f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_OBFF_CFG, data);
151223f0703cSBryan Whitehead 	return 0;
151323f0703cSBryan Whitehead }
151423f0703cSBryan Whitehead 
lan743x_dmac_tx_get_state(struct lan743x_adapter * adapter,int tx_channel)151523f0703cSBryan Whitehead static int lan743x_dmac_tx_get_state(struct lan743x_adapter *adapter,
151623f0703cSBryan Whitehead 				     int tx_channel)
151723f0703cSBryan Whitehead {
151823f0703cSBryan Whitehead 	u32 dmac_cmd = 0;
151923f0703cSBryan Whitehead 
152023f0703cSBryan Whitehead 	dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD);
152123f0703cSBryan Whitehead 	return DMAC_CHANNEL_STATE_SET((dmac_cmd &
152223f0703cSBryan Whitehead 				      DMAC_CMD_START_T_(tx_channel)),
152323f0703cSBryan Whitehead 				      (dmac_cmd &
152423f0703cSBryan Whitehead 				      DMAC_CMD_STOP_T_(tx_channel)));
152523f0703cSBryan Whitehead }
152623f0703cSBryan Whitehead 
lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter * adapter,int tx_channel)152723f0703cSBryan Whitehead static int lan743x_dmac_tx_wait_till_stopped(struct lan743x_adapter *adapter,
152823f0703cSBryan Whitehead 					     int tx_channel)
152923f0703cSBryan Whitehead {
153023f0703cSBryan Whitehead 	int timeout = 100;
153123f0703cSBryan Whitehead 	int result = 0;
153223f0703cSBryan Whitehead 
153323f0703cSBryan Whitehead 	while (timeout &&
153423f0703cSBryan Whitehead 	       ((result = lan743x_dmac_tx_get_state(adapter, tx_channel)) ==
153523f0703cSBryan Whitehead 	       DMAC_CHANNEL_STATE_STOP_PENDING)) {
153623f0703cSBryan Whitehead 		usleep_range(1000, 20000);
153723f0703cSBryan Whitehead 		timeout--;
153823f0703cSBryan Whitehead 	}
153923f0703cSBryan Whitehead 	if (result == DMAC_CHANNEL_STATE_STOP_PENDING)
154023f0703cSBryan Whitehead 		result = -ENODEV;
154123f0703cSBryan Whitehead 	return result;
154223f0703cSBryan Whitehead }
154323f0703cSBryan Whitehead 
lan743x_dmac_rx_get_state(struct lan743x_adapter * adapter,int rx_channel)154423f0703cSBryan Whitehead static int lan743x_dmac_rx_get_state(struct lan743x_adapter *adapter,
154523f0703cSBryan Whitehead 				     int rx_channel)
154623f0703cSBryan Whitehead {
154723f0703cSBryan Whitehead 	u32 dmac_cmd = 0;
154823f0703cSBryan Whitehead 
154923f0703cSBryan Whitehead 	dmac_cmd = lan743x_csr_read(adapter, DMAC_CMD);
155023f0703cSBryan Whitehead 	return DMAC_CHANNEL_STATE_SET((dmac_cmd &
155123f0703cSBryan Whitehead 				      DMAC_CMD_START_R_(rx_channel)),
155223f0703cSBryan Whitehead 				      (dmac_cmd &
155323f0703cSBryan Whitehead 				      DMAC_CMD_STOP_R_(rx_channel)));
155423f0703cSBryan Whitehead }
155523f0703cSBryan Whitehead 
lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter * adapter,int rx_channel)155623f0703cSBryan Whitehead static int lan743x_dmac_rx_wait_till_stopped(struct lan743x_adapter *adapter,
155723f0703cSBryan Whitehead 					     int rx_channel)
155823f0703cSBryan Whitehead {
155923f0703cSBryan Whitehead 	int timeout = 100;
156023f0703cSBryan Whitehead 	int result = 0;
156123f0703cSBryan Whitehead 
156223f0703cSBryan Whitehead 	while (timeout &&
156323f0703cSBryan Whitehead 	       ((result = lan743x_dmac_rx_get_state(adapter, rx_channel)) ==
156423f0703cSBryan Whitehead 	       DMAC_CHANNEL_STATE_STOP_PENDING)) {
156523f0703cSBryan Whitehead 		usleep_range(1000, 20000);
156623f0703cSBryan Whitehead 		timeout--;
156723f0703cSBryan Whitehead 	}
156823f0703cSBryan Whitehead 	if (result == DMAC_CHANNEL_STATE_STOP_PENDING)
156923f0703cSBryan Whitehead 		result = -ENODEV;
157023f0703cSBryan Whitehead 	return result;
157123f0703cSBryan Whitehead }
157223f0703cSBryan Whitehead 
lan743x_tx_release_desc(struct lan743x_tx * tx,int descriptor_index,bool cleanup)157323f0703cSBryan Whitehead static void lan743x_tx_release_desc(struct lan743x_tx *tx,
157423f0703cSBryan Whitehead 				    int descriptor_index, bool cleanup)
157523f0703cSBryan Whitehead {
157623f0703cSBryan Whitehead 	struct lan743x_tx_buffer_info *buffer_info = NULL;
157723f0703cSBryan Whitehead 	struct lan743x_tx_descriptor *descriptor = NULL;
157823f0703cSBryan Whitehead 	u32 descriptor_type = 0;
157907624df1SBryan Whitehead 	bool ignore_sync;
158023f0703cSBryan Whitehead 
158123f0703cSBryan Whitehead 	descriptor = &tx->ring_cpu_ptr[descriptor_index];
158223f0703cSBryan Whitehead 	buffer_info = &tx->buffer_info[descriptor_index];
158323f0703cSBryan Whitehead 	if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_ACTIVE))
158423f0703cSBryan Whitehead 		goto done;
158523f0703cSBryan Whitehead 
158646251282SAlexey Denisov 	descriptor_type = le32_to_cpu(descriptor->data0) &
158723f0703cSBryan Whitehead 			  TX_DESC_DATA0_DTYPE_MASK_;
158823f0703cSBryan Whitehead 	if (descriptor_type == TX_DESC_DATA0_DTYPE_DATA_)
158923f0703cSBryan Whitehead 		goto clean_up_data_descriptor;
159023f0703cSBryan Whitehead 	else
159123f0703cSBryan Whitehead 		goto clear_active;
159223f0703cSBryan Whitehead 
159323f0703cSBryan Whitehead clean_up_data_descriptor:
159423f0703cSBryan Whitehead 	if (buffer_info->dma_ptr) {
159523f0703cSBryan Whitehead 		if (buffer_info->flags &
159623f0703cSBryan Whitehead 		    TX_BUFFER_INFO_FLAG_SKB_FRAGMENT) {
159723f0703cSBryan Whitehead 			dma_unmap_page(&tx->adapter->pdev->dev,
159823f0703cSBryan Whitehead 				       buffer_info->dma_ptr,
159923f0703cSBryan Whitehead 				       buffer_info->buffer_length,
160023f0703cSBryan Whitehead 				       DMA_TO_DEVICE);
160123f0703cSBryan Whitehead 		} else {
160223f0703cSBryan Whitehead 			dma_unmap_single(&tx->adapter->pdev->dev,
160323f0703cSBryan Whitehead 					 buffer_info->dma_ptr,
160423f0703cSBryan Whitehead 					 buffer_info->buffer_length,
160523f0703cSBryan Whitehead 					 DMA_TO_DEVICE);
160623f0703cSBryan Whitehead 		}
160723f0703cSBryan Whitehead 		buffer_info->dma_ptr = 0;
160823f0703cSBryan Whitehead 		buffer_info->buffer_length = 0;
160923f0703cSBryan Whitehead 	}
161007624df1SBryan Whitehead 	if (!buffer_info->skb)
161107624df1SBryan Whitehead 		goto clear_active;
161207624df1SBryan Whitehead 
161307624df1SBryan Whitehead 	if (!(buffer_info->flags & TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED)) {
1614e35df62eSSven Van Asbroeck 		dev_kfree_skb_any(buffer_info->skb);
161507624df1SBryan Whitehead 		goto clear_skb;
161623f0703cSBryan Whitehead 	}
161723f0703cSBryan Whitehead 
161807624df1SBryan Whitehead 	if (cleanup) {
161907624df1SBryan Whitehead 		lan743x_ptp_unrequest_tx_timestamp(tx->adapter);
1620e35df62eSSven Van Asbroeck 		dev_kfree_skb_any(buffer_info->skb);
162107624df1SBryan Whitehead 	} else {
162207624df1SBryan Whitehead 		ignore_sync = (buffer_info->flags &
162307624df1SBryan Whitehead 			       TX_BUFFER_INFO_FLAG_IGNORE_SYNC) != 0;
162407624df1SBryan Whitehead 		lan743x_ptp_tx_timestamp_skb(tx->adapter,
162507624df1SBryan Whitehead 					     buffer_info->skb, ignore_sync);
162607624df1SBryan Whitehead 	}
162707624df1SBryan Whitehead 
162807624df1SBryan Whitehead clear_skb:
162907624df1SBryan Whitehead 	buffer_info->skb = NULL;
163007624df1SBryan Whitehead 
163123f0703cSBryan Whitehead clear_active:
163223f0703cSBryan Whitehead 	buffer_info->flags &= ~TX_BUFFER_INFO_FLAG_ACTIVE;
163323f0703cSBryan Whitehead 
163423f0703cSBryan Whitehead done:
163523f0703cSBryan Whitehead 	memset(buffer_info, 0, sizeof(*buffer_info));
163623f0703cSBryan Whitehead 	memset(descriptor, 0, sizeof(*descriptor));
163723f0703cSBryan Whitehead }
163823f0703cSBryan Whitehead 
lan743x_tx_next_index(struct lan743x_tx * tx,int index)163923f0703cSBryan Whitehead static int lan743x_tx_next_index(struct lan743x_tx *tx, int index)
164023f0703cSBryan Whitehead {
164123f0703cSBryan Whitehead 	return ((++index) % tx->ring_size);
164223f0703cSBryan Whitehead }
164323f0703cSBryan Whitehead 
lan743x_tx_release_completed_descriptors(struct lan743x_tx * tx)164423f0703cSBryan Whitehead static void lan743x_tx_release_completed_descriptors(struct lan743x_tx *tx)
164523f0703cSBryan Whitehead {
164646251282SAlexey Denisov 	while (le32_to_cpu(*tx->head_cpu_ptr) != (tx->last_head)) {
164723f0703cSBryan Whitehead 		lan743x_tx_release_desc(tx, tx->last_head, false);
164823f0703cSBryan Whitehead 		tx->last_head = lan743x_tx_next_index(tx, tx->last_head);
164923f0703cSBryan Whitehead 	}
165023f0703cSBryan Whitehead }
165123f0703cSBryan Whitehead 
lan743x_tx_release_all_descriptors(struct lan743x_tx * tx)165223f0703cSBryan Whitehead static void lan743x_tx_release_all_descriptors(struct lan743x_tx *tx)
165323f0703cSBryan Whitehead {
165423f0703cSBryan Whitehead 	u32 original_head = 0;
165523f0703cSBryan Whitehead 
165623f0703cSBryan Whitehead 	original_head = tx->last_head;
165723f0703cSBryan Whitehead 	do {
165823f0703cSBryan Whitehead 		lan743x_tx_release_desc(tx, tx->last_head, true);
165923f0703cSBryan Whitehead 		tx->last_head = lan743x_tx_next_index(tx, tx->last_head);
166023f0703cSBryan Whitehead 	} while (tx->last_head != original_head);
166123f0703cSBryan Whitehead 	memset(tx->ring_cpu_ptr, 0,
166223f0703cSBryan Whitehead 	       sizeof(*tx->ring_cpu_ptr) * (tx->ring_size));
166323f0703cSBryan Whitehead 	memset(tx->buffer_info, 0,
166423f0703cSBryan Whitehead 	       sizeof(*tx->buffer_info) * (tx->ring_size));
166523f0703cSBryan Whitehead }
166623f0703cSBryan Whitehead 
lan743x_tx_get_desc_cnt(struct lan743x_tx * tx,struct sk_buff * skb)166723f0703cSBryan Whitehead static int lan743x_tx_get_desc_cnt(struct lan743x_tx *tx,
166823f0703cSBryan Whitehead 				   struct sk_buff *skb)
166923f0703cSBryan Whitehead {
167023f0703cSBryan Whitehead 	int result = 1; /* 1 for the main skb buffer */
167123f0703cSBryan Whitehead 	int nr_frags = 0;
167223f0703cSBryan Whitehead 
167323f0703cSBryan Whitehead 	if (skb_is_gso(skb))
167423f0703cSBryan Whitehead 		result++; /* requires an extension descriptor */
167523f0703cSBryan Whitehead 	nr_frags = skb_shinfo(skb)->nr_frags;
167623f0703cSBryan Whitehead 	result += nr_frags; /* 1 for each fragment buffer */
167723f0703cSBryan Whitehead 	return result;
167823f0703cSBryan Whitehead }
167923f0703cSBryan Whitehead 
lan743x_tx_get_avail_desc(struct lan743x_tx * tx)168023f0703cSBryan Whitehead static int lan743x_tx_get_avail_desc(struct lan743x_tx *tx)
168123f0703cSBryan Whitehead {
168223f0703cSBryan Whitehead 	int last_head = tx->last_head;
168323f0703cSBryan Whitehead 	int last_tail = tx->last_tail;
168423f0703cSBryan Whitehead 
168523f0703cSBryan Whitehead 	if (last_tail >= last_head)
168623f0703cSBryan Whitehead 		return tx->ring_size - last_tail + last_head - 1;
168723f0703cSBryan Whitehead 	else
168823f0703cSBryan Whitehead 		return last_head - last_tail - 1;
168923f0703cSBryan Whitehead }
169023f0703cSBryan Whitehead 
lan743x_rx_cfg_b_tstamp_config(struct lan743x_adapter * adapter,int rx_ts_config)1691169e0a5eSVishvambar Panth S static void lan743x_rx_cfg_b_tstamp_config(struct lan743x_adapter *adapter,
1692169e0a5eSVishvambar Panth S 					   int rx_ts_config)
1693169e0a5eSVishvambar Panth S {
1694169e0a5eSVishvambar Panth S 	int channel_number;
1695169e0a5eSVishvambar Panth S 	int index;
1696169e0a5eSVishvambar Panth S 	u32 data;
1697169e0a5eSVishvambar Panth S 
1698169e0a5eSVishvambar Panth S 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
1699169e0a5eSVishvambar Panth S 		channel_number = adapter->rx[index].channel_number;
1700169e0a5eSVishvambar Panth S 		data = lan743x_csr_read(adapter, RX_CFG_B(channel_number));
1701169e0a5eSVishvambar Panth S 		data &= RX_CFG_B_TS_MASK_;
1702169e0a5eSVishvambar Panth S 		data |= rx_ts_config;
1703169e0a5eSVishvambar Panth S 		lan743x_csr_write(adapter, RX_CFG_B(channel_number),
1704169e0a5eSVishvambar Panth S 				  data);
1705169e0a5eSVishvambar Panth S 	}
1706169e0a5eSVishvambar Panth S }
1707169e0a5eSVishvambar Panth S 
lan743x_rx_set_tstamp_mode(struct lan743x_adapter * adapter,int rx_filter)1708169e0a5eSVishvambar Panth S int lan743x_rx_set_tstamp_mode(struct lan743x_adapter *adapter,
1709169e0a5eSVishvambar Panth S 			       int rx_filter)
1710169e0a5eSVishvambar Panth S {
1711169e0a5eSVishvambar Panth S 	u32 data;
1712169e0a5eSVishvambar Panth S 
1713169e0a5eSVishvambar Panth S 	switch (rx_filter) {
1714169e0a5eSVishvambar Panth S 	case HWTSTAMP_FILTER_PTP_V2_EVENT:
1715169e0a5eSVishvambar Panth S 			lan743x_rx_cfg_b_tstamp_config(adapter,
1716169e0a5eSVishvambar Panth S 						       RX_CFG_B_TS_DESCR_EN_);
1717169e0a5eSVishvambar Panth S 			data = lan743x_csr_read(adapter, PTP_RX_TS_CFG);
1718169e0a5eSVishvambar Panth S 			data |= PTP_RX_TS_CFG_EVENT_MSGS_;
1719169e0a5eSVishvambar Panth S 			lan743x_csr_write(adapter, PTP_RX_TS_CFG, data);
1720169e0a5eSVishvambar Panth S 			break;
1721169e0a5eSVishvambar Panth S 	case HWTSTAMP_FILTER_NONE:
1722169e0a5eSVishvambar Panth S 			lan743x_rx_cfg_b_tstamp_config(adapter,
1723169e0a5eSVishvambar Panth S 						       RX_CFG_B_TS_NONE_);
1724169e0a5eSVishvambar Panth S 			break;
1725169e0a5eSVishvambar Panth S 	case HWTSTAMP_FILTER_ALL:
1726169e0a5eSVishvambar Panth S 			lan743x_rx_cfg_b_tstamp_config(adapter,
1727169e0a5eSVishvambar Panth S 						       RX_CFG_B_TS_ALL_RX_);
1728169e0a5eSVishvambar Panth S 			break;
1729169e0a5eSVishvambar Panth S 	default:
1730169e0a5eSVishvambar Panth S 			return -ERANGE;
1731169e0a5eSVishvambar Panth S 	}
1732169e0a5eSVishvambar Panth S 	return 0;
1733169e0a5eSVishvambar Panth S }
1734169e0a5eSVishvambar Panth S 
lan743x_tx_set_timestamping_mode(struct lan743x_tx * tx,bool enable_timestamping,bool enable_onestep_sync)173507624df1SBryan Whitehead void lan743x_tx_set_timestamping_mode(struct lan743x_tx *tx,
173607624df1SBryan Whitehead 				      bool enable_timestamping,
173707624df1SBryan Whitehead 				      bool enable_onestep_sync)
173807624df1SBryan Whitehead {
173907624df1SBryan Whitehead 	if (enable_timestamping)
174007624df1SBryan Whitehead 		tx->ts_flags |= TX_TS_FLAG_TIMESTAMPING_ENABLED;
174107624df1SBryan Whitehead 	else
174207624df1SBryan Whitehead 		tx->ts_flags &= ~TX_TS_FLAG_TIMESTAMPING_ENABLED;
174307624df1SBryan Whitehead 	if (enable_onestep_sync)
174407624df1SBryan Whitehead 		tx->ts_flags |= TX_TS_FLAG_ONE_STEP_SYNC;
174507624df1SBryan Whitehead 	else
174607624df1SBryan Whitehead 		tx->ts_flags &= ~TX_TS_FLAG_ONE_STEP_SYNC;
174707624df1SBryan Whitehead }
174807624df1SBryan Whitehead 
lan743x_tx_frame_start(struct lan743x_tx * tx,unsigned char * first_buffer,unsigned int first_buffer_length,unsigned int frame_length,bool time_stamp,bool check_sum)174923f0703cSBryan Whitehead static int lan743x_tx_frame_start(struct lan743x_tx *tx,
175023f0703cSBryan Whitehead 				  unsigned char *first_buffer,
175123f0703cSBryan Whitehead 				  unsigned int first_buffer_length,
175223f0703cSBryan Whitehead 				  unsigned int frame_length,
175307624df1SBryan Whitehead 				  bool time_stamp,
175423f0703cSBryan Whitehead 				  bool check_sum)
175523f0703cSBryan Whitehead {
175623f0703cSBryan Whitehead 	/* called only from within lan743x_tx_xmit_frame.
175723f0703cSBryan Whitehead 	 * assuming tx->ring_lock has already been acquired.
175823f0703cSBryan Whitehead 	 */
175923f0703cSBryan Whitehead 	struct lan743x_tx_descriptor *tx_descriptor = NULL;
176023f0703cSBryan Whitehead 	struct lan743x_tx_buffer_info *buffer_info = NULL;
176123f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = tx->adapter;
176223f0703cSBryan Whitehead 	struct device *dev = &adapter->pdev->dev;
176323f0703cSBryan Whitehead 	dma_addr_t dma_ptr;
176423f0703cSBryan Whitehead 
176523f0703cSBryan Whitehead 	tx->frame_flags |= TX_FRAME_FLAG_IN_PROGRESS;
176623f0703cSBryan Whitehead 	tx->frame_first = tx->last_tail;
176723f0703cSBryan Whitehead 	tx->frame_tail = tx->frame_first;
176823f0703cSBryan Whitehead 
176923f0703cSBryan Whitehead 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
177023f0703cSBryan Whitehead 	buffer_info = &tx->buffer_info[tx->frame_tail];
177123f0703cSBryan Whitehead 	dma_ptr = dma_map_single(dev, first_buffer, first_buffer_length,
177223f0703cSBryan Whitehead 				 DMA_TO_DEVICE);
177323f0703cSBryan Whitehead 	if (dma_mapping_error(dev, dma_ptr))
177423f0703cSBryan Whitehead 		return -ENOMEM;
177523f0703cSBryan Whitehead 
177646251282SAlexey Denisov 	tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr));
177746251282SAlexey Denisov 	tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr));
177846251282SAlexey Denisov 	tx_descriptor->data3 = cpu_to_le32((frame_length << 16) &
177946251282SAlexey Denisov 		TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_);
178023f0703cSBryan Whitehead 
178123f0703cSBryan Whitehead 	buffer_info->skb = NULL;
178223f0703cSBryan Whitehead 	buffer_info->dma_ptr = dma_ptr;
178323f0703cSBryan Whitehead 	buffer_info->buffer_length = first_buffer_length;
178423f0703cSBryan Whitehead 	buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
178523f0703cSBryan Whitehead 
178623f0703cSBryan Whitehead 	tx->frame_data0 = (first_buffer_length &
178723f0703cSBryan Whitehead 		TX_DESC_DATA0_BUF_LENGTH_MASK_) |
178823f0703cSBryan Whitehead 		TX_DESC_DATA0_DTYPE_DATA_ |
178923f0703cSBryan Whitehead 		TX_DESC_DATA0_FS_ |
179023f0703cSBryan Whitehead 		TX_DESC_DATA0_FCS_;
179107624df1SBryan Whitehead 	if (time_stamp)
179207624df1SBryan Whitehead 		tx->frame_data0 |= TX_DESC_DATA0_TSE_;
179323f0703cSBryan Whitehead 
179423f0703cSBryan Whitehead 	if (check_sum)
179523f0703cSBryan Whitehead 		tx->frame_data0 |= TX_DESC_DATA0_ICE_ |
179623f0703cSBryan Whitehead 				   TX_DESC_DATA0_IPE_ |
179723f0703cSBryan Whitehead 				   TX_DESC_DATA0_TPE_;
179823f0703cSBryan Whitehead 
179923f0703cSBryan Whitehead 	/* data0 will be programmed in one of other frame assembler functions */
180023f0703cSBryan Whitehead 	return 0;
180123f0703cSBryan Whitehead }
180223f0703cSBryan Whitehead 
lan743x_tx_frame_add_lso(struct lan743x_tx * tx,unsigned int frame_length,int nr_frags)180323f0703cSBryan Whitehead static void lan743x_tx_frame_add_lso(struct lan743x_tx *tx,
180490490ef7SBryan Whitehead 				     unsigned int frame_length,
180590490ef7SBryan Whitehead 				     int nr_frags)
180623f0703cSBryan Whitehead {
180723f0703cSBryan Whitehead 	/* called only from within lan743x_tx_xmit_frame.
180823f0703cSBryan Whitehead 	 * assuming tx->ring_lock has already been acquired.
180923f0703cSBryan Whitehead 	 */
181023f0703cSBryan Whitehead 	struct lan743x_tx_descriptor *tx_descriptor = NULL;
181123f0703cSBryan Whitehead 	struct lan743x_tx_buffer_info *buffer_info = NULL;
181223f0703cSBryan Whitehead 
181323f0703cSBryan Whitehead 	/* wrap up previous descriptor */
181423f0703cSBryan Whitehead 	tx->frame_data0 |= TX_DESC_DATA0_EXT_;
181590490ef7SBryan Whitehead 	if (nr_frags <= 0) {
181690490ef7SBryan Whitehead 		tx->frame_data0 |= TX_DESC_DATA0_LS_;
181790490ef7SBryan Whitehead 		tx->frame_data0 |= TX_DESC_DATA0_IOC_;
181890490ef7SBryan Whitehead 	}
181923f0703cSBryan Whitehead 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
182046251282SAlexey Denisov 	tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
182123f0703cSBryan Whitehead 
182223f0703cSBryan Whitehead 	/* move to next descriptor */
182323f0703cSBryan Whitehead 	tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
182423f0703cSBryan Whitehead 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
182523f0703cSBryan Whitehead 	buffer_info = &tx->buffer_info[tx->frame_tail];
182623f0703cSBryan Whitehead 
182723f0703cSBryan Whitehead 	/* add extension descriptor */
182823f0703cSBryan Whitehead 	tx_descriptor->data1 = 0;
182923f0703cSBryan Whitehead 	tx_descriptor->data2 = 0;
183023f0703cSBryan Whitehead 	tx_descriptor->data3 = 0;
183123f0703cSBryan Whitehead 
183223f0703cSBryan Whitehead 	buffer_info->skb = NULL;
183323f0703cSBryan Whitehead 	buffer_info->dma_ptr = 0;
183423f0703cSBryan Whitehead 	buffer_info->buffer_length = 0;
183523f0703cSBryan Whitehead 	buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
183623f0703cSBryan Whitehead 
183723f0703cSBryan Whitehead 	tx->frame_data0 = (frame_length & TX_DESC_DATA0_EXT_PAY_LENGTH_MASK_) |
183823f0703cSBryan Whitehead 			  TX_DESC_DATA0_DTYPE_EXT_ |
183923f0703cSBryan Whitehead 			  TX_DESC_DATA0_EXT_LSO_;
184023f0703cSBryan Whitehead 
184123f0703cSBryan Whitehead 	/* data0 will be programmed in one of other frame assembler functions */
184223f0703cSBryan Whitehead }
184323f0703cSBryan Whitehead 
lan743x_tx_frame_add_fragment(struct lan743x_tx * tx,const skb_frag_t * fragment,unsigned int frame_length)184423f0703cSBryan Whitehead static int lan743x_tx_frame_add_fragment(struct lan743x_tx *tx,
1845d7840976SMatthew Wilcox (Oracle) 					 const skb_frag_t *fragment,
184623f0703cSBryan Whitehead 					 unsigned int frame_length)
184723f0703cSBryan Whitehead {
184823f0703cSBryan Whitehead 	/* called only from within lan743x_tx_xmit_frame
184923f0703cSBryan Whitehead 	 * assuming tx->ring_lock has already been acquired
185023f0703cSBryan Whitehead 	 */
185123f0703cSBryan Whitehead 	struct lan743x_tx_descriptor *tx_descriptor = NULL;
185223f0703cSBryan Whitehead 	struct lan743x_tx_buffer_info *buffer_info = NULL;
185323f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = tx->adapter;
185423f0703cSBryan Whitehead 	struct device *dev = &adapter->pdev->dev;
185523f0703cSBryan Whitehead 	unsigned int fragment_length = 0;
185623f0703cSBryan Whitehead 	dma_addr_t dma_ptr;
185723f0703cSBryan Whitehead 
185823f0703cSBryan Whitehead 	fragment_length = skb_frag_size(fragment);
185923f0703cSBryan Whitehead 	if (!fragment_length)
186023f0703cSBryan Whitehead 		return 0;
186123f0703cSBryan Whitehead 
186223f0703cSBryan Whitehead 	/* wrap up previous descriptor */
186323f0703cSBryan Whitehead 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
186446251282SAlexey Denisov 	tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
186523f0703cSBryan Whitehead 
186623f0703cSBryan Whitehead 	/* move to next descriptor */
186723f0703cSBryan Whitehead 	tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
186823f0703cSBryan Whitehead 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
186923f0703cSBryan Whitehead 	buffer_info = &tx->buffer_info[tx->frame_tail];
187023f0703cSBryan Whitehead 	dma_ptr = skb_frag_dma_map(dev, fragment,
187123f0703cSBryan Whitehead 				   0, fragment_length,
187223f0703cSBryan Whitehead 				   DMA_TO_DEVICE);
187323f0703cSBryan Whitehead 	if (dma_mapping_error(dev, dma_ptr)) {
187423f0703cSBryan Whitehead 		int desc_index;
187523f0703cSBryan Whitehead 
187623f0703cSBryan Whitehead 		/* cleanup all previously setup descriptors */
187723f0703cSBryan Whitehead 		desc_index = tx->frame_first;
187823f0703cSBryan Whitehead 		while (desc_index != tx->frame_tail) {
187923f0703cSBryan Whitehead 			lan743x_tx_release_desc(tx, desc_index, true);
188023f0703cSBryan Whitehead 			desc_index = lan743x_tx_next_index(tx, desc_index);
188123f0703cSBryan Whitehead 		}
188223f0703cSBryan Whitehead 		dma_wmb();
188323f0703cSBryan Whitehead 		tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS;
188423f0703cSBryan Whitehead 		tx->frame_first = 0;
188523f0703cSBryan Whitehead 		tx->frame_data0 = 0;
188623f0703cSBryan Whitehead 		tx->frame_tail = 0;
188723f0703cSBryan Whitehead 		return -ENOMEM;
188823f0703cSBryan Whitehead 	}
188923f0703cSBryan Whitehead 
189046251282SAlexey Denisov 	tx_descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(dma_ptr));
189146251282SAlexey Denisov 	tx_descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(dma_ptr));
189246251282SAlexey Denisov 	tx_descriptor->data3 = cpu_to_le32((frame_length << 16) &
189346251282SAlexey Denisov 			       TX_DESC_DATA3_FRAME_LENGTH_MSS_MASK_);
189423f0703cSBryan Whitehead 
189523f0703cSBryan Whitehead 	buffer_info->skb = NULL;
189623f0703cSBryan Whitehead 	buffer_info->dma_ptr = dma_ptr;
189723f0703cSBryan Whitehead 	buffer_info->buffer_length = fragment_length;
189823f0703cSBryan Whitehead 	buffer_info->flags |= TX_BUFFER_INFO_FLAG_ACTIVE;
189923f0703cSBryan Whitehead 	buffer_info->flags |= TX_BUFFER_INFO_FLAG_SKB_FRAGMENT;
190023f0703cSBryan Whitehead 
190123f0703cSBryan Whitehead 	tx->frame_data0 = (fragment_length & TX_DESC_DATA0_BUF_LENGTH_MASK_) |
190223f0703cSBryan Whitehead 			  TX_DESC_DATA0_DTYPE_DATA_ |
190323f0703cSBryan Whitehead 			  TX_DESC_DATA0_FCS_;
190423f0703cSBryan Whitehead 
190523f0703cSBryan Whitehead 	/* data0 will be programmed in one of other frame assembler functions */
190623f0703cSBryan Whitehead 	return 0;
190723f0703cSBryan Whitehead }
190823f0703cSBryan Whitehead 
lan743x_tx_frame_end(struct lan743x_tx * tx,struct sk_buff * skb,bool time_stamp,bool ignore_sync)190923f0703cSBryan Whitehead static void lan743x_tx_frame_end(struct lan743x_tx *tx,
191023f0703cSBryan Whitehead 				 struct sk_buff *skb,
191107624df1SBryan Whitehead 				 bool time_stamp,
191223f0703cSBryan Whitehead 				 bool ignore_sync)
191323f0703cSBryan Whitehead {
191423f0703cSBryan Whitehead 	/* called only from within lan743x_tx_xmit_frame
191523f0703cSBryan Whitehead 	 * assuming tx->ring_lock has already been acquired
191623f0703cSBryan Whitehead 	 */
191723f0703cSBryan Whitehead 	struct lan743x_tx_descriptor *tx_descriptor = NULL;
191823f0703cSBryan Whitehead 	struct lan743x_tx_buffer_info *buffer_info = NULL;
191923f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = tx->adapter;
192023f0703cSBryan Whitehead 	u32 tx_tail_flags = 0;
192123f0703cSBryan Whitehead 
192223f0703cSBryan Whitehead 	/* wrap up previous descriptor */
192390490ef7SBryan Whitehead 	if ((tx->frame_data0 & TX_DESC_DATA0_DTYPE_MASK_) ==
192490490ef7SBryan Whitehead 	    TX_DESC_DATA0_DTYPE_DATA_) {
192523f0703cSBryan Whitehead 		tx->frame_data0 |= TX_DESC_DATA0_LS_;
192623f0703cSBryan Whitehead 		tx->frame_data0 |= TX_DESC_DATA0_IOC_;
192790490ef7SBryan Whitehead 	}
192823f0703cSBryan Whitehead 
192923f0703cSBryan Whitehead 	tx_descriptor = &tx->ring_cpu_ptr[tx->frame_tail];
193023f0703cSBryan Whitehead 	buffer_info = &tx->buffer_info[tx->frame_tail];
193123f0703cSBryan Whitehead 	buffer_info->skb = skb;
193207624df1SBryan Whitehead 	if (time_stamp)
193307624df1SBryan Whitehead 		buffer_info->flags |= TX_BUFFER_INFO_FLAG_TIMESTAMP_REQUESTED;
193423f0703cSBryan Whitehead 	if (ignore_sync)
193523f0703cSBryan Whitehead 		buffer_info->flags |= TX_BUFFER_INFO_FLAG_IGNORE_SYNC;
193623f0703cSBryan Whitehead 
193746251282SAlexey Denisov 	tx_descriptor->data0 = cpu_to_le32(tx->frame_data0);
193823f0703cSBryan Whitehead 	tx->frame_tail = lan743x_tx_next_index(tx, tx->frame_tail);
193923f0703cSBryan Whitehead 	tx->last_tail = tx->frame_tail;
194023f0703cSBryan Whitehead 
194123f0703cSBryan Whitehead 	dma_wmb();
194223f0703cSBryan Whitehead 
194323f0703cSBryan Whitehead 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET)
194423f0703cSBryan Whitehead 		tx_tail_flags |= TX_TAIL_SET_TOP_INT_VEC_EN_;
194523f0703cSBryan Whitehead 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET)
194623f0703cSBryan Whitehead 		tx_tail_flags |= TX_TAIL_SET_DMAC_INT_EN_ |
194723f0703cSBryan Whitehead 		TX_TAIL_SET_TOP_INT_EN_;
194823f0703cSBryan Whitehead 
194923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, TX_TAIL(tx->channel_number),
195023f0703cSBryan Whitehead 			  tx_tail_flags | tx->frame_tail);
195123f0703cSBryan Whitehead 	tx->frame_flags &= ~TX_FRAME_FLAG_IN_PROGRESS;
195223f0703cSBryan Whitehead }
195323f0703cSBryan Whitehead 
lan743x_tx_xmit_frame(struct lan743x_tx * tx,struct sk_buff * skb)195423f0703cSBryan Whitehead static netdev_tx_t lan743x_tx_xmit_frame(struct lan743x_tx *tx,
195523f0703cSBryan Whitehead 					 struct sk_buff *skb)
195623f0703cSBryan Whitehead {
195723f0703cSBryan Whitehead 	int required_number_of_descriptors = 0;
195823f0703cSBryan Whitehead 	unsigned int start_frame_length = 0;
1959721f80c4SRaju Lakkaraju 	netdev_tx_t retval = NETDEV_TX_OK;
196023f0703cSBryan Whitehead 	unsigned int frame_length = 0;
196123f0703cSBryan Whitehead 	unsigned int head_length = 0;
196223f0703cSBryan Whitehead 	unsigned long irq_flags = 0;
196307624df1SBryan Whitehead 	bool do_timestamp = false;
196423f0703cSBryan Whitehead 	bool ignore_sync = false;
1965721f80c4SRaju Lakkaraju 	struct netdev_queue *txq;
196623f0703cSBryan Whitehead 	int nr_frags = 0;
196723f0703cSBryan Whitehead 	bool gso = false;
196823f0703cSBryan Whitehead 	int j;
196923f0703cSBryan Whitehead 
197023f0703cSBryan Whitehead 	required_number_of_descriptors = lan743x_tx_get_desc_cnt(tx, skb);
197123f0703cSBryan Whitehead 
197223f0703cSBryan Whitehead 	spin_lock_irqsave(&tx->ring_lock, irq_flags);
197323f0703cSBryan Whitehead 	if (required_number_of_descriptors >
197423f0703cSBryan Whitehead 		lan743x_tx_get_avail_desc(tx)) {
197523f0703cSBryan Whitehead 		if (required_number_of_descriptors > (tx->ring_size - 1)) {
1976e35df62eSSven Van Asbroeck 			dev_kfree_skb_irq(skb);
197723f0703cSBryan Whitehead 		} else {
1978721f80c4SRaju Lakkaraju 			/* save how many descriptors we needed to restart the queue */
1979721f80c4SRaju Lakkaraju 			tx->rqd_descriptors = required_number_of_descriptors;
1980721f80c4SRaju Lakkaraju 			retval = NETDEV_TX_BUSY;
1981721f80c4SRaju Lakkaraju 			txq = netdev_get_tx_queue(tx->adapter->netdev,
1982721f80c4SRaju Lakkaraju 						  tx->channel_number);
1983721f80c4SRaju Lakkaraju 			netif_tx_stop_queue(txq);
198423f0703cSBryan Whitehead 		}
198523f0703cSBryan Whitehead 		goto unlock;
198623f0703cSBryan Whitehead 	}
198723f0703cSBryan Whitehead 
198823f0703cSBryan Whitehead 	/* space available, transmit skb  */
198907624df1SBryan Whitehead 	if ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
199007624df1SBryan Whitehead 	    (tx->ts_flags & TX_TS_FLAG_TIMESTAMPING_ENABLED) &&
199107624df1SBryan Whitehead 	    (lan743x_ptp_request_tx_timestamp(tx->adapter))) {
199207624df1SBryan Whitehead 		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
199307624df1SBryan Whitehead 		do_timestamp = true;
199407624df1SBryan Whitehead 		if (tx->ts_flags & TX_TS_FLAG_ONE_STEP_SYNC)
199507624df1SBryan Whitehead 			ignore_sync = true;
199607624df1SBryan Whitehead 	}
199723f0703cSBryan Whitehead 	head_length = skb_headlen(skb);
199823f0703cSBryan Whitehead 	frame_length = skb_pagelen(skb);
199923f0703cSBryan Whitehead 	nr_frags = skb_shinfo(skb)->nr_frags;
200023f0703cSBryan Whitehead 	start_frame_length = frame_length;
200123f0703cSBryan Whitehead 	gso = skb_is_gso(skb);
200223f0703cSBryan Whitehead 	if (gso) {
200323f0703cSBryan Whitehead 		start_frame_length = max(skb_shinfo(skb)->gso_size,
200423f0703cSBryan Whitehead 					 (unsigned short)8);
200523f0703cSBryan Whitehead 	}
200623f0703cSBryan Whitehead 
200723f0703cSBryan Whitehead 	if (lan743x_tx_frame_start(tx,
200823f0703cSBryan Whitehead 				   skb->data, head_length,
200923f0703cSBryan Whitehead 				   start_frame_length,
201007624df1SBryan Whitehead 				   do_timestamp,
201123f0703cSBryan Whitehead 				   skb->ip_summed == CHECKSUM_PARTIAL)) {
2012e35df62eSSven Van Asbroeck 		dev_kfree_skb_irq(skb);
201323f0703cSBryan Whitehead 		goto unlock;
201423f0703cSBryan Whitehead 	}
2015bc1962e5SRaju Lakkaraju 	tx->frame_count++;
201623f0703cSBryan Whitehead 
201723f0703cSBryan Whitehead 	if (gso)
201890490ef7SBryan Whitehead 		lan743x_tx_frame_add_lso(tx, frame_length, nr_frags);
201923f0703cSBryan Whitehead 
202023f0703cSBryan Whitehead 	if (nr_frags <= 0)
202123f0703cSBryan Whitehead 		goto finish;
202223f0703cSBryan Whitehead 
202323f0703cSBryan Whitehead 	for (j = 0; j < nr_frags; j++) {
2024d7840976SMatthew Wilcox (Oracle) 		const skb_frag_t *frag = &(skb_shinfo(skb)->frags[j]);
202523f0703cSBryan Whitehead 
202623f0703cSBryan Whitehead 		if (lan743x_tx_frame_add_fragment(tx, frag, frame_length)) {
202723f0703cSBryan Whitehead 			/* upon error no need to call
202823f0703cSBryan Whitehead 			 *	lan743x_tx_frame_end
202923f0703cSBryan Whitehead 			 * frame assembler clean up was performed inside
203023f0703cSBryan Whitehead 			 *	lan743x_tx_frame_add_fragment
203123f0703cSBryan Whitehead 			 */
2032e35df62eSSven Van Asbroeck 			dev_kfree_skb_irq(skb);
203323f0703cSBryan Whitehead 			goto unlock;
203423f0703cSBryan Whitehead 		}
203523f0703cSBryan Whitehead 	}
203623f0703cSBryan Whitehead 
203723f0703cSBryan Whitehead finish:
203807624df1SBryan Whitehead 	lan743x_tx_frame_end(tx, skb, do_timestamp, ignore_sync);
203923f0703cSBryan Whitehead 
204023f0703cSBryan Whitehead unlock:
204123f0703cSBryan Whitehead 	spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
2042721f80c4SRaju Lakkaraju 	return retval;
204323f0703cSBryan Whitehead }
204423f0703cSBryan Whitehead 
lan743x_tx_napi_poll(struct napi_struct * napi,int weight)204523f0703cSBryan Whitehead static int lan743x_tx_napi_poll(struct napi_struct *napi, int weight)
204623f0703cSBryan Whitehead {
204723f0703cSBryan Whitehead 	struct lan743x_tx *tx = container_of(napi, struct lan743x_tx, napi);
204823f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = tx->adapter;
204923f0703cSBryan Whitehead 	unsigned long irq_flags = 0;
2050721f80c4SRaju Lakkaraju 	struct netdev_queue *txq;
205123f0703cSBryan Whitehead 	u32 ioc_bit = 0;
205223f0703cSBryan Whitehead 
205323f0703cSBryan Whitehead 	ioc_bit = DMAC_INT_BIT_TX_IOC_(tx->channel_number);
20547c8c0291SJesse Brandeburg 	lan743x_csr_read(adapter, DMAC_INT_STS);
205523f0703cSBryan Whitehead 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C)
205623f0703cSBryan Whitehead 		lan743x_csr_write(adapter, DMAC_INT_STS, ioc_bit);
205723f0703cSBryan Whitehead 	spin_lock_irqsave(&tx->ring_lock, irq_flags);
205823f0703cSBryan Whitehead 
205923f0703cSBryan Whitehead 	/* clean up tx ring */
206023f0703cSBryan Whitehead 	lan743x_tx_release_completed_descriptors(tx);
2061721f80c4SRaju Lakkaraju 	txq = netdev_get_tx_queue(adapter->netdev, tx->channel_number);
2062721f80c4SRaju Lakkaraju 	if (netif_tx_queue_stopped(txq)) {
2063721f80c4SRaju Lakkaraju 		if (tx->rqd_descriptors) {
2064721f80c4SRaju Lakkaraju 			if (tx->rqd_descriptors <=
2065721f80c4SRaju Lakkaraju 			    lan743x_tx_get_avail_desc(tx)) {
2066721f80c4SRaju Lakkaraju 				tx->rqd_descriptors = 0;
2067721f80c4SRaju Lakkaraju 				netif_tx_wake_queue(txq);
2068721f80c4SRaju Lakkaraju 			}
206923f0703cSBryan Whitehead 		} else {
2070721f80c4SRaju Lakkaraju 			netif_tx_wake_queue(txq);
207123f0703cSBryan Whitehead 		}
207223f0703cSBryan Whitehead 	}
207323f0703cSBryan Whitehead 	spin_unlock_irqrestore(&tx->ring_lock, irq_flags);
207423f0703cSBryan Whitehead 
2075cc592205SBryan Whitehead 	if (!napi_complete(napi))
207623f0703cSBryan Whitehead 		goto done;
207723f0703cSBryan Whitehead 
207823f0703cSBryan Whitehead 	/* enable isr */
207923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_SET,
208023f0703cSBryan Whitehead 			  INT_BIT_DMA_TX_(tx->channel_number));
208123f0703cSBryan Whitehead 	lan743x_csr_read(adapter, INT_STS);
208223f0703cSBryan Whitehead 
208323f0703cSBryan Whitehead done:
2084cc592205SBryan Whitehead 	return 0;
208523f0703cSBryan Whitehead }
208623f0703cSBryan Whitehead 
lan743x_tx_ring_cleanup(struct lan743x_tx * tx)208723f0703cSBryan Whitehead static void lan743x_tx_ring_cleanup(struct lan743x_tx *tx)
208823f0703cSBryan Whitehead {
208923f0703cSBryan Whitehead 	if (tx->head_cpu_ptr) {
2090a3b7b493SChristophe JAILLET 		dma_free_coherent(&tx->adapter->pdev->dev,
2091a3b7b493SChristophe JAILLET 				  sizeof(*tx->head_cpu_ptr), tx->head_cpu_ptr,
209223f0703cSBryan Whitehead 				  tx->head_dma_ptr);
209323f0703cSBryan Whitehead 		tx->head_cpu_ptr = NULL;
209423f0703cSBryan Whitehead 		tx->head_dma_ptr = 0;
209523f0703cSBryan Whitehead 	}
209623f0703cSBryan Whitehead 	kfree(tx->buffer_info);
209723f0703cSBryan Whitehead 	tx->buffer_info = NULL;
209823f0703cSBryan Whitehead 
209923f0703cSBryan Whitehead 	if (tx->ring_cpu_ptr) {
2100a3b7b493SChristophe JAILLET 		dma_free_coherent(&tx->adapter->pdev->dev,
2101a3b7b493SChristophe JAILLET 				  tx->ring_allocation_size, tx->ring_cpu_ptr,
210223f0703cSBryan Whitehead 				  tx->ring_dma_ptr);
210323f0703cSBryan Whitehead 		tx->ring_allocation_size = 0;
210423f0703cSBryan Whitehead 		tx->ring_cpu_ptr = NULL;
210523f0703cSBryan Whitehead 		tx->ring_dma_ptr = 0;
210623f0703cSBryan Whitehead 	}
210723f0703cSBryan Whitehead 	tx->ring_size = 0;
210823f0703cSBryan Whitehead }
210923f0703cSBryan Whitehead 
lan743x_tx_ring_init(struct lan743x_tx * tx)211023f0703cSBryan Whitehead static int lan743x_tx_ring_init(struct lan743x_tx *tx)
211123f0703cSBryan Whitehead {
211223f0703cSBryan Whitehead 	size_t ring_allocation_size = 0;
211323f0703cSBryan Whitehead 	void *cpu_ptr = NULL;
211423f0703cSBryan Whitehead 	dma_addr_t dma_ptr;
211523f0703cSBryan Whitehead 	int ret = -ENOMEM;
211623f0703cSBryan Whitehead 
211723f0703cSBryan Whitehead 	tx->ring_size = LAN743X_TX_RING_SIZE;
211823f0703cSBryan Whitehead 	if (tx->ring_size & ~TX_CFG_B_TX_RING_LEN_MASK_) {
211923f0703cSBryan Whitehead 		ret = -EINVAL;
212023f0703cSBryan Whitehead 		goto cleanup;
212123f0703cSBryan Whitehead 	}
212295a359c9SYuiko Oshino 	if (dma_set_mask_and_coherent(&tx->adapter->pdev->dev,
212395a359c9SYuiko Oshino 				      DMA_BIT_MASK(64))) {
212495a359c9SYuiko Oshino 		dev_warn(&tx->adapter->pdev->dev,
212595a359c9SYuiko Oshino 			 "lan743x_: No suitable DMA available\n");
212695a359c9SYuiko Oshino 		ret = -ENOMEM;
212795a359c9SYuiko Oshino 		goto cleanup;
212895a359c9SYuiko Oshino 	}
212923f0703cSBryan Whitehead 	ring_allocation_size = ALIGN(tx->ring_size *
213023f0703cSBryan Whitehead 				     sizeof(struct lan743x_tx_descriptor),
213123f0703cSBryan Whitehead 				     PAGE_SIZE);
213223f0703cSBryan Whitehead 	dma_ptr = 0;
2133a3b7b493SChristophe JAILLET 	cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev,
2134a3b7b493SChristophe JAILLET 				     ring_allocation_size, &dma_ptr, GFP_KERNEL);
213523f0703cSBryan Whitehead 	if (!cpu_ptr) {
213623f0703cSBryan Whitehead 		ret = -ENOMEM;
213723f0703cSBryan Whitehead 		goto cleanup;
213823f0703cSBryan Whitehead 	}
213923f0703cSBryan Whitehead 
214023f0703cSBryan Whitehead 	tx->ring_allocation_size = ring_allocation_size;
214123f0703cSBryan Whitehead 	tx->ring_cpu_ptr = (struct lan743x_tx_descriptor *)cpu_ptr;
214223f0703cSBryan Whitehead 	tx->ring_dma_ptr = dma_ptr;
214323f0703cSBryan Whitehead 
214423f0703cSBryan Whitehead 	cpu_ptr = kcalloc(tx->ring_size, sizeof(*tx->buffer_info), GFP_KERNEL);
214523f0703cSBryan Whitehead 	if (!cpu_ptr) {
214623f0703cSBryan Whitehead 		ret = -ENOMEM;
214723f0703cSBryan Whitehead 		goto cleanup;
214823f0703cSBryan Whitehead 	}
214923f0703cSBryan Whitehead 	tx->buffer_info = (struct lan743x_tx_buffer_info *)cpu_ptr;
215023f0703cSBryan Whitehead 	dma_ptr = 0;
2151a3b7b493SChristophe JAILLET 	cpu_ptr = dma_alloc_coherent(&tx->adapter->pdev->dev,
2152a3b7b493SChristophe JAILLET 				     sizeof(*tx->head_cpu_ptr), &dma_ptr,
2153a3b7b493SChristophe JAILLET 				     GFP_KERNEL);
215423f0703cSBryan Whitehead 	if (!cpu_ptr) {
215523f0703cSBryan Whitehead 		ret = -ENOMEM;
215623f0703cSBryan Whitehead 		goto cleanup;
215723f0703cSBryan Whitehead 	}
215823f0703cSBryan Whitehead 
215923f0703cSBryan Whitehead 	tx->head_cpu_ptr = cpu_ptr;
216023f0703cSBryan Whitehead 	tx->head_dma_ptr = dma_ptr;
216123f0703cSBryan Whitehead 	if (tx->head_dma_ptr & 0x3) {
216223f0703cSBryan Whitehead 		ret = -ENOMEM;
216323f0703cSBryan Whitehead 		goto cleanup;
216423f0703cSBryan Whitehead 	}
216523f0703cSBryan Whitehead 
216623f0703cSBryan Whitehead 	return 0;
216723f0703cSBryan Whitehead 
216823f0703cSBryan Whitehead cleanup:
216923f0703cSBryan Whitehead 	lan743x_tx_ring_cleanup(tx);
217023f0703cSBryan Whitehead 	return ret;
217123f0703cSBryan Whitehead }
217223f0703cSBryan Whitehead 
lan743x_tx_close(struct lan743x_tx * tx)217323f0703cSBryan Whitehead static void lan743x_tx_close(struct lan743x_tx *tx)
217423f0703cSBryan Whitehead {
217523f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = tx->adapter;
217623f0703cSBryan Whitehead 
217723f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
217823f0703cSBryan Whitehead 			  DMAC_CMD,
217923f0703cSBryan Whitehead 			  DMAC_CMD_STOP_T_(tx->channel_number));
218023f0703cSBryan Whitehead 	lan743x_dmac_tx_wait_till_stopped(adapter, tx->channel_number);
218123f0703cSBryan Whitehead 
218223f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
218323f0703cSBryan Whitehead 			  DMAC_INT_EN_CLR,
218423f0703cSBryan Whitehead 			  DMAC_INT_BIT_TX_IOC_(tx->channel_number));
218523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_CLR,
218623f0703cSBryan Whitehead 			  INT_BIT_DMA_TX_(tx->channel_number));
218723f0703cSBryan Whitehead 	napi_disable(&tx->napi);
218823f0703cSBryan Whitehead 	netif_napi_del(&tx->napi);
218923f0703cSBryan Whitehead 
219023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, FCT_TX_CTL,
219123f0703cSBryan Whitehead 			  FCT_TX_CTL_DIS_(tx->channel_number));
219223f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL,
219323f0703cSBryan Whitehead 				 FCT_TX_CTL_EN_(tx->channel_number),
219423f0703cSBryan Whitehead 				 0, 1000, 20000, 100);
219523f0703cSBryan Whitehead 
219623f0703cSBryan Whitehead 	lan743x_tx_release_all_descriptors(tx);
219723f0703cSBryan Whitehead 
2198721f80c4SRaju Lakkaraju 	tx->rqd_descriptors = 0;
219923f0703cSBryan Whitehead 
220023f0703cSBryan Whitehead 	lan743x_tx_ring_cleanup(tx);
220123f0703cSBryan Whitehead }
220223f0703cSBryan Whitehead 
lan743x_tx_open(struct lan743x_tx * tx)220323f0703cSBryan Whitehead static int lan743x_tx_open(struct lan743x_tx *tx)
220423f0703cSBryan Whitehead {
220523f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = NULL;
220623f0703cSBryan Whitehead 	u32 data = 0;
220723f0703cSBryan Whitehead 	int ret;
220823f0703cSBryan Whitehead 
220923f0703cSBryan Whitehead 	adapter = tx->adapter;
221023f0703cSBryan Whitehead 	ret = lan743x_tx_ring_init(tx);
221123f0703cSBryan Whitehead 	if (ret)
221223f0703cSBryan Whitehead 		return ret;
221323f0703cSBryan Whitehead 
221423f0703cSBryan Whitehead 	/* initialize fifo */
221523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, FCT_TX_CTL,
221623f0703cSBryan Whitehead 			  FCT_TX_CTL_RESET_(tx->channel_number));
221723f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, FCT_TX_CTL,
221823f0703cSBryan Whitehead 				 FCT_TX_CTL_RESET_(tx->channel_number),
221923f0703cSBryan Whitehead 				 0, 1000, 20000, 100);
222023f0703cSBryan Whitehead 
222123f0703cSBryan Whitehead 	/* enable fifo */
222223f0703cSBryan Whitehead 	lan743x_csr_write(adapter, FCT_TX_CTL,
222323f0703cSBryan Whitehead 			  FCT_TX_CTL_EN_(tx->channel_number));
222423f0703cSBryan Whitehead 
222523f0703cSBryan Whitehead 	/* reset tx channel */
222623f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_CMD,
222723f0703cSBryan Whitehead 			  DMAC_CMD_TX_SWR_(tx->channel_number));
222823f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, DMAC_CMD,
222923f0703cSBryan Whitehead 				 DMAC_CMD_TX_SWR_(tx->channel_number),
223023f0703cSBryan Whitehead 				 0, 1000, 20000, 100);
223123f0703cSBryan Whitehead 
223223f0703cSBryan Whitehead 	/* Write TX_BASE_ADDR */
223323f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
223423f0703cSBryan Whitehead 			  TX_BASE_ADDRH(tx->channel_number),
223523f0703cSBryan Whitehead 			  DMA_ADDR_HIGH32(tx->ring_dma_ptr));
223623f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
223723f0703cSBryan Whitehead 			  TX_BASE_ADDRL(tx->channel_number),
223823f0703cSBryan Whitehead 			  DMA_ADDR_LOW32(tx->ring_dma_ptr));
223923f0703cSBryan Whitehead 
224023f0703cSBryan Whitehead 	/* Write TX_CFG_B */
224123f0703cSBryan Whitehead 	data = lan743x_csr_read(adapter, TX_CFG_B(tx->channel_number));
224223f0703cSBryan Whitehead 	data &= ~TX_CFG_B_TX_RING_LEN_MASK_;
224323f0703cSBryan Whitehead 	data |= ((tx->ring_size) & TX_CFG_B_TX_RING_LEN_MASK_);
224423f0703cSBryan Whitehead 	if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0))
224523f0703cSBryan Whitehead 		data |= TX_CFG_B_TDMABL_512_;
224623f0703cSBryan Whitehead 	lan743x_csr_write(adapter, TX_CFG_B(tx->channel_number), data);
224723f0703cSBryan Whitehead 
224823f0703cSBryan Whitehead 	/* Write TX_CFG_A */
224923f0703cSBryan Whitehead 	data = TX_CFG_A_TX_TMR_HPWB_SEL_IOC_ | TX_CFG_A_TX_HP_WB_EN_;
225023f0703cSBryan Whitehead 	if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
225123f0703cSBryan Whitehead 		data |= TX_CFG_A_TX_HP_WB_ON_INT_TMR_;
225223f0703cSBryan Whitehead 		data |= TX_CFG_A_TX_PF_THRES_SET_(0x10);
225323f0703cSBryan Whitehead 		data |= TX_CFG_A_TX_PF_PRI_THRES_SET_(0x04);
225423f0703cSBryan Whitehead 		data |= TX_CFG_A_TX_HP_WB_THRES_SET_(0x07);
225523f0703cSBryan Whitehead 	}
225623f0703cSBryan Whitehead 	lan743x_csr_write(adapter, TX_CFG_A(tx->channel_number), data);
225723f0703cSBryan Whitehead 
225823f0703cSBryan Whitehead 	/* Write TX_HEAD_WRITEBACK_ADDR */
225923f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
226023f0703cSBryan Whitehead 			  TX_HEAD_WRITEBACK_ADDRH(tx->channel_number),
226123f0703cSBryan Whitehead 			  DMA_ADDR_HIGH32(tx->head_dma_ptr));
226223f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
226323f0703cSBryan Whitehead 			  TX_HEAD_WRITEBACK_ADDRL(tx->channel_number),
226423f0703cSBryan Whitehead 			  DMA_ADDR_LOW32(tx->head_dma_ptr));
226523f0703cSBryan Whitehead 
226623f0703cSBryan Whitehead 	/* set last head */
226723f0703cSBryan Whitehead 	tx->last_head = lan743x_csr_read(adapter, TX_HEAD(tx->channel_number));
226823f0703cSBryan Whitehead 
226923f0703cSBryan Whitehead 	/* write TX_TAIL */
227023f0703cSBryan Whitehead 	tx->last_tail = 0;
227123f0703cSBryan Whitehead 	lan743x_csr_write(adapter, TX_TAIL(tx->channel_number),
227223f0703cSBryan Whitehead 			  (u32)(tx->last_tail));
227323f0703cSBryan Whitehead 	tx->vector_flags = lan743x_intr_get_vector_flags(adapter,
227423f0703cSBryan Whitehead 							 INT_BIT_DMA_TX_
227523f0703cSBryan Whitehead 							 (tx->channel_number));
22768d602e1aSJakub Kicinski 	netif_napi_add_tx_weight(adapter->netdev,
227723f0703cSBryan Whitehead 				 &tx->napi, lan743x_tx_napi_poll,
2278721f80c4SRaju Lakkaraju 				 NAPI_POLL_WEIGHT);
227923f0703cSBryan Whitehead 	napi_enable(&tx->napi);
228023f0703cSBryan Whitehead 
228123f0703cSBryan Whitehead 	data = 0;
228223f0703cSBryan Whitehead 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR)
228323f0703cSBryan Whitehead 		data |= TX_CFG_C_TX_TOP_INT_EN_AUTO_CLR_;
228423f0703cSBryan Whitehead 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR)
228523f0703cSBryan Whitehead 		data |= TX_CFG_C_TX_DMA_INT_STS_AUTO_CLR_;
228623f0703cSBryan Whitehead 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C)
228723f0703cSBryan Whitehead 		data |= TX_CFG_C_TX_INT_STS_R2C_MODE_MASK_;
228823f0703cSBryan Whitehead 	if (tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)
228923f0703cSBryan Whitehead 		data |= TX_CFG_C_TX_INT_EN_R2C_;
229023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, TX_CFG_C(tx->channel_number), data);
229123f0703cSBryan Whitehead 
229223f0703cSBryan Whitehead 	if (!(tx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET))
229323f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_SET,
229423f0703cSBryan Whitehead 				  INT_BIT_DMA_TX_(tx->channel_number));
229523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_INT_EN_SET,
229623f0703cSBryan Whitehead 			  DMAC_INT_BIT_TX_IOC_(tx->channel_number));
229723f0703cSBryan Whitehead 
229823f0703cSBryan Whitehead 	/*  start dmac channel */
229923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_CMD,
230023f0703cSBryan Whitehead 			  DMAC_CMD_START_T_(tx->channel_number));
230123f0703cSBryan Whitehead 	return 0;
230223f0703cSBryan Whitehead }
230323f0703cSBryan Whitehead 
lan743x_rx_next_index(struct lan743x_rx * rx,int index)230423f0703cSBryan Whitehead static int lan743x_rx_next_index(struct lan743x_rx *rx, int index)
230523f0703cSBryan Whitehead {
230623f0703cSBryan Whitehead 	return ((++index) % rx->ring_size);
230723f0703cSBryan Whitehead }
230823f0703cSBryan Whitehead 
lan743x_rx_update_tail(struct lan743x_rx * rx,int index)230957030a0bSSven Van Asbroeck static void lan743x_rx_update_tail(struct lan743x_rx *rx, int index)
231057030a0bSSven Van Asbroeck {
231157030a0bSSven Van Asbroeck 	/* update the tail once per 8 descriptors */
231257030a0bSSven Van Asbroeck 	if ((index & 7) == 7)
231357030a0bSSven Van Asbroeck 		lan743x_csr_write(rx->adapter, RX_TAIL(rx->channel_number),
231457030a0bSSven Van Asbroeck 				  index);
231557030a0bSSven Van Asbroeck }
231657030a0bSSven Van Asbroeck 
lan743x_rx_init_ring_element(struct lan743x_rx * rx,int index,gfp_t gfp)2317e8684db1SYuiko Oshino static int lan743x_rx_init_ring_element(struct lan743x_rx *rx, int index,
2318e8684db1SYuiko Oshino 					gfp_t gfp)
231923f0703cSBryan Whitehead {
2320a8db76d4SSven Van Asbroeck 	struct net_device *netdev = rx->adapter->netdev;
2321a8db76d4SSven Van Asbroeck 	struct device *dev = &rx->adapter->pdev->dev;
232223f0703cSBryan Whitehead 	struct lan743x_rx_buffer_info *buffer_info;
2323966df6deSSven Van Asbroeck 	unsigned int buffer_length, used_length;
232423f0703cSBryan Whitehead 	struct lan743x_rx_descriptor *descriptor;
2325a8db76d4SSven Van Asbroeck 	struct sk_buff *skb;
2326a8db76d4SSven Van Asbroeck 	dma_addr_t dma_ptr;
232723f0703cSBryan Whitehead 
23283bc41d6dSSven Van Asbroeck 	buffer_length = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + RX_HEAD_PADDING;
2329a8db76d4SSven Van Asbroeck 
233023f0703cSBryan Whitehead 	descriptor = &rx->ring_cpu_ptr[index];
233123f0703cSBryan Whitehead 	buffer_info = &rx->buffer_info[index];
2332e8684db1SYuiko Oshino 	skb = __netdev_alloc_skb(netdev, buffer_length, gfp);
2333a8db76d4SSven Van Asbroeck 	if (!skb)
233423f0703cSBryan Whitehead 		return -ENOMEM;
2335966df6deSSven Van Asbroeck 	dma_ptr = dma_map_single(dev, skb->data, buffer_length, DMA_FROM_DEVICE);
2336a8db76d4SSven Van Asbroeck 	if (dma_mapping_error(dev, dma_ptr)) {
2337a8db76d4SSven Van Asbroeck 		dev_kfree_skb_any(skb);
233823f0703cSBryan Whitehead 		return -ENOMEM;
233923f0703cSBryan Whitehead 	}
2340966df6deSSven Van Asbroeck 	if (buffer_info->dma_ptr) {
2341966df6deSSven Van Asbroeck 		/* sync used area of buffer only */
2342966df6deSSven Van Asbroeck 		if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_)
2343966df6deSSven Van Asbroeck 			/* frame length is valid only if LS bit is set.
2344966df6deSSven Van Asbroeck 			 * it's a safe upper bound for the used area in this
2345966df6deSSven Van Asbroeck 			 * buffer.
2346966df6deSSven Van Asbroeck 			 */
2347966df6deSSven Van Asbroeck 			used_length = min(RX_DESC_DATA0_FRAME_LENGTH_GET_
2348966df6deSSven Van Asbroeck 					  (le32_to_cpu(descriptor->data0)),
2349966df6deSSven Van Asbroeck 					  buffer_info->buffer_length);
2350966df6deSSven Van Asbroeck 		else
2351966df6deSSven Van Asbroeck 			used_length = buffer_info->buffer_length;
2352966df6deSSven Van Asbroeck 		dma_sync_single_for_cpu(dev, buffer_info->dma_ptr,
2353966df6deSSven Van Asbroeck 					used_length,
2354966df6deSSven Van Asbroeck 					DMA_FROM_DEVICE);
2355966df6deSSven Van Asbroeck 		dma_unmap_single_attrs(dev, buffer_info->dma_ptr,
2356966df6deSSven Van Asbroeck 				       buffer_info->buffer_length,
2357966df6deSSven Van Asbroeck 				       DMA_FROM_DEVICE,
2358966df6deSSven Van Asbroeck 				       DMA_ATTR_SKIP_CPU_SYNC);
2359966df6deSSven Van Asbroeck 	}
236023f0703cSBryan Whitehead 
2361a8db76d4SSven Van Asbroeck 	buffer_info->skb = skb;
2362a8db76d4SSven Van Asbroeck 	buffer_info->dma_ptr = dma_ptr;
2363966df6deSSven Van Asbroeck 	buffer_info->buffer_length = buffer_length;
236446251282SAlexey Denisov 	descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr));
236546251282SAlexey Denisov 	descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr));
236623f0703cSBryan Whitehead 	descriptor->data3 = 0;
236746251282SAlexey Denisov 	descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ |
2368966df6deSSven Van Asbroeck 			    (buffer_length & RX_DESC_DATA0_BUF_LENGTH_MASK_)));
236957030a0bSSven Van Asbroeck 	lan743x_rx_update_tail(rx, index);
237023f0703cSBryan Whitehead 
237123f0703cSBryan Whitehead 	return 0;
237223f0703cSBryan Whitehead }
237323f0703cSBryan Whitehead 
lan743x_rx_reuse_ring_element(struct lan743x_rx * rx,int index)237423f0703cSBryan Whitehead static void lan743x_rx_reuse_ring_element(struct lan743x_rx *rx, int index)
237523f0703cSBryan Whitehead {
237623f0703cSBryan Whitehead 	struct lan743x_rx_buffer_info *buffer_info;
237723f0703cSBryan Whitehead 	struct lan743x_rx_descriptor *descriptor;
237823f0703cSBryan Whitehead 
237923f0703cSBryan Whitehead 	descriptor = &rx->ring_cpu_ptr[index];
238023f0703cSBryan Whitehead 	buffer_info = &rx->buffer_info[index];
238123f0703cSBryan Whitehead 
238246251282SAlexey Denisov 	descriptor->data1 = cpu_to_le32(DMA_ADDR_LOW32(buffer_info->dma_ptr));
238346251282SAlexey Denisov 	descriptor->data2 = cpu_to_le32(DMA_ADDR_HIGH32(buffer_info->dma_ptr));
238423f0703cSBryan Whitehead 	descriptor->data3 = 0;
238546251282SAlexey Denisov 	descriptor->data0 = cpu_to_le32((RX_DESC_DATA0_OWN_ |
238623f0703cSBryan Whitehead 			    ((buffer_info->buffer_length) &
238746251282SAlexey Denisov 			    RX_DESC_DATA0_BUF_LENGTH_MASK_)));
238857030a0bSSven Van Asbroeck 	lan743x_rx_update_tail(rx, index);
238923f0703cSBryan Whitehead }
239023f0703cSBryan Whitehead 
lan743x_rx_release_ring_element(struct lan743x_rx * rx,int index)239123f0703cSBryan Whitehead static void lan743x_rx_release_ring_element(struct lan743x_rx *rx, int index)
239223f0703cSBryan Whitehead {
239323f0703cSBryan Whitehead 	struct lan743x_rx_buffer_info *buffer_info;
239423f0703cSBryan Whitehead 	struct lan743x_rx_descriptor *descriptor;
239523f0703cSBryan Whitehead 
239623f0703cSBryan Whitehead 	descriptor = &rx->ring_cpu_ptr[index];
239723f0703cSBryan Whitehead 	buffer_info = &rx->buffer_info[index];
239823f0703cSBryan Whitehead 
239923f0703cSBryan Whitehead 	memset(descriptor, 0, sizeof(*descriptor));
240023f0703cSBryan Whitehead 
240123f0703cSBryan Whitehead 	if (buffer_info->dma_ptr) {
240223f0703cSBryan Whitehead 		dma_unmap_single(&rx->adapter->pdev->dev,
240323f0703cSBryan Whitehead 				 buffer_info->dma_ptr,
240423f0703cSBryan Whitehead 				 buffer_info->buffer_length,
240523f0703cSBryan Whitehead 				 DMA_FROM_DEVICE);
240623f0703cSBryan Whitehead 		buffer_info->dma_ptr = 0;
240723f0703cSBryan Whitehead 	}
240823f0703cSBryan Whitehead 
240923f0703cSBryan Whitehead 	if (buffer_info->skb) {
241023f0703cSBryan Whitehead 		dev_kfree_skb(buffer_info->skb);
241123f0703cSBryan Whitehead 		buffer_info->skb = NULL;
241223f0703cSBryan Whitehead 	}
241323f0703cSBryan Whitehead 
241423f0703cSBryan Whitehead 	memset(buffer_info, 0, sizeof(*buffer_info));
241523f0703cSBryan Whitehead }
241623f0703cSBryan Whitehead 
2417a8db76d4SSven Van Asbroeck static struct sk_buff *
lan743x_rx_trim_skb(struct sk_buff * skb,int frame_length)2418a8db76d4SSven Van Asbroeck lan743x_rx_trim_skb(struct sk_buff *skb, int frame_length)
241923f0703cSBryan Whitehead {
2420a8db76d4SSven Van Asbroeck 	if (skb_linearize(skb)) {
2421a8db76d4SSven Van Asbroeck 		dev_kfree_skb_irq(skb);
2422a8db76d4SSven Van Asbroeck 		return NULL;
2423a8db76d4SSven Van Asbroeck 	}
24243bc41d6dSSven Van Asbroeck 	frame_length = max_t(int, 0, frame_length - ETH_FCS_LEN);
2425a8db76d4SSven Van Asbroeck 	if (skb->len > frame_length) {
2426a8db76d4SSven Van Asbroeck 		skb->tail -= skb->len - frame_length;
2427a8db76d4SSven Van Asbroeck 		skb->len = frame_length;
2428a8db76d4SSven Van Asbroeck 	}
2429a8db76d4SSven Van Asbroeck 	return skb;
2430a8db76d4SSven Van Asbroeck }
2431a8db76d4SSven Van Asbroeck 
lan743x_rx_process_buffer(struct lan743x_rx * rx)2432a8db76d4SSven Van Asbroeck static int lan743x_rx_process_buffer(struct lan743x_rx *rx)
2433a8db76d4SSven Van Asbroeck {
243446251282SAlexey Denisov 	int current_head_index = le32_to_cpu(*rx->head_cpu_ptr);
2435a8db76d4SSven Van Asbroeck 	struct lan743x_rx_descriptor *descriptor, *desc_ext;
2436a8db76d4SSven Van Asbroeck 	struct net_device *netdev = rx->adapter->netdev;
2437a8db76d4SSven Van Asbroeck 	int result = RX_PROCESS_RESULT_NOTHING_TO_DO;
243823f0703cSBryan Whitehead 	struct lan743x_rx_buffer_info *buffer_info;
2439a8db76d4SSven Van Asbroeck 	int frame_length, buffer_length;
2440cd691050SRaju Lakkaraju 	bool is_ice, is_tce, is_icsm;
244123f0703cSBryan Whitehead 	int extension_index = -1;
2442a8db76d4SSven Van Asbroeck 	bool is_last, is_first;
2443a8db76d4SSven Van Asbroeck 	struct sk_buff *skb;
244423f0703cSBryan Whitehead 
244523f0703cSBryan Whitehead 	if (current_head_index < 0 || current_head_index >= rx->ring_size)
244623f0703cSBryan Whitehead 		goto done;
244723f0703cSBryan Whitehead 
244823f0703cSBryan Whitehead 	if (rx->last_head < 0 || rx->last_head >= rx->ring_size)
244923f0703cSBryan Whitehead 		goto done;
245023f0703cSBryan Whitehead 
2451a8db76d4SSven Van Asbroeck 	if (rx->last_head == current_head_index)
2452a8db76d4SSven Van Asbroeck 		goto done;
2453a8db76d4SSven Van Asbroeck 
245423f0703cSBryan Whitehead 	descriptor = &rx->ring_cpu_ptr[rx->last_head];
245546251282SAlexey Denisov 	if (le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_OWN_)
245623f0703cSBryan Whitehead 		goto done;
2457a8db76d4SSven Van Asbroeck 	buffer_info = &rx->buffer_info[rx->last_head];
245823f0703cSBryan Whitehead 
2459a8db76d4SSven Van Asbroeck 	is_last = le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_LS_;
2460a8db76d4SSven Van Asbroeck 	is_first = le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_FS_;
246123f0703cSBryan Whitehead 
2462a8db76d4SSven Van Asbroeck 	if (is_last && le32_to_cpu(descriptor->data0) & RX_DESC_DATA0_EXT_) {
246323f0703cSBryan Whitehead 		/* extension is expected to follow */
2464a8db76d4SSven Van Asbroeck 		int index = lan743x_rx_next_index(rx, rx->last_head);
2465a8db76d4SSven Van Asbroeck 
2466a8db76d4SSven Van Asbroeck 		if (index == current_head_index)
2467a8db76d4SSven Van Asbroeck 			/* extension not yet available */
246823f0703cSBryan Whitehead 			goto done;
2469a8db76d4SSven Van Asbroeck 		desc_ext = &rx->ring_cpu_ptr[index];
2470a8db76d4SSven Van Asbroeck 		if (le32_to_cpu(desc_ext->data0) & RX_DESC_DATA0_OWN_)
2471a8db76d4SSven Van Asbroeck 			/* extension not yet available */
2472a8db76d4SSven Van Asbroeck 			goto done;
2473a8db76d4SSven Van Asbroeck 		if (!(le32_to_cpu(desc_ext->data0) & RX_DESC_DATA0_EXT_))
2474a8db76d4SSven Van Asbroeck 			goto move_forward;
247523f0703cSBryan Whitehead 		extension_index = index;
247623f0703cSBryan Whitehead 	}
247723f0703cSBryan Whitehead 
2478a8db76d4SSven Van Asbroeck 	/* Only the last buffer in a multi-buffer frame contains the total frame
2479a8db76d4SSven Van Asbroeck 	 * length. The chip occasionally sends more buffers than strictly
2480a8db76d4SSven Van Asbroeck 	 * required to reach the total frame length.
2481a8db76d4SSven Van Asbroeck 	 * Handle this by adding all buffers to the skb in their entirety.
2482a8db76d4SSven Van Asbroeck 	 * Once the real frame length is known, trim the skb.
2483a8db76d4SSven Van Asbroeck 	 */
2484a8db76d4SSven Van Asbroeck 	frame_length =
2485a8db76d4SSven Van Asbroeck 		RX_DESC_DATA0_FRAME_LENGTH_GET_(le32_to_cpu(descriptor->data0));
2486a8db76d4SSven Van Asbroeck 	buffer_length = buffer_info->buffer_length;
2487cd691050SRaju Lakkaraju 	is_ice = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_ICE_;
2488cd691050SRaju Lakkaraju 	is_tce = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_TCE_;
2489cd691050SRaju Lakkaraju 	is_icsm = le32_to_cpu(descriptor->data1) & RX_DESC_DATA1_STATUS_ICSM_;
249023f0703cSBryan Whitehead 
2491a8db76d4SSven Van Asbroeck 	netdev_dbg(netdev, "%s%schunk: %d/%d",
2492a8db76d4SSven Van Asbroeck 		   is_first ? "first " : "      ",
2493a8db76d4SSven Van Asbroeck 		   is_last  ? "last  " : "      ",
2494a8db76d4SSven Van Asbroeck 		   frame_length, buffer_length);
2495a8db76d4SSven Van Asbroeck 
2496a8db76d4SSven Van Asbroeck 	/* save existing skb, allocate new skb and map to dma */
2497a8db76d4SSven Van Asbroeck 	skb = buffer_info->skb;
2498e8684db1SYuiko Oshino 	if (lan743x_rx_init_ring_element(rx, rx->last_head,
2499e8684db1SYuiko Oshino 					 GFP_ATOMIC | GFP_DMA)) {
2500dd9d9f59SBryan Whitehead 		/* failed to allocate next skb.
2501dd9d9f59SBryan Whitehead 		 * Memory is very low.
2502dd9d9f59SBryan Whitehead 		 * Drop this packet and reuse buffer.
2503dd9d9f59SBryan Whitehead 		 */
2504a8db76d4SSven Van Asbroeck 		lan743x_rx_reuse_ring_element(rx, rx->last_head);
2505a8db76d4SSven Van Asbroeck 		/* drop packet that was being assembled */
2506a8db76d4SSven Van Asbroeck 		dev_kfree_skb_irq(rx->skb_head);
2507a8db76d4SSven Van Asbroeck 		rx->skb_head = NULL;
2508dd9d9f59SBryan Whitehead 		goto process_extension;
2509dd9d9f59SBryan Whitehead 	}
2510dd9d9f59SBryan Whitehead 
2511a8db76d4SSven Van Asbroeck 	/* add buffers to skb via skb->frag_list */
2512a8db76d4SSven Van Asbroeck 	if (is_first) {
2513a8db76d4SSven Van Asbroeck 		skb_reserve(skb, RX_HEAD_PADDING);
2514a8db76d4SSven Van Asbroeck 		skb_put(skb, buffer_length - RX_HEAD_PADDING);
2515a8db76d4SSven Van Asbroeck 		if (rx->skb_head)
2516a8db76d4SSven Van Asbroeck 			dev_kfree_skb_irq(rx->skb_head);
2517a8db76d4SSven Van Asbroeck 		rx->skb_head = skb;
2518a8db76d4SSven Van Asbroeck 	} else if (rx->skb_head) {
2519a8db76d4SSven Van Asbroeck 		skb_put(skb, buffer_length);
2520a8db76d4SSven Van Asbroeck 		if (skb_shinfo(rx->skb_head)->frag_list)
2521a8db76d4SSven Van Asbroeck 			rx->skb_tail->next = skb;
2522a8db76d4SSven Van Asbroeck 		else
2523a8db76d4SSven Van Asbroeck 			skb_shinfo(rx->skb_head)->frag_list = skb;
2524a8db76d4SSven Van Asbroeck 		rx->skb_tail = skb;
2525a8db76d4SSven Van Asbroeck 		rx->skb_head->len += skb->len;
2526a8db76d4SSven Van Asbroeck 		rx->skb_head->data_len += skb->len;
2527a8db76d4SSven Van Asbroeck 		rx->skb_head->truesize += skb->truesize;
252823f0703cSBryan Whitehead 	} else {
2529a8db76d4SSven Van Asbroeck 		/* packet to assemble has already been dropped because one or
2530a8db76d4SSven Van Asbroeck 		 * more of its buffers could not be allocated
253123f0703cSBryan Whitehead 		 */
2532a8db76d4SSven Van Asbroeck 		netdev_dbg(netdev, "drop buffer intended for dropped packet");
2533a8db76d4SSven Van Asbroeck 		dev_kfree_skb_irq(skb);
253423f0703cSBryan Whitehead 	}
253523f0703cSBryan Whitehead 
2536dd9d9f59SBryan Whitehead process_extension:
253723f0703cSBryan Whitehead 	if (extension_index >= 0) {
2538a8db76d4SSven Van Asbroeck 		u32 ts_sec;
2539a8db76d4SSven Van Asbroeck 		u32 ts_nsec;
254023f0703cSBryan Whitehead 
2541a8db76d4SSven Van Asbroeck 		ts_sec = le32_to_cpu(desc_ext->data1);
2542a8db76d4SSven Van Asbroeck 		ts_nsec = (le32_to_cpu(desc_ext->data2) &
254323f0703cSBryan Whitehead 			  RX_DESC_DATA2_TS_NS_MASK_);
2544a8db76d4SSven Van Asbroeck 		if (rx->skb_head)
2545a8db76d4SSven Van Asbroeck 			skb_hwtstamps(rx->skb_head)->hwtstamp =
2546a8db76d4SSven Van Asbroeck 				ktime_set(ts_sec, ts_nsec);
254723f0703cSBryan Whitehead 		lan743x_rx_reuse_ring_element(rx, extension_index);
2548a8db76d4SSven Van Asbroeck 		rx->last_head = extension_index;
2549a8db76d4SSven Van Asbroeck 		netdev_dbg(netdev, "process extension");
255023f0703cSBryan Whitehead 	}
255123f0703cSBryan Whitehead 
2552a8db76d4SSven Van Asbroeck 	if (is_last && rx->skb_head)
2553a8db76d4SSven Van Asbroeck 		rx->skb_head = lan743x_rx_trim_skb(rx->skb_head, frame_length);
2554a8db76d4SSven Van Asbroeck 
2555a8db76d4SSven Van Asbroeck 	if (is_last && rx->skb_head) {
2556a8db76d4SSven Van Asbroeck 		rx->skb_head->protocol = eth_type_trans(rx->skb_head,
2557a8db76d4SSven Van Asbroeck 							rx->adapter->netdev);
2558cd691050SRaju Lakkaraju 		if (rx->adapter->netdev->features & NETIF_F_RXCSUM) {
2559cd691050SRaju Lakkaraju 			if (!is_ice && !is_tce && !is_icsm)
2560cd691050SRaju Lakkaraju 				skb->ip_summed = CHECKSUM_UNNECESSARY;
2561cd691050SRaju Lakkaraju 		}
2562a8db76d4SSven Van Asbroeck 		netdev_dbg(netdev, "sending %d byte frame to OS",
2563a8db76d4SSven Van Asbroeck 			   rx->skb_head->len);
2564a8db76d4SSven Van Asbroeck 		napi_gro_receive(&rx->napi, rx->skb_head);
2565a8db76d4SSven Van Asbroeck 		rx->skb_head = NULL;
256623f0703cSBryan Whitehead 	}
256723f0703cSBryan Whitehead 
256823f0703cSBryan Whitehead move_forward:
256923f0703cSBryan Whitehead 	/* push tail and head forward */
2570a8db76d4SSven Van Asbroeck 	rx->last_tail = rx->last_head;
2571a8db76d4SSven Van Asbroeck 	rx->last_head = lan743x_rx_next_index(rx, rx->last_head);
2572a8db76d4SSven Van Asbroeck 	result = RX_PROCESS_RESULT_BUFFER_RECEIVED;
257323f0703cSBryan Whitehead done:
257423f0703cSBryan Whitehead 	return result;
257523f0703cSBryan Whitehead }
257623f0703cSBryan Whitehead 
lan743x_rx_napi_poll(struct napi_struct * napi,int weight)257723f0703cSBryan Whitehead static int lan743x_rx_napi_poll(struct napi_struct *napi, int weight)
257823f0703cSBryan Whitehead {
257923f0703cSBryan Whitehead 	struct lan743x_rx *rx = container_of(napi, struct lan743x_rx, napi);
258023f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = rx->adapter;
258157030a0bSSven Van Asbroeck 	int result = RX_PROCESS_RESULT_NOTHING_TO_DO;
258223f0703cSBryan Whitehead 	u32 rx_tail_flags = 0;
258323f0703cSBryan Whitehead 	int count;
258423f0703cSBryan Whitehead 
258523f0703cSBryan Whitehead 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_W2C) {
258623f0703cSBryan Whitehead 		/* clear int status bit before reading packet */
258723f0703cSBryan Whitehead 		lan743x_csr_write(adapter, DMAC_INT_STS,
258823f0703cSBryan Whitehead 				  DMAC_INT_BIT_RXFRM_(rx->channel_number));
258923f0703cSBryan Whitehead 	}
259057030a0bSSven Van Asbroeck 	for (count = 0; count < weight; count++) {
2591a8db76d4SSven Van Asbroeck 		result = lan743x_rx_process_buffer(rx);
259257030a0bSSven Van Asbroeck 		if (result == RX_PROCESS_RESULT_NOTHING_TO_DO)
259323f0703cSBryan Whitehead 			break;
259423f0703cSBryan Whitehead 	}
259523f0703cSBryan Whitehead 	rx->frame_count += count;
2596a8db76d4SSven Van Asbroeck 	if (count == weight || result == RX_PROCESS_RESULT_BUFFER_RECEIVED)
259757030a0bSSven Van Asbroeck 		return weight;
259823f0703cSBryan Whitehead 
259923f0703cSBryan Whitehead 	if (!napi_complete_done(napi, count))
260057030a0bSSven Van Asbroeck 		return count;
260123f0703cSBryan Whitehead 
260257030a0bSSven Van Asbroeck 	/* re-arm interrupts, must write to rx tail on some chip variants */
260323f0703cSBryan Whitehead 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_VECTOR_ENABLE_AUTO_SET)
260423f0703cSBryan Whitehead 		rx_tail_flags |= RX_TAIL_SET_TOP_INT_VEC_EN_;
260523f0703cSBryan Whitehead 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_SET) {
260623f0703cSBryan Whitehead 		rx_tail_flags |= RX_TAIL_SET_TOP_INT_EN_;
260723f0703cSBryan Whitehead 	} else {
260823f0703cSBryan Whitehead 		lan743x_csr_write(adapter, INT_EN_SET,
260923f0703cSBryan Whitehead 				  INT_BIT_DMA_RX_(rx->channel_number));
261023f0703cSBryan Whitehead 	}
261123f0703cSBryan Whitehead 
261257030a0bSSven Van Asbroeck 	if (rx_tail_flags)
261323f0703cSBryan Whitehead 		lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
261423f0703cSBryan Whitehead 				  rx_tail_flags | rx->last_tail);
261557030a0bSSven Van Asbroeck 
261623f0703cSBryan Whitehead 	return count;
261723f0703cSBryan Whitehead }
261823f0703cSBryan Whitehead 
lan743x_rx_ring_cleanup(struct lan743x_rx * rx)261923f0703cSBryan Whitehead static void lan743x_rx_ring_cleanup(struct lan743x_rx *rx)
262023f0703cSBryan Whitehead {
262123f0703cSBryan Whitehead 	if (rx->buffer_info && rx->ring_cpu_ptr) {
262223f0703cSBryan Whitehead 		int index;
262323f0703cSBryan Whitehead 
262423f0703cSBryan Whitehead 		for (index = 0; index < rx->ring_size; index++)
262523f0703cSBryan Whitehead 			lan743x_rx_release_ring_element(rx, index);
262623f0703cSBryan Whitehead 	}
262723f0703cSBryan Whitehead 
262823f0703cSBryan Whitehead 	if (rx->head_cpu_ptr) {
2629a3b7b493SChristophe JAILLET 		dma_free_coherent(&rx->adapter->pdev->dev,
2630a3b7b493SChristophe JAILLET 				  sizeof(*rx->head_cpu_ptr), rx->head_cpu_ptr,
263123f0703cSBryan Whitehead 				  rx->head_dma_ptr);
263223f0703cSBryan Whitehead 		rx->head_cpu_ptr = NULL;
263323f0703cSBryan Whitehead 		rx->head_dma_ptr = 0;
263423f0703cSBryan Whitehead 	}
263523f0703cSBryan Whitehead 
263623f0703cSBryan Whitehead 	kfree(rx->buffer_info);
263723f0703cSBryan Whitehead 	rx->buffer_info = NULL;
263823f0703cSBryan Whitehead 
263923f0703cSBryan Whitehead 	if (rx->ring_cpu_ptr) {
2640a3b7b493SChristophe JAILLET 		dma_free_coherent(&rx->adapter->pdev->dev,
2641a3b7b493SChristophe JAILLET 				  rx->ring_allocation_size, rx->ring_cpu_ptr,
264223f0703cSBryan Whitehead 				  rx->ring_dma_ptr);
264323f0703cSBryan Whitehead 		rx->ring_allocation_size = 0;
264423f0703cSBryan Whitehead 		rx->ring_cpu_ptr = NULL;
264523f0703cSBryan Whitehead 		rx->ring_dma_ptr = 0;
264623f0703cSBryan Whitehead 	}
264723f0703cSBryan Whitehead 
264823f0703cSBryan Whitehead 	rx->ring_size = 0;
264923f0703cSBryan Whitehead 	rx->last_head = 0;
265023f0703cSBryan Whitehead }
265123f0703cSBryan Whitehead 
lan743x_rx_ring_init(struct lan743x_rx * rx)265223f0703cSBryan Whitehead static int lan743x_rx_ring_init(struct lan743x_rx *rx)
265323f0703cSBryan Whitehead {
265423f0703cSBryan Whitehead 	size_t ring_allocation_size = 0;
265523f0703cSBryan Whitehead 	dma_addr_t dma_ptr = 0;
265623f0703cSBryan Whitehead 	void *cpu_ptr = NULL;
265723f0703cSBryan Whitehead 	int ret = -ENOMEM;
265823f0703cSBryan Whitehead 	int index = 0;
265923f0703cSBryan Whitehead 
266023f0703cSBryan Whitehead 	rx->ring_size = LAN743X_RX_RING_SIZE;
266123f0703cSBryan Whitehead 	if (rx->ring_size <= 1) {
266223f0703cSBryan Whitehead 		ret = -EINVAL;
266323f0703cSBryan Whitehead 		goto cleanup;
266423f0703cSBryan Whitehead 	}
266523f0703cSBryan Whitehead 	if (rx->ring_size & ~RX_CFG_B_RX_RING_LEN_MASK_) {
266623f0703cSBryan Whitehead 		ret = -EINVAL;
266723f0703cSBryan Whitehead 		goto cleanup;
266823f0703cSBryan Whitehead 	}
266995a359c9SYuiko Oshino 	if (dma_set_mask_and_coherent(&rx->adapter->pdev->dev,
267095a359c9SYuiko Oshino 				      DMA_BIT_MASK(64))) {
267195a359c9SYuiko Oshino 		dev_warn(&rx->adapter->pdev->dev,
267295a359c9SYuiko Oshino 			 "lan743x_: No suitable DMA available\n");
267395a359c9SYuiko Oshino 		ret = -ENOMEM;
267495a359c9SYuiko Oshino 		goto cleanup;
267595a359c9SYuiko Oshino 	}
267623f0703cSBryan Whitehead 	ring_allocation_size = ALIGN(rx->ring_size *
267723f0703cSBryan Whitehead 				     sizeof(struct lan743x_rx_descriptor),
267823f0703cSBryan Whitehead 				     PAGE_SIZE);
267923f0703cSBryan Whitehead 	dma_ptr = 0;
2680a3b7b493SChristophe JAILLET 	cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev,
2681a3b7b493SChristophe JAILLET 				     ring_allocation_size, &dma_ptr, GFP_KERNEL);
268223f0703cSBryan Whitehead 	if (!cpu_ptr) {
268323f0703cSBryan Whitehead 		ret = -ENOMEM;
268423f0703cSBryan Whitehead 		goto cleanup;
268523f0703cSBryan Whitehead 	}
268623f0703cSBryan Whitehead 	rx->ring_allocation_size = ring_allocation_size;
268723f0703cSBryan Whitehead 	rx->ring_cpu_ptr = (struct lan743x_rx_descriptor *)cpu_ptr;
268823f0703cSBryan Whitehead 	rx->ring_dma_ptr = dma_ptr;
268923f0703cSBryan Whitehead 
269023f0703cSBryan Whitehead 	cpu_ptr = kcalloc(rx->ring_size, sizeof(*rx->buffer_info),
269123f0703cSBryan Whitehead 			  GFP_KERNEL);
269223f0703cSBryan Whitehead 	if (!cpu_ptr) {
269323f0703cSBryan Whitehead 		ret = -ENOMEM;
269423f0703cSBryan Whitehead 		goto cleanup;
269523f0703cSBryan Whitehead 	}
269623f0703cSBryan Whitehead 	rx->buffer_info = (struct lan743x_rx_buffer_info *)cpu_ptr;
269723f0703cSBryan Whitehead 	dma_ptr = 0;
2698a3b7b493SChristophe JAILLET 	cpu_ptr = dma_alloc_coherent(&rx->adapter->pdev->dev,
2699a3b7b493SChristophe JAILLET 				     sizeof(*rx->head_cpu_ptr), &dma_ptr,
2700a3b7b493SChristophe JAILLET 				     GFP_KERNEL);
270123f0703cSBryan Whitehead 	if (!cpu_ptr) {
270223f0703cSBryan Whitehead 		ret = -ENOMEM;
270323f0703cSBryan Whitehead 		goto cleanup;
270423f0703cSBryan Whitehead 	}
270523f0703cSBryan Whitehead 
270623f0703cSBryan Whitehead 	rx->head_cpu_ptr = cpu_ptr;
270723f0703cSBryan Whitehead 	rx->head_dma_ptr = dma_ptr;
270823f0703cSBryan Whitehead 	if (rx->head_dma_ptr & 0x3) {
270923f0703cSBryan Whitehead 		ret = -ENOMEM;
271023f0703cSBryan Whitehead 		goto cleanup;
271123f0703cSBryan Whitehead 	}
271223f0703cSBryan Whitehead 
271323f0703cSBryan Whitehead 	rx->last_head = 0;
271423f0703cSBryan Whitehead 	for (index = 0; index < rx->ring_size; index++) {
2715e8684db1SYuiko Oshino 		ret = lan743x_rx_init_ring_element(rx, index, GFP_KERNEL);
271623f0703cSBryan Whitehead 		if (ret)
271723f0703cSBryan Whitehead 			goto cleanup;
271823f0703cSBryan Whitehead 	}
271923f0703cSBryan Whitehead 	return 0;
272023f0703cSBryan Whitehead 
272123f0703cSBryan Whitehead cleanup:
2722e8684db1SYuiko Oshino 	netif_warn(rx->adapter, ifup, rx->adapter->netdev,
2723e8684db1SYuiko Oshino 		   "Error allocating memory for LAN743x\n");
2724e8684db1SYuiko Oshino 
272523f0703cSBryan Whitehead 	lan743x_rx_ring_cleanup(rx);
272623f0703cSBryan Whitehead 	return ret;
272723f0703cSBryan Whitehead }
272823f0703cSBryan Whitehead 
lan743x_rx_close(struct lan743x_rx * rx)272923f0703cSBryan Whitehead static void lan743x_rx_close(struct lan743x_rx *rx)
273023f0703cSBryan Whitehead {
273123f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = rx->adapter;
273223f0703cSBryan Whitehead 
273323f0703cSBryan Whitehead 	lan743x_csr_write(adapter, FCT_RX_CTL,
273423f0703cSBryan Whitehead 			  FCT_RX_CTL_DIS_(rx->channel_number));
273523f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL,
273623f0703cSBryan Whitehead 				 FCT_RX_CTL_EN_(rx->channel_number),
273723f0703cSBryan Whitehead 				 0, 1000, 20000, 100);
273823f0703cSBryan Whitehead 
273923f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_CMD,
274023f0703cSBryan Whitehead 			  DMAC_CMD_STOP_R_(rx->channel_number));
274123f0703cSBryan Whitehead 	lan743x_dmac_rx_wait_till_stopped(adapter, rx->channel_number);
274223f0703cSBryan Whitehead 
274323f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_INT_EN_CLR,
274423f0703cSBryan Whitehead 			  DMAC_INT_BIT_RXFRM_(rx->channel_number));
274523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_CLR,
274623f0703cSBryan Whitehead 			  INT_BIT_DMA_RX_(rx->channel_number));
274723f0703cSBryan Whitehead 	napi_disable(&rx->napi);
274823f0703cSBryan Whitehead 
274923f0703cSBryan Whitehead 	netif_napi_del(&rx->napi);
275023f0703cSBryan Whitehead 
275123f0703cSBryan Whitehead 	lan743x_rx_ring_cleanup(rx);
275223f0703cSBryan Whitehead }
275323f0703cSBryan Whitehead 
lan743x_rx_open(struct lan743x_rx * rx)275423f0703cSBryan Whitehead static int lan743x_rx_open(struct lan743x_rx *rx)
275523f0703cSBryan Whitehead {
275623f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = rx->adapter;
275723f0703cSBryan Whitehead 	u32 data = 0;
275823f0703cSBryan Whitehead 	int ret;
275923f0703cSBryan Whitehead 
276023f0703cSBryan Whitehead 	rx->frame_count = 0;
276123f0703cSBryan Whitehead 	ret = lan743x_rx_ring_init(rx);
276223f0703cSBryan Whitehead 	if (ret)
276323f0703cSBryan Whitehead 		goto return_error;
276423f0703cSBryan Whitehead 
2765b48b89f9SJakub Kicinski 	netif_napi_add(adapter->netdev, &rx->napi, lan743x_rx_napi_poll);
276623f0703cSBryan Whitehead 
276723f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_CMD,
276823f0703cSBryan Whitehead 			  DMAC_CMD_RX_SWR_(rx->channel_number));
276923f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, DMAC_CMD,
277023f0703cSBryan Whitehead 				 DMAC_CMD_RX_SWR_(rx->channel_number),
277123f0703cSBryan Whitehead 				 0, 1000, 20000, 100);
277223f0703cSBryan Whitehead 
277323f0703cSBryan Whitehead 	/* set ring base address */
277423f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
277523f0703cSBryan Whitehead 			  RX_BASE_ADDRH(rx->channel_number),
277623f0703cSBryan Whitehead 			  DMA_ADDR_HIGH32(rx->ring_dma_ptr));
277723f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
277823f0703cSBryan Whitehead 			  RX_BASE_ADDRL(rx->channel_number),
277923f0703cSBryan Whitehead 			  DMA_ADDR_LOW32(rx->ring_dma_ptr));
278023f0703cSBryan Whitehead 
278123f0703cSBryan Whitehead 	/* set rx write back address */
278223f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
278323f0703cSBryan Whitehead 			  RX_HEAD_WRITEBACK_ADDRH(rx->channel_number),
278423f0703cSBryan Whitehead 			  DMA_ADDR_HIGH32(rx->head_dma_ptr));
278523f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
278623f0703cSBryan Whitehead 			  RX_HEAD_WRITEBACK_ADDRL(rx->channel_number),
278723f0703cSBryan Whitehead 			  DMA_ADDR_LOW32(rx->head_dma_ptr));
278823f0703cSBryan Whitehead 	data = RX_CFG_A_RX_HP_WB_EN_;
278923f0703cSBryan Whitehead 	if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0)) {
279023f0703cSBryan Whitehead 		data |= (RX_CFG_A_RX_WB_ON_INT_TMR_ |
279123f0703cSBryan Whitehead 			RX_CFG_A_RX_WB_THRES_SET_(0x7) |
279223f0703cSBryan Whitehead 			RX_CFG_A_RX_PF_THRES_SET_(16) |
279323f0703cSBryan Whitehead 			RX_CFG_A_RX_PF_PRI_THRES_SET_(4));
279423f0703cSBryan Whitehead 	}
279523f0703cSBryan Whitehead 
279623f0703cSBryan Whitehead 	/* set RX_CFG_A */
279723f0703cSBryan Whitehead 	lan743x_csr_write(adapter,
279823f0703cSBryan Whitehead 			  RX_CFG_A(rx->channel_number), data);
279923f0703cSBryan Whitehead 
280023f0703cSBryan Whitehead 	/* set RX_CFG_B */
280123f0703cSBryan Whitehead 	data = lan743x_csr_read(adapter, RX_CFG_B(rx->channel_number));
280223f0703cSBryan Whitehead 	data &= ~RX_CFG_B_RX_PAD_MASK_;
280323f0703cSBryan Whitehead 	if (!RX_HEAD_PADDING)
280423f0703cSBryan Whitehead 		data |= RX_CFG_B_RX_PAD_0_;
280523f0703cSBryan Whitehead 	else
280623f0703cSBryan Whitehead 		data |= RX_CFG_B_RX_PAD_2_;
280723f0703cSBryan Whitehead 	data &= ~RX_CFG_B_RX_RING_LEN_MASK_;
280823f0703cSBryan Whitehead 	data |= ((rx->ring_size) & RX_CFG_B_RX_RING_LEN_MASK_);
280923f0703cSBryan Whitehead 	if (!(adapter->csr.flags & LAN743X_CSR_FLAG_IS_A0))
281023f0703cSBryan Whitehead 		data |= RX_CFG_B_RDMABL_512_;
281123f0703cSBryan Whitehead 
281223f0703cSBryan Whitehead 	lan743x_csr_write(adapter, RX_CFG_B(rx->channel_number), data);
281323f0703cSBryan Whitehead 	rx->vector_flags = lan743x_intr_get_vector_flags(adapter,
281423f0703cSBryan Whitehead 							 INT_BIT_DMA_RX_
281523f0703cSBryan Whitehead 							 (rx->channel_number));
281623f0703cSBryan Whitehead 
281723f0703cSBryan Whitehead 	/* set RX_CFG_C */
281823f0703cSBryan Whitehead 	data = 0;
281923f0703cSBryan Whitehead 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_AUTO_CLEAR)
282023f0703cSBryan Whitehead 		data |= RX_CFG_C_RX_TOP_INT_EN_AUTO_CLR_;
282123f0703cSBryan Whitehead 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_AUTO_CLEAR)
282223f0703cSBryan Whitehead 		data |= RX_CFG_C_RX_DMA_INT_STS_AUTO_CLR_;
282323f0703cSBryan Whitehead 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_STATUS_R2C)
282423f0703cSBryan Whitehead 		data |= RX_CFG_C_RX_INT_STS_R2C_MODE_MASK_;
282523f0703cSBryan Whitehead 	if (rx->vector_flags & LAN743X_VECTOR_FLAG_SOURCE_ENABLE_R2C)
282623f0703cSBryan Whitehead 		data |= RX_CFG_C_RX_INT_EN_R2C_;
282723f0703cSBryan Whitehead 	lan743x_csr_write(adapter, RX_CFG_C(rx->channel_number), data);
282823f0703cSBryan Whitehead 
282923f0703cSBryan Whitehead 	rx->last_tail = ((u32)(rx->ring_size - 1));
283023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, RX_TAIL(rx->channel_number),
283123f0703cSBryan Whitehead 			  rx->last_tail);
283223f0703cSBryan Whitehead 	rx->last_head = lan743x_csr_read(adapter, RX_HEAD(rx->channel_number));
283323f0703cSBryan Whitehead 	if (rx->last_head) {
283423f0703cSBryan Whitehead 		ret = -EIO;
283523f0703cSBryan Whitehead 		goto napi_delete;
283623f0703cSBryan Whitehead 	}
283723f0703cSBryan Whitehead 
283823f0703cSBryan Whitehead 	napi_enable(&rx->napi);
283923f0703cSBryan Whitehead 
284023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_SET,
284123f0703cSBryan Whitehead 			  INT_BIT_DMA_RX_(rx->channel_number));
284223f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_INT_STS,
284323f0703cSBryan Whitehead 			  DMAC_INT_BIT_RXFRM_(rx->channel_number));
284423f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_INT_EN_SET,
284523f0703cSBryan Whitehead 			  DMAC_INT_BIT_RXFRM_(rx->channel_number));
284623f0703cSBryan Whitehead 	lan743x_csr_write(adapter, DMAC_CMD,
284723f0703cSBryan Whitehead 			  DMAC_CMD_START_R_(rx->channel_number));
284823f0703cSBryan Whitehead 
284923f0703cSBryan Whitehead 	/* initialize fifo */
285023f0703cSBryan Whitehead 	lan743x_csr_write(adapter, FCT_RX_CTL,
285123f0703cSBryan Whitehead 			  FCT_RX_CTL_RESET_(rx->channel_number));
285223f0703cSBryan Whitehead 	lan743x_csr_wait_for_bit(adapter, FCT_RX_CTL,
285323f0703cSBryan Whitehead 				 FCT_RX_CTL_RESET_(rx->channel_number),
285423f0703cSBryan Whitehead 				 0, 1000, 20000, 100);
285523f0703cSBryan Whitehead 	lan743x_csr_write(adapter, FCT_FLOW(rx->channel_number),
285623f0703cSBryan Whitehead 			  FCT_FLOW_CTL_REQ_EN_ |
285723f0703cSBryan Whitehead 			  FCT_FLOW_CTL_ON_THRESHOLD_SET_(0x2A) |
285823f0703cSBryan Whitehead 			  FCT_FLOW_CTL_OFF_THRESHOLD_SET_(0xA));
285923f0703cSBryan Whitehead 
286023f0703cSBryan Whitehead 	/* enable fifo */
286123f0703cSBryan Whitehead 	lan743x_csr_write(adapter, FCT_RX_CTL,
286223f0703cSBryan Whitehead 			  FCT_RX_CTL_EN_(rx->channel_number));
286323f0703cSBryan Whitehead 	return 0;
286423f0703cSBryan Whitehead 
286523f0703cSBryan Whitehead napi_delete:
286623f0703cSBryan Whitehead 	netif_napi_del(&rx->napi);
286723f0703cSBryan Whitehead 	lan743x_rx_ring_cleanup(rx);
286823f0703cSBryan Whitehead 
286923f0703cSBryan Whitehead return_error:
287023f0703cSBryan Whitehead 	return ret;
287123f0703cSBryan Whitehead }
287223f0703cSBryan Whitehead 
lan743x_phylink_sgmii_config(struct lan743x_adapter * adapter)2873a5f199a8SRaju Lakkaraju static int lan743x_phylink_sgmii_config(struct lan743x_adapter *adapter)
2874a5f199a8SRaju Lakkaraju {
2875a5f199a8SRaju Lakkaraju 	u32 sgmii_ctl;
2876a5f199a8SRaju Lakkaraju 	int ret;
2877a5f199a8SRaju Lakkaraju 
2878a5f199a8SRaju Lakkaraju 	ret = lan743x_get_lsd(SPEED_1000, DUPLEX_FULL,
2879a5f199a8SRaju Lakkaraju 			      MASTER_SLAVE_STATE_MASTER);
2880a5f199a8SRaju Lakkaraju 	if (ret < 0) {
2881a5f199a8SRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
2882a5f199a8SRaju Lakkaraju 			  "error %d link-speed-duplex(LSD) invalid\n", ret);
2883a5f199a8SRaju Lakkaraju 		return ret;
2884a5f199a8SRaju Lakkaraju 	}
2885a5f199a8SRaju Lakkaraju 
2886a5f199a8SRaju Lakkaraju 	adapter->sgmii_lsd = ret;
2887a5f199a8SRaju Lakkaraju 	netif_dbg(adapter, drv, adapter->netdev,
2888a5f199a8SRaju Lakkaraju 		  "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd);
2889a5f199a8SRaju Lakkaraju 
2890a5f199a8SRaju Lakkaraju 	/* LINK_STATUS_SOURCE from the External PHY via SGMII */
2891a5f199a8SRaju Lakkaraju 	sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
2892a5f199a8SRaju Lakkaraju 	sgmii_ctl &= ~SGMII_CTL_LINK_STATUS_SOURCE_;
2893a5f199a8SRaju Lakkaraju 	lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
2894a5f199a8SRaju Lakkaraju 
2895a5f199a8SRaju Lakkaraju 	ret = lan743x_serdes_clock_and_aneg_update(adapter);
2896a5f199a8SRaju Lakkaraju 	if (ret < 0) {
2897a5f199a8SRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
2898a5f199a8SRaju Lakkaraju 			  "error %d sgmii aneg update failed\n", ret);
2899a5f199a8SRaju Lakkaraju 		return ret;
2900a5f199a8SRaju Lakkaraju 	}
2901a5f199a8SRaju Lakkaraju 
2902a5f199a8SRaju Lakkaraju 	return lan743x_pcs_power_reset(adapter);
2903a5f199a8SRaju Lakkaraju }
2904a5f199a8SRaju Lakkaraju 
lan743x_phylink_1000basex_config(struct lan743x_adapter * adapter)2905a5f199a8SRaju Lakkaraju static int lan743x_phylink_1000basex_config(struct lan743x_adapter *adapter)
2906a5f199a8SRaju Lakkaraju {
2907a5f199a8SRaju Lakkaraju 	u32 sgmii_ctl;
2908a5f199a8SRaju Lakkaraju 	int ret;
2909a5f199a8SRaju Lakkaraju 
2910a5f199a8SRaju Lakkaraju 	ret = lan743x_get_lsd(SPEED_1000, DUPLEX_FULL,
2911a5f199a8SRaju Lakkaraju 			      MASTER_SLAVE_STATE_MASTER);
2912a5f199a8SRaju Lakkaraju 	if (ret < 0) {
2913a5f199a8SRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
2914a5f199a8SRaju Lakkaraju 			  "error %d link-speed-duplex(LSD) invalid\n", ret);
2915a5f199a8SRaju Lakkaraju 		return ret;
2916a5f199a8SRaju Lakkaraju 	}
2917a5f199a8SRaju Lakkaraju 
2918a5f199a8SRaju Lakkaraju 	adapter->sgmii_lsd = ret;
2919a5f199a8SRaju Lakkaraju 	netif_dbg(adapter, drv, adapter->netdev,
2920a5f199a8SRaju Lakkaraju 		  "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd);
2921a5f199a8SRaju Lakkaraju 
2922a5f199a8SRaju Lakkaraju 	/* LINK_STATUS_SOURCE from 1000BASE-X PCS link status */
2923a5f199a8SRaju Lakkaraju 	sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
2924a5f199a8SRaju Lakkaraju 	sgmii_ctl |= SGMII_CTL_LINK_STATUS_SOURCE_;
2925a5f199a8SRaju Lakkaraju 	lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
2926a5f199a8SRaju Lakkaraju 
2927a5f199a8SRaju Lakkaraju 	ret = lan743x_serdes_clock_and_aneg_update(adapter);
2928a5f199a8SRaju Lakkaraju 	if (ret < 0) {
2929a5f199a8SRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
2930a5f199a8SRaju Lakkaraju 			  "error %d 1000basex aneg update failed\n", ret);
2931a5f199a8SRaju Lakkaraju 		return ret;
2932a5f199a8SRaju Lakkaraju 	}
2933a5f199a8SRaju Lakkaraju 
2934a5f199a8SRaju Lakkaraju 	return lan743x_pcs_power_reset(adapter);
2935a5f199a8SRaju Lakkaraju }
2936a5f199a8SRaju Lakkaraju 
lan743x_phylink_2500basex_config(struct lan743x_adapter * adapter)2937a5f199a8SRaju Lakkaraju static int lan743x_phylink_2500basex_config(struct lan743x_adapter *adapter)
2938a5f199a8SRaju Lakkaraju {
2939a5f199a8SRaju Lakkaraju 	u32 sgmii_ctl;
2940a5f199a8SRaju Lakkaraju 	int ret;
2941a5f199a8SRaju Lakkaraju 
2942a5f199a8SRaju Lakkaraju 	ret = lan743x_get_lsd(SPEED_2500, DUPLEX_FULL,
2943a5f199a8SRaju Lakkaraju 			      MASTER_SLAVE_STATE_MASTER);
2944a5f199a8SRaju Lakkaraju 	if (ret < 0) {
2945a5f199a8SRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
2946a5f199a8SRaju Lakkaraju 			  "error %d link-speed-duplex(LSD) invalid\n", ret);
2947a5f199a8SRaju Lakkaraju 		return ret;
2948a5f199a8SRaju Lakkaraju 	}
2949a5f199a8SRaju Lakkaraju 
2950a5f199a8SRaju Lakkaraju 	adapter->sgmii_lsd = ret;
2951a5f199a8SRaju Lakkaraju 	netif_dbg(adapter, drv, adapter->netdev,
2952a5f199a8SRaju Lakkaraju 		  "Link Speed Duplex (lsd) : 0x%X\n", adapter->sgmii_lsd);
2953a5f199a8SRaju Lakkaraju 
2954a5f199a8SRaju Lakkaraju 	/* LINK_STATUS_SOURCE from 2500BASE-X PCS link status */
2955a5f199a8SRaju Lakkaraju 	sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
2956a5f199a8SRaju Lakkaraju 	sgmii_ctl |= SGMII_CTL_LINK_STATUS_SOURCE_;
2957a5f199a8SRaju Lakkaraju 	lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
2958a5f199a8SRaju Lakkaraju 
2959a5f199a8SRaju Lakkaraju 	ret = lan743x_serdes_clock_and_aneg_update(adapter);
2960a5f199a8SRaju Lakkaraju 	if (ret < 0) {
2961a5f199a8SRaju Lakkaraju 		netif_err(adapter, drv, adapter->netdev,
2962a5f199a8SRaju Lakkaraju 			  "error %d 2500basex aneg update failed\n", ret);
2963a5f199a8SRaju Lakkaraju 		return ret;
2964a5f199a8SRaju Lakkaraju 	}
2965a5f199a8SRaju Lakkaraju 
2966a5f199a8SRaju Lakkaraju 	return lan743x_pcs_power_reset(adapter);
2967a5f199a8SRaju Lakkaraju }
2968a5f199a8SRaju Lakkaraju 
lan743x_mac_eee_enable(struct lan743x_adapter * adapter,bool enable)2969*f95f28d7SRaju Lakkaraju void lan743x_mac_eee_enable(struct lan743x_adapter *adapter, bool enable)
2970*f95f28d7SRaju Lakkaraju {
2971*f95f28d7SRaju Lakkaraju 	u32 mac_cr;
2972*f95f28d7SRaju Lakkaraju 
2973*f95f28d7SRaju Lakkaraju 	mac_cr = lan743x_csr_read(adapter, MAC_CR);
2974*f95f28d7SRaju Lakkaraju 	if (enable)
2975*f95f28d7SRaju Lakkaraju 		mac_cr |= MAC_CR_EEE_EN_;
2976*f95f28d7SRaju Lakkaraju 	else
2977*f95f28d7SRaju Lakkaraju 		mac_cr &= ~MAC_CR_EEE_EN_;
2978*f95f28d7SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_CR, mac_cr);
2979*f95f28d7SRaju Lakkaraju }
2980*f95f28d7SRaju Lakkaraju 
lan743x_phylink_mac_config(struct phylink_config * config,unsigned int link_an_mode,const struct phylink_link_state * state)2981a5f199a8SRaju Lakkaraju static void lan743x_phylink_mac_config(struct phylink_config *config,
2982a5f199a8SRaju Lakkaraju 				       unsigned int link_an_mode,
2983a5f199a8SRaju Lakkaraju 				       const struct phylink_link_state *state)
2984a5f199a8SRaju Lakkaraju {
2985a5f199a8SRaju Lakkaraju 	struct net_device *netdev = to_net_dev(config->dev);
2986a5f199a8SRaju Lakkaraju 	struct lan743x_adapter *adapter = netdev_priv(netdev);
2987a5f199a8SRaju Lakkaraju 	int ret;
2988a5f199a8SRaju Lakkaraju 
2989a5f199a8SRaju Lakkaraju 	switch (state->interface) {
2990a5f199a8SRaju Lakkaraju 	case PHY_INTERFACE_MODE_2500BASEX:
2991a5f199a8SRaju Lakkaraju 		ret = lan743x_phylink_2500basex_config(adapter);
2992a5f199a8SRaju Lakkaraju 		if (ret < 0)
2993a5f199a8SRaju Lakkaraju 			netif_err(adapter, drv, adapter->netdev,
2994a5f199a8SRaju Lakkaraju 				  "2500BASEX config failed. Error %d\n", ret);
2995a5f199a8SRaju Lakkaraju 		else
2996a5f199a8SRaju Lakkaraju 			netif_dbg(adapter, drv, adapter->netdev,
2997a5f199a8SRaju Lakkaraju 				  "2500BASEX mode selected and configured\n");
2998a5f199a8SRaju Lakkaraju 		break;
2999a5f199a8SRaju Lakkaraju 	case PHY_INTERFACE_MODE_1000BASEX:
3000a5f199a8SRaju Lakkaraju 		ret = lan743x_phylink_1000basex_config(adapter);
3001a5f199a8SRaju Lakkaraju 		if (ret < 0)
3002a5f199a8SRaju Lakkaraju 			netif_err(adapter, drv, adapter->netdev,
3003a5f199a8SRaju Lakkaraju 				  "1000BASEX config failed. Error %d\n", ret);
3004a5f199a8SRaju Lakkaraju 		else
3005a5f199a8SRaju Lakkaraju 			netif_dbg(adapter, drv, adapter->netdev,
3006a5f199a8SRaju Lakkaraju 				  "1000BASEX mode selected and configured\n");
3007a5f199a8SRaju Lakkaraju 		break;
3008a5f199a8SRaju Lakkaraju 	case PHY_INTERFACE_MODE_SGMII:
3009a5f199a8SRaju Lakkaraju 		ret = lan743x_phylink_sgmii_config(adapter);
3010a5f199a8SRaju Lakkaraju 		if (ret < 0)
3011a5f199a8SRaju Lakkaraju 			netif_err(adapter, drv, adapter->netdev,
3012a5f199a8SRaju Lakkaraju 				  "SGMII config failed. Error %d\n", ret);
3013a5f199a8SRaju Lakkaraju 		else
3014a5f199a8SRaju Lakkaraju 			netif_dbg(adapter, drv, adapter->netdev,
3015a5f199a8SRaju Lakkaraju 				  "SGMII mode selected and configured\n");
3016a5f199a8SRaju Lakkaraju 		break;
3017a5f199a8SRaju Lakkaraju 	default:
3018a5f199a8SRaju Lakkaraju 		netif_dbg(adapter, drv, adapter->netdev,
3019a5f199a8SRaju Lakkaraju 			  "RGMII/GMII/MII(0x%X) mode enable\n",
3020a5f199a8SRaju Lakkaraju 			  state->interface);
3021a5f199a8SRaju Lakkaraju 		break;
3022a5f199a8SRaju Lakkaraju 	}
3023a5f199a8SRaju Lakkaraju }
3024a5f199a8SRaju Lakkaraju 
lan743x_phylink_mac_link_down(struct phylink_config * config,unsigned int link_an_mode,phy_interface_t interface)3025a5f199a8SRaju Lakkaraju static void lan743x_phylink_mac_link_down(struct phylink_config *config,
3026a5f199a8SRaju Lakkaraju 					  unsigned int link_an_mode,
3027a5f199a8SRaju Lakkaraju 					  phy_interface_t interface)
3028a5f199a8SRaju Lakkaraju {
3029*f95f28d7SRaju Lakkaraju 	struct net_device *netdev = to_net_dev(config->dev);
3030*f95f28d7SRaju Lakkaraju 	struct lan743x_adapter *adapter = netdev_priv(netdev);
3031*f95f28d7SRaju Lakkaraju 
3032a5f199a8SRaju Lakkaraju 	netif_tx_stop_all_queues(to_net_dev(config->dev));
3033*f95f28d7SRaju Lakkaraju 	lan743x_mac_eee_enable(adapter, false);
3034a5f199a8SRaju Lakkaraju }
3035a5f199a8SRaju Lakkaraju 
lan743x_phylink_mac_link_up(struct phylink_config * config,struct phy_device * phydev,unsigned int link_an_mode,phy_interface_t interface,int speed,int duplex,bool tx_pause,bool rx_pause)3036a5f199a8SRaju Lakkaraju static void lan743x_phylink_mac_link_up(struct phylink_config *config,
3037a5f199a8SRaju Lakkaraju 					struct phy_device *phydev,
3038a5f199a8SRaju Lakkaraju 					unsigned int link_an_mode,
3039a5f199a8SRaju Lakkaraju 					phy_interface_t interface,
3040a5f199a8SRaju Lakkaraju 					int speed, int duplex,
3041a5f199a8SRaju Lakkaraju 					bool tx_pause, bool rx_pause)
3042a5f199a8SRaju Lakkaraju {
3043a5f199a8SRaju Lakkaraju 	struct net_device *netdev = to_net_dev(config->dev);
3044a5f199a8SRaju Lakkaraju 	struct lan743x_adapter *adapter = netdev_priv(netdev);
3045a5f199a8SRaju Lakkaraju 	int mac_cr;
3046a5f199a8SRaju Lakkaraju 	u8 cap;
3047a5f199a8SRaju Lakkaraju 
3048a5f199a8SRaju Lakkaraju 	mac_cr = lan743x_csr_read(adapter, MAC_CR);
3049a5f199a8SRaju Lakkaraju 	/* Pre-initialize register bits.
3050a5f199a8SRaju Lakkaraju 	 * Resulting value corresponds to SPEED_10
3051a5f199a8SRaju Lakkaraju 	 */
3052a5f199a8SRaju Lakkaraju 	mac_cr &= ~(MAC_CR_CFG_H_ | MAC_CR_CFG_L_);
3053a5f199a8SRaju Lakkaraju 	if (speed == SPEED_2500)
3054a5f199a8SRaju Lakkaraju 		mac_cr |= MAC_CR_CFG_H_ | MAC_CR_CFG_L_;
3055a5f199a8SRaju Lakkaraju 	else if (speed == SPEED_1000)
3056a5f199a8SRaju Lakkaraju 		mac_cr |= MAC_CR_CFG_H_;
3057a5f199a8SRaju Lakkaraju 	else if (speed == SPEED_100)
3058a5f199a8SRaju Lakkaraju 		mac_cr |= MAC_CR_CFG_L_;
3059a5f199a8SRaju Lakkaraju 
3060a5f199a8SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_CR, mac_cr);
3061a5f199a8SRaju Lakkaraju 
3062a5f199a8SRaju Lakkaraju 	lan743x_ptp_update_latency(adapter, speed);
3063a5f199a8SRaju Lakkaraju 
3064a5f199a8SRaju Lakkaraju 	/* Flow Control operation */
3065a5f199a8SRaju Lakkaraju 	cap = 0;
3066a5f199a8SRaju Lakkaraju 	if (tx_pause)
3067a5f199a8SRaju Lakkaraju 		cap |= FLOW_CTRL_TX;
3068a5f199a8SRaju Lakkaraju 	if (rx_pause)
3069a5f199a8SRaju Lakkaraju 		cap |= FLOW_CTRL_RX;
3070a5f199a8SRaju Lakkaraju 
3071a5f199a8SRaju Lakkaraju 	lan743x_mac_flow_ctrl_set_enables(adapter,
3072a5f199a8SRaju Lakkaraju 					  cap & FLOW_CTRL_TX,
3073a5f199a8SRaju Lakkaraju 					  cap & FLOW_CTRL_RX);
3074a5f199a8SRaju Lakkaraju 
3075*f95f28d7SRaju Lakkaraju 	if (phydev)
3076*f95f28d7SRaju Lakkaraju 		lan743x_mac_eee_enable(adapter, phydev->enable_tx_lpi);
3077*f95f28d7SRaju Lakkaraju 
3078a5f199a8SRaju Lakkaraju 	netif_tx_wake_all_queues(netdev);
3079a5f199a8SRaju Lakkaraju }
3080a5f199a8SRaju Lakkaraju 
3081a5f199a8SRaju Lakkaraju static const struct phylink_mac_ops lan743x_phylink_mac_ops = {
3082a5f199a8SRaju Lakkaraju 	.mac_config = lan743x_phylink_mac_config,
3083a5f199a8SRaju Lakkaraju 	.mac_link_down = lan743x_phylink_mac_link_down,
3084a5f199a8SRaju Lakkaraju 	.mac_link_up = lan743x_phylink_mac_link_up,
3085a5f199a8SRaju Lakkaraju };
3086a5f199a8SRaju Lakkaraju 
lan743x_phylink_create(struct lan743x_adapter * adapter)3087a5f199a8SRaju Lakkaraju static int lan743x_phylink_create(struct lan743x_adapter *adapter)
3088a5f199a8SRaju Lakkaraju {
3089a5f199a8SRaju Lakkaraju 	struct net_device *netdev = adapter->netdev;
3090a5f199a8SRaju Lakkaraju 	struct phylink *pl;
3091a5f199a8SRaju Lakkaraju 
3092a5f199a8SRaju Lakkaraju 	adapter->phylink_config.dev = &netdev->dev;
3093a5f199a8SRaju Lakkaraju 	adapter->phylink_config.type = PHYLINK_NETDEV;
3094a5f199a8SRaju Lakkaraju 	adapter->phylink_config.mac_managed_pm = false;
3095a5f199a8SRaju Lakkaraju 
3096a5f199a8SRaju Lakkaraju 	adapter->phylink_config.mac_capabilities = MAC_ASYM_PAUSE |
3097a5f199a8SRaju Lakkaraju 		MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD;
3098a5f199a8SRaju Lakkaraju 
3099a5f199a8SRaju Lakkaraju 	lan743x_phy_interface_select(adapter);
3100a5f199a8SRaju Lakkaraju 
3101a5f199a8SRaju Lakkaraju 	switch (adapter->phy_interface) {
3102a5f199a8SRaju Lakkaraju 	case PHY_INTERFACE_MODE_SGMII:
3103a5f199a8SRaju Lakkaraju 		__set_bit(PHY_INTERFACE_MODE_SGMII,
3104a5f199a8SRaju Lakkaraju 			  adapter->phylink_config.supported_interfaces);
3105a5f199a8SRaju Lakkaraju 		__set_bit(PHY_INTERFACE_MODE_1000BASEX,
3106a5f199a8SRaju Lakkaraju 			  adapter->phylink_config.supported_interfaces);
3107a5f199a8SRaju Lakkaraju 		__set_bit(PHY_INTERFACE_MODE_2500BASEX,
3108a5f199a8SRaju Lakkaraju 			  adapter->phylink_config.supported_interfaces);
3109a5f199a8SRaju Lakkaraju 		adapter->phylink_config.mac_capabilities |= MAC_2500FD;
3110a5f199a8SRaju Lakkaraju 		break;
3111a5f199a8SRaju Lakkaraju 	case PHY_INTERFACE_MODE_GMII:
3112a5f199a8SRaju Lakkaraju 		__set_bit(PHY_INTERFACE_MODE_GMII,
3113a5f199a8SRaju Lakkaraju 			  adapter->phylink_config.supported_interfaces);
3114a5f199a8SRaju Lakkaraju 		break;
3115a5f199a8SRaju Lakkaraju 	case PHY_INTERFACE_MODE_MII:
3116a5f199a8SRaju Lakkaraju 		__set_bit(PHY_INTERFACE_MODE_MII,
3117a5f199a8SRaju Lakkaraju 			  adapter->phylink_config.supported_interfaces);
3118a5f199a8SRaju Lakkaraju 		break;
3119a5f199a8SRaju Lakkaraju 	default:
3120a5f199a8SRaju Lakkaraju 		phy_interface_set_rgmii(adapter->phylink_config.supported_interfaces);
3121a5f199a8SRaju Lakkaraju 	}
3122a5f199a8SRaju Lakkaraju 
3123a5f199a8SRaju Lakkaraju 	pl = phylink_create(&adapter->phylink_config, NULL,
3124a5f199a8SRaju Lakkaraju 			    adapter->phy_interface, &lan743x_phylink_mac_ops);
3125a5f199a8SRaju Lakkaraju 
3126a5f199a8SRaju Lakkaraju 	if (IS_ERR(pl)) {
3127a5f199a8SRaju Lakkaraju 		netdev_err(netdev, "Could not create phylink (%pe)\n", pl);
3128a5f199a8SRaju Lakkaraju 		return PTR_ERR(pl);
3129a5f199a8SRaju Lakkaraju 	}
3130a5f199a8SRaju Lakkaraju 
3131a5f199a8SRaju Lakkaraju 	adapter->phylink = pl;
3132a5f199a8SRaju Lakkaraju 	netdev_dbg(netdev, "lan743x phylink created");
3133a5f199a8SRaju Lakkaraju 
3134a5f199a8SRaju Lakkaraju 	return 0;
3135a5f199a8SRaju Lakkaraju }
3136a5f199a8SRaju Lakkaraju 
lan743x_phy_handle_exists(struct device_node * dn)3137a5f199a8SRaju Lakkaraju static bool lan743x_phy_handle_exists(struct device_node *dn)
3138a5f199a8SRaju Lakkaraju {
3139a5f199a8SRaju Lakkaraju 	dn = of_parse_phandle(dn, "phy-handle", 0);
3140a5f199a8SRaju Lakkaraju 	of_node_put(dn);
3141a5f199a8SRaju Lakkaraju 	return dn != NULL;
3142a5f199a8SRaju Lakkaraju }
3143a5f199a8SRaju Lakkaraju 
lan743x_phylink_connect(struct lan743x_adapter * adapter)3144a5f199a8SRaju Lakkaraju static int lan743x_phylink_connect(struct lan743x_adapter *adapter)
3145a5f199a8SRaju Lakkaraju {
3146a5f199a8SRaju Lakkaraju 	struct device_node *dn = adapter->pdev->dev.of_node;
3147a5f199a8SRaju Lakkaraju 	struct net_device *dev = adapter->netdev;
3148a5f199a8SRaju Lakkaraju 	struct phy_device *phydev;
3149a5f199a8SRaju Lakkaraju 	int ret;
3150a5f199a8SRaju Lakkaraju 
3151a5f199a8SRaju Lakkaraju 	if (dn)
3152a5f199a8SRaju Lakkaraju 		ret = phylink_of_phy_connect(adapter->phylink, dn, 0);
3153a5f199a8SRaju Lakkaraju 
3154a5f199a8SRaju Lakkaraju 	if (!dn || (ret && !lan743x_phy_handle_exists(dn))) {
3155a5f199a8SRaju Lakkaraju 		phydev = phy_find_first(adapter->mdiobus);
3156a5f199a8SRaju Lakkaraju 		if (phydev) {
3157a5f199a8SRaju Lakkaraju 			/* attach the mac to the phy */
3158a5f199a8SRaju Lakkaraju 			ret = phylink_connect_phy(adapter->phylink, phydev);
3159a5f199a8SRaju Lakkaraju 		} else if (((adapter->csr.id_rev & ID_REV_ID_MASK_) ==
3160a5f199a8SRaju Lakkaraju 			      ID_REV_ID_LAN7431_) || adapter->is_pci11x1x) {
3161a5f199a8SRaju Lakkaraju 			struct phylink_link_state state;
3162a5f199a8SRaju Lakkaraju 			unsigned long caps;
3163a5f199a8SRaju Lakkaraju 
3164a5f199a8SRaju Lakkaraju 			caps = adapter->phylink_config.mac_capabilities;
3165a5f199a8SRaju Lakkaraju 			if (caps & MAC_2500FD) {
3166a5f199a8SRaju Lakkaraju 				state.speed = SPEED_2500;
3167a5f199a8SRaju Lakkaraju 				state.duplex = DUPLEX_FULL;
3168a5f199a8SRaju Lakkaraju 			} else if (caps & MAC_1000FD) {
3169a5f199a8SRaju Lakkaraju 				state.speed = SPEED_1000;
3170a5f199a8SRaju Lakkaraju 				state.duplex = DUPLEX_FULL;
3171a5f199a8SRaju Lakkaraju 			} else {
3172a5f199a8SRaju Lakkaraju 				state.speed = SPEED_UNKNOWN;
3173a5f199a8SRaju Lakkaraju 				state.duplex = DUPLEX_UNKNOWN;
3174a5f199a8SRaju Lakkaraju 			}
3175a5f199a8SRaju Lakkaraju 
3176a5f199a8SRaju Lakkaraju 			ret = phylink_set_fixed_link(adapter->phylink, &state);
3177a5f199a8SRaju Lakkaraju 			if (ret) {
3178a5f199a8SRaju Lakkaraju 				netdev_err(dev, "Could not set fixed link\n");
3179a5f199a8SRaju Lakkaraju 				return ret;
3180a5f199a8SRaju Lakkaraju 			}
3181a5f199a8SRaju Lakkaraju 		} else {
3182a5f199a8SRaju Lakkaraju 			netdev_err(dev, "no PHY found\n");
3183a5f199a8SRaju Lakkaraju 			return -ENXIO;
3184a5f199a8SRaju Lakkaraju 		}
3185a5f199a8SRaju Lakkaraju 	}
3186a5f199a8SRaju Lakkaraju 
3187a5f199a8SRaju Lakkaraju 	if (ret) {
3188a5f199a8SRaju Lakkaraju 		netdev_err(dev, "Could not attach PHY (%d)\n", ret);
3189a5f199a8SRaju Lakkaraju 		return ret;
3190a5f199a8SRaju Lakkaraju 	}
3191a5f199a8SRaju Lakkaraju 
3192a5f199a8SRaju Lakkaraju 	phylink_start(adapter->phylink);
3193a5f199a8SRaju Lakkaraju 
3194a5f199a8SRaju Lakkaraju 	return 0;
3195a5f199a8SRaju Lakkaraju }
3196a5f199a8SRaju Lakkaraju 
lan743x_phylink_disconnect(struct lan743x_adapter * adapter)3197a5f199a8SRaju Lakkaraju static void lan743x_phylink_disconnect(struct lan743x_adapter *adapter)
3198a5f199a8SRaju Lakkaraju {
3199a5f199a8SRaju Lakkaraju 	phylink_stop(adapter->phylink);
3200a5f199a8SRaju Lakkaraju 	phylink_disconnect_phy(adapter->phylink);
3201a5f199a8SRaju Lakkaraju }
3202a5f199a8SRaju Lakkaraju 
lan743x_netdev_close(struct net_device * netdev)320323f0703cSBryan Whitehead static int lan743x_netdev_close(struct net_device *netdev)
320423f0703cSBryan Whitehead {
320523f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
320623f0703cSBryan Whitehead 	int index;
320723f0703cSBryan Whitehead 
3208cf9aaea8SRaju Lakkaraju 	for (index = 0; index < adapter->used_tx_channels; index++)
3209cf9aaea8SRaju Lakkaraju 		lan743x_tx_close(&adapter->tx[index]);
321023f0703cSBryan Whitehead 
321123f0703cSBryan Whitehead 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++)
321223f0703cSBryan Whitehead 		lan743x_rx_close(&adapter->rx[index]);
321323f0703cSBryan Whitehead 
321407624df1SBryan Whitehead 	lan743x_ptp_close(adapter);
321507624df1SBryan Whitehead 
3216a5f199a8SRaju Lakkaraju 	lan743x_phylink_disconnect(adapter);
321723f0703cSBryan Whitehead 
321823f0703cSBryan Whitehead 	lan743x_mac_close(adapter);
321923f0703cSBryan Whitehead 
322023f0703cSBryan Whitehead 	lan743x_intr_close(adapter);
322123f0703cSBryan Whitehead 
322223f0703cSBryan Whitehead 	return 0;
322323f0703cSBryan Whitehead }
322423f0703cSBryan Whitehead 
lan743x_netdev_open(struct net_device * netdev)322523f0703cSBryan Whitehead static int lan743x_netdev_open(struct net_device *netdev)
322623f0703cSBryan Whitehead {
322723f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
322823f0703cSBryan Whitehead 	int index;
322923f0703cSBryan Whitehead 	int ret;
323023f0703cSBryan Whitehead 
323123f0703cSBryan Whitehead 	ret = lan743x_intr_open(adapter);
323223f0703cSBryan Whitehead 	if (ret)
323323f0703cSBryan Whitehead 		goto return_error;
323423f0703cSBryan Whitehead 
323523f0703cSBryan Whitehead 	ret = lan743x_mac_open(adapter);
323623f0703cSBryan Whitehead 	if (ret)
323723f0703cSBryan Whitehead 		goto close_intr;
323823f0703cSBryan Whitehead 
3239a5f199a8SRaju Lakkaraju 	ret = lan743x_phylink_connect(adapter);
324023f0703cSBryan Whitehead 	if (ret)
324123f0703cSBryan Whitehead 		goto close_mac;
324223f0703cSBryan Whitehead 
324307624df1SBryan Whitehead 	ret = lan743x_ptp_open(adapter);
324407624df1SBryan Whitehead 	if (ret)
3245a5f199a8SRaju Lakkaraju 		goto close_mac;
324607624df1SBryan Whitehead 
324743e8fe9bSBryan Whitehead 	lan743x_rfe_open(adapter);
324843e8fe9bSBryan Whitehead 
324923f0703cSBryan Whitehead 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
325023f0703cSBryan Whitehead 		ret = lan743x_rx_open(&adapter->rx[index]);
325123f0703cSBryan Whitehead 		if (ret)
325223f0703cSBryan Whitehead 			goto close_rx;
325323f0703cSBryan Whitehead 	}
325423f0703cSBryan Whitehead 
3255cf9aaea8SRaju Lakkaraju 	for (index = 0; index < adapter->used_tx_channels; index++) {
3256cf9aaea8SRaju Lakkaraju 		ret = lan743x_tx_open(&adapter->tx[index]);
325723f0703cSBryan Whitehead 		if (ret)
3258cf9aaea8SRaju Lakkaraju 			goto close_tx;
3259cf9aaea8SRaju Lakkaraju 	}
32608c248cd8SRaju Lakkaraju 
3261*f95f28d7SRaju Lakkaraju 	if (netdev->phydev)
3262*f95f28d7SRaju Lakkaraju 		phy_support_eee(netdev->phydev);
3263*f95f28d7SRaju Lakkaraju 
32648c248cd8SRaju Lakkaraju #ifdef CONFIG_PM
32658c248cd8SRaju Lakkaraju 	if (adapter->netdev->phydev) {
32668c248cd8SRaju Lakkaraju 		struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
32678c248cd8SRaju Lakkaraju 
32688c248cd8SRaju Lakkaraju 		phy_ethtool_get_wol(netdev->phydev, &wol);
32698c248cd8SRaju Lakkaraju 		adapter->phy_wol_supported = wol.supported;
32708c248cd8SRaju Lakkaraju 		adapter->phy_wolopts = wol.wolopts;
32718c248cd8SRaju Lakkaraju 	}
32728c248cd8SRaju Lakkaraju #endif
32738c248cd8SRaju Lakkaraju 
327423f0703cSBryan Whitehead 	return 0;
327523f0703cSBryan Whitehead 
3276cf9aaea8SRaju Lakkaraju close_tx:
3277cf9aaea8SRaju Lakkaraju 	for (index = 0; index < adapter->used_tx_channels; index++) {
3278cf9aaea8SRaju Lakkaraju 		if (adapter->tx[index].ring_cpu_ptr)
3279cf9aaea8SRaju Lakkaraju 			lan743x_tx_close(&adapter->tx[index]);
3280cf9aaea8SRaju Lakkaraju 	}
3281cf9aaea8SRaju Lakkaraju 
328223f0703cSBryan Whitehead close_rx:
328323f0703cSBryan Whitehead 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
328423f0703cSBryan Whitehead 		if (adapter->rx[index].ring_cpu_ptr)
328523f0703cSBryan Whitehead 			lan743x_rx_close(&adapter->rx[index]);
328623f0703cSBryan Whitehead 	}
328707624df1SBryan Whitehead 	lan743x_ptp_close(adapter);
3288a5f199a8SRaju Lakkaraju 	if (adapter->phylink)
3289a5f199a8SRaju Lakkaraju 		lan743x_phylink_disconnect(adapter);
329023f0703cSBryan Whitehead 
329123f0703cSBryan Whitehead close_mac:
329223f0703cSBryan Whitehead 	lan743x_mac_close(adapter);
329323f0703cSBryan Whitehead 
329423f0703cSBryan Whitehead close_intr:
329523f0703cSBryan Whitehead 	lan743x_intr_close(adapter);
329623f0703cSBryan Whitehead 
329723f0703cSBryan Whitehead return_error:
329823f0703cSBryan Whitehead 	netif_warn(adapter, ifup, adapter->netdev,
329923f0703cSBryan Whitehead 		   "Error opening LAN743x\n");
330023f0703cSBryan Whitehead 	return ret;
330123f0703cSBryan Whitehead }
330223f0703cSBryan Whitehead 
lan743x_netdev_xmit_frame(struct sk_buff * skb,struct net_device * netdev)330323f0703cSBryan Whitehead static netdev_tx_t lan743x_netdev_xmit_frame(struct sk_buff *skb,
330423f0703cSBryan Whitehead 					     struct net_device *netdev)
330523f0703cSBryan Whitehead {
330623f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
3307cf9aaea8SRaju Lakkaraju 	u8 ch = 0;
330823f0703cSBryan Whitehead 
3309cf9aaea8SRaju Lakkaraju 	if (adapter->is_pci11x1x)
3310cf9aaea8SRaju Lakkaraju 		ch = skb->queue_mapping % PCI11X1X_USED_TX_CHANNELS;
3311cf9aaea8SRaju Lakkaraju 
3312cf9aaea8SRaju Lakkaraju 	return lan743x_tx_xmit_frame(&adapter->tx[ch], skb);
331323f0703cSBryan Whitehead }
331423f0703cSBryan Whitehead 
lan743x_netdev_ioctl(struct net_device * netdev,struct ifreq * ifr,int cmd)331523f0703cSBryan Whitehead static int lan743x_netdev_ioctl(struct net_device *netdev,
331623f0703cSBryan Whitehead 				struct ifreq *ifr, int cmd)
331723f0703cSBryan Whitehead {
3318a5f199a8SRaju Lakkaraju 	struct lan743x_adapter *adapter = netdev_priv(netdev);
3319a5f199a8SRaju Lakkaraju 
332023f0703cSBryan Whitehead 	if (!netif_running(netdev))
332123f0703cSBryan Whitehead 		return -EINVAL;
332207624df1SBryan Whitehead 	if (cmd == SIOCSHWTSTAMP)
332307624df1SBryan Whitehead 		return lan743x_ptp_ioctl(netdev, ifr, cmd);
3324a5f199a8SRaju Lakkaraju 
3325a5f199a8SRaju Lakkaraju 	return phylink_mii_ioctl(adapter->phylink, ifr, cmd);
332623f0703cSBryan Whitehead }
332723f0703cSBryan Whitehead 
lan743x_netdev_set_multicast(struct net_device * netdev)332823f0703cSBryan Whitehead static void lan743x_netdev_set_multicast(struct net_device *netdev)
332923f0703cSBryan Whitehead {
333023f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
333123f0703cSBryan Whitehead 
333223f0703cSBryan Whitehead 	lan743x_rfe_set_multicast(adapter);
333323f0703cSBryan Whitehead }
333423f0703cSBryan Whitehead 
lan743x_netdev_change_mtu(struct net_device * netdev,int new_mtu)333523f0703cSBryan Whitehead static int lan743x_netdev_change_mtu(struct net_device *netdev, int new_mtu)
333623f0703cSBryan Whitehead {
333723f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
333823f0703cSBryan Whitehead 	int ret = 0;
333923f0703cSBryan Whitehead 
334023f0703cSBryan Whitehead 	ret = lan743x_mac_set_mtu(adapter, new_mtu);
334123f0703cSBryan Whitehead 	if (!ret)
33421eb2cdedSEric Dumazet 		WRITE_ONCE(netdev->mtu, new_mtu);
334323f0703cSBryan Whitehead 	return ret;
334423f0703cSBryan Whitehead }
334523f0703cSBryan Whitehead 
lan743x_netdev_get_stats64(struct net_device * netdev,struct rtnl_link_stats64 * stats)334623f0703cSBryan Whitehead static void lan743x_netdev_get_stats64(struct net_device *netdev,
334723f0703cSBryan Whitehead 				       struct rtnl_link_stats64 *stats)
334823f0703cSBryan Whitehead {
334923f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
335023f0703cSBryan Whitehead 
335123f0703cSBryan Whitehead 	stats->rx_packets = lan743x_csr_read(adapter, STAT_RX_TOTAL_FRAMES);
335223f0703cSBryan Whitehead 	stats->tx_packets = lan743x_csr_read(adapter, STAT_TX_TOTAL_FRAMES);
335323f0703cSBryan Whitehead 	stats->rx_bytes = lan743x_csr_read(adapter,
335423f0703cSBryan Whitehead 					   STAT_RX_UNICAST_BYTE_COUNT) +
335523f0703cSBryan Whitehead 			  lan743x_csr_read(adapter,
335623f0703cSBryan Whitehead 					   STAT_RX_BROADCAST_BYTE_COUNT) +
335723f0703cSBryan Whitehead 			  lan743x_csr_read(adapter,
335823f0703cSBryan Whitehead 					   STAT_RX_MULTICAST_BYTE_COUNT);
335923f0703cSBryan Whitehead 	stats->tx_bytes = lan743x_csr_read(adapter,
336023f0703cSBryan Whitehead 					   STAT_TX_UNICAST_BYTE_COUNT) +
336123f0703cSBryan Whitehead 			  lan743x_csr_read(adapter,
336223f0703cSBryan Whitehead 					   STAT_TX_BROADCAST_BYTE_COUNT) +
336323f0703cSBryan Whitehead 			  lan743x_csr_read(adapter,
336423f0703cSBryan Whitehead 					   STAT_TX_MULTICAST_BYTE_COUNT);
336523f0703cSBryan Whitehead 	stats->rx_errors = lan743x_csr_read(adapter, STAT_RX_FCS_ERRORS) +
336623f0703cSBryan Whitehead 			   lan743x_csr_read(adapter,
336723f0703cSBryan Whitehead 					    STAT_RX_ALIGNMENT_ERRORS) +
336823f0703cSBryan Whitehead 			   lan743x_csr_read(adapter, STAT_RX_JABBER_ERRORS) +
336923f0703cSBryan Whitehead 			   lan743x_csr_read(adapter,
337023f0703cSBryan Whitehead 					    STAT_RX_UNDERSIZE_FRAME_ERRORS) +
337123f0703cSBryan Whitehead 			   lan743x_csr_read(adapter,
337223f0703cSBryan Whitehead 					    STAT_RX_OVERSIZE_FRAME_ERRORS);
337323f0703cSBryan Whitehead 	stats->tx_errors = lan743x_csr_read(adapter, STAT_TX_FCS_ERRORS) +
337423f0703cSBryan Whitehead 			   lan743x_csr_read(adapter,
337523f0703cSBryan Whitehead 					    STAT_TX_EXCESS_DEFERRAL_ERRORS) +
337623f0703cSBryan Whitehead 			   lan743x_csr_read(adapter, STAT_TX_CARRIER_ERRORS);
337723f0703cSBryan Whitehead 	stats->rx_dropped = lan743x_csr_read(adapter,
337823f0703cSBryan Whitehead 					     STAT_RX_DROPPED_FRAMES);
337923f0703cSBryan Whitehead 	stats->tx_dropped = lan743x_csr_read(adapter,
338023f0703cSBryan Whitehead 					     STAT_TX_EXCESSIVE_COLLISION);
338123f0703cSBryan Whitehead 	stats->multicast = lan743x_csr_read(adapter,
338223f0703cSBryan Whitehead 					    STAT_RX_MULTICAST_FRAMES) +
338323f0703cSBryan Whitehead 			   lan743x_csr_read(adapter,
338423f0703cSBryan Whitehead 					    STAT_TX_MULTICAST_FRAMES);
338523f0703cSBryan Whitehead 	stats->collisions = lan743x_csr_read(adapter,
338623f0703cSBryan Whitehead 					     STAT_TX_SINGLE_COLLISIONS) +
338723f0703cSBryan Whitehead 			    lan743x_csr_read(adapter,
338823f0703cSBryan Whitehead 					     STAT_TX_MULTIPLE_COLLISIONS) +
338923f0703cSBryan Whitehead 			    lan743x_csr_read(adapter,
339023f0703cSBryan Whitehead 					     STAT_TX_LATE_COLLISIONS);
339123f0703cSBryan Whitehead }
339223f0703cSBryan Whitehead 
lan743x_netdev_set_mac_address(struct net_device * netdev,void * addr)339323f0703cSBryan Whitehead static int lan743x_netdev_set_mac_address(struct net_device *netdev,
339423f0703cSBryan Whitehead 					  void *addr)
339523f0703cSBryan Whitehead {
339623f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
339723f0703cSBryan Whitehead 	struct sockaddr *sock_addr = addr;
339823f0703cSBryan Whitehead 	int ret;
339923f0703cSBryan Whitehead 
340023f0703cSBryan Whitehead 	ret = eth_prepare_mac_addr_change(netdev, sock_addr);
340123f0703cSBryan Whitehead 	if (ret)
340223f0703cSBryan Whitehead 		return ret;
3403f3956ebbSJakub Kicinski 	eth_hw_addr_set(netdev, sock_addr->sa_data);
340423f0703cSBryan Whitehead 	lan743x_mac_set_address(adapter, sock_addr->sa_data);
340523f0703cSBryan Whitehead 	lan743x_rfe_update_mac_address(adapter);
340623f0703cSBryan Whitehead 	return 0;
340723f0703cSBryan Whitehead }
340823f0703cSBryan Whitehead 
340923f0703cSBryan Whitehead static const struct net_device_ops lan743x_netdev_ops = {
341023f0703cSBryan Whitehead 	.ndo_open		= lan743x_netdev_open,
341123f0703cSBryan Whitehead 	.ndo_stop		= lan743x_netdev_close,
341223f0703cSBryan Whitehead 	.ndo_start_xmit		= lan743x_netdev_xmit_frame,
3413a7605370SArnd Bergmann 	.ndo_eth_ioctl		= lan743x_netdev_ioctl,
341423f0703cSBryan Whitehead 	.ndo_set_rx_mode	= lan743x_netdev_set_multicast,
341523f0703cSBryan Whitehead 	.ndo_change_mtu		= lan743x_netdev_change_mtu,
341623f0703cSBryan Whitehead 	.ndo_get_stats64	= lan743x_netdev_get_stats64,
341723f0703cSBryan Whitehead 	.ndo_set_mac_address	= lan743x_netdev_set_mac_address,
341823f0703cSBryan Whitehead };
341923f0703cSBryan Whitehead 
lan743x_hardware_cleanup(struct lan743x_adapter * adapter)342023f0703cSBryan Whitehead static void lan743x_hardware_cleanup(struct lan743x_adapter *adapter)
342123f0703cSBryan Whitehead {
342223f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
342323f0703cSBryan Whitehead }
342423f0703cSBryan Whitehead 
lan743x_mdiobus_cleanup(struct lan743x_adapter * adapter)342523f0703cSBryan Whitehead static void lan743x_mdiobus_cleanup(struct lan743x_adapter *adapter)
342623f0703cSBryan Whitehead {
342723f0703cSBryan Whitehead 	mdiobus_unregister(adapter->mdiobus);
342823f0703cSBryan Whitehead }
342923f0703cSBryan Whitehead 
lan743x_destroy_phylink(struct lan743x_adapter * adapter)3430a5f199a8SRaju Lakkaraju static void lan743x_destroy_phylink(struct lan743x_adapter *adapter)
3431a5f199a8SRaju Lakkaraju {
3432a5f199a8SRaju Lakkaraju 	phylink_destroy(adapter->phylink);
3433a5f199a8SRaju Lakkaraju 	adapter->phylink = NULL;
3434a5f199a8SRaju Lakkaraju }
3435a5f199a8SRaju Lakkaraju 
lan743x_full_cleanup(struct lan743x_adapter * adapter)343623f0703cSBryan Whitehead static void lan743x_full_cleanup(struct lan743x_adapter *adapter)
343723f0703cSBryan Whitehead {
343823f0703cSBryan Whitehead 	unregister_netdev(adapter->netdev);
343923f0703cSBryan Whitehead 
3440a5f199a8SRaju Lakkaraju 	lan743x_destroy_phylink(adapter);
344123f0703cSBryan Whitehead 	lan743x_mdiobus_cleanup(adapter);
344223f0703cSBryan Whitehead 	lan743x_hardware_cleanup(adapter);
344323f0703cSBryan Whitehead 	lan743x_pci_cleanup(adapter);
344423f0703cSBryan Whitehead }
344523f0703cSBryan Whitehead 
pci11x1x_set_rfe_rd_fifo_threshold(struct lan743x_adapter * adapter)3446e4a58989SRaju Lakkaraju static void pci11x1x_set_rfe_rd_fifo_threshold(struct lan743x_adapter *adapter)
3447e4a58989SRaju Lakkaraju {
3448e4a58989SRaju Lakkaraju 	u16 rev = adapter->csr.id_rev & ID_REV_CHIP_REV_MASK_;
3449e4a58989SRaju Lakkaraju 
3450e4a58989SRaju Lakkaraju 	if (rev == ID_REV_CHIP_REV_PCI11X1X_B0_) {
3451e4a58989SRaju Lakkaraju 		u32 misc_ctl;
3452e4a58989SRaju Lakkaraju 
3453e4a58989SRaju Lakkaraju 		misc_ctl = lan743x_csr_read(adapter, MISC_CTL_0);
3454e4a58989SRaju Lakkaraju 		misc_ctl &= ~MISC_CTL_0_RFE_READ_FIFO_MASK_;
3455e4a58989SRaju Lakkaraju 		misc_ctl |= FIELD_PREP(MISC_CTL_0_RFE_READ_FIFO_MASK_,
3456e4a58989SRaju Lakkaraju 				       RFE_RD_FIFO_TH_3_DWORDS);
3457e4a58989SRaju Lakkaraju 		lan743x_csr_write(adapter, MISC_CTL_0, misc_ctl);
3458e4a58989SRaju Lakkaraju 	}
3459e4a58989SRaju Lakkaraju }
3460e4a58989SRaju Lakkaraju 
lan743x_hardware_init(struct lan743x_adapter * adapter,struct pci_dev * pdev)346123f0703cSBryan Whitehead static int lan743x_hardware_init(struct lan743x_adapter *adapter,
346223f0703cSBryan Whitehead 				 struct pci_dev *pdev)
346323f0703cSBryan Whitehead {
346423f0703cSBryan Whitehead 	struct lan743x_tx *tx;
346523f0703cSBryan Whitehead 	int index;
346623f0703cSBryan Whitehead 	int ret;
346723f0703cSBryan Whitehead 
3468cf9aaea8SRaju Lakkaraju 	adapter->is_pci11x1x = is_pci11x1x_chip(adapter);
3469cf9aaea8SRaju Lakkaraju 	if (adapter->is_pci11x1x) {
3470cf9aaea8SRaju Lakkaraju 		adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS;
3471cf9aaea8SRaju Lakkaraju 		adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS;
3472ac16b6ebSRaju Lakkaraju 		adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
3473a46d9d37SRaju Lakkaraju 		pci11x1x_strap_get_status(adapter);
3474cdea83ccSRaju Lakkaraju 		spin_lock_init(&adapter->eth_syslock_spinlock);
347546b777adSRaju Lakkaraju 		mutex_init(&adapter->sgmii_rw_lock);
3476e4a58989SRaju Lakkaraju 		pci11x1x_set_rfe_rd_fifo_threshold(adapter);
3477cf9aaea8SRaju Lakkaraju 	} else {
3478cf9aaea8SRaju Lakkaraju 		adapter->max_tx_channels = LAN743X_MAX_TX_CHANNELS;
3479cf9aaea8SRaju Lakkaraju 		adapter->used_tx_channels = LAN743X_USED_TX_CHANNELS;
3480ac16b6ebSRaju Lakkaraju 		adapter->max_vector_count = LAN743X_MAX_VECTOR_COUNT;
3481cf9aaea8SRaju Lakkaraju 	}
3482cf9aaea8SRaju Lakkaraju 
348323f0703cSBryan Whitehead 	adapter->intr.irq = adapter->pdev->irq;
348423f0703cSBryan Whitehead 	lan743x_csr_write(adapter, INT_EN_CLR, 0xFFFFFFFF);
348507624df1SBryan Whitehead 
348607624df1SBryan Whitehead 	ret = lan743x_gpio_init(adapter);
348707624df1SBryan Whitehead 	if (ret)
348807624df1SBryan Whitehead 		return ret;
348907624df1SBryan Whitehead 
349023f0703cSBryan Whitehead 	ret = lan743x_mac_init(adapter);
349123f0703cSBryan Whitehead 	if (ret)
349223f0703cSBryan Whitehead 		return ret;
349323f0703cSBryan Whitehead 
349423f0703cSBryan Whitehead 	ret = lan743x_phy_init(adapter);
349523f0703cSBryan Whitehead 	if (ret)
349623f0703cSBryan Whitehead 		return ret;
349723f0703cSBryan Whitehead 
349807624df1SBryan Whitehead 	ret = lan743x_ptp_init(adapter);
349907624df1SBryan Whitehead 	if (ret)
350007624df1SBryan Whitehead 		return ret;
350107624df1SBryan Whitehead 
350223f0703cSBryan Whitehead 	lan743x_rfe_update_mac_address(adapter);
350323f0703cSBryan Whitehead 
350423f0703cSBryan Whitehead 	ret = lan743x_dmac_init(adapter);
350523f0703cSBryan Whitehead 	if (ret)
350623f0703cSBryan Whitehead 		return ret;
350723f0703cSBryan Whitehead 
350823f0703cSBryan Whitehead 	for (index = 0; index < LAN743X_USED_RX_CHANNELS; index++) {
350923f0703cSBryan Whitehead 		adapter->rx[index].adapter = adapter;
351023f0703cSBryan Whitehead 		adapter->rx[index].channel_number = index;
351123f0703cSBryan Whitehead 	}
351223f0703cSBryan Whitehead 
3513cf9aaea8SRaju Lakkaraju 	for (index = 0; index < adapter->used_tx_channels; index++) {
3514cf9aaea8SRaju Lakkaraju 		tx = &adapter->tx[index];
351523f0703cSBryan Whitehead 		tx->adapter = adapter;
3516cf9aaea8SRaju Lakkaraju 		tx->channel_number = index;
351723f0703cSBryan Whitehead 		spin_lock_init(&tx->ring_lock);
3518cf9aaea8SRaju Lakkaraju 	}
3519cf9aaea8SRaju Lakkaraju 
352023f0703cSBryan Whitehead 	return 0;
352123f0703cSBryan Whitehead }
352223f0703cSBryan Whitehead 
lan743x_mdiobus_init(struct lan743x_adapter * adapter)352323f0703cSBryan Whitehead static int lan743x_mdiobus_init(struct lan743x_adapter *adapter)
352423f0703cSBryan Whitehead {
3525a46d9d37SRaju Lakkaraju 	u32 sgmii_ctl;
352623f0703cSBryan Whitehead 	int ret;
352723f0703cSBryan Whitehead 
352823f0703cSBryan Whitehead 	adapter->mdiobus = devm_mdiobus_alloc(&adapter->pdev->dev);
352923f0703cSBryan Whitehead 	if (!(adapter->mdiobus)) {
353023f0703cSBryan Whitehead 		ret = -ENOMEM;
353123f0703cSBryan Whitehead 		goto return_error;
353223f0703cSBryan Whitehead 	}
353323f0703cSBryan Whitehead 
353423f0703cSBryan Whitehead 	adapter->mdiobus->priv = (void *)adapter;
3535a46d9d37SRaju Lakkaraju 	if (adapter->is_pci11x1x) {
3536a46d9d37SRaju Lakkaraju 		if (adapter->is_sgmii_en) {
3537a46d9d37SRaju Lakkaraju 			sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
3538a46d9d37SRaju Lakkaraju 			sgmii_ctl |= SGMII_CTL_SGMII_ENABLE_;
3539a46d9d37SRaju Lakkaraju 			sgmii_ctl &= ~SGMII_CTL_SGMII_POWER_DN_;
3540a46d9d37SRaju Lakkaraju 			lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
3541a46d9d37SRaju Lakkaraju 			netif_dbg(adapter, drv, adapter->netdev,
3542a46d9d37SRaju Lakkaraju 				  "SGMII operation\n");
35433d90c03cSAndrew Lunn 			adapter->mdiobus->read = lan743x_mdiobus_read_c22;
35443d90c03cSAndrew Lunn 			adapter->mdiobus->write = lan743x_mdiobus_write_c22;
35453d90c03cSAndrew Lunn 			adapter->mdiobus->read_c45 = lan743x_mdiobus_read_c45;
35463d90c03cSAndrew Lunn 			adapter->mdiobus->write_c45 = lan743x_mdiobus_write_c45;
354779dfeb29SRaju Lakkaraju 			adapter->mdiobus->name = "lan743x-mdiobus-c45";
354879dfeb29SRaju Lakkaraju 			netif_dbg(adapter, drv, adapter->netdev,
354979dfeb29SRaju Lakkaraju 				  "lan743x-mdiobus-c45\n");
3550a46d9d37SRaju Lakkaraju 		} else {
3551a46d9d37SRaju Lakkaraju 			sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
3552a46d9d37SRaju Lakkaraju 			sgmii_ctl &= ~SGMII_CTL_SGMII_ENABLE_;
3553a46d9d37SRaju Lakkaraju 			sgmii_ctl |= SGMII_CTL_SGMII_POWER_DN_;
3554a46d9d37SRaju Lakkaraju 			lan743x_csr_write(adapter, SGMII_CTL, sgmii_ctl);
3555a46d9d37SRaju Lakkaraju 			netif_dbg(adapter, drv, adapter->netdev,
355679dfeb29SRaju Lakkaraju 				  "RGMII operation\n");
355779dfeb29SRaju Lakkaraju 			// Only C22 support when RGMII I/F
35583d90c03cSAndrew Lunn 			adapter->mdiobus->read = lan743x_mdiobus_read_c22;
35593d90c03cSAndrew Lunn 			adapter->mdiobus->write = lan743x_mdiobus_write_c22;
356079dfeb29SRaju Lakkaraju 			adapter->mdiobus->name = "lan743x-mdiobus";
356179dfeb29SRaju Lakkaraju 			netif_dbg(adapter, drv, adapter->netdev,
356279dfeb29SRaju Lakkaraju 				  "lan743x-mdiobus\n");
3563a46d9d37SRaju Lakkaraju 		}
3564a2ab95a3SRaju Lakkaraju 	} else {
35653d90c03cSAndrew Lunn 		adapter->mdiobus->read = lan743x_mdiobus_read_c22;
35663d90c03cSAndrew Lunn 		adapter->mdiobus->write = lan743x_mdiobus_write_c22;
356723f0703cSBryan Whitehead 		adapter->mdiobus->name = "lan743x-mdiobus";
3568a2ab95a3SRaju Lakkaraju 		netif_dbg(adapter, drv, adapter->netdev, "lan743x-mdiobus\n");
3569a2ab95a3SRaju Lakkaraju 	}
3570a2ab95a3SRaju Lakkaraju 
357123f0703cSBryan Whitehead 	snprintf(adapter->mdiobus->id, MII_BUS_ID_SIZE,
357223f0703cSBryan Whitehead 		 "pci-%s", pci_name(adapter->pdev));
357323f0703cSBryan Whitehead 
35740db7d253SBryan Whitehead 	if ((adapter->csr.id_rev & ID_REV_ID_MASK_) == ID_REV_ID_LAN7430_)
35750db7d253SBryan Whitehead 		/* LAN7430 uses internal phy at address 1 */
357623f0703cSBryan Whitehead 		adapter->mdiobus->phy_mask = ~(u32)BIT(1);
357723f0703cSBryan Whitehead 
357823f0703cSBryan Whitehead 	/* register mdiobus */
357923f0703cSBryan Whitehead 	ret = mdiobus_register(adapter->mdiobus);
358023f0703cSBryan Whitehead 	if (ret < 0)
358123f0703cSBryan Whitehead 		goto return_error;
358223f0703cSBryan Whitehead 	return 0;
358323f0703cSBryan Whitehead 
358423f0703cSBryan Whitehead return_error:
358523f0703cSBryan Whitehead 	return ret;
358623f0703cSBryan Whitehead }
358723f0703cSBryan Whitehead 
358823f0703cSBryan Whitehead /* lan743x_pcidev_probe - Device Initialization Routine
358923f0703cSBryan Whitehead  * @pdev: PCI device information struct
359023f0703cSBryan Whitehead  * @id: entry in lan743x_pci_tbl
359123f0703cSBryan Whitehead  *
359223f0703cSBryan Whitehead  * Returns 0 on success, negative on failure
359323f0703cSBryan Whitehead  *
359423f0703cSBryan Whitehead  * initializes an adapter identified by a pci_dev structure.
359523f0703cSBryan Whitehead  * The OS initialization, configuring of the adapter private structure,
359623f0703cSBryan Whitehead  * and a hardware reset occur.
359723f0703cSBryan Whitehead  **/
lan743x_pcidev_probe(struct pci_dev * pdev,const struct pci_device_id * id)359823f0703cSBryan Whitehead static int lan743x_pcidev_probe(struct pci_dev *pdev,
359923f0703cSBryan Whitehead 				const struct pci_device_id *id)
360023f0703cSBryan Whitehead {
360123f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = NULL;
360223f0703cSBryan Whitehead 	struct net_device *netdev = NULL;
360323f0703cSBryan Whitehead 	int ret = -ENODEV;
360423f0703cSBryan Whitehead 
3605cf9aaea8SRaju Lakkaraju 	if (id->device == PCI_DEVICE_ID_SMSC_A011 ||
3606cf9aaea8SRaju Lakkaraju 	    id->device == PCI_DEVICE_ID_SMSC_A041) {
3607cf9aaea8SRaju Lakkaraju 		netdev = devm_alloc_etherdev_mqs(&pdev->dev,
3608cf9aaea8SRaju Lakkaraju 						 sizeof(struct lan743x_adapter),
3609cf9aaea8SRaju Lakkaraju 						 PCI11X1X_USED_TX_CHANNELS,
3610cf9aaea8SRaju Lakkaraju 						 LAN743X_USED_RX_CHANNELS);
3611cf9aaea8SRaju Lakkaraju 	} else {
3612721f80c4SRaju Lakkaraju 		netdev = devm_alloc_etherdev_mqs(&pdev->dev,
3613721f80c4SRaju Lakkaraju 						 sizeof(struct lan743x_adapter),
3614721f80c4SRaju Lakkaraju 						 LAN743X_USED_TX_CHANNELS,
3615721f80c4SRaju Lakkaraju 						 LAN743X_USED_RX_CHANNELS);
3616cf9aaea8SRaju Lakkaraju 	}
3617cf9aaea8SRaju Lakkaraju 
361823f0703cSBryan Whitehead 	if (!netdev)
361923f0703cSBryan Whitehead 		goto return_error;
362023f0703cSBryan Whitehead 
362123f0703cSBryan Whitehead 	SET_NETDEV_DEV(netdev, &pdev->dev);
362223f0703cSBryan Whitehead 	pci_set_drvdata(pdev, netdev);
362323f0703cSBryan Whitehead 	adapter = netdev_priv(netdev);
362423f0703cSBryan Whitehead 	adapter->netdev = netdev;
362523f0703cSBryan Whitehead 	adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE |
362623f0703cSBryan Whitehead 			      NETIF_MSG_LINK | NETIF_MSG_IFUP |
362723f0703cSBryan Whitehead 			      NETIF_MSG_IFDOWN | NETIF_MSG_TX_QUEUED;
362823f0703cSBryan Whitehead 	netdev->max_mtu = LAN743X_MAX_FRAME_SIZE;
362923f0703cSBryan Whitehead 
363083216e39SMichael Walle 	of_get_mac_address(pdev->dev.of_node, adapter->mac_address);
3631c90834cdSTim Harvey 
363223f0703cSBryan Whitehead 	ret = lan743x_pci_init(adapter, pdev);
363323f0703cSBryan Whitehead 	if (ret)
363423f0703cSBryan Whitehead 		goto return_error;
363523f0703cSBryan Whitehead 
363623f0703cSBryan Whitehead 	ret = lan743x_csr_init(adapter);
363723f0703cSBryan Whitehead 	if (ret)
363823f0703cSBryan Whitehead 		goto cleanup_pci;
363923f0703cSBryan Whitehead 
364023f0703cSBryan Whitehead 	ret = lan743x_hardware_init(adapter, pdev);
364123f0703cSBryan Whitehead 	if (ret)
364223f0703cSBryan Whitehead 		goto cleanup_pci;
364323f0703cSBryan Whitehead 
364423f0703cSBryan Whitehead 	ret = lan743x_mdiobus_init(adapter);
364523f0703cSBryan Whitehead 	if (ret)
364623f0703cSBryan Whitehead 		goto cleanup_hardware;
364723f0703cSBryan Whitehead 
364823f0703cSBryan Whitehead 	adapter->netdev->netdev_ops = &lan743x_netdev_ops;
36490cf63226SBryan Whitehead 	adapter->netdev->ethtool_ops = &lan743x_ethtool_ops;
3650cd691050SRaju Lakkaraju 	adapter->netdev->features = NETIF_F_SG | NETIF_F_TSO |
3651cd691050SRaju Lakkaraju 				    NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
365223f0703cSBryan Whitehead 	adapter->netdev->hw_features = adapter->netdev->features;
365323f0703cSBryan Whitehead 
3654a5f199a8SRaju Lakkaraju 	ret = lan743x_phylink_create(adapter);
3655a5f199a8SRaju Lakkaraju 	if (ret < 0) {
3656a5f199a8SRaju Lakkaraju 		netif_err(adapter, probe, netdev,
3657a5f199a8SRaju Lakkaraju 			  "failed to setup phylink (%d)\n", ret);
3658a5f199a8SRaju Lakkaraju 		goto cleanup_mdiobus;
3659a5f199a8SRaju Lakkaraju 	}
366023f0703cSBryan Whitehead 
366123f0703cSBryan Whitehead 	ret = register_netdev(adapter->netdev);
366223f0703cSBryan Whitehead 	if (ret < 0)
3663a5f199a8SRaju Lakkaraju 		goto cleanup_phylink;
366423f0703cSBryan Whitehead 	return 0;
366523f0703cSBryan Whitehead 
3666a5f199a8SRaju Lakkaraju cleanup_phylink:
3667a5f199a8SRaju Lakkaraju 	lan743x_destroy_phylink(adapter);
3668a5f199a8SRaju Lakkaraju 
366923f0703cSBryan Whitehead cleanup_mdiobus:
367023f0703cSBryan Whitehead 	lan743x_mdiobus_cleanup(adapter);
367123f0703cSBryan Whitehead 
367223f0703cSBryan Whitehead cleanup_hardware:
367323f0703cSBryan Whitehead 	lan743x_hardware_cleanup(adapter);
367423f0703cSBryan Whitehead 
367523f0703cSBryan Whitehead cleanup_pci:
367623f0703cSBryan Whitehead 	lan743x_pci_cleanup(adapter);
367723f0703cSBryan Whitehead 
367823f0703cSBryan Whitehead return_error:
367923f0703cSBryan Whitehead 	pr_warn("Initialization failed\n");
368023f0703cSBryan Whitehead 	return ret;
368123f0703cSBryan Whitehead }
368223f0703cSBryan Whitehead 
368323f0703cSBryan Whitehead /**
368423f0703cSBryan Whitehead  * lan743x_pcidev_remove - Device Removal Routine
368523f0703cSBryan Whitehead  * @pdev: PCI device information struct
368623f0703cSBryan Whitehead  *
368723f0703cSBryan Whitehead  * this is called by the PCI subsystem to alert the driver
368823f0703cSBryan Whitehead  * that it should release a PCI device.  This could be caused by a
368923f0703cSBryan Whitehead  * Hot-Plug event, or because the driver is going to be removed from
369023f0703cSBryan Whitehead  * memory.
369123f0703cSBryan Whitehead  **/
lan743x_pcidev_remove(struct pci_dev * pdev)369223f0703cSBryan Whitehead static void lan743x_pcidev_remove(struct pci_dev *pdev)
369323f0703cSBryan Whitehead {
369423f0703cSBryan Whitehead 	struct net_device *netdev = pci_get_drvdata(pdev);
369523f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
369623f0703cSBryan Whitehead 
369723f0703cSBryan Whitehead 	lan743x_full_cleanup(adapter);
369823f0703cSBryan Whitehead }
369923f0703cSBryan Whitehead 
lan743x_pcidev_shutdown(struct pci_dev * pdev)370023f0703cSBryan Whitehead static void lan743x_pcidev_shutdown(struct pci_dev *pdev)
370123f0703cSBryan Whitehead {
370223f0703cSBryan Whitehead 	struct net_device *netdev = pci_get_drvdata(pdev);
370323f0703cSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
370423f0703cSBryan Whitehead 
370523f0703cSBryan Whitehead 	rtnl_lock();
370623f0703cSBryan Whitehead 	netif_device_detach(netdev);
370723f0703cSBryan Whitehead 
370823f0703cSBryan Whitehead 	/* close netdev when netdev is at running state.
370923f0703cSBryan Whitehead 	 * For instance, it is true when system goes to sleep by pm-suspend
371023f0703cSBryan Whitehead 	 * However, it is false when system goes to sleep by suspend GUI menu
371123f0703cSBryan Whitehead 	 */
371223f0703cSBryan Whitehead 	if (netif_running(netdev))
371323f0703cSBryan Whitehead 		lan743x_netdev_close(netdev);
371423f0703cSBryan Whitehead 	rtnl_unlock();
371523f0703cSBryan Whitehead 
37164d94282aSBryan Whitehead #ifdef CONFIG_PM
37174d94282aSBryan Whitehead 	pci_save_state(pdev);
37184d94282aSBryan Whitehead #endif
37194d94282aSBryan Whitehead 
372023f0703cSBryan Whitehead 	/* clean up lan743x portion */
372123f0703cSBryan Whitehead 	lan743x_hardware_cleanup(adapter);
372223f0703cSBryan Whitehead }
372323f0703cSBryan Whitehead 
3724c7348091Szhong jiang #ifdef CONFIG_PM_SLEEP
lan743x_pm_wakeframe_crc16(const u8 * buf,int len)37254d94282aSBryan Whitehead static u16 lan743x_pm_wakeframe_crc16(const u8 *buf, int len)
37264d94282aSBryan Whitehead {
37274d94282aSBryan Whitehead 	return bitrev16(crc16(0xFFFF, buf, len));
37284d94282aSBryan Whitehead }
37294d94282aSBryan Whitehead 
lan743x_pm_set_wol(struct lan743x_adapter * adapter)37304d94282aSBryan Whitehead static void lan743x_pm_set_wol(struct lan743x_adapter *adapter)
37314d94282aSBryan Whitehead {
37324d94282aSBryan Whitehead 	const u8 ipv4_multicast[3] = { 0x01, 0x00, 0x5E };
37334d94282aSBryan Whitehead 	const u8 ipv6_multicast[3] = { 0x33, 0x33 };
37344d94282aSBryan Whitehead 	const u8 arp_type[2] = { 0x08, 0x06 };
37354d94282aSBryan Whitehead 	int mask_index;
37366b3768acSRaju Lakkaraju 	u32 sopass;
37374d94282aSBryan Whitehead 	u32 pmtctl;
37384d94282aSBryan Whitehead 	u32 wucsr;
37394d94282aSBryan Whitehead 	u32 macrx;
37404d94282aSBryan Whitehead 	u16 crc;
37414d94282aSBryan Whitehead 
37424d94282aSBryan Whitehead 	for (mask_index = 0; mask_index < MAC_NUM_OF_WUF_CFG; mask_index++)
37434d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index), 0);
37444d94282aSBryan Whitehead 
37454d94282aSBryan Whitehead 	/* clear wake settings */
37464d94282aSBryan Whitehead 	pmtctl = lan743x_csr_read(adapter, PMT_CTL);
374777253639SRaju Lakkaraju 	pmtctl |= PMT_CTL_WUPS_MASK_ | PMT_CTL_RES_CLR_WKP_MASK_;
37484d94282aSBryan Whitehead 	pmtctl &= ~(PMT_CTL_GPIO_WAKEUP_EN_ | PMT_CTL_EEE_WAKEUP_EN_ |
37494d94282aSBryan Whitehead 		PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_ |
37504d94282aSBryan Whitehead 		PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_ | PMT_CTL_ETH_PHY_WAKE_EN_);
37514d94282aSBryan Whitehead 
37524d94282aSBryan Whitehead 	macrx = lan743x_csr_read(adapter, MAC_RX);
37534d94282aSBryan Whitehead 
37544d94282aSBryan Whitehead 	wucsr = 0;
37554d94282aSBryan Whitehead 	mask_index = 0;
37564d94282aSBryan Whitehead 
37574d94282aSBryan Whitehead 	pmtctl |= PMT_CTL_ETH_PHY_D3_COLD_OVR_ | PMT_CTL_ETH_PHY_D3_OVR_;
37584d94282aSBryan Whitehead 
37598c248cd8SRaju Lakkaraju 	if (adapter->phy_wolopts)
37604d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_ETH_PHY_WAKE_EN_;
37618c248cd8SRaju Lakkaraju 
37624d94282aSBryan Whitehead 	if (adapter->wolopts & WAKE_MAGIC) {
37634d94282aSBryan Whitehead 		wucsr |= MAC_WUCSR_MPEN_;
37644d94282aSBryan Whitehead 		macrx |= MAC_RX_RXEN_;
37654d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
37664d94282aSBryan Whitehead 	}
37674d94282aSBryan Whitehead 	if (adapter->wolopts & WAKE_UCAST) {
37684d94282aSBryan Whitehead 		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_PFDA_EN_;
37694d94282aSBryan Whitehead 		macrx |= MAC_RX_RXEN_;
37704d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
37714d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
37724d94282aSBryan Whitehead 	}
37734d94282aSBryan Whitehead 	if (adapter->wolopts & WAKE_BCAST) {
37744d94282aSBryan Whitehead 		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_BCST_EN_;
37754d94282aSBryan Whitehead 		macrx |= MAC_RX_RXEN_;
37764d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
37774d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
37784d94282aSBryan Whitehead 	}
37794d94282aSBryan Whitehead 	if (adapter->wolopts & WAKE_MCAST) {
37804d94282aSBryan Whitehead 		/* IPv4 multicast */
37814d94282aSBryan Whitehead 		crc = lan743x_pm_wakeframe_crc16(ipv4_multicast, 3);
37824d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
37834d94282aSBryan Whitehead 				  MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
37844d94282aSBryan Whitehead 				  (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
37854d94282aSBryan Whitehead 				  (crc & MAC_WUF_CFG_CRC16_MASK_));
37864d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 7);
37874d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
37884d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
37894d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
37904d94282aSBryan Whitehead 		mask_index++;
37914d94282aSBryan Whitehead 
37924d94282aSBryan Whitehead 		/* IPv6 multicast */
37934d94282aSBryan Whitehead 		crc = lan743x_pm_wakeframe_crc16(ipv6_multicast, 2);
37944d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
37954d94282aSBryan Whitehead 				  MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_MCAST_ |
37964d94282aSBryan Whitehead 				  (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
37974d94282aSBryan Whitehead 				  (crc & MAC_WUF_CFG_CRC16_MASK_));
37984d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 3);
37994d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
38004d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
38014d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
38024d94282aSBryan Whitehead 		mask_index++;
38034d94282aSBryan Whitehead 
38044d94282aSBryan Whitehead 		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_;
38054d94282aSBryan Whitehead 		macrx |= MAC_RX_RXEN_;
38064d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
38074d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
38084d94282aSBryan Whitehead 	}
38094d94282aSBryan Whitehead 	if (adapter->wolopts & WAKE_ARP) {
38104d94282aSBryan Whitehead 		/* set MAC_WUF_CFG & WUF_MASK
38114d94282aSBryan Whitehead 		 * for packettype (offset 12,13) = ARP (0x0806)
38124d94282aSBryan Whitehead 		 */
38134d94282aSBryan Whitehead 		crc = lan743x_pm_wakeframe_crc16(arp_type, 2);
38144d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_CFG(mask_index),
38154d94282aSBryan Whitehead 				  MAC_WUF_CFG_EN_ | MAC_WUF_CFG_TYPE_ALL_ |
38164d94282aSBryan Whitehead 				  (0 << MAC_WUF_CFG_OFFSET_SHIFT_) |
38174d94282aSBryan Whitehead 				  (crc & MAC_WUF_CFG_CRC16_MASK_));
38184d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK0(mask_index), 0x3000);
38194d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK1(mask_index), 0);
38204d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK2(mask_index), 0);
38214d94282aSBryan Whitehead 		lan743x_csr_write(adapter, MAC_WUF_MASK3(mask_index), 0);
38224d94282aSBryan Whitehead 		mask_index++;
38234d94282aSBryan Whitehead 
38244d94282aSBryan Whitehead 		wucsr |= MAC_WUCSR_RFE_WAKE_EN_ | MAC_WUCSR_WAKE_EN_;
38254d94282aSBryan Whitehead 		macrx |= MAC_RX_RXEN_;
38264d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_WOL_EN_ | PMT_CTL_MAC_D3_RX_CLK_OVR_;
38274d94282aSBryan Whitehead 		pmtctl |= PMT_CTL_RX_FCT_RFE_D3_CLK_OVR_;
38284d94282aSBryan Whitehead 	}
38294d94282aSBryan Whitehead 
38306b3768acSRaju Lakkaraju 	if (adapter->wolopts & WAKE_MAGICSECURE) {
38316b3768acSRaju Lakkaraju 		sopass = *(u32 *)adapter->sopass;
38326b3768acSRaju Lakkaraju 		lan743x_csr_write(adapter, MAC_MP_SO_LO, sopass);
38336b3768acSRaju Lakkaraju 		sopass = *(u16 *)&adapter->sopass[4];
38346b3768acSRaju Lakkaraju 		lan743x_csr_write(adapter, MAC_MP_SO_HI, sopass);
38356b3768acSRaju Lakkaraju 		wucsr |= MAC_MP_SO_EN_;
38366b3768acSRaju Lakkaraju 	}
38376b3768acSRaju Lakkaraju 
38384d94282aSBryan Whitehead 	lan743x_csr_write(adapter, MAC_WUCSR, wucsr);
38394d94282aSBryan Whitehead 	lan743x_csr_write(adapter, PMT_CTL, pmtctl);
38404d94282aSBryan Whitehead 	lan743x_csr_write(adapter, MAC_RX, macrx);
38414d94282aSBryan Whitehead }
38424d94282aSBryan Whitehead 
lan743x_pm_suspend(struct device * dev)38434d94282aSBryan Whitehead static int lan743x_pm_suspend(struct device *dev)
38444d94282aSBryan Whitehead {
38454d94282aSBryan Whitehead 	struct pci_dev *pdev = to_pci_dev(dev);
38464d94282aSBryan Whitehead 	struct net_device *netdev = pci_get_drvdata(pdev);
38474d94282aSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
38486b3768acSRaju Lakkaraju 	u32 data;
38494d94282aSBryan Whitehead 
38504d94282aSBryan Whitehead 	lan743x_pcidev_shutdown(pdev);
38514d94282aSBryan Whitehead 
38524d94282aSBryan Whitehead 	/* clear all wakes */
38534d94282aSBryan Whitehead 	lan743x_csr_write(adapter, MAC_WUCSR, 0);
38544d94282aSBryan Whitehead 	lan743x_csr_write(adapter, MAC_WUCSR2, 0);
38554d94282aSBryan Whitehead 	lan743x_csr_write(adapter, MAC_WK_SRC, 0xFFFFFFFF);
38564d94282aSBryan Whitehead 
38578c248cd8SRaju Lakkaraju 	if (adapter->wolopts || adapter->phy_wolopts)
38584d94282aSBryan Whitehead 		lan743x_pm_set_wol(adapter);
38594d94282aSBryan Whitehead 
38606b3768acSRaju Lakkaraju 	if (adapter->is_pci11x1x) {
38616b3768acSRaju Lakkaraju 		/* Save HW_CFG to config again in PM resume */
38626b3768acSRaju Lakkaraju 		data = lan743x_csr_read(adapter, HW_CFG);
38636b3768acSRaju Lakkaraju 		adapter->hw_cfg = data;
38646b3768acSRaju Lakkaraju 		data |= (HW_CFG_RST_PROTECT_PCIE_ |
38656b3768acSRaju Lakkaraju 			 HW_CFG_D3_RESET_DIS_ |
38666b3768acSRaju Lakkaraju 			 HW_CFG_D3_VAUX_OVR_ |
38676b3768acSRaju Lakkaraju 			 HW_CFG_HOT_RESET_DIS_ |
38686b3768acSRaju Lakkaraju 			 HW_CFG_RST_PROTECT_);
38696b3768acSRaju Lakkaraju 		lan743x_csr_write(adapter, HW_CFG, data);
38706b3768acSRaju Lakkaraju 	}
38716b3768acSRaju Lakkaraju 
38724d94282aSBryan Whitehead 	/* Host sets PME_En, put D3hot */
3873e228c0deSYang Yingliang 	return pci_prepare_to_sleep(pdev);
38744d94282aSBryan Whitehead }
38754d94282aSBryan Whitehead 
lan743x_pm_resume(struct device * dev)38764d94282aSBryan Whitehead static int lan743x_pm_resume(struct device *dev)
38774d94282aSBryan Whitehead {
38784d94282aSBryan Whitehead 	struct pci_dev *pdev = to_pci_dev(dev);
38794d94282aSBryan Whitehead 	struct net_device *netdev = pci_get_drvdata(pdev);
38804d94282aSBryan Whitehead 	struct lan743x_adapter *adapter = netdev_priv(netdev);
388177253639SRaju Lakkaraju 	u32 data;
38824d94282aSBryan Whitehead 	int ret;
38834d94282aSBryan Whitehead 
38844d94282aSBryan Whitehead 	pci_set_power_state(pdev, PCI_D0);
38854d94282aSBryan Whitehead 	pci_restore_state(pdev);
38864d94282aSBryan Whitehead 	pci_save_state(pdev);
38874d94282aSBryan Whitehead 
38886b3768acSRaju Lakkaraju 	/* Restore HW_CFG that was saved during pm suspend */
38896b3768acSRaju Lakkaraju 	if (adapter->is_pci11x1x)
38906b3768acSRaju Lakkaraju 		lan743x_csr_write(adapter, HW_CFG, adapter->hw_cfg);
38916b3768acSRaju Lakkaraju 
38924d94282aSBryan Whitehead 	ret = lan743x_hardware_init(adapter, pdev);
38934d94282aSBryan Whitehead 	if (ret) {
38944d94282aSBryan Whitehead 		netif_err(adapter, probe, adapter->netdev,
38954d94282aSBryan Whitehead 			  "lan743x_hardware_init returned %d\n", ret);
3896d6423d2eSYuiko Oshino 		lan743x_pci_cleanup(adapter);
3897d6423d2eSYuiko Oshino 		return ret;
38984d94282aSBryan Whitehead 	}
38994d94282aSBryan Whitehead 
390077253639SRaju Lakkaraju 	ret = lan743x_csr_read(adapter, MAC_WK_SRC);
390177253639SRaju Lakkaraju 	netif_dbg(adapter, drv, adapter->netdev,
390277253639SRaju Lakkaraju 		  "Wakeup source : 0x%08X\n", ret);
390377253639SRaju Lakkaraju 
390477253639SRaju Lakkaraju 	/* Clear the wol configuration and status bits. Note that
390577253639SRaju Lakkaraju 	 * the status bits are "Write One to Clear (W1C)"
390677253639SRaju Lakkaraju 	 */
390777253639SRaju Lakkaraju 	data = MAC_WUCSR_EEE_TX_WAKE_ | MAC_WUCSR_EEE_RX_WAKE_ |
390877253639SRaju Lakkaraju 	       MAC_WUCSR_RFE_WAKE_FR_ | MAC_WUCSR_PFDA_FR_ | MAC_WUCSR_WUFR_ |
390977253639SRaju Lakkaraju 	       MAC_WUCSR_MPR_ | MAC_WUCSR_BCAST_FR_;
391077253639SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_WUCSR, data);
391177253639SRaju Lakkaraju 
391277253639SRaju Lakkaraju 	data = MAC_WUCSR2_NS_RCD_ | MAC_WUCSR2_ARP_RCD_ |
391377253639SRaju Lakkaraju 	       MAC_WUCSR2_IPV6_TCPSYN_RCD_ | MAC_WUCSR2_IPV4_TCPSYN_RCD_;
391477253639SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_WUCSR2, data);
391577253639SRaju Lakkaraju 
391677253639SRaju Lakkaraju 	data = MAC_WK_SRC_ETH_PHY_WK_ | MAC_WK_SRC_IPV6_TCPSYN_RCD_WK_ |
391777253639SRaju Lakkaraju 	       MAC_WK_SRC_IPV4_TCPSYN_RCD_WK_ | MAC_WK_SRC_EEE_TX_WK_ |
391877253639SRaju Lakkaraju 	       MAC_WK_SRC_EEE_RX_WK_ | MAC_WK_SRC_RFE_FR_WK_ |
391977253639SRaju Lakkaraju 	       MAC_WK_SRC_PFDA_FR_WK_ | MAC_WK_SRC_MP_FR_WK_ |
392077253639SRaju Lakkaraju 	       MAC_WK_SRC_BCAST_FR_WK_ | MAC_WK_SRC_WU_FR_WK_ |
392177253639SRaju Lakkaraju 	       MAC_WK_SRC_WK_FR_SAVED_;
392277253639SRaju Lakkaraju 	lan743x_csr_write(adapter, MAC_WK_SRC, data);
392377253639SRaju Lakkaraju 
3924a5f199a8SRaju Lakkaraju 	rtnl_lock();
39254d94282aSBryan Whitehead 	/* open netdev when netdev is at running state while resume.
39264d94282aSBryan Whitehead 	 * For instance, it is true when system wakesup after pm-suspend
39274d94282aSBryan Whitehead 	 * However, it is false when system wakes up after suspend GUI menu
39284d94282aSBryan Whitehead 	 */
39294d94282aSBryan Whitehead 	if (netif_running(netdev))
39304d94282aSBryan Whitehead 		lan743x_netdev_open(netdev);
39314d94282aSBryan Whitehead 
39324d94282aSBryan Whitehead 	netif_device_attach(netdev);
3933a5f199a8SRaju Lakkaraju 	rtnl_unlock();
39344d94282aSBryan Whitehead 
39354d94282aSBryan Whitehead 	return 0;
39364d94282aSBryan Whitehead }
39374d94282aSBryan Whitehead 
393841147bb1SWei Yongjun static const struct dev_pm_ops lan743x_pm_ops = {
39394d94282aSBryan Whitehead 	SET_SYSTEM_SLEEP_PM_OPS(lan743x_pm_suspend, lan743x_pm_resume)
39404d94282aSBryan Whitehead };
3941c7348091Szhong jiang #endif /* CONFIG_PM_SLEEP */
39424d94282aSBryan Whitehead 
394323f0703cSBryan Whitehead static const struct pci_device_id lan743x_pcidev_tbl[] = {
394423f0703cSBryan Whitehead 	{ PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7430) },
39454df5ce9bSBryan Whitehead 	{ PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_LAN7431) },
3946bb4f6bffSRaju Lakkaraju 	{ PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_A011) },
3947bb4f6bffSRaju Lakkaraju 	{ PCI_DEVICE(PCI_VENDOR_ID_SMSC, PCI_DEVICE_ID_SMSC_A041) },
394823f0703cSBryan Whitehead 	{ 0, }
394923f0703cSBryan Whitehead };
395023f0703cSBryan Whitehead 
3951ea12fe9dSTim Harvey MODULE_DEVICE_TABLE(pci, lan743x_pcidev_tbl);
3952ea12fe9dSTim Harvey 
395323f0703cSBryan Whitehead static struct pci_driver lan743x_pcidev_driver = {
395423f0703cSBryan Whitehead 	.name     = DRIVER_NAME,
395523f0703cSBryan Whitehead 	.id_table = lan743x_pcidev_tbl,
395623f0703cSBryan Whitehead 	.probe    = lan743x_pcidev_probe,
395723f0703cSBryan Whitehead 	.remove   = lan743x_pcidev_remove,
3958c7348091Szhong jiang #ifdef CONFIG_PM_SLEEP
39594d94282aSBryan Whitehead 	.driver.pm = &lan743x_pm_ops,
39604d94282aSBryan Whitehead #endif
396123f0703cSBryan Whitehead 	.shutdown = lan743x_pcidev_shutdown,
396223f0703cSBryan Whitehead };
396323f0703cSBryan Whitehead 
396423f0703cSBryan Whitehead module_pci_driver(lan743x_pcidev_driver);
396523f0703cSBryan Whitehead 
396623f0703cSBryan Whitehead MODULE_AUTHOR(DRIVER_AUTHOR);
396723f0703cSBryan Whitehead MODULE_DESCRIPTION(DRIVER_DESC);
396823f0703cSBryan Whitehead MODULE_LICENSE("GPL");
3969